gdb_server, rtos: Fine-grained RTOS register access

1. Add get_thread_reg() to rtos. It's used in rtos_get_gdb_reg() to read
the value of a single register, instead of reading all register values
by calling get_thread_reg_list().
2. Add set_reg() to rtos. gdb_server uses this to change a single
register value for a specific thread.
3. Add target_get_gdb_reg_list_noread() so it's possible for gdb to get
a list of registers without attempting to read their contents.

The clang static checker doesn't find any new problems with this change.

Change-Id: I77f792d1238cb015b91527ca8cb99593ccc8870e
Signed-off-by: Tim Newsome <tim@sifive.com>
Reviewed-on: http://openocd.zylin.com/5114
Tested-by: jenkins
Reviewed-by: Matthias Welwarsky <matthias@welwarsky.de>
This commit is contained in:
Tim Newsome
2019-04-08 16:42:48 -07:00
committed by Andreas Fritiofson
parent 16496488d1
commit 0819541366
8 changed files with 158 additions and 50 deletions
+37 -9
View File
@@ -462,6 +462,7 @@ static int rtos_put_gdb_reg_list(struct connection *connection,
return ERROR_OK;
}
/** Look through all registers to find this register. */
int rtos_get_gdb_reg(struct connection *connection, int reg_num)
{
struct target *target = get_target_from_connection(connection);
@@ -473,19 +474,31 @@ int rtos_get_gdb_reg(struct connection *connection, int reg_num)
struct rtos_reg *reg_list;
int num_regs;
LOG_DEBUG("RTOS: getting register %d for thread 0x%" PRIx64
", target->rtos->current_thread=0x%" PRIx64 "\r\n",
LOG_DEBUG("getting register %d for thread 0x%" PRIx64
", target->rtos->current_thread=0x%" PRIx64,
reg_num,
current_threadid,
target->rtos->current_thread);
int retval = target->rtos->type->get_thread_reg_list(target->rtos,
current_threadid,
&reg_list,
&num_regs);
if (retval != ERROR_OK) {
LOG_ERROR("RTOS: failed to get register list");
return retval;
int retval;
if (target->rtos->type->get_thread_reg) {
reg_list = calloc(1, sizeof(*reg_list));
num_regs = 1;
retval = target->rtos->type->get_thread_reg(target->rtos,
current_threadid, reg_num, &reg_list[0]);
if (retval != ERROR_OK) {
LOG_ERROR("RTOS: failed to get register %d", reg_num);
return retval;
}
} else {
retval = target->rtos->type->get_thread_reg_list(target->rtos,
current_threadid,
&reg_list,
&num_regs);
if (retval != ERROR_OK) {
LOG_ERROR("RTOS: failed to get register list");
return retval;
}
}
for (int i = 0; i < num_regs; ++i) {
@@ -501,6 +514,7 @@ int rtos_get_gdb_reg(struct connection *connection, int reg_num)
return ERROR_FAIL;
}
/** Return a list of general registers. */
int rtos_get_gdb_reg_list(struct connection *connection)
{
struct target *target = get_target_from_connection(connection);
@@ -534,6 +548,20 @@ int rtos_get_gdb_reg_list(struct connection *connection)
return ERROR_FAIL;
}
int rtos_set_reg(struct connection *connection, int reg_num,
uint8_t *reg_value)
{
struct target *target = get_target_from_connection(connection);
int64_t current_threadid = target->rtos->current_threadid;
if ((target->rtos != NULL) &&
(target->rtos->type->set_reg != NULL) &&
(current_threadid != -1) &&
(current_threadid != 0)) {
return target->rtos->type->set_reg(target->rtos, reg_num, reg_value);
}
return ERROR_FAIL;
}
int rtos_generic_stack_read(struct target *target,
const struct rtos_register_stacking *stacking,
int64_t stack_ptr,