main.c revision 9273:9a0603d78ad3
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
52const 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 */
64typedef 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 */
70typedef 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
77typedef 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
90static 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
97const 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 */
106const char *
107demangle(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 */
118void
119failure(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 */
128static void
129detail_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 */
176void
177dump_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 */
252int
253process_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 */
307typedef enum {
308	ATOUI_PT,
309	ATOUI_SHT,
310	ATOUI_OSABI
311} atoui_type_t;
312
313static int
314atoui(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 */
367static int
368match_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 */
449int
450match(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 */
518static int
519add_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
547static int
548decide(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
561static int
562archive(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
711int
712main(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
973usage_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