1 /* $OpenBSD: nm.c,v 1.51 2015/12/09 19:28:34 mmcc Exp $ */ 2 /* $NetBSD: nm.c,v 1.7 1996/01/14 23:04:03 pk Exp $ */ 3 4 /* 5 * Copyright (c) 1989, 1993 6 * The Regents of the University of California. All rights reserved. 7 * 8 * This code is derived from software contributed to Berkeley by 9 * Hans Huebner. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 3. Neither the name of the University nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 */ 35 36 #include <sys/types.h> 37 #include <sys/mman.h> 38 #include <a.out.h> 39 #include <elf_abi.h> 40 #include <ar.h> 41 #include <ranlib.h> 42 #include <unistd.h> 43 #include <err.h> 44 #include <errno.h> 45 #include <ctype.h> 46 #include <link.h> 47 48 #include <stdio.h> 49 #include <stdlib.h> 50 #include <string.h> 51 #include <getopt.h> 52 #include "util.h" 53 #include "elfuncs.h" 54 55 #define SYMTABMAG "/ " 56 #define STRTABMAG "//" 57 #define SYM64MAG "/SYM64/ " 58 59 union hdr { 60 Elf32_Ehdr elf32; 61 Elf64_Ehdr elf64; 62 }; 63 64 int armap; 65 int demangle; 66 int non_object_warning; 67 int print_only_external_symbols; 68 int print_only_undefined_symbols; 69 int print_all_symbols; 70 int print_file_each_line; 71 int show_extensions; 72 int issize; 73 char posix_fmtstr[6]; 74 int posix_output; 75 char posix_radix = 'x'; 76 int usemmap = 1; 77 int dynamic_only; 78 79 /* size vars */ 80 unsigned long total_text, total_data, total_bss, total_total; 81 int non_object_warning, print_totals; 82 83 int rev; 84 int fname(const void *, const void *); 85 int rname(const void *, const void *); 86 int value(const void *, const void *); 87 char *otherstring(struct xnlist *); 88 int (*sfunc)(const void *, const void *) = fname; 89 char typeletter(struct xnlist *); 90 int mmbr_name(struct ar_hdr *, char **, int, int *, FILE *); 91 int show_symtab(off_t, u_long, const char *, FILE *); 92 int show_symdef(off_t, u_long, const char *, FILE *); 93 94 /* some macros for symbol type (nlist.n_type) handling */ 95 #define IS_EXTERNAL(x) ((x) & N_EXT) 96 #define SYMBOL_TYPE(x) ((x) & (N_TYPE | N_STAB)) 97 98 void pipe2cppfilt(void); 99 void usage(void); 100 char *symname(struct xnlist *); 101 int process_file(int, const char *); 102 int show_archive(int, const char *, FILE *); 103 int show_file(int, int, const char *, FILE *fp, off_t, union hdr *); 104 void print_symbol(const char *, struct xnlist *); 105 106 #define OPTSTRING_NM "aABCDegnopPrst:uvw" 107 const struct option longopts_nm[] = { 108 { "debug-syms", no_argument, 0, 'a' }, 109 { "demangle", no_argument, 0, 'C' }, 110 { "dynamic", no_argument, 0, 'D' }, 111 { "extern-only", no_argument, 0, 'g' }, 112 /* { "line-numbers", no_argument, 0, 'l' }, */ 113 { "no-sort", no_argument, 0, 'p' }, 114 { "numeric-sort", no_argument, 0, 'n' }, 115 { "print-armap", no_argument, 0, 's' }, 116 { "print-file-name", no_argument, 0, 'o' }, 117 { "reverse-sort", no_argument, 0, 'r' }, 118 /* { "size-sort", no_argument, &szval, 1 }, */ 119 { "undefined-only", no_argument, 0, 'u' }, 120 { "help", no_argument, 0, '?' }, 121 { NULL } 122 }; 123 124 /* 125 * main() 126 * parse command line, execute process_file() for each file 127 * specified on the command line. 128 */ 129 int 130 main(int argc, char *argv[]) 131 { 132 extern char *__progname; 133 extern int optind; 134 const char *optstr; 135 const struct option *lopts; 136 int ch, eval; 137 138 if (pledge("stdio rpath proc exec", NULL) == -1) 139 err(1, "pledge"); 140 141 optstr = OPTSTRING_NM; 142 lopts = longopts_nm; 143 if (!strcmp(__progname, "size")) { 144 if (pledge("stdio rpath", NULL) == -1) 145 err(1, "pledge"); 146 147 issize = 1; 148 optstr = "tw"; 149 lopts = NULL; 150 } 151 152 while ((ch = getopt_long(argc, argv, optstr, lopts, NULL)) != -1) { 153 switch (ch) { 154 case 'a': 155 print_all_symbols = 1; 156 break; 157 case 'B': 158 /* no-op, compat with gnu-nm */ 159 break; 160 case 'C': 161 demangle = 1; 162 break; 163 case 'D': 164 dynamic_only = 1; 165 break; 166 case 'e': 167 show_extensions = 1; 168 break; 169 case 'g': 170 print_only_external_symbols = 1; 171 break; 172 case 'n': 173 case 'v': 174 sfunc = value; 175 break; 176 case 'A': 177 case 'o': 178 print_file_each_line = 1; 179 break; 180 case 'p': 181 sfunc = NULL; 182 break; 183 case 'P': 184 posix_output = 1; 185 break; 186 case 'r': 187 rev = 1; 188 break; 189 case 's': 190 armap = 1; 191 break; 192 case 'u': 193 print_only_undefined_symbols = 1; 194 break; 195 case 'w': 196 non_object_warning = 1; 197 break; 198 case 't': 199 if (issize) { 200 print_totals = 1; 201 } else { 202 posix_radix = *optarg; 203 if (strlen(optarg) != 1 || 204 (posix_radix != 'd' && posix_radix != 'o' && 205 posix_radix != 'x')) 206 usage(); 207 } 208 break; 209 case '?': 210 default: 211 usage(); 212 } 213 } 214 215 if (posix_output) 216 (void)snprintf(posix_fmtstr, sizeof posix_fmtstr, "%%%c %%%c", 217 posix_radix, posix_radix); 218 if (demangle) 219 pipe2cppfilt(); 220 221 if (pledge("stdio rpath", NULL) == -1) 222 err(1, "pledge"); 223 224 argv += optind; 225 argc -= optind; 226 227 if (rev && sfunc == fname) 228 sfunc = rname; 229 230 eval = 0; 231 if (*argv) 232 do { 233 eval |= process_file(argc, *argv); 234 } while (*++argv); 235 else 236 eval |= process_file(1, "a.out"); 237 238 if (issize && print_totals) 239 printf("\n%lu\t%lu\t%lu\t%lu\t%lx\tTOTAL\n", 240 total_text, total_data, total_bss, 241 total_total, total_total); 242 exit(eval); 243 } 244 245 /* 246 * process_file() 247 * show symbols in the file given as an argument. Accepts archive and 248 * object files as input. 249 */ 250 int 251 process_file(int count, const char *fname) 252 { 253 union hdr exec_head; 254 FILE *fp; 255 int retval; 256 size_t bytes; 257 char magic[SARMAG]; 258 259 if (!(fp = fopen(fname, "r"))) { 260 warn("cannot read %s", fname); 261 return(1); 262 } 263 264 if (!issize && count > 1) 265 (void)printf("\n%s:\n", fname); 266 267 /* 268 * first check whether this is an object file - read a object 269 * header, and skip back to the beginning 270 */ 271 bzero(&exec_head, sizeof(exec_head)); 272 bytes = fread((char *)&exec_head, 1, sizeof(exec_head), fp); 273 if (bytes < sizeof(exec_head)) { 274 if (bytes < sizeof(exec_head.elf32) || IS_ELF(exec_head.elf32)) { 275 warnx("%s: bad format", fname); 276 (void)fclose(fp); 277 return(1); 278 } 279 } 280 rewind(fp); 281 282 /* this could be an archive */ 283 if (!IS_ELF(exec_head.elf32)) { 284 if (fread(magic, sizeof(magic), (size_t)1, fp) != 1 || 285 strncmp(magic, ARMAG, SARMAG)) { 286 warnx("%s: not object file or archive", fname); 287 (void)fclose(fp); 288 return(1); 289 } 290 retval = show_archive(count, fname, fp); 291 } else 292 retval = show_file(count, 1, fname, fp, 0, &exec_head); 293 (void)fclose(fp); 294 return(retval); 295 } 296 297 char *nametab; 298 299 /* 300 * 301 * given the archive member header -- produce member name 302 */ 303 int 304 mmbr_name(struct ar_hdr *arh, char **name, int baselen, int *namelen, FILE *fp) 305 { 306 char *p = *name + strlen(*name); 307 long i; 308 309 if (nametab && arh->ar_name[0] == '/') { 310 int len; 311 312 i = atol(&arh->ar_name[1]); 313 len = strlen(&nametab[i]); 314 if (len > *namelen) { 315 p -= (long)*name; 316 if ((*name = realloc(*name, baselen+len)) == NULL) 317 err(1, NULL); 318 *namelen = len; 319 p += (long)*name; 320 } 321 strlcpy(p, &nametab[i], len); 322 p += len; 323 } else 324 #ifdef AR_EFMT1 325 /* 326 * BSD 4.4 extended AR format: #1/<namelen>, with name as the 327 * first <namelen> bytes of the file 328 */ 329 if ((arh->ar_name[0] == '#') && 330 (arh->ar_name[1] == '1') && 331 (arh->ar_name[2] == '/') && 332 (isdigit((unsigned char)arh->ar_name[3]))) { 333 int len = atoi(&arh->ar_name[3]); 334 335 if (len > *namelen) { 336 p -= (long)*name; 337 if ((*name = realloc(*name, baselen+len)) == NULL) 338 err(1, NULL); 339 *namelen = len; 340 p += (long)*name; 341 } 342 if (fread(p, len, 1, fp) != 1) { 343 warnx("%s: premature EOF", *name); 344 free(*name); 345 return(1); 346 } 347 p += len; 348 } else 349 #endif 350 for (i = 0; i < sizeof(arh->ar_name); ++i) 351 if (arh->ar_name[i] && arh->ar_name[i] != ' ') 352 *p++ = arh->ar_name[i]; 353 *p = '\0'; 354 if (p[-1] == '/') 355 *--p = '\0'; 356 357 return (0); 358 } 359 360 /* 361 * show_symtab() 362 * show archive ranlib index (fs5) 363 */ 364 int 365 show_symtab(off_t off, u_long len, const char *name, FILE *fp) 366 { 367 struct ar_hdr ar_head; 368 int *symtab, *ps; 369 char *strtab, *p; 370 int num, rval = 0; 371 int namelen; 372 off_t restore; 373 374 restore = ftello(fp); 375 376 MMAP(symtab, len, PROT_READ, MAP_PRIVATE|MAP_FILE, fileno(fp), off); 377 if (symtab == MAP_FAILED) 378 return (1); 379 380 namelen = sizeof(ar_head.ar_name); 381 if ((p = malloc(sizeof(ar_head.ar_name))) == NULL) { 382 warn("%s: malloc", name); 383 MUNMAP(symtab, len); 384 } 385 386 printf("\nArchive index:\n"); 387 num = betoh32(*symtab); 388 strtab = (char *)(symtab + num + 1); 389 for (ps = symtab + 1; num--; ps++, strtab += strlen(strtab) + 1) { 390 if (fseeko(fp, betoh32(*ps), SEEK_SET)) { 391 warn("%s: fseeko", name); 392 rval = 1; 393 break; 394 } 395 396 if (fread(&ar_head, sizeof(ar_head), 1, fp) != 1 || 397 memcmp(ar_head.ar_fmag, ARFMAG, sizeof(ar_head.ar_fmag))) { 398 warnx("%s: member fseeko", name); 399 rval = 1; 400 break; 401 } 402 403 *p = '\0'; 404 if (mmbr_name(&ar_head, &p, 0, &namelen, fp)) { 405 rval = 1; 406 break; 407 } 408 409 printf("%s in %s\n", strtab, p); 410 } 411 412 fseeko(fp, restore, SEEK_SET); 413 414 free(p); 415 MUNMAP(symtab, len); 416 return (rval); 417 } 418 419 /* 420 * show_symdef() 421 * show archive ranlib index (gob) 422 */ 423 int 424 show_symdef(off_t off, u_long len, const char *name, FILE *fp) 425 { 426 struct ranlib *prn, *eprn; 427 struct ar_hdr ar_head; 428 char *symdef; 429 char *strtab, *p; 430 u_long size; 431 int namelen, rval = 0; 432 433 MMAP(symdef, len, PROT_READ, MAP_PRIVATE|MAP_FILE, fileno(fp), off); 434 if (symdef == MAP_FAILED) 435 return (1); 436 if (usemmap) 437 (void)madvise(symdef, len, MADV_SEQUENTIAL); 438 439 namelen = sizeof(ar_head.ar_name); 440 if ((p = malloc(sizeof(ar_head.ar_name))) == NULL) { 441 warn("%s: malloc", name); 442 MUNMAP(symdef, len); 443 return (1); 444 } 445 446 size = *(u_long *)symdef; 447 prn = (struct ranlib *)(symdef + sizeof(u_long)); 448 eprn = prn + size / sizeof(*prn); 449 strtab = symdef + sizeof(u_long) + size + sizeof(u_long); 450 451 printf("\nArchive index:\n"); 452 for (; prn < eprn; prn++) { 453 if (fseeko(fp, prn->ran_off, SEEK_SET)) { 454 warn("%s: fseeko", name); 455 rval = 1; 456 break; 457 } 458 459 if (fread(&ar_head, sizeof(ar_head), 1, fp) != 1 || 460 memcmp(ar_head.ar_fmag, ARFMAG, sizeof(ar_head.ar_fmag))) { 461 warnx("%s: member fseeko", name); 462 rval = 1; 463 break; 464 } 465 466 *p = '\0'; 467 if (mmbr_name(&ar_head, &p, 0, &namelen, fp)) { 468 rval = 1; 469 break; 470 } 471 472 printf("%s in %s\n", strtab + prn->ran_un.ran_strx, p); 473 } 474 475 free(p); 476 MUNMAP(symdef, len); 477 return (rval); 478 } 479 480 /* 481 * show_archive() 482 * show symbols in the given archive file 483 */ 484 int 485 show_archive(int count, const char *fname, FILE *fp) 486 { 487 struct ar_hdr ar_head; 488 union hdr exec_head; 489 int i, rval; 490 off_t last_ar_off, foff, symtaboff; 491 char *name; 492 int baselen, namelen; 493 u_long mmbrlen, symtablen; 494 495 baselen = strlen(fname) + 3; 496 if (posix_output) 497 baselen += 2; 498 namelen = sizeof(ar_head.ar_name); 499 if ((name = malloc(baselen + namelen)) == NULL) 500 err(1, NULL); 501 502 rval = 0; 503 nametab = NULL; 504 symtaboff = 0; 505 symtablen = 0; 506 507 /* while there are more entries in the archive */ 508 while (fread(&ar_head, sizeof(ar_head), 1, fp) == 1) { 509 /* bad archive entry - stop processing this archive */ 510 if (memcmp(ar_head.ar_fmag, ARFMAG, sizeof(ar_head.ar_fmag))) { 511 warnx("%s: bad format archive header", fname); 512 rval = 1; 513 break; 514 } 515 516 /* remember start position of current archive object */ 517 last_ar_off = ftello(fp); 518 mmbrlen = atol(ar_head.ar_size); 519 520 if (strncmp(ar_head.ar_name, RANLIBMAG, 521 sizeof(RANLIBMAG) - 1) == 0) { 522 if (!issize && armap && 523 show_symdef(last_ar_off, mmbrlen, fname, fp)) { 524 rval = 1; 525 break; 526 } 527 goto skip; 528 } else if (strncmp(ar_head.ar_name, SYMTABMAG, 529 sizeof(SYMTABMAG) - 1) == 0) { 530 /* if nametab hasn't been seen yet -- doit later */ 531 if (!nametab) { 532 symtablen = mmbrlen; 533 symtaboff = last_ar_off; 534 goto skip; 535 } 536 537 /* load the Sys5 long names table */ 538 } else if (strncmp(ar_head.ar_name, STRTABMAG, 539 sizeof(STRTABMAG) - 1) == 0) { 540 char *p; 541 542 if ((nametab = malloc(mmbrlen)) == NULL) { 543 warn("%s: nametab", fname); 544 rval = 1; 545 break; 546 } 547 548 if (fread(nametab, mmbrlen, (size_t)1, fp) != 1) { 549 warnx("%s: premature EOF", fname); 550 rval = 1; 551 break; 552 } 553 554 for (p = nametab, i = mmbrlen; i--; p++) 555 if (*p == '\n') 556 *p = '\0'; 557 558 if (issize || !armap || !symtablen || !symtaboff) 559 goto skip; 560 } 561 #ifdef __mips64 562 else if (memcmp(ar_head.ar_name, SYM64MAG, 563 sizeof(ar_head.ar_name)) == 0) { 564 /* IRIX6-compatible archive map */ 565 goto skip; 566 } 567 #endif 568 569 if (!issize && armap && symtablen && symtaboff) { 570 if (show_symtab(symtaboff, symtablen, fname, fp)) { 571 rval = 1; 572 break; 573 } else { 574 symtaboff = 0; 575 symtablen = 0; 576 } 577 } 578 579 /* 580 * construct a name of the form "archive.a:obj.o:" for the 581 * current archive entry if the object name is to be printed 582 * on each output line 583 */ 584 *name = '\0'; 585 if (posix_output) 586 snprintf(name, baselen - 1, "%s[", fname); 587 else if (count > 1) 588 snprintf(name, baselen - 1, "%s:", fname); 589 590 if (mmbr_name(&ar_head, &name, baselen, &namelen, fp)) { 591 rval = 1; 592 break; 593 } 594 595 if (posix_output) 596 strlcat(name, "]", baselen + namelen); 597 598 foff = ftello(fp); 599 600 /* get and check current object's header */ 601 if (fread((char *)&exec_head, sizeof(exec_head), 602 (size_t)1, fp) != 1) { 603 warnx("%s: premature EOF", fname); 604 rval = 1; 605 break; 606 } 607 608 rval |= show_file(2, non_object_warning, name, fp, foff, &exec_head); 609 /* 610 * skip to next archive object - it starts at the next 611 * even byte boundary 612 */ 613 #define even(x) (((x) + 1) & ~1) 614 skip: if (fseeko(fp, last_ar_off + even(mmbrlen), SEEK_SET)) { 615 warn("%s", fname); 616 rval = 1; 617 break; 618 } 619 } 620 free(nametab); 621 nametab = NULL; 622 free(name); 623 return(rval); 624 } 625 626 char *stab; 627 628 /* 629 * show_file() 630 * show symbols from the object file pointed to by fp. The current 631 * file pointer for fp is expected to be at the beginning of an object 632 * file header. 633 */ 634 int 635 show_file(int count, int warn_fmt, const char *name, FILE *fp, off_t foff, union hdr *head) 636 { 637 u_long text, data, bss, total; 638 struct xnlist *np, *names, **snames; 639 int i, nrawnames, nnames; 640 size_t stabsize; 641 642 if (IS_ELF(head->elf32) && 643 head->elf32.e_ident[EI_CLASS] == ELFCLASS32 && 644 head->elf32.e_ident[EI_VERSION] == ELF_TARG_VER) { 645 void *shdr; 646 647 if (!(shdr = elf32_load_shdrs(name, fp, foff, &head->elf32))) 648 return (1); 649 650 i = issize? 651 elf32_size(&head->elf32, shdr, &text, &data, &bss) : 652 elf32_symload(name, fp, foff, &head->elf32, shdr, 653 &names, &snames, &stabsize, &nrawnames); 654 free(shdr); 655 if (i) 656 return (i); 657 658 } else if (IS_ELF(head->elf64) && 659 head->elf64.e_ident[EI_CLASS] == ELFCLASS64 && 660 head->elf64.e_ident[EI_VERSION] == ELF_TARG_VER) { 661 void *shdr; 662 663 if (!(shdr = elf64_load_shdrs(name, fp, foff, &head->elf64))) 664 return (1); 665 666 i = issize? 667 elf64_size(&head->elf64, shdr, &text, &data, &bss) : 668 elf64_symload(name, fp, foff, &head->elf64, shdr, 669 &names, &snames, &stabsize, &nrawnames); 670 free(shdr); 671 if (i) 672 return (i); 673 } else { 674 if (warn_fmt) 675 warnx("%s: bad format", name); 676 return (1); 677 } 678 679 if (issize) { 680 static int first = 1; 681 682 if (first) { 683 first = 0; 684 printf("text\tdata\tbss\tdec\thex\n"); 685 } 686 687 total = text + data + bss; 688 printf("%lu\t%lu\t%lu\t%lu\t%lx", 689 text, data, bss, total, total); 690 if (count > 1) 691 (void)printf("\t%s", name); 692 693 total_text += text; 694 total_data += data; 695 total_bss += bss; 696 total_total += total; 697 698 printf("\n"); 699 return (0); 700 } 701 /* else we are nm */ 702 703 /* 704 * it seems that string table is sequential 705 * relative to the symbol table order 706 */ 707 if (sfunc == NULL && usemmap) 708 (void)madvise(stab, stabsize, MADV_SEQUENTIAL); 709 710 /* 711 * fix up the symbol table and filter out unwanted entries 712 * 713 * common symbols are characterized by a n_type of N_UNDF and a 714 * non-zero n_value -- change n_type to N_COMM for all such 715 * symbols to make life easier later. 716 * 717 * filter out all entries which we don't want to print anyway 718 */ 719 for (np = names, i = nnames = 0; i < nrawnames; np++, i++) { 720 /* 721 * make n_un.n_name a character pointer by adding the string 722 * table's base to n_un.n_strx 723 * 724 * don't mess with zero offsets 725 */ 726 if (np->nl.n_un.n_strx) 727 np->nl.n_un.n_name = stab + np->nl.n_un.n_strx; 728 else 729 np->nl.n_un.n_name = ""; 730 if (print_only_external_symbols && !IS_EXTERNAL(np->nl.n_type)) 731 continue; 732 if (print_only_undefined_symbols && 733 SYMBOL_TYPE(np->nl.n_type) != N_UNDF) 734 continue; 735 736 snames[nnames++] = np; 737 } 738 739 /* sort the symbol table if applicable */ 740 if (sfunc) 741 qsort(snames, (size_t)nnames, sizeof(*snames), sfunc); 742 743 if (count > 1) 744 (void)printf("\n%s:\n", name); 745 746 /* print out symbols */ 747 for (i = 0; i < nnames; i++) 748 print_symbol(name, snames[i]); 749 750 free(snames); 751 free(names); 752 MUNMAP(stab, stabsize); 753 return(0); 754 } 755 756 char * 757 symname(struct xnlist *sym) 758 { 759 return sym->nl.n_un.n_name; 760 } 761 762 /* 763 * print_symbol() 764 * show one symbol 765 */ 766 void 767 print_symbol(const char *name, struct xnlist *sym) 768 { 769 if (print_file_each_line) { 770 if (posix_output) 771 (void)printf("%s: ", name); 772 else 773 (void)printf("%s:", name); 774 } 775 776 if (posix_output) { 777 (void)printf("%s %c ", symname(sym), typeletter(sym)); 778 if (SYMBOL_TYPE(sym->nl.n_type) != N_UNDF) 779 (void)printf(posix_fmtstr, sym->nl.n_value, 780 sym->n_size); 781 (void)printf("\n"); 782 } else { 783 /* 784 * handle undefined-only format especially (no space is 785 * left for symbol values, no type field is printed) 786 */ 787 if (!print_only_undefined_symbols) { 788 /* print symbol's value */ 789 if (SYMBOL_TYPE(sym->nl.n_type) == N_UNDF) 790 (void)printf(" "); 791 else 792 (void)printf("%08lx", sym->nl.n_value); 793 794 /* print type information */ 795 if (show_extensions) 796 (void)printf(" %c ", typeletter(sym)); 797 else 798 (void)printf(" %c ", typeletter(sym)); 799 } 800 801 (void)puts(symname(sym)); 802 } 803 } 804 805 /* 806 * typeletter() 807 * return a description letter for the given basic type code of an 808 * symbol table entry. The return value will be upper case for 809 * external, lower case for internal symbols. 810 */ 811 char 812 typeletter(struct xnlist *np) 813 { 814 int ext = IS_EXTERNAL(np->nl.n_type); 815 816 if (np->nl.n_other) 817 return np->nl.n_other; 818 819 switch(SYMBOL_TYPE(np->nl.n_type)) { 820 case N_ABS: 821 return(ext? 'A' : 'a'); 822 case N_BSS: 823 return(ext? 'B' : 'b'); 824 case N_COMM: 825 return(ext? 'C' : 'c'); 826 case N_DATA: 827 return(ext? 'D' : 'd'); 828 case N_FN: 829 /* NOTE: N_FN == N_WARNING, 830 * in this case, the N_EXT bit is to considered as 831 * part of the symbol's type itself. 832 */ 833 return(ext? 'F' : 'W'); 834 case N_TEXT: 835 return(ext? 'T' : 't'); 836 case N_SIZE: 837 return(ext? 'S' : 's'); 838 case N_UNDF: 839 return(ext? 'U' : 'u'); 840 } 841 return('?'); 842 } 843 844 int 845 fname(const void *a0, const void *b0) 846 { 847 struct xnlist * const *a = a0, * const *b = b0; 848 849 return(strcmp((*a)->nl.n_un.n_name, (*b)->nl.n_un.n_name)); 850 } 851 852 int 853 rname(const void *a0, const void *b0) 854 { 855 struct xnlist * const *a = a0, * const *b = b0; 856 857 return(strcmp((*b)->nl.n_un.n_name, (*a)->nl.n_un.n_name)); 858 } 859 860 int 861 value(const void *a0, const void *b0) 862 { 863 struct xnlist * const *a = a0, * const *b = b0; 864 865 if (SYMBOL_TYPE((*a)->nl.n_type) == N_UNDF) 866 if (SYMBOL_TYPE((*b)->nl.n_type) == N_UNDF) 867 return(0); 868 else 869 return(-1); 870 else if (SYMBOL_TYPE((*b)->nl.n_type) == N_UNDF) 871 return(1); 872 if (rev) { 873 if ((*a)->nl.n_value == (*b)->nl.n_value) 874 return(rname(a0, b0)); 875 return((*b)->nl.n_value > (*a)->nl.n_value ? 1 : -1); 876 } else { 877 if ((*a)->nl.n_value == (*b)->nl.n_value) 878 return(fname(a0, b0)); 879 return((*a)->nl.n_value > (*b)->nl.n_value ? 1 : -1); 880 } 881 } 882 883 #define CPPFILT "/usr/bin/c++filt" 884 885 void 886 pipe2cppfilt(void) 887 { 888 int pip[2]; 889 char *argv[2]; 890 891 argv[0] = "c++filt"; 892 argv[1] = NULL; 893 894 if (pipe(pip) == -1) 895 err(1, "pipe"); 896 switch(fork()) { 897 case -1: 898 err(1, "fork"); 899 default: 900 dup2(pip[0], 0); 901 close(pip[0]); 902 close(pip[1]); 903 execve(CPPFILT, argv, NULL); 904 err(1, "execve"); 905 case 0: 906 dup2(pip[1], 1); 907 close(pip[1]); 908 close(pip[0]); 909 } 910 } 911 912 void 913 usage(void) 914 { 915 extern char *__progname; 916 917 if (issize) 918 fprintf(stderr, "usage: %s [-tw] [file ...]\n", __progname); 919 else 920 fprintf(stderr, "usage: %s [-AaCDegnoPprsuw] [-t d|o|x] [file ...]\n", 921 __progname); 922 exit(1); 923 } 924