diff --git a/include/debugger.h b/include/debugger.h index 7c80b1f..1ee4ecc 100644 --- a/include/debugger.h +++ b/include/debugger.h @@ -64,6 +64,7 @@ bool dbg_set_function_breakpoint(const char *_name, void(*cb)(struct breakpoint* bool dbg_set_address_breakpoint(uint32_t address, void(*cb)(struct breakpoint*), void *data); bool dbg_set_step_over_breakpoint(void); bool dbg_set_step_into_breakpoint(void); +bool dbg_set_finish_breakpoint(void); void dbg_print_frame(unsigned no); void dbg_print_stack_trace(void); void dbg_print_stack(void); diff --git a/src/debug.c b/src/debug.c index 5deb01f..fa090f0 100644 --- a/src/debug.c +++ b/src/debug.c @@ -341,6 +341,9 @@ static int32_t dbg_next_address(bool into, int *call_index) bool dbg_set_step_over_breakpoint(void) { + if (instr_ptr <= 0) + return false; + int call_index; int32_t address = dbg_next_address(false, &call_index); if (address < 0) @@ -351,6 +354,9 @@ bool dbg_set_step_over_breakpoint(void) bool dbg_set_step_into_breakpoint(void) { + if (instr_ptr <= 0) + return false; + int call_index; int32_t address = dbg_next_address(true, &call_index); if (address < 0) @@ -359,6 +365,19 @@ bool dbg_set_step_into_breakpoint(void) return true; } +bool dbg_set_finish_breakpoint(void) +{ + if (call_stack_ptr < 2) + return false; + + int32_t address = call_stack[call_stack_ptr-1].return_address; + // XXX: VM_RETURN + if (address < 0) + return false; + dbg_set_step_breakpoint(address, call_stack_ptr - 1); + return true; +} + static void _dbg_handle_breakpoint(void *data) { struct breakpoint *bp = data; @@ -549,6 +568,9 @@ struct string *dbg_value_to_string(struct ain_type *type, union vm_value value, // Rewind to DASM_REWIND instructions before the current instruction pointer. static bool dbg_init_dasm(struct dasm *dasm) { + if (call_stack_ptr < 1) + goto error; + unsigned addr_i = 0; size_t addr[DASM_REWIND] = {0}; int fno = call_stack[call_stack_ptr-1].fno; @@ -759,6 +781,11 @@ static bool dasm_print_finished(struct dasm *dasm, int dasm_i) void dbg_print_vm_state(void) { + if (call_stack_ptr < 1) { + DBG_ERROR("VM not running"); + return; + } + puts(""); puts(" Stack Disassembly"); puts("----------------- -----------"); diff --git a/src/debugger_cmd.c b/src/debugger_cmd.c index cb59395..981c9ee 100644 --- a/src/debugger_cmd.c +++ b/src/debugger_cmd.c @@ -183,19 +183,31 @@ static void dbg_cmd_scene(unsigned nr_args, char **args) static void dbg_cmd_next(unsigned nr_args, char **args) { - if (!dbg_set_step_over_breakpoint()) + if (!dbg_set_step_over_breakpoint()) { DBG_ERROR("Can't step over this instruction"); - else - stepping = true; + return; + } + stepping = true; dbg_continue(); } static void dbg_cmd_step(unsigned nr_args, char **args) { - if (!dbg_set_step_into_breakpoint()) + if (!dbg_set_step_into_breakpoint()) { DBG_ERROR("Can't step into this instruction"); - else - stepping = true; + return; + } + stepping = true; + dbg_continue(); +} + +static void dbg_cmd_finish(unsigned nr_args, char **args) +{ + if (!dbg_set_finish_breakpoint()) { + DBG_ERROR("Can't set finish breakpoint from this location"); + return; + } + stepping = true; dbg_continue(); } @@ -216,6 +228,7 @@ static struct dbg_cmd dbg_default_commands[] = { { "backtrace", "bt", "- Display stack trace", 0, 0, dbg_cmd_backtrace }, { "breakpoint", "bp", " - Set breakpoint", 1, 1, dbg_cmd_breakpoint }, { "continue", "c", "- Resume execution", 0, 0, dbg_cmd_continue }, + { "finish", "fin", "- Step back to the caller function", 0, 0, dbg_cmd_finish }, { "frame", "f", " - Set the current frame", 1, 1, dbg_cmd_frame }, { "locals", "l", "[frame-number] - Print local variables", 0, 1, dbg_cmd_locals }, { "log", NULL, " - Log function calls", 1, 1, dbg_cmd_log },