Blame libdwfl/dwfl_segment_report_module.c

Packit Service 97d2fb
/* Sniff out modules from ELF headers visible in memory segments.
Packit Service 97d2fb
   Copyright (C) 2008-2012, 2014, 2015, 2018 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 "../libelf/libelfP.h"	/* For NOTE_ALIGN4 and NOTE_ALIGN8.  */
Packit Service 97d2fb
#undef	_
Packit Service 97d2fb
#include "libdwflP.h"
Packit Service 97d2fb
#include "common.h"
Packit Service 97d2fb
Packit Service 97d2fb
#include <elf.h>
Packit Service 97d2fb
#include <gelf.h>
Packit Service 97d2fb
#include <inttypes.h>
Packit Service 97d2fb
#include <endian.h>
Packit Service 97d2fb
#include <unistd.h>
Packit Service 97d2fb
#include <fcntl.h>
Packit Service 97d2fb
Packit Service 97d2fb
#include <system.h>
Packit Service 97d2fb
Packit Service 97d2fb
Packit Service 97d2fb
/* A good size for the initial read from memory, if it's not too costly.
Packit Service 97d2fb
   This more than covers the phdrs and note segment in the average 64-bit
Packit Service 97d2fb
   binary.  */
Packit Service 97d2fb
Packit Service 97d2fb
#define INITIAL_READ	1024
Packit Service 97d2fb
Packit Service 97d2fb
#if __BYTE_ORDER == __LITTLE_ENDIAN
Packit Service 97d2fb
# define MY_ELFDATA	ELFDATA2LSB
Packit Service 97d2fb
#else
Packit Service 97d2fb
# define MY_ELFDATA	ELFDATA2MSB
Packit Service 97d2fb
#endif
Packit Service 97d2fb
Packit Service 97d2fb
Packit Service 97d2fb
/* Return user segment index closest to ADDR but not above it.
Packit Service 97d2fb
   If NEXT, return the closest to ADDR but not below it.  */
Packit Service 97d2fb
static int
Packit Service 97d2fb
addr_segndx (Dwfl *dwfl, size_t segment, GElf_Addr addr, bool next)
Packit Service 97d2fb
{
Packit Service 97d2fb
  int ndx = -1;
Packit Service 97d2fb
  do
Packit Service 97d2fb
    {
Packit Service 97d2fb
      if (dwfl->lookup_segndx[segment] >= 0)
Packit Service 97d2fb
	ndx = dwfl->lookup_segndx[segment];
Packit Service 97d2fb
      if (++segment >= dwfl->lookup_elts - 1)
Packit Service 97d2fb
	return next ? ndx + 1 : ndx;
Packit Service 97d2fb
    }
Packit Service 97d2fb
  while (dwfl->lookup_addr[segment] < addr);
Packit Service 97d2fb
Packit Service 97d2fb
  if (next)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      while (dwfl->lookup_segndx[segment] < 0)
Packit Service 97d2fb
	if (++segment >= dwfl->lookup_elts - 1)
Packit Service 97d2fb
	  return ndx + 1;
Packit Service 97d2fb
      ndx = dwfl->lookup_segndx[segment];
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  return ndx;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
/* Return whether there is SZ bytes available at PTR till END.  */
Packit Service 97d2fb
Packit Service 97d2fb
static bool
Packit Service 97d2fb
buf_has_data (const void *ptr, const void *end, size_t sz)
Packit Service 97d2fb
{
Packit Service 97d2fb
  return ptr < end && (size_t) (end - ptr) >= sz;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
/* Read SZ bytes into *RETP from *PTRP (limited by END) in format EI_DATA.
Packit Service 97d2fb
   Function comes from src/readelf.c .  */
Packit Service 97d2fb
Packit Service 97d2fb
static bool
Packit Service 97d2fb
buf_read_ulong (unsigned char ei_data, size_t sz,
Packit Service 97d2fb
		const void **ptrp, const void *end, uint64_t *retp)
Packit Service 97d2fb
{
Packit Service 97d2fb
  if (! buf_has_data (*ptrp, end, sz))
Packit Service 97d2fb
    return false;
Packit Service 97d2fb
Packit Service 97d2fb
  union
Packit Service 97d2fb
  {
Packit Service 97d2fb
    uint64_t u64;
Packit Service 97d2fb
    uint32_t u32;
Packit Service 97d2fb
  } u;
Packit Service 97d2fb
Packit Service 97d2fb
  memcpy (&u, *ptrp, sz);
Packit Service 97d2fb
  (*ptrp) += sz;
Packit Service 97d2fb
Packit Service 97d2fb
  if (retp == NULL)
Packit Service 97d2fb
    return true;
Packit Service 97d2fb
Packit Service 97d2fb
  if (MY_ELFDATA != ei_data)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      if (sz == 4)
Packit Service 97d2fb
	CONVERT (u.u32);
Packit Service 97d2fb
      else
Packit Service 97d2fb
	CONVERT (u.u64);
Packit Service 97d2fb
    }
Packit Service 97d2fb
  if (sz == 4)
Packit Service 97d2fb
    *retp = u.u32;
Packit Service 97d2fb
  else
Packit Service 97d2fb
    *retp = u.u64;
Packit Service 97d2fb
  return true;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
/* Try to find matching entry for module from address MODULE_START to
Packit Service 97d2fb
   MODULE_END in NT_FILE note located at NOTE_FILE of NOTE_FILE_SIZE
Packit Service 97d2fb
   bytes in format EI_CLASS and EI_DATA.  */
Packit Service 97d2fb
Packit Service 97d2fb
static const char *
Packit Service 97d2fb
handle_file_note (GElf_Addr module_start, GElf_Addr module_end,
Packit Service 97d2fb
		  unsigned char ei_class, unsigned char ei_data,
Packit Service 97d2fb
		  const void *note_file, size_t note_file_size)
Packit Service 97d2fb
{
Packit Service 97d2fb
  if (note_file == NULL)
Packit Service 97d2fb
    return NULL;
Packit Service 97d2fb
Packit Service 97d2fb
  size_t sz;
Packit Service 97d2fb
  switch (ei_class)
Packit Service 97d2fb
    {
Packit Service 97d2fb
    case ELFCLASS32:
Packit Service 97d2fb
      sz = 4;
Packit Service 97d2fb
      break;
Packit Service 97d2fb
    case ELFCLASS64:
Packit Service 97d2fb
      sz = 8;
Packit Service 97d2fb
      break;
Packit Service 97d2fb
    default:
Packit Service 97d2fb
      return NULL;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  const void *ptr = note_file;
Packit Service 97d2fb
  const void *end = note_file + note_file_size;
Packit Service 97d2fb
  uint64_t count;
Packit Service 97d2fb
  if (! buf_read_ulong (ei_data, sz, &ptr, end, &count))
Packit Service 97d2fb
    return NULL;
Packit Service 97d2fb
  if (! buf_read_ulong (ei_data, sz, &ptr, end, NULL)) // page_size
Packit Service 97d2fb
    return NULL;
Packit Service 97d2fb
Packit Service 97d2fb
  uint64_t maxcount = (size_t) (end - ptr) / (3 * sz);
Packit Service 97d2fb
  if (count > maxcount)
Packit Service 97d2fb
    return NULL;
Packit Service 97d2fb
Packit Service 97d2fb
  /* Where file names are stored.  */
Packit Service 97d2fb
  const char *fptr = ptr + 3 * count * sz;
Packit Service 97d2fb
Packit Service 97d2fb
  ssize_t firstix = -1;
Packit Service 97d2fb
  ssize_t lastix = -1;
Packit Service 97d2fb
  for (size_t mix = 0; mix < count; mix++)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      uint64_t mstart, mend, moffset;
Packit Service 97d2fb
      if (! buf_read_ulong (ei_data, sz, &ptr, fptr, &mstart)
Packit Service 97d2fb
	  || ! buf_read_ulong (ei_data, sz, &ptr, fptr, &mend)
Packit Service 97d2fb
	  || ! buf_read_ulong (ei_data, sz, &ptr, fptr, &moffset))
Packit Service 97d2fb
	return NULL;
Packit Service 97d2fb
      if (mstart == module_start && moffset == 0)
Packit Service 97d2fb
	firstix = lastix = mix;
Packit Service 97d2fb
      if (firstix != -1 && mstart < module_end)
Packit Service 97d2fb
	lastix = mix;
Packit Service 97d2fb
      if (mend >= module_end)
Packit Service 97d2fb
	break;
Packit Service 97d2fb
    }
Packit Service 97d2fb
  if (firstix == -1)
Packit Service 97d2fb
    return NULL;
Packit Service 97d2fb
Packit Service 97d2fb
  const char *retval = NULL;
Packit Service 97d2fb
  for (ssize_t mix = 0; mix <= lastix; mix++)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      const char *fnext = memchr (fptr, 0, (const char *) end - fptr);
Packit Service 97d2fb
      if (fnext == NULL)
Packit Service 97d2fb
	return NULL;
Packit Service 97d2fb
      if (mix == firstix)
Packit Service 97d2fb
	retval = fptr;
Packit Service 97d2fb
      if (firstix < mix && mix <= lastix && strcmp (fptr, retval) != 0)
Packit Service 97d2fb
	return NULL;
Packit Service 97d2fb
      fptr = fnext + 1;
Packit Service 97d2fb
    }
Packit Service 97d2fb
  return retval;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
/* Return true iff we are certain ELF cannot match BUILD_ID of
Packit Service 97d2fb
   BUILD_ID_LEN bytes.  Pass DISK_FILE_HAS_BUILD_ID as false if it is
Packit Service 97d2fb
   certain ELF does not contain build-id (it is only a performance hit
Packit Service 97d2fb
   to pass it always as true).  */
Packit Service 97d2fb
Packit Service 97d2fb
static bool
Packit Service 97d2fb
invalid_elf (Elf *elf, bool disk_file_has_build_id,
Packit Service 97d2fb
	     const void *build_id, size_t build_id_len)
Packit Service 97d2fb
{
Packit Service 97d2fb
  if (! disk_file_has_build_id && build_id_len > 0)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      /* Module found in segments with build-id is more reliable
Packit Service 97d2fb
	 than a module found via DT_DEBUG on disk without any
Packit Service 97d2fb
	 build-id.   */
Packit Service 97d2fb
      return true;
Packit Service 97d2fb
    }
Packit Service 97d2fb
  if (disk_file_has_build_id && build_id_len > 0)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      const void *elf_build_id;
Packit Service 97d2fb
      ssize_t elf_build_id_len;
Packit Service 97d2fb
Packit Service 97d2fb
      /* If there is a build id in the elf file, check it.  */
Packit Service 97d2fb
      elf_build_id_len = INTUSE(dwelf_elf_gnu_build_id) (elf, &elf_build_id);
Packit Service 97d2fb
      if (elf_build_id_len > 0)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  if (build_id_len != (size_t) elf_build_id_len
Packit Service 97d2fb
	      || memcmp (build_id, elf_build_id, build_id_len) != 0)
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
int
Packit Service 97d2fb
dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name,
Packit Service 97d2fb
			    Dwfl_Memory_Callback *memory_callback,
Packit Service 97d2fb
			    void *memory_callback_arg,
Packit Service 97d2fb
			    Dwfl_Module_Callback *read_eagerly,
Packit Service 97d2fb
			    void *read_eagerly_arg,
Packit Service 97d2fb
			    const void *note_file, size_t note_file_size,
Packit Service 97d2fb
			    const struct r_debug_info *r_debug_info)
Packit Service 97d2fb
{
Packit Service 97d2fb
  size_t segment = ndx;
Packit Service 97d2fb
Packit Service 97d2fb
  if (segment >= dwfl->lookup_elts)
Packit Service 97d2fb
    segment = dwfl->lookup_elts - 1;
Packit Service 97d2fb
Packit Service 97d2fb
  while (segment > 0
Packit Service 97d2fb
	 && (dwfl->lookup_segndx[segment] > ndx
Packit Service 97d2fb
	     || dwfl->lookup_segndx[segment] == -1))
Packit Service 97d2fb
    --segment;
Packit Service 97d2fb
Packit Service 97d2fb
  while (dwfl->lookup_segndx[segment] < ndx)
Packit Service 97d2fb
    if (++segment == dwfl->lookup_elts)
Packit Service 97d2fb
      return 0;
Packit Service 97d2fb
Packit Service 97d2fb
  GElf_Addr start = dwfl->lookup_addr[segment];
Packit Service 97d2fb
Packit Service 97d2fb
  inline bool segment_read (int segndx,
Packit Service 97d2fb
			    void **buffer, size_t *buffer_available,
Packit Service 97d2fb
			    GElf_Addr addr, size_t minread)
Packit Service 97d2fb
  {
Packit Service 97d2fb
    return ! (*memory_callback) (dwfl, segndx, buffer, buffer_available,
Packit Service 97d2fb
				 addr, minread, memory_callback_arg);
Packit Service 97d2fb
  }
Packit Service 97d2fb
Packit Service 97d2fb
  inline void release_buffer (void **buffer, size_t *buffer_available)
Packit Service 97d2fb
  {
Packit Service 97d2fb
    if (*buffer != NULL)
Packit Service 97d2fb
      (void) segment_read (-1, buffer, buffer_available, 0, 0);
Packit Service 97d2fb
  }
Packit Service 97d2fb
Packit Service 97d2fb
  /* First read in the file header and check its sanity.  */
Packit Service 97d2fb
Packit Service 97d2fb
  void *buffer = NULL;
Packit Service 97d2fb
  size_t buffer_available = INITIAL_READ;
Packit Service 97d2fb
  Elf *elf = NULL;
Packit Service 97d2fb
  int fd = -1;
Packit Service 97d2fb
Packit Service 97d2fb
  /* We might have to reserve some memory for the phdrs.  Set to NULL
Packit Service 97d2fb
     here so we can always safely free it.  */
Packit Service 97d2fb
  void *phdrsp = NULL;
Packit Service 97d2fb
Packit Service 97d2fb
  inline int finish (void)
Packit Service 97d2fb
  {
Packit Service 97d2fb
    free (phdrsp);
Packit Service 97d2fb
    release_buffer (&buffer, &buffer_available);
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
    return ndx;
Packit Service 97d2fb
  }
Packit Service 97d2fb
Packit Service 97d2fb
  if (segment_read (ndx, &buffer, &buffer_available,
Packit Service 97d2fb
		    start, sizeof (Elf64_Ehdr))
Packit Service 97d2fb
      || memcmp (buffer, ELFMAG, SELFMAG) != 0)
Packit Service 97d2fb
    return finish ();
Packit Service 97d2fb
Packit Service 97d2fb
  inline bool read_portion (void **data, size_t *data_size,
Packit Service 97d2fb
			    GElf_Addr vaddr, size_t filesz)
Packit Service 97d2fb
  {
Packit Service 97d2fb
    /* Check whether we will have to read the segment data, or if it
Packit Service 97d2fb
       can be returned from the existing buffer.  */
Packit Service 97d2fb
    if (filesz > buffer_available
Packit Service 97d2fb
	|| vaddr - start > buffer_available - filesz
Packit Service 97d2fb
	/* If we're in string mode, then don't consider the buffer we have
Packit Service 97d2fb
	   sufficient unless it contains the terminator of the string.  */
Packit Service 97d2fb
	|| (filesz == 0 && memchr (vaddr - start + buffer, '\0',
Packit Service 97d2fb
				   buffer_available - (vaddr - start)) == NULL))
Packit Service 97d2fb
      {
Packit Service 97d2fb
	*data = NULL;
Packit Service 97d2fb
	*data_size = filesz;
Packit Service 97d2fb
	return segment_read (addr_segndx (dwfl, segment, vaddr, false),
Packit Service 97d2fb
			     data, data_size, vaddr, filesz);
Packit Service 97d2fb
      }
Packit Service 97d2fb
Packit Service 97d2fb
    /* We already have this whole note segment from our initial read.  */
Packit Service 97d2fb
    *data = vaddr - start + buffer;
Packit Service 97d2fb
    *data_size = 0;
Packit Service 97d2fb
    return false;
Packit Service 97d2fb
  }
Packit Service 97d2fb
Packit Service 97d2fb
  inline void finish_portion (void **data, size_t *data_size)
Packit Service 97d2fb
  {
Packit Service 97d2fb
    if (*data_size != 0)
Packit Service 97d2fb
      release_buffer (data, data_size);
Packit Service 97d2fb
  }
Packit Service 97d2fb
Packit Service 97d2fb
  /* Extract the information we need from the file header.  */
Packit Service 97d2fb
  const unsigned char *e_ident;
Packit Service 97d2fb
  unsigned char ei_class;
Packit Service 97d2fb
  unsigned char ei_data;
Packit Service 97d2fb
  uint16_t e_type;
Packit Service 97d2fb
  union
Packit Service 97d2fb
  {
Packit Service 97d2fb
    Elf32_Ehdr e32;
Packit Service 97d2fb
    Elf64_Ehdr e64;
Packit Service 97d2fb
  } ehdr;
Packit Service 97d2fb
  GElf_Off phoff;
Packit Service 97d2fb
  uint_fast16_t phnum;
Packit Service 97d2fb
  uint_fast16_t phentsize;
Packit Service 97d2fb
  GElf_Off shdrs_end;
Packit Service 97d2fb
  Elf_Data xlatefrom =
Packit Service 97d2fb
    {
Packit Service 97d2fb
      .d_type = ELF_T_EHDR,
Packit Service 97d2fb
      .d_buf = (void *) buffer,
Packit Service 97d2fb
      .d_version = EV_CURRENT,
Packit Service 97d2fb
    };
Packit Service 97d2fb
  Elf_Data xlateto =
Packit Service 97d2fb
    {
Packit Service 97d2fb
      .d_type = ELF_T_EHDR,
Packit Service 97d2fb
      .d_buf = &ehdr,
Packit Service 97d2fb
      .d_size = sizeof ehdr,
Packit Service 97d2fb
      .d_version = EV_CURRENT,
Packit Service 97d2fb
    };
Packit Service 97d2fb
  e_ident = ((const unsigned char *) buffer);
Packit Service 97d2fb
  ei_class = e_ident[EI_CLASS];
Packit Service 97d2fb
  ei_data = e_ident[EI_DATA];
Packit Service 97d2fb
  switch (ei_class)
Packit Service 97d2fb
    {
Packit Service 97d2fb
    case ELFCLASS32:
Packit Service 97d2fb
      xlatefrom.d_size = sizeof (Elf32_Ehdr);
Packit Service 97d2fb
      if (elf32_xlatetom (&xlateto, &xlatefrom, ei_data) == NULL)
Packit Service 97d2fb
	return finish ();
Packit Service 97d2fb
      e_type = ehdr.e32.e_type;
Packit Service 97d2fb
      phoff = ehdr.e32.e_phoff;
Packit Service 97d2fb
      phnum = ehdr.e32.e_phnum;
Packit Service 97d2fb
      phentsize = ehdr.e32.e_phentsize;
Packit Service 97d2fb
      if (phentsize != sizeof (Elf32_Phdr))
Packit Service 97d2fb
	return finish ();
Packit Service 97d2fb
      /* NOTE if the number of sections is > 0xff00 then e_shnum
Packit Service 97d2fb
	 is zero and the actual number would come from the section
Packit Service 97d2fb
	 zero sh_size field. We ignore this here because getting shdrs
Packit Service 97d2fb
	 is just a nice bonus (see below in consider_phdr PT_LOAD
Packit Service 97d2fb
	 where we trim the last segment).  */
Packit Service 97d2fb
      shdrs_end = ehdr.e32.e_shoff + ehdr.e32.e_shnum * ehdr.e32.e_shentsize;
Packit Service 97d2fb
      break;
Packit Service 97d2fb
Packit Service 97d2fb
    case ELFCLASS64:
Packit Service 97d2fb
      xlatefrom.d_size = sizeof (Elf64_Ehdr);
Packit Service 97d2fb
      if (elf64_xlatetom (&xlateto, &xlatefrom, ei_data) == NULL)
Packit Service 97d2fb
	return finish ();
Packit Service 97d2fb
      e_type = ehdr.e64.e_type;
Packit Service 97d2fb
      phoff = ehdr.e64.e_phoff;
Packit Service 97d2fb
      phnum = ehdr.e64.e_phnum;
Packit Service 97d2fb
      phentsize = ehdr.e64.e_phentsize;
Packit Service 97d2fb
      if (phentsize != sizeof (Elf64_Phdr))
Packit Service 97d2fb
	return finish ();
Packit Service 97d2fb
      /* See the NOTE above for shdrs_end and ehdr.e32.e_shnum.  */
Packit Service 97d2fb
      shdrs_end = ehdr.e64.e_shoff + ehdr.e64.e_shnum * ehdr.e64.e_shentsize;
Packit Service 97d2fb
      break;
Packit Service 97d2fb
Packit Service 97d2fb
    default:
Packit Service 97d2fb
      return finish ();
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  /* The file header tells where to find the program headers.
Packit Service 97d2fb
     These are what we need to find the boundaries of the module.
Packit Service 97d2fb
     Without them, we don't have a module to report.  */
Packit Service 97d2fb
Packit Service 97d2fb
  if (phnum == 0)
Packit Service 97d2fb
    return finish ();
Packit Service 97d2fb
Packit Service 97d2fb
  xlatefrom.d_type = xlateto.d_type = ELF_T_PHDR;
Packit Service 97d2fb
  xlatefrom.d_size = phnum * phentsize;
Packit Service 97d2fb
Packit Service 97d2fb
  void *ph_buffer = NULL;
Packit Service 97d2fb
  size_t ph_buffer_size = 0;
Packit Service 97d2fb
  if (read_portion (&ph_buffer, &ph_buffer_size,
Packit Service 97d2fb
		    start + phoff, xlatefrom.d_size))
Packit Service 97d2fb
    return finish ();
Packit Service 97d2fb
Packit Service 97d2fb
  /* ph_buffer_size will be zero if we got everything from the initial
Packit Service 97d2fb
     buffer, otherwise it will be the size of the new buffer that
Packit Service 97d2fb
     could be read.  */
Packit Service 97d2fb
  if (ph_buffer_size != 0)
Packit Service 97d2fb
    xlatefrom.d_size = ph_buffer_size;
Packit Service 97d2fb
Packit Service 97d2fb
  xlatefrom.d_buf = ph_buffer;
Packit Service 97d2fb
Packit Service 97d2fb
  bool class32 = ei_class == ELFCLASS32;
Packit Service 97d2fb
  size_t phdr_size = class32 ? sizeof (Elf32_Phdr) : sizeof (Elf64_Phdr);
Packit Service 97d2fb
  if (unlikely (phnum > SIZE_MAX / phdr_size))
Packit Service 97d2fb
    return finish ();
Packit Service 97d2fb
  const size_t phdrsp_bytes = phnum * phdr_size;
Packit Service 97d2fb
  phdrsp = malloc (phdrsp_bytes);
Packit Service 97d2fb
  if (unlikely (phdrsp == NULL))
Packit Service 97d2fb
    return finish ();
Packit Service 97d2fb
Packit Service 97d2fb
  xlateto.d_buf = phdrsp;
Packit Service 97d2fb
  xlateto.d_size = phdrsp_bytes;
Packit Service 97d2fb
Packit Service 97d2fb
  /* Track the bounds of the file visible in memory.  */
Packit Service 97d2fb
  GElf_Off file_trimmed_end = 0; /* Proper p_vaddr + p_filesz end.  */
Packit Service 97d2fb
  GElf_Off file_end = 0;	 /* Rounded up to effective page size.  */
Packit Service 97d2fb
  GElf_Off contiguous = 0;	 /* Visible as contiguous file from START.  */
Packit Service 97d2fb
  GElf_Off total_filesz = 0;	 /* Total size of data to read.  */
Packit Service 97d2fb
Packit Service 97d2fb
  /* Collect the bias between START and the containing PT_LOAD's p_vaddr.  */
Packit Service 97d2fb
  GElf_Addr bias = 0;
Packit Service 97d2fb
  bool found_bias = false;
Packit Service 97d2fb
Packit Service 97d2fb
  /* Collect the unbiased bounds of the module here.  */
Packit Service 97d2fb
  GElf_Addr module_start = -1l;
Packit Service 97d2fb
  GElf_Addr module_end = 0;
Packit Service 97d2fb
  GElf_Addr module_address_sync = 0;
Packit Service 97d2fb
Packit Service 97d2fb
  /* If we see PT_DYNAMIC, record it here.  */
Packit Service 97d2fb
  GElf_Addr dyn_vaddr = 0;
Packit Service 97d2fb
  GElf_Xword dyn_filesz = 0;
Packit Service 97d2fb
Packit Service 97d2fb
  /* Collect the build ID bits here.  */
Packit Service 97d2fb
  void *build_id = NULL;
Packit Service 97d2fb
  size_t build_id_len = 0;
Packit Service 97d2fb
  GElf_Addr build_id_vaddr = 0;
Packit Service 97d2fb
Packit Service 97d2fb
  /* Consider a PT_NOTE we've found in the image.  */
Packit Service 97d2fb
  inline void consider_notes (GElf_Addr vaddr, GElf_Xword filesz,
Packit Service 97d2fb
			      GElf_Xword align)
Packit Service 97d2fb
  {
Packit Service 97d2fb
    /* If we have already seen a build ID, we don't care any more.  */
Packit Service 97d2fb
    if (build_id != NULL || filesz == 0)
Packit Service 97d2fb
      return;
Packit Service 97d2fb
Packit Service 97d2fb
    void *data;
Packit Service 97d2fb
    size_t data_size;
Packit Service 97d2fb
    if (read_portion (&data, &data_size, vaddr, filesz))
Packit Service 97d2fb
      return;
Packit Service 97d2fb
Packit Service 97d2fb
    /* data_size will be zero if we got everything from the initial
Packit Service 97d2fb
       buffer, otherwise it will be the size of the new buffer that
Packit Service 97d2fb
       could be read.  */
Packit Service 97d2fb
    if (data_size != 0)
Packit Service 97d2fb
      filesz = data_size;
Packit Service 97d2fb
Packit Service 97d2fb
    assert (sizeof (Elf32_Nhdr) == sizeof (Elf64_Nhdr));
Packit Service 97d2fb
Packit Service 97d2fb
    void *notes;
Packit Service 97d2fb
    if (ei_data == MY_ELFDATA)
Packit Service 97d2fb
      notes = data;
Packit Service 97d2fb
    else
Packit Service 97d2fb
      {
Packit Service 97d2fb
	notes = malloc (filesz);
Packit Service 97d2fb
	if (unlikely (notes == NULL))
Packit Service 97d2fb
	  return;
Packit Service 97d2fb
	xlatefrom.d_type = xlateto.d_type = (align == 8
Packit Service 97d2fb
					     ? ELF_T_NHDR8 : ELF_T_NHDR);
Packit Service 97d2fb
	xlatefrom.d_buf = (void *) data;
Packit Service 97d2fb
	xlatefrom.d_size = filesz;
Packit Service 97d2fb
	xlateto.d_buf = notes;
Packit Service 97d2fb
	xlateto.d_size = filesz;
Packit Service 97d2fb
	if (elf32_xlatetom (&xlateto, &xlatefrom,
Packit Service 97d2fb
			    ehdr.e32.e_ident[EI_DATA]) == NULL)
Packit Service 97d2fb
	  goto done;
Packit Service 97d2fb
      }
Packit Service 97d2fb
Packit Service 97d2fb
    const GElf_Nhdr *nh = notes;
Packit Service 97d2fb
    size_t len = 0;
Packit Service 97d2fb
    while (filesz > len + sizeof (*nh))
Packit Service 97d2fb
      {
Packit Service 97d2fb
	const void *note_name;
Packit Service 97d2fb
	const void *note_desc;
Packit Service 97d2fb
Packit Service 97d2fb
	len += sizeof (*nh);
Packit Service 97d2fb
	note_name = notes + len;
Packit Service 97d2fb
Packit Service 97d2fb
	len += nh->n_namesz;
Packit Service 97d2fb
	len = align == 8 ? NOTE_ALIGN8 (len) : NOTE_ALIGN4 (len);
Packit Service 97d2fb
	note_desc = notes + len;
Packit Service 97d2fb
Packit Service 97d2fb
	if (unlikely (filesz < len + nh->n_descsz))
Packit Service 97d2fb
	  break;
Packit Service 97d2fb
Packit Service 97d2fb
        if (nh->n_type == NT_GNU_BUILD_ID
Packit Service 97d2fb
	    && nh->n_descsz > 0
Packit Service 97d2fb
	    && nh->n_namesz == sizeof "GNU"
Packit Service 97d2fb
	    && !memcmp (note_name, "GNU", sizeof "GNU"))
Packit Service 97d2fb
	  {
Packit Service 97d2fb
	    build_id_vaddr = note_desc - (const void *) notes + vaddr;
Packit Service 97d2fb
	    build_id_len = nh->n_descsz;
Packit Service 97d2fb
	    build_id = malloc (nh->n_descsz);
Packit Service 97d2fb
	    if (likely (build_id != NULL))
Packit Service 97d2fb
	      memcpy (build_id, note_desc, build_id_len);
Packit Service 97d2fb
	    break;
Packit Service 97d2fb
	  }
Packit Service 97d2fb
Packit Service 97d2fb
	len += nh->n_descsz;
Packit Service 97d2fb
	len = align == 8 ? NOTE_ALIGN8 (len) : NOTE_ALIGN4 (len);
Packit Service 97d2fb
	nh = (void *) notes + len;
Packit Service 97d2fb
      }
Packit Service 97d2fb
Packit Service 97d2fb
  done:
Packit Service 97d2fb
    if (notes != data)
Packit Service 97d2fb
      free (notes);
Packit Service 97d2fb
    finish_portion (&data, &data_size);
Packit Service 97d2fb
  }
Packit Service 97d2fb
Packit Service 97d2fb
  /* Consider each of the program headers we've read from the image.  */
Packit Service 97d2fb
  inline void consider_phdr (GElf_Word type,
Packit Service 97d2fb
			     GElf_Addr vaddr, GElf_Xword memsz,
Packit Service 97d2fb
			     GElf_Off offset, GElf_Xword filesz,
Packit Service 97d2fb
			     GElf_Xword align)
Packit Service 97d2fb
  {
Packit Service 97d2fb
    switch (type)
Packit Service 97d2fb
      {
Packit Service 97d2fb
      case PT_DYNAMIC:
Packit Service 97d2fb
	dyn_vaddr = vaddr;
Packit Service 97d2fb
	dyn_filesz = filesz;
Packit Service 97d2fb
	break;
Packit Service 97d2fb
Packit Service 97d2fb
      case PT_NOTE:
Packit Service 97d2fb
	/* We calculate from the p_offset of the note segment,
Packit Service 97d2fb
	   because we don't yet know the bias for its p_vaddr.  */
Packit Service 97d2fb
	consider_notes (start + offset, filesz, align);
Packit Service 97d2fb
	break;
Packit Service 97d2fb
Packit Service 97d2fb
      case PT_LOAD:
Packit Service 97d2fb
	align = dwfl->segment_align > 1 ? dwfl->segment_align : align ?: 1;
Packit Service 97d2fb
Packit Service 97d2fb
	GElf_Addr vaddr_end = (vaddr + memsz + align - 1) & -align;
Packit Service 97d2fb
	GElf_Addr filesz_vaddr = filesz < memsz ? vaddr + filesz : vaddr_end;
Packit Service 97d2fb
	GElf_Off filesz_offset = filesz_vaddr - vaddr + offset;
Packit Service 97d2fb
Packit Service 97d2fb
	if (file_trimmed_end < offset + filesz)
Packit Service 97d2fb
	  {
Packit Service 97d2fb
	    file_trimmed_end = offset + filesz;
Packit Service 97d2fb
Packit Service 97d2fb
	    /* Trim the last segment so we don't bother with zeros
Packit Service 97d2fb
	       in the last page that are off the end of the file.
Packit Service 97d2fb
	       However, if the extra bit in that page includes the
Packit Service 97d2fb
	       section headers, keep them.  */
Packit Service 97d2fb
	    if (shdrs_end <= filesz_offset && shdrs_end > file_trimmed_end)
Packit Service 97d2fb
	      {
Packit Service 97d2fb
		filesz += shdrs_end - file_trimmed_end;
Packit Service 97d2fb
		file_trimmed_end = shdrs_end;
Packit Service 97d2fb
	      }
Packit Service 97d2fb
	  }
Packit Service 97d2fb
Packit Service 97d2fb
	total_filesz += filesz;
Packit Service 97d2fb
Packit Service 97d2fb
	if (file_end < filesz_offset)
Packit Service 97d2fb
	  {
Packit Service 97d2fb
	    file_end = filesz_offset;
Packit Service 97d2fb
	    if (filesz_vaddr - start == filesz_offset)
Packit Service 97d2fb
	      contiguous = file_end;
Packit Service 97d2fb
	  }
Packit Service 97d2fb
Packit Service 97d2fb
	if (!found_bias && (offset & -align) == 0
Packit Service 97d2fb
	    && likely (filesz_offset >= phoff + phnum * phentsize))
Packit Service 97d2fb
	  {
Packit Service 97d2fb
	    bias = start - vaddr;
Packit Service 97d2fb
	    found_bias = true;
Packit Service 97d2fb
	  }
Packit Service 97d2fb
Packit Service 97d2fb
	if ((vaddr & -align) < module_start)
Packit Service 97d2fb
	  {
Packit Service 97d2fb
	    module_start = vaddr & -align;
Packit Service 97d2fb
	    module_address_sync = vaddr + memsz;
Packit Service 97d2fb
	  }
Packit Service 97d2fb
Packit Service 97d2fb
	if (module_end < vaddr_end)
Packit Service 97d2fb
	  module_end = vaddr_end;
Packit Service 97d2fb
	break;
Packit Service 97d2fb
      }
Packit Service 97d2fb
  }
Packit Service 97d2fb
Packit Service 97d2fb
  Elf32_Phdr (*p32)[phnum] = phdrsp;
Packit Service 97d2fb
  Elf64_Phdr (*p64)[phnum] = phdrsp;
Packit Service 97d2fb
  if (ei_class == ELFCLASS32)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      if (elf32_xlatetom (&xlateto, &xlatefrom, ei_data) == NULL)
Packit Service 97d2fb
	found_bias = false;	/* Trigger error check.  */
Packit Service 97d2fb
      else
Packit Service 97d2fb
	for (uint_fast16_t i = 0; i < phnum; ++i)
Packit Service 97d2fb
	  consider_phdr ((*p32)[i].p_type,
Packit Service 97d2fb
			 (*p32)[i].p_vaddr, (*p32)[i].p_memsz,
Packit Service 97d2fb
			 (*p32)[i].p_offset, (*p32)[i].p_filesz,
Packit Service 97d2fb
			 (*p32)[i].p_align);
Packit Service 97d2fb
    }
Packit Service 97d2fb
  else
Packit Service 97d2fb
    {
Packit Service 97d2fb
      if (elf64_xlatetom (&xlateto, &xlatefrom, ei_data) == NULL)
Packit Service 97d2fb
	found_bias = false;	/* Trigger error check.  */
Packit Service 97d2fb
      else
Packit Service 97d2fb
	for (uint_fast16_t i = 0; i < phnum; ++i)
Packit Service 97d2fb
	  consider_phdr ((*p64)[i].p_type,
Packit Service 97d2fb
			 (*p64)[i].p_vaddr, (*p64)[i].p_memsz,
Packit Service 97d2fb
			 (*p64)[i].p_offset, (*p64)[i].p_filesz,
Packit Service 97d2fb
			 (*p64)[i].p_align);
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  finish_portion (&ph_buffer, &ph_buffer_size);
Packit Service 97d2fb
Packit Service 97d2fb
  /* We must have seen the segment covering offset 0, or else the ELF
Packit Service 97d2fb
     header we read at START was not produced by these program headers.  */
Packit Service 97d2fb
  if (unlikely (!found_bias))
Packit Service 97d2fb
    {
Packit Service 97d2fb
      free (build_id);
Packit Service 97d2fb
      return finish ();
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  /* Now we know enough to report a module for sure: its bounds.  */
Packit Service 97d2fb
  module_start += bias;
Packit Service 97d2fb
  module_end += bias;
Packit Service 97d2fb
Packit Service 97d2fb
  dyn_vaddr += bias;
Packit Service 97d2fb
Packit Service 97d2fb
  /* NAME found from link map has precedence over DT_SONAME possibly read
Packit Service 97d2fb
     below.  */
Packit Service 97d2fb
  bool name_is_final = false;
Packit Service 97d2fb
Packit Service 97d2fb
  /* Try to match up DYN_VADDR against L_LD as found in link map.
Packit Service 97d2fb
     Segments sniffing may guess invalid address as the first read-only memory
Packit Service 97d2fb
     mapping may not be dumped to the core file (if ELF headers are not dumped)
Packit Service 97d2fb
     and the ELF header is dumped first with the read/write mapping of the same
Packit Service 97d2fb
     file at higher addresses.  */
Packit Service 97d2fb
  if (r_debug_info != NULL)
Packit Service 97d2fb
    for (const struct r_debug_info_module *module = r_debug_info->module;
Packit Service 97d2fb
	 module != NULL; module = module->next)
Packit Service 97d2fb
      if (module_start <= module->l_ld && module->l_ld < module_end)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  /* L_LD read from link map must be right while DYN_VADDR is unsafe.
Packit Service 97d2fb
	     Therefore subtract DYN_VADDR and add L_LD to get a possibly
Packit Service 97d2fb
	     corrective displacement for all addresses computed so far.  */
Packit Service 97d2fb
	  GElf_Addr fixup = module->l_ld - dyn_vaddr;
Packit Service 97d2fb
	  if ((fixup & (dwfl->segment_align - 1)) == 0
Packit Service 97d2fb
	      && module_start + fixup <= module->l_ld
Packit Service 97d2fb
	      && module->l_ld < module_end + fixup)
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      module_start += fixup;
Packit Service 97d2fb
	      module_end += fixup;
Packit Service 97d2fb
	      dyn_vaddr += fixup;
Packit Service 97d2fb
	      bias += fixup;
Packit Service 97d2fb
	      if (module->name[0] != '\0')
Packit Service 97d2fb
		{
Packit Service 97d2fb
		  name = basename (module->name);
Packit Service 97d2fb
		  name_is_final = true;
Packit Service 97d2fb
		}
Packit Service 97d2fb
	      break;
Packit Service 97d2fb
	    }
Packit Service 97d2fb
	}
Packit Service 97d2fb
Packit Service 97d2fb
  if (r_debug_info != NULL)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      bool skip_this_module = false;
Packit Service 97d2fb
      for (struct r_debug_info_module *module = r_debug_info->module;
Packit Service 97d2fb
	   module != NULL; module = module->next)
Packit Service 97d2fb
	if ((module_end > module->start && module_start < module->end)
Packit Service 97d2fb
	    || dyn_vaddr == module->l_ld)
Packit Service 97d2fb
	  {
Packit Service 97d2fb
	    if (module->elf != NULL
Packit Service 97d2fb
	        && invalid_elf (module->elf, module->disk_file_has_build_id,
Packit Service 97d2fb
				build_id, build_id_len))
Packit Service 97d2fb
	      {
Packit Service 97d2fb
		elf_end (module->elf);
Packit Service 97d2fb
		close (module->fd);
Packit Service 97d2fb
		module->elf = NULL;
Packit Service 97d2fb
		module->fd = -1;
Packit Service 97d2fb
	      }
Packit Service 97d2fb
	    if (module->elf != NULL)
Packit Service 97d2fb
	      {
Packit Service 97d2fb
		/* Ignore this found module if it would conflict in address
Packit Service 97d2fb
		   space with any already existing module of DWFL.  */
Packit Service 97d2fb
		skip_this_module = true;
Packit Service 97d2fb
	      }
Packit Service 97d2fb
	  }
Packit Service 97d2fb
      if (skip_this_module)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  free (build_id);
Packit Service 97d2fb
	  return finish ();
Packit Service 97d2fb
	}
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  const char *file_note_name = handle_file_note (module_start, module_end,
Packit Service 97d2fb
						 ei_class, ei_data,
Packit Service 97d2fb
						 note_file, note_file_size);
Packit Service 97d2fb
  if (file_note_name)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      name = file_note_name;
Packit Service 97d2fb
      name_is_final = true;
Packit Service 97d2fb
      bool invalid = false;
Packit Service 97d2fb
      fd = open (name, O_RDONLY);
Packit Service 97d2fb
      if (fd >= 0)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  Dwfl_Error error = __libdw_open_file (&fd, &elf, true, false);
Packit Service 97d2fb
	  if (error == DWFL_E_NOERROR)
Packit Service 97d2fb
	    invalid = invalid_elf (elf, true /* disk_file_has_build_id */,
Packit Service 97d2fb
				   build_id, build_id_len);
Packit Service 97d2fb
	}
Packit Service 97d2fb
      if (invalid)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  /* The file was there, but the build_id didn't match.  We
Packit Service 97d2fb
	     still want to report the module, but need to get the ELF
Packit Service 97d2fb
	     some other way if possible.  */
Packit Service 97d2fb
	  close (fd);
Packit Service 97d2fb
	  fd = -1;
Packit Service 97d2fb
	  elf_end (elf);
Packit Service 97d2fb
	  elf = NULL;
Packit Service 97d2fb
	}
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  /* Our return value now says to skip the segments contained
Packit Service 97d2fb
     within the module.  */
Packit Service 97d2fb
  ndx = addr_segndx (dwfl, segment, module_end, true);
Packit Service 97d2fb
Packit Service 97d2fb
  /* Examine its .dynamic section to get more interesting details.
Packit Service 97d2fb
     If it has DT_SONAME, we'll use that as the module name.
Packit Service 97d2fb
     If it has a DT_DEBUG, then it's actually a PIE rather than a DSO.
Packit Service 97d2fb
     We need its DT_STRTAB and DT_STRSZ to decipher DT_SONAME,
Packit Service 97d2fb
     and they also tell us the essential portion of the file
Packit Service 97d2fb
     for fetching symbols.  */
Packit Service 97d2fb
  GElf_Addr soname_stroff = 0;
Packit Service 97d2fb
  GElf_Addr dynstr_vaddr = 0;
Packit Service 97d2fb
  GElf_Xword dynstrsz = 0;
Packit Service 97d2fb
  bool execlike = false;
Packit Service 97d2fb
  inline bool consider_dyn (GElf_Sxword tag, GElf_Xword val)
Packit Service 97d2fb
  {
Packit Service 97d2fb
    switch (tag)
Packit Service 97d2fb
      {
Packit Service 97d2fb
      default:
Packit Service 97d2fb
	return false;
Packit Service 97d2fb
Packit Service 97d2fb
      case DT_DEBUG:
Packit Service 97d2fb
	execlike = true;
Packit Service 97d2fb
	break;
Packit Service 97d2fb
Packit Service 97d2fb
      case DT_SONAME:
Packit Service 97d2fb
	soname_stroff = val;
Packit Service 97d2fb
	break;
Packit Service 97d2fb
Packit Service 97d2fb
      case DT_STRTAB:
Packit Service 97d2fb
	dynstr_vaddr = val;
Packit Service 97d2fb
	break;
Packit Service 97d2fb
Packit Service 97d2fb
      case DT_STRSZ:
Packit Service 97d2fb
	dynstrsz = val;
Packit Service 97d2fb
	break;
Packit Service 97d2fb
      }
Packit Service 97d2fb
Packit Service 97d2fb
    return soname_stroff != 0 && dynstr_vaddr != 0 && dynstrsz != 0;
Packit Service 97d2fb
  }
Packit Service 97d2fb
Packit Service 97d2fb
  const size_t dyn_entsize = (ei_class == ELFCLASS32
Packit Service 97d2fb
			      ? sizeof (Elf32_Dyn) : sizeof (Elf64_Dyn));
Packit Service 97d2fb
  void *dyn_data = NULL;
Packit Service 97d2fb
  size_t dyn_data_size = 0;
Packit Service 97d2fb
  if (dyn_filesz != 0 && dyn_filesz % dyn_entsize == 0
Packit Service 97d2fb
      && ! read_portion (&dyn_data, &dyn_data_size, dyn_vaddr, dyn_filesz))
Packit Service 97d2fb
    {
Packit Service 97d2fb
      /* dyn_data_size will be zero if we got everything from the initial
Packit Service 97d2fb
         buffer, otherwise it will be the size of the new buffer that
Packit Service 97d2fb
         could be read.  */
Packit Service 97d2fb
      if (dyn_data_size != 0)
Packit Service 97d2fb
	dyn_filesz = dyn_data_size;
Packit Service 97d2fb
Packit Service 97d2fb
      void *dyns = malloc (dyn_filesz);
Packit Service 97d2fb
      Elf32_Dyn (*d32)[dyn_filesz / sizeof (Elf32_Dyn)] = dyns;
Packit Service 97d2fb
      Elf64_Dyn (*d64)[dyn_filesz / sizeof (Elf64_Dyn)] = dyns;
Packit Service 97d2fb
      if (unlikely (dyns == NULL))
Packit Service 97d2fb
	return finish ();
Packit Service 97d2fb
Packit Service 97d2fb
      xlatefrom.d_type = xlateto.d_type = ELF_T_DYN;
Packit Service 97d2fb
      xlatefrom.d_buf = (void *) dyn_data;
Packit Service 97d2fb
      xlatefrom.d_size = dyn_filesz;
Packit Service 97d2fb
      xlateto.d_buf = dyns;
Packit Service 97d2fb
      xlateto.d_size = dyn_filesz;
Packit Service 97d2fb
Packit Service 97d2fb
      if (ei_class == ELFCLASS32)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  if (elf32_xlatetom (&xlateto, &xlatefrom, ei_data) != NULL)
Packit Service 97d2fb
	    for (size_t i = 0; i < dyn_filesz / sizeof (Elf32_Dyn); ++i)
Packit Service 97d2fb
	      if (consider_dyn ((*d32)[i].d_tag, (*d32)[i].d_un.d_val))
Packit Service 97d2fb
		break;
Packit Service 97d2fb
	}
Packit Service 97d2fb
      else
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  if (elf64_xlatetom (&xlateto, &xlatefrom, ei_data) != NULL)
Packit Service 97d2fb
	    for (size_t i = 0; i < dyn_filesz / sizeof (Elf64_Dyn); ++i)
Packit Service 97d2fb
	      if (consider_dyn ((*d64)[i].d_tag, (*d64)[i].d_un.d_val))
Packit Service 97d2fb
		break;
Packit Service 97d2fb
	}
Packit Service 97d2fb
      free (dyns);
Packit Service 97d2fb
    }
Packit Service 97d2fb
  finish_portion (&dyn_data, &dyn_data_size);
Packit Service 97d2fb
Packit Service 97d2fb
  /* We'll use the name passed in or a stupid default if not DT_SONAME.  */
Packit Service 97d2fb
  if (name == NULL)
Packit Service 97d2fb
    name = e_type == ET_EXEC ? "[exe]" : execlike ? "[pie]" : "[dso]";
Packit Service 97d2fb
Packit Service 97d2fb
  void *soname = NULL;
Packit Service 97d2fb
  size_t soname_size = 0;
Packit Service 97d2fb
  if (! name_is_final && dynstrsz != 0 && dynstr_vaddr != 0)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      /* We know the bounds of the .dynstr section.
Packit Service 97d2fb
Packit Service 97d2fb
	 The DYNSTR_VADDR pointer comes from the .dynamic section
Packit Service 97d2fb
	 (DT_STRTAB, detected above).  Ordinarily the dynamic linker
Packit Service 97d2fb
	 will have adjusted this pointer in place so it's now an
Packit Service 97d2fb
	 absolute address.  But sometimes .dynamic is read-only (in
Packit Service 97d2fb
	 vDSOs and odd architectures), and sometimes the adjustment
Packit Service 97d2fb
	 just hasn't happened yet in the memory image we looked at.
Packit Service 97d2fb
	 So treat DYNSTR_VADDR as an absolute address if it falls
Packit Service 97d2fb
	 within the module bounds, or try applying the phdr bias
Packit Service 97d2fb
	 when that adjusts it to fall within the module bounds.  */
Packit Service 97d2fb
Packit Service 97d2fb
      if ((dynstr_vaddr < module_start || dynstr_vaddr >= module_end)
Packit Service 97d2fb
	  && dynstr_vaddr + bias >= module_start
Packit Service 97d2fb
	  && dynstr_vaddr + bias < module_end)
Packit Service 97d2fb
	dynstr_vaddr += bias;
Packit Service 97d2fb
Packit Service 97d2fb
      if (unlikely (dynstr_vaddr + dynstrsz > module_end))
Packit Service 97d2fb
	dynstrsz = 0;
Packit Service 97d2fb
Packit Service 97d2fb
      /* Try to get the DT_SONAME string.  */
Packit Service 97d2fb
      if (soname_stroff != 0 && soname_stroff + 1 < dynstrsz
Packit Service 97d2fb
	  && ! read_portion (&soname, &soname_size,
Packit Service 97d2fb
			     dynstr_vaddr + soname_stroff, 0))
Packit Service 97d2fb
	name = soname;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  /* Now that we have chosen the module's name and bounds, report it.
Packit Service 97d2fb
     If we found a build ID, report that too.  */
Packit Service 97d2fb
Packit Service 97d2fb
  Dwfl_Module *mod = INTUSE(dwfl_report_module) (dwfl, name,
Packit Service 97d2fb
						 module_start, module_end);
Packit Service 97d2fb
Packit Service 97d2fb
  // !execlike && ET_EXEC is PIE.
Packit Service 97d2fb
  // execlike && !ET_EXEC is a static executable.
Packit Service 97d2fb
  if (mod != NULL && (execlike || ehdr.e32.e_type == ET_EXEC))
Packit Service 97d2fb
    mod->is_executable = true;
Packit Service 97d2fb
Packit Service 97d2fb
  if (likely (mod != NULL) && build_id != NULL
Packit Service 97d2fb
      && unlikely (INTUSE(dwfl_module_report_build_id) (mod,
Packit Service 97d2fb
							build_id,
Packit Service 97d2fb
							build_id_len,
Packit Service 97d2fb
							build_id_vaddr)))
Packit Service 97d2fb
    {
Packit Service 97d2fb
      mod->gc = true;
Packit Service 97d2fb
      mod = NULL;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  /* At this point we do not need BUILD_ID or NAME any more.
Packit Service 97d2fb
     They have been copied.  */
Packit Service 97d2fb
  free (build_id);
Packit Service 97d2fb
  finish_portion (&soname, &soname_size);
Packit Service 97d2fb
Packit Service 97d2fb
  if (unlikely (mod == NULL))
Packit Service 97d2fb
    {
Packit Service 97d2fb
      ndx = -1;
Packit Service 97d2fb
      return finish ();
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  /* We have reported the module.  Now let the caller decide whether we
Packit Service 97d2fb
     should read the whole thing in right now.  */
Packit Service 97d2fb
Packit Service 97d2fb
  const GElf_Off cost = (contiguous < file_trimmed_end ? total_filesz
Packit Service 97d2fb
			 : buffer_available >= contiguous ? 0
Packit Service 97d2fb
			 : contiguous - buffer_available);
Packit Service 97d2fb
  const GElf_Off worthwhile = ((dynstr_vaddr == 0 || dynstrsz == 0) ? 0
Packit Service 97d2fb
			       : dynstr_vaddr + dynstrsz - start);
Packit Service 97d2fb
  const GElf_Off whole = MAX (file_trimmed_end, shdrs_end);
Packit Service 97d2fb
Packit Service 97d2fb
  if (elf == NULL
Packit Service 97d2fb
      && (*read_eagerly) (MODCB_ARGS (mod), &buffer, &buffer_available,
Packit Service 97d2fb
			  cost, worthwhile, whole, contiguous,
Packit Service 97d2fb
			  read_eagerly_arg, &elf)
Packit Service 97d2fb
      && elf == NULL)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      /* The caller wants to read the whole file in right now, but hasn't
Packit Service 97d2fb
	 done it for us.  Fill in a local image of the virtual file.  */
Packit Service 97d2fb
Packit Service 97d2fb
      void *contents = calloc (1, file_trimmed_end);
Packit Service 97d2fb
      if (unlikely (contents == NULL))
Packit Service 97d2fb
	return finish ();
Packit Service 97d2fb
Packit Service 97d2fb
      inline void final_read (size_t offset, GElf_Addr vaddr, size_t size)
Packit Service 97d2fb
      {
Packit Service 97d2fb
	void *into = contents + offset;
Packit Service 97d2fb
	size_t read_size = size;
Packit Service 97d2fb
	(void) segment_read (addr_segndx (dwfl, segment, vaddr, false),
Packit Service 97d2fb
			     &into, &read_size, vaddr, size);
Packit Service 97d2fb
      }
Packit Service 97d2fb
Packit Service 97d2fb
      if (contiguous < file_trimmed_end)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  /* We can't use the memory image verbatim as the file image.
Packit Service 97d2fb
	     So we'll be reading into a local image of the virtual file.  */
Packit Service 97d2fb
Packit Service 97d2fb
	  inline void read_phdr (GElf_Word type, GElf_Addr vaddr,
Packit Service 97d2fb
				 GElf_Off offset, GElf_Xword filesz)
Packit Service 97d2fb
	  {
Packit Service 97d2fb
	    if (type == PT_LOAD)
Packit Service 97d2fb
	      final_read (offset, vaddr + bias, filesz);
Packit Service 97d2fb
	  }
Packit Service 97d2fb
Packit Service 97d2fb
	  if (ei_class == ELFCLASS32)
Packit Service 97d2fb
	    for (uint_fast16_t i = 0; i < phnum; ++i)
Packit Service 97d2fb
	      read_phdr ((*p32)[i].p_type, (*p32)[i].p_vaddr,
Packit Service 97d2fb
			 (*p32)[i].p_offset, (*p32)[i].p_filesz);
Packit Service 97d2fb
	  else
Packit Service 97d2fb
	    for (uint_fast16_t i = 0; i < phnum; ++i)
Packit Service 97d2fb
	      read_phdr ((*p64)[i].p_type, (*p64)[i].p_vaddr,
Packit Service 97d2fb
			 (*p64)[i].p_offset, (*p64)[i].p_filesz);
Packit Service 97d2fb
	}
Packit Service 97d2fb
      else
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  /* The whole file sits contiguous in memory,
Packit Service 97d2fb
	     but the caller didn't want to just do it.  */
Packit Service 97d2fb
Packit Service 97d2fb
	  const size_t have = MIN (buffer_available, file_trimmed_end);
Packit Service 97d2fb
	  memcpy (contents, buffer, have);
Packit Service 97d2fb
Packit Service 97d2fb
	  if (have < file_trimmed_end)
Packit Service 97d2fb
	    final_read (have, start + have, file_trimmed_end - have);
Packit Service 97d2fb
	}
Packit Service 97d2fb
Packit Service 97d2fb
      elf = elf_memory (contents, file_trimmed_end);
Packit Service 97d2fb
      if (unlikely (elf == NULL))
Packit Service 97d2fb
	free (contents);
Packit Service 97d2fb
      else
Packit Service 97d2fb
	elf->flags |= ELF_F_MALLOCED;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  if (elf != NULL)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      /* Install the file in the module.  */
Packit Service 97d2fb
      mod->main.elf = elf;
Packit Service 97d2fb
      mod->main.fd = fd;
Packit Service 97d2fb
      elf = NULL;
Packit Service 97d2fb
      fd = -1;
Packit Service 97d2fb
      mod->main.vaddr = module_start - bias;
Packit Service 97d2fb
      mod->main.address_sync = module_address_sync;
Packit Service 97d2fb
      mod->main_bias = bias;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  return finish ();
Packit Service 97d2fb
}