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