xref: /onnv-gate/usr/src/cmd/sgs/elfdump/common/fake_shdr.c (revision 11827:d7ef53deac3f)
14665Sab196087 /*
24665Sab196087  * CDDL HEADER START
34665Sab196087  *
44665Sab196087  * The contents of this file are subject to the terms of the
54665Sab196087  * Common Development and Distribution License (the "License").
64665Sab196087  * You may not use this file except in compliance with the License.
74665Sab196087  *
84665Sab196087  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
94665Sab196087  * or http://www.opensolaris.org/os/licensing.
104665Sab196087  * See the License for the specific language governing permissions
114665Sab196087  * and limitations under the License.
124665Sab196087  *
134665Sab196087  * When distributing Covered Code, include this CDDL HEADER in each
144665Sab196087  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
154665Sab196087  * If applicable, add the following below this CDDL HEADER, with the
164665Sab196087  * fields enclosed by brackets "[]" replaced with your own identifying
174665Sab196087  * information: Portions Copyright [yyyy] [name of copyright owner]
184665Sab196087  *
194665Sab196087  * CDDL HEADER END
204665Sab196087  */
214665Sab196087 
224665Sab196087 /*
23*11827SRod.Evans@Sun.COM  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
244665Sab196087  * Use is subject to license terms.
254665Sab196087  */
264665Sab196087 
274665Sab196087 /*
284665Sab196087  * Generate a cache of section header information for an ELF
294665Sab196087  * object from the information found in its program headers.
304665Sab196087  *
314665Sab196087  * Malicious code can remove or corrupt section headers. The
324665Sab196087  * resulting program will be difficult to analyze, but is still
334665Sab196087  * runnable. Hence, scribbling on the section headers or removing
344665Sab196087  * them is an effective form of obfuscation. On the other hand,
354665Sab196087  * program headers must be accurate or the program will not run.
364665Sab196087  * Section headers derived from them will necessarily lack information
374665Sab196087  * found in the originals (particularly for non-allocable sections),
384665Sab196087  * but will provide essential symbol information. The focus is on
394665Sab196087  * recovering information that elfdump knows how to display, and that
404665Sab196087  * might be interesting in a forensic situation.
414665Sab196087  *
424665Sab196087  * There are some things we don't attempt to create sections for:
434665Sab196087  *
444665Sab196087  *	plt, got
454665Sab196087  *		We have no way to determine the length of either of
464665Sab196087  *		these sections from the information available via
474665Sab196087  *		the program headers or dynamic section. The data in
484665Sab196087  *		the PLT is of little use to elfdump. The data in the
494665Sab196087  *		GOT might be somewhat more interesting, especially as
504665Sab196087  *		it pertains to relocations. However, the sizing issue
514665Sab196087  *		remains.
524665Sab196087  *
534665Sab196087  *	text, data, bss
544665Sab196087  *		Although we could create these, there is little value
554665Sab196087  *		to doing so. elfdump cannot display the arbitrary
564665Sab196087  *		data in these sections, so this would amount to a
574665Sab196087  *		simple repetition of the information already displayed
584665Sab196087  *		in the program headers, with no additional benefit.
594665Sab196087  */
604665Sab196087 
614665Sab196087 
624665Sab196087 
634665Sab196087 #include	<sys/elf_amd64.h>
645549Srie #include	<stdio.h>
654665Sab196087 #include	<unistd.h>
664665Sab196087 #include	<errno.h>
674665Sab196087 #include	<string.h>
684665Sab196087 #include	<strings.h>
694665Sab196087 #include	<conv.h>
704665Sab196087 #include	<msg.h>
714665Sab196087 #include	<_elfdump.h>
724665Sab196087 
734665Sab196087 
744665Sab196087 
754665Sab196087 /*
764665Sab196087  * Common information about the object that is needed by
774665Sab196087  * all the routines in this module.
784665Sab196087  */
794665Sab196087 typedef struct {
804665Sab196087 	const char	*file;
814665Sab196087 	int		fd;
824665Sab196087 	Ehdr		*ehdr;
834665Sab196087 	Phdr		*phdr;
844665Sab196087 	size_t		phnum;
854665Sab196087 } FSTATE;
864665Sab196087 
874665Sab196087 
884665Sab196087 
894665Sab196087 /*
904665Sab196087  * These values uniquely identify the sections that we know
914665Sab196087  * how to recover.
924665Sab196087  *
934665Sab196087  * Note: We write the sections to the cache array in this same order.
944665Sab196087  * It simplifies this code if the dynamic, dynstr, dynsym, and ldynsym
954665Sab196087  * sections occupy known slots in the cache array. Other sections reference
964665Sab196087  * them by index, and if they are at a known spot, there is no need
974665Sab196087  * for a fixup pass. Putting them in positions [1-4] solves this.
984665Sab196087  *
994665Sab196087  * The order they are in was chosen such that if any one of them exists,
1004665Sab196087  * all of the ones before it must also exist. This means that if the
1014665Sab196087  * desired section exists, it will end up in the desired index in the
1024665Sab196087  * cache array.
1034665Sab196087  *
1044665Sab196087  * The order of the other sections is arbitrary. I've arranged them
1054665Sab196087  * in roughly related groups.
1064665Sab196087  */
1074665Sab196087 typedef enum {
1084665Sab196087 	SINFO_T_NULL =		0,
1094665Sab196087 	SINFO_T_DYN =		1,
1104665Sab196087 	SINFO_T_DYNSTR = 	2,
1114665Sab196087 	SINFO_T_DYNSYM =	3,
1124665Sab196087 	SINFO_T_LDYNSYM =	4,
1134665Sab196087 
1144665Sab196087 	SINFO_T_HASH =		5,
1154665Sab196087 	SINFO_T_SYMINFO =	6,
1164665Sab196087 	SINFO_T_SYMSORT =	7,
1174665Sab196087 	SINFO_T_TLSSORT =	8,
1184665Sab196087 	SINFO_T_VERNEED =	9,
1194665Sab196087 	SINFO_T_VERDEF =	10,
1204665Sab196087 	SINFO_T_VERSYM =	11,
1214665Sab196087 	SINFO_T_INTERP =	12,
1224665Sab196087 	SINFO_T_CAP =		13,
123*11827SRod.Evans@Sun.COM 	SINFO_T_CAPINFO =	14,
124*11827SRod.Evans@Sun.COM 	SINFO_T_CAPCHAIN =	15,
125*11827SRod.Evans@Sun.COM 	SINFO_T_UNWIND =	16,
126*11827SRod.Evans@Sun.COM 	SINFO_T_MOVE =		17,
127*11827SRod.Evans@Sun.COM 	SINFO_T_REL =		18,
128*11827SRod.Evans@Sun.COM 	SINFO_T_RELA =		19,
129*11827SRod.Evans@Sun.COM 	SINFO_T_PREINITARR =	20,
130*11827SRod.Evans@Sun.COM 	SINFO_T_INITARR =	21,
131*11827SRod.Evans@Sun.COM 	SINFO_T_FINIARR =	22,
132*11827SRod.Evans@Sun.COM 	SINFO_T_NOTE =		23,
1334665Sab196087 
134*11827SRod.Evans@Sun.COM 	SINFO_T_NUM =		24 /* Count of items. Must come last */
1354665Sab196087 } SINFO_TYPE;
1364665Sab196087 
1374665Sab196087 
1384665Sab196087 
1394665Sab196087 /*
1404665Sab196087  * Table of per-section constant data used to set up the section
1414665Sab196087  * header cache and the various sub-parts it references. Indexed by
1424665Sab196087  * SINFO_T value.
1434665Sab196087  *
1444665Sab196087  * note: The sh_flags value should be either SHF_ALLOC, or 0.
1454665Sab196087  *	get_data() sets SHF_WRITE if the program header containing the
1464665Sab196087  *	section is writable. The other flags require information that
1474665Sab196087  *	the program headers don't contain (i.e. SHF_STRINGS, etc) so
1484665Sab196087  *	we don't set them.
1494665Sab196087  */
1504665Sab196087 typedef struct {
1514665Sab196087 	const char	*name;
1524665Sab196087 	Word		sh_type;
1534665Sab196087 	Word		sh_flags;
1544665Sab196087 	Word		sh_addralign;
1554665Sab196087 	Word		sh_entsize;
1564665Sab196087 	Elf_Type	libelf_type;
1574665Sab196087 } SINFO_DATA;
1584665Sab196087 
1596206Sab196087 /*
1606206Sab196087  * Many of these sections use an alignment given by M_WORD_ALIGN, a
1616206Sab196087  * value that varies depending on the object target machine. Since we
1626206Sab196087  * don't know that value at compile time, we settle for a value of
1636206Sab196087  * 4 for ELFCLASS32 objects, and 8 for ELFCLASS64. This matches the
1646206Sab196087  * platforms we current support (sparc and x86), and is good enough for
1656206Sab196087  * a fake section header in any event, as the resulting object is only
1666206Sab196087  * analyzed, and is not executed.
1676206Sab196087  */
1686206Sab196087 #ifdef _ELF64
1696206Sab196087 #define	FAKE_M_WORD_ALIGN 8
1706206Sab196087 #else
1716206Sab196087 #define	FAKE_M_WORD_ALIGN 4
1726206Sab196087 #endif
1736206Sab196087 
1744665Sab196087 static SINFO_DATA sinfo_data[SINFO_T_NUM] = {
1754665Sab196087 	/* SINFO_T_NULL */
1764665Sab196087 	{ 0 },
1774665Sab196087 
1784665Sab196087 	/* SINFO_T_DYN */
1794665Sab196087 	{ MSG_ORIG(MSG_PHDRNAM_DYN), SHT_DYNAMIC, SHF_ALLOC,
1806206Sab196087 	    FAKE_M_WORD_ALIGN, sizeof (Dyn), ELF_T_DYN },
1814665Sab196087 
1824665Sab196087 	/* SINFO_T_DYNSTR */
1834665Sab196087 	{ MSG_ORIG(MSG_PHDRNAM_DYNSTR), SHT_STRTAB, SHF_ALLOC,
1844665Sab196087 	    1, 0, ELF_T_BYTE },
1854665Sab196087 
1864665Sab196087 	/* SINFO_T_DYNSYM */
1874665Sab196087 	{ MSG_ORIG(MSG_PHDRNAM_DYNSYM), SHT_DYNSYM, SHF_ALLOC,
1886206Sab196087 	    FAKE_M_WORD_ALIGN, sizeof (Sym), ELF_T_SYM },
1894665Sab196087 
1904665Sab196087 	/* SINFO_T_LDYNSYM */
1914665Sab196087 	{ MSG_ORIG(MSG_PHDRNAM_LDYNSYM), SHT_SUNW_LDYNSYM, SHF_ALLOC,
1926206Sab196087 	    FAKE_M_WORD_ALIGN, sizeof (Sym), ELF_T_SYM },
1934665Sab196087 
1944665Sab196087 	/* SINFO_T_HASH */
1954665Sab196087 	{ MSG_ORIG(MSG_PHDRNAM_HASH), SHT_HASH, SHF_ALLOC,
1966206Sab196087 	    FAKE_M_WORD_ALIGN, sizeof (Word), ELF_T_WORD },
1974665Sab196087 
1984665Sab196087 	/* SINFO_T_SYMINFO */
1994665Sab196087 	{ MSG_ORIG(MSG_PHDRNAM_SYMINFO),  SHT_SUNW_syminfo, SHF_ALLOC,
2006206Sab196087 	    FAKE_M_WORD_ALIGN, sizeof (Syminfo), ELF_T_SYMINFO },
2014665Sab196087 
2024665Sab196087 	/* SINFO_T_SYMSORT */
2034665Sab196087 	{ MSG_ORIG(MSG_PHDRNAM_SYMSORT), SHT_SUNW_symsort, SHF_ALLOC,
2046206Sab196087 	    FAKE_M_WORD_ALIGN, sizeof (Word), ELF_T_WORD },
2054665Sab196087 
2064665Sab196087 	/* SINFO_T_TLSSORT */
2074665Sab196087 	{ MSG_ORIG(MSG_PHDRNAM_TLSSORT), SHT_SUNW_tlssort, SHF_ALLOC,
2086206Sab196087 	    FAKE_M_WORD_ALIGN, sizeof (Word), ELF_T_WORD },
2094665Sab196087 
2104665Sab196087 	/* SINFO_T_VERNEED */
2114665Sab196087 	{ MSG_ORIG(MSG_PHDRNAM_VER), SHT_SUNW_verneed, SHF_ALLOC,
2126206Sab196087 	    FAKE_M_WORD_ALIGN, 1, ELF_T_VNEED },
2134665Sab196087 
2144665Sab196087 	/* SINFO_T_VERDEF */
2154665Sab196087 	{ MSG_ORIG(MSG_PHDRNAM_VER), SHT_SUNW_verdef, SHF_ALLOC,
2166206Sab196087 	    FAKE_M_WORD_ALIGN, 1, ELF_T_VDEF },
2174665Sab196087 
2184665Sab196087 	/* SINFO_T_VERSYM */
2194665Sab196087 	{ MSG_ORIG(MSG_PHDRNAM_VER), SHT_SUNW_versym, SHF_ALLOC,
2206206Sab196087 	    FAKE_M_WORD_ALIGN, sizeof (Versym), ELF_T_HALF },
2214665Sab196087 
2224665Sab196087 	/* SINFO_T_INTERP */
2234665Sab196087 	{ MSG_ORIG(MSG_PHDRNAM_INTERP), SHT_PROGBITS, SHF_ALLOC,
2244665Sab196087 	    1, 0, ELF_T_BYTE },
2254665Sab196087 
2264665Sab196087 	/* SINFO_T_CAP */
2274665Sab196087 	{ MSG_ORIG(MSG_PHDRNAM_CAP), SHT_SUNW_cap, SHF_ALLOC,
2284665Sab196087 	    sizeof (Addr), sizeof (Cap), ELF_T_CAP },
2294665Sab196087 
230*11827SRod.Evans@Sun.COM 	/* SINFO_T_CAPINFO */
231*11827SRod.Evans@Sun.COM 	{ MSG_ORIG(MSG_PHDRNAM_CAPINFO), SHT_SUNW_capinfo, SHF_ALLOC,
232*11827SRod.Evans@Sun.COM 	    FAKE_M_WORD_ALIGN, sizeof (Capinfo), ELF_T_WORD },
233*11827SRod.Evans@Sun.COM 
234*11827SRod.Evans@Sun.COM 	/* SINFO_T_CAPCHAIN */
235*11827SRod.Evans@Sun.COM 	{ MSG_ORIG(MSG_PHDRNAM_CAPCHAIN), SHT_SUNW_capchain, SHF_ALLOC,
236*11827SRod.Evans@Sun.COM 	    FAKE_M_WORD_ALIGN, sizeof (Capchain), ELF_T_WORD },
237*11827SRod.Evans@Sun.COM 
2384665Sab196087 	/* SINFO_T_UNWIND */
2394665Sab196087 	{ MSG_ORIG(MSG_PHDRNAM_UNWIND), SHT_AMD64_UNWIND, SHF_ALLOC,
2404665Sab196087 	    sizeof (Addr), 0, ELF_T_BYTE },
2414665Sab196087 
2424665Sab196087 	/* SINFO_T_MOVE */
2434665Sab196087 	{ MSG_ORIG(MSG_PHDRNAM_MOVE), SHT_SUNW_move, SHF_ALLOC,
244*11827SRod.Evans@Sun.COM 	    sizeof (Lword), sizeof (Move), ELF_T_MOVE },
2454665Sab196087 
2464665Sab196087 	/* SINFO_T_REL */
2474665Sab196087 	{ MSG_ORIG(MSG_PHDRNAM_REL), SHT_REL, SHF_ALLOC,
2486206Sab196087 	    FAKE_M_WORD_ALIGN, sizeof (Rel), ELF_T_REL },
2494665Sab196087 
2504665Sab196087 	/* SINFO_T_RELA */
2514665Sab196087 	{ MSG_ORIG(MSG_PHDRNAM_RELA), SHT_RELA, SHF_ALLOC,
2526206Sab196087 	    FAKE_M_WORD_ALIGN, sizeof (Rela), ELF_T_RELA },
2534665Sab196087 
2544665Sab196087 	/* SINFO_T_PREINITARR */
2554665Sab196087 	{ MSG_ORIG(MSG_PHDRNAM_PREINITARR), SHT_PREINIT_ARRAY, SHF_ALLOC,
2564665Sab196087 	    sizeof (Addr), sizeof (Addr), ELF_T_ADDR },
2574665Sab196087 
2584665Sab196087 	/* SINFO_T_INITARR */
2594665Sab196087 	{ MSG_ORIG(MSG_PHDRNAM_INITARR), SHT_INIT_ARRAY, SHF_ALLOC,
2604665Sab196087 	    sizeof (Addr), sizeof (Addr),  ELF_T_ADDR },
2614665Sab196087 
2624665Sab196087 	/* SINFO_T_FINIARR */
2634665Sab196087 	{ MSG_ORIG(MSG_PHDRNAM_FINIARR), SHT_FINI_ARRAY, SHF_ALLOC,
2644665Sab196087 	    sizeof (Addr), sizeof (Addr), ELF_T_ADDR },
2654665Sab196087 
2664665Sab196087 	/* SINFO_T_NOTE */
2674665Sab196087 	{ MSG_ORIG(MSG_PHDRNAM_NOTE), SHT_NOTE, 0,
2686206Sab196087 	    FAKE_M_WORD_ALIGN, 1, ELF_T_NOTE }
2694665Sab196087 };
2704665Sab196087 
2714665Sab196087 
2724665Sab196087 
2734665Sab196087 
2744665Sab196087 
2754665Sab196087 /*
2764665Sab196087  * As we read program headers and dynamic elements, we build up
2774665Sab196087  * the data for our fake section headers in variables of the
2784665Sab196087  * SINFO type. SINFO is used to track the sections that can only
2794665Sab196087  * appear a fixed number of times (usually once).
2804665Sab196087  *
2814665Sab196087  * SINFO_LISTELT is used for sections that can occur an arbitrary
2824665Sab196087  * number of times. They are kept in a doubly linked circular
2834665Sab196087  * buffer.
2844665Sab196087  */
2854665Sab196087 typedef struct {
2864665Sab196087 	SINFO_TYPE	type;	/* Our type code for the section */
2874665Sab196087 	Addr		vaddr;	/* Virtual memory address */
2884665Sab196087 	Off		offset;	/* File offset of data. Ignored unless */
2894665Sab196087 				/*	vaddr is 0. Used by program headers */
2904665Sab196087 	size_t		size;	/* # bytes in section */
2914665Sab196087 	size_t		vercnt;	/* Used by verdef and verneed to hold count */
2924665Sab196087 	Shdr		*shdr;	/* Constructed shdr */
2934665Sab196087 	Elf_Data	*data;	/* Constructed data descriptor */
2944665Sab196087 } SINFO;
2954665Sab196087 
2964665Sab196087 typedef struct _sinfo_listelt {
2974665Sab196087 	struct _sinfo_listelt	*next;
2984665Sab196087 	struct _sinfo_listelt	*prev;
2994665Sab196087 	SINFO			sinfo;
3004665Sab196087 } SINFO_LISTELT;
3014665Sab196087 
3024665Sab196087 
3034665Sab196087 
3044665Sab196087 /*
3054665Sab196087  * Free dynamic memory used by SINFO structures.
3064665Sab196087  *
3074665Sab196087  * entry:
3084665Sab196087  *	sinfo - Address of first SINFO structure to free
3094665Sab196087  *	n - # of structures to clear
3104665Sab196087  *
3114665Sab196087  * exit:
3124665Sab196087  *	For each SINFO struct, the section header, data descriptor,
3134665Sab196087  *	and data buffer are freed if non-NULL. The relevant
3144665Sab196087  *	fields are set to NULL, and the type is set to SINFO_T_NULL.
3154665Sab196087  */
3164665Sab196087 static void
sinfo_free(SINFO * sinfo,size_t n)3174665Sab196087 sinfo_free(SINFO *sinfo, size_t n)
3184665Sab196087 {
3194665Sab196087 	for (; n-- > 0; sinfo++) {
3204665Sab196087 		if (sinfo->data != NULL) {
3214665Sab196087 			if (sinfo->data->d_buf != NULL)
3224665Sab196087 				free(sinfo->data->d_buf);
3234665Sab196087 			free(sinfo->data);
3244665Sab196087 			sinfo->data = NULL;
3254665Sab196087 		}
3264665Sab196087 
3274665Sab196087 		if (sinfo->shdr) {
3284665Sab196087 			free(sinfo->shdr);
3294665Sab196087 			sinfo->shdr = NULL;
3304665Sab196087 		}
3314665Sab196087 		sinfo->type = SINFO_T_NULL;
3324665Sab196087 	}
3334665Sab196087 }
3344665Sab196087 
3354665Sab196087 
3364665Sab196087 
3374665Sab196087 /*
3384665Sab196087  * Allocate a new SINFO_LISTELT and put it at the end of the
3394665Sab196087  * doubly linked list anchored by the given list root node.
3404665Sab196087  *
3414665Sab196087  * On success, a new node has been put at the end of the circular
3424665Sab196087  * doubly linked list, and a pointer to the SINFO sub-structure is
3434665Sab196087  * returned. On failure, an error is printed, and NULL is returned.
3444665Sab196087  */
3454665Sab196087 
3464665Sab196087 static SINFO *
sinfo_list_alloc(FSTATE * fstate,SINFO_LISTELT * root)3474665Sab196087 sinfo_list_alloc(FSTATE *fstate, SINFO_LISTELT *root)
3484665Sab196087 {
3494665Sab196087 	SINFO_LISTELT *elt;
3504665Sab196087 
3514665Sab196087 	if ((elt = malloc(sizeof (*elt))) == NULL) {
3524665Sab196087 		int err = errno;
3534665Sab196087 		(void) fprintf(stderr, MSG_INTL(MSG_ERR_MALLOC),
3544665Sab196087 		    fstate->file, strerror(err));
3554665Sab196087 		return (0);
3564665Sab196087 	}
3574665Sab196087 
3584665Sab196087 	elt->next = root;
3594665Sab196087 	elt->prev = root->prev;
3604665Sab196087 
3614665Sab196087 	root->prev = elt;
3624665Sab196087 	elt->prev->next = elt;
3634665Sab196087 
3644665Sab196087 	bzero(&elt->sinfo, sizeof (elt->sinfo));
3654665Sab196087 	return (&elt->sinfo);
3664665Sab196087 }
3674665Sab196087 
3684665Sab196087 
3694665Sab196087 
3704665Sab196087 /*
3714665Sab196087  * Release the memory used by the given list, restoring it to
3724665Sab196087  * an empty list.
3734665Sab196087  */
3744665Sab196087 static void
sinfo_list_free_all(SINFO_LISTELT * root)3754665Sab196087 sinfo_list_free_all(SINFO_LISTELT *root)
3764665Sab196087 {
3774665Sab196087 	SINFO_LISTELT *elt;
3784665Sab196087 
3794665Sab196087 	for (elt = root->next; elt != root; elt = elt->next)
3804665Sab196087 		sinfo_free(&elt->sinfo, 1);
3814665Sab196087 
3824665Sab196087 	root->next = root->prev = root;
3834665Sab196087 }
3844665Sab196087 
3854665Sab196087 
3864665Sab196087 
3874665Sab196087 /*
3884665Sab196087  * Given a virtual address and desired size of the data to be found
3894665Sab196087  * at that address, look through the program headers for the PT_LOAD
3904665Sab196087  * segment that contains it and return the offset within the ELF file
3914665Sab196087  * at which it resides.
3924665Sab196087  *
3934665Sab196087  * entry:
3944665Sab196087  *	fstate - Object state
3954665Sab196087  *	addr - virtual address to be translated
3964665Sab196087  *	size - Size of the data to be found at that address, in bytes
3974665Sab196087  *	zero_bytes - NULL, or address to receive the number of data
3984665Sab196087  *		bytes at the end of the data that are not contained
3994665Sab196087  *		in the file, and which must be zero filled by the caller.
4004665Sab196087  *		If zero_bytes is NULL, the file must contain all of the
4014665Sab196087  *		desired data. If zero_bytes is not NULL, then the program
4024665Sab196087  *		header must reserve the space for all of the data (p_memsz)
4034665Sab196087  *		but it is acceptable for only part of the data to be in
4044665Sab196087  *		the file (p_filesz). *zero_bytes is set to the difference
4054665Sab196087  *		in size, and is the number of bytes the caller must
4064665Sab196087  *		set to 0 rather than reading from the file.
4074665Sab196087  *	phdr_ret - NULL, or address of variable to receive pointer
4084665Sab196087  *		to program header that contains offset.
4094665Sab196087  * exit:
4104665Sab196087  *	On success: If zero_bytes is non-NULL, it is updated. If phdr_ret
4114665Sab196087  *	is non-NULL, it is updated. The file offset is returned.
4124665Sab196087  *
4134665Sab196087  *	On failure, 0 is returned. Since any ELF file we can understand
4144665Sab196087  *	must start with an ELF magic number, 0 cannot be a valid file
4154665Sab196087  *	offset for a virtual address, and is therefore unambiguous as
4164665Sab196087  *	a failure indication.
4174665Sab196087  */
4184665Sab196087 static Off
map_addr_to_offset(FSTATE * fstate,Addr addr,size_t size,size_t * zero_bytes,Phdr ** phdr_ret)4194665Sab196087 map_addr_to_offset(FSTATE *fstate, Addr addr, size_t size, size_t *zero_bytes,
4204665Sab196087     Phdr **phdr_ret)
4214665Sab196087 {
4224665Sab196087 	Off	offset;
4234665Sab196087 	Addr	end_addr = addr + size;
4244665Sab196087 	size_t	avail_file;
4254665Sab196087 	Phdr	*phdr = fstate->phdr;
4264665Sab196087 	size_t	phnum = fstate->phnum;
4274665Sab196087 
4284665Sab196087 	for (; phnum--; phdr++) {
4294665Sab196087 		if (phdr->p_type != PT_LOAD)
4304665Sab196087 			continue;
4314665Sab196087 
4324665Sab196087 		if ((addr >= phdr->p_vaddr) &&
4334665Sab196087 		    (end_addr <= (phdr->p_vaddr + phdr->p_memsz))) {
4344665Sab196087 			/*
4354665Sab196087 			 * Subtract segment virtual address, leaving the
4364665Sab196087 			 * offset relative to the segment (not the file).
4374665Sab196087 			 */
4384665Sab196087 			offset = addr - phdr->p_vaddr;
4394665Sab196087 			avail_file = phdr->p_filesz - offset;
4404665Sab196087 
4414665Sab196087 			/*
4424665Sab196087 			 * The addr/size are in bounds for this segment.
4434665Sab196087 			 * Is there enough data in the file to satisfy
4444665Sab196087 			 * the request? If zero_bytes is NULL, it must
4454665Sab196087 			 * all be in the file. Otherwise it can be
4464665Sab196087 			 * zero filled.
4474665Sab196087 			 */
4484665Sab196087 			if (zero_bytes == NULL) {
4494665Sab196087 				if (size > avail_file)
4504665Sab196087 					continue;
4514665Sab196087 			} else {
4524665Sab196087 				*zero_bytes = (size > avail_file) ?
4534665Sab196087 				    (size - avail_file) : 0;
4544665Sab196087 			}
4554665Sab196087 
4564665Sab196087 			if (phdr_ret != NULL)
4574665Sab196087 				*phdr_ret = phdr;
4584665Sab196087 
4594665Sab196087 			/* Add segment file offset, giving overall offset */
4604665Sab196087 			return (phdr->p_offset + offset);
4614665Sab196087 		}
4624665Sab196087 	}
4634665Sab196087 
4644665Sab196087 	/* If we get here, the mapping failed */
4654665Sab196087 	return (0);
4664665Sab196087 }
4674665Sab196087 
4684665Sab196087 
4694665Sab196087 
4704665Sab196087 /*
4714665Sab196087  * This routine is the same thing as map_addr_to_offset(), except that
4724665Sab196087  * it goes the other way, mapping from offset to virtual address.
4734665Sab196087  *
4744665Sab196087  * The comments for map_addr_to_offset() are applicable if you
4754665Sab196087  * reverse offset and address.
4764665Sab196087  */
4774665Sab196087 
4784665Sab196087 static Addr
map_offset_to_addr(FSTATE * fstate,Off offset,size_t size,size_t * zero_bytes,Phdr ** phdr_ret)4794665Sab196087 map_offset_to_addr(FSTATE *fstate, Off offset, size_t size, size_t *zero_bytes,
4804665Sab196087     Phdr **phdr_ret)
4814665Sab196087 {
4824665Sab196087 	Off	end_offset = offset + size;
4834665Sab196087 	size_t	avail_file;
4844665Sab196087 	Phdr	*phdr = fstate->phdr;
4854665Sab196087 	size_t	phnum = fstate->phnum;
4864665Sab196087 
4874665Sab196087 	for (; phnum--; phdr++) {
4884665Sab196087 		if (phdr->p_type != PT_LOAD)
4894665Sab196087 			continue;
4904665Sab196087 
4914665Sab196087 		if ((offset >= phdr->p_offset) &&
4924665Sab196087 		    (end_offset <= (phdr->p_offset + phdr->p_memsz))) {
4934665Sab196087 			/*
4944665Sab196087 			 * Subtract segment offset, leaving the
4954665Sab196087 			 * offset relative to the segment (not the file).
4964665Sab196087 			 */
4974665Sab196087 			offset -= phdr->p_offset;
4984665Sab196087 			avail_file = phdr->p_filesz - offset;
4994665Sab196087 
5004665Sab196087 			/*
5014665Sab196087 			 * The offset/size are in bounds for this segment.
5024665Sab196087 			 * Is there enough data in the file to satisfy
5034665Sab196087 			 * the request? If zero_bytes is NULL, it must
5044665Sab196087 			 * all be in the file. Otherwise it can be
5054665Sab196087 			 * zero filled.
5064665Sab196087 			 */
5074665Sab196087 			if (zero_bytes == NULL) {
5084665Sab196087 				if (size > avail_file)
5094665Sab196087 					continue;
5104665Sab196087 			} else {
5114665Sab196087 				*zero_bytes = (size > avail_file) ?
5124665Sab196087 				    (size - avail_file) : 0;
5134665Sab196087 			}
5144665Sab196087 
5154665Sab196087 			if (phdr_ret != NULL)
5164665Sab196087 				*phdr_ret = phdr;
5174665Sab196087 
5184665Sab196087 			/* Add segment virtual address, giving overall addr */
5194665Sab196087 			return (phdr->p_vaddr + offset);
5204665Sab196087 		}
5214665Sab196087 	}
5224665Sab196087 
5234665Sab196087 	/* If we get here, the mapping failed */
5244665Sab196087 	return (0);
5254665Sab196087 }
5264665Sab196087 
5274665Sab196087 
5284665Sab196087 
5294665Sab196087 /*
5304665Sab196087  * Use elf_xlatetom() to convert the bytes in buf from their
5314665Sab196087  * in-file representation to their in-memory representation.
5324665Sab196087  *
5334665Sab196087  * Returns True(1) for success. On failure, an error message is printed
5344665Sab196087  * and False(0) is returned.
5354665Sab196087  */
5364665Sab196087 static int
xlate_data(FSTATE * fstate,void * buf,size_t nbyte,Elf_Type xlate_type)5374665Sab196087 xlate_data(FSTATE *fstate, void *buf, size_t nbyte, Elf_Type xlate_type)
5384665Sab196087 {
5394665Sab196087 	Elf_Data	data;
5404665Sab196087 
5414665Sab196087 	data.d_type = xlate_type;
5424665Sab196087 	data.d_size = nbyte;
5434665Sab196087 	data.d_off = 0;
5444665Sab196087 	data.d_align = 0;
5454665Sab196087 	data.d_version = fstate->ehdr->e_version;
5464665Sab196087 	data.d_buf = buf;
5474665Sab196087 
5484665Sab196087 	if (elf_xlatetom(&data, &data,
5494665Sab196087 	    fstate->ehdr->e_ident[EI_DATA]) == NULL) {
5504665Sab196087 		failure(fstate->file, MSG_ORIG(MSG_ELF_XLATETOM));
5514665Sab196087 		return (0);
5524665Sab196087 	}
5534665Sab196087 
5544665Sab196087 	return (1);
5554665Sab196087 }
5564665Sab196087 
5574665Sab196087 
5584665Sab196087 /*
5594665Sab196087  * Read nbytes of data into buf, starting at the specified offset
5604665Sab196087  * within the ELF file.
5614665Sab196087  *
5624665Sab196087  * entry:
5634665Sab196087  *	fstate - Object state
5644665Sab196087  *	offset - Offset within the file at which desired data resides.
5654665Sab196087  *	buf - Buffer to receive the data
5664665Sab196087  *	nbyte - # of bytes to read into buf
5674665Sab196087  *	xlate_type - An ELF xlate type, specifying the type of data
5684665Sab196087  *		being input. If xlate_type is ELF_T_BYTE, xlate is not
5694665Sab196087  *		done. Otherwise, xlate_data() is called to convert the
5704665Sab196087  *		data into its in-memory representation.
5714665Sab196087  * exit:
5724665Sab196087  *	On success, the data has been written into buf, xlate_data()
5734665Sab196087  *	called on it if required, and True(1) is returned. Otherwise
5744665Sab196087  *	False(0) is returned.
5754665Sab196087  *
5764665Sab196087  * note:
5774665Sab196087  *	This routine does not move the file pointer.
5784665Sab196087  */
5794665Sab196087 static int
read_data(FSTATE * fstate,Off offset,void * buf,size_t nbyte,Elf_Type xlate_type)5804665Sab196087 read_data(FSTATE *fstate, Off offset, void *buf, size_t nbyte,
5814665Sab196087     Elf_Type xlate_type)
5824665Sab196087 {
5834665Sab196087 	if (pread(fstate->fd, buf, nbyte, offset) != nbyte) {
5844665Sab196087 		int err = errno;
5854665Sab196087 
5864665Sab196087 		(void) fprintf(stderr, MSG_INTL(MSG_ERR_READ),
5874665Sab196087 		    fstate->file, strerror(err));
5884665Sab196087 		return (0);
5894665Sab196087 	}
5904665Sab196087 
5914665Sab196087 	if (xlate_type != ELF_T_BYTE)
5924665Sab196087 		return (xlate_data(fstate, buf, nbyte, xlate_type));
5934665Sab196087 
5944665Sab196087 	return (1);
5954665Sab196087 }
5964665Sab196087 
5974665Sab196087 
5984665Sab196087 
5994665Sab196087 /*
6004665Sab196087  * Read the hash nbucket/nchain values from the start of the hash
6014665Sab196087  * table found at the given virtual address in the mapped ELF object.
6024665Sab196087  *
6034665Sab196087  * On success, *nbucket, and *nchain have been filled in with their
6044665Sab196087  * values, *total contains the number of elements in the hash table,
6054665Sab196087  * and this routine returns True (1).
6064665Sab196087  *
6074665Sab196087  * On failure, False (0) is returned.
6084665Sab196087  */
6094665Sab196087 static int
hash_size(FSTATE * fstate,SINFO * hash_sinfo,Word * nbucket,Word * nchain,size_t * total)6104665Sab196087 hash_size(FSTATE *fstate, SINFO *hash_sinfo,
6114665Sab196087     Word *nbucket, Word *nchain, size_t *total)
6124665Sab196087 {
6134665Sab196087 	Off		offset;
6144665Sab196087 	Word		buf[2];
6154665Sab196087 
6164665Sab196087 	offset = map_addr_to_offset(fstate, hash_sinfo->vaddr,
6174665Sab196087 	    sizeof (buf), NULL, NULL);
6184665Sab196087 	if (offset == 0)
6194665Sab196087 		return (0);
6204665Sab196087 
6214665Sab196087 	if (read_data(fstate, offset, buf, sizeof (buf), ELF_T_WORD) == 0)
6224665Sab196087 		return (0);
6234665Sab196087 
6244665Sab196087 	*nbucket = buf[0];
6254665Sab196087 	*nchain = buf[1];
6264665Sab196087 	*total = 2 + *nbucket + *nchain;
6274665Sab196087 	return (1);
6284665Sab196087 }
6294665Sab196087 
6304665Sab196087 
6314665Sab196087 
6324665Sab196087 /*
6334665Sab196087  * Read a Verdef structure at the specified file offset and return
6344665Sab196087  * its vd_cnt, vd_aux, and vd_next fields.
6354665Sab196087  */
6364665Sab196087 static int
read_verdef(FSTATE * fstate,Off offset,Half * cnt,Word * aux,Word * next)6374665Sab196087 read_verdef(FSTATE *fstate, Off offset, Half *cnt, Word *aux, Word *next)
6384665Sab196087 {
6394665Sab196087 	Verdef		verdef;
6404665Sab196087 
6414665Sab196087 	if (read_data(fstate, offset, &verdef, sizeof (verdef),
6424665Sab196087 	    ELF_T_BYTE) == 0)
6434665Sab196087 		return (0);
6444665Sab196087 
6454665Sab196087 	/* xlate vd_cnt */
6464665Sab196087 	if (xlate_data(fstate, &verdef.vd_cnt, sizeof (verdef.vd_cnt),
6474665Sab196087 	    ELF_T_HALF) == 0)
6484665Sab196087 		return (0);
6494665Sab196087 
6504665Sab196087 	/*
6514665Sab196087 	 * xlate vd_aux and vd_next. These items are adjacent and are
6524665Sab196087 	 * both Words, so they can be handled in a single operation.
6534665Sab196087 	 */
6544665Sab196087 	if (xlate_data(fstate, &verdef.vd_aux,
6554665Sab196087 	    2 * sizeof (Word), ELF_T_WORD) == 0)
6564665Sab196087 		return (0);
6574665Sab196087 
6584665Sab196087 	*cnt = verdef.vd_cnt;
6594665Sab196087 	*aux = verdef.vd_aux;
6604665Sab196087 	*next = verdef.vd_next;
6614665Sab196087 
6624665Sab196087 	return (1);
6634665Sab196087 }
6644665Sab196087 
6654665Sab196087 
6664665Sab196087 
6674665Sab196087 /*
6684665Sab196087  * Read a Verdaux structure at the specified file offset and return
6694665Sab196087  * its vda_next field.
6704665Sab196087  */
6714665Sab196087 static int
read_verdaux(FSTATE * fstate,Off offset,Word * next)6724665Sab196087 read_verdaux(FSTATE *fstate, Off offset, Word *next)
6734665Sab196087 {
6744665Sab196087 	Verdaux		verdaux;
6754665Sab196087 
6764665Sab196087 	if (read_data(fstate, offset, &verdaux, sizeof (verdaux),
6774665Sab196087 	    ELF_T_BYTE) == 0)
6784665Sab196087 		return (0);
6794665Sab196087 
6804665Sab196087 	/* xlate vda_next */
6814665Sab196087 	if (xlate_data(fstate, &verdaux.vda_next, sizeof (verdaux.vda_next),
6824665Sab196087 	    ELF_T_WORD) == 0)
6834665Sab196087 		return (0);
6844665Sab196087 
6854665Sab196087 	*next = verdaux.vda_next;
6864665Sab196087 
6874665Sab196087 	return (1);
6884665Sab196087 }
6894665Sab196087 
6904665Sab196087 
6914665Sab196087 
6924665Sab196087 /*
6934665Sab196087  * Read a Verneed structure at the specified file offset and return
6944665Sab196087  * its vn_cnt, vn_aux, and vn_next fields.
6954665Sab196087  */
6964665Sab196087 static int
read_verneed(FSTATE * fstate,Off offset,Half * cnt,Word * aux,Word * next)6974665Sab196087 read_verneed(FSTATE *fstate, Off offset, Half *cnt, Word *aux, Word *next)
6984665Sab196087 {
6994665Sab196087 	Verneed		verneed;
7004665Sab196087 
7014665Sab196087 	if (read_data(fstate, offset, &verneed, sizeof (verneed),
7024665Sab196087 	    ELF_T_BYTE) == 0)
7034665Sab196087 		return (0);
7044665Sab196087 
7054665Sab196087 	/* xlate vn_cnt */
7064665Sab196087 	if (xlate_data(fstate, &verneed.vn_cnt, sizeof (verneed.vn_cnt),
7074665Sab196087 	    ELF_T_HALF) == 0)
7084665Sab196087 		return (0);
7094665Sab196087 
7104665Sab196087 	/*
7114665Sab196087 	 * xlate vn_aux and vn_next. These items are adjacent and are
7124665Sab196087 	 * both Words, so they can be handled in a single operation.
7134665Sab196087 	 */
7144665Sab196087 	if (xlate_data(fstate, &verneed.vn_aux,
7154665Sab196087 	    2 * sizeof (Word), ELF_T_WORD) == 0)
7164665Sab196087 		return (0);
7174665Sab196087 
7184665Sab196087 	*cnt = verneed.vn_cnt;
7194665Sab196087 	*aux = verneed.vn_aux;
7204665Sab196087 	*next = verneed.vn_next;
7214665Sab196087 
7224665Sab196087 	return (1);
7234665Sab196087 }
7244665Sab196087 
7254665Sab196087 
7264665Sab196087 
7274665Sab196087 /*
7284665Sab196087  * Read a Vernaux structure at the specified file offset and return
7294665Sab196087  * its vna_next field.
7304665Sab196087  */
7314665Sab196087 static int
read_vernaux(FSTATE * fstate,Off offset,Word * next)7324665Sab196087 read_vernaux(FSTATE *fstate, Off offset, Word *next)
7334665Sab196087 {
7344665Sab196087 	Vernaux		vernaux;
7354665Sab196087 
7364665Sab196087 	if (read_data(fstate, offset, &vernaux, sizeof (vernaux),
7374665Sab196087 	    ELF_T_BYTE) == 0)
7384665Sab196087 		return (0);
7394665Sab196087 
7404665Sab196087 	/* xlate vna_next */
7414665Sab196087 	if (xlate_data(fstate, &vernaux.vna_next, sizeof (vernaux.vna_next),
7424665Sab196087 	    ELF_T_WORD) == 0)
7434665Sab196087 		return (0);
7444665Sab196087 
7454665Sab196087 	*next = vernaux.vna_next;
7464665Sab196087 
7474665Sab196087 	return (1);
7484665Sab196087 }
7494665Sab196087 
7504665Sab196087 
7514665Sab196087 
7524665Sab196087 /*
7534665Sab196087  * Compute the size of Verdef and Verneed sections. Both of these
7544665Sab196087  * sections are made up of interleaved main nodes (Verdef and Verneed)
7554665Sab196087  * and auxiliary blocks (Verdaux and Vernaux). These nodes refer to
7564665Sab196087  * each other by relative offsets. The linker has a lot of flexibility
7574665Sab196087  * in how it lays out these items, and we cannot assume a standard
7584665Sab196087  * layout. To determine the size of the section, we must read each
7594665Sab196087  * main node and compute the high water mark of the memory it and its
7604665Sab196087  * auxiliary structs access.
7614665Sab196087  *
7624665Sab196087  * Although Verdef/Verdaux and Verneed/Vernaux are different types,
7634665Sab196087  * their logical organization is the same. Each main block has
7644665Sab196087  * a cnt field that tells how many auxiliary blocks it has, an
7654665Sab196087  * aux field that gives the offset of the first auxiliary block, and
7664665Sab196087  * an offset to the next main block. Each auxiliary block contains
7674665Sab196087  * an offset to the next auxiliary block. By breaking the type specific
7684665Sab196087  * code into separate sub-functions, we can process both Verdef and
7694665Sab196087  * sections Verdaux from a single routine.
7704665Sab196087  *
7714665Sab196087  * entry:
7724665Sab196087  *	fstate - Object state
7734665Sab196087  *	sec - Section to be processed (SINFO_T_VERDEF or SINFO_T_VERNEED).
7744665Sab196087  *
7754665Sab196087  * exit:
7764665Sab196087  *	On success, sec->size is set to the section size in bytes, and
7774665Sab196087  *	True (1) is returned. On failure, False (0) is returned.
7784665Sab196087  */
7794665Sab196087 static int
verdefneed_size(FSTATE * fstate,SINFO * sec)7804665Sab196087 verdefneed_size(FSTATE *fstate, SINFO *sec)
7814665Sab196087 {
7824665Sab196087 	int (* read_main)(FSTATE *, Off, Half *, Word *, Word *);
7834665Sab196087 	int (* read_aux)(FSTATE *, Off, Word *);
7844665Sab196087 	size_t	size_main, size_aux;
7854665Sab196087 
7864665Sab196087 	Off	offset, aux_offset;
7874665Sab196087 	Off	highwater, extent;
7884665Sab196087 	size_t	num_main = sec->vercnt;
7894665Sab196087 	Half	v_cnt;
7904665Sab196087 	Word	v_aux, v_next, va_next;
7914665Sab196087 
7924665Sab196087 
7934665Sab196087 	/*
7944665Sab196087 	 * Set up the function pointers to the type-specific code
7954665Sab196087 	 * for fetching data from the main and auxiliary blocks.
7964665Sab196087 	 */
7974665Sab196087 	if (sec->type == SINFO_T_VERDEF) {
7984665Sab196087 		read_main = read_verdef;
7994665Sab196087 		read_aux = read_verdaux;
8004665Sab196087 		size_main = sizeof (Verdef);
8014665Sab196087 		size_aux = sizeof (Verdaux);
8024665Sab196087 	} else {			/* SINFO_T_VERNEED */
8034665Sab196087 		read_main = read_verneed;
8044665Sab196087 		read_aux = read_vernaux;
8054665Sab196087 		size_main = sizeof (Verneed);
8064665Sab196087 		size_aux = sizeof (Vernaux);
8074665Sab196087 	}
8084665Sab196087 
8094665Sab196087 	/*
8104665Sab196087 	 * Map starting address to file offset. Save the starting offset
8114665Sab196087 	 * in the SINFO size field. Once we have the high water offset, we
8124665Sab196087 	 * can subtract this from it to get the size.
8134665Sab196087 	 *
8144665Sab196087 	 * Note: The size argument set here is a lower bound --- the
8154665Sab196087 	 * size of the main blocks without any auxiliary ones. It's
8164665Sab196087 	 * the best we can do until the size has been determined for real.
8174665Sab196087 	 */
8184665Sab196087 	offset = highwater = map_addr_to_offset(fstate, sec->vaddr,
8194665Sab196087 	    size_main * num_main, NULL, NULL);
8204665Sab196087 	if (offset == 0)
8214665Sab196087 		return (0);
8224665Sab196087 	sec->size = offset;
8234665Sab196087 
8244665Sab196087 	for (; num_main-- > 0; offset += v_next) {
8254665Sab196087 		/* Does this move the high water mark up? */
8264665Sab196087 		extent = offset + size_main;
8274665Sab196087 		if (extent > highwater)
8284665Sab196087 			highwater = extent;
8294665Sab196087 
8304665Sab196087 		if ((*read_main)(fstate, offset, &v_cnt, &v_aux, &v_next) == 0)
8314665Sab196087 			return (0);
8324665Sab196087 
8334665Sab196087 		/*
8344665Sab196087 		 * If there are auxiliary structures referenced,
8354665Sab196087 		 * check their position to see if it pushes
8364665Sab196087 		 * the high water mark.
8374665Sab196087 		 */
8384665Sab196087 		aux_offset = offset + v_aux;
8394665Sab196087 		for (; v_cnt-- > 0; aux_offset += va_next) {
8404665Sab196087 			extent = aux_offset + size_aux;
8414665Sab196087 			if (extent > highwater)
8424665Sab196087 				highwater = extent;
8434665Sab196087 
8444665Sab196087 			if ((*read_aux)(fstate, aux_offset, &va_next) == 0)
8454665Sab196087 				return (0);
8464665Sab196087 		}
8474665Sab196087 	}
8484665Sab196087 
8494665Sab196087 	sec->size = highwater - sec->size;
8504665Sab196087 	return (1);
8514665Sab196087 }
8524665Sab196087 
8534665Sab196087 
8544665Sab196087 /*
8554665Sab196087  * Allocate and fill in a fake section header, data descriptor,
8564665Sab196087  * and data buffer for the given section. Fill them in and read
8574665Sab196087  * the associated data into the buffer.
8584665Sab196087  *
8594665Sab196087  * entry:
8604665Sab196087  *	fstate - Object state
8614665Sab196087  *	sec - Section information
8624665Sab196087  *
8634665Sab196087  * exit:
8644665Sab196087  *	On success, the actions described above are complete, and
8654665Sab196087  *	True (1) is returned.
8664665Sab196087  *
8674665Sab196087  *	On failure, an error is reported, all resources used by sec
8684665Sab196087  *	are released, and sec->type is set to SINFO_T_NULL, effectively
8694665Sab196087  *	eliminating its contents from any further use. False (0) is
8704665Sab196087  *	returned.
8714665Sab196087  */
8724665Sab196087 static int
get_data(FSTATE * fstate,SINFO * sec)8734665Sab196087 get_data(FSTATE *fstate, SINFO *sec)
8744665Sab196087 {
8754665Sab196087 
8764665Sab196087 	SINFO_DATA	*tinfo;
8774665Sab196087 	size_t		read_bytes, zero_bytes;
8784665Sab196087 	Phdr		*phdr = NULL;
8794665Sab196087 
8804665Sab196087 	/*
8814665Sab196087 	 * If this is a NULL section, or if we've already processed
8824665Sab196087 	 * this item, then we are already done.
8834665Sab196087 	 */
8844665Sab196087 	if ((sec->type == SINFO_T_NULL) || (sec->shdr != NULL))
8854665Sab196087 		return (1);
8864665Sab196087 
8874665Sab196087 	if (((sec->shdr = malloc(sizeof (*sec->shdr))) == NULL) ||
8884665Sab196087 	    ((sec->data = malloc(sizeof (*sec->data))) == NULL)) {
8894665Sab196087 		int err = errno;
8904665Sab196087 		sinfo_free(sec, 1);
8914665Sab196087 		(void) fprintf(stderr, MSG_INTL(MSG_ERR_MALLOC),
8924665Sab196087 		    fstate->file, strerror(err));
8934665Sab196087 		return (0);
8944665Sab196087 	}
8954665Sab196087 	tinfo = &sinfo_data[sec->type];
8964665Sab196087 
8974665Sab196087 
8984665Sab196087 
8994665Sab196087 	/*
9004665Sab196087 	 * Fill in fake section header
9014665Sab196087 	 *
9024665Sab196087 	 * sh_name should be the offset of the name in the shstrtab
9034665Sab196087 	 * section referenced by the ELF header. There is no
9044665Sab196087 	 * value to elfdump in creating shstrtab, so we set
9054665Sab196087 	 * sh_name to 0, knowing that elfdump doesn't look at it.
9064665Sab196087 	 */
9074665Sab196087 	sec->shdr->sh_name = 0;
9084665Sab196087 	sec->shdr->sh_type = tinfo->sh_type;
9094665Sab196087 	sec->shdr->sh_flags = tinfo->sh_flags;
9104665Sab196087 	if ((tinfo->sh_flags & SHF_ALLOC) == 0) {
9114665Sab196087 		/*
9124665Sab196087 		 * Non-allocable section: Pass the addr (which is probably
9134665Sab196087 		 * 0) and offset through without inspection.
9144665Sab196087 		 */
9154665Sab196087 		sec->shdr->sh_addr = sec->vaddr;
9164665Sab196087 		sec->shdr->sh_offset = sec->offset;
9174665Sab196087 		zero_bytes = 0;
9184665Sab196087 	} else if (sec->vaddr == 0) {
9194665Sab196087 		/*
9204665Sab196087 		 * Allocable section with a 0 vaddr. Figure out the
9214665Sab196087 		 * real address by mapping the offset to it using the
9224665Sab196087 		 * program headers.
9234665Sab196087 		 */
9244665Sab196087 		sec->shdr->sh_addr = map_offset_to_addr(fstate, sec->offset,
9254665Sab196087 		    sec->size, &zero_bytes, &phdr);
9264665Sab196087 		sec->shdr->sh_offset = sec->offset;
9274665Sab196087 	} else {
9284665Sab196087 		/*
9294665Sab196087 		 * Allocable section with non-0 vaddr. Use the vaddr
9304665Sab196087 		 * to derive the offset.
9314665Sab196087 		 */
9324665Sab196087 		sec->shdr->sh_addr = sec->vaddr;
9334665Sab196087 		sec->shdr->sh_offset = map_addr_to_offset(fstate,
9344665Sab196087 		    sec->vaddr, sec->size, &zero_bytes, &phdr);
9354665Sab196087 	}
9364665Sab196087 	if (sec->shdr->sh_offset == 0) {
9374665Sab196087 		sinfo_free(sec, 1);
9384665Sab196087 		return (0);
9394665Sab196087 	}
9404665Sab196087 	/*
9414665Sab196087 	 * If the program header has its write flags set, then set
9424665Sab196087 	 * the section write flag.
9434665Sab196087 	 */
9444665Sab196087 	if (phdr && ((phdr->p_flags & PF_W) != 0))
9454665Sab196087 		sec->shdr->sh_flags |= SHF_WRITE;
9464665Sab196087 	sec->shdr->sh_size = sec->size;
9474665Sab196087 	sec->shdr->sh_link = 0;
9484665Sab196087 	sec->shdr->sh_info = 0;
9494665Sab196087 	sec->shdr->sh_addralign = tinfo->sh_addralign;
9504665Sab196087 	sec->shdr->sh_entsize = tinfo->sh_entsize;
9514665Sab196087 
9524665Sab196087 	/*
9534665Sab196087 	 * Some sections define special meanings for sh_link and sh_info.
9544665Sab196087 	 */
9554665Sab196087 	switch (tinfo->sh_type) {
9564665Sab196087 	case SHT_DYNAMIC:
9574665Sab196087 		sec->shdr->sh_link = SINFO_T_DYNSTR;
9584665Sab196087 		break;
9594665Sab196087 
9604665Sab196087 	case SHT_DYNSYM:
9614665Sab196087 		sec->shdr->sh_link = SINFO_T_DYNSTR;
9624665Sab196087 		sec->shdr->sh_info = 1;	/* First global symbol */
9634665Sab196087 		break;
9644665Sab196087 
9654665Sab196087 	case SHT_SUNW_LDYNSYM:
9664665Sab196087 		sec->shdr->sh_link = SINFO_T_DYNSTR;
9674665Sab196087 		/*
9684665Sab196087 		 * ldynsym is all local symbols, so the index of the
9694665Sab196087 		 * first global is equivalent to the number of symbols.
9704665Sab196087 		 */
9714665Sab196087 		sec->shdr->sh_info = sec->shdr->sh_size / sizeof (Sym);
9724665Sab196087 		break;
9734665Sab196087 
9744665Sab196087 	case SHT_HASH:
9754665Sab196087 	case SHT_SUNW_move:
9764665Sab196087 	case SHT_REL:
9774665Sab196087 	case SHT_RELA:
9784665Sab196087 	case SHT_SUNW_versym:
9794665Sab196087 		sec->shdr->sh_link = SINFO_T_DYNSYM;
9804665Sab196087 		break;
9814665Sab196087 
9824665Sab196087 	case SHT_SUNW_verdef:
9834665Sab196087 	case SHT_SUNW_verneed:
9844665Sab196087 		sec->shdr->sh_link = SINFO_T_DYNSTR;
9854665Sab196087 		sec->shdr->sh_info = sec->vercnt;
9864665Sab196087 		break;
9874665Sab196087 
9884665Sab196087 	case SHT_SUNW_syminfo:
9894665Sab196087 		sec->shdr->sh_link = SINFO_T_DYNSYM;
9904665Sab196087 		sec->shdr->sh_info = SINFO_T_DYN;
9914665Sab196087 		break;
9924665Sab196087 
9934665Sab196087 	case SHT_SUNW_symsort:
9944665Sab196087 	case SHT_SUNW_tlssort:
9954665Sab196087 		sec->shdr->sh_link = SINFO_T_LDYNSYM;
9964665Sab196087 		break;
9974665Sab196087 	}
9984665Sab196087 
9994665Sab196087 
10004665Sab196087 
10014665Sab196087 	/* Fill in fake Elf_Data descriptor */
10024665Sab196087 	sec->data->d_type = tinfo->libelf_type;
10034665Sab196087 	sec->data->d_size = sec->size;
10044665Sab196087 	sec->data->d_off = 0;
10054665Sab196087 	sec->data->d_align = tinfo->sh_addralign;
10064665Sab196087 	sec->data->d_version = fstate->ehdr->e_version;
10074665Sab196087 
10084665Sab196087 	if (sec->size == 0) {
10094665Sab196087 		sec->data->d_buf = NULL;
10104665Sab196087 		return (1);
10114665Sab196087 	}
10124665Sab196087 
10134665Sab196087 	if ((sec->data->d_buf = malloc(sec->size)) == NULL) {
10144665Sab196087 		int err = errno;
10154665Sab196087 
10164665Sab196087 		sinfo_free(sec, 1);
10174665Sab196087 		(void) fprintf(stderr, MSG_INTL(MSG_ERR_MALLOC),
10184665Sab196087 		    fstate->file, strerror(err));
10194665Sab196087 		return (0);
10204665Sab196087 	}
10214665Sab196087 
10224665Sab196087 	read_bytes = sec->size - zero_bytes;
10234665Sab196087 	if ((read_bytes > 0) &&
10244665Sab196087 	    (read_data(fstate, sec->shdr->sh_offset, sec->data->d_buf,
10254665Sab196087 	    read_bytes, ELF_T_BYTE) == 0)) {
10264665Sab196087 		sinfo_free(sec, 1);
10274665Sab196087 		return (0);
10284665Sab196087 	}
10294665Sab196087 	if (zero_bytes > 0)
10304665Sab196087 		bzero(read_bytes + (char *)sec->data->d_buf, zero_bytes);
10314665Sab196087 
10324665Sab196087 	if ((tinfo->libelf_type != ELF_T_BYTE) &&
10334665Sab196087 	    (elf_xlatetom(sec->data, sec->data,
10344665Sab196087 	    fstate->ehdr->e_ident[EI_DATA]) == NULL)) {
10354665Sab196087 		sinfo_free(sec, 1);
10364665Sab196087 		failure(fstate->file, MSG_ORIG(MSG_ELF_XLATETOM));
10374665Sab196087 		return (0);
10384665Sab196087 	}
10394665Sab196087 
10404665Sab196087 	return (1);
10414665Sab196087 }
10424665Sab196087 
10434665Sab196087 
10444665Sab196087 
10454665Sab196087 /*
10464665Sab196087  * Generate a section header cache made up of information derived
10474665Sab196087  * from the program headers.
10484665Sab196087  *
10494665Sab196087  * entry:
10504665Sab196087  *	file - Name of object
10514665Sab196087  *	fd - Open file handle for object
10524665Sab196087  *	elf - ELF descriptor
10534665Sab196087  *	ehdr - Elf header
10544665Sab196087  *	cache, shnum - Addresses of variables to receive resulting
10554665Sab196087  *		cache and number of sections.
10564665Sab196087  *
10574665Sab196087  * exit:
10584665Sab196087  *	On success, *cache and *shnum are set, and True (1) is returned.
10594665Sab196087  *	On failure, False (0) is returned.
10604665Sab196087  *
10614665Sab196087  * note:
10624665Sab196087  *	The cache returned by this routine must be freed using
10634665Sab196087  *	fake_shdr_cache_free(), and not by a direct call to free().
10644665Sab196087  *	Otherwise, memory will leak.
10654665Sab196087  */
10664665Sab196087 int
fake_shdr_cache(const char * file,int fd,Elf * elf,Ehdr * ehdr,Cache ** cache,size_t * shnum)10674665Sab196087 fake_shdr_cache(const char *file, int fd, Elf *elf, Ehdr *ehdr,
10684665Sab196087     Cache **cache, size_t *shnum)
10694665Sab196087 {
10704665Sab196087 	/*
10714665Sab196087 	 * The C language guarantees that a structure of homogeneous
10724665Sab196087 	 * items will receive exactly the same layout in a structure
10734665Sab196087 	 * as a plain array of the same type. Hence, this structure, which
10744665Sab196087 	 * gives us by-name or by-index access to the various section
10754665Sab196087 	 * info descriptors we maintain.
10764665Sab196087 	 *
10774665Sab196087 	 * We use this for sections where
10784665Sab196087 	 *	- Only one instance is allowed
10794665Sab196087 	 *	- We need to be able to access them easily by
10804665Sab196087 	 *		name (for instance, when mining the .dynamic
10814665Sab196087 	 *		section for information to build them up.
10824665Sab196087 	 *
10834665Sab196087 	 * NOTE: These fields must be in the same order as the
10844665Sab196087 	 * SINFO_T_ type codes that correspond to them. Otherwise,
10854665Sab196087 	 * they will end up in the wrong order in the cache array,
10864665Sab196087 	 * and the sh_link/sh_info fields may be wrong.
10874665Sab196087 	 */
10884665Sab196087 	struct {
10894665Sab196087 		/* Note: No entry is needed for SINFO_T_NULL */
10904665Sab196087 		SINFO	dyn;
10914665Sab196087 		SINFO	dynstr;
10924665Sab196087 		SINFO	dynsym;
10934665Sab196087 		SINFO	ldynsym;
10944665Sab196087 
10954665Sab196087 		SINFO	hash;
10964665Sab196087 		SINFO	syminfo;
10974665Sab196087 		SINFO	symsort;
10984665Sab196087 		SINFO	tlssort;
10994665Sab196087 		SINFO	verneed;
11004665Sab196087 		SINFO	verdef;
11014665Sab196087 		SINFO	versym;
11024665Sab196087 		SINFO	interp;
11034665Sab196087 		SINFO	cap;
1104*11827SRod.Evans@Sun.COM 		SINFO	capinfo;
1105*11827SRod.Evans@Sun.COM 		SINFO	capchain;
11064665Sab196087 		SINFO	unwind;
11074665Sab196087 		SINFO	move;
11084665Sab196087 		SINFO	rel;
11094665Sab196087 		SINFO	rela;
11104665Sab196087 		SINFO	preinitarr;
11114665Sab196087 		SINFO	initarr;
11124665Sab196087 		SINFO	finiarr;
11134665Sab196087 	} sec;
11144665Sab196087 	static const size_t sinfo_n = sizeof (sec) / sizeof (sec.dyn);
11154665Sab196087 	SINFO *secarr = (SINFO *) &sec;
11164665Sab196087 
11174665Sab196087 	/*
11184665Sab196087 	 * Doubly linked circular list, used to track sections
11194665Sab196087 	 * where multiple sections of a given type can exist.
11204665Sab196087 	 * seclist is the root of the list. Its sinfo field is not
11214665Sab196087 	 * used --- it serves to anchor the root of the list, allowing
11224665Sab196087 	 * rapid access to the first and last element in the list.
11234665Sab196087 	 */
11244665Sab196087 	SINFO_LISTELT	seclist;
11254665Sab196087 
11264665Sab196087 	FSTATE		fstate;
11274665Sab196087 	size_t		ndx;
11284665Sab196087 	size_t		num_sinfo, num_list_sinfo;
11294665Sab196087 	SINFO		*sinfo;
11304665Sab196087 	SINFO_LISTELT	*sinfo_list;
11314665Sab196087 	Cache		*_cache;
11324665Sab196087 
11334665Sab196087 
11344665Sab196087 	fstate.file = file;
11354665Sab196087 	fstate.fd = fd;
11364665Sab196087 	fstate.ehdr = ehdr;
11379900SAli.Bahrami@Sun.COM 	if (elf_getphdrnum(elf, &fstate.phnum) == -1) {
11389900SAli.Bahrami@Sun.COM 		failure(file, MSG_ORIG(MSG_ELF_GETPHDRNUM));
11394665Sab196087 		return (0);
11404665Sab196087 	}
11414665Sab196087 	if ((fstate.phdr = elf_getphdr(elf)) == NULL) {
11424665Sab196087 		failure(file, MSG_ORIG(MSG_ELF_GETPHDR));
11434665Sab196087 		return (0);
11444665Sab196087 	}
11454665Sab196087 
11464665Sab196087 	bzero(&sec, sizeof (sec));	/* Initialize "by-name" sec info */
11474665Sab196087 	seclist.next = seclist.prev = &seclist;	  /* Empty circular list */
11484665Sab196087 
11494665Sab196087 	/*
11504665Sab196087 	 * Go through the program headers and look for information
11514665Sab196087 	 * we can use to synthesize section headers. By far the most
11524665Sab196087 	 * valuable thing is a dynamic section, the contents of
11534665Sab196087 	 * which point at all sections used by ld.so.1.
11544665Sab196087 	 */
11554665Sab196087 	for (ndx = 0; ndx < fstate.phnum; ndx++) {
11564665Sab196087 		/*
11574665Sab196087 		 * A program header with no file size does
11584665Sab196087 		 * not have a backing section.
11594665Sab196087 		 */
11604665Sab196087 		if (fstate.phdr[ndx].p_filesz == 0)
11614665Sab196087 			continue;
11624665Sab196087 
11634665Sab196087 
11644665Sab196087 		switch (fstate.phdr[ndx].p_type) {
11654665Sab196087 		default:
11664665Sab196087 			/* Header we can't use. Move on to next one */
11674665Sab196087 			continue;
11684665Sab196087 
11694665Sab196087 		case PT_DYNAMIC:
11704665Sab196087 			sec.dyn.type = SINFO_T_DYN;
11714665Sab196087 			sinfo = &sec.dyn;
11724665Sab196087 			break;
11734665Sab196087 
11744665Sab196087 		case PT_INTERP:
11754665Sab196087 			sec.interp.type = SINFO_T_INTERP;
11764665Sab196087 			sinfo = &sec.interp;
11774665Sab196087 			break;
11784665Sab196087 
11794665Sab196087 		case PT_NOTE:
11804665Sab196087 			if ((sinfo = sinfo_list_alloc(&fstate, &seclist)) ==
11814665Sab196087 			    NULL)
11824665Sab196087 				continue;
11834665Sab196087 			sinfo->type = SINFO_T_NOTE;
11844665Sab196087 			break;
11854665Sab196087 
11864665Sab196087 		case PT_SUNW_UNWIND:
11879085SAli.Bahrami@Sun.COM 		case PT_SUNW_EH_FRAME:
11884665Sab196087 			sec.unwind.type = SINFO_T_UNWIND;
11894665Sab196087 			sinfo = &sec.unwind;
11904665Sab196087 			break;
11914665Sab196087 
11924665Sab196087 		case PT_SUNWCAP:
11934665Sab196087 			sec.cap.type = SINFO_T_CAP;
11944665Sab196087 			sinfo = &sec.cap;
11954665Sab196087 			break;
11964665Sab196087 		}
11974665Sab196087 
11984665Sab196087 		/*
11994665Sab196087 		 * Capture the position/extent information for
12004665Sab196087 		 * the header in the SINFO struct set up by the
12014665Sab196087 		 * switch statement above.
12024665Sab196087 		 */
12034665Sab196087 		sinfo->vaddr = fstate.phdr[ndx].p_vaddr;
12044665Sab196087 		sinfo->offset = fstate.phdr[ndx].p_offset;
12054665Sab196087 		sinfo->size = fstate.phdr[ndx].p_filesz;
12064665Sab196087 	}
12074665Sab196087 
12084665Sab196087 	/*
12094665Sab196087 	 * If we found a dynamic section, look through it and
12104665Sab196087 	 * gather information about the sections it references.
12114665Sab196087 	 */
12124665Sab196087 	if (sec.dyn.type == SINFO_T_DYN)
12134665Sab196087 		(void) get_data(&fstate, &sec.dyn);
12144665Sab196087 	if ((sec.dyn.type == SINFO_T_DYN) && (sec.dyn.data->d_buf != NULL)) {
12154665Sab196087 		Dyn *dyn;
12164665Sab196087 		for (dyn = sec.dyn.data->d_buf; dyn->d_tag != DT_NULL; dyn++) {
12174665Sab196087 			switch (dyn->d_tag) {
12184665Sab196087 			case DT_HASH:
12194665Sab196087 				sec.hash.type = SINFO_T_HASH;
12204665Sab196087 				sec.hash.vaddr = dyn->d_un.d_ptr;
12214665Sab196087 				break;
12224665Sab196087 
12234665Sab196087 			case DT_STRTAB:
12244665Sab196087 				sec.dynstr.type = SINFO_T_DYNSTR;
12254665Sab196087 				sec.dynstr.vaddr = dyn->d_un.d_ptr;
12264665Sab196087 				break;
12274665Sab196087 
12284665Sab196087 			case DT_SYMTAB:
12294665Sab196087 				sec.dynsym.type = SINFO_T_DYNSYM;
12304665Sab196087 				sec.dynsym.vaddr = dyn->d_un.d_ptr;
12314665Sab196087 				break;
12324665Sab196087 
12334665Sab196087 			case DT_RELA:
12344665Sab196087 				sec.rela.type = SINFO_T_RELA;
12354665Sab196087 				sec.rela.vaddr = dyn->d_un.d_ptr;
12364665Sab196087 				break;
12374665Sab196087 
12384665Sab196087 			case DT_RELASZ:
12394665Sab196087 				sec.rela.size = dyn->d_un.d_val;
12404665Sab196087 				break;
12414665Sab196087 
12424665Sab196087 			case DT_STRSZ:
12434665Sab196087 				sec.dynstr.size = dyn->d_un.d_val;
12444665Sab196087 				break;
12454665Sab196087 
12464665Sab196087 			case DT_REL:
12474665Sab196087 				sec.rel.type = SINFO_T_REL;
12484665Sab196087 				sec.rel.vaddr = dyn->d_un.d_ptr;
12494665Sab196087 				break;
12504665Sab196087 
12514665Sab196087 			case DT_RELSZ:
12524665Sab196087 				sec.rel.size = dyn->d_un.d_val;
12534665Sab196087 				break;
12544665Sab196087 
12554665Sab196087 			case DT_INIT_ARRAY:
12564665Sab196087 				sec.initarr.type = SINFO_T_INITARR;
12574665Sab196087 				sec.initarr.vaddr = dyn->d_un.d_ptr;
12584665Sab196087 				break;
12594665Sab196087 
12604665Sab196087 			case DT_INIT_ARRAYSZ:
12614665Sab196087 				sec.initarr.size = dyn->d_un.d_val;
12624665Sab196087 				break;
12634665Sab196087 
12644665Sab196087 			case DT_FINI_ARRAY:
12654665Sab196087 				sec.finiarr.type = SINFO_T_FINIARR;
12664665Sab196087 				sec.finiarr.vaddr = dyn->d_un.d_ptr;
12674665Sab196087 				break;
12684665Sab196087 
12694665Sab196087 			case DT_FINI_ARRAYSZ:
12704665Sab196087 				sec.finiarr.size = dyn->d_un.d_val;
12714665Sab196087 				break;
12724665Sab196087 
12734665Sab196087 			case DT_PREINIT_ARRAY:
12744665Sab196087 				sec.preinitarr.type = SINFO_T_PREINITARR;
12754665Sab196087 				sec.preinitarr.vaddr = dyn->d_un.d_ptr;
12764665Sab196087 				break;
12774665Sab196087 
12784665Sab196087 			case DT_PREINIT_ARRAYSZ:
12794665Sab196087 				sec.preinitarr.size = dyn->d_un.d_val;
12804665Sab196087 				break;
12814665Sab196087 
1282*11827SRod.Evans@Sun.COM 			case DT_SUNW_CAPINFO:
1283*11827SRod.Evans@Sun.COM 				sec.capinfo.type = SINFO_T_CAPINFO;
1284*11827SRod.Evans@Sun.COM 				sec.capinfo.vaddr = dyn->d_un.d_ptr;
1285*11827SRod.Evans@Sun.COM 				break;
1286*11827SRod.Evans@Sun.COM 
1287*11827SRod.Evans@Sun.COM 			case DT_SUNW_CAPCHAIN:
1288*11827SRod.Evans@Sun.COM 				sec.capchain.type = SINFO_T_CAPCHAIN;
1289*11827SRod.Evans@Sun.COM 				sec.capchain.vaddr = dyn->d_un.d_ptr;
1290*11827SRod.Evans@Sun.COM 				break;
1291*11827SRod.Evans@Sun.COM 
12924665Sab196087 			case DT_SUNW_SYMTAB:
12934665Sab196087 				sec.ldynsym.type = SINFO_T_LDYNSYM;
12944665Sab196087 				sec.ldynsym.vaddr = dyn->d_un.d_ptr;
12954665Sab196087 				break;
12964665Sab196087 
12974665Sab196087 			case DT_SUNW_SYMSZ:
12984665Sab196087 				sec.ldynsym.size = dyn->d_un.d_val;
12994665Sab196087 				break;
13004665Sab196087 
13014665Sab196087 			case DT_SUNW_SYMSORT:
13024665Sab196087 				sec.symsort.type = SINFO_T_SYMSORT;
13034665Sab196087 				sec.symsort.vaddr = dyn->d_un.d_ptr;
13044665Sab196087 				break;
13054665Sab196087 
13064665Sab196087 			case DT_SUNW_SYMSORTSZ:
13074665Sab196087 				sec.symsort.size = dyn->d_un.d_val;
13084665Sab196087 				break;
13094665Sab196087 
13104665Sab196087 			case DT_SUNW_TLSSORT:
13114665Sab196087 				sec.tlssort.type = SINFO_T_TLSSORT;
13124665Sab196087 				sec.tlssort.vaddr = dyn->d_un.d_ptr;
13134665Sab196087 				break;
13144665Sab196087 
13154665Sab196087 			case DT_SUNW_TLSSORTSZ:
13164665Sab196087 				sec.tlssort.size = dyn->d_un.d_val;
13174665Sab196087 				break;
13184665Sab196087 
13194665Sab196087 			case DT_MOVETAB:
13204665Sab196087 				sec.move.type = SINFO_T_MOVE;
13214665Sab196087 				sec.move.vaddr = dyn->d_un.d_ptr;
13224665Sab196087 				break;
13234665Sab196087 
13244665Sab196087 			case DT_MOVESZ:
13254665Sab196087 				sec.move.size = dyn->d_un.d_val;
13264665Sab196087 				break;
13274665Sab196087 
13284665Sab196087 			case DT_SYMINFO:
13294665Sab196087 				sec.syminfo.type = SINFO_T_SYMINFO;
13304665Sab196087 				sec.syminfo.vaddr = dyn->d_un.d_ptr;
13314665Sab196087 				break;
13324665Sab196087 
13334665Sab196087 			case DT_SYMINSZ:
13344665Sab196087 				sec.syminfo.size = dyn->d_un.d_val;
13354665Sab196087 				break;
13364665Sab196087 
13374665Sab196087 			case DT_VERSYM:
13384665Sab196087 				sec.versym.type = SINFO_T_VERSYM;
13394665Sab196087 				sec.versym.vaddr = dyn->d_un.d_ptr;
13404665Sab196087 				break;
13414665Sab196087 
13424665Sab196087 			case DT_VERDEF:
13434665Sab196087 				sec.verdef.type = SINFO_T_VERDEF;
13444665Sab196087 				sec.verdef.vaddr = dyn->d_un.d_ptr;
13454665Sab196087 				break;
13464665Sab196087 
13474665Sab196087 			case DT_VERDEFNUM:
13484665Sab196087 				sec.verdef.vercnt = dyn->d_un.d_val;
13494665Sab196087 				sec.verdef.size = sizeof (Verdef) *
13504665Sab196087 				    dyn->d_un.d_val;
13514665Sab196087 				break;
13524665Sab196087 
13534665Sab196087 			case DT_VERNEED:
13544665Sab196087 				sec.verneed.type = SINFO_T_VERNEED;
13554665Sab196087 				sec.verneed.vaddr = dyn->d_un.d_ptr;
13564665Sab196087 				break;
13574665Sab196087 
13584665Sab196087 			case DT_VERNEEDNUM:
13594665Sab196087 				sec.verneed.vercnt = dyn->d_un.d_val;
13604665Sab196087 				sec.verneed.size = sizeof (Verneed) *
13614665Sab196087 				    dyn->d_un.d_val;
13624665Sab196087 				break;
13634665Sab196087 			}
13644665Sab196087 		}
13654665Sab196087 	}
13664665Sab196087 
13674665Sab196087 	/*
13684665Sab196087 	 * Different sections depend on each other, and are meaningless
13694665Sab196087 	 * without them. For instance, even if a .dynsym exists,
13704665Sab196087 	 * no use can be made of it without a dynstr. These relationships
13714665Sab196087 	 * fan out: Disqualifying the .dynsym will disqualify the hash
13724665Sab196087 	 * section, and so forth.
13734665Sab196087 	 *
13744665Sab196087 	 * Disqualify sections that don't have the necessary prerequisites.
13754665Sab196087 	 */
13764665Sab196087 
13774665Sab196087 	/* Things that need the dynamic string table */
13784665Sab196087 	if (sec.dynstr.size == 0)
13794665Sab196087 		sec.dynstr.type = SINFO_T_NULL;
13804665Sab196087 	if (sec.dynstr.type != SINFO_T_DYNSTR) {
13814665Sab196087 		sinfo_free(&sec.dyn, 1);	/* Data already fetched */
13824665Sab196087 		sec.dynsym.type =  SINFO_T_NULL;
13834665Sab196087 		sec.dynsym.type =  SINFO_T_NULL;
13844665Sab196087 		sec.verdef.type =  SINFO_T_NULL;
13854665Sab196087 		sec.verneed.type =  SINFO_T_NULL;
13864665Sab196087 	}
13874665Sab196087 
13884665Sab196087 	/*
13894665Sab196087 	 * The length of the hash section is encoded in its first two
13904665Sab196087 	 * elements (nbucket, and nchain). The length of the dynsym,
13914665Sab196087 	 * ldynsym, and versym are not given in the dynamic section,
13924665Sab196087 	 * but are known to be the same as nchain.
13934665Sab196087 	 *
13944665Sab196087 	 * If we don't have a hash table, or cannot read nbuckets and
13954665Sab196087 	 * nchain, we have to invalidate all of these.
13964665Sab196087 	 */
13974665Sab196087 	if (sec.hash.type == SINFO_T_HASH) {
13984665Sab196087 		Word nbucket;
13994665Sab196087 		Word nchain;
14004665Sab196087 		size_t total;
14014665Sab196087 
14024665Sab196087 		if (hash_size(&fstate, &sec.hash,
14034665Sab196087 		    &nbucket, &nchain, &total) == 0) {
14044665Sab196087 			sec.hash.type = SINFO_T_NULL;
14054665Sab196087 		} else {
14064665Sab196087 			/* Use these counts to set sizes for related sections */
14074665Sab196087 			sec.hash.size = total * sizeof (Word);
14084665Sab196087 			sec.dynsym.size = nchain * sizeof (Sym);
14094665Sab196087 			sec.versym.size = nchain * sizeof (Versym);
14104665Sab196087 
14114665Sab196087 			/*
14124665Sab196087 			 * The ldynsym size received the DT_SUNW_SYMSZ
14134665Sab196087 			 * value, which is the combined size of .dynsym
14144665Sab196087 			 * and .ldynsym. Now that we have the dynsym size,
14154665Sab196087 			 * use it to lower the ldynsym size to its real size.
14164665Sab196087 			 */
14174665Sab196087 			if (sec.ldynsym.size > sec.dynsym.size)
14184665Sab196087 				sec.ldynsym.size  -= sec.dynsym.size;
14194665Sab196087 		}
14204665Sab196087 	}
14214665Sab196087 	/*
14224665Sab196087 	 * If the hash table is not present, or if the call to
14234665Sab196087 	 * hash_size() failed, then discard the sections that
14244665Sab196087 	 * need it to determine their length.
14254665Sab196087 	 */
14264665Sab196087 	if (sec.hash.type != SINFO_T_HASH) {
14274665Sab196087 		sec.dynsym.type = SINFO_T_NULL;
14284665Sab196087 		sec.ldynsym.type = SINFO_T_NULL;
14294665Sab196087 		sec.versym.type = SINFO_T_NULL;
14304665Sab196087 	}
14314665Sab196087 
14324665Sab196087 	/*
14334665Sab196087 	 * The runtime linker does not receive size information for
14344665Sab196087 	 * Verdef and Verneed sections. We have to read their data
14354665Sab196087 	 * in pieces and calculate it.
14364665Sab196087 	 */
14374665Sab196087 	if ((sec.verdef.type == SINFO_T_VERDEF) &&
14384665Sab196087 	    (verdefneed_size(&fstate, &sec.verdef) == 0))
14394665Sab196087 		sec.verdef.type = SINFO_T_NULL;
14404665Sab196087 	if ((sec.verneed.type == SINFO_T_VERNEED) &&
14414665Sab196087 	    (verdefneed_size(&fstate, &sec.verneed) == 0))
14424665Sab196087 		sec.verneed.type = SINFO_T_NULL;
14434665Sab196087 
14444665Sab196087 	/* Discard any section with a zero length */
14454665Sab196087 	ndx = sinfo_n;
14464665Sab196087 	for (sinfo = secarr; ndx-- > 0; sinfo++)
14474665Sab196087 		if ((sinfo->type != SINFO_T_NULL) && (sinfo->size == 0))
14484665Sab196087 			sinfo->type = SINFO_T_NULL;
14494665Sab196087 
14504665Sab196087 	/* Things that need the dynamic symbol table */
14514665Sab196087 	if (sec.dynsym.type != SINFO_T_DYNSYM) {
14524665Sab196087 		sec.ldynsym.type = SINFO_T_NULL;
14534665Sab196087 		sec.hash.type = SINFO_T_NULL;
14544665Sab196087 		sec.syminfo.type = SINFO_T_NULL;
14554665Sab196087 		sec.versym.type = SINFO_T_NULL;
14564665Sab196087 		sec.move.type = SINFO_T_NULL;
14574665Sab196087 		sec.rel.type = SINFO_T_NULL;
14584665Sab196087 		sec.rela.type = SINFO_T_NULL;
14594665Sab196087 	}
14604665Sab196087 
14614665Sab196087 	/* Things that need the dynamic local symbol table */
14624665Sab196087 	if (sec.ldynsym.type != SINFO_T_DYNSYM) {
14634665Sab196087 		sec.symsort.type = SINFO_T_NULL;
14644665Sab196087 		sec.tlssort.type = SINFO_T_NULL;
14654665Sab196087 	}
14664665Sab196087 
14674665Sab196087 	/*
14684665Sab196087 	 * Look through the results and fetch the data for any sections
14694665Sab196087 	 * we have found. At the same time, count the number.
14704665Sab196087 	 */
14714665Sab196087 	num_sinfo = num_list_sinfo = 0;
14724665Sab196087 	ndx = sinfo_n;
14734665Sab196087 	for (sinfo = secarr; ndx-- > 0; sinfo++) {
14744665Sab196087 		if ((sinfo->type != SINFO_T_NULL) && (sinfo->data == NULL))
14754665Sab196087 			(void) get_data(&fstate, sinfo);
14764665Sab196087 		if (sinfo->data != NULL)
14774665Sab196087 			num_sinfo++;
14784665Sab196087 	}
14794665Sab196087 	for (sinfo_list = seclist.next; sinfo_list != &seclist;
14804665Sab196087 	    sinfo_list = sinfo_list->next) {
14814665Sab196087 		sinfo = &sinfo_list->sinfo;
14824665Sab196087 		if ((sinfo->type != SINFO_T_NULL) && (sinfo->data == NULL))
14834665Sab196087 			(void) get_data(&fstate, sinfo);
14844665Sab196087 		if (sinfo->data != NULL)
14854665Sab196087 			num_list_sinfo++;
14864665Sab196087 	}
14874665Sab196087 
14884665Sab196087 	/*
14894665Sab196087 	 * Allocate the cache array and fill it in. The cache array
14904665Sab196087 	 * ends up taking all the dynamic memory we've allocated
14914665Sab196087 	 * to build up sec and seclist, so on success, we have nothing
14924665Sab196087 	 * left to clean up. If we can't allocate the cache array
14934665Sab196087 	 * though, we have to free up everything else.
14944665Sab196087 	 */
14954665Sab196087 	*shnum = num_sinfo + num_list_sinfo + 1; /* Extra for 1st NULL sec. */
14964665Sab196087 	if ((*cache = _cache = malloc((*shnum) * sizeof (Cache))) == NULL) {
14974665Sab196087 		int err = errno;
14984665Sab196087 		(void) fprintf(stderr, MSG_INTL(MSG_ERR_MALLOC),
14994665Sab196087 		    file, strerror(err));
15004665Sab196087 		sinfo_free(secarr, num_sinfo);
15014665Sab196087 		sinfo_list_free_all(&seclist);
15024665Sab196087 		return (0);
15034665Sab196087 	}
15044665Sab196087 	*_cache = cache_init;
15054665Sab196087 	_cache++;
15064665Sab196087 	ndx = 1;
15074665Sab196087 	for (sinfo = secarr; num_sinfo > 0; sinfo++) {
15084665Sab196087 		if (sinfo->data != NULL) {
15094665Sab196087 			_cache->c_scn = NULL;
15104665Sab196087 			_cache->c_shdr = sinfo->shdr;
15114665Sab196087 			_cache->c_data = sinfo->data;
15124665Sab196087 			_cache->c_name = (char *)sinfo_data[sinfo->type].name;
15134665Sab196087 			_cache->c_ndx = ndx++;
15144665Sab196087 			_cache++;
15154665Sab196087 			num_sinfo--;
15164665Sab196087 		}
15174665Sab196087 	}
15184665Sab196087 	for (sinfo_list = seclist.next; num_list_sinfo > 0;
15194665Sab196087 	    sinfo_list = sinfo_list->next) {
15204665Sab196087 		sinfo = &sinfo_list->sinfo;
15214665Sab196087 		if (sinfo->data != NULL) {
15224665Sab196087 			_cache->c_scn = NULL;
15234665Sab196087 			_cache->c_shdr = sinfo->shdr;
15244665Sab196087 			_cache->c_data = sinfo->data;
15254665Sab196087 			_cache->c_name = (char *)sinfo_data[sinfo->type].name;
15264665Sab196087 			_cache->c_ndx = ndx++;
15274665Sab196087 			_cache++;
15284665Sab196087 			num_list_sinfo--;
15294665Sab196087 		}
15304665Sab196087 	}
15314665Sab196087 
15324665Sab196087 	return (1);
15334665Sab196087 }
15344665Sab196087 
15354665Sab196087 
15364665Sab196087 
15374665Sab196087 
15384665Sab196087 
15394665Sab196087 /*
15404665Sab196087  * Release all the memory referenced by a cache array allocated
15414665Sab196087  * by fake_shdr_cache().
15424665Sab196087  */
15434665Sab196087 void
fake_shdr_cache_free(Cache * cache,size_t shnum)15444665Sab196087 fake_shdr_cache_free(Cache *cache, size_t shnum)
15454665Sab196087 {
15464665Sab196087 	Cache *_cache;
15474665Sab196087 
15484665Sab196087 	for (_cache = cache; shnum--; _cache++) {
15494665Sab196087 		if (_cache->c_data != NULL) {
15504665Sab196087 			if (_cache->c_data->d_buf != NULL)
15514665Sab196087 				free(_cache->c_data->d_buf);
15524665Sab196087 			free(_cache->c_data);
15534665Sab196087 		}
15544665Sab196087 		if (_cache->c_shdr)
15554665Sab196087 			free(_cache->c_shdr);
15564665Sab196087 	}
15574665Sab196087 
15584665Sab196087 	free(cache);
15594665Sab196087 }
1560