1 /* 2 * stack related functions 3 * 4 * This code is free software; you can redistribute it and/or modify it 5 * under the terms of the GNU Library General Public License version 2. 6 */ 7 8 #include <libcflat.h> 9 #include <stdbool.h> 10 #include <stack.h> 11 12 #define MAX_DEPTH 20 13 14 #ifdef CONFIG_RELOC 15 extern char _text, _etext; 16 17 bool __attribute__((weak)) arch_base_address(const void *rebased_addr, unsigned long *addr) 18 { 19 unsigned long ra = (unsigned long)rebased_addr; 20 unsigned long start = (unsigned long)&_text; 21 unsigned long end = (unsigned long)&_etext; 22 23 if (ra < start || ra >= end) 24 return false; 25 26 *addr = ra - start; 27 return true; 28 } 29 #else 30 bool __attribute__((weak)) arch_base_address(const void *rebased_addr, unsigned long *addr) 31 { 32 *addr = (unsigned long)rebased_addr; 33 return true; 34 } 35 #endif 36 37 static void print_stack(const void **return_addrs, int depth, 38 bool top_is_return_address) 39 { 40 unsigned long addr; 41 int i = 0; 42 43 printf("\tSTACK:"); 44 45 /* @addr indicates a non-return address, as expected by the stack 46 * pretty printer script. */ 47 if (depth > 0 && !top_is_return_address) { 48 if (arch_base_address(return_addrs[0], &addr)) 49 printf(" @%lx", addr); 50 i++; 51 } 52 53 for (; i < depth; i++) { 54 if (arch_base_address(return_addrs[i], &addr)) 55 printf(" %lx", addr); 56 } 57 printf("\n"); 58 } 59 60 void dump_stack(void) 61 { 62 const void *return_addrs[MAX_DEPTH]; 63 int depth; 64 65 depth = backtrace(return_addrs, MAX_DEPTH); 66 print_stack(&return_addrs[1], depth ? depth - 1 : 0, true); 67 } 68 69 void dump_frame_stack(const void *instruction, const void *frame) 70 { 71 const void *return_addrs[MAX_DEPTH]; 72 int depth; 73 74 return_addrs[0] = instruction; 75 depth = backtrace_frame(frame, &return_addrs[1], MAX_DEPTH - 1); 76 print_stack(return_addrs, depth + 1, false); 77 } 78 79 #ifndef HAVE_ARCH_BACKTRACE 80 int backtrace(const void **return_addrs, int max_depth) 81 { 82 static int walking; 83 int depth = 0; 84 void *addr; 85 86 if (walking) { 87 printf("RECURSIVE STACK WALK!!!\n"); 88 return 0; 89 } 90 walking = 1; 91 92 /* __builtin_return_address requires a compile-time constant argument */ 93 #define GET_RETURN_ADDRESS(i) \ 94 if (max_depth == i) \ 95 goto done; \ 96 addr = __builtin_return_address(i); \ 97 if (!addr) \ 98 goto done; \ 99 return_addrs[i] = __builtin_extract_return_addr(addr); \ 100 depth = i + 1; \ 101 102 GET_RETURN_ADDRESS(0) 103 GET_RETURN_ADDRESS(1) 104 GET_RETURN_ADDRESS(2) 105 GET_RETURN_ADDRESS(3) 106 GET_RETURN_ADDRESS(4) 107 GET_RETURN_ADDRESS(5) 108 GET_RETURN_ADDRESS(6) 109 GET_RETURN_ADDRESS(7) 110 GET_RETURN_ADDRESS(8) 111 GET_RETURN_ADDRESS(9) 112 GET_RETURN_ADDRESS(10) 113 GET_RETURN_ADDRESS(11) 114 GET_RETURN_ADDRESS(12) 115 GET_RETURN_ADDRESS(13) 116 GET_RETURN_ADDRESS(14) 117 GET_RETURN_ADDRESS(15) 118 GET_RETURN_ADDRESS(16) 119 GET_RETURN_ADDRESS(17) 120 GET_RETURN_ADDRESS(18) 121 GET_RETURN_ADDRESS(19) 122 GET_RETURN_ADDRESS(20) 123 124 #undef GET_RETURN_ADDRESS 125 126 done: 127 walking = 0; 128 return depth; 129 } 130 #endif /* HAVE_ARCH_BACKTRACE */ 131