arch: riscv: relocate stack unwinding code into a separate file

Declutter `fatal.c` by moving the stack unwinding logic into
`stacktrace.c` and guard its compilation with `CMakeLists.txt`.

Signed-off-by: Yong Cong Sin <ycsin@meta.com>
This commit is contained in:
Yong Cong Sin 2024-05-16 17:45:47 +08:00 committed by Anas Nashif
commit 8c6da49f73
3 changed files with 135 additions and 113 deletions

View file

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

View file

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

View file

@ -0,0 +1,126 @@
/*
* Copyright (c) 2024 Meta Platforms
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/kernel.h>
#include <zephyr/kernel_structs.h>
#include <kernel_internal.h>
#include <zephyr/logging/log.h>
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 */