libelf_ehdr.c revision 4484:7c56a6c9c265
12810SN/A/*- 29725Sandreas.hansson@arm.com * Copyright (c) 2006 Joseph Koshy 39347SAndreas.Sandberg@arm.com * All rights reserved. 49347SAndreas.Sandberg@arm.com * 59347SAndreas.Sandberg@arm.com * Redistribution and use in source and binary forms, with or without 69347SAndreas.Sandberg@arm.com * modification, are permitted provided that the following conditions 79347SAndreas.Sandberg@arm.com * are met: 89347SAndreas.Sandberg@arm.com * 1. Redistributions of source code must retain the above copyright 99347SAndreas.Sandberg@arm.com * notice, this list of conditions and the following disclaimer. 109347SAndreas.Sandberg@arm.com * 2. Redistributions in binary form must reproduce the above copyright 119347SAndreas.Sandberg@arm.com * notice, this list of conditions and the following disclaimer in the 129347SAndreas.Sandberg@arm.com * documentation and/or other materials provided with the distribution. 139347SAndreas.Sandberg@arm.com * 142810SN/A * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 152810SN/A * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 162810SN/A * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 172810SN/A * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 182810SN/A * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 192810SN/A * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 202810SN/A * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 212810SN/A * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 222810SN/A * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 232810SN/A * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 242810SN/A * SUCH DAMAGE. 252810SN/A * 262810SN/A * $FreeBSD: src/lib/libelf/libelf_ehdr.c,v 1.2 2006/12/25 02:22:22 jkoshy Exp $ 272810SN/A */ 282810SN/A 292810SN/A#include <assert.h> 302810SN/A#include "gelf.h" 312810SN/A#include "libelf.h" 322810SN/A#include <stdlib.h> 332810SN/A 342810SN/A#include "_libelf.h" 352810SN/A 362810SN/A/* 372810SN/A * Retrieve counts for sections, phdrs and the section string table index 382810SN/A * from section header #0 of the ELF object. 392810SN/A */ 402810SN/Astatic int 419347SAndreas.Sandberg@arm.com_libelf_load_extended(Elf *e, int ec, uint64_t shoff, uint16_t phnum, 422810SN/A uint16_t strndx) 432810SN/A{ 442810SN/A Elf_Scn *scn; 452810SN/A size_t fsz; 462810SN/A void (*xlator)(char *_d, char *_s, size_t _c, int _swap); 472810SN/A uint32_t shtype; 484626SN/A 494626SN/A assert(STAILQ_EMPTY(&e->e_u.e_elf.e_scn)); 502810SN/A 512810SN/A fsz = _libelf_fsize(ELF_T_SHDR, ec, e->e_version, 1); 524626SN/A assert(fsz > 0); 538229Snate@binkert.org 544626SN/A if (e->e_rawsize < shoff + fsz) { /* raw file too small */ 559347SAndreas.Sandberg@arm.com LIBELF_SET_ERROR(HEADER, 0); 562810SN/A return (0); 572810SN/A } 583374SN/A 592810SN/A if ((scn = _libelf_allocate_scn(e, (size_t) 0)) == NULL) 609347SAndreas.Sandberg@arm.com return (0); 614626SN/A 622810SN/A xlator = _libelf_get_translator(ELF_T_SHDR, ELF_TOMEMORY, ec); 635314SN/A (*xlator)((char *) &scn->s_shdr, e->e_rawfile + shoff, (size_t) 1, 645314SN/A e->e_byteorder != LIBELF_PRIVATE(byteorder)); 655314SN/A 662810SN/A#define GET_SHDR_MEMBER(M) ((ec == ELFCLASS32) ? scn->s_shdr.s_shdr32.M : \ 672810SN/A scn->s_shdr.s_shdr64.M) 684626SN/A 694626SN/A if ((shtype = GET_SHDR_MEMBER(sh_type)) != SHT_NULL) { 704626SN/A LIBELF_SET_ERROR(SECTION, 0); 712810SN/A return (0); 724626SN/A } 732810SN/A 742810SN/A e->e_u.e_elf.e_nscn = GET_SHDR_MEMBER(sh_size); 754626SN/A e->e_u.e_elf.e_nphdr = (phnum != PN_XNUM) ? phnum : 764626SN/A GET_SHDR_MEMBER(sh_info); 772810SN/A e->e_u.e_elf.e_strndx = (strndx != SHN_XINDEX) ? strndx : 782810SN/A GET_SHDR_MEMBER(sh_link); 792810SN/A#undef GET_SHDR_MEMBER 8010622Smitch.hayenga@arm.com 8110622Smitch.hayenga@arm.com return (1); 8210622Smitch.hayenga@arm.com} 8310622Smitch.hayenga@arm.com 8410622Smitch.hayenga@arm.com#define EHDR_INIT(E,SZ) do { \ 8510622Smitch.hayenga@arm.com Elf##SZ##_Ehdr *eh = (E); \ 869725Sandreas.hansson@arm.com eh->e_ident[EI_MAG0] = ELFMAG0; \ 879725Sandreas.hansson@arm.com eh->e_ident[EI_MAG1] = ELFMAG1; \ 889725Sandreas.hansson@arm.com eh->e_ident[EI_MAG2] = ELFMAG2; \ 899725Sandreas.hansson@arm.com eh->e_ident[EI_MAG3] = ELFMAG3; \ 909725Sandreas.hansson@arm.com eh->e_ident[EI_CLASS] = ELFCLASS##SZ; \ 919725Sandreas.hansson@arm.com eh->e_ident[EI_DATA] = ELFDATANONE; \ 929725Sandreas.hansson@arm.com eh->e_ident[EI_VERSION] = LIBELF_PRIVATE(version); \ 939725Sandreas.hansson@arm.com eh->e_machine = EM_NONE; \ 949725Sandreas.hansson@arm.com eh->e_type = ELF_K_NONE; \ 959347SAndreas.Sandberg@arm.com eh->e_version = LIBELF_PRIVATE(version); \ 969347SAndreas.Sandberg@arm.com } while (0) 979347SAndreas.Sandberg@arm.com 984666SN/Avoid * 994666SN/A_libelf_ehdr(Elf *e, int ec, int allocate) 1004666SN/A{ 1012810SN/A void *ehdr; 1024626SN/A size_t fsz, msz; 1032810SN/A uint16_t phnum, shnum, strndx; 1044626SN/A uint64_t shoff; 1054626SN/A void (*xlator)(char *_d, char *_s, size_t _c, int _swap); 1064628SN/A 1074628SN/A assert(ec == ELFCLASS32 || ec == ELFCLASS64); 1084628SN/A 1092810SN/A if (e == NULL || e->e_kind != ELF_K_ELF) { 1102810SN/A LIBELF_SET_ERROR(ARGUMENT, 0); 1114626SN/A return (NULL); 1124626SN/A } 1134626SN/A 1144626SN/A if (e->e_class != ELFCLASSNONE && e->e_class != ec) { 11510622Smitch.hayenga@arm.com LIBELF_SET_ERROR(CLASS, 0); 11610622Smitch.hayenga@arm.com return (NULL); 1172810SN/A } 1185314SN/A 11910622Smitch.hayenga@arm.com if (e->e_version != EV_CURRENT) { 1202810SN/A LIBELF_SET_ERROR(VERSION, 0); 1212810SN/A return (NULL); 1224626SN/A } 1232810SN/A 12410028SGiacomo.Gabrielli@arm.com if (e->e_class == ELFCLASSNONE) 1252810SN/A e->e_class = ec; 1262810SN/A 12710028SGiacomo.Gabrielli@arm.com if (ec == ELFCLASS32) 1282810SN/A ehdr = (void *) e->e_u.e_elf.e_ehdr.e_ehdr32; 1292810SN/A else 1304626SN/A ehdr = (void *) e->e_u.e_elf.e_ehdr.e_ehdr64; 1312810SN/A 13210028SGiacomo.Gabrielli@arm.com if (ehdr != NULL) /* already have a translated ehdr */ 1334626SN/A return (ehdr); 1342810SN/A 1352810SN/A fsz = _libelf_fsize(ELF_T_EHDR, ec, e->e_version, (size_t) 1); 1362810SN/A assert(fsz > 0); 13710028SGiacomo.Gabrielli@arm.com 13810028SGiacomo.Gabrielli@arm.com if (e->e_cmd != ELF_C_WRITE && e->e_rawsize < fsz) { 1392810SN/A LIBELF_SET_ERROR(HEADER, 0); 1402810SN/A return (NULL); 1413374SN/A } 1422982SN/A 14310028SGiacomo.Gabrielli@arm.com msz = _libelf_msize(ELF_T_EHDR, ec, EV_CURRENT); 1442810SN/A 1452810SN/A assert(msz > 0); 14610028SGiacomo.Gabrielli@arm.com 1472810SN/A if ((ehdr = calloc((size_t) 1, msz)) == NULL) { 1484920SN/A LIBELF_SET_ERROR(RESOURCE, 0); 1494920SN/A return (NULL); 1502810SN/A } 1513374SN/A 1522810SN/A if (ec == ELFCLASS32) { 1532982SN/A e->e_u.e_elf.e_ehdr.e_ehdr32 = ehdr; 1542810SN/A EHDR_INIT(ehdr,32); 1552810SN/A } else { 1562810SN/A e->e_u.e_elf.e_ehdr.e_ehdr64 = ehdr; 1574626SN/A EHDR_INIT(ehdr,64); 1582810SN/A } 1594666SN/A 1604666SN/A if (allocate) 1612810SN/A e->e_flags |= ELF_F_DIRTY; 1622810SN/A 1632810SN/A if (e->e_cmd == ELF_C_WRITE) 1642810SN/A return (ehdr); 1652810SN/A 1662810SN/A xlator = _libelf_get_translator(ELF_T_EHDR, ELF_TOMEMORY, ec); 1674626SN/A (*xlator)(ehdr, e->e_rawfile, (size_t) 1, 1682810SN/A e->e_byteorder != LIBELF_PRIVATE(byteorder)); 1692810SN/A 1704626SN/A /* 1714626SN/A * If extended numbering is being used, read the correct 1722810SN/A * number of sections and program header entries. 1732810SN/A */ 1742810SN/A if (ec == ELFCLASS32) { 1754626SN/A phnum = ((Elf32_Ehdr *) ehdr)->e_phnum; 1762810SN/A shnum = ((Elf32_Ehdr *) ehdr)->e_shnum; 1772810SN/A shoff = ((Elf32_Ehdr *) ehdr)->e_shoff; 1784626SN/A strndx = ((Elf32_Ehdr *) ehdr)->e_shstrndx; 1794626SN/A } else { 1804626SN/A phnum = ((Elf64_Ehdr *) ehdr)->e_phnum; 1812810SN/A shnum = ((Elf64_Ehdr *) ehdr)->e_shnum; 1822810SN/A shoff = ((Elf64_Ehdr *) ehdr)->e_shoff; 1832810SN/A strndx = ((Elf64_Ehdr *) ehdr)->e_shstrndx; 1842810SN/A } 1852810SN/A 1864666SN/A if (shnum >= SHN_LORESERVE || 1872810SN/A (shoff == 0LL && (shnum != 0 || phnum == PN_XNUM || 1882810SN/A strndx == SHN_XINDEX))) { 1897667Ssteve.reinhardt@amd.com LIBELF_SET_ERROR(HEADER, 0); 1902810SN/A return (NULL); 1912810SN/A } 1924626SN/A 1932810SN/A if (shnum != 0 || shoff == 0LL) { /* not using extended numbering */ 1942810SN/A e->e_u.e_elf.e_nphdr = phnum; 1954626SN/A e->e_u.e_elf.e_nscn = shnum; 1962810SN/A e->e_u.e_elf.e_strndx = strndx; 1972810SN/A } else if (_libelf_load_extended(e, ec, shoff, phnum, strndx) == 0) 1983374SN/A return (NULL); 1992810SN/A 2002982SN/A return (ehdr); 2012810SN/A} 2022812SN/A