Blame libelf/elf_begin.c

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