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