xref: /onnv-gate/usr/src/lib/libproc/common/Psymtab_machelf32.c (revision 10201:47013accbd9c)
13347Sab196087 /*
23347Sab196087  * CDDL HEADER START
33347Sab196087  *
43347Sab196087  * The contents of this file are subject to the terms of the
53347Sab196087  * Common Development and Distribution License (the "License").
63347Sab196087  * You may not use this file except in compliance with the License.
73347Sab196087  *
83347Sab196087  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
93347Sab196087  * or http://www.opensolaris.org/os/licensing.
103347Sab196087  * See the License for the specific language governing permissions
113347Sab196087  * and limitations under the License.
123347Sab196087  *
133347Sab196087  * When distributing Covered Code, include this CDDL HEADER in each
143347Sab196087  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
153347Sab196087  * If applicable, add the following below this CDDL HEADER, with the
163347Sab196087  * fields enclosed by brackets "[]" replaced with your own identifying
173347Sab196087  * information: Portions Copyright [yyyy] [name of copyright owner]
183347Sab196087  *
193347Sab196087  * CDDL HEADER END
203347Sab196087  */
213347Sab196087 
223347Sab196087 /*
23*10201SEdward.Pilatowicz@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
243347Sab196087  * Use is subject to license terms.
253347Sab196087  */
263347Sab196087 
27*10201SEdward.Pilatowicz@Sun.COM #include <assert.h>
283347Sab196087 #include <stdio.h>
293347Sab196087 #include <stdlib.h>
303347Sab196087 #include <stddef.h>
31*10201SEdward.Pilatowicz@Sun.COM #include <string.h>
323347Sab196087 #include <memory.h>
333347Sab196087 #include <sys/sysmacros.h>
343347Sab196087 #include <sys/machelf.h>
353347Sab196087 
363347Sab196087 #include "Pcontrol.h"
373347Sab196087 #include "Psymtab_machelf.h"
383347Sab196087 
393347Sab196087 
403347Sab196087 /*
413347Sab196087  * This file contains code for use by Psymtab.c that is compiled once
423347Sab196087  * for each supported ELFCLASS.
433347Sab196087  *
443347Sab196087  * When processing ELF files, it is common to encounter a situation where
453347Sab196087  * a program with one ELFCLASS (32 or 64-bit) is required to examine a
463347Sab196087  * file with a different ELFCLASS. For example, the 32-bit linker (ld) may
473347Sab196087  * be used to link a 64-bit program. The simplest solution to this problem
483347Sab196087  * is to duplicate each such piece of code, modifying only the data types,
493347Sab196087  * and to use if statements to select the code to run. The problem with
503347Sab196087  * doing it that way is that the resulting code is difficult to maintain.
513347Sab196087  * It is inevitable that the copies will not always get modified identically,
523347Sab196087  * and will drift apart. The only robust solution is to generate the
533347Sab196087  * multiple instances of code automatically from a single piece of code.
543347Sab196087  *
553347Sab196087  * The solution used within the Solaris linker is to write the code once,
563347Sab196087  * using the data types defined in sys/machelf.h, and then to compile that
573347Sab196087  * code twice, once with _ELF64 defined (to generate ELFCLASS64 code) and
583347Sab196087  * once without (to generate ELFCLASS32). We use the same approach here.
593347Sab196087  *
603347Sab196087  * Note that the _ELF64 definition does not refer to the ELFCLASS of
613347Sab196087  * the resulting code, but rather, to the ELFCLASS of the data it
623347Sab196087  * examines. By repeating the above double-compilation for both 32-bit
633347Sab196087  * and 64-bit builds, we end up with 4 instances, which collectively
643347Sab196087  * can handle any combination of program and ELF data class:
653347Sab196087  *
663347Sab196087  *		    \  Compilation class
673347Sab196087  *		     \	  32	64
683347Sab196087  *		      \------------------
693347Sab196087  *		       |
703347Sab196087  *		    32 |   X	 X
713347Sab196087  *   ELF Data Class    |
723347Sab196087  *		    64 |   X	 X
733347Sab196087  */
743347Sab196087 
753347Sab196087 
763347Sab196087 
773347Sab196087 /*
783347Sab196087  * Read data from the specified process and construct an in memory
793347Sab196087  * image of an ELF file that will let us use libelf for most of the
803347Sab196087  * work we need to later (e.g. symbol table lookups). This is used
813347Sab196087  * in cases where no usable on-disk image for the process is available.
823347Sab196087  * We need sections for the dynsym, dynstr, and plt, and we need
833347Sab196087  * the program headers from the text section. The former is used in
843347Sab196087  * Pbuild_file_symtab(); the latter is used in several functions in
853347Sab196087  * Pcore.c to reconstruct the origin of each mapping from the load
863347Sab196087  * object that spawned it.
873347Sab196087  *
883347Sab196087  * Here are some useful pieces of elf trivia that will help
893347Sab196087  * to elucidate this code.
903347Sab196087  *
913347Sab196087  * All the information we need about the dynstr can be found in these
923347Sab196087  * two entries in the dynamic section:
933347Sab196087  *
943347Sab196087  *	DT_STRTAB	base of dynstr
953347Sab196087  *	DT_STRSZ	size of dynstr
963347Sab196087  *
973347Sab196087  * So deciphering the dynstr is pretty straightforward.
983347Sab196087  *
993347Sab196087  * The dynsym is a little trickier.
1003347Sab196087  *
1013347Sab196087  *	DT_SYMTAB	base of dynsym
1023347Sab196087  *	DT_SYMENT	size of a dynstr entry (Elf{32,64}_Sym)
1033347Sab196087  *	DT_HASH		base of hash table for dynamic lookups
1043347Sab196087  *
1053347Sab196087  * The DT_SYMTAB entry gives us any easy way of getting to the base
1063347Sab196087  * of the dynsym, but getting the size involves rooting around in the
1073347Sab196087  * dynamic lookup hash table. Here's the layout of the hash table:
1083347Sab196087  *
1093347Sab196087  *		+-------------------+
1103347Sab196087  *		|	nbucket	    |	All values are 32-bit
1113347Sab196087  *		+-------------------+	(Elf32_Word or Elf64_Word)
1123347Sab196087  *		|	nchain	    |
1133347Sab196087  *		+-------------------+
1143347Sab196087  *		|	bucket[0]   |
1153347Sab196087  *		|	. . .	    |
1163347Sab196087  *		| bucket[nbucket-1] |
1173347Sab196087  *		+-------------------+
1183347Sab196087  *		|	chain[0]    |
1193347Sab196087  *		|	. . .	    |
1203347Sab196087  *		|  chain[nchain-1]  |
1213347Sab196087  *		+-------------------+
1223347Sab196087  *	(figure 5-12 from the SYS V Generic ABI)
1233347Sab196087  *
1243347Sab196087  * Symbols names are hashed into a particular bucket which contains
1253347Sab196087  * an index into the symbol table. Each entry in the symbol table
1263347Sab196087  * has a corresponding entry in the chain table which tells the
1273347Sab196087  * consumer where the next entry in the hash chain is. We can use
1283347Sab196087  * the nchain field to find out the size of the dynsym.
1293347Sab196087  *
1303347Sab196087  * If there is a dynsym present, there may also be an optional
1313347Sab196087  * section called the SUNW_ldynsym that augments the dynsym by
1323347Sab196087  * providing local function symbols. When the Solaris linker lays
1333347Sab196087  * out a file that has both of these sections, it makes sure that
1343347Sab196087  * the data for the two sections is adjacent with the SUNW_ldynsym
1353347Sab196087  * in front. This allows the runtime linker to treat these two
1363347Sab196087  * symbol tables as being a single larger table. There are two
1373347Sab196087  * items in the dynamic section for this:
1383347Sab196087  *
1393347Sab196087  *	DT_SUNW_SYMTAB	base of the SUNW_ldynsym
1403347Sab196087  *	DT_SUNW_SYMSZ	total size of SUNW_ldynsym and dynsym
1413347Sab196087  *			added together. We can figure out the
1423347Sab196087  *			size of the SUNW_ldynsym section by
1433347Sab196087  *			subtracting the size of the dynsym
1443347Sab196087  *			(described above) from this value.
1453347Sab196087  *
1463347Sab196087  * We can figure out the size of the .plt section, but it takes some
1473347Sab196087  * doing. We need to use the following information:
1483347Sab196087  *
149*10201SEdward.Pilatowicz@Sun.COM  *	DT_PLTGOT	GOT PLT entry offset (on x86) or PLT offset (on sparc)
1503347Sab196087  *	DT_JMPREL	base of the PLT's relocation section
1513347Sab196087  *	DT_PLTRELSZ	size of the PLT's relocation section
1523347Sab196087  *	DT_PLTREL	type of the PLT's relocation section
1533347Sab196087  *
154*10201SEdward.Pilatowicz@Sun.COM  * We can use the number of relocation entries to calculate the size of
155*10201SEdward.Pilatowicz@Sun.COM  * the PLT.  We get the address of the PLT by looking up the
156*10201SEdward.Pilatowicz@Sun.COM  * _PROCEDURE_LINKAGE_TABLE_ symbol.
1573347Sab196087  *
1583347Sab196087  * For more information, check out the System V Generic ABI.
1593347Sab196087  */
1603347Sab196087 
1613347Sab196087 
1623347Sab196087 /*
1633347Sab196087  * The fake_elfXX() function generated by this file uses the following
1643347Sab196087  * string as the string table for the section names. Since it is critical
1653347Sab196087  * to count correctly, and to improve readability, the SHSTR_NDX_ macros
1663347Sab196087  * supply the proper offset for each name within the string.
1673347Sab196087  */
1683347Sab196087 static char shstr[] =
1693347Sab196087 	".shstrtab\0.dynsym\0.dynstr\0.dynamic\0.plt\0.SUNW_ldynsym";
1703347Sab196087 
1713347Sab196087 /* Offsets within shstr for each name */
1723347Sab196087 #define	SHSTR_NDX_shstrtab	0
1733347Sab196087 #define	SHSTR_NDX_dynsym	10
1743347Sab196087 #define	SHSTR_NDX_dynstr	18
1753347Sab196087 #define	SHSTR_NDX_dynamic	26
1763347Sab196087 #define	SHSTR_NDX_plt		35
1773347Sab196087 #define	SHSTR_NDX_SUNW_ldynsym	40
1783347Sab196087 
1793347Sab196087 
1803347Sab196087 /*
1813347Sab196087  * Section header alignment for 32 and 64-bit ELF files differs
1823347Sab196087  */
1833347Sab196087 #ifdef _ELF64
1843347Sab196087 #define	SH_ADDRALIGN	8
1853347Sab196087 #else
1863347Sab196087 #define	SH_ADDRALIGN	4
1873347Sab196087 #endif
1883347Sab196087 
1893656Sjj204856 /*
1903656Sjj204856  * This is the smallest number of PLT relocation entries allowed in a proper
1913656Sjj204856  * .plt section.
1923656Sjj204856  */
1933656Sjj204856 #ifdef	__sparc
1943656Sjj204856 #define	PLTREL_MIN_ENTRIES	4	/* SPARC psABI 3.0 and SCD 2.4 */
1953656Sjj204856 #else
1963656Sjj204856 #ifdef	__lint
1973656Sjj204856 /*
1983656Sjj204856  * On x86, lint would complain about unsigned comparison with
1993656Sjj204856  * PLTREL_MIN_ENTRIES. This define fakes up the value of PLTREL_MIN_ENTRIES
2003656Sjj204856  * and silences lint. On SPARC, there is no such issue.
2013656Sjj204856  */
2023656Sjj204856 #define	PLTREL_MIN_ENTRIES	1
2033656Sjj204856 #else
2043656Sjj204856 #define	PLTREL_MIN_ENTRIES	0
2053656Sjj204856 #endif
2063656Sjj204856 #endif
2073656Sjj204856 
2083347Sab196087 #ifdef _ELF64
2093347Sab196087 Elf *
fake_elf64(struct ps_prochandle * P,file_info_t * fptr,uintptr_t addr,Ehdr * ehdr,uint_t phnum,Phdr * phdr)2103347Sab196087 fake_elf64(struct ps_prochandle *P, file_info_t *fptr, uintptr_t addr,
2113347Sab196087     Ehdr *ehdr, uint_t phnum, Phdr *phdr)
2123347Sab196087 #else
2133347Sab196087 Elf *
2143347Sab196087 fake_elf32(struct ps_prochandle *P, file_info_t *fptr, uintptr_t addr,
2153347Sab196087     Ehdr *ehdr, uint_t phnum, Phdr *phdr)
2163347Sab196087 #endif
2173347Sab196087 {
2183347Sab196087 	enum {
2193347Sab196087 		DI_PLTGOT,
2203347Sab196087 		DI_JMPREL,
2213347Sab196087 		DI_PLTRELSZ,
2223347Sab196087 		DI_PLTREL,
2233347Sab196087 		DI_SYMTAB,
2243347Sab196087 		DI_HASH,
2253347Sab196087 		DI_SYMENT,
2263347Sab196087 		DI_STRTAB,
2273347Sab196087 		DI_STRSZ,
2283347Sab196087 		DI_SUNW_SYMTAB,
2293347Sab196087 		DI_SUNW_SYMSZ,
2303347Sab196087 		DI_NENT
2313347Sab196087 	};
2323347Sab196087 	/*
2333347Sab196087 	 * Mask of dynamic options that must be present in a well
2343347Sab196087 	 * formed dynamic section. We need all of these in order to
2353347Sab196087 	 * put together a complete set of elf sections. They are
2363347Sab196087 	 * mandatory in both executables and shared objects so if one
2373347Sab196087 	 * of them is missing, we're in some trouble and should abort.
2383347Sab196087 	 * The PLT items are expected, but we will let them slide if
2393347Sab196087 	 * need be. The DI_SUNW_SYM* items are completely optional, so
2403347Sab196087 	 * we use them if they are present and ignore them otherwise.
2413347Sab196087 	 */
2423347Sab196087 	const int di_req_mask = (1 << DI_SYMTAB) | (1 << DI_HASH) |
2433347Sab196087 		(1 << DI_SYMENT) | (1 << DI_STRTAB) | (1 << DI_STRSZ);
2443347Sab196087 	int di_mask = 0;
2453347Sab196087 	size_t size = 0;
2463347Sab196087 	caddr_t elfdata = NULL;
2473347Sab196087 	Elf *elf;
248*10201SEdward.Pilatowicz@Sun.COM 	size_t dynsym_size = 0, ldynsym_size;
2493347Sab196087 	int dynstr_shndx;
2503347Sab196087 	Ehdr *ep;
2513347Sab196087 	Shdr *sp;
2523347Sab196087 	Dyn *dp;
2533347Sab196087 	Dyn *d[DI_NENT] = { 0 };
2543347Sab196087 	uint_t i;
2553347Sab196087 	Off off;
256*10201SEdward.Pilatowicz@Sun.COM 	size_t pltsz = 0, pltentries = 0;
257*10201SEdward.Pilatowicz@Sun.COM 	uintptr_t hptr = NULL;
258*10201SEdward.Pilatowicz@Sun.COM 	Word hnchains, hnbuckets;
2593347Sab196087 
2603347Sab196087 	if (ehdr->e_type == ET_DYN)
2613347Sab196087 		phdr->p_vaddr += addr;
2623347Sab196087 
2636830Sedp 	if (P->rap != NULL) {
2646830Sedp 		if (rd_get_dyns(P->rap, addr, (void **)&dp, NULL) != RD_OK)
2656830Sedp 			goto bad;
2666830Sedp 	} else {
2676830Sedp 		if ((dp = malloc(phdr->p_filesz)) == NULL)
2686830Sedp 			goto bad;
2696830Sedp 		if (Pread(P, dp, phdr->p_filesz, phdr->p_vaddr) !=
2706830Sedp 		    phdr->p_filesz)
2716830Sedp 			goto bad;
2723347Sab196087 	}
2733347Sab196087 
2743347Sab196087 	/*
2753347Sab196087 	 * Iterate over the items in the dynamic section, grabbing
2763347Sab196087 	 * the address of items we want and saving them in dp[].
2773347Sab196087 	 */
2783347Sab196087 	for (i = 0; i < phdr->p_filesz / sizeof (Dyn); i++) {
2793347Sab196087 		switch (dp[i].d_tag) {
2803347Sab196087 		/* For the .plt section */
2813347Sab196087 		case DT_PLTGOT:
2823347Sab196087 			d[DI_PLTGOT] = &dp[i];
2833347Sab196087 			break;
2843347Sab196087 		case DT_JMPREL:
2853347Sab196087 			d[DI_JMPREL] = &dp[i];
2863347Sab196087 			break;
2873347Sab196087 		case DT_PLTRELSZ:
2883347Sab196087 			d[DI_PLTRELSZ] = &dp[i];
2893347Sab196087 			break;
2903347Sab196087 		case DT_PLTREL:
2913347Sab196087 			d[DI_PLTREL] = &dp[i];
2923347Sab196087 			break;
2933347Sab196087 
2943347Sab196087 		/* For the .dynsym section */
2953347Sab196087 		case DT_SYMTAB:
2963347Sab196087 			d[DI_SYMTAB] = &dp[i];
2973347Sab196087 			di_mask |= (1 << DI_SYMTAB);
2983347Sab196087 			break;
2993347Sab196087 		case DT_HASH:
3003347Sab196087 			d[DI_HASH] = &dp[i];
3013347Sab196087 			di_mask |= (1 << DI_HASH);
3023347Sab196087 			break;
3033347Sab196087 		case DT_SYMENT:
3043347Sab196087 			d[DI_SYMENT] = &dp[i];
3053347Sab196087 			di_mask |= (1 << DI_SYMENT);
3063347Sab196087 			break;
3073347Sab196087 		case DT_SUNW_SYMTAB:
3083347Sab196087 			d[DI_SUNW_SYMTAB] = &dp[i];
3093347Sab196087 			break;
3103347Sab196087 		case DT_SUNW_SYMSZ:
3113347Sab196087 			d[DI_SUNW_SYMSZ] = &dp[i];
3123347Sab196087 			break;
3133347Sab196087 
3143347Sab196087 		/* For the .dynstr section */
3153347Sab196087 		case DT_STRTAB:
3163347Sab196087 			d[DI_STRTAB] = &dp[i];
3173347Sab196087 			di_mask |= (1 << DI_STRTAB);
3183347Sab196087 			break;
3193347Sab196087 		case DT_STRSZ:
3203347Sab196087 			d[DI_STRSZ] = &dp[i];
3213347Sab196087 			di_mask |= (1 << DI_STRSZ);
3223347Sab196087 			break;
3233347Sab196087 		}
3243347Sab196087 	}
3253347Sab196087 
3263347Sab196087 	/* Ensure all required entries were collected */
3273347Sab196087 	if ((di_mask & di_req_mask) != di_req_mask) {
3283347Sab196087 		dprintf("text section missing required dynamic entries\n");
3293347Sab196087 		goto bad;
3303347Sab196087 	}
3313347Sab196087 
3323347Sab196087 	/* SUNW_ldynsym must be adjacent to dynsym. Ignore if not */
3333347Sab196087 	if ((d[DI_SUNW_SYMTAB] != NULL) && (d[DI_SUNW_SYMSZ] != NULL) &&
3343347Sab196087 	    ((d[DI_SYMTAB]->d_un.d_ptr <= d[DI_SUNW_SYMTAB]->d_un.d_ptr) ||
3353347Sab196087 	    (d[DI_SYMTAB]->d_un.d_ptr >= (d[DI_SUNW_SYMTAB]->d_un.d_ptr +
3363347Sab196087 	    d[DI_SUNW_SYMSZ]->d_un.d_val)))) {
3373347Sab196087 		d[DI_SUNW_SYMTAB] = NULL;
3383347Sab196087 		d[DI_SUNW_SYMSZ] = NULL;
3393347Sab196087 	}
3403347Sab196087 
3413347Sab196087 	/* elf header */
3423347Sab196087 	size = sizeof (Ehdr);
3433347Sab196087 
3443347Sab196087 	/* program headers from in-core elf fragment */
3453347Sab196087 	size += phnum * ehdr->e_phentsize;
3463347Sab196087 
3473347Sab196087 	/* unused shdr, and .shstrtab section */
3483347Sab196087 	size += sizeof (Shdr);
3493347Sab196087 	size += sizeof (Shdr);
3503347Sab196087 	size += roundup(sizeof (shstr), SH_ADDRALIGN);
3513347Sab196087 
352*10201SEdward.Pilatowicz@Sun.COM 	if (d[DI_HASH] != NULL) {
353*10201SEdward.Pilatowicz@Sun.COM 		Word hash[2];
354*10201SEdward.Pilatowicz@Sun.COM 
355*10201SEdward.Pilatowicz@Sun.COM 		hptr = d[DI_HASH]->d_un.d_ptr;
356*10201SEdward.Pilatowicz@Sun.COM 		if (ehdr->e_type == ET_DYN)
357*10201SEdward.Pilatowicz@Sun.COM 			hptr += addr;
358*10201SEdward.Pilatowicz@Sun.COM 
359*10201SEdward.Pilatowicz@Sun.COM 		if (Pread(P, hash, sizeof (hash), hptr) != sizeof (hash)) {
360*10201SEdward.Pilatowicz@Sun.COM 			dprintf("Pread of .hash at %lx failed\n",
361*10201SEdward.Pilatowicz@Sun.COM 			    (long)(hptr));
362*10201SEdward.Pilatowicz@Sun.COM 			goto bad;
363*10201SEdward.Pilatowicz@Sun.COM 		}
364*10201SEdward.Pilatowicz@Sun.COM 
365*10201SEdward.Pilatowicz@Sun.COM 		hnbuckets = hash[0];
366*10201SEdward.Pilatowicz@Sun.COM 		hnchains = hash[1];
367*10201SEdward.Pilatowicz@Sun.COM 	}
368*10201SEdward.Pilatowicz@Sun.COM 
3693347Sab196087 	/*
3703347Sab196087 	 * .dynsym and .SUNW_ldynsym sections.
3713347Sab196087 	 *
3723347Sab196087 	 * The string table section used for the symbol table and
3733347Sab196087 	 * dynamic sections lies immediately after the dynsym, so the
3743347Sab196087 	 * presence of SUNW_ldynsym changes the dynstr section index.
3753347Sab196087 	 */
3763347Sab196087 	if (d[DI_SUNW_SYMTAB] != NULL) {
3773347Sab196087 		size += sizeof (Shdr);	/* SUNW_ldynsym shdr */
3783347Sab196087 		ldynsym_size = (size_t)d[DI_SUNW_SYMSZ]->d_un.d_val;
3793347Sab196087 		dynsym_size = ldynsym_size - (d[DI_SYMTAB]->d_un.d_ptr
3803347Sab196087 		    - d[DI_SUNW_SYMTAB]->d_un.d_ptr);
3813347Sab196087 		ldynsym_size -= dynsym_size;
3823347Sab196087 		dynstr_shndx = 4;
3833347Sab196087 	} else {
384*10201SEdward.Pilatowicz@Sun.COM 		dynsym_size = sizeof (Sym) * hnchains;
3853347Sab196087 		ldynsym_size = 0;
3863347Sab196087 		dynstr_shndx = 3;
3873347Sab196087 	}
3883347Sab196087 	size += sizeof (Shdr) + ldynsym_size + dynsym_size;
3893347Sab196087 
3903347Sab196087 	/* .dynstr section */
3913347Sab196087 	size += sizeof (Shdr);
3923347Sab196087 	size += roundup(d[DI_STRSZ]->d_un.d_val, SH_ADDRALIGN);
3933347Sab196087 
3943347Sab196087 	/* .dynamic section */
3953347Sab196087 	size += sizeof (Shdr);
3963347Sab196087 	size += roundup(phdr->p_filesz, SH_ADDRALIGN);
3973347Sab196087 
3983347Sab196087 	/* .plt section */
3993347Sab196087 	if (d[DI_PLTGOT] != NULL && d[DI_JMPREL] != NULL &&
4003347Sab196087 	    d[DI_PLTRELSZ] != NULL && d[DI_PLTREL] != NULL) {
4013347Sab196087 		size_t pltrelsz = d[DI_PLTRELSZ]->d_un.d_val;
4023347Sab196087 
4033347Sab196087 		if (d[DI_PLTREL]->d_un.d_val == DT_RELA) {
404*10201SEdward.Pilatowicz@Sun.COM 			pltentries = pltrelsz / sizeof (Rela);
4053347Sab196087 		} else if (d[DI_PLTREL]->d_un.d_val == DT_REL) {
406*10201SEdward.Pilatowicz@Sun.COM 			pltentries = pltrelsz / sizeof (Rel);
407*10201SEdward.Pilatowicz@Sun.COM 		} else {
408*10201SEdward.Pilatowicz@Sun.COM 			/* fall back to the platform default */
409*10201SEdward.Pilatowicz@Sun.COM #if ((defined(__i386) || defined(__amd64)) && !defined(_ELF64))
410*10201SEdward.Pilatowicz@Sun.COM 			pltentries = pltrelsz / sizeof (Rel);
411*10201SEdward.Pilatowicz@Sun.COM 			dprintf("DI_PLTREL not found, defaulting to Rel");
412*10201SEdward.Pilatowicz@Sun.COM #else /* (!(__i386 || __amd64)) || _ELF64 */
413*10201SEdward.Pilatowicz@Sun.COM 			pltentries = pltrelsz / sizeof (Rela);
414*10201SEdward.Pilatowicz@Sun.COM 			dprintf("DI_PLTREL not found, defaulting to Rela");
415*10201SEdward.Pilatowicz@Sun.COM #endif /* (!(__i386 || __amd64) || _ELF64 */
416*10201SEdward.Pilatowicz@Sun.COM 		}
4173347Sab196087 
418*10201SEdward.Pilatowicz@Sun.COM 		if (pltentries < PLTREL_MIN_ENTRIES) {
419*10201SEdward.Pilatowicz@Sun.COM 			dprintf("too few PLT relocation entries "
420*10201SEdward.Pilatowicz@Sun.COM 			    "(found %lu, expected at least %d)\n",
421*10201SEdward.Pilatowicz@Sun.COM 			    (long)pltentries, PLTREL_MIN_ENTRIES);
4223347Sab196087 			goto bad;
4233347Sab196087 		}
424*10201SEdward.Pilatowicz@Sun.COM 		if (pltentries < PLTREL_MIN_ENTRIES + 2)
425*10201SEdward.Pilatowicz@Sun.COM 			goto done_with_plt;
4263347Sab196087 
427*10201SEdward.Pilatowicz@Sun.COM 		/*
428*10201SEdward.Pilatowicz@Sun.COM 		 * Now that we know the number of plt relocation entries
429*10201SEdward.Pilatowicz@Sun.COM 		 * we can calculate the size of the plt.
430*10201SEdward.Pilatowicz@Sun.COM 		 */
431*10201SEdward.Pilatowicz@Sun.COM 		pltsz = (pltentries + M_PLT_XNumber) * M_PLT_ENTSIZE;
432*10201SEdward.Pilatowicz@Sun.COM #if defined(__sparc)
433*10201SEdward.Pilatowicz@Sun.COM 		/* The sparc PLT always has a (delay slot) nop at the end */
434*10201SEdward.Pilatowicz@Sun.COM 		pltsz += 4;
435*10201SEdward.Pilatowicz@Sun.COM #endif /* __sparc */
4363347Sab196087 
4373347Sab196087 		size += sizeof (Shdr);
4383347Sab196087 		size += roundup(pltsz, SH_ADDRALIGN);
4393347Sab196087 	}
4403656Sjj204856 done_with_plt:
4413347Sab196087 
4423347Sab196087 	if ((elfdata = calloc(1, size)) == NULL)
4433347Sab196087 		goto bad;
4443347Sab196087 
4453347Sab196087 	/* LINTED - alignment */
4463347Sab196087 	ep = (Ehdr *)elfdata;
4473347Sab196087 	(void) memcpy(ep, ehdr, offsetof(Ehdr, e_phoff));
4483347Sab196087 
4493347Sab196087 	ep->e_ehsize = sizeof (Ehdr);
4503347Sab196087 	ep->e_phoff = sizeof (Ehdr);
4513347Sab196087 	ep->e_phentsize = ehdr->e_phentsize;
4523347Sab196087 	ep->e_phnum = phnum;
4533347Sab196087 	ep->e_shoff = ep->e_phoff + phnum * ep->e_phentsize;
4543347Sab196087 	ep->e_shentsize = sizeof (Shdr);
4553347Sab196087 	/*
4563347Sab196087 	 * Plt and SUNW_ldynsym sections are optional. C logical
4573347Sab196087 	 * binary operators return a 0 or 1 value, so the following
4583347Sab196087 	 * adds 1 for each optional section present.
4593347Sab196087 	 */
4603347Sab196087 	ep->e_shnum = 5 + (pltsz != 0) + (d[DI_SUNW_SYMTAB] != NULL);
4613347Sab196087 	ep->e_shstrndx = 1;
4623347Sab196087 
4633347Sab196087 	/* LINTED - alignment */
4643347Sab196087 	sp = (Shdr *)(elfdata + ep->e_shoff);
4653347Sab196087 	off = ep->e_shoff + ep->e_shentsize * ep->e_shnum;
4663347Sab196087 
4673347Sab196087 	/*
4683347Sab196087 	 * Copying the program headers directly from the process's
4693347Sab196087 	 * address space is a little suspect, but since we only
4703347Sab196087 	 * use them for their address and size values, this is fine.
4713347Sab196087 	 */
4723347Sab196087 	if (Pread(P, &elfdata[ep->e_phoff], phnum * ep->e_phentsize,
4733347Sab196087 	    addr + ehdr->e_phoff) != phnum * ep->e_phentsize) {
4743347Sab196087 		dprintf("failed to read program headers\n");
4753347Sab196087 		goto bad;
4763347Sab196087 	}
4773347Sab196087 
4783347Sab196087 	/*
4793347Sab196087 	 * The first elf section is always skipped.
4803347Sab196087 	 */
4813347Sab196087 	sp++;
4823347Sab196087 
4833347Sab196087 	/*
4843347Sab196087 	 * Section Header: .shstrtab
4853347Sab196087 	 */
4863347Sab196087 	sp->sh_name = SHSTR_NDX_shstrtab;
4873347Sab196087 	sp->sh_type = SHT_STRTAB;
4883347Sab196087 	sp->sh_flags = SHF_STRINGS;
4893347Sab196087 	sp->sh_addr = 0;
4903347Sab196087 	sp->sh_offset = off;
4913347Sab196087 	sp->sh_size = sizeof (shstr);
4923347Sab196087 	sp->sh_link = 0;
4933347Sab196087 	sp->sh_info = 0;
4943347Sab196087 	sp->sh_addralign = 1;
4953347Sab196087 	sp->sh_entsize = 0;
4963347Sab196087 
4973347Sab196087 	(void) memcpy(&elfdata[off], shstr, sizeof (shstr));
4983347Sab196087 	off += roundup(sp->sh_size, SH_ADDRALIGN);
4993347Sab196087 	sp++;
5003347Sab196087 
5013347Sab196087 	/*
5023347Sab196087 	 * Section Header: .SUNW_ldynsym
5033347Sab196087 	 */
5043347Sab196087 	if (d[DI_SUNW_SYMTAB] != NULL) {
5053347Sab196087 		sp->sh_name = SHSTR_NDX_SUNW_ldynsym;
5063347Sab196087 		sp->sh_type = SHT_SUNW_LDYNSYM;
5073347Sab196087 		sp->sh_flags = SHF_ALLOC;
5083347Sab196087 		sp->sh_addr = d[DI_SUNW_SYMTAB]->d_un.d_ptr;
5093347Sab196087 		if (ehdr->e_type == ET_DYN)
510*10201SEdward.Pilatowicz@Sun.COM 			sp->sh_addr += addr;
5113347Sab196087 		sp->sh_offset = off;
5123347Sab196087 		sp->sh_size = ldynsym_size;
5133347Sab196087 		sp->sh_link = dynstr_shndx;
5143347Sab196087 		/* Index of 1st global in table that has none == # items */
5153347Sab196087 		sp->sh_info = sp->sh_size / sizeof (Sym);
5163347Sab196087 		sp->sh_addralign = SH_ADDRALIGN;
5173347Sab196087 		sp->sh_entsize = sizeof (Sym);
5183347Sab196087 
5193347Sab196087 		if (Pread(P, &elfdata[off], sp->sh_size,
520*10201SEdward.Pilatowicz@Sun.COM 		    sp->sh_addr) != sp->sh_size) {
5213347Sab196087 			dprintf("failed to read .SUNW_ldynsym at %lx\n",
522*10201SEdward.Pilatowicz@Sun.COM 			    (long)sp->sh_addr);
5233347Sab196087 			goto bad;
5243347Sab196087 		}
5253347Sab196087 		off += sp->sh_size;
5263347Sab196087 		/* No need to round up ldynsym data. Dynsym data is same type */
5273347Sab196087 		sp++;
5283347Sab196087 	}
5293347Sab196087 
5303347Sab196087 	/*
5313347Sab196087 	 * Section Header: .dynsym
5323347Sab196087 	 */
5333347Sab196087 	sp->sh_name = SHSTR_NDX_dynsym;
5343347Sab196087 	sp->sh_type = SHT_DYNSYM;
5353347Sab196087 	sp->sh_flags = SHF_ALLOC;
5363347Sab196087 	sp->sh_addr = d[DI_SYMTAB]->d_un.d_ptr;
5373347Sab196087 	if (ehdr->e_type == ET_DYN)
538*10201SEdward.Pilatowicz@Sun.COM 		sp->sh_addr += addr;
5393347Sab196087 	sp->sh_offset = off;
5403347Sab196087 	sp->sh_size = dynsym_size;
5413347Sab196087 	sp->sh_link = dynstr_shndx;
5423347Sab196087 	sp->sh_info = 1;	/* Index of 1st global in table */
5433347Sab196087 	sp->sh_addralign = SH_ADDRALIGN;
5443347Sab196087 	sp->sh_entsize = sizeof (Sym);
5453347Sab196087 
5463347Sab196087 	if (Pread(P, &elfdata[off], sp->sh_size,
547*10201SEdward.Pilatowicz@Sun.COM 	    sp->sh_addr) != sp->sh_size) {
5483347Sab196087 		dprintf("failed to read .dynsym at %lx\n",
549*10201SEdward.Pilatowicz@Sun.COM 		    (long)sp->sh_addr);
5503347Sab196087 		goto bad;
5513347Sab196087 	}
5523347Sab196087 
5533347Sab196087 	off += roundup(sp->sh_size, SH_ADDRALIGN);
5543347Sab196087 	sp++;
5553347Sab196087 
5563347Sab196087 	/*
5573347Sab196087 	 * Section Header: .dynstr
5583347Sab196087 	 */
5593347Sab196087 	sp->sh_name = SHSTR_NDX_dynstr;
5603347Sab196087 	sp->sh_type = SHT_STRTAB;
5613347Sab196087 	sp->sh_flags = SHF_ALLOC | SHF_STRINGS;
5623347Sab196087 	sp->sh_addr = d[DI_STRTAB]->d_un.d_ptr;
5633347Sab196087 	if (ehdr->e_type == ET_DYN)
564*10201SEdward.Pilatowicz@Sun.COM 		sp->sh_addr += addr;
5653347Sab196087 	sp->sh_offset = off;
5663347Sab196087 	sp->sh_size = d[DI_STRSZ]->d_un.d_val;
5673347Sab196087 	sp->sh_link = 0;
5683347Sab196087 	sp->sh_info = 0;
5693347Sab196087 	sp->sh_addralign = 1;
5703347Sab196087 	sp->sh_entsize = 0;
5713347Sab196087 
5723347Sab196087 	if (Pread(P, &elfdata[off], sp->sh_size,
573*10201SEdward.Pilatowicz@Sun.COM 	    sp->sh_addr) != sp->sh_size) {
5743347Sab196087 		dprintf("failed to read .dynstr\n");
5753347Sab196087 		goto bad;
5763347Sab196087 	}
5773347Sab196087 	off += roundup(sp->sh_size, SH_ADDRALIGN);
5783347Sab196087 	sp++;
5793347Sab196087 
5803347Sab196087 	/*
5813347Sab196087 	 * Section Header: .dynamic
5823347Sab196087 	 */
5833347Sab196087 	sp->sh_name = SHSTR_NDX_dynamic;
5843347Sab196087 	sp->sh_type = SHT_DYNAMIC;
5853347Sab196087 	sp->sh_flags = SHF_WRITE | SHF_ALLOC;
5863347Sab196087 	sp->sh_addr = phdr->p_vaddr;
5873347Sab196087 	if (ehdr->e_type == ET_DYN)
5883347Sab196087 		sp->sh_addr -= addr;
5893347Sab196087 	sp->sh_offset = off;
5903347Sab196087 	sp->sh_size = phdr->p_filesz;
5913347Sab196087 	sp->sh_link = dynstr_shndx;
5923347Sab196087 	sp->sh_info = 0;
5933347Sab196087 	sp->sh_addralign = SH_ADDRALIGN;
5943347Sab196087 	sp->sh_entsize = sizeof (Dyn);
5953347Sab196087 
5963347Sab196087 	(void) memcpy(&elfdata[off], dp, sp->sh_size);
5973347Sab196087 	off += roundup(sp->sh_size, SH_ADDRALIGN);
5983347Sab196087 	sp++;
5993347Sab196087 
6003347Sab196087 	/*
6013347Sab196087 	 * Section Header: .plt
6023347Sab196087 	 */
6033347Sab196087 	if (pltsz != 0) {
604*10201SEdward.Pilatowicz@Sun.COM 		ulong_t		plt_symhash;
605*10201SEdward.Pilatowicz@Sun.COM 		uint_t		htmp, ndx;
606*10201SEdward.Pilatowicz@Sun.COM 		uintptr_t	strtabptr, strtabname;
607*10201SEdward.Pilatowicz@Sun.COM 		Sym		sym, *symtabptr;
608*10201SEdward.Pilatowicz@Sun.COM 		uint_t		*hash;
609*10201SEdward.Pilatowicz@Sun.COM 		char		strbuf[sizeof ("_PROCEDURE_LINKAGE_TABLE_")];
610*10201SEdward.Pilatowicz@Sun.COM 
611*10201SEdward.Pilatowicz@Sun.COM 		/*
612*10201SEdward.Pilatowicz@Sun.COM 		 * Now we need to find the address of the plt by looking
613*10201SEdward.Pilatowicz@Sun.COM 		 * up the "_PROCEDURE_LINKAGE_TABLE_" symbol.
614*10201SEdward.Pilatowicz@Sun.COM 		 */
615*10201SEdward.Pilatowicz@Sun.COM 
616*10201SEdward.Pilatowicz@Sun.COM 		/* get the address of the symtab and strtab sections */
617*10201SEdward.Pilatowicz@Sun.COM 		strtabptr = d[DI_STRTAB]->d_un.d_ptr;
618*10201SEdward.Pilatowicz@Sun.COM 		symtabptr = (Sym *)(uintptr_t)d[DI_SYMTAB]->d_un.d_ptr;
619*10201SEdward.Pilatowicz@Sun.COM 		if (ehdr->e_type == ET_DYN) {
620*10201SEdward.Pilatowicz@Sun.COM 			strtabptr += addr;
621*10201SEdward.Pilatowicz@Sun.COM 			symtabptr = (Sym*)((uintptr_t)symtabptr + addr);
622*10201SEdward.Pilatowicz@Sun.COM 		}
623*10201SEdward.Pilatowicz@Sun.COM 
624*10201SEdward.Pilatowicz@Sun.COM 		/* find the .hash bucket address for this symbol */
625*10201SEdward.Pilatowicz@Sun.COM 		plt_symhash = elf_hash("_PROCEDURE_LINKAGE_TABLE_");
626*10201SEdward.Pilatowicz@Sun.COM 		htmp = plt_symhash % hnbuckets;
627*10201SEdward.Pilatowicz@Sun.COM 		hash = &((uint_t *)hptr)[2 + htmp];
628*10201SEdward.Pilatowicz@Sun.COM 
629*10201SEdward.Pilatowicz@Sun.COM 		/* read the elf hash bucket index */
630*10201SEdward.Pilatowicz@Sun.COM 		if (Pread(P, &ndx, sizeof (ndx), (uintptr_t)hash) !=
631*10201SEdward.Pilatowicz@Sun.COM 		    sizeof (ndx)) {
632*10201SEdward.Pilatowicz@Sun.COM 			dprintf("Pread of .hash at %lx failed\n", (long)hash);
633*10201SEdward.Pilatowicz@Sun.COM 			goto bad;
634*10201SEdward.Pilatowicz@Sun.COM 		}
635*10201SEdward.Pilatowicz@Sun.COM 
636*10201SEdward.Pilatowicz@Sun.COM 		while (ndx) {
637*10201SEdward.Pilatowicz@Sun.COM 			if (Pread(P, &sym, sizeof (sym),
638*10201SEdward.Pilatowicz@Sun.COM 			    (uintptr_t)&symtabptr[ndx]) != sizeof (sym)) {
639*10201SEdward.Pilatowicz@Sun.COM 				dprintf("Pread of .symtab at %lx failed\n",
640*10201SEdward.Pilatowicz@Sun.COM 				    (long)&symtabptr[ndx]);
641*10201SEdward.Pilatowicz@Sun.COM 				goto bad;
642*10201SEdward.Pilatowicz@Sun.COM 			}
643*10201SEdward.Pilatowicz@Sun.COM 
644*10201SEdward.Pilatowicz@Sun.COM 			strtabname = strtabptr + sym.st_name;
645*10201SEdward.Pilatowicz@Sun.COM 			if (Pread_string(P, strbuf, sizeof (strbuf),
646*10201SEdward.Pilatowicz@Sun.COM 			    strtabname) < 0) {
647*10201SEdward.Pilatowicz@Sun.COM 				dprintf("Pread of .strtab at %lx failed\n",
648*10201SEdward.Pilatowicz@Sun.COM 				    (long)strtabname);
649*10201SEdward.Pilatowicz@Sun.COM 				goto bad;
650*10201SEdward.Pilatowicz@Sun.COM 			}
651*10201SEdward.Pilatowicz@Sun.COM 
652*10201SEdward.Pilatowicz@Sun.COM 			if (strcmp("_PROCEDURE_LINKAGE_TABLE_", strbuf) == 0)
653*10201SEdward.Pilatowicz@Sun.COM 				break;
654*10201SEdward.Pilatowicz@Sun.COM 
655*10201SEdward.Pilatowicz@Sun.COM 			hash = &((uint_t *)hptr)[2 + hnbuckets + ndx];
656*10201SEdward.Pilatowicz@Sun.COM 			if (Pread(P, &ndx, sizeof (ndx), (uintptr_t)hash) !=
657*10201SEdward.Pilatowicz@Sun.COM 			    sizeof (ndx)) {
658*10201SEdward.Pilatowicz@Sun.COM 				dprintf("Pread of .hash at %lx failed\n",
659*10201SEdward.Pilatowicz@Sun.COM 				    (long)hash);
660*10201SEdward.Pilatowicz@Sun.COM 				goto bad;
661*10201SEdward.Pilatowicz@Sun.COM 			}
662*10201SEdward.Pilatowicz@Sun.COM 		}
663*10201SEdward.Pilatowicz@Sun.COM 
664*10201SEdward.Pilatowicz@Sun.COM #if defined(__sparc)
665*10201SEdward.Pilatowicz@Sun.COM 		if (sym.st_value != d[DI_PLTGOT]->d_un.d_ptr) {
666*10201SEdward.Pilatowicz@Sun.COM 			dprintf("warning: DI_PLTGOT (%lx) doesn't match "
667*10201SEdward.Pilatowicz@Sun.COM 			    ".plt symbol pointer (%lx)",
668*10201SEdward.Pilatowicz@Sun.COM 			    (long)d[DI_PLTGOT]->d_un.d_ptr,
669*10201SEdward.Pilatowicz@Sun.COM 			    (long)sym.st_value);
670*10201SEdward.Pilatowicz@Sun.COM 		}
671*10201SEdward.Pilatowicz@Sun.COM #endif /* __sparc */
672*10201SEdward.Pilatowicz@Sun.COM 
673*10201SEdward.Pilatowicz@Sun.COM 		if (ndx == 0) {
674*10201SEdward.Pilatowicz@Sun.COM 			dprintf(
675*10201SEdward.Pilatowicz@Sun.COM 			    "Failed to find \"_PROCEDURE_LINKAGE_TABLE_\"\n");
676*10201SEdward.Pilatowicz@Sun.COM 			goto bad;
677*10201SEdward.Pilatowicz@Sun.COM 		}
678*10201SEdward.Pilatowicz@Sun.COM 
6793347Sab196087 		sp->sh_name = SHSTR_NDX_plt;
6803347Sab196087 		sp->sh_type = SHT_PROGBITS;
6813347Sab196087 		sp->sh_flags = SHF_WRITE | SHF_ALLOC | SHF_EXECINSTR;
682*10201SEdward.Pilatowicz@Sun.COM 		sp->sh_addr = sym.st_value;
6833347Sab196087 		if (ehdr->e_type == ET_DYN)
684*10201SEdward.Pilatowicz@Sun.COM 			sp->sh_addr += addr;
6853347Sab196087 		sp->sh_offset = off;
6863347Sab196087 		sp->sh_size = pltsz;
6873347Sab196087 		sp->sh_link = 0;
6883347Sab196087 		sp->sh_info = 0;
6893347Sab196087 		sp->sh_addralign = SH_ADDRALIGN;
690*10201SEdward.Pilatowicz@Sun.COM 		sp->sh_entsize = M_PLT_ENTSIZE;
6913347Sab196087 
692*10201SEdward.Pilatowicz@Sun.COM 		if (Pread(P, &elfdata[off], sp->sh_size, sp->sh_addr) !=
693*10201SEdward.Pilatowicz@Sun.COM 		    sp->sh_size) {
694*10201SEdward.Pilatowicz@Sun.COM 			dprintf("failed to read .plt at %lx\n",
695*10201SEdward.Pilatowicz@Sun.COM 			    (long)sp->sh_addr);
6963347Sab196087 			goto bad;
6973347Sab196087 		}
6983347Sab196087 		off += roundup(sp->sh_size, SH_ADDRALIGN);
6993347Sab196087 		sp++;
7003347Sab196087 	}
7013347Sab196087 
702*10201SEdward.Pilatowicz@Sun.COM 	/* make sure we didn't write past the end of allocated memory */
703*10201SEdward.Pilatowicz@Sun.COM 	sp++;
704*10201SEdward.Pilatowicz@Sun.COM 	assert(((uintptr_t)(sp) - 1) < ((uintptr_t)elfdata + size));
705*10201SEdward.Pilatowicz@Sun.COM 
7063347Sab196087 	free(dp);
7073347Sab196087 	if ((elf = elf_memory(elfdata, size)) == NULL) {
7083347Sab196087 		free(elfdata);
7093347Sab196087 		return (NULL);
7103347Sab196087 	}
7113347Sab196087 
7123347Sab196087 	fptr->file_elfmem = elfdata;
7133347Sab196087 
7143347Sab196087 	return (elf);
7153347Sab196087 
7163347Sab196087 bad:
7173347Sab196087 	if (dp != NULL)
7183347Sab196087 		free(dp);
7193347Sab196087 	if (elfdata != NULL)
7203347Sab196087 		free(elfdata);
7213347Sab196087 	return (NULL);
7223347Sab196087 }
723