Debugger: Execution tracing
@@ -92,6 +92,7 @@ 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); void (*checkBreakpoints)(struct mDebuggerPlatform*); + void (*trace)(struct mDebuggerPlatform*, char* out, size_t* length); }; struct mDebuggerSymbols;
@@ -7,6 +7,7 @@ #include <mgba/internal/arm/debugger/debugger.h>
#include <mgba/core/core.h> #include <mgba/internal/arm/arm.h> +#include <mgba/internal/arm/decoder.h> #include <mgba/internal/arm/isa-inlines.h> #include <mgba/internal/arm/debugger/memory-debugger.h>@@ -54,6 +55,7 @@ static void ARMDebuggerSetWatchpoint(struct mDebuggerPlatform*, uint32_t address, int segment, enum mWatchpointType type);
static void ARMDebuggerClearWatchpoint(struct mDebuggerPlatform*, uint32_t address, int segment); static void ARMDebuggerCheckBreakpoints(struct mDebuggerPlatform*); static bool ARMDebuggerHasBreakpoints(struct mDebuggerPlatform*); +static void ARMDebuggerTrace(struct mDebuggerPlatform*, char* out, size_t* length); struct mDebuggerPlatform* ARMDebuggerPlatformCreate(void) { struct mDebuggerPlatform* platform = (struct mDebuggerPlatform*) malloc(sizeof(struct ARMDebugger));@@ -66,6 +68,7 @@ platform->setWatchpoint = ARMDebuggerSetWatchpoint;
platform->clearWatchpoint = ARMDebuggerClearWatchpoint; platform->checkBreakpoints = ARMDebuggerCheckBreakpoints; platform->hasBreakpoints = ARMDebuggerHasBreakpoints; + platform->trace = ARMDebuggerTrace; return platform; }@@ -207,3 +210,39 @@ if (!ARMDebugWatchpointListSize(&debugger->watchpoints)) {
ARMDebuggerRemoveMemoryShim(debugger); } } + +static void ARMDebuggerTrace(struct mDebuggerPlatform* d, char* out, size_t* length) { + struct ARMDebugger* debugger = (struct ARMDebugger*) d; + struct ARMCore* cpu = debugger->cpu; + + char disassembly[64]; + + struct ARMInstructionInfo info; + if (cpu->executionMode == MODE_ARM) { + uint32_t instruction = cpu->prefetch[0]; + sprintf(disassembly, "%08X: ", instruction); + ARMDecodeARM(instruction, &info); + ARMDisassemble(&info, cpu->gprs[ARM_PC], disassembly + strlen("00000000: "), sizeof(disassembly) - strlen("00000000: ")); + } else { + struct ARMInstructionInfo info2; + struct ARMInstructionInfo combined; + uint16_t instruction = cpu->prefetch[0]; + uint16_t instruction2 = cpu->prefetch[1]; + ARMDecodeThumb(instruction, &info); + ARMDecodeThumb(instruction2, &info2); + if (ARMDecodeThumbCombine(&info, &info2, &combined)) { + sprintf(disassembly, "%04X%04X: ", instruction, instruction2); + ARMDisassemble(&combined, cpu->gprs[ARM_PC], disassembly + strlen("00000000: "), sizeof(disassembly) - strlen("00000000: ")); + } else { + sprintf(disassembly, " %04X: ", instruction); + ARMDisassemble(&info, cpu->gprs[ARM_PC], disassembly + strlen("00000000: "), sizeof(disassembly) - strlen("00000000: ")); + } + } + + *length = snprintf(out, *length, "%08X %08X %08X %08X %08X %08X %08X %08X %08X %08X %08X %08X %08X %08X %08X %08X cpsr: %08X | %s", + cpu->gprs[0], cpu->gprs[1], cpu->gprs[2], cpu->gprs[3], + cpu->gprs[4], cpu->gprs[5], cpu->gprs[6], cpu->gprs[7], + cpu->gprs[8], cpu->gprs[9], cpu->gprs[10], cpu->gprs[11], + cpu->gprs[12], cpu->gprs[13], cpu->gprs[14], cpu->gprs[15], + cpu->cpsr.packed, disassembly); +}
@@ -44,6 +44,7 @@ static void _clearBreakpoint(struct CLIDebugger*, struct CLIDebugVector*);
static void _setWatchpoint(struct CLIDebugger*, struct CLIDebugVector*); static void _setReadWatchpoint(struct CLIDebugger*, struct CLIDebugVector*); static void _setWriteWatchpoint(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*); static void _writeWord(struct CLIDebugger*, struct CLIDebugVector*);@@ -80,6 +81,7 @@ { "r/1", _readByte, CLIDVParse, "Read a byte from a specified offset" },
{ "r/2", _readHalfword, CLIDVParse, "Read a halfword from a specified offset" }, { "r/4", _readWord, CLIDVParse, "Read a word from a specified offset" }, { "status", _printStatus, 0, "Print the current status" }, + { "trace", _trace, CLIDVParse, "Trace a fixed number of instructions" }, { "w", _setWatchpoint, CLIDVParse, "Set a watchpoint" }, { "w/1", _writeByte, CLIDVParse, "Write a byte at a specified offset" }, { "w/2", _writeHalfword, CLIDVParse, "Write a halfword at a specified offset" },@@ -466,6 +468,27 @@ 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); + } +} + +static void _trace(struct CLIDebugger* debugger, struct CLIDebugVector* dv) { + if (!dv || dv->type != CLIDV_INT_TYPE) { + debugger->backend->printf(debugger->backend, "%s\n", ERROR_MISSING_ARGS); + return; + } + + char trace[1024]; + trace[sizeof(trace) - 1] = '\0'; + + int i; + for (i = 0; i < dv->intValue; ++i) { + debugger->d.core->step(debugger->d.core); + size_t traceSize = sizeof(trace) - 1; + debugger->d.platform->trace(debugger->d.platform, trace, &traceSize); + if (traceSize + 1 < sizeof(trace)) { + trace[traceSize + 1] = '\0'; + } + debugger->backend->printf(debugger->backend, "%s\n", trace); } }
@@ -6,6 +6,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include <mgba/internal/lr35902/debugger/debugger.h> #include <mgba/core/core.h> +#include <mgba/internal/lr35902/decoder.h> #include <mgba/internal/lr35902/lr35902.h> #include <mgba/internal/lr35902/debugger/memory-debugger.h>@@ -48,6 +49,7 @@ static void LR35902DebuggerSetWatchpoint(struct mDebuggerPlatform*, uint32_t address, int segment, enum mWatchpointType type);
static void LR35902DebuggerClearWatchpoint(struct mDebuggerPlatform*, uint32_t address, int segment); static void LR35902DebuggerCheckBreakpoints(struct mDebuggerPlatform*); static bool LR35902DebuggerHasBreakpoints(struct mDebuggerPlatform*); +static void LR35902DebuggerTrace(struct mDebuggerPlatform*, char* out, size_t* length); struct mDebuggerPlatform* LR35902DebuggerPlatformCreate(void) { struct mDebuggerPlatform* platform = (struct mDebuggerPlatform*) malloc(sizeof(struct LR35902Debugger));@@ -60,6 +62,7 @@ platform->setWatchpoint = LR35902DebuggerSetWatchpoint;
platform->clearWatchpoint = LR35902DebuggerClearWatchpoint; platform->checkBreakpoints = LR35902DebuggerCheckBreakpoints; platform->hasBreakpoints = LR35902DebuggerHasBreakpoints; + platform->trace = LR35902DebuggerTrace; return platform; }@@ -137,3 +140,31 @@ if (!LR35902DebugWatchpointListSize(&debugger->watchpoints)) {
LR35902DebuggerRemoveMemoryShim(debugger); } } + +static void LR35902DebuggerTrace(struct mDebuggerPlatform* d, char* out, size_t* length) { + struct LR35902Debugger* debugger = (struct LR35902Debugger*) d; + struct LR35902Core* cpu = debugger->cpu; + + char disassembly[64]; + + struct LR35902InstructionInfo info = {{0}}; + char* disPtr = disassembly; + uint8_t instruction; + uint16_t address = cpu->pc; + size_t bytesRemaining = 1; + for (bytesRemaining = 1; bytesRemaining; --bytesRemaining) { + instruction = debugger->d.p->core->rawRead8(debugger->d.p->core, address, -1); + disPtr += snprintf(disPtr, sizeof(disassembly) - (disPtr - disassembly), "%02X", instruction); + ++address; + bytesRemaining += LR35902Decode(instruction, &info); + }; + disPtr[0] = ':'; + disPtr[1] = ' '; + disPtr += 2; + LR35902Disassemble(&info, disPtr, sizeof(disassembly) - (disPtr - disassembly)); + + *length = snprintf(out, *length, "A: %02X F: %02X B: %02X C: %02X D: %02X E: %02X H: %02X L: %02X SP: %04X PC: %04X | %s", + cpu->a, cpu->f.packed, cpu->b, cpu->c, + cpu->d, cpu->e, cpu->h, cpu->l, + cpu->sp, cpu->pc, disassembly); +}