size.c revision 77298
16295Siignatyev/* size.c -- report size of various sections of an executable file. 211833Sctornqvi Copyright 1991, 92, 93, 94, 95, 96, 97, 98, 99, 2000 36295Siignatyev Free Software Foundation, Inc. 46295Siignatyev 56295SiignatyevThis file is part of GNU Binutils. 66295Siignatyev 76295SiignatyevThis program is free software; you can redistribute it and/or modify 86295Siignatyevit under the terms of the GNU General Public License as published by 96295Siignatyevthe Free Software Foundation; either version 2 of the License, or 106295Siignatyev(at your option) any later version. 116295Siignatyev 126295SiignatyevThis program is distributed in the hope that it will be useful, 136295Siignatyevbut WITHOUT ANY WARRANTY; without even the implied warranty of 146295SiignatyevMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 156295SiignatyevGNU General Public License for more details. 166295Siignatyev 176295SiignatyevYou should have received a copy of the GNU General Public License 186295Siignatyevalong with this program; if not, write to the Free Software 196295SiignatyevFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ 206295Siignatyev 216295Siignatyev/* Extensions/incompatibilities: 226295Siignatyev o - BSD output has filenames at the end. 236295Siignatyev o - BSD output can appear in different radicies. 246295Siignatyev o - SysV output has less redundant whitespace. Filename comes at end. 256295Siignatyev o - SysV output doesn't show VMA which is always the same as the PMA. 266295Siignatyev o - We also handle core files. 276295Siignatyev o - We also handle archives. 2811833Sctornqvi If you write shell scripts which manipulate this info then you may be 2910551Schegar out of luck; there's no --compatibility or --pedantic option. 308013Sykantser*/ 3113139Sepavlova 3211833Sctornqvi#include "bfd.h" 3311534Siignatyev#include "getopt.h" 3411534Siignatyev#include "bucomm.h" 356295Siignatyev#include "libiberty.h" 3611707Stpivovarova 3711707Stpivovarova#ifndef BSD_DEFAULT 386295Siignatyev#define BSD_DEFAULT 1 396295Siignatyev#endif 4011707Stpivovarova 4111707Stpivovarova/* Program options. */ 4211707Stpivovarova 4311707Stpivovarovaenum 4411707Stpivovarova { 4511707Stpivovarova decimal, octal, hex 4611707Stpivovarova } radix = decimal; 4711833Sctornqviint berkeley_format = BSD_DEFAULT; /* 0 means use AT&T-style output. */ 4811707Stpivovarovaint show_version = 0; 496295Siignatyevint show_help = 0; 506295Siignatyev 516295Siignatyev/* Program exit status. */ 526295Siignatyevint return_code = 0; 536295Siignatyev 546295Siignatyevstatic char *target = NULL; 556295Siignatyev 566295Siignatyev/* Static declarations */ 576295Siignatyev 586295Siignatyevstatic void usage PARAMS ((FILE *, int)); 596295Siignatyevstatic void display_file PARAMS ((char *filename)); 606295Siignatyevstatic void display_bfd PARAMS ((bfd *)); 6113139Sepavlovastatic void display_archive PARAMS ((bfd *)); 626295Siignatyevstatic int size_number PARAMS ((bfd_size_type)); 636295Siignatyev#if 0 646295Siignatyevstatic void lprint_number PARAMS ((int, bfd_size_type)); 656295Siignatyev#endif 666295Siignatyevstatic void rprint_number PARAMS ((int, bfd_size_type)); 676295Siignatyevstatic void print_berkeley_format PARAMS ((bfd *)); 686295Siignatyevstatic void sysv_internal_sizer PARAMS ((bfd *, asection *, PTR)); 696295Siignatyevstatic void sysv_internal_printer PARAMS ((bfd *, asection *, PTR)); 706295Siignatyevstatic void print_sysv_format PARAMS ((bfd *)); 716295Siignatyevstatic void print_sizes PARAMS ((bfd * file)); 726295Siignatyevstatic void berkeley_sum PARAMS ((bfd *, sec_ptr, PTR)); 736295Siignatyev 746295Siignatyevstatic void 756295Siignatyevusage (stream, status) 766295Siignatyev FILE *stream; 776295Siignatyev int status; 786295Siignatyev{ 796295Siignatyev fprintf (stream, _("\ 806295SiignatyevUsage: %s [-A | --format=sysv | -B | --format=berkeley]\n\ 816295Siignatyev [-o | --radix=8 | -d | --radix=10 | -h | --radix=16]\n\ 826295Siignatyev [-V | --version] [--target=bfdname] [--help] [file...]\n"), 836295Siignatyev program_name); 846295Siignatyev#if BSD_DEFAULT 856295Siignatyev fputs (_("default is --format=berkeley\n"), stream); 866295Siignatyev#else 876295Siignatyev fputs (_("default is --format=sysv\n"), stream); 886295Siignatyev#endif 896295Siignatyev list_supported_targets (program_name, stream); 906295Siignatyev if (status == 0) 916295Siignatyev fprintf (stream, _("Report bugs to %s\n"), REPORT_BUGS_TO); 926295Siignatyev exit (status); 936295Siignatyev} 9413139Sepavlova 956295Siignatyevstruct option long_options[] = 966295Siignatyev{ 97 {"format", required_argument, 0, 200}, 98 {"radix", required_argument, 0, 201}, 99 {"target", required_argument, 0, 202}, 100 {"version", no_argument, &show_version, 1}, 101 {"help", no_argument, &show_help, 1}, 102 {0, no_argument, 0, 0} 103}; 104 105int 106main (argc, argv) 107 int argc; 108 char **argv; 109{ 110 int temp; 111 int c; 112 113#if defined (HAVE_SETLOCALE) && defined (HAVE_LC_MESSAGES) 114 setlocale (LC_MESSAGES, ""); 115#endif 116 bindtextdomain (PACKAGE, LOCALEDIR); 117 textdomain (PACKAGE); 118 119 program_name = *argv; 120 xmalloc_set_program_name (program_name); 121 122 bfd_init (); 123 set_default_bfd_target (); 124 125 while ((c = getopt_long (argc, argv, "ABVdfox", long_options, 126 (int *) 0)) != EOF) 127 switch (c) 128 { 129 case 200: /* --format */ 130 switch (*optarg) 131 { 132 case 'B': 133 case 'b': 134 berkeley_format = 1; 135 break; 136 case 'S': 137 case 's': 138 berkeley_format = 0; 139 break; 140 default: 141 non_fatal (_("invalid argument to --format: %s"), optarg); 142 usage (stderr, 1); 143 } 144 break; 145 146 case 202: /* --target */ 147 target = optarg; 148 break; 149 150 case 201: /* --radix */ 151#ifdef ANSI_LIBRARIES 152 temp = strtol (optarg, NULL, 10); 153#else 154 temp = atol (optarg); 155#endif 156 switch (temp) 157 { 158 case 10: 159 radix = decimal; 160 break; 161 case 8: 162 radix = octal; 163 break; 164 case 16: 165 radix = hex; 166 break; 167 default: 168 non_fatal (_("Invalid radix: %s\n"), optarg); 169 usage (stderr, 1); 170 } 171 break; 172 173 case 'A': 174 berkeley_format = 0; 175 break; 176 case 'B': 177 berkeley_format = 1; 178 break; 179 case 'V': 180 show_version = 1; 181 break; 182 case 'd': 183 radix = decimal; 184 break; 185 case 'x': 186 radix = hex; 187 break; 188 case 'o': 189 radix = octal; 190 break; 191 case 'f': /* FIXME : For sysv68, `-f' means `full format', i.e. 192 `[fname:] M(.text) + N(.data) + O(.bss) + P(.comment) = Q' 193 where `fname: ' appears only if there are >= 2 input files, 194 and M, N, O, P, Q are expressed in decimal by default, 195 hexa or octal if requested by `-x' or `-o'. 196 Just to make things interesting, Solaris also accepts -f, 197 which prints out the size of each allocatable section, the 198 name of the section, and the total of the section sizes. */ 199 /* For the moment, accept `-f' silently, and ignore it. */ 200 break; 201 case 0: 202 break; 203 case '?': 204 usage (stderr, 1); 205 } 206 207 if (show_version) 208 print_version ("size"); 209 if (show_help) 210 usage (stdout, 0); 211 212 if (optind == argc) 213 display_file ("a.out"); 214 else 215 for (; optind < argc;) 216 display_file (argv[optind++]); 217 218 return return_code; 219} 220 221/* Display stats on file or archive member ABFD. */ 222 223static void 224display_bfd (abfd) 225 bfd *abfd; 226{ 227 char **matching; 228 229 if (bfd_check_format (abfd, bfd_archive)) 230 /* An archive within an archive. */ 231 return; 232 233 if (bfd_check_format_matches (abfd, bfd_object, &matching)) 234 { 235 print_sizes (abfd); 236 printf ("\n"); 237 return; 238 } 239 240 if (bfd_get_error () == bfd_error_file_ambiguously_recognized) 241 { 242 bfd_nonfatal (bfd_get_filename (abfd)); 243 list_matching_formats (matching); 244 free (matching); 245 return_code = 3; 246 return; 247 } 248 249 if (bfd_check_format_matches (abfd, bfd_core, &matching)) 250 { 251 CONST char *core_cmd; 252 253 print_sizes (abfd); 254 fputs (" (core file", stdout); 255 256 core_cmd = bfd_core_file_failing_command (abfd); 257 if (core_cmd) 258 printf (" invoked as %s", core_cmd); 259 260 puts (")\n"); 261 return; 262 } 263 264 bfd_nonfatal (bfd_get_filename (abfd)); 265 266 if (bfd_get_error () == bfd_error_file_ambiguously_recognized) 267 { 268 list_matching_formats (matching); 269 free (matching); 270 } 271 272 return_code = 3; 273} 274 275static void 276display_archive (file) 277 bfd *file; 278{ 279 bfd *arfile = (bfd *) NULL; 280 281 for (;;) 282 { 283 bfd_set_error (bfd_error_no_error); 284 285 arfile = bfd_openr_next_archived_file (file, arfile); 286 if (arfile == NULL) 287 { 288 if (bfd_get_error () != bfd_error_no_more_archived_files) 289 { 290 bfd_nonfatal (bfd_get_filename (file)); 291 return_code = 2; 292 } 293 break; 294 } 295 296 display_bfd (arfile); 297 /* Don't close the archive elements; we need them for next_archive */ 298 } 299} 300 301static void 302display_file (filename) 303 char *filename; 304{ 305 bfd *file = bfd_openr (filename, target); 306 if (file == NULL) 307 { 308 bfd_nonfatal (filename); 309 return_code = 1; 310 return; 311 } 312 313 if (bfd_check_format (file, bfd_archive) == true) 314 display_archive (file); 315 else 316 display_bfd (file); 317 318 if (bfd_close (file) == false) 319 { 320 bfd_nonfatal (filename); 321 return_code = 1; 322 return; 323 } 324} 325 326/* This is what lexical functions are for. */ 327 328static int 329size_number (num) 330 bfd_size_type num; 331{ 332 char buffer[40]; 333 sprintf (buffer, 334 (radix == decimal ? "%lu" : 335 ((radix == octal) ? "0%lo" : "0x%lx")), 336 (unsigned long) num); 337 338 return strlen (buffer); 339} 340 341#if 0 342 343/* This is not used. */ 344 345static void 346lprint_number (width, num) 347 int width; 348 bfd_size_type num; 349{ 350 char buffer[40]; 351 sprintf (buffer, 352 (radix == decimal ? "%lu" : 353 ((radix == octal) ? "0%lo" : "0x%lx")), 354 (unsigned long) num); 355 356 printf ("%-*s", width, buffer); 357} 358 359#endif 360 361static void 362rprint_number (width, num) 363 int width; 364 bfd_size_type num; 365{ 366 char buffer[40]; 367 sprintf (buffer, 368 (radix == decimal ? "%lu" : 369 ((radix == octal) ? "0%lo" : "0x%lx")), 370 (unsigned long) num); 371 372 printf ("%*s", width, buffer); 373} 374 375static bfd_size_type bsssize; 376static bfd_size_type datasize; 377static bfd_size_type textsize; 378 379static void 380berkeley_sum (abfd, sec, ignore) 381 bfd *abfd ATTRIBUTE_UNUSED; 382 sec_ptr sec; 383 PTR ignore ATTRIBUTE_UNUSED; 384{ 385 flagword flags; 386 bfd_size_type size; 387 388 flags = bfd_get_section_flags (abfd, sec); 389 if ((flags & SEC_ALLOC) == 0) 390 return; 391 392 size = bfd_get_section_size_before_reloc (sec); 393 if ((flags & SEC_CODE) != 0 || (flags & SEC_READONLY) != 0) 394 textsize += size; 395 else if ((flags & SEC_HAS_CONTENTS) != 0) 396 datasize += size; 397 else 398 bsssize += size; 399} 400 401static void 402print_berkeley_format (abfd) 403 bfd *abfd; 404{ 405 static int files_seen = 0; 406 bfd_size_type total; 407 408 bsssize = 0; 409 datasize = 0; 410 textsize = 0; 411 412 bfd_map_over_sections (abfd, berkeley_sum, (PTR) NULL); 413 414 if (files_seen++ == 0) 415#if 0 416 /* Intel doesn't like bss/stk because they don't have core files. */ 417 puts ((radix == octal) ? " text\t data\tbss/stk\t oct\t hex\tfilename" : 418 " text\t data\tbss/stk\t dec\t hex\tfilename"); 419#else 420 puts ((radix == octal) ? " text\t data\t bss\t oct\t hex\tfilename" : 421 " text\t data\t bss\t dec\t hex\tfilename"); 422#endif 423 424 total = textsize + datasize + bsssize; 425 426 rprint_number (7, textsize); 427 putchar ('\t'); 428 rprint_number (7, datasize); 429 putchar ('\t'); 430 rprint_number (7, bsssize); 431 printf (((radix == octal) ? "\t%7lo\t%7lx\t" : "\t%7lu\t%7lx\t"), 432 (unsigned long) total, (unsigned long) total); 433 434 fputs (bfd_get_filename (abfd), stdout); 435 if (bfd_my_archive (abfd)) 436 printf (" (ex %s)", bfd_get_filename (bfd_my_archive (abfd))); 437} 438 439/* I REALLY miss lexical functions! */ 440bfd_size_type svi_total = 0; 441bfd_vma svi_maxvma = 0; 442int svi_namelen = 0; 443int svi_vmalen = 0; 444int svi_sizelen = 0; 445 446static void 447sysv_internal_sizer (file, sec, ignore) 448 bfd *file ATTRIBUTE_UNUSED; 449 sec_ptr sec; 450 PTR ignore ATTRIBUTE_UNUSED; 451{ 452 bfd_size_type size = bfd_section_size (file, sec); 453 if (!bfd_is_abs_section (sec) 454 && !bfd_is_com_section (sec) 455 && !bfd_is_und_section (sec)) 456 { 457 int namelen = strlen (bfd_section_name (file, sec)); 458 if (namelen > svi_namelen) 459 svi_namelen = namelen; 460 461 svi_total += size; 462 if (bfd_section_vma (file, sec) > svi_maxvma) 463 svi_maxvma = bfd_section_vma (file, sec); 464 } 465} 466 467static void 468sysv_internal_printer (file, sec, ignore) 469 bfd *file ATTRIBUTE_UNUSED; 470 sec_ptr sec; 471 PTR ignore ATTRIBUTE_UNUSED; 472{ 473 bfd_size_type size = bfd_section_size (file, sec); 474 if (!bfd_is_abs_section (sec) 475 && !bfd_is_com_section (sec) 476 && !bfd_is_und_section (sec)) 477 { 478 svi_total += size; 479 480 printf ("%-*s ", svi_namelen, bfd_section_name (file, sec)); 481 rprint_number (svi_sizelen, size); 482 printf (" "); 483 rprint_number (svi_vmalen, bfd_section_vma (file, sec)); 484 printf ("\n"); 485 } 486} 487 488static void 489print_sysv_format (file) 490 bfd *file; 491{ 492 /* size all of the columns */ 493 svi_total = 0; 494 svi_maxvma = 0; 495 svi_namelen = 0; 496 bfd_map_over_sections (file, sysv_internal_sizer, (PTR) NULL); 497 svi_vmalen = size_number ((bfd_size_type)svi_maxvma); 498 if ((size_t) svi_vmalen < sizeof ("addr") - 1) 499 svi_vmalen = sizeof ("addr")-1; 500 501 svi_sizelen = size_number (svi_total); 502 if ((size_t) svi_sizelen < sizeof ("size") - 1) 503 svi_sizelen = sizeof ("size")-1; 504 505 svi_total = 0; 506 printf ("%s ", bfd_get_filename (file)); 507 if (bfd_my_archive (file)) 508 printf (" (ex %s)", bfd_get_filename (bfd_my_archive (file))); 509 510 printf (":\n%-*s %*s %*s\n", svi_namelen, "section", 511 svi_sizelen, "size", svi_vmalen, "addr"); 512 bfd_map_over_sections (file, sysv_internal_printer, (PTR) NULL); 513 514 printf ("%-*s ", svi_namelen, "Total"); 515 rprint_number (svi_sizelen, svi_total); 516 printf ("\n\n"); 517} 518 519static void 520print_sizes (file) 521 bfd *file; 522{ 523 if (berkeley_format) 524 print_berkeley_format (file); 525 else 526 print_sysv_format (file); 527} 528