#include "flash.h"
#include "gdb_server.h"
#include "image.h"
-#include "jtag.h"
+#include <jtag/jtag.h>
#if 0
static void gdb_log_callback(void *priv, const char *file, unsigned line,
const char *function, const char *string);
-/* number of gdb connections, mainly to supress gdb related debugging spam
+/* number of gdb connections, mainly to suppress gdb related debugging spam
* in helper/log.c when no gdb connections are actually active */
int gdb_actual_connections;
break;
case '+':
/* gdb sends a dummy ack '+' at every remote connect - see remote_start_remote (remote.c)
- * incase anyone tries to debug why they receive this warning every time */
+ * in case anyone tries to debug why they receive this warning every time */
LOG_WARNING("acknowledgment received, but no packet pending");
break;
case '-':
gdb_actual_connections++;
LOG_DEBUG("New GDB Connection: %d, Target %s, state: %s",
gdb_actual_connections,
- gdb_service->target->cmd_name,
+ target_name(gdb_service->target),
target_state_name(gdb_service->target));
return ERROR_OK;
gdb_actual_connections--;
LOG_DEBUG("GDB Close, Target: %s, state: %s, gdb_actual_connections=%d",
- gdb_service->target->cmd_name,
+ target_name(gdb_service->target),
target_state_name(gdb_service->target),
gdb_actual_connections);
* register might be non-divisible by 8(a byte), in which
* case an entire byte is shown.
*
- * NB! the format on the wire is the target endianess
+ * NB! the format on the wire is the target endianness
*
* The format of reg->value is little endian
*
watchpoint_clear_target(gdb_service->target);
command_run_linef(connection->cmd_ctx,
"ocd_gdb_restart %s",
- target->cmd_name);
+ target_name(target));
break;
default:
- /* ignore unkown packets */
+ /* ignore unknown packets */
LOG_DEBUG("ignoring 0x%2.2x packet", packet[0]);
gdb_put_packet(connection, NULL, 0);
break;
return ERROR_OK;
}
-int gdb_init(void)
+static int gdb_target_start(struct target *target, uint16_t port)
{
- struct gdb_service *gdb_service;
- struct target *target = all_targets;
+ bool use_pipes = 0 == port;
+ struct gdb_service *gdb_service = malloc(sizeof(struct gdb_service));
+ if (NULL == gdb_service)
+ return -ENOMEM;
- if (!target)
- {
- LOG_WARNING("no gdb ports allocated as no target has been specified");
- return ERROR_OK;
- }
+ gdb_service->target = target;
+
+ add_service("gdb", use_pipes ? CONNECTION_PIPE : CONNECTION_TCP,
+ 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;
+}
+
+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 (server_use_pipes)
+ bool use_pipes = server_use_pipes;
+ static bool server_started_with_pipes = false;
+ if (server_started_with_pipes)
{
- /* only a single gdb connection when using a pipe */
+ LOG_WARNING("gdb service permits one target when using pipes");
+ if (0 == gdb_port)
+ return ERROR_OK;
- gdb_service = malloc(sizeof(struct gdb_service));
- gdb_service->target = target;
+ use_pipes = false;
+ }
+
+ int e = gdb_target_start(target, use_pipes ? 0 : gdb_port++);
+ if (ERROR_OK == e)
+ server_started_with_pipes |= use_pipes;
- add_service("gdb", CONNECTION_PIPE, 0, 1, gdb_new_connection, gdb_input, gdb_connection_closed, gdb_service);
+ return e;
+}
- LOG_DEBUG("gdb service for target %s using pipes",
- target_get_name(target));
+int gdb_target_add_all(struct target *target)
+{
+ if (NULL == target)
+ {
+ LOG_WARNING("gdb services need one or more targets defined");
+ return ERROR_OK;
}
- else
+
+ while (NULL != target)
{
- unsigned short port = gdb_port;
+ int retval = gdb_target_add_one(target);
+ if (ERROR_OK != retval)
+ return retval;
- while (target)
- {
- gdb_service = malloc(sizeof(struct gdb_service));
- gdb_service->target = target;
-
- add_service("gdb", CONNECTION_TCP,
- port, 1,
- gdb_new_connection, gdb_input,
- gdb_connection_closed, gdb_service);
-
- LOG_DEBUG("gdb service for target %s at TCP port %i",
- target_get_name(target),
- port);
- target = target->next;
- port++;
- }
+ target = target->next;
}
return ERROR_OK;
COMMAND_HANDLER(handle_gdb_memory_map_command)
{
if (CMD_ARGC == 1)
- {
- if (strcmp(CMD_ARGV[0], "enable") == 0)
- {
- gdb_use_memory_map = 1;
- return ERROR_OK;
- }
- else if (strcmp(CMD_ARGV[0], "disable") == 0)
- {
- gdb_use_memory_map = 0;
- return ERROR_OK;
- }
- else
- LOG_WARNING("invalid gdb_memory_map configuration directive %s", CMD_ARGV[0]);
- }
+ COMMAND_PARSE_ENABLE(CMD_ARGV[0], gdb_use_memory_map);
return ERROR_COMMAND_SYNTAX_ERROR;
}
COMMAND_HANDLER(handle_gdb_flash_program_command)
{
if (CMD_ARGC == 1)
- {
- if (strcmp(CMD_ARGV[0], "enable") == 0)
- {
- gdb_flash_program = 1;
- return ERROR_OK;
- }
- else if (strcmp(CMD_ARGV[0], "disable") == 0)
- {
- gdb_flash_program = 0;
- return ERROR_OK;
- }
- else
- LOG_WARNING("invalid gdb_flash_program configuration directive: %s", CMD_ARGV[0]);
- }
+ COMMAND_PARSE_ENABLE(CMD_ARGV[0], gdb_flash_program);
return ERROR_COMMAND_SYNTAX_ERROR;
}
COMMAND_HANDLER(handle_gdb_report_data_abort_command)
{
if (CMD_ARGC == 1)
- {
- if (strcmp(CMD_ARGV[0], "enable") == 0)
- {
- gdb_report_data_abort = 1;
- return ERROR_OK;
- }
- else if (strcmp(CMD_ARGV[0], "disable") == 0)
- {
- gdb_report_data_abort = 0;
- return ERROR_OK;
- }
- else
- LOG_WARNING("invalid gdb_report_data_abort configuration directive: %s", CMD_ARGV[0]);
- }
+ COMMAND_PARSE_ENABLE(CMD_ARGV[0], gdb_report_data_abort);
return ERROR_COMMAND_SYNTAX_ERROR;
}
LOG_USER("force %s breakpoints", (gdb_breakpoint_override_type == BKPT_HARD)?"hard":"soft");
} else
{
- LOG_USER("breakpoint type is not overriden");
+ LOG_USER("breakpoint type is not overridden");
}
return ERROR_OK;
}
-int gdb_register_commands(struct command_context *command_context)
+static const struct command_registration gdb_command_handlers[] = {
+ {
+ .name = "gdb_sync",
+ .handler = &handle_gdb_sync_command,
+ .mode = COMMAND_ANY,
+ .help = "next stepi will return immediately allowing "
+ "GDB to fetch register state without affecting "
+ "target state",
+ },
+ {
+ .name = "gdb_port",
+ .handler = &handle_gdb_port_command,
+ .mode = COMMAND_ANY,
+ .help = "daemon configuration command gdb_port",
+ .usage = "<port>",
+ },
+ {
+ .name = "gdb_memory_map",
+ .handler = &handle_gdb_memory_map_command,
+ .mode = COMMAND_CONFIG,
+ .help = "enable or disable memory map",
+ .usage = "enable|disable"
+ },
+ {
+ .name = "gdb_flash_program",
+ .handler = &handle_gdb_flash_program_command,
+ .mode = COMMAND_CONFIG,
+ .help = "enable or disable flash program",
+ .usage = "enable|disable"
+ },
+ {
+ .name = "gdb_report_data_abort",
+ .handler = &handle_gdb_report_data_abort_command,
+ .mode = COMMAND_CONFIG,
+ .help = "enable or disable reporting data aborts",
+ .usage = "enable|disable"
+ },
+ {
+ .name = "gdb_breakpoint_override",
+ .handler = &handle_gdb_breakpoint_override_command,
+ .mode = COMMAND_EXEC,
+ .help = "force type of breakpoint "
+ "used by gdb 'break' commands.",
+ .usage = "hard|soft|disable",
+ },
+ COMMAND_REGISTRATION_DONE
+};
+
+int gdb_register_commands(struct command_context *cmd_ctx)
{
- register_command(command_context, NULL, "gdb_sync",
- handle_gdb_sync_command, COMMAND_ANY,
- "next stepi will return immediately allowing GDB to "
- "fetch register state without affecting target state");
- register_command(command_context, NULL, "gdb_port",
- handle_gdb_port_command, COMMAND_ANY,
- "daemon configuration command gdb_port");
- register_command(command_context, NULL, "gdb_memory_map",
- handle_gdb_memory_map_command, COMMAND_CONFIG,
- "enable or disable memory map");
- register_command(command_context, NULL, "gdb_flash_program",
- handle_gdb_flash_program_command, COMMAND_CONFIG,
- "enable or disable flash program");
- register_command(command_context, NULL, "gdb_report_data_abort",
- handle_gdb_report_data_abort_command, COMMAND_CONFIG,
- "enable or disable reporting data aborts");
- register_command(command_context, NULL, "gdb_breakpoint_override",
- handle_gdb_breakpoint_override_command, COMMAND_EXEC,
- "hard/soft/disable - force type of breakpoint "
- "used by gdb 'break' commands.");
- return ERROR_OK;
+ return register_commands(cmd_ctx, NULL, gdb_command_handlers);
}