* Disabled by default.
*/
static int gdb_report_data_abort;
+/* If set, errors when accessing registers are reported to gdb. Disabled by
+ * default. */
+static int gdb_report_register_access_error;
/* set if we are sending target descriptions to gdb
* via qXfer:features:read packet */
bool program_exited = false;
if (strcmp(target->fileio_info->identifier, "open") == 0)
- sprintf(fileio_command, "F%s,%" PRIx32 "/%" PRIx32 ",%" PRIx32 ",%" PRIx32, target->fileio_info->identifier,
+ sprintf(fileio_command, "F%s,%" PRIx64 "/%" PRIx64 ",%" PRIx64 ",%" PRIx64, target->fileio_info->identifier,
target->fileio_info->param_1,
target->fileio_info->param_2,
target->fileio_info->param_3,
target->fileio_info->param_4);
else if (strcmp(target->fileio_info->identifier, "close") == 0)
- sprintf(fileio_command, "F%s,%" PRIx32, target->fileio_info->identifier,
+ sprintf(fileio_command, "F%s,%" PRIx64, target->fileio_info->identifier,
target->fileio_info->param_1);
else if (strcmp(target->fileio_info->identifier, "read") == 0)
- sprintf(fileio_command, "F%s,%" PRIx32 ",%" PRIx32 ",%" PRIx32, target->fileio_info->identifier,
+ sprintf(fileio_command, "F%s,%" PRIx64 ",%" PRIx64 ",%" PRIx64, target->fileio_info->identifier,
target->fileio_info->param_1,
target->fileio_info->param_2,
target->fileio_info->param_3);
else if (strcmp(target->fileio_info->identifier, "write") == 0)
- sprintf(fileio_command, "F%s,%" PRIx32 ",%" PRIx32 ",%" PRIx32, target->fileio_info->identifier,
+ sprintf(fileio_command, "F%s,%" PRIx64 ",%" PRIx64 ",%" PRIx64, target->fileio_info->identifier,
target->fileio_info->param_1,
target->fileio_info->param_2,
target->fileio_info->param_3);
else if (strcmp(target->fileio_info->identifier, "lseek") == 0)
- sprintf(fileio_command, "F%s,%" PRIx32 ",%" PRIx32 ",%" PRIx32, target->fileio_info->identifier,
+ sprintf(fileio_command, "F%s,%" PRIx64 ",%" PRIx64 ",%" PRIx64, target->fileio_info->identifier,
target->fileio_info->param_1,
target->fileio_info->param_2,
target->fileio_info->param_3);
else if (strcmp(target->fileio_info->identifier, "rename") == 0)
- sprintf(fileio_command, "F%s,%" PRIx32 "/%" PRIx32 ",%" PRIx32 "/%" PRIx32, target->fileio_info->identifier,
+ sprintf(fileio_command, "F%s,%" PRIx64 "/%" PRIx64 ",%" PRIx64 "/%" PRIx64, target->fileio_info->identifier,
target->fileio_info->param_1,
target->fileio_info->param_2,
target->fileio_info->param_3,
target->fileio_info->param_4);
else if (strcmp(target->fileio_info->identifier, "unlink") == 0)
- sprintf(fileio_command, "F%s,%" PRIx32 "/%" PRIx32, target->fileio_info->identifier,
+ sprintf(fileio_command, "F%s,%" PRIx64 "/%" PRIx64, target->fileio_info->identifier,
target->fileio_info->param_1,
target->fileio_info->param_2);
else if (strcmp(target->fileio_info->identifier, "stat") == 0)
- sprintf(fileio_command, "F%s,%" PRIx32 "/%" PRIx32 ",%" PRIx32, target->fileio_info->identifier,
+ sprintf(fileio_command, "F%s,%" PRIx64 "/%" PRIx64 ",%" PRIx64, target->fileio_info->identifier,
target->fileio_info->param_1,
target->fileio_info->param_2,
target->fileio_info->param_3);
else if (strcmp(target->fileio_info->identifier, "fstat") == 0)
- sprintf(fileio_command, "F%s,%" PRIx32 ",%" PRIx32, target->fileio_info->identifier,
+ sprintf(fileio_command, "F%s,%" PRIx64 ",%" PRIx64, target->fileio_info->identifier,
target->fileio_info->param_1,
target->fileio_info->param_2);
else if (strcmp(target->fileio_info->identifier, "gettimeofday") == 0)
- sprintf(fileio_command, "F%s,%" PRIx32 ",%" PRIx32, target->fileio_info->identifier,
+ sprintf(fileio_command, "F%s,%" PRIx64 ",%" PRIx64, target->fileio_info->identifier,
target->fileio_info->param_1,
target->fileio_info->param_2);
else if (strcmp(target->fileio_info->identifier, "isatty") == 0)
- sprintf(fileio_command, "F%s,%" PRIx32, target->fileio_info->identifier,
+ sprintf(fileio_command, "F%s,%" PRIx64, target->fileio_info->identifier,
target->fileio_info->param_1);
else if (strcmp(target->fileio_info->identifier, "system") == 0)
- sprintf(fileio_command, "F%s,%" PRIx32 "/%" PRIx32, target->fileio_info->identifier,
+ sprintf(fileio_command, "F%s,%" PRIx64 "/%" PRIx64, target->fileio_info->identifier,
target->fileio_info->param_1,
target->fileio_info->param_2);
else if (strcmp(target->fileio_info->identifier, "exit") == 0) {
/* If target hits exit syscall, report to GDB the program is terminated.
* In addition, let target run its own exit syscall handler. */
program_exited = true;
- sprintf(fileio_command, "W%02" PRIx32, target->fileio_info->param_1);
+ sprintf(fileio_command, "W%02" PRIx64, target->fileio_info->param_1);
} else {
LOG_DEBUG("Unknown syscall: %s", target->fileio_info->identifier);
target = get_target_from_connection(connection);
connection->priv = gdb_connection;
+ connection->cmd_ctx->current_target = target;
/* initialize gdb connection information */
gdb_connection->buf_p = gdb_connection->buffer;
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]);
+ if (!reg_list[i]->valid) {
+ retval = reg_list[i]->type->get(reg_list[i]);
+ if (retval != ERROR_OK && gdb_report_register_access_error) {
+ LOG_DEBUG("Couldn't get register %s.", reg_list[i]->name);
+ free(reg_packet);
+ free(reg_list);
+ return gdb_error(connection, retval);
+ }
+ }
gdb_str_to_target(target, reg_packet_p, reg_list[i]);
reg_packet_p += DIV_ROUND_UP(reg_list[i]->size, 8) * 2;
}
bin_buf = malloc(DIV_ROUND_UP(reg_list[i]->size, 8));
gdb_target_to_reg(target, packet_p, chars, bin_buf);
- reg_list[i]->type->set(reg_list[i], bin_buf);
+ retval = reg_list[i]->type->set(reg_list[i], bin_buf);
+ if (retval != ERROR_OK && gdb_report_register_access_error) {
+ LOG_DEBUG("Couldn't set register %s.", reg_list[i]->name);
+ free(reg_list);
+ free(bin_buf);
+ return gdb_error(connection, retval);
+ }
/* advance packet pointer */
packet_p += chars;
return ERROR_SERVER_REMOTE_CLOSED;
}
- if (!reg_list[reg_num]->valid)
- reg_list[reg_num]->type->get(reg_list[reg_num]);
+ if (!reg_list[reg_num]->valid) {
+ retval = reg_list[reg_num]->type->get(reg_list[reg_num]);
+ if (retval != ERROR_OK && gdb_report_register_access_error) {
+ LOG_DEBUG("Couldn't get register %s.", reg_list[reg_num]->name);
+ free(reg_list);
+ return gdb_error(connection, retval);
+ }
+ }
reg_packet = malloc(DIV_ROUND_UP(reg_list[reg_num]->size, 8) * 2 + 1); /* plus one for string termination null */
int chars = (DIV_ROUND_UP(reg_list[reg_num]->size, 8) * 2);
if ((unsigned int)chars != strlen(separator + 1)) {
- LOG_ERROR("gdb sent a packet with wrong register size");
+ LOG_ERROR("gdb sent %zu bits for a %d-bit register (%s)",
+ strlen(separator + 1) * 4, chars * 4, reg_list[reg_num]->name);
free(bin_buf);
return ERROR_SERVER_REMOTE_CLOSED;
}
gdb_target_to_reg(target, separator + 1, chars, bin_buf);
- reg_list[reg_num]->type->set(reg_list[reg_num], bin_buf);
+ retval = reg_list[reg_num]->type->set(reg_list[reg_num], bin_buf);
+ if (retval != ERROR_OK && gdb_report_register_access_error) {
+ LOG_DEBUG("Couldn't set register %s.", reg_list[reg_num]->name);
+ free(bin_buf);
+ free(reg_list);
+ return gdb_error(connection, retval);
+ }
gdb_put_packet(connection, "OK", 2);
int offset;
int length;
char *separator;
- uint32_t ram_start = 0;
+ target_addr_t ram_start = 0;
int i;
int target_flash_banks = 0;
/* Sort banks in ascending order. We need to report non-flash
* memory as ram (or rather read/write) by default for GDB, since
* it has no concept of non-cacheable read/write memory (i/o etc).
- *
- * FIXME Most non-flash addresses are *NOT* RAM! Don't lie.
- * Current versions of GDB assume unlisted addresses are RAM...
*/
banks = malloc(sizeof(struct flash_bank *)*flash_get_bank_count());
for (i = 0; i < target_flash_banks; i++) {
int j;
unsigned sector_size = 0;
- uint32_t start;
+ unsigned group_len = 0;
p = banks[i];
- start = p->base;
if (ram_start < p->base)
xml_printf(&retval, &xml, &pos, &size,
- "<memory type=\"ram\" start=\"0x%x\" "
+ "<memory type=\"ram\" start=\"" TARGET_ADDR_FMT "\" "
"length=\"0x%x\"/>\n",
ram_start, p->base - ram_start);
* regions with 8KB, 32KB, and 64KB sectors; etc.
*/
for (j = 0; j < p->num_sectors; j++) {
- unsigned group_len;
/* Maybe start a new group of sectors. */
if (sector_size == 0) {
+ if (p->sectors[j].offset + p->sectors[j].size > p->size) {
+ LOG_WARNING("The flash sector at offset 0x%08" PRIx32
+ " overflows the end of %s bank.",
+ p->sectors[j].offset, p->name);
+ LOG_WARNING("The rest of bank will not show in gdb memory map.");
+ break;
+ }
+ target_addr_t start;
start = p->base + p->sectors[j].offset;
xml_printf(&retval, &xml, &pos, &size,
"<memory type=\"flash\" "
- "start=\"0x%x\" ",
+ "start=\"" TARGET_ADDR_FMT "\" ",
start);
sector_size = p->sectors[j].size;
+ group_len = sector_size;
+ } else {
+ group_len += sector_size; /* equal to p->sectors[j].size */
}
/* Does this finish a group of sectors?
* If not, continue an already-started group.
*/
- if (j == p->num_sectors - 1)
- group_len = (p->base + p->size) - start;
- else if (p->sectors[j + 1].size != sector_size)
- group_len = p->base + p->sectors[j + 1].offset
- - start;
- else
+ if (j < p->num_sectors - 1
+ && p->sectors[j + 1].size == sector_size
+ && p->sectors[j + 1].offset == p->sectors[j].offset + sector_size
+ && p->sectors[j + 1].offset + p->sectors[j + 1].size <= p->size)
continue;
xml_printf(&retval, &xml, &pos, &size,
if (ram_start != 0)
xml_printf(&retval, &xml, &pos, &size,
- "<memory type=\"ram\" start=\"0x%x\" "
+ "<memory type=\"ram\" start=\"" TARGET_ADDR_FMT "\" "
"length=\"0x%x\"/>\n",
ram_start, 0-ram_start);
/* ELSE a flash chip could be at the very end of the 32 bit address
*/
free(banks);
- banks = NULL;
xml_printf(&retval, &xml, &pos, &size, "</memory-map>\n");
if (retval != ERROR_OK) {
+ free(xml);
gdb_error(connection, retval);
return retval;
}
/* simple case, a continue packet */
if (parse[0] == 'c') {
+ gdb_running_type = 'c';
LOG_DEBUG("target %s continue", target_name(target));
log_add_callback(gdb_log_callback, connection);
retval = target_resume(target, 1, 0, 0, 0);
/* single-step or step-over-breakpoint */
if (parse[0] == 's') {
+ gdb_running_type = 's';
bool fake_step = false;
if (strncmp(parse, "s:", 2) == 0) {
static int gdb_detach(struct connection *connection)
{
- target_call_event_callbacks(get_target_from_connection(connection),
- TARGET_EVENT_GDB_DETACH);
-
+ /*
+ * Only reply "OK" to GDB
+ * it will close the connection and this will trigger a call to
+ * gdb_connection_closed() that will in turn trigger the event
+ * TARGET_EVENT_GDB_DETACH
+ */
return gdb_put_packet(connection, "OK", 2);
}
if (NULL == gdb_service)
return -ENOMEM;
+ LOG_DEBUG("starting gdb server for %s on %s", target_name(target), port);
+
gdb_service->target = target;
gdb_service->core[0] = -1;
gdb_service->core[1] = -1;
static int gdb_target_add_one(struct target *target)
{
+ /* one gdb instance per smp list */
+ if ((target->smp) && (target->gdb_service))
+ return ERROR_OK;
+
+ if (target->gdb_port_override) {
+ if (strcmp(target->gdb_port_override, "disabled") == 0) {
+ LOG_INFO("gdb port disabled");
+ return ERROR_OK;
+ }
+ return gdb_target_start(target, target->gdb_port_override);
+ }
+
if (strcmp(gdb_port, "disabled") == 0) {
LOG_INFO("gdb port disabled");
return ERROR_OK;
}
- /* 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) {
+ /* save the port number so can be queried with
+ * $target_name cget -gdb-port
+ */
+ target->gdb_port_override = strdup(gdb_port_next);
+
long portnumber;
/* If we can parse the port number
* then we increment the port number for the next target.
int gdb_target_add_all(struct target *target)
{
- if (strcmp(gdb_port, "disabled") == 0) {
- LOG_INFO("gdb server disabled");
- return ERROR_OK;
- }
-
if (NULL == target) {
LOG_WARNING("gdb services need one or more targets defined");
return ERROR_OK;
return ERROR_OK;
}
+COMMAND_HANDLER(handle_gdb_report_register_access_error)
+{
+ if (CMD_ARGC != 1)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ COMMAND_PARSE_ENABLE(CMD_ARGV[0], gdb_report_register_access_error);
+ return ERROR_OK;
+}
+
/* gdb_breakpoint_override */
COMMAND_HANDLER(handle_gdb_breakpoint_override_command)
{
.help = "enable or disable reporting data aborts",
.usage = "('enable'|'disable')"
},
+ {
+ .name = "gdb_report_register_access_error",
+ .handler = handle_gdb_report_register_access_error,
+ .mode = COMMAND_CONFIG,
+ .help = "enable or disable reporting register access errors",
+ .usage = "('enable'|'disable')"
+ },
{
.name = "gdb_breakpoint_override",
.handler = handle_gdb_breakpoint_override_command,