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
51const 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 */
63typedef 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 */
69typedef 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
76typedef 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
89static 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
96const 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 */
105const char *
106demangle(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 */
117void
118failure(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 */
127static void
128detail_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 */
175void
176dump_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 */
251int
252process_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 */
306typedef enum {
307	ATOUI_PT,
308	ATOUI_SHT,
309	ATOUI_OSABI
310} atoui_type_t;
311
312static int
313atoui(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 */
366static int
367match_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 */
448int
449match(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 */
517static int
518add_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
546static int
547decide(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
560static int
561archive(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
726int
727main(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
988usage_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