Home | History | Annotate | Download | only in tests
      1 /* Test program for unwinding of frames.
      2    Copyright (C) 2013, 2014, 2016 Red Hat, Inc.
      3    This file is part of elfutils.
      4 
      5    This file is free software; you can redistribute it and/or modify
      6    it under the terms of the GNU General Public License as published by
      7    the Free Software Foundation; either version 3 of the License, or
      8    (at your option) any later version.
      9 
     10    elfutils is distributed in the hope that it will be useful, but
     11    WITHOUT ANY WARRANTY; without even the implied warranty of
     12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     13    GNU General Public License for more details.
     14 
     15    You should have received a copy of the GNU General Public License
     16    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
     17 
     18 #include <config.h>
     19 #include <assert.h>
     20 #include <inttypes.h>
     21 #include <stdio.h>
     22 #include <stdio_ext.h>
     23 #include <locale.h>
     24 #include <dirent.h>
     25 #include <stdlib.h>
     26 #include <errno.h>
     27 #include <unistd.h>
     28 #include <dwarf.h>
     29 #ifdef __linux__
     30 #include <sys/resource.h>
     31 #include <sys/ptrace.h>
     32 #include <signal.h>
     33 #include <sys/types.h>
     34 #include <sys/wait.h>
     35 #include <sys/user.h>
     36 #include <fcntl.h>
     37 #include <string.h>
     38 #include <argp.h>
     39 #include ELFUTILS_HEADER(dwfl)
     40 #endif
     41 #include "system.h"
     42 
     43 #ifndef __linux__
     44 
     45 int
     46 main (int argc __attribute__ ((unused)), char **argv)
     47 {
     48   fprintf (stderr, "%s: Unwinding not supported for this architecture\n",
     49 	   argv[0]);
     50   return 77;
     51 }
     52 
     53 #else /* __linux__ */
     54 
     55 static int
     56 dump_modules (Dwfl_Module *mod, void **userdata __attribute__ ((unused)),
     57 	      const char *name, Dwarf_Addr start,
     58 	      void *arg __attribute__ ((unused)))
     59 {
     60   Dwarf_Addr end;
     61   dwfl_module_info (mod, NULL, NULL, &end, NULL, NULL, NULL, NULL);
     62   printf ("%#" PRIx64 "\t%#" PRIx64 "\t%s\n", (uint64_t) start, (uint64_t) end,
     63 	  name);
     64   return DWARF_CB_OK;
     65 }
     66 
     67 static bool use_raise_jmp_patching;
     68 static pid_t check_tid;
     69 
     70 static void
     71 callback_verify (pid_t tid, unsigned frameno, Dwarf_Addr pc,
     72 		 const char *symname, Dwfl *dwfl)
     73 {
     74   static bool seen_main = false;
     75   if (symname && *symname == '.')
     76     symname++;
     77   if (symname && strcmp (symname, "main") == 0)
     78     seen_main = true;
     79   if (pc == 0)
     80     {
     81       assert (seen_main);
     82       return;
     83     }
     84   if (check_tid == 0)
     85     check_tid = tid;
     86   if (tid != check_tid)
     87     {
     88       // For the main thread we are only interested if we can unwind till
     89       // we see the "main" symbol.
     90       return;
     91     }
     92   Dwfl_Module *mod;
     93   /* See case 4. Special case to help out simple frame pointer unwinders. */
     94   static bool duplicate_sigusr2 = false;
     95   if (duplicate_sigusr2)
     96     frameno--;
     97   static bool reduce_frameno = false;
     98   if (reduce_frameno)
     99     frameno--;
    100   if (! use_raise_jmp_patching && frameno >= 2)
    101     frameno += 2;
    102   const char *symname2 = NULL;
    103   switch (frameno)
    104   {
    105     case 0:
    106       if (! reduce_frameno && symname
    107 	       && (strcmp (symname, "__kernel_vsyscall") == 0
    108 		   || strcmp (symname, "__libc_do_syscall") == 0))
    109 	reduce_frameno = true;
    110       else
    111 	assert (symname && strcmp (symname, "raise") == 0);
    112       break;
    113     case 1:
    114       assert (symname != NULL && strcmp (symname, "sigusr2") == 0);
    115       break;
    116     case 2: // x86_64 only
    117       /* __restore_rt - glibc maybe does not have to have this symbol.  */
    118       break;
    119     case 3: // use_raise_jmp_patching
    120       if (use_raise_jmp_patching)
    121 	{
    122 	  /* Verify we trapped on the very first instruction of jmp.  */
    123 	  assert (symname != NULL && strcmp (symname, "jmp") == 0);
    124 	  mod = dwfl_addrmodule (dwfl, pc - 1);
    125 	  if (mod)
    126 	    symname2 = dwfl_module_addrname (mod, pc - 1);
    127 	  assert (symname2 == NULL || strcmp (symname2, "jmp") != 0);
    128 	  break;
    129 	}
    130       FALLTHROUGH;
    131     case 4:
    132       /* Some simple frame unwinders get this wrong and think sigusr2
    133 	 is calling itself again. Allow it and just pretend there is
    134 	 an extra sigusr2 frame. */
    135       if (symname != NULL && strcmp (symname, "sigusr2") == 0)
    136 	{
    137 	  duplicate_sigusr2 = true;
    138 	  break;
    139 	}
    140       assert (symname != NULL && strcmp (symname, "stdarg") == 0);
    141       break;
    142     case 5:
    143       /* Verify we trapped on the very last instruction of child.  */
    144       assert (symname != NULL && strcmp (symname, "backtracegen") == 0);
    145       mod = dwfl_addrmodule (dwfl, pc);
    146       if (mod)
    147 	symname2 = dwfl_module_addrname (mod, pc);
    148 
    149       // Note that the following assert might in theory even fail on x86_64,
    150       // there is no guarantee that the compiler doesn't reorder the
    151       // instructions or even inserts some padding instructions at the end
    152       // (which apparently happens on ppc64).
    153       if (use_raise_jmp_patching)
    154         assert (symname2 == NULL || strcmp (symname2, "backtracegen") != 0);
    155       break;
    156   }
    157 }
    158 
    159 static int
    160 frame_callback (Dwfl_Frame *state, void *frame_arg)
    161 {
    162   int *framenop = frame_arg;
    163   Dwarf_Addr pc;
    164   bool isactivation;
    165 
    166   if (*framenop > 16)
    167     {
    168       error (0, 0, "Too many frames: %d\n", *framenop);
    169       return DWARF_CB_ABORT;
    170     }
    171 
    172   if (! dwfl_frame_pc (state, &pc, &isactivation))
    173     {
    174       error (0, 0, "%s", dwfl_errmsg (-1));
    175       return DWARF_CB_ABORT;
    176     }
    177   Dwarf_Addr pc_adjusted = pc - (isactivation ? 0 : 1);
    178 
    179   /* Get PC->SYMNAME.  */
    180   Dwfl_Thread *thread = dwfl_frame_thread (state);
    181   Dwfl *dwfl = dwfl_thread_dwfl (thread);
    182   Dwfl_Module *mod = dwfl_addrmodule (dwfl, pc_adjusted);
    183   const char *symname = NULL;
    184   if (mod)
    185     symname = dwfl_module_addrname (mod, pc_adjusted);
    186 
    187   printf ("#%2d %#" PRIx64 "%4s\t%s\n", *framenop, (uint64_t) pc,
    188 	  ! isactivation ? "- 1" : "", symname);
    189   pid_t tid = dwfl_thread_tid (thread);
    190   callback_verify (tid, *framenop, pc, symname, dwfl);
    191   (*framenop)++;
    192 
    193   return DWARF_CB_OK;
    194 }
    195 
    196 static int
    197 thread_callback (Dwfl_Thread *thread, void *thread_arg __attribute__((unused)))
    198 {
    199   printf ("TID %ld:\n", (long) dwfl_thread_tid (thread));
    200   int frameno = 0;
    201   switch (dwfl_thread_getframes (thread, frame_callback, &frameno))
    202     {
    203     case 0:
    204       break;
    205     case DWARF_CB_ABORT:
    206       return DWARF_CB_ABORT;
    207     case -1:
    208       error (0, 0, "dwfl_thread_getframes: %s", dwfl_errmsg (-1));
    209       /* All platforms do not have yet proper unwind termination.  */
    210       break;
    211     default:
    212       abort ();
    213     }
    214   return DWARF_CB_OK;
    215 }
    216 
    217 static void
    218 dump (Dwfl *dwfl)
    219 {
    220   ptrdiff_t ptrdiff = dwfl_getmodules (dwfl, dump_modules, NULL, 0);
    221   assert (ptrdiff == 0);
    222   bool err = false;
    223   switch (dwfl_getthreads (dwfl, thread_callback, NULL))
    224     {
    225     case 0:
    226       break;
    227     case DWARF_CB_ABORT:
    228       err = true;
    229       break;
    230     case -1:
    231       error (0, 0, "dwfl_getthreads: %s", dwfl_errmsg (-1));
    232       err = true;
    233       break;
    234     default:
    235       abort ();
    236     }
    237   callback_verify (0, 0, 0, NULL, dwfl);
    238   if (err)
    239     exit (EXIT_FAILURE);
    240 }
    241 
    242 struct see_exec_module
    243 {
    244   Dwfl_Module *mod;
    245   char selfpath[PATH_MAX + 1];
    246 };
    247 
    248 static int
    249 see_exec_module (Dwfl_Module *mod, void **userdata __attribute__ ((unused)),
    250 		 const char *name __attribute__ ((unused)),
    251 		 Dwarf_Addr start __attribute__ ((unused)), void *arg)
    252 {
    253   struct see_exec_module *data = arg;
    254   if (strcmp (name, data->selfpath) != 0)
    255     return DWARF_CB_OK;
    256   assert (data->mod == NULL);
    257   data->mod = mod;
    258   return DWARF_CB_ABORT;
    259 }
    260 
    261 /* We used to do this on x86_64 only (see backtrace-child why we now don't):
    262      PC will get changed to function 'jmp' by backtrace.c function
    263      prepare_thread.  Then SIGUSR2 will be signalled to backtrace-child
    264      which will invoke function sigusr2.
    265      This is all done so that signal interrupts execution of the very first
    266      instruction of a function.  Properly handled unwind should not slip into
    267      the previous unrelated function.  */
    268 
    269 #ifdef __x86_64__
    270 /* #define RAISE_JMP_PATCHING 1 */
    271 #endif
    272 
    273 static void
    274 prepare_thread (pid_t pid2 __attribute__ ((unused)),
    275 		void (*jmp) (void) __attribute__ ((unused)))
    276 {
    277 #ifndef RAISE_JMP_PATCHING
    278   abort ();
    279 #else /* RAISE_JMP_PATCHING */
    280   long l;
    281   struct user_regs_struct user_regs;
    282   errno = 0;
    283   l = ptrace (PTRACE_GETREGS, pid2, 0, (intptr_t) &user_regs);
    284   assert (l == 0);
    285   user_regs.rip = (intptr_t) jmp;
    286   l = ptrace (PTRACE_SETREGS, pid2, 0, (intptr_t) &user_regs);
    287   assert (l == 0);
    288   l = ptrace (PTRACE_CONT, pid2, NULL, (void *) (intptr_t) SIGUSR2);
    289   int status;
    290   pid_t got = waitpid (pid2, &status, __WALL);
    291   assert (got == pid2);
    292   assert (WIFSTOPPED (status));
    293   assert (WSTOPSIG (status) == SIGUSR1);
    294 #endif /* RAISE_JMP_PATCHING */
    295 }
    296 
    297 #include <asm/unistd.h>
    298 #include <unistd.h>
    299 
    300 static void
    301 report_pid (Dwfl *dwfl, pid_t pid)
    302 {
    303   int result = dwfl_linux_proc_report (dwfl, pid);
    304   if (result < 0)
    305     error (2, 0, "dwfl_linux_proc_report: %s", dwfl_errmsg (-1));
    306   else if (result > 0)
    307     error (2, result, "dwfl_linux_proc_report");
    308 
    309   if (dwfl_report_end (dwfl, NULL, NULL) != 0)
    310     error (2, 0, "dwfl_report_end: %s", dwfl_errmsg (-1));
    311 
    312   result = dwfl_linux_proc_attach (dwfl, pid, true);
    313   if (result < 0)
    314     error (2, 0, "dwfl_linux_proc_attach: %s", dwfl_errmsg (-1));
    315   else if (result > 0)
    316     error (2, result, "dwfl_linux_proc_attach");
    317 }
    318 
    319 static Dwfl *
    320 pid_to_dwfl (pid_t pid)
    321 {
    322   static char *debuginfo_path;
    323   static const Dwfl_Callbacks proc_callbacks =
    324     {
    325       .find_debuginfo = dwfl_standard_find_debuginfo,
    326       .debuginfo_path = &debuginfo_path,
    327 
    328       .find_elf = dwfl_linux_proc_find_elf,
    329     };
    330   Dwfl *dwfl = dwfl_begin (&proc_callbacks);
    331   if (dwfl == NULL)
    332     error (2, 0, "dwfl_begin: %s", dwfl_errmsg (-1));
    333   report_pid (dwfl, pid);
    334   return dwfl;
    335 }
    336 
    337 static void
    338 exec_dump (const char *exec)
    339 {
    340   pid_t pid = fork ();
    341   switch (pid)
    342   {
    343     case -1:
    344       abort ();
    345     case 0:
    346       execl (exec, exec, "--ptraceme", NULL);
    347       abort ();
    348     default:
    349       break;
    350   }
    351 
    352   /* Catch the main thread.  Catch it first otherwise the /proc evaluation of
    353      PID may have caught still ourselves before executing execl above.  */
    354   errno = 0;
    355   int status;
    356   pid_t got = waitpid (pid, &status, 0);
    357   assert (got == pid);
    358   assert (WIFSTOPPED (status));
    359   // Main thread will signal SIGUSR2.  Other thread will signal SIGUSR1.
    360   assert (WSTOPSIG (status) == SIGUSR2);
    361 
    362   /* Catch the spawned thread.  Do not use __WCLONE as we could get racy
    363      __WCLONE, probably despite pthread_create already had to be called the new
    364      task is not yet alive enough for waitpid.  */
    365   pid_t pid2 = waitpid (-1, &status, __WALL);
    366   assert (pid2 > 0);
    367   assert (pid2 != pid);
    368   assert (WIFSTOPPED (status));
    369   // Main thread will signal SIGUSR2.  Other thread will signal SIGUSR1.
    370   assert (WSTOPSIG (status) == SIGUSR1);
    371 
    372   Dwfl *dwfl = pid_to_dwfl (pid);
    373   char *selfpathname;
    374   int i = asprintf (&selfpathname, "/proc/%ld/exe", (long) pid);
    375   assert (i > 0);
    376   struct see_exec_module data;
    377   ssize_t ssize = readlink (selfpathname, data.selfpath,
    378 			    sizeof (data.selfpath));
    379   free (selfpathname);
    380   assert (ssize > 0 && ssize < (ssize_t) sizeof (data.selfpath));
    381   data.selfpath[ssize] = '\0';
    382   data.mod = NULL;
    383   dwfl_getmodules (dwfl, see_exec_module, &data, 0);
    384   assert (data.mod != NULL);
    385   GElf_Addr loadbase;
    386   Elf *elf = dwfl_module_getelf (data.mod, &loadbase);
    387   GElf_Ehdr ehdr_mem, *ehdr = gelf_getehdr (elf, &ehdr_mem);
    388   assert (ehdr != NULL);
    389   /* It is false also on x86_64 with i386 inferior.  */
    390 #ifndef RAISE_JMP_PATCHING
    391   use_raise_jmp_patching = false;
    392 #else /* RAISE_JMP_PATCHING_ */
    393   use_raise_jmp_patching = ehdr->e_machine == EM_X86_64;
    394 #endif /* __x86_64__ */
    395   void (*jmp) (void) = 0;
    396   if (use_raise_jmp_patching)
    397     {
    398       // Find inferior symbol named "jmp".
    399       int nsym = dwfl_module_getsymtab (data.mod);
    400       int symi;
    401       for (symi = 1; symi < nsym; ++symi)
    402 	{
    403 	  GElf_Sym symbol;
    404 	  const char *symbol_name = dwfl_module_getsym (data.mod, symi, &symbol, NULL);
    405 	  if (symbol_name == NULL)
    406 	    continue;
    407 	  switch (GELF_ST_TYPE (symbol.st_info))
    408 	    {
    409 	    case STT_SECTION:
    410 	    case STT_FILE:
    411 	    case STT_TLS:
    412 	      continue;
    413 	    default:
    414 	      if (strcmp (symbol_name, "jmp") != 0)
    415 		continue;
    416 	      break;
    417 	    }
    418 	  /* LOADBASE is already applied here.  */
    419 	  jmp = (void (*) (void)) (uintptr_t) symbol.st_value;
    420 	  break;
    421 	}
    422       assert (symi < nsym);
    423       prepare_thread (pid2, jmp);
    424     }
    425   dwfl_end (dwfl);
    426   check_tid = pid2;
    427   dwfl = pid_to_dwfl (pid);
    428   dump (dwfl);
    429   dwfl_end (dwfl);
    430 }
    431 
    432 #define OPT_BACKTRACE_EXEC 0x100
    433 
    434 static const struct argp_option options[] =
    435   {
    436     { "backtrace-exec", OPT_BACKTRACE_EXEC, "EXEC", 0, N_("Run executable"), 0 },
    437     { NULL, 0, NULL, 0, NULL, 0 }
    438   };
    439 
    440 
    441 static error_t
    442 parse_opt (int key, char *arg, struct argp_state *state)
    443 {
    444   switch (key)
    445     {
    446     case ARGP_KEY_INIT:
    447       state->child_inputs[0] = state->input;
    448       break;
    449 
    450     case OPT_BACKTRACE_EXEC:
    451       exec_dump (arg);
    452       exit (0);
    453 
    454     default:
    455       return ARGP_ERR_UNKNOWN;
    456     }
    457   return 0;
    458 }
    459 
    460 int
    461 main (int argc __attribute__ ((unused)), char **argv)
    462 {
    463   /* We use no threads here which can interfere with handling a stream.  */
    464   __fsetlocking (stdin, FSETLOCKING_BYCALLER);
    465   __fsetlocking (stdout, FSETLOCKING_BYCALLER);
    466   __fsetlocking (stderr, FSETLOCKING_BYCALLER);
    467 
    468   /* Set locale.  */
    469   (void) setlocale (LC_ALL, "");
    470 
    471   elf_version (EV_CURRENT);
    472 
    473   Dwfl *dwfl = NULL;
    474   const struct argp_child argp_children[] =
    475     {
    476       { .argp = dwfl_standard_argp () },
    477       { .argp = NULL }
    478     };
    479   const struct argp argp =
    480     {
    481       options, parse_opt, NULL, NULL, argp_children, NULL, NULL
    482     };
    483   (void) argp_parse (&argp, argc, argv, 0, NULL, &dwfl);
    484   assert (dwfl != NULL);
    485   /* We want to make sure the dwfl was properly attached.  */
    486   if (dwfl_pid (dwfl) < 0)
    487     error (2, 0, "dwfl_pid: %s", dwfl_errmsg (-1));
    488   dump (dwfl);
    489   dwfl_end (dwfl);
    490   return 0;
    491 }
    492 
    493 #endif /* ! __linux__ */
    494 
    495