1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21/*
22 * Copyright (c) 1988 AT&T
23 * Copyright (c) 1989 AT&T
24 * All Rights Reserved
25 *
26 *
27 * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
28 * Use is subject to license terms.
29 */
30
31#pragma ident	"%Z%%M%	%I%	%E% SMI"
32
33/* UNIX HEADERS */
34#include <stdio.h>
35#include <stdlib.h>
36#include <unistd.h>
37#include <fcntl.h>
38#include <libelf.h>
39
40
41/* SIZE HEADER */
42#include "defs.h"
43
44/* RELEASE STRING */
45#include "conv.h"
46#include "sgs.h"
47
48
49/* EXTERNAL VARIABLES DEFINED */
50int		fflag = 0,	/* print full output if -f option is supplied */
51		Fflag = 0,	/* print full output if -F option is supplied */
52		nflag = 0; 	/* include NOLOAD sections in size if -n */
53				/* option  is supplied */
54int		numbase = DECIMAL;
55static int	errflag = 0;	/* Global error flag */
56int		oneflag = 0;
57int		exitcode = 0;   /* Global exit code */
58char		*fname;
59char		*archive;
60int		is_archive = 0;
61
62static char	*tool_name;
63
64static void	usagerr();
65
66#define	OPTSTR "VoxnfF"		/* option string for usage error message */
67#define	GETOPTSTR "VoxnfF?"	/* option string for getopt */
68
69static Elf	*elf;
70static Elf_Arhdr	*arhdr;
71
72/*
73 *  main(argc, argv)
74 *
75 *  parses the command line
76 *  opens, processes and closes each object file command line argument
77 *
78 *  defines:
79 *      - int	numbase = HEX if the -x flag is in the command line
80 *			= OCTAL if the -o flag is in the command line
81 *			= DECIMAL if the -d flag is in the command line
82 *
83 *  calls:
84 *      - process(filename) to print the size information in the object file
85 *        filename
86 *
87 *  prints:
88 *      - an error message if any unknown options appear on the command line
89 *      - a usage message if no object file args appear on the command line
90 *      - an error message if it can't open an object file
91 *	      or if the object file has the wrong magic number
92 *
93 *  exits 1 - errors found, 0 - no errors
94 */
95int
96main(int argc, char ** argv, char ** envp)
97{
98	/* UNIX FUNCTIONS CALLED */
99	extern	void	error();
100
101	/* SIZE FUNCTIONS CALLED */
102	extern void process();
103
104	/* EXTERNAL VARIABLES USED */
105	extern int	numbase;
106	extern int	errflag;
107	extern int	oneflag;
108	extern int	optind;
109	extern char	*fname;
110
111	int c;
112	static int	fd;
113	extern char	*archive;
114	Elf_Cmd		cmd;
115	Elf		*arf;
116	unsigned	Vflag = 0;
117
118	/*
119	 * Check for a binary that better fits this architecture.
120	 */
121	(void) conv_check_native(argv, envp);
122
123	tool_name = argv[0];
124
125	while ((c = getopt(argc, argv, GETOPTSTR)) != EOF) {
126		switch (c) {
127		case 'o':
128			if (numbase != HEX)
129				numbase = OCTAL;
130			else
131				(void) fprintf(stderr,
132				"size: -x set, -o ignored\n");
133			break;
134
135		case 'd':
136			numbase = DECIMAL;
137			break;
138
139		case 'x':
140			if (numbase != OCTAL)
141				numbase = HEX;
142			else
143				(void) fprintf(stderr,
144				"size: -o set, -x ignored\n");
145			break;
146
147		case 'f':
148			fflag++;
149			break;
150
151		case 'F':
152			Fflag++;
153			break;
154
155		case 'n':
156			nflag++;
157			break;
158		case 'V':
159			(void) fprintf(stderr, "size: %s %s\n",
160			    (const char *)SGU_PKG,
161			    (const char *)SGU_REL);
162			Vflag++;
163			break;
164		case '?':
165			errflag++;
166			break;
167		default:
168			break;
169		}
170	}
171	if (errflag || (optind >= argc)) {
172		if (!(Vflag && (argc == 2) && !errflag)) {
173			usagerr();
174		}
175	}
176	if ((argc - optind) == 1) {
177		oneflag++;	/* only one file to process */
178	}
179
180	if (elf_version(EV_CURRENT) == EV_NONE) {
181		(void) fprintf(stderr, "size: Libelf is out of date");
182		exit(FATAL);	/* library out of date */
183	}
184
185	for (; optind < argc; optind++) {
186		fname = argv[optind];
187		if ((fd = open(argv[optind], O_RDONLY)) == -1) {
188			error(fname, "cannot open");
189		} else {
190			cmd = ELF_C_READ;
191			arf = 0;
192
193			if ((arf = elf_begin(fd, cmd, arf)) == 0) {
194				/* error(fname, "cannot open"); */
195				(void) fprintf(stderr,
196				"size: %s: %s\n", fname, elf_errmsg(-1));
197				return (FATAL);
198			}
199
200			if (elf_kind(arf) == ELF_K_AR) {
201				archive = argv[optind];
202			} else {
203				archive = "";
204			}
205
206			while ((elf = elf_begin(fd, cmd, arf)) != 0) {
207				if ((arhdr = elf_getarhdr(elf)) == 0) {
208					if (elf_kind(arf) == ELF_K_NONE) {
209						/* BEGIN CSTYLED */
210						(void) fprintf(stderr,
211						  "%s: %s: invalid file type\n",
212						    tool_name, fname);
213						/* END CSTYLED */
214						exitcode++;
215						break;
216					} else {
217						process(elf);
218					}
219				} else if (arhdr->ar_name[0] != '/') {
220					fname = arhdr->ar_name;
221					if (elf_kind(arf) == ELF_K_NONE) {
222						/* BEGIN CSTYLED */
223						(void) fprintf(stderr,
224					    "%s: %s[%s]: invalid file type\n",
225						    tool_name, archive, fname);
226						/* END CSTYLED */
227						exitcode++;
228						break;
229					} else {
230						is_archive++;
231						process(elf);
232					}
233				}
234				cmd = elf_next(elf);
235				(void) elf_end(elf);
236			}
237			(void) elf_end(arf);
238			(void) close(fd);
239		}
240	}
241	if (exitcode)
242		exit(FATAL);
243	else
244		exit(0);
245	return (0);
246}
247
248static void
249usagerr()
250{
251	(void) fprintf(stderr,
252	"usage: %s [-%s] file(s)...\n", tool_name, OPTSTR);
253	exitcode++;
254}
255