diff --git a/arch/Kconfig b/arch/Kconfig index 069eeb0321050a7..02b833193313ce3 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -111,6 +111,7 @@ config RISCV select ARCH_SUPPORTS_ROM_START if !SOC_SERIES_ESP32C3 select ARCH_HAS_CODE_DATA_RELOCATION select ARCH_HAS_THREAD_LOCAL_STORAGE + select ARCH_HAS_STACKWALK select IRQ_OFFLOAD_NESTED if IRQ_OFFLOAD select USE_SWITCH_SUPPORTED select USE_SWITCH @@ -405,6 +406,13 @@ config FRAME_POINTER Select Y here to gain precise stack traces at the expense of slightly increased size and decreased speed. +config ARCH_STACKWALK_MAX_FRAMES + int "Max depth for stack walk function" + default 8 + depends on ARCH_HAS_STACKWALK + help + Blah + menu "Interrupt Configuration" config ISR_TABLES_LOCAL_DECLARATION_SUPPORTED diff --git a/arch/riscv/core/stacktrace.c b/arch/riscv/core/stacktrace.c index cda6748c36371ee..a6700155e58d8c6 100644 --- a/arch/riscv/core/stacktrace.c +++ b/arch/riscv/core/stacktrace.c @@ -14,34 +14,14 @@ LOG_MODULE_DECLARE(os, CONFIG_KERNEL_LOG_LEVEL); uintptr_t z_riscv_get_sp_before_exc(const struct arch_esf *esf); -#if __riscv_xlen == 32 - #define PR_REG "%08" PRIxPTR -#elif __riscv_xlen == 64 - #define PR_REG "%016" PRIxPTR -#endif - -#define MAX_STACK_FRAMES CONFIG_EXCEPTION_STACK_TRACE_MAX_FRAMES +#define MAX_STACK_FRAMES \ + MAX(CONFIG_EXCEPTION_STACK_TRACE_MAX_FRAMES, CONFIG_ARCH_STACKWALK_MAX_FRAMES) struct stackframe { uintptr_t fp; uintptr_t ra; }; -#ifdef CONFIG_FRAME_POINTER -#define SFP_FMT "fp: " -#else -#define SFP_FMT "sp: " -#endif - -#ifdef CONFIG_EXCEPTION_STACK_TRACE_SYMTAB -#define LOG_STACK_TRACE(idx, sfp, ra, name, offset) \ - LOG_ERR(" %2d: " SFP_FMT PR_REG " ra: " PR_REG " [%s+0x%x]", idx, sfp, ra, name, \ - offset) -#else -#define LOG_STACK_TRACE(idx, sfp, ra, name, offset) \ - LOG_ERR(" %2d: " SFP_FMT PR_REG " ra: " PR_REG, idx, sfp, ra) -#endif - static bool in_stack_bound(uintptr_t addr, const struct arch_esf *esf) { #ifdef CONFIG_THREAD_STACK_INFO @@ -86,23 +66,21 @@ static inline bool in_text_region(uintptr_t addr) } #ifdef CONFIG_FRAME_POINTER -void z_riscv_unwind_stack(const struct arch_esf *esf) +static void walk_stackframe(const _callee_saved_t *csf, const struct arch_esf *esf, + bool (*fn)(void *, unsigned long), void *arg) { + ARG_UNUSED(csf); uintptr_t fp = esf->s0; uintptr_t ra; struct stackframe *frame; - LOG_ERR("call trace:"); - for (int i = 0; (i < MAX_STACK_FRAMES) && (fp != 0U) && in_stack_bound(fp, esf);) { frame = (struct stackframe *)fp - 1; ra = frame->ra; if (in_text_region(ra)) { -#ifdef CONFIG_EXCEPTION_STACK_TRACE_SYMTAB - uint32_t offset = 0; - const char *name = symtab_find_symbol_name(ra, &offset); -#endif - LOG_STACK_TRACE(i, fp, ra, name, offset); + if (!fn(arg, ra)) { + break; + } /* * Increment the iterator only if `ra` is within the text region to get the * most out of it @@ -111,28 +89,24 @@ void z_riscv_unwind_stack(const struct arch_esf *esf) } fp = frame->fp; } - - LOG_ERR(""); } #else /* !CONFIG_FRAME_POINTER */ -void z_riscv_unwind_stack(const struct arch_esf *esf) +static void walk_stackframe(const _callee_saved_t *csf, const struct arch_esf *esf, + bool (*fn)(void *, unsigned long), void *arg) { + ARG_UNUSED(csf); uintptr_t sp = z_riscv_get_sp_before_exc(esf); uintptr_t ra; uintptr_t *ksp = (uintptr_t *)sp; - LOG_ERR("call trace:"); - for (int i = 0; (i < MAX_STACK_FRAMES) && ((uintptr_t)ksp != 0U) && in_stack_bound((uintptr_t)ksp, esf); ksp++) { ra = *ksp; if (in_text_region(ra)) { -#ifdef CONFIG_EXCEPTION_STACK_TRACE_SYMTAB - uint32_t offset = 0; - const char *name = symtab_find_symbol_name(ra, &offset); -#endif - LOG_STACK_TRACE(i, (uintptr_t)ksp, ra, name, offset); + if (!fn(arg, ra)) { + break; + } /* * Increment the iterator only if `ra` is within the text region to get the * most out of it @@ -140,7 +114,46 @@ void z_riscv_unwind_stack(const struct arch_esf *esf) i++; } } +} +#endif /* CONFIG_FRAME_POINTER */ + +void arch_stack_walk(stack_trace_callback_fn callback_fn, void *cookie, + const struct k_thread *thread, const struct arch_esf *esf) +{ + walk_stackframe(&thread->callee_saved, esf, callback_fn, cookie); +} + +#if __riscv_xlen == 32 +#define PR_REG "%08" PRIxPTR +#elif __riscv_xlen == 64 +#define PR_REG "%016" PRIxPTR +#endif + +#ifdef CONFIG_EXCEPTION_STACK_TRACE_SYMTAB +#define LOG_STACK_TRACE(idx, ra, name, offset) \ + LOG_ERR(" %2d: ra: " PR_REG " [%s+0x%x]", idx, ra, name, offset) +#else +#define LOG_STACK_TRACE(idx, ra, name, offset) LOG_ERR(" %2d: ra: " PR_REG, idx, ra) +#endif /* CONFIG_EXCEPTION_STACK_TRACE_SYMTAB */ + +static bool print_trace_address(void *arg, unsigned long ra) +{ + int *i = arg; +#ifdef CONFIG_EXCEPTION_STACK_TRACE_SYMTAB + uint32_t offset = 0; + const char *name = symtab_find_symbol_name(ra, &offset); +#endif + + LOG_STACK_TRACE((*i)++, ra, name, offset); + + return true; +} + +void z_riscv_unwind_stack(const struct arch_esf *esf) +{ + int i = 0; + LOG_ERR("call trace:"); + arch_stack_walk(print_trace_address, &i, NULL, esf); LOG_ERR(""); } -#endif /* CONFIG_FRAME_POINTER */ diff --git a/tests/arch/common/stack_unwind/testcase.yaml b/tests/arch/common/stack_unwind/testcase.yaml index 1699adeae5d3749..b6fbd0f7ed8bb74 100644 --- a/tests/arch/common/stack_unwind/testcase.yaml +++ b/tests/arch/common/stack_unwind/testcase.yaml @@ -15,8 +15,8 @@ tests: type: multi_line regex: - "E: call trace:" - - "E: 0: fp: \\w+ ra: \\w+" - - "E: 1: fp: \\w+ ra: \\w+" + - "E: 0: ra: \\w+" + - "E: 1: ra: \\w+" arch.common.stack_unwind.riscv_sp: arch_allow: riscv integration_platforms: @@ -26,8 +26,8 @@ tests: type: multi_line regex: - "E: call trace:" - - "E: 0: sp: \\w+ ra: \\w+" - - "E: 1: sp: \\w+ ra: \\w+" + - "E: 0: ra: \\w+" + - "E: 1: ra: \\w+" arch.common.stack_unwind.x86: arch_allow: x86 extra_configs: