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