elf.c revision 663860b1408516d02ebfcb3a9999a134e6cfb223
1ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 2ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--------------------------------------------------------------------*/ 3ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- User-mode execve() for ELF executables m_ume_elf.c ---*/ 4ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--------------------------------------------------------------------*/ 5ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 6ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* 7ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown This file is part of Valgrind, a dynamic binary instrumentation 8ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown framework. 9ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 10663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng Copyright (C) 2000-2012 Julian Seward 11ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown jseward@acm.org 12ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 13ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown This program is free software; you can redistribute it and/or 14ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown modify it under the terms of the GNU General Public License as 15ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown published by the Free Software Foundation; either version 2 of the 16ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown License, or (at your option) any later version. 17ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 18ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown This program is distributed in the hope that it will be useful, but 19ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown WITHOUT ANY WARRANTY; without even the implied warranty of 20ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 21ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown General Public License for more details. 22ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 23ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown You should have received a copy of the GNU General Public License 24ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown along with this program; if not, write to the Free Software 25ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 26ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 02111-1307, USA. 27ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 28ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown The GNU General Public License is contained in the file COPYING. 29ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/ 30ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 31ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#if defined(VGO_linux) 32ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 33ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_basics.h" 34ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_vki.h" 35ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 36ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_aspacemgr.h" // various mapping fns 37ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_debuglog.h" 38ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_libcassert.h" // VG_(exit), vg_assert 39ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_libcbase.h" // VG_(memcmp), etc 40ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_libcprint.h" 41ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_libcfile.h" // VG_(open) et al 42ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_machine.h" // VG_ELF_CLASS (XXX: which should be moved) 43ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_mallocfree.h" // VG_(malloc), VG_(free) 44ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_syscall.h" // VG_(strerror) 45ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_ume.h" // self 46ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 47ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "priv_ume.h" 48ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 49ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* --- !!! --- EXTERNAL HEADERS start --- !!! --- */ 50ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define _GNU_SOURCE 51ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define _FILE_OFFSET_BITS 64 52ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* This is for ELF types etc, and also the AT_ constants. */ 53ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include <elf.h> 54ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* --- !!! --- EXTERNAL HEADERS end --- !!! --- */ 55ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 56ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 57ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#if VG_WORDSIZE == 8 58ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define ESZ(x) Elf64_##x 59ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#elif VG_WORDSIZE == 4 60ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define ESZ(x) Elf32_##x 61ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#else 62ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#error VG_WORDSIZE needs to ==4 or ==8 63ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#endif 64ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 65ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstruct elfinfo 66ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 67ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ESZ(Ehdr) e; 68ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ESZ(Phdr) *p; 69ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Int fd; 70ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}; 71ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 72ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void check_mmap(SysRes res, Addr base, SizeT len) 73ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 74ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (sr_isError(res)) { 75ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(printf)("valgrind: mmap(0x%llx, %lld) failed in UME " 76ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown "with error %lu (%s).\n", 77ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown (ULong)base, (Long)len, 78ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown sr_Err(res), VG_(strerror)(sr_Err(res)) ); 79ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (sr_Err(res) == VKI_EINVAL) { 80ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(printf)("valgrind: this can be caused by executables with " 81ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown "very large text, data or bss segments.\n"); 82ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 83ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(exit)(1); 84ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 85ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 86ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 87ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/ 88ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- Loading ELF files ---*/ 89ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/ 90ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 91ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic 92ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstruct elfinfo *readelf(Int fd, const char *filename) 93ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 94ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown SysRes sres; 95ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown struct elfinfo *e = VG_(malloc)("ume.re.1", sizeof(*e)); 96ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Int phsz; 97ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 98ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown vg_assert(e); 99ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown e->fd = fd; 100ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 101ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown sres = VG_(pread)(fd, &e->e, sizeof(e->e), 0); 102ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (sr_isError(sres) || sr_Res(sres) != sizeof(e->e)) { 103ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(printf)("valgrind: %s: can't read ELF header: %s\n", 104ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown filename, VG_(strerror)(sr_Err(sres))); 105ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown goto bad; 106ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 107ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 108ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (VG_(memcmp)(&e->e.e_ident[0], ELFMAG, SELFMAG) != 0) { 109ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(printf)("valgrind: %s: bad ELF magic number\n", filename); 110ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown goto bad; 111ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 112ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (e->e.e_ident[EI_CLASS] != VG_ELF_CLASS) { 113ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(printf)("valgrind: wrong ELF executable class " 114ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown "(eg. 32-bit instead of 64-bit)\n"); 115ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown goto bad; 116ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 117ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (e->e.e_ident[EI_DATA] != VG_ELF_DATA2XXX) { 118ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(printf)("valgrind: executable has wrong endian-ness\n"); 119ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown goto bad; 120ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 121ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (!(e->e.e_type == ET_EXEC || e->e.e_type == ET_DYN)) { 122ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(printf)("valgrind: this is not an executable\n"); 123ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown goto bad; 124ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 125ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 126ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (e->e.e_machine != VG_ELF_MACHINE) { 127ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(printf)("valgrind: executable is not for " 128ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown "this architecture\n"); 129ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown goto bad; 130ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 131ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 132ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (e->e.e_phentsize != sizeof(ESZ(Phdr))) { 133ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(printf)("valgrind: sizeof ELF Phdr wrong\n"); 134ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown goto bad; 135ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 136ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 137ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown phsz = sizeof(ESZ(Phdr)) * e->e.e_phnum; 138ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown e->p = VG_(malloc)("ume.re.2", phsz); 139ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown vg_assert(e->p); 140ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 141ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown sres = VG_(pread)(fd, e->p, phsz, e->e.e_phoff); 142ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (sr_isError(sres) || sr_Res(sres) != phsz) { 143ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(printf)("valgrind: can't read phdr: %s\n", 144ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(strerror)(sr_Err(sres))); 145ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(free)(e->p); 146ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown goto bad; 147ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 148ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 149ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return e; 150ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 151ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown bad: 152ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(free)(e); 153ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return NULL; 154ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 155ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 156ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Map an ELF file. Returns the brk address. */ 157ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic 158ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownESZ(Addr) mapelf(struct elfinfo *e, ESZ(Addr) base) 159ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 160ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Int i; 161ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown SysRes res; 162ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ESZ(Addr) elfbrk = 0; 163ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 164ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown for (i = 0; i < e->e.e_phnum; i++) { 165ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ESZ(Phdr) *ph = &e->p[i]; 166ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ESZ(Addr) addr, brkaddr; 167ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ESZ(Word) memsz; 168ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 169ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (ph->p_type != PT_LOAD) 170ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown continue; 171ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 172ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown addr = ph->p_vaddr+base; 173ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown memsz = ph->p_memsz; 174ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown brkaddr = addr+memsz; 175ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 176ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (brkaddr > elfbrk) 177ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown elfbrk = brkaddr; 178ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 179ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 180ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown for (i = 0; i < e->e.e_phnum; i++) { 181ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ESZ(Phdr) *ph = &e->p[i]; 182ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ESZ(Addr) addr, bss, brkaddr; 183ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ESZ(Off) off; 184ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ESZ(Word) filesz; 185ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ESZ(Word) memsz; 186ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown unsigned prot = 0; 187ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 188ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (ph->p_type != PT_LOAD) 189ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown continue; 190ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 191ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (ph->p_flags & PF_X) prot |= VKI_PROT_EXEC; 192ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (ph->p_flags & PF_W) prot |= VKI_PROT_WRITE; 193ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (ph->p_flags & PF_R) prot |= VKI_PROT_READ; 194ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 195ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown addr = ph->p_vaddr+base; 196ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown off = ph->p_offset; 197ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown filesz = ph->p_filesz; 198ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown bss = addr+filesz; 199ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown memsz = ph->p_memsz; 200ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown brkaddr = addr+memsz; 201ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 202ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // Tom says: In the following, do what the Linux kernel does and only 203ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // map the pages that are required instead of rounding everything to 204ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // the specified alignment (ph->p_align). (AMD64 doesn't work if you 205ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // use ph->p_align -- part of stage2's memory gets trashed somehow.) 206ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // 207ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // The condition handles the case of a zero-length segment. 208ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (VG_PGROUNDUP(bss)-VG_PGROUNDDN(addr) > 0) { 209ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (0) VG_(debugLog)(0,"ume","mmap_file_fixed_client #1\n"); 210ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown res = VG_(am_mmap_file_fixed_client)( 211ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_PGROUNDDN(addr), 212ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_PGROUNDUP(bss)-VG_PGROUNDDN(addr), 213ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown prot, /*VKI_MAP_FIXED|VKI_MAP_PRIVATE, */ 214ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown e->fd, VG_PGROUNDDN(off) 215ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ); 216ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (0) VG_(am_show_nsegments)(0,"after #1"); 217ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown check_mmap(res, VG_PGROUNDDN(addr), 218ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_PGROUNDUP(bss)-VG_PGROUNDDN(addr)); 219ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 220ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 221ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // if memsz > filesz, fill the remainder with zeroed pages 222ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (memsz > filesz) { 223ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown UInt bytes; 224ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 225ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown bytes = VG_PGROUNDUP(brkaddr)-VG_PGROUNDUP(bss); 226ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (bytes > 0) { 227ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (0) VG_(debugLog)(0,"ume","mmap_anon_fixed_client #2\n"); 228ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown res = VG_(am_mmap_anon_fixed_client)( 229ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_PGROUNDUP(bss), bytes, 230ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown prot 231ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ); 232ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (0) VG_(am_show_nsegments)(0,"after #2"); 233ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown check_mmap(res, VG_PGROUNDUP(bss), bytes); 234ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 235ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 236ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown bytes = bss & (VKI_PAGE_SIZE - 1); 237ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 238ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // The 'prot' condition allows for a read-only bss 239ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if ((prot & VKI_PROT_WRITE) && (bytes > 0)) { 240ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown bytes = VKI_PAGE_SIZE - bytes; 241ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(memset)((char *)bss, 0, bytes); 242ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 243ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 244ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 245ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 246ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return elfbrk; 247ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 248ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 249ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownBool VG_(match_ELF)(Char *hdr, Int len) 250ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 251ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ESZ(Ehdr) *e = (ESZ(Ehdr) *)hdr; 252ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return (len > sizeof(*e)) && VG_(memcmp)(&e->e_ident[0], ELFMAG, SELFMAG) == 0; 253ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 254ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 255ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 256ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* load_ELF pulls an ELF executable into the address space, prepares 257ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown it for execution, and writes info about it into INFO. In 258ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown particular it fills in .init_eip, which is the starting point. 259ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 260ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Returns zero on success, non-zero (a VKI_E.. value) on failure. 261ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 262ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown The sequence of activities is roughly as follows: 263ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 264ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown - use readelf() to extract program header info from the exe file. 265ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 266ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown - scan the program header, collecting info (not sure what all those 267ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown info-> fields are, or whether they are used, but still) and in 268ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown particular looking out fo the PT_INTERP header, which describes 269ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown the interpreter. If such a field is found, the space needed to 270ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown hold the interpreter is computed into interp_size. 271ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 272ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown - map the executable in, by calling mapelf(). This maps in all 273ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown loadable sections, and I _think_ also creates any .bss areas 274ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown required. mapelf() returns the address just beyond the end of 275ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown the furthest-along mapping it creates. The executable is mapped 276ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown starting at EBASE, which is usually read from it (eg, 0x8048000 277ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown etc) except if it's a PIE, in which case I'm not sure what 278ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown happens. 279ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 280ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown The returned address is recorded in info->brkbase as the start 281ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown point of the brk (data) segment, as it is traditional to place 282ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown the data segment just after the executable. Neither load_ELF nor 283ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown mapelf creates the brk segment, though: that is for the caller of 284ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown load_ELF to attend to. 285ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 286ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown - If the initial phdr scan didn't find any mention of an 287ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown interpreter (interp == NULL), this must be a statically linked 288ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown executable, and we're pretty much done. 289ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 290ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown - Otherwise, we need to use mapelf() a second time to load the 291ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown interpreter. The interpreter can go anywhere, but mapelf() wants 292ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown to be told a specific address to put it at. So an advisory query 293ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown is passed to aspacem, asking where it would put an anonymous 294ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown client mapping of size INTERP_SIZE. That address is then used 295ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown as the mapping address for the interpreter. 296ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 297ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown - The entry point in INFO is set to the interpreter's entry point, 298ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown and we're done. */ 299ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownInt VG_(load_ELF)(Int fd, const HChar* name, /*MOD*/ExeInfo* info) 300ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 301ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown SysRes sres; 302ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown struct elfinfo *e; 303ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown struct elfinfo *interp = NULL; 304ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ESZ(Addr) minaddr = ~0; /* lowest mapped address */ 305ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ESZ(Addr) maxaddr = 0; /* highest mapped address */ 306ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ESZ(Addr) interp_addr = 0; /* interpreter (ld.so) address */ 307ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ESZ(Word) interp_size = 0; /* interpreter size */ 308b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov /* ESZ(Word) interp_align = VKI_PAGE_SIZE; */ /* UNUSED */ 309ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Int i; 310ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown void *entry; 311ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ESZ(Addr) ebase = 0; 312ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 313ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* The difference between where the interpreter got mapped and 314ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown where it asked to be mapped. Needed for computing the ppc64 ELF 315ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown entry point and initial tocptr (R2) value. */ 316ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ESZ(Word) interp_offset = 0; 317ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 318ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#ifdef HAVE_PIE 319ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ebase = info->exe_base; 320ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#endif 321ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 322ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown e = readelf(fd, name); 323ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 324ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (e == NULL) 325ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return VKI_ENOEXEC; 326ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 327ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* The kernel maps position-independent executables at TASK_SIZE*2/3; 328ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown duplicate this behavior as close as we can. */ 329ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (e->e.e_type == ET_DYN && ebase == 0) { 330ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ebase = VG_PGROUNDDN(info->exe_base 331ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown + (info->exe_end - info->exe_base) * 2 / 3); 332ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* We really don't want to load PIEs at zero or too close. It 333ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown works, but it's unrobust (NULL pointer reads and writes 334ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown become legit, which is really bad) and causes problems for 335ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown exp-ptrcheck, which assumes all numbers below 1MB are 336ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown nonpointers. So, hackily, move it above 1MB. */ 337ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* Later .. is appears ppc32-linux tries to put [vdso] at 1MB, 338ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown which totally screws things up, because nothing else can go 339ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown there. So bump the hacky load addess along by 0x8000, to 340ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 0x108000. */ 341ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (ebase < 0x108000) 342ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ebase = 0x108000; 343ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 344ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 345ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown info->phnum = e->e.e_phnum; 346ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown info->entry = e->e.e_entry + ebase; 347ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown info->phdr = 0; 348ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 349ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown for (i = 0; i < e->e.e_phnum; i++) { 350ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ESZ(Phdr) *ph = &e->p[i]; 351ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 352ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown switch(ph->p_type) { 353ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown case PT_PHDR: 354ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown info->phdr = ph->p_vaddr + ebase; 355ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown break; 356ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 357ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown case PT_LOAD: 358ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (ph->p_vaddr < minaddr) 359ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown minaddr = ph->p_vaddr; 360ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (ph->p_vaddr+ph->p_memsz > maxaddr) 361ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown maxaddr = ph->p_vaddr+ph->p_memsz; 362ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown break; 363ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 364ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown case PT_INTERP: { 365ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown HChar *buf = VG_(malloc)("ume.LE.1", ph->p_filesz+1); 366ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Int j; 367ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Int intfd; 368ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Int baseaddr_set; 369ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 370ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown vg_assert(buf); 371ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(pread)(fd, buf, ph->p_filesz, ph->p_offset); 372ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown buf[ph->p_filesz] = '\0'; 373ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 374ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown sres = VG_(open)(buf, VKI_O_RDONLY, 0); 375ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (sr_isError(sres)) { 376ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(printf)("valgrind: m_ume.c: can't open interpreter\n"); 377ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(exit)(1); 378ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 379ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown intfd = sr_Res(sres); 380ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 381ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown interp = readelf(intfd, buf); 382ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (interp == NULL) { 383ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(printf)("valgrind: m_ume.c: can't read interpreter\n"); 384ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return 1; 385ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 386ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(free)(buf); 387ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 388ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown baseaddr_set = 0; 389ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown for (j = 0; j < interp->e.e_phnum; j++) { 390ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ESZ(Phdr) *iph = &interp->p[j]; 391ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ESZ(Addr) end; 392ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 393b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov if (iph->p_type != PT_LOAD || iph->p_memsz == 0) 394ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown continue; 395ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 396ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (!baseaddr_set) { 397ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown interp_addr = iph->p_vaddr; 398b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov /* interp_align = iph->p_align; */ /* UNUSED */ 399ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown baseaddr_set = 1; 400ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 401ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 402ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* assumes that all segments in the interp are close */ 403ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown end = (iph->p_vaddr - interp_addr) + iph->p_memsz; 404ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 405ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (end > interp_size) 406ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown interp_size = end; 407ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 408ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown break; 409ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 410ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown default: 411ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // do nothing 412ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown break; 413ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 414ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 415ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 416ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 417ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (info->phdr == 0) 418ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown info->phdr = minaddr + ebase + e->e.e_phoff; 419ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 420ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (info->exe_base != info->exe_end) { 421ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (minaddr >= maxaddr || 422ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown (minaddr + ebase < info->exe_base || 423ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown maxaddr + ebase > info->exe_end)) { 424ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(printf)("Executable range %p-%p is outside the\n" 425ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown "acceptable range %p-%p\n", 426ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown (char *)minaddr + ebase, (char *)maxaddr + ebase, 427ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown (char *)info->exe_base, (char *)info->exe_end); 428ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return VKI_ENOMEM; 429ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 430ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 431ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 432ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown info->brkbase = mapelf(e, ebase); /* map the executable */ 433ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 434ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (info->brkbase == 0) 435ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return VKI_ENOMEM; 436ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 437ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (interp != NULL) { 438ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* reserve a chunk of address space for interpreter */ 439ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown MapRequest mreq; 440ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Addr advised; 441ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Bool ok; 442ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 443ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* Don't actually reserve the space. Just get an advisory 444ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown indicating where it would be allocated, and pass that to 445ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown mapelf(), which in turn asks aspacem to do some fixed maps at 446ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown the specified address. This is a bit of hack, but it should 447ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown work because there should be no intervening transactions with 448ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown aspacem which could cause those fixed maps to fail. 449ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 450ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Placement policy is: 451ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 452ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if the interpreter asks to be loaded at zero 453ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ignore that and put it wherever we like (mappings at zero 454ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown are bad news) 455ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown else 456ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown try and put it where it asks for, but if that doesn't work, 457ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown just put it anywhere. 458ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown */ 459ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (interp_addr == 0) { 460ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown mreq.rkind = MAny; 461ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown mreq.start = 0; 462ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown mreq.len = interp_size; 463ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } else { 464ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown mreq.rkind = MHint; 465ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown mreq.start = interp_addr; 466ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown mreq.len = interp_size; 467ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 468ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 469ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown advised = VG_(am_get_advisory)( &mreq, True/*client*/, &ok ); 470ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 471ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (!ok) { 472ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* bomb out */ 473ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown SysRes res = VG_(mk_SysRes_Error)(VKI_EINVAL); 474ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (0) VG_(printf)("reserve for interp: failed\n"); 475ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown check_mmap(res, (Addr)interp_addr, interp_size); 476ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /*NOTREACHED*/ 477ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 478ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 479ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown (void)mapelf(interp, (ESZ(Addr))advised - interp_addr); 480ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 481ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(close)(interp->fd); 482ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 483ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown entry = (void *)(advised - interp_addr + interp->e.e_entry); 484ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown info->interp_base = (ESZ(Addr))advised; 485ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown interp_offset = advised - interp_addr; 486ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 487ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(free)(interp->p); 488ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(free)(interp); 489663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng } else 490ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown entry = (void *)(ebase + e->e.e_entry); 491ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 492ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown info->exe_base = minaddr + ebase; 493ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown info->exe_end = maxaddr + ebase; 494ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 495ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#if defined(VGP_ppc64_linux) 496ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* On PPC64, a func ptr is represented by a TOC entry ptr. This 497ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown TOC entry contains three words; the first word is the function 498ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown address, the second word is the TOC ptr (r2), and the third word 499ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown is the static chain value. */ 500ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown info->init_ip = ((ULong*)entry)[0]; 501ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown info->init_toc = ((ULong*)entry)[1]; 502ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown info->init_ip += interp_offset; 503ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown info->init_toc += interp_offset; 504ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#else 505ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown info->init_ip = (Addr)entry; 506ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown info->init_toc = 0; /* meaningless on this platform */ 507b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov (void) interp_offset; /* stop gcc complaining it is unused */ 508ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#endif 509ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(free)(e->p); 510ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(free)(e); 511ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 512ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return 0; 513ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 514ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 515ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#endif // defined(VGO_linux) 516ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 517ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--------------------------------------------------------------------*/ 518ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- end ---*/ 519ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--------------------------------------------------------------------*/ 520