Annotation of 43BSDReno/pgrm/nm/nm.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  * Copyright (c) 1989 The Regents of the University of California.
                      3:  * All rights reserved.
                      4:  *
                      5:  * This code is derived from software contributed to Berkeley by
                      6:  * Hans Huebner.
                      7:  *
                      8:  * Redistribution and use in source and binary forms are permitted
                      9:  * provided that: (1) source distributions retain this entire copyright
                     10:  * notice and comment, and (2) distributions including binaries display
                     11:  * the following acknowledgement:  ``This product includes software
                     12:  * developed by the University of California, Berkeley and its contributors''
                     13:  * in the documentation or other materials provided with the distribution
                     14:  * and in all advertising materials mentioning features or use of this
                     15:  * software. Neither the name of the University nor the names of its
                     16:  * contributors may be used to endorse or promote products derived
                     17:  * from this software without specific prior written permission.
                     18:  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
                     19:  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
                     20:  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
                     21:  */
                     22: 
                     23: #ifndef lint
                     24: char copyright[] =
                     25: "@(#) Copyright (c) 1989 The Regents of the University of California.\n\
                     26:  All rights reserved.\n";
                     27: #endif /* not lint */
                     28: 
                     29: #ifndef lint
                     30: static char sccsid[] = "@(#)nm.c       5.6 (Berkeley) 6/1/90";
                     31: #endif /* not lint */
                     32: 
                     33: #include <sys/types.h>
                     34: #include <a.out.h>
                     35: #include <stab.h>
                     36: #include <ar.h>
                     37: #include <ranlib.h>
                     38: #include <unistd.h>
                     39: #include <errno.h>
                     40: #include <ctype.h>
                     41: #include <stdio.h>
                     42: #include <stdlib.h>
                     43: #include <string.h>
                     44: 
                     45: int ignore_bad_archive_entries = 1;
                     46: int print_only_external_symbols;
                     47: int print_only_undefined_symbols;
                     48: int print_all_symbols;
                     49: int print_file_each_line;
                     50: int cmp_value(), cmp_name();
                     51: int (*sort_func)() = cmp_name;
                     52: 
                     53: enum { FORWARD, BACKWARD } sort_direction = FORWARD;
                     54: int fcount;
                     55: 
                     56: /* some macros for symbol type (nlist.n_type) handling */
                     57: #define        IS_DEBUGGER_SYMBOL(x)   ((x) & N_STAB)
                     58: #define        IS_EXTERNAL(x)          ((x) & N_EXT)
                     59: #define        SYMBOL_TYPE(x)          ((x) & (N_TYPE | N_STAB))
                     60: 
                     61: /*
                     62:  * main()
                     63:  *     parse command line, execute process_file() for each file
                     64:  *     specified on the command line.
                     65:  */
                     66: main(argc, argv)
                     67:        int argc;
                     68:        char **argv;
                     69: {
                     70:        extern int optind;
                     71:        int ch, errors;
                     72: 
                     73:        while ((ch = getopt(argc, argv, "agnopruw")) != EOF) {
                     74:                switch (ch) {
                     75:                case 'a':
                     76:                        print_all_symbols = 1;
                     77:                        break;
                     78:                case 'g':
                     79:                        print_only_external_symbols = 1;
                     80:                        break;
                     81:                case 'n':
                     82:                        sort_func = cmp_value;
                     83:                        break;
                     84:                case 'o':
                     85:                        print_file_each_line = 1;
                     86:                        break;
                     87:                case 'p':
                     88:                        sort_func = NULL;
                     89:                        break;
                     90:                case 'r':
                     91:                        sort_direction = BACKWARD;
                     92:                        break;
                     93:                case 'u':
                     94:                        print_only_undefined_symbols = 1;
                     95:                        break;
                     96:                case 'w':
                     97:                        ignore_bad_archive_entries = 0;
                     98:                        break;
                     99:                case '?':
                    100:                default:
                    101:                        usage();
                    102:                }
                    103:        }
                    104:        fcount = argc - optind;
                    105:        argv += optind;
                    106: 
                    107:        if (!fcount)
                    108:                errors = process_file("a.out");
                    109:        else {
                    110:                errors = 0;
                    111:                do {
                    112:                        errors |= process_file(*argv);
                    113:                } while (*++argv);
                    114:        }
                    115:        exit(errors);
                    116: }
                    117: 
                    118: /*
                    119:  * process_file()
                    120:  *     show symbols in the file given as an argument.  Accepts archive and
                    121:  *     object files as input.
                    122:  */
                    123: process_file(fname)
                    124:        char *fname;
                    125: {
                    126:        struct exec exec_head;
                    127:        FILE *fp;
                    128:        int retval;
                    129:        char magic[SARMAG];
                    130:     
                    131:        if (!(fp = fopen(fname, "r"))) {
                    132:                (void)fprintf(stderr, "nm: cannot read %s.\n", fname);
                    133:                return(1);
                    134:        }
                    135: 
                    136:        if (fcount > 1)
                    137:                (void)printf("\n%s:\n", fname);
                    138:     
                    139:        /*
                    140:         * first check whether this is an object file - read a object
                    141:         * header, and skip back to the beginning
                    142:         */
                    143:        if (fread((char *)&exec_head, sizeof(exec_head), (size_t)1, fp) != 1) {
                    144:                (void)fprintf(stderr, "nm: %s: bad format.\n", fname);
                    145:                (void)fclose(fp);
                    146:                return(1);
                    147:        }
                    148:        rewind(fp);
                    149: 
                    150:        /* this could be an archive */
                    151:        if (N_BADMAG(exec_head)) {
                    152:                if (fread(magic, sizeof(magic), (size_t)1, fp) != 1 ||
                    153:                    strncmp(magic, ARMAG, SARMAG)) {
                    154:                        (void)fprintf(stderr,
                    155:                            "nm: %s: not object file or archive.\n", fname);
                    156:                        (void)fclose(fp);
                    157:                        return(1);
                    158:                }
                    159:                retval = show_archive(fname, fp);
                    160:        } else
                    161:                retval = show_objfile(fname, fp);
                    162:        (void)fclose(fp);
                    163:        return(retval);
                    164: }
                    165: 
                    166: /*
                    167:  * show_archive()
                    168:  *     show symbols in the given archive file
                    169:  */
                    170: show_archive(fname, fp)
                    171:        char *fname;
                    172:        FILE *fp;
                    173: {
                    174:        struct ar_hdr ar_head;
                    175:        struct exec exec_head;
                    176:        int i, rval;
                    177:        long last_ar_off;
                    178:        char *p, *name, *emalloc();
                    179:        long atol();
                    180: 
                    181:        name = emalloc(sizeof(ar_head.ar_name) + strlen(fname) + 3);
                    182: 
                    183:        rval = 0;
                    184: 
                    185:        /* while there are more entries in the archive */
                    186:        while (fread((char *)&ar_head, sizeof(ar_head), (size_t)1, fp) == 1) {
                    187:                /* bad archive entry - stop processing this archive */
                    188:                if (strncmp(ar_head.ar_fmag, ARFMAG, sizeof(ar_head.ar_fmag))) {
                    189:                        (void)fprintf(stderr,
                    190:                            "nm: %s: bad format archive header", fname);
                    191:                        (void)free(name);
                    192:                        return(1);
                    193:                }
                    194: 
                    195:                /*
                    196:                 * construct a name of the form "archive.a:obj.o:" for the
                    197:                 * current archive entry if the object name is to be printed
                    198:                 * on each output line
                    199:                 */
                    200:                p = name;
                    201:                if (print_file_each_line)
                    202:                        p += sprintf(p, "%s:", fname);
                    203:                for (i = 0; i < sizeof(ar_head.ar_name); ++i)
                    204:                        if (ar_head.ar_name[i] && ar_head.ar_name[i] != ' ')
                    205:                                *p++ = ar_head.ar_name[i];
                    206:                *p++ = '\0';
                    207: 
                    208:                /* remember start position of current archive object */
                    209:                last_ar_off = ftell(fp);
                    210: 
                    211:                /* get and check current object's header */
                    212:                if (fread((char *)&exec_head, sizeof(exec_head),
                    213:                    (size_t)1, fp) != 1) {
                    214:                        (void)fprintf(stderr, "nm: %s: premature EOF.\n", name);
                    215:                        (void)free(name);
                    216:                        return(1);
                    217:                }
                    218:                if (strcmp(name, RANLIBMAG))
                    219:                        if (N_BADMAG(exec_head)) {
                    220:                                if (!ignore_bad_archive_entries) {
                    221:                                        (void)fprintf(stderr,
                    222:                                            "nm: %s: bad format.\n", name);
                    223:                                        rval = 1;
                    224:                                }
                    225:                        } else {
                    226:                                (void)fseek(fp, (long)-sizeof(exec_head),
                    227:                                    SEEK_CUR);
                    228:                                if (!print_file_each_line)
                    229:                                        (void)printf("\n%s:\n", name);
                    230:                                rval |= show_objfile(name, fp);
                    231:                        }
                    232: 
                    233:                /*
                    234:                 * skip to next archive object - it starts at the next
                    235:                 * even byte boundary
                    236:                 */
                    237: #define even(x) (((x) + 1) & ~1)
                    238:                if (fseek(fp, last_ar_off + even(atol(ar_head.ar_size)),
                    239:                    SEEK_SET)) {
                    240:                        (void)fprintf(stderr,
                    241:                            "nm: %s: %s\n", fname, strerror(errno));
                    242:                        (void)free(name);
                    243:                        return(1);
                    244:                }
                    245:        }
                    246:        (void)free(name);
                    247:        return(rval);
                    248: }
                    249: 
                    250: /*
                    251:  * show_objfile()
                    252:  *     show symbols from the object file pointed to by fp.  The current
                    253:  *     file pointer for fp is expected to be at the beginning of an a.out
                    254:  *     header.
                    255:  */
                    256: show_objfile(objname, fp)
                    257:        char *objname;
                    258:        FILE *fp;
                    259: {
                    260:        register struct nlist *names, *np;
                    261:        register int i, nnames, nrawnames;
                    262:        struct exec head;
                    263:        long stabsize;
                    264:        char *stab, *emalloc();
                    265: 
                    266:        /* read a.out header */
                    267:        if (fread((char *)&head, sizeof(head), (size_t)1, fp) != 1) {
                    268:                (void)fprintf(stderr,
                    269:                    "nm: %s: cannot read header.\n", objname);
                    270:                return(1);
                    271:        }
                    272: 
                    273:        /*
                    274:         * skip back to the header - the N_-macros return values relative
                    275:         * to the beginning of the a.out header
                    276:         */
                    277:        if (fseek(fp, (long)-sizeof(head), SEEK_CUR)) {
                    278:                (void)fprintf(stderr,
                    279:                    "nm: %s: %s\n", objname, strerror(errno));
                    280:                return(1);
                    281:        }
                    282: 
                    283:        /* stop if this is no valid object file */
                    284:        if (N_BADMAG(head)) {
                    285:                (void)fprintf(stderr,
                    286:                    "nm: %s: bad format.\n", objname);
                    287:                return(1);
                    288:        }
                    289: 
                    290:        /* stop if the object file contains no symbol table */
                    291:        if (!head.a_syms) {
                    292:                (void)fprintf(stderr,
                    293:                    "nm: %s: no name list.\n", objname);
                    294:                return(1);
                    295:        }
                    296: 
                    297:        if (fseek(fp, (long)N_SYMOFF(head), SEEK_CUR)) {
                    298:                (void)fprintf(stderr,
                    299:                    "nm: %s: %s\n", objname, strerror(errno));
                    300:                return(1);
                    301:        }
                    302: 
                    303:        /* get memory for the symbol table */
                    304:        names = (struct nlist *)emalloc((size_t)head.a_syms);
                    305:        nrawnames = head.a_syms / sizeof(*names);
                    306:        if (fread((char *)names, (size_t)head.a_syms, (size_t)1, fp) != 1) {
                    307:                (void)fprintf(stderr,
                    308:                    "nm: %s: cannot read symbol table.\n", objname);
                    309:                (void)free((char *)names);
                    310:                return(1);
                    311:        }
                    312: 
                    313:        /*
                    314:         * Following the symbol table comes the string table.  The first
                    315:         * 4-byte-integer gives the total size of the string table
                    316:         * _including_ the size specification itself.
                    317:         */
                    318:        if (fread((char *)&stabsize, sizeof(stabsize), (size_t)1, fp) != 1) {
                    319:                (void)fprintf(stderr,
                    320:                    "nm: %s: cannot read stab size.\n", objname);
                    321:                (void)free((char *)names);
                    322:                return(1);
                    323:        }
                    324:        stab = emalloc((size_t)stabsize);
                    325: 
                    326:        /*
                    327:         * read the string table offset by 4 - all indices into the string
                    328:         * table include the size specification.
                    329:         */
                    330:        stabsize -= 4;          /* we already have the size */
                    331:        if (fread(stab + 4, (size_t)stabsize, (size_t)1, fp) != 1) {
                    332:                (void)fprintf(stderr,
                    333:                    "nm: %s: stab truncated..\n", objname);
                    334:                (void)free((char *)names);
                    335:                (void)free(stab);
                    336:                return(1);
                    337:        }
                    338: 
                    339:        /*
                    340:         * fix up the symbol table and filter out unwanted entries
                    341:         *
                    342:         * common symbols are characterized by a n_type of N_UNDF and a
                    343:         * non-zero n_value -- change n_type to N_COMM for all such
                    344:         * symbols to make life easier later.
                    345:         *
                    346:         * filter out all entries which we don't want to print anyway
                    347:         */
                    348:        for (np = names, i = nnames = 0; i < nrawnames; np++, i++) {
                    349:                if (SYMBOL_TYPE(np->n_type) == N_UNDF && np->n_value)
                    350:                        np->n_type = N_COMM | (np->n_type & N_EXT);
                    351:                if (!print_all_symbols && IS_DEBUGGER_SYMBOL(np->n_type))
                    352:                        continue;
                    353:                if (print_only_external_symbols && !IS_EXTERNAL(np->n_type))
                    354:                        continue;
                    355:                if (print_only_undefined_symbols &&
                    356:                    SYMBOL_TYPE(np->n_type) != N_UNDF)
                    357:                        continue;
                    358: 
                    359:                /*
                    360:                 * make n_un.n_name a character pointer by adding the string
                    361:                 * table's base to n_un.n_strx
                    362:                 *
                    363:                 * don't mess with zero offsets
                    364:                 */
                    365:                if (np->n_un.n_strx)
                    366:                        np->n_un.n_name = stab + np->n_un.n_strx;
                    367:                else
                    368:                        np->n_un.n_name = "";
                    369:                names[nnames++] = *np;
                    370:        }
                    371: 
                    372:        /* sort the symbol table if applicable */
                    373:        if (sort_func)
                    374:                qsort((char *)names, (size_t)nnames, sizeof(*names), sort_func);
                    375: 
                    376:        /* print out symbols */
                    377:        for (np = names, i = 0; i < nnames; np++, i++)
                    378:                print_symbol(objname, np);
                    379: 
                    380:        (void)free((char *)names);
                    381:        (void)free(stab);
                    382:        return(0);
                    383: }
                    384: 
                    385: /*
                    386:  * print_symbol()
                    387:  *     show one symbol
                    388:  */
                    389: print_symbol(objname, sym)
                    390:        char *objname;
                    391:        register struct nlist *sym;
                    392: {
                    393:        char *typestring(), typeletter();
                    394: 
                    395:        if (print_file_each_line)
                    396:                (void)printf("%s:", objname);
                    397: 
                    398:        /*
                    399:         * handle undefined-only format seperately (no space is
                    400:         * left for symbol values, no type field is printed)
                    401:         */
                    402:        if (print_only_undefined_symbols) {
                    403:                (void)puts(sym->n_un.n_name);
                    404:                return;
                    405:        }
                    406: 
                    407:        /* print symbol's value */
                    408:        if (SYMBOL_TYPE(sym->n_type) == N_UNDF)
                    409:                (void)printf("        ");
                    410:        else
                    411:                (void)printf("%08lx", sym->n_value);
                    412: 
                    413:        /* print type information */
                    414:        if (IS_DEBUGGER_SYMBOL(sym->n_type))
                    415:                (void)printf(" - %02x %04x %5s ", sym->n_other,
                    416:                    sym->n_desc&0xffff, typestring(sym->n_type));
                    417:        else
                    418:                (void)printf(" %c ", typeletter(sym->n_type));
                    419: 
                    420:        /* print the symbol's name */
                    421:        (void)puts(sym->n_un.n_name);
                    422: }
                    423: 
                    424: /*
                    425:  * typestring()
                    426:  *     return the a description string for an STAB entry
                    427:  */
                    428: char *
                    429: typestring(type)
                    430:        register u_char type;
                    431: {
                    432:        switch(type) {
                    433:        case N_BCOMM:
                    434:                return("BCOMM");
                    435:        case N_ECOML:
                    436:                return("ECOML");
                    437:        case N_ECOMM:
                    438:                return("ECOMM");
                    439:        case N_ENTRY:
                    440:                return("ENTRY");
                    441:        case N_FNAME:
                    442:                return("FNAME");
                    443:        case N_FUN:
                    444:                return("FUN");
                    445:        case N_GSYM:
                    446:                return("GSYM");
                    447:        case N_LBRAC:
                    448:                return("LBRAC");
                    449:        case N_LCSYM:
                    450:                return("LCSYM");
                    451:        case N_LENG:
                    452:                return("LENG");
                    453:        case N_LSYM:
                    454:                return("LSYM");
                    455:        case N_PC:
                    456:                return("PC");
                    457:        case N_PSYM:
                    458:                return("PSYM");
                    459:        case N_RBRAC:
                    460:                return("RBRAC");
                    461:        case N_RSYM:
                    462:                return("RSYM");
                    463:        case N_SLINE:
                    464:                return("SLINE");
                    465:        case N_SO:
                    466:                return("SO");
                    467:        case N_SOL:
                    468:                return("SOL");
                    469:        case N_SSYM:
                    470:                return("SSYM");
                    471:        case N_STSYM:
                    472:                return("STSYM");
                    473:        }
                    474:        return("???");
                    475: }
                    476: 
                    477: /*
                    478:  * typeletter()
                    479:  *     return a description letter for the given basic type code of an
                    480:  *     symbol table entry.  The return value will be upper case for
                    481:  *     external, lower case for internal symbols.
                    482:  */
                    483: char
                    484: typeletter(type)
                    485:        u_char type;
                    486: {
                    487:        switch(SYMBOL_TYPE(type)) {
                    488:        case N_ABS:
                    489:                return(IS_EXTERNAL(type) ? 'A' : 'a');
                    490:        case N_BSS:
                    491:                return(IS_EXTERNAL(type) ? 'B' : 'b');
                    492:        case N_COMM:
                    493:                return(IS_EXTERNAL(type) ? 'C' : 'c');
                    494:        case N_DATA:
                    495:                return(IS_EXTERNAL(type) ? 'D' : 'd');
                    496:        case N_FN:
                    497:                return(IS_EXTERNAL(type) ? 'F' : 'f');
                    498:        case N_TEXT:
                    499:                return(IS_EXTERNAL(type) ? 'T' : 't');
                    500:        case N_UNDF:
                    501:                return(IS_EXTERNAL(type) ? 'U' : 'u');
                    502:        }
                    503:        return('?');
                    504: }
                    505: 
                    506: /*
                    507:  * cmp_name()
                    508:  *     compare two symbols by their names
                    509:  */
                    510: cmp_name(a0, b0)
                    511:        void *a0, *b0;
                    512: {
                    513:        struct nlist *a = a0, *b = b0;
                    514: 
                    515:        return(sort_direction == FORWARD ?
                    516:            strcmp(a->n_un.n_name, b->n_un.n_name) :
                    517:            strcmp(b->n_un.n_name, a->n_un.n_name));
                    518: }
                    519: 
                    520: /*
                    521:  * cmp_value()
                    522:  *     compare two symbols by their values
                    523:  */
                    524: cmp_value(a0, b0)
                    525:        void *a0, *b0;
                    526: {
                    527:        register struct nlist *a = a0, *b = b0;
                    528: 
                    529:        if (SYMBOL_TYPE(a->n_type) == N_UNDF)
                    530:                if (SYMBOL_TYPE(b->n_type) == N_UNDF)
                    531:                        return(0);
                    532:                else
                    533:                        return(-1);
                    534:        else if (SYMBOL_TYPE(b->n_type) == N_UNDF)
                    535:                return(1);
                    536:        if (a->n_value == b->n_value)
                    537:                return(cmp_name((void *)a, (void *)b));
                    538:        return(sort_direction == FORWARD ? a->n_value > b->n_value :
                    539:            a->n_value < b->n_value);
                    540: }
                    541: 
                    542: char *
                    543: emalloc(size)
                    544:        size_t size;
                    545: {
                    546:        char *p;
                    547: 
                    548:        /* NOSTRICT */
                    549:        if (!(p = malloc(size))) {
                    550:                (void)fprintf(stderr, "nm: no more memory.\n");
                    551:                exit(1);
                    552:        }
                    553:        return(p);
                    554: }
                    555: 
                    556: usage()
                    557: {
                    558:        (void)fprintf(stderr, "usage: nm [-agnopruw] [file ...]\n");
                    559:        exit(1);
                    560: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.