125b3c049e70834cf33790a28643ab058b507b35cBen Cheng/* Sniff out modules from ELF headers visible in memory segments.
225b3c049e70834cf33790a28643ab058b507b35cBen Cheng   Copyright (C) 2008-2010 Red Hat, Inc.
325b3c049e70834cf33790a28643ab058b507b35cBen Cheng   This file is part of Red Hat elfutils.
425b3c049e70834cf33790a28643ab058b507b35cBen Cheng
525b3c049e70834cf33790a28643ab058b507b35cBen Cheng   Red Hat elfutils is free software; you can redistribute it and/or modify
625b3c049e70834cf33790a28643ab058b507b35cBen Cheng   it under the terms of the GNU General Public License as published by the
725b3c049e70834cf33790a28643ab058b507b35cBen Cheng   Free Software Foundation; version 2 of the License.
825b3c049e70834cf33790a28643ab058b507b35cBen Cheng
925b3c049e70834cf33790a28643ab058b507b35cBen Cheng   Red Hat elfutils is distributed in the hope that it will be useful, but
1025b3c049e70834cf33790a28643ab058b507b35cBen Cheng   WITHOUT ANY WARRANTY; without even the implied warranty of
1125b3c049e70834cf33790a28643ab058b507b35cBen Cheng   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
1225b3c049e70834cf33790a28643ab058b507b35cBen Cheng   General Public License for more details.
1325b3c049e70834cf33790a28643ab058b507b35cBen Cheng
1425b3c049e70834cf33790a28643ab058b507b35cBen Cheng   You should have received a copy of the GNU General Public License along
1525b3c049e70834cf33790a28643ab058b507b35cBen Cheng   with Red Hat elfutils; if not, write to the Free Software Foundation,
1625b3c049e70834cf33790a28643ab058b507b35cBen Cheng   Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
1725b3c049e70834cf33790a28643ab058b507b35cBen Cheng
1825b3c049e70834cf33790a28643ab058b507b35cBen Cheng   In addition, as a special exception, Red Hat, Inc. gives You the
1925b3c049e70834cf33790a28643ab058b507b35cBen Cheng   additional right to link the code of Red Hat elfutils with code licensed
2025b3c049e70834cf33790a28643ab058b507b35cBen Cheng   under any Open Source Initiative certified open source license
2125b3c049e70834cf33790a28643ab058b507b35cBen Cheng   (http://www.opensource.org/licenses/index.php) which requires the
2225b3c049e70834cf33790a28643ab058b507b35cBen Cheng   distribution of source code with any binary distribution and to
2325b3c049e70834cf33790a28643ab058b507b35cBen Cheng   distribute linked combinations of the two.  Non-GPL Code permitted under
2425b3c049e70834cf33790a28643ab058b507b35cBen Cheng   this exception must only link to the code of Red Hat elfutils through
2525b3c049e70834cf33790a28643ab058b507b35cBen Cheng   those well defined interfaces identified in the file named EXCEPTION
2625b3c049e70834cf33790a28643ab058b507b35cBen Cheng   found in the source code files (the "Approved Interfaces").  The files
2725b3c049e70834cf33790a28643ab058b507b35cBen Cheng   of Non-GPL Code may instantiate templates or use macros or inline
2825b3c049e70834cf33790a28643ab058b507b35cBen Cheng   functions from the Approved Interfaces without causing the resulting
2925b3c049e70834cf33790a28643ab058b507b35cBen Cheng   work to be covered by the GNU General Public License.  Only Red Hat,
3025b3c049e70834cf33790a28643ab058b507b35cBen Cheng   Inc. may make changes or additions to the list of Approved Interfaces.
3125b3c049e70834cf33790a28643ab058b507b35cBen Cheng   Red Hat's grant of this exception is conditioned upon your not adding
3225b3c049e70834cf33790a28643ab058b507b35cBen Cheng   any new exceptions.  If you wish to add a new Approved Interface or
3325b3c049e70834cf33790a28643ab058b507b35cBen Cheng   exception, please contact Red Hat.  You must obey the GNU General Public
3425b3c049e70834cf33790a28643ab058b507b35cBen Cheng   License in all respects for all of the Red Hat elfutils code and other
3525b3c049e70834cf33790a28643ab058b507b35cBen Cheng   code used in conjunction with Red Hat elfutils except the Non-GPL Code
3625b3c049e70834cf33790a28643ab058b507b35cBen Cheng   covered by this exception.  If you modify this file, you may extend this
3725b3c049e70834cf33790a28643ab058b507b35cBen Cheng   exception to your version of the file, but you are not obligated to do
3825b3c049e70834cf33790a28643ab058b507b35cBen Cheng   so.  If you do not wish to provide this exception without modification,
3925b3c049e70834cf33790a28643ab058b507b35cBen Cheng   you must delete this exception statement from your version and license
4025b3c049e70834cf33790a28643ab058b507b35cBen Cheng   this file solely under the GPL without exception.
4125b3c049e70834cf33790a28643ab058b507b35cBen Cheng
4225b3c049e70834cf33790a28643ab058b507b35cBen Cheng   Red Hat elfutils is an included package of the Open Invention Network.
4325b3c049e70834cf33790a28643ab058b507b35cBen Cheng   An included package of the Open Invention Network is a package for which
4425b3c049e70834cf33790a28643ab058b507b35cBen Cheng   Open Invention Network licensees cross-license their patents.  No patent
4525b3c049e70834cf33790a28643ab058b507b35cBen Cheng   license is granted, either expressly or impliedly, by designation as an
4625b3c049e70834cf33790a28643ab058b507b35cBen Cheng   included package.  Should you wish to participate in the Open Invention
4725b3c049e70834cf33790a28643ab058b507b35cBen Cheng   Network licensing program, please visit www.openinventionnetwork.com
4825b3c049e70834cf33790a28643ab058b507b35cBen Cheng   <http://www.openinventionnetwork.com>.  */
4925b3c049e70834cf33790a28643ab058b507b35cBen Cheng
5025b3c049e70834cf33790a28643ab058b507b35cBen Cheng#include <config.h>
5125b3c049e70834cf33790a28643ab058b507b35cBen Cheng#include "../libelf/libelfP.h"	/* For NOTE_ALIGN.  */
5225b3c049e70834cf33790a28643ab058b507b35cBen Cheng#undef	_
5325b3c049e70834cf33790a28643ab058b507b35cBen Cheng#include "libdwflP.h"
5425b3c049e70834cf33790a28643ab058b507b35cBen Cheng
5525b3c049e70834cf33790a28643ab058b507b35cBen Cheng#include <elf.h>
5625b3c049e70834cf33790a28643ab058b507b35cBen Cheng#include <gelf.h>
5725b3c049e70834cf33790a28643ab058b507b35cBen Cheng#include <inttypes.h>
5825b3c049e70834cf33790a28643ab058b507b35cBen Cheng#include <sys/param.h>
5925b3c049e70834cf33790a28643ab058b507b35cBen Cheng#include <alloca.h>
6025b3c049e70834cf33790a28643ab058b507b35cBen Cheng#include <endian.h>
6125b3c049e70834cf33790a28643ab058b507b35cBen Cheng
6225b3c049e70834cf33790a28643ab058b507b35cBen Cheng
6325b3c049e70834cf33790a28643ab058b507b35cBen Cheng/* A good size for the initial read from memory, if it's not too costly.
6425b3c049e70834cf33790a28643ab058b507b35cBen Cheng   This more than covers the phdrs and note segment in the average 64-bit
6525b3c049e70834cf33790a28643ab058b507b35cBen Cheng   binary.  */
6625b3c049e70834cf33790a28643ab058b507b35cBen Cheng
6725b3c049e70834cf33790a28643ab058b507b35cBen Cheng#define INITIAL_READ	1024
6825b3c049e70834cf33790a28643ab058b507b35cBen Cheng
6925b3c049e70834cf33790a28643ab058b507b35cBen Cheng#if __BYTE_ORDER == __LITTLE_ENDIAN
7025b3c049e70834cf33790a28643ab058b507b35cBen Cheng# define MY_ELFDATA	ELFDATA2LSB
7125b3c049e70834cf33790a28643ab058b507b35cBen Cheng#else
7225b3c049e70834cf33790a28643ab058b507b35cBen Cheng# define MY_ELFDATA	ELFDATA2MSB
7325b3c049e70834cf33790a28643ab058b507b35cBen Cheng#endif
7425b3c049e70834cf33790a28643ab058b507b35cBen Cheng
7525b3c049e70834cf33790a28643ab058b507b35cBen Cheng
7625b3c049e70834cf33790a28643ab058b507b35cBen Cheng/* Return user segment index closest to ADDR but not above it.
7725b3c049e70834cf33790a28643ab058b507b35cBen Cheng   If NEXT, return the closest to ADDR but not below it.  */
7825b3c049e70834cf33790a28643ab058b507b35cBen Chengstatic int
7925b3c049e70834cf33790a28643ab058b507b35cBen Chengaddr_segndx (Dwfl *dwfl, size_t segment, GElf_Addr addr, bool next)
8025b3c049e70834cf33790a28643ab058b507b35cBen Cheng{
8125b3c049e70834cf33790a28643ab058b507b35cBen Cheng  int ndx = -1;
8225b3c049e70834cf33790a28643ab058b507b35cBen Cheng  do
8325b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
8425b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (dwfl->lookup_segndx[segment] >= 0)
8525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	ndx = dwfl->lookup_segndx[segment];
8625b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (++segment >= dwfl->lookup_elts - 1)
8725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	return next ? ndx + 1 : ndx;
8825b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
8925b3c049e70834cf33790a28643ab058b507b35cBen Cheng  while (dwfl->lookup_addr[segment] < addr);
9025b3c049e70834cf33790a28643ab058b507b35cBen Cheng
9125b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (next)
9225b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
9325b3c049e70834cf33790a28643ab058b507b35cBen Cheng      while (dwfl->lookup_segndx[segment] < 0)
9425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	if (++segment >= dwfl->lookup_elts - 1)
9525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  return ndx + 1;
9625b3c049e70834cf33790a28643ab058b507b35cBen Cheng      ndx = dwfl->lookup_segndx[segment];
9725b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
9825b3c049e70834cf33790a28643ab058b507b35cBen Cheng
9925b3c049e70834cf33790a28643ab058b507b35cBen Cheng  return ndx;
10025b3c049e70834cf33790a28643ab058b507b35cBen Cheng}
10125b3c049e70834cf33790a28643ab058b507b35cBen Cheng
10225b3c049e70834cf33790a28643ab058b507b35cBen Chengint
10325b3c049e70834cf33790a28643ab058b507b35cBen Chengdwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name,
10425b3c049e70834cf33790a28643ab058b507b35cBen Cheng			    Dwfl_Memory_Callback *memory_callback,
10525b3c049e70834cf33790a28643ab058b507b35cBen Cheng			    void *memory_callback_arg,
10625b3c049e70834cf33790a28643ab058b507b35cBen Cheng			    Dwfl_Module_Callback *read_eagerly,
10725b3c049e70834cf33790a28643ab058b507b35cBen Cheng			    void *read_eagerly_arg)
10825b3c049e70834cf33790a28643ab058b507b35cBen Cheng{
10925b3c049e70834cf33790a28643ab058b507b35cBen Cheng  size_t segment = ndx;
11025b3c049e70834cf33790a28643ab058b507b35cBen Cheng
11125b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (segment >= dwfl->lookup_elts)
11225b3c049e70834cf33790a28643ab058b507b35cBen Cheng    segment = dwfl->lookup_elts - 1;
11325b3c049e70834cf33790a28643ab058b507b35cBen Cheng
11425b3c049e70834cf33790a28643ab058b507b35cBen Cheng  while (segment > 0
11525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	 && (dwfl->lookup_segndx[segment] > ndx
11625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	     || dwfl->lookup_segndx[segment] == -1))
11725b3c049e70834cf33790a28643ab058b507b35cBen Cheng    --segment;
11825b3c049e70834cf33790a28643ab058b507b35cBen Cheng
11925b3c049e70834cf33790a28643ab058b507b35cBen Cheng  while (dwfl->lookup_segndx[segment] < ndx)
12025b3c049e70834cf33790a28643ab058b507b35cBen Cheng    if (++segment == dwfl->lookup_elts)
12125b3c049e70834cf33790a28643ab058b507b35cBen Cheng      return 0;
12225b3c049e70834cf33790a28643ab058b507b35cBen Cheng
12325b3c049e70834cf33790a28643ab058b507b35cBen Cheng  GElf_Addr start = dwfl->lookup_addr[segment];
12425b3c049e70834cf33790a28643ab058b507b35cBen Cheng
12525b3c049e70834cf33790a28643ab058b507b35cBen Cheng  inline bool segment_read (int segndx,
12625b3c049e70834cf33790a28643ab058b507b35cBen Cheng			    void **buffer, size_t *buffer_available,
12725b3c049e70834cf33790a28643ab058b507b35cBen Cheng			    GElf_Addr addr, size_t minread)
12825b3c049e70834cf33790a28643ab058b507b35cBen Cheng  {
12925b3c049e70834cf33790a28643ab058b507b35cBen Cheng    return ! (*memory_callback) (dwfl, segndx, buffer, buffer_available,
13025b3c049e70834cf33790a28643ab058b507b35cBen Cheng				 addr, minread, memory_callback_arg);
13125b3c049e70834cf33790a28643ab058b507b35cBen Cheng  }
13225b3c049e70834cf33790a28643ab058b507b35cBen Cheng
13325b3c049e70834cf33790a28643ab058b507b35cBen Cheng  inline void release_buffer (void **buffer, size_t *buffer_available)
13425b3c049e70834cf33790a28643ab058b507b35cBen Cheng  {
13525b3c049e70834cf33790a28643ab058b507b35cBen Cheng    if (*buffer != NULL)
13625b3c049e70834cf33790a28643ab058b507b35cBen Cheng      (void) segment_read (-1, buffer, buffer_available, 0, 0);
13725b3c049e70834cf33790a28643ab058b507b35cBen Cheng  }
13825b3c049e70834cf33790a28643ab058b507b35cBen Cheng
13925b3c049e70834cf33790a28643ab058b507b35cBen Cheng  /* First read in the file header and check its sanity.  */
14025b3c049e70834cf33790a28643ab058b507b35cBen Cheng
14125b3c049e70834cf33790a28643ab058b507b35cBen Cheng  void *buffer = NULL;
14225b3c049e70834cf33790a28643ab058b507b35cBen Cheng  size_t buffer_available = INITIAL_READ;
14325b3c049e70834cf33790a28643ab058b507b35cBen Cheng
14425b3c049e70834cf33790a28643ab058b507b35cBen Cheng  inline int finish (void)
14525b3c049e70834cf33790a28643ab058b507b35cBen Cheng  {
14625b3c049e70834cf33790a28643ab058b507b35cBen Cheng    release_buffer (&buffer, &buffer_available);
14725b3c049e70834cf33790a28643ab058b507b35cBen Cheng    return ndx;
14825b3c049e70834cf33790a28643ab058b507b35cBen Cheng  }
14925b3c049e70834cf33790a28643ab058b507b35cBen Cheng
15025b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (segment_read (ndx, &buffer, &buffer_available,
15125b3c049e70834cf33790a28643ab058b507b35cBen Cheng		    start, sizeof (Elf64_Ehdr))
15225b3c049e70834cf33790a28643ab058b507b35cBen Cheng      || memcmp (buffer, ELFMAG, SELFMAG) != 0)
15325b3c049e70834cf33790a28643ab058b507b35cBen Cheng    return finish ();
15425b3c049e70834cf33790a28643ab058b507b35cBen Cheng
15525b3c049e70834cf33790a28643ab058b507b35cBen Cheng  inline bool read_portion (void **data, size_t *data_size,
15625b3c049e70834cf33790a28643ab058b507b35cBen Cheng			    GElf_Addr vaddr, size_t filesz)
15725b3c049e70834cf33790a28643ab058b507b35cBen Cheng  {
15825b3c049e70834cf33790a28643ab058b507b35cBen Cheng    if (vaddr - start + filesz > buffer_available)
15925b3c049e70834cf33790a28643ab058b507b35cBen Cheng      {
16025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	*data = NULL;
16125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	*data_size = filesz;
16225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	return segment_read (addr_segndx (dwfl, segment, vaddr, false),
16325b3c049e70834cf33790a28643ab058b507b35cBen Cheng			     data, data_size, vaddr, filesz);
16425b3c049e70834cf33790a28643ab058b507b35cBen Cheng      }
16525b3c049e70834cf33790a28643ab058b507b35cBen Cheng
16625b3c049e70834cf33790a28643ab058b507b35cBen Cheng    /* We already have this whole note segment from our initial read.  */
16725b3c049e70834cf33790a28643ab058b507b35cBen Cheng    *data = vaddr - start + buffer;
16825b3c049e70834cf33790a28643ab058b507b35cBen Cheng    *data_size = 0;
16925b3c049e70834cf33790a28643ab058b507b35cBen Cheng    return false;
17025b3c049e70834cf33790a28643ab058b507b35cBen Cheng  }
17125b3c049e70834cf33790a28643ab058b507b35cBen Cheng
17225b3c049e70834cf33790a28643ab058b507b35cBen Cheng  inline void finish_portion (void **data, size_t *data_size)
17325b3c049e70834cf33790a28643ab058b507b35cBen Cheng  {
17425b3c049e70834cf33790a28643ab058b507b35cBen Cheng    if (*data_size != 0)
17525b3c049e70834cf33790a28643ab058b507b35cBen Cheng      release_buffer (data, data_size);
17625b3c049e70834cf33790a28643ab058b507b35cBen Cheng  }
17725b3c049e70834cf33790a28643ab058b507b35cBen Cheng
17825b3c049e70834cf33790a28643ab058b507b35cBen Cheng  /* Extract the information we need from the file header.  */
17925b3c049e70834cf33790a28643ab058b507b35cBen Cheng  union
18025b3c049e70834cf33790a28643ab058b507b35cBen Cheng  {
18125b3c049e70834cf33790a28643ab058b507b35cBen Cheng    Elf32_Ehdr e32;
18225b3c049e70834cf33790a28643ab058b507b35cBen Cheng    Elf64_Ehdr e64;
18325b3c049e70834cf33790a28643ab058b507b35cBen Cheng  } ehdr;
18425b3c049e70834cf33790a28643ab058b507b35cBen Cheng  GElf_Off phoff;
18525b3c049e70834cf33790a28643ab058b507b35cBen Cheng  uint_fast16_t phnum;
18625b3c049e70834cf33790a28643ab058b507b35cBen Cheng  uint_fast16_t phentsize;
18725b3c049e70834cf33790a28643ab058b507b35cBen Cheng  GElf_Off shdrs_end;
18825b3c049e70834cf33790a28643ab058b507b35cBen Cheng  Elf_Data xlatefrom =
18925b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
19025b3c049e70834cf33790a28643ab058b507b35cBen Cheng      .d_type = ELF_T_EHDR,
19125b3c049e70834cf33790a28643ab058b507b35cBen Cheng      .d_buf = (void *) buffer,
19225b3c049e70834cf33790a28643ab058b507b35cBen Cheng      .d_version = EV_CURRENT,
19325b3c049e70834cf33790a28643ab058b507b35cBen Cheng    };
19425b3c049e70834cf33790a28643ab058b507b35cBen Cheng  Elf_Data xlateto =
19525b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
19625b3c049e70834cf33790a28643ab058b507b35cBen Cheng      .d_type = ELF_T_EHDR,
19725b3c049e70834cf33790a28643ab058b507b35cBen Cheng      .d_buf = &ehdr,
19825b3c049e70834cf33790a28643ab058b507b35cBen Cheng      .d_size = sizeof ehdr,
19925b3c049e70834cf33790a28643ab058b507b35cBen Cheng      .d_version = EV_CURRENT,
20025b3c049e70834cf33790a28643ab058b507b35cBen Cheng    };
20125b3c049e70834cf33790a28643ab058b507b35cBen Cheng  switch (((const unsigned char *) buffer)[EI_CLASS])
20225b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
20325b3c049e70834cf33790a28643ab058b507b35cBen Cheng    case ELFCLASS32:
20425b3c049e70834cf33790a28643ab058b507b35cBen Cheng      xlatefrom.d_size = sizeof (Elf32_Ehdr);
20525b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (elf32_xlatetom (&xlateto, &xlatefrom,
20625b3c049e70834cf33790a28643ab058b507b35cBen Cheng			  ((const unsigned char *) buffer)[EI_DATA]) == NULL)
20725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	return finish ();
20825b3c049e70834cf33790a28643ab058b507b35cBen Cheng      phoff = ehdr.e32.e_phoff;
20925b3c049e70834cf33790a28643ab058b507b35cBen Cheng      phnum = ehdr.e32.e_phnum;
21025b3c049e70834cf33790a28643ab058b507b35cBen Cheng      phentsize = ehdr.e32.e_phentsize;
21125b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (phentsize != sizeof (Elf32_Phdr))
21225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	return finish ();
21325b3c049e70834cf33790a28643ab058b507b35cBen Cheng      shdrs_end = ehdr.e32.e_shoff + ehdr.e32.e_shnum * ehdr.e32.e_shentsize;
21425b3c049e70834cf33790a28643ab058b507b35cBen Cheng      break;
21525b3c049e70834cf33790a28643ab058b507b35cBen Cheng
21625b3c049e70834cf33790a28643ab058b507b35cBen Cheng    case ELFCLASS64:
21725b3c049e70834cf33790a28643ab058b507b35cBen Cheng      xlatefrom.d_size = sizeof (Elf64_Ehdr);
21825b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (elf64_xlatetom (&xlateto, &xlatefrom,
21925b3c049e70834cf33790a28643ab058b507b35cBen Cheng			  ((const unsigned char *) buffer)[EI_DATA]) == NULL)
22025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	return finish ();
22125b3c049e70834cf33790a28643ab058b507b35cBen Cheng      phoff = ehdr.e64.e_phoff;
22225b3c049e70834cf33790a28643ab058b507b35cBen Cheng      phnum = ehdr.e64.e_phnum;
22325b3c049e70834cf33790a28643ab058b507b35cBen Cheng      phentsize = ehdr.e64.e_phentsize;
22425b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (phentsize != sizeof (Elf64_Phdr))
22525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	return finish ();
22625b3c049e70834cf33790a28643ab058b507b35cBen Cheng      shdrs_end = ehdr.e64.e_shoff + ehdr.e64.e_shnum * ehdr.e64.e_shentsize;
22725b3c049e70834cf33790a28643ab058b507b35cBen Cheng      break;
22825b3c049e70834cf33790a28643ab058b507b35cBen Cheng
22925b3c049e70834cf33790a28643ab058b507b35cBen Cheng    default:
23025b3c049e70834cf33790a28643ab058b507b35cBen Cheng      return finish ();
23125b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
23225b3c049e70834cf33790a28643ab058b507b35cBen Cheng
23325b3c049e70834cf33790a28643ab058b507b35cBen Cheng  /* The file header tells where to find the program headers.
23425b3c049e70834cf33790a28643ab058b507b35cBen Cheng     These are what we need to find the boundaries of the module.
23525b3c049e70834cf33790a28643ab058b507b35cBen Cheng     Without them, we don't have a module to report.  */
23625b3c049e70834cf33790a28643ab058b507b35cBen Cheng
23725b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (phnum == 0)
23825b3c049e70834cf33790a28643ab058b507b35cBen Cheng    return finish ();
23925b3c049e70834cf33790a28643ab058b507b35cBen Cheng
24025b3c049e70834cf33790a28643ab058b507b35cBen Cheng  xlatefrom.d_type = xlateto.d_type = ELF_T_PHDR;
24125b3c049e70834cf33790a28643ab058b507b35cBen Cheng  xlatefrom.d_size = phnum * phentsize;
24225b3c049e70834cf33790a28643ab058b507b35cBen Cheng
24325b3c049e70834cf33790a28643ab058b507b35cBen Cheng  void *ph_buffer = NULL;
24425b3c049e70834cf33790a28643ab058b507b35cBen Cheng  size_t ph_buffer_size = 0;
24525b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (read_portion (&ph_buffer, &ph_buffer_size,
24625b3c049e70834cf33790a28643ab058b507b35cBen Cheng		    start + phoff, xlatefrom.d_size))
24725b3c049e70834cf33790a28643ab058b507b35cBen Cheng    return finish ();
24825b3c049e70834cf33790a28643ab058b507b35cBen Cheng
24925b3c049e70834cf33790a28643ab058b507b35cBen Cheng  xlatefrom.d_buf = ph_buffer;
25025b3c049e70834cf33790a28643ab058b507b35cBen Cheng
25125b3c049e70834cf33790a28643ab058b507b35cBen Cheng  union
25225b3c049e70834cf33790a28643ab058b507b35cBen Cheng  {
25325b3c049e70834cf33790a28643ab058b507b35cBen Cheng    Elf32_Phdr p32[phnum];
25425b3c049e70834cf33790a28643ab058b507b35cBen Cheng    Elf64_Phdr p64[phnum];
25525b3c049e70834cf33790a28643ab058b507b35cBen Cheng  } phdrs;
25625b3c049e70834cf33790a28643ab058b507b35cBen Cheng
25725b3c049e70834cf33790a28643ab058b507b35cBen Cheng  xlateto.d_buf = &phdrs;
25825b3c049e70834cf33790a28643ab058b507b35cBen Cheng  xlateto.d_size = sizeof phdrs;
25925b3c049e70834cf33790a28643ab058b507b35cBen Cheng
26025b3c049e70834cf33790a28643ab058b507b35cBen Cheng  /* Track the bounds of the file visible in memory.  */
26125b3c049e70834cf33790a28643ab058b507b35cBen Cheng  GElf_Off file_trimmed_end = 0; /* Proper p_vaddr + p_filesz end.  */
26225b3c049e70834cf33790a28643ab058b507b35cBen Cheng  GElf_Off file_end = 0;	 /* Rounded up to effective page size.  */
26325b3c049e70834cf33790a28643ab058b507b35cBen Cheng  GElf_Off contiguous = 0;	 /* Visible as contiguous file from START.  */
26425b3c049e70834cf33790a28643ab058b507b35cBen Cheng  GElf_Off total_filesz = 0;	 /* Total size of data to read.  */
26525b3c049e70834cf33790a28643ab058b507b35cBen Cheng
26625b3c049e70834cf33790a28643ab058b507b35cBen Cheng  /* Collect the bias between START and the containing PT_LOAD's p_vaddr.  */
26725b3c049e70834cf33790a28643ab058b507b35cBen Cheng  GElf_Addr bias = 0;
26825b3c049e70834cf33790a28643ab058b507b35cBen Cheng  bool found_bias = false;
26925b3c049e70834cf33790a28643ab058b507b35cBen Cheng
27025b3c049e70834cf33790a28643ab058b507b35cBen Cheng  /* Collect the unbiased bounds of the module here.  */
27125b3c049e70834cf33790a28643ab058b507b35cBen Cheng  GElf_Addr module_start = -1l;
27225b3c049e70834cf33790a28643ab058b507b35cBen Cheng  GElf_Addr module_end = 0;
27325b3c049e70834cf33790a28643ab058b507b35cBen Cheng  GElf_Addr module_address_sync = 0;
27425b3c049e70834cf33790a28643ab058b507b35cBen Cheng
27525b3c049e70834cf33790a28643ab058b507b35cBen Cheng  /* If we see PT_DYNAMIC, record it here.  */
27625b3c049e70834cf33790a28643ab058b507b35cBen Cheng  GElf_Addr dyn_vaddr = 0;
27725b3c049e70834cf33790a28643ab058b507b35cBen Cheng  GElf_Xword dyn_filesz = 0;
27825b3c049e70834cf33790a28643ab058b507b35cBen Cheng
27925b3c049e70834cf33790a28643ab058b507b35cBen Cheng  /* Collect the build ID bits here.  */
28025b3c049e70834cf33790a28643ab058b507b35cBen Cheng  void *build_id = NULL;
28125b3c049e70834cf33790a28643ab058b507b35cBen Cheng  size_t build_id_len = 0;
28225b3c049e70834cf33790a28643ab058b507b35cBen Cheng  GElf_Addr build_id_vaddr = 0;
28325b3c049e70834cf33790a28643ab058b507b35cBen Cheng
28425b3c049e70834cf33790a28643ab058b507b35cBen Cheng  /* Consider a PT_NOTE we've found in the image.  */
28525b3c049e70834cf33790a28643ab058b507b35cBen Cheng  inline void consider_notes (GElf_Addr vaddr, GElf_Xword filesz)
28625b3c049e70834cf33790a28643ab058b507b35cBen Cheng  {
28725b3c049e70834cf33790a28643ab058b507b35cBen Cheng    /* If we have already seen a build ID, we don't care any more.  */
28825b3c049e70834cf33790a28643ab058b507b35cBen Cheng    if (build_id != NULL || filesz == 0)
28925b3c049e70834cf33790a28643ab058b507b35cBen Cheng      return;
29025b3c049e70834cf33790a28643ab058b507b35cBen Cheng
29125b3c049e70834cf33790a28643ab058b507b35cBen Cheng    void *data;
29225b3c049e70834cf33790a28643ab058b507b35cBen Cheng    size_t data_size;
29325b3c049e70834cf33790a28643ab058b507b35cBen Cheng    if (read_portion (&data, &data_size, vaddr, filesz))
29425b3c049e70834cf33790a28643ab058b507b35cBen Cheng      return;
29525b3c049e70834cf33790a28643ab058b507b35cBen Cheng
29625b3c049e70834cf33790a28643ab058b507b35cBen Cheng    assert (sizeof (Elf32_Nhdr) == sizeof (Elf64_Nhdr));
29725b3c049e70834cf33790a28643ab058b507b35cBen Cheng
29825b3c049e70834cf33790a28643ab058b507b35cBen Cheng    void *notes;
29925b3c049e70834cf33790a28643ab058b507b35cBen Cheng    if (ehdr.e32.e_ident[EI_DATA] == MY_ELFDATA)
30025b3c049e70834cf33790a28643ab058b507b35cBen Cheng      notes = data;
30125b3c049e70834cf33790a28643ab058b507b35cBen Cheng    else
30225b3c049e70834cf33790a28643ab058b507b35cBen Cheng      {
30325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	notes = malloc (filesz);
30425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	if (unlikely (notes == NULL))
30525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  return;
30625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	xlatefrom.d_type = xlateto.d_type = ELF_T_NHDR;
30725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	xlatefrom.d_buf = (void *) data;
30825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	xlatefrom.d_size = filesz;
30925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	xlateto.d_buf = notes;
31025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	xlateto.d_size = filesz;
31125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	if (elf32_xlatetom (&xlateto, &xlatefrom,
31225b3c049e70834cf33790a28643ab058b507b35cBen Cheng			    ehdr.e32.e_ident[EI_DATA]) == NULL)
31325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  goto done;
31425b3c049e70834cf33790a28643ab058b507b35cBen Cheng      }
31525b3c049e70834cf33790a28643ab058b507b35cBen Cheng
31625b3c049e70834cf33790a28643ab058b507b35cBen Cheng    const GElf_Nhdr *nh = notes;
31725b3c049e70834cf33790a28643ab058b507b35cBen Cheng    while ((const void *) nh < (const void *) notes + filesz)
31825b3c049e70834cf33790a28643ab058b507b35cBen Cheng     {
31925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	const void *note_name = nh + 1;
32025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	const void *note_desc = note_name + NOTE_ALIGN (nh->n_namesz);
32125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	if (unlikely ((size_t) ((const void *) notes + filesz
32225b3c049e70834cf33790a28643ab058b507b35cBen Cheng				- note_desc) < nh->n_descsz))
32325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  break;
32425b3c049e70834cf33790a28643ab058b507b35cBen Cheng
32525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	if (nh->n_type == NT_GNU_BUILD_ID
32625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    && nh->n_descsz > 0
32725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    && nh->n_namesz == sizeof "GNU"
32825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    && !memcmp (note_name, "GNU", sizeof "GNU"))
32925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  {
33025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    build_id_vaddr = note_desc - (const void *) notes + vaddr;
33125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    build_id_len = nh->n_descsz;
33225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    build_id = malloc (nh->n_descsz);
33325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    if (likely (build_id != NULL))
33425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      memcpy (build_id, note_desc, build_id_len);
33525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    break;
33625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  }
33725b3c049e70834cf33790a28643ab058b507b35cBen Cheng
33825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	nh = note_desc + NOTE_ALIGN (nh->n_descsz);
33925b3c049e70834cf33790a28643ab058b507b35cBen Cheng      }
34025b3c049e70834cf33790a28643ab058b507b35cBen Cheng
34125b3c049e70834cf33790a28643ab058b507b35cBen Cheng  done:
34225b3c049e70834cf33790a28643ab058b507b35cBen Cheng    if (notes != data)
34325b3c049e70834cf33790a28643ab058b507b35cBen Cheng      free (notes);
34425b3c049e70834cf33790a28643ab058b507b35cBen Cheng    finish_portion (&data, &data_size);
34525b3c049e70834cf33790a28643ab058b507b35cBen Cheng  }
34625b3c049e70834cf33790a28643ab058b507b35cBen Cheng
34725b3c049e70834cf33790a28643ab058b507b35cBen Cheng  /* Consider each of the program headers we've read from the image.  */
34825b3c049e70834cf33790a28643ab058b507b35cBen Cheng  inline void consider_phdr (GElf_Word type,
34925b3c049e70834cf33790a28643ab058b507b35cBen Cheng			     GElf_Addr vaddr, GElf_Xword memsz,
35025b3c049e70834cf33790a28643ab058b507b35cBen Cheng			     GElf_Off offset, GElf_Xword filesz,
35125b3c049e70834cf33790a28643ab058b507b35cBen Cheng			     GElf_Xword align)
35225b3c049e70834cf33790a28643ab058b507b35cBen Cheng  {
35325b3c049e70834cf33790a28643ab058b507b35cBen Cheng    switch (type)
35425b3c049e70834cf33790a28643ab058b507b35cBen Cheng      {
35525b3c049e70834cf33790a28643ab058b507b35cBen Cheng      case PT_DYNAMIC:
35625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	dyn_vaddr = vaddr;
35725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	dyn_filesz = filesz;
35825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	break;
35925b3c049e70834cf33790a28643ab058b507b35cBen Cheng
36025b3c049e70834cf33790a28643ab058b507b35cBen Cheng      case PT_NOTE:
36125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	/* We calculate from the p_offset of the note segment,
36225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	   because we don't yet know the bias for its p_vaddr.  */
36325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	consider_notes (start + offset, filesz);
36425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	break;
36525b3c049e70834cf33790a28643ab058b507b35cBen Cheng
36625b3c049e70834cf33790a28643ab058b507b35cBen Cheng      case PT_LOAD:
36725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	align = dwfl->segment_align > 1 ? dwfl->segment_align : align ?: 1;
36825b3c049e70834cf33790a28643ab058b507b35cBen Cheng
36925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	GElf_Addr vaddr_end = (vaddr + memsz + align - 1) & -align;
37025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	GElf_Addr filesz_vaddr = filesz < memsz ? vaddr + filesz : vaddr_end;
37125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	GElf_Off filesz_offset = filesz_vaddr - vaddr + offset;
37225b3c049e70834cf33790a28643ab058b507b35cBen Cheng
37325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	if (file_trimmed_end < offset + filesz)
37425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  {
37525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    file_trimmed_end = offset + filesz;
37625b3c049e70834cf33790a28643ab058b507b35cBen Cheng
37725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    /* Trim the last segment so we don't bother with zeros
37825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	       in the last page that are off the end of the file.
37925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	       However, if the extra bit in that page includes the
38025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	       section headers, keep them.  */
38125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    if (shdrs_end <= filesz_offset && shdrs_end > file_trimmed_end)
38225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      {
38325b3c049e70834cf33790a28643ab058b507b35cBen Cheng		filesz += shdrs_end - file_trimmed_end;
38425b3c049e70834cf33790a28643ab058b507b35cBen Cheng		file_trimmed_end = shdrs_end;
38525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      }
38625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  }
38725b3c049e70834cf33790a28643ab058b507b35cBen Cheng
38825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	total_filesz += filesz;
38925b3c049e70834cf33790a28643ab058b507b35cBen Cheng
39025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	if (file_end < filesz_offset)
39125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  {
39225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    file_end = filesz_offset;
39325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    if (filesz_vaddr - start == filesz_offset)
39425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      contiguous = file_end;
39525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  }
39625b3c049e70834cf33790a28643ab058b507b35cBen Cheng
39725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	if (!found_bias && (offset & -align) == 0
39825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    && likely (filesz_offset >= phoff + phnum * phentsize))
39925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  {
40025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    bias = start - vaddr;
40125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    found_bias = true;
40225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  }
40325b3c049e70834cf33790a28643ab058b507b35cBen Cheng
40425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	if ((vaddr & -align) < module_start)
40525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  {
40625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    module_start = vaddr & -align;
40725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    module_address_sync = vaddr + memsz;
40825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  }
40925b3c049e70834cf33790a28643ab058b507b35cBen Cheng
41025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	if (module_end < vaddr_end)
41125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  module_end = vaddr_end;
41225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	break;
41325b3c049e70834cf33790a28643ab058b507b35cBen Cheng      }
41425b3c049e70834cf33790a28643ab058b507b35cBen Cheng  }
41525b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (ehdr.e32.e_ident[EI_CLASS] == ELFCLASS32)
41625b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
41725b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (elf32_xlatetom (&xlateto, &xlatefrom,
41825b3c049e70834cf33790a28643ab058b507b35cBen Cheng			  ehdr.e32.e_ident[EI_DATA]) == NULL)
41925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	found_bias = false;	/* Trigger error check.  */
42025b3c049e70834cf33790a28643ab058b507b35cBen Cheng      else
42125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	for (uint_fast16_t i = 0; i < phnum; ++i)
42225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  consider_phdr (phdrs.p32[i].p_type,
42325b3c049e70834cf33790a28643ab058b507b35cBen Cheng			 phdrs.p32[i].p_vaddr, phdrs.p32[i].p_memsz,
42425b3c049e70834cf33790a28643ab058b507b35cBen Cheng			 phdrs.p32[i].p_offset, phdrs.p32[i].p_filesz,
42525b3c049e70834cf33790a28643ab058b507b35cBen Cheng			 phdrs.p32[i].p_align);
42625b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
42725b3c049e70834cf33790a28643ab058b507b35cBen Cheng  else
42825b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
42925b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (elf64_xlatetom (&xlateto, &xlatefrom,
43025b3c049e70834cf33790a28643ab058b507b35cBen Cheng			  ehdr.e32.e_ident[EI_DATA]) == NULL)
43125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	found_bias = false;	/* Trigger error check.  */
43225b3c049e70834cf33790a28643ab058b507b35cBen Cheng      else
43325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	for (uint_fast16_t i = 0; i < phnum; ++i)
43425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  consider_phdr (phdrs.p64[i].p_type,
43525b3c049e70834cf33790a28643ab058b507b35cBen Cheng			 phdrs.p64[i].p_vaddr, phdrs.p64[i].p_memsz,
43625b3c049e70834cf33790a28643ab058b507b35cBen Cheng			 phdrs.p64[i].p_offset, phdrs.p64[i].p_filesz,
43725b3c049e70834cf33790a28643ab058b507b35cBen Cheng			 phdrs.p64[i].p_align);
43825b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
43925b3c049e70834cf33790a28643ab058b507b35cBen Cheng
44025b3c049e70834cf33790a28643ab058b507b35cBen Cheng  finish_portion (&ph_buffer, &ph_buffer_size);
44125b3c049e70834cf33790a28643ab058b507b35cBen Cheng
44225b3c049e70834cf33790a28643ab058b507b35cBen Cheng  /* We must have seen the segment covering offset 0, or else the ELF
44325b3c049e70834cf33790a28643ab058b507b35cBen Cheng     header we read at START was not produced by these program headers.  */
44425b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (unlikely (!found_bias))
44525b3c049e70834cf33790a28643ab058b507b35cBen Cheng    return finish ();
44625b3c049e70834cf33790a28643ab058b507b35cBen Cheng
44725b3c049e70834cf33790a28643ab058b507b35cBen Cheng  /* Now we know enough to report a module for sure: its bounds.  */
44825b3c049e70834cf33790a28643ab058b507b35cBen Cheng  module_start += bias;
44925b3c049e70834cf33790a28643ab058b507b35cBen Cheng  module_end += bias;
45025b3c049e70834cf33790a28643ab058b507b35cBen Cheng
45125b3c049e70834cf33790a28643ab058b507b35cBen Cheng  dyn_vaddr += bias;
45225b3c049e70834cf33790a28643ab058b507b35cBen Cheng
45325b3c049e70834cf33790a28643ab058b507b35cBen Cheng  /* Our return value now says to skip the segments contained
45425b3c049e70834cf33790a28643ab058b507b35cBen Cheng     within the module.  */
45525b3c049e70834cf33790a28643ab058b507b35cBen Cheng  ndx = addr_segndx (dwfl, segment, module_end, true);
45625b3c049e70834cf33790a28643ab058b507b35cBen Cheng
45725b3c049e70834cf33790a28643ab058b507b35cBen Cheng  /* Examine its .dynamic section to get more interesting details.
45825b3c049e70834cf33790a28643ab058b507b35cBen Cheng     If it has DT_SONAME, we'll use that as the module name.
45925b3c049e70834cf33790a28643ab058b507b35cBen Cheng     If it has a DT_DEBUG, then it's actually a PIE rather than a DSO.
46025b3c049e70834cf33790a28643ab058b507b35cBen Cheng     We need its DT_STRTAB and DT_STRSZ to decipher DT_SONAME,
46125b3c049e70834cf33790a28643ab058b507b35cBen Cheng     and they also tell us the essential portion of the file
46225b3c049e70834cf33790a28643ab058b507b35cBen Cheng     for fetching symbols.  */
46325b3c049e70834cf33790a28643ab058b507b35cBen Cheng  GElf_Addr soname_stroff = 0;
46425b3c049e70834cf33790a28643ab058b507b35cBen Cheng  GElf_Addr dynstr_vaddr = 0;
46525b3c049e70834cf33790a28643ab058b507b35cBen Cheng  GElf_Xword dynstrsz = 0;
46625b3c049e70834cf33790a28643ab058b507b35cBen Cheng  bool execlike = false;
46725b3c049e70834cf33790a28643ab058b507b35cBen Cheng  inline bool consider_dyn (GElf_Sxword tag, GElf_Xword val)
46825b3c049e70834cf33790a28643ab058b507b35cBen Cheng  {
46925b3c049e70834cf33790a28643ab058b507b35cBen Cheng    switch (tag)
47025b3c049e70834cf33790a28643ab058b507b35cBen Cheng      {
47125b3c049e70834cf33790a28643ab058b507b35cBen Cheng      default:
47225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	return false;
47325b3c049e70834cf33790a28643ab058b507b35cBen Cheng
47425b3c049e70834cf33790a28643ab058b507b35cBen Cheng      case DT_DEBUG:
47525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	execlike = true;
47625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	break;
47725b3c049e70834cf33790a28643ab058b507b35cBen Cheng
47825b3c049e70834cf33790a28643ab058b507b35cBen Cheng      case DT_SONAME:
47925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	soname_stroff = val;
48025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	break;
48125b3c049e70834cf33790a28643ab058b507b35cBen Cheng
48225b3c049e70834cf33790a28643ab058b507b35cBen Cheng      case DT_STRTAB:
48325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	dynstr_vaddr = val;
48425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	break;
48525b3c049e70834cf33790a28643ab058b507b35cBen Cheng
48625b3c049e70834cf33790a28643ab058b507b35cBen Cheng      case DT_STRSZ:
48725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	dynstrsz = val;
48825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	break;
48925b3c049e70834cf33790a28643ab058b507b35cBen Cheng      }
49025b3c049e70834cf33790a28643ab058b507b35cBen Cheng
49125b3c049e70834cf33790a28643ab058b507b35cBen Cheng    return soname_stroff != 0 && dynstr_vaddr != 0 && dynstrsz != 0;
49225b3c049e70834cf33790a28643ab058b507b35cBen Cheng  }
49325b3c049e70834cf33790a28643ab058b507b35cBen Cheng
49425b3c049e70834cf33790a28643ab058b507b35cBen Cheng  const size_t dyn_entsize = (ehdr.e32.e_ident[EI_CLASS] == ELFCLASS32
49525b3c049e70834cf33790a28643ab058b507b35cBen Cheng			      ? sizeof (Elf32_Dyn) : sizeof (Elf64_Dyn));
49625b3c049e70834cf33790a28643ab058b507b35cBen Cheng  void *dyn_data = NULL;
49725b3c049e70834cf33790a28643ab058b507b35cBen Cheng  size_t dyn_data_size = 0;
49825b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (dyn_filesz != 0 && dyn_filesz % dyn_entsize == 0
49925b3c049e70834cf33790a28643ab058b507b35cBen Cheng      && ! read_portion (&dyn_data, &dyn_data_size, dyn_vaddr, dyn_filesz))
50025b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
50125b3c049e70834cf33790a28643ab058b507b35cBen Cheng      union
50225b3c049e70834cf33790a28643ab058b507b35cBen Cheng      {
50325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	Elf32_Dyn d32[dyn_filesz / sizeof (Elf32_Dyn)];
50425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	Elf64_Dyn d64[dyn_filesz / sizeof (Elf64_Dyn)];
50525b3c049e70834cf33790a28643ab058b507b35cBen Cheng      } dyn;
50625b3c049e70834cf33790a28643ab058b507b35cBen Cheng
50725b3c049e70834cf33790a28643ab058b507b35cBen Cheng      xlatefrom.d_type = xlateto.d_type = ELF_T_DYN;
50825b3c049e70834cf33790a28643ab058b507b35cBen Cheng      xlatefrom.d_buf = (void *) dyn_data;
50925b3c049e70834cf33790a28643ab058b507b35cBen Cheng      xlatefrom.d_size = dyn_filesz;
51025b3c049e70834cf33790a28643ab058b507b35cBen Cheng      xlateto.d_buf = &dyn;
51125b3c049e70834cf33790a28643ab058b507b35cBen Cheng      xlateto.d_size = sizeof dyn;
51225b3c049e70834cf33790a28643ab058b507b35cBen Cheng
51325b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (ehdr.e32.e_ident[EI_CLASS] == ELFCLASS32)
51425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	{
51525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  if (elf32_xlatetom (&xlateto, &xlatefrom,
51625b3c049e70834cf33790a28643ab058b507b35cBen Cheng			      ehdr.e32.e_ident[EI_DATA]) != NULL)
51725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    for (size_t i = 0; i < dyn_filesz / sizeof dyn.d32[0]; ++i)
51825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      if (consider_dyn (dyn.d32[i].d_tag, dyn.d32[i].d_un.d_val))
51925b3c049e70834cf33790a28643ab058b507b35cBen Cheng		break;
52025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	}
52125b3c049e70834cf33790a28643ab058b507b35cBen Cheng      else
52225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	{
52325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  if (elf64_xlatetom (&xlateto, &xlatefrom,
52425b3c049e70834cf33790a28643ab058b507b35cBen Cheng			      ehdr.e32.e_ident[EI_DATA]) != NULL)
52525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    for (size_t i = 0; i < dyn_filesz / sizeof dyn.d64[0]; ++i)
52625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      if (consider_dyn (dyn.d64[i].d_tag, dyn.d64[i].d_un.d_val))
52725b3c049e70834cf33790a28643ab058b507b35cBen Cheng		break;
52825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	}
52925b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
53025b3c049e70834cf33790a28643ab058b507b35cBen Cheng  finish_portion (&dyn_data, &dyn_data_size);
53125b3c049e70834cf33790a28643ab058b507b35cBen Cheng
53225b3c049e70834cf33790a28643ab058b507b35cBen Cheng  /* We'll use the name passed in or a stupid default if not DT_SONAME.  */
53325b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (name == NULL)
53425b3c049e70834cf33790a28643ab058b507b35cBen Cheng    name = ehdr.e32.e_type == ET_EXEC ? "[exe]" : execlike ? "[pie]" : "[dso]";
53525b3c049e70834cf33790a28643ab058b507b35cBen Cheng
53625b3c049e70834cf33790a28643ab058b507b35cBen Cheng  void *soname = NULL;
53725b3c049e70834cf33790a28643ab058b507b35cBen Cheng  size_t soname_size = 0;
53825b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (dynstrsz != 0 && dynstr_vaddr != 0)
53925b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
54025b3c049e70834cf33790a28643ab058b507b35cBen Cheng      /* We know the bounds of the .dynstr section.
54125b3c049e70834cf33790a28643ab058b507b35cBen Cheng
54225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	 The DYNSTR_VADDR pointer comes from the .dynamic section
54325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	 (DT_STRTAB, detected above).  Ordinarily the dynamic linker
54425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	 will have adjusted this pointer in place so it's now an
54525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	 absolute address.  But sometimes .dynamic is read-only (in
54625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	 vDSOs and odd architectures), and sometimes the adjustment
54725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	 just hasn't happened yet in the memory image we looked at.
54825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	 So treat DYNSTR_VADDR as an absolute address if it falls
54925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	 within the module bounds, or try applying the phdr bias
55025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	 when that adjusts it to fall within the module bounds.  */
55125b3c049e70834cf33790a28643ab058b507b35cBen Cheng
55225b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if ((dynstr_vaddr < module_start || dynstr_vaddr >= module_end)
55325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  && dynstr_vaddr + bias >= module_start
55425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  && dynstr_vaddr + bias < module_end)
55525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	dynstr_vaddr += bias;
55625b3c049e70834cf33790a28643ab058b507b35cBen Cheng
55725b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (unlikely (dynstr_vaddr + dynstrsz > module_end))
55825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	dynstrsz = 0;
55925b3c049e70834cf33790a28643ab058b507b35cBen Cheng
56025b3c049e70834cf33790a28643ab058b507b35cBen Cheng      /* Try to get the DT_SONAME string.  */
56125b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (soname_stroff != 0 && soname_stroff + 1 < dynstrsz
56225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  && ! read_portion (&soname, &soname_size,
56325b3c049e70834cf33790a28643ab058b507b35cBen Cheng			     dynstr_vaddr + soname_stroff, 0))
56425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	name = soname;
56525b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
56625b3c049e70834cf33790a28643ab058b507b35cBen Cheng
56725b3c049e70834cf33790a28643ab058b507b35cBen Cheng  /* Now that we have chosen the module's name and bounds, report it.
56825b3c049e70834cf33790a28643ab058b507b35cBen Cheng     If we found a build ID, report that too.  */
56925b3c049e70834cf33790a28643ab058b507b35cBen Cheng
57025b3c049e70834cf33790a28643ab058b507b35cBen Cheng  Dwfl_Module *mod = INTUSE(dwfl_report_module) (dwfl, name,
57125b3c049e70834cf33790a28643ab058b507b35cBen Cheng						 module_start, module_end);
57225b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (likely (mod != NULL) && build_id != NULL
57325b3c049e70834cf33790a28643ab058b507b35cBen Cheng      && unlikely (INTUSE(dwfl_module_report_build_id) (mod,
57425b3c049e70834cf33790a28643ab058b507b35cBen Cheng							build_id,
57525b3c049e70834cf33790a28643ab058b507b35cBen Cheng							build_id_len,
57625b3c049e70834cf33790a28643ab058b507b35cBen Cheng							build_id_vaddr)))
57725b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
57825b3c049e70834cf33790a28643ab058b507b35cBen Cheng      mod->gc = true;
57925b3c049e70834cf33790a28643ab058b507b35cBen Cheng      mod = NULL;
58025b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
58125b3c049e70834cf33790a28643ab058b507b35cBen Cheng
58225b3c049e70834cf33790a28643ab058b507b35cBen Cheng  /* At this point we do not need BUILD_ID or NAME any more.
58325b3c049e70834cf33790a28643ab058b507b35cBen Cheng     They have been copied.  */
58425b3c049e70834cf33790a28643ab058b507b35cBen Cheng  free (build_id);
58525b3c049e70834cf33790a28643ab058b507b35cBen Cheng  finish_portion (&soname, &soname_size);
58625b3c049e70834cf33790a28643ab058b507b35cBen Cheng
58725b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (unlikely (mod == NULL))
58825b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
58925b3c049e70834cf33790a28643ab058b507b35cBen Cheng      ndx = -1;
59025b3c049e70834cf33790a28643ab058b507b35cBen Cheng      return finish ();
59125b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
59225b3c049e70834cf33790a28643ab058b507b35cBen Cheng
59325b3c049e70834cf33790a28643ab058b507b35cBen Cheng  /* We have reported the module.  Now let the caller decide whether we
59425b3c049e70834cf33790a28643ab058b507b35cBen Cheng     should read the whole thing in right now.  */
59525b3c049e70834cf33790a28643ab058b507b35cBen Cheng
59625b3c049e70834cf33790a28643ab058b507b35cBen Cheng  const GElf_Off cost = (contiguous < file_trimmed_end ? total_filesz
59725b3c049e70834cf33790a28643ab058b507b35cBen Cheng			 : buffer_available >= contiguous ? 0
59825b3c049e70834cf33790a28643ab058b507b35cBen Cheng			 : contiguous - buffer_available);
59925b3c049e70834cf33790a28643ab058b507b35cBen Cheng  const GElf_Off worthwhile = ((dynstr_vaddr == 0 || dynstrsz == 0) ? 0
60025b3c049e70834cf33790a28643ab058b507b35cBen Cheng			       : dynstr_vaddr + dynstrsz - start);
60125b3c049e70834cf33790a28643ab058b507b35cBen Cheng  const GElf_Off whole = MAX (file_trimmed_end, shdrs_end);
60225b3c049e70834cf33790a28643ab058b507b35cBen Cheng
60325b3c049e70834cf33790a28643ab058b507b35cBen Cheng  Elf *elf = NULL;
60425b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if ((*read_eagerly) (MODCB_ARGS (mod), &buffer, &buffer_available,
60525b3c049e70834cf33790a28643ab058b507b35cBen Cheng		       cost, worthwhile, whole, contiguous,
60625b3c049e70834cf33790a28643ab058b507b35cBen Cheng		       read_eagerly_arg, &elf)
60725b3c049e70834cf33790a28643ab058b507b35cBen Cheng      && elf == NULL)
60825b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
60925b3c049e70834cf33790a28643ab058b507b35cBen Cheng      /* The caller wants to read the whole file in right now, but hasn't
61025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	 done it for us.  Fill in a local image of the virtual file.  */
61125b3c049e70834cf33790a28643ab058b507b35cBen Cheng
61225b3c049e70834cf33790a28643ab058b507b35cBen Cheng      void *contents = calloc (1, file_trimmed_end);
61325b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (unlikely (contents == NULL))
61425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	return finish ();
61525b3c049e70834cf33790a28643ab058b507b35cBen Cheng
61625b3c049e70834cf33790a28643ab058b507b35cBen Cheng      inline void final_read (size_t offset, GElf_Addr vaddr, size_t size)
61725b3c049e70834cf33790a28643ab058b507b35cBen Cheng      {
61825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	void *into = contents + offset;
61925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	size_t read_size = size;
62025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	(void) segment_read (addr_segndx (dwfl, segment, vaddr, false),
62125b3c049e70834cf33790a28643ab058b507b35cBen Cheng			     &into, &read_size, vaddr, size);
62225b3c049e70834cf33790a28643ab058b507b35cBen Cheng      }
62325b3c049e70834cf33790a28643ab058b507b35cBen Cheng
62425b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (contiguous < file_trimmed_end)
62525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	{
62625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  /* We can't use the memory image verbatim as the file image.
62725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	     So we'll be reading into a local image of the virtual file.  */
62825b3c049e70834cf33790a28643ab058b507b35cBen Cheng
62925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  inline void read_phdr (GElf_Word type, GElf_Addr vaddr,
63025b3c049e70834cf33790a28643ab058b507b35cBen Cheng				 GElf_Off offset, GElf_Xword filesz)
63125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  {
63225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    if (type == PT_LOAD)
63325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      final_read (offset, vaddr + bias, filesz);
63425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  }
63525b3c049e70834cf33790a28643ab058b507b35cBen Cheng
63625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  if (ehdr.e32.e_ident[EI_CLASS] == ELFCLASS32)
63725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    for (uint_fast16_t i = 0; i < phnum; ++i)
63825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      read_phdr (phdrs.p32[i].p_type, phdrs.p32[i].p_vaddr,
63925b3c049e70834cf33790a28643ab058b507b35cBen Cheng			 phdrs.p32[i].p_offset, phdrs.p32[i].p_filesz);
64025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  else
64125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    for (uint_fast16_t i = 0; i < phnum; ++i)
64225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      read_phdr (phdrs.p64[i].p_type, phdrs.p64[i].p_vaddr,
64325b3c049e70834cf33790a28643ab058b507b35cBen Cheng			 phdrs.p64[i].p_offset, phdrs.p64[i].p_filesz);
64425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	}
64525b3c049e70834cf33790a28643ab058b507b35cBen Cheng      else
64625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	{
64725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  /* The whole file sits contiguous in memory,
64825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	     but the caller didn't want to just do it.  */
64925b3c049e70834cf33790a28643ab058b507b35cBen Cheng
65025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  const size_t have = MIN (buffer_available, file_trimmed_end);
65125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  memcpy (contents, buffer, have);
65225b3c049e70834cf33790a28643ab058b507b35cBen Cheng
65325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  if (have < file_trimmed_end)
65425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    final_read (have, start + have, file_trimmed_end - have);
65525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	}
65625b3c049e70834cf33790a28643ab058b507b35cBen Cheng
65725b3c049e70834cf33790a28643ab058b507b35cBen Cheng      elf = elf_memory (contents, file_trimmed_end);
65825b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (unlikely (elf == NULL))
65925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	free (contents);
66025b3c049e70834cf33790a28643ab058b507b35cBen Cheng      else
66125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	elf->flags |= ELF_F_MALLOCED;
66225b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
66325b3c049e70834cf33790a28643ab058b507b35cBen Cheng
66425b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (elf != NULL)
66525b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
66625b3c049e70834cf33790a28643ab058b507b35cBen Cheng      /* Install the file in the module.  */
66725b3c049e70834cf33790a28643ab058b507b35cBen Cheng      mod->main.elf = elf;
66825b3c049e70834cf33790a28643ab058b507b35cBen Cheng      mod->main.vaddr = module_start - bias;
66925b3c049e70834cf33790a28643ab058b507b35cBen Cheng      mod->main.address_sync = module_address_sync;
67025b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
67125b3c049e70834cf33790a28643ab058b507b35cBen Cheng
67225b3c049e70834cf33790a28643ab058b507b35cBen Cheng  return finish ();
67325b3c049e70834cf33790a28643ab058b507b35cBen Cheng}
674