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:
parent
06a8c35316
commit
ab676fdb86
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue