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