1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Backtrace support. 4 */ 5 #include <libcflat.h> 6 #include <stdbool.h> 7 #include <stack.h> 8 9 extern char vector_stub_start, vector_stub_end; 10 11 int backtrace_frame(const void *frame, const void **return_addrs, int max_depth) 12 { 13 const void *fp = frame; 14 static bool walking; 15 void *lr; 16 int depth; 17 bool is_exception = false; 18 unsigned long addr; 19 20 if (walking) { 21 printf("RECURSIVE STACK WALK!!!\n"); 22 return 0; 23 } 24 walking = true; 25 26 /* 27 * ARM64 stack grows down. fp points to the previous fp on the stack, 28 * and lr is just above it 29 */ 30 for (depth = 0; fp && depth < max_depth; ++depth) { 31 32 asm volatile ("ldp %0, %1, [%2]" 33 : "=r" (fp), "=r" (lr) 34 : "r" (fp) 35 : ); 36 37 return_addrs[depth] = lr; 38 39 /* 40 * If this is an exception, add 1 to the pointer so when the 41 * pretty_print_stacks script is run it would get the right 42 * address (it deducts 1 to find the call address, but we want 43 * the actual address). 44 */ 45 if (is_exception) 46 return_addrs[depth] += 1; 47 48 /* Check if we are in the exception handlers for the next entry */ 49 addr = (unsigned long)lr; 50 is_exception = (addr >= (unsigned long)&vector_stub_start && 51 addr < (unsigned long)&vector_stub_end); 52 } 53 54 walking = false; 55 return depth; 56 } 57 58 int backtrace(const void **return_addrs, int max_depth) 59 { 60 return backtrace_frame(__builtin_frame_address(0), 61 return_addrs, max_depth); 62 } 63