1/*
2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23/*	$OpenBSD: size.c,v 1.6 1997/01/28 07:12:27 deraadt Exp $	*/
24/*	$NetBSD: size.c,v 1.7 1996/01/14 23:07:12 pk Exp $	*/
25
26/*
27 * Copyright (c) 1988, 1993
28 *	The Regents of the University of California.  All rights reserved.
29 *
30 * Redistribution and use in source and binary forms, with or without
31 * modification, are permitted provided that the following conditions
32 * are met:
33 * 1. Redistributions of source code must retain the above copyright
34 *    notice, this list of conditions and the following disclaimer.
35 * 2. Redistributions in binary form must reproduce the above copyright
36 *    notice, this list of conditions and the following disclaimer in the
37 *    documentation and/or other materials provided with the distribution.
38 * 3. All advertising materials mentioning features or use of this software
39 *    must display the following acknowledgement:
40 *	This product includes software developed by the University of
41 *	California, Berkeley and its contributors.
42 * 4. Neither the name of the University nor the names of its contributors
43 *    may be used to endorse or promote products derived from this software
44 *    without specific prior written permission.
45 *
46 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
47 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
48 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
49 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
50 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
51 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
52 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
53 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
54 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
55 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
56 * SUCH DAMAGE.
57 */
58/*
59 * The NeXT Computer, Inc. size(1) program that handles fat files, archives and
60 * Mach-O objects files (no BSD a.out files).  A few lines of code were taken
61 * and adapted from the BSD release.
62 */
63#include <stdio.h>
64#include <stdlib.h>
65#include <string.h>
66#include "stuff/bool.h"
67#include "stuff/ofile.h"
68#include "stuff/errors.h"
69#include "stuff/allocate.h"
70
71char *progname = NULL;
72
73struct flags {
74    uint32_t nfiles;
75    enum bool m;
76    enum bool l;
77    enum bool x;
78};
79
80static void usage(
81    void);
82static void size(
83    struct ofile *ofile,
84    char *arch_name,
85    void *cookie);
86
87/* apple_version is created by the libstuff/Makefile */
88extern char apple_version[];
89char *version = apple_version;
90
91int
92main(
93int argc,
94char **argv,
95char **envp)
96{
97    int i;
98    enum bool args_left;
99    struct flags flag;
100    struct arch_flag *arch_flags;
101    uint32_t narch_flags;
102    enum bool all_archs;
103
104	progname = argv[0];
105	arch_flags = NULL;
106	narch_flags = 0;
107	all_archs = FALSE;
108
109	flag.nfiles = 0;
110	flag.m = FALSE;
111	flag.l = FALSE;
112	flag.x = FALSE;
113
114	for(i = 1; i < argc; i++){
115	    if(argv[i][0] == '-'){
116		if(argv[i][1] == '\0'){
117		    flag.nfiles += argc - i - 1;
118		    break;
119		}
120		if(strcmp(argv[i], "-m") == 0){
121		    flag.m = TRUE;
122		    continue;
123		}
124		if(strcmp(argv[i], "-l") == 0){
125		    flag.l = TRUE;
126		    flag.m = TRUE;
127		    continue;
128		}
129		if(strcmp(argv[i], "-x") == 0){
130		    flag.x = TRUE;
131		    flag.m = TRUE;
132		    continue;
133		}
134		if(strcmp(argv[i], "-arch") == 0){
135		    if(i + 1 == argc){
136			error("missing argument(s) to %s option", argv[i]);
137			usage();
138		    }
139		    if(strcmp("all", argv[i+1]) == 0){
140			all_archs = TRUE;
141		    }
142		    else{
143			arch_flags = reallocate(arch_flags,
144				(narch_flags + 1) * sizeof(struct arch_flag));
145			if(get_arch_from_flag(argv[i+1],
146					      arch_flags + narch_flags) == 0){
147			    error("unknown architecture specification flag: "
148				  "%s %s", argv[i], argv[i+1]);
149			    arch_usage();
150			    usage();
151			}
152			narch_flags++;
153		    }
154		    i++;
155		    continue;
156		}
157	    }
158	    flag.nfiles++;
159	}
160
161	if(flag.m == FALSE)
162	    printf("__TEXT\t__DATA\t__OBJC\tothers\tdec\thex\n");
163
164	args_left = TRUE;
165	for (i = 1; i < argc; i++) {
166	    if(args_left == TRUE && argv[i][0] == '-'){
167		if(argv[i][1] == '\0'){
168		    args_left = FALSE;
169		    continue;
170		}
171		if(strcmp(argv[i], "-m") == 0)
172		    continue;
173		if(strcmp(argv[i], "-l") == 0)
174		    continue;
175		if(strcmp(argv[i], "-x") == 0)
176		    continue;
177		if(strcmp(argv[i], "-arch") == 0){
178		    i++;
179		    continue;
180		}
181	    }
182	    ofile_process(argv[i], arch_flags, narch_flags, all_archs, FALSE,
183			  TRUE, TRUE, size, &flag);
184	}
185	if(flag.nfiles == 0)
186	    ofile_process("a.out", arch_flags, narch_flags, all_archs, FALSE,
187			  TRUE, TRUE, size, &flag);
188	if(errors == 0)
189	    return(EXIT_SUCCESS);
190	else
191	    return(EXIT_FAILURE);
192}
193
194/*
195 * usage() prints the current usage message and exits indicating failure.
196 */
197static
198void
199usage(
200void)
201{
202	fprintf(stderr, "Usage: %s [-m] [-l] [-x] [--] "
203		"[[-arch <arch_flag>] ...] [file ...]\n", progname);
204	exit(EXIT_FAILURE);
205}
206
207/*
208 * size() is the routine that gets called by ofile_process() to process single
209 * object files.
210 */
211static
212void
213size(
214struct ofile *ofile,
215char *arch_name,
216void *cookie)
217{
218    struct flags *flag;
219    uint64_t seg_sum, sect_sum;
220    uint32_t i, j;
221    struct load_command *lc;
222    struct segment_command *sg;
223    struct segment_command_64 *sg64;
224    struct section *s;
225    struct section_64 *s64;
226    uint64_t text, data, objc, others, sum;
227    uint32_t ncmds;
228
229	flag = (struct flags *)cookie;
230	if(ofile->mh != NULL)
231	    ncmds = ofile->mh->ncmds;
232	else
233	    ncmds = ofile->mh64->ncmds;
234	if(flag->m == TRUE){
235	    if(flag->nfiles > 1 || ofile->member_ar_hdr != NULL ||
236	       arch_name != NULL){
237		if(ofile->member_ar_hdr != NULL){
238		    printf("%s(%.*s)", ofile->file_name,
239			   (int)ofile->member_name_size,
240			   ofile->member_name);
241		}
242		else{
243		    printf("%s", ofile->file_name);
244		}
245		if(arch_name != NULL)
246		    printf(" (for architecture %s):\n", arch_name);
247		else
248		    printf(":\n");
249	    }
250	    lc = ofile->load_commands;
251	    seg_sum = 0;
252	    for(i = 0; i < ncmds; i++){
253		if(lc->cmd == LC_SEGMENT){
254		    sg = (struct segment_command *)lc;
255		    printf("Segment %.16s: ", sg->segname);
256		    if(flag->x == TRUE)
257			printf("0x%x", (unsigned int)sg->vmsize);
258		    else
259			printf("%u", sg->vmsize);
260		    if(sg->flags & SG_FVMLIB)
261			printf(" (fixed vm library segment)\n");
262		    else{
263			if(flag->l == TRUE)
264			    printf(" (vmaddr 0x%x fileoff %u)\n",
265				    (unsigned int)sg->vmaddr, sg->fileoff);
266			else
267			    printf("\n");
268		    }
269		    seg_sum += sg->vmsize;
270		    s = (struct section *)((char *)sg +
271			    sizeof(struct segment_command));
272		    sect_sum = 0;
273		    for(j = 0; j < sg->nsects; j++){
274			if(ofile->mh_filetype == MH_OBJECT)
275			    printf("\tSection (%.16s, %.16s): ",
276				   s->segname, s->sectname);
277			else
278			    printf("\tSection %.16s: ", s->sectname);
279			if(flag->x == TRUE)
280			    printf("0x%x", (unsigned int)s->size);
281			else
282			    printf("%u", s->size);
283			if(flag->l == TRUE)
284			    printf(" (addr 0x%x offset %u)\n",
285				    (unsigned int)s->addr, s->offset);
286			else
287			    printf("\n");
288			sect_sum += s->size;
289			s++;
290		    }
291		    if(sg->nsects > 0){
292			if(flag->x == TRUE)
293			    printf("\ttotal 0x%llx\n", sect_sum);
294			else
295			    printf("\ttotal %llu\n", sect_sum);
296		    }
297		}
298		else if(lc->cmd == LC_SEGMENT_64){
299		    sg64 = (struct segment_command_64 *)lc;
300		    printf("Segment %.16s: ", sg64->segname);
301		    if(flag->x == TRUE)
302			printf("0x%llx", sg64->vmsize);
303		    else
304			printf("%llu", sg64->vmsize);
305		    if(sg64->flags & SG_FVMLIB)
306			printf(" (fixed vm library segment)\n");
307		    else{
308			if(flag->l == TRUE)
309			    printf(" (vmaddr 0x%llx fileoff %llu)\n",
310				    sg64->vmaddr, sg64->fileoff);
311			else
312			    printf("\n");
313		    }
314		    seg_sum += sg64->vmsize;
315		    s64 = (struct section_64 *)((char *)sg64 +
316			    sizeof(struct segment_command_64));
317		    sect_sum = 0;
318		    for(j = 0; j < sg64->nsects; j++){
319			if(ofile->mh_filetype == MH_OBJECT)
320			    printf("\tSection (%.16s, %.16s): ",
321				   s64->segname, s64->sectname);
322			else
323			    printf("\tSection %.16s: ", s64->sectname);
324			if(flag->x == TRUE)
325			    printf("0x%llx", s64->size);
326			else
327			    printf("%llu", s64->size);
328			if(flag->l == TRUE)
329			    printf(" (addr 0x%llx offset %u)\n",
330				    s64->addr,
331				    s64->offset);
332			else
333			    printf("\n");
334			sect_sum += s64->size;
335			s64++;
336		    }
337		    if(sg64->nsects > 0){
338			if(flag->x == TRUE)
339			    printf("\ttotal 0x%llx\n", sect_sum);
340			else
341			    printf("\ttotal %llu\n", sect_sum);
342		    }
343		}
344		lc = (struct load_command *)((char *)lc + lc->cmdsize);
345	    }
346	    if(flag->x == TRUE)
347		printf("total 0x%llx\n", seg_sum);
348	    else
349		printf("total %llu\n", seg_sum);
350	}
351	else{
352	    text = 0;
353	    data = 0;
354	    objc = 0;
355	    others = 0;
356	    lc = ofile->load_commands;
357	    for(i = 0; i < ncmds; i++){
358		if(lc->cmd == LC_SEGMENT){
359		    sg = (struct segment_command *)lc;
360		    if(ofile->mh_filetype == MH_OBJECT){
361			s = (struct section *)((char *)sg +
362				sizeof(struct segment_command));
363			for(j = 0; j < sg->nsects; j++){
364			    if(strcmp(s->segname, SEG_TEXT) == 0)
365				text += s->size;
366			    else if(strcmp(s->segname, SEG_DATA) == 0)
367				data += s->size;
368			    else if(strcmp(s->segname, SEG_OBJC) == 0)
369				objc += s->size;
370			    else
371				others += s->size;
372			    s++;
373			}
374		    }
375		    else{
376			if(strcmp(sg->segname, SEG_TEXT) == 0)
377			    text += sg->vmsize;
378			else if(strcmp(sg->segname, SEG_DATA) == 0)
379			    data += sg->vmsize;
380			else if(strcmp(sg->segname, SEG_OBJC) == 0)
381			    objc += sg->vmsize;
382			else
383			    others += sg->vmsize;
384		    }
385		}
386		else if(lc->cmd == LC_SEGMENT_64){
387		    sg64 = (struct segment_command_64 *)lc;
388		    if(ofile->mh_filetype == MH_OBJECT){
389			s64 = (struct section_64 *)((char *)sg64 +
390				sizeof(struct segment_command_64));
391			for(j = 0; j < sg64->nsects; j++){
392			    if(strcmp(s64->segname, SEG_TEXT) == 0)
393				text += s64->size;
394			    else if(strcmp(s64->segname, SEG_DATA) == 0)
395				data += s64->size;
396			    else if(strcmp(s64->segname, SEG_OBJC) == 0)
397				objc += s64->size;
398			    else
399				others += s64->size;
400			    s64++;
401			}
402		    }
403		    else{
404			if(strcmp(sg64->segname, SEG_TEXT) == 0)
405			    text += sg64->vmsize;
406			else if(strcmp(sg64->segname, SEG_DATA) == 0)
407			    data += sg64->vmsize;
408			else if(strcmp(sg64->segname, SEG_OBJC) == 0)
409			    objc += sg64->vmsize;
410			else
411			    others += sg64->vmsize;
412		    }
413		}
414		lc = (struct load_command *)((char *)lc + lc->cmdsize);
415	    }
416	    printf("%llu\t%llu\t%llu\t%llu\t", text, data, objc, others);
417	    sum = text + data + objc + others;
418	    printf("%llu\t%llx", sum, sum);
419	    if(flag->nfiles > 1 || ofile->member_ar_hdr != NULL ||
420	       arch_name != NULL){
421		if(ofile->member_ar_hdr != NULL){
422		    printf("\t%s(%.*s)", ofile->file_name,
423			   (int)ofile->member_name_size,
424			   ofile->member_name);
425		}
426		else{
427		    printf("\t%s", ofile->file_name);
428		}
429		if(arch_name != NULL)
430		    printf(" (for architecture %s)", arch_name);
431	    }
432	    printf("\n");
433	}
434}
435