| // SPDX-License-Identifier: GPL-2.0-only |
| /* |
| * Backtrace support. |
| */ |
| #include <libcflat.h> |
| #include <stdbool.h> |
| #include <stack.h> |
| |
| extern char vector_stub_start, vector_stub_end; |
| |
| int arch_backtrace_frame(const void *frame, const void **return_addrs, |
| int max_depth, bool current_frame) |
| { |
| const void *fp = frame; |
| static bool walking; |
| void *lr; |
| int depth; |
| bool is_exception = false; |
| unsigned long addr; |
| |
| if (current_frame) |
| fp = __builtin_frame_address(0); |
| |
| if (walking) { |
| printf("RECURSIVE STACK WALK!!!\n"); |
| return 0; |
| } |
| walking = true; |
| |
| /* |
| * ARM64 stack grows down. fp points to the previous fp on the stack, |
| * and lr is just above it |
| */ |
| for (depth = 0; fp && depth < max_depth; ++depth) { |
| |
| asm volatile ("ldp %0, %1, [%2]" |
| : "=r" (fp), "=r" (lr) |
| : "r" (fp) |
| : ); |
| |
| return_addrs[depth] = lr; |
| |
| /* |
| * If this is an exception, add 1 to the pointer so when the |
| * pretty_print_stacks script is run it would get the right |
| * address (it deducts 1 to find the call address, but we want |
| * the actual address). |
| */ |
| if (is_exception) |
| return_addrs[depth] += 1; |
| |
| /* Check if we are in the exception handlers for the next entry */ |
| addr = (unsigned long)lr; |
| is_exception = (addr >= (unsigned long)&vector_stub_start && |
| addr < (unsigned long)&vector_stub_end); |
| } |
| |
| walking = false; |
| return depth; |
| } |