diff --git a/include/request.h b/include/request.h index c5f2603..9a1cb10 100644 --- a/include/request.h +++ b/include/request.h @@ -1,6 +1,7 @@ #ifndef RDBSERVER_REQUEST_H #define RDBSERVER_REQUEST_H +#include #include #define INBUF_LEN 256 @@ -29,15 +30,14 @@ typedef struct RdbRequest { size_t index; } inbuf; rdb_read_state_t state; - char *cmd; - size_t cmdlen; - size_t outlen; + char *outbuf; + size_t outbuflen; char chk; } RdbRequest; void rdb_request_init(RdbRequest *req, int connfd, char *cmd, size_t cmdlen); void rdb_request_reset(RdbRequest *req); void rdb_request_set_blocking(RdbRequest *req, bool blocking); -rdb_read_result_t rdb_request_read(RdbRequest *req, size_t *len); +rdb_read_result_t rdb_request_read(RdbRequest *req, CommandBuf *cmd); #endif \ No newline at end of file diff --git a/include/server.h b/include/server.h new file mode 100644 index 0000000..3131054 --- /dev/null +++ b/include/server.h @@ -0,0 +1,11 @@ +#ifndef RDBSERVER_SERVER_H_ +#define RDBSERVER_SERVER_H_ + +#include +#include +#include +#include + +int handle_command(RdbClient *client, CommandBuf *cmd, VB *sim, bool *running); + +#endif \ No newline at end of file diff --git a/main.c b/main.c index ce21ea6..e1dea5d 100644 --- a/main.c +++ b/main.c @@ -1,9 +1,8 @@ #include #include #include -#include +#include #include -#include #include #include #include @@ -11,217 +10,10 @@ const size_t BUFLEN = 8096; -const char* REGISTERS[] = { - "name:r0;bitsize:32;offset:0;encoding:uint;format:hex;set:General Purpose Registers;dwarf:0", - "name:r1;bitsize:32;offset:4;encoding:uint;format:hex;set:General Purpose Registers;dwarf:0", - "name:fp;alt-name:r2;bitsize:32;offset:8;encoding:uint;format:hex;set:General Purpose Registers;dwarf:0;generic:fp", - "name:sp;alt-name:r3;bitsize:32;offset:12;encoding:uint;format:hex;set:General Purpose Registers;dwarf:0;generic:sp", - "name:gp;alt-name:r4;bitsize:32;offset:16;encoding:uint;format:hex;set:General Purpose Registers;dwarf:0", - "name:tp;alt-name:r5;bitsize:32;offset:20;encoding:uint;format:hex;set:General Purpose Registers;dwarf:0", - "name:r6;bitsize:32;offset:24;encoding:uint;format:hex;set:General Purpose Registers;dwarf:0;generic:arg1", - "name:r7;bitsize:32;offset:28;encoding:uint;format:hex;set:General Purpose Registers;dwarf:0;generic:arg2", - "name:r8;bitsize:32;offset:32;encoding:uint;format:hex;set:General Purpose Registers;dwarf:0;generic:arg3", - "name:r9;bitsize:32;offset:36;encoding:uint;format:hex;set:General Purpose Registers;dwarf:0;generic:arg4", - "name:r10;bitsize:32;offset:40;encoding:uint;format:hex;set:General Purpose Registers;dwarf:0", - "name:r11;bitsize:32;offset:44;encoding:uint;format:hex;set:General Purpose Registers;dwarf:0", - "name:r12;bitsize:32;offset:48;encoding:uint;format:hex;set:General Purpose Registers;dwarf:0", - "name:r13;bitsize:32;offset:52;encoding:uint;format:hex;set:General Purpose Registers;dwarf:0", - "name:r14;bitsize:32;offset:56;encoding:uint;format:hex;set:General Purpose Registers;dwarf:0", - "name:r15;bitsize:32;offset:60;encoding:uint;format:hex;set:General Purpose Registers;dwarf:0", - "name:r16;bitsize:32;offset:64;encoding:uint;format:hex;set:General Purpose Registers;dwarf:0", - "name:r17;bitsize:32;offset:68;encoding:uint;format:hex;set:General Purpose Registers;dwarf:0", - "name:r18;bitsize:32;offset:72;encoding:uint;format:hex;set:General Purpose Registers;dwarf:0", - "name:r19;bitsize:32;offset:76;encoding:uint;format:hex;set:General Purpose Registers;dwarf:0", - "name:r20;bitsize:32;offset:80;encoding:uint;format:hex;set:General Purpose Registers;dwarf:0", - "name:r21;bitsize:32;offset:84;encoding:uint;format:hex;set:General Purpose Registers;dwarf:0", - "name:r22;bitsize:32;offset:88;encoding:uint;format:hex;set:General Purpose Registers;dwarf:0", - "name:r23;bitsize:32;offset:92;encoding:uint;format:hex;set:General Purpose Registers;dwarf:0", - "name:r24;bitsize:32;offset:96;encoding:uint;format:hex;set:General Purpose Registers;dwarf:0", - "name:r25;bitsize:32;offset:100;encoding:uint;format:hex;set:General Purpose Registers;dwarf:0", - "name:r26;bitsize:32;offset:104;encoding:uint;format:hex;set:General Purpose Registers;dwarf:0", - "name:r27;bitsize:32;offset:108;encoding:uint;format:hex;set:General Purpose Registers;dwarf:0", - "name:r28;bitsize:32;offset:112;encoding:uint;format:hex;set:General Purpose Registers;dwarf:0", - "name:r29;bitsize:32;offset:116;encoding:uint;format:hex;set:General Purpose Registers;dwarf:0", - "name:r30;bitsize:32;offset:120;encoding:uint;format:hex;set:General Purpose Registers;dwarf:0", - "name:lp;alt-name:r31;bitsize:32;offset:124;encoding:uint;format:hex;set:General Purpose Registers;dwarf:0;generic:ra", - "name:eipc;alt-name:sr0;bitsize:32;offset:128;encoding:uint;format:hex;set:Special Registers;dwarf:0", - "name:eipsw;alt-name:sr1;bitsize:32;offset:132;encoding:uint;format:hex;set:Special Registers;dwarf:0", - "name:fepc;alt-name:sr2;bitsize:32;offset:136;encoding:uint;format:hex;set:Special Registers;dwarf:0", - "name:fepsw;alt-name:sr3;bitsize:32;offset:140;encoding:uint;format:hex;set:Special Registers;dwarf:0", - "name:ecr;alt-name:sr4;bitsize:32;offset:144;encoding:uint;format:hex;set:Special Registers;dwarf:0", - "name:psw;alt-name:sr5;bitsize:32;offset:148;encoding:uint;format:hex;set:Special Registers;dwarf:0;generic:flags", - "name:pir;alt-name:sr6;bitsize:32;offset:152;encoding:uint;format:hex;set:Special Registers;dwarf:0", - "name:tkcw;alt-name:sr7;bitsize:32;offset:156;encoding:uint;format:hex;set:Special Registers;dwarf:0", - "name:chcw;alt-name:sr24;bitsize:32;offset:160;encoding:uint;format:hex;set:Special Registers;dwarf:0", - "name:adtre;alt-name:sr25;bitsize:32;offset:164;encoding:uint;format:hex;set:Special Registers;dwarf:0", - "name:sr29;bitsize:32;offset:168;encoding:uint;format:hex;set:Special Registers;dwarf:0", - "name:sr30;bitsize:32;offset:172;encoding:uint;format:hex;set:Special Registers;dwarf:0", - "name:sr31;bitsize:32;offset:176;encoding:uint;format:hex;set:Special Registers;dwarf:0", - "name:pc;bitsize:32;offset:180;encoding:uint;format:hex;set:Special Registers;dwarf:0;generic:pc", -}; - -const uint32_t SYSTEM_REGISTERS[] = { - VB_EIPC, - VB_EIPSW, - VB_FEPC, - VB_FEPSW, - VB_ECR, - VB_PSW, - VB_PIR, - VB_TKCW, - VB_CHCW, - VB_ADTRE, - 29, - 30, - 31, -}; - -const uint32_t PC_INDEX = 32 + 13; - -int handle_command(RdbClient *client, CommandBuf *cmd, VB *sim, bool *running) { - rdb_client_begin_packet(client); - - if (cmd_match_only_str(cmd, "\x03")) { - *running = false; - rdb_client_write_str(client, "T05thread:p1.t1;threads:p1.t1"); - return rdb_client_send_packet(client); - } - if (cmd_match_only_str(cmd, "QStartNoAckMode")) { - client->should_ack = false; - rdb_client_write_str(client, "OK"); - return rdb_client_send_packet(client); - } - if (cmd_match_str(cmd, "qSupported")) { - rdb_client_write_str(client, "no-resumed+;multiprocess;vContSupported;QNonStop+"); - return rdb_client_send_packet(client); - } - if (cmd_match_only_str(cmd, "QThreadSuffixSupported")) { - rdb_client_write_str(client, "OK"); - return rdb_client_send_packet(client); - } - if (cmd_match_only_str(cmd, "QListThreadsInStopReply")) { - rdb_client_write_str(client, "OK"); - return rdb_client_send_packet(client); - } - if (cmd_match_only_str(cmd, "qHostInfo")) { - rdb_client_write_str(client, "triple:"); - rdb_client_write_str_hex(client, "v810-unknown-vb"); - rdb_client_write_str(client, ";endian:little;ptrsize:4;"); - return rdb_client_send_packet(client); - } - if (cmd_match_only_str(cmd, "qProcessInfo")) { - rdb_client_write_str(client, "pid:1;triple:"); - rdb_client_write_str_hex(client, "v810-unknown-vb"); - rdb_client_write_str(client, "endian:little;ptrsize:4;"); - return rdb_client_send_packet(client); - } - if (cmd_match_str(cmd, "qRegisterInfo")) { - uint32_t reg_no; - if (!cmd_match_hex_number(cmd, ®_no)) return 1; - if (reg_no <= PC_INDEX) { - rdb_client_write_str(client, REGISTERS[reg_no]); - } - return rdb_client_send_packet(client); - } - if (cmd_match_only_str(cmd, "qfThreadInfo")) { - rdb_client_write_str(client, "mp1.t1"); - return rdb_client_send_packet(client); - } - if (cmd_match_only_str(cmd, "qsThreadInfo")) { - rdb_client_write_str(client, "l"); - return rdb_client_send_packet(client); - } - if (cmd_match_only_str(cmd, "vCont?")) { - rdb_client_write_str(client, "c;C;s;S"); - return rdb_client_send_packet(client); - } - if (cmd_match_only_str(cmd, "qVAttachOrWaitSupported")) { - return rdb_client_send_packet(client); - } - if (cmd_match_only_str(cmd, "qC")) { - rdb_client_write_str(client, "QCp1.t1"); - return rdb_client_send_packet(client); - } - if (cmd_match_str(cmd, "p")) { - uint32_t reg_no; - if (!cmd_match_hex_number(cmd, ®_no)) return 1; - int32_t reg_value; - if (reg_no == PC_INDEX) { - reg_value = vbGetProgramCounter(sim); - } else if (reg_no > 31) { - reg_value = vbGetSystemRegister(sim, SYSTEM_REGISTERS[reg_no - 32]); - } else { - reg_value = vbGetProgramRegister(sim, reg_no); - } - rdb_client_write_i32_hex(client, reg_value); - return rdb_client_send_packet(client); - } - if (cmd_match_str(cmd, "P")) { - uint32_t reg_no; - char reg_bytes[4]; - if (!cmd_match_hex_number(cmd, ®_no)) return -1; - if (!cmd_match_str(cmd, "=")) return -1; - if (!cmd_match_hex_bytes(cmd, 4, reg_bytes)) return -1; - - int32_t reg_value = ((uint32_t) (reg_bytes[3]) << 24) | - ((uint32_t) (reg_bytes[2]) << 16) | - ((uint32_t) (reg_bytes[1]) << 8) | - ((uint32_t) reg_bytes[0]); - - if (reg_no == PC_INDEX) { - vbSetProgramCounter(sim, reg_value); - } else if (reg_no > 31) { - vbSetSystemRegister(sim, SYSTEM_REGISTERS[reg_no - 32], reg_value); - } else { - vbSetProgramRegister(sim, reg_no, reg_value); - } - rdb_client_write_str(client, "OK"); - return rdb_client_send_packet(client); - } - if (cmd_match_str(cmd, "Hc-1")) { - rdb_client_write_str(client, "OK"); - return rdb_client_send_packet(client); - } - if (cmd_match_only_str(cmd, "c")) { - printf("running until we hit a breakpoint or the server stops us\n"); - *running = true; - return 0; - } - if (cmd_match_only_str(cmd, "?")) { - rdb_client_write_str(client, "T00thread:p1.t1;threads:p1.t1;"); - return rdb_client_send_packet(client); - } - if (cmd_match_str(cmd, "qMemoryRegionInfo:")) { - rdb_client_write_str(client, "start:0;size:100000000;permissions:rx;name:"); - rdb_client_write_str_hex(client, "ROM"); - rdb_client_write_str(client, ";"); - return rdb_client_send_packet(client); - } - if (cmd_match_str(cmd, "m")) { - // read memory - uint32_t address; - uint32_t len; - if (!cmd_match_hex_number(cmd, &address)) return -1; - if (!cmd_match_str(cmd, ",")) return -1; - if (!cmd_match_hex_number(cmd, &len)) return -1; - - printf("read %d bytes from %d\n", len, address); - for (uint32_t i = 0; i < len; ++i) { - uint8_t byte = vbRead(sim, address + i, VB_U8); - rdb_client_write_i8_hex(client, byte); - } - return rdb_client_send_packet(client); - } - fprintf(stderr, "Unrecognized command.\n"); - return rdb_client_send_packet(client); -} - - int server(int connfd, VB *sim) { RdbRequest req; RdbClient client; char buf[BUFLEN]; - size_t len; rdb_request_init(&req, connfd, buf, BUFLEN); rdb_client_init(&client, connfd); @@ -229,7 +21,8 @@ int server(int connfd, VB *sim) { bool running = false; while (1) { - rdb_read_result_t result = rdb_request_read(&req, &len); + CommandBuf cmd; + rdb_read_result_t result = rdb_request_read(&req, &cmd); if (result == read_result_error) { return -1; } else if (result == read_result_disconnected) { @@ -242,11 +35,8 @@ int server(int connfd, VB *sim) { } continue; } else { - printf("received command \"%.*s\"\n", (int) len, buf); + printf("received command \"%.*s\"\n", (int) cmd.len, cmd.buf); fflush(stdout); - CommandBuf cmd; - cmd.buf = buf; - cmd.len = len; int res = handle_command(&client, &cmd, sim, &running); if (res != 0) { return res; diff --git a/makefile b/makefile index 1aa5e15..2207a39 100644 --- a/makefile +++ b/makefile @@ -1,6 +1,7 @@ build: @mkdir -p build - @gcc main.c client.c cmdbuf.c hex.c request.c ../vbtest/vb.c -I include -I ../vbtest \ + @gcc main.c client.c cmdbuf.c hex.c request.c server.c ../vbtest/vb.c \ + -I include -I ../vbtest \ -Werror -Wall -Wextra -Wpedantic \ -Wno-unused-parameter -Wno-unused-function \ -o ./build/rdb diff --git a/request.c b/request.c index f17d625..46e0ea8 100644 --- a/request.c +++ b/request.c @@ -5,10 +5,9 @@ #include #include -void rdb_request_init(RdbRequest *req, int connfd, char *cmd, size_t cmdlen) { +void rdb_request_init(RdbRequest *req, int connfd, char *buf, size_t buflen) { req->connfd = connfd; - req->cmd = cmd; - req->cmdlen = cmdlen; + req->outbuf = buf; req->blocking = true; rdb_request_reset(req); } @@ -17,7 +16,6 @@ void rdb_request_reset(RdbRequest *req) { req->state = read_state_header; req->inbuf.len = 0; req->inbuf.index = 0; - req->outlen = 0; req->chk = 0; } @@ -47,12 +45,15 @@ static rdb_read_result_t read_char(RdbRequest *req, char *in) { return read_result_success; } -rdb_read_result_t rdb_request_read(RdbRequest *req, size_t *len) { +rdb_read_result_t rdb_request_read(RdbRequest *req, CommandBuf *cmd) { rdb_read_result_t res; char in; switch (req->state) { case read_state_header: + cmd->buf = req->outbuf; + cmd->len = 0; + // read any acknowledgements and continue do { res = read_char(req, &in); @@ -66,8 +67,8 @@ rdb_read_result_t rdb_request_read(RdbRequest *req, size_t *len) { if (in == '\x03') { // interrupt from the server - req->cmd[0] = in; - req->outlen = 1; + cmd->buf[0] = in; + cmd->len = 1; return read_result_success; } @@ -98,17 +99,17 @@ rdb_read_result_t rdb_request_read(RdbRequest *req, size_t *len) { continue; } - if (req->outlen >= req->cmdlen) { + if (cmd->len >= req->outbuflen) { // ran out of room in the buffer fprintf(stderr, "packet too big for buffer\n"); return read_result_error; } if (req->state == read_state_body_escape) { - req->cmd[req->outlen++] = in ^ 0x20; + cmd->buf[cmd->len++] = in ^ 0x20; req->state = read_state_body; } else { - req->cmd[req->outlen++] = in; + cmd->buf[cmd->len++] = in; } } req->state = read_state_checksum_1; @@ -144,7 +145,6 @@ rdb_read_result_t rdb_request_read(RdbRequest *req, size_t *len) { return read_result_error; } - *len = req->outlen; return read_result_success; default: fprintf(stderr, "invalid state\n"); diff --git a/server.c b/server.c new file mode 100644 index 0000000..3638e10 --- /dev/null +++ b/server.c @@ -0,0 +1,228 @@ +#include +#include +#include + +const char* REGISTERS[] = { + "name:r0;bitsize:32;offset:0;encoding:uint;format:hex;set:General Purpose Registers;dwarf:0", + "name:r1;bitsize:32;offset:4;encoding:uint;format:hex;set:General Purpose Registers;dwarf:0", + "name:fp;alt-name:r2;bitsize:32;offset:8;encoding:uint;format:hex;set:General Purpose Registers;dwarf:0;generic:fp", + "name:sp;alt-name:r3;bitsize:32;offset:12;encoding:uint;format:hex;set:General Purpose Registers;dwarf:0;generic:sp", + "name:gp;alt-name:r4;bitsize:32;offset:16;encoding:uint;format:hex;set:General Purpose Registers;dwarf:0", + "name:tp;alt-name:r5;bitsize:32;offset:20;encoding:uint;format:hex;set:General Purpose Registers;dwarf:0", + "name:r6;bitsize:32;offset:24;encoding:uint;format:hex;set:General Purpose Registers;dwarf:0;generic:arg1", + "name:r7;bitsize:32;offset:28;encoding:uint;format:hex;set:General Purpose Registers;dwarf:0;generic:arg2", + "name:r8;bitsize:32;offset:32;encoding:uint;format:hex;set:General Purpose Registers;dwarf:0;generic:arg3", + "name:r9;bitsize:32;offset:36;encoding:uint;format:hex;set:General Purpose Registers;dwarf:0;generic:arg4", + "name:r10;bitsize:32;offset:40;encoding:uint;format:hex;set:General Purpose Registers;dwarf:0", + "name:r11;bitsize:32;offset:44;encoding:uint;format:hex;set:General Purpose Registers;dwarf:0", + "name:r12;bitsize:32;offset:48;encoding:uint;format:hex;set:General Purpose Registers;dwarf:0", + "name:r13;bitsize:32;offset:52;encoding:uint;format:hex;set:General Purpose Registers;dwarf:0", + "name:r14;bitsize:32;offset:56;encoding:uint;format:hex;set:General Purpose Registers;dwarf:0", + "name:r15;bitsize:32;offset:60;encoding:uint;format:hex;set:General Purpose Registers;dwarf:0", + "name:r16;bitsize:32;offset:64;encoding:uint;format:hex;set:General Purpose Registers;dwarf:0", + "name:r17;bitsize:32;offset:68;encoding:uint;format:hex;set:General Purpose Registers;dwarf:0", + "name:r18;bitsize:32;offset:72;encoding:uint;format:hex;set:General Purpose Registers;dwarf:0", + "name:r19;bitsize:32;offset:76;encoding:uint;format:hex;set:General Purpose Registers;dwarf:0", + "name:r20;bitsize:32;offset:80;encoding:uint;format:hex;set:General Purpose Registers;dwarf:0", + "name:r21;bitsize:32;offset:84;encoding:uint;format:hex;set:General Purpose Registers;dwarf:0", + "name:r22;bitsize:32;offset:88;encoding:uint;format:hex;set:General Purpose Registers;dwarf:0", + "name:r23;bitsize:32;offset:92;encoding:uint;format:hex;set:General Purpose Registers;dwarf:0", + "name:r24;bitsize:32;offset:96;encoding:uint;format:hex;set:General Purpose Registers;dwarf:0", + "name:r25;bitsize:32;offset:100;encoding:uint;format:hex;set:General Purpose Registers;dwarf:0", + "name:r26;bitsize:32;offset:104;encoding:uint;format:hex;set:General Purpose Registers;dwarf:0", + "name:r27;bitsize:32;offset:108;encoding:uint;format:hex;set:General Purpose Registers;dwarf:0", + "name:r28;bitsize:32;offset:112;encoding:uint;format:hex;set:General Purpose Registers;dwarf:0", + "name:r29;bitsize:32;offset:116;encoding:uint;format:hex;set:General Purpose Registers;dwarf:0", + "name:r30;bitsize:32;offset:120;encoding:uint;format:hex;set:General Purpose Registers;dwarf:0", + "name:lp;alt-name:r31;bitsize:32;offset:124;encoding:uint;format:hex;set:General Purpose Registers;dwarf:0;generic:ra", + "name:eipc;alt-name:sr0;bitsize:32;offset:128;encoding:uint;format:hex;set:Special Registers;dwarf:0", + "name:eipsw;alt-name:sr1;bitsize:32;offset:132;encoding:uint;format:hex;set:Special Registers;dwarf:0", + "name:fepc;alt-name:sr2;bitsize:32;offset:136;encoding:uint;format:hex;set:Special Registers;dwarf:0", + "name:fepsw;alt-name:sr3;bitsize:32;offset:140;encoding:uint;format:hex;set:Special Registers;dwarf:0", + "name:ecr;alt-name:sr4;bitsize:32;offset:144;encoding:uint;format:hex;set:Special Registers;dwarf:0", + "name:psw;alt-name:sr5;bitsize:32;offset:148;encoding:uint;format:hex;set:Special Registers;dwarf:0;generic:flags", + "name:pir;alt-name:sr6;bitsize:32;offset:152;encoding:uint;format:hex;set:Special Registers;dwarf:0", + "name:tkcw;alt-name:sr7;bitsize:32;offset:156;encoding:uint;format:hex;set:Special Registers;dwarf:0", + "name:chcw;alt-name:sr24;bitsize:32;offset:160;encoding:uint;format:hex;set:Special Registers;dwarf:0", + "name:adtre;alt-name:sr25;bitsize:32;offset:164;encoding:uint;format:hex;set:Special Registers;dwarf:0", + "name:sr29;bitsize:32;offset:168;encoding:uint;format:hex;set:Special Registers;dwarf:0", + "name:sr30;bitsize:32;offset:172;encoding:uint;format:hex;set:Special Registers;dwarf:0", + "name:sr31;bitsize:32;offset:176;encoding:uint;format:hex;set:Special Registers;dwarf:0", + "name:pc;bitsize:32;offset:180;encoding:uint;format:hex;set:Special Registers;dwarf:0;generic:pc", +}; + +const uint32_t SYSTEM_REGISTERS[] = { + VB_EIPC, + VB_EIPSW, + VB_FEPC, + VB_FEPSW, + VB_ECR, + VB_PSW, + VB_PIR, + VB_TKCW, + VB_CHCW, + VB_ADTRE, + 29, + 30, + 31, +}; + +const uint32_t PC_INDEX = 32 + 13; + +int handle_command(RdbClient *client, CommandBuf *cmd, VB *sim, bool *running) { + rdb_client_begin_packet(client); + + if (cmd_match_only_str(cmd, "QStartNoAckMode")) { + // The debugger is asking us to no longer ACK messages. + // Note that we ack THIS response, because we already called rdb_client_begin_packet. + client->should_ack = false; + rdb_client_write_str(client, "OK"); + return rdb_client_send_packet(client); + } + if (cmd_match_str(cmd, "qSupported")) { + // The debugger is asking for a list of features we support. + rdb_client_write_str(client, "no-resumed+;multiprocess;vContSupported;QNonStop+"); + return rdb_client_send_packet(client); + } + if (cmd_match_only_str(cmd, "QThreadSuffixSupported")) { + // The debugger is asking us to include the current thread as a suffix to some responses. + rdb_client_write_str(client, "OK"); + return rdb_client_send_packet(client); + } + if (cmd_match_only_str(cmd, "QListThreadsInStopReply")) { + // The debugger is asking us to list all threads whenever we stop running. + rdb_client_write_str(client, "OK"); + return rdb_client_send_packet(client); + } + if (cmd_match_only_str(cmd, "qHostInfo")) { + // The debugger is asking us to describe the "host machine" getting debugged. + rdb_client_write_str(client, "triple:"); + rdb_client_write_str_hex(client, "v810-unknown-vb"); + rdb_client_write_str(client, ";endian:little;ptrsize:4;"); + return rdb_client_send_packet(client); + } + if (cmd_match_only_str(cmd, "qProcessInfo")) { + // The debugger is asking us to describe the "process" getting debugged. + // We make up a process with id 1. + rdb_client_write_str(client, "pid:1;triple:"); + rdb_client_write_str_hex(client, "v810-unknown-vb"); + rdb_client_write_str(client, "endian:little;ptrsize:4;"); + return rdb_client_send_packet(client); + } + if (cmd_match_str(cmd, "qRegisterInfo")) { + // The debugger is asking for information about a specific register. + uint32_t reg_no; + if (!cmd_match_hex_number(cmd, ®_no)) return 1; + if (reg_no <= PC_INDEX) { + rdb_client_write_str(client, REGISTERS[reg_no]); + } + return rdb_client_send_packet(client); + } + if (cmd_match_only_str(cmd, "qfThreadInfo")) { + // The debugger is asking us to list all threads. Return a list with "thread 1". + rdb_client_write_str(client, "mp1.t1"); + return rdb_client_send_packet(client); + } + if (cmd_match_only_str(cmd, "qsThreadInfo")) { + // The debugger is asking us to list all threads. + rdb_client_write_str(client, "l"); + return rdb_client_send_packet(client); + } + if (cmd_match_only_str(cmd, "vCont?")) { + // The debugger is asking which vCont commands we support. + rdb_client_write_str(client, "c;C;s;S"); + return rdb_client_send_packet(client); + } + if (cmd_match_only_str(cmd, "qC")) { + // The debugger is asking for the current thread id. Return "thread 1". + rdb_client_write_str(client, "QCp1.t1"); + return rdb_client_send_packet(client); + } + if (cmd_match_str(cmd, "p")) { + // read a register. + uint32_t reg_no; + if (!cmd_match_hex_number(cmd, ®_no)) return 1; + if (reg_no > PC_INDEX) { + return rdb_client_send_packet(client); + } + + int32_t reg_value; + if (reg_no == PC_INDEX) { + reg_value = vbGetProgramCounter(sim); + } else if (reg_no > 31) { + reg_value = vbGetSystemRegister(sim, SYSTEM_REGISTERS[reg_no - 32]); + } else { + reg_value = vbGetProgramRegister(sim, reg_no); + } + rdb_client_write_i32_hex(client, reg_value); + return rdb_client_send_packet(client); + } + if (cmd_match_str(cmd, "P")) { + // write a register. + uint32_t reg_no; + char reg_bytes[4]; + if (!cmd_match_hex_number(cmd, ®_no)) return -1; + if (!cmd_match_str(cmd, "=")) return -1; + if (!cmd_match_hex_bytes(cmd, 4, reg_bytes)) return -1; + + int32_t reg_value = ((uint32_t) (reg_bytes[3]) << 24) | + ((uint32_t) (reg_bytes[2]) << 16) | + ((uint32_t) (reg_bytes[1]) << 8) | + ((uint32_t) reg_bytes[0]); + + if (reg_no > PC_INDEX) { + return rdb_client_send_packet(client); + } + if (reg_no == PC_INDEX) { + vbSetProgramCounter(sim, reg_value); + } else if (reg_no > 31) { + vbSetSystemRegister(sim, SYSTEM_REGISTERS[reg_no - 32], reg_value); + } else { + vbSetProgramRegister(sim, reg_no, reg_value); + } + rdb_client_write_str(client, "OK"); + return rdb_client_send_packet(client); + } + if (cmd_match_str(cmd, "Hc-1")) { + // Set the "current thread" for future commands to all threads (thread -1). + rdb_client_write_str(client, "OK"); + return rdb_client_send_packet(client); + } + if (cmd_match_only_str(cmd, "c")) { + // 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). + *running = true; + return 0; + } + if (cmd_match_only_str(cmd, "\x03")) { + // Received an ETX, indicating that the server wants to cancel the "c" command from before. + *running = false; + // Send the response to the "c" command from before. + rdb_client_write_str(client, "T05thread:p1.t1;threads:p1.t1"); + return rdb_client_send_packet(client); + } + if (cmd_match_only_str(cmd, "?")) { + // The debugger has asked us why we stopped + rdb_client_write_str(client, "T"); + rdb_client_write_str(client, *running ? "00" : "05"); + rdb_client_write_str(client, "thread:p1.t1;threads:p1.t1;"); + return rdb_client_send_packet(client); + } + if (cmd_match_str(cmd, "m")) { + // read memory + uint32_t address; + uint32_t len; + if (!cmd_match_hex_number(cmd, &address)) return -1; + if (!cmd_match_str(cmd, ",")) return -1; + if (!cmd_match_hex_number(cmd, &len)) return -1; + + for (uint32_t i = 0; i < len; ++i) { + uint8_t byte = vbRead(sim, address + i, VB_U8); + rdb_client_write_i8_hex(client, byte); + } + return rdb_client_send_packet(client); + } + fprintf(stderr, "Unrecognized command.\n"); + return rdb_client_send_packet(client); +} +