* Copyright (C) 2005 by Dominic Rath *
* Dominic.Rath@gmx.de *
* *
- * Copyright (C) 2007,2008 Øyvind Harboe *
+ * Copyright (C) 2007,2008 Øyvind Harboe *
* oyvind.harboe@zylin.com *
* *
* This program is free software; you can redistribute it and/or modify *
#define _DEBUG_GDB_IO_
#endif
+static int gdb_breakpoint_override;
+static enum breakpoint_type gdb_breakpoint_override_type;
+
extern int gdb_error(connection_t *connection, int retval);
static unsigned short gdb_port;
static const char *DIGITS = "0123456789abcdef";
gdb_write(connection, buffer, len);
gdb_write(connection, local_buffer+1, 3);
}
-
+
+ if (gdb_con->noack_mode)
+ break;
+
if ((retval = gdb_get_char(connection, &reply)) != ERROR_OK)
return retval;
i++;
my_checksum += character & 0xff;
buffer[count++] = (character ^ 0x20) & 0xff;
- } else
+ }
+ else
{
my_checksum += character & 0xff;
buffer[count++] = character & 0xff;
my_checksum += character & 0xff;
buffer[count++] = character & 0xff;
}
-
}
*len = count;
if (my_checksum == strtoul(checksum, NULL, 16))
{
+ if (gdb_con->noack_mode)
+ break;
gdb_write(connection, "+", 1);
break;
}
- LOG_WARNING("checksum error, requesting retransmission");
- gdb_write(connection, "-", 1);
+ if (!gdb_con->noack_mode)
+ {
+ LOG_WARNING("checksum error, requesting retransmission");
+ gdb_write(connection, "-", 1);
+ }
+ else
+ {
+ LOG_WARNING("checksum error, no-ack-mode");
+ break;
+ }
}
if (gdb_con->closed)
return ERROR_SERVER_REMOTE_CLOSED;
case TARGET_EVENT_HALTED:
gdb_frontend_halted(target, connection);
break;
- case TARGET_EVENT_GDB_PROGRAM:
+ case TARGET_EVENT_GDB_FLASH_ERASE_START:
gdb_program_handler(target, event, connection->cmd_ctx);
break;
default:
gdb_connection->vflash_image = NULL;
gdb_connection->closed = 0;
gdb_connection->busy = 0;
+ gdb_connection->noack_mode = 0;
/* send ACK to GDB for debug request */
gdb_write(connection, "+", 1);
wp_type = WPT_READ;
else if (type == 4) /* access watchpoint */
wp_type = WPT_ACCESS;
+
+ if (gdb_breakpoint_override&&((bp_type==BKPT_SOFT)||(bp_type==BKPT_HARD)))
+ {
+ bp_type=gdb_breakpoint_override_type;
+ }
if (*separator != ',')
{
int gdb_query_packet(connection_t *connection, target_t *target, char *packet, int packet_size)
{
command_context_t *cmd_ctx = connection->cmd_ctx;
-
+ gdb_connection_t *gdb_connection = connection->priv;
+
if (strstr(packet, "qRcmd,"))
{
if (packet_size > 6)
int size = 0;
xml_printf(&retval, &buffer, &pos, &size,
- "PacketSize=%x;qXfer:memory-map:read%c;qXfer:features:read-",
+ "PacketSize=%x;qXfer:memory-map:read%c;qXfer:features:read-;QStartNoAckMode+",
(GDB_BUFFER_SIZE - 1), ((gdb_use_memory_map == 1)&&(flash_get_bank_count()>0)) ? '+' : '-');
if (retval != ERROR_OK)
free(xml);
return ERROR_OK;
}
+ else if (strstr(packet, "QStartNoAckMode"))
+ {
+ gdb_connection->noack_mode = 1;
+ gdb_put_packet(connection, "OK", 2);
+ return ERROR_OK;
+ }
gdb_put_packet(connection, "", 0);
return ERROR_OK;
flash_set_dirty();
/* perform any target specific operations before the erase */
- target_call_event_callbacks(gdb_service->target, TARGET_EVENT_GDB_PROGRAM);
+ target_call_event_callbacks(gdb_service->target, TARGET_EVENT_GDB_FLASH_ERASE_START);
/* perform erase */
if ((result = flash_erase_address_range(gdb_service->target, addr, length)) != ERROR_OK)
gdb_put_packet(connection, NULL, 0);
break;
case 'q':
+ case 'Q':
retval = gdb_query_packet(connection, target, packet, packet_size);
break;
case 'g':
break;
case 'R':
/* handle extended restart packet */
+ breakpoint_clear_target(gdb_service->target);
+ watchpoint_clear_target(gdb_service->target);
command_run_linef(connection->cmd_ctx, "ocd_gdb_restart %d", get_num_by_target(target));
break;
default:
int gdb_init(void)
{
gdb_service_t *gdb_service;
- target_t *target = targets;
- int i = 0;
+ target_t *target = all_targets;
if (!target)
{
{
char service_name[8];
- snprintf(service_name, 8, "gdb-%2.2i", i);
+ snprintf(service_name, 8, "gdb-%2.2i", target->target_number);
gdb_service = malloc(sizeof(gdb_service_t));
gdb_service->target = target;
- add_service("gdb", CONNECTION_GDB, gdb_port + i, 1, gdb_new_connection, gdb_input, gdb_connection_closed, gdb_service);
+ add_service("gdb", CONNECTION_GDB,
+ gdb_port + target->target_number,
+ 1, gdb_new_connection, gdb_input,
+ gdb_connection_closed,
+ gdb_service);
- LOG_DEBUG("gdb service for target %s at port %i", target->type->name, gdb_port + i);
+ LOG_DEBUG("gdb service for target %s at port %i",
+ target->type->name,
+ gdb_port + target->target_number);
- i++;
target = target->next;
}
return ERROR_OK;
}
+/* daemon configuration command gdb_port */
+int handle_gdb_breakpoint_override_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+ if (argc == 0)
+ {
+
+ } else if (argc==1)
+ {
+ gdb_breakpoint_override = 1;
+ if (strcmp(args[0], "hard")==0)
+ {
+ gdb_breakpoint_override_type=BKPT_HARD;
+ } else if (strcmp(args[0], "soft")==0)
+ {
+ gdb_breakpoint_override_type=BKPT_SOFT;
+ } else if (strcmp(args[0], "disable") == 0)
+ {
+ gdb_breakpoint_override = 0;
+ }
+ } else
+ {
+ return ERROR_COMMAND_SYNTAX_ERROR;
+ }
+ if (gdb_breakpoint_override)
+ {
+ LOG_USER("force %s breakpoints", (gdb_breakpoint_override_type==BKPT_HARD)?"hard":"soft");
+ } else
+ {
+ LOG_USER("breakpoint type is not overriden");
+ }
+
+ return ERROR_OK;
+}
+
+
int gdb_register_commands(command_context_t *command_context)
{
register_command(command_context, NULL, "gdb_port", handle_gdb_port_command,
COMMAND_CONFIG, "");
register_command(command_context, NULL, "gdb_report_data_abort", handle_gdb_report_data_abort_command,
COMMAND_CONFIG, "");
+ register_command(command_context, NULL, "gdb_breakpoint_override", handle_gdb_breakpoint_override_command,
+ COMMAND_EXEC, "hard/soft/disabled - force breakpoint type for gdb 'break' commands."
+ "The raison d'etre for this option is to support GDB GUI's without "
+ "a hard/soft breakpoint concept where the default OpenOCD behaviour "
+ "is not sufficient");
return ERROR_OK;
}