xref: /onnv-gate/usr/src/cmd/sgs/elfdump/common/main.c (revision 9085:ff7eb0bace56)
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 /*
23*9085SAli.Bahrami@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
241618Srie  * Use is subject to license terms.
251618Srie  */
261618Srie 
271618Srie /*
281618Srie  * Dump an elf file.
291618Srie  */
301618Srie #include	<sys/param.h>
311618Srie #include	<fcntl.h>
321618Srie #include	<stdio.h>
334168Sab196087 #include	<stdlib.h>
344168Sab196087 #include	<ctype.h>
351618Srie #include	<libelf.h>
361618Srie #include	<link.h>
371618Srie #include	<stdarg.h>
381618Srie #include	<unistd.h>
391618Srie #include	<libgen.h>
401618Srie #include	<libintl.h>
411618Srie #include	<locale.h>
421618Srie #include	<errno.h>
431618Srie #include	<strings.h>
441618Srie #include	<debug.h>
451618Srie #include	<conv.h>
461618Srie #include	<msg.h>
471618Srie #include	<_elfdump.h>
485411Sab196087 #include	<sys/elf_SPARC.h>
495411Sab196087 #include	<sys/elf_amd64.h>
505411Sab196087 
511618Srie 
524063Sab196087 const Cache	cache_init = {NULL, NULL, NULL, NULL, 0};
531618Srie 
544168Sab196087 
554168Sab196087 
565411Sab196087 /*
575411Sab196087  * The -I, -N, and -T options are called "match options", because
585411Sab196087  * they allow selecting the items to be displayed based on matching
595411Sab196087  * their index, name, or type.
605411Sab196087  *
615411Sab196087  * The ELF information to which -I, -N, or -T are applied in
625411Sab196087  * the current invocation is called the "match item".
635411Sab196087  */
644168Sab196087 typedef enum {
655411Sab196087 	MATCH_ITEM_PT,		/* Program header (PT_) */
665411Sab196087 	MATCH_ITEM_SHT		/* Section header (SHT_) */
675411Sab196087 } match_item_t;
685411Sab196087 
695411Sab196087 /* match_opt_t is  used to note which match option was used */
705411Sab196087 typedef enum {
715411Sab196087 	MATCH_OPT_NAME,		/* Record contains a name */
725411Sab196087 	MATCH_OPT_NDX,		/* Record contains a single index */
735411Sab196087 	MATCH_OPT_RANGE,	/* Record contains an index range */
745411Sab196087 	MATCH_OPT_TYPE,		/* Record contains a type (shdr or phdr) */
755411Sab196087 } match_opt_t;
764168Sab196087 
774168Sab196087 typedef struct _match {
784168Sab196087 	struct _match	*next;		/* Pointer to next item in list */
795411Sab196087 	match_opt_t	opt_type;
804168Sab196087 	union {
815411Sab196087 		const char	*name;	/* MATCH_OPT_NAME */
825411Sab196087 		struct {		/* MATCH_OPT_NDX and MATCH_OPT_RANGE */
834168Sab196087 			int	start;
845411Sab196087 			int	end;	/* Only for MATCH_OPT_RANGE */
854168Sab196087 		} ndx;
865411Sab196087 		uint32_t	type;	/* MATCH_OPT_TYPE */
874168Sab196087 	} value;
885411Sab196087 } match_rec_t;
895411Sab196087 
905411Sab196087 static struct {
915411Sab196087 	match_item_t	item_type;	/* Type of item being matched */
925411Sab196087 	match_rec_t	*list;		/* Records for (-I, -N, -T) options */
935411Sab196087 } match_state;
945411Sab196087 
955411Sab196087 
965411Sab196087 
975411Sab196087 /* Map names to their integer value */
985411Sab196087 typedef struct {
995411Sab196087 	const char	*sym_name;
1005411Sab196087 	uint32_t	sym_value;
1015411Sab196087 } atoui_sym_t;
1025411Sab196087 
1035411Sab196087 /*
1045411Sab196087  * ELF section types.
1055411Sab196087  */
1065411Sab196087 static atoui_sym_t sym_sht[] = {
1075411Sab196087 	{ MSG_ORIG(MSG_SHT_NULL),		SHT_NULL },
1085411Sab196087 	{ MSG_ORIG(MSG_SHT_NULL_ALT1),		SHT_NULL },
1095411Sab196087 
1105411Sab196087 	{ MSG_ORIG(MSG_SHT_PROGBITS),		SHT_PROGBITS },
1115411Sab196087 	{ MSG_ORIG(MSG_SHT_PROGBITS_ALT1),	SHT_PROGBITS },
1125411Sab196087 
1135411Sab196087 	{ MSG_ORIG(MSG_SHT_SYMTAB),		SHT_SYMTAB },
1145411Sab196087 	{ MSG_ORIG(MSG_SHT_SYMTAB_ALT1),	SHT_SYMTAB },
1155411Sab196087 
1165411Sab196087 	{ MSG_ORIG(MSG_SHT_STRTAB),		SHT_STRTAB },
1175411Sab196087 	{ MSG_ORIG(MSG_SHT_STRTAB_ALT1),	SHT_STRTAB },
1185411Sab196087 
1195411Sab196087 	{ MSG_ORIG(MSG_SHT_RELA),		SHT_RELA },
1205411Sab196087 	{ MSG_ORIG(MSG_SHT_RELA_ALT1),		SHT_RELA },
1215411Sab196087 
1225411Sab196087 	{ MSG_ORIG(MSG_SHT_HASH),		SHT_HASH },
1235411Sab196087 	{ MSG_ORIG(MSG_SHT_HASH_ALT1),		SHT_HASH },
1245411Sab196087 
1255411Sab196087 	{ MSG_ORIG(MSG_SHT_DYNAMIC),		SHT_DYNAMIC },
1265411Sab196087 	{ MSG_ORIG(MSG_SHT_DYNAMIC_ALT1),	SHT_DYNAMIC },
1275411Sab196087 
1285411Sab196087 	{ MSG_ORIG(MSG_SHT_NOTE),		SHT_NOTE },
1295411Sab196087 	{ MSG_ORIG(MSG_SHT_NOTE_ALT1),		SHT_NOTE },
1305411Sab196087 
1315411Sab196087 	{ MSG_ORIG(MSG_SHT_NOBITS),		SHT_NOBITS },
1325411Sab196087 	{ MSG_ORIG(MSG_SHT_NOBITS_ALT1),	SHT_NOBITS },
1335411Sab196087 
1345411Sab196087 	{ MSG_ORIG(MSG_SHT_REL),		SHT_REL },
1355411Sab196087 	{ MSG_ORIG(MSG_SHT_REL_ALT1),		SHT_REL },
1365411Sab196087 
1375411Sab196087 	{ MSG_ORIG(MSG_SHT_SHLIB),		SHT_SHLIB },
1385411Sab196087 	{ MSG_ORIG(MSG_SHT_SHLIB_ALT1),		SHT_SHLIB },
1395411Sab196087 
1405411Sab196087 	{ MSG_ORIG(MSG_SHT_DYNSYM),		SHT_DYNSYM },
1415411Sab196087 	{ MSG_ORIG(MSG_SHT_DYNSYM_ALT1),	SHT_DYNSYM },
1425411Sab196087 
1435411Sab196087 	{ MSG_ORIG(MSG_SHT_INIT_ARRAY),		SHT_INIT_ARRAY },
1445411Sab196087 	{ MSG_ORIG(MSG_SHT_INIT_ARRAY_ALT1),	SHT_INIT_ARRAY },
1455411Sab196087 
1465411Sab196087 	{ MSG_ORIG(MSG_SHT_FINI_ARRAY),		SHT_FINI_ARRAY },
1475411Sab196087 	{ MSG_ORIG(MSG_SHT_FINI_ARRAY_ALT1),	SHT_FINI_ARRAY },
1485411Sab196087 
1495411Sab196087 	{ MSG_ORIG(MSG_SHT_PREINIT_ARRAY),	SHT_PREINIT_ARRAY },
1505411Sab196087 	{ MSG_ORIG(MSG_SHT_PREINIT_ARRAY_ALT1),	SHT_PREINIT_ARRAY },
1515411Sab196087 
1525411Sab196087 	{ MSG_ORIG(MSG_SHT_GROUP),		SHT_GROUP },
1535411Sab196087 	{ MSG_ORIG(MSG_SHT_GROUP_ALT1),		SHT_GROUP },
1545411Sab196087 
1555411Sab196087 	{ MSG_ORIG(MSG_SHT_SYMTAB_SHNDX),	SHT_SYMTAB_SHNDX },
1565411Sab196087 	{ MSG_ORIG(MSG_SHT_SYMTAB_SHNDX_ALT1),	SHT_SYMTAB_SHNDX },
1575411Sab196087 
1585411Sab196087 	{ MSG_ORIG(MSG_SHT_SUNW_SYMSORT),	SHT_SUNW_symsort },
1595411Sab196087 	{ MSG_ORIG(MSG_SHT_SUNW_SYMSORT_ALT1),	SHT_SUNW_symsort },
1605411Sab196087 
1615411Sab196087 	{ MSG_ORIG(MSG_SHT_SUNW_TLSSORT),	SHT_SUNW_tlssort },
1625411Sab196087 	{ MSG_ORIG(MSG_SHT_SUNW_TLSSORT_ALT1),	SHT_SUNW_tlssort },
1635411Sab196087 
1645411Sab196087 	{ MSG_ORIG(MSG_SHT_SUNW_LDYNSYM),	SHT_SUNW_LDYNSYM },
1655411Sab196087 	{ MSG_ORIG(MSG_SHT_SUNW_LDYNSYM_ALT1),	SHT_SUNW_LDYNSYM },
1665411Sab196087 
1675411Sab196087 	{ MSG_ORIG(MSG_SHT_SUNW_DOF),		SHT_SUNW_dof },
1685411Sab196087 	{ MSG_ORIG(MSG_SHT_SUNW_DOF_ALT1),	SHT_SUNW_dof },
1695411Sab196087 
1705411Sab196087 	{ MSG_ORIG(MSG_SHT_SUNW_CAP),		SHT_SUNW_cap },
1715411Sab196087 	{ MSG_ORIG(MSG_SHT_SUNW_CAP_ALT1),	SHT_SUNW_cap },
1725411Sab196087 
1735411Sab196087 	{ MSG_ORIG(MSG_SHT_SUNW_SIGNATURE),	SHT_SUNW_SIGNATURE },
1745411Sab196087 	{ MSG_ORIG(MSG_SHT_SUNW_SIGNATURE_ALT1), SHT_SUNW_SIGNATURE },
1755411Sab196087 
1765411Sab196087 	{ MSG_ORIG(MSG_SHT_SUNW_ANNOTATE),	SHT_SUNW_ANNOTATE },
1775411Sab196087 	{ MSG_ORIG(MSG_SHT_SUNW_ANNOTATE_ALT1),	SHT_SUNW_ANNOTATE },
1784168Sab196087 
1795411Sab196087 	{ MSG_ORIG(MSG_SHT_SUNW_DEBUGSTR),	SHT_SUNW_DEBUGSTR },
1805411Sab196087 	{ MSG_ORIG(MSG_SHT_SUNW_DEBUGSTR_ALT1),	SHT_SUNW_DEBUGSTR },
1815411Sab196087 
1825411Sab196087 	{ MSG_ORIG(MSG_SHT_SUNW_DEBUG),		SHT_SUNW_DEBUG },
1835411Sab196087 	{ MSG_ORIG(MSG_SHT_SUNW_DEBUG_ALT1),	SHT_SUNW_DEBUG },
1845411Sab196087 
1855411Sab196087 	{ MSG_ORIG(MSG_SHT_SUNW_MOVE),		SHT_SUNW_move },
1865411Sab196087 	{ MSG_ORIG(MSG_SHT_SUNW_MOVE_ALT1),	SHT_SUNW_move },
1875411Sab196087 
1885411Sab196087 	{ MSG_ORIG(MSG_SHT_SUNW_COMDAT),	SHT_SUNW_COMDAT },
1895411Sab196087 	{ MSG_ORIG(MSG_SHT_SUNW_COMDAT_ALT1),	SHT_SUNW_COMDAT },
1905411Sab196087 
1915411Sab196087 	{ MSG_ORIG(MSG_SHT_SUNW_SYMINFO),	SHT_SUNW_syminfo },
1925411Sab196087 	{ MSG_ORIG(MSG_SHT_SUNW_SYMINFO_ALT1),	SHT_SUNW_syminfo },
1935411Sab196087 
1945411Sab196087 	{ MSG_ORIG(MSG_SHT_SUNW_VERDEF),	SHT_SUNW_verdef },
1955411Sab196087 	{ MSG_ORIG(MSG_SHT_SUNW_VERDEF_ALT1),	SHT_SUNW_verdef },
1965411Sab196087 
1975411Sab196087 	{ MSG_ORIG(MSG_SHT_GNU_VERDEF),		SHT_GNU_verdef },
1985411Sab196087 	{ MSG_ORIG(MSG_SHT_GNU_VERDEF_ALT1),	SHT_GNU_verdef },
1995411Sab196087 
2005411Sab196087 	{ MSG_ORIG(MSG_SHT_SUNW_VERNEED),	SHT_SUNW_verneed },
2015411Sab196087 	{ MSG_ORIG(MSG_SHT_SUNW_VERNEED_ALT1),	SHT_SUNW_verneed },
2025411Sab196087 
2035411Sab196087 	{ MSG_ORIG(MSG_SHT_GNU_VERNEED),	SHT_GNU_verneed },
2045411Sab196087 	{ MSG_ORIG(MSG_SHT_GNU_VERNEED_ALT1),	SHT_GNU_verneed },
2055411Sab196087 
2065411Sab196087 	{ MSG_ORIG(MSG_SHT_SUNW_VERSYM),	SHT_SUNW_versym },
2075411Sab196087 	{ MSG_ORIG(MSG_SHT_SUNW_VERSYM_ALT1),	SHT_SUNW_versym },
2085411Sab196087 
2095411Sab196087 	{ MSG_ORIG(MSG_SHT_GNU_VERSYM),		SHT_GNU_versym },
2105411Sab196087 	{ MSG_ORIG(MSG_SHT_GNU_VERSYM_ALT1),	SHT_GNU_versym },
2115411Sab196087 
2125411Sab196087 	{ MSG_ORIG(MSG_SHT_SPARC_GOTDATA),	SHT_SPARC_GOTDATA },
2135411Sab196087 	{ MSG_ORIG(MSG_SHT_SPARC_GOTDATA_ALT1),	SHT_SPARC_GOTDATA },
2145411Sab196087 
2155411Sab196087 	{ MSG_ORIG(MSG_SHT_AMD64_UNWIND),	SHT_AMD64_UNWIND },
2165411Sab196087 	{ MSG_ORIG(MSG_SHT_AMD64_UNWIND_ALT1),	SHT_AMD64_UNWIND },
2175411Sab196087 
2185411Sab196087 	{ NULL }
2195411Sab196087 };
2205411Sab196087 
2215411Sab196087 /*
2225411Sab196087  * Program header PT_* type values
2235411Sab196087  */
2245411Sab196087 static atoui_sym_t sym_pt[] = {
2255411Sab196087 	{ MSG_ORIG(MSG_PT_NULL),		PT_NULL },
2265411Sab196087 	{ MSG_ORIG(MSG_PT_NULL_ALT1),		PT_NULL },
2275411Sab196087 
2285411Sab196087 	{ MSG_ORIG(MSG_PT_LOAD),		PT_LOAD },
2295411Sab196087 	{ MSG_ORIG(MSG_PT_LOAD_ALT1),		PT_LOAD },
2305411Sab196087 
2315411Sab196087 	{ MSG_ORIG(MSG_PT_DYNAMIC),		PT_DYNAMIC },
2325411Sab196087 	{ MSG_ORIG(MSG_PT_DYNAMIC_ALT1),	PT_DYNAMIC },
2335411Sab196087 
2345411Sab196087 	{ MSG_ORIG(MSG_PT_INTERP),		PT_INTERP },
2355411Sab196087 	{ MSG_ORIG(MSG_PT_INTERP_ALT1),		PT_INTERP },
2365411Sab196087 
2375411Sab196087 	{ MSG_ORIG(MSG_PT_NOTE),		PT_NOTE },
2385411Sab196087 	{ MSG_ORIG(MSG_PT_NOTE_ALT1),		PT_NOTE },
2395411Sab196087 
2405411Sab196087 	{ MSG_ORIG(MSG_PT_SHLIB),		PT_SHLIB },
2415411Sab196087 	{ MSG_ORIG(MSG_PT_SHLIB_ALT1),		PT_SHLIB },
2425411Sab196087 
2435411Sab196087 	{ MSG_ORIG(MSG_PT_PHDR),		PT_PHDR },
2445411Sab196087 	{ MSG_ORIG(MSG_PT_PHDR_ALT1),		PT_PHDR },
2455411Sab196087 
2465411Sab196087 	{ MSG_ORIG(MSG_PT_TLS),			PT_TLS },
2475411Sab196087 	{ MSG_ORIG(MSG_PT_TLS_ALT1),		PT_TLS },
2485411Sab196087 
2495411Sab196087 	{ MSG_ORIG(MSG_PT_SUNW_UNWIND),		PT_SUNW_UNWIND },
2505411Sab196087 	{ MSG_ORIG(MSG_PT_SUNW_UNWIND_ALT1),	PT_SUNW_UNWIND },
2515411Sab196087 
252*9085SAli.Bahrami@Sun.COM 	{ MSG_ORIG(MSG_PT_SUNW_EH_FRAME),	PT_SUNW_EH_FRAME },
253*9085SAli.Bahrami@Sun.COM 	{ MSG_ORIG(MSG_PT_SUNW_EH_FRAME_ALT1),	PT_SUNW_EH_FRAME },
254*9085SAli.Bahrami@Sun.COM 
2555411Sab196087 	{ MSG_ORIG(MSG_PT_SUNWBSS),		PT_SUNWBSS },
2565411Sab196087 	{ MSG_ORIG(MSG_PT_SUNWBSS_ALT1),	PT_SUNWBSS },
2575411Sab196087 
2585411Sab196087 	{ MSG_ORIG(MSG_PT_SUNWSTACK),		PT_SUNWSTACK },
2595411Sab196087 	{ MSG_ORIG(MSG_PT_SUNWSTACK_ALT1),	PT_SUNWSTACK },
2605411Sab196087 
2615411Sab196087 	{ MSG_ORIG(MSG_PT_SUNWDTRACE),		PT_SUNWDTRACE },
2625411Sab196087 	{ MSG_ORIG(MSG_PT_SUNWDTRACE_ALT1),	PT_SUNWDTRACE },
2635411Sab196087 
2645411Sab196087 	{ MSG_ORIG(MSG_PT_SUNWCAP),		PT_SUNWCAP },
2655411Sab196087 	{ MSG_ORIG(MSG_PT_SUNWCAP_ALT1),	PT_SUNWCAP },
2665411Sab196087 
2675411Sab196087 	{ NULL }
2685411Sab196087 };
2695411Sab196087 
2705411Sab196087 
2715411Sab196087 
2725411Sab196087 
2734168Sab196087 
2741618Srie const char *
2751618Srie _elfdump_msg(Msg mid)
2761618Srie {
2771618Srie 	return (gettext(MSG_ORIG(mid)));
2781618Srie }
2791618Srie 
2801618Srie /*
2811618Srie  * Determine whether a symbol name should be demangled.
2821618Srie  */
2831618Srie const char *
2841618Srie demangle(const char *name, uint_t flags)
2851618Srie {
2865411Sab196087 	if (flags & FLG_CTL_DEMANGLE)
2871618Srie 		return (Elf_demangle_name(name));
2881618Srie 	else
2891618Srie 		return ((char *)name);
2901618Srie }
2911618Srie 
2921618Srie /*
2931618Srie  * Define our own standard error routine.
2941618Srie  */
2951618Srie void
2961618Srie failure(const char *file, const char *func)
2971618Srie {
2981618Srie 	(void) fprintf(stderr, MSG_INTL(MSG_ERR_FAILURE),
2991618Srie 	    file, func, elf_errmsg(elf_errno()));
3001618Srie }
3011618Srie 
3021618Srie /*
3031618Srie  * The full usage message
3041618Srie  */
3051618Srie static void
3061618Srie detail_usage()
3071618Srie {
3081618Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL1));
3091618Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL2));
3101618Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL3));
3111618Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL4));
3121618Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL5));
3131618Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL6));
3141618Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL7));
3151618Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL8));
3161618Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL9));
3171618Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL10));
3181618Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL11));
3191618Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL12));
3201618Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL13));
3211618Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL14));
3221618Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL15));
3231618Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL16));
3241618Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL17));
3251618Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL18));
3261618Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL19));
3271618Srie 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL20));
3283492Sab196087 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL21));
3294168Sab196087 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL22));
3304168Sab196087 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL23));
3314665Sab196087 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL24));
3325411Sab196087 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL25));
3334168Sab196087 }
3344168Sab196087 
3354168Sab196087 /*
3366635Sab196087  * Output a block of raw data as hex bytes. Each row is given
3376635Sab196087  * the index of the first byte in the row.
3386635Sab196087  *
3396635Sab196087  * entry:
3406635Sab196087  *	data - Pointer to first byte of data to be displayed
3416635Sab196087  *	n - # of bytes of data
3426635Sab196087  *	prefix - String to be output before each line. Useful
3436635Sab196087  *		for indenting output.
3446635Sab196087  *	bytes_per_col - # of space separated bytes to output
3456635Sab196087  *		in each column.
3466635Sab196087  *	col_per_row - # of columns to output per row
3476635Sab196087  *
3486635Sab196087  * exit:
3496635Sab196087  *	The formatted data has been sent to stdout. Each row of output
3506635Sab196087  *	shows (bytes_per_col * col_per_row) bytes of data.
3516635Sab196087  */
3526635Sab196087 void
353*9085SAli.Bahrami@Sun.COM dump_hex_bytes(const void *data, size_t n, int indent,
3546635Sab196087 	int bytes_per_col, int col_per_row)
3556635Sab196087 {
356*9085SAli.Bahrami@Sun.COM 	const uchar_t *ldata = data;
3576635Sab196087 	int	bytes_per_row = bytes_per_col * col_per_row;
3586635Sab196087 	int	ndx, byte, word;
3596635Sab196087 	char	string[128], *str = string;
3606635Sab196087 	char	index[MAXNDXSIZE];
3616635Sab196087 	int	index_width;
3626635Sab196087 	int	sp_prefix = 0;
3636635Sab196087 
3646635Sab196087 
3656635Sab196087 	/*
3666635Sab196087 	 * Determine the width to use for the index string. We follow
3676635Sab196087 	 * 8-byte tab rules, but don't use an actual \t character so
3686635Sab196087 	 * that the output can be arbitrarily shifted without odd
3696635Sab196087 	 * tab effects, and so that all the columns line up no matter
3706635Sab196087 	 * how many lines of output are produced.
3716635Sab196087 	 */
3726635Sab196087 	ndx = n / bytes_per_row;
3736635Sab196087 	(void) snprintf(index, sizeof (index),
3746635Sab196087 	    MSG_ORIG(MSG_FMT_INDEX2), EC_WORD(ndx));
3756635Sab196087 	index_width = strlen(index);
3766635Sab196087 	index_width = S_ROUND(index_width, 8);
3776635Sab196087 
378*9085SAli.Bahrami@Sun.COM 	for (ndx = byte = word = 0; n > 0; n--, ldata++) {
3796635Sab196087 		while (sp_prefix-- > 0)
3806635Sab196087 			*str++ = ' ';
3816635Sab196087 
3826635Sab196087 		(void) snprintf(str, sizeof (string),
383*9085SAli.Bahrami@Sun.COM 		    MSG_ORIG(MSG_HEXDUMP_TOK), (int)*ldata);
3846635Sab196087 		str += 2;
3856635Sab196087 		sp_prefix = 1;
3866635Sab196087 
3876635Sab196087 		if (++byte == bytes_per_col) {
3886635Sab196087 			sp_prefix += 2;
3896635Sab196087 			word++;
3906635Sab196087 			byte = 0;
3916635Sab196087 		}
3926635Sab196087 		if (word == col_per_row) {
3936635Sab196087 			*str = '\0';
3946635Sab196087 			(void) snprintf(index, sizeof (index),
3956635Sab196087 			    MSG_ORIG(MSG_FMT_INDEX2), EC_WORD(ndx));
3966635Sab196087 			dbg_print(0, MSG_ORIG(MSG_HEXDUMP_ROW),
3976635Sab196087 			    indent, MSG_ORIG(MSG_STR_EMPTY),
3986635Sab196087 			    index_width, index, string);
3996635Sab196087 			sp_prefix = 0;
4006635Sab196087 			word = 0;
4016635Sab196087 			ndx += bytes_per_row;
4026635Sab196087 			str = string;
4036635Sab196087 		}
4046635Sab196087 	}
4056635Sab196087 	if (byte || word) {
4066635Sab196087 		*str = '\0';	/*  */
4076635Sab196087 		(void) snprintf(index, sizeof (index),
4086635Sab196087 		    MSG_ORIG(MSG_FMT_INDEX2), EC_WORD(ndx));
4096635Sab196087 		dbg_print(0, MSG_ORIG(MSG_HEXDUMP_ROW), indent,
4106635Sab196087 		    MSG_ORIG(MSG_STR_EMPTY), index_width, index, string);
4116635Sab196087 	}
4126635Sab196087 }
4136635Sab196087 
4146635Sab196087 /*
4154168Sab196087  * Convert the ASCII representation of an index, or index range, into
4164168Sab196087  * binary form, and store it in rec:
4174168Sab196087  *
4184168Sab196087  *	index: An positive or 0 valued integer
4194168Sab196087  *	range: Two indexes, separated by a ':' character, denoting
4204168Sab196087  *		a range of allowed values. If the second value is omitted,
4214168Sab196087  *		any values equal to or greater than the first will match.
4224168Sab196087  *
4234168Sab196087  * exit:
4245411Sab196087  *	On success, *rec is filled in with a MATCH_OPT_NDX or MATCH_OPT_RANGE
4254168Sab196087  *	value, and this function returns (1). On failure, the contents
4264168Sab196087  *	of *rec are undefined, and (0) is returned.
4274168Sab196087  */
4284168Sab196087 int
4295411Sab196087 process_index_opt(const char *str, match_rec_t *rec)
4304168Sab196087 {
4314168Sab196087 #define	SKIP_BLANK for (; *str && isspace(*str); str++)
4324168Sab196087 
4334168Sab196087 	char	*endptr;
4344168Sab196087 
4354168Sab196087 	rec->value.ndx.start = strtol(str, &endptr, 10);
4364168Sab196087 	/* Value must use some of the input, and be 0 or positive */
4374168Sab196087 	if ((str == endptr) || (rec->value.ndx.start < 0))
4384168Sab196087 		return (0);
4394168Sab196087 	str = endptr;
4404168Sab196087 
4414168Sab196087 	SKIP_BLANK;
4424168Sab196087 	if (*str != ':') {
4435411Sab196087 		rec->opt_type = MATCH_OPT_NDX;
4444168Sab196087 	} else {
4454168Sab196087 		str++;					/* Skip the ':' */
4465411Sab196087 		rec->opt_type = MATCH_OPT_RANGE;
4474168Sab196087 		SKIP_BLANK;
4484168Sab196087 		if (*str == '\0') {
4494168Sab196087 			rec->value.ndx.end = -1;	/* Indicates "to end" */
4504168Sab196087 		} else {
4514168Sab196087 			rec->value.ndx.end = strtol(str, &endptr, 10);
4524168Sab196087 			if ((str == endptr) || (rec->value.ndx.end < 0))
4534168Sab196087 				return (0);
4544168Sab196087 			str = endptr;
4554168Sab196087 			SKIP_BLANK;
4564168Sab196087 		}
4574168Sab196087 	}
4584168Sab196087 
4594168Sab196087 	/* Syntax error if anything is left over */
4604168Sab196087 	if (*str != '\0')
4614168Sab196087 		return (0);
4624168Sab196087 
4634168Sab196087 	return (1);
4644168Sab196087 
4654168Sab196087 #undef	SKIP_BLANK
4664168Sab196087 }
4674168Sab196087 
4684168Sab196087 /*
4695411Sab196087  * Process the symbolic name to value mappings passed to the
4705411Sab196087  * atoui() function.
4715411Sab196087  *
4725411Sab196087  * entry:
4735411Sab196087  *	sym - NULL terminated array of name->value mappings.
4745411Sab196087  *	value - Address of variable to receive corresponding value.
4755411Sab196087  *
4765411Sab196087  * exit:
4775411Sab196087  *	If a mapping is found, *value is set to it, and True is returned.
4785411Sab196087  *	Otherwise False is returned.
4795411Sab196087  */
4805411Sab196087 static int
4815411Sab196087 atoui_sym_process(const char *str, const atoui_sym_t *sym, uint32_t *value)
4825411Sab196087 {
4835411Sab196087 	size_t		cmp_len;
4845411Sab196087 	const char	*tail;
4855411Sab196087 
4865411Sab196087 	while (isspace(*str))
4875411Sab196087 		str++;
4885411Sab196087 
4895411Sab196087 	tail = str + strlen(str);
4905411Sab196087 	while ((tail > str) && isspace(*(tail - 1)))
4915411Sab196087 		tail--;
4925411Sab196087 
4935411Sab196087 	cmp_len = tail - str;
4945411Sab196087 
4955411Sab196087 	for (; sym->sym_name != NULL; sym++) {
4965411Sab196087 		if ((strlen(sym->sym_name) == cmp_len) &&
4975411Sab196087 		    (strncasecmp(sym->sym_name, str, cmp_len) == 0)) {
4985411Sab196087 			*value = sym->sym_value;
4995411Sab196087 			return (1);
5005411Sab196087 		}
5015411Sab196087 	}
5025411Sab196087 
5035411Sab196087 	/* No symbolic mapping was found */
5045411Sab196087 	return (0);
5055411Sab196087 }
5065411Sab196087 
5075411Sab196087 
5085411Sab196087 /*
5095411Sab196087  * Convert a string to a numeric value. Strings starting with '0'
5105411Sab196087  * are taken to be octal, those staring with '0x' are hex, and all
5115411Sab196087  * others are decimal.
5125411Sab196087  *
5135411Sab196087  * entry:
5145411Sab196087  *	str - String to be converted
5155411Sab196087  *	sym - NULL, or NULL terminated array of name/value pairs.
5165411Sab196087  *	v - Address of variable to receive resulting value.
5175411Sab196087  *
5185411Sab196087  * exit:
5195411Sab196087  *	On success, returns True (1) and *v is set to the value.
5205411Sab196087  *	On failure, returns False (0) and *v is undefined.
5215411Sab196087  */
5225411Sab196087 static int
5235411Sab196087 atoui(const char *str, const atoui_sym_t *sym, uint32_t *v)
5245411Sab196087 {
5255411Sab196087 	char		*endptr;
5265411Sab196087 
5275411Sab196087 	if (sym && atoui_sym_process(str, sym, v))
5285411Sab196087 		return (1);
5295411Sab196087 
5305411Sab196087 	*v = strtoull(str, &endptr, 0);
5315411Sab196087 
5325411Sab196087 	/* If the left over part contains anything but whitespace, fail */
5335411Sab196087 	for (; *endptr; endptr++)
5345411Sab196087 		if (!isspace(*endptr))
5355411Sab196087 			return (0);
5365411Sab196087 	return (1);
5375411Sab196087 }
5385411Sab196087 
5395411Sab196087 /*
5405411Sab196087  * Called after getopt() processing is finished if there is a non-empty
5415411Sab196087  * match list. Prepares the matching code for use.
5425411Sab196087  *
5435411Sab196087  * exit:
5445411Sab196087  *	Returns True (1) if no errors are encountered. Writes an
5455411Sab196087  *	error string to stderr and returns False (0) otherwise.
5465411Sab196087  */
5475411Sab196087 static int
5485411Sab196087 match_prepare(char *argv0, uint_t flags)
5495411Sab196087 {
5505411Sab196087 	atoui_sym_t	*sym;
5515411Sab196087 	match_rec_t	*list;
5525411Sab196087 	const char	*str;
5535411Sab196087 	int		minus_p = (flags & FLG_SHOW_PHDR) != 0;
5545411Sab196087 
5555411Sab196087 	/*
5565411Sab196087 	 * Flag ambiguous attempt to use match option with both -p and
5575411Sab196087 	 * and one or more section SHOW options. In this case, we
5585411Sab196087 	 * can't tell what type of item we're supposed to match against.
5595411Sab196087 	 */
5605411Sab196087 	if (minus_p && (flags & FLG_MASK_SHOW_SHDR)) {
5615411Sab196087 		(void) fprintf(stderr, MSG_INTL(MSG_ERR_AMBIG_MATCH),
5625411Sab196087 		    basename(argv0));
5635411Sab196087 		return (0);
5645411Sab196087 	}
5655411Sab196087 
5665411Sab196087 	/* Set the match type, based on the presence of the -p option */
5675411Sab196087 	if (minus_p) {
5685411Sab196087 		match_state.item_type = MATCH_ITEM_PT;
5695411Sab196087 		sym = sym_pt;
5705411Sab196087 	} else {
5715411Sab196087 		match_state.item_type = MATCH_ITEM_SHT;
5725411Sab196087 		sym = sym_sht;
5735411Sab196087 	}
5745411Sab196087 
5755411Sab196087 	/*
5765411Sab196087 	 * Scan match list and perform any necessary fixups:
5775411Sab196087 	 *
5785411Sab196087 	 * MATCH_OPT_NAME: If -p is specified, convert MATCH_OPT_NAME (-N)
5795411Sab196087 	 *	requests into MATCH_OPT_TYPE (-T).
5805411Sab196087 	 *
5815411Sab196087 	 * MATCH_OPT_TYPE: Now that we know item type we are matching
5825411Sab196087 	 *	against, we can convert the string saved in the name
5835411Sab196087 	 *	field during getopt() processing into an integer and
5845411Sab196087 	 *	write it into the type field.
5855411Sab196087 	 */
5865411Sab196087 	for (list = match_state.list; list; list = list->next) {
5875411Sab196087 		if ((list->opt_type == MATCH_OPT_NAME) && minus_p)
5885411Sab196087 			list->opt_type = MATCH_OPT_TYPE;
5895411Sab196087 
5905411Sab196087 		if (list->opt_type != MATCH_OPT_TYPE)
5915411Sab196087 			continue;
5925411Sab196087 
5935411Sab196087 		str = list->value.name;
5945411Sab196087 		if (atoui(str, sym, &list->value.type) == 0) {
5955411Sab196087 			const char *fmt = minus_p ?
5965411Sab196087 			    MSG_INTL(MSG_ERR_BAD_T_PT) :
5975411Sab196087 			    MSG_INTL(MSG_ERR_BAD_T_SHT);
5985411Sab196087 
5995411Sab196087 			(void) fprintf(stderr, fmt, basename(argv0), str);
6005411Sab196087 			return (0);
6015411Sab196087 		}
6025411Sab196087 	}
6035411Sab196087 
6045411Sab196087 	return (1);
6055411Sab196087 }
6065411Sab196087 
6075411Sab196087 
6085411Sab196087 /*
6094168Sab196087  * Returns True (1) if the item with the given name or index should
6104168Sab196087  * be displayed, and False (0) if it should not be.
6114168Sab196087  *
6124168Sab196087  * entry:
6135411Sab196087  *	match_flags - Bitmask specifying matching options, as described
6145411Sab196087  *		in _elfdump.h.
6155411Sab196087  *	name - If MATCH_F_NAME flag is set, name of item under
6165411Sab196087  *		consideration. Otherwise ignored.
6174168Sab196087  *		should not be considered.
6185411Sab196087  *	ndx - If MATCH_F_NDX flag is set, index of item under consideration.
6195411Sab196087  *	type - If MATCH_F_TYPE is set, type of item under consideration.
6205411Sab196087  *		If MATCH_F_PHDR is set, this would be a program
6215411Sab196087  *		header type (PT_). Otherwise, a section header type (SHT_).
6224168Sab196087  *
6234168Sab196087  * exit:
6244168Sab196087  *	True will be returned if the given name/index matches those given
6255411Sab196087  *	by one of the (-I, -N -T) command line options, or if no such option
6265411Sab196087  *	was used in the command invocation and MATCH_F_STRICT is not
6275411Sab196087  *	set.
6284168Sab196087  */
6294168Sab196087 int
6305411Sab196087 match(match_flags_t match_flags, const char *name, uint_t ndx, uint_t type)
6314168Sab196087 {
6325411Sab196087 	match_item_t item_type = (match_flags & MATCH_F_PHDR) ?
6335411Sab196087 	    MATCH_ITEM_PT  : MATCH_ITEM_SHT;
6345411Sab196087 	match_rec_t *list;
6354168Sab196087 
6365411Sab196087 	/*
6375411Sab196087 	 * If there is no match list, then we use the MATCH_F_STRICT
6385411Sab196087 	 * flag to decide what to return. In the strict case, we return
6395411Sab196087 	 * False (0), in the normal case, True (1).
6405411Sab196087 	 */
6415411Sab196087 	if (match_state.list == NULL)
6425411Sab196087 		return ((match_flags & MATCH_F_STRICT) == 0);
6435411Sab196087 
6445411Sab196087 	/*
6455411Sab196087 	 * If item being checked is not the current match type,
6465411Sab196087 	 * then allow it.
6475411Sab196087 	 */
6485411Sab196087 	if (item_type != match_state.item_type)
6494168Sab196087 		return (1);
6504168Sab196087 
6514168Sab196087 	/* Run through the match records and check for a hit */
6525411Sab196087 	for (list = match_state.list; list; list = list->next) {
6535411Sab196087 		switch (list->opt_type) {
6545411Sab196087 		case MATCH_OPT_NAME:
6555411Sab196087 			if (((match_flags & MATCH_F_NAME) == 0) ||
6565411Sab196087 			    (name == NULL))
6575411Sab196087 				break;
6585411Sab196087 			if (strcmp(list->value.name, name) == 0)
6594168Sab196087 				return (1);
6604168Sab196087 			break;
6615411Sab196087 		case MATCH_OPT_NDX:
6625411Sab196087 			if ((match_flags & MATCH_F_NDX) &&
6635411Sab196087 			    (ndx == list->value.ndx.start))
6644168Sab196087 				return (1);
6654168Sab196087 			break;
6665411Sab196087 		case MATCH_OPT_RANGE:
6674168Sab196087 			/*
6684168Sab196087 			 * A range end value less than 0 means that any value
6694168Sab196087 			 * above the start is acceptible.
6704168Sab196087 			 */
6715411Sab196087 			if ((match_flags & MATCH_F_NDX) &&
6725411Sab196087 			    (ndx >= list->value.ndx.start) &&
6734168Sab196087 			    ((list->value.ndx.end < 0) ||
6744168Sab196087 			    (ndx <= list->value.ndx.end)))
6754168Sab196087 				return (1);
6764168Sab196087 			break;
6775411Sab196087 
6785411Sab196087 		case MATCH_OPT_TYPE:
6795411Sab196087 			if ((match_flags & MATCH_F_TYPE) &&
6805411Sab196087 			    (type == list->value.type))
6815411Sab196087 				return (1);
6825411Sab196087 			break;
6834168Sab196087 		}
6844168Sab196087 	}
6854168Sab196087 
6864168Sab196087 	/* Nothing matched */
6874168Sab196087 	return (0);
6884168Sab196087 }
6894168Sab196087 
6904168Sab196087 /*
6915411Sab196087  * Add an entry to match_state.list for use by match(). This routine is for
6925411Sab196087  * use during getopt() processing. It should not be called once
6935411Sab196087  * match_prepare() has been called.
6944168Sab196087  *
6954168Sab196087  * Return True (1) for success. On failure, an error is written
6964168Sab196087  * to stderr, and False (0) is returned.
6974168Sab196087  */
6984168Sab196087 static int
6995411Sab196087 add_match_record(char *argv0, match_rec_t *data)
7004168Sab196087 {
7015411Sab196087 	match_rec_t	*rec;
7025411Sab196087 	match_rec_t	*list;
7034168Sab196087 
7044168Sab196087 	if ((rec = malloc(sizeof (*rec))) == NULL) {
7054168Sab196087 		int err = errno;
7064168Sab196087 		(void) fprintf(stderr, MSG_INTL(MSG_ERR_MALLOC),
7074168Sab196087 		    basename(argv0), strerror(err));
7084168Sab196087 		return (0);
7094168Sab196087 	}
7104168Sab196087 
7114168Sab196087 	*rec = *data;
7124168Sab196087 
7135411Sab196087 	/* Insert at end of match_state.list */
7145411Sab196087 	if (match_state.list == NULL) {
7155411Sab196087 		match_state.list = rec;
7164168Sab196087 	} else {
7175411Sab196087 		for (list = match_state.list; list->next != NULL;
7185411Sab196087 		    list = list->next)
7194168Sab196087 			;
7204168Sab196087 		list->next = rec;
7214168Sab196087 	}
7224168Sab196087 
7234168Sab196087 	rec->next = NULL;
7244168Sab196087 	return (1);
7251618Srie }
7261618Srie 
7275411Sab196087 static int
7285411Sab196087 decide(const char *file, int fd, Elf *elf, uint_t flags,
7295411Sab196087     const char *wname, int wfd)
7301618Srie {
7315411Sab196087 	int r;
7325411Sab196087 
7331618Srie 	if (gelf_getclass(elf) == ELFCLASS64)
7345411Sab196087 		r = regular64(file, fd, elf, flags, wname, wfd);
7351618Srie 	else
7365411Sab196087 		r = regular32(file, fd, elf, flags, wname, wfd);
7375411Sab196087 
7385411Sab196087 	return (r);
7391618Srie }
7401618Srie 
7415411Sab196087 static int
7425411Sab196087 archive(const char *file, int fd, Elf *elf, uint_t flags,
7435411Sab196087     const char *wname, int wfd)
7441618Srie {
7451618Srie 	Elf_Cmd		cmd = ELF_C_READ;
7461618Srie 	Elf_Arhdr	*arhdr;
747*9085SAli.Bahrami@Sun.COM 	Elf		*_elf = NULL;
7481618Srie 	size_t		ptr;
749*9085SAli.Bahrami@Sun.COM 	Elf_Arsym	*arsym = NULL;
7501618Srie 
7511618Srie 	/*
7523492Sab196087 	 * Determine if the archive symbol table itself is required.
7531618Srie 	 */
7545411Sab196087 	if ((flags & FLG_SHOW_SYMBOLS) &&
7555411Sab196087 	    match(MATCH_F_NAME, MSG_ORIG(MSG_ELF_ARSYM), 0, 0)) {
7561618Srie 		/*
7571618Srie 		 * Get the archive symbol table.
7581618Srie 		 */
7591618Srie 		if (((arsym = elf_getarsym(elf, &ptr)) == 0) && elf_errno()) {
7601618Srie 			/*
7611618Srie 			 * The arsym could be 0 even though there was no error.
7621618Srie 			 * Print the error message only when there was
7631618Srie 			 * real error from elf_getarsym().
7641618Srie 			 */
7651618Srie 			failure(file, MSG_ORIG(MSG_ELF_GETARSYM));
7665411Sab196087 			return (0);
7671618Srie 		}
7681618Srie 	}
7691618Srie 
7701618Srie 	/*
7711618Srie 	 * Print the archive symbol table only when the archive symbol
7721618Srie 	 * table exists and it was requested to print.
7731618Srie 	 */
7741618Srie 	if (arsym) {
7751618Srie 		size_t		cnt;
7761618Srie 		char		index[MAXNDXSIZE];
7771618Srie 		size_t		offset = 0, _offset = 0;
7781618Srie 
7791618Srie 		/*
7801618Srie 		 * Print out all the symbol entries.
7811618Srie 		 */
7821618Srie 		dbg_print(0, MSG_INTL(MSG_ARCHIVE_SYMTAB));
7831618Srie 		dbg_print(0, MSG_INTL(MSG_ARCHIVE_FIELDS));
7841618Srie 
7851618Srie 		for (cnt = 0; cnt < ptr; cnt++, arsym++) {
7861618Srie 			/*
7871618Srie 			 * For each object obtain an elf descriptor so that we
7881618Srie 			 * can establish the members name.  Note, we have had
7891618Srie 			 * archives where the archive header has not been
7901618Srie 			 * obtainable so be lenient with errors.
7911618Srie 			 */
7921618Srie 			if ((offset == 0) || ((arsym->as_off != 0) &&
7931618Srie 			    (arsym->as_off != _offset))) {
7941618Srie 
7951618Srie 				if (_elf)
7961618Srie 					(void) elf_end(_elf);
7971618Srie 
7981618Srie 				if (elf_rand(elf, arsym->as_off) !=
7991618Srie 				    arsym->as_off) {
8001618Srie 					failure(file, MSG_ORIG(MSG_ELF_RAND));
801*9085SAli.Bahrami@Sun.COM 					arhdr = NULL;
8021618Srie 				} else if ((_elf = elf_begin(fd,
8031618Srie 				    ELF_C_READ, elf)) == 0) {
8041618Srie 					failure(file, MSG_ORIG(MSG_ELF_BEGIN));
805*9085SAli.Bahrami@Sun.COM 					arhdr = NULL;
8061618Srie 				} else if ((arhdr = elf_getarhdr(_elf)) == 0) {
8071618Srie 					failure(file,
8081618Srie 					    MSG_ORIG(MSG_ELF_GETARHDR));
809*9085SAli.Bahrami@Sun.COM 					arhdr = NULL;
8101618Srie 				}
8111618Srie 
8121618Srie 				_offset = arsym->as_off;
8131618Srie 				if (offset == 0)
8141618Srie 					offset = _offset;
8151618Srie 			}
8161618Srie 
8171618Srie 			(void) snprintf(index, MAXNDXSIZE,
8181618Srie 			    MSG_ORIG(MSG_FMT_INDEX), EC_XWORD(cnt));
8191618Srie 			if (arsym->as_off)
8201618Srie 				dbg_print(0, MSG_ORIG(MSG_FMT_ARSYM1), index,
8211618Srie 				    /* LINTED */
8221618Srie 				    (int)arsym->as_off, arhdr ? arhdr->ar_name :
8231618Srie 				    MSG_INTL(MSG_STR_UNKNOWN), (arsym->as_name ?
8241618Srie 				    demangle(arsym->as_name, flags) :
8251618Srie 				    MSG_INTL(MSG_STR_NULL)));
8261618Srie 			else
8271618Srie 				dbg_print(0, MSG_ORIG(MSG_FMT_ARSYM2), index,
8281618Srie 				    /* LINTED */
8291618Srie 				    (int)arsym->as_off);
8301618Srie 		}
8311618Srie 
8321618Srie 		if (_elf)
8331618Srie 			(void) elf_end(_elf);
8341618Srie 
8351618Srie 		/*
8361618Srie 		 * If we only need the archive symbol table return.
8371618Srie 		 */
8385411Sab196087 		if ((flags & FLG_SHOW_SYMBOLS) &&
8395411Sab196087 		    match(MATCH_F_STRICT | MATCH_F_NAME,
8405411Sab196087 		    MSG_ORIG(MSG_ELF_ARSYM), -1, -1))
8415411Sab196087 			return (0);
8421618Srie 
8431618Srie 		/*
8441618Srie 		 * Reset elf descriptor in preparation for processing each
8451618Srie 		 * member.
8461618Srie 		 */
8471618Srie 		if (offset)
8481618Srie 			(void) elf_rand(elf, offset);
8491618Srie 	}
8501618Srie 
8511618Srie 	/*
8521618Srie 	 * Process each object within the archive.
8531618Srie 	 */
8541618Srie 	while ((_elf = elf_begin(fd, cmd, elf)) != NULL) {
8551618Srie 		char	name[MAXPATHLEN];
8561618Srie 
8571618Srie 		if ((arhdr = elf_getarhdr(_elf)) == NULL) {
8581618Srie 			failure(file, MSG_ORIG(MSG_ELF_GETARHDR));
8595411Sab196087 			return (0);
8601618Srie 		}
8611618Srie 		if (*arhdr->ar_name != '/') {
8621618Srie 			(void) snprintf(name, MAXPATHLEN,
8631618Srie 			    MSG_ORIG(MSG_FMT_ARNAME), file, arhdr->ar_name);
8641618Srie 			dbg_print(0, MSG_ORIG(MSG_FMT_NLSTR), name);
8651618Srie 
8661618Srie 			switch (elf_kind(_elf)) {
8671618Srie 			case ELF_K_AR:
8685411Sab196087 				if (archive(name, fd, _elf, flags,
8695411Sab196087 				    wname, wfd) == 1)
8705411Sab196087 					return (1);
8711618Srie 				break;
8721618Srie 			case ELF_K_ELF:
8735411Sab196087 				if (decide(name, fd, _elf, flags,
8745411Sab196087 				    wname, wfd) == 1)
8755411Sab196087 					return (1);
8761618Srie 				break;
8771618Srie 			default:
8781618Srie 				(void) fprintf(stderr,
8791618Srie 				    MSG_INTL(MSG_ERR_BADFILE), name);
8801618Srie 				break;
8811618Srie 			}
8821618Srie 		}
8831618Srie 
8841618Srie 		cmd = elf_next(_elf);
8851618Srie 		(void) elf_end(_elf);
8861618Srie 	}
8875411Sab196087 
8885411Sab196087 	return (0);
8891618Srie }
8901618Srie 
8911618Srie int
8921618Srie main(int argc, char **argv, char **envp)
8931618Srie {
8941618Srie 	Elf		*elf;
8951618Srie 	int		var, fd, wfd = 0;
8965411Sab196087 	char		*wname = NULL;
8971618Srie 	uint_t		flags = 0;
8985411Sab196087 	match_rec_t	match_data;
8995411Sab196087 	int		ret;
9001618Srie 
9011618Srie 	/*
9021618Srie 	 * If we're on a 64-bit kernel, try to exec a full 64-bit version of
9031618Srie 	 * the binary.  If successful, conv_check_native() won't return.
9041618Srie 	 */
9052647Srie 	(void) conv_check_native(argv, envp);
9061618Srie 
9071618Srie 	/*
9081618Srie 	 * Establish locale.
9091618Srie 	 */
9101618Srie 	(void) setlocale(LC_MESSAGES, MSG_ORIG(MSG_STR_EMPTY));
9111618Srie 	(void) textdomain(MSG_ORIG(MSG_SUNW_OST_SGS));
9121618Srie 
9131618Srie 	(void) setvbuf(stdout, NULL, _IOLBF, 0);
9141618Srie 	(void) setvbuf(stderr, NULL, _IOLBF, 0);
9151618Srie 
9161618Srie 	opterr = 0;
9171618Srie 	while ((var = getopt(argc, argv, MSG_ORIG(MSG_STR_OPTIONS))) != EOF) {
9181618Srie 		switch (var) {
9191618Srie 		case 'C':
9205411Sab196087 			flags |= FLG_CTL_DEMANGLE;
9211618Srie 			break;
9221618Srie 		case 'c':
9235411Sab196087 			flags |= FLG_SHOW_SHDR;
9241618Srie 			break;
9251618Srie 		case 'd':
9265411Sab196087 			flags |= FLG_SHOW_DYNAMIC;
9271618Srie 			break;
9281618Srie 		case 'e':
9295411Sab196087 			flags |= FLG_SHOW_EHDR;
9301618Srie 			break;
9311618Srie 		case 'G':
9325411Sab196087 			flags |= FLG_SHOW_GOT;
9331618Srie 			break;
9341618Srie 		case 'g':
9355411Sab196087 			flags |= FLG_SHOW_GROUP;
9361618Srie 			break;
9371618Srie 		case 'H':
9385411Sab196087 			flags |= FLG_SHOW_CAP;
9391618Srie 			break;
9401618Srie 		case 'h':
9415411Sab196087 			flags |= FLG_SHOW_HASH;
9421618Srie 			break;
9434168Sab196087 		case 'I':
9445411Sab196087 			if (!process_index_opt(optarg, &match_data))
9455411Sab196087 				goto usage_brief;
9464168Sab196087 			if (!add_match_record(argv[0], &match_data))
9474168Sab196087 				return (1);
9485411Sab196087 			flags |= FLG_CTL_MATCH;
9494168Sab196087 			break;
9501618Srie 		case 'i':
9515411Sab196087 			flags |= FLG_SHOW_INTERP;
9521618Srie 			break;
9531618Srie 		case 'k':
9545411Sab196087 			flags |= FLG_CALC_CHECKSUM;
9551618Srie 			break;
9561618Srie 		case 'l':
9575411Sab196087 			flags |= FLG_CTL_LONGNAME;
9581618Srie 			break;
9591618Srie 		case 'm':
9605411Sab196087 			flags |= FLG_SHOW_MOVE;
9611618Srie 			break;
9621618Srie 		case 'N':
9635411Sab196087 			match_data.opt_type = MATCH_OPT_NAME;
9644168Sab196087 			match_data.value.name = optarg;
9654168Sab196087 			if (!add_match_record(argv[0], &match_data))
9664168Sab196087 				return (1);
9675411Sab196087 			flags |= FLG_CTL_MATCH;
9681618Srie 			break;
9691618Srie 		case 'n':
9705411Sab196087 			flags |= FLG_SHOW_NOTE;
9711618Srie 			break;
9724665Sab196087 		case 'P':
9735411Sab196087 			flags |= FLG_CTL_FAKESHDR;
9744665Sab196087 			break;
9751618Srie 		case 'p':
9765411Sab196087 			flags |= FLG_SHOW_PHDR;
9771618Srie 			break;
9781618Srie 		case 'r':
9795411Sab196087 			flags |= FLG_SHOW_RELOC;
9801618Srie 			break;
9813492Sab196087 		case 'S':
9825411Sab196087 			flags |= FLG_SHOW_SORT;
9833492Sab196087 			break;
9841618Srie 		case 's':
9855411Sab196087 			flags |= FLG_SHOW_SYMBOLS;
9865411Sab196087 			break;
9875411Sab196087 		case 'T':
9885411Sab196087 			/*
9895411Sab196087 			 * We can't evaluate the value yet, because
9905411Sab196087 			 * we need to know if -p is used or not in
9915411Sab196087 			 * order to tell if we're seeing section header
9925411Sab196087 			 * or program header types. So, we save the
9935411Sab196087 			 * string in the name field, and then convert
9945411Sab196087 			 * it to a type integer in a following pass.
9955411Sab196087 			 */
9965411Sab196087 			match_data.opt_type = MATCH_OPT_TYPE;
9975411Sab196087 			match_data.value.name = optarg;
9985411Sab196087 			if (!add_match_record(argv[0], &match_data))
9995411Sab196087 				return (1);
10005411Sab196087 			flags |= FLG_CTL_MATCH;
10011618Srie 			break;
10021618Srie 		case 'u':
10035411Sab196087 			flags |= FLG_SHOW_UNWIND;
10041618Srie 			break;
10051618Srie 		case 'v':
10065411Sab196087 			flags |= FLG_SHOW_VERSIONS;
10071618Srie 			break;
10081618Srie 		case 'w':
10091618Srie 			wname = optarg;
10101618Srie 			break;
10111618Srie 		case 'y':
10125411Sab196087 			flags |= FLG_SHOW_SYMINFO;
10131618Srie 			break;
10141618Srie 		case '?':
10151618Srie 			(void) fprintf(stderr, MSG_INTL(MSG_USAGE_BRIEF),
10161618Srie 			    basename(argv[0]));
10171618Srie 			detail_usage();
10181618Srie 			return (1);
10191618Srie 		default:
10201618Srie 			break;
10211618Srie 		}
10221618Srie 	}
10231618Srie 
10245411Sab196087 	/* -p and -w are mutually exclusive. -w only works with sections */
10255411Sab196087 	if (((flags & FLG_SHOW_PHDR) != 0) && (wname != NULL))
10265411Sab196087 		goto usage_brief;
10275411Sab196087 
10285411Sab196087 	/* If a match argument is present, prepare the match state */
10295411Sab196087 	if ((match_state.list != NULL) && (match_prepare(argv[0], flags) == 0))
10305411Sab196087 		return (1);
10315411Sab196087 
10321618Srie 	/*
10335411Sab196087 	 * Decide what to do if no options specifying something to
10345411Sab196087 	 * show or do are present.
10355411Sab196087 	 *
10365411Sab196087 	 * If there is no -w and no match options, then we will set all
10375411Sab196087 	 * the show flags, causing a full display of everything in the
10385411Sab196087 	 * file that we know how to handle.
10395411Sab196087 	 *
10405411Sab196087 	 * Otherwise, if there is no match list, we generate a usage
10415411Sab196087 	 * error and quit.
10425411Sab196087 	 *
10435411Sab196087 	 * In the case where there is a match list, we go ahead and call
10445411Sab196087 	 * regular() anyway, leaving it to decide what to do. If -w is
10455411Sab196087 	 * present, regular() will use the match list to handle it.
10465411Sab196087 	 * In addition, in the absence of explicit show/calc flags, regular()
10475411Sab196087 	 * will compare the section headers to the match list and use
10485411Sab196087 	 * that to generate the FLG_ bits that will display the information
10495411Sab196087 	 * specified by the match list.
10501618Srie 	 */
10515411Sab196087 	if ((flags & ~FLG_MASK_CTL) == 0) {
10525411Sab196087 		if (!wname && (match_state.list == NULL))
10535411Sab196087 			flags |= FLG_MASK_SHOW;
10545411Sab196087 		else if (match_state.list == NULL)
10555411Sab196087 			goto usage_brief;
10561618Srie 	}
10571618Srie 
10585411Sab196087 	/* There needs to be at least 1 filename left following the options */
10595411Sab196087 	if ((var = argc - optind) == 0)
10605411Sab196087 		goto usage_brief;
10611618Srie 
10621618Srie 	/*
10631618Srie 	 * If the -l/-C option is specified, set up the liblddbg.so.
10641618Srie 	 */
10655411Sab196087 	if (flags & FLG_CTL_LONGNAME)
10661618Srie 		dbg_desc->d_extra |= DBG_E_LONG;
10675411Sab196087 	if (flags & FLG_CTL_DEMANGLE)
10681618Srie 		dbg_desc->d_extra |= DBG_E_DEMANGLE;
10691618Srie 
10701618Srie 	/*
10711618Srie 	 * If the -w option has indicated an output file open it.  It's
10721618Srie 	 * arguable whether this option has much use when multiple files are
10731618Srie 	 * being processed.
10745411Sab196087 	 *
10755411Sab196087 	 * If wname is non-NULL, we know that -p was not specified, due
10765411Sab196087 	 * to the test above.
10771618Srie 	 */
10781618Srie 	if (wname) {
10791618Srie 		if ((wfd = open(wname, (O_RDWR | O_CREAT | O_TRUNC),
10801618Srie 		    0666)) < 0) {
10811618Srie 			int err = errno;
10821618Srie 			(void) fprintf(stderr, MSG_INTL(MSG_ERR_OPEN),
10831618Srie 			    wname, strerror(err));
10845411Sab196087 			return (1);
10851618Srie 		}
10861618Srie 	}
10871618Srie 
10881618Srie 	/*
10895411Sab196087 	 * Open the input file, initialize the elf interface, and
10905411Sab196087 	 * process it.
10911618Srie 	 */
10925411Sab196087 	ret = 0;
10935411Sab196087 	for (; (optind < argc) && (ret == 0); optind++) {
10941618Srie 		const char	*file = argv[optind];
10951618Srie 
10961618Srie 		if ((fd = open(argv[optind], O_RDONLY)) == -1) {
10971618Srie 			int err = errno;
10981618Srie 			(void) fprintf(stderr, MSG_INTL(MSG_ERR_OPEN),
10991618Srie 			    file, strerror(err));
11001618Srie 			continue;
11011618Srie 		}
11021618Srie 		(void) elf_version(EV_CURRENT);
11031618Srie 		if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) {
11041618Srie 			failure(file, MSG_ORIG(MSG_ELF_BEGIN));
11051618Srie 			(void) close(fd);
11061618Srie 			continue;
11071618Srie 		}
11081618Srie 
11091618Srie 		if (var > 1)
11101618Srie 			dbg_print(0, MSG_ORIG(MSG_FMT_NLSTRNL), file);
11111618Srie 
11121618Srie 		switch (elf_kind(elf)) {
11131618Srie 		case ELF_K_AR:
11145411Sab196087 			ret = archive(file, fd, elf, flags, wname, wfd);
11151618Srie 			break;
11161618Srie 		case ELF_K_ELF:
11175411Sab196087 			ret = decide(file, fd, elf, flags, wname, wfd);
11181618Srie 			break;
11191618Srie 		default:
11201618Srie 			(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADFILE), file);
11211618Srie 			break;
11221618Srie 		}
11231618Srie 
11241618Srie 		(void) close(fd);
11251618Srie 		(void) elf_end(elf);
11261618Srie 	}
11271618Srie 
11281618Srie 	if (wfd)
11291618Srie 		(void) close(wfd);
11305411Sab196087 	return (ret);
11315411Sab196087 
11325411Sab196087 usage_brief:
11335411Sab196087 	/* Control comes here for a simple usage message and exit */
11345411Sab196087 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_BRIEF),
11355411Sab196087 	    basename(argv[0]));
11365411Sab196087 	return (1);
11375411Sab196087 
11381618Srie }
1139