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