mirror of
https://github.com/openharmony/third_party_elfutils.git
synced 2026-07-01 06:41:51 -04:00
5199e15870
GNU Property notes are different from normal notes because they use variable alignment/padding of their fields. They are 8 byte aligned, but use 4 byte fields. The name is aligned at 4 bytes and padded so that, the desc is aligned at 8 bytes. The whole note is padded to 8 bytes again. For normal notes all fields are both 4 bytes wide and 4 bytes aligned. To recognize these new kind of ELF Notes a new Elf_Type is introduced, ELF_T_NHDR8. This type is used in the xlate functions to determine how to align and pad the various fields. Since the fields themselves can now have different alignments we will have to keep track of the current alignement and use either NOTE_ALIGN4 or NOTE_ALIGN8 to determine the padding. To set the correct Elf_Type on the Elf_Data we use either the section sh_addralign or the segment p_align values. Assuming 8 means the section or segment contains the new style notes, otherwise normal notes. When we cannot determine the "alignment" directly, like when parsing special kernel sys files, we check the name "GNU" and type "GNU_PROPERTY_TYPE_0" fields. ebl_object_note now parses the new NT_GNU_PROPERTY_TYPE_0 and can extract the GNU_PROPERTY_STACK_SIZE, GNU_PROPERTY_NO_COPY_ON_PROTECTED and GNU_PROPERTY_X86_FEATURE_1_AND types GNU_PROPERTY_X86_FEATURE_1_IBT and GNU_PROPERTY_X86_FEATURE_1_SHSTK. Tests are added for extracting the note from sections or segments as set by gcc -fcf-protection. Signed-off-by: Mark Wielaard <mark@klomp.org>
159 lines
4.4 KiB
C
159 lines
4.4 KiB
C
/* Returns the build id if found in a NT_GNU_BUILD_ID note.
|
|
Copyright (C) 2014 Red Hat, Inc.
|
|
This file is part of elfutils.
|
|
|
|
This file is free software; you can redistribute it and/or modify
|
|
it under the terms of either
|
|
|
|
* the GNU Lesser General Public License as published by the Free
|
|
Software Foundation; either version 3 of the License, or (at
|
|
your option) any later version
|
|
|
|
or
|
|
|
|
* the GNU General Public License as published by the Free
|
|
Software Foundation; either version 2 of the License, or (at
|
|
your option) any later version
|
|
|
|
or both in parallel, as here.
|
|
|
|
elfutils is distributed in the hope that it will be useful, but
|
|
WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
General Public License for more details.
|
|
|
|
You should have received copies of the GNU General Public License and
|
|
the GNU Lesser General Public License along with this program. If
|
|
not, see <http://www.gnu.org/licenses/>. */
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
# include <config.h>
|
|
#endif
|
|
|
|
#include "libdwelfP.h"
|
|
#include "libdwflP.h"
|
|
|
|
#define NO_VADDR ((GElf_Addr) -1l)
|
|
|
|
static int
|
|
check_notes (Elf_Data *data, GElf_Addr data_elfaddr,
|
|
const void **build_id_bits, GElf_Addr *build_id_elfaddr,
|
|
int *build_id_len)
|
|
{
|
|
size_t pos = 0;
|
|
GElf_Nhdr nhdr;
|
|
size_t name_pos;
|
|
size_t desc_pos;
|
|
while ((pos = gelf_getnote (data, pos, &nhdr, &name_pos, &desc_pos)) > 0)
|
|
if (nhdr.n_type == NT_GNU_BUILD_ID
|
|
&& nhdr.n_namesz == sizeof "GNU"
|
|
&& !memcmp (data->d_buf + name_pos, "GNU", sizeof "GNU"))
|
|
{
|
|
*build_id_bits = data->d_buf + desc_pos;
|
|
*build_id_elfaddr = (data_elfaddr == NO_VADDR
|
|
? 0 : data_elfaddr + desc_pos);
|
|
*build_id_len = nhdr.n_descsz;
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* Defined here for reuse. The dwelf interface doesn't care about the
|
|
address of the note, but libdwfl does. */
|
|
static int
|
|
find_elf_build_id (Dwfl_Module *mod, int e_type, Elf *elf,
|
|
const void **build_id_bits, GElf_Addr *build_id_elfaddr,
|
|
int *build_id_len)
|
|
{
|
|
size_t shstrndx = SHN_UNDEF;
|
|
int result = 0;
|
|
|
|
Elf_Scn *scn = elf_nextscn (elf, NULL);
|
|
|
|
if (scn == NULL)
|
|
{
|
|
/* No sections, have to look for phdrs. */
|
|
size_t phnum;
|
|
if (unlikely (elf_getphdrnum (elf, &phnum) != 0))
|
|
{
|
|
if (mod != NULL)
|
|
__libdwfl_seterrno (DWFL_E_LIBELF);
|
|
return -1;
|
|
}
|
|
for (size_t i = 0; result == 0 && i < phnum; ++i)
|
|
{
|
|
GElf_Phdr phdr_mem;
|
|
GElf_Phdr *phdr = gelf_getphdr (elf, i, &phdr_mem);
|
|
if (likely (phdr != NULL) && phdr->p_type == PT_NOTE)
|
|
result = check_notes (elf_getdata_rawchunk (elf,
|
|
phdr->p_offset,
|
|
phdr->p_filesz,
|
|
(phdr->p_align == 8
|
|
? ELF_T_NHDR8
|
|
: ELF_T_NHDR)),
|
|
phdr->p_vaddr,
|
|
build_id_bits,
|
|
build_id_elfaddr,
|
|
build_id_len);
|
|
}
|
|
}
|
|
else
|
|
do
|
|
{
|
|
GElf_Shdr shdr_mem;
|
|
GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
|
|
if (likely (shdr != NULL) && shdr->sh_type == SHT_NOTE)
|
|
{
|
|
/* Determine the right sh_addr in this module. */
|
|
GElf_Addr vaddr = 0;
|
|
if (!(shdr->sh_flags & SHF_ALLOC))
|
|
vaddr = NO_VADDR;
|
|
else if (mod == NULL || e_type != ET_REL)
|
|
vaddr = shdr->sh_addr;
|
|
else if (__libdwfl_relocate_value (mod, elf, &shstrndx,
|
|
elf_ndxscn (scn), &vaddr))
|
|
vaddr = NO_VADDR;
|
|
result = check_notes (elf_getdata (scn, NULL), vaddr,
|
|
build_id_bits,
|
|
build_id_elfaddr,
|
|
build_id_len);
|
|
}
|
|
}
|
|
while (result == 0 && (scn = elf_nextscn (elf, scn)) != NULL);
|
|
|
|
return result;
|
|
}
|
|
|
|
int
|
|
internal_function
|
|
__libdwfl_find_elf_build_id (Dwfl_Module *mod, Elf *elf,
|
|
const void **build_id_bits,
|
|
GElf_Addr *build_id_elfaddr, int *build_id_len)
|
|
{
|
|
GElf_Ehdr ehdr_mem, *ehdr = gelf_getehdr (elf, &ehdr_mem);
|
|
if (unlikely (ehdr == NULL))
|
|
{
|
|
__libdwfl_seterrno (DWFL_E_LIBELF);
|
|
return -1;
|
|
}
|
|
// MOD->E_TYPE is zero here.
|
|
assert (ehdr->e_type != ET_REL || mod != NULL);
|
|
|
|
return find_elf_build_id (mod, ehdr->e_type, elf,
|
|
build_id_bits, build_id_elfaddr, build_id_len);
|
|
}
|
|
|
|
ssize_t
|
|
dwelf_elf_gnu_build_id (Elf *elf, const void **build_idp)
|
|
{
|
|
GElf_Addr build_id_elfaddr;
|
|
int build_id_len;
|
|
int result = find_elf_build_id (NULL, ET_NONE, elf, build_idp,
|
|
&build_id_elfaddr, &build_id_len);
|
|
if (result > 0)
|
|
return build_id_len;
|
|
|
|
return result;
|
|
}
|
|
INTDEF(dwelf_elf_gnu_build_id)
|