size.c revision 33965
1/* size.c -- report size of various sections of an executable file. 2 Copyright 1991, 92, 93, 94, 95, 96, 1997 Free Software Foundation, Inc. 3 4This file is part of GNU Binutils. 5 6This program is free software; you can redistribute it and/or modify 7it under the terms of the GNU General Public License as published by 8the Free Software Foundation; either version 2 of the License, or 9(at your option) any later version. 10 11This program is distributed in the hope that it will be useful, 12but WITHOUT ANY WARRANTY; without even the implied warranty of 13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14GNU General Public License for more details. 15 16You should have received a copy of the GNU General Public License 17along with this program; if not, write to the Free Software 18Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ 19 20/* Extensions/incompatibilities: 21 o - BSD output has filenames at the end. 22 o - BSD output can appear in different radicies. 23 o - SysV output has less redundant whitespace. Filename comes at end. 24 o - SysV output doesn't show VMA which is always the same as the PMA. 25 o - We also handle core files. 26 o - We also handle archives. 27 If you write shell scripts which manipulate this info then you may be 28 out of luck; there's no --compatibility or --pedantic option. 29*/ 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 45 } radix = decimal; 46int berkeley_format = BSD_DEFAULT; /* 0 means use AT&T-style output. */ 47int show_version = 0; 48int show_help = 0; 49 50/* Program exit status. */ 51int return_code = 0; 52 53/* IMPORTS */ 54extern char *target; 55 56/* Static declarations */ 57 58static void usage PARAMS ((FILE *, int)); 59static void display_file PARAMS ((char *filename)); 60static void display_bfd PARAMS ((bfd *)); 61static void display_archive PARAMS ((bfd *)); 62static void lprint_number PARAMS ((int, bfd_size_type)); 63static void rprint_number PARAMS ((int, bfd_size_type)); 64static void print_berkeley_format PARAMS ((bfd *)); 65static void sysv_internal_printer PARAMS ((bfd *, asection *, PTR)); 66static void print_sysv_format PARAMS ((bfd *)); 67static void print_sizes PARAMS ((bfd * file)); 68static void berkeley_sum PARAMS ((bfd *, sec_ptr, PTR)); 69 70static void 71usage (stream, status) 72 FILE *stream; 73 int status; 74{ 75 fprintf (stream, "\ 76Usage: %s [-ABdoxV] [--format=berkeley|sysv] [--radix=8|10|16]\n\ 77 [--target=bfdname] [--version] [--help] [file...]\n", program_name); 78#if BSD_DEFAULT 79 fputs ("default is --format=berkeley\n", stream); 80#else 81 fputs ("default is --format=sysv\n", stream); 82#endif 83 list_supported_targets (program_name, stream); 84 if (status == 0) 85 fprintf (stream, "Report bugs to bug-gnu-utils@prep.ai.mit.edu\n"); 86 exit (status); 87} 88 89struct option long_options[] = 90{ 91 {"format", required_argument, 0, 200}, 92 {"radix", required_argument, 0, 201}, 93 {"target", required_argument, 0, 202}, 94 {"version", no_argument, &show_version, 1}, 95 {"help", no_argument, &show_help, 1}, 96 {0, no_argument, 0, 0} 97}; 98 99int 100main (argc, argv) 101 int argc; 102 char **argv; 103{ 104 int temp; 105 int c; 106 107 program_name = *argv; 108 xmalloc_set_program_name (program_name); 109 110 bfd_init (); 111 set_default_bfd_target (); 112 113 while ((c = getopt_long (argc, argv, "ABVdox", long_options, 114 (int *) 0)) != EOF) 115 switch (c) 116 { 117 case 200: /* --format */ 118 switch (*optarg) 119 { 120 case 'B': 121 case 'b': 122 berkeley_format = 1; 123 break; 124 case 'S': 125 case 's': 126 berkeley_format = 0; 127 break; 128 default: 129 fprintf (stderr, "invalid argument to --format: %s\n", optarg); 130 usage (stderr, 1); 131 } 132 break; 133 134 case 202: /* --target */ 135 target = optarg; 136 break; 137 138 case 201: /* --radix */ 139#ifdef ANSI_LIBRARIES 140 temp = strtol (optarg, NULL, 10); 141#else 142 temp = atol (optarg); 143#endif 144 switch (temp) 145 { 146 case 10: 147 radix = decimal; 148 break; 149 case 8: 150 radix = octal; 151 break; 152 case 16: 153 radix = hex; 154 break; 155 default: 156 printf ("Invalid radix: %s\n", optarg); 157 usage (stderr, 1); 158 } 159 break; 160 161 case 'A': 162 berkeley_format = 0; 163 break; 164 case 'B': 165 berkeley_format = 1; 166 break; 167 case 'V': 168 show_version = 1; 169 break; 170 case 'd': 171 radix = decimal; 172 break; 173 case 'x': 174 radix = hex; 175 break; 176 case 'o': 177 radix = octal; 178 break; 179 case 0: 180 break; 181 case '?': 182 usage (stderr, 1); 183 } 184 185 if (show_version) 186 print_version ("size"); 187 if (show_help) 188 usage (stdout, 0); 189 190 if (optind == argc) 191 display_file ("a.out"); 192 else 193 for (; optind < argc;) 194 display_file (argv[optind++]); 195 196 return return_code; 197} 198 199/* Display stats on file or archive member ABFD. */ 200 201static void 202display_bfd (abfd) 203 bfd *abfd; 204{ 205 char **matching; 206 207 if (bfd_check_format (abfd, bfd_archive)) 208 /* An archive within an archive. */ 209 return; 210 211 if (bfd_check_format_matches (abfd, bfd_object, &matching)) 212 { 213 print_sizes (abfd); 214 printf ("\n"); 215 return; 216 } 217 218 if (bfd_get_error () == bfd_error_file_ambiguously_recognized) 219 { 220 bfd_nonfatal (bfd_get_filename (abfd)); 221 list_matching_formats (matching); 222 free (matching); 223 return_code = 3; 224 return; 225 } 226 227 if (bfd_check_format_matches (abfd, bfd_core, &matching)) 228 { 229 CONST char *core_cmd; 230 231 print_sizes (abfd); 232 fputs (" (core file", stdout); 233 234 core_cmd = bfd_core_file_failing_command (abfd); 235 if (core_cmd) 236 printf (" invoked as %s", core_cmd); 237 238 puts (")\n"); 239 return; 240 } 241 242 bfd_nonfatal (bfd_get_filename (abfd)); 243 244 if (bfd_get_error () == bfd_error_file_ambiguously_recognized) 245 { 246 list_matching_formats (matching); 247 free (matching); 248 } 249 250 return_code = 3; 251} 252 253static void 254display_archive (file) 255 bfd *file; 256{ 257 bfd *arfile = (bfd *) NULL; 258 259 for (;;) 260 { 261 bfd_set_error (bfd_error_no_error); 262 263 arfile = bfd_openr_next_archived_file (file, arfile); 264 if (arfile == NULL) 265 { 266 if (bfd_get_error () != bfd_error_no_more_archived_files) 267 { 268 bfd_nonfatal (bfd_get_filename (file)); 269 return_code = 2; 270 } 271 break; 272 } 273 274 display_bfd (arfile); 275 /* Don't close the archive elements; we need them for next_archive */ 276 } 277} 278 279static void 280display_file (filename) 281 char *filename; 282{ 283 bfd *file = bfd_openr (filename, target); 284 if (file == NULL) 285 { 286 bfd_nonfatal (filename); 287 return_code = 1; 288 return; 289 } 290 291 if (bfd_check_format (file, bfd_archive) == true) 292 display_archive (file); 293 else 294 display_bfd (file); 295 296 if (bfd_close (file) == false) 297 { 298 bfd_nonfatal (filename); 299 return_code = 1; 300 return; 301 } 302} 303 304/* This is what lexical functions are for. */ 305 306static void 307lprint_number (width, num) 308 int width; 309 bfd_size_type num; 310{ 311 printf ((radix == decimal ? "%-*lu\t" : 312 ((radix == octal) ? "%-*lo\t" : "%-*lx\t")), 313 width, (unsigned long) num); 314} 315 316static void 317rprint_number (width, num) 318 int width; 319 bfd_size_type num; 320{ 321 printf ((radix == decimal ? "%*lu\t" : 322 ((radix == octal) ? "%*lo\t" : "%*lx\t")), 323 width, (unsigned long) num); 324} 325 326static bfd_size_type bsssize; 327static bfd_size_type datasize; 328static bfd_size_type textsize; 329 330static void 331berkeley_sum (abfd, sec, ignore) 332 bfd *abfd; 333 sec_ptr sec; 334 PTR ignore; 335{ 336 flagword flags; 337 bfd_size_type size; 338 339 flags = bfd_get_section_flags (abfd, sec); 340 if ((flags & SEC_ALLOC) == 0) 341 return; 342 343 size = bfd_get_section_size_before_reloc (sec); 344 if ((flags & SEC_CODE) != 0 || (flags & SEC_READONLY) != 0) 345 textsize += size; 346 else if ((flags & SEC_HAS_CONTENTS) != 0) 347 datasize += size; 348 else 349 bsssize += size; 350} 351 352static void 353print_berkeley_format (abfd) 354 bfd *abfd; 355{ 356 static int files_seen = 0; 357 bfd_size_type total; 358 359 bsssize = 0; 360 datasize = 0; 361 textsize = 0; 362 363 bfd_map_over_sections (abfd, berkeley_sum, (PTR) NULL); 364 365 if (files_seen++ == 0) 366#if 0 367 /* Intel doesn't like bss/stk because they don't have core files. */ 368 puts ((radix == octal) ? "text\tdata\tbss/stk\toct\thex\tfilename" : 369 "text\tdata\tbss/stk\tdec\thex\tfilename"); 370#else 371 puts ((radix == octal) ? "text\tdata\tbss\toct\thex\tfilename" : 372 "text\tdata\tbss\tdec\thex\tfilename"); 373#endif 374 375 total = textsize + datasize + bsssize; 376 377 lprint_number (7, textsize); 378 lprint_number (7, datasize); 379 lprint_number (7, bsssize); 380 printf (((radix == octal) ? "%-7lo\t%-7lx\t" : "%-7lu\t%-7lx\t"), 381 (unsigned long) total, (unsigned long) total); 382 383 fputs (bfd_get_filename (abfd), stdout); 384 if (bfd_my_archive (abfd)) 385 printf (" (ex %s)", bfd_get_filename (bfd_my_archive (abfd))); 386} 387 388/* I REALLY miss lexical functions! */ 389bfd_size_type svi_total = 0; 390 391static void 392sysv_internal_printer (file, sec, ignore) 393 bfd *file; 394 sec_ptr sec; 395 PTR ignore; 396{ 397 bfd_size_type size = bfd_section_size (file, sec); 398 if (!bfd_is_abs_section (sec) 399 && !bfd_is_com_section (sec) 400 && !bfd_is_und_section (sec)) 401 { 402 svi_total += size; 403 404 printf ("%-12s", bfd_section_name (file, sec)); 405 rprint_number (8, size); 406 printf (" "); 407 rprint_number (8, bfd_section_vma (file, sec)); 408 printf ("\n"); 409 } 410} 411 412static void 413print_sysv_format (file) 414 bfd *file; 415{ 416 svi_total = 0; 417 418 printf ("%s ", bfd_get_filename (file)); 419 if (bfd_my_archive (file)) 420 printf (" (ex %s)", bfd_get_filename (bfd_my_archive (file))); 421 422 puts (":\nsection\t\tsize\t addr"); 423 bfd_map_over_sections (file, sysv_internal_printer, (PTR) NULL); 424 425 printf ("Total "); 426 rprint_number (8, svi_total); 427 printf ("\n\n"); 428} 429 430static void 431print_sizes (file) 432 bfd *file; 433{ 434 if (berkeley_format) 435 print_berkeley_format (file); 436 else 437 print_sysv_format (file); 438} 439