]>
Commit | Line | Data |
---|---|---|
7e309104 | 1 | /* nm.c -- Describe symbol table of a rel file. |
249c6fc0 | 2 | Copyright 1991, 1992 Free Software Foundation, Inc. |
7e309104 SC |
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 | ||
2fa0b342 | 20 | #include "bfd.h" |
7e309104 | 21 | #include "sysdep.h" |
d20f480f | 22 | #include "bucomm.h" |
2fa0b342 | 23 | #include "getopt.h" |
4aa58a0a | 24 | #include "aout/stab_gnu.h" |
d20f480f | 25 | #include "aout/ranlib.h" |
2fa0b342 | 26 | |
249c6fc0 RS |
27 | static boolean |
28 | display_file PARAMS ((char *filename)); | |
29 | ||
30 | static void | |
d2442698 | 31 | do_one_rel_file PARAMS ((bfd* file, bfd *archive)); |
2fa0b342 | 32 | |
249c6fc0 RS |
33 | static unsigned int |
34 | filter_symbols PARAMS ((bfd *file, asymbol **syms, unsigned long symcount)); | |
2fa0b342 | 35 | |
249c6fc0 | 36 | static void |
d2442698 DM |
37 | print_symbols PARAMS ((bfd *file, asymbol **syms, unsigned long symcount, |
38 | bfd *archive)); | |
2fa0b342 | 39 | |
249c6fc0 RS |
40 | static void |
41 | print_symdef_entry PARAMS ((bfd * abfd)); | |
2fa0b342 DHW |
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 */ | |
249c6fc0 | 53 | int show_version = 0; /* show the version number */ |
2fa0b342 DHW |
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; | |
249c6fc0 | 61 | extern int print_version; |
2fa0b342 DHW |
62 | |
63 | struct option long_options[] = { | |
96cc09a0 PB |
64 | {"debug-syms", no_argument, &print_debug_syms, 1}, |
65 | {"extern-only", no_argument, &external_only, 1}, | |
d2442698 | 66 | {"no-sort", no_argument, &no_sort, 1}, |
96cc09a0 PB |
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}, | |
d2442698 | 71 | {"target", optional_argument, 0, 200}, |
96cc09a0 | 72 | {"undefined-only", no_argument, &undefined_only, 1}, |
d2442698 | 73 | {"version", no_argument, &show_version, 1}, |
96cc09a0 | 74 | {0, no_argument, 0, 0} |
2fa0b342 | 75 | }; |
7e309104 SC |
76 | |
77 | int show_names = 0; | |
2fa0b342 DHW |
78 | \f |
79 | /* Some error-reporting functions */ | |
80 | ||
81 | void | |
82 | usage () | |
83 | { | |
d2442698 DM |
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", | |
2fa0b342 | 88 | program_version, program_name); |
d2442698 | 89 | exit(1); |
2fa0b342 DHW |
90 | } |
91 | ||
92 | int | |
93 | main (argc, argv) | |
94 | int argc; | |
95 | char **argv; | |
96 | { | |
7e309104 | 97 | int c; /* sez which option char */ |
249c6fc0 | 98 | int retval; |
2fa0b342 | 99 | program_name = *argv; |
7e309104 SC |
100 | |
101 | bfd_init(); | |
102 | ||
d2442698 | 103 | while ((c = getopt_long(argc, argv, "agnoprsuvABV", long_options, (int *) 0)) != EOF) { |
2fa0b342 DHW |
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; | |
d2442698 | 113 | case 'v': |
249c6fc0 RS |
114 | case 'V': show_version = 1; break; |
115 | ||
d2442698 DM |
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; | |
249c6fc0 | 121 | |
d2442698 DM |
122 | case 200: /* --target */ |
123 | target = optarg; | |
124 | break; | |
249c6fc0 | 125 | |
2fa0b342 DHW |
126 | default: |
127 | usage (); | |
128 | } | |
129 | } | |
249c6fc0 RS |
130 | |
131 | if (show_version) | |
132 | printf ("%s version %s\n", program_name, program_version); | |
133 | ||
2fa0b342 DHW |
134 | /* Strangely, for the shell you should return only a nonzero value |
135 | on sucess -- the inverse of the C sense. */ | |
249c6fc0 | 136 | |
2fa0b342 | 137 | /* OK, all options now parsed. If no filename specified, do a.out. */ |
d2442698 | 138 | if (optind == argc) return !display_file ("a.out"); |
249c6fc0 | 139 | |
7e309104 SC |
140 | retval = 0; |
141 | show_names = (argc -optind)>1; | |
2fa0b342 | 142 | /* We were given several filenames to do: */ |
7e309104 SC |
143 | while (optind < argc) { |
144 | if (!display_file (argv[optind++])) { | |
145 | retval++; | |
146 | } | |
147 | } | |
2fa0b342 | 148 | |
7e309104 | 149 | return retval; |
2fa0b342 DHW |
150 | } |
151 | \f | |
249c6fc0 | 152 | /* Display a file's stats */ |
2fa0b342 DHW |
153 | |
154 | /* goto here is marginally cleaner than the nested if syntax */ | |
155 | ||
156 | static boolean | |
157 | display_file (filename) | |
158 | char *filename; | |
159 | { | |
7e309104 | 160 | boolean retval = true; |
2fa0b342 DHW |
161 | bfd *file; |
162 | bfd *arfile = NULL; | |
249c6fc0 | 163 | |
2fa0b342 DHW |
164 | file = bfd_openr(filename, target); |
165 | if (file == NULL) { | |
d2442698 DM |
166 | fprintf (stderr, "%s: ", program_name); |
167 | bfd_perror (filename); | |
7e309104 | 168 | return false; |
2fa0b342 DHW |
169 | } |
170 | ||
249c6fc0 | 171 | if (bfd_check_format(file, bfd_object)) |
7e309104 SC |
172 | { |
173 | if (show_names) { | |
174 | printf ("\n%s:\n",filename); | |
175 | } | |
d2442698 | 176 | do_one_rel_file (file, NULL); |
7e309104 SC |
177 | } |
178 | else if (bfd_check_format (file, bfd_archive)) { | |
179 | if (!bfd_check_format (file, bfd_archive)) { | |
d2442698 | 180 | fprintf (stderr, "%s: %s: unknown format\n", program_name, filename); |
7e309104 | 181 | retval = false; |
2fa0b342 DHW |
182 | goto closer; |
183 | } | |
7e309104 | 184 | |
d2442698 DM |
185 | if (!file_on_each_line) |
186 | printf("\n%s:\n", filename); | |
7e309104 SC |
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 | } | |
249c6fc0 | 196 | |
7e309104 SC |
197 | if (!bfd_check_format(arfile, bfd_object)) |
198 | printf("%s: not an object file\n", arfile->filename); | |
199 | else { | |
d2442698 DM |
200 | if (!file_on_each_line) |
201 | printf ("\n%s:\n", arfile->filename); | |
202 | do_one_rel_file (arfile, file) ; | |
7e309104 | 203 | } |
2fa0b342 DHW |
204 | } |
205 | } | |
7e309104 | 206 | else { |
d2442698 | 207 | fprintf (stderr, "\n%s: %s: unknown format\n", program_name, filename); |
7e309104 SC |
208 | retval = false; |
209 | } | |
210 | ||
2fa0b342 DHW |
211 | closer: |
212 | if (bfd_close(file) == false) | |
213 | bfd_fatal (filename); | |
214 | ||
215 | return retval; | |
216 | } | |
217 | \f | |
249c6fc0 RS |
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 | } | |
2fa0b342 | 255 | |
249c6fc0 RS |
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 | |
7e309104 | 261 | static void |
d2442698 | 262 | do_one_rel_file (abfd, archive_bfd) |
2fa0b342 | 263 | bfd *abfd; |
d2442698 | 264 | bfd *archive_bfd; /* If non-NULL: archive containing abfd. */ |
2fa0b342 DHW |
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)); | |
7e309104 | 272 | return; |
2fa0b342 DHW |
273 | } |
274 | ||
2fa0b342 DHW |
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)); | |
d2442698 | 280 | return; |
2fa0b342 DHW |
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); | |
249c6fc0 RS |
293 | |
294 | if (!no_sort) | |
2fa0b342 DHW |
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)); | |
249c6fc0 | 300 | |
d2442698 | 301 | print_symbols (abfd, syms, symcount, archive_bfd); |
2fa0b342 | 302 | free (syms); |
2fa0b342 DHW |
303 | } |
304 | \f | |
2fa0b342 DHW |
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; | |
96cc09a0 | 316 | asymbol *sym; |
249c6fc0 | 317 | |
2fa0b342 DHW |
318 | unsigned int src_count; |
319 | for (from = to = syms, src_count = 0; src_count <symcount; src_count++) { | |
320 | int keep = 0; | |
2fa0b342 | 321 | |
96cc09a0 PB |
322 | flagword flags = (from[src_count])->flags; |
323 | sym = from[src_count]; | |
2fa0b342 | 324 | if (undefined_only) { |
96cc09a0 | 325 | keep = sym->section == &bfd_und_section; |
2fa0b342 | 326 | } else if (external_only) { |
249c6fc0 RS |
327 | keep = ((flags & BSF_GLOBAL) |
328 | || (sym->section == &bfd_und_section) | |
d2442698 | 329 | || (bfd_is_com_section (sym->section))); |
2fa0b342 DHW |
330 | } else { |
331 | keep = 1; | |
332 | } | |
249c6fc0 | 333 | |
2fa0b342 DHW |
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 | } | |
249c6fc0 | 342 | |
2fa0b342 DHW |
343 | return dst_count; |
344 | } | |
345 | \f | |
2fa0b342 | 346 | static void |
d2442698 | 347 | print_symbols (abfd, syms, symcount, archive_bfd) |
2fa0b342 DHW |
348 | bfd *abfd; |
349 | asymbol **syms; | |
350 | unsigned long symcount; | |
d2442698 | 351 | bfd *archive_bfd; |
2fa0b342 DHW |
352 | { |
353 | asymbol **sym = syms, **end = syms + symcount; | |
2fa0b342 DHW |
354 | |
355 | for (; sym < end; ++sym) { | |
d2442698 DM |
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 | } | |
2fa0b342 DHW |
361 | |
362 | if (undefined_only) { | |
96cc09a0 | 363 | if ((*sym)->section == &bfd_und_section) |
2fa0b342 DHW |
364 | puts ((*sym)->name); |
365 | } | |
366 | else { | |
367 | asymbol *p = *sym; | |
368 | if (p) { | |
4aa58a0a SC |
369 | bfd_print_symbol(abfd, stdout, p, bfd_print_symbol_nm); |
370 | putchar('\n'); | |
371 | } | |
2fa0b342 DHW |
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) { | |
249c6fc0 RS |
394 | printf ("%s in %s\n", thesym->name, bfd_get_filename (elt)); |
395 | } | |
2fa0b342 DHW |
396 | } |
397 | } |