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