mirror of https://github.com/mgba-emu/mgba.git
Debugger: Execution tracing
This commit is contained in:
parent
727fcb94aa
commit
70a6622a5c
1
CHANGES
1
CHANGES
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue