Blame libdwfl/link_map.c

Packit Service 97d2fb
/* Report modules by examining dynamic linker data structures.
Packit Service 97d2fb
   Copyright (C) 2008-2016 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
#include <config.h>
Packit Service 97d2fb
#include "libdwflP.h"
Packit Service 97d2fb
#include "../libdw/memory-access.h"
Packit Service 97d2fb
#include "system.h"
Packit Service 97d2fb
Packit Service 97d2fb
#include <byteswap.h>
Packit Service 97d2fb
#include <endian.h>
Packit Service 97d2fb
#include <fcntl.h>
Packit Service 97d2fb
Packit Service 97d2fb
/* This element is always provided and always has a constant value.
Packit Service 97d2fb
   This makes it an easy thing to scan for to discern the format.  */
Packit Service 97d2fb
#define PROBE_TYPE	AT_PHENT
Packit Service 97d2fb
#define PROBE_VAL32	sizeof (Elf32_Phdr)
Packit Service 97d2fb
#define PROBE_VAL64	sizeof (Elf64_Phdr)
Packit Service 97d2fb
Packit Service 97d2fb
Packit Service 97d2fb
static inline bool
Packit Service 97d2fb
do_check64 (const char *a64, uint_fast8_t *elfdata)
Packit Service 97d2fb
{
Packit Service 97d2fb
  /* The AUXV pointer might not even be naturally aligned for 64-bit
Packit Service 97d2fb
     data, because note payloads in a core file are not aligned.  */
Packit Service 97d2fb
  const char *typep = a64 + offsetof (Elf64_auxv_t, a_type);
Packit Service 97d2fb
  uint64_t type = read_8ubyte_unaligned_noncvt (typep);
Packit Service 97d2fb
  const char *valp = a64 + offsetof (Elf64_auxv_t, a_un.a_val);
Packit Service 97d2fb
  uint64_t val = read_8ubyte_unaligned_noncvt (valp);
Packit Service 97d2fb
Packit Service 97d2fb
  if (type == BE64 (PROBE_TYPE)
Packit Service 97d2fb
      && val == BE64 (PROBE_VAL64))
Packit Service 97d2fb
    {
Packit Service 97d2fb
      *elfdata = ELFDATA2MSB;
Packit Service 97d2fb
      return true;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  if (type == LE64 (PROBE_TYPE)
Packit Service 97d2fb
      && val == LE64 (PROBE_VAL64))
Packit Service 97d2fb
    {
Packit Service 97d2fb
      *elfdata = ELFDATA2LSB;
Packit Service 97d2fb
      return true;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  return false;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
static inline bool
Packit Service 97d2fb
do_check32 (const char *a32, uint_fast8_t *elfdata)
Packit Service 97d2fb
{
Packit Service 97d2fb
  /* The AUXV pointer might not even be naturally aligned for 32-bit
Packit Service 97d2fb
     data, because note payloads in a core file are not aligned.  */
Packit Service 97d2fb
  const char *typep = a32 + offsetof (Elf32_auxv_t, a_type);
Packit Service 97d2fb
  uint32_t type = read_4ubyte_unaligned_noncvt (typep);
Packit Service 97d2fb
  const char *valp = a32 + offsetof (Elf32_auxv_t, a_un.a_val);
Packit Service 97d2fb
  uint32_t val = read_4ubyte_unaligned_noncvt (valp);
Packit Service 97d2fb
Packit Service 97d2fb
  if (type == BE32 (PROBE_TYPE)
Packit Service 97d2fb
      && val == BE32 (PROBE_VAL32))
Packit Service 97d2fb
    {
Packit Service 97d2fb
      *elfdata = ELFDATA2MSB;
Packit Service 97d2fb
      return true;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  if (type == LE32 (PROBE_TYPE)
Packit Service 97d2fb
      && val == LE32 (PROBE_VAL32))
Packit Service 97d2fb
    {
Packit Service 97d2fb
      *elfdata = ELFDATA2LSB;
Packit Service 97d2fb
      return true;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  return false;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
/* Examine an auxv data block and determine its format.
Packit Service 97d2fb
   Return true iff we figured it out.  */
Packit Service 97d2fb
static bool
Packit Service 97d2fb
auxv_format_probe (const void *auxv, size_t size,
Packit Service 97d2fb
		   uint_fast8_t *elfclass, uint_fast8_t *elfdata)
Packit Service 97d2fb
{
Packit Service 97d2fb
  for (size_t i = 0; i < size / sizeof (Elf64_auxv_t); ++i)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      if (do_check64 (auxv + i * sizeof (Elf64_auxv_t), elfdata))
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  *elfclass = ELFCLASS64;
Packit Service 97d2fb
	  return true;
Packit Service 97d2fb
	}
Packit Service 97d2fb
Packit Service 97d2fb
      if (do_check32 (auxv + (i * 2) * sizeof (Elf32_auxv_t), elfdata)
Packit Service 97d2fb
	  || do_check32 (auxv + (i * 2 + 1) * sizeof (Elf32_auxv_t), elfdata))
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  *elfclass = ELFCLASS32;
Packit Service 97d2fb
	  return true;
Packit Service 97d2fb
	}
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  return false;
Packit Service 97d2fb
}
Packit Service 97d2fb

Packit Service 97d2fb
/* This is a Dwfl_Memory_Callback that wraps another memory callback.
Packit Service 97d2fb
   If the underlying callback cannot fill the data, then this will
Packit Service 97d2fb
   fall back to fetching data from module files.  */
Packit Service 97d2fb
Packit Service 97d2fb
struct integrated_memory_callback
Packit Service 97d2fb
{
Packit Service 97d2fb
  Dwfl_Memory_Callback *memory_callback;
Packit Service 97d2fb
  void *memory_callback_arg;
Packit Service 97d2fb
  void *buffer;
Packit Service 97d2fb
};
Packit Service 97d2fb
Packit Service 97d2fb
static bool
Packit Service 97d2fb
integrated_memory_callback (Dwfl *dwfl, int ndx,
Packit Service 97d2fb
			       void **buffer, size_t *buffer_available,
Packit Service 97d2fb
			       GElf_Addr vaddr,
Packit Service 97d2fb
			       size_t minread,
Packit Service 97d2fb
			       void *arg)
Packit Service 97d2fb
{
Packit Service 97d2fb
  struct integrated_memory_callback *info = arg;
Packit Service 97d2fb
Packit Service 97d2fb
  if (ndx == -1)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      /* Called for cleanup.  */
Packit Service 97d2fb
      if (info->buffer != NULL)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  /* The last probe buffer came from the underlying callback.
Packit Service 97d2fb
	     Let it do its cleanup.  */
Packit Service 97d2fb
	  assert (*buffer == info->buffer); /* XXX */
Packit Service 97d2fb
	  *buffer = info->buffer;
Packit Service 97d2fb
	  info->buffer = NULL;
Packit Service 97d2fb
	  return (*info->memory_callback) (dwfl, ndx, buffer, buffer_available,
Packit Service 97d2fb
					   vaddr, minread,
Packit Service 97d2fb
					   info->memory_callback_arg);
Packit Service 97d2fb
	}
Packit Service 97d2fb
      *buffer = NULL;
Packit Service 97d2fb
      *buffer_available = 0;
Packit Service 97d2fb
      return false;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  if (*buffer != NULL)
Packit Service 97d2fb
    /* For a final-read request, we only use the underlying callback.  */
Packit Service 97d2fb
    return (*info->memory_callback) (dwfl, ndx, buffer, buffer_available,
Packit Service 97d2fb
				     vaddr, minread, info->memory_callback_arg);
Packit Service 97d2fb
Packit Service 97d2fb
  /* Let the underlying callback try to fill this request.  */
Packit Service 97d2fb
  if ((*info->memory_callback) (dwfl, ndx, &info->buffer, buffer_available,
Packit Service 97d2fb
				vaddr, minread, info->memory_callback_arg))
Packit Service 97d2fb
    {
Packit Service 97d2fb
      *buffer = info->buffer;
Packit Service 97d2fb
      return true;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  /* Now look for module text covering this address.  */
Packit Service 97d2fb
Packit Service 97d2fb
  Dwfl_Module *mod;
Packit Service 97d2fb
  (void) INTUSE(dwfl_addrsegment) (dwfl, vaddr, &mod);
Packit Service 97d2fb
  if (mod == NULL)
Packit Service 97d2fb
    return false;
Packit Service 97d2fb
Packit Service 97d2fb
  Dwarf_Addr bias;
Packit Service 97d2fb
  Elf_Scn *scn = INTUSE(dwfl_module_address_section) (mod, &vaddr, &bias);
Packit Service 97d2fb
  if (unlikely (scn == NULL))
Packit Service 97d2fb
    {
Packit Service 97d2fb
#if 0 // XXX would have to handle ndx=-1 cleanup calls passed down.
Packit Service 97d2fb
      /* If we have no sections we can try to fill it from the module file
Packit Service 97d2fb
	 based on its phdr mappings.  */
Packit Service 97d2fb
      if (likely (mod->e_type != ET_REL) && mod->main.elf != NULL)
Packit Service 97d2fb
	return INTUSE(dwfl_elf_phdr_memory_callback)
Packit Service 97d2fb
	  (dwfl, 0, buffer, buffer_available,
Packit Service 97d2fb
	   vaddr - mod->main.bias, minread, mod->main.elf);
Packit Service 97d2fb
#endif
Packit Service 97d2fb
      return false;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  Elf_Data *data = elf_rawdata (scn, NULL);
Packit Service 97d2fb
  if (unlikely (data == NULL))
Packit Service 97d2fb
    // XXX throw error?
Packit Service 97d2fb
    return false;
Packit Service 97d2fb
Packit Service 97d2fb
  if (unlikely (data->d_size < vaddr))
Packit Service 97d2fb
    return false;
Packit Service 97d2fb
Packit Service 97d2fb
  /* Provide as much data as we have.  */
Packit Service 97d2fb
  void *contents = data->d_buf + vaddr;
Packit Service 97d2fb
  size_t avail = data->d_size - vaddr;
Packit Service 97d2fb
  if (unlikely (avail < minread))
Packit Service 97d2fb
    return false;
Packit Service 97d2fb
Packit Service 97d2fb
  /* If probing for a string, make sure it's terminated.  */
Packit Service 97d2fb
  if (minread == 0 && unlikely (memchr (contents, '\0', avail) == NULL))
Packit Service 97d2fb
    return false;
Packit Service 97d2fb
Packit Service 97d2fb
  /* We have it! */
Packit Service 97d2fb
  *buffer = contents;
Packit Service 97d2fb
  *buffer_available = avail;
Packit Service 97d2fb
  return true;
Packit Service 97d2fb
}
Packit Service 97d2fb

Packit Service 97d2fb
static size_t
Packit Service 97d2fb
addrsize (uint_fast8_t elfclass)
Packit Service 97d2fb
{
Packit Service 97d2fb
  return elfclass * 4;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
/* Report a module for each struct link_map in the linked list at r_map
Packit Service 97d2fb
   in the struct r_debug at R_DEBUG_VADDR.  For r_debug_info description
Packit Service 97d2fb
   see dwfl_link_map_report in libdwflP.h.  If R_DEBUG_INFO is not NULL then no
Packit Service 97d2fb
   modules get added to DWFL, caller has to add them from filled in
Packit Service 97d2fb
   R_DEBUG_INFO.
Packit Service 97d2fb
Packit Service 97d2fb
   For each link_map entry, if an existing module resides at its address,
Packit Service 97d2fb
   this just modifies that module's name and suggested file name.  If
Packit Service 97d2fb
   no such module exists, this calls dwfl_report_elf on the l_name string.
Packit Service 97d2fb
Packit Service 97d2fb
   Returns the number of modules found, or -1 for errors.  */
Packit Service 97d2fb
Packit Service 97d2fb
static int
Packit Service 97d2fb
report_r_debug (uint_fast8_t elfclass, uint_fast8_t elfdata,
Packit Service 97d2fb
		Dwfl *dwfl, GElf_Addr r_debug_vaddr,
Packit Service 97d2fb
		Dwfl_Memory_Callback *memory_callback,
Packit Service 97d2fb
		void *memory_callback_arg,
Packit Service 97d2fb
		struct r_debug_info *r_debug_info)
Packit Service 97d2fb
{
Packit Service 97d2fb
  /* Skip r_version, to aligned r_map field.  */
Packit Service 97d2fb
  GElf_Addr read_vaddr = r_debug_vaddr + addrsize (elfclass);
Packit Service 97d2fb
Packit Service 97d2fb
  void *buffer = NULL;
Packit Service 97d2fb
  size_t buffer_available = 0;
Packit Service 97d2fb
  inline int release_buffer (int result)
Packit Service 97d2fb
  {
Packit Service 97d2fb
    if (buffer != NULL)
Packit Service 97d2fb
      (void) (*memory_callback) (dwfl, -1, &buffer, &buffer_available, 0, 0,
Packit Service 97d2fb
				 memory_callback_arg);
Packit Service 97d2fb
    return result;
Packit Service 97d2fb
  }
Packit Service 97d2fb
Packit Service 97d2fb
  GElf_Addr addrs[4];
Packit Service 97d2fb
  inline bool read_addrs (GElf_Addr vaddr, size_t n)
Packit Service 97d2fb
  {
Packit Service 97d2fb
    size_t nb = n * addrsize (elfclass); /* Address words -> bytes to read.  */
Packit Service 97d2fb
Packit Service 97d2fb
    /* Read a new buffer if the old one doesn't cover these words.  */
Packit Service 97d2fb
    if (buffer == NULL
Packit Service 97d2fb
	|| vaddr < read_vaddr
Packit Service 97d2fb
	|| vaddr - read_vaddr + nb > buffer_available)
Packit Service 97d2fb
      {
Packit Service 97d2fb
	release_buffer (0);
Packit Service 97d2fb
Packit Service 97d2fb
	read_vaddr = vaddr;
Packit Service 97d2fb
	int segndx = INTUSE(dwfl_addrsegment) (dwfl, vaddr, NULL);
Packit Service 97d2fb
	if (unlikely (segndx < 0)
Packit Service 97d2fb
	    || unlikely (! (*memory_callback) (dwfl, segndx,
Packit Service 97d2fb
					       &buffer, &buffer_available,
Packit Service 97d2fb
					       vaddr, nb, memory_callback_arg)))
Packit Service 97d2fb
	  return true;
Packit Service 97d2fb
      }
Packit Service 97d2fb
Packit Service 97d2fb
    Elf32_Addr (*a32)[n] = vaddr - read_vaddr + buffer;
Packit Service 97d2fb
    Elf64_Addr (*a64)[n] = (void *) a32;
Packit Service 97d2fb
Packit Service 97d2fb
    if (elfclass == ELFCLASS32)
Packit Service 97d2fb
      {
Packit Service 97d2fb
	if (elfdata == ELFDATA2MSB)
Packit Service 97d2fb
	  for (size_t i = 0; i < n; ++i)
Packit Service 97d2fb
	    addrs[i] = BE32 (read_4ubyte_unaligned_noncvt (&(*a32)[i]));
Packit Service 97d2fb
	else
Packit Service 97d2fb
	  for (size_t i = 0; i < n; ++i)
Packit Service 97d2fb
	    addrs[i] = LE32 (read_4ubyte_unaligned_noncvt (&(*a32)[i]));
Packit Service 97d2fb
      }
Packit Service 97d2fb
    else
Packit Service 97d2fb
      {
Packit Service 97d2fb
	if (elfdata == ELFDATA2MSB)
Packit Service 97d2fb
	  for (size_t i = 0; i < n; ++i)
Packit Service 97d2fb
	    addrs[i] = BE64 (read_8ubyte_unaligned_noncvt (&(*a64)[i]));
Packit Service 97d2fb
	else
Packit Service 97d2fb
	  for (size_t i = 0; i < n; ++i)
Packit Service 97d2fb
	    addrs[i] = LE64 (read_8ubyte_unaligned_noncvt (&(*a64)[i]));
Packit Service 97d2fb
      }
Packit Service 97d2fb
Packit Service 97d2fb
    return false;
Packit Service 97d2fb
  }
Packit Service 97d2fb
Packit Service 97d2fb
  if (unlikely (read_addrs (read_vaddr, 1)))
Packit Service 97d2fb
    return release_buffer (-1);
Packit Service 97d2fb
Packit Service 97d2fb
  GElf_Addr next = addrs[0];
Packit Service 97d2fb
Packit Service 97d2fb
  Dwfl_Module **lastmodp = &dwfl->modulelist;
Packit Service 97d2fb
  int result = 0;
Packit Service 97d2fb
Packit Service 97d2fb
  /* There can't be more elements in the link_map list than there are
Packit Service 97d2fb
     segments.  DWFL->lookup_elts is probably twice that number, so it
Packit Service 97d2fb
     is certainly above the upper bound.  If we iterate too many times,
Packit Service 97d2fb
     there must be a loop in the pointers due to link_map clobberation.  */
Packit Service 97d2fb
  size_t iterations = 0;
Packit Service 97d2fb
  while (next != 0 && ++iterations < dwfl->lookup_elts)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      if (read_addrs (next, 4))
Packit Service 97d2fb
	return release_buffer (-1);
Packit Service 97d2fb
Packit Service 97d2fb
      /* Unused: l_addr is the difference between the address in memory
Packit Service 97d2fb
         and the ELF file when the core was created. We need to
Packit Service 97d2fb
         recalculate the difference below because the ELF file we use
Packit Service 97d2fb
         might be differently pre-linked.  */
Packit Service 97d2fb
      // GElf_Addr l_addr = addrs[0];
Packit Service 97d2fb
      GElf_Addr l_name = addrs[1];
Packit Service 97d2fb
      GElf_Addr l_ld = addrs[2];
Packit Service 97d2fb
      next = addrs[3];
Packit Service 97d2fb
Packit Service 97d2fb
      /* If a clobbered or truncated memory image has no useful pointer,
Packit Service 97d2fb
	 just skip this element.  */
Packit Service 97d2fb
      if (l_ld == 0)
Packit Service 97d2fb
	continue;
Packit Service 97d2fb
Packit Service 97d2fb
      /* Fetch the string at the l_name address.  */
Packit Service 97d2fb
      const char *name = NULL;
Packit Service 97d2fb
      if (buffer != NULL
Packit Service 97d2fb
	  && read_vaddr <= l_name
Packit Service 97d2fb
	  && l_name + 1 - read_vaddr < buffer_available
Packit Service 97d2fb
	  && memchr (l_name - read_vaddr + buffer, '\0',
Packit Service 97d2fb
		     buffer_available - (l_name - read_vaddr)) != NULL)
Packit Service 97d2fb
	name = l_name - read_vaddr + buffer;
Packit Service 97d2fb
      else
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  release_buffer (0);
Packit Service 97d2fb
	  read_vaddr = l_name;
Packit Service 97d2fb
	  int segndx = INTUSE(dwfl_addrsegment) (dwfl, l_name, NULL);
Packit Service 97d2fb
	  if (likely (segndx >= 0)
Packit Service 97d2fb
	      && (*memory_callback) (dwfl, segndx,
Packit Service 97d2fb
				     &buffer, &buffer_available,
Packit Service 97d2fb
				     l_name, 0, memory_callback_arg))
Packit Service 97d2fb
	    name = buffer;
Packit Service 97d2fb
	}
Packit Service 97d2fb
Packit Service 97d2fb
      if (name != NULL && name[0] == '\0')
Packit Service 97d2fb
	name = NULL;
Packit Service 97d2fb
Packit Service 97d2fb
      if (iterations == 1
Packit Service 97d2fb
	  && dwfl->user_core != NULL
Packit Service 97d2fb
	  && dwfl->user_core->executable_for_core != NULL)
Packit Service 97d2fb
	name = dwfl->user_core->executable_for_core;
Packit Service 97d2fb
Packit Service 97d2fb
      struct r_debug_info_module *r_debug_info_module = NULL;
Packit Service 97d2fb
      if (r_debug_info != NULL)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  /* Save link map information about valid shared library (or
Packit Service 97d2fb
	     executable) which has not been found on disk.  */
Packit Service 97d2fb
	  const char *name1 = name == NULL ? "" : name;
Packit Service 97d2fb
	  r_debug_info_module = malloc (sizeof (*r_debug_info_module)
Packit Service 97d2fb
					+ strlen (name1) + 1);
Packit Service 97d2fb
	  if (unlikely (r_debug_info_module == NULL))
Packit Service 97d2fb
	    return release_buffer (result);
Packit Service 97d2fb
	  r_debug_info_module->fd = -1;
Packit Service 97d2fb
	  r_debug_info_module->elf = NULL;
Packit Service 97d2fb
	  r_debug_info_module->l_ld = l_ld;
Packit Service 97d2fb
	  r_debug_info_module->start = 0;
Packit Service 97d2fb
	  r_debug_info_module->end = 0;
Packit Service 97d2fb
	  r_debug_info_module->disk_file_has_build_id = false;
Packit Service 97d2fb
	  strcpy (r_debug_info_module->name, name1);
Packit Service 97d2fb
	  r_debug_info_module->next = r_debug_info->module;
Packit Service 97d2fb
	  r_debug_info->module = r_debug_info_module;
Packit Service 97d2fb
	}
Packit Service 97d2fb
Packit Service 97d2fb
      Dwfl_Module *mod = NULL;
Packit Service 97d2fb
      if (name != NULL)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  /* This code is mostly inlined dwfl_report_elf.  */
Packit Service 97d2fb
	  // XXX hook for sysroot
Packit Service 97d2fb
	  int fd = open (name, O_RDONLY);
Packit Service 97d2fb
	  if (fd >= 0)
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      Elf *elf;
Packit Service 97d2fb
	      Dwfl_Error error = __libdw_open_file (&fd, &elf, true, false);
Packit Service 97d2fb
	      GElf_Addr elf_dynamic_vaddr;
Packit Service 97d2fb
	      if (error == DWFL_E_NOERROR
Packit Service 97d2fb
		  && __libdwfl_dynamic_vaddr_get (elf, &elf_dynamic_vaddr))
Packit Service 97d2fb
		{
Packit Service 97d2fb
		  const void *build_id_bits;
Packit Service 97d2fb
		  GElf_Addr build_id_elfaddr;
Packit Service 97d2fb
		  int build_id_len;
Packit Service 97d2fb
		  bool valid = true;
Packit Service 97d2fb
Packit Service 97d2fb
		  if (__libdwfl_find_elf_build_id (NULL, elf, &build_id_bits,
Packit Service 97d2fb
						   &build_id_elfaddr,
Packit Service 97d2fb
						   &build_id_len) > 0
Packit Service 97d2fb
		      && build_id_elfaddr != 0)
Packit Service 97d2fb
		    {
Packit Service 97d2fb
		      if (r_debug_info_module != NULL)
Packit Service 97d2fb
			r_debug_info_module->disk_file_has_build_id = true;
Packit Service 97d2fb
		      GElf_Addr build_id_vaddr = (build_id_elfaddr
Packit Service 97d2fb
						  - elf_dynamic_vaddr + l_ld);
Packit Service 97d2fb
Packit Service 97d2fb
		      release_buffer (0);
Packit Service 97d2fb
		      int segndx = INTUSE(dwfl_addrsegment) (dwfl,
Packit Service 97d2fb
							     build_id_vaddr,
Packit Service 97d2fb
							     NULL);
Packit Service 97d2fb
		      if (! (*memory_callback) (dwfl, segndx,
Packit Service 97d2fb
						&buffer, &buffer_available,
Packit Service 97d2fb
						build_id_vaddr, build_id_len,
Packit Service 97d2fb
						memory_callback_arg))
Packit Service 97d2fb
			{
Packit Service 97d2fb
			  /* File has valid build-id which cannot be read from
Packit Service 97d2fb
			     memory.  This happens for core files without bit 4
Packit Service 97d2fb
			     (0x10) set in Linux /proc/PID/coredump_filter.  */
Packit Service 97d2fb
			}
Packit Service 97d2fb
		      else
Packit Service 97d2fb
			{
Packit Service 97d2fb
			  if (memcmp (build_id_bits, buffer, build_id_len) != 0)
Packit Service 97d2fb
			    /* File has valid build-id which does not match
Packit Service 97d2fb
			       the one in memory.  */
Packit Service 97d2fb
			    valid = false;
Packit Service 97d2fb
			  release_buffer (0);
Packit Service 97d2fb
			}
Packit Service 97d2fb
		    }
Packit Service 97d2fb
Packit Service 97d2fb
		  if (valid)
Packit Service 97d2fb
		    {
Packit Service 97d2fb
		      // It is like l_addr but it handles differently prelinked
Packit Service 97d2fb
		      // files at core dumping vs. core loading time.
Packit Service 97d2fb
		      GElf_Addr base = l_ld - elf_dynamic_vaddr;
Packit Service 97d2fb
		      if (r_debug_info_module == NULL)
Packit Service 97d2fb
			{
Packit Service 97d2fb
			  // XXX hook for sysroot
Packit Service 97d2fb
			  mod = __libdwfl_report_elf (dwfl, basename (name),
Packit Service 97d2fb
						      name, fd, elf, base,
Packit Service 97d2fb
						      true, true);
Packit Service 97d2fb
			  if (mod != NULL)
Packit Service 97d2fb
			    {
Packit Service 97d2fb
			      elf = NULL;
Packit Service 97d2fb
			      fd = -1;
Packit Service 97d2fb
			    }
Packit Service 97d2fb
			}
Packit Service 97d2fb
		      else if (__libdwfl_elf_address_range (elf, base, true,
Packit Service 97d2fb
							    true, NULL, NULL,
Packit Service 97d2fb
						    &r_debug_info_module->start,
Packit Service 97d2fb
						    &r_debug_info_module->end,
Packit Service 97d2fb
							    NULL, NULL))
Packit Service 97d2fb
			{
Packit Service 97d2fb
			  r_debug_info_module->elf = elf;
Packit Service 97d2fb
			  r_debug_info_module->fd = fd;
Packit Service 97d2fb
			  elf = NULL;
Packit Service 97d2fb
			  fd = -1;
Packit Service 97d2fb
			}
Packit Service 97d2fb
		    }
Packit Service 97d2fb
		  if (elf != NULL)
Packit Service 97d2fb
		    elf_end (elf);
Packit Service 97d2fb
		  if (fd != -1)
Packit Service 97d2fb
		    close (fd);
Packit Service 97d2fb
		}
Packit Service 97d2fb
	    }
Packit Service 97d2fb
	}
Packit Service 97d2fb
Packit Service 97d2fb
      if (mod != NULL)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  ++result;
Packit Service 97d2fb
Packit Service 97d2fb
	  /* Move this module to the end of the list, so that we end
Packit Service 97d2fb
	     up with a list in the same order as the link_map chain.  */
Packit Service 97d2fb
	  if (mod->next != NULL)
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      if (*lastmodp != mod)
Packit Service 97d2fb
		{
Packit Service 97d2fb
		  lastmodp = &dwfl->modulelist;
Packit Service 97d2fb
		  while (*lastmodp != mod)
Packit Service 97d2fb
		    lastmodp = &(*lastmodp)->next;
Packit Service 97d2fb
		}
Packit Service 97d2fb
	      *lastmodp = mod->next;
Packit Service 97d2fb
	      mod->next = NULL;
Packit Service 97d2fb
	      while (*lastmodp != NULL)
Packit Service 97d2fb
		lastmodp = &(*lastmodp)->next;
Packit Service 97d2fb
	      *lastmodp = mod;
Packit Service 97d2fb
	    }
Packit Service 97d2fb
Packit Service 97d2fb
	  lastmodp = &mod->next;
Packit Service 97d2fb
	}
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  return release_buffer (result);
Packit Service 97d2fb
}
Packit Service 97d2fb

Packit Service 97d2fb
static GElf_Addr
Packit Service 97d2fb
consider_executable (Dwfl_Module *mod, GElf_Addr at_phdr, GElf_Addr at_entry,
Packit Service 97d2fb
		     uint_fast8_t *elfclass, uint_fast8_t *elfdata,
Packit Service 97d2fb
		     Dwfl_Memory_Callback *memory_callback,
Packit Service 97d2fb
		     void *memory_callback_arg)
Packit Service 97d2fb
{
Packit Service 97d2fb
  GElf_Ehdr ehdr;
Packit Service 97d2fb
  if (unlikely (gelf_getehdr (mod->main.elf, &ehdr) == NULL))
Packit Service 97d2fb
    return 0;
Packit Service 97d2fb
Packit Service 97d2fb
  if (at_entry != 0)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      /* If we have an AT_ENTRY value, reject this executable if
Packit Service 97d2fb
	 its entry point address could not have supplied that.  */
Packit Service 97d2fb
Packit Service 97d2fb
      if (ehdr.e_entry == 0)
Packit Service 97d2fb
	return 0;
Packit Service 97d2fb
Packit Service 97d2fb
      if (mod->e_type == ET_EXEC)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  if (ehdr.e_entry != at_entry)
Packit Service 97d2fb
	    return 0;
Packit Service 97d2fb
	}
Packit Service 97d2fb
      else
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  /* It could be a PIE.  */
Packit Service 97d2fb
	}
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  // XXX this could be saved in the file cache: phdr vaddr, DT_DEBUG d_val vaddr
Packit Service 97d2fb
  /* Find the vaddr of the DT_DEBUG's d_ptr.  This is the memory
Packit Service 97d2fb
     address where &r_debug was written at runtime.  */
Packit Service 97d2fb
  GElf_Xword align = mod->dwfl->segment_align;
Packit Service 97d2fb
  GElf_Addr d_val_vaddr = 0;
Packit Service 97d2fb
  size_t phnum;
Packit Service 97d2fb
  if (elf_getphdrnum (mod->main.elf, &phnum) != 0)
Packit Service 97d2fb
    return 0;
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_align > 1 && (align == 0 || phdr->p_align < align))
Packit Service 97d2fb
	align = phdr->p_align;
Packit Service 97d2fb
Packit Service 97d2fb
      if (at_phdr != 0
Packit Service 97d2fb
	  && phdr->p_type == PT_LOAD
Packit Service 97d2fb
	  && (phdr->p_offset & -align) == (ehdr.e_phoff & -align))
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  /* This is the segment that would map the phdrs.
Packit Service 97d2fb
	     If we have an AT_PHDR value, reject this executable
Packit Service 97d2fb
	     if its phdr mapping could not have supplied that.  */
Packit Service 97d2fb
	  if (mod->e_type == ET_EXEC)
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      if (ehdr.e_phoff - phdr->p_offset + phdr->p_vaddr != at_phdr)
Packit Service 97d2fb
		return 0;
Packit Service 97d2fb
	    }
Packit Service 97d2fb
	  else
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      /* It could be a PIE.  If the AT_PHDR value and our
Packit Service 97d2fb
		 phdr address don't match modulo ALIGN, then this
Packit Service 97d2fb
		 could not have been the right PIE.  */
Packit Service 97d2fb
	      if (((ehdr.e_phoff - phdr->p_offset + phdr->p_vaddr) & -align)
Packit Service 97d2fb
		  != (at_phdr & -align))
Packit Service 97d2fb
		return 0;
Packit Service 97d2fb
Packit Service 97d2fb
	      /* Calculate the bias applied to the PIE's p_vaddr values.  */
Packit Service 97d2fb
	      GElf_Addr bias = (at_phdr - (ehdr.e_phoff - phdr->p_offset
Packit Service 97d2fb
					   + phdr->p_vaddr));
Packit Service 97d2fb
Packit Service 97d2fb
	      /* Final sanity check: if we have an AT_ENTRY value,
Packit Service 97d2fb
		 reject this PIE unless its biased e_entry matches.  */
Packit Service 97d2fb
	      if (at_entry != 0 && at_entry != ehdr.e_entry + bias)
Packit Service 97d2fb
		return 0;
Packit Service 97d2fb
Packit Service 97d2fb
	      /* If we're changing the module's address range,
Packit Service 97d2fb
		 we've just invalidated the module lookup table.  */
Packit Service 97d2fb
	      GElf_Addr mod_bias = dwfl_adjusted_address (mod, 0);
Packit Service 97d2fb
	      if (bias != mod_bias)
Packit Service 97d2fb
		{
Packit Service 97d2fb
		  mod->low_addr -= mod_bias;
Packit Service 97d2fb
		  mod->high_addr -= mod_bias;
Packit Service 97d2fb
		  mod->low_addr += bias;
Packit Service 97d2fb
		  mod->high_addr += bias;
Packit Service 97d2fb
Packit Service 97d2fb
		  free (mod->dwfl->lookup_module);
Packit Service 97d2fb
		  mod->dwfl->lookup_module = NULL;
Packit Service 97d2fb
		}
Packit Service 97d2fb
	    }
Packit Service 97d2fb
	}
Packit Service 97d2fb
Packit Service 97d2fb
      if (phdr->p_type == PT_DYNAMIC)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  Elf_Data *data = elf_getdata_rawchunk (mod->main.elf, phdr->p_offset,
Packit Service 97d2fb
						 phdr->p_filesz, ELF_T_DYN);
Packit Service 97d2fb
	  if (data == NULL)
Packit Service 97d2fb
	    continue;
Packit Service 97d2fb
	  const size_t entsize = gelf_fsize (mod->main.elf,
Packit Service 97d2fb
					     ELF_T_DYN, 1, EV_CURRENT);
Packit Service 97d2fb
	  const size_t n = data->d_size / entsize;
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 && dyn->d_tag == DT_DEBUG)
Packit Service 97d2fb
		{
Packit Service 97d2fb
		  d_val_vaddr = phdr->p_vaddr + entsize * j + entsize / 2;
Packit Service 97d2fb
		  break;
Packit Service 97d2fb
		}
Packit Service 97d2fb
	    }
Packit Service 97d2fb
	}
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  if (d_val_vaddr != 0)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      /* Now we have the final address from which to read &r_debug.  */
Packit Service 97d2fb
      d_val_vaddr = dwfl_adjusted_address (mod, d_val_vaddr);
Packit Service 97d2fb
Packit Service 97d2fb
      void *buffer = NULL;
Packit Service 97d2fb
      size_t buffer_available = addrsize (ehdr.e_ident[EI_CLASS]);
Packit Service 97d2fb
Packit Service 97d2fb
      int segndx = INTUSE(dwfl_addrsegment) (mod->dwfl, d_val_vaddr, NULL);
Packit Service 97d2fb
Packit Service 97d2fb
      if ((*memory_callback) (mod->dwfl, segndx,
Packit Service 97d2fb
			      &buffer, &buffer_available,
Packit Service 97d2fb
			      d_val_vaddr, buffer_available,
Packit Service 97d2fb
			      memory_callback_arg))
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  const union
Packit Service 97d2fb
	  {
Packit Service 97d2fb
	    Elf32_Addr a32;
Packit Service 97d2fb
	    Elf64_Addr a64;
Packit Service 97d2fb
	  } *u = buffer;
Packit Service 97d2fb
Packit Service 97d2fb
	  GElf_Addr vaddr;
Packit Service 97d2fb
	  if (ehdr.e_ident[EI_CLASS] == ELFCLASS32)
Packit Service 97d2fb
	    vaddr = (ehdr.e_ident[EI_DATA] == ELFDATA2MSB
Packit Service 97d2fb
		     ? BE32 (u->a32) : LE32 (u->a32));
Packit Service 97d2fb
	  else
Packit Service 97d2fb
	    vaddr = (ehdr.e_ident[EI_DATA] == ELFDATA2MSB
Packit Service 97d2fb
		     ? BE64 (u->a64) : LE64 (u->a64));
Packit Service 97d2fb
Packit Service 97d2fb
	  (*memory_callback) (mod->dwfl, -1, &buffer, &buffer_available, 0, 0,
Packit Service 97d2fb
			      memory_callback_arg);
Packit Service 97d2fb
Packit Service 97d2fb
	  if (*elfclass == ELFCLASSNONE)
Packit Service 97d2fb
	    *elfclass = ehdr.e_ident[EI_CLASS];
Packit Service 97d2fb
	  else if (*elfclass != ehdr.e_ident[EI_CLASS])
Packit Service 97d2fb
	    return 0;
Packit Service 97d2fb
Packit Service 97d2fb
	  if (*elfdata == ELFDATANONE)
Packit Service 97d2fb
	    *elfdata = ehdr.e_ident[EI_DATA];
Packit Service 97d2fb
	  else if (*elfdata != ehdr.e_ident[EI_DATA])
Packit Service 97d2fb
	    return 0;
Packit Service 97d2fb
Packit Service 97d2fb
	  return vaddr;
Packit Service 97d2fb
	}
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  return 0;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
/* Try to find an existing executable module with a DT_DEBUG.  */
Packit Service 97d2fb
static GElf_Addr
Packit Service 97d2fb
find_executable (Dwfl *dwfl, GElf_Addr at_phdr, GElf_Addr at_entry,
Packit Service 97d2fb
		 uint_fast8_t *elfclass, uint_fast8_t *elfdata,
Packit Service 97d2fb
		 Dwfl_Memory_Callback *memory_callback,
Packit Service 97d2fb
		 void *memory_callback_arg)
Packit Service 97d2fb
{
Packit Service 97d2fb
  for (Dwfl_Module *mod = dwfl->modulelist; mod != NULL; mod = mod->next)
Packit Service 97d2fb
    if (mod->main.elf != NULL)
Packit Service 97d2fb
      {
Packit Service 97d2fb
	GElf_Addr r_debug_vaddr = consider_executable (mod, at_phdr, at_entry,
Packit Service 97d2fb
						       elfclass, elfdata,
Packit Service 97d2fb
						       memory_callback,
Packit Service 97d2fb
						       memory_callback_arg);
Packit Service 97d2fb
	if (r_debug_vaddr != 0)
Packit Service 97d2fb
	  return r_debug_vaddr;
Packit Service 97d2fb
      }
Packit Service 97d2fb
Packit Service 97d2fb
  return 0;
Packit Service 97d2fb
}
Packit Service 97d2fb

Packit Service 97d2fb
Packit Service 97d2fb
int
Packit Service 97d2fb
dwfl_link_map_report (Dwfl *dwfl, const void *auxv, size_t auxv_size,
Packit Service 97d2fb
		      Dwfl_Memory_Callback *memory_callback,
Packit Service 97d2fb
		      void *memory_callback_arg,
Packit Service 97d2fb
		      struct r_debug_info *r_debug_info)
Packit Service 97d2fb
{
Packit Service 97d2fb
  GElf_Addr r_debug_vaddr = 0;
Packit Service 97d2fb
Packit Service 97d2fb
  uint_fast8_t elfclass = ELFCLASSNONE;
Packit Service 97d2fb
  uint_fast8_t elfdata = ELFDATANONE;
Packit Service 97d2fb
  if (likely (auxv != NULL)
Packit Service 97d2fb
      && likely (auxv_format_probe (auxv, auxv_size, &elfclass, &elfdata)))
Packit Service 97d2fb
    {
Packit Service 97d2fb
      GElf_Addr entry = 0;
Packit Service 97d2fb
      GElf_Addr phdr = 0;
Packit Service 97d2fb
      GElf_Xword phent = 0;
Packit Service 97d2fb
      GElf_Xword phnum = 0;
Packit Service 97d2fb
Packit Service 97d2fb
#define READ_AUXV32(ptr)	read_4ubyte_unaligned_noncvt (ptr)
Packit Service 97d2fb
#define READ_AUXV64(ptr)	read_8ubyte_unaligned_noncvt (ptr)
Packit Service 97d2fb
#define AUXV_SCAN(NN, BL) do                                            \
Packit Service 97d2fb
	{                                                               \
Packit Service 97d2fb
	  const Elf##NN##_auxv_t *av = auxv;                            \
Packit Service 97d2fb
	  for (size_t i = 0; i < auxv_size / sizeof av[0]; ++i)         \
Packit Service 97d2fb
	    {                                                           \
Packit Service 97d2fb
	      const char *typep = auxv + i * sizeof (Elf##NN##_auxv_t); \
Packit Service 97d2fb
	      typep += offsetof (Elf##NN##_auxv_t, a_type);             \
Packit Service 97d2fb
	      uint##NN##_t type = READ_AUXV##NN (typep);                \
Packit Service 97d2fb
	      const char *valp = auxv + i * sizeof (Elf##NN##_auxv_t);  \
Packit Service 97d2fb
	      valp += offsetof (Elf##NN##_auxv_t, a_un.a_val);          \
Packit Service 97d2fb
	      uint##NN##_t val = BL##NN (READ_AUXV##NN (valp));         \
Packit Service 97d2fb
	      if (type == BL##NN (AT_ENTRY))                            \
Packit Service 97d2fb
		entry = val;                                            \
Packit Service 97d2fb
	      else if (type == BL##NN (AT_PHDR))                        \
Packit Service 97d2fb
		phdr = val;                                             \
Packit Service 97d2fb
	      else if (type == BL##NN (AT_PHNUM))                       \
Packit Service 97d2fb
		phnum = val;                                            \
Packit Service 97d2fb
	      else if (type == BL##NN (AT_PHENT))                       \
Packit Service 97d2fb
		phent = val;                                            \
Packit Service 97d2fb
	      else if (type == BL##NN (AT_PAGESZ))                      \
Packit Service 97d2fb
		{                                                       \
Packit Service 97d2fb
		  if (val > 1                                           \
Packit Service 97d2fb
		      && (dwfl->segment_align == 0                      \
Packit Service 97d2fb
			  || val < dwfl->segment_align))                \
Packit Service 97d2fb
		    dwfl->segment_align = val;                          \
Packit Service 97d2fb
		}                                                       \
Packit Service 97d2fb
	    }                                                           \
Packit Service 97d2fb
	}                                                               \
Packit Service 97d2fb
      while (0)
Packit Service 97d2fb
Packit Service 97d2fb
      if (elfclass == ELFCLASS32)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  if (elfdata == ELFDATA2MSB)
Packit Service 97d2fb
	    AUXV_SCAN (32, BE);
Packit Service 97d2fb
	  else
Packit Service 97d2fb
	    AUXV_SCAN (32, LE);
Packit Service 97d2fb
	}
Packit Service 97d2fb
      else
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  if (elfdata == ELFDATA2MSB)
Packit Service 97d2fb
	    AUXV_SCAN (64, BE);
Packit Service 97d2fb
	  else
Packit Service 97d2fb
	    AUXV_SCAN (64, LE);
Packit Service 97d2fb
	}
Packit Service 97d2fb
Packit Service 97d2fb
      /* If we found the phdr dimensions, search phdrs for PT_DYNAMIC.  */
Packit Service 97d2fb
      GElf_Addr dyn_vaddr = 0;
Packit Service 97d2fb
      GElf_Xword dyn_filesz = 0;
Packit Service 97d2fb
      GElf_Addr dyn_bias = (GElf_Addr) -1;
Packit Service 97d2fb
Packit Service 97d2fb
      inline bool consider_phdr (GElf_Word type,
Packit Service 97d2fb
				 GElf_Addr vaddr, GElf_Xword filesz)
Packit Service 97d2fb
      {
Packit Service 97d2fb
	switch (type)
Packit Service 97d2fb
	  {
Packit Service 97d2fb
	  case PT_PHDR:
Packit Service 97d2fb
	    if (dyn_bias == (GElf_Addr) -1
Packit Service 97d2fb
		/* Do a sanity check on the putative address.  */
Packit Service 97d2fb
		&& ((vaddr & (dwfl->segment_align - 1))
Packit Service 97d2fb
		    == (phdr & (dwfl->segment_align - 1))))
Packit Service 97d2fb
	      {
Packit Service 97d2fb
		dyn_bias = phdr - vaddr;
Packit Service 97d2fb
		return dyn_vaddr != 0;
Packit Service 97d2fb
	      }
Packit Service 97d2fb
	    break;
Packit Service 97d2fb
Packit Service 97d2fb
	  case PT_DYNAMIC:
Packit Service 97d2fb
	    dyn_vaddr = vaddr;
Packit Service 97d2fb
	    dyn_filesz = filesz;
Packit Service 97d2fb
	    return dyn_bias != (GElf_Addr) -1;
Packit Service 97d2fb
	  }
Packit Service 97d2fb
Packit Service 97d2fb
	return false;
Packit Service 97d2fb
      }
Packit Service 97d2fb
Packit Service 97d2fb
      if (phdr != 0 && phnum != 0)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  Dwfl_Module *phdr_mod;
Packit Service 97d2fb
	  int phdr_segndx = INTUSE(dwfl_addrsegment) (dwfl, phdr, &phdr_mod);
Packit Service 97d2fb
	  Elf_Data in =
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      .d_type = ELF_T_PHDR,
Packit Service 97d2fb
	      .d_version = EV_CURRENT,
Packit Service 97d2fb
	      .d_size = phnum * phent,
Packit Service 97d2fb
	      .d_buf = NULL
Packit Service 97d2fb
	    };
Packit Service 97d2fb
	  bool in_ok = (*memory_callback) (dwfl, phdr_segndx, &in.d_buf,
Packit Service 97d2fb
					   &in.d_size, phdr, phnum * phent,
Packit Service 97d2fb
					   memory_callback_arg);
Packit Service 97d2fb
	  bool in_from_exec = false;
Packit Service 97d2fb
	  if (! in_ok
Packit Service 97d2fb
	      && dwfl->user_core != NULL
Packit Service 97d2fb
	      && dwfl->user_core->executable_for_core != NULL)
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      /* AUXV -> PHDR -> DYNAMIC
Packit Service 97d2fb
		 Both AUXV and DYNAMIC should be always present in a core file.
Packit Service 97d2fb
		 PHDR may be missing in core file, try to read it from
Packit Service 97d2fb
		 EXECUTABLE_FOR_CORE to find where DYNAMIC is located in the
Packit Service 97d2fb
		 core file.  */
Packit Service 97d2fb
Packit Service 97d2fb
	      int fd = open (dwfl->user_core->executable_for_core, O_RDONLY);
Packit Service 97d2fb
	      Elf *elf;
Packit Service 97d2fb
	      Dwfl_Error error = DWFL_E_ERRNO;
Packit Service 97d2fb
	      if (fd != -1)
Packit Service 97d2fb
		error = __libdw_open_file (&fd, &elf, true, false);
Packit Service 97d2fb
	      if (error != DWFL_E_NOERROR)
Packit Service 97d2fb
		{
Packit Service 97d2fb
		  __libdwfl_seterrno (error);
Packit Service 97d2fb
		  return false;
Packit Service 97d2fb
		}
Packit Service 97d2fb
	      GElf_Ehdr ehdr_mem, *ehdr = gelf_getehdr (elf, &ehdr_mem);
Packit Service 97d2fb
	      if (ehdr == NULL)
Packit Service 97d2fb
		{
Packit Service 97d2fb
		  elf_end (elf);
Packit Service 97d2fb
		  close (fd);
Packit Service 97d2fb
		  __libdwfl_seterrno (DWFL_E_LIBELF);
Packit Service 97d2fb
		  return false;
Packit Service 97d2fb
		}
Packit Service 97d2fb
	      size_t e_phnum;
Packit Service 97d2fb
	      if (elf_getphdrnum (elf, &e_phnum) != 0)
Packit Service 97d2fb
		{
Packit Service 97d2fb
		  elf_end (elf);
Packit Service 97d2fb
		  close (fd);
Packit Service 97d2fb
		  __libdwfl_seterrno (DWFL_E_LIBELF);
Packit Service 97d2fb
		  return false;
Packit Service 97d2fb
		}
Packit Service 97d2fb
	      if (e_phnum != phnum || ehdr->e_phentsize != phent)
Packit Service 97d2fb
		{
Packit Service 97d2fb
		  elf_end (elf);
Packit Service 97d2fb
		  close (fd);
Packit Service 97d2fb
		  __libdwfl_seterrno (DWFL_E_BADELF);
Packit Service 97d2fb
		  return false;
Packit Service 97d2fb
		}
Packit Service 97d2fb
	      off_t off = ehdr->e_phoff;
Packit Service 97d2fb
	      assert (in.d_buf == NULL);
Packit Service 97d2fb
	      /* Note this in the !in_ok path.  That means memory_callback
Packit Service 97d2fb
		 failed.  But the callback might still have reset the d_size
Packit Service 97d2fb
		 value (to zero).  So explicitly set it here again.  */
Packit Service 97d2fb
	      in.d_size = phnum * phent;
Packit Service 97d2fb
	      in.d_buf = malloc (in.d_size);
Packit Service 97d2fb
	      if (unlikely (in.d_buf == NULL))
Packit Service 97d2fb
		{
Packit Service 97d2fb
		  elf_end (elf);
Packit Service 97d2fb
		  close (fd);
Packit Service 97d2fb
		  __libdwfl_seterrno (DWFL_E_NOMEM);
Packit Service 97d2fb
		  return false;
Packit Service 97d2fb
		}
Packit Service 97d2fb
	      ssize_t nread = pread_retry (fd, in.d_buf, in.d_size, off);
Packit Service 97d2fb
	      elf_end (elf);
Packit Service 97d2fb
	      close (fd);
Packit Service 97d2fb
	      if (nread != (ssize_t) in.d_size)
Packit Service 97d2fb
		{
Packit Service 97d2fb
		  free (in.d_buf);
Packit Service 97d2fb
		  __libdwfl_seterrno (DWFL_E_ERRNO);
Packit Service 97d2fb
		  return false;
Packit Service 97d2fb
		}
Packit Service 97d2fb
	      in_ok = true;
Packit Service 97d2fb
	      in_from_exec = true;
Packit Service 97d2fb
	    }
Packit Service 97d2fb
	  if (in_ok)
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      if (unlikely (phnum > SIZE_MAX / phent))
Packit Service 97d2fb
		{
Packit Service 97d2fb
		  __libdwfl_seterrno (DWFL_E_NOMEM);
Packit Service 97d2fb
		  return false;
Packit Service 97d2fb
		}
Packit Service 97d2fb
	      size_t nbytes = phnum * phent;
Packit Service 97d2fb
	      void *buf = malloc (nbytes);
Packit Service 97d2fb
	      Elf32_Phdr (*p32)[phnum] = buf;
Packit Service 97d2fb
	      Elf64_Phdr (*p64)[phnum] = buf;
Packit Service 97d2fb
	      if (unlikely (buf == NULL))
Packit Service 97d2fb
		{
Packit Service 97d2fb
		  __libdwfl_seterrno (DWFL_E_NOMEM);
Packit Service 97d2fb
		  return false;
Packit Service 97d2fb
		}
Packit Service 97d2fb
	      Elf_Data out =
Packit Service 97d2fb
		{
Packit Service 97d2fb
		  .d_type = ELF_T_PHDR,
Packit Service 97d2fb
		  .d_version = EV_CURRENT,
Packit Service 97d2fb
		  .d_size = phnum * phent,
Packit Service 97d2fb
		  .d_buf = buf
Packit Service 97d2fb
		};
Packit Service 97d2fb
	      in.d_size = out.d_size;
Packit Service 97d2fb
	      if (likely ((elfclass == ELFCLASS32
Packit Service 97d2fb
			   ? elf32_xlatetom : elf64_xlatetom)
Packit Service 97d2fb
			  (&out, &in, elfdata) != NULL))
Packit Service 97d2fb
		{
Packit Service 97d2fb
		  /* We are looking for PT_DYNAMIC.  */
Packit Service 97d2fb
		  if (elfclass == ELFCLASS32)
Packit Service 97d2fb
		    {
Packit Service 97d2fb
		      for (size_t i = 0; i < phnum; ++i)
Packit Service 97d2fb
			if (consider_phdr ((*p32)[i].p_type,
Packit Service 97d2fb
					   (*p32)[i].p_vaddr,
Packit Service 97d2fb
					   (*p32)[i].p_filesz))
Packit Service 97d2fb
			  break;
Packit Service 97d2fb
		    }
Packit Service 97d2fb
		  else
Packit Service 97d2fb
		    {
Packit Service 97d2fb
		      for (size_t i = 0; i < phnum; ++i)
Packit Service 97d2fb
			if (consider_phdr ((*p64)[i].p_type,
Packit Service 97d2fb
					   (*p64)[i].p_vaddr,
Packit Service 97d2fb
					   (*p64)[i].p_filesz))
Packit Service 97d2fb
			  break;
Packit Service 97d2fb
		    }
Packit Service 97d2fb
		}
Packit Service 97d2fb
Packit Service 97d2fb
	      if (in_from_exec)
Packit Service 97d2fb
		free (in.d_buf);
Packit Service 97d2fb
	      else
Packit Service 97d2fb
		(*memory_callback) (dwfl, -1, &in.d_buf, &in.d_size, 0, 0,
Packit Service 97d2fb
				    memory_callback_arg);
Packit Service 97d2fb
	      free (buf);
Packit Service 97d2fb
	    }
Packit Service 97d2fb
	  else
Packit Service 97d2fb
	    /* We could not read the executable's phdrs from the
Packit Service 97d2fb
	       memory image.  If we have a presupplied executable,
Packit Service 97d2fb
	       we can still use the AT_PHDR and AT_ENTRY values to
Packit Service 97d2fb
	       verify it, and to adjust its bias if it's a PIE.
Packit Service 97d2fb
Packit Service 97d2fb
	       If there was an ET_EXEC module presupplied that contains
Packit Service 97d2fb
	       the AT_PHDR address, then we only consider that one.
Packit Service 97d2fb
	       We'll either accept it if its phdr location and e_entry
Packit Service 97d2fb
	       make sense or reject it if they don't.  If there is no
Packit Service 97d2fb
	       presupplied ET_EXEC, then look for a presupplied module,
Packit Service 97d2fb
	       which might be a PIE (ET_DYN) that needs its bias adjusted.  */
Packit Service 97d2fb
	    r_debug_vaddr = ((phdr_mod == NULL
Packit Service 97d2fb
			      || phdr_mod->main.elf == NULL
Packit Service 97d2fb
			      || phdr_mod->e_type != ET_EXEC)
Packit Service 97d2fb
			     ? find_executable (dwfl, phdr, entry,
Packit Service 97d2fb
						&elfclass, &elfdata,
Packit Service 97d2fb
						memory_callback,
Packit Service 97d2fb
						memory_callback_arg)
Packit Service 97d2fb
			     : consider_executable (phdr_mod, phdr, entry,
Packit Service 97d2fb
						    &elfclass, &elfdata,
Packit Service 97d2fb
						    memory_callback,
Packit Service 97d2fb
						    memory_callback_arg));
Packit Service 97d2fb
	}
Packit Service 97d2fb
Packit Service 97d2fb
      /* If we found PT_DYNAMIC, search it for DT_DEBUG.  */
Packit Service 97d2fb
      if (dyn_filesz != 0)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  if (dyn_bias != (GElf_Addr) -1)
Packit Service 97d2fb
	    dyn_vaddr += dyn_bias;
Packit Service 97d2fb
Packit Service 97d2fb
	  Elf_Data in =
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      .d_type = ELF_T_DYN,
Packit Service 97d2fb
	      .d_version = EV_CURRENT,
Packit Service 97d2fb
	      .d_size = dyn_filesz,
Packit Service 97d2fb
	      .d_buf = NULL
Packit Service 97d2fb
	    };
Packit Service 97d2fb
	  int dyn_segndx = dwfl_addrsegment (dwfl, dyn_vaddr, NULL);
Packit Service 97d2fb
	  if ((*memory_callback) (dwfl, dyn_segndx, &in.d_buf, &in.d_size,
Packit Service 97d2fb
				  dyn_vaddr, dyn_filesz, memory_callback_arg))
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      void *buf = malloc (dyn_filesz);
Packit Service 97d2fb
	      Elf32_Dyn (*d32)[dyn_filesz / sizeof (Elf32_Dyn)] = buf;
Packit Service 97d2fb
	      Elf64_Dyn (*d64)[dyn_filesz / sizeof (Elf64_Dyn)] = buf;
Packit Service 97d2fb
	      if (unlikely (buf == NULL))
Packit Service 97d2fb
		{
Packit Service 97d2fb
		  __libdwfl_seterrno (DWFL_E_NOMEM);
Packit Service 97d2fb
		  return false;
Packit Service 97d2fb
		}
Packit Service 97d2fb
	      Elf_Data out =
Packit Service 97d2fb
		{
Packit Service 97d2fb
		  .d_type = ELF_T_DYN,
Packit Service 97d2fb
		  .d_version = EV_CURRENT,
Packit Service 97d2fb
		  .d_size = dyn_filesz,
Packit Service 97d2fb
		  .d_buf = buf
Packit Service 97d2fb
		};
Packit Service 97d2fb
	      in.d_size = out.d_size;
Packit Service 97d2fb
	      if (likely ((elfclass == ELFCLASS32
Packit Service 97d2fb
			   ? elf32_xlatetom : elf64_xlatetom)
Packit Service 97d2fb
			  (&out, &in, elfdata) != NULL))
Packit Service 97d2fb
		{
Packit Service 97d2fb
		  /* We are looking for DT_DEBUG.  */
Packit Service 97d2fb
		  if (elfclass == ELFCLASS32)
Packit Service 97d2fb
		    {
Packit Service 97d2fb
		      size_t n = dyn_filesz / sizeof (Elf32_Dyn);
Packit Service 97d2fb
		      for (size_t i = 0; i < n; ++i)
Packit Service 97d2fb
			if ((*d32)[i].d_tag == DT_DEBUG)
Packit Service 97d2fb
			  {
Packit Service 97d2fb
			    r_debug_vaddr = (*d32)[i].d_un.d_val;
Packit Service 97d2fb
			    break;
Packit Service 97d2fb
			  }
Packit Service 97d2fb
		    }
Packit Service 97d2fb
		  else
Packit Service 97d2fb
		    {
Packit Service 97d2fb
		      size_t n = dyn_filesz / sizeof (Elf64_Dyn);
Packit Service 97d2fb
		      for (size_t i = 0; i < n; ++i)
Packit Service 97d2fb
			if ((*d64)[i].d_tag == DT_DEBUG)
Packit Service 97d2fb
			  {
Packit Service 97d2fb
			    r_debug_vaddr = (*d64)[i].d_un.d_val;
Packit Service 97d2fb
			    break;
Packit Service 97d2fb
			  }
Packit Service 97d2fb
		    }
Packit Service 97d2fb
		}
Packit Service 97d2fb
Packit Service 97d2fb
	      (*memory_callback) (dwfl, -1, &in.d_buf, &in.d_size, 0, 0,
Packit Service 97d2fb
				  memory_callback_arg);
Packit Service 97d2fb
	      free (buf);
Packit Service 97d2fb
	    }
Packit Service 97d2fb
	}
Packit Service 97d2fb
    }
Packit Service 97d2fb
  else
Packit Service 97d2fb
    /* We have to look for a presupplied executable file to determine
Packit Service 97d2fb
       the vaddr of its dynamic section and DT_DEBUG therein.  */
Packit Service 97d2fb
    r_debug_vaddr = find_executable (dwfl, 0, 0, &elfclass, &elfdata,
Packit Service 97d2fb
				     memory_callback, memory_callback_arg);
Packit Service 97d2fb
Packit Service 97d2fb
  if (r_debug_vaddr == 0)
Packit Service 97d2fb
    return 0;
Packit Service 97d2fb
Packit Service 97d2fb
  /* For following pointers from struct link_map, we will use an
Packit Service 97d2fb
     integrated memory access callback that can consult module text
Packit Service 97d2fb
     elided from the core file.  This is necessary when the l_name
Packit Service 97d2fb
     pointer for the dynamic linker's own entry is a pointer into the
Packit Service 97d2fb
     executable's .interp section.  */
Packit Service 97d2fb
  struct integrated_memory_callback mcb =
Packit Service 97d2fb
    {
Packit Service 97d2fb
      .memory_callback = memory_callback,
Packit Service 97d2fb
      .memory_callback_arg = memory_callback_arg
Packit Service 97d2fb
    };
Packit Service 97d2fb
Packit Service 97d2fb
  /* Now we can follow the dynamic linker's library list.  */
Packit Service 97d2fb
  return report_r_debug (elfclass, elfdata, dwfl, r_debug_vaddr,
Packit Service 97d2fb
			 &integrated_memory_callback, &mcb, r_debug_info);
Packit Service 97d2fb
}
Packit Service 97d2fb
INTDEF (dwfl_link_map_report)