1/*- 2 * Copyright (c) 2007 Hyogeol Lee <hyogeollee@gmail.com> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer 10 * in this position and unchanged. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27#include <sys/queue.h> 28#include <sys/types.h> 29#include <sys/stat.h> 30#include <ar.h> 31#include <assert.h> 32#include <ctype.h> 33#include <dwarf.h> 34#include <err.h> 35#include <errno.h> 36#include <fcntl.h> 37#include <gelf.h> 38#include <getopt.h> 39#include <inttypes.h> 40#include <libdwarf.h> 41#include <libelftc.h> 42#include <stdbool.h> 43#include <stdio.h> 44#include <stdlib.h> 45#include <string.h> 46#include <strings.h> 47#include <unistd.h> 48 49#include "_elftc.h" 50 51ELFTC_VCSID("$Id: nm.c 3722 2019-03-23 17:01:58Z jkoshy $"); 52 53/* symbol information list */ 54STAILQ_HEAD(sym_head, sym_entry); 55 56struct sym_entry { 57 char *name; 58 GElf_Sym *sym; 59 STAILQ_ENTRY(sym_entry) sym_entries; 60}; 61 62typedef int (*fn_sort)(const void *, const void *); 63typedef void (*fn_elem_print)(char, const char *, const GElf_Sym *, const char *); 64typedef void (*fn_sym_print)(const GElf_Sym *); 65typedef int (*fn_filter)(char, const GElf_Sym *, const char *); 66 67/* output filter list */ 68static SLIST_HEAD(filter_head, filter_entry) nm_out_filter = 69 SLIST_HEAD_INITIALIZER(nm_out_filter); 70 71struct filter_entry { 72 fn_filter fn; 73 SLIST_ENTRY(filter_entry) filter_entries; 74}; 75 76struct sym_print_data { 77 struct sym_head *headp; 78 size_t sh_num, list_num; 79 const char *t_table, **s_table, *filename, *objname; 80}; 81 82struct nm_prog_info { 83 const char *name; 84 const char *def_filename; 85}; 86 87/* List for line number information. */ 88struct line_info_entry { 89 uint64_t addr; /* address */ 90 uint64_t line; /* line number */ 91 char *file; /* file name with path */ 92 SLIST_ENTRY(line_info_entry) entries; 93}; 94SLIST_HEAD(line_info_head, line_info_entry); 95 96/* List for function line number information. */ 97struct func_info_entry { 98 char *name; /* function name */ 99 char *file; /* file name with path */ 100 uint64_t lowpc; /* low address */ 101 uint64_t highpc; /* high address */ 102 uint64_t line; /* line number */ 103 SLIST_ENTRY(func_info_entry) entries; 104}; 105SLIST_HEAD(func_info_head, func_info_entry); 106 107/* List for variable line number information. */ 108struct var_info_entry { 109 char *name; /* variable name */ 110 char *file; /* file name with path */ 111 uint64_t addr; /* address */ 112 uint64_t line; /* line number */ 113 SLIST_ENTRY(var_info_entry) entries; 114}; 115SLIST_HEAD(var_info_head, var_info_entry); 116 117/* output numric type */ 118enum radix { 119 RADIX_OCT, 120 RADIX_HEX, 121 RADIX_DEC 122}; 123 124/* output symbol type, PRINT_SYM_DYN for dynamic symbol only */ 125enum print_symbol { 126 PRINT_SYM_SYM, 127 PRINT_SYM_DYN 128}; 129 130/* output name type */ 131enum print_name { 132 PRINT_NAME_NONE, 133 PRINT_NAME_FULL, 134 PRINT_NAME_MULTI 135}; 136 137struct nm_prog_options { 138 enum print_symbol print_symbol; 139 enum print_name print_name; 140 enum radix t; 141 int demangle_type; 142 bool print_debug; 143 bool print_armap; 144 int print_size; 145 bool debug_line; 146 int def_only; 147 bool undef_only; 148 int sort_size; 149 bool sort_reverse; 150 int no_demangle; 151 152 /* 153 * function pointer to sort symbol list. 154 * possible function - cmp_name, cmp_none, cmp_size, cmp_value 155 */ 156 fn_sort sort_fn; 157 158 /* 159 * function pointer to print symbol elem. 160 * possible function - sym_elem_print_all 161 * sym_elem_print_all_portable 162 * sym_elem_print_all_sysv 163 */ 164 fn_elem_print elem_print_fn; 165 166 fn_sym_print value_print_fn; 167 fn_sym_print size_print_fn; 168}; 169 170#define CHECK_SYM_PRINT_DATA(p) (p->headp == NULL || p->sh_num == 0 || \ 171p->t_table == NULL || p->s_table == NULL || p->filename == NULL) 172#define IS_SYM_TYPE(t) ((t) == '?' || isalpha((t)) != 0) 173#define IS_UNDEF_SYM_TYPE(t) ((t) == 'U' || (t) == 'v' || (t) == 'w') 174#define UNUSED(p) ((void)p) 175 176static int cmp_name(const void *, const void *); 177static int cmp_none(const void *, const void *); 178static int cmp_size(const void *, const void *); 179static int cmp_value(const void *, const void *); 180static void filter_dest(void); 181static int filter_insert(fn_filter); 182static void get_opt(int *, char ***); 183static int get_sym(Elf *, struct sym_head *, int, size_t, size_t, 184 const char *, const char **, int); 185static const char * get_sym_name(Elf *, const GElf_Sym *, size_t, 186 const char **, int); 187static char get_sym_type(const GElf_Sym *, const char *); 188static void global_dest(void); 189static void global_init(void); 190static bool is_sec_data(GElf_Shdr *); 191static bool is_sec_debug(const char *); 192static bool is_sec_nobits(GElf_Shdr *); 193static bool is_sec_readonly(GElf_Shdr *); 194static bool is_sec_text(GElf_Shdr *); 195static void print_ar_index(int, Elf *); 196static void print_header(const char *, const char *); 197static void print_version(void); 198static int read_elf(Elf *, const char *, Elf_Kind); 199static int read_object(const char *); 200static int read_files(int, char **); 201static void set_opt_value_print_fn(enum radix); 202static int sym_elem_def(char, const GElf_Sym *, const char *); 203static int sym_elem_global(char, const GElf_Sym *, const char *); 204static int sym_elem_global_static(char, const GElf_Sym *, 205 const char *); 206static int sym_elem_nondebug(char, const GElf_Sym *, const char *); 207static int sym_elem_nonzero_size(char, const GElf_Sym *, 208 const char *); 209static void sym_elem_print_all(char, const char *, 210 const GElf_Sym *, const char *); 211static void sym_elem_print_all_portable(char, const char *, 212 const GElf_Sym *, const char *); 213static void sym_elem_print_all_sysv(char, const char *, 214 const GElf_Sym *, const char *); 215static int sym_elem_undef(char, const GElf_Sym *, const char *); 216static void sym_list_dest(struct sym_head *); 217static int sym_list_insert(struct sym_head *, const char *, 218 const GElf_Sym *); 219static void sym_list_print(struct sym_print_data *, 220 struct func_info_head *, struct var_info_head *, 221 struct line_info_head *); 222static void sym_list_print_each(struct sym_entry *, 223 struct sym_print_data *, struct func_info_head *, 224 struct var_info_head *, struct line_info_head *); 225static struct sym_entry *sym_list_sort(struct sym_print_data *); 226static void sym_size_oct_print(const GElf_Sym *); 227static void sym_size_hex_print(const GElf_Sym *); 228static void sym_size_dec_print(const GElf_Sym *); 229static void sym_value_oct_print(const GElf_Sym *); 230static void sym_value_hex_print(const GElf_Sym *); 231static void sym_value_dec_print(const GElf_Sym *); 232static void usage(int); 233 234static struct nm_prog_info nm_info; 235static struct nm_prog_options nm_opts; 236static int nm_elfclass; 237 238/* 239 * Point to current sym_print_data to use portable qsort function. 240 * (e.g. There is no qsort_r function in NetBSD.) 241 * 242 * Using in sym_list_sort. 243 */ 244static struct sym_print_data *nm_print_data; 245 246static const struct option nm_longopts[] = { 247 { "debug-syms", no_argument, NULL, 'a' }, 248 { "defined-only", no_argument, &nm_opts.def_only, 1}, 249 { "demangle", optional_argument, NULL, 'C' }, 250 { "dynamic", no_argument, NULL, 'D' }, 251 { "extern-only", no_argument, NULL, 'g' }, 252 { "format", required_argument, NULL, 'F' }, 253 { "help", no_argument, NULL, 'h' }, 254 { "line-numbers", no_argument, NULL, 'l' }, 255 { "no-demangle", no_argument, &nm_opts.no_demangle, 256 1}, 257 { "no-sort", no_argument, NULL, 'p' }, 258 { "numeric-sort", no_argument, NULL, 'v' }, 259 { "print-armap", no_argument, NULL, 's' }, 260 { "print-file-name", no_argument, NULL, 'A' }, 261 { "print-size", no_argument, NULL, 'S' }, 262 { "radix", required_argument, NULL, 't' }, 263 { "reverse-sort", no_argument, NULL, 'r' }, 264 { "size-sort", no_argument, &nm_opts.sort_size, 1}, 265 { "undefined-only", no_argument, NULL, 'u' }, 266 { "version", no_argument, NULL, 'V' }, 267 { NULL, 0, NULL, 0 } 268}; 269 270#if defined(ELFTC_NEED_BYTEORDER_EXTENSIONS) 271static __inline uint32_t 272be32dec(const void *pp) 273{ 274 unsigned char const *p = (unsigned char const *)pp; 275 276 return ((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]); 277} 278 279static __inline uint32_t 280le32dec(const void *pp) 281{ 282 unsigned char const *p = (unsigned char const *)pp; 283 284 return ((p[3] << 24) | (p[2] << 16) | (p[1] << 8) | p[0]); 285} 286 287static __inline uint64_t 288be64dec(const void *pp) 289{ 290 unsigned char const *p = (unsigned char const *)pp; 291 292 return (((uint64_t)be32dec(p) << 32) | be32dec(p + 4)); 293} 294 295static __inline uint64_t 296le64dec(const void *pp) 297{ 298 unsigned char const *p = (unsigned char const *)pp; 299 300 return (((uint64_t)le32dec(p + 4) << 32) | le32dec(p)); 301} 302#endif 303 304static int 305cmp_name(const void *l, const void *r) 306{ 307 308 assert(l != NULL); 309 assert(r != NULL); 310 assert(((const struct sym_entry *)l)->name != NULL); 311 assert(((const struct sym_entry *)r)->name != NULL); 312 313 return (strcmp(((const struct sym_entry *)l)->name, 314 ((const struct sym_entry *)r)->name)); 315} 316 317static int 318cmp_none(const void *l, const void *r) 319{ 320 321 UNUSED(l); 322 UNUSED(r); 323 324 return (0); 325} 326 327/* Size comparison. If l and r have same size, compare their name. */ 328static int 329cmp_size(const void *lp, const void *rp) 330{ 331 const struct sym_entry *l, *r; 332 333 l = lp; 334 r = rp; 335 336 assert(l != NULL); 337 assert(l->name != NULL); 338 assert(l->sym != NULL); 339 assert(r != NULL); 340 assert(r->name != NULL); 341 assert(r->sym != NULL); 342 343 if (l->sym->st_size == r->sym->st_size) 344 return (strcmp(l->name, r->name)); 345 346 return (l->sym->st_size - r->sym->st_size); 347} 348 349/* Value comparison. Undefined symbols come first. */ 350static int 351cmp_value(const void *lp, const void *rp) 352{ 353 const struct sym_entry *l, *r; 354 const char *ttable; 355 int l_is_undef, r_is_undef; 356 357 l = lp; 358 r = rp; 359 360 assert(nm_print_data != NULL); 361 ttable = nm_print_data->t_table; 362 363 assert(l != NULL); 364 assert(l->name != NULL); 365 assert(l->sym != NULL); 366 assert(r != NULL); 367 assert(r->name != NULL); 368 assert(r->sym != NULL); 369 assert(ttable != NULL); 370 371 l_is_undef = IS_UNDEF_SYM_TYPE(get_sym_type(l->sym, ttable)) ? 1 : 0; 372 r_is_undef = IS_UNDEF_SYM_TYPE(get_sym_type(r->sym, ttable)) ? 1 : 0; 373 374 assert(l_is_undef + r_is_undef >= 0); 375 assert(l_is_undef + r_is_undef <= 2); 376 377 switch (l_is_undef + r_is_undef) { 378 case 0: 379 /* Both defined */ 380 if (l->sym->st_value == r->sym->st_value) 381 return (strcmp(l->name, r->name)); 382 return (l->sym->st_value > r->sym->st_value ? 1 : -1); 383 case 1: 384 /* One undefined */ 385 return (l_is_undef == 0 ? 1 : -1); 386 case 2: 387 /* Both undefined */ 388 return (strcmp(l->name, r->name)); 389 } 390 /* NOTREACHED */ 391 392 return (l->sym->st_value - r->sym->st_value); 393} 394 395static void 396filter_dest(void) 397{ 398 struct filter_entry *e; 399 400 while (!SLIST_EMPTY(&nm_out_filter)) { 401 e = SLIST_FIRST(&nm_out_filter); 402 SLIST_REMOVE_HEAD(&nm_out_filter, filter_entries); 403 free(e); 404 } 405} 406 407static int 408filter_insert(fn_filter filter_fn) 409{ 410 struct filter_entry *e; 411 412 assert(filter_fn != NULL); 413 414 if ((e = malloc(sizeof(struct filter_entry))) == NULL) { 415 warn("malloc"); 416 return (0); 417 } 418 e->fn = filter_fn; 419 SLIST_INSERT_HEAD(&nm_out_filter, e, filter_entries); 420 421 return (1); 422} 423 424static int 425parse_demangle_option(const char *opt) 426{ 427 428 if (opt == NULL) 429 return (ELFTC_DEM_UNKNOWN); 430 else if (!strncasecmp(opt, "gnu-v2", 6)) 431 return (ELFTC_DEM_GNU2); 432 else if (!strncasecmp(opt, "gnu-v3", 6)) 433 return (ELFTC_DEM_GNU3); 434 else if (!strncasecmp(opt, "arm", 3)) 435 return (ELFTC_DEM_ARM); 436 else 437 errx(EXIT_FAILURE, "unknown demangling style '%s'", opt); 438 439 /* NOTREACHED */ 440 return (0); 441} 442 443static void 444get_opt(int *argc, char ***argv) 445{ 446 int ch; 447 bool is_posix, oflag; 448 449 if (*argc <= 0 || *argv == NULL) 450 return; 451 452 oflag = is_posix = false; 453 nm_opts.t = RADIX_HEX; 454 while ((ch = getopt_long(*argc, *argv, "ABCDF:PSVaefghlnoprst:uvx", 455 nm_longopts, NULL)) != -1) { 456 switch (ch) { 457 case 'A': 458 nm_opts.print_name = PRINT_NAME_FULL; 459 break; 460 case 'B': 461 nm_opts.elem_print_fn = &sym_elem_print_all; 462 break; 463 case 'C': 464 nm_opts.demangle_type = parse_demangle_option(optarg); 465 break; 466 case 'D': 467 nm_opts.print_symbol = PRINT_SYM_DYN; 468 break; 469 case 'F': 470 /* sysv, bsd, posix */ 471 switch (optarg[0]) { 472 case 'B': 473 case 'b': 474 nm_opts.elem_print_fn = &sym_elem_print_all; 475 break; 476 case 'P': 477 case 'p': 478 is_posix = true; 479 nm_opts.elem_print_fn = 480 &sym_elem_print_all_portable; 481 break; 482 case 'S': 483 case 's': 484 nm_opts.elem_print_fn = 485 &sym_elem_print_all_sysv; 486 break; 487 default: 488 warnx("%s: Invalid format", optarg); 489 usage(1); 490 } 491 492 break; 493 case 'P': 494 is_posix = true; 495 nm_opts.elem_print_fn = &sym_elem_print_all_portable; 496 break; 497 case 'S': 498 nm_opts.print_size = 1; 499 break; 500 case 'V': 501 print_version(); 502 /* NOTREACHED */ 503 case 'a': 504 nm_opts.print_debug = true; 505 break; 506 case 'e': 507 filter_insert(sym_elem_global_static); 508 break; 509 case 'f': 510 break; 511 case 'g': 512 filter_insert(sym_elem_global); 513 break; 514 case 'h': 515 usage(0); 516 break; 517 case 'l': 518 nm_opts.debug_line = true; 519 break; 520 case 'n': 521 case 'v': 522 nm_opts.sort_fn = &cmp_value; 523 break; 524 case 'o': 525 oflag = true; 526 break; 527 case 'p': 528 nm_opts.sort_fn = &cmp_none; 529 break; 530 case 'r': 531 nm_opts.sort_reverse = true; 532 break; 533 case 's': 534 nm_opts.print_armap = true; 535 break; 536 case 't': 537 /* t require always argument to getopt_long */ 538 switch (optarg[0]) { 539 case 'd': 540 nm_opts.t = RADIX_DEC; 541 break; 542 case 'o': 543 nm_opts.t = RADIX_OCT; 544 break; 545 case 'x': 546 nm_opts.t = RADIX_HEX; 547 break; 548 default: 549 warnx("%s: Invalid radix", optarg); 550 usage(1); 551 } 552 break; 553 case 'u': 554 filter_insert(sym_elem_undef); 555 nm_opts.undef_only = true; 556 break; 557 /* case 'v': see case 'n' above. */ 558 case 'x': 559 nm_opts.t = RADIX_HEX; 560 break; 561 case 0: 562 if (nm_opts.sort_size != 0) { 563 nm_opts.sort_fn = &cmp_size; 564 filter_insert(sym_elem_def); 565 filter_insert(sym_elem_nonzero_size); 566 } 567 if (nm_opts.def_only != 0) 568 filter_insert(sym_elem_def); 569 if (nm_opts.no_demangle != 0) 570 nm_opts.demangle_type = -1; 571 break; 572 default : 573 usage(1); 574 } 575 } 576 *argc -= optind; 577 *argv += optind; 578 579 /* 580 * In POSIX mode, the '-o' option controls the output radix. 581 * In non-POSIX mode, the option is a synonym for the '-A' and 582 * '--print-file-name' options. 583 */ 584 if (oflag) { 585 if (is_posix) 586 nm_opts.t = RADIX_OCT; 587 else 588 nm_opts.print_name = PRINT_NAME_FULL; 589 } 590 591 assert(nm_opts.sort_fn != NULL && "nm_opts.sort_fn is null"); 592 assert(nm_opts.elem_print_fn != NULL && 593 "nm_opts.elem_print_fn is null"); 594 assert(nm_opts.value_print_fn != NULL && 595 "nm_opts.value_print_fn is null"); 596 597 set_opt_value_print_fn(nm_opts.t); 598 599 if (nm_opts.undef_only == true) { 600 if (nm_opts.sort_fn == &cmp_size) 601 errx(EXIT_FAILURE, 602 "--size-sort with -u is meaningless"); 603 if (nm_opts.def_only != 0) 604 errx(EXIT_FAILURE, 605 "-u with --defined-only is meaningless"); 606 } 607 if (nm_opts.print_debug == false) 608 filter_insert(sym_elem_nondebug); 609 if (nm_opts.sort_reverse == true && nm_opts.sort_fn == cmp_none) 610 nm_opts.sort_reverse = false; 611} 612 613/* 614 * Get symbol information from elf. 615 */ 616static int 617get_sym(Elf *elf, struct sym_head *headp, int shnum, size_t dynndx, 618 size_t strndx, const char *type_table, const char **sec_table, 619 int sec_table_size) 620{ 621 Elf_Scn *scn; 622 Elf_Data *data; 623 GElf_Shdr shdr; 624 GElf_Sym sym; 625 struct filter_entry *fep; 626 size_t ndx; 627 int rtn; 628 const char *sym_name; 629 char type; 630 bool filter; 631 int i, j; 632 633 assert(elf != NULL); 634 assert(headp != NULL); 635 636 rtn = 0; 637 for (i = 1; i < shnum; i++) { 638 if ((scn = elf_getscn(elf, i)) == NULL) { 639 warnx("elf_getscn failed: %s", elf_errmsg(-1)); 640 continue; 641 } 642 if (gelf_getshdr(scn, &shdr) != &shdr) { 643 warnx("gelf_getshdr failed: %s", elf_errmsg(-1)); 644 continue; 645 } 646 if (shdr.sh_type == SHT_SYMTAB) { 647 if (nm_opts.print_symbol != PRINT_SYM_SYM) 648 continue; 649 } else if (shdr.sh_type == SHT_DYNSYM) { 650 if (nm_opts.print_symbol != PRINT_SYM_DYN) 651 continue; 652 } else 653 continue; 654 655 ndx = shdr.sh_type == SHT_DYNSYM ? dynndx : strndx; 656 657 data = NULL; 658 while ((data = elf_getdata(scn, data)) != NULL) { 659 j = 1; 660 while (gelf_getsym(data, j++, &sym) != NULL) { 661 sym_name = get_sym_name(elf, &sym, ndx, 662 sec_table, sec_table_size); 663 filter = false; 664 type = get_sym_type(&sym, type_table); 665 SLIST_FOREACH(fep, &nm_out_filter, 666 filter_entries) { 667 if (!fep->fn(type, &sym, sym_name)) { 668 filter = true; 669 break; 670 } 671 } 672 if (filter == false) { 673 if (sym_list_insert(headp, sym_name, 674 &sym) == 0) 675 return (0); 676 rtn++; 677 } 678 } 679 } 680 } 681 682 return (rtn); 683} 684 685static const char * 686get_sym_name(Elf *elf, const GElf_Sym *sym, size_t ndx, const char **sec_table, 687 int sec_table_size) 688{ 689 const char *sym_name; 690 691 sym_name = NULL; 692 693 /* Show section name as symbol name for STT_SECTION symbols. */ 694 if (GELF_ST_TYPE(sym->st_info) == STT_SECTION) { 695 if (sec_table != NULL && sym->st_shndx < sec_table_size) 696 sym_name = sec_table[sym->st_shndx]; 697 } else 698 sym_name = elf_strptr(elf, ndx, sym->st_name); 699 700 if (sym_name == NULL) 701 sym_name = "(null)"; 702 703 return (sym_name); 704} 705 706static char 707get_sym_type(const GElf_Sym *sym, const char *type_table) 708{ 709 bool is_local; 710 711 if (sym == NULL || type_table == NULL) 712 return ('?'); 713 714 is_local = sym->st_info >> 4 == STB_LOCAL; 715 716 if (sym->st_shndx == SHN_ABS) /* absolute */ 717 return (is_local ? 'a' : 'A'); 718 719 if (sym->st_shndx == SHN_COMMON) /* common */ 720 return ('C'); 721 722 if ((sym->st_info) >> 4 == STB_WEAK) { /* weak */ 723 if ((sym->st_info & 0xf) == STT_OBJECT) 724 return (sym->st_shndx == SHN_UNDEF ? 'v' : 'V'); 725 726 return (sym->st_shndx == SHN_UNDEF ? 'w' : 'W'); 727 } 728 729 if (sym->st_shndx == SHN_UNDEF) /* undefined */ 730 return ('U'); 731 732 return (is_local == true && type_table[sym->st_shndx] != 'N' ? 733 tolower((unsigned char) type_table[sym->st_shndx]) : 734 type_table[sym->st_shndx]); 735} 736 737static void 738global_dest(void) 739{ 740 741 filter_dest(); 742} 743 744static void 745global_init(void) 746{ 747 748 if (elf_version(EV_CURRENT) == EV_NONE) 749 errx(EXIT_FAILURE, "elf_version error"); 750 751 nm_info.name = ELFTC_GETPROGNAME(); 752 nm_info.def_filename = "a.out"; 753 nm_opts.print_symbol = PRINT_SYM_SYM; 754 nm_opts.print_name = PRINT_NAME_NONE; 755 nm_opts.demangle_type = -1; 756 nm_opts.print_debug = false; 757 nm_opts.print_armap = false; 758 nm_opts.print_size = 0; 759 nm_opts.debug_line = false; 760 nm_opts.def_only = 0; 761 nm_opts.undef_only = false; 762 nm_opts.sort_size = 0; 763 nm_opts.sort_reverse = false; 764 nm_opts.no_demangle = 0; 765 nm_opts.sort_fn = &cmp_name; 766 nm_opts.elem_print_fn = &sym_elem_print_all; 767 nm_opts.value_print_fn = &sym_value_dec_print; 768 nm_opts.size_print_fn = &sym_size_dec_print; 769 SLIST_INIT(&nm_out_filter); 770} 771 772static bool 773is_sec_data(GElf_Shdr *s) 774{ 775 776 assert(s != NULL && "shdr is NULL"); 777 778 return (((s->sh_flags & SHF_ALLOC) != 0) && s->sh_type != SHT_NOBITS); 779} 780 781static bool 782is_sec_debug(const char *shname) 783{ 784 const char *dbg_sec[] = { 785 ".debug", 786 ".gnu.linkonce.wi.", 787 ".line", 788 ".rel.debug", 789 ".rela.debug", 790 ".stab", 791 NULL 792 }; 793 const char **p; 794 795 if (shname == NULL) 796 return (false); 797 798 for (p = dbg_sec; *p; p++) { 799 if (!strncmp(shname, *p, strlen(*p))) 800 return (true); 801 } 802 803 return (false); 804} 805 806static bool 807is_sec_nobits(GElf_Shdr *s) 808{ 809 810 assert(s != NULL && "shdr is NULL"); 811 812 return (s->sh_type == SHT_NOBITS); 813} 814 815static bool 816is_sec_readonly(GElf_Shdr *s) 817{ 818 819 assert(s != NULL && "shdr is NULL"); 820 821 return ((s->sh_flags & SHF_WRITE) == 0); 822} 823 824static bool 825is_sec_text(GElf_Shdr *s) 826{ 827 828 assert(s != NULL && "shdr is NULL"); 829 830 return ((s->sh_flags & SHF_EXECINSTR) != 0); 831} 832 833static void 834print_ar_index(int fd, Elf *arf) 835{ 836 Elf *elf; 837 Elf_Arhdr *arhdr; 838 Elf_Arsym *arsym; 839 Elf_Cmd cmd; 840 off_t start; 841 size_t arsym_size; 842 843 if (arf == NULL) 844 return; 845 846 if ((arsym = elf_getarsym(arf, &arsym_size)) == NULL) 847 return; 848 849 printf("\nArchive index:\n"); 850 851 start = arsym->as_off; 852 cmd = ELF_C_READ; 853 while (arsym_size > 1) { 854 if (elf_rand(arf, arsym->as_off) == arsym->as_off && 855 (elf = elf_begin(fd, cmd, arf)) != NULL) { 856 if ((arhdr = elf_getarhdr(elf)) != NULL) 857 printf("%s in %s\n", arsym->as_name, 858 arhdr->ar_name != NULL ? 859 arhdr->ar_name : arhdr->ar_rawname); 860 elf_end(elf); 861 } 862 ++arsym; 863 --arsym_size; 864 } 865 866 elf_rand(arf, start); 867} 868 869#define DEMANGLED_BUFFER_SIZE (8 * 1024) 870#define PRINT_DEMANGLED_NAME(FORMAT, NAME) do { \ 871 char _demangled[DEMANGLED_BUFFER_SIZE]; \ 872 if (nm_opts.demangle_type < 0 || \ 873 elftc_demangle((NAME), _demangled, sizeof(_demangled), \ 874 nm_opts.demangle_type) < 0) \ 875 printf((FORMAT), (NAME)); \ 876 else \ 877 printf((FORMAT), _demangled); \ 878 } while (0) 879 880static void 881print_header(const char *file, const char *obj) 882{ 883 884 if (file == NULL) 885 return; 886 887 if (nm_opts.elem_print_fn == &sym_elem_print_all_sysv) { 888 printf("\n\n%s from %s", 889 nm_opts.undef_only == false ? "Symbols" : 890 "Undefined symbols", file); 891 if (obj != NULL) 892 printf("[%s]", obj); 893 printf(":\n\n"); 894 895 printf("\ 896Name Value Class Type Size Line Section\n\n"); 897 } else { 898 /* archive file without -A option and POSIX */ 899 if (nm_opts.print_name != PRINT_NAME_FULL && obj != NULL) { 900 if (nm_opts.elem_print_fn == 901 sym_elem_print_all_portable) 902 printf("%s[%s]:\n", file, obj); 903 else if (nm_opts.elem_print_fn == sym_elem_print_all) 904 printf("\n%s:\n", obj); 905 /* multiple files(not archive) without -A option */ 906 } else if (nm_opts.print_name == PRINT_NAME_MULTI) { 907 if (nm_opts.elem_print_fn == sym_elem_print_all) 908 printf("\n"); 909 printf("%s:\n", file); 910 } 911 } 912} 913 914static void 915print_version(void) 916{ 917 918 (void) printf("%s (%s)\n", nm_info.name, elftc_version()); 919 exit(0); 920} 921 922static uint64_t 923get_block_value(Dwarf_Debug dbg, Dwarf_Block *block) 924{ 925 Elf *elf; 926 GElf_Ehdr eh; 927 Dwarf_Error de; 928 929 if (dwarf_get_elf(dbg, &elf, &de) != DW_DLV_OK) { 930 warnx("dwarf_get_elf failed: %s", dwarf_errmsg(de)); 931 return (0); 932 } 933 934 if (gelf_getehdr(elf, &eh) != &eh) { 935 warnx("gelf_getehdr failed: %s", elf_errmsg(-1)); 936 return (0); 937 } 938 939 if (block->bl_len == 5) { 940 if (eh.e_ident[EI_DATA] == ELFDATA2LSB) 941 return (le32dec((uint8_t *) block->bl_data + 1)); 942 else 943 return (be32dec((uint8_t *) block->bl_data + 1)); 944 } else if (block->bl_len == 9) { 945 if (eh.e_ident[EI_DATA] == ELFDATA2LSB) 946 return (le64dec((uint8_t *) block->bl_data + 1)); 947 else 948 return (be64dec((uint8_t *) block->bl_data + 1)); 949 } 950 951 return (0); 952} 953 954static char * 955find_object_name(Dwarf_Debug dbg, Dwarf_Die die) 956{ 957 Dwarf_Die ret_die; 958 Dwarf_Attribute at; 959 Dwarf_Off off; 960 Dwarf_Error de; 961 const char *str; 962 char *name; 963 964 if (dwarf_attrval_string(die, DW_AT_name, &str, &de) == DW_DLV_OK) { 965 if ((name = strdup(str)) == NULL) { 966 warn("strdup"); 967 return (NULL); 968 } 969 return (name); 970 } 971 972 if (dwarf_attr(die, DW_AT_specification, &at, &de) != DW_DLV_OK) 973 return (NULL); 974 975 if (dwarf_global_formref(at, &off, &de) != DW_DLV_OK) 976 return (NULL); 977 978 if (dwarf_offdie(dbg, off, &ret_die, &de) != DW_DLV_OK) 979 return (NULL); 980 981 return (find_object_name(dbg, ret_die)); 982} 983 984static void 985search_line_attr(Dwarf_Debug dbg, struct func_info_head *func_info, 986 struct var_info_head *var_info, Dwarf_Die die, char **src_files, 987 Dwarf_Signed filecount) 988{ 989 Dwarf_Attribute at; 990 Dwarf_Unsigned udata; 991 Dwarf_Half tag; 992 Dwarf_Block *block; 993 Dwarf_Bool flag; 994 Dwarf_Die ret_die; 995 Dwarf_Error de; 996 struct func_info_entry *func; 997 struct var_info_entry *var; 998 int ret; 999 1000 if (dwarf_tag(die, &tag, &de) != DW_DLV_OK) { 1001 warnx("dwarf_tag failed: %s", dwarf_errmsg(de)); 1002 goto cont_search; 1003 } 1004 1005 /* We're interested in DIEs which define functions or variables. */ 1006 if (tag != DW_TAG_subprogram && tag != DW_TAG_entry_point && 1007 tag != DW_TAG_inlined_subroutine && tag != DW_TAG_variable) 1008 goto cont_search; 1009 1010 if (tag == DW_TAG_variable) { 1011 1012 /* Ignore "artificial" variable. */ 1013 if (dwarf_attrval_flag(die, DW_AT_artificial, &flag, &de) == 1014 DW_DLV_OK && flag) 1015 goto cont_search; 1016 1017 /* Ignore pure declaration. */ 1018 if (dwarf_attrval_flag(die, DW_AT_declaration, &flag, &de) == 1019 DW_DLV_OK && flag) 1020 goto cont_search; 1021 1022 /* Ignore stack varaibles. */ 1023 if (dwarf_attrval_flag(die, DW_AT_external, &flag, &de) != 1024 DW_DLV_OK || !flag) 1025 goto cont_search; 1026 1027 if ((var = calloc(1, sizeof(*var))) == NULL) { 1028 warn("calloc failed"); 1029 goto cont_search; 1030 } 1031 1032 if (dwarf_attrval_unsigned(die, DW_AT_decl_file, &udata, 1033 &de) == DW_DLV_OK && udata > 0 && 1034 (Dwarf_Signed) (udata - 1) < filecount) { 1035 var->file = strdup(src_files[udata - 1]); 1036 if (var->file == NULL) { 1037 warn("strdup"); 1038 free(var); 1039 goto cont_search; 1040 } 1041 } 1042 1043 if (dwarf_attrval_unsigned(die, DW_AT_decl_line, &udata, &de) == 1044 DW_DLV_OK) 1045 var->line = udata; 1046 1047 var->name = find_object_name(dbg, die); 1048 if (var->name == NULL) { 1049 if (var->file) 1050 free(var->file); 1051 free(var); 1052 goto cont_search; 1053 } 1054 1055 if (dwarf_attr(die, DW_AT_location, &at, &de) == DW_DLV_OK && 1056 dwarf_formblock(at, &block, &de) == DW_DLV_OK) { 1057 /* 1058 * Since we ignored stack variables, the rest are the 1059 * external varaibles which should always use DW_OP_addr 1060 * operator for DW_AT_location value. 1061 */ 1062 if (*((uint8_t *)block->bl_data) == DW_OP_addr) 1063 var->addr = get_block_value(dbg, block); 1064 } 1065 1066 SLIST_INSERT_HEAD(var_info, var, entries); 1067 1068 } else { 1069 1070 if ((func = calloc(1, sizeof(*func))) == NULL) { 1071 warn("calloc failed"); 1072 goto cont_search; 1073 } 1074 1075 /* 1076 * Note that dwarf_attrval_unsigned() handles DW_AT_abstract_origin 1077 * internally, so it can retrieve DW_AT_decl_file/DW_AT_decl_line 1078 * attributes for inlined functions as well. 1079 */ 1080 if (dwarf_attrval_unsigned(die, DW_AT_decl_file, &udata, 1081 &de) == DW_DLV_OK && udata > 0 && 1082 (Dwarf_Signed) (udata - 1) < filecount) { 1083 func->file = strdup(src_files[udata - 1]); 1084 if (func->file == NULL) { 1085 warn("strdup"); 1086 free(func); 1087 goto cont_search; 1088 } 1089 } 1090 1091 if (dwarf_attrval_unsigned(die, DW_AT_decl_line, &udata, &de) == 1092 DW_DLV_OK) 1093 func->line = udata; 1094 1095 func->name = find_object_name(dbg, die); 1096 if (func->name == NULL) { 1097 if (func->file) 1098 free(func->file); 1099 free(func); 1100 goto cont_search; 1101 } 1102 1103 if (dwarf_attrval_unsigned(die, DW_AT_low_pc, &udata, &de) == 1104 DW_DLV_OK) 1105 func->lowpc = udata; 1106 if (dwarf_attrval_unsigned(die, DW_AT_high_pc, &udata, &de) == 1107 DW_DLV_OK) 1108 func->highpc = udata; 1109 1110 SLIST_INSERT_HEAD(func_info, func, entries); 1111 } 1112 1113cont_search: 1114 1115 /* Search children. */ 1116 ret = dwarf_child(die, &ret_die, &de); 1117 if (ret == DW_DLV_ERROR) 1118 warnx("dwarf_child: %s", dwarf_errmsg(de)); 1119 else if (ret == DW_DLV_OK) 1120 search_line_attr(dbg, func_info, var_info, ret_die, src_files, 1121 filecount); 1122 1123 /* Search sibling. */ 1124 ret = dwarf_siblingof(dbg, die, &ret_die, &de); 1125 if (ret == DW_DLV_ERROR) 1126 warnx("dwarf_siblingof: %s", dwarf_errmsg(de)); 1127 else if (ret == DW_DLV_OK) 1128 search_line_attr(dbg, func_info, var_info, ret_die, src_files, 1129 filecount); 1130 1131 dwarf_dealloc(dbg, die, DW_DLA_DIE); 1132} 1133 1134/* 1135 * Read elf file and collect symbol information, sort them, print. 1136 * Return 1 at failed, 0 at success. 1137 */ 1138static int 1139read_elf(Elf *elf, const char *filename, Elf_Kind kind) 1140{ 1141 Dwarf_Debug dbg; 1142 Dwarf_Die die; 1143 Dwarf_Error de; 1144 Dwarf_Half tag; 1145 Elf_Arhdr *arhdr; 1146 Elf_Scn *scn; 1147 GElf_Shdr shdr; 1148 Dwarf_Line *lbuf; 1149 Dwarf_Unsigned lineno; 1150 Dwarf_Signed lcount, filecount; 1151 Dwarf_Addr lineaddr; 1152 struct sym_print_data p_data; 1153 struct sym_head list_head; 1154 struct line_info_head *line_info; 1155 struct func_info_head *func_info; 1156 struct var_info_head *var_info; 1157 struct line_info_entry *lie; 1158 struct func_info_entry *func; 1159 struct var_info_entry *var; 1160 const char *shname, *objname; 1161 char *type_table, **sec_table, *sfile, **src_files; 1162 size_t i, shstrndx, shnum, dynndx, strndx; 1163 int ret, rtn, e_err; 1164 1165#define OBJNAME (objname == NULL ? filename : objname) 1166 1167 assert(filename != NULL && "filename is null"); 1168 1169 STAILQ_INIT(&list_head); 1170 type_table = NULL; 1171 sec_table = NULL; 1172 line_info = NULL; 1173 func_info = NULL; 1174 var_info = NULL; 1175 objname = NULL; 1176 dynndx = SHN_UNDEF; 1177 strndx = SHN_UNDEF; 1178 rtn = 0; 1179 1180 nm_elfclass = gelf_getclass(elf); 1181 1182 if (kind == ELF_K_AR) { 1183 if ((arhdr = elf_getarhdr(elf)) == NULL) 1184 goto next_cmd; 1185 objname = arhdr->ar_name != NULL ? arhdr->ar_name : 1186 arhdr->ar_rawname; 1187 } 1188 if (!elf_getshnum(elf, &shnum)) { 1189 if ((e_err = elf_errno()) != 0) 1190 warnx("%s: %s", OBJNAME, "File format not recognized"); 1191 else 1192 warnx("%s: cannot get section number", OBJNAME); 1193 rtn = 1; 1194 goto next_cmd; 1195 } 1196 if (shnum == 0) { 1197 warnx("%s: has no section", OBJNAME); 1198 rtn = 1; 1199 goto next_cmd; 1200 } 1201 if (!elf_getshstrndx(elf, &shstrndx)) { 1202 warnx("%s: cannot get str index", OBJNAME); 1203 rtn = 1; 1204 goto next_cmd; 1205 } 1206 /* type_table for type determine */ 1207 if ((type_table = malloc(sizeof(char) * shnum)) == NULL) { 1208 warn("%s: malloc", OBJNAME); 1209 rtn = 1; 1210 goto next_cmd; 1211 } 1212 /* sec_table for section name to display in sysv format */ 1213 if ((sec_table = calloc(shnum, sizeof(char *))) == NULL) { 1214 warn("%s: calloc", OBJNAME); 1215 rtn = 1; 1216 goto next_cmd; 1217 } 1218 1219 type_table[0] = 'U'; 1220 if ((sec_table[0] = strdup("*UND*")) == NULL) { 1221 warn("strdup"); 1222 goto next_cmd; 1223 } 1224 1225 for (i = 1; i < shnum; ++i) { 1226 type_table[i] = 'U'; 1227 if ((scn = elf_getscn(elf, i)) == NULL) { 1228 if ((e_err = elf_errno()) != 0) 1229 warnx("%s: %s", OBJNAME, elf_errmsg(e_err)); 1230 else 1231 warnx("%s: cannot get section", OBJNAME); 1232 rtn = 1; 1233 goto next_cmd; 1234 } 1235 if (gelf_getshdr(scn, &shdr) == NULL) 1236 goto next_cmd; 1237 1238 /* 1239 * Cannot test by type and attribute for dynstr, strtab 1240 */ 1241 shname = elf_strptr(elf, shstrndx, (size_t) shdr.sh_name); 1242 if (shname != NULL) { 1243 if ((sec_table[i] = strdup(shname)) == NULL) { 1244 warn("strdup"); 1245 goto next_cmd; 1246 } 1247 if (!strncmp(shname, ".dynstr", 7)) { 1248 dynndx = elf_ndxscn(scn); 1249 if (dynndx == SHN_UNDEF) { 1250 warnx("%s: elf_ndxscn failed: %s", 1251 OBJNAME, elf_errmsg(-1)); 1252 goto next_cmd; 1253 } 1254 } 1255 if (!strncmp(shname, ".strtab", 7)) { 1256 strndx = elf_ndxscn(scn); 1257 if (strndx == SHN_UNDEF) { 1258 warnx("%s: elf_ndxscn failed: %s", 1259 OBJNAME, elf_errmsg(-1)); 1260 goto next_cmd; 1261 } 1262 } 1263 } else { 1264 sec_table[i] = strdup("*UND*"); 1265 if (sec_table[i] == NULL) { 1266 warn("strdup"); 1267 goto next_cmd; 1268 } 1269 } 1270 1271 1272 if (is_sec_text(&shdr)) 1273 type_table[i] = 'T'; 1274 else if (is_sec_data(&shdr)) { 1275 if (is_sec_readonly(&shdr)) 1276 type_table[i] = 'R'; 1277 else 1278 type_table[i] = 'D'; 1279 } else if (is_sec_nobits(&shdr)) 1280 type_table[i] = 'B'; 1281 else if (is_sec_debug(shname)) 1282 type_table[i] = 'N'; 1283 else if (is_sec_readonly(&shdr) && !is_sec_nobits(&shdr)) 1284 type_table[i] = 'n'; 1285 } 1286 1287 print_header(filename, objname); 1288 1289 if ((dynndx == SHN_UNDEF && nm_opts.print_symbol == PRINT_SYM_DYN) || 1290 (strndx == SHN_UNDEF && nm_opts.print_symbol == PRINT_SYM_SYM)) { 1291 warnx("%s: no symbols", OBJNAME); 1292 /* This is not an error case */ 1293 goto next_cmd; 1294 } 1295 1296 STAILQ_INIT(&list_head); 1297 1298 if (!nm_opts.debug_line) 1299 goto process_sym; 1300 1301 /* 1302 * Collect dwarf line number information. 1303 */ 1304 1305 if (dwarf_elf_init(elf, DW_DLC_READ, NULL, NULL, &dbg, &de) != 1306 DW_DLV_OK) { 1307 warnx("dwarf_elf_init failed: %s", dwarf_errmsg(de)); 1308 goto process_sym; 1309 } 1310 1311 line_info = malloc(sizeof(struct line_info_head)); 1312 func_info = malloc(sizeof(struct func_info_head)); 1313 var_info = malloc(sizeof(struct var_info_head)); 1314 if (line_info != NULL) 1315 SLIST_INIT(line_info); 1316 if (func_info != NULL) 1317 SLIST_INIT(func_info); 1318 if (var_info != NULL) 1319 SLIST_INIT(var_info); 1320 if (line_info == NULL || func_info == NULL || var_info == NULL) { 1321 warn("malloc"); 1322 (void) dwarf_finish(dbg, &de); 1323 goto process_sym; 1324 } 1325 1326 while ((ret = dwarf_next_cu_header(dbg, NULL, NULL, NULL, NULL, NULL, 1327 &de)) == DW_DLV_OK) { 1328 die = NULL; 1329 while (dwarf_siblingof(dbg, die, &die, &de) == DW_DLV_OK) { 1330 if (dwarf_tag(die, &tag, &de) != DW_DLV_OK) { 1331 warnx("dwarf_tag failed: %s", 1332 dwarf_errmsg(de)); 1333 continue; 1334 } 1335 /* XXX: What about DW_TAG_partial_unit? */ 1336 if (tag == DW_TAG_compile_unit) 1337 break; 1338 } 1339 if (die == NULL) { 1340 warnx("could not find DW_TAG_compile_unit die"); 1341 continue; 1342 } 1343 1344 /* Retrieve source file list. */ 1345 ret = dwarf_srcfiles(die, &src_files, &filecount, &de); 1346 if (ret == DW_DLV_ERROR) 1347 warnx("dwarf_srclines: %s", dwarf_errmsg(de)); 1348 if (ret != DW_DLV_OK) 1349 continue; 1350 1351 /* 1352 * Retrieve line number information from .debug_line section. 1353 */ 1354 1355 ret = dwarf_srclines(die, &lbuf, &lcount, &de); 1356 if (ret == DW_DLV_ERROR) 1357 warnx("dwarf_srclines: %s", dwarf_errmsg(de)); 1358 if (ret != DW_DLV_OK) 1359 goto line_attr; 1360 for (i = 0; (Dwarf_Signed) i < lcount; i++) { 1361 if (dwarf_lineaddr(lbuf[i], &lineaddr, &de)) { 1362 warnx("dwarf_lineaddr: %s", dwarf_errmsg(de)); 1363 continue; 1364 } 1365 if (dwarf_lineno(lbuf[i], &lineno, &de)) { 1366 warnx("dwarf_lineno: %s", dwarf_errmsg(de)); 1367 continue; 1368 } 1369 if (dwarf_linesrc(lbuf[i], &sfile, &de)) { 1370 warnx("dwarf_linesrc: %s", dwarf_errmsg(de)); 1371 continue; 1372 } 1373 if ((lie = malloc(sizeof(*lie))) == NULL) { 1374 warn("malloc"); 1375 continue; 1376 } 1377 lie->addr = lineaddr; 1378 lie->line = lineno; 1379 lie->file = strdup(sfile); 1380 if (lie->file == NULL) { 1381 warn("strdup"); 1382 free(lie); 1383 continue; 1384 } 1385 SLIST_INSERT_HEAD(line_info, lie, entries); 1386 } 1387 1388 line_attr: 1389 /* Retrieve line number information from DIEs. */ 1390 search_line_attr(dbg, func_info, var_info, die, src_files, filecount); 1391 } 1392 1393 (void) dwarf_finish(dbg, &de); 1394 1395process_sym: 1396 1397 p_data.list_num = get_sym(elf, &list_head, shnum, dynndx, strndx, 1398 type_table, (void *) sec_table, shnum); 1399 1400 if (p_data.list_num == 0) 1401 goto next_cmd; 1402 1403 p_data.headp = &list_head; 1404 p_data.sh_num = shnum; 1405 p_data.t_table = type_table; 1406 p_data.s_table = (void *) sec_table; 1407 p_data.filename = filename; 1408 p_data.objname = objname; 1409 1410 sym_list_print(&p_data, func_info, var_info, line_info); 1411 1412next_cmd: 1413 if (nm_opts.debug_line) { 1414 if (func_info != NULL) { 1415 while (!SLIST_EMPTY(func_info)) { 1416 func = SLIST_FIRST(func_info); 1417 SLIST_REMOVE_HEAD(func_info, entries); 1418 free(func->file); 1419 free(func->name); 1420 free(func); 1421 } 1422 free(func_info); 1423 func_info = NULL; 1424 } 1425 if (var_info != NULL) { 1426 while (!SLIST_EMPTY(var_info)) { 1427 var = SLIST_FIRST(var_info); 1428 SLIST_REMOVE_HEAD(var_info, entries); 1429 free(var->file); 1430 free(var->name); 1431 free(var); 1432 } 1433 free(var_info); 1434 var_info = NULL; 1435 } 1436 if (line_info != NULL) { 1437 while (!SLIST_EMPTY(line_info)) { 1438 lie = SLIST_FIRST(line_info); 1439 SLIST_REMOVE_HEAD(line_info, entries); 1440 free(lie->file); 1441 free(lie); 1442 } 1443 free(line_info); 1444 line_info = NULL; 1445 } 1446 } 1447 1448 if (sec_table != NULL) 1449 for (i = 0; i < shnum; ++i) 1450 free(sec_table[i]); 1451 free(sec_table); 1452 free(type_table); 1453 1454 sym_list_dest(&list_head); 1455 1456 return (rtn); 1457 1458#undef OBJNAME 1459} 1460 1461static int 1462read_object(const char *filename) 1463{ 1464 Elf *elf, *arf; 1465 Elf_Cmd elf_cmd; 1466 Elf_Kind kind; 1467 int fd, rtn, e_err; 1468 1469 assert(filename != NULL && "filename is null"); 1470 1471 if ((fd = open(filename, O_RDONLY)) == -1) { 1472 warn("'%s'", filename); 1473 return (1); 1474 } 1475 1476 elf_cmd = ELF_C_READ; 1477 if ((arf = elf_begin(fd, elf_cmd, (Elf *) NULL)) == NULL) { 1478 if ((e_err = elf_errno()) != 0) 1479 warnx("elf_begin error: %s", elf_errmsg(e_err)); 1480 else 1481 warnx("elf_begin error"); 1482 close(fd); 1483 return (1); 1484 } 1485 1486 assert(arf != NULL && "arf is null."); 1487 1488 rtn = 0; 1489 if ((kind = elf_kind(arf)) == ELF_K_NONE) { 1490 warnx("%s: File format not recognized", filename); 1491 elf_end(arf); 1492 close(fd); 1493 return (1); 1494 } 1495 if (kind == ELF_K_AR) { 1496 if (nm_opts.print_name == PRINT_NAME_MULTI && 1497 nm_opts.elem_print_fn == sym_elem_print_all) 1498 printf("\n%s:\n", filename); 1499 if (nm_opts.print_armap == true) 1500 print_ar_index(fd, arf); 1501 } 1502 1503 while ((elf = elf_begin(fd, elf_cmd, arf)) != NULL) { 1504 rtn |= read_elf(elf, filename, kind); 1505 1506 /* 1507 * If file is not archive, elf_next return ELF_C_NULL and 1508 * stop the loop. 1509 */ 1510 elf_cmd = elf_next(elf); 1511 elf_end(elf); 1512 } 1513 1514 elf_end(arf); 1515 close(fd); 1516 1517 return (rtn); 1518} 1519 1520static int 1521read_files(int argc, char **argv) 1522{ 1523 int rtn = 0; 1524 1525 if (argc < 0 || argv == NULL) 1526 return (1); 1527 1528 if (argc == 0) 1529 rtn |= read_object(nm_info.def_filename); 1530 else { 1531 if (nm_opts.print_name == PRINT_NAME_NONE && argc > 1) 1532 nm_opts.print_name = PRINT_NAME_MULTI; 1533 while (argc > 0) { 1534 rtn |= read_object(*argv); 1535 --argc; 1536 ++argv; 1537 } 1538 } 1539 1540 return (rtn); 1541} 1542 1543static void 1544print_lineno(struct sym_entry *ep, struct func_info_head *func_info, 1545 struct var_info_head *var_info, struct line_info_head *line_info) 1546{ 1547 struct func_info_entry *func; 1548 struct var_info_entry *var; 1549 struct line_info_entry *lie; 1550 1551 /* For function symbol, search the function line information list. */ 1552 if ((ep->sym->st_info & 0xf) == STT_FUNC && func_info != NULL) { 1553 SLIST_FOREACH(func, func_info, entries) { 1554 if (func->name != NULL && 1555 !strcmp(ep->name, func->name) && 1556 ep->sym->st_value >= func->lowpc && 1557 ep->sym->st_value < func->highpc) { 1558 printf("\t%s:%" PRIu64, func->file, func->line); 1559 return; 1560 } 1561 } 1562 } 1563 1564 /* For variable symbol, search the variable line information list. */ 1565 if ((ep->sym->st_info & 0xf) == STT_OBJECT && var_info != NULL) { 1566 SLIST_FOREACH(var, var_info, entries) { 1567 if (!strcmp(ep->name, var->name) && 1568 ep->sym->st_value == var->addr) { 1569 printf("\t%s:%" PRIu64, var->file, var->line); 1570 return; 1571 } 1572 } 1573 } 1574 1575 /* Otherwise search line number information the .debug_line section. */ 1576 if (line_info != NULL) { 1577 SLIST_FOREACH(lie, line_info, entries) { 1578 if (ep->sym->st_value == lie->addr) { 1579 printf("\t%s:%" PRIu64, lie->file, lie->line); 1580 return; 1581 } 1582 } 1583 } 1584} 1585 1586static void 1587set_opt_value_print_fn(enum radix t) 1588{ 1589 1590 switch (t) { 1591 case RADIX_OCT: 1592 nm_opts.value_print_fn = &sym_value_oct_print; 1593 nm_opts.size_print_fn = &sym_size_oct_print; 1594 1595 break; 1596 case RADIX_DEC: 1597 nm_opts.value_print_fn = &sym_value_dec_print; 1598 nm_opts.size_print_fn = &sym_size_dec_print; 1599 1600 break; 1601 case RADIX_HEX: 1602 default : 1603 nm_opts.value_print_fn = &sym_value_hex_print; 1604 nm_opts.size_print_fn = &sym_size_hex_print; 1605 } 1606 1607 assert(nm_opts.value_print_fn != NULL && 1608 "nm_opts.value_print_fn is null"); 1609} 1610 1611static void 1612sym_elem_print_all(char type, const char *sec, const GElf_Sym *sym, 1613 const char *name) 1614{ 1615 1616 if (sec == NULL || sym == NULL || name == NULL || 1617 nm_opts.value_print_fn == NULL) 1618 return; 1619 1620 if (IS_UNDEF_SYM_TYPE(type)) { 1621 if (nm_opts.t == RADIX_HEX && nm_elfclass == ELFCLASS32) 1622 printf("%-8s", ""); 1623 else 1624 printf("%-16s", ""); 1625 } else { 1626 switch ((nm_opts.sort_fn == & cmp_size ? 2 : 0) + 1627 nm_opts.print_size) { 1628 case 3: 1629 if (sym->st_size != 0) { 1630 nm_opts.value_print_fn(sym); 1631 printf(" "); 1632 nm_opts.size_print_fn(sym); 1633 } 1634 break; 1635 1636 case 2: 1637 if (sym->st_size != 0) 1638 nm_opts.size_print_fn(sym); 1639 break; 1640 1641 case 1: 1642 nm_opts.value_print_fn(sym); 1643 if (sym->st_size != 0) { 1644 printf(" "); 1645 nm_opts.size_print_fn(sym); 1646 } 1647 break; 1648 1649 case 0: 1650 default: 1651 nm_opts.value_print_fn(sym); 1652 } 1653 } 1654 1655 printf(" %c ", type); 1656 PRINT_DEMANGLED_NAME("%s", name); 1657} 1658 1659static void 1660sym_elem_print_all_portable(char type, const char *sec, const GElf_Sym *sym, 1661 const char *name) 1662{ 1663 1664 if (sec == NULL || sym == NULL || name == NULL || 1665 nm_opts.value_print_fn == NULL) 1666 return; 1667 1668 PRINT_DEMANGLED_NAME("%s", name); 1669 printf(" %c ", type); 1670 if (!IS_UNDEF_SYM_TYPE(type)) { 1671 nm_opts.value_print_fn(sym); 1672 printf(" "); 1673 if (sym->st_size != 0) 1674 nm_opts.size_print_fn(sym); 1675 } else 1676 printf(" "); 1677} 1678 1679static void 1680sym_elem_print_all_sysv(char type, const char *sec, const GElf_Sym *sym, 1681 const char *name) 1682{ 1683 1684 if (sec == NULL || sym == NULL || name == NULL || 1685 nm_opts.value_print_fn == NULL) 1686 return; 1687 1688 PRINT_DEMANGLED_NAME("%-20s|", name); 1689 if (IS_UNDEF_SYM_TYPE(type)) 1690 printf(" "); 1691 else 1692 nm_opts.value_print_fn(sym); 1693 1694 printf("| %c |", type); 1695 1696 switch (sym->st_info & 0xf) { 1697 case STT_OBJECT: 1698 printf("%18s|", "OBJECT"); 1699 break; 1700 1701 case STT_FUNC: 1702 printf("%18s|", "FUNC"); 1703 break; 1704 1705 case STT_SECTION: 1706 printf("%18s|", "SECTION"); 1707 break; 1708 1709 case STT_FILE: 1710 printf("%18s|", "FILE"); 1711 break; 1712 1713 case STT_LOPROC: 1714 printf("%18s|", "LOPROC"); 1715 break; 1716 1717 case STT_HIPROC: 1718 printf("%18s|", "HIPROC"); 1719 break; 1720 1721 case STT_NOTYPE: 1722 default: 1723 printf("%18s|", "NOTYPE"); 1724 } 1725 1726 if (sym->st_size != 0) 1727 nm_opts.size_print_fn(sym); 1728 else 1729 printf(" "); 1730 1731 printf("| |%s", sec); 1732} 1733 1734static int 1735sym_elem_def(char type, const GElf_Sym *sym, const char *name) 1736{ 1737 1738 assert(IS_SYM_TYPE((unsigned char) type)); 1739 1740 UNUSED(sym); 1741 UNUSED(name); 1742 1743 return (!IS_UNDEF_SYM_TYPE((unsigned char) type)); 1744} 1745 1746static int 1747sym_elem_global(char type, const GElf_Sym *sym, const char *name) 1748{ 1749 1750 assert(IS_SYM_TYPE((unsigned char) type)); 1751 1752 UNUSED(sym); 1753 UNUSED(name); 1754 1755 /* weak symbols resemble global. */ 1756 return (isupper((unsigned char) type) || type == 'w'); 1757} 1758 1759static int 1760sym_elem_global_static(char type, const GElf_Sym *sym, const char *name) 1761{ 1762 unsigned char info; 1763 1764 assert(sym != NULL); 1765 1766 UNUSED(type); 1767 UNUSED(name); 1768 1769 info = sym->st_info >> 4; 1770 1771 return (info == STB_LOCAL || 1772 info == STB_GLOBAL || 1773 info == STB_WEAK); 1774} 1775 1776static int 1777sym_elem_nondebug(char type, const GElf_Sym *sym, const char *name) 1778{ 1779 1780 assert(sym != NULL); 1781 1782 UNUSED(type); 1783 UNUSED(name); 1784 1785 if (sym->st_value == 0 && (sym->st_info & 0xf) == STT_FILE) 1786 return (0); 1787 if (sym->st_name == 0) 1788 return (0); 1789 1790 return (1); 1791} 1792 1793static int 1794sym_elem_nonzero_size(char type, const GElf_Sym *sym, const char *name) 1795{ 1796 1797 assert(sym != NULL); 1798 1799 UNUSED(type); 1800 UNUSED(name); 1801 1802 return (sym->st_size > 0); 1803} 1804 1805static int 1806sym_elem_undef(char type, const GElf_Sym *sym, const char *name) 1807{ 1808 1809 assert(IS_SYM_TYPE((unsigned char) type)); 1810 1811 UNUSED(sym); 1812 UNUSED(name); 1813 1814 return (IS_UNDEF_SYM_TYPE((unsigned char) type)); 1815} 1816 1817static void 1818sym_list_dest(struct sym_head *headp) 1819{ 1820 struct sym_entry *ep, *ep_n; 1821 1822 if (headp == NULL) 1823 return; 1824 1825 ep = STAILQ_FIRST(headp); 1826 while (ep != NULL) { 1827 ep_n = STAILQ_NEXT(ep, sym_entries); 1828 free(ep->sym); 1829 free(ep->name); 1830 free(ep); 1831 ep = ep_n; 1832 } 1833} 1834 1835static int 1836sym_list_insert(struct sym_head *headp, const char *name, const GElf_Sym *sym) 1837{ 1838 struct sym_entry *e; 1839 1840 if (headp == NULL || name == NULL || sym == NULL) 1841 return (0); 1842 if ((e = malloc(sizeof(struct sym_entry))) == NULL) { 1843 warn("malloc"); 1844 return (0); 1845 } 1846 if ((e->name = strdup(name)) == NULL) { 1847 warn("strdup"); 1848 free(e); 1849 return (0); 1850 } 1851 if ((e->sym = malloc(sizeof(GElf_Sym))) == NULL) { 1852 warn("malloc"); 1853 free(e->name); 1854 free(e); 1855 return (0); 1856 } 1857 1858 memcpy(e->sym, sym, sizeof(GElf_Sym)); 1859 1860 /* Display size instead of value for common symbol. */ 1861 if (sym->st_shndx == SHN_COMMON) 1862 e->sym->st_value = sym->st_size; 1863 1864 STAILQ_INSERT_TAIL(headp, e, sym_entries); 1865 1866 return (1); 1867} 1868 1869/* If file has not .debug_info, line_info will be NULL */ 1870static void 1871sym_list_print(struct sym_print_data *p, struct func_info_head *func_info, 1872 struct var_info_head *var_info, struct line_info_head *line_info) 1873{ 1874 struct sym_entry *e_v; 1875 size_t si; 1876 int i; 1877 1878 if (p == NULL || CHECK_SYM_PRINT_DATA(p)) 1879 return; 1880 if ((e_v = sym_list_sort(p)) == NULL) 1881 return; 1882 if (nm_opts.sort_reverse == false) 1883 for (si = 0; si != p->list_num; ++si) 1884 sym_list_print_each(&e_v[si], p, func_info, var_info, 1885 line_info); 1886 else 1887 for (i = p->list_num - 1; i != -1; --i) 1888 sym_list_print_each(&e_v[i], p, func_info, var_info, 1889 line_info); 1890 1891 free(e_v); 1892} 1893 1894/* If file has not .debug_info, line_info will be NULL */ 1895static void 1896sym_list_print_each(struct sym_entry *ep, struct sym_print_data *p, 1897 struct func_info_head *func_info, struct var_info_head *var_info, 1898 struct line_info_head *line_info) 1899{ 1900 const char *sec; 1901 char type; 1902 1903 if (ep == NULL || CHECK_SYM_PRINT_DATA(p)) 1904 return; 1905 1906 assert(ep->name != NULL); 1907 assert(ep->sym != NULL); 1908 1909 type = get_sym_type(ep->sym, p->t_table); 1910 1911 if (nm_opts.print_name == PRINT_NAME_FULL) { 1912 printf("%s", p->filename); 1913 if (nm_opts.elem_print_fn == &sym_elem_print_all_portable) { 1914 if (p->objname != NULL) 1915 printf("[%s]", p->objname); 1916 printf(": "); 1917 } else { 1918 if (p->objname != NULL) 1919 printf(":%s", p->objname); 1920 printf(":"); 1921 } 1922 } 1923 1924 switch (ep->sym->st_shndx) { 1925 case SHN_LOPROC: 1926 /* LOPROC or LORESERVE */ 1927 sec = "*LOPROC*"; 1928 break; 1929 case SHN_HIPROC: 1930 sec = "*HIPROC*"; 1931 break; 1932 case SHN_LOOS: 1933 sec = "*LOOS*"; 1934 break; 1935 case SHN_HIOS: 1936 sec = "*HIOS*"; 1937 break; 1938 case SHN_ABS: 1939 sec = "*ABS*"; 1940 break; 1941 case SHN_COMMON: 1942 sec = "*COM*"; 1943 break; 1944 case SHN_HIRESERVE: 1945 /* HIRESERVE or XINDEX */ 1946 sec = "*HIRESERVE*"; 1947 break; 1948 default: 1949 if (ep->sym->st_shndx > p->sh_num) 1950 return; 1951 sec = p->s_table[ep->sym->st_shndx]; 1952 break; 1953 } 1954 1955 nm_opts.elem_print_fn(type, sec, ep->sym, ep->name); 1956 1957 if (nm_opts.debug_line == true && !IS_UNDEF_SYM_TYPE(type)) 1958 print_lineno(ep, func_info, var_info, line_info); 1959 1960 printf("\n"); 1961} 1962 1963static struct sym_entry * 1964sym_list_sort(struct sym_print_data *p) 1965{ 1966 struct sym_entry *ep, *e_v; 1967 int idx; 1968 1969 if (p == NULL || CHECK_SYM_PRINT_DATA(p)) 1970 return (NULL); 1971 1972 if ((e_v = malloc(sizeof(struct sym_entry) * p->list_num)) == NULL) { 1973 warn("malloc"); 1974 return (NULL); 1975 } 1976 1977 idx = 0; 1978 STAILQ_FOREACH(ep, p->headp, sym_entries) { 1979 if (ep->name != NULL && ep->sym != NULL) { 1980 e_v[idx].name = ep->name; 1981 e_v[idx].sym = ep->sym; 1982 ++idx; 1983 } 1984 } 1985 1986 assert((size_t)idx == p->list_num); 1987 1988 if (nm_opts.sort_fn != &cmp_none) { 1989 nm_print_data = p; 1990 assert(nm_print_data != NULL); 1991 qsort(e_v, p->list_num, sizeof(struct sym_entry), 1992 nm_opts.sort_fn); 1993 } 1994 1995 return (e_v); 1996} 1997 1998static void 1999sym_size_oct_print(const GElf_Sym *sym) 2000{ 2001 2002 assert(sym != NULL && "sym is null"); 2003 printf("%016" PRIo64, sym->st_size); 2004} 2005 2006static void 2007sym_size_hex_print(const GElf_Sym *sym) 2008{ 2009 2010 assert(sym != NULL && "sym is null"); 2011 if (nm_elfclass == ELFCLASS32) 2012 printf("%08" PRIx64, sym->st_size); 2013 else 2014 printf("%016" PRIx64, sym->st_size); 2015} 2016 2017static void 2018sym_size_dec_print(const GElf_Sym *sym) 2019{ 2020 2021 assert(sym != NULL && "sym is null"); 2022 printf("%016" PRId64, sym->st_size); 2023} 2024 2025static void 2026sym_value_oct_print(const GElf_Sym *sym) 2027{ 2028 2029 assert(sym != NULL && "sym is null"); 2030 printf("%016" PRIo64, sym->st_value); 2031} 2032 2033static void 2034sym_value_hex_print(const GElf_Sym *sym) 2035{ 2036 2037 assert(sym != NULL && "sym is null"); 2038 if (nm_elfclass == ELFCLASS32) 2039 printf("%08" PRIx64, sym->st_value); 2040 else 2041 printf("%016" PRIx64, sym->st_value); 2042} 2043 2044static void 2045sym_value_dec_print(const GElf_Sym *sym) 2046{ 2047 2048 assert(sym != NULL && "sym is null"); 2049 printf("%016" PRId64, sym->st_value); 2050} 2051 2052static void 2053usage(int exitcode) 2054{ 2055 2056 printf("Usage: %s [options] file ...\ 2057\n Display symbolic information in file.\n\ 2058\n Options: \ 2059\n -A, --print-file-name Write the full pathname or library name of an\ 2060\n object on each line.\ 2061\n -a, --debug-syms Display all symbols include debugger-only\ 2062\n symbols.", nm_info.name); 2063 printf("\ 2064\n -B Equivalent to specifying \"--format=bsd\".\ 2065\n -C, --demangle[=style] Decode low-level symbol names.\ 2066\n --no-demangle Do not demangle low-level symbol names.\ 2067\n -D, --dynamic Display only dynamic symbols.\ 2068\n -e Display only global and static symbols."); 2069 printf("\ 2070\n -f Produce full output (default).\ 2071\n --format=format Display output in specific format. Allowed\ 2072\n formats are: \"bsd\", \"posix\" and \"sysv\".\ 2073\n -g, --extern-only Display only global symbol information.\ 2074\n -h, --help Show this help message.\ 2075\n -l, --line-numbers Display filename and linenumber using\ 2076\n debugging information.\ 2077\n -n, --numeric-sort Sort symbols numerically by value."); 2078 printf("\ 2079\n -o Write numeric values in octal. Equivalent to\ 2080\n specifying \"-t o\".\ 2081\n -p, --no-sort Do not sort symbols.\ 2082\n -P Write information in a portable output format.\ 2083\n Equivalent to specifying \"--format=posix\".\ 2084\n -r, --reverse-sort Reverse the order of the sort.\ 2085\n -S, --print-size Print symbol sizes instead values.\ 2086\n -s, --print-armap Include an index of archive members.\ 2087\n --size-sort Sort symbols by size."); 2088 printf("\ 2089\n -t, --radix=format Write each numeric value in the specified\ 2090\n format:\ 2091\n d In decimal,\ 2092\n o In octal,\ 2093\n x In hexadecimal."); 2094 printf("\ 2095\n -u, --undefined-only Display only undefined symbols.\ 2096\n --defined-only Display only defined symbols.\ 2097\n -V, --version Show the version identifier for %s.\ 2098\n -v Sort output by value.\ 2099\n -x Write numeric values in hexadecimal.\ 2100\n Equivalent to specifying \"-t x\".", 2101 nm_info.name); 2102 printf("\n\ 2103\n The default options are: output in bsd format, use a hexadecimal radix,\ 2104\n sort by symbol name, do not demangle names.\n"); 2105 2106 exit(exitcode); 2107} 2108 2109/* 2110 * Display symbolic information in file. 2111 * Return 0 at success, >0 at failed. 2112 */ 2113int 2114main(int argc, char **argv) 2115{ 2116 int rtn; 2117 2118 global_init(); 2119 get_opt(&argc, &argv); 2120 rtn = read_files(argc, argv); 2121 global_dest(); 2122 2123 exit(rtn); 2124} 2125