130855Sbostic /*
2*62154Sbostic * Copyright (c) 1989, 1993
3*62154Sbostic * The Regents of the University of California. All rights reserved.
439109Sbostic *
539109Sbostic * This code is derived from software contributed to Berkeley by
639109Sbostic * Hans Huebner.
739109Sbostic *
842689Sbostic * %sccs.include.redist.c%
930855Sbostic */
1030855Sbostic
1112672Ssam #ifndef lint
12*62154Sbostic static char copyright[] =
13*62154Sbostic "@(#) Copyright (c) 1989, 1993\n\
14*62154Sbostic The Regents of the University of California. All rights reserved.\n";
1539109Sbostic #endif /* not lint */
1630855Sbostic
1739109Sbostic #ifndef lint
18*62154Sbostic static char sccsid[] = "@(#)nm.c 8.1 (Berkeley) 06/06/93";
1939109Sbostic #endif /* not lint */
2030855Sbostic
21619Sbill #include <sys/types.h>
22653Sbill #include <a.out.h>
23619Sbill #include <stab.h>
2439109Sbostic #include <ar.h>
2530855Sbostic #include <ranlib.h>
2639109Sbostic #include <unistd.h>
2739109Sbostic #include <errno.h>
2839109Sbostic #include <ctype.h>
2939109Sbostic #include <stdio.h>
3042452Sbostic #include <stdlib.h>
3142034Sbostic #include <string.h>
32619Sbill
3340272Sbostic int ignore_bad_archive_entries = 1;
3440272Sbostic int print_only_external_symbols;
3540272Sbostic int print_only_undefined_symbols;
3640272Sbostic int print_all_symbols;
3740272Sbostic int print_file_each_line;
3839109Sbostic int fcount;
3930855Sbostic
4048955Sbostic int rev;
4148955Sbostic int fname(), rname(), value();
4248955Sbostic int (*sfunc)() = fname;
4348955Sbostic
4439109Sbostic /* some macros for symbol type (nlist.n_type) handling */
4539109Sbostic #define IS_DEBUGGER_SYMBOL(x) ((x) & N_STAB)
4639109Sbostic #define IS_EXTERNAL(x) ((x) & N_EXT)
4739109Sbostic #define SYMBOL_TYPE(x) ((x) & (N_TYPE | N_STAB))
4830855Sbostic
4948955Sbostic void *emalloc();
5048955Sbostic
5139109Sbostic /*
5239109Sbostic * main()
5339109Sbostic * parse command line, execute process_file() for each file
5439109Sbostic * specified on the command line.
5539109Sbostic */
main(argc,argv)56619Sbill main(argc, argv)
5739109Sbostic int argc;
5839109Sbostic char **argv;
59619Sbill {
6039109Sbostic extern int optind;
6139109Sbostic int ch, errors;
62619Sbill
6339109Sbostic while ((ch = getopt(argc, argv, "agnopruw")) != EOF) {
6439109Sbostic switch (ch) {
6530855Sbostic case 'a':
6639109Sbostic print_all_symbols = 1;
6730855Sbostic break;
6830855Sbostic case 'g':
6939109Sbostic print_only_external_symbols = 1;
7030855Sbostic break;
71619Sbill case 'n':
7248955Sbostic sfunc = value;
7330855Sbostic break;
7430855Sbostic case 'o':
7539109Sbostic print_file_each_line = 1;
7630855Sbostic break;
7730855Sbostic case 'p':
7848955Sbostic sfunc = NULL;
7930855Sbostic break;
80619Sbill case 'r':
8148955Sbostic rev = 1;
8230855Sbostic break;
8330855Sbostic case 'u':
8439109Sbostic print_only_undefined_symbols = 1;
8530855Sbostic break;
8639109Sbostic case 'w':
8739109Sbostic ignore_bad_archive_entries = 0;
8839109Sbostic break;
8930855Sbostic case '?':
90619Sbill default:
9139109Sbostic usage();
92619Sbill }
9339109Sbostic }
9439109Sbostic fcount = argc - optind;
9530855Sbostic argv += optind;
9639109Sbostic
9748955Sbostic if (rev && sfunc == fname)
9848955Sbostic sfunc = rname;
9948955Sbostic
10039109Sbostic if (!fcount)
10139109Sbostic errors = process_file("a.out");
10239109Sbostic else {
10339109Sbostic errors = 0;
10439109Sbostic do {
10539109Sbostic errors |= process_file(*argv);
10639109Sbostic } while (*++argv);
107619Sbill }
10839109Sbostic exit(errors);
109619Sbill }
110619Sbill
11139109Sbostic /*
11239109Sbostic * process_file()
11339109Sbostic * show symbols in the file given as an argument. Accepts archive and
11439109Sbostic * object files as input.
11539109Sbostic */
process_file(fname)11639109Sbostic process_file(fname)
11739109Sbostic char *fname;
118619Sbill {
11939109Sbostic struct exec exec_head;
12039109Sbostic FILE *fp;
12139109Sbostic int retval;
12239109Sbostic char magic[SARMAG];
12339109Sbostic
12439109Sbostic if (!(fp = fopen(fname, "r"))) {
12539109Sbostic (void)fprintf(stderr, "nm: cannot read %s.\n", fname);
12639109Sbostic return(1);
12739109Sbostic }
128619Sbill
12939109Sbostic if (fcount > 1)
13039109Sbostic (void)printf("\n%s:\n", fname);
13139109Sbostic
13230855Sbostic /*
13339109Sbostic * first check whether this is an object file - read a object
13439109Sbostic * header, and skip back to the beginning
13530855Sbostic */
13642452Sbostic if (fread((char *)&exec_head, sizeof(exec_head), (size_t)1, fp) != 1) {
13739109Sbostic (void)fprintf(stderr, "nm: %s: bad format.\n", fname);
13839109Sbostic (void)fclose(fp);
13939109Sbostic return(1);
140619Sbill }
14139109Sbostic rewind(fp);
14239109Sbostic
14339109Sbostic /* this could be an archive */
14439109Sbostic if (N_BADMAG(exec_head)) {
14542452Sbostic if (fread(magic, sizeof(magic), (size_t)1, fp) != 1 ||
14639109Sbostic strncmp(magic, ARMAG, SARMAG)) {
14739109Sbostic (void)fprintf(stderr,
14839109Sbostic "nm: %s: not object file or archive.\n", fname);
14939109Sbostic (void)fclose(fp);
15039109Sbostic return(1);
15130855Sbostic }
15239109Sbostic retval = show_archive(fname, fp);
15339109Sbostic } else
15439109Sbostic retval = show_objfile(fname, fp);
15539109Sbostic (void)fclose(fp);
15639109Sbostic return(retval);
15739109Sbostic }
15839109Sbostic
15939109Sbostic /*
16039109Sbostic * show_archive()
16139109Sbostic * show symbols in the given archive file
16239109Sbostic */
show_archive(fname,fp)16339109Sbostic show_archive(fname, fp)
16439109Sbostic char *fname;
16539109Sbostic FILE *fp;
16639109Sbostic {
16739109Sbostic struct ar_hdr ar_head;
16839109Sbostic struct exec exec_head;
16942452Sbostic int i, rval;
17042452Sbostic long last_ar_off;
17148955Sbostic char *p, *name;
17239109Sbostic
17342452Sbostic name = emalloc(sizeof(ar_head.ar_name) + strlen(fname) + 3);
17439109Sbostic
17539109Sbostic rval = 0;
17639109Sbostic
17739109Sbostic /* while there are more entries in the archive */
17842452Sbostic while (fread((char *)&ar_head, sizeof(ar_head), (size_t)1, fp) == 1) {
17939109Sbostic /* bad archive entry - stop processing this archive */
18039109Sbostic if (strncmp(ar_head.ar_fmag, ARFMAG, sizeof(ar_head.ar_fmag))) {
18139109Sbostic (void)fprintf(stderr,
18239109Sbostic "nm: %s: bad format archive header", fname);
18339109Sbostic (void)free(name);
18439109Sbostic return(1);
18539109Sbostic }
18639109Sbostic
18746550Sbostic /* remember start position of current archive object */
18846550Sbostic last_ar_off = ftell(fp);
18946550Sbostic
19046550Sbostic /* skip ranlib entries */
19146550Sbostic if (!strncmp(ar_head.ar_name, RANLIBMAG, sizeof(RANLIBMAG) - 1))
19246550Sbostic goto skip;
19346550Sbostic
19430855Sbostic /*
19539143Sbostic * construct a name of the form "archive.a:obj.o:" for the
19639109Sbostic * current archive entry if the object name is to be printed
19739109Sbostic * on each output line
19830855Sbostic */
19942452Sbostic p = name;
20042452Sbostic if (print_file_each_line)
20142452Sbostic p += sprintf(p, "%s:", fname);
20239109Sbostic for (i = 0; i < sizeof(ar_head.ar_name); ++i)
20339109Sbostic if (ar_head.ar_name[i] && ar_head.ar_name[i] != ' ')
20439109Sbostic *p++ = ar_head.ar_name[i];
20539109Sbostic *p++ = '\0';
20630855Sbostic
20739109Sbostic /* get and check current object's header */
20842452Sbostic if (fread((char *)&exec_head, sizeof(exec_head),
20942452Sbostic (size_t)1, fp) != 1) {
21039109Sbostic (void)fprintf(stderr, "nm: %s: premature EOF.\n", name);
21139109Sbostic (void)free(name);
21239109Sbostic return(1);
213619Sbill }
21446550Sbostic
21546550Sbostic if (N_BADMAG(exec_head)) {
21646550Sbostic if (!ignore_bad_archive_entries) {
21746550Sbostic (void)fprintf(stderr,
21846550Sbostic "nm: %s: bad format.\n", name);
21946550Sbostic rval = 1;
22039109Sbostic }
22146550Sbostic } else {
22246550Sbostic (void)fseek(fp, (long)-sizeof(exec_head),
22346550Sbostic SEEK_CUR);
22446550Sbostic if (!print_file_each_line)
22546550Sbostic (void)printf("\n%s:\n", name);
22646550Sbostic rval |= show_objfile(name, fp);
22746550Sbostic }
22830855Sbostic
22939109Sbostic /*
23042452Sbostic * skip to next archive object - it starts at the next
23142452Sbostic * even byte boundary
23239109Sbostic */
23342452Sbostic #define even(x) (((x) + 1) & ~1)
23446550Sbostic skip: if (fseek(fp, last_ar_off + even(atol(ar_head.ar_size)),
23539109Sbostic SEEK_SET)) {
23639109Sbostic (void)fprintf(stderr,
23739109Sbostic "nm: %s: %s\n", fname, strerror(errno));
23839109Sbostic (void)free(name);
23939109Sbostic return(1);
24030855Sbostic }
24139109Sbostic }
24239109Sbostic (void)free(name);
24339109Sbostic return(rval);
24439109Sbostic }
24530855Sbostic
24639109Sbostic /*
24739109Sbostic * show_objfile()
24839109Sbostic * show symbols from the object file pointed to by fp. The current
24939109Sbostic * file pointer for fp is expected to be at the beginning of an a.out
25039109Sbostic * header.
25139109Sbostic */
show_objfile(objname,fp)25239109Sbostic show_objfile(objname, fp)
25339109Sbostic char *objname;
25439109Sbostic FILE *fp;
25539109Sbostic {
25642452Sbostic register struct nlist *names, *np;
25739109Sbostic register int i, nnames, nrawnames;
25839109Sbostic struct exec head;
25939109Sbostic long stabsize;
26048955Sbostic char *stab;
26139109Sbostic
26239109Sbostic /* read a.out header */
26342452Sbostic if (fread((char *)&head, sizeof(head), (size_t)1, fp) != 1) {
26439109Sbostic (void)fprintf(stderr,
26539109Sbostic "nm: %s: cannot read header.\n", objname);
26639109Sbostic return(1);
26739109Sbostic }
26839109Sbostic
26939109Sbostic /*
27039109Sbostic * skip back to the header - the N_-macros return values relative
27139109Sbostic * to the beginning of the a.out header
27239109Sbostic */
27339109Sbostic if (fseek(fp, (long)-sizeof(head), SEEK_CUR)) {
27439109Sbostic (void)fprintf(stderr,
27539109Sbostic "nm: %s: %s\n", objname, strerror(errno));
27639109Sbostic return(1);
27739109Sbostic }
27839109Sbostic
27939109Sbostic /* stop if this is no valid object file */
28039109Sbostic if (N_BADMAG(head)) {
28139109Sbostic (void)fprintf(stderr,
28239109Sbostic "nm: %s: bad format.\n", objname);
28339109Sbostic return(1);
28439109Sbostic }
28539109Sbostic
28639109Sbostic /* stop if the object file contains no symbol table */
28739109Sbostic if (!head.a_syms) {
28839109Sbostic (void)fprintf(stderr,
28939109Sbostic "nm: %s: no name list.\n", objname);
29039109Sbostic return(1);
29139109Sbostic }
29239109Sbostic
29339109Sbostic if (fseek(fp, (long)N_SYMOFF(head), SEEK_CUR)) {
29439109Sbostic (void)fprintf(stderr,
29539109Sbostic "nm: %s: %s\n", objname, strerror(errno));
29639109Sbostic return(1);
29739109Sbostic }
29839109Sbostic
29939109Sbostic /* get memory for the symbol table */
30048955Sbostic names = emalloc((size_t)head.a_syms);
30139109Sbostic nrawnames = head.a_syms / sizeof(*names);
30242452Sbostic if (fread((char *)names, (size_t)head.a_syms, (size_t)1, fp) != 1) {
30339109Sbostic (void)fprintf(stderr,
30439109Sbostic "nm: %s: cannot read symbol table.\n", objname);
30539109Sbostic (void)free((char *)names);
30639109Sbostic return(1);
30739109Sbostic }
30839109Sbostic
30939109Sbostic /*
31039109Sbostic * Following the symbol table comes the string table. The first
31139109Sbostic * 4-byte-integer gives the total size of the string table
31239109Sbostic * _including_ the size specification itself.
31339109Sbostic */
31442452Sbostic if (fread((char *)&stabsize, sizeof(stabsize), (size_t)1, fp) != 1) {
31539109Sbostic (void)fprintf(stderr,
31639109Sbostic "nm: %s: cannot read stab size.\n", objname);
31739109Sbostic (void)free((char *)names);
31839109Sbostic return(1);
31939109Sbostic }
32042452Sbostic stab = emalloc((size_t)stabsize);
32139109Sbostic
32239109Sbostic /*
32339109Sbostic * read the string table offset by 4 - all indices into the string
32439109Sbostic * table include the size specification.
32539109Sbostic */
32639143Sbostic stabsize -= 4; /* we already have the size */
32742452Sbostic if (fread(stab + 4, (size_t)stabsize, (size_t)1, fp) != 1) {
32839109Sbostic (void)fprintf(stderr,
32939109Sbostic "nm: %s: stab truncated..\n", objname);
33039109Sbostic (void)free((char *)names);
33139109Sbostic (void)free(stab);
33239109Sbostic return(1);
33339109Sbostic }
33439109Sbostic
33539109Sbostic /*
33639109Sbostic * fix up the symbol table and filter out unwanted entries
33739109Sbostic *
33839109Sbostic * common symbols are characterized by a n_type of N_UNDF and a
33939109Sbostic * non-zero n_value -- change n_type to N_COMM for all such
34039109Sbostic * symbols to make life easier later.
34139109Sbostic *
34239109Sbostic * filter out all entries which we don't want to print anyway
34339109Sbostic */
34442452Sbostic for (np = names, i = nnames = 0; i < nrawnames; np++, i++) {
34542452Sbostic if (SYMBOL_TYPE(np->n_type) == N_UNDF && np->n_value)
34642452Sbostic np->n_type = N_COMM | (np->n_type & N_EXT);
34742452Sbostic if (!print_all_symbols && IS_DEBUGGER_SYMBOL(np->n_type))
34830855Sbostic continue;
34942452Sbostic if (print_only_external_symbols && !IS_EXTERNAL(np->n_type))
350619Sbill continue;
35139109Sbostic if (print_only_undefined_symbols &&
35242452Sbostic SYMBOL_TYPE(np->n_type) != N_UNDF)
35339109Sbostic continue;
35430855Sbostic
35539109Sbostic /*
35639109Sbostic * make n_un.n_name a character pointer by adding the string
35739109Sbostic * table's base to n_un.n_strx
35839109Sbostic *
35942452Sbostic * don't mess with zero offsets
36039109Sbostic */
36142452Sbostic if (np->n_un.n_strx)
36242452Sbostic np->n_un.n_name = stab + np->n_un.n_strx;
36339109Sbostic else
36442452Sbostic np->n_un.n_name = "";
36542452Sbostic names[nnames++] = *np;
36639109Sbostic }
36730855Sbostic
36839109Sbostic /* sort the symbol table if applicable */
36948955Sbostic if (sfunc)
37048955Sbostic qsort((char *)names, (size_t)nnames, sizeof(*names), sfunc);
37130855Sbostic
37239109Sbostic /* print out symbols */
37342452Sbostic for (np = names, i = 0; i < nnames; np++, i++)
37442452Sbostic print_symbol(objname, np);
37530855Sbostic
37639109Sbostic (void)free((char *)names);
37739109Sbostic (void)free(stab);
37839109Sbostic return(0);
379619Sbill }
380619Sbill
38139109Sbostic /*
38239109Sbostic * print_symbol()
38339109Sbostic * show one symbol
38439109Sbostic */
print_symbol(objname,sym)38539109Sbostic print_symbol(objname, sym)
38639109Sbostic char *objname;
38742452Sbostic register struct nlist *sym;
388619Sbill {
38939109Sbostic char *typestring(), typeletter();
390619Sbill
39139109Sbostic if (print_file_each_line)
39242452Sbostic (void)printf("%s:", objname);
39339109Sbostic
39439109Sbostic /*
39539109Sbostic * handle undefined-only format seperately (no space is
39639109Sbostic * left for symbol values, no type field is printed)
39739109Sbostic */
39839109Sbostic if (print_only_undefined_symbols) {
39942452Sbostic (void)puts(sym->n_un.n_name);
40039109Sbostic return;
401619Sbill }
40239109Sbostic
40339109Sbostic /* print symbol's value */
40439109Sbostic if (SYMBOL_TYPE(sym->n_type) == N_UNDF)
40539109Sbostic (void)printf(" ");
40639109Sbostic else
40739109Sbostic (void)printf("%08lx", sym->n_value);
40839109Sbostic
40939109Sbostic /* print type information */
41039109Sbostic if (IS_DEBUGGER_SYMBOL(sym->n_type))
41139109Sbostic (void)printf(" - %02x %04x %5s ", sym->n_other,
41239109Sbostic sym->n_desc&0xffff, typestring(sym->n_type));
41339109Sbostic else
41439109Sbostic (void)printf(" %c ", typeletter(sym->n_type));
41539109Sbostic
41639109Sbostic /* print the symbol's name */
41742452Sbostic (void)puts(sym->n_un.n_name);
418619Sbill }
419619Sbill
42039109Sbostic /*
42139109Sbostic * typestring()
42239109Sbostic * return the a description string for an STAB entry
42339109Sbostic */
42439109Sbostic char *
typestring(type)42539109Sbostic typestring(type)
42639109Sbostic register u_char type;
427619Sbill {
42839109Sbostic switch(type) {
42939109Sbostic case N_BCOMM:
43039109Sbostic return("BCOMM");
43139109Sbostic case N_ECOML:
43239109Sbostic return("ECOML");
43339109Sbostic case N_ECOMM:
43439109Sbostic return("ECOMM");
43539109Sbostic case N_ENTRY:
43639109Sbostic return("ENTRY");
43739109Sbostic case N_FNAME:
43839109Sbostic return("FNAME");
43939109Sbostic case N_FUN:
44039109Sbostic return("FUN");
44139109Sbostic case N_GSYM:
44239109Sbostic return("GSYM");
44339109Sbostic case N_LBRAC:
44439109Sbostic return("LBRAC");
44539109Sbostic case N_LCSYM:
44639109Sbostic return("LCSYM");
44739109Sbostic case N_LENG:
44839109Sbostic return("LENG");
44939109Sbostic case N_LSYM:
45039109Sbostic return("LSYM");
45139109Sbostic case N_PC:
45239109Sbostic return("PC");
45339109Sbostic case N_PSYM:
45439109Sbostic return("PSYM");
45539109Sbostic case N_RBRAC:
45639109Sbostic return("RBRAC");
45739109Sbostic case N_RSYM:
45839109Sbostic return("RSYM");
45939109Sbostic case N_SLINE:
46039109Sbostic return("SLINE");
46139109Sbostic case N_SO:
46239109Sbostic return("SO");
46339109Sbostic case N_SOL:
46439109Sbostic return("SOL");
46539109Sbostic case N_SSYM:
46639109Sbostic return("SSYM");
46739109Sbostic case N_STSYM:
46839109Sbostic return("STSYM");
469619Sbill }
47039109Sbostic return("???");
471619Sbill }
472619Sbill
47339109Sbostic /*
47439109Sbostic * typeletter()
47539109Sbostic * return a description letter for the given basic type code of an
47639109Sbostic * symbol table entry. The return value will be upper case for
47739109Sbostic * external, lower case for internal symbols.
47839109Sbostic */
47939109Sbostic char
typeletter(type)48039109Sbostic typeletter(type)
48139109Sbostic u_char type;
482619Sbill {
48339109Sbostic switch(SYMBOL_TYPE(type)) {
48439109Sbostic case N_ABS:
48539109Sbostic return(IS_EXTERNAL(type) ? 'A' : 'a');
48639109Sbostic case N_BSS:
48739109Sbostic return(IS_EXTERNAL(type) ? 'B' : 'b');
48839109Sbostic case N_COMM:
48939109Sbostic return(IS_EXTERNAL(type) ? 'C' : 'c');
49039109Sbostic case N_DATA:
49139109Sbostic return(IS_EXTERNAL(type) ? 'D' : 'd');
49239109Sbostic case N_FN:
49339109Sbostic return(IS_EXTERNAL(type) ? 'F' : 'f');
49439109Sbostic case N_TEXT:
49539109Sbostic return(IS_EXTERNAL(type) ? 'T' : 't');
49639109Sbostic case N_UNDF:
49739109Sbostic return(IS_EXTERNAL(type) ? 'U' : 'u');
49839109Sbostic }
49939109Sbostic return('?');
50039109Sbostic }
501619Sbill
fname(a0,b0)50248955Sbostic fname(a0, b0)
50342452Sbostic void *a0, *b0;
50439109Sbostic {
50542452Sbostic struct nlist *a = a0, *b = b0;
50642452Sbostic
50748955Sbostic return(strcmp(a->n_un.n_name, b->n_un.n_name));
508619Sbill }
509619Sbill
rname(a0,b0)51048955Sbostic rname(a0, b0)
51142452Sbostic void *a0, *b0;
51239109Sbostic {
51348955Sbostic struct nlist *a = a0, *b = b0;
51448955Sbostic
51548955Sbostic return(strcmp(b->n_un.n_name, a->n_un.n_name));
51648955Sbostic }
51748955Sbostic
value(a0,b0)51848955Sbostic value(a0, b0)
51948955Sbostic void *a0, *b0;
52048955Sbostic {
52142452Sbostic register struct nlist *a = a0, *b = b0;
52242452Sbostic
52339109Sbostic if (SYMBOL_TYPE(a->n_type) == N_UNDF)
52439109Sbostic if (SYMBOL_TYPE(b->n_type) == N_UNDF)
52539109Sbostic return(0);
52639109Sbostic else
52739109Sbostic return(-1);
52839109Sbostic else if (SYMBOL_TYPE(b->n_type) == N_UNDF)
52939109Sbostic return(1);
53048955Sbostic if (rev) {
53148955Sbostic if (a->n_value == b->n_value)
53248955Sbostic return(rname(a0, b0));
53348955Sbostic return(b->n_value > a->n_value ? 1 : -1);
53448955Sbostic } else {
53548955Sbostic if (a->n_value == b->n_value)
53648955Sbostic return(fname(a0, b0));
53748955Sbostic return(a->n_value > b->n_value ? 1 : -1);
53848955Sbostic }
53939109Sbostic }
540619Sbill
54148955Sbostic void *
emalloc(size)54239109Sbostic emalloc(size)
54342452Sbostic size_t size;
544619Sbill {
54542452Sbostic char *p;
546619Sbill
54739109Sbostic /* NOSTRICT */
54848955Sbostic if (p = malloc(size))
54948955Sbostic return(p);
55048955Sbostic (void)fprintf(stderr, "nm: %s\n", strerror(errno));
55148955Sbostic exit(1);
552619Sbill }
55330855Sbostic
usage()55439109Sbostic usage()
55530855Sbostic {
55642452Sbostic (void)fprintf(stderr, "usage: nm [-agnopruw] [file ...]\n");
55739109Sbostic exit(1);
55830855Sbostic }
559