Added +version (-V) option to print version number.
[external/binutils.git] / binutils / nm.c
1 /* nm.c -- Describe symbol table of a rel file.
2    Copyright 1991, 1992 Free Software Foundation, Inc.
3
4 This file is part of GNU Binutils.
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
19
20 #include "bfd.h"
21 #include "sysdep.h"
22 #include "bucomm.h"
23 #include "getopt.h"
24 #include "aout/stab_gnu.h"
25 #include "aout/ranlib.h"
26
27 static boolean
28 display_file PARAMS ((char *filename));
29
30 static void
31 do_one_rel_file PARAMS ((bfd *file));
32
33 static unsigned int
34 filter_symbols PARAMS ((bfd *file, asymbol **syms, unsigned long symcount));
35
36 static void
37 print_symbols PARAMS ((bfd *file, asymbol **syms, unsigned long symcount));
38
39 static void
40 print_symdef_entry PARAMS ((bfd * abfd));
41
42 /* Command options.  */
43
44 int external_only = 0;  /* print external symbols only */
45 int file_on_each_line = 0; /* print file name on each line */
46 int no_sort = 0;        /* don't sort; print syms in order found */
47 int print_debug_syms = 0; /* print debugger-only symbols too */
48 int print_armap = 0;    /* describe __.SYMDEF data in archive files.  */
49 int reverse_sort = 0;   /* sort in downward(alpha or numeric) order */
50 int sort_numerically = 0; /* sort in numeric rather than alpha order */
51 int undefined_only = 0; /* print undefined symbols only */
52 int show_version = 0;   /* show the version number */
53
54 boolean print_each_filename = false; /* Ick.  Used in archives. */
55
56 /* IMPORT */
57 extern char *program_name;
58 extern char *program_version;
59 extern char *target;
60 extern int print_version;
61
62 struct option long_options[] = {
63         {"debug-syms",      no_argument, &print_debug_syms,  1},
64         {"extern-only",     no_argument, &external_only,     1},
65         {"no-sort",         no_argument, &no_sort,         1},
66         {"numeric-sort",    no_argument, &sort_numerically,  1},
67         {"print-armap",     no_argument, &print_armap,       1},
68         {"print-file-name", no_argument, &file_on_each_line, 1},
69         {"reverse-sort",    no_argument, &reverse_sort,      1},
70         {"target",          optional_argument, (int *)NULL,        0},
71         {"undefined-only",  no_argument, &undefined_only,    1},
72         {"version",         no_argument, &show_version,    1},
73         {0, no_argument, 0, 0}
74 };
75
76 int show_names = 0;
77 \f
78 /* Some error-reporting functions */
79
80 void
81 usage ()
82 {
83   fprintf(stderr, "nm %s\nUsage: %s [-agnoprsuV] filename...\n",
84           program_version, program_name);
85   exit(0);
86 }
87
88 int
89 main (argc, argv)
90      int argc;
91      char **argv;
92 {
93   int c;                        /* sez which option char */
94   int option_index = 0;         /* used by getopt and ignored by us */
95   int retval;
96   program_name = *argv;
97
98   bfd_init();
99
100   while ((c = getopt_long(argc, argv, "agnoprsuV", long_options, &option_index)) != EOF) {
101     switch (c) {
102     case 'a': print_debug_syms = 1; break;
103     case 'g': external_only = 1; break;
104     case 'n': sort_numerically = 1; break;
105     case 'o': file_on_each_line = 1; break;
106     case 'p': no_sort = 1; break;
107     case 'r': reverse_sort = 1; break;
108     case 's': print_armap = 1; break;
109     case 'u': undefined_only = 1; break;
110     case 'V': show_version = 1; break;
111
112     case  0:
113       if (!strcmp("target",(long_options[option_index]).name)) {
114         target = optarg;
115       }
116
117       break;                    /* we've been given a long option */
118
119     default:
120       usage ();
121     }
122   }
123
124   if (show_version)
125         printf ("%s version %s\n", program_name, program_version);
126
127   /* Strangely, for the shell you should return only a nonzero value
128      on sucess -- the inverse of the C sense. */
129
130   /* OK, all options now parsed.  If no filename specified, do a.out. */
131   if (option_index == argc) return !display_file ("a.out");
132
133   retval = 0;
134   show_names = (argc -optind)>1;
135   /* We were given several filenames to do: */
136   while (optind < argc) {
137     if (!display_file (argv[optind++])) {
138       retval++;
139     }
140   }
141
142   return retval;
143 }
144 \f
145 /* Display a file's stats */
146
147 /* goto here is marginally cleaner than the nested if syntax */
148
149 static boolean
150 display_file (filename)
151      char *filename;
152 {
153   boolean retval = true;
154   bfd *file;
155   bfd *arfile = NULL;
156
157   file = bfd_openr(filename, target);
158   if (file == NULL) {
159     fprintf (stderr, "\n%s: can't open '%s'.\n", program_name, filename);
160     return false;
161   }
162
163   if (bfd_check_format(file, bfd_object))
164       {
165         if (show_names) {
166           printf ("\n%s:\n",filename);
167         }
168         do_one_rel_file (file);
169       }
170   else if (bfd_check_format (file, bfd_archive)) {
171     if (!bfd_check_format (file, bfd_archive)) {
172       fprintf (stderr, "%s:  %s: unknown format.\n", program_name, filename);
173       retval = false;
174       goto closer;
175     }
176
177     printf("\n%s:\n", filename);
178     if (print_armap) print_symdef_entry (file);
179     for (;;) {
180       arfile = bfd_openr_next_archived_file (file, arfile);
181
182       if (arfile == NULL) {
183         if (bfd_error != no_more_archived_files)
184           bfd_fatal (filename);
185         goto closer;
186       }
187
188       if (!bfd_check_format(arfile, bfd_object))
189         printf("%s: not an object file\n", arfile->filename);
190       else {
191         printf ("\n%s:\n", arfile->filename);
192         do_one_rel_file (arfile) ;
193       }
194     }
195   }
196   else {
197     fprintf (stderr, "\n%s:  %s: unknown format.\n", program_name, filename);
198     retval = false;
199   }
200
201  closer:
202   if (bfd_close(file) == false)
203     bfd_fatal (filename);
204
205   return retval;
206 }
207 \f
208 /* Symbol-sorting predicates */
209 #define valueof(x) ((x)->section->vma + (x)->value)
210 int
211 numeric_forward (x, y)
212      CONST void *x;
213      CONST void *y;
214 {
215   return (valueof(*(asymbol **)x) - valueof(*(asymbol **) y));
216 }
217
218 int
219 numeric_reverse (x, y)
220      CONST void *x;
221      CONST void *y;
222 {
223   return (valueof(*(asymbol **)y) - valueof(*(asymbol **) x));
224 }
225
226 int
227 non_numeric_forward (x, y)
228      CONST void *x;
229      CONST void *y;
230 {
231   CONST char *xn = (*(asymbol **) x)->name;
232   CONST char *yn = (*(asymbol **) y)->name;
233
234   return ((xn == NULL) ? ((yn == NULL) ? 0 : -1) :
235           ((yn == NULL) ? 1 : strcmp (xn, yn)));
236 }
237
238 int
239 non_numeric_reverse (x, y)
240      CONST void *x;
241      CONST void *y;
242 {
243   return -(non_numeric_forward (x, y));
244 }
245
246 int (*(sorters[2][2])) PARAMS ((CONST void *, CONST void *)) = {
247         {non_numeric_forward, non_numeric_reverse},
248         {numeric_forward, numeric_reverse},
249 };
250 \f
251 static void
252 do_one_rel_file (abfd)
253      bfd *abfd;
254 {
255   unsigned int storage;
256   asymbol **syms;
257   unsigned int symcount = 0;
258
259   if (!(bfd_get_file_flags (abfd) & HAS_SYMS)) {
260     (void) printf ("No symbols in \"%s\".\n", bfd_get_filename (abfd));
261     return;
262   }
263
264   storage = get_symtab_upper_bound (abfd);
265   if (storage == 0) {
266   nosymz:
267     fprintf (stderr, "%s: Symflags set but there are none?\n",
268              bfd_get_filename (abfd));
269     exit (1);
270   }
271
272   syms = (asymbol **) xmalloc (storage);
273
274   symcount = bfd_canonicalize_symtab (abfd, syms);
275   if (symcount == 0) goto nosymz;
276
277   /* Discard the symbols we don't want to print.
278      It's OK to do this in place; we'll free the storage anyway
279      (after printing) */
280
281   symcount = filter_symbols (abfd, syms, symcount);
282
283   if (!no_sort)
284     qsort((char *) syms, symcount, sizeof (asymbol *),
285           sorters[sort_numerically][reverse_sort]);
286
287   if (print_each_filename && !file_on_each_line)
288     printf("\n%s:\n", bfd_get_filename(abfd));
289
290   print_symbols (abfd, syms, symcount);
291   free (syms);
292 }
293 \f
294 /* Choose which symbol entries to print;
295    compact them downward to get rid of the rest.
296    Return the number of symbols to be printed.  */
297 static unsigned int
298 filter_symbols (abfd, syms, symcount)
299      bfd *abfd;
300      asymbol **syms;
301      unsigned long symcount;
302 {
303   asymbol **from, **to;
304   unsigned int dst_count = 0;
305   asymbol *sym;
306
307   unsigned int src_count;
308   for (from = to = syms, src_count = 0; src_count <symcount; src_count++) {
309     int keep = 0;
310
311     flagword flags = (from[src_count])->flags;
312     sym = from[src_count];
313     if (undefined_only) {
314       keep = sym->section == &bfd_und_section;
315     } else if (external_only) {
316       keep = ((flags & BSF_GLOBAL)
317               || (sym->section == &bfd_und_section)
318               ||   (sym->section == &bfd_com_section));
319     } else {
320       keep = 1;
321     }
322
323     if (!print_debug_syms && ((flags & BSF_DEBUGGING) != 0)) {
324       keep = 0;
325     }
326
327     if (keep) {
328       to[dst_count++] = from[src_count];
329     }
330   }
331
332   return dst_count;
333 }
334 \f
335 static void
336 print_symbols (abfd, syms, symcount)
337      bfd *abfd;
338      asymbol **syms;
339      unsigned long symcount;
340 {
341   asymbol **sym = syms, **end = syms + symcount;
342
343   for (; sym < end; ++sym) {
344     if (file_on_each_line) printf("%s:", bfd_get_filename(abfd));
345
346     if (undefined_only) {
347       if ((*sym)->section == &bfd_und_section)
348         puts ((*sym)->name);
349     }
350     else {
351       asymbol *p = *sym;
352       if (p) {
353         bfd_print_symbol(abfd, stdout, p, bfd_print_symbol_nm);
354         putchar('\n');
355       }
356     }
357   }
358 }
359
360 static void
361 print_symdef_entry (abfd)
362      bfd * abfd;
363 {
364   symindex idx = BFD_NO_MORE_SYMBOLS;
365   carsym *thesym;
366   boolean everprinted = false;
367
368   for (idx = bfd_get_next_mapent (abfd, idx, &thesym);
369        idx != BFD_NO_MORE_SYMBOLS;
370        idx = bfd_get_next_mapent (abfd, idx, &thesym)) {
371     bfd *elt;
372     if (!everprinted) {
373       printf ("\nArchive index:\n");
374       everprinted = true;
375     }
376     elt = bfd_get_elt_at_index (abfd, idx);
377     if (thesym->name != (char *)NULL) {
378       printf ("%s in %s\n", thesym->name, bfd_get_filename (elt));
379     }
380   }
381 }