1441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project/* Create descriptor for processing file. 2cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng Copyright (C) 1998-2005, 2006, 2007, 2008 Red Hat, Inc. 3cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng This file is part of Red Hat elfutils. 4441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project Written by Ulrich Drepper <drepper@redhat.com>, 1998. 5441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project 6cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng Red Hat elfutils is free software; you can redistribute it and/or modify 7cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng it under the terms of the GNU General Public License as published by the 8cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng Free Software Foundation; version 2 of the License. 9cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 10cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng Red Hat elfutils is distributed in the hope that it will be useful, but 11cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng WITHOUT ANY WARRANTY; without even the implied warranty of 12cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng General Public License for more details. 14cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 15cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng You should have received a copy of the GNU General Public License along 16cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng with Red Hat elfutils; if not, write to the Free Software Foundation, 17cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA. 18cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 19cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng In addition, as a special exception, Red Hat, Inc. gives You the 20cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng additional right to link the code of Red Hat elfutils with code licensed 21cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng under any Open Source Initiative certified open source license 22cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng (http://www.opensource.org/licenses/index.php) which requires the 23cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng distribution of source code with any binary distribution and to 24cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng distribute linked combinations of the two. Non-GPL Code permitted under 25cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng this exception must only link to the code of Red Hat elfutils through 26cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng those well defined interfaces identified in the file named EXCEPTION 27cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng found in the source code files (the "Approved Interfaces"). The files 28cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng of Non-GPL Code may instantiate templates or use macros or inline 29cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng functions from the Approved Interfaces without causing the resulting 30cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng work to be covered by the GNU General Public License. Only Red Hat, 31cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng Inc. may make changes or additions to the list of Approved Interfaces. 32cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng Red Hat's grant of this exception is conditioned upon your not adding 33cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng any new exceptions. If you wish to add a new Approved Interface or 34cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng exception, please contact Red Hat. You must obey the GNU General Public 35cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng License in all respects for all of the Red Hat elfutils code and other 36cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng code used in conjunction with Red Hat elfutils except the Non-GPL Code 37cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng covered by this exception. If you modify this file, you may extend this 38cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng exception to your version of the file, but you are not obligated to do 39cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng so. If you do not wish to provide this exception without modification, 40cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng you must delete this exception statement from your version and license 41cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng this file solely under the GPL without exception. 42cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 43cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng Red Hat elfutils is an included package of the Open Invention Network. 44cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng An included package of the Open Invention Network is a package for which 45cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng Open Invention Network licensees cross-license their patents. No patent 46cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng license is granted, either expressly or impliedly, by designation as an 47cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng included package. Should you wish to participate in the Open Invention 48cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng Network licensing program, please visit www.openinventionnetwork.com 49cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng <http://www.openinventionnetwork.com>. */ 50441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project 51441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project#ifdef HAVE_CONFIG_H 52441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project# include <config.h> 53441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project#endif 54441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project 55441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project#include <assert.h> 56441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project#include <ctype.h> 57441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project#include <errno.h> 58441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project#include <fcntl.h> 59441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project#include <stdbool.h> 60441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project#include <stddef.h> 61441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project#include <string.h> 62441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project#include <unistd.h> 63441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project#include <sys/mman.h> 64441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project#include <sys/param.h> 65441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project#include <sys/stat.h> 66441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project 67cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng#include <system.h> 68441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project#include "libelfP.h" 69441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project#include "common.h" 70441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project 71441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project/* Create descriptor for archive in memory. */ 72441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectstatic inline Elf * 73441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectfile_read_ar (int fildes, void *map_address, off_t offset, size_t maxsize, 74441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project Elf_Cmd cmd, Elf *parent) 75441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project{ 76441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project Elf *elf; 77441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project 78441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project /* Create a descriptor. */ 79441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project elf = allocate_elf (fildes, map_address, offset, maxsize, cmd, parent, 80441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project ELF_K_AR, 0); 81441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project if (elf != NULL) 82441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project { 83441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project /* We don't read all the symbol tables in advance. All this will 84441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project happen on demand. */ 85441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project elf->state.ar.offset = offset + SARMAG; 86441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project 87441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project elf->state.ar.elf_ar_hdr.ar_rawname = elf->state.ar.raw_name; 88441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project } 89441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project 90441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project return elf; 91441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project} 92441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project 93441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project 94441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectstatic size_t 95441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectget_shnum (void *map_address, unsigned char *e_ident, int fildes, off_t offset, 96441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project size_t maxsize) 97441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project{ 98441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project size_t result; 99441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project union 100441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project { 101441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project Elf32_Ehdr *e32; 102441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project Elf64_Ehdr *e64; 103441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project void *p; 104441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project } ehdr; 105cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng union 106cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng { 107cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng Elf32_Ehdr e32; 108cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng Elf64_Ehdr e64; 109cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng } ehdr_mem; 110441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project bool is32 = e_ident[EI_CLASS] == ELFCLASS32; 111441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project 112441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project /* Make the ELF header available. */ 113cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng if (e_ident[EI_DATA] == MY_ELFDATA 114441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project && (ALLOW_UNALIGNED 115cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng || (((size_t) e_ident 116cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng & ((is32 ? __alignof__ (Elf32_Ehdr) : __alignof__ (Elf64_Ehdr)) 117cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng - 1)) == 0))) 118cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng ehdr.p = e_ident; 119441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project else 120441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project { 121cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng /* We already read the ELF header. We have to copy the header 122cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng since we possibly modify the data here and the caller 123cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng expects the memory it passes in to be preserved. */ 124cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng ehdr.p = &ehdr_mem; 125441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project 126cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng if (is32) 127cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng { 128cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng if (ALLOW_UNALIGNED) 129cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng { 130cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng ehdr_mem.e32.e_shnum = ((Elf32_Ehdr *) e_ident)->e_shnum; 131cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng ehdr_mem.e32.e_shoff = ((Elf32_Ehdr *) e_ident)->e_shoff; 132cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng } 133cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng else 134cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng memcpy (&ehdr_mem, e_ident, sizeof (Elf32_Ehdr)); 135441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project 136cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng if (e_ident[EI_DATA] != MY_ELFDATA) 137cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng { 138cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng CONVERT (ehdr_mem.e32.e_shnum); 139cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng CONVERT (ehdr_mem.e32.e_shoff); 140cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng } 141cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng } 142cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng else 143441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project { 144cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng if (ALLOW_UNALIGNED) 145441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project { 146cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng ehdr_mem.e64.e_shnum = ((Elf64_Ehdr *) e_ident)->e_shnum; 147cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng ehdr_mem.e64.e_shoff = ((Elf64_Ehdr *) e_ident)->e_shoff; 148441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project } 149441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project else 150cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng memcpy (&ehdr_mem, e_ident, sizeof (Elf64_Ehdr)); 151cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 152cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng if (e_ident[EI_DATA] != MY_ELFDATA) 153441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project { 154cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng CONVERT (ehdr_mem.e64.e_shnum); 155cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng CONVERT (ehdr_mem.e64.e_shoff); 156441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project } 157441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project } 158441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project } 159441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project 160441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project if (is32) 161441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project { 162441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project /* Get the number of sections from the ELF header. */ 163441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project result = ehdr.e32->e_shnum; 164441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project 165441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project if (unlikely (result == 0) && ehdr.e32->e_shoff != 0) 166441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project { 167cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng if (ehdr.e32->e_shoff + sizeof (Elf32_Shdr) > maxsize) 168441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project /* Cannot read the first section header. */ 169cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng return 0; 170441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project 171441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project if (likely (map_address != NULL) && e_ident[EI_DATA] == MY_ELFDATA 172441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project && (ALLOW_UNALIGNED 173441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project || (((size_t) ((char *) map_address + offset)) 174441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project & (__alignof__ (Elf32_Ehdr) - 1)) == 0)) 175441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project /* We can directly access the memory. */ 176cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng result = ((Elf32_Shdr *) ((char *) map_address + ehdr.e32->e_shoff 177441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project + offset))->sh_size; 178441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project else 179441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project { 180441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project Elf32_Word size; 181441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project 182cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng if (likely (map_address != NULL)) 183cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng /* gcc will optimize the memcpy to a simple memory 184cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng access while taking care of alignment issues. */ 185cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng memcpy (&size, &((Elf32_Shdr *) ((char *) map_address 186cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng + ehdr.e32->e_shoff 187cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng + offset))->sh_size, 188cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng sizeof (Elf32_Word)); 189cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng else 190cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng if (unlikely (pread_retry (fildes, &size, sizeof (Elf32_Word), 191cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng offset + ehdr.e32->e_shoff 192cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng + offsetof (Elf32_Shdr, sh_size)) 193cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng != sizeof (Elf32_Word))) 194cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng return (size_t) -1l; 195441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project 196441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project if (e_ident[EI_DATA] != MY_ELFDATA) 197441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project CONVERT (size); 198441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project 199441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project result = size; 200441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project } 201441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project } 202cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 203cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng /* If the section headers were truncated, pretend none were there. */ 204cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng if (ehdr.e32->e_shoff > maxsize 205cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng || maxsize - ehdr.e32->e_shoff < sizeof (Elf32_Shdr) * result) 206cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng result = 0; 207441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project } 208441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project else 209441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project { 210441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project /* Get the number of sections from the ELF header. */ 211441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project result = ehdr.e64->e_shnum; 212441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project 213441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project if (unlikely (result == 0) && ehdr.e64->e_shoff != 0) 214441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project { 215cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng if (ehdr.e64->e_shoff + sizeof (Elf64_Shdr) > maxsize) 216441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project /* Cannot read the first section header. */ 217cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng return 0; 218441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project 219cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng Elf64_Xword size; 220441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project if (likely (map_address != NULL) && e_ident[EI_DATA] == MY_ELFDATA 221441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project && (ALLOW_UNALIGNED 222441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project || (((size_t) ((char *) map_address + offset)) 223441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project & (__alignof__ (Elf64_Ehdr) - 1)) == 0)) 224441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project /* We can directly access the memory. */ 225cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng size = ((Elf64_Shdr *) ((char *) map_address + ehdr.e64->e_shoff 226cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng + offset))->sh_size; 227441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project else 228441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project { 229cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng if (likely (map_address != NULL)) 230cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng /* gcc will optimize the memcpy to a simple memory 231cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng access while taking care of alignment issues. */ 232cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng memcpy (&size, &((Elf64_Shdr *) ((char *) map_address 233cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng + ehdr.e64->e_shoff 234cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng + offset))->sh_size, 235cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng sizeof (Elf64_Xword)); 236cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng else 237cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng if (unlikely (pread_retry (fildes, &size, sizeof (Elf64_Word), 238cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng offset + ehdr.e64->e_shoff 239cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng + offsetof (Elf64_Shdr, sh_size)) 240cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng != sizeof (Elf64_Xword))) 241cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng return (size_t) -1l; 242441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project 243441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project if (e_ident[EI_DATA] != MY_ELFDATA) 244441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project CONVERT (size); 245441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project } 246cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 247cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng if (size > ~((GElf_Word) 0)) 248cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng /* Invalid value, it is too large. */ 249cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng return (size_t) -1l; 250cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 251cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng result = size; 252441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project } 253cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 254cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng /* If the section headers were truncated, pretend none were there. */ 255cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng if (ehdr.e64->e_shoff > maxsize 256cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng || maxsize - ehdr.e64->e_shoff < sizeof (Elf64_Shdr) * result) 257cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng result = 0; 258441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project } 259441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project 260441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project return result; 261441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project} 262441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project 263441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project 264441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project/* Create descriptor for ELF file in memory. */ 265441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectstatic Elf * 266cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengfile_read_elf (int fildes, void *map_address, unsigned char *e_ident, 267cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng off_t offset, size_t maxsize, Elf_Cmd cmd, Elf *parent) 268441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project{ 269441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project /* Verify the binary is of the class we can handle. */ 270cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng if (unlikely ((e_ident[EI_CLASS] != ELFCLASS32 271cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng && e_ident[EI_CLASS] != ELFCLASS64) 272cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng /* We also can only handle two encodings. */ 273cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng || (e_ident[EI_DATA] != ELFDATA2LSB 274cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng && e_ident[EI_DATA] != ELFDATA2MSB))) 275441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project { 276441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project /* Cannot handle this. */ 277441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project __libelf_seterrno (ELF_E_INVALID_FILE); 278441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project return NULL; 279441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project } 280441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project 281441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project /* Determine the number of sections. */ 282cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng size_t scncnt = get_shnum (map_address, e_ident, fildes, offset, maxsize); 283441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project if (scncnt == (size_t) -1l) 284441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project /* Could not determine the number of sections. */ 285441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project return NULL; 286441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project 287441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project /* We can now allocate the memory. */ 288cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng Elf *elf = allocate_elf (fildes, map_address, offset, maxsize, cmd, parent, 289cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng ELF_K_ELF, scncnt * sizeof (Elf_Scn)); 290441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project if (elf == NULL) 291441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project /* Not enough memory. */ 292441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project return NULL; 293441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project 294441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project /* Some more or less arbitrary value. */ 295441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project elf->state.elf.scnincr = 10; 296441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project 297cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng /* Make the class easily available. */ 298cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng elf->class = e_ident[EI_CLASS]; 299cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 300441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project if (e_ident[EI_CLASS] == ELFCLASS32) 301441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project { 302441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project /* This pointer might not be directly usable if the alignment is 303441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project not sufficient for the architecture. */ 304441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project Elf32_Ehdr *ehdr = (Elf32_Ehdr *) ((char *) map_address + offset); 305441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project 306441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project assert ((unsigned int) scncnt == scncnt); 307441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project elf->state.elf32.scns.cnt = elf->state.elf32.scns.max = scncnt; 308441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project 309441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project /* This is a 32-bit binary. */ 310441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project if (map_address != NULL && e_ident[EI_DATA] == MY_ELFDATA 311441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project && (ALLOW_UNALIGNED 312441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project || ((((uintptr_t) ehdr) & (__alignof__ (Elf32_Ehdr) - 1)) == 0 313441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project && ((uintptr_t) ((char *) ehdr + ehdr->e_shoff) 314441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project & (__alignof__ (Elf32_Shdr) - 1)) == 0 315441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project && ((uintptr_t) ((char *) ehdr + ehdr->e_phoff) 316441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project & (__alignof__ (Elf32_Phdr) - 1)) == 0))) 317441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project { 318441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project /* We can use the mmapped memory. */ 319cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng elf->state.elf32.ehdr = ehdr; 320cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng elf->state.elf32.shdr 321cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng = (Elf32_Shdr *) ((char *) ehdr + ehdr->e_shoff); 322cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng if (ehdr->e_phnum > 0) 323441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project /* Assign a value only if there really is a program 324441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project header. Otherwise the value remains NULL. */ 325441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project elf->state.elf32.phdr 326cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng = (Elf32_Phdr *) ((char *) ehdr + ehdr->e_phoff); 327441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project 328cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng for (size_t cnt = 0; cnt < scncnt; ++cnt) 329441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project { 330441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project elf->state.elf32.scns.data[cnt].index = cnt; 331441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project elf->state.elf32.scns.data[cnt].elf = elf; 332441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project elf->state.elf32.scns.data[cnt].shdr.e32 = 333441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project &elf->state.elf32.shdr[cnt]; 334441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project elf->state.elf32.scns.data[cnt].rawdata_base = 335441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project elf->state.elf32.scns.data[cnt].data_base = 336441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project ((char *) map_address + offset 337441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project + elf->state.elf32.shdr[cnt].sh_offset); 338441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project elf->state.elf32.scns.data[cnt].list = &elf->state.elf32.scns; 339cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 340cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng /* If this is a section with an extended index add a 341cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng reference in the section which uses the extended 342cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng index. */ 343cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng if (elf->state.elf32.shdr[cnt].sh_type == SHT_SYMTAB_SHNDX 344cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng && elf->state.elf32.shdr[cnt].sh_link < scncnt) 345cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng elf->state.elf32.scns.data[elf->state.elf32.shdr[cnt].sh_link].shndx_index 346cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng = cnt; 347cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 348cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng /* Set the own shndx_index field in case it has not yet 349cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng been set. */ 350cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng if (elf->state.elf32.scns.data[cnt].shndx_index == 0) 351cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng elf->state.elf32.scns.data[cnt].shndx_index = -1; 352441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project } 353441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project } 354441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project else 355441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project { 356cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng /* Copy the ELF header. */ 357cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng elf->state.elf32.ehdr = memcpy (&elf->state.elf32.ehdr_mem, e_ident, 358cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng sizeof (Elf32_Ehdr)); 359441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project 360441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project if (e_ident[EI_DATA] != MY_ELFDATA) 361441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project { 362441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project CONVERT (elf->state.elf32.ehdr_mem.e_type); 363441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project CONVERT (elf->state.elf32.ehdr_mem.e_machine); 364441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project CONVERT (elf->state.elf32.ehdr_mem.e_version); 365441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project CONVERT (elf->state.elf32.ehdr_mem.e_entry); 366441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project CONVERT (elf->state.elf32.ehdr_mem.e_phoff); 367441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project CONVERT (elf->state.elf32.ehdr_mem.e_shoff); 368441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project CONVERT (elf->state.elf32.ehdr_mem.e_flags); 369441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project CONVERT (elf->state.elf32.ehdr_mem.e_ehsize); 370441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project CONVERT (elf->state.elf32.ehdr_mem.e_phentsize); 371441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project CONVERT (elf->state.elf32.ehdr_mem.e_phnum); 372441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project CONVERT (elf->state.elf32.ehdr_mem.e_shentsize); 373441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project CONVERT (elf->state.elf32.ehdr_mem.e_shnum); 374441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project CONVERT (elf->state.elf32.ehdr_mem.e_shstrndx); 375441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project } 376441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project 377cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng for (size_t cnt = 0; cnt < scncnt; ++cnt) 378441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project { 379441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project elf->state.elf32.scns.data[cnt].index = cnt; 380441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project elf->state.elf32.scns.data[cnt].elf = elf; 381441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project elf->state.elf32.scns.data[cnt].list = &elf->state.elf32.scns; 382441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project } 383441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project } 384441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project 385441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project /* So far only one block with sections. */ 386441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project elf->state.elf32.scns_last = &elf->state.elf32.scns; 387441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project } 388441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project else 389441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project { 390441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project /* This pointer might not be directly usable if the alignment is 391441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project not sufficient for the architecture. */ 392441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project Elf64_Ehdr *ehdr = (Elf64_Ehdr *) ((char *) map_address + offset); 393441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project 394441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project assert ((unsigned int) scncnt == scncnt); 395441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project elf->state.elf64.scns.cnt = elf->state.elf64.scns.max = scncnt; 396441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project 397441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project /* This is a 64-bit binary. */ 398441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project if (map_address != NULL && e_ident[EI_DATA] == MY_ELFDATA 399441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project && (ALLOW_UNALIGNED 400441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project || ((((uintptr_t) ehdr) & (__alignof__ (Elf64_Ehdr) - 1)) == 0 401441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project && ((uintptr_t) ((char *) ehdr + ehdr->e_shoff) 402441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project & (__alignof__ (Elf64_Shdr) - 1)) == 0 403441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project && ((uintptr_t) ((char *) ehdr + ehdr->e_phoff) 404441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project & (__alignof__ (Elf64_Phdr) - 1)) == 0))) 405441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project { 406441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project /* We can use the mmapped memory. */ 407cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng elf->state.elf64.ehdr = ehdr; 408cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng elf->state.elf64.shdr 409cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng = (Elf64_Shdr *) ((char *) ehdr + ehdr->e_shoff); 410cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng if (ehdr->e_phnum > 0) 411441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project /* Assign a value only if there really is a program 412441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project header. Otherwise the value remains NULL. */ 413441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project elf->state.elf64.phdr 414cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng = (Elf64_Phdr *) ((char *) ehdr + ehdr->e_phoff); 415441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project 416cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng for (size_t cnt = 0; cnt < scncnt; ++cnt) 417441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project { 418441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project elf->state.elf64.scns.data[cnt].index = cnt; 419441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project elf->state.elf64.scns.data[cnt].elf = elf; 420441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project elf->state.elf64.scns.data[cnt].shdr.e64 = 421441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project &elf->state.elf64.shdr[cnt]; 422441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project elf->state.elf64.scns.data[cnt].rawdata_base = 423441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project elf->state.elf64.scns.data[cnt].data_base = 424441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project ((char *) map_address + offset 425441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project + elf->state.elf64.shdr[cnt].sh_offset); 426441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project elf->state.elf64.scns.data[cnt].list = &elf->state.elf64.scns; 427cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 428cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng /* If this is a section with an extended index add a 429cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng reference in the section which uses the extended 430cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng index. */ 431cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng if (elf->state.elf64.shdr[cnt].sh_type == SHT_SYMTAB_SHNDX 432cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng && elf->state.elf64.shdr[cnt].sh_link < scncnt) 433cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng elf->state.elf64.scns.data[elf->state.elf64.shdr[cnt].sh_link].shndx_index 434cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng = cnt; 435cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 436cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng /* Set the own shndx_index field in case it has not yet 437cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng been set. */ 438cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng if (elf->state.elf64.scns.data[cnt].shndx_index == 0) 439cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng elf->state.elf64.scns.data[cnt].shndx_index = -1; 440441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project } 441441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project } 442441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project else 443441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project { 444cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng /* Copy the ELF header. */ 445cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng elf->state.elf64.ehdr = memcpy (&elf->state.elf64.ehdr_mem, e_ident, 446cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng sizeof (Elf64_Ehdr)); 447441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project 448441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project if (e_ident[EI_DATA] != MY_ELFDATA) 449441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project { 450441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project CONVERT (elf->state.elf64.ehdr_mem.e_type); 451441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project CONVERT (elf->state.elf64.ehdr_mem.e_machine); 452441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project CONVERT (elf->state.elf64.ehdr_mem.e_version); 453441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project CONVERT (elf->state.elf64.ehdr_mem.e_entry); 454441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project CONVERT (elf->state.elf64.ehdr_mem.e_phoff); 455441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project CONVERT (elf->state.elf64.ehdr_mem.e_shoff); 456441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project CONVERT (elf->state.elf64.ehdr_mem.e_flags); 457441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project CONVERT (elf->state.elf64.ehdr_mem.e_ehsize); 458441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project CONVERT (elf->state.elf64.ehdr_mem.e_phentsize); 459441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project CONVERT (elf->state.elf64.ehdr_mem.e_phnum); 460441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project CONVERT (elf->state.elf64.ehdr_mem.e_shentsize); 461441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project CONVERT (elf->state.elf64.ehdr_mem.e_shnum); 462441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project CONVERT (elf->state.elf64.ehdr_mem.e_shstrndx); 463441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project } 464441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project 465cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng for (size_t cnt = 0; cnt < scncnt; ++cnt) 466441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project { 467441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project elf->state.elf64.scns.data[cnt].index = cnt; 468441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project elf->state.elf64.scns.data[cnt].elf = elf; 469441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project elf->state.elf64.scns.data[cnt].list = &elf->state.elf64.scns; 470441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project } 471441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project } 472441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project 473441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project /* So far only one block with sections. */ 474441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project elf->state.elf64.scns_last = &elf->state.elf64.scns; 475441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project } 476441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project 477441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project return elf; 478441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project} 479441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project 480441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project 481441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source ProjectElf * 482cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chenginternal_function 483441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project__libelf_read_mmaped_file (int fildes, void *map_address, off_t offset, 484441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project size_t maxsize, Elf_Cmd cmd, Elf *parent) 485441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project{ 486441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project /* We have to find out what kind of file this is. We handle ELF 487441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project files and archives. To find out what we have we must look at the 488441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project header. The header for an ELF file is EI_NIDENT bytes in size, 489441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project the header for an archive file SARMAG bytes long. */ 490cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng unsigned char *e_ident = (unsigned char *) map_address + offset; 491441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project 492441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project /* See what kind of object we have here. */ 493cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng Elf_Kind kind = determine_kind (e_ident, maxsize); 494441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project 495441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project switch (kind) 496441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project { 497441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project case ELF_K_ELF: 498cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng return file_read_elf (fildes, map_address, e_ident, offset, maxsize, 499cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng cmd, parent); 500441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project 501441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project case ELF_K_AR: 502441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project return file_read_ar (fildes, map_address, offset, maxsize, cmd, parent); 503441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project 504441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project default: 505441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project break; 506441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project } 507441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project 508441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project /* This case is easy. Since we cannot do anything with this file 509441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project create a dummy descriptor. */ 510441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project return allocate_elf (fildes, map_address, offset, maxsize, cmd, parent, 511441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project ELF_K_NONE, 0); 512441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project} 513441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project 514441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project 515441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectstatic Elf * 516441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectread_unmmaped_file (int fildes, off_t offset, size_t maxsize, Elf_Cmd cmd, 517441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project Elf *parent) 518441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project{ 519441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project /* We have to find out what kind of file this is. We handle ELF 520441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project files and archives. To find out what we have we must read the 521cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng header. The identification header for an ELF file is EI_NIDENT 522cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng bytes in size, but we read the whole ELF header since we will 523cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng need it anyway later. For archives the header in SARMAG bytes 524cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng long. Read the maximum of these numbers. 525441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project 526cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng XXX We have to change this for the extended `ar' format some day. 527cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 528cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng Use a union to ensure alignment. We might later access the 529cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng memory as a ElfXX_Ehdr. */ 530cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng union 531cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng { 532cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng Elf64_Ehdr ehdr; 533cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng unsigned char header[MAX (sizeof (Elf64_Ehdr), SARMAG)]; 534cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng } mem; 535441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project 536441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project /* Read the head of the file. */ 537cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng ssize_t nread = pread_retry (fildes, mem.header, 538cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng MIN (MAX (sizeof (Elf64_Ehdr), SARMAG), 539cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng maxsize), 540cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng offset); 541cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng if (unlikely (nread == -1)) 542441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project /* We cannot even read the head of the file. Maybe FILDES is associated 543441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project with an unseekable device. This is nothing we can handle. */ 544441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project return NULL; 545441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project 546441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project /* See what kind of object we have here. */ 547cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng Elf_Kind kind = determine_kind (mem.header, nread); 548441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project 549441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project switch (kind) 550441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project { 551441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project case ELF_K_AR: 552441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project return file_read_ar (fildes, NULL, offset, maxsize, cmd, parent); 553441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project 554441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project case ELF_K_ELF: 555441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project /* Make sure at least the ELF header is contained in the file. */ 556cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng if ((size_t) nread >= (mem.header[EI_CLASS] == ELFCLASS32 557cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng ? sizeof (Elf32_Ehdr) : sizeof (Elf64_Ehdr))) 558cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng return file_read_elf (fildes, NULL, mem.header, offset, maxsize, cmd, 559cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng parent); 560441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project /* FALLTHROUGH */ 561441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project 562441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project default: 563441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project break; 564441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project } 565441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project 566441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project /* This case is easy. Since we cannot do anything with this file 567441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project create a dummy descriptor. */ 568441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project return allocate_elf (fildes, NULL, offset, maxsize, cmd, parent, 569441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project ELF_K_NONE, 0); 570441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project} 571441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project 572441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project 573441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project/* Open a file for reading. If possible we will try to mmap() the file. */ 574441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectstatic struct Elf * 575441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectread_file (int fildes, off_t offset, size_t maxsize, 576441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project Elf_Cmd cmd, Elf *parent) 577441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project{ 578441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project void *map_address = NULL; 579441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project int use_mmap = (cmd == ELF_C_READ_MMAP || cmd == ELF_C_RDWR_MMAP 580441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project || cmd == ELF_C_WRITE_MMAP 581441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project || cmd == ELF_C_READ_MMAP_PRIVATE); 582441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project 583cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng#if _MUDFLAP 584cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng /* Mudflap doesn't grok that our mmap'd data is ok. */ 585cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng use_mmap = 0; 586cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng#endif 587cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 588441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project if (use_mmap) 589441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project { 590441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project if (parent == NULL) 591441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project { 592441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project if (maxsize == ~((size_t) 0)) 593441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project { 594441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project /* We don't know in the moment how large the file is. 595441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project Determine it now. */ 596441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project struct stat st; 597441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project 598441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project if (fstat (fildes, &st) == 0 599441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project && (sizeof (size_t) >= sizeof (st.st_size) 600441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project || st.st_size <= ~((size_t) 0))) 601441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project maxsize = (size_t) st.st_size; 602441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project } 603441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project 604441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project /* We try to map the file ourself. */ 605441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project map_address = mmap (NULL, maxsize, (cmd == ELF_C_READ_MMAP 606441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project ? PROT_READ 607441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project : PROT_READ|PROT_WRITE), 608441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project cmd == ELF_C_READ_MMAP_PRIVATE 609cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng || cmd == ELF_C_READ_MMAP 610441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project ? MAP_PRIVATE : MAP_SHARED, 611441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project fildes, offset); 612441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project 613441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project if (map_address == MAP_FAILED) 614441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project map_address = NULL; 615441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project } 616441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project else 617441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project { 618441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project /* The parent is already loaded. Use it. */ 619441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project assert (maxsize != ~((size_t) 0)); 620441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project 621441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project map_address = parent->map_address; 622441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project } 623441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project } 624441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project 625441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project /* If we have the file in memory optimize the access. */ 626441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project if (map_address != NULL) 627441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project { 628cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng assert (map_address != MAP_FAILED); 629441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project 630cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng struct Elf *result = __libelf_read_mmaped_file (fildes, map_address, 631cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng offset, maxsize, cmd, 632cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng parent); 633441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project 634441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project /* If something went wrong during the initialization unmap the 635441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project memory if we mmaped here. */ 636441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project if (result == NULL 637441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project && (parent == NULL 638441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project || parent->map_address != map_address)) 639441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project munmap (map_address, maxsize); 640441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project else if (parent == NULL) 641441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project /* Remember that we mmap()ed the memory. */ 642441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project result->flags |= ELF_F_MMAPPED; 643441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project 644441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project return result; 645441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project } 646441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project 647441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project /* Otherwise we have to do it the hard way. We read as much as necessary 648441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project from the file whenever we need information which is not available. */ 649441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project return read_unmmaped_file (fildes, offset, maxsize, cmd, parent); 650441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project} 651441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project 652441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project 653441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project/* Find the entry with the long names for the content of this archive. */ 654441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectstatic const char * 655441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectread_long_names (Elf *elf) 656441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project{ 657441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project off_t offset = SARMAG; /* This is the first entry. */ 658441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project struct ar_hdr hdrm; 659441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project struct ar_hdr *hdr; 660441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project char *newp; 661441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project size_t len; 662441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project 663441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project while (1) 664441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project { 665441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project if (elf->map_address != NULL) 666441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project { 667441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project if (offset + sizeof (struct ar_hdr) > elf->maximum_size) 668441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project return NULL; 669441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project 670441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project /* The data is mapped. */ 671441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project hdr = (struct ar_hdr *) (elf->map_address + offset); 672441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project } 673441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project else 674441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project { 675441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project /* Read the header from the file. */ 676cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng if (unlikely (pread_retry (elf->fildes, &hdrm, sizeof (hdrm), 677cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng elf->start_offset + offset) 678cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng != sizeof (hdrm))) 679441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project return NULL; 680441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project 681441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project hdr = &hdrm; 682441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project } 683441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project 684441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project len = atol (hdr->ar_size); 685441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project 686441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project if (memcmp (hdr->ar_name, "// ", 16) == 0) 687441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project break; 688441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project 689441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project offset += sizeof (struct ar_hdr) + ((len + 1) & ~1l); 690441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project } 691441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project 692441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project /* Due to the stupid format of the long name table entry (which are not 693441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project NUL terminted) we have to provide an appropriate representation anyhow. 694441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project Therefore we always make a copy which has the appropriate form. */ 695441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project newp = (char *) malloc (len); 696441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project if (newp != NULL) 697441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project { 698441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project char *runp; 699441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project 700441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project if (elf->map_address != NULL) 701441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project /* Simply copy it over. */ 702441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project elf->state.ar.long_names = (char *) memcpy (newp, 703441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project elf->map_address + offset 704441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project + sizeof (struct ar_hdr), 705441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project len); 706441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project else 707441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project { 708cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng if (unlikely ((size_t) pread_retry (elf->fildes, newp, len, 709cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng elf->start_offset + offset 710cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng + sizeof (struct ar_hdr)) 711cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng != len)) 712441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project { 713441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project /* We were not able to read all data. */ 714441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project free (newp); 715441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project elf->state.ar.long_names = NULL; 716441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project return NULL; 717441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project } 718441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project elf->state.ar.long_names = newp; 719441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project } 720441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project 721441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project elf->state.ar.long_names_len = len; 722441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project 723441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project /* Now NUL-terminate the strings. */ 724441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project runp = newp; 725441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project while (1) 726441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project { 727441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project runp = (char *) memchr (runp, '/', newp + len - runp); 728441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project if (runp == NULL) 729441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project /* This was the last entry. */ 730441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project break; 731441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project 732441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project /* NUL-terminate the string. */ 733441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project *runp = '\0'; 734441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project 735cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng /* Skip the NUL byte and the \012. */ 736441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project runp += 2; 737441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project 738441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project /* A sanity check. Somebody might have generated invalid 739441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project archive. */ 740441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project if (runp >= newp + len) 741441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project break; 742441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project } 743441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project } 744441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project 745441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project return newp; 746441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project} 747441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project 748441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project 749441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project/* Read the next archive header. */ 750441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectint 751cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chenginternal_function 752cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng__libelf_next_arhdr_wrlock (elf) 753441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project Elf *elf; 754441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project{ 755441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project struct ar_hdr *ar_hdr; 756441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project Elf_Arhdr *elf_ar_hdr; 757441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project 758441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project if (elf->map_address != NULL) 759441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project { 760441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project /* See whether this entry is in the file. */ 761cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng if (unlikely (elf->state.ar.offset + sizeof (struct ar_hdr) 762cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng > elf->start_offset + elf->maximum_size)) 763441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project { 764441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project /* This record is not anymore in the file. */ 765441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project __libelf_seterrno (ELF_E_RANGE); 766441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project return -1; 767441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project } 768441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project ar_hdr = (struct ar_hdr *) (elf->map_address + elf->state.ar.offset); 769441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project } 770441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project else 771441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project { 772441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project ar_hdr = &elf->state.ar.ar_hdr; 773441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project 774cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng if (unlikely (pread_retry (elf->fildes, ar_hdr, sizeof (struct ar_hdr), 775cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng elf->state.ar.offset) 776cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng != sizeof (struct ar_hdr))) 777441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project { 778441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project /* Something went wrong while reading the file. */ 779441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project __libelf_seterrno (ELF_E_RANGE); 780441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project return -1; 781441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project } 782441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project } 783441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project 784441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project /* One little consistency check. */ 785cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng if (unlikely (memcmp (ar_hdr->ar_fmag, ARFMAG, 2) != 0)) 786441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project { 787441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project /* This is no valid archive. */ 788441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project __libelf_seterrno (ELF_E_ARCHIVE_FMAG); 789441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project return -1; 790441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project } 791441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project 792441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project /* Copy the raw name over to a NUL terminated buffer. */ 793441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project *((char *) __mempcpy (elf->state.ar.raw_name, ar_hdr->ar_name, 16)) = '\0'; 794441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project 795441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project elf_ar_hdr = &elf->state.ar.elf_ar_hdr; 796441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project 797441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project /* Now convert the `struct ar_hdr' into `Elf_Arhdr'. 798441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project Determine whether this is a special entry. */ 799441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project if (ar_hdr->ar_name[0] == '/') 800441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project { 801441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project if (ar_hdr->ar_name[1] == ' ' 802441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project && memcmp (ar_hdr->ar_name, "/ ", 16) == 0) 803441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project /* This is the index. */ 804441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project elf_ar_hdr->ar_name = memcpy (elf->state.ar.ar_name, "/", 2); 805441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project else if (ar_hdr->ar_name[1] == '/' 806441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project && memcmp (ar_hdr->ar_name, "// ", 16) == 0) 807441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project /* This is the array with the long names. */ 808441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project elf_ar_hdr->ar_name = memcpy (elf->state.ar.ar_name, "//", 3); 809cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng else if (likely (isdigit (ar_hdr->ar_name[1]))) 810441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project { 811441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project size_t offset; 812441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project 813441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project /* This is a long name. First we have to read the long name 814441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project table, if this hasn't happened already. */ 815cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng if (unlikely (elf->state.ar.long_names == NULL 816cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng && read_long_names (elf) == NULL)) 817441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project { 818441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project /* No long name table although it is reference. The archive is 819441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project broken. */ 820441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project __libelf_seterrno (ELF_E_INVALID_ARCHIVE); 821441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project return -1; 822441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project } 823441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project 824441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project offset = atol (ar_hdr->ar_name + 1); 825cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng if (unlikely (offset >= elf->state.ar.long_names_len)) 826441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project { 827441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project /* The index in the long name table is larger than the table. */ 828441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project __libelf_seterrno (ELF_E_INVALID_ARCHIVE); 829441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project return -1; 830441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project } 831441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project elf_ar_hdr->ar_name = elf->state.ar.long_names + offset; 832441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project } 833441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project else 834441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project { 835441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project /* This is none of the known special entries. */ 836441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project __libelf_seterrno (ELF_E_INVALID_ARCHIVE); 837441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project return -1; 838441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project } 839441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project } 840441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project else 841441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project { 842441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project char *endp; 843441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project 844441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project /* It is a normal entry. Copy over the name. */ 845441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project endp = (char *) memccpy (elf->state.ar.ar_name, ar_hdr->ar_name, 846441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project '/', 16); 847441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project if (endp != NULL) 848441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project endp[-1] = '\0'; 849441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project else 850cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng { 851cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng /* In the old BSD style of archive, there is no / terminator. 852cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng Instead, there is space padding at the end of the name. */ 853cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng size_t i = 15; 854cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng do 855cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng elf->state.ar.ar_name[i] = '\0'; 856cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng while (i > 0 && elf->state.ar.ar_name[--i] == ' '); 857cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng } 858441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project 859441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project elf_ar_hdr->ar_name = elf->state.ar.ar_name; 860441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project } 861441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project 862cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng if (unlikely (ar_hdr->ar_size[0] == ' ')) 863cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng /* Something is really wrong. We cannot live without a size for 864cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng the member since it will not be possible to find the next 865cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng archive member. */ 866cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng { 867cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng __libelf_seterrno (ELF_E_INVALID_ARCHIVE); 868cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng return -1; 869cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng } 870cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 871441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project /* Since there are no specialized functions to convert ASCII to 872441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project time_t, uid_t, gid_t, mode_t, and off_t we use either atol or 873441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project atoll depending on the size of the types. We are also prepared 874441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project for the case where the whole field in the `struct ar_hdr' is 875441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project filled in which case we cannot simply use atol/l but instead have 876441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project to create a temporary copy. */ 877441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project 878cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng#define INT_FIELD(FIELD) \ 879cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng do \ 880cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng { \ 881cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng char buf[sizeof (ar_hdr->FIELD) + 1]; \ 882cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng const char *string = ar_hdr->FIELD; \ 883cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng if (ar_hdr->FIELD[sizeof (ar_hdr->FIELD) - 1] != ' ') \ 884cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng { \ 885cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng *((char *) __mempcpy (buf, ar_hdr->FIELD, sizeof (ar_hdr->FIELD))) \ 886cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng = '\0'; \ 887cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng string = buf; \ 888cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng } \ 889cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng if (sizeof (elf_ar_hdr->FIELD) <= sizeof (long int)) \ 890cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng elf_ar_hdr->FIELD = (__typeof (elf_ar_hdr->FIELD)) atol (string); \ 891cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng else \ 892cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng elf_ar_hdr->FIELD = (__typeof (elf_ar_hdr->FIELD)) atoll (string); \ 893cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng } \ 894cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng while (0) 895cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 896cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng INT_FIELD (ar_date); 897cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng INT_FIELD (ar_uid); 898cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng INT_FIELD (ar_gid); 899cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng INT_FIELD (ar_mode); 900cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng INT_FIELD (ar_size); 901441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project 902441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project return 0; 903441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project} 904441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project 905441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project 906441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project/* We were asked to return a clone of an existing descriptor. This 907441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project function must be called with the lock on the parent descriptor 908441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project being held. */ 909441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectstatic Elf * 910441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectdup_elf (int fildes, Elf_Cmd cmd, Elf *ref) 911441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project{ 912441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project struct Elf *result; 913441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project 914441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project if (fildes == -1) 915441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project /* Allow the user to pass -1 as the file descriptor for the new file. */ 916441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project fildes = ref->fildes; 917441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project /* The file descriptor better should be the same. If it was disconnected 918441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project already (using `elf_cntl') we do not test it. */ 919cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng else if (unlikely (ref->fildes != -1 && fildes != ref->fildes)) 920441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project { 921441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project __libelf_seterrno (ELF_E_FD_MISMATCH); 922441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project return NULL; 923441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project } 924441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project 925441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project /* The mode must allow reading. I.e., a descriptor creating with a 926441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project command different then ELF_C_READ, ELF_C_WRITE and ELF_C_RDWR is 927441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project not allowed. */ 928cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng if (unlikely (ref->cmd != ELF_C_READ && ref->cmd != ELF_C_READ_MMAP 929cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng && ref->cmd != ELF_C_WRITE && ref->cmd != ELF_C_WRITE_MMAP 930cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng && ref->cmd != ELF_C_RDWR && ref->cmd != ELF_C_RDWR_MMAP 931cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng && ref->cmd != ELF_C_READ_MMAP_PRIVATE)) 932441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project { 933441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project __libelf_seterrno (ELF_E_INVALID_OP); 934441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project return NULL; 935441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project } 936441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project 937441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project /* Now it is time to distinguish between reading normal files and 938441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project archives. Normal files can easily be handled be incrementing the 939441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project reference counter and return the same descriptor. */ 940441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project if (ref->kind != ELF_K_AR) 941441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project { 942441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project ++ref->ref_count; 943441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project return ref; 944441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project } 945441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project 946441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project /* This is an archive. We must create a descriptor for the archive 947441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project member the internal pointer of the archive file desriptor is 948441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project pointing to. First read the header of the next member if this 949441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project has not happened already. */ 950441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project if (ref->state.ar.elf_ar_hdr.ar_name == NULL 951cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng && __libelf_next_arhdr_wrlock (ref) != 0) 952441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project /* Something went wrong. Maybe there is no member left. */ 953441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project return NULL; 954441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project 955441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project /* We have all the information we need about the next archive member. 956441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project Now create a descriptor for it. */ 957441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project result = read_file (fildes, ref->state.ar.offset + sizeof (struct ar_hdr), 958441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project ref->state.ar.elf_ar_hdr.ar_size, cmd, ref); 959441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project 960441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project /* Enlist this new descriptor in the list of children. */ 961441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project if (result != NULL) 962441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project { 963441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project result->next = ref->state.ar.children; 964441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project ref->state.ar.children = result; 965441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project } 966441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project 967441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project return result; 968441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project} 969441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project 970441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project 971441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project/* Return desriptor for empty file ready for writing. */ 972441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectstatic struct Elf * 973441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectwrite_file (int fd, Elf_Cmd cmd) 974441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project{ 975441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project /* We simply create an empty `Elf' structure. */ 976441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project#define NSCNSALLOC 10 977441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project Elf *result = allocate_elf (fd, NULL, 0, 0, cmd, NULL, ELF_K_ELF, 978441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project NSCNSALLOC * sizeof (Elf_Scn)); 979441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project 980441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project if (result != NULL) 981441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project { 982441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project /* We have to write to the file in any case. */ 983441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project result->flags = ELF_F_DIRTY; 984441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project 985441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project /* Some more or less arbitrary value. */ 986441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project result->state.elf.scnincr = NSCNSALLOC; 987441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project 988441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project /* We have allocated room for some sections. */ 989441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project assert (offsetof (struct Elf, state.elf32.scns) 990441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project == offsetof (struct Elf, state.elf64.scns)); 991441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project result->state.elf.scns_last = &result->state.elf32.scns; 992441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project result->state.elf32.scns.max = NSCNSALLOC; 993441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project } 994441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project 995441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project return result; 996441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project} 997441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project 998441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project 999441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project/* Return a descriptor for the file belonging to FILDES. */ 1000441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source ProjectElf * 1001441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectelf_begin (fildes, cmd, ref) 1002441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project int fildes; 1003441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project Elf_Cmd cmd; 1004441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project Elf *ref; 1005441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project{ 1006441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project Elf *retval; 1007441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project 1008cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng if (unlikely (! __libelf_version_initialized)) 1009441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project { 1010441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project /* Version wasn't set so far. */ 1011441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project __libelf_seterrno (ELF_E_NO_VERSION); 1012441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project return NULL; 1013441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project } 1014441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project 1015441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project if (ref != NULL) 1016441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project /* Make sure the descriptor is not suddenly going away. */ 1017441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project rwlock_rdlock (ref->lock); 1018cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng else if (unlikely (fcntl (fildes, F_GETFL) == -1 && errno == EBADF)) 1019441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project { 1020441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project /* We cannot do anything productive without a file descriptor. */ 1021441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project __libelf_seterrno (ELF_E_INVALID_FILE); 1022441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project return NULL; 1023441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project } 1024441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project 1025cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng Elf *lock_dup_elf () 1026cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng { 1027cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng /* We need wrlock to dup an archive. */ 1028cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng if (ref->kind == ELF_K_AR) 1029cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng { 1030cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng rwlock_unlock (ref->lock); 1031cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng rwlock_wrlock (ref->lock); 1032cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng } 1033cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 1034cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng /* Duplicate the descriptor. */ 1035cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng return dup_elf (fildes, cmd, ref); 1036cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng } 1037cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 1038441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project switch (cmd) 1039441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project { 1040441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project case ELF_C_NULL: 1041441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project /* We simply return a NULL pointer. */ 1042441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project retval = NULL; 1043441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project break; 1044441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project 1045441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project case ELF_C_READ_MMAP_PRIVATE: 1046441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project /* If we have a reference it must also be opened this way. */ 1047cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng if (unlikely (ref != NULL && ref->cmd != ELF_C_READ_MMAP_PRIVATE)) 1048441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project { 1049441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project __libelf_seterrno (ELF_E_INVALID_CMD); 1050441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project retval = NULL; 1051441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project break; 1052441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project } 1053441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project /* FALLTHROUGH */ 1054441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project 1055441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project case ELF_C_READ: 1056441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project case ELF_C_READ_MMAP: 1057441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project if (ref != NULL) 1058cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng retval = lock_dup_elf (); 1059441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project else 1060441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project /* Create descriptor for existing file. */ 1061441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project retval = read_file (fildes, 0, ~((size_t) 0), cmd, NULL); 1062441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project break; 1063441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project 1064441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project case ELF_C_RDWR: 1065441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project case ELF_C_RDWR_MMAP: 1066441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project /* If we have a REF object it must also be opened using this 1067441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project command. */ 1068441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project if (ref != NULL) 1069441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project { 1070cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng if (unlikely (ref->cmd != ELF_C_RDWR && ref->cmd != ELF_C_RDWR_MMAP 1071cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng && ref->cmd != ELF_C_WRITE 1072cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng && ref->cmd != ELF_C_WRITE_MMAP)) 1073441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project { 1074441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project /* This is not ok. REF must also be opened for writing. */ 1075441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project __libelf_seterrno (ELF_E_INVALID_CMD); 1076441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project retval = NULL; 1077441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project } 1078441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project else 1079cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng retval = lock_dup_elf (); 1080441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project } 1081441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project else 1082441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project /* Create descriptor for existing file. */ 1083441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project retval = read_file (fildes, 0, ~((size_t) 0), cmd, NULL); 1084441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project break; 1085441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project 1086441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project case ELF_C_WRITE: 1087441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project case ELF_C_WRITE_MMAP: 1088441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project /* We ignore REF and prepare a descriptor to write a new file. */ 1089441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project retval = write_file (fildes, cmd); 1090441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project break; 1091441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project 1092441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project default: 1093441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project __libelf_seterrno (ELF_E_INVALID_CMD); 1094441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project retval = NULL; 1095441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project break; 1096441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project } 1097441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project 1098441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project /* Release the lock. */ 1099441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project if (ref != NULL) 1100441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project rwlock_unlock (ref->lock); 1101441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project 1102441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project return retval; 1103441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project} 1104441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source ProjectINTDEF(elf_begin) 1105