size.c revision 60484
1/* size.c -- report size of various sections of an executable file. 2 Copyright 1991, 92, 93, 94, 95, 96, 97, 98, 99, 2000 3 Free Software Foundation, Inc. 4 5This file is part of GNU Binutils. 6 7This program is free software; you can redistribute it and/or modify 8it under the terms of the GNU General Public License as published by 9the Free Software Foundation; either version 2 of the License, or 10(at your option) any later version. 11 12This program is distributed in the hope that it will be useful, 13but WITHOUT ANY WARRANTY; without even the implied warranty of 14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15GNU General Public License for more details. 16 17You should have received a copy of the GNU General Public License 18along with this program; if not, write to the Free Software 19Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ 20 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 29 out of luck; there's no --compatibility or --pedantic option. 30*/ 31 32#include "bfd.h" 33#include "getopt.h" 34#include "bucomm.h" 35#include "libiberty.h" 36 37#ifndef BSD_DEFAULT 38#define BSD_DEFAULT 1 39#endif 40 41/* Program options. */ 42 43enum 44 { 45 decimal, octal, hex 46 } radix = decimal; 47int berkeley_format = BSD_DEFAULT; /* 0 means use AT&T-style output. */ 48int show_version = 0; 49int show_help = 0; 50 51/* Program exit status. */ 52int return_code = 0; 53 54static char *target = NULL; 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 int size_number PARAMS ((bfd_size_type)); 63#if 0 64static void lprint_number PARAMS ((int, bfd_size_type)); 65#endif 66static void rprint_number PARAMS ((int, bfd_size_type)); 67static void print_berkeley_format PARAMS ((bfd *)); 68static void sysv_internal_sizer PARAMS ((bfd *, asection *, PTR)); 69static void sysv_internal_printer PARAMS ((bfd *, asection *, PTR)); 70static void print_sysv_format PARAMS ((bfd *)); 71static void print_sizes PARAMS ((bfd * file)); 72static void berkeley_sum PARAMS ((bfd *, sec_ptr, PTR)); 73 74static void 75usage (stream, status) 76 FILE *stream; 77 int status; 78{ 79 fprintf (stream, _("\ 80Usage: %s [-ABdoxV] [--format=berkeley|sysv] [--radix=8|10|16]\n\ 81 [--target=bfdname] [--version] [--help] [file...]\n"), program_name); 82#if BSD_DEFAULT 83 fputs (_("default is --format=berkeley\n"), stream); 84#else 85 fputs (_("default is --format=sysv\n"), stream); 86#endif 87 list_supported_targets (program_name, stream); 88 if (status == 0) 89 fprintf (stream, _("Report bugs to %s\n"), REPORT_BUGS_TO); 90 exit (status); 91} 92 93struct option long_options[] = 94{ 95 {"format", required_argument, 0, 200}, 96 {"radix", required_argument, 0, 201}, 97 {"target", required_argument, 0, 202}, 98 {"version", no_argument, &show_version, 1}, 99 {"help", no_argument, &show_help, 1}, 100 {0, no_argument, 0, 0} 101}; 102 103int 104main (argc, argv) 105 int argc; 106 char **argv; 107{ 108 int temp; 109 int c; 110 111#if defined (HAVE_SETLOCALE) && defined (HAVE_LC_MESSAGES) 112 setlocale (LC_MESSAGES, ""); 113#endif 114 bindtextdomain (PACKAGE, LOCALEDIR); 115 textdomain (PACKAGE); 116 117 program_name = *argv; 118 xmalloc_set_program_name (program_name); 119 120 bfd_init (); 121 set_default_bfd_target (); 122 123 while ((c = getopt_long (argc, argv, "ABVdox", long_options, 124 (int *) 0)) != EOF) 125 switch (c) 126 { 127 case 200: /* --format */ 128 switch (*optarg) 129 { 130 case 'B': 131 case 'b': 132 berkeley_format = 1; 133 break; 134 case 'S': 135 case 's': 136 berkeley_format = 0; 137 break; 138 default: 139 non_fatal (_("invalid argument to --format: %s"), optarg); 140 usage (stderr, 1); 141 } 142 break; 143 144 case 202: /* --target */ 145 target = optarg; 146 break; 147 148 case 201: /* --radix */ 149#ifdef ANSI_LIBRARIES 150 temp = strtol (optarg, NULL, 10); 151#else 152 temp = atol (optarg); 153#endif 154 switch (temp) 155 { 156 case 10: 157 radix = decimal; 158 break; 159 case 8: 160 radix = octal; 161 break; 162 case 16: 163 radix = hex; 164 break; 165 default: 166 non_fatal (_("Invalid radix: %s\n"), optarg); 167 usage (stderr, 1); 168 } 169 break; 170 171 case 'A': 172 berkeley_format = 0; 173 break; 174 case 'B': 175 berkeley_format = 1; 176 break; 177 case 'V': 178 show_version = 1; 179 break; 180 case 'd': 181 radix = decimal; 182 break; 183 case 'x': 184 radix = hex; 185 break; 186 case 'o': 187 radix = octal; 188 break; 189 case 0: 190 break; 191 case '?': 192 usage (stderr, 1); 193 } 194 195 if (show_version) 196 print_version ("size"); 197 if (show_help) 198 usage (stdout, 0); 199 200 if (optind == argc) 201 display_file ("a.out"); 202 else 203 for (; optind < argc;) 204 display_file (argv[optind++]); 205 206 return return_code; 207} 208 209/* Display stats on file or archive member ABFD. */ 210 211static void 212display_bfd (abfd) 213 bfd *abfd; 214{ 215 char **matching; 216 217 if (bfd_check_format (abfd, bfd_archive)) 218 /* An archive within an archive. */ 219 return; 220 221 if (bfd_check_format_matches (abfd, bfd_object, &matching)) 222 { 223 print_sizes (abfd); 224 printf ("\n"); 225 return; 226 } 227 228 if (bfd_get_error () == bfd_error_file_ambiguously_recognized) 229 { 230 bfd_nonfatal (bfd_get_filename (abfd)); 231 list_matching_formats (matching); 232 free (matching); 233 return_code = 3; 234 return; 235 } 236 237 if (bfd_check_format_matches (abfd, bfd_core, &matching)) 238 { 239 CONST char *core_cmd; 240 241 print_sizes (abfd); 242 fputs (" (core file", stdout); 243 244 core_cmd = bfd_core_file_failing_command (abfd); 245 if (core_cmd) 246 printf (" invoked as %s", core_cmd); 247 248 puts (")\n"); 249 return; 250 } 251 252 bfd_nonfatal (bfd_get_filename (abfd)); 253 254 if (bfd_get_error () == bfd_error_file_ambiguously_recognized) 255 { 256 list_matching_formats (matching); 257 free (matching); 258 } 259 260 return_code = 3; 261} 262 263static void 264display_archive (file) 265 bfd *file; 266{ 267 bfd *arfile = (bfd *) NULL; 268 269 for (;;) 270 { 271 bfd_set_error (bfd_error_no_error); 272 273 arfile = bfd_openr_next_archived_file (file, arfile); 274 if (arfile == NULL) 275 { 276 if (bfd_get_error () != bfd_error_no_more_archived_files) 277 { 278 bfd_nonfatal (bfd_get_filename (file)); 279 return_code = 2; 280 } 281 break; 282 } 283 284 display_bfd (arfile); 285 /* Don't close the archive elements; we need them for next_archive */ 286 } 287} 288 289static void 290display_file (filename) 291 char *filename; 292{ 293 bfd *file = bfd_openr (filename, target); 294 if (file == NULL) 295 { 296 bfd_nonfatal (filename); 297 return_code = 1; 298 return; 299 } 300 301 if (bfd_check_format (file, bfd_archive) == true) 302 display_archive (file); 303 else 304 display_bfd (file); 305 306 if (bfd_close (file) == false) 307 { 308 bfd_nonfatal (filename); 309 return_code = 1; 310 return; 311 } 312} 313 314/* This is what lexical functions are for. */ 315 316static int 317size_number (num) 318 bfd_size_type num; 319{ 320 char buffer[40]; 321 sprintf (buffer, 322 (radix == decimal ? "%lu" : 323 ((radix == octal) ? "0%lo" : "0x%lx")), 324 (unsigned long) num); 325 326 return strlen (buffer); 327} 328 329#if 0 330 331/* This is not used. */ 332 333static void 334lprint_number (width, num) 335 int width; 336 bfd_size_type num; 337{ 338 char buffer[40]; 339 sprintf (buffer, 340 (radix == decimal ? "%lu" : 341 ((radix == octal) ? "0%lo" : "0x%lx")), 342 (unsigned long) num); 343 344 printf ("%-*s", width, buffer); 345} 346 347#endif 348 349static void 350rprint_number (width, num) 351 int width; 352 bfd_size_type num; 353{ 354 char buffer[40]; 355 sprintf (buffer, 356 (radix == decimal ? "%lu" : 357 ((radix == octal) ? "0%lo" : "0x%lx")), 358 (unsigned long) num); 359 360 printf ("%*s", width, buffer); 361} 362 363static bfd_size_type bsssize; 364static bfd_size_type datasize; 365static bfd_size_type textsize; 366 367static void 368berkeley_sum (abfd, sec, ignore) 369 bfd *abfd ATTRIBUTE_UNUSED; 370 sec_ptr sec; 371 PTR ignore ATTRIBUTE_UNUSED; 372{ 373 flagword flags; 374 bfd_size_type size; 375 376 flags = bfd_get_section_flags (abfd, sec); 377 if ((flags & SEC_ALLOC) == 0) 378 return; 379 380 size = bfd_get_section_size_before_reloc (sec); 381 if ((flags & SEC_CODE) != 0 || (flags & SEC_READONLY) != 0) 382 textsize += size; 383 else if ((flags & SEC_HAS_CONTENTS) != 0) 384 datasize += size; 385 else 386 bsssize += size; 387} 388 389static void 390print_berkeley_format (abfd) 391 bfd *abfd; 392{ 393 static int files_seen = 0; 394 bfd_size_type total; 395 396 bsssize = 0; 397 datasize = 0; 398 textsize = 0; 399 400 bfd_map_over_sections (abfd, berkeley_sum, (PTR) NULL); 401 402 if (files_seen++ == 0) 403#if 0 404 /* Intel doesn't like bss/stk because they don't have core files. */ 405 puts ((radix == octal) ? " text\t data\tbss/stk\t oct\t hex\tfilename" : 406 " text\t data\tbss/stk\t dec\t hex\tfilename"); 407#else 408 puts ((radix == octal) ? " text\t data\t bss\t oct\t hex\tfilename" : 409 " text\t data\t bss\t dec\t hex\tfilename"); 410#endif 411 412 total = textsize + datasize + bsssize; 413 414 rprint_number (7, textsize); 415 putchar ('\t'); 416 rprint_number (7, datasize); 417 putchar ('\t'); 418 rprint_number (7, bsssize); 419 printf (((radix == octal) ? "\t%7lo\t%7lx\t" : "\t%7lu\t%7lx\t"), 420 (unsigned long) total, (unsigned long) total); 421 422 fputs (bfd_get_filename (abfd), stdout); 423 if (bfd_my_archive (abfd)) 424 printf (" (ex %s)", bfd_get_filename (bfd_my_archive (abfd))); 425} 426 427/* I REALLY miss lexical functions! */ 428bfd_size_type svi_total = 0; 429bfd_vma svi_maxvma = 0; 430int svi_namelen = 0; 431int svi_vmalen = 0; 432int svi_sizelen = 0; 433 434static void 435sysv_internal_sizer (file, sec, ignore) 436 bfd *file ATTRIBUTE_UNUSED; 437 sec_ptr sec; 438 PTR ignore ATTRIBUTE_UNUSED; 439{ 440 bfd_size_type size = bfd_section_size (file, sec); 441 if (!bfd_is_abs_section (sec) 442 && !bfd_is_com_section (sec) 443 && !bfd_is_und_section (sec)) 444 { 445 int namelen = strlen (bfd_section_name (file, sec)); 446 if (namelen > svi_namelen) 447 svi_namelen = namelen; 448 449 svi_total += size; 450 if (bfd_section_vma (file, sec) > svi_maxvma) 451 svi_maxvma = bfd_section_vma (file, sec); 452 } 453} 454 455static void 456sysv_internal_printer (file, sec, ignore) 457 bfd *file ATTRIBUTE_UNUSED; 458 sec_ptr sec; 459 PTR ignore ATTRIBUTE_UNUSED; 460{ 461 bfd_size_type size = bfd_section_size (file, sec); 462 if (!bfd_is_abs_section (sec) 463 && !bfd_is_com_section (sec) 464 && !bfd_is_und_section (sec)) 465 { 466 svi_total += size; 467 468 printf ("%-*s ", svi_namelen, bfd_section_name (file, sec)); 469 rprint_number (svi_sizelen, size); 470 printf (" "); 471 rprint_number (svi_vmalen, bfd_section_vma (file, sec)); 472 printf ("\n"); 473 } 474} 475 476static void 477print_sysv_format (file) 478 bfd *file; 479{ 480 /* size all of the columns */ 481 svi_total = 0; 482 svi_maxvma = 0; 483 svi_namelen = 0; 484 bfd_map_over_sections (file, sysv_internal_sizer, (PTR) NULL); 485 svi_vmalen = size_number ((bfd_size_type)svi_maxvma); 486 if ((size_t) svi_vmalen < sizeof ("addr") - 1) 487 svi_vmalen = sizeof ("addr")-1; 488 489 svi_sizelen = size_number (svi_total); 490 if ((size_t) svi_sizelen < sizeof ("size") - 1) 491 svi_sizelen = sizeof ("size")-1; 492 493 svi_total = 0; 494 printf ("%s ", bfd_get_filename (file)); 495 if (bfd_my_archive (file)) 496 printf (" (ex %s)", bfd_get_filename (bfd_my_archive (file))); 497 498 printf (":\n%-*s %*s %*s\n", svi_namelen, "section", 499 svi_sizelen, "size", svi_vmalen, "addr"); 500 bfd_map_over_sections (file, sysv_internal_printer, (PTR) NULL); 501 502 printf ("%-*s ", svi_namelen, "Total"); 503 rprint_number (svi_sizelen, svi_total); 504 printf ("\n\n"); 505} 506 507static void 508print_sizes (file) 509 bfd *file; 510{ 511 if (berkeley_format) 512 print_berkeley_format (file); 513 else 514 print_sysv_format (file); 515} 516