|
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)
|