Home | History | Annotate | Download | only in tests
      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