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