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