From 8564f5fef4beb7135d497396cd20a3c8d28f3057 Mon Sep 17 00:00:00 2001 From: aldelaro5 Date: Thu, 30 Dec 2021 16:48:42 -0500 Subject: [PATCH] GDB Stub: Add target descriptior and memory map xml This allows gdb to know the memory mapping as well as the architecture once connected. It also allows us to not send dummy data for the fpr because we explicitly do not mention them. --- include/mgba/internal/debugger/gdb-stub.h | 1 + src/debugger/gdb-stub.c | 97 ++++++++++++++++++++--- 2 files changed, 87 insertions(+), 11 deletions(-) diff --git a/include/mgba/internal/debugger/gdb-stub.h b/include/mgba/internal/debugger/gdb-stub.h index 5743834a2..a617bc558 100644 --- a/include/mgba/internal/debugger/gdb-stub.h +++ b/include/mgba/internal/debugger/gdb-stub.h @@ -29,6 +29,7 @@ struct GDBStub { char line[GDB_STUB_MAX_LINE]; char outgoing[GDB_STUB_MAX_LINE]; + char memoryMapXml[GDB_STUB_MAX_LINE]; enum GDBStubAckState lineAck; Socket socket; diff --git a/src/debugger/gdb-stub.c b/src/debugger/gdb-stub.c index e2435b20f..7069c7f75 100644 --- a/src/debugger/gdb-stub.c +++ b/src/debugger/gdb-stub.c @@ -9,6 +9,7 @@ #include #include #include +#include #include @@ -29,6 +30,30 @@ enum { MACH_O_ARM_V4T = 5 }; +static const char* TARGET_XML = "" + "armv4t" + "none" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + ""; + static void _sendMessage(struct GDBStub* stub); static void _gdbStubDeinit(struct mDebugger* debugger) { @@ -336,16 +361,6 @@ static void _readGPRs(struct GDBStub* stub, const char* message) { _int2hex32(cpu->gprs[ARM_PC] - (cpu->cpsr.t ? WORD_SIZE_THUMB : WORD_SIZE_ARM), &stub->outgoing[i]); i += 8; - // Floating point registers, unused on the GBA (8 of them, 24 bits each) - for (r = 0; r < 8 * 3; ++r) { - _int2hex32(0, &stub->outgoing[i]); - i += 8; - } - - // Floating point status, unused on the GBA (32 bits) - _int2hex32(0, &stub->outgoing[i]); - i += 8; - // CPU status _int2hex32(cpu->cpsr.packed, &stub->outgoing[i]); i += 8; @@ -433,7 +448,58 @@ static void _processQSupportedCommand(struct GDBStub* stub, const char* message) } message = end + 1; } - strncpy(stub->outgoing, "swbreak+;hwbreak+", GDB_STUB_MAX_LINE - 4); + strncpy(stub->outgoing, "swbreak+;hwbreak+;qXfer:features:read+;qXfer:memory-map:read+", GDB_STUB_MAX_LINE - 4); +} + +static void _processQXferCommand(struct GDBStub* stub, const char* params, const char* data) { + unsigned offset = 0; + unsigned length = 0; + + unsigned index = 0; + for (index = 0; params[index] != ','; ++index) { + offset <<= 4; + offset |= _hex2int(¶ms[index], 1); + } + + ++index; + unsigned int paramsLength = strlen(params); + for (; index + 3 < paramsLength; ++index) { + length <<= 4; + length |= _hex2int(¶ms[index], 1); + } + + length += 1; + + if (length + 4 > GDB_STUB_MAX_LINE) { + length = GDB_STUB_MAX_LINE - 4; + } + + if (strlen(data) < length + offset) { + length = strlen(data) - offset + 1; + stub->outgoing[0] = 'l'; + } else { + stub->outgoing[0] = 'm'; + } + strlcpy(&stub->outgoing[1], &data[offset], length); +} + +static void _generateMemoryMapXml(struct GDBStub* stub, char* memoryMap) { + size_t index = 0; + strncpy(memoryMap, "", 27); + index += strlen(memoryMap); + const struct mCoreMemoryBlock* blocks; + size_t nBlocks = stub->d.core->listMemoryBlocks(stub->d.core, &blocks); + size_t i; + for (i = 0; i < nBlocks; ++i) { + if (!(blocks[i].flags & mCORE_MEMORY_MAPPED)) { + continue; + } + + const char* type = blocks[i].flags & (mCORE_MEMORY_WRITE | mCORE_MEMORY_WORM) ? "ram" : "rom"; + index += snprintf(&memoryMap[index], GDB_STUB_MAX_LINE - index, "", type, blocks[i].start, blocks[i].size); + } + int amountLeft = GDB_STUB_MAX_LINE - index; + strncpy(&memoryMap[index], "", amountLeft); } static void _processQReadCommand(struct GDBStub* stub, const char* message) { @@ -452,6 +518,13 @@ static void _processQReadCommand(struct GDBStub* stub, const char* message) { strncpy(stub->outgoing, "m1", GDB_STUB_MAX_LINE - 4); } else if (!strncmp("sThreadInfo#", message, 12)) { strncpy(stub->outgoing, "l", GDB_STUB_MAX_LINE - 4); + } else if (!strncmp("Xfer:features:read:target.xml:", message, 30)) { + _processQXferCommand(stub, message + 30, TARGET_XML); + } else if (!strncmp("Xfer:memory-map:read::", message, 22)) { + if (strlen(stub->memoryMapXml) == 0) { + _generateMemoryMapXml(stub, stub->memoryMapXml); + } + _processQXferCommand(stub, message + 22, stub->memoryMapXml); } else if (!strncmp("Supported:", message, 10)) { _processQSupportedCommand(stub, message + 10); } @@ -707,6 +780,8 @@ bool GDBStubListen(struct GDBStub* stub, int port, const struct Address* bindAdd goto cleanup; } + memset(stub->memoryMapXml, 0, GDB_STUB_MAX_LINE); + return true; cleanup: