xref: /onnv-gate/usr/src/cmd/sgs/elfdump/common/main.c (revision 5411:7e4b0f185bae)
11618Srie /*
21618Srie  * CDDL HEADER START
31618Srie  *
41618Srie  * The contents of this file are subject to the terms of the
51618Srie  * Common Development and Distribution License (the "License").
61618Srie  * You may not use this file except in compliance with the License.
71618Srie  *
81618Srie  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
91618Srie  * or http://www.opensolaris.org/os/licensing.
101618Srie  * See the License for the specific language governing permissions
111618Srie  * and limitations under the License.
121618Srie  *
131618Srie  * When distributing Covered Code, include this CDDL HEADER in each
141618Srie  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
151618Srie  * If applicable, add the following below this CDDL HEADER, with the
161618Srie  * fields enclosed by brackets "[]" replaced with your own identifying
171618Srie  * information: Portions Copyright [yyyy] [name of copyright owner]
181618Srie  *
191618Srie  * CDDL HEADER END
201618Srie  */
211618Srie 
221618Srie /*
233492Sab196087  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
241618Srie  * Use is subject to license terms.
251618Srie  */
261618Srie #pragma ident	"%Z%%M%	%I%	%E% SMI"
271618Srie 
281618Srie /*
291618Srie  * Dump an elf file.
301618Srie  */
311618Srie #include	<sys/param.h>
321618Srie #include	<fcntl.h>
331618Srie #include	<stdio.h>
344168Sab196087 #include	<stdlib.h>
354168Sab196087 #include	<ctype.h>
361618Srie #include	<libelf.h>
371618Srie #include	<link.h>
381618Srie #include	<stdarg.h>
391618Srie #include	<unistd.h>
401618Srie #include	<libgen.h>
411618Srie #include	<libintl.h>
421618Srie #include	<locale.h>
431618Srie #include	<errno.h>
441618Srie #include	<strings.h>
451618Srie #include	<debug.h>
461618Srie #include	<conv.h>
471618Srie #include	<msg.h>
481618Srie #include	<_elfdump.h>
49*5411Sab196087 #include	<sys/elf_SPARC.h>
50*5411Sab196087 #include	<sys/elf_amd64.h>
51*5411Sab196087 
521618Srie 
534063Sab196087 const Cache	cache_init = {NULL, NULL, NULL, NULL, 0};
541618Srie 
554168Sab196087 
564168Sab196087 
57*5411Sab196087 /*
58*5411Sab196087  * The -I, -N, and -T options are called "match options", because
59*5411Sab196087  * they allow selecting the items to be displayed based on matching
60*5411Sab196087  * their index, name, or type.
61*5411Sab196087  *
62*5411Sab196087  * The ELF information to which -I, -N, or -T are applied in
63*5411Sab196087  * the current invocation is called the "match item".
64*5411Sab196087  */
654168Sab196087 typedef enum {
66*5411Sab196087 	MATCH_ITEM_PT,		/* Program header (PT_) */
67*5411Sab196087 	MATCH_ITEM_SHT		/* Section header (SHT_) */
68*5411Sab196087 } match_item_t;
69*5411Sab196087 
70*5411Sab196087 /* match_opt_t is  used to note which match option was used */
71*5411Sab196087 typedef enum {
72*5411Sab196087 	MATCH_OPT_NAME,		/* Record contains a name */
73*5411Sab196087 	MATCH_OPT_NDX,		/* Record contains a single index */
74*5411Sab196087 	MATCH_OPT_RANGE,	/* Record contains an index range */
75*5411Sab196087 	MATCH_OPT_TYPE,		/* Record contains a type (shdr or phdr) */
76*5411Sab196087 } match_opt_t;
774168Sab196087 
784168Sab196087 typedef struct _match {
794168Sab196087 	struct _match	*next;		/* Pointer to next item in list */
80*5411Sab196087 	match_opt_t	opt_type;
814168Sab196087 	union {
82*5411Sab196087 		const char	*name;	/* MATCH_OPT_NAME */
83*5411Sab196087 		struct {		/* MATCH_OPT_NDX and MATCH_OPT_RANGE */
844168Sab196087 			int	start;
85*5411Sab196087 			int	end;	/* Only for MATCH_OPT_RANGE */
864168Sab196087 		} ndx;
87*5411Sab196087 		uint32_t	type;	/* MATCH_OPT_TYPE */
884168Sab196087 	} value;
89*5411Sab196087 } match_rec_t;
90*5411Sab196087 
91*5411Sab196087 static struct {
92*5411Sab196087 	match_item_t	item_type;	/* Type of item being matched */
93*5411Sab196087 	match_rec_t	*list;		/* Records for (-I, -N, -T) options */
94*5411Sab196087 } match_state;
95*5411Sab196087 
96*5411Sab196087 
97*5411Sab196087 
98*5411Sab196087 /* Map names to their integer value */
99*5411Sab196087 typedef struct {
100*5411Sab196087 	const char	*sym_name;
101*5411Sab196087 	uint32_t	sym_value;
102*5411Sab196087 } atoui_sym_t;
103*5411Sab196087 
104*5411Sab196087 /*
105*5411Sab196087  * ELF section types.
106*5411Sab196087  */
107*5411Sab196087 static atoui_sym_t sym_sht[] = {
108*5411Sab196087 	{ MSG_ORIG(MSG_SHT_NULL),		SHT_NULL },
109*5411Sab196087 	{ MSG_ORIG(MSG_SHT_NULL_ALT1),		SHT_NULL },
110*5411Sab196087 
111*5411Sab196087 	{ MSG_ORIG(MSG_SHT_PROGBITS),		SHT_PROGBITS },
112*5411Sab196087 	{ MSG_ORIG(MSG_SHT_PROGBITS_ALT1),	SHT_PROGBITS },
113*5411Sab196087 
114*5411Sab196087 	{ MSG_ORIG(MSG_SHT_SYMTAB),		SHT_SYMTAB },
115*5411Sab196087 	{ MSG_ORIG(MSG_SHT_SYMTAB_ALT1),	SHT_SYMTAB },
116*5411Sab196087 
117*5411Sab196087 	{ MSG_ORIG(MSG_SHT_STRTAB),		SHT_STRTAB },
118*5411Sab196087 	{ MSG_ORIG(MSG_SHT_STRTAB_ALT1),	SHT_STRTAB },
119*5411Sab196087 
120*5411Sab196087 	{ MSG_ORIG(MSG_SHT_RELA),		SHT_RELA },
121*5411Sab196087 	{ MSG_ORIG(MSG_SHT_RELA_ALT1),		SHT_RELA },
122*5411Sab196087 
123*5411Sab196087 	{ MSG_ORIG(MSG_SHT_HASH),		SHT_HASH },
124*5411Sab196087 	{ MSG_ORIG(MSG_SHT_HASH_ALT1),		SHT_HASH },
125*5411Sab196087 
126*5411Sab196087 	{ MSG_ORIG(MSG_SHT_DYNAMIC),		SHT_DYNAMIC },
127*5411Sab196087 	{ MSG_ORIG(MSG_SHT_DYNAMIC_ALT1),	SHT_DYNAMIC },
128*5411Sab196087 
129*5411Sab196087 	{ MSG_ORIG(MSG_SHT_NOTE),		SHT_NOTE },
130*5411Sab196087 	{ MSG_ORIG(MSG_SHT_NOTE_ALT1),		SHT_NOTE },
131*5411Sab196087 
132*5411Sab196087 	{ MSG_ORIG(MSG_SHT_NOBITS),		SHT_NOBITS },
133*5411Sab196087 	{ MSG_ORIG(MSG_SHT_NOBITS_ALT1),	SHT_NOBITS },
134*5411Sab196087 
135*5411Sab196087 	{ MSG_ORIG(MSG_SHT_REL),		SHT_REL },
136*5411Sab196087 	{ MSG_ORIG(MSG_SHT_REL_ALT1),		SHT_REL },
137*5411Sab196087 
138*5411Sab196087 	{ MSG_ORIG(MSG_SHT_SHLIB),		SHT_SHLIB },
139*5411Sab196087 	{ MSG_ORIG(MSG_SHT_SHLIB_ALT1),		SHT_SHLIB },
140*5411Sab196087 
141*5411Sab196087 	{ MSG_ORIG(MSG_SHT_DYNSYM),		SHT_DYNSYM },
142*5411Sab196087 	{ MSG_ORIG(MSG_SHT_DYNSYM_ALT1),	SHT_DYNSYM },
143*5411Sab196087 
144*5411Sab196087 	{ MSG_ORIG(MSG_SHT_INIT_ARRAY),		SHT_INIT_ARRAY },
145*5411Sab196087 	{ MSG_ORIG(MSG_SHT_INIT_ARRAY_ALT1),	SHT_INIT_ARRAY },
146*5411Sab196087 
147*5411Sab196087 	{ MSG_ORIG(MSG_SHT_FINI_ARRAY),		SHT_FINI_ARRAY },
148*5411Sab196087 	{ MSG_ORIG(MSG_SHT_FINI_ARRAY_ALT1),	SHT_FINI_ARRAY },
149*5411Sab196087 
150*5411Sab196087 	{ MSG_ORIG(MSG_SHT_PREINIT_ARRAY),	SHT_PREINIT_ARRAY },
151*5411Sab196087 	{ MSG_ORIG(MSG_SHT_PREINIT_ARRAY_ALT1),	SHT_PREINIT_ARRAY },
152*5411Sab196087 
153*5411Sab196087 	{ MSG_ORIG(MSG_SHT_GROUP),		SHT_GROUP },
154*5411Sab196087 	{ MSG_ORIG(MSG_SHT_GROUP_ALT1),		SHT_GROUP },
155*5411Sab196087 
156*5411Sab196087 	{ MSG_ORIG(MSG_SHT_SYMTAB_SHNDX),	SHT_SYMTAB_SHNDX },
157*5411Sab196087 	{ MSG_ORIG(MSG_SHT_SYMTAB_SHNDX_ALT1),	SHT_SYMTAB_SHNDX },
158*5411Sab196087 
159*5411Sab196087 	{ MSG_ORIG(MSG_SHT_SUNW_SYMSORT),	SHT_SUNW_symsort },
160*5411Sab196087 	{ MSG_ORIG(MSG_SHT_SUNW_SYMSORT_ALT1),	SHT_SUNW_symsort },
161*5411Sab196087 
162*5411Sab196087 	{ MSG_ORIG(MSG_SHT_SUNW_TLSSORT),	SHT_SUNW_tlssort },
163*5411Sab196087 	{ MSG_ORIG(MSG_SHT_SUNW_TLSSORT_ALT1),	SHT_SUNW_tlssort },
164*5411Sab196087 
165*5411Sab196087 	{ MSG_ORIG(MSG_SHT_SUNW_LDYNSYM),	SHT_SUNW_LDYNSYM },
166*5411Sab196087 	{ MSG_ORIG(MSG_SHT_SUNW_LDYNSYM_ALT1),	SHT_SUNW_LDYNSYM },
167*5411Sab196087 
168*5411Sab196087 	{ MSG_ORIG(MSG_SHT_SUNW_DOF),		SHT_SUNW_dof },
169*5411Sab196087 	{ MSG_ORIG(MSG_SHT_SUNW_DOF_ALT1),	SHT_SUNW_dof },
170*5411Sab196087 
171*5411Sab196087 	{ MSG_ORIG(MSG_SHT_SUNW_CAP),		SHT_SUNW_cap },
172*5411Sab196087 	{ MSG_ORIG(MSG_SHT_SUNW_CAP_ALT1),	SHT_SUNW_cap },
173*5411Sab196087 
174*5411Sab196087 	{ MSG_ORIG(MSG_SHT_SUNW_SIGNATURE),	SHT_SUNW_SIGNATURE },
175*5411Sab196087 	{ MSG_ORIG(MSG_SHT_SUNW_SIGNATURE_ALT1), SHT_SUNW_SIGNATURE },
176*5411Sab196087 
177*5411Sab196087 	{ MSG_ORIG(MSG_SHT_SUNW_ANNOTATE),	SHT_SUNW_ANNOTATE },
178*5411Sab196087 	{ MSG_ORIG(MSG_SHT_SUNW_ANNOTATE_ALT1),	SHT_SUNW_ANNOTATE },
1794168Sab196087 
180*5411Sab196087 	{ MSG_ORIG(MSG_SHT_SUNW_DEBUGSTR),	SHT_SUNW_DEBUGSTR },
181*5411Sab196087 	{ MSG_ORIG(MSG_SHT_SUNW_DEBUGSTR_ALT1),	SHT_SUNW_DEBUGSTR },
182*5411Sab196087 
183*5411Sab196087 	{ MSG_ORIG(MSG_SHT_SUNW_DEBUG),		SHT_SUNW_DEBUG },
184*5411Sab196087 	{ MSG_ORIG(MSG_SHT_SUNW_DEBUG_ALT1),	SHT_SUNW_DEBUG },
185*5411Sab196087 
186*5411Sab196087 	{ MSG_ORIG(MSG_SHT_SUNW_MOVE),		SHT_SUNW_move },
187*5411Sab196087 	{ MSG_ORIG(MSG_SHT_SUNW_MOVE_ALT1),	SHT_SUNW_move },
188*5411Sab196087 
189*5411Sab196087 	{ MSG_ORIG(MSG_SHT_SUNW_COMDAT),	SHT_SUNW_COMDAT },
190*5411Sab196087 	{ MSG_ORIG(MSG_SHT_SUNW_COMDAT_ALT1),	SHT_SUNW_COMDAT },
191*5411Sab196087 
192*5411Sab196087 	{ MSG_ORIG(MSG_SHT_SUNW_SYMINFO),	SHT_SUNW_syminfo },
193*5411Sab196087 	{ MSG_ORIG(MSG_SHT_SUNW_SYMINFO_ALT1),	SHT_SUNW_syminfo },
194*5411Sab196087 
195*5411Sab196087 	{ MSG_ORIG(MSG_SHT_SUNW_VERDEF),	SHT_SUNW_verdef },
196*5411Sab196087 	{ MSG_ORIG(MSG_SHT_SUNW_VERDEF_ALT1),	SHT_SUNW_verdef },
197*5411Sab196087 
198*5411Sab196087 	{ MSG_ORIG(MSG_SHT_GNU_VERDEF),		SHT_GNU_verdef },
199*5411Sab196087 	{ MSG_ORIG(MSG_SHT_GNU_VERDEF_ALT1),	SHT_GNU_verdef },
200*5411Sab196087 
201*5411Sab196087 	{ MSG_ORIG(MSG_SHT_SUNW_VERNEED),	SHT_SUNW_verneed },
202*5411Sab196087 	{ MSG_ORIG(MSG_SHT_SUNW_VERNEED_ALT1),	SHT_SUNW_verneed },
203*5411Sab196087 
204*5411Sab196087 	{ MSG_ORIG(MSG_SHT_GNU_VERNEED),	SHT_GNU_verneed },
205*5411Sab196087 	{ MSG_ORIG(MSG_SHT_GNU_VERNEED_ALT1),	SHT_GNU_verneed },
206*5411Sab196087 
207*5411Sab196087 	{ MSG_ORIG(MSG_SHT_SUNW_VERSYM),	SHT_SUNW_versym },
208*5411Sab196087 	{ MSG_ORIG(MSG_SHT_SUNW_VERSYM_ALT1),	SHT_SUNW_versym },
209*5411Sab196087 
210*5411Sab196087 	{ MSG_ORIG(MSG_SHT_GNU_VERSYM),		SHT_GNU_versym },
211*5411Sab196087 	{ MSG_ORIG(MSG_SHT_GNU_VERSYM_ALT1),	SHT_GNU_versym },
212*5411Sab196087 
213*5411Sab196087 	{ MSG_ORIG(MSG_SHT_SPARC_GOTDATA),	SHT_SPARC_GOTDATA },
214*5411Sab196087 	{ MSG_ORIG(MSG_SHT_SPARC_GOTDATA_ALT1),	SHT_SPARC_GOTDATA },
215*5411Sab196087 
216*5411Sab196087 	{ MSG_ORIG(MSG_SHT_AMD64_UNWIND),	SHT_AMD64_UNWIND },
217*5411Sab196087 	{ MSG_ORIG(MSG_SHT_AMD64_UNWIND_ALT1),	SHT_AMD64_UNWIND },
218*5411Sab196087 
219*5411Sab196087 	{ NULL }
220*5411Sab196087 };
221*5411Sab196087 
222*5411Sab196087 /*
223*5411Sab196087  * Program header PT_* type values
224*5411Sab196087  */
225*5411Sab196087 static atoui_sym_t sym_pt[] = {
226*5411Sab196087 	{ MSG_ORIG(MSG_PT_NULL),		PT_NULL },
227*5411Sab196087 	{ MSG_ORIG(MSG_PT_NULL_ALT1),		PT_NULL },
228*5411Sab196087 
229*5411Sab196087 	{ MSG_ORIG(MSG_PT_LOAD),		PT_LOAD },
230*5411Sab196087 	{ MSG_ORIG(MSG_PT_LOAD_ALT1),		PT_LOAD },
231*5411Sab196087 
232*5411Sab196087 	{ MSG_ORIG(MSG_PT_DYNAMIC),		PT_DYNAMIC },
233*5411Sab196087 	{ MSG_ORIG(MSG_PT_DYNAMIC_ALT1),	PT_DYNAMIC },
234*5411Sab196087 
235*5411Sab196087 	{ MSG_ORIG(MSG_PT_INTERP),		PT_INTERP },
236*5411Sab196087 	{ MSG_ORIG(MSG_PT_INTERP_ALT1),		PT_INTERP },
237*5411Sab196087 
238*5411Sab196087 	{ MSG_ORIG(MSG_PT_NOTE),		PT_NOTE },
239*5411Sab196087 	{ MSG_ORIG(MSG_PT_NOTE_ALT1),		PT_NOTE },
240*5411Sab196087 
241*5411Sab196087 	{ MSG_ORIG(MSG_PT_SHLIB),		PT_SHLIB },
242*5411Sab196087 	{ MSG_ORIG(MSG_PT_SHLIB_ALT1),		PT_SHLIB },
243*5411Sab196087 
244*5411Sab196087 	{ MSG_ORIG(MSG_PT_PHDR),		PT_PHDR },
245*5411Sab196087 	{ MSG_ORIG(MSG_PT_PHDR_ALT1),		PT_PHDR },
246*5411Sab196087 
247*5411Sab196087 	{ MSG_ORIG(MSG_PT_TLS),			PT_TLS },
248*5411Sab196087 	{ MSG_ORIG(MSG_PT_TLS_ALT1),		PT_TLS },
249*5411Sab196087 
250*5411Sab196087 	{ MSG_ORIG(MSG_PT_SUNW_UNWIND),		PT_SUNW_UNWIND },
251*5411Sab196087 	{ MSG_ORIG(MSG_PT_SUNW_UNWIND_ALT1),	PT_SUNW_UNWIND },
252*5411Sab196087 
253*5411Sab196087 	{ MSG_ORIG(MSG_PT_SUNWBSS),		PT_SUNWBSS },
254*5411Sab196087 	{ MSG_ORIG(MSG_PT_SUNWBSS_ALT1),	PT_SUNWBSS },
255*5411Sab196087 
256*5411Sab196087 	{ MSG_ORIG(MSG_PT_SUNWSTACK),		PT_SUNWSTACK },
257*5411Sab196087 	{ MSG_ORIG(MSG_PT_SUNWSTACK_ALT1),	PT_SUNWSTACK },
258*5411Sab196087 
259*5411Sab196087 	{ MSG_ORIG(MSG_PT_SUNWDTRACE),		PT_SUNWDTRACE },
260*5411Sab196087 	{ MSG_ORIG(MSG_PT_SUNWDTRACE_ALT1),	PT_SUNWDTRACE },
261*5411Sab196087 
262*5411Sab196087 	{ MSG_ORIG(MSG_PT_SUNWCAP),		PT_SUNWCAP },
263*5411Sab196087 	{ MSG_ORIG(MSG_PT_SUNWCAP_ALT1),	PT_SUNWCAP },
264*5411Sab196087 
265*5411Sab196087 	{ NULL }
266*5411Sab196087 };
267*5411Sab196087 
268*5411Sab196087 
269*5411Sab196087 
270*5411Sab196087 
2714168Sab196087 
2721618Srie const char *
2731618Srie _elfdump_msg(Msg mid)
2741618Srie {
2751618Srie 	return (gettext(MSG_ORIG(mid)));
2761618Srie }
2771618Srie 
2781618Srie /*
2791618Srie  * Determine whether a symbol name should be demangled.
2801618Srie  */
2811618Srie const char *
2821618Srie demangle(const char *name, uint_t flags)
2831618Srie {
284*5411Sab196087 	if (flags & FLG_CTL_DEMANGLE)
2851618Srie 		return (Elf_demangle_name(name));
2861618Srie 	else
2871618Srie 		return ((char *)name);
2881618Srie }
2891618Srie 
2901618Srie /*
2911618Srie  * Define our own standard error routine.
2921618Srie  */
2931618Srie void
2941618Srie failure(const char *file, const char *func)
2951618Srie {
2961618Srie 	(void) fprintf(stderr, MSG_INTL(MSG_ERR_FAILURE),
2971618Srie 	    file, func, elf_errmsg(elf_errno()));
2981618Srie }
2991618Srie 
3001618Srie /*
3011618Srie  * The full usage message
3021618Srie  */
3031618Srie static void
3041618Srie detail_usage()
3051618Srie {
3061618Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL1));
3071618Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL2));
3081618Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL3));
3091618Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL4));
3101618Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL5));
3111618Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL6));
3121618Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL7));
3131618Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL8));
3141618Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL9));
3151618Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL10));
3161618Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL11));
3171618Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL12));
3181618Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL13));
3191618Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL14));
3201618Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL15));
3211618Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL16));
3221618Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL17));
3231618Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL18));
3241618Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL19));
3251618Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL20));
3263492Sab196087 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL21));
3274168Sab196087 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL22));
3284168Sab196087 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL23));
3294665Sab196087 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL24));
330*5411Sab196087 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL25));
3314168Sab196087 }
3324168Sab196087 
3334168Sab196087 /*
3344168Sab196087  * Convert the ASCII representation of an index, or index range, into
3354168Sab196087  * binary form, and store it in rec:
3364168Sab196087  *
3374168Sab196087  *	index: An positive or 0 valued integer
3384168Sab196087  *	range: Two indexes, separated by a ':' character, denoting
3394168Sab196087  *		a range of allowed values. If the second value is omitted,
3404168Sab196087  *		any values equal to or greater than the first will match.
3414168Sab196087  *
3424168Sab196087  * exit:
343*5411Sab196087  *	On success, *rec is filled in with a MATCH_OPT_NDX or MATCH_OPT_RANGE
3444168Sab196087  *	value, and this function returns (1). On failure, the contents
3454168Sab196087  *	of *rec are undefined, and (0) is returned.
3464168Sab196087  */
3474168Sab196087 int
348*5411Sab196087 process_index_opt(const char *str, match_rec_t *rec)
3494168Sab196087 {
3504168Sab196087 #define	SKIP_BLANK for (; *str && isspace(*str); str++)
3514168Sab196087 
3524168Sab196087 	char	*endptr;
3534168Sab196087 
3544168Sab196087 	rec->value.ndx.start = strtol(str, &endptr, 10);
3554168Sab196087 	/* Value must use some of the input, and be 0 or positive */
3564168Sab196087 	if ((str == endptr) || (rec->value.ndx.start < 0))
3574168Sab196087 		return (0);
3584168Sab196087 	str = endptr;
3594168Sab196087 
3604168Sab196087 	SKIP_BLANK;
3614168Sab196087 	if (*str != ':') {
362*5411Sab196087 		rec->opt_type = MATCH_OPT_NDX;
3634168Sab196087 	} else {
3644168Sab196087 		str++;					/* Skip the ':' */
365*5411Sab196087 		rec->opt_type = MATCH_OPT_RANGE;
3664168Sab196087 		SKIP_BLANK;
3674168Sab196087 		if (*str == '\0') {
3684168Sab196087 			rec->value.ndx.end = -1;	/* Indicates "to end" */
3694168Sab196087 		} else {
3704168Sab196087 			rec->value.ndx.end = strtol(str, &endptr, 10);
3714168Sab196087 			if ((str == endptr) || (rec->value.ndx.end < 0))
3724168Sab196087 				return (0);
3734168Sab196087 			str = endptr;
3744168Sab196087 			SKIP_BLANK;
3754168Sab196087 		}
3764168Sab196087 	}
3774168Sab196087 
3784168Sab196087 	/* Syntax error if anything is left over */
3794168Sab196087 	if (*str != '\0')
3804168Sab196087 		return (0);
3814168Sab196087 
3824168Sab196087 	return (1);
3834168Sab196087 
3844168Sab196087 #undef	SKIP_BLANK
3854168Sab196087 }
3864168Sab196087 
3874168Sab196087 /*
388*5411Sab196087  * Process the symbolic name to value mappings passed to the
389*5411Sab196087  * atoui() function.
390*5411Sab196087  *
391*5411Sab196087  * entry:
392*5411Sab196087  *	sym - NULL terminated array of name->value mappings.
393*5411Sab196087  *	value - Address of variable to receive corresponding value.
394*5411Sab196087  *
395*5411Sab196087  * exit:
396*5411Sab196087  *	If a mapping is found, *value is set to it, and True is returned.
397*5411Sab196087  *	Otherwise False is returned.
398*5411Sab196087  */
399*5411Sab196087 static int
400*5411Sab196087 atoui_sym_process(const char *str, const atoui_sym_t *sym, uint32_t *value)
401*5411Sab196087 {
402*5411Sab196087 	size_t		cmp_len;
403*5411Sab196087 	const char	*tail;
404*5411Sab196087 
405*5411Sab196087 	while (isspace(*str))
406*5411Sab196087 		str++;
407*5411Sab196087 
408*5411Sab196087 	tail = str + strlen(str);
409*5411Sab196087 	while ((tail > str) && isspace(*(tail - 1)))
410*5411Sab196087 		tail--;
411*5411Sab196087 
412*5411Sab196087 	cmp_len = tail - str;
413*5411Sab196087 
414*5411Sab196087 	for (; sym->sym_name != NULL; sym++) {
415*5411Sab196087 		if ((strlen(sym->sym_name) == cmp_len) &&
416*5411Sab196087 		    (strncasecmp(sym->sym_name, str, cmp_len) == 0)) {
417*5411Sab196087 			*value = sym->sym_value;
418*5411Sab196087 			return (1);
419*5411Sab196087 		}
420*5411Sab196087 	}
421*5411Sab196087 
422*5411Sab196087 	/* No symbolic mapping was found */
423*5411Sab196087 	return (0);
424*5411Sab196087 }
425*5411Sab196087 
426*5411Sab196087 
427*5411Sab196087 /*
428*5411Sab196087  * Convert a string to a numeric value. Strings starting with '0'
429*5411Sab196087  * are taken to be octal, those staring with '0x' are hex, and all
430*5411Sab196087  * others are decimal.
431*5411Sab196087  *
432*5411Sab196087  * entry:
433*5411Sab196087  *	str - String to be converted
434*5411Sab196087  *	sym - NULL, or NULL terminated array of name/value pairs.
435*5411Sab196087  *	v - Address of variable to receive resulting value.
436*5411Sab196087  *
437*5411Sab196087  * exit:
438*5411Sab196087  *	On success, returns True (1) and *v is set to the value.
439*5411Sab196087  *	On failure, returns False (0) and *v is undefined.
440*5411Sab196087  */
441*5411Sab196087 static int
442*5411Sab196087 atoui(const char *str, const atoui_sym_t *sym, uint32_t *v)
443*5411Sab196087 {
444*5411Sab196087 	char		*endptr;
445*5411Sab196087 
446*5411Sab196087 	if (sym && atoui_sym_process(str, sym, v))
447*5411Sab196087 		return (1);
448*5411Sab196087 
449*5411Sab196087 	*v = strtoull(str, &endptr, 0);
450*5411Sab196087 
451*5411Sab196087 	/* If the left over part contains anything but whitespace, fail */
452*5411Sab196087 	for (; *endptr; endptr++)
453*5411Sab196087 		if (!isspace(*endptr))
454*5411Sab196087 			return (0);
455*5411Sab196087 	return (1);
456*5411Sab196087 }
457*5411Sab196087 
458*5411Sab196087 /*
459*5411Sab196087  * Called after getopt() processing is finished if there is a non-empty
460*5411Sab196087  * match list. Prepares the matching code for use.
461*5411Sab196087  *
462*5411Sab196087  * exit:
463*5411Sab196087  *	Returns True (1) if no errors are encountered. Writes an
464*5411Sab196087  *	error string to stderr and returns False (0) otherwise.
465*5411Sab196087  */
466*5411Sab196087 static int
467*5411Sab196087 match_prepare(char *argv0, uint_t flags)
468*5411Sab196087 {
469*5411Sab196087 	atoui_sym_t	*sym;
470*5411Sab196087 	match_rec_t	*list;
471*5411Sab196087 	const char	*str;
472*5411Sab196087 	int		minus_p = (flags & FLG_SHOW_PHDR) != 0;
473*5411Sab196087 
474*5411Sab196087 	/*
475*5411Sab196087 	 * Flag ambiguous attempt to use match option with both -p and
476*5411Sab196087 	 * and one or more section SHOW options. In this case, we
477*5411Sab196087 	 * can't tell what type of item we're supposed to match against.
478*5411Sab196087 	 */
479*5411Sab196087 	if (minus_p && (flags & FLG_MASK_SHOW_SHDR)) {
480*5411Sab196087 		(void) fprintf(stderr, MSG_INTL(MSG_ERR_AMBIG_MATCH),
481*5411Sab196087 		    basename(argv0));
482*5411Sab196087 		return (0);
483*5411Sab196087 	}
484*5411Sab196087 
485*5411Sab196087 	/* Set the match type, based on the presence of the -p option */
486*5411Sab196087 	if (minus_p) {
487*5411Sab196087 		match_state.item_type = MATCH_ITEM_PT;
488*5411Sab196087 		sym = sym_pt;
489*5411Sab196087 	} else {
490*5411Sab196087 		match_state.item_type = MATCH_ITEM_SHT;
491*5411Sab196087 		sym = sym_sht;
492*5411Sab196087 	}
493*5411Sab196087 
494*5411Sab196087 	/*
495*5411Sab196087 	 * Scan match list and perform any necessary fixups:
496*5411Sab196087 	 *
497*5411Sab196087 	 * MATCH_OPT_NAME: If -p is specified, convert MATCH_OPT_NAME (-N)
498*5411Sab196087 	 *	requests into MATCH_OPT_TYPE (-T).
499*5411Sab196087 	 *
500*5411Sab196087 	 * MATCH_OPT_TYPE: Now that we know item type we are matching
501*5411Sab196087 	 *	against, we can convert the string saved in the name
502*5411Sab196087 	 *	field during getopt() processing into an integer and
503*5411Sab196087 	 *	write it into the type field.
504*5411Sab196087 	 */
505*5411Sab196087 	for (list = match_state.list; list; list = list->next) {
506*5411Sab196087 		if ((list->opt_type == MATCH_OPT_NAME) && minus_p)
507*5411Sab196087 			list->opt_type = MATCH_OPT_TYPE;
508*5411Sab196087 
509*5411Sab196087 		if (list->opt_type != MATCH_OPT_TYPE)
510*5411Sab196087 			continue;
511*5411Sab196087 
512*5411Sab196087 		str = list->value.name;
513*5411Sab196087 		if (atoui(str, sym, &list->value.type) == 0) {
514*5411Sab196087 			const char *fmt = minus_p ?
515*5411Sab196087 			    MSG_INTL(MSG_ERR_BAD_T_PT) :
516*5411Sab196087 			    MSG_INTL(MSG_ERR_BAD_T_SHT);
517*5411Sab196087 
518*5411Sab196087 			(void) fprintf(stderr, fmt, basename(argv0), str);
519*5411Sab196087 			return (0);
520*5411Sab196087 		}
521*5411Sab196087 	}
522*5411Sab196087 
523*5411Sab196087 	return (1);
524*5411Sab196087 }
525*5411Sab196087 
526*5411Sab196087 
527*5411Sab196087 /*
5284168Sab196087  * Returns True (1) if the item with the given name or index should
5294168Sab196087  * be displayed, and False (0) if it should not be.
5304168Sab196087  *
5314168Sab196087  * entry:
532*5411Sab196087  *	match_flags - Bitmask specifying matching options, as described
533*5411Sab196087  *		in _elfdump.h.
534*5411Sab196087  *	name - If MATCH_F_NAME flag is set, name of item under
535*5411Sab196087  *		consideration. Otherwise ignored.
5364168Sab196087  *		should not be considered.
537*5411Sab196087  *	ndx - If MATCH_F_NDX flag is set, index of item under consideration.
538*5411Sab196087  *	type - If MATCH_F_TYPE is set, type of item under consideration.
539*5411Sab196087  *		If MATCH_F_PHDR is set, this would be a program
540*5411Sab196087  *		header type (PT_). Otherwise, a section header type (SHT_).
5414168Sab196087  *
5424168Sab196087  * exit:
5434168Sab196087  *	True will be returned if the given name/index matches those given
544*5411Sab196087  *	by one of the (-I, -N -T) command line options, or if no such option
545*5411Sab196087  *	was used in the command invocation and MATCH_F_STRICT is not
546*5411Sab196087  *	set.
5474168Sab196087  */
5484168Sab196087 int
549*5411Sab196087 match(match_flags_t match_flags, const char *name, uint_t ndx, uint_t type)
5504168Sab196087 {
551*5411Sab196087 	match_item_t item_type = (match_flags & MATCH_F_PHDR) ?
552*5411Sab196087 	    MATCH_ITEM_PT  : MATCH_ITEM_SHT;
553*5411Sab196087 	match_rec_t *list;
5544168Sab196087 
555*5411Sab196087 	/*
556*5411Sab196087 	 * If there is no match list, then we use the MATCH_F_STRICT
557*5411Sab196087 	 * flag to decide what to return. In the strict case, we return
558*5411Sab196087 	 * False (0), in the normal case, True (1).
559*5411Sab196087 	 */
560*5411Sab196087 	if (match_state.list == NULL)
561*5411Sab196087 		return ((match_flags & MATCH_F_STRICT) == 0);
562*5411Sab196087 
563*5411Sab196087 	/*
564*5411Sab196087 	 * If item being checked is not the current match type,
565*5411Sab196087 	 * then allow it.
566*5411Sab196087 	 */
567*5411Sab196087 	if (item_type != match_state.item_type)
5684168Sab196087 		return (1);
5694168Sab196087 
5704168Sab196087 	/* Run through the match records and check for a hit */
571*5411Sab196087 	for (list = match_state.list; list; list = list->next) {
572*5411Sab196087 		switch (list->opt_type) {
573*5411Sab196087 		case MATCH_OPT_NAME:
574*5411Sab196087 			if (((match_flags & MATCH_F_NAME) == 0) ||
575*5411Sab196087 			    (name == NULL))
576*5411Sab196087 				break;
577*5411Sab196087 			if (strcmp(list->value.name, name) == 0)
5784168Sab196087 				return (1);
5794168Sab196087 			break;
580*5411Sab196087 		case MATCH_OPT_NDX:
581*5411Sab196087 			if ((match_flags & MATCH_F_NDX) &&
582*5411Sab196087 			    (ndx == list->value.ndx.start))
5834168Sab196087 				return (1);
5844168Sab196087 			break;
585*5411Sab196087 		case MATCH_OPT_RANGE:
5864168Sab196087 			/*
5874168Sab196087 			 * A range end value less than 0 means that any value
5884168Sab196087 			 * above the start is acceptible.
5894168Sab196087 			 */
590*5411Sab196087 			if ((match_flags & MATCH_F_NDX) &&
591*5411Sab196087 			    (ndx >= list->value.ndx.start) &&
5924168Sab196087 			    ((list->value.ndx.end < 0) ||
5934168Sab196087 			    (ndx <= list->value.ndx.end)))
5944168Sab196087 				return (1);
5954168Sab196087 			break;
596*5411Sab196087 
597*5411Sab196087 		case MATCH_OPT_TYPE:
598*5411Sab196087 			if ((match_flags & MATCH_F_TYPE) &&
599*5411Sab196087 			    (type == list->value.type))
600*5411Sab196087 				return (1);
601*5411Sab196087 			break;
6024168Sab196087 		}
6034168Sab196087 	}
6044168Sab196087 
6054168Sab196087 	/* Nothing matched */
6064168Sab196087 	return (0);
6074168Sab196087 }
6084168Sab196087 
6094168Sab196087 /*
610*5411Sab196087  * Add an entry to match_state.list for use by match(). This routine is for
611*5411Sab196087  * use during getopt() processing. It should not be called once
612*5411Sab196087  * match_prepare() has been called.
6134168Sab196087  *
6144168Sab196087  * Return True (1) for success. On failure, an error is written
6154168Sab196087  * to stderr, and False (0) is returned.
6164168Sab196087  */
6174168Sab196087 static int
618*5411Sab196087 add_match_record(char *argv0, match_rec_t *data)
6194168Sab196087 {
620*5411Sab196087 	match_rec_t	*rec;
621*5411Sab196087 	match_rec_t	*list;
6224168Sab196087 
6234168Sab196087 	if ((rec = malloc(sizeof (*rec))) == NULL) {
6244168Sab196087 		int err = errno;
6254168Sab196087 		(void) fprintf(stderr, MSG_INTL(MSG_ERR_MALLOC),
6264168Sab196087 		    basename(argv0), strerror(err));
6274168Sab196087 		return (0);
6284168Sab196087 	}
6294168Sab196087 
6304168Sab196087 	*rec = *data;
6314168Sab196087 
632*5411Sab196087 	/* Insert at end of match_state.list */
633*5411Sab196087 	if (match_state.list == NULL) {
634*5411Sab196087 		match_state.list = rec;
6354168Sab196087 	} else {
636*5411Sab196087 		for (list = match_state.list; list->next != NULL;
637*5411Sab196087 		    list = list->next)
6384168Sab196087 			;
6394168Sab196087 		list->next = rec;
6404168Sab196087 	}
6414168Sab196087 
6424168Sab196087 	rec->next = NULL;
6434168Sab196087 	return (1);
6441618Srie }
6451618Srie 
646*5411Sab196087 static int
647*5411Sab196087 decide(const char *file, int fd, Elf *elf, uint_t flags,
648*5411Sab196087     const char *wname, int wfd)
6491618Srie {
650*5411Sab196087 	int r;
651*5411Sab196087 
6521618Srie 	if (gelf_getclass(elf) == ELFCLASS64)
653*5411Sab196087 		r = regular64(file, fd, elf, flags, wname, wfd);
6541618Srie 	else
655*5411Sab196087 		r = regular32(file, fd, elf, flags, wname, wfd);
656*5411Sab196087 
657*5411Sab196087 	return (r);
6581618Srie }
6591618Srie 
660*5411Sab196087 static int
661*5411Sab196087 archive(const char *file, int fd, Elf *elf, uint_t flags,
662*5411Sab196087     const char *wname, int wfd)
6631618Srie {
6641618Srie 	Elf_Cmd		cmd = ELF_C_READ;
6651618Srie 	Elf_Arhdr	*arhdr;
6661618Srie 	Elf		*_elf = 0;
6671618Srie 	size_t		ptr;
6681618Srie 	Elf_Arsym	*arsym = 0;
6691618Srie 
6701618Srie 	/*
6713492Sab196087 	 * Determine if the archive symbol table itself is required.
6721618Srie 	 */
673*5411Sab196087 	if ((flags & FLG_SHOW_SYMBOLS) &&
674*5411Sab196087 	    match(MATCH_F_NAME, MSG_ORIG(MSG_ELF_ARSYM), 0, 0)) {
6751618Srie 		/*
6761618Srie 		 * Get the archive symbol table.
6771618Srie 		 */
6781618Srie 		if (((arsym = elf_getarsym(elf, &ptr)) == 0) && elf_errno()) {
6791618Srie 			/*
6801618Srie 			 * The arsym could be 0 even though there was no error.
6811618Srie 			 * Print the error message only when there was
6821618Srie 			 * real error from elf_getarsym().
6831618Srie 			 */
6841618Srie 			failure(file, MSG_ORIG(MSG_ELF_GETARSYM));
685*5411Sab196087 			return (0);
6861618Srie 		}
6871618Srie 	}
6881618Srie 
6891618Srie 	/*
6901618Srie 	 * Print the archive symbol table only when the archive symbol
6911618Srie 	 * table exists and it was requested to print.
6921618Srie 	 */
6931618Srie 	if (arsym) {
6941618Srie 		size_t		cnt;
6951618Srie 		char		index[MAXNDXSIZE];
6961618Srie 		size_t		offset = 0, _offset = 0;
6971618Srie 
6981618Srie 		/*
6991618Srie 		 * Print out all the symbol entries.
7001618Srie 		 */
7011618Srie 		dbg_print(0, MSG_INTL(MSG_ARCHIVE_SYMTAB));
7021618Srie 		dbg_print(0, MSG_INTL(MSG_ARCHIVE_FIELDS));
7031618Srie 
7041618Srie 		for (cnt = 0; cnt < ptr; cnt++, arsym++) {
7051618Srie 			/*
7061618Srie 			 * For each object obtain an elf descriptor so that we
7071618Srie 			 * can establish the members name.  Note, we have had
7081618Srie 			 * archives where the archive header has not been
7091618Srie 			 * obtainable so be lenient with errors.
7101618Srie 			 */
7111618Srie 			if ((offset == 0) || ((arsym->as_off != 0) &&
7121618Srie 			    (arsym->as_off != _offset))) {
7131618Srie 
7141618Srie 				if (_elf)
7151618Srie 					(void) elf_end(_elf);
7161618Srie 
7171618Srie 				if (elf_rand(elf, arsym->as_off) !=
7181618Srie 				    arsym->as_off) {
7191618Srie 					failure(file, MSG_ORIG(MSG_ELF_RAND));
7201618Srie 					arhdr = 0;
7211618Srie 				} else if ((_elf = elf_begin(fd,
7221618Srie 				    ELF_C_READ, elf)) == 0) {
7231618Srie 					failure(file, MSG_ORIG(MSG_ELF_BEGIN));
7241618Srie 					arhdr = 0;
7251618Srie 				} else if ((arhdr = elf_getarhdr(_elf)) == 0) {
7261618Srie 					failure(file,
7271618Srie 					    MSG_ORIG(MSG_ELF_GETARHDR));
7281618Srie 					arhdr = 0;
7291618Srie 				}
7301618Srie 
7311618Srie 				_offset = arsym->as_off;
7321618Srie 				if (offset == 0)
7331618Srie 					offset = _offset;
7341618Srie 			}
7351618Srie 
7361618Srie 			(void) snprintf(index, MAXNDXSIZE,
7371618Srie 			    MSG_ORIG(MSG_FMT_INDEX), EC_XWORD(cnt));
7381618Srie 			if (arsym->as_off)
7391618Srie 				dbg_print(0, MSG_ORIG(MSG_FMT_ARSYM1), index,
7401618Srie 				    /* LINTED */
7411618Srie 				    (int)arsym->as_off, arhdr ? arhdr->ar_name :
7421618Srie 				    MSG_INTL(MSG_STR_UNKNOWN), (arsym->as_name ?
7431618Srie 				    demangle(arsym->as_name, flags) :
7441618Srie 				    MSG_INTL(MSG_STR_NULL)));
7451618Srie 			else
7461618Srie 				dbg_print(0, MSG_ORIG(MSG_FMT_ARSYM2), index,
7471618Srie 				    /* LINTED */
7481618Srie 				    (int)arsym->as_off);
7491618Srie 		}
7501618Srie 
7511618Srie 		if (_elf)
7521618Srie 			(void) elf_end(_elf);
7531618Srie 
7541618Srie 		/*
7551618Srie 		 * If we only need the archive symbol table return.
7561618Srie 		 */
757*5411Sab196087 		if ((flags & FLG_SHOW_SYMBOLS) &&
758*5411Sab196087 		    match(MATCH_F_STRICT | MATCH_F_NAME,
759*5411Sab196087 		    MSG_ORIG(MSG_ELF_ARSYM), -1, -1))
760*5411Sab196087 			return (0);
7611618Srie 
7621618Srie 		/*
7631618Srie 		 * Reset elf descriptor in preparation for processing each
7641618Srie 		 * member.
7651618Srie 		 */
7661618Srie 		if (offset)
7671618Srie 			(void) elf_rand(elf, offset);
7681618Srie 	}
7691618Srie 
7701618Srie 	/*
7711618Srie 	 * Process each object within the archive.
7721618Srie 	 */
7731618Srie 	while ((_elf = elf_begin(fd, cmd, elf)) != NULL) {
7741618Srie 		char	name[MAXPATHLEN];
7751618Srie 
7761618Srie 		if ((arhdr = elf_getarhdr(_elf)) == NULL) {
7771618Srie 			failure(file, MSG_ORIG(MSG_ELF_GETARHDR));
778*5411Sab196087 			return (0);
7791618Srie 		}
7801618Srie 		if (*arhdr->ar_name != '/') {
7811618Srie 			(void) snprintf(name, MAXPATHLEN,
7821618Srie 			    MSG_ORIG(MSG_FMT_ARNAME), file, arhdr->ar_name);
7831618Srie 			dbg_print(0, MSG_ORIG(MSG_FMT_NLSTR), name);
7841618Srie 
7851618Srie 			switch (elf_kind(_elf)) {
7861618Srie 			case ELF_K_AR:
787*5411Sab196087 				if (archive(name, fd, _elf, flags,
788*5411Sab196087 				    wname, wfd) == 1)
789*5411Sab196087 					return (1);
7901618Srie 				break;
7911618Srie 			case ELF_K_ELF:
792*5411Sab196087 				if (decide(name, fd, _elf, flags,
793*5411Sab196087 				    wname, wfd) == 1)
794*5411Sab196087 					return (1);
7951618Srie 				break;
7961618Srie 			default:
7971618Srie 				(void) fprintf(stderr,
7981618Srie 				    MSG_INTL(MSG_ERR_BADFILE), name);
7991618Srie 				break;
8001618Srie 			}
8011618Srie 		}
8021618Srie 
8031618Srie 		cmd = elf_next(_elf);
8041618Srie 		(void) elf_end(_elf);
8051618Srie 	}
806*5411Sab196087 
807*5411Sab196087 	return (0);
8081618Srie }
8091618Srie 
8101618Srie int
8111618Srie main(int argc, char **argv, char **envp)
8121618Srie {
8131618Srie 	Elf		*elf;
8141618Srie 	int		var, fd, wfd = 0;
815*5411Sab196087 	char		*wname = NULL;
8161618Srie 	uint_t		flags = 0;
817*5411Sab196087 	match_rec_t	match_data;
818*5411Sab196087 	int		ret;
8191618Srie 
8201618Srie 	/*
8211618Srie 	 * If we're on a 64-bit kernel, try to exec a full 64-bit version of
8221618Srie 	 * the binary.  If successful, conv_check_native() won't return.
8231618Srie 	 */
8242647Srie 	(void) conv_check_native(argv, envp);
8251618Srie 
8261618Srie 	/*
8271618Srie 	 * Establish locale.
8281618Srie 	 */
8291618Srie 	(void) setlocale(LC_MESSAGES, MSG_ORIG(MSG_STR_EMPTY));
8301618Srie 	(void) textdomain(MSG_ORIG(MSG_SUNW_OST_SGS));
8311618Srie 
8321618Srie 	(void) setvbuf(stdout, NULL, _IOLBF, 0);
8331618Srie 	(void) setvbuf(stderr, NULL, _IOLBF, 0);
8341618Srie 
8351618Srie 	opterr = 0;
8361618Srie 	while ((var = getopt(argc, argv, MSG_ORIG(MSG_STR_OPTIONS))) != EOF) {
8371618Srie 		switch (var) {
8381618Srie 		case 'C':
839*5411Sab196087 			flags |= FLG_CTL_DEMANGLE;
8401618Srie 			break;
8411618Srie 		case 'c':
842*5411Sab196087 			flags |= FLG_SHOW_SHDR;
8431618Srie 			break;
8441618Srie 		case 'd':
845*5411Sab196087 			flags |= FLG_SHOW_DYNAMIC;
8461618Srie 			break;
8471618Srie 		case 'e':
848*5411Sab196087 			flags |= FLG_SHOW_EHDR;
8491618Srie 			break;
8501618Srie 		case 'G':
851*5411Sab196087 			flags |= FLG_SHOW_GOT;
8521618Srie 			break;
8531618Srie 		case 'g':
854*5411Sab196087 			flags |= FLG_SHOW_GROUP;
8551618Srie 			break;
8561618Srie 		case 'H':
857*5411Sab196087 			flags |= FLG_SHOW_CAP;
8581618Srie 			break;
8591618Srie 		case 'h':
860*5411Sab196087 			flags |= FLG_SHOW_HASH;
8611618Srie 			break;
8624168Sab196087 		case 'I':
863*5411Sab196087 			if (!process_index_opt(optarg, &match_data))
864*5411Sab196087 				goto usage_brief;
8654168Sab196087 			if (!add_match_record(argv[0], &match_data))
8664168Sab196087 				return (1);
867*5411Sab196087 			flags |= FLG_CTL_MATCH;
8684168Sab196087 			break;
8691618Srie 		case 'i':
870*5411Sab196087 			flags |= FLG_SHOW_INTERP;
8711618Srie 			break;
8721618Srie 		case 'k':
873*5411Sab196087 			flags |= FLG_CALC_CHECKSUM;
8741618Srie 			break;
8751618Srie 		case 'l':
876*5411Sab196087 			flags |= FLG_CTL_LONGNAME;
8771618Srie 			break;
8781618Srie 		case 'm':
879*5411Sab196087 			flags |= FLG_SHOW_MOVE;
8801618Srie 			break;
8811618Srie 		case 'N':
882*5411Sab196087 			match_data.opt_type = MATCH_OPT_NAME;
8834168Sab196087 			match_data.value.name = optarg;
8844168Sab196087 			if (!add_match_record(argv[0], &match_data))
8854168Sab196087 				return (1);
886*5411Sab196087 			flags |= FLG_CTL_MATCH;
8871618Srie 			break;
8881618Srie 		case 'n':
889*5411Sab196087 			flags |= FLG_SHOW_NOTE;
8901618Srie 			break;
8914665Sab196087 		case 'P':
892*5411Sab196087 			flags |= FLG_CTL_FAKESHDR;
8934665Sab196087 			break;
8941618Srie 		case 'p':
895*5411Sab196087 			flags |= FLG_SHOW_PHDR;
8961618Srie 			break;
8971618Srie 		case 'r':
898*5411Sab196087 			flags |= FLG_SHOW_RELOC;
8991618Srie 			break;
9003492Sab196087 		case 'S':
901*5411Sab196087 			flags |= FLG_SHOW_SORT;
9023492Sab196087 			break;
9031618Srie 		case 's':
904*5411Sab196087 			flags |= FLG_SHOW_SYMBOLS;
905*5411Sab196087 			break;
906*5411Sab196087 		case 'T':
907*5411Sab196087 			/*
908*5411Sab196087 			 * We can't evaluate the value yet, because
909*5411Sab196087 			 * we need to know if -p is used or not in
910*5411Sab196087 			 * order to tell if we're seeing section header
911*5411Sab196087 			 * or program header types. So, we save the
912*5411Sab196087 			 * string in the name field, and then convert
913*5411Sab196087 			 * it to a type integer in a following pass.
914*5411Sab196087 			 */
915*5411Sab196087 			match_data.opt_type = MATCH_OPT_TYPE;
916*5411Sab196087 			match_data.value.name = optarg;
917*5411Sab196087 			if (!add_match_record(argv[0], &match_data))
918*5411Sab196087 				return (1);
919*5411Sab196087 			flags |= FLG_CTL_MATCH;
9201618Srie 			break;
9211618Srie 		case 'u':
922*5411Sab196087 			flags |= FLG_SHOW_UNWIND;
9231618Srie 			break;
9241618Srie 		case 'v':
925*5411Sab196087 			flags |= FLG_SHOW_VERSIONS;
9261618Srie 			break;
9271618Srie 		case 'w':
9281618Srie 			wname = optarg;
9291618Srie 			break;
9301618Srie 		case 'y':
931*5411Sab196087 			flags |= FLG_SHOW_SYMINFO;
9321618Srie 			break;
9331618Srie 		case '?':
9341618Srie 			(void) fprintf(stderr, MSG_INTL(MSG_USAGE_BRIEF),
9351618Srie 			    basename(argv[0]));
9361618Srie 			detail_usage();
9371618Srie 			return (1);
9381618Srie 		default:
9391618Srie 			break;
9401618Srie 		}
9411618Srie 	}
9421618Srie 
943*5411Sab196087 	/* -p and -w are mutually exclusive. -w only works with sections */
944*5411Sab196087 	if (((flags & FLG_SHOW_PHDR) != 0) && (wname != NULL))
945*5411Sab196087 		goto usage_brief;
946*5411Sab196087 
947*5411Sab196087 	/* If a match argument is present, prepare the match state */
948*5411Sab196087 	if ((match_state.list != NULL) && (match_prepare(argv[0], flags) == 0))
949*5411Sab196087 		return (1);
950*5411Sab196087 
9511618Srie 	/*
952*5411Sab196087 	 * Decide what to do if no options specifying something to
953*5411Sab196087 	 * show or do are present.
954*5411Sab196087 	 *
955*5411Sab196087 	 * If there is no -w and no match options, then we will set all
956*5411Sab196087 	 * the show flags, causing a full display of everything in the
957*5411Sab196087 	 * file that we know how to handle.
958*5411Sab196087 	 *
959*5411Sab196087 	 * Otherwise, if there is no match list, we generate a usage
960*5411Sab196087 	 * error and quit.
961*5411Sab196087 	 *
962*5411Sab196087 	 * In the case where there is a match list, we go ahead and call
963*5411Sab196087 	 * regular() anyway, leaving it to decide what to do. If -w is
964*5411Sab196087 	 * present, regular() will use the match list to handle it.
965*5411Sab196087 	 * In addition, in the absence of explicit show/calc flags, regular()
966*5411Sab196087 	 * will compare the section headers to the match list and use
967*5411Sab196087 	 * that to generate the FLG_ bits that will display the information
968*5411Sab196087 	 * specified by the match list.
9691618Srie 	 */
970*5411Sab196087 	if ((flags & ~FLG_MASK_CTL) == 0) {
971*5411Sab196087 		if (!wname && (match_state.list == NULL))
972*5411Sab196087 			flags |= FLG_MASK_SHOW;
973*5411Sab196087 		else if (match_state.list == NULL)
974*5411Sab196087 			goto usage_brief;
9751618Srie 	}
9761618Srie 
977*5411Sab196087 	/* There needs to be at least 1 filename left following the options */
978*5411Sab196087 	if ((var = argc - optind) == 0)
979*5411Sab196087 		goto usage_brief;
9801618Srie 
9811618Srie 	/*
9821618Srie 	 * If the -l/-C option is specified, set up the liblddbg.so.
9831618Srie 	 */
984*5411Sab196087 	if (flags & FLG_CTL_LONGNAME)
9851618Srie 		dbg_desc->d_extra |= DBG_E_LONG;
986*5411Sab196087 	if (flags & FLG_CTL_DEMANGLE)
9871618Srie 		dbg_desc->d_extra |= DBG_E_DEMANGLE;
9881618Srie 
9891618Srie 	/*
9901618Srie 	 * If the -w option has indicated an output file open it.  It's
9911618Srie 	 * arguable whether this option has much use when multiple files are
9921618Srie 	 * being processed.
993*5411Sab196087 	 *
994*5411Sab196087 	 * If wname is non-NULL, we know that -p was not specified, due
995*5411Sab196087 	 * to the test above.
9961618Srie 	 */
9971618Srie 	if (wname) {
9981618Srie 		if ((wfd = open(wname, (O_RDWR | O_CREAT | O_TRUNC),
9991618Srie 		    0666)) < 0) {
10001618Srie 			int err = errno;
10011618Srie 			(void) fprintf(stderr, MSG_INTL(MSG_ERR_OPEN),
10021618Srie 			    wname, strerror(err));
1003*5411Sab196087 			return (1);
10041618Srie 		}
10051618Srie 	}
10061618Srie 
10071618Srie 	/*
1008*5411Sab196087 	 * Open the input file, initialize the elf interface, and
1009*5411Sab196087 	 * process it.
10101618Srie 	 */
1011*5411Sab196087 	ret = 0;
1012*5411Sab196087 	for (; (optind < argc) && (ret == 0); optind++) {
10131618Srie 		const char	*file = argv[optind];
10141618Srie 
10151618Srie 		if ((fd = open(argv[optind], O_RDONLY)) == -1) {
10161618Srie 			int err = errno;
10171618Srie 			(void) fprintf(stderr, MSG_INTL(MSG_ERR_OPEN),
10181618Srie 			    file, strerror(err));
10191618Srie 			continue;
10201618Srie 		}
10211618Srie 		(void) elf_version(EV_CURRENT);
10221618Srie 		if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) {
10231618Srie 			failure(file, MSG_ORIG(MSG_ELF_BEGIN));
10241618Srie 			(void) close(fd);
10251618Srie 			continue;
10261618Srie 		}
10271618Srie 
10281618Srie 		if (var > 1)
10291618Srie 			dbg_print(0, MSG_ORIG(MSG_FMT_NLSTRNL), file);
10301618Srie 
10311618Srie 		switch (elf_kind(elf)) {
10321618Srie 		case ELF_K_AR:
1033*5411Sab196087 			ret = archive(file, fd, elf, flags, wname, wfd);
10341618Srie 			break;
10351618Srie 		case ELF_K_ELF:
1036*5411Sab196087 			ret = decide(file, fd, elf, flags, wname, wfd);
10371618Srie 			break;
10381618Srie 		default:
10391618Srie 			(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADFILE), file);
10401618Srie 			break;
10411618Srie 		}
10421618Srie 
10431618Srie 		(void) close(fd);
10441618Srie 		(void) elf_end(elf);
10451618Srie 	}
10461618Srie 
10471618Srie 	if (wfd)
10481618Srie 		(void) close(wfd);
1049*5411Sab196087 	return (ret);
1050*5411Sab196087 
1051*5411Sab196087 usage_brief:
1052*5411Sab196087 	/* Control comes here for a simple usage message and exit */
1053*5411Sab196087 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_BRIEF),
1054*5411Sab196087 	    basename(argv[0]));
1055*5411Sab196087 	return (1);
1056*5411Sab196087 
10571618Srie }
1058