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