Imported Upstream version 1.3.1
[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 <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
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
131 foo (long val UNUSED)
132 {
133   do_backtrace ();
134 }
135
136 void
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
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__)
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__
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__
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
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 }