xref: /csrg-svn/usr.bin/nm/nm.c (revision 39109)
130855Sbostic /*
2*39109Sbostic  * Copyright (c) 1989 The Regents of the University of California.
3*39109Sbostic  * All rights reserved.
4*39109Sbostic  *
5*39109Sbostic  * This code is derived from software contributed to Berkeley by
6*39109Sbostic  * Hans Huebner.
7*39109Sbostic  *
8*39109Sbostic  * Redistribution and use in source and binary forms are permitted
9*39109Sbostic  * provided that the above copyright notice and this paragraph are
10*39109Sbostic  * duplicated in all such forms and that any documentation,
11*39109Sbostic  * advertising materials, and other materials related to such
12*39109Sbostic  * distribution and use acknowledge that the software was developed
13*39109Sbostic  * by the University of California, Berkeley.  The name of the
14*39109Sbostic  * University may not be used to endorse or promote products derived
15*39109Sbostic  * from this software without specific prior written permission.
16*39109Sbostic  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
17*39109Sbostic  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
18*39109Sbostic  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1930855Sbostic  */
2030855Sbostic 
2112672Ssam #ifndef lint
22*39109Sbostic char copyright[] =
23*39109Sbostic "@(#) Copyright (c) 1989 The Regents of the University of California.\n\
24*39109Sbostic  All rights reserved.\n";
25*39109Sbostic #endif /* not lint */
2630855Sbostic 
27*39109Sbostic #ifndef lint
28*39109Sbostic static char sccsid[] = "@(#)nm.c	5.1 (Berkeley) 09/10/89";
29*39109Sbostic #endif /* not lint */
3030855Sbostic 
31619Sbill #include <sys/types.h>
32653Sbill #include <a.out.h>
33619Sbill #include <stab.h>
34*39109Sbostic #include <ar.h>
3530855Sbostic #include <ranlib.h>
36*39109Sbostic #include <unistd.h>
37*39109Sbostic #include <errno.h>
38*39109Sbostic #include <ctype.h>
39*39109Sbostic #include <stdio.h>
40*39109Sbostic #include <strings.h>
41619Sbill 
42*39109Sbostic int	ignore_bad_archive_entries = 1;
43*39109Sbostic int	print_only_external_symbols;
44*39109Sbostic int	print_only_undefined_symbols;
45*39109Sbostic int	print_all_symbols;
46*39109Sbostic int	print_file_each_line;
47*39109Sbostic int	cmp_value(), cmp_name();
48*39109Sbostic int	(*sort_func)() = cmp_name;
49619Sbill 
50*39109Sbostic enum { FORWARD, BACKWARD } sort_direction = FORWARD;
51*39109Sbostic int fcount;
5230855Sbostic 
53*39109Sbostic /* some macros for symbol type (nlist.n_type) handling */
54*39109Sbostic #define	IS_DEBUGGER_SYMBOL(x)	((x) & N_STAB)
55*39109Sbostic #define	IS_EXTERNAL(x)		((x) & N_EXT)
56*39109Sbostic #define	SYMBOL_TYPE(x)		((x) & (N_TYPE | N_STAB))
5730855Sbostic 
58*39109Sbostic /*
59*39109Sbostic  * main()
60*39109Sbostic  *	parse command line, execute process_file() for each file
61*39109Sbostic  *	specified on the command line.
62*39109Sbostic  */
63619Sbill main(argc, argv)
64*39109Sbostic 	int argc;
65*39109Sbostic 	char **argv;
66619Sbill {
67*39109Sbostic 	extern int optind;
68*39109Sbostic 	int ch, errors;
69619Sbill 
70*39109Sbostic 	while ((ch = getopt(argc, argv, "agnopruw")) != EOF) {
71*39109Sbostic 		switch (ch) {
7230855Sbostic 		case 'a':
73*39109Sbostic 			print_all_symbols = 1;
7430855Sbostic 			break;
7530855Sbostic 		case 'g':
76*39109Sbostic 			print_only_external_symbols = 1;
7730855Sbostic 			break;
78619Sbill 		case 'n':
79*39109Sbostic 			sort_func = cmp_value;
8030855Sbostic 			break;
8130855Sbostic 		case 'o':
82*39109Sbostic 			print_file_each_line = 1;
8330855Sbostic 			break;
8430855Sbostic 		case 'p':
85*39109Sbostic 			sort_func = NULL;
8630855Sbostic 			break;
87619Sbill 		case 'r':
88*39109Sbostic 			sort_direction = BACKWARD;
8930855Sbostic 			break;
9030855Sbostic 		case 'u':
91*39109Sbostic 			print_only_undefined_symbols = 1;
9230855Sbostic 			break;
93*39109Sbostic 		case 'w':
94*39109Sbostic 			ignore_bad_archive_entries = 0;
95*39109Sbostic 			break;
9630855Sbostic 		case '?':
97619Sbill 		default:
98*39109Sbostic 			usage();
99619Sbill 		}
100*39109Sbostic 	}
101*39109Sbostic 	fcount = argc - optind;
10230855Sbostic 	argv += optind;
103*39109Sbostic 
104*39109Sbostic 	if (!fcount)
105*39109Sbostic 		errors = process_file("a.out");
106*39109Sbostic 	else {
107*39109Sbostic 		errors = 0;
108*39109Sbostic 		do {
109*39109Sbostic 			errors |= process_file(*argv);
110*39109Sbostic 		} while (*++argv);
111619Sbill 	}
112*39109Sbostic 	exit(errors);
113619Sbill }
114619Sbill 
115*39109Sbostic /*
116*39109Sbostic  * process_file()
117*39109Sbostic  *	show symbols in the file given as an argument.  Accepts archive and
118*39109Sbostic  *	object files as input.
119*39109Sbostic  */
120*39109Sbostic process_file(fname)
121*39109Sbostic 	char *fname;
122619Sbill {
123*39109Sbostic 	struct exec exec_head;
124*39109Sbostic 	FILE *fp;
125*39109Sbostic 	int retval;
126*39109Sbostic 	char magic[SARMAG];
127*39109Sbostic 
128*39109Sbostic 	if (!(fp = fopen(fname, "r"))) {
129*39109Sbostic 		(void)fprintf(stderr, "nm: cannot read %s.\n", fname);
130*39109Sbostic 		return(1);
131*39109Sbostic 	}
132619Sbill 
133*39109Sbostic 	if (fcount > 1)
134*39109Sbostic 		(void)printf("\n%s:\n", fname);
135*39109Sbostic 
13630855Sbostic 	/*
137*39109Sbostic 	 * first check whether this is an object file - read a object
138*39109Sbostic 	 * header, and skip back to the beginning
13930855Sbostic 	 */
140*39109Sbostic 	if (fread((char *)&exec_head, 1, sizeof(exec_head), fp) !=
141*39109Sbostic 	    sizeof(exec_head)) {
142*39109Sbostic 		(void)fprintf(stderr, "nm: %s: bad format.\n", fname);
143*39109Sbostic 		(void)fclose(fp);
144*39109Sbostic 		return(1);
145619Sbill 	}
146*39109Sbostic 	rewind(fp);
147*39109Sbostic 
148*39109Sbostic 	/* this could be an archive */
149*39109Sbostic 	if (N_BADMAG(exec_head)) {
150*39109Sbostic 		if (fread(magic, 1, sizeof(magic), fp) != sizeof(magic) ||
151*39109Sbostic 		    strncmp(magic, ARMAG, SARMAG)) {
152*39109Sbostic 			(void)fprintf(stderr,
153*39109Sbostic 			    "nm: %s: not object file or archive.\n", fname);
154*39109Sbostic 			(void)fclose(fp);
155*39109Sbostic 			return(1);
15630855Sbostic 		}
157*39109Sbostic 		retval = show_archive(fname, fp);
158*39109Sbostic 	} else
159*39109Sbostic 		retval = show_objfile(fname, fp);
160*39109Sbostic 	(void)fclose(fp);
161*39109Sbostic 	return(retval);
162*39109Sbostic }
163*39109Sbostic 
164*39109Sbostic /*
165*39109Sbostic  * show_archive()
166*39109Sbostic  *	show symbols in the given archive file
167*39109Sbostic  */
168*39109Sbostic show_archive(fname, fp)
169*39109Sbostic 	char *fname;
170*39109Sbostic 	FILE *fp;
171*39109Sbostic {
172*39109Sbostic 	extern int errno;
173*39109Sbostic 	struct ar_hdr ar_head;
174*39109Sbostic 	struct exec exec_head;
175*39109Sbostic 	off_t esize;
176*39109Sbostic 	int i, last_ar_off, rval;
177*39109Sbostic 	char *p, *name, *emalloc();
178*39109Sbostic 	long atol();
179*39109Sbostic 
180*39109Sbostic 	name = emalloc((u_int)(sizeof(ar_head.ar_name) + strlen(fname) + 3));
181*39109Sbostic 
182*39109Sbostic 	rval = 0;
183*39109Sbostic 
184*39109Sbostic 	/* while there are more entries in the archive */
185*39109Sbostic 	while (fread((char *)&ar_head, 1, sizeof(ar_head), fp) ==
186*39109Sbostic 	    sizeof(ar_head)) {
187*39109Sbostic 		/* bad archive entry - stop processing this archive */
188*39109Sbostic 		if (strncmp(ar_head.ar_fmag, ARFMAG, sizeof(ar_head.ar_fmag))) {
189*39109Sbostic 			(void)fprintf(stderr,
190*39109Sbostic 			    "nm: %s: bad format archive header", fname);
191*39109Sbostic 			(void)free(name);
192*39109Sbostic 			return(1);
193*39109Sbostic 		}
194*39109Sbostic 
19530855Sbostic 		/*
196*39109Sbostic 		 * construct a name of the form "archive.a(obj.o)" for the
197*39109Sbostic 		 * current archive entry if the object name is to be printed
198*39109Sbostic 		 * on each output line
19930855Sbostic 		 */
200*39109Sbostic 		if (print_file_each_line) {
201*39109Sbostic 			(void)sprintf(name, "%s(", fname);
202*39109Sbostic 			p = name + strlen(name);
203*39109Sbostic 		} else
204*39109Sbostic 			p = name;
205*39109Sbostic 		for (i = 0; i < sizeof(ar_head.ar_name); ++i)
206*39109Sbostic 			if (ar_head.ar_name[i] && ar_head.ar_name[i] != ' ')
207*39109Sbostic 				*p++ = ar_head.ar_name[i];
208*39109Sbostic 		if (print_file_each_line)
209*39109Sbostic 			*p++ = ')';
210*39109Sbostic 		*p++ = '\0';
21130855Sbostic 
212*39109Sbostic 		/* remember start position of current archive object */
213*39109Sbostic 		last_ar_off = ftell(fp);
21430855Sbostic 
215*39109Sbostic 		/* get and check current object's header */
216*39109Sbostic 		if (fread((char *)&exec_head, 1, sizeof(exec_head), fp) !=
217*39109Sbostic 		    sizeof(exec_head)) {
218*39109Sbostic 			(void)fprintf(stderr, "nm: %s: premature EOF.\n", name);
219*39109Sbostic 			(void)free(name);
220*39109Sbostic 			return(1);
221619Sbill 		}
222*39109Sbostic 		if (strcmp(name, RANLIBMAG))
223*39109Sbostic 			if (N_BADMAG(exec_head)) {
224*39109Sbostic 				if (!ignore_bad_archive_entries) {
225*39109Sbostic 					(void)fprintf(stderr,
226*39109Sbostic 					    "nm: %s: bad format.\n", name);
227*39109Sbostic 					rval = 1;
228*39109Sbostic 				}
229*39109Sbostic 			} else {
230*39109Sbostic 				(void)fseek(fp, (long)-sizeof(exec_head),
231*39109Sbostic 				    SEEK_CUR);
232*39109Sbostic 				if (!print_file_each_line)
233*39109Sbostic 					(void)printf("\n%s:\n", name);
234*39109Sbostic 				rval |= show_objfile(name, fp);
235*39109Sbostic 			}
236*39109Sbostic 		esize = atol(ar_head.ar_size);
23730855Sbostic 
238*39109Sbostic 		/*
239*39109Sbostic 		 * skip to next archive object - esize&1 is added to stay
240*39109Sbostic 	 	 * on even starting points relative to the start of the
241*39109Sbostic 		 * archive file
242*39109Sbostic 		 */
243*39109Sbostic 		if (fseek(fp, (long)(last_ar_off + esize + (esize&1)),
244*39109Sbostic 		    SEEK_SET)) {
245*39109Sbostic 			(void)fprintf(stderr,
246*39109Sbostic 			    "nm: %s: %s\n", fname, strerror(errno));
247*39109Sbostic 			(void)free(name);
248*39109Sbostic 			return(1);
24930855Sbostic 		}
250*39109Sbostic 	}
251*39109Sbostic 	(void)free(name);
252*39109Sbostic 	return(rval);
253*39109Sbostic }
25430855Sbostic 
255*39109Sbostic /*
256*39109Sbostic  * show_objfile()
257*39109Sbostic  *	show symbols from the object file pointed to by fp.  The current
258*39109Sbostic  *	file pointer for fp is expected to be at the beginning of an a.out
259*39109Sbostic  *	header.
260*39109Sbostic  */
261*39109Sbostic show_objfile(objname, fp)
262*39109Sbostic 	char *objname;
263*39109Sbostic 	FILE *fp;
264*39109Sbostic {
265*39109Sbostic 	register struct nlist *names;
266*39109Sbostic 	register int i, nnames, nrawnames;
267*39109Sbostic 	struct exec head;
268*39109Sbostic 	long stabsize;
269*39109Sbostic 	char *stab, *emalloc();
270*39109Sbostic 
271*39109Sbostic 	/* read a.out header */
272*39109Sbostic 	if (fread((char *)&head, sizeof(head), 1, fp) != 1) {
273*39109Sbostic 		(void)fprintf(stderr,
274*39109Sbostic 		    "nm: %s: cannot read header.\n", objname);
275*39109Sbostic 		return(1);
276*39109Sbostic 	}
277*39109Sbostic 
278*39109Sbostic 	/*
279*39109Sbostic 	 * skip back to the header - the N_-macros return values relative
280*39109Sbostic 	 * to the beginning of the a.out header
281*39109Sbostic 	 */
282*39109Sbostic 	if (fseek(fp, (long)-sizeof(head), SEEK_CUR)) {
283*39109Sbostic 		(void)fprintf(stderr,
284*39109Sbostic 		    "nm: %s: %s\n", objname, strerror(errno));
285*39109Sbostic 		return(1);
286*39109Sbostic 	}
287*39109Sbostic 
288*39109Sbostic 	/* stop if this is no valid object file */
289*39109Sbostic 	if (N_BADMAG(head)) {
290*39109Sbostic 		(void)fprintf(stderr,
291*39109Sbostic 		    "nm: %s: bad format.\n", objname);
292*39109Sbostic 		return(1);
293*39109Sbostic 	}
294*39109Sbostic 
295*39109Sbostic 	/* stop if the object file contains no symbol table */
296*39109Sbostic 	if (!head.a_syms) {
297*39109Sbostic 		(void)fprintf(stderr,
298*39109Sbostic 		    "nm: %s: no name list.\n", objname);
299*39109Sbostic 		return(1);
300*39109Sbostic 	}
301*39109Sbostic 
302*39109Sbostic 	if (fseek(fp, (long)N_SYMOFF(head), SEEK_CUR)) {
303*39109Sbostic 		(void)fprintf(stderr,
304*39109Sbostic 		    "nm: %s: %s\n", objname, strerror(errno));
305*39109Sbostic 		return(1);
306*39109Sbostic 	}
307*39109Sbostic 
308*39109Sbostic 	/* get memory for the symbol table */
309*39109Sbostic 	names = (struct nlist *)emalloc((u_int)head.a_syms);
310*39109Sbostic 	nrawnames = head.a_syms / sizeof(*names);
311*39109Sbostic 	if (fread((char *)names, 1, (int)head.a_syms, fp) != head.a_syms) {
312*39109Sbostic 		(void)fprintf(stderr,
313*39109Sbostic 		    "nm: %s: cannot read symbol table.\n", objname);
314*39109Sbostic 		(void)free((char *)names);
315*39109Sbostic 		return(1);
316*39109Sbostic 	}
317*39109Sbostic 
318*39109Sbostic 	/*
319*39109Sbostic 	 * Following the symbol table comes the string table.  The first
320*39109Sbostic 	 * 4-byte-integer gives the total size of the string table
321*39109Sbostic 	 * _including_ the size specification itself.
322*39109Sbostic 	 */
323*39109Sbostic 	if (fread((char *)&stabsize, sizeof(stabsize), 1, fp) != 1) {
324*39109Sbostic 		(void)fprintf(stderr,
325*39109Sbostic 		    "nm: %s: cannot read stab size.\n", objname);
326*39109Sbostic 		(void)free((char *)names);
327*39109Sbostic 		return(1);
328*39109Sbostic 	}
329*39109Sbostic 	stab = emalloc((u_int)stabsize);
330*39109Sbostic 
331*39109Sbostic 	/*
332*39109Sbostic 	 * read the string table offset by 4 - all indices into the string
333*39109Sbostic 	 * table include the size specification.
334*39109Sbostic 	 */
335*39109Sbostic 	stabsize -=4;		/* we already have the size */
336*39109Sbostic 	if (fread(stab + 4, 1, (int)stabsize, fp) != stabsize) {
337*39109Sbostic 		(void)fprintf(stderr,
338*39109Sbostic 		    "nm: %s: stab truncated..\n", objname);
339*39109Sbostic 		(void)free((char *)names);
340*39109Sbostic 		(void)free(stab);
341*39109Sbostic 		return(1);
342*39109Sbostic 	}
343*39109Sbostic 
344*39109Sbostic 	/*
345*39109Sbostic 	 * fix up the symbol table and filter out unwanted entries
346*39109Sbostic 	 *
347*39109Sbostic 	 * common symbols are characterized by a n_type of N_UNDF and a
348*39109Sbostic 	 * non-zero n_value -- change n_type to N_COMM for all such
349*39109Sbostic 	 * symbols to make life easier later.
350*39109Sbostic 	 *
351*39109Sbostic 	 * filter out all entries which we don't want to print anyway
352*39109Sbostic 	 */
353*39109Sbostic 	for (i = nnames = 0; i < nrawnames; ++i) {
354*39109Sbostic 		if (SYMBOL_TYPE(names[i].n_type) == N_UNDF && names[i].n_value)
355*39109Sbostic 			names[i].n_type = N_COMM | (names[i].n_type & N_EXT);
356*39109Sbostic 		if (!print_all_symbols && IS_DEBUGGER_SYMBOL(names[i].n_type))
35730855Sbostic 			continue;
358*39109Sbostic 		if (print_only_external_symbols &&
359*39109Sbostic 		    !IS_EXTERNAL(names[i].n_type))
360619Sbill 			continue;
361*39109Sbostic 		if (print_only_undefined_symbols &&
362*39109Sbostic 		    (SYMBOL_TYPE(names[i].n_type) != N_UNDF))
363*39109Sbostic 			continue;
36430855Sbostic 
365*39109Sbostic 		/*
366*39109Sbostic 		 * make n_un.n_name a character pointer by adding the string
367*39109Sbostic 		 * table's base to n_un.n_strx
368*39109Sbostic 		 *
369*39109Sbostic 		 * don't mess with null offsets
370*39109Sbostic 		 */
371*39109Sbostic 		if (names[i].n_un.n_name)
372*39109Sbostic 			names[i].n_un.n_name = stab + names[i].n_un.n_strx;
373*39109Sbostic 		else
374*39109Sbostic 			names[i].n_un.n_name = "";
375*39109Sbostic 		if (nnames != i)
376*39109Sbostic 			names[nnames] = names[i];
377*39109Sbostic 		++nnames;
378*39109Sbostic 	}
37930855Sbostic 
380*39109Sbostic 	/* sort the symbol table if applicable */
381*39109Sbostic 	if (sort_func)
382*39109Sbostic 		qsort((char *)names, (int)nnames, sizeof(*names), sort_func);
38330855Sbostic 
384*39109Sbostic 	/* print out symbols */
385*39109Sbostic 	for (i = 0; i < nnames; ++i)
386*39109Sbostic 		print_symbol(objname, &names[i]);
38730855Sbostic 
388*39109Sbostic 	(void)free((char *)names);
389*39109Sbostic 	(void)free(stab);
390*39109Sbostic 	return(0);
391619Sbill }
392619Sbill 
393*39109Sbostic /*
394*39109Sbostic  * print_symbol()
395*39109Sbostic  *	show one symbol
396*39109Sbostic  */
397*39109Sbostic print_symbol(objname, sym)
398*39109Sbostic 	char *objname;
399*39109Sbostic 	struct nlist *sym;
400619Sbill {
401*39109Sbostic 	char *typestring(), typeletter();
402619Sbill 
403*39109Sbostic 	if (print_file_each_line)
404*39109Sbostic 		printf("%s: ", objname);
405*39109Sbostic 
406*39109Sbostic 	/*
407*39109Sbostic 	 * handle undefined-only format seperately (no space is
408*39109Sbostic 	 * left for symbol values, no type field is printed)
409*39109Sbostic 	 */
410*39109Sbostic 	if (print_only_undefined_symbols) {
411*39109Sbostic 		printf("%s\n", sym->n_un.n_name);
412*39109Sbostic 		return;
413619Sbill 	}
414*39109Sbostic 
415*39109Sbostic 	/* print symbol's value */
416*39109Sbostic 	if (SYMBOL_TYPE(sym->n_type) == N_UNDF)
417*39109Sbostic 		(void)printf("        ");
418*39109Sbostic 	else
419*39109Sbostic 		(void)printf("%08lx", sym->n_value);
420*39109Sbostic 
421*39109Sbostic 	/* print type information */
422*39109Sbostic 	if (IS_DEBUGGER_SYMBOL(sym->n_type))
423*39109Sbostic 		(void)printf(" - %02x %04x %5s ", sym->n_other,
424*39109Sbostic 		    sym->n_desc&0xffff, typestring(sym->n_type));
425*39109Sbostic 	else
426*39109Sbostic 		(void)printf(" %c ", typeletter(sym->n_type));
427*39109Sbostic 
428*39109Sbostic 	/* print the symbol's name */
429*39109Sbostic 	(void)printf("%s\n", sym->n_un.n_name ? sym->n_un.n_name : "");
430619Sbill }
431619Sbill 
432*39109Sbostic /*
433*39109Sbostic  * typestring()
434*39109Sbostic  *	return the a description string for an STAB entry
435*39109Sbostic  */
436*39109Sbostic char *
437*39109Sbostic typestring(type)
438*39109Sbostic 	register u_char type;
439619Sbill {
440*39109Sbostic 	switch(type) {
441*39109Sbostic 	case N_BCOMM:
442*39109Sbostic 		return("BCOMM");
443*39109Sbostic 	case N_ECOML:
444*39109Sbostic 		return("ECOML");
445*39109Sbostic 	case N_ECOMM:
446*39109Sbostic 		return("ECOMM");
447*39109Sbostic 	case N_ENTRY:
448*39109Sbostic 		return("ENTRY");
449*39109Sbostic 	case N_FNAME:
450*39109Sbostic 		return("FNAME");
451*39109Sbostic 	case N_FUN:
452*39109Sbostic 		return("FUN");
453*39109Sbostic 	case N_GSYM:
454*39109Sbostic 		return("GSYM");
455*39109Sbostic 	case N_LBRAC:
456*39109Sbostic 		return("LBRAC");
457*39109Sbostic 	case N_LCSYM:
458*39109Sbostic 		return("LCSYM");
459*39109Sbostic 	case N_LENG:
460*39109Sbostic 		return("LENG");
461*39109Sbostic 	case N_LSYM:
462*39109Sbostic 		return("LSYM");
463*39109Sbostic 	case N_PC:
464*39109Sbostic 		return("PC");
465*39109Sbostic 	case N_PSYM:
466*39109Sbostic 		return("PSYM");
467*39109Sbostic 	case N_RBRAC:
468*39109Sbostic 		return("RBRAC");
469*39109Sbostic 	case N_RSYM:
470*39109Sbostic 		return("RSYM");
471*39109Sbostic 	case N_SLINE:
472*39109Sbostic 		return("SLINE");
473*39109Sbostic 	case N_SO:
474*39109Sbostic 		return("SO");
475*39109Sbostic 	case N_SOL:
476*39109Sbostic 		return("SOL");
477*39109Sbostic 	case N_SSYM:
478*39109Sbostic 		return("SSYM");
479*39109Sbostic 	case N_STSYM:
480*39109Sbostic 		return("STSYM");
481619Sbill 	}
482*39109Sbostic 	return("???");
483619Sbill }
484619Sbill 
485*39109Sbostic /*
486*39109Sbostic  * typeletter()
487*39109Sbostic  *	return a description letter for the given basic type code of an
488*39109Sbostic  *	symbol table entry.  The return value will be upper case for
489*39109Sbostic  *	external, lower case for internal symbols.
490*39109Sbostic  */
491*39109Sbostic char
492*39109Sbostic typeletter(type)
493*39109Sbostic 	u_char type;
494619Sbill {
495*39109Sbostic 	switch(SYMBOL_TYPE(type)) {
496*39109Sbostic 	case N_ABS:
497*39109Sbostic 		return(IS_EXTERNAL(type) ? 'A' : 'a');
498*39109Sbostic 	case N_BSS:
499*39109Sbostic 		return(IS_EXTERNAL(type) ? 'B' : 'b');
500*39109Sbostic 	case N_COMM:
501*39109Sbostic 		return(IS_EXTERNAL(type) ? 'C' : 'c');
502*39109Sbostic 	case N_DATA:
503*39109Sbostic 		return(IS_EXTERNAL(type) ? 'D' : 'd');
504*39109Sbostic 	case N_FN:
505*39109Sbostic 		return(IS_EXTERNAL(type) ? 'F' : 'f');
506*39109Sbostic 	case N_TEXT:
507*39109Sbostic 		return(IS_EXTERNAL(type) ? 'T' : 't');
508*39109Sbostic 	case N_UNDF:
509*39109Sbostic 		return(IS_EXTERNAL(type) ? 'U' : 'u');
510*39109Sbostic 	}
511*39109Sbostic 	return('?');
512*39109Sbostic }
513619Sbill 
514*39109Sbostic /*
515*39109Sbostic  * cmp_name()
516*39109Sbostic  *	compare two symbols by their names
517*39109Sbostic  */
518*39109Sbostic cmp_name(a, b)
519*39109Sbostic 	struct nlist *a, *b;
520*39109Sbostic {
521*39109Sbostic 	return(sort_direction == FORWARD ?
522*39109Sbostic 	    strcmp(a->n_un.n_name, b->n_un.n_name) :
523*39109Sbostic 	    strcmp(b->n_un.n_name, a->n_un.n_name));
524619Sbill }
525619Sbill 
526*39109Sbostic /*
527*39109Sbostic  * cmp_value()
528*39109Sbostic  *	compare two symbols by their values
529*39109Sbostic  */
530*39109Sbostic cmp_value(a, b)
531*39109Sbostic 	struct nlist *a, *b;
532*39109Sbostic {
533*39109Sbostic 	if (SYMBOL_TYPE(a->n_type) == N_UNDF)
534*39109Sbostic 		if (SYMBOL_TYPE(b->n_type) == N_UNDF)
535*39109Sbostic 			return(0);
536*39109Sbostic 		else
537*39109Sbostic 			return(-1);
538*39109Sbostic 	else if (SYMBOL_TYPE(b->n_type) == N_UNDF)
539*39109Sbostic 		return(1);
540*39109Sbostic 	if (a->n_value == b->n_value)
541*39109Sbostic 		return(cmp_name(a, b));
542*39109Sbostic 	return(sort_direction == FORWARD ? a->n_value > b->n_value :
543*39109Sbostic 	    a->n_value < b->n_value);
544*39109Sbostic }
545619Sbill 
546619Sbill char *
547*39109Sbostic emalloc(size)
548*39109Sbostic 	u_int size;
549619Sbill {
550*39109Sbostic 	char *p, *malloc();
551619Sbill 
552*39109Sbostic 	/* NOSTRICT */
553*39109Sbostic 	if (!(p = malloc(size))) {
554*39109Sbostic 		(void)fprintf(stderr, "nm: no more memory.\n");
555*39109Sbostic 		exit(1);
556*39109Sbostic 	}
557*39109Sbostic 	return(p);
558619Sbill }
55930855Sbostic 
560*39109Sbostic usage()
56130855Sbostic {
562*39109Sbostic 	(void)fprintf(stderr, "usage: nm [-agnopruw] [file ...]");
563*39109Sbostic 	exit(1);
56430855Sbostic }
565