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