X-Git-Url: https://review.openocd.org/gitweb?p=openocd.git;a=blobdiff_plain;f=src%2Fserver%2Fgdb_server.c;h=8d84a991f2ee4058fff367c9eebe460c496fb86e;hp=9503a130a6cfb7b1b9e43c78abe7d2a91657bc22;hb=ebac7c963a76ba20b4e66b0525d12127295cdccb;hpb=c62fb3fa81efa46f073db46a7eb7f2a91b16909a diff --git a/src/server/gdb_server.c b/src/server/gdb_server.c index 9503a130a6..8d84a991f2 100644 --- a/src/server/gdb_server.c +++ b/src/server/gdb_server.c @@ -8,6 +8,12 @@ * 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,7 +41,8 @@ #include "gdb_server.h" #include #include - +#include "rtos/rtos.h" +#include "target/smp.h" /** * @file @@ -58,7 +65,7 @@ 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 @@ -69,7 +76,6 @@ struct gdb_connection bool mem_write_error; }; - #if 0 #define _DEBUG_GDB_IO_ #endif @@ -237,9 +243,7 @@ static int gdb_get_char_inner(struct connection *connection, int* next_char) } #ifdef _DEBUG_GDB_IO_ - debug_buffer = malloc(gdb_con->buf_cnt + 1); - memcpy(debug_buffer, gdb_con->buffer, gdb_con->buf_cnt); - debug_buffer[gdb_con->buf_cnt] = 0; + debug_buffer = strndup(gdb_con->buffer, gdb_con->buf_cnt); LOG_DEBUG("received '%s'", debug_buffer); free(debug_buffer); #endif @@ -381,9 +385,7 @@ static int gdb_put_packet_inner(struct connection *connection, while (1) { #ifdef _DEBUG_GDB_IO_ - debug_buffer = malloc(len + 1); - memcpy(debug_buffer, buffer, len); - debug_buffer[len] = 0; + debug_buffer = strndup(buffer, len); LOG_DEBUG("sending packet '$%s#%2.2x'", debug_buffer, my_checksum); free(debug_buffer); #endif @@ -479,7 +481,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; @@ -767,6 +769,7 @@ static void gdb_frontend_halted(struct target *target, struct connection *connec 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 ); } } @@ -833,8 +836,10 @@ 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); + /* 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); /* remove the initial ACK from the incoming buffer */ if ((retval = gdb_get_char(connection, &initial_ack)) != ERROR_OK) @@ -869,9 +874,16 @@ static int gdb_new_connection(struct connection *connection) 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)); + 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; } @@ -931,8 +943,9 @@ static void gdb_send_error(struct connection *connection, uint8_t the_error) } static int gdb_last_signal_packet(struct connection *connection, - struct target *target, char* packet, int packet_size) + char* packet, int packet_size) { + struct target *target = get_target_from_connection(connection); char sig_reply[4]; int signal_var; @@ -1016,8 +1029,9 @@ static void gdb_target_to_reg(struct target *target, } static int gdb_get_registers_packet(struct connection *connection, - struct target *target, char* packet, int packet_size) + char* packet, int packet_size) { + struct target *target = get_target_from_connection(connection); struct reg **reg_list; int reg_list_size; int retval; @@ -1030,6 +1044,12 @@ static int gdb_get_registers_packet(struct connection *connection, LOG_DEBUG("-"); #endif + if ((target->rtos != NULL) && + (ERROR_OK == rtos_get_gdb_reg_list(connection))) + { + return ERROR_OK; + } + if ((retval = target_get_gdb_reg_list(target, ®_list, ®_list_size)) != ERROR_OK) { return gdb_error(connection, retval); @@ -1037,28 +1057,32 @@ static int gdb_get_registers_packet(struct connection *connection, for (i = 0; i < reg_list_size; i++) { - reg_packet_size += reg_list[i]->size; + reg_packet_size += DIV_ROUND_UP(reg_list[i]->size, 8) * 2; } - reg_packet = malloc(DIV_ROUND_UP(reg_packet_size, 8) * 2); + assert(reg_packet_size > 0); + + reg_packet = malloc(reg_packet_size); 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]); gdb_str_to_target(target, reg_packet_p, reg_list[i]); reg_packet_p += DIV_ROUND_UP(reg_list[i]->size, 8) * 2; } #ifdef _DEBUG_GDB_IO_ { - char *reg_packet_p; - reg_packet_p = strndup(reg_packet, DIV_ROUND_UP(reg_packet_size, 8) * 2); - LOG_DEBUG("reg_packet: %s", reg_packet_p); - free(reg_packet_p); + char *reg_packet_p_debug; + reg_packet_p_debug = strndup(reg_packet, reg_packet_size); + LOG_DEBUG("reg_packet: %s", reg_packet_p_debug); + free(reg_packet_p_debug); } #endif - gdb_put_packet(connection, reg_packet, DIV_ROUND_UP(reg_packet_size, 8) * 2); + gdb_put_packet(connection, reg_packet, reg_packet_size); free(reg_packet); free(reg_list); @@ -1067,8 +1091,9 @@ static int gdb_get_registers_packet(struct connection *connection, } static int gdb_set_registers_packet(struct connection *connection, - struct target *target, char *packet, int packet_size) + char *packet, int packet_size) { + struct target *target = get_target_from_connection(connection); int i; struct reg **reg_list; int reg_list_size; @@ -1126,8 +1151,9 @@ static int gdb_set_registers_packet(struct connection *connection, } static int gdb_get_register_packet(struct connection *connection, - struct target *target, char *packet, int packet_size) + char *packet, int packet_size) { + struct target *target = get_target_from_connection(connection); char *reg_packet; int reg_num = strtoul(packet + 1, NULL, 16); struct reg **reg_list; @@ -1149,6 +1175,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]); @@ -1162,8 +1191,9 @@ static int gdb_get_register_packet(struct connection *connection, } static int gdb_set_register_packet(struct connection *connection, - struct target *target, char *packet, int packet_size) + char *packet, int packet_size) { + struct target *target = get_target_from_connection(connection); char *separator; uint8_t *bin_buf; int reg_num = strtoul(packet + 1, &separator, 16); @@ -1225,8 +1255,9 @@ static int gdb_error(struct connection *connection, int retval) * 8191 bytes by the looks of it. Why 8191 bytes instead of 8192????? */ static int gdb_read_memory_packet(struct connection *connection, - struct target *target, char *packet, int packet_size) + char *packet, int packet_size) { + struct target *target = get_target_from_connection(connection); char *separator; uint32_t addr = 0; uint32_t len = 0; @@ -1300,8 +1331,9 @@ static int gdb_read_memory_packet(struct connection *connection, } static int gdb_write_memory_packet(struct connection *connection, - struct target *target, char *packet, int packet_size) + char *packet, int packet_size) { + struct target *target = get_target_from_connection(connection); char *separator; uint32_t addr = 0; uint32_t len = 0; @@ -1358,8 +1390,9 @@ static int gdb_write_memory_packet(struct connection *connection, } static int gdb_write_memory_binary_packet(struct connection *connection, - struct target *target, char *packet, int packet_size) + char *packet, int packet_size) { + struct target *target = get_target_from_connection(connection); char *separator; uint32_t addr = 0; uint32_t len = 0; @@ -1422,8 +1455,9 @@ static int gdb_write_memory_binary_packet(struct connection *connection, } static int gdb_step_continue_packet(struct connection *connection, - struct target *target, char *packet, int packet_size) + char *packet, int packet_size) { + struct target *target = get_target_from_connection(connection); int current = 0; uint32_t address = 0x0; int retval = ERROR_OK; @@ -1456,8 +1490,9 @@ static int gdb_step_continue_packet(struct connection *connection, } static int gdb_breakpoint_watchpoint_packet(struct connection *connection, - struct target *target, char *packet, int packet_size) + char *packet, int packet_size) { + struct target *target = get_target_from_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 */; @@ -1650,7 +1685,7 @@ static int compare_bank (const void * a, const void * b) } static int gdb_memory_map(struct connection *connection, - struct target *target, char *packet, int packet_size) + char *packet, int packet_size) { /* We get away with only specifying flash here. Regions that are not * specified are treated as if we provided no memory map(if not we @@ -1659,6 +1694,7 @@ static int gdb_memory_map(struct connection *connection, * have to regenerate it a couple of times. */ + struct target *target = get_target_from_connection(connection); struct flash_bank *p; char *xml = NULL; int size = 0; @@ -1704,14 +1740,13 @@ static int gdb_memory_map(struct connection *connection, qsort(banks, target_flash_banks, sizeof(struct flash_bank *), compare_bank); - for (i = 0; i < flash_get_bank_count(); i++) { + for (i = 0; i < target_flash_banks; 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, @@ -1795,10 +1830,11 @@ static int gdb_memory_map(struct connection *connection, } static int gdb_query_packet(struct connection *connection, - struct target *target, char *packet, int packet_size) + char *packet, int packet_size) { struct command_context *cmd_ctx = connection->cmd_ctx; struct gdb_connection *gdb_connection = connection->priv; + struct target *target = get_target_from_connection(connection); if (strstr(packet, "qRcmd,")) { @@ -1896,7 +1932,7 @@ static int gdb_query_packet(struct connection *connection, } else if (strstr(packet, "qXfer:memory-map:read::") && (flash_get_bank_count() > 0)) - return gdb_memory_map(connection, target, packet, packet_size); + return gdb_memory_map(connection, packet, packet_size); else if (strstr(packet, "qXfer:features:read:")) { char *xml = NULL; @@ -1949,7 +1985,7 @@ static int gdb_query_packet(struct connection *connection, } static int gdb_v_packet(struct connection *connection, - struct target *target, char *packet, int packet_size) + char *packet, int packet_size) { struct gdb_connection *gdb_connection = connection->priv; struct gdb_service *gdb_service = connection->service->priv; @@ -2096,7 +2132,7 @@ static int gdb_v_packet(struct connection *connection, return ERROR_OK; } -static int gdb_detach(struct connection *connection, struct target *target) +static int gdb_detach(struct connection *connection) { struct gdb_service *gdb_service = connection->service->priv; @@ -2183,59 +2219,49 @@ 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, packet, packet_size); + break; + case 'H': // Set current thread ( 'c' for step and continue, 'g' for all other operations ) + gdb_thread_packet(connection, packet, packet_size); + break; case 'q': case 'Q': - retval = gdb_query_packet(connection, - target, packet, - packet_size); + retval = gdb_thread_packet(connection, packet, packet_size); + if ( retval == GDB_THREAD_PACKET_NOT_CONSUMED ) + { + retval = gdb_query_packet(connection, packet, packet_size); + } break; case 'g': - retval = gdb_get_registers_packet( - connection, target, - packet, packet_size); + retval = gdb_get_registers_packet(connection, packet, packet_size); break; case 'G': - retval = gdb_set_registers_packet( - connection, target, - packet, packet_size); + retval = gdb_set_registers_packet(connection, packet, packet_size); break; case 'p': - retval = gdb_get_register_packet( - connection, target, - packet, packet_size); + retval = gdb_get_register_packet(connection, packet, packet_size); break; case 'P': - retval = gdb_set_register_packet( - connection, target, - packet, packet_size); + retval = gdb_set_register_packet(connection, packet, packet_size); break; case 'm': - retval = gdb_read_memory_packet( - connection, target, - packet, packet_size); + retval = gdb_read_memory_packet(connection, packet, packet_size); break; case 'M': - retval = gdb_write_memory_packet( - connection, target, - packet, packet_size); + retval = gdb_write_memory_packet(connection, packet, packet_size); break; case 'z': case 'Z': - retval = gdb_breakpoint_watchpoint_packet(connection, target, packet, packet_size); + retval = gdb_breakpoint_watchpoint_packet(connection, packet, packet_size); break; case '?': - gdb_last_signal_packet( - connection, target, - packet, packet_size); + gdb_last_signal_packet(connection, packet, packet_size); break; case 'c': case 's': { + gdb_thread_packet(connection, packet, packet_size); log_add_callback(gdb_log_callback, connection); if (gdb_con->mem_write_error) @@ -2294,7 +2320,7 @@ static int gdb_input_inner(struct connection *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); + retval = gdb_step_continue_packet(connection, packet, packet_size); if (retval != ERROR_OK) { /* we'll never receive a halted condition... issue a false one.. */ @@ -2305,18 +2331,14 @@ static int gdb_input_inner(struct connection *connection) } break; case 'v': - retval = gdb_v_packet( - connection, target, - packet, packet_size); + retval = gdb_v_packet(connection, packet, packet_size); break; case 'D': - retval = gdb_detach(connection, target); + retval = gdb_detach(connection); extended_protocol = 0; break; case 'X': - retval = gdb_write_memory_binary_packet( - connection, target, - packet, packet_size); + retval = gdb_write_memory_binary_packet(connection, packet, packet_size); if (retval != ERROR_OK) return retval; break; @@ -2337,7 +2359,22 @@ 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, 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, packet, packet_size); break; + default: /* ignore unknown packets */ LOG_DEBUG("ignoring 0x%2.2x packet", packet[0]); @@ -2389,19 +2426,41 @@ static int gdb_input(struct connection *connection) static int gdb_target_start(struct target *target, const char *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; - return add_service("gdb", + ret = add_service("gdb", port, 1, &gdb_new_connection, &gdb_input, &gdb_connection_closed, gdb_service); + /* 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) { + /* 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) {