xdebug

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README

commit a40174ffcba9b1331b3e8857c4b4b3fc781e0aac
parent 95db60c95beaaf3ffd3600804df5941e3be83b2d
Author: Brian Swetland <swetland@frotz.net>
Date:   Tue,  7 Mar 2023 14:10:43 -0800

more core debugger features

- show commands in log
- ignore blank commandlines
- treat ESC as an interrupt key
- provide dc_core_step() and dc_core_wait_halt()
- add step, rd, and wr commands
- display registers on successfult halt or step

Diffstat:
Msrc/commands.c | 65+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------
Msrc/transport-arm-debug.c | 39++++++++++++++++++++++++++++++++++++++-
Msrc/transport-dap.c | 8++++++++
Msrc/transport-private.h | 3+++
Msrc/transport.h | 5+++++
Msrc/xdebug.c | 13++++++++++++-
6 files changed, 125 insertions(+), 8 deletions(-)

diff --git a/src/commands.c b/src/commands.c @@ -22,7 +22,7 @@ static uint32_t reglist[20] = { }; static uint32_t lastregs[20]; -int do_regs(DC* dc, CC* cc) { +static int read_show_regs(DC* dc) { if (dc_core_reg_rd_list(dc, reglist, lastregs, 20)) { return DBG_ERR; } @@ -44,6 +44,10 @@ int do_regs(DC* dc, CC* cc) { return 0; } +int do_regs(DC* dc, CC* cc) { + return read_show_regs(dc); +} + static uint32_t lastaddr = 0x20000000; static uint32_t lastcount = 0x40; @@ -90,15 +94,59 @@ int do_dw(DC* dc, CC* cc) { return 0; } +int do_rd(DC* dc, CC* cc) { + uint32_t addr, val; + if (cmd_arg_u32(cc, 1, &addr)) return DBG_ERR; + int r = dc_mem_rd32(dc, addr, &val); + if (r < 0) { + INFO("%08x: ????????\n", addr); + } else { + INFO("%08x: %08x\n", addr, val); + } + return r; +} + +int do_wr(DC* dc, CC* cc) { + uint32_t addr, val; + if (cmd_arg_u32(cc, 1, &addr)) return DBG_ERR; + if (cmd_arg_u32(cc, 2, &val)) return DBG_ERR; + int r; + if ((r = dc_mem_wr32(dc, addr, val)) == 0) { + INFO("%08x< %08x\n", addr, val); + } + return r; +} int do_stop(DC* dc, CC* cc) { - return dc_core_halt(dc); + int r; + if ((r = dc_core_halt(dc)) < 0) { + return r; + } + if ((r = dc_core_wait_halt(dc)) < 0) { + return r; + } + return read_show_regs(dc); } int do_resume(DC* dc, CC* cc) { return dc_core_resume(dc); } +int do_step(DC* dc, CC* cc) { + int r; + if ((r = dc_core_step(dc)) < 0) { + return r; + } + if ((r = dc_core_wait_halt(dc)) < 0) { + return r; + } + return read_show_regs(dc); +} + +int do_reset(DC* dc, CC* cc) { + return -1; //return dc_core_reset(dc); +} + int do_exit(DC* dc, CC* cc) { debugger_exit(); return 0; @@ -114,12 +162,17 @@ struct { { "attach", do_attach, "connect to target" }, { "stop", do_stop, "halt core" }, { "halt", do_stop, NULL }, - { "resume", do_resume, "resume core" }, { "go", do_resume, NULL }, - { "dw", do_dw, "dw <addr> [ <count> ] - dump words" }, - //{ "db", do_db, "db <addr> [ <count> ] - dump bytes" }, + { "resume", do_resume, "resume core" }, + { "step", do_step, "single-step core" }, + { "reset", do_reset, "reset core" }, + { "dw", do_dw, "dump words dw <addr> [ <count> ]" }, + //{ "db", do_db, "dump bytes db <addr> [ <count> ]" }, + { "rd", do_rd, "read word rd <addr>" }, + { "dr", do_rd, NULL }, + { "wr", do_wr, "write word wr <addr> <val>" }, { "regs", do_regs, "dump registers" }, - { "help", do_help, "list debugger commands" }, + { "help", do_help, "list commands" }, { "exit", do_exit, "exit debugger" }, { "quit", do_exit, NULL }, }; diff --git a/src/transport-arm-debug.c b/src/transport-arm-debug.c @@ -206,7 +206,44 @@ int dc_core_resume(DC* dc){ } int dc_core_step(DC* dc) { - return DC_ERR_FAILED; + uint32_t val; + int r; + if ((r = dc_mem_rd32(dc, DHCSR, &val)) < 0) { + return r; + } + val &= (DHCSR_C_DEBUGEN | DHCSR_C_HALT | DHCSR_C_MASKINTS); + val |= DHCSR_DBGKEY; + + if (!(val & DHCSR_C_HALT)) { + val |= DHCSR_C_HALT | DHCSR_C_DEBUGEN; + if ((r = dc_mem_wr32(dc, DHCSR, val)) < 0) { + return r; + } + } else { + val = (val & (~DHCSR_C_HALT)) | DHCSR_C_STEP; + if ((r = dc_mem_wr32(dc, DHCSR, val)) < 0) { + return r; + } + } + return 0; +} + +int dc_core_wait_halt(DC* dc) { + uint32_t last = dc_get_attn_value(dc); + uint32_t val; + int r; + for (;;) { + if ((r = dc_mem_rd32(dc, DHCSR, &val)) < 0) { + return r; + } + if (val & DHCSR_S_HALT) { + return 0; + } + if (last != dc_get_attn_value(dc)) { + return DC_ERR_INTERRUPTED; + } + } + return 0; } static void dc_q_core_reg_rd(DC* dc, unsigned id, uint32_t* val) { diff --git a/src/transport-dap.c b/src/transport-dap.c @@ -12,6 +12,14 @@ #include "transport.h" #include "transport-private.h" +void dc_interrupt(DC *dc) { + dc->attn++; +} + +uint32_t dc_get_attn_value(DC *dc) { + return dc->attn; +} + static void usb_failure(DC* dc, int status) { ERROR("usb_failure status %d usb %p\n", status, dc->usb); if (dc->usb != NULL) { diff --git a/src/transport-private.h b/src/transport-private.h @@ -13,6 +13,8 @@ struct debug_context { usb_handle* usb; unsigned status; + volatile uint32_t attn; + // dap protocol info uint32_t max_packet_count; uint32_t max_packet_size; @@ -68,4 +70,5 @@ static void dump(const char* str, const void* ptr, unsigned len) { #define dump(...) do {} while (0) #endif +uint32_t dc_get_attn_value(DC* dc); diff --git a/src/transport.h b/src/transport.h @@ -12,6 +12,8 @@ void dc_require_serialno(const char* sn); typedef struct debug_context dctx_t; int dc_periodic(dctx_t* dc); +void dc_interrupt(dctx_t* dc); + #define DC_OK 0 #define DC_ERR_FAILED -1 // generic internal failure #define DC_ERR_BAD_PARAMS -2 // Invalid parameters @@ -27,6 +29,8 @@ int dc_periodic(dctx_t* dc); #define DC_ERR_UNSUPPORTED -12 // unsupported operation #define DC_ERR_REMOTE -13 // failure from debug probe #define DC_ERR_DETACHED -14 // transport not connected to target +#define DC_ERR_BAD_STATE -15 +#define DC_ERR_INTERRUPTED -16 int dc_set_clock(dctx_t* dc, uint32_t hz); @@ -85,6 +89,7 @@ int dc_mem_wr_words(dctx_t* dc, uint32_t addr, uint32_t num, const uint32_t* ptr int dc_core_halt(dctx_t* dc); int dc_core_resume(dctx_t* dc); int dc_core_step(dctx_t* dc); +int dc_core_wait_halt(dctx_t* dc); int dc_core_reg_rd(dctx_t* dc, unsigned id, uint32_t* val); int dc_core_reg_wr(dctx_t* dc, unsigned id, uint32_t val); diff --git a/src/xdebug.c b/src/xdebug.c @@ -116,6 +116,8 @@ int parse(TOKEN* tok) { void debug_command(char *line) { CC cc; + INFO("> %s\n", line); + while (*line && (*line <= ' ')) line++; if (*line == '/') { cc.count = 2; @@ -205,9 +207,18 @@ static void *work_thread(void* arg) { } void handle_line(char *line, unsigned len) { + if (!strcmp(line, "@ESC@")) { + dc_interrupt(dc); + return; + } + if (len == 0) { + return; + } if (busy) { INFO("busy\n"); - } else if (len < (sizeof(linebuf)-1)) { + return; + } + if (len < (sizeof(linebuf)-1)) { memcpy(linebuf, line, len + 1); busy = 1; uint64_t n = 1;