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