xref: /illumos-gate/usr/src/cmd/sgs/elfdump/common/main.c (revision 7d1e83948cb684521e72cab96020be241508f449)
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