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