all repos — mgba @ ea6b129509b5f9b68391ad52e611790af55cbbcd

mGBA Game Boy Advance Emulator

LLDB compatibility
Jeffrey Pfau jeffrey@endrift.com
Sat, 01 Feb 2014 15:21:17 -0800
commit

ea6b129509b5f9b68391ad52e611790af55cbbcd

parent

1541e6e0b060637cff5ff882fa24956f88dc3a35

2 files changed, 134 insertions(+), 11 deletions(-)

jump to
M src/debugger/debugger.hsrc/debugger/debugger.h

@@ -25,6 +25,7 @@ };

enum DebuggerEntryReason { DEBUGGER_ENTER_MANUAL, + DEBUGGER_ENTER_ATTACHED, DEBUGGER_ENTER_BREAKPOINT, DEBUGGER_ENTER_WATCHPOINT, DEBUGGER_ENTER_ILLEGAL_OP
M src/debugger/gdb-stub.csrc/debugger/gdb-stub.c

@@ -3,6 +3,7 @@

#include <errno.h> #include <fcntl.h> #include <netinet/in.h> +#include <signal.h> #include <stdio.h> #include <string.h> #include <sys/socket.h>

@@ -19,6 +20,8 @@ MACH_O_ARM = 12,

MACH_O_ARM_V4T = 5 }; +static void _sendMessage(struct GDBStub* stub); + static void _gdbStubDeinit(struct ARMDebugger* debugger) { struct GDBStub* stub = (struct GDBStub*) debugger; if (stub->socket >= 0) {

@@ -26,6 +29,41 @@ GDBStubShutdown(stub);

} } +static void _gdbStubEntered(struct ARMDebugger* debugger, enum DebuggerEntryReason reason) { + struct GDBStub* stub = (struct GDBStub*) debugger; + switch (reason) { + case DEBUGGER_ENTER_MANUAL: + snprintf(stub->outgoing, GDB_STUB_MAX_LINE - 4, "S%02x", SIGINT); + break; + case DEBUGGER_ENTER_BREAKPOINT: + case DEBUGGER_ENTER_WATCHPOINT: // TODO: Make watchpoints raise with address + snprintf(stub->outgoing, GDB_STUB_MAX_LINE - 4, "S%02x", SIGTRAP); + break; + case DEBUGGER_ENTER_ILLEGAL_OP: + snprintf(stub->outgoing, GDB_STUB_MAX_LINE - 4, "S%02x", SIGILL); + break; + case DEBUGGER_ENTER_ATTACHED: + return; + } + _sendMessage(stub); +} + +static void _gdbStubPoll(struct ARMDebugger* debugger) { + struct GDBStub* stub = (struct GDBStub*) debugger; + int flags; + while (stub->d.state == DEBUGGER_PAUSED) { + if (stub->connection >= 0) { + flags = fcntl(stub->connection, F_GETFL); + if (flags == -1) { + GDBStubHangup(stub); + return; + } + fcntl(stub->connection, F_SETFL, flags & ~O_NONBLOCK); + } + GDBStubUpdate(stub); + } +} + static void _ack(struct GDBStub* stub) { char ack = '+'; send(stub->connection, &ack, 1, 0);

@@ -115,6 +153,19 @@ snprintf(stub->outgoing, GDB_STUB_MAX_LINE - 4, "cputype:%u;cpusubtype:%u:ostype:none;vendor:none;endian:little;ptrsize:4;", MACH_O_ARM, MACH_O_ARM_V4T);

_sendMessage(stub); } +static void _continue(struct GDBStub* stub, const char* message) { + stub->d.state = DEBUGGER_RUNNING; + if (stub->connection >= 0) { + int flags = fcntl(stub->connection, F_GETFL); + if (flags == -1) { + GDBStubHangup(stub); + return; + } + fcntl(stub->connection, F_SETFL, flags | O_NONBLOCK); + } + // TODO: parse message +} + static void _readMemory(struct GDBStub* stub, const char* message) { const char* readAddress = message; unsigned i;

@@ -182,29 +233,79 @@ _sendMessage(stub);

} static void _processQReadCommand(struct GDBStub* stub, const char* message) { - if (!strncmp("HostInfo", message, 8)) { + stub->outgoing[0] = '\0'; + if (!strncmp("HostInfo#", message, 9)) { _writeHostInfo(stub); return; } - stub->outgoing[0] = '\0'; + if (!strncmp("Attached#", message, 9)) { + strncpy(stub->outgoing, "1", GDB_STUB_MAX_LINE - 4); + } else if (!strncmp("VAttachOrWaitSupported#", message, 23)) { + strncpy(stub->outgoing, "OK", GDB_STUB_MAX_LINE - 4); + } else if (!strncmp("C#", message, 2)) { + strncpy(stub->outgoing, "QC1", GDB_STUB_MAX_LINE - 4); + } else if (!strncmp("fThreadInfo#", message, 12)) { + strncpy(stub->outgoing, "m1", GDB_STUB_MAX_LINE - 4); + } else if (!strncmp("sThreadInfo#", message, 12)) { + strncpy(stub->outgoing, "l", GDB_STUB_MAX_LINE - 4); + } _sendMessage(stub); } static void _processQWriteCommand(struct GDBStub* stub, const char* message) { stub->outgoing[0] = '\0'; + if (!strncmp("StartNoAckMode#", message, 16)) { + stub->lineAck = GDB_ACK_OFF; + strncpy(stub->outgoing, "OK", GDB_STUB_MAX_LINE - 4); + } _sendMessage(stub); } -static void _processVMajCommand(struct GDBStub* stub, const char* message) { +static void _processVWriteCommand(struct GDBStub* stub, const char* message) { stub->outgoing[0] = '\0'; _sendMessage(stub); } -static void _processVMinCommand(struct GDBStub* stub, const char* message) { +static void _processVReadCommand(struct GDBStub* stub, const char* message) { stub->outgoing[0] = '\0'; + if (!strncmp("Attach", message, 6)) { + strncpy(stub->outgoing, "1", GDB_STUB_MAX_LINE - 4); + ARMDebuggerEnter(&stub->d, DEBUGGER_ENTER_MANUAL); + } _sendMessage(stub); } +static void _setBreakpoint(struct GDBStub* stub, const char* message) { + switch (message[0]) { + case '0': // Memory breakpoints are not currently supported + case '1': { + const char* readAddress = &message[2]; + unsigned i; + for (i = 0; i < 8; ++i) { + if (readAddress[i] == ',') { + break; + } + } + uint32_t address = _hex2int(readAddress, i); + for (i = 0; i < 8; ++i) { + if (readAddress[i] == '#') { + break; + } + } + uint32_t kind = _hex2int(readAddress, i); // We don't use this in hardware watchpoints + ARMDebuggerSetBreakpoint(&stub->d, address); + strncpy(stub->outgoing, "OK", GDB_STUB_MAX_LINE - 4); + _sendMessage(stub); + break; + } + case '2': + case '3': + // TODO: Watchpoints + default: + break; + } +} + size_t _parseGDBMessage(struct GDBStub* stub, const char* message) { uint8_t checksum = 0; int parsed = 1;

@@ -219,6 +320,9 @@ return parsed;

case '$': ++message; break; + case '\x03': + ARMDebuggerEnter(&stub->d, DEBUGGER_ENTER_MANUAL); + return parsed; default: _nak(stub); return parsed;

@@ -254,8 +358,20 @@

_ack(stub); ++message; switch (messageType) { + case '?': + snprintf(stub->outgoing, GDB_STUB_MAX_LINE - 4, "S%02x", SIGINT); + _sendMessage(stub); + break; + case 'c': + _continue(stub, message); + break; case 'g': _readGPRs(stub, message); + break; + case 'H': + // This is faked because we only have one thread + strncpy(stub->outgoing, "OK", GDB_STUB_MAX_LINE - 4); + _sendMessage(stub); break; case 'm': _readMemory(stub, message);

@@ -270,10 +386,13 @@ case 'q':

_processQReadCommand(stub, message); break; case 'V': - _processVMajCommand(stub, message); + _processVWriteCommand(stub, message); break; case 'v': - _processVMinCommand(stub, message); + _processVReadCommand(stub, message); + break; + case 'Z': + _setBreakpoint(stub, message); break; default: _error(stub, GDB_UNSUPPORTED_COMMAND);

@@ -287,7 +406,8 @@ stub->socket = -1;

stub->connection = -1; stub->d.init = 0; stub->d.deinit = _gdbStubDeinit; - stub->d.paused = 0; + stub->d.paused = _gdbStubPoll; + stub->d.entered = _gdbStubEntered; } int GDBStubListen(struct GDBStub* stub, int port, uint32_t bindAddress) {

@@ -336,6 +456,9 @@ if (stub->connection >= 0) {

close(stub->connection); stub->connection = -1; } + if (stub->d.state == DEBUGGER_PAUSED) { + stub->d.state = DEBUGGER_RUNNING; + } } void GDBStubShutdown(struct GDBStub* stub) {

@@ -349,16 +472,15 @@

void GDBStubUpdate(struct GDBStub* stub) { if (stub->connection == -1) { stub->connection = accept(stub->socket, 0, 0); - if (errno == EWOULDBLOCK || errno == EAGAIN) { - return; - } if (stub->connection >= 0) { int flags = fcntl(stub->connection, F_GETFL); if (flags == -1) { goto connectionLost; } - flags |= O_NONBLOCK; fcntl(stub->connection, F_SETFL, flags | O_NONBLOCK); + ARMDebuggerEnter(&stub->d, DEBUGGER_ENTER_ATTACHED); + } else if (errno == EWOULDBLOCK || errno == EAGAIN) { + return; } else { goto connectionLost; }