Annotation of 43BSDReno/pgrm/nm/nm.c, revision 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.