keep-alive: drop link with log framework
[openocd.git] / src / server / gdb_server.c
index d0586d1706e89ded317c5845ab2e180efe1a3528..f5736196eddfb4717d389688d631c1e76f31bceb 100644 (file)
  * found in most modern embedded processors.
  */
 
+enum gdb_output_flag {
+       /* GDB doesn't accept 'O' packets */
+       GDB_OUTPUT_NO,
+       /* GDB accepts 'O' packets */
+       GDB_OUTPUT_ALL,
+};
+
 struct target_desc_format {
        char *tdesc;
        uint32_t tdesc_length;
@@ -97,6 +104,8 @@ struct gdb_connection {
        struct target_desc_format target_desc;
        /* temporarily used for thread list support */
        char *thread_list;
+       /* flag to mask the output from gdb_log_callback() */
+       enum gdb_output_flag output_flag;
 };
 
 #if 0
@@ -177,7 +186,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 +236,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,11 +358,15 @@ 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;
 }
@@ -369,7 +383,7 @@ static void gdb_log_incoming_packet(char *packet)
                /* 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 != NULL);
+               const bool packet_has_prefix = (colon);
                const bool packet_prefix_printable = (packet_has_prefix && nonprint > colon);
 
                if (packet_prefix_printable) {
@@ -473,7 +487,7 @@ static int gdb_put_packet_inner(struct connection *connection,
                        break;
                else if (reply == '-') {
                        /* Stop sending output packets for now */
-                       log_remove_callback(gdb_log_callback, connection);
+                       gdb_con->output_flag = GDB_OUTPUT_NO;
                        LOG_WARNING("negative reply, retrying");
                } else if (reply == 0x3) {
                        gdb_con->ctrl_c = true;
@@ -484,7 +498,7 @@ static int gdb_put_packet_inner(struct connection *connection,
                                break;
                        else if (reply == '-') {
                                /* Stop sending output packets for now */
-                               log_remove_callback(gdb_log_callback, connection);
+                               gdb_con->output_flag = GDB_OUTPUT_NO;
                                LOG_WARNING("negative reply, retrying");
                        } else if (reply == '$') {
                                LOG_ERROR("GDB missing ack(1) - assumed good");
@@ -737,7 +751,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';
@@ -771,7 +785,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 {
@@ -810,7 +824,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);
 
@@ -927,7 +941,7 @@ static void gdb_frontend_halted(struct target *target, struct connection *connec
         */
        if (gdb_connection->frontend_state == TARGET_RUNNING) {
                /* stop forwarding log packets! */
-               log_remove_callback(gdb_log_callback, connection);
+               gdb_connection->output_flag = GDB_OUTPUT_NO;
 
                /* check fileio first */
                if (target_get_gdb_fileio_info(target, target->fileio_info) == ERROR_OK)
@@ -987,6 +1001,7 @@ static int gdb_new_connection(struct connection *connection)
        gdb_connection->target_desc.tdesc = NULL;
        gdb_connection->target_desc.tdesc_length = 0;
        gdb_connection->thread_list = NULL;
+       gdb_connection->output_flag = GDB_OUTPUT_NO;
 
        /* send ACK to GDB for debug request */
        gdb_write(connection, "+", 1);
@@ -1001,16 +1016,19 @@ static int gdb_new_connection(struct connection *connection)
        breakpoint_clear_target(target);
        watchpoint_clear_target(target);
 
-       /* remove the initial ACK from the incoming buffer */
+       /* 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;
 
-       /* 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 (target->rtos) {
@@ -1043,7 +1061,7 @@ 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,
@@ -1068,6 +1086,8 @@ static int gdb_new_connection(struct connection *connection)
         * register callback to be informed about target events */
        target_register_event_callback(gdb_target_callback_event_handler, connection);
 
+       log_add_callback(gdb_log_callback, connection);
+
        return ERROR_OK;
 }
 
@@ -1212,7 +1232,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,
@@ -1221,7 +1241,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 || reg_list[i]->hidden)
+               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;
        }
@@ -1229,13 +1249,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 || reg_list[i]->hidden)
+               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]);
@@ -1342,7 +1362,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,
@@ -1351,7 +1371,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;
        }
 
@@ -1398,8 +1418,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;
@@ -1413,7 +1433,7 @@ 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;
@@ -1494,7 +1514,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.
@@ -1565,7 +1589,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);
@@ -1634,7 +1662,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;
        }
@@ -1779,14 +1812,14 @@ 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 (!*xml) {
                                free(t);
                                *retval = ERROR_SERVER_REMOTE_CLOSED;
                                return;
@@ -1811,7 +1844,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
@@ -1825,9 +1858,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;
        }
 
@@ -2046,7 +2079,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;
@@ -2089,7 +2122,7 @@ static int gdb_generate_reg_type_description(struct target *target,
        } 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,
@@ -2109,7 +2142,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);
@@ -2131,7 +2164,7 @@ static int gdb_generate_reg_type_description(struct target *target,
                        xml_printf(&retval, tdesc, pos, size,
                                        "<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=\"%" PRIu32 "\" end=\"%" PRIu32 "\" type=\"%s\" />\n",
                                                field->name, field->bitfield->start, field->bitfield->end,
@@ -2140,7 +2173,7 @@ static int gdb_generate_reg_type_description(struct target *target,
                                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,
@@ -2157,7 +2190,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);
@@ -2179,7 +2212,7 @@ static int gdb_generate_reg_type_description(struct target *target,
 
                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=\"%" PRIu32 "\" end=\"%" PRIu32 "\" type=\"%s\" />\n",
                                        field->name, field->bitfield->start, field->bitfield->end,
@@ -2211,8 +2244,8 @@ static int get_reg_features_list(struct target *target, char const **feature_lis
                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
@@ -2238,6 +2271,122 @@ 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;
+       struct reg **local_list = malloc(combined_allocated * sizeof(struct reg *));
+       if (!local_list) {
+               LOG_ERROR("malloc(%zu) failed", combined_allocated * sizeof(struct reg *));
+               return ERROR_FAIL;
+       }
+       unsigned int local_list_size = 0;
+
+       struct target_list *head;
+       foreach_smp_target(head, target->smp_targets) {
+               if (!target_was_examined(head->target))
+                       continue;
+
+               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(local_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 (unsigned int j = 0; j < local_list_size; j++) {
+                                       struct reg *b = local_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(local_list);
+                                                       return ERROR_FAIL;
+                                               }
+                                               break;
+                                       }
+                               }
+                               if (!found) {
+                                       LOG_DEBUG("[%s] %s not found in combined list", target_name(target), a->name);
+                                       if (local_list_size >= combined_allocated) {
+                                               combined_allocated *= 2;
+                                               local_list = realloc(local_list, combined_allocated * sizeof(struct reg *));
+                                               if (!local_list) {
+                                                       LOG_ERROR("realloc(%zu) failed", combined_allocated * sizeof(struct reg *));
+                                                       return ERROR_FAIL;
+                                               }
+                                       }
+                                       local_list[local_list_size] = a;
+                                       local_list_size++;
+                               }
+                       }
+               }
+               free(reg_list);
+       }
+
+       if (local_list_size == 0) {
+               LOG_ERROR("Unable to get register list");
+               free(local_list);
+               return ERROR_FAIL;
+       }
+
+       /* Now warn the user about any registers that weren't found in every target. */
+       foreach_smp_target(head, target->smp_targets) {
+               if (!target_was_examined(head->target))
+                       continue;
+
+               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(local_list);
+                       return result;
+               }
+               for (unsigned int i = 0; i < local_list_size; i++) {
+                       bool found = false;
+                       struct reg *a = local_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);
+       }
+
+       *combined_list = local_list;
+       *combined_list_size = local_list_size;
+       return ERROR_OK;
+}
+
 static int gdb_generate_target_description(struct target *target, char **tdesc_out)
 {
        int retval = ERROR_OK;
@@ -2251,8 +2400,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");
@@ -2284,12 +2433,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;
@@ -2309,7 +2458,7 @@ static int gdb_generate_target_description(struct target *target, char **tdesc_o
                                        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,
@@ -2347,7 +2496,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);
 
@@ -2381,7 +2530,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;
        }
@@ -2389,7 +2538,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");
@@ -2407,7 +2556,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;
        }
@@ -2489,22 +2638,28 @@ 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];
 
                        if (!thread_detail->exists)
                                continue;
 
-                       xml_printf(&retval, &thread_list, &pos, &size,
-                                  "<thread id=\"%" PRIx64 "\">", thread_detail->threadid);
+                       if (thread_detail->thread_name_str)
+                               xml_printf(&retval, &thread_list, &pos, &size,
+                                          "<thread id=\"%" PRIx64 "\" name=\"%s\">",
+                                          thread_detail->threadid,
+                                          thread_detail->thread_name_str);
+                       else
+                               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,
@@ -2530,7 +2685,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");
@@ -2552,7 +2707,7 @@ static int gdb_get_thread_list_chunk(struct target *target, char **thread_list,
         * 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;
        }
@@ -2585,7 +2740,7 @@ static int gdb_query_packet(struct connection *connection,
                        cmd[len] = 0;
 
                        /* We want to print all debug output to GDB connection */
-                       log_add_callback(gdb_log_callback, connection);
+                       gdb_connection->output_flag = GDB_OUTPUT_ALL;
                        target_call_timer_callbacks_now();
                        /* some commands need to know the GDB connection, make note of current
                         * GDB connection. */
@@ -2593,7 +2748,7 @@ static int gdb_query_packet(struct connection *connection,
                        command_run_line(cmd_ctx, cmd);
                        current_gdb_connection = NULL;
                        target_call_timer_callbacks_now();
-                       log_remove_callback(gdb_log_callback, connection);
+                       gdb_connection->output_flag = GDB_OUTPUT_NO;
                        free(cmd);
                }
                gdb_put_packet(connection, "OK", 2);
@@ -2757,7 +2912,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;
@@ -2774,7 +2929,7 @@ static bool gdb_handle_vcont_packet(struct connection *connection, const char *p
        if (parse[0] == 'c') {
                gdb_running_type = 'c';
                LOG_DEBUG("target %s continue", target_name(target));
-               log_add_callback(gdb_log_callback, connection);
+               gdb_connection->output_flag = GDB_OUTPUT_ALL;
                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));
@@ -2812,12 +2967,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);
 
@@ -2863,7 +3018,7 @@ static bool gdb_handle_vcont_packet(struct connection *connection, const char *p
                        }
 
                        LOG_DEBUG("target %s single-step thread %"PRIx64, target_name(ct), thread_id);
-                       log_add_callback(gdb_log_callback, connection);
+                       gdb_connection->output_flag = GDB_OUTPUT_ALL;
                        target_call_event_callbacks(ct, TARGET_EVENT_GDB_START);
 
                        /*
@@ -2884,7 +3039,7 @@ static bool gdb_handle_vcont_packet(struct connection *connection, const char *p
                                                                                 "T05thread:%016"PRIx64";", thread_id);
 
                                gdb_put_packet(connection, sig_reply, sig_reply_len);
-                               log_remove_callback(gdb_log_callback, connection);
+                               gdb_connection->output_flag = GDB_OUTPUT_NO;
 
                                return true;
                        }
@@ -2896,7 +3051,7 @@ static bool gdb_handle_vcont_packet(struct connection *connection, const char *p
                                        LOG_DEBUG("stepi ignored. GDB will now fetch the register state "
                                                                        "from the target.");
                                        gdb_sig_halted(connection);
-                                       log_remove_callback(gdb_log_callback, connection);
+                                       gdb_connection->output_flag = GDB_OUTPUT_NO;
                                } else
                                        gdb_connection->frontend_state = TARGET_RUNNING;
                                return true;
@@ -2914,7 +3069,7 @@ static bool gdb_handle_vcont_packet(struct connection *connection, const char *p
                                /* send back signal information */
                                gdb_signal_reply(ct, connection);
                                /* stop forwarding log packets! */
-                               log_remove_callback(gdb_log_callback, connection);
+                               gdb_connection->output_flag = GDB_OUTPUT_NO;
                        } else
                                gdb_connection->frontend_state = TARGET_RUNNING;
                } else {
@@ -2935,7 +3090,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;
@@ -2948,7 +3103,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);
@@ -2993,16 +3148,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;
@@ -3129,7 +3286,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");
                }
@@ -3242,6 +3399,10 @@ static void gdb_log_callback(void *priv, const char *file, unsigned line,
        struct connection *connection = priv;
        struct gdb_connection *gdb_con = connection->priv;
 
+       if (gdb_con->output_flag == GDB_OUTPUT_NO)
+               /* No out allowed */
+               return;
+
        if (gdb_con->busy) {
                /* do not reply this using the O packet */
                return;
@@ -3344,7 +3505,7 @@ static int gdb_input_inner(struct connection *connection)
                                case 's':
                                {
                                        gdb_thread_packet(connection, packet, packet_size);
-                                       log_add_callback(gdb_log_callback, connection);
+                                       gdb_con->output_flag = GDB_OUTPUT_ALL;
 
                                        if (gdb_con->mem_write_error) {
                                                LOG_ERROR("Memory write failure!");
@@ -3387,7 +3548,7 @@ static int gdb_input_inner(struct connection *connection)
                                                gdb_sig_halted(connection);
 
                                                /* stop forwarding log packets! */
-                                               log_remove_callback(gdb_log_callback, connection);
+                                               gdb_con->output_flag = GDB_OUTPUT_NO;
                                        } else {
                                                /* We're running/stepping, in which case we can
                                                 * forward log output until the target is halted
@@ -3459,7 +3620,7 @@ static int gdb_input_inner(struct connection *connection)
                                         * Fretcode,errno,Ctrl-C flag;call-specific attachment
                                         */
                                        gdb_con->frontend_state = TARGET_RUNNING;
-                                       log_add_callback(gdb_log_callback, connection);
+                                       gdb_con->output_flag = GDB_OUTPUT_ALL;
                                        gdb_fileio_response_packet(connection, packet, packet_size);
                                        break;
 
@@ -3512,13 +3673,44 @@ static int gdb_input(struct connection *connection)
        return ERROR_OK;
 }
 
+static void gdb_keep_client_alive(struct connection *connection)
+{
+       struct gdb_connection *gdb_con = connection->priv;
+
+       if (gdb_con->busy) {
+               /* do not send packets, retry asap */
+               return;
+       }
+
+       switch (gdb_con->output_flag) {
+       case GDB_OUTPUT_NO:
+               /* no need for keep-alive */
+               break;
+       case GDB_OUTPUT_ALL:
+               /* send an empty O packet */
+               gdb_output_con(connection, "");
+               break;
+       default:
+               break;
+       }
+}
+
+static const struct service_driver gdb_service_driver = {
+       .name = "gdb",
+       .new_connection_during_keep_alive_handler = NULL,
+       .new_connection_handler = gdb_new_connection,
+       .input_handler = gdb_input,
+       .connection_closed_handler = gdb_connection_closed,
+       .keep_client_alive_handler = gdb_keep_client_alive,
+};
+
 static int gdb_target_start(struct target *target, const char *port)
 {
        struct gdb_service *gdb_service;
        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);
@@ -3528,19 +3720,14 @@ static int gdb_target_start(struct target *target, const char *port)
        gdb_service->core[1] = -1;
        target->gdb_service = gdb_service;
 
-       ret = add_service("gdb",
-                       port, target->gdb_max_connections, &gdb_new_connection, &gdb_input,
-                       &gdb_connection_closed, gdb_service);
+       ret = add_service(&gdb_service_driver, port, target->gdb_max_connections, 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) {
-                       curr = head->target;
+               foreach_smp_target(head, target->smp_targets) {
+                       struct target *curr = head->target;
                        if (curr != target)
                                curr->gdb_service = gdb_service;
-                       head = head->next;
                }
        }
        return ret;
@@ -3602,14 +3789,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;
@@ -3623,7 +3810,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;
@@ -3638,7 +3825,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);
        }
@@ -3732,7 +3919,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)