diff options
author | Andreas Fritiofson <andreas.fritiofson@gmail.com> | 2018-08-20 15:34:19 +0200 |
---|---|---|
committer | Andreas Fritiofson <andreas.fritiofson@gmail.com> | 2019-10-18 09:21:56 +0100 |
commit | a944ee28d98d538c6a46f8026bbf0f0e90219c36 (patch) | |
tree | b58739728c27a25edcaf406ce08dc7b8f92087bb /src/server | |
parent | c983f8ee00527504cedad932858f00458d7b9b43 (diff) |
gdb_server: Support vRun packet, allow setting cmdline from GDB
GDB uses the vRun packet if available to restart a running process in
extended remote mode. Support this like the R packet and set the
semihosting command-line to allow it to be specified from GDB.
Change-Id: I9cb812b22170630f782113c9927e46e0cd5b1f0f
Signed-off-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
Reviewed-on: http://openocd.zylin.com/5186
Tested-by: jenkins
Reviewed-by: Tomas Vanek <vanekt@fbl.cz>
Reviewed-by: Matthias Welwarsky <matthias@welwarsky.de>
Diffstat (limited to 'src/server')
-rw-r--r-- | src/server/gdb_server.c | 110 |
1 files changed, 102 insertions, 8 deletions
diff --git a/src/server/gdb_server.c b/src/server/gdb_server.c index 0370fcd5..c8f0e523 100644 --- a/src/server/gdb_server.c +++ b/src/server/gdb_server.c @@ -43,6 +43,7 @@ #include <target/register.h> #include <target/target.h> #include <target/target_type.h> +#include <target/semihosting_common.h> #include "server.h" #include <flash/nor/core.h> #include "gdb_server.h" @@ -2887,6 +2888,96 @@ static bool gdb_handle_vcont_packet(struct connection *connection, const char *p return false; } +static char *next_hex_encoded_field(const char **str, char sep) +{ + size_t hexlen; + const char *hex = *str; + if (hex[0] == '\0') + return NULL; + + const char *end = strchr(hex, sep); + if (end == NULL) + hexlen = strlen(hex); + else + hexlen = end - hex; + *str = hex + hexlen + 1; + + if (hexlen % 2 != 0) { + /* Malformed hex data */ + return NULL; + } + + size_t count = hexlen / 2; + char *decoded = malloc(count + 1); + if (decoded == NULL) + return NULL; + + size_t converted = unhexify((void *)decoded, hex, count); + if (converted != count) { + free(decoded); + return NULL; + } + + decoded[count] = '\0'; + return decoded; +} + +/* handle extended restart packet */ +static void gdb_restart_inferior(struct connection *connection, const char *packet, int packet_size) +{ + struct gdb_connection *gdb_con = connection->priv; + struct target *target = get_target_from_connection(connection); + + breakpoint_clear_target(target); + watchpoint_clear_target(target); + command_run_linef(connection->cmd_ctx, "ocd_gdb_restart %s", + target_name(target)); + /* set connection as attached after reset */ + gdb_con->attached = true; + /* info rtos parts */ + gdb_thread_packet(connection, packet, packet_size); +} + +static bool gdb_handle_vrun_packet(struct connection *connection, const char *packet, int packet_size) +{ + struct target *target = get_target_from_connection(connection); + const char *parse = packet; + + /* Skip "vRun" */ + parse += 4; + + if (parse[0] != ';') + return false; + parse++; + + /* Skip first field "filename"; don't know what to do with it. */ + free(next_hex_encoded_field(&parse, ';')); + + char *cmdline = next_hex_encoded_field(&parse, ';'); + char *arg; + while (cmdline != NULL && (arg = next_hex_encoded_field(&parse, ';')) != NULL) { + char *new_cmdline = alloc_printf("%s %s", cmdline, arg); + free(cmdline); + free(arg); + cmdline = new_cmdline; + } + + if (cmdline != NULL) { + if (target->semihosting != NULL) { + LOG_INFO("GDB set inferior command line to '%s'", cmdline); + free(target->semihosting->cmdline); + target->semihosting->cmdline = cmdline; + } else { + LOG_INFO("GDB set inferior command line to '%s' but semihosting is unavailable", cmdline); + free(cmdline); + } + } + + gdb_restart_inferior(connection, packet, packet_size); + gdb_put_packet(connection, "S00", 3); + return true; +} + static int gdb_v_packet(struct connection *connection, char const *packet, int packet_size) { @@ -2908,6 +2999,16 @@ static int gdb_v_packet(struct connection *connection, return ERROR_OK; } + if (strncmp(packet, "vRun", 4) == 0) { + bool handled; + + handled = gdb_handle_vrun_packet(connection, packet, packet_size); + if (!handled) + gdb_put_packet(connection, "", 0); + + return ERROR_OK; + } + /* if flash programming disabled - send a empty reply */ if (gdb_flash_program == 0) { @@ -3300,14 +3401,7 @@ static int gdb_input_inner(struct connection *connection) break; case 'R': /* handle extended restart packet */ - breakpoint_clear_target(target); - watchpoint_clear_target(target); - command_run_linef(connection->cmd_ctx, "ocd_gdb_restart %s", - target_name(target)); - /* set connection as attached after reset */ - gdb_con->attached = true; - /* info rtos parts */ - gdb_thread_packet(connection, packet, packet_size); + gdb_restart_inferior(connection, packet, packet_size); break; case 'j': |