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