xref: /illumos-gate/usr/src/cmd/sgs/elfdump/common/main.c (revision c6c9aed4d309e3d11be652b85e3bf8bb72f20c87)
15aefb655Srie /*
25aefb655Srie  * CDDL HEADER START
35aefb655Srie  *
45aefb655Srie  * The contents of this file are subject to the terms of the
55aefb655Srie  * Common Development and Distribution License (the "License").
65aefb655Srie  * You may not use this file except in compliance with the License.
75aefb655Srie  *
85aefb655Srie  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
95aefb655Srie  * or http://www.opensolaris.org/os/licensing.
105aefb655Srie  * See the License for the specific language governing permissions
115aefb655Srie  * and limitations under the License.
125aefb655Srie  *
135aefb655Srie  * When distributing Covered Code, include this CDDL HEADER in each
145aefb655Srie  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
155aefb655Srie  * If applicable, add the following below this CDDL HEADER, with the
165aefb655Srie  * fields enclosed by brackets "[]" replaced with your own identifying
175aefb655Srie  * information: Portions Copyright [yyyy] [name of copyright owner]
185aefb655Srie  *
195aefb655Srie  * CDDL HEADER END
205aefb655Srie  */
215aefb655Srie 
225aefb655Srie /*
23*c6c9aed4Sab  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
245aefb655Srie  * Use is subject to license terms.
255aefb655Srie  */
265aefb655Srie #pragma ident	"%Z%%M%	%I%	%E% SMI"
275aefb655Srie 
285aefb655Srie /*
295aefb655Srie  * Dump an elf file.
305aefb655Srie  */
315aefb655Srie #include	<sys/param.h>
325aefb655Srie #include	<fcntl.h>
335aefb655Srie #include	<stdio.h>
34c809c407Sab #include	<stdlib.h>
35c809c407Sab #include	<ctype.h>
365aefb655Srie #include	<libelf.h>
375aefb655Srie #include	<link.h>
385aefb655Srie #include	<stdarg.h>
395aefb655Srie #include	<unistd.h>
405aefb655Srie #include	<libgen.h>
415aefb655Srie #include	<libintl.h>
425aefb655Srie #include	<locale.h>
435aefb655Srie #include	<errno.h>
445aefb655Srie #include	<strings.h>
455aefb655Srie #include	<debug.h>
465aefb655Srie #include	<conv.h>
475aefb655Srie #include	<msg.h>
485aefb655Srie #include	<_elfdump.h>
49981a172dSab #include	<sys/elf_SPARC.h>
50981a172dSab #include	<sys/elf_amd64.h>
51981a172dSab 
525aefb655Srie 
5331fdd7caSab const Cache	cache_init = {NULL, NULL, NULL, NULL, 0};
545aefb655Srie 
55c809c407Sab 
56c809c407Sab 
57981a172dSab /*
58981a172dSab  * The -I, -N, and -T options are called "match options", because
59981a172dSab  * they allow selecting the items to be displayed based on matching
60981a172dSab  * their index, name, or type.
61981a172dSab  *
62981a172dSab  * The ELF information to which -I, -N, or -T are applied in
63981a172dSab  * the current invocation is called the "match item".
64981a172dSab  */
65981a172dSab typedef enum {
66981a172dSab 	MATCH_ITEM_PT,		/* Program header (PT_) */
67981a172dSab 	MATCH_ITEM_SHT		/* Section header (SHT_) */
68981a172dSab } match_item_t;
69981a172dSab 
70981a172dSab /* match_opt_t is  used to note which match option was used */
71c809c407Sab typedef enum {
72981a172dSab 	MATCH_OPT_NAME,		/* Record contains a name */
73981a172dSab 	MATCH_OPT_NDX,		/* Record contains a single index */
74981a172dSab 	MATCH_OPT_RANGE,	/* Record contains an index range */
75981a172dSab 	MATCH_OPT_TYPE,		/* Record contains a type (shdr or phdr) */
76981a172dSab } match_opt_t;
77c809c407Sab 
78c809c407Sab typedef struct _match {
79c809c407Sab 	struct _match	*next;		/* Pointer to next item in list */
80981a172dSab 	match_opt_t	opt_type;
81c809c407Sab 	union {
82981a172dSab 		const char	*name;	/* MATCH_OPT_NAME */
83981a172dSab 		struct {		/* MATCH_OPT_NDX and MATCH_OPT_RANGE */
84c809c407Sab 			int	start;
85981a172dSab 			int	end;	/* Only for MATCH_OPT_RANGE */
86c809c407Sab 		} ndx;
87981a172dSab 		uint32_t	type;	/* MATCH_OPT_TYPE */
88c809c407Sab 	} value;
89981a172dSab } match_rec_t;
90981a172dSab 
91981a172dSab static struct {
92981a172dSab 	match_item_t	item_type;	/* Type of item being matched */
93981a172dSab 	match_rec_t	*list;		/* Records for (-I, -N, -T) options */
94981a172dSab } match_state;
95981a172dSab 
96981a172dSab 
97981a172dSab 
98981a172dSab /* Map names to their integer value */
99981a172dSab typedef struct {
100981a172dSab 	const char	*sym_name;
101981a172dSab 	uint32_t	sym_value;
102981a172dSab } atoui_sym_t;
103981a172dSab 
104981a172dSab /*
105981a172dSab  * ELF section types.
106981a172dSab  */
107981a172dSab static atoui_sym_t sym_sht[] = {
108981a172dSab 	{ MSG_ORIG(MSG_SHT_NULL),		SHT_NULL },
109981a172dSab 	{ MSG_ORIG(MSG_SHT_NULL_ALT1),		SHT_NULL },
110981a172dSab 
111981a172dSab 	{ MSG_ORIG(MSG_SHT_PROGBITS),		SHT_PROGBITS },
112981a172dSab 	{ MSG_ORIG(MSG_SHT_PROGBITS_ALT1),	SHT_PROGBITS },
113981a172dSab 
114981a172dSab 	{ MSG_ORIG(MSG_SHT_SYMTAB),		SHT_SYMTAB },
115981a172dSab 	{ MSG_ORIG(MSG_SHT_SYMTAB_ALT1),	SHT_SYMTAB },
116981a172dSab 
117981a172dSab 	{ MSG_ORIG(MSG_SHT_STRTAB),		SHT_STRTAB },
118981a172dSab 	{ MSG_ORIG(MSG_SHT_STRTAB_ALT1),	SHT_STRTAB },
119981a172dSab 
120981a172dSab 	{ MSG_ORIG(MSG_SHT_RELA),		SHT_RELA },
121981a172dSab 	{ MSG_ORIG(MSG_SHT_RELA_ALT1),		SHT_RELA },
122981a172dSab 
123981a172dSab 	{ MSG_ORIG(MSG_SHT_HASH),		SHT_HASH },
124981a172dSab 	{ MSG_ORIG(MSG_SHT_HASH_ALT1),		SHT_HASH },
125981a172dSab 
126981a172dSab 	{ MSG_ORIG(MSG_SHT_DYNAMIC),		SHT_DYNAMIC },
127981a172dSab 	{ MSG_ORIG(MSG_SHT_DYNAMIC_ALT1),	SHT_DYNAMIC },
128981a172dSab 
129981a172dSab 	{ MSG_ORIG(MSG_SHT_NOTE),		SHT_NOTE },
130981a172dSab 	{ MSG_ORIG(MSG_SHT_NOTE_ALT1),		SHT_NOTE },
131981a172dSab 
132981a172dSab 	{ MSG_ORIG(MSG_SHT_NOBITS),		SHT_NOBITS },
133981a172dSab 	{ MSG_ORIG(MSG_SHT_NOBITS_ALT1),	SHT_NOBITS },
134981a172dSab 
135981a172dSab 	{ MSG_ORIG(MSG_SHT_REL),		SHT_REL },
136981a172dSab 	{ MSG_ORIG(MSG_SHT_REL_ALT1),		SHT_REL },
137981a172dSab 
138981a172dSab 	{ MSG_ORIG(MSG_SHT_SHLIB),		SHT_SHLIB },
139981a172dSab 	{ MSG_ORIG(MSG_SHT_SHLIB_ALT1),		SHT_SHLIB },
140981a172dSab 
141981a172dSab 	{ MSG_ORIG(MSG_SHT_DYNSYM),		SHT_DYNSYM },
142981a172dSab 	{ MSG_ORIG(MSG_SHT_DYNSYM_ALT1),	SHT_DYNSYM },
143981a172dSab 
144981a172dSab 	{ MSG_ORIG(MSG_SHT_INIT_ARRAY),		SHT_INIT_ARRAY },
145981a172dSab 	{ MSG_ORIG(MSG_SHT_INIT_ARRAY_ALT1),	SHT_INIT_ARRAY },
146981a172dSab 
147981a172dSab 	{ MSG_ORIG(MSG_SHT_FINI_ARRAY),		SHT_FINI_ARRAY },
148981a172dSab 	{ MSG_ORIG(MSG_SHT_FINI_ARRAY_ALT1),	SHT_FINI_ARRAY },
149981a172dSab 
150981a172dSab 	{ MSG_ORIG(MSG_SHT_PREINIT_ARRAY),	SHT_PREINIT_ARRAY },
151981a172dSab 	{ MSG_ORIG(MSG_SHT_PREINIT_ARRAY_ALT1),	SHT_PREINIT_ARRAY },
152981a172dSab 
153981a172dSab 	{ MSG_ORIG(MSG_SHT_GROUP),		SHT_GROUP },
154981a172dSab 	{ MSG_ORIG(MSG_SHT_GROUP_ALT1),		SHT_GROUP },
155981a172dSab 
156981a172dSab 	{ MSG_ORIG(MSG_SHT_SYMTAB_SHNDX),	SHT_SYMTAB_SHNDX },
157981a172dSab 	{ MSG_ORIG(MSG_SHT_SYMTAB_SHNDX_ALT1),	SHT_SYMTAB_SHNDX },
158981a172dSab 
159981a172dSab 	{ MSG_ORIG(MSG_SHT_SUNW_SYMSORT),	SHT_SUNW_symsort },
160981a172dSab 	{ MSG_ORIG(MSG_SHT_SUNW_SYMSORT_ALT1),	SHT_SUNW_symsort },
161981a172dSab 
162981a172dSab 	{ MSG_ORIG(MSG_SHT_SUNW_TLSSORT),	SHT_SUNW_tlssort },
163981a172dSab 	{ MSG_ORIG(MSG_SHT_SUNW_TLSSORT_ALT1),	SHT_SUNW_tlssort },
164981a172dSab 
165981a172dSab 	{ MSG_ORIG(MSG_SHT_SUNW_LDYNSYM),	SHT_SUNW_LDYNSYM },
166981a172dSab 	{ MSG_ORIG(MSG_SHT_SUNW_LDYNSYM_ALT1),	SHT_SUNW_LDYNSYM },
167981a172dSab 
168981a172dSab 	{ MSG_ORIG(MSG_SHT_SUNW_DOF),		SHT_SUNW_dof },
169981a172dSab 	{ MSG_ORIG(MSG_SHT_SUNW_DOF_ALT1),	SHT_SUNW_dof },
170981a172dSab 
171981a172dSab 	{ MSG_ORIG(MSG_SHT_SUNW_CAP),		SHT_SUNW_cap },
172981a172dSab 	{ MSG_ORIG(MSG_SHT_SUNW_CAP_ALT1),	SHT_SUNW_cap },
173981a172dSab 
174981a172dSab 	{ MSG_ORIG(MSG_SHT_SUNW_SIGNATURE),	SHT_SUNW_SIGNATURE },
175981a172dSab 	{ MSG_ORIG(MSG_SHT_SUNW_SIGNATURE_ALT1), SHT_SUNW_SIGNATURE },
176981a172dSab 
177981a172dSab 	{ MSG_ORIG(MSG_SHT_SUNW_ANNOTATE),	SHT_SUNW_ANNOTATE },
178981a172dSab 	{ MSG_ORIG(MSG_SHT_SUNW_ANNOTATE_ALT1),	SHT_SUNW_ANNOTATE },
179981a172dSab 
180981a172dSab 	{ MSG_ORIG(MSG_SHT_SUNW_DEBUGSTR),	SHT_SUNW_DEBUGSTR },
181981a172dSab 	{ MSG_ORIG(MSG_SHT_SUNW_DEBUGSTR_ALT1),	SHT_SUNW_DEBUGSTR },
182981a172dSab 
183981a172dSab 	{ MSG_ORIG(MSG_SHT_SUNW_DEBUG),		SHT_SUNW_DEBUG },
184981a172dSab 	{ MSG_ORIG(MSG_SHT_SUNW_DEBUG_ALT1),	SHT_SUNW_DEBUG },
185981a172dSab 
186981a172dSab 	{ MSG_ORIG(MSG_SHT_SUNW_MOVE),		SHT_SUNW_move },
187981a172dSab 	{ MSG_ORIG(MSG_SHT_SUNW_MOVE_ALT1),	SHT_SUNW_move },
188981a172dSab 
189981a172dSab 	{ MSG_ORIG(MSG_SHT_SUNW_COMDAT),	SHT_SUNW_COMDAT },
190981a172dSab 	{ MSG_ORIG(MSG_SHT_SUNW_COMDAT_ALT1),	SHT_SUNW_COMDAT },
191981a172dSab 
192981a172dSab 	{ MSG_ORIG(MSG_SHT_SUNW_SYMINFO),	SHT_SUNW_syminfo },
193981a172dSab 	{ MSG_ORIG(MSG_SHT_SUNW_SYMINFO_ALT1),	SHT_SUNW_syminfo },
194981a172dSab 
195981a172dSab 	{ MSG_ORIG(MSG_SHT_SUNW_VERDEF),	SHT_SUNW_verdef },
196981a172dSab 	{ MSG_ORIG(MSG_SHT_SUNW_VERDEF_ALT1),	SHT_SUNW_verdef },
197981a172dSab 
198981a172dSab 	{ MSG_ORIG(MSG_SHT_GNU_VERDEF),		SHT_GNU_verdef },
199981a172dSab 	{ MSG_ORIG(MSG_SHT_GNU_VERDEF_ALT1),	SHT_GNU_verdef },
200981a172dSab 
201981a172dSab 	{ MSG_ORIG(MSG_SHT_SUNW_VERNEED),	SHT_SUNW_verneed },
202981a172dSab 	{ MSG_ORIG(MSG_SHT_SUNW_VERNEED_ALT1),	SHT_SUNW_verneed },
203981a172dSab 
204981a172dSab 	{ MSG_ORIG(MSG_SHT_GNU_VERNEED),	SHT_GNU_verneed },
205981a172dSab 	{ MSG_ORIG(MSG_SHT_GNU_VERNEED_ALT1),	SHT_GNU_verneed },
206981a172dSab 
207981a172dSab 	{ MSG_ORIG(MSG_SHT_SUNW_VERSYM),	SHT_SUNW_versym },
208981a172dSab 	{ MSG_ORIG(MSG_SHT_SUNW_VERSYM_ALT1),	SHT_SUNW_versym },
209981a172dSab 
210981a172dSab 	{ MSG_ORIG(MSG_SHT_GNU_VERSYM),		SHT_GNU_versym },
211981a172dSab 	{ MSG_ORIG(MSG_SHT_GNU_VERSYM_ALT1),	SHT_GNU_versym },
212981a172dSab 
213981a172dSab 	{ MSG_ORIG(MSG_SHT_SPARC_GOTDATA),	SHT_SPARC_GOTDATA },
214981a172dSab 	{ MSG_ORIG(MSG_SHT_SPARC_GOTDATA_ALT1),	SHT_SPARC_GOTDATA },
215981a172dSab 
216981a172dSab 	{ MSG_ORIG(MSG_SHT_AMD64_UNWIND),	SHT_AMD64_UNWIND },
217981a172dSab 	{ MSG_ORIG(MSG_SHT_AMD64_UNWIND_ALT1),	SHT_AMD64_UNWIND },
218981a172dSab 
219981a172dSab 	{ NULL }
220981a172dSab };
221981a172dSab 
222981a172dSab /*
223981a172dSab  * Program header PT_* type values
224981a172dSab  */
225981a172dSab static atoui_sym_t sym_pt[] = {
226981a172dSab 	{ MSG_ORIG(MSG_PT_NULL),		PT_NULL },
227981a172dSab 	{ MSG_ORIG(MSG_PT_NULL_ALT1),		PT_NULL },
228981a172dSab 
229981a172dSab 	{ MSG_ORIG(MSG_PT_LOAD),		PT_LOAD },
230981a172dSab 	{ MSG_ORIG(MSG_PT_LOAD_ALT1),		PT_LOAD },
231981a172dSab 
232981a172dSab 	{ MSG_ORIG(MSG_PT_DYNAMIC),		PT_DYNAMIC },
233981a172dSab 	{ MSG_ORIG(MSG_PT_DYNAMIC_ALT1),	PT_DYNAMIC },
234981a172dSab 
235981a172dSab 	{ MSG_ORIG(MSG_PT_INTERP),		PT_INTERP },
236981a172dSab 	{ MSG_ORIG(MSG_PT_INTERP_ALT1),		PT_INTERP },
237981a172dSab 
238981a172dSab 	{ MSG_ORIG(MSG_PT_NOTE),		PT_NOTE },
239981a172dSab 	{ MSG_ORIG(MSG_PT_NOTE_ALT1),		PT_NOTE },
240981a172dSab 
241981a172dSab 	{ MSG_ORIG(MSG_PT_SHLIB),		PT_SHLIB },
242981a172dSab 	{ MSG_ORIG(MSG_PT_SHLIB_ALT1),		PT_SHLIB },
243981a172dSab 
244981a172dSab 	{ MSG_ORIG(MSG_PT_PHDR),		PT_PHDR },
245981a172dSab 	{ MSG_ORIG(MSG_PT_PHDR_ALT1),		PT_PHDR },
246981a172dSab 
247981a172dSab 	{ MSG_ORIG(MSG_PT_TLS),			PT_TLS },
248981a172dSab 	{ MSG_ORIG(MSG_PT_TLS_ALT1),		PT_TLS },
249981a172dSab 
250981a172dSab 	{ MSG_ORIG(MSG_PT_SUNW_UNWIND),		PT_SUNW_UNWIND },
251981a172dSab 	{ MSG_ORIG(MSG_PT_SUNW_UNWIND_ALT1),	PT_SUNW_UNWIND },
252981a172dSab 
253981a172dSab 	{ MSG_ORIG(MSG_PT_SUNWBSS),		PT_SUNWBSS },
254981a172dSab 	{ MSG_ORIG(MSG_PT_SUNWBSS_ALT1),	PT_SUNWBSS },
255981a172dSab 
256981a172dSab 	{ MSG_ORIG(MSG_PT_SUNWSTACK),		PT_SUNWSTACK },
257981a172dSab 	{ MSG_ORIG(MSG_PT_SUNWSTACK_ALT1),	PT_SUNWSTACK },
258981a172dSab 
259981a172dSab 	{ MSG_ORIG(MSG_PT_SUNWDTRACE),		PT_SUNWDTRACE },
260981a172dSab 	{ MSG_ORIG(MSG_PT_SUNWDTRACE_ALT1),	PT_SUNWDTRACE },
261981a172dSab 
262981a172dSab 	{ MSG_ORIG(MSG_PT_SUNWCAP),		PT_SUNWCAP },
263981a172dSab 	{ MSG_ORIG(MSG_PT_SUNWCAP_ALT1),	PT_SUNWCAP },
264981a172dSab 
265981a172dSab 	{ NULL }
266981a172dSab };
267981a172dSab 
268981a172dSab 
269981a172dSab 
270c809c407Sab 
271c809c407Sab 
2725aefb655Srie const char *
2735aefb655Srie _elfdump_msg(Msg mid)
2745aefb655Srie {
2755aefb655Srie 	return (gettext(MSG_ORIG(mid)));
2765aefb655Srie }
2775aefb655Srie 
2785aefb655Srie /*
2795aefb655Srie  * Determine whether a symbol name should be demangled.
2805aefb655Srie  */
2815aefb655Srie const char *
2825aefb655Srie demangle(const char *name, uint_t flags)
2835aefb655Srie {
284981a172dSab 	if (flags & FLG_CTL_DEMANGLE)
2855aefb655Srie 		return (Elf_demangle_name(name));
2865aefb655Srie 	else
2875aefb655Srie 		return ((char *)name);
2885aefb655Srie }
2895aefb655Srie 
2905aefb655Srie /*
2915aefb655Srie  * Define our own standard error routine.
2925aefb655Srie  */
2935aefb655Srie void
2945aefb655Srie failure(const char *file, const char *func)
2955aefb655Srie {
2965aefb655Srie 	(void) fprintf(stderr, MSG_INTL(MSG_ERR_FAILURE),
2975aefb655Srie 	    file, func, elf_errmsg(elf_errno()));
2985aefb655Srie }
2995aefb655Srie 
3005aefb655Srie /*
3015aefb655Srie  * The full usage message
3025aefb655Srie  */
3035aefb655Srie static void
3045aefb655Srie detail_usage()
3055aefb655Srie {
3065aefb655Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL1));
3075aefb655Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL2));
3085aefb655Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL3));
3095aefb655Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL4));
3105aefb655Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL5));
3115aefb655Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL6));
3125aefb655Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL7));
3135aefb655Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL8));
3145aefb655Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL9));
3155aefb655Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL10));
3165aefb655Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL11));
3175aefb655Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL12));
3185aefb655Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL13));
3195aefb655Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL14));
3205aefb655Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL15));
3215aefb655Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL16));
3225aefb655Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL17));
3235aefb655Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL18));
3245aefb655Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL19));
3255aefb655Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL20));
326d579eb63Sab 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL21));
327c809c407Sab 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL22));
328c809c407Sab 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL23));
32939773e46Sab 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL24));
330981a172dSab 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL25));
331c809c407Sab }
332c809c407Sab 
333*c6c9aed4Sab /*
334*c6c9aed4Sab  * Output a block of raw data as hex bytes. Each row is given
335*c6c9aed4Sab  * the index of the first byte in the row.
336*c6c9aed4Sab  *
337*c6c9aed4Sab  * entry:
338*c6c9aed4Sab  *	data - Pointer to first byte of data to be displayed
339*c6c9aed4Sab  *	n - # of bytes of data
340*c6c9aed4Sab  *	prefix - String to be output before each line. Useful
341*c6c9aed4Sab  *		for indenting output.
342*c6c9aed4Sab  *	bytes_per_col - # of space separated bytes to output
343*c6c9aed4Sab  *		in each column.
344*c6c9aed4Sab  *	col_per_row - # of columns to output per row
345*c6c9aed4Sab  *
346*c6c9aed4Sab  * exit:
347*c6c9aed4Sab  *	The formatted data has been sent to stdout. Each row of output
348*c6c9aed4Sab  *	shows (bytes_per_col * col_per_row) bytes of data.
349*c6c9aed4Sab  */
350*c6c9aed4Sab void
351*c6c9aed4Sab dump_hex_bytes(const char *data, size_t n, int indent,
352*c6c9aed4Sab 	int bytes_per_col, int col_per_row)
353*c6c9aed4Sab {
354*c6c9aed4Sab 	int	bytes_per_row = bytes_per_col * col_per_row;
355*c6c9aed4Sab 	int	ndx, byte, word;
356*c6c9aed4Sab 	char	string[128], *str = string;
357*c6c9aed4Sab 	char	index[MAXNDXSIZE];
358*c6c9aed4Sab 	int	index_width;
359*c6c9aed4Sab 	int	sp_prefix = 0;
360*c6c9aed4Sab 
361*c6c9aed4Sab 
362*c6c9aed4Sab 	/*
363*c6c9aed4Sab 	 * Determine the width to use for the index string. We follow
364*c6c9aed4Sab 	 * 8-byte tab rules, but don't use an actual \t character so
365*c6c9aed4Sab 	 * that the output can be arbitrarily shifted without odd
366*c6c9aed4Sab 	 * tab effects, and so that all the columns line up no matter
367*c6c9aed4Sab 	 * how many lines of output are produced.
368*c6c9aed4Sab 	 */
369*c6c9aed4Sab 	ndx = n / bytes_per_row;
370*c6c9aed4Sab 	(void) snprintf(index, sizeof (index),
371*c6c9aed4Sab 	    MSG_ORIG(MSG_FMT_INDEX2), EC_WORD(ndx));
372*c6c9aed4Sab 	index_width = strlen(index);
373*c6c9aed4Sab 	index_width = S_ROUND(index_width, 8);
374*c6c9aed4Sab 
375*c6c9aed4Sab 	for (ndx = byte = word = 0; n > 0; n--, data++) {
376*c6c9aed4Sab 		while (sp_prefix-- > 0)
377*c6c9aed4Sab 			*str++ = ' ';
378*c6c9aed4Sab 
379*c6c9aed4Sab 		(void) snprintf(str, sizeof (string),
380*c6c9aed4Sab 		    MSG_ORIG(MSG_HEXDUMP_TOK), (int)*data);
381*c6c9aed4Sab 		str += 2;
382*c6c9aed4Sab 		sp_prefix = 1;
383*c6c9aed4Sab 
384*c6c9aed4Sab 		if (++byte == bytes_per_col) {
385*c6c9aed4Sab 			sp_prefix += 2;
386*c6c9aed4Sab 			word++;
387*c6c9aed4Sab 			byte = 0;
388*c6c9aed4Sab 		}
389*c6c9aed4Sab 		if (word == col_per_row) {
390*c6c9aed4Sab 			*str = '\0';
391*c6c9aed4Sab 			(void) snprintf(index, sizeof (index),
392*c6c9aed4Sab 			    MSG_ORIG(MSG_FMT_INDEX2), EC_WORD(ndx));
393*c6c9aed4Sab 			dbg_print(0, MSG_ORIG(MSG_HEXDUMP_ROW),
394*c6c9aed4Sab 			    indent, MSG_ORIG(MSG_STR_EMPTY),
395*c6c9aed4Sab 			    index_width, index, string);
396*c6c9aed4Sab 			sp_prefix = 0;
397*c6c9aed4Sab 			word = 0;
398*c6c9aed4Sab 			ndx += bytes_per_row;
399*c6c9aed4Sab 			str = string;
400*c6c9aed4Sab 		}
401*c6c9aed4Sab 	}
402*c6c9aed4Sab 	if (byte || word) {
403*c6c9aed4Sab 		*str = '\0';	/*  */
404*c6c9aed4Sab 		(void) snprintf(index, sizeof (index),
405*c6c9aed4Sab 		    MSG_ORIG(MSG_FMT_INDEX2), EC_WORD(ndx));
406*c6c9aed4Sab 		dbg_print(0, MSG_ORIG(MSG_HEXDUMP_ROW), indent,
407*c6c9aed4Sab 		    MSG_ORIG(MSG_STR_EMPTY), index_width, index, string);
408*c6c9aed4Sab 	}
409*c6c9aed4Sab }
410*c6c9aed4Sab 
411c809c407Sab /*
412c809c407Sab  * Convert the ASCII representation of an index, or index range, into
413c809c407Sab  * binary form, and store it in rec:
414c809c407Sab  *
415c809c407Sab  *	index: An positive or 0 valued integer
416c809c407Sab  *	range: Two indexes, separated by a ':' character, denoting
417c809c407Sab  *		a range of allowed values. If the second value is omitted,
418c809c407Sab  *		any values equal to or greater than the first will match.
419c809c407Sab  *
420c809c407Sab  * exit:
421981a172dSab  *	On success, *rec is filled in with a MATCH_OPT_NDX or MATCH_OPT_RANGE
422c809c407Sab  *	value, and this function returns (1). On failure, the contents
423c809c407Sab  *	of *rec are undefined, and (0) is returned.
424c809c407Sab  */
425c809c407Sab int
426981a172dSab process_index_opt(const char *str, match_rec_t *rec)
427c809c407Sab {
428c809c407Sab #define	SKIP_BLANK for (; *str && isspace(*str); str++)
429c809c407Sab 
430c809c407Sab 	char	*endptr;
431c809c407Sab 
432c809c407Sab 	rec->value.ndx.start = strtol(str, &endptr, 10);
433c809c407Sab 	/* Value must use some of the input, and be 0 or positive */
434c809c407Sab 	if ((str == endptr) || (rec->value.ndx.start < 0))
435c809c407Sab 		return (0);
436c809c407Sab 	str = endptr;
437c809c407Sab 
438c809c407Sab 	SKIP_BLANK;
439c809c407Sab 	if (*str != ':') {
440981a172dSab 		rec->opt_type = MATCH_OPT_NDX;
441c809c407Sab 	} else {
442c809c407Sab 		str++;					/* Skip the ':' */
443981a172dSab 		rec->opt_type = MATCH_OPT_RANGE;
444c809c407Sab 		SKIP_BLANK;
445c809c407Sab 		if (*str == '\0') {
446c809c407Sab 			rec->value.ndx.end = -1;	/* Indicates "to end" */
447c809c407Sab 		} else {
448c809c407Sab 			rec->value.ndx.end = strtol(str, &endptr, 10);
449c809c407Sab 			if ((str == endptr) || (rec->value.ndx.end < 0))
450c809c407Sab 				return (0);
451c809c407Sab 			str = endptr;
452c809c407Sab 			SKIP_BLANK;
453c809c407Sab 		}
454c809c407Sab 	}
455c809c407Sab 
456c809c407Sab 	/* Syntax error if anything is left over */
457c809c407Sab 	if (*str != '\0')
458c809c407Sab 		return (0);
459c809c407Sab 
460c809c407Sab 	return (1);
461c809c407Sab 
462c809c407Sab #undef	SKIP_BLANK
463c809c407Sab }
464c809c407Sab 
465981a172dSab /*
466981a172dSab  * Process the symbolic name to value mappings passed to the
467981a172dSab  * atoui() function.
468981a172dSab  *
469981a172dSab  * entry:
470981a172dSab  *	sym - NULL terminated array of name->value mappings.
471981a172dSab  *	value - Address of variable to receive corresponding value.
472981a172dSab  *
473981a172dSab  * exit:
474981a172dSab  *	If a mapping is found, *value is set to it, and True is returned.
475981a172dSab  *	Otherwise False is returned.
476981a172dSab  */
477981a172dSab static int
478981a172dSab atoui_sym_process(const char *str, const atoui_sym_t *sym, uint32_t *value)
479981a172dSab {
480981a172dSab 	size_t		cmp_len;
481981a172dSab 	const char	*tail;
482981a172dSab 
483981a172dSab 	while (isspace(*str))
484981a172dSab 		str++;
485981a172dSab 
486981a172dSab 	tail = str + strlen(str);
487981a172dSab 	while ((tail > str) && isspace(*(tail - 1)))
488981a172dSab 		tail--;
489981a172dSab 
490981a172dSab 	cmp_len = tail - str;
491981a172dSab 
492981a172dSab 	for (; sym->sym_name != NULL; sym++) {
493981a172dSab 		if ((strlen(sym->sym_name) == cmp_len) &&
494981a172dSab 		    (strncasecmp(sym->sym_name, str, cmp_len) == 0)) {
495981a172dSab 			*value = sym->sym_value;
496981a172dSab 			return (1);
497981a172dSab 		}
498981a172dSab 	}
499981a172dSab 
500981a172dSab 	/* No symbolic mapping was found */
501981a172dSab 	return (0);
502981a172dSab }
503981a172dSab 
504981a172dSab 
505981a172dSab /*
506981a172dSab  * Convert a string to a numeric value. Strings starting with '0'
507981a172dSab  * are taken to be octal, those staring with '0x' are hex, and all
508981a172dSab  * others are decimal.
509981a172dSab  *
510981a172dSab  * entry:
511981a172dSab  *	str - String to be converted
512981a172dSab  *	sym - NULL, or NULL terminated array of name/value pairs.
513981a172dSab  *	v - Address of variable to receive resulting value.
514981a172dSab  *
515981a172dSab  * exit:
516981a172dSab  *	On success, returns True (1) and *v is set to the value.
517981a172dSab  *	On failure, returns False (0) and *v is undefined.
518981a172dSab  */
519981a172dSab static int
520981a172dSab atoui(const char *str, const atoui_sym_t *sym, uint32_t *v)
521981a172dSab {
522981a172dSab 	char		*endptr;
523981a172dSab 
524981a172dSab 	if (sym && atoui_sym_process(str, sym, v))
525981a172dSab 		return (1);
526981a172dSab 
527981a172dSab 	*v = strtoull(str, &endptr, 0);
528981a172dSab 
529981a172dSab 	/* If the left over part contains anything but whitespace, fail */
530981a172dSab 	for (; *endptr; endptr++)
531981a172dSab 		if (!isspace(*endptr))
532981a172dSab 			return (0);
533981a172dSab 	return (1);
534981a172dSab }
535981a172dSab 
536981a172dSab /*
537981a172dSab  * Called after getopt() processing is finished if there is a non-empty
538981a172dSab  * match list. Prepares the matching code for use.
539981a172dSab  *
540981a172dSab  * exit:
541981a172dSab  *	Returns True (1) if no errors are encountered. Writes an
542981a172dSab  *	error string to stderr and returns False (0) otherwise.
543981a172dSab  */
544981a172dSab static int
545981a172dSab match_prepare(char *argv0, uint_t flags)
546981a172dSab {
547981a172dSab 	atoui_sym_t	*sym;
548981a172dSab 	match_rec_t	*list;
549981a172dSab 	const char	*str;
550981a172dSab 	int		minus_p = (flags & FLG_SHOW_PHDR) != 0;
551981a172dSab 
552981a172dSab 	/*
553981a172dSab 	 * Flag ambiguous attempt to use match option with both -p and
554981a172dSab 	 * and one or more section SHOW options. In this case, we
555981a172dSab 	 * can't tell what type of item we're supposed to match against.
556981a172dSab 	 */
557981a172dSab 	if (minus_p && (flags & FLG_MASK_SHOW_SHDR)) {
558981a172dSab 		(void) fprintf(stderr, MSG_INTL(MSG_ERR_AMBIG_MATCH),
559981a172dSab 		    basename(argv0));
560981a172dSab 		return (0);
561981a172dSab 	}
562981a172dSab 
563981a172dSab 	/* Set the match type, based on the presence of the -p option */
564981a172dSab 	if (minus_p) {
565981a172dSab 		match_state.item_type = MATCH_ITEM_PT;
566981a172dSab 		sym = sym_pt;
567981a172dSab 	} else {
568981a172dSab 		match_state.item_type = MATCH_ITEM_SHT;
569981a172dSab 		sym = sym_sht;
570981a172dSab 	}
571981a172dSab 
572981a172dSab 	/*
573981a172dSab 	 * Scan match list and perform any necessary fixups:
574981a172dSab 	 *
575981a172dSab 	 * MATCH_OPT_NAME: If -p is specified, convert MATCH_OPT_NAME (-N)
576981a172dSab 	 *	requests into MATCH_OPT_TYPE (-T).
577981a172dSab 	 *
578981a172dSab 	 * MATCH_OPT_TYPE: Now that we know item type we are matching
579981a172dSab 	 *	against, we can convert the string saved in the name
580981a172dSab 	 *	field during getopt() processing into an integer and
581981a172dSab 	 *	write it into the type field.
582981a172dSab 	 */
583981a172dSab 	for (list = match_state.list; list; list = list->next) {
584981a172dSab 		if ((list->opt_type == MATCH_OPT_NAME) && minus_p)
585981a172dSab 			list->opt_type = MATCH_OPT_TYPE;
586981a172dSab 
587981a172dSab 		if (list->opt_type != MATCH_OPT_TYPE)
588981a172dSab 			continue;
589981a172dSab 
590981a172dSab 		str = list->value.name;
591981a172dSab 		if (atoui(str, sym, &list->value.type) == 0) {
592981a172dSab 			const char *fmt = minus_p ?
593981a172dSab 			    MSG_INTL(MSG_ERR_BAD_T_PT) :
594981a172dSab 			    MSG_INTL(MSG_ERR_BAD_T_SHT);
595981a172dSab 
596981a172dSab 			(void) fprintf(stderr, fmt, basename(argv0), str);
597981a172dSab 			return (0);
598981a172dSab 		}
599981a172dSab 	}
600981a172dSab 
601981a172dSab 	return (1);
602981a172dSab }
603981a172dSab 
604981a172dSab 
605c809c407Sab /*
606c809c407Sab  * Returns True (1) if the item with the given name or index should
607c809c407Sab  * be displayed, and False (0) if it should not be.
608c809c407Sab  *
609c809c407Sab  * entry:
610981a172dSab  *	match_flags - Bitmask specifying matching options, as described
611981a172dSab  *		in _elfdump.h.
612981a172dSab  *	name - If MATCH_F_NAME flag is set, name of item under
613981a172dSab  *		consideration. Otherwise ignored.
614c809c407Sab  *		should not be considered.
615981a172dSab  *	ndx - If MATCH_F_NDX flag is set, index of item under consideration.
616981a172dSab  *	type - If MATCH_F_TYPE is set, type of item under consideration.
617981a172dSab  *		If MATCH_F_PHDR is set, this would be a program
618981a172dSab  *		header type (PT_). Otherwise, a section header type (SHT_).
619c809c407Sab  *
620c809c407Sab  * exit:
621c809c407Sab  *	True will be returned if the given name/index matches those given
622981a172dSab  *	by one of the (-I, -N -T) command line options, or if no such option
623981a172dSab  *	was used in the command invocation and MATCH_F_STRICT is not
624981a172dSab  *	set.
625c809c407Sab  */
626c809c407Sab int
627981a172dSab match(match_flags_t match_flags, const char *name, uint_t ndx, uint_t type)
628c809c407Sab {
629981a172dSab 	match_item_t item_type = (match_flags & MATCH_F_PHDR) ?
630981a172dSab 	    MATCH_ITEM_PT  : MATCH_ITEM_SHT;
631981a172dSab 	match_rec_t *list;
632981a172dSab 
633981a172dSab 	/*
634981a172dSab 	 * If there is no match list, then we use the MATCH_F_STRICT
635981a172dSab 	 * flag to decide what to return. In the strict case, we return
636981a172dSab 	 * False (0), in the normal case, True (1).
637981a172dSab 	 */
638981a172dSab 	if (match_state.list == NULL)
639981a172dSab 		return ((match_flags & MATCH_F_STRICT) == 0);
640c809c407Sab 
641981a172dSab 	/*
642981a172dSab 	 * If item being checked is not the current match type,
643981a172dSab 	 * then allow it.
644981a172dSab 	 */
645981a172dSab 	if (item_type != match_state.item_type)
646c809c407Sab 		return (1);
647c809c407Sab 
648c809c407Sab 	/* Run through the match records and check for a hit */
649981a172dSab 	for (list = match_state.list; list; list = list->next) {
650981a172dSab 		switch (list->opt_type) {
651981a172dSab 		case MATCH_OPT_NAME:
652981a172dSab 			if (((match_flags & MATCH_F_NAME) == 0) ||
653981a172dSab 			    (name == NULL))
654981a172dSab 				break;
655981a172dSab 			if (strcmp(list->value.name, name) == 0)
656c809c407Sab 				return (1);
657c809c407Sab 			break;
658981a172dSab 		case MATCH_OPT_NDX:
659981a172dSab 			if ((match_flags & MATCH_F_NDX) &&
660981a172dSab 			    (ndx == list->value.ndx.start))
661c809c407Sab 				return (1);
662c809c407Sab 			break;
663981a172dSab 		case MATCH_OPT_RANGE:
664c809c407Sab 			/*
665c809c407Sab 			 * A range end value less than 0 means that any value
666c809c407Sab 			 * above the start is acceptible.
667c809c407Sab 			 */
668981a172dSab 			if ((match_flags & MATCH_F_NDX) &&
669981a172dSab 			    (ndx >= list->value.ndx.start) &&
670c809c407Sab 			    ((list->value.ndx.end < 0) ||
671c809c407Sab 			    (ndx <= list->value.ndx.end)))
672c809c407Sab 				return (1);
673c809c407Sab 			break;
674981a172dSab 
675981a172dSab 		case MATCH_OPT_TYPE:
676981a172dSab 			if ((match_flags & MATCH_F_TYPE) &&
677981a172dSab 			    (type == list->value.type))
678981a172dSab 				return (1);
679981a172dSab 			break;
680c809c407Sab 		}
681c809c407Sab 	}
682c809c407Sab 
683c809c407Sab 	/* Nothing matched */
684c809c407Sab 	return (0);
685c809c407Sab }
686c809c407Sab 
687c809c407Sab /*
688981a172dSab  * Add an entry to match_state.list for use by match(). This routine is for
689981a172dSab  * use during getopt() processing. It should not be called once
690981a172dSab  * match_prepare() has been called.
691c809c407Sab  *
692c809c407Sab  * Return True (1) for success. On failure, an error is written
693c809c407Sab  * to stderr, and False (0) is returned.
694c809c407Sab  */
695c809c407Sab static int
696981a172dSab add_match_record(char *argv0, match_rec_t *data)
697c809c407Sab {
698981a172dSab 	match_rec_t	*rec;
699981a172dSab 	match_rec_t	*list;
700c809c407Sab 
701c809c407Sab 	if ((rec = malloc(sizeof (*rec))) == NULL) {
702c809c407Sab 		int err = errno;
703c809c407Sab 		(void) fprintf(stderr, MSG_INTL(MSG_ERR_MALLOC),
704c809c407Sab 		    basename(argv0), strerror(err));
705c809c407Sab 		return (0);
706c809c407Sab 	}
707c809c407Sab 
708c809c407Sab 	*rec = *data;
709c809c407Sab 
710981a172dSab 	/* Insert at end of match_state.list */
711981a172dSab 	if (match_state.list == NULL) {
712981a172dSab 		match_state.list = rec;
713c809c407Sab 	} else {
714981a172dSab 		for (list = match_state.list; list->next != NULL;
715981a172dSab 		    list = list->next)
716c809c407Sab 			;
717c809c407Sab 		list->next = rec;
718c809c407Sab 	}
719c809c407Sab 
720c809c407Sab 	rec->next = NULL;
721c809c407Sab 	return (1);
7225aefb655Srie }
7235aefb655Srie 
724981a172dSab static int
725981a172dSab decide(const char *file, int fd, Elf *elf, uint_t flags,
726981a172dSab     const char *wname, int wfd)
7275aefb655Srie {
728981a172dSab 	int r;
729981a172dSab 
7305aefb655Srie 	if (gelf_getclass(elf) == ELFCLASS64)
731981a172dSab 		r = regular64(file, fd, elf, flags, wname, wfd);
7325aefb655Srie 	else
733981a172dSab 		r = regular32(file, fd, elf, flags, wname, wfd);
734981a172dSab 
735981a172dSab 	return (r);
7365aefb655Srie }
7375aefb655Srie 
738981a172dSab static int
739981a172dSab archive(const char *file, int fd, Elf *elf, uint_t flags,
740981a172dSab     const char *wname, int wfd)
7415aefb655Srie {
7425aefb655Srie 	Elf_Cmd		cmd = ELF_C_READ;
7435aefb655Srie 	Elf_Arhdr	*arhdr;
7445aefb655Srie 	Elf		*_elf = 0;
7455aefb655Srie 	size_t		ptr;
7465aefb655Srie 	Elf_Arsym	*arsym = 0;
7475aefb655Srie 
7485aefb655Srie 	/*
749d579eb63Sab 	 * Determine if the archive symbol table itself is required.
7505aefb655Srie 	 */
751981a172dSab 	if ((flags & FLG_SHOW_SYMBOLS) &&
752981a172dSab 	    match(MATCH_F_NAME, MSG_ORIG(MSG_ELF_ARSYM), 0, 0)) {
7535aefb655Srie 		/*
7545aefb655Srie 		 * Get the archive symbol table.
7555aefb655Srie 		 */
7565aefb655Srie 		if (((arsym = elf_getarsym(elf, &ptr)) == 0) && elf_errno()) {
7575aefb655Srie 			/*
7585aefb655Srie 			 * The arsym could be 0 even though there was no error.
7595aefb655Srie 			 * Print the error message only when there was
7605aefb655Srie 			 * real error from elf_getarsym().
7615aefb655Srie 			 */
7625aefb655Srie 			failure(file, MSG_ORIG(MSG_ELF_GETARSYM));
763981a172dSab 			return (0);
7645aefb655Srie 		}
7655aefb655Srie 	}
7665aefb655Srie 
7675aefb655Srie 	/*
7685aefb655Srie 	 * Print the archive symbol table only when the archive symbol
7695aefb655Srie 	 * table exists and it was requested to print.
7705aefb655Srie 	 */
7715aefb655Srie 	if (arsym) {
7725aefb655Srie 		size_t		cnt;
7735aefb655Srie 		char		index[MAXNDXSIZE];
7745aefb655Srie 		size_t		offset = 0, _offset = 0;
7755aefb655Srie 
7765aefb655Srie 		/*
7775aefb655Srie 		 * Print out all the symbol entries.
7785aefb655Srie 		 */
7795aefb655Srie 		dbg_print(0, MSG_INTL(MSG_ARCHIVE_SYMTAB));
7805aefb655Srie 		dbg_print(0, MSG_INTL(MSG_ARCHIVE_FIELDS));
7815aefb655Srie 
7825aefb655Srie 		for (cnt = 0; cnt < ptr; cnt++, arsym++) {
7835aefb655Srie 			/*
7845aefb655Srie 			 * For each object obtain an elf descriptor so that we
7855aefb655Srie 			 * can establish the members name.  Note, we have had
7865aefb655Srie 			 * archives where the archive header has not been
7875aefb655Srie 			 * obtainable so be lenient with errors.
7885aefb655Srie 			 */
7895aefb655Srie 			if ((offset == 0) || ((arsym->as_off != 0) &&
7905aefb655Srie 			    (arsym->as_off != _offset))) {
7915aefb655Srie 
7925aefb655Srie 				if (_elf)
7935aefb655Srie 					(void) elf_end(_elf);
7945aefb655Srie 
7955aefb655Srie 				if (elf_rand(elf, arsym->as_off) !=
7965aefb655Srie 				    arsym->as_off) {
7975aefb655Srie 					failure(file, MSG_ORIG(MSG_ELF_RAND));
7985aefb655Srie 					arhdr = 0;
7995aefb655Srie 				} else if ((_elf = elf_begin(fd,
8005aefb655Srie 				    ELF_C_READ, elf)) == 0) {
8015aefb655Srie 					failure(file, MSG_ORIG(MSG_ELF_BEGIN));
8025aefb655Srie 					arhdr = 0;
8035aefb655Srie 				} else if ((arhdr = elf_getarhdr(_elf)) == 0) {
8045aefb655Srie 					failure(file,
8055aefb655Srie 					    MSG_ORIG(MSG_ELF_GETARHDR));
8065aefb655Srie 					arhdr = 0;
8075aefb655Srie 				}
8085aefb655Srie 
8095aefb655Srie 				_offset = arsym->as_off;
8105aefb655Srie 				if (offset == 0)
8115aefb655Srie 					offset = _offset;
8125aefb655Srie 			}
8135aefb655Srie 
8145aefb655Srie 			(void) snprintf(index, MAXNDXSIZE,
8155aefb655Srie 			    MSG_ORIG(MSG_FMT_INDEX), EC_XWORD(cnt));
8165aefb655Srie 			if (arsym->as_off)
8175aefb655Srie 				dbg_print(0, MSG_ORIG(MSG_FMT_ARSYM1), index,
8185aefb655Srie 				    /* LINTED */
8195aefb655Srie 				    (int)arsym->as_off, arhdr ? arhdr->ar_name :
8205aefb655Srie 				    MSG_INTL(MSG_STR_UNKNOWN), (arsym->as_name ?
8215aefb655Srie 				    demangle(arsym->as_name, flags) :
8225aefb655Srie 				    MSG_INTL(MSG_STR_NULL)));
8235aefb655Srie 			else
8245aefb655Srie 				dbg_print(0, MSG_ORIG(MSG_FMT_ARSYM2), index,
8255aefb655Srie 				    /* LINTED */
8265aefb655Srie 				    (int)arsym->as_off);
8275aefb655Srie 		}
8285aefb655Srie 
8295aefb655Srie 		if (_elf)
8305aefb655Srie 			(void) elf_end(_elf);
8315aefb655Srie 
8325aefb655Srie 		/*
8335aefb655Srie 		 * If we only need the archive symbol table return.
8345aefb655Srie 		 */
835981a172dSab 		if ((flags & FLG_SHOW_SYMBOLS) &&
836981a172dSab 		    match(MATCH_F_STRICT | MATCH_F_NAME,
837981a172dSab 		    MSG_ORIG(MSG_ELF_ARSYM), -1, -1))
838981a172dSab 			return (0);
8395aefb655Srie 
8405aefb655Srie 		/*
8415aefb655Srie 		 * Reset elf descriptor in preparation for processing each
8425aefb655Srie 		 * member.
8435aefb655Srie 		 */
8445aefb655Srie 		if (offset)
8455aefb655Srie 			(void) elf_rand(elf, offset);
8465aefb655Srie 	}
8475aefb655Srie 
8485aefb655Srie 	/*
8495aefb655Srie 	 * Process each object within the archive.
8505aefb655Srie 	 */
8515aefb655Srie 	while ((_elf = elf_begin(fd, cmd, elf)) != NULL) {
8525aefb655Srie 		char	name[MAXPATHLEN];
8535aefb655Srie 
8545aefb655Srie 		if ((arhdr = elf_getarhdr(_elf)) == NULL) {
8555aefb655Srie 			failure(file, MSG_ORIG(MSG_ELF_GETARHDR));
856981a172dSab 			return (0);
8575aefb655Srie 		}
8585aefb655Srie 		if (*arhdr->ar_name != '/') {
8595aefb655Srie 			(void) snprintf(name, MAXPATHLEN,
8605aefb655Srie 			    MSG_ORIG(MSG_FMT_ARNAME), file, arhdr->ar_name);
8615aefb655Srie 			dbg_print(0, MSG_ORIG(MSG_FMT_NLSTR), name);
8625aefb655Srie 
8635aefb655Srie 			switch (elf_kind(_elf)) {
8645aefb655Srie 			case ELF_K_AR:
865981a172dSab 				if (archive(name, fd, _elf, flags,
866981a172dSab 				    wname, wfd) == 1)
867981a172dSab 					return (1);
8685aefb655Srie 				break;
8695aefb655Srie 			case ELF_K_ELF:
870981a172dSab 				if (decide(name, fd, _elf, flags,
871981a172dSab 				    wname, wfd) == 1)
872981a172dSab 					return (1);
8735aefb655Srie 				break;
8745aefb655Srie 			default:
8755aefb655Srie 				(void) fprintf(stderr,
8765aefb655Srie 				    MSG_INTL(MSG_ERR_BADFILE), name);
8775aefb655Srie 				break;
8785aefb655Srie 			}
8795aefb655Srie 		}
8805aefb655Srie 
8815aefb655Srie 		cmd = elf_next(_elf);
8825aefb655Srie 		(void) elf_end(_elf);
8835aefb655Srie 	}
884981a172dSab 
885981a172dSab 	return (0);
8865aefb655Srie }
8875aefb655Srie 
8885aefb655Srie int
8895aefb655Srie main(int argc, char **argv, char **envp)
8905aefb655Srie {
8915aefb655Srie 	Elf		*elf;
8925aefb655Srie 	int		var, fd, wfd = 0;
893981a172dSab 	char		*wname = NULL;
8945aefb655Srie 	uint_t		flags = 0;
895981a172dSab 	match_rec_t	match_data;
896981a172dSab 	int		ret;
8975aefb655Srie 
8985aefb655Srie 	/*
8995aefb655Srie 	 * If we're on a 64-bit kernel, try to exec a full 64-bit version of
9005aefb655Srie 	 * the binary.  If successful, conv_check_native() won't return.
9015aefb655Srie 	 */
9027010c12aSrie 	(void) conv_check_native(argv, envp);
9035aefb655Srie 
9045aefb655Srie 	/*
9055aefb655Srie 	 * Establish locale.
9065aefb655Srie 	 */
9075aefb655Srie 	(void) setlocale(LC_MESSAGES, MSG_ORIG(MSG_STR_EMPTY));
9085aefb655Srie 	(void) textdomain(MSG_ORIG(MSG_SUNW_OST_SGS));
9095aefb655Srie 
9105aefb655Srie 	(void) setvbuf(stdout, NULL, _IOLBF, 0);
9115aefb655Srie 	(void) setvbuf(stderr, NULL, _IOLBF, 0);
9125aefb655Srie 
9135aefb655Srie 	opterr = 0;
9145aefb655Srie 	while ((var = getopt(argc, argv, MSG_ORIG(MSG_STR_OPTIONS))) != EOF) {
9155aefb655Srie 		switch (var) {
9165aefb655Srie 		case 'C':
917981a172dSab 			flags |= FLG_CTL_DEMANGLE;
9185aefb655Srie 			break;
9195aefb655Srie 		case 'c':
920981a172dSab 			flags |= FLG_SHOW_SHDR;
9215aefb655Srie 			break;
9225aefb655Srie 		case 'd':
923981a172dSab 			flags |= FLG_SHOW_DYNAMIC;
9245aefb655Srie 			break;
9255aefb655Srie 		case 'e':
926981a172dSab 			flags |= FLG_SHOW_EHDR;
9275aefb655Srie 			break;
9285aefb655Srie 		case 'G':
929981a172dSab 			flags |= FLG_SHOW_GOT;
9305aefb655Srie 			break;
9315aefb655Srie 		case 'g':
932981a172dSab 			flags |= FLG_SHOW_GROUP;
9335aefb655Srie 			break;
9345aefb655Srie 		case 'H':
935981a172dSab 			flags |= FLG_SHOW_CAP;
9365aefb655Srie 			break;
9375aefb655Srie 		case 'h':
938981a172dSab 			flags |= FLG_SHOW_HASH;
9395aefb655Srie 			break;
940c809c407Sab 		case 'I':
941981a172dSab 			if (!process_index_opt(optarg, &match_data))
942981a172dSab 				goto usage_brief;
943c809c407Sab 			if (!add_match_record(argv[0], &match_data))
944c809c407Sab 				return (1);
945981a172dSab 			flags |= FLG_CTL_MATCH;
946c809c407Sab 			break;
9475aefb655Srie 		case 'i':
948981a172dSab 			flags |= FLG_SHOW_INTERP;
9495aefb655Srie 			break;
9505aefb655Srie 		case 'k':
951981a172dSab 			flags |= FLG_CALC_CHECKSUM;
9525aefb655Srie 			break;
9535aefb655Srie 		case 'l':
954981a172dSab 			flags |= FLG_CTL_LONGNAME;
9555aefb655Srie 			break;
9565aefb655Srie 		case 'm':
957981a172dSab 			flags |= FLG_SHOW_MOVE;
9585aefb655Srie 			break;
9595aefb655Srie 		case 'N':
960981a172dSab 			match_data.opt_type = MATCH_OPT_NAME;
961c809c407Sab 			match_data.value.name = optarg;
962c809c407Sab 			if (!add_match_record(argv[0], &match_data))
963c809c407Sab 				return (1);
964981a172dSab 			flags |= FLG_CTL_MATCH;
9655aefb655Srie 			break;
9665aefb655Srie 		case 'n':
967981a172dSab 			flags |= FLG_SHOW_NOTE;
9685aefb655Srie 			break;
96939773e46Sab 		case 'P':
970981a172dSab 			flags |= FLG_CTL_FAKESHDR;
97139773e46Sab 			break;
9725aefb655Srie 		case 'p':
973981a172dSab 			flags |= FLG_SHOW_PHDR;
9745aefb655Srie 			break;
9755aefb655Srie 		case 'r':
976981a172dSab 			flags |= FLG_SHOW_RELOC;
9775aefb655Srie 			break;
978d579eb63Sab 		case 'S':
979981a172dSab 			flags |= FLG_SHOW_SORT;
980d579eb63Sab 			break;
9815aefb655Srie 		case 's':
982981a172dSab 			flags |= FLG_SHOW_SYMBOLS;
983981a172dSab 			break;
984981a172dSab 		case 'T':
985981a172dSab 			/*
986981a172dSab 			 * We can't evaluate the value yet, because
987981a172dSab 			 * we need to know if -p is used or not in
988981a172dSab 			 * order to tell if we're seeing section header
989981a172dSab 			 * or program header types. So, we save the
990981a172dSab 			 * string in the name field, and then convert
991981a172dSab 			 * it to a type integer in a following pass.
992981a172dSab 			 */
993981a172dSab 			match_data.opt_type = MATCH_OPT_TYPE;
994981a172dSab 			match_data.value.name = optarg;
995981a172dSab 			if (!add_match_record(argv[0], &match_data))
996981a172dSab 				return (1);
997981a172dSab 			flags |= FLG_CTL_MATCH;
9985aefb655Srie 			break;
9995aefb655Srie 		case 'u':
1000981a172dSab 			flags |= FLG_SHOW_UNWIND;
10015aefb655Srie 			break;
10025aefb655Srie 		case 'v':
1003981a172dSab 			flags |= FLG_SHOW_VERSIONS;
10045aefb655Srie 			break;
10055aefb655Srie 		case 'w':
10065aefb655Srie 			wname = optarg;
10075aefb655Srie 			break;
10085aefb655Srie 		case 'y':
1009981a172dSab 			flags |= FLG_SHOW_SYMINFO;
10105aefb655Srie 			break;
10115aefb655Srie 		case '?':
10125aefb655Srie 			(void) fprintf(stderr, MSG_INTL(MSG_USAGE_BRIEF),
10135aefb655Srie 			    basename(argv[0]));
10145aefb655Srie 			detail_usage();
10155aefb655Srie 			return (1);
10165aefb655Srie 		default:
10175aefb655Srie 			break;
10185aefb655Srie 		}
10195aefb655Srie 	}
10205aefb655Srie 
1021981a172dSab 	/* -p and -w are mutually exclusive. -w only works with sections */
1022981a172dSab 	if (((flags & FLG_SHOW_PHDR) != 0) && (wname != NULL))
1023981a172dSab 		goto usage_brief;
1024981a172dSab 
1025981a172dSab 	/* If a match argument is present, prepare the match state */
1026981a172dSab 	if ((match_state.list != NULL) && (match_prepare(argv[0], flags) == 0))
1027981a172dSab 		return (1);
1028981a172dSab 
10295aefb655Srie 	/*
1030981a172dSab 	 * Decide what to do if no options specifying something to
1031981a172dSab 	 * show or do are present.
1032981a172dSab 	 *
1033981a172dSab 	 * If there is no -w and no match options, then we will set all
1034981a172dSab 	 * the show flags, causing a full display of everything in the
1035981a172dSab 	 * file that we know how to handle.
1036981a172dSab 	 *
1037981a172dSab 	 * Otherwise, if there is no match list, we generate a usage
1038981a172dSab 	 * error and quit.
1039981a172dSab 	 *
1040981a172dSab 	 * In the case where there is a match list, we go ahead and call
1041981a172dSab 	 * regular() anyway, leaving it to decide what to do. If -w is
1042981a172dSab 	 * present, regular() will use the match list to handle it.
1043981a172dSab 	 * In addition, in the absence of explicit show/calc flags, regular()
1044981a172dSab 	 * will compare the section headers to the match list and use
1045981a172dSab 	 * that to generate the FLG_ bits that will display the information
1046981a172dSab 	 * specified by the match list.
10475aefb655Srie 	 */
1048981a172dSab 	if ((flags & ~FLG_MASK_CTL) == 0) {
1049981a172dSab 		if (!wname && (match_state.list == NULL))
1050981a172dSab 			flags |= FLG_MASK_SHOW;
1051981a172dSab 		else if (match_state.list == NULL)
1052981a172dSab 			goto usage_brief;
10535aefb655Srie 	}
10545aefb655Srie 
1055981a172dSab 	/* There needs to be at least 1 filename left following the options */
1056981a172dSab 	if ((var = argc - optind) == 0)
1057981a172dSab 		goto usage_brief;
10585aefb655Srie 
10595aefb655Srie 	/*
10605aefb655Srie 	 * If the -l/-C option is specified, set up the liblddbg.so.
10615aefb655Srie 	 */
1062981a172dSab 	if (flags & FLG_CTL_LONGNAME)
10635aefb655Srie 		dbg_desc->d_extra |= DBG_E_LONG;
1064981a172dSab 	if (flags & FLG_CTL_DEMANGLE)
10655aefb655Srie 		dbg_desc->d_extra |= DBG_E_DEMANGLE;
10665aefb655Srie 
10675aefb655Srie 	/*
10685aefb655Srie 	 * If the -w option has indicated an output file open it.  It's
10695aefb655Srie 	 * arguable whether this option has much use when multiple files are
10705aefb655Srie 	 * being processed.
1071981a172dSab 	 *
1072981a172dSab 	 * If wname is non-NULL, we know that -p was not specified, due
1073981a172dSab 	 * to the test above.
10745aefb655Srie 	 */
10755aefb655Srie 	if (wname) {
10765aefb655Srie 		if ((wfd = open(wname, (O_RDWR | O_CREAT | O_TRUNC),
10775aefb655Srie 		    0666)) < 0) {
10785aefb655Srie 			int err = errno;
10795aefb655Srie 			(void) fprintf(stderr, MSG_INTL(MSG_ERR_OPEN),
10805aefb655Srie 			    wname, strerror(err));
1081981a172dSab 			return (1);
10825aefb655Srie 		}
10835aefb655Srie 	}
10845aefb655Srie 
10855aefb655Srie 	/*
1086981a172dSab 	 * Open the input file, initialize the elf interface, and
1087981a172dSab 	 * process it.
10885aefb655Srie 	 */
1089981a172dSab 	ret = 0;
1090981a172dSab 	for (; (optind < argc) && (ret == 0); optind++) {
10915aefb655Srie 		const char	*file = argv[optind];
10925aefb655Srie 
10935aefb655Srie 		if ((fd = open(argv[optind], O_RDONLY)) == -1) {
10945aefb655Srie 			int err = errno;
10955aefb655Srie 			(void) fprintf(stderr, MSG_INTL(MSG_ERR_OPEN),
10965aefb655Srie 			    file, strerror(err));
10975aefb655Srie 			continue;
10985aefb655Srie 		}
10995aefb655Srie 		(void) elf_version(EV_CURRENT);
11005aefb655Srie 		if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) {
11015aefb655Srie 			failure(file, MSG_ORIG(MSG_ELF_BEGIN));
11025aefb655Srie 			(void) close(fd);
11035aefb655Srie 			continue;
11045aefb655Srie 		}
11055aefb655Srie 
11065aefb655Srie 		if (var > 1)
11075aefb655Srie 			dbg_print(0, MSG_ORIG(MSG_FMT_NLSTRNL), file);
11085aefb655Srie 
11095aefb655Srie 		switch (elf_kind(elf)) {
11105aefb655Srie 		case ELF_K_AR:
1111981a172dSab 			ret = archive(file, fd, elf, flags, wname, wfd);
11125aefb655Srie 			break;
11135aefb655Srie 		case ELF_K_ELF:
1114981a172dSab 			ret = decide(file, fd, elf, flags, wname, wfd);
11155aefb655Srie 			break;
11165aefb655Srie 		default:
11175aefb655Srie 			(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADFILE), file);
11185aefb655Srie 			break;
11195aefb655Srie 		}
11205aefb655Srie 
11215aefb655Srie 		(void) close(fd);
11225aefb655Srie 		(void) elf_end(elf);
11235aefb655Srie 	}
11245aefb655Srie 
11255aefb655Srie 	if (wfd)
11265aefb655Srie 		(void) close(wfd);
1127981a172dSab 	return (ret);
1128981a172dSab 
1129981a172dSab usage_brief:
1130981a172dSab 	/* Control comes here for a simple usage message and exit */
1131981a172dSab 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_BRIEF),
1132981a172dSab 	    basename(argv[0]));
1133981a172dSab 	return (1);
1134981a172dSab 
11355aefb655Srie }
1136