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