Home | History | Annotate | Download | only in common
      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 /*
     23  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     24  * Use is subject to license terms.
     25  */
     26 
     27 /*
     28  * Dump an elf file.
     29  */
     30 #include	<sys/param.h>
     31 #include	<fcntl.h>
     32 #include	<stdio.h>
     33 #include	<stdlib.h>
     34 #include	<ctype.h>
     35 #include	<libelf.h>
     36 #include	<link.h>
     37 #include	<stdarg.h>
     38 #include	<unistd.h>
     39 #include	<libgen.h>
     40 #include	<libintl.h>
     41 #include	<locale.h>
     42 #include	<errno.h>
     43 #include	<strings.h>
     44 #include	<debug.h>
     45 #include	<conv.h>
     46 #include	<msg.h>
     47 #include	<_elfdump.h>
     48 #include	<sys/elf_SPARC.h>
     49 #include	<sys/elf_amd64.h>
     50 
     51 
     52 const Cache	cache_init = {NULL, NULL, NULL, NULL, 0};
     53 
     54 
     55 
     56 /*
     57  * The -I, -N, and -T options are called "match options", because
     58  * they allow selecting the items to be displayed based on matching
     59  * their index, name, or type.
     60  *
     61  * The ELF information to which -I, -N, or -T are applied in
     62  * the current invocation is called the "match item".
     63  */
     64 typedef enum {
     65 	MATCH_ITEM_PT,		/* Program header (PT_) */
     66 	MATCH_ITEM_SHT		/* Section header (SHT_) */
     67 } match_item_t;
     68 
     69 /* match_opt_t is  used to note which match option was used */
     70 typedef enum {
     71 	MATCH_OPT_NAME,		/* Record contains a name */
     72 	MATCH_OPT_NDX,		/* Record contains a single index */
     73 	MATCH_OPT_RANGE,	/* Record contains an index range */
     74 	MATCH_OPT_TYPE,		/* Record contains a type (shdr or phdr) */
     75 } match_opt_t;
     76 
     77 typedef struct _match {
     78 	struct _match	*next;		/* Pointer to next item in list */
     79 	match_opt_t	opt_type;
     80 	union {
     81 		const char	*name;	/* MATCH_OPT_NAME */
     82 		struct {		/* MATCH_OPT_NDX and MATCH_OPT_RANGE */
     83 			int	start;
     84 			int	end;	/* Only for MATCH_OPT_RANGE */
     85 		} ndx;
     86 		uint32_t	type;	/* MATCH_OPT_TYPE */
     87 	} value;
     88 } match_rec_t;
     89 
     90 static struct {
     91 	match_item_t	item_type;	/* Type of item being matched */
     92 	match_rec_t	*list;		/* Records for (-I, -N, -T) options */
     93 } match_state;
     94 
     95 
     96 
     97 const char *
     98 _elfdump_msg(Msg mid)
     99 {
    100 	return (gettext(MSG_ORIG(mid)));
    101 }
    102 
    103 /*
    104  * Determine whether a symbol name should be demangled.
    105  */
    106 const char *
    107 demangle(const char *name, uint_t flags)
    108 {
    109 	if (flags & FLG_CTL_DEMANGLE)
    110 		return (Elf_demangle_name(name));
    111 	else
    112 		return ((char *)name);
    113 }
    114 
    115 /*
    116  * Define our own standard error routine.
    117  */
    118 void
    119 failure(const char *file, const char *func)
    120 {
    121 	(void) fprintf(stderr, MSG_INTL(MSG_ERR_FAILURE),
    122 	    file, func, elf_errmsg(elf_errno()));
    123 }
    124 
    125 /*
    126  * The full usage message
    127  */
    128 static void
    129 detail_usage()
    130 {
    131 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL1));
    132 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL2));
    133 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL3));
    134 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL4));
    135 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL5));
    136 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL6));
    137 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL7));
    138 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL8));
    139 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL9));
    140 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL10));
    141 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL11));
    142 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL12));
    143 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL13));
    144 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL14));
    145 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL15));
    146 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL16));
    147 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL17));
    148 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL18));
    149 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL19));
    150 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL20));
    151 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL21));
    152 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL22));
    153 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL23));
    154 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL24));
    155 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL25));
    156 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL26));
    157 }
    158 
    159 /*
    160  * Output a block of raw data as hex bytes. Each row is given
    161  * the index of the first byte in the row.
    162  *
    163  * entry:
    164  *	data - Pointer to first byte of data to be displayed
    165  *	n - # of bytes of data
    166  *	prefix - String to be output before each line. Useful
    167  *		for indenting output.
    168  *	bytes_per_col - # of space separated bytes to output
    169  *		in each column.
    170  *	col_per_row - # of columns to output per row
    171  *
    172  * exit:
    173  *	The formatted data has been sent to stdout. Each row of output
    174  *	shows (bytes_per_col * col_per_row) bytes of data.
    175  */
    176 void
    177 dump_hex_bytes(const void *data, size_t n, int indent,
    178 	int bytes_per_col, int col_per_row)
    179 {
    180 	const uchar_t *ldata = data;
    181 	int	bytes_per_row = bytes_per_col * col_per_row;
    182 	int	ndx, byte, word;
    183 	char	string[128], *str = string;
    184 	char	index[MAXNDXSIZE];
    185 	int	index_width;
    186 	int	sp_prefix = 0;
    187 
    188 
    189 	/*
    190 	 * Determine the width to use for the index string. We follow
    191 	 * 8-byte tab rules, but don't use an actual \t character so
    192 	 * that the output can be arbitrarily shifted without odd
    193 	 * tab effects, and so that all the columns line up no matter
    194 	 * how many lines of output are produced.
    195 	 */
    196 	ndx = n / bytes_per_row;
    197 	(void) snprintf(index, sizeof (index),
    198 	    MSG_ORIG(MSG_FMT_INDEX2), EC_WORD(ndx));
    199 	index_width = strlen(index);
    200 	index_width = S_ROUND(index_width, 8);
    201 
    202 	for (ndx = byte = word = 0; n > 0; n--, ldata++) {
    203 		while (sp_prefix-- > 0)
    204 			*str++ = ' ';
    205 
    206 		(void) snprintf(str, sizeof (string),
    207 		    MSG_ORIG(MSG_HEXDUMP_TOK), (int)*ldata);
    208 		str += 2;
    209 		sp_prefix = 1;
    210 
    211 		if (++byte == bytes_per_col) {
    212 			sp_prefix += 2;
    213 			word++;
    214 			byte = 0;
    215 		}
    216 		if (word == col_per_row) {
    217 			*str = '\0';
    218 			(void) snprintf(index, sizeof (index),
    219 			    MSG_ORIG(MSG_FMT_INDEX2), EC_WORD(ndx));
    220 			dbg_print(0, MSG_ORIG(MSG_HEXDUMP_ROW),
    221 			    indent, MSG_ORIG(MSG_STR_EMPTY),
    222 			    index_width, index, string);
    223 			sp_prefix = 0;
    224 			word = 0;
    225 			ndx += bytes_per_row;
    226 			str = string;
    227 		}
    228 	}
    229 	if (byte || word) {
    230 		*str = '\0';	/*  */
    231 		(void) snprintf(index, sizeof (index),
    232 		    MSG_ORIG(MSG_FMT_INDEX2), EC_WORD(ndx));
    233 		dbg_print(0, MSG_ORIG(MSG_HEXDUMP_ROW), indent,
    234 		    MSG_ORIG(MSG_STR_EMPTY), index_width, index, string);
    235 	}
    236 }
    237 
    238 /*
    239  * Convert the ASCII representation of an index, or index range, into
    240  * binary form, and store it in rec:
    241  *
    242  *	index: An positive or 0 valued integer
    243  *	range: Two indexes, separated by a ':' character, denoting
    244  *		a range of allowed values. If the second value is omitted,
    245  *		any values equal to or greater than the first will match.
    246  *
    247  * exit:
    248  *	On success, *rec is filled in with a MATCH_OPT_NDX or MATCH_OPT_RANGE
    249  *	value, and this function returns (1). On failure, the contents
    250  *	of *rec are undefined, and (0) is returned.
    251  */
    252 int
    253 process_index_opt(const char *str, match_rec_t *rec)
    254 {
    255 #define	SKIP_BLANK for (; *str && isspace(*str); str++)
    256 
    257 	char	*endptr;
    258 
    259 	rec->value.ndx.start = strtol(str, &endptr, 10);
    260 	/* Value must use some of the input, and be 0 or positive */
    261 	if ((str == endptr) || (rec->value.ndx.start < 0))
    262 		return (0);
    263 	str = endptr;
    264 
    265 	SKIP_BLANK;
    266 	if (*str != ':') {
    267 		rec->opt_type = MATCH_OPT_NDX;
    268 	} else {
    269 		str++;					/* Skip the ':' */
    270 		rec->opt_type = MATCH_OPT_RANGE;
    271 		SKIP_BLANK;
    272 		if (*str == '\0') {
    273 			rec->value.ndx.end = -1;	/* Indicates "to end" */
    274 		} else {
    275 			rec->value.ndx.end = strtol(str, &endptr, 10);
    276 			if ((str == endptr) || (rec->value.ndx.end < 0))
    277 				return (0);
    278 			str = endptr;
    279 			SKIP_BLANK;
    280 		}
    281 	}
    282 
    283 	/* Syntax error if anything is left over */
    284 	if (*str != '\0')
    285 		return (0);
    286 
    287 	return (1);
    288 
    289 #undef	SKIP_BLANK
    290 }
    291 
    292 /*
    293  * Convert a string containing a specific type of ELF constant, or an ASCII
    294  * representation of a number, to an integer. Strings starting with '0'
    295  * are taken to be octal, those staring with '0x' are hex, and all
    296  * others are decimal.
    297  *
    298  * entry:
    299  *	str - String to be converted
    300  *	ctype - Constant type
    301  *	v - Address of variable to receive resulting value.
    302  *
    303  * exit:
    304  *	On success, returns True (1) and *v is set to the value.
    305  *	On failure, returns False (0) and *v is undefined.
    306  */
    307 typedef enum {
    308 	ATOUI_PT,
    309 	ATOUI_SHT,
    310 	ATOUI_OSABI
    311 } atoui_type_t;
    312 
    313 static int
    314 atoui(const char *str, atoui_type_t type, uint32_t *v)
    315 {
    316 	conv_strtol_uvalue_t	uvalue;
    317 	char			*endptr;
    318 
    319 	if (conv_iter_strtol_init(str, &uvalue) != 0) {
    320 		switch (type) {
    321 		case ATOUI_PT:
    322 			if (conv_iter_phdr_type(CONV_OSABI_ALL, CONV_FMT_ALT_CF,
    323 			    conv_iter_strtol, &uvalue) == CONV_ITER_DONE)
    324 				break;
    325 			(void) conv_iter_phdr_type(CONV_OSABI_ALL,
    326 			    CONV_FMT_ALT_NF, conv_iter_strtol, &uvalue);
    327 			break;
    328 		case ATOUI_SHT:
    329 			if (conv_iter_sec_type(CONV_OSABI_ALL, CONV_MACH_ALL,
    330 			    CONV_FMT_ALT_CF, conv_iter_strtol, &uvalue) ==
    331 			    CONV_ITER_DONE)
    332 				break;
    333 			(void) conv_iter_sec_type(CONV_OSABI_ALL, CONV_MACH_ALL,
    334 			    CONV_FMT_ALT_NF, conv_iter_strtol, &uvalue);
    335 			break;
    336 		case ATOUI_OSABI:
    337 			if (conv_iter_ehdr_osabi(CONV_FMT_ALT_CF,
    338 			    conv_iter_strtol, &uvalue) == CONV_ITER_DONE)
    339 				break;
    340 			(void) conv_iter_ehdr_osabi(CONV_FMT_ALT_NF,
    341 			    conv_iter_strtol, &uvalue);
    342 			break;
    343 		}
    344 		if (uvalue.csl_found) {
    345 			*v = uvalue.csl_value;
    346 			return (1);
    347 		}
    348 	}
    349 
    350 	*v = strtoull(str, &endptr, 0);
    351 
    352 	/* If the left over part contains anything but whitespace, fail */
    353 	for (; *endptr; endptr++)
    354 		if (!isspace(*endptr))
    355 			return (0);
    356 	return (1);
    357 }
    358 
    359 /*
    360  * Called after getopt() processing is finished if there is a non-empty
    361  * match list. Prepares the matching code for use.
    362  *
    363  * exit:
    364  *	Returns True (1) if no errors are encountered. Writes an
    365  *	error string to stderr and returns False (0) otherwise.
    366  */
    367 static int
    368 match_prepare(char *argv0, uint_t flags)
    369 {
    370 	match_rec_t	*list;
    371 	const char	*str;
    372 	int		minus_p = (flags & FLG_SHOW_PHDR) != 0;
    373 	atoui_type_t	atoui_type;
    374 
    375 	/*
    376 	 * Flag ambiguous attempt to use match option with both -p and
    377 	 * and one or more section SHOW options. In this case, we
    378 	 * can't tell what type of item we're supposed to match against.
    379 	 */
    380 	if (minus_p && (flags & FLG_MASK_SHOW_SHDR)) {
    381 		(void) fprintf(stderr, MSG_INTL(MSG_ERR_AMBIG_MATCH),
    382 		    basename(argv0));
    383 		return (0);
    384 	}
    385 
    386 	/* Set the match type, based on the presence of the -p option */
    387 	if (minus_p) {
    388 		match_state.item_type = MATCH_ITEM_PT;
    389 		atoui_type = ATOUI_PT;
    390 	} else {
    391 		match_state.item_type = MATCH_ITEM_SHT;
    392 		atoui_type = ATOUI_SHT;
    393 	}
    394 
    395 	/*
    396 	 * Scan match list and perform any necessary fixups:
    397 	 *
    398 	 * MATCH_OPT_NAME: If -p is specified, convert MATCH_OPT_NAME (-N)
    399 	 *	requests into MATCH_OPT_TYPE (-T).
    400 	 *
    401 	 * MATCH_OPT_TYPE: Now that we know item type we are matching
    402 	 *	against, we can convert the string saved in the name
    403 	 *	field during getopt() processing into an integer and
    404 	 *	write it into the type field.
    405 	 */
    406 	for (list = match_state.list; list; list = list->next) {
    407 		if ((list->opt_type == MATCH_OPT_NAME) && minus_p)
    408 			list->opt_type = MATCH_OPT_TYPE;
    409 
    410 		if (list->opt_type != MATCH_OPT_TYPE)
    411 			continue;
    412 
    413 		str = list->value.name;
    414 		if (atoui(str, atoui_type, &list->value.type) == 0) {
    415 			const char *fmt = minus_p ?
    416 			    MSG_INTL(MSG_ERR_BAD_T_PT) :
    417 			    MSG_INTL(MSG_ERR_BAD_T_SHT);
    418 
    419 			(void) fprintf(stderr, fmt, basename(argv0), str);
    420 			return (0);
    421 		}
    422 	}
    423 
    424 	return (1);
    425 }
    426 
    427 
    428 /*
    429  * Returns True (1) if the item with the given name or index should
    430  * be displayed, and False (0) if it should not be.
    431  *
    432  * entry:
    433  *	match_flags - Bitmask specifying matching options, as described
    434  *		in _elfdump.h.
    435  *	name - If MATCH_F_NAME flag is set, name of item under
    436  *		consideration. Otherwise ignored.
    437  *		should not be considered.
    438  *	ndx - If MATCH_F_NDX flag is set, index of item under consideration.
    439  *	type - If MATCH_F_TYPE is set, type of item under consideration.
    440  *		If MATCH_F_PHDR is set, this would be a program
    441  *		header type (PT_). Otherwise, a section header type (SHT_).
    442  *
    443  * exit:
    444  *	True will be returned if the given name/index matches those given
    445  *	by one of the (-I, -N -T) command line options, or if no such option
    446  *	was used in the command invocation and MATCH_F_STRICT is not
    447  *	set.
    448  */
    449 int
    450 match(match_flags_t match_flags, const char *name, uint_t ndx, uint_t type)
    451 {
    452 	match_item_t item_type = (match_flags & MATCH_F_PHDR) ?
    453 	    MATCH_ITEM_PT  : MATCH_ITEM_SHT;
    454 	match_rec_t *list;
    455 
    456 	/*
    457 	 * If there is no match list, then we use the MATCH_F_STRICT
    458 	 * flag to decide what to return. In the strict case, we return
    459 	 * False (0), in the normal case, True (1).
    460 	 */
    461 	if (match_state.list == NULL)
    462 		return ((match_flags & MATCH_F_STRICT) == 0);
    463 
    464 	/*
    465 	 * If item being checked is not the current match type,
    466 	 * then allow it.
    467 	 */
    468 	if (item_type != match_state.item_type)
    469 		return (1);
    470 
    471 	/* Run through the match records and check for a hit */
    472 	for (list = match_state.list; list; list = list->next) {
    473 		switch (list->opt_type) {
    474 		case MATCH_OPT_NAME:
    475 			if (((match_flags & MATCH_F_NAME) == 0) ||
    476 			    (name == NULL))
    477 				break;
    478 			if (strcmp(list->value.name, name) == 0)
    479 				return (1);
    480 			break;
    481 		case MATCH_OPT_NDX:
    482 			if ((match_flags & MATCH_F_NDX) &&
    483 			    (ndx == list->value.ndx.start))
    484 				return (1);
    485 			break;
    486 		case MATCH_OPT_RANGE:
    487 			/*
    488 			 * A range end value less than 0 means that any value
    489 			 * above the start is acceptible.
    490 			 */
    491 			if ((match_flags & MATCH_F_NDX) &&
    492 			    (ndx >= list->value.ndx.start) &&
    493 			    ((list->value.ndx.end < 0) ||
    494 			    (ndx <= list->value.ndx.end)))
    495 				return (1);
    496 			break;
    497 
    498 		case MATCH_OPT_TYPE:
    499 			if ((match_flags & MATCH_F_TYPE) &&
    500 			    (type == list->value.type))
    501 				return (1);
    502 			break;
    503 		}
    504 	}
    505 
    506 	/* Nothing matched */
    507 	return (0);
    508 }
    509 
    510 /*
    511  * Add an entry to match_state.list for use by match(). This routine is for
    512  * use during getopt() processing. It should not be called once
    513  * match_prepare() has been called.
    514  *
    515  * Return True (1) for success. On failure, an error is written
    516  * to stderr, and False (0) is returned.
    517  */
    518 static int
    519 add_match_record(char *argv0, match_rec_t *data)
    520 {
    521 	match_rec_t	*rec;
    522 	match_rec_t	*list;
    523 
    524 	if ((rec = malloc(sizeof (*rec))) == NULL) {
    525 		int err = errno;
    526 		(void) fprintf(stderr, MSG_INTL(MSG_ERR_MALLOC),
    527 		    basename(argv0), strerror(err));
    528 		return (0);
    529 	}
    530 
    531 	*rec = *data;
    532 
    533 	/* Insert at end of match_state.list */
    534 	if (match_state.list == NULL) {
    535 		match_state.list = rec;
    536 	} else {
    537 		for (list = match_state.list; list->next != NULL;
    538 		    list = list->next)
    539 			;
    540 		list->next = rec;
    541 	}
    542 
    543 	rec->next = NULL;
    544 	return (1);
    545 }
    546 
    547 static int
    548 decide(const char *file, int fd, Elf *elf, uint_t flags,
    549     const char *wname, int wfd, uchar_t osabi)
    550 {
    551 	int r;
    552 
    553 	if (gelf_getclass(elf) == ELFCLASS64)
    554 		r = regular64(file, fd, elf, flags, wname, wfd, osabi);
    555 	else
    556 		r = regular32(file, fd, elf, flags, wname, wfd, osabi);
    557 
    558 	return (r);
    559 }
    560 
    561 static int
    562 archive(const char *file, int fd, Elf *elf, uint_t flags,
    563     const char *wname, int wfd, uchar_t osabi)
    564 {
    565 	Elf_Cmd		cmd = ELF_C_READ;
    566 	Elf_Arhdr	*arhdr;
    567 	Elf		*_elf = NULL;
    568 	size_t		ptr;
    569 	Elf_Arsym	*arsym = NULL;
    570 
    571 	/*
    572 	 * Determine if the archive symbol table itself is required.
    573 	 */
    574 	if ((flags & FLG_SHOW_SYMBOLS) &&
    575 	    match(MATCH_F_NAME, MSG_ORIG(MSG_ELF_ARSYM), 0, 0)) {
    576 		/*
    577 		 * Get the archive symbol table.
    578 		 */
    579 		if (((arsym = elf_getarsym(elf, &ptr)) == 0) && elf_errno()) {
    580 			/*
    581 			 * The arsym could be 0 even though there was no error.
    582 			 * Print the error message only when there was
    583 			 * real error from elf_getarsym().
    584 			 */
    585 			failure(file, MSG_ORIG(MSG_ELF_GETARSYM));
    586 			return (0);
    587 		}
    588 	}
    589 
    590 	/*
    591 	 * Print the archive symbol table only when the archive symbol
    592 	 * table exists and it was requested to print.
    593 	 */
    594 	if (arsym) {
    595 		size_t		cnt;
    596 		char		index[MAXNDXSIZE];
    597 		size_t		offset = 0, _offset = 0;
    598 
    599 		/*
    600 		 * Print out all the symbol entries.
    601 		 */
    602 		dbg_print(0, MSG_INTL(MSG_ARCHIVE_SYMTAB));
    603 		dbg_print(0, MSG_INTL(MSG_ARCHIVE_FIELDS));
    604 
    605 		for (cnt = 0; cnt < ptr; cnt++, arsym++) {
    606 			/*
    607 			 * For each object obtain an elf descriptor so that we
    608 			 * can establish the members name.  Note, we have had
    609 			 * archives where the archive header has not been
    610 			 * obtainable so be lenient with errors.
    611 			 */
    612 			if ((offset == 0) || ((arsym->as_off != 0) &&
    613 			    (arsym->as_off != _offset))) {
    614 
    615 				if (_elf)
    616 					(void) elf_end(_elf);
    617 
    618 				if (elf_rand(elf, arsym->as_off) !=
    619 				    arsym->as_off) {
    620 					failure(file, MSG_ORIG(MSG_ELF_RAND));
    621 					arhdr = NULL;
    622 				} else if ((_elf = elf_begin(fd,
    623 				    ELF_C_READ, elf)) == 0) {
    624 					failure(file, MSG_ORIG(MSG_ELF_BEGIN));
    625 					arhdr = NULL;
    626 				} else if ((arhdr = elf_getarhdr(_elf)) == 0) {
    627 					failure(file,
    628 					    MSG_ORIG(MSG_ELF_GETARHDR));
    629 					arhdr = NULL;
    630 				}
    631 
    632 				_offset = arsym->as_off;
    633 				if (offset == 0)
    634 					offset = _offset;
    635 			}
    636 
    637 			(void) snprintf(index, MAXNDXSIZE,
    638 			    MSG_ORIG(MSG_FMT_INDEX), EC_XWORD(cnt));
    639 			if (arsym->as_off)
    640 				dbg_print(0, MSG_ORIG(MSG_FMT_ARSYM1), index,
    641 				    /* LINTED */
    642 				    (int)arsym->as_off, arhdr ? arhdr->ar_name :
    643 				    MSG_INTL(MSG_STR_UNKNOWN), (arsym->as_name ?
    644 				    demangle(arsym->as_name, flags) :
    645 				    MSG_INTL(MSG_STR_NULL)));
    646 			else
    647 				dbg_print(0, MSG_ORIG(MSG_FMT_ARSYM2), index,
    648 				    /* LINTED */
    649 				    (int)arsym->as_off);
    650 		}
    651 
    652 		if (_elf)
    653 			(void) elf_end(_elf);
    654 
    655 		/*
    656 		 * If we only need the archive symbol table return.
    657 		 */
    658 		if ((flags & FLG_SHOW_SYMBOLS) &&
    659 		    match(MATCH_F_STRICT | MATCH_F_NAME,
    660 		    MSG_ORIG(MSG_ELF_ARSYM), -1, -1))
    661 			return (0);
    662 
    663 		/*
    664 		 * Reset elf descriptor in preparation for processing each
    665 		 * member.
    666 		 */
    667 		if (offset)
    668 			(void) elf_rand(elf, offset);
    669 	}
    670 
    671 	/*
    672 	 * Process each object within the archive.
    673 	 */
    674 	while ((_elf = elf_begin(fd, cmd, elf)) != NULL) {
    675 		char	name[MAXPATHLEN];
    676 
    677 		if ((arhdr = elf_getarhdr(_elf)) == NULL) {
    678 			failure(file, MSG_ORIG(MSG_ELF_GETARHDR));
    679 			return (0);
    680 		}
    681 		if (*arhdr->ar_name != '/') {
    682 			(void) snprintf(name, MAXPATHLEN,
    683 			    MSG_ORIG(MSG_FMT_ARNAME), file, arhdr->ar_name);
    684 			dbg_print(0, MSG_ORIG(MSG_FMT_NLSTR), name);
    685 
    686 			switch (elf_kind(_elf)) {
    687 			case ELF_K_AR:
    688 				if (archive(name, fd, _elf, flags,
    689 				    wname, wfd, osabi) == 1)
    690 					return (1);
    691 				break;
    692 			case ELF_K_ELF:
    693 				if (decide(name, fd, _elf, flags,
    694 				    wname, wfd, osabi) == 1)
    695 					return (1);
    696 				break;
    697 			default:
    698 				(void) fprintf(stderr,
    699 				    MSG_INTL(MSG_ERR_BADFILE), name);
    700 				break;
    701 			}
    702 		}
    703 
    704 		cmd = elf_next(_elf);
    705 		(void) elf_end(_elf);
    706 	}
    707 
    708 	return (0);
    709 }
    710 
    711 int
    712 main(int argc, char **argv, char **envp)
    713 {
    714 	Elf		*elf;
    715 	int		var, fd, wfd = 0;
    716 	char		*wname = NULL;
    717 	uint_t		flags = 0;
    718 	match_rec_t	match_data;
    719 	int		ret;
    720 	uchar_t		osabi;
    721 
    722 	/*
    723 	 * If we're on a 64-bit kernel, try to exec a full 64-bit version of
    724 	 * the binary.  If successful, conv_check_native() won't return.
    725 	 */
    726 	(void) conv_check_native(argv, envp);
    727 
    728 	/*
    729 	 * Establish locale.
    730 	 */
    731 	(void) setlocale(LC_MESSAGES, MSG_ORIG(MSG_STR_EMPTY));
    732 	(void) textdomain(MSG_ORIG(MSG_SUNW_OST_SGS));
    733 
    734 	(void) setvbuf(stdout, NULL, _IOLBF, 0);
    735 	(void) setvbuf(stderr, NULL, _IOLBF, 0);
    736 
    737 	opterr = 0;
    738 	while ((var = getopt(argc, argv, MSG_ORIG(MSG_STR_OPTIONS))) != EOF) {
    739 		switch (var) {
    740 		case 'C':
    741 			flags |= FLG_CTL_DEMANGLE;
    742 			break;
    743 		case 'c':
    744 			flags |= FLG_SHOW_SHDR;
    745 			break;
    746 		case 'd':
    747 			flags |= FLG_SHOW_DYNAMIC;
    748 			break;
    749 		case 'e':
    750 			flags |= FLG_SHOW_EHDR;
    751 			break;
    752 		case 'G':
    753 			flags |= FLG_SHOW_GOT;
    754 			break;
    755 		case 'g':
    756 			flags |= FLG_SHOW_GROUP;
    757 			break;
    758 		case 'H':
    759 			flags |= FLG_SHOW_CAP;
    760 			break;
    761 		case 'h':
    762 			flags |= FLG_SHOW_HASH;
    763 			break;
    764 		case 'I':
    765 			if (!process_index_opt(optarg, &match_data))
    766 				goto usage_brief;
    767 			if (!add_match_record(argv[0], &match_data))
    768 				return (1);
    769 			flags |= FLG_CTL_MATCH;
    770 			break;
    771 		case 'i':
    772 			flags |= FLG_SHOW_INTERP;
    773 			break;
    774 		case 'k':
    775 			flags |= FLG_CALC_CHECKSUM;
    776 			break;
    777 		case 'l':
    778 			flags |= FLG_CTL_LONGNAME;
    779 			break;
    780 		case 'm':
    781 			flags |= FLG_SHOW_MOVE;
    782 			break;
    783 		case 'N':
    784 			match_data.opt_type = MATCH_OPT_NAME;
    785 			match_data.value.name = optarg;
    786 			if (!add_match_record(argv[0], &match_data))
    787 				return (1);
    788 			flags |= FLG_CTL_MATCH;
    789 			break;
    790 		case 'n':
    791 			flags |= FLG_SHOW_NOTE;
    792 			break;
    793 		case 'O':
    794 			{
    795 				uint32_t val;
    796 
    797 				/*
    798 				 * osabi is a uchar_t in the ELF header.
    799 				 * Don't accept any value that exceeds
    800 				 * that range.
    801 				 */
    802 				if ((atoui(optarg, ATOUI_OSABI, &val) == 0) ||
    803 				    (val > 255)) {
    804 					(void) fprintf(stderr,
    805 					    MSG_INTL(MSG_ERR_BAD_T_OSABI),
    806 					    basename(argv[0]), optarg);
    807 					return (1);
    808 				}
    809 				osabi = val;
    810 			}
    811 			flags |= FLG_CTL_OSABI;
    812 			break;
    813 		case 'P':
    814 			flags |= FLG_CTL_FAKESHDR;
    815 			break;
    816 		case 'p':
    817 			flags |= FLG_SHOW_PHDR;
    818 			break;
    819 		case 'r':
    820 			flags |= FLG_SHOW_RELOC;
    821 			break;
    822 		case 'S':
    823 			flags |= FLG_SHOW_SORT;
    824 			break;
    825 		case 's':
    826 			flags |= FLG_SHOW_SYMBOLS;
    827 			break;
    828 		case 'T':
    829 			/*
    830 			 * We can't evaluate the value yet, because
    831 			 * we need to know if -p is used or not in
    832 			 * order to tell if we're seeing section header
    833 			 * or program header types. So, we save the
    834 			 * string in the name field, and then convert
    835 			 * it to a type integer in a following pass.
    836 			 */
    837 			match_data.opt_type = MATCH_OPT_TYPE;
    838 			match_data.value.name = optarg;
    839 			if (!add_match_record(argv[0], &match_data))
    840 				return (1);
    841 			flags |= FLG_CTL_MATCH;
    842 			break;
    843 		case 'u':
    844 			flags |= FLG_SHOW_UNWIND;
    845 			break;
    846 		case 'v':
    847 			flags |= FLG_SHOW_VERSIONS;
    848 			break;
    849 		case 'w':
    850 			wname = optarg;
    851 			break;
    852 		case 'y':
    853 			flags |= FLG_SHOW_SYMINFO;
    854 			break;
    855 		case '?':
    856 			(void) fprintf(stderr, MSG_INTL(MSG_USAGE_BRIEF),
    857 			    basename(argv[0]));
    858 			detail_usage();
    859 			return (1);
    860 		default:
    861 			break;
    862 		}
    863 	}
    864 
    865 	/* -p and -w are mutually exclusive. -w only works with sections */
    866 	if (((flags & FLG_SHOW_PHDR) != 0) && (wname != NULL))
    867 		goto usage_brief;
    868 
    869 	/* If a match argument is present, prepare the match state */
    870 	if ((match_state.list != NULL) && (match_prepare(argv[0], flags) == 0))
    871 		return (1);
    872 
    873 	/*
    874 	 * Decide what to do if no options specifying something to
    875 	 * show or do are present.
    876 	 *
    877 	 * If there is no -w and no match options, then we will set all
    878 	 * the show flags, causing a full display of everything in the
    879 	 * file that we know how to handle.
    880 	 *
    881 	 * Otherwise, if there is no match list, we generate a usage
    882 	 * error and quit.
    883 	 *
    884 	 * In the case where there is a match list, we go ahead and call
    885 	 * regular() anyway, leaving it to decide what to do. If -w is
    886 	 * present, regular() will use the match list to handle it.
    887 	 * In addition, in the absence of explicit show/calc flags, regular()
    888 	 * will compare the section headers to the match list and use
    889 	 * that to generate the FLG_ bits that will display the information
    890 	 * specified by the match list.
    891 	 */
    892 	if ((flags & ~FLG_MASK_CTL) == 0) {
    893 		if (!wname && (match_state.list == NULL))
    894 			flags |= FLG_MASK_SHOW;
    895 		else if (match_state.list == NULL)
    896 			goto usage_brief;
    897 	}
    898 
    899 	/* There needs to be at least 1 filename left following the options */
    900 	if ((var = argc - optind) == 0)
    901 		goto usage_brief;
    902 
    903 	/*
    904 	 * If the -l/-C option is specified, set up the liblddbg.so.
    905 	 */
    906 	if (flags & FLG_CTL_LONGNAME)
    907 		dbg_desc->d_extra |= DBG_E_LONG;
    908 	if (flags & FLG_CTL_DEMANGLE)
    909 		dbg_desc->d_extra |= DBG_E_DEMANGLE;
    910 
    911 	/*
    912 	 * If the -w option has indicated an output file open it.  It's
    913 	 * arguable whether this option has much use when multiple files are
    914 	 * being processed.
    915 	 *
    916 	 * If wname is non-NULL, we know that -p was not specified, due
    917 	 * to the test above.
    918 	 */
    919 	if (wname) {
    920 		if ((wfd = open(wname, (O_RDWR | O_CREAT | O_TRUNC),
    921 		    0666)) < 0) {
    922 			int err = errno;
    923 			(void) fprintf(stderr, MSG_INTL(MSG_ERR_OPEN),
    924 			    wname, strerror(err));
    925 			return (1);
    926 		}
    927 	}
    928 
    929 	/*
    930 	 * Open the input file, initialize the elf interface, and
    931 	 * process it.
    932 	 */
    933 	ret = 0;
    934 	for (; (optind < argc) && (ret == 0); optind++) {
    935 		const char	*file = argv[optind];
    936 
    937 		if ((fd = open(argv[optind], O_RDONLY)) == -1) {
    938 			int err = errno;
    939 			(void) fprintf(stderr, MSG_INTL(MSG_ERR_OPEN),
    940 			    file, strerror(err));
    941 			continue;
    942 		}
    943 		(void) elf_version(EV_CURRENT);
    944 		if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) {
    945 			failure(file, MSG_ORIG(MSG_ELF_BEGIN));
    946 			(void) close(fd);
    947 			continue;
    948 		}
    949 
    950 		if (var > 1)
    951 			dbg_print(0, MSG_ORIG(MSG_FMT_NLSTRNL), file);
    952 
    953 		switch (elf_kind(elf)) {
    954 		case ELF_K_AR:
    955 			ret = archive(file, fd, elf, flags, wname, wfd, osabi);
    956 			break;
    957 		case ELF_K_ELF:
    958 			ret = decide(file, fd, elf, flags, wname, wfd, osabi);
    959 			break;
    960 		default:
    961 			(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADFILE), file);
    962 			break;
    963 		}
    964 
    965 		(void) close(fd);
    966 		(void) elf_end(elf);
    967 	}
    968 
    969 	if (wfd)
    970 		(void) close(wfd);
    971 	return (ret);
    972 
    973 usage_brief:
    974 	/* Control comes here for a simple usage message and exit */
    975 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_BRIEF),
    976 	    basename(argv[0]));
    977 	return (1);
    978 
    979 }
    980