* Makefile.in: Let's call it version 2.0.
[deliverable/binutils-gdb.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 }
This page took 0.037615 seconds and 4 git commands to generate.