xref: /csrg-svn/usr.bin/nm/nm.c (revision 39143)
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  *
839109Sbostic  * Redistribution and use in source and binary forms are permitted
939109Sbostic  * provided that the above copyright notice and this paragraph are
1039109Sbostic  * duplicated in all such forms and that any documentation,
1139109Sbostic  * advertising materials, and other materials related to such
1239109Sbostic  * distribution and use acknowledge that the software was developed
1339109Sbostic  * by the University of California, Berkeley.  The name of the
1439109Sbostic  * University may not be used to endorse or promote products derived
1539109Sbostic  * from this software without specific prior written permission.
1639109Sbostic  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
1739109Sbostic  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
1839109Sbostic  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1930855Sbostic  */
2030855Sbostic 
2112672Ssam #ifndef lint
2239109Sbostic char copyright[] =
2339109Sbostic "@(#) Copyright (c) 1989 The Regents of the University of California.\n\
2439109Sbostic  All rights reserved.\n";
2539109Sbostic #endif /* not lint */
2630855Sbostic 
2739109Sbostic #ifndef lint
28*39143Sbostic static char sccsid[] = "@(#)nm.c	5.2 (Berkeley) 09/13/89";
2939109Sbostic #endif /* not lint */
3030855Sbostic 
31619Sbill #include <sys/types.h>
32653Sbill #include <a.out.h>
33619Sbill #include <stab.h>
3439109Sbostic #include <ar.h>
3530855Sbostic #include <ranlib.h>
3639109Sbostic #include <unistd.h>
3739109Sbostic #include <errno.h>
3839109Sbostic #include <ctype.h>
3939109Sbostic #include <stdio.h>
4039109Sbostic #include <strings.h>
41619Sbill 
4239109Sbostic int	ignore_bad_archive_entries = 1;
4339109Sbostic int	print_only_external_symbols;
4439109Sbostic int	print_only_undefined_symbols;
4539109Sbostic int	print_all_symbols;
4639109Sbostic int	print_file_each_line;
4739109Sbostic int	cmp_value(), cmp_name();
4839109Sbostic int	(*sort_func)() = cmp_name;
49619Sbill 
5039109Sbostic enum { FORWARD, BACKWARD } sort_direction = FORWARD;
5139109Sbostic int fcount;
5230855Sbostic 
5339109Sbostic /* some macros for symbol type (nlist.n_type) handling */
5439109Sbostic #define	IS_DEBUGGER_SYMBOL(x)	((x) & N_STAB)
5539109Sbostic #define	IS_EXTERNAL(x)		((x) & N_EXT)
5639109Sbostic #define	SYMBOL_TYPE(x)		((x) & (N_TYPE | N_STAB))
5730855Sbostic 
5839109Sbostic /*
5939109Sbostic  * main()
6039109Sbostic  *	parse command line, execute process_file() for each file
6139109Sbostic  *	specified on the command line.
6239109Sbostic  */
63619Sbill main(argc, argv)
6439109Sbostic 	int argc;
6539109Sbostic 	char **argv;
66619Sbill {
6739109Sbostic 	extern int optind;
6839109Sbostic 	int ch, errors;
69619Sbill 
7039109Sbostic 	while ((ch = getopt(argc, argv, "agnopruw")) != EOF) {
7139109Sbostic 		switch (ch) {
7230855Sbostic 		case 'a':
7339109Sbostic 			print_all_symbols = 1;
7430855Sbostic 			break;
7530855Sbostic 		case 'g':
7639109Sbostic 			print_only_external_symbols = 1;
7730855Sbostic 			break;
78619Sbill 		case 'n':
7939109Sbostic 			sort_func = cmp_value;
8030855Sbostic 			break;
8130855Sbostic 		case 'o':
8239109Sbostic 			print_file_each_line = 1;
8330855Sbostic 			break;
8430855Sbostic 		case 'p':
8539109Sbostic 			sort_func = NULL;
8630855Sbostic 			break;
87619Sbill 		case 'r':
8839109Sbostic 			sort_direction = BACKWARD;
8930855Sbostic 			break;
9030855Sbostic 		case 'u':
9139109Sbostic 			print_only_undefined_symbols = 1;
9230855Sbostic 			break;
9339109Sbostic 		case 'w':
9439109Sbostic 			ignore_bad_archive_entries = 0;
9539109Sbostic 			break;
9630855Sbostic 		case '?':
97619Sbill 		default:
9839109Sbostic 			usage();
99619Sbill 		}
10039109Sbostic 	}
10139109Sbostic 	fcount = argc - optind;
10230855Sbostic 	argv += optind;
10339109Sbostic 
10439109Sbostic 	if (!fcount)
10539109Sbostic 		errors = process_file("a.out");
10639109Sbostic 	else {
10739109Sbostic 		errors = 0;
10839109Sbostic 		do {
10939109Sbostic 			errors |= process_file(*argv);
11039109Sbostic 		} while (*++argv);
111619Sbill 	}
11239109Sbostic 	exit(errors);
113619Sbill }
114619Sbill 
11539109Sbostic /*
11639109Sbostic  * process_file()
11739109Sbostic  *	show symbols in the file given as an argument.  Accepts archive and
11839109Sbostic  *	object files as input.
11939109Sbostic  */
12039109Sbostic process_file(fname)
12139109Sbostic 	char *fname;
122619Sbill {
12339109Sbostic 	struct exec exec_head;
12439109Sbostic 	FILE *fp;
12539109Sbostic 	int retval;
12639109Sbostic 	char magic[SARMAG];
12739109Sbostic 
12839109Sbostic 	if (!(fp = fopen(fname, "r"))) {
12939109Sbostic 		(void)fprintf(stderr, "nm: cannot read %s.\n", fname);
13039109Sbostic 		return(1);
13139109Sbostic 	}
132619Sbill 
13339109Sbostic 	if (fcount > 1)
13439109Sbostic 		(void)printf("\n%s:\n", fname);
13539109Sbostic 
13630855Sbostic 	/*
13739109Sbostic 	 * first check whether this is an object file - read a object
13839109Sbostic 	 * header, and skip back to the beginning
13930855Sbostic 	 */
14039109Sbostic 	if (fread((char *)&exec_head, 1, sizeof(exec_head), fp) !=
14139109Sbostic 	    sizeof(exec_head)) {
14239109Sbostic 		(void)fprintf(stderr, "nm: %s: bad format.\n", fname);
14339109Sbostic 		(void)fclose(fp);
14439109Sbostic 		return(1);
145619Sbill 	}
14639109Sbostic 	rewind(fp);
14739109Sbostic 
14839109Sbostic 	/* this could be an archive */
14939109Sbostic 	if (N_BADMAG(exec_head)) {
15039109Sbostic 		if (fread(magic, 1, sizeof(magic), fp) != sizeof(magic) ||
15139109Sbostic 		    strncmp(magic, ARMAG, SARMAG)) {
15239109Sbostic 			(void)fprintf(stderr,
15339109Sbostic 			    "nm: %s: not object file or archive.\n", fname);
15439109Sbostic 			(void)fclose(fp);
15539109Sbostic 			return(1);
15630855Sbostic 		}
15739109Sbostic 		retval = show_archive(fname, fp);
15839109Sbostic 	} else
15939109Sbostic 		retval = show_objfile(fname, fp);
16039109Sbostic 	(void)fclose(fp);
16139109Sbostic 	return(retval);
16239109Sbostic }
16339109Sbostic 
16439109Sbostic /*
16539109Sbostic  * show_archive()
16639109Sbostic  *	show symbols in the given archive file
16739109Sbostic  */
16839109Sbostic show_archive(fname, fp)
16939109Sbostic 	char *fname;
17039109Sbostic 	FILE *fp;
17139109Sbostic {
17239109Sbostic 	extern int errno;
17339109Sbostic 	struct ar_hdr ar_head;
17439109Sbostic 	struct exec exec_head;
17539109Sbostic 	off_t esize;
17639109Sbostic 	int i, last_ar_off, rval;
17739109Sbostic 	char *p, *name, *emalloc();
17839109Sbostic 	long atol();
17939109Sbostic 
18039109Sbostic 	name = emalloc((u_int)(sizeof(ar_head.ar_name) + strlen(fname) + 3));
18139109Sbostic 
18239109Sbostic 	rval = 0;
18339109Sbostic 
18439109Sbostic 	/* while there are more entries in the archive */
18539109Sbostic 	while (fread((char *)&ar_head, 1, sizeof(ar_head), fp) ==
18639109Sbostic 	    sizeof(ar_head)) {
18739109Sbostic 		/* bad archive entry - stop processing this archive */
18839109Sbostic 		if (strncmp(ar_head.ar_fmag, ARFMAG, sizeof(ar_head.ar_fmag))) {
18939109Sbostic 			(void)fprintf(stderr,
19039109Sbostic 			    "nm: %s: bad format archive header", fname);
19139109Sbostic 			(void)free(name);
19239109Sbostic 			return(1);
19339109Sbostic 		}
19439109Sbostic 
19530855Sbostic 		/*
196*39143Sbostic 		 * construct a name of the form "archive.a:obj.o:" for the
19739109Sbostic 		 * current archive entry if the object name is to be printed
19839109Sbostic 		 * on each output line
19930855Sbostic 		 */
20039109Sbostic 		if (print_file_each_line) {
201*39143Sbostic 			(void)sprintf(name, "%s:", fname);
20239109Sbostic 			p = name + strlen(name);
20339109Sbostic 		} else
20439109Sbostic 			p = name;
20539109Sbostic 		for (i = 0; i < sizeof(ar_head.ar_name); ++i)
20639109Sbostic 			if (ar_head.ar_name[i] && ar_head.ar_name[i] != ' ')
20739109Sbostic 				*p++ = ar_head.ar_name[i];
20839109Sbostic 		*p++ = '\0';
20930855Sbostic 
21039109Sbostic 		/* remember start position of current archive object */
21139109Sbostic 		last_ar_off = ftell(fp);
21230855Sbostic 
21339109Sbostic 		/* get and check current object's header */
21439109Sbostic 		if (fread((char *)&exec_head, 1, sizeof(exec_head), fp) !=
21539109Sbostic 		    sizeof(exec_head)) {
21639109Sbostic 			(void)fprintf(stderr, "nm: %s: premature EOF.\n", name);
21739109Sbostic 			(void)free(name);
21839109Sbostic 			return(1);
219619Sbill 		}
22039109Sbostic 		if (strcmp(name, RANLIBMAG))
22139109Sbostic 			if (N_BADMAG(exec_head)) {
22239109Sbostic 				if (!ignore_bad_archive_entries) {
22339109Sbostic 					(void)fprintf(stderr,
22439109Sbostic 					    "nm: %s: bad format.\n", name);
22539109Sbostic 					rval = 1;
22639109Sbostic 				}
22739109Sbostic 			} else {
22839109Sbostic 				(void)fseek(fp, (long)-sizeof(exec_head),
22939109Sbostic 				    SEEK_CUR);
23039109Sbostic 				if (!print_file_each_line)
23139109Sbostic 					(void)printf("\n%s:\n", name);
23239109Sbostic 				rval |= show_objfile(name, fp);
23339109Sbostic 			}
23439109Sbostic 		esize = atol(ar_head.ar_size);
23530855Sbostic 
23639109Sbostic 		/*
23739109Sbostic 		 * skip to next archive object - esize&1 is added to stay
23839109Sbostic 	 	 * on even starting points relative to the start of the
23939109Sbostic 		 * archive file
24039109Sbostic 		 */
24139109Sbostic 		if (fseek(fp, (long)(last_ar_off + esize + (esize&1)),
24239109Sbostic 		    SEEK_SET)) {
24339109Sbostic 			(void)fprintf(stderr,
24439109Sbostic 			    "nm: %s: %s\n", fname, strerror(errno));
24539109Sbostic 			(void)free(name);
24639109Sbostic 			return(1);
24730855Sbostic 		}
24839109Sbostic 	}
24939109Sbostic 	(void)free(name);
25039109Sbostic 	return(rval);
25139109Sbostic }
25230855Sbostic 
25339109Sbostic /*
25439109Sbostic  * show_objfile()
25539109Sbostic  *	show symbols from the object file pointed to by fp.  The current
25639109Sbostic  *	file pointer for fp is expected to be at the beginning of an a.out
25739109Sbostic  *	header.
25839109Sbostic  */
25939109Sbostic show_objfile(objname, fp)
26039109Sbostic 	char *objname;
26139109Sbostic 	FILE *fp;
26239109Sbostic {
26339109Sbostic 	register struct nlist *names;
26439109Sbostic 	register int i, nnames, nrawnames;
26539109Sbostic 	struct exec head;
26639109Sbostic 	long stabsize;
26739109Sbostic 	char *stab, *emalloc();
26839109Sbostic 
26939109Sbostic 	/* read a.out header */
27039109Sbostic 	if (fread((char *)&head, sizeof(head), 1, fp) != 1) {
27139109Sbostic 		(void)fprintf(stderr,
27239109Sbostic 		    "nm: %s: cannot read header.\n", objname);
27339109Sbostic 		return(1);
27439109Sbostic 	}
27539109Sbostic 
27639109Sbostic 	/*
27739109Sbostic 	 * skip back to the header - the N_-macros return values relative
27839109Sbostic 	 * to the beginning of the a.out header
27939109Sbostic 	 */
28039109Sbostic 	if (fseek(fp, (long)-sizeof(head), SEEK_CUR)) {
28139109Sbostic 		(void)fprintf(stderr,
28239109Sbostic 		    "nm: %s: %s\n", objname, strerror(errno));
28339109Sbostic 		return(1);
28439109Sbostic 	}
28539109Sbostic 
28639109Sbostic 	/* stop if this is no valid object file */
28739109Sbostic 	if (N_BADMAG(head)) {
28839109Sbostic 		(void)fprintf(stderr,
28939109Sbostic 		    "nm: %s: bad format.\n", objname);
29039109Sbostic 		return(1);
29139109Sbostic 	}
29239109Sbostic 
29339109Sbostic 	/* stop if the object file contains no symbol table */
29439109Sbostic 	if (!head.a_syms) {
29539109Sbostic 		(void)fprintf(stderr,
29639109Sbostic 		    "nm: %s: no name list.\n", objname);
29739109Sbostic 		return(1);
29839109Sbostic 	}
29939109Sbostic 
30039109Sbostic 	if (fseek(fp, (long)N_SYMOFF(head), SEEK_CUR)) {
30139109Sbostic 		(void)fprintf(stderr,
30239109Sbostic 		    "nm: %s: %s\n", objname, strerror(errno));
30339109Sbostic 		return(1);
30439109Sbostic 	}
30539109Sbostic 
30639109Sbostic 	/* get memory for the symbol table */
30739109Sbostic 	names = (struct nlist *)emalloc((u_int)head.a_syms);
30839109Sbostic 	nrawnames = head.a_syms / sizeof(*names);
30939109Sbostic 	if (fread((char *)names, 1, (int)head.a_syms, fp) != head.a_syms) {
31039109Sbostic 		(void)fprintf(stderr,
31139109Sbostic 		    "nm: %s: cannot read symbol table.\n", objname);
31239109Sbostic 		(void)free((char *)names);
31339109Sbostic 		return(1);
31439109Sbostic 	}
31539109Sbostic 
31639109Sbostic 	/*
31739109Sbostic 	 * Following the symbol table comes the string table.  The first
31839109Sbostic 	 * 4-byte-integer gives the total size of the string table
31939109Sbostic 	 * _including_ the size specification itself.
32039109Sbostic 	 */
32139109Sbostic 	if (fread((char *)&stabsize, sizeof(stabsize), 1, fp) != 1) {
32239109Sbostic 		(void)fprintf(stderr,
32339109Sbostic 		    "nm: %s: cannot read stab size.\n", objname);
32439109Sbostic 		(void)free((char *)names);
32539109Sbostic 		return(1);
32639109Sbostic 	}
32739109Sbostic 	stab = emalloc((u_int)stabsize);
32839109Sbostic 
32939109Sbostic 	/*
33039109Sbostic 	 * read the string table offset by 4 - all indices into the string
33139109Sbostic 	 * table include the size specification.
33239109Sbostic 	 */
333*39143Sbostic 	stabsize -= 4;		/* we already have the size */
33439109Sbostic 	if (fread(stab + 4, 1, (int)stabsize, fp) != stabsize) {
33539109Sbostic 		(void)fprintf(stderr,
33639109Sbostic 		    "nm: %s: stab truncated..\n", objname);
33739109Sbostic 		(void)free((char *)names);
33839109Sbostic 		(void)free(stab);
33939109Sbostic 		return(1);
34039109Sbostic 	}
34139109Sbostic 
34239109Sbostic 	/*
34339109Sbostic 	 * fix up the symbol table and filter out unwanted entries
34439109Sbostic 	 *
34539109Sbostic 	 * common symbols are characterized by a n_type of N_UNDF and a
34639109Sbostic 	 * non-zero n_value -- change n_type to N_COMM for all such
34739109Sbostic 	 * symbols to make life easier later.
34839109Sbostic 	 *
34939109Sbostic 	 * filter out all entries which we don't want to print anyway
35039109Sbostic 	 */
35139109Sbostic 	for (i = nnames = 0; i < nrawnames; ++i) {
35239109Sbostic 		if (SYMBOL_TYPE(names[i].n_type) == N_UNDF && names[i].n_value)
35339109Sbostic 			names[i].n_type = N_COMM | (names[i].n_type & N_EXT);
35439109Sbostic 		if (!print_all_symbols && IS_DEBUGGER_SYMBOL(names[i].n_type))
35530855Sbostic 			continue;
35639109Sbostic 		if (print_only_external_symbols &&
35739109Sbostic 		    !IS_EXTERNAL(names[i].n_type))
358619Sbill 			continue;
35939109Sbostic 		if (print_only_undefined_symbols &&
36039109Sbostic 		    (SYMBOL_TYPE(names[i].n_type) != N_UNDF))
36139109Sbostic 			continue;
36230855Sbostic 
36339109Sbostic 		/*
36439109Sbostic 		 * make n_un.n_name a character pointer by adding the string
36539109Sbostic 		 * table's base to n_un.n_strx
36639109Sbostic 		 *
36739109Sbostic 		 * don't mess with null offsets
36839109Sbostic 		 */
36939109Sbostic 		if (names[i].n_un.n_name)
37039109Sbostic 			names[i].n_un.n_name = stab + names[i].n_un.n_strx;
37139109Sbostic 		else
37239109Sbostic 			names[i].n_un.n_name = "";
37339109Sbostic 		if (nnames != i)
37439109Sbostic 			names[nnames] = names[i];
37539109Sbostic 		++nnames;
37639109Sbostic 	}
37730855Sbostic 
37839109Sbostic 	/* sort the symbol table if applicable */
37939109Sbostic 	if (sort_func)
38039109Sbostic 		qsort((char *)names, (int)nnames, sizeof(*names), sort_func);
38130855Sbostic 
38239109Sbostic 	/* print out symbols */
38339109Sbostic 	for (i = 0; i < nnames; ++i)
38439109Sbostic 		print_symbol(objname, &names[i]);
38530855Sbostic 
38639109Sbostic 	(void)free((char *)names);
38739109Sbostic 	(void)free(stab);
38839109Sbostic 	return(0);
389619Sbill }
390619Sbill 
39139109Sbostic /*
39239109Sbostic  * print_symbol()
39339109Sbostic  *	show one symbol
39439109Sbostic  */
39539109Sbostic print_symbol(objname, sym)
39639109Sbostic 	char *objname;
39739109Sbostic 	struct nlist *sym;
398619Sbill {
39939109Sbostic 	char *typestring(), typeletter();
400619Sbill 
40139109Sbostic 	if (print_file_each_line)
402*39143Sbostic 		printf("%s:", objname);
40339109Sbostic 
40439109Sbostic 	/*
40539109Sbostic 	 * handle undefined-only format seperately (no space is
40639109Sbostic 	 * left for symbol values, no type field is printed)
40739109Sbostic 	 */
40839109Sbostic 	if (print_only_undefined_symbols) {
40939109Sbostic 		printf("%s\n", sym->n_un.n_name);
41039109Sbostic 		return;
411619Sbill 	}
41239109Sbostic 
41339109Sbostic 	/* print symbol's value */
41439109Sbostic 	if (SYMBOL_TYPE(sym->n_type) == N_UNDF)
41539109Sbostic 		(void)printf("        ");
41639109Sbostic 	else
41739109Sbostic 		(void)printf("%08lx", sym->n_value);
41839109Sbostic 
41939109Sbostic 	/* print type information */
42039109Sbostic 	if (IS_DEBUGGER_SYMBOL(sym->n_type))
42139109Sbostic 		(void)printf(" - %02x %04x %5s ", sym->n_other,
42239109Sbostic 		    sym->n_desc&0xffff, typestring(sym->n_type));
42339109Sbostic 	else
42439109Sbostic 		(void)printf(" %c ", typeletter(sym->n_type));
42539109Sbostic 
42639109Sbostic 	/* print the symbol's name */
42739109Sbostic 	(void)printf("%s\n", sym->n_un.n_name ? sym->n_un.n_name : "");
428619Sbill }
429619Sbill 
43039109Sbostic /*
43139109Sbostic  * typestring()
43239109Sbostic  *	return the a description string for an STAB entry
43339109Sbostic  */
43439109Sbostic char *
43539109Sbostic typestring(type)
43639109Sbostic 	register u_char type;
437619Sbill {
43839109Sbostic 	switch(type) {
43939109Sbostic 	case N_BCOMM:
44039109Sbostic 		return("BCOMM");
44139109Sbostic 	case N_ECOML:
44239109Sbostic 		return("ECOML");
44339109Sbostic 	case N_ECOMM:
44439109Sbostic 		return("ECOMM");
44539109Sbostic 	case N_ENTRY:
44639109Sbostic 		return("ENTRY");
44739109Sbostic 	case N_FNAME:
44839109Sbostic 		return("FNAME");
44939109Sbostic 	case N_FUN:
45039109Sbostic 		return("FUN");
45139109Sbostic 	case N_GSYM:
45239109Sbostic 		return("GSYM");
45339109Sbostic 	case N_LBRAC:
45439109Sbostic 		return("LBRAC");
45539109Sbostic 	case N_LCSYM:
45639109Sbostic 		return("LCSYM");
45739109Sbostic 	case N_LENG:
45839109Sbostic 		return("LENG");
45939109Sbostic 	case N_LSYM:
46039109Sbostic 		return("LSYM");
46139109Sbostic 	case N_PC:
46239109Sbostic 		return("PC");
46339109Sbostic 	case N_PSYM:
46439109Sbostic 		return("PSYM");
46539109Sbostic 	case N_RBRAC:
46639109Sbostic 		return("RBRAC");
46739109Sbostic 	case N_RSYM:
46839109Sbostic 		return("RSYM");
46939109Sbostic 	case N_SLINE:
47039109Sbostic 		return("SLINE");
47139109Sbostic 	case N_SO:
47239109Sbostic 		return("SO");
47339109Sbostic 	case N_SOL:
47439109Sbostic 		return("SOL");
47539109Sbostic 	case N_SSYM:
47639109Sbostic 		return("SSYM");
47739109Sbostic 	case N_STSYM:
47839109Sbostic 		return("STSYM");
479619Sbill 	}
48039109Sbostic 	return("???");
481619Sbill }
482619Sbill 
48339109Sbostic /*
48439109Sbostic  * typeletter()
48539109Sbostic  *	return a description letter for the given basic type code of an
48639109Sbostic  *	symbol table entry.  The return value will be upper case for
48739109Sbostic  *	external, lower case for internal symbols.
48839109Sbostic  */
48939109Sbostic char
49039109Sbostic typeletter(type)
49139109Sbostic 	u_char type;
492619Sbill {
49339109Sbostic 	switch(SYMBOL_TYPE(type)) {
49439109Sbostic 	case N_ABS:
49539109Sbostic 		return(IS_EXTERNAL(type) ? 'A' : 'a');
49639109Sbostic 	case N_BSS:
49739109Sbostic 		return(IS_EXTERNAL(type) ? 'B' : 'b');
49839109Sbostic 	case N_COMM:
49939109Sbostic 		return(IS_EXTERNAL(type) ? 'C' : 'c');
50039109Sbostic 	case N_DATA:
50139109Sbostic 		return(IS_EXTERNAL(type) ? 'D' : 'd');
50239109Sbostic 	case N_FN:
50339109Sbostic 		return(IS_EXTERNAL(type) ? 'F' : 'f');
50439109Sbostic 	case N_TEXT:
50539109Sbostic 		return(IS_EXTERNAL(type) ? 'T' : 't');
50639109Sbostic 	case N_UNDF:
50739109Sbostic 		return(IS_EXTERNAL(type) ? 'U' : 'u');
50839109Sbostic 	}
50939109Sbostic 	return('?');
51039109Sbostic }
511619Sbill 
51239109Sbostic /*
51339109Sbostic  * cmp_name()
51439109Sbostic  *	compare two symbols by their names
51539109Sbostic  */
51639109Sbostic cmp_name(a, b)
51739109Sbostic 	struct nlist *a, *b;
51839109Sbostic {
51939109Sbostic 	return(sort_direction == FORWARD ?
52039109Sbostic 	    strcmp(a->n_un.n_name, b->n_un.n_name) :
52139109Sbostic 	    strcmp(b->n_un.n_name, a->n_un.n_name));
522619Sbill }
523619Sbill 
52439109Sbostic /*
52539109Sbostic  * cmp_value()
52639109Sbostic  *	compare two symbols by their values
52739109Sbostic  */
52839109Sbostic cmp_value(a, b)
52939109Sbostic 	struct nlist *a, *b;
53039109Sbostic {
53139109Sbostic 	if (SYMBOL_TYPE(a->n_type) == N_UNDF)
53239109Sbostic 		if (SYMBOL_TYPE(b->n_type) == N_UNDF)
53339109Sbostic 			return(0);
53439109Sbostic 		else
53539109Sbostic 			return(-1);
53639109Sbostic 	else if (SYMBOL_TYPE(b->n_type) == N_UNDF)
53739109Sbostic 		return(1);
53839109Sbostic 	if (a->n_value == b->n_value)
53939109Sbostic 		return(cmp_name(a, b));
54039109Sbostic 	return(sort_direction == FORWARD ? a->n_value > b->n_value :
54139109Sbostic 	    a->n_value < b->n_value);
54239109Sbostic }
543619Sbill 
544619Sbill char *
54539109Sbostic emalloc(size)
54639109Sbostic 	u_int size;
547619Sbill {
54839109Sbostic 	char *p, *malloc();
549619Sbill 
55039109Sbostic 	/* NOSTRICT */
55139109Sbostic 	if (!(p = malloc(size))) {
55239109Sbostic 		(void)fprintf(stderr, "nm: no more memory.\n");
55339109Sbostic 		exit(1);
55439109Sbostic 	}
55539109Sbostic 	return(p);
556619Sbill }
55730855Sbostic 
55839109Sbostic usage()
55930855Sbostic {
56039109Sbostic 	(void)fprintf(stderr, "usage: nm [-agnopruw] [file ...]");
56139109Sbostic 	exit(1);
56230855Sbostic }
563