* 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 *
#include "gdb_server.h"
#include <target/image.h>
#include <jtag/jtag.h>
+#include "rtos/rtos.h"
+#include "target/smp.h"
/**
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
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;
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 );
}
}
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;
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;
}
}
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;
}
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);
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(
"ocd_gdb_restart %s",
target_name(target));
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]);
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
* then we increment the port number for the next target.
*/
char *end;
- strtol(gdb_port_next, &end, 0);
+ portnumber = strtol(gdb_port_next, &end, 0);
if (!*end)
{
if (parse_long(gdb_port_next, &portnumber) == ERROR_OK)