Add new --common option to size.
[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,
92f01d61 3 2001, 2002, 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
252b5132 4
15c82623 5 This file is part of GNU Binutils.
252b5132 6
15c82623
NC
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
252b5132 11
15c82623
NC
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
252b5132 16
15c82623
NC
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
b43b5d5f 19 Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */
252b5132
RH
20\f
21/* Extensions/incompatibilities:
22 o - BSD output has filenames at the end.
23 o - BSD output can appear in different radicies.
24 o - SysV output has less redundant whitespace. Filename comes at end.
25 o - SysV output doesn't show VMA which is always the same as the PMA.
26 o - We also handle core files.
27 o - We also handle archives.
28 If you write shell scripts which manipulate this info then you may be
15c82623 29 out of luck; there's no --compatibility or --pedantic option. */
252b5132 30
3db64b00 31#include "sysdep.h"
252b5132 32#include "bfd.h"
252b5132 33#include "libiberty.h"
d7a283d4 34#include "getopt.h"
3db64b00 35#include "bucomm.h"
252b5132
RH
36
37#ifndef BSD_DEFAULT
38#define BSD_DEFAULT 1
39#endif
40
41/* Program options. */
42
29422971 43static enum
252b5132
RH
44 {
45 decimal, octal, hex
15c82623
NC
46 }
47radix = decimal;
48
85b1c36d
BE
49/* 0 means use AT&T-style output. */
50static int berkeley_format = BSD_DEFAULT;
51
29422971
AM
52static int show_version = 0;
53static int show_help = 0;
54static int show_totals = 0;
55static int show_common = 0;
15c82623 56
29422971 57static bfd_size_type common_size;
15c82623
NC
58static bfd_size_type total_bsssize;
59static bfd_size_type total_datasize;
60static bfd_size_type total_textsize;
252b5132
RH
61
62/* Program exit status. */
29422971 63static int return_code = 0;
252b5132
RH
64
65static char *target = NULL;
66
29422971 67/* Forward declarations. */
252b5132 68
2da42df6 69static void display_file (char *);
2da42df6 70static void rprint_number (int, bfd_size_type);
2da42df6 71static void print_sizes (bfd * file);
252b5132
RH
72\f
73static void
2da42df6 74usage (FILE *stream, int status)
252b5132 75{
8b53311e
NC
76 fprintf (stream, _("Usage: %s [option(s)] [file(s)]\n"), program_name);
77 fprintf (stream, _(" Displays the sizes of sections inside binary files\n"));
9f66665a 78 fprintf (stream, _(" If no input file(s) are specified, a.out is assumed\n"));
8b53311e
NC
79 fprintf (stream, _(" The options are:\n\
80 -A|-B --format={sysv|berkeley} Select output style (default is %s)\n\
92acdfaf 81 -o|-d|-x --radix={8|10|16} Display numbers in octal, decimal or hex\n\
15c82623 82 -t --totals Display the total sizes (Berkeley only)\n\
29422971 83 --common Display total size for *COM* syms\n\
8b53311e 84 --target=<bfdname> Set the binary file format\n\
07012eee 85 @<file> Read options from <file>\n\
8b53311e
NC
86 -h --help Display this information\n\
87 -v --version Display the program's version\n\
88\n"),
252b5132 89#if BSD_DEFAULT
8b53311e 90 "berkeley"
252b5132 91#else
8b53311e 92 "sysv"
252b5132 93#endif
8b53311e 94);
252b5132 95 list_supported_targets (program_name, stream);
92f01d61 96 if (REPORT_BUGS_TO[0] && status == 0)
8ad3436c 97 fprintf (stream, _("Report bugs to %s\n"), REPORT_BUGS_TO);
252b5132
RH
98 exit (status);
99}
100
29422971
AM
101#define OPTION_FORMAT (200)
102#define OPTION_RADIX (OPTION_FORMAT + 1)
103#define OPTION_TARGET (OPTION_RADIX + 1)
104
85b1c36d 105static struct option long_options[] =
252b5132 106{
29422971
AM
107 {"common", no_argument, &show_common, 1},
108 {"format", required_argument, 0, OPTION_FORMAT},
109 {"radix", required_argument, 0, OPTION_RADIX},
110 {"target", required_argument, 0, OPTION_TARGET},
15c82623 111 {"totals", no_argument, &show_totals, 1},
252b5132
RH
112 {"version", no_argument, &show_version, 1},
113 {"help", no_argument, &show_help, 1},
114 {0, no_argument, 0, 0}
115};
116
2da42df6 117int main (int, char **);
65de42c0 118
252b5132 119int
2da42df6 120main (int argc, char **argv)
252b5132
RH
121{
122 int temp;
123 int c;
124
125#if defined (HAVE_SETLOCALE) && defined (HAVE_LC_MESSAGES)
126 setlocale (LC_MESSAGES, "");
3882b010
L
127#endif
128#if defined (HAVE_SETLOCALE)
129 setlocale (LC_CTYPE, "");
252b5132
RH
130#endif
131 bindtextdomain (PACKAGE, LOCALEDIR);
132 textdomain (PACKAGE);
133
134 program_name = *argv;
135 xmalloc_set_program_name (program_name);
136
869b9d07
MM
137 expandargv (&argc, &argv);
138
252b5132
RH
139 bfd_init ();
140 set_default_bfd_target ();
141
15c82623 142 while ((c = getopt_long (argc, argv, "ABHhVvdfotx", long_options,
252b5132
RH
143 (int *) 0)) != EOF)
144 switch (c)
145 {
29422971 146 case OPTION_FORMAT:
252b5132
RH
147 switch (*optarg)
148 {
149 case 'B':
150 case 'b':
151 berkeley_format = 1;
152 break;
153 case 'S':
154 case 's':
155 berkeley_format = 0;
156 break;
157 default:
37cc8ec1 158 non_fatal (_("invalid argument to --format: %s"), optarg);
252b5132
RH
159 usage (stderr, 1);
160 }
161 break;
162
29422971 163 case OPTION_TARGET:
252b5132
RH
164 target = optarg;
165 break;
166
29422971 167 case OPTION_RADIX:
252b5132
RH
168#ifdef ANSI_LIBRARIES
169 temp = strtol (optarg, NULL, 10);
170#else
171 temp = atol (optarg);
172#endif
173 switch (temp)
174 {
175 case 10:
176 radix = decimal;
177 break;
178 case 8:
179 radix = octal;
180 break;
181 case 16:
182 radix = hex;
183 break;
184 default:
37cc8ec1 185 non_fatal (_("Invalid radix: %s\n"), optarg);
252b5132
RH
186 usage (stderr, 1);
187 }
188 break;
189
190 case 'A':
191 berkeley_format = 0;
192 break;
193 case 'B':
194 berkeley_format = 1;
195 break;
8b53311e 196 case 'v':
252b5132
RH
197 case 'V':
198 show_version = 1;
199 break;
200 case 'd':
201 radix = decimal;
202 break;
203 case 'x':
204 radix = hex;
205 break;
206 case 'o':
207 radix = octal;
208 break;
15c82623
NC
209 case 't':
210 show_totals = 1;
211 break;
e3a69612
AM
212 case 'f': /* FIXME : For sysv68, `-f' means `full format', i.e.
213 `[fname:] M(.text) + N(.data) + O(.bss) + P(.comment) = Q'
214 where `fname: ' appears only if there are >= 2 input files,
215 and M, N, O, P, Q are expressed in decimal by default,
216 hexa or octal if requested by `-x' or `-o'.
217 Just to make things interesting, Solaris also accepts -f,
218 which prints out the size of each allocatable section, the
219 name of the section, and the total of the section sizes. */
220 /* For the moment, accept `-f' silently, and ignore it. */
221 break;
252b5132
RH
222 case 0:
223 break;
8b53311e
NC
224 case 'h':
225 case 'H':
252b5132
RH
226 case '?':
227 usage (stderr, 1);
228 }
229
230 if (show_version)
231 print_version ("size");
232 if (show_help)
233 usage (stdout, 0);
234
235 if (optind == argc)
236 display_file ("a.out");
237 else
238 for (; optind < argc;)
239 display_file (argv[optind++]);
240
15c82623
NC
241 if (show_totals && berkeley_format)
242 {
243 bfd_size_type total = total_textsize + total_datasize + total_bsssize;
244
245 rprint_number (7, total_textsize);
246 putchar('\t');
247 rprint_number (7, total_datasize);
248 putchar('\t');
249 rprint_number (7, total_bsssize);
250 printf (((radix == octal) ? "\t%7lo\t%7lx\t" : "\t%7lu\t%7lx\t"),
251 (unsigned long) total, (unsigned long) total);
252 fputs ("(TOTALS)\n", stdout);
253 }
254
252b5132
RH
255 return return_code;
256}
257\f
29422971
AM
258/* Total size required for common symbols in ABFD. */
259
260static void
261calculate_common_size (bfd *abfd)
262{
263 asymbol **syms = NULL;
264 long storage, symcount;
265
266 common_size = 0;
267 if ((bfd_get_file_flags (abfd) & (EXEC_P | DYNAMIC | HAS_SYMS)) != HAS_SYMS)
268 return;
269
270 storage = bfd_get_symtab_upper_bound (abfd);
271 if (storage < 0)
272 bfd_fatal (bfd_get_filename (abfd));
273 if (storage)
274 syms = xmalloc (storage);
275
276 symcount = bfd_canonicalize_symtab (abfd, syms);
277 if (symcount < 0)
278 bfd_fatal (bfd_get_filename (abfd));
279
280 while (--symcount >= 0)
281 {
282 asymbol *sym = syms[symcount];
283
284 if (bfd_is_com_section (sym->section)
285 && (sym->flags & BSF_SECTION_SYM) == 0)
286 common_size += sym->value;
287 }
288 free (syms);
289}
290
252b5132
RH
291/* Display stats on file or archive member ABFD. */
292
293static void
2da42df6 294display_bfd (bfd *abfd)
252b5132
RH
295{
296 char **matching;
297
298 if (bfd_check_format (abfd, bfd_archive))
299 /* An archive within an archive. */
300 return;
301
302 if (bfd_check_format_matches (abfd, bfd_object, &matching))
303 {
304 print_sizes (abfd);
305 printf ("\n");
306 return;
307 }
308
309 if (bfd_get_error () == bfd_error_file_ambiguously_recognized)
310 {
311 bfd_nonfatal (bfd_get_filename (abfd));
312 list_matching_formats (matching);
313 free (matching);
314 return_code = 3;
315 return;
316 }
317
318 if (bfd_check_format_matches (abfd, bfd_core, &matching))
319 {
15c82623 320 const char *core_cmd;
252b5132
RH
321
322 print_sizes (abfd);
323 fputs (" (core file", stdout);
324
325 core_cmd = bfd_core_file_failing_command (abfd);
326 if (core_cmd)
327 printf (" invoked as %s", core_cmd);
328
329 puts (")\n");
330 return;
331 }
332
333 bfd_nonfatal (bfd_get_filename (abfd));
334
335 if (bfd_get_error () == bfd_error_file_ambiguously_recognized)
336 {
337 list_matching_formats (matching);
338 free (matching);
339 }
340
341 return_code = 3;
342}
343
344static void
2da42df6 345display_archive (bfd *file)
252b5132
RH
346{
347 bfd *arfile = (bfd *) NULL;
6b52b824 348 bfd *last_arfile = (bfd *) NULL;
252b5132
RH
349
350 for (;;)
351 {
352 bfd_set_error (bfd_error_no_error);
353
354 arfile = bfd_openr_next_archived_file (file, arfile);
355 if (arfile == NULL)
356 {
357 if (bfd_get_error () != bfd_error_no_more_archived_files)
358 {
359 bfd_nonfatal (bfd_get_filename (file));
360 return_code = 2;
361 }
362 break;
363 }
364
365 display_bfd (arfile);
6b52b824
AM
366
367 if (last_arfile != NULL)
368 bfd_close (last_arfile);
369 last_arfile = arfile;
252b5132 370 }
6b52b824
AM
371
372 if (last_arfile != NULL)
373 bfd_close (last_arfile);
252b5132
RH
374}
375
376static void
2da42df6 377display_file (char *filename)
252b5132 378{
f24ddbdd 379 bfd *file;
15c82623 380
f24ddbdd 381 if (get_file_size (filename) < 1)
d68c385b
NC
382 {
383 return_code = 1;
384 return;
385 }
f24ddbdd
NC
386
387 file = bfd_openr (filename, target);
252b5132
RH
388 if (file == NULL)
389 {
390 bfd_nonfatal (filename);
391 return_code = 1;
392 return;
393 }
394
b34976b6 395 if (bfd_check_format (file, bfd_archive))
252b5132
RH
396 display_archive (file);
397 else
398 display_bfd (file);
399
b34976b6 400 if (!bfd_close (file))
252b5132
RH
401 {
402 bfd_nonfatal (filename);
403 return_code = 1;
404 return;
405 }
406}
407\f
408/* This is what lexical functions are for. */
409
410static int
2da42df6 411size_number (bfd_size_type num)
252b5132
RH
412{
413 char buffer[40];
15c82623 414
252b5132
RH
415 sprintf (buffer,
416 (radix == decimal ? "%lu" :
417 ((radix == octal) ? "0%lo" : "0x%lx")),
418 (unsigned long) num);
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
RH
428 sprintf (buffer,
429 (radix == decimal ? "%lu" :
430 ((radix == octal) ? "0%lo" : "0x%lx")),
431 (unsigned long) num);
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.326107 seconds and 4 git commands to generate.