Skip to content

Commit

Permalink
arch: riscv: stacktrace: implement arch_stack_walk()
Browse files Browse the repository at this point in the history
Created the `arch_stack_walk()` function out from the original
`z_riscv_unwind_stack()`. Updated test case accordingly.

Signed-off-by: Yong Cong Sin <ycsin@meta.com>
  • Loading branch information
ycsin committed May 31, 2024
1 parent 9e7ce19 commit 0c6c067
Show file tree
Hide file tree
Showing 6 changed files with 69 additions and 47 deletions.
8 changes: 8 additions & 0 deletions arch/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -411,6 +412,13 @@ config ARCH_STACKWALK
help
Select Y here to enable the `arch_stack_walk()` function for stack unwinding.

config ARCH_STACKWALK_MAX_FRAMES
int "Max depth for stack walk function"
default 8
depends on ARCH_STACKWALK
help
Blah

menu "Interrupt Configuration"

config ISR_TABLES_LOCAL_DECLARATION_SUPPORTED
Expand Down
1 change: 1 addition & 0 deletions arch/riscv/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ config RISCV_ALWAYS_SWITCH_THROUGH_ECALL
config RISCV_EXCEPTION_STACK_TRACE
bool
default y
depends on ARCH_STACKWALK
depends on EXCEPTION_STACK_TRACE
imply THREAD_STACK_INFO
help
Expand Down
2 changes: 1 addition & 1 deletion arch/riscv/core/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +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_library_sources_ifdef(CONFIG_ARCH_STACKWALK stacktrace.c)
zephyr_linker_sources(ROM_START SORT_KEY 0x0vectors vector_table.ld)
95 changes: 54 additions & 41 deletions arch/riscv/core/stacktrace.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,34 +14,14 @@ 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 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 z_arch_esf_t *esf)
{
#ifdef CONFIG_THREAD_STACK_INFO
Expand Down Expand Up @@ -86,23 +66,19 @@ static inline bool in_text_region(uintptr_t addr)
}

#ifdef CONFIG_FRAME_POINTER
void z_riscv_unwind_stack(const z_arch_esf_t *esf)
static void walk_stackframe(const z_arch_esf_t *esf, bool (*fn)(void *, unsigned long), void *arg)
{
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
Expand All @@ -111,36 +87,73 @@ void z_riscv_unwind_stack(const z_arch_esf_t *esf)
}
fp = frame->fp;
}

LOG_ERR("");
}
#else /* !CONFIG_FRAME_POINTER */
void z_riscv_unwind_stack(const z_arch_esf_t *esf)
static void walk_stackframe(const z_arch_esf_t *esf, bool (*fn)(void *, unsigned long), void *arg)
{
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
*/
i++;
}
}
}
#endif /* CONFIG_FRAME_POINTER */

void arch_stack_walk(stack_trace_consume_fn consume_entry, void *cookie, void *thread,
const void *esf)
{
ARG_UNUSED(thread);

walk_stackframe(esf, consume_entry, cookie);
}

#ifdef CONFIG_RISCV_EXCEPTION_STACK_TRACE
#ifdef CONFIG_EXCEPTION_STACK_TRACE_SYMTAB
#if __riscv_xlen == 32
#define PR_REG "%08" PRIxPTR
#elif __riscv_xlen == 64
#define PR_REG "%016" PRIxPTR
#endif

#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 z_arch_esf_t *esf)
{
int i = 0;

LOG_ERR("call trace:");
arch_stack_walk(print_trace_address, &i, NULL, esf);
LOG_ERR("");
}
#endif /* CONFIG_FRAME_POINTER */
#endif /* CONFIG_RISCV_EXCEPTION_STACK_TRACE */
2 changes: 1 addition & 1 deletion include/zephyr/arch/arch_interface.h
Original file line number Diff line number Diff line change
Expand Up @@ -1266,7 +1266,7 @@ typedef bool (*stack_trace_consume_fn)(void *cookie, unsigned long addr);
* ============ ======= ============================================
*/
void arch_stack_walk(stack_trace_consume_fn consume_entry, void *cookie,
k_thread *thread, const void *esf);
void *thread, const void *esf);
#endif /* CONFIG_ARCH_STACKWALK */

#ifdef __cplusplus
Expand Down
8 changes: 4 additions & 4 deletions tests/arch/common/stack_unwind/testcase.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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:
Expand Down

0 comments on commit 0c6c067

Please sign in to comment.