|
|
1.1 root 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 4/7/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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.