]> Git Repo - binutils.git/blob - binutils/nm.c
misc fixes
[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, bfd *archive));
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                        bfd *archive));
39
40 static void
41 print_symdef_entry PARAMS ((bfd * abfd));
42
43 /* Command options.  */
44
45 int external_only = 0;  /* print external symbols only */
46 int file_on_each_line = 0; /* print file name on each line */
47 int no_sort = 0;        /* don't sort; print syms in order found */
48 int print_debug_syms = 0; /* print debugger-only symbols too */
49 int print_armap = 0;    /* describe __.SYMDEF data in archive files.  */
50 int reverse_sort = 0;   /* sort in downward(alpha or numeric) order */
51 int sort_numerically = 0; /* sort in numeric rather than alpha order */
52 int undefined_only = 0; /* print undefined symbols only */
53 int show_version = 0;   /* show the version number */
54
55 boolean print_each_filename = false; /* Ick.  Used in archives. */
56
57 /* IMPORT */
58 extern char *program_name;
59 extern char *program_version;
60 extern char *target;
61 extern int print_version;
62
63 struct option long_options[] = {
64         {"debug-syms",      no_argument, &print_debug_syms,  1},
65         {"extern-only",     no_argument, &external_only,     1},
66         {"no-sort",         no_argument, &no_sort,           1},
67         {"numeric-sort",    no_argument, &sort_numerically,  1},
68         {"print-armap",     no_argument, &print_armap,       1},
69         {"print-file-name", no_argument, &file_on_each_line, 1},
70         {"reverse-sort",    no_argument, &reverse_sort,      1},
71         {"target",          optional_argument, 0,            200},
72         {"undefined-only",  no_argument, &undefined_only,    1},
73         {"version",         no_argument, &show_version,      1},
74         {0, no_argument, 0, 0}
75 };
76
77 int show_names = 0;
78 \f
79 /* Some error-reporting functions */
80
81 void
82 usage ()
83 {
84   fprintf(stderr, "nm %s\n\
85 Usage: %s [-agnoprsuV] [--debug-syms] [--extern-only] [--print-armap]\n\
86        [--print-file-name] [--numeric-sort] [--no-sort] [--reverse-sort]\n\
87        [--undefined-only] [--target=bfdname] [file...]\n",
88           program_version, program_name);
89   exit(1);
90 }
91
92 int
93 main (argc, argv)
94      int argc;
95      char **argv;
96 {
97   int c;                        /* sez which option char */
98   int retval;
99   program_name = *argv;
100
101   bfd_init();
102
103   while ((c = getopt_long(argc, argv, "agnoprsuvABV", long_options, (int *) 0)) != EOF) {
104     switch (c) {
105     case 'a': print_debug_syms = 1; break;
106     case 'g': external_only = 1; break;
107     case 'n': sort_numerically = 1; break;
108     case 'o': file_on_each_line = 1; break;
109     case 'p': no_sort = 1; break;
110     case 'r': reverse_sort = 1; break;
111     case 's': print_armap = 1; break;
112     case 'u': undefined_only = 1; break;
113     case 'v':
114     case 'V': show_version = 1; break;
115
116     /* For MIPS compatibility, -A selects System V style output, -B
117        selects BSD style output.  These are not implemented.  When
118        they are, they should be added to usage ().  */
119     case 'A': break;
120     case 'B': break;
121
122     case 200:                   /* --target */
123       target = optarg;
124       break;
125
126     default:
127       usage ();
128     }
129   }
130
131   if (show_version)
132         printf ("%s version %s\n", program_name, program_version);
133
134   /* Strangely, for the shell you should return only a nonzero value
135      on sucess -- the inverse of the C sense. */
136
137   /* OK, all options now parsed.  If no filename specified, do a.out. */
138   if (optind == argc) return !display_file ("a.out");
139
140   retval = 0;
141   show_names = (argc -optind)>1;
142   /* We were given several filenames to do: */
143   while (optind < argc) {
144     if (!display_file (argv[optind++])) {
145       retval++;
146     }
147   }
148
149   return retval;
150 }
151 \f
152 /* Display a file's stats */
153
154 /* goto here is marginally cleaner than the nested if syntax */
155
156 static boolean
157 display_file (filename)
158      char *filename;
159 {
160   boolean retval = true;
161   bfd *file;
162   bfd *arfile = NULL;
163
164   file = bfd_openr(filename, target);
165   if (file == NULL) {
166     fprintf (stderr, "%s: ", program_name);
167     bfd_perror (filename);
168     return false;
169   }
170
171   if (bfd_check_format(file, bfd_object))
172       {
173         if (show_names) {
174           printf ("\n%s:\n",filename);
175         }
176         do_one_rel_file (file, NULL);
177       }
178   else if (bfd_check_format (file, bfd_archive)) {
179     if (!bfd_check_format (file, bfd_archive)) {
180       fprintf (stderr, "%s: %s: unknown format\n", program_name, filename);
181       retval = false;
182       goto closer;
183     }
184
185     if (!file_on_each_line)
186       printf("\n%s:\n", filename);
187     if (print_armap) print_symdef_entry (file);
188     for (;;) {
189       arfile = bfd_openr_next_archived_file (file, arfile);
190
191       if (arfile == NULL) {
192         if (bfd_error != no_more_archived_files)
193           bfd_fatal (filename);
194         goto closer;
195       }
196
197       if (!bfd_check_format(arfile, bfd_object))
198         printf("%s: not an object file\n", arfile->filename);
199       else {
200         if (!file_on_each_line)
201           printf ("\n%s:\n", arfile->filename);
202         do_one_rel_file (arfile, file) ;
203       }
204     }
205   }
206   else {
207     fprintf (stderr, "\n%s: %s: unknown format\n", program_name, filename);
208     retval = false;
209   }
210
211  closer:
212   if (bfd_close(file) == false)
213     bfd_fatal (filename);
214
215   return retval;
216 }
217 \f
218 /* Symbol-sorting predicates */
219 #define valueof(x) ((x)->section->vma + (x)->value)
220 int
221 numeric_forward (x, y)
222      CONST void *x;
223      CONST void *y;
224 {
225   return (valueof(*(asymbol **)x) - valueof(*(asymbol **) y));
226 }
227
228 int
229 numeric_reverse (x, y)
230      CONST void *x;
231      CONST void *y;
232 {
233   return (valueof(*(asymbol **)y) - valueof(*(asymbol **) x));
234 }
235
236 int
237 non_numeric_forward (x, y)
238      CONST void *x;
239      CONST void *y;
240 {
241   CONST char *xn = (*(asymbol **) x)->name;
242   CONST char *yn = (*(asymbol **) y)->name;
243
244   return ((xn == NULL) ? ((yn == NULL) ? 0 : -1) :
245           ((yn == NULL) ? 1 : strcmp (xn, yn)));
246 }
247
248 int
249 non_numeric_reverse (x, y)
250      CONST void *x;
251      CONST void *y;
252 {
253   return -(non_numeric_forward (x, y));
254 }
255
256 int (*(sorters[2][2])) PARAMS ((CONST void *, CONST void *)) = {
257         {non_numeric_forward, non_numeric_reverse},
258         {numeric_forward, numeric_reverse},
259 };
260 \f
261 static void
262 do_one_rel_file (abfd, archive_bfd)
263      bfd *abfd;
264      bfd *archive_bfd; /* If non-NULL: archive containing abfd. */
265 {
266   unsigned int storage;
267   asymbol **syms;
268   unsigned int symcount = 0;
269
270   if (!(bfd_get_file_flags (abfd) & HAS_SYMS)) {
271     (void) printf ("No symbols in \"%s\".\n", bfd_get_filename (abfd));
272     return;
273   }
274
275   storage = get_symtab_upper_bound (abfd);
276   if (storage == 0) {
277   nosymz:
278     fprintf (stderr, "%s: Symflags set but there are none?\n",
279              bfd_get_filename (abfd));
280     return;
281   }
282
283   syms = (asymbol **) xmalloc (storage);
284
285   symcount = bfd_canonicalize_symtab (abfd, syms);
286   if (symcount == 0) goto nosymz;
287
288   /* Discard the symbols we don't want to print.
289      It's OK to do this in place; we'll free the storage anyway
290      (after printing) */
291
292   symcount = filter_symbols (abfd, syms, symcount);
293
294   if (!no_sort)
295     qsort((char *) syms, symcount, sizeof (asymbol *),
296           sorters[sort_numerically][reverse_sort]);
297
298   if (print_each_filename && !file_on_each_line)
299     printf("\n%s:\n", bfd_get_filename(abfd));
300
301   print_symbols (abfd, syms, symcount, archive_bfd);
302   free (syms);
303 }
304 \f
305 /* Choose which symbol entries to print;
306    compact them downward to get rid of the rest.
307    Return the number of symbols to be printed.  */
308 static unsigned int
309 filter_symbols (abfd, syms, symcount)
310      bfd *abfd;
311      asymbol **syms;
312      unsigned long symcount;
313 {
314   asymbol **from, **to;
315   unsigned int dst_count = 0;
316   asymbol *sym;
317
318   unsigned int src_count;
319   for (from = to = syms, src_count = 0; src_count <symcount; src_count++) {
320     int keep = 0;
321
322     flagword flags = (from[src_count])->flags;
323     sym = from[src_count];
324     if (undefined_only) {
325       keep = sym->section == &bfd_und_section;
326     } else if (external_only) {
327       keep = ((flags & BSF_GLOBAL)
328               || (sym->section == &bfd_und_section)
329               || (bfd_is_com_section (sym->section)));
330     } else {
331       keep = 1;
332     }
333
334     if (!print_debug_syms && ((flags & BSF_DEBUGGING) != 0)) {
335       keep = 0;
336     }
337
338     if (keep) {
339       to[dst_count++] = from[src_count];
340     }
341   }
342
343   return dst_count;
344 }
345 \f
346 static void
347 print_symbols (abfd, syms, symcount, archive_bfd)
348      bfd *abfd;
349      asymbol **syms;
350      unsigned long symcount;
351      bfd *archive_bfd;
352 {
353   asymbol **sym = syms, **end = syms + symcount;
354
355   for (; sym < end; ++sym) {
356     if (file_on_each_line) {
357       if (archive_bfd)
358         printf("%s:", bfd_get_filename(archive_bfd));
359       printf("%s:", bfd_get_filename(abfd));
360     }
361
362     if (undefined_only) {
363       if ((*sym)->section == &bfd_und_section)
364         puts ((*sym)->name);
365     }
366     else {
367       asymbol *p = *sym;
368       if (p) {
369         bfd_print_symbol(abfd, stdout, p, bfd_print_symbol_nm);
370         putchar('\n');
371       }
372     }
373   }
374 }
375
376 static void
377 print_symdef_entry (abfd)
378      bfd * abfd;
379 {
380   symindex idx = BFD_NO_MORE_SYMBOLS;
381   carsym *thesym;
382   boolean everprinted = false;
383
384   for (idx = bfd_get_next_mapent (abfd, idx, &thesym);
385        idx != BFD_NO_MORE_SYMBOLS;
386        idx = bfd_get_next_mapent (abfd, idx, &thesym)) {
387     bfd *elt;
388     if (!everprinted) {
389       printf ("\nArchive index:\n");
390       everprinted = true;
391     }
392     elt = bfd_get_elt_at_index (abfd, idx);
393     if (thesym->name != (char *)NULL) {
394       printf ("%s in %s\n", thesym->name, bfd_get_filename (elt));
395     }
396   }
397 }
This page took 0.044999 seconds and 4 git commands to generate.