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