Annotation of src/usr.bin/nm/nm.c, Revision 1.24
1.24 ! miod 1: /* $OpenBSD: nm.c,v 1.23 2004/01/14 04:23:26 millert 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:
36: #ifndef lint
1.20 mickey 37: static const char copyright[] =
1.1 deraadt 38: "@(#) Copyright (c) 1989, 1993\n\
39: The Regents of the University of California. All rights reserved.\n";
40: #endif /* not lint */
41:
42: #if 0
1.20 mickey 43: static const char sccsid[] = "@(#)nm.c 8.1 (Berkeley) 6/6/93";
1.1 deraadt 44: #endif
1.24 ! miod 45: static const char rcsid[] = "$OpenBSD: nm.c,v 1.23 2004/01/14 04:23:26 millert Exp $";
1.1 deraadt 46:
1.5 deraadt 47: #include <sys/param.h>
1.20 mickey 48: #include <sys/mman.h>
1.1 deraadt 49: #include <a.out.h>
1.20 mickey 50: #include <elf_abi.h>
1.1 deraadt 51: #include <stab.h>
52: #include <ar.h>
53: #include <ranlib.h>
54: #include <unistd.h>
1.2 deraadt 55: #include <err.h>
1.23 millert 56: #include <errno.h>
1.1 deraadt 57: #include <ctype.h>
1.14 espie 58: #include <link.h>
1.20 mickey 59: #ifdef __ELF__
60: #include <link_aout.h>
61: #endif
1.1 deraadt 62: #include <stdio.h>
63: #include <stdlib.h>
64: #include <string.h>
1.20 mickey 65: #include <getopt.h>
1.8 espie 66: /* XXX get shared code to handle byte-order swaps */
67: #include "byte.c"
1.20 mickey 68: #include "elf.c"
1.7 niklas 69:
1.20 mickey 70: #ifdef MID_MACHINE_OVERRIDE
71: #undef MID_MACHINE
72: #define MID_MACHINE MID_MACHINE_OVERRIDE
73: #endif
1.1 deraadt 74:
1.20 mickey 75: #define SYMTABMAG "/ "
76: #define STRTABMAG "//"
77:
78: union hdr {
79: struct exec aout;
80: Elf_Ehdr elf;
81: };
82:
83: int armap;
84: int demangle;
85: int non_object_warning;
1.1 deraadt 86: int print_only_external_symbols;
87: int print_only_undefined_symbols;
88: int print_all_symbols;
89: int print_file_each_line;
1.20 mickey 90: int show_extensions;
91: int issize;
1.23 millert 92: int usemmap = 1;
1.20 mickey 93:
94: /* size vars */
95: unsigned long total_text, total_data, total_bss, total_total;
96: int non_object_warning, print_totals;
1.1 deraadt 97:
98: int rev;
1.16 millert 99: int fname(const void *, const void *);
100: int rname(const void *, const void *);
101: int value(const void *, const void *);
102: int (*sfunc)(const void *, const void *) = fname;
103: char *otherstring(struct nlist *);
104: char *typestring(unsigned int);
1.20 mickey 105: char typeletter(struct nlist *, int);
1.8 espie 106:
1.1 deraadt 107: /* some macros for symbol type (nlist.n_type) handling */
108: #define IS_DEBUGGER_SYMBOL(x) ((x) & N_STAB)
109: #define IS_EXTERNAL(x) ((x) & N_EXT)
110: #define SYMBOL_TYPE(x) ((x) & (N_TYPE | N_STAB))
111:
1.16 millert 112: void pipe2cppfilt(void);
113: void usage(void);
114: char *symname(struct nlist *);
1.20 mickey 115: int process_file(int, const char *);
116: int show_archive(int, const char *, FILE *);
117: int show_file(int, int, const char *, FILE *fp, off_t, union hdr *);
118: void print_symbol(const char *, struct nlist *, int);
119: int elf_symload(const char *, FILE *, off_t, Elf_Ehdr *, Elf_Shdr *);
120:
121: #define OPTSTRING_NM "aABCegnoprsuvVw"
122: const struct option longopts_nm[] = {
123: { "debug-syms", no_argument, 0, 'a' },
124: { "demangle", no_argument, 0, 'C' },
125: /* { "dynamic", no_argument, 0, 'D' }, */
126: { "extern-only", no_argument, 0, 'g' },
127: /* { "line-numbers", no_argument, 0, 'l' }, */
128: { "no-sort", no_argument, 0, 'p' },
129: { "numeric-sort", no_argument, 0, 'n' },
130: { "print-armap", no_argument, 0, 's' },
131: { "print-file-name", no_argument, 0, 'o' },
132: { "reverse-sort", no_argument, 0, 'r' },
133: /* { "size-sort", no_argument, &szval, 1 }, */
134: { "undefined-only", no_argument, 0, 'u' },
135: { "version", no_argument, 0, 'V' },
136: { "help", no_argument, 0, '?' },
137: { NULL }
138: };
1.10 espie 139:
1.1 deraadt 140: /*
141: * main()
142: * parse command line, execute process_file() for each file
143: * specified on the command line.
144: */
1.20 mickey 145: int
1.19 deraadt 146: main(int argc, char *argv[])
1.1 deraadt 147: {
1.20 mickey 148: extern char *__progname;
1.1 deraadt 149: extern int optind;
1.20 mickey 150: const char *optstr;
151: const struct option *lopts;
152: int ch, eval;
153:
154: optstr = OPTSTRING_NM;
155: lopts = longopts_nm;
156: if (!strcmp(__progname, "size")) {
157: issize++;
158: optstr = "tw";
159: lopts = NULL;
160: }
1.1 deraadt 161:
1.20 mickey 162: while ((ch = getopt_long(argc, argv, optstr, lopts, NULL)) != -1) {
1.1 deraadt 163: switch (ch) {
164: case 'a':
165: print_all_symbols = 1;
166: break;
1.10 espie 167: case 'B':
168: /* no-op, compat with gnu-nm */
169: break;
170: case 'C':
171: demangle = 1;
172: break;
1.12 espie 173: case 'e':
174: show_extensions = 1;
175: break;
1.1 deraadt 176: case 'g':
177: print_only_external_symbols = 1;
178: break;
179: case 'n':
1.20 mickey 180: case 'v':
1.1 deraadt 181: sfunc = value;
182: break;
1.20 mickey 183: case 'A':
1.1 deraadt 184: case 'o':
185: print_file_each_line = 1;
186: break;
187: case 'p':
188: sfunc = NULL;
189: break;
190: case 'r':
191: rev = 1;
192: break;
1.20 mickey 193: case 's':
194: armap = 1;
195: break;
1.1 deraadt 196: case 'u':
197: print_only_undefined_symbols = 1;
198: break;
1.20 mickey 199: case 'V':
200: fprintf(stderr, "%s\n", rcsid);
201: exit(0);
1.1 deraadt 202: case 'w':
1.20 mickey 203: non_object_warning = 1;
1.1 deraadt 204: break;
1.20 mickey 205: case 't':
206: if (issize) {
207: print_totals = 1;
208: break;
209: }
1.1 deraadt 210: case '?':
211: default:
212: usage();
213: }
214: }
1.10 espie 215:
216: if (demangle)
217: pipe2cppfilt();
1.1 deraadt 218: argv += optind;
1.20 mickey 219: argc -= optind;
1.1 deraadt 220:
221: if (rev && sfunc == fname)
222: sfunc = rname;
223:
1.20 mickey 224: eval = 0;
225: if (*argv)
1.1 deraadt 226: do {
1.20 mickey 227: eval |= process_file(argc, *argv);
1.1 deraadt 228: } while (*++argv);
1.20 mickey 229: else
230: eval |= process_file(1, "a.out");
231:
232: if (issize && print_totals)
233: printf("\n%lu\t%lu\t%lu\t%lu\t%lx\tTOTAL\n",
234: total_text, total_data, total_bss,
235: total_total, total_total);
236: exit(eval);
1.1 deraadt 237: }
238:
239: /*
240: * process_file()
241: * show symbols in the file given as an argument. Accepts archive and
242: * object files as input.
243: */
1.20 mickey 244: int
245: process_file(int count, const char *fname)
1.1 deraadt 246: {
1.20 mickey 247: union hdr exec_head;
1.1 deraadt 248: FILE *fp;
249: int retval;
1.24 ! miod 250: size_t bytes;
1.1 deraadt 251: char magic[SARMAG];
252:
253: if (!(fp = fopen(fname, "r"))) {
1.6 deraadt 254: warn("cannot read %s", fname);
1.1 deraadt 255: return(1);
256: }
257:
1.20 mickey 258: if (!issize && count > 1)
1.1 deraadt 259: (void)printf("\n%s:\n", fname);
260:
261: /*
262: * first check whether this is an object file - read a object
263: * header, and skip back to the beginning
264: */
1.24 ! miod 265: bzero(&exec_head, sizeof(exec_head));
! 266: bytes = fread((char *)&exec_head, 1, sizeof(exec_head), fp);
! 267: if (bytes < sizeof(exec_head)) {
! 268: if (bytes < sizeof(exec_head.aout) || IS_ELF(exec_head.elf)) {
! 269: warnx("%s: bad format", fname);
! 270: (void)fclose(fp);
! 271: return(1);
! 272: }
1.1 deraadt 273: }
274: rewind(fp);
275:
276: /* this could be an archive */
1.20 mickey 277: if (!IS_ELF(exec_head.elf) && N_BADMAG(exec_head.aout)) {
1.1 deraadt 278: if (fread(magic, sizeof(magic), (size_t)1, fp) != 1 ||
279: strncmp(magic, ARMAG, SARMAG)) {
1.2 deraadt 280: warnx("%s: not object file or archive", fname);
1.1 deraadt 281: (void)fclose(fp);
282: return(1);
283: }
1.20 mickey 284: retval = show_archive(count, fname, fp);
1.1 deraadt 285: } else
1.20 mickey 286: retval = show_file(count, 1, fname, fp, 0, &exec_head);
1.1 deraadt 287: (void)fclose(fp);
288: return(retval);
289: }
290:
1.20 mickey 291: char *nametab;
292:
293: /*
294: *
295: * given the archive member header -- produce member name
296: */
297: int
298: mmbr_name(struct ar_hdr *arh, char **name, int baselen, int *namelen, FILE *fp)
299: {
300: char *p = *name + strlen(*name);
301: long i;
302:
303: if (nametab && arh->ar_name[0] == '/') {
304: int len;
305:
306: i = atol(&arh->ar_name[1]);
307: len = strlen(&nametab[i]);
308: if (len > *namelen) {
309: p -= (long)*name;
310: if ((*name = realloc(*name, baselen+len)) == NULL)
311: err(1, NULL);
312: *namelen = len;
313: p += (long)*name;
314: }
315: strlcpy(p, &nametab[i], len);
316: p += len;
317: } else
318: #ifdef AR_EFMT1
319: /*
320: * BSD 4.4 extended AR format: #1/<namelen>, with name as the
321: * first <namelen> bytes of the file
322: */
323: if ((arh->ar_name[0] == '#') &&
324: (arh->ar_name[1] == '1') &&
325: (arh->ar_name[2] == '/') &&
326: (isdigit(arh->ar_name[3]))) {
327: int len = atoi(&arh->ar_name[3]);
328:
329: if (len > *namelen) {
330: p -= (long)*name;
331: if ((*name = realloc(*name, baselen+len)) == NULL)
332: err(1, NULL);
333: *namelen = len;
334: p += (long)*name;
335: }
336: if (fread(p, len, 1, fp) != 1) {
337: warnx("%s: premature EOF", *name);
338: free(*name);
339: return(1);
340: }
341: p += len;
342: } else
343: #endif
344: for (i = 0; i < sizeof(arh->ar_name); ++i)
345: if (arh->ar_name[i] && arh->ar_name[i] != ' ')
346: *p++ = arh->ar_name[i];
347: *p = '\0';
348: if (p[-1] == '/')
349: *--p = '\0';
350:
351: return (0);
352: }
353:
1.22 millert 354: #define MMAP(ptr, len, prot, flags, fd, off) do { \
1.23 millert 355: if ((ptr = mmap(NULL, len, prot, flags, fd, off)) == MAP_FAILED) { \
356: usemmap = 0; \
357: if (errno != EINVAL) \
358: warn("mmap"); \
359: else if ((ptr = malloc(len)) == NULL) { \
1.22 millert 360: ptr = MAP_FAILED; \
361: warn("malloc"); \
362: } else if (pread(fd, ptr, len, off) != len) { \
363: free(ptr); \
364: ptr = MAP_FAILED; \
365: warn("pread"); \
366: } \
367: } \
368: } while (0)
369:
370: #define MUNMAP(addr, len) do { \
1.23 millert 371: if (usemmap) \
1.22 millert 372: munmap(addr, len); \
373: else \
374: free(addr); \
375: } while (0)
376:
1.20 mickey 377: /*
378: * show_symtab()
379: * show archive ranlib index (fs5)
380: */
381: int
382: show_symtab(off_t off, u_long len, const char *name, FILE *fp)
383: {
384: struct ar_hdr ar_head;
385: int *symtab, *ps;
386: char *strtab, *p;
387: int num, rval = 0;
1.23 millert 388: int namelen;
1.20 mickey 389:
1.22 millert 390: MMAP(symtab, len, PROT_READ, MAP_PRIVATE|MAP_FILE, fileno(fp), off);
391: if (symtab == MAP_FAILED)
1.20 mickey 392: return (1);
393:
394: namelen = sizeof(ar_head.ar_name);
395: if ((p = malloc(sizeof(ar_head.ar_name))) == NULL) {
396: warn("%s: malloc", name);
1.22 millert 397: MUNMAP(symtab, len);
1.20 mickey 398: }
399:
400: printf("\nArchive index:\n");
401: num = betoh32(*symtab);
402: strtab = (char *)(symtab + num + 1);
403: for (ps = symtab + 1; num--; ps++, strtab += strlen(strtab) + 1) {
404: if (fseeko(fp, betoh32(*ps), SEEK_SET)) {
405: warn("%s: fseeko", name);
406: rval = 1;
407: break;
408: }
409:
410: if (fread(&ar_head, sizeof(ar_head), 1, fp) != 1 ||
411: memcmp(ar_head.ar_fmag, ARFMAG, sizeof(ar_head.ar_fmag))) {
412: warnx("%s: member fseeko", name);
413: rval = 1;
414: break;
415: }
416:
417: *p = '\0';
418: if (mmbr_name(&ar_head, &p, 0, &namelen, fp)) {
419: rval = 1;
420: break;
421: }
422:
423: printf("%s in %s\n", strtab, p);
424: }
425:
426: free(p);
1.22 millert 427: MUNMAP(symtab, len);
1.20 mickey 428: return (rval);
429: }
430:
431: /*
432: * show_symdef()
433: * show archive ranlib index (gob)
434: */
435: int
436: show_symdef(off_t off, u_long len, const char *name, FILE *fp)
437: {
438: struct ranlib *prn, *eprn;
439: struct ar_hdr ar_head;
440: void *symdef;
441: char *strtab, *p;
442: u_long size;
1.23 millert 443: int namelen, rval = 0;
1.20 mickey 444:
1.22 millert 445: MMAP(symdef, len, PROT_READ, MAP_PRIVATE|MAP_FILE, fileno(fp), off);
446: if (symdef == MAP_FAILED)
1.20 mickey 447: return (1);
1.23 millert 448: if (usemmap)
1.22 millert 449: (void)madvise(symdef, len, MADV_SEQUENTIAL);
1.20 mickey 450:
451: namelen = sizeof(ar_head.ar_name);
452: if ((p = malloc(sizeof(ar_head.ar_name))) == NULL) {
453: warn("%s: malloc", name);
1.22 millert 454: MUNMAP(symdef, len);
1.20 mickey 455: return (1);
456: }
457:
458: size = *(u_long *)symdef;
459: prn = symdef + sizeof(u_long);
460: eprn = prn + size / sizeof(*prn);
461: strtab = symdef + sizeof(u_long) + size + sizeof(u_long);
462:
463: printf("\nArchive index:\n");
464: for (; prn < eprn; prn++) {
465: if (fseeko(fp, prn->ran_off, SEEK_SET)) {
466: warn("%s: fseeko", name);
467: rval = 1;
468: break;
469: }
470:
471: if (fread(&ar_head, sizeof(ar_head), 1, fp) != 1 ||
472: memcmp(ar_head.ar_fmag, ARFMAG, sizeof(ar_head.ar_fmag))) {
473: warnx("%s: member fseeko", name);
474: rval = 1;
475: break;
476: }
477:
478: *p = '\0';
479: if (mmbr_name(&ar_head, &p, 0, &namelen, fp)) {
480: rval = 1;
481: break;
482: }
483:
484: printf("%s in %s\n", strtab + prn->ran_un.ran_strx, p);
485: }
486:
487: free(p);
1.22 millert 488: MUNMAP(symdef, len);
1.20 mickey 489: return (rval);
490: }
491:
1.1 deraadt 492: /*
493: * show_archive()
494: * show symbols in the given archive file
495: */
1.20 mickey 496: int
497: show_archive(int count, const char *fname, FILE *fp)
1.1 deraadt 498: {
499: struct ar_hdr ar_head;
1.20 mickey 500: union hdr exec_head;
1.1 deraadt 501: int i, rval;
1.20 mickey 502: off_t last_ar_off, foff, symtaboff;
503: char *name;
1.1 deraadt 504: int baselen, namelen;
1.20 mickey 505: u_long mmbrlen, symtablen;
1.1 deraadt 506:
507: baselen = strlen(fname) + 3;
508: namelen = sizeof(ar_head.ar_name);
1.20 mickey 509: if ((name = malloc(baselen + namelen)) == NULL)
510: err(1, NULL);
1.1 deraadt 511:
512: rval = 0;
1.20 mickey 513: nametab = NULL;
514: symtaboff = 0;
515: symtablen = 0;
1.1 deraadt 516:
517: /* while there are more entries in the archive */
1.20 mickey 518: while (fread(&ar_head, sizeof(ar_head), 1, fp) == 1) {
1.1 deraadt 519: /* bad archive entry - stop processing this archive */
1.20 mickey 520: if (memcmp(ar_head.ar_fmag, ARFMAG, sizeof(ar_head.ar_fmag))) {
1.2 deraadt 521: warnx("%s: bad format archive header", fname);
1.20 mickey 522: rval = 1;
523: break;
1.1 deraadt 524: }
525:
526: /* remember start position of current archive object */
1.20 mickey 527: last_ar_off = ftello(fp);
528: mmbrlen = atol(ar_head.ar_size);
1.1 deraadt 529:
1.20 mickey 530: if (strncmp(ar_head.ar_name, RANLIBMAG,
531: sizeof(RANLIBMAG) - 1) == 0) {
532: if (!issize && armap &&
533: show_symdef(last_ar_off, mmbrlen, fname, fp)) {
534: rval = 1;
535: break;
536: }
1.1 deraadt 537: goto skip;
1.20 mickey 538: } else if (strncmp(ar_head.ar_name, SYMTABMAG,
539: sizeof(SYMTABMAG) - 1) == 0) {
540: /* if nametab hasn't been seen yet -- doit later */
541: if (!nametab) {
542: symtablen = mmbrlen;
543: symtaboff = last_ar_off;
544: goto skip;
545: }
546:
547: /* load the Sys5 long names table */
548: } else if (strncmp(ar_head.ar_name, STRTABMAG,
549: sizeof(STRTABMAG) - 1) == 0) {
550: char *p;
551:
552: if ((nametab = malloc(mmbrlen)) == NULL) {
553: warn("%s: nametab", fname);
554: rval = 1;
555: break;
556: }
557:
558: if (fread(nametab, mmbrlen, (size_t)1, fp) != 1) {
559: warnx("%s: premature EOF", fname);
560: rval = 1;
561: break;
562: }
563:
564: for (p = nametab, i = mmbrlen; i--; p++)
565: if (*p == '\n')
566: *p = '\0';
567:
568: if (issize || !armap || !symtablen || !symtaboff)
569: goto skip;
570: }
571:
572: if (!issize && armap && symtablen && symtaboff) {
573: if (show_symtab(symtaboff, symtablen, fname, fp)) {
574: rval = 1;
575: break;
576: } else {
577: symtaboff = 0;
578: symtablen = 0;
579: goto skip;
580: }
581: }
1.1 deraadt 582:
583: /*
584: * construct a name of the form "archive.a:obj.o:" for the
585: * current archive entry if the object name is to be printed
586: * on each output line
587: */
1.20 mickey 588: *name = '\0';
589: if (count > 1)
590: snprintf(name, baselen - 1, "%s:", fname);
591:
592: if (mmbr_name(&ar_head, &name, baselen, &namelen, fp)) {
593: rval = 1;
594: break;
1.17 deraadt 595: }
1.20 mickey 596:
597: foff = ftello(fp);
1.1 deraadt 598:
599: /* get and check current object's header */
600: if (fread((char *)&exec_head, sizeof(exec_head),
601: (size_t)1, fp) != 1) {
1.20 mickey 602: warnx("%s: premature EOF", fname);
603: rval = 1;
604: break;
1.1 deraadt 605: }
606:
1.20 mickey 607: rval |= show_file(2, non_object_warning, name, fp, foff, &exec_head);
1.1 deraadt 608: /*
609: * skip to next archive object - it starts at the next
610: * even byte boundary
611: */
612: #define even(x) (((x) + 1) & ~1)
1.20 mickey 613: skip: if (fseeko(fp, last_ar_off + even(mmbrlen), SEEK_SET)) {
1.2 deraadt 614: warn("%s", fname);
1.20 mickey 615: rval = 1;
616: break;
1.1 deraadt 617: }
618: }
1.20 mickey 619: if (nametab) {
620: free(nametab);
621: nametab = NULL;
622: }
623: free(name);
1.1 deraadt 624: return(rval);
625: }
626:
1.20 mickey 627: struct nlist *names;
628: struct nlist **snames;
629: char *stab;
630: int nnames, nrawnames, stabsize;
631:
1.1 deraadt 632: /*
1.20 mickey 633: * show_file()
1.1 deraadt 634: * show symbols from the object file pointed to by fp. The current
635: * file pointer for fp is expected to be at the beginning of an a.out
636: * header.
637: */
1.20 mickey 638: int
639: show_file(int count, int warn_fmt, const char *name, FILE *fp, off_t foff, union hdr *head)
1.1 deraadt 640: {
1.20 mickey 641: u_long text, data, bss, total;
642: struct nlist *np;
643: Elf_Shdr *shdr;
644: off_t staboff;
1.23 millert 645: int i, aout;
1.20 mickey 646:
647: aout = 0;
648: if (IS_ELF(head->elf) &&
649: head->elf.e_ident[EI_CLASS] == ELF_TARG_CLASS &&
650: head->elf.e_ident[EI_VERSION] == ELF_TARG_VER) {
651:
652: elf_fix_header(&head->elf);
653:
654: if ((shdr = malloc(head->elf.e_shentsize *
655: head->elf.e_shnum)) == NULL) {
656: warn("%s: malloc shdr", name);
657: return (1);
658: }
659:
660: if (fseeko(fp, foff + head->elf.e_shoff, SEEK_SET)) {
661: warn("%s: fseeko", name);
662: free(shdr);
663: return (1);
664: }
665:
666: if (fread(shdr, head->elf.e_shentsize, head->elf.e_shnum,
667: fp) != head->elf.e_shnum) {
668: warnx("%s: premature EOF", name);
669: free(shdr);
670: return(1);
671: }
672:
673: elf_fix_shdrs(&head->elf, shdr);
674:
675: if (issize) {
676: text = data = bss = 0;
677: for (i = 0; i < head->elf.e_shnum; i++) {
678: if (!(shdr[i].sh_flags & SHF_ALLOC))
679: ;
680: else if (shdr[i].sh_flags & SHF_EXECINSTR ||
681: !(shdr[i].sh_flags & SHF_WRITE))
682: text += shdr[i].sh_size;
683: else if (shdr[i].sh_type == SHT_NOBITS)
684: bss += shdr[i].sh_size;
685: else
686: data += shdr[i].sh_size;
687: }
688: free(shdr);
689: } else {
690: i = elf_symload(name, fp, foff, &head->elf, shdr);
691: free(shdr);
692: if (i)
693: return (i);
694: }
695:
696: } else if (BAD_OBJECT(head->aout)) {
697: if (warn_fmt)
698: warnx("%s: bad format", name);
699: return (1);
700: } else do {
701: aout++;
702:
703: fix_header_order(&head->aout);
704:
705: if (issize) {
706: text = head->aout.a_text;
707: data = head->aout.a_data;
708: bss = head->aout.a_bss;
709: break;
710: }
711:
712: /* stop if the object file contains no symbol table */
713: if (!head->aout.a_syms) {
714: warnx("%s: no name list", name);
715: return(1);
716: }
717:
718: if (fseeko(fp, foff + N_SYMOFF(head->aout), SEEK_SET)) {
719: warn("%s", name);
720: return(1);
721: }
722:
723: /* get memory for the symbol table */
724: if ((names = malloc(head->aout.a_syms)) == NULL) {
725: warn("%s: malloc names", name);
726: return (1);
727: }
728: nrawnames = head->aout.a_syms / sizeof(*names);
729: if ((snames = malloc(nrawnames * sizeof(struct nlist *))) == NULL) {
730: warn("%s: malloc snames", name);
731: free(names);
732: return (1);
733: }
1.1 deraadt 734:
1.20 mickey 735: if (fread(names, head->aout.a_syms, 1, fp) != 1) {
736: warnx("%s: cannot read symbol table", name);
737: free(snames);
738: free(names);
739: return(1);
740: }
741: fix_nlists_order(names, nrawnames, N_GETMID(head->aout));
1.1 deraadt 742:
1.20 mickey 743: staboff = ftello(fp);
744: /*
745: * Following the symbol table comes the string table.
746: * The first 4-byte-integer gives the total size of the
747: * string table _including_ the size specification itself.
748: */
749: if (fread(&stabsize, sizeof(stabsize), (size_t)1, fp) != 1) {
750: warnx("%s: cannot read stab size", name);
751: free(snames);
752: free(names);
753: return(1);
754: }
1.22 millert 755: MMAP(stab, stabsize, PROT_READ, MAP_PRIVATE|MAP_FILE,
756: fileno(fp), staboff);
757: if (stab == MAP_FAILED) {
1.20 mickey 758: free(snames);
759: free(names);
760: return (1);
761: }
1.1 deraadt 762:
1.20 mickey 763: stabsize -= 4; /* we already have the size */
764: } while (0);
1.8 espie 765:
1.20 mickey 766: if (issize) {
767: static int first = 1;
1.1 deraadt 768:
1.20 mickey 769: if (first) {
770: first = 0;
771: printf("text\tdata\tbss\tdec\thex\n");
772: }
1.1 deraadt 773:
1.20 mickey 774: total = text + data + bss;
775: printf("%lu\t%lu\t%lu\t%lu\t%lx",
776: text, data, bss, total, total);
777: if (count > 1)
778: (void)printf("\t%s", name);
779:
780: total_text += text;
781: total_data += data;
782: total_bss += bss;
783: total_total += total;
1.1 deraadt 784:
1.20 mickey 785: printf("\n");
786: return (0);
1.1 deraadt 787: }
1.20 mickey 788: /* else we are nm */
1.1 deraadt 789:
790: /*
1.20 mickey 791: * it seems that string table is sequential
792: * relative to the symbol table order
1.1 deraadt 793: */
1.23 millert 794: if (sfunc == NULL && usemmap)
795: (void)madvise(stab, stabsize, MADV_SEQUENTIAL);
1.1 deraadt 796:
797: /*
798: * fix up the symbol table and filter out unwanted entries
799: *
800: * common symbols are characterized by a n_type of N_UNDF and a
801: * non-zero n_value -- change n_type to N_COMM for all such
802: * symbols to make life easier later.
803: *
804: * filter out all entries which we don't want to print anyway
805: */
806: for (np = names, i = nnames = 0; i < nrawnames; np++, i++) {
1.13 espie 807: /*
808: * make n_un.n_name a character pointer by adding the string
809: * table's base to n_un.n_strx
810: *
811: * don't mess with zero offsets
812: */
813: if (np->n_un.n_strx)
814: np->n_un.n_name = stab + np->n_un.n_strx;
815: else
816: np->n_un.n_name = "";
1.20 mickey 817: if (aout && SYMBOL_TYPE(np->n_type) == N_UNDF && np->n_value)
1.1 deraadt 818: np->n_type = N_COMM | (np->n_type & N_EXT);
819: if (!print_all_symbols && IS_DEBUGGER_SYMBOL(np->n_type))
820: continue;
821: if (print_only_external_symbols && !IS_EXTERNAL(np->n_type))
822: continue;
823: if (print_only_undefined_symbols &&
824: SYMBOL_TYPE(np->n_type) != N_UNDF)
825: continue;
826:
1.13 espie 827: snames[nnames++] = np;
1.1 deraadt 828: }
829:
830: /* sort the symbol table if applicable */
831: if (sfunc)
1.13 espie 832: qsort(snames, (size_t)nnames, sizeof(*snames), sfunc);
1.1 deraadt 833:
1.20 mickey 834: if (count > 1)
835: (void)printf("\n%s:\n", name);
836:
1.1 deraadt 837: /* print out symbols */
1.13 espie 838: for (i = 0; i < nnames; i++) {
839: if (show_extensions && snames[i] != names &&
840: SYMBOL_TYPE((snames[i] -1)->n_type) == N_INDR)
841: continue;
1.20 mickey 842: print_symbol(name, snames[i], aout);
1.13 espie 843: }
1.1 deraadt 844:
1.20 mickey 845: free(snames);
846: free(names);
1.22 millert 847: MUNMAP(stab, stabsize);
1.1 deraadt 848: return(0);
849: }
850:
1.20 mickey 851: int
852: elf_symload(const char *name, FILE *fp, off_t foff, Elf_Ehdr *eh, Elf_Shdr *shdr)
853: {
1.21 mickey 854: long symsize, shstrsize;
1.20 mickey 855: struct nlist *np;
856: Elf_Sym sbuf;
857: char *shstr;
1.23 millert 858: int i;
1.20 mickey 859:
860: shstrsize = shdr[eh->e_shstrndx].sh_size;
861: if ((shstr = malloc(shstrsize)) == NULL) {
862: warn("%s: malloc shsrt", name);
863: return (1);
864: }
865:
866: if (fseeko(fp, foff + shdr[eh->e_shstrndx].sh_offset, SEEK_SET)) {
867: warn("%s: fseeko", name);
868: free(shstr);
869: return (1);
870: }
871:
872: if (fread(shstr, 1, shstrsize, fp) != shstrsize) {
873: warnx("%s: premature EOF", name);
874: free(shstr);
875: return(1);
876: }
877:
878: stab = NULL;
879: names = NULL; snames = NULL;
880: for (i = 0; i < eh->e_shnum; i++) {
881: if (!strcmp(shstr + shdr[i].sh_name, ELF_STRTAB)) {
882: stabsize = shdr[i].sh_size;
883: if (stabsize > SIZE_T_MAX) {
884: warnx("%s: corrupt file", name);
885: free(shstr);
886: return (1);
887: }
888:
1.22 millert 889: MMAP(stab, stabsize, PROT_READ, MAP_PRIVATE|MAP_FILE,
890: fileno(fp), foff + shdr[i].sh_offset);
891: if (stab == MAP_FAILED) {
1.20 mickey 892: free(shstr);
893: return (1);
894: }
895: }
896: }
897: for (i = 0; i < eh->e_shnum; i++) {
898: if (!strcmp(shstr + shdr[i].sh_name, ELF_SYMTAB)) {
899: symsize = shdr[i].sh_size;
900: if (fseeko(fp, foff + shdr[i].sh_offset, SEEK_SET)) {
901: warn("%s: fseeko", name);
902: if (stab)
1.22 millert 903: MUNMAP(stab, stabsize);
1.20 mickey 904: free(shstr);
905: return (1);
906: }
907:
908: nrawnames = symsize / sizeof(sbuf);
909: if ((names = calloc(nrawnames, sizeof(*np))) == NULL) {
910: warn("%s: malloc names", name);
911: if (stab)
1.22 millert 912: MUNMAP(stab, stabsize);
1.20 mickey 913: free(names);
914: free(shstr);
915: return (1);
916: }
917: if ((snames = malloc(nrawnames * sizeof(np))) == NULL) {
918: warn("%s: malloc snames", name);
919: if (stab)
1.22 millert 920: MUNMAP(stab, stabsize);
1.20 mickey 921: free(shstr);
922: free(names);
923: free(snames);
924: return (1);
925: }
926:
927: for (np = names; symsize > 0; symsize -= sizeof(sbuf)) {
928: if (fread(&sbuf, 1, sizeof(sbuf),
929: fp) != sizeof(sbuf)) {
930: warn("%s: read symbol", name);
931: if (stab)
1.22 millert 932: MUNMAP(stab, stabsize);
1.20 mickey 933: free(shstr);
934: free(names);
935: free(snames);
936: return (1);
937: }
938:
939: elf_fix_sym(eh, &sbuf);
940:
941: if (!sbuf.st_name)
942: continue;
943:
944: elf2nlist(&sbuf, eh, shdr, shstr, np);
945: np->n_value = sbuf.st_value;
946: np->n_un.n_strx = sbuf.st_name;
947: np++;
948: }
949: nrawnames = np - names;
950: }
951: }
952:
953: free(shstr);
954: if (stab == NULL) {
955: warnx("%s: no name list", name);
956: if (names)
957: free(names);
958: if (snames)
959: free(snames);
960: return (1);
961: }
962:
963: return (0);
964: }
965:
1.13 espie 966: char *
1.19 deraadt 967: symname(struct nlist *sym)
1.13 espie 968: {
969: if (demangle && sym->n_un.n_name[0] == '_')
970: return sym->n_un.n_name + 1;
971: else
972: return sym->n_un.n_name;
973: }
974:
1.1 deraadt 975: /*
976: * print_symbol()
977: * show one symbol
978: */
1.13 espie 979: void
1.20 mickey 980: print_symbol(const char *name, struct nlist *sym, int aout)
1.1 deraadt 981: {
982: if (print_file_each_line)
1.20 mickey 983: (void)printf("%s:", name);
1.1 deraadt 984:
985: /*
1.10 espie 986: * handle undefined-only format especially (no space is
1.1 deraadt 987: * left for symbol values, no type field is printed)
988: */
1.10 espie 989: if (!print_only_undefined_symbols) {
990: /* print symbol's value */
1.13 espie 991: if (SYMBOL_TYPE(sym->n_type) == N_UNDF ||
992: (show_extensions && SYMBOL_TYPE(sym->n_type) == N_INDR &&
993: sym->n_value == 0))
1.10 espie 994: (void)printf(" ");
995: else
996: (void)printf("%08lx", sym->n_value);
997:
998: /* print type information */
999: if (IS_DEBUGGER_SYMBOL(sym->n_type))
1000: (void)printf(" - %02x %04x %5s ", sym->n_other,
1001: sym->n_desc&0xffff, typestring(sym->n_type));
1.12 espie 1002: else if (show_extensions)
1.20 mickey 1003: (void)printf(" %c%2s ", typeletter(sym, aout),
1.14 espie 1004: otherstring(sym));
1.10 espie 1005: else
1.20 mickey 1006: (void)printf(" %c ", typeletter(sym, aout));
1.1 deraadt 1007: }
1008:
1.13 espie 1009: if (SYMBOL_TYPE(sym->n_type) == N_INDR && show_extensions) {
1010: printf("%s -> %s\n", symname(sym), symname(sym+1));
1011: }
1.1 deraadt 1012: else
1.13 espie 1013: (void)puts(symname(sym));
1.12 espie 1014: }
1015:
1016: char *
1.19 deraadt 1017: otherstring(struct nlist *sym)
1.12 espie 1018: {
1019: static char buf[3];
1020: char *result;
1021:
1022: result = buf;
1023:
1.14 espie 1024: if (N_BIND(sym) == BIND_WEAK)
1.12 espie 1025: *result++ = 'w';
1.14 espie 1026: if (N_AUX(sym) == AUX_OBJECT)
1.12 espie 1027: *result++ = 'o';
1.14 espie 1028: else if (N_AUX(sym) == AUX_FUNC)
1.12 espie 1029: *result++ = 'f';
1030: *result++ = 0;
1031: return buf;
1.1 deraadt 1032: }
1033:
1034: /*
1035: * typestring()
1036: * return the a description string for an STAB entry
1037: */
1038: char *
1.19 deraadt 1039: typestring(unsigned int type)
1.1 deraadt 1040: {
1041: switch(type) {
1042: case N_BCOMM:
1043: return("BCOMM");
1044: case N_ECOML:
1045: return("ECOML");
1046: case N_ECOMM:
1047: return("ECOMM");
1048: case N_ENTRY:
1049: return("ENTRY");
1050: case N_FNAME:
1051: return("FNAME");
1052: case N_FUN:
1053: return("FUN");
1054: case N_GSYM:
1055: return("GSYM");
1056: case N_LBRAC:
1057: return("LBRAC");
1058: case N_LCSYM:
1059: return("LCSYM");
1060: case N_LENG:
1061: return("LENG");
1062: case N_LSYM:
1063: return("LSYM");
1064: case N_PC:
1065: return("PC");
1066: case N_PSYM:
1067: return("PSYM");
1068: case N_RBRAC:
1069: return("RBRAC");
1070: case N_RSYM:
1071: return("RSYM");
1072: case N_SLINE:
1073: return("SLINE");
1074: case N_SO:
1075: return("SO");
1076: case N_SOL:
1077: return("SOL");
1078: case N_SSYM:
1079: return("SSYM");
1080: case N_STSYM:
1081: return("STSYM");
1082: }
1083: return("???");
1084: }
1085:
1086: /*
1087: * typeletter()
1088: * return a description letter for the given basic type code of an
1089: * symbol table entry. The return value will be upper case for
1090: * external, lower case for internal symbols.
1091: */
1092: char
1.20 mickey 1093: typeletter(struct nlist *np, int aout)
1.1 deraadt 1094: {
1.20 mickey 1095: int ext = IS_EXTERNAL(np->n_type);
1096:
1097: if (!aout && !IS_DEBUGGER_SYMBOL(np->n_type) && np->n_other)
1098: return np->n_other;
1099:
1100: switch(SYMBOL_TYPE(np->n_type)) {
1.1 deraadt 1101: case N_ABS:
1.20 mickey 1102: return(ext? 'A' : 'a');
1.1 deraadt 1103: case N_BSS:
1.20 mickey 1104: return(ext? 'B' : 'b');
1.1 deraadt 1105: case N_COMM:
1.20 mickey 1106: return(ext? 'C' : 'c');
1.1 deraadt 1107: case N_DATA:
1.20 mickey 1108: return(ext? 'D' : 'd');
1.1 deraadt 1109: case N_FN:
1110: /* NOTE: N_FN == N_WARNING,
1111: * in this case, the N_EXT bit is to considered as
1112: * part of the symbol's type itself.
1113: */
1.20 mickey 1114: return(ext? 'F' : 'W');
1.1 deraadt 1115: case N_TEXT:
1.20 mickey 1116: return(ext? 'T' : 't');
1.1 deraadt 1117: case N_INDR:
1.20 mickey 1118: return(ext? 'I' : 'i');
1.1 deraadt 1119: case N_SIZE:
1.20 mickey 1120: return(ext? 'S' : 's');
1.1 deraadt 1121: case N_UNDF:
1.20 mickey 1122: return(ext? 'U' : 'u');
1.1 deraadt 1123: }
1124: return('?');
1125: }
1126:
1.13 espie 1127: int
1.19 deraadt 1128: fname(const void *a0, const void *b0)
1.1 deraadt 1129: {
1.13 espie 1130: struct nlist * const *a = a0, * const *b = b0;
1.1 deraadt 1131:
1.13 espie 1132: return(strcmp((*a)->n_un.n_name, (*b)->n_un.n_name));
1.1 deraadt 1133: }
1134:
1.13 espie 1135: int
1.19 deraadt 1136: rname(const void *a0, const void *b0)
1.1 deraadt 1137: {
1.13 espie 1138: struct nlist * const *a = a0, * const *b = b0;
1.1 deraadt 1139:
1.13 espie 1140: return(strcmp((*b)->n_un.n_name, (*a)->n_un.n_name));
1.1 deraadt 1141: }
1142:
1.13 espie 1143: int
1.19 deraadt 1144: value(const void *a0, const void *b0)
1.1 deraadt 1145: {
1.13 espie 1146: struct nlist * const *a = a0, * const *b = b0;
1.1 deraadt 1147:
1.13 espie 1148: if (SYMBOL_TYPE((*a)->n_type) == N_UNDF)
1149: if (SYMBOL_TYPE((*b)->n_type) == N_UNDF)
1.1 deraadt 1150: return(0);
1151: else
1152: return(-1);
1.13 espie 1153: else if (SYMBOL_TYPE((*b)->n_type) == N_UNDF)
1.1 deraadt 1154: return(1);
1155: if (rev) {
1.13 espie 1156: if ((*a)->n_value == (*b)->n_value)
1.1 deraadt 1157: return(rname(a0, b0));
1.13 espie 1158: return((*b)->n_value > (*a)->n_value ? 1 : -1);
1.1 deraadt 1159: } else {
1.13 espie 1160: if ((*a)->n_value == (*b)->n_value)
1.1 deraadt 1161: return(fname(a0, b0));
1.13 espie 1162: return((*a)->n_value > (*b)->n_value ? 1 : -1);
1.1 deraadt 1163: }
1164: }
1165:
1.10 espie 1166: #define CPPFILT "/usr/bin/c++filt"
1167:
1168: void
1.19 deraadt 1169: pipe2cppfilt(void)
1.10 espie 1170: {
1171: int pip[2];
1172: char *argv[2];
1173:
1174: argv[0] = "c++filt";
1175: argv[1] = NULL;
1176:
1177: if (pipe(pip) == -1)
1178: err(1, "pipe");
1179: switch(fork()) {
1180: case -1:
1181: err(1, "fork");
1182: default:
1183: dup2(pip[0], 0);
1184: close(pip[0]);
1185: close(pip[1]);
1186: execve(CPPFILT, argv, NULL);
1187: err(1, "execve");
1188: case 0:
1189: dup2(pip[1], 1);
1190: close(pip[1]);
1191: close(pip[0]);
1192: }
1193: }
1194:
1.11 smart 1195: void
1.19 deraadt 1196: usage(void)
1.1 deraadt 1197: {
1.20 mickey 1198: extern char *__progname;
1199:
1200: if (issize)
1201: fprintf(stderr, "usage: %s [-tw] [file ...]\n", __progname);
1202: else
1203: fprintf(stderr, "usage: %s [-aABCegnoprsuvVw] [file ...]\n",
1204: __progname);
1.1 deraadt 1205: exit(1);
1206: }