blob: 8565436c5d8e9ecbc57c6ae9d223337e4e021ca4 [file] [log] [blame]
Lassi Tuura9e98f152011-03-19 10:00:48 +01001/* libunwind - a platform-independent unwind library
2 Copyright (C) 2010 by Lassi Tuura <lat@iki.fi>
3
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 }
89 while ((ret = unw_step (&cursor)) >= 0 && ++i < 128);
90
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 }
97 }
98
99 if (verbose)
100 for (i = 0; i < depth; ++i)
101 printf ("\t #%-3d ip=%p\n", i, addresses[0][i]);
102
103 if (verbose)
104 printf ("\n\tvia backtrace():\n");
105
106 n = backtrace (addresses[1], 128);
107
108 if (verbose)
109 for (i = 0; i < n; ++i)
110 printf ("\t #%-3d ip=%p\n", i, addresses[1][i]);
111
112 if (n != depth)
113 {
114 printf ("FAILURE: unw_tdep_trace() and backtrace() depths differ: %d vs. %d\n", depth, n);
115 ++num_errors;
116 }
117 else
118 for (i = 1; i < depth; ++i)
119 /* Allow one in difference in comparison, trace returns adjusted addresses. */
120 if (labs((unw_word_t) addresses[0][i] - (unw_word_t) addresses[1][i]) > 1)
121 {
122 printf ("FAILURE: unw_tdep_trace() and backtrace() addresses differ at %d: %p vs. %p\n",
123 i, addresses[0][n], addresses[1][n]);
124 ++num_errors;
125 }
126}
127
128void
129foo (long val)
130{
131 do_backtrace ();
132}
133
134void
135bar (long v)
136{
137 extern long f (long);
138 int arr[v];
139
140 /* This is a vain attempt to use up lots of registers to force
141 the frame-chain info to be saved on the memory stack on ia64.
142 It happens to work with gcc v3.3.4 and gcc v3.4.1 but perhaps
143 not with any other compiler. */
144 foo (f (arr[0]) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v)
145 + (f (v) + (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 ))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))
162 )))))))))))))))))))))))))))))))))))))))))))))))))))))));
163}
164
165void
166sighandler (int signal, void *siginfo, void *context)
167{
168 ucontext_t *uc = context;
169 int sp;
170
171 if (verbose)
172 {
173 printf ("sighandler: got signal %d, sp=%p", signal, &sp);
174#if UNW_TARGET_IA64
175# if defined(__linux__)
176 printf (" @ %lx", uc->uc_mcontext.sc_ip);
177# else
178 {
179 uint16_t reason;
180 uint64_t ip;
181
182 __uc_get_reason (uc, &reason);
183 __uc_get_ip (uc, &ip);
184 printf (" @ %lx (reason=%d)", ip, reason);
185 }
186# endif
187#elif UNW_TARGET_X86
188#if defined __linux__
189 printf (" @ %lx", (unsigned long) uc->uc_mcontext.gregs[REG_EIP]);
190#elif defined __FreeBSD__
191 printf (" @ %lx", (unsigned long) uc->uc_mcontext.mc_eip);
192#endif
193#elif UNW_TARGET_X86_64
194#if defined __linux__
195 printf (" @ %lx", (unsigned long) uc->uc_mcontext.gregs[REG_RIP]);
196#elif defined __FreeBSD__
197 printf (" @ %lx", (unsigned long) uc->uc_mcontext.mc_rip);
198#endif
199#endif
200 printf ("\n");
201 }
202 do_backtrace();
203}
204
205int
206main (int argc, char **argv)
207{
208 struct sigaction act;
209 stack_t stk;
210
Lassi Tuura9e98f152011-03-19 10:00:48 +0100211 verbose = (argc > 1);
212
213 if (verbose)
214 printf ("Normal backtrace:\n");
215
216 bar (1);
217
218 memset (&act, 0, sizeof (act));
219 act.sa_handler = (void (*)(int)) sighandler;
220 act.sa_flags = SA_SIGINFO;
221 if (sigaction (SIGTERM, &act, NULL) < 0)
222 panic ("sigaction: %s\n", strerror (errno));
223
224 if (verbose)
225 printf ("\nBacktrace across signal handler:\n");
226 kill (getpid (), SIGTERM);
227
228 if (verbose)
229 printf ("\nBacktrace across signal handler on alternate stack:\n");
230 stk.ss_sp = malloc (SIGSTKSZ);
231 if (!stk.ss_sp)
232 panic ("failed to allocate SIGSTKSZ (%u) bytes\n", SIGSTKSZ);
233 stk.ss_size = SIGSTKSZ;
234 stk.ss_flags = 0;
235 if (sigaltstack (&stk, NULL) < 0)
236 panic ("sigaltstack: %s\n", strerror (errno));
237
238 memset (&act, 0, sizeof (act));
239 act.sa_handler = (void (*)(int)) sighandler;
240 act.sa_flags = SA_ONSTACK | SA_SIGINFO;
241 if (sigaction (SIGTERM, &act, NULL) < 0)
242 panic ("sigaction: %s\n", strerror (errno));
243 kill (getpid (), SIGTERM);
244
245 if (num_errors > 0)
246 {
247 fprintf (stderr, "FAILURE: detected %d errors\n", num_errors);
248 exit (-1);
249 }
250
Lassi Tuura9e98f152011-03-19 10:00:48 +0100251 if (verbose)
252 printf ("SUCCESS.\n");
253 return 0;
254}