Debugger: Execution tracing

This commit is contained in:
Vicki Pfau 2017-06-11 09:26:26 -07:00
parent 727fcb94aa
commit 70a6622a5c
5 changed files with 95 additions and 0 deletions

View File

@ -24,6 +24,7 @@ Features:
- GBA: Implement keypad interrupts
- LR35902: Watchpoints
- Memory search
- Debugger: Execution tracing
Bugfixes:
- LR35902: Fix core never exiting with certain event patterns
- GB Timer: Improve DIV reset behavior

View File

@ -92,6 +92,7 @@ struct mDebuggerPlatform {
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;

View File

@ -7,6 +7,7 @@
#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
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 @@ struct mDebuggerPlatform* ARMDebuggerPlatformCreate(void) {
platform->clearWatchpoint = ARMDebuggerClearWatchpoint;
platform->checkBreakpoints = ARMDebuggerCheckBreakpoints;
platform->hasBreakpoints = ARMDebuggerHasBreakpoints;
platform->trace = ARMDebuggerTrace;
return platform;
}
@ -207,3 +210,39 @@ static void ARMDebuggerClearWatchpoint(struct mDebuggerPlatform* d, uint32_t add
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);
}

View File

@ -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 @@ static struct CLIDebuggerCommandSummary _debuggerCommands[] = {
{ "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" },
@ -469,6 +471,27 @@ static void _clearBreakpoint(struct CLIDebugger* debugger, struct CLIDebugVector
}
}
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);
}
}
static void _printStatus(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
UNUSED(dv);
debugger->system->printStatus(debugger->system);

View File

@ -6,6 +6,7 @@
#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 add
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 @@ struct mDebuggerPlatform* LR35902DebuggerPlatformCreate(void) {
platform->clearWatchpoint = LR35902DebuggerClearWatchpoint;
platform->checkBreakpoints = LR35902DebuggerCheckBreakpoints;
platform->hasBreakpoints = LR35902DebuggerHasBreakpoints;
platform->trace = LR35902DebuggerTrace;
return platform;
}
@ -137,3 +140,31 @@ static void LR35902DebuggerClearWatchpoint(struct mDebuggerPlatform* d, uint32_t
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);
}