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