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