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