blob: 47a7d5785383126a2d36efb5065b7e716a87695d [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];
53void *addresses[2][128];
54unw_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;
62 int depth = 128;
63 int i, n;
64
65 if (verbose)
66 printf ("\tfast backtrace:\n");
67
68 unw_getcontext (&uc);
69 if (unw_init_local (&cursor, &uc) < 0)
70 panic ("unw_init_local failed!\n");
71
72#if UNW_TARGET_X86_64
Arun Sharma7ff83c02011-03-24 23:25:43 -070073 if ((ret = unw_tdep_trace (&cursor, addresses[0], &depth)) < 0)
Lassi Tuura9e98f152011-03-19 10:00:48 +010074 {
75 unw_get_reg (&cursor, UNW_REG_IP, &ip);
76 printf ("FAILURE: unw_tdep_trace() returned %d for ip=%lx\n", ret, (long) ip);
77 ++num_errors;
78 }
79#endif
80
81 if (ret < 0)
82 {
83 i = 0;
84 do
85 {
86 unw_get_reg (&cursor, UNW_REG_IP, &ip);
87 addresses[0][i] = (void *) ip;
88 }
Arun Sharma27d0dbf2011-03-25 14:34:41 -070089 while ((ret = unw_step (&cursor)) > 0 && ++i < 128);
Lassi Tuura9e98f152011-03-19 10:00:48 +010090
91 if (ret < 0)
92 {
93 unw_get_reg (&cursor, UNW_REG_IP, &ip);
94 printf ("FAILURE: unw_step() returned %d for ip=%lx\n", ret, (long) ip);
95 ++num_errors;
96 }
Arun Sharma27d0dbf2011-03-25 14:34:41 -070097 depth = i;
Lassi Tuura9e98f152011-03-19 10:00:48 +010098 }
99
100 if (verbose)
101 for (i = 0; i < depth; ++i)
102 printf ("\t #%-3d ip=%p\n", i, addresses[0][i]);
103
104 if (verbose)
105 printf ("\n\tvia backtrace():\n");
106
107 n = backtrace (addresses[1], 128);
108
109 if (verbose)
110 for (i = 0; i < n; ++i)
111 printf ("\t #%-3d ip=%p\n", i, addresses[1][i]);
112
113 if (n != depth)
114 {
115 printf ("FAILURE: unw_tdep_trace() and backtrace() depths differ: %d vs. %d\n", depth, n);
116 ++num_errors;
117 }
118 else
119 for (i = 1; i < depth; ++i)
120 /* Allow one in difference in comparison, trace returns adjusted addresses. */
121 if (labs((unw_word_t) addresses[0][i] - (unw_word_t) addresses[1][i]) > 1)
122 {
123 printf ("FAILURE: unw_tdep_trace() and backtrace() addresses differ at %d: %p vs. %p\n",
124 i, addresses[0][n], addresses[1][n]);
125 ++num_errors;
126 }
127}
128
129void
130foo (long val)
131{
132 do_backtrace ();
133}
134
135void
136bar (long v)
137{
138 extern long f (long);
139 int arr[v];
140
141 /* This is a vain attempt to use up lots of registers to force
142 the frame-chain info to be saved on the memory stack on ia64.
143 It happens to work with gcc v3.3.4 and gcc v3.4.1 but perhaps
144 not with any other compiler. */
145 foo (f (arr[0]) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v)
146 + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v)
147 + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v)
148 + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v)
149 + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v)
150 + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v)
151 + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v)
152 + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v)
153 + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v)
154 + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v)
155 + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v)
156 + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v)
157 + (f (v) + (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 ))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))
163 )))))))))))))))))))))))))))))))))))))))))))))))))))))));
164}
165
166void
167sighandler (int signal, void *siginfo, void *context)
168{
169 ucontext_t *uc = context;
170 int sp;
171
172 if (verbose)
173 {
174 printf ("sighandler: got signal %d, sp=%p", signal, &sp);
175#if UNW_TARGET_IA64
176# if defined(__linux__)
177 printf (" @ %lx", uc->uc_mcontext.sc_ip);
178# else
179 {
180 uint16_t reason;
181 uint64_t ip;
182
183 __uc_get_reason (uc, &reason);
184 __uc_get_ip (uc, &ip);
185 printf (" @ %lx (reason=%d)", ip, reason);
186 }
187# endif
188#elif UNW_TARGET_X86
189#if defined __linux__
190 printf (" @ %lx", (unsigned long) uc->uc_mcontext.gregs[REG_EIP]);
191#elif defined __FreeBSD__
192 printf (" @ %lx", (unsigned long) uc->uc_mcontext.mc_eip);
193#endif
194#elif UNW_TARGET_X86_64
195#if defined __linux__
196 printf (" @ %lx", (unsigned long) uc->uc_mcontext.gregs[REG_RIP]);
197#elif defined __FreeBSD__
198 printf (" @ %lx", (unsigned long) uc->uc_mcontext.mc_rip);
199#endif
200#endif
201 printf ("\n");
202 }
203 do_backtrace();
204}
205
206int
207main (int argc, char **argv)
208{
209 struct sigaction act;
210 stack_t stk;
211
Lassi Tuura9e98f152011-03-19 10:00:48 +0100212 verbose = (argc > 1);
213
214 if (verbose)
215 printf ("Normal backtrace:\n");
216
217 bar (1);
218
219 memset (&act, 0, sizeof (act));
220 act.sa_handler = (void (*)(int)) sighandler;
221 act.sa_flags = SA_SIGINFO;
222 if (sigaction (SIGTERM, &act, NULL) < 0)
223 panic ("sigaction: %s\n", strerror (errno));
224
225 if (verbose)
226 printf ("\nBacktrace across signal handler:\n");
227 kill (getpid (), SIGTERM);
228
229 if (verbose)
230 printf ("\nBacktrace across signal handler on alternate stack:\n");
231 stk.ss_sp = malloc (SIGSTKSZ);
232 if (!stk.ss_sp)
233 panic ("failed to allocate SIGSTKSZ (%u) bytes\n", SIGSTKSZ);
234 stk.ss_size = SIGSTKSZ;
235 stk.ss_flags = 0;
236 if (sigaltstack (&stk, NULL) < 0)
237 panic ("sigaltstack: %s\n", strerror (errno));
238
239 memset (&act, 0, sizeof (act));
240 act.sa_handler = (void (*)(int)) sighandler;
241 act.sa_flags = SA_ONSTACK | SA_SIGINFO;
242 if (sigaction (SIGTERM, &act, NULL) < 0)
243 panic ("sigaction: %s\n", strerror (errno));
244 kill (getpid (), SIGTERM);
245
246 if (num_errors > 0)
247 {
248 fprintf (stderr, "FAILURE: detected %d errors\n", num_errors);
249 exit (-1);
250 }
251
Lassi Tuura9e98f152011-03-19 10:00:48 +0100252 if (verbose)
253 printf ("SUCCESS.\n");
254 return 0;
255}