• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* libunwind - a platform-independent unwind library
2    Copyright (C) 2010, 2011 by FERMI NATIONAL ACCELERATOR LABORATORY
3 
4 Permission is hereby granted, free of charge, to any person obtaining
5 a copy of this software and associated documentation files (the
6 "Software"), to deal in the Software without restriction, including
7 without limitation the rights to use, copy, modify, merge, publish,
8 distribute, sublicense, and/or sell copies of the Software, and to
9 permit persons to whom the Software is furnished to do so, subject to
10 the following conditions:
11 
12 The above copyright notice and this permission notice shall be
13 included in all copies or substantial portions of the Software.
14 
15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19 LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21 WITH 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 "compiler.h"
28 
29 #include <errno.h>
30 #if HAVE_EXECINFO_H
31 # include <execinfo.h>
32 #else
33   extern int backtrace (void **, int);
34 #endif
35 #include <signal.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <ucontext.h>
40 #include <unistd.h>
41 #include <libunwind.h>
42 
43 #define panic(args...)				\
44 	{ fprintf (stderr, args); exit (-1); }
45 
46 #define SIG_STACK_SIZE 0x100000
47 
48 int verbose;
49 int num_errors;
50 
51 /* These variables are global because they
52  * cause the signal stack to overflow */
53 char buf[512], name[256];
54 void *addresses[3][128];
55 unw_cursor_t cursor;
56 unw_context_t uc;
57 
58 static void
do_backtrace(void)59 do_backtrace (void)
60 {
61   unw_word_t ip;
62   int ret = -UNW_ENOINFO;
63   int depth = 0;
64   int i, n, m;
65 
66   if (verbose)
67     printf ("\tnormal trace:\n");
68 
69   unw_getcontext (&uc);
70   if (unw_init_local (&cursor, &uc) < 0)
71     panic ("unw_init_local failed!\n");
72 
73   do
74     {
75       unw_get_reg (&cursor, UNW_REG_IP, &ip);
76       addresses[0][depth] = (void *) ip;
77     }
78   while ((ret = unw_step (&cursor)) > 0 && ++depth < 128);
79 
80   if (ret < 0)
81     {
82       unw_get_reg (&cursor, UNW_REG_IP, &ip);
83       printf ("FAILURE: unw_step() returned %d for ip=%lx\n", ret, (long) ip);
84       ++num_errors;
85     }
86 
87   if (verbose)
88     for (i = 0; i < depth; ++i)
89       printf ("\t #%-3d ip=%p\n", i, addresses[0][i]);
90 
91   if (verbose)
92     printf ("\n\tvia backtrace():\n");
93 
94   n = backtrace (addresses[1], 128);
95 
96   if (verbose)
97     for (i = 0; i < n; ++i)
98 	printf ("\t #%-3d ip=%p\n", i, addresses[1][i]);
99 
100   if (verbose)
101     printf ("\n\tvia unw_backtrace():\n");
102 
103   m = unw_backtrace (addresses[2], 128);
104 
105   if (verbose)
106     for (i = 0; i < m; ++i)
107 	printf ("\t #%-3d ip=%p\n", i, addresses[2][i]);
108 
109   if (m != depth+1)
110     {
111       printf ("FAILURE: unw_step() loop and unw_backtrace() depths differ: %d vs. %d\n", depth, m);
112       ++num_errors;
113     }
114 
115   if (n != depth+1)
116     {
117       printf ("FAILURE: unw_step() loop and backtrace() depths differ: %d vs. %d\n", depth, n);
118       ++num_errors;
119     }
120 
121   if (n == m)
122     for (i = 1; i < n; ++i)
123       /* Allow one in difference in comparison, trace returns adjusted addresses. */
124       if (labs((unw_word_t) addresses[1][i] - (unw_word_t) addresses[2][i]) > 1)
125 	{
126           printf ("FAILURE: backtrace() and unw_backtrace() addresses differ at %d: %p vs. %p\n",
127                   i, addresses[1][i], addresses[2][i]);
128           ++num_errors;
129 	}
130 
131   if (n == depth+1)
132     for (i = 1; i < depth; ++i)
133       /* Allow one in difference in comparison, trace returns adjusted addresses. */
134       if (labs((unw_word_t) addresses[0][i] - (unw_word_t) addresses[1][i]) > 1)
135 	{
136           printf ("FAILURE: unw_step() loop and backtrace() addresses differ at %d: %p vs. %p\n",
137                   i, addresses[0][i], addresses[1][i]);
138           ++num_errors;
139 	}
140 }
141 
142 void
foo(long val UNUSED)143 foo (long val UNUSED)
144 {
145   do_backtrace ();
146 }
147 
148 void
bar(long v)149 bar (long v)
150 {
151   extern long f (long);
152   int arr[v];
153 
154   /* This is a vain attempt to use up lots of registers to force
155      the frame-chain info to be saved on the memory stack on ia64.
156      It happens to work with gcc v3.3.4 and gcc v3.4.1 but perhaps
157      not with any other compiler.  */
158   foo (f (arr[0]) + (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        + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + (f (v) + f (v))
175        ))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))
176        )))))))))))))))))))))))))))))))))))))))))))))))))))))));
177 }
178 
179 void
sighandler(int signal,void * siginfo UNUSED,void * context)180 sighandler (int signal, void *siginfo UNUSED, void *context)
181 {
182   ucontext_t *uc UNUSED;
183   int sp;
184 
185   uc = context;
186 
187   if (verbose)
188     {
189       printf ("sighandler: got signal %d, sp=%p", signal, &sp);
190 #if UNW_TARGET_IA64
191 # if defined(__linux__)
192       printf (" @ %lx", uc->uc_mcontext.sc_ip);
193 # else
194       {
195 	uint16_t reason;
196 	uint64_t ip;
197 
198 	__uc_get_reason (uc, &reason);
199 	__uc_get_ip (uc, &ip);
200 	printf (" @ %lx (reason=%d)", ip, reason);
201       }
202 # endif
203 #elif UNW_TARGET_X86
204 #if defined __linux__
205       printf (" @ %lx", (unsigned long) uc->uc_mcontext.gregs[REG_EIP]);
206 #elif defined __FreeBSD__
207       printf (" @ %lx", (unsigned long) uc->uc_mcontext.mc_eip);
208 #endif
209 #elif UNW_TARGET_X86_64
210 #if defined __linux__ || defined __sun
211       printf (" @ %lx", (unsigned long) uc->uc_mcontext.gregs[REG_RIP]);
212 #elif defined __FreeBSD__
213       printf (" @ %lx", (unsigned long) uc->uc_mcontext.mc_rip);
214 #endif
215 #elif defined UNW_TARGET_ARM
216 #if defined __linux__
217       printf (" @ %lx", (unsigned long) uc->uc_mcontext.arm_pc);
218 #elif defined __FreeBSD__
219       printf (" @ %lx", (unsigned long) uc->uc_mcontext.__gregs[_REG_PC]);
220 #endif
221 #endif
222       printf ("\n");
223     }
224   do_backtrace();
225 }
226 
227 int
main(int argc,char ** argv UNUSED)228 main (int argc, char **argv UNUSED)
229 {
230   struct sigaction act;
231   stack_t stk;
232 
233   verbose = (argc > 1);
234 
235   if (verbose)
236     printf ("Normal backtrace:\n");
237 
238   bar (1);
239 
240   memset (&act, 0, sizeof (act));
241   act.sa_handler = (void (*)(int)) sighandler;
242   act.sa_flags = SA_SIGINFO;
243   if (sigaction (SIGTERM, &act, NULL) < 0)
244     panic ("sigaction: %s\n", strerror (errno));
245 
246   if (verbose)
247     printf ("\nBacktrace across signal handler:\n");
248   kill (getpid (), SIGTERM);
249 
250   if (verbose)
251     printf ("\nBacktrace across signal handler on alternate stack:\n");
252   stk.ss_sp = malloc (SIG_STACK_SIZE);
253   if (!stk.ss_sp)
254     panic ("failed to allocate %u bytes\n", SIG_STACK_SIZE);
255   stk.ss_size = SIG_STACK_SIZE;
256   stk.ss_flags = 0;
257   if (sigaltstack (&stk, NULL) < 0)
258     panic ("sigaltstack: %s\n", strerror (errno));
259 
260   memset (&act, 0, sizeof (act));
261   act.sa_handler = (void (*)(int)) sighandler;
262   act.sa_flags = SA_ONSTACK | SA_SIGINFO;
263   if (sigaction (SIGTERM, &act, NULL) < 0)
264     panic ("sigaction: %s\n", strerror (errno));
265   kill (getpid (), SIGTERM);
266 
267   if (num_errors > 0)
268     {
269       fprintf (stderr, "FAILURE: detected %d errors\n", num_errors);
270       exit (-1);
271     }
272 
273   if (verbose)
274     printf ("SUCCESS.\n");
275 
276   signal (SIGTERM, SIG_DFL);
277   stk.ss_flags = SS_DISABLE;
278   sigaltstack (&stk, NULL);
279   free (stk.ss_sp);
280 
281   return 0;
282 }
283