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