blob: b4c0bfcdd6ca45a5ad6422bcd46b08d4005068f5 [file] [log] [blame]
Lassi Tuura9e98f152011-03-19 10:00:48 +01001/* libunwind - a platform-independent unwind library
Lassi Tuura3b9fd992011-03-25 00:11:43 -07002 Copyright (C) 2010, 2011 by FERMI NATIONAL ACCELERATOR LABORATORY
Lassi Tuura9e98f152011-03-19 10:00:48 +01003
4Permission is hereby granted, free of charge, to any person obtaining
5a copy of this software and associated documentation files (the
6"Software"), to deal in the Software without restriction, including
7without limitation the rights to use, copy, modify, merge, publish,
8distribute, sublicense, and/or sell copies of the Software, and to
9permit persons to whom the Software is furnished to do so, subject to
10the following conditions:
11
12The above copyright notice and this permission notice shall be
13included in all copies or substantial portions of the Software.
14
15THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21WITH 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 <errno.h>
28#if HAVE_EXECINFO_H
29# include <execinfo.h>
30#else
31 extern int backtrace (void **, int);
32#endif
33#include <signal.h>
34#include <stdio.h>
35#include <stdlib.h>
36#include <string.h>
37#include <unistd.h>
38#include <libunwind.h>
39
40#define panic(args...) \
41 { fprintf (stderr, args); exit (-1); }
42
43#ifndef HAVE_SIGHANDLER_T
44typedef RETSIGTYPE (*sighandler_t) (int);
45#endif
46
Ken Wernere4593e22011-04-01 18:42:20 +020047#define SIG_STACK_SIZE 0x100000
48
Lassi Tuura9e98f152011-03-19 10:00:48 +010049int verbose;
50int num_errors;
51
52/* These variables are global because they
53 * cause the signal stack to overflow */
54char buf[512], name[256];
Lassi Tuura5f38f352011-03-31 23:47:20 -070055void *addresses[3][128];
Lassi Tuura9e98f152011-03-19 10:00:48 +010056unw_cursor_t cursor;
57ucontext_t uc;
Lassi Tuura9e98f152011-03-19 10:00:48 +010058
59static void
60do_backtrace (void)
61{
62 unw_word_t ip;
63 int ret = -UNW_ENOINFO;
Lassi Tuura5f38f352011-03-31 23:47:20 -070064 int depth = 0;
65 int i, n, m;
Lassi Tuura9e98f152011-03-19 10:00:48 +010066
67 if (verbose)
Lassi Tuura5f38f352011-03-31 23:47:20 -070068 printf ("\tnormal trace:\n");
Lassi Tuura9e98f152011-03-19 10:00:48 +010069
70 unw_getcontext (&uc);
71 if (unw_init_local (&cursor, &uc) < 0)
72 panic ("unw_init_local failed!\n");
73
Lassi Tuura5f38f352011-03-31 23:47:20 -070074 do
Lassi Tuura9e98f152011-03-19 10:00:48 +010075 {
76 unw_get_reg (&cursor, UNW_REG_IP, &ip);
Lassi Tuura5f38f352011-03-31 23:47:20 -070077 addresses[0][depth] = (void *) ip;
Lassi Tuura9e98f152011-03-19 10:00:48 +010078 }
Lassi Tuura5f38f352011-03-31 23:47:20 -070079 while ((ret = unw_step (&cursor)) > 0 && ++depth < 128);
Lassi Tuura9e98f152011-03-19 10:00:48 +010080
81 if (ret < 0)
82 {
Lassi Tuura5f38f352011-03-31 23:47:20 -070083 unw_get_reg (&cursor, UNW_REG_IP, &ip);
84 printf ("FAILURE: unw_step() returned %d for ip=%lx\n", ret, (long) ip);
85 ++num_errors;
Lassi Tuura9e98f152011-03-19 10:00:48 +010086 }
87
88 if (verbose)
89 for (i = 0; i < depth; ++i)
90 printf ("\t #%-3d ip=%p\n", i, addresses[0][i]);
91
92 if (verbose)
93 printf ("\n\tvia backtrace():\n");
94
95 n = backtrace (addresses[1], 128);
96
97 if (verbose)
98 for (i = 0; i < n; ++i)
99 printf ("\t #%-3d ip=%p\n", i, addresses[1][i]);
100
Lassi Tuura5f38f352011-03-31 23:47:20 -0700101 if (verbose)
102 printf ("\n\tvia unw_backtrace():\n");
103
104 m = unw_backtrace (addresses[2], 128);
105
106 if (verbose)
107 for (i = 0; i < m; ++i)
108 printf ("\t #%-3d ip=%p\n", i, addresses[2][i]);
109
110 if (m != depth+1)
Lassi Tuura9e98f152011-03-19 10:00:48 +0100111 {
Lassi Tuura5f38f352011-03-31 23:47:20 -0700112 printf ("FAILURE: unw_step() loop and unw_backtrace() depths differ: %d vs. %d\n", depth, m);
Lassi Tuura9e98f152011-03-19 10:00:48 +0100113 ++num_errors;
114 }
Lassi Tuura5f38f352011-03-31 23:47:20 -0700115
116 if (n != depth+1)
117 {
118 printf ("FAILURE: unw_step() loop and backtrace() depths differ: %d vs. %d\n", depth, n);
119 ++num_errors;
120 }
121
122 if (n == m)
123 for (i = 1; i < n; ++i)
124 /* Allow one in difference in comparison, trace returns adjusted addresses. */
125 if (labs((unw_word_t) addresses[1][i] - (unw_word_t) addresses[2][i]) > 1)
126 {
127 printf ("FAILURE: backtrace() and unw_backtrace() addresses differ at %d: %p vs. %p\n",
128 i, addresses[1][n], addresses[2][n]);
129 ++num_errors;
130 }
131
132 if (n == depth+1)
Lassi Tuura9e98f152011-03-19 10:00:48 +0100133 for (i = 1; i < depth; ++i)
134 /* Allow one in difference in comparison, trace returns adjusted addresses. */
135 if (labs((unw_word_t) addresses[0][i] - (unw_word_t) addresses[1][i]) > 1)
136 {
Lassi Tuura5f38f352011-03-31 23:47:20 -0700137 printf ("FAILURE: unw_step() loop and backtrace() addresses differ at %d: %p vs. %p\n",
Lassi Tuura9e98f152011-03-19 10:00:48 +0100138 i, addresses[0][n], addresses[1][n]);
139 ++num_errors;
140 }
141}
142
143void
144foo (long val)
145{
146 do_backtrace ();
147}
148
149void
150bar (long v)
151{
152 extern long f (long);
153 int arr[v];
154
155 /* This is a vain attempt to use up lots of registers to force
156 the frame-chain info to be saved on the memory stack on ia64.
157 It happens to work with gcc v3.3.4 and gcc v3.4.1 but perhaps
158 not with any other compiler. */
159 foo (f (arr[0]) + (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 + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v)
175 + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + f (v))
176 ))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))
177 )))))))))))))))))))))))))))))))))))))))))))))))))))))));
178}
179
180void
181sighandler (int signal, void *siginfo, void *context)
182{
183 ucontext_t *uc = context;
184 int sp;
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
Ken Wernera6248122011-04-06 10:36:49 +0200214#elif defined UNW_TARGET_ARM
215 printf (" @ %lx", (unsigned long) uc->uc_mcontext.arm_ip);
Lassi Tuura9e98f152011-03-19 10:00:48 +0100216#endif
217 printf ("\n");
218 }
219 do_backtrace();
220}
221
222int
223main (int argc, char **argv)
224{
225 struct sigaction act;
226 stack_t stk;
227
Lassi Tuura9e98f152011-03-19 10:00:48 +0100228 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");
Ken Wernere4593e22011-04-01 18:42:20 +0200247 stk.ss_sp = malloc (SIG_STACK_SIZE);
Lassi Tuura9e98f152011-03-19 10:00:48 +0100248 if (!stk.ss_sp)
Ken Wernere4593e22011-04-01 18:42:20 +0200249 panic ("failed to allocate %u bytes\n", SIG_STACK_SIZE);
250 stk.ss_size = SIG_STACK_SIZE;
Lassi Tuura9e98f152011-03-19 10:00:48 +0100251 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
Lassi Tuura9e98f152011-03-19 10:00:48 +0100268 if (verbose)
269 printf ("SUCCESS.\n");
270 return 0;
271}