]>
Commit | Line | Data |
---|---|---|
770cde30 | 1 | /* size.c -- report size of various sections of an executable file. |
cef35d48 | 2 | Copyright 1991, 92, 93, 94 Free Software Foundation, Inc. |
770cde30 JG |
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. */ | |
cef35d48 | 19 | \f |
2fa0b342 DHW |
20 | /* Extensions/incompatibilities: |
21 | o - BSD output has filenames at the end. | |
22 | o - BSD output can appear in different radicies. | |
23 | o - SysV output has less redundant whitespace. Filename comes at end. | |
24 | o - SysV output doesn't show VMA which is always the same as the PMA. | |
25 | o - We also handle core files. | |
26 | o - We also handle archives. | |
27 | If you write shell scripts which manipulate this info then you may be | |
cef35d48 | 28 | out of luck; there's no --compatibility or --pedantic option. |
2fa0b342 | 29 | */ |
770cde30 | 30 | |
2fa0b342 | 31 | #include "bfd.h" |
770cde30 | 32 | #include "sysdep.h" |
2fa0b342 | 33 | #include "getopt.h" |
cef35d48 | 34 | #include "bucomm.h" |
2fa0b342 | 35 | |
2fa0b342 DHW |
36 | #ifndef BSD_DEFAULT |
37 | #define BSD_DEFAULT 1 | |
38 | #endif | |
39 | ||
cef35d48 | 40 | /* Program options. */ |
2fa0b342 | 41 | |
cef35d48 DM |
42 | enum |
43 | { | |
44 | decimal, octal, hex | |
45 | } radix = decimal; | |
46 | int berkeley_format = BSD_DEFAULT; /* 0 means use AT&T-style output. */ | |
2fa0b342 DHW |
47 | int show_version = 0; |
48 | int show_help = 0; | |
49 | ||
cef35d48 | 50 | /* Program exit status. */ |
770cde30 JG |
51 | int return_code = 0; |
52 | ||
2fa0b342 DHW |
53 | /* IMPORTS */ |
54 | extern char *program_version; | |
2fa0b342 | 55 | extern char *target; |
e2fe2df4 PB |
56 | |
57 | /* Forward declarations */ | |
58 | ||
cef35d48 | 59 | static void display_file PARAMS ((char *filename)); |
e2fe2df4 | 60 | |
cef35d48 | 61 | static void print_sizes PARAMS ((bfd * file)); |
2fa0b342 | 62 | |
cef35d48 DM |
63 | static void berkeley_sum PARAMS ((bfd *, sec_ptr, PTR)); |
64 | \f | |
2fa0b342 | 65 | void |
cef35d48 DM |
66 | usage (stream, status) |
67 | FILE *stream; | |
68 | int status; | |
2fa0b342 | 69 | { |
cef35d48 | 70 | fprintf (stream, "\ |
d2442698 | 71 | Usage: %s [-ABdoxV] [--format=berkeley|sysv] [--radix=8|10|16]\n\ |
cef35d48 | 72 | [--target=bfdname] [--version] [--help] [file...]\n", program_name); |
2fa0b342 | 73 | #if BSD_DEFAULT |
cef35d48 | 74 | fputs ("default is --format=berkeley\n", stream); |
2fa0b342 | 75 | #else |
cef35d48 | 76 | fputs ("default is --format=sysv\n", stream); |
2fa0b342 | 77 | #endif |
cef35d48 | 78 | exit (status); |
2fa0b342 DHW |
79 | } |
80 | ||
cef35d48 DM |
81 | struct option long_options[] = |
82 | { | |
83 | {"format", required_argument, 0, 200}, | |
84 | {"radix", required_argument, 0, 201}, | |
85 | {"target", required_argument, 0, 202}, | |
d2442698 | 86 | {"version", no_argument, &show_version, 1}, |
cef35d48 | 87 | {"help", no_argument, &show_help, 1}, |
d2442698 DM |
88 | {0, no_argument, 0, 0} |
89 | }; | |
2fa0b342 DHW |
90 | |
91 | int | |
92 | main (argc, argv) | |
93 | int argc; | |
94 | char **argv; | |
95 | { | |
96 | int temp; | |
cef35d48 | 97 | int c; |
d2442698 | 98 | |
2fa0b342 DHW |
99 | program_name = *argv; |
100 | ||
cef35d48 DM |
101 | bfd_init (); |
102 | ||
103 | while ((c = getopt_long (argc, argv, "ABVdox", long_options, | |
104 | (int *) 0)) != EOF) | |
105 | switch (c) | |
106 | { | |
107 | case 200: /* --format */ | |
108 | switch (*optarg) | |
109 | { | |
110 | case 'B': | |
111 | case 'b': | |
112 | berkeley_format = 1; | |
113 | break; | |
114 | case 'S': | |
115 | case 's': | |
116 | berkeley_format = 0; | |
117 | break; | |
118 | default: | |
119 | fprintf (stderr, "invalid argument to --format: %s\n", optarg); | |
120 | usage (stderr, 1); | |
121 | } | |
2fa0b342 | 122 | break; |
2fa0b342 | 123 | |
cef35d48 | 124 | case 202: /* --target */ |
2fa0b342 DHW |
125 | target = optarg; |
126 | break; | |
2fa0b342 | 127 | |
cef35d48 | 128 | case 201: /* --radix */ |
2fa0b342 | 129 | #ifdef ANSI_LIBRARIES |
cef35d48 | 130 | temp = strtol (optarg, NULL, 10); |
2fa0b342 | 131 | #else |
cef35d48 | 132 | temp = atol (optarg); |
2fa0b342 | 133 | #endif |
cef35d48 DM |
134 | switch (temp) |
135 | { | |
136 | case 10: | |
137 | radix = decimal; | |
138 | break; | |
139 | case 8: | |
140 | radix = octal; | |
141 | break; | |
142 | case 16: | |
143 | radix = hex; | |
144 | break; | |
145 | default: | |
146 | printf ("Invalid radix: %s\n", optarg); | |
147 | usage (stderr, 1); | |
148 | } | |
d2442698 DM |
149 | break; |
150 | ||
cef35d48 DM |
151 | case 'A': |
152 | berkeley_format = 0; | |
153 | break; | |
154 | case 'B': | |
155 | berkeley_format = 1; | |
156 | break; | |
157 | case 'V': | |
158 | show_version = 1; | |
159 | break; | |
160 | case 'd': | |
161 | radix = decimal; | |
162 | break; | |
163 | case 'x': | |
164 | radix = hex; | |
165 | break; | |
166 | case 'o': | |
167 | radix = octal; | |
168 | break; | |
169 | case 0: | |
170 | break; | |
171 | case '?': | |
172 | usage (stderr, 1); | |
173 | } | |
174 | ||
175 | if (show_version) | |
176 | { | |
177 | printf ("GNU %s version %s\n", program_name, program_version); | |
178 | exit (0); | |
2fa0b342 | 179 | } |
cef35d48 DM |
180 | if (show_help) |
181 | usage (stdout, 0); | |
2fa0b342 | 182 | |
2fa0b342 DHW |
183 | if (optind == argc) |
184 | display_file ("a.out"); | |
185 | else | |
186 | for (; optind < argc;) | |
187 | display_file (argv[optind++]); | |
188 | ||
770cde30 | 189 | return return_code; |
2fa0b342 DHW |
190 | } |
191 | \f | |
cef35d48 | 192 | /* Display stats on file or archive member ABFD. */ |
2fa0b342 DHW |
193 | |
194 | void | |
195 | display_bfd (abfd) | |
196 | bfd *abfd; | |
197 | { | |
cef35d48 | 198 | char **matching; |
2fa0b342 | 199 | |
cef35d48 DM |
200 | if (bfd_check_format (abfd, bfd_archive)) |
201 | /* An archive within an archive. */ | |
202 | return; | |
2fa0b342 | 203 | |
cef35d48 DM |
204 | if (bfd_check_format_matches (abfd, bfd_object, &matching)) |
205 | { | |
206 | print_sizes (abfd); | |
207 | printf ("\n"); | |
208 | return; | |
209 | } | |
2fa0b342 | 210 | |
cef35d48 DM |
211 | if (bfd_error == file_ambiguously_recognized) |
212 | { | |
213 | bfd_nonfatal (bfd_get_filename (abfd)); | |
214 | list_matching_formats (matching); | |
215 | free (matching); | |
216 | return_code = 3; | |
217 | return; | |
218 | } | |
2fa0b342 | 219 | |
cef35d48 DM |
220 | if (bfd_check_format_matches (abfd, bfd_core, &matching)) |
221 | { | |
222 | CONST char *core_cmd; | |
2fa0b342 | 223 | |
cef35d48 DM |
224 | print_sizes (abfd); |
225 | fputs (" (core file", stdout); | |
2fa0b342 | 226 | |
cef35d48 DM |
227 | core_cmd = bfd_core_file_failing_command (abfd); |
228 | if (core_cmd) | |
229 | printf (" invoked as %s", core_cmd); | |
2fa0b342 | 230 | |
cef35d48 DM |
231 | puts (")\n"); |
232 | return; | |
233 | } | |
234 | ||
235 | bfd_nonfatal (bfd_get_filename (abfd)); | |
236 | ||
237 | if (bfd_error == file_ambiguously_recognized) | |
238 | { | |
239 | list_matching_formats (matching); | |
240 | free (matching); | |
241 | } | |
2fa0b342 | 242 | |
cef35d48 | 243 | return_code = 3; |
2fa0b342 DHW |
244 | } |
245 | ||
e2fe2df4 | 246 | static void |
cef35d48 DM |
247 | display_archive (file) |
248 | bfd *file; | |
2fa0b342 | 249 | { |
cef35d48 | 250 | bfd *arfile = (bfd *) NULL; |
2fa0b342 | 251 | |
cef35d48 DM |
252 | for (;;) |
253 | { | |
2fa0b342 DHW |
254 | bfd_error = no_error; |
255 | ||
cef35d48 DM |
256 | arfile = bfd_openr_next_archived_file (file, arfile); |
257 | if (arfile == NULL) | |
258 | { | |
259 | if (bfd_error != no_more_archived_files) | |
260 | { | |
261 | bfd_nonfatal (bfd_get_filename (file)); | |
262 | return_code = 2; | |
263 | } | |
264 | break; | |
265 | } | |
2fa0b342 DHW |
266 | |
267 | display_bfd (arfile); | |
268 | /* Don't close the archive elements; we need them for next_archive */ | |
269 | } | |
cef35d48 DM |
270 | } |
271 | ||
272 | static void | |
273 | display_file (filename) | |
274 | char *filename; | |
275 | { | |
276 | bfd *file = bfd_openr (filename, target); | |
277 | if (file == NULL) | |
278 | { | |
279 | bfd_nonfatal (filename); | |
280 | return_code = 1; | |
281 | return; | |
282 | } | |
283 | ||
284 | if (bfd_check_format (file, bfd_archive) == true) | |
285 | display_archive (file); | |
2fa0b342 DHW |
286 | else |
287 | display_bfd (file); | |
288 | ||
cef35d48 DM |
289 | if (bfd_close (file) == false) |
290 | { | |
291 | bfd_nonfatal (filename); | |
292 | return_code = 1; | |
293 | return; | |
294 | } | |
2fa0b342 DHW |
295 | } |
296 | \f | |
cef35d48 DM |
297 | /* This is what lexical functions are for. */ |
298 | ||
2fa0b342 DHW |
299 | void |
300 | lprint_number (width, num) | |
e2fe2df4 PB |
301 | int width; |
302 | bfd_size_type num; | |
2fa0b342 | 303 | { |
d2442698 DM |
304 | printf ((radix == decimal ? "%-*lu\t" : |
305 | ((radix == octal) ? "%-*lo\t" : "%-*lx\t")), | |
cef35d48 | 306 | width, (unsigned long) num); |
2fa0b342 DHW |
307 | } |
308 | ||
309 | void | |
cef35d48 | 310 | rprint_number (width, num) |
e2fe2df4 PB |
311 | int width; |
312 | bfd_size_type num; | |
2fa0b342 | 313 | { |
d2442698 DM |
314 | printf ((radix == decimal ? "%*lu\t" : |
315 | ((radix == octal) ? "%*lo\t" : "%*lx\t")), | |
cef35d48 | 316 | width, (unsigned long) num); |
2fa0b342 DHW |
317 | } |
318 | ||
cef35d48 DM |
319 | static bfd_size_type bsssize; |
320 | static bfd_size_type datasize; | |
321 | static bfd_size_type textsize; | |
2fa0b342 | 322 | |
cef35d48 DM |
323 | static void |
324 | berkeley_sum (abfd, sec, ignore) | |
325 | bfd *abfd; | |
326 | sec_ptr sec; | |
327 | PTR ignore; | |
328 | { | |
329 | bfd_size_type size; | |
330 | ||
331 | size = bfd_get_section_size_before_reloc (sec); | |
332 | if (bfd_get_section_flags (abfd, sec) & SEC_CODE) | |
333 | textsize += size; | |
334 | else if (bfd_get_section_flags (abfd, sec) & SEC_DATA) | |
335 | datasize += size; | |
336 | else if (bfd_get_section_flags (abfd, sec) & SEC_ALLOC) | |
337 | bsssize += size; | |
338 | } | |
339 | ||
340 | void | |
341 | print_berkeley_format (abfd) | |
342 | bfd *abfd; | |
2fa0b342 | 343 | { |
770cde30 | 344 | static int files_seen = 0; |
cef35d48 DM |
345 | bfd_size_type total; |
346 | ||
347 | bsssize = 0; | |
348 | datasize = 0; | |
349 | textsize = 0; | |
350 | ||
351 | bfd_map_over_sections (abfd, berkeley_sum, (PTR) NULL); | |
770cde30 JG |
352 | |
353 | if (files_seen++ == 0) | |
cef35d48 DM |
354 | #if 0 |
355 | /* Intel doesn't like bss/stk because they don't have core files. */ | |
356 | puts ((radix == octal) ? "text\tdata\tbss/stk\toct\thex\tfilename" : | |
357 | "text\tdata\tbss/stk\tdec\thex\tfilename"); | |
770cde30 | 358 | #else |
cef35d48 DM |
359 | puts ((radix == octal) ? "text\tdata\tbss\toct\thex\tfilename" : |
360 | "text\tdata\tbss\tdec\thex\tfilename"); | |
770cde30 | 361 | #endif |
cef35d48 | 362 | |
2fa0b342 | 363 | total = textsize + datasize + bsssize; |
cef35d48 | 364 | |
2fa0b342 DHW |
365 | lprint_number (7, textsize); |
366 | lprint_number (7, datasize); | |
367 | lprint_number (7, bsssize); | |
d2442698 | 368 | printf (((radix == octal) ? "%-7lo\t%-7lx\t" : "%-7lu\t%-7lx\t"), |
cef35d48 | 369 | (unsigned long) total, (unsigned long) total); |
2fa0b342 | 370 | |
cef35d48 | 371 | fputs (bfd_get_filename (abfd), stdout); |
0c5dc23c DM |
372 | if (bfd_my_archive (abfd)) |
373 | printf (" (ex %s)", bfd_get_filename (bfd_my_archive (abfd))); | |
2fa0b342 DHW |
374 | } |
375 | ||
376 | /* I REALLY miss lexical functions! */ | |
e2fe2df4 | 377 | bfd_size_type svi_total = 0; |
2fa0b342 DHW |
378 | |
379 | void | |
cef35d48 | 380 | sysv_internal_printer (file, sec, ignore) |
2fa0b342 DHW |
381 | bfd *file; |
382 | sec_ptr sec; | |
770cde30 | 383 | PTR ignore; |
2fa0b342 | 384 | { |
e2fe2df4 | 385 | bfd_size_type size = bfd_section_size (file, sec); |
cef35d48 DM |
386 | if (sec != &bfd_abs_section |
387 | && !bfd_is_com_section (sec) | |
388 | && sec != &bfd_und_section) | |
389 | { | |
390 | svi_total += size; | |
391 | ||
392 | printf ("%-12s", bfd_section_name (file, sec)); | |
393 | rprint_number (8, size); | |
394 | printf (" "); | |
395 | rprint_number (8, bfd_section_vma (file, sec)); | |
396 | printf ("\n"); | |
397 | } | |
2fa0b342 DHW |
398 | } |
399 | ||
400 | void | |
cef35d48 | 401 | print_sysv_format (file) |
2fa0b342 DHW |
402 | bfd *file; |
403 | { | |
404 | svi_total = 0; | |
405 | ||
406 | printf ("%s ", bfd_get_filename (file)); | |
6f9dff07 DM |
407 | if (bfd_my_archive (file)) |
408 | printf (" (ex %s)", bfd_get_filename (bfd_my_archive (file))); | |
2fa0b342 | 409 | |
cef35d48 DM |
410 | puts (":\nsection\t\tsize\t addr"); |
411 | bfd_map_over_sections (file, sysv_internal_printer, (PTR) NULL); | |
2fa0b342 | 412 | |
cef35d48 DM |
413 | printf ("Total "); |
414 | rprint_number (8, svi_total); | |
415 | printf ("\n\n"); | |
2fa0b342 DHW |
416 | } |
417 | ||
e2fe2df4 | 418 | static void |
cef35d48 | 419 | print_sizes (file) |
2fa0b342 DHW |
420 | bfd *file; |
421 | { | |
422 | if (berkeley_format) | |
cef35d48 DM |
423 | print_berkeley_format (file); |
424 | else | |
425 | print_sysv_format (file); | |
2fa0b342 | 426 | } |