xref: /original-bsd/usr.bin/nm/nm.c (revision 7211505a)
1 /*
2  * Copyright (c) 1987 Regents of the University of California.
3  * All rights reserved.  The Berkeley software License Agreement
4  * specifies the terms and conditions for redistribution.
5  */
6 
7 #ifndef lint
8 static	char sccsid[] = "@(#)nm.c 4.8 04/07/87";
9 #endif
10 
11 /*
12  * nm - print name list; VAX string table version
13  */
14 
15 #include <sys/types.h>
16 #include <sys/file.h>
17 #include <ar.h>
18 #include <stdio.h>
19 #include <ctype.h>
20 #include <a.out.h>
21 #include <stab.h>
22 #include <ranlib.h>
23 
24 #define	OARMAG		0177545		/* OLD archive magic number */
25 #define	SELECT		(archive ? archdr.ar_name : *xargv)
26 
27 #define	YES		1
28 #define	NO		0
29 
30 #define	u_strx		n_un.n_strx
31 #define	u_name		n_un.n_name
32 
33 typedef struct nlist	NLIST;
34 
35 union {				/* exec header, or magic string from library */
36 	char	mag_armag[SARMAG + 1];
37 	struct	exec mag_exp;
38 } mag_un;
39 
40 struct	ar_hdr	archdr;		/* archive file header structure */
41 FILE	*fi;			/* input file stream */
42 off_t	off;			/* offset into file */
43 int	aflg,			/* print debugger symbols */
44 	gflg,			/* print only global (external symbols */
45 	nflg,			/* sort numerically, not alphabetically */
46 	oflg,			/* prepend element name to each output line */
47 	pflg,			/* don't sort */
48 	rflg = 1,		/* how to sort */
49 	uflg,			/* print only undefined symbols */
50 	narg,			/* global number of arguments */
51 	errs,			/* global error flag */
52 	archive;		/* if file is an archive */
53 char	**xargv;		/* global pointer to file name */
54 
55 main(argc, argv)
56 	int	argc;
57 	char	**argv;
58 {
59 	extern int	optind;
60 	int	ch;			/* getopts char */
61 
62 	while ((ch = getopt(argc, argv, "agnopru")) != EOF)
63 		switch((char)ch) {
64 		case 'a':
65 			aflg = YES;
66 			break;
67 		case 'g':
68 			gflg = YES;
69 			break;
70 		case 'n':
71 			nflg = YES;
72 			break;
73 		case 'o':
74 			oflg = YES;
75 			break;
76 		case 'p':
77 			pflg = YES;
78 			break;
79 		case 'r':
80 			rflg = -1;
81 			break;
82 		case 'u':
83 			uflg = YES;
84 			break;
85 		case '?':
86 		default:
87 			fputs("usage: nm [-agnopru] [file ...]\n", stderr);
88 			exit(2);
89 		}
90 	argc -= optind;
91 	argv += optind;
92 	if (!argc) {
93 		argc = 1;
94 		argv[0] = "a.out";
95 	}
96 	narg = argc;
97 	for (xargv = argv; argc--; ++xargv)
98 		if (fi = fopen(*xargv, "r")) {
99 			namelist();
100 			(void)fclose(fi);
101 		}
102 		else
103 			error(NO, "cannot open");
104 	exit(errs);
105 }
106 
107 namelist()
108 {
109 	register NLIST	*N, **L;
110 	register int	symcount, nsyms;
111 	static	NLIST	*symp, **list;
112 	static int	lastnsyms = -1,
113 			laststrsiz = -1;
114 	static char	*strp;
115 	off_t	strsiz;
116 	long	lseek();
117 	int	compare();
118 	char	*malloc(), *realloc();
119 
120 	/*
121 	 * read first few bytes, determine if an archive,
122 	 * or executable; if executable, check magic number
123 	 */
124 	/*NOSTRICT*/
125 	if (!fread((char *)&mag_un, sizeof(mag_un), 1, fi)) {
126 		error(NO, "unable to read file");
127 		return;
128 	}
129 	if (mag_un.mag_exp.a_magic == OARMAG) {
130 		error(NO, "old archive");
131 		return;
132 	}
133 	if (bcmp(mag_un.mag_armag, ARMAG, SARMAG)) {
134 		if (N_BADMAG(mag_un.mag_exp)) {
135 			error(NO, "bad format");
136 			return;
137 		}
138 		archive = NO;
139 		rewind(fi);
140 	}
141 	else {
142 		/*
143 		 * if archive, skip first entry
144 		 * if ranlib'd, skip second entry
145 		 */
146 		off = SARMAG;		/* see nextel() */
147 		(void)nextel();
148 		if (!strcmp(RANLIBMAG, archdr.ar_name))
149 			(void)nextel();
150 		if (narg > 1)
151 			printf("\n%s:\n", *xargv);
152 		archive = YES;
153 	}
154 
155 	do {
156 		/* check for bad magic number */
157 		/*NOSTRICT*/
158 		if (!fread((char *)&mag_un.mag_exp, sizeof(struct exec), 1, fi)) {
159 			error(NO, "unable to read magic number");
160 			return;
161 		}
162 		if (N_BADMAG(mag_un.mag_exp))
163 			continue;
164 
165 		/* calculate number of symbols in object */
166 		if (!(nsyms = mag_un.mag_exp.a_syms / sizeof(NLIST))) {
167 			error(NO, "no name list");
168 			continue;
169 		}
170 
171 		/* seek to and read symbols */
172 		(void)fseek(fi, (long)(N_SYMOFF(mag_un.mag_exp) - sizeof(struct exec)), L_INCR);
173 		if (!symp || nsyms > lastnsyms) {
174 			if (!symp) {
175 				/*NOSTRICT*/
176 				symp = (NLIST *)malloc((u_int)(nsyms * sizeof(NLIST)));
177 				/*NOSTRICT*/
178 				list = (NLIST **)malloc((u_int)(nsyms * sizeof(NLIST *)));
179 			}
180 			else {
181 				/*NOSTRICT*/
182 				symp = (NLIST *)realloc((char *)symp, (u_int)(nsyms * sizeof(NLIST)));
183 				/*NOSTRICT*/
184 				list = (NLIST **)realloc((char *)list, (u_int)(nsyms * sizeof(NLIST *)));
185 			}
186 			if (!symp || !list)
187 				error(YES, "out of memory");
188 			lastnsyms = nsyms;
189 		}
190 		/*NOSTRICT*/
191 		if (fread((char *)symp, sizeof(NLIST), nsyms, fi) != nsyms) {
192 			error(NO, "bad symbol table");
193 			continue;
194 		}
195 
196 		/* read number of strings, string table */
197 		/*NOSTRICT*/
198 		if (!fread((char *)&strsiz, sizeof(strsiz), 1, fi)) {
199 			error(NO, "no string table (old format .o?)");
200 			continue;
201 		}
202 		if (!strp || strsiz > laststrsiz) {
203 			strp = strp ? realloc(strp, (u_int)strsiz) : malloc((u_int)strsiz);
204 			if (!strp)
205 				error(YES, "out of memory");
206 			laststrsiz = strsiz;
207 		}
208 		if (!fread(strp + sizeof(strsiz), 1, (int)(strsiz - sizeof(strsiz)), fi)) {
209 			error(NO, "no string table (old format .o?)");
210 			continue;
211 		}
212 
213 		for (symcount = nsyms, L = list, N = symp;--nsyms >= 0;++N)
214 			if (!(N->n_type & N_EXT) && gflg || N->n_type & N_STAB && (!aflg || gflg || uflg))
215 				--symcount;
216 			else {
217 				N->u_name = N->u_strx ? strp + N->u_strx : "";
218 				*L++ = N;
219 			}
220 
221 		if (!pflg)
222 			qsort(list, symcount, sizeof(NLIST *), compare);
223 
224 		if ((archive || narg > 1) && !oflg)
225 			printf("\n%s:\n", SELECT);
226 
227 		psyms(list, symcount);
228 	} while(archive && nextel());
229 }
230 
231 psyms(list, nsyms)
232 	NLIST	**list;
233 	register int	nsyms;
234 {
235 	register NLIST	*L;
236 	register u_char	type;
237 	char	*stab();
238 
239 	while (nsyms--) {
240 		L = *list++;
241 		type = L->n_type;
242 		if (type & N_STAB) {
243 			if (oflg) {
244 				if (archive)
245 					printf("%s:", *xargv);
246 				printf("%s:", SELECT);
247 			}
248 			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);
249 			continue;
250 		}
251 		switch (type & N_TYPE) {
252 		case N_UNDF:
253 			type = L->n_value ? 'c' : 'u';
254 			break;
255 		case N_ABS:
256 			type = 'a';
257 			break;
258 		case N_TEXT:
259 			type = 't';
260 			break;
261 		case N_DATA:
262 			type = 'd';
263 			break;
264 		case N_BSS:
265 			type = 'b';
266 			break;
267 		case N_FN:
268 			type = 'f';
269 			break;
270 		default:
271 			type = '?';
272 			break;
273 		}
274 		if (uflg && type != 'u')
275 			continue;
276 		if (oflg) {
277 			if (archive)
278 				printf("%s:", *xargv);
279 			printf("%s:", SELECT);
280 		}
281 		if (L->n_type & N_EXT)
282 			type = toupper(type);
283 		if (!uflg) {
284 			if (type == 'u' || type == 'U')
285 				fputs("        ", stdout);
286 			else
287 				printf(N_FORMAT, (int)L->n_value);
288 			printf(" %c ", (char)type);
289 		}
290 		puts(L->u_name);
291 	}
292 }
293 
294 compare(p1, p2)
295 	NLIST	**p1, **p2;
296 {
297 	if (nflg) {
298 		if ((*p1)->n_value > (*p2)->n_value)
299 			return(rflg);
300 		if ((*p1)->n_value < (*p2)->n_value)
301 			return(-rflg);
302 	}
303 	return(rflg * strcmp((*p1)->u_name, (*p2)->u_name));
304 }
305 
306 nextel()
307 {
308 	register char	*cp;
309 	long	arsize,
310 		lseek();
311 
312 	(void)fseek(fi, off, L_SET);
313 	/*NOSTRICT*/
314 	if (!fread((char *)&archdr, sizeof(struct ar_hdr), 1, fi))
315 		return(0);
316 	for (cp = archdr.ar_name; cp < &archdr.ar_name[sizeof(archdr.ar_name)]; ++cp)
317 		if (*cp == ' ') {
318 			*cp = '\0';
319 			break;
320 		}
321 	arsize = atol(archdr.ar_size);
322 	if (arsize & 1)
323 		++arsize;
324 	off = ftell(fi) + arsize;	/* beginning of next element */
325 	return(1);
326 }
327 
328 struct	stabnames {
329 	int	st_value;
330 	char	*st_name;
331 } stabnames[] ={
332 	N_GSYM,		"GSYM",
333 	N_FNAME,	"FNAME",
334 	N_FUN,		"FUN",
335 	N_STSYM,	"STSYM",
336 	N_LCSYM,	"LCSYM",
337 	N_RSYM,		"RSYM",
338 	N_SLINE,	"SLINE",
339 	N_SSYM,		"SSYM",
340 	N_SO,		"SO",
341 	N_LSYM,		"LSYM",
342 	N_SOL,		"SOL",
343 	N_PSYM,		"PSYM",
344 	N_ENTRY,	"ENTRY",
345 	N_LBRAC,	"LBRAC",
346 	N_RBRAC,	"RBRAC",
347 	N_BCOMM,	"BCOMM",
348 	N_ECOMM,	"ECOMM",
349 	N_ECOML,	"ECOML",
350 	N_LENG,		"LENG",
351 	N_PC,		"PC",
352 	0,		0
353 };
354 
355 char *
356 stab(val)
357 	register u_char	val;
358 {
359 	register struct stabnames	*sp;
360 	static char	prbuf[5];
361 
362 	for (sp = stabnames; sp->st_value; ++sp)
363 		if (sp->st_value == val)
364 			return(sp->st_name);
365 	(void)sprintf(prbuf, "%02x", (int)val);
366 	return(prbuf);
367 }
368 
369 error(doexit, msg)
370 	int	doexit;
371 	char	*msg;
372 {
373 	fprintf(stderr, "nm: %s:", *xargv);
374 	if (archive)
375 		fprintf(stderr, "(%s): %s\n", archdr.ar_name, msg);
376 	else
377 		fprintf(stderr, " %s\n", msg);
378 	if (doexit)
379 		exit(2);
380 	errs = 1;
381 }
382