1 /* libunwind - a platform-independent unwind library
2 Copyright (C) 2010, 2011 by FERMI NATIONAL ACCELERATOR LABORATORY
3
4 Permission is hereby granted, free of charge, to any person obtaining
5 a copy of this software and associated documentation files (the
6 "Software"), to deal in the Software without restriction, including
7 without limitation the rights to use, copy, modify, merge, publish,
8 distribute, sublicense, and/or sell copies of the Software, and to
9 permit persons to whom the Software is furnished to do so, subject to
10 the following conditions:
11
12 The above copyright notice and this permission notice shall be
13 included in all copies or substantial portions of the Software.
14
15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19 LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
22
23 #ifdef HAVE_CONFIG_H
24 # include "config.h"
25 #endif
26
27 #include "compiler.h"
28
29 #include <errno.h>
30 #if HAVE_EXECINFO_H
31 # include <execinfo.h>
32 #else
33 extern int backtrace (void **, int);
34 #endif
35 #include <signal.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <unistd.h>
40 #include <libunwind.h>
41
42 #define panic(args...) \
43 { fprintf (stderr, args); exit (-1); }
44
45 #define SIG_STACK_SIZE 0x100000
46
47 int verbose;
48 int num_errors;
49
50 /* These variables are global because they
51 * cause the signal stack to overflow */
52 char buf[512], name[256];
53 void *addresses[3][128];
54 unw_cursor_t cursor;
55 unw_context_t uc;
56
57 static void
do_backtrace(void)58 do_backtrace (void)
59 {
60 unw_word_t ip;
61 int ret = -UNW_ENOINFO;
62 int depth = 0;
63 int i, n, m;
64
65 if (verbose)
66 printf ("\tnormal trace:\n");
67
68 unw_getcontext (&uc);
69 if (unw_init_local (&cursor, &uc) < 0)
70 panic ("unw_init_local failed!\n");
71
72 do
73 {
74 unw_get_reg (&cursor, UNW_REG_IP, &ip);
75 addresses[0][depth] = (void *) ip;
76 }
77 while ((ret = unw_step (&cursor)) > 0 && ++depth < 128);
78
79 if (ret < 0)
80 {
81 unw_get_reg (&cursor, UNW_REG_IP, &ip);
82 printf ("FAILURE: unw_step() returned %d for ip=%lx\n", ret, (long) ip);
83 ++num_errors;
84 }
85
86 if (verbose)
87 for (i = 0; i < depth; ++i)
88 printf ("\t #%-3d ip=%p\n", i, addresses[0][i]);
89
90 if (verbose)
91 printf ("\n\tvia backtrace():\n");
92
93 n = backtrace (addresses[1], 128);
94
95 if (verbose)
96 for (i = 0; i < n; ++i)
97 printf ("\t #%-3d ip=%p\n", i, addresses[1][i]);
98
99 if (verbose)
100 printf ("\n\tvia unw_backtrace():\n");
101
102 m = unw_backtrace (addresses[2], 128);
103
104 if (verbose)
105 for (i = 0; i < m; ++i)
106 printf ("\t #%-3d ip=%p\n", i, addresses[2][i]);
107
108 if (m != depth+1)
109 {
110 printf ("FAILURE: unw_step() loop and unw_backtrace() depths differ: %d vs. %d\n", depth, m);
111 ++num_errors;
112 }
113
114 if (n != depth+1)
115 {
116 printf ("FAILURE: unw_step() loop and backtrace() depths differ: %d vs. %d\n", depth, n);
117 ++num_errors;
118 }
119
120 if (n == m)
121 for (i = 1; i < n; ++i)
122 /* Allow one in difference in comparison, trace returns adjusted addresses. */
123 if (labs((unw_word_t) addresses[1][i] - (unw_word_t) addresses[2][i]) > 1)
124 {
125 printf ("FAILURE: backtrace() and unw_backtrace() addresses differ at %d: %p vs. %p\n",
126 i, addresses[1][n], addresses[2][n]);
127 ++num_errors;
128 }
129
130 if (n == depth+1)
131 for (i = 1; i < depth; ++i)
132 /* Allow one in difference in comparison, trace returns adjusted addresses. */
133 if (labs((unw_word_t) addresses[0][i] - (unw_word_t) addresses[1][i]) > 1)
134 {
135 printf ("FAILURE: unw_step() loop and backtrace() addresses differ at %d: %p vs. %p\n",
136 i, addresses[0][n], addresses[1][n]);
137 ++num_errors;
138 }
139 }
140
141 void
foo(long val UNUSED)142 foo (long val UNUSED)
143 {
144 do_backtrace ();
145 }
146
147 void
bar(long v)148 bar (long v)
149 {
150 extern long f (long);
151 int arr[v];
152
153 /* This is a vain attempt to use up lots of registers to force
154 the frame-chain info to be saved on the memory stack on ia64.
155 It happens to work with gcc v3.3.4 and gcc v3.4.1 but perhaps
156 not with any other compiler. */
157 foo (f (arr[0]) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v)
158 + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v)
159 + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v)
160 + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v)
161 + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v)
162 + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v)
163 + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v)
164 + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v)
165 + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v)
166 + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v)
167 + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v)
168 + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v)
169 + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v)
170 + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v)
171 + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v)
172 + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v)
173 + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + f (v))
174 ))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))
175 )))))))))))))))))))))))))))))))))))))))))))))))))))))));
176 }
177
178 void
sighandler(int signal,void * siginfo UNUSED,void * context)179 sighandler (int signal, void *siginfo UNUSED, void *context)
180 {
181 ucontext_t *uc UNUSED;
182 int sp;
183
184 uc = context;
185
186 if (verbose)
187 {
188 printf ("sighandler: got signal %d, sp=%p", signal, &sp);
189 #if UNW_TARGET_IA64
190 # if defined(__linux__)
191 printf (" @ %lx", uc->uc_mcontext.sc_ip);
192 # else
193 {
194 uint16_t reason;
195 uint64_t ip;
196
197 __uc_get_reason (uc, &reason);
198 __uc_get_ip (uc, &ip);
199 printf (" @ %lx (reason=%d)", ip, reason);
200 }
201 # endif
202 #elif UNW_TARGET_X86
203 #if defined __linux__
204 printf (" @ %lx", (unsigned long) uc->uc_mcontext.gregs[REG_EIP]);
205 #elif defined __FreeBSD__
206 printf (" @ %lx", (unsigned long) uc->uc_mcontext.mc_eip);
207 #endif
208 #elif UNW_TARGET_X86_64
209 #if defined __linux__
210 printf (" @ %lx", (unsigned long) uc->uc_mcontext.gregs[REG_RIP]);
211 #elif defined __FreeBSD__
212 printf (" @ %lx", (unsigned long) uc->uc_mcontext.mc_rip);
213 #endif
214 #elif defined UNW_TARGET_ARM
215 printf (" @ %lx", (unsigned long) uc->uc_mcontext.arm_pc);
216 #endif
217 printf ("\n");
218 }
219 do_backtrace();
220 }
221
222 int
main(int argc,char ** argv UNUSED)223 main (int argc, char **argv UNUSED)
224 {
225 struct sigaction act;
226 stack_t stk;
227
228 verbose = (argc > 1);
229
230 if (verbose)
231 printf ("Normal backtrace:\n");
232
233 bar (1);
234
235 memset (&act, 0, sizeof (act));
236 act.sa_handler = (void (*)(int)) sighandler;
237 act.sa_flags = SA_SIGINFO;
238 if (sigaction (SIGTERM, &act, NULL) < 0)
239 panic ("sigaction: %s\n", strerror (errno));
240
241 if (verbose)
242 printf ("\nBacktrace across signal handler:\n");
243 kill (getpid (), SIGTERM);
244
245 if (verbose)
246 printf ("\nBacktrace across signal handler on alternate stack:\n");
247 stk.ss_sp = malloc (SIG_STACK_SIZE);
248 if (!stk.ss_sp)
249 panic ("failed to allocate %u bytes\n", SIG_STACK_SIZE);
250 stk.ss_size = SIG_STACK_SIZE;
251 stk.ss_flags = 0;
252 if (sigaltstack (&stk, NULL) < 0)
253 panic ("sigaltstack: %s\n", strerror (errno));
254
255 memset (&act, 0, sizeof (act));
256 act.sa_handler = (void (*)(int)) sighandler;
257 act.sa_flags = SA_ONSTACK | SA_SIGINFO;
258 if (sigaction (SIGTERM, &act, NULL) < 0)
259 panic ("sigaction: %s\n", strerror (errno));
260 kill (getpid (), SIGTERM);
261
262 if (num_errors > 0)
263 {
264 fprintf (stderr, "FAILURE: detected %d errors\n", num_errors);
265 exit (-1);
266 }
267
268 if (verbose)
269 printf ("SUCCESS.\n");
270
271 signal (SIGTERM, SIG_DFL);
272 stk.ss_flags = SS_DISABLE;
273 sigaltstack (&stk, NULL);
274 free (stk.ss_sp);
275
276 return 0;
277 }
278