From: Matthias Welwarsky Date: Wed, 20 Sep 2017 10:02:08 +0000 (+0200) Subject: gdb_server: add support for vCont X-Git-Tag: v0.11.0-rc1~1226 X-Git-Url: https://review.openocd.org/gitweb?p=openocd.git;a=commitdiff_plain;h=d301d8b42f0bfe67d76d6f340db6570cc71c876e gdb_server: add support for vCont Make gdb use target support for single-stepping if available. Change-Id: Ie72345a1e749aefba7cd175ccbf5cf51d4f1a632 Signed-off-by: Matthias Welwarsky Reviewed-on: http://openocd.zylin.com/3833 Tested-by: jenkins Reviewed-by: Tomas Vanek --- diff --git a/src/server/gdb_server.c b/src/server/gdb_server.c index f90f12bb5c..d866fc6e2a 100644 --- a/src/server/gdb_server.c +++ b/src/server/gdb_server.c @@ -41,6 +41,8 @@ #include #include #include +#include +#include #include "server.h" #include #include "gdb_server.h" @@ -110,6 +112,8 @@ static char *gdb_port_next; static void gdb_log_callback(void *priv, const char *file, unsigned line, const char *function, const char *string); +static void gdb_sig_halted(struct connection *connection); + /* number of gdb connections, mainly to suppress gdb related debugging spam * in helper/log.c when no gdb connections are actually active */ int gdb_actual_connections; @@ -2470,7 +2474,7 @@ static int gdb_query_packet(struct connection *connection, &buffer, &pos, &size, - "PacketSize=%x;qXfer:memory-map:read%c;qXfer:features:read%c;qXfer:threads:read+;QStartNoAckMode+", + "PacketSize=%x;qXfer:memory-map:read%c;qXfer:features:read%c;qXfer:threads:read+;QStartNoAckMode+;vContSupported+", (GDB_BUFFER_SIZE - 1), ((gdb_use_memory_map == 1) && (flash_get_bank_count() > 0)) ? '+' : '-', (gdb_target_desc_supported == 1) ? '+' : '-'); @@ -2559,6 +2563,90 @@ static int gdb_query_packet(struct connection *connection, return ERROR_OK; } +static bool gdb_handle_vcont_packet(struct connection *connection, const char *packet, int packet_size) +{ + struct gdb_connection *gdb_connection = connection->priv; + struct target *target = get_target_from_connection(connection); + const char *parse = packet; + int retval; + + /* query for vCont supported */ + if (parse[0] == '?') { + if (target->type->step != NULL) { + /* gdb doesn't accept c without C and s without S */ + gdb_put_packet(connection, "vCont;c;C;s;S", 13); + return true; + } + return false; + } + + if (parse[0] == ';') { + ++parse; + --packet_size; + } + + /* simple case, a continue packet */ + if (parse[0] == 'c') { + LOG_DEBUG("target %s continue", target_name(target)); + log_add_callback(gdb_log_callback, connection); + retval = target_resume(target, 1, 0, 0, 0); + if (retval == ERROR_OK) { + gdb_connection->frontend_state = TARGET_RUNNING; + target_call_event_callbacks(target, TARGET_EVENT_GDB_START); + } + return true; + } + + /* single-step or step-over-breakpoint */ + if (parse[0] == 's') { + if (strncmp(parse, "s:", 2) == 0) { + int handle_breakpoint = 1; + struct target *ct = target; + int64_t thread_id; + char *endp; + + parse += 2; + packet_size -= 2; + + thread_id = strtoll(parse, &endp, 16); + if (endp != NULL) { + packet_size -= endp - parse; + parse = endp; + } + + if (parse[0] == ';') { + ++parse; + --packet_size; + + if (parse[0] == 'c') { + parse += 1; + packet_size -= 1; + + handle_breakpoint = 0; + } + } + + LOG_DEBUG("target %s single-step thread %"PRId64, target_name(ct), thread_id); + retval = target_step(ct, 1, 0, handle_breakpoint); + if (retval == ERROR_OK) { + gdb_signal_reply(target, connection); + /* stop forwarding log packets! */ + log_remove_callback(gdb_log_callback, connection); + } else + if (retval == ERROR_TARGET_TIMEOUT) { + gdb_connection->frontend_state = TARGET_RUNNING; + target_call_event_callbacks(ct, TARGET_EVENT_GDB_START); + } + } else { + LOG_ERROR("Unknown vCont packet"); + return false; + } + return true; + } + + return false; +} + static int gdb_v_packet(struct connection *connection, char const *packet, int packet_size) { @@ -2568,6 +2656,19 @@ static int gdb_v_packet(struct connection *connection, target = get_target_from_connection(connection); + if (strncmp(packet, "vCont", 5) == 0) { + bool handled; + + packet += 5; + packet_size -= 5; + + handled = gdb_handle_vcont_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) {