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 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 is_x86_64_native; 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 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 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 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 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 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 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 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 * 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 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 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 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