Initial DAP implementation

So far only basic debugging functionality is implemented (breakpoints,
stepping, stack traces/variables).

This is not tested against an established DAP client. My intention is to
create a custom GUI frontend and extend the protocol to support
xsystem4-specific features, such as inspecting the scene. (This work is
underway.)

Instruction references are hex-encoded address strings. Clients do not
need to obtain them from DAP requests. This is outside the spec, but it
is needed for a binary-only debugger.

Functions that write directly to stdout (e.g. printf) should generally
not be used any more.  Instead, use either sys_message (which respects
sys_silent) or log_message (which will send the message to the debugger
if DAP is enabled). stderr can be used as normal.
This commit is contained in:
Nunuhara Cabbage
2023-04-29 10:32:50 -07:00
parent 4ad893c147
commit d4e06db8e2
19 changed files with 1217 additions and 255 deletions
+28 -8
View File
@@ -36,6 +36,7 @@
#include "little_endian.h"
#include "xsystem4.h"
bool dbg_dap = false;
bool dbg_enabled = true;
bool dbg_start_in_debugger = false;
unsigned dbg_current_frame = 0;
@@ -74,7 +75,10 @@ void dbg_start(void(*fun)(void*), void *data)
static void _dbg_repl(void *_)
{
dbg_cmd_repl();
if (dbg_dap)
dbg_dap_repl();
else
dbg_cmd_repl();
}
void dbg_repl(void)
@@ -86,10 +90,15 @@ void dbg_repl(void)
void dbg_init(void)
{
dbg_cmd_init();
if (dbg_dap)
dbg_dap_init();
else
dbg_cmd_init();
#ifdef HAVE_SCHEME
dbg_scm_init();
#endif
if (!dbg_dap && dbg_start_in_debugger)
dbg_repl();
}
void dbg_fini(void)
@@ -135,6 +144,17 @@ static struct breakpoint *get_breakpoint(uint32_t addr)
return ht_get_int(bp_table, addr, NULL);
}
bool dbg_clear_breakpoint(uint32_t addr, void(*free_data)(void*))
{
struct breakpoint *bp = get_breakpoint(addr);
if (!bp)
return false;
if (free_data)
free_data(bp->data);
delete_breakpoint(addr, bp);
return true;
}
bool dbg_set_function_breakpoint(const char *_name, void(*cb)(struct breakpoint*), void *data)
{
char *name = utf2sjis(_name, 0);
@@ -157,7 +177,7 @@ bool dbg_set_function_breakpoint(const char *_name, void(*cb)(struct breakpoint*
LittleEndian_putW(ain->code, f->address, BREAKPOINT | bp->restore_op);
add_breakpoint(f->address, bp);
printf("Set breakpoint at function '%s' (0x%08x)\n", display_utf0(_name), f->address);
log_message("debug", "Set breakpoint at function '%s' (0x%08x)\n", display_utf0(_name), f->address);
return true;
}
@@ -185,7 +205,7 @@ bool dbg_set_address_breakpoint(uint32_t address, void(*cb)(struct breakpoint*),
LittleEndian_putW(ain->code, address, BREAKPOINT | bp->restore_op);
add_breakpoint(address, bp);
printf("Set breakpoint at 0x%08x\n", address);
log_message("debug", "Set breakpoint at 0x%08x\n", address);
return true;
}
@@ -196,7 +216,7 @@ static void dbg_step_breakpoint_cb(struct breakpoint *bp)
if ((intptr_t)bp->data != call_stack_ptr)
return;
delete_breakpoint(instr_ptr, bp);
dbg_cmd_repl();
_dbg_repl(NULL);
}
static void dbg_set_step_breakpoint(int32_t address, int call_index)
@@ -384,8 +404,8 @@ static void _dbg_handle_breakpoint(void *data)
if (bp->cb) {
bp->cb(bp);
} else {
printf("%s\n", bp->message);
dbg_cmd_repl();
log_message("debug", "%s\n", bp->message);
_dbg_repl(NULL);
}
}
@@ -408,7 +428,7 @@ void dbg_print_frame(unsigned no)
unsigned cs_no = call_stack_ptr - (1 + no);
struct ain_function *f = &ain->functions[call_stack[cs_no].fno];
uint32_t addr = no ? call_stack[cs_no+1].call_address : instr_ptr;
printf("%c #%d 0x%08x in %s\n", no == dbg_current_frame ? '*' : ' ',
sys_message("%c #%d 0x%08x in %s\n", no == dbg_current_frame ? '*' : ' ',
no, addr, display_sjis0(f->name));
}