X-Git-Url: https://review.openocd.org/gitweb?p=openocd.git;a=blobdiff_plain;f=src%2Fserver%2Fgdb_server.c;h=77142dfadec8acfd5c2ebf41560cd491ded3ca38;hp=275d41468daa40597fb2ea40cd0d3506c9300be0;hb=33a17fd35995a7f679f92600055a8f55ae380022;hpb=82ea640830fe13f9ab8ef33c65a76480b697f856 diff --git a/src/server/gdb_server.c b/src/server/gdb_server.c index 275d41468d..77142dfade 100644 --- a/src/server/gdb_server.c +++ b/src/server/gdb_server.c @@ -80,8 +80,8 @@ static int gdb_breakpoint_override; static enum breakpoint_type gdb_breakpoint_override_type; static int gdb_error(struct connection *connection, int retval); -static unsigned short gdb_port = 3333; -static unsigned short gdb_port_next = 0; +static const char *gdb_port; +static const char *gdb_port_next; static const char DIGITS[16] = "0123456789abcdef"; static void gdb_log_callback(void *priv, const char *file, unsigned line, @@ -171,9 +171,12 @@ static int gdb_get_char_inner(struct connection *connection, int* next_char) struct gdb_connection *gdb_con = connection->priv; int retval = ERROR_OK; +#ifdef _DEBUG_GDB_IO_ + char *debug_buffer; +#endif for (;;) { - if (connection->service->type == CONNECTION_PIPE) + if (connection->service->type != CONNECTION_TCP) { gdb_con->buf_cnt = read(connection->fd, gdb_con->buffer, GDB_BUFFER_SIZE); } @@ -325,20 +328,9 @@ static int gdb_write(struct connection *connection, void *data, int len) if (gdb_con->closed) return ERROR_SERVER_REMOTE_CLOSED; - if (connection->service->type == CONNECTION_PIPE) + if (connection_write(connection, data, len) == len) { - /* write to stdout */ - if (write(STDOUT_FILENO, data, len) == len) - { - return ERROR_OK; - } - } - else - { - if (write_socket(connection->fd, data, len) == len) - { - return ERROR_OK; - } + return ERROR_OK; } gdb_con->closed = 1; return ERROR_SERVER_REMOTE_CLOSED; @@ -757,22 +749,22 @@ static void gdb_frontend_halted(struct target *target, struct connection *connec if (gdb_connection->frontend_state == TARGET_RUNNING) { char sig_reply[4]; - int signal; + int signal_var; /* stop forwarding log packets! */ log_remove_callback(gdb_log_callback, connection); if (gdb_connection->ctrl_c) { - signal = 0x2; + signal_var = 0x2; gdb_connection->ctrl_c = 0; } else { - signal = gdb_last_signal(target); + signal_var = gdb_last_signal(target); } - snprintf(sig_reply, 4, "T%2.2x", signal); + snprintf(sig_reply, 4, "T%2.2x", signal_var); gdb_put_packet(connection, sig_reply, 3); gdb_connection->frontend_state = TARGET_HALTED; } @@ -841,9 +833,6 @@ static int gdb_new_connection(struct connection *connection) breakpoint_clear_target(gdb_service->target); watchpoint_clear_target(gdb_service->target); - /* register callback to be informed about target events */ - target_register_event_callback(gdb_target_callback_event_handler, connection); - /* remove the initial ACK from the incoming buffer */ if ((retval = gdb_get_char(connection, &initial_ack)) != ERROR_OK) return retval; @@ -869,7 +858,7 @@ static int gdb_new_connection(struct connection *connection) retval = get_flash_bank_by_num(i, &p); if (retval != ERROR_OK) { - LOG_ERROR("Connect failed. Consider setting up a gdb-attach event for the target to prepare target for GDB connect."); + LOG_ERROR("Connect failed. Consider setting up a gdb-attach event for the target to prepare target for GDB connect, or use 'gdb_memory_map disable'."); return retval; } } @@ -881,6 +870,13 @@ static int gdb_new_connection(struct connection *connection) target_name(gdb_service->target), target_state_name(gdb_service->target)); + /* DANGER! If we fail subsequently, we must remove this handler, + * otherwise we occasionally see crashes as the timer can invoke the + * callback fn. + * + * register callback to be informed about target events */ + target_register_event_callback(gdb_target_callback_event_handler, connection); + return ERROR_OK; } @@ -942,11 +938,11 @@ static int gdb_last_signal_packet(struct connection *connection, struct target *target, char* packet, int packet_size) { char sig_reply[4]; - int signal; + int signal_var; - signal = gdb_last_signal(target); + signal_var = gdb_last_signal(target); - snprintf(sig_reply, 4, "S%2.2x", signal); + snprintf(sig_reply, 4, "S%2.2x", signal_var); gdb_put_packet(connection, sig_reply, 3); return ERROR_OK; @@ -1216,29 +1212,14 @@ static int gdb_set_register_packet(struct connection *connection, return ERROR_OK; } +/* No attempt is made to translate the "retval" to + * GDB speak. This has to be done at the calling + * site as no mapping really exists. + */ static int gdb_error(struct connection *connection, int retval) { - switch (retval) - { - case ERROR_TARGET_DATA_ABORT: - gdb_send_error(connection, EIO); - break; - case ERROR_TARGET_TRANSLATION_FAULT: - gdb_send_error(connection, EFAULT); - break; - case ERROR_TARGET_UNALIGNED_ACCESS: - gdb_send_error(connection, EFAULT); - break; - case ERROR_TARGET_NOT_HALTED: - gdb_send_error(connection, EFAULT); - break; - default: - /* This could be that the target reset itself. */ - LOG_ERROR("unexpected error %i", retval); - gdb_send_error(connection, EFAULT); - break; - } - + LOG_DEBUG("Reporting %i to GDB as generic error", retval); + gdb_send_error(connection, EFAULT); return ERROR_OK; } @@ -1693,6 +1674,7 @@ static int gdb_memory_map(struct connection *connection, char *separator; uint32_t ram_start = 0; int i; + int target_flash_banks = 0; /* skip command character */ packet += 23; @@ -1716,13 +1698,14 @@ static int gdb_memory_map(struct connection *connection, if (retval != ERROR_OK) { free(banks); - gdb_send_error(connection, retval); + gdb_error(connection, retval); return retval; } - banks[i] = p; + if(p->target == target) + banks[target_flash_banks++] = p; } - qsort(banks, flash_get_bank_count(), sizeof(struct flash_bank *), + qsort(banks, target_flash_banks, sizeof(struct flash_bank *), compare_bank); for (i = 0; i < flash_get_bank_count(); i++) { @@ -1798,7 +1781,7 @@ static int gdb_memory_map(struct connection *connection, xml_printf(&retval, &xml, &pos, &size, "\n"); if (retval != ERROR_OK) { - gdb_send_error(connection, retval); + gdb_error(connection, retval); return retval; } @@ -1949,7 +1932,7 @@ static int gdb_query_packet(struct connection *connection, if (retval != ERROR_OK) { - gdb_send_error(connection, retval); + gdb_error(connection, retval); return retval; } @@ -2163,7 +2146,17 @@ static int gdb_input_inner(struct connection *connection) struct gdb_connection *gdb_con = connection->priv; static int extended_protocol = 0; - /* drain input buffer */ + /* drain input buffer. If one of the packets fail, then an error + * packet is replied, if applicable. + * + * This loop will terminate and the error code is returned. + * + * The calling fn will check if this error is something that + * can be recovered from, or if the connection must be closed. + * + * If the error is recoverable, this fn is called again to + * drain the rest of the buffer. + */ do { packet_size = GDB_BUFFER_SIZE-1; @@ -2247,9 +2240,6 @@ static int gdb_input_inner(struct connection *connection) case 'c': case 's': { - int retval = ERROR_OK; - - struct gdb_connection *gdb_con = connection->priv; log_add_callback(gdb_log_callback, connection); if (gdb_con->mem_write_error) @@ -2283,7 +2273,7 @@ static int gdb_input_inner(struct connection *connection) } gdb_con->sync = false; - if ((retval!=ERROR_OK) || (!already_running && nostep)) + if (!already_running && nostep) { /* Either the target isn't in the halted state, then we can't * step/continue. This might be early setup, etc. @@ -2306,7 +2296,9 @@ static int gdb_input_inner(struct connection *connection) if (!already_running) { - int retval = gdb_step_continue_packet(connection, target, packet, packet_size); + /* Here we don't want packet processing to stop even if this fails, + * so we use a local variable instead of retval. */ + retval = gdb_step_continue_packet(connection, target, packet, packet_size); if (retval != ERROR_OK) { /* we'll never receive a halted condition... issue a false one.. */ @@ -2399,55 +2391,40 @@ static int gdb_input(struct connection *connection) return ERROR_OK; } -static int gdb_target_start(struct target *target, uint16_t port) +static int gdb_target_start(struct target *target, const char *port) { - bool use_pipes = 0 == port; struct gdb_service *gdb_service = malloc(sizeof(struct gdb_service)); if (NULL == gdb_service) return -ENOMEM; gdb_service->target = target; - add_service("gdb", use_pipes ? CONNECTION_PIPE : CONNECTION_TCP, + return add_service("gdb", port, 1, &gdb_new_connection, &gdb_input, &gdb_connection_closed, gdb_service); - - const char *name = target_name(target); - if (use_pipes) - LOG_DEBUG("gdb service for target '%s' using pipes", name); - else - LOG_DEBUG("gdb service for target '%s' on TCP port %u", name, port); - return ERROR_OK; } static int gdb_target_add_one(struct target *target) { - if (gdb_port == 0 && server_use_pipes == 0) - { - LOG_INFO("gdb port disabled"); - return ERROR_OK; - } - if (0 == gdb_port_next) - gdb_port_next = gdb_port; - - bool use_pipes = server_use_pipes; - static bool server_started_with_pipes = false; - if (server_started_with_pipes) - { - LOG_WARNING("gdb service permits one target when using pipes"); - if (0 == gdb_port) - return ERROR_OK; - - use_pipes = false; - } - - int e = gdb_target_start(target, use_pipes ? 0 : gdb_port_next); - if (ERROR_OK == e) + int retval = gdb_target_start(target, gdb_port_next); + if (retval == ERROR_OK) { - server_started_with_pipes |= use_pipes; - gdb_port_next++; + long portnumber; + /* If we can parse the port number + * then we increment the port number for the next target. + */ + char *end; + portnumber = strtol(gdb_port_next, &end, 0); + if (!*end) + { + if (parse_long(gdb_port_next, &portnumber) == ERROR_OK) + { + free((void *)gdb_port_next); + gdb_port_next = alloc_printf("%d", portnumber+1); + } + } } - return e; + return retval; } int gdb_target_add_all(struct target *target) @@ -2492,34 +2469,39 @@ COMMAND_HANDLER(handle_gdb_sync_command) /* daemon configuration command gdb_port */ COMMAND_HANDLER(handle_gdb_port_command) { - int retval = CALL_COMMAND_HANDLER(server_port_command, &gdb_port); - if (ERROR_OK == retval) - gdb_port_next = gdb_port; + int retval = CALL_COMMAND_HANDLER(server_pipe_command, &gdb_port); + if (ERROR_OK == retval) { + free((void*)gdb_port_next); + gdb_port_next = strdup(gdb_port); + } return retval; } COMMAND_HANDLER(handle_gdb_memory_map_command) { - if (CMD_ARGC == 1) - COMMAND_PARSE_ENABLE(CMD_ARGV[0], gdb_use_memory_map); + if (CMD_ARGC != 1) + return ERROR_COMMAND_SYNTAX_ERROR; - return ERROR_COMMAND_SYNTAX_ERROR; + COMMAND_PARSE_ENABLE(CMD_ARGV[0], gdb_use_memory_map); + return ERROR_OK; } COMMAND_HANDLER(handle_gdb_flash_program_command) { - if (CMD_ARGC == 1) - COMMAND_PARSE_ENABLE(CMD_ARGV[0], gdb_flash_program); + if (CMD_ARGC != 1) + return ERROR_COMMAND_SYNTAX_ERROR; - return ERROR_COMMAND_SYNTAX_ERROR; + COMMAND_PARSE_ENABLE(CMD_ARGV[0], gdb_flash_program); + return ERROR_OK; } COMMAND_HANDLER(handle_gdb_report_data_abort_command) { - if (CMD_ARGC == 1) - COMMAND_PARSE_ENABLE(CMD_ARGV[0], gdb_report_data_abort); + if (CMD_ARGC != 1) + return ERROR_COMMAND_SYNTAX_ERROR; - return ERROR_COMMAND_SYNTAX_ERROR; + COMMAND_PARSE_ENABLE(CMD_ARGV[0], gdb_report_data_abort); + return ERROR_OK; } /* gdb_breakpoint_override */ @@ -2569,9 +2551,13 @@ static const struct command_registration gdb_command_handlers[] = { .name = "gdb_port", .handler = handle_gdb_port_command, .mode = COMMAND_ANY, - .help = "Display or specify base port on which to listen " - "for incoming GDB connections. " - "No arguments reports GDB port; zero disables.", + .help = "Normally gdb listens to a TCP/IP port. Each subsequent GDB " + "server listens for the next port number after the " + "base port number specified. " + "No arguments reports GDB port. \"pipe\" means listen to stdin " + "output to stdout, an integer is base port number, \"disable\" disables " + "port. Any other string is are interpreted as named pipe to listen to. " + "Output pipe is the same name as input pipe, but with 'o' appended.", .usage = "[port_num]", }, { @@ -2608,5 +2594,7 @@ static const struct command_registration gdb_command_handlers[] = { int gdb_register_commands(struct command_context *cmd_ctx) { + gdb_port = strdup("3333"); + gdb_port_next = strdup("3333"); return register_commands(cmd_ctx, NULL, gdb_command_handlers); }