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,
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
43enum
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
252b5132
RH
52int show_version = 0;
53int show_help = 0;
15c82623
NC
54int show_totals = 0;
55
56static bfd_size_type total_bsssize;
57static bfd_size_type total_datasize;
58static bfd_size_type total_textsize;
252b5132
RH
59
60/* Program exit status. */
61int return_code = 0;
62
63static char *target = NULL;
64
15c82623 65/* Static declarations. */
252b5132 66
2da42df6
AJ
67static void usage (FILE *, int);
68static void display_file (char *);
69static void display_bfd (bfd *);
70static void display_archive (bfd *);
71static int size_number (bfd_size_type);
2da42df6
AJ
72static void rprint_number (int, bfd_size_type);
73static void print_berkeley_format (bfd *);
74static void sysv_internal_sizer (bfd *, asection *, void *);
75static void sysv_internal_printer (bfd *, asection *, void *);
76static void print_sysv_format (bfd *);
77static void print_sizes (bfd * file);
78static void berkeley_sum (bfd *, sec_ptr, void *);
252b5132
RH
79\f
80static void
2da42df6 81usage (FILE *stream, int status)
252b5132 82{
8b53311e
NC
83 fprintf (stream, _("Usage: %s [option(s)] [file(s)]\n"), program_name);
84 fprintf (stream, _(" Displays the sizes of sections inside binary files\n"));
9f66665a 85 fprintf (stream, _(" If no input file(s) are specified, a.out is assumed\n"));
8b53311e
NC
86 fprintf (stream, _(" The options are:\n\
87 -A|-B --format={sysv|berkeley} Select output style (default is %s)\n\
92acdfaf 88 -o|-d|-x --radix={8|10|16} Display numbers in octal, decimal or hex\n\
15c82623 89 -t --totals Display the total sizes (Berkeley only)\n\
8b53311e 90 --target=<bfdname> Set the binary file format\n\
07012eee 91 @<file> Read options from <file>\n\
8b53311e
NC
92 -h --help Display this information\n\
93 -v --version Display the program's version\n\
94\n"),
252b5132 95#if BSD_DEFAULT
8b53311e 96 "berkeley"
252b5132 97#else
8b53311e 98 "sysv"
252b5132 99#endif
8b53311e 100);
252b5132 101 list_supported_targets (program_name, stream);
92f01d61 102 if (REPORT_BUGS_TO[0] && status == 0)
8ad3436c 103 fprintf (stream, _("Report bugs to %s\n"), REPORT_BUGS_TO);
252b5132
RH
104 exit (status);
105}
106
85b1c36d 107static struct option long_options[] =
252b5132
RH
108{
109 {"format", required_argument, 0, 200},
110 {"radix", required_argument, 0, 201},
111 {"target", required_argument, 0, 202},
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 {
147 case 200: /* --format */
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
164 case 202: /* --target */
165 target = optarg;
166 break;
167
168 case 201: /* --radix */
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
259/* Display stats on file or archive member ABFD. */
260
261static void
2da42df6 262display_bfd (bfd *abfd)
252b5132
RH
263{
264 char **matching;
265
266 if (bfd_check_format (abfd, bfd_archive))
267 /* An archive within an archive. */
268 return;
269
270 if (bfd_check_format_matches (abfd, bfd_object, &matching))
271 {
272 print_sizes (abfd);
273 printf ("\n");
274 return;
275 }
276
277 if (bfd_get_error () == bfd_error_file_ambiguously_recognized)
278 {
279 bfd_nonfatal (bfd_get_filename (abfd));
280 list_matching_formats (matching);
281 free (matching);
282 return_code = 3;
283 return;
284 }
285
286 if (bfd_check_format_matches (abfd, bfd_core, &matching))
287 {
15c82623 288 const char *core_cmd;
252b5132
RH
289
290 print_sizes (abfd);
291 fputs (" (core file", stdout);
292
293 core_cmd = bfd_core_file_failing_command (abfd);
294 if (core_cmd)
295 printf (" invoked as %s", core_cmd);
296
297 puts (")\n");
298 return;
299 }
300
301 bfd_nonfatal (bfd_get_filename (abfd));
302
303 if (bfd_get_error () == bfd_error_file_ambiguously_recognized)
304 {
305 list_matching_formats (matching);
306 free (matching);
307 }
308
309 return_code = 3;
310}
311
312static void
2da42df6 313display_archive (bfd *file)
252b5132
RH
314{
315 bfd *arfile = (bfd *) NULL;
6b52b824 316 bfd *last_arfile = (bfd *) NULL;
252b5132
RH
317
318 for (;;)
319 {
320 bfd_set_error (bfd_error_no_error);
321
322 arfile = bfd_openr_next_archived_file (file, arfile);
323 if (arfile == NULL)
324 {
325 if (bfd_get_error () != bfd_error_no_more_archived_files)
326 {
327 bfd_nonfatal (bfd_get_filename (file));
328 return_code = 2;
329 }
330 break;
331 }
332
333 display_bfd (arfile);
6b52b824
AM
334
335 if (last_arfile != NULL)
336 bfd_close (last_arfile);
337 last_arfile = arfile;
252b5132 338 }
6b52b824
AM
339
340 if (last_arfile != NULL)
341 bfd_close (last_arfile);
252b5132
RH
342}
343
344static void
2da42df6 345display_file (char *filename)
252b5132 346{
f24ddbdd 347 bfd *file;
15c82623 348
f24ddbdd 349 if (get_file_size (filename) < 1)
d68c385b
NC
350 {
351 return_code = 1;
352 return;
353 }
f24ddbdd
NC
354
355 file = bfd_openr (filename, target);
252b5132
RH
356 if (file == NULL)
357 {
358 bfd_nonfatal (filename);
359 return_code = 1;
360 return;
361 }
362
b34976b6 363 if (bfd_check_format (file, bfd_archive))
252b5132
RH
364 display_archive (file);
365 else
366 display_bfd (file);
367
b34976b6 368 if (!bfd_close (file))
252b5132
RH
369 {
370 bfd_nonfatal (filename);
371 return_code = 1;
372 return;
373 }
374}
375\f
376/* This is what lexical functions are for. */
377
378static int
2da42df6 379size_number (bfd_size_type num)
252b5132
RH
380{
381 char buffer[40];
15c82623 382
252b5132
RH
383 sprintf (buffer,
384 (radix == decimal ? "%lu" :
385 ((radix == octal) ? "0%lo" : "0x%lx")),
386 (unsigned long) num);
387
388 return strlen (buffer);
389}
390
252b5132 391static void
2da42df6 392rprint_number (int width, bfd_size_type num)
252b5132
RH
393{
394 char buffer[40];
15c82623 395
252b5132
RH
396 sprintf (buffer,
397 (radix == decimal ? "%lu" :
398 ((radix == octal) ? "0%lo" : "0x%lx")),
399 (unsigned long) num);
400
401 printf ("%*s", width, buffer);
402}
403
404static bfd_size_type bsssize;
405static bfd_size_type datasize;
406static bfd_size_type textsize;
407
408static void
2da42df6
AJ
409berkeley_sum (bfd *abfd ATTRIBUTE_UNUSED, sec_ptr sec,
410 void *ignore ATTRIBUTE_UNUSED)
252b5132
RH
411{
412 flagword flags;
413 bfd_size_type size;
414
415 flags = bfd_get_section_flags (abfd, sec);
416 if ((flags & SEC_ALLOC) == 0)
417 return;
418
135dfb4a 419 size = bfd_get_section_size (sec);
252b5132
RH
420 if ((flags & SEC_CODE) != 0 || (flags & SEC_READONLY) != 0)
421 textsize += size;
422 else if ((flags & SEC_HAS_CONTENTS) != 0)
423 datasize += size;
424 else
425 bsssize += size;
426}
427
9f66665a 428static void
2da42df6 429print_berkeley_format (bfd *abfd)
252b5132
RH
430{
431 static int files_seen = 0;
432 bfd_size_type total;
433
434 bsssize = 0;
435 datasize = 0;
436 textsize = 0;
437
2da42df6 438 bfd_map_over_sections (abfd, berkeley_sum, NULL);
252b5132
RH
439
440 if (files_seen++ == 0)
252b5132
RH
441 puts ((radix == octal) ? " text\t data\t bss\t oct\t hex\tfilename" :
442 " text\t data\t bss\t dec\t hex\tfilename");
252b5132
RH
443
444 total = textsize + datasize + bsssize;
445
15c82623
NC
446 if (show_totals)
447 {
448 total_textsize += textsize;
449 total_datasize += datasize;
450 total_bsssize += bsssize;
451 }
452
252b5132
RH
453 rprint_number (7, textsize);
454 putchar ('\t');
455 rprint_number (7, datasize);
456 putchar ('\t');
457 rprint_number (7, bsssize);
458 printf (((radix == octal) ? "\t%7lo\t%7lx\t" : "\t%7lu\t%7lx\t"),
459 (unsigned long) total, (unsigned long) total);
460
461 fputs (bfd_get_filename (abfd), stdout);
15c82623 462
252b5132
RH
463 if (bfd_my_archive (abfd))
464 printf (" (ex %s)", bfd_get_filename (bfd_my_archive (abfd)));
465}
466
467/* I REALLY miss lexical functions! */
468bfd_size_type svi_total = 0;
469bfd_vma svi_maxvma = 0;
470int svi_namelen = 0;
471int svi_vmalen = 0;
472int svi_sizelen = 0;
473
474static void
2da42df6
AJ
475sysv_internal_sizer (bfd *file ATTRIBUTE_UNUSED, sec_ptr sec,
476 void *ignore ATTRIBUTE_UNUSED)
252b5132
RH
477{
478 bfd_size_type size = bfd_section_size (file, sec);
15c82623
NC
479
480 if ( ! bfd_is_abs_section (sec)
481 && ! bfd_is_com_section (sec)
482 && ! bfd_is_und_section (sec))
252b5132
RH
483 {
484 int namelen = strlen (bfd_section_name (file, sec));
15c82623 485
252b5132
RH
486 if (namelen > svi_namelen)
487 svi_namelen = namelen;
488
489 svi_total += size;
15c82623 490
252b5132
RH
491 if (bfd_section_vma (file, sec) > svi_maxvma)
492 svi_maxvma = bfd_section_vma (file, sec);
493 }
494}
495
496static void
2da42df6
AJ
497sysv_internal_printer (bfd *file ATTRIBUTE_UNUSED, sec_ptr sec,
498 void *ignore ATTRIBUTE_UNUSED)
252b5132
RH
499{
500 bfd_size_type size = bfd_section_size (file, sec);
15c82623
NC
501
502 if ( ! bfd_is_abs_section (sec)
503 && ! bfd_is_com_section (sec)
504 && ! bfd_is_und_section (sec))
252b5132
RH
505 {
506 svi_total += size;
507
508 printf ("%-*s ", svi_namelen, bfd_section_name (file, sec));
509 rprint_number (svi_sizelen, size);
510 printf (" ");
511 rprint_number (svi_vmalen, bfd_section_vma (file, sec));
512 printf ("\n");
513 }
514}
515
516static void
2da42df6 517print_sysv_format (bfd *file)
252b5132 518{
15c82623 519 /* Size all of the columns. */
252b5132
RH
520 svi_total = 0;
521 svi_maxvma = 0;
522 svi_namelen = 0;
2da42df6 523 bfd_map_over_sections (file, sysv_internal_sizer, NULL);
252b5132 524 svi_vmalen = size_number ((bfd_size_type)svi_maxvma);
15c82623 525
252b5132
RH
526 if ((size_t) svi_vmalen < sizeof ("addr") - 1)
527 svi_vmalen = sizeof ("addr")-1;
528
529 svi_sizelen = size_number (svi_total);
530 if ((size_t) svi_sizelen < sizeof ("size") - 1)
531 svi_sizelen = sizeof ("size")-1;
532
533 svi_total = 0;
534 printf ("%s ", bfd_get_filename (file));
15c82623 535
252b5132
RH
536 if (bfd_my_archive (file))
537 printf (" (ex %s)", bfd_get_filename (bfd_my_archive (file)));
538
539 printf (":\n%-*s %*s %*s\n", svi_namelen, "section",
540 svi_sizelen, "size", svi_vmalen, "addr");
15c82623 541
2da42df6 542 bfd_map_over_sections (file, sysv_internal_printer, NULL);
252b5132
RH
543
544 printf ("%-*s ", svi_namelen, "Total");
545 rprint_number (svi_sizelen, svi_total);
546 printf ("\n\n");
547}
548
549static void
2da42df6 550print_sizes (bfd *file)
252b5132
RH
551{
552 if (berkeley_format)
553 print_berkeley_format (file);
554 else
555 print_sysv_format (file);
556}
This page took 0.352927 seconds and 4 git commands to generate.