blob: 8211f7324af49bf707a813282591041d1a1a2925 [file] [log] [blame]
hp.com!davidm186cbb22004-09-15 11:37:04 +00001/* 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
5Permission is hereby granted, free of charge, to any person obtaining
6a copy of this software and associated documentation files (the
7"Software"), to deal in the Software without restriction, including
8without limitation the rights to use, copy, modify, merge, publish,
9distribute, sublicense, and/or sell copies of the Software, and to
10permit persons to whom the Software is furnished to do so, subject to
11the following conditions:
12
13The above copyright notice and this permission notice shall be
14included in all copies or substantial portions of the Software.
15
16THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22WITH 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 <errno.h>
29#if HAVE_EXECINFO_H
30# include <execinfo.h>
31#else
32 extern int backtrace (void **, int);
33#endif
34#include <signal.h>
35#include <stdio.h>
36#include <stdlib.h>
37#include <string.h>
38#include <unistd.h>
39#include <libunwind.h>
40
Bruna Moreira6f282a02008-04-21 13:39:11 -060041#if UNW_TARGET_X86 || UNW_TARGET_X86_64 || UNW_TARGET_ARM
42# define STACK_SIZE (128*1024) /* On x86/-64 and ARM, SIGSTKSZ is too small */
hp.com!davidm186cbb22004-09-15 11:37:04 +000043#else
44# define STACK_SIZE SIGSTKSZ
45#endif
46
47#define panic(args...) \
48 { fprintf (stderr, args); exit (-1); }
49
50#ifndef HAVE_SIGHANDLER_T
51typedef RETSIGTYPE (*sighandler_t) (int);
52#endif
53
54int verbose;
55int num_errors;
56
57static void
58do_backtrace (void)
59{
60 char buf[512], name[256];
61 unw_word_t ip, sp, off;
62 unw_cursor_t cursor;
63 unw_proc_info_t pi;
64 unw_context_t uc;
65 int ret;
66
mostang.com!davidm1ee6b0a2005-05-03 09:13:17 +000067 if (verbose)
68 printf ("\texplicit backtrace:\n");
69
hp.com!davidm186cbb22004-09-15 11:37:04 +000070 unw_getcontext (&uc);
71 if (unw_init_local (&cursor, &uc) < 0)
72 panic ("unw_init_local failed!\n");
73
74 do
75 {
76 unw_get_reg (&cursor, UNW_REG_IP, &ip);
77 unw_get_reg (&cursor, UNW_REG_SP, &sp);
78 buf[0] = '\0';
79 if (unw_get_proc_name (&cursor, name, sizeof (name), &off) == 0)
80 {
81 if (off)
82 snprintf (buf, sizeof (buf), "<%s+0x%lx>", name, (long) off);
83 else
84 snprintf (buf, sizeof (buf), "<%s>", name);
85 }
86 if (verbose)
87 {
88 printf ("%016lx %-32s (sp=%016lx)\n", (long) ip, buf, (long) sp);
89
90 unw_get_proc_info (&cursor, &pi);
91 printf ("\tproc=%lx-%lx\n\thandler=%lx lsda=%lx gp=%lx",
92 (long) pi.start_ip, (long) pi.end_ip,
93 (long) pi.handler, (long) pi.lsda, (long) pi.gp);
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);
mostang.com!davidm1ee6b0a2005-05-03 09:13:17 +0000116
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 }
hp.com!davidm186cbb22004-09-15 11:37:04 +0000128}
129
130void
131foo (long val)
132{
hp.com!davidm186cbb22004-09-15 11:37:04 +0000133 do_backtrace ();
hp.com!davidm186cbb22004-09-15 11:37:04 +0000134}
135
136void
137bar (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
167void
168sighandler (int signal, void *siginfo, void *context)
169{
170 ucontext_t *uc = context;
171 int sp;
172
173 if (verbose)
174 {
175 printf ("sighandler: got signal %d, sp=%p", signal, &sp);
176#if UNW_TARGET_IA64
177# if defined(__linux__)
178 printf (" @ %lx", uc->uc_mcontext.sc_ip);
179# else
180 {
181 uint16_t reason;
182 uint64_t ip;
183
184 __uc_get_reason (uc, &reason);
185 __uc_get_ip (uc, &ip);
186 printf (" @ %lx (reason=%d)", ip, reason);
187 }
188# endif
189#elif UNW_TARGET_X86
190 printf (" @ %lx", (unsigned long) uc->uc_mcontext.gregs[REG_EIP]);
191#endif
192 printf ("\n");
193 }
194 do_backtrace();
195}
196
197int
198main (int argc, char **argv)
199{
200 struct sigaction act;
201 stack_t stk;
202
203 verbose = (argc > 1);
204
205 if (verbose)
206 printf ("Normal backtrace:\n");
207
208 bar (1);
209
210 memset (&act, 0, sizeof (act));
211 act.sa_handler = (void (*)(int)) sighandler;
212 act.sa_flags = SA_SIGINFO;
213 if (sigaction (SIGTERM, &act, NULL) < 0)
214 panic ("sigaction: %s\n", strerror (errno));
215
216 if (verbose)
217 printf ("\nBacktrace across signal handler:\n");
218 kill (getpid (), SIGTERM);
219
220 if (verbose)
221 printf ("\nBacktrace across signal handler on alternate stack:\n");
222 stk.ss_sp = malloc (STACK_SIZE);
223 if (!stk.ss_sp)
224 panic ("failed to allocate SIGSTKSZ (%u) bytes\n", SIGSTKSZ);
225 stk.ss_size = STACK_SIZE;
226 stk.ss_flags = 0;
227 if (sigaltstack (&stk, NULL) < 0)
228 panic ("sigaltstack: %s\n", strerror (errno));
229
230 memset (&act, 0, sizeof (act));
231 act.sa_handler = (void (*)(int)) sighandler;
232 act.sa_flags = SA_ONSTACK | SA_SIGINFO;
233 if (sigaction (SIGTERM, &act, NULL) < 0)
234 panic ("sigaction: %s\n", strerror (errno));
235 kill (getpid (), SIGTERM);
236
237 if (num_errors > 0)
238 {
239 fprintf (stderr, "FAILURE: detected %d errors\n", num_errors);
240 exit (-1);
241 }
242 if (verbose)
243 printf ("SUCCESS.\n");
244 return 0;
245}