1da0c48c4Sopenharmony_ci/* Create descriptor for processing file. 2da0c48c4Sopenharmony_ci Copyright (C) 1998-2010, 2012, 2014, 2015, 2016 Red Hat, Inc. 3da0c48c4Sopenharmony_ci Copyright (C) 2021, 2022 Mark J. Wielaard <mark@klomp.org> 4da0c48c4Sopenharmony_ci This file is part of elfutils. 5da0c48c4Sopenharmony_ci Written by Ulrich Drepper <drepper@redhat.com>, 1998. 6da0c48c4Sopenharmony_ci 7da0c48c4Sopenharmony_ci This file is free software; you can redistribute it and/or modify 8da0c48c4Sopenharmony_ci it under the terms of either 9da0c48c4Sopenharmony_ci 10da0c48c4Sopenharmony_ci * the GNU Lesser General Public License as published by the Free 11da0c48c4Sopenharmony_ci Software Foundation; either version 3 of the License, or (at 12da0c48c4Sopenharmony_ci your option) any later version 13da0c48c4Sopenharmony_ci 14da0c48c4Sopenharmony_ci or 15da0c48c4Sopenharmony_ci 16da0c48c4Sopenharmony_ci * the GNU General Public License as published by the Free 17da0c48c4Sopenharmony_ci Software Foundation; either version 2 of the License, or (at 18da0c48c4Sopenharmony_ci your option) any later version 19da0c48c4Sopenharmony_ci 20da0c48c4Sopenharmony_ci or both in parallel, as here. 21da0c48c4Sopenharmony_ci 22da0c48c4Sopenharmony_ci elfutils is distributed in the hope that it will be useful, but 23da0c48c4Sopenharmony_ci WITHOUT ANY WARRANTY; without even the implied warranty of 24da0c48c4Sopenharmony_ci MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 25da0c48c4Sopenharmony_ci General Public License for more details. 26da0c48c4Sopenharmony_ci 27da0c48c4Sopenharmony_ci You should have received copies of the GNU General Public License and 28da0c48c4Sopenharmony_ci the GNU Lesser General Public License along with this program. If 29da0c48c4Sopenharmony_ci not, see <http://www.gnu.org/licenses/>. */ 30da0c48c4Sopenharmony_ci 31da0c48c4Sopenharmony_ci#ifdef HAVE_CONFIG_H 32da0c48c4Sopenharmony_ci# include <config.h> 33da0c48c4Sopenharmony_ci#endif 34da0c48c4Sopenharmony_ci 35da0c48c4Sopenharmony_ci#include <assert.h> 36da0c48c4Sopenharmony_ci#include <ctype.h> 37da0c48c4Sopenharmony_ci#include <errno.h> 38da0c48c4Sopenharmony_ci#include <fcntl.h> 39da0c48c4Sopenharmony_ci#include <stdbool.h> 40da0c48c4Sopenharmony_ci#include <stddef.h> 41da0c48c4Sopenharmony_ci#include <string.h> 42da0c48c4Sopenharmony_ci#include <sys/stat.h> 43da0c48c4Sopenharmony_ci 44da0c48c4Sopenharmony_ci#include "libelfP.h" 45da0c48c4Sopenharmony_ci#include "common.h" 46da0c48c4Sopenharmony_ci 47da0c48c4Sopenharmony_ci 48da0c48c4Sopenharmony_ci/* Create descriptor for archive in memory. */ 49da0c48c4Sopenharmony_cistatic inline Elf * 50da0c48c4Sopenharmony_cifile_read_ar (int fildes, void *map_address, off_t offset, size_t maxsize, 51da0c48c4Sopenharmony_ci Elf_Cmd cmd, Elf *parent) 52da0c48c4Sopenharmony_ci{ 53da0c48c4Sopenharmony_ci Elf *elf; 54da0c48c4Sopenharmony_ci 55da0c48c4Sopenharmony_ci /* Create a descriptor. */ 56da0c48c4Sopenharmony_ci elf = allocate_elf (fildes, map_address, offset, maxsize, cmd, parent, 57da0c48c4Sopenharmony_ci ELF_K_AR, 0); 58da0c48c4Sopenharmony_ci if (elf != NULL) 59da0c48c4Sopenharmony_ci { 60da0c48c4Sopenharmony_ci /* We don't read all the symbol tables in advance. All this will 61da0c48c4Sopenharmony_ci happen on demand. */ 62da0c48c4Sopenharmony_ci elf->state.ar.offset = offset + SARMAG; 63da0c48c4Sopenharmony_ci 64da0c48c4Sopenharmony_ci elf->state.ar.elf_ar_hdr.ar_rawname = elf->state.ar.raw_name; 65da0c48c4Sopenharmony_ci } 66da0c48c4Sopenharmony_ci 67da0c48c4Sopenharmony_ci return elf; 68da0c48c4Sopenharmony_ci} 69da0c48c4Sopenharmony_ci 70da0c48c4Sopenharmony_ci 71da0c48c4Sopenharmony_cistatic size_t 72da0c48c4Sopenharmony_ciget_shnum (void *map_address, unsigned char *e_ident, int fildes, 73da0c48c4Sopenharmony_ci int64_t offset, size_t maxsize) 74da0c48c4Sopenharmony_ci{ 75da0c48c4Sopenharmony_ci size_t result; 76da0c48c4Sopenharmony_ci union 77da0c48c4Sopenharmony_ci { 78da0c48c4Sopenharmony_ci Elf32_Ehdr *e32; 79da0c48c4Sopenharmony_ci Elf64_Ehdr *e64; 80da0c48c4Sopenharmony_ci void *p; 81da0c48c4Sopenharmony_ci } ehdr; 82da0c48c4Sopenharmony_ci union 83da0c48c4Sopenharmony_ci { 84da0c48c4Sopenharmony_ci Elf32_Ehdr e32; 85da0c48c4Sopenharmony_ci Elf64_Ehdr e64; 86da0c48c4Sopenharmony_ci } ehdr_mem; 87da0c48c4Sopenharmony_ci bool is32 = e_ident[EI_CLASS] == ELFCLASS32; 88da0c48c4Sopenharmony_ci 89da0c48c4Sopenharmony_ci if ((is32 && maxsize < sizeof (Elf32_Ehdr)) 90da0c48c4Sopenharmony_ci || (!is32 && maxsize < sizeof (Elf64_Ehdr))) 91da0c48c4Sopenharmony_ci { 92da0c48c4Sopenharmony_ci __libelf_seterrno (ELF_E_INVALID_ELF); 93da0c48c4Sopenharmony_ci return (size_t) -1l; 94da0c48c4Sopenharmony_ci } 95da0c48c4Sopenharmony_ci 96da0c48c4Sopenharmony_ci /* Make the ELF header available. */ 97da0c48c4Sopenharmony_ci if (e_ident[EI_DATA] == MY_ELFDATA 98da0c48c4Sopenharmony_ci && (ALLOW_UNALIGNED 99da0c48c4Sopenharmony_ci || (((size_t) e_ident 100da0c48c4Sopenharmony_ci & ((is32 ? __alignof__ (Elf32_Ehdr) : __alignof__ (Elf64_Ehdr)) 101da0c48c4Sopenharmony_ci - 1)) == 0))) 102da0c48c4Sopenharmony_ci ehdr.p = e_ident; 103da0c48c4Sopenharmony_ci else 104da0c48c4Sopenharmony_ci { 105da0c48c4Sopenharmony_ci /* We already read the ELF header. We have to copy the header 106da0c48c4Sopenharmony_ci since we possibly modify the data here and the caller 107da0c48c4Sopenharmony_ci expects the memory it passes in to be preserved. */ 108da0c48c4Sopenharmony_ci ehdr.p = &ehdr_mem; 109da0c48c4Sopenharmony_ci 110da0c48c4Sopenharmony_ci if (is32) 111da0c48c4Sopenharmony_ci { 112da0c48c4Sopenharmony_ci if (ALLOW_UNALIGNED) 113da0c48c4Sopenharmony_ci { 114da0c48c4Sopenharmony_ci ehdr_mem.e32.e_shnum = ((Elf32_Ehdr *) e_ident)->e_shnum; 115da0c48c4Sopenharmony_ci ehdr_mem.e32.e_shoff = ((Elf32_Ehdr *) e_ident)->e_shoff; 116da0c48c4Sopenharmony_ci } 117da0c48c4Sopenharmony_ci else 118da0c48c4Sopenharmony_ci memcpy (&ehdr_mem, e_ident, sizeof (Elf32_Ehdr)); 119da0c48c4Sopenharmony_ci 120da0c48c4Sopenharmony_ci if (e_ident[EI_DATA] != MY_ELFDATA) 121da0c48c4Sopenharmony_ci { 122da0c48c4Sopenharmony_ci CONVERT (ehdr_mem.e32.e_shnum); 123da0c48c4Sopenharmony_ci CONVERT (ehdr_mem.e32.e_shoff); 124da0c48c4Sopenharmony_ci } 125da0c48c4Sopenharmony_ci } 126da0c48c4Sopenharmony_ci else 127da0c48c4Sopenharmony_ci { 128da0c48c4Sopenharmony_ci if (ALLOW_UNALIGNED) 129da0c48c4Sopenharmony_ci { 130da0c48c4Sopenharmony_ci ehdr_mem.e64.e_shnum = ((Elf64_Ehdr *) e_ident)->e_shnum; 131da0c48c4Sopenharmony_ci ehdr_mem.e64.e_shoff = ((Elf64_Ehdr *) e_ident)->e_shoff; 132da0c48c4Sopenharmony_ci } 133da0c48c4Sopenharmony_ci else 134da0c48c4Sopenharmony_ci memcpy (&ehdr_mem, e_ident, sizeof (Elf64_Ehdr)); 135da0c48c4Sopenharmony_ci 136da0c48c4Sopenharmony_ci if (e_ident[EI_DATA] != MY_ELFDATA) 137da0c48c4Sopenharmony_ci { 138da0c48c4Sopenharmony_ci CONVERT (ehdr_mem.e64.e_shnum); 139da0c48c4Sopenharmony_ci CONVERT (ehdr_mem.e64.e_shoff); 140da0c48c4Sopenharmony_ci } 141da0c48c4Sopenharmony_ci } 142da0c48c4Sopenharmony_ci } 143da0c48c4Sopenharmony_ci 144da0c48c4Sopenharmony_ci if (is32) 145da0c48c4Sopenharmony_ci { 146da0c48c4Sopenharmony_ci /* Get the number of sections from the ELF header. */ 147da0c48c4Sopenharmony_ci result = ehdr.e32->e_shnum; 148da0c48c4Sopenharmony_ci 149da0c48c4Sopenharmony_ci if (unlikely (result == 0) && ehdr.e32->e_shoff != 0) 150da0c48c4Sopenharmony_ci { 151da0c48c4Sopenharmony_ci if (unlikely (ehdr.e32->e_shoff >= maxsize) 152da0c48c4Sopenharmony_ci || unlikely (maxsize - ehdr.e32->e_shoff < sizeof (Elf32_Shdr))) 153da0c48c4Sopenharmony_ci /* Cannot read the first section header. */ 154da0c48c4Sopenharmony_ci return 0; 155da0c48c4Sopenharmony_ci 156da0c48c4Sopenharmony_ci if (likely (map_address != NULL) && e_ident[EI_DATA] == MY_ELFDATA 157da0c48c4Sopenharmony_ci && (ALLOW_UNALIGNED 158da0c48c4Sopenharmony_ci || (((size_t) ((char *) (map_address + ehdr.e32->e_shoff 159da0c48c4Sopenharmony_ci + offset))) 160da0c48c4Sopenharmony_ci & (__alignof__ (Elf32_Shdr) - 1)) == 0)) 161da0c48c4Sopenharmony_ci /* We can directly access the memory. */ 162da0c48c4Sopenharmony_ci result = ((Elf32_Shdr *) ((char *) map_address + ehdr.e32->e_shoff 163da0c48c4Sopenharmony_ci + offset))->sh_size; 164da0c48c4Sopenharmony_ci else 165da0c48c4Sopenharmony_ci { 166da0c48c4Sopenharmony_ci Elf32_Word size; 167da0c48c4Sopenharmony_ci ssize_t r; 168da0c48c4Sopenharmony_ci 169da0c48c4Sopenharmony_ci if (likely (map_address != NULL)) 170da0c48c4Sopenharmony_ci /* gcc will optimize the memcpy to a simple memory 171da0c48c4Sopenharmony_ci access while taking care of alignment issues. */ 172da0c48c4Sopenharmony_ci memcpy (&size, ((char *) map_address 173da0c48c4Sopenharmony_ci + ehdr.e32->e_shoff 174da0c48c4Sopenharmony_ci + offset 175da0c48c4Sopenharmony_ci + offsetof (Elf32_Shdr, sh_size)), 176da0c48c4Sopenharmony_ci sizeof (Elf32_Word)); 177da0c48c4Sopenharmony_ci else 178da0c48c4Sopenharmony_ci if (unlikely ((r = pread_retry (fildes, &size, 179da0c48c4Sopenharmony_ci sizeof (Elf32_Word), 180da0c48c4Sopenharmony_ci offset + ehdr.e32->e_shoff 181da0c48c4Sopenharmony_ci + offsetof (Elf32_Shdr, 182da0c48c4Sopenharmony_ci sh_size))) 183da0c48c4Sopenharmony_ci != sizeof (Elf32_Word))) 184da0c48c4Sopenharmony_ci { 185da0c48c4Sopenharmony_ci if (r < 0) 186da0c48c4Sopenharmony_ci __libelf_seterrno (ELF_E_INVALID_FILE); 187da0c48c4Sopenharmony_ci else 188da0c48c4Sopenharmony_ci __libelf_seterrno (ELF_E_INVALID_ELF); 189da0c48c4Sopenharmony_ci return (size_t) -1l; 190da0c48c4Sopenharmony_ci } 191da0c48c4Sopenharmony_ci 192da0c48c4Sopenharmony_ci if (e_ident[EI_DATA] != MY_ELFDATA) 193da0c48c4Sopenharmony_ci CONVERT (size); 194da0c48c4Sopenharmony_ci 195da0c48c4Sopenharmony_ci result = size; 196da0c48c4Sopenharmony_ci } 197da0c48c4Sopenharmony_ci } 198da0c48c4Sopenharmony_ci 199da0c48c4Sopenharmony_ci /* If the section headers were truncated, pretend none were there. */ 200da0c48c4Sopenharmony_ci if (ehdr.e32->e_shoff > maxsize 201da0c48c4Sopenharmony_ci || maxsize - ehdr.e32->e_shoff < sizeof (Elf32_Shdr) * result) 202da0c48c4Sopenharmony_ci result = 0; 203da0c48c4Sopenharmony_ci } 204da0c48c4Sopenharmony_ci else 205da0c48c4Sopenharmony_ci { 206da0c48c4Sopenharmony_ci /* Get the number of sections from the ELF header. */ 207da0c48c4Sopenharmony_ci result = ehdr.e64->e_shnum; 208da0c48c4Sopenharmony_ci 209da0c48c4Sopenharmony_ci if (unlikely (result == 0) && ehdr.e64->e_shoff != 0) 210da0c48c4Sopenharmony_ci { 211da0c48c4Sopenharmony_ci if (unlikely (ehdr.e64->e_shoff >= maxsize) 212da0c48c4Sopenharmony_ci || unlikely (ehdr.e64->e_shoff + sizeof (Elf64_Shdr) > maxsize)) 213da0c48c4Sopenharmony_ci /* Cannot read the first section header. */ 214da0c48c4Sopenharmony_ci return 0; 215da0c48c4Sopenharmony_ci 216da0c48c4Sopenharmony_ci Elf64_Xword size; 217da0c48c4Sopenharmony_ci if (likely (map_address != NULL) && e_ident[EI_DATA] == MY_ELFDATA 218da0c48c4Sopenharmony_ci && (ALLOW_UNALIGNED 219da0c48c4Sopenharmony_ci || (((size_t) ((char *) (map_address + ehdr.e64->e_shoff 220da0c48c4Sopenharmony_ci + offset))) 221da0c48c4Sopenharmony_ci & (__alignof__ (Elf64_Shdr) - 1)) == 0)) 222da0c48c4Sopenharmony_ci /* We can directly access the memory. */ 223da0c48c4Sopenharmony_ci size = ((Elf64_Shdr *) ((char *) map_address + ehdr.e64->e_shoff 224da0c48c4Sopenharmony_ci + offset))->sh_size; 225da0c48c4Sopenharmony_ci else 226da0c48c4Sopenharmony_ci { 227da0c48c4Sopenharmony_ci ssize_t r; 228da0c48c4Sopenharmony_ci if (likely (map_address != NULL)) 229da0c48c4Sopenharmony_ci /* gcc will optimize the memcpy to a simple memory 230da0c48c4Sopenharmony_ci access while taking care of alignment issues. */ 231da0c48c4Sopenharmony_ci memcpy (&size, ((char *) map_address 232da0c48c4Sopenharmony_ci + ehdr.e64->e_shoff 233da0c48c4Sopenharmony_ci + offset 234da0c48c4Sopenharmony_ci + offsetof (Elf64_Shdr, sh_size)), 235da0c48c4Sopenharmony_ci sizeof (Elf64_Xword)); 236da0c48c4Sopenharmony_ci else 237da0c48c4Sopenharmony_ci if (unlikely ((r = pread_retry (fildes, &size, 238da0c48c4Sopenharmony_ci sizeof (Elf64_Xword), 239da0c48c4Sopenharmony_ci offset + ehdr.e64->e_shoff 240da0c48c4Sopenharmony_ci + offsetof (Elf64_Shdr, 241da0c48c4Sopenharmony_ci sh_size))) 242da0c48c4Sopenharmony_ci != sizeof (Elf64_Xword))) 243da0c48c4Sopenharmony_ci { 244da0c48c4Sopenharmony_ci if (r < 0) 245da0c48c4Sopenharmony_ci __libelf_seterrno (ELF_E_INVALID_FILE); 246da0c48c4Sopenharmony_ci else 247da0c48c4Sopenharmony_ci __libelf_seterrno (ELF_E_INVALID_ELF); 248da0c48c4Sopenharmony_ci return (size_t) -1l; 249da0c48c4Sopenharmony_ci } 250da0c48c4Sopenharmony_ci 251da0c48c4Sopenharmony_ci if (e_ident[EI_DATA] != MY_ELFDATA) 252da0c48c4Sopenharmony_ci CONVERT (size); 253da0c48c4Sopenharmony_ci } 254da0c48c4Sopenharmony_ci 255da0c48c4Sopenharmony_ci /* Although sh_size is an Elf64_Xword and can contain a 64bit 256da0c48c4Sopenharmony_ci value, we only expect an 32bit value max. GElf_Word is 257da0c48c4Sopenharmony_ci 32bit unsigned. */ 258da0c48c4Sopenharmony_ci if (size > ~((GElf_Word) 0)) 259da0c48c4Sopenharmony_ci { 260da0c48c4Sopenharmony_ci /* Invalid value, it is too large. */ 261da0c48c4Sopenharmony_ci __libelf_seterrno (ELF_E_INVALID_ELF); 262da0c48c4Sopenharmony_ci return (size_t) -1l; 263da0c48c4Sopenharmony_ci } 264da0c48c4Sopenharmony_ci 265da0c48c4Sopenharmony_ci result = size; 266da0c48c4Sopenharmony_ci } 267da0c48c4Sopenharmony_ci 268da0c48c4Sopenharmony_ci /* If the section headers were truncated, pretend none were there. */ 269da0c48c4Sopenharmony_ci if (ehdr.e64->e_shoff > maxsize 270da0c48c4Sopenharmony_ci || maxsize - ehdr.e64->e_shoff < sizeof (Elf64_Shdr) * result) 271da0c48c4Sopenharmony_ci result = 0; 272da0c48c4Sopenharmony_ci } 273da0c48c4Sopenharmony_ci 274da0c48c4Sopenharmony_ci return result; 275da0c48c4Sopenharmony_ci} 276da0c48c4Sopenharmony_ci 277da0c48c4Sopenharmony_ci 278da0c48c4Sopenharmony_ci/* Create descriptor for ELF file in memory. */ 279da0c48c4Sopenharmony_cistatic Elf * 280da0c48c4Sopenharmony_cifile_read_elf (int fildes, void *map_address, unsigned char *e_ident, 281da0c48c4Sopenharmony_ci int64_t offset, size_t maxsize, Elf_Cmd cmd, Elf *parent) 282da0c48c4Sopenharmony_ci{ 283da0c48c4Sopenharmony_ci /* Verify the binary is of the class we can handle. */ 284da0c48c4Sopenharmony_ci if (unlikely ((e_ident[EI_CLASS] != ELFCLASS32 285da0c48c4Sopenharmony_ci && e_ident[EI_CLASS] != ELFCLASS64) 286da0c48c4Sopenharmony_ci /* We also can only handle two encodings. */ 287da0c48c4Sopenharmony_ci || (e_ident[EI_DATA] != ELFDATA2LSB 288da0c48c4Sopenharmony_ci && e_ident[EI_DATA] != ELFDATA2MSB))) 289da0c48c4Sopenharmony_ci { 290da0c48c4Sopenharmony_ci /* Cannot handle this. */ 291da0c48c4Sopenharmony_ci __libelf_seterrno (ELF_E_INVALID_ELF); 292da0c48c4Sopenharmony_ci return NULL; 293da0c48c4Sopenharmony_ci } 294da0c48c4Sopenharmony_ci 295da0c48c4Sopenharmony_ci /* Determine the number of sections. Returns -1 and sets libelf errno 296da0c48c4Sopenharmony_ci if the file handle or elf file is invalid. Returns zero if there 297da0c48c4Sopenharmony_ci are no section headers (or they cannot be read). */ 298da0c48c4Sopenharmony_ci size_t scncnt = get_shnum (map_address, e_ident, fildes, offset, maxsize); 299da0c48c4Sopenharmony_ci if (scncnt == (size_t) -1l) 300da0c48c4Sopenharmony_ci /* Could not determine the number of sections. */ 301da0c48c4Sopenharmony_ci return NULL; 302da0c48c4Sopenharmony_ci 303da0c48c4Sopenharmony_ci /* Check for too many sections. */ 304da0c48c4Sopenharmony_ci if (e_ident[EI_CLASS] == ELFCLASS32) 305da0c48c4Sopenharmony_ci { 306da0c48c4Sopenharmony_ci if (scncnt > SIZE_MAX / (sizeof (Elf_Scn) + sizeof (Elf32_Shdr))) 307da0c48c4Sopenharmony_ci { 308da0c48c4Sopenharmony_ci __libelf_seterrno (ELF_E_INVALID_ELF); 309da0c48c4Sopenharmony_ci return NULL; 310da0c48c4Sopenharmony_ci } 311da0c48c4Sopenharmony_ci } 312da0c48c4Sopenharmony_ci else if (scncnt > SIZE_MAX / (sizeof (Elf_Scn) + sizeof (Elf64_Shdr))) 313da0c48c4Sopenharmony_ci { 314da0c48c4Sopenharmony_ci __libelf_seterrno (ELF_E_INVALID_ELF); 315da0c48c4Sopenharmony_ci return NULL; 316da0c48c4Sopenharmony_ci } 317da0c48c4Sopenharmony_ci 318da0c48c4Sopenharmony_ci /* We can now allocate the memory. Even if there are no section headers, 319da0c48c4Sopenharmony_ci we allocate space for a zeroth section in case we need it later. */ 320da0c48c4Sopenharmony_ci const size_t scnmax = (scncnt ?: (cmd == ELF_C_RDWR || cmd == ELF_C_RDWR_MMAP) 321da0c48c4Sopenharmony_ci ? 1 : 0); 322da0c48c4Sopenharmony_ci Elf *elf = allocate_elf (fildes, map_address, offset, maxsize, cmd, parent, 323da0c48c4Sopenharmony_ci ELF_K_ELF, scnmax * sizeof (Elf_Scn)); 324da0c48c4Sopenharmony_ci if (elf == NULL) 325da0c48c4Sopenharmony_ci /* Not enough memory. allocate_elf will have set libelf errno. */ 326da0c48c4Sopenharmony_ci return NULL; 327da0c48c4Sopenharmony_ci 328da0c48c4Sopenharmony_ci assert ((unsigned int) scncnt == scncnt); 329da0c48c4Sopenharmony_ci assert (offsetof (struct Elf, state.elf32.scns) 330da0c48c4Sopenharmony_ci == offsetof (struct Elf, state.elf64.scns)); 331da0c48c4Sopenharmony_ci elf->state.elf32.scns.cnt = scncnt; 332da0c48c4Sopenharmony_ci elf->state.elf32.scns.max = scnmax; 333da0c48c4Sopenharmony_ci 334da0c48c4Sopenharmony_ci /* Some more or less arbitrary value. */ 335da0c48c4Sopenharmony_ci elf->state.elf.scnincr = 10; 336da0c48c4Sopenharmony_ci 337da0c48c4Sopenharmony_ci /* Make the class easily available. */ 338da0c48c4Sopenharmony_ci elf->class = e_ident[EI_CLASS]; 339da0c48c4Sopenharmony_ci 340da0c48c4Sopenharmony_ci if (e_ident[EI_CLASS] == ELFCLASS32) 341da0c48c4Sopenharmony_ci { 342da0c48c4Sopenharmony_ci /* This pointer might not be directly usable if the alignment is 343da0c48c4Sopenharmony_ci not sufficient for the architecture. */ 344da0c48c4Sopenharmony_ci Elf32_Ehdr *ehdr = (Elf32_Ehdr *) ((char *) map_address + offset); 345da0c48c4Sopenharmony_ci 346da0c48c4Sopenharmony_ci /* This is a 32-bit binary. */ 347da0c48c4Sopenharmony_ci if (map_address != NULL && e_ident[EI_DATA] == MY_ELFDATA 348da0c48c4Sopenharmony_ci && (ALLOW_UNALIGNED 349da0c48c4Sopenharmony_ci || (((uintptr_t) ehdr) & (__alignof__ (Elf32_Ehdr) - 1)) == 0)) 350da0c48c4Sopenharmony_ci { 351da0c48c4Sopenharmony_ci /* We can use the mmapped memory. */ 352da0c48c4Sopenharmony_ci elf->state.elf32.ehdr = ehdr; 353da0c48c4Sopenharmony_ci } 354da0c48c4Sopenharmony_ci else 355da0c48c4Sopenharmony_ci { 356da0c48c4Sopenharmony_ci /* Copy the ELF header. */ 357da0c48c4Sopenharmony_ci elf->state.elf32.ehdr = memcpy (&elf->state.elf32.ehdr_mem, e_ident, 358da0c48c4Sopenharmony_ci sizeof (Elf32_Ehdr)); 359da0c48c4Sopenharmony_ci 360da0c48c4Sopenharmony_ci if (e_ident[EI_DATA] != MY_ELFDATA) 361da0c48c4Sopenharmony_ci { 362da0c48c4Sopenharmony_ci CONVERT (elf->state.elf32.ehdr_mem.e_type); 363da0c48c4Sopenharmony_ci CONVERT (elf->state.elf32.ehdr_mem.e_machine); 364da0c48c4Sopenharmony_ci CONVERT (elf->state.elf32.ehdr_mem.e_version); 365da0c48c4Sopenharmony_ci CONVERT (elf->state.elf32.ehdr_mem.e_entry); 366da0c48c4Sopenharmony_ci CONVERT (elf->state.elf32.ehdr_mem.e_phoff); 367da0c48c4Sopenharmony_ci CONVERT (elf->state.elf32.ehdr_mem.e_shoff); 368da0c48c4Sopenharmony_ci CONVERT (elf->state.elf32.ehdr_mem.e_flags); 369da0c48c4Sopenharmony_ci CONVERT (elf->state.elf32.ehdr_mem.e_ehsize); 370da0c48c4Sopenharmony_ci CONVERT (elf->state.elf32.ehdr_mem.e_phentsize); 371da0c48c4Sopenharmony_ci CONVERT (elf->state.elf32.ehdr_mem.e_phnum); 372da0c48c4Sopenharmony_ci CONVERT (elf->state.elf32.ehdr_mem.e_shentsize); 373da0c48c4Sopenharmony_ci CONVERT (elf->state.elf32.ehdr_mem.e_shnum); 374da0c48c4Sopenharmony_ci CONVERT (elf->state.elf32.ehdr_mem.e_shstrndx); 375da0c48c4Sopenharmony_ci } 376da0c48c4Sopenharmony_ci } 377da0c48c4Sopenharmony_ci 378da0c48c4Sopenharmony_ci /* Don't precache the phdr pointer here. 379da0c48c4Sopenharmony_ci elf32_getphdr will validate it against the size when asked. */ 380da0c48c4Sopenharmony_ci 381da0c48c4Sopenharmony_ci Elf32_Off e_shoff = elf->state.elf32.ehdr->e_shoff; 382da0c48c4Sopenharmony_ci if (map_address != NULL && e_ident[EI_DATA] == MY_ELFDATA 383da0c48c4Sopenharmony_ci && cmd != ELF_C_READ_MMAP /* We need a copy to be able to write. */ 384da0c48c4Sopenharmony_ci && (ALLOW_UNALIGNED 385da0c48c4Sopenharmony_ci || ((((uintptr_t) ehdr + e_shoff) 386da0c48c4Sopenharmony_ci & (__alignof__ (Elf32_Shdr) - 1)) == 0))) 387da0c48c4Sopenharmony_ci { 388da0c48c4Sopenharmony_ci if (unlikely (scncnt > 0 && e_shoff >= maxsize) 389da0c48c4Sopenharmony_ci || unlikely (maxsize - e_shoff 390da0c48c4Sopenharmony_ci < scncnt * sizeof (Elf32_Shdr))) 391da0c48c4Sopenharmony_ci { 392da0c48c4Sopenharmony_ci free_and_out: 393da0c48c4Sopenharmony_ci free (elf); 394da0c48c4Sopenharmony_ci __libelf_seterrno (ELF_E_INVALID_ELF); 395da0c48c4Sopenharmony_ci return NULL; 396da0c48c4Sopenharmony_ci } 397da0c48c4Sopenharmony_ci 398da0c48c4Sopenharmony_ci if (scncnt > 0) 399da0c48c4Sopenharmony_ci elf->state.elf32.shdr 400da0c48c4Sopenharmony_ci = (Elf32_Shdr *) ((char *) ehdr + e_shoff); 401da0c48c4Sopenharmony_ci 402da0c48c4Sopenharmony_ci for (size_t cnt = 0; cnt < scncnt; ++cnt) 403da0c48c4Sopenharmony_ci { 404da0c48c4Sopenharmony_ci elf->state.elf32.scns.data[cnt].index = cnt; 405da0c48c4Sopenharmony_ci elf->state.elf32.scns.data[cnt].elf = elf; 406da0c48c4Sopenharmony_ci elf->state.elf32.scns.data[cnt].shdr.e32 = 407da0c48c4Sopenharmony_ci &elf->state.elf32.shdr[cnt]; 408da0c48c4Sopenharmony_ci if (likely (elf->state.elf32.shdr[cnt].sh_offset < maxsize) 409da0c48c4Sopenharmony_ci && likely (elf->state.elf32.shdr[cnt].sh_size 410da0c48c4Sopenharmony_ci <= maxsize - elf->state.elf32.shdr[cnt].sh_offset)) 411da0c48c4Sopenharmony_ci elf->state.elf32.scns.data[cnt].rawdata_base = 412da0c48c4Sopenharmony_ci elf->state.elf32.scns.data[cnt].data_base = 413da0c48c4Sopenharmony_ci ((char *) map_address + offset 414da0c48c4Sopenharmony_ci + elf->state.elf32.shdr[cnt].sh_offset); 415da0c48c4Sopenharmony_ci elf->state.elf32.scns.data[cnt].list = &elf->state.elf32.scns; 416da0c48c4Sopenharmony_ci 417da0c48c4Sopenharmony_ci /* If this is a section with an extended index add a 418da0c48c4Sopenharmony_ci reference in the section which uses the extended 419da0c48c4Sopenharmony_ci index. */ 420da0c48c4Sopenharmony_ci if (elf->state.elf32.shdr[cnt].sh_type == SHT_SYMTAB_SHNDX 421da0c48c4Sopenharmony_ci && elf->state.elf32.shdr[cnt].sh_link < scncnt) 422da0c48c4Sopenharmony_ci elf->state.elf32.scns.data[elf->state.elf32.shdr[cnt].sh_link].shndx_index 423da0c48c4Sopenharmony_ci = cnt; 424da0c48c4Sopenharmony_ci 425da0c48c4Sopenharmony_ci /* Set the own shndx_index field in case it has not yet 426da0c48c4Sopenharmony_ci been set. */ 427da0c48c4Sopenharmony_ci if (elf->state.elf32.scns.data[cnt].shndx_index == 0) 428da0c48c4Sopenharmony_ci elf->state.elf32.scns.data[cnt].shndx_index = -1; 429da0c48c4Sopenharmony_ci } 430da0c48c4Sopenharmony_ci } 431da0c48c4Sopenharmony_ci else 432da0c48c4Sopenharmony_ci { 433da0c48c4Sopenharmony_ci for (size_t cnt = 0; cnt < scncnt; ++cnt) 434da0c48c4Sopenharmony_ci { 435da0c48c4Sopenharmony_ci elf->state.elf32.scns.data[cnt].index = cnt; 436da0c48c4Sopenharmony_ci elf->state.elf32.scns.data[cnt].elf = elf; 437da0c48c4Sopenharmony_ci elf->state.elf32.scns.data[cnt].list = &elf->state.elf32.scns; 438da0c48c4Sopenharmony_ci } 439da0c48c4Sopenharmony_ci } 440da0c48c4Sopenharmony_ci 441da0c48c4Sopenharmony_ci /* So far only one block with sections. */ 442da0c48c4Sopenharmony_ci elf->state.elf32.scns_last = &elf->state.elf32.scns; 443da0c48c4Sopenharmony_ci } 444da0c48c4Sopenharmony_ci else 445da0c48c4Sopenharmony_ci { 446da0c48c4Sopenharmony_ci /* This pointer might not be directly usable if the alignment is 447da0c48c4Sopenharmony_ci not sufficient for the architecture. */ 448da0c48c4Sopenharmony_ci Elf64_Ehdr *ehdr = (Elf64_Ehdr *) ((char *) map_address + offset); 449da0c48c4Sopenharmony_ci 450da0c48c4Sopenharmony_ci /* This is a 64-bit binary. */ 451da0c48c4Sopenharmony_ci if (map_address != NULL && e_ident[EI_DATA] == MY_ELFDATA 452da0c48c4Sopenharmony_ci && (ALLOW_UNALIGNED 453da0c48c4Sopenharmony_ci || (((uintptr_t) ehdr) & (__alignof__ (Elf64_Ehdr) - 1)) == 0)) 454da0c48c4Sopenharmony_ci { 455da0c48c4Sopenharmony_ci /* We can use the mmapped memory. */ 456da0c48c4Sopenharmony_ci elf->state.elf64.ehdr = ehdr; 457da0c48c4Sopenharmony_ci } 458da0c48c4Sopenharmony_ci else 459da0c48c4Sopenharmony_ci { 460da0c48c4Sopenharmony_ci /* Copy the ELF header. */ 461da0c48c4Sopenharmony_ci elf->state.elf64.ehdr = memcpy (&elf->state.elf64.ehdr_mem, e_ident, 462da0c48c4Sopenharmony_ci sizeof (Elf64_Ehdr)); 463da0c48c4Sopenharmony_ci 464da0c48c4Sopenharmony_ci if (e_ident[EI_DATA] != MY_ELFDATA) 465da0c48c4Sopenharmony_ci { 466da0c48c4Sopenharmony_ci CONVERT (elf->state.elf64.ehdr_mem.e_type); 467da0c48c4Sopenharmony_ci CONVERT (elf->state.elf64.ehdr_mem.e_machine); 468da0c48c4Sopenharmony_ci CONVERT (elf->state.elf64.ehdr_mem.e_version); 469da0c48c4Sopenharmony_ci CONVERT (elf->state.elf64.ehdr_mem.e_entry); 470da0c48c4Sopenharmony_ci CONVERT (elf->state.elf64.ehdr_mem.e_phoff); 471da0c48c4Sopenharmony_ci CONVERT (elf->state.elf64.ehdr_mem.e_shoff); 472da0c48c4Sopenharmony_ci CONVERT (elf->state.elf64.ehdr_mem.e_flags); 473da0c48c4Sopenharmony_ci CONVERT (elf->state.elf64.ehdr_mem.e_ehsize); 474da0c48c4Sopenharmony_ci CONVERT (elf->state.elf64.ehdr_mem.e_phentsize); 475da0c48c4Sopenharmony_ci CONVERT (elf->state.elf64.ehdr_mem.e_phnum); 476da0c48c4Sopenharmony_ci CONVERT (elf->state.elf64.ehdr_mem.e_shentsize); 477da0c48c4Sopenharmony_ci CONVERT (elf->state.elf64.ehdr_mem.e_shnum); 478da0c48c4Sopenharmony_ci CONVERT (elf->state.elf64.ehdr_mem.e_shstrndx); 479da0c48c4Sopenharmony_ci } 480da0c48c4Sopenharmony_ci } 481da0c48c4Sopenharmony_ci 482da0c48c4Sopenharmony_ci /* Don't precache the phdr pointer here. 483da0c48c4Sopenharmony_ci elf64_getphdr will validate it against the size when asked. */ 484da0c48c4Sopenharmony_ci 485da0c48c4Sopenharmony_ci Elf64_Off e_shoff = elf->state.elf64.ehdr->e_shoff; 486da0c48c4Sopenharmony_ci if (map_address != NULL && e_ident[EI_DATA] == MY_ELFDATA 487da0c48c4Sopenharmony_ci && cmd != ELF_C_READ_MMAP /* We need a copy to be able to write. */ 488da0c48c4Sopenharmony_ci && (ALLOW_UNALIGNED 489da0c48c4Sopenharmony_ci || ((((uintptr_t) ehdr + e_shoff) 490da0c48c4Sopenharmony_ci & (__alignof__ (Elf64_Shdr) - 1)) == 0))) 491da0c48c4Sopenharmony_ci { 492da0c48c4Sopenharmony_ci if (unlikely (scncnt > 0 && e_shoff >= maxsize) 493da0c48c4Sopenharmony_ci || unlikely (maxsize - e_shoff 494da0c48c4Sopenharmony_ci < scncnt * sizeof (Elf64_Shdr))) 495da0c48c4Sopenharmony_ci goto free_and_out; 496da0c48c4Sopenharmony_ci 497da0c48c4Sopenharmony_ci if (scncnt > 0) 498da0c48c4Sopenharmony_ci elf->state.elf64.shdr 499da0c48c4Sopenharmony_ci = (Elf64_Shdr *) ((char *) ehdr + e_shoff); 500da0c48c4Sopenharmony_ci 501da0c48c4Sopenharmony_ci for (size_t cnt = 0; cnt < scncnt; ++cnt) 502da0c48c4Sopenharmony_ci { 503da0c48c4Sopenharmony_ci elf->state.elf64.scns.data[cnt].index = cnt; 504da0c48c4Sopenharmony_ci elf->state.elf64.scns.data[cnt].elf = elf; 505da0c48c4Sopenharmony_ci elf->state.elf64.scns.data[cnt].shdr.e64 = 506da0c48c4Sopenharmony_ci &elf->state.elf64.shdr[cnt]; 507da0c48c4Sopenharmony_ci if (likely (elf->state.elf64.shdr[cnt].sh_offset < maxsize) 508da0c48c4Sopenharmony_ci && likely (elf->state.elf64.shdr[cnt].sh_size 509da0c48c4Sopenharmony_ci <= maxsize - elf->state.elf64.shdr[cnt].sh_offset)) 510da0c48c4Sopenharmony_ci elf->state.elf64.scns.data[cnt].rawdata_base = 511da0c48c4Sopenharmony_ci elf->state.elf64.scns.data[cnt].data_base = 512da0c48c4Sopenharmony_ci ((char *) map_address + offset 513da0c48c4Sopenharmony_ci + elf->state.elf64.shdr[cnt].sh_offset); 514da0c48c4Sopenharmony_ci elf->state.elf64.scns.data[cnt].list = &elf->state.elf64.scns; 515da0c48c4Sopenharmony_ci 516da0c48c4Sopenharmony_ci /* If this is a section with an extended index add a 517da0c48c4Sopenharmony_ci reference in the section which uses the extended 518da0c48c4Sopenharmony_ci index. */ 519da0c48c4Sopenharmony_ci if (elf->state.elf64.shdr[cnt].sh_type == SHT_SYMTAB_SHNDX 520da0c48c4Sopenharmony_ci && elf->state.elf64.shdr[cnt].sh_link < scncnt) 521da0c48c4Sopenharmony_ci elf->state.elf64.scns.data[elf->state.elf64.shdr[cnt].sh_link].shndx_index 522da0c48c4Sopenharmony_ci = cnt; 523da0c48c4Sopenharmony_ci 524da0c48c4Sopenharmony_ci /* Set the own shndx_index field in case it has not yet 525da0c48c4Sopenharmony_ci been set. */ 526da0c48c4Sopenharmony_ci if (elf->state.elf64.scns.data[cnt].shndx_index == 0) 527da0c48c4Sopenharmony_ci elf->state.elf64.scns.data[cnt].shndx_index = -1; 528da0c48c4Sopenharmony_ci } 529da0c48c4Sopenharmony_ci } 530da0c48c4Sopenharmony_ci else 531da0c48c4Sopenharmony_ci { 532da0c48c4Sopenharmony_ci for (size_t cnt = 0; cnt < scncnt; ++cnt) 533da0c48c4Sopenharmony_ci { 534da0c48c4Sopenharmony_ci elf->state.elf64.scns.data[cnt].index = cnt; 535da0c48c4Sopenharmony_ci elf->state.elf64.scns.data[cnt].elf = elf; 536da0c48c4Sopenharmony_ci elf->state.elf64.scns.data[cnt].list = &elf->state.elf64.scns; 537da0c48c4Sopenharmony_ci } 538da0c48c4Sopenharmony_ci } 539da0c48c4Sopenharmony_ci 540da0c48c4Sopenharmony_ci /* So far only one block with sections. */ 541da0c48c4Sopenharmony_ci elf->state.elf64.scns_last = &elf->state.elf64.scns; 542da0c48c4Sopenharmony_ci } 543da0c48c4Sopenharmony_ci 544da0c48c4Sopenharmony_ci return elf; 545da0c48c4Sopenharmony_ci} 546da0c48c4Sopenharmony_ci 547da0c48c4Sopenharmony_ci 548da0c48c4Sopenharmony_ciElf * 549da0c48c4Sopenharmony_ciinternal_function 550da0c48c4Sopenharmony_ci__libelf_read_mmaped_file (int fildes, void *map_address, int64_t offset, 551da0c48c4Sopenharmony_ci size_t maxsize, Elf_Cmd cmd, Elf *parent) 552da0c48c4Sopenharmony_ci{ 553da0c48c4Sopenharmony_ci /* We have to find out what kind of file this is. We handle ELF 554da0c48c4Sopenharmony_ci files and archives. To find out what we have we must look at the 555da0c48c4Sopenharmony_ci header. The header for an ELF file is EI_NIDENT bytes in size, 556da0c48c4Sopenharmony_ci the header for an archive file SARMAG bytes long. */ 557da0c48c4Sopenharmony_ci unsigned char *e_ident = (unsigned char *) map_address + offset; 558da0c48c4Sopenharmony_ci 559da0c48c4Sopenharmony_ci /* See what kind of object we have here. */ 560da0c48c4Sopenharmony_ci Elf_Kind kind = determine_kind (e_ident, maxsize); 561da0c48c4Sopenharmony_ci 562da0c48c4Sopenharmony_ci switch (kind) 563da0c48c4Sopenharmony_ci { 564da0c48c4Sopenharmony_ci case ELF_K_ELF: 565da0c48c4Sopenharmony_ci return file_read_elf (fildes, map_address, e_ident, offset, maxsize, 566da0c48c4Sopenharmony_ci cmd, parent); 567da0c48c4Sopenharmony_ci 568da0c48c4Sopenharmony_ci case ELF_K_AR: 569da0c48c4Sopenharmony_ci return file_read_ar (fildes, map_address, offset, maxsize, cmd, parent); 570da0c48c4Sopenharmony_ci 571da0c48c4Sopenharmony_ci default: 572da0c48c4Sopenharmony_ci break; 573da0c48c4Sopenharmony_ci } 574da0c48c4Sopenharmony_ci 575da0c48c4Sopenharmony_ci /* This case is easy. Since we cannot do anything with this file 576da0c48c4Sopenharmony_ci create a dummy descriptor. */ 577da0c48c4Sopenharmony_ci return allocate_elf (fildes, map_address, offset, maxsize, cmd, parent, 578da0c48c4Sopenharmony_ci ELF_K_NONE, 0); 579da0c48c4Sopenharmony_ci} 580da0c48c4Sopenharmony_ci 581da0c48c4Sopenharmony_ci 582da0c48c4Sopenharmony_cistatic Elf * 583da0c48c4Sopenharmony_ciread_unmmaped_file (int fildes, int64_t offset, size_t maxsize, Elf_Cmd cmd, 584da0c48c4Sopenharmony_ci Elf *parent) 585da0c48c4Sopenharmony_ci{ 586da0c48c4Sopenharmony_ci /* We have to find out what kind of file this is. We handle ELF 587da0c48c4Sopenharmony_ci files and archives. To find out what we have we must read the 588da0c48c4Sopenharmony_ci header. The identification header for an ELF file is EI_NIDENT 589da0c48c4Sopenharmony_ci bytes in size, but we read the whole ELF header since we will 590da0c48c4Sopenharmony_ci need it anyway later. For archives the header in SARMAG bytes 591da0c48c4Sopenharmony_ci long. Read the maximum of these numbers. 592da0c48c4Sopenharmony_ci 593da0c48c4Sopenharmony_ci XXX We have to change this for the extended `ar' format some day. 594da0c48c4Sopenharmony_ci 595da0c48c4Sopenharmony_ci Use a union to ensure alignment. We might later access the 596da0c48c4Sopenharmony_ci memory as a ElfXX_Ehdr. */ 597da0c48c4Sopenharmony_ci union 598da0c48c4Sopenharmony_ci { 599da0c48c4Sopenharmony_ci Elf64_Ehdr ehdr; 600da0c48c4Sopenharmony_ci unsigned char header[MAX (sizeof (Elf64_Ehdr), SARMAG)]; 601da0c48c4Sopenharmony_ci } mem; 602da0c48c4Sopenharmony_ci 603da0c48c4Sopenharmony_ci /* Read the head of the file. */ 604da0c48c4Sopenharmony_ci ssize_t nread = pread_retry (fildes, mem.header, 605da0c48c4Sopenharmony_ci MIN (MAX (sizeof (Elf64_Ehdr), SARMAG), 606da0c48c4Sopenharmony_ci maxsize), 607da0c48c4Sopenharmony_ci offset); 608da0c48c4Sopenharmony_ci if (unlikely (nread == -1)) 609da0c48c4Sopenharmony_ci { 610da0c48c4Sopenharmony_ci /* We cannot even read the head of the file. Maybe FILDES is associated 611da0c48c4Sopenharmony_ci with an unseekable device. This is nothing we can handle. */ 612da0c48c4Sopenharmony_ci __libelf_seterrno (ELF_E_INVALID_FILE); 613da0c48c4Sopenharmony_ci return NULL; 614da0c48c4Sopenharmony_ci } 615da0c48c4Sopenharmony_ci 616da0c48c4Sopenharmony_ci /* See what kind of object we have here. */ 617da0c48c4Sopenharmony_ci Elf_Kind kind = determine_kind (mem.header, nread); 618da0c48c4Sopenharmony_ci 619da0c48c4Sopenharmony_ci switch (kind) 620da0c48c4Sopenharmony_ci { 621da0c48c4Sopenharmony_ci case ELF_K_AR: 622da0c48c4Sopenharmony_ci return file_read_ar (fildes, NULL, offset, maxsize, cmd, parent); 623da0c48c4Sopenharmony_ci 624da0c48c4Sopenharmony_ci case ELF_K_ELF: 625da0c48c4Sopenharmony_ci /* Make sure at least the ELF header is contained in the file. */ 626da0c48c4Sopenharmony_ci if ((size_t) nread >= (mem.header[EI_CLASS] == ELFCLASS32 627da0c48c4Sopenharmony_ci ? sizeof (Elf32_Ehdr) : sizeof (Elf64_Ehdr))) 628da0c48c4Sopenharmony_ci return file_read_elf (fildes, NULL, mem.header, offset, maxsize, cmd, 629da0c48c4Sopenharmony_ci parent); 630da0c48c4Sopenharmony_ci FALLTHROUGH; 631da0c48c4Sopenharmony_ci 632da0c48c4Sopenharmony_ci default: 633da0c48c4Sopenharmony_ci break; 634da0c48c4Sopenharmony_ci } 635da0c48c4Sopenharmony_ci 636da0c48c4Sopenharmony_ci /* This case is easy. Since we cannot do anything with this file 637da0c48c4Sopenharmony_ci create a dummy descriptor. */ 638da0c48c4Sopenharmony_ci return allocate_elf (fildes, NULL, offset, maxsize, cmd, parent, 639da0c48c4Sopenharmony_ci ELF_K_NONE, 0); 640da0c48c4Sopenharmony_ci} 641da0c48c4Sopenharmony_ci 642da0c48c4Sopenharmony_ci 643da0c48c4Sopenharmony_ci/* Open a file for reading. If possible we will try to mmap() the file. */ 644da0c48c4Sopenharmony_cistatic struct Elf * 645da0c48c4Sopenharmony_ciread_file (int fildes, int64_t offset, size_t maxsize, 646da0c48c4Sopenharmony_ci Elf_Cmd cmd, Elf *parent) 647da0c48c4Sopenharmony_ci{ 648da0c48c4Sopenharmony_ci void *map_address = NULL; 649da0c48c4Sopenharmony_ci int use_mmap = (cmd == ELF_C_READ_MMAP || cmd == ELF_C_RDWR_MMAP 650da0c48c4Sopenharmony_ci || cmd == ELF_C_WRITE_MMAP 651da0c48c4Sopenharmony_ci || cmd == ELF_C_READ_MMAP_PRIVATE); 652da0c48c4Sopenharmony_ci 653da0c48c4Sopenharmony_ci if (parent == NULL) 654da0c48c4Sopenharmony_ci { 655da0c48c4Sopenharmony_ci if (maxsize == ~((size_t) 0)) 656da0c48c4Sopenharmony_ci { 657da0c48c4Sopenharmony_ci /* We don't know in the moment how large the file is. 658da0c48c4Sopenharmony_ci Determine it now. */ 659da0c48c4Sopenharmony_ci struct stat st; 660da0c48c4Sopenharmony_ci 661da0c48c4Sopenharmony_ci if (fstat (fildes, &st) == 0 662da0c48c4Sopenharmony_ci && (sizeof (size_t) >= sizeof (st.st_size) 663da0c48c4Sopenharmony_ci || st.st_size <= ~((size_t) 0))) 664da0c48c4Sopenharmony_ci maxsize = (size_t) st.st_size; 665da0c48c4Sopenharmony_ci } 666da0c48c4Sopenharmony_ci } 667da0c48c4Sopenharmony_ci else 668da0c48c4Sopenharmony_ci { 669da0c48c4Sopenharmony_ci /* The parent is already loaded. Use it. */ 670da0c48c4Sopenharmony_ci assert (maxsize != ~((size_t) 0)); 671da0c48c4Sopenharmony_ci } 672da0c48c4Sopenharmony_ci 673da0c48c4Sopenharmony_ci if (use_mmap) 674da0c48c4Sopenharmony_ci { 675da0c48c4Sopenharmony_ci if (parent == NULL) 676da0c48c4Sopenharmony_ci { 677da0c48c4Sopenharmony_ci /* We try to map the file ourself. */ 678da0c48c4Sopenharmony_ci map_address = mmap (NULL, maxsize, (cmd == ELF_C_READ_MMAP 679da0c48c4Sopenharmony_ci ? PROT_READ 680da0c48c4Sopenharmony_ci : PROT_READ|PROT_WRITE), 681da0c48c4Sopenharmony_ci cmd == ELF_C_READ_MMAP_PRIVATE 682da0c48c4Sopenharmony_ci || cmd == ELF_C_READ_MMAP 683da0c48c4Sopenharmony_ci ? MAP_PRIVATE : MAP_SHARED, 684da0c48c4Sopenharmony_ci fildes, offset); 685da0c48c4Sopenharmony_ci 686da0c48c4Sopenharmony_ci if (map_address == MAP_FAILED) 687da0c48c4Sopenharmony_ci map_address = NULL; 688da0c48c4Sopenharmony_ci } 689da0c48c4Sopenharmony_ci else 690da0c48c4Sopenharmony_ci { 691da0c48c4Sopenharmony_ci map_address = parent->map_address; 692da0c48c4Sopenharmony_ci } 693da0c48c4Sopenharmony_ci } 694da0c48c4Sopenharmony_ci 695da0c48c4Sopenharmony_ci /* If we have the file in memory optimize the access. */ 696da0c48c4Sopenharmony_ci if (map_address != NULL) 697da0c48c4Sopenharmony_ci { 698da0c48c4Sopenharmony_ci assert (map_address != MAP_FAILED); 699da0c48c4Sopenharmony_ci 700da0c48c4Sopenharmony_ci struct Elf *result = __libelf_read_mmaped_file (fildes, map_address, 701da0c48c4Sopenharmony_ci offset, maxsize, cmd, 702da0c48c4Sopenharmony_ci parent); 703da0c48c4Sopenharmony_ci 704da0c48c4Sopenharmony_ci /* If something went wrong during the initialization unmap the 705da0c48c4Sopenharmony_ci memory if we mmaped here. */ 706da0c48c4Sopenharmony_ci if (result == NULL 707da0c48c4Sopenharmony_ci && (parent == NULL 708da0c48c4Sopenharmony_ci || parent->map_address != map_address)) 709da0c48c4Sopenharmony_ci munmap (map_address, maxsize); 710da0c48c4Sopenharmony_ci else if (parent == NULL) 711da0c48c4Sopenharmony_ci /* Remember that we mmap()ed the memory. */ 712da0c48c4Sopenharmony_ci result->flags |= ELF_F_MMAPPED; 713da0c48c4Sopenharmony_ci 714da0c48c4Sopenharmony_ci return result; 715da0c48c4Sopenharmony_ci } 716da0c48c4Sopenharmony_ci 717da0c48c4Sopenharmony_ci /* Otherwise we have to do it the hard way. We read as much as necessary 718da0c48c4Sopenharmony_ci from the file whenever we need information which is not available. */ 719da0c48c4Sopenharmony_ci return read_unmmaped_file (fildes, offset, maxsize, cmd, parent); 720da0c48c4Sopenharmony_ci} 721da0c48c4Sopenharmony_ci 722da0c48c4Sopenharmony_ci 723da0c48c4Sopenharmony_ci/* Find the entry with the long names for the content of this archive. */ 724da0c48c4Sopenharmony_cistatic const char * 725da0c48c4Sopenharmony_ciread_long_names (Elf *elf) 726da0c48c4Sopenharmony_ci{ 727da0c48c4Sopenharmony_ci off_t offset = SARMAG; /* This is the first entry. */ 728da0c48c4Sopenharmony_ci struct ar_hdr hdrm; 729da0c48c4Sopenharmony_ci struct ar_hdr *hdr; 730da0c48c4Sopenharmony_ci char *newp; 731da0c48c4Sopenharmony_ci size_t len; 732da0c48c4Sopenharmony_ci 733da0c48c4Sopenharmony_ci while (1) 734da0c48c4Sopenharmony_ci { 735da0c48c4Sopenharmony_ci if (elf->map_address != NULL) 736da0c48c4Sopenharmony_ci { 737da0c48c4Sopenharmony_ci if ((size_t) offset > elf->maximum_size 738da0c48c4Sopenharmony_ci || elf->maximum_size - offset < sizeof (struct ar_hdr)) 739da0c48c4Sopenharmony_ci return NULL; 740da0c48c4Sopenharmony_ci 741da0c48c4Sopenharmony_ci /* The data is mapped. */ 742da0c48c4Sopenharmony_ci hdr = (struct ar_hdr *) (elf->map_address + offset); 743da0c48c4Sopenharmony_ci } 744da0c48c4Sopenharmony_ci else 745da0c48c4Sopenharmony_ci { 746da0c48c4Sopenharmony_ci /* Read the header from the file. */ 747da0c48c4Sopenharmony_ci if (unlikely (pread_retry (elf->fildes, &hdrm, sizeof (hdrm), 748da0c48c4Sopenharmony_ci elf->start_offset + offset) 749da0c48c4Sopenharmony_ci != sizeof (hdrm))) 750da0c48c4Sopenharmony_ci return NULL; 751da0c48c4Sopenharmony_ci 752da0c48c4Sopenharmony_ci hdr = &hdrm; 753da0c48c4Sopenharmony_ci } 754da0c48c4Sopenharmony_ci 755da0c48c4Sopenharmony_ci /* The ar_size is given as a fixed size decimal string, right 756da0c48c4Sopenharmony_ci padded with spaces. Make sure we read it properly even if 757da0c48c4Sopenharmony_ci there is no terminating space. */ 758da0c48c4Sopenharmony_ci char buf[sizeof (hdr->ar_size) + 1]; 759da0c48c4Sopenharmony_ci const char *string = hdr->ar_size; 760da0c48c4Sopenharmony_ci if (hdr->ar_size[sizeof (hdr->ar_size) - 1] != ' ') 761da0c48c4Sopenharmony_ci { 762da0c48c4Sopenharmony_ci *((char *) mempcpy (buf, hdr->ar_size, sizeof (hdr->ar_size))) = '\0'; 763da0c48c4Sopenharmony_ci string = buf; 764da0c48c4Sopenharmony_ci } 765da0c48c4Sopenharmony_ci 766da0c48c4Sopenharmony_ci /* atol expects to see at least one digit. 767da0c48c4Sopenharmony_ci It also cannot be negative (-). */ 768da0c48c4Sopenharmony_ci if (!isdigit(string[0])) 769da0c48c4Sopenharmony_ci return NULL; 770da0c48c4Sopenharmony_ci len = atol (string); 771da0c48c4Sopenharmony_ci 772da0c48c4Sopenharmony_ci if (memcmp (hdr->ar_name, "// ", 16) == 0) 773da0c48c4Sopenharmony_ci break; 774da0c48c4Sopenharmony_ci 775da0c48c4Sopenharmony_ci offset += sizeof (struct ar_hdr) + ((len + 1) & ~1l); 776da0c48c4Sopenharmony_ci } 777da0c48c4Sopenharmony_ci 778da0c48c4Sopenharmony_ci /* Sanity check len early if we can. */ 779da0c48c4Sopenharmony_ci if (elf->map_address != NULL) 780da0c48c4Sopenharmony_ci { 781da0c48c4Sopenharmony_ci if (len > elf->maximum_size - offset - sizeof (struct ar_hdr)) 782da0c48c4Sopenharmony_ci return NULL; 783da0c48c4Sopenharmony_ci } 784da0c48c4Sopenharmony_ci 785da0c48c4Sopenharmony_ci /* Due to the stupid format of the long name table entry (which are not 786da0c48c4Sopenharmony_ci NUL terminted) we have to provide an appropriate representation anyhow. 787da0c48c4Sopenharmony_ci Therefore we always make a copy which has the appropriate form. */ 788da0c48c4Sopenharmony_ci newp = malloc (len); 789da0c48c4Sopenharmony_ci if (newp != NULL) 790da0c48c4Sopenharmony_ci { 791da0c48c4Sopenharmony_ci char *runp; 792da0c48c4Sopenharmony_ci 793da0c48c4Sopenharmony_ci if (elf->map_address != NULL) 794da0c48c4Sopenharmony_ci { 795da0c48c4Sopenharmony_ci /* Simply copy it over. */ 796da0c48c4Sopenharmony_ci elf->state.ar.long_names = (char *) memcpy (newp, 797da0c48c4Sopenharmony_ci elf->map_address + offset 798da0c48c4Sopenharmony_ci + sizeof (struct ar_hdr), 799da0c48c4Sopenharmony_ci len); 800da0c48c4Sopenharmony_ci } 801da0c48c4Sopenharmony_ci else 802da0c48c4Sopenharmony_ci { 803da0c48c4Sopenharmony_ci if (unlikely ((size_t) pread_retry (elf->fildes, newp, len, 804da0c48c4Sopenharmony_ci elf->start_offset + offset 805da0c48c4Sopenharmony_ci + sizeof (struct ar_hdr)) 806da0c48c4Sopenharmony_ci != len)) 807da0c48c4Sopenharmony_ci { 808da0c48c4Sopenharmony_ci /* We were not able to read all data. */ 809da0c48c4Sopenharmony_ci free (newp); 810da0c48c4Sopenharmony_ci elf->state.ar.long_names = NULL; 811da0c48c4Sopenharmony_ci return NULL; 812da0c48c4Sopenharmony_ci } 813da0c48c4Sopenharmony_ci elf->state.ar.long_names = newp; 814da0c48c4Sopenharmony_ci } 815da0c48c4Sopenharmony_ci 816da0c48c4Sopenharmony_ci elf->state.ar.long_names_len = len; 817da0c48c4Sopenharmony_ci 818da0c48c4Sopenharmony_ci /* Now NUL-terminate the strings. */ 819da0c48c4Sopenharmony_ci runp = newp; 820da0c48c4Sopenharmony_ci while (1) 821da0c48c4Sopenharmony_ci { 822da0c48c4Sopenharmony_ci char *startp = runp; 823da0c48c4Sopenharmony_ci runp = (char *) memchr (runp, '/', newp + len - runp); 824da0c48c4Sopenharmony_ci if (runp == NULL) 825da0c48c4Sopenharmony_ci { 826da0c48c4Sopenharmony_ci /* This was the last entry. Clear any left overs. */ 827da0c48c4Sopenharmony_ci memset (startp, '\0', newp + len - startp); 828da0c48c4Sopenharmony_ci break; 829da0c48c4Sopenharmony_ci } 830da0c48c4Sopenharmony_ci 831da0c48c4Sopenharmony_ci /* NUL-terminate the string. */ 832da0c48c4Sopenharmony_ci *runp++ = '\0'; 833da0c48c4Sopenharmony_ci 834da0c48c4Sopenharmony_ci /* A sanity check. Somebody might have generated invalid 835da0c48c4Sopenharmony_ci archive. */ 836da0c48c4Sopenharmony_ci if (runp >= newp + len) 837da0c48c4Sopenharmony_ci break; 838da0c48c4Sopenharmony_ci } 839da0c48c4Sopenharmony_ci } 840da0c48c4Sopenharmony_ci 841da0c48c4Sopenharmony_ci return newp; 842da0c48c4Sopenharmony_ci} 843da0c48c4Sopenharmony_ci 844da0c48c4Sopenharmony_ci 845da0c48c4Sopenharmony_ci/* Read the next archive header. */ 846da0c48c4Sopenharmony_ciint 847da0c48c4Sopenharmony_ciinternal_function 848da0c48c4Sopenharmony_ci__libelf_next_arhdr_wrlock (Elf *elf) 849da0c48c4Sopenharmony_ci{ 850da0c48c4Sopenharmony_ci struct ar_hdr *ar_hdr; 851da0c48c4Sopenharmony_ci Elf_Arhdr *elf_ar_hdr; 852da0c48c4Sopenharmony_ci 853da0c48c4Sopenharmony_ci if (elf->map_address != NULL) 854da0c48c4Sopenharmony_ci { 855da0c48c4Sopenharmony_ci /* See whether this entry is in the file. */ 856da0c48c4Sopenharmony_ci if (unlikely ((size_t) elf->state.ar.offset 857da0c48c4Sopenharmony_ci > elf->start_offset + elf->maximum_size 858da0c48c4Sopenharmony_ci || (elf->start_offset + elf->maximum_size 859da0c48c4Sopenharmony_ci - elf->state.ar.offset) < sizeof (struct ar_hdr))) 860da0c48c4Sopenharmony_ci { 861da0c48c4Sopenharmony_ci /* This record is not anymore in the file. */ 862da0c48c4Sopenharmony_ci __libelf_seterrno (ELF_E_RANGE); 863da0c48c4Sopenharmony_ci return -1; 864da0c48c4Sopenharmony_ci } 865da0c48c4Sopenharmony_ci ar_hdr = (struct ar_hdr *) (elf->map_address + elf->state.ar.offset); 866da0c48c4Sopenharmony_ci } 867da0c48c4Sopenharmony_ci else 868da0c48c4Sopenharmony_ci { 869da0c48c4Sopenharmony_ci ar_hdr = &elf->state.ar.ar_hdr; 870da0c48c4Sopenharmony_ci 871da0c48c4Sopenharmony_ci if (unlikely (pread_retry (elf->fildes, ar_hdr, sizeof (struct ar_hdr), 872da0c48c4Sopenharmony_ci elf->state.ar.offset) 873da0c48c4Sopenharmony_ci != sizeof (struct ar_hdr))) 874da0c48c4Sopenharmony_ci { 875da0c48c4Sopenharmony_ci /* Something went wrong while reading the file. */ 876da0c48c4Sopenharmony_ci __libelf_seterrno (ELF_E_RANGE); 877da0c48c4Sopenharmony_ci return -1; 878da0c48c4Sopenharmony_ci } 879da0c48c4Sopenharmony_ci } 880da0c48c4Sopenharmony_ci 881da0c48c4Sopenharmony_ci /* One little consistency check. */ 882da0c48c4Sopenharmony_ci if (unlikely (memcmp (ar_hdr->ar_fmag, ARFMAG, 2) != 0)) 883da0c48c4Sopenharmony_ci { 884da0c48c4Sopenharmony_ci /* This is no valid archive. */ 885da0c48c4Sopenharmony_ci __libelf_seterrno (ELF_E_ARCHIVE_FMAG); 886da0c48c4Sopenharmony_ci return -1; 887da0c48c4Sopenharmony_ci } 888da0c48c4Sopenharmony_ci 889da0c48c4Sopenharmony_ci /* Copy the raw name over to a NUL terminated buffer. */ 890da0c48c4Sopenharmony_ci *((char *) mempcpy (elf->state.ar.raw_name, ar_hdr->ar_name, 16)) = '\0'; 891da0c48c4Sopenharmony_ci 892da0c48c4Sopenharmony_ci elf_ar_hdr = &elf->state.ar.elf_ar_hdr; 893da0c48c4Sopenharmony_ci 894da0c48c4Sopenharmony_ci /* Now convert the `struct ar_hdr' into `Elf_Arhdr'. 895da0c48c4Sopenharmony_ci Determine whether this is a special entry. */ 896da0c48c4Sopenharmony_ci if (ar_hdr->ar_name[0] == '/') 897da0c48c4Sopenharmony_ci { 898da0c48c4Sopenharmony_ci if (ar_hdr->ar_name[1] == ' ' 899da0c48c4Sopenharmony_ci && memcmp (ar_hdr->ar_name, "/ ", 16) == 0) 900da0c48c4Sopenharmony_ci /* This is the index. */ 901da0c48c4Sopenharmony_ci elf_ar_hdr->ar_name = memcpy (elf->state.ar.ar_name, "/", 2); 902da0c48c4Sopenharmony_ci else if (ar_hdr->ar_name[1] == 'S' 903da0c48c4Sopenharmony_ci && memcmp (ar_hdr->ar_name, "/SYM64/ ", 16) == 0) 904da0c48c4Sopenharmony_ci /* 64-bit index. */ 905da0c48c4Sopenharmony_ci elf_ar_hdr->ar_name = memcpy (elf->state.ar.ar_name, "/SYM64/", 8); 906da0c48c4Sopenharmony_ci else if (ar_hdr->ar_name[1] == '/' 907da0c48c4Sopenharmony_ci && memcmp (ar_hdr->ar_name, "// ", 16) == 0) 908da0c48c4Sopenharmony_ci /* This is the array with the long names. */ 909da0c48c4Sopenharmony_ci elf_ar_hdr->ar_name = memcpy (elf->state.ar.ar_name, "//", 3); 910da0c48c4Sopenharmony_ci else if (likely (isdigit (ar_hdr->ar_name[1]))) 911da0c48c4Sopenharmony_ci { 912da0c48c4Sopenharmony_ci size_t offset; 913da0c48c4Sopenharmony_ci 914da0c48c4Sopenharmony_ci /* This is a long name. First we have to read the long name 915da0c48c4Sopenharmony_ci table, if this hasn't happened already. */ 916da0c48c4Sopenharmony_ci if (unlikely (elf->state.ar.long_names == NULL 917da0c48c4Sopenharmony_ci && read_long_names (elf) == NULL)) 918da0c48c4Sopenharmony_ci { 919da0c48c4Sopenharmony_ci /* No long name table although it is reference. The archive is 920da0c48c4Sopenharmony_ci broken. */ 921da0c48c4Sopenharmony_ci __libelf_seterrno (ELF_E_INVALID_ARCHIVE); 922da0c48c4Sopenharmony_ci return -1; 923da0c48c4Sopenharmony_ci } 924da0c48c4Sopenharmony_ci 925da0c48c4Sopenharmony_ci offset = atol (ar_hdr->ar_name + 1); 926da0c48c4Sopenharmony_ci if (unlikely (offset >= elf->state.ar.long_names_len)) 927da0c48c4Sopenharmony_ci { 928da0c48c4Sopenharmony_ci /* The index in the long name table is larger than the table. */ 929da0c48c4Sopenharmony_ci __libelf_seterrno (ELF_E_INVALID_ARCHIVE); 930da0c48c4Sopenharmony_ci return -1; 931da0c48c4Sopenharmony_ci } 932da0c48c4Sopenharmony_ci elf_ar_hdr->ar_name = elf->state.ar.long_names + offset; 933da0c48c4Sopenharmony_ci } 934da0c48c4Sopenharmony_ci else 935da0c48c4Sopenharmony_ci { 936da0c48c4Sopenharmony_ci /* This is none of the known special entries. */ 937da0c48c4Sopenharmony_ci __libelf_seterrno (ELF_E_INVALID_ARCHIVE); 938da0c48c4Sopenharmony_ci return -1; 939da0c48c4Sopenharmony_ci } 940da0c48c4Sopenharmony_ci } 941da0c48c4Sopenharmony_ci else 942da0c48c4Sopenharmony_ci { 943da0c48c4Sopenharmony_ci char *endp; 944da0c48c4Sopenharmony_ci 945da0c48c4Sopenharmony_ci /* It is a normal entry. Copy over the name. */ 946da0c48c4Sopenharmony_ci endp = (char *) memccpy (elf->state.ar.ar_name, ar_hdr->ar_name, 947da0c48c4Sopenharmony_ci '/', 16); 948da0c48c4Sopenharmony_ci if (endp != NULL) 949da0c48c4Sopenharmony_ci endp[-1] = '\0'; 950da0c48c4Sopenharmony_ci else 951da0c48c4Sopenharmony_ci { 952da0c48c4Sopenharmony_ci /* In the old BSD style of archive, there is no / terminator. 953da0c48c4Sopenharmony_ci Instead, there is space padding at the end of the name. */ 954da0c48c4Sopenharmony_ci size_t i = 15; 955da0c48c4Sopenharmony_ci do 956da0c48c4Sopenharmony_ci elf->state.ar.ar_name[i] = '\0'; 957da0c48c4Sopenharmony_ci while (i > 0 && elf->state.ar.ar_name[--i] == ' '); 958da0c48c4Sopenharmony_ci } 959da0c48c4Sopenharmony_ci 960da0c48c4Sopenharmony_ci elf_ar_hdr->ar_name = elf->state.ar.ar_name; 961da0c48c4Sopenharmony_ci } 962da0c48c4Sopenharmony_ci 963da0c48c4Sopenharmony_ci if (unlikely (ar_hdr->ar_size[0] == ' ')) 964da0c48c4Sopenharmony_ci /* Something is really wrong. We cannot live without a size for 965da0c48c4Sopenharmony_ci the member since it will not be possible to find the next 966da0c48c4Sopenharmony_ci archive member. */ 967da0c48c4Sopenharmony_ci { 968da0c48c4Sopenharmony_ci __libelf_seterrno (ELF_E_INVALID_ARCHIVE); 969da0c48c4Sopenharmony_ci return -1; 970da0c48c4Sopenharmony_ci } 971da0c48c4Sopenharmony_ci 972da0c48c4Sopenharmony_ci /* Since there are no specialized functions to convert ASCII to 973da0c48c4Sopenharmony_ci time_t, uid_t, gid_t, mode_t, and off_t we use either atol or 974da0c48c4Sopenharmony_ci atoll depending on the size of the types. We are also prepared 975da0c48c4Sopenharmony_ci for the case where the whole field in the `struct ar_hdr' is 976da0c48c4Sopenharmony_ci filled in which case we cannot simply use atol/l but instead have 977da0c48c4Sopenharmony_ci to create a temporary copy. Note that all fields use decimal 978da0c48c4Sopenharmony_ci encoding, except ar_mode which uses octal. */ 979da0c48c4Sopenharmony_ci 980da0c48c4Sopenharmony_ci#define INT_FIELD(FIELD) \ 981da0c48c4Sopenharmony_ci do \ 982da0c48c4Sopenharmony_ci { \ 983da0c48c4Sopenharmony_ci char buf[sizeof (ar_hdr->FIELD) + 1]; \ 984da0c48c4Sopenharmony_ci const char *string = ar_hdr->FIELD; \ 985da0c48c4Sopenharmony_ci if (ar_hdr->FIELD[sizeof (ar_hdr->FIELD) - 1] != ' ') \ 986da0c48c4Sopenharmony_ci { \ 987da0c48c4Sopenharmony_ci *((char *) mempcpy (buf, ar_hdr->FIELD, sizeof (ar_hdr->FIELD))) \ 988da0c48c4Sopenharmony_ci = '\0'; \ 989da0c48c4Sopenharmony_ci string = buf; \ 990da0c48c4Sopenharmony_ci } \ 991da0c48c4Sopenharmony_ci if (sizeof (elf_ar_hdr->FIELD) <= sizeof (long int)) \ 992da0c48c4Sopenharmony_ci elf_ar_hdr->FIELD = (__typeof (elf_ar_hdr->FIELD)) atol (string); \ 993da0c48c4Sopenharmony_ci else \ 994da0c48c4Sopenharmony_ci elf_ar_hdr->FIELD = (__typeof (elf_ar_hdr->FIELD)) atoll (string); \ 995da0c48c4Sopenharmony_ci } \ 996da0c48c4Sopenharmony_ci while (0) 997da0c48c4Sopenharmony_ci 998da0c48c4Sopenharmony_ci#define OCT_FIELD(FIELD) \ 999da0c48c4Sopenharmony_ci do \ 1000da0c48c4Sopenharmony_ci { \ 1001da0c48c4Sopenharmony_ci char buf[sizeof (ar_hdr->FIELD) + 1]; \ 1002da0c48c4Sopenharmony_ci const char *string = ar_hdr->FIELD; \ 1003da0c48c4Sopenharmony_ci if (ar_hdr->FIELD[sizeof (ar_hdr->FIELD) - 1] != ' ') \ 1004da0c48c4Sopenharmony_ci { \ 1005da0c48c4Sopenharmony_ci *((char *) mempcpy (buf, ar_hdr->FIELD, sizeof (ar_hdr->FIELD))) \ 1006da0c48c4Sopenharmony_ci = '\0'; \ 1007da0c48c4Sopenharmony_ci string = buf; \ 1008da0c48c4Sopenharmony_ci } \ 1009da0c48c4Sopenharmony_ci if (sizeof (elf_ar_hdr->FIELD) <= sizeof (long int)) \ 1010da0c48c4Sopenharmony_ci elf_ar_hdr->FIELD \ 1011da0c48c4Sopenharmony_ci = (__typeof (elf_ar_hdr->FIELD)) strtol (string, NULL, 8); \ 1012da0c48c4Sopenharmony_ci else \ 1013da0c48c4Sopenharmony_ci elf_ar_hdr->FIELD \ 1014da0c48c4Sopenharmony_ci = (__typeof (elf_ar_hdr->FIELD)) strtoll (string, NULL, 8); \ 1015da0c48c4Sopenharmony_ci } \ 1016da0c48c4Sopenharmony_ci while (0) 1017da0c48c4Sopenharmony_ci 1018da0c48c4Sopenharmony_ci INT_FIELD (ar_date); 1019da0c48c4Sopenharmony_ci INT_FIELD (ar_uid); 1020da0c48c4Sopenharmony_ci INT_FIELD (ar_gid); 1021da0c48c4Sopenharmony_ci OCT_FIELD (ar_mode); 1022da0c48c4Sopenharmony_ci INT_FIELD (ar_size); 1023da0c48c4Sopenharmony_ci 1024da0c48c4Sopenharmony_ci if (elf_ar_hdr->ar_size < 0) 1025da0c48c4Sopenharmony_ci { 1026da0c48c4Sopenharmony_ci __libelf_seterrno (ELF_E_INVALID_ARCHIVE); 1027da0c48c4Sopenharmony_ci return -1; 1028da0c48c4Sopenharmony_ci } 1029da0c48c4Sopenharmony_ci 1030da0c48c4Sopenharmony_ci /* Truncated file? */ 1031da0c48c4Sopenharmony_ci size_t maxsize; 1032da0c48c4Sopenharmony_ci maxsize = (elf->start_offset + elf->maximum_size 1033da0c48c4Sopenharmony_ci - elf->state.ar.offset - sizeof (struct ar_hdr)); 1034da0c48c4Sopenharmony_ci if ((size_t) elf_ar_hdr->ar_size > maxsize) 1035da0c48c4Sopenharmony_ci elf_ar_hdr->ar_size = maxsize; 1036da0c48c4Sopenharmony_ci 1037da0c48c4Sopenharmony_ci return 0; 1038da0c48c4Sopenharmony_ci} 1039da0c48c4Sopenharmony_ci 1040da0c48c4Sopenharmony_ci 1041da0c48c4Sopenharmony_ci/* We were asked to return a clone of an existing descriptor. This 1042da0c48c4Sopenharmony_ci function must be called with the lock on the parent descriptor 1043da0c48c4Sopenharmony_ci being held. */ 1044da0c48c4Sopenharmony_cistatic Elf * 1045da0c48c4Sopenharmony_cidup_elf (int fildes, Elf_Cmd cmd, Elf *ref) 1046da0c48c4Sopenharmony_ci{ 1047da0c48c4Sopenharmony_ci struct Elf *result; 1048da0c48c4Sopenharmony_ci 1049da0c48c4Sopenharmony_ci if (fildes == -1) 1050da0c48c4Sopenharmony_ci /* Allow the user to pass -1 as the file descriptor for the new file. */ 1051da0c48c4Sopenharmony_ci fildes = ref->fildes; 1052da0c48c4Sopenharmony_ci /* The file descriptor better should be the same. If it was disconnected 1053da0c48c4Sopenharmony_ci already (using `elf_cntl') we do not test it. */ 1054da0c48c4Sopenharmony_ci else if (unlikely (ref->fildes != -1 && fildes != ref->fildes)) 1055da0c48c4Sopenharmony_ci { 1056da0c48c4Sopenharmony_ci __libelf_seterrno (ELF_E_FD_MISMATCH); 1057da0c48c4Sopenharmony_ci return NULL; 1058da0c48c4Sopenharmony_ci } 1059da0c48c4Sopenharmony_ci 1060da0c48c4Sopenharmony_ci /* The mode must allow reading. I.e., a descriptor creating with a 1061da0c48c4Sopenharmony_ci command different then ELF_C_READ, ELF_C_WRITE and ELF_C_RDWR is 1062da0c48c4Sopenharmony_ci not allowed. */ 1063da0c48c4Sopenharmony_ci if (unlikely (ref->cmd != ELF_C_READ && ref->cmd != ELF_C_READ_MMAP 1064da0c48c4Sopenharmony_ci && ref->cmd != ELF_C_WRITE && ref->cmd != ELF_C_WRITE_MMAP 1065da0c48c4Sopenharmony_ci && ref->cmd != ELF_C_RDWR && ref->cmd != ELF_C_RDWR_MMAP 1066da0c48c4Sopenharmony_ci && ref->cmd != ELF_C_READ_MMAP_PRIVATE)) 1067da0c48c4Sopenharmony_ci { 1068da0c48c4Sopenharmony_ci __libelf_seterrno (ELF_E_INVALID_OP); 1069da0c48c4Sopenharmony_ci return NULL; 1070da0c48c4Sopenharmony_ci } 1071da0c48c4Sopenharmony_ci 1072da0c48c4Sopenharmony_ci /* Now it is time to distinguish between reading normal files and 1073da0c48c4Sopenharmony_ci archives. Normal files can easily be handled be incrementing the 1074da0c48c4Sopenharmony_ci reference counter and return the same descriptor. */ 1075da0c48c4Sopenharmony_ci if (ref->kind != ELF_K_AR) 1076da0c48c4Sopenharmony_ci { 1077da0c48c4Sopenharmony_ci ++ref->ref_count; 1078da0c48c4Sopenharmony_ci return ref; 1079da0c48c4Sopenharmony_ci } 1080da0c48c4Sopenharmony_ci 1081da0c48c4Sopenharmony_ci /* This is an archive. We must create a descriptor for the archive 1082da0c48c4Sopenharmony_ci member the internal pointer of the archive file descriptor is 1083da0c48c4Sopenharmony_ci pointing to. First read the header of the next member if this 1084da0c48c4Sopenharmony_ci has not happened already. */ 1085da0c48c4Sopenharmony_ci if (ref->state.ar.elf_ar_hdr.ar_name == NULL 1086da0c48c4Sopenharmony_ci && __libelf_next_arhdr_wrlock (ref) != 0) 1087da0c48c4Sopenharmony_ci /* Something went wrong. Maybe there is no member left. */ 1088da0c48c4Sopenharmony_ci return NULL; 1089da0c48c4Sopenharmony_ci 1090da0c48c4Sopenharmony_ci /* We have all the information we need about the next archive member. 1091da0c48c4Sopenharmony_ci Now create a descriptor for it. */ 1092da0c48c4Sopenharmony_ci result = read_file (fildes, ref->state.ar.offset + sizeof (struct ar_hdr), 1093da0c48c4Sopenharmony_ci ref->state.ar.elf_ar_hdr.ar_size, cmd, ref); 1094da0c48c4Sopenharmony_ci 1095da0c48c4Sopenharmony_ci /* Enlist this new descriptor in the list of children. */ 1096da0c48c4Sopenharmony_ci if (result != NULL) 1097da0c48c4Sopenharmony_ci { 1098da0c48c4Sopenharmony_ci result->next = ref->state.ar.children; 1099da0c48c4Sopenharmony_ci ref->state.ar.children = result; 1100da0c48c4Sopenharmony_ci } 1101da0c48c4Sopenharmony_ci 1102da0c48c4Sopenharmony_ci return result; 1103da0c48c4Sopenharmony_ci} 1104da0c48c4Sopenharmony_ci 1105da0c48c4Sopenharmony_ci 1106da0c48c4Sopenharmony_ci/* Return descriptor for empty file ready for writing. */ 1107da0c48c4Sopenharmony_cistatic struct Elf * 1108da0c48c4Sopenharmony_ciwrite_file (int fd, Elf_Cmd cmd) 1109da0c48c4Sopenharmony_ci{ 1110da0c48c4Sopenharmony_ci /* We simply create an empty `Elf' structure. */ 1111da0c48c4Sopenharmony_ci#define NSCNSALLOC 10 1112da0c48c4Sopenharmony_ci Elf *result = allocate_elf (fd, NULL, 0, 0, cmd, NULL, ELF_K_ELF, 1113da0c48c4Sopenharmony_ci NSCNSALLOC * sizeof (Elf_Scn)); 1114da0c48c4Sopenharmony_ci 1115da0c48c4Sopenharmony_ci if (result != NULL) 1116da0c48c4Sopenharmony_ci { 1117da0c48c4Sopenharmony_ci /* We have to write to the file in any case. */ 1118da0c48c4Sopenharmony_ci result->flags = ELF_F_DIRTY; 1119da0c48c4Sopenharmony_ci 1120da0c48c4Sopenharmony_ci /* Some more or less arbitrary value. */ 1121da0c48c4Sopenharmony_ci result->state.elf.scnincr = NSCNSALLOC; 1122da0c48c4Sopenharmony_ci 1123da0c48c4Sopenharmony_ci /* We have allocated room for some sections. */ 1124da0c48c4Sopenharmony_ci assert (offsetof (struct Elf, state.elf32.scns) 1125da0c48c4Sopenharmony_ci == offsetof (struct Elf, state.elf64.scns)); 1126da0c48c4Sopenharmony_ci result->state.elf.scns_last = &result->state.elf32.scns; 1127da0c48c4Sopenharmony_ci result->state.elf32.scns.max = NSCNSALLOC; 1128da0c48c4Sopenharmony_ci } 1129da0c48c4Sopenharmony_ci 1130da0c48c4Sopenharmony_ci return result; 1131da0c48c4Sopenharmony_ci} 1132da0c48c4Sopenharmony_ci 1133da0c48c4Sopenharmony_ci/* Lock if necessary before dup an archive. */ 1134da0c48c4Sopenharmony_cistatic inline Elf * 1135da0c48c4Sopenharmony_cilock_dup_elf (int fildes, Elf_Cmd cmd, Elf *ref) 1136da0c48c4Sopenharmony_ci{ 1137da0c48c4Sopenharmony_ci /* We need wrlock to dup an archive. */ 1138da0c48c4Sopenharmony_ci if (ref->kind == ELF_K_AR) 1139da0c48c4Sopenharmony_ci { 1140da0c48c4Sopenharmony_ci rwlock_unlock (ref->lock); 1141da0c48c4Sopenharmony_ci rwlock_wrlock (ref->lock); 1142da0c48c4Sopenharmony_ci } 1143da0c48c4Sopenharmony_ci /* Duplicate the descriptor. */ 1144da0c48c4Sopenharmony_ci return dup_elf (fildes, cmd, ref); 1145da0c48c4Sopenharmony_ci} 1146da0c48c4Sopenharmony_ci 1147da0c48c4Sopenharmony_ci/* Return a descriptor for the file belonging to FILDES. */ 1148da0c48c4Sopenharmony_ciElf * 1149da0c48c4Sopenharmony_cielf_begin (int fildes, Elf_Cmd cmd, Elf *ref) 1150da0c48c4Sopenharmony_ci{ 1151da0c48c4Sopenharmony_ci Elf *retval; 1152da0c48c4Sopenharmony_ci 1153da0c48c4Sopenharmony_ci if (unlikely (__libelf_version != EV_CURRENT)) 1154da0c48c4Sopenharmony_ci { 1155da0c48c4Sopenharmony_ci /* Version wasn't set so far. */ 1156da0c48c4Sopenharmony_ci __libelf_seterrno (ELF_E_NO_VERSION); 1157da0c48c4Sopenharmony_ci return NULL; 1158da0c48c4Sopenharmony_ci } 1159da0c48c4Sopenharmony_ci 1160da0c48c4Sopenharmony_ci if (ref != NULL) 1161da0c48c4Sopenharmony_ci /* Make sure the descriptor is not suddenly going away. */ 1162da0c48c4Sopenharmony_ci rwlock_rdlock (ref->lock); 1163da0c48c4Sopenharmony_ci else if (unlikely (fcntl (fildes, F_GETFD) == -1 && errno == EBADF)) 1164da0c48c4Sopenharmony_ci { 1165da0c48c4Sopenharmony_ci /* We cannot do anything productive without a file descriptor. */ 1166da0c48c4Sopenharmony_ci __libelf_seterrno (ELF_E_INVALID_FILE); 1167da0c48c4Sopenharmony_ci return NULL; 1168da0c48c4Sopenharmony_ci } 1169da0c48c4Sopenharmony_ci 1170da0c48c4Sopenharmony_ci switch (cmd) 1171da0c48c4Sopenharmony_ci { 1172da0c48c4Sopenharmony_ci case ELF_C_NULL: 1173da0c48c4Sopenharmony_ci /* We simply return a NULL pointer. */ 1174da0c48c4Sopenharmony_ci retval = NULL; 1175da0c48c4Sopenharmony_ci break; 1176da0c48c4Sopenharmony_ci 1177da0c48c4Sopenharmony_ci case ELF_C_READ_MMAP_PRIVATE: 1178da0c48c4Sopenharmony_ci /* If we have a reference it must also be opened this way. */ 1179da0c48c4Sopenharmony_ci if (unlikely (ref != NULL && ref->cmd != ELF_C_READ_MMAP_PRIVATE)) 1180da0c48c4Sopenharmony_ci { 1181da0c48c4Sopenharmony_ci __libelf_seterrno (ELF_E_INVALID_CMD); 1182da0c48c4Sopenharmony_ci retval = NULL; 1183da0c48c4Sopenharmony_ci break; 1184da0c48c4Sopenharmony_ci } 1185da0c48c4Sopenharmony_ci FALLTHROUGH; 1186da0c48c4Sopenharmony_ci 1187da0c48c4Sopenharmony_ci case ELF_C_READ: 1188da0c48c4Sopenharmony_ci case ELF_C_READ_MMAP: 1189da0c48c4Sopenharmony_ci if (ref != NULL) 1190da0c48c4Sopenharmony_ci retval = lock_dup_elf (fildes, cmd, ref); 1191da0c48c4Sopenharmony_ci else 1192da0c48c4Sopenharmony_ci /* Create descriptor for existing file. */ 1193da0c48c4Sopenharmony_ci retval = read_file (fildes, 0, ~((size_t) 0), cmd, NULL); 1194da0c48c4Sopenharmony_ci break; 1195da0c48c4Sopenharmony_ci 1196da0c48c4Sopenharmony_ci case ELF_C_RDWR: 1197da0c48c4Sopenharmony_ci case ELF_C_RDWR_MMAP: 1198da0c48c4Sopenharmony_ci /* If we have a REF object it must also be opened using this 1199da0c48c4Sopenharmony_ci command. */ 1200da0c48c4Sopenharmony_ci if (ref != NULL) 1201da0c48c4Sopenharmony_ci { 1202da0c48c4Sopenharmony_ci if (unlikely (ref->cmd != ELF_C_RDWR && ref->cmd != ELF_C_RDWR_MMAP 1203da0c48c4Sopenharmony_ci && ref->cmd != ELF_C_WRITE 1204da0c48c4Sopenharmony_ci && ref->cmd != ELF_C_WRITE_MMAP)) 1205da0c48c4Sopenharmony_ci { 1206da0c48c4Sopenharmony_ci /* This is not ok. REF must also be opened for writing. */ 1207da0c48c4Sopenharmony_ci __libelf_seterrno (ELF_E_INVALID_CMD); 1208da0c48c4Sopenharmony_ci retval = NULL; 1209da0c48c4Sopenharmony_ci } 1210da0c48c4Sopenharmony_ci else 1211da0c48c4Sopenharmony_ci retval = lock_dup_elf (fildes, cmd, ref); 1212da0c48c4Sopenharmony_ci } 1213da0c48c4Sopenharmony_ci else 1214da0c48c4Sopenharmony_ci /* Create descriptor for existing file. */ 1215da0c48c4Sopenharmony_ci retval = read_file (fildes, 0, ~((size_t) 0), cmd, NULL); 1216da0c48c4Sopenharmony_ci break; 1217da0c48c4Sopenharmony_ci 1218da0c48c4Sopenharmony_ci case ELF_C_WRITE: 1219da0c48c4Sopenharmony_ci case ELF_C_WRITE_MMAP: 1220da0c48c4Sopenharmony_ci /* We ignore REF and prepare a descriptor to write a new file. */ 1221da0c48c4Sopenharmony_ci retval = write_file (fildes, cmd); 1222da0c48c4Sopenharmony_ci break; 1223da0c48c4Sopenharmony_ci 1224da0c48c4Sopenharmony_ci default: 1225da0c48c4Sopenharmony_ci __libelf_seterrno (ELF_E_INVALID_CMD); 1226da0c48c4Sopenharmony_ci retval = NULL; 1227da0c48c4Sopenharmony_ci break; 1228da0c48c4Sopenharmony_ci } 1229da0c48c4Sopenharmony_ci 1230da0c48c4Sopenharmony_ci /* Release the lock. */ 1231da0c48c4Sopenharmony_ci if (ref != NULL) 1232da0c48c4Sopenharmony_ci rwlock_unlock (ref->lock); 1233da0c48c4Sopenharmony_ci 1234da0c48c4Sopenharmony_ci return retval; 1235da0c48c4Sopenharmony_ci} 1236da0c48c4Sopenharmony_ciINTDEF(elf_begin) 1237