386BSD 0.1 development
[unix-history] / usr / src / usr.bin / nm / nm.c
index 21cf300..e72285b 100644 (file)
@@ -5,17 +5,33 @@
  * This code is derived from software contributed to Berkeley by
  * Hans Huebner.
  *
  * This code is derived from software contributed to Berkeley by
  * Hans Huebner.
  *
- * Redistribution and use in source and binary forms are permitted
- * provided that the above copyright notice and this paragraph are
- * duplicated in all such forms and that any documentation,
- * advertising materials, and other materials related to such
- * distribution and use acknowledge that the software was developed
- * by the University of California, Berkeley.  The name of the
- * University may not be used to endorse or promote products derived
- * from this software without specific prior written permission.
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
  */
 
 #ifndef lint
  */
 
 #ifndef lint
@@ -25,7 +41,7 @@ char copyright[] =
 #endif /* not lint */
 
 #ifndef lint
 #endif /* not lint */
 
 #ifndef lint
-static char sccsid[] = "@(#)nm.c       5.3 (Berkeley) %G%";
+static char sccsid[] = "@(#)nm.c       5.8 (Berkeley) 5/2/91";
 #endif /* not lint */
 
 #include <sys/types.h>
 #endif /* not lint */
 
 #include <sys/types.h>
@@ -37,26 +53,27 @@ static char sccsid[] = "@(#)nm.c    5.3 (Berkeley) %G%";
 #include <errno.h>
 #include <ctype.h>
 #include <stdio.h>
 #include <errno.h>
 #include <ctype.h>
 #include <stdio.h>
-#include <strings.h>
-
-extern int errno;
+#include <stdlib.h>
+#include <string.h>
 
 int ignore_bad_archive_entries = 1;
 int print_only_external_symbols;
 int print_only_undefined_symbols;
 int print_all_symbols;
 int print_file_each_line;
 
 int ignore_bad_archive_entries = 1;
 int print_only_external_symbols;
 int print_only_undefined_symbols;
 int print_all_symbols;
 int print_file_each_line;
-int cmp_value(), cmp_name();
-int (*sort_func)() = cmp_name;
-
-enum { FORWARD, BACKWARD } sort_direction = FORWARD;
 int fcount;
 
 int fcount;
 
+int rev;
+int fname(), rname(), value();
+int (*sfunc)() = fname;
+
 /* some macros for symbol type (nlist.n_type) handling */
 #define        IS_DEBUGGER_SYMBOL(x)   ((x) & N_STAB)
 #define        IS_EXTERNAL(x)          ((x) & N_EXT)
 #define        SYMBOL_TYPE(x)          ((x) & (N_TYPE | N_STAB))
 
 /* some macros for symbol type (nlist.n_type) handling */
 #define        IS_DEBUGGER_SYMBOL(x)   ((x) & N_STAB)
 #define        IS_EXTERNAL(x)          ((x) & N_EXT)
 #define        SYMBOL_TYPE(x)          ((x) & (N_TYPE | N_STAB))
 
+void *emalloc();
+
 /*
  * main()
  *     parse command line, execute process_file() for each file
 /*
  * main()
  *     parse command line, execute process_file() for each file
@@ -78,16 +95,16 @@ main(argc, argv)
                        print_only_external_symbols = 1;
                        break;
                case 'n':
                        print_only_external_symbols = 1;
                        break;
                case 'n':
-                       sort_func = cmp_value;
+                       sfunc = value;
                        break;
                case 'o':
                        print_file_each_line = 1;
                        break;
                case 'p':
                        break;
                case 'o':
                        print_file_each_line = 1;
                        break;
                case 'p':
-                       sort_func = NULL;
+                       sfunc = NULL;
                        break;
                case 'r':
                        break;
                case 'r':
-                       sort_direction = BACKWARD;
+                       rev = 1;
                        break;
                case 'u':
                        print_only_undefined_symbols = 1;
                        break;
                case 'u':
                        print_only_undefined_symbols = 1;
@@ -103,6 +120,9 @@ main(argc, argv)
        fcount = argc - optind;
        argv += optind;
 
        fcount = argc - optind;
        argv += optind;
 
+       if (rev && sfunc == fname)
+               sfunc = rname;
+
        if (!fcount)
                errors = process_file("a.out");
        else {
        if (!fcount)
                errors = process_file("a.out");
        else {
@@ -139,8 +159,7 @@ process_file(fname)
         * first check whether this is an object file - read a object
         * header, and skip back to the beginning
         */
         * first check whether this is an object file - read a object
         * header, and skip back to the beginning
         */
-       if (fread((char *)&exec_head, 1, sizeof(exec_head), fp) !=
-           sizeof(exec_head)) {
+       if (fread((char *)&exec_head, sizeof(exec_head), (size_t)1, fp) != 1) {
                (void)fprintf(stderr, "nm: %s: bad format.\n", fname);
                (void)fclose(fp);
                return(1);
                (void)fprintf(stderr, "nm: %s: bad format.\n", fname);
                (void)fclose(fp);
                return(1);
@@ -149,7 +168,7 @@ process_file(fname)
 
        /* this could be an archive */
        if (N_BADMAG(exec_head)) {
 
        /* this could be an archive */
        if (N_BADMAG(exec_head)) {
-               if (fread(magic, 1, sizeof(magic), fp) != sizeof(magic) ||
+               if (fread(magic, sizeof(magic), (size_t)1, fp) != 1 ||
                    strncmp(magic, ARMAG, SARMAG)) {
                        (void)fprintf(stderr,
                            "nm: %s: not object file or archive.\n", fname);
                    strncmp(magic, ARMAG, SARMAG)) {
                        (void)fprintf(stderr,
                            "nm: %s: not object file or archive.\n", fname);
@@ -173,18 +192,16 @@ show_archive(fname, fp)
 {
        struct ar_hdr ar_head;
        struct exec exec_head;
 {
        struct ar_hdr ar_head;
        struct exec exec_head;
-       off_t esize;
-       int i, last_ar_off, rval;
-       char *p, *name, *emalloc();
-       long atol();
+       int i, rval;
+       long last_ar_off;
+       char *p, *name;
 
 
-       name = emalloc((u_int)(sizeof(ar_head.ar_name) + strlen(fname) + 3));
+       name = emalloc(sizeof(ar_head.ar_name) + strlen(fname) + 3);
 
        rval = 0;
 
        /* while there are more entries in the archive */
 
        rval = 0;
 
        /* while there are more entries in the archive */
-       while (fread((char *)&ar_head, 1, sizeof(ar_head), fp) ==
-           sizeof(ar_head)) {
+       while (fread((char *)&ar_head, sizeof(ar_head), (size_t)1, fp) == 1) {
                /* bad archive entry - stop processing this archive */
                if (strncmp(ar_head.ar_fmag, ARFMAG, sizeof(ar_head.ar_fmag))) {
                        (void)fprintf(stderr,
                /* bad archive entry - stop processing this archive */
                if (strncmp(ar_head.ar_fmag, ARFMAG, sizeof(ar_head.ar_fmag))) {
                        (void)fprintf(stderr,
@@ -193,53 +210,54 @@ show_archive(fname, fp)
                        return(1);
                }
 
                        return(1);
                }
 
+               /* remember start position of current archive object */
+               last_ar_off = ftell(fp);
+
+               /* skip ranlib entries */
+               if (!strncmp(ar_head.ar_name, RANLIBMAG, sizeof(RANLIBMAG) - 1))
+                       goto skip;
+
                /*
                 * construct a name of the form "archive.a:obj.o:" for the
                 * current archive entry if the object name is to be printed
                 * on each output line
                 */
                /*
                 * construct a name of the form "archive.a:obj.o:" for the
                 * current archive entry if the object name is to be printed
                 * on each output line
                 */
-               if (print_file_each_line) {
-                       (void)sprintf(name, "%s:", fname);
-                       p = name + strlen(name);
-               } else
-                       p = name;
+               p = name;
+               if (print_file_each_line)
+                       p += sprintf(p, "%s:", fname);
                for (i = 0; i < sizeof(ar_head.ar_name); ++i)
                        if (ar_head.ar_name[i] && ar_head.ar_name[i] != ' ')
                                *p++ = ar_head.ar_name[i];
                *p++ = '\0';
 
                for (i = 0; i < sizeof(ar_head.ar_name); ++i)
                        if (ar_head.ar_name[i] && ar_head.ar_name[i] != ' ')
                                *p++ = ar_head.ar_name[i];
                *p++ = '\0';
 
-               /* remember start position of current archive object */
-               last_ar_off = ftell(fp);
-
                /* get and check current object's header */
                /* get and check current object's header */
-               if (fread((char *)&exec_head, 1, sizeof(exec_head), fp) !=
-                   sizeof(exec_head)) {
+               if (fread((char *)&exec_head, sizeof(exec_head),
+                   (size_t)1, fp) != 1) {
                        (void)fprintf(stderr, "nm: %s: premature EOF.\n", name);
                        (void)free(name);
                        return(1);
                }
                        (void)fprintf(stderr, "nm: %s: premature EOF.\n", name);
                        (void)free(name);
                        return(1);
                }
-               if (strcmp(name, RANLIBMAG))
-                       if (N_BADMAG(exec_head)) {
-                               if (!ignore_bad_archive_entries) {
-                                       (void)fprintf(stderr,
-                                           "nm: %s: bad format.\n", name);
-                                       rval = 1;
-                               }
-                       } else {
-                               (void)fseek(fp, (long)-sizeof(exec_head),
-                                   SEEK_CUR);
-                               if (!print_file_each_line)
-                                       (void)printf("\n%s:\n", name);
-                               rval |= show_objfile(name, fp);
+
+               if (N_BADMAG(exec_head)) {
+                       if (!ignore_bad_archive_entries) {
+                               (void)fprintf(stderr,
+                                   "nm: %s: bad format.\n", name);
+                               rval = 1;
                        }
                        }
-               esize = atol(ar_head.ar_size);
+               } else {
+                       (void)fseek(fp, (long)-sizeof(exec_head),
+                           SEEK_CUR);
+                       if (!print_file_each_line)
+                               (void)printf("\n%s:\n", name);
+                       rval |= show_objfile(name, fp);
+               }
 
                /*
 
                /*
-                * skip to next archive object - esize&1 is added to stay
-                * on even starting points relative to the start of the
-                * archive file
+                * skip to next archive object - it starts at the next
+                * even byte boundary
                 */
                 */
-               if (fseek(fp, (long)(last_ar_off + esize + (esize&1)),
+#define even(x) (((x) + 1) & ~1)
+skip:          if (fseek(fp, last_ar_off + even(atol(ar_head.ar_size)),
                    SEEK_SET)) {
                        (void)fprintf(stderr,
                            "nm: %s: %s\n", fname, strerror(errno));
                    SEEK_SET)) {
                        (void)fprintf(stderr,
                            "nm: %s: %s\n", fname, strerror(errno));
@@ -261,14 +279,14 @@ show_objfile(objname, fp)
        char *objname;
        FILE *fp;
 {
        char *objname;
        FILE *fp;
 {
-       register struct nlist *names;
+       register struct nlist *names, *np;
        register int i, nnames, nrawnames;
        struct exec head;
        long stabsize;
        register int i, nnames, nrawnames;
        struct exec head;
        long stabsize;
-       char *stab, *emalloc();
+       char *stab;
 
        /* read a.out header */
 
        /* read a.out header */
-       if (fread((char *)&head, sizeof(head), 1, fp) != 1) {
+       if (fread((char *)&head, sizeof(head), (size_t)1, fp) != 1) {
                (void)fprintf(stderr,
                    "nm: %s: cannot read header.\n", objname);
                return(1);
                (void)fprintf(stderr,
                    "nm: %s: cannot read header.\n", objname);
                return(1);
@@ -305,9 +323,9 @@ show_objfile(objname, fp)
        }
 
        /* get memory for the symbol table */
        }
 
        /* get memory for the symbol table */
-       names = (struct nlist *)emalloc((u_int)head.a_syms);
+       names = emalloc((size_t)head.a_syms);
        nrawnames = head.a_syms / sizeof(*names);
        nrawnames = head.a_syms / sizeof(*names);
-       if (fread((char *)names, 1, (int)head.a_syms, fp) != head.a_syms) {
+       if (fread((char *)names, (size_t)head.a_syms, (size_t)1, fp) != 1) {
                (void)fprintf(stderr,
                    "nm: %s: cannot read symbol table.\n", objname);
                (void)free((char *)names);
                (void)fprintf(stderr,
                    "nm: %s: cannot read symbol table.\n", objname);
                (void)free((char *)names);
@@ -319,20 +337,20 @@ show_objfile(objname, fp)
         * 4-byte-integer gives the total size of the string table
         * _including_ the size specification itself.
         */
         * 4-byte-integer gives the total size of the string table
         * _including_ the size specification itself.
         */
-       if (fread((char *)&stabsize, sizeof(stabsize), 1, fp) != 1) {
+       if (fread((char *)&stabsize, sizeof(stabsize), (size_t)1, fp) != 1) {
                (void)fprintf(stderr,
                    "nm: %s: cannot read stab size.\n", objname);
                (void)free((char *)names);
                return(1);
        }
                (void)fprintf(stderr,
                    "nm: %s: cannot read stab size.\n", objname);
                (void)free((char *)names);
                return(1);
        }
-       stab = emalloc((u_int)stabsize);
+       stab = emalloc((size_t)stabsize);
 
        /*
         * read the string table offset by 4 - all indices into the string
         * table include the size specification.
         */
        stabsize -= 4;          /* we already have the size */
 
        /*
         * read the string table offset by 4 - all indices into the string
         * table include the size specification.
         */
        stabsize -= 4;          /* we already have the size */
-       if (fread(stab + 4, 1, (int)stabsize, fp) != stabsize) {
+       if (fread(stab + 4, (size_t)stabsize, (size_t)1, fp) != 1) {
                (void)fprintf(stderr,
                    "nm: %s: stab truncated..\n", objname);
                (void)free((char *)names);
                (void)fprintf(stderr,
                    "nm: %s: stab truncated..\n", objname);
                (void)free((char *)names);
@@ -349,40 +367,37 @@ show_objfile(objname, fp)
         *
         * filter out all entries which we don't want to print anyway
         */
         *
         * filter out all entries which we don't want to print anyway
         */
-       for (i = nnames = 0; i < nrawnames; ++i) {
-               if (SYMBOL_TYPE(names[i].n_type) == N_UNDF && names[i].n_value)
-                       names[i].n_type = N_COMM | (names[i].n_type & N_EXT);
-               if (!print_all_symbols && IS_DEBUGGER_SYMBOL(names[i].n_type))
+       for (np = names, i = nnames = 0; i < nrawnames; np++, i++) {
+               if (SYMBOL_TYPE(np->n_type) == N_UNDF && np->n_value)
+                       np->n_type = N_COMM | (np->n_type & N_EXT);
+               if (!print_all_symbols && IS_DEBUGGER_SYMBOL(np->n_type))
                        continue;
                        continue;
-               if (print_only_external_symbols &&
-                   !IS_EXTERNAL(names[i].n_type))
+               if (print_only_external_symbols && !IS_EXTERNAL(np->n_type))
                        continue;
                if (print_only_undefined_symbols &&
                        continue;
                if (print_only_undefined_symbols &&
-                   (SYMBOL_TYPE(names[i].n_type) != N_UNDF))
+                   SYMBOL_TYPE(np->n_type) != N_UNDF)
                        continue;
 
                /*
                 * make n_un.n_name a character pointer by adding the string
                 * table's base to n_un.n_strx
                 *
                        continue;
 
                /*
                 * make n_un.n_name a character pointer by adding the string
                 * table's base to n_un.n_strx
                 *
-                * don't mess with null offsets
+                * don't mess with zero offsets
                 */
                 */
-               if (names[i].n_un.n_name)
-                       names[i].n_un.n_name = stab + names[i].n_un.n_strx;
+               if (np->n_un.n_strx)
+                       np->n_un.n_name = stab + np->n_un.n_strx;
                else
                else
-                       names[i].n_un.n_name = "";
-               if (nnames != i)
-                       names[nnames] = names[i];
-               ++nnames;
+                       np->n_un.n_name = "";
+               names[nnames++] = *np;
        }
 
        /* sort the symbol table if applicable */
        }
 
        /* sort the symbol table if applicable */
-       if (sort_func)
-               qsort((char *)names, (int)nnames, sizeof(*names), sort_func);
+       if (sfunc)
+               qsort((char *)names, (size_t)nnames, sizeof(*names), sfunc);
 
        /* print out symbols */
 
        /* print out symbols */
-       for (i = 0; i < nnames; ++i)
-               print_symbol(objname, &names[i]);
+       for (np = names, i = 0; i < nnames; np++, i++)
+               print_symbol(objname, np);
 
        (void)free((char *)names);
        (void)free(stab);
 
        (void)free((char *)names);
        (void)free(stab);
@@ -395,19 +410,19 @@ show_objfile(objname, fp)
  */
 print_symbol(objname, sym)
        char *objname;
  */
 print_symbol(objname, sym)
        char *objname;
-       struct nlist *sym;
+       register struct nlist *sym;
 {
        char *typestring(), typeletter();
 
        if (print_file_each_line)
 {
        char *typestring(), typeletter();
 
        if (print_file_each_line)
-               printf("%s:", objname);
+               (void)printf("%s:", objname);
 
        /*
         * handle undefined-only format seperately (no space is
         * left for symbol values, no type field is printed)
         */
        if (print_only_undefined_symbols) {
 
        /*
         * handle undefined-only format seperately (no space is
         * left for symbol values, no type field is printed)
         */
        if (print_only_undefined_symbols) {
-               printf("%s\n", sym->n_un.n_name);
+               (void)puts(sym->n_un.n_name);
                return;
        }
 
                return;
        }
 
@@ -425,7 +440,7 @@ print_symbol(objname, sym)
                (void)printf(" %c ", typeletter(sym->n_type));
 
        /* print the symbol's name */
                (void)printf(" %c ", typeletter(sym->n_type));
 
        /* print the symbol's name */
-       (void)printf("%s\n", sym->n_un.n_name ? sym->n_un.n_name : "");
+       (void)puts(sym->n_un.n_name);
 }
 
 /*
 }
 
 /*
@@ -510,25 +525,27 @@ typeletter(type)
        return('?');
 }
 
        return('?');
 }
 
-/*
- * cmp_name()
- *     compare two symbols by their names
- */
-cmp_name(a, b)
-       struct nlist *a, *b;
+fname(a0, b0)
+       void *a0, *b0;
 {
 {
-       return(sort_direction == FORWARD ?
-           strcmp(a->n_un.n_name, b->n_un.n_name) :
-           strcmp(b->n_un.n_name, a->n_un.n_name));
+       struct nlist *a = a0, *b = b0;
+
+       return(strcmp(a->n_un.n_name, b->n_un.n_name));
 }
 
 }
 
-/*
- * cmp_value()
- *     compare two symbols by their values
- */
-cmp_value(a, b)
-       struct nlist *a, *b;
+rname(a0, b0)
+       void *a0, *b0;
+{
+       struct nlist *a = a0, *b = b0;
+
+       return(strcmp(b->n_un.n_name, a->n_un.n_name));
+}
+
+value(a0, b0)
+       void *a0, *b0;
 {
 {
+       register struct nlist *a = a0, *b = b0;
+
        if (SYMBOL_TYPE(a->n_type) == N_UNDF)
                if (SYMBOL_TYPE(b->n_type) == N_UNDF)
                        return(0);
        if (SYMBOL_TYPE(a->n_type) == N_UNDF)
                if (SYMBOL_TYPE(b->n_type) == N_UNDF)
                        return(0);
@@ -536,28 +553,32 @@ cmp_value(a, b)
                        return(-1);
        else if (SYMBOL_TYPE(b->n_type) == N_UNDF)
                return(1);
                        return(-1);
        else if (SYMBOL_TYPE(b->n_type) == N_UNDF)
                return(1);
-       if (a->n_value == b->n_value)
-               return(cmp_name(a, b));
-       return(sort_direction == FORWARD ? a->n_value > b->n_value :
-           a->n_value < b->n_value);
+       if (rev) {
+               if (a->n_value == b->n_value)
+                       return(rname(a0, b0));
+               return(b->n_value > a->n_value ? 1 : -1);
+       } else {
+               if (a->n_value == b->n_value)
+                       return(fname(a0, b0));
+               return(a->n_value > b->n_value ? 1 : -1);
+       }
 }
 
 }
 
-char *
+void *
 emalloc(size)
 emalloc(size)
-       u_int size;
+       size_t size;
 {
 {
-       char *p, *malloc();
+       char *p;
 
        /* NOSTRICT */
 
        /* NOSTRICT */
-       if (!(p = malloc(size))) {
-               (void)fprintf(stderr, "nm: no more memory.\n");
-               exit(1);
-       }
-       return(p);
+       if (p = malloc(size))
+               return(p);
+       (void)fprintf(stderr, "nm: %s\n", strerror(errno));
+       exit(1);
 }
 
 usage()
 {
 }
 
 usage()
 {
-       (void)fprintf(stderr, "usage: nm [-agnopruw] [file ...]");
+       (void)fprintf(stderr, "usage: nm [-agnopruw] [file ...]\n");
        exit(1);
 }
        exit(1);
 }