Blame libdwelf/dwelf_elf_gnu_build_id.c

Packit 032894
/* Returns the build id if found in a NT_GNU_BUILD_ID note.
Packit 032894
   Copyright (C) 2014 Red Hat, Inc.
Packit 032894
   This file is part of elfutils.
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 "libdwelfP.h"
Packit 032894
#include "libdwflP.h"
Packit 032894
Packit 032894
#define NO_VADDR	((GElf_Addr) -1l)
Packit 032894
Packit 032894
static int
Packit 032894
check_notes (Elf_Data *data, GElf_Addr data_elfaddr,
Packit 032894
             const void **build_id_bits, GElf_Addr *build_id_elfaddr,
Packit 032894
             int *build_id_len)
Packit 032894
{
Packit 032894
  size_t pos = 0;
Packit 032894
  GElf_Nhdr nhdr;
Packit 032894
  size_t name_pos;
Packit 032894
  size_t desc_pos;
Packit 032894
  while ((pos = gelf_getnote (data, pos, &nhdr, &name_pos, &desc_pos)) > 0)
Packit 032894
    if (nhdr.n_type == NT_GNU_BUILD_ID
Packit 032894
	&& nhdr.n_namesz == sizeof "GNU"
Packit 032894
	&& !memcmp (data->d_buf + name_pos, "GNU", sizeof "GNU"))
Packit 032894
	{
Packit 032894
	  *build_id_bits = data->d_buf + desc_pos;
Packit 032894
	  *build_id_elfaddr = (data_elfaddr == NO_VADDR
Packit 032894
	                      ? 0 : data_elfaddr + desc_pos);
Packit 032894
	  *build_id_len = nhdr.n_descsz;
Packit 032894
	  return 1;
Packit 032894
	}
Packit 032894
  return 0;
Packit 032894
}
Packit 032894
Packit 032894
/* Defined here for reuse. The dwelf interface doesn't care about the
Packit 032894
   address of the note, but libdwfl does.  */
Packit 032894
static int
Packit 032894
find_elf_build_id (Dwfl_Module *mod, int e_type, Elf *elf,
Packit 032894
		   const void **build_id_bits, GElf_Addr *build_id_elfaddr,
Packit 032894
		   int *build_id_len)
Packit 032894
{
Packit 032894
  size_t shstrndx = SHN_UNDEF;
Packit 032894
  int result = 0;
Packit 032894
Packit 032894
  Elf_Scn *scn = elf_nextscn (elf, NULL);
Packit 032894
Packit 032894
  if (scn == NULL)
Packit 032894
    {
Packit 032894
      /* No sections, have to look for phdrs.  */
Packit 032894
      size_t phnum;
Packit 032894
      if (unlikely (elf_getphdrnum (elf, &phnum) != 0))
Packit 032894
	{
Packit 032894
	  if (mod != NULL)
Packit 032894
	    __libdwfl_seterrno (DWFL_E_LIBELF);
Packit 032894
	  return -1;
Packit 032894
	}
Packit 032894
      for (size_t i = 0; result == 0 && i < phnum; ++i)
Packit 032894
	{
Packit 032894
	  GElf_Phdr phdr_mem;
Packit 032894
	  GElf_Phdr *phdr = gelf_getphdr (elf, i, &phdr_mem);
Packit 032894
	  if (likely (phdr != NULL) && phdr->p_type == PT_NOTE)
Packit 032894
	    result = check_notes (elf_getdata_rawchunk (elf,
Packit 032894
							phdr->p_offset,
Packit 032894
							phdr->p_filesz,
Packit 032894
							(phdr->p_align == 8
Packit 032894
							 ? ELF_T_NHDR8
Packit 032894
							 : ELF_T_NHDR)),
Packit 032894
				  phdr->p_vaddr,
Packit 032894
				  build_id_bits,
Packit 032894
				  build_id_elfaddr,
Packit 032894
				  build_id_len);
Packit 032894
	}
Packit 032894
    }
Packit 032894
  else
Packit 032894
    do
Packit 032894
      {
Packit 032894
	GElf_Shdr shdr_mem;
Packit 032894
	GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
Packit 032894
	if (likely (shdr != NULL) && shdr->sh_type == SHT_NOTE)
Packit 032894
	  {
Packit 032894
	    /* Determine the right sh_addr in this module.  */
Packit 032894
	    GElf_Addr vaddr = 0;
Packit 032894
	    if (!(shdr->sh_flags & SHF_ALLOC))
Packit 032894
	      vaddr = NO_VADDR;
Packit 032894
	    else if (mod == NULL || e_type != ET_REL)
Packit 032894
	      vaddr = shdr->sh_addr;
Packit 032894
	    else if (__libdwfl_relocate_value (mod, elf, &shstrndx,
Packit 032894
					       elf_ndxscn (scn), &vaddr))
Packit 032894
	      vaddr = NO_VADDR;
Packit 032894
	    result = check_notes (elf_getdata (scn, NULL), vaddr,
Packit 032894
	                          build_id_bits,
Packit 032894
	                          build_id_elfaddr,
Packit 032894
	                          build_id_len);
Packit 032894
	  }
Packit 032894
      }
Packit 032894
    while (result == 0 && (scn = elf_nextscn (elf, scn)) != NULL);
Packit 032894
Packit 032894
  return result;
Packit 032894
}
Packit 032894
Packit 032894
int
Packit 032894
internal_function
Packit 032894
__libdwfl_find_elf_build_id (Dwfl_Module *mod, Elf *elf,
Packit 032894
			     const void **build_id_bits,
Packit 032894
			     GElf_Addr *build_id_elfaddr, int *build_id_len)
Packit 032894
{
Packit 032894
  GElf_Ehdr ehdr_mem, *ehdr = gelf_getehdr (elf, &ehdr_mem);
Packit 032894
  if (unlikely (ehdr == NULL))
Packit 032894
    {
Packit 032894
      __libdwfl_seterrno (DWFL_E_LIBELF);
Packit 032894
      return -1;
Packit 032894
    }
Packit 032894
  // MOD->E_TYPE is zero here.
Packit 032894
  assert (ehdr->e_type != ET_REL || mod != NULL);
Packit 032894
Packit 032894
  return find_elf_build_id (mod, ehdr->e_type, elf,
Packit 032894
			    build_id_bits, build_id_elfaddr, build_id_len);
Packit 032894
}
Packit 032894
Packit 032894
ssize_t
Packit 032894
dwelf_elf_gnu_build_id (Elf *elf, const void **build_idp)
Packit 032894
{
Packit 032894
  GElf_Addr build_id_elfaddr;
Packit 032894
  int build_id_len;
Packit 032894
  int result = find_elf_build_id (NULL, ET_NONE, elf, build_idp,
Packit 032894
				  &build_id_elfaddr, &build_id_len);
Packit 032894
  if (result > 0)
Packit 032894
    return build_id_len;
Packit 032894
Packit 032894
  return result;
Packit 032894
}
Packit 032894
INTDEF(dwelf_elf_gnu_build_id)