• 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 <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 unw_cursor_t cursor;
55 unw_context_t uc;
56 
57 static void
do_backtrace(void)58 do_backtrace (void)
59 {
60   unw_word_t ip, sp, off;
61   unw_proc_info_t pi;
62   int ret;
63 
64   if (verbose)
65     printf ("\texplicit backtrace:\n");
66 
67   unw_getcontext (&uc);
68   if (unw_init_local (&cursor, &uc) < 0)
69     panic ("unw_init_local failed!\n");
70 
71   do
72     {
73       unw_get_reg (&cursor, UNW_REG_IP, &ip);
74       unw_get_reg (&cursor, UNW_REG_SP, &sp);
75       buf[0] = '\0';
76       if (unw_get_proc_name (&cursor, name, sizeof (name), &off) == 0)
77 	{
78 	  if (off)
79 	    snprintf (buf, sizeof (buf), "<%s+0x%lx>", name, (long) off);
80 	  else
81 	    snprintf (buf, sizeof (buf), "<%s>", name);
82 	}
83       if (verbose)
84 	{
85 	  printf ("%016lx %-32s (sp=%016lx)\n", (long) ip, buf, (long) sp);
86 
87 	  if (unw_get_proc_info (&cursor, &pi) == 0)
88 	    {
89 	      printf ("\tproc=0x%lx-0x%lx\n\thandler=0x%lx lsda=0x%lx gp=0x%lx",
90 		  (long) pi.start_ip, (long) pi.end_ip,
91 		  (long) pi.handler, (long) pi.lsda, (long) pi.gp);
92 	    }
93 
94 #if UNW_TARGET_IA64
95 	  {
96 	    unw_word_t bsp;
97 
98 	    unw_get_reg (&cursor, UNW_IA64_BSP, &bsp);
99 	    printf (" bsp=%lx", bsp);
100 	  }
101 #endif
102 	  printf ("\n");
103 	}
104 
105       ret = unw_step (&cursor);
106       if (ret < 0)
107 	{
108 	  unw_get_reg (&cursor, UNW_REG_IP, &ip);
109 	  printf ("FAILURE: unw_step() returned %d for ip=%lx\n",
110 		  ret, (long) ip);
111 	  ++num_errors;
112 	}
113     }
114   while (ret > 0);
115 
116   {
117     void *buffer[20];
118     int i, n;
119 
120     if (verbose)
121       printf ("\n\tvia backtrace():\n");
122     n = backtrace (buffer, 20);
123     if (verbose)
124       for (i = 0; i < n; ++i)
125 	printf ("[%d] ip=%p\n", i, buffer[i]);
126   }
127 }
128 
129 void
foo(long val UNUSED)130 foo (long val UNUSED)
131 {
132   do_backtrace ();
133 }
134 
135 void
bar(long v)136 bar (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 
166 void
sighandler(int signal,void * siginfo UNUSED,void * context)167 sighandler (int signal, void *siginfo UNUSED, void *context)
168 {
169   ucontext_t *uc UNUSED;
170   int sp;
171 
172   uc = context;
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 
208 int
main(int argc,char ** argv UNUSED)209 main (int argc, char **argv UNUSED)
210 {
211   struct sigaction act;
212   stack_t stk;
213 
214   verbose = (argc > 1);
215 
216   if (verbose)
217     printf ("Normal backtrace:\n");
218 
219   bar (1);
220 
221   memset (&act, 0, sizeof (act));
222   act.sa_handler = (void (*)(int)) sighandler;
223   act.sa_flags = SA_SIGINFO;
224   if (sigaction (SIGTERM, &act, NULL) < 0)
225     panic ("sigaction: %s\n", strerror (errno));
226 
227   if (verbose)
228     printf ("\nBacktrace across signal handler:\n");
229   kill (getpid (), SIGTERM);
230 
231   if (verbose)
232     printf ("\nBacktrace across signal handler on alternate stack:\n");
233   stk.ss_sp = malloc (SIG_STACK_SIZE);
234   if (!stk.ss_sp)
235     panic ("failed to allocate %u bytes\n", SIG_STACK_SIZE);
236   stk.ss_size = SIG_STACK_SIZE;
237   stk.ss_flags = 0;
238   if (sigaltstack (&stk, NULL) < 0)
239     panic ("sigaltstack: %s\n", strerror (errno));
240 
241   memset (&act, 0, sizeof (act));
242   act.sa_handler = (void (*)(int)) sighandler;
243   act.sa_flags = SA_ONSTACK | SA_SIGINFO;
244   if (sigaction (SIGTERM, &act, NULL) < 0)
245     panic ("sigaction: %s\n", strerror (errno));
246   kill (getpid (), SIGTERM);
247 
248   if (num_errors > 0)
249     {
250       fprintf (stderr, "FAILURE: detected %d errors\n", num_errors);
251       exit (-1);
252     }
253   if (verbose)
254     printf ("SUCCESS.\n");
255 
256   signal (SIGTERM, SIG_DFL);
257   stk.ss_flags = SS_DISABLE;
258   sigaltstack (&stk, NULL);
259   free (stk.ss_sp);
260 
261   return 0;
262 }
263