diff --git a/arch/riscv/core/CMakeLists.txt b/arch/riscv/core/CMakeLists.txt index 1d8daac060c..7ffcffd65c8 100644 --- a/arch/riscv/core/CMakeLists.txt +++ b/arch/riscv/core/CMakeLists.txt @@ -25,4 +25,5 @@ zephyr_library_sources_ifdef(CONFIG_RISCV_PMP pmp.c pmp.S) zephyr_library_sources_ifdef(CONFIG_THREAD_LOCAL_STORAGE tls.c) zephyr_library_sources_ifdef(CONFIG_USERSPACE userspace.S) zephyr_library_sources_ifdef(CONFIG_SEMIHOST semihost.c) +zephyr_library_sources_ifdef(CONFIG_RISCV_EXCEPTION_STACK_TRACE stacktrace.c) zephyr_linker_sources(ROM_START SORT_KEY 0x0vectors vector_table.ld) diff --git a/arch/riscv/core/fatal.c b/arch/riscv/core/fatal.c index 47abb7c0977..8efffd37371 100644 --- a/arch/riscv/core/fatal.c +++ b/arch/riscv/core/fatal.c @@ -28,7 +28,10 @@ static const struct z_exc_handle exceptions[] = { #define NO_REG " " #endif -static inline uintptr_t get_sp(const z_arch_esf_t *esf) +/* Stack trace function */ +void z_riscv_unwind_stack(const z_arch_esf_t *esf); + +uintptr_t z_riscv_get_sp_before_exc(const z_arch_esf_t *esf) { /* * Kernel stack pointer prior this exception i.e. before @@ -49,114 +52,6 @@ static inline uintptr_t get_sp(const z_arch_esf_t *esf) return sp; } -#ifdef CONFIG_RISCV_EXCEPTION_STACK_TRACE -#define MAX_STACK_FRAMES 8 - -struct stackframe { - uintptr_t fp; - uintptr_t ra; -}; - -static bool in_stack_bound(uintptr_t addr) -{ -#ifdef CONFIG_THREAD_STACK_INFO - uintptr_t start, end; - - if (_current == NULL || arch_is_in_isr()) { - /* We were servicing an interrupt */ - int cpu_id; - -#ifdef CONFIG_SMP - cpu_id = arch_curr_cpu()->id; -#else - cpu_id = 0; -#endif - - start = (uintptr_t)K_KERNEL_STACK_BUFFER(z_interrupt_stacks[cpu_id]); - end = start + CONFIG_ISR_STACK_SIZE; -#ifdef CONFIG_USERSPACE - /* TODO: handle user threads */ -#endif - } else { - start = _current->stack_info.start; - end = Z_STACK_PTR_ALIGN(_current->stack_info.start + _current->stack_info.size); - } - - return (addr >= start) && (addr < end); -#else - ARG_UNUSED(addr); - return true; -#endif /* CONFIG_THREAD_STACK_INFO */ -} - -static inline bool in_text_region(uintptr_t addr) -{ - extern uintptr_t __text_region_start, __text_region_end; - - return (addr >= (uintptr_t)&__text_region_start) && (addr < (uintptr_t)&__text_region_end); -} - -#ifdef CONFIG_RISCV_ENABLE_FRAME_POINTER -static void unwind_stack(const z_arch_esf_t *esf) -{ - uintptr_t fp = esf->s0; - uintptr_t ra; - struct stackframe *frame; - - if (esf == NULL) { - return; - } - - LOG_ERR("call trace:"); - - for (int i = 0; (i < MAX_STACK_FRAMES) && (fp != 0U) && in_stack_bound(fp);) { - frame = (struct stackframe *)fp - 1; - ra = frame->ra; - if (in_text_region(ra)) { - LOG_ERR(" %2d: fp: " PR_REG " ra: " PR_REG, i, fp, ra); - /* - * Increment the iterator only if `ra` is within the text region to get the - * most out of it - */ - i++; - } - fp = frame->fp; - } - - LOG_ERR(""); -} -#else /* !CONFIG_RISCV_ENABLE_FRAME_POINTER */ -static void unwind_stack(const z_arch_esf_t *esf) -{ - uintptr_t sp = get_sp(esf); - uintptr_t ra; - uintptr_t *ksp = (uintptr_t *)sp; - - if (esf == NULL) { - return; - } - - LOG_ERR("call trace:"); - - for (int i = 0; - (i < MAX_STACK_FRAMES) && ((uintptr_t)ksp != 0U) && in_stack_bound((uintptr_t)ksp); - ksp++) { - ra = *ksp; - if (in_text_region(ra)) { - LOG_ERR(" %2d: sp: " PR_REG " ra: " PR_REG, i, (uintptr_t)ksp, ra); - /* - * Increment the iterator only if `ra` is within the text region to get the - * most out of it - */ - i++; - } - } - - LOG_ERR(""); -} -#endif /* CONFIG_RISCV_ENABLE_FRAME_POINTER */ -#endif /* CONFIG_RISCV_EXCEPTION_STACK_TRACE */ - FUNC_NORETURN void z_riscv_fatal_error(unsigned int reason, const z_arch_esf_t *esf) { @@ -182,7 +77,7 @@ FUNC_NORETURN void z_riscv_fatal_error_csf(unsigned int reason, const z_arch_esf LOG_ERR(" a6: " PR_REG " t6: " PR_REG, esf->a6, esf->t6); LOG_ERR(" a7: " PR_REG, esf->a7); #endif /* CONFIG_RISCV_ISA_RV32E */ - LOG_ERR(" sp: " PR_REG, get_sp(esf)); + LOG_ERR(" sp: " PR_REG, z_riscv_get_sp_before_exc(esf)); LOG_ERR(" ra: " PR_REG, esf->ra); LOG_ERR(" mepc: " PR_REG, esf->mepc); LOG_ERR("mstatus: " PR_REG, esf->mstatus); @@ -204,9 +99,9 @@ FUNC_NORETURN void z_riscv_fatal_error_csf(unsigned int reason, const z_arch_esf LOG_ERR(""); } -#ifdef CONFIG_RISCV_EXCEPTION_STACK_TRACE - unwind_stack(esf); -#endif /* CONFIG_RISCV_EXCEPTION_STACK_TRACE */ + if (IS_ENABLED(CONFIG_RISCV_EXCEPTION_STACK_TRACE)) { + z_riscv_unwind_stack(esf); + } #endif /* CONFIG_EXCEPTION_DEBUG */ z_fatal_error(reason, esf); diff --git a/arch/riscv/core/stacktrace.c b/arch/riscv/core/stacktrace.c new file mode 100644 index 00000000000..a85dcfbd82d --- /dev/null +++ b/arch/riscv/core/stacktrace.c @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2024 Meta Platforms + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include + +LOG_MODULE_DECLARE(os, CONFIG_KERNEL_LOG_LEVEL); + +uintptr_t z_riscv_get_sp_before_exc(const z_arch_esf_t *esf); + +#if __riscv_xlen == 32 + #define PR_REG "%08" PRIxPTR +#elif __riscv_xlen == 64 + #define PR_REG "%016" PRIxPTR +#endif + +#define MAX_STACK_FRAMES 8 + +struct stackframe { + uintptr_t fp; + uintptr_t ra; +}; + +static bool in_stack_bound(uintptr_t addr) +{ +#ifdef CONFIG_THREAD_STACK_INFO + uintptr_t start, end; + + if (_current == NULL || arch_is_in_isr()) { + /* We were servicing an interrupt */ + int cpu_id; + +#ifdef CONFIG_SMP + cpu_id = arch_curr_cpu()->id; +#else + cpu_id = 0; +#endif + + start = (uintptr_t)K_KERNEL_STACK_BUFFER(z_interrupt_stacks[cpu_id]); + end = start + CONFIG_ISR_STACK_SIZE; +#ifdef CONFIG_USERSPACE + /* TODO: handle user threads */ +#endif + } else { + start = _current->stack_info.start; + end = Z_STACK_PTR_ALIGN(_current->stack_info.start + _current->stack_info.size); + } + + return (addr >= start) && (addr < end); +#else + ARG_UNUSED(addr); + return true; +#endif /* CONFIG_THREAD_STACK_INFO */ +} + +static inline bool in_text_region(uintptr_t addr) +{ + extern uintptr_t __text_region_start, __text_region_end; + + return (addr >= (uintptr_t)&__text_region_start) && (addr < (uintptr_t)&__text_region_end); +} + +#ifdef CONFIG_RISCV_ENABLE_FRAME_POINTER +void z_riscv_unwind_stack(const z_arch_esf_t *esf) +{ + uintptr_t fp = esf->s0; + uintptr_t ra; + struct stackframe *frame; + + if (esf == NULL) { + return; + } + + LOG_ERR("call trace:"); + + for (int i = 0; (i < MAX_STACK_FRAMES) && (fp != 0U) && in_stack_bound(fp);) { + frame = (struct stackframe *)fp - 1; + ra = frame->ra; + if (in_text_region(ra)) { + LOG_ERR(" %2d: fp: " PR_REG " ra: " PR_REG, i, fp, ra); + /* + * Increment the iterator only if `ra` is within the text region to get the + * most out of it + */ + i++; + } + fp = frame->fp; + } + + LOG_ERR(""); +} +#else /* !CONFIG_RISCV_ENABLE_FRAME_POINTER */ +void z_riscv_unwind_stack(const z_arch_esf_t *esf) +{ + uintptr_t sp = z_riscv_get_sp_before_exc(esf); + uintptr_t ra; + uintptr_t *ksp = (uintptr_t *)sp; + + if (esf == NULL) { + return; + } + + LOG_ERR("call trace:"); + + for (int i = 0; + (i < MAX_STACK_FRAMES) && ((uintptr_t)ksp != 0U) && in_stack_bound((uintptr_t)ksp); + ksp++) { + ra = *ksp; + if (in_text_region(ra)) { + LOG_ERR(" %2d: sp: " PR_REG " ra: " PR_REG, i, (uintptr_t)ksp, ra); + /* + * Increment the iterator only if `ra` is within the text region to get the + * most out of it + */ + i++; + } + } + + LOG_ERR(""); +} +#endif /* CONFIG_RISCV_ENABLE_FRAME_POINTER */