Added backtrace command to debugger
This commit is contained in:
parent
a5670b6643
commit
806d0775a4
@ -1166,12 +1166,29 @@ static bool mbc(GB_gameboy_t *gb, char *arguments)
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool backtrace(GB_gameboy_t *gb, char *arguments)
|
||||
{
|
||||
if (strlen(lstrip(arguments))) {
|
||||
GB_log(gb, "Usage: backtrace\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
GB_log(gb, " 1. %s\n", value_to_string(gb, gb->pc, true));
|
||||
for (unsigned int i = gb->backtrace_size; i--;) {
|
||||
GB_log(gb, "%3d. %s\n", gb->backtrace_size - i + 1, debugger_value_to_string(gb, (value_t){true, gb->backtrace_returns[i].bank, gb->backtrace_returns[i].addr}, true));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool help(GB_gameboy_t *gb, char *arguments);
|
||||
static const debugger_command_t commands[] = {
|
||||
{"continue", 1, cont, "Continue running until next stop"},
|
||||
{"next", 1, next, "Run the next instruction, skipping over function calls"},
|
||||
{"step", 1, step, "Run the next instruction, stepping into function calls"},
|
||||
{"finish", 1, finish, "Run until the current function returns"},
|
||||
{"backtrace", 2, backtrace, "Display the current call stack"},
|
||||
{"bt", 2, backtrace, NULL},
|
||||
{"sld", 3, stack_leak_detection, "Run until the current function returns, or a stack leak is detected (Experimental)"},
|
||||
{"registers", 1, registers, "Print values of processor registers and other important registers"},
|
||||
{"cartridge", 2, mbc, "Displays information about the MBC and cartridge"},
|
||||
@ -1185,6 +1202,7 @@ static const debugger_command_t commands[] = {
|
||||
{"eval", 2, print, NULL},
|
||||
{"examine", 2, examine, "Examine values at address"},
|
||||
{"x", 1, examine, NULL},
|
||||
|
||||
{"help", 1, help, "List available commands"},
|
||||
};
|
||||
|
||||
@ -1215,7 +1233,7 @@ static const debugger_command_t *find_command(const char *string)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void GB_debugger_call_hook(GB_gameboy_t *gb)
|
||||
void GB_debugger_call_hook(GB_gameboy_t *gb, uint16_t call_addr)
|
||||
{
|
||||
/* Called just after the CPU calls a function/enters an interrupt/etc... */
|
||||
|
||||
@ -1230,6 +1248,23 @@ void GB_debugger_call_hook(GB_gameboy_t *gb)
|
||||
}
|
||||
}
|
||||
|
||||
if (gb->backtrace_size < sizeof(gb->backtrace_sps) / sizeof(gb->backtrace_sps[0])) {
|
||||
|
||||
while (gb->backtrace_size) {
|
||||
if (gb->backtrace_sps[gb->backtrace_size - 1] < gb->registers[GB_REGISTER_SP]) {
|
||||
gb->backtrace_size--;
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
gb->backtrace_sps[gb->backtrace_size] = gb->registers[GB_REGISTER_SP];
|
||||
gb->backtrace_returns[gb->backtrace_size].bank = bank_for_addr(gb, call_addr);
|
||||
gb->backtrace_returns[gb->backtrace_size].addr = call_addr;
|
||||
gb->backtrace_size++;
|
||||
}
|
||||
|
||||
gb->debug_call_depth++;
|
||||
}
|
||||
|
||||
@ -1253,6 +1288,15 @@ void GB_debugger_ret_hook(GB_gameboy_t *gb)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
while (gb->backtrace_size) {
|
||||
if (gb->backtrace_sps[gb->backtrace_size - 1] <= gb->registers[GB_REGISTER_SP]) {
|
||||
gb->backtrace_size--;
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool _GB_debugger_test_write_watchpoint(GB_gameboy_t *gb, value_t addr, uint8_t value)
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
void GB_debugger_run(GB_gameboy_t *gb);
|
||||
void GB_debugger_handle_async_commands(GB_gameboy_t *gb);
|
||||
void GB_debugger_call_hook(GB_gameboy_t *gb);
|
||||
void GB_debugger_call_hook(GB_gameboy_t *gb, uint16_t call_addr);
|
||||
void GB_debugger_ret_hook(GB_gameboy_t *gb);
|
||||
void GB_debugger_test_write_watchpoint(GB_gameboy_t *gb, uint16_t addr, uint8_t value);
|
||||
void GB_debugger_test_read_watchpoint(GB_gameboy_t *gb, uint16_t addr);
|
||||
|
10
Core/gb.h
10
Core/gb.h
@ -385,12 +385,20 @@ typedef struct GB_gameboy_s {
|
||||
uint16_t n_breakpoints;
|
||||
struct GB_breakpoint_s *breakpoints;
|
||||
|
||||
/* SLD */
|
||||
/* SLD (Todo: merge with backtrace) */
|
||||
bool stack_leak_detection;
|
||||
int debug_call_depth;
|
||||
uint16_t sp_for_call_depth[0x200]; /* Should be much more than enough */
|
||||
uint16_t addr_for_call_depth[0x200];
|
||||
|
||||
/* Backtrace */
|
||||
unsigned int backtrace_size;
|
||||
uint16_t backtrace_sps[0x200];
|
||||
struct {
|
||||
uint16_t bank;
|
||||
uint16_t addr;
|
||||
} backtrace_returns[0x200];
|
||||
|
||||
/* Watchpoints */
|
||||
uint16_t n_watchpoints;
|
||||
struct GB_watchpoint_s *watchpoints;
|
||||
|
@ -789,6 +789,7 @@ static void jp_a16(GB_gameboy_t *gb, uint8_t opcode)
|
||||
|
||||
static void call_cc_a16(GB_gameboy_t *gb, uint8_t opcode)
|
||||
{
|
||||
uint16_t call_addr = gb->pc;
|
||||
gb->pc++;
|
||||
if (condition_code(gb, opcode)) {
|
||||
GB_advance_cycles(gb, 4);
|
||||
@ -803,7 +804,7 @@ static void call_cc_a16(GB_gameboy_t *gb, uint8_t opcode)
|
||||
GB_advance_cycles(gb, 4);
|
||||
gb->pc = addr;
|
||||
|
||||
GB_debugger_call_hook(gb);
|
||||
GB_debugger_call_hook(gb, call_addr);
|
||||
}
|
||||
else {
|
||||
GB_advance_cycles(gb, 12);
|
||||
@ -973,6 +974,7 @@ static void cp_a_d8(GB_gameboy_t *gb, uint8_t opcode)
|
||||
|
||||
static void rst(GB_gameboy_t *gb, uint8_t opcode)
|
||||
{
|
||||
uint16_t call_addr = gb->pc;
|
||||
GB_advance_cycles(gb, 8);
|
||||
gb->registers[GB_REGISTER_SP] -= 2;
|
||||
GB_write_memory(gb, gb->registers[GB_REGISTER_SP] + 1, (gb->pc + 1) >> 8);
|
||||
@ -980,7 +982,7 @@ static void rst(GB_gameboy_t *gb, uint8_t opcode)
|
||||
GB_write_memory(gb, gb->registers[GB_REGISTER_SP], (gb->pc + 1) & 0xFF);
|
||||
GB_advance_cycles(gb, 4);
|
||||
gb->pc = opcode ^ 0xC7;
|
||||
GB_debugger_call_hook(gb);
|
||||
GB_debugger_call_hook(gb, call_addr);
|
||||
}
|
||||
|
||||
static void ret(GB_gameboy_t *gb, uint8_t opcode)
|
||||
@ -1002,6 +1004,7 @@ static void reti(GB_gameboy_t *gb, uint8_t opcode)
|
||||
|
||||
static void call_a16(GB_gameboy_t *gb, uint8_t opcode)
|
||||
{
|
||||
uint16_t call_addr = gb->pc;
|
||||
gb->pc++;
|
||||
GB_advance_cycles(gb, 4);
|
||||
gb->registers[GB_REGISTER_SP] -= 2;
|
||||
@ -1014,7 +1017,7 @@ static void call_a16(GB_gameboy_t *gb, uint8_t opcode)
|
||||
GB_write_memory(gb, gb->registers[GB_REGISTER_SP], (gb->pc + 2) & 0xFF);
|
||||
GB_advance_cycles(gb, 4);
|
||||
gb->pc = addr;
|
||||
GB_debugger_call_hook(gb);
|
||||
GB_debugger_call_hook(gb, call_addr);
|
||||
}
|
||||
|
||||
static void ld_da8_a(GB_gameboy_t *gb, uint8_t opcode)
|
||||
|
Loading…
Reference in New Issue
Block a user