Debugger: Conditional watchpoints

This commit is contained in:
Vicki Pfau 2017-12-29 16:38:46 -05:00
parent 0383c82b46
commit 0131a196d1
9 changed files with 129 additions and 47 deletions

View File

@ -11,7 +11,7 @@ Features:
- Automatic cheat loading and saving - Automatic cheat loading and saving
- GameShark and Action Replay button support - GameShark and Action Replay button support
- AGBPrint support - AGBPrint support
- Debugger: Conditional breakpoints - Debugger: Conditional breakpoints and watchpoints
Bugfixes: Bugfixes:
- GB Audio: Make audio unsigned with bias (fixes mgba.io/i/749) - GB Audio: Make audio unsigned with bias (fixes mgba.io/i/749)
- GB Serialize: Fix audio state loading - GB Serialize: Fix audio state loading

View File

@ -83,6 +83,7 @@ struct mDebuggerPlatform {
void (*setConditionalBreakpoint)(struct mDebuggerPlatform*, uint32_t address, int segment, struct ParseTree* condition); void (*setConditionalBreakpoint)(struct mDebuggerPlatform*, uint32_t address, int segment, struct ParseTree* condition);
void (*clearBreakpoint)(struct mDebuggerPlatform*, uint32_t address, int segment); void (*clearBreakpoint)(struct mDebuggerPlatform*, uint32_t address, int segment);
void (*setWatchpoint)(struct mDebuggerPlatform*, uint32_t address, int segment, enum mWatchpointType type); 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 (*clearWatchpoint)(struct mDebuggerPlatform*, uint32_t address, int segment);
void (*checkBreakpoints)(struct mDebuggerPlatform*); void (*checkBreakpoints)(struct mDebuggerPlatform*);
void (*trace)(struct mDebuggerPlatform*, char* out, size_t* length); void (*trace)(struct mDebuggerPlatform*, char* out, size_t* length);

View File

@ -29,6 +29,7 @@ struct ARMDebugBreakpoint {
struct ARMDebugWatchpoint { struct ARMDebugWatchpoint {
uint32_t address; uint32_t address;
enum mWatchpointType type; enum mWatchpointType type;
struct ParseTree* condition;
}; };
DECLARE_VECTOR(ARMDebugBreakpointList, struct ARMDebugBreakpoint); DECLARE_VECTOR(ARMDebugBreakpointList, struct ARMDebugBreakpoint);

View File

@ -26,6 +26,7 @@ struct LR35902DebugWatchpoint {
uint16_t address; uint16_t address;
int segment; int segment;
enum mWatchpointType type; enum mWatchpointType type;
struct ParseTree* condition;
}; };
struct LR35902Segment { struct LR35902Segment {

View File

@ -32,6 +32,13 @@ static void _destroyBreakpoint(struct ARMDebugBreakpoint* breakpoint) {
} }
} }
static void _destroyWatchpoint(struct ARMDebugWatchpoint* watchpoint) {
if (watchpoint->condition) {
parseFree(watchpoint->condition);
free(watchpoint->condition);
}
}
static void ARMDebuggerCheckBreakpoints(struct mDebuggerPlatform* d) { static void ARMDebuggerCheckBreakpoints(struct mDebuggerPlatform* d) {
struct ARMDebugger* debugger = (struct ARMDebugger*) d; struct ARMDebugger* debugger = (struct ARMDebugger*) d;
int instructionLength; int instructionLength;
@ -68,6 +75,7 @@ static void ARMDebuggerSetBreakpoint(struct mDebuggerPlatform*, uint32_t address
static void ARMDebuggerSetConditionalBreakpoint(struct mDebuggerPlatform*, uint32_t address, int segment, struct ParseTree* condition); 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 ARMDebuggerClearBreakpoint(struct mDebuggerPlatform*, uint32_t address, int segment);
static void ARMDebuggerSetWatchpoint(struct mDebuggerPlatform*, uint32_t address, int segment, enum mWatchpointType type); 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 void ARMDebuggerClearWatchpoint(struct mDebuggerPlatform*, uint32_t address, int segment);
static void ARMDebuggerCheckBreakpoints(struct mDebuggerPlatform*); static void ARMDebuggerCheckBreakpoints(struct mDebuggerPlatform*);
static bool ARMDebuggerHasBreakpoints(struct mDebuggerPlatform*); static bool ARMDebuggerHasBreakpoints(struct mDebuggerPlatform*);
@ -84,6 +92,7 @@ struct mDebuggerPlatform* ARMDebuggerPlatformCreate(void) {
platform->setConditionalBreakpoint = ARMDebuggerSetConditionalBreakpoint; platform->setConditionalBreakpoint = ARMDebuggerSetConditionalBreakpoint;
platform->clearBreakpoint = ARMDebuggerClearBreakpoint; platform->clearBreakpoint = ARMDebuggerClearBreakpoint;
platform->setWatchpoint = ARMDebuggerSetWatchpoint; platform->setWatchpoint = ARMDebuggerSetWatchpoint;
platform->setConditionalWatchpoint = ARMDebuggerSetConditionalWatchpoint;
platform->clearWatchpoint = ARMDebuggerClearWatchpoint; platform->clearWatchpoint = ARMDebuggerClearWatchpoint;
platform->checkBreakpoints = ARMDebuggerCheckBreakpoints; platform->checkBreakpoints = ARMDebuggerCheckBreakpoints;
platform->hasBreakpoints = ARMDebuggerHasBreakpoints; platform->hasBreakpoints = ARMDebuggerHasBreakpoints;
@ -119,6 +128,10 @@ void ARMDebuggerDeinit(struct mDebuggerPlatform* platform) {
_destroyBreakpoint(ARMDebugBreakpointListGetPointer(&debugger->breakpoints, i)); _destroyBreakpoint(ARMDebugBreakpointListGetPointer(&debugger->breakpoints, i));
} }
ARMDebugBreakpointListDeinit(&debugger->breakpoints); ARMDebugBreakpointListDeinit(&debugger->breakpoints);
for (i = 0; i < ARMDebugWatchpointListSize(&debugger->watchpoints); ++i) {
_destroyWatchpoint(ARMDebugWatchpointListGetPointer(&debugger->watchpoints, i));
}
ARMDebugBreakpointListDeinit(&debugger->swBreakpoints); ARMDebugBreakpointListDeinit(&debugger->swBreakpoints);
ARMDebugWatchpointListDeinit(&debugger->watchpoints); ARMDebugWatchpointListDeinit(&debugger->watchpoints);
} }
@ -186,12 +199,7 @@ void ARMDebuggerClearSoftwareBreakpoint(struct mDebuggerPlatform* d, uint32_t ad
} }
static void ARMDebuggerSetBreakpoint(struct mDebuggerPlatform* d, uint32_t address, int segment) { static void ARMDebuggerSetBreakpoint(struct mDebuggerPlatform* d, uint32_t address, int segment) {
UNUSED(segment); ARMDebuggerSetConditionalBreakpoint(d, address, segment, NULL);
struct ARMDebugger* debugger = (struct ARMDebugger*) d;
struct ARMDebugBreakpoint* breakpoint = ARMDebugBreakpointListAppend(&debugger->breakpoints);
breakpoint->condition = NULL;
breakpoint->address = address;
breakpoint->isSw = false;
} }
static void ARMDebuggerSetConditionalBreakpoint(struct mDebuggerPlatform* d, uint32_t address, int segment, struct ParseTree* condition) { static void ARMDebuggerSetConditionalBreakpoint(struct mDebuggerPlatform* d, uint32_t address, int segment, struct ParseTree* condition) {
@ -222,6 +230,10 @@ static bool ARMDebuggerHasBreakpoints(struct mDebuggerPlatform* d) {
} }
static void ARMDebuggerSetWatchpoint(struct mDebuggerPlatform* d, uint32_t address, int segment, enum mWatchpointType type) { static void ARMDebuggerSetWatchpoint(struct mDebuggerPlatform* d, uint32_t address, int segment, enum mWatchpointType type) {
ARMDebuggerSetConditionalWatchpoint(d, address, segment, type, NULL);
}
static void ARMDebuggerSetConditionalWatchpoint(struct mDebuggerPlatform* d, uint32_t address, int segment, enum mWatchpointType type, struct ParseTree* condition) {
UNUSED(segment); UNUSED(segment);
struct ARMDebugger* debugger = (struct ARMDebugger*) d; struct ARMDebugger* debugger = (struct ARMDebugger*) d;
if (!ARMDebugWatchpointListSize(&debugger->watchpoints)) { if (!ARMDebugWatchpointListSize(&debugger->watchpoints)) {
@ -230,6 +242,7 @@ static void ARMDebuggerSetWatchpoint(struct mDebuggerPlatform* d, uint32_t addre
struct ARMDebugWatchpoint* watchpoint = ARMDebugWatchpointListAppend(&debugger->watchpoints); struct ARMDebugWatchpoint* watchpoint = ARMDebugWatchpointListAppend(&debugger->watchpoints);
watchpoint->address = address; watchpoint->address = address;
watchpoint->type = type; watchpoint->type = type;
watchpoint->condition = condition;
} }
static void ARMDebuggerClearWatchpoint(struct mDebuggerPlatform* d, uint32_t address, int segment) { static void ARMDebuggerClearWatchpoint(struct mDebuggerPlatform* d, uint32_t address, int segment) {
@ -239,6 +252,7 @@ static void ARMDebuggerClearWatchpoint(struct mDebuggerPlatform* d, uint32_t add
size_t i; size_t i;
for (i = 0; i < ARMDebugWatchpointListSize(watchpoints); ++i) { for (i = 0; i < ARMDebugWatchpointListSize(watchpoints); ++i) {
if (ARMDebugWatchpointListGetPointer(watchpoints, i)->address == address) { if (ARMDebugWatchpointListGetPointer(watchpoints, i)->address == address) {
_destroyWatchpoint(ARMDebugWatchpointListGetPointer(watchpoints, i));
ARMDebugWatchpointListShift(watchpoints, i, 1); ARMDebugWatchpointListShift(watchpoints, i, 1);
} }
} }

View File

@ -6,6 +6,7 @@
#include <mgba/internal/arm/debugger/memory-debugger.h> #include <mgba/internal/arm/debugger/memory-debugger.h>
#include <mgba/internal/arm/debugger/debugger.h> #include <mgba/internal/arm/debugger/debugger.h>
#include <mgba/internal/debugger/parser.h>
#include <mgba-util/math.h> #include <mgba-util/math.h>
@ -97,6 +98,14 @@ static bool _checkWatchpoints(struct ARMDebugger* debugger, uint32_t address, st
for (i = 0; i < ARMDebugWatchpointListSize(&debugger->watchpoints); ++i) { for (i = 0; i < ARMDebugWatchpointListSize(&debugger->watchpoints); ++i) {
watchpoint = ARMDebugWatchpointListGetPointer(&debugger->watchpoints, i); watchpoint = ARMDebugWatchpointListGetPointer(&debugger->watchpoints, i);
if (!((watchpoint->address ^ address) & ~width) && watchpoint->type & type) { if (!((watchpoint->address ^ address) & ~width) && watchpoint->type & type) {
if (watchpoint->condition) {
int32_t value;
int segment;
if (!mDebuggerEvaluateParseTree(debugger->d.p, watchpoint->condition, &value, &segment) || !(value || segment >= 0)) {
return false;
}
}
switch (width + 1) { switch (width + 1) {
case 1: case 1:
info->type.wp.oldValue = debugger->originalMemory.load8(debugger->cpu, address, 0); info->type.wp.oldValue = debugger->originalMemory.load8(debugger->cpu, address, 0);

View File

@ -91,14 +91,14 @@ static struct CLIDebuggerCommandSummary _debuggerCommands[] = {
{ "r/4", _readWord, "I", "Read a word from a specified offset" }, { "r/4", _readWord, "I", "Read a word from a specified offset" },
{ "status", _printStatus, "", "Print the current status" }, { "status", _printStatus, "", "Print the current status" },
{ "trace", _trace, "I", "Trace a fixed number of instructions" }, { "trace", _trace, "I", "Trace a fixed number of instructions" },
{ "w", _setWatchpoint, "I", "Set a watchpoint" }, { "w", _setWatchpoint, "Is", "Set a watchpoint" },
{ "w/1", _writeByte, "II", "Write a byte at a specified offset" }, { "w/1", _writeByte, "II", "Write a byte at a specified offset" },
{ "w/2", _writeHalfword, "II", "Write a halfword at a specified offset" }, { "w/2", _writeHalfword, "II", "Write a halfword at a specified offset" },
{ "w/r", _writeRegister, "SI", "Write a register" }, { "w/r", _writeRegister, "SI", "Write a register" },
{ "w/4", _writeWord, "II", "Write a word at a specified offset" }, { "w/4", _writeWord, "II", "Write a word at a specified offset" },
{ "watch", _setWatchpoint, "I", "Set a watchpoint" }, { "watch", _setWatchpoint, "Is", "Set a watchpoint" },
{ "watch/r", _setReadWatchpoint, "I", "Set a read watchpoint" }, { "watch/r", _setReadWatchpoint, "Is", "Set a read watchpoint" },
{ "watch/w", _setWriteWatchpoint, "I", "Set a write watchpoint" }, { "watch/w", _setWriteWatchpoint, "Is", "Set a write watchpoint" },
{ "x/1", _dumpByte, "Ii", "Examine bytes at a specified offset" }, { "x/1", _dumpByte, "Ii", "Examine bytes at a specified offset" },
{ "x/2", _dumpHalfword, "Ii", "Examine halfwords at a specified offset" }, { "x/2", _dumpHalfword, "Ii", "Examine halfwords at a specified offset" },
{ "x/4", _dumpWord, "Ii", "Examine words at a specified offset" }, { "x/4", _dumpWord, "Ii", "Examine words at a specified offset" },
@ -452,18 +452,11 @@ static void _source(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
} }
#endif #endif
static void _setBreakpoint(struct CLIDebugger* debugger, struct CLIDebugVector* dv) { static struct ParseTree* _parseTree(const char* string) {
if (!dv || dv->type != CLIDV_INT_TYPE) {
debugger->backend->printf(debugger->backend, "%s\n", ERROR_MISSING_ARGS);
return;
}
uint32_t address = dv->intValue;
if (dv->next && dv->next->type == CLIDV_CHAR_TYPE) {
struct LexVector lv; struct LexVector lv;
bool error = false; bool error = false;
LexVectorInit(&lv, 0); LexVectorInit(&lv, 0);
const char* string = dv->next->charValue; size_t length = strlen(string);
size_t length = strlen(dv->next->charValue);
size_t adjusted = lexExpression(&lv, string, length, NULL); size_t adjusted = lexExpression(&lv, string, length, NULL);
struct ParseTree* tree = malloc(sizeof(*tree)); struct ParseTree* tree = malloc(sizeof(*tree));
if (!adjusted) { if (!adjusted) {
@ -484,9 +477,24 @@ static void _setBreakpoint(struct CLIDebugger* debugger, struct CLIDebugVector*
if (error) { if (error) {
parseFree(tree); parseFree(tree);
free(tree); free(tree);
debugger->backend->printf(debugger->backend, "%s\n", ERROR_INVALID_ARGS); return NULL;
} else { } else {
return tree;
}
}
static void _setBreakpoint(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;
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); debugger->d.platform->setConditionalBreakpoint(debugger->d.platform, address, dv->segmentValue, tree);
} else {
debugger->backend->printf(debugger->backend, "%s\n", ERROR_INVALID_ARGS);
} }
} else { } else {
debugger->d.platform->setBreakpoint(debugger->d.platform, address, dv->segmentValue); debugger->d.platform->setBreakpoint(debugger->d.platform, address, dv->segmentValue);
@ -503,8 +511,17 @@ static void _setWatchpoint(struct CLIDebugger* debugger, struct CLIDebugVector*
return; return;
} }
uint32_t address = dv->intValue; 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_RW, tree);
} else {
debugger->backend->printf(debugger->backend, "%s\n", ERROR_INVALID_ARGS);
}
} else {
debugger->d.platform->setWatchpoint(debugger->d.platform, address, dv->segmentValue, WATCHPOINT_RW); debugger->d.platform->setWatchpoint(debugger->d.platform, address, dv->segmentValue, WATCHPOINT_RW);
} }
}
static void _setReadWatchpoint(struct CLIDebugger* debugger, struct CLIDebugVector* dv) { static void _setReadWatchpoint(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
if (!dv || dv->type != CLIDV_INT_TYPE) { if (!dv || dv->type != CLIDV_INT_TYPE) {
@ -516,8 +533,17 @@ static void _setReadWatchpoint(struct CLIDebugger* debugger, struct CLIDebugVect
return; return;
} }
uint32_t address = dv->intValue; 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);
} else {
debugger->backend->printf(debugger->backend, "%s\n", ERROR_INVALID_ARGS);
}
} else {
debugger->d.platform->setWatchpoint(debugger->d.platform, address, dv->segmentValue, WATCHPOINT_READ); debugger->d.platform->setWatchpoint(debugger->d.platform, address, dv->segmentValue, WATCHPOINT_READ);
} }
}
static void _setWriteWatchpoint(struct CLIDebugger* debugger, struct CLIDebugVector* dv) { static void _setWriteWatchpoint(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
if (!dv || dv->type != CLIDV_INT_TYPE) { if (!dv || dv->type != CLIDV_INT_TYPE) {
@ -529,8 +555,16 @@ static void _setWriteWatchpoint(struct CLIDebugger* debugger, struct CLIDebugVec
return; return;
} }
uint32_t address = dv->intValue; uint32_t address = dv->intValue;
debugger->d.platform->setWatchpoint(debugger->d.platform, address, dv->segmentValue, WATCHPOINT_WRITE); 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);
} else {
debugger->backend->printf(debugger->backend, "%s\n", ERROR_INVALID_ARGS);
} }
} else {
debugger->d.platform->setWatchpoint(debugger->d.platform, address, dv->segmentValue, WATCHPOINT_WRITE);
}}
static void _clearBreakpoint(struct CLIDebugger* debugger, struct CLIDebugVector* dv) { static void _clearBreakpoint(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
if (!dv || dv->type != CLIDV_INT_TYPE) { if (!dv || dv->type != CLIDV_INT_TYPE) {

View File

@ -31,6 +31,13 @@ static void _destroyBreakpoint(struct LR35902DebugBreakpoint* breakpoint) {
} }
} }
static void _destroyWatchpoint(struct LR35902DebugWatchpoint* watchpoint) {
if (watchpoint->condition) {
parseFree(watchpoint->condition);
free(watchpoint->condition);
}
}
static void LR35902DebuggerCheckBreakpoints(struct mDebuggerPlatform* d) { static void LR35902DebuggerCheckBreakpoints(struct mDebuggerPlatform* d) {
struct LR35902Debugger* debugger = (struct LR35902Debugger*) d; struct LR35902Debugger* debugger = (struct LR35902Debugger*) d;
struct LR35902DebugBreakpoint* breakpoint = _lookupBreakpoint(&debugger->breakpoints, debugger->cpu->pc); struct LR35902DebugBreakpoint* breakpoint = _lookupBreakpoint(&debugger->breakpoints, debugger->cpu->pc);
@ -62,6 +69,7 @@ static void LR35902DebuggerSetBreakpoint(struct mDebuggerPlatform*, uint32_t add
static void LR35902DebuggerSetConditionalBreakpoint(struct mDebuggerPlatform*, uint32_t address, int segment, struct ParseTree* condition); 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 LR35902DebuggerClearBreakpoint(struct mDebuggerPlatform*, uint32_t address, int segment);
static void LR35902DebuggerSetWatchpoint(struct mDebuggerPlatform*, uint32_t address, int segment, enum mWatchpointType type); 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 void LR35902DebuggerClearWatchpoint(struct mDebuggerPlatform*, uint32_t address, int segment);
static void LR35902DebuggerCheckBreakpoints(struct mDebuggerPlatform*); static void LR35902DebuggerCheckBreakpoints(struct mDebuggerPlatform*);
static bool LR35902DebuggerHasBreakpoints(struct mDebuggerPlatform*); static bool LR35902DebuggerHasBreakpoints(struct mDebuggerPlatform*);
@ -78,6 +86,7 @@ struct mDebuggerPlatform* LR35902DebuggerPlatformCreate(void) {
platform->setConditionalBreakpoint = LR35902DebuggerSetConditionalBreakpoint; platform->setConditionalBreakpoint = LR35902DebuggerSetConditionalBreakpoint;
platform->clearBreakpoint = LR35902DebuggerClearBreakpoint; platform->clearBreakpoint = LR35902DebuggerClearBreakpoint;
platform->setWatchpoint = LR35902DebuggerSetWatchpoint; platform->setWatchpoint = LR35902DebuggerSetWatchpoint;
platform->setConditionalWatchpoint = LR35902DebuggerSetConditionalWatchpoint;
platform->clearWatchpoint = LR35902DebuggerClearWatchpoint; platform->clearWatchpoint = LR35902DebuggerClearWatchpoint;
platform->checkBreakpoints = LR35902DebuggerCheckBreakpoints; platform->checkBreakpoints = LR35902DebuggerCheckBreakpoints;
platform->hasBreakpoints = LR35902DebuggerHasBreakpoints; platform->hasBreakpoints = LR35902DebuggerHasBreakpoints;
@ -101,6 +110,10 @@ void LR35902DebuggerDeinit(struct mDebuggerPlatform* platform) {
_destroyBreakpoint(LR35902DebugBreakpointListGetPointer(&debugger->breakpoints, i)); _destroyBreakpoint(LR35902DebugBreakpointListGetPointer(&debugger->breakpoints, i));
} }
LR35902DebugBreakpointListDeinit(&debugger->breakpoints); LR35902DebugBreakpointListDeinit(&debugger->breakpoints);
for (i = 0; i < LR35902DebugWatchpointListSize(&debugger->watchpoints); ++i) {
_destroyWatchpoint(LR35902DebugWatchpointListGetPointer(&debugger->watchpoints, i));
}
LR35902DebugWatchpointListDeinit(&debugger->watchpoints); LR35902DebugWatchpointListDeinit(&debugger->watchpoints);
} }
@ -117,11 +130,7 @@ static void LR35902DebuggerEnter(struct mDebuggerPlatform* platform, enum mDebug
} }
static void LR35902DebuggerSetBreakpoint(struct mDebuggerPlatform* d, uint32_t address, int segment) { static void LR35902DebuggerSetBreakpoint(struct mDebuggerPlatform* d, uint32_t address, int segment) {
struct LR35902Debugger* debugger = (struct LR35902Debugger*) d; LR35902DebuggerSetConditionalBreakpoint(d, address, segment, NULL);
struct LR35902DebugBreakpoint* breakpoint = LR35902DebugBreakpointListAppend(&debugger->breakpoints);
breakpoint->address = address;
breakpoint->segment = segment;
breakpoint->condition = NULL;
} }
static void LR35902DebuggerSetConditionalBreakpoint(struct mDebuggerPlatform* d, uint32_t address, int segment, struct ParseTree* condition) { static void LR35902DebuggerSetConditionalBreakpoint(struct mDebuggerPlatform* d, uint32_t address, int segment, struct ParseTree* condition) {
@ -151,6 +160,10 @@ static bool LR35902DebuggerHasBreakpoints(struct mDebuggerPlatform* d) {
} }
static void LR35902DebuggerSetWatchpoint(struct mDebuggerPlatform* d, uint32_t address, int segment, enum mWatchpointType type) { static void LR35902DebuggerSetWatchpoint(struct mDebuggerPlatform* d, uint32_t address, int segment, enum mWatchpointType type) {
LR35902DebuggerSetConditionalWatchpoint(d, address, segment, type, NULL);
}
static void LR35902DebuggerSetConditionalWatchpoint(struct mDebuggerPlatform* d, uint32_t address, int segment, enum mWatchpointType type, struct ParseTree* condition) {
struct LR35902Debugger* debugger = (struct LR35902Debugger*) d; struct LR35902Debugger* debugger = (struct LR35902Debugger*) d;
if (!LR35902DebugWatchpointListSize(&debugger->watchpoints)) { if (!LR35902DebugWatchpointListSize(&debugger->watchpoints)) {
LR35902DebuggerInstallMemoryShim(debugger); LR35902DebuggerInstallMemoryShim(debugger);
@ -159,6 +172,7 @@ static void LR35902DebuggerSetWatchpoint(struct mDebuggerPlatform* d, uint32_t a
watchpoint->address = address; watchpoint->address = address;
watchpoint->type = type; watchpoint->type = type;
watchpoint->segment = segment; watchpoint->segment = segment;
watchpoint->condition = condition;
} }
static void LR35902DebuggerClearWatchpoint(struct mDebuggerPlatform* d, uint32_t address, int segment) { static void LR35902DebuggerClearWatchpoint(struct mDebuggerPlatform* d, uint32_t address, int segment) {

View File

@ -5,6 +5,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include <mgba/internal/lr35902/debugger/memory-debugger.h> #include <mgba/internal/lr35902/debugger/memory-debugger.h>
#include <mgba/internal/debugger/parser.h>
#include <mgba/internal/lr35902/debugger/debugger.h> #include <mgba/internal/lr35902/debugger/debugger.h>
#include <mgba-util/math.h> #include <mgba-util/math.h>
@ -47,6 +48,13 @@ static bool _checkWatchpoints(struct LR35902Debugger* debugger, uint16_t address
for (i = 0; i < LR35902DebugWatchpointListSize(&debugger->watchpoints); ++i) { for (i = 0; i < LR35902DebugWatchpointListSize(&debugger->watchpoints); ++i) {
watchpoint = LR35902DebugWatchpointListGetPointer(&debugger->watchpoints, i); watchpoint = LR35902DebugWatchpointListGetPointer(&debugger->watchpoints, i);
if (watchpoint->address == address && (watchpoint->segment < 0 || watchpoint->segment == debugger->originalMemory.currentSegment(debugger->cpu, address)) && watchpoint->type & type) { if (watchpoint->address == address && (watchpoint->segment < 0 || watchpoint->segment == debugger->originalMemory.currentSegment(debugger->cpu, address)) && watchpoint->type & type) {
if (watchpoint->condition) {
int32_t value;
int segment;
if (!mDebuggerEvaluateParseTree(debugger->d.p, watchpoint->condition, &value, &segment) || !(value || segment >= 0)) {
return false;
}
}
info->type.wp.oldValue = debugger->originalMemory.load8(debugger->cpu, address); info->type.wp.oldValue = debugger->originalMemory.load8(debugger->cpu, address);
info->type.wp.newValue = newValue; info->type.wp.newValue = newValue;
info->address = address; info->address = address;