]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.bin/nm/nm.c
Fixed classic sign extension bug `-(long)sizeof(foo)'.
[FreeBSD/FreeBSD.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         "$Id: nm.c,v 1.11 1997/07/31 06:53:36 charnier 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         extern int optind;
101         int ch, errors;
102
103         while ((ch = getopt(argc, argv, "agnoprtuwW")) != -1) {
104                 switch (ch) {
105                 case 'a':
106                         print_all_symbols = 1;
107                         break;
108                 case 'g':
109                         print_only_external_symbols = 1;
110                         break;
111                 case 'n':
112                         sfunc = value;
113                         break;
114                 case 'o':
115                         print_file_each_line = 1;
116                         break;
117                 case 'p':
118                         sfunc = NULL;
119                         break;
120                 case 'r':
121                         rev = 1;
122                         break;
123                 case 't':
124                         table = 1;
125                         break;
126                 case 'u':
127                         print_only_undefined_symbols = 1;
128                         break;
129                 case 'w':
130                         ignore_bad_archive_entries = 0;
131                         break;
132                 case 'W':
133                         print_weak_symbols = 1;
134                         break;
135                 case '?':
136                 default:
137                         usage();
138                 }
139         }
140         fcount = argc - optind;
141         argv += optind;
142
143         if (rev && sfunc == fname)
144                 sfunc = rname;
145
146         if (!fcount)
147                 errors = process_file("a.out");
148         else {
149                 errors = 0;
150                 do {
151                         errors |= process_file(*argv);
152                 } while (*++argv);
153         }
154         exit(errors);
155 }
156
157 /*
158  * process_file()
159  *      show symbols in the file given as an argument.  Accepts archive and
160  *      object files as input.
161  */
162 int
163 process_file(fname)
164         char *fname;
165 {
166         struct exec exec_head;
167         FILE *fp;
168         int retval;
169         char magic[SARMAG];
170
171         if (!(fp = fopen(fname, "r"))) {
172                 warnx("cannot read %s", fname);
173                 return(1);
174         }
175
176         if (fcount > 1 && !table)
177                 (void)printf("\n%s:\n", fname);
178
179         /*
180          * first check whether this is an object file - read a object
181          * header, and skip back to the beginning
182          */
183         if (fread((char *)&exec_head, sizeof(exec_head), (size_t)1, fp) != 1) {
184                 warnx("%s: bad format", fname);
185                 (void)fclose(fp);
186                 return(1);
187         }
188         rewind(fp);
189
190         /* this could be an archive */
191         if (N_BADMAG(exec_head)) {
192                 if (fread(magic, sizeof(magic), (size_t)1, fp) != 1 ||
193                     strncmp(magic, ARMAG, SARMAG)) {
194                         warnx("%s: not object file or archive", fname);
195                         (void)fclose(fp);
196                         return(1);
197                 }
198                 retval = show_archive(fname, fp);
199         } else
200                 retval = show_objfile(fname, fp);
201         (void)fclose(fp);
202         return(retval);
203 }
204
205 /* scat: concatenate strings, returning new concatenation point
206  * and permitting overlap.
207  */
208 static char *scat(char *dest, char *src)
209 {
210         char *end;
211         int l1 = strlen(dest), l2 = strlen(src);
212
213         memmove(dest + l1, src, l2);
214         end = dest + l1 + l2;
215         *end = 0;
216
217         return end;
218 }
219
220 /*
221  * show_archive()
222  *      show symbols in the given archive file
223  */
224 int
225 show_archive(fname, fp)
226         char *fname;
227         FILE *fp;
228 {
229         struct ar_hdr ar_head;
230         struct exec exec_head;
231         int i, rval;
232         long last_ar_off;
233         char *p, *name, *ar_name;
234         int extra = strlen(fname) + 3;
235
236         name = emalloc(MAXNAMLEN + extra);
237         ar_name = name + extra;
238
239         rval = 0;
240
241         /* while there are more entries in the archive */
242         while (fread((char *)&ar_head, sizeof(ar_head), (size_t)1, fp) == 1) {
243                 /* bad archive entry - stop processing this archive */
244                 if (strncmp(ar_head.ar_fmag, ARFMAG, sizeof(ar_head.ar_fmag))) {
245                         warnx("%s: bad format archive header", fname);
246                         (void)free(name);
247                         return(1);
248                 }
249
250                 /* remember start position of current archive object */
251                 last_ar_off = ftell(fp);
252
253                 /* skip ranlib entries */
254                 if (!bcmp(ar_head.ar_name, RANLIBMAG, sizeof(RANLIBMAG) - 1))
255                         goto skip;
256
257                 /* handle long names.  If one is present, read it in at the
258                  * end of the "name" buffer.
259                  */
260                 if (!bcmp(ar_head.ar_name, AR_EFMT1, sizeof(AR_EFMT1) - 1))
261                 {
262                         size_t len = atoi(ar_head.ar_name + sizeof(AR_EFMT1) - 1);
263
264                         if (len <= 0 || len > MAXNAMLEN)
265                         {
266                                 warnx("illegal length for format 1 long name");
267                                 goto skip;
268                         }
269                         if (fread(ar_name, 1, len, fp) != len)
270                         {
271                                 warnx("EOF reading format 1 long name");
272                                 (void)free(name);
273                                 return(1);
274                         }
275                         ar_name[len] = 0;
276                 }
277                 else
278                 {
279                         p = ar_head.ar_name;
280                         for (i = 0; i < sizeof(ar_head.ar_name) && p[i] && p[i] != ' '; i++)
281                                         ar_name[i] = p[i];
282                         ar_name[i] = 0;
283                 }
284
285                 /*
286                  * construct a name of the form "archive.a:obj.o:" for the
287                  * current archive entry if the object name is to be printed
288                  * on each output line
289                  */
290                 p = name;
291                 *p = 0;
292                 if (print_file_each_line && !table)
293                 {
294                         p = scat(p, fname);
295                         p = scat(p, ":");
296                 }
297                 p = scat(p, ar_name);
298
299                 /* get and check current object's header */
300                 if (fread((char *)&exec_head, sizeof(exec_head), (size_t)1, fp) != 1) {
301                         warnx("%s: premature EOF", name);
302                         (void)free(name);
303                         return(1);
304                 }
305
306                 if (N_BADMAG(exec_head)) {
307                         if (!ignore_bad_archive_entries) {
308                                 warnx("%s: bad format", name);
309                                 rval = 1;
310                         }
311                 } else {
312                         (void)fseek(fp, -(long)sizeof(exec_head),
313                             SEEK_CUR);
314                         if (!print_file_each_line && !table)
315                                 (void)printf("\n%s:\n", name);
316                         rval |= show_objfile(name, fp);
317                 }
318
319                 /*
320                  * skip to next archive object - it starts at the next
321                  * even byte boundary
322                  */
323 #define even(x) (((x) + 1) & ~1)
324 skip:           if (fseek(fp, last_ar_off + even(atol(ar_head.ar_size)),
325                     SEEK_SET)) {
326                         warn("%s", fname);
327                         (void)free(name);
328                         return(1);
329                 }
330         }
331         (void)free(name);
332         return(rval);
333 }
334
335 /*
336  * show_objfile()
337  *      show symbols from the object file pointed to by fp.  The current
338  *      file pointer for fp is expected to be at the beginning of an a.out
339  *      header.
340  */
341 int
342 show_objfile(objname, fp)
343         char *objname;
344         FILE *fp;
345 {
346         register struct nlist *names, *np;
347         register int i, nnames, nrawnames;
348         struct exec head;
349         int32_t stabsize;
350         char *stab;
351
352         /* read a.out header */
353         if (fread((char *)&head, sizeof(head), (size_t)1, fp) != 1) {
354                 warnx("%s: cannot read header", objname);
355                 return(1);
356         }
357
358         /*
359          * skip back to the header - the N_-macros return values relative
360          * to the beginning of the a.out header
361          */
362         if (fseek(fp, -(long)sizeof(head), SEEK_CUR)) {
363                 warn("%s", objname);
364                 return(1);
365         }
366
367         /* stop if this is no valid object file */
368         if (N_BADMAG(head)) {
369                 warnx("%s: bad format", objname);
370                 return(1);
371         }
372
373         /* stop if the object file contains no symbol table */
374         if (!head.a_syms) {
375                 warnx("%s: no name list", objname);
376                 return(1);
377         }
378
379         if (fseek(fp, (long)N_SYMOFF(head), SEEK_CUR)) {
380                 warn("%s", objname);
381                 return(1);
382         }
383
384         /* get memory for the symbol table */
385         names = emalloc((size_t)head.a_syms);
386         nrawnames = head.a_syms / sizeof(*names);
387         if (fread((char *)names, (size_t)head.a_syms, (size_t)1, fp) != 1) {
388                 warnx("%s: cannot read symbol table", objname);
389                 (void)free((char *)names);
390                 return(1);
391         }
392
393         /*
394          * Following the symbol table comes the string table.  The first
395          * 4-byte-integer gives the total size of the string table
396          * _including_ the size specification itself.
397          */
398         if (fread((char *)&stabsize, sizeof(stabsize), (size_t)1, fp) != 1) {
399                 warnx("%s: cannot read stab size", objname);
400                 (void)free((char *)names);
401                 return(1);
402         }
403         stab = emalloc((size_t)stabsize);
404
405         /*
406          * read the string table offset by 4 - all indices into the string
407          * table include the size specification.
408          */
409         stabsize -= 4;          /* we already have the size */
410         if (fread(stab + 4, (size_t)stabsize, (size_t)1, fp) != 1) {
411                 warnx("%s: stab truncated..", objname);
412                 (void)free((char *)names);
413                 (void)free(stab);
414                 return(1);
415         }
416
417         /*
418          * fix up the symbol table and filter out unwanted entries
419          *
420          * common symbols are characterized by a n_type of N_UNDF and a
421          * non-zero n_value -- change n_type to N_COMM for all such
422          * symbols to make life easier later.
423          *
424          * filter out all entries which we don't want to print anyway
425          */
426         for (np = names, i = nnames = 0; i < nrawnames; np++, i++) {
427                 if (SYMBOL_TYPE(np->n_type) == N_UNDF && np->n_value)
428                         np->n_type = N_COMM | (np->n_type & N_EXT);
429                 if (!print_all_symbols && IS_DEBUGGER_SYMBOL(np->n_type))
430                         continue;
431                 if (print_only_external_symbols && !IS_EXTERNAL(np->n_type))
432                         continue;
433                 if (print_only_undefined_symbols &&
434                     SYMBOL_TYPE(np->n_type) != N_UNDF)
435                         continue;
436
437                 /*
438                  * make n_un.n_name a character pointer by adding the string
439                  * table's base to n_un.n_strx
440                  *
441                  * don't mess with zero offsets
442                  */
443                 if (np->n_un.n_strx)
444                         np->n_un.n_name = stab + np->n_un.n_strx;
445                 else
446                         np->n_un.n_name = "";
447                 names[nnames++] = *np;
448         }
449
450         /* sort the symbol table if applicable */
451         if (sfunc)
452                 qsort((char *)names, (size_t)nnames, sizeof(*names), sfunc);
453
454         /* print out symbols */
455         for (np = names, i = 0; i < nnames; np++, i++)
456                 print_symbol(objname, np);
457
458         (void)free((char *)names);
459         (void)free(stab);
460         return(0);
461 }
462
463 /*
464  * print_symbol()
465  *      show one symbol
466  */
467 void
468 print_symbol(objname, sym)
469         char *objname;
470         register struct nlist *sym;
471 {
472         char *typestring();
473
474         if (table) {
475                 printf("%s|", objname);
476                 if (SYMBOL_TYPE(sym->n_type) != N_UNDF)
477                         (void)printf("%08lx", (u_long)sym->n_value);
478                 (void)printf("|");
479                 if (IS_DEBUGGER_SYMBOL(sym->n_type))
480                         (void)printf("-|%02x %04x %5s|", sym->n_other,
481                             sym->n_desc&0xffff, typestring(sym->n_type));
482                 else {
483                         putchar(typeletter(sym->n_type));
484                         if (print_weak_symbols && SYMBOL_BIND(sym->n_other)== 2)
485                                 putchar('W');
486                         putchar('|');
487                 }
488
489                 /* print the symbol's name */
490                 (void)printf("%s\n",sym->n_un.n_name);
491                 return;
492         }
493         if (print_file_each_line)
494                 (void)printf("%s:", objname);
495
496         /*
497          * handle undefined-only format seperately (no space is
498          * left for symbol values, no type field is printed)
499          */
500         if (print_only_undefined_symbols) {
501                 (void)puts(sym->n_un.n_name);
502                 return;
503         }
504
505         /* print symbol's value */
506         if (SYMBOL_TYPE(sym->n_type) == N_UNDF)
507                 (void)printf("        ");
508         else
509                 (void)printf("%08lx", (u_long)sym->n_value);
510
511         /* print type information */
512         if (IS_DEBUGGER_SYMBOL(sym->n_type))
513                 (void)printf(" - %02x %04x %5s ", sym->n_other,
514                     sym->n_desc&0xffff, typestring(sym->n_type));
515         else {
516                 putchar(' ');
517                 putchar(typeletter(sym->n_type));
518                 if (print_weak_symbols) {
519                         if (SYMBOL_BIND(sym->n_other) == 2)
520                                 putchar('W');
521                         else
522                                 putchar(' ');
523                 }
524                 putchar(' ');
525         }
526
527         /* print the symbol's name */
528         (void)puts(sym->n_un.n_name);
529 }
530
531 /*
532  * typestring()
533  *      return the a description string for an STAB entry
534  */
535 char *
536 typestring(type)
537         register u_char type;
538 {
539         switch(type) {
540         case N_BCOMM:
541                 return("BCOMM");
542         case N_ECOML:
543                 return("ECOML");
544         case N_ECOMM:
545                 return("ECOMM");
546         case N_ENTRY:
547                 return("ENTRY");
548         case N_FNAME:
549                 return("FNAME");
550         case N_FUN:
551                 return("FUN");
552         case N_GSYM:
553                 return("GSYM");
554         case N_LBRAC:
555                 return("LBRAC");
556         case N_LCSYM:
557                 return("LCSYM");
558         case N_LENG:
559                 return("LENG");
560         case N_LSYM:
561                 return("LSYM");
562         case N_PC:
563                 return("PC");
564         case N_PSYM:
565                 return("PSYM");
566         case N_RBRAC:
567                 return("RBRAC");
568         case N_RSYM:
569                 return("RSYM");
570         case N_SLINE:
571                 return("SLINE");
572         case N_SO:
573                 return("SO");
574         case N_SOL:
575                 return("SOL");
576         case N_SSYM:
577                 return("SSYM");
578         case N_STSYM:
579                 return("STSYM");
580         }
581         return("???");
582 }
583
584 /*
585  * typeletter()
586  *      return a description letter for the given basic type code of an
587  *      symbol table entry.  The return value will be upper case for
588  *      external, lower case for internal symbols.
589  */
590 char
591 typeletter(type)
592         u_char type;
593 {
594         switch(SYMBOL_TYPE(type)) {
595         case N_ABS:
596                 return(IS_EXTERNAL(type) ? 'A' : 'a');
597         case N_BSS:
598                 return(IS_EXTERNAL(type) ? 'B' : 'b');
599         case N_COMM:
600                 return(IS_EXTERNAL(type) ? 'C' : 'c');
601         case N_DATA:
602                 return(IS_EXTERNAL(type) ? 'D' : 'd');
603         case N_FN:
604                 /* This one is overloaded. EXT = Filename, INT = warn refs */
605                 return(IS_EXTERNAL(type) ? 'F' : 'w');
606         case N_INDR:
607                 return(IS_EXTERNAL(type) ? 'I' : 'i');
608         case N_TEXT:
609                 return(IS_EXTERNAL(type) ? 'T' : 't');
610         case N_UNDF:
611                 return(IS_EXTERNAL(type) ? 'U' : 'u');
612         }
613         return('?');
614 }
615
616 int
617 fname(a0, b0)
618         void *a0, *b0;
619 {
620         struct nlist *a = a0, *b = b0;
621
622         return(strcmp(a->n_un.n_name, b->n_un.n_name));
623 }
624
625 int
626 rname(a0, b0)
627         void *a0, *b0;
628 {
629         struct nlist *a = a0, *b = b0;
630
631         return(strcmp(b->n_un.n_name, a->n_un.n_name));
632 }
633
634 int
635 value(a0, b0)
636         void *a0, *b0;
637 {
638         register struct nlist *a = a0, *b = b0;
639
640         if (SYMBOL_TYPE(a->n_type) == N_UNDF)
641                 if (SYMBOL_TYPE(b->n_type) == N_UNDF)
642                         return(0);
643                 else
644                         return(-1);
645         else if (SYMBOL_TYPE(b->n_type) == N_UNDF)
646                 return(1);
647         if (rev) {
648                 if (a->n_value == b->n_value)
649                         return(rname(a0, b0));
650                 return(b->n_value > a->n_value ? 1 : -1);
651         } else {
652                 if (a->n_value == b->n_value)
653                         return(fname(a0, b0));
654                 return(a->n_value > b->n_value ? 1 : -1);
655         }
656 }
657
658 void *
659 emalloc(size)
660         size_t size;
661 {
662         char *p;
663
664         /* NOSTRICT */
665         if ( (p = malloc(size)) )
666                 return(p);
667         err(1, NULL);
668 }
669
670 static void
671 usage(void)
672 {
673         (void)fprintf(stderr, "usage: nm [-agnoprtuwW] [file ...]\n");
674         exit(1);
675 }