X-Git-Url: https://review.openocd.org/gitweb?p=openocd.git;a=blobdiff_plain;f=src%2Fserver%2Fgdb_server.c;h=c6cf7d350e076d438832d4de9bb038ec2f48218b;hp=a3783af841644a476ed97c9ca7eda14877c65411;hb=6cb5ba6f1136df2986850f5c176cb38e34ca1795;hpb=2e2bb14b276f5bd973308dcfabd1b8018e187243
diff --git a/src/server/gdb_server.c b/src/server/gdb_server.c
index a3783af841..c6cf7d350e 100644
--- a/src/server/gdb_server.c
+++ b/src/server/gdb_server.c
@@ -153,6 +153,8 @@ static int gdb_last_signal(struct target *target)
return 0x05; /* SIGTRAP */
case DBG_REASON_SINGLESTEP:
return 0x05; /* SIGTRAP */
+ case DBG_REASON_EXC_CATCH:
+ return 0x05;
case DBG_REASON_NOTHALTED:
return 0x0; /* no signal... shouldn't happen */
default:
@@ -793,64 +795,64 @@ static void gdb_fileio_reply(struct target *target, struct connection *connectio
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);
@@ -936,6 +938,7 @@ static int gdb_new_connection(struct connection *connection)
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;
@@ -1178,8 +1181,11 @@ static int gdb_get_registers_packet(struct connection *connection,
if (retval != ERROR_OK)
return gdb_error(connection, retval);
- for (i = 0; i < reg_list_size; i++)
+ for (i = 0; i < reg_list_size; i++) {
+ if (reg_list[i] == NULL || reg_list[i]->exist == false)
+ continue;
reg_packet_size += DIV_ROUND_UP(reg_list[i]->size, 8) * 2;
+ }
assert(reg_packet_size > 0);
@@ -1190,6 +1196,8 @@ static int gdb_get_registers_packet(struct connection *connection,
reg_packet_p = reg_packet;
for (i = 0; i < reg_list_size; i++) {
+ if (reg_list[i] == NULL || reg_list[i]->exist == false)
+ continue;
if (!reg_list[i]->valid) {
retval = reg_list[i]->type->get(reg_list[i]);
if (retval != ERROR_OK && gdb_report_register_access_error) {
@@ -1295,6 +1303,9 @@ static int gdb_get_register_packet(struct connection *connection,
LOG_DEBUG("-");
#endif
+ if ((target->rtos != NULL) && (ERROR_OK == rtos_get_gdb_reg(connection, reg_num)))
+ return ERROR_OK;
+
retval = target_get_gdb_reg_list(target, ®_list, ®_list_size,
REG_CLASS_ALL);
if (retval != ERROR_OK)
@@ -1359,7 +1370,8 @@ static int gdb_set_register_packet(struct connection *connection,
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;
}
@@ -1425,7 +1437,7 @@ static int gdb_read_memory_packet(struct connection *connection,
if (!len) {
LOG_WARNING("invalid read memory packet received (len == 0)");
- gdb_put_packet(connection, NULL, 0);
+ gdb_put_packet(connection, "", 0);
return ERROR_OK;
}
@@ -1808,7 +1820,7 @@ static int gdb_memory_map(struct connection *connection,
int offset;
int length;
char *separator;
- uint32_t ram_start = 0;
+ target_addr_t ram_start = 0;
int i;
int target_flash_banks = 0;
@@ -1823,9 +1835,6 @@ static int gdb_memory_map(struct connection *connection,
/* 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());
@@ -1848,14 +1857,13 @@ static int gdb_memory_map(struct connection *connection,
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,
- "\n",
ram_start, p->base - ram_start);
@@ -1866,27 +1874,35 @@ static int gdb_memory_map(struct connection *connection,
* 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,
"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,
@@ -1904,19 +1920,18 @@ static int gdb_memory_map(struct connection *connection,
if (ram_start != 0)
xml_printf(&retval, &xml, &pos, &size,
- "\n",
- ram_start, 0-ram_start);
- /* ELSE a flash chip could be at the very end of the 32 bit address
- * space, in which case ram_start will be precisely 0
- */
+ "\n",
+ ram_start, target_address_max(target) - ram_start + 1);
+ /* ELSE a flash chip could be at the very end of the address space, in
+ * which case ram_start will be precisely 0 */
free(banks);
- banks = NULL;
xml_printf(&retval, &xml, &pos, &size, "\n");
if (retval != ERROR_OK) {
+ free(xml);
gdb_error(connection, retval);
return retval;
}
@@ -2182,6 +2197,7 @@ static int gdb_generate_target_description(struct target *target, char **tdesc_o
int retval = ERROR_OK;
struct reg **reg_list = NULL;
int reg_list_size;
+ char const *architecture;
char const **features = NULL;
char const **arch_defined_types = NULL;
int feature_list_size = 0;
@@ -2223,6 +2239,12 @@ static int gdb_generate_target_description(struct target *target, char **tdesc_o
"\n"
"\n");
+ /* generate architecture element if supported by target */
+ architecture = target_get_gdb_arch(target);
+ if (architecture != NULL)
+ xml_printf(&retval, &tdesc, &pos, &size,
+ "%s\n", architecture);
+
/* generate target description according to register list */
if (features != NULL) {
while (features[current_feature]) {
@@ -2372,6 +2394,8 @@ static int gdb_target_description_supported(struct target *target, int *supporte
char const **features = NULL;
int feature_list_size = 0;
+ char const *architecture = target_get_gdb_arch(target);
+
retval = target_get_gdb_reg_list(target, ®_list,
®_list_size, REG_CLASS_ALL);
if (retval != ERROR_OK) {
@@ -2393,7 +2417,7 @@ static int gdb_target_description_supported(struct target *target, int *supporte
}
if (supported) {
- if (feature_list_size)
+ if (architecture || feature_list_size)
*supported = 1;
else
*supported = 0;
@@ -2702,6 +2726,7 @@ static bool gdb_handle_vcont_packet(struct connection *connection, const char *p
/* 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);
@@ -2728,6 +2753,7 @@ static bool gdb_handle_vcont_packet(struct connection *connection, const char *p
/* single-step or step-over-breakpoint */
if (parse[0] == 's') {
+ gdb_running_type = 's';
bool fake_step = false;
if (strncmp(parse, "s:", 2) == 0) {
@@ -2823,7 +2849,7 @@ static bool gdb_handle_vcont_packet(struct connection *connection, const char *p
if (gdb_connection->sync) {
gdb_connection->sync = false;
if (ct->state == TARGET_HALTED) {
- LOG_WARNING("stepi ignored. GDB will now fetch the register state " \
+ LOG_DEBUG("stepi ignored. GDB will now fetch the register state " \
"from the target.");
gdb_sig_halted(connection);
log_remove_callback(gdb_log_callback, connection);
@@ -3010,9 +3036,12 @@ static int gdb_v_packet(struct connection *connection,
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);
}
@@ -3204,7 +3233,7 @@ static int gdb_input_inner(struct connection *connection)
* make only the single stepping have the sync feature...
*/
nostep = true;
- LOG_WARNING("stepi ignored. GDB will now fetch the register state " \
+ LOG_DEBUG("stepi ignored. GDB will now fetch the register state " \
"from the target.");
}
gdb_con->sync = false;
@@ -3307,7 +3336,7 @@ static int gdb_input_inner(struct connection *connection)
default:
/* ignore unknown packets */
LOG_DEBUG("ignoring 0x%2.2x packet", packet[0]);
- gdb_put_packet(connection, NULL, 0);
+ gdb_put_packet(connection, "", 0);
break;
}
@@ -3362,6 +3391,8 @@ static int gdb_target_start(struct target *target, const char *port)
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;
@@ -3387,16 +3418,36 @@ static int gdb_target_start(struct target *target, const char *port)
static int gdb_target_add_one(struct target *target)
{
+ /* one gdb instance per smp list */
+ if ((target->smp) && (target->gdb_service))
+ return ERROR_OK;
+
+ /* skip targets that cannot handle a gdb connections (e.g. mem_ap) */
+ if (!target_supports_gdb_connection(target)) {
+ LOG_DEBUG("skip gdb server for target %s", target_name(target));
+ 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.
@@ -3421,11 +3472,6 @@ static int gdb_target_add_one(struct target *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;
@@ -3448,7 +3494,7 @@ COMMAND_HANDLER(handle_gdb_sync_command)
return ERROR_COMMAND_SYNTAX_ERROR;
if (current_gdb_connection == NULL) {
- command_print(CMD_CTX,
+ command_print(CMD,
"gdb_sync command can only be run from within gdb using \"monitor gdb_sync\"");
return ERROR_FAIL;
}
@@ -3653,6 +3699,7 @@ static const struct command_registration gdb_command_handlers[] = {
.handler = handle_gdb_save_tdesc_command,
.mode = COMMAND_EXEC,
.help = "Save the target description file",
+ .usage = "",
},
COMMAND_REGISTRATION_DONE
};