* Makefile.in (dist): Fix permissions before release.
[external/binutils.git] / binutils / size.c
1 /* size.c -- report size of various sections of an executable file.
2    Copyright 1991, 1992 Free Software Foundation, Inc.
3
4 This file is part of GNU Binutils.
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
19
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 +predantic switch.
30 */
31
32 #include "bfd.h"
33 #include "sysdep.h"
34 #include "getopt.h"
35
36 #ifndef BSD_DEFAULT
37 #define BSD_DEFAULT 1
38 #endif
39
40 /* Various program options */
41
42 enum {decimal, octal, hex} radix = decimal;
43 int berkeley_format = BSD_DEFAULT; /* 0 means use AT&T-style output */
44 int show_version = 0;
45 int show_help = 0;
46
47 int return_code = 0;
48
49 /* IMPORTS */
50 extern char *program_version;
51 extern char *program_name;
52 extern char *target;
53
54 /* Forward declarations */
55
56 static void
57 display_file PARAMS ((char *filename));
58
59 static void
60 print_sizes PARAMS ((bfd *file));
61 \f
62 /** main and like trivia */
63
64 void
65 usage ()
66 {
67   fprintf (stderr, "size %s\nUsage: %s -{dox}{AB}V files ...\n",
68          program_version, program_name);
69   fputs("\t+radix={8|10|16} -- select appropriate output radix.\n\
70 \t-d -- output in decimal\n\
71 \t-o -- output in octal\n\
72 \t-x -- output in hex", stderr);
73   fputs("\t+format={Berkeley|SysV} -- select display format.\n\
74 \t-A -- SysV(AT&T) format\n\
75 \t-B -- BSD format", stderr);
76 #if BSD_DEFAULT
77   fputs("\t  (Default is +format=Berkeley)", stderr);
78 #else
79   fputs("\t  (Default is +format=SysV)", stderr);
80 #endif
81   fputs("\t-V, +version -- display program version, etc.\n\
82 \t+help -- this message\n", stderr);
83   exit(1);
84 }
85
86 struct option long_options[] = {{"radix",   no_argument, 0, 0},
87                                 {"format",  required_argument, 0, 0},
88                                 {"version", no_argument, &show_version, 1},
89                                 {"target",  optional_argument, NULL, 0},
90                                 {"help",    no_argument, &show_help, 1},
91                                 {0, no_argument, 0, 0}};
92
93 int
94 main (argc, argv)
95      int argc;
96      char **argv;
97 {
98   int temp;
99   int c;                        /* sez which option char */
100   int option_index = 0;
101   extern int optind;            /* steps thru options */
102   program_name = *argv;
103
104   bfd_init();
105
106   while ((c = getopt_long(argc, argv, "ABVdox", long_options,
107                           &option_index)) != EOF)
108     switch(c) {
109     case 0:
110       if (!strcmp("format",(long_options[option_index]).name)) {
111         switch(*optarg) {
112         case 'B': case 'b': berkeley_format = 1; break;
113         case 'S': case 's': berkeley_format = 0; break;
114         default: printf("Unknown option to +format: %s\n", optarg);
115           usage();
116         }
117         break;
118       }
119
120       if (!strcmp("target",(long_options[option_index]).name)) {
121         target = optarg;
122         break;
123       }
124
125       if (!strcmp("radix",(long_options[option_index]).name)) {
126 #ifdef ANSI_LIBRARIES
127         temp = strtol(optarg, NULL, 10);
128 #else
129         temp = atol(optarg);
130 #endif
131         switch(temp) {
132         case 10: radix = decimal; break;
133         case 8:  radix = octal; break;
134         case 16: radix = hex; break;
135         default: printf("Unknown radix: %s\n", optarg);
136           usage();
137         }
138       }
139       break;
140     case 'A': berkeley_format = 0; break;
141     case 'B': berkeley_format = 1; break;
142     case 'V': show_version = 1; break;
143     case 'd': radix = decimal; break;
144     case 'x': radix = hex; break;
145     case 'o': radix = octal; break;
146     case '?': usage();
147     }
148
149   if (show_version) printf("%s version %s\n", program_name, program_version);
150   if (show_help) usage();
151         
152   if (optind == argc)
153     display_file ("a.out");
154   else
155     for (; optind < argc;)
156       display_file (argv[optind++]);
157
158   return return_code;
159 }
160 \f
161 /** Display a file's stats */
162
163 void
164 display_bfd (abfd)
165      bfd *abfd;
166 {
167   CONST  char *core_cmd;
168
169   if (bfd_check_format(abfd, bfd_archive)) return;
170
171   if (bfd_check_format(abfd, bfd_object)) {
172     print_sizes(abfd);
173     goto done;
174   }
175
176   if (bfd_check_format(abfd, bfd_core)) {
177     print_sizes(abfd);
178     fputs(" (core file", stdout);
179
180     core_cmd = bfd_core_file_failing_command(abfd);
181     if (core_cmd) printf(" invoked as %s", core_cmd);
182
183     puts(")");
184     goto done;
185   }
186   
187   printf("Unknown file format: %s.", bfd_get_filename(abfd));
188   return_code = 3;
189
190  done:
191
192
193   printf("\n");
194   return;
195 }
196
197 static void
198 display_file(filename)
199      char *filename;
200 {
201   bfd *file, *arfile = (bfd *) NULL;
202
203   file = bfd_openr (filename, target);
204   if (file == NULL) {
205     bfd_perror (filename);
206     return_code = 1;
207     return;
208   }
209
210   if (bfd_check_format(file, bfd_archive) == true) {
211     for(;;) {
212       
213       bfd_error = no_error;
214
215        arfile = bfd_openr_next_archived_file (file, arfile);
216       if (arfile == NULL) {
217         if (bfd_error != no_more_archived_files) {
218           bfd_perror (bfd_get_filename (file));
219           return_code = 2;
220         }
221         return;
222       }
223
224       display_bfd (arfile);
225       /* Don't close the archive elements; we need them for next_archive */
226     }
227   }
228   else
229     display_bfd (file);
230
231   bfd_close (file);
232 }
233 \f
234 /* This is what lexical functions are for */
235 void
236 lprint_number (width, num)
237      int width;
238      bfd_size_type num;
239 {
240   printf ((radix == decimal ? "%-*ld\t" :
241            ((radix == octal) ? "%-*lo\t" : "%-*lx\t")), width, (long)num);
242 }
243
244 void
245 rprint_number(width, num)
246      int width;
247      bfd_size_type num;
248 {
249   printf ((radix == decimal ? "%*ld\t" :
250            ((radix == octal) ? "%*lo\t" : "%*lx\t")), width, (long)num);
251 }
252
253 static char *bss_section_name = ".bss";
254 static char *data_section_name = ".data";
255 static char *stack_section_name = ".stack";
256 static char *text_section_name = ".text";
257
258 void print_berkeley_format(abfd)
259 bfd *abfd;
260 {
261   static int files_seen = 0;
262   sec_ptr bsssection = NULL;
263   sec_ptr datasection = NULL;
264   sec_ptr textsection = NULL;
265   bfd_size_type bsssize = 0;
266   bfd_size_type datasize = 0;
267   bfd_size_type textsize = 0;
268   bfd_size_type total = 0;
269
270   
271   if ((textsection = bfd_get_section_by_name (abfd, text_section_name))
272       != NULL) {
273     textsize = bfd_get_section_size_before_reloc (textsection);
274   }
275
276   if ((datasection = bfd_get_section_by_name (abfd, data_section_name))
277       != NULL) {
278     datasize = bfd_get_section_size_before_reloc ( datasection);
279   }
280         
281   if (bfd_get_format (abfd) == bfd_object) {
282     if ((bsssection = bfd_get_section_by_name (abfd, bss_section_name))
283         != NULL) {
284       bsssize = bfd_section_size(abfd, bsssection);
285     }
286   } else {
287     if ((bsssection = bfd_get_section_by_name (abfd, stack_section_name))
288         != NULL) {
289       bsssize = bfd_section_size(abfd, bsssection);
290     }
291   }
292
293   if (files_seen++ == 0)
294 #if 0   /* intel doesn't like bss/stk b/c they don't gave core files */
295     puts((radix == octal) ? "text\tdata\tbss/stk\toct\thex\tfilename" :
296          "text\tdata\tbss/stk\tdec\thex\tfilename");
297 #else
298     puts((radix == octal) ? "text\tdata\tbss\toct\thex\tfilename" :
299          "text\tdata\tbss\tdec\thex\tfilename");
300 #endif
301         
302   total = textsize + datasize + bsssize;
303         
304   lprint_number (7, textsize);
305   lprint_number (7, datasize);
306   lprint_number (7, bsssize);
307   printf (((radix == octal) ? "%-7lo\t%-7lx\t" : "%-7ld\t%-7lx\t"),
308           (long)total, (long)total);
309
310   fputs(bfd_get_filename(abfd), stdout);
311   if (abfd->my_archive) printf (" (ex %s)", abfd->my_archive->filename);
312 }
313
314 /* I REALLY miss lexical functions! */
315 bfd_size_type svi_total = 0;
316
317 void
318 sysv_internal_printer(file, sec, ignore)
319      bfd *file;
320      sec_ptr sec;
321      PTR ignore;
322 {
323   bfd_size_type size = bfd_section_size (file, sec);
324   if (sec!= &bfd_abs_section 
325       && sec!= &bfd_com_section
326       && sec!=&bfd_und_section) 
327   {
328   
329     svi_total += size;
330         
331     printf ("%-12s", bfd_section_name(file, sec));
332     rprint_number (8, size);
333     printf(" ");
334     rprint_number (8, bfd_section_vma(file, sec));
335     printf ("\n");
336   }
337
338 }
339
340 void
341 print_sysv_format(file)
342      bfd *file;
343 {
344   svi_total = 0;
345
346   printf ("%s  ", bfd_get_filename (file));
347   if (file->my_archive) printf (" (ex %s)", file->my_archive->filename);
348
349   puts(":\nsection\t\tsize\t     addr");
350   bfd_map_over_sections (file, sysv_internal_printer, (PTR)NULL);
351
352   printf("Total       ");
353   rprint_number(8, svi_total);
354   printf("\n");  printf("\n");
355 }
356
357 static void
358 print_sizes(file)
359      bfd *file;
360 {
361   if (berkeley_format)
362     print_berkeley_format(file);
363   else print_sysv_format(file);
364 }