all repos — mgba @ 5e4e00938cc930167bf2bb3108ab19d0a62e7608

mGBA Game Boy Advance Emulator

Debugger: Support additional GDB stub packets

Implements memory writing packets 'X' and 'M', and register writing
packets 'G' and 'P'.

Fixes the checksum verification to allow inclusion of '\0', which is
needed for the binary data argument of packet 'X'.
Touched jtouched@gmail.com
Mon, 11 Jul 2016 19:22:56 +0200
commit

5e4e00938cc930167bf2bb3108ab19d0a62e7608

parent

5ca36e9418101caee8d41a22c817c1bcf7432e41

2 files changed, 119 insertions(+), 2 deletions(-)

jump to
M CHANGESCHANGES

@@ -18,6 +18,7 @@ - ARM7: Flush prefetch cache when loading CPSR via MSR

- OpenGL: Add texSize uniform - ARM7: Clean up instruction decoding for future expandability - Qt: Make -g flag work in Qt build + - Debugger: Support register and memory writes via GDB stub 0.4.1: (2016-07-11) Bugfixes:
M src/debugger/gdb-stub.csrc/debugger/gdb-stub.c

@@ -6,6 +6,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#include "gdb-stub.h" #include "core/core.h" +#include "gba/memory.h" #include <signal.h>

@@ -149,7 +150,7 @@

static uint32_t _readHex(const char* in, unsigned* out) { unsigned i; for (i = 0; i < 8; ++i) { - if (in[i] == ',') { + if (in[i] == ',' || in[i] == ':' || in[i] == '=') { break; } }

@@ -210,6 +211,65 @@ // TODO: parse message

UNUSED(message); } +static void _writeMemoryBinary(struct GDBStub* stub, const char* message) { + const char* readAddress = message; + unsigned i = 0; + uint32_t address = _readHex(readAddress, &i); + readAddress += i + 1; + + i = 0; + uint32_t size = _readHex(readAddress, &i); + readAddress += i + 1; + + if (size > 512) { + _error(stub, GDB_BAD_ARGUMENTS); + return; + } + + struct ARMCore* cpu = stub->d.core->cpu; + for (i = 0; i < size; i++) { + uint8_t byte = *readAddress; + ++readAddress; + + // Parse escape char + if (byte == 0x7D) { + byte = *readAddress ^ 0x20; + ++readAddress; + } + + GBAPatch8(cpu, address + i, byte, 0); + } + + strncpy(stub->outgoing, "OK", GDB_STUB_MAX_LINE - 4); + _sendMessage(stub); +} + + +static void _writeMemory(struct GDBStub* stub, const char* message) { + const char* readAddress = message; + unsigned i = 0; + uint32_t address = _readHex(readAddress, &i); + readAddress += i + 1; + + i = 0; + uint32_t size = _readHex(readAddress, &i); + readAddress += i + 1; + + if (size > 512) { + _error(stub, GDB_BAD_ARGUMENTS); + return; + } + + struct ARMCore* cpu = stub->d.core->cpu; + for (i = 0; i < size; ++i, readAddress += 2) { + uint8_t byte = _hex2int(readAddress, 2); + GBAPatch8(cpu, address + i, byte, 0); + } + + strncpy(stub->outgoing, "OK", GDB_STUB_MAX_LINE - 4); + _sendMessage(stub); +} + static void _readMemory(struct GDBStub* stub, const char* message) { const char* readAddress = message; unsigned i = 0;

@@ -230,6 +290,20 @@ stub->outgoing[writeAddress] = 0;

_sendMessage(stub); } +static void _writeGPRs(struct GDBStub* stub, const char* message) { + struct ARMCore* cpu = stub->d.core->cpu; + const char* readAddress = message; + + int r; + for (r = 0; r < 16; ++r) { + cpu->gprs[r] = _hex2int(readAddress, 8); + readAddress += 8; + } + + strncpy(stub->outgoing, "OK", GDB_STUB_MAX_LINE - 4); + _sendMessage(stub); +} + static void _readGPRs(struct GDBStub* stub, const char* message) { struct ARMCore* cpu = stub->d.core->cpu; UNUSED(message);

@@ -243,6 +317,36 @@ stub->outgoing[i] = 0;

_sendMessage(stub); } +static void _writeRegister(struct GDBStub* stub, const char* message) { + struct ARMCore* cpu = stub->d.core->cpu; + const char* readAddress = message; + + unsigned i = 0; + uint32_t reg = _readHex(readAddress, &i); + readAddress += i + 1; + + uint32_t value = _readHex(readAddress, &i); + +#ifdef _MSC_VER + value = _byteswap_ulong(value); +#else + value = __builtin_bswap32(value); +#endif + + if (reg < 0x10) { + cpu->gprs[reg] = value; + } else if (reg == 0x19) { + cpu->cpsr.packed = value; + } else { + stub->outgoing[0] = '\0'; + _sendMessage(stub); + return; + } + + strncpy(stub->outgoing, "OK", GDB_STUB_MAX_LINE - 4); + _sendMessage(stub); +} + static void _readRegister(struct GDBStub* stub, const char* message) { struct ARMCore* cpu = stub->d.core->cpu; const char* readAddress = message;

@@ -388,7 +492,7 @@ }

int i; char messageType = message[0]; - for (i = 0; message[i] && message[i] != '#'; ++i, ++parsed) { + for (i = 0; message[i] != '#'; ++i, ++parsed) { checksum += message[i]; } if (!message[i]) {

@@ -423,6 +527,9 @@ break;

case 'c': _continue(stub, message); break; + case 'G': + _writeGPRs(stub, message); + break; case 'g': _readGPRs(stub, message); break;

@@ -431,8 +538,14 @@ // This is faked because we only have one thread

strncpy(stub->outgoing, "OK", GDB_STUB_MAX_LINE - 4); _sendMessage(stub); break; + case 'M': + _writeMemory(stub, message); + break; case 'm': _readMemory(stub, message); + break; + case 'P': + _writeRegister(stub, message); break; case 'p': _readRegister(stub, message);

@@ -452,6 +565,9 @@ break;

case 'v': _processVReadCommand(stub, message); break; + case 'X': + _writeMemoryBinary(stub, message); + break; case 'Z': _setBreakpoint(stub, message); break;