1 /* Print symbol information from ELF file in human-readable form. 2 Copyright (C) 2000-2008, 2009, 2011, 2012 Red Hat, Inc. 3 This file is part of Red Hat elfutils. 4 Written by Ulrich Drepper <drepper (at) redhat.com>, 2000. 5 6 Red Hat elfutils is free software; you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by the 8 Free Software Foundation; version 2 of the License. 9 10 Red Hat 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 GNU 13 General Public License for more details. 14 15 You should have received a copy of the GNU General Public License along 16 with Red Hat elfutils; if not, write to the Free Software Foundation, 17 Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA. 18 19 Red Hat elfutils is an included package of the Open Invention Network. 20 An included package of the Open Invention Network is a package for which 21 Open Invention Network licensees cross-license their patents. No patent 22 license is granted, either expressly or impliedly, by designation as an 23 included package. Should you wish to participate in the Open Invention 24 Network licensing program, please visit www.openinventionnetwork.com 25 <http://www.openinventionnetwork.com>. */ 26 27 #ifdef HAVE_CONFIG_H 28 # include <config.h> 29 #endif 30 31 #include <ar.h> 32 #include <argp.h> 33 #include <assert.h> 34 #include <ctype.h> 35 #include <dwarf.h> 36 #include <errno.h> 37 #include <error.h> 38 #include <fcntl.h> 39 #include <gelf.h> 40 #include <inttypes.h> 41 #include <libdw.h> 42 #include <libintl.h> 43 #include <locale.h> 44 #include <mcheck.h> 45 #include <obstack.h> 46 #include <search.h> 47 #include <stdbool.h> 48 #include <stdio.h> 49 #include <stdio_ext.h> 50 #include <stdlib.h> 51 #include <string.h> 52 #include <unistd.h> 53 #include <sys/param.h> 54 55 #include <system.h> 56 #include "../libebl/libeblP.h" 57 58 59 /* Name and version of program. */ 60 static void print_version (FILE *stream, struct argp_state *state); 61 ARGP_PROGRAM_VERSION_HOOK_DEF = print_version; 62 63 /* Bug report address. */ 64 ARGP_PROGRAM_BUG_ADDRESS_DEF = PACKAGE_BUGREPORT; 65 66 67 /* Values for the parameters which have no short form. */ 68 #define OPT_DEFINED 0x100 69 #define OPT_MARK_SPECIAL 0x101 70 71 /* Definitions of arguments for argp functions. */ 72 static const struct argp_option options[] = 73 { 74 { NULL, 0, NULL, 0, N_("Output selection:"), 0 }, 75 { "debug-syms", 'a', NULL, 0, N_("Display debugger-only symbols"), 0 }, 76 { "defined-only", OPT_DEFINED, NULL, 0, N_("Display only defined symbols"), 77 0 }, 78 { "dynamic", 'D', NULL, 0, 79 N_("Display dynamic symbols instead of normal symbols"), 0 }, 80 { "extern-only", 'g', NULL, 0, N_("Display only external symbols"), 0 }, 81 { "undefined-only", 'u', NULL, 0, N_("Display only undefined symbols"), 0 }, 82 { "print-armap", 's', NULL, 0, 83 N_("Include index for symbols from archive members"), 0 }, 84 85 { NULL, 0, NULL, 0, N_("Output format:"), 0 }, 86 { "print-file-name", 'A', NULL, 0, 87 N_("Print name of the input file before every symbol"), 0 }, 88 { NULL, 'o', NULL, OPTION_HIDDEN, "Same as -A", 0 }, 89 { "format", 'f', "FORMAT", 0, 90 N_("Use the output format FORMAT. FORMAT can be `bsd', `sysv' or `posix'. The default is `sysv'"), 91 0 }, 92 { NULL, 'B', NULL, 0, N_("Same as --format=bsd"), 0 }, 93 { "portability", 'P', NULL, 0, N_("Same as --format=posix"), 0 }, 94 { "radix", 't', "RADIX", 0, N_("Use RADIX for printing symbol values"), 0 }, 95 { "mark-special", OPT_MARK_SPECIAL, NULL, 0, N_("Mark special symbols"), 0 }, 96 { "mark-weak", OPT_MARK_SPECIAL, NULL, OPTION_HIDDEN, "", 0 }, 97 { "print-size", 'S', NULL, 0, N_("Print size of defined symbols"), 0 }, 98 99 { NULL, 0, NULL, 0, N_("Output options:"), 0 }, 100 { "numeric-sort", 'n', NULL, 0, N_("Sort symbols numerically by address"), 101 0 }, 102 { "no-sort", 'p', NULL, 0, N_("Do not sort the symbols"), 0 }, 103 { "reverse-sort", 'r', NULL, 0, N_("Reverse the sense of the sort"), 0 }, 104 #ifdef USE_DEMANGLE 105 { "demangle", 'C', NULL, 0, 106 N_("Decode low-level symbol names into source code names"), 0 }, 107 #endif 108 { NULL, 0, NULL, 0, N_("Miscellaneous:"), 0 }, 109 { NULL, 0, NULL, 0, NULL, 0 } 110 }; 111 112 /* Short description of program. */ 113 static const char doc[] = N_("List symbols from FILEs (a.out by default)."); 114 115 /* Strings for arguments in help texts. */ 116 static const char args_doc[] = N_("[FILE...]"); 117 118 /* Prototype for option handler. */ 119 static error_t parse_opt (int key, char *arg, struct argp_state *state); 120 121 /* Parser children. */ 122 static struct argp_child argp_children[] = 123 { 124 { &color_argp, 0, N_("Output formatting"), 2 }, 125 { NULL, 0, NULL, 0} 126 }; 127 128 /* Data structure to communicate with argp functions. */ 129 static struct argp argp = 130 { 131 options, parse_opt, args_doc, doc, argp_children, NULL, NULL 132 }; 133 134 135 /* Print symbols in file named FNAME. */ 136 static int process_file (const char *fname, bool more_than_one); 137 138 /* Handle content of archive. */ 139 static int handle_ar (int fd, Elf *elf, const char *prefix, const char *fname, 140 const char *suffix); 141 142 /* Handle ELF file. */ 143 static int handle_elf (Elf *elf, const char *prefix, const char *fname, 144 const char *suffix); 145 146 147 #define INTERNAL_ERROR(fname) \ 148 error (EXIT_FAILURE, 0, gettext ("%s: INTERNAL ERROR %d (%s-%s): %s"), \ 149 fname, __LINE__, PACKAGE_VERSION, __DATE__, elf_errmsg (-1)) 150 151 152 /* Internal representation of symbols. */ 153 typedef struct GElf_SymX 154 { 155 GElf_Sym sym; 156 Elf32_Word xndx; 157 char *where; 158 } GElf_SymX; 159 160 161 /* User-selectable options. */ 162 163 /* The selected output format. */ 164 static enum 165 { 166 format_sysv = 0, 167 format_bsd, 168 format_posix 169 } format; 170 171 /* Print defined, undefined, or both? */ 172 static bool hide_undefined; 173 static bool hide_defined; 174 175 /* Print local symbols also? */ 176 static bool hide_local; 177 178 /* Nonzero if full filename should precede every symbol. */ 179 static bool print_file_name; 180 181 /* If true print size of defined symbols in BSD format. */ 182 static bool print_size; 183 184 /* If true print archive index. */ 185 static bool print_armap; 186 187 /* If true reverse sorting. */ 188 static bool reverse_sort; 189 190 #ifdef USE_DEMANGLE 191 /* If true demangle symbols. */ 192 static bool demangle; 193 #endif 194 195 /* Type of the section we are printing. */ 196 static GElf_Word symsec_type = SHT_SYMTAB; 197 198 /* Sorting selection. */ 199 static enum 200 { 201 sort_name = 0, 202 sort_numeric, 203 sort_nosort 204 } sort; 205 206 /* Radix for printed numbers. */ 207 static enum 208 { 209 radix_hex = 0, 210 radix_decimal, 211 radix_octal 212 } radix; 213 214 /* If nonzero mark special symbols: 215 - weak symbols are distinguished from global symbols by adding 216 a `*' after the identifying letter for the symbol class and type. 217 - TLS symbols are distinguished from normal symbols by adding 218 a '@' after the identifying letter for the symbol class and type. */ 219 static bool mark_special; 220 221 222 int 223 main (int argc, char *argv[]) 224 { 225 int remaining; 226 int result = 0; 227 228 /* Make memory leak detection possible. */ 229 mtrace (); 230 231 /* We use no threads here which can interfere with handling a stream. */ 232 (void) __fsetlocking (stdin, FSETLOCKING_BYCALLER); 233 (void) __fsetlocking (stdout, FSETLOCKING_BYCALLER); 234 (void) __fsetlocking (stderr, FSETLOCKING_BYCALLER); 235 236 /* Set locale. */ 237 (void) setlocale (LC_ALL, ""); 238 239 /* Make sure the message catalog can be found. */ 240 (void) bindtextdomain (PACKAGE_TARNAME, LOCALEDIR); 241 242 /* Initialize the message catalog. */ 243 (void) textdomain (PACKAGE_TARNAME); 244 245 /* Parse and process arguments. */ 246 (void) argp_parse (&argp, argc, argv, 0, &remaining, NULL); 247 248 /* Tell the library which version we are expecting. */ 249 (void) elf_version (EV_CURRENT); 250 251 if (remaining == argc) 252 /* The user didn't specify a name so we use a.out. */ 253 result = process_file ("a.out", false); 254 else 255 { 256 /* Process all the remaining files. */ 257 const bool more_than_one = remaining + 1 < argc; 258 259 do 260 result |= process_file (argv[remaining], more_than_one); 261 while (++remaining < argc); 262 } 263 264 return result; 265 } 266 267 268 /* Print the version information. */ 269 static void 270 print_version (FILE *stream, struct argp_state *state __attribute__ ((unused))) 271 { 272 fprintf (stream, "nm (%s) %s\n", PACKAGE_NAME, PACKAGE_VERSION); 273 fprintf (stream, gettext ("\ 274 Copyright (C) %s Red Hat, Inc.\n\ 275 This is free software; see the source for copying conditions. There is NO\n\ 276 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\ 277 "), "2012"); 278 fprintf (stream, gettext ("Written by %s.\n"), "Ulrich Drepper"); 279 } 280 281 282 /* Handle program arguments. */ 283 static error_t 284 parse_opt (int key, char *arg, 285 struct argp_state *state __attribute__ ((unused))) 286 { 287 switch (key) 288 { 289 case 'a': 290 /* XXX */ 291 break; 292 293 #ifdef USE_DEMANGLE 294 case 'C': 295 demangle = true; 296 break; 297 #endif 298 299 case 'f': 300 if (strcmp (arg, "bsd") == 0) 301 format = format_bsd; 302 else if (strcmp (arg, "posix") == 0) 303 format = format_posix; 304 else 305 /* Be bug compatible. The BFD implementation also defaulted to 306 using the SysV format if nothing else matches. */ 307 format = format_sysv; 308 break; 309 310 case 'g': 311 hide_local = true; 312 break; 313 314 case 'n': 315 sort = sort_numeric; 316 break; 317 318 case 'p': 319 sort = sort_nosort; 320 break; 321 322 case 't': 323 if (strcmp (arg, "10") == 0 || strcmp (arg, "d") == 0) 324 radix = radix_decimal; 325 else if (strcmp (arg, "8") == 0 || strcmp (arg, "o") == 0) 326 radix = radix_octal; 327 else 328 radix = radix_hex; 329 break; 330 331 case 'u': 332 hide_undefined = false; 333 hide_defined = true; 334 break; 335 336 case 'A': 337 case 'o': 338 print_file_name = true; 339 break; 340 341 case 'B': 342 format = format_bsd; 343 break; 344 345 case 'D': 346 symsec_type = SHT_DYNSYM; 347 break; 348 349 case 'P': 350 format = format_posix; 351 break; 352 353 case OPT_DEFINED: 354 hide_undefined = true; 355 hide_defined = false; 356 break; 357 358 case OPT_MARK_SPECIAL: 359 mark_special = true; 360 break; 361 362 case 'S': 363 print_size = true; 364 break; 365 366 case 's': 367 print_armap = true; 368 break; 369 370 case 'r': 371 reverse_sort = true; 372 break; 373 374 default: 375 return ARGP_ERR_UNKNOWN; 376 } 377 return 0; 378 } 379 380 381 /* Open the file and determine the type. */ 382 static int 383 process_file (const char *fname, bool more_than_one) 384 { 385 /* Open the file. */ 386 int fd = open (fname, O_RDONLY); 387 if (fd == -1) 388 { 389 error (0, errno, gettext ("cannot open '%s'"), fname); 390 return 1; 391 } 392 393 /* Now get the ELF descriptor. */ 394 Elf *elf = elf_begin (fd, ELF_C_READ_MMAP, NULL); 395 if (elf != NULL) 396 { 397 if (elf_kind (elf) == ELF_K_ELF) 398 { 399 int result = handle_elf (elf, more_than_one ? "" : NULL, 400 fname, NULL); 401 402 if (elf_end (elf) != 0) 403 INTERNAL_ERROR (fname); 404 405 if (close (fd) != 0) 406 error (EXIT_FAILURE, errno, gettext ("while closing '%s'"), fname); 407 408 return result; 409 } 410 else if (elf_kind (elf) == ELF_K_AR) 411 { 412 int result = handle_ar (fd, elf, NULL, fname, NULL); 413 414 if (elf_end (elf) != 0) 415 INTERNAL_ERROR (fname); 416 417 if (close (fd) != 0) 418 error (EXIT_FAILURE, errno, gettext ("while closing '%s'"), fname); 419 420 return result; 421 } 422 423 /* We cannot handle this type. Close the descriptor anyway. */ 424 if (elf_end (elf) != 0) 425 INTERNAL_ERROR (fname); 426 } 427 428 error (0, 0, gettext ("%s: File format not recognized"), fname); 429 430 return 1; 431 } 432 433 434 static int 435 handle_ar (int fd, Elf *elf, const char *prefix, const char *fname, 436 const char *suffix) 437 { 438 size_t fname_len = strlen (fname) + 1; 439 size_t prefix_len = prefix != NULL ? strlen (prefix) : 0; 440 char new_prefix[prefix_len + fname_len + 2]; 441 size_t suffix_len = suffix != NULL ? strlen (suffix) : 0; 442 char new_suffix[suffix_len + 2]; 443 Elf *subelf; 444 Elf_Cmd cmd = ELF_C_READ_MMAP; 445 int result = 0; 446 447 char *cp = new_prefix; 448 if (prefix != NULL) 449 cp = stpcpy (cp, prefix); 450 cp = stpcpy (cp, fname); 451 stpcpy (cp, "["); 452 453 cp = new_suffix; 454 if (suffix != NULL) 455 cp = stpcpy (cp, suffix); 456 stpcpy (cp, "]"); 457 458 /* First print the archive index if this is wanted. */ 459 if (print_armap) 460 { 461 Elf_Arsym *arsym = elf_getarsym (elf, NULL); 462 463 if (arsym != NULL) 464 { 465 Elf_Arhdr *arhdr = NULL; 466 size_t arhdr_off = 0; /* Note: 0 is no valid offset. */ 467 468 fputs_unlocked (gettext("\nArchive index:\n"), stdout); 469 470 while (arsym->as_off != 0) 471 { 472 if (arhdr_off != arsym->as_off 473 && (elf_rand (elf, arsym->as_off) != arsym->as_off 474 || (subelf = elf_begin (fd, cmd, elf)) == NULL 475 || (arhdr = elf_getarhdr (subelf)) == NULL)) 476 { 477 error (0, 0, gettext ("invalid offset %zu for symbol %s"), 478 arsym->as_off, arsym->as_name); 479 continue; 480 } 481 482 printf (gettext ("%s in %s\n"), arsym->as_name, arhdr->ar_name); 483 484 ++arsym; 485 } 486 487 if (elf_rand (elf, SARMAG) != SARMAG) 488 { 489 error (0, 0, 490 gettext ("cannot reset archive offset to beginning")); 491 return 1; 492 } 493 } 494 } 495 496 /* Process all the files contained in the archive. */ 497 while ((subelf = elf_begin (fd, cmd, elf)) != NULL) 498 { 499 /* The the header for this element. */ 500 Elf_Arhdr *arhdr = elf_getarhdr (subelf); 501 502 /* Skip over the index entries. */ 503 if (strcmp (arhdr->ar_name, "/") != 0 504 && strcmp (arhdr->ar_name, "//") != 0) 505 { 506 if (elf_kind (subelf) == ELF_K_ELF) 507 result |= handle_elf (subelf, new_prefix, arhdr->ar_name, 508 new_suffix); 509 else if (elf_kind (subelf) == ELF_K_AR) 510 result |= handle_ar (fd, subelf, new_prefix, arhdr->ar_name, 511 new_suffix); 512 else 513 { 514 error (0, 0, gettext ("%s%s%s: file format not recognized"), 515 new_prefix, arhdr->ar_name, new_suffix); 516 result = 1; 517 } 518 } 519 520 /* Get next archive element. */ 521 cmd = elf_next (subelf); 522 if (elf_end (subelf) != 0) 523 INTERNAL_ERROR (fname); 524 } 525 526 return result; 527 } 528 529 530 /* Mapping of radix and binary class to length. */ 531 static const int length_map[2][3] = 532 { 533 [ELFCLASS32 - 1] = 534 { 535 [radix_hex] = 8, 536 [radix_decimal] = 10, 537 [radix_octal] = 11 538 }, 539 [ELFCLASS64 - 1] = 540 { 541 [radix_hex] = 16, 542 [radix_decimal] = 20, 543 [radix_octal] = 22 544 } 545 }; 546 547 548 static int 549 global_compare (const void *p1, const void *p2) 550 { 551 const Dwarf_Global *g1 = (const Dwarf_Global *) p1; 552 const Dwarf_Global *g2 = (const Dwarf_Global *) p2; 553 554 return strcmp (g1->name, g2->name); 555 } 556 557 558 static void *global_root; 559 560 561 static int 562 get_global (Dwarf *dbg __attribute__ ((unused)), Dwarf_Global *global, 563 void *arg __attribute__ ((unused))) 564 { 565 tsearch (memcpy (xmalloc (sizeof (Dwarf_Global)), global, 566 sizeof (Dwarf_Global)), 567 &global_root, global_compare); 568 569 return DWARF_CB_OK; 570 } 571 572 573 struct local_name 574 { 575 const char *name; 576 const char *file; 577 Dwarf_Word lineno; 578 Dwarf_Addr lowpc; 579 Dwarf_Addr highpc; 580 }; 581 582 583 static int 584 local_compare (const void *p1, const void *p2) 585 { 586 struct local_name *g1 = (struct local_name *) p1; 587 struct local_name *g2 = (struct local_name *) p2; 588 int result; 589 590 result = strcmp (g1->name, g2->name); 591 if (result == 0) 592 { 593 if (g1->lowpc <= g2->lowpc && g1->highpc >= g2->highpc) 594 { 595 /* g2 is contained in g1. Update the data. */ 596 g2->lowpc = g1->lowpc; 597 g2->highpc = g1->highpc; 598 result = 0; 599 } 600 else if (g2->lowpc <= g1->lowpc && g2->highpc >= g1->highpc) 601 { 602 /* g1 is contained in g2. Update the data. */ 603 g1->lowpc = g2->lowpc; 604 g1->highpc = g2->highpc; 605 result = 0; 606 } 607 else 608 result = g1->lowpc < g2->lowpc ? -1 : 1; 609 } 610 611 return result; 612 } 613 614 615 static int 616 get_var_range (Dwarf_Die *die, Dwarf_Word *lowpc, Dwarf_Word *highpc) 617 { 618 Dwarf_Attribute locattr_mem; 619 Dwarf_Attribute *locattr = dwarf_attr (die, DW_AT_location, &locattr_mem); 620 if (locattr == NULL) 621 return 1; 622 623 Dwarf_Op *loc; 624 size_t nloc; 625 if (dwarf_getlocation (locattr, &loc, &nloc) != 0) 626 return 1; 627 628 /* Interpret the location expressions. */ 629 // XXX For now just the simple one: 630 if (nloc == 1 && loc[0].atom == DW_OP_addr) 631 { 632 *lowpc = *highpc = loc[0].number; 633 return 0; 634 } 635 636 return 1; 637 } 638 639 640 641 static void *local_root; 642 643 644 static void 645 get_local_names (Dwarf *dbg) 646 { 647 Dwarf_Off offset = 0; 648 Dwarf_Off old_offset; 649 size_t hsize; 650 651 while (dwarf_nextcu (dbg, old_offset = offset, &offset, &hsize, NULL, NULL, 652 NULL) == 0) 653 { 654 Dwarf_Die cudie_mem; 655 Dwarf_Die *cudie = dwarf_offdie (dbg, old_offset + hsize, &cudie_mem); 656 657 /* If we cannot get the CU DIE there is no need to go on with 658 this CU. */ 659 if (cudie == NULL) 660 continue; 661 /* This better be a CU DIE. */ 662 if (dwarf_tag (cudie) != DW_TAG_compile_unit) 663 continue; 664 665 /* Get the line information. */ 666 Dwarf_Files *files; 667 size_t nfiles; 668 if (dwarf_getsrcfiles (cudie, &files, &nfiles) != 0) 669 continue; 670 671 Dwarf_Die die_mem; 672 Dwarf_Die *die = &die_mem; 673 if (dwarf_child (cudie, die) == 0) 674 /* Iterate over all immediate children of the CU DIE. */ 675 do 676 { 677 int tag = dwarf_tag (die); 678 if (tag != DW_TAG_subprogram && tag != DW_TAG_variable) 679 continue; 680 681 /* We are interested in five attributes: name, decl_file, 682 decl_line, low_pc, and high_pc. */ 683 Dwarf_Attribute attr_mem; 684 Dwarf_Attribute *attr = dwarf_attr (die, DW_AT_name, &attr_mem); 685 const char *name = dwarf_formstring (attr); 686 if (name == NULL) 687 continue; 688 689 Dwarf_Word fileidx; 690 attr = dwarf_attr (die, DW_AT_decl_file, &attr_mem); 691 if (dwarf_formudata (attr, &fileidx) != 0 || fileidx >= nfiles) 692 continue; 693 694 Dwarf_Word lineno; 695 attr = dwarf_attr (die, DW_AT_decl_line, &attr_mem); 696 if (dwarf_formudata (attr, &lineno) != 0 || lineno == 0) 697 continue; 698 699 Dwarf_Addr lowpc; 700 Dwarf_Addr highpc; 701 if (tag == DW_TAG_subprogram) 702 { 703 if (dwarf_lowpc (die, &lowpc) != 0 704 || dwarf_highpc (die, &highpc) != 0) 705 continue; 706 } 707 else 708 { 709 if (get_var_range (die, &lowpc, &highpc) != 0) 710 continue; 711 } 712 713 /* We have all the information. Create a record. */ 714 struct local_name *newp 715 = (struct local_name *) xmalloc (sizeof (*newp)); 716 newp->name = name; 717 newp->file = dwarf_filesrc (files, fileidx, NULL, NULL); 718 newp->lineno = lineno; 719 newp->lowpc = lowpc; 720 newp->highpc = highpc; 721 722 /* Since we cannot deallocate individual memory we do not test 723 for duplicates in the tree. This should not happen anyway. */ 724 if (tsearch (newp, &local_root, local_compare) == NULL) 725 error (EXIT_FAILURE, errno, 726 gettext ("cannot create search tree")); 727 } 728 while (dwarf_siblingof (die, die) == 0); 729 } 730 } 731 732 /* Do elf_strptr, but return a backup string and never NULL. */ 733 static const char * 734 sym_name (Elf *elf, GElf_Word strndx, GElf_Word st_name, char buf[], size_t n) 735 { 736 const char *symstr = elf_strptr (elf, strndx, st_name); 737 if (symstr == NULL) 738 { 739 snprintf (buf, n, "[invalid st_name %#" PRIx32 "]", st_name); 740 symstr = buf; 741 } 742 return symstr; 743 } 744 745 /* Show symbols in SysV format. */ 746 static void 747 show_symbols_sysv (Ebl *ebl, GElf_Word strndx, const char *fullname, 748 GElf_SymX *syms, size_t nsyms, int longest_name, 749 int longest_where) 750 { 751 size_t shnum; 752 if (elf_getshdrnum (ebl->elf, &shnum) < 0) 753 INTERNAL_ERROR (fullname); 754 755 bool scnnames_malloced = shnum * sizeof (const char *) > 128 * 1024; 756 const char **scnnames; 757 if (scnnames_malloced) 758 scnnames = (const char **) xmalloc (sizeof (const char *) * shnum); 759 else 760 scnnames = (const char **) alloca (sizeof (const char *) * shnum); 761 /* Get the section header string table index. */ 762 size_t shstrndx; 763 if (elf_getshdrstrndx (ebl->elf, &shstrndx) < 0) 764 error (EXIT_FAILURE, 0, 765 gettext ("cannot get section header string table index")); 766 767 /* Cache the section names. */ 768 Elf_Scn *scn = NULL; 769 size_t cnt = 1; 770 while ((scn = elf_nextscn (ebl->elf, scn)) != NULL) 771 { 772 GElf_Shdr shdr_mem; 773 774 assert (elf_ndxscn (scn) == cnt++); 775 776 char *name = elf_strptr (ebl->elf, shstrndx, 777 gelf_getshdr (scn, &shdr_mem)->sh_name); 778 if (unlikely (name == NULL)) 779 { 780 name = alloca (sizeof "[invalid sh_name 0x12345678]"); 781 snprintf (name, sizeof name, "[invalid sh_name %#" PRIx32 "]", 782 gelf_getshdr (scn, &shdr_mem)->sh_name); 783 } 784 scnnames[elf_ndxscn (scn)] = name; 785 } 786 787 int digits = length_map[gelf_getclass (ebl->elf) - 1][radix]; 788 789 /* We always print this prolog. */ 790 printf (gettext ("\n\nSymbols from %s:\n\n"), fullname); 791 792 /* The header line. */ 793 printf (gettext ("%*s%-*s %-*s Class Type %-*s %*s Section\n\n"), 794 print_file_name ? (int) strlen (fullname) + 1: 0, "", 795 longest_name, sgettext ("sysv|Name"), 796 /* TRANS: the "sysv|" parts makes the string unique. */ 797 digits, sgettext ("sysv|Value"), 798 /* TRANS: the "sysv|" parts makes the string unique. */ 799 digits, sgettext ("sysv|Size"), 800 /* TRANS: the "sysv|" parts makes the string unique. */ 801 longest_where, sgettext ("sysv|Line")); 802 803 /* Which format string to use (different radix for numbers). */ 804 const char *number_fmtstr; 805 if (radix == radix_hex) 806 number_fmtstr = "%0*" PRIx64; 807 else if (radix == radix_decimal) 808 number_fmtstr = "%0*" PRId64; 809 else 810 number_fmtstr = "%0*" PRIo64; 811 812 #ifdef USE_DEMANGLE 813 size_t demangle_buffer_len = 0; 814 char *demangle_buffer = NULL; 815 #endif 816 817 /* Iterate over all symbols. */ 818 for (cnt = 1; cnt < nsyms; ++cnt) 819 { 820 /* In this format SECTION entries are not printed. */ 821 if (GELF_ST_TYPE (syms[cnt].sym.st_info) == STT_SECTION) 822 continue; 823 824 char symstrbuf[50]; 825 const char *symstr = sym_name (ebl->elf, strndx, syms[cnt].sym.st_name, 826 symstrbuf, sizeof symstrbuf); 827 828 #ifdef USE_DEMANGLE 829 /* Demangle if necessary. */ 830 if (demangle) 831 { 832 int status = -1; 833 char *dmsymstr = __cxa_demangle (symstr, demangle_buffer, 834 &demangle_buffer_len, &status); 835 836 if (status == 0) 837 symstr = dmsymstr; 838 } 839 #endif 840 841 char symbindbuf[50]; 842 char symtypebuf[50]; 843 char secnamebuf[1024]; 844 char addressbuf[(64 + 2) / 3 + 1]; 845 char sizebuf[(64 + 2) / 3 + 1]; 846 847 /* If we have to precede the line with the file name. */ 848 if (print_file_name) 849 { 850 fputs_unlocked (fullname, stdout); 851 putchar_unlocked (':'); 852 } 853 854 /* Covert the address. */ 855 if (syms[cnt].sym.st_shndx == SHN_UNDEF) 856 addressbuf[0] = sizebuf[0] = '\0'; 857 else 858 { 859 snprintf (addressbuf, sizeof (addressbuf), number_fmtstr, 860 digits, syms[cnt].sym.st_value); 861 snprintf (sizebuf, sizeof (sizebuf), number_fmtstr, 862 digits, syms[cnt].sym.st_size); 863 } 864 865 /* Print the actual string. */ 866 printf ("%-*s|%s|%-6s|%-8s|%s|%*s|%s\n", 867 longest_name, symstr, addressbuf, 868 ebl_symbol_binding_name (ebl, 869 GELF_ST_BIND (syms[cnt].sym.st_info), 870 symbindbuf, sizeof (symbindbuf)), 871 ebl_symbol_type_name (ebl, GELF_ST_TYPE (syms[cnt].sym.st_info), 872 symtypebuf, sizeof (symtypebuf)), 873 sizebuf, longest_where, syms[cnt].where, 874 ebl_section_name (ebl, syms[cnt].sym.st_shndx, syms[cnt].xndx, 875 secnamebuf, sizeof (secnamebuf), scnnames, 876 shnum)); 877 } 878 879 #ifdef USE_DEMANGLE 880 free (demangle_buffer); 881 #endif 882 883 if (scnnames_malloced) 884 free (scnnames); 885 } 886 887 888 static char 889 class_type_char (Elf *elf, const GElf_Ehdr *ehdr, GElf_Sym *sym) 890 { 891 int local_p = GELF_ST_BIND (sym->st_info) == STB_LOCAL; 892 893 /* XXX Add support for architecture specific types and classes. */ 894 if (sym->st_shndx == SHN_ABS) 895 return local_p ? 'a' : 'A'; 896 897 if (sym->st_shndx == SHN_UNDEF) 898 /* Undefined symbols must be global. */ 899 return 'U'; 900 901 char result = "NDTSFBD "[GELF_ST_TYPE (sym->st_info)]; 902 903 if (result == 'D') 904 { 905 /* Special handling: unique data symbols. */ 906 if (ehdr->e_ident[EI_OSABI] == ELFOSABI_LINUX 907 && GELF_ST_BIND (sym->st_info) == STB_GNU_UNIQUE) 908 result = 'u'; 909 else 910 { 911 GElf_Shdr shdr_mem; 912 GElf_Shdr *shdr = gelf_getshdr (elf_getscn (elf, sym->st_shndx), 913 &shdr_mem); 914 if (shdr != NULL) 915 { 916 if ((shdr->sh_flags & SHF_WRITE) == 0) 917 result = 'R'; 918 else if (shdr->sh_type == SHT_NOBITS) 919 result = 'B'; 920 } 921 } 922 } 923 924 return local_p ? tolower (result) : result; 925 } 926 927 928 static void 929 show_symbols_bsd (Elf *elf, const GElf_Ehdr *ehdr, GElf_Word strndx, 930 const char *prefix, const char *fname, const char *fullname, 931 GElf_SymX *syms, size_t nsyms) 932 { 933 int digits = length_map[gelf_getclass (elf) - 1][radix]; 934 935 if (prefix != NULL && ! print_file_name) 936 printf ("\n%s:\n", fname); 937 938 static const char *const fmtstrs[] = 939 { 940 [radix_hex] = "%8$s%2$0*1$" PRIx64 "%10$s %9$s%3$c%4$s %5$s", 941 [radix_decimal] = "%8$s%*" PRId64 "%10$s %9$s%3$c%4$s %5$s", 942 [radix_octal] = "%8$s%2$0*1$" PRIo64 "%10$s %9$s%3$c%4$s %5$s" 943 }; 944 static const char *const sfmtstrs[] = 945 { 946 [radix_hex] = "%8$s%2$0*1$" PRIx64 "%10$s %7$0*6$" PRIx64 " %9$s%3$c%4$s %5$s", 947 [radix_decimal] = "%8$s%2$*1$" PRId64 "%10$s %7$*6$" PRId64 " %9$s%3$c%4$s %5$s", 948 [radix_octal] = "%8$s%2$0*1$" PRIo64 "%10$s %7$0*6$" PRIo64 " %9$s%3$c%4$s %5$s" 949 }; 950 951 #ifdef USE_DEMANGLE 952 size_t demangle_buffer_len = 0; 953 char *demangle_buffer = NULL; 954 #endif 955 956 /* Iterate over all symbols. */ 957 for (size_t cnt = 0; cnt < nsyms; ++cnt) 958 { 959 char symstrbuf[50]; 960 const char *symstr = sym_name (elf, strndx, syms[cnt].sym.st_name, 961 symstrbuf, sizeof symstrbuf); 962 963 /* Printing entries with a zero-length name makes the output 964 not very well parseable. Since these entries don't carry 965 much information we leave them out. */ 966 if (symstr[0] == '\0') 967 continue; 968 969 /* We do not print the entries for files. */ 970 if (GELF_ST_TYPE (syms[cnt].sym.st_info) == STT_FILE) 971 continue; 972 973 #ifdef USE_DEMANGLE 974 /* Demangle if necessary. */ 975 if (demangle) 976 { 977 int status = -1; 978 char *dmsymstr = __cxa_demangle (symstr, demangle_buffer, 979 &demangle_buffer_len, &status); 980 981 if (status == 0) 982 symstr = dmsymstr; 983 } 984 #endif 985 986 /* If we have to precede the line with the file name. */ 987 if (print_file_name) 988 { 989 fputs_unlocked (fullname, stdout); 990 putchar_unlocked (':'); 991 } 992 993 bool is_tls = GELF_ST_TYPE (syms[cnt].sym.st_info) == STT_TLS; 994 bool is_weak = GELF_ST_BIND (syms[cnt].sym.st_info) == STB_WEAK; 995 const char *marker = (mark_special 996 ? (is_tls ? "@" : (is_weak ? "*" : " ")) : ""); 997 998 if (syms[cnt].sym.st_shndx == SHN_UNDEF) 999 { 1000 const char *color = ""; 1001 if (color_mode) 1002 { 1003 if (is_tls) 1004 color = color_undef_tls; 1005 else if (is_weak) 1006 color = color_undef_weak; 1007 else 1008 color = color_undef; 1009 } 1010 1011 printf ("%*s %sU%s %s", digits, "", color, marker, symstr); 1012 } 1013 else 1014 { 1015 const char *color = ""; 1016 if (color_mode) 1017 { 1018 if (is_tls) 1019 color = color_tls; 1020 else if (is_weak) 1021 color = color_weak; 1022 else 1023 color = color_symbol; 1024 } 1025 1026 printf (print_size && syms[cnt].sym.st_size != 0 1027 ? sfmtstrs[radix] : fmtstrs[radix], 1028 digits, syms[cnt].sym.st_value, 1029 class_type_char (elf, ehdr, &syms[cnt].sym), marker, 1030 symstr, 1031 digits, (uint64_t) syms[cnt].sym.st_size, 1032 color_mode ? color_address : "", 1033 color, 1034 color_mode ? color_off : ""); 1035 } 1036 1037 if (color_mode) 1038 fputs_unlocked (color_off, stdout); 1039 putchar_unlocked ('\n'); 1040 } 1041 1042 #ifdef USE_DEMANGLE 1043 free (demangle_buffer); 1044 #endif 1045 } 1046 1047 1048 static void 1049 show_symbols_posix (Elf *elf, const GElf_Ehdr *ehdr, GElf_Word strndx, 1050 const char *prefix, const char *fullname, GElf_SymX *syms, 1051 size_t nsyms) 1052 { 1053 if (prefix != NULL && ! print_file_name) 1054 printf ("%s:\n", fullname); 1055 1056 const char *fmtstr; 1057 if (radix == radix_hex) 1058 fmtstr = "%s %c%s %0*" PRIx64 " %0*" PRIx64 "\n"; 1059 else if (radix == radix_decimal) 1060 fmtstr = "%s %c%s %*" PRId64 " %*" PRId64 "\n"; 1061 else 1062 fmtstr = "%s %c%s %0*" PRIo64 " %0*" PRIo64 "\n"; 1063 1064 int digits = length_map[gelf_getclass (elf) - 1][radix]; 1065 1066 #ifdef USE_DEMANGLE 1067 size_t demangle_buffer_len = 0; 1068 char *demangle_buffer = NULL; 1069 #endif 1070 1071 /* Iterate over all symbols. */ 1072 for (size_t cnt = 0; cnt < nsyms; ++cnt) 1073 { 1074 char symstrbuf[50]; 1075 const char *symstr = sym_name (elf, strndx, syms[cnt].sym.st_name, 1076 symstrbuf, sizeof symstrbuf); 1077 1078 /* Printing entries with a zero-length name makes the output 1079 not very well parseable. Since these entries don't carry 1080 much information we leave them out. */ 1081 if (symstr[0] == '\0') 1082 continue; 1083 1084 #ifdef USE_DEMANGLE 1085 /* Demangle if necessary. */ 1086 if (demangle) 1087 { 1088 int status = -1; 1089 char *dmsymstr = __cxa_demangle (symstr, demangle_buffer, 1090 &demangle_buffer_len, &status); 1091 1092 if (status == 0) 1093 symstr = dmsymstr; 1094 } 1095 #endif 1096 1097 /* If we have to precede the line with the file name. */ 1098 if (print_file_name) 1099 { 1100 fputs_unlocked (fullname, stdout); 1101 putchar_unlocked (':'); 1102 putchar_unlocked (' '); 1103 } 1104 1105 printf (fmtstr, 1106 symstr, 1107 class_type_char (elf, ehdr, &syms[cnt].sym), 1108 mark_special 1109 ? (GELF_ST_TYPE (syms[cnt].sym.st_info) == STT_TLS 1110 ? "@" 1111 : (GELF_ST_BIND (syms[cnt].sym.st_info) == STB_WEAK 1112 ? "*" : " ")) 1113 : "", 1114 digits, syms[cnt].sym.st_value, 1115 digits, syms[cnt].sym.st_size); 1116 } 1117 1118 #ifdef USE_DEMANGLE 1119 free (demangle_buffer); 1120 #endif 1121 } 1122 1123 1124 /* Maximum size of memory we allocate on the stack. */ 1125 #define MAX_STACK_ALLOC 65536 1126 1127 static int 1128 sort_by_address (const void *p1, const void *p2) 1129 { 1130 GElf_SymX *s1 = (GElf_SymX *) p1; 1131 GElf_SymX *s2 = (GElf_SymX *) p2; 1132 1133 int result = (s1->sym.st_value < s2->sym.st_value 1134 ? -1 : (s1->sym.st_value == s2->sym.st_value ? 0 : 1)); 1135 1136 return reverse_sort ? -result : result; 1137 } 1138 1139 static Elf_Data *sort_by_name_strtab; 1140 1141 static int 1142 sort_by_name (const void *p1, const void *p2) 1143 { 1144 GElf_SymX *s1 = (GElf_SymX *) p1; 1145 GElf_SymX *s2 = (GElf_SymX *) p2; 1146 1147 const char *n1 = sort_by_name_strtab->d_buf + s1->sym.st_name; 1148 const char *n2 = sort_by_name_strtab->d_buf + s2->sym.st_name; 1149 1150 int result = strcmp (n1, n2); 1151 1152 return reverse_sort ? -result : result; 1153 } 1154 1155 static void 1156 show_symbols (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, Elf_Scn *xndxscn, 1157 GElf_Shdr *shdr, const char *prefix, const char *fname, 1158 const char *fullname) 1159 { 1160 /* Get the section header string table index. */ 1161 size_t shstrndx; 1162 if (elf_getshdrstrndx (ebl->elf, &shstrndx) < 0) 1163 error (EXIT_FAILURE, 0, 1164 gettext ("cannot get section header string table index")); 1165 1166 /* The section is that large. */ 1167 size_t size = shdr->sh_size; 1168 /* One entry is this large. */ 1169 size_t entsize = shdr->sh_entsize; 1170 1171 /* Consistency checks. */ 1172 if (entsize != gelf_fsize (ebl->elf, ELF_T_SYM, 1, ehdr->e_version)) 1173 error (0, 0, 1174 gettext ("%s: entry size in section `%s' is not what we expect"), 1175 fullname, elf_strptr (ebl->elf, shstrndx, shdr->sh_name)); 1176 else if (size % entsize != 0) 1177 error (0, 0, 1178 gettext ("%s: size of section `%s' is not multiple of entry size"), 1179 fullname, elf_strptr (ebl->elf, shstrndx, shdr->sh_name)); 1180 1181 /* Compute number of entries. Handle buggy entsize values. */ 1182 size_t nentries = size / (entsize ?: 1); 1183 1184 1185 #define obstack_chunk_alloc xmalloc 1186 #define obstack_chunk_free free 1187 struct obstack whereob; 1188 obstack_init (&whereob); 1189 1190 /* Get a DWARF debugging descriptor. It's no problem if this isn't 1191 possible. We just won't print any line number information. */ 1192 Dwarf *dbg = NULL; 1193 if (format == format_sysv) 1194 { 1195 dbg = dwarf_begin_elf (ebl->elf, DWARF_C_READ, NULL); 1196 if (dbg != NULL) 1197 { 1198 (void) dwarf_getpubnames (dbg, get_global, NULL, 0); 1199 1200 get_local_names (dbg); 1201 } 1202 } 1203 1204 /* Allocate the memory. 1205 1206 XXX We can use a dirty trick here. Since GElf_Sym == Elf64_Sym we 1207 can use the data memory instead of copying again if what we read 1208 is a 64 bit file. */ 1209 GElf_SymX *sym_mem; 1210 if (nentries * sizeof (GElf_SymX) < MAX_STACK_ALLOC) 1211 sym_mem = (GElf_SymX *) alloca (nentries * sizeof (GElf_SymX)); 1212 else 1213 sym_mem = (GElf_SymX *) xmalloc (nentries * sizeof (GElf_SymX)); 1214 1215 /* Get the data of the section. */ 1216 Elf_Data *data = elf_getdata (scn, NULL); 1217 Elf_Data *xndxdata = elf_getdata (xndxscn, NULL); 1218 if (data == NULL || (xndxscn != NULL && xndxdata == NULL)) 1219 INTERNAL_ERROR (fullname); 1220 1221 /* Iterate over all symbols. */ 1222 #ifdef USE_DEMANGLE 1223 size_t demangle_buffer_len = 0; 1224 char *demangle_buffer = NULL; 1225 #endif 1226 int longest_name = 4; 1227 int longest_where = 4; 1228 size_t nentries_used = 0; 1229 for (size_t cnt = 0; cnt < nentries; ++cnt) 1230 { 1231 GElf_Sym *sym = gelf_getsymshndx (data, xndxdata, cnt, 1232 &sym_mem[nentries_used].sym, 1233 &sym_mem[nentries_used].xndx); 1234 if (sym == NULL) 1235 INTERNAL_ERROR (fullname); 1236 1237 /* Filter out administrative symbols without a name and those 1238 deselected by the user with command line options. */ 1239 if ((hide_undefined && sym->st_shndx == SHN_UNDEF) 1240 || (hide_defined && sym->st_shndx != SHN_UNDEF) 1241 || (hide_local && GELF_ST_BIND (sym->st_info) == STB_LOCAL)) 1242 continue; 1243 1244 sym_mem[nentries_used].where = ""; 1245 if (format == format_sysv) 1246 { 1247 const char *symstr = elf_strptr (ebl->elf, shdr->sh_link, 1248 sym->st_name); 1249 if (symstr == NULL) 1250 continue; 1251 1252 #ifdef USE_DEMANGLE 1253 /* Demangle if necessary. */ 1254 if (demangle) 1255 { 1256 int status = -1; 1257 char *dmsymstr = __cxa_demangle (symstr, demangle_buffer, 1258 &demangle_buffer_len, &status); 1259 1260 if (status == 0) 1261 symstr = dmsymstr; 1262 } 1263 #endif 1264 1265 longest_name = MAX ((size_t) longest_name, strlen (symstr)); 1266 1267 if (sym->st_shndx != SHN_UNDEF 1268 && GELF_ST_BIND (sym->st_info) != STB_LOCAL 1269 && global_root != NULL) 1270 { 1271 Dwarf_Global fake = { .name = symstr }; 1272 Dwarf_Global **found = tfind (&fake, &global_root, 1273 global_compare); 1274 if (found != NULL) 1275 { 1276 Dwarf_Die die_mem; 1277 Dwarf_Die *die = dwarf_offdie (dbg, (*found)->die_offset, 1278 &die_mem); 1279 1280 Dwarf_Die cudie_mem; 1281 Dwarf_Die *cudie = NULL; 1282 1283 Dwarf_Addr lowpc; 1284 Dwarf_Addr highpc; 1285 if (die != NULL 1286 && dwarf_lowpc (die, &lowpc) == 0 1287 && lowpc <= sym->st_value 1288 && dwarf_highpc (die, &highpc) == 0 1289 && highpc > sym->st_value) 1290 cudie = dwarf_offdie (dbg, (*found)->cu_offset, 1291 &cudie_mem); 1292 if (cudie != NULL) 1293 { 1294 Dwarf_Line *line = dwarf_getsrc_die (cudie, 1295 sym->st_value); 1296 if (line != NULL) 1297 { 1298 /* We found the line. */ 1299 int lineno; 1300 (void) dwarf_lineno (line, &lineno); 1301 int n; 1302 n = obstack_printf (&whereob, "%s:%d%c", 1303 basename (dwarf_linesrc (line, 1304 NULL, 1305 NULL)), 1306 lineno, '\0'); 1307 sym_mem[nentries_used].where 1308 = obstack_finish (&whereob); 1309 1310 /* The return value of obstack_print included the 1311 NUL byte, so subtract one. */ 1312 if (--n > (int) longest_where) 1313 longest_where = (size_t) n; 1314 } 1315 } 1316 } 1317 } 1318 1319 /* Try to find the symbol among the local symbols. */ 1320 if (sym_mem[nentries_used].where[0] == '\0') 1321 { 1322 struct local_name fake = 1323 { 1324 .name = symstr, 1325 .lowpc = sym->st_value, 1326 .highpc = sym->st_value, 1327 }; 1328 struct local_name **found = tfind (&fake, &local_root, 1329 local_compare); 1330 if (found != NULL) 1331 { 1332 /* We found the line. */ 1333 int n = obstack_printf (&whereob, "%s:%" PRIu64 "%c", 1334 basename ((*found)->file), 1335 (*found)->lineno, 1336 '\0'); 1337 sym_mem[nentries_used].where = obstack_finish (&whereob); 1338 1339 /* The return value of obstack_print included the 1340 NUL byte, so subtract one. */ 1341 if (--n > (int) longest_where) 1342 longest_where = (size_t) n; 1343 } 1344 } 1345 } 1346 1347 /* We use this entry. */ 1348 ++nentries_used; 1349 } 1350 #ifdef USE_DEMANGLE 1351 free (demangle_buffer); 1352 #endif 1353 /* Now we know the exact number. */ 1354 nentries = nentries_used; 1355 1356 /* Sort the entries according to the users wishes. */ 1357 if (sort == sort_name) 1358 { 1359 sort_by_name_strtab = elf_getdata (elf_getscn (ebl->elf, shdr->sh_link), 1360 NULL); 1361 qsort (sym_mem, nentries, sizeof (GElf_SymX), sort_by_name); 1362 } 1363 else if (sort == sort_numeric) 1364 qsort (sym_mem, nentries, sizeof (GElf_SymX), sort_by_address); 1365 1366 /* Finally print according to the users selection. */ 1367 switch (format) 1368 { 1369 case format_sysv: 1370 show_symbols_sysv (ebl, shdr->sh_link, fullname, sym_mem, nentries, 1371 longest_name, longest_where); 1372 break; 1373 1374 case format_bsd: 1375 show_symbols_bsd (ebl->elf, ehdr, shdr->sh_link, prefix, fname, fullname, 1376 sym_mem, nentries); 1377 break; 1378 1379 case format_posix: 1380 default: 1381 assert (format == format_posix); 1382 show_symbols_posix (ebl->elf, ehdr, shdr->sh_link, prefix, fullname, 1383 sym_mem, nentries); 1384 break; 1385 } 1386 1387 /* Free all memory. */ 1388 if (nentries * sizeof (GElf_Sym) >= MAX_STACK_ALLOC) 1389 free (sym_mem); 1390 1391 obstack_free (&whereob, NULL); 1392 1393 if (dbg != NULL) 1394 { 1395 tdestroy (global_root, free); 1396 global_root = NULL; 1397 1398 tdestroy (local_root, free); 1399 local_root = NULL; 1400 1401 (void) dwarf_end (dbg); 1402 } 1403 } 1404 1405 1406 static int 1407 handle_elf (Elf *elf, const char *prefix, const char *fname, 1408 const char *suffix) 1409 { 1410 size_t prefix_len = prefix == NULL ? 0 : strlen (prefix); 1411 size_t suffix_len = suffix == NULL ? 0 : strlen (suffix); 1412 size_t fname_len = strlen (fname) + 1; 1413 char fullname[prefix_len + 1 + fname_len + suffix_len]; 1414 char *cp = fullname; 1415 Elf_Scn *scn = NULL; 1416 int any = 0; 1417 int result = 0; 1418 GElf_Ehdr ehdr_mem; 1419 GElf_Ehdr *ehdr; 1420 Ebl *ebl; 1421 1422 /* Get the backend for this object file type. */ 1423 ebl = ebl_openbackend (elf); 1424 1425 /* We need the ELF header in a few places. */ 1426 ehdr = gelf_getehdr (elf, &ehdr_mem); 1427 if (ehdr == NULL) 1428 INTERNAL_ERROR (fullname); 1429 1430 /* If we are asked to print the dynamic symbol table and this is 1431 executable or dynamic executable, fail. */ 1432 if (symsec_type == SHT_DYNSYM 1433 && ehdr->e_type != ET_EXEC && ehdr->e_type != ET_DYN) 1434 { 1435 /* XXX Add machine specific object file types. */ 1436 error (0, 0, gettext ("%s%s%s%s: Invalid operation"), 1437 prefix ?: "", prefix ? "(" : "", fname, prefix ? ")" : ""); 1438 result = 1; 1439 goto out; 1440 } 1441 1442 /* Create the full name of the file. */ 1443 if (prefix != NULL) 1444 cp = mempcpy (cp, prefix, prefix_len); 1445 cp = mempcpy (cp, fname, fname_len); 1446 if (suffix != NULL) 1447 memcpy (cp - 1, suffix, suffix_len + 1); 1448 1449 /* Find the symbol table. 1450 1451 XXX Can there be more than one? Do we print all? Currently we do. */ 1452 while ((scn = elf_nextscn (elf, scn)) != NULL) 1453 { 1454 GElf_Shdr shdr_mem; 1455 GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); 1456 1457 if (shdr == NULL) 1458 INTERNAL_ERROR (fullname); 1459 1460 if (shdr->sh_type == symsec_type) 1461 { 1462 Elf_Scn *xndxscn = NULL; 1463 1464 /* We have a symbol table. First make sure we remember this. */ 1465 any = 1; 1466 1467 /* Look for an extended section index table for this section. */ 1468 if (symsec_type == SHT_SYMTAB) 1469 { 1470 size_t scnndx = elf_ndxscn (scn); 1471 1472 while ((xndxscn = elf_nextscn (elf, xndxscn)) != NULL) 1473 { 1474 GElf_Shdr xndxshdr_mem; 1475 GElf_Shdr *xndxshdr = gelf_getshdr (xndxscn, &xndxshdr_mem); 1476 1477 if (xndxshdr == NULL) 1478 INTERNAL_ERROR (fullname); 1479 1480 if (xndxshdr->sh_type == SHT_SYMTAB_SHNDX 1481 && xndxshdr->sh_link == scnndx) 1482 break; 1483 } 1484 } 1485 1486 show_symbols (ebl, ehdr, scn, xndxscn, shdr, prefix, fname, 1487 fullname); 1488 } 1489 } 1490 1491 if (! any) 1492 { 1493 error (0, 0, gettext ("%s%s%s: no symbols"), 1494 prefix ?: "", prefix ? ":" : "", fname); 1495 result = 1; 1496 } 1497 1498 out: 1499 /* Close the ELF backend library descriptor. */ 1500 ebl_closebackend (ebl); 1501 1502 return result; 1503 } 1504 1505 1506 #include "debugpred.h" 1507