Annotation of src/usr.bin/nm/nm.c, Revision 1.26
1.26 ! mickey 1: /* $OpenBSD: nm.c,v 1.25 2004/05/04 23:09: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:
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.26 ! mickey 45: static const char rcsid[] = "$OpenBSD: nm.c,v 1.25 2004/05/04 23:09:07 deraadt 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 *);
1.25 deraadt 118: void print_symbol(const char *, struct nlist *, int);
1.20 mickey 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];
1.25 deraadt 252:
1.1 deraadt 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);
1.25 deraadt 260:
1.1 deraadt 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') &&
1.25 deraadt 325: (arh->ar_name[2] == '/') &&
1.20 mickey 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
1.25 deraadt 610: * even byte boundary
1.1 deraadt 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.26 ! mickey 755: stabsize = fix_long_order(stabsize, N_GETMID(head->aout));
1.22 millert 756: MMAP(stab, stabsize, PROT_READ, MAP_PRIVATE|MAP_FILE,
757: fileno(fp), staboff);
758: if (stab == MAP_FAILED) {
1.20 mickey 759: free(snames);
760: free(names);
761: return (1);
762: }
1.1 deraadt 763:
1.20 mickey 764: stabsize -= 4; /* we already have the size */
765: } while (0);
1.8 espie 766:
1.20 mickey 767: if (issize) {
768: static int first = 1;
1.1 deraadt 769:
1.20 mickey 770: if (first) {
771: first = 0;
772: printf("text\tdata\tbss\tdec\thex\n");
773: }
1.1 deraadt 774:
1.20 mickey 775: total = text + data + bss;
776: printf("%lu\t%lu\t%lu\t%lu\t%lx",
777: text, data, bss, total, total);
778: if (count > 1)
779: (void)printf("\t%s", name);
780:
781: total_text += text;
782: total_data += data;
783: total_bss += bss;
784: total_total += total;
1.1 deraadt 785:
1.20 mickey 786: printf("\n");
787: return (0);
1.1 deraadt 788: }
1.20 mickey 789: /* else we are nm */
1.1 deraadt 790:
791: /*
1.20 mickey 792: * it seems that string table is sequential
793: * relative to the symbol table order
1.1 deraadt 794: */
1.23 millert 795: if (sfunc == NULL && usemmap)
796: (void)madvise(stab, stabsize, MADV_SEQUENTIAL);
1.1 deraadt 797:
798: /*
799: * fix up the symbol table and filter out unwanted entries
800: *
801: * common symbols are characterized by a n_type of N_UNDF and a
802: * non-zero n_value -- change n_type to N_COMM for all such
803: * symbols to make life easier later.
804: *
805: * filter out all entries which we don't want to print anyway
806: */
807: for (np = names, i = nnames = 0; i < nrawnames; np++, i++) {
1.13 espie 808: /*
809: * make n_un.n_name a character pointer by adding the string
810: * table's base to n_un.n_strx
811: *
812: * don't mess with zero offsets
813: */
814: if (np->n_un.n_strx)
815: np->n_un.n_name = stab + np->n_un.n_strx;
816: else
817: np->n_un.n_name = "";
1.20 mickey 818: if (aout && SYMBOL_TYPE(np->n_type) == N_UNDF && np->n_value)
1.1 deraadt 819: np->n_type = N_COMM | (np->n_type & N_EXT);
820: if (!print_all_symbols && IS_DEBUGGER_SYMBOL(np->n_type))
821: continue;
822: if (print_only_external_symbols && !IS_EXTERNAL(np->n_type))
823: continue;
824: if (print_only_undefined_symbols &&
825: SYMBOL_TYPE(np->n_type) != N_UNDF)
826: continue;
827:
1.13 espie 828: snames[nnames++] = np;
1.1 deraadt 829: }
830:
831: /* sort the symbol table if applicable */
832: if (sfunc)
1.13 espie 833: qsort(snames, (size_t)nnames, sizeof(*snames), sfunc);
1.1 deraadt 834:
1.20 mickey 835: if (count > 1)
836: (void)printf("\n%s:\n", name);
837:
1.1 deraadt 838: /* print out symbols */
1.13 espie 839: for (i = 0; i < nnames; i++) {
840: if (show_extensions && snames[i] != names &&
841: SYMBOL_TYPE((snames[i] -1)->n_type) == N_INDR)
842: continue;
1.20 mickey 843: print_symbol(name, snames[i], aout);
1.13 espie 844: }
1.1 deraadt 845:
1.20 mickey 846: free(snames);
847: free(names);
1.22 millert 848: MUNMAP(stab, stabsize);
1.1 deraadt 849: return(0);
850: }
851:
1.20 mickey 852: int
853: elf_symload(const char *name, FILE *fp, off_t foff, Elf_Ehdr *eh, Elf_Shdr *shdr)
854: {
1.21 mickey 855: long symsize, shstrsize;
1.20 mickey 856: struct nlist *np;
857: Elf_Sym sbuf;
858: char *shstr;
1.23 millert 859: int i;
1.20 mickey 860:
861: shstrsize = shdr[eh->e_shstrndx].sh_size;
862: if ((shstr = malloc(shstrsize)) == NULL) {
863: warn("%s: malloc shsrt", name);
864: return (1);
865: }
866:
867: if (fseeko(fp, foff + shdr[eh->e_shstrndx].sh_offset, SEEK_SET)) {
868: warn("%s: fseeko", name);
869: free(shstr);
870: return (1);
871: }
872:
873: if (fread(shstr, 1, shstrsize, fp) != shstrsize) {
874: warnx("%s: premature EOF", name);
875: free(shstr);
876: return(1);
877: }
878:
879: stab = NULL;
880: names = NULL; snames = NULL;
881: for (i = 0; i < eh->e_shnum; i++) {
882: if (!strcmp(shstr + shdr[i].sh_name, ELF_STRTAB)) {
883: stabsize = shdr[i].sh_size;
884: if (stabsize > SIZE_T_MAX) {
885: warnx("%s: corrupt file", name);
886: free(shstr);
887: return (1);
888: }
889:
1.22 millert 890: MMAP(stab, stabsize, PROT_READ, MAP_PRIVATE|MAP_FILE,
891: fileno(fp), foff + shdr[i].sh_offset);
892: if (stab == MAP_FAILED) {
1.20 mickey 893: free(shstr);
894: return (1);
895: }
896: }
897: }
898: for (i = 0; i < eh->e_shnum; i++) {
899: if (!strcmp(shstr + shdr[i].sh_name, ELF_SYMTAB)) {
900: symsize = shdr[i].sh_size;
901: if (fseeko(fp, foff + shdr[i].sh_offset, SEEK_SET)) {
902: warn("%s: fseeko", name);
903: if (stab)
1.22 millert 904: MUNMAP(stab, stabsize);
1.20 mickey 905: free(shstr);
906: return (1);
907: }
908:
909: nrawnames = symsize / sizeof(sbuf);
910: if ((names = calloc(nrawnames, sizeof(*np))) == NULL) {
911: warn("%s: malloc names", name);
912: if (stab)
1.22 millert 913: MUNMAP(stab, stabsize);
1.20 mickey 914: free(names);
915: free(shstr);
916: return (1);
917: }
918: if ((snames = malloc(nrawnames * sizeof(np))) == NULL) {
919: warn("%s: malloc snames", name);
920: if (stab)
1.22 millert 921: MUNMAP(stab, stabsize);
1.20 mickey 922: free(shstr);
923: free(names);
924: free(snames);
925: return (1);
926: }
927:
928: for (np = names; symsize > 0; symsize -= sizeof(sbuf)) {
929: if (fread(&sbuf, 1, sizeof(sbuf),
930: fp) != sizeof(sbuf)) {
931: warn("%s: read symbol", name);
932: if (stab)
1.22 millert 933: MUNMAP(stab, stabsize);
1.20 mickey 934: free(shstr);
935: free(names);
936: free(snames);
937: return (1);
938: }
939:
940: elf_fix_sym(eh, &sbuf);
941:
942: if (!sbuf.st_name)
943: continue;
944:
945: elf2nlist(&sbuf, eh, shdr, shstr, np);
946: np->n_value = sbuf.st_value;
947: np->n_un.n_strx = sbuf.st_name;
948: np++;
949: }
950: nrawnames = np - names;
951: }
952: }
953:
954: free(shstr);
955: if (stab == NULL) {
956: warnx("%s: no name list", name);
957: if (names)
958: free(names);
959: if (snames)
960: free(snames);
961: return (1);
962: }
1.25 deraadt 963:
1.20 mickey 964: return (0);
965: }
966:
1.13 espie 967: char *
1.19 deraadt 968: symname(struct nlist *sym)
1.13 espie 969: {
1.25 deraadt 970: if (demangle && sym->n_un.n_name[0] == '_')
1.13 espie 971: return sym->n_un.n_name + 1;
972: else
973: return sym->n_un.n_name;
974: }
975:
1.1 deraadt 976: /*
977: * print_symbol()
978: * show one symbol
979: */
1.13 espie 980: void
1.20 mickey 981: print_symbol(const char *name, struct nlist *sym, int aout)
1.1 deraadt 982: {
983: if (print_file_each_line)
1.20 mickey 984: (void)printf("%s:", name);
1.1 deraadt 985:
986: /*
1.10 espie 987: * handle undefined-only format especially (no space is
1.1 deraadt 988: * left for symbol values, no type field is printed)
989: */
1.10 espie 990: if (!print_only_undefined_symbols) {
991: /* print symbol's value */
1.25 deraadt 992: if (SYMBOL_TYPE(sym->n_type) == N_UNDF ||
993: (show_extensions && SYMBOL_TYPE(sym->n_type) == N_INDR &&
994: sym->n_value == 0))
1.10 espie 995: (void)printf(" ");
996: else
997: (void)printf("%08lx", sym->n_value);
998:
999: /* print type information */
1000: if (IS_DEBUGGER_SYMBOL(sym->n_type))
1001: (void)printf(" - %02x %04x %5s ", sym->n_other,
1002: sym->n_desc&0xffff, typestring(sym->n_type));
1.12 espie 1003: else if (show_extensions)
1.20 mickey 1004: (void)printf(" %c%2s ", typeletter(sym, aout),
1.14 espie 1005: otherstring(sym));
1.10 espie 1006: else
1.20 mickey 1007: (void)printf(" %c ", typeletter(sym, aout));
1.1 deraadt 1008: }
1009:
1.13 espie 1010: if (SYMBOL_TYPE(sym->n_type) == N_INDR && show_extensions) {
1011: printf("%s -> %s\n", symname(sym), symname(sym+1));
1012: }
1.1 deraadt 1013: else
1.13 espie 1014: (void)puts(symname(sym));
1.12 espie 1015: }
1016:
1017: char *
1.19 deraadt 1018: otherstring(struct nlist *sym)
1.12 espie 1019: {
1020: static char buf[3];
1021: char *result;
1022:
1023: result = buf;
1024:
1.14 espie 1025: if (N_BIND(sym) == BIND_WEAK)
1.12 espie 1026: *result++ = 'w';
1.14 espie 1027: if (N_AUX(sym) == AUX_OBJECT)
1.12 espie 1028: *result++ = 'o';
1.14 espie 1029: else if (N_AUX(sym) == AUX_FUNC)
1.12 espie 1030: *result++ = 'f';
1031: *result++ = 0;
1032: return buf;
1.1 deraadt 1033: }
1034:
1035: /*
1036: * typestring()
1037: * return the a description string for an STAB entry
1038: */
1039: char *
1.19 deraadt 1040: typestring(unsigned int type)
1.1 deraadt 1041: {
1042: switch(type) {
1043: case N_BCOMM:
1044: return("BCOMM");
1045: case N_ECOML:
1046: return("ECOML");
1047: case N_ECOMM:
1048: return("ECOMM");
1049: case N_ENTRY:
1050: return("ENTRY");
1051: case N_FNAME:
1052: return("FNAME");
1053: case N_FUN:
1054: return("FUN");
1055: case N_GSYM:
1056: return("GSYM");
1057: case N_LBRAC:
1058: return("LBRAC");
1059: case N_LCSYM:
1060: return("LCSYM");
1061: case N_LENG:
1062: return("LENG");
1063: case N_LSYM:
1064: return("LSYM");
1065: case N_PC:
1066: return("PC");
1067: case N_PSYM:
1068: return("PSYM");
1069: case N_RBRAC:
1070: return("RBRAC");
1071: case N_RSYM:
1072: return("RSYM");
1073: case N_SLINE:
1074: return("SLINE");
1075: case N_SO:
1076: return("SO");
1077: case N_SOL:
1078: return("SOL");
1079: case N_SSYM:
1080: return("SSYM");
1081: case N_STSYM:
1082: return("STSYM");
1083: }
1084: return("???");
1085: }
1086:
1087: /*
1088: * typeletter()
1089: * return a description letter for the given basic type code of an
1090: * symbol table entry. The return value will be upper case for
1091: * external, lower case for internal symbols.
1092: */
1093: char
1.20 mickey 1094: typeletter(struct nlist *np, int aout)
1.1 deraadt 1095: {
1.20 mickey 1096: int ext = IS_EXTERNAL(np->n_type);
1097:
1098: if (!aout && !IS_DEBUGGER_SYMBOL(np->n_type) && np->n_other)
1099: return np->n_other;
1100:
1101: switch(SYMBOL_TYPE(np->n_type)) {
1.1 deraadt 1102: case N_ABS:
1.20 mickey 1103: return(ext? 'A' : 'a');
1.1 deraadt 1104: case N_BSS:
1.20 mickey 1105: return(ext? 'B' : 'b');
1.1 deraadt 1106: case N_COMM:
1.20 mickey 1107: return(ext? 'C' : 'c');
1.1 deraadt 1108: case N_DATA:
1.20 mickey 1109: return(ext? 'D' : 'd');
1.1 deraadt 1110: case N_FN:
1111: /* NOTE: N_FN == N_WARNING,
1112: * in this case, the N_EXT bit is to considered as
1113: * part of the symbol's type itself.
1114: */
1.20 mickey 1115: return(ext? 'F' : 'W');
1.1 deraadt 1116: case N_TEXT:
1.20 mickey 1117: return(ext? 'T' : 't');
1.1 deraadt 1118: case N_INDR:
1.20 mickey 1119: return(ext? 'I' : 'i');
1.1 deraadt 1120: case N_SIZE:
1.20 mickey 1121: return(ext? 'S' : 's');
1.1 deraadt 1122: case N_UNDF:
1.20 mickey 1123: return(ext? 'U' : 'u');
1.1 deraadt 1124: }
1125: return('?');
1126: }
1127:
1.13 espie 1128: int
1.19 deraadt 1129: fname(const void *a0, const void *b0)
1.1 deraadt 1130: {
1.13 espie 1131: struct nlist * const *a = a0, * const *b = b0;
1.1 deraadt 1132:
1.13 espie 1133: return(strcmp((*a)->n_un.n_name, (*b)->n_un.n_name));
1.1 deraadt 1134: }
1135:
1.13 espie 1136: int
1.19 deraadt 1137: rname(const void *a0, const void *b0)
1.1 deraadt 1138: {
1.13 espie 1139: struct nlist * const *a = a0, * const *b = b0;
1.1 deraadt 1140:
1.13 espie 1141: return(strcmp((*b)->n_un.n_name, (*a)->n_un.n_name));
1.1 deraadt 1142: }
1143:
1.13 espie 1144: int
1.19 deraadt 1145: value(const void *a0, const void *b0)
1.1 deraadt 1146: {
1.13 espie 1147: struct nlist * const *a = a0, * const *b = b0;
1.1 deraadt 1148:
1.13 espie 1149: if (SYMBOL_TYPE((*a)->n_type) == N_UNDF)
1150: if (SYMBOL_TYPE((*b)->n_type) == N_UNDF)
1.1 deraadt 1151: return(0);
1152: else
1153: return(-1);
1.13 espie 1154: else if (SYMBOL_TYPE((*b)->n_type) == N_UNDF)
1.1 deraadt 1155: return(1);
1156: if (rev) {
1.13 espie 1157: if ((*a)->n_value == (*b)->n_value)
1.1 deraadt 1158: return(rname(a0, b0));
1.13 espie 1159: return((*b)->n_value > (*a)->n_value ? 1 : -1);
1.1 deraadt 1160: } else {
1.13 espie 1161: if ((*a)->n_value == (*b)->n_value)
1.1 deraadt 1162: return(fname(a0, b0));
1.13 espie 1163: return((*a)->n_value > (*b)->n_value ? 1 : -1);
1.1 deraadt 1164: }
1165: }
1166:
1.10 espie 1167: #define CPPFILT "/usr/bin/c++filt"
1168:
1169: void
1.19 deraadt 1170: pipe2cppfilt(void)
1.10 espie 1171: {
1172: int pip[2];
1173: char *argv[2];
1174:
1175: argv[0] = "c++filt";
1176: argv[1] = NULL;
1177:
1178: if (pipe(pip) == -1)
1179: err(1, "pipe");
1180: switch(fork()) {
1181: case -1:
1182: err(1, "fork");
1183: default:
1184: dup2(pip[0], 0);
1185: close(pip[0]);
1186: close(pip[1]);
1187: execve(CPPFILT, argv, NULL);
1188: err(1, "execve");
1189: case 0:
1190: dup2(pip[1], 1);
1191: close(pip[1]);
1192: close(pip[0]);
1193: }
1194: }
1195:
1.11 smart 1196: void
1.19 deraadt 1197: usage(void)
1.1 deraadt 1198: {
1.20 mickey 1199: extern char *__progname;
1200:
1201: if (issize)
1202: fprintf(stderr, "usage: %s [-tw] [file ...]\n", __progname);
1203: else
1204: fprintf(stderr, "usage: %s [-aABCegnoprsuvVw] [file ...]\n",
1205: __progname);
1.1 deraadt 1206: exit(1);
1207: }