diff --git a/CHANGES b/CHANGES index 47adeff9a..5e4ff85a2 100644 --- a/CHANGES +++ b/CHANGES @@ -11,6 +11,7 @@ Features: - Automatic cheat loading and saving - GameShark and Action Replay button support - AGBPrint support + - Debugger: Conditional breakpoints Bugfixes: - GB Audio: Make audio unsigned with bias (fixes mgba.io/i/749) - GB Serialize: Fix audio state loading diff --git a/include/mgba/debugger/debugger.h b/include/mgba/debugger/debugger.h index f2a030827..a8e808b32 100644 --- a/include/mgba/debugger/debugger.h +++ b/include/mgba/debugger/debugger.h @@ -70,6 +70,7 @@ struct mDebuggerEntryInfo { }; struct mDebugger; +struct ParseTree; struct mDebuggerPlatform { struct mDebugger* p; @@ -79,6 +80,7 @@ struct mDebuggerPlatform { 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 (*clearWatchpoint)(struct mDebuggerPlatform*, uint32_t address, int segment); diff --git a/include/mgba/internal/arm/debugger/debugger.h b/include/mgba/internal/arm/debugger/debugger.h index d35dbed13..0941b0dd5 100644 --- a/include/mgba/internal/arm/debugger/debugger.h +++ b/include/mgba/internal/arm/debugger/debugger.h @@ -15,8 +15,10 @@ CXX_GUARD_START #include #include +struct ParseTree; struct ARMDebugBreakpoint { uint32_t address; + struct ParseTree* condition; bool isSw; struct { uint32_t opcode; diff --git a/include/mgba/internal/debugger/parser.h b/include/mgba/internal/debugger/parser.h index 99c43dc73..6092c1f8c 100644 --- a/include/mgba/internal/debugger/parser.h +++ b/include/mgba/internal/debugger/parser.h @@ -12,6 +12,9 @@ CXX_GUARD_START +struct Token; +DECLARE_VECTOR(LexVector, struct Token); + enum Operation { OP_ASSIGN, OP_ADD, @@ -54,15 +57,13 @@ struct Token { }; }; -DECLARE_VECTOR(LexVector, struct Token); - struct ParseTree { struct Token token; struct ParseTree* lhs; struct ParseTree* rhs; }; -size_t lexExpression(struct LexVector* lv, const char* string, size_t length); +size_t lexExpression(struct LexVector* lv, const char* string, size_t length, const char* eol); void parseLexedExpression(struct ParseTree* tree, struct LexVector* lv); void lexFree(struct LexVector* lv); diff --git a/include/mgba/internal/lr35902/debugger/debugger.h b/include/mgba/internal/lr35902/debugger/debugger.h index 340e13aac..6fb7dd734 100644 --- a/include/mgba/internal/lr35902/debugger/debugger.h +++ b/include/mgba/internal/lr35902/debugger/debugger.h @@ -15,10 +15,11 @@ CXX_GUARD_START #include #include - +struct ParseTree; struct LR35902DebugBreakpoint { uint16_t address; int segment; + struct ParseTree* condition; }; struct LR35902DebugWatchpoint { diff --git a/src/arm/debugger/debugger.c b/src/arm/debugger/debugger.c index 1d646208e..1476f8c8a 100644 --- a/src/arm/debugger/debugger.c +++ b/src/arm/debugger/debugger.c @@ -10,6 +10,7 @@ #include #include #include +#include DEFINE_VECTOR(ARMDebugBreakpointList, struct ARMDebugBreakpoint); DEFINE_VECTOR(ARMDebugWatchpointList, struct ARMDebugWatchpoint); @@ -24,6 +25,13 @@ static struct ARMDebugBreakpoint* _lookupBreakpoint(struct ARMDebugBreakpointLis return 0; } +static void _destroyBreakpoint(struct ARMDebugBreakpoint* breakpoint) { + if (breakpoint->condition) { + parseFree(breakpoint->condition); + free(breakpoint->condition); + } +} + static void ARMDebuggerCheckBreakpoints(struct mDebuggerPlatform* d) { struct ARMDebugger* debugger = (struct ARMDebugger*) d; int instructionLength; @@ -37,6 +45,13 @@ static void ARMDebuggerCheckBreakpoints(struct mDebuggerPlatform* d) { if (!breakpoint) { return; } + if (breakpoint->condition) { + int32_t value; + int segment; + if (!mDebuggerEvaluateParseTree(d->p, breakpoint->condition, &value, &segment) || !(value || segment >= 0)) { + return; + } + } struct mDebuggerEntryInfo info = { .address = breakpoint->address, .type.bp.breakType = BREAKPOINT_HARDWARE @@ -50,6 +65,7 @@ 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 ARMDebuggerClearWatchpoint(struct mDebuggerPlatform*, uint32_t address, int segment); @@ -65,6 +81,7 @@ struct mDebuggerPlatform* ARMDebuggerPlatformCreate(void) { platform->init = ARMDebuggerInit; platform->deinit = ARMDebuggerDeinit; platform->setBreakpoint = ARMDebuggerSetBreakpoint; + platform->setConditionalBreakpoint = ARMDebuggerSetConditionalBreakpoint; platform->clearBreakpoint = ARMDebuggerClearBreakpoint; platform->setWatchpoint = ARMDebuggerSetWatchpoint; platform->clearWatchpoint = ARMDebuggerClearWatchpoint; @@ -97,6 +114,10 @@ void ARMDebuggerDeinit(struct mDebuggerPlatform* platform) { } ARMDebuggerRemoveMemoryShim(debugger); + size_t i; + for (i = 0; i < ARMDebugBreakpointListSize(&debugger->breakpoints); ++i) { + _destroyBreakpoint(ARMDebugBreakpointListGetPointer(&debugger->breakpoints, i)); + } ARMDebugBreakpointListDeinit(&debugger->breakpoints); ARMDebugBreakpointListDeinit(&debugger->swBreakpoints); ARMDebugWatchpointListDeinit(&debugger->watchpoints); @@ -168,6 +189,16 @@ static void ARMDebuggerSetBreakpoint(struct mDebuggerPlatform* d, uint32_t addre UNUSED(segment); 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) { + UNUSED(segment); + struct ARMDebugger* debugger = (struct ARMDebugger*) d; + struct ARMDebugBreakpoint* breakpoint = ARMDebugBreakpointListAppend(&debugger->breakpoints); + breakpoint->condition = condition; breakpoint->address = address; breakpoint->isSw = false; } @@ -179,6 +210,7 @@ static void ARMDebuggerClearBreakpoint(struct mDebuggerPlatform* d, uint32_t add size_t i; for (i = 0; i < ARMDebugBreakpointListSize(breakpoints); ++i) { if (ARMDebugBreakpointListGetPointer(breakpoints, i)->address == address) { + _destroyBreakpoint(ARMDebugBreakpointListGetPointer(breakpoints, i)); ARMDebugBreakpointListShift(breakpoints, i, 1); } } diff --git a/src/debugger/cli-debugger.c b/src/debugger/cli-debugger.c index c439a9427..bf975d2aa 100644 --- a/src/debugger/cli-debugger.c +++ b/src/debugger/cli-debugger.c @@ -62,8 +62,8 @@ static void _source(struct CLIDebugger*, struct CLIDebugVector*); #endif static struct CLIDebuggerCommandSummary _debuggerCommands[] = { - { "b", _setBreakpoint, "I", "Set a breakpoint" }, - { "break", _setBreakpoint, "I", "Set a breakpoint" }, + { "b", _setBreakpoint, "Is", "Set a breakpoint" }, + { "break", _setBreakpoint, "Is", "Set a breakpoint" }, { "c", _continue, "", "Continue execution" }, { "continue", _continue, "", "Continue execution" }, { "d", _clearBreakpoint, "I", "Delete a breakpoint" }, @@ -458,7 +458,39 @@ static void _setBreakpoint(struct CLIDebugger* debugger, struct CLIDebugVector* return; } uint32_t address = dv->intValue; - debugger->d.platform->setBreakpoint(debugger->d.platform, address, dv->segmentValue); + 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; + } 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); + } } static void _setWatchpoint(struct CLIDebugger* debugger, struct CLIDebugVector* dv) { @@ -547,7 +579,7 @@ struct CLIDebugVector* CLIDVParse(struct CLIDebugger* debugger, const char* stri struct LexVector lv; LexVectorInit(&lv, 0); - size_t adjusted = lexExpression(&lv, string, length); + size_t adjusted = lexExpression(&lv, string, length, " "); if (adjusted > length) { dvTemp.type = CLIDV_ERROR_TYPE; } @@ -562,8 +594,7 @@ struct CLIDebugVector* CLIDVParse(struct CLIDebugger* debugger, const char* stri } } - parseFree(tree.lhs); - parseFree(tree.rhs); + parseFree(&tree); lexFree(&lv); LexVectorDeinit(&lv); diff --git a/src/debugger/parser.c b/src/debugger/parser.c index 7cc778208..41eafc6d4 100644 --- a/src/debugger/parser.c +++ b/src/debugger/parser.c @@ -166,13 +166,20 @@ static void _lexValue(struct LexVector* lv, char token, uint32_t next, enum LexS lvNext->type = TOKEN_CLOSE_PAREN_TYPE; *state = LEX_EXPECT_OPERATOR; break; + case ' ': + case '\t': + lvNext = LexVectorAppend(lv); + lvNext->type = TOKEN_UINT_TYPE; + lvNext->uintValue = next; + *state = LEX_EXPECT_OPERATOR; + break; default: *state = LEX_ERROR; break; } } -size_t lexExpression(struct LexVector* lv, const char* string, size_t length) { +size_t lexExpression(struct LexVector* lv, const char* string, size_t length, const char* eol) { if (!string || length < 1) { return 0; } @@ -184,7 +191,11 @@ size_t lexExpression(struct LexVector* lv, const char* string, size_t length) { const char* tokenStart = 0; struct Token* lvNext; - while (length > 0 && string[0] && string[0] != ' ' && state != LEX_ERROR) { + if (!eol) { + eol = " \r\n"; + } + + while (length > 0 && string[0] && !strchr(eol, string[0]) && state != LEX_ERROR) { char token = string[0]; ++string; ++adjusted; @@ -236,6 +247,9 @@ size_t lexExpression(struct LexVector* lv, const char* string, size_t length) { lvNext = LexVectorAppend(lv); lvNext->type = TOKEN_OPEN_PAREN_TYPE; break; + case ' ': + case '\t': + break; default: if (tolower(token) >= 'a' && tolower(token <= 'z')) { state = LEX_EXPECT_IDENTIFIER; @@ -272,6 +286,13 @@ size_t lexExpression(struct LexVector* lv, const char* string, size_t length) { lvNext->type = TOKEN_CLOSE_PAREN_TYPE; state = LEX_EXPECT_OPERATOR; break; + case ' ': + case '\t': + lvNext = LexVectorAppend(lv); + lvNext->type = TOKEN_IDENTIFIER_TYPE; + lvNext->identifierValue = strndup(tokenStart, string - tokenStart - 1); + state = LEX_EXPECT_OPERATOR; + break; default: break; } @@ -412,7 +433,9 @@ size_t lexExpression(struct LexVector* lv, const char* string, size_t length) { case ')': lvNext = LexVectorAppend(lv); lvNext->type = TOKEN_CLOSE_PAREN_TYPE; - state = LEX_EXPECT_OPERATOR; + break; + case ' ': + case '\t': break; default: state = LEX_ERROR; @@ -585,13 +608,18 @@ void parseFree(struct ParseTree* tree) { return; } - parseFree(tree->lhs); - parseFree(tree->rhs); + if (tree->lhs) { + parseFree(tree->lhs); + free(tree->lhs); + } + if (tree->rhs) { + parseFree(tree->rhs); + free(tree->rhs); + } if (tree->token.type == TOKEN_IDENTIFIER_TYPE) { free(tree->token.identifierValue); } - free(tree); } static bool _performOperation(enum Operation operation, int32_t current, int32_t next, int32_t* value) { diff --git a/src/debugger/test/lexer.c b/src/debugger/test/lexer.c index e9e5ac2d2..89e1024df 100644 --- a/src/debugger/test/lexer.c +++ b/src/debugger/test/lexer.c @@ -11,7 +11,7 @@ struct LexVector* lv = *state; \ lexFree(lv); \ LexVectorClear(lv); \ - size_t adjusted = lexExpression(lv, STR, strlen(STR)); \ + size_t adjusted = lexExpression(lv, STR, strlen(STR), ""); \ assert_false(adjusted > strlen(STR)) M_TEST_SUITE_SETUP(Lexer) { @@ -715,6 +715,68 @@ M_TEST_DEFINE(lexNestedParentheticalExpression) { assert_int_equal(LexVectorGetPointer(lv, 8)->type, TOKEN_CLOSE_PAREN_TYPE); } +M_TEST_DEFINE(lexSpaceSimple) { + LEX(" 1 "); + + assert_int_equal(LexVectorSize(lv), 1); + assert_int_equal(LexVectorGetPointer(lv, 0)->type, TOKEN_UINT_TYPE); + assert_int_equal(LexVectorGetPointer(lv, 0)->uintValue, 1); +} + +M_TEST_DEFINE(lexSpaceIdentifier) { + LEX(" x "); + + assert_int_equal(LexVectorSize(lv), 1); + assert_int_equal(LexVectorGetPointer(lv, 0)->type, TOKEN_IDENTIFIER_TYPE); + assert_string_equal(LexVectorGetPointer(lv, 0)->identifierValue, "x"); +} + +M_TEST_DEFINE(lexSpaceOperator) { + LEX("1 + 2"); + + assert_int_equal(LexVectorSize(lv), 3); + assert_int_equal(LexVectorGetPointer(lv, 0)->type, TOKEN_UINT_TYPE); + assert_int_equal(LexVectorGetPointer(lv, 0)->uintValue, 1); + assert_int_equal(LexVectorGetPointer(lv, 1)->type, TOKEN_OPERATOR_TYPE); + assert_int_equal(LexVectorGetPointer(lv, 1)->operatorValue, OP_ADD); + assert_int_equal(LexVectorGetPointer(lv, 2)->type, TOKEN_UINT_TYPE); + assert_int_equal(LexVectorGetPointer(lv, 2)->uintValue, 2); +} + +M_TEST_DEFINE(lexSpaceParen) { + LEX(" ( 1 + 2 ) "); + + assert_int_equal(LexVectorSize(lv), 5); + assert_int_equal(LexVectorGetPointer(lv, 0)->type, TOKEN_OPEN_PAREN_TYPE); + assert_int_equal(LexVectorGetPointer(lv, 1)->type, TOKEN_UINT_TYPE); + assert_int_equal(LexVectorGetPointer(lv, 1)->uintValue, 1); + assert_int_equal(LexVectorGetPointer(lv, 2)->type, TOKEN_OPERATOR_TYPE); + assert_int_equal(LexVectorGetPointer(lv, 2)->operatorValue, OP_ADD); + assert_int_equal(LexVectorGetPointer(lv, 3)->type, TOKEN_UINT_TYPE); + assert_int_equal(LexVectorGetPointer(lv, 3)->uintValue, 2); + assert_int_equal(LexVectorGetPointer(lv, 4)->type, TOKEN_CLOSE_PAREN_TYPE); +} + +M_TEST_DEFINE(lexSpaceParens) { + LEX(" ( 1 + ( 2 + 3 ) ) "); + + assert_int_equal(LexVectorSize(lv), 9); + assert_int_equal(LexVectorGetPointer(lv, 0)->type, TOKEN_OPEN_PAREN_TYPE); + assert_int_equal(LexVectorGetPointer(lv, 1)->type, TOKEN_UINT_TYPE); + assert_int_equal(LexVectorGetPointer(lv, 1)->uintValue, 1); + assert_int_equal(LexVectorGetPointer(lv, 2)->type, TOKEN_OPERATOR_TYPE); + assert_int_equal(LexVectorGetPointer(lv, 2)->operatorValue, OP_ADD); + assert_int_equal(LexVectorGetPointer(lv, 3)->type, TOKEN_OPEN_PAREN_TYPE); + assert_int_equal(LexVectorGetPointer(lv, 4)->type, TOKEN_UINT_TYPE); + assert_int_equal(LexVectorGetPointer(lv, 4)->uintValue, 2); + assert_int_equal(LexVectorGetPointer(lv, 5)->type, TOKEN_OPERATOR_TYPE); + assert_int_equal(LexVectorGetPointer(lv, 5)->operatorValue, OP_ADD); + assert_int_equal(LexVectorGetPointer(lv, 6)->type, TOKEN_UINT_TYPE); + assert_int_equal(LexVectorGetPointer(lv, 6)->uintValue, 3); + assert_int_equal(LexVectorGetPointer(lv, 7)->type, TOKEN_CLOSE_PAREN_TYPE); + assert_int_equal(LexVectorGetPointer(lv, 8)->type, TOKEN_CLOSE_PAREN_TYPE); +} + M_TEST_SUITE_DEFINE_SETUP_TEARDOWN(Lexer, cmocka_unit_test(lexEmpty), cmocka_unit_test(lexInt), @@ -785,4 +847,9 @@ M_TEST_SUITE_DEFINE_SETUP_TEARDOWN(Lexer, cmocka_unit_test(lexCloseParen), cmocka_unit_test(lexIdentifierCloseParen), cmocka_unit_test(lexParentheticalExpression), - cmocka_unit_test(lexNestedParentheticalExpression)) + cmocka_unit_test(lexNestedParentheticalExpression), + cmocka_unit_test(lexSpaceSimple), + cmocka_unit_test(lexSpaceIdentifier), + cmocka_unit_test(lexSpaceOperator), + cmocka_unit_test(lexSpaceParen), + cmocka_unit_test(lexSpaceParens)) diff --git a/src/debugger/test/parser.c b/src/debugger/test/parser.c index dd566be9f..412fc65c9 100644 --- a/src/debugger/test/parser.c +++ b/src/debugger/test/parser.c @@ -16,7 +16,7 @@ struct LPTest { struct LPTest* lp = *state; \ lexFree(&lp->lv); \ LexVectorClear(&lp->lv); \ - size_t adjusted = lexExpression(&lp->lv, STR, strlen(STR)); \ + size_t adjusted = lexExpression(&lp->lv, STR, strlen(STR), ""); \ assert_false(adjusted > strlen(STR)); \ struct ParseTree* tree = &lp->tree; \ parseLexedExpression(tree, &lp->lv) @@ -30,8 +30,7 @@ M_TEST_SUITE_SETUP(Parser) { M_TEST_SUITE_TEARDOWN(Parser) { struct LPTest* lp = *state; - parseFree(lp->tree.lhs); \ - parseFree(lp->tree.rhs); \ + parseFree(&lp->tree); \ lexFree(&lp->lv); LexVectorDeinit(&lp->lv); free(lp); diff --git a/src/lr35902/debugger/debugger.c b/src/lr35902/debugger/debugger.c index 53ae0ea57..fa2c77620 100644 --- a/src/lr35902/debugger/debugger.c +++ b/src/lr35902/debugger/debugger.c @@ -6,6 +6,7 @@ #include #include +#include #include #include #include @@ -23,6 +24,13 @@ static struct LR35902DebugBreakpoint* _lookupBreakpoint(struct LR35902DebugBreak return 0; } +static void _destroyBreakpoint(struct LR35902DebugBreakpoint* breakpoint) { + if (breakpoint->condition) { + parseFree(breakpoint->condition); + free(breakpoint->condition); + } +} + static void LR35902DebuggerCheckBreakpoints(struct mDebuggerPlatform* d) { struct LR35902Debugger* debugger = (struct LR35902Debugger*) d; struct LR35902DebugBreakpoint* breakpoint = _lookupBreakpoint(&debugger->breakpoints, debugger->cpu->pc); @@ -32,6 +40,13 @@ static void LR35902DebuggerCheckBreakpoints(struct mDebuggerPlatform* d) { if (breakpoint->segment >= 0 && debugger->cpu->memory.currentSegment(debugger->cpu, breakpoint->address) != breakpoint->segment) { return; } + if (breakpoint->condition) { + int32_t value; + int segment; + if (!mDebuggerEvaluateParseTree(d->p, breakpoint->condition, &value, &segment) || !(value || segment >= 0)) { + return; + } + } struct mDebuggerEntryInfo info = { .address = breakpoint->address }; @@ -44,6 +59,7 @@ 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 LR35902DebuggerClearWatchpoint(struct mDebuggerPlatform*, uint32_t address, int segment); @@ -59,6 +75,7 @@ struct mDebuggerPlatform* LR35902DebuggerPlatformCreate(void) { platform->init = LR35902DebuggerInit; platform->deinit = LR35902DebuggerDeinit; platform->setBreakpoint = LR35902DebuggerSetBreakpoint; + platform->setConditionalBreakpoint = LR35902DebuggerSetConditionalBreakpoint; platform->clearBreakpoint = LR35902DebuggerClearBreakpoint; platform->setWatchpoint = LR35902DebuggerSetWatchpoint; platform->clearWatchpoint = LR35902DebuggerClearWatchpoint; @@ -79,6 +96,10 @@ void LR35902DebuggerInit(void* cpu, struct mDebuggerPlatform* platform) { 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)); + } LR35902DebugBreakpointListDeinit(&debugger->breakpoints); LR35902DebugWatchpointListDeinit(&debugger->watchpoints); } @@ -100,6 +121,15 @@ static void LR35902DebuggerSetBreakpoint(struct mDebuggerPlatform* d, uint32_t a 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) { + struct LR35902Debugger* debugger = (struct LR35902Debugger*) d; + struct LR35902DebugBreakpoint* breakpoint = LR35902DebugBreakpointListAppend(&debugger->breakpoints); + breakpoint->address = address; + breakpoint->segment = segment; + breakpoint->condition = condition; } static void LR35902DebuggerClearBreakpoint(struct mDebuggerPlatform* d, uint32_t address, int segment) { @@ -109,6 +139,7 @@ static void LR35902DebuggerClearBreakpoint(struct mDebuggerPlatform* d, uint32_t 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); } }