xref: /kvm-unit-tests/lib/stack.c (revision ab0bbb9fd1eb426a8f43ac74eb762bc135568023)
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