From e847ad3f6e182d2d295e9f0e3ed92b4a9f3d317f Mon Sep 17 00:00:00 2001 From: Lephenixnoir Date: Sat, 30 Mar 2024 11:47:04 +0100 Subject: [PATCH] gdb: provide [fxsdk gdb] wrapper --- fxsdk/fxsdk.sh | 7 +++ fxsdk/gdb-bridge.c | 131 ++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 126 insertions(+), 12 deletions(-) diff --git a/fxsdk/fxsdk.sh b/fxsdk/fxsdk.sh index 33b7fc4..d3bb853 100755 --- a/fxsdk/fxsdk.sh +++ b/fxsdk/fxsdk.sh @@ -51,6 +51,11 @@ ${R}fxsdk${n} (${R}send${n}|${R}send-fx${n}|${R}send-cg${n}) externally) for the fx-9860G, and fxlink for the fx-CG. For the G-III series, call fxlink directly instead of this command. +${R}fxsdk${n} ${R}gdb${n} [${g}${n}...] [${R}--${n} ${g}${n}...] + Starts the GDB bridge and GDB itself. In general, you'll want at least one + GDB option--the path to the executable file to debug. + With --bridge-only, don't start GDB and instead enable bridge logs. + ${R}fxsdk${n} ${R}path${n} (${R}sysroot${n}|${R}include${n}|${R}lib${n}) Prints commonly-used paths in the SuperH sysroot: ${R}sysroot${n} The root folder of the SuperH toolchain and libraries @@ -335,6 +340,8 @@ case "$1" in fxsdk_send_cg;; # Utilities + "gdb") + fxsdk-gdb-bridge "${@:2}";; "path") fxsdk_path "${@:2}";; diff --git a/fxsdk/gdb-bridge.c b/fxsdk/gdb-bridge.c index f9a9705..7111fcf 100644 --- a/fxsdk/gdb-bridge.c +++ b/fxsdk/gdb-bridge.c @@ -4,7 +4,10 @@ #include #include #include +#include #include +#include +#include #include @@ -50,8 +53,8 @@ static struct fxlink_device *setup_calc(libusb_context *context, bool nostart) struct fxlink_message *msg = fxlink_device_finish_bulk_IN(fdev); if(!msg) continue; + hlog("gdb"); if(fxlink_message_is_apptype(msg, "gdb", "start")) { - hlog("gdb"); log_("got start message\n"); break; } @@ -72,6 +75,8 @@ static int setup_socket(char const *listen_path) return -1; } + unlink(listen_path); + struct sockaddr_un listen_address = { .sun_family = AF_UNIX, .sun_path = {0}, @@ -92,6 +97,58 @@ static int setup_socket(char const *listen_path) hlog("socket"); log_("waiting for client on \"%s\"...\n", listen_address.sun_path); + + return listen_socket; +} + +static int volatile gdb_terminated_flag = 0; +static int volatile interrupted_flag = 0; + +void SIGINT_SIGCHLD_handler(int signal) +{ + if(signal == SIGCHLD) + gdb_terminated_flag = 1; + else + interrupted_flag = 1; +} + +static pid_t fork_gdb(char **user_argv, char const *socket_path) +{ + int n = 0; + while(user_argv[n]) + n++; + + char target_command[256]; + sprintf(target_command, "target remote %s", socket_path); + + char **argv = malloc((n + 5) * sizeof *argv); + argv[0] = "sh-elf-gdb"; + argv[1] = "-q"; + argv[2] = "-ex"; + argv[3] = target_command; + memcpy(argv+4, user_argv, (n+1) * sizeof *argv); + + struct sigaction action = { + .sa_handler = SIGINT_SIGCHLD_handler, + }; + sigaction(SIGCHLD, &action, NULL); + + pid_t pid = fork(); + + /* Child - execvp() only returns if there is an error */ + if(pid == 0) { + execvp("sh-elf-gdb", argv); + perror("execvp"); + exit(1); + } + /* Parent */ + if(pid == -1) + perror("fork"); + return pid; +} + +static int accept_gdb(int listen_socket) +{ int client_socket = accept(listen_socket, NULL, NULL); if(client_socket < 0) { close(listen_socket); @@ -102,17 +159,42 @@ static int setup_socket(char const *listen_path) return client_socket; } -int main(int argc, char *argv[]) +struct options { + bool bridge_only; +}; + +/* Parse options, returns positional arguments to forward to gdb. */ +static char **parse_argv(int argc, char **argv, struct options *opts) +{ + int bridge_only = 0; + struct option longs[] = { + { "bridge-only", no_argument, &bridge_only, 1 }, + { NULL }, + }; + + getopt_long(argc, argv, "", longs, NULL); + + opts->bridge_only = (bridge_only != 0); + return argv + optind + (argv[optind] && !strcmp(argv[optind], "--")); +} + +static void noop_log_handler(int display_fmt, char const *str) +{ + (void)display_fmt; + (void)str; +} + +int main(int argc, char **argv) { libusb_context *context = NULL; struct fxlink_device *fdev = NULL; struct fxlink_pollfds fxlink_polled_fds = { 0 }; + char socket_path[256] = { 0 }; + pid_t gdb_pid = -1; int ret = 1; - if(argc != 2) { - elog("Usage : %s [listen path]\n", argv[0]); - goto end; - } + struct options opts; + char **gdb_argv = parse_argv(argc, argv, &opts); int err = libusb_init(&context); if(err != 0) { @@ -124,17 +206,37 @@ int main(int argc, char *argv[]) if(!fdev) goto end; - int client_socket = setup_socket(argv[1]); + sprintf(socket_path, "/tmp/fxsdk-gdb-bridge-%03d-%03d.socket", + fdev->busNumber, fdev->deviceAddress); + + int listen_socket = setup_socket(socket_path); + if(listen_socket < 0) + goto end; + + if(!opts.bridge_only) { + gdb_pid = fork_gdb(gdb_argv, socket_path); + if(gdb_pid == -1) + goto end; + /* Cut fxlink logs to not mix in with gdb's output */ + fxlink_log_set_handler(noop_log_handler); + } + + int client_socket = accept_gdb(listen_socket); if(client_socket < 0) goto end; + struct sigaction action = { + .sa_handler = SIGINT_SIGCHLD_handler, + }; + sigaction(SIGINT, &action, NULL); + /* Track libusb fds as an indirect way to watch the calculator itself */ struct pollfd client_socket_pollfd = { .fd = client_socket, .events = POLLIN }; fxlink_pollfds_track(&fxlink_polled_fds, context); - while(true) { + while(!interrupted_flag && !gdb_terminated_flag) { int err = fxlink_multipoll(-1, fxlink_polled_fds.fds, fxlink_polled_fds.count, &client_socket_pollfd, 1, @@ -150,12 +252,14 @@ int main(int argc, char *argv[]) struct fxlink_message *msg; while((msg = fxlink_device_finish_bulk_IN(fdev)) != NULL) { if(!fxlink_message_is_apptype(msg, "gdb", "remote")) { + hlog("gdb"); wlog("dropped a message of type %.16s:%.16s\n", msg->application, msg->type); fxlink_device_start_bulk_IN(fdev); continue; } - printf("CAL> %.*s\n", msg->size, (char *)msg->data); + if(opts.bridge_only) + printf("CAL> %.*s\n", msg->size, (char *)msg->data); ssize_t send_ret = send(client_socket, msg->data, msg->size, 0); if(send_ret != msg->size) { perror("send"); @@ -182,7 +286,8 @@ int main(int argc, char *argv[]) perror("recv"); goto end; } - printf("GDB> %.*s\n", (int)recv_ret, buf); + if(opts.bridge_only) + printf("GDB> %.*s\n", (int)recv_ret, buf); if(!fxlink_device_start_bulk_OUT(fdev, "gdb", "remote", buf, recv_ret, false)) { elog("unable to start bulk OUT transfer\n"); goto end; @@ -193,8 +298,10 @@ int main(int argc, char *argv[]) ret = 0; end: - /* TODO: Close socket at end, including after ^C */ - + if(gdb_pid != -1) + waitpid(gdb_pid, NULL, 0); + if(socket_path[0]) + unlink(socket_path); if(fxlink_polled_fds.ctx) fxlink_pollfds_stop(&fxlink_polled_fds); if(fdev) {