xref: /csrg-svn/usr.bin/nm/nm.c (revision 30855)
1*30855Sbostic /*
2*30855Sbostic  * Copyright (c) 1987 Regents of the University of California.
3*30855Sbostic  * All rights reserved.  The Berkeley software License Agreement
4*30855Sbostic  * specifies the terms and conditions for redistribution.
5*30855Sbostic  */
6*30855Sbostic 
712672Ssam #ifndef lint
8*30855Sbostic static	char sccsid[] = "@(#)nm.c 4.8 04/07/87";
912672Ssam #endif
10*30855Sbostic 
11619Sbill /*
12619Sbill  * nm - print name list; VAX string table version
13619Sbill  */
14*30855Sbostic 
15619Sbill #include <sys/types.h>
16*30855Sbostic #include <sys/file.h>
17653Sbill #include <ar.h>
18619Sbill #include <stdio.h>
19619Sbill #include <ctype.h>
20653Sbill #include <a.out.h>
21619Sbill #include <stab.h>
22*30855Sbostic #include <ranlib.h>
23619Sbill 
24*30855Sbostic #define	OARMAG		0177545		/* OLD archive magic number */
25*30855Sbostic #define	SELECT		(archive ? archdr.ar_name : *xargv)
26619Sbill 
27*30855Sbostic #define	YES		1
28*30855Sbostic #define	NO		0
29*30855Sbostic 
30*30855Sbostic #define	u_strx		n_un.n_strx
31*30855Sbostic #define	u_name		n_un.n_name
32*30855Sbostic 
33*30855Sbostic typedef struct nlist	NLIST;
34*30855Sbostic 
35*30855Sbostic union {				/* exec header, or magic string from library */
36*30855Sbostic 	char	mag_armag[SARMAG + 1];
37619Sbill 	struct	exec mag_exp;
38619Sbill } mag_un;
39619Sbill 
40*30855Sbostic struct	ar_hdr	archdr;		/* archive file header structure */
41*30855Sbostic FILE	*fi;			/* input file stream */
42*30855Sbostic off_t	off;			/* offset into file */
43*30855Sbostic int	aflg,			/* print debugger symbols */
44*30855Sbostic 	gflg,			/* print only global (external symbols */
45*30855Sbostic 	nflg,			/* sort numerically, not alphabetically */
46*30855Sbostic 	oflg,			/* prepend element name to each output line */
47*30855Sbostic 	pflg,			/* don't sort */
48*30855Sbostic 	rflg = 1,		/* how to sort */
49*30855Sbostic 	uflg,			/* print only undefined symbols */
50*30855Sbostic 	narg,			/* global number of arguments */
51*30855Sbostic 	errs,			/* global error flag */
52*30855Sbostic 	archive;		/* if file is an archive */
53*30855Sbostic char	**xargv;		/* global pointer to file name */
54*30855Sbostic 
55619Sbill main(argc, argv)
56*30855Sbostic 	int	argc;
57*30855Sbostic 	char	**argv;
58619Sbill {
59*30855Sbostic 	extern int	optind;
60*30855Sbostic 	int	ch;			/* getopts char */
61619Sbill 
62*30855Sbostic 	while ((ch = getopt(argc, argv, "agnopru")) != EOF)
63*30855Sbostic 		switch((char)ch) {
64*30855Sbostic 		case 'a':
65*30855Sbostic 			aflg = YES;
66*30855Sbostic 			break;
67*30855Sbostic 		case 'g':
68*30855Sbostic 			gflg = YES;
69*30855Sbostic 			break;
70619Sbill 		case 'n':
71*30855Sbostic 			nflg = YES;
72*30855Sbostic 			break;
73*30855Sbostic 		case 'o':
74*30855Sbostic 			oflg = YES;
75*30855Sbostic 			break;
76*30855Sbostic 		case 'p':
77*30855Sbostic 			pflg = YES;
78*30855Sbostic 			break;
79619Sbill 		case 'r':
80619Sbill 			rflg = -1;
81*30855Sbostic 			break;
82*30855Sbostic 		case 'u':
83*30855Sbostic 			uflg = YES;
84*30855Sbostic 			break;
85*30855Sbostic 		case '?':
86619Sbill 		default:
87*30855Sbostic 			fputs("usage: nm [-agnopru] [file ...]\n", stderr);
88619Sbill 			exit(2);
89619Sbill 		}
90*30855Sbostic 	argc -= optind;
91*30855Sbostic 	argv += optind;
92*30855Sbostic 	if (!argc) {
93619Sbill 		argc = 1;
94*30855Sbostic 		argv[0] = "a.out";
95619Sbill 	}
96619Sbill 	narg = argc;
97*30855Sbostic 	for (xargv = argv; argc--; ++xargv)
98*30855Sbostic 		if (fi = fopen(*xargv, "r")) {
99*30855Sbostic 			namelist();
100*30855Sbostic 			(void)fclose(fi);
101*30855Sbostic 		}
102*30855Sbostic 		else
103*30855Sbostic 			error(NO, "cannot open");
104619Sbill 	exit(errs);
105619Sbill }
106619Sbill 
107619Sbill namelist()
108619Sbill {
109*30855Sbostic 	register NLIST	*N, **L;
110*30855Sbostic 	register int	symcount, nsyms;
111*30855Sbostic 	static	NLIST	*symp, **list;
112*30855Sbostic 	static int	lastnsyms = -1,
113*30855Sbostic 			laststrsiz = -1;
114*30855Sbostic 	static char	*strp;
115*30855Sbostic 	off_t	strsiz;
116*30855Sbostic 	long	lseek();
117*30855Sbostic 	int	compare();
118*30855Sbostic 	char	*malloc(), *realloc();
119619Sbill 
120*30855Sbostic 	/*
121*30855Sbostic 	 * read first few bytes, determine if an archive,
122*30855Sbostic 	 * or executable; if executable, check magic number
123*30855Sbostic 	 */
124*30855Sbostic 	/*NOSTRICT*/
125*30855Sbostic 	if (!fread((char *)&mag_un, sizeof(mag_un), 1, fi)) {
126*30855Sbostic 		error(NO, "unable to read file");
127619Sbill 		return;
128619Sbill 	}
129619Sbill 	if (mag_un.mag_exp.a_magic == OARMAG) {
130*30855Sbostic 		error(NO, "old archive");
131*30855Sbostic 		return;
132619Sbill 	}
133*30855Sbostic 	if (bcmp(mag_un.mag_armag, ARMAG, SARMAG)) {
134*30855Sbostic 		if (N_BADMAG(mag_un.mag_exp)) {
135*30855Sbostic 			error(NO, "bad format");
136*30855Sbostic 			return;
137*30855Sbostic 		}
138*30855Sbostic 		archive = NO;
139*30855Sbostic 		rewind(fi);
140619Sbill 	}
141*30855Sbostic 	else {
142*30855Sbostic 		/*
143*30855Sbostic 		 * if archive, skip first entry
144*30855Sbostic 		 * if ranlib'd, skip second entry
145*30855Sbostic 		 */
146*30855Sbostic 		off = SARMAG;		/* see nextel() */
147*30855Sbostic 		(void)nextel();
148*30855Sbostic 		if (!strcmp(RANLIBMAG, archdr.ar_name))
149*30855Sbostic 			(void)nextel();
150619Sbill 		if (narg > 1)
151619Sbill 			printf("\n%s:\n", *xargv);
152*30855Sbostic 		archive = YES;
153619Sbill 	}
154*30855Sbostic 
155619Sbill 	do {
156*30855Sbostic 		/* check for bad magic number */
157*30855Sbostic 		/*NOSTRICT*/
158*30855Sbostic 		if (!fread((char *)&mag_un.mag_exp, sizeof(struct exec), 1, fi)) {
159*30855Sbostic 			error(NO, "unable to read magic number");
160*30855Sbostic 			return;
161*30855Sbostic 		}
162619Sbill 		if (N_BADMAG(mag_un.mag_exp))
163619Sbill 			continue;
164*30855Sbostic 
165*30855Sbostic 		/* calculate number of symbols in object */
166*30855Sbostic 		if (!(nsyms = mag_un.mag_exp.a_syms / sizeof(NLIST))) {
167*30855Sbostic 			error(NO, "no name list");
168619Sbill 			continue;
169619Sbill 		}
170*30855Sbostic 
171*30855Sbostic 		/* seek to and read symbols */
172*30855Sbostic 		(void)fseek(fi, (long)(N_SYMOFF(mag_un.mag_exp) - sizeof(struct exec)), L_INCR);
173*30855Sbostic 		if (!symp || nsyms > lastnsyms) {
174*30855Sbostic 			if (!symp) {
175*30855Sbostic 				/*NOSTRICT*/
176*30855Sbostic 				symp = (NLIST *)malloc((u_int)(nsyms * sizeof(NLIST)));
177*30855Sbostic 				/*NOSTRICT*/
178*30855Sbostic 				list = (NLIST **)malloc((u_int)(nsyms * sizeof(NLIST *)));
179*30855Sbostic 			}
180*30855Sbostic 			else {
181*30855Sbostic 				/*NOSTRICT*/
182*30855Sbostic 				symp = (NLIST *)realloc((char *)symp, (u_int)(nsyms * sizeof(NLIST)));
183*30855Sbostic 				/*NOSTRICT*/
184*30855Sbostic 				list = (NLIST **)realloc((char *)list, (u_int)(nsyms * sizeof(NLIST *)));
185*30855Sbostic 			}
186*30855Sbostic 			if (!symp || !list)
187*30855Sbostic 				error(YES, "out of memory");
188*30855Sbostic 			lastnsyms = nsyms;
189*30855Sbostic 		}
190*30855Sbostic 		/*NOSTRICT*/
191*30855Sbostic 		if (fread((char *)symp, sizeof(NLIST), nsyms, fi) != nsyms) {
192*30855Sbostic 			error(NO, "bad symbol table");
19317424Sralph 			continue;
19417424Sralph 		}
195*30855Sbostic 
196*30855Sbostic 		/* read number of strings, string table */
197*30855Sbostic 		/*NOSTRICT*/
198*30855Sbostic 		if (!fread((char *)&strsiz, sizeof(strsiz), 1, fi)) {
199*30855Sbostic 			error(NO, "no string table (old format .o?)");
200*30855Sbostic 			continue;
201619Sbill 		}
202*30855Sbostic 		if (!strp || strsiz > laststrsiz) {
203*30855Sbostic 			strp = strp ? realloc(strp, (u_int)strsiz) : malloc((u_int)strsiz);
204*30855Sbostic 			if (!strp)
205*30855Sbostic 				error(YES, "out of memory");
206*30855Sbostic 			laststrsiz = strsiz;
207*30855Sbostic 		}
208*30855Sbostic 		if (!fread(strp + sizeof(strsiz), 1, (int)(strsiz - sizeof(strsiz)), fi)) {
209*30855Sbostic 			error(NO, "no string table (old format .o?)");
210619Sbill 			continue;
211619Sbill 		}
212*30855Sbostic 
213*30855Sbostic 		for (symcount = nsyms, L = list, N = symp;--nsyms >= 0;++N)
214*30855Sbostic 			if (!(N->n_type & N_EXT) && gflg || N->n_type & N_STAB && (!aflg || gflg || uflg))
215*30855Sbostic 				--symcount;
216*30855Sbostic 			else {
217*30855Sbostic 				N->u_name = N->u_strx ? strp + N->u_strx : "";
218*30855Sbostic 				*L++ = N;
219*30855Sbostic 			}
220*30855Sbostic 
221*30855Sbostic 		if (!pflg)
222*30855Sbostic 			qsort(list, symcount, sizeof(NLIST *), compare);
223*30855Sbostic 
224*30855Sbostic 		if ((archive || narg > 1) && !oflg)
225619Sbill 			printf("\n%s:\n", SELECT);
226*30855Sbostic 
227*30855Sbostic 		psyms(list, symcount);
228*30855Sbostic 	} while(archive && nextel());
229619Sbill }
230619Sbill 
231*30855Sbostic psyms(list, nsyms)
232*30855Sbostic 	NLIST	**list;
233*30855Sbostic 	register int	nsyms;
234619Sbill {
235*30855Sbostic 	register NLIST	*L;
236*30855Sbostic 	register u_char	type;
237*30855Sbostic 	char	*stab();
238619Sbill 
239*30855Sbostic 	while (nsyms--) {
240*30855Sbostic 		L = *list++;
241*30855Sbostic 		type = L->n_type;
242*30855Sbostic 		if (type & N_STAB) {
243619Sbill 			if (oflg) {
244619Sbill 				if (archive)
245619Sbill 					printf("%s:", *xargv);
246619Sbill 				printf("%s:", SELECT);
247619Sbill 			}
248*30855Sbostic 			printf("%08x - %02x %04x %5.5s %s\n", (int)L->n_value, L->n_other & 0xff, L->n_desc & 0xffff, stab(L->n_type), L->u_name);
249619Sbill 			continue;
250619Sbill 		}
251*30855Sbostic 		switch (type & N_TYPE) {
252619Sbill 		case N_UNDF:
253*30855Sbostic 			type = L->n_value ? 'c' : 'u';
254619Sbill 			break;
255619Sbill 		case N_ABS:
256*30855Sbostic 			type = 'a';
257619Sbill 			break;
258619Sbill 		case N_TEXT:
259*30855Sbostic 			type = 't';
260619Sbill 			break;
261619Sbill 		case N_DATA:
262*30855Sbostic 			type = 'd';
263619Sbill 			break;
264619Sbill 		case N_BSS:
265*30855Sbostic 			type = 'b';
266619Sbill 			break;
267*30855Sbostic 		case N_FN:
268*30855Sbostic 			type = 'f';
269*30855Sbostic 			break;
27028296Skarels 		default:
271*30855Sbostic 			type = '?';
272619Sbill 			break;
273619Sbill 		}
274*30855Sbostic 		if (uflg && type != 'u')
275619Sbill 			continue;
276619Sbill 		if (oflg) {
277619Sbill 			if (archive)
278619Sbill 				printf("%s:", *xargv);
279619Sbill 			printf("%s:", SELECT);
280619Sbill 		}
281*30855Sbostic 		if (L->n_type & N_EXT)
282*30855Sbostic 			type = toupper(type);
283619Sbill 		if (!uflg) {
284*30855Sbostic 			if (type == 'u' || type == 'U')
285*30855Sbostic 				fputs("        ", stdout);
286619Sbill 			else
287*30855Sbostic 				printf(N_FORMAT, (int)L->n_value);
288*30855Sbostic 			printf(" %c ", (char)type);
289619Sbill 		}
290*30855Sbostic 		puts(L->u_name);
291619Sbill 	}
292619Sbill }
293619Sbill 
294619Sbill compare(p1, p2)
295*30855Sbostic 	NLIST	**p1, **p2;
296619Sbill {
297619Sbill 	if (nflg) {
298*30855Sbostic 		if ((*p1)->n_value > (*p2)->n_value)
299619Sbill 			return(rflg);
300*30855Sbostic 		if ((*p1)->n_value < (*p2)->n_value)
301619Sbill 			return(-rflg);
302619Sbill 	}
303*30855Sbostic 	return(rflg * strcmp((*p1)->u_name, (*p2)->u_name));
304619Sbill }
305619Sbill 
306*30855Sbostic nextel()
307619Sbill {
308*30855Sbostic 	register char	*cp;
309*30855Sbostic 	long	arsize,
310*30855Sbostic 		lseek();
311619Sbill 
312*30855Sbostic 	(void)fseek(fi, off, L_SET);
313*30855Sbostic 	/*NOSTRICT*/
314*30855Sbostic 	if (!fread((char *)&archdr, sizeof(struct ar_hdr), 1, fi))
315619Sbill 		return(0);
316*30855Sbostic 	for (cp = archdr.ar_name; cp < &archdr.ar_name[sizeof(archdr.ar_name)]; ++cp)
317*30855Sbostic 		if (*cp == ' ') {
318619Sbill 			*cp = '\0';
319*30855Sbostic 			break;
320*30855Sbostic 		}
321619Sbill 	arsize = atol(archdr.ar_size);
322619Sbill 	if (arsize & 1)
323619Sbill 		++arsize;
324*30855Sbostic 	off = ftell(fi) + arsize;	/* beginning of next element */
325619Sbill 	return(1);
326619Sbill }
327619Sbill 
328619Sbill struct	stabnames {
329619Sbill 	int	st_value;
330619Sbill 	char	*st_name;
331619Sbill } stabnames[] ={
332*30855Sbostic 	N_GSYM,		"GSYM",
333*30855Sbostic 	N_FNAME,	"FNAME",
334*30855Sbostic 	N_FUN,		"FUN",
335*30855Sbostic 	N_STSYM,	"STSYM",
336*30855Sbostic 	N_LCSYM,	"LCSYM",
337*30855Sbostic 	N_RSYM,		"RSYM",
338*30855Sbostic 	N_SLINE,	"SLINE",
339*30855Sbostic 	N_SSYM,		"SSYM",
340*30855Sbostic 	N_SO,		"SO",
341*30855Sbostic 	N_LSYM,		"LSYM",
342*30855Sbostic 	N_SOL,		"SOL",
343*30855Sbostic 	N_PSYM,		"PSYM",
344*30855Sbostic 	N_ENTRY,	"ENTRY",
345*30855Sbostic 	N_LBRAC,	"LBRAC",
346*30855Sbostic 	N_RBRAC,	"RBRAC",
347*30855Sbostic 	N_BCOMM,	"BCOMM",
348*30855Sbostic 	N_ECOMM,	"ECOMM",
349*30855Sbostic 	N_ECOML,	"ECOML",
350*30855Sbostic 	N_LENG,		"LENG",
351*30855Sbostic 	N_PC,		"PC",
352*30855Sbostic 	0,		0
353619Sbill };
354619Sbill 
355619Sbill char *
356619Sbill stab(val)
357*30855Sbostic 	register u_char	val;
358619Sbill {
359*30855Sbostic 	register struct stabnames	*sp;
360*30855Sbostic 	static char	prbuf[5];
361619Sbill 
362*30855Sbostic 	for (sp = stabnames; sp->st_value; ++sp)
363619Sbill 		if (sp->st_value == val)
364*30855Sbostic 			return(sp->st_name);
365*30855Sbostic 	(void)sprintf(prbuf, "%02x", (int)val);
366*30855Sbostic 	return(prbuf);
367619Sbill }
368*30855Sbostic 
369*30855Sbostic error(doexit, msg)
370*30855Sbostic 	int	doexit;
371*30855Sbostic 	char	*msg;
372*30855Sbostic {
373*30855Sbostic 	fprintf(stderr, "nm: %s:", *xargv);
374*30855Sbostic 	if (archive)
375*30855Sbostic 		fprintf(stderr, "(%s): %s\n", archdr.ar_name, msg);
376*30855Sbostic 	else
377*30855Sbostic 		fprintf(stderr, " %s\n", msg);
378*30855Sbostic 	if (doexit)
379*30855Sbostic 		exit(2);
380*30855Sbostic 	errs = 1;
381*30855Sbostic }
382