802dd085795fbb85b2e9d07c8e8c12a0d113a6b4
[platform/upstream/libunwind.git] / tests / Gtest-bt.c
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
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
130 foo (long val UNUSED)
131 {
132   do_backtrace ();
133 }
134
135 void
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
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
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 }