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