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