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 <ycsin@meta.com>
Signed-off-by: Yong Cong Sin <yongcong.sin@gmail.com>
This commit is contained in:
Yong Cong Sin 2024-08-14 17:56:26 +08:00 committed by Anas Nashif
parent 06a8c35316
commit ab676fdb86
4 changed files with 66 additions and 31 deletions

View File

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

View File

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

View File

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

View File

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