1 /* $OpenBSD: nm.c,v 1.54 2019/03/03 16:07:39 schwarze 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.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]) + 1; 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 - 1; 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 return (1); 385 } 386 387 printf("\nArchive index:\n"); 388 num = betoh32(*symtab); 389 strtab = (char *)(symtab + num + 1); 390 for (ps = symtab + 1; num--; ps++, strtab += strlen(strtab) + 1) { 391 if (fseeko(fp, betoh32(*ps), SEEK_SET)) { 392 warn("%s: fseeko", name); 393 rval = 1; 394 break; 395 } 396 397 if (fread(&ar_head, sizeof(ar_head), 1, fp) != 1 || 398 memcmp(ar_head.ar_fmag, ARFMAG, sizeof(ar_head.ar_fmag))) { 399 warnx("%s: member fseeko", name); 400 rval = 1; 401 break; 402 } 403 404 *p = '\0'; 405 if (mmbr_name(&ar_head, &p, 0, &namelen, fp)) { 406 rval = 1; 407 break; 408 } 409 410 printf("%s in %s\n", strtab, p); 411 } 412 413 fseeko(fp, restore, SEEK_SET); 414 415 free(p); 416 MUNMAP(symtab, len); 417 return (rval); 418 } 419 420 /* 421 * show_symdef() 422 * show archive ranlib index (gob) 423 */ 424 int 425 show_symdef(off_t off, u_long len, const char *name, FILE *fp) 426 { 427 struct ranlib *prn, *eprn; 428 struct ar_hdr ar_head; 429 char *symdef; 430 char *strtab, *p; 431 u_long size; 432 int namelen, rval = 0; 433 434 MMAP(symdef, len, PROT_READ, MAP_PRIVATE|MAP_FILE, fileno(fp), off); 435 if (symdef == MAP_FAILED) 436 return (1); 437 if (usemmap) 438 (void)madvise(symdef, len, MADV_SEQUENTIAL); 439 440 namelen = sizeof(ar_head.ar_name); 441 if ((p = malloc(sizeof(ar_head.ar_name))) == NULL) { 442 warn("%s: malloc", name); 443 MUNMAP(symdef, len); 444 return (1); 445 } 446 447 size = *(u_long *)symdef; 448 prn = (struct ranlib *)(symdef + sizeof(u_long)); 449 eprn = prn + size / sizeof(*prn); 450 strtab = symdef + sizeof(u_long) + size + sizeof(u_long); 451 452 printf("\nArchive index:\n"); 453 for (; prn < eprn; prn++) { 454 if (fseeko(fp, prn->ran_off, SEEK_SET)) { 455 warn("%s: fseeko", name); 456 rval = 1; 457 break; 458 } 459 460 if (fread(&ar_head, sizeof(ar_head), 1, fp) != 1 || 461 memcmp(ar_head.ar_fmag, ARFMAG, sizeof(ar_head.ar_fmag))) { 462 warnx("%s: member fseeko", name); 463 rval = 1; 464 break; 465 } 466 467 *p = '\0'; 468 if (mmbr_name(&ar_head, &p, 0, &namelen, fp)) { 469 rval = 1; 470 break; 471 } 472 473 printf("%s in %s\n", strtab + prn->ran_un.ran_strx, p); 474 } 475 476 free(p); 477 MUNMAP(symdef, len); 478 return (rval); 479 } 480 481 /* 482 * show_archive() 483 * show symbols in the given archive file 484 */ 485 int 486 show_archive(int count, const char *fname, FILE *fp) 487 { 488 struct ar_hdr ar_head; 489 union hdr exec_head; 490 int i, rval; 491 off_t last_ar_off, foff, symtaboff; 492 char *name; 493 int baselen, namelen; 494 u_long mmbrlen, symtablen; 495 496 baselen = strlen(fname) + 3; 497 if (posix_output) 498 baselen += 2; 499 namelen = sizeof(ar_head.ar_name); 500 if ((name = malloc(baselen + namelen)) == NULL) 501 err(1, NULL); 502 503 rval = 0; 504 nametab = NULL; 505 symtaboff = 0; 506 symtablen = 0; 507 508 /* while there are more entries in the archive */ 509 while (fread(&ar_head, sizeof(ar_head), 1, fp) == 1) { 510 /* bad archive entry - stop processing this archive */ 511 if (memcmp(ar_head.ar_fmag, ARFMAG, sizeof(ar_head.ar_fmag))) { 512 warnx("%s: bad format archive header", fname); 513 rval = 1; 514 break; 515 } 516 517 /* remember start position of current archive object */ 518 last_ar_off = ftello(fp); 519 mmbrlen = atol(ar_head.ar_size); 520 521 if (strncmp(ar_head.ar_name, RANLIBMAG, 522 sizeof(RANLIBMAG) - 1) == 0) { 523 if (!issize && armap && 524 show_symdef(last_ar_off, mmbrlen, fname, fp)) { 525 rval = 1; 526 break; 527 } 528 goto skip; 529 } else if (strncmp(ar_head.ar_name, SYMTABMAG, 530 sizeof(SYMTABMAG) - 1) == 0) { 531 /* if nametab hasn't been seen yet -- doit later */ 532 if (!nametab) { 533 symtablen = mmbrlen; 534 symtaboff = last_ar_off; 535 goto skip; 536 } 537 538 /* load the Sys5 long names table */ 539 } else if (strncmp(ar_head.ar_name, STRTABMAG, 540 sizeof(STRTABMAG) - 1) == 0) { 541 char *p; 542 543 if ((nametab = malloc(mmbrlen)) == NULL) { 544 warn("%s: nametab", fname); 545 rval = 1; 546 break; 547 } 548 549 if (fread(nametab, mmbrlen, (size_t)1, fp) != 1) { 550 warnx("%s: premature EOF", fname); 551 rval = 1; 552 break; 553 } 554 555 for (p = nametab, i = mmbrlen; i--; p++) 556 if (*p == '\n') 557 *p = '\0'; 558 559 if (issize || !armap || !symtablen || !symtaboff) 560 goto skip; 561 } 562 #ifdef __mips64 563 else if (memcmp(ar_head.ar_name, SYM64MAG, 564 sizeof(ar_head.ar_name)) == 0) { 565 /* IRIX6-compatible archive map */ 566 goto skip; 567 } 568 #endif 569 570 if (!issize && armap && symtablen && symtaboff) { 571 if (show_symtab(symtaboff, symtablen, fname, fp)) { 572 rval = 1; 573 break; 574 } else { 575 symtaboff = 0; 576 symtablen = 0; 577 } 578 } 579 580 /* 581 * construct a name of the form "archive.a:obj.o:" for the 582 * current archive entry if the object name is to be printed 583 * on each output line 584 */ 585 *name = '\0'; 586 if (posix_output) 587 snprintf(name, baselen - 1, "%s[", fname); 588 else if (count > 1) 589 snprintf(name, baselen - 1, "%s:", fname); 590 591 if (mmbr_name(&ar_head, &name, baselen, &namelen, fp)) { 592 rval = 1; 593 break; 594 } 595 596 if (posix_output) 597 strlcat(name, "]", baselen + namelen); 598 599 foff = ftello(fp); 600 601 /* get and check current object's header */ 602 if (fread((char *)&exec_head, sizeof(exec_head), 603 (size_t)1, fp) != 1) { 604 warnx("%s: premature EOF", fname); 605 rval = 1; 606 break; 607 } 608 609 rval |= show_file(2, non_object_warning, name, fp, foff, &exec_head); 610 /* 611 * skip to next archive object - it starts at the next 612 * even byte boundary 613 */ 614 #define even(x) (((x) + 1) & ~1) 615 skip: if (fseeko(fp, last_ar_off + even(mmbrlen), SEEK_SET)) { 616 warn("%s", fname); 617 rval = 1; 618 break; 619 } 620 } 621 free(nametab); 622 nametab = NULL; 623 free(name); 624 return(rval); 625 } 626 627 char *stab; 628 629 /* 630 * show_file() 631 * show symbols from the object file pointed to by fp. The current 632 * file pointer for fp is expected to be at the beginning of an object 633 * file header. 634 */ 635 int 636 show_file(int count, int warn_fmt, const char *name, FILE *fp, off_t foff, union hdr *head) 637 { 638 u_long text, data, bss, total; 639 struct xnlist *np, *names, **snames; 640 int i, nrawnames, nnames; 641 size_t stabsize; 642 643 if (IS_ELF(head->elf32) && 644 head->elf32.e_ident[EI_CLASS] == ELFCLASS32 && 645 head->elf32.e_ident[EI_VERSION] == ELF_TARG_VER) { 646 void *shdr; 647 648 if (!(shdr = elf32_load_shdrs(name, fp, foff, &head->elf32))) 649 return (1); 650 651 i = issize? 652 elf32_size(&head->elf32, shdr, &text, &data, &bss) : 653 elf32_symload(name, fp, foff, &head->elf32, shdr, 654 &names, &snames, &stabsize, &nrawnames); 655 free(shdr); 656 if (i) 657 return (i); 658 659 } else if (IS_ELF(head->elf64) && 660 head->elf64.e_ident[EI_CLASS] == ELFCLASS64 && 661 head->elf64.e_ident[EI_VERSION] == ELF_TARG_VER) { 662 void *shdr; 663 664 if (!(shdr = elf64_load_shdrs(name, fp, foff, &head->elf64))) 665 return (1); 666 667 i = issize? 668 elf64_size(&head->elf64, shdr, &text, &data, &bss) : 669 elf64_symload(name, fp, foff, &head->elf64, shdr, 670 &names, &snames, &stabsize, &nrawnames); 671 free(shdr); 672 if (i) 673 return (i); 674 } else { 675 if (warn_fmt) 676 warnx("%s: bad format", name); 677 return (1); 678 } 679 680 if (issize) { 681 static int first = 1; 682 683 if (first) { 684 first = 0; 685 printf("text\tdata\tbss\tdec\thex\n"); 686 } 687 688 total = text + data + bss; 689 printf("%lu\t%lu\t%lu\t%lu\t%lx", 690 text, data, bss, total, total); 691 if (count > 1) 692 (void)printf("\t%s", name); 693 694 total_text += text; 695 total_data += data; 696 total_bss += bss; 697 total_total += total; 698 699 printf("\n"); 700 return (0); 701 } 702 /* else we are nm */ 703 704 /* 705 * it seems that string table is sequential 706 * relative to the symbol table order 707 */ 708 if (sfunc == NULL && usemmap) 709 (void)madvise(stab, stabsize, MADV_SEQUENTIAL); 710 711 /* 712 * fix up the symbol table and filter out unwanted entries 713 * 714 * common symbols are characterized by a n_type of N_UNDF and a 715 * non-zero n_value -- change n_type to N_COMM for all such 716 * symbols to make life easier later. 717 * 718 * filter out all entries which we don't want to print anyway 719 */ 720 for (np = names, i = nnames = 0; i < nrawnames; np++, i++) { 721 /* 722 * make n_un.n_name a character pointer by adding the string 723 * table's base to n_un.n_strx 724 * 725 * don't mess with zero offsets 726 */ 727 if (np->nl.n_un.n_strx) 728 np->nl.n_un.n_name = stab + np->nl.n_un.n_strx; 729 else 730 np->nl.n_un.n_name = ""; 731 if (print_only_external_symbols && !IS_EXTERNAL(np->nl.n_type)) 732 continue; 733 if (print_only_undefined_symbols && 734 SYMBOL_TYPE(np->nl.n_type) != N_UNDF) 735 continue; 736 737 snames[nnames++] = np; 738 } 739 740 /* sort the symbol table if applicable */ 741 if (sfunc) 742 qsort(snames, (size_t)nnames, sizeof(*snames), sfunc); 743 744 if (count > 1) 745 (void)printf("\n%s:\n", name); 746 747 /* print out symbols */ 748 for (i = 0; i < nnames; i++) 749 print_symbol(name, snames[i]); 750 751 free(snames); 752 free(names); 753 MUNMAP(stab, stabsize); 754 return(0); 755 } 756 757 char * 758 symname(struct xnlist *sym) 759 { 760 return sym->nl.n_un.n_name; 761 } 762 763 /* 764 * print_symbol() 765 * show one symbol 766 */ 767 void 768 print_symbol(const char *name, struct xnlist *sym) 769 { 770 if (print_file_each_line) { 771 if (posix_output) 772 (void)printf("%s: ", name); 773 else 774 (void)printf("%s:", name); 775 } 776 777 if (posix_output) { 778 (void)printf("%s %c ", symname(sym), typeletter(sym)); 779 if (SYMBOL_TYPE(sym->nl.n_type) != N_UNDF) 780 (void)printf(posix_fmtstr, sym->nl.n_value, 781 sym->n_size); 782 (void)printf("\n"); 783 } else { 784 /* 785 * handle undefined-only format especially (no space is 786 * left for symbol values, no type field is printed) 787 */ 788 if (!print_only_undefined_symbols) { 789 /* print symbol's value */ 790 if (SYMBOL_TYPE(sym->nl.n_type) == N_UNDF) 791 (void)printf(" "); 792 else 793 (void)printf("%08lx", sym->nl.n_value); 794 795 /* print type information */ 796 if (show_extensions) 797 (void)printf(" %c ", typeletter(sym)); 798 else 799 (void)printf(" %c ", typeletter(sym)); 800 } 801 802 (void)puts(symname(sym)); 803 } 804 } 805 806 /* 807 * typeletter() 808 * return a description letter for the given basic type code of an 809 * symbol table entry. The return value will be upper case for 810 * external, lower case for internal symbols. 811 */ 812 char 813 typeletter(struct xnlist *np) 814 { 815 int ext = IS_EXTERNAL(np->nl.n_type); 816 817 if (np->nl.n_other) 818 return np->nl.n_other; 819 820 switch(SYMBOL_TYPE(np->nl.n_type)) { 821 case N_ABS: 822 return(ext? 'A' : 'a'); 823 case N_BSS: 824 return(ext? 'B' : 'b'); 825 case N_COMM: 826 return(ext? 'C' : 'c'); 827 case N_DATA: 828 return(ext? 'D' : 'd'); 829 case N_FN: 830 /* NOTE: N_FN == N_WARNING, 831 * in this case, the N_EXT bit is to considered as 832 * part of the symbol's type itself. 833 */ 834 return(ext? 'F' : 'W'); 835 case N_TEXT: 836 return(ext? 'T' : 't'); 837 case N_SIZE: 838 return(ext? 'S' : 's'); 839 case N_UNDF: 840 return(ext? 'U' : 'u'); 841 } 842 return('?'); 843 } 844 845 int 846 fname(const void *a0, const void *b0) 847 { 848 struct xnlist * const *a = a0, * const *b = b0; 849 850 return(strcmp((*a)->nl.n_un.n_name, (*b)->nl.n_un.n_name)); 851 } 852 853 int 854 rname(const void *a0, const void *b0) 855 { 856 struct xnlist * const *a = a0, * const *b = b0; 857 858 return(strcmp((*b)->nl.n_un.n_name, (*a)->nl.n_un.n_name)); 859 } 860 861 int 862 value(const void *a0, const void *b0) 863 { 864 struct xnlist * const *a = a0, * const *b = b0; 865 866 if (SYMBOL_TYPE((*a)->nl.n_type) == N_UNDF) 867 if (SYMBOL_TYPE((*b)->nl.n_type) == N_UNDF) 868 return(0); 869 else 870 return(-1); 871 else if (SYMBOL_TYPE((*b)->nl.n_type) == N_UNDF) 872 return(1); 873 if (rev) { 874 if ((*a)->nl.n_value == (*b)->nl.n_value) 875 return(rname(a0, b0)); 876 return((*b)->nl.n_value > (*a)->nl.n_value ? 1 : -1); 877 } else { 878 if ((*a)->nl.n_value == (*b)->nl.n_value) 879 return(fname(a0, b0)); 880 return((*a)->nl.n_value > (*b)->nl.n_value ? 1 : -1); 881 } 882 } 883 884 #define CPPFILT "/usr/bin/c++filt" 885 886 void 887 pipe2cppfilt(void) 888 { 889 int pip[2]; 890 char *argv[2]; 891 892 argv[0] = "c++filt"; 893 argv[1] = NULL; 894 895 if (pipe(pip) == -1) 896 err(1, "pipe"); 897 switch(fork()) { 898 case -1: 899 err(1, "fork"); 900 default: 901 dup2(pip[0], 0); 902 close(pip[0]); 903 close(pip[1]); 904 execve(CPPFILT, argv, NULL); 905 err(1, "execve"); 906 case 0: 907 dup2(pip[1], 1); 908 close(pip[1]); 909 close(pip[0]); 910 } 911 } 912 913 void 914 usage(void) 915 { 916 extern char *__progname; 917 918 if (issize) 919 fprintf(stderr, "usage: %s [-tw] [file ...]\n", __progname); 920 else 921 fprintf(stderr, "usage: %s [-AaCDegnoPprsuw] [-t d|o|x] [file ...]\n", 922 __progname); 923 exit(1); 924 } 925