From ab676fdb86f5b0e57475d4e711d45ff073c9a11f Mon Sep 17 00:00:00 2001 From: Yong Cong Sin Date: Wed, 14 Aug 2024 17:56:26 +0800 Subject: [PATCH] arch: arm64: implement `arch_stack_walk()` Currently it supports `esf` based unwinding only. Then, update the exception stack unwinding to use `arch_stack_walk()`, and update the Kconfigs & testcase accordingly. Also, `EXCEPTION_STACK_TRACE_MAX_FRAMES` is unused and made redundant after this change, so remove it. Signed-off-by: Yong Cong Sin Signed-off-by: Yong Cong Sin --- arch/arm64/core/Kconfig | 8 +++ arch/arm64/core/fatal.c | 73 +++++++++++++++----- subsys/debug/Kconfig | 11 +-- tests/arch/common/stack_unwind/testcase.yaml | 5 +- 4 files changed, 66 insertions(+), 31 deletions(-) diff --git a/arch/arm64/core/Kconfig b/arch/arm64/core/Kconfig index 367480015c4..29f2cb6105b 100644 --- a/arch/arm64/core/Kconfig +++ b/arch/arm64/core/Kconfig @@ -161,6 +161,14 @@ config ARM64_EXCEPTION_STACK_TRACE help Internal config to enable runtime stack traces on fatal exceptions. +config ARCH_HAS_STACKWALK + bool + default y + depends on FRAME_POINTER + help + Internal config to indicate that the arch_stack_walk() API is implemented + and it can be enabled. + config ARM64_SAFE_EXCEPTION_STACK_SIZE int "The stack size of the safe exception stack" default 4096 diff --git a/arch/arm64/core/fatal.c b/arch/arm64/core/fatal.c index a02ae13acf8..53e01146422 100644 --- a/arch/arm64/core/fatal.c +++ b/arch/arm64/core/fatal.c @@ -194,9 +194,13 @@ static void esf_dump(const struct arch_esf *esf) LOG_ERR("x16: 0x%016llx x17: 0x%016llx", esf->x16, esf->x17); LOG_ERR("x18: 0x%016llx lr: 0x%016llx", esf->x18, esf->lr); } +#endif /* CONFIG_EXCEPTION_DEBUG */ -#ifdef CONFIG_EXCEPTION_STACK_TRACE -static void esf_unwind(const struct arch_esf *esf) +#ifdef CONFIG_ARCH_STACKWALK +typedef bool (*arm64_stacktrace_cb)(void *cookie, unsigned long addr, void *fp); + +static void walk_stackframe(arm64_stacktrace_cb cb, void *cookie, const struct arch_esf *esf, + int max_frames) { /* * For GCC: @@ -218,30 +222,61 @@ static void esf_unwind(const struct arch_esf *esf) * + +-----------------+ */ - uint64_t *fp = (uint64_t *) esf->fp; - unsigned int count = 0; + uint64_t *fp; uint64_t lr; - LOG_ERR(""); - for (int i = 0; (fp != NULL) && (i < CONFIG_EXCEPTION_STACK_TRACE_MAX_FRAMES); i++) { - lr = fp[1]; -#ifdef CONFIG_SYMTAB - uint32_t offset = 0; - const char *name = symtab_find_symbol_name(lr, &offset); + if (esf != NULL) { + fp = (uint64_t *) esf->fp; + } else { + return; + } - LOG_ERR("backtrace %2d: fp: 0x%016llx lr: 0x%016llx [%s+0x%x]", - count++, (uint64_t) fp, lr, name, offset); -#else - LOG_ERR("backtrace %2d: fp: 0x%016llx lr: 0x%016llx", - count++, (uint64_t) fp, lr); -#endif + for (int i = 0; (fp != NULL) && (i < max_frames); i++) { + lr = fp[1]; + if (!cb(cookie, lr, fp)) { + break; + } fp = (uint64_t *) fp[0]; } +} + +void arch_stack_walk(stack_trace_callback_fn callback_fn, void *cookie, + const struct k_thread *thread, const struct arch_esf *esf) +{ + ARG_UNUSED(thread); + + walk_stackframe((arm64_stacktrace_cb)callback_fn, cookie, esf, + CONFIG_ARCH_STACKWALK_MAX_FRAMES); +} +#endif /* CONFIG_ARCH_STACKWALK */ + +#ifdef CONFIG_EXCEPTION_STACK_TRACE +static bool print_trace_address(void *arg, unsigned long lr, void *fp) +{ + int *i = arg; +#ifdef CONFIG_SYMTAB + uint32_t offset = 0; + const char *name = symtab_find_symbol_name(lr, &offset); + + LOG_ERR(" %d: fp: 0x%016llx lr: 0x%016lx [%s+0x%x]", (*i)++, (uint64_t)fp, lr, name, + offset); +#else + LOG_ERR(" %d: fp: 0x%016llx lr: 0x%016lx", (*i)++, (uint64_t)fp, lr); +#endif /* CONFIG_SYMTAB */ + + return true; +} + +static void esf_unwind(const struct arch_esf *esf) +{ + int i = 0; + + LOG_ERR(""); + LOG_ERR("call trace:"); + walk_stackframe(print_trace_address, &i, esf, CONFIG_ARCH_STACKWALK_MAX_FRAMES); LOG_ERR(""); } -#endif - -#endif /* CONFIG_EXCEPTION_DEBUG */ +#endif /* CONFIG_EXCEPTION_STACK_TRACE */ #ifdef CONFIG_ARM64_STACK_PROTECTION static bool z_arm64_stack_corruption_check(struct arch_esf *esf, uint64_t esr, uint64_t far) diff --git a/subsys/debug/Kconfig b/subsys/debug/Kconfig index 1e5f7eadab2..0f34f75e68f 100644 --- a/subsys/debug/Kconfig +++ b/subsys/debug/Kconfig @@ -381,21 +381,12 @@ config DEBUG_INFO config EXCEPTION_STACK_TRACE bool "Attempt to print stack traces upon exceptions" default y - depends on ARM64_EXCEPTION_STACK_TRACE || ARCH_STACKWALK + depends on ARCH_STACKWALK help If the architecture fatal handling code supports it, attempt to print a stack trace of function memory addresses when an exception is reported. -config EXCEPTION_STACK_TRACE_MAX_FRAMES - int "Configures the depth of stack trace" - default ARCH_STACKWALK_MAX_FRAMES if ARCH_STACKWALK - default 8 - depends on EXCEPTION_STACK_TRACE - help - In the event of a stack trace, this place a limit on the depths - of the stack to examine. - config EXCEPTION_STACK_TRACE_SYMTAB bool "Print function names in the stack trace" select SYMTAB diff --git a/tests/arch/common/stack_unwind/testcase.yaml b/tests/arch/common/stack_unwind/testcase.yaml index 123e9be405c..4a7d4994cb2 100644 --- a/tests/arch/common/stack_unwind/testcase.yaml +++ b/tests/arch/common/stack_unwind/testcase.yaml @@ -54,8 +54,9 @@ tests: harness_config: type: multi_line regex: - - "E: backtrace 0: fp: \\w+ lr: \\w+" - - "E: backtrace 1: fp: \\w+ lr: \\w+" + - "E: call trace:" + - "E: 0: fp: \\w+ lr: \\w+" + - "E: 1: fp: \\w+ lr: \\w+" arch.common.stack_unwind.symtab: arch_allow: - riscv