Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions arch/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ config ARM64
select ARCH_SUPPORTS_COREDUMP
select HAS_ARM_SMCCC
select ARCH_HAS_THREAD_LOCAL_STORAGE
select ARCH_HAS_STACKWALK
select USE_SWITCH
select USE_SWITCH_SUPPORTED
select IRQ_OFFLOAD_NESTED if IRQ_OFFLOAD
Expand Down Expand Up @@ -89,6 +90,7 @@ config X86
select ARCH_HAS_TIMING_FUNCTIONS
select ARCH_HAS_THREAD_LOCAL_STORAGE
select ARCH_HAS_DEMAND_PAGING if !X86_64
select ARCH_HAS_STACKWALK
select IRQ_OFFLOAD_NESTED if IRQ_OFFLOAD
select NEED_LIBC_MEM_PARTITION if USERSPACE && TIMING_FUNCTIONS \
&& !BOARD_HAS_TIMING_FUNCTIONS \
Expand Down
68 changes: 53 additions & 15 deletions arch/arm64/core/fatal.c
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,23 @@ static void esf_dump(const struct arch_esf *esf)
}

#ifdef CONFIG_EXCEPTION_STACK_TRACE
static void esf_unwind(const struct arch_esf *esf)
static bool print_trace_address(void *arg, unsigned long lr)
{
int *i = arg;
#ifdef CONFIG_SYMTAB
uint32_t offset = 0;
const char *name = symtab_find_symbol_name(lr, &offset);

LOG_ERR("backtrace %2d: lr: 0x%016lx [%s+0x%x]", (*i)++, lr, name, offset);
#else
LOG_ERR("backtrace %2d: lr: 0x%016lx", (*i)++, lr);
#endif /* CONFIG_SYMTAB */

return true;
}

static void walk_stackframe(stack_trace_callback_fn cb, void *cookie, const struct arch_esf *esf,
int max_frames)
{
/*
* For GCC:
Expand All @@ -218,31 +234,53 @@ 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)) {
break;
}
fp = (uint64_t *) fp[0];
}
}

static void esf_unwind(const struct arch_esf *esf)
{
int i = 0;

LOG_ERR("");
walk_stackframe(print_trace_address, &i, esf, CONFIG_EXCEPTION_STACK_TRACE_MAX_FRAMES);
LOG_ERR("");
}
#endif

#endif /* CONFIG_EXCEPTION_DEBUG */

void arch_stack_walk(stack_trace_callback_fn callback_fn, void *cookie,
const struct k_thread *thread, const struct arch_esf *esf)
{
#ifdef CONFIG_EXCEPTION_STACK_TRACE
ARG_UNUSED(thread);

walk_stackframe(callback_fn, cookie, esf, CONFIG_ARCH_STACKWALK_MAX_FRAMES);
#else
ARG_UNUSED(callback_fn);
ARG_UNUSED(cookie);
ARG_UNUSED(thread);
ARG_UNUSED(esf);

LOG_DBG("Enable CONFIG_EXCEPTION_STACK_TRACE for %s()", __func__);
#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)
{
Expand Down
70 changes: 59 additions & 11 deletions arch/x86/core/fatal.c
Original file line number Diff line number Diff line change
Expand Up @@ -140,20 +140,44 @@ struct stack_frame {
#endif
};

#define MAX_STACK_FRAMES CONFIG_EXCEPTION_STACK_TRACE_MAX_FRAMES
static bool print_trace_address(void *arg, unsigned long addr)
{
ARG_UNUSED(arg);

__pinned_func
static void unwind_stack(uintptr_t base_ptr, uint16_t cs)
#ifdef CONFIG_X86_64
LOG_ERR(" 0x%016lx", addr);
#else
LOG_ERR(" 0x%08lx", addr);
#endif

return true;
}

__pinned_func static void walk_stackframe(stack_trace_callback_fn cb, void *cookie,
const struct arch_esf *esf, int max_frames)
{
uintptr_t base_ptr;
uint16_t cs;
struct stack_frame *frame;
int i;

if (esf != NULL) {
#ifdef CONFIG_X86_64
base_ptr = esf->rbp;
#else /* x86 32-bit */
base_ptr = esf->ebp;
#endif /* CONFIG_X86_64 */
cs = esf->cs;
} else {
return;
}

if (base_ptr == 0U) {
LOG_ERR("NULL base ptr");
return;
}

for (i = 0; i < MAX_STACK_FRAMES; i++) {
for (i = 0; i < max_frames; i++) {
if (base_ptr % sizeof(base_ptr) != 0U) {
LOG_ERR("unaligned frame ptr");
return;
Expand All @@ -178,16 +202,40 @@ static void unwind_stack(uintptr_t base_ptr, uint16_t cs)
if (frame->ret_addr == 0U) {
break;
}
#ifdef CONFIG_X86_64
LOG_ERR(" 0x%016lx", frame->ret_addr);
#else
LOG_ERR(" 0x%08lx (0x%lx)", frame->ret_addr, frame->args);
#endif

if (!cb(cookie, frame->ret_addr)) {
break;
}

base_ptr = frame->next;
}
}

__pinned_func
static void unwind_stack(const struct arch_esf *esf)
{
walk_stackframe(print_trace_address, NULL, esf,
CONFIG_EXCEPTION_STACK_TRACE_MAX_FRAMES);
}
#endif /* CONFIG_EXCEPTION_STACK_TRACE */

void arch_stack_walk(stack_trace_callback_fn callback_fn, void *cookie,
const struct k_thread *thread, const struct arch_esf *esf)
{
#ifdef CONFIG_EXCEPTION_STACK_TRACE
ARG_UNUSED(thread);

walk_stackframe(callback_fn, cookie, esf, CONFIG_ARCH_STACKWALK_MAX_FRAMES);
#else
ARG_UNUSED(callback_fn);
ARG_UNUSED(cookie);
ARG_UNUSED(thread);
ARG_UNUSED(esf);

LOG_DBG("Enable CONFIG_EXCEPTION_STACK_TRACE for %s()", __func__);
#endif /* CONFIG_EXCEPTION_STACK_TRACE */
}

static inline uintptr_t get_cr3(const struct arch_esf *esf)
{
#if defined(CONFIG_USERSPACE) && defined(CONFIG_X86_KPTI)
Expand Down Expand Up @@ -231,7 +279,7 @@ static void dump_regs(const struct arch_esf *esf)
#endif
LOG_ERR("RIP: 0x%016lx", esf->rip);
#ifdef CONFIG_EXCEPTION_STACK_TRACE
unwind_stack(esf->rbp, esf->cs);
unwind_stack(esf);
#endif
}
#else /* 32-bit */
Expand All @@ -250,7 +298,7 @@ static void dump_regs(const struct arch_esf *esf)
#endif
LOG_ERR("EIP: 0x%08x", esf->eip);
#ifdef CONFIG_EXCEPTION_STACK_TRACE
unwind_stack(esf->ebp, esf->cs);
unwind_stack(esf);
#endif
}
#endif /* CONFIG_X86_64 */
Expand Down
4 changes: 2 additions & 2 deletions tests/arch/common/stack_unwind/testcase.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,8 @@ tests:
harness_config:
type: multi_line
regex:
- "E: backtrace 0: fp: \\w+ lr: \\w+"
- "E: backtrace 1: fp: \\w+ lr: \\w+"
- "E: backtrace 0: lr: \\w+"
- "E: backtrace 1: lr: \\w+"
arch.common.stack_unwind.symtab:
arch_allow:
- riscv
Expand Down