Blame libdwfl/dwfl_module_getdwarf.c

Packit Service 97d2fb
/* Find debugging and symbol information for a module in libdwfl.
Packit Service 97d2fb
   Copyright (C) 2005-2012, 2014, 2015 Red Hat, Inc.
Packit Service 97d2fb
   This file is part of elfutils.
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 "libdwflP.h"
Packit Service 97d2fb
#include <inttypes.h>
Packit Service 97d2fb
#include <fcntl.h>
Packit Service 97d2fb
#include <string.h>
Packit Service 97d2fb
#include <unistd.h>
Packit Service 97d2fb
#include "../libdw/libdwP.h"	/* DWARF_E_* values are here.  */
Packit Service 97d2fb
#include "../libelf/libelfP.h"
Packit Service 97d2fb
#include "system.h"
Packit Service 97d2fb
Packit Service 97d2fb
static inline Dwfl_Error
Packit Service 97d2fb
open_elf_file (Elf **elf, int *fd, char **name)
Packit Service 97d2fb
{
Packit Service 97d2fb
  if (*elf == NULL)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      /* CBFAIL uses errno if it's set, so clear it first in case we don't
Packit Service 97d2fb
	 set it with an open failure below.  */
Packit Service 97d2fb
      errno = 0;
Packit Service 97d2fb
Packit Service 97d2fb
      /* If there was a pre-primed file name left that the callback left
Packit Service 97d2fb
	 behind, try to open that file name.  */
Packit Service 97d2fb
      if (*fd < 0 && *name != NULL)
Packit Service 97d2fb
	*fd = TEMP_FAILURE_RETRY (open (*name, O_RDONLY));
Packit Service 97d2fb
Packit Service 97d2fb
      if (*fd < 0)
Packit Service 97d2fb
	return CBFAIL;
Packit Service 97d2fb
Packit Service 97d2fb
      return __libdw_open_file (fd, elf, true, false);
Packit Service 97d2fb
    }
Packit Service 97d2fb
  else if (unlikely (elf_kind (*elf) != ELF_K_ELF))
Packit Service 97d2fb
    {
Packit Service 97d2fb
      elf_end (*elf);
Packit Service 97d2fb
      *elf = NULL;
Packit Service 97d2fb
      close (*fd);
Packit Service 97d2fb
      *fd = -1;
Packit Service 97d2fb
      return DWFL_E_BADELF;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  /* Elf file already open and looks fine.  */
Packit Service 97d2fb
  return DWFL_E_NOERROR;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
/* Open libelf FILE->fd and compute the load base of ELF as loaded in MOD.
Packit Service 97d2fb
   When we return success, FILE->elf and FILE->vaddr are set up.  */
Packit Service 97d2fb
static inline Dwfl_Error
Packit Service 97d2fb
open_elf (Dwfl_Module *mod, struct dwfl_file *file)
Packit Service 97d2fb
{
Packit Service 97d2fb
  Dwfl_Error error = open_elf_file (&file->elf, &file->fd, &file->name);
Packit Service 97d2fb
  if (error != DWFL_E_NOERROR)
Packit Service 97d2fb
    return error;
Packit Service 97d2fb
Packit Service 97d2fb
  GElf_Ehdr ehdr_mem, *ehdr = gelf_getehdr (file->elf, &ehdr_mem);
Packit Service 97d2fb
  if (ehdr == NULL)
Packit Service 97d2fb
    {
Packit Service 97d2fb
    elf_error:
Packit Service 97d2fb
      elf_end (file->elf);
Packit Service 97d2fb
      file->elf = NULL;
Packit Service 97d2fb
      close (file->fd);
Packit Service 97d2fb
      file->fd = -1;
Packit Service 97d2fb
      return DWFL_E (LIBELF, elf_errno ());
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  if (ehdr->e_type != ET_REL)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      /* In any non-ET_REL file, we compute the "synchronization address".
Packit Service 97d2fb
Packit Service 97d2fb
	 We start with the address at the end of the first PT_LOAD
Packit Service 97d2fb
	 segment.  When prelink converts REL to RELA in an ET_DYN
Packit Service 97d2fb
	 file, it expands the space between the beginning of the
Packit Service 97d2fb
	 segment and the actual code/data addresses.  Since that
Packit Service 97d2fb
	 change wasn't made in the debug file, the distance from
Packit Service 97d2fb
	 p_vaddr to an address of interest (in an st_value or DWARF
Packit Service 97d2fb
	 data) now differs between the main and debug files.  The
Packit Service 97d2fb
	 distance from address_sync to an address of interest remains
Packit Service 97d2fb
	 consistent.
Packit Service 97d2fb
Packit Service 97d2fb
	 If there are no section headers at all (full stripping), then
Packit Service 97d2fb
	 the end of the first segment is a valid synchronization address.
Packit Service 97d2fb
	 This cannot happen in a prelinked file, since prelink itself
Packit Service 97d2fb
	 relies on section headers for prelinking and for undoing it.
Packit Service 97d2fb
	 (If you do full stripping on a prelinked file, then you get what
Packit Service 97d2fb
	 you deserve--you can neither undo the prelinking, nor expect to
Packit Service 97d2fb
	 line it up with a debug file separated before prelinking.)
Packit Service 97d2fb
Packit Service 97d2fb
	 However, when prelink processes an ET_EXEC file, it can do
Packit Service 97d2fb
	 something different.  There it juggles the "special" sections
Packit Service 97d2fb
	 (SHT_DYNSYM et al) to make space for the additional prelink
Packit Service 97d2fb
	 special sections.  Sometimes it will do this by moving a special
Packit Service 97d2fb
	 section like .dynstr after the real program sections in the first
Packit Service 97d2fb
	 PT_LOAD segment--i.e. to the end.  That changes the end address of
Packit Service 97d2fb
	 the segment, so it no longer lines up correctly and is not a valid
Packit Service 97d2fb
	 synchronization address to use.  Because of this, we need to apply
Packit Service 97d2fb
	 a different prelink-savvy means to discover the synchronization
Packit Service 97d2fb
	 address when there is a separate debug file and a prelinked main
Packit Service 97d2fb
	 file.  That is done in find_debuginfo, below.  */
Packit Service 97d2fb
Packit Service 97d2fb
      size_t phnum;
Packit Service 97d2fb
      if (unlikely (elf_getphdrnum (file->elf, &phnum) != 0))
Packit Service 97d2fb
	goto elf_error;
Packit Service 97d2fb
Packit Service 97d2fb
      file->vaddr = file->address_sync = 0;
Packit Service 97d2fb
      for (size_t i = 0; i < phnum; ++i)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  GElf_Phdr ph_mem;
Packit Service 97d2fb
	  GElf_Phdr *ph = gelf_getphdr (file->elf, i, &ph_mem);
Packit Service 97d2fb
	  if (unlikely (ph == NULL))
Packit Service 97d2fb
	    goto elf_error;
Packit Service 97d2fb
	  if (ph->p_type == PT_LOAD)
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      file->vaddr = ph->p_vaddr & -ph->p_align;
Packit Service 97d2fb
	      file->address_sync = ph->p_vaddr + ph->p_memsz;
Packit Service 97d2fb
	      break;
Packit Service 97d2fb
	    }
Packit Service 97d2fb
	}
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  /* We only want to set the module e_type explictly once, derived from
Packit Service 97d2fb
     the main ELF file.  (It might be changed for the kernel, because
Packit Service 97d2fb
     that is special - see below.)  open_elf is always called first for
Packit Service 97d2fb
     the main ELF file, because both find_dw and find_symtab call
Packit Service 97d2fb
     __libdwfl_getelf first to open the main file.  So don't let debug
Packit Service 97d2fb
     or aux files override the module e_type.  The kernel heuristic
Packit Service 97d2fb
     below could otherwise trigger for non-kernel/non-main files, since
Packit Service 97d2fb
     their phdrs might not match the actual load addresses.  */
Packit Service 97d2fb
  if (file == &mod->main)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      mod->e_type = ehdr->e_type;
Packit Service 97d2fb
Packit Service 97d2fb
      /* Relocatable Linux kernels are ET_EXEC but act like ET_DYN.  */
Packit Service 97d2fb
      if (mod->e_type == ET_EXEC && file->vaddr != mod->low_addr)
Packit Service 97d2fb
	mod->e_type = ET_DYN;
Packit Service 97d2fb
    }
Packit Service 97d2fb
  else
Packit Service 97d2fb
    assert (mod->main.elf != NULL);
Packit Service 97d2fb
Packit Service 97d2fb
  return DWFL_E_NOERROR;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
/* We have an authoritative build ID for this module MOD, so don't use
Packit Service 97d2fb
   a file by name that doesn't match that ID.  */
Packit Service 97d2fb
static void
Packit Service 97d2fb
mod_verify_build_id (Dwfl_Module *mod)
Packit Service 97d2fb
{
Packit Service 97d2fb
  assert (mod->build_id_len > 0);
Packit Service 97d2fb
Packit Service 97d2fb
  switch (__builtin_expect (__libdwfl_find_build_id (mod, false,
Packit Service 97d2fb
						     mod->main.elf), 2))
Packit Service 97d2fb
    {
Packit Service 97d2fb
    case 2:
Packit Service 97d2fb
      /* Build ID matches as it should. */
Packit Service 97d2fb
      return;
Packit Service 97d2fb
Packit Service 97d2fb
    case -1:			/* ELF error.  */
Packit Service 97d2fb
      mod->elferr = INTUSE(dwfl_errno) ();
Packit Service 97d2fb
      break;
Packit Service 97d2fb
Packit Service 97d2fb
    case 0:			/* File has no build ID note.  */
Packit Service 97d2fb
    case 1:			/* FIle has a build ID that does not match.  */
Packit Service 97d2fb
      mod->elferr = DWFL_E_WRONG_ID_ELF;
Packit Service 97d2fb
      break;
Packit Service 97d2fb
Packit Service 97d2fb
    default:
Packit Service 97d2fb
      abort ();
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  /* We get here when it was the right ELF file.  Clear it out.  */
Packit Service 97d2fb
  elf_end (mod->main.elf);
Packit Service 97d2fb
  mod->main.elf = NULL;
Packit Service 97d2fb
  if (mod->main.fd >= 0)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      close (mod->main.fd);
Packit Service 97d2fb
      mod->main.fd = -1;
Packit Service 97d2fb
    }
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
/* Find the main ELF file for this module and open libelf on it.
Packit Service 97d2fb
   When we return success, MOD->main.elf and MOD->main.bias are set up.  */
Packit Service 97d2fb
void
Packit Service 97d2fb
internal_function
Packit Service 97d2fb
__libdwfl_getelf (Dwfl_Module *mod)
Packit Service 97d2fb
{
Packit Service 97d2fb
  if (mod->main.elf != NULL	/* Already done.  */
Packit Service 97d2fb
      || mod->elferr != DWFL_E_NOERROR)	/* Cached failure.  */
Packit Service 97d2fb
    return;
Packit Service 97d2fb
Packit Service 97d2fb
  mod->main.fd = (*mod->dwfl->callbacks->find_elf) (MODCB_ARGS (mod),
Packit Service 97d2fb
						    &mod->main.name,
Packit Service 97d2fb
						    &mod->main.elf);
Packit Service 97d2fb
  const bool fallback = mod->main.elf == NULL && mod->main.fd < 0;
Packit Service 97d2fb
  mod->elferr = open_elf (mod, &mod->main);
Packit Service 97d2fb
  if (mod->elferr != DWFL_E_NOERROR)
Packit Service 97d2fb
    return;
Packit Service 97d2fb
Packit Service 97d2fb
  if (!mod->main.valid)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      /* Clear any explicitly reported build ID, just in case it was wrong.
Packit Service 97d2fb
	 We'll fetch it from the file when asked.  */
Packit Service 97d2fb
      free (mod->build_id_bits);
Packit Service 97d2fb
      mod->build_id_bits = NULL;
Packit Service 97d2fb
      mod->build_id_len = 0;
Packit Service 97d2fb
    }
Packit Service 97d2fb
  else if (fallback)
Packit Service 97d2fb
    mod_verify_build_id (mod);
Packit Service 97d2fb
Packit Service 97d2fb
  mod->main_bias = mod->e_type == ET_REL ? 0 : mod->low_addr - mod->main.vaddr;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
static inline void
Packit Service 97d2fb
consider_shdr (GElf_Addr interp,
Packit Service 97d2fb
               GElf_Word sh_type,
Packit Service 97d2fb
               GElf_Xword sh_flags,
Packit Service 97d2fb
               GElf_Addr sh_addr,
Packit Service 97d2fb
               GElf_Xword sh_size,
Packit Service 97d2fb
               GElf_Addr *phighest)
Packit Service 97d2fb
{
Packit Service 97d2fb
  if ((sh_flags & SHF_ALLOC)
Packit Service 97d2fb
      && ((sh_type == SHT_PROGBITS && sh_addr != interp)
Packit Service 97d2fb
          || sh_type == SHT_NOBITS))
Packit Service 97d2fb
    {
Packit Service 97d2fb
      const GElf_Addr sh_end = sh_addr + sh_size;
Packit Service 97d2fb
      if (sh_end > *phighest)
Packit Service 97d2fb
        *phighest = sh_end;
Packit Service 97d2fb
    }
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
/* If the main file might have been prelinked, then we need to
Packit Service 97d2fb
   discover the correct synchronization address between the main and
Packit Service 97d2fb
   debug files.  Because of prelink's section juggling, we cannot rely
Packit Service 97d2fb
   on the address_sync computed from PT_LOAD segments (see open_elf).
Packit Service 97d2fb
Packit Service 97d2fb
   We will attempt to discover a synchronization address based on the
Packit Service 97d2fb
   section headers instead.  But finding a section address that is
Packit Service 97d2fb
   safe to use requires identifying which sections are SHT_PROGBITS.
Packit Service 97d2fb
   We can do that in the main file, but in the debug file all the
Packit Service 97d2fb
   allocated sections have been transformed into SHT_NOBITS so we have
Packit Service 97d2fb
   lost the means to match them up correctly.
Packit Service 97d2fb
Packit Service 97d2fb
   The only method left to us is to decode the .gnu.prelink_undo
Packit Service 97d2fb
   section in the prelinked main file.  This shows what the sections
Packit Service 97d2fb
   looked like before prelink juggled them--when they still had a
Packit Service 97d2fb
   direct correspondence to the debug file.  */
Packit Service 97d2fb
static Dwfl_Error
Packit Service 97d2fb
find_prelink_address_sync (Dwfl_Module *mod, struct dwfl_file *file)
Packit Service 97d2fb
{
Packit Service 97d2fb
  /* The magic section is only identified by name.  */
Packit Service 97d2fb
  size_t shstrndx;
Packit Service 97d2fb
  if (elf_getshdrstrndx (mod->main.elf, &shstrndx) < 0)
Packit Service 97d2fb
    return DWFL_E_LIBELF;
Packit Service 97d2fb
Packit Service 97d2fb
  Elf_Scn *scn = NULL;
Packit Service 97d2fb
  while ((scn = elf_nextscn (mod->main.elf, scn)) != NULL)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      GElf_Shdr shdr_mem;
Packit Service 97d2fb
      GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
Packit Service 97d2fb
      if (unlikely (shdr == NULL))
Packit Service 97d2fb
	return DWFL_E_LIBELF;
Packit Service 97d2fb
      if (shdr->sh_type == SHT_PROGBITS
Packit Service 97d2fb
	  && !(shdr->sh_flags & SHF_ALLOC)
Packit Service 97d2fb
	  && shdr->sh_name != 0)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  const char *secname = elf_strptr (mod->main.elf, shstrndx,
Packit Service 97d2fb
					    shdr->sh_name);
Packit Service 97d2fb
	  if (unlikely (secname == NULL))
Packit Service 97d2fb
	    return DWFL_E_LIBELF;
Packit Service 97d2fb
	  if (!strcmp (secname, ".gnu.prelink_undo"))
Packit Service 97d2fb
	    break;
Packit Service 97d2fb
	}
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  if (scn == NULL)
Packit Service 97d2fb
    /* There was no .gnu.prelink_undo section.  */
Packit Service 97d2fb
    return DWFL_E_NOERROR;
Packit Service 97d2fb
Packit Service 97d2fb
  Elf_Data *undodata = elf_rawdata (scn, NULL);
Packit Service 97d2fb
  if (unlikely (undodata == NULL))
Packit Service 97d2fb
    return DWFL_E_LIBELF;
Packit Service 97d2fb
Packit Service 97d2fb
  /* Decode the section.  It consists of the original ehdr, phdrs,
Packit Service 97d2fb
     and shdrs (but omits section 0).  */
Packit Service 97d2fb
Packit Service 97d2fb
  union
Packit Service 97d2fb
  {
Packit Service 97d2fb
    Elf32_Ehdr e32;
Packit Service 97d2fb
    Elf64_Ehdr e64;
Packit Service 97d2fb
  } ehdr;
Packit Service 97d2fb
  Elf_Data dst =
Packit Service 97d2fb
    {
Packit Service 97d2fb
      .d_buf = &ehdr,
Packit Service 97d2fb
      .d_size = sizeof ehdr,
Packit Service 97d2fb
      .d_type = ELF_T_EHDR,
Packit Service 97d2fb
      .d_version = EV_CURRENT
Packit Service 97d2fb
    };
Packit Service 97d2fb
  Elf_Data src = *undodata;
Packit Service 97d2fb
  src.d_size = gelf_fsize (mod->main.elf, ELF_T_EHDR, 1, EV_CURRENT);
Packit Service 97d2fb
  src.d_type = ELF_T_EHDR;
Packit Service 97d2fb
  if (unlikely (gelf_xlatetom (mod->main.elf, &dst, &src,
Packit Service 97d2fb
			       elf_getident (mod->main.elf, NULL)[EI_DATA])
Packit Service 97d2fb
		== NULL))
Packit Service 97d2fb
    return DWFL_E_LIBELF;
Packit Service 97d2fb
Packit Service 97d2fb
  size_t shentsize = gelf_fsize (mod->main.elf, ELF_T_SHDR, 1, EV_CURRENT);
Packit Service 97d2fb
  size_t phentsize = gelf_fsize (mod->main.elf, ELF_T_PHDR, 1, EV_CURRENT);
Packit Service 97d2fb
Packit Service 97d2fb
  uint_fast16_t phnum;
Packit Service 97d2fb
  uint_fast16_t shnum;
Packit Service 97d2fb
  if (ehdr.e32.e_ident[EI_CLASS] == ELFCLASS32)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      if (ehdr.e32.e_shentsize != shentsize
Packit Service 97d2fb
	  || ehdr.e32.e_phentsize != phentsize)
Packit Service 97d2fb
	return DWFL_E_BAD_PRELINK;
Packit Service 97d2fb
      phnum = ehdr.e32.e_phnum;
Packit Service 97d2fb
      shnum = ehdr.e32.e_shnum;
Packit Service 97d2fb
    }
Packit Service 97d2fb
  else
Packit Service 97d2fb
    {
Packit Service 97d2fb
      if (ehdr.e64.e_shentsize != shentsize
Packit Service 97d2fb
	  || ehdr.e64.e_phentsize != phentsize)
Packit Service 97d2fb
	return DWFL_E_BAD_PRELINK;
Packit Service 97d2fb
      phnum = ehdr.e64.e_phnum;
Packit Service 97d2fb
      shnum = ehdr.e64.e_shnum;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  /* Since prelink does not store the zeroth section header in the undo
Packit Service 97d2fb
     section, it cannot support SHN_XINDEX encoding.  */
Packit Service 97d2fb
  if (unlikely (shnum >= SHN_LORESERVE) || unlikely(shnum == 0)
Packit Service 97d2fb
      || unlikely (undodata->d_size != (src.d_size
Packit Service 97d2fb
					+ phnum * phentsize
Packit Service 97d2fb
					+ (shnum - 1) * shentsize)))
Packit Service 97d2fb
    return DWFL_E_BAD_PRELINK;
Packit Service 97d2fb
Packit Service 97d2fb
  --shnum;
Packit Service 97d2fb
Packit Service 97d2fb
  /* We look at the allocated SHT_PROGBITS (or SHT_NOBITS) sections.  (Most
Packit Service 97d2fb
     every file will have some SHT_PROGBITS sections, but it's possible to
Packit Service 97d2fb
     have one with nothing but .bss, i.e. SHT_NOBITS.)  The special sections
Packit Service 97d2fb
     that can be moved around have different sh_type values--except for
Packit Service 97d2fb
     .interp, the section that became the PT_INTERP segment.  So we exclude
Packit Service 97d2fb
     the SHT_PROGBITS section whose address matches the PT_INTERP p_vaddr.
Packit Service 97d2fb
     For this reason, we must examine the phdrs first to find PT_INTERP.  */
Packit Service 97d2fb
Packit Service 97d2fb
  GElf_Addr main_interp = 0;
Packit Service 97d2fb
  {
Packit Service 97d2fb
    size_t main_phnum;
Packit Service 97d2fb
    if (unlikely (elf_getphdrnum (mod->main.elf, &main_phnum)))
Packit Service 97d2fb
      return DWFL_E_LIBELF;
Packit Service 97d2fb
    for (size_t i = 0; i < main_phnum; ++i)
Packit Service 97d2fb
      {
Packit Service 97d2fb
	GElf_Phdr phdr;
Packit Service 97d2fb
	if (unlikely (gelf_getphdr (mod->main.elf, i, &phdr) == NULL))
Packit Service 97d2fb
	  return DWFL_E_LIBELF;
Packit Service 97d2fb
	if (phdr.p_type == PT_INTERP)
Packit Service 97d2fb
	  {
Packit Service 97d2fb
	    main_interp = phdr.p_vaddr;
Packit Service 97d2fb
	    break;
Packit Service 97d2fb
	  }
Packit Service 97d2fb
      }
Packit Service 97d2fb
  }
Packit Service 97d2fb
Packit Service 97d2fb
  src.d_buf += src.d_size;
Packit Service 97d2fb
  src.d_type = ELF_T_PHDR;
Packit Service 97d2fb
  src.d_size = phnum * phentsize;
Packit Service 97d2fb
Packit Service 97d2fb
  GElf_Addr undo_interp = 0;
Packit Service 97d2fb
  bool class32 = ehdr.e32.e_ident[EI_CLASS] == ELFCLASS32;
Packit Service 97d2fb
  {
Packit Service 97d2fb
    size_t phdr_size = class32 ? sizeof (Elf32_Phdr) : sizeof (Elf64_Phdr);
Packit Service 97d2fb
    if (unlikely (phnum > SIZE_MAX / phdr_size))
Packit Service 97d2fb
      return DWFL_E_NOMEM;
Packit Service 97d2fb
    const size_t phdrs_bytes = phnum * phdr_size;
Packit Service 97d2fb
    void *phdrs = malloc (phdrs_bytes);
Packit Service 97d2fb
    if (unlikely (phdrs == NULL))
Packit Service 97d2fb
      return DWFL_E_NOMEM;
Packit Service 97d2fb
    dst.d_buf = phdrs;
Packit Service 97d2fb
    dst.d_size = phdrs_bytes;
Packit Service 97d2fb
    if (unlikely (gelf_xlatetom (mod->main.elf, &dst, &src,
Packit Service 97d2fb
				 ehdr.e32.e_ident[EI_DATA]) == NULL))
Packit Service 97d2fb
      {
Packit Service 97d2fb
	free (phdrs);
Packit Service 97d2fb
	return DWFL_E_LIBELF;
Packit Service 97d2fb
      }
Packit Service 97d2fb
    if (class32)
Packit Service 97d2fb
      {
Packit Service 97d2fb
	Elf32_Phdr (*p32)[phnum] = phdrs;
Packit Service 97d2fb
	for (uint_fast16_t i = 0; i < phnum; ++i)
Packit Service 97d2fb
	  if ((*p32)[i].p_type == PT_INTERP)
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      undo_interp = (*p32)[i].p_vaddr;
Packit Service 97d2fb
	      break;
Packit Service 97d2fb
	    }
Packit Service 97d2fb
      }
Packit Service 97d2fb
    else
Packit Service 97d2fb
      {
Packit Service 97d2fb
	Elf64_Phdr (*p64)[phnum] = phdrs;
Packit Service 97d2fb
	for (uint_fast16_t i = 0; i < phnum; ++i)
Packit Service 97d2fb
	  if ((*p64)[i].p_type == PT_INTERP)
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      undo_interp = (*p64)[i].p_vaddr;
Packit Service 97d2fb
	      break;
Packit Service 97d2fb
	    }
Packit Service 97d2fb
      }
Packit Service 97d2fb
    free (phdrs);
Packit Service 97d2fb
  }
Packit Service 97d2fb
Packit Service 97d2fb
  if (unlikely ((main_interp == 0) != (undo_interp == 0)))
Packit Service 97d2fb
    return DWFL_E_BAD_PRELINK;
Packit Service 97d2fb
Packit Service 97d2fb
  src.d_buf += src.d_size;
Packit Service 97d2fb
  src.d_type = ELF_T_SHDR;
Packit Service 97d2fb
  src.d_size = gelf_fsize (mod->main.elf, ELF_T_SHDR, shnum, EV_CURRENT);
Packit Service 97d2fb
Packit Service 97d2fb
  size_t shdr_size = class32 ? sizeof (Elf32_Shdr) : sizeof (Elf64_Shdr);
Packit Service 97d2fb
  if (unlikely (shnum > SIZE_MAX / shdr_size))
Packit Service 97d2fb
    return DWFL_E_NOMEM;
Packit Service 97d2fb
  const size_t shdrs_bytes = shnum * shdr_size;
Packit Service 97d2fb
  void *shdrs = malloc (shdrs_bytes);
Packit Service 97d2fb
  if (unlikely (shdrs == NULL))
Packit Service 97d2fb
    return DWFL_E_NOMEM;
Packit Service 97d2fb
  dst.d_buf = shdrs;
Packit Service 97d2fb
  dst.d_size = shdrs_bytes;
Packit Service 97d2fb
  if (unlikely (gelf_xlatetom (mod->main.elf, &dst, &src,
Packit Service 97d2fb
			       ehdr.e32.e_ident[EI_DATA]) == NULL))
Packit Service 97d2fb
    {
Packit Service 97d2fb
      free (shdrs);
Packit Service 97d2fb
      return DWFL_E_LIBELF;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  /* Now we can look at the original section headers of the main file
Packit Service 97d2fb
     before it was prelinked.  First we'll apply our method to the main
Packit Service 97d2fb
     file sections as they are after prelinking, to calculate the
Packit Service 97d2fb
     synchronization address of the main file.  Then we'll apply that
Packit Service 97d2fb
     same method to the saved section headers, to calculate the matching
Packit Service 97d2fb
     synchronization address of the debug file.
Packit Service 97d2fb
Packit Service 97d2fb
     The method is to consider SHF_ALLOC sections that are either
Packit Service 97d2fb
     SHT_PROGBITS or SHT_NOBITS, excluding the section whose sh_addr
Packit Service 97d2fb
     matches the PT_INTERP p_vaddr.  The special sections that can be
Packit Service 97d2fb
     moved by prelink have other types, except for .interp (which
Packit Service 97d2fb
     becomes PT_INTERP).  The "real" sections cannot move as such, but
Packit Service 97d2fb
     .bss can be split into .dynbss and .bss, with the total memory
Packit Service 97d2fb
     image remaining the same but being spread across the two sections.
Packit Service 97d2fb
     So we consider the highest section end, which still matches up.  */
Packit Service 97d2fb
Packit Service 97d2fb
  GElf_Addr highest;
Packit Service 97d2fb
Packit Service 97d2fb
  highest = 0;
Packit Service 97d2fb
  scn = NULL;
Packit Service 97d2fb
  while ((scn = elf_nextscn (mod->main.elf, scn)) != NULL)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      GElf_Shdr sh_mem;
Packit Service 97d2fb
      GElf_Shdr *sh = gelf_getshdr (scn, &sh_mem);
Packit Service 97d2fb
      if (unlikely (sh == NULL))
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  free (shdrs);
Packit Service 97d2fb
	  return DWFL_E_LIBELF;
Packit Service 97d2fb
	}
Packit Service 97d2fb
      consider_shdr (main_interp, sh->sh_type, sh->sh_flags,
Packit Service 97d2fb
		     sh->sh_addr, sh->sh_size, &highest);
Packit Service 97d2fb
    }
Packit Service 97d2fb
  if (highest > mod->main.vaddr)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      mod->main.address_sync = highest;
Packit Service 97d2fb
Packit Service 97d2fb
      highest = 0;
Packit Service 97d2fb
      if (class32)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  Elf32_Shdr (*s32)[shnum] = shdrs;
Packit Service 97d2fb
	  for (size_t i = 0; i < shnum; ++i)
Packit Service 97d2fb
	    consider_shdr (undo_interp, (*s32)[i].sh_type,
Packit Service 97d2fb
			   (*s32)[i].sh_flags, (*s32)[i].sh_addr,
Packit Service 97d2fb
			   (*s32)[i].sh_size, &highest);
Packit Service 97d2fb
	}
Packit Service 97d2fb
      else
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  Elf64_Shdr (*s64)[shnum] = shdrs;
Packit Service 97d2fb
	  for (size_t i = 0; i < shnum; ++i)
Packit Service 97d2fb
	    consider_shdr (undo_interp, (*s64)[i].sh_type,
Packit Service 97d2fb
			   (*s64)[i].sh_flags, (*s64)[i].sh_addr,
Packit Service 97d2fb
			   (*s64)[i].sh_size, &highest);
Packit Service 97d2fb
	}
Packit Service 97d2fb
Packit Service 97d2fb
      if (highest > file->vaddr)
Packit Service 97d2fb
	file->address_sync = highest;
Packit Service 97d2fb
      else
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  free (shdrs);
Packit Service 97d2fb
	  return DWFL_E_BAD_PRELINK;
Packit Service 97d2fb
	}
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  free (shdrs);
Packit Service 97d2fb
Packit Service 97d2fb
  return DWFL_E_NOERROR;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
/* Find the separate debuginfo file for this module and open libelf on it.
Packit Service 97d2fb
   When we return success, MOD->debug is set up.  */
Packit Service 97d2fb
static Dwfl_Error
Packit Service 97d2fb
find_debuginfo (Dwfl_Module *mod)
Packit Service 97d2fb
{
Packit Service 97d2fb
  if (mod->debug.elf != NULL)
Packit Service 97d2fb
    return DWFL_E_NOERROR;
Packit Service 97d2fb
Packit Service 97d2fb
  GElf_Word debuglink_crc = 0;
Packit Service 97d2fb
  const char *debuglink_file;
Packit Service 97d2fb
  debuglink_file = INTUSE(dwelf_elf_gnu_debuglink) (mod->main.elf,
Packit Service 97d2fb
						    &debuglink_crc);
Packit Service 97d2fb
Packit Service 97d2fb
  mod->debug.fd = (*mod->dwfl->callbacks->find_debuginfo) (MODCB_ARGS (mod),
Packit Service 97d2fb
							   mod->main.name,
Packit Service 97d2fb
							   debuglink_file,
Packit Service 97d2fb
							   debuglink_crc,
Packit Service 97d2fb
							   &mod->debug.name);
Packit Service 97d2fb
  Dwfl_Error result = open_elf (mod, &mod->debug);
Packit Service 97d2fb
  if (result == DWFL_E_NOERROR && mod->debug.address_sync != 0)
Packit Service 97d2fb
    result = find_prelink_address_sync (mod, &mod->debug);
Packit Service 97d2fb
  return result;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
/* Try to find the alternative debug link for the given DWARF and set
Packit Service 97d2fb
   it if found.  Only called when mod->dw is already setup but still
Packit Service 97d2fb
   might need an alternative (dwz multi) debug file.  filename is either
Packit Service 97d2fb
   the main or debug name from which the Dwarf was created. */
Packit Service 97d2fb
static void
Packit Service 97d2fb
find_debug_altlink (Dwfl_Module *mod, const char *filename)
Packit Service 97d2fb
{
Packit Service 97d2fb
  assert (mod->dw != NULL);
Packit Service 97d2fb
Packit Service 97d2fb
  const char *altname;
Packit Service 97d2fb
  const void *build_id;
Packit Service 97d2fb
  ssize_t build_id_len = INTUSE(dwelf_dwarf_gnu_debugaltlink) (mod->dw,
Packit Service 97d2fb
							       &altname,
Packit Service 97d2fb
							       &build_id);
Packit Service 97d2fb
Packit Service 97d2fb
  if (build_id_len > 0)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      /* We could store altfile in the module, but don't really need it.  */
Packit Service 97d2fb
      char *altfile = NULL;
Packit Service 97d2fb
      mod->alt_fd = (*mod->dwfl->callbacks->find_debuginfo) (MODCB_ARGS (mod),
Packit Service 97d2fb
							     filename,
Packit Service 97d2fb
							     altname,
Packit Service 97d2fb
							     0,
Packit Service 97d2fb
							     &altfile);
Packit Service 97d2fb
Packit Service 97d2fb
      /* The (internal) callbacks might just set mod->alt_elf directly
Packit Service 97d2fb
	 because they open the Elf anyway for sanity checking.
Packit Service 97d2fb
	 Otherwise open either the given file name or use the fd
Packit Service 97d2fb
	 returned.  */
Packit Service 97d2fb
      Dwfl_Error error = open_elf_file (&mod->alt_elf, &mod->alt_fd,
Packit Service 97d2fb
					&altfile);
Packit Service 97d2fb
      if (error == DWFL_E_NOERROR)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  mod->alt = INTUSE(dwarf_begin_elf) (mod->alt_elf,
Packit Service 97d2fb
					      DWARF_C_READ, NULL);
Packit Service 97d2fb
	  if (mod->alt == NULL)
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      elf_end (mod->alt_elf);
Packit Service 97d2fb
	      mod->alt_elf = NULL;
Packit Service 97d2fb
	      close (mod->alt_fd);
Packit Service 97d2fb
	      mod->alt_fd = -1;
Packit Service 97d2fb
	    }
Packit Service 97d2fb
	  else
Packit Service 97d2fb
	    dwarf_setalt (mod->dw, mod->alt);
Packit Service 97d2fb
	}
Packit Service 97d2fb
Packit Service 97d2fb
      free (altfile); /* See above, we don't really need it.  */
Packit Service 97d2fb
    }
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
/* Try to find a symbol table in FILE.
Packit Service 97d2fb
   Returns DWFL_E_NOERROR if a proper one is found.
Packit Service 97d2fb
   Returns DWFL_E_NO_SYMTAB if not, but still sets results for SHT_DYNSYM.  */
Packit Service 97d2fb
static Dwfl_Error
Packit Service 97d2fb
load_symtab (struct dwfl_file *file, struct dwfl_file **symfile,
Packit Service 97d2fb
	     Elf_Scn **symscn, Elf_Scn **xndxscn,
Packit Service 97d2fb
	     size_t *syments, int *first_global, GElf_Word *strshndx)
Packit Service 97d2fb
{
Packit Service 97d2fb
  bool symtab = false;
Packit Service 97d2fb
  Elf_Scn *scn = NULL;
Packit Service 97d2fb
  while ((scn = elf_nextscn (file->elf, scn)) != NULL)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      GElf_Shdr shdr_mem, *shdr = gelf_getshdr (scn, &shdr_mem);
Packit Service 97d2fb
      if (shdr != NULL)
Packit Service 97d2fb
	switch (shdr->sh_type)
Packit Service 97d2fb
	  {
Packit Service 97d2fb
	  case SHT_SYMTAB:
Packit Service 97d2fb
	    if (shdr->sh_entsize == 0)
Packit Service 97d2fb
	      break;
Packit Service 97d2fb
	    symtab = true;
Packit Service 97d2fb
	    *symscn = scn;
Packit Service 97d2fb
	    *symfile = file;
Packit Service 97d2fb
	    *strshndx = shdr->sh_link;
Packit Service 97d2fb
	    *syments = shdr->sh_size / shdr->sh_entsize;
Packit Service 97d2fb
	    *first_global = shdr->sh_info;
Packit Service 97d2fb
	    if (*xndxscn != NULL)
Packit Service 97d2fb
	      return DWFL_E_NOERROR;
Packit Service 97d2fb
	    break;
Packit Service 97d2fb
Packit Service 97d2fb
	  case SHT_DYNSYM:
Packit Service 97d2fb
	    if (symtab)
Packit Service 97d2fb
	      break;
Packit Service 97d2fb
	    /* Use this if need be, but keep looking for SHT_SYMTAB.  */
Packit Service 97d2fb
	    if (shdr->sh_entsize == 0)
Packit Service 97d2fb
	      break;
Packit Service 97d2fb
	    *symscn = scn;
Packit Service 97d2fb
	    *symfile = file;
Packit Service 97d2fb
	    *strshndx = shdr->sh_link;
Packit Service 97d2fb
	    *syments = shdr->sh_size / shdr->sh_entsize;
Packit Service 97d2fb
	    *first_global = shdr->sh_info;
Packit Service 97d2fb
	    break;
Packit Service 97d2fb
Packit Service 97d2fb
	  case SHT_SYMTAB_SHNDX:
Packit Service 97d2fb
	    *xndxscn = scn;
Packit Service 97d2fb
	    if (symtab)
Packit Service 97d2fb
	      return DWFL_E_NOERROR;
Packit Service 97d2fb
	    break;
Packit Service 97d2fb
Packit Service 97d2fb
	  default:
Packit Service 97d2fb
	    break;
Packit Service 97d2fb
	  }
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  if (symtab)
Packit Service 97d2fb
    /* We found one, though no SHT_SYMTAB_SHNDX to go with it.  */
Packit Service 97d2fb
    return DWFL_E_NOERROR;
Packit Service 97d2fb
Packit Service 97d2fb
  /* We found no SHT_SYMTAB, so any SHT_SYMTAB_SHNDX was bogus.
Packit Service 97d2fb
     We might have found an SHT_DYNSYM and set *SYMSCN et al though.  */
Packit Service 97d2fb
  *xndxscn = NULL;
Packit Service 97d2fb
  return DWFL_E_NO_SYMTAB;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
Packit Service 97d2fb
/* Translate addresses into file offsets.
Packit Service 97d2fb
   OFFS[*] start out zero and remain zero if unresolved.  */
Packit Service 97d2fb
static void
Packit Service 97d2fb
find_offsets (Elf *elf, GElf_Addr main_bias, size_t phnum, size_t n,
Packit Service 97d2fb
	      GElf_Addr addrs[n], GElf_Off offs[n])
Packit Service 97d2fb
{
Packit Service 97d2fb
  size_t unsolved = n;
Packit Service 97d2fb
  for (size_t i = 0; i < phnum; ++i)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      GElf_Phdr phdr_mem;
Packit Service 97d2fb
      GElf_Phdr *phdr = gelf_getphdr (elf, i, &phdr_mem);
Packit Service 97d2fb
      if (phdr != NULL && phdr->p_type == PT_LOAD && phdr->p_memsz > 0)
Packit Service 97d2fb
	for (size_t j = 0; j < n; ++j)
Packit Service 97d2fb
	  if (offs[j] == 0
Packit Service 97d2fb
	      && addrs[j] >= phdr->p_vaddr + main_bias
Packit Service 97d2fb
	      && addrs[j] - (phdr->p_vaddr + main_bias) < phdr->p_filesz)
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      offs[j] = addrs[j] - (phdr->p_vaddr + main_bias) + phdr->p_offset;
Packit Service 97d2fb
	      if (--unsolved == 0)
Packit Service 97d2fb
		break;
Packit Service 97d2fb
	    }
Packit Service 97d2fb
    }
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
/* Various addresses we might want to pull from the dynamic segment.  */
Packit Service 97d2fb
enum
Packit Service 97d2fb
{
Packit Service 97d2fb
  i_symtab,
Packit Service 97d2fb
  i_strtab,
Packit Service 97d2fb
  i_hash,
Packit Service 97d2fb
  i_gnu_hash,
Packit Service 97d2fb
  i_max
Packit Service 97d2fb
};
Packit Service 97d2fb
Packit Service 97d2fb
/* Translate pointers into file offsets.  ADJUST is either zero
Packit Service 97d2fb
   in case the dynamic segment wasn't adjusted or mod->main_bias.
Packit Service 97d2fb
   Will set mod->symfile if the translated offsets can be used as
Packit Service 97d2fb
   symbol table.  */
Packit Service 97d2fb
static void
Packit Service 97d2fb
translate_offs (GElf_Addr adjust,
Packit Service 97d2fb
                Dwfl_Module *mod, size_t phnum,
Packit Service 97d2fb
                GElf_Addr addrs[i_max], GElf_Xword strsz,
Packit Service 97d2fb
                GElf_Ehdr *ehdr)
Packit Service 97d2fb
{
Packit Service 97d2fb
  GElf_Off offs[i_max] = { 0, };
Packit Service 97d2fb
  find_offsets (mod->main.elf, adjust, phnum, i_max, addrs, offs);
Packit Service 97d2fb
Packit Service 97d2fb
  /* Figure out the size of the symbol table.  */
Packit Service 97d2fb
  if (offs[i_hash] != 0)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      /* In the original format, .hash says the size of .dynsym.  */
Packit Service 97d2fb
Packit Service 97d2fb
      size_t entsz = SH_ENTSIZE_HASH (ehdr);
Packit Service 97d2fb
      Elf_Data *data = elf_getdata_rawchunk (mod->main.elf,
Packit Service 97d2fb
					     offs[i_hash] + entsz, entsz,
Packit Service 97d2fb
					     (entsz == 4
Packit Service 97d2fb
					      ? ELF_T_WORD : ELF_T_XWORD));
Packit Service 97d2fb
      if (data != NULL)
Packit Service 97d2fb
	mod->syments = (entsz == 4
Packit Service 97d2fb
			? *(const GElf_Word *) data->d_buf
Packit Service 97d2fb
			: *(const GElf_Xword *) data->d_buf);
Packit Service 97d2fb
    }
Packit Service 97d2fb
  if (offs[i_gnu_hash] != 0 && mod->syments == 0)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      /* In the new format, we can derive it with some work.  */
Packit Service 97d2fb
Packit Service 97d2fb
      const struct
Packit Service 97d2fb
      {
Packit Service 97d2fb
        Elf32_Word nbuckets;
Packit Service 97d2fb
        Elf32_Word symndx;
Packit Service 97d2fb
        Elf32_Word maskwords;
Packit Service 97d2fb
        Elf32_Word shift2;
Packit Service 97d2fb
      } *header;
Packit Service 97d2fb
Packit Service 97d2fb
      Elf_Data *data = elf_getdata_rawchunk (mod->main.elf, offs[i_gnu_hash],
Packit Service 97d2fb
					     sizeof *header, ELF_T_WORD);
Packit Service 97d2fb
      if (data != NULL)
Packit Service 97d2fb
        {
Packit Service 97d2fb
          header = data->d_buf;
Packit Service 97d2fb
          Elf32_Word nbuckets = header->nbuckets;
Packit Service 97d2fb
          Elf32_Word symndx = header->symndx;
Packit Service 97d2fb
          GElf_Off buckets_at = (offs[i_gnu_hash] + sizeof *header
Packit Service 97d2fb
				 + (gelf_getclass (mod->main.elf)
Packit Service 97d2fb
				    * sizeof (Elf32_Word)
Packit Service 97d2fb
				    * header->maskwords));
Packit Service 97d2fb
Packit Service 97d2fb
          // elf_getdata_rawchunk takes a size_t, make sure it
Packit Service 97d2fb
          // doesn't overflow.
Packit Service 97d2fb
#if SIZE_MAX <= UINT32_MAX
Packit Service 97d2fb
          if (nbuckets > SIZE_MAX / sizeof (Elf32_Word))
Packit Service 97d2fb
            data = NULL;
Packit Service 97d2fb
          else
Packit Service 97d2fb
#endif
Packit Service 97d2fb
            data = elf_getdata_rawchunk (mod->main.elf, buckets_at,
Packit Service 97d2fb
					   nbuckets * sizeof (Elf32_Word),
Packit Service 97d2fb
					   ELF_T_WORD);
Packit Service 97d2fb
	  if (data != NULL && symndx < nbuckets)
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      const Elf32_Word *const buckets = data->d_buf;
Packit Service 97d2fb
	      Elf32_Word maxndx = symndx;
Packit Service 97d2fb
	      for (Elf32_Word bucket = 0; bucket < nbuckets; ++bucket)
Packit Service 97d2fb
		if (buckets[bucket] > maxndx)
Packit Service 97d2fb
		  maxndx = buckets[bucket];
Packit Service 97d2fb
Packit Service 97d2fb
	      GElf_Off hasharr_at = (buckets_at
Packit Service 97d2fb
				     + nbuckets * sizeof (Elf32_Word));
Packit Service 97d2fb
	      hasharr_at += (maxndx - symndx) * sizeof (Elf32_Word);
Packit Service 97d2fb
	      do
Packit Service 97d2fb
		{
Packit Service 97d2fb
		  data = elf_getdata_rawchunk (mod->main.elf,
Packit Service 97d2fb
					       hasharr_at,
Packit Service 97d2fb
					       sizeof (Elf32_Word),
Packit Service 97d2fb
					       ELF_T_WORD);
Packit Service 97d2fb
		  if (data != NULL
Packit Service 97d2fb
		      && (*(const Elf32_Word *) data->d_buf & 1u))
Packit Service 97d2fb
		    {
Packit Service 97d2fb
		      mod->syments = maxndx + 1;
Packit Service 97d2fb
		      break;
Packit Service 97d2fb
		    }
Packit Service 97d2fb
		  ++maxndx;
Packit Service 97d2fb
		  hasharr_at += sizeof (Elf32_Word);
Packit Service 97d2fb
		}
Packit Service 97d2fb
	      while (data != NULL);
Packit Service 97d2fb
	    }
Packit Service 97d2fb
	}
Packit Service 97d2fb
    }
Packit Service 97d2fb
  if (offs[i_strtab] > offs[i_symtab] && mod->syments == 0)
Packit Service 97d2fb
    mod->syments = ((offs[i_strtab] - offs[i_symtab])
Packit Service 97d2fb
		    / gelf_fsize (mod->main.elf,
Packit Service 97d2fb
				  ELF_T_SYM, 1, EV_CURRENT));
Packit Service 97d2fb
Packit Service 97d2fb
  if (mod->syments > 0)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      mod->symdata = elf_getdata_rawchunk (mod->main.elf,
Packit Service 97d2fb
					   offs[i_symtab],
Packit Service 97d2fb
					   gelf_fsize (mod->main.elf,
Packit Service 97d2fb
						       ELF_T_SYM,
Packit Service 97d2fb
						       mod->syments,
Packit Service 97d2fb
						       EV_CURRENT),
Packit Service 97d2fb
						       ELF_T_SYM);
Packit Service 97d2fb
      if (mod->symdata != NULL)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  mod->symstrdata = elf_getdata_rawchunk (mod->main.elf,
Packit Service 97d2fb
						  offs[i_strtab],
Packit Service 97d2fb
						  strsz,
Packit Service 97d2fb
						  ELF_T_BYTE);
Packit Service 97d2fb
	  if (mod->symstrdata == NULL)
Packit Service 97d2fb
	    mod->symdata = NULL;
Packit Service 97d2fb
	}
Packit Service 97d2fb
      if (mod->symdata == NULL)
Packit Service 97d2fb
	mod->symerr = DWFL_E (LIBELF, elf_errno ());
Packit Service 97d2fb
      else
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  mod->symfile = &mod->main;
Packit Service 97d2fb
	  mod->symerr = DWFL_E_NOERROR;
Packit Service 97d2fb
	}
Packit Service 97d2fb
    }
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
/* Try to find a dynamic symbol table via phdrs.  */
Packit Service 97d2fb
static void
Packit Service 97d2fb
find_dynsym (Dwfl_Module *mod)
Packit Service 97d2fb
{
Packit Service 97d2fb
  GElf_Ehdr ehdr_mem;
Packit Service 97d2fb
  GElf_Ehdr *ehdr = gelf_getehdr (mod->main.elf, &ehdr_mem);
Packit Service 97d2fb
Packit Service 97d2fb
  size_t phnum;
Packit Service 97d2fb
  if (unlikely (elf_getphdrnum (mod->main.elf, &phnum) != 0))
Packit Service 97d2fb
    return;
Packit Service 97d2fb
Packit Service 97d2fb
  for (size_t i = 0; i < phnum; ++i)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      GElf_Phdr phdr_mem;
Packit Service 97d2fb
      GElf_Phdr *phdr = gelf_getphdr (mod->main.elf, i, &phdr_mem);
Packit Service 97d2fb
      if (phdr == NULL)
Packit Service 97d2fb
	break;
Packit Service 97d2fb
Packit Service 97d2fb
      if (phdr->p_type == PT_DYNAMIC)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  /* Examine the dynamic section for the pointers we need.  */
Packit Service 97d2fb
Packit Service 97d2fb
	  Elf_Data *data = elf_getdata_rawchunk (mod->main.elf,
Packit Service 97d2fb
						 phdr->p_offset, phdr->p_filesz,
Packit Service 97d2fb
						 ELF_T_DYN);
Packit Service 97d2fb
	  if (data == NULL)
Packit Service 97d2fb
	    continue;
Packit Service 97d2fb
Packit Service 97d2fb
	  GElf_Addr addrs[i_max] = { 0, };
Packit Service 97d2fb
	  GElf_Xword strsz = 0;
Packit Service 97d2fb
	  size_t n = data->d_size / gelf_fsize (mod->main.elf,
Packit Service 97d2fb
						ELF_T_DYN, 1, EV_CURRENT);
Packit Service 97d2fb
	  for (size_t j = 0; j < n; ++j)
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      GElf_Dyn dyn_mem;
Packit Service 97d2fb
	      GElf_Dyn *dyn = gelf_getdyn (data, j, &dyn_mem);
Packit Service 97d2fb
	      if (dyn != NULL)
Packit Service 97d2fb
		switch (dyn->d_tag)
Packit Service 97d2fb
		  {
Packit Service 97d2fb
		  case DT_SYMTAB:
Packit Service 97d2fb
		    addrs[i_symtab] = dyn->d_un.d_ptr;
Packit Service 97d2fb
		    continue;
Packit Service 97d2fb
Packit Service 97d2fb
		  case DT_HASH:
Packit Service 97d2fb
		    addrs[i_hash] = dyn->d_un.d_ptr;
Packit Service 97d2fb
		    continue;
Packit Service 97d2fb
Packit Service 97d2fb
		  case DT_GNU_HASH:
Packit Service 97d2fb
		    addrs[i_gnu_hash] = dyn->d_un.d_ptr;
Packit Service 97d2fb
		    continue;
Packit Service 97d2fb
Packit Service 97d2fb
		  case DT_STRTAB:
Packit Service 97d2fb
		    addrs[i_strtab] = dyn->d_un.d_ptr;
Packit Service 97d2fb
		    continue;
Packit Service 97d2fb
Packit Service 97d2fb
		  case DT_STRSZ:
Packit Service 97d2fb
		    strsz = dyn->d_un.d_val;
Packit Service 97d2fb
		    continue;
Packit Service 97d2fb
Packit Service 97d2fb
		  default:
Packit Service 97d2fb
		    continue;
Packit Service 97d2fb
Packit Service 97d2fb
		  case DT_NULL:
Packit Service 97d2fb
		    break;
Packit Service 97d2fb
		  }
Packit Service 97d2fb
	      break;
Packit Service 97d2fb
	    }
Packit Service 97d2fb
Packit Service 97d2fb
	  /* First try unadjusted, like ELF files from disk, vdso.
Packit Service 97d2fb
	     Then try for already adjusted dynamic section, like ELF
Packit Service 97d2fb
	     from remote memory.  */
Packit Service 97d2fb
	  translate_offs (0, mod, phnum, addrs, strsz, ehdr);
Packit Service 97d2fb
	  if (mod->symfile == NULL)
Packit Service 97d2fb
	    translate_offs (mod->main_bias, mod, phnum, addrs, strsz, ehdr);
Packit Service 97d2fb
Packit Service 97d2fb
	  return;
Packit Service 97d2fb
	}
Packit Service 97d2fb
    }
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
Packit Service 97d2fb
#if USE_LZMA
Packit Service 97d2fb
/* Try to find the offset between the main file and .gnu_debugdata.  */
Packit Service 97d2fb
static bool
Packit Service 97d2fb
find_aux_address_sync (Dwfl_Module *mod)
Packit Service 97d2fb
{
Packit Service 97d2fb
  /* Don't trust the phdrs in the minisymtab elf file to be setup correctly.
Packit Service 97d2fb
     The address_sync is equal to the main file it is embedded in at first.  */
Packit Service 97d2fb
  mod->aux_sym.address_sync = mod->main.address_sync;
Packit Service 97d2fb
Packit Service 97d2fb
  /* Adjust address_sync for the difference in entry addresses, attempting to
Packit Service 97d2fb
     account for ELF relocation changes after aux was split.  */
Packit Service 97d2fb
  GElf_Ehdr ehdr_main, ehdr_aux;
Packit Service 97d2fb
  if (unlikely (gelf_getehdr (mod->main.elf, &ehdr_main) == NULL)
Packit Service 97d2fb
      || unlikely (gelf_getehdr (mod->aux_sym.elf, &ehdr_aux) == NULL))
Packit Service 97d2fb
    return false;
Packit Service 97d2fb
  mod->aux_sym.address_sync += ehdr_aux.e_entry - ehdr_main.e_entry;
Packit Service 97d2fb
Packit Service 97d2fb
  /* The shdrs are setup OK to make find_prelink_address_sync () do the right
Packit Service 97d2fb
     thing, which is possibly more reliable, but it needs .gnu.prelink_undo.  */
Packit Service 97d2fb
  if (mod->aux_sym.address_sync != 0)
Packit Service 97d2fb
    return find_prelink_address_sync (mod, &mod->aux_sym) == DWFL_E_NOERROR;
Packit Service 97d2fb
Packit Service 97d2fb
  return true;
Packit Service 97d2fb
}
Packit Service 97d2fb
#endif
Packit Service 97d2fb
Packit Service 97d2fb
/* Try to find the auxiliary symbol table embedded in the main elf file
Packit Service 97d2fb
   section .gnu_debugdata.  Only matters if the symbol information comes
Packit Service 97d2fb
   from the main file dynsym.  No harm done if not found.  */
Packit Service 97d2fb
static void
Packit Service 97d2fb
find_aux_sym (Dwfl_Module *mod __attribute__ ((unused)),
Packit Service 97d2fb
	      Elf_Scn **aux_symscn __attribute__ ((unused)),
Packit Service 97d2fb
	      Elf_Scn **aux_xndxscn __attribute__ ((unused)),
Packit Service 97d2fb
	      GElf_Word *aux_strshndx __attribute__ ((unused)))
Packit Service 97d2fb
{
Packit Service 97d2fb
  /* Since a .gnu_debugdata section is compressed using lzma don't do
Packit Service 97d2fb
     anything unless we have support for that.  */
Packit Service 97d2fb
#if USE_LZMA
Packit Service 97d2fb
  Elf *elf = mod->main.elf;
Packit Service 97d2fb
Packit Service 97d2fb
  size_t shstrndx;
Packit Service 97d2fb
  if (elf_getshdrstrndx (elf, &shstrndx) < 0)
Packit Service 97d2fb
    return;
Packit Service 97d2fb
Packit Service 97d2fb
  Elf_Scn *scn = NULL;
Packit Service 97d2fb
  while ((scn = elf_nextscn (elf, scn)) != NULL)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      GElf_Shdr shdr_mem;
Packit Service 97d2fb
      GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
Packit Service 97d2fb
      if (shdr == NULL)
Packit Service 97d2fb
	return;
Packit Service 97d2fb
Packit Service 97d2fb
      const char *name = elf_strptr (elf, shstrndx, shdr->sh_name);
Packit Service 97d2fb
      if (name == NULL)
Packit Service 97d2fb
	return;
Packit Service 97d2fb
Packit Service 97d2fb
      if (!strcmp (name, ".gnu_debugdata"))
Packit Service 97d2fb
	break;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  if (scn == NULL)
Packit Service 97d2fb
    return;
Packit Service 97d2fb
Packit Service 97d2fb
  /* Found the .gnu_debugdata section.  Uncompress the lzma image and
Packit Service 97d2fb
     turn it into an ELF image.  */
Packit Service 97d2fb
  Elf_Data *rawdata = elf_rawdata (scn, NULL);
Packit Service 97d2fb
  if (rawdata == NULL)
Packit Service 97d2fb
    return;
Packit Service 97d2fb
Packit Service 97d2fb
  Dwfl_Error error;
Packit Service 97d2fb
  void *buffer = NULL;
Packit Service 97d2fb
  size_t size = 0;
Packit Service 97d2fb
  error = __libdw_unlzma (-1, 0, rawdata->d_buf, rawdata->d_size,
Packit Service 97d2fb
			  &buffer, &size);
Packit Service 97d2fb
  if (error == DWFL_E_NOERROR)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      if (unlikely (size == 0))
Packit Service 97d2fb
	free (buffer);
Packit Service 97d2fb
      else
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  mod->aux_sym.elf = elf_memory (buffer, size);
Packit Service 97d2fb
	  if (mod->aux_sym.elf == NULL)
Packit Service 97d2fb
	    free (buffer);
Packit Service 97d2fb
	  else
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      mod->aux_sym.fd = -1;
Packit Service 97d2fb
	      mod->aux_sym.elf->flags |= ELF_F_MALLOCED;
Packit Service 97d2fb
	      if (open_elf (mod, &mod->aux_sym) != DWFL_E_NOERROR)
Packit Service 97d2fb
		return;
Packit Service 97d2fb
	      if (! find_aux_address_sync (mod))
Packit Service 97d2fb
		{
Packit Service 97d2fb
		  elf_end (mod->aux_sym.elf);
Packit Service 97d2fb
		  mod->aux_sym.elf = NULL;
Packit Service 97d2fb
		  return;
Packit Service 97d2fb
		}
Packit Service 97d2fb
Packit Service 97d2fb
	      /* So far, so good. Get minisymtab table data and cache it. */
Packit Service 97d2fb
	      bool minisymtab = false;
Packit Service 97d2fb
	      scn = NULL;
Packit Service 97d2fb
	      while ((scn = elf_nextscn (mod->aux_sym.elf, scn)) != NULL)
Packit Service 97d2fb
		{
Packit Service 97d2fb
		  GElf_Shdr shdr_mem, *shdr = gelf_getshdr (scn, &shdr_mem);
Packit Service 97d2fb
		  if (shdr != NULL)
Packit Service 97d2fb
		    switch (shdr->sh_type)
Packit Service 97d2fb
		      {
Packit Service 97d2fb
		      case SHT_SYMTAB:
Packit Service 97d2fb
			if (shdr->sh_entsize == 0)
Packit Service 97d2fb
			  return;
Packit Service 97d2fb
			minisymtab = true;
Packit Service 97d2fb
			*aux_symscn = scn;
Packit Service 97d2fb
			*aux_strshndx = shdr->sh_link;
Packit Service 97d2fb
			mod->aux_syments = shdr->sh_size / shdr->sh_entsize;
Packit Service 97d2fb
			mod->aux_first_global = shdr->sh_info;
Packit Service 97d2fb
			if (*aux_xndxscn != NULL)
Packit Service 97d2fb
			  return;
Packit Service 97d2fb
			break;
Packit Service 97d2fb
Packit Service 97d2fb
		      case SHT_SYMTAB_SHNDX:
Packit Service 97d2fb
			*aux_xndxscn = scn;
Packit Service 97d2fb
			if (minisymtab)
Packit Service 97d2fb
			  return;
Packit Service 97d2fb
			break;
Packit Service 97d2fb
Packit Service 97d2fb
		      default:
Packit Service 97d2fb
			break;
Packit Service 97d2fb
		      }
Packit Service 97d2fb
		}
Packit Service 97d2fb
Packit Service 97d2fb
	      if (minisymtab)
Packit Service 97d2fb
		/* We found one, though no SHT_SYMTAB_SHNDX to go with it.  */
Packit Service 97d2fb
		return;
Packit Service 97d2fb
Packit Service 97d2fb
	      /* We found no SHT_SYMTAB, so everything else is bogus.  */
Packit Service 97d2fb
	      *aux_xndxscn = NULL;
Packit Service 97d2fb
	      *aux_strshndx = 0;
Packit Service 97d2fb
	      mod->aux_syments = 0;
Packit Service 97d2fb
	      elf_end (mod->aux_sym.elf);
Packit Service 97d2fb
	      mod->aux_sym.elf = NULL;
Packit Service 97d2fb
	      return;
Packit Service 97d2fb
	    }
Packit Service 97d2fb
	}
Packit Service 97d2fb
    }
Packit Service 97d2fb
  else
Packit Service 97d2fb
    free (buffer);
Packit Service 97d2fb
#endif
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
/* Try to find a symbol table in either MOD->main.elf or MOD->debug.elf.  */
Packit Service 97d2fb
static void
Packit Service 97d2fb
find_symtab (Dwfl_Module *mod)
Packit Service 97d2fb
{
Packit Service 97d2fb
  if (mod->symdata != NULL || mod->aux_symdata != NULL	/* Already done.  */
Packit Service 97d2fb
      || mod->symerr != DWFL_E_NOERROR) /* Cached previous failure.  */
Packit Service 97d2fb
    return;
Packit Service 97d2fb
Packit Service 97d2fb
  __libdwfl_getelf (mod);
Packit Service 97d2fb
  mod->symerr = mod->elferr;
Packit Service 97d2fb
  if (mod->symerr != DWFL_E_NOERROR)
Packit Service 97d2fb
    return;
Packit Service 97d2fb
Packit Service 97d2fb
  /* First see if the main ELF file has the debugging information.  */
Packit Service 97d2fb
  Elf_Scn *symscn = NULL, *xndxscn = NULL;
Packit Service 97d2fb
  Elf_Scn *aux_symscn = NULL, *aux_xndxscn = NULL;
Packit Service 97d2fb
  GElf_Word strshndx, aux_strshndx = 0;
Packit Service 97d2fb
  mod->symerr = load_symtab (&mod->main, &mod->symfile, &symscn,
Packit Service 97d2fb
			     &xndxscn, &mod->syments, &mod->first_global,
Packit Service 97d2fb
			     &strshndx);
Packit Service 97d2fb
  switch (mod->symerr)
Packit Service 97d2fb
    {
Packit Service 97d2fb
    default:
Packit Service 97d2fb
      return;
Packit Service 97d2fb
Packit Service 97d2fb
    case DWFL_E_NOERROR:
Packit Service 97d2fb
      break;
Packit Service 97d2fb
Packit Service 97d2fb
    case DWFL_E_NO_SYMTAB:
Packit Service 97d2fb
      /* Now we have to look for a separate debuginfo file.  */
Packit Service 97d2fb
      mod->symerr = find_debuginfo (mod);
Packit Service 97d2fb
      switch (mod->symerr)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	default:
Packit Service 97d2fb
	  return;
Packit Service 97d2fb
Packit Service 97d2fb
	case DWFL_E_NOERROR:
Packit Service 97d2fb
	  mod->symerr = load_symtab (&mod->debug, &mod->symfile, &symscn,
Packit Service 97d2fb
				     &xndxscn, &mod->syments,
Packit Service 97d2fb
				     &mod->first_global, &strshndx);
Packit Service 97d2fb
	  break;
Packit Service 97d2fb
Packit Service 97d2fb
	case DWFL_E_CB:		/* The find_debuginfo hook failed.  */
Packit Service 97d2fb
	  mod->symerr = DWFL_E_NO_SYMTAB;
Packit Service 97d2fb
	  break;
Packit Service 97d2fb
	}
Packit Service 97d2fb
Packit Service 97d2fb
      switch (mod->symerr)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	default:
Packit Service 97d2fb
	  return;
Packit Service 97d2fb
Packit Service 97d2fb
	case DWFL_E_NOERROR:
Packit Service 97d2fb
	  break;
Packit Service 97d2fb
Packit Service 97d2fb
	case DWFL_E_NO_SYMTAB:
Packit Service 97d2fb
	  /* There might be an auxiliary table.  */
Packit Service 97d2fb
	  find_aux_sym (mod, &aux_symscn, &aux_xndxscn, &aux_strshndx);
Packit Service 97d2fb
Packit Service 97d2fb
	  if (symscn != NULL)
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      /* We still have the dynamic symbol table.  */
Packit Service 97d2fb
	      mod->symerr = DWFL_E_NOERROR;
Packit Service 97d2fb
	      break;
Packit Service 97d2fb
	    }
Packit Service 97d2fb
Packit Service 97d2fb
	  if (aux_symscn != NULL)
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      /* We still have the auxiliary symbol table.  */
Packit Service 97d2fb
	      mod->symerr = DWFL_E_NOERROR;
Packit Service 97d2fb
	      goto aux_cache;
Packit Service 97d2fb
	    }
Packit Service 97d2fb
Packit Service 97d2fb
	  /* Last ditch, look for dynamic symbols without section headers.  */
Packit Service 97d2fb
	  find_dynsym (mod);
Packit Service 97d2fb
	  return;
Packit Service 97d2fb
	}
Packit Service 97d2fb
      break;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  /* This does some sanity checks on the string table section.  */
Packit Service 97d2fb
  if (elf_strptr (mod->symfile->elf, strshndx, 0) == NULL)
Packit Service 97d2fb
    {
Packit Service 97d2fb
    elferr:
Packit Service 97d2fb
      mod->symdata = NULL;
Packit Service 97d2fb
      mod->syments = 0;
Packit Service 97d2fb
      mod->first_global = 0;
Packit Service 97d2fb
      mod->symerr = DWFL_E (LIBELF, elf_errno ());
Packit Service 97d2fb
      goto aux_cleanup; /* This cleans up some more and tries find_dynsym.  */
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  /* Cache the data; MOD->syments and MOD->first_global were set
Packit Service 97d2fb
     above.  If any of the sections is compressed, uncompress it
Packit Service 97d2fb
     first.  Only the string data setion could theoretically be
Packit Service 97d2fb
     compressed GNU style (as .zdebug_str).  Everything else only ELF
Packit Service 97d2fb
     gabi style (SHF_COMPRESSED).  */
Packit Service 97d2fb
Packit Service 97d2fb
  Elf_Scn *symstrscn = elf_getscn (mod->symfile->elf, strshndx);
Packit Service 97d2fb
  if (symstrscn == NULL)
Packit Service 97d2fb
    goto elferr;
Packit Service 97d2fb
Packit Service 97d2fb
  GElf_Shdr shdr_mem;
Packit Service 97d2fb
  GElf_Shdr *shdr = gelf_getshdr (symstrscn, &shdr_mem);
Packit Service 97d2fb
  if (shdr == NULL)
Packit Service 97d2fb
    goto elferr;
Packit Service 97d2fb
Packit Service 97d2fb
  size_t shstrndx;
Packit Service 97d2fb
  if (elf_getshdrstrndx (mod->symfile->elf, &shstrndx) < 0)
Packit Service 97d2fb
    goto elferr;
Packit Service 97d2fb
Packit Service 97d2fb
  const char *sname = elf_strptr (mod->symfile->elf, shstrndx, shdr->sh_name);
Packit Service 97d2fb
  if (sname == NULL)
Packit Service 97d2fb
    goto elferr;
Packit Service 97d2fb
Packit Service 97d2fb
  if (strncmp (sname, ".zdebug", strlen (".zdebug")) == 0)
Packit Service 97d2fb
    /* Try to uncompress, but it might already have been, an error
Packit Service 97d2fb
       might just indicate, already uncompressed.  */
Packit Service 97d2fb
    elf_compress_gnu (symstrscn, 0, 0);
Packit Service 97d2fb
Packit Service 97d2fb
  if ((shdr->sh_flags & SHF_COMPRESSED) != 0)
Packit Service 97d2fb
    if (elf_compress (symstrscn, 0, 0) < 0)
Packit Service 97d2fb
      goto elferr;
Packit Service 97d2fb
Packit Service 97d2fb
  mod->symstrdata = elf_getdata (symstrscn, NULL);
Packit Service 97d2fb
  if (mod->symstrdata == NULL || mod->symstrdata->d_buf == NULL)
Packit Service 97d2fb
    goto elferr;
Packit Service 97d2fb
Packit Service 97d2fb
  if (xndxscn == NULL)
Packit Service 97d2fb
    mod->symxndxdata = NULL;
Packit Service 97d2fb
  else
Packit Service 97d2fb
    {
Packit Service 97d2fb
      shdr = gelf_getshdr (xndxscn, &shdr_mem);
Packit Service 97d2fb
      if (shdr == NULL)
Packit Service 97d2fb
	goto elferr;
Packit Service 97d2fb
Packit Service 97d2fb
      if ((shdr->sh_flags & SHF_COMPRESSED) != 0)
Packit Service 97d2fb
	if (elf_compress (xndxscn, 0, 0) < 0)
Packit Service 97d2fb
	  goto elferr;
Packit Service 97d2fb
Packit Service 97d2fb
      mod->symxndxdata = elf_getdata (xndxscn, NULL);
Packit Service 97d2fb
      if (mod->symxndxdata == NULL || mod->symxndxdata->d_buf == NULL)
Packit Service 97d2fb
	goto elferr;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  shdr = gelf_getshdr (symscn, &shdr_mem);
Packit Service 97d2fb
  if (shdr == NULL)
Packit Service 97d2fb
    goto elferr;
Packit Service 97d2fb
Packit Service 97d2fb
  if ((shdr->sh_flags & SHF_COMPRESSED) != 0)
Packit Service 97d2fb
    if (elf_compress (symscn, 0, 0) < 0)
Packit Service 97d2fb
      goto elferr;
Packit Service 97d2fb
Packit Service 97d2fb
  mod->symdata = elf_getdata (symscn, NULL);
Packit Service 97d2fb
  if (mod->symdata == NULL || mod->symdata->d_buf == NULL)
Packit Service 97d2fb
    goto elferr;
Packit Service 97d2fb
Packit Service 97d2fb
  // Sanity check number of symbols.
Packit Service 97d2fb
  shdr = gelf_getshdr (symscn, &shdr_mem);
Packit Service 97d2fb
  if (shdr == NULL || shdr->sh_entsize == 0
Packit Service 97d2fb
      || mod->syments > mod->symdata->d_size / shdr->sh_entsize
Packit Service 97d2fb
      || (size_t) mod->first_global > mod->syments)
Packit Service 97d2fb
    goto elferr;
Packit Service 97d2fb
Packit Service 97d2fb
  /* Cache any auxiliary symbol info, when it fails, just ignore aux_sym.  */
Packit Service 97d2fb
  if (aux_symscn != NULL)
Packit Service 97d2fb
    {
Packit Service 97d2fb
  aux_cache:
Packit Service 97d2fb
      /* This does some sanity checks on the string table section.  */
Packit Service 97d2fb
      if (elf_strptr (mod->aux_sym.elf, aux_strshndx, 0) == NULL)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	aux_cleanup:
Packit Service 97d2fb
	  mod->aux_syments = 0;
Packit Service 97d2fb
	  elf_end (mod->aux_sym.elf);
Packit Service 97d2fb
	  mod->aux_sym.elf = NULL;
Packit Service 97d2fb
	  /* We thought we had something through shdrs, but it failed...
Packit Service 97d2fb
	     Last ditch, look for dynamic symbols without section headers.  */
Packit Service 97d2fb
	  find_dynsym (mod);
Packit Service 97d2fb
	  return;
Packit Service 97d2fb
	}
Packit Service 97d2fb
Packit Service 97d2fb
      Elf_Scn *aux_strscn = elf_getscn (mod->aux_sym.elf, aux_strshndx);
Packit Service 97d2fb
      if (aux_strscn == NULL)
Packit Service 97d2fb
	goto elferr;
Packit Service 97d2fb
Packit Service 97d2fb
      shdr = gelf_getshdr (aux_strscn, &shdr_mem);
Packit Service 97d2fb
      if (shdr == NULL)
Packit Service 97d2fb
	goto elferr;
Packit Service 97d2fb
Packit Service 97d2fb
      size_t aux_shstrndx;
Packit Service 97d2fb
      if (elf_getshdrstrndx (mod->aux_sym.elf, &aux_shstrndx) < 0)
Packit Service 97d2fb
	goto elferr;
Packit Service 97d2fb
Packit Service 97d2fb
      sname = elf_strptr (mod->aux_sym.elf, aux_shstrndx,
Packit Service 97d2fb
				      shdr->sh_name);
Packit Service 97d2fb
      if (sname == NULL)
Packit Service 97d2fb
	goto elferr;
Packit Service 97d2fb
Packit Service 97d2fb
      if (strncmp (sname, ".zdebug", strlen (".zdebug")) == 0)
Packit Service 97d2fb
	/* Try to uncompress, but it might already have been, an error
Packit Service 97d2fb
	   might just indicate, already uncompressed.  */
Packit Service 97d2fb
	elf_compress_gnu (aux_strscn, 0, 0);
Packit Service 97d2fb
Packit Service 97d2fb
      if ((shdr->sh_flags & SHF_COMPRESSED) != 0)
Packit Service 97d2fb
	if (elf_compress (aux_strscn, 0, 0) < 0)
Packit Service 97d2fb
	  goto elferr;
Packit Service 97d2fb
Packit Service 97d2fb
      mod->aux_symstrdata = elf_getdata (aux_strscn, NULL);
Packit Service 97d2fb
      if (mod->aux_symstrdata == NULL || mod->aux_symstrdata->d_buf == NULL)
Packit Service 97d2fb
	goto aux_cleanup;
Packit Service 97d2fb
Packit Service 97d2fb
      if (aux_xndxscn == NULL)
Packit Service 97d2fb
	mod->aux_symxndxdata = NULL;
Packit Service 97d2fb
      else
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  shdr = gelf_getshdr (aux_xndxscn, &shdr_mem);
Packit Service 97d2fb
	  if (shdr == NULL)
Packit Service 97d2fb
	    goto elferr;
Packit Service 97d2fb
Packit Service 97d2fb
	  if ((shdr->sh_flags & SHF_COMPRESSED) != 0)
Packit Service 97d2fb
	    if (elf_compress (aux_xndxscn, 0, 0) < 0)
Packit Service 97d2fb
	      goto elferr;
Packit Service 97d2fb
Packit Service 97d2fb
	  mod->aux_symxndxdata = elf_getdata (aux_xndxscn, NULL);
Packit Service 97d2fb
	  if (mod->aux_symxndxdata == NULL
Packit Service 97d2fb
	      || mod->aux_symxndxdata->d_buf == NULL)
Packit Service 97d2fb
	    goto aux_cleanup;
Packit Service 97d2fb
	}
Packit Service 97d2fb
Packit Service 97d2fb
      shdr = gelf_getshdr (aux_symscn, &shdr_mem);
Packit Service 97d2fb
      if (shdr == NULL)
Packit Service 97d2fb
	goto elferr;
Packit Service 97d2fb
Packit Service 97d2fb
      if ((shdr->sh_flags & SHF_COMPRESSED) != 0)
Packit Service 97d2fb
	if (elf_compress (aux_symscn, 0, 0) < 0)
Packit Service 97d2fb
	  goto elferr;
Packit Service 97d2fb
Packit Service 97d2fb
      mod->aux_symdata = elf_getdata (aux_symscn, NULL);
Packit Service 97d2fb
      if (mod->aux_symdata == NULL || mod->aux_symdata->d_buf == NULL)
Packit Service 97d2fb
	goto aux_cleanup;
Packit Service 97d2fb
Packit Service 97d2fb
      // Sanity check number of aux symbols.
Packit Service 97d2fb
      shdr = gelf_getshdr (aux_symscn, &shdr_mem);
Packit Service 97d2fb
      if (mod->aux_syments > mod->aux_symdata->d_size / shdr->sh_entsize
Packit Service 97d2fb
	  || (size_t) mod->aux_first_global > mod->aux_syments)
Packit Service 97d2fb
	goto aux_cleanup;
Packit Service 97d2fb
    }
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
Packit Service 97d2fb
/* Try to open a libebl backend for MOD.  */
Packit Service 97d2fb
Dwfl_Error
Packit Service 97d2fb
internal_function
Packit Service 97d2fb
__libdwfl_module_getebl (Dwfl_Module *mod)
Packit Service 97d2fb
{
Packit Service 97d2fb
  if (mod->ebl == NULL)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      __libdwfl_getelf (mod);
Packit Service 97d2fb
      if (mod->elferr != DWFL_E_NOERROR)
Packit Service 97d2fb
	return mod->elferr;
Packit Service 97d2fb
Packit Service 97d2fb
      mod->ebl = ebl_openbackend (mod->main.elf);
Packit Service 97d2fb
      if (mod->ebl == NULL)
Packit Service 97d2fb
	return DWFL_E_LIBEBL;
Packit Service 97d2fb
    }
Packit Service 97d2fb
  return DWFL_E_NOERROR;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
/* Try to start up libdw on DEBUGFILE.  */
Packit Service 97d2fb
static Dwfl_Error
Packit Service 97d2fb
load_dw (Dwfl_Module *mod, struct dwfl_file *debugfile)
Packit Service 97d2fb
{
Packit Service 97d2fb
  if (mod->e_type == ET_REL && !debugfile->relocated)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      const Dwfl_Callbacks *const cb = mod->dwfl->callbacks;
Packit Service 97d2fb
Packit Service 97d2fb
      /* The debugging sections have to be relocated.  */
Packit Service 97d2fb
      if (cb->section_address == NULL)
Packit Service 97d2fb
	return DWFL_E_NOREL;
Packit Service 97d2fb
Packit Service 97d2fb
      Dwfl_Error error = __libdwfl_module_getebl (mod);
Packit Service 97d2fb
      if (error != DWFL_E_NOERROR)
Packit Service 97d2fb
	return error;
Packit Service 97d2fb
Packit Service 97d2fb
      find_symtab (mod);
Packit Service 97d2fb
      Dwfl_Error result = mod->symerr;
Packit Service 97d2fb
      if (result == DWFL_E_NOERROR)
Packit Service 97d2fb
	result = __libdwfl_relocate (mod, debugfile->elf, true);
Packit Service 97d2fb
      if (result != DWFL_E_NOERROR)
Packit Service 97d2fb
	return result;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  mod->dw = INTUSE(dwarf_begin_elf) (debugfile->elf, DWARF_C_READ, NULL);
Packit Service 97d2fb
  if (mod->dw == NULL)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      int err = INTUSE(dwarf_errno) ();
Packit Service 97d2fb
      return err == DWARF_E_NO_DWARF ? DWFL_E_NO_DWARF : DWFL_E (LIBDW, err);
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  /* Do this after dwarf_begin_elf has a chance to process the fd.  */
Packit Service 97d2fb
  if (mod->e_type == ET_REL && !debugfile->relocated)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      /* Don't keep the file descriptors around.  */
Packit Service 97d2fb
      if (mod->main.fd != -1 && elf_cntl (mod->main.elf, ELF_C_FDREAD) == 0)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  close (mod->main.fd);
Packit Service 97d2fb
	  mod->main.fd = -1;
Packit Service 97d2fb
	}
Packit Service 97d2fb
      if (debugfile->fd != -1 && elf_cntl (debugfile->elf, ELF_C_FDREAD) == 0)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  close (debugfile->fd);
Packit Service 97d2fb
	  debugfile->fd = -1;
Packit Service 97d2fb
	}
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  /* We might have already closed the fd when we asked dwarf_begin_elf to
Packit Service 97d2fb
     create an Dwarf.  Help out a little in case we need to find an alt or
Packit Service 97d2fb
     dwo file later.  */
Packit Service 97d2fb
  if (mod->dw->debugdir == NULL && mod->elfdir != NULL
Packit Service 97d2fb
      && debugfile == &mod->main)
Packit Service 97d2fb
    mod->dw->debugdir = strdup (mod->elfdir);
Packit Service 97d2fb
Packit Service 97d2fb
  /* Until we have iterated through all CU's, we might do lazy lookups.  */
Packit Service 97d2fb
  mod->lazycu = 1;
Packit Service 97d2fb
Packit Service 97d2fb
  return DWFL_E_NOERROR;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
/* Try to start up libdw on either the main file or the debuginfo file.  */
Packit Service 97d2fb
static void
Packit Service 97d2fb
find_dw (Dwfl_Module *mod)
Packit Service 97d2fb
{
Packit Service 97d2fb
  if (mod->dw != NULL		/* Already done.  */
Packit Service 97d2fb
      || mod->dwerr != DWFL_E_NOERROR) /* Cached previous failure.  */
Packit Service 97d2fb
    return;
Packit Service 97d2fb
Packit Service 97d2fb
  __libdwfl_getelf (mod);
Packit Service 97d2fb
  mod->dwerr = mod->elferr;
Packit Service 97d2fb
  if (mod->dwerr != DWFL_E_NOERROR)
Packit Service 97d2fb
    return;
Packit Service 97d2fb
Packit Service 97d2fb
  /* First see if the main ELF file has the debugging information.  */
Packit Service 97d2fb
  mod->dwerr = load_dw (mod, &mod->main);
Packit Service 97d2fb
  switch (mod->dwerr)
Packit Service 97d2fb
    {
Packit Service 97d2fb
    case DWFL_E_NOERROR:
Packit Service 97d2fb
      mod->debug.elf = mod->main.elf;
Packit Service 97d2fb
      mod->debug.address_sync = mod->main.address_sync;
Packit Service 97d2fb
Packit Service 97d2fb
      /* The Dwarf might need an alt debug file, find that now after
Packit Service 97d2fb
	 everything about the debug file has been setup (the
Packit Service 97d2fb
	 find_debuginfo callback might need it).  */
Packit Service 97d2fb
      find_debug_altlink (mod, mod->main.name);
Packit Service 97d2fb
      return;
Packit Service 97d2fb
Packit Service 97d2fb
    case DWFL_E_NO_DWARF:
Packit Service 97d2fb
      break;
Packit Service 97d2fb
Packit Service 97d2fb
    default:
Packit Service 97d2fb
      goto canonicalize;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  /* Now we have to look for a separate debuginfo file.  */
Packit Service 97d2fb
  mod->dwerr = find_debuginfo (mod);
Packit Service 97d2fb
  switch (mod->dwerr)
Packit Service 97d2fb
    {
Packit Service 97d2fb
    case DWFL_E_NOERROR:
Packit Service 97d2fb
      mod->dwerr = load_dw (mod, &mod->debug);
Packit Service 97d2fb
      if (mod->dwerr == DWFL_E_NOERROR)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  /* The Dwarf might need an alt debug file, find that now after
Packit Service 97d2fb
	     everything about the debug file has been setup (the
Packit Service 97d2fb
	     find_debuginfo callback might need it).  */
Packit Service 97d2fb
	  find_debug_altlink (mod, mod->debug.name);
Packit Service 97d2fb
	  return;
Packit Service 97d2fb
	}
Packit Service 97d2fb
Packit Service 97d2fb
      break;
Packit Service 97d2fb
Packit Service 97d2fb
    case DWFL_E_CB:		/* The find_debuginfo hook failed.  */
Packit Service 97d2fb
      mod->dwerr = DWFL_E_NO_DWARF;
Packit Service 97d2fb
      return;
Packit Service 97d2fb
Packit Service 97d2fb
    default:
Packit Service 97d2fb
      break;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
 canonicalize:
Packit Service 97d2fb
  mod->dwerr = __libdwfl_canon_error (mod->dwerr);
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
Dwarf *
Packit Service 97d2fb
dwfl_module_getdwarf (Dwfl_Module *mod, Dwarf_Addr *bias)
Packit Service 97d2fb
{
Packit Service 97d2fb
  if (mod == NULL)
Packit Service 97d2fb
    return NULL;
Packit Service 97d2fb
Packit Service 97d2fb
  find_dw (mod);
Packit Service 97d2fb
  if (mod->dwerr == DWFL_E_NOERROR)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      /* If dwfl_module_getelf was used previously, then partial apply
Packit Service 97d2fb
	 relocation to miscellaneous sections in the debug file too.  */
Packit Service 97d2fb
      if (mod->e_type == ET_REL
Packit Service 97d2fb
	  && mod->main.relocated && ! mod->debug.relocated)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  mod->debug.relocated = true;
Packit Service 97d2fb
	  if (mod->debug.elf != mod->main.elf)
Packit Service 97d2fb
	    (void) __libdwfl_relocate (mod, mod->debug.elf, false);
Packit Service 97d2fb
	}
Packit Service 97d2fb
Packit Service 97d2fb
      *bias = dwfl_adjusted_dwarf_addr (mod, 0);
Packit Service 97d2fb
      return mod->dw;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  __libdwfl_seterrno (mod->dwerr);
Packit Service 97d2fb
  return NULL;
Packit Service 97d2fb
}
Packit Service 97d2fb
INTDEF (dwfl_module_getdwarf)
Packit Service 97d2fb
Packit Service 97d2fb
int
Packit Service 97d2fb
dwfl_module_getsymtab (Dwfl_Module *mod)
Packit Service 97d2fb
{
Packit Service 97d2fb
  if (mod == NULL)
Packit Service 97d2fb
    return -1;
Packit Service 97d2fb
Packit Service 97d2fb
  find_symtab (mod);
Packit Service 97d2fb
  if (mod->symerr == DWFL_E_NOERROR)
Packit Service 97d2fb
    /* We will skip the auxiliary zero entry if there is another one.  */
Packit Service 97d2fb
    return (mod->syments + mod->aux_syments
Packit Service 97d2fb
	    - (mod->syments > 0 && mod->aux_syments > 0 ? 1 : 0));
Packit Service 97d2fb
Packit Service 97d2fb
  __libdwfl_seterrno (mod->symerr);
Packit Service 97d2fb
  return -1;
Packit Service 97d2fb
}
Packit Service 97d2fb
INTDEF (dwfl_module_getsymtab)
Packit Service 97d2fb
Packit Service 97d2fb
int
Packit Service 97d2fb
dwfl_module_getsymtab_first_global (Dwfl_Module *mod)
Packit Service 97d2fb
{
Packit Service 97d2fb
  if (mod == NULL)
Packit Service 97d2fb
    return -1;
Packit Service 97d2fb
Packit Service 97d2fb
  find_symtab (mod);
Packit Service 97d2fb
  if (mod->symerr == DWFL_E_NOERROR)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      /* All local symbols should come before all global symbols.  If
Packit Service 97d2fb
	 we have an auxiliary table make sure all the main locals come
Packit Service 97d2fb
	 first, then all aux locals, then all main globals and finally all
Packit Service 97d2fb
	 aux globals.  And skip the auxiliary table zero undefined
Packit Service 97d2fb
	 entry.  */
Packit Service 97d2fb
      int skip_aux_zero = (mod->syments > 0 && mod->aux_syments > 0) ? 1 : 0;
Packit Service 97d2fb
      return mod->first_global + mod->aux_first_global - skip_aux_zero;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  __libdwfl_seterrno (mod->symerr);
Packit Service 97d2fb
  return -1;
Packit Service 97d2fb
}
Packit Service 97d2fb
INTDEF (dwfl_module_getsymtab_first_global)