Blame libdwfl/link_map.c

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