X-Git-Url: https://review.openocd.org/gitweb?p=openocd.git;a=blobdiff_plain;f=src%2Fserver%2Fgdb_server.c;h=3ade195cbffb8afb0833d1aeccdb51f70baeb04e;hp=c293f5b057235f829bd6228c94b0459c23dff4b9;hb=57e30102ea440d77aa001e26eb901d0cbb305a30;hpb=47b8cf84202bf792cf66fbfa01169e9592236b8a diff --git a/src/server/gdb_server.c b/src/server/gdb_server.c index c293f5b057..3ade195cbf 100644 --- a/src/server/gdb_server.c +++ b/src/server/gdb_server.c @@ -41,6 +41,8 @@ #include #include #include +#include +#include #include "server.h" #include #include "gdb_server.h" @@ -71,8 +73,8 @@ struct gdb_connection { int ctrl_c; enum target_state frontend_state; struct image *vflash_image; - int closed; - int busy; + bool closed; + bool busy; int noack_mode; /* set flag to true if you want the next stepi to return immediately. * allowing GDB to pick up a fresh set of register values from the target @@ -110,6 +112,8 @@ static char *gdb_port_next; static void gdb_log_callback(void *priv, const char *file, unsigned line, const char *function, const char *string); +static void gdb_sig_halted(struct connection *connection); + /* number of gdb connections, mainly to suppress gdb related debugging spam * in helper/log.c when no gdb connections are actually active */ int gdb_actual_connections; @@ -126,6 +130,9 @@ static int gdb_flash_program = 1; * Disabled by default. */ static int gdb_report_data_abort; +/* If set, errors when accessing registers are reported to gdb. Disabled by + * default. */ +static int gdb_report_register_access_error; /* set if we are sending target descriptions to gdb * via qXfer:features:read packet */ @@ -146,6 +153,8 @@ static int gdb_last_signal(struct target *target) return 0x05; /* SIGTRAP */ case DBG_REASON_SINGLESTEP: return 0x05; /* SIGTRAP */ + case DBG_REASON_EXC_CATCH: + return 0x05; case DBG_REASON_NOTHALTED: return 0x0; /* no signal... shouldn't happen */ default: @@ -215,7 +224,7 @@ static int gdb_get_char_inner(struct connection *connection, int *next_char) if (gdb_con->buf_cnt > 0) break; if (gdb_con->buf_cnt == 0) { - gdb_con->closed = 1; + gdb_con->closed = true; return ERROR_SERVER_REMOTE_CLOSED; } @@ -227,10 +236,10 @@ static int gdb_get_char_inner(struct connection *connection, int *next_char) usleep(1000); break; case WSAECONNABORTED: - gdb_con->closed = 1; + gdb_con->closed = true; return ERROR_SERVER_REMOTE_CLOSED; case WSAECONNRESET: - gdb_con->closed = 1; + gdb_con->closed = true; return ERROR_SERVER_REMOTE_CLOSED; default: LOG_ERROR("read: %d", errno); @@ -242,14 +251,14 @@ static int gdb_get_char_inner(struct connection *connection, int *next_char) usleep(1000); break; case ECONNABORTED: - gdb_con->closed = 1; + gdb_con->closed = true; return ERROR_SERVER_REMOTE_CLOSED; case ECONNRESET: - gdb_con->closed = 1; + gdb_con->closed = true; return ERROR_SERVER_REMOTE_CLOSED; default: LOG_ERROR("read: %s", strerror(errno)); - gdb_con->closed = 1; + gdb_con->closed = true; return ERROR_SERVER_REMOTE_CLOSED; } #endif @@ -341,7 +350,7 @@ static int gdb_write(struct connection *connection, void *data, int len) if (connection_write(connection, data, len) == len) return ERROR_OK; - gdb_con->closed = 1; + gdb_con->closed = true; return ERROR_SERVER_REMOTE_CLOSED; } @@ -448,7 +457,7 @@ static int gdb_put_packet_inner(struct connection *connection, return ERROR_OK; } else { LOG_ERROR("unknown character(1) 0x%2.2x in reply, dropping connection", reply); - gdb_con->closed = 1; + gdb_con->closed = true; return ERROR_SERVER_REMOTE_CLOSED; } } else if (reply == '$') { @@ -458,7 +467,7 @@ static int gdb_put_packet_inner(struct connection *connection, } else { LOG_ERROR("unknown character(2) 0x%2.2x in reply, dropping connection", reply); - gdb_con->closed = 1; + gdb_con->closed = true; return ERROR_SERVER_REMOTE_CLOSED; } } @@ -471,9 +480,9 @@ static int gdb_put_packet_inner(struct connection *connection, int gdb_put_packet(struct connection *connection, char *buffer, int len) { struct gdb_connection *gdb_con = connection->priv; - gdb_con->busy = 1; + gdb_con->busy = true; int retval = gdb_put_packet_inner(connection, buffer, len); - gdb_con->busy = 0; + gdb_con->busy = false; /* we sent some data, reset timer for keep alive messages */ kept_alive(); @@ -679,9 +688,9 @@ static int gdb_get_packet_inner(struct connection *connection, static int gdb_get_packet(struct connection *connection, char *buffer, int *len) { struct gdb_connection *gdb_con = connection->priv; - gdb_con->busy = 1; + gdb_con->busy = true; int retval = gdb_get_packet_inner(connection, buffer, len); - gdb_con->busy = 0; + gdb_con->busy = false; return retval; } @@ -728,7 +737,6 @@ static void gdb_signal_reply(struct target *target, struct connection *connectio } else { if (gdb_connection->ctrl_c) { signal_var = 0x2; - gdb_connection->ctrl_c = 0; } else signal_var = gdb_last_signal(target); @@ -760,12 +768,19 @@ static void gdb_signal_reply(struct target *target, struct connection *connectio current_thread[0] = '\0'; if (target->rtos != NULL) { - snprintf(current_thread, sizeof(current_thread), "thread:%016" PRIx64 ";", target->rtos->current_thread); + struct target *ct; + snprintf(current_thread, sizeof(current_thread), "thread:%016" PRIx64 ";", + target->rtos->current_thread); target->rtos->current_threadid = target->rtos->current_thread; + target->rtos->gdb_target_for_threadid(connection, target->rtos->current_threadid, &ct); + if (!gdb_connection->ctrl_c) + signal_var = gdb_last_signal(ct); } sig_reply_len = snprintf(sig_reply, sizeof(sig_reply), "T%2.2x%s%s", signal_var, stop_reason, current_thread); + + gdb_connection->ctrl_c = 0; } gdb_put_packet(connection, sig_reply, sig_reply_len); @@ -780,64 +795,64 @@ static void gdb_fileio_reply(struct target *target, struct connection *connectio bool program_exited = false; if (strcmp(target->fileio_info->identifier, "open") == 0) - sprintf(fileio_command, "F%s,%" PRIx32 "/%" PRIx32 ",%" PRIx32 ",%" PRIx32, target->fileio_info->identifier, + sprintf(fileio_command, "F%s,%" PRIx64 "/%" PRIx64 ",%" PRIx64 ",%" PRIx64, target->fileio_info->identifier, target->fileio_info->param_1, target->fileio_info->param_2, target->fileio_info->param_3, target->fileio_info->param_4); else if (strcmp(target->fileio_info->identifier, "close") == 0) - sprintf(fileio_command, "F%s,%" PRIx32, target->fileio_info->identifier, + sprintf(fileio_command, "F%s,%" PRIx64, target->fileio_info->identifier, target->fileio_info->param_1); else if (strcmp(target->fileio_info->identifier, "read") == 0) - sprintf(fileio_command, "F%s,%" PRIx32 ",%" PRIx32 ",%" PRIx32, target->fileio_info->identifier, + sprintf(fileio_command, "F%s,%" PRIx64 ",%" PRIx64 ",%" PRIx64, target->fileio_info->identifier, target->fileio_info->param_1, target->fileio_info->param_2, target->fileio_info->param_3); else if (strcmp(target->fileio_info->identifier, "write") == 0) - sprintf(fileio_command, "F%s,%" PRIx32 ",%" PRIx32 ",%" PRIx32, target->fileio_info->identifier, + sprintf(fileio_command, "F%s,%" PRIx64 ",%" PRIx64 ",%" PRIx64, target->fileio_info->identifier, target->fileio_info->param_1, target->fileio_info->param_2, target->fileio_info->param_3); else if (strcmp(target->fileio_info->identifier, "lseek") == 0) - sprintf(fileio_command, "F%s,%" PRIx32 ",%" PRIx32 ",%" PRIx32, target->fileio_info->identifier, + sprintf(fileio_command, "F%s,%" PRIx64 ",%" PRIx64 ",%" PRIx64, target->fileio_info->identifier, target->fileio_info->param_1, target->fileio_info->param_2, target->fileio_info->param_3); else if (strcmp(target->fileio_info->identifier, "rename") == 0) - sprintf(fileio_command, "F%s,%" PRIx32 "/%" PRIx32 ",%" PRIx32 "/%" PRIx32, target->fileio_info->identifier, + sprintf(fileio_command, "F%s,%" PRIx64 "/%" PRIx64 ",%" PRIx64 "/%" PRIx64, target->fileio_info->identifier, target->fileio_info->param_1, target->fileio_info->param_2, target->fileio_info->param_3, target->fileio_info->param_4); else if (strcmp(target->fileio_info->identifier, "unlink") == 0) - sprintf(fileio_command, "F%s,%" PRIx32 "/%" PRIx32, target->fileio_info->identifier, + sprintf(fileio_command, "F%s,%" PRIx64 "/%" PRIx64, target->fileio_info->identifier, target->fileio_info->param_1, target->fileio_info->param_2); else if (strcmp(target->fileio_info->identifier, "stat") == 0) - sprintf(fileio_command, "F%s,%" PRIx32 "/%" PRIx32 ",%" PRIx32, target->fileio_info->identifier, + sprintf(fileio_command, "F%s,%" PRIx64 "/%" PRIx64 ",%" PRIx64, target->fileio_info->identifier, target->fileio_info->param_1, target->fileio_info->param_2, target->fileio_info->param_3); else if (strcmp(target->fileio_info->identifier, "fstat") == 0) - sprintf(fileio_command, "F%s,%" PRIx32 ",%" PRIx32, target->fileio_info->identifier, + sprintf(fileio_command, "F%s,%" PRIx64 ",%" PRIx64, target->fileio_info->identifier, target->fileio_info->param_1, target->fileio_info->param_2); else if (strcmp(target->fileio_info->identifier, "gettimeofday") == 0) - sprintf(fileio_command, "F%s,%" PRIx32 ",%" PRIx32, target->fileio_info->identifier, + sprintf(fileio_command, "F%s,%" PRIx64 ",%" PRIx64, target->fileio_info->identifier, target->fileio_info->param_1, target->fileio_info->param_2); else if (strcmp(target->fileio_info->identifier, "isatty") == 0) - sprintf(fileio_command, "F%s,%" PRIx32, target->fileio_info->identifier, + sprintf(fileio_command, "F%s,%" PRIx64, target->fileio_info->identifier, target->fileio_info->param_1); else if (strcmp(target->fileio_info->identifier, "system") == 0) - sprintf(fileio_command, "F%s,%" PRIx32 "/%" PRIx32, target->fileio_info->identifier, + sprintf(fileio_command, "F%s,%" PRIx64 "/%" PRIx64, target->fileio_info->identifier, target->fileio_info->param_1, target->fileio_info->param_2); else if (strcmp(target->fileio_info->identifier, "exit") == 0) { /* If target hits exit syscall, report to GDB the program is terminated. * In addition, let target run its own exit syscall handler. */ program_exited = true; - sprintf(fileio_command, "W%02" PRIx32, target->fileio_info->param_1); + sprintf(fileio_command, "W%02" PRIx64, target->fileio_info->param_1); } else { LOG_DEBUG("Unknown syscall: %s", target->fileio_info->identifier); @@ -917,11 +932,13 @@ static int gdb_target_callback_event_handler(struct target *target, static int gdb_new_connection(struct connection *connection) { struct gdb_connection *gdb_connection = malloc(sizeof(struct gdb_connection)); - struct gdb_service *gdb_service = connection->service->priv; + struct target *target; int retval; int initial_ack; + target = get_target_from_connection(connection); connection->priv = gdb_connection; + connection->cmd_ctx->current_target = target; /* initialize gdb connection information */ gdb_connection->buf_p = gdb_connection->buffer; @@ -929,8 +946,8 @@ static int gdb_new_connection(struct connection *connection) gdb_connection->ctrl_c = 0; gdb_connection->frontend_state = TARGET_HALTED; gdb_connection->vflash_image = NULL; - gdb_connection->closed = 0; - gdb_connection->busy = 0; + gdb_connection->closed = false; + gdb_connection->busy = false; gdb_connection->noack_mode = 0; gdb_connection->sync = false; gdb_connection->mem_write_error = false; @@ -949,12 +966,17 @@ static int gdb_new_connection(struct connection *connection) * GDB session could leave dangling breakpoints if e.g. communication * timed out. */ - breakpoint_clear_target(gdb_service->target); - watchpoint_clear_target(gdb_service->target); + breakpoint_clear_target(target); + watchpoint_clear_target(target); - /* clean previous rtos session if supported*/ - if ((gdb_service->target->rtos) && (gdb_service->target->rtos->type->clean)) - gdb_service->target->rtos->type->clean(gdb_service->target); + if (target->rtos) { + /* clean previous rtos session if supported*/ + if (target->rtos->type->clean) + target->rtos->type->clean(target); + + /* update threads */ + rtos_update_threads(target); + } /* remove the initial ACK from the incoming buffer */ retval = gdb_get_char(connection, &initial_ack); @@ -966,7 +988,7 @@ static int gdb_new_connection(struct connection *connection) */ if (initial_ack != '+') gdb_putback_char(connection, initial_ack); - target_call_event_callbacks(gdb_service->target, TARGET_EVENT_GDB_ATTACH); + target_call_event_callbacks(target, TARGET_EVENT_GDB_ATTACH); if (gdb_use_memory_map) { /* Connect must fail if the memory map can't be set up correctly. @@ -978,7 +1000,7 @@ static int gdb_new_connection(struct connection *connection) for (i = 0; i < flash_get_bank_count(); i++) { struct flash_bank *p; p = get_flash_bank_by_num_noprobe(i); - if (p->target != gdb_service->target) + if (p->target != target) continue; retval = get_flash_bank_by_num(i, &p); if (retval != ERROR_OK) { @@ -990,10 +1012,12 @@ static int gdb_new_connection(struct connection *connection) } gdb_actual_connections++; - LOG_DEBUG("New GDB Connection: %d, Target %s, state: %s", + log_printf_lf(all_targets->next != NULL ? LOG_LVL_INFO : LOG_LVL_DEBUG, + __FILE__, __LINE__, __func__, + "New GDB Connection: %d, Target %s, state: %s", gdb_actual_connections, - target_name(gdb_service->target), - target_state_name(gdb_service->target)); + target_name(target), + target_state_name(target)); /* DANGER! If we fail subsequently, we must remove this handler, * otherwise we occasionally see crashes as the timer can invoke the @@ -1007,9 +1031,11 @@ static int gdb_new_connection(struct connection *connection) static int gdb_connection_closed(struct connection *connection) { - struct gdb_service *gdb_service = connection->service->priv; + struct target *target; struct gdb_connection *gdb_connection = connection->priv; + target = get_target_from_connection(connection); + /* we're done forwarding messages. Tear down callback before * cleaning up connection. */ @@ -1017,8 +1043,8 @@ static int gdb_connection_closed(struct connection *connection) gdb_actual_connections--; LOG_DEBUG("GDB Close, Target: %s, state: %s, gdb_actual_connections=%d", - target_name(gdb_service->target), - target_state_name(gdb_service->target), + target_name(target), + target_state_name(target), gdb_actual_connections); /* see if an image built with vFlash commands is left */ @@ -1029,7 +1055,7 @@ static int gdb_connection_closed(struct connection *connection) } /* if this connection registered a debug-message receiver delete it */ - delete_debug_msg_receiver(connection->cmd_ctx, gdb_service->target); + delete_debug_msg_receiver(connection->cmd_ctx, target); if (connection->priv) { free(connection->priv); @@ -1039,9 +1065,9 @@ static int gdb_connection_closed(struct connection *connection) target_unregister_event_callback(gdb_target_callback_event_handler, connection); - target_call_event_callbacks(gdb_service->target, TARGET_EVENT_GDB_END); + target_call_event_callbacks(target, TARGET_EVENT_GDB_END); - target_call_event_callbacks(gdb_service->target, TARGET_EVENT_GDB_DETACH); + target_call_event_callbacks(target, TARGET_EVENT_GDB_DETACH); return ERROR_OK; } @@ -1155,8 +1181,11 @@ static int gdb_get_registers_packet(struct connection *connection, if (retval != ERROR_OK) return gdb_error(connection, retval); - for (i = 0; i < reg_list_size; i++) + for (i = 0; i < reg_list_size; i++) { + if (reg_list[i] == NULL || reg_list[i]->exist == false) + continue; reg_packet_size += DIV_ROUND_UP(reg_list[i]->size, 8) * 2; + } assert(reg_packet_size > 0); @@ -1167,8 +1196,17 @@ static int gdb_get_registers_packet(struct connection *connection, reg_packet_p = reg_packet; for (i = 0; i < reg_list_size; i++) { - if (!reg_list[i]->valid) - reg_list[i]->type->get(reg_list[i]); + if (reg_list[i] == NULL || reg_list[i]->exist == false) + continue; + if (!reg_list[i]->valid) { + retval = reg_list[i]->type->get(reg_list[i]); + if (retval != ERROR_OK && gdb_report_register_access_error) { + LOG_DEBUG("Couldn't get register %s.", reg_list[i]->name); + free(reg_packet); + free(reg_list); + return gdb_error(connection, retval); + } + } gdb_str_to_target(target, reg_packet_p, reg_list[i]); reg_packet_p += DIV_ROUND_UP(reg_list[i]->size, 8) * 2; } @@ -1229,7 +1267,13 @@ static int gdb_set_registers_packet(struct connection *connection, bin_buf = malloc(DIV_ROUND_UP(reg_list[i]->size, 8)); gdb_target_to_reg(target, packet_p, chars, bin_buf); - reg_list[i]->type->set(reg_list[i], bin_buf); + retval = reg_list[i]->type->set(reg_list[i], bin_buf); + if (retval != ERROR_OK && gdb_report_register_access_error) { + LOG_DEBUG("Couldn't set register %s.", reg_list[i]->name); + free(reg_list); + free(bin_buf); + return gdb_error(connection, retval); + } /* advance packet pointer */ packet_p += chars; @@ -1259,6 +1303,9 @@ 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))) + return ERROR_OK; + retval = target_get_gdb_reg_list(target, ®_list, ®_list_size, REG_CLASS_ALL); if (retval != ERROR_OK) @@ -1269,8 +1316,14 @@ static int gdb_get_register_packet(struct connection *connection, return ERROR_SERVER_REMOTE_CLOSED; } - if (!reg_list[reg_num]->valid) - reg_list[reg_num]->type->get(reg_list[reg_num]); + if (!reg_list[reg_num]->valid) { + retval = reg_list[reg_num]->type->get(reg_list[reg_num]); + if (retval != ERROR_OK && gdb_report_register_access_error) { + LOG_DEBUG("Couldn't get register %s.", reg_list[reg_num]->name); + free(reg_list); + return gdb_error(connection, retval); + } + } reg_packet = malloc(DIV_ROUND_UP(reg_list[reg_num]->size, 8) * 2 + 1); /* plus one for string termination null */ @@ -1317,14 +1370,21 @@ static int gdb_set_register_packet(struct connection *connection, int chars = (DIV_ROUND_UP(reg_list[reg_num]->size, 8) * 2); if ((unsigned int)chars != strlen(separator + 1)) { - LOG_ERROR("gdb sent a packet with wrong register size"); + LOG_ERROR("gdb sent %zu bits for a %d-bit register (%s)", + strlen(separator + 1) * 4, chars * 4, reg_list[reg_num]->name); free(bin_buf); return ERROR_SERVER_REMOTE_CLOSED; } gdb_target_to_reg(target, separator + 1, chars, bin_buf); - reg_list[reg_num]->type->set(reg_list[reg_num], bin_buf); + retval = reg_list[reg_num]->type->set(reg_list[reg_num], bin_buf); + if (retval != ERROR_OK && gdb_report_register_access_error) { + LOG_DEBUG("Couldn't set register %s.", reg_list[reg_num]->name); + free(bin_buf); + free(reg_list); + return gdb_error(connection, retval); + } gdb_put_packet(connection, "OK", 2); @@ -1355,7 +1415,7 @@ static int gdb_read_memory_packet(struct connection *connection, { struct target *target = get_target_from_connection(connection); char *separator; - uint32_t addr = 0; + uint64_t addr = 0; uint32_t len = 0; uint8_t *buffer; @@ -1366,7 +1426,7 @@ static int gdb_read_memory_packet(struct connection *connection, /* skip command character */ packet++; - addr = strtoul(packet, &separator, 16); + addr = strtoull(packet, &separator, 16); if (*separator != ',') { LOG_ERROR("incomplete read memory packet received, dropping connection"); @@ -1377,13 +1437,13 @@ static int gdb_read_memory_packet(struct connection *connection, if (!len) { LOG_WARNING("invalid read memory packet received (len == 0)"); - gdb_put_packet(connection, NULL, 0); + gdb_put_packet(connection, "", 0); return ERROR_OK; } buffer = malloc(len); - LOG_DEBUG("addr: 0x%8.8" PRIx32 ", len: 0x%8.8" PRIx32 "", addr, len); + LOG_DEBUG("addr: 0x%16.16" PRIx64 ", len: 0x%8.8" PRIx32 "", addr, len); retval = target_read_buffer(target, addr, len, buffer); @@ -1426,7 +1486,7 @@ static int gdb_write_memory_packet(struct connection *connection, { struct target *target = get_target_from_connection(connection); char *separator; - uint32_t addr = 0; + uint64_t addr = 0; uint32_t len = 0; uint8_t *buffer; @@ -1435,7 +1495,7 @@ static int gdb_write_memory_packet(struct connection *connection, /* skip command character */ packet++; - addr = strtoul(packet, &separator, 16); + addr = strtoull(packet, &separator, 16); if (*separator != ',') { LOG_ERROR("incomplete write memory packet received, dropping connection"); @@ -1451,7 +1511,7 @@ static int gdb_write_memory_packet(struct connection *connection, buffer = malloc(len); - LOG_DEBUG("addr: 0x%8.8" PRIx32 ", len: 0x%8.8" PRIx32 "", addr, len); + LOG_DEBUG("addr: 0x%" PRIx64 ", len: 0x%8.8" PRIx32 "", addr, len); if (unhexify(buffer, separator, len) != len) LOG_ERROR("unable to decode memory packet"); @@ -1473,7 +1533,7 @@ static int gdb_write_memory_binary_packet(struct connection *connection, { struct target *target = get_target_from_connection(connection); char *separator; - uint32_t addr = 0; + uint64_t addr = 0; uint32_t len = 0; int retval = ERROR_OK; @@ -1485,7 +1545,7 @@ static int gdb_write_memory_binary_packet(struct connection *connection, /* skip command character */ packet++; - addr = strtoul(packet, &separator, 16); + addr = strtoull(packet, &separator, 16); if (*separator != ',') { LOG_ERROR("incomplete write memory binary packet received, dropping connection"); @@ -1523,7 +1583,7 @@ static int gdb_write_memory_binary_packet(struct connection *connection, } if (len) { - LOG_DEBUG("addr: 0x%8.8" PRIx32 ", len: 0x%8.8" PRIx32 "", addr, len); + LOG_DEBUG("addr: 0x%" PRIx64 ", len: 0x%8.8" PRIx32 "", addr, len); retval = target_write_buffer(target, addr, len, (uint8_t *)separator); if (retval != ERROR_OK) @@ -1547,13 +1607,13 @@ static int gdb_step_continue_packet(struct connection *connection, { struct target *target = get_target_from_connection(connection); int current = 0; - uint32_t address = 0x0; + uint64_t address = 0x0; int retval = ERROR_OK; LOG_DEBUG("-"); if (packet_size > 1) - address = strtoul(packet + 1, NULL, 16); + address = strtoull(packet + 1, NULL, 16); else current = 1; @@ -1577,7 +1637,7 @@ static int gdb_breakpoint_watchpoint_packet(struct connection *connection, int type; enum breakpoint_type bp_type = BKPT_SOFT /* dummy init to avoid warning */; enum watchpoint_rw wp_type = WPT_READ /* dummy init to avoid warning */; - uint32_t address; + uint64_t address; uint32_t size; char *separator; int retval; @@ -1609,7 +1669,7 @@ static int gdb_breakpoint_watchpoint_packet(struct connection *connection, return ERROR_SERVER_REMOTE_CLOSED; } - address = strtoul(separator + 1, &separator, 16); + address = strtoull(separator + 1, &separator, 16); if (*separator != ',') { LOG_ERROR("incomplete breakpoint/watchpoint packet received, dropping connection"); @@ -1760,7 +1820,7 @@ static int gdb_memory_map(struct connection *connection, int offset; int length; char *separator; - uint32_t ram_start = 0; + target_addr_t ram_start = 0; int i; int target_flash_banks = 0; @@ -1775,9 +1835,6 @@ static int gdb_memory_map(struct connection *connection, /* Sort banks in ascending order. We need to report non-flash * memory as ram (or rather read/write) by default for GDB, since * it has no concept of non-cacheable read/write memory (i/o etc). - * - * FIXME Most non-flash addresses are *NOT* RAM! Don't lie. - * Current versions of GDB assume unlisted addresses are RAM... */ banks = malloc(sizeof(struct flash_bank *)*flash_get_bank_count()); @@ -1800,14 +1857,13 @@ static int gdb_memory_map(struct connection *connection, for (i = 0; i < target_flash_banks; i++) { int j; unsigned sector_size = 0; - uint32_t start; + unsigned group_len = 0; p = banks[i]; - start = p->base; if (ram_start < p->base) xml_printf(&retval, &xml, &pos, &size, - "\n", ram_start, p->base - ram_start); @@ -1818,27 +1874,35 @@ static int gdb_memory_map(struct connection *connection, * regions with 8KB, 32KB, and 64KB sectors; etc. */ for (j = 0; j < p->num_sectors; j++) { - unsigned group_len; /* Maybe start a new group of sectors. */ if (sector_size == 0) { + if (p->sectors[j].offset + p->sectors[j].size > p->size) { + LOG_WARNING("The flash sector at offset 0x%08" PRIx32 + " overflows the end of %s bank.", + p->sectors[j].offset, p->name); + LOG_WARNING("The rest of bank will not show in gdb memory map."); + break; + } + target_addr_t start; start = p->base + p->sectors[j].offset; xml_printf(&retval, &xml, &pos, &size, "sectors[j].size; + group_len = sector_size; + } else { + group_len += sector_size; /* equal to p->sectors[j].size */ } /* Does this finish a group of sectors? * If not, continue an already-started group. */ - if (j == p->num_sectors - 1) - group_len = (p->base + p->size) - start; - else if (p->sectors[j + 1].size != sector_size) - group_len = p->base + p->sectors[j + 1].offset - - start; - else + if (j < p->num_sectors - 1 + && p->sectors[j + 1].size == sector_size + && p->sectors[j + 1].offset == p->sectors[j].offset + sector_size + && p->sectors[j + 1].offset + p->sectors[j + 1].size <= p->size) continue; xml_printf(&retval, &xml, &pos, &size, @@ -1856,19 +1920,18 @@ static int gdb_memory_map(struct connection *connection, if (ram_start != 0) xml_printf(&retval, &xml, &pos, &size, - "\n", - ram_start, 0-ram_start); - /* ELSE a flash chip could be at the very end of the 32 bit address - * space, in which case ram_start will be precisely 0 - */ + "\n", + ram_start, target_address_max(target) - ram_start + 1); + /* ELSE a flash chip could be at the very end of the address space, in + * which case ram_start will be precisely 0 */ free(banks); - banks = NULL; xml_printf(&retval, &xml, &pos, &size, "\n"); if (retval != ERROR_OK) { + free(xml); gdb_error(connection, retval); return retval; } @@ -1889,6 +1952,8 @@ static int gdb_memory_map(struct connection *connection, static const char *gdb_get_reg_type_name(enum reg_type type) { switch (type) { + case REG_TYPE_BOOL: + return "bool"; case REG_TYPE_INT: return "int"; case REG_TYPE_INT8: @@ -1901,6 +1966,8 @@ static const char *gdb_get_reg_type_name(enum reg_type type) return "int64"; case REG_TYPE_INT128: return "int128"; + case REG_TYPE_UINT: + return "uint"; case REG_TYPE_UINT8: return "uint8"; case REG_TYPE_UINT16: @@ -1928,12 +1995,45 @@ static const char *gdb_get_reg_type_name(enum reg_type type) return "int"; /* "int" as default value */ } +static int lookup_add_arch_defined_types(char const **arch_defined_types_list[], const char *type_id, + int *num_arch_defined_types) +{ + int tbl_sz = *num_arch_defined_types; + + if (type_id != NULL && (strcmp(type_id, ""))) { + for (int j = 0; j < (tbl_sz + 1); j++) { + if (!((*arch_defined_types_list)[j])) { + (*arch_defined_types_list)[tbl_sz++] = type_id; + *arch_defined_types_list = realloc(*arch_defined_types_list, + sizeof(char *) * (tbl_sz + 1)); + (*arch_defined_types_list)[tbl_sz] = NULL; + *num_arch_defined_types = tbl_sz; + return 1; + } else { + if (!strcmp((*arch_defined_types_list)[j], type_id)) + return 0; + } + } + } + + return -1; +} + static int gdb_generate_reg_type_description(struct target *target, - char **tdesc, int *pos, int *size, struct reg_data_type *type) + char **tdesc, int *pos, int *size, struct reg_data_type *type, + char const **arch_defined_types_list[], int * num_arch_defined_types) { int retval = ERROR_OK; if (type->type_class == REG_TYPE_CLASS_VECTOR) { + struct reg_data_type *data_type = type->reg_type_vector->type; + if (data_type->type == REG_TYPE_ARCH_DEFINED) { + if (lookup_add_arch_defined_types(arch_defined_types_list, data_type->id, + num_arch_defined_types)) + gdb_generate_reg_type_description(target, tdesc, pos, size, data_type, + arch_defined_types_list, + num_arch_defined_types); + } /* */ xml_printf(&retval, tdesc, pos, size, "\n", @@ -1941,6 +2041,20 @@ static int gdb_generate_reg_type_description(struct target *target, type->reg_type_vector->count); } else if (type->type_class == REG_TYPE_CLASS_UNION) { + struct reg_data_type_union_field *field; + field = type->reg_type_union->fields; + while (field != NULL) { + struct reg_data_type *data_type = field->type; + if (data_type->type == REG_TYPE_ARCH_DEFINED) { + if (lookup_add_arch_defined_types(arch_defined_types_list, data_type->id, + num_arch_defined_types)) + gdb_generate_reg_type_description(target, tdesc, pos, size, data_type, + arch_defined_types_list, + num_arch_defined_types); + } + + field = field->next; + } /* * ... * */ @@ -1948,7 +2062,6 @@ static int gdb_generate_reg_type_description(struct target *target, "\n", type->id); - struct reg_data_type_union_field *field; field = type->reg_type_union->fields; while (field != NULL) { xml_printf(&retval, tdesc, pos, size, @@ -1974,13 +2087,24 @@ static int gdb_generate_reg_type_description(struct target *target, type->id, type->reg_type_struct->size); while (field != NULL) { xml_printf(&retval, tdesc, pos, size, - "\n", - field->name, field->bitfield->start, - field->bitfield->end); + "\n", + field->name, field->bitfield->start, field->bitfield->end, + gdb_get_reg_type_name(field->bitfield->type)); field = field->next; } } else { + while (field != NULL) { + struct reg_data_type *data_type = field->type; + if (data_type->type == REG_TYPE_ARCH_DEFINED) { + if (lookup_add_arch_defined_types(arch_defined_types_list, data_type->id, + num_arch_defined_types)) + gdb_generate_reg_type_description(target, tdesc, pos, size, data_type, + arch_defined_types_list, + num_arch_defined_types); + } + } + /* * ... * */ @@ -2011,8 +2135,9 @@ static int gdb_generate_reg_type_description(struct target *target, field = type->reg_type_flags->fields; while (field != NULL) { xml_printf(&retval, tdesc, pos, size, - "\n", - field->name, field->bitfield->start, field->bitfield->end); + "\n", + field->name, field->bitfield->start, field->bitfield->end, + gdb_get_reg_type_name(field->bitfield->type)); field = field->next; } @@ -2072,12 +2197,17 @@ static int gdb_generate_target_description(struct target *target, char **tdesc_o int retval = ERROR_OK; struct reg **reg_list = NULL; int reg_list_size; + char const *architecture; char const **features = NULL; + char const **arch_defined_types = NULL; int feature_list_size = 0; + int num_arch_defined_types = 0; char *tdesc = NULL; int pos = 0; int size = 0; + arch_defined_types = calloc(1, sizeof(char *)); + retval = target_get_gdb_reg_list(target, ®_list, ®_list_size, REG_CLASS_ALL); @@ -2109,6 +2239,12 @@ static int gdb_generate_target_description(struct target *target, char **tdesc_o "\n" "\n"); + /* generate architecture element if supported by target */ + architecture = target_get_gdb_arch(target); + if (architecture != NULL) + xml_printf(&retval, &tdesc, &pos, &size, + "%s\n", architecture); + /* generate target description according to register list */ if (features != NULL) { while (features[current_feature]) { @@ -2130,8 +2266,13 @@ static int gdb_generate_target_description(struct target *target, char **tdesc_o if (reg_list[i]->reg_data_type != NULL) { if (reg_list[i]->reg_data_type->type == REG_TYPE_ARCH_DEFINED) { /* generate reg_data_type); + if (lookup_add_arch_defined_types(&arch_defined_types, + reg_list[i]->reg_data_type->id, + &num_arch_defined_types)) + gdb_generate_reg_type_description(target, &tdesc, &pos, &size, + reg_list[i]->reg_data_type, + &arch_defined_types, + &num_arch_defined_types); type_str = reg_list[i]->reg_data_type->id; } else { @@ -2181,6 +2322,7 @@ static int gdb_generate_target_description(struct target *target, char **tdesc_o error: free(features); free(reg_list); + free(arch_defined_types); if (retval == ERROR_OK) *tdesc_out = tdesc; @@ -2252,6 +2394,8 @@ static int gdb_target_description_supported(struct target *target, int *supporte char const **features = NULL; int feature_list_size = 0; + char const *architecture = target_get_gdb_arch(target); + retval = target_get_gdb_reg_list(target, ®_list, ®_list_size, REG_CLASS_ALL); if (retval != ERROR_OK) { @@ -2273,7 +2417,7 @@ static int gdb_target_description_supported(struct target *target, int *supporte } if (supported) { - if (feature_list_size) + if (architecture || feature_list_size) *supported = 1; else *supported = 0; @@ -2357,7 +2501,11 @@ static int gdb_get_thread_list_chunk(struct target *target, char **thread_list, else transfer_type = 'l'; - *chunk = malloc(length + 2); + *chunk = malloc(length + 2 + 3); + /* Allocating extra 3 bytes prevents false positive valgrind report + * of strlen(chunk) word access: + * Invalid read of size 4 + * Address 0x4479934 is 44 bytes inside a block of size 45 alloc'd */ if (*chunk == NULL) { LOG_ERROR("Unable to allocate memory"); return ERROR_FAIL; @@ -2410,13 +2558,13 @@ static int gdb_query_packet(struct connection *connection, char gdb_reply[10]; char *separator; uint32_t checksum; - uint32_t addr = 0; + target_addr_t addr = 0; uint32_t len = 0; /* skip command character */ packet += 5; - addr = strtoul(packet, &separator, 16); + addr = strtoull(packet, &separator, 16); if (*separator != ',') { LOG_ERROR("incomplete read memory packet received, dropping connection"); @@ -2465,7 +2613,7 @@ static int gdb_query_packet(struct connection *connection, &buffer, &pos, &size, - "PacketSize=%x;qXfer:memory-map:read%c;qXfer:features:read%c;qXfer:threads:read+;QStartNoAckMode+", + "PacketSize=%x;qXfer:memory-map:read%c;qXfer:features:read%c;qXfer:threads:read+;QStartNoAckMode+;vContSupported+", (GDB_BUFFER_SIZE - 1), ((gdb_use_memory_map == 1) && (flash_get_bank_count() > 0)) ? '+' : '-', (gdb_target_desc_supported == 1) ? '+' : '-'); @@ -2554,13 +2702,209 @@ static int gdb_query_packet(struct connection *connection, return ERROR_OK; } +static bool gdb_handle_vcont_packet(struct connection *connection, const char *packet, int packet_size) +{ + struct gdb_connection *gdb_connection = connection->priv; + struct target *target = get_target_from_connection(connection); + const char *parse = packet; + int retval; + + /* query for vCont supported */ + if (parse[0] == '?') { + if (target->type->step != NULL) { + /* gdb doesn't accept c without C and s without S */ + gdb_put_packet(connection, "vCont;c;C;s;S", 13); + return true; + } + return false; + } + + if (parse[0] == ';') { + ++parse; + --packet_size; + } + + /* simple case, a continue packet */ + if (parse[0] == 'c') { + gdb_running_type = 'c'; + LOG_DEBUG("target %s continue", target_name(target)); + log_add_callback(gdb_log_callback, connection); + retval = target_resume(target, 1, 0, 0, 0); + if (retval == ERROR_TARGET_NOT_HALTED) + LOG_INFO("target %s was not halted when resume was requested", target_name(target)); + + /* poll target in an attempt to make its internal state consistent */ + if (retval != ERROR_OK) { + retval = target_poll(target); + if (retval != ERROR_OK) + LOG_DEBUG("error polling target %s after failed resume", target_name(target)); + } + + /* + * We don't report errors to gdb here, move frontend_state to + * TARGET_RUNNING to stay in sync with gdb's expectation of the + * target state + */ + gdb_connection->frontend_state = TARGET_RUNNING; + target_call_event_callbacks(target, TARGET_EVENT_GDB_START); + + return true; + } + + /* single-step or step-over-breakpoint */ + if (parse[0] == 's') { + gdb_running_type = 's'; + bool fake_step = false; + + if (strncmp(parse, "s:", 2) == 0) { + struct target *ct = target; + int current_pc = 1; + int64_t thread_id; + char *endp; + + parse += 2; + packet_size -= 2; + + thread_id = strtoll(parse, &endp, 16); + if (endp != NULL) { + packet_size -= endp - parse; + parse = endp; + } + + if (target->rtos != NULL) { + /* FIXME: why is this necessary? rtos state should be up-to-date here already! */ + rtos_update_threads(target); + + target->rtos->gdb_target_for_threadid(connection, thread_id, &ct); + + /* + * check if the thread to be stepped is the current rtos thread + * if not, we must fake the step + */ + if (target->rtos->current_thread != thread_id) + fake_step = true; + } + + if (parse[0] == ';') { + ++parse; + --packet_size; + + if (parse[0] == 'c') { + parse += 1; + packet_size -= 1; + + /* check if thread-id follows */ + if (parse[0] == ':') { + int64_t tid; + parse += 1; + packet_size -= 1; + + tid = strtoll(parse, &endp, 16); + if (tid == thread_id) { + /* + * Special case: only step a single thread (core), + * keep the other threads halted. Currently, only + * aarch64 target understands it. Other target types don't + * care (nobody checks the actual value of 'current') + * and it doesn't really matter. This deserves + * a symbolic constant and a formal interface documentation + * at a later time. + */ + LOG_DEBUG("request to step current core only"); + /* uncomment after checking that indeed other targets are safe */ + /*current_pc = 2;*/ + } + } + } + } + + LOG_DEBUG("target %s single-step thread %"PRIx64, target_name(ct), thread_id); + log_add_callback(gdb_log_callback, connection); + target_call_event_callbacks(ct, TARGET_EVENT_GDB_START); + + /* + * work around an annoying gdb behaviour: when the current thread + * is changed in gdb, it assumes that the target can follow and also + * make the thread current. This is an assumption that cannot hold + * for a real target running a multi-threading OS. We just fake + * the step to not trigger an internal error in gdb. See + * https://sourceware.org/bugzilla/show_bug.cgi?id=22925 for details + */ + if (fake_step) { + int sig_reply_len; + char sig_reply[128]; + + LOG_DEBUG("fake step thread %"PRIx64, thread_id); + + sig_reply_len = snprintf(sig_reply, sizeof(sig_reply), + "T05thread:%016"PRIx64";", thread_id); + + gdb_put_packet(connection, sig_reply, sig_reply_len); + log_remove_callback(gdb_log_callback, connection); + + return true; + } + + /* support for gdb_sync command */ + if (gdb_connection->sync) { + gdb_connection->sync = false; + if (ct->state == TARGET_HALTED) { + LOG_DEBUG("stepi ignored. GDB will now fetch the register state " \ + "from the target."); + gdb_sig_halted(connection); + log_remove_callback(gdb_log_callback, connection); + } else + gdb_connection->frontend_state = TARGET_RUNNING; + return true; + } + + retval = target_step(ct, current_pc, 0, 0); + if (retval == ERROR_TARGET_NOT_HALTED) + LOG_INFO("target %s was not halted when step was requested", target_name(ct)); + + /* if step was successful send a reply back to gdb */ + if (retval == ERROR_OK) { + retval = target_poll(ct); + if (retval != ERROR_OK) + LOG_DEBUG("error polling target %s after successful step", target_name(ct)); + /* send back signal information */ + gdb_signal_reply(ct, connection); + /* stop forwarding log packets! */ + log_remove_callback(gdb_log_callback, connection); + } else + gdb_connection->frontend_state = TARGET_RUNNING; + } else { + LOG_ERROR("Unknown vCont packet"); + return false; + } + return true; + } + + return false; +} + static int gdb_v_packet(struct connection *connection, char const *packet, int packet_size) { struct gdb_connection *gdb_connection = connection->priv; - struct gdb_service *gdb_service = connection->service->priv; + struct target *target; int result; + target = get_target_from_connection(connection); + + if (strncmp(packet, "vCont", 5) == 0) { + bool handled; + + packet += 5; + packet_size -= 5; + + handled = gdb_handle_vcont_packet(connection, packet, packet_size); + if (!handled) + gdb_put_packet(connection, "", 0); + + return ERROR_OK; + } + /* if flash programming disabled - send a empty reply */ if (gdb_flash_program == 0) { @@ -2597,18 +2941,18 @@ static int gdb_v_packet(struct connection *connection, flash_set_dirty(); /* perform any target specific operations before the erase */ - target_call_event_callbacks(gdb_service->target, + target_call_event_callbacks(target, TARGET_EVENT_GDB_FLASH_ERASE_START); /* vFlashErase:addr,length messages require region start and * end to be "block" aligned ... if padding is ever needed, * GDB will have become dangerously confused. */ - result = flash_erase_address_range(gdb_service->target, - false, addr, length); + result = flash_erase_address_range(target, false, addr, + length); /* perform any target specific operations after the erase */ - target_call_event_callbacks(gdb_service->target, + target_call_event_callbacks(target, TARGET_EVENT_GDB_FLASH_ERASE_END); /* perform erase */ @@ -2663,10 +3007,12 @@ static int gdb_v_packet(struct connection *connection, /* process the flashing buffer. No need to erase as GDB * always issues a vFlashErase first. */ - target_call_event_callbacks(gdb_service->target, + target_call_event_callbacks(target, TARGET_EVENT_GDB_FLASH_WRITE_START); - result = flash_write(gdb_service->target, gdb_connection->vflash_image, &written, 0); - target_call_event_callbacks(gdb_service->target, TARGET_EVENT_GDB_FLASH_WRITE_END); + result = flash_write(target, gdb_connection->vflash_image, + &written, 0); + target_call_event_callbacks(target, + TARGET_EVENT_GDB_FLASH_WRITE_END); if (result != ERROR_OK) { if (result == ERROR_FLASH_DST_OUT_OF_BANK) gdb_put_packet(connection, "E.memtype", 9); @@ -2690,10 +3036,12 @@ static int gdb_v_packet(struct connection *connection, static int gdb_detach(struct connection *connection) { - struct gdb_service *gdb_service = connection->service->priv; - - target_call_event_callbacks(gdb_service->target, TARGET_EVENT_GDB_DETACH); - + /* + * Only reply "OK" to GDB + * it will close the connection and this will trigger a call to + * gdb_connection_closed() that will in turn trigger the event + * TARGET_EVENT_GDB_DETACH + */ return gdb_put_packet(connection, "OK", 2); } @@ -2771,14 +3119,15 @@ static int gdb_input_inner(struct connection *connection) /* Do not allocate this on the stack */ static char gdb_packet_buffer[GDB_BUFFER_SIZE]; - struct gdb_service *gdb_service = connection->service->priv; - struct target *target = gdb_service->target; + struct target *target; char const *packet = gdb_packet_buffer; int packet_size; int retval; struct gdb_connection *gdb_con = connection->priv; static int extended_protocol; + target = get_target_from_connection(connection); + /* drain input buffer. If one of the packets fail, then an error * packet is replied, if applicable. * @@ -2884,7 +3233,7 @@ static int gdb_input_inner(struct connection *connection) * make only the single stepping have the sync feature... */ nostep = true; - LOG_WARNING("stepi ignored. GDB will now fetch the register state " \ + LOG_DEBUG("stepi ignored. GDB will now fetch the register state " \ "from the target."); } gdb_con->sync = false; @@ -2948,8 +3297,8 @@ static int gdb_input_inner(struct connection *connection) break; case 'R': /* handle extended restart packet */ - breakpoint_clear_target(gdb_service->target); - watchpoint_clear_target(gdb_service->target); + breakpoint_clear_target(target); + watchpoint_clear_target(target); command_run_linef(connection->cmd_ctx, "ocd_gdb_restart %s", target_name(target)); /* set connection as attached after reset */ @@ -2987,7 +3336,7 @@ static int gdb_input_inner(struct connection *connection) default: /* ignore unknown packets */ LOG_DEBUG("ignoring 0x%2.2x packet", packet[0]); - gdb_put_packet(connection, NULL, 0); + gdb_put_packet(connection, "", 0); break; } @@ -2998,7 +3347,12 @@ static int gdb_input_inner(struct connection *connection) if (gdb_con->ctrl_c) { if (target->state == TARGET_RUNNING) { - retval = target_halt(target); + struct target *t = target; + if (target->rtos) + target->rtos->gdb_target_for_threadid(connection, target->rtos->current_threadid, &t); + retval = target_halt(t); + if (retval == ERROR_OK) + retval = target_poll(t); if (retval != ERROR_OK) target_call_event_callbacks(target, TARGET_EVENT_GDB_HALT); gdb_con->ctrl_c = 0; @@ -3037,6 +3391,8 @@ static int gdb_target_start(struct target *target, const char *port) if (NULL == gdb_service) return -ENOMEM; + LOG_DEBUG("starting gdb server for %s on %s", target_name(target), port); + gdb_service->target = target; gdb_service->core[0] = -1; gdb_service->core[1] = -1; @@ -3062,16 +3418,36 @@ static int gdb_target_start(struct target *target, const char *port) static int gdb_target_add_one(struct target *target) { + /* one gdb instance per smp list */ + if ((target->smp) && (target->gdb_service)) + return ERROR_OK; + + /* skip targets that cannot handle a gdb connections (e.g. mem_ap) */ + if (!target_supports_gdb_connection(target)) { + LOG_DEBUG("skip gdb server for target %s", target_name(target)); + return ERROR_OK; + } + + if (target->gdb_port_override) { + if (strcmp(target->gdb_port_override, "disabled") == 0) { + LOG_INFO("gdb port disabled"); + return ERROR_OK; + } + return gdb_target_start(target, target->gdb_port_override); + } + if (strcmp(gdb_port, "disabled") == 0) { LOG_INFO("gdb port disabled"); return ERROR_OK; } - /* one gdb instance per smp list */ - if ((target->smp) && (target->gdb_service)) - return ERROR_OK; int retval = gdb_target_start(target, gdb_port_next); if (retval == ERROR_OK) { + /* save the port number so can be queried with + * $target_name cget -gdb-port + */ + target->gdb_port_override = strdup(gdb_port_next); + long portnumber; /* If we can parse the port number * then we increment the port number for the next target. @@ -3081,7 +3457,13 @@ static int gdb_target_add_one(struct target *target) if (!*end) { if (parse_long(gdb_port_next, &portnumber) == ERROR_OK) { free(gdb_port_next); - gdb_port_next = alloc_printf("%d", portnumber+1); + if (portnumber) { + gdb_port_next = alloc_printf("%d", portnumber+1); + } else { + /* Don't increment if gdb_port is 0, since we're just + * trying to allocate an unused port. */ + gdb_port_next = strdup("0"); + } } } } @@ -3090,11 +3472,6 @@ static int gdb_target_add_one(struct target *target) int gdb_target_add_all(struct target *target) { - if (strcmp(gdb_port, "disabled") == 0) { - LOG_INFO("gdb server disabled"); - return ERROR_OK; - } - if (NULL == target) { LOG_WARNING("gdb services need one or more targets defined"); return ERROR_OK; @@ -3165,6 +3542,15 @@ COMMAND_HANDLER(handle_gdb_report_data_abort_command) return ERROR_OK; } +COMMAND_HANDLER(handle_gdb_report_register_access_error) +{ + if (CMD_ARGC != 1) + return ERROR_COMMAND_SYNTAX_ERROR; + + COMMAND_PARSE_ENABLE(CMD_ARGV[0], gdb_report_register_access_error); + return ERROR_OK; +} + /* gdb_breakpoint_override */ COMMAND_HANDLER(handle_gdb_breakpoint_override_command) { @@ -3286,6 +3672,13 @@ static const struct command_registration gdb_command_handlers[] = { .help = "enable or disable reporting data aborts", .usage = "('enable'|'disable')" }, + { + .name = "gdb_report_register_access_error", + .handler = handle_gdb_report_register_access_error, + .mode = COMMAND_CONFIG, + .help = "enable or disable reporting register access errors", + .usage = "('enable'|'disable')" + }, { .name = "gdb_breakpoint_override", .handler = handle_gdb_breakpoint_override_command, @@ -3316,3 +3709,9 @@ int gdb_register_commands(struct command_context *cmd_ctx) gdb_port_next = strdup("3333"); return register_commands(cmd_ctx, NULL, gdb_command_handlers); } + +void gdb_service_free(void) +{ + free(gdb_port); + free(gdb_port_next); +}