]>
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 | |
31 | do_one_rel_file PARAMS ((bfd *file)); | |
2fa0b342 | 32 | |
249c6fc0 RS |
33 | static unsigned int |
34 | filter_symbols PARAMS ((bfd *file, asymbol **syms, unsigned long symcount)); | |
2fa0b342 | 35 | |
249c6fc0 RS |
36 | static void |
37 | print_symbols PARAMS ((bfd *file, asymbol **syms, unsigned long symcount)); | |
2fa0b342 | 38 | |
249c6fc0 RS |
39 | static void |
40 | print_symdef_entry PARAMS ((bfd * abfd)); | |
2fa0b342 DHW |
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 */ | |
249c6fc0 | 52 | int show_version = 0; /* show the version number */ |
2fa0b342 DHW |
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; | |
249c6fc0 | 60 | extern int print_version; |
2fa0b342 DHW |
61 | |
62 | struct option long_options[] = { | |
96cc09a0 PB |
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}, | |
249c6fc0 | 72 | {"version", no_argument, &show_version, 1}, |
96cc09a0 | 73 | {0, no_argument, 0, 0} |
2fa0b342 | 74 | }; |
7e309104 SC |
75 | |
76 | int show_names = 0; | |
2fa0b342 DHW |
77 | \f |
78 | /* Some error-reporting functions */ | |
79 | ||
80 | void | |
81 | usage () | |
82 | { | |
249c6fc0 | 83 | fprintf(stderr, "nm %s\nUsage: %s [-agnoprsuV] filename...\n", |
2fa0b342 DHW |
84 | program_version, program_name); |
85 | exit(0); | |
86 | } | |
87 | ||
88 | int | |
89 | main (argc, argv) | |
90 | int argc; | |
91 | char **argv; | |
92 | { | |
7e309104 | 93 | int c; /* sez which option char */ |
96cc09a0 | 94 | int option_index = 0; /* used by getopt and ignored by us */ |
249c6fc0 | 95 | int retval; |
2fa0b342 | 96 | program_name = *argv; |
7e309104 SC |
97 | |
98 | bfd_init(); | |
99 | ||
249c6fc0 | 100 | while ((c = getopt_long(argc, argv, "agnoprsuV", long_options, &option_index)) != EOF) { |
2fa0b342 DHW |
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; | |
249c6fc0 RS |
110 | case 'V': show_version = 1; break; |
111 | ||
2fa0b342 DHW |
112 | case 0: |
113 | if (!strcmp("target",(long_options[option_index]).name)) { | |
114 | target = optarg; | |
115 | } | |
249c6fc0 | 116 | |
7e309104 | 117 | break; /* we've been given a long option */ |
249c6fc0 | 118 | |
2fa0b342 DHW |
119 | default: |
120 | usage (); | |
121 | } | |
122 | } | |
249c6fc0 RS |
123 | |
124 | if (show_version) | |
125 | printf ("%s version %s\n", program_name, program_version); | |
126 | ||
2fa0b342 DHW |
127 | /* Strangely, for the shell you should return only a nonzero value |
128 | on sucess -- the inverse of the C sense. */ | |
249c6fc0 | 129 | |
2fa0b342 | 130 | /* OK, all options now parsed. If no filename specified, do a.out. */ |
96cc09a0 | 131 | if (option_index == argc) return !display_file ("a.out"); |
249c6fc0 | 132 | |
7e309104 SC |
133 | retval = 0; |
134 | show_names = (argc -optind)>1; | |
2fa0b342 | 135 | /* We were given several filenames to do: */ |
7e309104 SC |
136 | while (optind < argc) { |
137 | if (!display_file (argv[optind++])) { | |
138 | retval++; | |
139 | } | |
140 | } | |
2fa0b342 | 141 | |
7e309104 | 142 | return retval; |
2fa0b342 DHW |
143 | } |
144 | \f | |
249c6fc0 | 145 | /* Display a file's stats */ |
2fa0b342 DHW |
146 | |
147 | /* goto here is marginally cleaner than the nested if syntax */ | |
148 | ||
149 | static boolean | |
150 | display_file (filename) | |
151 | char *filename; | |
152 | { | |
7e309104 | 153 | boolean retval = true; |
2fa0b342 DHW |
154 | bfd *file; |
155 | bfd *arfile = NULL; | |
249c6fc0 | 156 | |
2fa0b342 DHW |
157 | file = bfd_openr(filename, target); |
158 | if (file == NULL) { | |
7e309104 SC |
159 | fprintf (stderr, "\n%s: can't open '%s'.\n", program_name, filename); |
160 | return false; | |
2fa0b342 DHW |
161 | } |
162 | ||
249c6fc0 | 163 | if (bfd_check_format(file, bfd_object)) |
7e309104 SC |
164 | { |
165 | if (show_names) { | |
166 | printf ("\n%s:\n",filename); | |
167 | } | |
168 | do_one_rel_file (file); | |
7e309104 SC |
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; | |
2fa0b342 DHW |
174 | goto closer; |
175 | } | |
7e309104 SC |
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 | } | |
249c6fc0 | 187 | |
7e309104 SC |
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 | } | |
2fa0b342 DHW |
194 | } |
195 | } | |
7e309104 SC |
196 | else { |
197 | fprintf (stderr, "\n%s: %s: unknown format.\n", program_name, filename); | |
198 | retval = false; | |
199 | } | |
200 | ||
2fa0b342 DHW |
201 | closer: |
202 | if (bfd_close(file) == false) | |
203 | bfd_fatal (filename); | |
204 | ||
205 | return retval; | |
206 | } | |
207 | \f | |
249c6fc0 RS |
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 | } | |
2fa0b342 | 245 | |
249c6fc0 RS |
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 | |
7e309104 | 251 | static void |
2fa0b342 DHW |
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)); | |
7e309104 | 261 | return; |
2fa0b342 DHW |
262 | } |
263 | ||
2fa0b342 DHW |
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); | |
249c6fc0 RS |
282 | |
283 | if (!no_sort) | |
2fa0b342 DHW |
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)); | |
249c6fc0 | 289 | |
2fa0b342 DHW |
290 | print_symbols (abfd, syms, symcount); |
291 | free (syms); | |
2fa0b342 DHW |
292 | } |
293 | \f | |
2fa0b342 DHW |
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; | |
96cc09a0 | 305 | asymbol *sym; |
249c6fc0 | 306 | |
2fa0b342 DHW |
307 | unsigned int src_count; |
308 | for (from = to = syms, src_count = 0; src_count <symcount; src_count++) { | |
309 | int keep = 0; | |
2fa0b342 | 310 | |
96cc09a0 PB |
311 | flagword flags = (from[src_count])->flags; |
312 | sym = from[src_count]; | |
2fa0b342 | 313 | if (undefined_only) { |
96cc09a0 | 314 | keep = sym->section == &bfd_und_section; |
2fa0b342 | 315 | } else if (external_only) { |
249c6fc0 RS |
316 | keep = ((flags & BSF_GLOBAL) |
317 | || (sym->section == &bfd_und_section) | |
96cc09a0 | 318 | || (sym->section == &bfd_com_section)); |
2fa0b342 DHW |
319 | } else { |
320 | keep = 1; | |
321 | } | |
249c6fc0 | 322 | |
2fa0b342 DHW |
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 | } | |
249c6fc0 | 331 | |
2fa0b342 DHW |
332 | return dst_count; |
333 | } | |
334 | \f | |
2fa0b342 DHW |
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; | |
2fa0b342 DHW |
342 | |
343 | for (; sym < end; ++sym) { | |
344 | if (file_on_each_line) printf("%s:", bfd_get_filename(abfd)); | |
345 | ||
346 | if (undefined_only) { | |
96cc09a0 | 347 | if ((*sym)->section == &bfd_und_section) |
2fa0b342 DHW |
348 | puts ((*sym)->name); |
349 | } | |
350 | else { | |
351 | asymbol *p = *sym; | |
352 | if (p) { | |
4aa58a0a SC |
353 | bfd_print_symbol(abfd, stdout, p, bfd_print_symbol_nm); |
354 | putchar('\n'); | |
355 | } | |
2fa0b342 DHW |
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) { | |
249c6fc0 RS |
378 | printf ("%s in %s\n", thesym->name, bfd_get_filename (elt)); |
379 | } | |
2fa0b342 DHW |
380 | } |
381 | } |