xref: /onnv-gate/usr/src/cmd/sgs/elfdump/common/main.c (revision 4168:7a68e9a5dc29)
11618Srie /*
21618Srie  * CDDL HEADER START
31618Srie  *
41618Srie  * The contents of this file are subject to the terms of the
51618Srie  * Common Development and Distribution License (the "License").
61618Srie  * You may not use this file except in compliance with the License.
71618Srie  *
81618Srie  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
91618Srie  * or http://www.opensolaris.org/os/licensing.
101618Srie  * See the License for the specific language governing permissions
111618Srie  * and limitations under the License.
121618Srie  *
131618Srie  * When distributing Covered Code, include this CDDL HEADER in each
141618Srie  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
151618Srie  * If applicable, add the following below this CDDL HEADER, with the
161618Srie  * fields enclosed by brackets "[]" replaced with your own identifying
171618Srie  * information: Portions Copyright [yyyy] [name of copyright owner]
181618Srie  *
191618Srie  * CDDL HEADER END
201618Srie  */
211618Srie 
221618Srie /*
233492Sab196087  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
241618Srie  * Use is subject to license terms.
251618Srie  */
261618Srie #pragma ident	"%Z%%M%	%I%	%E% SMI"
271618Srie 
281618Srie /*
291618Srie  * Dump an elf file.
301618Srie  */
311618Srie #include	<sys/param.h>
321618Srie #include	<fcntl.h>
331618Srie #include	<stdio.h>
34*4168Sab196087 #include	<stdlib.h>
35*4168Sab196087 #include	<ctype.h>
361618Srie #include	<libelf.h>
371618Srie #include	<link.h>
381618Srie #include	<stdarg.h>
391618Srie #include	<unistd.h>
401618Srie #include	<libgen.h>
411618Srie #include	<libintl.h>
421618Srie #include	<locale.h>
431618Srie #include	<errno.h>
441618Srie #include	<strings.h>
451618Srie #include	<debug.h>
461618Srie #include	<conv.h>
471618Srie #include	<msg.h>
481618Srie #include	<_elfdump.h>
491618Srie 
504063Sab196087 const Cache	cache_init = {NULL, NULL, NULL, NULL, 0};
511618Srie 
52*4168Sab196087 
53*4168Sab196087 
54*4168Sab196087 /* MATCH is  used to retain information about -N and -I options */
55*4168Sab196087 typedef enum {
56*4168Sab196087 	MATCH_T_NAME,		/* Record contains a name */
57*4168Sab196087 	MATCH_T_NDX,		/* Record contains a single index */
58*4168Sab196087 	MATCH_T_RANGE		/* Record contains an index range */
59*4168Sab196087 } MATCH_T;
60*4168Sab196087 
61*4168Sab196087 typedef struct _match {
62*4168Sab196087 	struct _match	*next;		/* Pointer to next item in list */
63*4168Sab196087 	MATCH_T		type;
64*4168Sab196087 	union {
65*4168Sab196087 		const char	*name;	/* MATCH_T_NAME */
66*4168Sab196087 		struct {		/* MATCH_T_NDX and MATCH_T_RANGE */
67*4168Sab196087 			int	start;
68*4168Sab196087 			int	end;	/* Only for MATCH_T_RANGE */
69*4168Sab196087 		} ndx;
70*4168Sab196087 	} value;
71*4168Sab196087 } MATCH;
72*4168Sab196087 
73*4168Sab196087 /* List of MATCH records used by match() to implement -N and -I options */
74*4168Sab196087 static MATCH *match_list = NULL;
75*4168Sab196087 
761618Srie const char *
771618Srie _elfdump_msg(Msg mid)
781618Srie {
791618Srie 	return (gettext(MSG_ORIG(mid)));
801618Srie }
811618Srie 
821618Srie /*
831618Srie  * Determine whether a symbol name should be demangled.
841618Srie  */
851618Srie const char *
861618Srie demangle(const char *name, uint_t flags)
871618Srie {
881618Srie 	if (flags & FLG_DEMANGLE)
891618Srie 		return (Elf_demangle_name(name));
901618Srie 	else
911618Srie 		return ((char *)name);
921618Srie }
931618Srie 
941618Srie /*
951618Srie  * Define our own standard error routine.
961618Srie  */
971618Srie void
981618Srie failure(const char *file, const char *func)
991618Srie {
1001618Srie 	(void) fprintf(stderr, MSG_INTL(MSG_ERR_FAILURE),
1011618Srie 	    file, func, elf_errmsg(elf_errno()));
1021618Srie }
1031618Srie 
1041618Srie /*
1051618Srie  * The full usage message
1061618Srie  */
1071618Srie static void
1081618Srie detail_usage()
1091618Srie {
1101618Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL1));
1111618Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL2));
1121618Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL3));
1131618Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL4));
1141618Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL5));
1151618Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL6));
1161618Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL7));
1171618Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL8));
1181618Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL9));
1191618Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL10));
1201618Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL11));
1211618Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL12));
1221618Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL13));
1231618Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL14));
1241618Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL15));
1251618Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL16));
1261618Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL17));
1271618Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL18));
1281618Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL19));
1291618Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL20));
1303492Sab196087 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL21));
131*4168Sab196087 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL22));
132*4168Sab196087 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL23));
133*4168Sab196087 }
134*4168Sab196087 
135*4168Sab196087 /*
136*4168Sab196087  * Convert the ASCII representation of an index, or index range, into
137*4168Sab196087  * binary form, and store it in rec:
138*4168Sab196087  *
139*4168Sab196087  *	index: An positive or 0 valued integer
140*4168Sab196087  *	range: Two indexes, separated by a ':' character, denoting
141*4168Sab196087  *		a range of allowed values. If the second value is omitted,
142*4168Sab196087  *		any values equal to or greater than the first will match.
143*4168Sab196087  *
144*4168Sab196087  * exit:
145*4168Sab196087  *	On success, *rec is filled in with a MATCH_T_NDX or MATCH_T_RANGE
146*4168Sab196087  *	value, and this function returns (1). On failure, the contents
147*4168Sab196087  *	of *rec are undefined, and (0) is returned.
148*4168Sab196087  */
149*4168Sab196087 int
150*4168Sab196087 process_index_opt(const char *str, MATCH *rec)
151*4168Sab196087 {
152*4168Sab196087 #define	SKIP_BLANK for (; *str && isspace(*str); str++)
153*4168Sab196087 
154*4168Sab196087 	char	*endptr;
155*4168Sab196087 
156*4168Sab196087 	rec->value.ndx.start = strtol(str, &endptr, 10);
157*4168Sab196087 	/* Value must use some of the input, and be 0 or positive */
158*4168Sab196087 	if ((str == endptr) || (rec->value.ndx.start < 0))
159*4168Sab196087 		return (0);
160*4168Sab196087 	str = endptr;
161*4168Sab196087 
162*4168Sab196087 	SKIP_BLANK;
163*4168Sab196087 	if (*str != ':') {
164*4168Sab196087 		rec->type = MATCH_T_NDX;
165*4168Sab196087 	} else {
166*4168Sab196087 		str++;					/* Skip the ':' */
167*4168Sab196087 		rec->type = MATCH_T_RANGE;
168*4168Sab196087 		SKIP_BLANK;
169*4168Sab196087 		if (*str == '\0') {
170*4168Sab196087 			rec->value.ndx.end = -1;	/* Indicates "to end" */
171*4168Sab196087 		} else {
172*4168Sab196087 			rec->value.ndx.end = strtol(str, &endptr, 10);
173*4168Sab196087 			if ((str == endptr) || (rec->value.ndx.end < 0))
174*4168Sab196087 				return (0);
175*4168Sab196087 			str = endptr;
176*4168Sab196087 			SKIP_BLANK;
177*4168Sab196087 		}
178*4168Sab196087 	}
179*4168Sab196087 
180*4168Sab196087 	/* Syntax error if anything is left over */
181*4168Sab196087 	if (*str != '\0')
182*4168Sab196087 		return (0);
183*4168Sab196087 
184*4168Sab196087 	return (1);
185*4168Sab196087 
186*4168Sab196087 #undef	SKIP_BLANK
187*4168Sab196087 }
188*4168Sab196087 
189*4168Sab196087 /*
190*4168Sab196087  * Returns True (1) if the item with the given name or index should
191*4168Sab196087  * be displayed, and False (0) if it should not be.
192*4168Sab196087  *
193*4168Sab196087  * entry:
194*4168Sab196087  *	strict - A strict match requires an explicit match to
195*4168Sab196087  *		a user specified -I or -N option. A non-strict match
196*4168Sab196087  *		succeeds if the match list is empty.
197*4168Sab196087  *	name - Name of item under consideration, or NULL if the name
198*4168Sab196087  *		should not be considered.
199*4168Sab196087  *	ndx - if (ndx >= 0) index of item under consideration.
200*4168Sab196087  *		A negative value indicates that the item has no index.
201*4168Sab196087  *
202*4168Sab196087  * exit:
203*4168Sab196087  *	True will be returned if the given name/index matches those given
204*4168Sab196087  *	by one of the -N or -I command line options, or if no such option
205*4168Sab196087  *	was used in the command invocation.
206*4168Sab196087  */
207*4168Sab196087 int
208*4168Sab196087 match(int strict, const char *name, int ndx)
209*4168Sab196087 {
210*4168Sab196087 	MATCH *list;
211*4168Sab196087 
212*4168Sab196087 	/* If no match options were specified, allow everything */
213*4168Sab196087 	if (!strict && (match_list == NULL))
214*4168Sab196087 		return (1);
215*4168Sab196087 
216*4168Sab196087 	/* Run through the match records and check for a hit */
217*4168Sab196087 	for (list = match_list; list; list = list->next) {
218*4168Sab196087 		switch (list->type) {
219*4168Sab196087 		case MATCH_T_NAME:
220*4168Sab196087 			if ((name != NULL) &&
221*4168Sab196087 			    (strcmp(list->value.name, name) == 0))
222*4168Sab196087 				return (1);
223*4168Sab196087 			break;
224*4168Sab196087 		case MATCH_T_NDX:
225*4168Sab196087 			if (ndx == list->value.ndx.start)
226*4168Sab196087 				return (1);
227*4168Sab196087 			break;
228*4168Sab196087 		case MATCH_T_RANGE:
229*4168Sab196087 			/*
230*4168Sab196087 			 * A range end value less than 0 means that any value
231*4168Sab196087 			 * above the start is acceptible.
232*4168Sab196087 			 */
233*4168Sab196087 			if ((ndx >= list->value.ndx.start) &&
234*4168Sab196087 			    ((list->value.ndx.end < 0) ||
235*4168Sab196087 			    (ndx <= list->value.ndx.end)))
236*4168Sab196087 				return (1);
237*4168Sab196087 			break;
238*4168Sab196087 		}
239*4168Sab196087 	}
240*4168Sab196087 
241*4168Sab196087 	/* Nothing matched */
242*4168Sab196087 	return (0);
243*4168Sab196087 }
244*4168Sab196087 
245*4168Sab196087 /*
246*4168Sab196087  * Add an entry to match_list for use by match().
247*4168Sab196087  *
248*4168Sab196087  * Return True (1) for success. On failure, an error is written
249*4168Sab196087  * to stderr, and False (0) is returned.
250*4168Sab196087  */
251*4168Sab196087 static int
252*4168Sab196087 add_match_record(char *argv0, MATCH *data)
253*4168Sab196087 {
254*4168Sab196087 	MATCH *rec;
255*4168Sab196087 	MATCH *list;
256*4168Sab196087 
257*4168Sab196087 	if ((rec = malloc(sizeof (*rec))) == NULL) {
258*4168Sab196087 		int err = errno;
259*4168Sab196087 		(void) fprintf(stderr, MSG_INTL(MSG_ERR_MALLOC),
260*4168Sab196087 		    basename(argv0), strerror(err));
261*4168Sab196087 		return (0);
262*4168Sab196087 	}
263*4168Sab196087 
264*4168Sab196087 	*rec = *data;
265*4168Sab196087 
266*4168Sab196087 	/* Insert at end of match_list */
267*4168Sab196087 	if (match_list == NULL) {
268*4168Sab196087 		match_list = rec;
269*4168Sab196087 	} else {
270*4168Sab196087 		for (list = match_list; list->next != NULL; list = list->next)
271*4168Sab196087 			;
272*4168Sab196087 		list->next = rec;
273*4168Sab196087 	}
274*4168Sab196087 
275*4168Sab196087 	rec->next = NULL;
276*4168Sab196087 	return (1);
2771618Srie }
2781618Srie 
2791618Srie static void
280*4168Sab196087 decide(const char *file, Elf *elf, uint_t flags, int wfd)
2811618Srie {
2821618Srie 	if (gelf_getclass(elf) == ELFCLASS64)
283*4168Sab196087 		regular64(file, elf, flags, wfd);
2841618Srie 	else
285*4168Sab196087 		regular32(file, elf, flags, wfd);
2861618Srie }
2871618Srie 
2881618Srie static void
289*4168Sab196087 archive(const char *file, int fd, Elf *elf, uint_t flags, int wfd)
2901618Srie {
2911618Srie 	Elf_Cmd		cmd = ELF_C_READ;
2921618Srie 	Elf_Arhdr	*arhdr;
2931618Srie 	Elf		*_elf = 0;
2941618Srie 	size_t		ptr;
2951618Srie 	Elf_Arsym	*arsym = 0;
2961618Srie 
2971618Srie 	/*
2983492Sab196087 	 * Determine if the archive symbol table itself is required.
2991618Srie 	 */
300*4168Sab196087 	if ((flags & FLG_SYMBOLS) && match(0, MSG_ORIG(MSG_ELF_ARSYM), -1)) {
3011618Srie 		/*
3021618Srie 		 * Get the archive symbol table.
3031618Srie 		 */
3041618Srie 		if (((arsym = elf_getarsym(elf, &ptr)) == 0) && elf_errno()) {
3051618Srie 			/*
3061618Srie 			 * The arsym could be 0 even though there was no error.
3071618Srie 			 * Print the error message only when there was
3081618Srie 			 * real error from elf_getarsym().
3091618Srie 			 */
3101618Srie 			failure(file, MSG_ORIG(MSG_ELF_GETARSYM));
3111618Srie 			return;
3121618Srie 		}
3131618Srie 	}
3141618Srie 
3151618Srie 	/*
3161618Srie 	 * Print the archive symbol table only when the archive symbol
3171618Srie 	 * table exists and it was requested to print.
3181618Srie 	 */
3191618Srie 	if (arsym) {
3201618Srie 		size_t		cnt;
3211618Srie 		char		index[MAXNDXSIZE];
3221618Srie 		size_t		offset = 0, _offset = 0;
3231618Srie 
3241618Srie 		/*
3251618Srie 		 * Print out all the symbol entries.
3261618Srie 		 */
3271618Srie 		dbg_print(0, MSG_INTL(MSG_ARCHIVE_SYMTAB));
3281618Srie 		dbg_print(0, MSG_INTL(MSG_ARCHIVE_FIELDS));
3291618Srie 
3301618Srie 		for (cnt = 0; cnt < ptr; cnt++, arsym++) {
3311618Srie 			/*
3321618Srie 			 * For each object obtain an elf descriptor so that we
3331618Srie 			 * can establish the members name.  Note, we have had
3341618Srie 			 * archives where the archive header has not been
3351618Srie 			 * obtainable so be lenient with errors.
3361618Srie 			 */
3371618Srie 			if ((offset == 0) || ((arsym->as_off != 0) &&
3381618Srie 			    (arsym->as_off != _offset))) {
3391618Srie 
3401618Srie 				if (_elf)
3411618Srie 					(void) elf_end(_elf);
3421618Srie 
3431618Srie 				if (elf_rand(elf, arsym->as_off) !=
3441618Srie 				    arsym->as_off) {
3451618Srie 					failure(file, MSG_ORIG(MSG_ELF_RAND));
3461618Srie 					arhdr = 0;
3471618Srie 				} else if ((_elf = elf_begin(fd,
3481618Srie 				    ELF_C_READ, elf)) == 0) {
3491618Srie 					failure(file, MSG_ORIG(MSG_ELF_BEGIN));
3501618Srie 					arhdr = 0;
3511618Srie 				} else if ((arhdr = elf_getarhdr(_elf)) == 0) {
3521618Srie 					failure(file,
3531618Srie 					    MSG_ORIG(MSG_ELF_GETARHDR));
3541618Srie 					arhdr = 0;
3551618Srie 				}
3561618Srie 
3571618Srie 				_offset = arsym->as_off;
3581618Srie 				if (offset == 0)
3591618Srie 					offset = _offset;
3601618Srie 			}
3611618Srie 
3621618Srie 			(void) snprintf(index, MAXNDXSIZE,
3631618Srie 			    MSG_ORIG(MSG_FMT_INDEX), EC_XWORD(cnt));
3641618Srie 			if (arsym->as_off)
3651618Srie 				dbg_print(0, MSG_ORIG(MSG_FMT_ARSYM1), index,
3661618Srie 				    /* LINTED */
3671618Srie 				    (int)arsym->as_off, arhdr ? arhdr->ar_name :
3681618Srie 				    MSG_INTL(MSG_STR_UNKNOWN), (arsym->as_name ?
3691618Srie 				    demangle(arsym->as_name, flags) :
3701618Srie 				    MSG_INTL(MSG_STR_NULL)));
3711618Srie 			else
3721618Srie 				dbg_print(0, MSG_ORIG(MSG_FMT_ARSYM2), index,
3731618Srie 				    /* LINTED */
3741618Srie 				    (int)arsym->as_off);
3751618Srie 		}
3761618Srie 
3771618Srie 		if (_elf)
3781618Srie 			(void) elf_end(_elf);
3791618Srie 
3801618Srie 		/*
3811618Srie 		 * If we only need the archive symbol table return.
3821618Srie 		 */
383*4168Sab196087 		if ((flags & FLG_SYMBOLS) &&
384*4168Sab196087 		    match(1, MSG_ORIG(MSG_ELF_ARSYM), -1))
3851618Srie 			return;
3861618Srie 
3871618Srie 		/*
3881618Srie 		 * Reset elf descriptor in preparation for processing each
3891618Srie 		 * member.
3901618Srie 		 */
3911618Srie 		if (offset)
3921618Srie 			(void) elf_rand(elf, offset);
3931618Srie 	}
3941618Srie 
3951618Srie 	/*
3961618Srie 	 * Process each object within the archive.
3971618Srie 	 */
3981618Srie 	while ((_elf = elf_begin(fd, cmd, elf)) != NULL) {
3991618Srie 		char	name[MAXPATHLEN];
4001618Srie 
4011618Srie 		if ((arhdr = elf_getarhdr(_elf)) == NULL) {
4021618Srie 			failure(file, MSG_ORIG(MSG_ELF_GETARHDR));
4031618Srie 			return;
4041618Srie 		}
4051618Srie 		if (*arhdr->ar_name != '/') {
4061618Srie 			(void) snprintf(name, MAXPATHLEN,
4071618Srie 			    MSG_ORIG(MSG_FMT_ARNAME), file, arhdr->ar_name);
4081618Srie 			dbg_print(0, MSG_ORIG(MSG_FMT_NLSTR), name);
4091618Srie 
4101618Srie 			switch (elf_kind(_elf)) {
4111618Srie 			case ELF_K_AR:
412*4168Sab196087 				archive(name, fd, _elf, flags, wfd);
4131618Srie 				break;
4141618Srie 			case ELF_K_ELF:
415*4168Sab196087 				decide(name, _elf, flags, wfd);
4161618Srie 				break;
4171618Srie 			default:
4181618Srie 				(void) fprintf(stderr,
4191618Srie 				    MSG_INTL(MSG_ERR_BADFILE), name);
4201618Srie 				break;
4211618Srie 			}
4221618Srie 		}
4231618Srie 
4241618Srie 		cmd = elf_next(_elf);
4251618Srie 		(void) elf_end(_elf);
4261618Srie 	}
4271618Srie }
4281618Srie 
4291618Srie int
4301618Srie main(int argc, char **argv, char **envp)
4311618Srie {
4321618Srie 	Elf		*elf;
4331618Srie 	int		var, fd, wfd = 0;
434*4168Sab196087 	char		*wname = 0;
4351618Srie 	uint_t		flags = 0;
436*4168Sab196087 	MATCH		match_data;
4371618Srie 
4381618Srie 	/*
4391618Srie 	 * If we're on a 64-bit kernel, try to exec a full 64-bit version of
4401618Srie 	 * the binary.  If successful, conv_check_native() won't return.
4411618Srie 	 */
4422647Srie 	(void) conv_check_native(argv, envp);
4431618Srie 
4441618Srie 	/*
4451618Srie 	 * Establish locale.
4461618Srie 	 */
4471618Srie 	(void) setlocale(LC_MESSAGES, MSG_ORIG(MSG_STR_EMPTY));
4481618Srie 	(void) textdomain(MSG_ORIG(MSG_SUNW_OST_SGS));
4491618Srie 
4501618Srie 	(void) setvbuf(stdout, NULL, _IOLBF, 0);
4511618Srie 	(void) setvbuf(stderr, NULL, _IOLBF, 0);
4521618Srie 
4531618Srie 	opterr = 0;
4541618Srie 	while ((var = getopt(argc, argv, MSG_ORIG(MSG_STR_OPTIONS))) != EOF) {
4551618Srie 		switch (var) {
4561618Srie 		case 'C':
4571618Srie 			flags |= FLG_DEMANGLE;
4581618Srie 			break;
4591618Srie 		case 'c':
4601618Srie 			flags |= FLG_SHDR;
4611618Srie 			break;
4621618Srie 		case 'd':
4631618Srie 			flags |= FLG_DYNAMIC;
4641618Srie 			break;
4651618Srie 		case 'e':
4661618Srie 			flags |= FLG_EHDR;
4671618Srie 			break;
4681618Srie 		case 'G':
4691618Srie 			flags |= FLG_GOT;
4701618Srie 			break;
4711618Srie 		case 'g':
4721618Srie 			flags |= FLG_GROUP;
4731618Srie 			break;
4741618Srie 		case 'H':
4751618Srie 			flags |= FLG_CAP;
4761618Srie 			break;
4771618Srie 		case 'h':
4781618Srie 			flags |= FLG_HASH;
4791618Srie 			break;
480*4168Sab196087 		case 'I':
481*4168Sab196087 			if (!process_index_opt(optarg, &match_data)) {
482*4168Sab196087 				(void) fprintf(stderr,
483*4168Sab196087 				    MSG_INTL(MSG_USAGE_BRIEF),
484*4168Sab196087 				    basename(argv[0]));
485*4168Sab196087 				return (1);
486*4168Sab196087 			}
487*4168Sab196087 			if (!add_match_record(argv[0], &match_data))
488*4168Sab196087 				return (1);
489*4168Sab196087 			break;
4901618Srie 		case 'i':
4911618Srie 			flags |= FLG_INTERP;
4921618Srie 			break;
4931618Srie 		case 'k':
4941618Srie 			flags |= FLG_CHECKSUM;
4951618Srie 			break;
4961618Srie 		case 'l':
4971618Srie 			flags |= FLG_LONGNAME;
4981618Srie 			break;
4991618Srie 		case 'm':
5001618Srie 			flags |= FLG_MOVE;
5011618Srie 			break;
5021618Srie 		case 'N':
503*4168Sab196087 			match_data.type = MATCH_T_NAME;
504*4168Sab196087 			match_data.value.name = optarg;
505*4168Sab196087 			if (!add_match_record(argv[0], &match_data))
506*4168Sab196087 				return (1);
5071618Srie 			break;
5081618Srie 		case 'n':
5091618Srie 			flags |= FLG_NOTE;
5101618Srie 			break;
5111618Srie 		case 'p':
5121618Srie 			flags |= FLG_PHDR;
5131618Srie 			break;
5141618Srie 		case 'r':
5151618Srie 			flags |= FLG_RELOC;
5161618Srie 			break;
5173492Sab196087 		case 'S':
5183492Sab196087 			flags |= FLG_SORT;
5193492Sab196087 			break;
5201618Srie 		case 's':
5211618Srie 			flags |= FLG_SYMBOLS;
5221618Srie 			break;
5231618Srie 		case 'u':
5241618Srie 			flags |= FLG_UNWIND;
5251618Srie 			break;
5261618Srie 		case 'v':
5271618Srie 			flags |= FLG_VERSIONS;
5281618Srie 			break;
5291618Srie 		case 'w':
5301618Srie 			wname = optarg;
5311618Srie 			break;
5321618Srie 		case 'y':
5331618Srie 			flags |= FLG_SYMINFO;
5341618Srie 			break;
5351618Srie 		case '?':
5361618Srie 			(void) fprintf(stderr, MSG_INTL(MSG_USAGE_BRIEF),
5371618Srie 			    basename(argv[0]));
5381618Srie 			detail_usage();
5391618Srie 			return (1);
5401618Srie 		default:
5411618Srie 			break;
5421618Srie 		}
5431618Srie 	}
5441618Srie 
5451618Srie 	/*
5461618Srie 	 * Validate any arguments.
5471618Srie 	 */
5481618Srie 	if ((flags & ~(FLG_DEMANGLE | FLG_LONGNAME)) == 0) {
549*4168Sab196087 		if (!wname && (match_list == NULL)) {
5501618Srie 			flags |= FLG_EVERYTHING;
551*4168Sab196087 		} else if (!wname || (match_list == NULL)) {
5521618Srie 			(void) fprintf(stderr, MSG_INTL(MSG_USAGE_BRIEF),
5531618Srie 			    basename(argv[0]));
5541618Srie 			return (1);
5551618Srie 		}
5561618Srie 	}
5571618Srie 
5581618Srie 	if ((var = argc - optind) == 0) {
5591618Srie 		(void) fprintf(stderr, MSG_INTL(MSG_USAGE_BRIEF),
5601618Srie 		    basename(argv[0]));
5611618Srie 		return (1);
5621618Srie 	}
5631618Srie 
5641618Srie 	/*
5651618Srie 	 * If the -l/-C option is specified, set up the liblddbg.so.
5661618Srie 	 */
5671618Srie 	if (flags & FLG_LONGNAME)
5681618Srie 		dbg_desc->d_extra |= DBG_E_LONG;
5691618Srie 	if (flags & FLG_DEMANGLE)
5701618Srie 		dbg_desc->d_extra |= DBG_E_DEMANGLE;
5711618Srie 
5721618Srie 	/*
5731618Srie 	 * If the -w option has indicated an output file open it.  It's
5741618Srie 	 * arguable whether this option has much use when multiple files are
5751618Srie 	 * being processed.
5761618Srie 	 */
5771618Srie 	if (wname) {
5781618Srie 		if ((wfd = open(wname, (O_RDWR | O_CREAT | O_TRUNC),
5791618Srie 		    0666)) < 0) {
5801618Srie 			int err = errno;
5811618Srie 			(void) fprintf(stderr, MSG_INTL(MSG_ERR_OPEN),
5821618Srie 			    wname, strerror(err));
5831618Srie 			wfd = 0;
5841618Srie 		}
5851618Srie 	}
5861618Srie 
5871618Srie 	/*
5881618Srie 	 * Open the input file and initialize the elf interface.
5891618Srie 	 */
5901618Srie 	for (; optind < argc; optind++) {
5911618Srie 		const char	*file = argv[optind];
5921618Srie 
5931618Srie 		if ((fd = open(argv[optind], O_RDONLY)) == -1) {
5941618Srie 			int err = errno;
5951618Srie 			(void) fprintf(stderr, MSG_INTL(MSG_ERR_OPEN),
5961618Srie 			    file, strerror(err));
5971618Srie 			continue;
5981618Srie 		}
5991618Srie 		(void) elf_version(EV_CURRENT);
6001618Srie 		if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) {
6011618Srie 			failure(file, MSG_ORIG(MSG_ELF_BEGIN));
6021618Srie 			(void) close(fd);
6031618Srie 			continue;
6041618Srie 		}
6051618Srie 
6061618Srie 		if (var > 1)
6071618Srie 			dbg_print(0, MSG_ORIG(MSG_FMT_NLSTRNL), file);
6081618Srie 
6091618Srie 		switch (elf_kind(elf)) {
6101618Srie 		case ELF_K_AR:
611*4168Sab196087 			archive(file, fd, elf, flags, wfd);
6121618Srie 			break;
6131618Srie 		case ELF_K_ELF:
614*4168Sab196087 			decide(file, elf, flags, wfd);
6151618Srie 			break;
6161618Srie 		default:
6171618Srie 			(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADFILE), file);
6181618Srie 			break;
6191618Srie 		}
6201618Srie 
6211618Srie 		(void) close(fd);
6221618Srie 		(void) elf_end(elf);
6231618Srie 	}
6241618Srie 
6251618Srie 	if (wfd)
6261618Srie 		(void) close(wfd);
6271618Srie 	return (0);
6281618Srie }
629