xref: /csrg-svn/usr.bin/nm/nm.c (revision 46550)
130855Sbostic /*
239109Sbostic  * Copyright (c) 1989 The Regents of the University of California.
339109Sbostic  * 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
1239109Sbostic char copyright[] =
1339109Sbostic "@(#) Copyright (c) 1989 The Regents of the University of California.\n\
1439109Sbostic  All rights reserved.\n";
1539109Sbostic #endif /* not lint */
1630855Sbostic 
1739109Sbostic #ifndef lint
18*46550Sbostic static char sccsid[] = "@(#)nm.c	5.7 (Berkeley) 02/22/91";
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;
3840272Sbostic int cmp_value(), cmp_name();
3940272Sbostic int (*sort_func)() = cmp_name;
4040272Sbostic 
4139109Sbostic enum { FORWARD, BACKWARD } sort_direction = FORWARD;
4239109Sbostic int fcount;
4330855Sbostic 
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 
4939109Sbostic /*
5039109Sbostic  * main()
5139109Sbostic  *	parse command line, execute process_file() for each file
5239109Sbostic  *	specified on the command line.
5339109Sbostic  */
54619Sbill main(argc, argv)
5539109Sbostic 	int argc;
5639109Sbostic 	char **argv;
57619Sbill {
5839109Sbostic 	extern int optind;
5939109Sbostic 	int ch, errors;
60619Sbill 
6139109Sbostic 	while ((ch = getopt(argc, argv, "agnopruw")) != EOF) {
6239109Sbostic 		switch (ch) {
6330855Sbostic 		case 'a':
6439109Sbostic 			print_all_symbols = 1;
6530855Sbostic 			break;
6630855Sbostic 		case 'g':
6739109Sbostic 			print_only_external_symbols = 1;
6830855Sbostic 			break;
69619Sbill 		case 'n':
7039109Sbostic 			sort_func = cmp_value;
7130855Sbostic 			break;
7230855Sbostic 		case 'o':
7339109Sbostic 			print_file_each_line = 1;
7430855Sbostic 			break;
7530855Sbostic 		case 'p':
7639109Sbostic 			sort_func = NULL;
7730855Sbostic 			break;
78619Sbill 		case 'r':
7939109Sbostic 			sort_direction = BACKWARD;
8030855Sbostic 			break;
8130855Sbostic 		case 'u':
8239109Sbostic 			print_only_undefined_symbols = 1;
8330855Sbostic 			break;
8439109Sbostic 		case 'w':
8539109Sbostic 			ignore_bad_archive_entries = 0;
8639109Sbostic 			break;
8730855Sbostic 		case '?':
88619Sbill 		default:
8939109Sbostic 			usage();
90619Sbill 		}
9139109Sbostic 	}
9239109Sbostic 	fcount = argc - optind;
9330855Sbostic 	argv += optind;
9439109Sbostic 
9539109Sbostic 	if (!fcount)
9639109Sbostic 		errors = process_file("a.out");
9739109Sbostic 	else {
9839109Sbostic 		errors = 0;
9939109Sbostic 		do {
10039109Sbostic 			errors |= process_file(*argv);
10139109Sbostic 		} while (*++argv);
102619Sbill 	}
10339109Sbostic 	exit(errors);
104619Sbill }
105619Sbill 
10639109Sbostic /*
10739109Sbostic  * process_file()
10839109Sbostic  *	show symbols in the file given as an argument.  Accepts archive and
10939109Sbostic  *	object files as input.
11039109Sbostic  */
11139109Sbostic process_file(fname)
11239109Sbostic 	char *fname;
113619Sbill {
11439109Sbostic 	struct exec exec_head;
11539109Sbostic 	FILE *fp;
11639109Sbostic 	int retval;
11739109Sbostic 	char magic[SARMAG];
11839109Sbostic 
11939109Sbostic 	if (!(fp = fopen(fname, "r"))) {
12039109Sbostic 		(void)fprintf(stderr, "nm: cannot read %s.\n", fname);
12139109Sbostic 		return(1);
12239109Sbostic 	}
123619Sbill 
12439109Sbostic 	if (fcount > 1)
12539109Sbostic 		(void)printf("\n%s:\n", fname);
12639109Sbostic 
12730855Sbostic 	/*
12839109Sbostic 	 * first check whether this is an object file - read a object
12939109Sbostic 	 * header, and skip back to the beginning
13030855Sbostic 	 */
13142452Sbostic 	if (fread((char *)&exec_head, sizeof(exec_head), (size_t)1, fp) != 1) {
13239109Sbostic 		(void)fprintf(stderr, "nm: %s: bad format.\n", fname);
13339109Sbostic 		(void)fclose(fp);
13439109Sbostic 		return(1);
135619Sbill 	}
13639109Sbostic 	rewind(fp);
13739109Sbostic 
13839109Sbostic 	/* this could be an archive */
13939109Sbostic 	if (N_BADMAG(exec_head)) {
14042452Sbostic 		if (fread(magic, sizeof(magic), (size_t)1, fp) != 1 ||
14139109Sbostic 		    strncmp(magic, ARMAG, SARMAG)) {
14239109Sbostic 			(void)fprintf(stderr,
14339109Sbostic 			    "nm: %s: not object file or archive.\n", fname);
14439109Sbostic 			(void)fclose(fp);
14539109Sbostic 			return(1);
14630855Sbostic 		}
14739109Sbostic 		retval = show_archive(fname, fp);
14839109Sbostic 	} else
14939109Sbostic 		retval = show_objfile(fname, fp);
15039109Sbostic 	(void)fclose(fp);
15139109Sbostic 	return(retval);
15239109Sbostic }
15339109Sbostic 
15439109Sbostic /*
15539109Sbostic  * show_archive()
15639109Sbostic  *	show symbols in the given archive file
15739109Sbostic  */
15839109Sbostic show_archive(fname, fp)
15939109Sbostic 	char *fname;
16039109Sbostic 	FILE *fp;
16139109Sbostic {
16239109Sbostic 	struct ar_hdr ar_head;
16339109Sbostic 	struct exec exec_head;
16442452Sbostic 	int i, rval;
16542452Sbostic 	long last_ar_off;
16639109Sbostic 	char *p, *name, *emalloc();
16739109Sbostic 	long atol();
16839109Sbostic 
16942452Sbostic 	name = emalloc(sizeof(ar_head.ar_name) + strlen(fname) + 3);
17039109Sbostic 
17139109Sbostic 	rval = 0;
17239109Sbostic 
17339109Sbostic 	/* while there are more entries in the archive */
17442452Sbostic 	while (fread((char *)&ar_head, sizeof(ar_head), (size_t)1, fp) == 1) {
17539109Sbostic 		/* bad archive entry - stop processing this archive */
17639109Sbostic 		if (strncmp(ar_head.ar_fmag, ARFMAG, sizeof(ar_head.ar_fmag))) {
17739109Sbostic 			(void)fprintf(stderr,
17839109Sbostic 			    "nm: %s: bad format archive header", fname);
17939109Sbostic 			(void)free(name);
18039109Sbostic 			return(1);
18139109Sbostic 		}
18239109Sbostic 
183*46550Sbostic 		/* remember start position of current archive object */
184*46550Sbostic 		last_ar_off = ftell(fp);
185*46550Sbostic 
186*46550Sbostic 		/* skip ranlib entries */
187*46550Sbostic 		if (!strncmp(ar_head.ar_name, RANLIBMAG, sizeof(RANLIBMAG) - 1))
188*46550Sbostic 			goto skip;
189*46550Sbostic 
19030855Sbostic 		/*
19139143Sbostic 		 * construct a name of the form "archive.a:obj.o:" for the
19239109Sbostic 		 * current archive entry if the object name is to be printed
19339109Sbostic 		 * on each output line
19430855Sbostic 		 */
19542452Sbostic 		p = name;
19642452Sbostic 		if (print_file_each_line)
19742452Sbostic 			p += sprintf(p, "%s:", fname);
19839109Sbostic 		for (i = 0; i < sizeof(ar_head.ar_name); ++i)
19939109Sbostic 			if (ar_head.ar_name[i] && ar_head.ar_name[i] != ' ')
20039109Sbostic 				*p++ = ar_head.ar_name[i];
20139109Sbostic 		*p++ = '\0';
20230855Sbostic 
20339109Sbostic 		/* get and check current object's header */
20442452Sbostic 		if (fread((char *)&exec_head, sizeof(exec_head),
20542452Sbostic 		    (size_t)1, fp) != 1) {
20639109Sbostic 			(void)fprintf(stderr, "nm: %s: premature EOF.\n", name);
20739109Sbostic 			(void)free(name);
20839109Sbostic 			return(1);
209619Sbill 		}
210*46550Sbostic 
211*46550Sbostic 		if (N_BADMAG(exec_head)) {
212*46550Sbostic 			if (!ignore_bad_archive_entries) {
213*46550Sbostic 				(void)fprintf(stderr,
214*46550Sbostic 				    "nm: %s: bad format.\n", name);
215*46550Sbostic 				rval = 1;
21639109Sbostic 			}
217*46550Sbostic 		} else {
218*46550Sbostic 			(void)fseek(fp, (long)-sizeof(exec_head),
219*46550Sbostic 			    SEEK_CUR);
220*46550Sbostic 			if (!print_file_each_line)
221*46550Sbostic 				(void)printf("\n%s:\n", name);
222*46550Sbostic 			rval |= show_objfile(name, fp);
223*46550Sbostic 		}
22430855Sbostic 
22539109Sbostic 		/*
22642452Sbostic 		 * skip to next archive object - it starts at the next
22742452Sbostic 	 	 * even byte boundary
22839109Sbostic 		 */
22942452Sbostic #define even(x) (((x) + 1) & ~1)
230*46550Sbostic skip:		if (fseek(fp, last_ar_off + even(atol(ar_head.ar_size)),
23139109Sbostic 		    SEEK_SET)) {
23239109Sbostic 			(void)fprintf(stderr,
23339109Sbostic 			    "nm: %s: %s\n", fname, strerror(errno));
23439109Sbostic 			(void)free(name);
23539109Sbostic 			return(1);
23630855Sbostic 		}
23739109Sbostic 	}
23839109Sbostic 	(void)free(name);
23939109Sbostic 	return(rval);
24039109Sbostic }
24130855Sbostic 
24239109Sbostic /*
24339109Sbostic  * show_objfile()
24439109Sbostic  *	show symbols from the object file pointed to by fp.  The current
24539109Sbostic  *	file pointer for fp is expected to be at the beginning of an a.out
24639109Sbostic  *	header.
24739109Sbostic  */
24839109Sbostic show_objfile(objname, fp)
24939109Sbostic 	char *objname;
25039109Sbostic 	FILE *fp;
25139109Sbostic {
25242452Sbostic 	register struct nlist *names, *np;
25339109Sbostic 	register int i, nnames, nrawnames;
25439109Sbostic 	struct exec head;
25539109Sbostic 	long stabsize;
25639109Sbostic 	char *stab, *emalloc();
25739109Sbostic 
25839109Sbostic 	/* read a.out header */
25942452Sbostic 	if (fread((char *)&head, sizeof(head), (size_t)1, fp) != 1) {
26039109Sbostic 		(void)fprintf(stderr,
26139109Sbostic 		    "nm: %s: cannot read header.\n", objname);
26239109Sbostic 		return(1);
26339109Sbostic 	}
26439109Sbostic 
26539109Sbostic 	/*
26639109Sbostic 	 * skip back to the header - the N_-macros return values relative
26739109Sbostic 	 * to the beginning of the a.out header
26839109Sbostic 	 */
26939109Sbostic 	if (fseek(fp, (long)-sizeof(head), SEEK_CUR)) {
27039109Sbostic 		(void)fprintf(stderr,
27139109Sbostic 		    "nm: %s: %s\n", objname, strerror(errno));
27239109Sbostic 		return(1);
27339109Sbostic 	}
27439109Sbostic 
27539109Sbostic 	/* stop if this is no valid object file */
27639109Sbostic 	if (N_BADMAG(head)) {
27739109Sbostic 		(void)fprintf(stderr,
27839109Sbostic 		    "nm: %s: bad format.\n", objname);
27939109Sbostic 		return(1);
28039109Sbostic 	}
28139109Sbostic 
28239109Sbostic 	/* stop if the object file contains no symbol table */
28339109Sbostic 	if (!head.a_syms) {
28439109Sbostic 		(void)fprintf(stderr,
28539109Sbostic 		    "nm: %s: no name list.\n", objname);
28639109Sbostic 		return(1);
28739109Sbostic 	}
28839109Sbostic 
28939109Sbostic 	if (fseek(fp, (long)N_SYMOFF(head), SEEK_CUR)) {
29039109Sbostic 		(void)fprintf(stderr,
29139109Sbostic 		    "nm: %s: %s\n", objname, strerror(errno));
29239109Sbostic 		return(1);
29339109Sbostic 	}
29439109Sbostic 
29539109Sbostic 	/* get memory for the symbol table */
29642452Sbostic 	names = (struct nlist *)emalloc((size_t)head.a_syms);
29739109Sbostic 	nrawnames = head.a_syms / sizeof(*names);
29842452Sbostic 	if (fread((char *)names, (size_t)head.a_syms, (size_t)1, fp) != 1) {
29939109Sbostic 		(void)fprintf(stderr,
30039109Sbostic 		    "nm: %s: cannot read symbol table.\n", objname);
30139109Sbostic 		(void)free((char *)names);
30239109Sbostic 		return(1);
30339109Sbostic 	}
30439109Sbostic 
30539109Sbostic 	/*
30639109Sbostic 	 * Following the symbol table comes the string table.  The first
30739109Sbostic 	 * 4-byte-integer gives the total size of the string table
30839109Sbostic 	 * _including_ the size specification itself.
30939109Sbostic 	 */
31042452Sbostic 	if (fread((char *)&stabsize, sizeof(stabsize), (size_t)1, fp) != 1) {
31139109Sbostic 		(void)fprintf(stderr,
31239109Sbostic 		    "nm: %s: cannot read stab size.\n", objname);
31339109Sbostic 		(void)free((char *)names);
31439109Sbostic 		return(1);
31539109Sbostic 	}
31642452Sbostic 	stab = emalloc((size_t)stabsize);
31739109Sbostic 
31839109Sbostic 	/*
31939109Sbostic 	 * read the string table offset by 4 - all indices into the string
32039109Sbostic 	 * table include the size specification.
32139109Sbostic 	 */
32239143Sbostic 	stabsize -= 4;		/* we already have the size */
32342452Sbostic 	if (fread(stab + 4, (size_t)stabsize, (size_t)1, fp) != 1) {
32439109Sbostic 		(void)fprintf(stderr,
32539109Sbostic 		    "nm: %s: stab truncated..\n", objname);
32639109Sbostic 		(void)free((char *)names);
32739109Sbostic 		(void)free(stab);
32839109Sbostic 		return(1);
32939109Sbostic 	}
33039109Sbostic 
33139109Sbostic 	/*
33239109Sbostic 	 * fix up the symbol table and filter out unwanted entries
33339109Sbostic 	 *
33439109Sbostic 	 * common symbols are characterized by a n_type of N_UNDF and a
33539109Sbostic 	 * non-zero n_value -- change n_type to N_COMM for all such
33639109Sbostic 	 * symbols to make life easier later.
33739109Sbostic 	 *
33839109Sbostic 	 * filter out all entries which we don't want to print anyway
33939109Sbostic 	 */
34042452Sbostic 	for (np = names, i = nnames = 0; i < nrawnames; np++, i++) {
34142452Sbostic 		if (SYMBOL_TYPE(np->n_type) == N_UNDF && np->n_value)
34242452Sbostic 			np->n_type = N_COMM | (np->n_type & N_EXT);
34342452Sbostic 		if (!print_all_symbols && IS_DEBUGGER_SYMBOL(np->n_type))
34430855Sbostic 			continue;
34542452Sbostic 		if (print_only_external_symbols && !IS_EXTERNAL(np->n_type))
346619Sbill 			continue;
34739109Sbostic 		if (print_only_undefined_symbols &&
34842452Sbostic 		    SYMBOL_TYPE(np->n_type) != N_UNDF)
34939109Sbostic 			continue;
35030855Sbostic 
35139109Sbostic 		/*
35239109Sbostic 		 * make n_un.n_name a character pointer by adding the string
35339109Sbostic 		 * table's base to n_un.n_strx
35439109Sbostic 		 *
35542452Sbostic 		 * don't mess with zero offsets
35639109Sbostic 		 */
35742452Sbostic 		if (np->n_un.n_strx)
35842452Sbostic 			np->n_un.n_name = stab + np->n_un.n_strx;
35939109Sbostic 		else
36042452Sbostic 			np->n_un.n_name = "";
36142452Sbostic 		names[nnames++] = *np;
36239109Sbostic 	}
36330855Sbostic 
36439109Sbostic 	/* sort the symbol table if applicable */
36539109Sbostic 	if (sort_func)
36642452Sbostic 		qsort((char *)names, (size_t)nnames, sizeof(*names), sort_func);
36730855Sbostic 
36839109Sbostic 	/* print out symbols */
36942452Sbostic 	for (np = names, i = 0; i < nnames; np++, i++)
37042452Sbostic 		print_symbol(objname, np);
37130855Sbostic 
37239109Sbostic 	(void)free((char *)names);
37339109Sbostic 	(void)free(stab);
37439109Sbostic 	return(0);
375619Sbill }
376619Sbill 
37739109Sbostic /*
37839109Sbostic  * print_symbol()
37939109Sbostic  *	show one symbol
38039109Sbostic  */
38139109Sbostic print_symbol(objname, sym)
38239109Sbostic 	char *objname;
38342452Sbostic 	register struct nlist *sym;
384619Sbill {
38539109Sbostic 	char *typestring(), typeletter();
386619Sbill 
38739109Sbostic 	if (print_file_each_line)
38842452Sbostic 		(void)printf("%s:", objname);
38939109Sbostic 
39039109Sbostic 	/*
39139109Sbostic 	 * handle undefined-only format seperately (no space is
39239109Sbostic 	 * left for symbol values, no type field is printed)
39339109Sbostic 	 */
39439109Sbostic 	if (print_only_undefined_symbols) {
39542452Sbostic 		(void)puts(sym->n_un.n_name);
39639109Sbostic 		return;
397619Sbill 	}
39839109Sbostic 
39939109Sbostic 	/* print symbol's value */
40039109Sbostic 	if (SYMBOL_TYPE(sym->n_type) == N_UNDF)
40139109Sbostic 		(void)printf("        ");
40239109Sbostic 	else
40339109Sbostic 		(void)printf("%08lx", sym->n_value);
40439109Sbostic 
40539109Sbostic 	/* print type information */
40639109Sbostic 	if (IS_DEBUGGER_SYMBOL(sym->n_type))
40739109Sbostic 		(void)printf(" - %02x %04x %5s ", sym->n_other,
40839109Sbostic 		    sym->n_desc&0xffff, typestring(sym->n_type));
40939109Sbostic 	else
41039109Sbostic 		(void)printf(" %c ", typeletter(sym->n_type));
41139109Sbostic 
41239109Sbostic 	/* print the symbol's name */
41342452Sbostic 	(void)puts(sym->n_un.n_name);
414619Sbill }
415619Sbill 
41639109Sbostic /*
41739109Sbostic  * typestring()
41839109Sbostic  *	return the a description string for an STAB entry
41939109Sbostic  */
42039109Sbostic char *
42139109Sbostic typestring(type)
42239109Sbostic 	register u_char type;
423619Sbill {
42439109Sbostic 	switch(type) {
42539109Sbostic 	case N_BCOMM:
42639109Sbostic 		return("BCOMM");
42739109Sbostic 	case N_ECOML:
42839109Sbostic 		return("ECOML");
42939109Sbostic 	case N_ECOMM:
43039109Sbostic 		return("ECOMM");
43139109Sbostic 	case N_ENTRY:
43239109Sbostic 		return("ENTRY");
43339109Sbostic 	case N_FNAME:
43439109Sbostic 		return("FNAME");
43539109Sbostic 	case N_FUN:
43639109Sbostic 		return("FUN");
43739109Sbostic 	case N_GSYM:
43839109Sbostic 		return("GSYM");
43939109Sbostic 	case N_LBRAC:
44039109Sbostic 		return("LBRAC");
44139109Sbostic 	case N_LCSYM:
44239109Sbostic 		return("LCSYM");
44339109Sbostic 	case N_LENG:
44439109Sbostic 		return("LENG");
44539109Sbostic 	case N_LSYM:
44639109Sbostic 		return("LSYM");
44739109Sbostic 	case N_PC:
44839109Sbostic 		return("PC");
44939109Sbostic 	case N_PSYM:
45039109Sbostic 		return("PSYM");
45139109Sbostic 	case N_RBRAC:
45239109Sbostic 		return("RBRAC");
45339109Sbostic 	case N_RSYM:
45439109Sbostic 		return("RSYM");
45539109Sbostic 	case N_SLINE:
45639109Sbostic 		return("SLINE");
45739109Sbostic 	case N_SO:
45839109Sbostic 		return("SO");
45939109Sbostic 	case N_SOL:
46039109Sbostic 		return("SOL");
46139109Sbostic 	case N_SSYM:
46239109Sbostic 		return("SSYM");
46339109Sbostic 	case N_STSYM:
46439109Sbostic 		return("STSYM");
465619Sbill 	}
46639109Sbostic 	return("???");
467619Sbill }
468619Sbill 
46939109Sbostic /*
47039109Sbostic  * typeletter()
47139109Sbostic  *	return a description letter for the given basic type code of an
47239109Sbostic  *	symbol table entry.  The return value will be upper case for
47339109Sbostic  *	external, lower case for internal symbols.
47439109Sbostic  */
47539109Sbostic char
47639109Sbostic typeletter(type)
47739109Sbostic 	u_char type;
478619Sbill {
47939109Sbostic 	switch(SYMBOL_TYPE(type)) {
48039109Sbostic 	case N_ABS:
48139109Sbostic 		return(IS_EXTERNAL(type) ? 'A' : 'a');
48239109Sbostic 	case N_BSS:
48339109Sbostic 		return(IS_EXTERNAL(type) ? 'B' : 'b');
48439109Sbostic 	case N_COMM:
48539109Sbostic 		return(IS_EXTERNAL(type) ? 'C' : 'c');
48639109Sbostic 	case N_DATA:
48739109Sbostic 		return(IS_EXTERNAL(type) ? 'D' : 'd');
48839109Sbostic 	case N_FN:
48939109Sbostic 		return(IS_EXTERNAL(type) ? 'F' : 'f');
49039109Sbostic 	case N_TEXT:
49139109Sbostic 		return(IS_EXTERNAL(type) ? 'T' : 't');
49239109Sbostic 	case N_UNDF:
49339109Sbostic 		return(IS_EXTERNAL(type) ? 'U' : 'u');
49439109Sbostic 	}
49539109Sbostic 	return('?');
49639109Sbostic }
497619Sbill 
49839109Sbostic /*
49939109Sbostic  * cmp_name()
50039109Sbostic  *	compare two symbols by their names
50139109Sbostic  */
50242452Sbostic cmp_name(a0, b0)
50342452Sbostic 	void *a0, *b0;
50439109Sbostic {
50542452Sbostic 	struct nlist *a = a0, *b = b0;
50642452Sbostic 
50739109Sbostic 	return(sort_direction == FORWARD ?
50839109Sbostic 	    strcmp(a->n_un.n_name, b->n_un.n_name) :
50939109Sbostic 	    strcmp(b->n_un.n_name, a->n_un.n_name));
510619Sbill }
511619Sbill 
51239109Sbostic /*
51339109Sbostic  * cmp_value()
51439109Sbostic  *	compare two symbols by their values
51539109Sbostic  */
51642452Sbostic cmp_value(a0, b0)
51742452Sbostic 	void *a0, *b0;
51839109Sbostic {
51942452Sbostic 	register struct nlist *a = a0, *b = b0;
52042452Sbostic 
52139109Sbostic 	if (SYMBOL_TYPE(a->n_type) == N_UNDF)
52239109Sbostic 		if (SYMBOL_TYPE(b->n_type) == N_UNDF)
52339109Sbostic 			return(0);
52439109Sbostic 		else
52539109Sbostic 			return(-1);
52639109Sbostic 	else if (SYMBOL_TYPE(b->n_type) == N_UNDF)
52739109Sbostic 		return(1);
52839109Sbostic 	if (a->n_value == b->n_value)
52942452Sbostic 		return(cmp_name((void *)a, (void *)b));
53039109Sbostic 	return(sort_direction == FORWARD ? a->n_value > b->n_value :
53139109Sbostic 	    a->n_value < b->n_value);
53239109Sbostic }
533619Sbill 
534619Sbill char *
53539109Sbostic emalloc(size)
53642452Sbostic 	size_t size;
537619Sbill {
53842452Sbostic 	char *p;
539619Sbill 
54039109Sbostic 	/* NOSTRICT */
54139109Sbostic 	if (!(p = malloc(size))) {
54239109Sbostic 		(void)fprintf(stderr, "nm: no more memory.\n");
54339109Sbostic 		exit(1);
54439109Sbostic 	}
54539109Sbostic 	return(p);
546619Sbill }
54730855Sbostic 
54839109Sbostic usage()
54930855Sbostic {
55042452Sbostic 	(void)fprintf(stderr, "usage: nm [-agnopruw] [file ...]\n");
55139109Sbostic 	exit(1);
55230855Sbostic }
553