139773e46Sab /*
239773e46Sab  * CDDL HEADER START
339773e46Sab  *
439773e46Sab  * The contents of this file are subject to the terms of the
539773e46Sab  * Common Development and Distribution License (the "License").
639773e46Sab  * You may not use this file except in compliance with the License.
739773e46Sab  *
839773e46Sab  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
939773e46Sab  * or http://www.opensolaris.org/os/licensing.
1039773e46Sab  * See the License for the specific language governing permissions
1139773e46Sab  * and limitations under the License.
1239773e46Sab  *
1339773e46Sab  * When distributing Covered Code, include this CDDL HEADER in each
1439773e46Sab  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1539773e46Sab  * If applicable, add the following below this CDDL HEADER, with the
1639773e46Sab  * fields enclosed by brackets "[]" replaced with your own identifying
1739773e46Sab  * information: Portions Copyright [yyyy] [name of copyright owner]
1839773e46Sab  *
1939773e46Sab  * CDDL HEADER END
2039773e46Sab  */
2139773e46Sab 
2239773e46Sab /*
23*08278a5eSRod Evans  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
2439773e46Sab  * Use is subject to license terms.
2539773e46Sab  */
2639773e46Sab 
2739773e46Sab /*
2839773e46Sab  * Generate a cache of section header information for an ELF
2939773e46Sab  * object from the information found in its program headers.
3039773e46Sab  *
3139773e46Sab  * Malicious code can remove or corrupt section headers. The
3239773e46Sab  * resulting program will be difficult to analyze, but is still
3339773e46Sab  * runnable. Hence, scribbling on the section headers or removing
3439773e46Sab  * them is an effective form of obfuscation. On the other hand,
3539773e46Sab  * program headers must be accurate or the program will not run.
3639773e46Sab  * Section headers derived from them will necessarily lack information
3739773e46Sab  * found in the originals (particularly for non-allocable sections),
3839773e46Sab  * but will provide essential symbol information. The focus is on
3939773e46Sab  * recovering information that elfdump knows how to display, and that
4039773e46Sab  * might be interesting in a forensic situation.
4139773e46Sab  *
4239773e46Sab  * There are some things we don't attempt to create sections for:
4339773e46Sab  *
4439773e46Sab  *	plt, got
4539773e46Sab  *		We have no way to determine the length of either of
4639773e46Sab  *		these sections from the information available via
4739773e46Sab  *		the program headers or dynamic section. The data in
4839773e46Sab  *		the PLT is of little use to elfdump. The data in the
4939773e46Sab  *		GOT might be somewhat more interesting, especially as
5039773e46Sab  *		it pertains to relocations. However, the sizing issue
5139773e46Sab  *		remains.
5239773e46Sab  *
5339773e46Sab  *	text, data, bss
5439773e46Sab  *		Although we could create these, there is little value
5539773e46Sab  *		to doing so. elfdump cannot display the arbitrary
5639773e46Sab  *		data in these sections, so this would amount to a
5739773e46Sab  *		simple repetition of the information already displayed
5839773e46Sab  *		in the program headers, with no additional benefit.
5939773e46Sab  */
6039773e46Sab 
6139773e46Sab 
6239773e46Sab 
6339773e46Sab #include	<sys/elf_amd64.h>
64a194faf8Srie #include	<stdio.h>
6539773e46Sab #include	<unistd.h>
6639773e46Sab #include	<errno.h>
6739773e46Sab #include	<string.h>
6839773e46Sab #include	<strings.h>
6939773e46Sab #include	<conv.h>
7039773e46Sab #include	<msg.h>
7139773e46Sab #include	<_elfdump.h>
7239773e46Sab 
7339773e46Sab 
7439773e46Sab 
7539773e46Sab /*
7639773e46Sab  * Common information about the object that is needed by
7739773e46Sab  * all the routines in this module.
7839773e46Sab  */
7939773e46Sab typedef struct {
8039773e46Sab 	const char	*file;
8139773e46Sab 	int		fd;
8239773e46Sab 	Ehdr		*ehdr;
8339773e46Sab 	Phdr		*phdr;
8439773e46Sab 	size_t		phnum;
8539773e46Sab } FSTATE;
8639773e46Sab 
8739773e46Sab 
8839773e46Sab 
8939773e46Sab /*
9039773e46Sab  * These values uniquely identify the sections that we know
9139773e46Sab  * how to recover.
9239773e46Sab  *
9339773e46Sab  * Note: We write the sections to the cache array in this same order.
9439773e46Sab  * It simplifies this code if the dynamic, dynstr, dynsym, and ldynsym
9539773e46Sab  * sections occupy known slots in the cache array. Other sections reference
9639773e46Sab  * them by index, and if they are at a known spot, there is no need
9739773e46Sab  * for a fixup pass. Putting them in positions [1-4] solves this.
9839773e46Sab  *
9939773e46Sab  * The order they are in was chosen such that if any one of them exists,
10039773e46Sab  * all of the ones before it must also exist. This means that if the
10139773e46Sab  * desired section exists, it will end up in the desired index in the
10239773e46Sab  * cache array.
10339773e46Sab  *
10439773e46Sab  * The order of the other sections is arbitrary. I've arranged them
10539773e46Sab  * in roughly related groups.
10639773e46Sab  */
10739773e46Sab typedef enum {
10839773e46Sab 	SINFO_T_NULL =		0,
10939773e46Sab 	SINFO_T_DYN =		1,
11039773e46Sab 	SINFO_T_DYNSTR = 	2,
11139773e46Sab 	SINFO_T_DYNSYM =	3,
11239773e46Sab 	SINFO_T_LDYNSYM =	4,
11339773e46Sab 
11439773e46Sab 	SINFO_T_HASH =		5,
11539773e46Sab 	SINFO_T_SYMINFO =	6,
11639773e46Sab 	SINFO_T_SYMSORT =	7,
11739773e46Sab 	SINFO_T_TLSSORT =	8,
11839773e46Sab 	SINFO_T_VERNEED =	9,
11939773e46Sab 	SINFO_T_VERDEF =	10,
12039773e46Sab 	SINFO_T_VERSYM =	11,
12139773e46Sab 	SINFO_T_INTERP =	12,
12239773e46Sab 	SINFO_T_CAP =		13,
123*08278a5eSRod Evans 	SINFO_T_CAPINFO =	14,
124*08278a5eSRod Evans 	SINFO_T_CAPCHAIN =	15,
125*08278a5eSRod Evans 	SINFO_T_UNWIND =	16,
126*08278a5eSRod Evans 	SINFO_T_MOVE =		17,
127*08278a5eSRod Evans 	SINFO_T_REL =		18,
128*08278a5eSRod Evans 	SINFO_T_RELA =		19,
129*08278a5eSRod Evans 	SINFO_T_PREINITARR =	20,
130*08278a5eSRod Evans 	SINFO_T_INITARR =	21,
131*08278a5eSRod Evans 	SINFO_T_FINIARR =	22,
132*08278a5eSRod Evans 	SINFO_T_NOTE =		23,
133*08278a5eSRod Evans 
134*08278a5eSRod Evans 	SINFO_T_NUM =		24 /* Count of items. Must come last */
13539773e46Sab } SINFO_TYPE;
13639773e46Sab 
13739773e46Sab 
13839773e46Sab 
13939773e46Sab /*
14039773e46Sab  * Table of per-section constant data used to set up the section
14139773e46Sab  * header cache and the various sub-parts it references. Indexed by
14239773e46Sab  * SINFO_T value.
14339773e46Sab  *
14439773e46Sab  * note: The sh_flags value should be either SHF_ALLOC, or 0.
14539773e46Sab  *	get_data() sets SHF_WRITE if the program header containing the
14639773e46Sab  *	section is writable. The other flags require information that
14739773e46Sab  *	the program headers don't contain (i.e. SHF_STRINGS, etc) so
14839773e46Sab  *	we don't set them.
14939773e46Sab  */
15039773e46Sab typedef struct {
15139773e46Sab 	const char	*name;
15239773e46Sab 	Word		sh_type;
15339773e46Sab 	Word		sh_flags;
15439773e46Sab 	Word		sh_addralign;
15539773e46Sab 	Word		sh_entsize;
15639773e46Sab 	Elf_Type	libelf_type;
15739773e46Sab } SINFO_DATA;
15839773e46Sab 
159ba2be530Sab /*
160ba2be530Sab  * Many of these sections use an alignment given by M_WORD_ALIGN, a
161ba2be530Sab  * value that varies depending on the object target machine. Since we
162ba2be530Sab  * don't know that value at compile time, we settle for a value of
163ba2be530Sab  * 4 for ELFCLASS32 objects, and 8 for ELFCLASS64. This matches the
164ba2be530Sab  * platforms we current support (sparc and x86), and is good enough for
165ba2be530Sab  * a fake section header in any event, as the resulting object is only
166ba2be530Sab  * analyzed, and is not executed.
167ba2be530Sab  */
168ba2be530Sab #ifdef _ELF64
169ba2be530Sab #define	FAKE_M_WORD_ALIGN 8
170ba2be530Sab #else
171ba2be530Sab #define	FAKE_M_WORD_ALIGN 4
172ba2be530Sab #endif
173ba2be530Sab 
17439773e46Sab static SINFO_DATA sinfo_data[SINFO_T_NUM] = {
17539773e46Sab 	/* SINFO_T_NULL */
17639773e46Sab 	{ 0 },
17739773e46Sab 
17839773e46Sab 	/* SINFO_T_DYN */
17939773e46Sab 	{ MSG_ORIG(MSG_PHDRNAM_DYN), SHT_DYNAMIC, SHF_ALLOC,
180ba2be530Sab 	    FAKE_M_WORD_ALIGN, sizeof (Dyn), ELF_T_DYN },
18139773e46Sab 
18239773e46Sab 	/* SINFO_T_DYNSTR */
18339773e46Sab 	{ MSG_ORIG(MSG_PHDRNAM_DYNSTR), SHT_STRTAB, SHF_ALLOC,
18439773e46Sab 	    1, 0, ELF_T_BYTE },
18539773e46Sab 
18639773e46Sab 	/* SINFO_T_DYNSYM */
18739773e46Sab 	{ MSG_ORIG(MSG_PHDRNAM_DYNSYM), SHT_DYNSYM, SHF_ALLOC,
188ba2be530Sab 	    FAKE_M_WORD_ALIGN, sizeof (Sym), ELF_T_SYM },
18939773e46Sab 
19039773e46Sab 	/* SINFO_T_LDYNSYM */
19139773e46Sab 	{ MSG_ORIG(MSG_PHDRNAM_LDYNSYM), SHT_SUNW_LDYNSYM, SHF_ALLOC,
192ba2be530Sab 	    FAKE_M_WORD_ALIGN, sizeof (Sym), ELF_T_SYM },
19339773e46Sab 
19439773e46Sab 	/* SINFO_T_HASH */
19539773e46Sab 	{ MSG_ORIG(MSG_PHDRNAM_HASH), SHT_HASH, SHF_ALLOC,
196ba2be530Sab 	    FAKE_M_WORD_ALIGN, sizeof (Word), ELF_T_WORD },
19739773e46Sab 
19839773e46Sab 	/* SINFO_T_SYMINFO */
19939773e46Sab 	{ MSG_ORIG(MSG_PHDRNAM_SYMINFO),  SHT_SUNW_syminfo, SHF_ALLOC,
200ba2be530Sab 	    FAKE_M_WORD_ALIGN, sizeof (Syminfo), ELF_T_SYMINFO },
20139773e46Sab 
20239773e46Sab 	/* SINFO_T_SYMSORT */
20339773e46Sab 	{ MSG_ORIG(MSG_PHDRNAM_SYMSORT), SHT_SUNW_symsort, SHF_ALLOC,
204ba2be530Sab 	    FAKE_M_WORD_ALIGN, sizeof (Word), ELF_T_WORD },
20539773e46Sab 
20639773e46Sab 	/* SINFO_T_TLSSORT */
20739773e46Sab 	{ MSG_ORIG(MSG_PHDRNAM_TLSSORT), SHT_SUNW_tlssort, SHF_ALLOC,
208ba2be530Sab 	    FAKE_M_WORD_ALIGN, sizeof (Word), ELF_T_WORD },
20939773e46Sab 
21039773e46Sab 	/* SINFO_T_VERNEED */
21139773e46Sab 	{ MSG_ORIG(MSG_PHDRNAM_VER), SHT_SUNW_verneed, SHF_ALLOC,
212ba2be530Sab 	    FAKE_M_WORD_ALIGN, 1, ELF_T_VNEED },
21339773e46Sab 
21439773e46Sab 	/* SINFO_T_VERDEF */
21539773e46Sab 	{ MSG_ORIG(MSG_PHDRNAM_VER), SHT_SUNW_verdef, SHF_ALLOC,
216ba2be530Sab 	    FAKE_M_WORD_ALIGN, 1, ELF_T_VDEF },
21739773e46Sab 
21839773e46Sab 	/* SINFO_T_VERSYM */
21939773e46Sab 	{ MSG_ORIG(MSG_PHDRNAM_VER), SHT_SUNW_versym, SHF_ALLOC,
220ba2be530Sab 	    FAKE_M_WORD_ALIGN, sizeof (Versym), ELF_T_HALF },
22139773e46Sab 
22239773e46Sab 	/* SINFO_T_INTERP */
22339773e46Sab 	{ MSG_ORIG(MSG_PHDRNAM_INTERP), SHT_PROGBITS, SHF_ALLOC,
22439773e46Sab 	    1, 0, ELF_T_BYTE },
22539773e46Sab 
22639773e46Sab 	/* SINFO_T_CAP */
22739773e46Sab 	{ MSG_ORIG(MSG_PHDRNAM_CAP), SHT_SUNW_cap, SHF_ALLOC,
22839773e46Sab 	    sizeof (Addr), sizeof (Cap), ELF_T_CAP },
22939773e46Sab 
230*08278a5eSRod Evans 	/* SINFO_T_CAPINFO */
231*08278a5eSRod Evans 	{ MSG_ORIG(MSG_PHDRNAM_CAPINFO), SHT_SUNW_capinfo, SHF_ALLOC,
232*08278a5eSRod Evans 	    FAKE_M_WORD_ALIGN, sizeof (Capinfo), ELF_T_WORD },
233*08278a5eSRod Evans 
234*08278a5eSRod Evans 	/* SINFO_T_CAPCHAIN */
235*08278a5eSRod Evans 	{ MSG_ORIG(MSG_PHDRNAM_CAPCHAIN), SHT_SUNW_capchain, SHF_ALLOC,
236*08278a5eSRod Evans 	    FAKE_M_WORD_ALIGN, sizeof (Capchain), ELF_T_WORD },
237*08278a5eSRod Evans 
23839773e46Sab 	/* SINFO_T_UNWIND */
23939773e46Sab 	{ MSG_ORIG(MSG_PHDRNAM_UNWIND), SHT_AMD64_UNWIND, SHF_ALLOC,
24039773e46Sab 	    sizeof (Addr), 0, ELF_T_BYTE },
24139773e46Sab 
24239773e46Sab 	/* SINFO_T_MOVE */
24339773e46Sab 	{ MSG_ORIG(MSG_PHDRNAM_MOVE), SHT_SUNW_move, SHF_ALLOC,
244*08278a5eSRod Evans 	    sizeof (Lword), sizeof (Move), ELF_T_MOVE },
24539773e46Sab 
24639773e46Sab 	/* SINFO_T_REL */
24739773e46Sab 	{ MSG_ORIG(MSG_PHDRNAM_REL), SHT_REL, SHF_ALLOC,
248ba2be530Sab 	    FAKE_M_WORD_ALIGN, sizeof (Rel), ELF_T_REL },
24939773e46Sab 
25039773e46Sab 	/* SINFO_T_RELA */
25139773e46Sab 	{ MSG_ORIG(MSG_PHDRNAM_RELA), SHT_RELA, SHF_ALLOC,
252ba2be530Sab 	    FAKE_M_WORD_ALIGN, sizeof (Rela), ELF_T_RELA },
25339773e46Sab 
25439773e46Sab 	/* SINFO_T_PREINITARR */
25539773e46Sab 	{ MSG_ORIG(MSG_PHDRNAM_PREINITARR), SHT_PREINIT_ARRAY, SHF_ALLOC,
25639773e46Sab 	    sizeof (Addr), sizeof (Addr), ELF_T_ADDR },
25739773e46Sab 
25839773e46Sab 	/* SINFO_T_INITARR */
25939773e46Sab 	{ MSG_ORIG(MSG_PHDRNAM_INITARR), SHT_INIT_ARRAY, SHF_ALLOC,
26039773e46Sab 	    sizeof (Addr), sizeof (Addr),  ELF_T_ADDR },
26139773e46Sab 
26239773e46Sab 	/* SINFO_T_FINIARR */
26339773e46Sab 	{ MSG_ORIG(MSG_PHDRNAM_FINIARR), SHT_FINI_ARRAY, SHF_ALLOC,
26439773e46Sab 	    sizeof (Addr), sizeof (Addr), ELF_T_ADDR },
26539773e46Sab 
26639773e46Sab 	/* SINFO_T_NOTE */
26739773e46Sab 	{ MSG_ORIG(MSG_PHDRNAM_NOTE), SHT_NOTE, 0,
268ba2be530Sab 	    FAKE_M_WORD_ALIGN, 1, ELF_T_NOTE }
26939773e46Sab };
27039773e46Sab 
27139773e46Sab 
27239773e46Sab 
27339773e46Sab 
27439773e46Sab 
27539773e46Sab /*
27639773e46Sab  * As we read program headers and dynamic elements, we build up
27739773e46Sab  * the data for our fake section headers in variables of the
27839773e46Sab  * SINFO type. SINFO is used to track the sections that can only
27939773e46Sab  * appear a fixed number of times (usually once).
28039773e46Sab  *
28139773e46Sab  * SINFO_LISTELT is used for sections that can occur an arbitrary
28239773e46Sab  * number of times. They are kept in a doubly linked circular
28339773e46Sab  * buffer.
28439773e46Sab  */
28539773e46Sab typedef struct {
28639773e46Sab 	SINFO_TYPE	type;	/* Our type code for the section */
28739773e46Sab 	Addr		vaddr;	/* Virtual memory address */
28839773e46Sab 	Off		offset;	/* File offset of data. Ignored unless */
28939773e46Sab 				/*	vaddr is 0. Used by program headers */
29039773e46Sab 	size_t		size;	/* # bytes in section */
29139773e46Sab 	size_t		vercnt;	/* Used by verdef and verneed to hold count */
29239773e46Sab 	Shdr		*shdr;	/* Constructed shdr */
29339773e46Sab 	Elf_Data	*data;	/* Constructed data descriptor */
29439773e46Sab } SINFO;
29539773e46Sab 
29639773e46Sab typedef struct _sinfo_listelt {
29739773e46Sab 	struct _sinfo_listelt	*next;
29839773e46Sab 	struct _sinfo_listelt	*prev;
29939773e46Sab 	SINFO			sinfo;
30039773e46Sab } SINFO_LISTELT;
30139773e46Sab 
30239773e46Sab 
30339773e46Sab 
30439773e46Sab /*
30539773e46Sab  * Free dynamic memory used by SINFO structures.
30639773e46Sab  *
30739773e46Sab  * entry:
30839773e46Sab  *	sinfo - Address of first SINFO structure to free
30939773e46Sab  *	n - # of structures to clear
31039773e46Sab  *
31139773e46Sab  * exit:
31239773e46Sab  *	For each SINFO struct, the section header, data descriptor,
31339773e46Sab  *	and data buffer are freed if non-NULL. The relevant
31439773e46Sab  *	fields are set to NULL, and the type is set to SINFO_T_NULL.
31539773e46Sab  */
31639773e46Sab static void
sinfo_free(SINFO * sinfo,size_t n)31739773e46Sab sinfo_free(SINFO *sinfo, size_t n)
31839773e46Sab {
31939773e46Sab 	for (; n-- > 0; sinfo++) {
32039773e46Sab 		if (sinfo->data != NULL) {
32139773e46Sab 			if (sinfo->data->d_buf != NULL)
32239773e46Sab 				free(sinfo->data->d_buf);
32339773e46Sab 			free(sinfo->data);
32439773e46Sab 			sinfo->data = NULL;
32539773e46Sab 		}
32639773e46Sab 
32739773e46Sab 		if (sinfo->shdr) {
32839773e46Sab 			free(sinfo->shdr);
32939773e46Sab 			sinfo->shdr = NULL;
33039773e46Sab 		}
33139773e46Sab 		sinfo->type = SINFO_T_NULL;
33239773e46Sab 	}
33339773e46Sab }
33439773e46Sab 
33539773e46Sab 
33639773e46Sab 
33739773e46Sab /*
33839773e46Sab  * Allocate a new SINFO_LISTELT and put it at the end of the
33939773e46Sab  * doubly linked list anchored by the given list root node.
34039773e46Sab  *
34139773e46Sab  * On success, a new node has been put at the end of the circular
34239773e46Sab  * doubly linked list, and a pointer to the SINFO sub-structure is
34339773e46Sab  * returned. On failure, an error is printed, and NULL is returned.
34439773e46Sab  */
34539773e46Sab 
34639773e46Sab static SINFO *
sinfo_list_alloc(FSTATE * fstate,SINFO_LISTELT * root)34739773e46Sab sinfo_list_alloc(FSTATE *fstate, SINFO_LISTELT *root)
34839773e46Sab {
34939773e46Sab 	SINFO_LISTELT *elt;
35039773e46Sab 
35139773e46Sab 	if ((elt = malloc(sizeof (*elt))) == NULL) {
35239773e46Sab 		int err = errno;
35339773e46Sab 		(void) fprintf(stderr, MSG_INTL(MSG_ERR_MALLOC),
35439773e46Sab 		    fstate->file, strerror(err));
35539773e46Sab 		return (0);
35639773e46Sab 	}
35739773e46Sab 
35839773e46Sab 	elt->next = root;
35939773e46Sab 	elt->prev = root->prev;
36039773e46Sab 
36139773e46Sab 	root->prev = elt;
36239773e46Sab 	elt->prev->next = elt;
36339773e46Sab 
36439773e46Sab 	bzero(&elt->sinfo, sizeof (elt->sinfo));
36539773e46Sab 	return (&elt->sinfo);
36639773e46Sab }
36739773e46Sab 
36839773e46Sab 
36939773e46Sab 
37039773e46Sab /*
37139773e46Sab  * Release the memory used by the given list, restoring it to
37239773e46Sab  * an empty list.
37339773e46Sab  */
37439773e46Sab static void
sinfo_list_free_all(SINFO_LISTELT * root)37539773e46Sab sinfo_list_free_all(SINFO_LISTELT *root)
37639773e46Sab {
37739773e46Sab 	SINFO_LISTELT *elt;
37839773e46Sab 
37939773e46Sab 	for (elt = root->next; elt != root; elt = elt->next)
38039773e46Sab 		sinfo_free(&elt->sinfo, 1);
38139773e46Sab 
38239773e46Sab 	root->next = root->prev = root;
38339773e46Sab }
38439773e46Sab 
38539773e46Sab 
38639773e46Sab 
38739773e46Sab /*
38839773e46Sab  * Given a virtual address and desired size of the data to be found
38939773e46Sab  * at that address, look through the program headers for the PT_LOAD
39039773e46Sab  * segment that contains it and return the offset within the ELF file
39139773e46Sab  * at which it resides.
39239773e46Sab  *
39339773e46Sab  * entry:
39439773e46Sab  *	fstate - Object state
39539773e46Sab  *	addr - virtual address to be translated
39639773e46Sab  *	size - Size of the data to be found at that address, in bytes
39739773e46Sab  *	zero_bytes - NULL, or address to receive the number of data
39839773e46Sab  *		bytes at the end of the data that are not contained
39939773e46Sab  *		in the file, and which must be zero filled by the caller.
40039773e46Sab  *		If zero_bytes is NULL, the file must contain all of the
40139773e46Sab  *		desired data. If zero_bytes is not NULL, then the program
40239773e46Sab  *		header must reserve the space for all of the data (p_memsz)
40339773e46Sab  *		but it is acceptable for only part of the data to be in
40439773e46Sab  *		the file (p_filesz). *zero_bytes is set to the difference
40539773e46Sab  *		in size, and is the number of bytes the caller must
40639773e46Sab  *		set to 0 rather than reading from the file.
40739773e46Sab  *	phdr_ret - NULL, or address of variable to receive pointer
40839773e46Sab  *		to program header that contains offset.
40939773e46Sab  * exit:
41039773e46Sab  *	On success: If zero_bytes is non-NULL, it is updated. If phdr_ret
41139773e46Sab  *	is non-NULL, it is updated. The file offset is returned.
41239773e46Sab  *
41339773e46Sab  *	On failure, 0 is returned. Since any ELF file we can understand
41439773e46Sab  *	must start with an ELF magic number, 0 cannot be a valid file
41539773e46Sab  *	offset for a virtual address, and is therefore unambiguous as
41639773e46Sab  *	a failure indication.
41739773e46Sab  */
41839773e46Sab static Off
map_addr_to_offset(FSTATE * fstate,Addr addr,size_t size,size_t * zero_bytes,Phdr ** phdr_ret)41939773e46Sab map_addr_to_offset(FSTATE *fstate, Addr addr, size_t size, size_t *zero_bytes,
42039773e46Sab     Phdr **phdr_ret)
42139773e46Sab {
42239773e46Sab 	Off	offset;
42339773e46Sab 	Addr	end_addr = addr + size;
42439773e46Sab 	size_t	avail_file;
42539773e46Sab 	Phdr	*phdr = fstate->phdr;
42639773e46Sab 	size_t	phnum = fstate->phnum;
42739773e46Sab 
42839773e46Sab 	for (; phnum--; phdr++) {
42939773e46Sab 		if (phdr->p_type != PT_LOAD)
43039773e46Sab 			continue;
43139773e46Sab 
43239773e46Sab 		if ((addr >= phdr->p_vaddr) &&
43339773e46Sab 		    (end_addr <= (phdr->p_vaddr + phdr->p_memsz))) {
43439773e46Sab 			/*
43539773e46Sab 			 * Subtract segment virtual address, leaving the
43639773e46Sab 			 * offset relative to the segment (not the file).
43739773e46Sab 			 */
43839773e46Sab 			offset = addr - phdr->p_vaddr;
43939773e46Sab 			avail_file = phdr->p_filesz - offset;
44039773e46Sab 
44139773e46Sab 			/*
44239773e46Sab 			 * The addr/size are in bounds for this segment.
44339773e46Sab 			 * Is there enough data in the file to satisfy
44439773e46Sab 			 * the request? If zero_bytes is NULL, it must
44539773e46Sab 			 * all be in the file. Otherwise it can be
44639773e46Sab 			 * zero filled.
44739773e46Sab 			 */
44839773e46Sab 			if (zero_bytes == NULL) {
44939773e46Sab 				if (size > avail_file)
45039773e46Sab 					continue;
45139773e46Sab 			} else {
45239773e46Sab 				*zero_bytes = (size > avail_file) ?
45339773e46Sab 				    (size - avail_file) : 0;
45439773e46Sab 			}
45539773e46Sab 
45639773e46Sab 			if (phdr_ret != NULL)
45739773e46Sab 				*phdr_ret = phdr;
45839773e46Sab 
45939773e46Sab 			/* Add segment file offset, giving overall offset */
46039773e46Sab 			return (phdr->p_offset + offset);
46139773e46Sab 		}
46239773e46Sab 	}
46339773e46Sab 
46439773e46Sab 	/* If we get here, the mapping failed */
46539773e46Sab 	return (0);
46639773e46Sab }
46739773e46Sab 
46839773e46Sab 
46939773e46Sab 
47039773e46Sab /*
47139773e46Sab  * This routine is the same thing as map_addr_to_offset(), except that
47239773e46Sab  * it goes the other way, mapping from offset to virtual address.
47339773e46Sab  *
47439773e46Sab  * The comments for map_addr_to_offset() are applicable if you
47539773e46Sab  * reverse offset and address.
47639773e46Sab  */
47739773e46Sab 
47839773e46Sab static Addr
map_offset_to_addr(FSTATE * fstate,Off offset,size_t size,size_t * zero_bytes,Phdr ** phdr_ret)47939773e46Sab map_offset_to_addr(FSTATE *fstate, Off offset, size_t size, size_t *zero_bytes,
48039773e46Sab     Phdr **phdr_ret)
48139773e46Sab {
48239773e46Sab 	Off	end_offset = offset + size;
48339773e46Sab 	size_t	avail_file;
48439773e46Sab 	Phdr	*phdr = fstate->phdr;
48539773e46Sab 	size_t	phnum = fstate->phnum;
48639773e46Sab 
48739773e46Sab 	for (; phnum--; phdr++) {
48839773e46Sab 		if (phdr->p_type != PT_LOAD)
48939773e46Sab 			continue;
49039773e46Sab 
49139773e46Sab 		if ((offset >= phdr->p_offset) &&
49239773e46Sab 		    (end_offset <= (phdr->p_offset + phdr->p_memsz))) {
49339773e46Sab 			/*
49439773e46Sab 			 * Subtract segment offset, leaving the
49539773e46Sab 			 * offset relative to the segment (not the file).
49639773e46Sab 			 */
49739773e46Sab 			offset -= phdr->p_offset;
49839773e46Sab 			avail_file = phdr->p_filesz - offset;
49939773e46Sab 
50039773e46Sab 			/*
50139773e46Sab 			 * The offset/size are in bounds for this segment.
50239773e46Sab 			 * Is there enough data in the file to satisfy
50339773e46Sab 			 * the request? If zero_bytes is NULL, it must
50439773e46Sab 			 * all be in the file. Otherwise it can be
50539773e46Sab 			 * zero filled.
50639773e46Sab 			 */
50739773e46Sab 			if (zero_bytes == NULL) {
50839773e46Sab 				if (size > avail_file)
50939773e46Sab 					continue;
51039773e46Sab 			} else {
51139773e46Sab 				*zero_bytes = (size > avail_file) ?
51239773e46Sab 				    (size - avail_file) : 0;
51339773e46Sab 			}
51439773e46Sab 
51539773e46Sab 			if (phdr_ret != NULL)
51639773e46Sab 				*phdr_ret = phdr;
51739773e46Sab 
51839773e46Sab 			/* Add segment virtual address, giving overall addr */
51939773e46Sab 			return (phdr->p_vaddr + offset);
52039773e46Sab 		}
52139773e46Sab 	}
52239773e46Sab 
52339773e46Sab 	/* If we get here, the mapping failed */
52439773e46Sab 	return (0);
52539773e46Sab }
52639773e46Sab 
52739773e46Sab 
52839773e46Sab 
52939773e46Sab /*
53039773e46Sab  * Use elf_xlatetom() to convert the bytes in buf from their
53139773e46Sab  * in-file representation to their in-memory representation.
53239773e46Sab  *
53339773e46Sab  * Returns True(1) for success. On failure, an error message is printed
53439773e46Sab  * and False(0) is returned.
53539773e46Sab  */
53639773e46Sab static int
xlate_data(FSTATE * fstate,void * buf,size_t nbyte,Elf_Type xlate_type)53739773e46Sab xlate_data(FSTATE *fstate, void *buf, size_t nbyte, Elf_Type xlate_type)
53839773e46Sab {
53939773e46Sab 	Elf_Data	data;
54039773e46Sab 
54139773e46Sab 	data.d_type = xlate_type;
54239773e46Sab 	data.d_size = nbyte;
54339773e46Sab 	data.d_off = 0;
54439773e46Sab 	data.d_align = 0;
54539773e46Sab 	data.d_version = fstate->ehdr->e_version;
54639773e46Sab 	data.d_buf = buf;
54739773e46Sab 
54839773e46Sab 	if (elf_xlatetom(&data, &data,
54939773e46Sab 	    fstate->ehdr->e_ident[EI_DATA]) == NULL) {
55039773e46Sab 		failure(fstate->file, MSG_ORIG(MSG_ELF_XLATETOM));
55139773e46Sab 		return (0);
55239773e46Sab 	}
55339773e46Sab 
55439773e46Sab 	return (1);
55539773e46Sab }
55639773e46Sab 
55739773e46Sab 
55839773e46Sab /*
55939773e46Sab  * Read nbytes of data into buf, starting at the specified offset
56039773e46Sab  * within the ELF file.
56139773e46Sab  *
56239773e46Sab  * entry:
56339773e46Sab  *	fstate - Object state
56439773e46Sab  *	offset - Offset within the file at which desired data resides.
56539773e46Sab  *	buf - Buffer to receive the data
56639773e46Sab  *	nbyte - # of bytes to read into buf
56739773e46Sab  *	xlate_type - An ELF xlate type, specifying the type of data
56839773e46Sab  *		being input. If xlate_type is ELF_T_BYTE, xlate is not
56939773e46Sab  *		done. Otherwise, xlate_data() is called to convert the
57039773e46Sab  *		data into its in-memory representation.
57139773e46Sab  * exit:
57239773e46Sab  *	On success, the data has been written into buf, xlate_data()
57339773e46Sab  *	called on it if required, and True(1) is returned. Otherwise
57439773e46Sab  *	False(0) is returned.
57539773e46Sab  *
57639773e46Sab  * note:
57739773e46Sab  *	This routine does not move the file pointer.
57839773e46Sab  */
57939773e46Sab static int
read_data(FSTATE * fstate,Off offset,void * buf,size_t nbyte,Elf_Type xlate_type)58039773e46Sab read_data(FSTATE *fstate, Off offset, void *buf, size_t nbyte,
58139773e46Sab     Elf_Type xlate_type)
58239773e46Sab {
58339773e46Sab 	if (pread(fstate->fd, buf, nbyte, offset) != nbyte) {
58439773e46Sab 		int err = errno;
58539773e46Sab 
58639773e46Sab 		(void) fprintf(stderr, MSG_INTL(MSG_ERR_READ),
58739773e46Sab 		    fstate->file, strerror(err));
58839773e46Sab 		return (0);
58939773e46Sab 	}
59039773e46Sab 
59139773e46Sab 	if (xlate_type != ELF_T_BYTE)
59239773e46Sab 		return (xlate_data(fstate, buf, nbyte, xlate_type));
59339773e46Sab 
59439773e46Sab 	return (1);
59539773e46Sab }
59639773e46Sab 
59739773e46Sab 
59839773e46Sab 
59939773e46Sab /*
60039773e46Sab  * Read the hash nbucket/nchain values from the start of the hash
60139773e46Sab  * table found at the given virtual address in the mapped ELF object.
60239773e46Sab  *
60339773e46Sab  * On success, *nbucket, and *nchain have been filled in with their
60439773e46Sab  * values, *total contains the number of elements in the hash table,
60539773e46Sab  * and this routine returns True (1).
60639773e46Sab  *
60739773e46Sab  * On failure, False (0) is returned.
60839773e46Sab  */
60939773e46Sab static int
hash_size(FSTATE * fstate,SINFO * hash_sinfo,Word * nbucket,Word * nchain,size_t * total)61039773e46Sab hash_size(FSTATE *fstate, SINFO *hash_sinfo,
61139773e46Sab     Word *nbucket, Word *nchain, size_t *total)
61239773e46Sab {
61339773e46Sab 	Off		offset;
61439773e46Sab 	Word		buf[2];
61539773e46Sab 
61639773e46Sab 	offset = map_addr_to_offset(fstate, hash_sinfo->vaddr,
61739773e46Sab 	    sizeof (buf), NULL, NULL);
61839773e46Sab 	if (offset == 0)
61939773e46Sab 		return (0);
62039773e46Sab 
62139773e46Sab 	if (read_data(fstate, offset, buf, sizeof (buf), ELF_T_WORD) == 0)
62239773e46Sab 		return (0);
62339773e46Sab 
62439773e46Sab 	*nbucket = buf[0];
62539773e46Sab 	*nchain = buf[1];
62639773e46Sab 	*total = 2 + *nbucket + *nchain;
62739773e46Sab 	return (1);
62839773e46Sab }
62939773e46Sab 
63039773e46Sab 
63139773e46Sab 
63239773e46Sab /*
63339773e46Sab  * Read a Verdef structure at the specified file offset and return
63439773e46Sab  * its vd_cnt, vd_aux, and vd_next fields.
63539773e46Sab  */
63639773e46Sab static int
read_verdef(FSTATE * fstate,Off offset,Half * cnt,Word * aux,Word * next)63739773e46Sab read_verdef(FSTATE *fstate, Off offset, Half *cnt, Word *aux, Word *next)
63839773e46Sab {
63939773e46Sab 	Verdef		verdef;
64039773e46Sab 
64139773e46Sab 	if (read_data(fstate, offset, &verdef, sizeof (verdef),
64239773e46Sab 	    ELF_T_BYTE) == 0)
64339773e46Sab 		return (0);
64439773e46Sab 
64539773e46Sab 	/* xlate vd_cnt */
64639773e46Sab 	if (xlate_data(fstate, &verdef.vd_cnt, sizeof (verdef.vd_cnt),
64739773e46Sab 	    ELF_T_HALF) == 0)
64839773e46Sab 		return (0);
64939773e46Sab 
65039773e46Sab 	/*
65139773e46Sab 	 * xlate vd_aux and vd_next. These items are adjacent and are
65239773e46Sab 	 * both Words, so they can be handled in a single operation.
65339773e46Sab 	 */
65439773e46Sab 	if (xlate_data(fstate, &verdef.vd_aux,
65539773e46Sab 	    2 * sizeof (Word), ELF_T_WORD) == 0)
65639773e46Sab 		return (0);
65739773e46Sab 
65839773e46Sab 	*cnt = verdef.vd_cnt;
65939773e46Sab 	*aux = verdef.vd_aux;
66039773e46Sab 	*next = verdef.vd_next;
66139773e46Sab 
66239773e46Sab 	return (1);
66339773e46Sab }
66439773e46Sab 
66539773e46Sab 
66639773e46Sab 
66739773e46Sab /*
66839773e46Sab  * Read a Verdaux structure at the specified file offset and return
66939773e46Sab  * its vda_next field.
67039773e46Sab  */
67139773e46Sab static int
read_verdaux(FSTATE * fstate,Off offset,Word * next)67239773e46Sab read_verdaux(FSTATE *fstate, Off offset, Word *next)
67339773e46Sab {
67439773e46Sab 	Verdaux		verdaux;
67539773e46Sab 
67639773e46Sab 	if (read_data(fstate, offset, &verdaux, sizeof (verdaux),
67739773e46Sab 	    ELF_T_BYTE) == 0)
67839773e46Sab 		return (0);
67939773e46Sab 
68039773e46Sab 	/* xlate vda_next */
68139773e46Sab 	if (xlate_data(fstate, &verdaux.vda_next, sizeof (verdaux.vda_next),
68239773e46Sab 	    ELF_T_WORD) == 0)
68339773e46Sab 		return (0);
68439773e46Sab 
68539773e46Sab 	*next = verdaux.vda_next;
68639773e46Sab 
68739773e46Sab 	return (1);
68839773e46Sab }
68939773e46Sab 
69039773e46Sab 
69139773e46Sab 
69239773e46Sab /*
69339773e46Sab  * Read a Verneed structure at the specified file offset and return
69439773e46Sab  * its vn_cnt, vn_aux, and vn_next fields.
69539773e46Sab  */
69639773e46Sab static int
read_verneed(FSTATE * fstate,Off offset,Half * cnt,Word * aux,Word * next)69739773e46Sab read_verneed(FSTATE *fstate, Off offset, Half *cnt, Word *aux, Word *next)
69839773e46Sab {
69939773e46Sab 	Verneed		verneed;
70039773e46Sab 
70139773e46Sab 	if (read_data(fstate, offset, &verneed, sizeof (verneed),
70239773e46Sab 	    ELF_T_BYTE) == 0)
70339773e46Sab 		return (0);
70439773e46Sab 
70539773e46Sab 	/* xlate vn_cnt */
70639773e46Sab 	if (xlate_data(fstate, &verneed.vn_cnt, sizeof (verneed.vn_cnt),
70739773e46Sab 	    ELF_T_HALF) == 0)
70839773e46Sab 		return (0);
70939773e46Sab 
71039773e46Sab 	/*
71139773e46Sab 	 * xlate vn_aux and vn_next. These items are adjacent and are
71239773e46Sab 	 * both Words, so they can be handled in a single operation.
71339773e46Sab 	 */
71439773e46Sab 	if (xlate_data(fstate, &verneed.vn_aux,
71539773e46Sab 	    2 * sizeof (Word), ELF_T_WORD) == 0)
71639773e46Sab 		return (0);
71739773e46Sab 
71839773e46Sab 	*cnt = verneed.vn_cnt;
71939773e46Sab 	*aux = verneed.vn_aux;
72039773e46Sab 	*next = verneed.vn_next;
72139773e46Sab 
72239773e46Sab 	return (1);
72339773e46Sab }
72439773e46Sab 
72539773e46Sab 
72639773e46Sab 
72739773e46Sab /*
72839773e46Sab  * Read a Vernaux structure at the specified file offset and return
72939773e46Sab  * its vna_next field.
73039773e46Sab  */
73139773e46Sab static int
read_vernaux(FSTATE * fstate,Off offset,Word * next)73239773e46Sab read_vernaux(FSTATE *fstate, Off offset, Word *next)
73339773e46Sab {
73439773e46Sab 	Vernaux		vernaux;
73539773e46Sab 
73639773e46Sab 	if (read_data(fstate, offset, &vernaux, sizeof (vernaux),
73739773e46Sab 	    ELF_T_BYTE) == 0)
73839773e46Sab 		return (0);
73939773e46Sab 
74039773e46Sab 	/* xlate vna_next */
74139773e46Sab 	if (xlate_data(fstate, &vernaux.vna_next, sizeof (vernaux.vna_next),
74239773e46Sab 	    ELF_T_WORD) == 0)
74339773e46Sab 		return (0);
74439773e46Sab 
74539773e46Sab 	*next = vernaux.vna_next;
74639773e46Sab 
74739773e46Sab 	return (1);
74839773e46Sab }
74939773e46Sab 
75039773e46Sab 
75139773e46Sab 
75239773e46Sab /*
75339773e46Sab  * Compute the size of Verdef and Verneed sections. Both of these
75439773e46Sab  * sections are made up of interleaved main nodes (Verdef and Verneed)
75539773e46Sab  * and auxiliary blocks (Verdaux and Vernaux). These nodes refer to
75639773e46Sab  * each other by relative offsets. The linker has a lot of flexibility
75739773e46Sab  * in how it lays out these items, and we cannot assume a standard
75839773e46Sab  * layout. To determine the size of the section, we must read each
75939773e46Sab  * main node and compute the high water mark of the memory it and its
76039773e46Sab  * auxiliary structs access.
76139773e46Sab  *
76239773e46Sab  * Although Verdef/Verdaux and Verneed/Vernaux are different types,
76339773e46Sab  * their logical organization is the same. Each main block has
76439773e46Sab  * a cnt field that tells how many auxiliary blocks it has, an
76539773e46Sab  * aux field that gives the offset of the first auxiliary block, and
76639773e46Sab  * an offset to the next main block. Each auxiliary block contains
76739773e46Sab  * an offset to the next auxiliary block. By breaking the type specific
76839773e46Sab  * code into separate sub-functions, we can process both Verdef and
76939773e46Sab  * sections Verdaux from a single routine.
77039773e46Sab  *
77139773e46Sab  * entry:
77239773e46Sab  *	fstate - Object state
77339773e46Sab  *	sec - Section to be processed (SINFO_T_VERDEF or SINFO_T_VERNEED).
77439773e46Sab  *
77539773e46Sab  * exit:
77639773e46Sab  *	On success, sec->size is set to the section size in bytes, and
77739773e46Sab  *	True (1) is returned. On failure, False (0) is returned.
77839773e46Sab  */
77939773e46Sab static int
verdefneed_size(FSTATE * fstate,SINFO * sec)78039773e46Sab verdefneed_size(FSTATE *fstate, SINFO *sec)
78139773e46Sab {
78239773e46Sab 	int (* read_main)(FSTATE *, Off, Half *, Word *, Word *);
78339773e46Sab 	int (* read_aux)(FSTATE *, Off, Word *);
78439773e46Sab 	size_t	size_main, size_aux;
78539773e46Sab 
78639773e46Sab 	Off	offset, aux_offset;
78739773e46Sab 	Off	highwater, extent;
78839773e46Sab 	size_t	num_main = sec->vercnt;
78939773e46Sab 	Half	v_cnt;
79039773e46Sab 	Word	v_aux, v_next, va_next;
79139773e46Sab 
79239773e46Sab 
79339773e46Sab 	/*
79439773e46Sab 	 * Set up the function pointers to the type-specific code
79539773e46Sab 	 * for fetching data from the main and auxiliary blocks.
79639773e46Sab 	 */
79739773e46Sab 	if (sec->type == SINFO_T_VERDEF) {
79839773e46Sab 		read_main = read_verdef;
79939773e46Sab 		read_aux = read_verdaux;
80039773e46Sab 		size_main = sizeof (Verdef);
80139773e46Sab 		size_aux = sizeof (Verdaux);
80239773e46Sab 	} else {			/* SINFO_T_VERNEED */
80339773e46Sab 		read_main = read_verneed;
80439773e46Sab 		read_aux = read_vernaux;
80539773e46Sab 		size_main = sizeof (Verneed);
80639773e46Sab 		size_aux = sizeof (Vernaux);
80739773e46Sab 	}
80839773e46Sab 
80939773e46Sab 	/*
81039773e46Sab 	 * Map starting address to file offset. Save the starting offset
81139773e46Sab 	 * in the SINFO size field. Once we have the high water offset, we
81239773e46Sab 	 * can subtract this from it to get the size.
81339773e46Sab 	 *
81439773e46Sab 	 * Note: The size argument set here is a lower bound --- the
81539773e46Sab 	 * size of the main blocks without any auxiliary ones. It's
81639773e46Sab 	 * the best we can do until the size has been determined for real.
81739773e46Sab 	 */
81839773e46Sab 	offset = highwater = map_addr_to_offset(fstate, sec->vaddr,
81939773e46Sab 	    size_main * num_main, NULL, NULL);
82039773e46Sab 	if (offset == 0)
82139773e46Sab 		return (0);
82239773e46Sab 	sec->size = offset;
82339773e46Sab 
82439773e46Sab 	for (; num_main-- > 0; offset += v_next) {
82539773e46Sab 		/* Does this move the high water mark up? */
82639773e46Sab 		extent = offset + size_main;
82739773e46Sab 		if (extent > highwater)
82839773e46Sab 			highwater = extent;
82939773e46Sab 
83039773e46Sab 		if ((*read_main)(fstate, offset, &v_cnt, &v_aux, &v_next) == 0)
83139773e46Sab 			return (0);
83239773e46Sab 
83339773e46Sab 		/*
83439773e46Sab 		 * If there are auxiliary structures referenced,
83539773e46Sab 		 * check their position to see if it pushes
83639773e46Sab 		 * the high water mark.
83739773e46Sab 		 */
83839773e46Sab 		aux_offset = offset + v_aux;
83939773e46Sab 		for (; v_cnt-- > 0; aux_offset += va_next) {
84039773e46Sab 			extent = aux_offset + size_aux;
84139773e46Sab 			if (extent > highwater)
84239773e46Sab 				highwater = extent;
84339773e46Sab 
84439773e46Sab 			if ((*read_aux)(fstate, aux_offset, &va_next) == 0)
84539773e46Sab 				return (0);
84639773e46Sab 		}
84739773e46Sab 	}
84839773e46Sab 
84939773e46Sab 	sec->size = highwater - sec->size;
85039773e46Sab 	return (1);
85139773e46Sab }
85239773e46Sab 
85339773e46Sab 
85439773e46Sab /*
85539773e46Sab  * Allocate and fill in a fake section header, data descriptor,
85639773e46Sab  * and data buffer for the given section. Fill them in and read
85739773e46Sab  * the associated data into the buffer.
85839773e46Sab  *
85939773e46Sab  * entry:
86039773e46Sab  *	fstate - Object state
86139773e46Sab  *	sec - Section information
86239773e46Sab  *
86339773e46Sab  * exit:
86439773e46Sab  *	On success, the actions described above are complete, and
86539773e46Sab  *	True (1) is returned.
86639773e46Sab  *
86739773e46Sab  *	On failure, an error is reported, all resources used by sec
86839773e46Sab  *	are released, and sec->type is set to SINFO_T_NULL, effectively
86939773e46Sab  *	eliminating its contents from any further use. False (0) is
87039773e46Sab  *	returned.
87139773e46Sab  */
87239773e46Sab static int
get_data(FSTATE * fstate,SINFO * sec)87339773e46Sab get_data(FSTATE *fstate, SINFO *sec)
87439773e46Sab {
87539773e46Sab 
87639773e46Sab 	SINFO_DATA	*tinfo;
87739773e46Sab 	size_t		read_bytes, zero_bytes;
87839773e46Sab 	Phdr		*phdr = NULL;
87939773e46Sab 
88039773e46Sab 	/*
88139773e46Sab 	 * If this is a NULL section, or if we've already processed
88239773e46Sab 	 * this item, then we are already done.
88339773e46Sab 	 */
88439773e46Sab 	if ((sec->type == SINFO_T_NULL) || (sec->shdr != NULL))
88539773e46Sab 		return (1);
88639773e46Sab 
88739773e46Sab 	if (((sec->shdr = malloc(sizeof (*sec->shdr))) == NULL) ||
88839773e46Sab 	    ((sec->data = malloc(sizeof (*sec->data))) == NULL)) {
88939773e46Sab 		int err = errno;
89039773e46Sab 		sinfo_free(sec, 1);
89139773e46Sab 		(void) fprintf(stderr, MSG_INTL(MSG_ERR_MALLOC),
89239773e46Sab 		    fstate->file, strerror(err));
89339773e46Sab 		return (0);
89439773e46Sab 	}
89539773e46Sab 	tinfo = &sinfo_data[sec->type];
89639773e46Sab 
89739773e46Sab 
89839773e46Sab 
89939773e46Sab 	/*
90039773e46Sab 	 * Fill in fake section header
90139773e46Sab 	 *
90239773e46Sab 	 * sh_name should be the offset of the name in the shstrtab
90339773e46Sab 	 * section referenced by the ELF header. There is no
90439773e46Sab 	 * value to elfdump in creating shstrtab, so we set
90539773e46Sab 	 * sh_name to 0, knowing that elfdump doesn't look at it.
90639773e46Sab 	 */
90739773e46Sab 	sec->shdr->sh_name = 0;
90839773e46Sab 	sec->shdr->sh_type = tinfo->sh_type;
90939773e46Sab 	sec->shdr->sh_flags = tinfo->sh_flags;
91039773e46Sab 	if ((tinfo->sh_flags & SHF_ALLOC) == 0) {
91139773e46Sab 		/*
91239773e46Sab 		 * Non-allocable section: Pass the addr (which is probably
91339773e46Sab 		 * 0) and offset through without inspection.
91439773e46Sab 		 */
91539773e46Sab 		sec->shdr->sh_addr = sec->vaddr;
91639773e46Sab 		sec->shdr->sh_offset = sec->offset;
91739773e46Sab 		zero_bytes = 0;
91839773e46Sab 	} else if (sec->vaddr == 0) {
91939773e46Sab 		/*
92039773e46Sab 		 * Allocable section with a 0 vaddr. Figure out the
92139773e46Sab 		 * real address by mapping the offset to it using the
92239773e46Sab 		 * program headers.
92339773e46Sab 		 */
92439773e46Sab 		sec->shdr->sh_addr = map_offset_to_addr(fstate, sec->offset,
92539773e46Sab 		    sec->size, &zero_bytes, &phdr);
92639773e46Sab 		sec->shdr->sh_offset = sec->offset;
92739773e46Sab 	} else {
92839773e46Sab 		/*
92939773e46Sab 		 * Allocable section with non-0 vaddr. Use the vaddr
93039773e46Sab 		 * to derive the offset.
93139773e46Sab 		 */
93239773e46Sab 		sec->shdr->sh_addr = sec->vaddr;
93339773e46Sab 		sec->shdr->sh_offset = map_addr_to_offset(fstate,
93439773e46Sab 		    sec->vaddr, sec->size, &zero_bytes, &phdr);
93539773e46Sab 	}
93639773e46Sab 	if (sec->shdr->sh_offset == 0) {
93739773e46Sab 		sinfo_free(sec, 1);
93839773e46Sab 		return (0);
93939773e46Sab 	}
94039773e46Sab 	/*
94139773e46Sab 	 * If the program header has its write flags set, then set
94239773e46Sab 	 * the section write flag.
94339773e46Sab 	 */
94439773e46Sab 	if (phdr && ((phdr->p_flags & PF_W) != 0))
94539773e46Sab 		sec->shdr->sh_flags |= SHF_WRITE;
94639773e46Sab 	sec->shdr->sh_size = sec->size;
94739773e46Sab 	sec->shdr->sh_link = 0;
94839773e46Sab 	sec->shdr->sh_info = 0;
94939773e46Sab 	sec->shdr->sh_addralign = tinfo->sh_addralign;
95039773e46Sab 	sec->shdr->sh_entsize = tinfo->sh_entsize;
95139773e46Sab 
95239773e46Sab 	/*
95339773e46Sab 	 * Some sections define special meanings for sh_link and sh_info.
95439773e46Sab 	 */
95539773e46Sab 	switch (tinfo->sh_type) {
95639773e46Sab 	case SHT_DYNAMIC:
95739773e46Sab 		sec->shdr->sh_link = SINFO_T_DYNSTR;
95839773e46Sab 		break;
95939773e46Sab 
96039773e46Sab 	case SHT_DYNSYM:
96139773e46Sab 		sec->shdr->sh_link = SINFO_T_DYNSTR;
96239773e46Sab 		sec->shdr->sh_info = 1;	/* First global symbol */
96339773e46Sab 		break;
96439773e46Sab 
96539773e46Sab 	case SHT_SUNW_LDYNSYM:
96639773e46Sab 		sec->shdr->sh_link = SINFO_T_DYNSTR;
96739773e46Sab 		/*
96839773e46Sab 		 * ldynsym is all local symbols, so the index of the
96939773e46Sab 		 * first global is equivalent to the number of symbols.
97039773e46Sab 		 */
97139773e46Sab 		sec->shdr->sh_info = sec->shdr->sh_size / sizeof (Sym);
97239773e46Sab 		break;
97339773e46Sab 
97439773e46Sab 	case SHT_HASH:
97539773e46Sab 	case SHT_SUNW_move:
97639773e46Sab 	case SHT_REL:
97739773e46Sab 	case SHT_RELA:
97839773e46Sab 	case SHT_SUNW_versym:
97939773e46Sab 		sec->shdr->sh_link = SINFO_T_DYNSYM;
98039773e46Sab 		break;
98139773e46Sab 
98239773e46Sab 	case SHT_SUNW_verdef:
98339773e46Sab 	case SHT_SUNW_verneed:
98439773e46Sab 		sec->shdr->sh_link = SINFO_T_DYNSTR;
98539773e46Sab 		sec->shdr->sh_info = sec->vercnt;
98639773e46Sab 		break;
98739773e46Sab 
98839773e46Sab 	case SHT_SUNW_syminfo:
98939773e46Sab 		sec->shdr->sh_link = SINFO_T_DYNSYM;
99039773e46Sab 		sec->shdr->sh_info = SINFO_T_DYN;
99139773e46Sab 		break;
99239773e46Sab 
99339773e46Sab 	case SHT_SUNW_symsort:
99439773e46Sab 	case SHT_SUNW_tlssort:
99539773e46Sab 		sec->shdr->sh_link = SINFO_T_LDYNSYM;
99639773e46Sab 		break;
99739773e46Sab 	}
99839773e46Sab 
99939773e46Sab 
100039773e46Sab 
100139773e46Sab 	/* Fill in fake Elf_Data descriptor */
100239773e46Sab 	sec->data->d_type = tinfo->libelf_type;
100339773e46Sab 	sec->data->d_size = sec->size;
100439773e46Sab 	sec->data->d_off = 0;
100539773e46Sab 	sec->data->d_align = tinfo->sh_addralign;
100639773e46Sab 	sec->data->d_version = fstate->ehdr->e_version;
100739773e46Sab 
100839773e46Sab 	if (sec->size == 0) {
100939773e46Sab 		sec->data->d_buf = NULL;
101039773e46Sab 		return (1);
101139773e46Sab 	}
101239773e46Sab 
101339773e46Sab 	if ((sec->data->d_buf = malloc(sec->size)) == NULL) {
101439773e46Sab 		int err = errno;
101539773e46Sab 
101639773e46Sab 		sinfo_free(sec, 1);
101739773e46Sab 		(void) fprintf(stderr, MSG_INTL(MSG_ERR_MALLOC),
101839773e46Sab 		    fstate->file, strerror(err));
101939773e46Sab 		return (0);
102039773e46Sab 	}
102139773e46Sab 
102239773e46Sab 	read_bytes = sec->size - zero_bytes;
102339773e46Sab 	if ((read_bytes > 0) &&
102439773e46Sab 	    (read_data(fstate, sec->shdr->sh_offset, sec->data->d_buf,
102539773e46Sab 	    read_bytes, ELF_T_BYTE) == 0)) {
102639773e46Sab 		sinfo_free(sec, 1);
102739773e46Sab 		return (0);
102839773e46Sab 	}
102939773e46Sab 	if (zero_bytes > 0)
103039773e46Sab 		bzero(read_bytes + (char *)sec->data->d_buf, zero_bytes);
103139773e46Sab 
103239773e46Sab 	if ((tinfo->libelf_type != ELF_T_BYTE) &&
103339773e46Sab 	    (elf_xlatetom(sec->data, sec->data,
103439773e46Sab 	    fstate->ehdr->e_ident[EI_DATA]) == NULL)) {
103539773e46Sab 		sinfo_free(sec, 1);
103639773e46Sab 		failure(fstate->file, MSG_ORIG(MSG_ELF_XLATETOM));
103739773e46Sab 		return (0);
103839773e46Sab 	}
103939773e46Sab 
104039773e46Sab 	return (1);
104139773e46Sab }
104239773e46Sab 
104339773e46Sab 
104439773e46Sab 
104539773e46Sab /*
104639773e46Sab  * Generate a section header cache made up of information derived
104739773e46Sab  * from the program headers.
104839773e46Sab  *
104939773e46Sab  * entry:
105039773e46Sab  *	file - Name of object
105139773e46Sab  *	fd - Open file handle for object
105239773e46Sab  *	elf - ELF descriptor
105339773e46Sab  *	ehdr - Elf header
105439773e46Sab  *	cache, shnum - Addresses of variables to receive resulting
105539773e46Sab  *		cache and number of sections.
105639773e46Sab  *
105739773e46Sab  * exit:
105839773e46Sab  *	On success, *cache and *shnum are set, and True (1) is returned.
105939773e46Sab  *	On failure, False (0) is returned.
106039773e46Sab  *
106139773e46Sab  * note:
106239773e46Sab  *	The cache returned by this routine must be freed using
106339773e46Sab  *	fake_shdr_cache_free(), and not by a direct call to free().
106439773e46Sab  *	Otherwise, memory will leak.
106539773e46Sab  */
106639773e46Sab int
fake_shdr_cache(const char * file,int fd,Elf * elf,Ehdr * ehdr,Cache ** cache,size_t * shnum)106739773e46Sab fake_shdr_cache(const char *file, int fd, Elf *elf, Ehdr *ehdr,
106839773e46Sab     Cache **cache, size_t *shnum)
106939773e46Sab {
107039773e46Sab 	/*
107139773e46Sab 	 * The C language guarantees that a structure of homogeneous
107239773e46Sab 	 * items will receive exactly the same layout in a structure
107339773e46Sab 	 * as a plain array of the same type. Hence, this structure, which
107439773e46Sab 	 * gives us by-name or by-index access to the various section
107539773e46Sab 	 * info descriptors we maintain.
107639773e46Sab 	 *
107739773e46Sab 	 * We use this for sections where
107839773e46Sab 	 *	- Only one instance is allowed
107939773e46Sab 	 *	- We need to be able to access them easily by
108039773e46Sab 	 *		name (for instance, when mining the .dynamic
108139773e46Sab 	 *		section for information to build them up.
108239773e46Sab 	 *
108339773e46Sab 	 * NOTE: These fields must be in the same order as the
108439773e46Sab 	 * SINFO_T_ type codes that correspond to them. Otherwise,
108539773e46Sab 	 * they will end up in the wrong order in the cache array,
108639773e46Sab 	 * and the sh_link/sh_info fields may be wrong.
108739773e46Sab 	 */
108839773e46Sab 	struct {
108939773e46Sab 		/* Note: No entry is needed for SINFO_T_NULL */
109039773e46Sab 		SINFO	dyn;
109139773e46Sab 		SINFO	dynstr;
109239773e46Sab 		SINFO	dynsym;
109339773e46Sab 		SINFO	ldynsym;
109439773e46Sab 
109539773e46Sab 		SINFO	hash;
109639773e46Sab 		SINFO	syminfo;
109739773e46Sab 		SINFO	symsort;
109839773e46Sab 		SINFO	tlssort;
109939773e46Sab 		SINFO	verneed;
110039773e46Sab 		SINFO	verdef;
110139773e46Sab 		SINFO	versym;
110239773e46Sab 		SINFO	interp;
110339773e46Sab 		SINFO	cap;
1104*08278a5eSRod Evans 		SINFO	capinfo;
1105*08278a5eSRod Evans 		SINFO	capchain;
110639773e46Sab 		SINFO	unwind;
110739773e46Sab 		SINFO	move;
110839773e46Sab 		SINFO	rel;
110939773e46Sab 		SINFO	rela;
111039773e46Sab 		SINFO	preinitarr;
111139773e46Sab 		SINFO	initarr;
111239773e46Sab 		SINFO	finiarr;
111339773e46Sab 	} sec;
111439773e46Sab 	static const size_t sinfo_n = sizeof (sec) / sizeof (sec.dyn);
111539773e46Sab 	SINFO *secarr = (SINFO *) &sec;
111639773e46Sab 
111739773e46Sab 	/*
111839773e46Sab 	 * Doubly linked circular list, used to track sections
111939773e46Sab 	 * where multiple sections of a given type can exist.
112039773e46Sab 	 * seclist is the root of the list. Its sinfo field is not
112139773e46Sab 	 * used --- it serves to anchor the root of the list, allowing
112239773e46Sab 	 * rapid access to the first and last element in the list.
112339773e46Sab 	 */
112439773e46Sab 	SINFO_LISTELT	seclist;
112539773e46Sab 
112639773e46Sab 	FSTATE		fstate;
112739773e46Sab 	size_t		ndx;
112839773e46Sab 	size_t		num_sinfo, num_list_sinfo;
112939773e46Sab 	SINFO		*sinfo;
113039773e46Sab 	SINFO_LISTELT	*sinfo_list;
113139773e46Sab 	Cache		*_cache;
113239773e46Sab 
113339773e46Sab 
113439773e46Sab 	fstate.file = file;
113539773e46Sab 	fstate.fd = fd;
113639773e46Sab 	fstate.ehdr = ehdr;
113762b628a6SAli Bahrami 	if (elf_getphdrnum(elf, &fstate.phnum) == -1) {
113862b628a6SAli Bahrami 		failure(file, MSG_ORIG(MSG_ELF_GETPHDRNUM));
113939773e46Sab 		return (0);
114039773e46Sab 	}
114139773e46Sab 	if ((fstate.phdr = elf_getphdr(elf)) == NULL) {
114239773e46Sab 		failure(file, MSG_ORIG(MSG_ELF_GETPHDR));
114339773e46Sab 		return (0);
114439773e46Sab 	}
114539773e46Sab 
114639773e46Sab 	bzero(&sec, sizeof (sec));	/* Initialize "by-name" sec info */
114739773e46Sab 	seclist.next = seclist.prev = &seclist;	  /* Empty circular list */
114839773e46Sab 
114939773e46Sab 	/*
115039773e46Sab 	 * Go through the program headers and look for information
115139773e46Sab 	 * we can use to synthesize section headers. By far the most
115239773e46Sab 	 * valuable thing is a dynamic section, the contents of
115339773e46Sab 	 * which point at all sections used by ld.so.1.
115439773e46Sab 	 */
115539773e46Sab 	for (ndx = 0; ndx < fstate.phnum; ndx++) {
115639773e46Sab 		/*
115739773e46Sab 		 * A program header with no file size does
115839773e46Sab 		 * not have a backing section.
115939773e46Sab 		 */
116039773e46Sab 		if (fstate.phdr[ndx].p_filesz == 0)
116139773e46Sab 			continue;
116239773e46Sab 
116339773e46Sab 
116439773e46Sab 		switch (fstate.phdr[ndx].p_type) {
116539773e46Sab 		default:
116639773e46Sab 			/* Header we can't use. Move on to next one */
116739773e46Sab 			continue;
116839773e46Sab 
116939773e46Sab 		case PT_DYNAMIC:
117039773e46Sab 			sec.dyn.type = SINFO_T_DYN;
117139773e46Sab 			sinfo = &sec.dyn;
117239773e46Sab 			break;
117339773e46Sab 
117439773e46Sab 		case PT_INTERP:
117539773e46Sab 			sec.interp.type = SINFO_T_INTERP;
117639773e46Sab 			sinfo = &sec.interp;
117739773e46Sab 			break;
117839773e46Sab 
117939773e46Sab 		case PT_NOTE:
118039773e46Sab 			if ((sinfo = sinfo_list_alloc(&fstate, &seclist)) ==
118139773e46Sab 			    NULL)
118239773e46Sab 				continue;
118339773e46Sab 			sinfo->type = SINFO_T_NOTE;
118439773e46Sab 			break;
118539773e46Sab 
118639773e46Sab 		case PT_SUNW_UNWIND:
11877e16fca0SAli Bahrami 		case PT_SUNW_EH_FRAME:
118839773e46Sab 			sec.unwind.type = SINFO_T_UNWIND;
118939773e46Sab 			sinfo = &sec.unwind;
119039773e46Sab 			break;
119139773e46Sab 
119239773e46Sab 		case PT_SUNWCAP:
119339773e46Sab 			sec.cap.type = SINFO_T_CAP;
119439773e46Sab 			sinfo = &sec.cap;
119539773e46Sab 			break;
119639773e46Sab 		}
119739773e46Sab 
119839773e46Sab 		/*
119939773e46Sab 		 * Capture the position/extent information for
120039773e46Sab 		 * the header in the SINFO struct set up by the
120139773e46Sab 		 * switch statement above.
120239773e46Sab 		 */
120339773e46Sab 		sinfo->vaddr = fstate.phdr[ndx].p_vaddr;
120439773e46Sab 		sinfo->offset = fstate.phdr[ndx].p_offset;
120539773e46Sab 		sinfo->size = fstate.phdr[ndx].p_filesz;
120639773e46Sab 	}
120739773e46Sab 
120839773e46Sab 	/*
120939773e46Sab 	 * If we found a dynamic section, look through it and
121039773e46Sab 	 * gather information about the sections it references.
121139773e46Sab 	 */
121239773e46Sab 	if (sec.dyn.type == SINFO_T_DYN)
121339773e46Sab 		(void) get_data(&fstate, &sec.dyn);
121439773e46Sab 	if ((sec.dyn.type == SINFO_T_DYN) && (sec.dyn.data->d_buf != NULL)) {
121539773e46Sab 		Dyn *dyn;
121639773e46Sab 		for (dyn = sec.dyn.data->d_buf; dyn->d_tag != DT_NULL; dyn++) {
121739773e46Sab 			switch (dyn->d_tag) {
121839773e46Sab 			case DT_HASH:
121939773e46Sab 				sec.hash.type = SINFO_T_HASH;
122039773e46Sab 				sec.hash.vaddr = dyn->d_un.d_ptr;
122139773e46Sab 				break;
122239773e46Sab 
122339773e46Sab 			case DT_STRTAB:
122439773e46Sab 				sec.dynstr.type = SINFO_T_DYNSTR;
122539773e46Sab 				sec.dynstr.vaddr = dyn->d_un.d_ptr;
122639773e46Sab 				break;
122739773e46Sab 
122839773e46Sab 			case DT_SYMTAB:
122939773e46Sab 				sec.dynsym.type = SINFO_T_DYNSYM;
123039773e46Sab 				sec.dynsym.vaddr = dyn->d_un.d_ptr;
123139773e46Sab 				break;
123239773e46Sab 
123339773e46Sab 			case DT_RELA:
123439773e46Sab 				sec.rela.type = SINFO_T_RELA;
123539773e46Sab 				sec.rela.vaddr = dyn->d_un.d_ptr;
123639773e46Sab 				break;
123739773e46Sab 
123839773e46Sab 			case DT_RELASZ:
123939773e46Sab 				sec.rela.size = dyn->d_un.d_val;
124039773e46Sab 				break;
124139773e46Sab 
124239773e46Sab 			case DT_STRSZ:
124339773e46Sab 				sec.dynstr.size = dyn->d_un.d_val;
124439773e46Sab 				break;
124539773e46Sab 
124639773e46Sab 			case DT_REL:
124739773e46Sab 				sec.rel.type = SINFO_T_REL;
124839773e46Sab 				sec.rel.vaddr = dyn->d_un.d_ptr;
124939773e46Sab 				break;
125039773e46Sab 
125139773e46Sab 			case DT_RELSZ:
125239773e46Sab 				sec.rel.size = dyn->d_un.d_val;
125339773e46Sab 				break;
125439773e46Sab 
125539773e46Sab 			case DT_INIT_ARRAY:
125639773e46Sab 				sec.initarr.type = SINFO_T_INITARR;
125739773e46Sab 				sec.initarr.vaddr = dyn->d_un.d_ptr;
125839773e46Sab 				break;
125939773e46Sab 
126039773e46Sab 			case DT_INIT_ARRAYSZ:
126139773e46Sab 				sec.initarr.size = dyn->d_un.d_val;
126239773e46Sab 				break;
126339773e46Sab 
126439773e46Sab 			case DT_FINI_ARRAY:
126539773e46Sab 				sec.finiarr.type = SINFO_T_FINIARR;
126639773e46Sab 				sec.finiarr.vaddr = dyn->d_un.d_ptr;
126739773e46Sab 				break;
126839773e46Sab 
126939773e46Sab 			case DT_FINI_ARRAYSZ:
127039773e46Sab 				sec.finiarr.size = dyn->d_un.d_val;
127139773e46Sab 				break;
127239773e46Sab 
127339773e46Sab 			case DT_PREINIT_ARRAY:
127439773e46Sab 				sec.preinitarr.type = SINFO_T_PREINITARR;
127539773e46Sab 				sec.preinitarr.vaddr = dyn->d_un.d_ptr;
127639773e46Sab 				break;
127739773e46Sab 
127839773e46Sab 			case DT_PREINIT_ARRAYSZ:
127939773e46Sab 				sec.preinitarr.size = dyn->d_un.d_val;
128039773e46Sab 				break;
128139773e46Sab 
1282*08278a5eSRod Evans 			case DT_SUNW_CAPINFO:
1283*08278a5eSRod Evans 				sec.capinfo.type = SINFO_T_CAPINFO;
1284*08278a5eSRod Evans 				sec.capinfo.vaddr = dyn->d_un.d_ptr;
1285*08278a5eSRod Evans 				break;
1286*08278a5eSRod Evans 
1287*08278a5eSRod Evans 			case DT_SUNW_CAPCHAIN:
1288*08278a5eSRod Evans 				sec.capchain.type = SINFO_T_CAPCHAIN;
1289*08278a5eSRod Evans 				sec.capchain.vaddr = dyn->d_un.d_ptr;
1290*08278a5eSRod Evans 				break;
1291*08278a5eSRod Evans 
129239773e46Sab 			case DT_SUNW_SYMTAB:
129339773e46Sab 				sec.ldynsym.type = SINFO_T_LDYNSYM;
129439773e46Sab 				sec.ldynsym.vaddr = dyn->d_un.d_ptr;
129539773e46Sab 				break;
129639773e46Sab 
129739773e46Sab 			case DT_SUNW_SYMSZ:
129839773e46Sab 				sec.ldynsym.size = dyn->d_un.d_val;
129939773e46Sab 				break;
130039773e46Sab 
130139773e46Sab 			case DT_SUNW_SYMSORT:
130239773e46Sab 				sec.symsort.type = SINFO_T_SYMSORT;
130339773e46Sab 				sec.symsort.vaddr = dyn->d_un.d_ptr;
130439773e46Sab 				break;
130539773e46Sab 
130639773e46Sab 			case DT_SUNW_SYMSORTSZ:
130739773e46Sab 				sec.symsort.size = dyn->d_un.d_val;
130839773e46Sab 				break;
130939773e46Sab 
131039773e46Sab 			case DT_SUNW_TLSSORT:
131139773e46Sab 				sec.tlssort.type = SINFO_T_TLSSORT;
131239773e46Sab 				sec.tlssort.vaddr = dyn->d_un.d_ptr;
131339773e46Sab 				break;
131439773e46Sab 
131539773e46Sab 			case DT_SUNW_TLSSORTSZ:
131639773e46Sab 				sec.tlssort.size = dyn->d_un.d_val;
131739773e46Sab 				break;
131839773e46Sab 
131939773e46Sab 			case DT_MOVETAB:
132039773e46Sab 				sec.move.type = SINFO_T_MOVE;
132139773e46Sab 				sec.move.vaddr = dyn->d_un.d_ptr;
132239773e46Sab 				break;
132339773e46Sab 
132439773e46Sab 			case DT_MOVESZ:
132539773e46Sab 				sec.move.size = dyn->d_un.d_val;
132639773e46Sab 				break;
132739773e46Sab 
132839773e46Sab 			case DT_SYMINFO:
132939773e46Sab 				sec.syminfo.type = SINFO_T_SYMINFO;
133039773e46Sab 				sec.syminfo.vaddr = dyn->d_un.d_ptr;
133139773e46Sab 				break;
133239773e46Sab 
133339773e46Sab 			case DT_SYMINSZ:
133439773e46Sab 				sec.syminfo.size = dyn->d_un.d_val;
133539773e46Sab 				break;
133639773e46Sab 
133739773e46Sab 			case DT_VERSYM:
133839773e46Sab 				sec.versym.type = SINFO_T_VERSYM;
133939773e46Sab 				sec.versym.vaddr = dyn->d_un.d_ptr;
134039773e46Sab 				break;
134139773e46Sab 
134239773e46Sab 			case DT_VERDEF:
134339773e46Sab 				sec.verdef.type = SINFO_T_VERDEF;
134439773e46Sab 				sec.verdef.vaddr = dyn->d_un.d_ptr;
134539773e46Sab 				break;
134639773e46Sab 
134739773e46Sab 			case DT_VERDEFNUM:
134839773e46Sab 				sec.verdef.vercnt = dyn->d_un.d_val;
134939773e46Sab 				sec.verdef.size = sizeof (Verdef) *
135039773e46Sab 				    dyn->d_un.d_val;
135139773e46Sab 				break;
135239773e46Sab 
135339773e46Sab 			case DT_VERNEED:
135439773e46Sab 				sec.verneed.type = SINFO_T_VERNEED;
135539773e46Sab 				sec.verneed.vaddr = dyn->d_un.d_ptr;
135639773e46Sab 				break;
135739773e46Sab 
135839773e46Sab 			case DT_VERNEEDNUM:
135939773e46Sab 				sec.verneed.vercnt = dyn->d_un.d_val;
136039773e46Sab 				sec.verneed.size = sizeof (Verneed) *
136139773e46Sab 				    dyn->d_un.d_val;
136239773e46Sab 				break;
136339773e46Sab 			}
136439773e46Sab 		}
136539773e46Sab 	}
136639773e46Sab 
136739773e46Sab 	/*
136839773e46Sab 	 * Different sections depend on each other, and are meaningless
136939773e46Sab 	 * without them. For instance, even if a .dynsym exists,
137039773e46Sab 	 * no use can be made of it without a dynstr. These relationships
137139773e46Sab 	 * fan out: Disqualifying the .dynsym will disqualify the hash
137239773e46Sab 	 * section, and so forth.
137339773e46Sab 	 *
137439773e46Sab 	 * Disqualify sections that don't have the necessary prerequisites.
137539773e46Sab 	 */
137639773e46Sab 
137739773e46Sab 	/* Things that need the dynamic string table */
137839773e46Sab 	if (sec.dynstr.size == 0)
137939773e46Sab 		sec.dynstr.type = SINFO_T_NULL;
138039773e46Sab 	if (sec.dynstr.type != SINFO_T_DYNSTR) {
138139773e46Sab 		sinfo_free(&sec.dyn, 1);	/* Data already fetched */
138239773e46Sab 		sec.dynsym.type =  SINFO_T_NULL;
138339773e46Sab 		sec.dynsym.type =  SINFO_T_NULL;
138439773e46Sab 		sec.verdef.type =  SINFO_T_NULL;
138539773e46Sab 		sec.verneed.type =  SINFO_T_NULL;
138639773e46Sab 	}
138739773e46Sab 
138839773e46Sab 	/*
138939773e46Sab 	 * The length of the hash section is encoded in its first two
139039773e46Sab 	 * elements (nbucket, and nchain). The length of the dynsym,
139139773e46Sab 	 * ldynsym, and versym are not given in the dynamic section,
139239773e46Sab 	 * but are known to be the same as nchain.
139339773e46Sab 	 *
139439773e46Sab 	 * If we don't have a hash table, or cannot read nbuckets and
139539773e46Sab 	 * nchain, we have to invalidate all of these.
139639773e46Sab 	 */
139739773e46Sab 	if (sec.hash.type == SINFO_T_HASH) {
139839773e46Sab 		Word nbucket;
139939773e46Sab 		Word nchain;
140039773e46Sab 		size_t total;
140139773e46Sab 
140239773e46Sab 		if (hash_size(&fstate, &sec.hash,
140339773e46Sab 		    &nbucket, &nchain, &total) == 0) {
140439773e46Sab 			sec.hash.type = SINFO_T_NULL;
140539773e46Sab 		} else {
140639773e46Sab 			/* Use these counts to set sizes for related sections */
140739773e46Sab 			sec.hash.size = total * sizeof (Word);
140839773e46Sab 			sec.dynsym.size = nchain * sizeof (Sym);
140939773e46Sab 			sec.versym.size = nchain * sizeof (Versym);
141039773e46Sab 
141139773e46Sab 			/*
141239773e46Sab 			 * The ldynsym size received the DT_SUNW_SYMSZ
141339773e46Sab 			 * value, which is the combined size of .dynsym
141439773e46Sab 			 * and .ldynsym. Now that we have the dynsym size,
141539773e46Sab 			 * use it to lower the ldynsym size to its real size.
141639773e46Sab 			 */
141739773e46Sab 			if (sec.ldynsym.size > sec.dynsym.size)
141839773e46Sab 				sec.ldynsym.size  -= sec.dynsym.size;
141939773e46Sab 		}
142039773e46Sab 	}
142139773e46Sab 	/*
142239773e46Sab 	 * If the hash table is not present, or if the call to
142339773e46Sab 	 * hash_size() failed, then discard the sections that
142439773e46Sab 	 * need it to determine their length.
142539773e46Sab 	 */
142639773e46Sab 	if (sec.hash.type != SINFO_T_HASH) {
142739773e46Sab 		sec.dynsym.type = SINFO_T_NULL;
142839773e46Sab 		sec.ldynsym.type = SINFO_T_NULL;
142939773e46Sab 		sec.versym.type = SINFO_T_NULL;
143039773e46Sab 	}
143139773e46Sab 
143239773e46Sab 	/*
143339773e46Sab 	 * The runtime linker does not receive size information for
143439773e46Sab 	 * Verdef and Verneed sections. We have to read their data
143539773e46Sab 	 * in pieces and calculate it.
143639773e46Sab 	 */
143739773e46Sab 	if ((sec.verdef.type == SINFO_T_VERDEF) &&
143839773e46Sab 	    (verdefneed_size(&fstate, &sec.verdef) == 0))
143939773e46Sab 		sec.verdef.type = SINFO_T_NULL;
144039773e46Sab 	if ((sec.verneed.type == SINFO_T_VERNEED) &&
144139773e46Sab 	    (verdefneed_size(&fstate, &sec.verneed) == 0))
144239773e46Sab 		sec.verneed.type = SINFO_T_NULL;
144339773e46Sab 
144439773e46Sab 	/* Discard any section with a zero length */
144539773e46Sab 	ndx = sinfo_n;
144639773e46Sab 	for (sinfo = secarr; ndx-- > 0; sinfo++)
144739773e46Sab 		if ((sinfo->type != SINFO_T_NULL) && (sinfo->size == 0))
144839773e46Sab 			sinfo->type = SINFO_T_NULL;
144939773e46Sab 
145039773e46Sab 	/* Things that need the dynamic symbol table */
145139773e46Sab 	if (sec.dynsym.type != SINFO_T_DYNSYM) {
145239773e46Sab 		sec.ldynsym.type = SINFO_T_NULL;
145339773e46Sab 		sec.hash.type = SINFO_T_NULL;
145439773e46Sab 		sec.syminfo.type = SINFO_T_NULL;
145539773e46Sab 		sec.versym.type = SINFO_T_NULL;
145639773e46Sab 		sec.move.type = SINFO_T_NULL;
145739773e46Sab 		sec.rel.type = SINFO_T_NULL;
145839773e46Sab 		sec.rela.type = SINFO_T_NULL;
145939773e46Sab 	}
146039773e46Sab 
146139773e46Sab 	/* Things that need the dynamic local symbol table */
146239773e46Sab 	if (sec.ldynsym.type != SINFO_T_DYNSYM) {
146339773e46Sab 		sec.symsort.type = SINFO_T_NULL;
146439773e46Sab 		sec.tlssort.type = SINFO_T_NULL;
146539773e46Sab 	}
146639773e46Sab 
146739773e46Sab 	/*
146839773e46Sab 	 * Look through the results and fetch the data for any sections
146939773e46Sab 	 * we have found. At the same time, count the number.
147039773e46Sab 	 */
147139773e46Sab 	num_sinfo = num_list_sinfo = 0;
147239773e46Sab 	ndx = sinfo_n;
147339773e46Sab 	for (sinfo = secarr; ndx-- > 0; sinfo++) {
147439773e46Sab 		if ((sinfo->type != SINFO_T_NULL) && (sinfo->data == NULL))
147539773e46Sab 			(void) get_data(&fstate, sinfo);
147639773e46Sab 		if (sinfo->data != NULL)
147739773e46Sab 			num_sinfo++;
147839773e46Sab 	}
147939773e46Sab 	for (sinfo_list = seclist.next; sinfo_list != &seclist;
148039773e46Sab 	    sinfo_list = sinfo_list->next) {
148139773e46Sab 		sinfo = &sinfo_list->sinfo;
148239773e46Sab 		if ((sinfo->type != SINFO_T_NULL) && (sinfo->data == NULL))
148339773e46Sab 			(void) get_data(&fstate, sinfo);
148439773e46Sab 		if (sinfo->data != NULL)
148539773e46Sab 			num_list_sinfo++;
148639773e46Sab 	}
148739773e46Sab 
148839773e46Sab 	/*
148939773e46Sab 	 * Allocate the cache array and fill it in. The cache array
149039773e46Sab 	 * ends up taking all the dynamic memory we've allocated
149139773e46Sab 	 * to build up sec and seclist, so on success, we have nothing
149239773e46Sab 	 * left to clean up. If we can't allocate the cache array
149339773e46Sab 	 * though, we have to free up everything else.
149439773e46Sab 	 */
149539773e46Sab 	*shnum = num_sinfo + num_list_sinfo + 1; /* Extra for 1st NULL sec. */
149639773e46Sab 	if ((*cache = _cache = malloc((*shnum) * sizeof (Cache))) == NULL) {
149739773e46Sab 		int err = errno;
149839773e46Sab 		(void) fprintf(stderr, MSG_INTL(MSG_ERR_MALLOC),
149939773e46Sab 		    file, strerror(err));
150039773e46Sab 		sinfo_free(secarr, num_sinfo);
150139773e46Sab 		sinfo_list_free_all(&seclist);
150239773e46Sab 		return (0);
150339773e46Sab 	}
150439773e46Sab 	*_cache = cache_init;
150539773e46Sab 	_cache++;
150639773e46Sab 	ndx = 1;
150739773e46Sab 	for (sinfo = secarr; num_sinfo > 0; sinfo++) {
150839773e46Sab 		if (sinfo->data != NULL) {
150939773e46Sab 			_cache->c_scn = NULL;
151039773e46Sab 			_cache->c_shdr = sinfo->shdr;
151139773e46Sab 			_cache->c_data = sinfo->data;
151239773e46Sab 			_cache->c_name = (char *)sinfo_data[sinfo->type].name;
151339773e46Sab 			_cache->c_ndx = ndx++;
151439773e46Sab 			_cache++;
151539773e46Sab 			num_sinfo--;
151639773e46Sab 		}
151739773e46Sab 	}
151839773e46Sab 	for (sinfo_list = seclist.next; num_list_sinfo > 0;
151939773e46Sab 	    sinfo_list = sinfo_list->next) {
152039773e46Sab 		sinfo = &sinfo_list->sinfo;
152139773e46Sab 		if (sinfo->data != NULL) {
152239773e46Sab 			_cache->c_scn = NULL;
152339773e46Sab 			_cache->c_shdr = sinfo->shdr;
152439773e46Sab 			_cache->c_data = sinfo->data;
152539773e46Sab 			_cache->c_name = (char *)sinfo_data[sinfo->type].name;
152639773e46Sab 			_cache->c_ndx = ndx++;
152739773e46Sab 			_cache++;
152839773e46Sab 			num_list_sinfo--;
152939773e46Sab 		}
153039773e46Sab 	}
153139773e46Sab 
153239773e46Sab 	return (1);
153339773e46Sab }
153439773e46Sab 
153539773e46Sab 
153639773e46Sab 
153739773e46Sab 
153839773e46Sab 
153939773e46Sab /*
154039773e46Sab  * Release all the memory referenced by a cache array allocated
154139773e46Sab  * by fake_shdr_cache().
154239773e46Sab  */
154339773e46Sab void
fake_shdr_cache_free(Cache * cache,size_t shnum)154439773e46Sab fake_shdr_cache_free(Cache *cache, size_t shnum)
154539773e46Sab {
154639773e46Sab 	Cache *_cache;
154739773e46Sab 
154839773e46Sab 	for (_cache = cache; shnum--; _cache++) {
154939773e46Sab 		if (_cache->c_data != NULL) {
155039773e46Sab 			if (_cache->c_data->d_buf != NULL)
155139773e46Sab 				free(_cache->c_data->d_buf);
155239773e46Sab 			free(_cache->c_data);
155339773e46Sab 		}
155439773e46Sab 		if (_cache->c_shdr)
155539773e46Sab 			free(_cache->c_shdr);
155639773e46Sab 	}
155739773e46Sab 
155839773e46Sab 	free(cache);
155939773e46Sab }
1560