bfd/
[deliverable/binutils-gdb.git] / binutils / size.c
CommitLineData
252b5132 1/* size.c -- report size of various sections of an executable file.
aef6203b 2 Copyright 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
14a91970
AM
3 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
4 Free Software Foundation, Inc.
252b5132 5
15c82623 6 This file is part of GNU Binutils.
252b5132 7
15c82623
NC
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
32866df7 10 the Free Software Foundation; either version 3 of the License, or
15c82623 11 (at your option) any later version.
252b5132 12
15c82623
NC
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
252b5132 17
15c82623
NC
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
32866df7
NC
20 Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
21 MA 02110-1301, USA. */
252b5132
RH
22\f
23/* Extensions/incompatibilities:
24 o - BSD output has filenames at the end.
25 o - BSD output can appear in different radicies.
26 o - SysV output has less redundant whitespace. Filename comes at end.
27 o - SysV output doesn't show VMA which is always the same as the PMA.
28 o - We also handle core files.
29 o - We also handle archives.
30 If you write shell scripts which manipulate this info then you may be
15c82623 31 out of luck; there's no --compatibility or --pedantic option. */
252b5132 32
3db64b00 33#include "sysdep.h"
252b5132 34#include "bfd.h"
252b5132 35#include "libiberty.h"
d7a283d4 36#include "getopt.h"
3db64b00 37#include "bucomm.h"
252b5132
RH
38
39#ifndef BSD_DEFAULT
40#define BSD_DEFAULT 1
41#endif
42
43/* Program options. */
44
29422971 45static enum
252b5132
RH
46 {
47 decimal, octal, hex
15c82623
NC
48 }
49radix = decimal;
50
85b1c36d
BE
51/* 0 means use AT&T-style output. */
52static int berkeley_format = BSD_DEFAULT;
53
29422971
AM
54static int show_version = 0;
55static int show_help = 0;
56static int show_totals = 0;
57static int show_common = 0;
15c82623 58
29422971 59static bfd_size_type common_size;
15c82623
NC
60static bfd_size_type total_bsssize;
61static bfd_size_type total_datasize;
62static bfd_size_type total_textsize;
252b5132
RH
63
64/* Program exit status. */
29422971 65static int return_code = 0;
252b5132
RH
66
67static char *target = NULL;
68
29422971 69/* Forward declarations. */
252b5132 70
2da42df6 71static void display_file (char *);
2da42df6 72static void rprint_number (int, bfd_size_type);
2da42df6 73static void print_sizes (bfd * file);
252b5132
RH
74\f
75static void
2da42df6 76usage (FILE *stream, int status)
252b5132 77{
8b53311e
NC
78 fprintf (stream, _("Usage: %s [option(s)] [file(s)]\n"), program_name);
79 fprintf (stream, _(" Displays the sizes of sections inside binary files\n"));
9f66665a 80 fprintf (stream, _(" If no input file(s) are specified, a.out is assumed\n"));
8b53311e
NC
81 fprintf (stream, _(" The options are:\n\
82 -A|-B --format={sysv|berkeley} Select output style (default is %s)\n\
92acdfaf 83 -o|-d|-x --radix={8|10|16} Display numbers in octal, decimal or hex\n\
15c82623 84 -t --totals Display the total sizes (Berkeley only)\n\
29422971 85 --common Display total size for *COM* syms\n\
8b53311e 86 --target=<bfdname> Set the binary file format\n\
07012eee 87 @<file> Read options from <file>\n\
8b53311e
NC
88 -h --help Display this information\n\
89 -v --version Display the program's version\n\
90\n"),
252b5132 91#if BSD_DEFAULT
8b53311e 92 "berkeley"
252b5132 93#else
8b53311e 94 "sysv"
252b5132 95#endif
8b53311e 96);
252b5132 97 list_supported_targets (program_name, stream);
92f01d61 98 if (REPORT_BUGS_TO[0] && status == 0)
8ad3436c 99 fprintf (stream, _("Report bugs to %s\n"), REPORT_BUGS_TO);
252b5132
RH
100 exit (status);
101}
102
29422971
AM
103#define OPTION_FORMAT (200)
104#define OPTION_RADIX (OPTION_FORMAT + 1)
105#define OPTION_TARGET (OPTION_RADIX + 1)
106
85b1c36d 107static struct option long_options[] =
252b5132 108{
29422971
AM
109 {"common", no_argument, &show_common, 1},
110 {"format", required_argument, 0, OPTION_FORMAT},
111 {"radix", required_argument, 0, OPTION_RADIX},
112 {"target", required_argument, 0, OPTION_TARGET},
15c82623 113 {"totals", no_argument, &show_totals, 1},
252b5132
RH
114 {"version", no_argument, &show_version, 1},
115 {"help", no_argument, &show_help, 1},
116 {0, no_argument, 0, 0}
117};
118
2da42df6 119int main (int, char **);
65de42c0 120
252b5132 121int
2da42df6 122main (int argc, char **argv)
252b5132
RH
123{
124 int temp;
125 int c;
126
127#if defined (HAVE_SETLOCALE) && defined (HAVE_LC_MESSAGES)
128 setlocale (LC_MESSAGES, "");
3882b010
L
129#endif
130#if defined (HAVE_SETLOCALE)
131 setlocale (LC_CTYPE, "");
252b5132
RH
132#endif
133 bindtextdomain (PACKAGE, LOCALEDIR);
134 textdomain (PACKAGE);
135
136 program_name = *argv;
137 xmalloc_set_program_name (program_name);
138
869b9d07
MM
139 expandargv (&argc, &argv);
140
252b5132
RH
141 bfd_init ();
142 set_default_bfd_target ();
143
15c82623 144 while ((c = getopt_long (argc, argv, "ABHhVvdfotx", long_options,
252b5132
RH
145 (int *) 0)) != EOF)
146 switch (c)
147 {
29422971 148 case OPTION_FORMAT:
252b5132
RH
149 switch (*optarg)
150 {
151 case 'B':
152 case 'b':
153 berkeley_format = 1;
154 break;
155 case 'S':
156 case 's':
157 berkeley_format = 0;
158 break;
159 default:
37cc8ec1 160 non_fatal (_("invalid argument to --format: %s"), optarg);
252b5132
RH
161 usage (stderr, 1);
162 }
163 break;
164
29422971 165 case OPTION_TARGET:
252b5132
RH
166 target = optarg;
167 break;
168
29422971 169 case OPTION_RADIX:
252b5132
RH
170#ifdef ANSI_LIBRARIES
171 temp = strtol (optarg, NULL, 10);
172#else
173 temp = atol (optarg);
174#endif
175 switch (temp)
176 {
177 case 10:
178 radix = decimal;
179 break;
180 case 8:
181 radix = octal;
182 break;
183 case 16:
184 radix = hex;
185 break;
186 default:
37cc8ec1 187 non_fatal (_("Invalid radix: %s\n"), optarg);
252b5132
RH
188 usage (stderr, 1);
189 }
190 break;
191
192 case 'A':
193 berkeley_format = 0;
194 break;
195 case 'B':
196 berkeley_format = 1;
197 break;
8b53311e 198 case 'v':
252b5132
RH
199 case 'V':
200 show_version = 1;
201 break;
202 case 'd':
203 radix = decimal;
204 break;
205 case 'x':
206 radix = hex;
207 break;
208 case 'o':
209 radix = octal;
210 break;
15c82623
NC
211 case 't':
212 show_totals = 1;
213 break;
e3a69612
AM
214 case 'f': /* FIXME : For sysv68, `-f' means `full format', i.e.
215 `[fname:] M(.text) + N(.data) + O(.bss) + P(.comment) = Q'
216 where `fname: ' appears only if there are >= 2 input files,
217 and M, N, O, P, Q are expressed in decimal by default,
218 hexa or octal if requested by `-x' or `-o'.
219 Just to make things interesting, Solaris also accepts -f,
220 which prints out the size of each allocatable section, the
221 name of the section, and the total of the section sizes. */
222 /* For the moment, accept `-f' silently, and ignore it. */
223 break;
252b5132
RH
224 case 0:
225 break;
8b53311e
NC
226 case 'h':
227 case 'H':
252b5132
RH
228 case '?':
229 usage (stderr, 1);
230 }
231
232 if (show_version)
233 print_version ("size");
234 if (show_help)
235 usage (stdout, 0);
236
237 if (optind == argc)
238 display_file ("a.out");
239 else
240 for (; optind < argc;)
241 display_file (argv[optind++]);
242
15c82623
NC
243 if (show_totals && berkeley_format)
244 {
245 bfd_size_type total = total_textsize + total_datasize + total_bsssize;
246
247 rprint_number (7, total_textsize);
248 putchar('\t');
249 rprint_number (7, total_datasize);
250 putchar('\t');
251 rprint_number (7, total_bsssize);
252 printf (((radix == octal) ? "\t%7lo\t%7lx\t" : "\t%7lu\t%7lx\t"),
253 (unsigned long) total, (unsigned long) total);
254 fputs ("(TOTALS)\n", stdout);
255 }
256
252b5132
RH
257 return return_code;
258}
259\f
29422971
AM
260/* Total size required for common symbols in ABFD. */
261
262static void
263calculate_common_size (bfd *abfd)
264{
265 asymbol **syms = NULL;
266 long storage, symcount;
267
268 common_size = 0;
269 if ((bfd_get_file_flags (abfd) & (EXEC_P | DYNAMIC | HAS_SYMS)) != HAS_SYMS)
270 return;
271
272 storage = bfd_get_symtab_upper_bound (abfd);
273 if (storage < 0)
274 bfd_fatal (bfd_get_filename (abfd));
275 if (storage)
276 syms = xmalloc (storage);
277
278 symcount = bfd_canonicalize_symtab (abfd, syms);
279 if (symcount < 0)
280 bfd_fatal (bfd_get_filename (abfd));
281
282 while (--symcount >= 0)
283 {
284 asymbol *sym = syms[symcount];
285
286 if (bfd_is_com_section (sym->section)
287 && (sym->flags & BSF_SECTION_SYM) == 0)
288 common_size += sym->value;
289 }
290 free (syms);
291}
292
252b5132
RH
293/* Display stats on file or archive member ABFD. */
294
295static void
2da42df6 296display_bfd (bfd *abfd)
252b5132
RH
297{
298 char **matching;
299
300 if (bfd_check_format (abfd, bfd_archive))
301 /* An archive within an archive. */
302 return;
303
304 if (bfd_check_format_matches (abfd, bfd_object, &matching))
305 {
306 print_sizes (abfd);
307 printf ("\n");
308 return;
309 }
310
311 if (bfd_get_error () == bfd_error_file_ambiguously_recognized)
312 {
313 bfd_nonfatal (bfd_get_filename (abfd));
314 list_matching_formats (matching);
315 free (matching);
316 return_code = 3;
317 return;
318 }
319
320 if (bfd_check_format_matches (abfd, bfd_core, &matching))
321 {
15c82623 322 const char *core_cmd;
252b5132
RH
323
324 print_sizes (abfd);
325 fputs (" (core file", stdout);
326
327 core_cmd = bfd_core_file_failing_command (abfd);
328 if (core_cmd)
329 printf (" invoked as %s", core_cmd);
330
331 puts (")\n");
332 return;
333 }
334
335 bfd_nonfatal (bfd_get_filename (abfd));
336
337 if (bfd_get_error () == bfd_error_file_ambiguously_recognized)
338 {
339 list_matching_formats (matching);
340 free (matching);
341 }
342
343 return_code = 3;
344}
345
346static void
2da42df6 347display_archive (bfd *file)
252b5132
RH
348{
349 bfd *arfile = (bfd *) NULL;
6b52b824 350 bfd *last_arfile = (bfd *) NULL;
252b5132
RH
351
352 for (;;)
353 {
354 bfd_set_error (bfd_error_no_error);
355
356 arfile = bfd_openr_next_archived_file (file, arfile);
357 if (arfile == NULL)
358 {
359 if (bfd_get_error () != bfd_error_no_more_archived_files)
360 {
361 bfd_nonfatal (bfd_get_filename (file));
362 return_code = 2;
363 }
364 break;
365 }
366
367 display_bfd (arfile);
6b52b824
AM
368
369 if (last_arfile != NULL)
370 bfd_close (last_arfile);
371 last_arfile = arfile;
252b5132 372 }
6b52b824
AM
373
374 if (last_arfile != NULL)
375 bfd_close (last_arfile);
252b5132
RH
376}
377
378static void
2da42df6 379display_file (char *filename)
252b5132 380{
f24ddbdd 381 bfd *file;
15c82623 382
f24ddbdd 383 if (get_file_size (filename) < 1)
d68c385b
NC
384 {
385 return_code = 1;
386 return;
387 }
f24ddbdd
NC
388
389 file = bfd_openr (filename, target);
252b5132
RH
390 if (file == NULL)
391 {
392 bfd_nonfatal (filename);
393 return_code = 1;
394 return;
395 }
396
b34976b6 397 if (bfd_check_format (file, bfd_archive))
252b5132
RH
398 display_archive (file);
399 else
400 display_bfd (file);
401
b34976b6 402 if (!bfd_close (file))
252b5132
RH
403 {
404 bfd_nonfatal (filename);
405 return_code = 1;
406 return;
407 }
408}
409\f
252b5132 410static int
2da42df6 411size_number (bfd_size_type num)
252b5132
RH
412{
413 char buffer[40];
15c82623 414
252b5132 415 sprintf (buffer,
14a91970
AM
416 (radix == decimal ? "%" BFD_VMA_FMT "u" :
417 ((radix == octal) ? "0%" BFD_VMA_FMT "o" : "0x%" BFD_VMA_FMT "x")),
418 num);
252b5132
RH
419
420 return strlen (buffer);
421}
422
252b5132 423static void
2da42df6 424rprint_number (int width, bfd_size_type num)
252b5132
RH
425{
426 char buffer[40];
15c82623 427
252b5132 428 sprintf (buffer,
14a91970
AM
429 (radix == decimal ? "%" BFD_VMA_FMT "u" :
430 ((radix == octal) ? "0%" BFD_VMA_FMT "o" : "0x%" BFD_VMA_FMT "x")),
431 num);
252b5132
RH
432
433 printf ("%*s", width, buffer);
434}
435
436static bfd_size_type bsssize;
437static bfd_size_type datasize;
438static bfd_size_type textsize;
439
440static void
2da42df6
AJ
441berkeley_sum (bfd *abfd ATTRIBUTE_UNUSED, sec_ptr sec,
442 void *ignore ATTRIBUTE_UNUSED)
252b5132
RH
443{
444 flagword flags;
445 bfd_size_type size;
446
447 flags = bfd_get_section_flags (abfd, sec);
448 if ((flags & SEC_ALLOC) == 0)
449 return;
450
135dfb4a 451 size = bfd_get_section_size (sec);
252b5132
RH
452 if ((flags & SEC_CODE) != 0 || (flags & SEC_READONLY) != 0)
453 textsize += size;
454 else if ((flags & SEC_HAS_CONTENTS) != 0)
455 datasize += size;
456 else
457 bsssize += size;
458}
459
9f66665a 460static void
2da42df6 461print_berkeley_format (bfd *abfd)
252b5132
RH
462{
463 static int files_seen = 0;
464 bfd_size_type total;
465
466 bsssize = 0;
467 datasize = 0;
468 textsize = 0;
469
2da42df6 470 bfd_map_over_sections (abfd, berkeley_sum, NULL);
252b5132 471
29422971 472 bsssize += common_size;
252b5132 473 if (files_seen++ == 0)
252b5132
RH
474 puts ((radix == octal) ? " text\t data\t bss\t oct\t hex\tfilename" :
475 " text\t data\t bss\t dec\t hex\tfilename");
252b5132
RH
476
477 total = textsize + datasize + bsssize;
478
15c82623
NC
479 if (show_totals)
480 {
481 total_textsize += textsize;
482 total_datasize += datasize;
483 total_bsssize += bsssize;
484 }
485
252b5132
RH
486 rprint_number (7, textsize);
487 putchar ('\t');
488 rprint_number (7, datasize);
489 putchar ('\t');
490 rprint_number (7, bsssize);
491 printf (((radix == octal) ? "\t%7lo\t%7lx\t" : "\t%7lu\t%7lx\t"),
492 (unsigned long) total, (unsigned long) total);
493
494 fputs (bfd_get_filename (abfd), stdout);
15c82623 495
252b5132
RH
496 if (bfd_my_archive (abfd))
497 printf (" (ex %s)", bfd_get_filename (bfd_my_archive (abfd)));
498}
499
500/* I REALLY miss lexical functions! */
501bfd_size_type svi_total = 0;
502bfd_vma svi_maxvma = 0;
503int svi_namelen = 0;
504int svi_vmalen = 0;
505int svi_sizelen = 0;
506
507static void
2da42df6
AJ
508sysv_internal_sizer (bfd *file ATTRIBUTE_UNUSED, sec_ptr sec,
509 void *ignore ATTRIBUTE_UNUSED)
252b5132
RH
510{
511 bfd_size_type size = bfd_section_size (file, sec);
15c82623
NC
512
513 if ( ! bfd_is_abs_section (sec)
514 && ! bfd_is_com_section (sec)
515 && ! bfd_is_und_section (sec))
252b5132
RH
516 {
517 int namelen = strlen (bfd_section_name (file, sec));
15c82623 518
252b5132
RH
519 if (namelen > svi_namelen)
520 svi_namelen = namelen;
521
522 svi_total += size;
15c82623 523
252b5132
RH
524 if (bfd_section_vma (file, sec) > svi_maxvma)
525 svi_maxvma = bfd_section_vma (file, sec);
526 }
527}
528
29422971
AM
529static void
530sysv_one_line (const char *name, bfd_size_type size, bfd_vma vma)
531{
532 printf ("%-*s ", svi_namelen, name);
533 rprint_number (svi_sizelen, size);
534 printf (" ");
535 rprint_number (svi_vmalen, vma);
536 printf ("\n");
537}
538
252b5132 539static void
2da42df6
AJ
540sysv_internal_printer (bfd *file ATTRIBUTE_UNUSED, sec_ptr sec,
541 void *ignore ATTRIBUTE_UNUSED)
252b5132
RH
542{
543 bfd_size_type size = bfd_section_size (file, sec);
15c82623
NC
544
545 if ( ! bfd_is_abs_section (sec)
546 && ! bfd_is_com_section (sec)
547 && ! bfd_is_und_section (sec))
252b5132
RH
548 {
549 svi_total += size;
550
29422971
AM
551 sysv_one_line (bfd_section_name (file, sec),
552 size,
553 bfd_section_vma (file, sec));
252b5132
RH
554 }
555}
556
557static void
2da42df6 558print_sysv_format (bfd *file)
252b5132 559{
15c82623 560 /* Size all of the columns. */
252b5132
RH
561 svi_total = 0;
562 svi_maxvma = 0;
563 svi_namelen = 0;
2da42df6 564 bfd_map_over_sections (file, sysv_internal_sizer, NULL);
29422971
AM
565 if (show_common)
566 {
567 if (svi_namelen < (int) sizeof ("*COM*") - 1)
568 svi_namelen = sizeof ("*COM*") - 1;
569 svi_total += common_size;
570 }
571
252b5132 572 svi_vmalen = size_number ((bfd_size_type)svi_maxvma);
15c82623 573
252b5132
RH
574 if ((size_t) svi_vmalen < sizeof ("addr") - 1)
575 svi_vmalen = sizeof ("addr")-1;
576
577 svi_sizelen = size_number (svi_total);
578 if ((size_t) svi_sizelen < sizeof ("size") - 1)
579 svi_sizelen = sizeof ("size")-1;
580
581 svi_total = 0;
582 printf ("%s ", bfd_get_filename (file));
15c82623 583
252b5132
RH
584 if (bfd_my_archive (file))
585 printf (" (ex %s)", bfd_get_filename (bfd_my_archive (file)));
586
587 printf (":\n%-*s %*s %*s\n", svi_namelen, "section",
588 svi_sizelen, "size", svi_vmalen, "addr");
15c82623 589
2da42df6 590 bfd_map_over_sections (file, sysv_internal_printer, NULL);
29422971
AM
591 if (show_common)
592 {
593 svi_total += common_size;
594 sysv_one_line ("*COM*", common_size, 0);
595 }
252b5132
RH
596
597 printf ("%-*s ", svi_namelen, "Total");
598 rprint_number (svi_sizelen, svi_total);
599 printf ("\n\n");
600}
601
602static void
2da42df6 603print_sizes (bfd *file)
252b5132 604{
29422971
AM
605 if (show_common)
606 calculate_common_size (file);
252b5132
RH
607 if (berkeley_format)
608 print_berkeley_format (file);
609 else
610 print_sysv_format (file);
611}
This page took 0.392139 seconds and 4 git commands to generate.