From 10a807537bea1041e5332353b3d41f027ee53eb3 Mon Sep 17 00:00:00 2001 From: Yong Cong Sin Date: Mon, 13 May 2024 15:55:24 +0800 Subject: [PATCH] arch: riscv: Add support for stack unwind without fp Add a stack unwind implementation that only uses `sp` Signed-off-by: Yong Cong Sin --- arch/riscv/Kconfig | 1 - arch/riscv/core/fatal.c | 69 +++++++++++++++----- tests/arch/common/stack_unwind/testcase.yaml | 13 +++- 3 files changed, 65 insertions(+), 18 deletions(-) diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index 77d1c7aa53a..965ff4e3f8d 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -50,7 +50,6 @@ config RISCV_ENABLE_FRAME_POINTER config RISCV_EXCEPTION_STACK_TRACE bool default y - depends on RISCV_ENABLE_FRAME_POINTER depends on EXCEPTION_STACK_TRACE imply THREAD_STACK_INFO help diff --git a/arch/riscv/core/fatal.c b/arch/riscv/core/fatal.c index 07809c488aa..47abb7c0977 100644 --- a/arch/riscv/core/fatal.c +++ b/arch/riscv/core/fatal.c @@ -28,6 +28,27 @@ static const struct z_exc_handle exceptions[] = { #define NO_REG " " #endif +static inline uintptr_t get_sp(const z_arch_esf_t *esf) +{ + /* + * Kernel stack pointer prior this exception i.e. before + * storing the exception stack frame. + */ + uintptr_t sp = (uintptr_t)esf + sizeof(z_arch_esf_t); + +#ifdef CONFIG_USERSPACE + if ((esf->mstatus & MSTATUS_MPP) == PRV_U) { + /* + * Exception happened in user space: + * consider the saved user stack instead. + */ + sp = esf->sp; + } +#endif + + return sp; +} + #ifdef CONFIG_RISCV_EXCEPTION_STACK_TRACE #define MAX_STACK_FRAMES 8 @@ -75,6 +96,7 @@ static inline bool in_text_region(uintptr_t addr) 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; @@ -103,6 +125,36 @@ static void unwind_stack(const z_arch_esf_t *esf) 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, @@ -116,12 +168,6 @@ FUNC_NORETURN void z_riscv_fatal_error_csf(unsigned int reason, const z_arch_esf { #ifdef CONFIG_EXCEPTION_DEBUG if (esf != NULL) { - /* - * Kernel stack pointer prior this exception i.e. before - * storing the exception stack frame. - */ - uintptr_t sp = (uintptr_t)esf + sizeof(z_arch_esf_t); - LOG_ERR(" a0: " PR_REG " t0: " PR_REG, esf->a0, esf->t0); LOG_ERR(" a1: " PR_REG " t1: " PR_REG, esf->a1, esf->t1); LOG_ERR(" a2: " PR_REG " t2: " PR_REG, esf->a2, esf->t2); @@ -136,16 +182,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 */ -#ifdef CONFIG_USERSPACE - if ((esf->mstatus & MSTATUS_MPP) == 0) { - /* - * Exception happened in user space: - * consider the saved user stack instead. - */ - sp = esf->sp; - } -#endif - LOG_ERR(" sp: " PR_REG, sp); + LOG_ERR(" sp: " PR_REG, get_sp(esf)); LOG_ERR(" ra: " PR_REG, esf->ra); LOG_ERR(" mepc: " PR_REG, esf->mepc); LOG_ERR("mstatus: " PR_REG, esf->mstatus); diff --git a/tests/arch/common/stack_unwind/testcase.yaml b/tests/arch/common/stack_unwind/testcase.yaml index b935b5c596e..9f29790f95c 100644 --- a/tests/arch/common/stack_unwind/testcase.yaml +++ b/tests/arch/common/stack_unwind/testcase.yaml @@ -4,7 +4,7 @@ common: ignore_qemu_crash: true tags: kernel tests: - arch.common.stack_unwind.riscv: + arch.common.stack_unwind.riscv_fp: arch_allow: riscv integration_platforms: - qemu_riscv32 @@ -16,6 +16,17 @@ tests: - "E: call trace:" - "E: 0: fp: \\w+ ra: \\w+" - "E: 1: fp: \\w+ ra: \\w+" + arch.common.stack_unwind.riscv_sp: + arch_allow: riscv + integration_platforms: + - qemu_riscv32 + - qemu_riscv64 + harness_config: + type: multi_line + regex: + - "E: call trace:" + - "E: 0: sp: \\w+ ra: \\w+" + - "E: 1: sp: \\w+ ra: \\w+" arch.common.stack_unwind.x86: arch_allow: x86 extra_configs: