Permalink
Browse files

Debugger: Conditional watchpoints

  • Loading branch information...
endrift committed Dec 29, 2017
1 parent 0383c82 commit 0131a196d17494abcabf22dd6d07f6c582b6d806
View
@@ -11,7 +11,7 @@ Features:
- Automatic cheat loading and saving
- GameShark and Action Replay button support
- AGBPrint support
- - Debugger: Conditional breakpoints
+ - Debugger: Conditional breakpoints and watchpoints
Bugfixes:
- GB Audio: Make audio unsigned with bias (fixes mgba.io/i/749)
- GB Serialize: Fix audio state loading
@@ -83,6 +83,7 @@ struct mDebuggerPlatform {
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*);
void (*trace)(struct mDebuggerPlatform*, char* out, size_t* length);
@@ -29,6 +29,7 @@ struct ARMDebugBreakpoint {
struct ARMDebugWatchpoint {
uint32_t address;
enum mWatchpointType type;
+ struct ParseTree* condition;
};
DECLARE_VECTOR(ARMDebugBreakpointList, struct ARMDebugBreakpoint);
@@ -26,6 +26,7 @@ struct LR35902DebugWatchpoint {
uint16_t address;
int segment;
enum mWatchpointType type;
+ struct ParseTree* condition;
};
struct LR35902Segment {
@@ -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) {
struct ARMDebugger* debugger = (struct ARMDebugger*) d;
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 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 void ARMDebuggerCheckBreakpoints(struct mDebuggerPlatform*);
static bool ARMDebuggerHasBreakpoints(struct mDebuggerPlatform*);
@@ -84,6 +92,7 @@ struct mDebuggerPlatform* ARMDebuggerPlatformCreate(void) {
platform->setConditionalBreakpoint = ARMDebuggerSetConditionalBreakpoint;
platform->clearBreakpoint = ARMDebuggerClearBreakpoint;
platform->setWatchpoint = ARMDebuggerSetWatchpoint;
+ platform->setConditionalWatchpoint = ARMDebuggerSetConditionalWatchpoint;
platform->clearWatchpoint = ARMDebuggerClearWatchpoint;
platform->checkBreakpoints = ARMDebuggerCheckBreakpoints;
platform->hasBreakpoints = ARMDebuggerHasBreakpoints;
@@ -119,6 +128,10 @@ void ARMDebuggerDeinit(struct mDebuggerPlatform* platform) {
_destroyBreakpoint(ARMDebugBreakpointListGetPointer(&debugger->breakpoints, i));
}
ARMDebugBreakpointListDeinit(&debugger->breakpoints);
+
+ for (i = 0; i < ARMDebugWatchpointListSize(&debugger->watchpoints); ++i) {
+ _destroyWatchpoint(ARMDebugWatchpointListGetPointer(&debugger->watchpoints, i));
+ }
ARMDebugBreakpointListDeinit(&debugger->swBreakpoints);
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) {
- UNUSED(segment);
- struct ARMDebugger* debugger = (struct ARMDebugger*) d;
- struct ARMDebugBreakpoint* breakpoint = ARMDebugBreakpointListAppend(&debugger->breakpoints);
- breakpoint->condition = NULL;
- breakpoint->address = address;
- breakpoint->isSw = false;
+ ARMDebuggerSetConditionalBreakpoint(d, address, segment, NULL);
}
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) {
+ 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);
struct ARMDebugger* debugger = (struct ARMDebugger*) d;
if (!ARMDebugWatchpointListSize(&debugger->watchpoints)) {
@@ -230,6 +242,7 @@ static void ARMDebuggerSetWatchpoint(struct mDebuggerPlatform* d, uint32_t addre
struct ARMDebugWatchpoint* watchpoint = ARMDebugWatchpointListAppend(&debugger->watchpoints);
watchpoint->address = address;
watchpoint->type = type;
+ watchpoint->condition = condition;
}
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;
for (i = 0; i < ARMDebugWatchpointListSize(watchpoints); ++i) {
if (ARMDebugWatchpointListGetPointer(watchpoints, i)->address == address) {
+ _destroyWatchpoint(ARMDebugWatchpointListGetPointer(watchpoints, i));
ARMDebugWatchpointListShift(watchpoints, i, 1);
}
}
@@ -6,6 +6,7 @@
#include <mgba/internal/arm/debugger/memory-debugger.h>
#include <mgba/internal/arm/debugger/debugger.h>
+#include <mgba/internal/debugger/parser.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) {
watchpoint = ARMDebugWatchpointListGetPointer(&debugger->watchpoints, i);
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) {
case 1:
info->type.wp.oldValue = debugger->originalMemory.load8(debugger->cpu, address, 0);
View
@@ -91,14 +91,14 @@ static struct CLIDebuggerCommandSummary _debuggerCommands[] = {
{ "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, "I", "Set a watchpoint" },
+ { "w", _setWatchpoint, "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, "I", "Set a watchpoint" },
- { "watch/r", _setReadWatchpoint, "I", "Set a read watchpoint" },
- { "watch/w", _setWriteWatchpoint, "I", "Set a write watchpoint" },
+ { "watch", _setWatchpoint, "Is", "Set a 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" },
{ "x/2", _dumpHalfword, "Ii", "Examine halfwords at a specified offset" },
{ "x/4", _dumpWord, "Ii", "Examine words at a specified offset" },
@@ -452,41 +452,49 @@ static void _source(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
}
#endif
+static struct ParseTree* _parseTree(const char* string) {
+ struct LexVector lv;
+ bool error = false;
+ LexVectorInit(&lv, 0);
+ size_t length = strlen(string);
+ size_t adjusted = lexExpression(&lv, string, length, NULL);
+ struct ParseTree* tree = malloc(sizeof(*tree));
+ if (!adjusted) {
+ error = true;
+ } else {
+ parseLexedExpression(tree, &lv);
+
+ if (adjusted > length) {
+ error = true;
+ } else {
+ length -= adjusted;
+ string += adjusted;
+ }
+ }
+ lexFree(&lv);
+ LexVectorClear(&lv);
+ LexVectorDeinit(&lv);
+ if (error) {
+ parseFree(tree);
+ free(tree);
+ return NULL;
+ } 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 LexVector lv;
- bool error = false;
- LexVectorInit(&lv, 0);
- const char* string = dv->next->charValue;
- size_t length = strlen(dv->next->charValue);
- size_t adjusted = lexExpression(&lv, string, length, NULL);
- struct ParseTree* tree = malloc(sizeof(*tree));
- if (!adjusted) {
- error = true;
+ struct ParseTree* tree = _parseTree(dv->next->charValue);
+ if (tree) {
+ debugger->d.platform->setConditionalBreakpoint(debugger->d.platform, address, dv->segmentValue, tree);
} else {
- parseLexedExpression(tree, &lv);
-
- if (adjusted > length) {
- error = true;
- } else {
- length -= adjusted;
- string += adjusted;
- }
- }
- lexFree(&lv);
- LexVectorClear(&lv);
- LexVectorDeinit(&lv);
- if (error) {
- parseFree(tree);
- free(tree);
debugger->backend->printf(debugger->backend, "%s\n", ERROR_INVALID_ARGS);
- } else {
- debugger->d.platform->setConditionalBreakpoint(debugger->d.platform, address, dv->segmentValue, tree);
}
} else {
debugger->d.platform->setBreakpoint(debugger->d.platform, address, dv->segmentValue);
@@ -503,7 +511,16 @@ static void _setWatchpoint(struct CLIDebugger* debugger, struct CLIDebugVector*
return;
}
uint32_t address = dv->intValue;
- debugger->d.platform->setWatchpoint(debugger->d.platform, address, dv->segmentValue, WATCHPOINT_RW);
+ 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);
+ }
}
static void _setReadWatchpoint(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
@@ -516,7 +533,16 @@ static void _setReadWatchpoint(struct CLIDebugger* debugger, struct CLIDebugVect
return;
}
uint32_t address = dv->intValue;
- debugger->d.platform->setWatchpoint(debugger->d.platform, address, dv->segmentValue, WATCHPOINT_READ);
+ 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);
+ }
}
static void _setWriteWatchpoint(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
@@ -529,8 +555,16 @@ static void _setWriteWatchpoint(struct CLIDebugger* debugger, struct CLIDebugVec
return;
}
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) {
if (!dv || dv->type != CLIDV_INT_TYPE) {
@@ -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) {
struct LR35902Debugger* debugger = (struct LR35902Debugger*) d;
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 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 void LR35902DebuggerCheckBreakpoints(struct mDebuggerPlatform*);
static bool LR35902DebuggerHasBreakpoints(struct mDebuggerPlatform*);
@@ -78,6 +86,7 @@ struct mDebuggerPlatform* LR35902DebuggerPlatformCreate(void) {
platform->setConditionalBreakpoint = LR35902DebuggerSetConditionalBreakpoint;
platform->clearBreakpoint = LR35902DebuggerClearBreakpoint;
platform->setWatchpoint = LR35902DebuggerSetWatchpoint;
+ platform->setConditionalWatchpoint = LR35902DebuggerSetConditionalWatchpoint;
platform->clearWatchpoint = LR35902DebuggerClearWatchpoint;
platform->checkBreakpoints = LR35902DebuggerCheckBreakpoints;
platform->hasBreakpoints = LR35902DebuggerHasBreakpoints;
@@ -101,6 +110,10 @@ void LR35902DebuggerDeinit(struct mDebuggerPlatform* platform) {
_destroyBreakpoint(LR35902DebugBreakpointListGetPointer(&debugger->breakpoints, i));
}
LR35902DebugBreakpointListDeinit(&debugger->breakpoints);
+
+ for (i = 0; i < LR35902DebugWatchpointListSize(&debugger->watchpoints); ++i) {
+ _destroyWatchpoint(LR35902DebugWatchpointListGetPointer(&debugger->watchpoints, i));
+ }
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) {
- struct LR35902Debugger* debugger = (struct LR35902Debugger*) d;
- struct LR35902DebugBreakpoint* breakpoint = LR35902DebugBreakpointListAppend(&debugger->breakpoints);
- breakpoint->address = address;
- breakpoint->segment = segment;
- breakpoint->condition = NULL;
+ LR35902DebuggerSetConditionalBreakpoint(d, address, segment, NULL);
}
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) {
+ 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;
if (!LR35902DebugWatchpointListSize(&debugger->watchpoints)) {
LR35902DebuggerInstallMemoryShim(debugger);
@@ -159,6 +172,7 @@ static void LR35902DebuggerSetWatchpoint(struct mDebuggerPlatform* d, uint32_t a
watchpoint->address = address;
watchpoint->type = type;
watchpoint->segment = segment;
+ watchpoint->condition = condition;
}
static void LR35902DebuggerClearWatchpoint(struct mDebuggerPlatform* d, uint32_t address, int segment) {
@@ -5,6 +5,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include <mgba/internal/lr35902/debugger/memory-debugger.h>
+#include <mgba/internal/debugger/parser.h>
#include <mgba/internal/lr35902/debugger/debugger.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) {
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->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.newValue = newValue;
info->address = address;

0 comments on commit 0131a19

Please sign in to comment.