diff --git a/src/core/scripting.c b/src/core/scripting.c index 9e46b619c..012a739bc 100644 --- a/src/core/scripting.c +++ b/src/core/scripting.c @@ -769,7 +769,7 @@ static int64_t _addCallbackToBreakpoint(struct mScriptDebugger* debugger, struct return cbid; } -static void _runCallbacks(struct mScriptDebugger* debugger, struct mScriptBreakpoint* point) { +static void _runCallbacks(struct mScriptDebugger* debugger, struct mScriptBreakpoint* point, struct mScriptValue* info) { struct TableIterator iter; if (!HashTableIteratorStart(&point->callbacks, &iter)) { return; @@ -778,6 +778,7 @@ static void _runCallbacks(struct mScriptDebugger* debugger, struct mScriptBreakp struct mScriptValue* fn = HashTableIteratorGetValue(&point->callbacks, &iter); struct mScriptFrame frame; mScriptFrameInit(&frame); + mSCRIPT_PUSH(&frame.stack, WTABLE, info); mScriptContextInvoke(debugger->p->context, fn, &frame); mScriptFrameDeinit(&frame); } while (HashTableIteratorNext(&point->callbacks, &iter)); @@ -826,7 +827,33 @@ static void _scriptDebuggerEntered(struct mDebuggerModule* debugger, enum mDebug return; } - _runCallbacks(scriptDebugger, point); + struct mScriptValue cbInfo = { + .refs = mSCRIPT_VALUE_UNREF, + .flags = 0, + .type = mSCRIPT_TYPE_MS_TABLE, + }; + cbInfo.type->alloc(&cbInfo); + + // TODO: Intern strings + mScriptTableInsert(&cbInfo, mScriptStringCreateFromASCII("address"), mScriptValueCreateFromUInt(info->address)); + if (info->width > 0) { + mScriptTableInsert(&cbInfo, mScriptStringCreateFromASCII("width"), mScriptValueCreateFromSInt(info->width)); + } + if (info->segment >= 0) { + mScriptTableInsert(&cbInfo, mScriptStringCreateFromASCII("segment"), mScriptValueCreateFromSInt(info->segment)); + } + + if (reason == DEBUGGER_ENTER_WATCHPOINT) { + mScriptTableInsert(&cbInfo, mScriptStringCreateFromASCII("oldValue"), mScriptValueCreateFromSInt(info->type.wp.oldValue)); + if (info->type.wp.accessType != WATCHPOINT_READ) { + mScriptTableInsert(&cbInfo, mScriptStringCreateFromASCII("newValue"), mScriptValueCreateFromSInt(info->type.wp.newValue)); + } + mScriptTableInsert(&cbInfo, mScriptStringCreateFromASCII("accessType"), mScriptValueCreateFromSInt(info->type.wp.accessType)); + } + + _runCallbacks(scriptDebugger, point, &cbInfo); + + cbInfo.type->free(&cbInfo); debugger->isPaused = false; } diff --git a/src/core/test/scripting.c b/src/core/test/scripting.c index 63927effe..16692fc14 100644 --- a/src/core/test/scripting.c +++ b/src/core/test/scripting.c @@ -365,8 +365,10 @@ M_TEST_DEFINE(basicBreakpointGBA) { TEST_PROGRAM( "hit = 0\n" - "function bkpt()\n" + "address = nil\n" + "function bkpt(info)\n" " hit = hit + 1\n" + " address = info.address\n" "end" ); TEST_PROGRAM("cbid = emu:setBreakpoint(bkpt, 0x020000C4)"); @@ -379,6 +381,7 @@ M_TEST_DEFINE(basicBreakpointGBA) { assert_int_equal(debugger.state, DEBUGGER_RUNNING); TEST_PROGRAM("assert(hit >= 1)"); + TEST_PROGRAM("assert(address == 0x020000C4)"); mScriptContextDeinit(&context); TEARDOWN_CORE; @@ -404,8 +407,10 @@ M_TEST_DEFINE(basicBreakpointGB) { TEST_PROGRAM( "hit = 0\n" - "function bkpt()\n" + "address = nil\n" + "function bkpt(info)\n" " hit = hit + 1\n" + " address = info.address\n" "end" ); TEST_PROGRAM("cbid = emu:setBreakpoint(bkpt, 0xF0)"); @@ -418,6 +423,7 @@ M_TEST_DEFINE(basicBreakpointGB) { assert_int_equal(debugger.state, DEBUGGER_RUNNING); TEST_PROGRAM("assert(hit >= 1)"); + TEST_PROGRAM("assert(address == 0xF0)"); mScriptContextDeinit(&context); TEARDOWN_CORE; @@ -441,11 +447,22 @@ M_TEST_DEFINE(multipleBreakpoint) { TEST_PROGRAM( "hit = 0\n" - "function bkpt1()\n" + "address = nil\n" + "function bkpt1(info)\n" " hit = hit + 1\n" + " if address then\n" + " address = (address + info.address) / 2\n" + " else\n" + " address = info.address\n" + " end\n" "end\n" - "function bkpt2()\n" + "function bkpt2(info)\n" " hit = hit + 100\n" + " if address then\n" + " address = (address + info.address) / 2\n" + " else\n" + " address = info.address\n" + " end\n" "end" ); #ifdef M_CORE_GBA @@ -465,6 +482,13 @@ M_TEST_DEFINE(multipleBreakpoint) { assert_int_equal(debugger.state, DEBUGGER_RUNNING); TEST_PROGRAM("assert(hit >= 101)"); +#ifdef M_CORE_GBA + TEST_PROGRAM("assert(address >= 0x020000C4)"); + TEST_PROGRAM("assert(address <= 0x020000C8)"); +#else + TEST_PROGRAM("assert(address >= 0xF0)"); + TEST_PROGRAM("assert(address <= 0xF1)"); +#endif mScriptContextDeinit(&context); TEARDOWN_CORE; @@ -479,13 +503,28 @@ M_TEST_DEFINE(basicWatchpoint) { core->reset(core); mScriptContextAttachCore(&context, core); + int i; + for (i = 0; i < 4; ++i) { + core->busWrite8(core, RAM_BASE + i, i + 1); + } + mDebuggerInit(&debugger); mDebuggerAttach(&debugger, core); TEST_PROGRAM( "hit = 0\n" - "function bkpt()\n" + "address = nil\n" + "width = nil\n" + "oldValue = nil\n" + "newValue = nil\n" + "accessType = nil\n" + "function bkpt(info)\n" " hit = hit + 1\n" + " address = info.address\n" + " width = info.width\n" + " oldValue = info.oldValue\n" + " newValue = info.newValue\n" + " accessType = info.accessType\n" "end" ); struct mScriptValue base = mSCRIPT_MAKE_S32(RAM_BASE); @@ -499,7 +538,13 @@ M_TEST_DEFINE(basicWatchpoint) { uint8_t value; // Read - TEST_PROGRAM("hit = 0"); + TEST_PROGRAM( + "hit = 0\n" + "address = nil\n" + "width = nil\n" + "oldValue = nil\n" + "newValue = nil\n" + "accessType = nil\n"); value = core->rawRead8(core, RAM_BASE, -1); TEST_PROGRAM("assert(hit == 0)"); core->busRead8(core, RAM_BASE); @@ -508,31 +553,71 @@ M_TEST_DEFINE(basicWatchpoint) { TEST_PROGRAM("assert(hit == 1)"); core->busWrite8(core, RAM_BASE, ~value); TEST_PROGRAM("assert(hit == 1)"); + TEST_PROGRAM("assert(address == base)"); + TEST_PROGRAM("assert(width == 1)"); + TEST_PROGRAM("assert(oldValue == 1)"); + TEST_PROGRAM("assert(newValue == nil)"); + TEST_PROGRAM("assert(accessType == C.WATCHPOINT_TYPE.READ)"); // Write - TEST_PROGRAM("hit = 0"); + TEST_PROGRAM( + "hit = 0\n" + "address = nil\n" + "width = nil\n" + "oldValue = nil\n" + "newValue = nil\n" + "accessType = nil\n"); value = core->rawRead8(core, RAM_BASE + 1, -1); TEST_PROGRAM("assert(hit == 0)"); core->busRead8(core, RAM_BASE + 1); TEST_PROGRAM("assert(hit == 0)"); core->busWrite8(core, RAM_BASE + 1, value); TEST_PROGRAM("assert(hit == 1)"); + TEST_PROGRAM("assert(oldValue == 2)"); + TEST_PROGRAM("assert(newValue == 2)"); core->busWrite8(core, RAM_BASE + 1, ~value); TEST_PROGRAM("assert(hit == 2)"); + TEST_PROGRAM("assert(address == base + 1)"); + TEST_PROGRAM("assert(width == 1)"); + TEST_PROGRAM("assert(oldValue == 2)"); + TEST_PROGRAM("assert(newValue == -3)"); + TEST_PROGRAM("assert(accessType == C.WATCHPOINT_TYPE.WRITE)"); // RW - TEST_PROGRAM("hit = 0"); + TEST_PROGRAM( + "hit = 0\n" + "address = nil\n" + "width = nil\n" + "oldValue = nil\n" + "newValue = nil\n" + "accessType = nil\n"); value = core->rawRead8(core, RAM_BASE + 2, -1); TEST_PROGRAM("assert(hit == 0)"); core->busRead8(core, RAM_BASE + 2); + TEST_PROGRAM("assert(accessType == C.WATCHPOINT_TYPE.READ)"); TEST_PROGRAM("assert(hit == 1)"); + TEST_PROGRAM("assert(oldValue == 3)"); + TEST_PROGRAM("assert(newValue == nil)"); core->busWrite8(core, RAM_BASE + 2, value); TEST_PROGRAM("assert(hit == 2)"); + TEST_PROGRAM("assert(oldValue == 3)"); + TEST_PROGRAM("assert(newValue == 3)"); core->busWrite8(core, RAM_BASE + 2, ~value); TEST_PROGRAM("assert(hit == 3)"); + TEST_PROGRAM("assert(address == base + 2)"); + TEST_PROGRAM("assert(width == 1)"); + TEST_PROGRAM("assert(oldValue == 3)"); + TEST_PROGRAM("assert(newValue == -4)"); + TEST_PROGRAM("assert(accessType == C.WATCHPOINT_TYPE.WRITE)"); // Change - TEST_PROGRAM("hit = 0"); + TEST_PROGRAM( + "hit = 0\n" + "address = nil\n" + "width = nil\n" + "oldValue = nil\n" + "newValue = nil\n" + "accessType = nil\n"); value = core->rawRead8(core, RAM_BASE + 3, -1); TEST_PROGRAM("assert(hit == 0)"); core->busRead8(core, RAM_BASE + 3); @@ -541,6 +626,11 @@ M_TEST_DEFINE(basicWatchpoint) { TEST_PROGRAM("assert(hit == 0)"); core->busWrite8(core, RAM_BASE + 3, ~value); TEST_PROGRAM("assert(hit == 1)"); + TEST_PROGRAM("assert(address == base + 3)"); + TEST_PROGRAM("assert(width == 1)"); + TEST_PROGRAM("assert(oldValue == 4)"); + TEST_PROGRAM("assert(newValue == -5)"); + TEST_PROGRAM("assert(accessType == C.WATCHPOINT_TYPE.WRITE)"); mScriptContextDeinit(&context); TEARDOWN_CORE; @@ -728,8 +818,10 @@ M_TEST_DEFINE(rangeWatchpoint) { TEST_PROGRAM( "hit = 0\n" - "function bkpt()\n" + "address = nil\n" + "function bkpt(info)\n" " hit = hit + 1\n" + " address = info.address\n" "end" ); struct mScriptValue base = mSCRIPT_MAKE_S32(RAM_BASE); @@ -741,10 +833,13 @@ M_TEST_DEFINE(rangeWatchpoint) { TEST_PROGRAM("assert(hit == 0)"); core->busRead8(core, RAM_BASE); TEST_PROGRAM("assert(hit == 1)"); + TEST_PROGRAM("assert(address == base)"); core->busRead8(core, RAM_BASE + 1); TEST_PROGRAM("assert(hit == 3)"); + TEST_PROGRAM("assert(address == base + 1)"); core->busRead8(core, RAM_BASE + 2); TEST_PROGRAM("assert(hit == 4)"); + TEST_PROGRAM("assert(address == base + 2)"); mScriptContextDeinit(&context); TEARDOWN_CORE;