mirror of https://github.com/mgba-emu/mgba.git
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'.
This commit is contained in:
parent
5ca36e9418
commit
5e4e00938c
1
CHANGES
1
CHANGES
|
@ -18,6 +18,7 @@ Misc:
|
|||
- 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:
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include "gdb-stub.h"
|
||||
|
||||
#include "core/core.h"
|
||||
#include "gba/memory.h"
|
||||
|
||||
#include <signal.h>
|
||||
|
||||
|
@ -149,7 +150,7 @@ static void _int2hex32(uint32_t value, char* out) {
|
|||
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 @@ static void _step(struct GDBStub* stub, const char* 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 @@ static void _readMemory(struct GDBStub* stub, const char* message) {
|
|||
_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 @@ static void _readGPRs(struct GDBStub* stub, const char* message) {
|
|||
_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 @@ size_t _parseGDBMessage(struct GDBStub* stub, const char* message) {
|
|||
|
||||
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 @@ size_t _parseGDBMessage(struct GDBStub* stub, const char* message) {
|
|||
case 'c':
|
||||
_continue(stub, message);
|
||||
break;
|
||||
case 'G':
|
||||
_writeGPRs(stub, message);
|
||||
break;
|
||||
case 'g':
|
||||
_readGPRs(stub, message);
|
||||
break;
|
||||
|
@ -431,9 +538,15 @@ size_t _parseGDBMessage(struct GDBStub* stub, const char* message) {
|
|||
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);
|
||||
break;
|
||||
|
@ -452,6 +565,9 @@ size_t _parseGDBMessage(struct GDBStub* stub, const char* message) {
|
|||
case 'v':
|
||||
_processVReadCommand(stub, message);
|
||||
break;
|
||||
case 'X':
|
||||
_writeMemoryBinary(stub, message);
|
||||
break;
|
||||
case 'Z':
|
||||
_setBreakpoint(stub, message);
|
||||
break;
|
||||
|
|
Loading…
Reference in New Issue