diff --git a/arch/Kconfig b/arch/Kconfig index e338cdd4da025..ac4f089bd4ccf 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -48,6 +48,7 @@ config ARM64 select ARCH_SUPPORTS_COREDUMP select HAS_ARM_SMCCC select ARCH_HAS_THREAD_LOCAL_STORAGE + select ARCH_HAS_STACKWALK select USE_SWITCH select USE_SWITCH_SUPPORTED select IRQ_OFFLOAD_NESTED if IRQ_OFFLOAD @@ -89,6 +90,7 @@ config X86 select ARCH_HAS_TIMING_FUNCTIONS select ARCH_HAS_THREAD_LOCAL_STORAGE select ARCH_HAS_DEMAND_PAGING if !X86_64 + select ARCH_HAS_STACKWALK select IRQ_OFFLOAD_NESTED if IRQ_OFFLOAD select NEED_LIBC_MEM_PARTITION if USERSPACE && TIMING_FUNCTIONS \ && !BOARD_HAS_TIMING_FUNCTIONS \ diff --git a/arch/arm64/core/fatal.c b/arch/arm64/core/fatal.c index a02ae13acf89c..e5b40a6702582 100644 --- a/arch/arm64/core/fatal.c +++ b/arch/arm64/core/fatal.c @@ -196,7 +196,23 @@ static void esf_dump(const struct arch_esf *esf) } #ifdef CONFIG_EXCEPTION_STACK_TRACE -static void esf_unwind(const struct arch_esf *esf) +static bool print_trace_address(void *arg, unsigned long lr) +{ + int *i = arg; +#ifdef CONFIG_SYMTAB + uint32_t offset = 0; + const char *name = symtab_find_symbol_name(lr, &offset); + + LOG_ERR("backtrace %2d: lr: 0x%016lx [%s+0x%x]", (*i)++, lr, name, offset); +#else + LOG_ERR("backtrace %2d: lr: 0x%016lx", (*i)++, lr); +#endif /* CONFIG_SYMTAB */ + + return true; +} + +static void walk_stackframe(stack_trace_callback_fn cb, void *cookie, const struct arch_esf *esf, + int max_frames) { /* * For GCC: @@ -218,31 +234,53 @@ static void esf_unwind(const struct arch_esf *esf) * + +-----------------+ */ - uint64_t *fp = (uint64_t *) esf->fp; - unsigned int count = 0; + uint64_t *fp; uint64_t lr; - LOG_ERR(""); - for (int i = 0; (fp != NULL) && (i < CONFIG_EXCEPTION_STACK_TRACE_MAX_FRAMES); i++) { - lr = fp[1]; -#ifdef CONFIG_SYMTAB - uint32_t offset = 0; - const char *name = symtab_find_symbol_name(lr, &offset); + if (esf != NULL) { + fp = (uint64_t *) esf->fp; + } else { + return; + } - LOG_ERR("backtrace %2d: fp: 0x%016llx lr: 0x%016llx [%s+0x%x]", - count++, (uint64_t) fp, lr, name, offset); -#else - LOG_ERR("backtrace %2d: fp: 0x%016llx lr: 0x%016llx", - count++, (uint64_t) fp, lr); -#endif + for (int i = 0; (fp != NULL) && (i < max_frames); i++) { + lr = fp[1]; + if (!cb(cookie, lr)) { + break; + } fp = (uint64_t *) fp[0]; } +} + +static void esf_unwind(const struct arch_esf *esf) +{ + int i = 0; + + LOG_ERR(""); + walk_stackframe(print_trace_address, &i, esf, CONFIG_EXCEPTION_STACK_TRACE_MAX_FRAMES); LOG_ERR(""); } #endif #endif /* CONFIG_EXCEPTION_DEBUG */ +void arch_stack_walk(stack_trace_callback_fn callback_fn, void *cookie, + const struct k_thread *thread, const struct arch_esf *esf) +{ +#ifdef CONFIG_EXCEPTION_STACK_TRACE + ARG_UNUSED(thread); + + walk_stackframe(callback_fn, cookie, esf, CONFIG_ARCH_STACKWALK_MAX_FRAMES); +#else + ARG_UNUSED(callback_fn); + ARG_UNUSED(cookie); + ARG_UNUSED(thread); + ARG_UNUSED(esf); + + LOG_DBG("Enable CONFIG_EXCEPTION_STACK_TRACE for %s()", __func__); +#endif /* CONFIG_EXCEPTION_STACK_TRACE */ +} + #ifdef CONFIG_ARM64_STACK_PROTECTION static bool z_arm64_stack_corruption_check(struct arch_esf *esf, uint64_t esr, uint64_t far) { diff --git a/arch/x86/core/fatal.c b/arch/x86/core/fatal.c index 4eafd999bc784..3ecddcdadd9c4 100644 --- a/arch/x86/core/fatal.c +++ b/arch/x86/core/fatal.c @@ -140,20 +140,44 @@ struct stack_frame { #endif }; -#define MAX_STACK_FRAMES CONFIG_EXCEPTION_STACK_TRACE_MAX_FRAMES +static bool print_trace_address(void *arg, unsigned long addr) +{ + ARG_UNUSED(arg); -__pinned_func -static void unwind_stack(uintptr_t base_ptr, uint16_t cs) +#ifdef CONFIG_X86_64 + LOG_ERR(" 0x%016lx", addr); +#else + LOG_ERR(" 0x%08lx", addr); +#endif + + return true; +} + +__pinned_func static void walk_stackframe(stack_trace_callback_fn cb, void *cookie, + const struct arch_esf *esf, int max_frames) { + uintptr_t base_ptr; + uint16_t cs; struct stack_frame *frame; int i; + if (esf != NULL) { +#ifdef CONFIG_X86_64 + base_ptr = esf->rbp; +#else /* x86 32-bit */ + base_ptr = esf->ebp; +#endif /* CONFIG_X86_64 */ + cs = esf->cs; + } else { + return; + } + if (base_ptr == 0U) { LOG_ERR("NULL base ptr"); return; } - for (i = 0; i < MAX_STACK_FRAMES; i++) { + for (i = 0; i < max_frames; i++) { if (base_ptr % sizeof(base_ptr) != 0U) { LOG_ERR("unaligned frame ptr"); return; @@ -178,16 +202,40 @@ static void unwind_stack(uintptr_t base_ptr, uint16_t cs) if (frame->ret_addr == 0U) { break; } -#ifdef CONFIG_X86_64 - LOG_ERR(" 0x%016lx", frame->ret_addr); -#else - LOG_ERR(" 0x%08lx (0x%lx)", frame->ret_addr, frame->args); -#endif + + if (!cb(cookie, frame->ret_addr)) { + break; + } + base_ptr = frame->next; } } + +__pinned_func +static void unwind_stack(const struct arch_esf *esf) +{ + walk_stackframe(print_trace_address, NULL, esf, + CONFIG_EXCEPTION_STACK_TRACE_MAX_FRAMES); +} #endif /* CONFIG_EXCEPTION_STACK_TRACE */ +void arch_stack_walk(stack_trace_callback_fn callback_fn, void *cookie, + const struct k_thread *thread, const struct arch_esf *esf) +{ +#ifdef CONFIG_EXCEPTION_STACK_TRACE + ARG_UNUSED(thread); + + walk_stackframe(callback_fn, cookie, esf, CONFIG_ARCH_STACKWALK_MAX_FRAMES); +#else + ARG_UNUSED(callback_fn); + ARG_UNUSED(cookie); + ARG_UNUSED(thread); + ARG_UNUSED(esf); + + LOG_DBG("Enable CONFIG_EXCEPTION_STACK_TRACE for %s()", __func__); +#endif /* CONFIG_EXCEPTION_STACK_TRACE */ +} + static inline uintptr_t get_cr3(const struct arch_esf *esf) { #if defined(CONFIG_USERSPACE) && defined(CONFIG_X86_KPTI) @@ -231,7 +279,7 @@ static void dump_regs(const struct arch_esf *esf) #endif LOG_ERR("RIP: 0x%016lx", esf->rip); #ifdef CONFIG_EXCEPTION_STACK_TRACE - unwind_stack(esf->rbp, esf->cs); + unwind_stack(esf); #endif } #else /* 32-bit */ @@ -250,7 +298,7 @@ static void dump_regs(const struct arch_esf *esf) #endif LOG_ERR("EIP: 0x%08x", esf->eip); #ifdef CONFIG_EXCEPTION_STACK_TRACE - unwind_stack(esf->ebp, esf->cs); + unwind_stack(esf); #endif } #endif /* CONFIG_X86_64 */ diff --git a/tests/arch/common/stack_unwind/testcase.yaml b/tests/arch/common/stack_unwind/testcase.yaml index a6d6c52c30a1a..5c6ab32ab1c7f 100644 --- a/tests/arch/common/stack_unwind/testcase.yaml +++ b/tests/arch/common/stack_unwind/testcase.yaml @@ -53,8 +53,8 @@ tests: harness_config: type: multi_line regex: - - "E: backtrace 0: fp: \\w+ lr: \\w+" - - "E: backtrace 1: fp: \\w+ lr: \\w+" + - "E: backtrace 0: lr: \\w+" + - "E: backtrace 1: lr: \\w+" arch.common.stack_unwind.symtab: arch_allow: - riscv