diff options
author | Tim Newsome <tim@sifive.com> | 2019-04-08 16:42:48 -0700 |
---|---|---|
committer | Andreas Fritiofson <andreas.fritiofson@gmail.com> | 2019-08-28 08:07:37 +0100 |
commit | 081954136681b26ad30db9b4cc40cb360f47602c (patch) | |
tree | b154e83ef45f87aab59ad6bb6dd56bc47ec709fa /src/target | |
parent | 16496488d10fc9f6c340b81446a85eef2c95ce00 (diff) | |
download | riscv-openocd-081954136681b26ad30db9b4cc40cb360f47602c.zip riscv-openocd-081954136681b26ad30db9b4cc40cb360f47602c.tar.gz riscv-openocd-081954136681b26ad30db9b4cc40cb360f47602c.tar.bz2 |
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>
Diffstat (limited to 'src/target')
-rw-r--r-- | src/target/register.c | 23 | ||||
-rw-r--r-- | src/target/register.h | 2 | ||||
-rw-r--r-- | src/target/target.c | 24 | ||||
-rw-r--r-- | src/target/target.h | 10 | ||||
-rw-r--r-- | src/target/target_type.h | 7 |
5 files changed, 63 insertions, 3 deletions
diff --git a/src/target/register.c b/src/target/register.c index 5352d2f..4ddda6e 100644 --- a/src/target/register.c +++ b/src/target/register.c @@ -36,6 +36,29 @@ * may be separate registers associated with debug or trace modules. */ +struct reg *register_get_by_number(struct reg_cache *first, + uint32_t reg_num, bool search_all) +{ + unsigned i; + struct reg_cache *cache = first; + + while (cache) { + for (i = 0; i < cache->num_regs; i++) { + if (cache->reg_list[i].exist == false) + continue; + if (cache->reg_list[i].number == reg_num) + return &(cache->reg_list[i]); + } + + if (search_all) + cache = cache->next; + else + break; + } + + return NULL; +} + struct reg *register_get_by_name(struct reg_cache *first, const char *name, bool search_all) { diff --git a/src/target/register.h b/src/target/register.h index 32c1f39..7c53d6e 100644 --- a/src/target/register.h +++ b/src/target/register.h @@ -159,6 +159,8 @@ struct reg_arch_type { int (*set)(struct reg *reg, uint8_t *buf); }; +struct reg *register_get_by_number(struct reg_cache *first, + uint32_t reg_num, bool search_all); struct reg *register_get_by_name(struct reg_cache *first, const char *name, bool search_all); struct reg_cache **register_get_last_cache_p(struct reg_cache **first); diff --git a/src/target/target.c b/src/target/target.c index e6c4343..51fdff3 100644 --- a/src/target/target.c +++ b/src/target/target.c @@ -1215,7 +1215,24 @@ int target_get_gdb_reg_list(struct target *target, struct reg **reg_list[], int *reg_list_size, enum target_register_class reg_class) { - return target->type->get_gdb_reg_list(target, reg_list, reg_list_size, reg_class); + int result = target->type->get_gdb_reg_list(target, reg_list, + reg_list_size, reg_class); + if (result != ERROR_OK) { + *reg_list = NULL; + *reg_list_size = 0; + } + return result; +} + +int target_get_gdb_reg_list_noread(struct target *target, + struct reg **reg_list[], int *reg_list_size, + enum target_register_class reg_class) +{ + if (target->type->get_gdb_reg_list_noread && + target->type->get_gdb_reg_list_noread(target, reg_list, + reg_list_size, reg_class) == ERROR_OK) + return ERROR_OK; + return target_get_gdb_reg_list(target, reg_list, reg_list_size, reg_class); } bool target_supports_gdb_connection(struct target *target) @@ -1587,8 +1604,9 @@ int target_call_event_callbacks(struct target *target, enum target_event event) target_call_event_callbacks(target, TARGET_EVENT_GDB_HALT); } - LOG_DEBUG("target event %i (%s)", event, - Jim_Nvp_value2name_simple(nvp_target_event, event)->name); + LOG_DEBUG("target event %i (%s) for core %s", event, + Jim_Nvp_value2name_simple(nvp_target_event, event)->name, + target_name(target)); target_handle_event(target, event); diff --git a/src/target/target.h b/src/target/target.h index e944838..81fd9d2 100644 --- a/src/target/target.h +++ b/src/target/target.h @@ -503,6 +503,16 @@ int target_get_gdb_reg_list(struct target *target, enum target_register_class reg_class); /** + * Obtain the registers for GDB, but don't read register values from the + * target. + * + * This routine is a wrapper for target->type->get_gdb_reg_list_noread. + */ +int target_get_gdb_reg_list_noread(struct target *target, + struct reg **reg_list[], int *reg_list_size, + enum target_register_class reg_class); + +/** * Check if @a target allows GDB connections. * * Some target do not implement the necessary code required by GDB. diff --git a/src/target/target_type.h b/src/target/target_type.h index 95745c9..4bdea72 100644 --- a/src/target/target_type.h +++ b/src/target/target_type.h @@ -111,6 +111,13 @@ struct target_type { int (*get_gdb_reg_list)(struct target *target, struct reg **reg_list[], int *reg_list_size, enum target_register_class reg_class); + /** + * Same as get_gdb_reg_list, but doesn't read the register values. + * */ + int (*get_gdb_reg_list_noread)(struct target *target, + struct reg **reg_list[], int *reg_list_size, + enum target_register_class reg_class); + /* target memory access * size: 1 = byte (8bit), 2 = half-word (16bit), 4 = word (32bit) * count: number of items of <size> |