1cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng/* Reconstruct an ELF file by reading the segments out of remote memory. 2cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng Copyright (C) 2005, 2006, 2007 Red Hat, Inc. 3cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng This file is part of Red Hat elfutils. 4cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 5cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng Red Hat elfutils is free software; you can redistribute it and/or modify 6cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng it under the terms of the GNU General Public License as published by the 7cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng Free Software Foundation; version 2 of the License. 8cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 9cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng Red Hat elfutils is distributed in the hope that it will be useful, but 10cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng WITHOUT ANY WARRANTY; without even the implied warranty of 11cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng General Public License for more details. 13cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 14cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng You should have received a copy of the GNU General Public License along 15cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng with Red Hat elfutils; if not, write to the Free Software Foundation, 16cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA. 17cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 18cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng In addition, as a special exception, Red Hat, Inc. gives You the 19cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng additional right to link the code of Red Hat elfutils with code licensed 20cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng under any Open Source Initiative certified open source license 21cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng (http://www.opensource.org/licenses/index.php) which requires the 22cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng distribution of source code with any binary distribution and to 23cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng distribute linked combinations of the two. Non-GPL Code permitted under 24cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng this exception must only link to the code of Red Hat elfutils through 25cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng those well defined interfaces identified in the file named EXCEPTION 26cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng found in the source code files (the "Approved Interfaces"). The files 27cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng of Non-GPL Code may instantiate templates or use macros or inline 28cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng functions from the Approved Interfaces without causing the resulting 29cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng work to be covered by the GNU General Public License. Only Red Hat, 30cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng Inc. may make changes or additions to the list of Approved Interfaces. 31cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng Red Hat's grant of this exception is conditioned upon your not adding 32cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng any new exceptions. If you wish to add a new Approved Interface or 33cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng exception, please contact Red Hat. You must obey the GNU General Public 34cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng License in all respects for all of the Red Hat elfutils code and other 35cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng code used in conjunction with Red Hat elfutils except the Non-GPL Code 36cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng covered by this exception. If you modify this file, you may extend this 37cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng exception to your version of the file, but you are not obligated to do 38cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng so. If you do not wish to provide this exception without modification, 39cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng you must delete this exception statement from your version and license 40cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng this file solely under the GPL without exception. 41cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 42cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng Red Hat elfutils is an included package of the Open Invention Network. 43cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng An included package of the Open Invention Network is a package for which 44cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng Open Invention Network licensees cross-license their patents. No patent 45cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng license is granted, either expressly or impliedly, by designation as an 46cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng included package. Should you wish to participate in the Open Invention 47cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng Network licensing program, please visit www.openinventionnetwork.com 48cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng <http://www.openinventionnetwork.com>. */ 49cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 50cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng#include <config.h> 51cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng#include "../libelf/libelfP.h" 52cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng#undef _ 53cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 54cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng#include "libdwflP.h" 55cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 56cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng#include <gelf.h> 57cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng#include <sys/types.h> 58cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng#include <stdbool.h> 59cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng#include <stdlib.h> 60cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng#include <string.h> 61cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 62cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng/* Reconstruct an ELF file by reading the segments out of remote memory 63cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng based on the ELF file header at EHDR_VMA and the ELF program headers it 64cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng points to. If not null, *LOADBASEP is filled in with the difference 65cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng between the addresses from which the segments were read, and the 66cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng addresses the file headers put them at. 67cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 68cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng The function READ_MEMORY is called to copy at least MINREAD and at most 69cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng MAXREAD bytes from the remote memory at target address ADDRESS into the 70cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng local buffer at DATA; it should return -1 for errors (with code in 71cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng `errno'), 0 if it failed to read at least MINREAD bytes due to EOF, or 72cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng the number of bytes read if >= MINREAD. ARG is passed through. */ 73cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 74cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben ChengElf * 75cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengelf_from_remote_memory (GElf_Addr ehdr_vma, 76cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng GElf_Addr *loadbasep, 77cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng ssize_t (*read_memory) (void *arg, void *data, 78cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng GElf_Addr address, 79cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng size_t minread, 80cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng size_t maxread), 81cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng void *arg) 82cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng{ 83cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng /* First read in the file header and check its sanity. */ 84cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 85cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng const size_t initial_bufsize = 256; 86cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng unsigned char *buffer = malloc (initial_bufsize); 87cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng if (buffer == NULL) 88cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng { 89cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng no_memory: 90cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng __libdwfl_seterrno (DWFL_E_NOMEM); 91cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng return NULL; 92cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng } 93cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 94cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng ssize_t nread = (*read_memory) (arg, buffer, ehdr_vma, 95cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng sizeof (Elf32_Ehdr), initial_bufsize); 96cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng if (nread <= 0) 97cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng { 98cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng read_error: 99cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng free (buffer); 100cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng __libdwfl_seterrno (nread < 0 ? DWFL_E_ERRNO : DWFL_E_TRUNCATED); 101cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng return NULL; 102cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng } 103cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 104cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng if (memcmp (buffer, ELFMAG, SELFMAG) != 0) 105cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng { 106cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng bad_elf: 107cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng __libdwfl_seterrno (DWFL_E_BADELF); 108cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng return NULL; 109cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng } 110cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 111cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng /* Extract the information we need from the file header. */ 112cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 113cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng union 114cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng { 115cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng Elf32_Ehdr e32; 116cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng Elf64_Ehdr e64; 117cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng } ehdr; 118cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng Elf_Data xlatefrom = 119cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng { 120cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng .d_type = ELF_T_EHDR, 121cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng .d_buf = buffer, 122cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng .d_version = EV_CURRENT, 123cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng }; 124cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng Elf_Data xlateto = 125cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng { 126cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng .d_type = ELF_T_EHDR, 127cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng .d_buf = &ehdr, 128cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng .d_size = sizeof ehdr, 129cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng .d_version = EV_CURRENT, 130cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng }; 131cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 132cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng GElf_Off phoff; 133cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng uint_fast16_t phnum; 134cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng uint_fast16_t phentsize; 135cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng GElf_Off shdrs_end; 136cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 137cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng switch (buffer[EI_CLASS]) 138cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng { 139cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng case ELFCLASS32: 140cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng xlatefrom.d_size = sizeof (Elf32_Ehdr); 141cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng if (elf32_xlatetom (&xlateto, &xlatefrom, buffer[EI_DATA]) == NULL) 142cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng { 143cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng libelf_error: 144cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng __libdwfl_seterrno (DWFL_E_LIBELF); 145cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng return NULL; 146cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng } 147cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng phoff = ehdr.e32.e_phoff; 148cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng phnum = ehdr.e32.e_phnum; 149cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng phentsize = ehdr.e32.e_phentsize; 150cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng if (phentsize != sizeof (Elf32_Phdr) || phnum == 0) 151cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng goto bad_elf; 152cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng shdrs_end = ehdr.e32.e_shoff + ehdr.e32.e_shnum * ehdr.e32.e_shentsize; 153cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng break; 154cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 155cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng case ELFCLASS64: 156cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng xlatefrom.d_size = sizeof (Elf64_Ehdr); 157cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng if (elf64_xlatetom (&xlateto, &xlatefrom, buffer[EI_DATA]) == NULL) 158cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng goto libelf_error; 159cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng phoff = ehdr.e64.e_phoff; 160cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng phnum = ehdr.e64.e_phnum; 161cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng phentsize = ehdr.e64.e_phentsize; 162cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng if (phentsize != sizeof (Elf64_Phdr) || phnum == 0) 163cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng goto bad_elf; 164cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng shdrs_end = ehdr.e64.e_shoff + ehdr.e64.e_shnum * ehdr.e64.e_shentsize; 165cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng break; 166cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 167cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng default: 168cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng goto bad_elf; 169cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng } 170cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 171cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 172cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng /* The file header tells where to find the program headers. 173cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng These are what we use to actually choose what to read. */ 174cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 175cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng xlatefrom.d_type = xlateto.d_type = ELF_T_PHDR; 176cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng xlatefrom.d_size = phnum * phentsize; 177cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 178cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng if ((size_t) nread >= phoff + phnum * phentsize) 179cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng /* We already have all the phdrs from the initial read. */ 180cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng xlatefrom.d_buf = buffer + phoff; 181cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng else 182cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng { 183cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng /* Read in the program headers. */ 184cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 185cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng if (initial_bufsize < phnum * phentsize) 186cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng { 187cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng unsigned char *newbuf = realloc (buffer, phnum * phentsize); 188cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng if (newbuf == NULL) 189cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng { 190cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng free (buffer); 191cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng goto no_memory; 192cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng } 193cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng buffer = newbuf; 194cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng } 195cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng nread = (*read_memory) (arg, buffer, ehdr_vma + phoff, 196cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng phnum * phentsize, phnum * phentsize); 197cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng if (nread <= 0) 198cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng goto read_error; 199cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 200cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng xlatefrom.d_buf = buffer; 201cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng } 202cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 203cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng union 204cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng { 205cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng Elf32_Phdr p32[phnum]; 206cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng Elf64_Phdr p64[phnum]; 207cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng } phdrs; 208cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 209cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng xlateto.d_buf = &phdrs; 210cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng xlateto.d_size = sizeof phdrs; 211cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 212cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng /* Scan for PT_LOAD segments to find the total size of the file image. */ 213cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng size_t contents_size = 0; 214cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng GElf_Off segments_end = 0; 215cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng GElf_Addr loadbase = ehdr_vma; 216cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng bool found_base = false; 217cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng switch (ehdr.e32.e_ident[EI_CLASS]) 218cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng { 219cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng inline void handle_segment (GElf_Addr vaddr, GElf_Off offset, 220cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng GElf_Xword filesz, GElf_Xword align) 221cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng { 222cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng GElf_Off segment_end = ((offset + filesz + align - 1) & -align); 223cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 224cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng if (segment_end > (GElf_Off) contents_size) 225cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng contents_size = segment_end; 226cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 227cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng if (!found_base && (offset & -align) == 0) 228cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng { 229cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng loadbase = ehdr_vma - (vaddr & -align); 230cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng found_base = true; 231cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng } 232cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 233cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng segments_end = offset + filesz; 234cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng } 235cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 236cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng case ELFCLASS32: 237cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng if (elf32_xlatetom (&xlateto, &xlatefrom, 238cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng ehdr.e32.e_ident[EI_DATA]) == NULL) 239cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng goto libelf_error; 240cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng for (uint_fast16_t i = 0; i < phnum; ++i) 241cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng if (phdrs.p32[i].p_type == PT_LOAD) 242cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng handle_segment (phdrs.p32[i].p_vaddr, phdrs.p32[i].p_offset, 243cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng phdrs.p32[i].p_filesz, phdrs.p32[i].p_align); 244cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng break; 245cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 246cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng case ELFCLASS64: 247cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng if (elf32_xlatetom (&xlateto, &xlatefrom, 248cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng ehdr.e32.e_ident[EI_DATA]) == NULL) 249cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng goto libelf_error; 250cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng for (uint_fast16_t i = 0; i < phnum; ++i) 251cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng if (phdrs.p32[i].p_type == PT_LOAD) 252cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng handle_segment (phdrs.p64[i].p_vaddr, phdrs.p64[i].p_offset, 253cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng phdrs.p64[i].p_filesz, phdrs.p64[i].p_align); 254cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng break; 255cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 256cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng default: 257cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng abort (); 258cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng break; 259cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng } 260cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 261cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng /* Trim the last segment so we don't bother with zeros in the last page 262cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng that are off the end of the file. However, if the extra bit in that 263cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng page includes the section headers, keep them. */ 264cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng if ((GElf_Off) contents_size > segments_end 265cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng && (GElf_Off) contents_size >= shdrs_end) 266cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng { 267cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng contents_size = segments_end; 268cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng if ((GElf_Off) contents_size < shdrs_end) 269cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng contents_size = shdrs_end; 270cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng } 271cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng else 272cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng contents_size = segments_end; 273cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 274cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng free (buffer); 275cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 276cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng /* Now we know the size of the whole image we want read in. */ 277cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng buffer = calloc (1, contents_size); 278cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng if (buffer == NULL) 279cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng goto no_memory; 280cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 281cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng switch (ehdr.e32.e_ident[EI_CLASS]) 282cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng { 283cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng inline bool handle_segment (GElf_Addr vaddr, GElf_Off offset, 284cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng GElf_Xword filesz, GElf_Xword align) 285cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng { 286cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng GElf_Off start = offset & -align; 287cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng GElf_Off end = (offset + filesz + align - 1) & -align; 288cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng if (end > (GElf_Off) contents_size) 289cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng end = contents_size; 290cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng nread = (*read_memory) (arg, buffer + start, 291cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng (loadbase + vaddr) & -align, 292cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng end - start, end - start); 293cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng return nread <= 0; 294cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng } 295cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 296cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng case ELFCLASS32: 297cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng for (uint_fast16_t i = 0; i < phnum; ++i) 298cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng if (phdrs.p32[i].p_type == PT_LOAD) 299cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng if (handle_segment (phdrs.p32[i].p_vaddr, phdrs.p32[i].p_offset, 300cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng phdrs.p32[i].p_filesz, phdrs.p32[i].p_align)) 301cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng goto read_error; 302cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 303cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng /* If the segments visible in memory didn't include the section 304cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng headers, then clear them from the file header. */ 305cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng if (contents_size < shdrs_end) 306cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng { 307cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng ehdr.e32.e_shoff = 0; 308cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng ehdr.e32.e_shnum = 0; 309cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng ehdr.e32.e_shstrndx = 0; 310cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng } 311cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 312cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng /* This will normally have been in the first PT_LOAD segment. But it 313cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng conceivably could be missing, and we might have just changed it. */ 314cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng xlatefrom.d_type = xlateto.d_type = ELF_T_EHDR; 315cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng xlatefrom.d_size = xlateto.d_size = sizeof ehdr.e32; 316cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng xlatefrom.d_buf = &ehdr.e32; 317cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng xlateto.d_buf = buffer; 318cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng if (elf32_xlatetof (&xlateto, &xlatefrom, 319cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng ehdr.e32.e_ident[EI_DATA]) == NULL) 320cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng goto libelf_error; 321cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng break; 322cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 323cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng case ELFCLASS64: 324cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng for (uint_fast16_t i = 0; i < phnum; ++i) 325cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng if (phdrs.p32[i].p_type == PT_LOAD) 326cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng if (handle_segment (phdrs.p64[i].p_vaddr, phdrs.p64[i].p_offset, 327cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng phdrs.p64[i].p_filesz, phdrs.p64[i].p_align)) 328cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng goto read_error; 329cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 330cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng /* If the segments visible in memory didn't include the section 331cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng headers, then clear them from the file header. */ 332cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng if (contents_size < shdrs_end) 333cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng { 334cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng ehdr.e64.e_shoff = 0; 335cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng ehdr.e64.e_shnum = 0; 336cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng ehdr.e64.e_shstrndx = 0; 337cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng } 338cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 339cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng /* This will normally have been in the first PT_LOAD segment. But it 340cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng conceivably could be missing, and we might have just changed it. */ 341cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng xlatefrom.d_type = xlateto.d_type = ELF_T_EHDR; 342cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng xlatefrom.d_size = xlateto.d_size = sizeof ehdr.e64; 343cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng xlatefrom.d_buf = &ehdr.e64; 344cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng xlateto.d_buf = buffer; 345cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng if (elf64_xlatetof (&xlateto, &xlatefrom, 346cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng ehdr.e64.e_ident[EI_DATA]) == NULL) 347cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng goto libelf_error; 348cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng break; 349cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 350cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng default: 351cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng abort (); 352cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng break; 353cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng } 354cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 355cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng /* Now we have the image. Open libelf on it. */ 356cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 357cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng Elf *elf = elf_memory ((char *) buffer, contents_size); 358cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng if (elf == NULL) 359cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng { 360cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng free (buffer); 361cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng goto libelf_error; 362cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng } 363cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 364cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng elf->flags |= ELF_F_MALLOCED; 365cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng if (loadbasep != NULL) 366cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng *loadbasep = loadbase; 367cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng return elf; 368cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng} 369