Blame libelf/elf32_getshdr.c

Packit Service 97d2fb
/* Return section header.
Packit Service 97d2fb
   Copyright (C) 1998-2002, 2005, 2007, 2009, 2012, 2014, 2015 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 <errno.h>
Packit Service 97d2fb
#include <stdbool.h>
Packit Service 97d2fb
#include <unistd.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
#ifndef LIBELFBITS
Packit Service 97d2fb
# define LIBELFBITS 32
Packit Service 97d2fb
#endif
Packit Service 97d2fb
Packit Service 97d2fb
Packit Service 97d2fb
static ElfW2(LIBELFBITS,Shdr) *
Packit Service 97d2fb
load_shdr_wrlock (Elf_Scn *scn)
Packit Service 97d2fb
{
Packit Service 97d2fb
  ElfW2(LIBELFBITS,Shdr) *result;
Packit Service 97d2fb
Packit Service 97d2fb
  /* Read the section header table.  */
Packit Service 97d2fb
  Elf *elf = scn->elf;
Packit Service 97d2fb
  ElfW2(LIBELFBITS,Ehdr) *ehdr = elf->state.ELFW(elf,LIBELFBITS).ehdr;
Packit Service 97d2fb
Packit Service 97d2fb
  /* Try again, maybe the data is there now.  */
Packit Service 97d2fb
  result = scn->shdr.ELFW(e,LIBELFBITS);
Packit Service 97d2fb
  if (result != NULL)
Packit Service 97d2fb
    goto out;
Packit Service 97d2fb
Packit Service 97d2fb
  size_t shnum;
Packit Service 97d2fb
  if (__elf_getshdrnum_rdlock (elf, &shnum) != 0
Packit Service 97d2fb
      || shnum > SIZE_MAX / sizeof (ElfW2(LIBELFBITS,Shdr)))
Packit Service 97d2fb
    goto out;
Packit Service 97d2fb
  size_t size = shnum * sizeof (ElfW2(LIBELFBITS,Shdr));
Packit Service 97d2fb
Packit Service 97d2fb
  /* Allocate memory for the section headers.  We know the number
Packit Service 97d2fb
     of entries from the ELF header.  */
Packit Service 97d2fb
  ElfW2(LIBELFBITS,Shdr) *shdr = elf->state.ELFW(elf,LIBELFBITS).shdr =
Packit Service 97d2fb
    (ElfW2(LIBELFBITS,Shdr) *) malloc (size);
Packit Service 97d2fb
  if (elf->state.ELFW(elf,LIBELFBITS).shdr == NULL)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      __libelf_seterrno (ELF_E_NOMEM);
Packit Service 97d2fb
      goto out;
Packit Service 97d2fb
    }
Packit Service 97d2fb
  elf->state.ELFW(elf,LIBELFBITS).shdr_malloced = 1;
Packit Service 97d2fb
Packit Service 97d2fb
  if (elf->map_address != NULL)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      /* First see whether the information in the ELF header is
Packit Service 97d2fb
	 valid and it does not ask for too much.  */
Packit Service 97d2fb
      if (unlikely (ehdr->e_shoff >= elf->maximum_size)
Packit Service 97d2fb
	  || unlikely (elf->maximum_size - ehdr->e_shoff < size))
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  /* Something is wrong.  */
Packit Service 97d2fb
	  __libelf_seterrno (ELF_E_INVALID_SECTION_HEADER);
Packit Service 97d2fb
	  goto free_and_out;
Packit Service 97d2fb
	}
Packit Service 97d2fb
Packit Service 97d2fb
      ElfW2(LIBELFBITS,Shdr) *notcvt;
Packit Service 97d2fb
Packit Service 97d2fb
      /* All the data is already mapped.  If we could use it
Packit Service 97d2fb
	 directly this would already have happened.  Unless
Packit Service 97d2fb
	 we allocated the memory ourselves and the ELF_F_MALLOCED
Packit Service 97d2fb
	 flag is set.  */
Packit Service 97d2fb
      void *file_shdr = ((char *) elf->map_address
Packit Service 97d2fb
			 + elf->start_offset + ehdr->e_shoff);
Packit Service 97d2fb
Packit Service 97d2fb
      assert ((elf->flags & ELF_F_MALLOCED)
Packit Service 97d2fb
	      || ehdr->e_ident[EI_DATA] != MY_ELFDATA
Packit Service 97d2fb
	      || elf->cmd == ELF_C_READ_MMAP
Packit Service 97d2fb
	      || (! ALLOW_UNALIGNED
Packit Service 97d2fb
		  && ((uintptr_t) file_shdr
Packit Service 97d2fb
		      & (__alignof__ (ElfW2(LIBELFBITS,Shdr)) - 1)) != 0));
Packit Service 97d2fb
Packit Service 97d2fb
      /* Now copy the data and at the same time convert the byte order.  */
Packit Service 97d2fb
      if (ehdr->e_ident[EI_DATA] == MY_ELFDATA)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  assert ((elf->flags & ELF_F_MALLOCED)
Packit Service 97d2fb
		  || elf->cmd == ELF_C_READ_MMAP
Packit Service 97d2fb
		  || ! ALLOW_UNALIGNED);
Packit Service 97d2fb
	  memcpy (shdr, file_shdr, size);
Packit Service 97d2fb
	}
Packit Service 97d2fb
      else
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  bool copy = ! (ALLOW_UNALIGNED
Packit Service 97d2fb
			 || ((uintptr_t) file_shdr
Packit Service 97d2fb
			     & (__alignof__ (ElfW2(LIBELFBITS,Shdr)) - 1))
Packit Service 97d2fb
			     == 0);
Packit Service 97d2fb
	  if (! copy)
Packit Service 97d2fb
	    notcvt = (ElfW2(LIBELFBITS,Shdr) *)
Packit Service 97d2fb
	      ((char *) elf->map_address
Packit Service 97d2fb
	       + elf->start_offset + ehdr->e_shoff);
Packit Service 97d2fb
	  else
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      notcvt = (ElfW2(LIBELFBITS,Shdr) *) malloc (size);
Packit Service 97d2fb
	      if (unlikely (notcvt == NULL))
Packit Service 97d2fb
		{
Packit Service 97d2fb
		  __libelf_seterrno (ELF_E_NOMEM);
Packit Service 97d2fb
		  goto out;
Packit Service 97d2fb
		}
Packit Service 97d2fb
	      memcpy (notcvt, ((char *) elf->map_address
Packit Service 97d2fb
			       + elf->start_offset + ehdr->e_shoff),
Packit Service 97d2fb
		      size);
Packit Service 97d2fb
	    }
Packit Service 97d2fb
Packit Service 97d2fb
	  for (size_t cnt = 0; cnt < shnum; ++cnt)
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      CONVERT_TO (shdr[cnt].sh_name, notcvt[cnt].sh_name);
Packit Service 97d2fb
	      CONVERT_TO (shdr[cnt].sh_type, notcvt[cnt].sh_type);
Packit Service 97d2fb
	      CONVERT_TO (shdr[cnt].sh_flags, notcvt[cnt].sh_flags);
Packit Service 97d2fb
	      CONVERT_TO (shdr[cnt].sh_addr, notcvt[cnt].sh_addr);
Packit Service 97d2fb
	      CONVERT_TO (shdr[cnt].sh_offset, notcvt[cnt].sh_offset);
Packit Service 97d2fb
	      CONVERT_TO (shdr[cnt].sh_size, notcvt[cnt].sh_size);
Packit Service 97d2fb
	      CONVERT_TO (shdr[cnt].sh_link, notcvt[cnt].sh_link);
Packit Service 97d2fb
	      CONVERT_TO (shdr[cnt].sh_info, notcvt[cnt].sh_info);
Packit Service 97d2fb
	      CONVERT_TO (shdr[cnt].sh_addralign,
Packit Service 97d2fb
			  notcvt[cnt].sh_addralign);
Packit Service 97d2fb
	      CONVERT_TO (shdr[cnt].sh_entsize, notcvt[cnt].sh_entsize);
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 (shdr[cnt].sh_type == SHT_SYMTAB_SHNDX
Packit Service 97d2fb
		  && shdr[cnt].sh_link < shnum)
Packit Service 97d2fb
		elf->state.ELFW(elf,LIBELFBITS).scns.data[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.ELFW(elf,LIBELFBITS).scns.data[cnt].shndx_index == 0)
Packit Service 97d2fb
		elf->state.ELFW(elf,LIBELFBITS).scns.data[cnt].shndx_index
Packit Service 97d2fb
		  = -1;
Packit Service 97d2fb
	    }
Packit Service 97d2fb
Packit Service 97d2fb
	  if (copy)
Packit Service 97d2fb
	    free (notcvt);
Packit Service 97d2fb
	}
Packit Service 97d2fb
    }
Packit Service 97d2fb
  else if (likely (elf->fildes != -1))
Packit Service 97d2fb
    {
Packit Service 97d2fb
      /* Read the header.  */
Packit Service 97d2fb
      ssize_t n = pread_retry (elf->fildes,
Packit Service 97d2fb
			       elf->state.ELFW(elf,LIBELFBITS).shdr, size,
Packit Service 97d2fb
			       elf->start_offset + ehdr->e_shoff);
Packit Service 97d2fb
      if (unlikely ((size_t) n != size))
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  /* Severe problems.  We cannot read the data.  */
Packit Service 97d2fb
	  __libelf_seterrno (ELF_E_READ_ERROR);
Packit Service 97d2fb
	  goto free_and_out;
Packit Service 97d2fb
	}
Packit Service 97d2fb
Packit Service 97d2fb
      /* If the byte order of the file is not the same as the one
Packit Service 97d2fb
	 of the host convert the data now.  */
Packit Service 97d2fb
      if (ehdr->e_ident[EI_DATA] != MY_ELFDATA)
Packit Service 97d2fb
	for (size_t cnt = 0; cnt < shnum; ++cnt)
Packit Service 97d2fb
	  {
Packit Service 97d2fb
	    CONVERT (shdr[cnt].sh_name);
Packit Service 97d2fb
	    CONVERT (shdr[cnt].sh_type);
Packit Service 97d2fb
	    CONVERT (shdr[cnt].sh_flags);
Packit Service 97d2fb
	    CONVERT (shdr[cnt].sh_addr);
Packit Service 97d2fb
	    CONVERT (shdr[cnt].sh_offset);
Packit Service 97d2fb
	    CONVERT (shdr[cnt].sh_size);
Packit Service 97d2fb
	    CONVERT (shdr[cnt].sh_link);
Packit Service 97d2fb
	    CONVERT (shdr[cnt].sh_info);
Packit Service 97d2fb
	    CONVERT (shdr[cnt].sh_addralign);
Packit Service 97d2fb
	    CONVERT (shdr[cnt].sh_entsize);
Packit Service 97d2fb
	  }
Packit Service 97d2fb
    }
Packit Service 97d2fb
  else
Packit Service 97d2fb
    {
Packit Service 97d2fb
      /* The file descriptor was already enabled and not all data was
Packit Service 97d2fb
	 read.  Undo the allocation.  */
Packit Service 97d2fb
      __libelf_seterrno (ELF_E_FD_DISABLED);
Packit Service 97d2fb
Packit Service 97d2fb
    free_and_out:
Packit Service 97d2fb
      free (shdr);
Packit Service 97d2fb
      elf->state.ELFW(elf,LIBELFBITS).shdr = NULL;
Packit Service 97d2fb
      elf->state.ELFW(elf,LIBELFBITS).shdr_malloced = 0;
Packit Service 97d2fb
Packit Service 97d2fb
      goto out;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  /* Set the pointers in the `scn's.  */
Packit Service 97d2fb
  for (size_t cnt = 0; cnt < shnum; ++cnt)
Packit Service 97d2fb
    elf->state.ELFW(elf,LIBELFBITS).scns.data[cnt].shdr.ELFW(e,LIBELFBITS)
Packit Service 97d2fb
      = &elf->state.ELFW(elf,LIBELFBITS).shdr[cnt];
Packit Service 97d2fb
Packit Service 97d2fb
  result = scn->shdr.ELFW(e,LIBELFBITS);
Packit Service 97d2fb
  assert (result != NULL);
Packit Service 97d2fb
Packit Service 97d2fb
out:
Packit Service 97d2fb
  return result;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
static bool
Packit Service 97d2fb
scn_valid (Elf_Scn *scn)
Packit Service 97d2fb
{
Packit Service 97d2fb
  if (scn == NULL)
Packit Service 97d2fb
    return false;
Packit Service 97d2fb
Packit Service 97d2fb
  if (unlikely (scn->elf->state.elf.ehdr == NULL))
Packit Service 97d2fb
    {
Packit Service 97d2fb
      __libelf_seterrno (ELF_E_WRONG_ORDER_EHDR);
Packit Service 97d2fb
      return false;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  if (unlikely (scn->elf->class != ELFW(ELFCLASS,LIBELFBITS)))
Packit Service 97d2fb
    {
Packit Service 97d2fb
      __libelf_seterrno (ELF_E_INVALID_CLASS);
Packit Service 97d2fb
      return false;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  return true;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
ElfW2(LIBELFBITS,Shdr) *
Packit Service 97d2fb
internal_function
Packit Service 97d2fb
__elfw2(LIBELFBITS,getshdr_rdlock) (Elf_Scn *scn)
Packit Service 97d2fb
{
Packit Service 97d2fb
  ElfW2(LIBELFBITS,Shdr) *result;
Packit Service 97d2fb
Packit Service 97d2fb
  if (!scn_valid (scn))
Packit Service 97d2fb
    return NULL;
Packit Service 97d2fb
Packit Service 97d2fb
  result = scn->shdr.ELFW(e,LIBELFBITS);
Packit Service 97d2fb
  if (result == NULL)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      rwlock_unlock (scn->elf->lock);
Packit Service 97d2fb
      rwlock_wrlock (scn->elf->lock);
Packit Service 97d2fb
      result = scn->shdr.ELFW(e,LIBELFBITS);
Packit Service 97d2fb
      if (result == NULL)
Packit Service 97d2fb
	result = load_shdr_wrlock (scn);
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  return result;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
ElfW2(LIBELFBITS,Shdr) *
Packit Service 97d2fb
internal_function
Packit Service 97d2fb
__elfw2(LIBELFBITS,getshdr_wrlock) (Elf_Scn *scn)
Packit Service 97d2fb
{
Packit Service 97d2fb
  ElfW2(LIBELFBITS,Shdr) *result;
Packit Service 97d2fb
Packit Service 97d2fb
  if (!scn_valid (scn))
Packit Service 97d2fb
    return NULL;
Packit Service 97d2fb
Packit Service 97d2fb
  result = scn->shdr.ELFW(e,LIBELFBITS);
Packit Service 97d2fb
  if (result == NULL)
Packit Service 97d2fb
    result = load_shdr_wrlock (scn);
Packit Service 97d2fb
Packit Service 97d2fb
  return result;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
ElfW2(LIBELFBITS,Shdr) *
Packit Service 97d2fb
elfw2(LIBELFBITS,getshdr) (Elf_Scn *scn)
Packit Service 97d2fb
{
Packit Service 97d2fb
  ElfW2(LIBELFBITS,Shdr) *result;
Packit Service 97d2fb
Packit Service 97d2fb
  if (!scn_valid (scn))
Packit Service 97d2fb
    return NULL;
Packit Service 97d2fb
Packit Service 97d2fb
  rwlock_rdlock (scn->elf->lock);
Packit Service 97d2fb
  result = __elfw2(LIBELFBITS,getshdr_rdlock) (scn);
Packit Service 97d2fb
  rwlock_unlock (scn->elf->lock);
Packit Service 97d2fb
Packit Service 97d2fb
  return result;
Packit Service 97d2fb
}