X-Git-Url: https://review.openocd.org/gitweb?p=openocd.git;a=blobdiff_plain;f=src%2Fserver%2Fgdb_server.c;h=b6921ff25f304d5ff52891649d7096fec90b4036;hp=222af47a0486ebc2dcab316d8d4a3429e9d94325;hb=f6315d5e5b7b71515ef051711e5f818a42d6b3b3;hpb=6229e438dd548ae75f9d26e2ea8cbf070ce27e5f diff --git a/src/server/gdb_server.c b/src/server/gdb_server.c index 222af47a04..b6921ff25f 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,6 +41,8 @@ #include "gdb_server.h" #include #include +#include "rtos/rtos.h" +#include "target/smp.h" /** @@ -58,7 +66,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 @@ -479,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; @@ -767,6 +775,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,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; @@ -861,7 +867,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; } } @@ -873,6 +879,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; } @@ -1030,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); @@ -1045,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; } @@ -1149,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]); @@ -1707,11 +1731,10 @@ static int gdb_memory_map(struct connection *connection, 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, @@ -2183,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( @@ -2337,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]); @@ -2389,21 +2438,43 @@ 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) + if (retval == ERROR_OK) { long portnumber; /* If we can parse the port number