xdebug

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

commit 1fee02a2717a44f3b5edddda1d5fc330082e4b7f
parent 2bc1b60f6f1793a27e90ebe1c754f492573d925c
Author: Brian Swetland <swetland@frotz.net>
Date:   Mon,  6 Mar 2023 18:35:09 -0800

multithreaded mayhem

- fire up a second thread to run all debugger commands on
- wire up a handoff between the ui thread and debugger thread
- set up periodic polling to detect target detach, usb disconnect,
  and usb connect and inform the user in a timely fashion

Diffstat:
Msrc/transport-dap.c | 131++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------------
Msrc/transport-private.h | 3++-
Msrc/transport.h | 6++++--
Msrc/usb.c | 12++++++++++++
Msrc/xdebug.c | 65++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
5 files changed, 188 insertions(+), 29 deletions(-)

diff --git a/src/transport-dap.c b/src/transport-dap.c @@ -12,15 +12,31 @@ #include "transport.h" #include "transport-private.h" +static void usb_failure(DC* dc, int status) { + ERROR("usb_failure status %d usb %p\n", status, dc->usb); + if (dc->usb != NULL) { + usb_close(dc->usb); + dc->usb = NULL; + } + dc->status = DC_OFFLINE; +} + static int dap_get_info(DC* dc, unsigned di, void *out, unsigned minlen, unsigned maxlen) { uint8_t buf[256 + 2]; buf[0] = DAP_Info; buf[1] = di; - if (usb_write(dc->usb, buf, 2) != 2) { + int r; + if ((r = usb_write(dc->usb, buf, 2)) != 2) { + if (r < 0) { + usb_failure(dc, r); + } return DC_ERR_IO; } int sz = usb_read(dc->usb, buf, 256 + 2); if ((sz < 2) || (buf[0] != DAP_Info)) { + if (sz < 0) { + usb_failure(dc, sz); + } return DC_ERR_PROTOCOL; } if ((buf[1] < minlen) || (buf[1] > maxlen)) { @@ -33,13 +49,20 @@ static int dap_get_info(DC* dc, unsigned di, void *out, unsigned minlen, unsigne static int dap_cmd(DC* dc, const void* tx, unsigned txlen, void* rx, unsigned rxlen) { uint8_t cmd = ((const uint8_t*) tx)[0]; dump("TX>", tx, txlen); - if (usb_write(dc->usb, tx, txlen) != txlen) { + int r; + if ((r = usb_write(dc->usb, tx, txlen)) != txlen) { ERROR("dap_cmd(0x%02x): usb write error\n", cmd); + if (r < 0) { + usb_failure(dc, r); + } return DC_ERR_IO; } int sz = usb_read(dc->usb, rx, rxlen); if (sz < 1) { ERROR("dap_cmd(0x%02x): usb read error\n", cmd); + if (sz < 0) { + usb_failure(dc, sz); + } return DC_ERR_IO; } dump("RX>", rx, rxlen); @@ -66,7 +89,14 @@ static int dap_cmd_std(DC* dc, const char* name, uint8_t* io, static int dap_connect(DC* dc) { uint8_t io[2] = { DAP_Connect, PORT_SWD }; - return dap_cmd_std(dc, "dap_connect()", io, 2, 2); + int r = dap_cmd(dc, io, 2, io, 2); + if (r < 0) { + return r; + } + if (io[1] != PORT_SWD) { + return DC_ERR_REMOTE; + } + return 0; } static int dap_swd_configure(DC* dc, unsigned cfg) { @@ -171,16 +201,21 @@ static int _dc_q_exec(DC* dc) { } int sz = dc->txnext - dc->txbuf; dump("TX>", dc->txbuf, sz); - if (usb_write(dc->usb, dc->txbuf, sz) != sz) { + int n = usb_write(dc->usb, dc->txbuf, sz); + if (n != sz) { ERROR("dc_q_exec() usb write error\n"); + if (n < 0) { + usb_failure(dc, n); + } return DC_ERR_IO; } sz = 3 + (dc->rxnext - dc->rxptr) * 4; uint8_t rxbuf[1024]; memset(rxbuf, 0xEE, 1024); // DEBUG - int n = usb_read(dc->usb, rxbuf, sz); + n = usb_read(dc->usb, rxbuf, sz); if (n < 0) { ERROR("dc_q_exec() usb read error\n"); + usb_failure(dc, n); return DC_ERR_IO; } dump("RX>", rxbuf, sz); @@ -209,7 +244,6 @@ int dc_q_exec(DC* dc) { if (r == DC_ERR_SWD_FAULT) { // clear all sticky errors dc_dp_wr(dc, DP_ABORT, DP_ABORT_ALLCLR); - } return r; } @@ -456,6 +490,8 @@ int dc_attach(DC* dc, unsigned flags, unsigned tgt, uint32_t* idcode) { dc->map_csw_keep &= MAP_CSW_KEEP; + dc->status = DC_ATTACHED; + return 0; } @@ -477,6 +513,21 @@ static usb_handle* usb_connect(void) { return usb_open(dc_vid, dc_pid, dc_serialno); } +static const char* di_name(unsigned n) { + switch (n) { + case DI_Vendor_Name: return "Vendor Name"; + case DI_Product_Name: return "Product Name"; + case DI_Serial_Number: return "Serial Number"; + case DI_Protocol_Version: return "Protocol Version"; + case DI_Target_Device_Vendor: return "Target Device Vendor"; + case DI_Target_Device_Name: return "Target Device Name"; + case DI_Target_Board_Vendor: return "Target Board Vendor"; + case DI_Target_Board_Name: return "Target Board Name"; + case DI_Product_Firmware_Version: return "Product Firmware Version"; + default: return "???"; + } +} + // setup a newly connected DAP device static int dap_configure(DC* dc) { uint8_t buf[256 + 2]; @@ -506,14 +557,13 @@ static int dap_configure(DC* dc) { int sz = dap_get_info(dc, n, buf, 0, 255); if (sz > 0) { buf[sz] = 0; - INFO("0x%02x: '%s'\n", n, (char*) buf); + INFO("connect: %s: '%s'\n", di_name(n), (char*) buf); } } buf[0] = 0; buf[1] = 0; if (dap_get_info(dc, DI_Capabilities, buf, 1, 2) > 0) { - INFO("Capabilities: 0x%02x 0x%02x\n", buf[0], buf[1]); - INFO("Capabilities:"); + INFO("connect: Capabilities:"); if (buf[0] & I0_SWD) INFO(" SWD"); if (buf[0] & I0_JTAG) INFO(" JTAG"); if (buf[0] & I0_SWO_UART) INFO(" SWO(UART)"); @@ -526,22 +576,22 @@ static int dap_configure(DC* dc) { INFO("\n"); } if (dap_get_info(dc, DI_UART_RX_Buffer_Size, &n32, 4, 4) == 4) { - INFO("UART RX Buffer Size: %u\n", n32); + INFO("connect: UART RX Buffer Size: %u\n", n32); } if (dap_get_info(dc, DI_UART_TX_Buffer_Size, &n32, 4, 4) == 4) { - INFO("UART TX Buffer Size: %u\n", n32); + INFO("connect: UART TX Buffer Size: %u\n", n32); } if (dap_get_info(dc, DI_SWO_Trace_Buffer_Size, &n32, 4, 4) == 4) { - INFO("SWO Trace Buffer Size: %u\n", n32); + INFO("connect: SWO Trace Buffer Size: %u\n", n32); } if (dap_get_info(dc, DI_Max_Packet_Count, &n8, 1, 1) == 1) { - INFO("Max Packet Count: %u\n", n8); dc->max_packet_count = n8; } if (dap_get_info(dc, DI_Max_Packet_Size, &n16, 2, 2) == 2) { - INFO("Max Packet Size: %u\n", n16); dc->max_packet_size = n16; } + INFO("connect: Max Packet Count: %u, Size: %u\n", + dc->max_packet_count, dc->max_packet_size); if ((dc->max_packet_count < 1) || (dc->max_packet_size < 64)) { ERROR("dc_init() impossible packet configuration\n"); return DC_ERR_PROTOCOL; @@ -561,23 +611,54 @@ static int dap_configure(DC* dc) { return DC_OK; } +static void dc_connect(DC* dc) { + if ((dc->usb = usb_connect()) != NULL) { + dc->status = DC_UNCONFIG; + if (dap_configure(dc) == 0) { + dc->status = DC_DETACHED; + } + } +} + int dc_create(DC** out) { DC* dc; if ((dc = calloc(1, sizeof(DC))) == NULL) { return DC_ERR_FAILED; } - - if ((dc->usb = usb_connect()) == NULL) { - free(dc); - return DC_ERR_OFFLINE; - } + *out = dc; + dc->status = DC_OFFLINE; + dc_connect(dc); + return 0; +} - int r = dap_configure(dc); - if (r < 0) { - free(dc); - } else { - *out = dc; +int dc_periodic(DC* dc) { + switch (dc->status) { + case DC_OFFLINE: + dc_connect(dc); + return 1000; + case DC_ATTACHED: { + uint32_t n; + int r = dc_dp_rd(dc, DP_CS, &n); + if (r == DC_ERR_IO) { + dc->status = DC_OFFLINE; + ERROR("offline\n"); + } else if (r < 0) { + dc->status = DC_DETACHED; + ERROR("detached\n"); + } + return 250; + } + case DC_FAILURE: + case DC_UNCONFIG: + case DC_DETACHED: { + // ping the probe to see if USB is still connected + uint8_t buf[256 + 2]; + dap_get_info(dc, DI_Protocol_Version, buf, 0, 255); + return 1000; + } + default: + return 1000; } - return r; } + diff --git a/src/transport-private.h b/src/transport-private.h @@ -48,7 +48,8 @@ typedef struct debug_context DC; #define DC_ATTACHED 0 // attached and ready to do txns #define DC_FAILURE 1 // last txn failed, need to re-attach #define DC_DETACHED 2 // have not yet attached -#define DC_OFFLINE 3 // usb connection not available +#define DC_UNCONFIG 3 // configure failed +#define DC_OFFLINE 4 // usb connection not available #define INVALID 0xFFFFFFFFU diff --git a/src/transport.h b/src/transport.h @@ -5,9 +5,13 @@ #include <stdint.h> + void dc_require_vid_pid(unsigned vid, unsigned pid); void dc_require_serialno(const char* sn); +typedef struct debug_context dctx_t; +int dc_periodic(dctx_t* dc); + #define DC_OK 0 #define DC_ERR_FAILED -1 // generic internal failure #define DC_ERR_BAD_PARAMS -2 // Invalid parameters @@ -24,8 +28,6 @@ void dc_require_serialno(const char* sn); #define DC_ERR_REMOTE -13 // failure from debug probe #define DC_ERR_DETACHED -14 // transport not connected to target -typedef struct debug_context dctx_t; - int dc_set_clock(dctx_t* dc, uint32_t hz); // queue Debug Port reads and writes diff --git a/src/usb.c b/src/usb.c @@ -269,6 +269,9 @@ void usb_close(usb_handle *usb) { int usb_ctrl(usb_handle *usb, void *data, uint8_t typ, uint8_t req, uint16_t val, uint16_t idx, uint16_t len) { + if (usb == NULL) { + return LIBUSB_ERROR_NO_DEVICE; + } int r = libusb_control_transfer(usb->dev, typ, req, val, idx, data, len, 5000); if (r < 0) { return -1; @@ -278,6 +281,9 @@ int usb_ctrl(usb_handle *usb, void *data, } int usb_read(usb_handle *usb, void *data, int len) { + if (usb == NULL) { + return LIBUSB_ERROR_NO_DEVICE; + } int xfer = len; int r = libusb_bulk_transfer(usb->dev, usb->ei, data, len, &xfer, 5000); if (r < 0) { @@ -287,6 +293,9 @@ int usb_read(usb_handle *usb, void *data, int len) { } int usb_read_forever(usb_handle *usb, void *data, int len) { + if (usb == NULL) { + return LIBUSB_ERROR_NO_DEVICE; + } int xfer = len; int r = libusb_bulk_transfer(usb->dev, usb->ei, data, len, &xfer, 0); if (r < 0) { @@ -296,6 +305,9 @@ int usb_read_forever(usb_handle *usb, void *data, int len) { } int usb_write(usb_handle *usb, const void *data, int len) { + if (usb == NULL) { + return LIBUSB_ERROR_NO_DEVICE; + } int xfer = len; int r = libusb_bulk_transfer(usb->dev, usb->eo, (void*) data, len, &xfer, 5000); if (r < 0) { diff --git a/src/xdebug.c b/src/xdebug.c @@ -7,6 +7,10 @@ #include <string.h> #include <stdarg.h> +#include <pthread.h> +#include <sys/eventfd.h> +#include <poll.h> + #include "xdebug.h" #include "tui.h" @@ -109,7 +113,7 @@ int parse(TOKEN* tok) { return 0; } -void handle_line(char *line, unsigned len) { +void debug_command(char *line) { CC cc; while (*line && (*line <= ' ')) line++; @@ -165,6 +169,52 @@ void handle_line(char *line, unsigned len) { debugger_command(dc, &cc); } +static volatile int running = 1; +static volatile int busy = 0; +static int efd = -1; +static char linebuf[1024]; + +static void *work_thread(void* arg) { + struct pollfd pfd = { + .fd = efd, + .events = POLLIN, + }; + int timeout = 250; + while (running) { + int r = poll(&pfd, 1, timeout); + if (r < 0) { + exit(-1); + } + if (r == 0) { + timeout = dc_periodic(dc); + if (timeout < 100) { + timeout = 100; + } + continue; + } + uint64_t n; + if (read(efd, &n, sizeof(n)) != sizeof(n)) { + break; + } + if (busy) { + debug_command(linebuf); + busy = 0; + } + } + return 0; +} + +void handle_line(char *line, unsigned len) { + if (busy) { + INFO("busy\n"); + } else if (len < (sizeof(linebuf)-1)) { + memcpy(linebuf, line, len + 1); + busy = 1; + uint64_t n = 1; + if (write(efd, &n, sizeof(n))) {} + } +} + static tui_ch_t* ch; int main(int argc, char** argv) { @@ -193,9 +243,22 @@ int main(int argc, char** argv) { return -1; } } + + if ((efd = eventfd(0, 0)) < 0) { + fprintf(stderr, "cannot create eventfd\n"); + return -1; + } + tui_init(); tui_ch_create(&ch, 0); dc_create(&dc); + + pthread_t t; + if (pthread_create(&t, NULL, work_thread, NULL) != 0) { + fprintf(stderr, "cannot start thread\n"); + return -1; + } + while (tui_handle_event(handle_line) == 0) ; tui_exit(); return 0;