12de3b87aSKai Wang /*- 22de3b87aSKai Wang * Copyright (c) 2006,2008 Joseph Koshy 32de3b87aSKai Wang * All rights reserved. 42de3b87aSKai Wang * 52de3b87aSKai Wang * Redistribution and use in source and binary forms, with or without 62de3b87aSKai Wang * modification, are permitted provided that the following conditions 72de3b87aSKai Wang * are met: 82de3b87aSKai Wang * 1. Redistributions of source code must retain the above copyright 92de3b87aSKai Wang * notice, this list of conditions and the following disclaimer. 102de3b87aSKai Wang * 2. Redistributions in binary form must reproduce the above copyright 112de3b87aSKai Wang * notice, this list of conditions and the following disclaimer in the 122de3b87aSKai Wang * documentation and/or other materials provided with the distribution. 132de3b87aSKai Wang * 142de3b87aSKai Wang * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 152de3b87aSKai Wang * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 162de3b87aSKai Wang * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 172de3b87aSKai Wang * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 182de3b87aSKai Wang * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 192de3b87aSKai Wang * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 202de3b87aSKai Wang * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 212de3b87aSKai Wang * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 222de3b87aSKai Wang * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 232de3b87aSKai Wang * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 242de3b87aSKai Wang * SUCH DAMAGE. 252de3b87aSKai Wang */ 262de3b87aSKai Wang 272de3b87aSKai Wang #include <assert.h> 282de3b87aSKai Wang #include <gelf.h> 292de3b87aSKai Wang #include <libelf.h> 302de3b87aSKai Wang #include <stdlib.h> 312de3b87aSKai Wang 322de3b87aSKai Wang #include "_libelf.h" 332de3b87aSKai Wang 3467d97fe7SEd Maste ELFTC_VCSID("$Id: libelf_ehdr.c 3174 2015-03-27 17:13:41Z emaste $"); 352de3b87aSKai Wang 362de3b87aSKai Wang /* 372de3b87aSKai Wang * Retrieve counts for sections, phdrs and the section string table index 382de3b87aSKai Wang * from section header #0 of the ELF object. 392de3b87aSKai Wang */ 402de3b87aSKai Wang static int 412de3b87aSKai Wang _libelf_load_extended(Elf *e, int ec, uint64_t shoff, uint16_t phnum, 422de3b87aSKai Wang uint16_t strndx) 432de3b87aSKai Wang { 442de3b87aSKai Wang Elf_Scn *scn; 452de3b87aSKai Wang size_t fsz; 46cf781b2eSEd Maste int (*xlator)(unsigned char *_d, size_t _dsz, unsigned char *_s, 47cf781b2eSEd Maste size_t _c, int _swap); 482de3b87aSKai Wang uint32_t shtype; 492de3b87aSKai Wang 502de3b87aSKai Wang assert(STAILQ_EMPTY(&e->e_u.e_elf.e_scn)); 512de3b87aSKai Wang 522de3b87aSKai Wang fsz = _libelf_fsize(ELF_T_SHDR, ec, e->e_version, 1); 532de3b87aSKai Wang assert(fsz > 0); 542de3b87aSKai Wang 552de3b87aSKai Wang if (e->e_rawsize < shoff + fsz) { /* raw file too small */ 562de3b87aSKai Wang LIBELF_SET_ERROR(HEADER, 0); 572de3b87aSKai Wang return (0); 582de3b87aSKai Wang } 592de3b87aSKai Wang 602de3b87aSKai Wang if ((scn = _libelf_allocate_scn(e, (size_t) 0)) == NULL) 612de3b87aSKai Wang return (0); 622de3b87aSKai Wang 632de3b87aSKai Wang xlator = _libelf_get_translator(ELF_T_SHDR, ELF_TOMEMORY, ec); 64cf781b2eSEd Maste (*xlator)((unsigned char *) &scn->s_shdr, sizeof(scn->s_shdr), 65cf781b2eSEd Maste (unsigned char *) e->e_rawfile + shoff, (size_t) 1, 662de3b87aSKai Wang e->e_byteorder != LIBELF_PRIVATE(byteorder)); 672de3b87aSKai Wang 682de3b87aSKai Wang #define GET_SHDR_MEMBER(M) ((ec == ELFCLASS32) ? scn->s_shdr.s_shdr32.M : \ 692de3b87aSKai Wang scn->s_shdr.s_shdr64.M) 702de3b87aSKai Wang 712de3b87aSKai Wang if ((shtype = GET_SHDR_MEMBER(sh_type)) != SHT_NULL) { 722de3b87aSKai Wang LIBELF_SET_ERROR(SECTION, 0); 732de3b87aSKai Wang return (0); 742de3b87aSKai Wang } 752de3b87aSKai Wang 76cf781b2eSEd Maste e->e_u.e_elf.e_nscn = (size_t) GET_SHDR_MEMBER(sh_size); 772de3b87aSKai Wang e->e_u.e_elf.e_nphdr = (phnum != PN_XNUM) ? phnum : 782de3b87aSKai Wang GET_SHDR_MEMBER(sh_info); 792de3b87aSKai Wang e->e_u.e_elf.e_strndx = (strndx != SHN_XINDEX) ? strndx : 802de3b87aSKai Wang GET_SHDR_MEMBER(sh_link); 812de3b87aSKai Wang #undef GET_SHDR_MEMBER 822de3b87aSKai Wang 832de3b87aSKai Wang return (1); 842de3b87aSKai Wang } 852de3b87aSKai Wang 862de3b87aSKai Wang #define EHDR_INIT(E,SZ) do { \ 872de3b87aSKai Wang Elf##SZ##_Ehdr *eh = (E); \ 882de3b87aSKai Wang eh->e_ident[EI_MAG0] = ELFMAG0; \ 892de3b87aSKai Wang eh->e_ident[EI_MAG1] = ELFMAG1; \ 902de3b87aSKai Wang eh->e_ident[EI_MAG2] = ELFMAG2; \ 912de3b87aSKai Wang eh->e_ident[EI_MAG3] = ELFMAG3; \ 922de3b87aSKai Wang eh->e_ident[EI_CLASS] = ELFCLASS##SZ; \ 932de3b87aSKai Wang eh->e_ident[EI_DATA] = ELFDATANONE; \ 94cf781b2eSEd Maste eh->e_ident[EI_VERSION] = LIBELF_PRIVATE(version) & 0xFFU; \ 952de3b87aSKai Wang eh->e_machine = EM_NONE; \ 962de3b87aSKai Wang eh->e_type = ELF_K_NONE; \ 972de3b87aSKai Wang eh->e_version = LIBELF_PRIVATE(version); \ 982de3b87aSKai Wang } while (0) 992de3b87aSKai Wang 1002de3b87aSKai Wang void * 1012de3b87aSKai Wang _libelf_ehdr(Elf *e, int ec, int allocate) 1022de3b87aSKai Wang { 1032de3b87aSKai Wang void *ehdr; 1042de3b87aSKai Wang size_t fsz, msz; 1052de3b87aSKai Wang uint16_t phnum, shnum, strndx; 1062de3b87aSKai Wang uint64_t shoff; 107cf781b2eSEd Maste int (*xlator)(unsigned char *_d, size_t _dsz, unsigned char *_s, 108cf781b2eSEd Maste size_t _c, int _swap); 1092de3b87aSKai Wang 1102de3b87aSKai Wang assert(ec == ELFCLASS32 || ec == ELFCLASS64); 1112de3b87aSKai Wang 1122de3b87aSKai Wang if (e == NULL || e->e_kind != ELF_K_ELF) { 1132de3b87aSKai Wang LIBELF_SET_ERROR(ARGUMENT, 0); 1142de3b87aSKai Wang return (NULL); 1152de3b87aSKai Wang } 1162de3b87aSKai Wang 1172de3b87aSKai Wang if (e->e_class != ELFCLASSNONE && e->e_class != ec) { 1182de3b87aSKai Wang LIBELF_SET_ERROR(CLASS, 0); 1192de3b87aSKai Wang return (NULL); 1202de3b87aSKai Wang } 1212de3b87aSKai Wang 1222de3b87aSKai Wang if (e->e_version != EV_CURRENT) { 1232de3b87aSKai Wang LIBELF_SET_ERROR(VERSION, 0); 1242de3b87aSKai Wang return (NULL); 1252de3b87aSKai Wang } 1262de3b87aSKai Wang 1272de3b87aSKai Wang if (e->e_class == ELFCLASSNONE) 1282de3b87aSKai Wang e->e_class = ec; 1292de3b87aSKai Wang 1302de3b87aSKai Wang if (ec == ELFCLASS32) 1312de3b87aSKai Wang ehdr = (void *) e->e_u.e_elf.e_ehdr.e_ehdr32; 1322de3b87aSKai Wang else 1332de3b87aSKai Wang ehdr = (void *) e->e_u.e_elf.e_ehdr.e_ehdr64; 1342de3b87aSKai Wang 1352de3b87aSKai Wang if (ehdr != NULL) /* already have a translated ehdr */ 1362de3b87aSKai Wang return (ehdr); 1372de3b87aSKai Wang 1382de3b87aSKai Wang fsz = _libelf_fsize(ELF_T_EHDR, ec, e->e_version, (size_t) 1); 1392de3b87aSKai Wang assert(fsz > 0); 1402de3b87aSKai Wang 1412de3b87aSKai Wang if (e->e_cmd != ELF_C_WRITE && e->e_rawsize < fsz) { 1422de3b87aSKai Wang LIBELF_SET_ERROR(HEADER, 0); 1432de3b87aSKai Wang return (NULL); 1442de3b87aSKai Wang } 1452de3b87aSKai Wang 1462de3b87aSKai Wang msz = _libelf_msize(ELF_T_EHDR, ec, EV_CURRENT); 1472de3b87aSKai Wang 1482de3b87aSKai Wang assert(msz > 0); 1492de3b87aSKai Wang 1502de3b87aSKai Wang if ((ehdr = calloc((size_t) 1, msz)) == NULL) { 1512de3b87aSKai Wang LIBELF_SET_ERROR(RESOURCE, 0); 1522de3b87aSKai Wang return (NULL); 1532de3b87aSKai Wang } 1542de3b87aSKai Wang 1552de3b87aSKai Wang if (ec == ELFCLASS32) { 1562de3b87aSKai Wang e->e_u.e_elf.e_ehdr.e_ehdr32 = ehdr; 1572de3b87aSKai Wang EHDR_INIT(ehdr,32); 1582de3b87aSKai Wang } else { 1592de3b87aSKai Wang e->e_u.e_elf.e_ehdr.e_ehdr64 = ehdr; 1602de3b87aSKai Wang EHDR_INIT(ehdr,64); 1612de3b87aSKai Wang } 1622de3b87aSKai Wang 1632de3b87aSKai Wang if (allocate) 1642de3b87aSKai Wang e->e_flags |= ELF_F_DIRTY; 1652de3b87aSKai Wang 1662de3b87aSKai Wang if (e->e_cmd == ELF_C_WRITE) 1672de3b87aSKai Wang return (ehdr); 1682de3b87aSKai Wang 1692de3b87aSKai Wang xlator = _libelf_get_translator(ELF_T_EHDR, ELF_TOMEMORY, ec); 170cf781b2eSEd Maste (*xlator)((unsigned char*) ehdr, msz, e->e_rawfile, (size_t) 1, 1712de3b87aSKai Wang e->e_byteorder != LIBELF_PRIVATE(byteorder)); 1722de3b87aSKai Wang 1732de3b87aSKai Wang if (ec == ELFCLASS32) { 1742de3b87aSKai Wang phnum = ((Elf32_Ehdr *) ehdr)->e_phnum; 1752de3b87aSKai Wang shnum = ((Elf32_Ehdr *) ehdr)->e_shnum; 1762de3b87aSKai Wang shoff = ((Elf32_Ehdr *) ehdr)->e_shoff; 1772de3b87aSKai Wang strndx = ((Elf32_Ehdr *) ehdr)->e_shstrndx; 1782de3b87aSKai Wang } else { 1792de3b87aSKai Wang phnum = ((Elf64_Ehdr *) ehdr)->e_phnum; 1802de3b87aSKai Wang shnum = ((Elf64_Ehdr *) ehdr)->e_shnum; 1812de3b87aSKai Wang shoff = ((Elf64_Ehdr *) ehdr)->e_shoff; 1822de3b87aSKai Wang strndx = ((Elf64_Ehdr *) ehdr)->e_shstrndx; 1832de3b87aSKai Wang } 1842de3b87aSKai Wang 1852de3b87aSKai Wang if (shnum >= SHN_LORESERVE || 1862de3b87aSKai Wang (shoff == 0LL && (shnum != 0 || phnum == PN_XNUM || 1872de3b87aSKai Wang strndx == SHN_XINDEX))) { 1882de3b87aSKai Wang LIBELF_SET_ERROR(HEADER, 0); 1892de3b87aSKai Wang return (NULL); 1902de3b87aSKai Wang } 1912de3b87aSKai Wang 192*1d1bfbbbSConrad Meyer /* 193*1d1bfbbbSConrad Meyer * If extended numbering is being used, read the correct 194*1d1bfbbbSConrad Meyer * number of sections and program header entries. 195*1d1bfbbbSConrad Meyer */ 196*1d1bfbbbSConrad Meyer if ((shnum == 0 && shoff != 0) || phnum == PN_XNUM || strndx == SHN_XINDEX) { 197*1d1bfbbbSConrad Meyer if (_libelf_load_extended(e, ec, shoff, phnum, strndx) == 0) 198*1d1bfbbbSConrad Meyer return (NULL); 199*1d1bfbbbSConrad Meyer } else { 200*1d1bfbbbSConrad Meyer /* not using extended numbering */ 2012de3b87aSKai Wang e->e_u.e_elf.e_nphdr = phnum; 2022de3b87aSKai Wang e->e_u.e_elf.e_nscn = shnum; 2032de3b87aSKai Wang e->e_u.e_elf.e_strndx = strndx; 204*1d1bfbbbSConrad Meyer } 2052de3b87aSKai Wang 2062de3b87aSKai Wang return (ehdr); 2072de3b87aSKai Wang } 208