diff options
Diffstat (limited to 'src/rtos')
-rw-r--r-- | src/rtos/Makefile.am | 10 | ||||
-rw-r--r-- | src/rtos/chibios.c | 18 | ||||
-rw-r--r-- | src/rtos/ecos.c (renamed from src/rtos/eCos.c) | 0 | ||||
-rw-r--r-- | src/rtos/embkernel.c (renamed from src/rtos/embKernel.c) | 0 | ||||
-rw-r--r-- | src/rtos/freertos.c (renamed from src/rtos/FreeRTOS.c) | 0 | ||||
-rw-r--r-- | src/rtos/hwthread.c | 94 | ||||
-rw-r--r-- | src/rtos/linux.c | 33 | ||||
-rw-r--r-- | src/rtos/mqx.c | 5 | ||||
-rw-r--r-- | src/rtos/nuttx.c | 54 | ||||
-rw-r--r-- | src/rtos/rtos.c | 12 | ||||
-rw-r--r-- | src/rtos/rtos_nuttx_stackings.c | 134 | ||||
-rw-r--r-- | src/rtos/rtos_nuttx_stackings.h | 9 | ||||
-rw-r--r-- | src/rtos/rtos_standard_stackings.c | 4 | ||||
-rw-r--r-- | src/rtos/threadx.c (renamed from src/rtos/ThreadX.c) | 0 | ||||
-rw-r--r-- | src/rtos/ucos_iii.c (renamed from src/rtos/uCOS-III.c) | 0 |
15 files changed, 192 insertions, 181 deletions
diff --git a/src/rtos/Makefile.am b/src/rtos/Makefile.am index 0796910..5267fea 100644 --- a/src/rtos/Makefile.am +++ b/src/rtos/Makefile.am @@ -11,15 +11,15 @@ noinst_LTLIBRARIES += %D%/librtos.la %D%/rtos_ucos_iii_stackings.c \ %D%/rtos_riot_stackings.c \ %D%/rtos_nuttx_stackings.c \ - %D%/FreeRTOS.c \ - %D%/ThreadX.c \ - %D%/eCos.c \ + %D%/freertos.c \ + %D%/threadx.c \ + %D%/ecos.c \ %D%/linux.c \ %D%/chibios.c \ %D%/chromium-ec.c \ - %D%/embKernel.c \ + %D%/embkernel.c \ %D%/mqx.c \ - %D%/uCOS-III.c \ + %D%/ucos_iii.c \ %D%/nuttx.c \ %D%/rtkernel.c \ %D%/hwthread.c \ diff --git a/src/rtos/chibios.c b/src/rtos/chibios.c index c1e4e84..af590c2 100644 --- a/src/rtos/chibios.c +++ b/src/rtos/chibios.c @@ -31,7 +31,7 @@ struct chibios_chdebug { char ch_identifier[4]; /**< @brief Always set to "main". */ uint8_t ch_zero; /**< @brief Must be zero. */ uint8_t ch_size; /**< @brief Size of this structure. */ - uint16_t ch_version; /**< @brief Encoded ChibiOS/RT version. */ + uint8_t ch_version[2]; /**< @brief Encoded ChibiOS/RT version. */ uint8_t ch_ptrsize; /**< @brief Size of a pointer. */ uint8_t ch_timesize; /**< @brief Size of a @p systime_t. */ uint8_t ch_threadsize; /**< @brief Size of a @p Thread struct. */ @@ -171,13 +171,7 @@ static int chibios_update_memory_signature(struct rtos *rtos) " expected. Assuming compatibility..."); } - /* Convert endianness of version field */ - const uint8_t *versiontarget = (const uint8_t *) - &signature->ch_version; - signature->ch_version = rtos->target->endianness == TARGET_LITTLE_ENDIAN ? - le_to_h_u32(versiontarget) : be_to_h_u32(versiontarget); - - const uint16_t ch_version = signature->ch_version; + const uint16_t ch_version = target_buffer_get_u16(rtos->target, signature->ch_version); LOG_INFO("Successfully loaded memory map of ChibiOS/RT target " "running version %i.%i.%i", GET_CH_KERNEL_MAJOR(ch_version), GET_CH_KERNEL_MINOR(ch_version), GET_CH_KERNEL_PATCH(ch_version)); @@ -427,9 +421,11 @@ static int chibios_update_threads(struct rtos *rtos) else state_desc = "Unknown"; - curr_thrd_details->extra_info_str = malloc(strlen( - state_desc)+8); - sprintf(curr_thrd_details->extra_info_str, "State: %s", state_desc); + curr_thrd_details->extra_info_str = alloc_printf("State: %s", state_desc); + if (!curr_thrd_details->extra_info_str) { + LOG_ERROR("Could not allocate space for thread state description"); + return -1; + } curr_thrd_details->exists = true; diff --git a/src/rtos/eCos.c b/src/rtos/ecos.c index 7048b00..7048b00 100644 --- a/src/rtos/eCos.c +++ b/src/rtos/ecos.c diff --git a/src/rtos/embKernel.c b/src/rtos/embkernel.c index 7e6de79..7e6de79 100644 --- a/src/rtos/embKernel.c +++ b/src/rtos/embkernel.c diff --git a/src/rtos/FreeRTOS.c b/src/rtos/freertos.c index 02409a5..02409a5 100644 --- a/src/rtos/FreeRTOS.c +++ b/src/rtos/freertos.c diff --git a/src/rtos/hwthread.c b/src/rtos/hwthread.c index f256bc2..3e4a4ec 100644 --- a/src/rtos/hwthread.c +++ b/src/rtos/hwthread.c @@ -36,7 +36,18 @@ struct target *hwthread_swbp_target(struct rtos *rtos, target_addr_t address, static inline threadid_t threadid_from_target(const struct target *target) { - return target->coreid + 1; + if (!target->smp) + return 1; + + threadid_t threadid = 1; + struct target_list *head; + foreach_smp_target(head, target->smp_targets) { + if (target == head->target) + return threadid; + ++threadid; + } + assert(0 && "Target is not found in it's own SMP group!"); + return -1; } const struct rtos_type hwthread_rtos = { @@ -59,14 +70,13 @@ struct hwthread_params { int dummy_param; }; -static int hwthread_fill_thread(struct rtos *rtos, struct target *curr, int thread_num) +static int hwthread_fill_thread(struct rtos *rtos, struct target *curr, int thread_num, threadid_t tid) { char tmp_str[HW_THREAD_NAME_STR_SIZE]; - threadid_t tid = threadid_from_target(curr); memset(tmp_str, 0, HW_THREAD_NAME_STR_SIZE); - /* thread-id is the core-id of this core inside the SMP group plus 1 */ + /* thread-id is the index of this core inside the SMP group plus 1 */ rtos->thread_details[thread_num].threadid = tid; /* create the thread name */ rtos->thread_details[thread_num].exists = true; @@ -115,7 +125,7 @@ static int hwthread_update_threads(struct rtos *rtos) if (current_threadid <= thread_list_size) rtos->current_threadid = current_threadid; else - LOG_WARNING("SMP node change, disconnect GDB from core/thread %" PRId64, + LOG_TARGET_WARNING(target, "SMP node change, disconnect GDB from core/thread %" PRId64, current_threadid); /* create space for new thread details */ @@ -131,8 +141,7 @@ static int hwthread_update_threads(struct rtos *rtos) continue; threadid_t tid = threadid_from_target(curr); - - hwthread_fill_thread(rtos, curr, threads_found); + hwthread_fill_thread(rtos, curr, threads_found, tid); /* find an interesting thread to set as current */ switch (current_reason) { @@ -152,9 +161,8 @@ static int hwthread_update_threads(struct rtos *rtos) if (curr->debug_reason == DBG_REASON_SINGLESTEP) { current_reason = curr->debug_reason; current_thread = tid; - } else - /* multiple breakpoints, prefer gdbs' threadid */ - if (curr->debug_reason == DBG_REASON_BREAKPOINT) { + } else if (curr->debug_reason == DBG_REASON_BREAKPOINT) { + /* multiple breakpoints, prefer gdbs' threadid */ if (tid == rtos->current_threadid) current_thread = tid; } @@ -174,8 +182,7 @@ static int hwthread_update_threads(struct rtos *rtos) curr->debug_reason == DBG_REASON_BREAKPOINT) { current_reason = curr->debug_reason; current_thread = tid; - } else - if (curr->debug_reason == DBG_REASON_DBGRQ) { + } else if (curr->debug_reason == DBG_REASON_DBGRQ) { if (tid == rtos->current_threadid) current_thread = tid; } @@ -189,8 +196,8 @@ static int hwthread_update_threads(struct rtos *rtos) threads_found++; } } else { - hwthread_fill_thread(rtos, target, threads_found); - current_thread = threadid_from_target(target); + current_thread = 1; + hwthread_fill_thread(rtos, target, threads_found, current_thread); threads_found++; } @@ -204,7 +211,8 @@ static int hwthread_update_threads(struct rtos *rtos) else rtos->current_thread = threadid_from_target(target); - LOG_DEBUG("current_thread=%i, threads_found=%d", (int)rtos->current_thread, threads_found); + LOG_TARGET_DEBUG(target, "current_thread=%i, threads_found=%d", + (int)rtos->current_thread, threads_found); return 0; } @@ -213,19 +221,17 @@ static int hwthread_smp_init(struct target *target) return hwthread_update_threads(target->rtos); } -static struct target *hwthread_find_thread(struct target *target, int64_t thread_id) +static struct target *hwthread_find_thread(struct target *target, threadid_t thread_id) { - /* Find the thread with that thread_id */ - if (!target) - return NULL; - if (target->smp) { - struct target_list *head; - foreach_smp_target(head, target->smp_targets) { - if (thread_id == threadid_from_target(head->target)) - return head->target; - } - } else if (thread_id == threadid_from_target(target)) { + /* Find the thread with that thread_id (index in SMP group plus 1)*/ + if (!(target && target->smp)) return target; + struct target_list *head; + threadid_t tid = 1; + foreach_smp_target(head, target->smp_targets) { + if (thread_id == tid) + return head->target; + ++tid; } return NULL; } @@ -254,7 +260,7 @@ static int hwthread_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, int j = 0; for (int i = 0; i < reg_list_size; i++) { - if (!reg_list[i] || reg_list[i]->exist == false || reg_list[i]->hidden) + if (!reg_list[i] || !reg_list[i]->exist || reg_list[i]->hidden) continue; j++; } @@ -267,12 +273,13 @@ static int hwthread_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, j = 0; for (int i = 0; i < reg_list_size; i++) { - if (!reg_list[i] || reg_list[i]->exist == false || reg_list[i]->hidden) + if (!reg_list[i] || !reg_list[i]->exist || reg_list[i]->hidden) continue; if (!reg_list[i]->valid) { retval = reg_list[i]->type->get(reg_list[i]); if (retval != ERROR_OK) { - LOG_ERROR("Couldn't get register %s.", reg_list[i]->name); + LOG_TARGET_ERROR(curr, "Couldn't get register %s", + reg_list[i]->name); free(reg_list); free(*rtos_reg_list); return retval; @@ -299,19 +306,20 @@ static int hwthread_get_thread_reg_value(struct rtos *rtos, int64_t thread_id, struct target *curr = hwthread_find_thread(target, thread_id); if (!curr) { - LOG_ERROR("Couldn't find RTOS thread for id %" PRId64 ".", thread_id); + LOG_TARGET_ERROR(target, "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); + LOG_TARGET_ERROR(curr, "Target hasn't been examined yet."); return ERROR_FAIL; } struct reg *reg = register_get_by_number(curr->reg_cache, reg_num, true); if (!reg) { - LOG_ERROR("Couldn't find register %" PRIu32 " in thread %" PRId64 ".", reg_num, - thread_id); + LOG_TARGET_ERROR(curr, "Couldn't find register %" PRIu32 " in thread %" PRId64, + reg_num, thread_id); return ERROR_FAIL; } @@ -319,7 +327,7 @@ static int hwthread_get_thread_reg_value(struct rtos *rtos, int64_t thread_id, return ERROR_FAIL; *size = reg->size; - unsigned bytes = DIV_ROUND_UP(reg->size, 8); + unsigned int bytes = DIV_ROUND_UP(reg->size, 8); *value = malloc(bytes); if (!*value) { LOG_ERROR("Failed to allocate memory for %d-bit register.", reg->size); @@ -377,24 +385,24 @@ static bool hwthread_detect_rtos(struct target *target) static int hwthread_thread_packet(struct connection *connection, const char *packet, int packet_size) { - struct target *target = get_target_from_connection(connection); - - struct target *curr = NULL; - int64_t current_threadid; - if (packet[0] == 'H' && packet[1] == 'g') { + int64_t current_threadid; sscanf(packet, "Hg%16" SCNx64, ¤t_threadid); + struct target *target = get_target_from_connection(connection); + if (current_threadid > 0) { + struct target *curr = NULL; if (hwthread_target_for_threadid(connection, current_threadid, &curr) != ERROR_OK) { - LOG_ERROR("hwthread: cannot find thread id %"PRId64, current_threadid); + LOG_TARGET_ERROR(target, "hwthread: cannot find thread id %" PRId64, + current_threadid); gdb_put_packet(connection, "E01", 3); return ERROR_FAIL; } target->rtos->current_thread = current_threadid; - } else - if (current_threadid == 0 || current_threadid == -1) + } else if (current_threadid == 0 || current_threadid == -1) { target->rtos->current_thread = threadid_from_target(target); + } target->rtos->current_threadid = current_threadid; @@ -407,7 +415,7 @@ static int hwthread_thread_packet(struct connection *connection, const char *pac static int hwthread_create(struct target *target) { - LOG_INFO("Hardware thread awareness created"); + LOG_TARGET_INFO(target, "Hardware thread awareness created"); target->rtos->rtos_specific_params = NULL; target->rtos->current_thread = 0; diff --git a/src/rtos/linux.c b/src/rtos/linux.c index 7517ec7..5efdc9f 100644 --- a/src/rtos/linux.c +++ b/src/rtos/linux.c @@ -624,7 +624,7 @@ static struct threads *liste_add_task(struct threads *task_list, struct threads { t->next = NULL; - if (!*last) + if (!*last) { if (!task_list) { task_list = t; return task_list; @@ -637,7 +637,8 @@ static struct threads *liste_add_task(struct threads *task_list, struct threads temp->next = t; *last = t; return task_list; - } else { + } + } else { (*last)->next = t; *last = t; return task_list; @@ -1039,6 +1040,10 @@ static int linux_gdb_thread_packet(struct target *target, return ERROR_TARGET_FAILURE; char *out_str = calloc(MAX_THREADS * 17 + 10, 1); + if (!out_str) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; + } char *tmp_str = out_str; tmp_str += sprintf(tmp_str, "m"); struct threads *temp = linux_os->thread_list; @@ -1115,23 +1120,13 @@ static int linux_thread_extra_info(struct target *target, while (temp) { if (temp->threadid == threadid) { - char *pid = " PID: "; - char *pid_current = "*PID: "; - char *name = "Name: "; - int str_size = strlen(pid) + strlen(name); - char *tmp_str = calloc(1, str_size + 50); - char *tmp_str_ptr = tmp_str; - - /* discriminate current task */ - if (temp->status == 3) - tmp_str_ptr += sprintf(tmp_str_ptr, "%s", - pid_current); - else - tmp_str_ptr += sprintf(tmp_str_ptr, "%s", pid); - - tmp_str_ptr += sprintf(tmp_str_ptr, "%d, ", (int)temp->pid); - sprintf(tmp_str_ptr, "%s", name); - sprintf(tmp_str_ptr, "%s", temp->name); + char *tmp_str = alloc_printf("%cPID: %" PRIu32 ", Name: %s", + temp->status == 3 ? '*' : ' ', + temp->pid, temp->name); + if (!tmp_str) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; + } char *hex_str = calloc(1, strlen(tmp_str) * 2 + 1); size_t pkt_len = hexify(hex_str, (const uint8_t *)tmp_str, strlen(tmp_str), strlen(tmp_str) * 2 + 1); diff --git a/src/rtos/mqx.c b/src/rtos/mqx.c index b4a1821..017fd2b 100644 --- a/src/rtos/mqx.c +++ b/src/rtos/mqx.c @@ -319,7 +319,7 @@ static int mqx_update_threads( i < (uint32_t)rtos->thread_count; i++ ) { - uint8_t task_name[MQX_THREAD_NAME_LENGTH + 1]; + char task_name[MQX_THREAD_NAME_LENGTH + 1]; uint32_t task_addr = 0, task_template = 0, task_state = 0; uint32_t task_name_addr = 0, task_id = 0, task_errno = 0; uint32_t state_index = 0; @@ -380,10 +380,9 @@ static int mqx_update_threads( rtos->thread_details[i].threadid = task_id; rtos->thread_details[i].exists = true; /* set thread name */ - rtos->thread_details[i].thread_name_str = malloc(strlen((void *)task_name) + 1); + rtos->thread_details[i].thread_name_str = strdup(task_name); if (!rtos->thread_details[i].thread_name_str) return ERROR_FAIL; - strcpy(rtos->thread_details[i].thread_name_str, (void *)task_name); /* set thread extra info * - task state * - task address diff --git a/src/rtos/nuttx.c b/src/rtos/nuttx.c index 9100148..821e550 100644 --- a/src/rtos/nuttx.c +++ b/src/rtos/nuttx.c @@ -32,7 +32,6 @@ struct nuttx_params { const char *target_name; const struct rtos_register_stacking *stacking; - const struct rtos_register_stacking *(*select_stackinfo)(struct target *target); }; /* @@ -56,19 +55,12 @@ struct symbols { bool optional; }; -/* Used to index the list of retrieved symbols. See nuttx_symbol_list for the order. */ -enum nuttx_symbol_vals { - NX_SYM_READYTORUN = 0, - NX_SYM_PIDHASH, - NX_SYM_NPIDHASH, - NX_SYM_TCB_INFO, -}; - static const struct symbols nuttx_symbol_list[] = { { "g_readytorun", false }, { "g_pidhash", false }, { "g_npidhash", false }, { "g_tcbinfo", false }, + { "g_reg_offs", false}, { NULL, false } }; @@ -86,18 +78,14 @@ static char *task_state_str[] = { "STOPPED", }; -static const struct rtos_register_stacking *cortexm_select_stackinfo(struct target *target); - static const struct nuttx_params nuttx_params_list[] = { { .target_name = "cortex_m", - .stacking = NULL, - .select_stackinfo = cortexm_select_stackinfo, + .stacking = &nuttx_stacking_cortex_m, }, { .target_name = "hla_target", - .stacking = NULL, - .select_stackinfo = cortexm_select_stackinfo, + .stacking = &nuttx_stacking_cortex_m, }, { .target_name = "esp32", @@ -117,28 +105,6 @@ static const struct nuttx_params nuttx_params_list[] = { }, }; -static bool cortexm_hasfpu(struct target *target) -{ - uint32_t cpacr; - struct armv7m_common *armv7m_target = target_to_armv7m(target); - - if (!is_armv7m(armv7m_target) || armv7m_target->fp_feature == FP_NONE) - return false; - - int retval = target_read_u32(target, FPU_CPACR, &cpacr); - if (retval != ERROR_OK) { - LOG_ERROR("Could not read CPACR register to check FPU state"); - return false; - } - - return cpacr & 0x00F00000; -} - -static const struct rtos_register_stacking *cortexm_select_stackinfo(struct target *target) -{ - return cortexm_hasfpu(target) ? &nuttx_stacking_cortex_m_fpu : &nuttx_stacking_cortex_m; -} - static bool nuttx_detect_rtos(struct target *target) { if (target->rtos->symbols && @@ -371,29 +337,25 @@ static int nuttx_getreg_current_thread(struct rtos *rtos, static int nuttx_getregs_fromstack(struct rtos *rtos, int64_t thread_id, struct rtos_reg **reg_list, int *num_regs) { - uint16_t xcpreg_off; + uint16_t regs_off; uint32_t regsaddr; const struct nuttx_params *priv = rtos->rtos_specific_params; const struct rtos_register_stacking *stacking = priv->stacking; if (!stacking) { - if (priv->select_stackinfo) { - stacking = priv->select_stackinfo(rtos->target); - } else { - LOG_ERROR("Can't find a way to get stacking info"); - return ERROR_FAIL; - } + LOG_ERROR("Can't find a way to get stacking info"); + return ERROR_FAIL; } int ret = target_read_u16(rtos->target, rtos->symbols[NX_SYM_TCB_INFO].address + offsetof(struct tcbinfo, regs_off), - &xcpreg_off); + ®s_off); if (ret != ERROR_OK) { LOG_ERROR("Failed to read registers' offset: ret = %d", ret); return ERROR_FAIL; } - ret = target_read_u32(rtos->target, thread_id + xcpreg_off, ®saddr); + ret = target_read_u32(rtos->target, thread_id + regs_off, ®saddr); if (ret != ERROR_OK) { LOG_ERROR("Failed to read registers' address: ret = %d", ret); return ERROR_FAIL; diff --git a/src/rtos/rtos.c b/src/rtos/rtos.c index b5e8e9a..e87e51c 100644 --- a/src/rtos/rtos.c +++ b/src/rtos/rtos.c @@ -109,7 +109,7 @@ int rtos_create(struct jim_getopt_info *goi, struct target *target) Jim_Obj *res; int e; - if (!goi->isconfigure && goi->argc != 0) { + if (!goi->is_configure && goi->argc != 0) { Jim_WrongNumArgs(goi->interp, goi->argc, goi->argv, "NO PARAMS"); return JIM_ERR; } @@ -317,7 +317,7 @@ int rtos_qsymbol(struct connection *connection, char const *packet, int packet_s reply_len += 2 * strlen(next_suffix); /* hexify(..., next_suffix, ...) */ reply_len += 1; /* Terminating NUL */ if (reply_len > sizeof(reply)) { - LOG_ERROR("ERROR: RTOS symbol '%s%s' name is too long for GDB!", next_sym->symbol_name, next_suffix); + LOG_ERROR("RTOS symbol '%s%s' name is too long for GDB", next_sym->symbol_name, next_suffix); goto done; } @@ -370,6 +370,10 @@ int rtos_thread_packet(struct connection *connection, char const *packet, int pa str_size += strlen(detail->extra_info_str); char *tmp_str = calloc(str_size + 9, sizeof(char)); + if (!tmp_str) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; + } char *tmp_str_ptr = tmp_str; if (detail->thread_name_str) @@ -397,7 +401,7 @@ int rtos_thread_packet(struct connection *connection, char const *packet, int pa return ERROR_OK; } else if (strncmp(packet, "qSymbol", 7) == 0) { if (rtos_qsymbol(connection, packet, packet_size) == 1) { - if (target->rtos_auto_detect == true) { + if (target->rtos_auto_detect) { target->rtos_auto_detect = false; target->rtos->type->create(target); } @@ -635,7 +639,7 @@ int rtos_generic_stack_read(struct target *target, int retval; if (stack_ptr == 0) { - LOG_ERROR("Error: null stack pointer in thread"); + LOG_ERROR("null stack pointer in thread"); return -5; } /* Read the stack */ diff --git a/src/rtos/rtos_nuttx_stackings.c b/src/rtos/rtos_nuttx_stackings.c index b70cccb..6faa56a 100644 --- a/src/rtos/rtos_nuttx_stackings.c +++ b/src/rtos/rtos_nuttx_stackings.c @@ -9,60 +9,100 @@ #include "rtos_nuttx_stackings.h" #include "rtos_standard_stackings.h" #include <target/riscv/riscv.h> +#include <helper/bits.h> -/* see arch/arm/include/armv7-m/irq_cmnvector.h */ +/* The cortex_m target uses nuttx_tcbinfo_stack_read which uses a symbol + * provided by Nuttx to read the registers from memory and place them directly + * in the order we need. This is because the register offsets change with + * different versions of Nuttx, FPU vs non-FPU and ARMv7 vs ARMv8. + * This allows a single function to work with many versions. + */ static const struct stack_register_offset nuttx_stack_offsets_cortex_m[] = { - { ARMV7M_R0, 0x28, 32 }, /* r0 */ - { ARMV7M_R1, 0x2c, 32 }, /* r1 */ - { ARMV7M_R2, 0x30, 32 }, /* r2 */ - { ARMV7M_R3, 0x34, 32 }, /* r3 */ - { ARMV7M_R4, 0x08, 32 }, /* r4 */ - { ARMV7M_R5, 0x0c, 32 }, /* r5 */ - { ARMV7M_R6, 0x10, 32 }, /* r6 */ - { ARMV7M_R7, 0x14, 32 }, /* r7 */ - { ARMV7M_R8, 0x18, 32 }, /* r8 */ - { ARMV7M_R9, 0x1c, 32 }, /* r9 */ - { ARMV7M_R10, 0x20, 32 }, /* r10 */ - { ARMV7M_R11, 0x24, 32 }, /* r11 */ - { ARMV7M_R12, 0x38, 32 }, /* r12 */ - { ARMV7M_R13, 0, 32 }, /* sp */ - { ARMV7M_R14, 0x3c, 32 }, /* lr */ - { ARMV7M_PC, 0x40, 32 }, /* pc */ - { ARMV7M_XPSR, 0x44, 32 }, /* xPSR */ + { ARMV7M_R0, 0, 32 }, /* r0 */ + { ARMV7M_R1, 4, 32 }, /* r1 */ + { ARMV7M_R2, 8, 32 }, /* r2 */ + { ARMV7M_R3, 12, 32 }, /* r3 */ + { ARMV7M_R4, 16, 32 }, /* r4 */ + { ARMV7M_R5, 20, 32 }, /* r5 */ + { ARMV7M_R6, 24, 32 }, /* r6 */ + { ARMV7M_R7, 28, 32 }, /* r7 */ + { ARMV7M_R8, 32, 32 }, /* r8 */ + { ARMV7M_R9, 36, 32 }, /* r9 */ + { ARMV7M_R10, 40, 32 }, /* r10 */ + { ARMV7M_R11, 44, 32 }, /* r11 */ + { ARMV7M_R12, 48, 32 }, /* r12 */ + { ARMV7M_R13, 52, 32 }, /* sp */ + { ARMV7M_R14, 56, 32 }, /* lr */ + { ARMV7M_PC, 60, 32 }, /* pc */ + { ARMV7M_XPSR, 64, 32 }, /* xPSR */ }; -const struct rtos_register_stacking nuttx_stacking_cortex_m = { - .stack_registers_size = 0x48, - .stack_growth_direction = -1, - .num_output_registers = 17, - .register_offsets = nuttx_stack_offsets_cortex_m, -}; +/* The Nuttx stack frame for most architectures has some registers placed + * by hardware and some by software. The hardware register order and number does not change + * but the software registers may change with different versions of Nuttx. + * For example with ARMv7, nuttx-12.3.0 added a new register which changed all + * the offsets. We can either create separate offset tables for each version of Nuttx + * which will break again in the future, or read the offsets from the TCB info. + * Nuttx provides a symbol (g_reg_offs) which holds all the offsets for each stored register. + * This offset table is stored in GDB org.gnu.gdb.xxx feature order. + * The same order we need. + * Please refer: + * https://sourceware.org/gdb/current/onlinedocs/gdb/ARM-Features.html + * https://sourceware.org/gdb/current/onlinedocs/gdb/RISC_002dV-Features.html + */ +static int nuttx_cortex_m_tcbinfo_stack_read(struct target *target, + int64_t stack_ptr, const struct rtos_register_stacking *stacking, + uint8_t *stack_data) +{ + struct rtos *rtos = target->rtos; + target_addr_t xcpreg_off = rtos->symbols[NX_SYM_REG_OFFSETS].address; -static const struct stack_register_offset nuttx_stack_offsets_cortex_m_fpu[] = { - { ARMV7M_R0, 0x6c, 32 }, /* r0 */ - { ARMV7M_R1, 0x70, 32 }, /* r1 */ - { ARMV7M_R2, 0x74, 32 }, /* r2 */ - { ARMV7M_R3, 0x78, 32 }, /* r3 */ - { ARMV7M_R4, 0x08, 32 }, /* r4 */ - { ARMV7M_R5, 0x0c, 32 }, /* r5 */ - { ARMV7M_R6, 0x10, 32 }, /* r6 */ - { ARMV7M_R7, 0x14, 32 }, /* r7 */ - { ARMV7M_R8, 0x18, 32 }, /* r8 */ - { ARMV7M_R9, 0x1c, 32 }, /* r9 */ - { ARMV7M_R10, 0x20, 32 }, /* r10 */ - { ARMV7M_R11, 0x24, 32 }, /* r11 */ - { ARMV7M_R12, 0x7c, 32 }, /* r12 */ - { ARMV7M_R13, 0, 32 }, /* sp */ - { ARMV7M_R14, 0x80, 32 }, /* lr */ - { ARMV7M_PC, 0x84, 32 }, /* pc */ - { ARMV7M_XPSR, 0x88, 32 }, /* xPSR */ -}; + for (int i = 0; i < stacking->num_output_registers; ++i) { + uint16_t stack_reg_offset; + int ret = target_read_u16(rtos->target, xcpreg_off + 2 * i, &stack_reg_offset); + if (ret != ERROR_OK) { + LOG_ERROR("Failed to read stack_reg_offset: ret = %d", ret); + return ret; + } + if (stack_reg_offset != UINT16_MAX && stacking->register_offsets[i].offset >= 0) { + ret = target_read_buffer(target, + stack_ptr + stack_reg_offset, + stacking->register_offsets[i].width_bits / 8, + &stack_data[stacking->register_offsets[i].offset]); + if (ret != ERROR_OK) { + LOG_ERROR("Failed to read register: ret = %d", ret); + return ret; + } + } + } + + /* Offset match nuttx_stack_offsets_cortex_m */ + const int XPSR_OFFSET = 64; + const int SP_OFFSET = 52; + /* Nuttx stack frames (produced in exception_common) store the SP of the ISR minus + * the hardware stack frame size. This SP may include an additional 4 byte alignment + * depending in xPSR[9]. The Nuttx stack frame stores post alignment since the + * hardware will add/remove automatically on both enter/exit. + * We need to adjust the SP to get the real SP of the stack. + * See Arm Reference manual "Stack alignment on exception entry" + */ + uint32_t xpsr = target_buffer_get_u32(target, &stack_data[XPSR_OFFSET]); + if (xpsr & BIT(9)) { + uint32_t sp = target_buffer_get_u32(target, &stack_data[SP_OFFSET]); + target_buffer_set_u32(target, &stack_data[SP_OFFSET], sp - 4 * stacking->stack_growth_direction); + } -const struct rtos_register_stacking nuttx_stacking_cortex_m_fpu = { - .stack_registers_size = 0x8c, + return ERROR_OK; +} + +const struct rtos_register_stacking nuttx_stacking_cortex_m = { + /* nuttx_tcbinfo_stack_read transforms the stack into just output registers */ + .stack_registers_size = ARRAY_SIZE(nuttx_stack_offsets_cortex_m) * 4, .stack_growth_direction = -1, - .num_output_registers = 17, - .register_offsets = nuttx_stack_offsets_cortex_m_fpu, + .num_output_registers = ARRAY_SIZE(nuttx_stack_offsets_cortex_m), + .read_stack = nuttx_cortex_m_tcbinfo_stack_read, + .calculate_process_stack = NULL, /* Stack alignment done in nuttx_cortex_m_tcbinfo_stack_read */ + .register_offsets = nuttx_stack_offsets_cortex_m, }; static const struct stack_register_offset nuttx_stack_offsets_riscv[] = { diff --git a/src/rtos/rtos_nuttx_stackings.h b/src/rtos/rtos_nuttx_stackings.h index 213a060..5d55e75 100644 --- a/src/rtos/rtos_nuttx_stackings.h +++ b/src/rtos/rtos_nuttx_stackings.h @@ -5,6 +5,15 @@ #include "rtos.h" +/* Used to index the list of retrieved symbols. See nuttx_symbol_list for the order. */ +enum nuttx_symbol_vals { + NX_SYM_READYTORUN = 0, + NX_SYM_PIDHASH, + NX_SYM_NPIDHASH, + NX_SYM_TCB_INFO, + NX_SYM_REG_OFFSETS, +}; + extern const struct rtos_register_stacking nuttx_stacking_cortex_m; extern const struct rtos_register_stacking nuttx_stacking_cortex_m_fpu; extern const struct rtos_register_stacking nuttx_riscv_stacking; diff --git a/src/rtos/rtos_standard_stackings.c b/src/rtos/rtos_standard_stackings.c index 0ca664f..360ae9b 100644 --- a/src/rtos/rtos_standard_stackings.c +++ b/src/rtos/rtos_standard_stackings.c @@ -327,9 +327,7 @@ target_addr_t rtos_cortex_m_stack_align(struct target *target, new_stack_ptr = stack_ptr - stacking->stack_growth_direction * stacking->stack_registers_size; - xpsr = (target->endianness == TARGET_LITTLE_ENDIAN) ? - le_to_h_u32(&stack_data[xpsr_offset]) : - be_to_h_u32(&stack_data[xpsr_offset]); + xpsr = target_buffer_get_u32(target, &stack_data[xpsr_offset]); if ((xpsr & ALIGN_NEEDED) != 0) { LOG_DEBUG("XPSR(0x%08" PRIx32 ") indicated stack alignment was necessary\r\n", xpsr); diff --git a/src/rtos/ThreadX.c b/src/rtos/threadx.c index 61c4926..61c4926 100644 --- a/src/rtos/ThreadX.c +++ b/src/rtos/threadx.c diff --git a/src/rtos/uCOS-III.c b/src/rtos/ucos_iii.c index f19d06e..f19d06e 100644 --- a/src/rtos/uCOS-III.c +++ b/src/rtos/ucos_iii.c |