LLDB compatibility

This commit is contained in:
Jeffrey Pfau 2014-02-01 15:21:17 -08:00
parent 1541e6e0b0
commit ea6b129509
2 changed files with 134 additions and 11 deletions

View File

@ -25,6 +25,7 @@ struct DebugMemoryShim {
enum DebuggerEntryReason {
DEBUGGER_ENTER_MANUAL,
DEBUGGER_ENTER_ATTACHED,
DEBUGGER_ENTER_BREAKPOINT,
DEBUGGER_ENTER_WATCHPOINT,
DEBUGGER_ENTER_ILLEGAL_OP

View File

@ -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 @@ enum {
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 @@ static void _gdbStubDeinit(struct ARMDebugger* debugger) {
}
}
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 @@ static void _writeHostInfo(struct GDBStub* stub) {
_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 @@ static void _readRegister(struct GDBStub* stub, const char* message) {
}
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 @@ size_t _parseGDBMessage(struct GDBStub* stub, const char* message) {
case '$':
++message;
break;
case '\x03':
ARMDebuggerEnter(&stub->d, DEBUGGER_ENTER_MANUAL);
return parsed;
default:
_nak(stub);
return parsed;
@ -254,9 +358,21 @@ size_t _parseGDBMessage(struct GDBStub* stub, const char* message) {
_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);
break;
@ -270,10 +386,13 @@ size_t _parseGDBMessage(struct GDBStub* stub, const char* message) {
_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 @@ void GDBStubCreate(struct GDBStub* stub) {
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 @@ void GDBStubHangup(struct GDBStub* stub) {
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 GDBStubShutdown(struct GDBStub* stub) {
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;
}