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