From 1b0d2d61b38c9ed49c6acf1ff2b30e98593a85b4 Mon Sep 17 00:00:00 2001 From: Simon Gellis Date: Thu, 10 Oct 2024 21:58:40 -0400 Subject: [PATCH] Implement breakpoints (untested) --- include/server.h | 19 ++++++++- main.c | 16 +++---- request.c | 1 + server.c | 109 ++++++++++++++++++++++++++++++++++++++++++----- 4 files changed, 126 insertions(+), 19 deletions(-) diff --git a/include/server.h b/include/server.h index 314f5c5..39260b4 100644 --- a/include/server.h +++ b/include/server.h @@ -6,13 +6,30 @@ #include #include +typedef enum rdb_server_stop_reason_t { + /* not even stopped */ + stop_reason_none, + /* we are stepping */ + stop_reason_trace, + /* we hit an actual breakpoint */ + stop_reason_breakpoint, + /* the user hit pause */ + stop_reason_trap, + /* some opcode is not implemented */ + stop_reason_not_implemented +} rdb_server_stop_reason_t; + +#define RDB_SERVER_MAX_BREAKPOINTS 16 typedef struct RdbServer { VB *sim; bool running; + uint32_t brks[RDB_SERVER_MAX_BREAKPOINTS]; + uint32_t brkslen; + rdb_server_stop_reason_t stopreason; } RdbServer; void rdbServerInit(RdbServer *srv, VB *sim); int rdbServerHandleCommand(RdbServer *srv, CommandBuf *cmd, RdbResponse *res); -int rdbServerBreak(RdbServer *srv, RdbResponse *res); +int rdbServerSendStopPacket(RdbServer *srv, RdbResponse *res); #endif \ No newline at end of file diff --git a/main.c b/main.c index 551ea00..72719af 100644 --- a/main.c +++ b/main.c @@ -48,13 +48,15 @@ int server(int connfd, VB *sim) { cycles = MAX_STEP_CYCLES; brk = vbEmulate(sim, &cycles); if (brk) { - /* We hit a breakpoint */ + /* We stopped for some reason */ if (brk == -1) { - /* actually, not implemented */ - rdbServerBreak(&srv, &res); - } else { - fprintf(stderr, "surprising response %d from vbEmulate\n", brk); - return -1; + /* the reason was "opcode not implemented" */ + srv.running = false; + srv.stopreason = stop_reason_not_implemented; + } + result = rdbServerSendStopPacket(&srv, &res); + if (result != 0) { + return result; } } else { sleepNanos((MAX_STEP_CYCLES - cycles) * 50); @@ -139,11 +141,9 @@ int main(int argc, char** argv) { return 1; } /* relevant state at the start of the physics sim's main */ - /* vbSetProgramCounter(sim, 0x070002ba); vbSetProgramRegister(sim, 3, 0x0500ffc0); vbSetProgramRegister(sim, 4, 0x05008000); - */ if (argc > 2) { char *end; diff --git a/request.c b/request.c index c3396a5..3964a30 100644 --- a/request.c +++ b/request.c @@ -8,6 +8,7 @@ void rdbRequestInit(RdbRequest *req, int connfd, char *buf, size_t buflen) { req->connfd = connfd; req->outbuf = buf; + req->outbuflen = buflen; req->blocking = true; rdbRequestReset(req); } diff --git a/server.c b/server.c index db05f8f..b17778c 100644 --- a/server.c +++ b/server.c @@ -69,9 +69,59 @@ const uint32_t SYSTEM_REGISTERS[] = { const uint32_t PC_INDEX = 32 + 13; +/* TODO: this should use userdata */ +static void *SERVER_POINTER; +static int onExecute(VB *sim, uint32_t address, const uint16_t *code, int length) { + uint32_t i; + RdbServer *srv = SERVER_POINTER; + + (void)sim; + (void)code; + (void)length; + for (i = 0; i < srv->brkslen; ++i) { + if (srv->brks[i] == address) { + srv->stopreason = stop_reason_breakpoint; + return 1; + } + } + return 0; +} + +static bool addBreakpoint(RdbServer *srv, uint32_t address) { + uint32_t i; + for (i = 0; i < srv->brkslen; ++i) { + if (srv->brks[i] == address) { + /* This breakpoint is already set */ + return true; + } + } + if (i == RDB_SERVER_MAX_BREAKPOINTS) { + /* We've added too many breakpoints */ + return false; + } + srv->brks[i] = address; + ++srv->brkslen; + return true; +} + +static void removeBreakpoint(RdbServer *srv, uint32_t address) { + uint32_t i; + for (i = 0; i < srv->brkslen; ++i) { + if (srv->brks[i] == address) { + srv->brks[i] = srv->brks[srv->brkslen - 1]; + --srv->brkslen; + return; + } + } +} + void rdbServerInit(RdbServer *srv, VB *sim) { srv->sim = sim; srv->running = false; + srv->brkslen = 0; + srv->stopreason = stop_reason_none; + SERVER_POINTER = srv; + vbSetCallback(sim, VB_EXECUTE, (void*)(uint64_t)&onExecute); } int rdbServerHandleCommand(RdbServer *srv, CommandBuf *cmd, RdbResponse *res) { @@ -199,21 +249,19 @@ int rdbServerHandleCommand(RdbServer *srv, CommandBuf *cmd, RdbResponse *res) { /* The debugger has told us to run until we are stopped. */ /* Don't send a response to this until we receive an ETX (when the debugger pauses us). */ srv->running = true; + srv->stopreason = stop_reason_none; return 0; } if (cmdMatchStr(cmd, "\x03")) { /* Received an ETX, indicating that the server wants to cancel the "c" command from before. */ srv->running = false; + srv->stopreason = stop_reason_trap; /* Send the response to the "c" command from before. */ - rdbResponseWriteStr(res, "T05thread:p1.t1;threads:p1.t1"); - return rdbResponseSendPacket(res); + return rdbServerSendStopPacket(srv, res); } if (cmdMatchStr(cmd, "?")) { /* The debugger has asked us why we stopped */ - rdbResponseWriteStr(res, "T"); - rdbResponseWriteStr(res, srv->running ? "00" : "05"); - rdbResponseWriteStr(res, "thread:p1.t1;threads:p1.t1;"); - return rdbResponseSendPacket(res); + return rdbServerSendStopPacket(srv, res); } if (cmdMatchStr(cmd, "m")) { /* read memory */ @@ -244,14 +292,55 @@ int rdbServerHandleCommand(RdbServer *srv, CommandBuf *cmd, RdbResponse *res) { rdbResponseWriteStr(res, "OK"); return rdbResponseSendPacket(res); } + if (cmdMatchStr(cmd, "Z0,")) { + /* set a breakpoint */ + uint32_t address; + if (!cmdMatchHexNumber(cmd, &address)) return -1; + if (!cmdMatchStr(cmd, ",0")) return -1; + + if (!addBreakpoint(srv, address)) return -1; + rdbResponseWriteStr(res, "OK"); + return rdbResponseSendPacket(res); + } + if (cmdMatchStr(cmd, "z0,")) { + /* remove a breakpoint */ + uint32_t address; + if (!cmdMatchHexNumber(cmd, &address)) return -1; + if (!cmdMatchStr(cmd, ",0")) return -1; + + removeBreakpoint(srv, address); + rdbResponseWriteStr(res, "OK"); + return rdbResponseSendPacket(res); + } fprintf(stderr, "Unrecognized command.\n"); return rdbResponseSendPacket(res); } -int rdbServerBreak(RdbServer *srv, RdbResponse *res) { - srv->running = false; +int rdbServerSendStopPacket(RdbServer *srv, RdbResponse *res) { rdbResponseBeginPacket(res); - rdbResponseWriteStr(res, "T05:thread:p1.t1;threads:p1.t1;"); + switch (srv->stopreason) { + case stop_reason_trace: + case stop_reason_none: + rdbResponseWriteStr(res, "T00"); + break; + default: + rdbResponseWriteStr(res, "T05"); + } + rdbResponseWriteStr(res, "thread:p1.t1;threads:p1.t1;"); + switch (srv->stopreason) { + case stop_reason_trace: + rdbResponseWriteStr(res, "reason:trace;"); + break; + case stop_reason_breakpoint: + rdbResponseWriteStr(res, "reason:breakpoint;"); + break; + case stop_reason_trap: + rdbResponseWriteStr(res, "reason:trap;"); + break; + case stop_reason_not_implemented: + rdbResponseWriteStr(res, "reason:exception;description:opcode not implemented;"); + break; + default: break; + } return rdbResponseSendPacket(res); } -