home *** CD-ROM | disk | FTP | other *** search
/ The CDPD Public Domain Collection for CDTV 3 / CDPDIII.bin / pd / programming / gnuc / nm / nm.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-04-20  |  13.5 KB  |  585 lines

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