Commit ab676fdb authored by Yong Cong Sin's avatar Yong Cong Sin Committed by Anas Nashif
Browse files

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: default avatarYong Cong Sin <ycsin@meta.com>
Signed-off-by: default avatarYong Cong Sin <yongcong.sin@gmail.com>
parent 06a8c353
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -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
+53 −18
Original line number Diff line number Diff line
@@ -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++) {
	if (esf != NULL) {
		fp = (uint64_t *) esf->fp;
	} else {
		return;
	}

	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("backtrace %2d: fp: 0x%016llx lr: 0x%016llx [%s+0x%x]",
			 count++, (uint64_t) fp, lr, name, offset);
	LOG_ERR("     %d: fp: 0x%016llx lr: 0x%016lx [%s+0x%x]", (*i)++, (uint64_t)fp, lr, name,
		offset);
#else
		LOG_ERR("backtrace %2d: fp: 0x%016llx lr: 0x%016llx",
			 count++, (uint64_t) fp, lr);
#endif
		fp = (uint64_t *) fp[0];
	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)
+1 −10
Original line number Diff line number Diff line
@@ -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
+3 −2
Original line number Diff line number Diff line
@@ -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