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