Browse Source

Software breakpoints sort of work.

pull/39/head
Tim Newsome 10 years ago
parent
commit
6ef848928a
  1. 4
      riscv/debug_module.cc
  2. 14
      riscv/debug_module.h
  3. 6
      riscv/decode.h
  4. 8
      riscv/encoding.h
  5. 137
      riscv/gdbserver.cc
  6. 5
      riscv/gdbserver.h

4
riscv/debug_module.cc

@ -41,6 +41,10 @@ bool debug_module_t::store(reg_t addr, size_t len, const uint8_t* bytes)
clear_interrupt(bytes[0] | (bytes[1] << 8) |
(bytes[2] << 16) | (bytes[3] << 24));
return true;
} else if (len == 4 && addr == DEBUG_SETHALTNOT) {
set_halt_notification(bytes[0] | (bytes[1] << 8) |
(bytes[2] << 16) | (bytes[3] << 24));
return true;
}
fprintf(stderr, "ERROR: invalid store to debug module: %ld bytes at 0x%lx\n",

14
riscv/debug_module.h

@ -27,9 +27,23 @@ class debug_module_t : public abstract_device_t
return interrupt.find(hartid) != interrupt.end();
}
void set_halt_notification(uint32_t hartid) {
fprintf(stderr, "set debug halt_notification 0x%x\n", hartid);
halt_notification.insert(hartid);
}
void clear_halt_notification(uint32_t hartid) {
fprintf(stderr, "clear debug halt_notification 0x%x\n", hartid);
halt_notification.erase(hartid);
}
bool get_halt_notification(uint32_t hartid) const {
return halt_notification.find(hartid) != halt_notification.end();
}
private:
// Track which interrupts from module to debugger are set.
std::set<uint32_t> interrupt;
// Track which halt notifications from debugger to module are set.
std::set<uint32_t> halt_notification;
char debug_ram[DEBUG_RAM_SIZE];
};

6
riscv/decode.h

@ -229,12 +229,6 @@ private:
* automatically generated. */
/* TODO */
#include "/media/sf_tnewsome/Synced/SiFive/debug-spec/core_registers.tex.h"
#define DCSR_CAUSE_NONE 0
#define DCSR_CAUSE_SWBP 1
#define DCSR_CAUSE_HWBP 2
#define DCSR_CAUSE_DEBUGINT 3
#define DCSR_CAUSE_STEPPED 4
#define DCSR_CAUSE_HALT 5
#define DEBUG_START 0x100
#define DEBUG_ROM_START 0x800

8
riscv/encoding.h

@ -34,6 +34,14 @@
#define SSTATUS64_SD 0x8000000000000000
#define DCSR_PRV (3<<14)
#define DCSR_CAUSE 7
#define DCSR_CAUSE_NONE 0
#define DCSR_CAUSE_SWBP 1
#define DCSR_CAUSE_HWBP 2
#define DCSR_CAUSE_DEBUGINT 3
#define DCSR_CAUSE_STEP 4
#define DCSR_CAUSE_HALT 5
#define MIP_SSIP (1 << IRQ_S_SOFT)
#define MIP_HSIP (1 << IRQ_H_SOFT)

137
riscv/gdbserver.cc

@ -247,7 +247,8 @@ void circular_buffer_t<T>::append(const T *src, unsigned int count)
class halt_op_t : public operation_t
{
public:
halt_op_t(gdbserver_t& gdbserver) : operation_t(gdbserver) {};
halt_op_t(gdbserver_t& gdbserver, bool send_status=false) :
operation_t(gdbserver), send_status(send_status) {};
bool perform_step(unsigned int step) {
switch (step) {
@ -287,10 +288,33 @@ class halt_op_t : public operation_t
gs.sptbr_valid = false;
gs.pte_cache.clear();
if (send_status) {
switch (get_field(gs.dcsr, DCSR_CAUSE)) {
case DCSR_CAUSE_NONE:
fprintf(stderr, "Internal error. Processor halted without reason.\n");
abort();
case DCSR_CAUSE_HWBP:
case DCSR_CAUSE_DEBUGINT:
case DCSR_CAUSE_STEP:
case DCSR_CAUSE_HALT:
// There's no gdb code for this.
gs.send_packet("T05");
break;
case DCSR_CAUSE_SWBP:
gs.send_packet("T05swbreak:;");
break;
}
}
return true;
}
return false;
}
private:
bool send_status;
};
class continue_op_t : public operation_t
@ -461,8 +485,11 @@ class register_read_op_t : public operation_t
class memory_read_op_t : public operation_t
{
public:
memory_read_op_t(gdbserver_t& gdbserver, reg_t vaddr, unsigned int length) :
operation_t(gdbserver), vaddr(vaddr), length(length) {};
// Read length bytes from vaddr, storing the result into data.
// If data is NULL, send the result straight to gdb.
memory_read_op_t(gdbserver_t& gdbserver, reg_t vaddr, unsigned int length,
unsigned char *data=NULL) :
operation_t(gdbserver), vaddr(vaddr), length(length), data(data) {};
bool perform_step(unsigned int step)
{
@ -472,6 +499,8 @@ class memory_read_op_t : public operation_t
access_size = (paddr % length);
if (access_size == 0)
access_size = length;
if (access_size > 8)
access_size = 8;
gs.write_debug_ram(0, ld(S0, 0, (uint16_t) DEBUG_RAM_START + 16));
switch (access_size) {
@ -487,9 +516,6 @@ class memory_read_op_t : public operation_t
case 8:
gs.write_debug_ram(1, ld(S1, S0, 0));
break;
default:
gs.send_packet("E12");
return true;
}
gs.write_debug_ram(2, sd(S1, 0, (uint16_t) DEBUG_RAM_START + 24));
gs.write_debug_ram(3, jal(0, (uint32_t) (DEBUG_ROM_RESUME - (DEBUG_RAM_START + 4*3))));
@ -497,22 +523,30 @@ class memory_read_op_t : public operation_t
gs.write_debug_ram(5, paddr >> 32);
gs.set_interrupt(0);
gs.start_packet();
if (!data) {
gs.start_packet();
}
return false;
}
char buffer[3];
reg_t value = ((uint64_t) gs.read_debug_ram(7) << 32) | gs.read_debug_ram(6);
for (unsigned int i = 0; i < access_size; i++) {
sprintf(buffer, "%02x", (unsigned int) (value & 0xff));
gs.send(buffer);
if (data) {
*(data++) = value & 0xff;
} else {
sprintf(buffer, "%02x", (unsigned int) (value & 0xff));
gs.send(buffer);
}
value >>= 8;
}
length -= access_size;
paddr += access_size;
if (length == 0) {
gs.end_packet();
if (!data) {
gs.end_packet();
}
return true;
} else {
gs.write_debug_ram(4, paddr);
@ -523,8 +557,10 @@ class memory_read_op_t : public operation_t
}
private:
reg_t vaddr, paddr;
reg_t vaddr;
unsigned int length;
unsigned char* data;
reg_t paddr;
unsigned int access_size;
};
@ -1265,28 +1301,6 @@ void gdbserver_t::handle_extended(const std::vector<uint8_t> &packet)
extended_mode = true;
}
void software_breakpoint_t::insert(mmu_t* mmu)
{
if (size == 2) {
instruction = mmu->load_uint16(address);
mmu->store_uint16(address, C_EBREAK);
} else {
instruction = mmu->load_uint32(address);
mmu->store_uint32(address, EBREAK);
}
fprintf(stderr, ">>> Read %x from %lx\n", instruction, address);
}
void software_breakpoint_t::remove(mmu_t* mmu)
{
fprintf(stderr, ">>> write %x to %lx\n", instruction, address);
if (size == 2) {
mmu->store_uint16(address, instruction);
} else {
mmu->store_uint32(address, instruction);
}
}
void gdbserver_t::handle_breakpoint(const std::vector<uint8_t> &packet)
{
// insert: Z type,addr,kind
@ -1312,22 +1326,35 @@ void gdbserver_t::handle_breakpoint(const std::vector<uint8_t> &packet)
return send_packet("E53");
}
processor_t *p = sim->get_core(0);
die("handle_breakpoint");
/*
mmu_t* mmu = p->mmu;
add_operation(new collect_translation_info_op_t(*this, bp.address, bp.size));
if (insert) {
bp.insert(mmu);
// TODO: this only works on little-endian hosts.
unsigned char* swbp = new unsigned char[4];
if (bp.size == 2) {
swbp[0] = C_EBREAK & 0xff;
swbp[1] = (C_EBREAK >> 8) & 0xff;
} else {
swbp[0] = EBREAK & 0xff;
swbp[1] = (EBREAK >> 8) & 0xff;
swbp[2] = (EBREAK >> 16) & 0xff;
swbp[3] = (EBREAK >> 24) & 0xff;
}
add_operation(new memory_read_op_t(*this, bp.address, bp.size, bp.instruction));
add_operation(new memory_write_op_t(*this, bp.address, bp.size, swbp));
breakpoints[bp.address] = bp;
} else {
bp = breakpoints[bp.address];
bp.remove(mmu);
unsigned char* instruction = new unsigned char[4];
memcpy(instruction, bp.instruction, 4);
add_operation(new memory_write_op_t(*this, bp.address, bp.size, instruction));
breakpoints.erase(bp.address);
}
mmu->flush_icache();
sim->debug_mmu->flush_icache();
*/
// TODO mmu->flush_icache();
// TODO sim->debug_mmu->flush_icache();
return send_packet("OK");
}
@ -1431,29 +1458,11 @@ void gdbserver_t::handle()
}
}
/* TODO
if (running && p->halted) {
// The core was running, but now it's halted. Better tell gdb.
switch (p->halt_reason) {
case HR_NONE:
fprintf(stderr, "Internal error. Processor halted without reason.\n");
abort();
case HR_STEPPED:
case HR_INTERRUPT:
case HR_CMDLINE:
case HR_ATTACHED:
// There's no gdb code for this.
send_packet("T05");
break;
case HR_SWBP:
send_packet("T05swbreak:;");
break;
}
send_packet("T00");
// TODO: Actually include register values here
running = false;
bool halt_notification = sim->debug_module.get_halt_notification(0);
if (halt_notification) {
sim->debug_module.clear_halt_notification(0);
add_operation(new halt_op_t(*this, true));
}
*/
this->read();
this->write();

5
riscv/gdbserver.h

@ -51,10 +51,7 @@ class software_breakpoint_t
public:
reg_t address;
unsigned int size;
uint32_t instruction;
void insert(mmu_t* mmu);
void remove(mmu_t* mmu);
unsigned char instruction[4];
};
class gdbserver_t;

Loading…
Cancel
Save