aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--riscv/execute.cc5
-rw-r--r--riscv/gdbserver.cc89
-rw-r--r--riscv/gdbserver.h15
-rw-r--r--riscv/processor.cc6
4 files changed, 102 insertions, 13 deletions
diff --git a/riscv/execute.cc b/riscv/execute.cc
index b632600..4bfaf4a 100644
--- a/riscv/execute.cc
+++ b/riscv/execute.cc
@@ -59,11 +59,8 @@ void processor_t::step(size_t n)
halted = false;
n = 1;
}
- if (halted) {
- return;
- }
- while (run && n > 0) {
+ while (run && !halted && n > 0) {
size_t instret = 0;
reg_t pc = state.pc;
mmu_t* _mmu = mmu;
diff --git a/riscv/gdbserver.cc b/riscv/gdbserver.cc
index e8517ae..83bc013 100644
--- a/riscv/gdbserver.cc
+++ b/riscv/gdbserver.cc
@@ -17,6 +17,9 @@
#include "gdbserver.h"
#include "mmu.h"
+#define C_EBREAK 0x9002
+#define EBREAK 0x00100073
+
template <typename T>
unsigned int circular_buffer_t<T>::size() const
{
@@ -96,6 +99,12 @@ gdbserver_t::gdbserver_t(uint16_t port, sim_t *sim) :
}
fcntl(socket_fd, F_SETFL, O_NONBLOCK);
+ int reuseaddr = 1;
+ if (setsockopt(socket_fd, SOL_SOCKET, SO_REUSEADDR, &reuseaddr,
+ sizeof(int)) == -1) {
+ fprintf(stderr, "failed setsockopt: %s (%d)\n", strerror(errno), errno);
+ abort();
+ }
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
@@ -346,7 +355,7 @@ void gdbserver_t::handle_register_read(const std::vector<uint8_t> &packet)
std::vector<uint8_t>::const_iterator iter = packet.begin() + 2;
unsigned int n = consume_hex_number(iter, packet.end());
if (*iter != '#')
- return send_packet("E16"); // EINVAL
+ return send_packet("E01");
processor_t *p = sim->get_core(0);
send("$");
@@ -356,7 +365,7 @@ void gdbserver_t::handle_register_read(const std::vector<uint8_t> &packet)
} else if (n == 0x20) {
send(p->state.pc);
} else {
- send("E16"); // EINVAL
+ send("E02");
}
send_running_checksum();
@@ -369,11 +378,11 @@ void gdbserver_t::handle_memory_read(const std::vector<uint8_t> &packet)
std::vector<uint8_t>::const_iterator iter = packet.begin() + 2;
reg_t address = consume_hex_number(iter, packet.end());
if (*iter != ',')
- return send_packet("E16"); // EINVAL
+ return send_packet("E10");
iter++;
reg_t length = consume_hex_number(iter, packet.end());
if (*iter != '#')
- return send_packet("E16"); // EINVAL
+ return send_packet("E11");
send("$");
running_checksum = 0;
@@ -394,18 +403,18 @@ void gdbserver_t::handle_memory_binary_write(const std::vector<uint8_t> &packet)
std::vector<uint8_t>::const_iterator iter = packet.begin() + 2;
reg_t address = consume_hex_number(iter, packet.end());
if (*iter != ',')
- return send_packet("E16"); // EINVAL
+ return send_packet("E20");
iter++;
reg_t length = consume_hex_number(iter, packet.end());
if (*iter != ':')
- return send_packet("E16"); // EINVAL
+ return send_packet("E21");
iter++;
processor_t *p = sim->get_core(0);
mmu_t* mmu = sim->debug_mmu;
for (unsigned int i = 0; i < length; i++) {
if (iter == packet.end()) {
- return send_packet("E16"); // EINVAL
+ return send_packet("E22");
}
mmu->store_uint8(address + i, *iter);
iter++;
@@ -424,7 +433,7 @@ void gdbserver_t::handle_continue(const std::vector<uint8_t> &packet)
std::vector<uint8_t>::const_iterator iter = packet.begin() + 2;
p->state.pc = consume_hex_number(iter, packet.end());
if (*iter != '#')
- return send_packet("E16"); // EINVAL
+ return send_packet("E30");
}
p->set_halted(false);
@@ -439,7 +448,7 @@ void gdbserver_t::handle_step(const std::vector<uint8_t> &packet)
std::vector<uint8_t>::const_iterator iter = packet.begin() + 2;
p->state.pc = consume_hex_number(iter, packet.end());
if (*iter != '#')
- return send_packet("E16"); // EINVAL
+ return send_packet("E40");
}
p->set_single_step(true);
@@ -462,6 +471,65 @@ 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);
+ }
+}
+
+void software_breakpoint_t::remove(mmu_t* mmu)
+{
+ 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
+ // remove: z type,addr,kind
+
+ software_breakpoint_t bp;
+ bool insert = (packet[1] == 'Z');
+ std::vector<uint8_t>::const_iterator iter = packet.begin() + 2;
+ int type = consume_hex_number(iter, packet.end());
+ if (*iter != ',')
+ return send_packet("E50");
+ iter++;
+ bp.address = consume_hex_number(iter, packet.end());
+ if (*iter != ',')
+ return send_packet("E51");
+ iter++;
+ bp.size = consume_hex_number(iter, packet.end());
+ // There may be more options after a ; here, but we don't support that.
+ if (*iter != '#')
+ return send_packet("E52");
+
+ if (bp.size != 2 && bp.size != 4) {
+ return send_packet("E53");
+ }
+
+ processor_t *p = sim->get_core(0);
+ mmu_t* mmu = sim->debug_mmu;
+ if (insert) {
+ bp.insert(mmu);
+ breakpoints[bp.address] = bp;
+
+ } else {
+ bp = breakpoints[bp.address];
+ bp.remove(mmu);
+ breakpoints.erase(bp.address);
+ }
+ return send_packet("OK");
+}
+
void gdbserver_t::handle_packet(const std::vector<uint8_t> &packet)
{
if (compute_checksum(packet) != extract_checksum(packet)) {
@@ -497,6 +565,9 @@ void gdbserver_t::handle_packet(const std::vector<uint8_t> &packet)
return handle_continue(packet);
case 's':
return handle_step(packet);
+ case 'z':
+ case 'Z':
+ return handle_breakpoint(packet);
}
// Not supported.
diff --git a/riscv/gdbserver.h b/riscv/gdbserver.h
index 178003d..67ae6d0 100644
--- a/riscv/gdbserver.h
+++ b/riscv/gdbserver.h
@@ -42,6 +42,18 @@ public:
void append(const T *src, unsigned int count);
};
+// Class to track software breakpoints that we set.
+class software_breakpoint_t
+{
+public:
+ reg_t address;
+ unsigned int size;
+ uint32_t instruction;
+
+ void insert(mmu_t* mmu);
+ void remove(mmu_t* mmu);
+};
+
class gdbserver_t
{
public:
@@ -55,6 +67,7 @@ public:
void handle_packet(const std::vector<uint8_t> &packet);
void handle_interrupt();
+ void handle_breakpoint(const std::vector<uint8_t> &packet);
void handle_continue(const std::vector<uint8_t> &packet);
void handle_extended(const std::vector<uint8_t> &packet);
void handle_general_registers_read(const std::vector<uint8_t> &packet);
@@ -78,6 +91,8 @@ private:
// but it isn't, we need to tell gdb about it.
bool running;
+ std::map <reg_t, software_breakpoint_t> breakpoints;
+
// Read pending data from the client.
void read();
void write();
diff --git a/riscv/processor.cc b/riscv/processor.cc
index 05fdb1c..1c53986 100644
--- a/riscv/processor.cc
+++ b/riscv/processor.cc
@@ -208,6 +208,12 @@ void processor_t::take_trap(trap_t& t, reg_t epc)
fprintf(stderr, "core %3d: exception %s, epc 0x%016" PRIx64 "\n",
id, t.name(), epc);
+ if (t.cause() == CAUSE_BREAKPOINT) {
+ // TODO: Only do this if there is a debugger attached.
+ halted = true;
+ return;
+ }
+
// by default, trap to M-mode, unless delegated to S-mode
reg_t bit = t.cause();
reg_t deleg = state.medeleg;