gdb-server/server.c

372 lines
15 KiB
C
Raw Permalink Normal View History

2024-10-08 02:00:01 +00:00
#include <server.h>
#include <signal.h>
#include <stdio.h>
const char* REGISTERS[] = {
"name:r0;bitsize:32;offset:0;encoding:uint;format:hex;set:General Purpose Registers;dwarf:0",
2024-10-10 03:03:38 +00:00
"name:r1;bitsize:32;offset:4;encoding:uint;format:hex;set:General Purpose Registers;dwarf:1",
"name:fp;alt-name:r2;bitsize:32;offset:8;encoding:uint;format:hex;set:General Purpose Registers;dwarf:2;generic:fp",
"name:sp;alt-name:r3;bitsize:32;offset:12;encoding:uint;format:hex;set:General Purpose Registers;dwarf:3;generic:sp",
"name:gp;alt-name:r4;bitsize:32;offset:16;encoding:uint;format:hex;set:General Purpose Registers;dwarf:4",
"name:tp;alt-name:r5;bitsize:32;offset:20;encoding:uint;format:hex;set:General Purpose Registers;dwarf:5",
"name:r6;bitsize:32;offset:24;encoding:uint;format:hex;set:General Purpose Registers;dwarf:6;generic:arg1",
"name:r7;bitsize:32;offset:28;encoding:uint;format:hex;set:General Purpose Registers;dwarf:7;generic:arg2",
"name:r8;bitsize:32;offset:32;encoding:uint;format:hex;set:General Purpose Registers;dwarf:8;generic:arg3",
"name:r9;bitsize:32;offset:36;encoding:uint;format:hex;set:General Purpose Registers;dwarf:9;generic:arg4",
"name:r10;bitsize:32;offset:40;encoding:uint;format:hex;set:General Purpose Registers;dwarf:10",
"name:r11;bitsize:32;offset:44;encoding:uint;format:hex;set:General Purpose Registers;dwarf:11",
"name:r12;bitsize:32;offset:48;encoding:uint;format:hex;set:General Purpose Registers;dwarf:12",
"name:r13;bitsize:32;offset:52;encoding:uint;format:hex;set:General Purpose Registers;dwarf:13",
"name:r14;bitsize:32;offset:56;encoding:uint;format:hex;set:General Purpose Registers;dwarf:14",
"name:r15;bitsize:32;offset:60;encoding:uint;format:hex;set:General Purpose Registers;dwarf:15",
"name:r16;bitsize:32;offset:64;encoding:uint;format:hex;set:General Purpose Registers;dwarf:16",
"name:r17;bitsize:32;offset:68;encoding:uint;format:hex;set:General Purpose Registers;dwarf:17",
"name:r18;bitsize:32;offset:72;encoding:uint;format:hex;set:General Purpose Registers;dwarf:18",
"name:r19;bitsize:32;offset:76;encoding:uint;format:hex;set:General Purpose Registers;dwarf:19",
"name:r20;bitsize:32;offset:80;encoding:uint;format:hex;set:General Purpose Registers;dwarf:20",
"name:r21;bitsize:32;offset:84;encoding:uint;format:hex;set:General Purpose Registers;dwarf:21",
"name:r22;bitsize:32;offset:88;encoding:uint;format:hex;set:General Purpose Registers;dwarf:22",
"name:r23;bitsize:32;offset:92;encoding:uint;format:hex;set:General Purpose Registers;dwarf:23",
"name:r24;bitsize:32;offset:96;encoding:uint;format:hex;set:General Purpose Registers;dwarf:24",
"name:r25;bitsize:32;offset:100;encoding:uint;format:hex;set:General Purpose Registers;dwarf:25",
"name:r26;bitsize:32;offset:104;encoding:uint;format:hex;set:General Purpose Registers;dwarf:26",
"name:r27;bitsize:32;offset:108;encoding:uint;format:hex;set:General Purpose Registers;dwarf:27",
"name:r28;bitsize:32;offset:112;encoding:uint;format:hex;set:General Purpose Registers;dwarf:28",
"name:r29;bitsize:32;offset:116;encoding:uint;format:hex;set:General Purpose Registers;dwarf:29",
"name:r30;bitsize:32;offset:120;encoding:uint;format:hex;set:General Purpose Registers;dwarf:30",
"name:lp;alt-name:r31;bitsize:32;offset:124;encoding:uint;format:hex;set:General Purpose Registers;dwarf:31;generic:ra",
"name:eipc;alt-name:sr0;bitsize:32;offset:128;encoding:uint;format:hex;set:Special Registers;dwarf:32",
"name:eipsw;alt-name:sr1;bitsize:32;offset:132;encoding:uint;format:hex;set:Special Registers;dwarf:33",
"name:fepc;alt-name:sr2;bitsize:32;offset:136;encoding:uint;format:hex;set:Special Registers;dwarf:34",
"name:fepsw;alt-name:sr3;bitsize:32;offset:140;encoding:uint;format:hex;set:Special Registers;dwarf:35",
"name:ecr;alt-name:sr4;bitsize:32;offset:144;encoding:uint;format:hex;set:Special Registers;dwarf:36",
"name:psw;alt-name:sr5;bitsize:32;offset:148;encoding:uint;format:hex;set:Special Registers;dwarf:37;generic:flags",
"name:pir;alt-name:sr6;bitsize:32;offset:152;encoding:uint;format:hex;set:Special Registers;dwarf:38",
"name:tkcw;alt-name:sr7;bitsize:32;offset:156;encoding:uint;format:hex;set:Special Registers;dwarf:39",
"name:chcw;alt-name:sr24;bitsize:32;offset:160;encoding:uint;format:hex;set:Special Registers;dwarf:40",
"name:adtre;alt-name:sr25;bitsize:32;offset:164;encoding:uint;format:hex;set:Special Registers;dwarf:41",
"name:sr29;bitsize:32;offset:168;encoding:uint;format:hex;set:Special Registers;dwarf:42",
"name:sr30;bitsize:32;offset:172;encoding:uint;format:hex;set:Special Registers;dwarf:43",
"name:sr31;bitsize:32;offset:176;encoding:uint;format:hex;set:Special Registers;dwarf:44",
"name:pc;bitsize:32;offset:180;encoding:uint;format:hex;set:Special Registers;dwarf:45;generic:pc",
2024-10-08 02:00:01 +00:00
};
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;
2024-10-11 01:58:40 +00:00
static int onExecute(VB *sim, uint32_t address, const uint16_t *code, int length) {
uint32_t i;
2024-10-12 00:17:07 +00:00
RdbServer *srv = (RdbServer *)vbGetUserData(sim);
2024-10-11 01:58:40 +00:00
(void)sim;
(void)code;
(void)length;
2024-10-12 05:06:10 +00:00
/* if we're stopped, just stop */
if (srv->state == state_stopped) {
return 1;
}
/* if we're stepping, we'll run this one instruction but no others */
if (srv->state == state_stepping) {
srv->state = state_stopped;
srv->stopreason = stop_reason_trace;
return 0;
}
2024-10-11 01:58:40 +00:00
for (i = 0; i < srv->brkslen; ++i) {
if (srv->brks[i] == address) {
2024-10-12 05:06:10 +00:00
srv->state = state_stopped;
2024-10-11 01:58:40 +00:00
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;
}
}
}
2024-10-10 22:38:40 +00:00
void rdbServerInit(RdbServer *srv, VB *sim) {
2024-10-10 22:20:16 +00:00
srv->sim = sim;
2024-10-11 01:58:40 +00:00
srv->brkslen = 0;
2024-10-12 05:06:10 +00:00
srv->state = state_stopped;
2024-10-11 01:58:40 +00:00
srv->stopreason = stop_reason_none;
2024-10-12 00:17:07 +00:00
vbSetUserData(sim, srv);
vbSetExecuteCallback(sim, onExecute);
2024-10-10 22:20:16 +00:00
}
2024-10-10 22:38:40 +00:00
int rdbServerHandleCommand(RdbServer *srv, CommandBuf *cmd, RdbResponse *res) {
rdbResponseBeginPacket(res);
2024-10-08 02:00:01 +00:00
2024-10-10 22:38:40 +00:00
if (cmdMatchStr(cmd, "QStartNoAckMode")) {
2024-10-08 02:42:28 +00:00
/* The debugger is asking us to no longer ACK messages. */
2024-10-10 22:38:40 +00:00
/* Note that we ack THIS response, because we already called rdbResponseBeginPacket. */
2024-10-08 02:18:42 +00:00
res->should_ack = false;
2024-10-10 22:38:40 +00:00
rdbResponseWriteStr(res, "OK");
return rdbResponseSendPacket(res);
2024-10-08 02:00:01 +00:00
}
2024-10-10 22:38:40 +00:00
if (cmdMatchStr(cmd, "qSupported")) {
2024-10-08 02:42:28 +00:00
/* The debugger is asking for a list of features we support. */
2024-10-12 05:06:10 +00:00
rdbResponseWriteStr(res, "no-resumed+;multiprocess;vContSupported");
2024-10-10 22:38:40 +00:00
return rdbResponseSendPacket(res);
2024-10-08 02:00:01 +00:00
}
2024-10-10 22:38:40 +00:00
if (cmdMatchStr(cmd, "QThreadSuffixSupported")) {
2024-10-08 02:42:28 +00:00
/* The debugger is asking us to include the current thread as a suffix to some responses. */
2024-10-10 22:38:40 +00:00
rdbResponseWriteStr(res, "OK");
return rdbResponseSendPacket(res);
2024-10-08 02:00:01 +00:00
}
2024-10-10 22:38:40 +00:00
if (cmdMatchStr(cmd, "QListThreadsInStopReply")) {
2024-10-08 02:42:28 +00:00
/* The debugger is asking us to list all threads whenever we stop running. */
2024-10-10 22:38:40 +00:00
rdbResponseWriteStr(res, "OK");
return rdbResponseSendPacket(res);
2024-10-08 02:00:01 +00:00
}
2024-10-10 22:38:40 +00:00
if (cmdMatchStr(cmd, "qHostInfo")) {
2024-10-08 02:42:28 +00:00
/* The debugger is asking us to describe the "host machine" getting debugged. */
2024-10-10 22:38:40 +00:00
rdbResponseWriteStr(res, "triple:");
rdbResponseWriteStrHex(res, "v810-unknown-vb");
rdbResponseWriteStr(res, ";endian:little;ptrsize:4;");
return rdbResponseSendPacket(res);
2024-10-08 02:00:01 +00:00
}
2024-10-10 22:38:40 +00:00
if (cmdMatchStr(cmd, "qProcessInfo")) {
2024-10-08 02:42:28 +00:00
/* The debugger is asking us to describe the "process" getting debugged. */
/* We make up a process with id 1. */
2024-10-10 22:38:40 +00:00
rdbResponseWriteStr(res, "pid:1;triple:");
rdbResponseWriteStrHex(res, "v810-unknown-vb");
rdbResponseWriteStr(res, "endian:little;ptrsize:4;");
return rdbResponseSendPacket(res);
2024-10-08 02:00:01 +00:00
}
2024-10-10 22:38:40 +00:00
if (cmdMatchStr(cmd, "qRegisterInfo")) {
2024-10-08 02:00:01 +00:00
uint32_t reg_no;
2024-10-08 02:42:28 +00:00
/* The debugger is asking for information about a specific register. */
2024-10-10 22:38:40 +00:00
if (!cmdMatchHexNumber(cmd, &reg_no)) return 1;
2024-10-08 02:00:01 +00:00
if (reg_no <= PC_INDEX) {
2024-10-10 22:38:40 +00:00
rdbResponseWriteStr(res, REGISTERS[reg_no]);
2024-10-08 02:00:01 +00:00
}
2024-10-10 22:38:40 +00:00
return rdbResponseSendPacket(res);
2024-10-08 02:00:01 +00:00
}
2024-10-10 22:38:40 +00:00
if (cmdMatchStr(cmd, "qfThreadInfo")) {
2024-10-08 02:42:28 +00:00
/* The debugger is asking us to list all threads. Return a list with "thread 1". */
2024-10-10 22:38:40 +00:00
rdbResponseWriteStr(res, "mp1.t1");
return rdbResponseSendPacket(res);
2024-10-08 02:00:01 +00:00
}
2024-10-10 22:38:40 +00:00
if (cmdMatchStr(cmd, "qsThreadInfo")) {
2024-10-08 02:42:28 +00:00
/* The debugger is asking us to list all threads. */
2024-10-10 22:38:40 +00:00
rdbResponseWriteStr(res, "l");
return rdbResponseSendPacket(res);
2024-10-08 02:00:01 +00:00
}
2024-10-10 22:38:40 +00:00
if (cmdMatchStr(cmd, "vCont?")) {
2024-10-08 02:42:28 +00:00
/* The debugger is asking which vCont commands we support. */
2024-10-10 22:38:40 +00:00
rdbResponseWriteStr(res, "c;C;s;S");
return rdbResponseSendPacket(res);
2024-10-08 02:00:01 +00:00
}
2024-10-12 05:06:10 +00:00
if (cmdMatchStr(cmd, "vCont;s:1")) {
/* The debugger wants us to step */
srv->state = state_stepping;
return 0;
}
2024-10-10 22:38:40 +00:00
if (cmdMatchStr(cmd, "qC")) {
2024-10-08 02:42:28 +00:00
/* The debugger is asking for the current thread id. Return "thread 1". */
2024-10-10 22:38:40 +00:00
rdbResponseWriteStr(res, "QCp1.t1");
return rdbResponseSendPacket(res);
2024-10-08 02:00:01 +00:00
}
2024-10-10 22:38:40 +00:00
if (cmdMatchStr(cmd, "p")) {
2024-10-08 02:42:28 +00:00
uint32_t reg_no, reg_value;
/* read a register. */
2024-10-10 22:38:40 +00:00
if (!cmdMatchHexNumber(cmd, &reg_no)) return 1;
2024-10-08 02:00:01 +00:00
if (reg_no > PC_INDEX) {
2024-10-10 22:38:40 +00:00
return rdbResponseSendPacket(res);
2024-10-08 02:00:01 +00:00
}
if (reg_no == PC_INDEX) {
2024-10-10 22:20:16 +00:00
reg_value = vbGetProgramCounter(srv->sim);
2024-10-08 02:00:01 +00:00
} else if (reg_no > 31) {
2024-10-10 22:20:16 +00:00
reg_value = vbGetSystemRegister(srv->sim, SYSTEM_REGISTERS[reg_no - 32]);
2024-10-08 02:00:01 +00:00
} else {
2024-10-10 22:20:16 +00:00
reg_value = vbGetProgramRegister(srv->sim, reg_no);
2024-10-08 02:00:01 +00:00
}
2024-10-10 22:38:40 +00:00
rdbResponseWriteI32Hex(res, reg_value);
return rdbResponseSendPacket(res);
2024-10-08 02:00:01 +00:00
}
2024-10-10 22:38:40 +00:00
if (cmdMatchStr(cmd, "P")) {
2024-10-08 02:42:28 +00:00
uint32_t reg_no, reg_value;
uint8_t reg_bytes[4];
2024-10-08 02:42:28 +00:00
/* write a register. */
2024-10-10 22:38:40 +00:00
if (!cmdMatchHexNumber(cmd, &reg_no)) return -1;
if (!cmdMatchStr(cmd, "=")) return -1;
if (!cmdMatchHexBytes(cmd, 4, reg_bytes)) return -1;
2024-10-08 02:00:01 +00:00
2024-10-08 02:42:28 +00:00
reg_value = ((uint32_t) (reg_bytes[3]) << 24) |
2024-10-08 02:00:01 +00:00
((uint32_t) (reg_bytes[2]) << 16) |
((uint32_t) (reg_bytes[1]) << 8) |
((uint32_t) reg_bytes[0]);
if (reg_no > PC_INDEX) {
2024-10-10 22:38:40 +00:00
return rdbResponseSendPacket(res);
2024-10-08 02:00:01 +00:00
}
if (reg_no == PC_INDEX) {
2024-10-10 22:20:16 +00:00
vbSetProgramCounter(srv->sim, reg_value);
2024-10-08 02:00:01 +00:00
} else if (reg_no > 31) {
2024-10-10 22:20:16 +00:00
vbSetSystemRegister(srv->sim, SYSTEM_REGISTERS[reg_no - 32], reg_value);
2024-10-08 02:00:01 +00:00
} else {
2024-10-10 22:20:16 +00:00
vbSetProgramRegister(srv->sim, reg_no, reg_value);
2024-10-08 02:00:01 +00:00
}
2024-10-10 22:38:40 +00:00
rdbResponseWriteStr(res, "OK");
return rdbResponseSendPacket(res);
2024-10-08 02:00:01 +00:00
}
2024-10-10 22:38:40 +00:00
if (cmdMatchStr(cmd, "Hc-1")) {
2024-10-08 02:42:28 +00:00
/* Set the "current thread" for future commands to all threads (thread -1). */
2024-10-10 22:38:40 +00:00
rdbResponseWriteStr(res, "OK");
return rdbResponseSendPacket(res);
2024-10-08 02:00:01 +00:00
}
2024-10-10 22:38:40 +00:00
if (cmdMatchStr(cmd, "c")) {
2024-10-08 02:42:28 +00:00
/* 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). */
2024-10-12 05:06:10 +00:00
srv->state = state_running;
2024-10-11 01:58:40 +00:00
srv->stopreason = stop_reason_none;
2024-10-08 02:00:01 +00:00
return 0;
}
2024-10-10 22:38:40 +00:00
if (cmdMatchStr(cmd, "\x03")) {
2024-10-08 02:42:28 +00:00
/* Received an ETX, indicating that the server wants to cancel the "c" command from before. */
2024-10-12 05:06:10 +00:00
srv->state = state_stopped;
2024-10-11 01:58:40 +00:00
srv->stopreason = stop_reason_trap;
2024-10-08 02:42:28 +00:00
/* Send the response to the "c" command from before. */
2024-10-11 01:58:40 +00:00
return rdbServerSendStopPacket(srv, res);
2024-10-08 02:00:01 +00:00
}
2024-10-10 22:38:40 +00:00
if (cmdMatchStr(cmd, "?")) {
2024-10-08 02:42:28 +00:00
/* The debugger has asked us why we stopped */
2024-10-11 01:58:40 +00:00
return rdbServerSendStopPacket(srv, res);
2024-10-08 02:00:01 +00:00
}
2024-10-10 22:38:40 +00:00
if (cmdMatchStr(cmd, "m")) {
2024-10-08 02:42:28 +00:00
/* read memory */
uint32_t i, address, len;
2024-10-10 22:38:40 +00:00
if (!cmdMatchHexNumber(cmd, &address)) return -1;
2024-10-12 05:06:10 +00:00
if (!cmdMatchStr(cmd, ",")) {
/* if the server asks for too much memory, just error */
return rdbResponseSendPacket(res);
};
2024-10-10 22:38:40 +00:00
if (!cmdMatchHexNumber(cmd, &len)) return -1;
2024-10-08 02:00:01 +00:00
2024-10-08 02:42:28 +00:00
for (i = 0; i < len; ++i) {
2024-10-10 22:20:16 +00:00
uint8_t byte = vbRead(srv->sim, address + i, VB_U8);
2024-10-10 22:38:40 +00:00
rdbResponseWriteI8Hex(res, byte);
2024-10-08 02:00:01 +00:00
}
2024-10-10 22:38:40 +00:00
return rdbResponseSendPacket(res);
2024-10-08 02:00:01 +00:00
}
2024-10-10 22:38:40 +00:00
if (cmdMatchStr(cmd, "M")) {
2024-10-10 03:25:43 +00:00
/* write memory */
uint32_t i, address, len;
2024-10-10 22:38:40 +00:00
if (!cmdMatchHexNumber(cmd, &address)) return -1;
if (!cmdMatchStr(cmd, ",")) return -1;
if (!cmdMatchHexNumber(cmd, &len)) return -1;
if (!cmdMatchStr(cmd, ":")) return -1;
2024-10-10 03:25:43 +00:00
for (i = 0; i < len; ++i) {
uint8_t byte;
2024-10-10 22:38:40 +00:00
if (!cmdMatchHexBytes(cmd, 1, &byte)) return -1;
2024-10-10 22:20:16 +00:00
vbWrite(srv->sim, address + i, VB_U8, byte);
2024-10-10 03:25:43 +00:00
}
2024-10-10 22:38:40 +00:00
rdbResponseWriteStr(res, "OK");
return rdbResponseSendPacket(res);
2024-10-10 03:25:43 +00:00
}
2024-10-11 01:58:40 +00:00
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);
}
2024-10-08 02:00:01 +00:00
fprintf(stderr, "Unrecognized command.\n");
2024-10-10 22:38:40 +00:00
return rdbResponseSendPacket(res);
2024-10-08 02:00:01 +00:00
}
2024-10-12 05:06:10 +00:00
bool rdbServerIsRunning(RdbServer *srv) {
/* stepping counts */
return srv->state != state_stopped;
}
2024-10-11 01:58:40 +00:00
int rdbServerSendStopPacket(RdbServer *srv, RdbResponse *res) {
2024-10-10 22:38:40 +00:00
rdbResponseBeginPacket(res);
2024-10-11 01:58:40 +00:00
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;
}
2024-10-10 22:38:40 +00:00
return rdbResponseSendPacket(res);
2024-10-10 22:20:16 +00:00
}