This is an automated email from Gerrit. Tim Newsome (t...@sifive.com) just uploaded a new patch set to Gerrit, which you can find at http://openocd.zylin.com/5101
-- gerrit commit 9b7c17f28de1412f8ba6ceedbe689b4ab21395a6 Author: Tim Newsome <t...@sifive.com> Date: Mon Apr 8 16:42:48 2019 -0700 gdb_server, rtos: Numerous hwthread improvements 1. Change hwthread_update_threads() to preserve current_threadid. Arguably hwthread_update_threads() should always be a nop after the initial call, since the number of threads is static, configured in the startup script. 2. 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(). 3. Add set_reg() to rtos. gdb_server uses this to change a single register value for a specific thread. 4. 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. Signed-off-by: Tim Newsome <t...@sifive.com> Change-Id: I7d040790268cd942ae3b66ec2781b0124f1bde8d diff --git a/src/rtos/hwthread.c b/src/rtos/hwthread.c index 2d9e42f..4d05d19 100644 --- a/src/rtos/hwthread.c +++ b/src/rtos/hwthread.c @@ -31,10 +31,13 @@ static bool hwthread_detect_rtos(struct target *target); static int hwthread_create(struct target *target); static int hwthread_update_threads(struct rtos *rtos); +static int hwthread_get_thread_reg(struct rtos *rtos, int64_t thread_id, + uint32_t reg_num, struct rtos_reg *rtos_reg); static int hwthread_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, - struct rtos_reg **reg_list, int *num_regs); + struct rtos_reg **reg_list, int *num_regs); static int hwthread_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[]); static int hwthread_smp_init(struct target *target); +int hwthread_set_reg(struct rtos *rtos, uint32_t reg_num, uint8_t *reg_value); #define HW_THREAD_NAME_STR_SIZE (32) @@ -51,8 +54,10 @@ const struct rtos_type hwthread_rtos = { .create = hwthread_create, .update_threads = hwthread_update_threads, .get_thread_reg_list = hwthread_get_thread_reg_list, + .get_thread_reg = hwthread_get_thread_reg, .get_symbol_list_to_lookup = hwthread_get_symbol_list_to_lookup, .smp_init = hwthread_smp_init, + .set_reg = hwthread_set_reg, }; struct hwthread_params { @@ -87,13 +92,10 @@ static int hwthread_update_threads(struct rtos *rtos) enum target_debug_reason current_reason = DBG_REASON_UNDEFINED; if (rtos == NULL) - return -1; + return ERROR_FAIL; target = rtos->target; - /* wipe out previous thread details if any */ - rtos_free_threadlist(rtos); - /* determine the number of "threads" */ if (target->smp) { for (head = target->head; head != NULL; head = head->next) { @@ -104,9 +106,16 @@ static int hwthread_update_threads(struct rtos *rtos) ++thread_list_size; } + + assert(thread_list_size); } else thread_list_size = 1; + /* Wipe out previous thread details if any, but preserve threadid. */ + int64_t current_threadid = rtos->current_threadid; + rtos_free_threadlist(rtos); + rtos->current_threadid = current_threadid; + /* create space for new thread details */ rtos->thread_details = malloc(sizeof(struct thread_detail) * thread_list_size); @@ -201,64 +210,114 @@ static int hwthread_smp_init(struct target *target) return hwthread_update_threads(target->rtos); } -static int hwthread_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, - struct rtos_reg **rtos_reg_list, int *num_regs) +static struct target *find_thread(struct target *target, int64_t thread_id) { - struct target_list *head; - struct target *target; - struct target *curr; - struct reg **reg_list; - int retval; - - if (rtos == NULL) - return ERROR_FAIL; - - target = rtos->target; - /* Find the thread with that thread_id */ + if (target == NULL) + return NULL; if (target->smp) { - curr = NULL; - for (head = target->head; head != NULL; head = head->next) { - curr = head->target; - - if (thread_id == threadid_from_target(curr)) - break; + for (struct target_list *head = target->head; head != NULL; head = head->next) { + if (thread_id == threadid_from_target(head->target)) + return head->target; } + } else if (thread_id == threadid_from_target(target)) { + return target; + } + return NULL; +} - if (head == NULL) - return ERROR_FAIL; - } else { - curr = target; - if (thread_id != threadid_from_target(curr)) - return ERROR_FAIL; +static int hwthread_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, + struct rtos_reg **rtos_reg_list, int *rtos_reg_list_size) +{ + if (rtos == NULL) + return ERROR_FAIL; - } + struct target *target = rtos->target; + + struct target *curr = find_thread(target, thread_id); + if (curr == NULL) + return ERROR_FAIL; if (!target_was_examined(curr)) return ERROR_FAIL; - retval = target_get_gdb_reg_list(curr, ®_list, num_regs, + struct reg **reg_list; + int retval = target_get_gdb_reg_list(curr, ®_list, rtos_reg_list_size, REG_CLASS_GENERAL); if (retval != ERROR_OK) return retval; - *rtos_reg_list = calloc(*num_regs, sizeof(struct rtos_reg)); + *rtos_reg_list = calloc(*rtos_reg_list_size, sizeof(struct rtos_reg)); if (*rtos_reg_list == NULL) { free(reg_list); return ERROR_FAIL; } - for (int i = 0; i < *num_regs; i++) { + for (int i = 0; i < *rtos_reg_list_size; i++) { (*rtos_reg_list)[i].number = (*reg_list)[i].number; (*rtos_reg_list)[i].size = (*reg_list)[i].size; memcpy((*rtos_reg_list)[i].value, (*reg_list)[i].value, - ((*reg_list)[i].size + 7) / 8); + ((*reg_list)[i].size + 7) / 8); } - free(reg_list); return ERROR_OK; +} + +static int hwthread_get_thread_reg(struct rtos *rtos, int64_t thread_id, + uint32_t reg_num, struct rtos_reg *rtos_reg) +{ + if (rtos == NULL) + return ERROR_FAIL; + struct target *target = rtos->target; + + struct target *curr = find_thread(target, thread_id); + if (curr == NULL) { + LOG_ERROR("Couldn't find RTOS thread for id %" PRId64 ".", thread_id); + return ERROR_FAIL; + } + + if (!target_was_examined(curr)) { + LOG_ERROR("Target %d hasn't been examined yet.", curr->coreid); + return ERROR_FAIL; + } + + struct reg *reg = register_get_by_number(curr->reg_cache, reg_num, true); + if (!reg) { + LOG_ERROR("Couldn't find register %d in thread %" PRId64 ".", reg_num, + thread_id); + return ERROR_FAIL; + } + + if (reg->type->get(reg) != ERROR_OK) + return ERROR_FAIL; + + rtos_reg->number = reg->number; + rtos_reg->size = reg->size; + unsigned bytes = (reg->size + 7) / 8; + assert(bytes <= sizeof(rtos_reg->value)); + memcpy(rtos_reg->value, reg->value, bytes); + + return ERROR_OK; +} + +int hwthread_set_reg(struct rtos *rtos, uint32_t reg_num, uint8_t *reg_value) +{ + if (rtos == NULL) + return ERROR_FAIL; + + struct target *target = rtos->target; + + struct target *curr = find_thread(target, rtos->current_thread); + if (curr == NULL) + return ERROR_FAIL; + + struct reg *reg = register_get_by_number(curr->reg_cache, reg_num, true); + if (!reg) + return ERROR_FAIL; + + return reg->type->set(reg, reg_value); } static int hwthread_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[]) @@ -272,26 +331,10 @@ static int hwthread_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[] static int hwthread_target_for_threadid(struct connection *connection, int64_t thread_id, struct target **p_target) { struct target *target = get_target_from_connection(connection); - struct target_list *head; - struct target *curr; - if (target->smp) { - /* Find the thread with that thread_id */ - curr = NULL; - for (head = target->head; head != NULL; head = head->next) { - curr = head->target; - - if (thread_id == threadid_from_target(curr)) - break; - } - - if (head == NULL) - return ERROR_FAIL; - } else { - curr = target; - if (thread_id != threadid_from_target(curr)) - return ERROR_FAIL; - } + struct target *curr = find_thread(target, thread_id); + if (curr == NULL) + return ERROR_FAIL; *p_target = curr; @@ -312,6 +355,7 @@ static int hwthread_thread_packet(struct connection *connection, const char *pac int64_t current_threadid; if (packet[0] == 'H' && packet[1] == 'g') { + /* Never reached, because this case is handled by rtos_thread_packet(). */ sscanf(packet, "Hg%16" SCNx64, ¤t_threadid); if (current_threadid > 0) { diff --git a/src/rtos/rtos.c b/src/rtos/rtos.c index da0a503..4dcc54f 100644 --- a/src/rtos/rtos.c +++ b/src/rtos/rtos.c @@ -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, - ®_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, ®_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, + ®_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, diff --git a/src/rtos/rtos.h b/src/rtos/rtos.h index b346047..517b321 100644 --- a/src/rtos/rtos.h +++ b/src/rtos/rtos.h @@ -20,6 +20,7 @@ #define OPENOCD_RTOS_RTOS_H #include "server/server.h" +#include "target/target.h" #include <jim-nvp.h> typedef int64_t threadid_t; @@ -49,7 +50,9 @@ struct rtos { symbol_table_elem_t *symbols; struct target *target; /* add a context variable instead of global variable */ + /* The thread currently selected by gdb. */ int64_t current_threadid; + /* The currently selected thread according to the target. */ threadid_t current_thread; struct thread_detail *thread_details; int thread_count; @@ -70,11 +73,15 @@ struct rtos_type { int (*create)(struct target *target); int (*smp_init)(struct target *target); int (*update_threads)(struct rtos *rtos); + /** Return a list of general registers, with their values filled out. */ int (*get_thread_reg_list)(struct rtos *rtos, int64_t thread_id, struct rtos_reg **reg_list, int *num_regs); + int (*get_thread_reg)(struct rtos *rtos, int64_t thread_id, + uint32_t reg_num, struct rtos_reg *reg); int (*get_symbol_list_to_lookup)(symbol_table_elem_t *symbol_list[]); int (*clean)(struct target *target); char * (*ps_command)(struct target *target); + int (*set_reg)(struct rtos *rtos, uint32_t reg_num, uint8_t *reg_value); }; struct stack_register_offset { @@ -104,6 +111,8 @@ struct rtos_register_stacking { #define GDB_THREAD_PACKET_NOT_CONSUMED (-40) int rtos_create(Jim_GetOptInfo *goi, struct target *target); +int rtos_set_reg(struct connection *connection, int reg_num, + uint8_t *reg_value); int rtos_generic_stack_read(struct target *target, const struct rtos_register_stacking *stacking, int64_t stack_ptr, diff --git a/src/server/gdb_server.c b/src/server/gdb_server.c index 95e6c04..dc912c9 100644 --- a/src/server/gdb_server.c +++ b/src/server/gdb_server.c @@ -724,7 +724,7 @@ static int gdb_output(struct command_context *context, const char *line) static void gdb_signal_reply(struct target *target, struct connection *connection) { struct gdb_connection *gdb_connection = connection->priv; - char sig_reply[45]; + char sig_reply[65]; char stop_reason[20]; char current_thread[25]; int sig_reply_len; @@ -735,17 +735,25 @@ static void gdb_signal_reply(struct target *target, struct connection *connectio if (target->debug_reason == DBG_REASON_EXIT) { sig_reply_len = snprintf(sig_reply, sizeof(sig_reply), "W00"); } else { + struct target *ct; + if (target->rtos != NULL) { + target->rtos->current_threadid = target->rtos->current_thread; + target->rtos->gdb_target_for_threadid(connection, target->rtos->current_threadid, &ct); + } else { + ct = target; + } + if (gdb_connection->ctrl_c) { signal_var = 0x2; } else - signal_var = gdb_last_signal(target); + signal_var = gdb_last_signal(ct); stop_reason[0] = '\0'; - if (target->debug_reason == DBG_REASON_WATCHPOINT) { + if (ct->debug_reason == DBG_REASON_WATCHPOINT) { enum watchpoint_rw hit_wp_type; target_addr_t hit_wp_address; - if (watchpoint_hit(target, &hit_wp_type, &hit_wp_address) == ERROR_OK) { + if (watchpoint_hit(ct, &hit_wp_type, &hit_wp_address) == ERROR_OK) { switch (hit_wp_type) { case WPT_WRITE: @@ -767,15 +775,9 @@ static void gdb_signal_reply(struct target *target, struct connection *connectio } current_thread[0] = '\0'; - if (target->rtos != NULL) { - struct target *ct; - snprintf(current_thread, sizeof(current_thread), "thread:%016" PRIx64 ";", + if (target->rtos != NULL) + snprintf(current_thread, sizeof(current_thread), "thread:%" PRIx64 ";", target->rtos->current_thread); - target->rtos->current_threadid = target->rtos->current_thread; - target->rtos->gdb_target_for_threadid(connection, target->rtos->current_threadid, &ct); - if (!gdb_connection->ctrl_c) - signal_var = gdb_last_signal(ct); - } sig_reply_len = snprintf(sig_reply, sizeof(sig_reply), "T%2.2x%s%s", signal_var, stop_reason, current_thread); @@ -1306,7 +1308,7 @@ static int gdb_get_register_packet(struct connection *connection, 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, + retval = target_get_gdb_reg_list_noread(target, ®_list, ®_list_size, REG_CLASS_ALL); if (retval != ERROR_OK) return gdb_error(connection, retval); @@ -1342,37 +1344,49 @@ static int gdb_set_register_packet(struct connection *connection, { struct target *target = get_target_from_connection(connection); char *separator; - uint8_t *bin_buf; int reg_num = strtoul(packet + 1, &separator, 16); struct reg **reg_list; int reg_list_size; int retval; +#ifdef _DEBUG_GDB_IO_ LOG_DEBUG("-"); +#endif - retval = target_get_gdb_reg_list(target, ®_list, ®_list_size, + if (*separator != '=') { + LOG_ERROR("GDB 'set register packet', but no '=' following the register number"); + return ERROR_SERVER_REMOTE_CLOSED; + } + size_t chars = strlen(separator + 1); + uint8_t *bin_buf = malloc(chars / 2); + gdb_target_to_reg(target, separator + 1, chars, bin_buf); + + if ((target->rtos != NULL) && + (ERROR_OK == rtos_set_reg(connection, reg_num, bin_buf))) { + free(bin_buf); + gdb_put_packet(connection, "OK", 2); + return ERROR_OK; + } + + retval = target_get_gdb_reg_list_noread(target, ®_list, ®_list_size, REG_CLASS_ALL); - if (retval != ERROR_OK) + if (retval != ERROR_OK) { + free(bin_buf); return gdb_error(connection, retval); + } if (reg_list_size <= reg_num) { LOG_ERROR("gdb requested a non-existing register"); + free(bin_buf); + free(reg_list); return ERROR_SERVER_REMOTE_CLOSED; } - if (*separator != '=') { - LOG_ERROR("GDB 'set register packet', but no '=' following the register number"); - return ERROR_SERVER_REMOTE_CLOSED; - } - - /* convert from GDB-string (target-endian) to hex-string (big-endian) */ - bin_buf = malloc(DIV_ROUND_UP(reg_list[reg_num]->size, 8)); - int chars = (DIV_ROUND_UP(reg_list[reg_num]->size, 8) * 2); - - if ((unsigned int)chars != strlen(separator + 1)) { - LOG_ERROR("gdb sent %zu bits for a %d-bit register (%s)", - strlen(separator + 1) * 4, chars * 4, reg_list[reg_num]->name); + if (chars != (DIV_ROUND_UP(reg_list[reg_num]->size, 8) * 2)) { + LOG_ERROR("gdb sent %d bits for a %d-bit register (%s)", + (int) chars * 4, reg_list[reg_num]->size, reg_list[reg_num]->name); free(bin_buf); + free(reg_list); return ERROR_SERVER_REMOTE_CLOSED; } @@ -1642,7 +1656,7 @@ static int gdb_breakpoint_watchpoint_packet(struct connection *connection, char *separator; int retval; - LOG_DEBUG("-"); + LOG_DEBUG("[%d]", target->coreid); type = strtoul(packet + 1, &separator, 16); @@ -2208,7 +2222,7 @@ static int gdb_generate_target_description(struct target *target, char **tdesc_o arch_defined_types = calloc(1, sizeof(char *)); - retval = target_get_gdb_reg_list(target, ®_list, + retval = target_get_gdb_reg_list_noread(target, ®_list, ®_list_size, REG_CLASS_ALL); if (retval != ERROR_OK) { @@ -2396,10 +2410,11 @@ static int gdb_target_description_supported(struct target *target, int *supporte char const *architecture = target_get_gdb_arch(target); - retval = target_get_gdb_reg_list(target, ®_list, + retval = target_get_gdb_reg_list_noread(target, ®_list, ®_list_size, REG_CLASS_ALL); if (retval != ERROR_OK) { LOG_ERROR("get register list failed"); + reg_list = NULL; goto error; } @@ -2791,13 +2806,11 @@ static bool gdb_handle_vcont_packet(struct connection *connection, const char *p if (parse[0] == 'c') { parse += 1; - packet_size -= 1; /* check if thread-id follows */ if (parse[0] == ':') { int64_t tid; parse += 1; - packet_size -= 1; tid = strtoll(parse, &endp, 16); if (tid == thread_id) { @@ -2887,10 +2900,9 @@ static int gdb_v_packet(struct connection *connection, char const *packet, int packet_size) { struct gdb_connection *gdb_connection = connection->priv; - struct target *target; int result; - target = get_target_from_connection(connection); + struct target *target = get_target_from_connection(connection); if (strncmp(packet, "vCont", 5) == 0) { bool handled; 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 380a9fc..0af8dd2 100644 --- a/src/target/target.c +++ b/src/target/target.c @@ -1224,6 +1224,17 @@ int target_get_gdb_reg_list(struct target *target, return target->type->get_gdb_reg_list(target, reg_list, reg_list_size, reg_class); } +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) { /* @@ -1593,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 %d", event, + Jim_Nvp_value2name_simple(nvp_target_event, event)->name, + target->coreid); target_handle_event(target, event); diff --git a/src/target/target.h b/src/target/target.h index 65494af..8dde03d 100644 --- a/src/target/target.h +++ b/src/target/target.h @@ -502,6 +502,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> -- _______________________________________________ OpenOCD-devel mailing list OpenOCD-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/openocd-devel