Debugger: Revamp breakpoint/watchpoint API, add listing
jump to
@@ -12,6 +12,7 @@ - GBA Savedata: Automatically map 1Mbit Flash files as 1Mbit Flash
- GB Memory: Support running from blocked memory - Qt: Don't unload ROM immediately if it crashes - GBA Video: Improve sprite cycle counting (fixes mgba.io/i/1274) + - Debugger: Add breakpoint and watchpoint listing 0.7.0: (2019-01-26) Features:
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2017 Jeffrey Pfau +/* Copyright (c) 2013-2019 Jeffrey Pfau * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this@@ -12,6 +12,7 @@ CXX_GUARD_START
#include <mgba/core/cpu.h> #include <mgba/core/log.h> +#include <mgba-util/vector.h> mLOG_DECLARE_CATEGORY(DEBUGGER);@@ -36,7 +37,8 @@
enum mWatchpointType { WATCHPOINT_WRITE = 1, WATCHPOINT_READ = 2, - WATCHPOINT_RW = 3 + WATCHPOINT_RW = 3, + WATCHPOINT_WRITE_CHANGE = 4, }; enum mBreakpointType {@@ -69,6 +71,25 @@ } bp;
} type; }; +struct mBreakpoint { + ssize_t id; + uint32_t address; + int segment; + enum mBreakpointType type; + struct ParseTree* condition; +}; + +struct mWatchpoint { + ssize_t id; + uint32_t address; + int segment; + enum mWatchpointType type; + struct ParseTree* condition; +}; + +DECLARE_VECTOR(mBreakpointList, struct mBreakpoint); +DECLARE_VECTOR(mWatchpointList, struct mWatchpoint); + struct mDebugger; struct ParseTree; struct mDebuggerPlatform {@@ -79,13 +100,15 @@ void (*deinit)(struct mDebuggerPlatform*);
void (*entered)(struct mDebuggerPlatform*, enum mDebuggerEntryReason, struct mDebuggerEntryInfo*); bool (*hasBreakpoints)(struct mDebuggerPlatform*); - void (*setBreakpoint)(struct mDebuggerPlatform*, uint32_t address, int segment); - void (*setConditionalBreakpoint)(struct mDebuggerPlatform*, uint32_t address, int segment, struct ParseTree* condition); - void (*clearBreakpoint)(struct mDebuggerPlatform*, uint32_t address, int segment); - void (*setWatchpoint)(struct mDebuggerPlatform*, uint32_t address, int segment, enum mWatchpointType type); - void (*setConditionalWatchpoint)(struct mDebuggerPlatform*, uint32_t address, int segment, enum mWatchpointType type, struct ParseTree* condition); - void (*clearWatchpoint)(struct mDebuggerPlatform*, uint32_t address, int segment); void (*checkBreakpoints)(struct mDebuggerPlatform*); + bool (*clearBreakpoint)(struct mDebuggerPlatform*, ssize_t id); + + ssize_t (*setBreakpoint)(struct mDebuggerPlatform*, const struct mBreakpoint*); + void (*listBreakpoints)(struct mDebuggerPlatform*, struct mBreakpointList*); + + ssize_t (*setWatchpoint)(struct mDebuggerPlatform*, const struct mWatchpoint*); + void (*listWatchpoints)(struct mDebuggerPlatform*, struct mWatchpointList*); + void (*trace)(struct mDebuggerPlatform*, char* out, size_t* length); bool (*getRegister)(struct mDebuggerPlatform*, const char* name, int32_t* value);
@@ -17,23 +17,14 @@ #include <mgba-util/vector.h>
struct ParseTree; struct ARMDebugBreakpoint { - uint32_t address; - struct ParseTree* condition; - bool isSw; + struct mBreakpoint d; struct { uint32_t opcode; enum ExecutionMode mode; } sw; }; -struct ARMDebugWatchpoint { - uint32_t address; - enum mWatchpointType type; - struct ParseTree* condition; -}; - DECLARE_VECTOR(ARMDebugBreakpointList, struct ARMDebugBreakpoint); -DECLARE_VECTOR(ARMDebugWatchpointList, struct ARMDebugWatchpoint); struct ARMDebugger { struct mDebuggerPlatform d;@@ -41,18 +32,19 @@ struct ARMCore* cpu;
struct ARMDebugBreakpointList breakpoints; struct ARMDebugBreakpointList swBreakpoints; - struct ARMDebugWatchpointList watchpoints; + struct mWatchpointList watchpoints; struct ARMMemory originalMemory; + ssize_t nextId; + void (*entered)(struct mDebugger*, enum mDebuggerEntryReason, struct mDebuggerEntryInfo*); - bool (*setSoftwareBreakpoint)(struct ARMDebugger*, uint32_t address, enum ExecutionMode mode, uint32_t* opcode); - bool (*clearSoftwareBreakpoint)(struct ARMDebugger*, uint32_t address, enum ExecutionMode mode, uint32_t opcode); + ssize_t (*setSoftwareBreakpoint)(struct ARMDebugger*, uint32_t address, enum ExecutionMode mode, uint32_t* opcode); + void (*clearSoftwareBreakpoint)(struct ARMDebugger*, const struct ARMDebugBreakpoint*); }; struct mDebuggerPlatform* ARMDebuggerPlatformCreate(void); -bool ARMDebuggerSetSoftwareBreakpoint(struct mDebuggerPlatform* debugger, uint32_t address, enum ExecutionMode mode); -void ARMDebuggerClearSoftwareBreakpoint(struct mDebuggerPlatform* debugger, uint32_t address); +ssize_t ARMDebuggerSetSoftwareBreakpoint(struct mDebuggerPlatform* debugger, uint32_t address, enum ExecutionMode mode); CXX_GUARD_END
@@ -13,38 +13,22 @@
#include <mgba/debugger/debugger.h> #include <mgba/internal/lr35902/lr35902.h> -#include <mgba-util/vector.h> - -struct ParseTree; -struct LR35902DebugBreakpoint { - uint16_t address; - int segment; - struct ParseTree* condition; -}; - -struct LR35902DebugWatchpoint { - uint16_t address; - int segment; - enum mWatchpointType type; - struct ParseTree* condition; -}; struct LR35902Segment { uint16_t start; uint16_t end; const char* name; }; - -DECLARE_VECTOR(LR35902DebugBreakpointList, struct LR35902DebugBreakpoint); -DECLARE_VECTOR(LR35902DebugWatchpointList, struct LR35902DebugWatchpoint); struct LR35902Debugger { struct mDebuggerPlatform d; struct LR35902Core* cpu; - struct LR35902DebugBreakpointList breakpoints; - struct LR35902DebugWatchpointList watchpoints; + struct mBreakpointList breakpoints; + struct mWatchpointList watchpoints; struct LR35902Memory originalMemory; + + ssize_t nextId; const struct LR35902Segment* segments; };
@@ -13,12 +13,11 @@ #include <mgba/internal/arm/debugger/memory-debugger.h>
#include <mgba/internal/debugger/parser.h> DEFINE_VECTOR(ARMDebugBreakpointList, struct ARMDebugBreakpoint); -DEFINE_VECTOR(ARMDebugWatchpointList, struct ARMDebugWatchpoint); static struct ARMDebugBreakpoint* _lookupBreakpoint(struct ARMDebugBreakpointList* breakpoints, uint32_t address) { size_t i; for (i = 0; i < ARMDebugBreakpointListSize(breakpoints); ++i) { - if (ARMDebugBreakpointListGetPointer(breakpoints, i)->address == address) { + if (ARMDebugBreakpointListGetPointer(breakpoints, i)->d.address == address) { return ARMDebugBreakpointListGetPointer(breakpoints, i); } }@@ -26,13 +25,13 @@ return 0;
} static void _destroyBreakpoint(struct ARMDebugBreakpoint* breakpoint) { - if (breakpoint->condition) { - parseFree(breakpoint->condition); - free(breakpoint->condition); + if (breakpoint->d.condition) { + parseFree(breakpoint->d.condition); + free(breakpoint->d.condition); } } -static void _destroyWatchpoint(struct ARMDebugWatchpoint* watchpoint) { +static void _destroyWatchpoint(struct mWatchpoint* watchpoint) { if (watchpoint->condition) { parseFree(watchpoint->condition); free(watchpoint->condition);@@ -52,15 +51,15 @@ struct ARMDebugBreakpoint* breakpoint = _lookupBreakpoint(&debugger->breakpoints, debugger->cpu->gprs[ARM_PC] - instructionLength);
if (!breakpoint) { return; } - if (breakpoint->condition) { + if (breakpoint->d.condition) { int32_t value; int segment; - if (!mDebuggerEvaluateParseTree(d->p, breakpoint->condition, &value, &segment) || !(value || segment >= 0)) { + if (!mDebuggerEvaluateParseTree(d->p, breakpoint->d.condition, &value, &segment) || !(value || segment >= 0)) { return; } } struct mDebuggerEntryInfo info = { - .address = breakpoint->address, + .address = breakpoint->d.address, .type.bp.breakType = BREAKPOINT_HARDWARE }; mDebuggerEnter(d->p, DEBUGGER_ENTER_BREAKPOINT, &info);@@ -71,12 +70,11 @@ static void ARMDebuggerDeinit(struct mDebuggerPlatform* platform);
static void ARMDebuggerEnter(struct mDebuggerPlatform* d, enum mDebuggerEntryReason reason, struct mDebuggerEntryInfo* info); -static void ARMDebuggerSetBreakpoint(struct mDebuggerPlatform*, uint32_t address, int segment); -static void ARMDebuggerSetConditionalBreakpoint(struct mDebuggerPlatform*, uint32_t address, int segment, struct ParseTree* condition); -static void ARMDebuggerClearBreakpoint(struct mDebuggerPlatform*, uint32_t address, int segment); -static void ARMDebuggerSetWatchpoint(struct mDebuggerPlatform*, uint32_t address, int segment, enum mWatchpointType type); -static void ARMDebuggerSetConditionalWatchpoint(struct mDebuggerPlatform*, uint32_t address, int segment, enum mWatchpointType type, struct ParseTree* condition); -static void ARMDebuggerClearWatchpoint(struct mDebuggerPlatform*, uint32_t address, int segment); +static ssize_t ARMDebuggerSetBreakpoint(struct mDebuggerPlatform*, const struct mBreakpoint*); +static bool ARMDebuggerClearBreakpoint(struct mDebuggerPlatform*, ssize_t id); +static void ARMDebuggerListBreakpoints(struct mDebuggerPlatform*, struct mBreakpointList*); +static ssize_t ARMDebuggerSetWatchpoint(struct mDebuggerPlatform*, const struct mWatchpoint*); +static void ARMDebuggerListWatchpoints(struct mDebuggerPlatform*, struct mWatchpointList*); static void ARMDebuggerCheckBreakpoints(struct mDebuggerPlatform*); static bool ARMDebuggerHasBreakpoints(struct mDebuggerPlatform*); static void ARMDebuggerTrace(struct mDebuggerPlatform*, char* out, size_t* length);@@ -89,11 +87,10 @@ platform->entered = ARMDebuggerEnter;
platform->init = ARMDebuggerInit; platform->deinit = ARMDebuggerDeinit; platform->setBreakpoint = ARMDebuggerSetBreakpoint; - platform->setConditionalBreakpoint = ARMDebuggerSetConditionalBreakpoint; + platform->listBreakpoints = ARMDebuggerListBreakpoints; platform->clearBreakpoint = ARMDebuggerClearBreakpoint; platform->setWatchpoint = ARMDebuggerSetWatchpoint; - platform->setConditionalWatchpoint = ARMDebuggerSetConditionalWatchpoint; - platform->clearWatchpoint = ARMDebuggerClearWatchpoint; + platform->listWatchpoints = ARMDebuggerListWatchpoints; platform->checkBreakpoints = ARMDebuggerCheckBreakpoints; platform->hasBreakpoints = ARMDebuggerHasBreakpoints; platform->trace = ARMDebuggerTrace;@@ -106,9 +103,10 @@ void ARMDebuggerInit(void* cpu, struct mDebuggerPlatform* platform) {
struct ARMDebugger* debugger = (struct ARMDebugger*) platform; debugger->cpu = cpu; debugger->originalMemory = debugger->cpu->memory; + debugger->nextId = 1; ARMDebugBreakpointListInit(&debugger->breakpoints, 0); ARMDebugBreakpointListInit(&debugger->swBreakpoints, 0); - ARMDebugWatchpointListInit(&debugger->watchpoints, 0); + mWatchpointListInit(&debugger->watchpoints, 0); } void ARMDebuggerDeinit(struct mDebuggerPlatform* platform) {@@ -118,7 +116,7 @@ // Clear the stack backwards in case any overlap
size_t b; for (b = ARMDebugBreakpointListSize(&debugger->swBreakpoints); b; --b) { struct ARMDebugBreakpoint* breakpoint = ARMDebugBreakpointListGetPointer(&debugger->swBreakpoints, b - 1); - debugger->clearSoftwareBreakpoint(debugger, breakpoint->address, breakpoint->sw.mode, breakpoint->sw.opcode); + debugger->clearSoftwareBreakpoint(debugger, breakpoint); } } ARMDebuggerRemoveMemoryShim(debugger);@@ -129,11 +127,11 @@ _destroyBreakpoint(ARMDebugBreakpointListGetPointer(&debugger->breakpoints, i));
} ARMDebugBreakpointListDeinit(&debugger->breakpoints); - for (i = 0; i < ARMDebugWatchpointListSize(&debugger->watchpoints); ++i) { - _destroyWatchpoint(ARMDebugWatchpointListGetPointer(&debugger->watchpoints, i)); + for (i = 0; i < mWatchpointListSize(&debugger->watchpoints); ++i) { + _destroyWatchpoint(mWatchpointListGetPointer(&debugger->watchpoints, i)); } ARMDebugBreakpointListDeinit(&debugger->swBreakpoints); - ARMDebugWatchpointListDeinit(&debugger->watchpoints); + mWatchpointListDeinit(&debugger->watchpoints); } static void ARMDebuggerEnter(struct mDebuggerPlatform* platform, enum mDebuggerEntryReason reason, struct mDebuggerEntryInfo* info) {@@ -142,16 +140,16 @@ struct ARMCore* cpu = debugger->cpu;
cpu->nextEvent = cpu->cycles; if (reason == DEBUGGER_ENTER_BREAKPOINT) { struct ARMDebugBreakpoint* breakpoint = _lookupBreakpoint(&debugger->swBreakpoints, _ARMPCAddress(cpu)); - if (breakpoint && breakpoint->isSw) { - info->address = breakpoint->address; + if (breakpoint && breakpoint->d.type == BREAKPOINT_SOFTWARE) { + info->address = breakpoint->d.address; if (debugger->clearSoftwareBreakpoint) { - debugger->clearSoftwareBreakpoint(debugger, breakpoint->address, breakpoint->sw.mode, breakpoint->sw.opcode); + debugger->clearSoftwareBreakpoint(debugger, breakpoint); } ARMRunFake(cpu, breakpoint->sw.opcode); if (debugger->setSoftwareBreakpoint) { - debugger->setSoftwareBreakpoint(debugger, breakpoint->address, breakpoint->sw.mode, &breakpoint->sw.opcode); + debugger->setSoftwareBreakpoint(debugger, breakpoint->d.address, breakpoint->sw.mode, &breakpoint->sw.opcode); } } }@@ -160,105 +158,135 @@ debugger->d.p->entered(debugger->d.p, reason, info);
} } -bool ARMDebuggerSetSoftwareBreakpoint(struct mDebuggerPlatform* d, uint32_t address, enum ExecutionMode mode) { +ssize_t ARMDebuggerSetSoftwareBreakpoint(struct mDebuggerPlatform* d, uint32_t address, enum ExecutionMode mode) { struct ARMDebugger* debugger = (struct ARMDebugger*) d; uint32_t opcode; if (!debugger->setSoftwareBreakpoint || !debugger->setSoftwareBreakpoint(debugger, address, mode, &opcode)) { - return false; + return -1; } struct ARMDebugBreakpoint* breakpoint = ARMDebugBreakpointListAppend(&debugger->swBreakpoints); - breakpoint->address = address; - breakpoint->isSw = true; + ssize_t id = debugger->nextId; + ++debugger->nextId; + breakpoint->d.id = id; + breakpoint->d.address = address; + breakpoint->d.segment = -1; + breakpoint->d.condition = NULL; + breakpoint->d.type = BREAKPOINT_SOFTWARE; breakpoint->sw.opcode = opcode; breakpoint->sw.mode = mode; - return true; + return id; } -void ARMDebuggerClearSoftwareBreakpoint(struct mDebuggerPlatform* d, uint32_t address) { +static ssize_t ARMDebuggerSetBreakpoint(struct mDebuggerPlatform* d, const struct mBreakpoint* info) { struct ARMDebugger* debugger = (struct ARMDebugger*) d; - if (!debugger->clearSoftwareBreakpoint) { - return; - } - - struct ARMDebugBreakpoint* breakpoint = NULL; - // Clear the stack backwards in case any overlap - size_t b; - for (b = ARMDebugBreakpointListSize(&debugger->swBreakpoints); b; --b) { - breakpoint = ARMDebugBreakpointListGetPointer(&debugger->swBreakpoints, b - 1); - if (breakpoint->address == address) { - break; - } - breakpoint = NULL; - } - - if (breakpoint) { - debugger->clearSoftwareBreakpoint(debugger, address, breakpoint->sw.mode, breakpoint->sw.opcode); + struct ARMDebugBreakpoint* breakpoint = ARMDebugBreakpointListAppend(&debugger->breakpoints); + ssize_t id = debugger->nextId; + ++debugger->nextId; + breakpoint->d = *info; + breakpoint->d.id = id; + if (info->type == BREAKPOINT_SOFTWARE) { + // TODO + abort(); } + return id; } -static void ARMDebuggerSetBreakpoint(struct mDebuggerPlatform* d, uint32_t address, int segment) { - ARMDebuggerSetConditionalBreakpoint(d, address, segment, NULL); -} - -static void ARMDebuggerSetConditionalBreakpoint(struct mDebuggerPlatform* d, uint32_t address, int segment, struct ParseTree* condition) { - UNUSED(segment); +static bool ARMDebuggerClearBreakpoint(struct mDebuggerPlatform* d, ssize_t id) { struct ARMDebugger* debugger = (struct ARMDebugger*) d; - struct ARMDebugBreakpoint* breakpoint = ARMDebugBreakpointListAppend(&debugger->breakpoints); - breakpoint->condition = condition; - breakpoint->address = address; - breakpoint->isSw = false; -} + size_t i; -static void ARMDebuggerClearBreakpoint(struct mDebuggerPlatform* d, uint32_t address, int segment) { - UNUSED(segment); - struct ARMDebugger* debugger = (struct ARMDebugger*) d; struct ARMDebugBreakpointList* breakpoints = &debugger->breakpoints; - size_t i; for (i = 0; i < ARMDebugBreakpointListSize(breakpoints); ++i) { - if (ARMDebugBreakpointListGetPointer(breakpoints, i)->address == address) { + if (ARMDebugBreakpointListGetPointer(breakpoints, i)->d.id == id) { _destroyBreakpoint(ARMDebugBreakpointListGetPointer(breakpoints, i)); ARMDebugBreakpointListShift(breakpoints, i, 1); + return true; } } + + struct ARMDebugBreakpointList* swBreakpoints = &debugger->swBreakpoints; + if (debugger->clearSoftwareBreakpoint) { + for (i = 0; i < ARMDebugBreakpointListSize(swBreakpoints); ++i) { + if (ARMDebugBreakpointListGetPointer(swBreakpoints, i)->d.id == id) { + debugger->clearSoftwareBreakpoint(debugger, ARMDebugBreakpointListGetPointer(swBreakpoints, i)); + ARMDebugBreakpointListShift(swBreakpoints, i, 1); + return true; + } + } + } + + struct mWatchpointList* watchpoints = &debugger->watchpoints; + for (i = 0; i < mWatchpointListSize(watchpoints); ++i) { + if (mWatchpointListGetPointer(watchpoints, i)->id == id) { + _destroyWatchpoint(mWatchpointListGetPointer(watchpoints, i)); + mWatchpointListShift(watchpoints, i, 1); + if (!mWatchpointListSize(&debugger->watchpoints)) { + ARMDebuggerRemoveMemoryShim(debugger); + } + return true; + } + } + return false; } -static bool ARMDebuggerHasBreakpoints(struct mDebuggerPlatform* d) { +static void ARMDebuggerListBreakpoints(struct mDebuggerPlatform* d, struct mBreakpointList* list) { struct ARMDebugger* debugger = (struct ARMDebugger*) d; - return ARMDebugBreakpointListSize(&debugger->breakpoints) || ARMDebugWatchpointListSize(&debugger->watchpoints); + mBreakpointListClear(list); + size_t i, s; + for (i = 0, s = 0; i < ARMDebugBreakpointListSize(&debugger->breakpoints) || s < ARMDebugBreakpointListSize(&debugger->swBreakpoints);) { + struct ARMDebugBreakpoint* hw = NULL; + struct ARMDebugBreakpoint* sw = NULL; + if (i < ARMDebugBreakpointListSize(&debugger->breakpoints)) { + hw = ARMDebugBreakpointListGetPointer(&debugger->breakpoints, i); + } + if (s < ARMDebugBreakpointListSize(&debugger->swBreakpoints)) { + sw = ARMDebugBreakpointListGetPointer(&debugger->swBreakpoints, s); + } + struct mBreakpoint* b = mBreakpointListAppend(list); + if (hw && sw) { + if (hw->d.id < sw->d.id) { + *b = hw->d; + ++i; + } else { + *b = sw->d; + ++s; + } + } else if (hw) { + *b = hw->d; + ++i; + } else if (sw) { + *b = sw->d; + ++s; + } else { + abort(); // Should be unreachable + } + } } -static void ARMDebuggerSetWatchpoint(struct mDebuggerPlatform* d, uint32_t address, int segment, enum mWatchpointType type) { - ARMDebuggerSetConditionalWatchpoint(d, address, segment, type, NULL); +static bool ARMDebuggerHasBreakpoints(struct mDebuggerPlatform* d) { + struct ARMDebugger* debugger = (struct ARMDebugger*) d; + return ARMDebugBreakpointListSize(&debugger->breakpoints) || mWatchpointListSize(&debugger->watchpoints); } -static void ARMDebuggerSetConditionalWatchpoint(struct mDebuggerPlatform* d, uint32_t address, int segment, enum mWatchpointType type, struct ParseTree* condition) { - UNUSED(segment); +static ssize_t ARMDebuggerSetWatchpoint(struct mDebuggerPlatform* d, const struct mWatchpoint* info) { struct ARMDebugger* debugger = (struct ARMDebugger*) d; - if (!ARMDebugWatchpointListSize(&debugger->watchpoints)) { + if (!mWatchpointListSize(&debugger->watchpoints)) { ARMDebuggerInstallMemoryShim(debugger); } - struct ARMDebugWatchpoint* watchpoint = ARMDebugWatchpointListAppend(&debugger->watchpoints); - watchpoint->address = address; - watchpoint->type = type; - watchpoint->condition = condition; + struct mWatchpoint* watchpoint = mWatchpointListAppend(&debugger->watchpoints); + ssize_t id = debugger->nextId; + ++debugger->nextId; + *watchpoint = *info; + watchpoint->id = id; + return id; } -static void ARMDebuggerClearWatchpoint(struct mDebuggerPlatform* d, uint32_t address, int segment) { - UNUSED(segment); +static void ARMDebuggerListWatchpoints(struct mDebuggerPlatform* d, struct mWatchpointList* list) { struct ARMDebugger* debugger = (struct ARMDebugger*) d; - struct ARMDebugWatchpointList* watchpoints = &debugger->watchpoints; - size_t i; - for (i = 0; i < ARMDebugWatchpointListSize(watchpoints); ++i) { - if (ARMDebugWatchpointListGetPointer(watchpoints, i)->address == address) { - _destroyWatchpoint(ARMDebugWatchpointListGetPointer(watchpoints, i)); - ARMDebugWatchpointListShift(watchpoints, i, 1); - } - } - if (!ARMDebugWatchpointListSize(&debugger->watchpoints)) { - ARMDebuggerRemoveMemoryShim(debugger); - } + mWatchpointListClear(list); + mWatchpointListCopy(list, &debugger->watchpoints); } static void ARMDebuggerTrace(struct mDebuggerPlatform* d, char* out, size_t* length) {
@@ -93,10 +93,10 @@ CREATE_SHIM(setActiveRegion, void, (struct ARMCore* cpu, uint32_t address), address)
static bool _checkWatchpoints(struct ARMDebugger* debugger, uint32_t address, struct mDebuggerEntryInfo* info, enum mWatchpointType type, uint32_t newValue, int width) { --width; - struct ARMDebugWatchpoint* watchpoint; + struct mWatchpoint* watchpoint; size_t i; - for (i = 0; i < ARMDebugWatchpointListSize(&debugger->watchpoints); ++i) { - watchpoint = ARMDebugWatchpointListGetPointer(&debugger->watchpoints, i); + for (i = 0; i < mWatchpointListSize(&debugger->watchpoints); ++i) { + watchpoint = mWatchpointListGetPointer(&debugger->watchpoints, i); if (!((watchpoint->address ^ address) & ~width) && watchpoint->type & type) { if (watchpoint->condition) { int32_t value;
@@ -46,9 +46,12 @@ static void _readHalfword(struct CLIDebugger*, struct CLIDebugVector*);
static void _readWord(struct CLIDebugger*, struct CLIDebugVector*); static void _setBreakpoint(struct CLIDebugger*, struct CLIDebugVector*); static void _clearBreakpoint(struct CLIDebugger*, struct CLIDebugVector*); -static void _setWatchpoint(struct CLIDebugger*, struct CLIDebugVector*); +static void _listBreakpoints(struct CLIDebugger*, struct CLIDebugVector*); +static void _setReadWriteWatchpoint(struct CLIDebugger*, struct CLIDebugVector*); static void _setReadWatchpoint(struct CLIDebugger*, struct CLIDebugVector*); static void _setWriteWatchpoint(struct CLIDebugger*, struct CLIDebugVector*); +static void _setWriteChangedWatchpoint(struct CLIDebugger*, struct CLIDebugVector*); +static void _listWatchpoints(struct CLIDebugger*, struct CLIDebugVector*); static void _trace(struct CLIDebugger*, struct CLIDebugVector*); static void _writeByte(struct CLIDebugger*, struct CLIDebugVector*); static void _writeHalfword(struct CLIDebugger*, struct CLIDebugVector*);@@ -75,6 +78,10 @@ { "h", _printHelp, "S", "Print help" },
{ "help", _printHelp, "S", "Print help" }, { "i", _printStatus, "", "Print the current status" }, { "info", _printStatus, "", "Print the current status" }, + { "lb", _listBreakpoints, "", "List breakpoints" }, + { "listb", _listBreakpoints, "", "List breakpoints" }, + { "lw", _listWatchpoints, "", "List watchpoints" }, + { "listw", _listWatchpoints, "", "List watchpoints" }, { "n", _next, "", "Execute next instruction" }, { "next", _next, "", "Execute next instruction" }, { "p", _print, "I", "Print a value" },@@ -91,12 +98,13 @@ { "r/2", _readHalfword, "I", "Read a halfword from a specified offset" },
{ "r/4", _readWord, "I", "Read a word from a specified offset" }, { "status", _printStatus, "", "Print the current status" }, { "trace", _trace, "I", "Trace a fixed number of instructions" }, - { "w", _setWatchpoint, "Is", "Set a watchpoint" }, + { "w", _setReadWriteWatchpoint, "Is", "Set a watchpoint" }, { "w/1", _writeByte, "II", "Write a byte at a specified offset" }, { "w/2", _writeHalfword, "II", "Write a halfword at a specified offset" }, { "w/r", _writeRegister, "SI", "Write a register" }, { "w/4", _writeWord, "II", "Write a word at a specified offset" }, - { "watch", _setWatchpoint, "Is", "Set a watchpoint" }, + { "watch", _setReadWriteWatchpoint, "Is", "Set a watchpoint" }, + { "watch/c", _setWriteChangedWatchpoint, "Is", "Set a change watchpoint" }, { "watch/r", _setReadWatchpoint, "Is", "Set a read watchpoint" }, { "watch/w", _setWriteWatchpoint, "Is", "Set a write watchpoint" }, { "x/1", _dumpByte, "Ii", "Examine bytes at a specified offset" },@@ -488,20 +496,24 @@ if (!dv || dv->type != CLIDV_INT_TYPE) {
debugger->backend->printf(debugger->backend, "%s\n", ERROR_MISSING_ARGS); return; } - uint32_t address = dv->intValue; + struct mBreakpoint breakpoint = { + .address = dv->intValue, + .segment = dv->segmentValue, + .type = BREAKPOINT_HARDWARE + }; if (dv->next && dv->next->type == CLIDV_CHAR_TYPE) { struct ParseTree* tree = _parseTree(dv->next->charValue); if (tree) { - debugger->d.platform->setConditionalBreakpoint(debugger->d.platform, address, dv->segmentValue, tree); + breakpoint.condition = tree; } else { debugger->backend->printf(debugger->backend, "%s\n", ERROR_INVALID_ARGS); + return; } - } else { - debugger->d.platform->setBreakpoint(debugger->d.platform, address, dv->segmentValue); } + debugger->d.platform->setBreakpoint(debugger->d.platform, &breakpoint); } -static void _setWatchpoint(struct CLIDebugger* debugger, struct CLIDebugVector* dv) { +static void _setWatchpoint(struct CLIDebugger* debugger, struct CLIDebugVector* dv, enum mWatchpointType type) { if (!dv || dv->type != CLIDV_INT_TYPE) { debugger->backend->printf(debugger->backend, "%s\n", ERROR_MISSING_ARGS); return;@@ -510,72 +522,80 @@ if (!debugger->d.platform->setWatchpoint) {
debugger->backend->printf(debugger->backend, "Watchpoints are not supported by this platform.\n"); return; } - uint32_t address = dv->intValue; + struct mWatchpoint watchpoint = { + .address = dv->intValue, + .segment = dv->segmentValue, + .type = type + }; if (dv->next && dv->next->type == CLIDV_CHAR_TYPE) { struct ParseTree* tree = _parseTree(dv->next->charValue); if (tree) { - debugger->d.platform->setConditionalWatchpoint(debugger->d.platform, address, dv->segmentValue, WATCHPOINT_RW, tree); + watchpoint.condition = tree; } else { debugger->backend->printf(debugger->backend, "%s\n", ERROR_INVALID_ARGS); + return; } - } else { - debugger->d.platform->setWatchpoint(debugger->d.platform, address, dv->segmentValue, WATCHPOINT_RW); } + debugger->d.platform->setWatchpoint(debugger->d.platform, &watchpoint); +} + +static void _setReadWriteWatchpoint(struct CLIDebugger* debugger, struct CLIDebugVector* dv) { + _setWatchpoint(debugger, dv, WATCHPOINT_RW); } static void _setReadWatchpoint(struct CLIDebugger* debugger, struct CLIDebugVector* dv) { + _setWatchpoint(debugger, dv, WATCHPOINT_READ); +} + +static void _setWriteWatchpoint(struct CLIDebugger* debugger, struct CLIDebugVector* dv) { + _setWatchpoint(debugger, dv, WATCHPOINT_WRITE); +} + +static void _setWriteChangedWatchpoint(struct CLIDebugger* debugger, struct CLIDebugVector* dv) { + _setWatchpoint(debugger, dv, WATCHPOINT_WRITE_CHANGE); +} + +static void _clearBreakpoint(struct CLIDebugger* debugger, struct CLIDebugVector* dv) { if (!dv || dv->type != CLIDV_INT_TYPE) { debugger->backend->printf(debugger->backend, "%s\n", ERROR_MISSING_ARGS); return; } - if (!debugger->d.platform->setWatchpoint) { - debugger->backend->printf(debugger->backend, "Watchpoints are not supported by this platform.\n"); - return; - } - uint32_t address = dv->intValue; - if (dv->next && dv->next->type == CLIDV_CHAR_TYPE) { - struct ParseTree* tree = _parseTree(dv->next->charValue); - if (tree) { - debugger->d.platform->setConditionalWatchpoint(debugger->d.platform, address, dv->segmentValue, WATCHPOINT_READ, tree); + uint64_t id = dv->intValue; + debugger->d.platform->clearBreakpoint(debugger->d.platform, id); +} + +static void _listBreakpoints(struct CLIDebugger* debugger, struct CLIDebugVector* dv) { + UNUSED(dv); + struct mBreakpointList breakpoints; + mBreakpointListInit(&breakpoints, 0); + debugger->d.platform->listBreakpoints(debugger->d.platform, &breakpoints); + size_t i; + for (i = 0; i < mBreakpointListSize(&breakpoints); ++i) { + struct mBreakpoint* breakpoint = mBreakpointListGetPointer(&breakpoints, i); + if (breakpoint->segment >= 0) { + debugger->backend->printf(debugger->backend, "%" PRIz "i: %02X:%X\n", breakpoint->id, breakpoint->segment, breakpoint->address); } else { - debugger->backend->printf(debugger->backend, "%s\n", ERROR_INVALID_ARGS); + debugger->backend->printf(debugger->backend, "%" PRIz "i: 0x%X\n", breakpoint->id, breakpoint->address); } - } else { - debugger->d.platform->setWatchpoint(debugger->d.platform, address, dv->segmentValue, WATCHPOINT_READ); } + mBreakpointListDeinit(&breakpoints); } -static void _setWriteWatchpoint(struct CLIDebugger* debugger, struct CLIDebugVector* dv) { - if (!dv || dv->type != CLIDV_INT_TYPE) { - debugger->backend->printf(debugger->backend, "%s\n", ERROR_MISSING_ARGS); - return; - } - if (!debugger->d.platform->setWatchpoint) { - debugger->backend->printf(debugger->backend, "Watchpoints are not supported by this platform.\n"); - return; - } - uint32_t address = dv->intValue; - if (dv->next && dv->next->type == CLIDV_CHAR_TYPE) { - struct ParseTree* tree = _parseTree(dv->next->charValue); - if (tree) { - debugger->d.platform->setConditionalWatchpoint(debugger->d.platform, address, dv->segmentValue, WATCHPOINT_WRITE, tree); +static void _listWatchpoints(struct CLIDebugger* debugger, struct CLIDebugVector* dv) { + UNUSED(dv); + struct mWatchpointList watchpoints; + mWatchpointListInit(&watchpoints, 0); + debugger->d.platform->listWatchpoints(debugger->d.platform, &watchpoints); + size_t i; + for (i = 0; i < mWatchpointListSize(&watchpoints); ++i) { + struct mWatchpoint* watchpoint = mWatchpointListGetPointer(&watchpoints, i); + if (watchpoint->segment >= 0) { + debugger->backend->printf(debugger->backend, "%" PRIz "i: %02X:%X\n", watchpoint->id, watchpoint->segment, watchpoint->address); } else { - debugger->backend->printf(debugger->backend, "%s\n", ERROR_INVALID_ARGS); + debugger->backend->printf(debugger->backend, "%" PRIz "i: 0x%X\n", watchpoint->id, watchpoint->address); } - } else { - debugger->d.platform->setWatchpoint(debugger->d.platform, address, dv->segmentValue, WATCHPOINT_WRITE); - }} - -static void _clearBreakpoint(struct CLIDebugger* debugger, struct CLIDebugVector* dv) { - if (!dv || dv->type != CLIDV_INT_TYPE) { - debugger->backend->printf(debugger->backend, "%s\n", ERROR_MISSING_ARGS); - return; } - 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, dv->segmentValue); - } + mWatchpointListDeinit(&watchpoints); } static void _trace(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
@@ -22,6 +22,9 @@ const uint32_t DEBUGGER_ID = 0xDEADBEEF;
mLOG_DEFINE_CATEGORY(DEBUGGER, "Debugger", "core.debugger"); +DEFINE_VECTOR(mBreakpointList, struct mBreakpoint); +DEFINE_VECTOR(mWatchpointList, struct mWatchpoint); + static void mDebuggerInit(void* cpu, struct mCPUComponent* component); static void mDebuggerDeinit(struct mCPUComponent* component);
@@ -62,6 +62,8 @@ stub->d.state = DEBUGGER_RUNNING;
} return; } + // Fall through + case WATCHPOINT_WRITE_CHANGE: type = "watch"; break; case WATCHPOINT_READ:@@ -488,21 +490,32 @@ uint32_t address = _readHex(readAddress, &i);
readAddress += i + 1; uint32_t kind = _readHex(readAddress, &i); + struct mBreakpoint breakpoint = { + .address = address, + .type = BREAKPOINT_HARDWARE + }; + struct mWatchpoint watchpoint = { + .address = address + }; + switch (message[0]) { case '0': ARMDebuggerSetSoftwareBreakpoint(stub->d.platform, address, kind == 2 ? MODE_THUMB : MODE_ARM); break; case '1': - stub->d.platform->setBreakpoint(stub->d.platform, address, -1); + stub->d.platform->setBreakpoint(stub->d.platform, &breakpoint); break; case '2': - stub->d.platform->setWatchpoint(stub->d.platform, address, -1, WATCHPOINT_WRITE); + watchpoint.type = WATCHPOINT_WRITE_CHANGE; + stub->d.platform->setWatchpoint(stub->d.platform, &watchpoint); break; case '3': - stub->d.platform->setWatchpoint(stub->d.platform, address, -1, WATCHPOINT_READ); + watchpoint.type = WATCHPOINT_READ; + stub->d.platform->setWatchpoint(stub->d.platform, &watchpoint); break; case '4': - stub->d.platform->setWatchpoint(stub->d.platform, address, -1, WATCHPOINT_RW); + watchpoint.type = WATCHPOINT_RW; + stub->d.platform->setWatchpoint(stub->d.platform, &watchpoint); break; default: stub->outgoing[0] = '\0';@@ -517,17 +530,35 @@ static void _clearBreakpoint(struct GDBStub* stub, const char* message) {
const char* readAddress = &message[2]; unsigned i = 0; uint32_t address = _readHex(readAddress, &i); + struct mBreakpointList breakpoints; + struct mWatchpointList watchpoints; + + size_t index; switch (message[0]) { case '0': - ARMDebuggerClearSoftwareBreakpoint(stub->d.platform, address); - break; case '1': - stub->d.platform->clearBreakpoint(stub->d.platform, address, -1); + mBreakpointListInit(&breakpoints, 0); + stub->d.platform->listBreakpoints(stub->d.platform, &breakpoints); + for (index = 0; index < mBreakpointListSize(&breakpoints); ++index) { + if (mBreakpointListGetPointer(&breakpoints, index)->address != address) { + continue; + } + stub->d.platform->clearBreakpoint(stub->d.platform, mBreakpointListGetPointer(&breakpoints, index)->id); + } + mBreakpointListDeinit(&breakpoints); break; case '2': case '3': case '4': - stub->d.platform->clearWatchpoint(stub->d.platform, address, -1); + mWatchpointListInit(&watchpoints, 0); + stub->d.platform->listWatchpoints(stub->d.platform, &watchpoints); + for (index = 0; index < mWatchpointListSize(&watchpoints); ++index) { + if (mWatchpointListGetPointer(&watchpoints, index)->address != address) { + continue; + } + stub->d.platform->clearBreakpoint(stub->d.platform, mWatchpointListGetPointer(&watchpoints, index)->id); + } + mWatchpointListDeinit(&watchpoints); break; default: break;
@@ -11,27 +11,28 @@ #include <mgba/internal/lr35902/decoder.h>
#include <mgba/internal/lr35902/lr35902.h> #include <mgba/internal/lr35902/debugger/memory-debugger.h> -DEFINE_VECTOR(LR35902DebugBreakpointList, struct LR35902DebugBreakpoint); -DEFINE_VECTOR(LR35902DebugWatchpointList, struct LR35902DebugWatchpoint); - -static struct LR35902DebugBreakpoint* _lookupBreakpoint(struct LR35902DebugBreakpointList* breakpoints, uint16_t address) { +static struct mBreakpoint* _lookupBreakpoint(struct mBreakpointList* breakpoints, struct LR35902Core* cpu) { size_t i; - for (i = 0; i < LR35902DebugBreakpointListSize(breakpoints); ++i) { - if (LR35902DebugBreakpointListGetPointer(breakpoints, i)->address == address) { - return LR35902DebugBreakpointListGetPointer(breakpoints, i); + for (i = 0; i < mBreakpointListSize(breakpoints); ++i) { + struct mBreakpoint* breakpoint = mBreakpointListGetPointer(breakpoints, i); + if (breakpoint->address != cpu->pc) { + continue; + } + if (breakpoint->segment < 0 || breakpoint->segment == cpu->memory.currentSegment(cpu, breakpoint->address)) { + return breakpoint; } } - return 0; + return NULL; } -static void _destroyBreakpoint(struct LR35902DebugBreakpoint* breakpoint) { +static void _destroyBreakpoint(struct mBreakpoint* breakpoint) { if (breakpoint->condition) { parseFree(breakpoint->condition); free(breakpoint->condition); } } -static void _destroyWatchpoint(struct LR35902DebugWatchpoint* watchpoint) { +static void _destroyWatchpoint(struct mWatchpoint* watchpoint) { if (watchpoint->condition) { parseFree(watchpoint->condition); free(watchpoint->condition);@@ -40,11 +41,8 @@ }
static void LR35902DebuggerCheckBreakpoints(struct mDebuggerPlatform* d) { struct LR35902Debugger* debugger = (struct LR35902Debugger*) d; - struct LR35902DebugBreakpoint* breakpoint = _lookupBreakpoint(&debugger->breakpoints, debugger->cpu->pc); + struct mBreakpoint* breakpoint = _lookupBreakpoint(&debugger->breakpoints, debugger->cpu); if (!breakpoint) { - return; - } - if (breakpoint->segment >= 0 && debugger->cpu->memory.currentSegment(debugger->cpu, breakpoint->address) != breakpoint->segment) { return; } if (breakpoint->condition) {@@ -65,12 +63,11 @@ static void LR35902DebuggerDeinit(struct mDebuggerPlatform* platform);
static void LR35902DebuggerEnter(struct mDebuggerPlatform* d, enum mDebuggerEntryReason reason, struct mDebuggerEntryInfo* info); -static void LR35902DebuggerSetBreakpoint(struct mDebuggerPlatform*, uint32_t address, int segment); -static void LR35902DebuggerSetConditionalBreakpoint(struct mDebuggerPlatform*, uint32_t address, int segment, struct ParseTree* condition); -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 LR35902DebuggerSetConditionalWatchpoint(struct mDebuggerPlatform*, uint32_t address, int segment, enum mWatchpointType type, struct ParseTree* condition); -static void LR35902DebuggerClearWatchpoint(struct mDebuggerPlatform*, uint32_t address, int segment); +static ssize_t LR35902DebuggerSetBreakpoint(struct mDebuggerPlatform*, const struct mBreakpoint*); +static void LR35902DebuggerListBreakpoints(struct mDebuggerPlatform*, struct mBreakpointList*); +static bool LR35902DebuggerClearBreakpoint(struct mDebuggerPlatform*, ssize_t id); +static ssize_t LR35902DebuggerSetWatchpoint(struct mDebuggerPlatform*, const struct mWatchpoint*); +static void LR35902DebuggerListWatchpoints(struct mDebuggerPlatform*, struct mWatchpointList*); static void LR35902DebuggerCheckBreakpoints(struct mDebuggerPlatform*); static bool LR35902DebuggerHasBreakpoints(struct mDebuggerPlatform*); static void LR35902DebuggerTrace(struct mDebuggerPlatform*, char* out, size_t* length);@@ -83,11 +80,10 @@ platform->entered = LR35902DebuggerEnter;
platform->init = LR35902DebuggerInit; platform->deinit = LR35902DebuggerDeinit; platform->setBreakpoint = LR35902DebuggerSetBreakpoint; - platform->setConditionalBreakpoint = LR35902DebuggerSetConditionalBreakpoint; + platform->listBreakpoints = LR35902DebuggerListBreakpoints; platform->clearBreakpoint = LR35902DebuggerClearBreakpoint; platform->setWatchpoint = LR35902DebuggerSetWatchpoint; - platform->setConditionalWatchpoint = LR35902DebuggerSetConditionalWatchpoint; - platform->clearWatchpoint = LR35902DebuggerClearWatchpoint; + platform->listWatchpoints = LR35902DebuggerListWatchpoints; platform->checkBreakpoints = LR35902DebuggerCheckBreakpoints; platform->hasBreakpoints = LR35902DebuggerHasBreakpoints; platform->trace = LR35902DebuggerTrace;@@ -100,22 +96,23 @@ void LR35902DebuggerInit(void* cpu, struct mDebuggerPlatform* platform) {
struct LR35902Debugger* debugger = (struct LR35902Debugger*) platform; debugger->cpu = cpu; debugger->originalMemory = debugger->cpu->memory; - LR35902DebugBreakpointListInit(&debugger->breakpoints, 0); - LR35902DebugWatchpointListInit(&debugger->watchpoints, 0); + mBreakpointListInit(&debugger->breakpoints, 0); + mWatchpointListInit(&debugger->watchpoints, 0); + debugger->nextId = 1; } void LR35902DebuggerDeinit(struct mDebuggerPlatform* platform) { struct LR35902Debugger* debugger = (struct LR35902Debugger*) platform; size_t i; - for (i = 0; i < LR35902DebugBreakpointListSize(&debugger->breakpoints); ++i) { - _destroyBreakpoint(LR35902DebugBreakpointListGetPointer(&debugger->breakpoints, i)); + for (i = 0; i < mBreakpointListSize(&debugger->breakpoints); ++i) { + _destroyBreakpoint(mBreakpointListGetPointer(&debugger->breakpoints, i)); } - LR35902DebugBreakpointListDeinit(&debugger->breakpoints); + mBreakpointListDeinit(&debugger->breakpoints); - for (i = 0; i < LR35902DebugWatchpointListSize(&debugger->watchpoints); ++i) { - _destroyWatchpoint(LR35902DebugWatchpointListGetPointer(&debugger->watchpoints, i)); + for (i = 0; i < mWatchpointListSize(&debugger->watchpoints); ++i) { + _destroyWatchpoint(mWatchpointListGetPointer(&debugger->watchpoints, i)); } - LR35902DebugWatchpointListDeinit(&debugger->watchpoints); + mWatchpointListDeinit(&debugger->watchpoints); } static void LR35902DebuggerEnter(struct mDebuggerPlatform* platform, enum mDebuggerEntryReason reason, struct mDebuggerEntryInfo* info) {@@ -130,65 +127,72 @@ debugger->d.p->entered(debugger->d.p, reason, info);
} } -static void LR35902DebuggerSetBreakpoint(struct mDebuggerPlatform* d, uint32_t address, int segment) { - LR35902DebuggerSetConditionalBreakpoint(d, address, segment, NULL); -} - -static void LR35902DebuggerSetConditionalBreakpoint(struct mDebuggerPlatform* d, uint32_t address, int segment, struct ParseTree* condition) { +static ssize_t LR35902DebuggerSetBreakpoint(struct mDebuggerPlatform* d, const struct mBreakpoint* info) { struct LR35902Debugger* debugger = (struct LR35902Debugger*) d; - struct LR35902DebugBreakpoint* breakpoint = LR35902DebugBreakpointListAppend(&debugger->breakpoints); - breakpoint->address = address; - breakpoint->segment = segment; - breakpoint->condition = condition; + struct mBreakpoint* breakpoint = mBreakpointListAppend(&debugger->breakpoints); + *breakpoint = *info; + breakpoint->id = debugger->nextId; + ++debugger->nextId; + return breakpoint->id; + } -static void LR35902DebuggerClearBreakpoint(struct mDebuggerPlatform* d, uint32_t address, int segment) { +static bool LR35902DebuggerClearBreakpoint(struct mDebuggerPlatform* d, ssize_t id) { struct LR35902Debugger* debugger = (struct LR35902Debugger*) d; - struct LR35902DebugBreakpointList* breakpoints = &debugger->breakpoints; size_t i; - for (i = 0; i < LR35902DebugBreakpointListSize(breakpoints); ++i) { - struct LR35902DebugBreakpoint* breakpoint = LR35902DebugBreakpointListGetPointer(breakpoints, i); - if (breakpoint->address == address && breakpoint->segment == segment) { - _destroyBreakpoint(LR35902DebugBreakpointListGetPointer(breakpoints, i)); - LR35902DebugBreakpointListShift(breakpoints, i, 1); + + struct mBreakpointList* breakpoints = &debugger->breakpoints; + for (i = 0; i < mBreakpointListSize(breakpoints); ++i) { + struct mBreakpoint* breakpoint = mBreakpointListGetPointer(breakpoints, i); + if (breakpoint->id == id) { + _destroyBreakpoint(breakpoint); + mBreakpointListShift(breakpoints, i, 1); + return true; + } + } + + struct mWatchpointList* watchpoints = &debugger->watchpoints; + for (i = 0; i < mWatchpointListSize(watchpoints); ++i) { + struct mWatchpoint* watchpoint = mWatchpointListGetPointer(watchpoints, i); + if (watchpoint->id == id) { + _destroyWatchpoint(watchpoint); + mWatchpointListShift(watchpoints, i, 1); + if (!mWatchpointListSize(&debugger->watchpoints)) { + LR35902DebuggerRemoveMemoryShim(debugger); + } + return true; } } + return false; } static bool LR35902DebuggerHasBreakpoints(struct mDebuggerPlatform* d) { struct LR35902Debugger* debugger = (struct LR35902Debugger*) d; - return LR35902DebugBreakpointListSize(&debugger->breakpoints) || LR35902DebugWatchpointListSize(&debugger->watchpoints); + return mBreakpointListSize(&debugger->breakpoints) || mWatchpointListSize(&debugger->watchpoints); } -static void LR35902DebuggerSetWatchpoint(struct mDebuggerPlatform* d, uint32_t address, int segment, enum mWatchpointType type) { - LR35902DebuggerSetConditionalWatchpoint(d, address, segment, type, NULL); +static ssize_t LR35902DebuggerSetWatchpoint(struct mDebuggerPlatform* d, const struct mWatchpoint* info) { + struct LR35902Debugger* debugger = (struct LR35902Debugger*) d; + if (!mWatchpointListSize(&debugger->watchpoints)) { + LR35902DebuggerInstallMemoryShim(debugger); + } + struct mWatchpoint* watchpoint = mWatchpointListAppend(&debugger->watchpoints); + *watchpoint = *info; + watchpoint->id = debugger->nextId; + ++debugger->nextId; + return watchpoint->id; } -static void LR35902DebuggerSetConditionalWatchpoint(struct mDebuggerPlatform* d, uint32_t address, int segment, enum mWatchpointType type, struct ParseTree* condition) { +static void LR35902DebuggerListBreakpoints(struct mDebuggerPlatform* d, struct mBreakpointList* list) { 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; - watchpoint->condition = condition; + mBreakpointListClear(list); + mBreakpointListCopy(list, &debugger->breakpoints); } -static void LR35902DebuggerClearWatchpoint(struct mDebuggerPlatform* d, uint32_t address, int segment) { +static void LR35902DebuggerListWatchpoints(struct mDebuggerPlatform* d, struct mWatchpointList* list) { 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); - } + mWatchpointListClear(list); + mWatchpointListCopy(list, &debugger->watchpoints); } static void LR35902DebuggerTrace(struct mDebuggerPlatform* d, char* out, size_t* length) {
@@ -43,10 +43,10 @@ CREATE_WATCHPOINT_SHIM(load8, READ, 0, uint8_t, (struct LR35902Core* cpu, uint16_t address), address)
CREATE_WATCHPOINT_SHIM(store8, WRITE, value, void, (struct LR35902Core* cpu, uint16_t address, int8_t value), address, value) static bool _checkWatchpoints(struct LR35902Debugger* debugger, uint16_t address, struct mDebuggerEntryInfo* info, enum mWatchpointType type, uint8_t newValue) { - struct LR35902DebugWatchpoint* watchpoint; + struct mWatchpoint* watchpoint; size_t i; - for (i = 0; i < LR35902DebugWatchpointListSize(&debugger->watchpoints); ++i) { - watchpoint = LR35902DebugWatchpointListGetPointer(&debugger->watchpoints, i); + for (i = 0; i < mWatchpointListSize(&debugger->watchpoints); ++i) { + watchpoint = mWatchpointListGetPointer(&debugger->watchpoints, i); if (watchpoint->address == address && (watchpoint->segment < 0 || watchpoint->segment == debugger->originalMemory.currentSegment(debugger->cpu, address)) && watchpoint->type & type) { if (watchpoint->condition) { int32_t value;