Blame libdwfl/dwfl_segment_report_module.c

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