aboutsummaryrefslogtreecommitdiff
path: root/src/server
diff options
context:
space:
mode:
authorAndreas Fritiofson <andreas.fritiofson@gmail.com>2018-08-20 15:34:19 +0200
committerAndreas Fritiofson <andreas.fritiofson@gmail.com>2019-10-18 09:21:56 +0100
commita944ee28d98d538c6a46f8026bbf0f0e90219c36 (patch)
treeb58739728c27a25edcaf406ce08dc7b8f92087bb /src/server
parentc983f8ee00527504cedad932858f00458d7b9b43 (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.c110
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':