From 2e2bb14b276f5bd973308dcfabd1b8018e187243 Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Tue, 6 Mar 2018 14:10:04 -0800 Subject: [PATCH] Add gdb_report_register_access_error command With this option enabled (it's disabled by default) errors accessing registers are returned to gdb. Otherwise they are ignored and success is reported to gdb. (This is the current behavior.) We want this for RISC-V, but there's still some cleanup that needs to be done before that can be upstreamed. Signed-off-by: Tim Newsome Change-Id: I7e56109ea52d18b780c14a07fb35f9e6e8979da4 Reviewed-on: http://openocd.zylin.com/4452 Reviewed-by: Steven Stallion Reviewed-by: Matthias Welwarsky Tested-by: jenkins --- doc/openocd.texi | 7 ++++++ src/server/gdb_server.c | 56 ++++++++++++++++++++++++++++++++++++----- 2 files changed, 57 insertions(+), 6 deletions(-) diff --git a/doc/openocd.texi b/doc/openocd.texi index f51ff244..967c637a 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -2200,6 +2200,13 @@ The default behaviour is @option{disable}; use @option{enable} see these errors reported. @end deffn +@deffn {Config Command} gdb_report_register_access_error (@option{enable}|@option{disable}) +Specifies whether register accesses requested by GDB register read/write +packets report errors or not. +The default behaviour is @option{disable}; +use @option{enable} see these errors reported. +@end deffn + @deffn {Config Command} gdb_target_description (@option{enable}|@option{disable}) Set to @option{enable} to cause OpenOCD to send the target descriptions to gdb via qXfer:features:read packet. The default behaviour is @option{enable}. diff --git a/src/server/gdb_server.c b/src/server/gdb_server.c index 428547b4..a3783af8 100644 --- a/src/server/gdb_server.c +++ b/src/server/gdb_server.c @@ -130,6 +130,9 @@ static int gdb_flash_program = 1; * 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 */ @@ -1187,8 +1190,15 @@ 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]->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; } @@ -1249,7 +1259,13 @@ static int gdb_set_registers_packet(struct connection *connection, 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; @@ -1289,8 +1305,14 @@ static int gdb_get_register_packet(struct connection *connection, 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 */ @@ -1344,7 +1366,13 @@ static int gdb_set_register_packet(struct connection *connection, 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); @@ -3468,6 +3496,15 @@ COMMAND_HANDLER(handle_gdb_report_data_abort_command) 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) { @@ -3589,6 +3626,13 @@ static const struct command_registration gdb_command_handlers[] = { .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, -- 2.39.5