Revise and update ``Releasing GDB''.
[deliverable/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"
32#include "getopt.h"
33#include "bucomm.h"
34#include "libiberty.h"
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"));
87 fprintf (stream, _(" If no input file(s) are specified, a.out is assumed\n"));
88 fprintf (stream, _(" The options are:\n\
89 -A|-B --format={sysv|berkeley} Select output style (default is %s)\n\
90 -o|-d|-h --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;
319
320 for (;;)
321 {
322 bfd_set_error (bfd_error_no_error);
323
324 arfile = bfd_openr_next_archived_file (file, arfile);
325 if (arfile == NULL)
326 {
327 if (bfd_get_error () != bfd_error_no_more_archived_files)
328 {
329 bfd_nonfatal (bfd_get_filename (file));
330 return_code = 2;
331 }
332 break;
333 }
334
335 display_bfd (arfile);
15c82623 336 /* Don't close the archive elements; we need them for next_archive. */
252b5132
RH
337 }
338}
339
340static void
341display_file (filename)
342 char *filename;
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
353 if (bfd_check_format (file, bfd_archive) == true)
354 display_archive (file);
355 else
356 display_bfd (file);
357
358 if (bfd_close (file) == false)
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
369size_number (num)
370 bfd_size_type num;
371{
372 char buffer[40];
15c82623 373
252b5132
RH
374 sprintf (buffer,
375 (radix == decimal ? "%lu" :
376 ((radix == octal) ? "0%lo" : "0x%lx")),
377 (unsigned long) num);
378
379 return strlen (buffer);
380}
381
382#if 0
383
384/* This is not used. */
385
386static void
387lprint_number (width, num)
388 int width;
389 bfd_size_type num;
390{
391 char buffer[40];
15c82623 392
252b5132
RH
393 sprintf (buffer,
394 (radix == decimal ? "%lu" :
395 ((radix == octal) ? "0%lo" : "0x%lx")),
396 (unsigned long) num);
397
398 printf ("%-*s", width, buffer);
399}
400
401#endif
402
403static void
404rprint_number (width, num)
405 int width;
406 bfd_size_type num;
407{
408 char buffer[40];
15c82623 409
252b5132
RH
410 sprintf (buffer,
411 (radix == decimal ? "%lu" :
412 ((radix == octal) ? "0%lo" : "0x%lx")),
413 (unsigned long) num);
414
415 printf ("%*s", width, buffer);
416}
417
418static bfd_size_type bsssize;
419static bfd_size_type datasize;
420static bfd_size_type textsize;
421
422static void
423berkeley_sum (abfd, sec, ignore)
b4c96d0d 424 bfd *abfd ATTRIBUTE_UNUSED;
252b5132 425 sec_ptr sec;
b4c96d0d 426 PTR ignore ATTRIBUTE_UNUSED;
252b5132
RH
427{
428 flagword flags;
429 bfd_size_type size;
430
431 flags = bfd_get_section_flags (abfd, sec);
432 if ((flags & SEC_ALLOC) == 0)
433 return;
434
435 size = bfd_get_section_size_before_reloc (sec);
436 if ((flags & SEC_CODE) != 0 || (flags & SEC_READONLY) != 0)
437 textsize += size;
438 else if ((flags & SEC_HAS_CONTENTS) != 0)
439 datasize += size;
440 else
441 bsssize += size;
442}
443
444static void
445print_berkeley_format (abfd)
446 bfd *abfd;
447{
448 static int files_seen = 0;
449 bfd_size_type total;
450
451 bsssize = 0;
452 datasize = 0;
453 textsize = 0;
454
455 bfd_map_over_sections (abfd, berkeley_sum, (PTR) NULL);
456
457 if (files_seen++ == 0)
458#if 0
459 /* Intel doesn't like bss/stk because they don't have core files. */
460 puts ((radix == octal) ? " text\t data\tbss/stk\t oct\t hex\tfilename" :
461 " text\t data\tbss/stk\t dec\t hex\tfilename");
462#else
463 puts ((radix == octal) ? " text\t data\t bss\t oct\t hex\tfilename" :
464 " text\t data\t bss\t dec\t hex\tfilename");
465#endif
466
467 total = textsize + datasize + bsssize;
468
15c82623
NC
469 if (show_totals)
470 {
471 total_textsize += textsize;
472 total_datasize += datasize;
473 total_bsssize += bsssize;
474 }
475
252b5132
RH
476 rprint_number (7, textsize);
477 putchar ('\t');
478 rprint_number (7, datasize);
479 putchar ('\t');
480 rprint_number (7, bsssize);
481 printf (((radix == octal) ? "\t%7lo\t%7lx\t" : "\t%7lu\t%7lx\t"),
482 (unsigned long) total, (unsigned long) total);
483
484 fputs (bfd_get_filename (abfd), stdout);
15c82623 485
252b5132
RH
486 if (bfd_my_archive (abfd))
487 printf (" (ex %s)", bfd_get_filename (bfd_my_archive (abfd)));
488}
489
490/* I REALLY miss lexical functions! */
491bfd_size_type svi_total = 0;
492bfd_vma svi_maxvma = 0;
493int svi_namelen = 0;
494int svi_vmalen = 0;
495int svi_sizelen = 0;
496
497static void
498sysv_internal_sizer (file, sec, ignore)
b4c96d0d 499 bfd *file ATTRIBUTE_UNUSED;
252b5132 500 sec_ptr sec;
b4c96d0d 501 PTR ignore ATTRIBUTE_UNUSED;
252b5132
RH
502{
503 bfd_size_type size = bfd_section_size (file, sec);
15c82623
NC
504
505 if ( ! bfd_is_abs_section (sec)
506 && ! bfd_is_com_section (sec)
507 && ! bfd_is_und_section (sec))
252b5132
RH
508 {
509 int namelen = strlen (bfd_section_name (file, sec));
15c82623 510
252b5132
RH
511 if (namelen > svi_namelen)
512 svi_namelen = namelen;
513
514 svi_total += size;
15c82623 515
252b5132
RH
516 if (bfd_section_vma (file, sec) > svi_maxvma)
517 svi_maxvma = bfd_section_vma (file, sec);
518 }
519}
520
521static void
522sysv_internal_printer (file, sec, ignore)
b4c96d0d 523 bfd *file ATTRIBUTE_UNUSED;
252b5132 524 sec_ptr sec;
b4c96d0d 525 PTR ignore ATTRIBUTE_UNUSED;
252b5132
RH
526{
527 bfd_size_type size = bfd_section_size (file, sec);
15c82623
NC
528
529 if ( ! bfd_is_abs_section (sec)
530 && ! bfd_is_com_section (sec)
531 && ! bfd_is_und_section (sec))
252b5132
RH
532 {
533 svi_total += size;
534
535 printf ("%-*s ", svi_namelen, bfd_section_name (file, sec));
536 rprint_number (svi_sizelen, size);
537 printf (" ");
538 rprint_number (svi_vmalen, bfd_section_vma (file, sec));
539 printf ("\n");
540 }
541}
542
543static void
544print_sysv_format (file)
545 bfd *file;
546{
15c82623 547 /* Size all of the columns. */
252b5132
RH
548 svi_total = 0;
549 svi_maxvma = 0;
550 svi_namelen = 0;
551 bfd_map_over_sections (file, sysv_internal_sizer, (PTR) NULL);
552 svi_vmalen = size_number ((bfd_size_type)svi_maxvma);
15c82623 553
252b5132
RH
554 if ((size_t) svi_vmalen < sizeof ("addr") - 1)
555 svi_vmalen = sizeof ("addr")-1;
556
557 svi_sizelen = size_number (svi_total);
558 if ((size_t) svi_sizelen < sizeof ("size") - 1)
559 svi_sizelen = sizeof ("size")-1;
560
561 svi_total = 0;
562 printf ("%s ", bfd_get_filename (file));
15c82623 563
252b5132
RH
564 if (bfd_my_archive (file))
565 printf (" (ex %s)", bfd_get_filename (bfd_my_archive (file)));
566
567 printf (":\n%-*s %*s %*s\n", svi_namelen, "section",
568 svi_sizelen, "size", svi_vmalen, "addr");
15c82623 569
252b5132
RH
570 bfd_map_over_sections (file, sysv_internal_printer, (PTR) NULL);
571
572 printf ("%-*s ", svi_namelen, "Total");
573 rprint_number (svi_sizelen, svi_total);
574 printf ("\n\n");
575}
576
577static void
578print_sizes (file)
579 bfd *file;
580{
581 if (berkeley_format)
582 print_berkeley_format (file);
583 else
584 print_sysv_format (file);
585}
This page took 0.127416 seconds and 4 git commands to generate.