Annotation of src/usr.bin/nm/nm.c, Revision 1.20
1.20 ! mickey 1: /* $OpenBSD: nm.c,v 1.19 2003/06/10 22:20:49 deraadt Exp $ */
1.2 deraadt 2: /* $NetBSD: nm.c,v 1.7 1996/01/14 23:04:03 pk Exp $ */
1.1 deraadt 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.
1.18 millert 19: * 3. Neither the name of the University nor the names of its contributors
1.1 deraadt 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: #ifndef lint
1.20 ! mickey 37: static const char copyright[] =
1.1 deraadt 38: "@(#) Copyright (c) 1989, 1993\n\
39: The Regents of the University of California. All rights reserved.\n";
40: #endif /* not lint */
41:
42: #if 0
1.20 ! mickey 43: static const char sccsid[] = "@(#)nm.c 8.1 (Berkeley) 6/6/93";
1.1 deraadt 44: #endif
1.20 ! mickey 45: static const char rcsid[] = "$OpenBSD: nm.c,v 1.19 2003/06/10 22:20:49 deraadt Exp $";
1.1 deraadt 46:
1.5 deraadt 47: #include <sys/param.h>
1.20 ! mickey 48: #include <sys/mman.h>
1.1 deraadt 49: #include <a.out.h>
1.20 ! mickey 50: #include <elf_abi.h>
1.1 deraadt 51: #include <stab.h>
52: #include <ar.h>
53: #include <ranlib.h>
54: #include <unistd.h>
1.2 deraadt 55: #include <err.h>
1.1 deraadt 56: #include <ctype.h>
1.14 espie 57: #include <link.h>
1.20 ! mickey 58: #ifdef __ELF__
! 59: #include <link_aout.h>
! 60: #endif
1.1 deraadt 61: #include <stdio.h>
62: #include <stdlib.h>
63: #include <string.h>
1.20 ! mickey 64: #include <getopt.h>
1.8 espie 65: /* XXX get shared code to handle byte-order swaps */
66: #include "byte.c"
1.20 ! mickey 67: #include "elf.c"
1.7 niklas 68:
1.20 ! mickey 69: #ifdef MID_MACHINE_OVERRIDE
! 70: #undef MID_MACHINE
! 71: #define MID_MACHINE MID_MACHINE_OVERRIDE
! 72: #endif
1.1 deraadt 73:
1.20 ! mickey 74: #define SYMTABMAG "/ "
! 75: #define STRTABMAG "//"
! 76:
! 77: union hdr {
! 78: struct exec aout;
! 79: Elf_Ehdr elf;
! 80: };
! 81:
! 82: int armap;
! 83: int demangle;
! 84: int non_object_warning;
1.1 deraadt 85: int print_only_external_symbols;
86: int print_only_undefined_symbols;
87: int print_all_symbols;
88: int print_file_each_line;
1.20 ! mickey 89: int show_extensions;
! 90: int issize;
! 91:
! 92: /* size vars */
! 93: unsigned long total_text, total_data, total_bss, total_total;
! 94: int non_object_warning, print_totals;
1.1 deraadt 95:
96: int rev;
1.16 millert 97: int fname(const void *, const void *);
98: int rname(const void *, const void *);
99: int value(const void *, const void *);
100: int (*sfunc)(const void *, const void *) = fname;
101: char *otherstring(struct nlist *);
102: char *typestring(unsigned int);
1.20 ! mickey 103: char typeletter(struct nlist *, int);
1.8 espie 104:
1.1 deraadt 105: /* some macros for symbol type (nlist.n_type) handling */
106: #define IS_DEBUGGER_SYMBOL(x) ((x) & N_STAB)
107: #define IS_EXTERNAL(x) ((x) & N_EXT)
108: #define SYMBOL_TYPE(x) ((x) & (N_TYPE | N_STAB))
109:
1.16 millert 110: void pipe2cppfilt(void);
111: void usage(void);
112: char *symname(struct nlist *);
1.20 ! mickey 113: int process_file(int, const char *);
! 114: int show_archive(int, const char *, FILE *);
! 115: int show_file(int, int, const char *, FILE *fp, off_t, union hdr *);
! 116: void print_symbol(const char *, struct nlist *, int);
! 117: int elf_symload(const char *, FILE *, off_t, Elf_Ehdr *, Elf_Shdr *);
! 118:
! 119: #define OPTSTRING_NM "aABCegnoprsuvVw"
! 120: const struct option longopts_nm[] = {
! 121: { "debug-syms", no_argument, 0, 'a' },
! 122: { "demangle", no_argument, 0, 'C' },
! 123: /* { "dynamic", no_argument, 0, 'D' }, */
! 124: { "extern-only", no_argument, 0, 'g' },
! 125: /* { "line-numbers", no_argument, 0, 'l' }, */
! 126: { "no-sort", no_argument, 0, 'p' },
! 127: { "numeric-sort", no_argument, 0, 'n' },
! 128: { "print-armap", no_argument, 0, 's' },
! 129: { "print-file-name", no_argument, 0, 'o' },
! 130: { "reverse-sort", no_argument, 0, 'r' },
! 131: /* { "size-sort", no_argument, &szval, 1 }, */
! 132: { "undefined-only", no_argument, 0, 'u' },
! 133: { "version", no_argument, 0, 'V' },
! 134: { "help", no_argument, 0, '?' },
! 135: { NULL }
! 136: };
1.10 espie 137:
1.1 deraadt 138: /*
139: * main()
140: * parse command line, execute process_file() for each file
141: * specified on the command line.
142: */
1.20 ! mickey 143: int
1.19 deraadt 144: main(int argc, char *argv[])
1.1 deraadt 145: {
1.20 ! mickey 146: extern char *__progname;
1.1 deraadt 147: extern int optind;
1.20 ! mickey 148: const char *optstr;
! 149: const struct option *lopts;
! 150: int ch, eval;
! 151:
! 152: optstr = OPTSTRING_NM;
! 153: lopts = longopts_nm;
! 154: if (!strcmp(__progname, "size")) {
! 155: issize++;
! 156: optstr = "tw";
! 157: lopts = NULL;
! 158: }
1.1 deraadt 159:
1.20 ! mickey 160: while ((ch = getopt_long(argc, argv, optstr, lopts, NULL)) != -1) {
1.1 deraadt 161: switch (ch) {
162: case 'a':
163: print_all_symbols = 1;
164: break;
1.10 espie 165: case 'B':
166: /* no-op, compat with gnu-nm */
167: break;
168: case 'C':
169: demangle = 1;
170: break;
1.12 espie 171: case 'e':
172: show_extensions = 1;
173: break;
1.1 deraadt 174: case 'g':
175: print_only_external_symbols = 1;
176: break;
177: case 'n':
1.20 ! mickey 178: case 'v':
1.1 deraadt 179: sfunc = value;
180: break;
1.20 ! mickey 181: case 'A':
1.1 deraadt 182: case 'o':
183: print_file_each_line = 1;
184: break;
185: case 'p':
186: sfunc = NULL;
187: break;
188: case 'r':
189: rev = 1;
190: break;
1.20 ! mickey 191: case 's':
! 192: armap = 1;
! 193: break;
1.1 deraadt 194: case 'u':
195: print_only_undefined_symbols = 1;
196: break;
1.20 ! mickey 197: case 'V':
! 198: fprintf(stderr, "%s\n", rcsid);
! 199: exit(0);
1.1 deraadt 200: case 'w':
1.20 ! mickey 201: non_object_warning = 1;
1.1 deraadt 202: break;
1.20 ! mickey 203: case 't':
! 204: if (issize) {
! 205: print_totals = 1;
! 206: break;
! 207: }
1.1 deraadt 208: case '?':
209: default:
210: usage();
211: }
212: }
1.10 espie 213:
214: if (demangle)
215: pipe2cppfilt();
1.1 deraadt 216: argv += optind;
1.20 ! mickey 217: argc -= optind;
1.1 deraadt 218:
219: if (rev && sfunc == fname)
220: sfunc = rname;
221:
1.20 ! mickey 222: eval = 0;
! 223: if (*argv)
1.1 deraadt 224: do {
1.20 ! mickey 225: eval |= process_file(argc, *argv);
1.1 deraadt 226: } while (*++argv);
1.20 ! mickey 227: else
! 228: eval |= process_file(1, "a.out");
! 229:
! 230: if (issize && print_totals)
! 231: printf("\n%lu\t%lu\t%lu\t%lu\t%lx\tTOTAL\n",
! 232: total_text, total_data, total_bss,
! 233: total_total, total_total);
! 234: exit(eval);
1.1 deraadt 235: }
236:
237: /*
238: * process_file()
239: * show symbols in the file given as an argument. Accepts archive and
240: * object files as input.
241: */
1.20 ! mickey 242: int
! 243: process_file(int count, const char *fname)
1.1 deraadt 244: {
1.20 ! mickey 245: union hdr exec_head;
1.1 deraadt 246: FILE *fp;
247: int retval;
248: char magic[SARMAG];
249:
250: if (!(fp = fopen(fname, "r"))) {
1.6 deraadt 251: warn("cannot read %s", fname);
1.1 deraadt 252: return(1);
253: }
254:
1.20 ! mickey 255: if (!issize && count > 1)
1.1 deraadt 256: (void)printf("\n%s:\n", fname);
257:
258: /*
259: * first check whether this is an object file - read a object
260: * header, and skip back to the beginning
261: */
262: if (fread((char *)&exec_head, sizeof(exec_head), (size_t)1, fp) != 1) {
1.2 deraadt 263: warnx("%s: bad format", fname);
1.1 deraadt 264: (void)fclose(fp);
265: return(1);
266: }
267: rewind(fp);
268:
269: /* this could be an archive */
1.20 ! mickey 270: if (!IS_ELF(exec_head.elf) && N_BADMAG(exec_head.aout)) {
1.1 deraadt 271: if (fread(magic, sizeof(magic), (size_t)1, fp) != 1 ||
272: strncmp(magic, ARMAG, SARMAG)) {
1.2 deraadt 273: warnx("%s: not object file or archive", fname);
1.1 deraadt 274: (void)fclose(fp);
275: return(1);
276: }
1.20 ! mickey 277: retval = show_archive(count, fname, fp);
1.1 deraadt 278: } else
1.20 ! mickey 279: retval = show_file(count, 1, fname, fp, 0, &exec_head);
1.1 deraadt 280: (void)fclose(fp);
281: return(retval);
282: }
283:
1.20 ! mickey 284: char *nametab;
! 285:
! 286: /*
! 287: *
! 288: * given the archive member header -- produce member name
! 289: */
! 290: int
! 291: mmbr_name(struct ar_hdr *arh, char **name, int baselen, int *namelen, FILE *fp)
! 292: {
! 293: char *p = *name + strlen(*name);
! 294: long i;
! 295:
! 296: if (nametab && arh->ar_name[0] == '/') {
! 297: int len;
! 298:
! 299: i = atol(&arh->ar_name[1]);
! 300: len = strlen(&nametab[i]);
! 301: if (len > *namelen) {
! 302: p -= (long)*name;
! 303: if ((*name = realloc(*name, baselen+len)) == NULL)
! 304: err(1, NULL);
! 305: *namelen = len;
! 306: p += (long)*name;
! 307: }
! 308: strlcpy(p, &nametab[i], len);
! 309: p += len;
! 310: } else
! 311: #ifdef AR_EFMT1
! 312: /*
! 313: * BSD 4.4 extended AR format: #1/<namelen>, with name as the
! 314: * first <namelen> bytes of the file
! 315: */
! 316: if ((arh->ar_name[0] == '#') &&
! 317: (arh->ar_name[1] == '1') &&
! 318: (arh->ar_name[2] == '/') &&
! 319: (isdigit(arh->ar_name[3]))) {
! 320: int len = atoi(&arh->ar_name[3]);
! 321:
! 322: if (len > *namelen) {
! 323: p -= (long)*name;
! 324: if ((*name = realloc(*name, baselen+len)) == NULL)
! 325: err(1, NULL);
! 326: *namelen = len;
! 327: p += (long)*name;
! 328: }
! 329: if (fread(p, len, 1, fp) != 1) {
! 330: warnx("%s: premature EOF", *name);
! 331: free(*name);
! 332: return(1);
! 333: }
! 334: p += len;
! 335: } else
! 336: #endif
! 337: for (i = 0; i < sizeof(arh->ar_name); ++i)
! 338: if (arh->ar_name[i] && arh->ar_name[i] != ' ')
! 339: *p++ = arh->ar_name[i];
! 340: *p = '\0';
! 341: if (p[-1] == '/')
! 342: *--p = '\0';
! 343:
! 344: return (0);
! 345: }
! 346:
! 347: /*
! 348: * show_symtab()
! 349: * show archive ranlib index (fs5)
! 350: */
! 351: int
! 352: show_symtab(off_t off, u_long len, const char *name, FILE *fp)
! 353: {
! 354: struct ar_hdr ar_head;
! 355: int *symtab, *ps;
! 356: char *strtab, *p;
! 357: int num, rval = 0;
! 358: int namelen;
! 359:
! 360: if ((symtab = mmap(NULL, len, PROT_READ,
! 361: MAP_PRIVATE|MAP_FILE, fileno(fp), off)) == MAP_FAILED) {
! 362: warn("%s: mmap", name);
! 363: return (1);
! 364: }
! 365:
! 366: namelen = sizeof(ar_head.ar_name);
! 367: if ((p = malloc(sizeof(ar_head.ar_name))) == NULL) {
! 368: warn("%s: malloc", name);
! 369: munmap(symtab, len);
! 370: return (1);
! 371: }
! 372:
! 373: printf("\nArchive index:\n");
! 374: num = betoh32(*symtab);
! 375: strtab = (char *)(symtab + num + 1);
! 376: for (ps = symtab + 1; num--; ps++, strtab += strlen(strtab) + 1) {
! 377: if (fseeko(fp, betoh32(*ps), SEEK_SET)) {
! 378: warn("%s: fseeko", name);
! 379: rval = 1;
! 380: break;
! 381: }
! 382:
! 383: if (fread(&ar_head, sizeof(ar_head), 1, fp) != 1 ||
! 384: memcmp(ar_head.ar_fmag, ARFMAG, sizeof(ar_head.ar_fmag))) {
! 385: warnx("%s: member fseeko", name);
! 386: rval = 1;
! 387: break;
! 388: }
! 389:
! 390: *p = '\0';
! 391: if (mmbr_name(&ar_head, &p, 0, &namelen, fp)) {
! 392: rval = 1;
! 393: break;
! 394: }
! 395:
! 396: printf("%s in %s\n", strtab, p);
! 397: }
! 398:
! 399: free(p);
! 400: munmap(symtab, len);
! 401: return (rval);
! 402: }
! 403:
! 404: /*
! 405: * show_symdef()
! 406: * show archive ranlib index (gob)
! 407: */
! 408: int
! 409: show_symdef(off_t off, u_long len, const char *name, FILE *fp)
! 410: {
! 411: struct ranlib *prn, *eprn;
! 412: struct ar_hdr ar_head;
! 413: void *symdef;
! 414: char *strtab, *p;
! 415: u_long size;
! 416: int namelen, rval = 0;
! 417:
! 418: if ((symdef = mmap(NULL, len, PROT_READ,
! 419: MAP_PRIVATE|MAP_FILE, fileno(fp), off)) == MAP_FAILED) {
! 420: warn("%s: mmap", name);
! 421: return (1);
! 422: }
! 423:
! 424: if (madvise(symdef, len, MADV_SEQUENTIAL)) {
! 425: warn("%s: madvise", name);
! 426: munmap(symdef, len);
! 427: return (1);
! 428: }
! 429:
! 430: namelen = sizeof(ar_head.ar_name);
! 431: if ((p = malloc(sizeof(ar_head.ar_name))) == NULL) {
! 432: warn("%s: malloc", name);
! 433: munmap(symdef, len);
! 434: return (1);
! 435: }
! 436:
! 437: size = *(u_long *)symdef;
! 438: prn = symdef + sizeof(u_long);
! 439: eprn = prn + size / sizeof(*prn);
! 440: strtab = symdef + sizeof(u_long) + size + sizeof(u_long);
! 441:
! 442: printf("\nArchive index:\n");
! 443: for (; prn < eprn; prn++) {
! 444: if (fseeko(fp, prn->ran_off, SEEK_SET)) {
! 445: warn("%s: fseeko", name);
! 446: rval = 1;
! 447: break;
! 448: }
! 449:
! 450: if (fread(&ar_head, sizeof(ar_head), 1, fp) != 1 ||
! 451: memcmp(ar_head.ar_fmag, ARFMAG, sizeof(ar_head.ar_fmag))) {
! 452: warnx("%s: member fseeko", name);
! 453: rval = 1;
! 454: break;
! 455: }
! 456:
! 457: *p = '\0';
! 458: if (mmbr_name(&ar_head, &p, 0, &namelen, fp)) {
! 459: rval = 1;
! 460: break;
! 461: }
! 462:
! 463: printf("%s in %s\n", strtab + prn->ran_un.ran_strx, p);
! 464: }
! 465:
! 466: free(p);
! 467: munmap(symdef, len);
! 468: return (rval);
! 469: }
! 470:
1.1 deraadt 471: /*
472: * show_archive()
473: * show symbols in the given archive file
474: */
1.20 ! mickey 475: int
! 476: show_archive(int count, const char *fname, FILE *fp)
1.1 deraadt 477: {
478: struct ar_hdr ar_head;
1.20 ! mickey 479: union hdr exec_head;
1.1 deraadt 480: int i, rval;
1.20 ! mickey 481: off_t last_ar_off, foff, symtaboff;
! 482: char *name;
1.1 deraadt 483: int baselen, namelen;
1.20 ! mickey 484: u_long mmbrlen, symtablen;
1.1 deraadt 485:
486: baselen = strlen(fname) + 3;
487: namelen = sizeof(ar_head.ar_name);
1.20 ! mickey 488: if ((name = malloc(baselen + namelen)) == NULL)
! 489: err(1, NULL);
1.1 deraadt 490:
491: rval = 0;
1.20 ! mickey 492: nametab = NULL;
! 493: symtaboff = 0;
! 494: symtablen = 0;
1.1 deraadt 495:
496: /* while there are more entries in the archive */
1.20 ! mickey 497: while (fread(&ar_head, sizeof(ar_head), 1, fp) == 1) {
1.1 deraadt 498: /* bad archive entry - stop processing this archive */
1.20 ! mickey 499: if (memcmp(ar_head.ar_fmag, ARFMAG, sizeof(ar_head.ar_fmag))) {
1.2 deraadt 500: warnx("%s: bad format archive header", fname);
1.20 ! mickey 501: rval = 1;
! 502: break;
1.1 deraadt 503: }
504:
505: /* remember start position of current archive object */
1.20 ! mickey 506: last_ar_off = ftello(fp);
! 507: mmbrlen = atol(ar_head.ar_size);
1.1 deraadt 508:
1.20 ! mickey 509: if (strncmp(ar_head.ar_name, RANLIBMAG,
! 510: sizeof(RANLIBMAG) - 1) == 0) {
! 511: if (!issize && armap &&
! 512: show_symdef(last_ar_off, mmbrlen, fname, fp)) {
! 513: rval = 1;
! 514: break;
! 515: }
1.1 deraadt 516: goto skip;
1.20 ! mickey 517: } else if (strncmp(ar_head.ar_name, SYMTABMAG,
! 518: sizeof(SYMTABMAG) - 1) == 0) {
! 519: /* if nametab hasn't been seen yet -- doit later */
! 520: if (!nametab) {
! 521: symtablen = mmbrlen;
! 522: symtaboff = last_ar_off;
! 523: goto skip;
! 524: }
! 525:
! 526: /* load the Sys5 long names table */
! 527: } else if (strncmp(ar_head.ar_name, STRTABMAG,
! 528: sizeof(STRTABMAG) - 1) == 0) {
! 529: char *p;
! 530:
! 531: if ((nametab = malloc(mmbrlen)) == NULL) {
! 532: warn("%s: nametab", fname);
! 533: rval = 1;
! 534: break;
! 535: }
! 536:
! 537: if (fread(nametab, mmbrlen, (size_t)1, fp) != 1) {
! 538: warnx("%s: premature EOF", fname);
! 539: rval = 1;
! 540: break;
! 541: }
! 542:
! 543: for (p = nametab, i = mmbrlen; i--; p++)
! 544: if (*p == '\n')
! 545: *p = '\0';
! 546:
! 547: if (issize || !armap || !symtablen || !symtaboff)
! 548: goto skip;
! 549: }
! 550:
! 551: if (!issize && armap && symtablen && symtaboff) {
! 552: if (show_symtab(symtaboff, symtablen, fname, fp)) {
! 553: rval = 1;
! 554: break;
! 555: } else {
! 556: symtaboff = 0;
! 557: symtablen = 0;
! 558: goto skip;
! 559: }
! 560: }
1.1 deraadt 561:
562: /*
563: * construct a name of the form "archive.a:obj.o:" for the
564: * current archive entry if the object name is to be printed
565: * on each output line
566: */
1.20 ! mickey 567: *name = '\0';
! 568: if (count > 1)
! 569: snprintf(name, baselen - 1, "%s:", fname);
! 570:
! 571: if (mmbr_name(&ar_head, &name, baselen, &namelen, fp)) {
! 572: rval = 1;
! 573: break;
1.17 deraadt 574: }
1.20 ! mickey 575:
! 576: foff = ftello(fp);
1.1 deraadt 577:
578: /* get and check current object's header */
579: if (fread((char *)&exec_head, sizeof(exec_head),
580: (size_t)1, fp) != 1) {
1.20 ! mickey 581: warnx("%s: premature EOF", fname);
! 582: rval = 1;
! 583: break;
1.1 deraadt 584: }
585:
1.20 ! mickey 586: rval |= show_file(2, non_object_warning, name, fp, foff, &exec_head);
1.1 deraadt 587: /*
588: * skip to next archive object - it starts at the next
589: * even byte boundary
590: */
591: #define even(x) (((x) + 1) & ~1)
1.20 ! mickey 592: skip: if (fseeko(fp, last_ar_off + even(mmbrlen), SEEK_SET)) {
1.2 deraadt 593: warn("%s", fname);
1.20 ! mickey 594: rval = 1;
! 595: break;
1.1 deraadt 596: }
597: }
1.20 ! mickey 598: if (nametab) {
! 599: free(nametab);
! 600: nametab = NULL;
! 601: }
! 602: free(name);
1.1 deraadt 603: return(rval);
604: }
605:
1.20 ! mickey 606: struct nlist *names;
! 607: struct nlist **snames;
! 608: char *stab;
! 609: int nnames, nrawnames, stabsize;
! 610:
1.1 deraadt 611: /*
1.20 ! mickey 612: * show_file()
1.1 deraadt 613: * show symbols from the object file pointed to by fp. The current
614: * file pointer for fp is expected to be at the beginning of an a.out
615: * header.
616: */
1.20 ! mickey 617: int
! 618: show_file(int count, int warn_fmt, const char *name, FILE *fp, off_t foff, union hdr *head)
1.1 deraadt 619: {
1.20 ! mickey 620: u_long text, data, bss, total;
! 621: struct nlist *np;
! 622: Elf_Shdr *shdr;
! 623: off_t staboff;
! 624: int i, aout;
! 625:
! 626: aout = 0;
! 627: if (IS_ELF(head->elf) &&
! 628: head->elf.e_ident[EI_CLASS] == ELF_TARG_CLASS &&
! 629: head->elf.e_ident[EI_VERSION] == ELF_TARG_VER) {
! 630:
! 631: elf_fix_header(&head->elf);
! 632:
! 633: if ((shdr = malloc(head->elf.e_shentsize *
! 634: head->elf.e_shnum)) == NULL) {
! 635: warn("%s: malloc shdr", name);
! 636: return (1);
! 637: }
! 638:
! 639: if (fseeko(fp, foff + head->elf.e_shoff, SEEK_SET)) {
! 640: warn("%s: fseeko", name);
! 641: free(shdr);
! 642: return (1);
! 643: }
! 644:
! 645: if (fread(shdr, head->elf.e_shentsize, head->elf.e_shnum,
! 646: fp) != head->elf.e_shnum) {
! 647: warnx("%s: premature EOF", name);
! 648: free(shdr);
! 649: return(1);
! 650: }
! 651:
! 652: elf_fix_shdrs(&head->elf, shdr);
! 653:
! 654: if (issize) {
! 655: text = data = bss = 0;
! 656: for (i = 0; i < head->elf.e_shnum; i++) {
! 657: if (!(shdr[i].sh_flags & SHF_ALLOC))
! 658: ;
! 659: else if (shdr[i].sh_flags & SHF_EXECINSTR ||
! 660: !(shdr[i].sh_flags & SHF_WRITE))
! 661: text += shdr[i].sh_size;
! 662: else if (shdr[i].sh_type == SHT_NOBITS)
! 663: bss += shdr[i].sh_size;
! 664: else
! 665: data += shdr[i].sh_size;
! 666: }
! 667: free(shdr);
! 668: } else {
! 669: i = elf_symload(name, fp, foff, &head->elf, shdr);
! 670: free(shdr);
! 671: if (i)
! 672: return (i);
! 673: }
! 674:
! 675: } else if (BAD_OBJECT(head->aout)) {
! 676: if (warn_fmt)
! 677: warnx("%s: bad format", name);
! 678: return (1);
! 679: } else do {
! 680: aout++;
! 681:
! 682: fix_header_order(&head->aout);
! 683:
! 684: if (issize) {
! 685: text = head->aout.a_text;
! 686: data = head->aout.a_data;
! 687: bss = head->aout.a_bss;
! 688: break;
! 689: }
! 690:
! 691: /* stop if the object file contains no symbol table */
! 692: if (!head->aout.a_syms) {
! 693: warnx("%s: no name list", name);
! 694: return(1);
! 695: }
! 696:
! 697: if (fseeko(fp, foff + N_SYMOFF(head->aout), SEEK_SET)) {
! 698: warn("%s", name);
! 699: return(1);
! 700: }
! 701:
! 702: /* get memory for the symbol table */
! 703: if ((names = malloc(head->aout.a_syms)) == NULL) {
! 704: warn("%s: malloc names", name);
! 705: return (1);
! 706: }
! 707: nrawnames = head->aout.a_syms / sizeof(*names);
! 708: if ((snames = malloc(nrawnames * sizeof(struct nlist *))) == NULL) {
! 709: warn("%s: malloc snames", name);
! 710: free(names);
! 711: return (1);
! 712: }
1.1 deraadt 713:
1.20 ! mickey 714: if (fread(names, head->aout.a_syms, 1, fp) != 1) {
! 715: warnx("%s: cannot read symbol table", name);
! 716: free(snames);
! 717: free(names);
! 718: return(1);
! 719: }
! 720: fix_nlists_order(names, nrawnames, N_GETMID(head->aout));
1.1 deraadt 721:
1.20 ! mickey 722: staboff = ftello(fp);
! 723: /*
! 724: * Following the symbol table comes the string table.
! 725: * The first 4-byte-integer gives the total size of the
! 726: * string table _including_ the size specification itself.
! 727: */
! 728: if (fread(&stabsize, sizeof(stabsize), (size_t)1, fp) != 1) {
! 729: warnx("%s: cannot read stab size", name);
! 730: free(snames);
! 731: free(names);
! 732: return(1);
! 733: }
! 734: stabsize = fix_long_order(stabsize, N_GETMID(head->aout));
! 735: if ((stab = mmap(NULL, stabsize, PROT_READ,
! 736: MAP_PRIVATE|MAP_FILE, fileno(fp), staboff)) == MAP_FAILED) {
! 737: warn("%s: mmap", name);
! 738: free(snames);
! 739: free(names);
! 740: return (1);
! 741: }
1.1 deraadt 742:
1.20 ! mickey 743: stabsize -= 4; /* we already have the size */
! 744: } while (0);
1.8 espie 745:
1.20 ! mickey 746: if (issize) {
! 747: static int first = 1;
1.1 deraadt 748:
1.20 ! mickey 749: if (first) {
! 750: first = 0;
! 751: printf("text\tdata\tbss\tdec\thex\n");
! 752: }
1.1 deraadt 753:
1.20 ! mickey 754: total = text + data + bss;
! 755: printf("%lu\t%lu\t%lu\t%lu\t%lx",
! 756: text, data, bss, total, total);
! 757: if (count > 1)
! 758: (void)printf("\t%s", name);
! 759:
! 760: total_text += text;
! 761: total_data += data;
! 762: total_bss += bss;
! 763: total_total += total;
1.1 deraadt 764:
1.20 ! mickey 765: printf("\n");
! 766: return (0);
1.1 deraadt 767: }
1.20 ! mickey 768: /* else we are nm */
1.1 deraadt 769:
770: /*
1.20 ! mickey 771: * it seems that string table is sequential
! 772: * relative to the symbol table order
1.1 deraadt 773: */
1.20 ! mickey 774: if (sfunc == NULL && madvise(stab, stabsize, MADV_SEQUENTIAL)) {
! 775: warn("%s: madvise", name);
! 776: free(snames);
! 777: free(names);
! 778: munmap(stab, stabsize);
! 779: return (1);
1.1 deraadt 780: }
781:
782: /*
783: * fix up the symbol table and filter out unwanted entries
784: *
785: * common symbols are characterized by a n_type of N_UNDF and a
786: * non-zero n_value -- change n_type to N_COMM for all such
787: * symbols to make life easier later.
788: *
789: * filter out all entries which we don't want to print anyway
790: */
791: for (np = names, i = nnames = 0; i < nrawnames; np++, i++) {
1.13 espie 792: /*
793: * make n_un.n_name a character pointer by adding the string
794: * table's base to n_un.n_strx
795: *
796: * don't mess with zero offsets
797: */
798: if (np->n_un.n_strx)
799: np->n_un.n_name = stab + np->n_un.n_strx;
800: else
801: np->n_un.n_name = "";
1.20 ! mickey 802: if (aout && SYMBOL_TYPE(np->n_type) == N_UNDF && np->n_value)
1.1 deraadt 803: np->n_type = N_COMM | (np->n_type & N_EXT);
804: if (!print_all_symbols && IS_DEBUGGER_SYMBOL(np->n_type))
805: continue;
806: if (print_only_external_symbols && !IS_EXTERNAL(np->n_type))
807: continue;
808: if (print_only_undefined_symbols &&
809: SYMBOL_TYPE(np->n_type) != N_UNDF)
810: continue;
811:
1.13 espie 812: snames[nnames++] = np;
1.1 deraadt 813: }
814:
815: /* sort the symbol table if applicable */
816: if (sfunc)
1.13 espie 817: qsort(snames, (size_t)nnames, sizeof(*snames), sfunc);
1.1 deraadt 818:
1.20 ! mickey 819: if (count > 1)
! 820: (void)printf("\n%s:\n", name);
! 821:
1.1 deraadt 822: /* print out symbols */
1.13 espie 823: for (i = 0; i < nnames; i++) {
824: if (show_extensions && snames[i] != names &&
825: SYMBOL_TYPE((snames[i] -1)->n_type) == N_INDR)
826: continue;
1.20 ! mickey 827: print_symbol(name, snames[i], aout);
1.13 espie 828: }
1.1 deraadt 829:
1.20 ! mickey 830: free(snames);
! 831: free(names);
! 832: munmap(stab, stabsize);
1.1 deraadt 833: return(0);
834: }
835:
1.20 ! mickey 836: int
! 837: elf_symload(const char *name, FILE *fp, off_t foff, Elf_Ehdr *eh, Elf_Shdr *shdr)
! 838: {
! 839: long symsize, shstrsize, nlistsize;
! 840: struct nlist *np;
! 841: Elf_Sym sbuf;
! 842: char *shstr;
! 843: int i;
! 844:
! 845: shstrsize = shdr[eh->e_shstrndx].sh_size;
! 846: if ((shstr = malloc(shstrsize)) == NULL) {
! 847: warn("%s: malloc shsrt", name);
! 848: return (1);
! 849: }
! 850:
! 851: if (fseeko(fp, foff + shdr[eh->e_shstrndx].sh_offset, SEEK_SET)) {
! 852: warn("%s: fseeko", name);
! 853: free(shstr);
! 854: return (1);
! 855: }
! 856:
! 857: if (fread(shstr, 1, shstrsize, fp) != shstrsize) {
! 858: warnx("%s: premature EOF", name);
! 859: free(shstr);
! 860: return(1);
! 861: }
! 862:
! 863: stab = NULL;
! 864: names = NULL; snames = NULL;
! 865: for (i = 0; i < eh->e_shnum; i++) {
! 866: if (!strcmp(shstr + shdr[i].sh_name, ELF_STRTAB)) {
! 867: stabsize = shdr[i].sh_size;
! 868: if (stabsize > SIZE_T_MAX) {
! 869: warnx("%s: corrupt file", name);
! 870: free(shstr);
! 871: return (1);
! 872: }
! 873:
! 874: if ((stab = mmap(NULL, stabsize, PROT_READ,
! 875: MAP_PRIVATE|MAP_FILE, fileno(fp),
! 876: foff + shdr[i].sh_offset)) == MAP_FAILED) {
! 877: warn("%s: mmap", name);
! 878: free(shstr);
! 879: return (1);
! 880: }
! 881: }
! 882: }
! 883: for (i = 0; i < eh->e_shnum; i++) {
! 884: if (!strcmp(shstr + shdr[i].sh_name, ELF_SYMTAB)) {
! 885: symsize = shdr[i].sh_size;
! 886: if (fseeko(fp, foff + shdr[i].sh_offset, SEEK_SET)) {
! 887: warn("%s: fseeko", name);
! 888: if (stab)
! 889: munmap(stab, stabsize);
! 890: free(shstr);
! 891: return (1);
! 892: }
! 893:
! 894: nrawnames = symsize / sizeof(sbuf);
! 895: if ((names = calloc(nrawnames, sizeof(*np))) == NULL) {
! 896: warn("%s: malloc names", name);
! 897: if (stab)
! 898: munmap(stab, stabsize);
! 899: free(names);
! 900: free(shstr);
! 901: return (1);
! 902: }
! 903: if ((snames = malloc(nrawnames * sizeof(np))) == NULL) {
! 904: warn("%s: malloc snames", name);
! 905: if (stab)
! 906: munmap(stab, stabsize);
! 907: free(shstr);
! 908: free(names);
! 909: free(snames);
! 910: return (1);
! 911: }
! 912:
! 913: for (np = names; symsize > 0; symsize -= sizeof(sbuf)) {
! 914: if (fread(&sbuf, 1, sizeof(sbuf),
! 915: fp) != sizeof(sbuf)) {
! 916: warn("%s: read symbol", name);
! 917: if (stab)
! 918: munmap(stab, stabsize);
! 919: free(shstr);
! 920: free(names);
! 921: free(snames);
! 922: return (1);
! 923: }
! 924:
! 925: elf_fix_sym(eh, &sbuf);
! 926:
! 927: if (!sbuf.st_name)
! 928: continue;
! 929:
! 930: elf2nlist(&sbuf, eh, shdr, shstr, np);
! 931: np->n_value = sbuf.st_value;
! 932: np->n_un.n_strx = sbuf.st_name;
! 933: np++;
! 934: }
! 935: nrawnames = np - names;
! 936: }
! 937: }
! 938:
! 939: free(shstr);
! 940: if (stab == NULL) {
! 941: warnx("%s: no name list", name);
! 942: if (names)
! 943: free(names);
! 944: if (snames)
! 945: free(snames);
! 946: return (1);
! 947: }
! 948:
! 949: return (0);
! 950: }
! 951:
1.13 espie 952: char *
1.19 deraadt 953: symname(struct nlist *sym)
1.13 espie 954: {
955: if (demangle && sym->n_un.n_name[0] == '_')
956: return sym->n_un.n_name + 1;
957: else
958: return sym->n_un.n_name;
959: }
960:
1.1 deraadt 961: /*
962: * print_symbol()
963: * show one symbol
964: */
1.13 espie 965: void
1.20 ! mickey 966: print_symbol(const char *name, struct nlist *sym, int aout)
1.1 deraadt 967: {
968: if (print_file_each_line)
1.20 ! mickey 969: (void)printf("%s:", name);
1.1 deraadt 970:
971: /*
1.10 espie 972: * handle undefined-only format especially (no space is
1.1 deraadt 973: * left for symbol values, no type field is printed)
974: */
1.10 espie 975: if (!print_only_undefined_symbols) {
976: /* print symbol's value */
1.13 espie 977: if (SYMBOL_TYPE(sym->n_type) == N_UNDF ||
978: (show_extensions && SYMBOL_TYPE(sym->n_type) == N_INDR &&
979: sym->n_value == 0))
1.10 espie 980: (void)printf(" ");
981: else
982: (void)printf("%08lx", sym->n_value);
983:
984: /* print type information */
985: if (IS_DEBUGGER_SYMBOL(sym->n_type))
986: (void)printf(" - %02x %04x %5s ", sym->n_other,
987: sym->n_desc&0xffff, typestring(sym->n_type));
1.12 espie 988: else if (show_extensions)
1.20 ! mickey 989: (void)printf(" %c%2s ", typeletter(sym, aout),
1.14 espie 990: otherstring(sym));
1.10 espie 991: else
1.20 ! mickey 992: (void)printf(" %c ", typeletter(sym, aout));
1.1 deraadt 993: }
994:
1.13 espie 995: if (SYMBOL_TYPE(sym->n_type) == N_INDR && show_extensions) {
996: printf("%s -> %s\n", symname(sym), symname(sym+1));
997: }
1.1 deraadt 998: else
1.13 espie 999: (void)puts(symname(sym));
1.12 espie 1000: }
1001:
1002: char *
1.19 deraadt 1003: otherstring(struct nlist *sym)
1.12 espie 1004: {
1005: static char buf[3];
1006: char *result;
1007:
1008: result = buf;
1009:
1.14 espie 1010: if (N_BIND(sym) == BIND_WEAK)
1.12 espie 1011: *result++ = 'w';
1.14 espie 1012: if (N_AUX(sym) == AUX_OBJECT)
1.12 espie 1013: *result++ = 'o';
1.14 espie 1014: else if (N_AUX(sym) == AUX_FUNC)
1.12 espie 1015: *result++ = 'f';
1016: *result++ = 0;
1017: return buf;
1.1 deraadt 1018: }
1019:
1020: /*
1021: * typestring()
1022: * return the a description string for an STAB entry
1023: */
1024: char *
1.19 deraadt 1025: typestring(unsigned int type)
1.1 deraadt 1026: {
1027: switch(type) {
1028: case N_BCOMM:
1029: return("BCOMM");
1030: case N_ECOML:
1031: return("ECOML");
1032: case N_ECOMM:
1033: return("ECOMM");
1034: case N_ENTRY:
1035: return("ENTRY");
1036: case N_FNAME:
1037: return("FNAME");
1038: case N_FUN:
1039: return("FUN");
1040: case N_GSYM:
1041: return("GSYM");
1042: case N_LBRAC:
1043: return("LBRAC");
1044: case N_LCSYM:
1045: return("LCSYM");
1046: case N_LENG:
1047: return("LENG");
1048: case N_LSYM:
1049: return("LSYM");
1050: case N_PC:
1051: return("PC");
1052: case N_PSYM:
1053: return("PSYM");
1054: case N_RBRAC:
1055: return("RBRAC");
1056: case N_RSYM:
1057: return("RSYM");
1058: case N_SLINE:
1059: return("SLINE");
1060: case N_SO:
1061: return("SO");
1062: case N_SOL:
1063: return("SOL");
1064: case N_SSYM:
1065: return("SSYM");
1066: case N_STSYM:
1067: return("STSYM");
1068: }
1069: return("???");
1070: }
1071:
1072: /*
1073: * typeletter()
1074: * return a description letter for the given basic type code of an
1075: * symbol table entry. The return value will be upper case for
1076: * external, lower case for internal symbols.
1077: */
1078: char
1.20 ! mickey 1079: typeletter(struct nlist *np, int aout)
1.1 deraadt 1080: {
1.20 ! mickey 1081: int ext = IS_EXTERNAL(np->n_type);
! 1082:
! 1083: if (!aout && !IS_DEBUGGER_SYMBOL(np->n_type) && np->n_other)
! 1084: return np->n_other;
! 1085:
! 1086: switch(SYMBOL_TYPE(np->n_type)) {
1.1 deraadt 1087: case N_ABS:
1.20 ! mickey 1088: return(ext? 'A' : 'a');
1.1 deraadt 1089: case N_BSS:
1.20 ! mickey 1090: return(ext? 'B' : 'b');
1.1 deraadt 1091: case N_COMM:
1.20 ! mickey 1092: return(ext? 'C' : 'c');
1.1 deraadt 1093: case N_DATA:
1.20 ! mickey 1094: return(ext? 'D' : 'd');
1.1 deraadt 1095: case N_FN:
1096: /* NOTE: N_FN == N_WARNING,
1097: * in this case, the N_EXT bit is to considered as
1098: * part of the symbol's type itself.
1099: */
1.20 ! mickey 1100: return(ext? 'F' : 'W');
1.1 deraadt 1101: case N_TEXT:
1.20 ! mickey 1102: return(ext? 'T' : 't');
1.1 deraadt 1103: case N_INDR:
1.20 ! mickey 1104: return(ext? 'I' : 'i');
1.1 deraadt 1105: case N_SIZE:
1.20 ! mickey 1106: return(ext? 'S' : 's');
1.1 deraadt 1107: case N_UNDF:
1.20 ! mickey 1108: return(ext? 'U' : 'u');
1.1 deraadt 1109: }
1110: return('?');
1111: }
1112:
1.13 espie 1113: int
1.19 deraadt 1114: fname(const void *a0, const void *b0)
1.1 deraadt 1115: {
1.13 espie 1116: struct nlist * const *a = a0, * const *b = b0;
1.1 deraadt 1117:
1.13 espie 1118: return(strcmp((*a)->n_un.n_name, (*b)->n_un.n_name));
1.1 deraadt 1119: }
1120:
1.13 espie 1121: int
1.19 deraadt 1122: rname(const void *a0, const void *b0)
1.1 deraadt 1123: {
1.13 espie 1124: struct nlist * const *a = a0, * const *b = b0;
1.1 deraadt 1125:
1.13 espie 1126: return(strcmp((*b)->n_un.n_name, (*a)->n_un.n_name));
1.1 deraadt 1127: }
1128:
1.13 espie 1129: int
1.19 deraadt 1130: value(const void *a0, const void *b0)
1.1 deraadt 1131: {
1.13 espie 1132: struct nlist * const *a = a0, * const *b = b0;
1.1 deraadt 1133:
1.13 espie 1134: if (SYMBOL_TYPE((*a)->n_type) == N_UNDF)
1135: if (SYMBOL_TYPE((*b)->n_type) == N_UNDF)
1.1 deraadt 1136: return(0);
1137: else
1138: return(-1);
1.13 espie 1139: else if (SYMBOL_TYPE((*b)->n_type) == N_UNDF)
1.1 deraadt 1140: return(1);
1141: if (rev) {
1.13 espie 1142: if ((*a)->n_value == (*b)->n_value)
1.1 deraadt 1143: return(rname(a0, b0));
1.13 espie 1144: return((*b)->n_value > (*a)->n_value ? 1 : -1);
1.1 deraadt 1145: } else {
1.13 espie 1146: if ((*a)->n_value == (*b)->n_value)
1.1 deraadt 1147: return(fname(a0, b0));
1.13 espie 1148: return((*a)->n_value > (*b)->n_value ? 1 : -1);
1.1 deraadt 1149: }
1150: }
1151:
1.10 espie 1152: #define CPPFILT "/usr/bin/c++filt"
1153:
1154: void
1.19 deraadt 1155: pipe2cppfilt(void)
1.10 espie 1156: {
1157: int pip[2];
1158: char *argv[2];
1159:
1160: argv[0] = "c++filt";
1161: argv[1] = NULL;
1162:
1163: if (pipe(pip) == -1)
1164: err(1, "pipe");
1165: switch(fork()) {
1166: case -1:
1167: err(1, "fork");
1168: default:
1169: dup2(pip[0], 0);
1170: close(pip[0]);
1171: close(pip[1]);
1172: execve(CPPFILT, argv, NULL);
1173: err(1, "execve");
1174: case 0:
1175: dup2(pip[1], 1);
1176: close(pip[1]);
1177: close(pip[0]);
1178: }
1179: }
1180:
1.11 smart 1181: void
1.19 deraadt 1182: usage(void)
1.1 deraadt 1183: {
1.20 ! mickey 1184: extern char *__progname;
! 1185:
! 1186: if (issize)
! 1187: fprintf(stderr, "usage: %s [-tw] [file ...]\n", __progname);
! 1188: else
! 1189: fprintf(stderr, "usage: %s [-aABCegnoprsuvVw] [file ...]\n",
! 1190: __progname);
1.1 deraadt 1191: exit(1);
1192: }