xref: /onnv-gate/usr/src/cmd/sgs/elfdump/common/elfdump.c (revision 942:8cf53d6a7d2e)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
50Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
60Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
70Sstevel@tonic-gate  * with the License.
80Sstevel@tonic-gate  *
90Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
100Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
110Sstevel@tonic-gate  * See the License for the specific language governing permissions
120Sstevel@tonic-gate  * and limitations under the License.
130Sstevel@tonic-gate  *
140Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
150Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
160Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
170Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
180Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
190Sstevel@tonic-gate  *
200Sstevel@tonic-gate  * CDDL HEADER END
210Sstevel@tonic-gate  */
220Sstevel@tonic-gate /*
23*942Sahl  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
270Sstevel@tonic-gate 
280Sstevel@tonic-gate /*
290Sstevel@tonic-gate  * Dump an elf file.
300Sstevel@tonic-gate  */
310Sstevel@tonic-gate #include	<sys/param.h>
320Sstevel@tonic-gate #include	<fcntl.h>
330Sstevel@tonic-gate #include	<stdio.h>
340Sstevel@tonic-gate #include	<libelf.h>
350Sstevel@tonic-gate #include	<gelf.h>
360Sstevel@tonic-gate #include	<link.h>
370Sstevel@tonic-gate #include	<stdarg.h>
380Sstevel@tonic-gate #include	<unistd.h>
390Sstevel@tonic-gate #include	<libgen.h>
400Sstevel@tonic-gate #include	<libintl.h>
410Sstevel@tonic-gate #include	<locale.h>
420Sstevel@tonic-gate #include	<errno.h>
430Sstevel@tonic-gate #include	<strings.h>
440Sstevel@tonic-gate #include	<sys/elf_SPARC.h>
450Sstevel@tonic-gate #include	<sys/elf_386.h>
460Sstevel@tonic-gate #include	<sys/elf_amd64.h>
470Sstevel@tonic-gate #include	<debug.h>
480Sstevel@tonic-gate #include	<_debug.h>
490Sstevel@tonic-gate #include	<conv.h>
500Sstevel@tonic-gate #include	<msg.h>
510Sstevel@tonic-gate #include	<dwarf.h>
520Sstevel@tonic-gate 
530Sstevel@tonic-gate #define	FLG_DYNAMIC	0x00000001
540Sstevel@tonic-gate #define	FLG_EHDR	0x00000002
550Sstevel@tonic-gate #define	FLG_INTERP	0x00000004
560Sstevel@tonic-gate #define	FLG_SHDR	0x00000008
570Sstevel@tonic-gate #define	FLG_NOTE	0x00000010
580Sstevel@tonic-gate #define	FLG_PHDR	0x00000020
590Sstevel@tonic-gate #define	FLG_RELOC	0x00000040
600Sstevel@tonic-gate #define	FLG_SYMBOLS	0x00000080
610Sstevel@tonic-gate #define	FLG_VERSIONS	0x00000100
620Sstevel@tonic-gate #define	FLG_HASH	0x00000200
630Sstevel@tonic-gate #define	FLG_GOT		0x00000400
640Sstevel@tonic-gate #define	FLG_SYMINFO	0x00000800
650Sstevel@tonic-gate #define	FLG_MOVE	0x00001000
660Sstevel@tonic-gate #define	FLG_GROUP	0x00002000
670Sstevel@tonic-gate #define	FLG_CAP		0x00004000
680Sstevel@tonic-gate #define	FLG_UNWIND	0x00008000
690Sstevel@tonic-gate #define	FLG_LONGNAME	0x00100000	/* not done by default */
700Sstevel@tonic-gate #define	FLG_CHECKSUM	0x00200000	/* not done by default */
710Sstevel@tonic-gate #define	FLG_DEMANGLE	0x00400000	/* not done by default */
720Sstevel@tonic-gate 
730Sstevel@tonic-gate #define	FLG_EVERYTHING	0x000fffff
740Sstevel@tonic-gate 
750Sstevel@tonic-gate #define	IAM_SPARC(X)	\
760Sstevel@tonic-gate 	((X == EM_SPARC) || (X == EM_SPARC32PLUS) || (X == EM_SPARCV9))
770Sstevel@tonic-gate #define	IAM_INTEL(X)	\
780Sstevel@tonic-gate 	(X == EM_386)
790Sstevel@tonic-gate 
800Sstevel@tonic-gate #define	MAXNDXSIZE	10
810Sstevel@tonic-gate 
820Sstevel@tonic-gate typedef struct cache {
830Sstevel@tonic-gate 	GElf_Shdr	c_shdr;
840Sstevel@tonic-gate 	Elf_Data	*c_data;
850Sstevel@tonic-gate 	char		*c_name;
860Sstevel@tonic-gate } Cache;
870Sstevel@tonic-gate 
880Sstevel@tonic-gate typedef struct got_info {
890Sstevel@tonic-gate 	GElf_Word	g_rshtype;	/* it will never happen, but */
900Sstevel@tonic-gate 					/* support mixed relocations */
910Sstevel@tonic-gate 	GElf_Rela	g_rela;
920Sstevel@tonic-gate 	const char	*g_symname;
930Sstevel@tonic-gate } Got_info;
940Sstevel@tonic-gate 
950Sstevel@tonic-gate static const Cache	_cache_init = {{0}, NULL, NULL};
960Sstevel@tonic-gate 
970Sstevel@tonic-gate const char *
980Sstevel@tonic-gate _elfdump_msg(Msg mid)
990Sstevel@tonic-gate {
1000Sstevel@tonic-gate 	return (gettext(MSG_ORIG(mid)));
1010Sstevel@tonic-gate }
1020Sstevel@tonic-gate 
1030Sstevel@tonic-gate /*
1040Sstevel@tonic-gate  * Determine whether a symbol name should be demangled.
1050Sstevel@tonic-gate  */
1060Sstevel@tonic-gate static const char *
1070Sstevel@tonic-gate demangle(const char *name, uint32_t flags)
1080Sstevel@tonic-gate {
1090Sstevel@tonic-gate 	if (flags & FLG_DEMANGLE)
1100Sstevel@tonic-gate 		return (Gelf_sym_dem(name));
1110Sstevel@tonic-gate 	else
1120Sstevel@tonic-gate 		return ((char *)name);
1130Sstevel@tonic-gate }
1140Sstevel@tonic-gate 
1150Sstevel@tonic-gate 
1160Sstevel@tonic-gate /*
1170Sstevel@tonic-gate  * Define our own printing routine.  All Elf routines referenced call upon
1180Sstevel@tonic-gate  * this routine to carry out the actual printing.
1190Sstevel@tonic-gate  */
1200Sstevel@tonic-gate /*PRINTFLIKE1*/
1210Sstevel@tonic-gate void
1220Sstevel@tonic-gate dbg_print(const char *format, ...)
1230Sstevel@tonic-gate {
1240Sstevel@tonic-gate 	va_list		ap;
1250Sstevel@tonic-gate 
1260Sstevel@tonic-gate 	va_start(ap, format);
1270Sstevel@tonic-gate 	(void) vprintf(format, ap);
1280Sstevel@tonic-gate 	(void) printf(MSG_ORIG(MSG_STR_NL));
1290Sstevel@tonic-gate 	va_end(ap);
1300Sstevel@tonic-gate }
1310Sstevel@tonic-gate 
1320Sstevel@tonic-gate /*
1330Sstevel@tonic-gate  * Just like dbg_print - except that it does not insert
1340Sstevel@tonic-gate  * a newline at the end.  Can be used for printing tables
1350Sstevel@tonic-gate  * and such.
1360Sstevel@tonic-gate  */
1370Sstevel@tonic-gate /*PRINTFLIKE1*/
1380Sstevel@tonic-gate void
1390Sstevel@tonic-gate dbg_printf(const char *format, ...)
1400Sstevel@tonic-gate {
1410Sstevel@tonic-gate 	va_list	    ap;
1420Sstevel@tonic-gate 	va_start(ap, format);
1430Sstevel@tonic-gate 	(void) vprintf(format, ap);
1440Sstevel@tonic-gate 	va_end(ap);
1450Sstevel@tonic-gate }
1460Sstevel@tonic-gate 
1470Sstevel@tonic-gate 
1480Sstevel@tonic-gate 
1490Sstevel@tonic-gate /*
1500Sstevel@tonic-gate  * Define our own standard error routine.
1510Sstevel@tonic-gate  */
1520Sstevel@tonic-gate static void
1530Sstevel@tonic-gate failure(const char *file, const char *func)
1540Sstevel@tonic-gate {
1550Sstevel@tonic-gate 	(void) fprintf(stderr, MSG_INTL(MSG_ERR_FAILURE),
1560Sstevel@tonic-gate 	    file, func, elf_errmsg(elf_errno()));
1570Sstevel@tonic-gate 	(void) fflush(stderr);
1580Sstevel@tonic-gate }
1590Sstevel@tonic-gate 
1600Sstevel@tonic-gate 
1610Sstevel@tonic-gate /*
1620Sstevel@tonic-gate  * Focal point for verifying symbol names.
1630Sstevel@tonic-gate  */
1640Sstevel@tonic-gate static const char *
1650Sstevel@tonic-gate string(Cache *refsec, GElf_Word ndx, Cache *strsec, const char *file,
1660Sstevel@tonic-gate     ulong_t name)
1670Sstevel@tonic-gate {
1680Sstevel@tonic-gate 	static Cache	*osec = 0;
1690Sstevel@tonic-gate 	static int	nostr;
1700Sstevel@tonic-gate 
1710Sstevel@tonic-gate 	const char	*strs = (char *)strsec->c_data->d_buf;
1720Sstevel@tonic-gate 	ulong_t		strn = strsec->c_data->d_size;
1730Sstevel@tonic-gate 
1740Sstevel@tonic-gate 	/*
1750Sstevel@tonic-gate 	 * Only print a diagnoistic regarding an empty string table once per
1760Sstevel@tonic-gate 	 * input section being processed.
1770Sstevel@tonic-gate 	 */
1780Sstevel@tonic-gate 	if (osec != refsec) {
1790Sstevel@tonic-gate 		osec = refsec;
1800Sstevel@tonic-gate 		nostr = 0;
1810Sstevel@tonic-gate 	}
1820Sstevel@tonic-gate 
1830Sstevel@tonic-gate 	/*
1840Sstevel@tonic-gate 	 * Is the string table offset within range of the available strings?
1850Sstevel@tonic-gate 	 */
1860Sstevel@tonic-gate 	if (name >= strn) {
1870Sstevel@tonic-gate 		/*
1880Sstevel@tonic-gate 		 * Do we have a empty string table?
1890Sstevel@tonic-gate 		 */
1900Sstevel@tonic-gate 		if (strs == 0) {
1910Sstevel@tonic-gate 			if (nostr == 0) {
1920Sstevel@tonic-gate 				(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ),
1930Sstevel@tonic-gate 				    file, strsec->c_name);
1940Sstevel@tonic-gate 				(void) fflush(stderr);
1950Sstevel@tonic-gate 				nostr++;
1960Sstevel@tonic-gate 			}
1970Sstevel@tonic-gate 		} else {
1980Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSTOFF),
1990Sstevel@tonic-gate 			    file, refsec->c_name, ndx, strsec->c_name,
2000Sstevel@tonic-gate 			    EC_XWORD(name), EC_XWORD(strn - 1));
2010Sstevel@tonic-gate 			(void) fflush(stderr);
2020Sstevel@tonic-gate 		}
2030Sstevel@tonic-gate 
2040Sstevel@tonic-gate 		/*
2050Sstevel@tonic-gate 		 * Return the empty string so that the calling function can
2060Sstevel@tonic-gate 		 * continue it's output diagnostics.
2070Sstevel@tonic-gate 		 */
2080Sstevel@tonic-gate 		return (MSG_INTL(MSG_STR_UNKNOWN));
2090Sstevel@tonic-gate 	}
2100Sstevel@tonic-gate 	return (strs + name);
2110Sstevel@tonic-gate }
2120Sstevel@tonic-gate 
2130Sstevel@tonic-gate /*
2140Sstevel@tonic-gate  * Lookup a symbol and set Sym accordingly.
2150Sstevel@tonic-gate  *
2160Sstevel@tonic-gate  * Returns:
2170Sstevel@tonic-gate  *	1 - symbol found
2180Sstevel@tonic-gate  *	0 - symbol not found
2190Sstevel@tonic-gate  */
2200Sstevel@tonic-gate static int
2210Sstevel@tonic-gate symlookup(const char *name, Cache *cache, GElf_Word shnum, GElf_Sym *sym,
2220Sstevel@tonic-gate     Cache *symtab, const char *file)
2230Sstevel@tonic-gate {
2240Sstevel@tonic-gate 	GElf_Shdr *	shdr;
2250Sstevel@tonic-gate 	GElf_Word	symn, cnt;
2260Sstevel@tonic-gate 
2270Sstevel@tonic-gate 	if (symtab == 0)
2280Sstevel@tonic-gate 		return (0);
2290Sstevel@tonic-gate 
2300Sstevel@tonic-gate 	shdr = &symtab->c_shdr;
2310Sstevel@tonic-gate 	/*
2320Sstevel@tonic-gate 	 * Determine the symbol data and number.
2330Sstevel@tonic-gate 	 */
2340Sstevel@tonic-gate 	if ((shdr->sh_entsize == 0) || (shdr->sh_size == 0)) {
2350Sstevel@tonic-gate 		(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ),
2360Sstevel@tonic-gate 		    file, symtab->c_name);
2370Sstevel@tonic-gate 		(void) fflush(stderr);
2380Sstevel@tonic-gate 		return (0);
2390Sstevel@tonic-gate 	}
2400Sstevel@tonic-gate 	/* LINTED */
2410Sstevel@tonic-gate 	symn = (GElf_Word)(shdr->sh_size / shdr->sh_entsize);
2420Sstevel@tonic-gate 
2430Sstevel@tonic-gate 	/*
2440Sstevel@tonic-gate 	 * Get the associated string table section.
2450Sstevel@tonic-gate 	 */
2460Sstevel@tonic-gate 	if ((shdr->sh_link == 0) || (shdr->sh_link >= shnum)) {
2470Sstevel@tonic-gate 		(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHLINK),
2480Sstevel@tonic-gate 		    file, symtab->c_name, EC_XWORD(shdr->sh_link));
2490Sstevel@tonic-gate 		(void) fflush(stderr);
2500Sstevel@tonic-gate 		return (0);
2510Sstevel@tonic-gate 	}
2520Sstevel@tonic-gate 
2530Sstevel@tonic-gate 	/*
2540Sstevel@tonic-gate 	 * Loop through the symbol table to find a match.
2550Sstevel@tonic-gate 	 */
2560Sstevel@tonic-gate 	for (cnt = 0; cnt < symn; cnt++) {
2570Sstevel@tonic-gate 		GElf_Sym	tsym;
2580Sstevel@tonic-gate 		const char	*sname;
2590Sstevel@tonic-gate 
2600Sstevel@tonic-gate 		if (gelf_getsym(symtab->c_data, cnt, &tsym) == NULL) {
2610Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSYM),
2620Sstevel@tonic-gate 			    file, symtab->c_name, elf_errmsg(0));
2630Sstevel@tonic-gate 			(void) fflush(stderr);
2640Sstevel@tonic-gate 			return (0);
2650Sstevel@tonic-gate 		}
2660Sstevel@tonic-gate 
2670Sstevel@tonic-gate 		sname = string(symtab, cnt, &cache[shdr->sh_link], file,
2680Sstevel@tonic-gate 		    tsym.st_name);
2690Sstevel@tonic-gate 
2700Sstevel@tonic-gate 		if (strcmp(name, sname) == 0) {
2710Sstevel@tonic-gate 			*sym = tsym;
2720Sstevel@tonic-gate 			return (1);
2730Sstevel@tonic-gate 		}
2740Sstevel@tonic-gate 	}
2750Sstevel@tonic-gate 	return (0);
2760Sstevel@tonic-gate }
2770Sstevel@tonic-gate 
2780Sstevel@tonic-gate /*
2790Sstevel@tonic-gate  * The full usage message
2800Sstevel@tonic-gate  */
2810Sstevel@tonic-gate static void
2820Sstevel@tonic-gate detail_usage()
2830Sstevel@tonic-gate {
2840Sstevel@tonic-gate 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL1));
2850Sstevel@tonic-gate 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL2));
2860Sstevel@tonic-gate 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL3));
2870Sstevel@tonic-gate 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL4));
2880Sstevel@tonic-gate 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL5));
2890Sstevel@tonic-gate 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL6));
2900Sstevel@tonic-gate 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL7));
2910Sstevel@tonic-gate 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL8));
2920Sstevel@tonic-gate 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL9));
2930Sstevel@tonic-gate 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL9_1));
2940Sstevel@tonic-gate 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL10));
2950Sstevel@tonic-gate 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL11));
2960Sstevel@tonic-gate 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL12));
2970Sstevel@tonic-gate 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL13));
2980Sstevel@tonic-gate 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL14));
2990Sstevel@tonic-gate 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL15));
3000Sstevel@tonic-gate 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL16));
3010Sstevel@tonic-gate 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL17));
3020Sstevel@tonic-gate 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL18));
3030Sstevel@tonic-gate 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL19));
3040Sstevel@tonic-gate 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL20));
3050Sstevel@tonic-gate 	(void) fflush(stderr);
3060Sstevel@tonic-gate }
3070Sstevel@tonic-gate 
3080Sstevel@tonic-gate /*
3090Sstevel@tonic-gate  * Print section headers.
3100Sstevel@tonic-gate  */
3110Sstevel@tonic-gate static void
312*942Sahl sections(const char *file, Cache *cache, GElf_Word shnum, GElf_Word phnum,
313*942Sahl     GElf_Ehdr *ehdr, const char *name)
3140Sstevel@tonic-gate {
3150Sstevel@tonic-gate 	GElf_Word	cnt;
3160Sstevel@tonic-gate 	Cache *		_cache;
3170Sstevel@tonic-gate 
3180Sstevel@tonic-gate 	for (cnt = 1; cnt < shnum; cnt++) {
3190Sstevel@tonic-gate 		GElf_Shdr	*shdr;
3200Sstevel@tonic-gate 		const char	*sname;
3210Sstevel@tonic-gate 
3220Sstevel@tonic-gate 		_cache = &cache[cnt];
3230Sstevel@tonic-gate 		sname = _cache->c_name;
3240Sstevel@tonic-gate 		if (name && strcmp(name, sname))
3250Sstevel@tonic-gate 			continue;
3260Sstevel@tonic-gate 
3270Sstevel@tonic-gate 		/*
3280Sstevel@tonic-gate 		 * Although numerous section header entries can be zero, it's
3290Sstevel@tonic-gate 		 * usually a sign of trouble if the name or type are zero.
3300Sstevel@tonic-gate 		 */
3310Sstevel@tonic-gate 		shdr = &_cache->c_shdr;
3320Sstevel@tonic-gate 		if (shdr->sh_type == 0) {
3330Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHTYPE),
3340Sstevel@tonic-gate 			    file, sname, EC_XWORD(shdr->sh_type));
3350Sstevel@tonic-gate 			(void) fflush(stderr);
3360Sstevel@tonic-gate 		}
3370Sstevel@tonic-gate 		if (shdr->sh_name == 0) {
3380Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHNAME),
3390Sstevel@tonic-gate 			    file, sname, EC_XWORD(shdr->sh_name));
3400Sstevel@tonic-gate 			(void) fflush(stderr);
3410Sstevel@tonic-gate 
3420Sstevel@tonic-gate 			/*
3430Sstevel@tonic-gate 			 * Use the empty string, rather than the fabricated
3440Sstevel@tonic-gate 			 * name for the section output.
3450Sstevel@tonic-gate 			 */
3460Sstevel@tonic-gate 			sname = MSG_ORIG(MSG_STR_EMPTY);
3470Sstevel@tonic-gate 		}
3480Sstevel@tonic-gate 
3490Sstevel@tonic-gate 		dbg_print(MSG_ORIG(MSG_STR_EMPTY));
3500Sstevel@tonic-gate 		/* LINTED */
3510Sstevel@tonic-gate 		dbg_print(MSG_INTL(MSG_ELF_SHDR), (uint_t)cnt, sname);
3520Sstevel@tonic-gate 		Gelf_shdr_entry(ehdr->e_machine, shdr);
3530Sstevel@tonic-gate 	}
3540Sstevel@tonic-gate }
3550Sstevel@tonic-gate 
3560Sstevel@tonic-gate static void
357*942Sahl unwind(Cache *cache, GElf_Word shnum, GElf_Word phnum, GElf_Ehdr *ehdr,
358*942Sahl     const char *name, const char *file, Elf *elf)
3590Sstevel@tonic-gate {
3600Sstevel@tonic-gate 	GElf_Word	cnt;
3610Sstevel@tonic-gate 	GElf_Phdr	unwind_phdr;
3620Sstevel@tonic-gate 	/*
3630Sstevel@tonic-gate 	 * For the moment - UNWIND is only relevant for
3640Sstevel@tonic-gate 	 * a AMD64 object
3650Sstevel@tonic-gate 	 */
3660Sstevel@tonic-gate 	if (ehdr->e_machine != EM_AMD64)
3670Sstevel@tonic-gate 	    return;
3680Sstevel@tonic-gate 
3690Sstevel@tonic-gate 	unwind_phdr.p_type = PT_NULL;
3700Sstevel@tonic-gate 
371*942Sahl 	for (cnt = 0; cnt < phnum; cnt++) {
3720Sstevel@tonic-gate 		GElf_Phdr	phdr;
3730Sstevel@tonic-gate 
3740Sstevel@tonic-gate 		if (gelf_getphdr(elf, cnt, &phdr) == NULL) {
3750Sstevel@tonic-gate 			failure(file, MSG_ORIG(MSG_ELF_GETPHDR));
3760Sstevel@tonic-gate 			return;
3770Sstevel@tonic-gate 		}
3780Sstevel@tonic-gate 
3790Sstevel@tonic-gate 		if (phdr.p_type == PT_SUNW_UNWIND) {
3800Sstevel@tonic-gate 			unwind_phdr = phdr;
3810Sstevel@tonic-gate 			break;
3820Sstevel@tonic-gate 		}
3830Sstevel@tonic-gate 	}
3840Sstevel@tonic-gate 
3850Sstevel@tonic-gate 
3860Sstevel@tonic-gate 	for (cnt = 1; cnt < shnum; cnt++) {
3870Sstevel@tonic-gate 		Cache		*_cache;
3880Sstevel@tonic-gate 		GElf_Shdr	*shdr;
3890Sstevel@tonic-gate 		unsigned char	*data;
3900Sstevel@tonic-gate 		size_t		datasize;
3910Sstevel@tonic-gate 		uint64_t	off, ndx;
3920Sstevel@tonic-gate 
3930Sstevel@tonic-gate 
3940Sstevel@tonic-gate 		_cache = &cache[cnt];
3950Sstevel@tonic-gate 		shdr = &_cache->c_shdr;
3960Sstevel@tonic-gate 		/*
3970Sstevel@tonic-gate 		 * XX64 - this is a strmcp() just to find the gcc
3980Sstevel@tonic-gate 		 *	  produced sections.  Soon gcc should be
3990Sstevel@tonic-gate 		 *	  settng the section type - and we'll not need
4000Sstevel@tonic-gate 		 *	  this strcmp().
4010Sstevel@tonic-gate 		 */
4020Sstevel@tonic-gate 		if ((shdr->sh_type != SHT_AMD64_UNWIND) &&
4030Sstevel@tonic-gate 		    (strncmp(_cache->c_name, MSG_ORIG(MSG_SCN_FRM),
4040Sstevel@tonic-gate 		    MSG_SCN_FRM_SIZE) != 0) &&
4050Sstevel@tonic-gate 		    (strncmp(_cache->c_name, MSG_ORIG(MSG_SCN_FRMHDR),
4060Sstevel@tonic-gate 		    MSG_SCN_FRMHDR_SIZE) != 0))
4070Sstevel@tonic-gate 			continue;
4080Sstevel@tonic-gate 		if (name && strcmp(name, _cache->c_name))
4090Sstevel@tonic-gate 			continue;
4100Sstevel@tonic-gate 
4110Sstevel@tonic-gate 		dbg_print(MSG_ORIG(MSG_STR_EMPTY));
4120Sstevel@tonic-gate 		dbg_print(MSG_INTL(MSG_ELF_SCN_UNWIND), _cache->c_name);
4130Sstevel@tonic-gate 
4140Sstevel@tonic-gate 		data = (unsigned char *)(_cache->c_data->d_buf);
4150Sstevel@tonic-gate 		datasize = _cache->c_data->d_size;
4160Sstevel@tonic-gate 		off = 0;
4170Sstevel@tonic-gate 
4180Sstevel@tonic-gate 		/*
4190Sstevel@tonic-gate 		 * Is this a .eh_frame_hdr
4200Sstevel@tonic-gate 		 */
4210Sstevel@tonic-gate 		if (((unwind_phdr.p_type == PT_SUNW_UNWIND) &&
4220Sstevel@tonic-gate 		    (shdr->sh_addr == unwind_phdr.p_vaddr)) ||
4230Sstevel@tonic-gate 		    (strncmp(_cache->c_name, MSG_ORIG(MSG_SCN_FRMHDR),
4240Sstevel@tonic-gate 			MSG_SCN_FRMHDR_SIZE) == 0)) {
4250Sstevel@tonic-gate 			    uint_t	vers;
4260Sstevel@tonic-gate 			    uint_t	frame_ptr_enc;
4270Sstevel@tonic-gate 			    uint64_t	frame_ptr;
4280Sstevel@tonic-gate 			    uint_t	fde_cnt_enc;
4290Sstevel@tonic-gate 			    uint64_t	fde_cnt;
4300Sstevel@tonic-gate 			    uint_t	table_enc;
4310Sstevel@tonic-gate 			    uint64_t	tabndx;
4320Sstevel@tonic-gate 
4330Sstevel@tonic-gate 			    dbg_print(MSG_ORIG(MSG_UNW_FRMHDR));
4340Sstevel@tonic-gate 			    ndx = 0;
4350Sstevel@tonic-gate 
4360Sstevel@tonic-gate 			    vers = data[ndx++];
4370Sstevel@tonic-gate 			    frame_ptr_enc = data[ndx++];
4380Sstevel@tonic-gate 			    fde_cnt_enc = data[ndx++];
4390Sstevel@tonic-gate 			    table_enc = data[ndx++];
4400Sstevel@tonic-gate 
4410Sstevel@tonic-gate 			    dbg_print(MSG_ORIG(MSG_UNW_FRMVERS), vers);
4420Sstevel@tonic-gate 
4430Sstevel@tonic-gate 			    frame_ptr = dwarf_ehe_extract(data,
4440Sstevel@tonic-gate 				&ndx, frame_ptr_enc, ehdr->e_ident,
4450Sstevel@tonic-gate 				shdr->sh_addr + ndx);
4460Sstevel@tonic-gate 
4470Sstevel@tonic-gate 			    dbg_print(MSG_ORIG(MSG_UNW_FRPTRENC),
4480Sstevel@tonic-gate 				conv_dwarf_ehe_str(frame_ptr_enc),
4490Sstevel@tonic-gate 				frame_ptr);
4500Sstevel@tonic-gate 
4510Sstevel@tonic-gate 			    fde_cnt = dwarf_ehe_extract(data,
4520Sstevel@tonic-gate 				&ndx, fde_cnt_enc, ehdr->e_ident,
4530Sstevel@tonic-gate 				shdr->sh_addr + ndx);
4540Sstevel@tonic-gate 			    dbg_print(MSG_ORIG(MSG_UNW_FDCNENC),
4550Sstevel@tonic-gate 				    conv_dwarf_ehe_str(fde_cnt_enc),
4560Sstevel@tonic-gate 				    fde_cnt);
4570Sstevel@tonic-gate 			    dbg_print(MSG_ORIG(MSG_UNW_TABENC),
4580Sstevel@tonic-gate 				    conv_dwarf_ehe_str(table_enc));
4590Sstevel@tonic-gate 			    dbg_print(MSG_ORIG(MSG_UNW_BINSRTAB1));
4600Sstevel@tonic-gate 			    dbg_print(MSG_ORIG(MSG_UNW_BINSRTAB2));
4610Sstevel@tonic-gate 
4620Sstevel@tonic-gate 			    for (tabndx = 0; tabndx < fde_cnt; tabndx++) {
4630Sstevel@tonic-gate 				    uint64_t	init_loc;
4640Sstevel@tonic-gate 				    uint64_t	fde_loc;
4650Sstevel@tonic-gate 				    init_loc = dwarf_ehe_extract(data,
4660Sstevel@tonic-gate 					&ndx, table_enc, ehdr->e_ident,
4670Sstevel@tonic-gate 					shdr->sh_addr);
4680Sstevel@tonic-gate 				    fde_loc = dwarf_ehe_extract(data,
4690Sstevel@tonic-gate 					&ndx, table_enc, ehdr->e_ident,
4700Sstevel@tonic-gate 					shdr->sh_addr);
4710Sstevel@tonic-gate 				    dbg_print(MSG_ORIG(MSG_UNW_BINSRTABENT),
4720Sstevel@tonic-gate 					init_loc, fde_loc);
4730Sstevel@tonic-gate 			    }
4740Sstevel@tonic-gate 			    continue;
4750Sstevel@tonic-gate 		}
4760Sstevel@tonic-gate 
4770Sstevel@tonic-gate 		/*
4780Sstevel@tonic-gate 		 * Walk the Eh_frame's
4790Sstevel@tonic-gate 		 */
4800Sstevel@tonic-gate 		while (off < datasize) {
4810Sstevel@tonic-gate 			uint_t		cieid, cielength, cieversion,
4820Sstevel@tonic-gate 					cieretaddr;
4830Sstevel@tonic-gate 			int		cieRflag, cieLflag,
4840Sstevel@tonic-gate 					ciePflag, cieZflag;
4850Sstevel@tonic-gate 			uint_t		length,	id;
4860Sstevel@tonic-gate 			uint64_t	ciecalign, ciedalign;
4870Sstevel@tonic-gate 			char		*cieaugstr;
4880Sstevel@tonic-gate 			uint_t		cieaugndx;
4890Sstevel@tonic-gate 
4900Sstevel@tonic-gate 			ndx = 0;
4910Sstevel@tonic-gate 			/*
4920Sstevel@tonic-gate 			 * extract length in lsb format
4930Sstevel@tonic-gate 			 */
4940Sstevel@tonic-gate 			length = LSB32EXTRACT(data + off + ndx);
4950Sstevel@tonic-gate 			ndx += 4;
4960Sstevel@tonic-gate 
4970Sstevel@tonic-gate 			/*
4980Sstevel@tonic-gate 			 * extract CIE id in lsb format
4990Sstevel@tonic-gate 			 */
5000Sstevel@tonic-gate 			id = LSB32EXTRACT(data + off + ndx);
5010Sstevel@tonic-gate 			ndx += 4;
5020Sstevel@tonic-gate 
5030Sstevel@tonic-gate 			/*
5040Sstevel@tonic-gate 			 * A CIE record has a id of '0', otherwise
5050Sstevel@tonic-gate 			 * this is a FDE entry and the 'id' is the
5060Sstevel@tonic-gate 			 * CIE pointer.
5070Sstevel@tonic-gate 			 */
5080Sstevel@tonic-gate 			if (id == 0) {
5090Sstevel@tonic-gate 				uint64_t    persVal;
5100Sstevel@tonic-gate 				cielength = length;
5110Sstevel@tonic-gate 				cieid = id;
5120Sstevel@tonic-gate 
5130Sstevel@tonic-gate 				cieLflag = 0;
5140Sstevel@tonic-gate 				ciePflag = 0;
5150Sstevel@tonic-gate 				cieRflag = 0;
5160Sstevel@tonic-gate 				cieZflag = 0;
5170Sstevel@tonic-gate 
5180Sstevel@tonic-gate 				dbg_print(MSG_ORIG(MSG_UNW_CIE),
5190Sstevel@tonic-gate 				    shdr->sh_addr + off);
5200Sstevel@tonic-gate 				dbg_print(MSG_ORIG(MSG_UNW_CIELNGTH),
5210Sstevel@tonic-gate 				    cielength, cieid);
5220Sstevel@tonic-gate 				cieversion = data[off + ndx];
5230Sstevel@tonic-gate 				ndx += 1;
5240Sstevel@tonic-gate 				cieaugstr = (char *)(&data[off + ndx]);
5250Sstevel@tonic-gate 				ndx += strlen(cieaugstr) + 1;
5260Sstevel@tonic-gate 				dbg_print(MSG_ORIG(MSG_UNW_CIEVERS),
5270Sstevel@tonic-gate 					cieversion, cieaugstr);
5280Sstevel@tonic-gate 				ciecalign = uleb_extract(&data[off], &ndx);
5290Sstevel@tonic-gate 				ciedalign = sleb_extract(&data[off], &ndx);
5300Sstevel@tonic-gate 				cieretaddr = data[off + ndx];
5310Sstevel@tonic-gate 				ndx += 1;
5320Sstevel@tonic-gate 				dbg_print(MSG_ORIG(MSG_UNW_CIECALGN),
5330Sstevel@tonic-gate 				    ciecalign, ciedalign, cieretaddr);
5340Sstevel@tonic-gate 
5350Sstevel@tonic-gate 				if (cieaugstr[0])
5360Sstevel@tonic-gate 				    dbg_print(MSG_ORIG(MSG_UNW_CIEAUXVAL));
5370Sstevel@tonic-gate 				for (cieaugndx = 0; cieaugstr[cieaugndx];
5380Sstevel@tonic-gate 				    cieaugndx++) {
5390Sstevel@tonic-gate 					uint_t	val;
5400Sstevel@tonic-gate 					switch (cieaugstr[cieaugndx]) {
5410Sstevel@tonic-gate 					case 'z':
5420Sstevel@tonic-gate 					    val = uleb_extract(&data[off],
5430Sstevel@tonic-gate 						&ndx);
5440Sstevel@tonic-gate 					    dbg_print(
5450Sstevel@tonic-gate 						MSG_ORIG(MSG_UNW_CIEAUXSIZE),
5460Sstevel@tonic-gate 						val);
5470Sstevel@tonic-gate 					    cieZflag = 1;
5480Sstevel@tonic-gate 					    break;
5490Sstevel@tonic-gate 					case 'P':
5500Sstevel@tonic-gate 					    ciePflag = data[off + ndx];
5510Sstevel@tonic-gate 					    ndx += 1;
5520Sstevel@tonic-gate 
5530Sstevel@tonic-gate 					    persVal = dwarf_ehe_extract(
5540Sstevel@tonic-gate 						&data[off],
5550Sstevel@tonic-gate 						&ndx, ciePflag, ehdr->e_ident,
5560Sstevel@tonic-gate 						shdr->sh_addr + off + ndx);
5570Sstevel@tonic-gate 					    dbg_print(
5580Sstevel@tonic-gate 						MSG_ORIG(MSG_UNW_CIEAUXPERS),
5590Sstevel@tonic-gate 						ciePflag,
5600Sstevel@tonic-gate 						conv_dwarf_ehe_str(ciePflag),
5610Sstevel@tonic-gate 						EC_XWORD(persVal));
5620Sstevel@tonic-gate 					    break;
5630Sstevel@tonic-gate 					case 'R':
5640Sstevel@tonic-gate 					    val = data[off + ndx];
5650Sstevel@tonic-gate 					    ndx += 1;
5660Sstevel@tonic-gate 					    dbg_print(
5670Sstevel@tonic-gate 						MSG_ORIG(MSG_UNW_CIEAUXCENC),
5680Sstevel@tonic-gate 						val, conv_dwarf_ehe_str(val));
5690Sstevel@tonic-gate 					    cieRflag = val;
5700Sstevel@tonic-gate 					    break;
5710Sstevel@tonic-gate 					case 'L':
5720Sstevel@tonic-gate 					    val = data[off + ndx];
5730Sstevel@tonic-gate 					    ndx += 1;
5740Sstevel@tonic-gate 					    dbg_print(
5750Sstevel@tonic-gate 						MSG_ORIG(MSG_UNW_CIEAUXLSDA),
5760Sstevel@tonic-gate 						val, conv_dwarf_ehe_str(val));
5770Sstevel@tonic-gate 					    cieLflag = val;
5780Sstevel@tonic-gate 					    break;
5790Sstevel@tonic-gate 					default:
5800Sstevel@tonic-gate 					    dbg_print(
5810Sstevel@tonic-gate 						MSG_ORIG(MSG_UNW_CIEAUXUNEC),
5820Sstevel@tonic-gate 						cieaugstr[cieaugndx]);
5830Sstevel@tonic-gate 					    break;
5840Sstevel@tonic-gate 					}
5850Sstevel@tonic-gate 				}
5860Sstevel@tonic-gate 				if ((cielength + 4) > ndx) {
5870Sstevel@tonic-gate 					uint_t	    cnt;
5880Sstevel@tonic-gate 					dbg_printf(MSG_ORIG(MSG_UNW_CIECFI));
5890Sstevel@tonic-gate 					cnt = 0;
5900Sstevel@tonic-gate 					while (ndx < (cielength + 4)) {
5910Sstevel@tonic-gate 						if ((cnt++ % 8) == 0) {
5920Sstevel@tonic-gate 						    dbg_printf(
5930Sstevel@tonic-gate 						    MSG_ORIG(MSG_UNW_CIECFI1));
5940Sstevel@tonic-gate 						}
5950Sstevel@tonic-gate 						dbg_printf(
5960Sstevel@tonic-gate 						    MSG_ORIG(MSG_UNW_CIECFI2),
5970Sstevel@tonic-gate 						    data[off + ndx++]);
5980Sstevel@tonic-gate 					}
5990Sstevel@tonic-gate 					dbg_print(MSG_ORIG(MSG_STR_EMPTY));
6000Sstevel@tonic-gate 				}
6010Sstevel@tonic-gate 				off += cielength + 4;
6020Sstevel@tonic-gate 			} else {
6030Sstevel@tonic-gate 				uint_t	    fdelength = length;
6040Sstevel@tonic-gate 				int	    fdecieptr = id;
6050Sstevel@tonic-gate 				uint64_t    fdeinitloc, fdeaddrrange;
6060Sstevel@tonic-gate 
6070Sstevel@tonic-gate 				dbg_print(MSG_ORIG(MSG_UNW_FDE),
6080Sstevel@tonic-gate 				    shdr->sh_addr + off);
6090Sstevel@tonic-gate 				dbg_print(MSG_ORIG(MSG_UNW_FDELNGTH),
6100Sstevel@tonic-gate 				    fdelength, fdecieptr);
6110Sstevel@tonic-gate 				fdeinitloc = dwarf_ehe_extract(&data[off],
6120Sstevel@tonic-gate 				    &ndx, cieRflag, ehdr->e_ident,
6130Sstevel@tonic-gate 				    shdr->sh_addr + off + ndx);
6140Sstevel@tonic-gate 				fdeaddrrange = dwarf_ehe_extract(&data[off],
6150Sstevel@tonic-gate 				    &ndx, (cieRflag & ~DW_EH_PE_pcrel),
6160Sstevel@tonic-gate 				    ehdr->e_ident,
6170Sstevel@tonic-gate 				    shdr->sh_addr + off + ndx);
6180Sstevel@tonic-gate 				dbg_print(MSG_ORIG(MSG_UNW_FDEINITLOC),
6190Sstevel@tonic-gate 				    fdeinitloc, fdeaddrrange);
6200Sstevel@tonic-gate 				if (cieaugstr[0])
6210Sstevel@tonic-gate 					dbg_print(MSG_ORIG(MSG_UNW_FDEAUXVAL));
6220Sstevel@tonic-gate 				if (cieZflag) {
6230Sstevel@tonic-gate 					uint64_t    val;
6240Sstevel@tonic-gate 					val = uleb_extract(&data[off], &ndx);
6250Sstevel@tonic-gate 					dbg_print(
6260Sstevel@tonic-gate 					    MSG_ORIG(MSG_UNW_FDEAUXSIZE), val);
6270Sstevel@tonic-gate 					if (val & cieLflag) {
6280Sstevel@tonic-gate 					    fdeinitloc = dwarf_ehe_extract(
6290Sstevel@tonic-gate 						&data[off], &ndx, cieLflag,
6300Sstevel@tonic-gate 						ehdr->e_ident,
6310Sstevel@tonic-gate 						shdr->sh_addr + off + ndx);
6320Sstevel@tonic-gate 					    dbg_print(
6330Sstevel@tonic-gate 						MSG_ORIG(MSG_UNW_FDEAUXLSDA),
6340Sstevel@tonic-gate 						val);
6350Sstevel@tonic-gate 					}
6360Sstevel@tonic-gate 				}
6370Sstevel@tonic-gate 				if ((fdelength + 4) > ndx) {
6380Sstevel@tonic-gate 					uint_t	    cnt;
6390Sstevel@tonic-gate 					dbg_printf(MSG_ORIG(MSG_UNW_FDECFI));
6400Sstevel@tonic-gate 					cnt = 0;
6410Sstevel@tonic-gate 					while (ndx < (fdelength + 4)) {
6420Sstevel@tonic-gate 						if ((cnt++ % 8) == 0) {
6430Sstevel@tonic-gate 						    dbg_printf(
6440Sstevel@tonic-gate 						    MSG_ORIG(MSG_UNW_FDECFI1));
6450Sstevel@tonic-gate 						}
6460Sstevel@tonic-gate 						dbg_printf(
6470Sstevel@tonic-gate 						MSG_ORIG(MSG_UNW_FDECFI2),
6480Sstevel@tonic-gate 						data[off + ndx++]);
6490Sstevel@tonic-gate 					}
6500Sstevel@tonic-gate 					dbg_print(MSG_ORIG(MSG_STR_EMPTY));
6510Sstevel@tonic-gate 				}
6520Sstevel@tonic-gate 
6530Sstevel@tonic-gate 				off += fdelength + 4;
6540Sstevel@tonic-gate 			}
6550Sstevel@tonic-gate 		}
6560Sstevel@tonic-gate 	}
6570Sstevel@tonic-gate }
6580Sstevel@tonic-gate 
6590Sstevel@tonic-gate /*
6600Sstevel@tonic-gate  * Print the hardware/software capabilities.  For executables and shared objects
6610Sstevel@tonic-gate  * this should be accompanied with a program header.
6620Sstevel@tonic-gate  */
6630Sstevel@tonic-gate static void
664*942Sahl cap(const char *file, Cache *cache, GElf_Word shnum, GElf_Word phnum,
665*942Sahl     GElf_Ehdr *ehdr, Elf *elf)
6660Sstevel@tonic-gate {
6670Sstevel@tonic-gate 	GElf_Word	cnt;
6680Sstevel@tonic-gate 	GElf_Shdr *	cshdr = 0;
6690Sstevel@tonic-gate 	Cache *		ccache;
6700Sstevel@tonic-gate 	Elf64_Off	cphdr_off = 0;
6710Sstevel@tonic-gate 	Elf64_Xword	cphdr_sz;
6720Sstevel@tonic-gate 
6730Sstevel@tonic-gate 	/*
6740Sstevel@tonic-gate 	 * Determine if a hardware/software capabilities header exists.
6750Sstevel@tonic-gate 	 */
676*942Sahl 	for (cnt = 0; cnt < phnum; cnt++) {
6770Sstevel@tonic-gate 		GElf_Phdr	phdr;
6780Sstevel@tonic-gate 
6790Sstevel@tonic-gate 		if (gelf_getphdr(elf, cnt, &phdr) == NULL) {
6800Sstevel@tonic-gate 			failure(file, MSG_ORIG(MSG_ELF_GETPHDR));
6810Sstevel@tonic-gate 			return;
6820Sstevel@tonic-gate 		}
6830Sstevel@tonic-gate 
6840Sstevel@tonic-gate 		if (phdr.p_type == PT_SUNWCAP) {
6850Sstevel@tonic-gate 			cphdr_off = phdr.p_offset;
6860Sstevel@tonic-gate 			cphdr_sz = phdr.p_filesz;
6870Sstevel@tonic-gate 			break;
6880Sstevel@tonic-gate 		}
6890Sstevel@tonic-gate 	}
6900Sstevel@tonic-gate 
6910Sstevel@tonic-gate 	/*
6920Sstevel@tonic-gate 	 * Determine if a hardware/software capabilities section exists.
6930Sstevel@tonic-gate 	 */
6940Sstevel@tonic-gate 	for (cnt = 1; cnt < shnum; cnt++) {
6950Sstevel@tonic-gate 		Cache *		_cache;
6960Sstevel@tonic-gate 		GElf_Shdr	*shdr;
6970Sstevel@tonic-gate 
6980Sstevel@tonic-gate 		_cache = &cache[cnt];
6990Sstevel@tonic-gate 		shdr = &_cache->c_shdr;
7000Sstevel@tonic-gate 
7010Sstevel@tonic-gate 		if (shdr->sh_type != SHT_SUNW_cap)
7020Sstevel@tonic-gate 			continue;
7030Sstevel@tonic-gate 
7040Sstevel@tonic-gate 		if (cphdr_off && ((cphdr_off < shdr->sh_offset) ||
7050Sstevel@tonic-gate 		    (cphdr_off + cphdr_sz) > (shdr->sh_offset + shdr->sh_size)))
7060Sstevel@tonic-gate 			continue;
7070Sstevel@tonic-gate 
7080Sstevel@tonic-gate 		ccache = _cache;
7090Sstevel@tonic-gate 		cshdr = shdr;
7100Sstevel@tonic-gate 		break;
7110Sstevel@tonic-gate 	}
7120Sstevel@tonic-gate 
7130Sstevel@tonic-gate 	if ((cshdr == 0) && (cphdr_off == 0))
7140Sstevel@tonic-gate 		return;
7150Sstevel@tonic-gate 
7160Sstevel@tonic-gate 	/*
7170Sstevel@tonic-gate 	 * Print the hardware/software capabilities section.
7180Sstevel@tonic-gate 	 */
7190Sstevel@tonic-gate 	if (cshdr) {
7200Sstevel@tonic-gate 		GElf_Word	ndx, capn;
7210Sstevel@tonic-gate 
7220Sstevel@tonic-gate 		dbg_print(MSG_ORIG(MSG_STR_EMPTY));
7230Sstevel@tonic-gate 		dbg_print(MSG_INTL(MSG_ELF_SCN_CAP), ccache->c_name);
7240Sstevel@tonic-gate 
7250Sstevel@tonic-gate 		Gelf_cap_title();
7260Sstevel@tonic-gate 
7270Sstevel@tonic-gate 		/* LINTED */
7280Sstevel@tonic-gate 		capn = (GElf_Word)(cshdr->sh_size / cshdr->sh_entsize);
7290Sstevel@tonic-gate 
7300Sstevel@tonic-gate 		/* LINTED */
7310Sstevel@tonic-gate 		for (ndx = 0; ndx < capn; ndx++) {
7320Sstevel@tonic-gate 			GElf_Cap	cap;
7330Sstevel@tonic-gate 
7340Sstevel@tonic-gate 			if (gelf_getcap(ccache->c_data, ndx, &cap) == NULL) {
7350Sstevel@tonic-gate 				(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADCAP),
7360Sstevel@tonic-gate 				    file, ccache->c_name, elf_errmsg(0));
7370Sstevel@tonic-gate 				(void) fflush(stderr);
7380Sstevel@tonic-gate 				return;
7390Sstevel@tonic-gate 			}
7400Sstevel@tonic-gate 			if (cap.c_tag != CA_SUNW_NULL)
7410Sstevel@tonic-gate 				Gelf_cap_print(&cap, ndx, ehdr->e_machine);
7420Sstevel@tonic-gate 		}
7430Sstevel@tonic-gate 	} else
7440Sstevel@tonic-gate 		(void) fprintf(stderr, MSG_INTL(MSG_WARN_INVCAP1), file);
7450Sstevel@tonic-gate 
7460Sstevel@tonic-gate 	/*
7470Sstevel@tonic-gate 	 * If this object is an executable or shared object, then the
7480Sstevel@tonic-gate 	 * hardware/software capabilities section should have an accompanying
7490Sstevel@tonic-gate 	 * program header.
7500Sstevel@tonic-gate 	 */
7510Sstevel@tonic-gate 	if (cshdr && ((ehdr->e_type == ET_EXEC) || (ehdr->e_type == ET_DYN))) {
7520Sstevel@tonic-gate 		if (cphdr_off == 0)
7530Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_INTL(MSG_WARN_INVCAP2),
7540Sstevel@tonic-gate 			    file, ccache->c_name);
7550Sstevel@tonic-gate 		else if ((cphdr_off != cshdr->sh_offset) ||
7560Sstevel@tonic-gate 		    (cphdr_sz != cshdr->sh_size))
7570Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_INTL(MSG_WARN_INVCAP3),
7580Sstevel@tonic-gate 			    file, ccache->c_name);
7590Sstevel@tonic-gate 	}
7600Sstevel@tonic-gate }
7610Sstevel@tonic-gate 
7620Sstevel@tonic-gate /*
7630Sstevel@tonic-gate  * Print the interpretor.
7640Sstevel@tonic-gate  */
7650Sstevel@tonic-gate static void
766*942Sahl interp(const char *file, Cache *cache, GElf_Word shnum, GElf_Word phnum,
767*942Sahl     GElf_Ehdr *ehdr, Elf *elf)
7680Sstevel@tonic-gate {
7690Sstevel@tonic-gate 	GElf_Word	cnt;
7700Sstevel@tonic-gate 	GElf_Shdr *	ishdr = 0;
7710Sstevel@tonic-gate 	Cache *		icache;
7720Sstevel@tonic-gate 	Elf64_Off	iphdr_off = 0;
7730Sstevel@tonic-gate 	Elf64_Xword	iphdr_sz;
7740Sstevel@tonic-gate 
7750Sstevel@tonic-gate 	/*
7760Sstevel@tonic-gate 	 * Determine if an interp header exists.
7770Sstevel@tonic-gate 	 */
778*942Sahl 	for (cnt = 0; cnt < phnum; cnt++) {
7790Sstevel@tonic-gate 		GElf_Phdr	phdr;
7800Sstevel@tonic-gate 
7810Sstevel@tonic-gate 		if (gelf_getphdr(elf, cnt, &phdr) == NULL) {
7820Sstevel@tonic-gate 			failure(file, MSG_ORIG(MSG_ELF_GETPHDR));
7830Sstevel@tonic-gate 			return;
7840Sstevel@tonic-gate 		}
7850Sstevel@tonic-gate 
7860Sstevel@tonic-gate 		if (phdr.p_type == PT_INTERP) {
7870Sstevel@tonic-gate 			iphdr_off = phdr.p_offset;
7880Sstevel@tonic-gate 			iphdr_sz = phdr.p_filesz;
7890Sstevel@tonic-gate 			break;
7900Sstevel@tonic-gate 		}
7910Sstevel@tonic-gate 	}
7920Sstevel@tonic-gate 
7930Sstevel@tonic-gate 	if (iphdr_off == 0)
7940Sstevel@tonic-gate 		return;
7950Sstevel@tonic-gate 
7960Sstevel@tonic-gate 	/*
7970Sstevel@tonic-gate 	 * Determine if an interp section exists.
7980Sstevel@tonic-gate 	 */
7990Sstevel@tonic-gate 	for (cnt = 1; cnt < shnum; cnt++) {
8000Sstevel@tonic-gate 		Cache *		_cache;
8010Sstevel@tonic-gate 		GElf_Shdr	*shdr;
8020Sstevel@tonic-gate 
8030Sstevel@tonic-gate 		_cache = &cache[cnt];
8040Sstevel@tonic-gate 		shdr = &_cache->c_shdr;
8050Sstevel@tonic-gate 
8060Sstevel@tonic-gate 		/*
8070Sstevel@tonic-gate 		 * Scan sections to find a section which contains the PT_INTERP
8080Sstevel@tonic-gate 		 * string.  The target section can't be in a NOBITS section.
8090Sstevel@tonic-gate 		 */
8100Sstevel@tonic-gate 		if ((shdr->sh_type == SHT_NOBITS) ||
8110Sstevel@tonic-gate 		    (iphdr_off < shdr->sh_offset) ||
8120Sstevel@tonic-gate 		    (iphdr_off + iphdr_sz) > (shdr->sh_offset + shdr->sh_size))
8130Sstevel@tonic-gate 			continue;
8140Sstevel@tonic-gate 
8150Sstevel@tonic-gate 		icache = _cache;
8160Sstevel@tonic-gate 		ishdr = shdr;
8170Sstevel@tonic-gate 		break;
8180Sstevel@tonic-gate 	}
8190Sstevel@tonic-gate 
8200Sstevel@tonic-gate 	/*
8210Sstevel@tonic-gate 	 * Print the interpreter string based on the offset defined in the
8220Sstevel@tonic-gate 	 * program header, as this is the offset used by the kernel.
8230Sstevel@tonic-gate 	 */
8240Sstevel@tonic-gate 	if (ishdr) {
8250Sstevel@tonic-gate 		dbg_print(MSG_ORIG(MSG_STR_EMPTY));
8260Sstevel@tonic-gate 		dbg_print(MSG_INTL(MSG_ELF_SCN_INTERP), icache->c_name);
8270Sstevel@tonic-gate 		dbg_print(MSG_ORIG(MSG_FMT_INDENT),
8280Sstevel@tonic-gate 		    (char *)icache->c_data->d_buf +
8290Sstevel@tonic-gate 		    (iphdr_off - ishdr->sh_offset));
8300Sstevel@tonic-gate 	} else
8310Sstevel@tonic-gate 		(void) fprintf(stderr, MSG_INTL(MSG_WARN_INVINTERP1), file);
8320Sstevel@tonic-gate 
8330Sstevel@tonic-gate 	/*
8340Sstevel@tonic-gate 	 * If there are any inconsistences between the program header and
8350Sstevel@tonic-gate 	 * section information, flag them.
8360Sstevel@tonic-gate 	 */
8370Sstevel@tonic-gate 	if (ishdr && ((iphdr_off != ishdr->sh_offset) ||
8380Sstevel@tonic-gate 	    (iphdr_sz != ishdr->sh_size))) {
8390Sstevel@tonic-gate 		(void) fprintf(stderr, MSG_INTL(MSG_WARN_INVINTERP2), file,
8400Sstevel@tonic-gate 		    icache->c_name);
8410Sstevel@tonic-gate 		(void) fflush(stderr);
8420Sstevel@tonic-gate 	}
8430Sstevel@tonic-gate }
8440Sstevel@tonic-gate 
8450Sstevel@tonic-gate /*
8460Sstevel@tonic-gate  * Print the syminfo section.
8470Sstevel@tonic-gate  */
8480Sstevel@tonic-gate static void
8490Sstevel@tonic-gate syminfo(Cache *cache, GElf_Word shnum, const char *file)
8500Sstevel@tonic-gate {
8510Sstevel@tonic-gate 	GElf_Shdr	*shdr;
8520Sstevel@tonic-gate 	Elf_Data	*dsyms, *ddyn;
8530Sstevel@tonic-gate 	GElf_Word	symn, cnt, ndx;
8540Sstevel@tonic-gate 	Cache		*syminfo = 0;
8550Sstevel@tonic-gate 	char		*sname;
8560Sstevel@tonic-gate 
8570Sstevel@tonic-gate 	for (cnt = 1; cnt < shnum; cnt++) {
8580Sstevel@tonic-gate 		if (cache[cnt].c_shdr.sh_type == SHT_SUNW_syminfo) {
8590Sstevel@tonic-gate 			syminfo = &cache[cnt];
8600Sstevel@tonic-gate 			break;
8610Sstevel@tonic-gate 		}
8620Sstevel@tonic-gate 	}
8630Sstevel@tonic-gate 	if (syminfo == 0)
8640Sstevel@tonic-gate 		return;
8650Sstevel@tonic-gate 
8660Sstevel@tonic-gate 	shdr = &syminfo->c_shdr;
8670Sstevel@tonic-gate 	/*
8680Sstevel@tonic-gate 	 * Determine the symbol info data and number.
8690Sstevel@tonic-gate 	 */
8700Sstevel@tonic-gate 	if ((shdr->sh_entsize == 0) || (shdr->sh_size == 0)) {
8710Sstevel@tonic-gate 		(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ),
8720Sstevel@tonic-gate 		    file, syminfo->c_name);
8730Sstevel@tonic-gate 		(void) fflush(stderr);
8740Sstevel@tonic-gate 		return;
8750Sstevel@tonic-gate 	}
8760Sstevel@tonic-gate 	/* LINTED */
8770Sstevel@tonic-gate 	symn = (GElf_Word)(shdr->sh_size / shdr->sh_entsize);
8780Sstevel@tonic-gate 
8790Sstevel@tonic-gate 	/*
8800Sstevel@tonic-gate 	 * Get the data buffer of the associated dynamic section.
8810Sstevel@tonic-gate 	 */
8820Sstevel@tonic-gate 	if ((shdr->sh_info == 0) || (shdr->sh_info >= shnum)) {
8830Sstevel@tonic-gate 		(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHINFO),
8840Sstevel@tonic-gate 		    file, syminfo->c_name, EC_XWORD(shdr->sh_info));
8850Sstevel@tonic-gate 		(void) fflush(stderr);
8860Sstevel@tonic-gate 		return;
8870Sstevel@tonic-gate 	}
8880Sstevel@tonic-gate 	ddyn = cache[shdr->sh_info].c_data;
8890Sstevel@tonic-gate 	if (ddyn->d_buf == 0) {
8900Sstevel@tonic-gate 		(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ),
8910Sstevel@tonic-gate 		    file, cache[shdr->sh_info].c_name);
8920Sstevel@tonic-gate 		(void) fflush(stderr);
8930Sstevel@tonic-gate 		return;
8940Sstevel@tonic-gate 	}
8950Sstevel@tonic-gate 
8960Sstevel@tonic-gate 	/*
8970Sstevel@tonic-gate 	 * Get the data buffer of the associated symbol table.
8980Sstevel@tonic-gate 	 */
8990Sstevel@tonic-gate 	if ((shdr->sh_link == 0) || (shdr->sh_link >= shnum)) {
9000Sstevel@tonic-gate 		(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHLINK),
9010Sstevel@tonic-gate 		    file, syminfo->c_name, EC_XWORD(shdr->sh_link));
9020Sstevel@tonic-gate 		(void) fflush(stderr);
9030Sstevel@tonic-gate 		return;
9040Sstevel@tonic-gate 	}
9050Sstevel@tonic-gate 	dsyms = cache[shdr->sh_link].c_data;
9060Sstevel@tonic-gate 	if (dsyms->d_buf == 0) {
9070Sstevel@tonic-gate 		(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ),
9080Sstevel@tonic-gate 		    file, cache[shdr->sh_link].c_name);
9090Sstevel@tonic-gate 		(void) fflush(stderr);
9100Sstevel@tonic-gate 		return;
9110Sstevel@tonic-gate 	}
9120Sstevel@tonic-gate 
9130Sstevel@tonic-gate 	sname = cache[shdr->sh_link].c_name;
9140Sstevel@tonic-gate 	shdr = &cache[shdr->sh_link].c_shdr;
9150Sstevel@tonic-gate 	/*
9160Sstevel@tonic-gate 	 * Get the associated string table section.
9170Sstevel@tonic-gate 	 */
9180Sstevel@tonic-gate 	if ((shdr->sh_link == 0) || (shdr->sh_link >= shnum)) {
9190Sstevel@tonic-gate 		(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHLINK),
9200Sstevel@tonic-gate 		    file, sname, EC_XWORD(shdr->sh_link));
9210Sstevel@tonic-gate 		(void) fflush(stderr);
9220Sstevel@tonic-gate 		return;
9230Sstevel@tonic-gate 	}
9240Sstevel@tonic-gate 
9250Sstevel@tonic-gate 	dbg_print(MSG_ORIG(MSG_STR_EMPTY));
9260Sstevel@tonic-gate 	dbg_print(MSG_INTL(MSG_ELF_SCN_SYMINFO), syminfo->c_name);
9270Sstevel@tonic-gate 	Gelf_syminfo_title();
9280Sstevel@tonic-gate 
9290Sstevel@tonic-gate 	for (ndx = 1; ndx < symn; ndx++) {
9300Sstevel@tonic-gate 		GElf_Syminfo 	gsip;
9310Sstevel@tonic-gate 		GElf_Sym 	gsym;
9320Sstevel@tonic-gate 		GElf_Dyn	gdyn;
9330Sstevel@tonic-gate 		const char	*needed, *sname;
9340Sstevel@tonic-gate 
9350Sstevel@tonic-gate 		if (gelf_getsyminfo(syminfo->c_data, ndx, &gsip) == 0) {
9360Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_INTL(MSG_ERR_SIBADCOUNT),
9370Sstevel@tonic-gate 			    file, syminfo->c_name, ndx);
9380Sstevel@tonic-gate 			(void) fflush(stderr);
9390Sstevel@tonic-gate 			return;
9400Sstevel@tonic-gate 		}
9410Sstevel@tonic-gate 		if ((gsip.si_flags == 0) && (gsip.si_boundto == 0))
9420Sstevel@tonic-gate 			continue;
9430Sstevel@tonic-gate 
9440Sstevel@tonic-gate 		if (gelf_getsym(dsyms, ndx, &gsym) == 0) {
9450Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSYM),
9460Sstevel@tonic-gate 			    file, syminfo->c_name, elf_errmsg(0));
9470Sstevel@tonic-gate 			(void) fflush(stderr);
9480Sstevel@tonic-gate 			return;
9490Sstevel@tonic-gate 		}
9500Sstevel@tonic-gate 
9510Sstevel@tonic-gate 		sname = string(syminfo, cnt, &cache[shdr->sh_link], file,
9520Sstevel@tonic-gate 		    gsym.st_name);
9530Sstevel@tonic-gate 		needed = 0;
9540Sstevel@tonic-gate 
9550Sstevel@tonic-gate 		if (gsip.si_boundto < SYMINFO_BT_LOWRESERVE) {
9560Sstevel@tonic-gate 			if (gelf_getdyn(ddyn, gsip.si_boundto, &gdyn) == 0) {
9570Sstevel@tonic-gate 				(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADDYN),
9580Sstevel@tonic-gate 				    file, syminfo->c_name, gsip.si_boundto);
9590Sstevel@tonic-gate 				(void) fflush(stderr);
9600Sstevel@tonic-gate 				return;
9610Sstevel@tonic-gate 			}
9620Sstevel@tonic-gate 			needed = string(syminfo, gsip.si_boundto,
9630Sstevel@tonic-gate 			    &cache[shdr->sh_link], file, gdyn.d_un.d_val);
9640Sstevel@tonic-gate 		}
9650Sstevel@tonic-gate 
9660Sstevel@tonic-gate 		Gelf_syminfo_entry(ndx, &gsip, sname, needed);
9670Sstevel@tonic-gate 	}
9680Sstevel@tonic-gate }
9690Sstevel@tonic-gate 
9700Sstevel@tonic-gate /*
9710Sstevel@tonic-gate  * Print version definition section entries.
9720Sstevel@tonic-gate  */
9730Sstevel@tonic-gate static void
9740Sstevel@tonic-gate version_def(GElf_Verdef *vdf, GElf_Word shnum, Cache *vcache, Cache *scache,
9750Sstevel@tonic-gate     const char *file)
9760Sstevel@tonic-gate {
9770Sstevel@tonic-gate 	GElf_Word	cnt;
9780Sstevel@tonic-gate 	char		index[MAXNDXSIZE];
9790Sstevel@tonic-gate 
9800Sstevel@tonic-gate 	Gelf_ver_def_title();
9810Sstevel@tonic-gate 
9820Sstevel@tonic-gate 	for (cnt = 1; cnt <= shnum; cnt++,
9830Sstevel@tonic-gate 	    vdf = (GElf_Verdef *)((uintptr_t)vdf + vdf->vd_next)) {
9840Sstevel@tonic-gate 
9850Sstevel@tonic-gate 		GElf_Half	vcnt = vdf->vd_cnt - 1;
9860Sstevel@tonic-gate 		GElf_Half	ndx = vdf->vd_ndx;
9870Sstevel@tonic-gate 		GElf_Verdaux	*vdap = (GElf_Verdaux *)
9880Sstevel@tonic-gate 				    ((uintptr_t)vdf + vdf->vd_aux);
9890Sstevel@tonic-gate 		const char	*name, *dep;
9900Sstevel@tonic-gate 
9910Sstevel@tonic-gate 		/*
9920Sstevel@tonic-gate 		 * Obtain the name and first dependency (if any).
9930Sstevel@tonic-gate 		 */
9940Sstevel@tonic-gate 		name = string(vcache, cnt, scache, file, vdap->vda_name);
9950Sstevel@tonic-gate 		vdap = (GElf_Verdaux *)((uintptr_t)vdap + vdap->vda_next);
9960Sstevel@tonic-gate 		if (vcnt)
9970Sstevel@tonic-gate 			dep = string(vcache, cnt, scache, file, vdap->vda_name);
9980Sstevel@tonic-gate 		else
9990Sstevel@tonic-gate 			dep = MSG_ORIG(MSG_STR_EMPTY);
10000Sstevel@tonic-gate 
10010Sstevel@tonic-gate 		(void) snprintf(index, MAXNDXSIZE, MSG_ORIG(MSG_FMT_INDEX),
10020Sstevel@tonic-gate 		    EC_XWORD(ndx));
10030Sstevel@tonic-gate 		Gelf_ver_line_1(index, name, dep,
10040Sstevel@tonic-gate 		    conv_verflg_str(vdf->vd_flags));
10050Sstevel@tonic-gate 
10060Sstevel@tonic-gate 		/*
10070Sstevel@tonic-gate 		 * Print any additional dependencies.
10080Sstevel@tonic-gate 		 */
10090Sstevel@tonic-gate 		if (vcnt) {
10100Sstevel@tonic-gate 			vdap = (GElf_Verdaux *)((uintptr_t)vdap +
10110Sstevel@tonic-gate 				vdap->vda_next);
10120Sstevel@tonic-gate 			for (vcnt--; vcnt; vcnt--,
10130Sstevel@tonic-gate 			    vdap = (GElf_Verdaux *)((uintptr_t)vdap +
10140Sstevel@tonic-gate 			    vdap->vda_next)) {
10150Sstevel@tonic-gate 				dep = string(vcache, cnt, scache, file,
10160Sstevel@tonic-gate 				    vdap->vda_name);
10170Sstevel@tonic-gate 				Gelf_ver_line_2(MSG_ORIG(MSG_STR_EMPTY), dep);
10180Sstevel@tonic-gate 			}
10190Sstevel@tonic-gate 		}
10200Sstevel@tonic-gate 	}
10210Sstevel@tonic-gate }
10220Sstevel@tonic-gate 
10230Sstevel@tonic-gate /*
10240Sstevel@tonic-gate  * Print a version needed section entries.
10250Sstevel@tonic-gate  */
10260Sstevel@tonic-gate static void
10270Sstevel@tonic-gate version_need(GElf_Verneed *vnd, GElf_Word shnum, Cache *vcache, Cache *scache,
10280Sstevel@tonic-gate     const char *file)
10290Sstevel@tonic-gate {
10300Sstevel@tonic-gate 	GElf_Word	cnt;
10310Sstevel@tonic-gate 
10320Sstevel@tonic-gate 	Gelf_ver_need_title();
10330Sstevel@tonic-gate 
10340Sstevel@tonic-gate 	for (cnt = 1; cnt <= shnum; cnt++,
10350Sstevel@tonic-gate 	    vnd = (GElf_Verneed *)((uintptr_t)vnd + vnd->vn_next)) {
10360Sstevel@tonic-gate 
10370Sstevel@tonic-gate 		GElf_Half	vcnt = vnd->vn_cnt;
10380Sstevel@tonic-gate 		GElf_Vernaux	*vnap = (GElf_Vernaux *)((uintptr_t)vnd +
10390Sstevel@tonic-gate 			vnd->vn_aux);
10400Sstevel@tonic-gate 		const char	*name, *dep;
10410Sstevel@tonic-gate 
10420Sstevel@tonic-gate 		/*
10430Sstevel@tonic-gate 		 * Obtain the name of the needed file and the version name
10440Sstevel@tonic-gate 		 * within it that we're dependent on.  Note that the count
10450Sstevel@tonic-gate 		 * should be at least one, otherwise this is a pretty bogus
10460Sstevel@tonic-gate 		 * entry.
10470Sstevel@tonic-gate 		 */
10480Sstevel@tonic-gate 		name = string(vcache, cnt, scache, file, vnd->vn_file);
10490Sstevel@tonic-gate 		if (vcnt)
10500Sstevel@tonic-gate 			dep = string(vcache, cnt, scache, file, vnap->vna_name);
10510Sstevel@tonic-gate 		else
10520Sstevel@tonic-gate 			dep = MSG_INTL(MSG_STR_NULL);
10530Sstevel@tonic-gate 
10540Sstevel@tonic-gate 		Gelf_ver_line_1(MSG_ORIG(MSG_STR_EMPTY), name, dep,
10550Sstevel@tonic-gate 		    conv_verflg_str(vnap->vna_flags));
10560Sstevel@tonic-gate 
10570Sstevel@tonic-gate 		/*
10580Sstevel@tonic-gate 		 * Print any additional version dependencies.
10590Sstevel@tonic-gate 		 */
10600Sstevel@tonic-gate 		if (vcnt) {
10610Sstevel@tonic-gate 			vnap = (GElf_Vernaux *)((uintptr_t)vnap +
10620Sstevel@tonic-gate 				vnap->vna_next);
10630Sstevel@tonic-gate 			for (vcnt--; vcnt; vcnt--,
10640Sstevel@tonic-gate 			    vnap = (GElf_Vernaux *)((uintptr_t)vnap +
10650Sstevel@tonic-gate 			    vnap->vna_next)) {
10660Sstevel@tonic-gate 				dep = string(vcache, cnt, scache, file,
10670Sstevel@tonic-gate 				    vnap->vna_name);
10680Sstevel@tonic-gate 				Gelf_ver_line_3(MSG_ORIG(MSG_STR_EMPTY), dep,
10690Sstevel@tonic-gate 				    conv_verflg_str(vnap->vna_flags));
10700Sstevel@tonic-gate 			}
10710Sstevel@tonic-gate 		}
10720Sstevel@tonic-gate 	}
10730Sstevel@tonic-gate }
10740Sstevel@tonic-gate 
10750Sstevel@tonic-gate /*
10760Sstevel@tonic-gate  * Search for any verion sections - the Versym output is possibly
10770Sstevel@tonic-gate  * used by the symbols() printing.  If VERSYM is specified - then
10780Sstevel@tonic-gate  * display the version information.
10790Sstevel@tonic-gate  */
10800Sstevel@tonic-gate static Cache *
10810Sstevel@tonic-gate versions(Cache *cache, GElf_Word shnum, const char *file, uint32_t flags)
10820Sstevel@tonic-gate {
10830Sstevel@tonic-gate 	GElf_Word	cnt;
10840Sstevel@tonic-gate 	Cache		*versymcache = 0;
10850Sstevel@tonic-gate 
10860Sstevel@tonic-gate 	for (cnt = 1; cnt < shnum; cnt++) {
10870Sstevel@tonic-gate 		void *		ver;
10880Sstevel@tonic-gate 		uint_t		num;
10890Sstevel@tonic-gate 		Cache *		_cache = &cache[cnt];
10900Sstevel@tonic-gate 		GElf_Shdr *	shdr = &_cache->c_shdr;
10910Sstevel@tonic-gate 
10920Sstevel@tonic-gate 		/*
10930Sstevel@tonic-gate 		 * If this is the version symbol table simply record its
10940Sstevel@tonic-gate 		 * data address for possible use in later symbol processing.
10950Sstevel@tonic-gate 		 */
10960Sstevel@tonic-gate 		if (shdr->sh_type == SHT_SUNW_versym) {
10970Sstevel@tonic-gate 			versymcache = _cache;
10980Sstevel@tonic-gate 			continue;
10990Sstevel@tonic-gate 		}
11000Sstevel@tonic-gate 
11010Sstevel@tonic-gate 		if ((flags & FLG_VERSIONS) == 0)
11020Sstevel@tonic-gate 			continue;
11030Sstevel@tonic-gate 
11040Sstevel@tonic-gate 		if ((shdr->sh_type != SHT_SUNW_verdef) &&
11050Sstevel@tonic-gate 		    (shdr->sh_type != SHT_SUNW_verneed))
11060Sstevel@tonic-gate 			continue;
11070Sstevel@tonic-gate 
11080Sstevel@tonic-gate 		/*
11090Sstevel@tonic-gate 		 * Determine the version section data and number.
11100Sstevel@tonic-gate 		 */
11110Sstevel@tonic-gate 		if ((ver = (void *)_cache->c_data->d_buf) == 0) {
11120Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ),
11130Sstevel@tonic-gate 			    file, _cache->c_name);
11140Sstevel@tonic-gate 			(void) fflush(stderr);
11150Sstevel@tonic-gate 			continue;
11160Sstevel@tonic-gate 		}
11170Sstevel@tonic-gate 		if ((num = shdr->sh_info) == 0) {
11180Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHINFO),
11190Sstevel@tonic-gate 			    file, _cache->c_name, EC_XWORD(shdr->sh_info));
11200Sstevel@tonic-gate 			(void) fflush(stderr);
11210Sstevel@tonic-gate 			continue;
11220Sstevel@tonic-gate 		}
11230Sstevel@tonic-gate 
11240Sstevel@tonic-gate 		/*
11250Sstevel@tonic-gate 		 * Get the data buffer for the associated string table.
11260Sstevel@tonic-gate 		 */
11270Sstevel@tonic-gate 		if ((shdr->sh_link == 0) || (shdr->sh_link >= shnum)) {
11280Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHLINK),
11290Sstevel@tonic-gate 			    file, _cache->c_name, EC_XWORD(shdr->sh_link));
11300Sstevel@tonic-gate 			(void) fflush(stderr);
11310Sstevel@tonic-gate 			continue;
11320Sstevel@tonic-gate 		}
11330Sstevel@tonic-gate 
11340Sstevel@tonic-gate 		dbg_print(MSG_ORIG(MSG_STR_EMPTY));
11350Sstevel@tonic-gate 		if (shdr->sh_type == SHT_SUNW_verdef) {
11360Sstevel@tonic-gate 			dbg_print(MSG_INTL(MSG_ELF_SCN_VERDEF),
11370Sstevel@tonic-gate 			    _cache->c_name);
11380Sstevel@tonic-gate 			version_def((GElf_Verdef *)ver, num, _cache,
11390Sstevel@tonic-gate 			    &cache[shdr->sh_link], file);
11400Sstevel@tonic-gate 		} else if (shdr->sh_type == SHT_SUNW_verneed) {
11410Sstevel@tonic-gate 			dbg_print(MSG_INTL(MSG_ELF_SCN_VERNEED),
11420Sstevel@tonic-gate 			    _cache->c_name);
11430Sstevel@tonic-gate 			version_need((GElf_Verneed *)ver, num, _cache,
11440Sstevel@tonic-gate 			    &cache[shdr->sh_link], file);
11450Sstevel@tonic-gate 		}
11460Sstevel@tonic-gate 	}
11470Sstevel@tonic-gate 	return (versymcache);
11480Sstevel@tonic-gate }
11490Sstevel@tonic-gate 
11500Sstevel@tonic-gate /*
11510Sstevel@tonic-gate  * Search for and process any symbol tables.
11520Sstevel@tonic-gate  */
11530Sstevel@tonic-gate static void
1154*942Sahl symbols(Cache *cache, GElf_Word shnum, GElf_Word phnum, GElf_Ehdr *ehdr,
1155*942Sahl     const char *name, Cache *versymcache, const char *file)
11560Sstevel@tonic-gate {
11570Sstevel@tonic-gate 	GElf_Word	cnt;
11580Sstevel@tonic-gate 	char		is_core = (ehdr->e_type == ET_CORE);
11590Sstevel@tonic-gate 
11600Sstevel@tonic-gate 	for (cnt = 1; cnt < shnum; cnt++) {
11610Sstevel@tonic-gate 		GElf_Sym 	sym;
11620Sstevel@tonic-gate 		GElf_Word	symn, _cnt;
11630Sstevel@tonic-gate 		GElf_Versym	*versym;
11640Sstevel@tonic-gate 		Cache		*_cache = &cache[cnt];
11650Sstevel@tonic-gate 		GElf_Shdr	*shdr = &_cache->c_shdr;
11660Sstevel@tonic-gate 		Word		*symshndx;
11670Sstevel@tonic-gate 		uint_t		nosymshndx;
11680Sstevel@tonic-gate 		uint_t		nosyminshndx;
11690Sstevel@tonic-gate 
11700Sstevel@tonic-gate 		if ((shdr->sh_type != SHT_SYMTAB) &&
11710Sstevel@tonic-gate 		    (shdr->sh_type != SHT_DYNSYM))
11720Sstevel@tonic-gate 			continue;
11730Sstevel@tonic-gate 		if (name && strcmp(name, _cache->c_name))
11740Sstevel@tonic-gate 			continue;
11750Sstevel@tonic-gate 
11760Sstevel@tonic-gate 		/*
11770Sstevel@tonic-gate 		 * Determine the symbol data and number.
11780Sstevel@tonic-gate 		 */
11790Sstevel@tonic-gate 		if ((shdr->sh_entsize == 0) || (shdr->sh_size == 0)) {
11800Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ),
11810Sstevel@tonic-gate 			    file, _cache->c_name);
11820Sstevel@tonic-gate 			(void) fflush(stderr);
11830Sstevel@tonic-gate 			continue;
11840Sstevel@tonic-gate 		}
11850Sstevel@tonic-gate 		/* LINTED */
11860Sstevel@tonic-gate 		symn = (GElf_Word)(shdr->sh_size / shdr->sh_entsize);
11870Sstevel@tonic-gate 
11880Sstevel@tonic-gate 		/*
11890Sstevel@tonic-gate 		 * Get the associated string table section.
11900Sstevel@tonic-gate 		 */
11910Sstevel@tonic-gate 		if ((shdr->sh_link == 0) || (shdr->sh_link >= shnum)) {
11920Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHLINK),
11930Sstevel@tonic-gate 			    file, _cache->c_name, EC_XWORD(shdr->sh_link));
11940Sstevel@tonic-gate 			(void) fflush(stderr);
11950Sstevel@tonic-gate 			continue;
11960Sstevel@tonic-gate 		}
11970Sstevel@tonic-gate 
11980Sstevel@tonic-gate 		/*
11990Sstevel@tonic-gate 		 * Determine if there is a associated Versym section
12000Sstevel@tonic-gate 		 * with this Symbol Table.
12010Sstevel@tonic-gate 		 */
12020Sstevel@tonic-gate 		if (versymcache && (versymcache->c_shdr.sh_link == cnt))
12030Sstevel@tonic-gate 			versym = versymcache->c_data->d_buf;
12040Sstevel@tonic-gate 		else
12050Sstevel@tonic-gate 			versym = 0;
12060Sstevel@tonic-gate 
12070Sstevel@tonic-gate 		/*
12080Sstevel@tonic-gate 		 * Loop through the symbol tables entries.
12090Sstevel@tonic-gate 		 */
12100Sstevel@tonic-gate 		dbg_print(MSG_ORIG(MSG_STR_EMPTY));
12110Sstevel@tonic-gate 		dbg_print(MSG_INTL(MSG_ELF_SCN_SYMTAB), _cache->c_name);
12120Sstevel@tonic-gate 		Gelf_sym_table_title(ehdr, MSG_INTL(MSG_STR_INDEX),
12130Sstevel@tonic-gate 		    MSG_INTL(MSG_STR_NAME));
12140Sstevel@tonic-gate 
12150Sstevel@tonic-gate 		symshndx = 0;
12160Sstevel@tonic-gate 		nosymshndx = 0;
12170Sstevel@tonic-gate 		nosyminshndx = 0;
12180Sstevel@tonic-gate 		for (_cnt = 0; _cnt < symn; _cnt++) {
12190Sstevel@tonic-gate 			char		index[MAXNDXSIZE];
12200Sstevel@tonic-gate 			char		*sec;
12210Sstevel@tonic-gate 			const char	*sname;
12220Sstevel@tonic-gate 			int		verndx;
12230Sstevel@tonic-gate 			uchar_t		type;
12240Sstevel@tonic-gate 			GElf_Shdr	*tshdr;
12250Sstevel@tonic-gate 			Word		shndx;
12260Sstevel@tonic-gate 
12270Sstevel@tonic-gate 			if (gelf_getsym(_cache->c_data, _cnt, &sym) == NULL) {
12280Sstevel@tonic-gate 				(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSYM),
12290Sstevel@tonic-gate 				    file, _cache->c_name, elf_errmsg(0));
12300Sstevel@tonic-gate 				(void) fflush(stderr);
12310Sstevel@tonic-gate 				break;
12320Sstevel@tonic-gate 			}
12330Sstevel@tonic-gate 
12340Sstevel@tonic-gate 			/*
12350Sstevel@tonic-gate 			 * If we are using extended symbol indexes, find the
12360Sstevel@tonic-gate 			 * corresponding SHN_SYMTAB_SHNDX table.
12370Sstevel@tonic-gate 			 */
12380Sstevel@tonic-gate 			if ((sym.st_shndx == SHN_XINDEX) &&
12390Sstevel@tonic-gate 			    (symshndx == 0) && (nosymshndx == 0)) {
12400Sstevel@tonic-gate 				Word	__cnt;
12410Sstevel@tonic-gate 
12420Sstevel@tonic-gate 				for (__cnt = 1; __cnt < shnum; __cnt++) {
12430Sstevel@tonic-gate 					Cache		*_cache = &cache[__cnt];
12440Sstevel@tonic-gate 					GElf_Shdr	*shdr = &_cache->c_shdr;
12450Sstevel@tonic-gate 
12460Sstevel@tonic-gate 					if ((shdr->sh_type !=
12470Sstevel@tonic-gate 					    SHT_SYMTAB_SHNDX) ||
12480Sstevel@tonic-gate 					    (shdr->sh_link != cnt))
12490Sstevel@tonic-gate 						continue;
12500Sstevel@tonic-gate 					if (shdr->sh_entsize)
12510Sstevel@tonic-gate 						/* LINTED */
12520Sstevel@tonic-gate 						nosyminshndx = (uint_t)
12530Sstevel@tonic-gate 						shdr->sh_size/shdr->sh_entsize;
12540Sstevel@tonic-gate 					if (nosyminshndx == 0)
12550Sstevel@tonic-gate 						continue;
12560Sstevel@tonic-gate 					symshndx = _cache->c_data->d_buf;
12570Sstevel@tonic-gate 					break;
12580Sstevel@tonic-gate 				}
12590Sstevel@tonic-gate 				if (symshndx == 0)
12600Sstevel@tonic-gate 					nosymshndx = 1;
12610Sstevel@tonic-gate 			}
12620Sstevel@tonic-gate 
12630Sstevel@tonic-gate 			/* LINTED */
12640Sstevel@tonic-gate 			sname = string(_cache, _cnt, &cache[shdr->sh_link],
12650Sstevel@tonic-gate 			    file, sym.st_name);
12660Sstevel@tonic-gate 
12670Sstevel@tonic-gate 			tshdr = 0;
12680Sstevel@tonic-gate 			sec = NULL;
12690Sstevel@tonic-gate 
12700Sstevel@tonic-gate 			if (is_core)
12710Sstevel@tonic-gate 				sec = (char *)MSG_INTL(MSG_STR_UNKNOWN);
12720Sstevel@tonic-gate 			else if ((sym.st_shndx < SHN_LORESERVE) &&
12730Sstevel@tonic-gate 			    (sym.st_shndx < shnum)) {
12740Sstevel@tonic-gate 				shndx = sym.st_shndx;
12750Sstevel@tonic-gate 				tshdr = &(cache[shndx].c_shdr);
12760Sstevel@tonic-gate 				sec = cache[shndx].c_name;
12770Sstevel@tonic-gate 			} else if (sym.st_shndx == SHN_XINDEX) {
12780Sstevel@tonic-gate 				if (symshndx) {
12790Sstevel@tonic-gate 					Word	_symshndx;
12800Sstevel@tonic-gate 
12810Sstevel@tonic-gate 					if (_cnt > nosyminshndx) {
12820Sstevel@tonic-gate 					    (void) fprintf(stderr,
12830Sstevel@tonic-gate 						MSG_INTL(MSG_ERR_BADSYMXINDEX1),
12840Sstevel@tonic-gate 						file, _cache->c_name,
12850Sstevel@tonic-gate 						EC_WORD(_cnt));
12860Sstevel@tonic-gate 					    (void) fflush(stderr);
12870Sstevel@tonic-gate 					} else if ((_symshndx =
12880Sstevel@tonic-gate 					    symshndx[_cnt]) > shnum) {
12890Sstevel@tonic-gate 					    (void) fprintf(stderr,
12900Sstevel@tonic-gate 						MSG_INTL(MSG_ERR_BADSYMXINDEX2),
12910Sstevel@tonic-gate 						file, _cache->c_name,
12920Sstevel@tonic-gate 						EC_WORD(_cnt),
12930Sstevel@tonic-gate 						EC_WORD(_symshndx));
12940Sstevel@tonic-gate 					    (void) fflush(stderr);
12950Sstevel@tonic-gate 					} else {
12960Sstevel@tonic-gate 					    shndx = _symshndx;
12970Sstevel@tonic-gate 					    tshdr = &(cache[shndx].c_shdr);
12980Sstevel@tonic-gate 					    sec = cache[shndx].c_name;
12990Sstevel@tonic-gate 					}
13000Sstevel@tonic-gate 				} else {
13010Sstevel@tonic-gate 					(void) fprintf(stderr,
13020Sstevel@tonic-gate 						MSG_INTL(MSG_ERR_BADSYMXINDEX3),
13030Sstevel@tonic-gate 						file, _cache->c_name,
13040Sstevel@tonic-gate 						EC_WORD(_cnt));
13050Sstevel@tonic-gate 					(void) fflush(stderr);
13060Sstevel@tonic-gate 				}
13070Sstevel@tonic-gate 			} else if ((sym.st_shndx < SHN_LORESERVE) &&
13080Sstevel@tonic-gate 			    (sym.st_shndx >= shnum)) {
13090Sstevel@tonic-gate 				(void) fprintf(stderr,
13100Sstevel@tonic-gate 					MSG_INTL(MSG_ERR_BADSYM5),
13110Sstevel@tonic-gate 					file, _cache->c_name,
13120Sstevel@tonic-gate 					sname, sym.st_shndx);
13130Sstevel@tonic-gate 				(void) fflush(stderr);
13140Sstevel@tonic-gate 			}
13150Sstevel@tonic-gate 
13160Sstevel@tonic-gate 			/*
13170Sstevel@tonic-gate 			 * If versioning is available display the
13180Sstevel@tonic-gate 			 * version index.
13190Sstevel@tonic-gate 			 */
13200Sstevel@tonic-gate 			if (versym)
13210Sstevel@tonic-gate 				verndx = (int)versym[_cnt];
13220Sstevel@tonic-gate 			else
13230Sstevel@tonic-gate 				verndx = 0;
13240Sstevel@tonic-gate 
13250Sstevel@tonic-gate 			/*
13260Sstevel@tonic-gate 			 * Error checking for TLS.
13270Sstevel@tonic-gate 			 */
13280Sstevel@tonic-gate 			type = ELF_ST_TYPE(sym.st_info);
13290Sstevel@tonic-gate 			if (type == STT_TLS) {
13300Sstevel@tonic-gate 				if (tshdr &&
13310Sstevel@tonic-gate 				    (sym.st_shndx != SHN_UNDEF) &&
13320Sstevel@tonic-gate 				    ((tshdr->sh_flags & SHF_TLS) == 0)) {
13330Sstevel@tonic-gate 					(void) fprintf(stderr,
13340Sstevel@tonic-gate 					    MSG_INTL(MSG_ERR_BADSYM3), file,
13350Sstevel@tonic-gate 					    _cache->c_name, sname);
13360Sstevel@tonic-gate 					(void) fflush(stderr);
13370Sstevel@tonic-gate 				}
13380Sstevel@tonic-gate 			} else if ((type != STT_SECTION) && sym.st_size &&
13390Sstevel@tonic-gate 			    tshdr && (tshdr->sh_flags & SHF_TLS)) {
13400Sstevel@tonic-gate 				(void) fprintf(stderr,
13410Sstevel@tonic-gate 				    MSG_INTL(MSG_ERR_BADSYM4), file,
13420Sstevel@tonic-gate 				    _cache->c_name, sname);
13430Sstevel@tonic-gate 				(void) fflush(stderr);
13440Sstevel@tonic-gate 			}
13450Sstevel@tonic-gate 
13460Sstevel@tonic-gate 			/*
13470Sstevel@tonic-gate 			 * If a symbol has size, then make sure the section it
13480Sstevel@tonic-gate 			 * references is appropriate.  Note, UNDEF symbols that
13490Sstevel@tonic-gate 			 * have a size, have been known to exist - ignore them.
13500Sstevel@tonic-gate 			 */
13510Sstevel@tonic-gate 			if (sym.st_size && shndx && tshdr &&
13520Sstevel@tonic-gate 			    (tshdr->sh_size < sym.st_size)) {
13530Sstevel@tonic-gate 				(void) fprintf(stderr,
13540Sstevel@tonic-gate 				    MSG_INTL(MSG_ERR_BADSYM6), file,
13550Sstevel@tonic-gate 				    _cache->c_name, sname, EC_WORD(shndx),
13560Sstevel@tonic-gate 				    EC_XWORD(tshdr->sh_size),
13570Sstevel@tonic-gate 				    EC_XWORD(sym.st_size));
13580Sstevel@tonic-gate 				(void) fflush(stderr);
13590Sstevel@tonic-gate 			}
13600Sstevel@tonic-gate 
13610Sstevel@tonic-gate 			(void) snprintf(index, MAXNDXSIZE,
13620Sstevel@tonic-gate 			    MSG_ORIG(MSG_FMT_INDEX), EC_XWORD(_cnt));
13630Sstevel@tonic-gate 
13640Sstevel@tonic-gate 			Gelf_sym_table_entry(index, ehdr, &sym, verndx, sec,
13650Sstevel@tonic-gate 			    sname);
13660Sstevel@tonic-gate 		}
13670Sstevel@tonic-gate 	}
13680Sstevel@tonic-gate }
13690Sstevel@tonic-gate 
13700Sstevel@tonic-gate /*
13710Sstevel@tonic-gate  * Search for and process any relocation sections.
13720Sstevel@tonic-gate  */
13730Sstevel@tonic-gate static void
1374*942Sahl reloc(Cache *cache, GElf_Word shnum, GElf_Word phnum, GElf_Ehdr *ehdr,
1375*942Sahl     const char *name, const char *file, uint32_t flags)
13760Sstevel@tonic-gate {
13770Sstevel@tonic-gate 	GElf_Word	cnt;
13780Sstevel@tonic-gate 
13790Sstevel@tonic-gate 	for (cnt = 1; cnt < shnum; cnt++) {
13800Sstevel@tonic-gate 		Word		type;
13810Sstevel@tonic-gate 		ulong_t		numrels, entsize;
13820Sstevel@tonic-gate 		int		ndx;
13830Sstevel@tonic-gate 		Elf_Data	*dsyms;
13840Sstevel@tonic-gate 		Cache		*_cache = &cache[cnt];
13850Sstevel@tonic-gate 		GElf_Shdr	*shdr = &_cache->c_shdr;
13860Sstevel@tonic-gate 		char		*sname;
13870Sstevel@tonic-gate 
13880Sstevel@tonic-gate 		if (((type = shdr->sh_type) != SHT_RELA) &&
13890Sstevel@tonic-gate 		    (type != SHT_REL))
13900Sstevel@tonic-gate 			continue;
13910Sstevel@tonic-gate 		if (name && strcmp(name, _cache->c_name))
13920Sstevel@tonic-gate 			continue;
13930Sstevel@tonic-gate 
13940Sstevel@tonic-gate 		/*
13950Sstevel@tonic-gate 		 * Decide entry size
13960Sstevel@tonic-gate 		 */
13970Sstevel@tonic-gate 		if (((entsize = shdr->sh_entsize) == 0) ||
13980Sstevel@tonic-gate 		    (entsize > shdr->sh_size)) {
13990Sstevel@tonic-gate 			if (type == SHT_RELA)
14000Sstevel@tonic-gate 				entsize = sizeof (GElf_Rela);
14010Sstevel@tonic-gate 			else
14020Sstevel@tonic-gate 				entsize = sizeof (GElf_Rel);
14030Sstevel@tonic-gate 		}
14040Sstevel@tonic-gate 
14050Sstevel@tonic-gate 		/*
14060Sstevel@tonic-gate 		 * Determine the number of relocations available.
14070Sstevel@tonic-gate 		 */
14080Sstevel@tonic-gate 		if (shdr->sh_size == 0) {
14090Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ),
14100Sstevel@tonic-gate 			    file, _cache->c_name);
14110Sstevel@tonic-gate 			(void) fflush(stderr);
14120Sstevel@tonic-gate 			continue;
14130Sstevel@tonic-gate 		}
14140Sstevel@tonic-gate 		numrels = shdr->sh_size / entsize;
14150Sstevel@tonic-gate 
14160Sstevel@tonic-gate 		/*
14170Sstevel@tonic-gate 		 * Get the data buffer for the associated symbol table.  Note
14180Sstevel@tonic-gate 		 * that we've been known to create static binaries containing
14190Sstevel@tonic-gate 		 * relocations against weak symbols, if these get stripped the
14200Sstevel@tonic-gate 		 * relocation records can't make symbolic references.
14210Sstevel@tonic-gate 		 */
14220Sstevel@tonic-gate 		if ((shdr->sh_link == 0) || (shdr->sh_link >= shnum)) {
14230Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHLINK),
14240Sstevel@tonic-gate 			    file, _cache->c_name, EC_XWORD(shdr->sh_link));
14250Sstevel@tonic-gate 			(void) fflush(stderr);
14260Sstevel@tonic-gate 			continue;
14270Sstevel@tonic-gate 		}
14280Sstevel@tonic-gate 		dsyms = cache[shdr->sh_link].c_data;
14290Sstevel@tonic-gate 		if (dsyms->d_buf == 0) {
14300Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ),
14310Sstevel@tonic-gate 			    file, cache[shdr->sh_link].c_name);
14320Sstevel@tonic-gate 			(void) fflush(stderr);
14330Sstevel@tonic-gate 			continue;
14340Sstevel@tonic-gate 		}
14350Sstevel@tonic-gate 
14360Sstevel@tonic-gate 		sname = cache[shdr->sh_link].c_name;
14370Sstevel@tonic-gate 		shdr = &cache[shdr->sh_link].c_shdr;
14380Sstevel@tonic-gate 		/*
14390Sstevel@tonic-gate 		 * Get the associated string table section.
14400Sstevel@tonic-gate 		 */
14410Sstevel@tonic-gate 		if ((shdr->sh_link == 0) || (shdr->sh_link >= shnum)) {
14420Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHLINK),
14430Sstevel@tonic-gate 			    file, sname, EC_XWORD(shdr->sh_link));
14440Sstevel@tonic-gate 			(void) fflush(stderr);
14450Sstevel@tonic-gate 			continue;
14460Sstevel@tonic-gate 		}
14470Sstevel@tonic-gate 
14480Sstevel@tonic-gate 		/*
14490Sstevel@tonic-gate 		 * Loop through the relocation entries.
14500Sstevel@tonic-gate 		 */
14510Sstevel@tonic-gate 		dbg_print(MSG_ORIG(MSG_STR_EMPTY));
14520Sstevel@tonic-gate 		dbg_print(MSG_INTL(MSG_ELF_SCN_RELOC), _cache->c_name);
14530Sstevel@tonic-gate 		if (type == SHT_RELA) {
14540Sstevel@tonic-gate 			if (flags & FLG_LONGNAME)
14550Sstevel@tonic-gate 				dbg_print(MSG_INTL(MSG_ELF_L_RELOC_RELA));
14560Sstevel@tonic-gate 			else
14570Sstevel@tonic-gate 				dbg_print(MSG_INTL(MSG_ELF_RELOC_RELA));
14580Sstevel@tonic-gate 		} else {
14590Sstevel@tonic-gate 			if (flags & FLG_LONGNAME)
14600Sstevel@tonic-gate 				dbg_print(MSG_INTL(MSG_ELF_L_RELOC_REL));
14610Sstevel@tonic-gate 			else
14620Sstevel@tonic-gate 				dbg_print(MSG_INTL(MSG_ELF_RELOC_REL));
14630Sstevel@tonic-gate 		}
14640Sstevel@tonic-gate 
14650Sstevel@tonic-gate 		/* LINTED */
14660Sstevel@tonic-gate 		for (ndx = 0; ndx < numrels; ndx++) {
14670Sstevel@tonic-gate 			char		section[BUFSIZ];
14680Sstevel@tonic-gate 			const char	*_name;
14690Sstevel@tonic-gate 			GElf_Word	sndx;
14700Sstevel@tonic-gate 			ulong_t		r_type;
14710Sstevel@tonic-gate 			GElf_Sym	_sym;
14720Sstevel@tonic-gate 			GElf_Rela	rela;
14730Sstevel@tonic-gate 
14740Sstevel@tonic-gate 			/*
14750Sstevel@tonic-gate 			 * Determine the symbol with which this relocation is
14760Sstevel@tonic-gate 			 * associated.  If the symbol represents a section
14770Sstevel@tonic-gate 			 * offset construct an appropriate string.
14780Sstevel@tonic-gate 			 */
14790Sstevel@tonic-gate 			if (type == SHT_RELA) {
14800Sstevel@tonic-gate 				(void) gelf_getrela(_cache->c_data, ndx,
14810Sstevel@tonic-gate 				    &rela);
14820Sstevel@tonic-gate 			} else {
14830Sstevel@tonic-gate 				(void) gelf_getrel(_cache->c_data, ndx,
14840Sstevel@tonic-gate 				    (GElf_Rel*)&rela);
14850Sstevel@tonic-gate 			}
14860Sstevel@tonic-gate 			/* LINTED */
14870Sstevel@tonic-gate 			sndx = (GElf_Word)GELF_R_SYM(rela.r_info);
14880Sstevel@tonic-gate 			r_type = GELF_R_TYPE(rela.r_info);
14890Sstevel@tonic-gate 
14900Sstevel@tonic-gate 			/* LINTED */
14910Sstevel@tonic-gate 			if (gelf_getsym(dsyms, (int)sndx, &_sym) == NULL) {
14920Sstevel@tonic-gate 				(void) fprintf(stderr,
14930Sstevel@tonic-gate 					MSG_INTL(MSG_ERR_RELBADSYMNDX),
14940Sstevel@tonic-gate 				    file, elf_errmsg(0));
14950Sstevel@tonic-gate 				(void) fflush(stderr);
14960Sstevel@tonic-gate 				_name = MSG_INTL(MSG_STR_UNKNOWN);
14970Sstevel@tonic-gate 			} else  {
14980Sstevel@tonic-gate 				if ((GELF_ST_TYPE(_sym.st_info) ==
14990Sstevel@tonic-gate 				    STT_SECTION) && (_sym.st_name == 0)) {
15000Sstevel@tonic-gate 					if (flags & FLG_LONGNAME)
15010Sstevel@tonic-gate 					    (void) snprintf(section, BUFSIZ,
15020Sstevel@tonic-gate 						MSG_INTL(MSG_STR_L_SECTION),
15030Sstevel@tonic-gate 						cache[_sym.st_shndx].c_name);
15040Sstevel@tonic-gate 					else
15050Sstevel@tonic-gate 					    (void) snprintf(section, BUFSIZ,
15060Sstevel@tonic-gate 						MSG_INTL(MSG_STR_SECTION),
15070Sstevel@tonic-gate 						cache[_sym.st_shndx].c_name);
15080Sstevel@tonic-gate 					_name = (const char *)section;
15090Sstevel@tonic-gate 				} else {
15100Sstevel@tonic-gate 					/* LINTED */
15110Sstevel@tonic-gate 					_name = string(_cache,
15120Sstevel@tonic-gate 					    sndx, &cache[shdr->sh_link],
15130Sstevel@tonic-gate 					    file, _sym.st_name);
15140Sstevel@tonic-gate 				}
15150Sstevel@tonic-gate 			}
15160Sstevel@tonic-gate 
15170Sstevel@tonic-gate 			if ((sndx == 0) && ((IAM_SPARC(ehdr->e_machine) &&
15180Sstevel@tonic-gate 			    ((r_type != R_SPARC_NONE) &&
15190Sstevel@tonic-gate 			    (r_type != R_SPARC_REGISTER) &&
15200Sstevel@tonic-gate 			    (r_type != R_SPARC_RELATIVE))) ||
15210Sstevel@tonic-gate 			    ((IAM_INTEL(ehdr->e_machine) &&
15220Sstevel@tonic-gate 			    ((r_type != R_386_NONE) &&
15230Sstevel@tonic-gate 			    (r_type != R_386_RELATIVE)))))) {
15240Sstevel@tonic-gate 				(void) fprintf(stderr,
15250Sstevel@tonic-gate 				    MSG_INTL(MSG_ERR_BADREL1), file,
15260Sstevel@tonic-gate 				    conv_reloc_type_str(ehdr->e_machine,
15270Sstevel@tonic-gate 				    /* LINTED */
15280Sstevel@tonic-gate 				    (uint_t)r_type));
15290Sstevel@tonic-gate 				(void) fflush(stderr);
15300Sstevel@tonic-gate 			}
15310Sstevel@tonic-gate 
15320Sstevel@tonic-gate 			Gelf_reloc_entry(MSG_ORIG(MSG_STR_EMPTY),
15330Sstevel@tonic-gate 			    ehdr->e_machine, type, (void *)&rela,
15340Sstevel@tonic-gate 			    _cache->c_name, _name);
15350Sstevel@tonic-gate 		}
15360Sstevel@tonic-gate 	}
15370Sstevel@tonic-gate }
15380Sstevel@tonic-gate 
15390Sstevel@tonic-gate /*
15400Sstevel@tonic-gate  * Search for and process a .dynamic section.
15410Sstevel@tonic-gate  */
15420Sstevel@tonic-gate static void
15430Sstevel@tonic-gate dynamic(Cache *cache, GElf_Word shnum, GElf_Ehdr *ehdr, const char *file)
15440Sstevel@tonic-gate {
15450Sstevel@tonic-gate 	GElf_Word	cnt;
15460Sstevel@tonic-gate 
15470Sstevel@tonic-gate 	for (cnt = 1; cnt < shnum; cnt++) {
15480Sstevel@tonic-gate 		GElf_Dyn	dyn;
15490Sstevel@tonic-gate 		ulong_t		numdyn;
15500Sstevel@tonic-gate 		int		ndx;
15510Sstevel@tonic-gate 		Cache *		_cache = &cache[cnt];
15520Sstevel@tonic-gate 		GElf_Shdr *	shdr = &_cache->c_shdr;
15530Sstevel@tonic-gate 
15540Sstevel@tonic-gate 		if (shdr->sh_type != SHT_DYNAMIC)
15550Sstevel@tonic-gate 			continue;
15560Sstevel@tonic-gate 
15570Sstevel@tonic-gate 		/*
15580Sstevel@tonic-gate 		 * Get the associated string table section.
15590Sstevel@tonic-gate 		 */
15600Sstevel@tonic-gate 		if ((shdr->sh_link == 0) || (shdr->sh_link >= shnum)) {
15610Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHLINK),
15620Sstevel@tonic-gate 			    file, _cache->c_name, EC_XWORD(shdr->sh_link));
15630Sstevel@tonic-gate 			(void) fflush(stderr);
15640Sstevel@tonic-gate 			continue;
15650Sstevel@tonic-gate 		}
15660Sstevel@tonic-gate 		numdyn = shdr->sh_size / shdr->sh_entsize;
15670Sstevel@tonic-gate 
15680Sstevel@tonic-gate 		dbg_print(MSG_ORIG(MSG_STR_EMPTY));
15690Sstevel@tonic-gate 		dbg_print(MSG_INTL(MSG_ELF_SCN_DYNAMIC), _cache->c_name);
15700Sstevel@tonic-gate 
15710Sstevel@tonic-gate 		Gelf_dyn_title();
15720Sstevel@tonic-gate 
15730Sstevel@tonic-gate 		/* LINTED */
15740Sstevel@tonic-gate 		for (ndx = 0; ndx < numdyn; ++ndx) {
15750Sstevel@tonic-gate 			const char	*name;
15760Sstevel@tonic-gate 
15770Sstevel@tonic-gate 			(void) gelf_getdyn(_cache->c_data, ndx, &dyn);
15780Sstevel@tonic-gate 			if (dyn.d_tag == DT_NULL)
15790Sstevel@tonic-gate 				break;
15800Sstevel@tonic-gate 
15810Sstevel@tonic-gate 			/*
15820Sstevel@tonic-gate 			 * Print the information numerically, and if possible
15830Sstevel@tonic-gate 			 * as a string.
15840Sstevel@tonic-gate 			 */
15850Sstevel@tonic-gate 			if ((dyn.d_tag == DT_NEEDED) ||
15860Sstevel@tonic-gate 			    (dyn.d_tag == DT_SONAME) ||
15870Sstevel@tonic-gate 			    (dyn.d_tag == DT_FILTER) ||
15880Sstevel@tonic-gate 			    (dyn.d_tag == DT_AUXILIARY) ||
15890Sstevel@tonic-gate 			    (dyn.d_tag == DT_CONFIG) ||
15900Sstevel@tonic-gate 			    (dyn.d_tag == DT_RPATH) ||
15910Sstevel@tonic-gate 			    (dyn.d_tag == DT_RUNPATH) ||
15920Sstevel@tonic-gate 			    (dyn.d_tag == DT_USED) ||
15930Sstevel@tonic-gate 			    (dyn.d_tag == DT_DEPAUDIT) ||
15940Sstevel@tonic-gate 			    (dyn.d_tag == DT_AUDIT) ||
15950Sstevel@tonic-gate 			    (dyn.d_tag == DT_SUNW_AUXILIARY) ||
15960Sstevel@tonic-gate 			    (dyn.d_tag == DT_SUNW_FILTER))
15970Sstevel@tonic-gate 				name = string(_cache, ndx,
15980Sstevel@tonic-gate 				    &cache[shdr->sh_link], file,
15990Sstevel@tonic-gate 				    dyn.d_un.d_ptr);
16000Sstevel@tonic-gate 			else if (dyn.d_tag == DT_FLAGS)
16010Sstevel@tonic-gate 			    /* LINTED */
16020Sstevel@tonic-gate 			    name = conv_dynflag_str((Word)dyn.d_un.d_val);
16030Sstevel@tonic-gate 			else if (dyn.d_tag == DT_FLAGS_1)
16040Sstevel@tonic-gate 			    /* LINTED */
16050Sstevel@tonic-gate 			    name = conv_dynflag_1_str((Word)dyn.d_un.d_val);
16060Sstevel@tonic-gate 			else if (dyn.d_tag == DT_POSFLAG_1)
16070Sstevel@tonic-gate 			    /* LINTED */
16080Sstevel@tonic-gate 			    name = conv_dynposflag_1_str((Word)dyn.d_un.d_val);
16090Sstevel@tonic-gate 			else if (dyn.d_tag == DT_FEATURE_1)
16100Sstevel@tonic-gate 			    /* LINTED */
16110Sstevel@tonic-gate 			    name = conv_dynfeature_1_str((Word)dyn.d_un.d_val);
16120Sstevel@tonic-gate 			else if (dyn.d_tag == DT_DEPRECATED_SPARC_REGISTER)
16130Sstevel@tonic-gate 			    name = MSG_INTL(MSG_STR_DEPRECATED);
16140Sstevel@tonic-gate 			else
16150Sstevel@tonic-gate 			    name = MSG_ORIG(MSG_STR_EMPTY);
16160Sstevel@tonic-gate 
16170Sstevel@tonic-gate 			Gelf_dyn_print(&dyn, ndx, name, ehdr->e_machine);
16180Sstevel@tonic-gate 		}
16190Sstevel@tonic-gate 	}
16200Sstevel@tonic-gate }
16210Sstevel@tonic-gate 
16220Sstevel@tonic-gate /*
16230Sstevel@tonic-gate  * Search for and process a MOVE section.
16240Sstevel@tonic-gate  */
16250Sstevel@tonic-gate static void
16260Sstevel@tonic-gate move(Cache *cache, GElf_Word shnum, const char *name, const char *file,
16270Sstevel@tonic-gate     uint32_t flags)
16280Sstevel@tonic-gate {
16290Sstevel@tonic-gate 	GElf_Word	cnt;
16300Sstevel@tonic-gate 
16310Sstevel@tonic-gate 	for (cnt = 1; cnt < shnum; cnt++) {
16320Sstevel@tonic-gate 		ulong_t		num, symn;
16330Sstevel@tonic-gate 		int		ndx;
16340Sstevel@tonic-gate 		Elf_Data	*dsyms;
16350Sstevel@tonic-gate 		const char	*fmt;
16360Sstevel@tonic-gate 		Cache		*_cache = &cache[cnt];
16370Sstevel@tonic-gate 		GElf_Shdr	*shdr = &_cache->c_shdr;
16380Sstevel@tonic-gate 		char		*sname;
16390Sstevel@tonic-gate 
16400Sstevel@tonic-gate 		if (shdr->sh_type != SHT_SUNW_move)
16410Sstevel@tonic-gate 			continue;
16420Sstevel@tonic-gate 		if (name && strcmp(name, _cache->c_name))
16430Sstevel@tonic-gate 			continue;
16440Sstevel@tonic-gate 
16450Sstevel@tonic-gate 		/*
16460Sstevel@tonic-gate 		 * Determine the move data and number.
16470Sstevel@tonic-gate 		 */
16480Sstevel@tonic-gate 		if ((shdr->sh_entsize == 0) || (shdr->sh_size == 0)) {
16490Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ),
16500Sstevel@tonic-gate 			    file, _cache->c_name);
16510Sstevel@tonic-gate 			(void) fflush(stderr);
16520Sstevel@tonic-gate 			continue;
16530Sstevel@tonic-gate 		}
16540Sstevel@tonic-gate 		num = shdr->sh_size / shdr->sh_entsize;
16550Sstevel@tonic-gate 
16560Sstevel@tonic-gate 		/*
16570Sstevel@tonic-gate 		 * Get the data buffer for the associated symbol table.
16580Sstevel@tonic-gate 		 */
16590Sstevel@tonic-gate 		if ((shdr->sh_link == 0) || (shdr->sh_link >= shnum)) {
16600Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHLINK),
16610Sstevel@tonic-gate 			    file, _cache->c_name, EC_XWORD(shdr->sh_link));
16620Sstevel@tonic-gate 			(void) fflush(stderr);
16630Sstevel@tonic-gate 			continue;
16640Sstevel@tonic-gate 		}
16650Sstevel@tonic-gate 		dsyms = cache[shdr->sh_link].c_data;
16660Sstevel@tonic-gate 		if (dsyms->d_buf == 0) {
16670Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ),
16680Sstevel@tonic-gate 			    file, cache[shdr->sh_link].c_name);
16690Sstevel@tonic-gate 			(void) fflush(stderr);
16700Sstevel@tonic-gate 			continue;
16710Sstevel@tonic-gate 		}
16720Sstevel@tonic-gate 
16730Sstevel@tonic-gate 		sname = cache[shdr->sh_link].c_name;
16740Sstevel@tonic-gate 		shdr = &cache[shdr->sh_link].c_shdr;
16750Sstevel@tonic-gate 
16760Sstevel@tonic-gate 		/*
16770Sstevel@tonic-gate 		 * Get the associated string table section.
16780Sstevel@tonic-gate 		 */
16790Sstevel@tonic-gate 		if ((shdr->sh_link == 0) || (shdr->sh_link >= shnum)) {
16800Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHLINK),
16810Sstevel@tonic-gate 			    file, sname, EC_XWORD(shdr->sh_link));
16820Sstevel@tonic-gate 			(void) fflush(stderr);
16830Sstevel@tonic-gate 			continue;
16840Sstevel@tonic-gate 		}
16850Sstevel@tonic-gate 		if ((shdr->sh_entsize == 0) || (shdr->sh_size == 0)) {
16860Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ),
16870Sstevel@tonic-gate 			    file, sname);
16880Sstevel@tonic-gate 			(void) fflush(stderr);
16890Sstevel@tonic-gate 			continue;
16900Sstevel@tonic-gate 		}
16910Sstevel@tonic-gate 		symn = shdr->sh_size / shdr->sh_entsize;
16920Sstevel@tonic-gate 
16930Sstevel@tonic-gate 		dbg_print(MSG_ORIG(MSG_STR_EMPTY));
16940Sstevel@tonic-gate 		dbg_print(MSG_INTL(MSG_MV_TITLE), _cache->c_name);
16950Sstevel@tonic-gate 
16960Sstevel@tonic-gate 		fmt = MSG_INTL(MSG_MV_ENTRY);
16970Sstevel@tonic-gate 
16980Sstevel@tonic-gate 		/* LINTED */
16990Sstevel@tonic-gate 		for (ndx = 0; ndx < num; ndx++) {
17000Sstevel@tonic-gate 			GElf_Move 	move;
17010Sstevel@tonic-gate 			const char	*name;
17020Sstevel@tonic-gate 			GElf_Sym	sym;
17030Sstevel@tonic-gate 			char		sct[BUFSIZ];
17040Sstevel@tonic-gate 			Word		shndx;
17050Sstevel@tonic-gate 
17060Sstevel@tonic-gate 			if (gelf_getmove(_cache->c_data, ndx, &move) == NULL) {
17070Sstevel@tonic-gate 				(void) fprintf(stderr,
17080Sstevel@tonic-gate 					MSG_INTL(MSG_ERR_BADMOVE),
17090Sstevel@tonic-gate 					file, _cache->c_name, elf_errmsg(0));
17100Sstevel@tonic-gate 				(void) fflush(stderr);
17110Sstevel@tonic-gate 				break;
17120Sstevel@tonic-gate 			}
17130Sstevel@tonic-gate 
17140Sstevel@tonic-gate 			/*
17150Sstevel@tonic-gate 			 * Check for null entries
17160Sstevel@tonic-gate 			 */
17170Sstevel@tonic-gate 			if ((move.m_info == 0) && (move.m_value == 0) &&
17180Sstevel@tonic-gate 			    (move.m_poffset == 0) && (move.m_repeat == 0) &&
17190Sstevel@tonic-gate 			    (move.m_stride == 0)) {
17200Sstevel@tonic-gate 				dbg_print(fmt, EC_XWORD(move.m_poffset),
17210Sstevel@tonic-gate 				    EC_XWORD(0), 0, 0, 0, EC_LWORD(0),
17220Sstevel@tonic-gate 				    MSG_ORIG(MSG_STR_EMPTY));
17230Sstevel@tonic-gate 				continue;
17240Sstevel@tonic-gate 			}
17250Sstevel@tonic-gate 			if ((GELF_M_SYM(move.m_info) == 0) ||
17260Sstevel@tonic-gate 			    (GELF_M_SYM(move.m_info) >= symn)) {
17270Sstevel@tonic-gate 				(void) fprintf(stderr,
17280Sstevel@tonic-gate 				    MSG_INTL(MSG_ERR_BADMINFO), file,
17290Sstevel@tonic-gate 				    _cache->c_name, EC_XWORD(move.m_info));
17300Sstevel@tonic-gate 				(void) fflush(stderr);
17310Sstevel@tonic-gate 				dbg_print(fmt, EC_XWORD(move.m_poffset),
17320Sstevel@tonic-gate 				    EC_XWORD(GELF_M_SYM(move.m_info)),
17330Sstevel@tonic-gate 				    /* LINTED */
17340Sstevel@tonic-gate 				    GELF_M_SIZE(move.m_info), move.m_repeat,
17350Sstevel@tonic-gate 				    move.m_stride, EC_LWORD(move.m_value),
17360Sstevel@tonic-gate 				    MSG_INTL(MSG_STR_UNKNOWN));
17370Sstevel@tonic-gate 				continue;
17380Sstevel@tonic-gate 			}
17390Sstevel@tonic-gate 
17400Sstevel@tonic-gate 			if (gelf_getsym(dsyms,
17410Sstevel@tonic-gate 			    /* LINTED */
17420Sstevel@tonic-gate 			    (int)GELF_M_SYM(move.m_info), &sym) == NULL) {
17430Sstevel@tonic-gate 				(void) fprintf(stderr,
17440Sstevel@tonic-gate 					MSG_INTL(MSG_ERR_MVBADSYMNDX),
17450Sstevel@tonic-gate 				    file, elf_errmsg(0));
17460Sstevel@tonic-gate 				(void) fflush(stderr);
17470Sstevel@tonic-gate 				name = MSG_INTL(MSG_STR_UNKNOWN);
17480Sstevel@tonic-gate 			} else {
17490Sstevel@tonic-gate 				if ((GELF_ST_TYPE(sym.st_info) ==
17500Sstevel@tonic-gate 				    STT_SECTION) && (sym.st_name == 0)) {
17510Sstevel@tonic-gate 				    if (flags & FLG_LONGNAME)
17520Sstevel@tonic-gate 					(void) snprintf(sct, BUFSIZ,
17530Sstevel@tonic-gate 					    MSG_INTL(MSG_STR_L_SECTION),
17540Sstevel@tonic-gate 					    cache[sym.st_shndx].c_name);
17550Sstevel@tonic-gate 				    else
17560Sstevel@tonic-gate 					(void) snprintf(sct, BUFSIZ,
17570Sstevel@tonic-gate 					    MSG_INTL(MSG_STR_SECTION),
17580Sstevel@tonic-gate 					    cache[sym.st_shndx].c_name);
17590Sstevel@tonic-gate 					name = (const char *)sct;
17600Sstevel@tonic-gate 				} else {
17610Sstevel@tonic-gate 					name = demangle(string(_cache,
17620Sstevel@tonic-gate 					    /* LINTED */
17630Sstevel@tonic-gate 					    (GElf_Word)GELF_M_SYM(move.m_info),
17640Sstevel@tonic-gate 					    &cache[shdr->sh_link], file,
17650Sstevel@tonic-gate 					    sym.st_name), flags);
17660Sstevel@tonic-gate 				}
17670Sstevel@tonic-gate 			}
17680Sstevel@tonic-gate 
17690Sstevel@tonic-gate 			/*
17700Sstevel@tonic-gate 			 * Additional sanity check.
17710Sstevel@tonic-gate 			 */
17720Sstevel@tonic-gate 			shndx = sym.st_shndx;
17730Sstevel@tonic-gate 			if (!((shndx == SHN_COMMON) ||
17740Sstevel@tonic-gate 			    (((shndx >= 1) && (shndx <= shnum)) &&
17750Sstevel@tonic-gate 			    (cache[shndx].c_shdr).sh_type == SHT_NOBITS))) {
17760Sstevel@tonic-gate 				(void) fprintf(stderr,
17770Sstevel@tonic-gate 					MSG_INTL(MSG_ERR_BADSYM2), file,
17780Sstevel@tonic-gate 					_cache->c_name, name);
17790Sstevel@tonic-gate 				(void) fflush(stderr);
17800Sstevel@tonic-gate 			}
17810Sstevel@tonic-gate 
17820Sstevel@tonic-gate 			dbg_print(fmt, EC_XWORD(move.m_poffset),
17830Sstevel@tonic-gate 			    EC_XWORD(GELF_M_SYM(move.m_info)),
17840Sstevel@tonic-gate 			    /* LINTED */
17850Sstevel@tonic-gate 			    GELF_M_SIZE(move.m_info), move.m_repeat,
17860Sstevel@tonic-gate 			    move.m_stride, EC_LWORD(move.m_value), name);
17870Sstevel@tonic-gate 		}
17880Sstevel@tonic-gate 	}
17890Sstevel@tonic-gate }
17900Sstevel@tonic-gate 
17910Sstevel@tonic-gate /*
17920Sstevel@tonic-gate  * Traverse a note section analyzing each note information block.
17930Sstevel@tonic-gate  * The data buffers size is used to validate references before they are made,
17940Sstevel@tonic-gate  * and is decremented as each element is processed.
17950Sstevel@tonic-gate  */
17960Sstevel@tonic-gate void
17970Sstevel@tonic-gate note_entry(Cache *cache, Word *data, Word size, const char *file)
17980Sstevel@tonic-gate {
17990Sstevel@tonic-gate 	Word	bsize = size;
18000Sstevel@tonic-gate 	/*
18010Sstevel@tonic-gate 	 * Print out a single `note' information block.
18020Sstevel@tonic-gate 	 */
18030Sstevel@tonic-gate 	while (size > 0) {
18040Sstevel@tonic-gate 		Word	namesz, descsz, type, pad, noteoff;
18050Sstevel@tonic-gate 
18060Sstevel@tonic-gate 
18070Sstevel@tonic-gate 		noteoff = bsize - size;
18080Sstevel@tonic-gate 		/*
18090Sstevel@tonic-gate 		 * Make sure we can at least reference the 3 initial entries
18100Sstevel@tonic-gate 		 * (4-byte words) of the note information block.
18110Sstevel@tonic-gate 		 */
18120Sstevel@tonic-gate 		if (size >= (Word)(sizeof (Word) * 3))
18130Sstevel@tonic-gate 			size -= (Word)(sizeof (Word) * 3);
18140Sstevel@tonic-gate 		else {
18150Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_INTL(MSG_NOTE_BADDATASIZE),
18160Sstevel@tonic-gate 				file, cache->c_name, EC_WORD(noteoff));
18170Sstevel@tonic-gate 			(void) fflush(stderr);
18180Sstevel@tonic-gate 			return;
18190Sstevel@tonic-gate 		}
18200Sstevel@tonic-gate 
18210Sstevel@tonic-gate 		/*
18220Sstevel@tonic-gate 		 * Make sure any specified name string can be referenced.
18230Sstevel@tonic-gate 		 */
18240Sstevel@tonic-gate 		if ((namesz = *data++) != 0) {
18250Sstevel@tonic-gate 			if (size >= namesz)
18260Sstevel@tonic-gate 				size -= namesz;
18270Sstevel@tonic-gate 			else {
18280Sstevel@tonic-gate 				(void) fprintf(stderr,
18290Sstevel@tonic-gate 					MSG_INTL(MSG_NOTE_BADNMSIZE),
18300Sstevel@tonic-gate 					file, cache->c_name, EC_WORD(noteoff),
18310Sstevel@tonic-gate 					EC_WORD(namesz));
18320Sstevel@tonic-gate 				(void) fflush(stderr);
18330Sstevel@tonic-gate 				return;
18340Sstevel@tonic-gate 			}
18350Sstevel@tonic-gate 		}
18360Sstevel@tonic-gate 		/*
18370Sstevel@tonic-gate 		 * Make sure any specified descriptor can be referenced.
18380Sstevel@tonic-gate 		 */
18390Sstevel@tonic-gate 		if ((descsz = *data++) != 0) {
18400Sstevel@tonic-gate 			/*
18410Sstevel@tonic-gate 			 * If namesz isn't a 4-byte multiple, account for any
18420Sstevel@tonic-gate 			 * padding that must exist before the descriptor.
18430Sstevel@tonic-gate 			 */
18440Sstevel@tonic-gate 			if ((pad = (namesz & (Word)(sizeof (Word) - 1))) != 0) {
18450Sstevel@tonic-gate 				pad = (Word)sizeof (Word) - pad;
18460Sstevel@tonic-gate 				size -= pad;
18470Sstevel@tonic-gate 			}
18480Sstevel@tonic-gate 			if (size >= descsz)
18490Sstevel@tonic-gate 				size -= descsz;
18500Sstevel@tonic-gate 			else {
18510Sstevel@tonic-gate 				(void) fprintf(stderr,
18520Sstevel@tonic-gate 					MSG_INTL(MSG_NOTE_BADDESIZE),
18530Sstevel@tonic-gate 					file, cache->c_name, EC_WORD(noteoff),
18540Sstevel@tonic-gate 					EC_WORD(namesz));
18550Sstevel@tonic-gate 				(void) fflush(stderr);
18560Sstevel@tonic-gate 				return;
18570Sstevel@tonic-gate 			}
18580Sstevel@tonic-gate 		}
18590Sstevel@tonic-gate 
18600Sstevel@tonic-gate 		type = *data++;
18610Sstevel@tonic-gate 
18620Sstevel@tonic-gate 		dbg_print(MSG_ORIG(MSG_STR_EMPTY));
18630Sstevel@tonic-gate 		dbg_print(MSG_ORIG(MSG_NOTE_TYPE), EC_WORD(type));
18640Sstevel@tonic-gate 
18650Sstevel@tonic-gate 		dbg_print(MSG_ORIG(MSG_NOTE_NAMESZ), EC_WORD(namesz));
18660Sstevel@tonic-gate 		if (namesz) {
18670Sstevel@tonic-gate 			char	*name = (char *)data;
18680Sstevel@tonic-gate 
18690Sstevel@tonic-gate 			/*
18700Sstevel@tonic-gate 			 * Since the name string may have 'null' bytes
18710Sstevel@tonic-gate 			 * in it (ia32 .string) - we just write the
18720Sstevel@tonic-gate 			 * whole stream in a single fwrite.
18730Sstevel@tonic-gate 			 */
18740Sstevel@tonic-gate 			(void) fwrite(name, namesz, 1, stdout);
18750Sstevel@tonic-gate 			name = name + ((namesz + (sizeof (Word) - 1)) &
18760Sstevel@tonic-gate 			    ~(sizeof (Word) - 1));
18770Sstevel@tonic-gate 			/* LINTED */
18780Sstevel@tonic-gate 			data = (Word *)name;
18790Sstevel@tonic-gate 			dbg_print(MSG_ORIG(MSG_STR_EMPTY));
18800Sstevel@tonic-gate 		}
18810Sstevel@tonic-gate 
18820Sstevel@tonic-gate 		/*
18830Sstevel@tonic-gate 		 * If multiple information blocks exist within a .note section
18840Sstevel@tonic-gate 		 * account for any padding that must exist before the next
18850Sstevel@tonic-gate 		 * information block.
18860Sstevel@tonic-gate 		 */
18870Sstevel@tonic-gate 		if ((pad = (descsz & (Word)(sizeof (Word) - 1))) != 0) {
18880Sstevel@tonic-gate 			pad = (Word)sizeof (Word) - pad;
18890Sstevel@tonic-gate 			if (size > pad)
18900Sstevel@tonic-gate 				size -= pad;
18910Sstevel@tonic-gate 		}
18920Sstevel@tonic-gate 
18930Sstevel@tonic-gate 		dbg_print(MSG_ORIG(MSG_NOTE_DESCSZ), EC_WORD(descsz));
18940Sstevel@tonic-gate 		if (descsz) {
18950Sstevel@tonic-gate 			int		ndx, byte, word;
18960Sstevel@tonic-gate 			char		string[58], * str = string;
18970Sstevel@tonic-gate 			uchar_t		*desc = (uchar_t *)data;
18980Sstevel@tonic-gate 
18990Sstevel@tonic-gate 			/*
19000Sstevel@tonic-gate 			 * Dump descriptor bytes.
19010Sstevel@tonic-gate 			 */
19020Sstevel@tonic-gate 			for (ndx = byte = word = 0; descsz; descsz--, desc++) {
19030Sstevel@tonic-gate 				int	tok = *desc;
19040Sstevel@tonic-gate 
19050Sstevel@tonic-gate 				(void) snprintf(str, 58, MSG_ORIG(MSG_NOTE_TOK),
19060Sstevel@tonic-gate 				    tok);
19070Sstevel@tonic-gate 				str += 3;
19080Sstevel@tonic-gate 
19090Sstevel@tonic-gate 				if (++byte == 4) {
19100Sstevel@tonic-gate 					*str++ = ' ', *str++ = ' ';
19110Sstevel@tonic-gate 					word++;
19120Sstevel@tonic-gate 					byte = 0;
19130Sstevel@tonic-gate 				}
19140Sstevel@tonic-gate 				if (word == 4) {
19150Sstevel@tonic-gate 					*str = '\0';
19160Sstevel@tonic-gate 					dbg_print(MSG_ORIG(MSG_NOTE_DESC),
19170Sstevel@tonic-gate 					    ndx, string);
19180Sstevel@tonic-gate 					word = 0;
19190Sstevel@tonic-gate 					ndx += 16;
19200Sstevel@tonic-gate 					str = string;
19210Sstevel@tonic-gate 				}
19220Sstevel@tonic-gate 			}
19230Sstevel@tonic-gate 			if (byte || word) {
19240Sstevel@tonic-gate 				*str = '\0';
19250Sstevel@tonic-gate 				dbg_print(MSG_ORIG(MSG_NOTE_DESC), ndx, string);
19260Sstevel@tonic-gate 			}
19270Sstevel@tonic-gate 
19280Sstevel@tonic-gate 			desc += pad;
19290Sstevel@tonic-gate 			/* LINTED */
19300Sstevel@tonic-gate 			data = (Word *)desc;
19310Sstevel@tonic-gate 		}
19320Sstevel@tonic-gate 	}
19330Sstevel@tonic-gate }
19340Sstevel@tonic-gate 
19350Sstevel@tonic-gate /*
19360Sstevel@tonic-gate  * Search for and process a .note section.
19370Sstevel@tonic-gate  */
19380Sstevel@tonic-gate static void
19390Sstevel@tonic-gate note(Cache *cache, GElf_Word shnum, const char *name, const char *file)
19400Sstevel@tonic-gate {
19410Sstevel@tonic-gate 	GElf_Word	cnt;
19420Sstevel@tonic-gate 
19430Sstevel@tonic-gate 	/*
19440Sstevel@tonic-gate 	 * Otherwise look for any .note sections.
19450Sstevel@tonic-gate 	 */
19460Sstevel@tonic-gate 	for (cnt = 1; cnt < shnum; cnt++) {
19470Sstevel@tonic-gate 		Cache *		_cache = &cache[cnt];
19480Sstevel@tonic-gate 		GElf_Shdr *	shdr = &_cache->c_shdr;
19490Sstevel@tonic-gate 
19500Sstevel@tonic-gate 		if (shdr->sh_type != SHT_NOTE)
19510Sstevel@tonic-gate 			continue;
19520Sstevel@tonic-gate 		if (name && strcmp(name, _cache->c_name))
19530Sstevel@tonic-gate 			continue;
19540Sstevel@tonic-gate 
19550Sstevel@tonic-gate 		/*
19560Sstevel@tonic-gate 		 * As these sections are often hand rolled, make sure they're
19570Sstevel@tonic-gate 		 * properly aligned before proceeding.
19580Sstevel@tonic-gate 		 */
19590Sstevel@tonic-gate 		if (shdr->sh_offset & (sizeof (Word) - 1)) {
19600Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADALIGN),
19610Sstevel@tonic-gate 			    file, _cache->c_name);
19620Sstevel@tonic-gate 			(void) fflush(stderr);
19630Sstevel@tonic-gate 			continue;
19640Sstevel@tonic-gate 		}
19650Sstevel@tonic-gate 
19660Sstevel@tonic-gate 		dbg_print(MSG_ORIG(MSG_STR_EMPTY));
19670Sstevel@tonic-gate 		dbg_print(MSG_INTL(MSG_ELF_SCN_NOTE), _cache->c_name);
19680Sstevel@tonic-gate 		note_entry(_cache, (Word *)_cache->c_data->d_buf,
19690Sstevel@tonic-gate 		/* LINTED */
19700Sstevel@tonic-gate 		    (Word)_cache->c_data->d_size, file);
19710Sstevel@tonic-gate 	}
19720Sstevel@tonic-gate }
19730Sstevel@tonic-gate 
19740Sstevel@tonic-gate 
19750Sstevel@tonic-gate #define	MAXCOUNT	500
19760Sstevel@tonic-gate 
19770Sstevel@tonic-gate static void
19780Sstevel@tonic-gate hash(Cache *cache, GElf_Word shnum, const char *name, const char *file,
19790Sstevel@tonic-gate     uint32_t flags)
19800Sstevel@tonic-gate {
19810Sstevel@tonic-gate 	static int	count[MAXCOUNT];
19820Sstevel@tonic-gate 	GElf_Word	cnt;
19830Sstevel@tonic-gate 	ulong_t		ndx, bkts;
19840Sstevel@tonic-gate 	char		number[MAXNDXSIZE];
19850Sstevel@tonic-gate 
19860Sstevel@tonic-gate 	for (cnt = 1; cnt < shnum; cnt++) {
19870Sstevel@tonic-gate 		uint_t		*hash, *chain;
19880Sstevel@tonic-gate 		Elf_Data	*dsyms;
19890Sstevel@tonic-gate 		Cache		*_cache = &cache[cnt];
19900Sstevel@tonic-gate 		GElf_Shdr	*shdr = &_cache->c_shdr;
19910Sstevel@tonic-gate 		char		*sname;
19920Sstevel@tonic-gate 
19930Sstevel@tonic-gate 		if (shdr->sh_type != SHT_HASH)
19940Sstevel@tonic-gate 			continue;
19950Sstevel@tonic-gate 		if (name && strcmp(name, _cache->c_name))
19960Sstevel@tonic-gate 			continue;
19970Sstevel@tonic-gate 
19980Sstevel@tonic-gate 		/*
19990Sstevel@tonic-gate 		 * Determine the hash table data and size.
20000Sstevel@tonic-gate 		 */
20010Sstevel@tonic-gate 		if ((shdr->sh_entsize == 0) || (shdr->sh_size == 0)) {
20020Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ),
20030Sstevel@tonic-gate 			    file, _cache->c_name);
20040Sstevel@tonic-gate 			(void) fflush(stderr);
20050Sstevel@tonic-gate 			continue;
20060Sstevel@tonic-gate 		}
20070Sstevel@tonic-gate 		hash = (uint_t *)_cache->c_data->d_buf;
20080Sstevel@tonic-gate 		bkts = *hash;
20090Sstevel@tonic-gate 		chain = hash + 2 + bkts;
20100Sstevel@tonic-gate 		hash += 2;
20110Sstevel@tonic-gate 
20120Sstevel@tonic-gate 		/*
20130Sstevel@tonic-gate 		 * Get the data buffer for the associated symbol table.
20140Sstevel@tonic-gate 		 */
20150Sstevel@tonic-gate 		if ((shdr->sh_link == 0) || (shdr->sh_link >= shnum)) {
20160Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHLINK),
20170Sstevel@tonic-gate 			    file, _cache->c_name, EC_XWORD(shdr->sh_link));
20180Sstevel@tonic-gate 			(void) fflush(stderr);
20190Sstevel@tonic-gate 			continue;
20200Sstevel@tonic-gate 		}
20210Sstevel@tonic-gate 		dsyms = cache[shdr->sh_link].c_data;
20220Sstevel@tonic-gate 		if (dsyms->d_buf == 0) {
20230Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ),
20240Sstevel@tonic-gate 			    file, cache[shdr->sh_link].c_name);
20250Sstevel@tonic-gate 			(void) fflush(stderr);
20260Sstevel@tonic-gate 			continue;
20270Sstevel@tonic-gate 		}
20280Sstevel@tonic-gate 
20290Sstevel@tonic-gate 		sname = cache[shdr->sh_link].c_name;
20300Sstevel@tonic-gate 		shdr = &cache[shdr->sh_link].c_shdr;
20310Sstevel@tonic-gate 		/*
20320Sstevel@tonic-gate 		 * Get the associated string table section.
20330Sstevel@tonic-gate 		 */
20340Sstevel@tonic-gate 		if ((shdr->sh_link == 0) || (shdr->sh_link >= shnum)) {
20350Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHLINK),
20360Sstevel@tonic-gate 			    file, sname, EC_XWORD(shdr->sh_link));
20370Sstevel@tonic-gate 			(void) fflush(stderr);
20380Sstevel@tonic-gate 			continue;
20390Sstevel@tonic-gate 		}
20400Sstevel@tonic-gate 
20410Sstevel@tonic-gate 		dbg_print(MSG_ORIG(MSG_STR_EMPTY));
20420Sstevel@tonic-gate 		dbg_print(MSG_INTL(MSG_ELF_SCN_HASH), _cache->c_name);
20430Sstevel@tonic-gate 		dbg_print(MSG_INTL(MSG_ELF_HASH_INFO));
20440Sstevel@tonic-gate 
20450Sstevel@tonic-gate 		/*
20460Sstevel@tonic-gate 		 * Loop through the hash buckets, printing the appropriate
20470Sstevel@tonic-gate 		 * symbols.
20480Sstevel@tonic-gate 		 */
20490Sstevel@tonic-gate 		for (ndx = 0; ndx < bkts; ndx++, hash++) {
20500Sstevel@tonic-gate 			GElf_Sym	_sym;
20510Sstevel@tonic-gate 			const char	*_str;
20520Sstevel@tonic-gate 			GElf_Word	_ndx, _cnt;
20530Sstevel@tonic-gate 			char		_number[MAXNDXSIZE];
20540Sstevel@tonic-gate 			ulong_t		nbkt, nhash;
20550Sstevel@tonic-gate 
20560Sstevel@tonic-gate 			if (*hash == 0) {
20570Sstevel@tonic-gate 				count[0]++;
20580Sstevel@tonic-gate 				continue;
20590Sstevel@tonic-gate 			}
20600Sstevel@tonic-gate 
20610Sstevel@tonic-gate 			/* LINTED */
20620Sstevel@tonic-gate 			if (gelf_getsym(dsyms, (int)*hash, &_sym) == NULL) {
20630Sstevel@tonic-gate 				(void) fprintf(stderr,
20640Sstevel@tonic-gate 					MSG_INTL(MSG_ERR_HSBADSYMNDX),
20650Sstevel@tonic-gate 				    file, elf_errmsg(0));
20660Sstevel@tonic-gate 				(void) fflush(stderr);
20670Sstevel@tonic-gate 				_str = MSG_INTL(MSG_STR_UNKNOWN);
20680Sstevel@tonic-gate 			} else {
20690Sstevel@tonic-gate 				_str = string(_cache, (GElf_Word)*hash,
20700Sstevel@tonic-gate 				    &cache[shdr->sh_link], file,
20710Sstevel@tonic-gate 				    _sym.st_name);
20720Sstevel@tonic-gate 			}
20730Sstevel@tonic-gate 
20740Sstevel@tonic-gate 			(void) snprintf(number, MAXNDXSIZE,
20750Sstevel@tonic-gate 			    /* LINTED */
20760Sstevel@tonic-gate 			    MSG_ORIG(MSG_FMT_INTEGER), (int)ndx);
20770Sstevel@tonic-gate 			(void) snprintf(_number, MAXNDXSIZE,
20780Sstevel@tonic-gate 			    MSG_ORIG(MSG_FMT_INDEX2), EC_XWORD(*hash));
20790Sstevel@tonic-gate 			dbg_print(MSG_ORIG(MSG_FMT_HASH_INFO), number, _number,
20800Sstevel@tonic-gate 			    demangle(_str, flags));
20810Sstevel@tonic-gate 
20820Sstevel@tonic-gate 			/*
20830Sstevel@tonic-gate 			 * Determine if this string is in the correct bucket.
20840Sstevel@tonic-gate 			 */
20850Sstevel@tonic-gate 			nhash = elf_hash(_str);
20860Sstevel@tonic-gate 			nbkt = nhash % bkts;
20870Sstevel@tonic-gate 			if (nbkt != ndx) {
20880Sstevel@tonic-gate 				(void) fprintf(stderr,
20890Sstevel@tonic-gate 				    MSG_INTL(MSG_ERR_BADHASH), file,
20900Sstevel@tonic-gate 				    /* LINTED */
20910Sstevel@tonic-gate 				    _cache->c_name, _str, (int)ndx, (int)nbkt);
20920Sstevel@tonic-gate 				(void) fflush(stderr);
20930Sstevel@tonic-gate 			}
20940Sstevel@tonic-gate 
20950Sstevel@tonic-gate 			/*
20960Sstevel@tonic-gate 			 * Determine if any other symbols are chained to this
20970Sstevel@tonic-gate 			 * bucket.
20980Sstevel@tonic-gate 			 */
20990Sstevel@tonic-gate 			_ndx = chain[*hash];
21000Sstevel@tonic-gate 			_cnt = 1;
21010Sstevel@tonic-gate 			while (_ndx) {
21020Sstevel@tonic-gate 				/* LINTED */
21030Sstevel@tonic-gate 				if (gelf_getsym(dsyms, (int)_ndx,
21040Sstevel@tonic-gate 				    &_sym) == NULL) {
21050Sstevel@tonic-gate 					(void) fprintf(stderr,
21060Sstevel@tonic-gate 						MSG_INTL(MSG_ERR_HSBADSYMNDX),
21070Sstevel@tonic-gate 					    file, elf_errmsg(0));
21080Sstevel@tonic-gate 					(void) fflush(stderr);
21090Sstevel@tonic-gate 					_str = MSG_INTL(MSG_STR_UNKNOWN);
21100Sstevel@tonic-gate 				} else
21110Sstevel@tonic-gate 					_str = string(_cache, _ndx,
21120Sstevel@tonic-gate 						&cache[shdr->sh_link], file,
21130Sstevel@tonic-gate 						_sym.st_name);
21140Sstevel@tonic-gate 
21150Sstevel@tonic-gate 				(void) snprintf(_number, MAXNDXSIZE,
21160Sstevel@tonic-gate 				    MSG_ORIG(MSG_FMT_INDEX2), EC_XWORD(_ndx));
21170Sstevel@tonic-gate 				dbg_print(MSG_ORIG(MSG_FMT_HASH_INFO),
21180Sstevel@tonic-gate 				    MSG_ORIG(MSG_STR_EMPTY), _number,
21190Sstevel@tonic-gate 				    demangle(_str, flags));
21200Sstevel@tonic-gate 				_ndx = chain[_ndx];
21210Sstevel@tonic-gate 				_cnt++;
21220Sstevel@tonic-gate 
21230Sstevel@tonic-gate 				/*
21240Sstevel@tonic-gate 				 * Determine if this string is in the correct
21250Sstevel@tonic-gate 				 * bucket.
21260Sstevel@tonic-gate 				 */
21270Sstevel@tonic-gate 				nhash = elf_hash(_str);
21280Sstevel@tonic-gate 				nbkt = nhash % bkts;
21290Sstevel@tonic-gate 				if (nbkt != ndx) {
21300Sstevel@tonic-gate 					(void) fprintf(stderr,
21310Sstevel@tonic-gate 					    MSG_INTL(MSG_ERR_BADHASH), file,
21320Sstevel@tonic-gate 					    _cache->c_name, _str,
21330Sstevel@tonic-gate 					    /* LINTED */
21340Sstevel@tonic-gate 					    (int)ndx, (int)nbkt);
21350Sstevel@tonic-gate 					(void) fflush(stderr);
21360Sstevel@tonic-gate 				}
21370Sstevel@tonic-gate 			}
21380Sstevel@tonic-gate 
21390Sstevel@tonic-gate 			if (_cnt >= MAXCOUNT) {
21400Sstevel@tonic-gate 				(void) fprintf(stderr,
21410Sstevel@tonic-gate 				    MSG_INTL(MSG_HASH_OVERFLW),
21420Sstevel@tonic-gate 				    /* LINTED */
21430Sstevel@tonic-gate 				    (int)ndx, _cnt);
21440Sstevel@tonic-gate 				(void) fflush(stderr);
21450Sstevel@tonic-gate 			} else
21460Sstevel@tonic-gate 				count[_cnt]++;
21470Sstevel@tonic-gate 		}
21480Sstevel@tonic-gate 		break;
21490Sstevel@tonic-gate 	}
21500Sstevel@tonic-gate 
21510Sstevel@tonic-gate 	/*
21520Sstevel@tonic-gate 	 * Print out the count information.
21530Sstevel@tonic-gate 	 */
21540Sstevel@tonic-gate 	bkts = cnt = 0;
21550Sstevel@tonic-gate 	dbg_print(MSG_ORIG(MSG_STR_EMPTY));
21560Sstevel@tonic-gate 	for (ndx = 0; ndx < MAXCOUNT; ndx++) {
21570Sstevel@tonic-gate 		GElf_Word	_cnt;
21580Sstevel@tonic-gate 
21590Sstevel@tonic-gate 		if ((_cnt = count[ndx]) == 0)
21600Sstevel@tonic-gate 			continue;
21610Sstevel@tonic-gate 
21620Sstevel@tonic-gate 		(void) snprintf(number, MAXNDXSIZE, MSG_ORIG(MSG_FMT_INTEGER),
21630Sstevel@tonic-gate 		    /* LINTED */
21640Sstevel@tonic-gate 		    (int)_cnt);
21650Sstevel@tonic-gate 		/* LINTED */
21660Sstevel@tonic-gate 		dbg_print(MSG_INTL(MSG_ELF_HASH_BKTS1), number, (int)ndx);
21670Sstevel@tonic-gate 		bkts += _cnt;
21680Sstevel@tonic-gate 		/* LINTED */
21690Sstevel@tonic-gate 		cnt += (GElf_Word)(ndx * _cnt);
21700Sstevel@tonic-gate 	}
21710Sstevel@tonic-gate 	if (cnt) {
21720Sstevel@tonic-gate 		(void) snprintf(number, MAXNDXSIZE, MSG_ORIG(MSG_FMT_INTEGER),
21730Sstevel@tonic-gate 		    /* LINTED */
21740Sstevel@tonic-gate 		    (int)bkts);
21750Sstevel@tonic-gate 		/* LINTED */
21760Sstevel@tonic-gate 		dbg_print(MSG_INTL(MSG_ELF_HASH_BKTS2), number, (int)cnt);
21770Sstevel@tonic-gate 	}
21780Sstevel@tonic-gate }
21790Sstevel@tonic-gate 
21800Sstevel@tonic-gate 
21810Sstevel@tonic-gate static void
21820Sstevel@tonic-gate group(Cache *cache, GElf_Word shnum, const char *name, const char *file,
21830Sstevel@tonic-gate     uint32_t flags)
21840Sstevel@tonic-gate {
21850Sstevel@tonic-gate 	GElf_Word	cnt;
21860Sstevel@tonic-gate 
21870Sstevel@tonic-gate 	for (cnt = 1; cnt < shnum; cnt++) {
21880Sstevel@tonic-gate 		Cache		*_cache = &cache[cnt];
21890Sstevel@tonic-gate 		GElf_Shdr	*shdr = &_cache->c_shdr;
21900Sstevel@tonic-gate 		Elf_Data	*dsyms;
21910Sstevel@tonic-gate 		GElf_Shdr	*symshdr;
21920Sstevel@tonic-gate 		GElf_Sym	sym;
21930Sstevel@tonic-gate 		const char	*symname;
21940Sstevel@tonic-gate 		char		flgstrbuf[MSG_GRP_COMDAT_SIZE + 10];
21950Sstevel@tonic-gate 		Word		*grpdata;
21960Sstevel@tonic-gate 		size_t		_cnt;
21970Sstevel@tonic-gate 		size_t		grpcnt;
21980Sstevel@tonic-gate 
21990Sstevel@tonic-gate 
22000Sstevel@tonic-gate 		if (shdr->sh_type != SHT_GROUP)
22010Sstevel@tonic-gate 			continue;
22020Sstevel@tonic-gate 		if (name && strcmp(name, _cache->c_name))
22030Sstevel@tonic-gate 			continue;
22040Sstevel@tonic-gate 		dbg_print(MSG_INTL(MSG_GRP_LINE1), _cache->c_name);
22050Sstevel@tonic-gate 		if ((shdr->sh_link == 0) || (shdr->sh_link >= shnum)) {
22060Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHLINK),
22070Sstevel@tonic-gate 				file, _cache->c_name, EC_XWORD(shdr->sh_link));
22080Sstevel@tonic-gate 			(void) fflush(stderr);
22090Sstevel@tonic-gate 			continue;
22100Sstevel@tonic-gate 		}
22110Sstevel@tonic-gate 
22120Sstevel@tonic-gate 		if (shdr->sh_entsize != sizeof (Word)) {
22130Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_INTL(MSG_GRP_BADENTSZ),
22140Sstevel@tonic-gate 				file, _cache->c_name,
22150Sstevel@tonic-gate 				EC_XWORD(shdr->sh_entsize));
22160Sstevel@tonic-gate 			(void) fflush(stderr);
22170Sstevel@tonic-gate 		}
22180Sstevel@tonic-gate 		symshdr = &(cache[shdr->sh_link].c_shdr);
22190Sstevel@tonic-gate 		if ((symshdr->sh_type != SHT_SYMTAB) &&
22200Sstevel@tonic-gate 		    (symshdr->sh_type != SHT_DYNSYM)) {
22210Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_INTL(MSG_GRP_NOTSYMTAB),
22220Sstevel@tonic-gate 				file, _cache->c_name, EC_XWORD(shdr->sh_link));
22230Sstevel@tonic-gate 			(void) fflush(stderr);
22240Sstevel@tonic-gate 			continue;
22250Sstevel@tonic-gate 		}
22260Sstevel@tonic-gate 		dsyms = cache[shdr->sh_link].c_data;
22270Sstevel@tonic-gate 		if ((shdr->sh_info == SHN_UNDEF) || ((ulong_t)shdr->sh_info >
22280Sstevel@tonic-gate 		    (symshdr->sh_size / symshdr->sh_entsize))) {
22290Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_INTL(MSG_GRP_BADSYMNDX),
22300Sstevel@tonic-gate 				file, _cache->c_name, EC_XWORD(shdr->sh_info));
22310Sstevel@tonic-gate 			(void) fflush(stderr);
22320Sstevel@tonic-gate 			continue;
22330Sstevel@tonic-gate 		}
22340Sstevel@tonic-gate 		flgstrbuf[0] = '[';
22350Sstevel@tonic-gate 		flgstrbuf[1] = '\0';
22360Sstevel@tonic-gate 		if ((shdr->sh_size != 0) &&
22370Sstevel@tonic-gate 		    (_cache->c_data) &&
22380Sstevel@tonic-gate 		    ((grpdata = (Word *)_cache->c_data->d_buf) != 0)) {
22390Sstevel@tonic-gate 			if (grpdata[0] & GRP_COMDAT) {
22400Sstevel@tonic-gate 				(void) strcat(flgstrbuf,
22410Sstevel@tonic-gate 					MSG_ORIG(MSG_GRP_COMDAT));
22420Sstevel@tonic-gate 			}
22430Sstevel@tonic-gate 			if ((grpdata[0] & ~GRP_COMDAT) != 0) {
22440Sstevel@tonic-gate 				(void) snprintf(flgstrbuf + strlen(flgstrbuf),
22450Sstevel@tonic-gate 				    (MSG_GRP_COMDAT_SIZE + 10),
22460Sstevel@tonic-gate 				    MSG_ORIG(MSG_GRP_FMT1),
22470Sstevel@tonic-gate 				    (uint_t)(grpdata[0] & ~GRP_COMDAT));
22480Sstevel@tonic-gate 			}
22490Sstevel@tonic-gate 		}
22500Sstevel@tonic-gate 		(void) strcat(flgstrbuf, MSG_ORIG(MSG_GRP_CLOSBRKT));
22510Sstevel@tonic-gate 
22520Sstevel@tonic-gate 		if (gelf_getsym(dsyms, shdr->sh_info, &sym) == NULL) {
22530Sstevel@tonic-gate 			(void) fprintf(stderr,
22540Sstevel@tonic-gate 				MSG_INTL(MSG_ERR_GRBADSYMNDX),
22550Sstevel@tonic-gate 				file, elf_errmsg(0));
22560Sstevel@tonic-gate 			(void) fflush(stderr);
22570Sstevel@tonic-gate 		}
22580Sstevel@tonic-gate 		symname = demangle(string(_cache, shdr->sh_link,
22590Sstevel@tonic-gate 			&cache[symshdr->sh_link], file, sym.st_name),
22600Sstevel@tonic-gate 			flags);
22610Sstevel@tonic-gate 		dbg_print(MSG_INTL(MSG_GRP_LINE2));
22620Sstevel@tonic-gate 		dbg_print(MSG_INTL(MSG_GRP_LINE3),
22630Sstevel@tonic-gate 			flgstrbuf, symname);
22640Sstevel@tonic-gate 		for (_cnt = 1, grpcnt = (shdr->sh_size / sizeof (Word));
22650Sstevel@tonic-gate 		    _cnt < grpcnt; _cnt++) {
22660Sstevel@tonic-gate 			char		index[MAXNDXSIZE];
22670Sstevel@tonic-gate 			const char	*sname;
22680Sstevel@tonic-gate 
22690Sstevel@tonic-gate 			(void) snprintf(index, MAXNDXSIZE,
22700Sstevel@tonic-gate 			    MSG_ORIG(MSG_FMT_INDEX), EC_XWORD(_cnt));
22710Sstevel@tonic-gate 			if (grpdata[_cnt] >= shnum) {
22720Sstevel@tonic-gate 				sname = MSG_INTL(MSG_GRP_INVALSCN);
22730Sstevel@tonic-gate 			} else {
22740Sstevel@tonic-gate 				sname = cache[grpdata[_cnt]].c_name;
22750Sstevel@tonic-gate 			}
22760Sstevel@tonic-gate 			(void) printf(MSG_ORIG(MSG_GRP_FMT2), index, sname,
22770Sstevel@tonic-gate 				(uint_t)grpdata[_cnt]);
22780Sstevel@tonic-gate 		}
22790Sstevel@tonic-gate 	}
22800Sstevel@tonic-gate }
22810Sstevel@tonic-gate 
22820Sstevel@tonic-gate 
22830Sstevel@tonic-gate static void
2284*942Sahl got(Cache *cache, GElf_Word shnum, GElf_Word phnum, GElf_Ehdr *ehdr,
2285*942Sahl     const char *file)
22860Sstevel@tonic-gate {
22870Sstevel@tonic-gate 	Cache		*gotcache = 0, *symtab = 0, *_cache;
22880Sstevel@tonic-gate 	GElf_Addr	gotbgn, gotend;
22890Sstevel@tonic-gate 	GElf_Shdr	*gotshdr;
22900Sstevel@tonic-gate 	GElf_Word	cnt, gotents, gotndx;
22910Sstevel@tonic-gate 	size_t		gentsize;
22920Sstevel@tonic-gate 	Got_info	*gottable;
22930Sstevel@tonic-gate 	char		*gotdata;
22940Sstevel@tonic-gate 	GElf_Sym	gsym;
22950Sstevel@tonic-gate 	GElf_Xword	gsymaddr;
22960Sstevel@tonic-gate 
22970Sstevel@tonic-gate 	/*
22980Sstevel@tonic-gate 	 * First we find the got
22990Sstevel@tonic-gate 	 */
23000Sstevel@tonic-gate 	for (cnt = 1; cnt < shnum; cnt++) {
23010Sstevel@tonic-gate 		_cache = &cache[cnt];
23020Sstevel@tonic-gate 		if (strncmp(_cache->c_name, MSG_ORIG(MSG_ELF_GOT), 4) == 0) {
23030Sstevel@tonic-gate 			gotcache = _cache;
23040Sstevel@tonic-gate 			break;
23050Sstevel@tonic-gate 		}
23060Sstevel@tonic-gate 	}
23070Sstevel@tonic-gate 	if (!gotcache)
23080Sstevel@tonic-gate 		return;
23090Sstevel@tonic-gate 	gotshdr = &gotcache->c_shdr;
23100Sstevel@tonic-gate 	gotbgn = gotshdr->sh_addr;
23110Sstevel@tonic-gate 
23120Sstevel@tonic-gate 	if (gotshdr->sh_size == 0) {
23130Sstevel@tonic-gate 		(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ),
23140Sstevel@tonic-gate 		    file, gotcache->c_name);
23150Sstevel@tonic-gate 		(void) fflush(stderr);
23160Sstevel@tonic-gate 		return;
23170Sstevel@tonic-gate 	}
23180Sstevel@tonic-gate 	gotend = gotbgn + gotshdr->sh_size;
23190Sstevel@tonic-gate 
23200Sstevel@tonic-gate 	/*
23210Sstevel@tonic-gate 	 * Some architectures don't properly set the sh_entsize
23220Sstevel@tonic-gate 	 * for the GOT table.  If it's not set we will default
23230Sstevel@tonic-gate 	 * to a size of a pointer.
23240Sstevel@tonic-gate 	 */
23250Sstevel@tonic-gate 	if ((gentsize = gotshdr->sh_entsize) == 0) {
23260Sstevel@tonic-gate 		if (ehdr->e_ident[EI_CLASS] == ELFCLASS64)
23270Sstevel@tonic-gate 			gentsize = sizeof (GElf_Xword);
23280Sstevel@tonic-gate 		else
23290Sstevel@tonic-gate 			gentsize = sizeof (GElf_Word);
23300Sstevel@tonic-gate 	}
23310Sstevel@tonic-gate 	/* LINTED */
23320Sstevel@tonic-gate 	gotents = (GElf_Word)(gotshdr->sh_size / gentsize);
23330Sstevel@tonic-gate 	gotdata = gotcache->c_data->d_buf;
23340Sstevel@tonic-gate 
23350Sstevel@tonic-gate 	if ((gottable = calloc(gotents, sizeof (Got_info))) == 0) {
23360Sstevel@tonic-gate 		int err = errno;
23370Sstevel@tonic-gate 		(void) fprintf(stderr, MSG_INTL(MSG_ERR_MALLOC),
23380Sstevel@tonic-gate 			file, strerror(err));
23390Sstevel@tonic-gate 		(void) fflush(stderr);
23400Sstevel@tonic-gate 		return;
23410Sstevel@tonic-gate 	}
23420Sstevel@tonic-gate 
23430Sstevel@tonic-gate 	/*
23440Sstevel@tonic-gate 	 * Now we scan through all the sections looking for any relocations
23450Sstevel@tonic-gate 	 * that may be against the GOT.  Since these may not be isolated to a
23460Sstevel@tonic-gate 	 * .rel[a].got section we check them all.
23470Sstevel@tonic-gate 	 * While scanning sections save the symbol table entry (a symtab
23480Sstevel@tonic-gate 	 * overriding a dynsym) so that we can lookup _GLOBAL_OFFSET_TABLE_.
23490Sstevel@tonic-gate 	 */
23500Sstevel@tonic-gate 	for (cnt = 1; cnt < shnum; cnt++) {
23510Sstevel@tonic-gate 		GElf_Shdr	*shdr;
23520Sstevel@tonic-gate 		GElf_Word	rtype;
23530Sstevel@tonic-gate 		Elf_Data	*dsyms, *reldata;
23540Sstevel@tonic-gate 		GElf_Rela	rela;
23550Sstevel@tonic-gate 		ulong_t		rcount;
23560Sstevel@tonic-gate 		int		ndx;
23570Sstevel@tonic-gate 		char		*sname;
23580Sstevel@tonic-gate 
23590Sstevel@tonic-gate 		_cache = &cache[cnt];
23600Sstevel@tonic-gate 		shdr = &_cache->c_shdr;
23610Sstevel@tonic-gate 
23620Sstevel@tonic-gate 		if ((symtab == 0) && (shdr->sh_type == SHT_DYNSYM)) {
23630Sstevel@tonic-gate 			symtab = _cache;
23640Sstevel@tonic-gate 			continue;
23650Sstevel@tonic-gate 		}
23660Sstevel@tonic-gate 		if (shdr->sh_type == SHT_SYMTAB) {
23670Sstevel@tonic-gate 			symtab = _cache;
23680Sstevel@tonic-gate 			continue;
23690Sstevel@tonic-gate 		}
23700Sstevel@tonic-gate 
23710Sstevel@tonic-gate 		rtype = shdr->sh_type;
23720Sstevel@tonic-gate 		if ((rtype != SHT_RELA) && (rtype != SHT_REL))
23730Sstevel@tonic-gate 			continue;
23740Sstevel@tonic-gate 
23750Sstevel@tonic-gate 		/*
23760Sstevel@tonic-gate 		 * Determine the relocation data and number.
23770Sstevel@tonic-gate 		 */
23780Sstevel@tonic-gate 		if ((shdr->sh_entsize == 0) || (shdr->sh_size == 0)) {
23790Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ),
23800Sstevel@tonic-gate 			    file, _cache->c_name);
23810Sstevel@tonic-gate 			(void) fflush(stderr);
23820Sstevel@tonic-gate 			continue;
23830Sstevel@tonic-gate 		}
23840Sstevel@tonic-gate 		rcount = shdr->sh_size / shdr->sh_entsize;
23850Sstevel@tonic-gate 
23860Sstevel@tonic-gate 		reldata = _cache->c_data;
23870Sstevel@tonic-gate 
23880Sstevel@tonic-gate 		/*
23890Sstevel@tonic-gate 		 * Get the data buffer for the associated symbol table.
23900Sstevel@tonic-gate 		 */
23910Sstevel@tonic-gate 		if ((shdr->sh_link == 0) || (shdr->sh_link >= shnum)) {
23920Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHLINK),
23930Sstevel@tonic-gate 				file, _cache->c_name, EC_XWORD(shdr->sh_link));
23940Sstevel@tonic-gate 			(void) fflush(stderr);
23950Sstevel@tonic-gate 			continue;
23960Sstevel@tonic-gate 		}
23970Sstevel@tonic-gate 		dsyms = cache[shdr->sh_link].c_data;
23980Sstevel@tonic-gate 		if (dsyms->d_buf == 0) {
23990Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ),
24000Sstevel@tonic-gate 			    file, cache[shdr->sh_link].c_name);
24010Sstevel@tonic-gate 			(void) fflush(stderr);
24020Sstevel@tonic-gate 			continue;
24030Sstevel@tonic-gate 		}
24040Sstevel@tonic-gate 
24050Sstevel@tonic-gate 		sname = cache[shdr->sh_link].c_name;
24060Sstevel@tonic-gate 		shdr = &cache[shdr->sh_link].c_shdr;
24070Sstevel@tonic-gate 		/*
24080Sstevel@tonic-gate 		 * Get the associated string table section.
24090Sstevel@tonic-gate 		 */
24100Sstevel@tonic-gate 		if ((shdr->sh_link == 0) || (shdr->sh_link >= shnum)) {
24110Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHLINK),
24120Sstevel@tonic-gate 			    file, sname, EC_XWORD(shdr->sh_link));
24130Sstevel@tonic-gate 			(void) fflush(stderr);
24140Sstevel@tonic-gate 			continue;
24150Sstevel@tonic-gate 		}
24160Sstevel@tonic-gate 
24170Sstevel@tonic-gate 		/* LINTED */
24180Sstevel@tonic-gate 		for (ndx = 0; ndx < rcount; ++ndx) {
24190Sstevel@tonic-gate 			GElf_Sym 	_sym;
24200Sstevel@tonic-gate 			GElf_Word	sndx;
24210Sstevel@tonic-gate 			GElf_Addr	offset;
24220Sstevel@tonic-gate 			Got_info	*gip;
24230Sstevel@tonic-gate 			void		*relret;
24240Sstevel@tonic-gate 
24250Sstevel@tonic-gate 			if (rtype == SHT_RELA) {
24260Sstevel@tonic-gate 				relret = (void *)gelf_getrela(reldata, ndx,
24270Sstevel@tonic-gate 				    &rela);
24280Sstevel@tonic-gate 			} else {
24290Sstevel@tonic-gate 				relret = (void *)gelf_getrel(reldata, ndx,
24300Sstevel@tonic-gate 				    (GElf_Rel *)&rela);
24310Sstevel@tonic-gate 			}
24320Sstevel@tonic-gate 			if (relret == NULL) {
24330Sstevel@tonic-gate 				(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADREL),
24340Sstevel@tonic-gate 				    file, _cache->c_name, elf_errmsg(0));
24350Sstevel@tonic-gate 				(void) fflush(stderr);
24360Sstevel@tonic-gate 				break;
24370Sstevel@tonic-gate 			}
24380Sstevel@tonic-gate 
24390Sstevel@tonic-gate 			offset = rela.r_offset;
24400Sstevel@tonic-gate 			/* LINTED */
24410Sstevel@tonic-gate 			sndx = (GElf_Word)GELF_R_SYM(rela.r_info);
24420Sstevel@tonic-gate 
24430Sstevel@tonic-gate 			/*
24440Sstevel@tonic-gate 			 * Only pay attention to relocations against the GOT.
24450Sstevel@tonic-gate 			 */
24460Sstevel@tonic-gate 			if ((offset < gotbgn) || (offset > gotend))
24470Sstevel@tonic-gate 				continue;
24480Sstevel@tonic-gate 
24490Sstevel@tonic-gate 			/* LINTED */
24500Sstevel@tonic-gate 			gotndx = (GElf_Word)((offset - gotbgn) /
24510Sstevel@tonic-gate 			    gotshdr->sh_entsize);
24520Sstevel@tonic-gate 			gip = &gottable[gotndx];
24530Sstevel@tonic-gate 			if (gip->g_rshtype != 0) {
24540Sstevel@tonic-gate 				(void) fprintf(stderr,
24550Sstevel@tonic-gate 				    MSG_INTL(MSG_GOT_MULTIPLE), file,
24560Sstevel@tonic-gate 				    /* LINTED */
24570Sstevel@tonic-gate 				    EC_WORD(gotndx), EC_XWORD(offset));
24580Sstevel@tonic-gate 				(void) fflush(stderr);
24590Sstevel@tonic-gate 				continue;
24600Sstevel@tonic-gate 			}
24610Sstevel@tonic-gate 
24620Sstevel@tonic-gate 			/* LINTED */
24630Sstevel@tonic-gate 			if (gelf_getsym(dsyms, sndx, &_sym) == NULL) {
24640Sstevel@tonic-gate 				(void) fprintf(stderr,
24650Sstevel@tonic-gate 					MSG_INTL(MSG_ERR_RELBADSYMNDX),
24660Sstevel@tonic-gate 				    file, elf_errmsg(0));
24670Sstevel@tonic-gate 				(void) fflush(stderr);
24680Sstevel@tonic-gate 				gip->g_symname = MSG_INTL(MSG_STR_UNKNOWN);
24690Sstevel@tonic-gate 			} else {
24700Sstevel@tonic-gate 				gip->g_symname = string(_cache, sndx,
24710Sstevel@tonic-gate 				    &cache[shdr->sh_link], file, _sym.st_name);
24720Sstevel@tonic-gate 			}
24730Sstevel@tonic-gate 			gip->g_rshtype = rtype;
24740Sstevel@tonic-gate 			gip->g_rela = rela;
24750Sstevel@tonic-gate 		}
24760Sstevel@tonic-gate 	}
24770Sstevel@tonic-gate 
24780Sstevel@tonic-gate 	if (symlookup(MSG_ORIG(MSG_GOT_SYM), cache, shnum, &gsym, symtab, file))
24790Sstevel@tonic-gate 		gsymaddr = gsym.st_value;
24800Sstevel@tonic-gate 	else
24810Sstevel@tonic-gate 		gsymaddr = gotbgn;
24820Sstevel@tonic-gate 
24830Sstevel@tonic-gate 	dbg_print(MSG_ORIG(MSG_STR_EMPTY));
24840Sstevel@tonic-gate 	dbg_print(MSG_INTL(MSG_ELF_SCN_GOT), gotcache->c_name, gotents);
24850Sstevel@tonic-gate 	Gelf_got_title(ehdr->e_ident[EI_CLASS]);
24860Sstevel@tonic-gate 
24870Sstevel@tonic-gate 	for (gotndx = 0; gotndx < gotents; gotndx++) {
24880Sstevel@tonic-gate 		Got_info	*gip;
24890Sstevel@tonic-gate 		Sword		gindex;
24900Sstevel@tonic-gate 		GElf_Addr	gaddr;
24910Sstevel@tonic-gate 		GElf_Xword	gotentry;
24920Sstevel@tonic-gate 
24930Sstevel@tonic-gate 		gip = &gottable[gotndx];
24940Sstevel@tonic-gate 
24950Sstevel@tonic-gate 		gaddr = gotbgn + (gotndx * gentsize);
24960Sstevel@tonic-gate 		/* LINTED */
24970Sstevel@tonic-gate 		gindex = (Sword)((gaddr - gsymaddr) / gentsize);
24980Sstevel@tonic-gate 
24990Sstevel@tonic-gate 		if (gentsize == sizeof (GElf_Word))
25000Sstevel@tonic-gate 			/* LINTED */
25010Sstevel@tonic-gate 			gotentry = (GElf_Xword)(*((GElf_Word *)(gotdata) +
25020Sstevel@tonic-gate 			    gotndx));
25030Sstevel@tonic-gate 		else
25040Sstevel@tonic-gate 			/* LINTED */
25050Sstevel@tonic-gate 			gotentry = *((GElf_Xword *)(gotdata) + gotndx);
25060Sstevel@tonic-gate 
25070Sstevel@tonic-gate 		Gelf_got_entry(ehdr, gindex, gaddr, gotentry, gip->g_rshtype,
25080Sstevel@tonic-gate 		    &gip->g_rela, gip->g_symname);
25090Sstevel@tonic-gate 	}
25100Sstevel@tonic-gate 
25110Sstevel@tonic-gate 	free(gottable);
25120Sstevel@tonic-gate }
25130Sstevel@tonic-gate 
25140Sstevel@tonic-gate void
25150Sstevel@tonic-gate checksum(Elf *elf)
25160Sstevel@tonic-gate {
25170Sstevel@tonic-gate 	dbg_print(MSG_ORIG(MSG_STR_EMPTY));
25180Sstevel@tonic-gate 	dbg_print(MSG_INTL(MSG_STR_CHECKSUM), gelf_checksum(elf));
25190Sstevel@tonic-gate }
25200Sstevel@tonic-gate 
25210Sstevel@tonic-gate static void
25220Sstevel@tonic-gate regular(const char *file, Elf *elf, uint32_t flags, char *Nname, int wfd)
25230Sstevel@tonic-gate {
25240Sstevel@tonic-gate 	Elf_Scn		*scn;
25250Sstevel@tonic-gate 	GElf_Ehdr	ehdr;
25260Sstevel@tonic-gate 	Elf_Data	*data;
25270Sstevel@tonic-gate 	uint_t		cnt;
2528*942Sahl 	GElf_Word	shnum, phnum;
2529*942Sahl 	size_t		shstrndx, _shnum, _phnum;
25300Sstevel@tonic-gate 	GElf_Shdr	nameshdr;
25310Sstevel@tonic-gate 	GElf_Shdr	shdr0;
25320Sstevel@tonic-gate 	GElf_Shdr	*_shdr0;
25330Sstevel@tonic-gate 	char		*names = 0;
25340Sstevel@tonic-gate 	Cache		*cache, *_cache;
25350Sstevel@tonic-gate 	Cache		*versymcache;
25360Sstevel@tonic-gate 
25370Sstevel@tonic-gate 	if (gelf_getehdr(elf, &ehdr) == NULL) {
25380Sstevel@tonic-gate 		failure(file, MSG_ORIG(MSG_ELF_GETEHDR));
25390Sstevel@tonic-gate 		return;
25400Sstevel@tonic-gate 	}
25410Sstevel@tonic-gate 
2542*942Sahl 	if (elf_getshnum(elf, &_shnum) == 0) {
25430Sstevel@tonic-gate 		failure(file, MSG_ORIG(MSG_ELF_GETSHNUM));
25440Sstevel@tonic-gate 		return;
25450Sstevel@tonic-gate 	}
25460Sstevel@tonic-gate 	/* LINTED */
25470Sstevel@tonic-gate 	shnum = (GElf_Word)_shnum;
25480Sstevel@tonic-gate 
2549*942Sahl 	if (elf_getshstrndx(elf, &shstrndx) == 0) {
25500Sstevel@tonic-gate 		failure(file, MSG_ORIG(MSG_ELF_GETSHSTRNDX));
25510Sstevel@tonic-gate 		return;
25520Sstevel@tonic-gate 	}
2553*942Sahl 
2554*942Sahl 	if (elf_getphnum(elf, &_phnum) == 0) {
2555*942Sahl 		failure(file, MSG_ORIG(MSG_ELF_GETPHNUM));
2556*942Sahl 		return;
2557*942Sahl 	}
2558*942Sahl 	/* LINTED */
2559*942Sahl 	phnum = (GElf_Word)_phnum;
2560*942Sahl 
25610Sstevel@tonic-gate 	if ((scn = elf_getscn(elf, 0)) != NULL) {
25620Sstevel@tonic-gate 		if ((_shdr0 = gelf_getshdr(scn, &shdr0)) == NULL) {
25630Sstevel@tonic-gate 			failure(file, MSG_ORIG(MSG_ELF_GETSHDR));
25640Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_INTL(MSG_ELF_ERR_SCN), 0);
25650Sstevel@tonic-gate 			(void) fflush(stderr);
25660Sstevel@tonic-gate 			return;
25670Sstevel@tonic-gate 		}
25680Sstevel@tonic-gate 	} else
25690Sstevel@tonic-gate 		_shdr0 = 0;
25700Sstevel@tonic-gate 
25710Sstevel@tonic-gate 	/*
25720Sstevel@tonic-gate 	 * Print the elf header.
25730Sstevel@tonic-gate 	 */
25740Sstevel@tonic-gate 	if (flags & FLG_EHDR)
25750Sstevel@tonic-gate 		Gelf_elf_header(&ehdr, _shdr0);
25760Sstevel@tonic-gate 
25770Sstevel@tonic-gate 	/*
25780Sstevel@tonic-gate 	 * Print the program headers.
25790Sstevel@tonic-gate 	 */
2580*942Sahl 	if ((flags & FLG_PHDR) && phnum != 0) {
25810Sstevel@tonic-gate 		GElf_Phdr phdr;
25820Sstevel@tonic-gate 
2583*942Sahl 		for (cnt = 0; cnt < phnum; cnt++) {
25840Sstevel@tonic-gate 			if (gelf_getphdr(elf, cnt, &phdr) == NULL) {
25850Sstevel@tonic-gate 				failure(file, MSG_ORIG(MSG_ELF_GETPHDR));
25860Sstevel@tonic-gate 				return;
25870Sstevel@tonic-gate 			}
25880Sstevel@tonic-gate 
25890Sstevel@tonic-gate 			dbg_print(MSG_ORIG(MSG_STR_EMPTY));
25900Sstevel@tonic-gate 			dbg_print(MSG_INTL(MSG_ELF_PHDR), cnt);
25910Sstevel@tonic-gate 			Gelf_phdr_entry(ehdr.e_machine, &phdr);
25920Sstevel@tonic-gate 		}
25930Sstevel@tonic-gate 	}
25940Sstevel@tonic-gate 
25950Sstevel@tonic-gate 
25960Sstevel@tonic-gate 	/*
2597*942Sahl 	 * Return now if there are no section, if there's just one section to
2598*942Sahl 	 * act as an extension of the ELF header, or if on section information
2599*942Sahl 	 * was requested.
26000Sstevel@tonic-gate 	 */
2601*942Sahl 	if ((shnum <= 1) || (flags && (flags & ~(FLG_EHDR | FLG_PHDR)) == 0)) {
26020Sstevel@tonic-gate 		if ((ehdr.e_type == ET_CORE) && (flags & FLG_NOTE))
26030Sstevel@tonic-gate 			note(0, shnum, 0, file);
26040Sstevel@tonic-gate 		return;
26050Sstevel@tonic-gate 	}
26060Sstevel@tonic-gate 
26070Sstevel@tonic-gate 	/*
26080Sstevel@tonic-gate 	 * Obtain the .shstrtab data buffer to provide the required section
26090Sstevel@tonic-gate 	 * name strings.
26100Sstevel@tonic-gate 	 */
26110Sstevel@tonic-gate 	if ((scn = elf_getscn(elf, shstrndx)) == NULL) {
26120Sstevel@tonic-gate 		failure(file, MSG_ORIG(MSG_ELF_GETSCN));
26130Sstevel@tonic-gate 		(void) fprintf(stderr, MSG_INTL(MSG_ELF_ERR_SHDR),
26140Sstevel@tonic-gate 		    EC_XWORD(shstrndx));
26150Sstevel@tonic-gate 		(void) fflush(stderr);
26160Sstevel@tonic-gate 	} else if ((data = elf_getdata(scn, NULL)) == NULL) {
26170Sstevel@tonic-gate 		failure(file, MSG_ORIG(MSG_ELF_GETDATA));
26180Sstevel@tonic-gate 		(void) fprintf(stderr, MSG_INTL(MSG_ELF_ERR_DATA),
26190Sstevel@tonic-gate 		    EC_XWORD(shstrndx));
26200Sstevel@tonic-gate 		(void) fflush(stderr);
26210Sstevel@tonic-gate 	} else if (gelf_getshdr(scn, &nameshdr) == NULL) {
26220Sstevel@tonic-gate 		failure(file, MSG_ORIG(MSG_ELF_GETSHDR));
26230Sstevel@tonic-gate 		(void) fprintf(stderr, MSG_INTL(MSG_ELF_ERR_SCN),
26240Sstevel@tonic-gate 		    /* LINTED */
26250Sstevel@tonic-gate 		    (int)elf_ndxscn(scn));
26260Sstevel@tonic-gate 		(void) fflush(stderr);
26270Sstevel@tonic-gate 	} else if ((names = data->d_buf) == 0) {
26280Sstevel@tonic-gate 		(void) fprintf(stderr, MSG_INTL(MSG_ERR_SHSTRNULL), file);
26290Sstevel@tonic-gate 		(void) fflush(stderr);
26300Sstevel@tonic-gate 	}
26310Sstevel@tonic-gate 
26320Sstevel@tonic-gate 	/*
26330Sstevel@tonic-gate 	 * Fill in the cache descriptor with information for each section.
26340Sstevel@tonic-gate 	 */
26350Sstevel@tonic-gate 	if ((cache = malloc(shnum * sizeof (Cache))) == 0) {
26360Sstevel@tonic-gate 		int err = errno;
26370Sstevel@tonic-gate 		(void) fprintf(stderr, MSG_INTL(MSG_ERR_MALLOC),
26380Sstevel@tonic-gate 		    file, strerror(err));
26390Sstevel@tonic-gate 		(void) fflush(stderr);
26400Sstevel@tonic-gate 		return;
26410Sstevel@tonic-gate 	}
26420Sstevel@tonic-gate 
26430Sstevel@tonic-gate 	*cache = _cache_init;
26440Sstevel@tonic-gate 	_cache = cache;
26450Sstevel@tonic-gate 	_cache++;
26460Sstevel@tonic-gate 
26470Sstevel@tonic-gate 	for (cnt = 1, scn = NULL; scn = elf_nextscn(elf, scn);
26480Sstevel@tonic-gate 	    cnt++, _cache++) {
26490Sstevel@tonic-gate 		if (gelf_getshdr(scn, &_cache->c_shdr) == NULL) {
26500Sstevel@tonic-gate 			failure(file, MSG_ORIG(MSG_ELF_GETSHDR));
26510Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_INTL(MSG_ELF_ERR_SCN),
26520Sstevel@tonic-gate 			    /* LINTED */
26530Sstevel@tonic-gate 			    (int)elf_ndxscn(scn));
26540Sstevel@tonic-gate 			(void) fflush(stderr);
26550Sstevel@tonic-gate 		}
26560Sstevel@tonic-gate 
26570Sstevel@tonic-gate 		if (names && _cache->c_shdr.sh_name &&
26580Sstevel@tonic-gate 		    /* LINTED */
26590Sstevel@tonic-gate 		    (nameshdr.sh_size > _cache->c_shdr.sh_name))
26600Sstevel@tonic-gate 			_cache->c_name = names + _cache->c_shdr.sh_name;
26610Sstevel@tonic-gate 		else {
26620Sstevel@tonic-gate 			/*
26630Sstevel@tonic-gate 			 * If there exists no shstrtab data, or a section header
26640Sstevel@tonic-gate 			 * has no name (an invalid index of 0), then compose a
26650Sstevel@tonic-gate 			 * name for each section.
26660Sstevel@tonic-gate 			 */
26670Sstevel@tonic-gate 			char	scnndxnm[100];
26680Sstevel@tonic-gate 
26690Sstevel@tonic-gate 			(void) snprintf(scnndxnm, 100, MSG_INTL(MSG_FMT_SCNNDX),
26700Sstevel@tonic-gate 			    cnt);
26710Sstevel@tonic-gate 
26720Sstevel@tonic-gate 			/*
26730Sstevel@tonic-gate 			 * Although we have a valid shstrtab section inform the
26740Sstevel@tonic-gate 			 * user if this section name index exceeds the shstrtab
26750Sstevel@tonic-gate 			 * data.
26760Sstevel@tonic-gate 			 */
26770Sstevel@tonic-gate 			if (names &&
26780Sstevel@tonic-gate 			    /* LINTED */
26790Sstevel@tonic-gate 			    (nameshdr.sh_size <= _cache->c_shdr.sh_name)) {
26800Sstevel@tonic-gate 				(void) fprintf(stderr,
26810Sstevel@tonic-gate 				    MSG_INTL(MSG_ERR_BADSHNAME), file,
26820Sstevel@tonic-gate 				    _cache->c_name,
26830Sstevel@tonic-gate 				    EC_XWORD(_cache->c_shdr.sh_name));
26840Sstevel@tonic-gate 				(void) fflush(stderr);
26850Sstevel@tonic-gate 			}
26860Sstevel@tonic-gate 
26870Sstevel@tonic-gate 			if ((_cache->c_name =
26880Sstevel@tonic-gate 			    malloc(strlen(scnndxnm) + 1)) == 0) {
26890Sstevel@tonic-gate 				int err = errno;
26900Sstevel@tonic-gate 				(void) fprintf(stderr, MSG_INTL(MSG_ERR_MALLOC),
26910Sstevel@tonic-gate 				    file, strerror(err));
26920Sstevel@tonic-gate 				(void) fflush(stderr);
26930Sstevel@tonic-gate 				return;
26940Sstevel@tonic-gate 			}
26950Sstevel@tonic-gate 			(void) strcpy(_cache->c_name, scnndxnm);
26960Sstevel@tonic-gate 		}
26970Sstevel@tonic-gate 
26980Sstevel@tonic-gate 		if ((_cache->c_data = elf_getdata(scn, NULL)) == NULL) {
26990Sstevel@tonic-gate 			failure(file, MSG_ORIG(MSG_ELF_GETDATA));
27000Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_INTL(MSG_ELF_ERR_SCNDATA),
27010Sstevel@tonic-gate 			    /* LINTED */
27020Sstevel@tonic-gate 			    (int)elf_ndxscn(scn));
27030Sstevel@tonic-gate 			(void) fflush(stderr);
27040Sstevel@tonic-gate 		}
27050Sstevel@tonic-gate 
27060Sstevel@tonic-gate 		/*
27070Sstevel@tonic-gate 		 * Do we wish to write the section out?
27080Sstevel@tonic-gate 		 */
27090Sstevel@tonic-gate 		if (wfd && Nname && (strcmp(Nname, _cache->c_name) == 0)) {
27100Sstevel@tonic-gate 			(void) write(wfd, _cache->c_data->d_buf,
27110Sstevel@tonic-gate 			    _cache->c_data->d_size);
27120Sstevel@tonic-gate 		}
27130Sstevel@tonic-gate 	}
27140Sstevel@tonic-gate 
27150Sstevel@tonic-gate 	if (flags & FLG_SHDR)
2716*942Sahl 		sections(file, cache, shnum, phnum, &ehdr, Nname);
27170Sstevel@tonic-gate 
27180Sstevel@tonic-gate 	if (flags & FLG_INTERP)
2719*942Sahl 		interp(file, cache, shnum, phnum, &ehdr, elf);
27200Sstevel@tonic-gate 
27210Sstevel@tonic-gate 	versymcache = versions(cache, shnum, file, flags);
27220Sstevel@tonic-gate 
27230Sstevel@tonic-gate 	if (flags & FLG_SYMBOLS)
2724*942Sahl 		symbols(cache, shnum, phnum, &ehdr, Nname, versymcache, file);
27250Sstevel@tonic-gate 
27260Sstevel@tonic-gate 	if (flags & FLG_HASH)
27270Sstevel@tonic-gate 		hash(cache, shnum, Nname, file, flags);
27280Sstevel@tonic-gate 
27290Sstevel@tonic-gate 	if (flags & FLG_GOT)
2730*942Sahl 		got(cache, shnum, phnum, &ehdr, file);
27310Sstevel@tonic-gate 
27320Sstevel@tonic-gate 	if (flags & FLG_GROUP)
27330Sstevel@tonic-gate 		group(cache, shnum, Nname, file, flags);
27340Sstevel@tonic-gate 
27350Sstevel@tonic-gate 	if (flags & FLG_SYMINFO)
27360Sstevel@tonic-gate 		syminfo(cache, shnum, file);
27370Sstevel@tonic-gate 
27380Sstevel@tonic-gate 	if (flags & FLG_RELOC)
2739*942Sahl 		reloc(cache, shnum, phnum, &ehdr, Nname, file, flags);
27400Sstevel@tonic-gate 
27410Sstevel@tonic-gate 	if (flags & FLG_DYNAMIC)
27420Sstevel@tonic-gate 		dynamic(cache, shnum, &ehdr, file);
27430Sstevel@tonic-gate 
27440Sstevel@tonic-gate 	if (flags & FLG_NOTE)
27450Sstevel@tonic-gate 		note(cache, shnum, Nname, file);
27460Sstevel@tonic-gate 
27470Sstevel@tonic-gate 	if (flags & FLG_MOVE)
27480Sstevel@tonic-gate 		move(cache, shnum, Nname, file, flags);
27490Sstevel@tonic-gate 
27500Sstevel@tonic-gate 	if (flags & FLG_CHECKSUM)
27510Sstevel@tonic-gate 		checksum(elf);
27520Sstevel@tonic-gate 
27530Sstevel@tonic-gate 	if (flags & FLG_CAP)
2754*942Sahl 		cap(file, cache, shnum, phnum, &ehdr, elf);
27550Sstevel@tonic-gate 
27560Sstevel@tonic-gate 	if (flags & FLG_UNWIND)
2757*942Sahl 		unwind(cache, shnum, phnum, &ehdr, Nname, file, elf);
27580Sstevel@tonic-gate 
27590Sstevel@tonic-gate 	free(cache);
27600Sstevel@tonic-gate }
27610Sstevel@tonic-gate 
27620Sstevel@tonic-gate static void
27630Sstevel@tonic-gate archive(const char *file, int fd, Elf *elf, uint32_t flags, char *Nname,
27640Sstevel@tonic-gate     int wfd)
27650Sstevel@tonic-gate {
27660Sstevel@tonic-gate 	Elf_Cmd		cmd = ELF_C_READ;
27670Sstevel@tonic-gate 	Elf_Arhdr	*arhdr;
27680Sstevel@tonic-gate 	Elf		*_elf = 0;
27690Sstevel@tonic-gate 	size_t		ptr;
27700Sstevel@tonic-gate 	Elf_Arsym	*arsym = 0;
27710Sstevel@tonic-gate 
27720Sstevel@tonic-gate 	/*
27730Sstevel@tonic-gate 	 * Determine if the archive sysmbol table itself is required.
27740Sstevel@tonic-gate 	 */
27750Sstevel@tonic-gate 	if ((flags & FLG_SYMBOLS) && ((Nname == NULL) ||
27760Sstevel@tonic-gate 	    (strcmp(Nname, MSG_ORIG(MSG_ELF_ARSYM)) == 0))) {
27770Sstevel@tonic-gate 		/*
27780Sstevel@tonic-gate 		 * Get the archive symbol table.
27790Sstevel@tonic-gate 		 */
27800Sstevel@tonic-gate 		if (((arsym = elf_getarsym(elf, &ptr)) == 0) && elf_errno()) {
27810Sstevel@tonic-gate 			/*
27820Sstevel@tonic-gate 			 * The arsym could be 0 even though there was no error.
27830Sstevel@tonic-gate 			 * Print the error message only when there was
27840Sstevel@tonic-gate 			 * real error from elf_getarsym().
27850Sstevel@tonic-gate 			 */
27860Sstevel@tonic-gate 			failure(file, MSG_ORIG(MSG_ELF_GETARSYM));
27870Sstevel@tonic-gate 			return;
27880Sstevel@tonic-gate 		}
27890Sstevel@tonic-gate 	}
27900Sstevel@tonic-gate 
27910Sstevel@tonic-gate 	/*
27920Sstevel@tonic-gate 	 * Print the archive symbol table only when the archive symbol
27930Sstevel@tonic-gate 	 * table exists and it was requested to print.
27940Sstevel@tonic-gate 	 */
27950Sstevel@tonic-gate 	if (arsym) {
27960Sstevel@tonic-gate 		size_t		cnt;
27970Sstevel@tonic-gate 		char		index[MAXNDXSIZE];
27980Sstevel@tonic-gate 		size_t		offset = 0, _offset = 0;
27990Sstevel@tonic-gate 
28000Sstevel@tonic-gate 		/*
28010Sstevel@tonic-gate 		 * Print out all the symbol entries.
28020Sstevel@tonic-gate 		 */
28030Sstevel@tonic-gate 		dbg_print(MSG_INTL(MSG_ARCHIVE_SYMTAB));
28040Sstevel@tonic-gate 		dbg_print(MSG_INTL(MSG_ARCHIVE_FIELDS));
28050Sstevel@tonic-gate 
28060Sstevel@tonic-gate 		for (cnt = 0; cnt < ptr; cnt++, arsym++) {
28070Sstevel@tonic-gate 			/*
28080Sstevel@tonic-gate 			 * For each object obtain an elf descriptor so that we
28090Sstevel@tonic-gate 			 * can establish the members name.  Note, we have had
28100Sstevel@tonic-gate 			 * archives where the archive header has not been
28110Sstevel@tonic-gate 			 * obtainable so be lenient with errors.
28120Sstevel@tonic-gate 			 */
28130Sstevel@tonic-gate 			if ((offset == 0) || ((arsym->as_off != 0) &&
28140Sstevel@tonic-gate 			    (arsym->as_off != _offset))) {
28150Sstevel@tonic-gate 
28160Sstevel@tonic-gate 				if (_elf)
28170Sstevel@tonic-gate 					(void) elf_end(_elf);
28180Sstevel@tonic-gate 
28190Sstevel@tonic-gate 				if (elf_rand(elf, arsym->as_off) !=
28200Sstevel@tonic-gate 				    arsym->as_off) {
28210Sstevel@tonic-gate 					failure(file, MSG_ORIG(MSG_ELF_RAND));
28220Sstevel@tonic-gate 					arhdr = 0;
28230Sstevel@tonic-gate 				} else if ((_elf = elf_begin(fd,
28240Sstevel@tonic-gate 				    ELF_C_READ, elf)) == 0) {
28250Sstevel@tonic-gate 					failure(file, MSG_ORIG(MSG_ELF_BEGIN));
28260Sstevel@tonic-gate 					arhdr = 0;
28270Sstevel@tonic-gate 				} else if ((arhdr = elf_getarhdr(_elf)) == 0) {
28280Sstevel@tonic-gate 					failure(file,
28290Sstevel@tonic-gate 					    MSG_ORIG(MSG_ELF_GETARHDR));
28300Sstevel@tonic-gate 					arhdr = 0;
28310Sstevel@tonic-gate 				}
28320Sstevel@tonic-gate 
28330Sstevel@tonic-gate 				_offset = arsym->as_off;
28340Sstevel@tonic-gate 				if (offset == 0)
28350Sstevel@tonic-gate 					offset = _offset;
28360Sstevel@tonic-gate 			}
28370Sstevel@tonic-gate 
28380Sstevel@tonic-gate 			(void) snprintf(index, MAXNDXSIZE,
28390Sstevel@tonic-gate 			    MSG_ORIG(MSG_FMT_INDEX), EC_XWORD(cnt));
28400Sstevel@tonic-gate 			if (arsym->as_off)
28410Sstevel@tonic-gate 				dbg_print(MSG_ORIG(MSG_FMT_ARSYM1), index,
28420Sstevel@tonic-gate 				    /* LINTED */
28430Sstevel@tonic-gate 				    (int)arsym->as_off, arhdr ? arhdr->ar_name :
28440Sstevel@tonic-gate 				    MSG_INTL(MSG_STR_UNKNOWN), (arsym->as_name ?
28450Sstevel@tonic-gate 				    demangle(arsym->as_name, flags) :
28460Sstevel@tonic-gate 				    MSG_INTL(MSG_STR_NULL)));
28470Sstevel@tonic-gate 			else
28480Sstevel@tonic-gate 				dbg_print(MSG_ORIG(MSG_FMT_ARSYM2), index,
28490Sstevel@tonic-gate 				    /* LINTED */
28500Sstevel@tonic-gate 				    (int)arsym->as_off);
28510Sstevel@tonic-gate 		}
28520Sstevel@tonic-gate 
28530Sstevel@tonic-gate 		if (_elf)
28540Sstevel@tonic-gate 			(void) elf_end(_elf);
28550Sstevel@tonic-gate 
28560Sstevel@tonic-gate 		/*
28570Sstevel@tonic-gate 		 * If we only need the archive symbol table return.
28580Sstevel@tonic-gate 		 */
28590Sstevel@tonic-gate 		if ((flags & FLG_SYMBOLS) && Nname &&
28600Sstevel@tonic-gate 		    (strcmp(Nname, MSG_ORIG(MSG_ELF_ARSYM)) == 0))
28610Sstevel@tonic-gate 			return;
28620Sstevel@tonic-gate 
28630Sstevel@tonic-gate 		/*
28640Sstevel@tonic-gate 		 * Reset elf descriptor in preparation for processing each
28650Sstevel@tonic-gate 		 * member.
28660Sstevel@tonic-gate 		 */
28670Sstevel@tonic-gate 		if (offset)
28680Sstevel@tonic-gate 			(void) elf_rand(elf, offset);
28690Sstevel@tonic-gate 	}
28700Sstevel@tonic-gate 
28710Sstevel@tonic-gate 	/*
28720Sstevel@tonic-gate 	 * Process each object within the archive.
28730Sstevel@tonic-gate 	 */
28740Sstevel@tonic-gate 	while ((_elf = elf_begin(fd, cmd, elf)) != NULL) {
28750Sstevel@tonic-gate 		char	name[MAXPATHLEN];
28760Sstevel@tonic-gate 
28770Sstevel@tonic-gate 		if ((arhdr = elf_getarhdr(_elf)) == NULL) {
28780Sstevel@tonic-gate 			failure(file, MSG_ORIG(MSG_ELF_GETARHDR));
28790Sstevel@tonic-gate 			return;
28800Sstevel@tonic-gate 		}
28810Sstevel@tonic-gate 		if (*arhdr->ar_name != '/') {
28820Sstevel@tonic-gate 			(void) snprintf(name, MAXPATHLEN,
28830Sstevel@tonic-gate 			    MSG_ORIG(MSG_FMT_ARNAME), file, arhdr->ar_name);
28840Sstevel@tonic-gate 			dbg_print(MSG_ORIG(MSG_FMT_NLSTR), name);
28850Sstevel@tonic-gate 
28860Sstevel@tonic-gate 			switch (elf_kind(_elf)) {
28870Sstevel@tonic-gate 			case ELF_K_AR:
28880Sstevel@tonic-gate 				archive(name, fd, _elf, flags, Nname, wfd);
28890Sstevel@tonic-gate 				break;
28900Sstevel@tonic-gate 			case ELF_K_ELF:
28910Sstevel@tonic-gate 				regular(name, _elf, flags, Nname, wfd);
28920Sstevel@tonic-gate 				break;
28930Sstevel@tonic-gate 			default:
28940Sstevel@tonic-gate 				(void) fprintf(stderr,
28950Sstevel@tonic-gate 					MSG_INTL(MSG_ERR_BADFILE), name);
28960Sstevel@tonic-gate 				(void) fflush(stderr);
28970Sstevel@tonic-gate 				break;
28980Sstevel@tonic-gate 			}
28990Sstevel@tonic-gate 		}
29000Sstevel@tonic-gate 
29010Sstevel@tonic-gate 		cmd = elf_next(_elf);
29020Sstevel@tonic-gate 		(void) elf_end(_elf);
29030Sstevel@tonic-gate 	}
29040Sstevel@tonic-gate }
29050Sstevel@tonic-gate 
29060Sstevel@tonic-gate int
29070Sstevel@tonic-gate main(int argc, char **argv, char **envp)
29080Sstevel@tonic-gate {
29090Sstevel@tonic-gate 	Elf		*elf;
29100Sstevel@tonic-gate 	int		var, fd, wfd = 0;
29110Sstevel@tonic-gate 	char		*Nname = NULL, *wname = 0;
29120Sstevel@tonic-gate 	uint32_t	flags = 0, dbg_flags = 0;
29130Sstevel@tonic-gate 
29140Sstevel@tonic-gate 	/*
29150Sstevel@tonic-gate 	 * If we're on a 64-bit kernel, try to exec a full 64-bit version of
29160Sstevel@tonic-gate 	 * the binary.  If successful, conv_check_native() won't return.
29170Sstevel@tonic-gate 	 */
29180Sstevel@tonic-gate 	conv_check_native(argv, envp);
29190Sstevel@tonic-gate 
29200Sstevel@tonic-gate 	/*
29210Sstevel@tonic-gate 	 * Establish locale.
29220Sstevel@tonic-gate 	 */
29230Sstevel@tonic-gate 	(void) setlocale(LC_MESSAGES, MSG_ORIG(MSG_STR_EMPTY));
29240Sstevel@tonic-gate 	(void) textdomain(MSG_ORIG(MSG_SUNW_OST_SGS));
29250Sstevel@tonic-gate 
29260Sstevel@tonic-gate 	(void) setvbuf(stdout, NULL, _IOLBF, 0);
29270Sstevel@tonic-gate 	(void) setvbuf(stderr, NULL, _IOLBF, 0);
29280Sstevel@tonic-gate 
29290Sstevel@tonic-gate 	opterr = 0;
29300Sstevel@tonic-gate 	while ((var = getopt(argc, argv, MSG_ORIG(MSG_STR_OPTIONS))) != EOF) {
29310Sstevel@tonic-gate 		switch (var) {
29320Sstevel@tonic-gate 		case 'C':
29330Sstevel@tonic-gate 			flags |= FLG_DEMANGLE;
29340Sstevel@tonic-gate 			break;
29350Sstevel@tonic-gate 		case 'c':
29360Sstevel@tonic-gate 			flags |= FLG_SHDR;
29370Sstevel@tonic-gate 			break;
29380Sstevel@tonic-gate 		case 'd':
29390Sstevel@tonic-gate 			flags |= FLG_DYNAMIC;
29400Sstevel@tonic-gate 			break;
29410Sstevel@tonic-gate 		case 'e':
29420Sstevel@tonic-gate 			flags |= FLG_EHDR;
29430Sstevel@tonic-gate 			break;
29440Sstevel@tonic-gate 		case 'G':
29450Sstevel@tonic-gate 			flags |= FLG_GOT;
29460Sstevel@tonic-gate 			break;
29470Sstevel@tonic-gate 		case 'g':
29480Sstevel@tonic-gate 			flags |= FLG_GROUP;
29490Sstevel@tonic-gate 			break;
29500Sstevel@tonic-gate 		case 'H':
29510Sstevel@tonic-gate 			flags |= FLG_CAP;
29520Sstevel@tonic-gate 			break;
29530Sstevel@tonic-gate 		case 'h':
29540Sstevel@tonic-gate 			flags |= FLG_HASH;
29550Sstevel@tonic-gate 			break;
29560Sstevel@tonic-gate 		case 'i':
29570Sstevel@tonic-gate 			flags |= FLG_INTERP;
29580Sstevel@tonic-gate 			break;
29590Sstevel@tonic-gate 		case 'k':
29600Sstevel@tonic-gate 			flags |= FLG_CHECKSUM;
29610Sstevel@tonic-gate 			break;
29620Sstevel@tonic-gate 		case 'l':
29630Sstevel@tonic-gate 			flags |= FLG_LONGNAME;
29640Sstevel@tonic-gate 			break;
29650Sstevel@tonic-gate 		case 'm':
29660Sstevel@tonic-gate 			flags |= FLG_MOVE;
29670Sstevel@tonic-gate 			break;
29680Sstevel@tonic-gate 		case 'N':
29690Sstevel@tonic-gate 			Nname = optarg;
29700Sstevel@tonic-gate 			break;
29710Sstevel@tonic-gate 		case 'n':
29720Sstevel@tonic-gate 			flags |= FLG_NOTE;
29730Sstevel@tonic-gate 			break;
29740Sstevel@tonic-gate 		case 'p':
29750Sstevel@tonic-gate 			flags |= FLG_PHDR;
29760Sstevel@tonic-gate 			break;
29770Sstevel@tonic-gate 		case 'r':
29780Sstevel@tonic-gate 			flags |= FLG_RELOC;
29790Sstevel@tonic-gate 			break;
29800Sstevel@tonic-gate 		case 's':
29810Sstevel@tonic-gate 			flags |= FLG_SYMBOLS;
29820Sstevel@tonic-gate 			break;
29830Sstevel@tonic-gate 		case 'u':
29840Sstevel@tonic-gate 			flags |= FLG_UNWIND;
29850Sstevel@tonic-gate 			break;
29860Sstevel@tonic-gate 		case 'v':
29870Sstevel@tonic-gate 			flags |= FLG_VERSIONS;
29880Sstevel@tonic-gate 			break;
29890Sstevel@tonic-gate 		case 'w':
29900Sstevel@tonic-gate 			wname = optarg;
29910Sstevel@tonic-gate 			break;
29920Sstevel@tonic-gate 		case 'y':
29930Sstevel@tonic-gate 			flags |= FLG_SYMINFO;
29940Sstevel@tonic-gate 			break;
29950Sstevel@tonic-gate 		case '?':
29960Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_INTL(MSG_USAGE_BRIEF),
29970Sstevel@tonic-gate 			    basename(argv[0]));
29980Sstevel@tonic-gate 			detail_usage();
29990Sstevel@tonic-gate 			return (1);
30000Sstevel@tonic-gate 		default:
30010Sstevel@tonic-gate 			break;
30020Sstevel@tonic-gate 		}
30030Sstevel@tonic-gate 	}
30040Sstevel@tonic-gate 
30050Sstevel@tonic-gate 	/*
30060Sstevel@tonic-gate 	 * Validate any arguments.
30070Sstevel@tonic-gate 	 */
30080Sstevel@tonic-gate 	if (flags == 0) {
30090Sstevel@tonic-gate 		if (!wname && !Nname) {
30100Sstevel@tonic-gate 			flags = FLG_EVERYTHING;
30110Sstevel@tonic-gate 		} else if (!wname || !Nname) {
30120Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_INTL(MSG_USAGE_BRIEF),
30130Sstevel@tonic-gate 			    basename(argv[0]));
30140Sstevel@tonic-gate 			return (1);
30150Sstevel@tonic-gate 		}
30160Sstevel@tonic-gate 	}
30170Sstevel@tonic-gate 
30180Sstevel@tonic-gate 	if ((var = argc - optind) == 0) {
30190Sstevel@tonic-gate 		(void) fprintf(stderr, MSG_INTL(MSG_USAGE_BRIEF),
30200Sstevel@tonic-gate 		    basename(argv[0]));
30210Sstevel@tonic-gate 		return (1);
30220Sstevel@tonic-gate 	}
30230Sstevel@tonic-gate 
30240Sstevel@tonic-gate 	/*
30250Sstevel@tonic-gate 	 * If the -C option is used by itself, report an error since the option
30260Sstevel@tonic-gate 	 * has no use without other symbol name generating options.
30270Sstevel@tonic-gate 	 *
30280Sstevel@tonic-gate 	 * If the -l option is used by itself, report an error.
30290Sstevel@tonic-gate 	 */
30300Sstevel@tonic-gate 	if ((flags == FLG_DEMANGLE) || (flags == FLG_LONGNAME) ||
30310Sstevel@tonic-gate 	    (flags == (FLG_DEMANGLE | FLG_LONGNAME))) {
30320Sstevel@tonic-gate 		if (flags & FLG_DEMANGLE)
30330Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DEMANGLE));
30340Sstevel@tonic-gate 		if (flags & FLG_LONGNAME)
30350Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_INTL(MSG_USAGE_LONGNAME));
30360Sstevel@tonic-gate 		return (1);
30370Sstevel@tonic-gate 	}
30380Sstevel@tonic-gate 
30390Sstevel@tonic-gate 	/*
30400Sstevel@tonic-gate 	 * If the -l/-C option is specified, set up the liblddbg.so.
30410Sstevel@tonic-gate 	 */
30420Sstevel@tonic-gate 	if (flags & FLG_LONGNAME)
30430Sstevel@tonic-gate 		dbg_flags = DBG_LONG;
30440Sstevel@tonic-gate 	if (flags & FLG_DEMANGLE)
30450Sstevel@tonic-gate 		dbg_flags |= DBG_DEMANGLE;
30460Sstevel@tonic-gate 	if (dbg_flags)
30470Sstevel@tonic-gate 		Dbg_set(dbg_flags);
30480Sstevel@tonic-gate 
30490Sstevel@tonic-gate 	/*
30500Sstevel@tonic-gate 	 * If the -w option has indicated an output file open it.  It's
30510Sstevel@tonic-gate 	 * arguable whether this option has much use when multiple files are
30520Sstevel@tonic-gate 	 * being processed.
30530Sstevel@tonic-gate 	 */
30540Sstevel@tonic-gate 	if (wname) {
30550Sstevel@tonic-gate 		if ((wfd = open(wname, (O_RDWR | O_CREAT | O_TRUNC),
30560Sstevel@tonic-gate 		    0666)) < 0) {
30570Sstevel@tonic-gate 			int err = errno;
30580Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_INTL(MSG_ERR_OPEN),
30590Sstevel@tonic-gate 			    wname, strerror(err));
30600Sstevel@tonic-gate 			(void) fflush(stderr);
30610Sstevel@tonic-gate 			wfd = 0;
30620Sstevel@tonic-gate 		}
30630Sstevel@tonic-gate 	}
30640Sstevel@tonic-gate 
30650Sstevel@tonic-gate 	/*
30660Sstevel@tonic-gate 	 * Open the input file and initialize the elf interface.
30670Sstevel@tonic-gate 	 */
30680Sstevel@tonic-gate 	for (; optind < argc; optind++) {
30690Sstevel@tonic-gate 		const char	*file = argv[optind];
30700Sstevel@tonic-gate 
30710Sstevel@tonic-gate 		if ((fd = open(argv[optind], O_RDONLY)) == -1) {
30720Sstevel@tonic-gate 			int err = errno;
30730Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_INTL(MSG_ERR_OPEN),
30740Sstevel@tonic-gate 			    file, strerror(err));
30750Sstevel@tonic-gate 			(void) fflush(stderr);
30760Sstevel@tonic-gate 			continue;
30770Sstevel@tonic-gate 		}
30780Sstevel@tonic-gate 		(void) elf_version(EV_CURRENT);
30790Sstevel@tonic-gate 		if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) {
30800Sstevel@tonic-gate 			failure(file, MSG_ORIG(MSG_ELF_BEGIN));
30810Sstevel@tonic-gate 			(void) close(fd);
30820Sstevel@tonic-gate 			continue;
30830Sstevel@tonic-gate 		}
30840Sstevel@tonic-gate 
30850Sstevel@tonic-gate 		if (var > 1)
30860Sstevel@tonic-gate 			dbg_print(MSG_ORIG(MSG_FMT_NLSTRNL), file);
30870Sstevel@tonic-gate 
30880Sstevel@tonic-gate 		switch (elf_kind(elf)) {
30890Sstevel@tonic-gate 		case ELF_K_AR:
30900Sstevel@tonic-gate 			archive(file, fd, elf, flags, Nname, wfd);
30910Sstevel@tonic-gate 			break;
30920Sstevel@tonic-gate 		case ELF_K_ELF:
30930Sstevel@tonic-gate 			regular(file, elf, flags, Nname, wfd);
30940Sstevel@tonic-gate 			break;
30950Sstevel@tonic-gate 		default:
30960Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADFILE), file);
30970Sstevel@tonic-gate 			(void) fflush(stderr);
30980Sstevel@tonic-gate 			break;
30990Sstevel@tonic-gate 		}
31000Sstevel@tonic-gate 
31010Sstevel@tonic-gate 		(void) close(fd);
31020Sstevel@tonic-gate 		(void) elf_end(elf);
31030Sstevel@tonic-gate 	}
31040Sstevel@tonic-gate 
31050Sstevel@tonic-gate 	if (wfd)
31060Sstevel@tonic-gate 		(void) close(wfd);
31070Sstevel@tonic-gate 	return (0);
31080Sstevel@tonic-gate }
3109