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