tdesc: bitfields may carry a type
[openocd.git] / src / server / gdb_server.c
index 483e5510b115234d5d4243fa5cb8c9e8d7b6a1e7..428547b460764982da6088bd373ffb4e83a43f11 100644 (file)
@@ -41,6 +41,8 @@
 #include <target/breakpoints.h>
 #include <target/target_request.h>
 #include <target/register.h>
+#include <target/target.h>
+#include <target/target_type.h>
 #include "server.h"
 #include <flash/nor/core.h>
 #include "gdb_server.h"
@@ -71,8 +73,8 @@ struct gdb_connection {
        int ctrl_c;
        enum target_state frontend_state;
        struct image *vflash_image;
-       int closed;
-       int busy;
+       bool closed;
+       bool busy;
        int noack_mode;
        /* set flag to true if you want the next stepi to return immediately.
         * allowing GDB to pick up a fresh set of register values from the target
@@ -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;
@@ -215,7 +219,7 @@ static int gdb_get_char_inner(struct connection *connection, int *next_char)
                if (gdb_con->buf_cnt > 0)
                        break;
                if (gdb_con->buf_cnt == 0) {
-                       gdb_con->closed = 1;
+                       gdb_con->closed = true;
                        return ERROR_SERVER_REMOTE_CLOSED;
                }
 
@@ -227,10 +231,10 @@ static int gdb_get_char_inner(struct connection *connection, int *next_char)
                                usleep(1000);
                                break;
                        case WSAECONNABORTED:
-                               gdb_con->closed = 1;
+                               gdb_con->closed = true;
                                return ERROR_SERVER_REMOTE_CLOSED;
                        case WSAECONNRESET:
-                               gdb_con->closed = 1;
+                               gdb_con->closed = true;
                                return ERROR_SERVER_REMOTE_CLOSED;
                        default:
                                LOG_ERROR("read: %d", errno);
@@ -242,14 +246,14 @@ static int gdb_get_char_inner(struct connection *connection, int *next_char)
                                usleep(1000);
                                break;
                        case ECONNABORTED:
-                               gdb_con->closed = 1;
+                               gdb_con->closed = true;
                                return ERROR_SERVER_REMOTE_CLOSED;
                        case ECONNRESET:
-                               gdb_con->closed = 1;
+                               gdb_con->closed = true;
                                return ERROR_SERVER_REMOTE_CLOSED;
                        default:
                                LOG_ERROR("read: %s", strerror(errno));
-                               gdb_con->closed = 1;
+                               gdb_con->closed = true;
                                return ERROR_SERVER_REMOTE_CLOSED;
                }
 #endif
@@ -341,7 +345,7 @@ static int gdb_write(struct connection *connection, void *data, int len)
 
        if (connection_write(connection, data, len) == len)
                return ERROR_OK;
-       gdb_con->closed = 1;
+       gdb_con->closed = true;
        return ERROR_SERVER_REMOTE_CLOSED;
 }
 
@@ -448,7 +452,7 @@ static int gdb_put_packet_inner(struct connection *connection,
                                return ERROR_OK;
                        } else {
                                LOG_ERROR("unknown character(1) 0x%2.2x in reply, dropping connection", reply);
-                               gdb_con->closed = 1;
+                               gdb_con->closed = true;
                                return ERROR_SERVER_REMOTE_CLOSED;
                        }
                } else if (reply == '$') {
@@ -458,7 +462,7 @@ static int gdb_put_packet_inner(struct connection *connection,
                } else {
                        LOG_ERROR("unknown character(2) 0x%2.2x in reply, dropping connection",
                                reply);
-                       gdb_con->closed = 1;
+                       gdb_con->closed = true;
                        return ERROR_SERVER_REMOTE_CLOSED;
                }
        }
@@ -471,9 +475,9 @@ static int gdb_put_packet_inner(struct connection *connection,
 int gdb_put_packet(struct connection *connection, char *buffer, int len)
 {
        struct gdb_connection *gdb_con = connection->priv;
-       gdb_con->busy = 1;
+       gdb_con->busy = true;
        int retval = gdb_put_packet_inner(connection, buffer, len);
-       gdb_con->busy = 0;
+       gdb_con->busy = false;
 
        /* we sent some data, reset timer for keep alive messages */
        kept_alive();
@@ -679,9 +683,9 @@ static int gdb_get_packet_inner(struct connection *connection,
 static int gdb_get_packet(struct connection *connection, char *buffer, int *len)
 {
        struct gdb_connection *gdb_con = connection->priv;
-       gdb_con->busy = 1;
+       gdb_con->busy = true;
        int retval = gdb_get_packet_inner(connection, buffer, len);
-       gdb_con->busy = 0;
+       gdb_con->busy = false;
        return retval;
 }
 
@@ -728,7 +732,6 @@ static void gdb_signal_reply(struct target *target, struct connection *connectio
        } else {
                if (gdb_connection->ctrl_c) {
                        signal_var = 0x2;
-                       gdb_connection->ctrl_c = 0;
                } else
                        signal_var = gdb_last_signal(target);
 
@@ -760,12 +763,19 @@ static void gdb_signal_reply(struct target *target, struct connection *connectio
 
                current_thread[0] = '\0';
                if (target->rtos != NULL) {
-                       snprintf(current_thread, sizeof(current_thread), "thread:%016" PRIx64 ";", target->rtos->current_thread);
+                       struct target *ct;
+                       snprintf(current_thread, sizeof(current_thread), "thread:%016" PRIx64 ";",
+                                       target->rtos->current_thread);
                        target->rtos->current_threadid = target->rtos->current_thread;
+                       target->rtos->gdb_target_for_threadid(connection, target->rtos->current_threadid, &ct);
+                       if (!gdb_connection->ctrl_c)
+                               signal_var = gdb_last_signal(ct);
                }
 
                sig_reply_len = snprintf(sig_reply, sizeof(sig_reply), "T%2.2x%s%s",
                                signal_var, stop_reason, current_thread);
+
+               gdb_connection->ctrl_c = 0;
        }
 
        gdb_put_packet(connection, sig_reply, sig_reply_len);
@@ -917,10 +927,11 @@ static int gdb_target_callback_event_handler(struct target *target,
 static int gdb_new_connection(struct connection *connection)
 {
        struct gdb_connection *gdb_connection = malloc(sizeof(struct gdb_connection));
-       struct gdb_service *gdb_service = connection->service->priv;
+       struct target *target;
        int retval;
        int initial_ack;
 
+       target = get_target_from_connection(connection);
        connection->priv = gdb_connection;
 
        /* initialize gdb connection information */
@@ -929,8 +940,8 @@ static int gdb_new_connection(struct connection *connection)
        gdb_connection->ctrl_c = 0;
        gdb_connection->frontend_state = TARGET_HALTED;
        gdb_connection->vflash_image = NULL;
-       gdb_connection->closed = 0;
-       gdb_connection->busy = 0;
+       gdb_connection->closed = false;
+       gdb_connection->busy = false;
        gdb_connection->noack_mode = 0;
        gdb_connection->sync = false;
        gdb_connection->mem_write_error = false;
@@ -949,12 +960,17 @@ static int gdb_new_connection(struct connection *connection)
         * GDB session could leave dangling breakpoints if e.g. communication
         * timed out.
         */
-       breakpoint_clear_target(gdb_service->target);
-       watchpoint_clear_target(gdb_service->target);
+       breakpoint_clear_target(target);
+       watchpoint_clear_target(target);
 
-       /* clean previous rtos session if supported*/
-       if ((gdb_service->target->rtos) && (gdb_service->target->rtos->type->clean))
-               gdb_service->target->rtos->type->clean(gdb_service->target);
+       if (target->rtos) {
+               /* clean previous rtos session if supported*/
+               if (target->rtos->type->clean)
+                       target->rtos->type->clean(target);
+
+               /* update threads */
+               rtos_update_threads(target);
+       }
 
        /* remove the initial ACK from the incoming buffer */
        retval = gdb_get_char(connection, &initial_ack);
@@ -966,7 +982,7 @@ static int gdb_new_connection(struct connection *connection)
         */
        if (initial_ack != '+')
                gdb_putback_char(connection, initial_ack);
-       target_call_event_callbacks(gdb_service->target, TARGET_EVENT_GDB_ATTACH);
+       target_call_event_callbacks(target, TARGET_EVENT_GDB_ATTACH);
 
        if (gdb_use_memory_map) {
                /* Connect must fail if the memory map can't be set up correctly.
@@ -978,7 +994,7 @@ static int gdb_new_connection(struct connection *connection)
                for (i = 0; i < flash_get_bank_count(); i++) {
                        struct flash_bank *p;
                        p = get_flash_bank_by_num_noprobe(i);
-                       if (p->target != gdb_service->target)
+                       if (p->target != target)
                                continue;
                        retval = get_flash_bank_by_num(i, &p);
                        if (retval != ERROR_OK) {
@@ -990,10 +1006,12 @@ static int gdb_new_connection(struct connection *connection)
        }
 
        gdb_actual_connections++;
-       LOG_DEBUG("New GDB Connection: %d, Target %s, state: %s",
+       log_printf_lf(all_targets->next != NULL ? LOG_LVL_INFO : LOG_LVL_DEBUG,
+                       __FILE__, __LINE__, __func__,
+                       "New GDB Connection: %d, Target %s, state: %s",
                        gdb_actual_connections,
-                       target_name(gdb_service->target),
-                       target_state_name(gdb_service->target));
+                       target_name(target),
+                       target_state_name(target));
 
        /* DANGER! If we fail subsequently, we must remove this handler,
         * otherwise we occasionally see crashes as the timer can invoke the
@@ -1007,9 +1025,11 @@ static int gdb_new_connection(struct connection *connection)
 
 static int gdb_connection_closed(struct connection *connection)
 {
-       struct gdb_service *gdb_service = connection->service->priv;
+       struct target *target;
        struct gdb_connection *gdb_connection = connection->priv;
 
+       target = get_target_from_connection(connection);
+
        /* we're done forwarding messages. Tear down callback before
         * cleaning up connection.
         */
@@ -1017,8 +1037,8 @@ static int gdb_connection_closed(struct connection *connection)
 
        gdb_actual_connections--;
        LOG_DEBUG("GDB Close, Target: %s, state: %s, gdb_actual_connections=%d",
-               target_name(gdb_service->target),
-               target_state_name(gdb_service->target),
+               target_name(target),
+               target_state_name(target),
                gdb_actual_connections);
 
        /* see if an image built with vFlash commands is left */
@@ -1029,7 +1049,7 @@ static int gdb_connection_closed(struct connection *connection)
        }
 
        /* if this connection registered a debug-message receiver delete it */
-       delete_debug_msg_receiver(connection->cmd_ctx, gdb_service->target);
+       delete_debug_msg_receiver(connection->cmd_ctx, target);
 
        if (connection->priv) {
                free(connection->priv);
@@ -1039,9 +1059,9 @@ static int gdb_connection_closed(struct connection *connection)
 
        target_unregister_event_callback(gdb_target_callback_event_handler, connection);
 
-       target_call_event_callbacks(gdb_service->target, TARGET_EVENT_GDB_END);
+       target_call_event_callbacks(target, TARGET_EVENT_GDB_END);
 
-       target_call_event_callbacks(gdb_service->target, TARGET_EVENT_GDB_DETACH);
+       target_call_event_callbacks(target, TARGET_EVENT_GDB_DETACH);
 
        return ERROR_OK;
 }
@@ -1889,6 +1909,8 @@ static int gdb_memory_map(struct connection *connection,
 static const char *gdb_get_reg_type_name(enum reg_type type)
 {
        switch (type) {
+               case REG_TYPE_BOOL:
+                       return "bool";
                case REG_TYPE_INT:
                        return "int";
                case REG_TYPE_INT8:
@@ -1901,6 +1923,8 @@ static const char *gdb_get_reg_type_name(enum reg_type type)
                        return "int64";
                case REG_TYPE_INT128:
                        return "int128";
+               case REG_TYPE_UINT:
+                       return "uint";
                case REG_TYPE_UINT8:
                        return "uint8";
                case REG_TYPE_UINT16:
@@ -1928,12 +1952,45 @@ static const char *gdb_get_reg_type_name(enum reg_type type)
        return "int"; /* "int" as default value */
 }
 
+static int lookup_add_arch_defined_types(char const **arch_defined_types_list[], const char *type_id,
+                                       int *num_arch_defined_types)
+{
+       int tbl_sz = *num_arch_defined_types;
+
+       if (type_id != NULL && (strcmp(type_id, ""))) {
+               for (int j = 0; j < (tbl_sz + 1); j++) {
+                       if (!((*arch_defined_types_list)[j])) {
+                               (*arch_defined_types_list)[tbl_sz++] = type_id;
+                               *arch_defined_types_list = realloc(*arch_defined_types_list,
+                                                               sizeof(char *) * (tbl_sz + 1));
+                               (*arch_defined_types_list)[tbl_sz] = NULL;
+                               *num_arch_defined_types = tbl_sz;
+                               return 1;
+                       } else {
+                               if (!strcmp((*arch_defined_types_list)[j], type_id))
+                                       return 0;
+                       }
+               }
+       }
+
+       return -1;
+}
+
 static int gdb_generate_reg_type_description(struct target *target,
-               char **tdesc, int *pos, int *size, struct reg_data_type *type)
+               char **tdesc, int *pos, int *size, struct reg_data_type *type,
+               char const **arch_defined_types_list[], int * num_arch_defined_types)
 {
        int retval = ERROR_OK;
 
        if (type->type_class == REG_TYPE_CLASS_VECTOR) {
+               struct reg_data_type *data_type = type->reg_type_vector->type;
+               if (data_type->type == REG_TYPE_ARCH_DEFINED) {
+                       if (lookup_add_arch_defined_types(arch_defined_types_list, data_type->id,
+                                                       num_arch_defined_types))
+                               gdb_generate_reg_type_description(target, tdesc, pos, size, data_type,
+                                                               arch_defined_types_list,
+                                                               num_arch_defined_types);
+               }
                /* <vector id="id" type="type" count="count"/> */
                xml_printf(&retval, tdesc, pos, size,
                                "<vector id=\"%s\" type=\"%s\" count=\"%d\"/>\n",
@@ -1941,6 +1998,20 @@ static int gdb_generate_reg_type_description(struct target *target,
                                type->reg_type_vector->count);
 
        } else if (type->type_class == REG_TYPE_CLASS_UNION) {
+               struct reg_data_type_union_field *field;
+               field = type->reg_type_union->fields;
+               while (field != NULL) {
+                       struct reg_data_type *data_type = field->type;
+                       if (data_type->type == REG_TYPE_ARCH_DEFINED) {
+                               if (lookup_add_arch_defined_types(arch_defined_types_list, data_type->id,
+                                                               num_arch_defined_types))
+                                       gdb_generate_reg_type_description(target, tdesc, pos, size, data_type,
+                                                                       arch_defined_types_list,
+                                                                       num_arch_defined_types);
+                       }
+
+                       field = field->next;
+               }
                /* <union id="id">
                 *  <field name="name" type="type"/> ...
                 * </union> */
@@ -1948,7 +2019,6 @@ static int gdb_generate_reg_type_description(struct target *target,
                                "<union id=\"%s\">\n",
                                type->id);
 
-               struct reg_data_type_union_field *field;
                field = type->reg_type_union->fields;
                while (field != NULL) {
                        xml_printf(&retval, tdesc, pos, size,
@@ -1974,13 +2044,24 @@ static int gdb_generate_reg_type_description(struct target *target,
                                        type->id, type->reg_type_struct->size);
                        while (field != NULL) {
                                xml_printf(&retval, tdesc, pos, size,
-                                               "<field name=\"%s\" start=\"%d\" end=\"%d\"/>\n",
-                                               field->name, field->bitfield->start,
-                                               field->bitfield->end);
+                                               "<field name=\"%s\" start=\"%d\" end=\"%d\" type=\"%s\" />\n",
+                                               field->name, field->bitfield->start, field->bitfield->end,
+                                               gdb_get_reg_type_name(field->bitfield->type));
 
                                field = field->next;
                        }
                } else {
+                       while (field != NULL) {
+                               struct reg_data_type *data_type = field->type;
+                               if (data_type->type == REG_TYPE_ARCH_DEFINED) {
+                                       if (lookup_add_arch_defined_types(arch_defined_types_list, data_type->id,
+                                                                       num_arch_defined_types))
+                                               gdb_generate_reg_type_description(target, tdesc, pos, size, data_type,
+                                                                               arch_defined_types_list,
+                                                                               num_arch_defined_types);
+                               }
+                       }
+
                        /* <struct id="id">
                         *  <field name="name" type="type"/> ...
                         * </struct> */
@@ -2011,8 +2092,9 @@ static int gdb_generate_reg_type_description(struct target *target,
                field = type->reg_type_flags->fields;
                while (field != NULL) {
                        xml_printf(&retval, tdesc, pos, size,
-                                       "<field name=\"%s\" start=\"%d\" end=\"%d\"/>\n",
-                                       field->name, field->bitfield->start, field->bitfield->end);
+                                       "<field name=\"%s\" start=\"%d\" end=\"%d\" type=\"%s\" />\n",
+                                       field->name, field->bitfield->start, field->bitfield->end,
+                                       gdb_get_reg_type_name(field->bitfield->type));
 
                        field = field->next;
                }
@@ -2073,11 +2155,15 @@ static int gdb_generate_target_description(struct target *target, char **tdesc_o
        struct reg **reg_list = NULL;
        int reg_list_size;
        char const **features = NULL;
+       char const **arch_defined_types = NULL;
        int feature_list_size = 0;
+       int num_arch_defined_types = 0;
        char *tdesc = NULL;
        int pos = 0;
        int size = 0;
 
+       arch_defined_types = calloc(1, sizeof(char *));
+
        retval = target_get_gdb_reg_list(target, &reg_list,
                        &reg_list_size, REG_CLASS_ALL);
 
@@ -2130,8 +2216,13 @@ static int gdb_generate_target_description(struct target *target, char **tdesc_o
                                if (reg_list[i]->reg_data_type != NULL) {
                                        if (reg_list[i]->reg_data_type->type == REG_TYPE_ARCH_DEFINED) {
                                                /* generate <type... first, if there are architecture-defined types. */
-                                               gdb_generate_reg_type_description(target, &tdesc, &pos, &size,
-                                                               reg_list[i]->reg_data_type);
+                                               if (lookup_add_arch_defined_types(&arch_defined_types,
+                                                                               reg_list[i]->reg_data_type->id,
+                                                                               &num_arch_defined_types))
+                                                       gdb_generate_reg_type_description(target, &tdesc, &pos, &size,
+                                                                                       reg_list[i]->reg_data_type,
+                                                                                       &arch_defined_types,
+                                                                                       &num_arch_defined_types);
 
                                                type_str = reg_list[i]->reg_data_type->id;
                                        } else {
@@ -2181,6 +2272,7 @@ static int gdb_generate_target_description(struct target *target, char **tdesc_o
 error:
        free(features);
        free(reg_list);
+       free(arch_defined_types);
 
        if (retval == ERROR_OK)
                *tdesc_out = tdesc;
@@ -2357,7 +2449,11 @@ static int gdb_get_thread_list_chunk(struct target *target, char **thread_list,
        else
                transfer_type = 'l';
 
-       *chunk = malloc(length + 2);
+       *chunk = malloc(length + 2 + 3);
+    /* Allocating extra 3 bytes prevents false positive valgrind report
+        * of strlen(chunk) word access:
+        * Invalid read of size 4
+        * Address 0x4479934 is 44 bytes inside a block of size 45 alloc'd */
        if (*chunk == NULL) {
                LOG_ERROR("Unable to allocate memory");
                return ERROR_FAIL;
@@ -2410,13 +2506,13 @@ static int gdb_query_packet(struct connection *connection,
                        char gdb_reply[10];
                        char *separator;
                        uint32_t checksum;
-                       uint32_t addr = 0;
+                       target_addr_t addr = 0;
                        uint32_t len = 0;
 
                        /* skip command character */
                        packet += 5;
 
-                       addr = strtoul(packet, &separator, 16);
+                       addr = strtoull(packet, &separator, 16);
 
                        if (*separator != ',') {
                                LOG_ERROR("incomplete read memory packet received, dropping connection");
@@ -2465,7 +2561,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) ? '+' : '-');
@@ -2554,13 +2650,207 @@ 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_TARGET_NOT_HALTED)
+                       LOG_INFO("target %s was not halted when resume was requested", target_name(target));
+
+               /* poll target in an attempt to make its internal state consistent */
+               if (retval != ERROR_OK) {
+                       retval = target_poll(target);
+                       if (retval != ERROR_OK)
+                               LOG_DEBUG("error polling target %s after failed resume", target_name(target));
+               }
+
+               /*
+                * We don't report errors to gdb here, move frontend_state to
+                * TARGET_RUNNING to stay in sync with gdb's expectation of the
+                * target state
+                */
+               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') {
+               bool fake_step = false;
+
+               if (strncmp(parse, "s:", 2) == 0) {
+                       struct target *ct = target;
+                       int current_pc = 1;
+                       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 (target->rtos != NULL) {
+                               /* FIXME: why is this necessary? rtos state should be up-to-date here already! */
+                               rtos_update_threads(target);
+
+                               target->rtos->gdb_target_for_threadid(connection, thread_id, &ct);
+
+                               /*
+                                * check if the thread to be stepped is the current rtos thread
+                                * if not, we must fake the step
+                                */
+                               if (target->rtos->current_thread != thread_id)
+                                       fake_step = true;
+                       }
+
+                       if (parse[0] == ';') {
+                               ++parse;
+                               --packet_size;
+
+                               if (parse[0] == 'c') {
+                                       parse += 1;
+                                       packet_size -= 1;
+
+                                       /* check if thread-id follows */
+                                       if (parse[0] == ':') {
+                                               int64_t tid;
+                                               parse += 1;
+                                               packet_size -= 1;
+
+                                               tid = strtoll(parse, &endp, 16);
+                                               if (tid == thread_id) {
+                                                       /*
+                                                        * Special case: only step a single thread (core),
+                                                        * keep the other threads halted. Currently, only
+                                                        * aarch64 target understands it. Other target types don't
+                                                        * care (nobody checks the actual value of 'current')
+                                                        * and it doesn't really matter. This deserves
+                                                        * a symbolic constant and a formal interface documentation
+                                                        * at a later time.
+                                                        */
+                                                       LOG_DEBUG("request to step current core only");
+                                                       /* uncomment after checking that indeed other targets are safe */
+                                                       /*current_pc = 2;*/
+                                               }
+                                       }
+                               }
+                       }
+
+                       LOG_DEBUG("target %s single-step thread %"PRIx64, target_name(ct), thread_id);
+                       log_add_callback(gdb_log_callback, connection);
+                       target_call_event_callbacks(ct, TARGET_EVENT_GDB_START);
+
+                       /*
+                        * work around an annoying gdb behaviour: when the current thread
+                        * is changed in gdb, it assumes that the target can follow and also
+                        * make the thread current. This is an assumption that cannot hold
+                        * for a real target running a multi-threading OS. We just fake
+                        * the step to not trigger an internal error in gdb. See
+                        * https://sourceware.org/bugzilla/show_bug.cgi?id=22925 for details
+                        */
+                       if (fake_step) {
+                               int sig_reply_len;
+                               char sig_reply[128];
+
+                               LOG_DEBUG("fake step thread %"PRIx64, thread_id);
+
+                               sig_reply_len = snprintf(sig_reply, sizeof(sig_reply),
+                                                                                "T05thread:%016"PRIx64";", thread_id);
+
+                               gdb_put_packet(connection, sig_reply, sig_reply_len);
+                               log_remove_callback(gdb_log_callback, connection);
+
+                               return true;
+                       }
+
+                       /* support for gdb_sync command */
+                       if (gdb_connection->sync) {
+                               gdb_connection->sync = false;
+                               if (ct->state == TARGET_HALTED) {
+                                       LOG_WARNING("stepi ignored. GDB will now fetch the register state " \
+                                                                       "from the target.");
+                                       gdb_sig_halted(connection);
+                                       log_remove_callback(gdb_log_callback, connection);
+                               } else
+                                       gdb_connection->frontend_state = TARGET_RUNNING;
+                               return true;
+                       }
+
+                       retval = target_step(ct, current_pc, 0, 0);
+                       if (retval == ERROR_TARGET_NOT_HALTED)
+                               LOG_INFO("target %s was not halted when step was requested", target_name(ct));
+
+                       /* if step was successful send a reply back to gdb */
+                       if (retval == ERROR_OK) {
+                               retval = target_poll(ct);
+                               if (retval != ERROR_OK)
+                                       LOG_DEBUG("error polling target %s after successful step", target_name(ct));
+                               /* send back signal information */
+                               gdb_signal_reply(ct, connection);
+                               /* stop forwarding log packets! */
+                               log_remove_callback(gdb_log_callback, connection);
+                       } else
+                               gdb_connection->frontend_state = TARGET_RUNNING;
+               } 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)
 {
        struct gdb_connection *gdb_connection = connection->priv;
-       struct gdb_service *gdb_service = connection->service->priv;
+       struct target *target;
        int result;
 
+       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) {
@@ -2597,18 +2887,18 @@ static int gdb_v_packet(struct connection *connection,
                flash_set_dirty();
 
                /* perform any target specific operations before the erase */
-               target_call_event_callbacks(gdb_service->target,
+               target_call_event_callbacks(target,
                        TARGET_EVENT_GDB_FLASH_ERASE_START);
 
                /* vFlashErase:addr,length messages require region start and
                 * end to be "block" aligned ... if padding is ever needed,
                 * GDB will have become dangerously confused.
                 */
-               result = flash_erase_address_range(gdb_service->target,
-                               false, addr, length);
+               result = flash_erase_address_range(target, false, addr,
+                       length);
 
                /* perform any target specific operations after the erase */
-               target_call_event_callbacks(gdb_service->target,
+               target_call_event_callbacks(target,
                        TARGET_EVENT_GDB_FLASH_ERASE_END);
 
                /* perform erase */
@@ -2663,10 +2953,12 @@ static int gdb_v_packet(struct connection *connection,
 
                /* process the flashing buffer. No need to erase as GDB
                 * always issues a vFlashErase first. */
-               target_call_event_callbacks(gdb_service->target,
+               target_call_event_callbacks(target,
                                TARGET_EVENT_GDB_FLASH_WRITE_START);
-               result = flash_write(gdb_service->target, gdb_connection->vflash_image, &written, 0);
-               target_call_event_callbacks(gdb_service->target, TARGET_EVENT_GDB_FLASH_WRITE_END);
+               result = flash_write(target, gdb_connection->vflash_image,
+                       &written, 0);
+               target_call_event_callbacks(target,
+                       TARGET_EVENT_GDB_FLASH_WRITE_END);
                if (result != ERROR_OK) {
                        if (result == ERROR_FLASH_DST_OUT_OF_BANK)
                                gdb_put_packet(connection, "E.memtype", 9);
@@ -2690,9 +2982,8 @@ static int gdb_v_packet(struct connection *connection,
 
 static int gdb_detach(struct connection *connection)
 {
-       struct gdb_service *gdb_service = connection->service->priv;
-
-       target_call_event_callbacks(gdb_service->target, TARGET_EVENT_GDB_DETACH);
+       target_call_event_callbacks(get_target_from_connection(connection),
+               TARGET_EVENT_GDB_DETACH);
 
        return gdb_put_packet(connection, "OK", 2);
 }
@@ -2771,14 +3062,15 @@ static int gdb_input_inner(struct connection *connection)
        /* Do not allocate this on the stack */
        static char gdb_packet_buffer[GDB_BUFFER_SIZE];
 
-       struct gdb_service *gdb_service = connection->service->priv;
-       struct target *target = gdb_service->target;
+       struct target *target;
        char const *packet = gdb_packet_buffer;
        int packet_size;
        int retval;
        struct gdb_connection *gdb_con = connection->priv;
        static int extended_protocol;
 
+       target = get_target_from_connection(connection);
+
        /* drain input buffer. If one of the packets fail, then an error
         * packet is replied, if applicable.
         *
@@ -2948,8 +3240,8 @@ static int gdb_input_inner(struct connection *connection)
                                        break;
                                case 'R':
                                        /* handle extended restart packet */
-                                       breakpoint_clear_target(gdb_service->target);
-                                       watchpoint_clear_target(gdb_service->target);
+                                       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 */
@@ -2998,7 +3290,12 @@ static int gdb_input_inner(struct connection *connection)
 
                if (gdb_con->ctrl_c) {
                        if (target->state == TARGET_RUNNING) {
-                               retval = target_halt(target);
+                               struct target *t = target;
+                               if (target->rtos)
+                                       target->rtos->gdb_target_for_threadid(connection, target->rtos->current_threadid, &t);
+                               retval = target_halt(t);
+                               if (retval == ERROR_OK)
+                                       retval = target_poll(t);
                                if (retval != ERROR_OK)
                                        target_call_event_callbacks(target, TARGET_EVENT_GDB_HALT);
                                gdb_con->ctrl_c = 0;
@@ -3081,7 +3378,13 @@ static int gdb_target_add_one(struct target *target)
                if (!*end) {
                        if (parse_long(gdb_port_next, &portnumber) == ERROR_OK) {
                                free(gdb_port_next);
-                               gdb_port_next = alloc_printf("%d", portnumber+1);
+                               if (portnumber) {
+                                       gdb_port_next = alloc_printf("%d", portnumber+1);
+                               } else {
+                                       /* Don't increment if gdb_port is 0, since we're just
+                                        * trying to allocate an unused port. */
+                                       gdb_port_next = strdup("0");
+                               }
                        }
                }
        }
@@ -3316,3 +3619,9 @@ int gdb_register_commands(struct command_context *cmd_ctx)
        gdb_port_next = strdup("3333");
        return register_commands(cmd_ctx, NULL, gdb_command_handlers);
 }
+
+void gdb_service_free(void)
+{
+       free(gdb_port);
+       free(gdb_port_next);
+}

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)