diff --git a/CHANGES b/CHANGES index 2767ecde0..db620fc67 100644 --- a/CHANGES +++ b/CHANGES @@ -22,6 +22,7 @@ Features: - GB: Symbol table support - GB MBC: Add MBC1 multicart support - GBA: Implement keypad interrupts + - LR35902: Watchpoints Bugfixes: - LR35902: Fix core never exiting with certain event patterns - GB Timer: Improve DIV reset behavior diff --git a/CMakeLists.txt b/CMakeLists.txt index 05aa152aa..e40465c6e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -604,6 +604,7 @@ if(M_CORE_GB) list(APPEND DEBUGGER_SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/lr35902/debugger/cli-debugger.c ${CMAKE_CURRENT_SOURCE_DIR}/src/lr35902/debugger/debugger.c + ${CMAKE_CURRENT_SOURCE_DIR}/src/lr35902/debugger/memory-debugger.c ${CMAKE_CURRENT_SOURCE_DIR}/src/gb/debugger/cli.c ${CMAKE_CURRENT_SOURCE_DIR}/src/gb/debugger/symbols.c) list(APPEND TEST_SRC diff --git a/include/mgba/internal/debugger/debugger.h b/include/mgba/internal/debugger/debugger.h index a54c353c8..d73afd39e 100644 --- a/include/mgba/internal/debugger/debugger.h +++ b/include/mgba/internal/debugger/debugger.h @@ -89,8 +89,8 @@ struct mDebuggerPlatform { bool (*hasBreakpoints)(struct mDebuggerPlatform*); void (*setBreakpoint)(struct mDebuggerPlatform*, uint32_t address, int segment); void (*clearBreakpoint)(struct mDebuggerPlatform*, uint32_t address, int segment); - void (*setWatchpoint)(struct mDebuggerPlatform*, uint32_t address, enum mWatchpointType type); - void (*clearWatchpoint)(struct mDebuggerPlatform*, uint32_t address); + void (*setWatchpoint)(struct mDebuggerPlatform*, uint32_t address, int segment, enum mWatchpointType type); + void (*clearWatchpoint)(struct mDebuggerPlatform*, uint32_t address, int segment); void (*checkBreakpoints)(struct mDebuggerPlatform*); }; diff --git a/include/mgba/internal/lr35902/debugger/debugger.h b/include/mgba/internal/lr35902/debugger/debugger.h index 06801d77b..039ae8e95 100644 --- a/include/mgba/internal/lr35902/debugger/debugger.h +++ b/include/mgba/internal/lr35902/debugger/debugger.h @@ -12,6 +12,9 @@ CXX_GUARD_START #include +#include + + struct LR35902DebugBreakpoint { uint16_t address; int segment; @@ -32,6 +35,7 @@ struct LR35902Debugger { struct LR35902DebugBreakpointList breakpoints; struct LR35902DebugWatchpointList watchpoints; + struct LR35902Memory originalMemory; }; struct mDebuggerPlatform* LR35902DebuggerPlatformCreate(void); diff --git a/src/arm/debugger/debugger.c b/src/arm/debugger/debugger.c index 47aa0d86e..03ae0e90e 100644 --- a/src/arm/debugger/debugger.c +++ b/src/arm/debugger/debugger.c @@ -50,8 +50,8 @@ static void ARMDebuggerEnter(struct mDebuggerPlatform* d, enum mDebuggerEntryRea static void ARMDebuggerSetBreakpoint(struct mDebuggerPlatform*, uint32_t address, int segment); static void ARMDebuggerClearBreakpoint(struct mDebuggerPlatform*, uint32_t address, int segment); -static void ARMDebuggerSetWatchpoint(struct mDebuggerPlatform*, uint32_t address, enum mWatchpointType type); -static void ARMDebuggerClearWatchpoint(struct mDebuggerPlatform*, uint32_t address); +static void ARMDebuggerSetWatchpoint(struct mDebuggerPlatform*, uint32_t address, int segment, enum mWatchpointType type); +static void ARMDebuggerClearWatchpoint(struct mDebuggerPlatform*, uint32_t address, int segment); static void ARMDebuggerCheckBreakpoints(struct mDebuggerPlatform*); static bool ARMDebuggerHasBreakpoints(struct mDebuggerPlatform*); @@ -182,7 +182,8 @@ static bool ARMDebuggerHasBreakpoints(struct mDebuggerPlatform* d) { return ARMDebugBreakpointListSize(&debugger->breakpoints) || ARMDebugWatchpointListSize(&debugger->watchpoints); } -static void ARMDebuggerSetWatchpoint(struct mDebuggerPlatform* d, uint32_t address, enum mWatchpointType type) { +static void ARMDebuggerSetWatchpoint(struct mDebuggerPlatform* d, uint32_t address, int segment, enum mWatchpointType type) { + UNUSED(segment); struct ARMDebugger* debugger = (struct ARMDebugger*) d; if (!ARMDebugWatchpointListSize(&debugger->watchpoints)) { ARMDebuggerInstallMemoryShim(debugger); @@ -192,7 +193,8 @@ static void ARMDebuggerSetWatchpoint(struct mDebuggerPlatform* d, uint32_t addre watchpoint->type = type; } -static void ARMDebuggerClearWatchpoint(struct mDebuggerPlatform* d, uint32_t address) { +static void ARMDebuggerClearWatchpoint(struct mDebuggerPlatform* d, uint32_t address, int segment) { + UNUSED(segment); struct ARMDebugger* debugger = (struct ARMDebugger*) d; struct ARMDebugWatchpointList* watchpoints = &debugger->watchpoints; size_t i; diff --git a/src/debugger/cli-debugger.c b/src/debugger/cli-debugger.c index 74a87c743..70cff2a5f 100644 --- a/src/debugger/cli-debugger.c +++ b/src/debugger/cli-debugger.c @@ -428,7 +428,7 @@ static void _setWatchpoint(struct CLIDebugger* debugger, struct CLIDebugVector* return; } uint32_t address = dv->intValue; - debugger->d.platform->setWatchpoint(debugger->d.platform, address, WATCHPOINT_RW); + debugger->d.platform->setWatchpoint(debugger->d.platform, address, dv->segmentValue, WATCHPOINT_RW); } static void _setReadWatchpoint(struct CLIDebugger* debugger, struct CLIDebugVector* dv) { @@ -441,7 +441,7 @@ static void _setReadWatchpoint(struct CLIDebugger* debugger, struct CLIDebugVect return; } uint32_t address = dv->intValue; - debugger->d.platform->setWatchpoint(debugger->d.platform, address, WATCHPOINT_READ); + debugger->d.platform->setWatchpoint(debugger->d.platform, address, dv->segmentValue, WATCHPOINT_READ); } static void _setWriteWatchpoint(struct CLIDebugger* debugger, struct CLIDebugVector* dv) { @@ -454,7 +454,7 @@ static void _setWriteWatchpoint(struct CLIDebugger* debugger, struct CLIDebugVec return; } uint32_t address = dv->intValue; - debugger->d.platform->setWatchpoint(debugger->d.platform, address, WATCHPOINT_WRITE); + debugger->d.platform->setWatchpoint(debugger->d.platform, address, dv->segmentValue, WATCHPOINT_WRITE); } static void _clearBreakpoint(struct CLIDebugger* debugger, struct CLIDebugVector* dv) { @@ -465,7 +465,7 @@ static void _clearBreakpoint(struct CLIDebugger* debugger, struct CLIDebugVector uint32_t address = dv->intValue; debugger->d.platform->clearBreakpoint(debugger->d.platform, address, dv->segmentValue); if (debugger->d.platform->clearWatchpoint) { - debugger->d.platform->clearWatchpoint(debugger->d.platform, address); + debugger->d.platform->clearWatchpoint(debugger->d.platform, address, dv->segmentValue); } } diff --git a/src/debugger/gdb-stub.c b/src/debugger/gdb-stub.c index 05005648b..3c149c9fc 100644 --- a/src/debugger/gdb-stub.c +++ b/src/debugger/gdb-stub.c @@ -498,13 +498,13 @@ static void _setBreakpoint(struct GDBStub* stub, const char* message) { stub->d.platform->setBreakpoint(stub->d.platform, address, -1); break; case '2': - stub->d.platform->setWatchpoint(stub->d.platform, address, WATCHPOINT_WRITE); + stub->d.platform->setWatchpoint(stub->d.platform, address, -1, WATCHPOINT_WRITE); break; case '3': - stub->d.platform->setWatchpoint(stub->d.platform, address, WATCHPOINT_READ); + stub->d.platform->setWatchpoint(stub->d.platform, address, -1, WATCHPOINT_READ); break; case '4': - stub->d.platform->setWatchpoint(stub->d.platform, address, WATCHPOINT_RW); + stub->d.platform->setWatchpoint(stub->d.platform, address, -1, WATCHPOINT_RW); break; default: stub->outgoing[0] = '\0'; @@ -529,7 +529,7 @@ static void _clearBreakpoint(struct GDBStub* stub, const char* message) { case '2': case '3': case '4': - stub->d.platform->clearWatchpoint(stub->d.platform, address); + stub->d.platform->clearWatchpoint(stub->d.platform, address, -1); break; default: break; diff --git a/src/lr35902/debugger/debugger.c b/src/lr35902/debugger/debugger.c index 91de87577..5d3f3a6ce 100644 --- a/src/lr35902/debugger/debugger.c +++ b/src/lr35902/debugger/debugger.c @@ -7,6 +7,7 @@ #include #include +#include DEFINE_VECTOR(LR35902DebugBreakpointList, struct LR35902DebugBreakpoint); DEFINE_VECTOR(LR35902DebugWatchpointList, struct LR35902DebugWatchpoint); @@ -43,6 +44,8 @@ static void LR35902DebuggerEnter(struct mDebuggerPlatform* d, enum mDebuggerEntr static void LR35902DebuggerSetBreakpoint(struct mDebuggerPlatform*, uint32_t address, int segment); static void LR35902DebuggerClearBreakpoint(struct mDebuggerPlatform*, uint32_t address, int segment); +static void LR35902DebuggerSetWatchpoint(struct mDebuggerPlatform*, uint32_t address, int segment, enum mWatchpointType type); +static void LR35902DebuggerClearWatchpoint(struct mDebuggerPlatform*, uint32_t address, int segment); static void LR35902DebuggerCheckBreakpoints(struct mDebuggerPlatform*); static bool LR35902DebuggerHasBreakpoints(struct mDebuggerPlatform*); @@ -53,8 +56,8 @@ struct mDebuggerPlatform* LR35902DebuggerPlatformCreate(void) { platform->deinit = LR35902DebuggerDeinit; platform->setBreakpoint = LR35902DebuggerSetBreakpoint; platform->clearBreakpoint = LR35902DebuggerClearBreakpoint; - platform->setWatchpoint = NULL; - platform->clearWatchpoint = NULL; + platform->setWatchpoint = LR35902DebuggerSetWatchpoint; + platform->clearWatchpoint = LR35902DebuggerClearWatchpoint; platform->checkBreakpoints = LR35902DebuggerCheckBreakpoints; platform->hasBreakpoints = LR35902DebuggerHasBreakpoints; return platform; @@ -79,6 +82,10 @@ static void LR35902DebuggerEnter(struct mDebuggerPlatform* platform, enum mDebug struct LR35902Debugger* debugger = (struct LR35902Debugger*) platform; struct LR35902Core* cpu = debugger->cpu; cpu->nextEvent = cpu->cycles; + + if (debugger->d.p->entered) { + debugger->d.p->entered(debugger->d.p, reason, info); + } } static void LR35902DebuggerSetBreakpoint(struct mDebuggerPlatform* d, uint32_t address, int segment) { @@ -104,3 +111,29 @@ static bool LR35902DebuggerHasBreakpoints(struct mDebuggerPlatform* d) { struct LR35902Debugger* debugger = (struct LR35902Debugger*) d; return LR35902DebugBreakpointListSize(&debugger->breakpoints) || LR35902DebugWatchpointListSize(&debugger->watchpoints); } + +static void LR35902DebuggerSetWatchpoint(struct mDebuggerPlatform* d, uint32_t address, int segment, enum mWatchpointType type) { + struct LR35902Debugger* debugger = (struct LR35902Debugger*) d; + if (!LR35902DebugWatchpointListSize(&debugger->watchpoints)) { + LR35902DebuggerInstallMemoryShim(debugger); + } + struct LR35902DebugWatchpoint* watchpoint = LR35902DebugWatchpointListAppend(&debugger->watchpoints); + watchpoint->address = address; + watchpoint->type = type; + watchpoint->segment = segment; +} + +static void LR35902DebuggerClearWatchpoint(struct mDebuggerPlatform* d, uint32_t address, int segment) { + struct LR35902Debugger* debugger = (struct LR35902Debugger*) d; + struct LR35902DebugWatchpointList* watchpoints = &debugger->watchpoints; + size_t i; + for (i = 0; i < LR35902DebugWatchpointListSize(watchpoints); ++i) { + struct LR35902DebugWatchpoint* watchpoint = LR35902DebugWatchpointListGetPointer(watchpoints, i); + if (watchpoint->address == address && watchpoint->segment == segment) { + LR35902DebugWatchpointListShift(watchpoints, i, 1); + } + } + if (!LR35902DebugWatchpointListSize(&debugger->watchpoints)) { + LR35902DebuggerRemoveMemoryShim(debugger); + } +}