Commit | Line | Data |
---|---|---|
7e309104 | 1 | /* nm.c -- Describe symbol table of a rel file. |
cef35d48 | 2 | Copyright 1991, 92, 93, 94 Free Software Foundation, Inc. |
7e309104 | 3 | |
cef35d48 | 4 | This file is part of GNU Binutils. |
7e309104 | 5 | |
cef35d48 DM |
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. | |
7e309104 | 10 | |
cef35d48 DM |
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. | |
7e309104 | 15 | |
cef35d48 DM |
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. */ | |
7e309104 | 19 | |
2fa0b342 | 20 | #include "bfd.h" |
7e309104 | 21 | #include "sysdep.h" |
0d84aa0f | 22 | #include "progress.h" |
d20f480f | 23 | #include "bucomm.h" |
2fa0b342 | 24 | #include "getopt.h" |
4aa58a0a | 25 | #include "aout/stab_gnu.h" |
d20f480f | 26 | #include "aout/ranlib.h" |
cef35d48 | 27 | #include "demangle.h" |
0d84aa0f | 28 | #include "libiberty.h" |
2fa0b342 | 29 | |
249c6fc0 RS |
30 | static boolean |
31 | display_file PARAMS ((char *filename)); | |
32 | ||
33 | static void | |
cef35d48 | 34 | display_rel_file PARAMS ((bfd * file, bfd * archive)); |
2fa0b342 | 35 | |
249c6fc0 | 36 | static unsigned int |
cef35d48 | 37 | filter_symbols PARAMS ((bfd * file, asymbol ** syms, unsigned long symcount)); |
2fa0b342 | 38 | |
0d84aa0f ILT |
39 | static unsigned int |
40 | sort_symbols_by_size PARAMS ((bfd *, asymbol **, unsigned long)); | |
41 | ||
249c6fc0 | 42 | static void |
cef35d48 DM |
43 | print_symbols PARAMS ((bfd * file, asymbol ** syms, unsigned long symcount, |
44 | bfd * archive)); | |
2fa0b342 | 45 | |
249c6fc0 RS |
46 | static void |
47 | print_symdef_entry PARAMS ((bfd * abfd)); | |
2fa0b342 | 48 | |
0d84aa0f ILT |
49 | /* The sorting functions. */ |
50 | ||
51 | static int | |
52 | numeric_forward PARAMS ((const PTR, const PTR)); | |
53 | ||
54 | static int | |
55 | numeric_reverse PARAMS ((const PTR, const PTR)); | |
56 | ||
57 | static int | |
58 | non_numeric_forward PARAMS ((const PTR, const PTR)); | |
59 | ||
60 | static int | |
61 | non_numeric_reverse PARAMS ((const PTR, const PTR)); | |
62 | ||
63 | static int | |
64 | size_forward PARAMS ((const PTR, const PTR)); | |
2fa0b342 | 65 | |
cef35d48 DM |
66 | /* The output formatting functions. */ |
67 | ||
68 | static void | |
69 | print_object_filename_bsd PARAMS ((char *filename)); | |
70 | ||
71 | static void | |
72 | print_object_filename_sysv PARAMS ((char *filename)); | |
73 | ||
74 | static void | |
75 | print_object_filename_posix PARAMS ((char *filename)); | |
76 | ||
77 | ||
78 | static void | |
79 | print_archive_filename_bsd PARAMS ((char *filename)); | |
80 | ||
81 | static void | |
82 | print_archive_filename_sysv PARAMS ((char *filename)); | |
83 | ||
84 | static void | |
85 | print_archive_filename_posix PARAMS ((char *filename)); | |
86 | ||
87 | ||
88 | static void | |
89 | print_archive_member_bsd PARAMS ((char *archive, CONST char *filename)); | |
90 | ||
91 | static void | |
92 | print_archive_member_sysv PARAMS ((char *archive, CONST char *filename)); | |
93 | ||
94 | static void | |
95 | print_archive_member_posix PARAMS ((char *archive, CONST char *filename)); | |
96 | ||
97 | ||
98 | static void | |
99 | print_symbol_filename_bsd PARAMS ((bfd * archive_bfd, bfd * abfd)); | |
100 | ||
101 | static void | |
102 | print_symbol_filename_sysv PARAMS ((bfd * archive_bfd, bfd * abfd)); | |
103 | ||
104 | static void | |
105 | print_symbol_filename_posix PARAMS ((bfd * archive_bfd, bfd * abfd)); | |
106 | ||
107 | ||
108 | static void | |
109 | print_symbol_info_bsd PARAMS ((symbol_info * info, bfd * abfd)); | |
110 | ||
111 | static void | |
112 | print_symbol_info_sysv PARAMS ((symbol_info * info, bfd * abfd)); | |
113 | ||
114 | static void | |
115 | print_symbol_info_posix PARAMS ((symbol_info * info, bfd * abfd)); | |
116 | ||
117 | ||
118 | /* Support for different output formats. */ | |
119 | struct output_fns | |
120 | { | |
121 | /* Print the name of an object file given on the command line. */ | |
122 | void (*print_object_filename) PARAMS ((char *filename)); | |
123 | ||
124 | /* Print the name of an archive file given on the command line. */ | |
125 | void (*print_archive_filename) PARAMS ((char *filename)); | |
126 | ||
127 | /* Print the name of an archive member file. */ | |
128 | void (*print_archive_member) PARAMS ((char *archive, CONST char *filename)); | |
2fa0b342 | 129 | |
cef35d48 DM |
130 | /* Print the name of the file (and archive, if there is one) |
131 | containing a symbol. */ | |
132 | void (*print_symbol_filename) PARAMS ((bfd * archive_bfd, bfd * abfd)); | |
133 | ||
134 | /* Print a line of information about a symbol. */ | |
135 | void (*print_symbol_info) PARAMS ((symbol_info * info, bfd * abfd)); | |
136 | }; | |
137 | static struct output_fns formats[] = | |
138 | { | |
139 | {print_object_filename_bsd, | |
140 | print_archive_filename_bsd, | |
141 | print_archive_member_bsd, | |
142 | print_symbol_filename_bsd, | |
143 | print_symbol_info_bsd}, | |
144 | {print_object_filename_sysv, | |
145 | print_archive_filename_sysv, | |
146 | print_archive_member_sysv, | |
147 | print_symbol_filename_sysv, | |
148 | print_symbol_info_sysv}, | |
149 | {print_object_filename_posix, | |
150 | print_archive_filename_posix, | |
151 | print_archive_member_posix, | |
152 | print_symbol_filename_posix, | |
153 | print_symbol_info_posix} | |
154 | }; | |
155 | ||
156 | /* Indices in `formats'. */ | |
157 | #define FORMAT_BSD 0 | |
158 | #define FORMAT_SYSV 1 | |
159 | #define FORMAT_POSIX 2 | |
160 | #define FORMAT_DEFAULT FORMAT_BSD | |
161 | ||
162 | /* The output format to use. */ | |
163 | static struct output_fns *format = &formats[FORMAT_DEFAULT]; | |
164 | ||
165 | ||
166 | /* Command options. */ | |
167 | ||
168 | static int do_demangle = 0; /* Pretty print C++ symbol names. */ | |
169 | static int external_only = 0; /* print external symbols only */ | |
170 | static int no_sort = 0; /* don't sort; print syms in order found */ | |
171 | static int print_debug_syms = 0; /* print debugger-only symbols too */ | |
172 | static int print_armap = 0; /* describe __.SYMDEF data in archive files. */ | |
173 | static int reverse_sort = 0; /* sort in downward(alpha or numeric) order */ | |
174 | static int sort_numerically = 0; /* sort in numeric rather than alpha order */ | |
0d84aa0f | 175 | static int sort_by_size = 0; /* sort by size of symbol */ |
cef35d48 | 176 | static int undefined_only = 0; /* print undefined symbols only */ |
8291be48 | 177 | static int dynamic = 0; /* print dynamic symbols. */ |
cef35d48 DM |
178 | static int show_version = 0; /* show the version number */ |
179 | ||
180 | /* When to print the names of files. Not mutually exclusive in SYSV format. */ | |
181 | static int filename_per_file = 0; /* Once per file, on its own line. */ | |
182 | static int filename_per_symbol = 0; /* Once per symbol, at start of line. */ | |
183 | ||
184 | /* Print formats for printing a symbol value. */ | |
8291be48 | 185 | #ifdef BFD_HOST_64_BIT |
cef35d48 DM |
186 | static char value_format[] = "%08x%08x"; |
187 | #else | |
188 | static char value_format[] = "%08lx"; | |
189 | #endif | |
190 | /* Print formats for printing stab info. */ | |
191 | static char other_format[] = "%02x"; | |
192 | static char desc_format[] = "%04x"; | |
2fa0b342 DHW |
193 | |
194 | /* IMPORT */ | |
195 | extern char *program_name; | |
196 | extern char *program_version; | |
197 | extern char *target; | |
249c6fc0 | 198 | extern int print_version; |
2fa0b342 | 199 | |
cef35d48 DM |
200 | static struct option long_options[] = |
201 | { | |
202 | {"debug-syms", no_argument, &print_debug_syms, 1}, | |
203 | {"demangle", no_argument, &do_demangle, 1}, | |
8291be48 | 204 | {"dynamic", no_argument, &dynamic, 1}, |
cef35d48 DM |
205 | {"extern-only", no_argument, &external_only, 1}, |
206 | {"format", required_argument, 0, 'f'}, | |
207 | {"help", no_argument, 0, 'h'}, | |
9eb39bca ILT |
208 | {"no-cplus", no_argument, &do_demangle, 0}, /* Linux compatibility. */ |
209 | {"no-demangle", no_argument, &do_demangle, 0}, | |
cef35d48 DM |
210 | {"no-sort", no_argument, &no_sort, 1}, |
211 | {"numeric-sort", no_argument, &sort_numerically, 1}, | |
212 | {"portability", no_argument, 0, 'P'}, | |
213 | {"print-armap", no_argument, &print_armap, 1}, | |
214 | {"print-file-name", no_argument, 0, 'o'}, | |
215 | {"radix", required_argument, 0, 't'}, | |
216 | {"reverse-sort", no_argument, &reverse_sort, 1}, | |
0d84aa0f | 217 | {"size-sort", no_argument, &sort_by_size, 1}, |
cef35d48 DM |
218 | {"target", required_argument, 0, 200}, |
219 | {"undefined-only", no_argument, &undefined_only, 1}, | |
220 | {"version", no_argument, &show_version, 1}, | |
221 | {0, no_argument, 0, 0} | |
2fa0b342 DHW |
222 | }; |
223 | \f | |
224 | /* Some error-reporting functions */ | |
225 | ||
226 | void | |
cef35d48 DM |
227 | usage (stream, status) |
228 | FILE *stream; | |
229 | int status; | |
230 | { | |
231 | fprintf (stream, "\ | |
8291be48 | 232 | Usage: %s [-aABCDgnopPrsuvV] [-t radix] [--radix=radix] [--target=bfdname]\n\ |
cef35d48 | 233 | [--debug-syms] [--extern-only] [--print-armap] [--print-file-name]\n\ |
0d84aa0f ILT |
234 | [--numeric-sort] [--no-sort] [--reverse-sort] [--size-sort]\n\ |
235 | [--undefined-only] [--portability] [-f {bsd,sysv,posix}]\n\ | |
236 | [--format={bsd,sysv,posix}] [--demangle] [--no-demangle] [--dynamic]\n\ | |
237 | [--version] [--help]\n\ | |
9eb39bca | 238 | [file...]\n", |
cef35d48 | 239 | program_name); |
0d84aa0f | 240 | list_supported_targets (program_name, stream); |
cef35d48 DM |
241 | exit (status); |
242 | } | |
243 | ||
244 | /* Set the radix for the symbol value and size according to RADIX. */ | |
245 | ||
246 | void | |
247 | set_print_radix (radix) | |
248 | char *radix; | |
249 | { | |
250 | switch (*radix) | |
251 | { | |
252 | case 'd': | |
253 | case 'o': | |
254 | case 'x': | |
8291be48 | 255 | #ifdef BFD_HOST_64_BIT |
cef35d48 DM |
256 | value_format[3] = value_format[7] = *radix; |
257 | #else | |
258 | value_format[4] = *radix; | |
259 | #endif | |
260 | other_format[3] = desc_format[3] = *radix; | |
261 | break; | |
262 | default: | |
263 | fprintf (stderr, "%s: %s: invalid radix\n", program_name, radix); | |
264 | exit (1); | |
265 | } | |
2fa0b342 DHW |
266 | } |
267 | ||
cef35d48 DM |
268 | void |
269 | set_output_format (f) | |
270 | char *f; | |
271 | { | |
272 | int i; | |
273 | ||
274 | switch (*f) | |
275 | { | |
276 | case 'b': | |
277 | case 'B': | |
278 | i = FORMAT_BSD; | |
279 | break; | |
280 | case 'p': | |
281 | case 'P': | |
282 | i = FORMAT_POSIX; | |
283 | break; | |
284 | case 's': | |
285 | case 'S': | |
286 | i = FORMAT_SYSV; | |
287 | break; | |
288 | default: | |
289 | fprintf (stderr, "%s: %s: invalid output format\n", program_name, f); | |
290 | exit (1); | |
291 | } | |
292 | format = &formats[i]; | |
293 | } | |
294 | \f | |
2fa0b342 DHW |
295 | int |
296 | main (argc, argv) | |
297 | int argc; | |
298 | char **argv; | |
299 | { | |
cef35d48 | 300 | int c; |
249c6fc0 | 301 | int retval; |
7e309104 | 302 | |
cef35d48 | 303 | program_name = *argv; |
9f191108 | 304 | xmalloc_set_program_name (program_name); |
249c6fc0 | 305 | |
0d84aa0f ILT |
306 | START_PROGRESS (program_name, 0); |
307 | ||
cef35d48 DM |
308 | bfd_init (); |
309 | ||
8291be48 | 310 | while ((c = getopt_long (argc, argv, "aABCDf:gnopPrst:uvV", long_options, (int *) 0)) != EOF) |
cef35d48 DM |
311 | { |
312 | switch (c) | |
313 | { | |
314 | case 'a': | |
315 | print_debug_syms = 1; | |
316 | break; | |
317 | case 'A': | |
318 | case 'o': | |
319 | filename_per_symbol = 1; | |
320 | break; | |
321 | case 'B': /* For MIPS compatibility. */ | |
322 | set_output_format ("bsd"); | |
323 | break; | |
324 | case 'C': | |
325 | do_demangle = 1; | |
326 | break; | |
8291be48 ILT |
327 | case 'D': |
328 | dynamic = 1; | |
329 | break; | |
cef35d48 DM |
330 | case 'f': |
331 | set_output_format (optarg); | |
332 | break; | |
333 | case 'g': | |
334 | external_only = 1; | |
335 | break; | |
336 | case 'h': | |
337 | usage (stdout, 0); | |
338 | case 'n': | |
339 | case 'v': | |
340 | sort_numerically = 1; | |
341 | break; | |
342 | case 'p': | |
343 | no_sort = 1; | |
344 | break; | |
345 | case 'P': | |
346 | set_output_format ("posix"); | |
347 | break; | |
348 | case 'r': | |
349 | reverse_sort = 1; | |
350 | break; | |
351 | case 's': | |
352 | print_armap = 1; | |
353 | break; | |
354 | case 't': | |
355 | set_print_radix (optarg); | |
356 | break; | |
357 | case 'u': | |
358 | undefined_only = 1; | |
359 | break; | |
360 | case 'V': | |
361 | show_version = 1; | |
362 | break; | |
363 | ||
364 | case 200: /* --target */ | |
365 | target = optarg; | |
366 | break; | |
367 | ||
368 | case 0: /* A long option that just sets a flag. */ | |
369 | break; | |
370 | ||
371 | default: | |
372 | usage (stderr, 1); | |
373 | } | |
2fa0b342 | 374 | } |
249c6fc0 RS |
375 | |
376 | if (show_version) | |
cef35d48 DM |
377 | { |
378 | printf ("GNU %s version %s\n", program_name, program_version); | |
379 | exit (0); | |
380 | } | |
249c6fc0 | 381 | |
cef35d48 DM |
382 | /* OK, all options now parsed. If no filename specified, do a.out. */ |
383 | if (optind == argc) | |
384 | return !display_file ("a.out"); | |
249c6fc0 | 385 | |
7e309104 | 386 | retval = 0; |
cef35d48 DM |
387 | |
388 | if (argc - optind > 1) | |
389 | filename_per_file = 1; | |
390 | ||
391 | /* We were given several filenames to do. */ | |
392 | while (optind < argc) | |
393 | { | |
0d84aa0f | 394 | PROGRESS (1); |
cef35d48 DM |
395 | if (!display_file (argv[optind++])) |
396 | retval++; | |
7e309104 | 397 | } |
2fa0b342 | 398 | |
0d84aa0f ILT |
399 | END_PROGRESS (program_name); |
400 | ||
cef35d48 | 401 | exit (retval); |
7e309104 | 402 | return retval; |
2fa0b342 DHW |
403 | } |
404 | \f | |
cef35d48 DM |
405 | static void |
406 | display_archive (file) | |
407 | bfd *file; | |
408 | { | |
409 | bfd *arfile = NULL; | |
8baf459b | 410 | bfd *last_arfile = NULL; |
6f9dff07 | 411 | char **matching; |
cef35d48 DM |
412 | |
413 | (*format->print_archive_filename) (bfd_get_filename (file)); | |
2fa0b342 | 414 | |
cef35d48 DM |
415 | if (print_armap) |
416 | print_symdef_entry (file); | |
417 | ||
418 | for (;;) | |
419 | { | |
0d84aa0f ILT |
420 | PROGRESS (1); |
421 | ||
cef35d48 DM |
422 | arfile = bfd_openr_next_archived_file (file, arfile); |
423 | ||
424 | if (arfile == NULL) | |
425 | { | |
9f191108 | 426 | if (bfd_get_error () != bfd_error_no_more_archived_files) |
cef35d48 DM |
427 | bfd_fatal (bfd_get_filename (file)); |
428 | break; | |
429 | } | |
430 | ||
6f9dff07 | 431 | if (bfd_check_format_matches (arfile, bfd_object, &matching)) |
cef35d48 DM |
432 | { |
433 | (*format->print_archive_member) (bfd_get_filename (file), | |
434 | bfd_get_filename (arfile)); | |
435 | display_rel_file (arfile, file); | |
436 | } | |
437 | else | |
6f9dff07 DM |
438 | { |
439 | bfd_nonfatal (bfd_get_filename (arfile)); | |
9f191108 | 440 | if (bfd_get_error () == bfd_error_file_ambiguously_recognized) |
6f9dff07 DM |
441 | { |
442 | list_matching_formats (matching); | |
443 | free (matching); | |
444 | } | |
445 | } | |
9f191108 | 446 | |
8baf459b ILT |
447 | if (last_arfile != NULL) |
448 | bfd_close (last_arfile); | |
449 | last_arfile = arfile; | |
cef35d48 | 450 | } |
8baf459b ILT |
451 | |
452 | if (last_arfile != NULL) | |
453 | bfd_close (last_arfile); | |
cef35d48 | 454 | } |
2fa0b342 DHW |
455 | |
456 | static boolean | |
457 | display_file (filename) | |
458 | char *filename; | |
459 | { | |
7e309104 | 460 | boolean retval = true; |
2fa0b342 | 461 | bfd *file; |
cef35d48 | 462 | char **matching; |
249c6fc0 | 463 | |
cef35d48 DM |
464 | file = bfd_openr (filename, target); |
465 | if (file == NULL) | |
466 | { | |
467 | bfd_nonfatal (filename); | |
468 | return false; | |
469 | } | |
470 | ||
471 | if (bfd_check_format (file, bfd_archive)) | |
472 | { | |
473 | display_archive (file); | |
474 | } | |
475 | else if (bfd_check_format_matches (file, bfd_object, &matching)) | |
476 | { | |
477 | (*format->print_object_filename) (filename); | |
478 | display_rel_file (file, NULL); | |
479 | } | |
480 | else | |
481 | { | |
482 | bfd_nonfatal (filename); | |
9f191108 | 483 | if (bfd_get_error () == bfd_error_file_ambiguously_recognized) |
cef35d48 DM |
484 | { |
485 | list_matching_formats (matching); | |
486 | free (matching); | |
7e309104 | 487 | } |
7e309104 | 488 | retval = false; |
2fa0b342 | 489 | } |
7e309104 | 490 | |
cef35d48 | 491 | if (bfd_close (file) == false) |
2fa0b342 DHW |
492 | bfd_fatal (filename); |
493 | ||
494 | return retval; | |
495 | } | |
496 | \f | |
249c6fc0 RS |
497 | /* Symbol-sorting predicates */ |
498 | #define valueof(x) ((x)->section->vma + (x)->value) | |
0d84aa0f ILT |
499 | |
500 | /* Numeric sorts. Undefined symbols are always considered "less than" | |
501 | defined symbols with zero values. Common symbols are not treated | |
502 | specially -- i.e., their sizes are used as their "values". */ | |
503 | static int | |
504 | numeric_forward (P_x, P_y) | |
505 | const PTR P_x; | |
506 | const PTR P_y; | |
249c6fc0 | 507 | { |
0d84aa0f ILT |
508 | asymbol *x = *(asymbol **) P_x; |
509 | asymbol *y = *(asymbol **) P_y; | |
510 | asection *xs = bfd_get_section (x); | |
511 | asection *ys = bfd_get_section (y); | |
512 | if (bfd_is_und_section (xs)) | |
513 | { | |
514 | if (bfd_is_und_section (ys)) | |
515 | goto equal; | |
516 | return -1; | |
517 | } | |
518 | else if (bfd_is_und_section (ys)) | |
519 | return 1; | |
520 | /* Don't just return the difference -- in cross configurations, | |
521 | after truncation to `int' it might not have the sign we want. */ | |
522 | if (valueof (x) != valueof (y)) | |
523 | return valueof (x) < valueof (y) ? -1 : 1; | |
524 | equal: | |
525 | return non_numeric_forward (P_x, P_y); | |
249c6fc0 RS |
526 | } |
527 | ||
0d84aa0f | 528 | static int |
249c6fc0 | 529 | numeric_reverse (x, y) |
0d84aa0f ILT |
530 | const PTR x; |
531 | const PTR y; | |
249c6fc0 | 532 | { |
0d84aa0f | 533 | return -numeric_forward (x, y); |
249c6fc0 RS |
534 | } |
535 | ||
0d84aa0f | 536 | static int |
249c6fc0 | 537 | non_numeric_forward (x, y) |
0d84aa0f ILT |
538 | const PTR x; |
539 | const PTR y; | |
249c6fc0 RS |
540 | { |
541 | CONST char *xn = (*(asymbol **) x)->name; | |
542 | CONST char *yn = (*(asymbol **) y)->name; | |
543 | ||
544 | return ((xn == NULL) ? ((yn == NULL) ? 0 : -1) : | |
545 | ((yn == NULL) ? 1 : strcmp (xn, yn))); | |
546 | } | |
547 | ||
0d84aa0f | 548 | static int |
249c6fc0 | 549 | non_numeric_reverse (x, y) |
0d84aa0f ILT |
550 | const PTR x; |
551 | const PTR y; | |
249c6fc0 | 552 | { |
0d84aa0f | 553 | return -non_numeric_forward (x, y); |
249c6fc0 | 554 | } |
2fa0b342 | 555 | |
0d84aa0f | 556 | static int (*(sorters[2][2])) PARAMS ((const PTR, const PTR)) = |
cef35d48 DM |
557 | { |
558 | { non_numeric_forward, non_numeric_reverse }, | |
559 | { numeric_forward, numeric_reverse } | |
249c6fc0 | 560 | }; |
0d84aa0f ILT |
561 | |
562 | /* This sort routine is used by sort_symbols_by_size. It is similar | |
563 | to numeric_forward, but when symbols have the same value it sorts | |
564 | by section VMA. This simplifies the sort_symbols_by_size code | |
565 | which handles symbols at the end of sections. Also, this routine | |
566 | tries to sort file names before other symbols with the same value. | |
567 | That will make the file name have a zero size, which will make | |
568 | sort_symbols_by_size choose the non file name symbol, leading to | |
569 | more meaningful output. For similar reasons, this code sorts | |
570 | gnu_compiled_* and gcc2_compiled before other symbols with the same | |
571 | value. */ | |
572 | ||
573 | static int | |
574 | size_forward (P_x, P_y) | |
575 | const PTR P_x; | |
576 | const PTR P_y; | |
577 | { | |
578 | asymbol *x = *(asymbol **) P_x; | |
579 | asymbol *y = *(asymbol **) P_y; | |
580 | asection *xs = bfd_get_section (x); | |
581 | asection *ys = bfd_get_section (y); | |
582 | const char *xn; | |
583 | const char *yn; | |
584 | size_t xnl; | |
585 | size_t ynl; | |
586 | int xf; | |
587 | int yf; | |
588 | ||
589 | if (bfd_is_und_section (xs)) | |
590 | abort (); | |
591 | if (bfd_is_und_section (ys)) | |
592 | abort (); | |
593 | ||
594 | if (valueof (x) != valueof (y)) | |
595 | return valueof (x) < valueof (y) ? -1 : 1; | |
596 | ||
597 | if (xs->vma != ys->vma) | |
598 | return xs->vma < ys->vma ? -1 : 1; | |
599 | ||
600 | xn = bfd_asymbol_name (x); | |
601 | yn = bfd_asymbol_name (y); | |
602 | xnl = strlen (xn); | |
603 | ynl = strlen (yn); | |
604 | ||
605 | /* The symbols gnu_compiled and gcc2_compiled convey even less | |
606 | information than the file name, so sort them out first. */ | |
607 | ||
608 | xf = (strstr (xn, "gnu_compiled") != NULL | |
609 | || strstr (xn, "gcc2_compiled") != NULL); | |
610 | yf = (strstr (yn, "gnu_compiled") != NULL | |
611 | || strstr (yn, "gcc2_compiled") != NULL); | |
612 | ||
613 | if (xf && ! yf) | |
614 | return -1; | |
615 | if (! xf && yf) | |
616 | return 1; | |
617 | ||
618 | /* We use a heuristic for the file name. It may not work on non | |
619 | Unix systems, but it doesn't really matter; the only difference | |
620 | is precisely which symbol names get printed. */ | |
621 | ||
622 | #define file_symbol(s, sn, snl) \ | |
623 | ((s->flags & BSF_FILE) != 0 \ | |
624 | || (sn[snl - 2] == '.' \ | |
625 | && (sn[snl - 1] == 'o' \ | |
626 | || sn[snl - 1] == 'a'))) | |
627 | ||
628 | xf = file_symbol (x, xn, xnl); | |
629 | yf = file_symbol (y, yn, ynl); | |
630 | ||
631 | if (xf && ! yf) | |
632 | return -1; | |
633 | if (! xf && yf) | |
634 | return 1; | |
635 | ||
636 | return non_numeric_forward (P_x, P_y); | |
637 | } | |
638 | ||
639 | /* Sort the symbols by size. We guess the size by assuming that the | |
640 | difference between the address of a symbol and the address of the | |
641 | next higher symbol is the size. FIXME: ELF actually stores a size | |
642 | with each symbol. We should use it. */ | |
643 | ||
644 | static unsigned int | |
645 | sort_symbols_by_size (abfd, syms, symcount) | |
646 | bfd *abfd; | |
647 | asymbol **syms; | |
648 | unsigned long symcount; | |
649 | { | |
650 | asymbol **from, **to; | |
651 | unsigned int src_count; | |
652 | unsigned int dst_count = 0; | |
653 | asymbol *sym; | |
654 | asection *sec; | |
655 | ||
656 | qsort ((PTR) syms, symcount, sizeof (asymbol *), size_forward); | |
657 | ||
658 | /* Note that filter_symbols has already removed all absolute and | |
659 | undefined symbols. Here we remove all symbols whose size winds | |
660 | up as zero. */ | |
661 | ||
662 | for (from = to = syms, src_count = 0; src_count < symcount; src_count++) | |
663 | { | |
664 | bfd_vma size; | |
665 | ||
666 | sym = from[src_count]; | |
667 | sec = bfd_get_section (sym); | |
668 | ||
669 | if (bfd_is_com_section (sec)) | |
670 | size = sym->value; | |
671 | else | |
672 | { | |
673 | if (src_count + 1 < symcount | |
674 | && sec == bfd_get_section (from[src_count + 1])) | |
675 | size = valueof (from[src_count + 1]) - valueof (sym); | |
676 | else | |
677 | size = (bfd_get_section_vma (abfd, sec) | |
678 | + bfd_section_size (abfd, sec) | |
679 | - valueof (sym)); | |
680 | } | |
681 | ||
682 | if (size != 0) | |
683 | { | |
684 | /* We adjust the value of the symbol so that when it is | |
685 | printed out, it will actually be the size. */ | |
686 | sym->value = size - bfd_get_section_vma (abfd, sec); | |
687 | ||
688 | to[dst_count++] = sym; | |
689 | } | |
690 | } | |
691 | ||
692 | /* We must now sort again by size. */ | |
693 | qsort ((PTR) syms, dst_count, sizeof (asymbol *), sorters[1][reverse_sort]); | |
694 | ||
695 | return dst_count; | |
696 | } | |
249c6fc0 | 697 | \f |
cef35d48 DM |
698 | /* If ARCHIVE_BFD is non-NULL, it is the archive containing ABFD. */ |
699 | ||
7e309104 | 700 | static void |
cef35d48 | 701 | display_rel_file (abfd, archive_bfd) |
2fa0b342 | 702 | bfd *abfd; |
cef35d48 | 703 | bfd *archive_bfd; |
2fa0b342 | 704 | { |
ae5d2ff5 | 705 | long storage; |
2fa0b342 | 706 | asymbol **syms; |
ae5d2ff5 | 707 | long symcount = 0; |
2fa0b342 | 708 | |
8291be48 | 709 | if (dynamic) |
cef35d48 | 710 | { |
8291be48 ILT |
711 | if (!(bfd_get_file_flags (abfd) & DYNAMIC)) |
712 | { | |
713 | printf ("\"%s\" is not a dynamic object.\n", | |
714 | bfd_get_filename (abfd)); | |
715 | return; | |
716 | } | |
717 | } | |
718 | else | |
719 | { | |
720 | if (!(bfd_get_file_flags (abfd) & HAS_SYMS)) | |
721 | { | |
722 | printf ("No symbols in \"%s\".\n", bfd_get_filename (abfd)); | |
723 | return; | |
724 | } | |
cef35d48 | 725 | } |
2fa0b342 | 726 | |
8291be48 ILT |
727 | if (dynamic) |
728 | storage = bfd_get_dynamic_symtab_upper_bound (abfd); | |
729 | else | |
730 | storage = bfd_get_symtab_upper_bound (abfd); | |
ae5d2ff5 ILT |
731 | if (storage < 0) |
732 | bfd_fatal (bfd_get_filename (abfd)); | |
cef35d48 DM |
733 | if (storage == 0) |
734 | { | |
735 | nosymz: | |
8291be48 ILT |
736 | if (dynamic) |
737 | fprintf (stderr, "%s: no symbols\n", bfd_get_filename (abfd)); | |
738 | else | |
739 | fprintf (stderr, "%s: Symflags set but there are none?\n", | |
740 | bfd_get_filename (abfd)); | |
cef35d48 DM |
741 | return; |
742 | } | |
2fa0b342 DHW |
743 | |
744 | syms = (asymbol **) xmalloc (storage); | |
745 | ||
8291be48 ILT |
746 | if (dynamic) |
747 | symcount = bfd_canonicalize_dynamic_symtab (abfd, syms); | |
748 | else | |
749 | symcount = bfd_canonicalize_symtab (abfd, syms); | |
ae5d2ff5 ILT |
750 | if (symcount < 0) |
751 | bfd_fatal (bfd_get_filename (abfd)); | |
cef35d48 DM |
752 | if (symcount == 0) |
753 | { | |
754 | free (syms); | |
755 | goto nosymz; | |
756 | } | |
2fa0b342 DHW |
757 | |
758 | /* Discard the symbols we don't want to print. | |
759 | It's OK to do this in place; we'll free the storage anyway | |
cef35d48 | 760 | (after printing). */ |
2fa0b342 DHW |
761 | |
762 | symcount = filter_symbols (abfd, syms, symcount); | |
249c6fc0 RS |
763 | |
764 | if (!no_sort) | |
0d84aa0f ILT |
765 | { |
766 | if (! sort_by_size) | |
767 | qsort ((char *) syms, symcount, sizeof (asymbol *), | |
768 | sorters[sort_numerically][reverse_sort]); | |
769 | else | |
770 | symcount = sort_symbols_by_size (abfd, syms, symcount); | |
771 | } | |
249c6fc0 | 772 | |
d2442698 | 773 | print_symbols (abfd, syms, symcount, archive_bfd); |
2fa0b342 | 774 | free (syms); |
2fa0b342 DHW |
775 | } |
776 | \f | |
2fa0b342 DHW |
777 | /* Choose which symbol entries to print; |
778 | compact them downward to get rid of the rest. | |
779 | Return the number of symbols to be printed. */ | |
cef35d48 | 780 | |
2fa0b342 DHW |
781 | static unsigned int |
782 | filter_symbols (abfd, syms, symcount) | |
cef35d48 | 783 | bfd *abfd; /* Unused. */ |
2fa0b342 DHW |
784 | asymbol **syms; |
785 | unsigned long symcount; | |
786 | { | |
787 | asymbol **from, **to; | |
cef35d48 | 788 | unsigned int src_count; |
2fa0b342 | 789 | unsigned int dst_count = 0; |
96cc09a0 | 790 | asymbol *sym; |
249c6fc0 | 791 | |
cef35d48 DM |
792 | for (from = to = syms, src_count = 0; src_count < symcount; src_count++) |
793 | { | |
794 | int keep = 0; | |
795 | flagword flags = (from[src_count])->flags; | |
796 | ||
0d84aa0f ILT |
797 | PROGRESS (1); |
798 | ||
cef35d48 DM |
799 | sym = from[src_count]; |
800 | if (undefined_only) | |
0d84aa0f | 801 | keep = bfd_is_und_section (sym->section); |
cef35d48 DM |
802 | else if (external_only) |
803 | keep = ((flags & BSF_GLOBAL) | |
0d84aa0f ILT |
804 | || bfd_is_und_section (sym->section) |
805 | || bfd_is_com_section (sym->section)); | |
cef35d48 DM |
806 | else |
807 | keep = 1; | |
808 | ||
809 | if (!print_debug_syms && ((flags & BSF_DEBUGGING) != 0)) | |
810 | keep = 0; | |
811 | ||
0d84aa0f ILT |
812 | if (sort_by_size |
813 | && (bfd_is_abs_section (sym->section) | |
814 | || bfd_is_und_section (sym->section))) | |
815 | keep = 0; | |
816 | ||
cef35d48 DM |
817 | if (keep) |
818 | to[dst_count++] = from[src_count]; | |
2fa0b342 | 819 | } |
249c6fc0 | 820 | |
cef35d48 DM |
821 | return dst_count; |
822 | } | |
823 | \f | |
824 | /* Print symbol name NAME, read from ABFD, with printf format FORMAT, | |
825 | demangling it if requested. */ | |
2fa0b342 | 826 | |
cef35d48 DM |
827 | static void |
828 | print_symname (format, name, abfd) | |
829 | char *format, *name; | |
830 | bfd *abfd; | |
831 | { | |
832 | if (do_demangle) | |
833 | { | |
834 | char *res; | |
835 | ||
836 | /* In this mode, give a user-level view of the symbol name | |
837 | even if it's not mangled; strip off any leading | |
838 | underscore. */ | |
839 | if (bfd_get_symbol_leading_char (abfd) == name[0]) | |
840 | name++; | |
841 | ||
842 | res = cplus_demangle (name, DMGL_ANSI | DMGL_PARAMS); | |
843 | if (res) | |
844 | { | |
845 | printf (format, res); | |
846 | free (res); | |
847 | return; | |
848 | } | |
2fa0b342 | 849 | } |
249c6fc0 | 850 | |
cef35d48 | 851 | printf (format, name); |
2fa0b342 | 852 | } |
cef35d48 DM |
853 | |
854 | /* If ARCHIVE_BFD is non-NULL, it is the archive containing ABFD. */ | |
855 | ||
2fa0b342 | 856 | static void |
d2442698 | 857 | print_symbols (abfd, syms, symcount, archive_bfd) |
2fa0b342 DHW |
858 | bfd *abfd; |
859 | asymbol **syms; | |
860 | unsigned long symcount; | |
d2442698 | 861 | bfd *archive_bfd; |
2fa0b342 DHW |
862 | { |
863 | asymbol **sym = syms, **end = syms + symcount; | |
cef35d48 DM |
864 | symbol_info syminfo; |
865 | ||
866 | for (; sym < end; ++sym) | |
867 | { | |
0d84aa0f ILT |
868 | PROGRESS (1); |
869 | ||
cef35d48 DM |
870 | (*format->print_symbol_filename) (archive_bfd, abfd); |
871 | ||
872 | if (undefined_only) | |
873 | { | |
0d84aa0f | 874 | if (bfd_is_und_section ((*sym)->section)) |
cef35d48 DM |
875 | { |
876 | print_symname ("%s\n", (*sym)->name, abfd); | |
877 | } | |
878 | } | |
879 | else | |
880 | { | |
881 | asymbol *p = *sym; | |
882 | if (p) | |
883 | { | |
884 | bfd_get_symbol_info (abfd, p, &syminfo); | |
885 | (*format->print_symbol_info) (&syminfo, abfd); | |
886 | putchar ('\n'); | |
887 | } | |
888 | } | |
889 | } | |
890 | } | |
891 | \f | |
892 | /* The following 3 groups of functions are called unconditionally, | |
893 | once at the start of processing each file of the appropriate type. | |
894 | They should check `filename_per_file' and `filename_per_symbol', | |
895 | as appropriate for their output format, to determine whether to | |
896 | print anything. */ | |
897 | \f | |
898 | /* Print the name of an object file given on the command line. */ | |
899 | ||
900 | static void | |
901 | print_object_filename_bsd (filename) | |
902 | char *filename; | |
903 | { | |
904 | if (filename_per_file && !filename_per_symbol) | |
905 | printf ("\n%s:\n", filename); | |
906 | } | |
907 | ||
908 | static void | |
909 | print_object_filename_sysv (filename) | |
910 | char *filename; | |
911 | { | |
912 | if (undefined_only) | |
913 | printf ("\n\nUndefined symbols from %s:\n\n", filename); | |
914 | else | |
915 | printf ("\n\nSymbols from %s:\n\n", filename); | |
916 | printf ("\ | |
917 | Name Value Class Type Size Line Section\n\n"); | |
918 | } | |
919 | ||
920 | static void | |
921 | print_object_filename_posix (filename) | |
922 | char *filename; | |
923 | { | |
924 | if (filename_per_file && !filename_per_symbol) | |
925 | printf ("%s:\n", filename); | |
926 | } | |
927 | \f | |
928 | /* Print the name of an archive file given on the command line. */ | |
929 | ||
930 | static void | |
931 | print_archive_filename_bsd (filename) | |
932 | char *filename; | |
933 | { | |
934 | if (filename_per_file) | |
935 | printf ("\n%s:\n", filename); | |
936 | } | |
937 | ||
938 | static void | |
939 | print_archive_filename_sysv (filename) | |
940 | char *filename; | |
941 | { | |
942 | } | |
943 | ||
944 | static void | |
945 | print_archive_filename_posix (filename) | |
946 | char *filename; | |
947 | { | |
948 | } | |
949 | \f | |
950 | /* Print the name of an archive member file. */ | |
951 | ||
952 | static void | |
953 | print_archive_member_bsd (archive, filename) | |
954 | char *archive; | |
955 | CONST char *filename; | |
956 | { | |
957 | if (!filename_per_symbol) | |
958 | printf ("\n%s:\n", filename); | |
959 | } | |
960 | ||
961 | static void | |
962 | print_archive_member_sysv (archive, filename) | |
963 | char *archive; | |
964 | CONST char *filename; | |
965 | { | |
966 | if (undefined_only) | |
967 | printf ("\n\nUndefined symbols from %s[%s]:\n\n", archive, filename); | |
968 | else | |
969 | printf ("\n\nSymbols from %s[%s]:\n\n", archive, filename); | |
970 | printf ("\ | |
971 | Name Value Class Type Size Line Section\n\n"); | |
972 | } | |
973 | ||
974 | static void | |
975 | print_archive_member_posix (archive, filename) | |
976 | char *archive; | |
977 | CONST char *filename; | |
978 | { | |
979 | if (!filename_per_symbol) | |
980 | printf ("%s[%s]:\n", archive, filename); | |
981 | } | |
982 | \f | |
983 | /* Print the name of the file (and archive, if there is one) | |
984 | containing a symbol. */ | |
985 | ||
986 | static void | |
987 | print_symbol_filename_bsd (archive_bfd, abfd) | |
988 | bfd *archive_bfd, *abfd; | |
989 | { | |
990 | if (filename_per_symbol) | |
991 | { | |
992 | if (archive_bfd) | |
993 | printf ("%s:", bfd_get_filename (archive_bfd)); | |
994 | printf ("%s:", bfd_get_filename (abfd)); | |
995 | } | |
996 | } | |
997 | ||
998 | static void | |
999 | print_symbol_filename_sysv (archive_bfd, abfd) | |
1000 | bfd *archive_bfd, *abfd; | |
1001 | { | |
1002 | if (filename_per_symbol) | |
1003 | { | |
1004 | if (archive_bfd) | |
1005 | printf ("%s:", bfd_get_filename (archive_bfd)); | |
1006 | printf ("%s:", bfd_get_filename (abfd)); | |
1007 | } | |
1008 | } | |
2fa0b342 | 1009 | |
cef35d48 DM |
1010 | static void |
1011 | print_symbol_filename_posix (archive_bfd, abfd) | |
1012 | bfd *archive_bfd, *abfd; | |
1013 | { | |
1014 | if (filename_per_symbol) | |
1015 | { | |
d2442698 | 1016 | if (archive_bfd) |
cef35d48 DM |
1017 | printf ("%s[%s]: ", bfd_get_filename (archive_bfd), |
1018 | bfd_get_filename (abfd)); | |
1019 | else | |
1020 | printf ("%s: ", bfd_get_filename (abfd)); | |
d2442698 | 1021 | } |
cef35d48 DM |
1022 | } |
1023 | \f | |
1024 | /* Print a line of information about a symbol. */ | |
1025 | ||
1026 | static void | |
1027 | print_symbol_info_bsd (info, abfd) | |
1028 | symbol_info *info; | |
1029 | bfd *abfd; | |
1030 | { | |
1031 | if (info->type == 'U') | |
0d84aa0f ILT |
1032 | { |
1033 | printf ("%*s", | |
1034 | #ifdef BFD_HOST_64_BIT | |
1035 | 16, | |
1036 | #else | |
1037 | 8, | |
1038 | #endif | |
1039 | ""); | |
1040 | } | |
cef35d48 DM |
1041 | else |
1042 | { | |
8291be48 | 1043 | #ifdef BFD_HOST_64_BIT |
cef35d48 DM |
1044 | printf (value_format, uint64_typeHIGH (info->value), |
1045 | uint64_typeLOW (info->value)); | |
1046 | #else | |
1047 | printf (value_format, info->value); | |
1048 | #endif | |
1049 | } | |
1050 | printf (" %c", info->type); | |
1051 | if (info->type == '-') | |
1052 | { | |
1053 | /* A stab. */ | |
1054 | printf (" "); | |
1055 | printf (other_format, info->stab_other); | |
1056 | printf (" "); | |
1057 | printf (desc_format, info->stab_desc); | |
1058 | printf (" %5s", info->stab_name); | |
1059 | } | |
1060 | print_symname (" %s", info->name, abfd); | |
1061 | } | |
2fa0b342 | 1062 | |
cef35d48 DM |
1063 | static void |
1064 | print_symbol_info_sysv (info, abfd) | |
1065 | symbol_info *info; | |
1066 | bfd *abfd; | |
1067 | { | |
1068 | print_symname ("%-20s|", info->name, abfd); /* Name */ | |
1069 | if (info->type == 'U') | |
1070 | printf (" "); /* Value */ | |
1071 | else | |
1072 | { | |
8291be48 | 1073 | #ifdef BFD_HOST_64_BIT |
cef35d48 DM |
1074 | printf (value_format, uint64_typeHIGH (info->value), |
1075 | uint64_typeLOW (info->value)); | |
1076 | #else | |
1077 | printf (value_format, info->value); | |
1078 | #endif | |
2fa0b342 | 1079 | } |
cef35d48 DM |
1080 | printf ("| %c |", info->type); /* Class */ |
1081 | if (info->type == '-') | |
1082 | { | |
1083 | /* A stab. */ | |
1084 | printf ("%18s| ", info->stab_name); /* (C) Type */ | |
1085 | printf (desc_format, info->stab_desc); /* Size */ | |
1086 | printf ("| |"); /* Line, Section */ | |
2fa0b342 | 1087 | } |
cef35d48 DM |
1088 | else |
1089 | printf (" | | |"); /* Type, Size, Line, Section */ | |
2fa0b342 DHW |
1090 | } |
1091 | ||
cef35d48 DM |
1092 | static void |
1093 | print_symbol_info_posix (info, abfd) | |
1094 | symbol_info *info; | |
1095 | bfd *abfd; | |
1096 | { | |
1097 | print_symname ("%s ", info->name, abfd); | |
1098 | printf ("%c ", info->type); | |
1099 | if (info->type == 'U') | |
1100 | printf (" "); | |
1101 | else | |
1102 | { | |
8291be48 | 1103 | #ifdef BFD_HOST_64_BIT |
cef35d48 DM |
1104 | printf (value_format, uint64_typeHIGH (info->value), |
1105 | uint64_typeLOW (info->value)); | |
1106 | #else | |
1107 | printf (value_format, info->value); | |
1108 | #endif | |
1109 | } | |
1110 | /* POSIX.2 wants the symbol size printed here, when applicable; | |
1111 | BFD currently doesn't provide it, so we take the easy way out by | |
1112 | considering it to never be applicable. */ | |
1113 | } | |
1114 | \f | |
2fa0b342 DHW |
1115 | static void |
1116 | print_symdef_entry (abfd) | |
cef35d48 | 1117 | bfd *abfd; |
2fa0b342 DHW |
1118 | { |
1119 | symindex idx = BFD_NO_MORE_SYMBOLS; | |
1120 | carsym *thesym; | |
1121 | boolean everprinted = false; | |
1122 | ||
1123 | for (idx = bfd_get_next_mapent (abfd, idx, &thesym); | |
1124 | idx != BFD_NO_MORE_SYMBOLS; | |
cef35d48 DM |
1125 | idx = bfd_get_next_mapent (abfd, idx, &thesym)) |
1126 | { | |
1127 | bfd *elt; | |
1128 | if (!everprinted) | |
1129 | { | |
1130 | printf ("\nArchive index:\n"); | |
1131 | everprinted = true; | |
1132 | } | |
1133 | elt = bfd_get_elt_at_index (abfd, idx); | |
1134 | if (thesym->name != (char *) NULL) | |
1135 | { | |
0d84aa0f ILT |
1136 | print_symname ("%s", thesym->name, abfd); |
1137 | printf (" in %s\n", bfd_get_filename (elt)); | |
cef35d48 | 1138 | } |
249c6fc0 | 1139 | } |
2fa0b342 | 1140 | } |