Blame libdwfl/dwfl_module_getdwarf.c

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