X-Git-Url: https://review.openocd.org/gitweb?p=openocd.git;a=blobdiff_plain;f=src%2Fserver%2Fgdb_server.c;h=b6921ff25f304d5ff52891649d7096fec90b4036;hp=f3e0575904b00fb464781aed65cfa6b2b15deb51;hb=f6315d5e5b7b71515ef051711e5f818a42d6b3b3;hpb=6f2b88448fff59d00f625d0d361a7b9abf6bd673 diff --git a/src/server/gdb_server.c b/src/server/gdb_server.c index f3e0575904..b6921ff25f 100644 --- a/src/server/gdb_server.c +++ b/src/server/gdb_server.c @@ -2,12 +2,18 @@ * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * - * Copyright (C) 2007-2009 Øyvind Harboe * + * Copyright (C) 2007-2010 Øyvind Harboe * * oyvind.harboe@zylin.com * * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * * * + * Copyright (C) 2011 by Broadcom Corporation * + * Evan Hunter - ehunter@broadcom.com * + * * + * Copyright (C) ST-Ericsson SA 2011 * + * michel.jaouen@stericsson.com : smp minimum support * + * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * @@ -35,6 +41,8 @@ #include "gdb_server.h" #include #include +#include "rtos/rtos.h" +#include "target/smp.h" /** @@ -58,10 +66,15 @@ struct gdb_connection int closed; int busy; int noack_mode; - bool sync; /* set flag to true if you want the next stepi to return immediately. + bool sync; /* 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 without modifying the target state. */ - + /* We delay reporting memory write errors until next step/continue or memory + * write. This improves performance of gdb load significantly as the GDB packet + * can be replied immediately and a new GDB packet will be ready without delay + * (ca. 10% or so...). + */ + bool mem_write_error; }; @@ -75,8 +88,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, @@ -166,9 +179,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); } @@ -320,20 +336,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) - { - /* write to stdout */ - if (write(STDOUT_FILENO, data, len) == len) - { - return ERROR_OK; - } - } - else + if (connection_write(connection, data, len) == len) { - if (write_socket(connection->fd, data, len) == len) - { - return ERROR_OK; - } + return ERROR_OK; } gdb_con->closed = 1; return ERROR_SERVER_REMOTE_CLOSED; @@ -482,7 +487,7 @@ static int gdb_put_packet_inner(struct connection *connection, return ERROR_OK; } -static int gdb_put_packet(struct connection *connection, char *buffer, int len) +int gdb_put_packet(struct connection *connection, char *buffer, int len) { struct gdb_connection *gdb_con = connection->priv; gdb_con->busy = 1; @@ -752,24 +757,25 @@ 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; + rtos_update_threads( target ); } } @@ -821,6 +827,7 @@ static int gdb_new_connection(struct connection *connection) gdb_connection->busy = 0; gdb_connection->noack_mode = 0; gdb_connection->sync = true; + gdb_connection->mem_write_error = false; /* send ACK to GDB for debug request */ gdb_write(connection, "+", 1); @@ -835,9 +842,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; @@ -849,12 +853,39 @@ static int gdb_new_connection(struct connection *connection) gdb_putback_char(connection, initial_ack); target_call_event_callbacks(gdb_service->target, TARGET_EVENT_GDB_ATTACH); + if (gdb_use_memory_map) + { + /* Connect must fail if the memory map can't be set up correctly. + * + * This will cause an auto_probe to be invoked, which is either + * a no-op or it will fail when the target isn't ready(e.g. not halted). + */ + int i; + for (i = 0; i < flash_get_bank_count(); i++) + { + struct flash_bank *p; + 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, or use 'gdb_memory_map disable'."); + return retval; + } + } + } + gdb_actual_connections++; LOG_DEBUG("New GDB Connection: %d, Target %s, state: %s", gdb_actual_connections, 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; } @@ -916,11 +947,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; @@ -1012,6 +1043,12 @@ static int gdb_get_registers_packet(struct connection *connection, LOG_DEBUG("-"); #endif + if ( ( target->rtos != NULL ) && + ( ERROR_FAIL != rtos_get_gdb_reg_list( connection, target, ®_list, ®_list_size) ) ) + { + return ERROR_OK; + } + if ((retval = target_get_gdb_reg_list(target, ®_list, ®_list_size)) != ERROR_OK) { return gdb_error(connection, retval); @@ -1027,6 +1064,8 @@ static int gdb_get_registers_packet(struct connection *connection, for (i = 0; i < reg_list_size; i++) { + if (!reg_list[i]->valid) + reg_list[i]->type->get(reg_list[i]); gdb_str_to_target(target, reg_packet_p, reg_list[i]); reg_packet_p += DIV_ROUND_UP(reg_list[i]->size, 8) * 2; } @@ -1131,6 +1170,9 @@ static int gdb_get_register_packet(struct connection *connection, exit(-1); } + if (!reg_list[reg_num]->valid) + reg_list[reg_num]->type->get(reg_list[reg_num]); + reg_packet = malloc(DIV_ROUND_UP(reg_list[reg_num]->size, 8) * 2); gdb_str_to_target(target, reg_packet, reg_list[reg_num]); @@ -1190,29 +1232,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; } @@ -1361,7 +1388,7 @@ static int gdb_write_memory_binary_packet(struct connection *connection, uint32_t addr = 0; uint32_t len = 0; - int retval; + int retval = ERROR_OK; /* skip command character */ packet++; @@ -1382,14 +1409,18 @@ static int gdb_write_memory_binary_packet(struct connection *connection, return ERROR_SERVER_REMOTE_CLOSED; } - retval = ERROR_OK; - if (len) - { - LOG_DEBUG("addr: 0x%8.8" PRIx32 ", len: 0x%8.8" PRIx32 "", addr, len); + struct gdb_connection *gdb_connection = connection->priv; - retval = target_write_buffer(target, addr, len, (uint8_t*)separator); + if (gdb_connection->mem_write_error) + { + retval = ERROR_FAIL; + /* now that we have reported the memory write error, we can clear the condition */ + gdb_connection->mem_write_error = false; } + /* By replying the packet *immediately* GDB will send us a new packet + * while we write the last one to the target. + */ if (retval == ERROR_OK) { gdb_put_packet(connection, "OK", 2); @@ -1400,6 +1431,17 @@ static int gdb_write_memory_binary_packet(struct connection *connection, return retval; } + if (len) + { + LOG_DEBUG("addr: 0x%8.8" PRIx32 ", len: 0x%8.8" PRIx32 "", addr, len); + + retval = target_write_buffer(target, addr, len, (uint8_t*)separator); + if (retval != ERROR_OK) + { + gdb_connection->mem_write_error = true; + } + } + return ERROR_OK; } @@ -1652,6 +1694,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; @@ -1671,27 +1714,27 @@ static int gdb_memory_map(struct connection *connection, banks = malloc(sizeof(struct flash_bank *)*flash_get_bank_count()); for (i = 0; i < flash_get_bank_count(); i++) { - p = get_flash_bank_by_num(i); - if (p == NULL) { + retval = get_flash_bank_by_num(i, &p); + if (retval != ERROR_OK) + { free(banks); - retval = ERROR_FAIL; - 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++) { int j; unsigned sector_size = 0; - uint32_t start, end; + uint32_t start; p = banks[i]; start = p->base; - end = p->base + p->size; if (ram_start < p->base) xml_printf(&retval, &xml, &pos, &size, @@ -1757,7 +1800,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; } @@ -1908,7 +1951,7 @@ static int gdb_query_packet(struct connection *connection, if (retval != ERROR_OK) { - gdb_send_error(connection, retval); + gdb_error(connection, retval); return retval; } @@ -2122,7 +2165,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; @@ -2153,16 +2206,23 @@ static int gdb_input_inner(struct connection *connection) retval = ERROR_OK; switch (packet[0]) { - case 'H': - /* Hct... -- set thread - * we don't have threads, send empty reply */ - gdb_put_packet(connection, NULL, 0); - break; + case 'T': // Is thread alive? + gdb_thread_packet(connection, target, packet, packet_size); + break; + case 'H': // Set current thread ( 'c' for step and continue, 'g' for all other operations ) + gdb_thread_packet(connection, target, packet, packet_size); + break; case 'q': case 'Q': - retval = gdb_query_packet(connection, - target, packet, - packet_size); + retval = gdb_thread_packet(connection, + target, packet, + packet_size); + if ( retval == GDB_THREAD_PACKET_NOT_CONSUMED ) + { + retval = gdb_query_packet(connection, + target, packet, + packet_size); + } break; case 'g': retval = gdb_get_registers_packet( @@ -2206,18 +2266,24 @@ 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) + { + LOG_ERROR("Memory write failure!"); + + /* now that we have reported the memory write error, we can clear the condition */ + gdb_con->mem_write_error = false; + } + bool nostep = false; + bool already_running = false; if (target->state == TARGET_RUNNING) { - LOG_WARNING("The target is already running. Halt target before stepi/continue."); - retval = target_halt(target); - if (retval == ERROR_OK) - retval = target_wait_state(target, TARGET_HALTED, 100); + LOG_WARNING("WARNING! The target is already running. " + "All changes GDB did to registers will be discarded! " + "Waiting for target to halt."); + already_running = true; } else if (target->state != TARGET_HALTED) { LOG_WARNING("The target is not in the halted nor running stated, stepi/continue ignored."); @@ -2233,7 +2299,7 @@ static int gdb_input_inner(struct connection *connection) } gdb_con->sync = false; - if ((retval!=ERROR_OK) || 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. @@ -2253,11 +2319,17 @@ static int gdb_input_inner(struct connection *connection) */ gdb_con->frontend_state = TARGET_RUNNING; target_call_event_callbacks(target, TARGET_EVENT_GDB_START); - int retval = gdb_step_continue_packet(connection, target, packet, packet_size); - if (retval != ERROR_OK) + + if (!already_running) { - /* we'll never receive a halted condition... issue a false one.. */ - gdb_frontend_halted(target, connection); + /* 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.. */ + gdb_frontend_halted(target, connection); + } } } } @@ -2295,7 +2367,26 @@ static int gdb_input_inner(struct connection *connection) command_run_linef(connection->cmd_ctx, "ocd_gdb_restart %s", target_name(target)); + gdb_put_packet(connection, "OK", 2); + break; + + case 'j': + /* packet supported only by smp target i.e cortex_a.c*/ + /* handle smp packet replying coreid played to gbd */ + gdb_read_smp_packet( + connection, target, + packet, packet_size); + break; + + case 'J': + /* packet supported only by smp target i.e cortex_a.c */ + /* handle smp packet setting coreid to be played at next + * resume to gdb */ + gdb_write_smp_packet( + connection, target, + packet, packet_size); break; + default: /* ignore unknown packets */ LOG_DEBUG("ignoring 0x%2.2x packet", packet[0]); @@ -2345,55 +2436,62 @@ 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)); + + struct gdb_service *gdb_service; + int ret; + gdb_service = malloc(sizeof(struct gdb_service)); + if (NULL == gdb_service) return -ENOMEM; gdb_service->target = target; + gdb_service->core[0] = -1; + gdb_service->core[1] = -1; + target->gdb_service = gdb_service; - add_service("gdb", use_pipes ? CONNECTION_PIPE : CONNECTION_TCP, + ret = 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; + /* initialialize 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; + if (curr != target) curr->gdb_service = gdb_service; + head = head->next; + } + } + return ret; } 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) - { - server_started_with_pipes |= use_pipes; - gdb_port_next++; + /* 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) + { + 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) @@ -2438,34 +2536,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 */ @@ -2515,9 +2618,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]", }, { @@ -2554,5 +2661,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); }