From 16ba5bd05ff423ba9bc98cb7615140b01ff49bd2 Mon Sep 17 00:00:00 2001 From: Jeffrey Pfau Date: Tue, 12 Jan 2016 17:43:09 -0800 Subject: [PATCH] Debugger: Fix watchpoints --- CHANGES | 1 + src/debugger/cli-debugger.c | 2 +- src/debugger/debugger.c | 3 ++- src/debugger/debugger.h | 4 ++-- src/debugger/gdb-stub.c | 16 ++++++++++++---- src/debugger/memory-debugger.c | 30 +++++++++++++++--------------- 6 files changed, 33 insertions(+), 23 deletions(-) diff --git a/CHANGES b/CHANGES index 6404363a1..f307e4305 100644 --- a/CHANGES +++ b/CHANGES @@ -30,6 +30,7 @@ Bugfixes: - GBA: Fix Iridion II savetype - Libretro: Fix aspect ratio - Qt: Fix some potential crashes with the gamepad mapping + - Debugger: Fix watchpoints in gdb Misc: - Qt: Window size command line options are now supported - Qt: Increase usability of key mapper diff --git a/src/debugger/cli-debugger.c b/src/debugger/cli-debugger.c index c3f0c9de1..1f2b54d55 100644 --- a/src/debugger/cli-debugger.c +++ b/src/debugger/cli-debugger.c @@ -536,7 +536,7 @@ static void _setWatchpoint(struct CLIDebugger* debugger, struct CLIDebugVector* return; } uint32_t address = dv->intValue; - ARMDebuggerSetWatchpoint(&debugger->d, address); + ARMDebuggerSetWatchpoint(&debugger->d, address, WATCHPOINT_RW); // TODO: ro/wo } static void _breakIntoDefault(int signal) { diff --git a/src/debugger/debugger.c b/src/debugger/debugger.c index 14e7da62a..8d696f796 100644 --- a/src/debugger/debugger.c +++ b/src/debugger/debugger.c @@ -161,12 +161,13 @@ void ARMDebuggerClearBreakpoint(struct ARMDebugger* debugger, uint32_t address) } } -void ARMDebuggerSetWatchpoint(struct ARMDebugger* debugger, uint32_t address) { +void ARMDebuggerSetWatchpoint(struct ARMDebugger* debugger, uint32_t address, enum WatchpointType type) { if (!debugger->watchpoints) { ARMDebuggerInstallMemoryShim(debugger); } struct DebugWatchpoint* watchpoint = malloc(sizeof(struct DebugWatchpoint)); watchpoint->address = address; + watchpoint->type = type; watchpoint->next = debugger->watchpoints; debugger->watchpoints = watchpoint; } diff --git a/src/debugger/debugger.h b/src/debugger/debugger.h index 5abfc4cc7..94a41d1dd 100644 --- a/src/debugger/debugger.h +++ b/src/debugger/debugger.h @@ -32,7 +32,7 @@ struct DebugBreakpoint { enum WatchpointType { WATCHPOINT_WRITE = 1, WATCHPOINT_READ = 2, - WATCHPOINT_RW = 3 + WATCHPOINT_RW = WATCHPOINT_WRITE | WATCHPOINT_READ }; struct DebugWatchpoint { @@ -101,7 +101,7 @@ void ARMDebuggerEnter(struct ARMDebugger*, enum DebuggerEntryReason, struct Debu void ARMDebuggerSetBreakpoint(struct ARMDebugger* debugger, uint32_t address); bool ARMDebuggerSetSoftwareBreakpoint(struct ARMDebugger* debugger, uint32_t address, enum ExecutionMode mode); void ARMDebuggerClearBreakpoint(struct ARMDebugger* debugger, uint32_t address); -void ARMDebuggerSetWatchpoint(struct ARMDebugger* debugger, uint32_t address); +void ARMDebuggerSetWatchpoint(struct ARMDebugger* debugger, uint32_t address, enum WatchpointType type); void ARMDebuggerClearWatchpoint(struct ARMDebugger* debugger, uint32_t address); #endif diff --git a/src/debugger/gdb-stub.c b/src/debugger/gdb-stub.c index 09f021805..a207bd57e 100644 --- a/src/debugger/gdb-stub.c +++ b/src/debugger/gdb-stub.c @@ -40,9 +40,9 @@ static void _gdbStubEntered(struct ARMDebugger* debugger, enum DebuggerEntryReas snprintf(stub->outgoing, GDB_STUB_MAX_LINE - 4, "S%02x", SIGINT); break; case DEBUGGER_ENTER_BREAKPOINT: - snprintf(stub->outgoing, GDB_STUB_MAX_LINE - 4, "S%02x", SIGTRAP); + snprintf(stub->outgoing, GDB_STUB_MAX_LINE - 4, "S%02x", SIGTRAP); // TODO: Use hwbreak/swbreak if gdb supports it break; - case DEBUGGER_ENTER_WATCHPOINT: // TODO: Make watchpoints raise with address + case DEBUGGER_ENTER_WATCHPOINT: if (info) { const char* type = 0; switch (info->watchType) { @@ -56,7 +56,7 @@ static void _gdbStubEntered(struct ARMDebugger* debugger, enum DebuggerEntryReas type = "awatch"; break; } - snprintf(stub->outgoing, GDB_STUB_MAX_LINE - 4, "T%02x%s:%08X", SIGTRAP, type, info->address); + snprintf(stub->outgoing, GDB_STUB_MAX_LINE - 4, "T%02x%s:%08x;", SIGTRAP, type, info->address); } else { snprintf(stub->outgoing, GDB_STUB_MAX_LINE - 4, "S%02x", SIGTRAP); } @@ -317,9 +317,17 @@ static void _setBreakpoint(struct GDBStub* stub, const char* message) { _sendMessage(stub); break; case '2': + ARMDebuggerSetWatchpoint(&stub->d, address, WATCHPOINT_WRITE); + strncpy(stub->outgoing, "OK", GDB_STUB_MAX_LINE - 4); + _sendMessage(stub); + break; case '3': + ARMDebuggerSetWatchpoint(&stub->d, address, WATCHPOINT_READ); + strncpy(stub->outgoing, "OK", GDB_STUB_MAX_LINE - 4); + _sendMessage(stub); + break; case '4': - ARMDebuggerSetWatchpoint(&stub->d, address); + ARMDebuggerSetWatchpoint(&stub->d, address, WATCHPOINT_RW); strncpy(stub->outgoing, "OK", GDB_STUB_MAX_LINE - 4); _sendMessage(stub); break; diff --git a/src/debugger/memory-debugger.c b/src/debugger/memory-debugger.c index 69d402d64..03fa1bf7f 100644 --- a/src/debugger/memory-debugger.c +++ b/src/debugger/memory-debugger.c @@ -11,7 +11,7 @@ #include -static bool _checkWatchpoints(struct ARMDebugger* debugger, uint32_t address, struct DebuggerEntryInfo* info, int width); +static bool _checkWatchpoints(struct ARMDebugger* debugger, uint32_t address, struct DebuggerEntryInfo* info, enum WatchpointType type, int width); #define FIND_DEBUGGER(DEBUGGER, CPU) \ { \ @@ -32,18 +32,18 @@ static bool _checkWatchpoints(struct ARMDebugger* debugger, uint32_t address, st return debugger->originalMemory.NAME(cpu, __VA_ARGS__); \ } -#define CREATE_WATCHPOINT_SHIM(NAME, WIDTH, RETURN, TYPES, ...) \ +#define CREATE_WATCHPOINT_SHIM(NAME, WIDTH, RETURN, TYPES, ACCESS_TYPE, ...) \ static RETURN ARMDebuggerShim_ ## NAME TYPES { \ struct ARMDebugger* debugger; \ FIND_DEBUGGER(debugger, cpu); \ struct DebuggerEntryInfo info; \ - if (_checkWatchpoints(debugger, address, &info, WIDTH)) { \ + if (_checkWatchpoints(debugger, address, &info, ACCESS_TYPE, WIDTH)) { \ ARMDebuggerEnter(debugger, DEBUGGER_ENTER_WATCHPOINT, &info); \ } \ return debugger->originalMemory.NAME(cpu, __VA_ARGS__); \ } -#define CREATE_MULTIPLE_WATCHPOINT_SHIM(NAME) \ +#define CREATE_MULTIPLE_WATCHPOINT_SHIM(NAME, ACCESS_TYPE) \ static uint32_t ARMDebuggerShim_ ## NAME (struct ARMCore* cpu, uint32_t address, int mask, enum LSMDirection direction, int* cycleCounter) { \ struct ARMDebugger* debugger; \ FIND_DEBUGGER(debugger, cpu); \ @@ -60,28 +60,28 @@ static bool _checkWatchpoints(struct ARMDebugger* debugger, uint32_t address, st unsigned i; \ for (i = 0; i < popcount; ++i) { \ struct DebuggerEntryInfo info; \ - if (_checkWatchpoints(debugger, base + 4 * i, &info, 4)) { \ + if (_checkWatchpoints(debugger, base + 4 * i, &info, ACCESS_TYPE, 4)) { \ ARMDebuggerEnter(debugger, DEBUGGER_ENTER_WATCHPOINT, &info); \ } \ } \ return debugger->originalMemory.NAME(cpu, address, mask, direction, cycleCounter); \ } -CREATE_WATCHPOINT_SHIM(load32, 4, uint32_t, (struct ARMCore* cpu, uint32_t address, int* cycleCounter), address, cycleCounter) -CREATE_WATCHPOINT_SHIM(load16, 2, uint32_t, (struct ARMCore* cpu, uint32_t address, int* cycleCounter), address, cycleCounter) -CREATE_WATCHPOINT_SHIM(load8, 1, uint32_t, (struct ARMCore* cpu, uint32_t address, int* cycleCounter), address, cycleCounter) -CREATE_WATCHPOINT_SHIM(store32, 4, void, (struct ARMCore* cpu, uint32_t address, int32_t value, int* cycleCounter), address, value, cycleCounter) -CREATE_WATCHPOINT_SHIM(store16, 2, void, (struct ARMCore* cpu, uint32_t address, int16_t value, int* cycleCounter), address, value, cycleCounter) -CREATE_WATCHPOINT_SHIM(store8, 1, void, (struct ARMCore* cpu, uint32_t address, int8_t value, int* cycleCounter), address, value, cycleCounter) -CREATE_MULTIPLE_WATCHPOINT_SHIM(loadMultiple) -CREATE_MULTIPLE_WATCHPOINT_SHIM(storeMultiple) +CREATE_WATCHPOINT_SHIM(load32, 4, uint32_t, (struct ARMCore* cpu, uint32_t address, int* cycleCounter), WATCHPOINT_READ, address, cycleCounter) +CREATE_WATCHPOINT_SHIM(load16, 2, uint32_t, (struct ARMCore* cpu, uint32_t address, int* cycleCounter), WATCHPOINT_READ, address, cycleCounter) +CREATE_WATCHPOINT_SHIM(load8, 1, uint32_t, (struct ARMCore* cpu, uint32_t address, int* cycleCounter), WATCHPOINT_READ, address, cycleCounter) +CREATE_WATCHPOINT_SHIM(store32, 4, void, (struct ARMCore* cpu, uint32_t address, int32_t value, int* cycleCounter), WATCHPOINT_WRITE, address, value, cycleCounter) +CREATE_WATCHPOINT_SHIM(store16, 2, void, (struct ARMCore* cpu, uint32_t address, int16_t value, int* cycleCounter), WATCHPOINT_WRITE, address, value, cycleCounter) +CREATE_WATCHPOINT_SHIM(store8, 1, void, (struct ARMCore* cpu, uint32_t address, int8_t value, int* cycleCounter), WATCHPOINT_WRITE, address, value, cycleCounter) +CREATE_MULTIPLE_WATCHPOINT_SHIM(loadMultiple, WATCHPOINT_READ) +CREATE_MULTIPLE_WATCHPOINT_SHIM(storeMultiple, WATCHPOINT_WRITE) CREATE_SHIM(setActiveRegion, void, (struct ARMCore* cpu, uint32_t address), address) -static bool _checkWatchpoints(struct ARMDebugger* debugger, uint32_t address, struct DebuggerEntryInfo* info, int width) { +static bool _checkWatchpoints(struct ARMDebugger* debugger, uint32_t address, struct DebuggerEntryInfo* info, enum WatchpointType type, int width) { --width; struct DebugWatchpoint* watchpoints; for (watchpoints = debugger->watchpoints; watchpoints; watchpoints = watchpoints->next) { - if (!((watchpoints->address ^ address) & ~width)) { + if (!((watchpoints->address ^ address) & ~width) && watchpoints->type & type) { switch (width + 1) { case 1: info->oldValue = debugger->originalMemory.load8(debugger->cpu, address, 0);