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>
This commit is contained in:
Andreas Fritiofson 2018-08-20 15:34:19 +02:00
parent c983f8ee00
commit a944ee28d9
1 changed files with 102 additions and 8 deletions

View File

@ -43,6 +43,7 @@
#include <target/register.h> #include <target/register.h>
#include <target/target.h> #include <target/target.h>
#include <target/target_type.h> #include <target/target_type.h>
#include <target/semihosting_common.h>
#include "server.h" #include "server.h"
#include <flash/nor/core.h> #include <flash/nor/core.h>
#include "gdb_server.h" #include "gdb_server.h"
@ -2887,6 +2888,96 @@ static bool gdb_handle_vcont_packet(struct connection *connection, const char *p
return false; 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, static int gdb_v_packet(struct connection *connection,
char const *packet, int packet_size) char const *packet, int packet_size)
{ {
@ -2908,6 +2999,16 @@ static int gdb_v_packet(struct connection *connection,
return ERROR_OK; 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 flash programming disabled - send a empty reply */
if (gdb_flash_program == 0) { if (gdb_flash_program == 0) {
@ -3300,14 +3401,7 @@ static int gdb_input_inner(struct connection *connection)
break; break;
case 'R': case 'R':
/* handle extended restart packet */ /* handle extended restart packet */
breakpoint_clear_target(target); gdb_restart_inferior(connection, packet, packet_size);
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);
break; break;
case 'j': case 'j':