2003-09-28 Andrew Cagney <cagney@redhat.com>
[deliverable/binutils-gdb.git] / binutils / size.c
CommitLineData
252b5132 1/* size.c -- report size of various sections of an executable file.
b34976b6 2 Copyright 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
2da42df6 3 2002, 2003 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
19 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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
RH
30
31#include "bfd.h"
252b5132
RH
32#include "bucomm.h"
33#include "libiberty.h"
d7a283d4 34#include "getopt.h"
252b5132
RH
35
36#ifndef BSD_DEFAULT
37#define BSD_DEFAULT 1
38#endif
39
40/* Program options. */
41
42enum
43 {
44 decimal, octal, hex
15c82623
NC
45 }
46radix = decimal;
47
252b5132
RH
48int berkeley_format = BSD_DEFAULT; /* 0 means use AT&T-style output. */
49int show_version = 0;
50int show_help = 0;
15c82623
NC
51int show_totals = 0;
52
53static bfd_size_type total_bsssize;
54static bfd_size_type total_datasize;
55static bfd_size_type total_textsize;
252b5132
RH
56
57/* Program exit status. */
58int return_code = 0;
59
60static char *target = NULL;
61
15c82623 62/* Static declarations. */
252b5132 63
2da42df6
AJ
64static void usage (FILE *, int);
65static void display_file (char *);
66static void display_bfd (bfd *);
67static void display_archive (bfd *);
68static int size_number (bfd_size_type);
252b5132 69#if 0
2da42df6 70static void lprint_number (int, bfd_size_type);
252b5132 71#endif
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
NC
90 --target=<bfdname> Set the binary file format\n\
91 -h --help Display this information\n\
92 -v --version Display the program's version\n\
93\n"),
252b5132 94#if BSD_DEFAULT
8b53311e 95 "berkeley"
252b5132 96#else
8b53311e 97 "sysv"
252b5132 98#endif
8b53311e 99);
252b5132
RH
100 list_supported_targets (program_name, stream);
101 if (status == 0)
8ad3436c 102 fprintf (stream, _("Report bugs to %s\n"), REPORT_BUGS_TO);
252b5132
RH
103 exit (status);
104}
105
106struct option long_options[] =
107{
108 {"format", required_argument, 0, 200},
109 {"radix", required_argument, 0, 201},
110 {"target", required_argument, 0, 202},
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
137 bfd_init ();
138 set_default_bfd_target ();
139
15c82623 140 while ((c = getopt_long (argc, argv, "ABHhVvdfotx", long_options,
252b5132
RH
141 (int *) 0)) != EOF)
142 switch (c)
143 {
144 case 200: /* --format */
145 switch (*optarg)
146 {
147 case 'B':
148 case 'b':
149 berkeley_format = 1;
150 break;
151 case 'S':
152 case 's':
153 berkeley_format = 0;
154 break;
155 default:
37cc8ec1 156 non_fatal (_("invalid argument to --format: %s"), optarg);
252b5132
RH
157 usage (stderr, 1);
158 }
159 break;
160
161 case 202: /* --target */
162 target = optarg;
163 break;
164
165 case 201: /* --radix */
166#ifdef ANSI_LIBRARIES
167 temp = strtol (optarg, NULL, 10);
168#else
169 temp = atol (optarg);
170#endif
171 switch (temp)
172 {
173 case 10:
174 radix = decimal;
175 break;
176 case 8:
177 radix = octal;
178 break;
179 case 16:
180 radix = hex;
181 break;
182 default:
37cc8ec1 183 non_fatal (_("Invalid radix: %s\n"), optarg);
252b5132
RH
184 usage (stderr, 1);
185 }
186 break;
187
188 case 'A':
189 berkeley_format = 0;
190 break;
191 case 'B':
192 berkeley_format = 1;
193 break;
8b53311e 194 case 'v':
252b5132
RH
195 case 'V':
196 show_version = 1;
197 break;
198 case 'd':
199 radix = decimal;
200 break;
201 case 'x':
202 radix = hex;
203 break;
204 case 'o':
205 radix = octal;
206 break;
15c82623
NC
207 case 't':
208 show_totals = 1;
209 break;
e3a69612
AM
210 case 'f': /* FIXME : For sysv68, `-f' means `full format', i.e.
211 `[fname:] M(.text) + N(.data) + O(.bss) + P(.comment) = Q'
212 where `fname: ' appears only if there are >= 2 input files,
213 and M, N, O, P, Q are expressed in decimal by default,
214 hexa or octal if requested by `-x' or `-o'.
215 Just to make things interesting, Solaris also accepts -f,
216 which prints out the size of each allocatable section, the
217 name of the section, and the total of the section sizes. */
218 /* For the moment, accept `-f' silently, and ignore it. */
219 break;
252b5132
RH
220 case 0:
221 break;
8b53311e
NC
222 case 'h':
223 case 'H':
252b5132
RH
224 case '?':
225 usage (stderr, 1);
226 }
227
228 if (show_version)
229 print_version ("size");
230 if (show_help)
231 usage (stdout, 0);
232
233 if (optind == argc)
234 display_file ("a.out");
235 else
236 for (; optind < argc;)
237 display_file (argv[optind++]);
238
15c82623
NC
239 if (show_totals && berkeley_format)
240 {
241 bfd_size_type total = total_textsize + total_datasize + total_bsssize;
242
243 rprint_number (7, total_textsize);
244 putchar('\t');
245 rprint_number (7, total_datasize);
246 putchar('\t');
247 rprint_number (7, total_bsssize);
248 printf (((radix == octal) ? "\t%7lo\t%7lx\t" : "\t%7lu\t%7lx\t"),
249 (unsigned long) total, (unsigned long) total);
250 fputs ("(TOTALS)\n", stdout);
251 }
252
252b5132
RH
253 return return_code;
254}
255\f
256/* Display stats on file or archive member ABFD. */
257
258static void
2da42df6 259display_bfd (bfd *abfd)
252b5132
RH
260{
261 char **matching;
262
263 if (bfd_check_format (abfd, bfd_archive))
264 /* An archive within an archive. */
265 return;
266
267 if (bfd_check_format_matches (abfd, bfd_object, &matching))
268 {
269 print_sizes (abfd);
270 printf ("\n");
271 return;
272 }
273
274 if (bfd_get_error () == bfd_error_file_ambiguously_recognized)
275 {
276 bfd_nonfatal (bfd_get_filename (abfd));
277 list_matching_formats (matching);
278 free (matching);
279 return_code = 3;
280 return;
281 }
282
283 if (bfd_check_format_matches (abfd, bfd_core, &matching))
284 {
15c82623 285 const char *core_cmd;
252b5132
RH
286
287 print_sizes (abfd);
288 fputs (" (core file", stdout);
289
290 core_cmd = bfd_core_file_failing_command (abfd);
291 if (core_cmd)
292 printf (" invoked as %s", core_cmd);
293
294 puts (")\n");
295 return;
296 }
297
298 bfd_nonfatal (bfd_get_filename (abfd));
299
300 if (bfd_get_error () == bfd_error_file_ambiguously_recognized)
301 {
302 list_matching_formats (matching);
303 free (matching);
304 }
305
306 return_code = 3;
307}
308
309static void
2da42df6 310display_archive (bfd *file)
252b5132
RH
311{
312 bfd *arfile = (bfd *) NULL;
6b52b824 313 bfd *last_arfile = (bfd *) NULL;
252b5132
RH
314
315 for (;;)
316 {
317 bfd_set_error (bfd_error_no_error);
318
319 arfile = bfd_openr_next_archived_file (file, arfile);
320 if (arfile == NULL)
321 {
322 if (bfd_get_error () != bfd_error_no_more_archived_files)
323 {
324 bfd_nonfatal (bfd_get_filename (file));
325 return_code = 2;
326 }
327 break;
328 }
329
330 display_bfd (arfile);
6b52b824
AM
331
332 if (last_arfile != NULL)
333 bfd_close (last_arfile);
334 last_arfile = arfile;
252b5132 335 }
6b52b824
AM
336
337 if (last_arfile != NULL)
338 bfd_close (last_arfile);
252b5132
RH
339}
340
341static void
2da42df6 342display_file (char *filename)
252b5132
RH
343{
344 bfd *file = bfd_openr (filename, target);
15c82623 345
252b5132
RH
346 if (file == NULL)
347 {
348 bfd_nonfatal (filename);
349 return_code = 1;
350 return;
351 }
352
b34976b6 353 if (bfd_check_format (file, bfd_archive))
252b5132
RH
354 display_archive (file);
355 else
356 display_bfd (file);
357
b34976b6 358 if (!bfd_close (file))
252b5132
RH
359 {
360 bfd_nonfatal (filename);
361 return_code = 1;
362 return;
363 }
364}
365\f
366/* This is what lexical functions are for. */
367
368static int
2da42df6 369size_number (bfd_size_type num)
252b5132
RH
370{
371 char buffer[40];
15c82623 372
252b5132
RH
373 sprintf (buffer,
374 (radix == decimal ? "%lu" :
375 ((radix == octal) ? "0%lo" : "0x%lx")),
376 (unsigned long) num);
377
378 return strlen (buffer);
379}
380
381#if 0
382
383/* This is not used. */
384
385static void
2da42df6 386lprint_number (int width, bfd_size_type num)
252b5132
RH
387{
388 char buffer[40];
15c82623 389
252b5132
RH
390 sprintf (buffer,
391 (radix == decimal ? "%lu" :
392 ((radix == octal) ? "0%lo" : "0x%lx")),
393 (unsigned long) num);
394
395 printf ("%-*s", width, buffer);
396}
397
398#endif
399
400static void
2da42df6 401rprint_number (int width, bfd_size_type num)
252b5132
RH
402{
403 char buffer[40];
15c82623 404
252b5132
RH
405 sprintf (buffer,
406 (radix == decimal ? "%lu" :
407 ((radix == octal) ? "0%lo" : "0x%lx")),
408 (unsigned long) num);
409
410 printf ("%*s", width, buffer);
411}
412
413static bfd_size_type bsssize;
414static bfd_size_type datasize;
415static bfd_size_type textsize;
416
417static void
2da42df6
AJ
418berkeley_sum (bfd *abfd ATTRIBUTE_UNUSED, sec_ptr sec,
419 void *ignore ATTRIBUTE_UNUSED)
252b5132
RH
420{
421 flagword flags;
422 bfd_size_type size;
423
424 flags = bfd_get_section_flags (abfd, sec);
425 if ((flags & SEC_ALLOC) == 0)
426 return;
427
428 size = bfd_get_section_size_before_reloc (sec);
429 if ((flags & SEC_CODE) != 0 || (flags & SEC_READONLY) != 0)
430 textsize += size;
431 else if ((flags & SEC_HAS_CONTENTS) != 0)
432 datasize += size;
433 else
434 bsssize += size;
435}
436
9f66665a 437static void
2da42df6 438print_berkeley_format (bfd *abfd)
252b5132
RH
439{
440 static int files_seen = 0;
441 bfd_size_type total;
442
443 bsssize = 0;
444 datasize = 0;
445 textsize = 0;
446
2da42df6 447 bfd_map_over_sections (abfd, berkeley_sum, NULL);
252b5132
RH
448
449 if (files_seen++ == 0)
450#if 0
451 /* Intel doesn't like bss/stk because they don't have core files. */
452 puts ((radix == octal) ? " text\t data\tbss/stk\t oct\t hex\tfilename" :
453 " text\t data\tbss/stk\t dec\t hex\tfilename");
454#else
455 puts ((radix == octal) ? " text\t data\t bss\t oct\t hex\tfilename" :
456 " text\t data\t bss\t dec\t hex\tfilename");
457#endif
458
459 total = textsize + datasize + bsssize;
460
15c82623
NC
461 if (show_totals)
462 {
463 total_textsize += textsize;
464 total_datasize += datasize;
465 total_bsssize += bsssize;
466 }
467
252b5132
RH
468 rprint_number (7, textsize);
469 putchar ('\t');
470 rprint_number (7, datasize);
471 putchar ('\t');
472 rprint_number (7, bsssize);
473 printf (((radix == octal) ? "\t%7lo\t%7lx\t" : "\t%7lu\t%7lx\t"),
474 (unsigned long) total, (unsigned long) total);
475
476 fputs (bfd_get_filename (abfd), stdout);
15c82623 477
252b5132
RH
478 if (bfd_my_archive (abfd))
479 printf (" (ex %s)", bfd_get_filename (bfd_my_archive (abfd)));
480}
481
482/* I REALLY miss lexical functions! */
483bfd_size_type svi_total = 0;
484bfd_vma svi_maxvma = 0;
485int svi_namelen = 0;
486int svi_vmalen = 0;
487int svi_sizelen = 0;
488
489static void
2da42df6
AJ
490sysv_internal_sizer (bfd *file ATTRIBUTE_UNUSED, sec_ptr sec,
491 void *ignore ATTRIBUTE_UNUSED)
252b5132
RH
492{
493 bfd_size_type size = bfd_section_size (file, sec);
15c82623
NC
494
495 if ( ! bfd_is_abs_section (sec)
496 && ! bfd_is_com_section (sec)
497 && ! bfd_is_und_section (sec))
252b5132
RH
498 {
499 int namelen = strlen (bfd_section_name (file, sec));
15c82623 500
252b5132
RH
501 if (namelen > svi_namelen)
502 svi_namelen = namelen;
503
504 svi_total += size;
15c82623 505
252b5132
RH
506 if (bfd_section_vma (file, sec) > svi_maxvma)
507 svi_maxvma = bfd_section_vma (file, sec);
508 }
509}
510
511static void
2da42df6
AJ
512sysv_internal_printer (bfd *file ATTRIBUTE_UNUSED, sec_ptr sec,
513 void *ignore ATTRIBUTE_UNUSED)
252b5132
RH
514{
515 bfd_size_type size = bfd_section_size (file, sec);
15c82623
NC
516
517 if ( ! bfd_is_abs_section (sec)
518 && ! bfd_is_com_section (sec)
519 && ! bfd_is_und_section (sec))
252b5132
RH
520 {
521 svi_total += size;
522
523 printf ("%-*s ", svi_namelen, bfd_section_name (file, sec));
524 rprint_number (svi_sizelen, size);
525 printf (" ");
526 rprint_number (svi_vmalen, bfd_section_vma (file, sec));
527 printf ("\n");
528 }
529}
530
531static void
2da42df6 532print_sysv_format (bfd *file)
252b5132 533{
15c82623 534 /* Size all of the columns. */
252b5132
RH
535 svi_total = 0;
536 svi_maxvma = 0;
537 svi_namelen = 0;
2da42df6 538 bfd_map_over_sections (file, sysv_internal_sizer, NULL);
252b5132 539 svi_vmalen = size_number ((bfd_size_type)svi_maxvma);
15c82623 540
252b5132
RH
541 if ((size_t) svi_vmalen < sizeof ("addr") - 1)
542 svi_vmalen = sizeof ("addr")-1;
543
544 svi_sizelen = size_number (svi_total);
545 if ((size_t) svi_sizelen < sizeof ("size") - 1)
546 svi_sizelen = sizeof ("size")-1;
547
548 svi_total = 0;
549 printf ("%s ", bfd_get_filename (file));
15c82623 550
252b5132
RH
551 if (bfd_my_archive (file))
552 printf (" (ex %s)", bfd_get_filename (bfd_my_archive (file)));
553
554 printf (":\n%-*s %*s %*s\n", svi_namelen, "section",
555 svi_sizelen, "size", svi_vmalen, "addr");
15c82623 556
2da42df6 557 bfd_map_over_sections (file, sysv_internal_printer, NULL);
252b5132
RH
558
559 printf ("%-*s ", svi_namelen, "Total");
560 rprint_number (svi_sizelen, svi_total);
561 printf ("\n\n");
562}
563
564static void
2da42df6 565print_sizes (bfd *file)
252b5132
RH
566{
567 if (berkeley_format)
568 print_berkeley_format (file);
569 else
570 print_sysv_format (file);
571}
This page took 0.267243 seconds and 4 git commands to generate.