[BACK]Return to nm.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / nm

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: }