break out special local mail processing (e.g., mapping to the
[unix-history] / usr / src / usr.bin / nm / nm.c
index d261157..c780566 100644 (file)
-#ifndef lint
-static char sccsid[] = "@(#)nm.c 4.5 %G%";
-#endif
 /*
 /*
- * nm - print name list; VAX string table version
+ * Copyright (c) 1989, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Hans Huebner.
+ *
+ * %sccs.include.redist.c%
  */
  */
+
+#ifndef lint
+static char copyright[] =
+"@(#) Copyright (c) 1989, 1993\n\
+       The Regents of the University of California.  All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)nm.c       8.1 (Berkeley) %G%";
+#endif /* not lint */
+
 #include <sys/types.h>
 #include <sys/types.h>
-#include <ar.h>
-#include <stdio.h>
-#include <ctype.h>
 #include <a.out.h>
 #include <stab.h>
 #include <a.out.h>
 #include <stab.h>
-#include <sys/stat.h>
-
-#define        SELECT  archive ? archdr.ar_name : *xargv
-
-int    aflg, gflg, nflg, oflg, pflg, uflg; 
-int    rflg = 1;
-char   **xargv;
-int    archive;
-struct ar_hdr  archdr;
-union {
-       char    mag_armag[SARMAG+1];
-       struct  exec mag_exp;
-} mag_un;
-#define        OARMAG  0177545
-FILE   *fi;
-off_t  off;
-off_t  ftell();
-char   *malloc();
-char   *realloc();
-char   *strp;
-char   *stab();
-off_t  strsiz;
-int    compare();
-int    narg;
-int    errs;
+#include <ar.h>
+#include <ranlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <ctype.h>
+#include <stdio.h>
+#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 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))
+
+void *emalloc();
+
+/*
+ * main()
+ *     parse command line, execute process_file() for each file
+ *     specified on the command line.
+ */
 main(argc, argv)
 main(argc, argv)
-char **argv;
+       int argc;
+       char **argv;
 {
 {
+       extern int optind;
+       int ch, errors;
 
 
-       if (--argc>0 && argv[1][0]=='-' && argv[1][1]!=0) {
-               argv++;
-               while (*++*argv) switch (**argv) {
-
-               case 'n':
-                       nflg++;
-                       continue;
+       while ((ch = getopt(argc, argv, "agnopruw")) != EOF) {
+               switch (ch) {
+               case 'a':
+                       print_all_symbols = 1;
+                       break;
                case 'g':
                case 'g':
-                       gflg++;
-                       continue;
-               case 'u':
-                       uflg++;
-                       continue;
-               case 'r':
-                       rflg = -1;
-                       continue;
-               case 'p':
-                       pflg++;
-                       continue;
+                       print_only_external_symbols = 1;
+                       break;
+               case 'n':
+                       sfunc = value;
+                       break;
                case 'o':
                case 'o':
-                       oflg++;
-                       continue;
-               case 'a':
-                       aflg++;
-                       continue;
+                       print_file_each_line = 1;
+                       break;
+               case 'p':
+                       sfunc = NULL;
+                       break;
+               case 'r':
+                       rev = 1;
+                       break;
+               case 'u':
+                       print_only_undefined_symbols = 1;
+                       break;
+               case 'w':
+                       ignore_bad_archive_entries = 0;
+                       break;
+               case '?':
                default:
                default:
-                       fprintf(stderr, "nm: invalid argument -%c\n",
-                           *argv[0]);
-                       exit(2);
+                       usage();
                }
                }
-               argc--;
        }
        }
-       if (argc == 0) {
-               argc = 1;
-               argv[1] = "a.out";
+       fcount = argc - optind;
+       argv += optind;
+
+       if (rev && sfunc == fname)
+               sfunc = rname;
+
+       if (!fcount)
+               errors = process_file("a.out");
+       else {
+               errors = 0;
+               do {
+                       errors |= process_file(*argv);
+               } while (*++argv);
+       }
+       exit(errors);
+}
+
+/*
+ * process_file()
+ *     show symbols in the file given as an argument.  Accepts archive and
+ *     object files as input.
+ */
+process_file(fname)
+       char *fname;
+{
+       struct exec exec_head;
+       FILE *fp;
+       int retval;
+       char magic[SARMAG];
+    
+       if (!(fp = fopen(fname, "r"))) {
+               (void)fprintf(stderr, "nm: cannot read %s.\n", fname);
+               return(1);
        }
        }
-       narg = argc;
-       xargv = argv;
-       while (argc--) {
-               ++xargv;
-               namelist();
+
+       if (fcount > 1)
+               (void)printf("\n%s:\n", fname);
+    
+       /*
+        * first check whether this is an object file - read a object
+        * header, and skip back to the beginning
+        */
+       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);
        }
        }
-       exit(errs);
+       rewind(fp);
+
+       /* this could be an archive */
+       if (N_BADMAG(exec_head)) {
+               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);
+                       (void)fclose(fp);
+                       return(1);
+               }
+               retval = show_archive(fname, fp);
+       } else
+               retval = show_objfile(fname, fp);
+       (void)fclose(fp);
+       return(retval);
 }
 
 }
 
-namelist()
+/*
+ * show_archive()
+ *     show symbols in the given archive file
+ */
+show_archive(fname, fp)
+       char *fname;
+       FILE *fp;
 {
 {
-       register int j;
+       struct ar_hdr ar_head;
+       struct exec exec_head;
+       int i, rval;
+       long last_ar_off;
+       char *p, *name;
 
 
-       archive = 0;
-       fi = fopen(*xargv, "r");
-       if (fi == NULL) {
-               error(0, "cannot open");
-               return;
+       name = emalloc(sizeof(ar_head.ar_name) + strlen(fname) + 3);
+
+       rval = 0;
+
+       /* while there are more entries in the archive */
+       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,
+                           "nm: %s: bad format archive header", fname);
+                       (void)free(name);
+                       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
+                */
+               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';
+
+               /* get and check current object's header */
+               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);
+               }
+
+               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);
+               }
+
+               /*
+                * skip to next archive object - it starts at the next
+                * even byte boundary
+                */
+#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));
+                       (void)free(name);
+                       return(1);
+               }
        }
        }
-       off = SARMAG;
-       fread((char *)&mag_un, 1, sizeof(mag_un), fi);
-       if (mag_un.mag_exp.a_magic == OARMAG) {
-               error(0, "old archive");
-               return;
+       (void)free(name);
+       return(rval);
+}
+
+/*
+ * show_objfile()
+ *     show symbols from the object file pointed to by fp.  The current
+ *     file pointer for fp is expected to be at the beginning of an a.out
+ *     header.
+ */
+show_objfile(objname, fp)
+       char *objname;
+       FILE *fp;
+{
+       register struct nlist *names, *np;
+       register int i, nnames, nrawnames;
+       struct exec head;
+       long stabsize;
+       char *stab;
+
+       /* read a.out header */
+       if (fread((char *)&head, sizeof(head), (size_t)1, fp) != 1) {
+               (void)fprintf(stderr,
+                   "nm: %s: cannot read header.\n", objname);
+               return(1);
        }
        }
-       if (strncmp(mag_un.mag_armag, ARMAG, SARMAG)==0)
-               archive++;
-       else if (N_BADMAG(mag_un.mag_exp)) {
-               error(0, "bad format");
-               return;
+
+       /*
+        * skip back to the header - the N_-macros return values relative
+        * to the beginning of the a.out header
+        */
+       if (fseek(fp, (long)-sizeof(head), SEEK_CUR)) {
+               (void)fprintf(stderr,
+                   "nm: %s: %s\n", objname, strerror(errno));
+               return(1);
        }
        }
-       fseek(fi, 0L, 0);
-       if (archive) {
-               nextel(fi);
-               if (narg > 1)
-                       printf("\n%s:\n", *xargv);
+
+       /* stop if this is no valid object file */
+       if (N_BADMAG(head)) {
+               (void)fprintf(stderr,
+                   "nm: %s: bad format.\n", objname);
+               return(1);
        }
        }
-       do {
-               off_t o;
-               register i, n, c;
-               struct nlist *symp = NULL;
-               struct nlist sym;
-               struct stat stb;
-
-               fread((char *)&mag_un.mag_exp, 1, sizeof(struct exec), fi);
-               if (N_BADMAG(mag_un.mag_exp))
-                       continue;
-               if (archive == 0)
-                       fstat(fileno(fi), &stb);
-               o = N_SYMOFF(mag_un.mag_exp) - sizeof (struct exec);
-               fseek(fi, o, 1);
-               n = mag_un.mag_exp.a_syms / sizeof(struct nlist);
-               if (n == 0) {
-                       error(0, "no name list");
+
+       /* stop if the object file contains no symbol table */
+       if (!head.a_syms) {
+               (void)fprintf(stderr,
+                   "nm: %s: no name list.\n", objname);
+               return(1);
+       }
+
+       if (fseek(fp, (long)N_SYMOFF(head), SEEK_CUR)) {
+               (void)fprintf(stderr,
+                   "nm: %s: %s\n", objname, strerror(errno));
+               return(1);
+       }
+
+       /* get memory for the symbol table */
+       names = emalloc((size_t)head.a_syms);
+       nrawnames = head.a_syms / sizeof(*names);
+       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);
+               return(1);
+       }
+
+       /*
+        * Following the symbol table comes the string table.  The first
+        * 4-byte-integer gives the total size of the string table
+        * _including_ the size specification itself.
+        */
+       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);
+       }
+       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 */
+       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)free(stab);
+               return(1);
+       }
+
+       /*
+        * fix up the symbol table and filter out unwanted entries
+        *
+        * common symbols are characterized by a n_type of N_UNDF and a
+        * non-zero n_value -- change n_type to N_COMM for all such
+        * symbols to make life easier later.
+        *
+        * filter out all entries which we don't want to print anyway
+        */
+       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 (N_STROFF(mag_un.mag_exp) + sizeof (off_t) >
-                   (archive ? off : stb.st_size)) {
-                       error(0, "old format .o (no string table) or truncated file");
+               if (print_only_external_symbols && !IS_EXTERNAL(np->n_type))
                        continue;
                        continue;
-               }
-               i = 0;
-               if (strp)
-                       free(strp), strp = 0;
-               while (--n >= 0) {
-                       fread((char *)&sym, 1, sizeof(sym), fi);
-                       if (gflg && (sym.n_type&N_EXT)==0)
-                               continue;
-                       if ((sym.n_type&N_STAB) && (!aflg||gflg||uflg))
-                               continue;
-                       if (symp==NULL)
-                               symp = (struct nlist *)
-                                   malloc(sizeof(struct nlist));
-                       else
-                               symp = (struct nlist *)
-                                   realloc(symp,
-                                       (i+1)*sizeof(struct nlist));
-                       if (symp == NULL)
-                               error(1, "out of memory");
-                       symp[i++] = sym;
-               }
-               if (archive && ftell(fi)+sizeof(off_t) >= off) {
-                       error(0, "no string table (old format .o?)");
+               if (print_only_undefined_symbols &&
+                   SYMBOL_TYPE(np->n_type) != N_UNDF)
                        continue;
                        continue;
-               }
-               if (fread((char *)&strsiz,sizeof(strsiz),1,fi) != 1) {
-                       error(0, "no string table (old format .o?)");
-                       goto out;
-               }
-               strp = (char *)malloc(strsiz);
-               if (strp == NULL)
-                       error(1, "ran out of memory");
-               if (fread(strp+sizeof(strsiz),strsiz-sizeof(strsiz),1,fi) != 1)
-                       error(1, "error reading string table");
-               for (j = 0; j < i; j++)
-                       if (symp[j].n_un.n_strx)
-                               symp[j].n_un.n_name =
-                                   symp[j].n_un.n_strx + strp;
-                       else
-                               symp[j].n_un.n_name = "";
-               if (pflg==0)
-                       qsort(symp, i, sizeof(struct nlist), compare);
-               if ((archive || narg>1) && oflg==0)
-                       printf("\n%s:\n", SELECT);
-               psyms(symp, i);
-               if (symp)
-                       free((char *)symp), symp = 0;
-               if (strp)
-                       free((char *)strp), strp = 0;
-       } while(archive && nextel(fi));
-out:
-       fclose(fi);
+
+               /*
+                * make n_un.n_name a character pointer by adding the string
+                * table's base to n_un.n_strx
+                *
+                * don't mess with zero offsets
+                */
+               if (np->n_un.n_strx)
+                       np->n_un.n_name = stab + np->n_un.n_strx;
+               else
+                       np->n_un.n_name = "";
+               names[nnames++] = *np;
+       }
+
+       /* sort the symbol table if applicable */
+       if (sfunc)
+               qsort((char *)names, (size_t)nnames, sizeof(*names), sfunc);
+
+       /* print out symbols */
+       for (np = names, i = 0; i < nnames; np++, i++)
+               print_symbol(objname, np);
+
+       (void)free((char *)names);
+       (void)free(stab);
+       return(0);
 }
 
 }
 
-psyms(symp, nsyms)
-       register struct nlist *symp;
-       int nsyms;
+/*
+ * print_symbol()
+ *     show one symbol
+ */
+print_symbol(objname, sym)
+       char *objname;
+       register struct nlist *sym;
 {
 {
-       register int n, c;
-
-       for (n=0; n<nsyms; n++) {
-               c = symp[n].n_type;
-               if (c & N_STAB) {
-                       if (oflg) {
-                               if (archive)
-                                       printf("%s:", *xargv);
-                               printf("%s:", SELECT);
-                       }
-                       printf("%08x - %02x %04x %5.5s %s\n",
-                           symp[n].n_value,
-                           symp[n].n_other & 0xff, symp[n].n_desc & 0xffff,
-                           stab(symp[n].n_type & 0xff),
-                           symp[n].n_un.n_name);
-                       continue;
-               }
-               switch (c&N_TYPE) {
+       char *typestring(), typeletter();
 
 
-               case N_UNDF:
-                       c = 'u';
-                       if (symp[n].n_value)
-                               c = 'c';
-                       break;
-               case N_ABS:
-                       c = 'a';
-                       break;
-               case N_TEXT:
-                       c = 't';
-                       break;
-               case N_DATA:
-                       c = 'd';
-                       break;
-               case N_BSS:
-                       c = 'b';
-                       break;
-               case N_FN:
-                       c = 'f';
-                       break;
-               }
-               if (uflg && c!='u')
-                       continue;
-               if (oflg) {
-                       if (archive)
-                               printf("%s:", *xargv);
-                       printf("%s:", SELECT);
-               }
-               if (symp[n].n_type&N_EXT)
-                       c = toupper(c);
-               if (!uflg) {
-                       if (c=='u' || c=='U')
-                               printf("        ");
-                       else
-                               printf(N_FORMAT, symp[n].n_value);
-                       printf(" %c ", c);
-               }
-               printf("%s\n", symp[n].n_un.n_name);
-l1:            ;
+       if (print_file_each_line)
+               (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) {
+               (void)puts(sym->n_un.n_name);
+               return;
        }
        }
+
+       /* print symbol's value */
+       if (SYMBOL_TYPE(sym->n_type) == N_UNDF)
+               (void)printf("        ");
+       else
+               (void)printf("%08lx", sym->n_value);
+
+       /* print type information */
+       if (IS_DEBUGGER_SYMBOL(sym->n_type))
+               (void)printf(" - %02x %04x %5s ", sym->n_other,
+                   sym->n_desc&0xffff, typestring(sym->n_type));
+       else
+               (void)printf(" %c ", typeletter(sym->n_type));
+
+       /* print the symbol's name */
+       (void)puts(sym->n_un.n_name);
 }
 
 }
 
-compare(p1, p2)
-struct nlist *p1, *p2;
+/*
+ * typestring()
+ *     return the a description string for an STAB entry
+ */
+char *
+typestring(type)
+       register u_char type;
 {
 {
-       register i;
+       switch(type) {
+       case N_BCOMM:
+               return("BCOMM");
+       case N_ECOML:
+               return("ECOML");
+       case N_ECOMM:
+               return("ECOMM");
+       case N_ENTRY:
+               return("ENTRY");
+       case N_FNAME:
+               return("FNAME");
+       case N_FUN:
+               return("FUN");
+       case N_GSYM:
+               return("GSYM");
+       case N_LBRAC:
+               return("LBRAC");
+       case N_LCSYM:
+               return("LCSYM");
+       case N_LENG:
+               return("LENG");
+       case N_LSYM:
+               return("LSYM");
+       case N_PC:
+               return("PC");
+       case N_PSYM:
+               return("PSYM");
+       case N_RBRAC:
+               return("RBRAC");
+       case N_RSYM:
+               return("RSYM");
+       case N_SLINE:
+               return("SLINE");
+       case N_SO:
+               return("SO");
+       case N_SOL:
+               return("SOL");
+       case N_SSYM:
+               return("SSYM");
+       case N_STSYM:
+               return("STSYM");
+       }
+       return("???");
+}
 
 
-       if (nflg) {
-               if (p1->n_value > p2->n_value)
-                       return(rflg);
-               if (p1->n_value < p2->n_value)
-                       return(-rflg);
+/*
+ * typeletter()
+ *     return a description letter for the given basic type code of an
+ *     symbol table entry.  The return value will be upper case for
+ *     external, lower case for internal symbols.
+ */
+char
+typeletter(type)
+       u_char type;
+{
+       switch(SYMBOL_TYPE(type)) {
+       case N_ABS:
+               return(IS_EXTERNAL(type) ? 'A' : 'a');
+       case N_BSS:
+               return(IS_EXTERNAL(type) ? 'B' : 'b');
+       case N_COMM:
+               return(IS_EXTERNAL(type) ? 'C' : 'c');
+       case N_DATA:
+               return(IS_EXTERNAL(type) ? 'D' : 'd');
+       case N_FN:
+               return(IS_EXTERNAL(type) ? 'F' : 'f');
+       case N_TEXT:
+               return(IS_EXTERNAL(type) ? 'T' : 't');
+       case N_UNDF:
+               return(IS_EXTERNAL(type) ? 'U' : 'u');
        }
        }
-       return (rflg * strcmp(p1->n_un.n_name, p2->n_un.n_name));
+       return('?');
 }
 
 }
 
-nextel(af)
-FILE *af;
+fname(a0, b0)
+       void *a0, *b0;
 {
 {
-       register char *cp;
-       register r;
-       long arsize;
-
-       fseek(af, off, 0);
-       r = fread((char *)&archdr, 1, sizeof(struct ar_hdr), af);
-       if (r != sizeof(struct ar_hdr))
-               return(0);
-       for (cp = archdr.ar_name; cp < &archdr.ar_name[sizeof(archdr.ar_name)]; cp++)
-               if (*cp == ' ')
-                       *cp = '\0';
-       arsize = atol(archdr.ar_size);
-       if (arsize & 1)
-               ++arsize;
-       off = ftell(af) + arsize;       /* beginning of next element */
-       return(1);
+       struct nlist *a = a0, *b = b0;
+
+       return(strcmp(a->n_un.n_name, b->n_un.n_name));
 }
 
 }
 
-error(n, s)
-char *s;
+rname(a0, b0)
+       void *a0, *b0;
 {
 {
-       fprintf(stderr, "nm: %s:", *xargv);
-       if (archive) {
-               fprintf(stderr, "(%s)", archdr.ar_name);
-               fprintf(stderr, ": ");
-       } else
-               fprintf(stderr, " ");
-       fprintf(stderr, "%s\n", s);
-       if (n)
-               exit(2);
-       errs = 1;
+       struct nlist *a = a0, *b = b0;
+
+       return(strcmp(b->n_un.n_name, a->n_un.n_name));
 }
 
 }
 
-struct stabnames {
-       int     st_value;
-       char    *st_name;
-} stabnames[] ={
-       N_GSYM, "GSYM",
-       N_FNAME, "FNAME",
-       N_FUN, "FUN",
-       N_STSYM, "STSYM",
-       N_LCSYM, "LCSYM",
-       N_RSYM, "RSYM",
-       N_SLINE, "SLINE",
-       N_SSYM, "SSYM",
-       N_SO, "SO",
-       N_LSYM, "LSYM",
-       N_SOL, "SOL",
-       N_PSYM, "PSYM",
-       N_ENTRY, "ENTRY",
-       N_LBRAC, "LBRAC",
-       N_RBRAC, "RBRAC",
-       N_BCOMM, "BCOMM",
-       N_ECOMM, "ECOMM",
-       N_ECOML, "ECOML",
-       N_LENG, "LENG",
-       N_PC, "PC",
-       0, 0
-};
+value(a0, b0)
+       void *a0, *b0;
+{
+       register struct nlist *a = a0, *b = b0;
 
 
-char *
-stab(val)
+       if (SYMBOL_TYPE(a->n_type) == N_UNDF)
+               if (SYMBOL_TYPE(b->n_type) == N_UNDF)
+                       return(0);
+               else
+                       return(-1);
+       else if (SYMBOL_TYPE(b->n_type) == N_UNDF)
+               return(1);
+       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);
+       }
+}
+
+void *
+emalloc(size)
+       size_t size;
+{
+       char *p;
+
+       /* NOSTRICT */
+       if (p = malloc(size))
+               return(p);
+       (void)fprintf(stderr, "nm: %s\n", strerror(errno));
+       exit(1);
+}
+
+usage()
 {
 {
-       register struct stabnames *sp;
-       static char prbuf[32];
-
-       for (sp = stabnames; sp->st_name; sp++)
-               if (sp->st_value == val)
-                       return (sp->st_name);
-       sprintf(prbuf, "%02x", val);
-       return (prbuf);
+       (void)fprintf(stderr, "usage: nm [-agnopruw] [file ...]\n");
+       exit(1);
 }
 }