mirror of https://github.com/mgba-emu/mgba.git
Breakpoint clearing
This commit is contained in:
parent
ea6b129509
commit
c30807117f
|
@ -16,7 +16,7 @@ static void _checkBreakpoints(struct ARMDebugger* debugger) {
|
||||||
instructionLength = WORD_SIZE_THUMB;
|
instructionLength = WORD_SIZE_THUMB;
|
||||||
}
|
}
|
||||||
for (breakpoint = debugger->breakpoints; breakpoint; breakpoint = breakpoint->next) {
|
for (breakpoint = debugger->breakpoints; breakpoint; breakpoint = breakpoint->next) {
|
||||||
if (breakpoint->address + instructionLength == debugger->cpu->gprs[ARM_PC]) {
|
if (breakpoint->address + instructionLength == (uint32_t) debugger->cpu->gprs[ARM_PC]) {
|
||||||
ARMDebuggerEnter(debugger, DEBUGGER_ENTER_BREAKPOINT);
|
ARMDebuggerEnter(debugger, DEBUGGER_ENTER_BREAKPOINT);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -86,6 +86,17 @@ void ARMDebuggerSetBreakpoint(struct ARMDebugger* debugger, uint32_t address) {
|
||||||
debugger->breakpoints = breakpoint;
|
debugger->breakpoints = breakpoint;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ARMDebuggerClearBreakpoint(struct ARMDebugger* debugger, uint32_t address) {
|
||||||
|
struct DebugBreakpoint** previous = &debugger->breakpoints;
|
||||||
|
struct DebugBreakpoint* breakpoint;
|
||||||
|
for (; (breakpoint = *previous); previous = &breakpoint->next) {
|
||||||
|
if (breakpoint->address == address) {
|
||||||
|
*previous = breakpoint->next;
|
||||||
|
free(breakpoint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void ARMDebuggerSetWatchpoint(struct ARMDebugger* debugger, uint32_t address) {
|
void ARMDebuggerSetWatchpoint(struct ARMDebugger* debugger, uint32_t address) {
|
||||||
if (debugger->cpu->memory != &debugger->memoryShim.d) {
|
if (debugger->cpu->memory != &debugger->memoryShim.d) {
|
||||||
ARMDebuggerInstallMemoryShim(debugger);
|
ARMDebuggerInstallMemoryShim(debugger);
|
||||||
|
|
|
@ -12,7 +12,7 @@ enum DebuggerState {
|
||||||
|
|
||||||
struct DebugBreakpoint {
|
struct DebugBreakpoint {
|
||||||
struct DebugBreakpoint* next;
|
struct DebugBreakpoint* next;
|
||||||
int32_t address;
|
uint32_t address;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct DebugMemoryShim {
|
struct DebugMemoryShim {
|
||||||
|
@ -49,6 +49,7 @@ void ARMDebuggerDeinit(struct ARMDebugger*);
|
||||||
void ARMDebuggerRun(struct ARMDebugger*);
|
void ARMDebuggerRun(struct ARMDebugger*);
|
||||||
void ARMDebuggerEnter(struct ARMDebugger*, enum DebuggerEntryReason);
|
void ARMDebuggerEnter(struct ARMDebugger*, enum DebuggerEntryReason);
|
||||||
void ARMDebuggerSetBreakpoint(struct ARMDebugger* debugger, uint32_t address);
|
void ARMDebuggerSetBreakpoint(struct ARMDebugger* debugger, uint32_t address);
|
||||||
|
void ARMDebuggerClearBreakpoint(struct ARMDebugger* debugger, uint32_t address);
|
||||||
void ARMDebuggerSetWatchpoint(struct ARMDebugger* debugger, uint32_t address);
|
void ARMDebuggerSetWatchpoint(struct ARMDebugger* debugger, uint32_t address);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -115,6 +115,17 @@ static void _int2hex32(uint32_t value, char* out) {
|
||||||
out[1] = language[value & 0xF];
|
out[1] = language[value & 0xF];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static uint32_t _readHex(const char* in, unsigned* out) {
|
||||||
|
unsigned i;
|
||||||
|
for (i = 0; i < 8; ++i) {
|
||||||
|
if (in[i] == ',') {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*out += i;
|
||||||
|
return _hex2int(in, i);
|
||||||
|
}
|
||||||
|
|
||||||
static void _sendMessage(struct GDBStub* stub) {
|
static void _sendMessage(struct GDBStub* stub) {
|
||||||
if (stub->lineAck != GDB_ACK_OFF) {
|
if (stub->lineAck != GDB_ACK_OFF) {
|
||||||
stub->lineAck = GDB_ACK_PENDING;
|
stub->lineAck = GDB_ACK_PENDING;
|
||||||
|
@ -168,20 +179,10 @@ static void _continue(struct GDBStub* stub, const char* message) {
|
||||||
|
|
||||||
static void _readMemory(struct GDBStub* stub, const char* message) {
|
static void _readMemory(struct GDBStub* stub, const char* message) {
|
||||||
const char* readAddress = message;
|
const char* readAddress = message;
|
||||||
unsigned i;
|
unsigned i = 0;
|
||||||
for (i = 0; i < 8; ++i) {
|
uint32_t address = _readHex(readAddress, &i);
|
||||||
if (readAddress[i] == ',') {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
uint32_t address = _hex2int(readAddress, i);
|
|
||||||
readAddress += i + 1;
|
readAddress += i + 1;
|
||||||
for (i = 0; i < 8; ++i) {
|
uint32_t size = _readHex(readAddress, &i);
|
||||||
if (readAddress[i] == '#') {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
uint32_t size = _hex2int(readAddress, i);
|
|
||||||
if (size > 512) {
|
if (size > 512) {
|
||||||
_error(stub, GDB_BAD_ARGUMENTS);
|
_error(stub, GDB_BAD_ARGUMENTS);
|
||||||
return;
|
return;
|
||||||
|
@ -210,13 +211,8 @@ static void _readGPRs(struct GDBStub* stub, const char* message) {
|
||||||
|
|
||||||
static void _readRegister(struct GDBStub* stub, const char* message) {
|
static void _readRegister(struct GDBStub* stub, const char* message) {
|
||||||
const char* readAddress = message;
|
const char* readAddress = message;
|
||||||
unsigned i;
|
unsigned i = 0;
|
||||||
for (i = 0; i < 8; ++i) {
|
uint32_t reg = _readHex(readAddress, &i);
|
||||||
if (readAddress[i] == '#') {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
uint32_t reg = _hex2int(readAddress, i);
|
|
||||||
uint32_t value;
|
uint32_t value;
|
||||||
if (reg < 0x10) {
|
if (reg < 0x10) {
|
||||||
value = stub->d.cpu->gprs[reg];
|
value = stub->d.cpu->gprs[reg];
|
||||||
|
@ -280,19 +276,10 @@ static void _setBreakpoint(struct GDBStub* stub, const char* message) {
|
||||||
case '0': // Memory breakpoints are not currently supported
|
case '0': // Memory breakpoints are not currently supported
|
||||||
case '1': {
|
case '1': {
|
||||||
const char* readAddress = &message[2];
|
const char* readAddress = &message[2];
|
||||||
unsigned i;
|
unsigned i = 0;
|
||||||
for (i = 0; i < 8; ++i) {
|
uint32_t address = _readHex(readAddress, &i);
|
||||||
if (readAddress[i] == ',') {
|
readAddress += i + 1;
|
||||||
break;
|
uint32_t kind = _readHex(readAddress, &i); // We don't use this in hardware watchpoints
|
||||||
}
|
|
||||||
}
|
|
||||||
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);
|
ARMDebuggerSetBreakpoint(&stub->d, address);
|
||||||
strncpy(stub->outgoing, "OK", GDB_STUB_MAX_LINE - 4);
|
strncpy(stub->outgoing, "OK", GDB_STUB_MAX_LINE - 4);
|
||||||
_sendMessage(stub);
|
_sendMessage(stub);
|
||||||
|
@ -306,6 +293,26 @@ static void _setBreakpoint(struct GDBStub* stub, const char* message) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void _clearBreakpoint(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 = 0;
|
||||||
|
uint32_t address = _readHex(readAddress, &i);
|
||||||
|
ARMDebuggerClearBreakpoint(&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) {
|
size_t _parseGDBMessage(struct GDBStub* stub, const char* message) {
|
||||||
uint8_t checksum = 0;
|
uint8_t checksum = 0;
|
||||||
int parsed = 1;
|
int parsed = 1;
|
||||||
|
@ -394,6 +401,9 @@ size_t _parseGDBMessage(struct GDBStub* stub, const char* message) {
|
||||||
case 'Z':
|
case 'Z':
|
||||||
_setBreakpoint(stub, message);
|
_setBreakpoint(stub, message);
|
||||||
break;
|
break;
|
||||||
|
case 'z':
|
||||||
|
_clearBreakpoint(stub, message);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
_error(stub, GDB_UNSUPPORTED_COMMAND);
|
_error(stub, GDB_UNSUPPORTED_COMMAND);
|
||||||
break;
|
break;
|
||||||
|
|
Loading…
Reference in New Issue