Blame libelf/elf_begin.c

Packit Service 97d2fb
/* Create descriptor for processing file.
Packit Service 97d2fb
   Copyright (C) 1998-2010, 2012, 2014, 2015, 2016 Red Hat, Inc.
Packit Service 97d2fb
   This file is part of elfutils.
Packit Service 97d2fb
   Written by Ulrich Drepper <drepper@redhat.com>, 1998.
Packit Service 97d2fb
Packit Service 97d2fb
   This file is free software; you can redistribute it and/or modify
Packit Service 97d2fb
   it under the terms of either
Packit Service 97d2fb
Packit Service 97d2fb
     * the GNU Lesser General Public License as published by the Free
Packit Service 97d2fb
       Software Foundation; either version 3 of the License, or (at
Packit Service 97d2fb
       your option) any later version
Packit Service 97d2fb
Packit Service 97d2fb
   or
Packit Service 97d2fb
Packit Service 97d2fb
     * the GNU General Public License as published by the Free
Packit Service 97d2fb
       Software Foundation; either version 2 of the License, or (at
Packit Service 97d2fb
       your option) any later version
Packit Service 97d2fb
Packit Service 97d2fb
   or both in parallel, as here.
Packit Service 97d2fb
Packit Service 97d2fb
   elfutils is distributed in the hope that it will be useful, but
Packit Service 97d2fb
   WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 97d2fb
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit Service 97d2fb
   General Public License for more details.
Packit Service 97d2fb
Packit Service 97d2fb
   You should have received copies of the GNU General Public License and
Packit Service 97d2fb
   the GNU Lesser General Public License along with this program.  If
Packit Service 97d2fb
   not, see <http://www.gnu.org/licenses/>.  */
Packit Service 97d2fb
Packit Service 97d2fb
#ifdef HAVE_CONFIG_H
Packit Service 97d2fb
# include <config.h>
Packit Service 97d2fb
#endif
Packit Service 97d2fb
Packit Service 97d2fb
#include <assert.h>
Packit Service 97d2fb
#include <ctype.h>
Packit Service 97d2fb
#include <errno.h>
Packit Service 97d2fb
#include <fcntl.h>
Packit Service 97d2fb
#include <stdbool.h>
Packit Service 97d2fb
#include <stddef.h>
Packit Service 97d2fb
#include <string.h>
Packit Service 97d2fb
#include <unistd.h>
Packit Service 97d2fb
#include <sys/mman.h>
Packit Service 97d2fb
#include <sys/stat.h>
Packit Service 97d2fb
Packit Service 97d2fb
#include <system.h>
Packit Service 97d2fb
#include "libelfP.h"
Packit Service 97d2fb
#include "common.h"
Packit Service 97d2fb
Packit Service 97d2fb
Packit Service 97d2fb
/* Create descriptor for archive in memory.  */
Packit Service 97d2fb
static inline Elf *
Packit Service 97d2fb
file_read_ar (int fildes, void *map_address, off_t offset, size_t maxsize,
Packit Service 97d2fb
	      Elf_Cmd cmd, Elf *parent)
Packit Service 97d2fb
{
Packit Service 97d2fb
  Elf *elf;
Packit Service 97d2fb
Packit Service 97d2fb
  /* Create a descriptor.  */
Packit Service 97d2fb
  elf = allocate_elf (fildes, map_address, offset, maxsize, cmd, parent,
Packit Service 97d2fb
                      ELF_K_AR, 0);
Packit Service 97d2fb
  if (elf != NULL)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      /* We don't read all the symbol tables in advance.  All this will
Packit Service 97d2fb
	 happen on demand.  */
Packit Service 97d2fb
      elf->state.ar.offset = offset + SARMAG;
Packit Service 97d2fb
Packit Service 97d2fb
      elf->state.ar.elf_ar_hdr.ar_rawname = elf->state.ar.raw_name;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  return elf;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
Packit Service 97d2fb
static size_t
Packit Service 97d2fb
get_shnum (void *map_address, unsigned char *e_ident, int fildes,
Packit Service 97d2fb
	   int64_t offset, size_t maxsize)
Packit Service 97d2fb
{
Packit Service 97d2fb
  size_t result;
Packit Service 97d2fb
  union
Packit Service 97d2fb
  {
Packit Service 97d2fb
    Elf32_Ehdr *e32;
Packit Service 97d2fb
    Elf64_Ehdr *e64;
Packit Service 97d2fb
    void *p;
Packit Service 97d2fb
  } ehdr;
Packit Service 97d2fb
  union
Packit Service 97d2fb
  {
Packit Service 97d2fb
    Elf32_Ehdr e32;
Packit Service 97d2fb
    Elf64_Ehdr e64;
Packit Service 97d2fb
  } ehdr_mem;
Packit Service 97d2fb
  bool is32 = e_ident[EI_CLASS] == ELFCLASS32;
Packit Service 97d2fb
Packit Service 97d2fb
  /* Make the ELF header available.  */
Packit Service 97d2fb
  if (e_ident[EI_DATA] == MY_ELFDATA
Packit Service 97d2fb
      && (ALLOW_UNALIGNED
Packit Service 97d2fb
	  || (((size_t) e_ident
Packit Service 97d2fb
	       & ((is32 ? __alignof__ (Elf32_Ehdr) : __alignof__ (Elf64_Ehdr))
Packit Service 97d2fb
		  - 1)) == 0)))
Packit Service 97d2fb
    ehdr.p = e_ident;
Packit Service 97d2fb
  else
Packit Service 97d2fb
    {
Packit Service 97d2fb
      /* We already read the ELF header.  We have to copy the header
Packit Service 97d2fb
	 since we possibly modify the data here and the caller
Packit Service 97d2fb
	 expects the memory it passes in to be preserved.  */
Packit Service 97d2fb
      ehdr.p = &ehdr_mem;
Packit Service 97d2fb
Packit Service 97d2fb
      if (is32)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  if (ALLOW_UNALIGNED)
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      ehdr_mem.e32.e_shnum = ((Elf32_Ehdr *) e_ident)->e_shnum;
Packit Service 97d2fb
	      ehdr_mem.e32.e_shoff = ((Elf32_Ehdr *) e_ident)->e_shoff;
Packit Service 97d2fb
	    }
Packit Service 97d2fb
	  else
Packit Service 97d2fb
	    memcpy (&ehdr_mem, e_ident, sizeof (Elf32_Ehdr));
Packit Service 97d2fb
Packit Service 97d2fb
	  if (e_ident[EI_DATA] != MY_ELFDATA)
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      CONVERT (ehdr_mem.e32.e_shnum);
Packit Service 97d2fb
	      CONVERT (ehdr_mem.e32.e_shoff);
Packit Service 97d2fb
	    }
Packit Service 97d2fb
	}
Packit Service 97d2fb
      else
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  if (ALLOW_UNALIGNED)
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      ehdr_mem.e64.e_shnum = ((Elf64_Ehdr *) e_ident)->e_shnum;
Packit Service 97d2fb
	      ehdr_mem.e64.e_shoff = ((Elf64_Ehdr *) e_ident)->e_shoff;
Packit Service 97d2fb
	    }
Packit Service 97d2fb
	  else
Packit Service 97d2fb
	    memcpy (&ehdr_mem, e_ident, sizeof (Elf64_Ehdr));
Packit Service 97d2fb
Packit Service 97d2fb
	  if (e_ident[EI_DATA] != MY_ELFDATA)
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      CONVERT (ehdr_mem.e64.e_shnum);
Packit Service 97d2fb
	      CONVERT (ehdr_mem.e64.e_shoff);
Packit Service 97d2fb
	    }
Packit Service 97d2fb
	}
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  if (is32)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      /* Get the number of sections from the ELF header.  */
Packit Service 97d2fb
      result = ehdr.e32->e_shnum;
Packit Service 97d2fb
Packit Service 97d2fb
      if (unlikely (result == 0) && ehdr.e32->e_shoff != 0)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  if (unlikely (ehdr.e32->e_shoff >= maxsize)
Packit Service 97d2fb
	      || unlikely (maxsize - ehdr.e32->e_shoff < sizeof (Elf32_Shdr)))
Packit Service 97d2fb
	    /* Cannot read the first section header.  */
Packit Service 97d2fb
	    return 0;
Packit Service 97d2fb
Packit Service 97d2fb
	  if (likely (map_address != NULL) && e_ident[EI_DATA] == MY_ELFDATA
Packit Service 97d2fb
	      && (ALLOW_UNALIGNED
Packit Service 97d2fb
		  || (((size_t) ((char *) map_address + ehdr.e32->e_shoff))
Packit Service 97d2fb
		      & (__alignof__ (Elf32_Shdr) - 1)) == 0))
Packit Service 97d2fb
	    /* We can directly access the memory.  */
Packit Service 97d2fb
	    result = ((Elf32_Shdr *) ((char *) map_address + ehdr.e32->e_shoff
Packit Service 97d2fb
				      + offset))->sh_size;
Packit Service 97d2fb
	  else
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      Elf32_Word size;
Packit Service 97d2fb
	      ssize_t r;
Packit Service 97d2fb
Packit Service 97d2fb
	      if (likely (map_address != NULL))
Packit Service 97d2fb
		/* gcc will optimize the memcpy to a simple memory
Packit Service 97d2fb
		   access while taking care of alignment issues.  */
Packit Service 97d2fb
		memcpy (&size, &((Elf32_Shdr *) ((char *) map_address
Packit Service 97d2fb
						 + ehdr.e32->e_shoff
Packit Service 97d2fb
						 + offset))->sh_size,
Packit Service 97d2fb
			sizeof (Elf32_Word));
Packit Service 97d2fb
	      else
Packit Service 97d2fb
		if (unlikely ((r = pread_retry (fildes, &size,
Packit Service 97d2fb
						sizeof (Elf32_Word),
Packit Service 97d2fb
						offset + ehdr.e32->e_shoff
Packit Service 97d2fb
						+ offsetof (Elf32_Shdr,
Packit Service 97d2fb
							    sh_size)))
Packit Service 97d2fb
			      != sizeof (Elf32_Word)))
Packit Service 97d2fb
		  {
Packit Service 97d2fb
		    if (r < 0)
Packit Service 97d2fb
		      __libelf_seterrno (ELF_E_INVALID_FILE);
Packit Service 97d2fb
		    else
Packit Service 97d2fb
		      __libelf_seterrno (ELF_E_INVALID_ELF);
Packit Service 97d2fb
		    return (size_t) -1l;
Packit Service 97d2fb
		  }
Packit Service 97d2fb
Packit Service 97d2fb
	      if (e_ident[EI_DATA] != MY_ELFDATA)
Packit Service 97d2fb
		CONVERT (size);
Packit Service 97d2fb
Packit Service 97d2fb
	      result = size;
Packit Service 97d2fb
	    }
Packit Service 97d2fb
	}
Packit Service 97d2fb
Packit Service 97d2fb
      /* If the section headers were truncated, pretend none were there.  */
Packit Service 97d2fb
      if (ehdr.e32->e_shoff > maxsize
Packit Service 97d2fb
	  || maxsize - ehdr.e32->e_shoff < sizeof (Elf32_Shdr) * result)
Packit Service 97d2fb
	result = 0;
Packit Service 97d2fb
    }
Packit Service 97d2fb
  else
Packit Service 97d2fb
    {
Packit Service 97d2fb
      /* Get the number of sections from the ELF header.  */
Packit Service 97d2fb
      result = ehdr.e64->e_shnum;
Packit Service 97d2fb
Packit Service 97d2fb
      if (unlikely (result == 0) && ehdr.e64->e_shoff != 0)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  if (unlikely (ehdr.e64->e_shoff >= maxsize)
Packit Service 97d2fb
	      || unlikely (ehdr.e64->e_shoff + sizeof (Elf64_Shdr) > maxsize))
Packit Service 97d2fb
	    /* Cannot read the first section header.  */
Packit Service 97d2fb
	    return 0;
Packit Service 97d2fb
Packit Service 97d2fb
	  Elf64_Xword size;
Packit Service 97d2fb
	  if (likely (map_address != NULL) && e_ident[EI_DATA] == MY_ELFDATA
Packit Service 97d2fb
	      && (ALLOW_UNALIGNED
Packit Service 97d2fb
		  || (((size_t) ((char *) map_address + ehdr.e64->e_shoff))
Packit Service 97d2fb
		      & (__alignof__ (Elf64_Shdr) - 1)) == 0))
Packit Service 97d2fb
	    /* We can directly access the memory.  */
Packit Service 97d2fb
	    size = ((Elf64_Shdr *) ((char *) map_address + ehdr.e64->e_shoff
Packit Service 97d2fb
				    + offset))->sh_size;
Packit Service 97d2fb
	  else
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      ssize_t r;
Packit Service 97d2fb
	      if (likely (map_address != NULL))
Packit Service 97d2fb
		/* gcc will optimize the memcpy to a simple memory
Packit Service 97d2fb
		   access while taking care of alignment issues.  */
Packit Service 97d2fb
		memcpy (&size, &((Elf64_Shdr *) ((char *) map_address
Packit Service 97d2fb
						 + ehdr.e64->e_shoff
Packit Service 97d2fb
						 + offset))->sh_size,
Packit Service 97d2fb
			sizeof (Elf64_Xword));
Packit Service 97d2fb
	      else
Packit Service 97d2fb
		if (unlikely ((r = pread_retry (fildes, &size,
Packit Service 97d2fb
						sizeof (Elf64_Xword),
Packit Service 97d2fb
						offset + ehdr.e64->e_shoff
Packit Service 97d2fb
						+ offsetof (Elf64_Shdr,
Packit Service 97d2fb
							    sh_size)))
Packit Service 97d2fb
			      != sizeof (Elf64_Xword)))
Packit Service 97d2fb
		  {
Packit Service 97d2fb
		    if (r < 0)
Packit Service 97d2fb
		      __libelf_seterrno (ELF_E_INVALID_FILE);
Packit Service 97d2fb
		    else
Packit Service 97d2fb
		      __libelf_seterrno (ELF_E_INVALID_ELF);
Packit Service 97d2fb
		    return (size_t) -1l;
Packit Service 97d2fb
		  }
Packit Service 97d2fb
Packit Service 97d2fb
	      if (e_ident[EI_DATA] != MY_ELFDATA)
Packit Service 97d2fb
		CONVERT (size);
Packit Service 97d2fb
	    }
Packit Service 97d2fb
Packit Service 97d2fb
	  /* Although sh_size is an Elf64_Xword and can contain a 64bit
Packit Service 97d2fb
	     value, we only expect an 32bit value max.  GElf_Word is
Packit Service 97d2fb
	     32bit unsigned.  */
Packit Service 97d2fb
	  if (size > ~((GElf_Word) 0))
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      /* Invalid value, it is too large.  */
Packit Service 97d2fb
	      __libelf_seterrno (ELF_E_INVALID_ELF);
Packit Service 97d2fb
	      return (size_t) -1l;
Packit Service 97d2fb
	    }
Packit Service 97d2fb
Packit Service 97d2fb
	  result = size;
Packit Service 97d2fb
	}
Packit Service 97d2fb
Packit Service 97d2fb
      /* If the section headers were truncated, pretend none were there.  */
Packit Service 97d2fb
      if (ehdr.e64->e_shoff > maxsize
Packit Service 97d2fb
	  || maxsize - ehdr.e64->e_shoff < sizeof (Elf64_Shdr) * result)
Packit Service 97d2fb
	result = 0;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  return result;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
Packit Service 97d2fb
/* Create descriptor for ELF file in memory.  */
Packit Service 97d2fb
static Elf *
Packit Service 97d2fb
file_read_elf (int fildes, void *map_address, unsigned char *e_ident,
Packit Service 97d2fb
	       int64_t offset, size_t maxsize, Elf_Cmd cmd, Elf *parent)
Packit Service 97d2fb
{
Packit Service 97d2fb
  /* Verify the binary is of the class we can handle.  */
Packit Service 97d2fb
  if (unlikely ((e_ident[EI_CLASS] != ELFCLASS32
Packit Service 97d2fb
		 && e_ident[EI_CLASS] != ELFCLASS64)
Packit Service 97d2fb
		/* We also can only handle two encodings.  */
Packit Service 97d2fb
		|| (e_ident[EI_DATA] != ELFDATA2LSB
Packit Service 97d2fb
		    && e_ident[EI_DATA] != ELFDATA2MSB)))
Packit Service 97d2fb
    {
Packit Service 97d2fb
      /* Cannot handle this.  */
Packit Service 97d2fb
      __libelf_seterrno (ELF_E_INVALID_ELF);
Packit Service 97d2fb
      return NULL;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  /* Determine the number of sections.  Returns -1 and sets libelf errno
Packit Service 97d2fb
     if the file handle or elf file is invalid.  Returns zero if there
Packit Service 97d2fb
     are no section headers (or they cannot be read).  */
Packit Service 97d2fb
  size_t scncnt = get_shnum (map_address, e_ident, fildes, offset, maxsize);
Packit Service 97d2fb
  if (scncnt == (size_t) -1l)
Packit Service 97d2fb
    /* Could not determine the number of sections.  */
Packit Service 97d2fb
    return NULL;
Packit Service 97d2fb
Packit Service 97d2fb
  /* Check for too many sections.  */
Packit Service 97d2fb
  if (e_ident[EI_CLASS] == ELFCLASS32)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      if (scncnt > SIZE_MAX / (sizeof (Elf_Scn) + sizeof (Elf32_Shdr)))
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  __libelf_seterrno (ELF_E_INVALID_ELF);
Packit Service 97d2fb
	  return NULL;
Packit Service 97d2fb
	}
Packit Service 97d2fb
    }
Packit Service 97d2fb
  else if (scncnt > SIZE_MAX / (sizeof (Elf_Scn) + sizeof (Elf64_Shdr)))
Packit Service 97d2fb
    {
Packit Service 97d2fb
      __libelf_seterrno (ELF_E_INVALID_ELF);
Packit Service 97d2fb
      return NULL;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  /* We can now allocate the memory.  Even if there are no section headers,
Packit Service 97d2fb
     we allocate space for a zeroth section in case we need it later.  */
Packit Service 97d2fb
  const size_t scnmax = (scncnt ?: (cmd == ELF_C_RDWR || cmd == ELF_C_RDWR_MMAP)
Packit Service 97d2fb
			 ? 1 : 0);
Packit Service 97d2fb
  Elf *elf = allocate_elf (fildes, map_address, offset, maxsize, cmd, parent,
Packit Service 97d2fb
			   ELF_K_ELF, scnmax * sizeof (Elf_Scn));
Packit Service 97d2fb
  if (elf == NULL)
Packit Service 97d2fb
    /* Not enough memory.  allocate_elf will have set libelf errno.  */
Packit Service 97d2fb
    return NULL;
Packit Service 97d2fb
Packit Service 97d2fb
  assert ((unsigned int) scncnt == scncnt);
Packit Service 97d2fb
  assert (offsetof (struct Elf, state.elf32.scns)
Packit Service 97d2fb
	  == offsetof (struct Elf, state.elf64.scns));
Packit Service 97d2fb
  elf->state.elf32.scns.cnt = scncnt;
Packit Service 97d2fb
  elf->state.elf32.scns.max = scnmax;
Packit Service 97d2fb
Packit Service 97d2fb
  /* Some more or less arbitrary value.  */
Packit Service 97d2fb
  elf->state.elf.scnincr = 10;
Packit Service 97d2fb
Packit Service 97d2fb
  /* Make the class easily available.  */
Packit Service 97d2fb
  elf->class = e_ident[EI_CLASS];
Packit Service 97d2fb
Packit Service 97d2fb
  if (e_ident[EI_CLASS] == ELFCLASS32)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      /* This pointer might not be directly usable if the alignment is
Packit Service 97d2fb
	 not sufficient for the architecture.  */
Packit Service 97d2fb
      Elf32_Ehdr *ehdr = (Elf32_Ehdr *) ((char *) map_address + offset);
Packit Service 97d2fb
Packit Service 97d2fb
      /* This is a 32-bit binary.  */
Packit Service 97d2fb
      if (map_address != NULL && e_ident[EI_DATA] == MY_ELFDATA
Packit Service 97d2fb
	  && (ALLOW_UNALIGNED
Packit Service 97d2fb
	      || (((uintptr_t) ehdr) & (__alignof__ (Elf32_Ehdr) - 1)) == 0))
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  /* We can use the mmapped memory.  */
Packit Service 97d2fb
	  elf->state.elf32.ehdr = ehdr;
Packit Service 97d2fb
	}
Packit Service 97d2fb
      else
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  /* Copy the ELF header.  */
Packit Service 97d2fb
	  elf->state.elf32.ehdr = memcpy (&elf->state.elf32.ehdr_mem, e_ident,
Packit Service 97d2fb
					  sizeof (Elf32_Ehdr));
Packit Service 97d2fb
Packit Service 97d2fb
	  if (e_ident[EI_DATA] != MY_ELFDATA)
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      CONVERT (elf->state.elf32.ehdr_mem.e_type);
Packit Service 97d2fb
	      CONVERT (elf->state.elf32.ehdr_mem.e_machine);
Packit Service 97d2fb
	      CONVERT (elf->state.elf32.ehdr_mem.e_version);
Packit Service 97d2fb
	      CONVERT (elf->state.elf32.ehdr_mem.e_entry);
Packit Service 97d2fb
	      CONVERT (elf->state.elf32.ehdr_mem.e_phoff);
Packit Service 97d2fb
	      CONVERT (elf->state.elf32.ehdr_mem.e_shoff);
Packit Service 97d2fb
	      CONVERT (elf->state.elf32.ehdr_mem.e_flags);
Packit Service 97d2fb
	      CONVERT (elf->state.elf32.ehdr_mem.e_ehsize);
Packit Service 97d2fb
	      CONVERT (elf->state.elf32.ehdr_mem.e_phentsize);
Packit Service 97d2fb
	      CONVERT (elf->state.elf32.ehdr_mem.e_phnum);
Packit Service 97d2fb
	      CONVERT (elf->state.elf32.ehdr_mem.e_shentsize);
Packit Service 97d2fb
	      CONVERT (elf->state.elf32.ehdr_mem.e_shnum);
Packit Service 97d2fb
	      CONVERT (elf->state.elf32.ehdr_mem.e_shstrndx);
Packit Service 97d2fb
	    }
Packit Service 97d2fb
	}
Packit Service 97d2fb
Packit Service 97d2fb
      /* Don't precache the phdr pointer here.
Packit Service 97d2fb
	 elf32_getphdr will validate it against the size when asked.  */
Packit Service 97d2fb
Packit Service 97d2fb
      Elf32_Off e_shoff = elf->state.elf32.ehdr->e_shoff;
Packit Service 97d2fb
      if (map_address != NULL && e_ident[EI_DATA] == MY_ELFDATA
Packit Service 97d2fb
	  && cmd != ELF_C_READ_MMAP /* We need a copy to be able to write.  */
Packit Service 97d2fb
	  && (ALLOW_UNALIGNED
Packit Service 97d2fb
	      || (((uintptr_t) ((char *) ehdr + e_shoff)
Packit Service 97d2fb
		   & (__alignof__ (Elf32_Shdr) - 1)) == 0)))
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  if (unlikely (scncnt > 0 && e_shoff >= maxsize)
Packit Service 97d2fb
	      || unlikely (maxsize - e_shoff
Packit Service 97d2fb
			   < scncnt * sizeof (Elf32_Shdr)))
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	    free_and_out:
Packit Service 97d2fb
	      free (elf);
Packit Service 97d2fb
	      __libelf_seterrno (ELF_E_INVALID_ELF);
Packit Service 97d2fb
	      return NULL;
Packit Service 97d2fb
	    }
Packit Service 97d2fb
	  elf->state.elf32.shdr
Packit Service 97d2fb
	    = (Elf32_Shdr *) ((char *) ehdr + e_shoff);
Packit Service 97d2fb
Packit Service 97d2fb
	  for (size_t cnt = 0; cnt < scncnt; ++cnt)
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      elf->state.elf32.scns.data[cnt].index = cnt;
Packit Service 97d2fb
	      elf->state.elf32.scns.data[cnt].elf = elf;
Packit Service 97d2fb
	      elf->state.elf32.scns.data[cnt].shdr.e32 =
Packit Service 97d2fb
		&elf->state.elf32.shdr[cnt];
Packit Service 97d2fb
	      if (likely (elf->state.elf32.shdr[cnt].sh_offset < maxsize)
Packit Service 97d2fb
		  && likely (elf->state.elf32.shdr[cnt].sh_size
Packit Service 97d2fb
			     <= maxsize - elf->state.elf32.shdr[cnt].sh_offset))
Packit Service 97d2fb
		elf->state.elf32.scns.data[cnt].rawdata_base =
Packit Service 97d2fb
		  elf->state.elf32.scns.data[cnt].data_base =
Packit Service 97d2fb
		  ((char *) map_address + offset
Packit Service 97d2fb
		   + elf->state.elf32.shdr[cnt].sh_offset);
Packit Service 97d2fb
	      elf->state.elf32.scns.data[cnt].list = &elf->state.elf32.scns;
Packit Service 97d2fb
Packit Service 97d2fb
	      /* If this is a section with an extended index add a
Packit Service 97d2fb
		 reference in the section which uses the extended
Packit Service 97d2fb
		 index.  */
Packit Service 97d2fb
	      if (elf->state.elf32.shdr[cnt].sh_type == SHT_SYMTAB_SHNDX
Packit Service 97d2fb
		  && elf->state.elf32.shdr[cnt].sh_link < scncnt)
Packit Service 97d2fb
		elf->state.elf32.scns.data[elf->state.elf32.shdr[cnt].sh_link].shndx_index
Packit Service 97d2fb
		  = cnt;
Packit Service 97d2fb
Packit Service 97d2fb
	      /* Set the own shndx_index field in case it has not yet
Packit Service 97d2fb
		 been set.  */
Packit Service 97d2fb
	      if (elf->state.elf32.scns.data[cnt].shndx_index == 0)
Packit Service 97d2fb
		elf->state.elf32.scns.data[cnt].shndx_index = -1;
Packit Service 97d2fb
	    }
Packit Service 97d2fb
	}
Packit Service 97d2fb
      else
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  for (size_t cnt = 0; cnt < scncnt; ++cnt)
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      elf->state.elf32.scns.data[cnt].index = cnt;
Packit Service 97d2fb
	      elf->state.elf32.scns.data[cnt].elf = elf;
Packit Service 97d2fb
	      elf->state.elf32.scns.data[cnt].list = &elf->state.elf32.scns;
Packit Service 97d2fb
	    }
Packit Service 97d2fb
	}
Packit Service 97d2fb
Packit Service 97d2fb
      /* So far only one block with sections.  */
Packit Service 97d2fb
      elf->state.elf32.scns_last = &elf->state.elf32.scns;
Packit Service 97d2fb
    }
Packit Service 97d2fb
  else
Packit Service 97d2fb
    {
Packit Service 97d2fb
      /* This pointer might not be directly usable if the alignment is
Packit Service 97d2fb
	 not sufficient for the architecture.  */
Packit Service 97d2fb
      Elf64_Ehdr *ehdr = (Elf64_Ehdr *) ((char *) map_address + offset);
Packit Service 97d2fb
Packit Service 97d2fb
      /* This is a 64-bit binary.  */
Packit Service 97d2fb
      if (map_address != NULL && e_ident[EI_DATA] == MY_ELFDATA
Packit Service 97d2fb
	  && (ALLOW_UNALIGNED
Packit Service 97d2fb
	      || (((uintptr_t) ehdr) & (__alignof__ (Elf64_Ehdr) - 1)) == 0))
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  /* We can use the mmapped memory.  */
Packit Service 97d2fb
	  elf->state.elf64.ehdr = ehdr;
Packit Service 97d2fb
	}
Packit Service 97d2fb
      else
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  /* Copy the ELF header.  */
Packit Service 97d2fb
	  elf->state.elf64.ehdr = memcpy (&elf->state.elf64.ehdr_mem, e_ident,
Packit Service 97d2fb
					  sizeof (Elf64_Ehdr));
Packit Service 97d2fb
Packit Service 97d2fb
	  if (e_ident[EI_DATA] != MY_ELFDATA)
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      CONVERT (elf->state.elf64.ehdr_mem.e_type);
Packit Service 97d2fb
	      CONVERT (elf->state.elf64.ehdr_mem.e_machine);
Packit Service 97d2fb
	      CONVERT (elf->state.elf64.ehdr_mem.e_version);
Packit Service 97d2fb
	      CONVERT (elf->state.elf64.ehdr_mem.e_entry);
Packit Service 97d2fb
	      CONVERT (elf->state.elf64.ehdr_mem.e_phoff);
Packit Service 97d2fb
	      CONVERT (elf->state.elf64.ehdr_mem.e_shoff);
Packit Service 97d2fb
	      CONVERT (elf->state.elf64.ehdr_mem.e_flags);
Packit Service 97d2fb
	      CONVERT (elf->state.elf64.ehdr_mem.e_ehsize);
Packit Service 97d2fb
	      CONVERT (elf->state.elf64.ehdr_mem.e_phentsize);
Packit Service 97d2fb
	      CONVERT (elf->state.elf64.ehdr_mem.e_phnum);
Packit Service 97d2fb
	      CONVERT (elf->state.elf64.ehdr_mem.e_shentsize);
Packit Service 97d2fb
	      CONVERT (elf->state.elf64.ehdr_mem.e_shnum);
Packit Service 97d2fb
	      CONVERT (elf->state.elf64.ehdr_mem.e_shstrndx);
Packit Service 97d2fb
	    }
Packit Service 97d2fb
	}
Packit Service 97d2fb
Packit Service 97d2fb
      /* Don't precache the phdr pointer here.
Packit Service 97d2fb
	 elf64_getphdr will validate it against the size when asked.  */
Packit Service 97d2fb
Packit Service 97d2fb
      Elf64_Off e_shoff = elf->state.elf64.ehdr->e_shoff;
Packit Service 97d2fb
      if (map_address != NULL && e_ident[EI_DATA] == MY_ELFDATA
Packit Service 97d2fb
	  && cmd != ELF_C_READ_MMAP /* We need a copy to be able to write.  */
Packit Service 97d2fb
	  && (ALLOW_UNALIGNED
Packit Service 97d2fb
	      || (((uintptr_t) ((char *) ehdr + e_shoff)
Packit Service 97d2fb
		   & (__alignof__ (Elf64_Shdr) - 1)) == 0)))
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  if (unlikely (scncnt > 0 && e_shoff >= maxsize)
Packit Service 97d2fb
	      || unlikely (maxsize - e_shoff
Packit Service 97d2fb
			   < scncnt * sizeof (Elf64_Shdr)))
Packit Service 97d2fb
	    goto free_and_out;
Packit Service 97d2fb
	  elf->state.elf64.shdr
Packit Service 97d2fb
	    = (Elf64_Shdr *) ((char *) ehdr + e_shoff);
Packit Service 97d2fb
Packit Service 97d2fb
	  for (size_t cnt = 0; cnt < scncnt; ++cnt)
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      elf->state.elf64.scns.data[cnt].index = cnt;
Packit Service 97d2fb
	      elf->state.elf64.scns.data[cnt].elf = elf;
Packit Service 97d2fb
	      elf->state.elf64.scns.data[cnt].shdr.e64 =
Packit Service 97d2fb
		&elf->state.elf64.shdr[cnt];
Packit Service 97d2fb
	      if (likely (elf->state.elf64.shdr[cnt].sh_offset < maxsize)
Packit Service 97d2fb
		  && likely (elf->state.elf64.shdr[cnt].sh_size
Packit Service 97d2fb
			     <= maxsize - elf->state.elf64.shdr[cnt].sh_offset))
Packit Service 97d2fb
		elf->state.elf64.scns.data[cnt].rawdata_base =
Packit Service 97d2fb
		  elf->state.elf64.scns.data[cnt].data_base =
Packit Service 97d2fb
		  ((char *) map_address + offset
Packit Service 97d2fb
		   + elf->state.elf64.shdr[cnt].sh_offset);
Packit Service 97d2fb
	      elf->state.elf64.scns.data[cnt].list = &elf->state.elf64.scns;
Packit Service 97d2fb
Packit Service 97d2fb
	      /* If this is a section with an extended index add a
Packit Service 97d2fb
		 reference in the section which uses the extended
Packit Service 97d2fb
		 index.  */
Packit Service 97d2fb
	      if (elf->state.elf64.shdr[cnt].sh_type == SHT_SYMTAB_SHNDX
Packit Service 97d2fb
		  && elf->state.elf64.shdr[cnt].sh_link < scncnt)
Packit Service 97d2fb
		elf->state.elf64.scns.data[elf->state.elf64.shdr[cnt].sh_link].shndx_index
Packit Service 97d2fb
		  = cnt;
Packit Service 97d2fb
Packit Service 97d2fb
	      /* Set the own shndx_index field in case it has not yet
Packit Service 97d2fb
		 been set.  */
Packit Service 97d2fb
	      if (elf->state.elf64.scns.data[cnt].shndx_index == 0)
Packit Service 97d2fb
		elf->state.elf64.scns.data[cnt].shndx_index = -1;
Packit Service 97d2fb
	    }
Packit Service 97d2fb
	}
Packit Service 97d2fb
      else
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  for (size_t cnt = 0; cnt < scncnt; ++cnt)
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      elf->state.elf64.scns.data[cnt].index = cnt;
Packit Service 97d2fb
	      elf->state.elf64.scns.data[cnt].elf = elf;
Packit Service 97d2fb
	      elf->state.elf64.scns.data[cnt].list = &elf->state.elf64.scns;
Packit Service 97d2fb
	    }
Packit Service 97d2fb
	}
Packit Service 97d2fb
Packit Service 97d2fb
      /* So far only one block with sections.  */
Packit Service 97d2fb
      elf->state.elf64.scns_last = &elf->state.elf64.scns;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  return elf;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
Packit Service 97d2fb
Elf *
Packit Service 97d2fb
internal_function
Packit Service 97d2fb
__libelf_read_mmaped_file (int fildes, void *map_address,  int64_t offset,
Packit Service 97d2fb
			   size_t maxsize, Elf_Cmd cmd, Elf *parent)
Packit Service 97d2fb
{
Packit Service 97d2fb
  /* We have to find out what kind of file this is.  We handle ELF
Packit Service 97d2fb
     files and archives.  To find out what we have we must look at the
Packit Service 97d2fb
     header.  The header for an ELF file is EI_NIDENT bytes in size,
Packit Service 97d2fb
     the header for an archive file SARMAG bytes long.  */
Packit Service 97d2fb
  unsigned char *e_ident = (unsigned char *) map_address + offset;
Packit Service 97d2fb
Packit Service 97d2fb
  /* See what kind of object we have here.  */
Packit Service 97d2fb
  Elf_Kind kind = determine_kind (e_ident, maxsize);
Packit Service 97d2fb
Packit Service 97d2fb
  switch (kind)
Packit Service 97d2fb
    {
Packit Service 97d2fb
    case ELF_K_ELF:
Packit Service 97d2fb
      return file_read_elf (fildes, map_address, e_ident, offset, maxsize,
Packit Service 97d2fb
			    cmd, parent);
Packit Service 97d2fb
Packit Service 97d2fb
    case ELF_K_AR:
Packit Service 97d2fb
      return file_read_ar (fildes, map_address, offset, maxsize, cmd, parent);
Packit Service 97d2fb
Packit Service 97d2fb
    default:
Packit Service 97d2fb
      break;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  /* This case is easy.  Since we cannot do anything with this file
Packit Service 97d2fb
     create a dummy descriptor.  */
Packit Service 97d2fb
  return allocate_elf (fildes, map_address, offset, maxsize, cmd, parent,
Packit Service 97d2fb
		       ELF_K_NONE, 0);
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
Packit Service 97d2fb
static Elf *
Packit Service 97d2fb
read_unmmaped_file (int fildes, int64_t offset, size_t maxsize, Elf_Cmd cmd,
Packit Service 97d2fb
		    Elf *parent)
Packit Service 97d2fb
{
Packit Service 97d2fb
  /* We have to find out what kind of file this is.  We handle ELF
Packit Service 97d2fb
     files and archives.  To find out what we have we must read the
Packit Service 97d2fb
     header.  The identification header for an ELF file is EI_NIDENT
Packit Service 97d2fb
     bytes in size, but we read the whole ELF header since we will
Packit Service 97d2fb
     need it anyway later.  For archives the header in SARMAG bytes
Packit Service 97d2fb
     long.  Read the maximum of these numbers.
Packit Service 97d2fb
Packit Service 97d2fb
     XXX We have to change this for the extended `ar' format some day.
Packit Service 97d2fb
Packit Service 97d2fb
     Use a union to ensure alignment.  We might later access the
Packit Service 97d2fb
     memory as a ElfXX_Ehdr.  */
Packit Service 97d2fb
  union
Packit Service 97d2fb
  {
Packit Service 97d2fb
    Elf64_Ehdr ehdr;
Packit Service 97d2fb
    unsigned char header[MAX (sizeof (Elf64_Ehdr), SARMAG)];
Packit Service 97d2fb
  } mem;
Packit Service 97d2fb
Packit Service 97d2fb
  /* Read the head of the file.  */
Packit Service 97d2fb
  ssize_t nread = pread_retry (fildes, mem.header,
Packit Service 97d2fb
			       MIN (MAX (sizeof (Elf64_Ehdr), SARMAG),
Packit Service 97d2fb
				    maxsize),
Packit Service 97d2fb
			       offset);
Packit Service 97d2fb
  if (unlikely (nread == -1))
Packit Service 97d2fb
    {
Packit Service 97d2fb
      /* We cannot even read the head of the file.  Maybe FILDES is associated
Packit Service 97d2fb
	 with an unseekable device.  This is nothing we can handle.  */
Packit Service 97d2fb
      __libelf_seterrno (ELF_E_INVALID_FILE);
Packit Service 97d2fb
      return NULL;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  /* See what kind of object we have here.  */
Packit Service 97d2fb
  Elf_Kind kind = determine_kind (mem.header, nread);
Packit Service 97d2fb
Packit Service 97d2fb
  switch (kind)
Packit Service 97d2fb
    {
Packit Service 97d2fb
    case ELF_K_AR:
Packit Service 97d2fb
      return file_read_ar (fildes, NULL, offset, maxsize, cmd, parent);
Packit Service 97d2fb
Packit Service 97d2fb
    case ELF_K_ELF:
Packit Service 97d2fb
      /* Make sure at least the ELF header is contained in the file.  */
Packit Service 97d2fb
      if ((size_t) nread >= (mem.header[EI_CLASS] == ELFCLASS32
Packit Service 97d2fb
			     ? sizeof (Elf32_Ehdr) : sizeof (Elf64_Ehdr)))
Packit Service 97d2fb
	return file_read_elf (fildes, NULL, mem.header, offset, maxsize, cmd,
Packit Service 97d2fb
			      parent);
Packit Service 97d2fb
      FALLTHROUGH;
Packit Service 97d2fb
Packit Service 97d2fb
    default:
Packit Service 97d2fb
      break;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  /* This case is easy.  Since we cannot do anything with this file
Packit Service 97d2fb
     create a dummy descriptor.  */
Packit Service 97d2fb
  return allocate_elf (fildes, NULL, offset, maxsize, cmd, parent,
Packit Service 97d2fb
		       ELF_K_NONE, 0);
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
Packit Service 97d2fb
/* Open a file for reading.  If possible we will try to mmap() the file.  */
Packit Service 97d2fb
static struct Elf *
Packit Service 97d2fb
read_file (int fildes, int64_t offset, size_t maxsize,
Packit Service 97d2fb
	   Elf_Cmd cmd, Elf *parent)
Packit Service 97d2fb
{
Packit Service 97d2fb
  void *map_address = NULL;
Packit Service 97d2fb
  int use_mmap = (cmd == ELF_C_READ_MMAP || cmd == ELF_C_RDWR_MMAP
Packit Service 97d2fb
		  || cmd == ELF_C_WRITE_MMAP
Packit Service 97d2fb
		  || cmd == ELF_C_READ_MMAP_PRIVATE);
Packit Service 97d2fb
Packit Service 97d2fb
  if (parent == NULL)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      if (maxsize == ~((size_t) 0))
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  /* We don't know in the moment how large the file is.
Packit Service 97d2fb
	     Determine it now.  */
Packit Service 97d2fb
	  struct stat st;
Packit Service 97d2fb
Packit Service 97d2fb
	  if (fstat (fildes, &st) == 0
Packit Service 97d2fb
	      && (sizeof (size_t) >= sizeof (st.st_size)
Packit Service 97d2fb
		  || st.st_size <= ~((size_t) 0)))
Packit Service 97d2fb
	    maxsize = (size_t) st.st_size;
Packit Service 97d2fb
	}
Packit Service 97d2fb
    }
Packit Service 97d2fb
  else
Packit Service 97d2fb
    {
Packit Service 97d2fb
      /* The parent is already loaded.  Use it.  */
Packit Service 97d2fb
      assert (maxsize != ~((size_t) 0));
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  if (use_mmap)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      if (parent == NULL)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  /* We try to map the file ourself.  */
Packit Service 97d2fb
	  map_address = mmap (NULL, maxsize, (cmd == ELF_C_READ_MMAP
Packit Service 97d2fb
					      ? PROT_READ
Packit Service 97d2fb
					      : PROT_READ|PROT_WRITE),
Packit Service 97d2fb
			      cmd == ELF_C_READ_MMAP_PRIVATE
Packit Service 97d2fb
			      || cmd == ELF_C_READ_MMAP
Packit Service 97d2fb
			      ? MAP_PRIVATE : MAP_SHARED,
Packit Service 97d2fb
			      fildes, offset);
Packit Service 97d2fb
Packit Service 97d2fb
	  if (map_address == MAP_FAILED)
Packit Service 97d2fb
	    map_address = NULL;
Packit Service 97d2fb
	}
Packit Service 97d2fb
      else
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  map_address = parent->map_address;
Packit Service 97d2fb
	}
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  /* If we have the file in memory optimize the access.  */
Packit Service 97d2fb
  if (map_address != NULL)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      assert (map_address != MAP_FAILED);
Packit Service 97d2fb
Packit Service 97d2fb
      struct Elf *result = __libelf_read_mmaped_file (fildes, map_address,
Packit Service 97d2fb
						      offset, maxsize, cmd,
Packit Service 97d2fb
						      parent);
Packit Service 97d2fb
Packit Service 97d2fb
      /* If something went wrong during the initialization unmap the
Packit Service 97d2fb
	 memory if we mmaped here.  */
Packit Service 97d2fb
      if (result == NULL
Packit Service 97d2fb
	  && (parent == NULL
Packit Service 97d2fb
	      || parent->map_address != map_address))
Packit Service 97d2fb
	munmap (map_address, maxsize);
Packit Service 97d2fb
      else if (parent == NULL)
Packit Service 97d2fb
	/* Remember that we mmap()ed the memory.  */
Packit Service 97d2fb
	result->flags |= ELF_F_MMAPPED;
Packit Service 97d2fb
Packit Service 97d2fb
      return result;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  /* Otherwise we have to do it the hard way.  We read as much as necessary
Packit Service 97d2fb
     from the file whenever we need information which is not available.  */
Packit Service 97d2fb
  return read_unmmaped_file (fildes, offset, maxsize, cmd, parent);
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
Packit Service 97d2fb
/* Find the entry with the long names for the content of this archive.  */
Packit Service 97d2fb
static const char *
Packit Service 97d2fb
read_long_names (Elf *elf)
Packit Service 97d2fb
{
Packit Service 97d2fb
  off_t offset = SARMAG;	/* This is the first entry.  */
Packit Service 97d2fb
  struct ar_hdr hdrm;
Packit Service 97d2fb
  struct ar_hdr *hdr;
Packit Service 97d2fb
  char *newp;
Packit Service 97d2fb
  size_t len;
Packit Service 97d2fb
Packit Service 97d2fb
  while (1)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      if (elf->map_address != NULL)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  if ((size_t) offset > elf->maximum_size
Packit Service 97d2fb
	      || elf->maximum_size - offset < sizeof (struct ar_hdr))
Packit Service 97d2fb
	    return NULL;
Packit Service 97d2fb
Packit Service 97d2fb
	  /* The data is mapped.  */
Packit Service 97d2fb
	  hdr = (struct ar_hdr *) (elf->map_address + offset);
Packit Service 97d2fb
	}
Packit Service 97d2fb
      else
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  /* Read the header from the file.  */
Packit Service 97d2fb
	  if (unlikely (pread_retry (elf->fildes, &hdrm, sizeof (hdrm),
Packit Service 97d2fb
				     elf->start_offset + offset)
Packit Service 97d2fb
			!= sizeof (hdrm)))
Packit Service 97d2fb
	    return NULL;
Packit Service 97d2fb
Packit Service 97d2fb
	  hdr = &hdrm;
Packit Service 97d2fb
	}
Packit Service 97d2fb
Packit Service 97d2fb
      /* The ar_size is given as a fixed size decimal string, right
Packit Service 97d2fb
	 padded with spaces.  Make sure we read it properly even if
Packit Service 97d2fb
	 there is no terminating space.  */
Packit Service 97d2fb
      char buf[sizeof (hdr->ar_size) + 1];
Packit Service 97d2fb
      const char *string = hdr->ar_size;
Packit Service 97d2fb
      if (hdr->ar_size[sizeof (hdr->ar_size) - 1] != ' ')
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  *((char *) mempcpy (buf, hdr->ar_size, sizeof (hdr->ar_size))) = '\0';
Packit Service 97d2fb
	  string = buf;
Packit Service 97d2fb
	}
Packit Service 97d2fb
      len = atol (string);
Packit Service 97d2fb
Packit Service 97d2fb
      if (memcmp (hdr->ar_name, "//              ", 16) == 0)
Packit Service 97d2fb
	break;
Packit Service 97d2fb
Packit Service 97d2fb
      offset += sizeof (struct ar_hdr) + ((len + 1) & ~1l);
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  /* Sanity check len early if we can.  */
Packit Service 97d2fb
  if (elf->map_address != NULL)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      if (len > elf->maximum_size - offset - sizeof (struct ar_hdr))
Packit Service 97d2fb
	return NULL;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  /* Due to the stupid format of the long name table entry (which are not
Packit Service 97d2fb
     NUL terminted) we have to provide an appropriate representation anyhow.
Packit Service 97d2fb
     Therefore we always make a copy which has the appropriate form.  */
Packit Service 97d2fb
  newp = (char *) malloc (len);
Packit Service 97d2fb
  if (newp != NULL)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      char *runp;
Packit Service 97d2fb
Packit Service 97d2fb
      if (elf->map_address != NULL)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  /* Simply copy it over.  */
Packit Service 97d2fb
	  elf->state.ar.long_names = (char *) memcpy (newp,
Packit Service 97d2fb
						      elf->map_address + offset
Packit Service 97d2fb
						      + sizeof (struct ar_hdr),
Packit Service 97d2fb
						      len);
Packit Service 97d2fb
	}
Packit Service 97d2fb
      else
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  if (unlikely ((size_t) pread_retry (elf->fildes, newp, len,
Packit Service 97d2fb
					      elf->start_offset + offset
Packit Service 97d2fb
					      + sizeof (struct ar_hdr))
Packit Service 97d2fb
			!= len))
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      /* We were not able to read all data.  */
Packit Service 97d2fb
	      free (newp);
Packit Service 97d2fb
	      elf->state.ar.long_names = NULL;
Packit Service 97d2fb
	      return NULL;
Packit Service 97d2fb
	    }
Packit Service 97d2fb
	  elf->state.ar.long_names = newp;
Packit Service 97d2fb
	}
Packit Service 97d2fb
Packit Service 97d2fb
      elf->state.ar.long_names_len = len;
Packit Service 97d2fb
Packit Service 97d2fb
      /* Now NUL-terminate the strings.  */
Packit Service 97d2fb
      runp = newp;
Packit Service 97d2fb
      while (1)
Packit Service 97d2fb
        {
Packit Service 97d2fb
	  char *startp = runp;
Packit Service 97d2fb
	  runp = (char *) memchr (runp, '/', newp + len - runp);
Packit Service 97d2fb
	  if (runp == NULL)
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      /* This was the last entry.  Clear any left overs.  */
Packit Service 97d2fb
	      memset (startp, '\0', newp + len - startp);
Packit Service 97d2fb
	      break;
Packit Service 97d2fb
	    }
Packit Service 97d2fb
Packit Service 97d2fb
	  /* NUL-terminate the string.  */
Packit Service 97d2fb
	  *runp++ = '\0';
Packit Service 97d2fb
Packit Service 97d2fb
	  /* A sanity check.  Somebody might have generated invalid
Packit Service 97d2fb
	     archive.  */
Packit Service 97d2fb
	  if (runp >= newp + len)
Packit Service 97d2fb
	    break;
Packit Service 97d2fb
	}
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  return newp;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
Packit Service 97d2fb
/* Read the next archive header.  */
Packit Service 97d2fb
int
Packit Service 97d2fb
internal_function
Packit Service 97d2fb
__libelf_next_arhdr_wrlock (Elf *elf)
Packit Service 97d2fb
{
Packit Service 97d2fb
  struct ar_hdr *ar_hdr;
Packit Service 97d2fb
  Elf_Arhdr *elf_ar_hdr;
Packit Service 97d2fb
Packit Service 97d2fb
  if (elf->map_address != NULL)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      /* See whether this entry is in the file.  */
Packit Service 97d2fb
      if (unlikely ((size_t) elf->state.ar.offset
Packit Service 97d2fb
		    > elf->start_offset + elf->maximum_size
Packit Service 97d2fb
		    || (elf->start_offset + elf->maximum_size
Packit Service 97d2fb
			- elf->state.ar.offset) < sizeof (struct ar_hdr)))
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  /* This record is not anymore in the file.  */
Packit Service 97d2fb
	  __libelf_seterrno (ELF_E_RANGE);
Packit Service 97d2fb
	  return -1;
Packit Service 97d2fb
	}
Packit Service 97d2fb
      ar_hdr = (struct ar_hdr *) (elf->map_address + elf->state.ar.offset);
Packit Service 97d2fb
    }
Packit Service 97d2fb
  else
Packit Service 97d2fb
    {
Packit Service 97d2fb
      ar_hdr = &elf->state.ar.ar_hdr;
Packit Service 97d2fb
Packit Service 97d2fb
      if (unlikely (pread_retry (elf->fildes, ar_hdr, sizeof (struct ar_hdr),
Packit Service 97d2fb
				 elf->state.ar.offset)
Packit Service 97d2fb
		    != sizeof (struct ar_hdr)))
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  /* Something went wrong while reading the file.  */
Packit Service 97d2fb
	  __libelf_seterrno (ELF_E_RANGE);
Packit Service 97d2fb
	  return -1;
Packit Service 97d2fb
	}
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  /* One little consistency check.  */
Packit Service 97d2fb
  if (unlikely (memcmp (ar_hdr->ar_fmag, ARFMAG, 2) != 0))
Packit Service 97d2fb
    {
Packit Service 97d2fb
      /* This is no valid archive.  */
Packit Service 97d2fb
      __libelf_seterrno (ELF_E_ARCHIVE_FMAG);
Packit Service 97d2fb
      return -1;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  /* Copy the raw name over to a NUL terminated buffer.  */
Packit Service 97d2fb
  *((char *) mempcpy (elf->state.ar.raw_name, ar_hdr->ar_name, 16)) = '\0';
Packit Service 97d2fb
Packit Service 97d2fb
  elf_ar_hdr = &elf->state.ar.elf_ar_hdr;
Packit Service 97d2fb
Packit Service 97d2fb
  /* Now convert the `struct ar_hdr' into `Elf_Arhdr'.
Packit Service 97d2fb
     Determine whether this is a special entry.  */
Packit Service 97d2fb
  if (ar_hdr->ar_name[0] == '/')
Packit Service 97d2fb
    {
Packit Service 97d2fb
      if (ar_hdr->ar_name[1] == ' '
Packit Service 97d2fb
	  && memcmp (ar_hdr->ar_name, "/               ", 16) == 0)
Packit Service 97d2fb
	/* This is the index.  */
Packit Service 97d2fb
	elf_ar_hdr->ar_name = memcpy (elf->state.ar.ar_name, "/", 2);
Packit Service 97d2fb
      else if (ar_hdr->ar_name[1] == 'S'
Packit Service 97d2fb
	       && memcmp (ar_hdr->ar_name, "/SYM64/         ", 16) == 0)
Packit Service 97d2fb
	/* 64-bit index.  */
Packit Service 97d2fb
	elf_ar_hdr->ar_name = memcpy (elf->state.ar.ar_name, "/SYM64/", 8);
Packit Service 97d2fb
      else if (ar_hdr->ar_name[1] == '/'
Packit Service 97d2fb
	       && memcmp (ar_hdr->ar_name, "//              ", 16) == 0)
Packit Service 97d2fb
	/* This is the array with the long names.  */
Packit Service 97d2fb
	elf_ar_hdr->ar_name = memcpy (elf->state.ar.ar_name, "//", 3);
Packit Service 97d2fb
      else if (likely  (isdigit (ar_hdr->ar_name[1])))
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  size_t offset;
Packit Service 97d2fb
Packit Service 97d2fb
	  /* This is a long name.  First we have to read the long name
Packit Service 97d2fb
	     table, if this hasn't happened already.  */
Packit Service 97d2fb
	  if (unlikely (elf->state.ar.long_names == NULL
Packit Service 97d2fb
			&& read_long_names (elf) == NULL))
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      /* No long name table although it is reference.  The archive is
Packit Service 97d2fb
		 broken.  */
Packit Service 97d2fb
	      __libelf_seterrno (ELF_E_INVALID_ARCHIVE);
Packit Service 97d2fb
	      return -1;
Packit Service 97d2fb
	    }
Packit Service 97d2fb
Packit Service 97d2fb
	  offset = atol (ar_hdr->ar_name + 1);
Packit Service 97d2fb
	  if (unlikely (offset >= elf->state.ar.long_names_len))
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      /* The index in the long name table is larger than the table.  */
Packit Service 97d2fb
	      __libelf_seterrno (ELF_E_INVALID_ARCHIVE);
Packit Service 97d2fb
	      return -1;
Packit Service 97d2fb
	    }
Packit Service 97d2fb
	  elf_ar_hdr->ar_name = elf->state.ar.long_names + offset;
Packit Service 97d2fb
	}
Packit Service 97d2fb
      else
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  /* This is none of the known special entries.  */
Packit Service 97d2fb
	  __libelf_seterrno (ELF_E_INVALID_ARCHIVE);
Packit Service 97d2fb
	  return -1;
Packit Service 97d2fb
	}
Packit Service 97d2fb
    }
Packit Service 97d2fb
  else
Packit Service 97d2fb
    {
Packit Service 97d2fb
      char *endp;
Packit Service 97d2fb
Packit Service 97d2fb
      /* It is a normal entry.  Copy over the name.  */
Packit Service 97d2fb
      endp = (char *) memccpy (elf->state.ar.ar_name, ar_hdr->ar_name,
Packit Service 97d2fb
			       '/', 16);
Packit Service 97d2fb
      if (endp != NULL)
Packit Service 97d2fb
	endp[-1] = '\0';
Packit Service 97d2fb
      else
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  /* In the old BSD style of archive, there is no / terminator.
Packit Service 97d2fb
	     Instead, there is space padding at the end of the name.  */
Packit Service 97d2fb
	  size_t i = 15;
Packit Service 97d2fb
	  do
Packit Service 97d2fb
	    elf->state.ar.ar_name[i] = '\0';
Packit Service 97d2fb
	  while (i > 0 && elf->state.ar.ar_name[--i] == ' ');
Packit Service 97d2fb
	}
Packit Service 97d2fb
Packit Service 97d2fb
      elf_ar_hdr->ar_name = elf->state.ar.ar_name;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  if (unlikely (ar_hdr->ar_size[0] == ' '))
Packit Service 97d2fb
    /* Something is really wrong.  We cannot live without a size for
Packit Service 97d2fb
       the member since it will not be possible to find the next
Packit Service 97d2fb
       archive member.  */
Packit Service 97d2fb
    {
Packit Service 97d2fb
      __libelf_seterrno (ELF_E_INVALID_ARCHIVE);
Packit Service 97d2fb
      return -1;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  /* Since there are no specialized functions to convert ASCII to
Packit Service 97d2fb
     time_t, uid_t, gid_t, mode_t, and off_t we use either atol or
Packit Service 97d2fb
     atoll depending on the size of the types.  We are also prepared
Packit Service 97d2fb
     for the case where the whole field in the `struct ar_hdr' is
Packit Service 97d2fb
     filled in which case we cannot simply use atol/l but instead have
Packit Service 97d2fb
     to create a temporary copy.  */
Packit Service 97d2fb
Packit Service 97d2fb
#define INT_FIELD(FIELD)						      \
Packit Service 97d2fb
  do									      \
Packit Service 97d2fb
    {									      \
Packit Service 97d2fb
      char buf[sizeof (ar_hdr->FIELD) + 1];				      \
Packit Service 97d2fb
      const char *string = ar_hdr->FIELD;				      \
Packit Service 97d2fb
      if (ar_hdr->FIELD[sizeof (ar_hdr->FIELD) - 1] != ' ')		      \
Packit Service 97d2fb
	{								      \
Packit Service 97d2fb
	  *((char *) mempcpy (buf, ar_hdr->FIELD, sizeof (ar_hdr->FIELD)))  \
Packit Service 97d2fb
	    = '\0';							      \
Packit Service 97d2fb
	  string = buf;							      \
Packit Service 97d2fb
	}								      \
Packit Service 97d2fb
      if (sizeof (elf_ar_hdr->FIELD) <= sizeof (long int))		      \
Packit Service 97d2fb
	elf_ar_hdr->FIELD = (__typeof (elf_ar_hdr->FIELD)) atol (string);     \
Packit Service 97d2fb
      else								      \
Packit Service 97d2fb
	elf_ar_hdr->FIELD = (__typeof (elf_ar_hdr->FIELD)) atoll (string);    \
Packit Service 97d2fb
    }									      \
Packit Service 97d2fb
  while (0)
Packit Service 97d2fb
Packit Service 97d2fb
  INT_FIELD (ar_date);
Packit Service 97d2fb
  INT_FIELD (ar_uid);
Packit Service 97d2fb
  INT_FIELD (ar_gid);
Packit Service 97d2fb
  INT_FIELD (ar_mode);
Packit Service 97d2fb
  INT_FIELD (ar_size);
Packit Service 97d2fb
Packit Service 97d2fb
  if (elf_ar_hdr->ar_size < 0)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      __libelf_seterrno (ELF_E_INVALID_ARCHIVE);
Packit Service 97d2fb
      return -1;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  /* Truncated file?  */
Packit Service 97d2fb
  size_t maxsize;
Packit Service 97d2fb
  maxsize = (elf->start_offset + elf->maximum_size
Packit Service 97d2fb
	     - elf->state.ar.offset - sizeof (struct ar_hdr));
Packit Service 97d2fb
  if ((size_t) elf_ar_hdr->ar_size > maxsize)
Packit Service 97d2fb
    elf_ar_hdr->ar_size = maxsize;
Packit Service 97d2fb
Packit Service 97d2fb
  return 0;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
Packit Service 97d2fb
/* We were asked to return a clone of an existing descriptor.  This
Packit Service 97d2fb
   function must be called with the lock on the parent descriptor
Packit Service 97d2fb
   being held. */
Packit Service 97d2fb
static Elf *
Packit Service 97d2fb
dup_elf (int fildes, Elf_Cmd cmd, Elf *ref)
Packit Service 97d2fb
{
Packit Service 97d2fb
  struct Elf *result;
Packit Service 97d2fb
Packit Service 97d2fb
  if (fildes == -1)
Packit Service 97d2fb
    /* Allow the user to pass -1 as the file descriptor for the new file.  */
Packit Service 97d2fb
    fildes = ref->fildes;
Packit Service 97d2fb
  /* The file descriptor better should be the same.  If it was disconnected
Packit Service 97d2fb
     already (using `elf_cntl') we do not test it.  */
Packit Service 97d2fb
  else if (unlikely (ref->fildes != -1 && fildes != ref->fildes))
Packit Service 97d2fb
    {
Packit Service 97d2fb
      __libelf_seterrno (ELF_E_FD_MISMATCH);
Packit Service 97d2fb
      return NULL;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  /* The mode must allow reading.  I.e., a descriptor creating with a
Packit Service 97d2fb
     command different then ELF_C_READ, ELF_C_WRITE and ELF_C_RDWR is
Packit Service 97d2fb
     not allowed.  */
Packit Service 97d2fb
  if (unlikely (ref->cmd != ELF_C_READ && ref->cmd != ELF_C_READ_MMAP
Packit Service 97d2fb
		&& ref->cmd != ELF_C_WRITE && ref->cmd != ELF_C_WRITE_MMAP
Packit Service 97d2fb
		&& ref->cmd != ELF_C_RDWR && ref->cmd != ELF_C_RDWR_MMAP
Packit Service 97d2fb
		&& ref->cmd != ELF_C_READ_MMAP_PRIVATE))
Packit Service 97d2fb
    {
Packit Service 97d2fb
      __libelf_seterrno (ELF_E_INVALID_OP);
Packit Service 97d2fb
      return NULL;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  /* Now it is time to distinguish between reading normal files and
Packit Service 97d2fb
     archives.  Normal files can easily be handled be incrementing the
Packit Service 97d2fb
     reference counter and return the same descriptor.  */
Packit Service 97d2fb
  if (ref->kind != ELF_K_AR)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      ++ref->ref_count;
Packit Service 97d2fb
      return ref;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  /* This is an archive.  We must create a descriptor for the archive
Packit Service 97d2fb
     member the internal pointer of the archive file desriptor is
Packit Service 97d2fb
     pointing to.  First read the header of the next member if this
Packit Service 97d2fb
     has not happened already.  */
Packit Service 97d2fb
  if (ref->state.ar.elf_ar_hdr.ar_name == NULL
Packit Service 97d2fb
      && __libelf_next_arhdr_wrlock (ref) != 0)
Packit Service 97d2fb
    /* Something went wrong.  Maybe there is no member left.  */
Packit Service 97d2fb
    return NULL;
Packit Service 97d2fb
Packit Service 97d2fb
  /* We have all the information we need about the next archive member.
Packit Service 97d2fb
     Now create a descriptor for it.  */
Packit Service 97d2fb
  result = read_file (fildes, ref->state.ar.offset + sizeof (struct ar_hdr),
Packit Service 97d2fb
		      ref->state.ar.elf_ar_hdr.ar_size, cmd, ref);
Packit Service 97d2fb
Packit Service 97d2fb
  /* Enlist this new descriptor in the list of children.  */
Packit Service 97d2fb
  if (result != NULL)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      result->next = ref->state.ar.children;
Packit Service 97d2fb
      ref->state.ar.children = result;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  return result;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
Packit Service 97d2fb
/* Return desriptor for empty file ready for writing.  */
Packit Service 97d2fb
static struct Elf *
Packit Service 97d2fb
write_file (int fd, Elf_Cmd cmd)
Packit Service 97d2fb
{
Packit Service 97d2fb
  /* We simply create an empty `Elf' structure.  */
Packit Service 97d2fb
#define NSCNSALLOC	10
Packit Service 97d2fb
  Elf *result = allocate_elf (fd, NULL, 0, 0, cmd, NULL, ELF_K_ELF,
Packit Service 97d2fb
			      NSCNSALLOC * sizeof (Elf_Scn));
Packit Service 97d2fb
Packit Service 97d2fb
  if (result != NULL)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      /* We have to write to the file in any case.  */
Packit Service 97d2fb
      result->flags = ELF_F_DIRTY;
Packit Service 97d2fb
Packit Service 97d2fb
      /* Some more or less arbitrary value.  */
Packit Service 97d2fb
      result->state.elf.scnincr = NSCNSALLOC;
Packit Service 97d2fb
Packit Service 97d2fb
      /* We have allocated room for some sections.  */
Packit Service 97d2fb
      assert (offsetof (struct Elf, state.elf32.scns)
Packit Service 97d2fb
	      == offsetof (struct Elf, state.elf64.scns));
Packit Service 97d2fb
      result->state.elf.scns_last = &result->state.elf32.scns;
Packit Service 97d2fb
      result->state.elf32.scns.max = NSCNSALLOC;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  return result;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
/* Lock if necessary before dup an archive.  */
Packit Service 97d2fb
static inline Elf *
Packit Service 97d2fb
lock_dup_elf (int fildes, Elf_Cmd cmd, Elf *ref)
Packit Service 97d2fb
{
Packit Service 97d2fb
  /* We need wrlock to dup an archive.  */
Packit Service 97d2fb
  if (ref->kind == ELF_K_AR)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      rwlock_unlock (ref->lock);
Packit Service 97d2fb
      rwlock_wrlock (ref->lock);
Packit Service 97d2fb
    }
Packit Service 97d2fb
    /* Duplicate the descriptor.  */
Packit Service 97d2fb
  return dup_elf (fildes, cmd, ref);
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
/* Return a descriptor for the file belonging to FILDES.  */
Packit Service 97d2fb
Elf *
Packit Service 97d2fb
elf_begin (int fildes, Elf_Cmd cmd, Elf *ref)
Packit Service 97d2fb
{
Packit Service 97d2fb
  Elf *retval;
Packit Service 97d2fb
Packit Service 97d2fb
  if (unlikely (__libelf_version != EV_CURRENT))
Packit Service 97d2fb
    {
Packit Service 97d2fb
      /* Version wasn't set so far.  */
Packit Service 97d2fb
      __libelf_seterrno (ELF_E_NO_VERSION);
Packit Service 97d2fb
      return NULL;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  if (ref != NULL)
Packit Service 97d2fb
    /* Make sure the descriptor is not suddenly going away.  */
Packit Service 97d2fb
    rwlock_rdlock (ref->lock);
Packit Service 97d2fb
  else if (unlikely (fcntl (fildes, F_GETFD) == -1 && errno == EBADF))
Packit Service 97d2fb
    {
Packit Service 97d2fb
      /* We cannot do anything productive without a file descriptor.  */
Packit Service 97d2fb
      __libelf_seterrno (ELF_E_INVALID_FILE);
Packit Service 97d2fb
      return NULL;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  switch (cmd)
Packit Service 97d2fb
    {
Packit Service 97d2fb
    case ELF_C_NULL:
Packit Service 97d2fb
      /* We simply return a NULL pointer.  */
Packit Service 97d2fb
      retval = NULL;
Packit Service 97d2fb
      break;
Packit Service 97d2fb
Packit Service 97d2fb
    case ELF_C_READ_MMAP_PRIVATE:
Packit Service 97d2fb
      /* If we have a reference it must also be opened this way.  */
Packit Service 97d2fb
      if (unlikely (ref != NULL && ref->cmd != ELF_C_READ_MMAP_PRIVATE))
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  __libelf_seterrno (ELF_E_INVALID_CMD);
Packit Service 97d2fb
	  retval = NULL;
Packit Service 97d2fb
	  break;
Packit Service 97d2fb
	}
Packit Service 97d2fb
      FALLTHROUGH;
Packit Service 97d2fb
Packit Service 97d2fb
    case ELF_C_READ:
Packit Service 97d2fb
    case ELF_C_READ_MMAP:
Packit Service 97d2fb
      if (ref != NULL)
Packit Service 97d2fb
	retval = lock_dup_elf (fildes, cmd, ref);
Packit Service 97d2fb
      else
Packit Service 97d2fb
	/* Create descriptor for existing file.  */
Packit Service 97d2fb
	retval = read_file (fildes, 0, ~((size_t) 0), cmd, NULL);
Packit Service 97d2fb
      break;
Packit Service 97d2fb
Packit Service 97d2fb
    case ELF_C_RDWR:
Packit Service 97d2fb
    case ELF_C_RDWR_MMAP:
Packit Service 97d2fb
      /* If we have a REF object it must also be opened using this
Packit Service 97d2fb
	 command.  */
Packit Service 97d2fb
      if (ref != NULL)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  if (unlikely (ref->cmd != ELF_C_RDWR && ref->cmd != ELF_C_RDWR_MMAP
Packit Service 97d2fb
			&& ref->cmd != ELF_C_WRITE
Packit Service 97d2fb
			&& ref->cmd != ELF_C_WRITE_MMAP))
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      /* This is not ok.  REF must also be opened for writing.  */
Packit Service 97d2fb
	      __libelf_seterrno (ELF_E_INVALID_CMD);
Packit Service 97d2fb
	      retval = NULL;
Packit Service 97d2fb
	    }
Packit Service 97d2fb
	  else
Packit Service 97d2fb
	    retval = lock_dup_elf (fildes, cmd, ref);
Packit Service 97d2fb
	}
Packit Service 97d2fb
      else
Packit Service 97d2fb
	/* Create descriptor for existing file.  */
Packit Service 97d2fb
	retval = read_file (fildes, 0, ~((size_t) 0), cmd, NULL);
Packit Service 97d2fb
      break;
Packit Service 97d2fb
Packit Service 97d2fb
    case ELF_C_WRITE:
Packit Service 97d2fb
    case ELF_C_WRITE_MMAP:
Packit Service 97d2fb
      /* We ignore REF and prepare a descriptor to write a new file.  */
Packit Service 97d2fb
      retval = write_file (fildes, cmd);
Packit Service 97d2fb
      break;
Packit Service 97d2fb
Packit Service 97d2fb
    default:
Packit Service 97d2fb
      __libelf_seterrno (ELF_E_INVALID_CMD);
Packit Service 97d2fb
      retval = NULL;
Packit Service 97d2fb
      break;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  /* Release the lock.  */
Packit Service 97d2fb
  if (ref != NULL)
Packit Service 97d2fb
    rwlock_unlock (ref->lock);
Packit Service 97d2fb
Packit Service 97d2fb
  return retval;
Packit Service 97d2fb
}
Packit Service 97d2fb
INTDEF(elf_begin)