X-Git-Url: https://review.openocd.org/gitweb?a=blobdiff_plain;f=src%2Fserver%2Fgdb_server.c;h=82c8ce92b31faf395ee6f933ba147ee8ad1582ac;hb=017d3ddafbfac459a799f7e60613312c61fa3195;hp=61d7686c44b7bd16a01bc2d58d21ae28d88e2608;hpb=2f92598f0d6d8304a9c15f7050c9e888279cd2fa;p=openocd.git diff --git a/src/server/gdb_server.c b/src/server/gdb_server.c index 61d7686c44..82c8ce92b3 100644 --- a/src/server/gdb_server.c +++ b/src/server/gdb_server.c @@ -61,6 +61,13 @@ * 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,23 +358,71 @@ 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(struct connection *connection, char *packet) +{ + if (!LOG_LEVEL_IS(LOG_LVL_DEBUG)) + return; + + struct target *target = get_target_from_connection(connection); + + /* 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_TARGET_DEBUG(target, "received packet: %.*s", prefix_len, + packet, payload_len); + } else { + LOG_TARGET_DEBUG(target, "received packet: ", packet_len); + } + } else { + /* All chars printable, dump the packet as is */ + LOG_TARGET_DEBUG(target, "received packet: %s", packet); + } +} + +static void gdb_log_outgoing_packet(struct connection *connection, char *packet_buf, + unsigned int packet_len, unsigned char checksum) +{ + if (!LOG_LEVEL_IS(LOG_LVL_DEBUG)) + return; + + struct target *target = get_target_from_connection(connection); + + if (find_nonprint_char(packet_buf, packet_len)) + LOG_TARGET_DEBUG(target, "sending packet: $#%2.2x", + packet_len, checksum); + else + LOG_TARGET_DEBUG(target, "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 +458,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(connection, buffer, len, my_checksum); char local_buffer[1024]; local_buffer[0] = '$'; @@ -437,22 +491,27 @@ static int gdb_put_packet_inner(struct connection *connection, if (retval != ERROR_OK) return retval; - if (reply == '+') + if (reply == '+') { + gdb_log_incoming_packet(connection, "+"); break; - else if (reply == '-') { + } else if (reply == '-') { /* Stop sending output packets for now */ - log_remove_callback(gdb_log_callback, connection); + gdb_con->output_flag = GDB_OUTPUT_NO; + gdb_log_incoming_packet(connection, "-"); LOG_WARNING("negative reply, retrying"); } else if (reply == 0x3) { gdb_con->ctrl_c = true; + gdb_log_incoming_packet(connection, ""); retval = gdb_get_char(connection, &reply); if (retval != ERROR_OK) return retval; - if (reply == '+') + if (reply == '+') { + gdb_log_incoming_packet(connection, "+"); break; - else if (reply == '-') { + } else if (reply == '-') { /* Stop sending output packets for now */ - log_remove_callback(gdb_log_callback, connection); + gdb_con->output_flag = GDB_OUTPUT_NO; + gdb_log_incoming_packet(connection, "-"); LOG_WARNING("negative reply, retrying"); } else if (reply == '$') { LOG_ERROR("GDB missing ack(1) - assumed good"); @@ -629,6 +688,7 @@ static int gdb_get_packet_inner(struct connection *connection, case '$': break; case '+': + gdb_log_incoming_packet(connection, "+"); /* According to the GDB documentation * (https://sourceware.org/gdb/onlinedocs/gdb/Packet-Acknowledgment.html): * "gdb sends a final `+` acknowledgment of the stub's `OK` @@ -646,9 +706,11 @@ static int gdb_get_packet_inner(struct connection *connection, } break; case '-': + gdb_log_incoming_packet(connection, "-"); LOG_WARNING("negative acknowledgment, but no packet pending"); break; case 0x3: + gdb_log_incoming_packet(connection, ""); gdb_con->ctrl_c = true; *len = 0; return ERROR_OK; @@ -705,7 +767,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 +790,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 +801,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 +840,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); @@ -895,7 +957,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) @@ -955,6 +1017,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); @@ -969,6 +1032,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 +1056,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,7 +1077,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, @@ -1025,7 +1091,7 @@ static int gdb_new_connection(struct connection *connection) return ERROR_TARGET_NOT_EXAMINED; } - if (target->state == TARGET_HALTED) + if (target->state != TARGET_HALTED) LOG_WARNING("GDB connection %d on target %s not halted", gdb_actual_connections, target_name(target)); @@ -1036,6 +1102,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; } @@ -1067,11 +1135,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); @@ -1183,7 +1248,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, ®_list, ®_list_size, @@ -1192,7 +1257,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; } @@ -1200,13 +1265,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]); @@ -1313,7 +1378,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, ®_list, ®_list_size, @@ -1322,7 +1387,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; } @@ -1335,7 +1400,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]); @@ -1369,8 +1434,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; @@ -1384,15 +1449,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; @@ -1465,7 +1530,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. @@ -1536,7 +1605,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); @@ -1605,7 +1678,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; } @@ -1750,16 +1828,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; } @@ -1783,7 +1860,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 @@ -1797,9 +1874,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; } @@ -2018,7 +2095,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; @@ -2054,14 +2131,14 @@ static int gdb_generate_reg_type_description(struct target *target, } /* */ xml_printf(&retval, tdesc, pos, size, - "\n", + "\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, @@ -2081,7 +2158,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, "\n", field->name, field->type->id); @@ -2101,18 +2178,18 @@ static int gdb_generate_reg_type_description(struct target *target, * ... * */ xml_printf(&retval, tdesc, pos, size, - "\n", + "\n", type->id, type->reg_type_struct->size); - while (field != NULL) { + while (field) { xml_printf(&retval, tdesc, pos, size, - "\n", + "\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, @@ -2129,7 +2206,7 @@ static int gdb_generate_reg_type_description(struct target *target, xml_printf(&retval, tdesc, pos, size, "\n", type->id); - while (field != NULL) { + while (field) { xml_printf(&retval, tdesc, pos, size, "\n", field->name, field->type->id); @@ -2146,14 +2223,14 @@ static int gdb_generate_reg_type_description(struct target *target, * ... * */ xml_printf(&retval, tdesc, pos, size, - "\n", + "\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, - "\n", + "\n", field->name, field->bitfield->start, field->bitfield->end, gdb_get_reg_type_name(field->bitfield->type)); @@ -2180,11 +2257,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 @@ -2210,6 +2287,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, ®_list, + ®_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, ®_list, + ®_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; @@ -2223,8 +2416,8 @@ static int gdb_generate_target_description(struct target *target, char **tdesc_o int size = 0; - retval = target_get_gdb_reg_list_noread(target, ®_list, - ®_list_size, REG_CLASS_ALL); + retval = smp_reg_list_noread(target, ®_list, ®_list_size, + REG_CLASS_ALL); if (retval != ERROR_OK) { LOG_ERROR("get register list failed"); @@ -2256,12 +2449,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, "%s\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; @@ -2274,14 +2467,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 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\""); @@ -2319,7 +2512,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); @@ -2353,7 +2546,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; } @@ -2361,7 +2554,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"); @@ -2379,7 +2572,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; } @@ -2461,22 +2654,28 @@ static int gdb_generate_thread_list(struct target *target, char **thread_list_ou "\n" "\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_detail->threadid); + if (thread_detail->thread_name_str) + xml_printf(&retval, &thread_list, &pos, &size, + "", + thread_detail->threadid, + thread_detail->thread_name_str); + else + xml_printf(&retval, &thread_list, &pos, &size, + "", 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, @@ -2502,7 +2701,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"); @@ -2520,11 +2719,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; } @@ -2557,7 +2756,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. */ @@ -2565,7 +2764,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); @@ -2729,7 +2928,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; @@ -2746,7 +2945,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)); @@ -2784,12 +2983,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); @@ -2835,7 +3034,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); /* @@ -2856,7 +3055,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; } @@ -2868,7 +3067,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; @@ -2886,7 +3085,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 { @@ -2907,7 +3106,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; @@ -2920,7 +3119,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); @@ -2965,16 +3164,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; @@ -3101,7 +3302,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"); } @@ -3214,6 +3415,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; @@ -3263,20 +3468,10 @@ 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:'", buf); - } else - LOG_DEBUG("received packet: '%s'", packet); - } - if (packet_size > 0) { + + gdb_log_incoming_packet(connection, gdb_packet_buffer); + retval = ERROR_OK; switch (packet[0]) { case 'T': /* Is thread alive? */ @@ -3319,7 +3514,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; @@ -3327,7 +3522,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!"); @@ -3370,7 +3565,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 @@ -3442,7 +3637,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; @@ -3495,13 +3690,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); @@ -3511,19 +3737,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, 1, &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; @@ -3585,14 +3806,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; @@ -3606,7 +3827,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; @@ -3621,7 +3842,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); } @@ -3715,7 +3936,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; }