1 /* Unwinding of frames like gstack/pstack. 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 <argp.h> 21 #include <error.h> 22 #include <stdlib.h> 23 #include <inttypes.h> 24 #include <stdio.h> 25 #include <stdio_ext.h> 26 #include <string.h> 27 #include <locale.h> 28 #include <fcntl.h> 29 #include ELFUTILS_HEADER(dwfl) 30 31 #include <dwarf.h> 32 #include <system.h> 33 34 /* Name and version of program. */ 35 static void print_version (FILE *stream, struct argp_state *state); 36 ARGP_PROGRAM_VERSION_HOOK_DEF = print_version; 37 38 /* Bug report address. */ 39 ARGP_PROGRAM_BUG_ADDRESS_DEF = PACKAGE_BUGREPORT; 40 41 /* non-printable argp options. */ 42 #define OPT_DEBUGINFO 0x100 43 #define OPT_COREFILE 0x101 44 45 static bool show_activation = false; 46 static bool show_module = false; 47 static bool show_build_id = false; 48 static bool show_source = false; 49 static bool show_one_tid = false; 50 static bool show_quiet = false; 51 static bool show_raw = false; 52 static bool show_modules = false; 53 static bool show_debugname = false; 54 static bool show_inlines = false; 55 56 static int maxframes = 256; 57 58 struct frame 59 { 60 Dwarf_Addr pc; 61 bool isactivation; 62 }; 63 64 struct frames 65 { 66 int frames; 67 int allocated; 68 struct frame *frame; 69 }; 70 71 static Dwfl *dwfl = NULL; 72 static pid_t pid = 0; 73 static int core_fd = -1; 74 static Elf *core = NULL; 75 static const char *exec = NULL; 76 static char *debuginfo_path = NULL; 77 78 static const Dwfl_Callbacks proc_callbacks = 79 { 80 .find_elf = dwfl_linux_proc_find_elf, 81 .find_debuginfo = dwfl_standard_find_debuginfo, 82 .debuginfo_path = &debuginfo_path, 83 }; 84 85 static const Dwfl_Callbacks core_callbacks = 86 { 87 .find_elf = dwfl_build_id_find_elf, 88 .find_debuginfo = dwfl_standard_find_debuginfo, 89 .debuginfo_path = &debuginfo_path, 90 }; 91 92 #ifdef USE_DEMANGLE 93 static size_t demangle_buffer_len = 0; 94 static char *demangle_buffer = NULL; 95 #endif 96 97 /* Whether any frames have been shown at all. Determines exit status. */ 98 static bool frames_shown = false; 99 100 /* Program exit codes. All frames shown without any errors is GOOD. 101 Some frames shown with some non-fatal errors is an ERROR. A fatal 102 error or no frames shown at all is BAD. A command line USAGE exit 103 is generated by argp_error. */ 104 #define EXIT_OK 0 105 #define EXIT_ERROR 1 106 #define EXIT_BAD 2 107 #define EXIT_USAGE 64 108 109 static int 110 get_addr_width (Dwfl_Module *mod) 111 { 112 // Try to find the address wide if possible. 113 static int width = 0; 114 if (width == 0 && mod) 115 { 116 Dwarf_Addr bias; 117 Elf *elf = dwfl_module_getelf (mod, &bias); 118 if (elf) 119 { 120 GElf_Ehdr ehdr_mem; 121 GElf_Ehdr *ehdr = gelf_getehdr (elf, &ehdr_mem); 122 if (ehdr) 123 width = ehdr->e_ident[EI_CLASS] == ELFCLASS32 ? 8 : 16; 124 } 125 } 126 if (width == 0) 127 width = 16; 128 129 return width; 130 } 131 132 static int 133 module_callback (Dwfl_Module *mod, void **userdata __attribute__((unused)), 134 const char *name, Dwarf_Addr start, 135 void *arg __attribute__((unused))) 136 { 137 /* Forces resolving of main elf and debug files. */ 138 Dwarf_Addr bias; 139 Elf *elf = dwfl_module_getelf (mod, &bias); 140 Dwarf *dwarf = dwfl_module_getdwarf (mod, &bias); 141 142 Dwarf_Addr end; 143 const char *mainfile; 144 const char *debugfile; 145 const char *modname = dwfl_module_info (mod, NULL, NULL, &end, NULL, 146 NULL, &mainfile, &debugfile); 147 assert (strcmp (modname, name) == 0); 148 149 int width = get_addr_width (mod); 150 printf ("0x%0*" PRIx64 "-0x%0*" PRIx64 " %s\n", 151 width, start, width, end, basename (name)); 152 153 const unsigned char *id; 154 GElf_Addr id_vaddr; 155 int id_len = dwfl_module_build_id (mod, &id, &id_vaddr); 156 if (id_len > 0) 157 { 158 printf (" ["); 159 do 160 printf ("%02" PRIx8, *id++); 161 while (--id_len > 0); 162 printf ("]\n"); 163 } 164 165 if (elf != NULL) 166 printf (" %s\n", mainfile != NULL ? mainfile : "-"); 167 if (dwarf != NULL) 168 printf (" %s\n", debugfile != NULL ? debugfile : "-"); 169 170 return DWARF_CB_OK; 171 } 172 173 static int 174 frame_callback (Dwfl_Frame *state, void *arg) 175 { 176 struct frames *frames = (struct frames *) arg; 177 int nr = frames->frames; 178 if (! dwfl_frame_pc (state, &frames->frame[nr].pc, 179 &frames->frame[nr].isactivation)) 180 return -1; 181 182 frames->frames++; 183 if (frames->frames == maxframes) 184 return DWARF_CB_ABORT; 185 186 if (frames->frames == frames->allocated) 187 { 188 frames->allocated *= 2; 189 frames->frame = realloc (frames->frame, 190 sizeof (struct frame) * frames->allocated); 191 if (frames->frame == NULL) 192 error (EXIT_BAD, errno, "realloc frames.frame"); 193 } 194 195 return DWARF_CB_OK; 196 } 197 198 static const char* 199 die_name (Dwarf_Die *die) 200 { 201 Dwarf_Attribute attr; 202 const char *name; 203 name = dwarf_formstring (dwarf_attr_integrate (die, 204 DW_AT_MIPS_linkage_name, 205 &attr) 206 ?: dwarf_attr_integrate (die, 207 DW_AT_linkage_name, 208 &attr)); 209 if (name == NULL) 210 name = dwarf_diename (die); 211 212 return name; 213 } 214 215 static void 216 print_frame (int nr, Dwarf_Addr pc, bool isactivation, 217 Dwarf_Addr pc_adjusted, Dwfl_Module *mod, 218 const char *symname, Dwarf_Die *cudie, 219 Dwarf_Die *die) 220 { 221 int width = get_addr_width (mod); 222 printf ("#%-2u 0x%0*" PRIx64, nr, width, (uint64_t) pc); 223 224 if (show_activation) 225 printf ("%4s", ! isactivation ? "- 1" : ""); 226 227 if (symname != NULL) 228 { 229 #ifdef USE_DEMANGLE 230 // Require GNU v3 ABI by the "_Z" prefix. 231 if (! show_raw && symname[0] == '_' && symname[1] == 'Z') 232 { 233 int status = -1; 234 char *dsymname = __cxa_demangle (symname, demangle_buffer, 235 &demangle_buffer_len, &status); 236 if (status == 0) 237 symname = demangle_buffer = dsymname; 238 } 239 #endif 240 printf (" %s", symname); 241 } 242 243 const char* fname; 244 Dwarf_Addr start; 245 fname = dwfl_module_info(mod, NULL, &start, 246 NULL, NULL, NULL, NULL, NULL); 247 if (show_module) 248 { 249 if (fname != NULL) 250 printf (" - %s", fname); 251 } 252 253 if (show_build_id) 254 { 255 const unsigned char *id; 256 GElf_Addr id_vaddr; 257 int id_len = dwfl_module_build_id (mod, &id, &id_vaddr); 258 if (id_len > 0) 259 { 260 printf ("\n ["); 261 do 262 printf ("%02" PRIx8, *id++); 263 while (--id_len > 0); 264 printf ("]@0x%0" PRIx64 "+0x%" PRIx64, 265 start, pc_adjusted - start); 266 } 267 } 268 269 if (show_source) 270 { 271 int line, col; 272 const char* sname; 273 line = col = -1; 274 sname = NULL; 275 if (die != NULL) 276 { 277 Dwarf_Files *files; 278 if (dwarf_getsrcfiles (cudie, &files, NULL) == 0) 279 { 280 Dwarf_Attribute attr; 281 Dwarf_Word val; 282 if (dwarf_formudata (dwarf_attr (die, DW_AT_call_file, &attr), 283 &val) == 0) 284 { 285 sname = dwarf_filesrc (files, val, NULL, NULL); 286 if (dwarf_formudata (dwarf_attr (die, DW_AT_call_line, 287 &attr), &val) == 0) 288 { 289 line = val; 290 if (dwarf_formudata (dwarf_attr (die, DW_AT_call_column, 291 &attr), &val) == 0) 292 col = val; 293 } 294 } 295 } 296 } 297 else 298 { 299 Dwfl_Line *lineobj = dwfl_module_getsrc(mod, pc_adjusted); 300 if (lineobj) 301 sname = dwfl_lineinfo (lineobj, NULL, &line, &col, NULL, NULL); 302 } 303 304 if (sname != NULL) 305 { 306 printf ("\n %s", sname); 307 if (line > 0) 308 { 309 printf (":%d", line); 310 if (col > 0) 311 printf (":%d", col); 312 } 313 } 314 } 315 printf ("\n"); 316 } 317 318 static void 319 print_inline_frames (int *nr, Dwarf_Addr pc, bool isactivation, 320 Dwarf_Addr pc_adjusted, Dwfl_Module *mod, 321 const char *symname, Dwarf_Die *cudie, Dwarf_Die *die) 322 { 323 Dwarf_Die *scopes = NULL; 324 int nscopes = dwarf_getscopes_die (die, &scopes); 325 if (nscopes > 0) 326 { 327 /* scopes[0] == die, the lowest level, for which we already have 328 the name. This is the actual source location where it 329 happened. */ 330 print_frame ((*nr)++, pc, isactivation, pc_adjusted, mod, symname, 331 NULL, NULL); 332 333 /* last_scope is the source location where the next frame/function 334 call was done. */ 335 Dwarf_Die *last_scope = &scopes[0]; 336 for (int i = 1; i < nscopes && (maxframes == 0 || *nr < maxframes); i++) 337 { 338 Dwarf_Die *scope = &scopes[i]; 339 int tag = dwarf_tag (scope); 340 if (tag != DW_TAG_inlined_subroutine 341 && tag != DW_TAG_entry_point 342 && tag != DW_TAG_subprogram) 343 continue; 344 345 symname = die_name (scope); 346 print_frame ((*nr)++, pc, isactivation, pc_adjusted, mod, symname, 347 cudie, last_scope); 348 349 /* Found the "top-level" in which everything was inlined? */ 350 if (tag == DW_TAG_subprogram) 351 break; 352 353 last_scope = scope; 354 } 355 } 356 free (scopes); 357 } 358 359 static void 360 print_frames (struct frames *frames, pid_t tid, int dwflerr, const char *what) 361 { 362 if (frames->frames > 0) 363 frames_shown = true; 364 365 printf ("TID %d:\n", tid); 366 int frame_nr = 0; 367 for (int nr = 0; nr < frames->frames && (maxframes == 0 368 || frame_nr < maxframes); nr++) 369 { 370 Dwarf_Addr pc = frames->frame[nr].pc; 371 bool isactivation = frames->frame[nr].isactivation; 372 Dwarf_Addr pc_adjusted = pc - (isactivation ? 0 : 1); 373 374 /* Get PC->SYMNAME. */ 375 Dwfl_Module *mod = dwfl_addrmodule (dwfl, pc_adjusted); 376 const char *symname = NULL; 377 Dwarf_Die die_mem; 378 Dwarf_Die *die = NULL; 379 Dwarf_Die *cudie = NULL; 380 if (mod && ! show_quiet) 381 { 382 if (show_debugname) 383 { 384 Dwarf_Addr bias = 0; 385 Dwarf_Die *scopes = NULL; 386 cudie = dwfl_module_addrdie (mod, pc_adjusted, &bias); 387 int nscopes = dwarf_getscopes (cudie, pc_adjusted - bias, 388 &scopes); 389 390 /* Find the first function-like DIE with a name in scope. */ 391 for (int i = 0; symname == NULL && i < nscopes; i++) 392 { 393 Dwarf_Die *scope = &scopes[i]; 394 int tag = dwarf_tag (scope); 395 if (tag == DW_TAG_subprogram 396 || tag == DW_TAG_inlined_subroutine 397 || tag == DW_TAG_entry_point) 398 symname = die_name (scope); 399 400 if (symname != NULL) 401 { 402 die_mem = *scope; 403 die = &die_mem; 404 } 405 } 406 free (scopes); 407 } 408 409 if (symname == NULL) 410 symname = dwfl_module_addrname (mod, pc_adjusted); 411 } 412 413 if (show_inlines && die != NULL) 414 print_inline_frames (&frame_nr, pc, isactivation, pc_adjusted, mod, 415 symname, cudie, die); 416 else 417 print_frame (frame_nr++, pc, isactivation, pc_adjusted, mod, symname, 418 NULL, NULL); 419 } 420 421 if (frames->frames > 0 && frame_nr == maxframes) 422 error (0, 0, "tid %d: shown max number of frames " 423 "(%d, use -n 0 for unlimited)", tid, maxframes); 424 else if (dwflerr != 0) 425 { 426 if (frames->frames > 0) 427 { 428 unsigned nr = frames->frames - 1; 429 Dwarf_Addr pc = frames->frame[nr].pc; 430 bool isactivation = frames->frame[nr].isactivation; 431 Dwarf_Addr pc_adjusted = pc - (isactivation ? 0 : 1); 432 Dwfl_Module *mod = dwfl_addrmodule (dwfl, pc_adjusted); 433 const char *mainfile = NULL; 434 const char *modname = dwfl_module_info (mod, NULL, NULL, NULL, NULL, 435 NULL, &mainfile, NULL); 436 if (modname == NULL || modname[0] == '\0') 437 { 438 if (mainfile != NULL) 439 modname = mainfile; 440 else 441 modname = "<unknown>"; 442 } 443 error (0, 0, "%s tid %d at 0x%" PRIx64 " in %s: %s", what, tid, 444 pc_adjusted, modname, dwfl_errmsg (dwflerr)); 445 } 446 else 447 error (0, 0, "%s tid %d: %s", what, tid, dwfl_errmsg (dwflerr)); 448 } 449 } 450 451 static int 452 thread_callback (Dwfl_Thread *thread, void *thread_arg) 453 { 454 struct frames *frames = (struct frames *) thread_arg; 455 pid_t tid = dwfl_thread_tid (thread); 456 int err = 0; 457 frames->frames = 0; 458 switch (dwfl_thread_getframes (thread, frame_callback, thread_arg)) 459 { 460 case DWARF_CB_OK: 461 case DWARF_CB_ABORT: 462 break; 463 case -1: 464 err = dwfl_errno (); 465 break; 466 default: 467 abort (); 468 } 469 print_frames (frames, tid, err, "dwfl_thread_getframes"); 470 return DWARF_CB_OK; 471 } 472 473 static void 474 print_version (FILE *stream, struct argp_state *state __attribute__ ((unused))) 475 { 476 fprintf (stream, "stack (%s) %s\n", PACKAGE_NAME, PACKAGE_VERSION); 477 } 478 479 static error_t 480 parse_opt (int key, char *arg __attribute__ ((unused)), 481 struct argp_state *state) 482 { 483 switch (key) 484 { 485 case 'p': 486 pid = atoi (arg); 487 if (pid == 0) 488 argp_error (state, N_("-p PID should be a positive process id.")); 489 break; 490 491 case OPT_COREFILE: 492 core_fd = open (arg, O_RDONLY); 493 if (core_fd < 0) 494 error (EXIT_BAD, errno, N_("Cannot open core file '%s'"), arg); 495 elf_version (EV_CURRENT); 496 core = elf_begin (core_fd, ELF_C_READ_MMAP, NULL); 497 if (core == NULL) 498 error (EXIT_BAD, 0, "core '%s' elf_begin: %s", arg, elf_errmsg(-1)); 499 break; 500 501 case 'e': 502 exec = arg; 503 break; 504 505 case OPT_DEBUGINFO: 506 debuginfo_path = arg; 507 break; 508 509 case 'm': 510 show_module = true; 511 break; 512 513 case 's': 514 show_source = true; 515 break; 516 517 case 'a': 518 show_activation = true; 519 break; 520 521 case 'd': 522 show_debugname = true; 523 break; 524 525 case 'i': 526 show_inlines = show_debugname = true; 527 break; 528 529 case 'v': 530 show_activation = show_source = show_module = show_debugname = true; 531 show_inlines = true; 532 break; 533 534 case 'b': 535 show_build_id = true; 536 break; 537 538 case 'q': 539 show_quiet = true; 540 break; 541 542 case 'r': 543 show_raw = true; 544 break; 545 546 case '1': 547 show_one_tid = true; 548 break; 549 550 case 'n': 551 maxframes = atoi (arg); 552 if (maxframes < 0) 553 { 554 argp_error (state, N_("-n MAXFRAMES should be 0 or higher.")); 555 return EINVAL; 556 } 557 break; 558 559 case 'l': 560 show_modules = true; 561 break; 562 563 case ARGP_KEY_END: 564 if (core == NULL && exec != NULL) 565 argp_error (state, 566 N_("-e EXEC needs a core given by --core.")); 567 568 if (pid == 0 && show_one_tid == true) 569 argp_error (state, 570 N_("-1 needs a thread id given by -p.")); 571 572 if ((pid == 0 && core == NULL) || (pid != 0 && core != NULL)) 573 argp_error (state, 574 N_("One of -p PID or --core COREFILE should be given.")); 575 576 if (pid != 0) 577 { 578 dwfl = dwfl_begin (&proc_callbacks); 579 if (dwfl == NULL) 580 error (EXIT_BAD, 0, "dwfl_begin: %s", dwfl_errmsg (-1)); 581 582 int err = dwfl_linux_proc_report (dwfl, pid); 583 if (err < 0) 584 error (EXIT_BAD, 0, "dwfl_linux_proc_report pid %d: %s", pid, 585 dwfl_errmsg (-1)); 586 else if (err > 0) 587 error (EXIT_BAD, err, "dwfl_linux_proc_report pid %d", pid); 588 } 589 590 if (core != NULL) 591 { 592 dwfl = dwfl_begin (&core_callbacks); 593 if (dwfl == NULL) 594 error (EXIT_BAD, 0, "dwfl_begin: %s", dwfl_errmsg (-1)); 595 if (dwfl_core_file_report (dwfl, core, exec) < 0) 596 error (EXIT_BAD, 0, "dwfl_core_file_report: %s", dwfl_errmsg (-1)); 597 } 598 599 if (dwfl_report_end (dwfl, NULL, NULL) != 0) 600 error (EXIT_BAD, 0, "dwfl_report_end: %s", dwfl_errmsg (-1)); 601 602 if (pid != 0) 603 { 604 int err = dwfl_linux_proc_attach (dwfl, pid, false); 605 if (err < 0) 606 error (EXIT_BAD, 0, "dwfl_linux_proc_attach pid %d: %s", pid, 607 dwfl_errmsg (-1)); 608 else if (err > 0) 609 error (EXIT_BAD, err, "dwfl_linux_proc_attach pid %d", pid); 610 } 611 612 if (core != NULL) 613 { 614 if (dwfl_core_file_attach (dwfl, core) < 0) 615 error (EXIT_BAD, 0, "dwfl_core_file_report: %s", dwfl_errmsg (-1)); 616 } 617 618 /* Makes sure we are properly attached. */ 619 if (dwfl_pid (dwfl) < 0) 620 error (EXIT_BAD, 0, "dwfl_pid: %s\n", dwfl_errmsg (-1)); 621 break; 622 623 default: 624 return ARGP_ERR_UNKNOWN; 625 } 626 return 0; 627 } 628 629 int 630 main (int argc, char **argv) 631 { 632 /* We use no threads here which can interfere with handling a stream. */ 633 __fsetlocking (stdin, FSETLOCKING_BYCALLER); 634 __fsetlocking (stdout, FSETLOCKING_BYCALLER); 635 __fsetlocking (stderr, FSETLOCKING_BYCALLER); 636 637 /* Set locale. */ 638 (void) setlocale (LC_ALL, ""); 639 640 const struct argp_option options[] = 641 { 642 { NULL, 0, NULL, 0, N_("Input selection options:"), 0 }, 643 { "pid", 'p', "PID", 0, 644 N_("Show stack of process PID"), 0 }, 645 { "core", OPT_COREFILE, "COREFILE", 0, 646 N_("Show stack found in COREFILE"), 0 }, 647 { "executable", 'e', "EXEC", 0, N_("(optional) EXECUTABLE that produced COREFILE"), 0 }, 648 { "debuginfo-path", OPT_DEBUGINFO, "PATH", 0, 649 N_("Search path for separate debuginfo files"), 0 }, 650 651 { NULL, 0, NULL, 0, N_("Output selection options:"), 0 }, 652 { "activation", 'a', NULL, 0, 653 N_("Additionally show frame activation"), 0 }, 654 { "debugname", 'd', NULL, 0, 655 N_("Additionally try to lookup DWARF debuginfo name for frame address"), 656 0 }, 657 { "inlines", 'i', NULL, 0, 658 N_("Additionally show inlined function frames using DWARF debuginfo if available (implies -d)"), 0 }, 659 { "module", 'm', NULL, 0, 660 N_("Additionally show module file information"), 0 }, 661 { "source", 's', NULL, 0, 662 N_("Additionally show source file information"), 0 }, 663 { "verbose", 'v', NULL, 0, 664 N_("Show all additional information (activation, debugname, inlines, module and source)"), 0 }, 665 { "quiet", 'q', NULL, 0, 666 N_("Do not resolve address to function symbol name"), 0 }, 667 { "raw", 'r', NULL, 0, 668 N_("Show raw function symbol names, do not try to demangle names"), 0 }, 669 { "build-id", 'b', NULL, 0, 670 N_("Show module build-id, load address and pc offset"), 0 }, 671 { NULL, '1', NULL, 0, 672 N_("Show the backtrace of only one thread"), 0 }, 673 { NULL, 'n', "MAXFRAMES", 0, 674 N_("Show at most MAXFRAMES per thread (default 256, use 0 for unlimited)"), 0 }, 675 { "list-modules", 'l', NULL, 0, 676 N_("Show module memory map with build-id, elf and debug files detected"), 0 }, 677 { NULL, 0, NULL, 0, NULL, 0 } 678 }; 679 680 const struct argp argp = 681 { 682 .options = options, 683 .parser = parse_opt, 684 .doc = N_("Print a stack for each thread in a process or core file.\v\ 685 Program exits with return code 0 if all frames were shown without \ 686 any errors. If some frames were shown, but there were some non-fatal \ 687 errors, possibly causing an incomplete backtrace, the program exits \ 688 with return code 1. If no frames could be shown, or a fatal error \ 689 occured the program exits with return code 2. If the program was \ 690 invoked with bad or missing arguments it will exit with return code 64.") 691 }; 692 693 argp_parse (&argp, argc, argv, 0, NULL, NULL); 694 695 if (show_modules) 696 { 697 printf ("PID %d - %s module memory map\n", dwfl_pid (dwfl), 698 pid != 0 ? "process" : "core"); 699 if (dwfl_getmodules (dwfl, module_callback, NULL, 0) != 0) 700 error (EXIT_BAD, 0, "dwfl_getmodules: %s", dwfl_errmsg (-1)); 701 } 702 703 struct frames frames; 704 /* When maxframes is zero, then 2048 is just the initial allocation 705 that will be increased using realloc in framecallback (). */ 706 frames.allocated = maxframes == 0 ? 2048 : maxframes; 707 frames.frames = 0; 708 frames.frame = malloc (sizeof (struct frame) * frames.allocated); 709 if (frames.frame == NULL) 710 error (EXIT_BAD, errno, "malloc frames.frame"); 711 712 if (show_one_tid) 713 { 714 int err = 0; 715 switch (dwfl_getthread_frames (dwfl, pid, frame_callback, &frames)) 716 { 717 case DWARF_CB_OK: 718 case DWARF_CB_ABORT: 719 break; 720 case -1: 721 err = dwfl_errno (); 722 break; 723 default: 724 abort (); 725 } 726 print_frames (&frames, pid, err, "dwfl_getthread_frames"); 727 } 728 else 729 { 730 printf ("PID %d - %s\n", dwfl_pid (dwfl), pid != 0 ? "process" : "core"); 731 switch (dwfl_getthreads (dwfl, thread_callback, &frames)) 732 { 733 case DWARF_CB_OK: 734 case DWARF_CB_ABORT: 735 break; 736 case -1: 737 error (0, 0, "dwfl_getthreads: %s", dwfl_errmsg (-1)); 738 break; 739 default: 740 abort (); 741 } 742 } 743 free (frames.frame); 744 dwfl_end (dwfl); 745 746 if (core != NULL) 747 elf_end (core); 748 749 if (core_fd != -1) 750 close (core_fd); 751 752 #ifdef USE_DEMANGLE 753 free (demangle_buffer); 754 #endif 755 756 if (! frames_shown) 757 error (EXIT_BAD, 0, N_("Couldn't show any frames.")); 758 759 return error_message_count != 0 ? EXIT_ERROR : EXIT_OK; 760 } 761