Blame libelf/elf_getdata.c

Packit Service 97d2fb
/* Return the next data element from the section after possibly converting it.
Packit Service 97d2fb
   Copyright (C) 1998-2005, 2006, 2007, 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 <errno.h>
Packit Service 97d2fb
#include <stddef.h>
Packit Service 97d2fb
#include <string.h>
Packit Service 97d2fb
#include <unistd.h>
Packit Service 97d2fb
Packit Service 97d2fb
#include "libelfP.h"
Packit Service 97d2fb
#include <system.h>
Packit Service 97d2fb
#include "common.h"
Packit Service 97d2fb
#include "elf-knowledge.h"
Packit Service 97d2fb
Packit Service 97d2fb
Packit Service 97d2fb
#define TYPEIDX(Sh_Type) \
Packit Service 97d2fb
  (Sh_Type >= SHT_NULL && Sh_Type < SHT_NUM				      \
Packit Service 97d2fb
   ? Sh_Type								      \
Packit Service 97d2fb
   : (Sh_Type >= SHT_GNU_HASH && Sh_Type <= SHT_HISUNW			      \
Packit Service 97d2fb
      ? SHT_NUM + Sh_Type - SHT_GNU_HASH				      \
Packit Service 97d2fb
      : 0))
Packit Service 97d2fb
Packit Service 97d2fb
/* Associate section types with libelf types.  */
Packit Service 97d2fb
static const Elf_Type shtype_map[TYPEIDX (SHT_HISUNW) + 1] =
Packit Service 97d2fb
  {
Packit Service 97d2fb
      [SHT_SYMTAB] = ELF_T_SYM,
Packit Service 97d2fb
      [SHT_RELA] = ELF_T_RELA,
Packit Service 97d2fb
      [SHT_HASH] = ELF_T_WORD,
Packit Service 97d2fb
      [SHT_DYNAMIC] = ELF_T_DYN,
Packit Service 97d2fb
      [SHT_REL] = ELF_T_REL,
Packit Service 97d2fb
      [SHT_DYNSYM] = ELF_T_SYM,
Packit Service 97d2fb
      [SHT_INIT_ARRAY] = ELF_T_ADDR,
Packit Service 97d2fb
      [SHT_FINI_ARRAY] = ELF_T_ADDR,
Packit Service 97d2fb
      [SHT_PREINIT_ARRAY] = ELF_T_ADDR,
Packit Service 97d2fb
      [SHT_GROUP] = ELF_T_WORD,
Packit Service 97d2fb
      [SHT_SYMTAB_SHNDX] = ELF_T_WORD,
Packit Service 97d2fb
      [SHT_NOTE] = ELF_T_NHDR, /* Need alignment to guess ELF_T_NHDR8.  */
Packit Service 97d2fb
      [TYPEIDX (SHT_GNU_verdef)] = ELF_T_VDEF,
Packit Service 97d2fb
      [TYPEIDX (SHT_GNU_verneed)] = ELF_T_VNEED,
Packit Service 97d2fb
      [TYPEIDX (SHT_GNU_versym)] = ELF_T_HALF,
Packit Service 97d2fb
      [TYPEIDX (SHT_SUNW_syminfo)] = ELF_T_SYMINFO,
Packit Service 97d2fb
      [TYPEIDX (SHT_SUNW_move)] = ELF_T_MOVE,
Packit Service 97d2fb
      [TYPEIDX (SHT_GNU_LIBLIST)] = ELF_T_LIB,
Packit Service 97d2fb
      [TYPEIDX (SHT_GNU_HASH)] = ELF_T_GNUHASH,
Packit Service 97d2fb
  };
Packit Service 97d2fb
Packit Service 97d2fb
/* Associate libelf types with their internal alignment requirements.  */
Packit Service 97d2fb
const uint_fast8_t __libelf_type_aligns[ELFCLASSNUM - 1][ELF_T_NUM] =
Packit Service 97d2fb
  {
Packit Service 97d2fb
# define TYPE_ALIGNS(Bits)						      \
Packit Service 97d2fb
    {									      \
Packit Service 97d2fb
      [ELF_T_ADDR] = __alignof__ (ElfW2(Bits,Addr)),			      \
Packit Service 97d2fb
      [ELF_T_EHDR] = __alignof__ (ElfW2(Bits,Ehdr)),			      \
Packit Service 97d2fb
      [ELF_T_HALF] = __alignof__ (ElfW2(Bits,Half)),			      \
Packit Service 97d2fb
      [ELF_T_OFF] = __alignof__ (ElfW2(Bits,Off)),			      \
Packit Service 97d2fb
      [ELF_T_PHDR] = __alignof__ (ElfW2(Bits,Phdr)),			      \
Packit Service 97d2fb
      [ELF_T_SHDR] = __alignof__ (ElfW2(Bits,Shdr)),			      \
Packit Service 97d2fb
      [ELF_T_SWORD] = __alignof__ (ElfW2(Bits,Sword)),			      \
Packit Service 97d2fb
      [ELF_T_WORD] = __alignof__ (ElfW2(Bits,Word)),			      \
Packit Service 97d2fb
      [ELF_T_XWORD] = __alignof__ (ElfW2(Bits,Xword)),			      \
Packit Service 97d2fb
      [ELF_T_SXWORD] = __alignof__ (ElfW2(Bits,Sxword)),		      \
Packit Service 97d2fb
      [ELF_T_SYM] = __alignof__ (ElfW2(Bits,Sym)),			      \
Packit Service 97d2fb
      [ELF_T_SYMINFO] = __alignof__ (ElfW2(Bits,Syminfo)),		      \
Packit Service 97d2fb
      [ELF_T_REL] = __alignof__ (ElfW2(Bits,Rel)),			      \
Packit Service 97d2fb
      [ELF_T_RELA] = __alignof__ (ElfW2(Bits,Rela)),			      \
Packit Service 97d2fb
      [ELF_T_DYN] = __alignof__ (ElfW2(Bits,Dyn)),			      \
Packit Service 97d2fb
      [ELF_T_VDEF] = __alignof__ (ElfW2(Bits,Verdef)),			      \
Packit Service 97d2fb
      [ELF_T_VDAUX] = __alignof__ (ElfW2(Bits,Verdaux)),		      \
Packit Service 97d2fb
      [ELF_T_VNEED] = __alignof__ (ElfW2(Bits,Verneed)),		      \
Packit Service 97d2fb
      [ELF_T_VNAUX] = __alignof__ (ElfW2(Bits,Vernaux)),		      \
Packit Service 97d2fb
      [ELF_T_MOVE] = __alignof__ (ElfW2(Bits,Move)),			      \
Packit Service 97d2fb
      [ELF_T_LIB] = __alignof__ (ElfW2(Bits,Lib)),			      \
Packit Service 97d2fb
      [ELF_T_NHDR] = __alignof__ (ElfW2(Bits,Nhdr)),			      \
Packit Service 97d2fb
      [ELF_T_GNUHASH] = __alignof__ (Elf32_Word),			      \
Packit Service 97d2fb
      [ELF_T_AUXV] = __alignof__ (ElfW2(Bits,auxv_t)),			      \
Packit Service 97d2fb
      [ELF_T_CHDR] = __alignof__ (ElfW2(Bits,Chdr)),			      \
Packit Service 97d2fb
      [ELF_T_NHDR8] = 8 /* Special case for GNU Property note.  */	      \
Packit Service 97d2fb
    }
Packit Service 97d2fb
      [ELFCLASS32 - 1] = TYPE_ALIGNS (32),
Packit Service 97d2fb
      [ELFCLASS64 - 1] = TYPE_ALIGNS (64),
Packit Service 97d2fb
# undef TYPE_ALIGNS
Packit Service 97d2fb
  };
Packit Service 97d2fb
Packit Service 97d2fb
Packit Service 97d2fb
Elf_Type
Packit Service 97d2fb
internal_function
Packit Service 97d2fb
__libelf_data_type (Elf *elf, int sh_type, GElf_Xword align)
Packit Service 97d2fb
{
Packit Service 97d2fb
  /* Some broken ELF ABI for 64-bit machines use the wrong hash table
Packit Service 97d2fb
     entry size.  See elf-knowledge.h for more information.  */
Packit Service 97d2fb
  if (sh_type == SHT_HASH && elf->class == ELFCLASS64)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      GElf_Ehdr ehdr_mem;
Packit Service 97d2fb
      GElf_Ehdr *ehdr = __gelf_getehdr_rdlock (elf, &ehdr_mem);
Packit Service 97d2fb
      return (SH_ENTSIZE_HASH (ehdr) == 4 ? ELF_T_WORD : ELF_T_XWORD);
Packit Service 97d2fb
    }
Packit Service 97d2fb
  else
Packit Service 97d2fb
    {
Packit Service 97d2fb
      Elf_Type t = shtype_map[TYPEIDX (sh_type)];
Packit Service 97d2fb
      /* Special case for GNU Property notes.  */
Packit Service 97d2fb
      if (t == ELF_T_NHDR && align == 8)
Packit Service 97d2fb
	t = ELF_T_NHDR8;
Packit Service 97d2fb
      return t;
Packit Service 97d2fb
    }
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
/* Convert the data in the current section.  */
Packit Service 97d2fb
static void
Packit Service 97d2fb
convert_data (Elf_Scn *scn, int eclass,
Packit Service 97d2fb
	      int data, size_t size, Elf_Type type)
Packit Service 97d2fb
{
Packit Service 97d2fb
  const size_t align = __libelf_type_align (eclass, type);
Packit Service 97d2fb
Packit Service 97d2fb
  /* Do we need to convert the data and/or adjust for alignment?  */
Packit Service 97d2fb
  if (data == MY_ELFDATA || type == ELF_T_BYTE)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      if (((((size_t) (char *) scn->rawdata_base)) & (align - 1)) == 0)
Packit Service 97d2fb
	/* No need to copy, we can use the raw data.  */
Packit Service 97d2fb
	scn->data_base = scn->rawdata_base;
Packit Service 97d2fb
      else
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  scn->data_base = (char *) malloc (size);
Packit Service 97d2fb
	  if (scn->data_base == NULL)
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      __libelf_seterrno (ELF_E_NOMEM);
Packit Service 97d2fb
	      return;
Packit Service 97d2fb
	    }
Packit Service 97d2fb
Packit Service 97d2fb
	  /* The copy will be appropriately aligned for direct access.  */
Packit Service 97d2fb
	  memcpy (scn->data_base, scn->rawdata_base, size);
Packit Service 97d2fb
	}
Packit Service 97d2fb
    }
Packit Service 97d2fb
  else
Packit Service 97d2fb
    {
Packit Service 97d2fb
      xfct_t fp;
Packit Service 97d2fb
Packit Service 97d2fb
      scn->data_base = (char *) malloc (size);
Packit Service 97d2fb
      if (scn->data_base == NULL)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  __libelf_seterrno (ELF_E_NOMEM);
Packit Service 97d2fb
	  return;
Packit Service 97d2fb
	}
Packit Service 97d2fb
Packit Service 97d2fb
      /* Make sure the source is correctly aligned for the conversion
Packit Service 97d2fb
	 function to directly access the data elements.  */
Packit Service 97d2fb
      char *rawdata_source;
Packit Service 97d2fb
      if (((((size_t) (char *) scn->rawdata_base)) & (align - 1)) == 0)
Packit Service 97d2fb
	rawdata_source = scn->rawdata_base;
Packit Service 97d2fb
      else
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  rawdata_source = (char *) malloc (size);
Packit Service 97d2fb
	  if (rawdata_source == NULL)
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      __libelf_seterrno (ELF_E_NOMEM);
Packit Service 97d2fb
	      return;
Packit Service 97d2fb
	    }
Packit Service 97d2fb
Packit Service 97d2fb
	  /* The copy will be appropriately aligned for direct access.  */
Packit Service 97d2fb
	  memcpy (rawdata_source, scn->rawdata_base, size);
Packit Service 97d2fb
	}
Packit Service 97d2fb
Packit Service 97d2fb
      /* Get the conversion function.  */
Packit Service 97d2fb
      fp = __elf_xfctstom[eclass - 1][type];
Packit Service 97d2fb
Packit Service 97d2fb
      fp (scn->data_base, rawdata_source, size, 0);
Packit Service 97d2fb
Packit Service 97d2fb
      if (rawdata_source != scn->rawdata_base)
Packit Service 97d2fb
	free (rawdata_source);
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  scn->data_list.data.d.d_buf = scn->data_base;
Packit Service 97d2fb
  scn->data_list.data.d.d_size = size;
Packit Service 97d2fb
  scn->data_list.data.d.d_type = type;
Packit Service 97d2fb
  scn->data_list.data.d.d_off = scn->rawdata.d.d_off;
Packit Service 97d2fb
  scn->data_list.data.d.d_align = scn->rawdata.d.d_align;
Packit Service 97d2fb
  scn->data_list.data.d.d_version = scn->rawdata.d.d_version;
Packit Service 97d2fb
Packit Service 97d2fb
  scn->data_list.data.s = scn;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
Packit Service 97d2fb
/* Store the information for the raw data in the `rawdata' element.  */
Packit Service 97d2fb
int
Packit Service 97d2fb
internal_function
Packit Service 97d2fb
__libelf_set_rawdata_wrlock (Elf_Scn *scn)
Packit Service 97d2fb
{
Packit Service 97d2fb
  Elf64_Off offset;
Packit Service 97d2fb
  Elf64_Xword size;
Packit Service 97d2fb
  Elf64_Xword align;
Packit Service 97d2fb
  Elf64_Xword flags;
Packit Service 97d2fb
  int type;
Packit Service 97d2fb
  Elf *elf = scn->elf;
Packit Service 97d2fb
Packit Service 97d2fb
  if (elf->class == ELFCLASS32)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      Elf32_Shdr *shdr
Packit Service 97d2fb
	= scn->shdr.e32 ?: __elf32_getshdr_wrlock (scn);
Packit Service 97d2fb
Packit Service 97d2fb
      if (shdr == NULL)
Packit Service 97d2fb
	/* Something went terribly wrong.  */
Packit Service 97d2fb
	return 1;
Packit Service 97d2fb
Packit Service 97d2fb
      offset = shdr->sh_offset;
Packit Service 97d2fb
      size = shdr->sh_size;
Packit Service 97d2fb
      type = shdr->sh_type;
Packit Service 97d2fb
      align = shdr->sh_addralign;
Packit Service 97d2fb
      flags = shdr->sh_flags;
Packit Service 97d2fb
    }
Packit Service 97d2fb
  else
Packit Service 97d2fb
    {
Packit Service 97d2fb
      Elf64_Shdr *shdr
Packit Service 97d2fb
	= scn->shdr.e64 ?: __elf64_getshdr_wrlock (scn);
Packit Service 97d2fb
Packit Service 97d2fb
      if (shdr == NULL)
Packit Service 97d2fb
	/* Something went terribly wrong.  */
Packit Service 97d2fb
	return 1;
Packit Service 97d2fb
Packit Service 97d2fb
      offset = shdr->sh_offset;
Packit Service 97d2fb
      size = shdr->sh_size;
Packit Service 97d2fb
      type = shdr->sh_type;
Packit Service 97d2fb
      align = shdr->sh_addralign;
Packit Service 97d2fb
      flags = shdr->sh_flags;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  /* If the section has no data (for whatever reason), leave the `d_buf'
Packit Service 97d2fb
     pointer NULL.  */
Packit Service 97d2fb
  if (size != 0 && type != SHT_NOBITS)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      /* First a test whether the section is valid at all.  */
Packit Service 97d2fb
      size_t entsize;
Packit Service 97d2fb
Packit Service 97d2fb
      /* Compressed data has a header, but then compressed data.
Packit Service 97d2fb
	 Make sure to set the alignment of the header explicitly,
Packit Service 97d2fb
	 don't trust the file alignment for the section, it is
Packit Service 97d2fb
	 often wrong.  */
Packit Service 97d2fb
      if ((flags & SHF_COMPRESSED) != 0)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  entsize = 1;
Packit Service 97d2fb
	  align = __libelf_type_align (elf->class, ELF_T_CHDR);
Packit Service 97d2fb
	}
Packit Service 97d2fb
      else if (type == SHT_HASH)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  GElf_Ehdr ehdr_mem;
Packit Service 97d2fb
	  GElf_Ehdr *ehdr = __gelf_getehdr_rdlock (elf, &ehdr_mem);
Packit Service 97d2fb
	  if (unlikely (ehdr == NULL))
Packit Service 97d2fb
	    return 1;
Packit Service 97d2fb
	  entsize = SH_ENTSIZE_HASH (ehdr);
Packit Service 97d2fb
	}
Packit Service 97d2fb
      else
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  Elf_Type t = shtype_map[TYPEIDX (type)];
Packit Service 97d2fb
	  if (t == ELF_T_NHDR && align == 8)
Packit Service 97d2fb
	    t = ELF_T_NHDR8;
Packit Service 97d2fb
	  if (t == ELF_T_VDEF || t == ELF_T_NHDR || t == ELF_T_NHDR8
Packit Service 97d2fb
	      || (t == ELF_T_GNUHASH && elf->class == ELFCLASS64))
Packit Service 97d2fb
	    entsize = 1;
Packit Service 97d2fb
	  else
Packit Service 97d2fb
	    entsize = __libelf_type_sizes[elf->class - 1][t];
Packit Service 97d2fb
	}
Packit Service 97d2fb
Packit Service 97d2fb
      /* We assume it is an array of bytes if it is none of the structured
Packit Service 97d2fb
	 sections we know of.  */
Packit Service 97d2fb
      if (entsize == 0)
Packit Service 97d2fb
	entsize = 1;
Packit Service 97d2fb
Packit Service 97d2fb
      if (unlikely (size % entsize != 0))
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  __libelf_seterrno (ELF_E_INVALID_DATA);
Packit Service 97d2fb
	  return 1;
Packit Service 97d2fb
	}
Packit Service 97d2fb
Packit Service 97d2fb
      /* We can use the mapped or loaded data if available.  */
Packit Service 97d2fb
      if (elf->map_address != NULL)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  /* First see whether the information in the section header is
Packit Service 97d2fb
	     valid and it does not ask for too much.  Check for unsigned
Packit Service 97d2fb
	     overflow.  */
Packit Service 97d2fb
	  if (unlikely (offset > elf->maximum_size
Packit Service 97d2fb
	      || elf->maximum_size - offset < size))
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      /* Something is wrong.  */
Packit Service 97d2fb
	      __libelf_seterrno (ELF_E_INVALID_SECTION_HEADER);
Packit Service 97d2fb
	      return 1;
Packit Service 97d2fb
	    }
Packit Service 97d2fb
Packit Service 97d2fb
	  scn->rawdata_base = scn->rawdata.d.d_buf
Packit Service 97d2fb
	    = (char *) elf->map_address + elf->start_offset + offset;
Packit Service 97d2fb
	}
Packit Service 97d2fb
      else if (likely (elf->fildes != -1))
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  /* First see whether the information in the section header is
Packit Service 97d2fb
	     valid and it does not ask for too much.  Check for unsigned
Packit Service 97d2fb
	     overflow.  */
Packit Service 97d2fb
	  if (unlikely (offset > elf->maximum_size
Packit Service 97d2fb
			|| elf->maximum_size - offset < size))
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      /* Something is wrong.  */
Packit Service 97d2fb
	      __libelf_seterrno (ELF_E_INVALID_SECTION_HEADER);
Packit Service 97d2fb
	      return 1;
Packit Service 97d2fb
	    }
Packit Service 97d2fb
Packit Service 97d2fb
	  /* We have to read the data from the file.  Allocate the needed
Packit Service 97d2fb
	     memory.  */
Packit Service 97d2fb
	  scn->rawdata_base = scn->rawdata.d.d_buf
Packit Service 97d2fb
	    = (char *) malloc (size);
Packit Service 97d2fb
	  if (scn->rawdata.d.d_buf == NULL)
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      __libelf_seterrno (ELF_E_NOMEM);
Packit Service 97d2fb
	      return 1;
Packit Service 97d2fb
	    }
Packit Service 97d2fb
Packit Service 97d2fb
	  ssize_t n = pread_retry (elf->fildes, scn->rawdata.d.d_buf, size,
Packit Service 97d2fb
				   elf->start_offset + offset);
Packit Service 97d2fb
	  if (unlikely ((size_t) n != size))
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      /* Cannot read the data.  */
Packit Service 97d2fb
	      free (scn->rawdata.d.d_buf);
Packit Service 97d2fb
	      scn->rawdata_base = scn->rawdata.d.d_buf = NULL;
Packit Service 97d2fb
	      __libelf_seterrno (ELF_E_READ_ERROR);
Packit Service 97d2fb
	      return 1;
Packit Service 97d2fb
	    }
Packit Service 97d2fb
	}
Packit Service 97d2fb
      else
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  /* The file descriptor is already closed, we cannot get the data
Packit Service 97d2fb
	     anymore.  */
Packit Service 97d2fb
	  __libelf_seterrno (ELF_E_FD_DISABLED);
Packit Service 97d2fb
	  return 1;
Packit Service 97d2fb
	}
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  scn->rawdata.d.d_size = size;
Packit Service 97d2fb
Packit Service 97d2fb
  /* Compressed data always has type ELF_T_CHDR regardless of the
Packit Service 97d2fb
     section type.  */
Packit Service 97d2fb
  if ((flags & SHF_COMPRESSED) != 0)
Packit Service 97d2fb
    scn->rawdata.d.d_type = ELF_T_CHDR;
Packit Service 97d2fb
  else
Packit Service 97d2fb
    scn->rawdata.d.d_type = __libelf_data_type (elf, type, align);
Packit Service 97d2fb
  scn->rawdata.d.d_off = 0;
Packit Service 97d2fb
Packit Service 97d2fb
  /* Make sure the alignment makes sense.  d_align should be aligned both
Packit Service 97d2fb
     in the section (trivially true since d_off is zero) and in the file.
Packit Service 97d2fb
     Unfortunately we cannot be too strict because there are ELF files
Packit Service 97d2fb
     out there that fail this requirement.  We will try to fix those up
Packit Service 97d2fb
     in elf_update when writing out the image.  But for very large
Packit Service 97d2fb
     alignment values this can bloat the image considerably.  So here
Packit Service 97d2fb
     just check and clamp the alignment value to not be bigger than the
Packit Service 97d2fb
     actual offset of the data in the file.  Given that there is always
Packit Service 97d2fb
     at least an ehdr this will only trigger for alignment values > 64
Packit Service 97d2fb
     which should be uncommon.  */
Packit Service 97d2fb
  align = align ?: 1;
Packit Service 97d2fb
  if (type != SHT_NOBITS && align > offset)
Packit Service 97d2fb
    align = offset;
Packit Service 97d2fb
  scn->rawdata.d.d_align = align;
Packit Service 97d2fb
  if (elf->class == ELFCLASS32
Packit Service 97d2fb
      || (offsetof (struct Elf, state.elf32.ehdr)
Packit Service 97d2fb
	  == offsetof (struct Elf, state.elf64.ehdr)))
Packit Service 97d2fb
    scn->rawdata.d.d_version =
Packit Service 97d2fb
      elf->state.elf32.ehdr->e_ident[EI_VERSION];
Packit Service 97d2fb
  else
Packit Service 97d2fb
    scn->rawdata.d.d_version =
Packit Service 97d2fb
      elf->state.elf64.ehdr->e_ident[EI_VERSION];
Packit Service 97d2fb
Packit Service 97d2fb
  scn->rawdata.s = scn;
Packit Service 97d2fb
Packit Service 97d2fb
  scn->data_read = 1;
Packit Service 97d2fb
Packit Service 97d2fb
  /* We actually read data from the file.  At least we tried.  */
Packit Service 97d2fb
  scn->flags |= ELF_F_FILEDATA;
Packit Service 97d2fb
Packit Service 97d2fb
  return 0;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
int
Packit Service 97d2fb
internal_function
Packit Service 97d2fb
__libelf_set_rawdata (Elf_Scn *scn)
Packit Service 97d2fb
{
Packit Service 97d2fb
  int result;
Packit Service 97d2fb
Packit Service 97d2fb
  if (scn == NULL)
Packit Service 97d2fb
    return 1;
Packit Service 97d2fb
Packit Service 97d2fb
  rwlock_wrlock (scn->elf->lock);
Packit Service 97d2fb
  result = __libelf_set_rawdata_wrlock (scn);
Packit Service 97d2fb
  rwlock_unlock (scn->elf->lock);
Packit Service 97d2fb
Packit Service 97d2fb
  return result;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
void
Packit Service 97d2fb
internal_function
Packit Service 97d2fb
__libelf_set_data_list_rdlock (Elf_Scn *scn, int wrlocked)
Packit Service 97d2fb
{
Packit Service 97d2fb
  if (scn->rawdata.d.d_buf != NULL && scn->rawdata.d.d_size > 0)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      Elf *elf = scn->elf;
Packit Service 97d2fb
Packit Service 97d2fb
      /* Upgrade the lock to a write lock if necessary and check
Packit Service 97d2fb
	 nobody else already did the work.  */
Packit Service 97d2fb
      if (!wrlocked)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  rwlock_unlock (elf->lock);
Packit Service 97d2fb
	  rwlock_wrlock (elf->lock);
Packit Service 97d2fb
	  if (scn->data_list_rear != NULL)
Packit Service 97d2fb
	    return;
Packit Service 97d2fb
	}
Packit Service 97d2fb
Packit Service 97d2fb
      /* Convert according to the version and the type.   */
Packit Service 97d2fb
      convert_data (scn, elf->class,
Packit Service 97d2fb
		    (elf->class == ELFCLASS32
Packit Service 97d2fb
		     || (offsetof (struct Elf, state.elf32.ehdr)
Packit Service 97d2fb
			 == offsetof (struct Elf, state.elf64.ehdr))
Packit Service 97d2fb
		     ? elf->state.elf32.ehdr->e_ident[EI_DATA]
Packit Service 97d2fb
		     : elf->state.elf64.ehdr->e_ident[EI_DATA]),
Packit Service 97d2fb
		    scn->rawdata.d.d_size, scn->rawdata.d.d_type);
Packit Service 97d2fb
    }
Packit Service 97d2fb
  else
Packit Service 97d2fb
    {
Packit Service 97d2fb
      /* This is an empty or NOBITS section.  There is no buffer but
Packit Service 97d2fb
	 the size information etc is important.  */
Packit Service 97d2fb
      scn->data_list.data.d = scn->rawdata.d;
Packit Service 97d2fb
      scn->data_list.data.s = scn;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  scn->data_list_rear = &scn->data_list;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
Elf_Data *
Packit Service 97d2fb
internal_function
Packit Service 97d2fb
__elf_getdata_rdlock (Elf_Scn *scn, Elf_Data *data)
Packit Service 97d2fb
{
Packit Service 97d2fb
  Elf_Data *result = NULL;
Packit Service 97d2fb
  Elf *elf;
Packit Service 97d2fb
  int locked = 0;
Packit Service 97d2fb
Packit Service 97d2fb
  if (scn == NULL)
Packit Service 97d2fb
    return NULL;
Packit Service 97d2fb
Packit Service 97d2fb
  if (unlikely (scn->elf->kind != ELF_K_ELF))
Packit Service 97d2fb
    {
Packit Service 97d2fb
      __libelf_seterrno (ELF_E_INVALID_HANDLE);
Packit Service 97d2fb
      return NULL;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  /* We will need this multiple times later on.  */
Packit Service 97d2fb
  elf = scn->elf;
Packit Service 97d2fb
Packit Service 97d2fb
  /* If `data' is not NULL this means we are not addressing the initial
Packit Service 97d2fb
     data in the file.  But this also means this data is already read
Packit Service 97d2fb
     (since otherwise it is not possible to have a valid `data' pointer)
Packit Service 97d2fb
     and all the data structures are initialized as well.  In this case
Packit Service 97d2fb
     we can simply walk the list of data records.  */
Packit Service 97d2fb
  if (data != NULL)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      Elf_Data_List *runp;
Packit Service 97d2fb
Packit Service 97d2fb
      /* It is not possible that if DATA is not NULL the first entry is
Packit Service 97d2fb
	 returned.  But this also means that there must be a first data
Packit Service 97d2fb
	 entry.  */
Packit Service 97d2fb
      if (scn->data_list_rear == NULL
Packit Service 97d2fb
	  /* The section the reference data is for must match the section
Packit Service 97d2fb
	     parameter.  */
Packit Service 97d2fb
	  || unlikely (((Elf_Data_Scn *) data)->s != scn))
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  __libelf_seterrno (ELF_E_DATA_MISMATCH);
Packit Service 97d2fb
	  goto out;
Packit Service 97d2fb
	}
Packit Service 97d2fb
Packit Service 97d2fb
      /* We start searching with the first entry.  */
Packit Service 97d2fb
      runp = &scn->data_list;
Packit Service 97d2fb
Packit Service 97d2fb
      while (1)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  /* If `data' does not match any known record punt.  */
Packit Service 97d2fb
	  if (runp == NULL)
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      __libelf_seterrno (ELF_E_DATA_MISMATCH);
Packit Service 97d2fb
	      goto out;
Packit Service 97d2fb
	    }
Packit Service 97d2fb
Packit Service 97d2fb
	  if (&runp->data.d == data)
Packit Service 97d2fb
	    /* Found the entry.  */
Packit Service 97d2fb
	    break;
Packit Service 97d2fb
Packit Service 97d2fb
	  runp = runp->next;
Packit Service 97d2fb
	}
Packit Service 97d2fb
Packit Service 97d2fb
      /* Return the data for the next data record.  */
Packit Service 97d2fb
      result = runp->next ? &runp->next->data.d : NULL;
Packit Service 97d2fb
      goto out;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  /* If the data for this section was not yet initialized do it now.  */
Packit Service 97d2fb
  if (scn->data_read == 0)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      /* We cannot acquire a write lock while we are holding a read
Packit Service 97d2fb
         lock.  Therefore give up the read lock and then get the write
Packit Service 97d2fb
         lock.  But this means that the data could meanwhile be
Packit Service 97d2fb
         modified, therefore start the tests again.  */
Packit Service 97d2fb
      rwlock_unlock (elf->lock);
Packit Service 97d2fb
      rwlock_wrlock (elf->lock);
Packit Service 97d2fb
      locked = 1;
Packit Service 97d2fb
Packit Service 97d2fb
      /* Read the data from the file.  There is always a file (or
Packit Service 97d2fb
	 memory region) associated with this descriptor since
Packit Service 97d2fb
	 otherwise the `data_read' flag would be set.  */
Packit Service 97d2fb
      if (scn->data_read == 0 && __libelf_set_rawdata_wrlock (scn) != 0)
Packit Service 97d2fb
	/* Something went wrong.  The error value is already set.  */
Packit Service 97d2fb
	goto out;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  /* At this point we know the raw data is available.  But it might be
Packit Service 97d2fb
     empty in case the section has size zero (for whatever reason).
Packit Service 97d2fb
     Now create the converted data in case this is necessary.  */
Packit Service 97d2fb
  if (scn->data_list_rear == NULL)
Packit Service 97d2fb
    __libelf_set_data_list_rdlock (scn, locked);
Packit Service 97d2fb
Packit Service 97d2fb
  /* Return the first data element in the list.  */
Packit Service 97d2fb
  result = &scn->data_list.data.d;
Packit Service 97d2fb
Packit Service 97d2fb
 out:
Packit Service 97d2fb
  return result;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
Elf_Data *
Packit Service 97d2fb
elf_getdata (Elf_Scn *scn, Elf_Data *data)
Packit Service 97d2fb
{
Packit Service 97d2fb
  Elf_Data *result;
Packit Service 97d2fb
Packit Service 97d2fb
  if (scn == NULL)
Packit Service 97d2fb
    return NULL;
Packit Service 97d2fb
Packit Service 97d2fb
  rwlock_rdlock (scn->elf->lock);
Packit Service 97d2fb
  result = __elf_getdata_rdlock (scn, data);
Packit Service 97d2fb
  rwlock_unlock (scn->elf->lock);
Packit Service 97d2fb
Packit Service 97d2fb
  return result;
Packit Service 97d2fb
}
Packit Service 97d2fb
INTDEF(elf_getdata)