Combine register lists of smp targets.
[openocd.git] / src / server / gdb_server.c
index 327d96b1772a4ba23135d1a450612f512fd04649..b6f4a82647a60cc07c8b81be525f1d04931a1cd9 100644 (file)
@@ -177,7 +177,7 @@ static int check_pending(struct connection *connection,
        fd_set read_fds;
        struct gdb_connection *gdb_con = connection->priv;
        int t;
-       if (got_data == NULL)
+       if (!got_data)
                got_data = &t;
        *got_data = 0;
 
@@ -227,6 +227,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) {
+                       LOG_DEBUG("GDB connection closed by the remote client");
                        gdb_con->closed = true;
                        return ERROR_SERVER_REMOTE_CLOSED;
                }
@@ -348,23 +349,63 @@ static int gdb_putback_char(struct connection *connection, int last_char)
 static int gdb_write(struct connection *connection, void *data, int len)
 {
        struct gdb_connection *gdb_con = connection->priv;
-       if (gdb_con->closed)
+       if (gdb_con->closed) {
+               LOG_DEBUG("GDB socket marked as closed, cannot write to it.");
                return ERROR_SERVER_REMOTE_CLOSED;
+       }
 
        if (connection_write(connection, data, len) == len)
                return ERROR_OK;
+
+       LOG_WARNING("Error writing to GDB socket. Dropping the connection.");
        gdb_con->closed = true;
        return ERROR_SERVER_REMOTE_CLOSED;
 }
 
+static void gdb_log_incoming_packet(char *packet)
+{
+       if (!LOG_LEVEL_IS(LOG_LVL_DEBUG))
+               return;
+
+       /* Avoid dumping non-printable characters to the terminal */
+       const unsigned packet_len = strlen(packet);
+       const char *nonprint = find_nonprint_char(packet, packet_len);
+       if (nonprint) {
+               /* Does packet at least have a prefix that is printable?
+                * Look within the first 50 chars of the packet. */
+               const char *colon = memchr(packet, ':', MIN(50, packet_len));
+               const bool packet_has_prefix = (colon);
+               const bool packet_prefix_printable = (packet_has_prefix && nonprint > colon);
+
+               if (packet_prefix_printable) {
+                       const unsigned int prefix_len = colon - packet + 1;  /* + 1 to include the ':' */
+                       const unsigned int payload_len = packet_len - prefix_len;
+                       LOG_DEBUG("received packet: %.*s<binary-data-%u-bytes>", prefix_len, packet, payload_len);
+               } else {
+                       LOG_DEBUG("received packet: <binary-data-%u-bytes>", packet_len);
+               }
+       } else {
+               /* All chars printable, dump the packet as is */
+               LOG_DEBUG("received packet: %s", packet);
+       }
+}
+
+static void gdb_log_outgoing_packet(char *packet_buf, unsigned int packet_len, unsigned char checksum)
+{
+       if (!LOG_LEVEL_IS(LOG_LVL_DEBUG))
+               return;
+
+       if (find_nonprint_char(packet_buf, packet_len))
+               LOG_DEBUG("sending packet: $<binary-data-%u-bytes>#%2.2x", packet_len, checksum);
+       else
+               LOG_DEBUG("sending packet: $%.*s#%2.2x'", packet_len, packet_buf, checksum);
+}
+
 static int gdb_put_packet_inner(struct connection *connection,
                char *buffer, int len)
 {
        int i;
        unsigned char my_checksum = 0;
-#ifdef _DEBUG_GDB_IO_
-       char *debug_buffer;
-#endif
        int reply;
        int retval;
        struct gdb_connection *gdb_con = connection->priv;
@@ -400,11 +441,7 @@ static int gdb_put_packet_inner(struct connection *connection,
 #endif
 
        while (1) {
-#ifdef _DEBUG_GDB_IO_
-               debug_buffer = strndup(buffer, len);
-               LOG_DEBUG("sending packet '$%s#%2.2x'", debug_buffer, my_checksum);
-               free(debug_buffer);
-#endif
+               gdb_log_outgoing_packet(buffer, len, my_checksum);
 
                char local_buffer[1024];
                local_buffer[0] = '$';
@@ -705,7 +742,7 @@ static int gdb_output_con(struct connection *connection, const char *line)
        bin_size = strlen(line);
 
        hex_buffer = malloc(bin_size * 2 + 2);
-       if (hex_buffer == NULL)
+       if (!hex_buffer)
                return ERROR_GDB_BUFFER_TOO_SMALL;
 
        hex_buffer[0] = 'O';
@@ -728,7 +765,7 @@ static void gdb_signal_reply(struct target *target, struct connection *connectio
 {
        struct gdb_connection *gdb_connection = connection->priv;
        char sig_reply[65];
-       char stop_reason[20];
+       char stop_reason[32];
        char current_thread[25];
        int sig_reply_len;
        int signal_var;
@@ -739,7 +776,7 @@ static void gdb_signal_reply(struct target *target, struct connection *connectio
                sig_reply_len = snprintf(sig_reply, sizeof(sig_reply), "W00");
        } else {
                struct target *ct;
-               if (target->rtos != NULL) {
+               if (target->rtos) {
                        target->rtos->current_threadid = target->rtos->current_thread;
                        target->rtos->gdb_target_for_threadid(connection, target->rtos->current_threadid, &ct);
                } else {
@@ -778,7 +815,7 @@ static void gdb_signal_reply(struct target *target, struct connection *connectio
                }
 
                current_thread[0] = '\0';
-               if (target->rtos != NULL)
+               if (target->rtos)
                        snprintf(current_thread, sizeof(current_thread), "thread:%" PRIx64 ";",
                                        target->rtos->current_thread);
 
@@ -969,6 +1006,21 @@ static int gdb_new_connection(struct connection *connection)
        breakpoint_clear_target(target);
        watchpoint_clear_target(target);
 
+       /* Since version 3.95 (gdb-19990504), with the exclusion of 6.5~6.8, GDB
+        * sends an ACK at connection with the following comment in its source code:
+        * "Ack any packet which the remote side has already sent."
+        * LLDB does the same since the first gdb-remote implementation.
+        * Remove the initial ACK from the incoming buffer.
+        */
+       retval = gdb_get_char(connection, &initial_ack);
+       if (retval != ERROR_OK)
+               return retval;
+
+       if (initial_ack != '+')
+               gdb_putback_char(connection, initial_ack);
+
+       target_call_event_callbacks(target, TARGET_EVENT_GDB_ATTACH);
+
        if (target->rtos) {
                /* clean previous rtos session if supported*/
                if (target->rtos->type->clean)
@@ -978,18 +1030,6 @@ static int gdb_new_connection(struct connection *connection)
                rtos_update_threads(target);
        }
 
-       /* remove the initial ACK from the incoming buffer */
-       retval = gdb_get_char(connection, &initial_ack);
-       if (retval != ERROR_OK)
-               return retval;
-
-       /* FIX!!!??? would we actually ever receive a + here???
-        * Not observed.
-        */
-       if (initial_ack != '+')
-               gdb_putback_char(connection, initial_ack);
-       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.
                 *
@@ -1011,13 +1051,24 @@ static int gdb_new_connection(struct connection *connection)
        }
 
        gdb_actual_connections++;
-       log_printf_lf(all_targets->next != NULL ? LOG_LVL_INFO : LOG_LVL_DEBUG,
+       log_printf_lf(all_targets->next ? LOG_LVL_INFO : LOG_LVL_DEBUG,
                        __FILE__, __LINE__, __func__,
                        "New GDB Connection: %d, Target %s, state: %s",
                        gdb_actual_connections,
                        target_name(target),
                        target_state_name(target));
 
+       if (!target_was_examined(target)) {
+               LOG_ERROR("Target %s not examined yet, refuse gdb connection %d!",
+                                 target_name(target), gdb_actual_connections);
+               gdb_actual_connections--;
+               return ERROR_TARGET_NOT_EXAMINED;
+       }
+
+       if (target->state != TARGET_HALTED)
+               LOG_WARNING("GDB connection %d on target %s not halted",
+                                       gdb_actual_connections, target_name(target));
+
        /* DANGER! If we fail subsequently, we must remove this handler,
         * otherwise we occasionally see crashes as the timer can invoke the
         * callback fn.
@@ -1056,11 +1107,8 @@ 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, target);
 
-       if (connection->priv) {
-               free(connection->priv);
-               connection->priv = NULL;
-       } else
-               LOG_ERROR("BUG: connection->priv == NULL");
+       free(connection->priv);
+       connection->priv = NULL;
 
        target_unregister_event_callback(gdb_target_callback_event_handler, connection);
 
@@ -1172,7 +1220,7 @@ static int gdb_get_registers_packet(struct connection *connection,
        LOG_DEBUG("-");
 #endif
 
-       if ((target->rtos != NULL) && (ERROR_OK == rtos_get_gdb_reg_list(connection)))
+       if ((target->rtos) && (rtos_get_gdb_reg_list(connection) == ERROR_OK))
                return ERROR_OK;
 
        retval = target_get_gdb_reg_list(target, &reg_list, &reg_list_size,
@@ -1181,7 +1229,7 @@ static int gdb_get_registers_packet(struct connection *connection,
                return gdb_error(connection, retval);
 
        for (i = 0; i < reg_list_size; i++) {
-               if (reg_list[i] == NULL || reg_list[i]->exist == false)
+               if (!reg_list[i] || reg_list[i]->exist == false || reg_list[i]->hidden)
                        continue;
                reg_packet_size += DIV_ROUND_UP(reg_list[i]->size, 8) * 2;
        }
@@ -1189,13 +1237,13 @@ static int gdb_get_registers_packet(struct connection *connection,
        assert(reg_packet_size > 0);
 
        reg_packet = malloc(reg_packet_size + 1); /* plus one for string termination null */
-       if (reg_packet == NULL)
+       if (!reg_packet)
                return ERROR_FAIL;
 
        reg_packet_p = reg_packet;
 
        for (i = 0; i < reg_list_size; i++) {
-               if (reg_list[i] == NULL || reg_list[i]->exist == false)
+               if (!reg_list[i] || reg_list[i]->exist == false || reg_list[i]->hidden)
                        continue;
                if (!reg_list[i]->valid) {
                        retval = reg_list[i]->type->get(reg_list[i]);
@@ -1302,7 +1350,7 @@ static int gdb_get_register_packet(struct connection *connection,
        LOG_DEBUG("-");
 #endif
 
-       if ((target->rtos != NULL) && (ERROR_OK == rtos_get_gdb_reg(connection, reg_num)))
+       if ((target->rtos) && (rtos_get_gdb_reg(connection, reg_num) == ERROR_OK))
                return ERROR_OK;
 
        retval = target_get_gdb_reg_list_noread(target, &reg_list, &reg_list_size,
@@ -1311,7 +1359,7 @@ static int gdb_get_register_packet(struct connection *connection,
                return gdb_error(connection, retval);
 
        if (reg_list_size <= reg_num) {
-               LOG_ERROR("gdb requested a non-existing register");
+               LOG_ERROR("gdb requested a non-existing register (reg_num=%d)", reg_num);
                return ERROR_SERVER_REMOTE_CLOSED;
        }
 
@@ -1324,7 +1372,7 @@ static int gdb_get_register_packet(struct connection *connection,
                }
        }
 
-       reg_packet = malloc(DIV_ROUND_UP(reg_list[reg_num]->size, 8) * 2 + 1); /* plus one for string termination null */
+       reg_packet = calloc(DIV_ROUND_UP(reg_list[reg_num]->size, 8) * 2 + 1, 1); /* plus one for string termination null */
 
        gdb_str_to_target(target, reg_packet, reg_list[reg_num]);
 
@@ -1358,8 +1406,8 @@ static int gdb_set_register_packet(struct connection *connection,
        uint8_t *bin_buf = malloc(chars / 2);
        gdb_target_to_reg(target, separator + 1, chars, bin_buf);
 
-       if ((target->rtos != NULL) &&
-                       (ERROR_OK == rtos_set_reg(connection, reg_num, bin_buf))) {
+       if ((target->rtos) &&
+                       (rtos_set_reg(connection, reg_num, bin_buf) == ERROR_OK)) {
                free(bin_buf);
                gdb_put_packet(connection, "OK", 2);
                return ERROR_OK;
@@ -1373,15 +1421,15 @@ static int gdb_set_register_packet(struct connection *connection,
        }
 
        if (reg_list_size <= reg_num) {
-               LOG_ERROR("gdb requested a non-existing register");
+               LOG_ERROR("gdb requested a non-existing register (reg_num=%d)", reg_num);
                free(bin_buf);
                free(reg_list);
                return ERROR_SERVER_REMOTE_CLOSED;
        }
 
        if (chars != (DIV_ROUND_UP(reg_list[reg_num]->size, 8) * 2)) {
-               LOG_ERROR("gdb sent %d bits for a %d-bit register (%s)",
-                               (int) chars * 4, reg_list[reg_num]->size, reg_list[reg_num]->name);
+               LOG_ERROR("gdb sent %zu bits for a %" PRIu32 "-bit register (%s)",
+                               chars * 4, reg_list[reg_num]->size, reg_list[reg_num]->name);
                free(bin_buf);
                free(reg_list);
                return ERROR_SERVER_REMOTE_CLOSED;
@@ -1454,7 +1502,11 @@ static int gdb_read_memory_packet(struct connection *connection,
 
        LOG_DEBUG("addr: 0x%16.16" PRIx64 ", len: 0x%8.8" PRIx32 "", addr, len);
 
-       retval = target_read_buffer(target, addr, len, buffer);
+       retval = ERROR_NOT_IMPLEMENTED;
+       if (target->rtos)
+               retval = rtos_read_buffer(target, addr, len, buffer);
+       if (retval == ERROR_NOT_IMPLEMENTED)
+               retval = target_read_buffer(target, addr, len, buffer);
 
        if ((retval != ERROR_OK) && !gdb_report_data_abort) {
                /* TODO : Here we have to lie and send back all zero's lest stack traces won't work.
@@ -1525,7 +1577,11 @@ static int gdb_write_memory_packet(struct connection *connection,
        if (unhexify(buffer, separator, len) != len)
                LOG_ERROR("unable to decode memory packet");
 
-       retval = target_write_buffer(target, addr, len, buffer);
+       retval = ERROR_NOT_IMPLEMENTED;
+       if (target->rtos)
+               retval = rtos_write_buffer(target, addr, len, buffer);
+       if (retval == ERROR_NOT_IMPLEMENTED)
+               retval = target_write_buffer(target, addr, len, buffer);
 
        if (retval == ERROR_OK)
                gdb_put_packet(connection, "OK", 2);
@@ -1594,7 +1650,12 @@ static int gdb_write_memory_binary_packet(struct connection *connection,
        if (len) {
                LOG_DEBUG("addr: 0x%" PRIx64 ", len: 0x%8.8" PRIx32 "", addr, len);
 
-               retval = target_write_buffer(target, addr, len, (uint8_t *)separator);
+               retval = ERROR_NOT_IMPLEMENTED;
+               if (target->rtos)
+                       retval = rtos_write_buffer(target, addr, len, (uint8_t *)separator);
+               if (retval == ERROR_NOT_IMPLEMENTED)
+                       retval = target_write_buffer(target, addr, len, (uint8_t *)separator);
+
                if (retval != ERROR_OK)
                        gdb_connection->mem_write_error = true;
        }
@@ -1739,16 +1800,15 @@ static __attribute__ ((format (PRINTF_ATTRIBUTE_FORMAT, 5, 6))) void xml_printf(
        int first = 1;
 
        for (;; ) {
-               if ((*xml == NULL) || (!first)) {
+               if ((!*xml) || (!first)) {
                        /* start by 0 to exercise all the code paths.
                         * Need minimum 2 bytes to fit 1 char and 0 terminator. */
 
                        *size = *size * 2 + 2;
                        char *t = *xml;
                        *xml = realloc(*xml, *size);
-                       if (*xml == NULL) {
-                               if (t)
-                                       free(t);
+                       if (!*xml) {
+                               free(t);
                                *retval = ERROR_SERVER_REMOTE_CLOSED;
                                return;
                        }
@@ -1772,7 +1832,7 @@ static int decode_xfer_read(char const *buf, char **annex, int *ofs, unsigned in
 {
        /* Locate the annex. */
        const char *annex_end = strchr(buf, ':');
-       if (annex_end == NULL)
+       if (!annex_end)
                return ERROR_FAIL;
 
        /* After the read marker and annex, qXfer looks like a
@@ -1786,9 +1846,9 @@ static int decode_xfer_read(char const *buf, char **annex, int *ofs, unsigned in
        *len = strtoul(separator + 1, NULL, 16);
 
        /* Extract the annex if needed */
-       if (annex != NULL) {
+       if (annex) {
                *annex = strndup(buf, annex_end - buf);
-               if (*annex == NULL)
+               if (!*annex)
                        return ERROR_FAIL;
        }
 
@@ -2007,7 +2067,7 @@ static int lookup_add_arch_defined_types(char const **arch_defined_types_list[],
 {
        int tbl_sz = *num_arch_defined_types;
 
-       if (type_id != NULL && (strcmp(type_id, ""))) {
+       if (type_id && (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;
@@ -2043,14 +2103,14 @@ static int gdb_generate_reg_type_description(struct target *target,
                }
                /* <vector id="id" type="type" count="count"/> */
                xml_printf(&retval, tdesc, pos, size,
-                               "<vector id=\"%s\" type=\"%s\" count=\"%d\"/>\n",
+                               "<vector id=\"%s\" type=\"%s\" count=\"%" PRIu32 "\"/>\n",
                                type->id, type->reg_type_vector->type->id,
                                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) {
+               while (field) {
                        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,
@@ -2070,7 +2130,7 @@ static int gdb_generate_reg_type_description(struct target *target,
                                type->id);
 
                field = type->reg_type_union->fields;
-               while (field != NULL) {
+               while (field) {
                        xml_printf(&retval, tdesc, pos, size,
                                        "<field name=\"%s\" type=\"%s\"/>\n",
                                        field->name, field->type->id);
@@ -2090,18 +2150,18 @@ static int gdb_generate_reg_type_description(struct target *target,
                         *  <field name="name" start="start" end="end"/> ...
                         * </struct> */
                        xml_printf(&retval, tdesc, pos, size,
-                                       "<struct id=\"%s\" size=\"%d\">\n",
+                                       "<struct id=\"%s\" size=\"%" PRIu32 "\">\n",
                                        type->id, type->reg_type_struct->size);
-                       while (field != NULL) {
+                       while (field) {
                                xml_printf(&retval, tdesc, pos, size,
-                                               "<field name=\"%s\" start=\"%d\" end=\"%d\" type=\"%s\" />\n",
+                                               "<field name=\"%s\" start=\"%" PRIu32 "\" end=\"%" PRIu32 "\" 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) {
+                       while (field) {
                                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,
@@ -2118,7 +2178,7 @@ static int gdb_generate_reg_type_description(struct target *target,
                        xml_printf(&retval, tdesc, pos, size,
                                        "<struct id=\"%s\">\n",
                                        type->id);
-                       while (field != NULL) {
+                       while (field) {
                                xml_printf(&retval, tdesc, pos, size,
                                                "<field name=\"%s\" type=\"%s\"/>\n",
                                                field->name, field->type->id);
@@ -2135,14 +2195,14 @@ static int gdb_generate_reg_type_description(struct target *target,
                 *  <field name="name" start="start" end="end"/> ...
                 * </flags> */
                xml_printf(&retval, tdesc, pos, size,
-                               "<flags id=\"%s\" size=\"%d\">\n",
+                               "<flags id=\"%s\" size=\"%" PRIu32 "\">\n",
                                type->id, type->reg_type_flags->size);
 
                struct reg_data_type_flags_field *field;
                field = type->reg_type_flags->fields;
-               while (field != NULL) {
+               while (field) {
                        xml_printf(&retval, tdesc, pos, size,
-                                       "<field name=\"%s\" start=\"%d\" end=\"%d\" type=\"%s\" />\n",
+                                       "<field name=\"%s\" start=\"%" PRIu32 "\" end=\"%" PRIu32 "\" type=\"%s\" />\n",
                                        field->name, field->bitfield->start, field->bitfield->end,
                                        gdb_get_reg_type_name(field->bitfield->type));
 
@@ -2169,11 +2229,11 @@ static int get_reg_features_list(struct target *target, char const **feature_lis
        *feature_list = calloc(1, sizeof(char *));
 
        for (int i = 0; i < reg_list_size; i++) {
-               if (reg_list[i]->exist == false)
+               if (reg_list[i]->exist == false || reg_list[i]->hidden)
                        continue;
 
-               if (reg_list[i]->feature != NULL
-                       && reg_list[i]->feature->name != NULL
+               if (reg_list[i]->feature
+                       && reg_list[i]->feature->name
                        && (strcmp(reg_list[i]->feature->name, ""))) {
                        /* We found a feature, check if the feature is already in the
                         * table. If not, allocate a new entry for the table and
@@ -2199,6 +2259,108 @@ static int get_reg_features_list(struct target *target, char const **feature_lis
        return ERROR_OK;
 }
 
+/* Create a register list that's the union of all the registers of the SMP
+ * group this target is in. If the target is not part of an SMP group, this
+ * returns the same as target_get_gdb_reg_list_noread().
+ */
+static int smp_reg_list_noread(struct target *target,
+               struct reg **combined_list[], int *combined_list_size,
+               enum target_register_class reg_class)
+{
+       if (!target->smp)
+               return target_get_gdb_reg_list_noread(target, combined_list,
+                               combined_list_size, REG_CLASS_ALL);
+
+       unsigned int combined_allocated = 256;
+       *combined_list = malloc(combined_allocated * sizeof(struct reg *));
+       if (*combined_list == NULL) {
+               LOG_ERROR("malloc(%zu) failed", combined_allocated * sizeof(struct reg *));
+               return ERROR_FAIL;
+       }
+       *combined_list_size = 0;
+
+       struct target_list *head;
+       foreach_smp_target(head, target->head) {
+               struct reg **reg_list = NULL;
+               int reg_list_size;
+               int result = target_get_gdb_reg_list_noread(head->target, &reg_list,
+                               &reg_list_size, reg_class);
+               if (result != ERROR_OK) {
+                       free(*combined_list);
+                       return result;
+               }
+               for (int i = 0; i < reg_list_size; i++) {
+                       bool found = false;
+                       struct reg *a = reg_list[i];
+                       if (a->exist) {
+                               /* Nested loop makes this O(n^2), but this entire function with
+                                * 5 RISC-V targets takes just 2ms on my computer. Fast enough
+                                * for me. */
+                               for (int j = 0; j < *combined_list_size; j++) {
+                                       struct reg *b = (*combined_list)[j];
+                                       if (!strcmp(a->name, b->name)) {
+                                               found = true;
+                                               if (a->size != b->size) {
+                                                       LOG_ERROR("SMP register %s is %d bits on one "
+                                                                       "target, but %d bits on another target.",
+                                                                       a->name, a->size, b->size);
+                                                       free(reg_list);
+                                                       free(*combined_list);
+                                                       return ERROR_FAIL;
+                                               }
+                                               break;
+                                       }
+                               }
+                               if (!found) {
+                                       LOG_DEBUG("[%s] %s not found in combined list", target_name(target), a->name);
+                                       if (*combined_list_size >= (int) combined_allocated) {
+                                               combined_allocated *= 2;
+                                               *combined_list = realloc(*combined_list, combined_allocated * sizeof(struct reg *));
+                                               if (*combined_list == NULL) {
+                                                       LOG_ERROR("realloc(%zu) failed", combined_allocated * sizeof(struct reg *));
+                                                       return ERROR_FAIL;
+                                               }
+                                       }
+                                       (*combined_list)[*combined_list_size] = a;
+                                       (*combined_list_size)++;
+                               }
+                       }
+               }
+               free(reg_list);
+       }
+
+       /* Now warn the user about any registers that weren't found in every target. */
+       foreach_smp_target(head, target->head) {
+               struct reg **reg_list = NULL;
+               int reg_list_size;
+               int result = target_get_gdb_reg_list_noread(head->target, &reg_list,
+                               &reg_list_size, reg_class);
+               if (result != ERROR_OK) {
+                       free(*combined_list);
+                       return result;
+               }
+               for (int i = 0; i < *combined_list_size; i++) {
+                       bool found = false;
+                       struct reg *a = (*combined_list)[i];
+                       for (int j = 0; j < reg_list_size; j++) {
+                               struct reg *b = reg_list[j];
+                               if (b->exist && !strcmp(a->name, b->name)) {
+                                       found = true;
+                                       break;
+                               }
+                       }
+                       if (!found) {
+                               LOG_WARNING("Register %s does not exist in %s, which is part of an SMP group where "
+                                           "this register does exist.",
+                                           a->name, target_name(head->target));
+                       }
+               }
+               free(reg_list);
+       }
+
+       return ERROR_OK;
+}
+
 static int gdb_generate_target_description(struct target *target, char **tdesc_out)
 {
        int retval = ERROR_OK;
@@ -2212,8 +2374,8 @@ static int gdb_generate_target_description(struct target *target, char **tdesc_o
        int size = 0;
 
 
-       retval = target_get_gdb_reg_list_noread(target, &reg_list,
-                       &reg_list_size, REG_CLASS_ALL);
+       retval = smp_reg_list_noread(target, &reg_list, &reg_list_size,
+                       REG_CLASS_ALL);
 
        if (retval != ERROR_OK) {
                LOG_ERROR("get register list failed");
@@ -2245,12 +2407,12 @@ static int gdb_generate_target_description(struct target *target, char **tdesc_o
 
        /* generate architecture element if supported by target */
        architecture = target_get_gdb_arch(target);
-       if (architecture != NULL)
+       if (architecture)
                xml_printf(&retval, &tdesc, &pos, &size,
                                "<architecture>%s</architecture>\n", architecture);
 
        /* generate target description according to register list */
-       if (features != NULL) {
+       if (features) {
                while (features[current_feature]) {
                        char const **arch_defined_types = NULL;
                        int num_arch_defined_types = 0;
@@ -2263,14 +2425,14 @@ static int gdb_generate_target_description(struct target *target, char **tdesc_o
                        int i;
                        for (i = 0; i < reg_list_size; i++) {
 
-                               if (reg_list[i]->exist == false)
+                               if (reg_list[i]->exist == false || reg_list[i]->hidden)
                                        continue;
 
                                if (strcmp(reg_list[i]->feature->name, features[current_feature]))
                                        continue;
 
                                const char *type_str;
-                               if (reg_list[i]->reg_data_type != NULL) {
+                               if (reg_list[i]->reg_data_type) {
                                        if (reg_list[i]->reg_data_type->type == REG_TYPE_ARCH_DEFINED) {
                                                /* generate <type... first, if there are architecture-defined types. */
                                                if (lookup_add_arch_defined_types(&arch_defined_types,
@@ -2295,9 +2457,9 @@ static int gdb_generate_target_description(struct target *target, char **tdesc_o
                                xml_printf(&retval, &tdesc, &pos, &size,
                                                "<reg name=\"%s\"", reg_list[i]->name);
                                xml_printf(&retval, &tdesc, &pos, &size,
-                                               " bitsize=\"%d\"", reg_list[i]->size);
+                                               " bitsize=\"%" PRIu32 "\"", reg_list[i]->size);
                                xml_printf(&retval, &tdesc, &pos, &size,
-                                               " regnum=\"%d\"", reg_list[i]->number);
+                                               " regnum=\"%" PRIu32 "\"", reg_list[i]->number);
                                if (reg_list[i]->caller_save)
                                        xml_printf(&retval, &tdesc, &pos, &size,
                                                        " save-restore=\"yes\"");
@@ -2308,7 +2470,7 @@ static int gdb_generate_target_description(struct target *target, char **tdesc_o
                                xml_printf(&retval, &tdesc, &pos, &size,
                                                " type=\"%s\"", type_str);
 
-                               if (reg_list[i]->group != NULL)
+                               if (reg_list[i]->group)
                                        xml_printf(&retval, &tdesc, &pos, &size,
                                                        " group=\"%s\"", reg_list[i]->group);
 
@@ -2342,7 +2504,7 @@ error:
 static int gdb_get_target_description_chunk(struct target *target, struct target_desc_format *target_desc,
                char **chunk, int32_t offset, uint32_t length)
 {
-       if (target_desc == NULL) {
+       if (!target_desc) {
                LOG_ERROR("Unable to Generate Target Description");
                return ERROR_FAIL;
        }
@@ -2350,7 +2512,7 @@ static int gdb_get_target_description_chunk(struct target *target, struct target
        char *tdesc = target_desc->tdesc;
        uint32_t tdesc_length = target_desc->tdesc_length;
 
-       if (tdesc == NULL) {
+       if (!tdesc) {
                int retval = gdb_generate_target_description(target, &tdesc);
                if (retval != ERROR_OK) {
                        LOG_ERROR("Unable to Generate Target Description");
@@ -2368,7 +2530,7 @@ static int gdb_get_target_description_chunk(struct target *target, struct target
                transfer_type = 'l';
 
        *chunk = malloc(length + 2);
-       if (*chunk == NULL) {
+       if (!*chunk) {
                LOG_ERROR("Unable to allocate memory");
                return ERROR_FAIL;
        }
@@ -2450,7 +2612,7 @@ static int gdb_generate_thread_list(struct target *target, char **thread_list_ou
                   "<?xml version=\"1.0\"?>\n"
                   "<threads>\n");
 
-       if (rtos != NULL) {
+       if (rtos) {
                for (int i = 0; i < rtos->thread_count; i++) {
                        struct thread_detail *thread_detail = &rtos->thread_details[i];
 
@@ -2460,12 +2622,12 @@ static int gdb_generate_thread_list(struct target *target, char **thread_list_ou
                        xml_printf(&retval, &thread_list, &pos, &size,
                                   "<thread id=\"%" PRIx64 "\">", thread_detail->threadid);
 
-                       if (thread_detail->thread_name_str != NULL)
+                       if (thread_detail->thread_name_str)
                                xml_printf(&retval, &thread_list, &pos, &size,
                                           "Name: %s", thread_detail->thread_name_str);
 
-                       if (thread_detail->extra_info_str != NULL) {
-                               if (thread_detail->thread_name_str != NULL)
+                       if (thread_detail->extra_info_str) {
+                               if (thread_detail->thread_name_str)
                                        xml_printf(&retval, &thread_list, &pos, &size,
                                                   ", ");
                                xml_printf(&retval, &thread_list, &pos, &size,
@@ -2491,7 +2653,7 @@ static int gdb_generate_thread_list(struct target *target, char **thread_list_ou
 static int gdb_get_thread_list_chunk(struct target *target, char **thread_list,
                char **chunk, int32_t offset, uint32_t length)
 {
-       if (*thread_list == NULL) {
+       if (!*thread_list) {
                int retval = gdb_generate_thread_list(target, thread_list);
                if (retval != ERROR_OK) {
                        LOG_ERROR("Unable to Generate Thread List");
@@ -2509,11 +2671,11 @@ static int gdb_get_thread_list_chunk(struct target *target, char **thread_list,
                transfer_type = 'l';
 
        *chunk = malloc(length + 2 + 3);
-    /* Allocating extra 3 bytes prevents false positive valgrind report
+       /* 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) {
+       if (!*chunk) {
                LOG_ERROR("Unable to allocate memory");
                return ERROR_FAIL;
        }
@@ -2718,7 +2880,7 @@ static bool gdb_handle_vcont_packet(struct connection *connection, const char *p
 
        /* query for vCont supported */
        if (parse[0] == '?') {
-               if (target->type->step != NULL) {
+               if (target->type->step) {
                        /* gdb doesn't accept c without C and s without S */
                        gdb_put_packet(connection, "vCont;c;C;s;S", 13);
                        return true;
@@ -2773,12 +2935,12 @@ static bool gdb_handle_vcont_packet(struct connection *connection, const char *p
                        packet_size -= 2;
 
                        thread_id = strtoll(parse, &endp, 16);
-                       if (endp != NULL) {
+                       if (endp) {
                                packet_size -= endp - parse;
                                parse = endp;
                        }
 
-                       if (target->rtos != NULL) {
+                       if (target->rtos) {
                                /* FIXME: why is this necessary? rtos state should be up-to-date here already! */
                                rtos_update_threads(target);
 
@@ -2896,7 +3058,7 @@ static char *next_hex_encoded_field(const char **str, char sep)
                return NULL;
 
        const char *end = strchr(hex, sep);
-       if (end == NULL)
+       if (!end)
                hexlen = strlen(hex);
        else
                hexlen = end - hex;
@@ -2909,7 +3071,7 @@ static char *next_hex_encoded_field(const char **str, char sep)
 
        size_t count = hexlen / 2;
        char *decoded = malloc(count + 1);
-       if (decoded == NULL)
+       if (!decoded)
                return NULL;
 
        size_t converted = unhexify((void *)decoded, hex, count);
@@ -2954,16 +3116,18 @@ static bool gdb_handle_vrun_packet(struct connection *connection, const char *pa
        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) {
+       while (cmdline) {
+               char *arg = next_hex_encoded_field(&parse, ';');
+               if (!arg)
+                       break;
                char *new_cmdline = alloc_printf("%s %s", cmdline, arg);
                free(cmdline);
                free(arg);
                cmdline = new_cmdline;
        }
 
-       if (cmdline != NULL) {
-               if (target->semihosting != NULL) {
+       if (cmdline) {
+               if (target->semihosting) {
                        LOG_INFO("GDB set inferior command line to '%s'", cmdline);
                        free(target->semihosting->cmdline);
                        target->semihosting->cmdline = cmdline;
@@ -3090,7 +3254,7 @@ static int gdb_v_packet(struct connection *connection,
                length = packet_size - (parse - packet);
 
                /* create a new image if there isn't already one */
-               if (gdb_connection->vflash_image == NULL) {
+               if (!gdb_connection->vflash_image) {
                        gdb_connection->vflash_image = malloc(sizeof(struct image));
                        image_open(gdb_connection->vflash_image, "", "build");
                }
@@ -3252,18 +3416,7 @@ static int gdb_input_inner(struct connection *connection)
                /* terminate with zero */
                gdb_packet_buffer[packet_size] = '\0';
 
-               if (LOG_LEVEL_IS(LOG_LVL_DEBUG)) {
-                       if (packet[0] == 'X') {
-                               /* binary packets spew junk into the debug log stream */
-                               char buf[50];
-                               int x;
-                               for (x = 0; (x < 49) && (packet[x] != ':'); x++)
-                                       buf[x] = packet[x];
-                               buf[x] = 0;
-                               LOG_DEBUG("received packet: '%s:<binary-data>'", buf);
-                       } else
-                               LOG_DEBUG("received packet: '%s'", packet);
-               }
+               gdb_log_incoming_packet(gdb_packet_buffer);
 
                if (packet_size > 0) {
                        retval = ERROR_OK;
@@ -3308,7 +3461,7 @@ static int gdb_input_inner(struct connection *connection)
                                        /* '?' is sent after the eventual '!' */
                                        if (!warn_use_ext && !gdb_con->extended_protocol) {
                                                warn_use_ext = true;
-                                               LOG_WARNING("Prefer GDB command \"target extended-remote %s\" instead of \"target remote %s\"",
+                                               LOG_WARNING("Prefer GDB command \"target extended-remote :%s\" instead of \"target remote :%s\"",
                                                                        connection->service->port, connection->service->port);
                                        }
                                        break;
@@ -3490,7 +3643,7 @@ static int gdb_target_start(struct target *target, const char *port)
        int ret;
        gdb_service = malloc(sizeof(struct gdb_service));
 
-       if (NULL == gdb_service)
+       if (!gdb_service)
                return -ENOMEM;
 
        LOG_INFO("starting gdb server for %s on %s", target_name(target), port);
@@ -3501,14 +3654,14 @@ static int gdb_target_start(struct target *target, const char *port)
        target->gdb_service = gdb_service;
 
        ret = add_service("gdb",
-                       port, 1, &gdb_new_connection, &gdb_input,
+                       port, target->gdb_max_connections, &gdb_new_connection, &gdb_input,
                        &gdb_connection_closed, gdb_service);
        /* initialize all targets gdb service with the same pointer */
        {
                struct target_list *head;
                struct target *curr;
                head = target->head;
-               while (head != (struct target_list *)NULL) {
+               while (head) {
                        curr = head->target;
                        if (curr != target)
                                curr->gdb_service = gdb_service;
@@ -3574,14 +3727,14 @@ static int gdb_target_add_one(struct target *target)
 
 int gdb_target_add_all(struct target *target)
 {
-       if (NULL == target) {
+       if (!target) {
                LOG_WARNING("gdb services need one or more targets defined");
                return ERROR_OK;
        }
 
-       while (NULL != target) {
+       while (target) {
                int retval = gdb_target_add_one(target);
-               if (ERROR_OK != retval)
+               if (retval != ERROR_OK)
                        return retval;
 
                target = target->next;
@@ -3595,7 +3748,7 @@ COMMAND_HANDLER(handle_gdb_sync_command)
        if (CMD_ARGC != 0)
                return ERROR_COMMAND_SYNTAX_ERROR;
 
-       if (current_gdb_connection == NULL) {
+       if (!current_gdb_connection) {
                command_print(CMD,
                        "gdb_sync command can only be run from within gdb using \"monitor gdb_sync\"");
                return ERROR_FAIL;
@@ -3610,7 +3763,7 @@ COMMAND_HANDLER(handle_gdb_sync_command)
 COMMAND_HANDLER(handle_gdb_port_command)
 {
        int retval = CALL_COMMAND_HANDLER(server_pipe_command, &gdb_port);
-       if (ERROR_OK == retval) {
+       if (retval == ERROR_OK) {
                free(gdb_port_next);
                gdb_port_next = strdup(gdb_port);
        }
@@ -3704,7 +3857,7 @@ COMMAND_HANDLER(handle_gdb_save_tdesc_command)
        size_t size_written;
 
        char *tdesc_filename = alloc_printf("%s.xml", target_type_name(target));
-       if (tdesc_filename == NULL) {
+       if (!tdesc_filename) {
                retval = ERROR_FAIL;
                goto out;
        }

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)