1 /* libunwind - a platform-independent unwind library 2 Copyright (C) 2001-2004 Hewlett-Packard Co 3 Contributed by David Mosberger-Tang <davidm (at) 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 } 263