cleanups, add manual page
[unix-history] / usr / src / usr.bin / nm / nm.c
CommitLineData
2fd2f477
KB
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
7ea0db89 7#ifndef lint
2fd2f477 8static char sccsid[] = "@(#)nm.c 4.8 %G%";
7ea0db89 9#endif
2fd2f477 10
c0bc0330
BJ
11/*
12 * nm - print name list; VAX string table version
13 */
2fd2f477 14
c0bc0330 15#include <sys/types.h>
2fd2f477 16#include <sys/file.h>
9789d1cb 17#include <ar.h>
c0bc0330
BJ
18#include <stdio.h>
19#include <ctype.h>
9789d1cb 20#include <a.out.h>
c0bc0330 21#include <stab.h>
2fd2f477 22#include <ranlib.h>
c0bc0330 23
2fd2f477
KB
24#define OARMAG 0177545 /* OLD archive magic number */
25#define SELECT (archive ? archdr.ar_name : *xargv)
c0bc0330 26
2fd2f477
KB
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
33typedef struct nlist NLIST;
34
35union { /* exec header, or magic string from library */
36 char mag_armag[SARMAG + 1];
c0bc0330
BJ
37 struct exec mag_exp;
38} mag_un;
2fd2f477
KB
39
40struct ar_hdr archdr; /* archive file header structure */
41FILE *fi; /* input file stream */
42off_t off; /* offset into file */
43int 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 */
53char **xargv; /* global pointer to file name */
c0bc0330
BJ
54
55main(argc, argv)
2fd2f477
KB
56 int argc;
57 char **argv;
c0bc0330 58{
2fd2f477
KB
59 extern int optind;
60 int ch; /* getopts char */
c0bc0330 61
2fd2f477
KB
62 while ((ch = getopt(argc, argv, "agnopru")) != EOF)
63 switch((char)ch) {
64 case 'a':
65 aflg = YES;
66 break;
c0bc0330 67 case 'g':
2fd2f477
KB
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;
c0bc0330
BJ
79 case 'r':
80 rflg = -1;
2fd2f477
KB
81 break;
82 case 'u':
83 uflg = YES;
84 break;
85 case '?':
c0bc0330 86 default:
2fd2f477 87 fputs("usage: nm [-agnopru] [file ...]\n", stderr);
c0bc0330
BJ
88 exit(2);
89 }
2fd2f477
KB
90 argc -= optind;
91 argv += optind;
92 if (!argc) {
c0bc0330 93 argc = 1;
2fd2f477 94 argv[0] = "a.out";
c0bc0330
BJ
95 }
96 narg = argc;
2fd2f477
KB
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");
c0bc0330
BJ
104 exit(errs);
105}
106
107namelist()
108{
2fd2f477
KB
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();
c0bc0330 119
2fd2f477
KB
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");
c0bc0330
BJ
127 return;
128 }
c0bc0330 129 if (mag_un.mag_exp.a_magic == OARMAG) {
2fd2f477
KB
130 error(NO, "old archive");
131 return;
c0bc0330 132 }
2fd2f477
KB
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);
c0bc0330 140 }
2fd2f477
KB
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();
c0bc0330
BJ
150 if (narg > 1)
151 printf("\n%s:\n", *xargv);
2fd2f477 152 archive = YES;
c0bc0330 153 }
c0bc0330 154
2fd2f477
KB
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 }
c0bc0330
BJ
162 if (N_BADMAG(mag_un.mag_exp))
163 continue;
2fd2f477
KB
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");
c0bc0330
BJ
168 continue;
169 }
2fd2f477
KB
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;
42d1ac1d 189 }
2fd2f477
KB
190 /*NOSTRICT*/
191 if (fread((char *)symp, sizeof(NLIST), nsyms, fi) != nsyms) {
192 error(NO, "bad symbol table");
193 continue;
c0bc0330 194 }
2fd2f477
KB
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?)");
c0bc0330
BJ
200 continue;
201 }
2fd2f477
KB
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;
c0bc0330 207 }
2fd2f477
KB
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)
c0bc0330 225 printf("\n%s:\n", SELECT);
2fd2f477
KB
226
227 psyms(list, symcount);
228 } while(archive && nextel());
c0bc0330
BJ
229}
230
2fd2f477
KB
231psyms(list, nsyms)
232 NLIST **list;
233 register int nsyms;
c0bc0330 234{
2fd2f477
KB
235 register NLIST *L;
236 register u_char type;
237 char *stab();
c0bc0330 238
2fd2f477
KB
239 while (nsyms--) {
240 L = *list++;
241 type = L->n_type;
242 if (type & N_STAB) {
c0bc0330
BJ
243 if (oflg) {
244 if (archive)
245 printf("%s:", *xargv);
246 printf("%s:", SELECT);
247 }
2fd2f477 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);
c0bc0330
BJ
249 continue;
250 }
2fd2f477 251 switch (type & N_TYPE) {
c0bc0330 252 case N_UNDF:
2fd2f477 253 type = L->n_value ? 'c' : 'u';
c0bc0330
BJ
254 break;
255 case N_ABS:
2fd2f477 256 type = 'a';
c0bc0330
BJ
257 break;
258 case N_TEXT:
2fd2f477 259 type = 't';
c0bc0330
BJ
260 break;
261 case N_DATA:
2fd2f477 262 type = 'd';
c0bc0330
BJ
263 break;
264 case N_BSS:
2fd2f477
KB
265 type = 'b';
266 break;
267 case N_FN:
268 type = 'f';
c0bc0330 269 break;
102fbeaf 270 default:
2fd2f477 271 type = '?';
c0bc0330
BJ
272 break;
273 }
2fd2f477 274 if (uflg && type != 'u')
c0bc0330
BJ
275 continue;
276 if (oflg) {
277 if (archive)
278 printf("%s:", *xargv);
279 printf("%s:", SELECT);
280 }
2fd2f477
KB
281 if (L->n_type & N_EXT)
282 type = toupper(type);
c0bc0330 283 if (!uflg) {
2fd2f477
KB
284 if (type == 'u' || type == 'U')
285 fputs(" ", stdout);
c0bc0330 286 else
2fd2f477
KB
287 printf(N_FORMAT, (int)L->n_value);
288 printf(" %c ", (char)type);
c0bc0330 289 }
2fd2f477 290 puts(L->u_name);
c0bc0330
BJ
291 }
292}
293
294compare(p1, p2)
2fd2f477 295 NLIST **p1, **p2;
c0bc0330 296{
c0bc0330 297 if (nflg) {
2fd2f477 298 if ((*p1)->n_value > (*p2)->n_value)
c0bc0330 299 return(rflg);
2fd2f477 300 if ((*p1)->n_value < (*p2)->n_value)
c0bc0330
BJ
301 return(-rflg);
302 }
2fd2f477 303 return(rflg * strcmp((*p1)->u_name, (*p2)->u_name));
c0bc0330
BJ
304}
305
2fd2f477 306nextel()
c0bc0330 307{
2fd2f477
KB
308 register char *cp;
309 long arsize,
310 lseek();
c0bc0330 311
2fd2f477
KB
312 (void)fseek(fi, off, L_SET);
313 /*NOSTRICT*/
314 if (!fread((char *)&archdr, sizeof(struct ar_hdr), 1, fi))
c0bc0330 315 return(0);
2fd2f477
KB
316 for (cp = archdr.ar_name; cp < &archdr.ar_name[sizeof(archdr.ar_name)]; ++cp)
317 if (*cp == ' ') {
c0bc0330 318 *cp = '\0';
2fd2f477
KB
319 break;
320 }
c0bc0330
BJ
321 arsize = atol(archdr.ar_size);
322 if (arsize & 1)
323 ++arsize;
2fd2f477 324 off = ftell(fi) + arsize; /* beginning of next element */
c0bc0330
BJ
325 return(1);
326}
327
c0bc0330
BJ
328struct stabnames {
329 int st_value;
330 char *st_name;
331} stabnames[] ={
2fd2f477
KB
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
c0bc0330
BJ
353};
354
355char *
356stab(val)
2fd2f477 357 register u_char val;
c0bc0330 358{
2fd2f477
KB
359 register struct stabnames *sp;
360 static char prbuf[5];
c0bc0330 361
2fd2f477 362 for (sp = stabnames; sp->st_value; ++sp)
c0bc0330 363 if (sp->st_value == val)
2fd2f477
KB
364 return(sp->st_name);
365 (void)sprintf(prbuf, "%02x", (int)val);
366 return(prbuf);
367}
368
369error(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;
c0bc0330 381}