blob: 1e966b21aa2137ad4488d9045b034f7076d0d158 [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
47int verbose;
48int num_errors;
49
50/* These variables are global because they
51 * cause the signal stack to overflow */
52char buf[512], name[256];
Lassi Tuura5f38f352011-03-31 23:47:20 -070053void *addresses[3][128];
Lassi Tuura9e98f152011-03-19 10:00:48 +010054unw_cursor_t cursor;
55ucontext_t uc;
Lassi Tuura9e98f152011-03-19 10:00:48 +010056
57static void
58do_backtrace (void)
59{
60 unw_word_t ip;
61 int ret = -UNW_ENOINFO;
Lassi Tuura5f38f352011-03-31 23:47:20 -070062 int depth = 0;
63 int i, n, m;
Lassi Tuura9e98f152011-03-19 10:00:48 +010064
65 if (verbose)
Lassi Tuura5f38f352011-03-31 23:47:20 -070066 printf ("\tnormal trace:\n");
Lassi Tuura9e98f152011-03-19 10:00:48 +010067
68 unw_getcontext (&uc);
69 if (unw_init_local (&cursor, &uc) < 0)
70 panic ("unw_init_local failed!\n");
71
Lassi Tuura5f38f352011-03-31 23:47:20 -070072 do
Lassi Tuura9e98f152011-03-19 10:00:48 +010073 {
74 unw_get_reg (&cursor, UNW_REG_IP, &ip);
Lassi Tuura5f38f352011-03-31 23:47:20 -070075 addresses[0][depth] = (void *) ip;
Lassi Tuura9e98f152011-03-19 10:00:48 +010076 }
Lassi Tuura5f38f352011-03-31 23:47:20 -070077 while ((ret = unw_step (&cursor)) > 0 && ++depth < 128);
Lassi Tuura9e98f152011-03-19 10:00:48 +010078
79 if (ret < 0)
80 {
Lassi Tuura5f38f352011-03-31 23:47:20 -070081 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;
Lassi Tuura9e98f152011-03-19 10:00:48 +010084 }
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
Lassi Tuura5f38f352011-03-31 23:47:20 -070099 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)
Lassi Tuura9e98f152011-03-19 10:00:48 +0100109 {
Lassi Tuura5f38f352011-03-31 23:47:20 -0700110 printf ("FAILURE: unw_step() loop and unw_backtrace() depths differ: %d vs. %d\n", depth, m);
Lassi Tuura9e98f152011-03-19 10:00:48 +0100111 ++num_errors;
112 }
Lassi Tuura5f38f352011-03-31 23:47:20 -0700113
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)
Lassi Tuura9e98f152011-03-19 10:00:48 +0100131 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 {
Lassi Tuura5f38f352011-03-31 23:47:20 -0700135 printf ("FAILURE: unw_step() loop and backtrace() addresses differ at %d: %p vs. %p\n",
Lassi Tuura9e98f152011-03-19 10:00:48 +0100136 i, addresses[0][n], addresses[1][n]);
137 ++num_errors;
138 }
139}
140
141void
142foo (long val)
143{
144 do_backtrace ();
145}
146
147void
148bar (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
178void
179sighandler (int signal, void *siginfo, void *context)
180{
181 ucontext_t *uc = context;
182 int sp;
183
184 if (verbose)
185 {
186 printf ("sighandler: got signal %d, sp=%p", signal, &sp);
187#if UNW_TARGET_IA64
188# if defined(__linux__)
189 printf (" @ %lx", uc->uc_mcontext.sc_ip);
190# else
191 {
192 uint16_t reason;
193 uint64_t ip;
194
195 __uc_get_reason (uc, &reason);
196 __uc_get_ip (uc, &ip);
197 printf (" @ %lx (reason=%d)", ip, reason);
198 }
199# endif
200#elif UNW_TARGET_X86
201#if defined __linux__
202 printf (" @ %lx", (unsigned long) uc->uc_mcontext.gregs[REG_EIP]);
203#elif defined __FreeBSD__
204 printf (" @ %lx", (unsigned long) uc->uc_mcontext.mc_eip);
205#endif
206#elif UNW_TARGET_X86_64
207#if defined __linux__
208 printf (" @ %lx", (unsigned long) uc->uc_mcontext.gregs[REG_RIP]);
209#elif defined __FreeBSD__
210 printf (" @ %lx", (unsigned long) uc->uc_mcontext.mc_rip);
211#endif
212#endif
213 printf ("\n");
214 }
215 do_backtrace();
216}
217
218int
219main (int argc, char **argv)
220{
221 struct sigaction act;
222 stack_t stk;
223
Lassi Tuura9e98f152011-03-19 10:00:48 +0100224 verbose = (argc > 1);
225
226 if (verbose)
227 printf ("Normal backtrace:\n");
228
229 bar (1);
230
231 memset (&act, 0, sizeof (act));
232 act.sa_handler = (void (*)(int)) sighandler;
233 act.sa_flags = SA_SIGINFO;
234 if (sigaction (SIGTERM, &act, NULL) < 0)
235 panic ("sigaction: %s\n", strerror (errno));
236
237 if (verbose)
238 printf ("\nBacktrace across signal handler:\n");
239 kill (getpid (), SIGTERM);
240
241 if (verbose)
242 printf ("\nBacktrace across signal handler on alternate stack:\n");
243 stk.ss_sp = malloc (SIGSTKSZ);
244 if (!stk.ss_sp)
245 panic ("failed to allocate SIGSTKSZ (%u) bytes\n", SIGSTKSZ);
246 stk.ss_size = SIGSTKSZ;
247 stk.ss_flags = 0;
248 if (sigaltstack (&stk, NULL) < 0)
249 panic ("sigaltstack: %s\n", strerror (errno));
250
251 memset (&act, 0, sizeof (act));
252 act.sa_handler = (void (*)(int)) sighandler;
253 act.sa_flags = SA_ONSTACK | SA_SIGINFO;
254 if (sigaction (SIGTERM, &act, NULL) < 0)
255 panic ("sigaction: %s\n", strerror (errno));
256 kill (getpid (), SIGTERM);
257
258 if (num_errors > 0)
259 {
260 fprintf (stderr, "FAILURE: detected %d errors\n", num_errors);
261 exit (-1);
262 }
263
Lassi Tuura9e98f152011-03-19 10:00:48 +0100264 if (verbose)
265 printf ("SUCCESS.\n");
266 return 0;
267}