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