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