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:
parent
c983f8ee00
commit
a944ee28d9
|
@ -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':
|
||||
|
|
Loading…
Reference in New Issue