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 #if defined(CONFIG_RELOC) && !defined(HAVE_ARCH_BASE_ADDRESS)
15 extern char _text, _etext;
16
base_address(const void * rebased_addr,unsigned long * addr)17 bool 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 #elif !defined(CONFIG_RELOC) && !defined(HAVE_ARCH_BASE_ADDRESS)
base_address(const void * rebased_addr,unsigned long * addr)30 bool base_address(const void *rebased_addr, unsigned long *addr)
31 {
32 *addr = (unsigned long)rebased_addr;
33 return true;
34 }
35 #endif
36
print_stack(const void ** return_addrs,int depth,bool top_is_return_address)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 (base_address(return_addrs[0], &addr))
49 printf(" @%lx", addr);
50 i++;
51 }
52
53 for (; i < depth; i++) {
54 if (base_address(return_addrs[i], &addr))
55 printf(" %lx", addr);
56 }
57 printf("\n");
58 }
59
dump_stack(void)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
dump_frame_stack(const void * instruction,const void * frame)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
backtrace(const void ** return_addrs,int max_depth)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