xref: /illumos-gate/usr/src/cmd/sgs/elfdump/common/main.c (revision c809c407c9c41d440fda0f2f904036185432957c)
15aefb655Srie /*
25aefb655Srie  * CDDL HEADER START
35aefb655Srie  *
45aefb655Srie  * The contents of this file are subject to the terms of the
55aefb655Srie  * Common Development and Distribution License (the "License").
65aefb655Srie  * You may not use this file except in compliance with the License.
75aefb655Srie  *
85aefb655Srie  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
95aefb655Srie  * or http://www.opensolaris.org/os/licensing.
105aefb655Srie  * See the License for the specific language governing permissions
115aefb655Srie  * and limitations under the License.
125aefb655Srie  *
135aefb655Srie  * When distributing Covered Code, include this CDDL HEADER in each
145aefb655Srie  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
155aefb655Srie  * If applicable, add the following below this CDDL HEADER, with the
165aefb655Srie  * fields enclosed by brackets "[]" replaced with your own identifying
175aefb655Srie  * information: Portions Copyright [yyyy] [name of copyright owner]
185aefb655Srie  *
195aefb655Srie  * CDDL HEADER END
205aefb655Srie  */
215aefb655Srie 
225aefb655Srie /*
23d579eb63Sab  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
245aefb655Srie  * Use is subject to license terms.
255aefb655Srie  */
265aefb655Srie #pragma ident	"%Z%%M%	%I%	%E% SMI"
275aefb655Srie 
285aefb655Srie /*
295aefb655Srie  * Dump an elf file.
305aefb655Srie  */
315aefb655Srie #include	<sys/param.h>
325aefb655Srie #include	<fcntl.h>
335aefb655Srie #include	<stdio.h>
34*c809c407Sab #include	<stdlib.h>
35*c809c407Sab #include	<ctype.h>
365aefb655Srie #include	<libelf.h>
375aefb655Srie #include	<link.h>
385aefb655Srie #include	<stdarg.h>
395aefb655Srie #include	<unistd.h>
405aefb655Srie #include	<libgen.h>
415aefb655Srie #include	<libintl.h>
425aefb655Srie #include	<locale.h>
435aefb655Srie #include	<errno.h>
445aefb655Srie #include	<strings.h>
455aefb655Srie #include	<debug.h>
465aefb655Srie #include	<conv.h>
475aefb655Srie #include	<msg.h>
485aefb655Srie #include	<_elfdump.h>
495aefb655Srie 
5031fdd7caSab const Cache	cache_init = {NULL, NULL, NULL, NULL, 0};
515aefb655Srie 
52*c809c407Sab 
53*c809c407Sab 
54*c809c407Sab /* MATCH is  used to retain information about -N and -I options */
55*c809c407Sab typedef enum {
56*c809c407Sab 	MATCH_T_NAME,		/* Record contains a name */
57*c809c407Sab 	MATCH_T_NDX,		/* Record contains a single index */
58*c809c407Sab 	MATCH_T_RANGE		/* Record contains an index range */
59*c809c407Sab } MATCH_T;
60*c809c407Sab 
61*c809c407Sab typedef struct _match {
62*c809c407Sab 	struct _match	*next;		/* Pointer to next item in list */
63*c809c407Sab 	MATCH_T		type;
64*c809c407Sab 	union {
65*c809c407Sab 		const char	*name;	/* MATCH_T_NAME */
66*c809c407Sab 		struct {		/* MATCH_T_NDX and MATCH_T_RANGE */
67*c809c407Sab 			int	start;
68*c809c407Sab 			int	end;	/* Only for MATCH_T_RANGE */
69*c809c407Sab 		} ndx;
70*c809c407Sab 	} value;
71*c809c407Sab } MATCH;
72*c809c407Sab 
73*c809c407Sab /* List of MATCH records used by match() to implement -N and -I options */
74*c809c407Sab static MATCH *match_list = NULL;
75*c809c407Sab 
765aefb655Srie const char *
775aefb655Srie _elfdump_msg(Msg mid)
785aefb655Srie {
795aefb655Srie 	return (gettext(MSG_ORIG(mid)));
805aefb655Srie }
815aefb655Srie 
825aefb655Srie /*
835aefb655Srie  * Determine whether a symbol name should be demangled.
845aefb655Srie  */
855aefb655Srie const char *
865aefb655Srie demangle(const char *name, uint_t flags)
875aefb655Srie {
885aefb655Srie 	if (flags & FLG_DEMANGLE)
895aefb655Srie 		return (Elf_demangle_name(name));
905aefb655Srie 	else
915aefb655Srie 		return ((char *)name);
925aefb655Srie }
935aefb655Srie 
945aefb655Srie /*
955aefb655Srie  * Define our own standard error routine.
965aefb655Srie  */
975aefb655Srie void
985aefb655Srie failure(const char *file, const char *func)
995aefb655Srie {
1005aefb655Srie 	(void) fprintf(stderr, MSG_INTL(MSG_ERR_FAILURE),
1015aefb655Srie 	    file, func, elf_errmsg(elf_errno()));
1025aefb655Srie }
1035aefb655Srie 
1045aefb655Srie /*
1055aefb655Srie  * The full usage message
1065aefb655Srie  */
1075aefb655Srie static void
1085aefb655Srie detail_usage()
1095aefb655Srie {
1105aefb655Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL1));
1115aefb655Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL2));
1125aefb655Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL3));
1135aefb655Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL4));
1145aefb655Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL5));
1155aefb655Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL6));
1165aefb655Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL7));
1175aefb655Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL8));
1185aefb655Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL9));
1195aefb655Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL10));
1205aefb655Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL11));
1215aefb655Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL12));
1225aefb655Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL13));
1235aefb655Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL14));
1245aefb655Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL15));
1255aefb655Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL16));
1265aefb655Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL17));
1275aefb655Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL18));
1285aefb655Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL19));
1295aefb655Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL20));
130d579eb63Sab 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL21));
131*c809c407Sab 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL22));
132*c809c407Sab 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL23));
133*c809c407Sab }
134*c809c407Sab 
135*c809c407Sab /*
136*c809c407Sab  * Convert the ASCII representation of an index, or index range, into
137*c809c407Sab  * binary form, and store it in rec:
138*c809c407Sab  *
139*c809c407Sab  *	index: An positive or 0 valued integer
140*c809c407Sab  *	range: Two indexes, separated by a ':' character, denoting
141*c809c407Sab  *		a range of allowed values. If the second value is omitted,
142*c809c407Sab  *		any values equal to or greater than the first will match.
143*c809c407Sab  *
144*c809c407Sab  * exit:
145*c809c407Sab  *	On success, *rec is filled in with a MATCH_T_NDX or MATCH_T_RANGE
146*c809c407Sab  *	value, and this function returns (1). On failure, the contents
147*c809c407Sab  *	of *rec are undefined, and (0) is returned.
148*c809c407Sab  */
149*c809c407Sab int
150*c809c407Sab process_index_opt(const char *str, MATCH *rec)
151*c809c407Sab {
152*c809c407Sab #define	SKIP_BLANK for (; *str && isspace(*str); str++)
153*c809c407Sab 
154*c809c407Sab 	char	*endptr;
155*c809c407Sab 
156*c809c407Sab 	rec->value.ndx.start = strtol(str, &endptr, 10);
157*c809c407Sab 	/* Value must use some of the input, and be 0 or positive */
158*c809c407Sab 	if ((str == endptr) || (rec->value.ndx.start < 0))
159*c809c407Sab 		return (0);
160*c809c407Sab 	str = endptr;
161*c809c407Sab 
162*c809c407Sab 	SKIP_BLANK;
163*c809c407Sab 	if (*str != ':') {
164*c809c407Sab 		rec->type = MATCH_T_NDX;
165*c809c407Sab 	} else {
166*c809c407Sab 		str++;					/* Skip the ':' */
167*c809c407Sab 		rec->type = MATCH_T_RANGE;
168*c809c407Sab 		SKIP_BLANK;
169*c809c407Sab 		if (*str == '\0') {
170*c809c407Sab 			rec->value.ndx.end = -1;	/* Indicates "to end" */
171*c809c407Sab 		} else {
172*c809c407Sab 			rec->value.ndx.end = strtol(str, &endptr, 10);
173*c809c407Sab 			if ((str == endptr) || (rec->value.ndx.end < 0))
174*c809c407Sab 				return (0);
175*c809c407Sab 			str = endptr;
176*c809c407Sab 			SKIP_BLANK;
177*c809c407Sab 		}
178*c809c407Sab 	}
179*c809c407Sab 
180*c809c407Sab 	/* Syntax error if anything is left over */
181*c809c407Sab 	if (*str != '\0')
182*c809c407Sab 		return (0);
183*c809c407Sab 
184*c809c407Sab 	return (1);
185*c809c407Sab 
186*c809c407Sab #undef	SKIP_BLANK
187*c809c407Sab }
188*c809c407Sab 
189*c809c407Sab /*
190*c809c407Sab  * Returns True (1) if the item with the given name or index should
191*c809c407Sab  * be displayed, and False (0) if it should not be.
192*c809c407Sab  *
193*c809c407Sab  * entry:
194*c809c407Sab  *	strict - A strict match requires an explicit match to
195*c809c407Sab  *		a user specified -I or -N option. A non-strict match
196*c809c407Sab  *		succeeds if the match list is empty.
197*c809c407Sab  *	name - Name of item under consideration, or NULL if the name
198*c809c407Sab  *		should not be considered.
199*c809c407Sab  *	ndx - if (ndx >= 0) index of item under consideration.
200*c809c407Sab  *		A negative value indicates that the item has no index.
201*c809c407Sab  *
202*c809c407Sab  * exit:
203*c809c407Sab  *	True will be returned if the given name/index matches those given
204*c809c407Sab  *	by one of the -N or -I command line options, or if no such option
205*c809c407Sab  *	was used in the command invocation.
206*c809c407Sab  */
207*c809c407Sab int
208*c809c407Sab match(int strict, const char *name, int ndx)
209*c809c407Sab {
210*c809c407Sab 	MATCH *list;
211*c809c407Sab 
212*c809c407Sab 	/* If no match options were specified, allow everything */
213*c809c407Sab 	if (!strict && (match_list == NULL))
214*c809c407Sab 		return (1);
215*c809c407Sab 
216*c809c407Sab 	/* Run through the match records and check for a hit */
217*c809c407Sab 	for (list = match_list; list; list = list->next) {
218*c809c407Sab 		switch (list->type) {
219*c809c407Sab 		case MATCH_T_NAME:
220*c809c407Sab 			if ((name != NULL) &&
221*c809c407Sab 			    (strcmp(list->value.name, name) == 0))
222*c809c407Sab 				return (1);
223*c809c407Sab 			break;
224*c809c407Sab 		case MATCH_T_NDX:
225*c809c407Sab 			if (ndx == list->value.ndx.start)
226*c809c407Sab 				return (1);
227*c809c407Sab 			break;
228*c809c407Sab 		case MATCH_T_RANGE:
229*c809c407Sab 			/*
230*c809c407Sab 			 * A range end value less than 0 means that any value
231*c809c407Sab 			 * above the start is acceptible.
232*c809c407Sab 			 */
233*c809c407Sab 			if ((ndx >= list->value.ndx.start) &&
234*c809c407Sab 			    ((list->value.ndx.end < 0) ||
235*c809c407Sab 			    (ndx <= list->value.ndx.end)))
236*c809c407Sab 				return (1);
237*c809c407Sab 			break;
238*c809c407Sab 		}
239*c809c407Sab 	}
240*c809c407Sab 
241*c809c407Sab 	/* Nothing matched */
242*c809c407Sab 	return (0);
243*c809c407Sab }
244*c809c407Sab 
245*c809c407Sab /*
246*c809c407Sab  * Add an entry to match_list for use by match().
247*c809c407Sab  *
248*c809c407Sab  * Return True (1) for success. On failure, an error is written
249*c809c407Sab  * to stderr, and False (0) is returned.
250*c809c407Sab  */
251*c809c407Sab static int
252*c809c407Sab add_match_record(char *argv0, MATCH *data)
253*c809c407Sab {
254*c809c407Sab 	MATCH *rec;
255*c809c407Sab 	MATCH *list;
256*c809c407Sab 
257*c809c407Sab 	if ((rec = malloc(sizeof (*rec))) == NULL) {
258*c809c407Sab 		int err = errno;
259*c809c407Sab 		(void) fprintf(stderr, MSG_INTL(MSG_ERR_MALLOC),
260*c809c407Sab 		    basename(argv0), strerror(err));
261*c809c407Sab 		return (0);
262*c809c407Sab 	}
263*c809c407Sab 
264*c809c407Sab 	*rec = *data;
265*c809c407Sab 
266*c809c407Sab 	/* Insert at end of match_list */
267*c809c407Sab 	if (match_list == NULL) {
268*c809c407Sab 		match_list = rec;
269*c809c407Sab 	} else {
270*c809c407Sab 		for (list = match_list; list->next != NULL; list = list->next)
271*c809c407Sab 			;
272*c809c407Sab 		list->next = rec;
273*c809c407Sab 	}
274*c809c407Sab 
275*c809c407Sab 	rec->next = NULL;
276*c809c407Sab 	return (1);
2775aefb655Srie }
2785aefb655Srie 
2795aefb655Srie static void
280*c809c407Sab decide(const char *file, Elf *elf, uint_t flags, int wfd)
2815aefb655Srie {
2825aefb655Srie 	if (gelf_getclass(elf) == ELFCLASS64)
283*c809c407Sab 		regular64(file, elf, flags, wfd);
2845aefb655Srie 	else
285*c809c407Sab 		regular32(file, elf, flags, wfd);
2865aefb655Srie }
2875aefb655Srie 
2885aefb655Srie static void
289*c809c407Sab archive(const char *file, int fd, Elf *elf, uint_t flags, int wfd)
2905aefb655Srie {
2915aefb655Srie 	Elf_Cmd		cmd = ELF_C_READ;
2925aefb655Srie 	Elf_Arhdr	*arhdr;
2935aefb655Srie 	Elf		*_elf = 0;
2945aefb655Srie 	size_t		ptr;
2955aefb655Srie 	Elf_Arsym	*arsym = 0;
2965aefb655Srie 
2975aefb655Srie 	/*
298d579eb63Sab 	 * Determine if the archive symbol table itself is required.
2995aefb655Srie 	 */
300*c809c407Sab 	if ((flags & FLG_SYMBOLS) && match(0, MSG_ORIG(MSG_ELF_ARSYM), -1)) {
3015aefb655Srie 		/*
3025aefb655Srie 		 * Get the archive symbol table.
3035aefb655Srie 		 */
3045aefb655Srie 		if (((arsym = elf_getarsym(elf, &ptr)) == 0) && elf_errno()) {
3055aefb655Srie 			/*
3065aefb655Srie 			 * The arsym could be 0 even though there was no error.
3075aefb655Srie 			 * Print the error message only when there was
3085aefb655Srie 			 * real error from elf_getarsym().
3095aefb655Srie 			 */
3105aefb655Srie 			failure(file, MSG_ORIG(MSG_ELF_GETARSYM));
3115aefb655Srie 			return;
3125aefb655Srie 		}
3135aefb655Srie 	}
3145aefb655Srie 
3155aefb655Srie 	/*
3165aefb655Srie 	 * Print the archive symbol table only when the archive symbol
3175aefb655Srie 	 * table exists and it was requested to print.
3185aefb655Srie 	 */
3195aefb655Srie 	if (arsym) {
3205aefb655Srie 		size_t		cnt;
3215aefb655Srie 		char		index[MAXNDXSIZE];
3225aefb655Srie 		size_t		offset = 0, _offset = 0;
3235aefb655Srie 
3245aefb655Srie 		/*
3255aefb655Srie 		 * Print out all the symbol entries.
3265aefb655Srie 		 */
3275aefb655Srie 		dbg_print(0, MSG_INTL(MSG_ARCHIVE_SYMTAB));
3285aefb655Srie 		dbg_print(0, MSG_INTL(MSG_ARCHIVE_FIELDS));
3295aefb655Srie 
3305aefb655Srie 		for (cnt = 0; cnt < ptr; cnt++, arsym++) {
3315aefb655Srie 			/*
3325aefb655Srie 			 * For each object obtain an elf descriptor so that we
3335aefb655Srie 			 * can establish the members name.  Note, we have had
3345aefb655Srie 			 * archives where the archive header has not been
3355aefb655Srie 			 * obtainable so be lenient with errors.
3365aefb655Srie 			 */
3375aefb655Srie 			if ((offset == 0) || ((arsym->as_off != 0) &&
3385aefb655Srie 			    (arsym->as_off != _offset))) {
3395aefb655Srie 
3405aefb655Srie 				if (_elf)
3415aefb655Srie 					(void) elf_end(_elf);
3425aefb655Srie 
3435aefb655Srie 				if (elf_rand(elf, arsym->as_off) !=
3445aefb655Srie 				    arsym->as_off) {
3455aefb655Srie 					failure(file, MSG_ORIG(MSG_ELF_RAND));
3465aefb655Srie 					arhdr = 0;
3475aefb655Srie 				} else if ((_elf = elf_begin(fd,
3485aefb655Srie 				    ELF_C_READ, elf)) == 0) {
3495aefb655Srie 					failure(file, MSG_ORIG(MSG_ELF_BEGIN));
3505aefb655Srie 					arhdr = 0;
3515aefb655Srie 				} else if ((arhdr = elf_getarhdr(_elf)) == 0) {
3525aefb655Srie 					failure(file,
3535aefb655Srie 					    MSG_ORIG(MSG_ELF_GETARHDR));
3545aefb655Srie 					arhdr = 0;
3555aefb655Srie 				}
3565aefb655Srie 
3575aefb655Srie 				_offset = arsym->as_off;
3585aefb655Srie 				if (offset == 0)
3595aefb655Srie 					offset = _offset;
3605aefb655Srie 			}
3615aefb655Srie 
3625aefb655Srie 			(void) snprintf(index, MAXNDXSIZE,
3635aefb655Srie 			    MSG_ORIG(MSG_FMT_INDEX), EC_XWORD(cnt));
3645aefb655Srie 			if (arsym->as_off)
3655aefb655Srie 				dbg_print(0, MSG_ORIG(MSG_FMT_ARSYM1), index,
3665aefb655Srie 				    /* LINTED */
3675aefb655Srie 				    (int)arsym->as_off, arhdr ? arhdr->ar_name :
3685aefb655Srie 				    MSG_INTL(MSG_STR_UNKNOWN), (arsym->as_name ?
3695aefb655Srie 				    demangle(arsym->as_name, flags) :
3705aefb655Srie 				    MSG_INTL(MSG_STR_NULL)));
3715aefb655Srie 			else
3725aefb655Srie 				dbg_print(0, MSG_ORIG(MSG_FMT_ARSYM2), index,
3735aefb655Srie 				    /* LINTED */
3745aefb655Srie 				    (int)arsym->as_off);
3755aefb655Srie 		}
3765aefb655Srie 
3775aefb655Srie 		if (_elf)
3785aefb655Srie 			(void) elf_end(_elf);
3795aefb655Srie 
3805aefb655Srie 		/*
3815aefb655Srie 		 * If we only need the archive symbol table return.
3825aefb655Srie 		 */
383*c809c407Sab 		if ((flags & FLG_SYMBOLS) &&
384*c809c407Sab 		    match(1, MSG_ORIG(MSG_ELF_ARSYM), -1))
3855aefb655Srie 			return;
3865aefb655Srie 
3875aefb655Srie 		/*
3885aefb655Srie 		 * Reset elf descriptor in preparation for processing each
3895aefb655Srie 		 * member.
3905aefb655Srie 		 */
3915aefb655Srie 		if (offset)
3925aefb655Srie 			(void) elf_rand(elf, offset);
3935aefb655Srie 	}
3945aefb655Srie 
3955aefb655Srie 	/*
3965aefb655Srie 	 * Process each object within the archive.
3975aefb655Srie 	 */
3985aefb655Srie 	while ((_elf = elf_begin(fd, cmd, elf)) != NULL) {
3995aefb655Srie 		char	name[MAXPATHLEN];
4005aefb655Srie 
4015aefb655Srie 		if ((arhdr = elf_getarhdr(_elf)) == NULL) {
4025aefb655Srie 			failure(file, MSG_ORIG(MSG_ELF_GETARHDR));
4035aefb655Srie 			return;
4045aefb655Srie 		}
4055aefb655Srie 		if (*arhdr->ar_name != '/') {
4065aefb655Srie 			(void) snprintf(name, MAXPATHLEN,
4075aefb655Srie 			    MSG_ORIG(MSG_FMT_ARNAME), file, arhdr->ar_name);
4085aefb655Srie 			dbg_print(0, MSG_ORIG(MSG_FMT_NLSTR), name);
4095aefb655Srie 
4105aefb655Srie 			switch (elf_kind(_elf)) {
4115aefb655Srie 			case ELF_K_AR:
412*c809c407Sab 				archive(name, fd, _elf, flags, wfd);
4135aefb655Srie 				break;
4145aefb655Srie 			case ELF_K_ELF:
415*c809c407Sab 				decide(name, _elf, flags, wfd);
4165aefb655Srie 				break;
4175aefb655Srie 			default:
4185aefb655Srie 				(void) fprintf(stderr,
4195aefb655Srie 				    MSG_INTL(MSG_ERR_BADFILE), name);
4205aefb655Srie 				break;
4215aefb655Srie 			}
4225aefb655Srie 		}
4235aefb655Srie 
4245aefb655Srie 		cmd = elf_next(_elf);
4255aefb655Srie 		(void) elf_end(_elf);
4265aefb655Srie 	}
4275aefb655Srie }
4285aefb655Srie 
4295aefb655Srie int
4305aefb655Srie main(int argc, char **argv, char **envp)
4315aefb655Srie {
4325aefb655Srie 	Elf		*elf;
4335aefb655Srie 	int		var, fd, wfd = 0;
434*c809c407Sab 	char		*wname = 0;
4355aefb655Srie 	uint_t		flags = 0;
436*c809c407Sab 	MATCH		match_data;
4375aefb655Srie 
4385aefb655Srie 	/*
4395aefb655Srie 	 * If we're on a 64-bit kernel, try to exec a full 64-bit version of
4405aefb655Srie 	 * the binary.  If successful, conv_check_native() won't return.
4415aefb655Srie 	 */
4427010c12aSrie 	(void) conv_check_native(argv, envp);
4435aefb655Srie 
4445aefb655Srie 	/*
4455aefb655Srie 	 * Establish locale.
4465aefb655Srie 	 */
4475aefb655Srie 	(void) setlocale(LC_MESSAGES, MSG_ORIG(MSG_STR_EMPTY));
4485aefb655Srie 	(void) textdomain(MSG_ORIG(MSG_SUNW_OST_SGS));
4495aefb655Srie 
4505aefb655Srie 	(void) setvbuf(stdout, NULL, _IOLBF, 0);
4515aefb655Srie 	(void) setvbuf(stderr, NULL, _IOLBF, 0);
4525aefb655Srie 
4535aefb655Srie 	opterr = 0;
4545aefb655Srie 	while ((var = getopt(argc, argv, MSG_ORIG(MSG_STR_OPTIONS))) != EOF) {
4555aefb655Srie 		switch (var) {
4565aefb655Srie 		case 'C':
4575aefb655Srie 			flags |= FLG_DEMANGLE;
4585aefb655Srie 			break;
4595aefb655Srie 		case 'c':
4605aefb655Srie 			flags |= FLG_SHDR;
4615aefb655Srie 			break;
4625aefb655Srie 		case 'd':
4635aefb655Srie 			flags |= FLG_DYNAMIC;
4645aefb655Srie 			break;
4655aefb655Srie 		case 'e':
4665aefb655Srie 			flags |= FLG_EHDR;
4675aefb655Srie 			break;
4685aefb655Srie 		case 'G':
4695aefb655Srie 			flags |= FLG_GOT;
4705aefb655Srie 			break;
4715aefb655Srie 		case 'g':
4725aefb655Srie 			flags |= FLG_GROUP;
4735aefb655Srie 			break;
4745aefb655Srie 		case 'H':
4755aefb655Srie 			flags |= FLG_CAP;
4765aefb655Srie 			break;
4775aefb655Srie 		case 'h':
4785aefb655Srie 			flags |= FLG_HASH;
4795aefb655Srie 			break;
480*c809c407Sab 		case 'I':
481*c809c407Sab 			if (!process_index_opt(optarg, &match_data)) {
482*c809c407Sab 				(void) fprintf(stderr,
483*c809c407Sab 				    MSG_INTL(MSG_USAGE_BRIEF),
484*c809c407Sab 				    basename(argv[0]));
485*c809c407Sab 				return (1);
486*c809c407Sab 			}
487*c809c407Sab 			if (!add_match_record(argv[0], &match_data))
488*c809c407Sab 				return (1);
489*c809c407Sab 			break;
4905aefb655Srie 		case 'i':
4915aefb655Srie 			flags |= FLG_INTERP;
4925aefb655Srie 			break;
4935aefb655Srie 		case 'k':
4945aefb655Srie 			flags |= FLG_CHECKSUM;
4955aefb655Srie 			break;
4965aefb655Srie 		case 'l':
4975aefb655Srie 			flags |= FLG_LONGNAME;
4985aefb655Srie 			break;
4995aefb655Srie 		case 'm':
5005aefb655Srie 			flags |= FLG_MOVE;
5015aefb655Srie 			break;
5025aefb655Srie 		case 'N':
503*c809c407Sab 			match_data.type = MATCH_T_NAME;
504*c809c407Sab 			match_data.value.name = optarg;
505*c809c407Sab 			if (!add_match_record(argv[0], &match_data))
506*c809c407Sab 				return (1);
5075aefb655Srie 			break;
5085aefb655Srie 		case 'n':
5095aefb655Srie 			flags |= FLG_NOTE;
5105aefb655Srie 			break;
5115aefb655Srie 		case 'p':
5125aefb655Srie 			flags |= FLG_PHDR;
5135aefb655Srie 			break;
5145aefb655Srie 		case 'r':
5155aefb655Srie 			flags |= FLG_RELOC;
5165aefb655Srie 			break;
517d579eb63Sab 		case 'S':
518d579eb63Sab 			flags |= FLG_SORT;
519d579eb63Sab 			break;
5205aefb655Srie 		case 's':
5215aefb655Srie 			flags |= FLG_SYMBOLS;
5225aefb655Srie 			break;
5235aefb655Srie 		case 'u':
5245aefb655Srie 			flags |= FLG_UNWIND;
5255aefb655Srie 			break;
5265aefb655Srie 		case 'v':
5275aefb655Srie 			flags |= FLG_VERSIONS;
5285aefb655Srie 			break;
5295aefb655Srie 		case 'w':
5305aefb655Srie 			wname = optarg;
5315aefb655Srie 			break;
5325aefb655Srie 		case 'y':
5335aefb655Srie 			flags |= FLG_SYMINFO;
5345aefb655Srie 			break;
5355aefb655Srie 		case '?':
5365aefb655Srie 			(void) fprintf(stderr, MSG_INTL(MSG_USAGE_BRIEF),
5375aefb655Srie 			    basename(argv[0]));
5385aefb655Srie 			detail_usage();
5395aefb655Srie 			return (1);
5405aefb655Srie 		default:
5415aefb655Srie 			break;
5425aefb655Srie 		}
5435aefb655Srie 	}
5445aefb655Srie 
5455aefb655Srie 	/*
5465aefb655Srie 	 * Validate any arguments.
5475aefb655Srie 	 */
5485aefb655Srie 	if ((flags & ~(FLG_DEMANGLE | FLG_LONGNAME)) == 0) {
549*c809c407Sab 		if (!wname && (match_list == NULL)) {
5505aefb655Srie 			flags |= FLG_EVERYTHING;
551*c809c407Sab 		} else if (!wname || (match_list == NULL)) {
5525aefb655Srie 			(void) fprintf(stderr, MSG_INTL(MSG_USAGE_BRIEF),
5535aefb655Srie 			    basename(argv[0]));
5545aefb655Srie 			return (1);
5555aefb655Srie 		}
5565aefb655Srie 	}
5575aefb655Srie 
5585aefb655Srie 	if ((var = argc - optind) == 0) {
5595aefb655Srie 		(void) fprintf(stderr, MSG_INTL(MSG_USAGE_BRIEF),
5605aefb655Srie 		    basename(argv[0]));
5615aefb655Srie 		return (1);
5625aefb655Srie 	}
5635aefb655Srie 
5645aefb655Srie 	/*
5655aefb655Srie 	 * If the -l/-C option is specified, set up the liblddbg.so.
5665aefb655Srie 	 */
5675aefb655Srie 	if (flags & FLG_LONGNAME)
5685aefb655Srie 		dbg_desc->d_extra |= DBG_E_LONG;
5695aefb655Srie 	if (flags & FLG_DEMANGLE)
5705aefb655Srie 		dbg_desc->d_extra |= DBG_E_DEMANGLE;
5715aefb655Srie 
5725aefb655Srie 	/*
5735aefb655Srie 	 * If the -w option has indicated an output file open it.  It's
5745aefb655Srie 	 * arguable whether this option has much use when multiple files are
5755aefb655Srie 	 * being processed.
5765aefb655Srie 	 */
5775aefb655Srie 	if (wname) {
5785aefb655Srie 		if ((wfd = open(wname, (O_RDWR | O_CREAT | O_TRUNC),
5795aefb655Srie 		    0666)) < 0) {
5805aefb655Srie 			int err = errno;
5815aefb655Srie 			(void) fprintf(stderr, MSG_INTL(MSG_ERR_OPEN),
5825aefb655Srie 			    wname, strerror(err));
5835aefb655Srie 			wfd = 0;
5845aefb655Srie 		}
5855aefb655Srie 	}
5865aefb655Srie 
5875aefb655Srie 	/*
5885aefb655Srie 	 * Open the input file and initialize the elf interface.
5895aefb655Srie 	 */
5905aefb655Srie 	for (; optind < argc; optind++) {
5915aefb655Srie 		const char	*file = argv[optind];
5925aefb655Srie 
5935aefb655Srie 		if ((fd = open(argv[optind], O_RDONLY)) == -1) {
5945aefb655Srie 			int err = errno;
5955aefb655Srie 			(void) fprintf(stderr, MSG_INTL(MSG_ERR_OPEN),
5965aefb655Srie 			    file, strerror(err));
5975aefb655Srie 			continue;
5985aefb655Srie 		}
5995aefb655Srie 		(void) elf_version(EV_CURRENT);
6005aefb655Srie 		if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) {
6015aefb655Srie 			failure(file, MSG_ORIG(MSG_ELF_BEGIN));
6025aefb655Srie 			(void) close(fd);
6035aefb655Srie 			continue;
6045aefb655Srie 		}
6055aefb655Srie 
6065aefb655Srie 		if (var > 1)
6075aefb655Srie 			dbg_print(0, MSG_ORIG(MSG_FMT_NLSTRNL), file);
6085aefb655Srie 
6095aefb655Srie 		switch (elf_kind(elf)) {
6105aefb655Srie 		case ELF_K_AR:
611*c809c407Sab 			archive(file, fd, elf, flags, wfd);
6125aefb655Srie 			break;
6135aefb655Srie 		case ELF_K_ELF:
614*c809c407Sab 			decide(file, elf, flags, wfd);
6155aefb655Srie 			break;
6165aefb655Srie 		default:
6175aefb655Srie 			(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADFILE), file);
6185aefb655Srie 			break;
6195aefb655Srie 		}
6205aefb655Srie 
6215aefb655Srie 		(void) close(fd);
6225aefb655Srie 		(void) elf_end(elf);
6235aefb655Srie 	}
6245aefb655Srie 
6255aefb655Srie 	if (wfd)
6265aefb655Srie 		(void) close(wfd);
6275aefb655Srie 	return (0);
6285aefb655Srie }
629