arch: riscv: Add support for stack unwind without fp

Add a stack unwind implementation that only uses `sp`

Signed-off-by: Yong Cong Sin <ycsin@meta.com>
This commit is contained in:
Yong Cong Sin 2024-05-13 15:55:24 +08:00 committed by Anas Nashif
commit 10a807537b
3 changed files with 65 additions and 18 deletions

View file

@ -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

View file

@ -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);

View file

@ -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: