Implement breakpoints (untested)

This commit is contained in:
Simon Gellis 2024-10-10 21:58:40 -04:00
parent bb680f9be4
commit 1b0d2d61b3
4 changed files with 126 additions and 19 deletions

View File

@ -6,13 +6,30 @@
#include <stdbool.h> #include <stdbool.h>
#include <vb.h> #include <vb.h>
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 { typedef struct RdbServer {
VB *sim; VB *sim;
bool running; bool running;
uint32_t brks[RDB_SERVER_MAX_BREAKPOINTS];
uint32_t brkslen;
rdb_server_stop_reason_t stopreason;
} RdbServer; } RdbServer;
void rdbServerInit(RdbServer *srv, VB *sim); void rdbServerInit(RdbServer *srv, VB *sim);
int rdbServerHandleCommand(RdbServer *srv, CommandBuf *cmd, RdbResponse *res); int rdbServerHandleCommand(RdbServer *srv, CommandBuf *cmd, RdbResponse *res);
int rdbServerBreak(RdbServer *srv, RdbResponse *res); int rdbServerSendStopPacket(RdbServer *srv, RdbResponse *res);
#endif #endif

16
main.c
View File

@ -48,13 +48,15 @@ int server(int connfd, VB *sim) {
cycles = MAX_STEP_CYCLES; cycles = MAX_STEP_CYCLES;
brk = vbEmulate(sim, &cycles); brk = vbEmulate(sim, &cycles);
if (brk) { if (brk) {
/* We hit a breakpoint */ /* We stopped for some reason */
if (brk == -1) { if (brk == -1) {
/* actually, not implemented */ /* the reason was "opcode not implemented" */
rdbServerBreak(&srv, &res); srv.running = false;
} else { srv.stopreason = stop_reason_not_implemented;
fprintf(stderr, "surprising response %d from vbEmulate\n", brk); }
return -1; result = rdbServerSendStopPacket(&srv, &res);
if (result != 0) {
return result;
} }
} else { } else {
sleepNanos((MAX_STEP_CYCLES - cycles) * 50); sleepNanos((MAX_STEP_CYCLES - cycles) * 50);
@ -139,11 +141,9 @@ int main(int argc, char** argv) {
return 1; return 1;
} }
/* relevant state at the start of the physics sim's main */ /* relevant state at the start of the physics sim's main */
/*
vbSetProgramCounter(sim, 0x070002ba); vbSetProgramCounter(sim, 0x070002ba);
vbSetProgramRegister(sim, 3, 0x0500ffc0); vbSetProgramRegister(sim, 3, 0x0500ffc0);
vbSetProgramRegister(sim, 4, 0x05008000); vbSetProgramRegister(sim, 4, 0x05008000);
*/
if (argc > 2) { if (argc > 2) {
char *end; char *end;

View File

@ -8,6 +8,7 @@
void rdbRequestInit(RdbRequest *req, int connfd, char *buf, size_t buflen) { void rdbRequestInit(RdbRequest *req, int connfd, char *buf, size_t buflen) {
req->connfd = connfd; req->connfd = connfd;
req->outbuf = buf; req->outbuf = buf;
req->outbuflen = buflen;
req->blocking = true; req->blocking = true;
rdbRequestReset(req); rdbRequestReset(req);
} }

109
server.c
View File

@ -69,9 +69,59 @@ const uint32_t SYSTEM_REGISTERS[] = {
const uint32_t PC_INDEX = 32 + 13; 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) { void rdbServerInit(RdbServer *srv, VB *sim) {
srv->sim = sim; srv->sim = sim;
srv->running = false; 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) { 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. */ /* 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). */ /* Don't send a response to this until we receive an ETX (when the debugger pauses us). */
srv->running = true; srv->running = true;
srv->stopreason = stop_reason_none;
return 0; return 0;
} }
if (cmdMatchStr(cmd, "\x03")) { if (cmdMatchStr(cmd, "\x03")) {
/* Received an ETX, indicating that the server wants to cancel the "c" command from before. */ /* Received an ETX, indicating that the server wants to cancel the "c" command from before. */
srv->running = false; srv->running = false;
srv->stopreason = stop_reason_trap;
/* Send the response to the "c" command from before. */ /* Send the response to the "c" command from before. */
rdbResponseWriteStr(res, "T05thread:p1.t1;threads:p1.t1"); return rdbServerSendStopPacket(srv, res);
return rdbResponseSendPacket(res);
} }
if (cmdMatchStr(cmd, "?")) { if (cmdMatchStr(cmd, "?")) {
/* The debugger has asked us why we stopped */ /* The debugger has asked us why we stopped */
rdbResponseWriteStr(res, "T"); return rdbServerSendStopPacket(srv, res);
rdbResponseWriteStr(res, srv->running ? "00" : "05");
rdbResponseWriteStr(res, "thread:p1.t1;threads:p1.t1;");
return rdbResponseSendPacket(res);
} }
if (cmdMatchStr(cmd, "m")) { if (cmdMatchStr(cmd, "m")) {
/* read memory */ /* read memory */
@ -244,14 +292,55 @@ int rdbServerHandleCommand(RdbServer *srv, CommandBuf *cmd, RdbResponse *res) {
rdbResponseWriteStr(res, "OK"); rdbResponseWriteStr(res, "OK");
return rdbResponseSendPacket(res); 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"); fprintf(stderr, "Unrecognized command.\n");
return rdbResponseSendPacket(res); return rdbResponseSendPacket(res);
} }
int rdbServerBreak(RdbServer *srv, RdbResponse *res) { int rdbServerSendStopPacket(RdbServer *srv, RdbResponse *res) {
srv->running = false;
rdbResponseBeginPacket(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); return rdbResponseSendPacket(res);
} }