summaryrefslogtreecommitdiffstats
path: root/usr.bin/nm
diff options
context:
space:
mode:
authorrgrimes <rgrimes@FreeBSD.org>1994-05-27 12:33:43 +0000
committerrgrimes <rgrimes@FreeBSD.org>1994-05-27 12:33:43 +0000
commitf9ab90d9d6d02989a075d0f0074496d5b1045e4b (patch)
treeadd7e996bac5289cdc55e6935750c352505560a9 /usr.bin/nm
parentbe22b15ae2ff8d7fe06b6e14fddf0c5b444a95da (diff)
downloadFreeBSD-src-f9ab90d9d6d02989a075d0f0074496d5b1045e4b.zip
FreeBSD-src-f9ab90d9d6d02989a075d0f0074496d5b1045e4b.tar.gz
BSD 4.4 Lite Usr.bin Sources
Diffstat (limited to 'usr.bin/nm')
-rw-r--r--usr.bin/nm/Makefile5
-rw-r--r--usr.bin/nm/nm.1117
-rw-r--r--usr.bin/nm/nm.c584
3 files changed, 706 insertions, 0 deletions
diff --git a/usr.bin/nm/Makefile b/usr.bin/nm/Makefile
new file mode 100644
index 0000000..5266202
--- /dev/null
+++ b/usr.bin/nm/Makefile
@@ -0,0 +1,5 @@
+# @(#)Makefile 8.1 (Berkeley) 6/6/93
+
+PROG= nm
+
+.include <bsd.prog.mk>
diff --git a/usr.bin/nm/nm.1 b/usr.bin/nm/nm.1
new file mode 100644
index 0000000..ff7cdb2
--- /dev/null
+++ b/usr.bin/nm/nm.1
@@ -0,0 +1,117 @@
+.\" Copyright (c) 1980, 1990, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" 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.
+.\"
+.\" @(#)nm.1 8.1 (Berkeley) 6/6/93
+.\"
+.Dd June 6, 1993
+.Dt NM 1
+.Os BSD 4
+.Sh NAME
+.Nm nm
+.Nd display name list (symbol table)
+.Sh SYNOPSIS
+.Nm nm
+.Op Fl agnopruw
+.Ar
+.Sh DESCRIPTION
+The symbol table (name list) of each object in
+.Ar file(s)
+is displayed.
+If a library (archive) is given,
+.Nm
+displays a list for each
+object archive member.
+If
+.Ar file
+is not present,
+.Nm
+searches for the file
+.Pa a.out
+and if present, displays the symbol
+table for
+.Pa a.out .
+.Bl -tag -width flag
+.It Fl a
+Display symbol table entries inserted for use by debuggers.
+.It Fl g
+Restrict display to external (global) symbols.
+.It Fl n
+Present results in numerical order.
+.It Fl o
+Display full path or library name of object on every line.
+.It Fl p
+Do not sort at all.
+.It Fl r
+Reverse order sort.
+.It Fl u
+Display undefined symbols only.
+.It Fl w
+Warn about non-object archive members.
+Normally, nm will silently ignore all archive members which are not
+object files.
+.El
+.Pp
+Each symbol name is preceded by its value (a blank field if the symbol
+is undefined) and one of the following letters:
+.Pp
+.Bl -tag -width Ds -compact -offset indent
+.It Fl
+debugger symbol table entries (see the
+.Fl a
+option).
+.It Li A
+absolute
+.It Li B
+bss segment symbol
+.It Li C
+common symbol
+.It Li D
+data segment symbol
+.It Li f
+file name
+.It Li T
+text segment symbol
+.It Li U
+undefined
+.El
+.Pp
+If the symbol is local (non-external) the type letter is in lower case.
+The output is sorted alphabetically.
+.Sh SEE ALSO
+.Xr ar 1 ,
+.Xr ar 5 ,
+.Xr a.out 5 ,
+.Xr stab 5
+.Sh HISTORY
+An
+.Nm nm
+command appeared in
+.At v6 .
diff --git a/usr.bin/nm/nm.c b/usr.bin/nm/nm.c
new file mode 100644
index 0000000..6744cf6
--- /dev/null
+++ b/usr.bin/nm/nm.c
@@ -0,0 +1,584 @@
+/*
+ * 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.
+ *
+ * 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
+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) 6/6/93";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <a.out.h>
+#include <stab.h>
+#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)
+ int argc;
+ char **argv;
+{
+ extern int optind;
+ int ch, errors;
+
+ while ((ch = getopt(argc, argv, "agnopruw")) != EOF) {
+ switch (ch) {
+ case 'a':
+ print_all_symbols = 1;
+ break;
+ case 'g':
+ print_only_external_symbols = 1;
+ break;
+ case 'n':
+ sfunc = value;
+ break;
+ case 'o':
+ 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:
+ usage();
+ }
+ }
+ 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);
+ }
+
+ 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);
+ }
+ 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);
+}
+
+/*
+ * show_archive()
+ * show symbols in the given archive file
+ */
+show_archive(fname, fp)
+ char *fname;
+ FILE *fp;
+{
+ struct ar_hdr ar_head;
+ struct exec exec_head;
+ int i, rval;
+ long last_ar_off;
+ char *p, *name;
+
+ 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);
+ }
+ }
+ (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);
+ }
+
+ /*
+ * 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);
+ }
+
+ /* stop if this is no valid object file */
+ if (N_BADMAG(head)) {
+ (void)fprintf(stderr,
+ "nm: %s: bad format.\n", objname);
+ return(1);
+ }
+
+ /* 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;
+ if (print_only_external_symbols && !IS_EXTERNAL(np->n_type))
+ continue;
+ if (print_only_undefined_symbols &&
+ 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
+ *
+ * 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);
+}
+
+/*
+ * print_symbol()
+ * show one symbol
+ */
+print_symbol(objname, sym)
+ char *objname;
+ register struct nlist *sym;
+{
+ char *typestring(), typeletter();
+
+ 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);
+}
+
+/*
+ * typestring()
+ * return the a description string for an STAB entry
+ */
+char *
+typestring(type)
+ register u_char type;
+{
+ 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("???");
+}
+
+/*
+ * 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('?');
+}
+
+fname(a0, b0)
+ void *a0, *b0;
+{
+ struct nlist *a = a0, *b = b0;
+
+ return(strcmp(a->n_un.n_name, b->n_un.n_name));
+}
+
+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);
+ 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()
+{
+ (void)fprintf(stderr, "usage: nm [-agnopruw] [file ...]\n");
+ exit(1);
+}
OpenPOWER on IntegriCloud