]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - binutils/size.c
2002-11-30 Nathanael Nerode <neroden@gcc.gnu.org>
[thirdparty/binutils-gdb.git] / binutils / size.c
CommitLineData
252b5132 1/* size.c -- report size of various sections of an executable file.
8b53311e 2 Copyright 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002
252b5132
RH
3 Free Software Foundation, Inc.
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
15c82623
NC
64static void usage PARAMS ((FILE *, int));
65static void display_file PARAMS ((char *));
66static void display_bfd PARAMS ((bfd *));
67static void display_archive PARAMS ((bfd *));
68static int size_number PARAMS ((bfd_size_type));
252b5132 69#if 0
15c82623 70static void lprint_number PARAMS ((int, bfd_size_type));
252b5132 71#endif
15c82623 72static void rprint_number PARAMS ((int, bfd_size_type));
252b5132 73static void print_berkeley_format PARAMS ((bfd *));
15c82623 74static void sysv_internal_sizer PARAMS ((bfd *, asection *, PTR));
252b5132 75static void sysv_internal_printer PARAMS ((bfd *, asection *, PTR));
15c82623
NC
76static void print_sysv_format PARAMS ((bfd *));
77static void print_sizes PARAMS ((bfd * file));
78static void berkeley_sum PARAMS ((bfd *, sec_ptr, PTR));
252b5132
RH
79\f
80static void
81usage (stream, status)
82 FILE *stream;
83 int status;
84{
8b53311e
NC
85 fprintf (stream, _("Usage: %s [option(s)] [file(s)]\n"), program_name);
86 fprintf (stream, _(" Displays the sizes of sections inside binary files\n"));
9f66665a 87 fprintf (stream, _(" If no input file(s) are specified, a.out is assumed\n"));
8b53311e
NC
88 fprintf (stream, _(" The options are:\n\
89 -A|-B --format={sysv|berkeley} Select output style (default is %s)\n\
92acdfaf 90 -o|-d|-x --radix={8|10|16} Display numbers in octal, decimal or hex\n\
15c82623 91 -t --totals Display the total sizes (Berkeley only)\n\
8b53311e
NC
92 --target=<bfdname> Set the binary file format\n\
93 -h --help Display this information\n\
94 -v --version Display the program's version\n\
95\n"),
252b5132 96#if BSD_DEFAULT
8b53311e 97 "berkeley"
252b5132 98#else
8b53311e 99 "sysv"
252b5132 100#endif
8b53311e 101);
252b5132
RH
102 list_supported_targets (program_name, stream);
103 if (status == 0)
8ad3436c 104 fprintf (stream, _("Report bugs to %s\n"), REPORT_BUGS_TO);
252b5132
RH
105 exit (status);
106}
107
108struct option long_options[] =
109{
110 {"format", required_argument, 0, 200},
111 {"radix", required_argument, 0, 201},
112 {"target", required_argument, 0, 202},
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
65de42c0
TS
119int main PARAMS ((int, char **));
120
252b5132
RH
121int
122main (argc, argv)
123 int argc;
124 char **argv;
125{
126 int temp;
127 int c;
128
129#if defined (HAVE_SETLOCALE) && defined (HAVE_LC_MESSAGES)
130 setlocale (LC_MESSAGES, "");
3882b010
L
131#endif
132#if defined (HAVE_SETLOCALE)
133 setlocale (LC_CTYPE, "");
252b5132
RH
134#endif
135 bindtextdomain (PACKAGE, LOCALEDIR);
136 textdomain (PACKAGE);
137
138 program_name = *argv;
139 xmalloc_set_program_name (program_name);
140
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 {
148 case 200: /* --format */
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
165 case 202: /* --target */
166 target = optarg;
167 break;
168
169 case 201: /* --radix */
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
260/* Display stats on file or archive member ABFD. */
261
262static void
263display_bfd (abfd)
264 bfd *abfd;
265{
266 char **matching;
267
268 if (bfd_check_format (abfd, bfd_archive))
269 /* An archive within an archive. */
270 return;
271
272 if (bfd_check_format_matches (abfd, bfd_object, &matching))
273 {
274 print_sizes (abfd);
275 printf ("\n");
276 return;
277 }
278
279 if (bfd_get_error () == bfd_error_file_ambiguously_recognized)
280 {
281 bfd_nonfatal (bfd_get_filename (abfd));
282 list_matching_formats (matching);
283 free (matching);
284 return_code = 3;
285 return;
286 }
287
288 if (bfd_check_format_matches (abfd, bfd_core, &matching))
289 {
15c82623 290 const char *core_cmd;
252b5132
RH
291
292 print_sizes (abfd);
293 fputs (" (core file", stdout);
294
295 core_cmd = bfd_core_file_failing_command (abfd);
296 if (core_cmd)
297 printf (" invoked as %s", core_cmd);
298
299 puts (")\n");
300 return;
301 }
302
303 bfd_nonfatal (bfd_get_filename (abfd));
304
305 if (bfd_get_error () == bfd_error_file_ambiguously_recognized)
306 {
307 list_matching_formats (matching);
308 free (matching);
309 }
310
311 return_code = 3;
312}
313
314static void
315display_archive (file)
316 bfd *file;
317{
318 bfd *arfile = (bfd *) NULL;
6b52b824 319 bfd *last_arfile = (bfd *) NULL;
252b5132
RH
320
321 for (;;)
322 {
323 bfd_set_error (bfd_error_no_error);
324
325 arfile = bfd_openr_next_archived_file (file, arfile);
326 if (arfile == NULL)
327 {
328 if (bfd_get_error () != bfd_error_no_more_archived_files)
329 {
330 bfd_nonfatal (bfd_get_filename (file));
331 return_code = 2;
332 }
333 break;
334 }
335
336 display_bfd (arfile);
6b52b824
AM
337
338 if (last_arfile != NULL)
339 bfd_close (last_arfile);
340 last_arfile = arfile;
252b5132 341 }
6b52b824
AM
342
343 if (last_arfile != NULL)
344 bfd_close (last_arfile);
252b5132
RH
345}
346
347static void
348display_file (filename)
349 char *filename;
350{
351 bfd *file = bfd_openr (filename, target);
15c82623 352
252b5132
RH
353 if (file == NULL)
354 {
355 bfd_nonfatal (filename);
356 return_code = 1;
357 return;
358 }
359
360 if (bfd_check_format (file, bfd_archive) == true)
361 display_archive (file);
362 else
363 display_bfd (file);
364
365 if (bfd_close (file) == false)
366 {
367 bfd_nonfatal (filename);
368 return_code = 1;
369 return;
370 }
371}
372\f
373/* This is what lexical functions are for. */
374
375static int
376size_number (num)
377 bfd_size_type num;
378{
379 char buffer[40];
15c82623 380
252b5132
RH
381 sprintf (buffer,
382 (radix == decimal ? "%lu" :
383 ((radix == octal) ? "0%lo" : "0x%lx")),
384 (unsigned long) num);
385
386 return strlen (buffer);
387}
388
389#if 0
390
391/* This is not used. */
392
393static void
394lprint_number (width, num)
395 int width;
396 bfd_size_type num;
397{
398 char buffer[40];
15c82623 399
252b5132
RH
400 sprintf (buffer,
401 (radix == decimal ? "%lu" :
402 ((radix == octal) ? "0%lo" : "0x%lx")),
403 (unsigned long) num);
404
405 printf ("%-*s", width, buffer);
406}
407
408#endif
409
410static void
411rprint_number (width, num)
412 int width;
413 bfd_size_type num;
414{
415 char buffer[40];
15c82623 416
252b5132
RH
417 sprintf (buffer,
418 (radix == decimal ? "%lu" :
419 ((radix == octal) ? "0%lo" : "0x%lx")),
420 (unsigned long) num);
421
422 printf ("%*s", width, buffer);
423}
424
425static bfd_size_type bsssize;
426static bfd_size_type datasize;
427static bfd_size_type textsize;
428
429static void
430berkeley_sum (abfd, sec, ignore)
b4c96d0d 431 bfd *abfd ATTRIBUTE_UNUSED;
252b5132 432 sec_ptr sec;
b4c96d0d 433 PTR ignore ATTRIBUTE_UNUSED;
252b5132
RH
434{
435 flagword flags;
436 bfd_size_type size;
437
438 flags = bfd_get_section_flags (abfd, sec);
439 if ((flags & SEC_ALLOC) == 0)
440 return;
441
442 size = bfd_get_section_size_before_reloc (sec);
443 if ((flags & SEC_CODE) != 0 || (flags & SEC_READONLY) != 0)
444 textsize += size;
445 else if ((flags & SEC_HAS_CONTENTS) != 0)
446 datasize += size;
447 else
448 bsssize += size;
449}
450
9f66665a 451static void
252b5132
RH
452print_berkeley_format (abfd)
453 bfd *abfd;
454{
455 static int files_seen = 0;
456 bfd_size_type total;
457
458 bsssize = 0;
459 datasize = 0;
460 textsize = 0;
461
462 bfd_map_over_sections (abfd, berkeley_sum, (PTR) NULL);
463
464 if (files_seen++ == 0)
465#if 0
466 /* Intel doesn't like bss/stk because they don't have core files. */
467 puts ((radix == octal) ? " text\t data\tbss/stk\t oct\t hex\tfilename" :
468 " text\t data\tbss/stk\t dec\t hex\tfilename");
469#else
470 puts ((radix == octal) ? " text\t data\t bss\t oct\t hex\tfilename" :
471 " text\t data\t bss\t dec\t hex\tfilename");
472#endif
473
474 total = textsize + datasize + bsssize;
475
15c82623
NC
476 if (show_totals)
477 {
478 total_textsize += textsize;
479 total_datasize += datasize;
480 total_bsssize += bsssize;
481 }
482
252b5132
RH
483 rprint_number (7, textsize);
484 putchar ('\t');
485 rprint_number (7, datasize);
486 putchar ('\t');
487 rprint_number (7, bsssize);
488 printf (((radix == octal) ? "\t%7lo\t%7lx\t" : "\t%7lu\t%7lx\t"),
489 (unsigned long) total, (unsigned long) total);
490
491 fputs (bfd_get_filename (abfd), stdout);
15c82623 492
252b5132
RH
493 if (bfd_my_archive (abfd))
494 printf (" (ex %s)", bfd_get_filename (bfd_my_archive (abfd)));
495}
496
497/* I REALLY miss lexical functions! */
498bfd_size_type svi_total = 0;
499bfd_vma svi_maxvma = 0;
500int svi_namelen = 0;
501int svi_vmalen = 0;
502int svi_sizelen = 0;
503
504static void
505sysv_internal_sizer (file, sec, ignore)
b4c96d0d 506 bfd *file ATTRIBUTE_UNUSED;
252b5132 507 sec_ptr sec;
b4c96d0d 508 PTR ignore ATTRIBUTE_UNUSED;
252b5132
RH
509{
510 bfd_size_type size = bfd_section_size (file, sec);
15c82623
NC
511
512 if ( ! bfd_is_abs_section (sec)
513 && ! bfd_is_com_section (sec)
514 && ! bfd_is_und_section (sec))
252b5132
RH
515 {
516 int namelen = strlen (bfd_section_name (file, sec));
15c82623 517
252b5132
RH
518 if (namelen > svi_namelen)
519 svi_namelen = namelen;
520
521 svi_total += size;
15c82623 522
252b5132
RH
523 if (bfd_section_vma (file, sec) > svi_maxvma)
524 svi_maxvma = bfd_section_vma (file, sec);
525 }
526}
527
528static void
529sysv_internal_printer (file, sec, ignore)
b4c96d0d 530 bfd *file ATTRIBUTE_UNUSED;
252b5132 531 sec_ptr sec;
b4c96d0d 532 PTR ignore ATTRIBUTE_UNUSED;
252b5132
RH
533{
534 bfd_size_type size = bfd_section_size (file, sec);
15c82623
NC
535
536 if ( ! bfd_is_abs_section (sec)
537 && ! bfd_is_com_section (sec)
538 && ! bfd_is_und_section (sec))
252b5132
RH
539 {
540 svi_total += size;
541
542 printf ("%-*s ", svi_namelen, bfd_section_name (file, sec));
543 rprint_number (svi_sizelen, size);
544 printf (" ");
545 rprint_number (svi_vmalen, bfd_section_vma (file, sec));
546 printf ("\n");
547 }
548}
549
550static void
551print_sysv_format (file)
552 bfd *file;
553{
15c82623 554 /* Size all of the columns. */
252b5132
RH
555 svi_total = 0;
556 svi_maxvma = 0;
557 svi_namelen = 0;
558 bfd_map_over_sections (file, sysv_internal_sizer, (PTR) NULL);
559 svi_vmalen = size_number ((bfd_size_type)svi_maxvma);
15c82623 560
252b5132
RH
561 if ((size_t) svi_vmalen < sizeof ("addr") - 1)
562 svi_vmalen = sizeof ("addr")-1;
563
564 svi_sizelen = size_number (svi_total);
565 if ((size_t) svi_sizelen < sizeof ("size") - 1)
566 svi_sizelen = sizeof ("size")-1;
567
568 svi_total = 0;
569 printf ("%s ", bfd_get_filename (file));
15c82623 570
252b5132
RH
571 if (bfd_my_archive (file))
572 printf (" (ex %s)", bfd_get_filename (bfd_my_archive (file)));
573
574 printf (":\n%-*s %*s %*s\n", svi_namelen, "section",
575 svi_sizelen, "size", svi_vmalen, "addr");
15c82623 576
252b5132
RH
577 bfd_map_over_sections (file, sysv_internal_printer, (PTR) NULL);
578
579 printf ("%-*s ", svi_namelen, "Total");
580 rprint_number (svi_sizelen, svi_total);
581 printf ("\n\n");
582}
583
584static void
585print_sizes (file)
586 bfd *file;
587{
588 if (berkeley_format)
589 print_berkeley_format (file);
590 else
591 print_sysv_format (file);
592}