125b3c049e70834cf33790a28643ab058b507b35cBen Cheng/* Report modules by examining dynamic linker data structures.
203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes   Copyright (C) 2008-2014 Red Hat, Inc.
303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes   This file is part of elfutils.
425b3c049e70834cf33790a28643ab058b507b35cBen Cheng
503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes   This file is free software; you can redistribute it and/or modify
603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes   it under the terms of either
725b3c049e70834cf33790a28643ab058b507b35cBen Cheng
803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes     * the GNU Lesser General Public License as published by the Free
903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes       Software Foundation; either version 3 of the License, or (at
1003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes       your option) any later version
1103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
1203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes   or
1303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
1403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes     * the GNU General Public License as published by the Free
1503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes       Software Foundation; either version 2 of the License, or (at
1603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes       your option) any later version
1703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
1803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes   or both in parallel, as here.
1903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
2003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes   elfutils is distributed in the hope that it will be useful, but
2125b3c049e70834cf33790a28643ab058b507b35cBen Cheng   WITHOUT ANY WARRANTY; without even the implied warranty of
2225b3c049e70834cf33790a28643ab058b507b35cBen Cheng   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
2325b3c049e70834cf33790a28643ab058b507b35cBen Cheng   General Public License for more details.
2425b3c049e70834cf33790a28643ab058b507b35cBen Cheng
2503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes   You should have received copies of the GNU General Public License and
2603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes   the GNU Lesser General Public License along with this program.  If
2703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes   not, see <http://www.gnu.org/licenses/>.  */
2825b3c049e70834cf33790a28643ab058b507b35cBen Cheng
2925b3c049e70834cf33790a28643ab058b507b35cBen Cheng#include <config.h>
3025b3c049e70834cf33790a28643ab058b507b35cBen Cheng#include "libdwflP.h"
3103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes#include "../libdw/memory-access.h"
3203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes#include "system.h"
3325b3c049e70834cf33790a28643ab058b507b35cBen Cheng
3425b3c049e70834cf33790a28643ab058b507b35cBen Cheng#include <byteswap.h>
3525b3c049e70834cf33790a28643ab058b507b35cBen Cheng#include <endian.h>
3603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes#include <fcntl.h>
3725b3c049e70834cf33790a28643ab058b507b35cBen Cheng
3825b3c049e70834cf33790a28643ab058b507b35cBen Cheng/* This element is always provided and always has a constant value.
3925b3c049e70834cf33790a28643ab058b507b35cBen Cheng   This makes it an easy thing to scan for to discern the format.  */
4025b3c049e70834cf33790a28643ab058b507b35cBen Cheng#define PROBE_TYPE	AT_PHENT
4125b3c049e70834cf33790a28643ab058b507b35cBen Cheng#define PROBE_VAL32	sizeof (Elf32_Phdr)
4225b3c049e70834cf33790a28643ab058b507b35cBen Cheng#define PROBE_VAL64	sizeof (Elf64_Phdr)
4325b3c049e70834cf33790a28643ab058b507b35cBen Cheng
4425b3c049e70834cf33790a28643ab058b507b35cBen Cheng
4525b3c049e70834cf33790a28643ab058b507b35cBen Cheng/* Examine an auxv data block and determine its format.
4625b3c049e70834cf33790a28643ab058b507b35cBen Cheng   Return true iff we figured it out.  */
4725b3c049e70834cf33790a28643ab058b507b35cBen Chengstatic bool
4825b3c049e70834cf33790a28643ab058b507b35cBen Chengauxv_format_probe (const void *auxv, size_t size,
4925b3c049e70834cf33790a28643ab058b507b35cBen Cheng		   uint_fast8_t *elfclass, uint_fast8_t *elfdata)
5025b3c049e70834cf33790a28643ab058b507b35cBen Cheng{
5125b3c049e70834cf33790a28643ab058b507b35cBen Cheng  const union
5225b3c049e70834cf33790a28643ab058b507b35cBen Cheng  {
5325b3c049e70834cf33790a28643ab058b507b35cBen Cheng    char buf[size];
5425b3c049e70834cf33790a28643ab058b507b35cBen Cheng    Elf32_auxv_t a32[size / sizeof (Elf32_auxv_t)];
5525b3c049e70834cf33790a28643ab058b507b35cBen Cheng    Elf64_auxv_t a64[size / sizeof (Elf64_auxv_t)];
5625b3c049e70834cf33790a28643ab058b507b35cBen Cheng  } *u = auxv;
5725b3c049e70834cf33790a28643ab058b507b35cBen Cheng
5825b3c049e70834cf33790a28643ab058b507b35cBen Cheng  inline bool check64 (size_t i)
5925b3c049e70834cf33790a28643ab058b507b35cBen Cheng  {
6003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    /* The AUXV pointer might not even be naturally aligned for 64-bit
6103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes       data, because note payloads in a core file are not aligned.
6203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes       But we assume the data is 32-bit aligned.  */
6303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
6403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    uint64_t type = read_8ubyte_unaligned_noncvt (&u->a64[i].a_type);
6503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    uint64_t val = read_8ubyte_unaligned_noncvt (&u->a64[i].a_un.a_val);
6603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
6703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    if (type == BE64 (PROBE_TYPE)
6803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	&& val == BE64 (PROBE_VAL64))
6925b3c049e70834cf33790a28643ab058b507b35cBen Cheng      {
7025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	*elfdata = ELFDATA2MSB;
7125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	return true;
7225b3c049e70834cf33790a28643ab058b507b35cBen Cheng      }
7325b3c049e70834cf33790a28643ab058b507b35cBen Cheng
7403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    if (type == LE64 (PROBE_TYPE)
7503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	&& val == LE64 (PROBE_VAL64))
7625b3c049e70834cf33790a28643ab058b507b35cBen Cheng      {
7725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	*elfdata = ELFDATA2LSB;
7825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	return true;
7925b3c049e70834cf33790a28643ab058b507b35cBen Cheng      }
8025b3c049e70834cf33790a28643ab058b507b35cBen Cheng
8125b3c049e70834cf33790a28643ab058b507b35cBen Cheng    return false;
8225b3c049e70834cf33790a28643ab058b507b35cBen Cheng  }
8325b3c049e70834cf33790a28643ab058b507b35cBen Cheng
8425b3c049e70834cf33790a28643ab058b507b35cBen Cheng  inline bool check32 (size_t i)
8525b3c049e70834cf33790a28643ab058b507b35cBen Cheng  {
8625b3c049e70834cf33790a28643ab058b507b35cBen Cheng    if (u->a32[i].a_type == BE32 (PROBE_TYPE)
8725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	&& u->a32[i].a_un.a_val == BE32 (PROBE_VAL32))
8825b3c049e70834cf33790a28643ab058b507b35cBen Cheng      {
8925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	*elfdata = ELFDATA2MSB;
9025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	return true;
9125b3c049e70834cf33790a28643ab058b507b35cBen Cheng      }
9225b3c049e70834cf33790a28643ab058b507b35cBen Cheng
9325b3c049e70834cf33790a28643ab058b507b35cBen Cheng    if (u->a32[i].a_type == LE32 (PROBE_TYPE)
9425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	&& u->a32[i].a_un.a_val == LE32 (PROBE_VAL32))
9525b3c049e70834cf33790a28643ab058b507b35cBen Cheng      {
9625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	*elfdata = ELFDATA2LSB;
9725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	return true;
9825b3c049e70834cf33790a28643ab058b507b35cBen Cheng      }
9925b3c049e70834cf33790a28643ab058b507b35cBen Cheng
10025b3c049e70834cf33790a28643ab058b507b35cBen Cheng    return false;
10125b3c049e70834cf33790a28643ab058b507b35cBen Cheng  }
10225b3c049e70834cf33790a28643ab058b507b35cBen Cheng
10325b3c049e70834cf33790a28643ab058b507b35cBen Cheng  for (size_t i = 0; i < size / sizeof (Elf64_auxv_t); ++i)
10425b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
10525b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (check64 (i))
10625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	{
10725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  *elfclass = ELFCLASS64;
10825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  return true;
10925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	}
11025b3c049e70834cf33790a28643ab058b507b35cBen Cheng
11125b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (check32 (i * 2) || check32 (i * 2 + 1))
11225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	{
11325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  *elfclass = ELFCLASS32;
11425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  return true;
11525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	}
11625b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
11725b3c049e70834cf33790a28643ab058b507b35cBen Cheng
11825b3c049e70834cf33790a28643ab058b507b35cBen Cheng  return false;
11925b3c049e70834cf33790a28643ab058b507b35cBen Cheng}
12025b3c049e70834cf33790a28643ab058b507b35cBen Cheng
12125b3c049e70834cf33790a28643ab058b507b35cBen Cheng/* This is a Dwfl_Memory_Callback that wraps another memory callback.
12225b3c049e70834cf33790a28643ab058b507b35cBen Cheng   If the underlying callback cannot fill the data, then this will
12325b3c049e70834cf33790a28643ab058b507b35cBen Cheng   fall back to fetching data from module files.  */
12425b3c049e70834cf33790a28643ab058b507b35cBen Cheng
12525b3c049e70834cf33790a28643ab058b507b35cBen Chengstruct integrated_memory_callback
12625b3c049e70834cf33790a28643ab058b507b35cBen Cheng{
12725b3c049e70834cf33790a28643ab058b507b35cBen Cheng  Dwfl_Memory_Callback *memory_callback;
12825b3c049e70834cf33790a28643ab058b507b35cBen Cheng  void *memory_callback_arg;
12925b3c049e70834cf33790a28643ab058b507b35cBen Cheng  void *buffer;
13025b3c049e70834cf33790a28643ab058b507b35cBen Cheng};
13125b3c049e70834cf33790a28643ab058b507b35cBen Cheng
13225b3c049e70834cf33790a28643ab058b507b35cBen Chengstatic bool
13325b3c049e70834cf33790a28643ab058b507b35cBen Chengintegrated_memory_callback (Dwfl *dwfl, int ndx,
13425b3c049e70834cf33790a28643ab058b507b35cBen Cheng			       void **buffer, size_t *buffer_available,
13525b3c049e70834cf33790a28643ab058b507b35cBen Cheng			       GElf_Addr vaddr,
13625b3c049e70834cf33790a28643ab058b507b35cBen Cheng			       size_t minread,
13725b3c049e70834cf33790a28643ab058b507b35cBen Cheng			       void *arg)
13825b3c049e70834cf33790a28643ab058b507b35cBen Cheng{
13925b3c049e70834cf33790a28643ab058b507b35cBen Cheng  struct integrated_memory_callback *info = arg;
14025b3c049e70834cf33790a28643ab058b507b35cBen Cheng
14125b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (ndx == -1)
14225b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
14325b3c049e70834cf33790a28643ab058b507b35cBen Cheng      /* Called for cleanup.  */
14425b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (info->buffer != NULL)
14525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	{
14625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  /* The last probe buffer came from the underlying callback.
14725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	     Let it do its cleanup.  */
14825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  assert (*buffer == info->buffer); /* XXX */
14925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  *buffer = info->buffer;
15025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  info->buffer = NULL;
15125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  return (*info->memory_callback) (dwfl, ndx, buffer, buffer_available,
15225b3c049e70834cf33790a28643ab058b507b35cBen Cheng					   vaddr, minread,
15325b3c049e70834cf33790a28643ab058b507b35cBen Cheng					   info->memory_callback_arg);
15425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	}
15525b3c049e70834cf33790a28643ab058b507b35cBen Cheng      *buffer = NULL;
15625b3c049e70834cf33790a28643ab058b507b35cBen Cheng      *buffer_available = 0;
15725b3c049e70834cf33790a28643ab058b507b35cBen Cheng      return false;
15825b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
15925b3c049e70834cf33790a28643ab058b507b35cBen Cheng
16025b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (*buffer != NULL)
16125b3c049e70834cf33790a28643ab058b507b35cBen Cheng    /* For a final-read request, we only use the underlying callback.  */
16225b3c049e70834cf33790a28643ab058b507b35cBen Cheng    return (*info->memory_callback) (dwfl, ndx, buffer, buffer_available,
16325b3c049e70834cf33790a28643ab058b507b35cBen Cheng				     vaddr, minread, info->memory_callback_arg);
16425b3c049e70834cf33790a28643ab058b507b35cBen Cheng
16525b3c049e70834cf33790a28643ab058b507b35cBen Cheng  /* Let the underlying callback try to fill this request.  */
16625b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if ((*info->memory_callback) (dwfl, ndx, &info->buffer, buffer_available,
16725b3c049e70834cf33790a28643ab058b507b35cBen Cheng				vaddr, minread, info->memory_callback_arg))
16825b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
16925b3c049e70834cf33790a28643ab058b507b35cBen Cheng      *buffer = info->buffer;
17025b3c049e70834cf33790a28643ab058b507b35cBen Cheng      return true;
17125b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
17225b3c049e70834cf33790a28643ab058b507b35cBen Cheng
17325b3c049e70834cf33790a28643ab058b507b35cBen Cheng  /* Now look for module text covering this address.  */
17425b3c049e70834cf33790a28643ab058b507b35cBen Cheng
17525b3c049e70834cf33790a28643ab058b507b35cBen Cheng  Dwfl_Module *mod;
17625b3c049e70834cf33790a28643ab058b507b35cBen Cheng  (void) INTUSE(dwfl_addrsegment) (dwfl, vaddr, &mod);
17725b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (mod == NULL)
17825b3c049e70834cf33790a28643ab058b507b35cBen Cheng    return false;
17925b3c049e70834cf33790a28643ab058b507b35cBen Cheng
18025b3c049e70834cf33790a28643ab058b507b35cBen Cheng  Dwarf_Addr bias;
18125b3c049e70834cf33790a28643ab058b507b35cBen Cheng  Elf_Scn *scn = INTUSE(dwfl_module_address_section) (mod, &vaddr, &bias);
18225b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (unlikely (scn == NULL))
18325b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
18425b3c049e70834cf33790a28643ab058b507b35cBen Cheng#if 0 // XXX would have to handle ndx=-1 cleanup calls passed down.
18525b3c049e70834cf33790a28643ab058b507b35cBen Cheng      /* If we have no sections we can try to fill it from the module file
18625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	 based on its phdr mappings.  */
18725b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (likely (mod->e_type != ET_REL) && mod->main.elf != NULL)
18825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	return INTUSE(dwfl_elf_phdr_memory_callback)
18925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  (dwfl, 0, buffer, buffer_available,
19025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	   vaddr - mod->main.bias, minread, mod->main.elf);
19125b3c049e70834cf33790a28643ab058b507b35cBen Cheng#endif
19225b3c049e70834cf33790a28643ab058b507b35cBen Cheng      return false;
19325b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
19425b3c049e70834cf33790a28643ab058b507b35cBen Cheng
19525b3c049e70834cf33790a28643ab058b507b35cBen Cheng  Elf_Data *data = elf_rawdata (scn, NULL);
19625b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (unlikely (data == NULL))
19725b3c049e70834cf33790a28643ab058b507b35cBen Cheng    // XXX throw error?
19825b3c049e70834cf33790a28643ab058b507b35cBen Cheng    return false;
19925b3c049e70834cf33790a28643ab058b507b35cBen Cheng
20025b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (unlikely (data->d_size < vaddr))
20125b3c049e70834cf33790a28643ab058b507b35cBen Cheng    return false;
20225b3c049e70834cf33790a28643ab058b507b35cBen Cheng
20325b3c049e70834cf33790a28643ab058b507b35cBen Cheng  /* Provide as much data as we have.  */
20425b3c049e70834cf33790a28643ab058b507b35cBen Cheng  void *contents = data->d_buf + vaddr;
20525b3c049e70834cf33790a28643ab058b507b35cBen Cheng  size_t avail = data->d_size - vaddr;
20625b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (unlikely (avail < minread))
20725b3c049e70834cf33790a28643ab058b507b35cBen Cheng    return false;
20825b3c049e70834cf33790a28643ab058b507b35cBen Cheng
20925b3c049e70834cf33790a28643ab058b507b35cBen Cheng  /* If probing for a string, make sure it's terminated.  */
21025b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (minread == 0 && unlikely (memchr (contents, '\0', avail) == NULL))
21125b3c049e70834cf33790a28643ab058b507b35cBen Cheng    return false;
21225b3c049e70834cf33790a28643ab058b507b35cBen Cheng
21325b3c049e70834cf33790a28643ab058b507b35cBen Cheng  /* We have it! */
21425b3c049e70834cf33790a28643ab058b507b35cBen Cheng  *buffer = contents;
21525b3c049e70834cf33790a28643ab058b507b35cBen Cheng  *buffer_available = avail;
21625b3c049e70834cf33790a28643ab058b507b35cBen Cheng  return true;
21725b3c049e70834cf33790a28643ab058b507b35cBen Cheng}
21825b3c049e70834cf33790a28643ab058b507b35cBen Cheng
21925b3c049e70834cf33790a28643ab058b507b35cBen Chengstatic size_t
22025b3c049e70834cf33790a28643ab058b507b35cBen Chengaddrsize (uint_fast8_t elfclass)
22125b3c049e70834cf33790a28643ab058b507b35cBen Cheng{
22225b3c049e70834cf33790a28643ab058b507b35cBen Cheng  return elfclass * 4;
22325b3c049e70834cf33790a28643ab058b507b35cBen Cheng}
22425b3c049e70834cf33790a28643ab058b507b35cBen Cheng
22525b3c049e70834cf33790a28643ab058b507b35cBen Cheng/* Report a module for each struct link_map in the linked list at r_map
22603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes   in the struct r_debug at R_DEBUG_VADDR.  For r_debug_info description
22703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes   see dwfl_link_map_report in libdwflP.h.  If R_DEBUG_INFO is not NULL then no
22803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes   modules get added to DWFL, caller has to add them from filled in
22903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes   R_DEBUG_INFO.
23025b3c049e70834cf33790a28643ab058b507b35cBen Cheng
23125b3c049e70834cf33790a28643ab058b507b35cBen Cheng   For each link_map entry, if an existing module resides at its address,
23225b3c049e70834cf33790a28643ab058b507b35cBen Cheng   this just modifies that module's name and suggested file name.  If
23325b3c049e70834cf33790a28643ab058b507b35cBen Cheng   no such module exists, this calls dwfl_report_elf on the l_name string.
23425b3c049e70834cf33790a28643ab058b507b35cBen Cheng
23525b3c049e70834cf33790a28643ab058b507b35cBen Cheng   Returns the number of modules found, or -1 for errors.  */
23625b3c049e70834cf33790a28643ab058b507b35cBen Cheng
23725b3c049e70834cf33790a28643ab058b507b35cBen Chengstatic int
23825b3c049e70834cf33790a28643ab058b507b35cBen Chengreport_r_debug (uint_fast8_t elfclass, uint_fast8_t elfdata,
23925b3c049e70834cf33790a28643ab058b507b35cBen Cheng		Dwfl *dwfl, GElf_Addr r_debug_vaddr,
24025b3c049e70834cf33790a28643ab058b507b35cBen Cheng		Dwfl_Memory_Callback *memory_callback,
24103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		void *memory_callback_arg,
24203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		struct r_debug_info *r_debug_info)
24325b3c049e70834cf33790a28643ab058b507b35cBen Cheng{
24425b3c049e70834cf33790a28643ab058b507b35cBen Cheng  /* Skip r_version, to aligned r_map field.  */
24525b3c049e70834cf33790a28643ab058b507b35cBen Cheng  GElf_Addr read_vaddr = r_debug_vaddr + addrsize (elfclass);
24625b3c049e70834cf33790a28643ab058b507b35cBen Cheng
24725b3c049e70834cf33790a28643ab058b507b35cBen Cheng  void *buffer = NULL;
24825b3c049e70834cf33790a28643ab058b507b35cBen Cheng  size_t buffer_available = 0;
24925b3c049e70834cf33790a28643ab058b507b35cBen Cheng  inline int release_buffer (int result)
25025b3c049e70834cf33790a28643ab058b507b35cBen Cheng  {
25125b3c049e70834cf33790a28643ab058b507b35cBen Cheng    if (buffer != NULL)
25225b3c049e70834cf33790a28643ab058b507b35cBen Cheng      (void) (*memory_callback) (dwfl, -1, &buffer, &buffer_available, 0, 0,
25325b3c049e70834cf33790a28643ab058b507b35cBen Cheng				 memory_callback_arg);
25425b3c049e70834cf33790a28643ab058b507b35cBen Cheng    return result;
25525b3c049e70834cf33790a28643ab058b507b35cBen Cheng  }
25625b3c049e70834cf33790a28643ab058b507b35cBen Cheng
25725b3c049e70834cf33790a28643ab058b507b35cBen Cheng  GElf_Addr addrs[4];
25825b3c049e70834cf33790a28643ab058b507b35cBen Cheng  inline bool read_addrs (GElf_Addr vaddr, size_t n)
25925b3c049e70834cf33790a28643ab058b507b35cBen Cheng  {
26025b3c049e70834cf33790a28643ab058b507b35cBen Cheng    size_t nb = n * addrsize (elfclass); /* Address words -> bytes to read.  */
26125b3c049e70834cf33790a28643ab058b507b35cBen Cheng
26225b3c049e70834cf33790a28643ab058b507b35cBen Cheng    /* Read a new buffer if the old one doesn't cover these words.  */
26325b3c049e70834cf33790a28643ab058b507b35cBen Cheng    if (buffer == NULL
26425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	|| vaddr < read_vaddr
26525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	|| vaddr - read_vaddr + nb > buffer_available)
26625b3c049e70834cf33790a28643ab058b507b35cBen Cheng      {
26725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	release_buffer (0);
26825b3c049e70834cf33790a28643ab058b507b35cBen Cheng
26925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	read_vaddr = vaddr;
27025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	int segndx = INTUSE(dwfl_addrsegment) (dwfl, vaddr, NULL);
27125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	if (unlikely (segndx < 0)
27225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    || unlikely (! (*memory_callback) (dwfl, segndx,
27325b3c049e70834cf33790a28643ab058b507b35cBen Cheng					       &buffer, &buffer_available,
27425b3c049e70834cf33790a28643ab058b507b35cBen Cheng					       vaddr, nb, memory_callback_arg)))
27525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  return true;
27625b3c049e70834cf33790a28643ab058b507b35cBen Cheng      }
27725b3c049e70834cf33790a28643ab058b507b35cBen Cheng
27825b3c049e70834cf33790a28643ab058b507b35cBen Cheng    const union
27925b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
28025b3c049e70834cf33790a28643ab058b507b35cBen Cheng      Elf32_Addr a32[n];
28125b3c049e70834cf33790a28643ab058b507b35cBen Cheng      Elf64_Addr a64[n];
28225b3c049e70834cf33790a28643ab058b507b35cBen Cheng    } *in = vaddr - read_vaddr + buffer;
28325b3c049e70834cf33790a28643ab058b507b35cBen Cheng
28425b3c049e70834cf33790a28643ab058b507b35cBen Cheng    if (elfclass == ELFCLASS32)
28525b3c049e70834cf33790a28643ab058b507b35cBen Cheng      {
28625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	if (elfdata == ELFDATA2MSB)
28725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  for (size_t i = 0; i < n; ++i)
28825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    addrs[i] = BE32 (in->a32[i]);
28925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	else
29025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  for (size_t i = 0; i < n; ++i)
29125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    addrs[i] = LE32 (in->a32[i]);
29225b3c049e70834cf33790a28643ab058b507b35cBen Cheng      }
29325b3c049e70834cf33790a28643ab058b507b35cBen Cheng    else
29425b3c049e70834cf33790a28643ab058b507b35cBen Cheng      {
29525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	if (elfdata == ELFDATA2MSB)
29625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  for (size_t i = 0; i < n; ++i)
29725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    addrs[i] = BE64 (in->a64[i]);
29825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	else
29925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  for (size_t i = 0; i < n; ++i)
30025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    addrs[i] = LE64 (in->a64[i]);
30125b3c049e70834cf33790a28643ab058b507b35cBen Cheng      }
30225b3c049e70834cf33790a28643ab058b507b35cBen Cheng
30325b3c049e70834cf33790a28643ab058b507b35cBen Cheng    return false;
30425b3c049e70834cf33790a28643ab058b507b35cBen Cheng  }
30525b3c049e70834cf33790a28643ab058b507b35cBen Cheng
30625b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (unlikely (read_addrs (read_vaddr, 1)))
30725b3c049e70834cf33790a28643ab058b507b35cBen Cheng    return release_buffer (-1);
30825b3c049e70834cf33790a28643ab058b507b35cBen Cheng
30925b3c049e70834cf33790a28643ab058b507b35cBen Cheng  GElf_Addr next = addrs[0];
31025b3c049e70834cf33790a28643ab058b507b35cBen Cheng
31125b3c049e70834cf33790a28643ab058b507b35cBen Cheng  Dwfl_Module **lastmodp = &dwfl->modulelist;
31225b3c049e70834cf33790a28643ab058b507b35cBen Cheng  int result = 0;
31325b3c049e70834cf33790a28643ab058b507b35cBen Cheng
31425b3c049e70834cf33790a28643ab058b507b35cBen Cheng  /* There can't be more elements in the link_map list than there are
31525b3c049e70834cf33790a28643ab058b507b35cBen Cheng     segments.  DWFL->lookup_elts is probably twice that number, so it
31625b3c049e70834cf33790a28643ab058b507b35cBen Cheng     is certainly above the upper bound.  If we iterate too many times,
31725b3c049e70834cf33790a28643ab058b507b35cBen Cheng     there must be a loop in the pointers due to link_map clobberation.  */
31825b3c049e70834cf33790a28643ab058b507b35cBen Cheng  size_t iterations = 0;
31925b3c049e70834cf33790a28643ab058b507b35cBen Cheng  while (next != 0 && ++iterations < dwfl->lookup_elts)
32025b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
32125b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (read_addrs (next, 4))
32225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	return release_buffer (-1);
32325b3c049e70834cf33790a28643ab058b507b35cBen Cheng
32403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      /* Unused: l_addr is the difference between the address in memory
32503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes         and the ELF file when the core was created. We need to
32603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes         recalculate the difference below because the ELF file we use
32703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes         might be differently pre-linked.  */
32803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      // GElf_Addr l_addr = addrs[0];
32925b3c049e70834cf33790a28643ab058b507b35cBen Cheng      GElf_Addr l_name = addrs[1];
33025b3c049e70834cf33790a28643ab058b507b35cBen Cheng      GElf_Addr l_ld = addrs[2];
33125b3c049e70834cf33790a28643ab058b507b35cBen Cheng      next = addrs[3];
33225b3c049e70834cf33790a28643ab058b507b35cBen Cheng
33325b3c049e70834cf33790a28643ab058b507b35cBen Cheng      /* If a clobbered or truncated memory image has no useful pointer,
33425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	 just skip this element.  */
33525b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (l_ld == 0)
33625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	continue;
33725b3c049e70834cf33790a28643ab058b507b35cBen Cheng
33825b3c049e70834cf33790a28643ab058b507b35cBen Cheng      /* Fetch the string at the l_name address.  */
33925b3c049e70834cf33790a28643ab058b507b35cBen Cheng      const char *name = NULL;
34025b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (buffer != NULL
34125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  && read_vaddr <= l_name
34225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  && l_name + 1 - read_vaddr < buffer_available
34325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  && memchr (l_name - read_vaddr + buffer, '\0',
34425b3c049e70834cf33790a28643ab058b507b35cBen Cheng		     buffer_available - (l_name - read_vaddr)) != NULL)
34525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	name = l_name - read_vaddr + buffer;
34625b3c049e70834cf33790a28643ab058b507b35cBen Cheng      else
34725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	{
34825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  release_buffer (0);
34925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  read_vaddr = l_name;
35025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  int segndx = INTUSE(dwfl_addrsegment) (dwfl, l_name, NULL);
35125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  if (likely (segndx >= 0)
35225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      && (*memory_callback) (dwfl, segndx,
35325b3c049e70834cf33790a28643ab058b507b35cBen Cheng				     &buffer, &buffer_available,
35425b3c049e70834cf33790a28643ab058b507b35cBen Cheng				     l_name, 0, memory_callback_arg))
35525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    name = buffer;
35625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	}
35725b3c049e70834cf33790a28643ab058b507b35cBen Cheng
35825b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (name != NULL && name[0] == '\0')
35925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	name = NULL;
36025b3c049e70834cf33790a28643ab058b507b35cBen Cheng
36103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      if (iterations == 1 && dwfl->executable_for_core != NULL)
36203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	name = dwfl->executable_for_core;
36303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
36403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      struct r_debug_info_module *r_debug_info_module = NULL;
36503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      if (r_debug_info != NULL)
36625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	{
36703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  /* Save link map information about valid shared library (or
36803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	     executable) which has not been found on disk.  */
36903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  const char *name1 = name == NULL ? "" : name;
37003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  r_debug_info_module = malloc (sizeof (*r_debug_info_module)
37103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes					+ strlen (name1) + 1);
37203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  if (r_debug_info_module == NULL)
37303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	    return release_buffer (result);
37403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  r_debug_info_module->fd = -1;
37503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  r_debug_info_module->elf = NULL;
37603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  r_debug_info_module->l_ld = l_ld;
37703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  r_debug_info_module->start = 0;
37803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  r_debug_info_module->end = 0;
37903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  r_debug_info_module->disk_file_has_build_id = false;
38003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  strcpy (r_debug_info_module->name, name1);
38103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  r_debug_info_module->next = r_debug_info->module;
38203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  r_debug_info->module = r_debug_info_module;
38303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	}
38403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
38503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      Dwfl_Module *mod = NULL;
38603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      if (name != NULL)
38703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	{
38803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  /* This code is mostly inlined dwfl_report_elf.  */
38903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  // XXX hook for sysroot
39003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  int fd = open64 (name, O_RDONLY);
39103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  if (fd >= 0)
39225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    {
39303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	      Elf *elf;
39403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	      Dwfl_Error error = __libdw_open_file (&fd, &elf, true, false);
39503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	      GElf_Addr elf_dynamic_vaddr;
39603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	      if (error == DWFL_E_NOERROR
39703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		  && __libdwfl_dynamic_vaddr_get (elf, &elf_dynamic_vaddr))
39825b3c049e70834cf33790a28643ab058b507b35cBen Cheng		{
39903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		  const void *build_id_bits;
40003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		  GElf_Addr build_id_elfaddr;
40103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		  int build_id_len;
40203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		  bool valid = true;
40303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
40403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		  if (__libdwfl_find_elf_build_id (NULL, elf, &build_id_bits,
40503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes						   &build_id_elfaddr,
40603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes						   &build_id_len) > 0
40703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		      && build_id_elfaddr != 0)
40803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		    {
40903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		      if (r_debug_info_module != NULL)
41003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes			r_debug_info_module->disk_file_has_build_id = true;
41103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		      GElf_Addr build_id_vaddr = (build_id_elfaddr
41203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes						  - elf_dynamic_vaddr + l_ld);
41303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
41403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		      release_buffer (0);
41503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		      int segndx = INTUSE(dwfl_addrsegment) (dwfl,
41603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes							     build_id_vaddr,
41703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes							     NULL);
41803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		      if (! (*memory_callback) (dwfl, segndx,
41903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes						&buffer, &buffer_available,
42003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes						build_id_vaddr, build_id_len,
42103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes						memory_callback_arg))
42203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes			{
42303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes			  /* File has valid build-id which cannot be read from
42403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes			     memory.  This happens for core files without bit 4
42503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes			     (0x10) set in Linux /proc/PID/coredump_filter.  */
42603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes			}
42703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		      else
42803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes			{
42903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes			  if (memcmp (build_id_bits, buffer, build_id_len) != 0)
43003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes			    /* File has valid build-id which does not match
43103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes			       the one in memory.  */
43203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes			    valid = false;
43303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes			  release_buffer (0);
43403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes			}
43503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		    }
43603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
43703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		  if (valid)
43803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		    {
43903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		      // It is like l_addr but it handles differently prelinked
44003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		      // files at core dumping vs. core loading time.
44103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		      GElf_Addr base = l_ld - elf_dynamic_vaddr;
44203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		      if (r_debug_info_module == NULL)
44303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes			{
44403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes			  // XXX hook for sysroot
44503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes			  mod = __libdwfl_report_elf (dwfl, basename (name),
44603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes						      name, fd, elf, base,
44703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes						      true, true);
44803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes			  if (mod != NULL)
44903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes			    {
45003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes			      elf = NULL;
45103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes			      fd = -1;
45203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes			    }
45303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes			}
45403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		      else if (__libdwfl_elf_address_range (elf, base, true,
45503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes							    true, NULL, NULL,
45603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes						    &r_debug_info_module->start,
45703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes						    &r_debug_info_module->end,
45803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes							    NULL, NULL))
45903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes			{
46003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes			  r_debug_info_module->elf = elf;
46103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes			  r_debug_info_module->fd = fd;
46203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes			  elf = NULL;
46303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes			  fd = -1;
46403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes			}
46503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		    }
46603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		  if (elf != NULL)
46703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		    elf_end (elf);
46803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		  if (fd != -1)
46903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		    close (fd);
47025b3c049e70834cf33790a28643ab058b507b35cBen Cheng		}
47125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    }
47225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	}
47325b3c049e70834cf33790a28643ab058b507b35cBen Cheng
47425b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (mod != NULL)
47525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	{
47625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  ++result;
47725b3c049e70834cf33790a28643ab058b507b35cBen Cheng
47825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  /* Move this module to the end of the list, so that we end
47925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	     up with a list in the same order as the link_map chain.  */
48025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  if (mod->next != NULL)
48125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    {
48225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      if (*lastmodp != mod)
48325b3c049e70834cf33790a28643ab058b507b35cBen Cheng		{
48425b3c049e70834cf33790a28643ab058b507b35cBen Cheng		  lastmodp = &dwfl->modulelist;
48525b3c049e70834cf33790a28643ab058b507b35cBen Cheng		  while (*lastmodp != mod)
48625b3c049e70834cf33790a28643ab058b507b35cBen Cheng		    lastmodp = &(*lastmodp)->next;
48725b3c049e70834cf33790a28643ab058b507b35cBen Cheng		}
48825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      *lastmodp = mod->next;
48925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      mod->next = NULL;
49025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      while (*lastmodp != NULL)
49125b3c049e70834cf33790a28643ab058b507b35cBen Cheng		lastmodp = &(*lastmodp)->next;
49225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      *lastmodp = mod;
49325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    }
49425b3c049e70834cf33790a28643ab058b507b35cBen Cheng
49525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  lastmodp = &mod->next;
49625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	}
49725b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
49825b3c049e70834cf33790a28643ab058b507b35cBen Cheng
49925b3c049e70834cf33790a28643ab058b507b35cBen Cheng  return release_buffer (result);
50025b3c049e70834cf33790a28643ab058b507b35cBen Cheng}
50125b3c049e70834cf33790a28643ab058b507b35cBen Cheng
50225b3c049e70834cf33790a28643ab058b507b35cBen Chengstatic GElf_Addr
50325b3c049e70834cf33790a28643ab058b507b35cBen Chengconsider_executable (Dwfl_Module *mod, GElf_Addr at_phdr, GElf_Addr at_entry,
50425b3c049e70834cf33790a28643ab058b507b35cBen Cheng		     uint_fast8_t *elfclass, uint_fast8_t *elfdata,
50525b3c049e70834cf33790a28643ab058b507b35cBen Cheng		     Dwfl_Memory_Callback *memory_callback,
50625b3c049e70834cf33790a28643ab058b507b35cBen Cheng		     void *memory_callback_arg)
50725b3c049e70834cf33790a28643ab058b507b35cBen Cheng{
50825b3c049e70834cf33790a28643ab058b507b35cBen Cheng  GElf_Ehdr ehdr;
50925b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (unlikely (gelf_getehdr (mod->main.elf, &ehdr) == NULL))
51025b3c049e70834cf33790a28643ab058b507b35cBen Cheng    return 0;
51125b3c049e70834cf33790a28643ab058b507b35cBen Cheng
51225b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (at_entry != 0)
51325b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
51425b3c049e70834cf33790a28643ab058b507b35cBen Cheng      /* If we have an AT_ENTRY value, reject this executable if
51525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	 its entry point address could not have supplied that.  */
51625b3c049e70834cf33790a28643ab058b507b35cBen Cheng
51725b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (ehdr.e_entry == 0)
51825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	return 0;
51925b3c049e70834cf33790a28643ab058b507b35cBen Cheng
52025b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (mod->e_type == ET_EXEC)
52125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	{
52225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  if (ehdr.e_entry != at_entry)
52325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    return 0;
52425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	}
52525b3c049e70834cf33790a28643ab058b507b35cBen Cheng      else
52625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	{
52725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  /* It could be a PIE.  */
52825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	}
52925b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
53025b3c049e70834cf33790a28643ab058b507b35cBen Cheng
53125b3c049e70834cf33790a28643ab058b507b35cBen Cheng  // XXX this could be saved in the file cache: phdr vaddr, DT_DEBUG d_val vaddr
53225b3c049e70834cf33790a28643ab058b507b35cBen Cheng  /* Find the vaddr of the DT_DEBUG's d_ptr.  This is the memory
53325b3c049e70834cf33790a28643ab058b507b35cBen Cheng     address where &r_debug was written at runtime.  */
53425b3c049e70834cf33790a28643ab058b507b35cBen Cheng  GElf_Xword align = mod->dwfl->segment_align;
53525b3c049e70834cf33790a28643ab058b507b35cBen Cheng  GElf_Addr d_val_vaddr = 0;
53603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  size_t phnum;
53703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  if (elf_getphdrnum (mod->main.elf, &phnum) != 0)
53803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    return 0;
53903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
54003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  for (size_t i = 0; i < phnum; ++i)
54125b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
54225b3c049e70834cf33790a28643ab058b507b35cBen Cheng      GElf_Phdr phdr_mem;
54325b3c049e70834cf33790a28643ab058b507b35cBen Cheng      GElf_Phdr *phdr = gelf_getphdr (mod->main.elf, i, &phdr_mem);
54425b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (phdr == NULL)
54525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	break;
54625b3c049e70834cf33790a28643ab058b507b35cBen Cheng
54725b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (phdr->p_align > 1 && (align == 0 || phdr->p_align < align))
54825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	align = phdr->p_align;
54925b3c049e70834cf33790a28643ab058b507b35cBen Cheng
55025b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (at_phdr != 0
55125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  && phdr->p_type == PT_LOAD
55225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  && (phdr->p_offset & -align) == (ehdr.e_phoff & -align))
55325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	{
55425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  /* This is the segment that would map the phdrs.
55525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	     If we have an AT_PHDR value, reject this executable
55625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	     if its phdr mapping could not have supplied that.  */
55725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  if (mod->e_type == ET_EXEC)
55825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    {
55925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      if (ehdr.e_phoff - phdr->p_offset + phdr->p_vaddr != at_phdr)
56025b3c049e70834cf33790a28643ab058b507b35cBen Cheng		return 0;
56125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    }
56225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  else
56325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    {
56425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      /* It could be a PIE.  If the AT_PHDR value and our
56525b3c049e70834cf33790a28643ab058b507b35cBen Cheng		 phdr address don't match modulo ALIGN, then this
56625b3c049e70834cf33790a28643ab058b507b35cBen Cheng		 could not have been the right PIE.  */
56725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      if (((ehdr.e_phoff - phdr->p_offset + phdr->p_vaddr) & -align)
56825b3c049e70834cf33790a28643ab058b507b35cBen Cheng		  != (at_phdr & -align))
56925b3c049e70834cf33790a28643ab058b507b35cBen Cheng		return 0;
57025b3c049e70834cf33790a28643ab058b507b35cBen Cheng
57125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      /* Calculate the bias applied to the PIE's p_vaddr values.  */
57225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      GElf_Addr bias = (at_phdr - (ehdr.e_phoff - phdr->p_offset
57325b3c049e70834cf33790a28643ab058b507b35cBen Cheng					   + phdr->p_vaddr));
57425b3c049e70834cf33790a28643ab058b507b35cBen Cheng
57525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      /* Final sanity check: if we have an AT_ENTRY value,
57625b3c049e70834cf33790a28643ab058b507b35cBen Cheng		 reject this PIE unless its biased e_entry matches.  */
57725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      if (at_entry != 0 && at_entry != ehdr.e_entry + bias)
57825b3c049e70834cf33790a28643ab058b507b35cBen Cheng		return 0;
57925b3c049e70834cf33790a28643ab058b507b35cBen Cheng
58025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      /* If we're changing the module's address range,
58125b3c049e70834cf33790a28643ab058b507b35cBen Cheng		 we've just invalidated the module lookup table.  */
58225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      GElf_Addr mod_bias = dwfl_adjusted_address (mod, 0);
58325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      if (bias != mod_bias)
58425b3c049e70834cf33790a28643ab058b507b35cBen Cheng		{
58525b3c049e70834cf33790a28643ab058b507b35cBen Cheng		  mod->low_addr -= mod_bias;
58625b3c049e70834cf33790a28643ab058b507b35cBen Cheng		  mod->high_addr -= mod_bias;
58725b3c049e70834cf33790a28643ab058b507b35cBen Cheng		  mod->low_addr += bias;
58825b3c049e70834cf33790a28643ab058b507b35cBen Cheng		  mod->high_addr += bias;
58925b3c049e70834cf33790a28643ab058b507b35cBen Cheng
59025b3c049e70834cf33790a28643ab058b507b35cBen Cheng		  free (mod->dwfl->lookup_module);
59125b3c049e70834cf33790a28643ab058b507b35cBen Cheng		  mod->dwfl->lookup_module = NULL;
59225b3c049e70834cf33790a28643ab058b507b35cBen Cheng		}
59325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    }
59425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	}
59525b3c049e70834cf33790a28643ab058b507b35cBen Cheng
59625b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (phdr->p_type == PT_DYNAMIC)
59725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	{
59825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  Elf_Data *data = elf_getdata_rawchunk (mod->main.elf, phdr->p_offset,
59925b3c049e70834cf33790a28643ab058b507b35cBen Cheng						 phdr->p_filesz, ELF_T_DYN);
60025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  if (data == NULL)
60125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    continue;
60225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  const size_t entsize = gelf_fsize (mod->main.elf,
60325b3c049e70834cf33790a28643ab058b507b35cBen Cheng					     ELF_T_DYN, 1, EV_CURRENT);
60425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  const size_t n = data->d_size / entsize;
60525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  for (size_t j = 0; j < n; ++j)
60625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    {
60725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      GElf_Dyn dyn_mem;
60825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      GElf_Dyn *dyn = gelf_getdyn (data, j, &dyn_mem);
60925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      if (dyn != NULL && dyn->d_tag == DT_DEBUG)
61025b3c049e70834cf33790a28643ab058b507b35cBen Cheng		{
61125b3c049e70834cf33790a28643ab058b507b35cBen Cheng		  d_val_vaddr = phdr->p_vaddr + entsize * j + entsize / 2;
61225b3c049e70834cf33790a28643ab058b507b35cBen Cheng		  break;
61325b3c049e70834cf33790a28643ab058b507b35cBen Cheng		}
61425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    }
61525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	}
61625b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
61725b3c049e70834cf33790a28643ab058b507b35cBen Cheng
61825b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (d_val_vaddr != 0)
61925b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
62025b3c049e70834cf33790a28643ab058b507b35cBen Cheng      /* Now we have the final address from which to read &r_debug.  */
62125b3c049e70834cf33790a28643ab058b507b35cBen Cheng      d_val_vaddr = dwfl_adjusted_address (mod, d_val_vaddr);
62225b3c049e70834cf33790a28643ab058b507b35cBen Cheng
62325b3c049e70834cf33790a28643ab058b507b35cBen Cheng      void *buffer = NULL;
62425b3c049e70834cf33790a28643ab058b507b35cBen Cheng      size_t buffer_available = addrsize (ehdr.e_ident[EI_CLASS]);
62525b3c049e70834cf33790a28643ab058b507b35cBen Cheng
62625b3c049e70834cf33790a28643ab058b507b35cBen Cheng      int segndx = INTUSE(dwfl_addrsegment) (mod->dwfl, d_val_vaddr, NULL);
62725b3c049e70834cf33790a28643ab058b507b35cBen Cheng
62825b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if ((*memory_callback) (mod->dwfl, segndx,
62925b3c049e70834cf33790a28643ab058b507b35cBen Cheng			      &buffer, &buffer_available,
63025b3c049e70834cf33790a28643ab058b507b35cBen Cheng			      d_val_vaddr, buffer_available,
63125b3c049e70834cf33790a28643ab058b507b35cBen Cheng			      memory_callback_arg))
63225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	{
63325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  const union
63425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  {
63525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    Elf32_Addr a32;
63625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    Elf64_Addr a64;
63725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  } *u = buffer;
63825b3c049e70834cf33790a28643ab058b507b35cBen Cheng
63925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  GElf_Addr vaddr;
64025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  if (ehdr.e_ident[EI_CLASS] == ELFCLASS32)
64125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    vaddr = (ehdr.e_ident[EI_DATA] == ELFDATA2MSB
64225b3c049e70834cf33790a28643ab058b507b35cBen Cheng		     ? BE32 (u->a32) : LE32 (u->a32));
64325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  else
64425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    vaddr = (ehdr.e_ident[EI_DATA] == ELFDATA2MSB
64525b3c049e70834cf33790a28643ab058b507b35cBen Cheng		     ? BE64 (u->a64) : LE64 (u->a64));
64625b3c049e70834cf33790a28643ab058b507b35cBen Cheng
64725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  (*memory_callback) (mod->dwfl, -1, &buffer, &buffer_available, 0, 0,
64825b3c049e70834cf33790a28643ab058b507b35cBen Cheng			      memory_callback_arg);
64925b3c049e70834cf33790a28643ab058b507b35cBen Cheng
65025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  if (*elfclass == ELFCLASSNONE)
65125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    *elfclass = ehdr.e_ident[EI_CLASS];
65225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  else if (*elfclass != ehdr.e_ident[EI_CLASS])
65325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    return 0;
65425b3c049e70834cf33790a28643ab058b507b35cBen Cheng
65525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  if (*elfdata == ELFDATANONE)
65625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    *elfdata = ehdr.e_ident[EI_DATA];
65725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  else if (*elfdata != ehdr.e_ident[EI_DATA])
65825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    return 0;
65925b3c049e70834cf33790a28643ab058b507b35cBen Cheng
66025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  return vaddr;
66125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	}
66225b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
66325b3c049e70834cf33790a28643ab058b507b35cBen Cheng
66425b3c049e70834cf33790a28643ab058b507b35cBen Cheng  return 0;
66525b3c049e70834cf33790a28643ab058b507b35cBen Cheng}
66625b3c049e70834cf33790a28643ab058b507b35cBen Cheng
66725b3c049e70834cf33790a28643ab058b507b35cBen Cheng/* Try to find an existing executable module with a DT_DEBUG.  */
66825b3c049e70834cf33790a28643ab058b507b35cBen Chengstatic GElf_Addr
66925b3c049e70834cf33790a28643ab058b507b35cBen Chengfind_executable (Dwfl *dwfl, GElf_Addr at_phdr, GElf_Addr at_entry,
67025b3c049e70834cf33790a28643ab058b507b35cBen Cheng		 uint_fast8_t *elfclass, uint_fast8_t *elfdata,
67125b3c049e70834cf33790a28643ab058b507b35cBen Cheng		 Dwfl_Memory_Callback *memory_callback,
67225b3c049e70834cf33790a28643ab058b507b35cBen Cheng		 void *memory_callback_arg)
67325b3c049e70834cf33790a28643ab058b507b35cBen Cheng{
67425b3c049e70834cf33790a28643ab058b507b35cBen Cheng  for (Dwfl_Module *mod = dwfl->modulelist; mod != NULL; mod = mod->next)
67525b3c049e70834cf33790a28643ab058b507b35cBen Cheng    if (mod->main.elf != NULL)
67625b3c049e70834cf33790a28643ab058b507b35cBen Cheng      {
67725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	GElf_Addr r_debug_vaddr = consider_executable (mod, at_phdr, at_entry,
67825b3c049e70834cf33790a28643ab058b507b35cBen Cheng						       elfclass, elfdata,
67925b3c049e70834cf33790a28643ab058b507b35cBen Cheng						       memory_callback,
68025b3c049e70834cf33790a28643ab058b507b35cBen Cheng						       memory_callback_arg);
68125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	if (r_debug_vaddr != 0)
68225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  return r_debug_vaddr;
68325b3c049e70834cf33790a28643ab058b507b35cBen Cheng      }
68425b3c049e70834cf33790a28643ab058b507b35cBen Cheng
68525b3c049e70834cf33790a28643ab058b507b35cBen Cheng  return 0;
68625b3c049e70834cf33790a28643ab058b507b35cBen Cheng}
68725b3c049e70834cf33790a28643ab058b507b35cBen Cheng
68825b3c049e70834cf33790a28643ab058b507b35cBen Cheng
68925b3c049e70834cf33790a28643ab058b507b35cBen Chengint
69025b3c049e70834cf33790a28643ab058b507b35cBen Chengdwfl_link_map_report (Dwfl *dwfl, const void *auxv, size_t auxv_size,
69125b3c049e70834cf33790a28643ab058b507b35cBen Cheng		      Dwfl_Memory_Callback *memory_callback,
69203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		      void *memory_callback_arg,
69303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		      struct r_debug_info *r_debug_info)
69425b3c049e70834cf33790a28643ab058b507b35cBen Cheng{
69525b3c049e70834cf33790a28643ab058b507b35cBen Cheng  GElf_Addr r_debug_vaddr = 0;
69625b3c049e70834cf33790a28643ab058b507b35cBen Cheng
69725b3c049e70834cf33790a28643ab058b507b35cBen Cheng  uint_fast8_t elfclass = ELFCLASSNONE;
69825b3c049e70834cf33790a28643ab058b507b35cBen Cheng  uint_fast8_t elfdata = ELFDATANONE;
69925b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (likely (auxv != NULL)
70025b3c049e70834cf33790a28643ab058b507b35cBen Cheng      && likely (auxv_format_probe (auxv, auxv_size, &elfclass, &elfdata)))
70125b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
70225b3c049e70834cf33790a28643ab058b507b35cBen Cheng      GElf_Addr entry = 0;
70325b3c049e70834cf33790a28643ab058b507b35cBen Cheng      GElf_Addr phdr = 0;
70425b3c049e70834cf33790a28643ab058b507b35cBen Cheng      GElf_Xword phent = 0;
70525b3c049e70834cf33790a28643ab058b507b35cBen Cheng      GElf_Xword phnum = 0;
70625b3c049e70834cf33790a28643ab058b507b35cBen Cheng
70703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes#define READ_AUXV32(ptr)	read_4ubyte_unaligned_noncvt (ptr)
70803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes#define READ_AUXV64(ptr)	read_8ubyte_unaligned_noncvt (ptr)
70903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes#define AUXV_SCAN(NN, BL) do                                            \
71003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	{                                                               \
71103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  const Elf##NN##_auxv_t *av = auxv;                            \
71203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  for (size_t i = 0; i < auxv_size / sizeof av[0]; ++i)         \
71303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	    {                                                           \
71403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes              uint##NN##_t type = READ_AUXV##NN (&av[i].a_type);        \
71503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes              uint##NN##_t val = BL##NN (READ_AUXV##NN (&av[i].a_un.a_val)); \
71603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	      if (type == BL##NN (AT_ENTRY))                            \
71703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		entry = val;                                            \
71803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	      else if (type == BL##NN (AT_PHDR))                        \
71903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		phdr = val;                                             \
72003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	      else if (type == BL##NN (AT_PHNUM))                       \
72103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		phnum = val;                                            \
72203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	      else if (type == BL##NN (AT_PHENT))                       \
72303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		phent = val;                                            \
72403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	      else if (type == BL##NN (AT_PAGESZ))                      \
72503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		{                                                       \
72603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		  if (val > 1                                           \
72703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		      && (dwfl->segment_align == 0                      \
72803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes			  || val < dwfl->segment_align))                \
72903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		    dwfl->segment_align = val;                          \
73003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		}                                                       \
73103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	    }                                                           \
73203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	}                                                               \
73325b3c049e70834cf33790a28643ab058b507b35cBen Cheng      while (0)
73425b3c049e70834cf33790a28643ab058b507b35cBen Cheng
73525b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (elfclass == ELFCLASS32)
73625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	{
73725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  if (elfdata == ELFDATA2MSB)
73825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    AUXV_SCAN (32, BE);
73925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  else
74025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    AUXV_SCAN (32, LE);
74125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	}
74225b3c049e70834cf33790a28643ab058b507b35cBen Cheng      else
74325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	{
74425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  if (elfdata == ELFDATA2MSB)
74525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    AUXV_SCAN (64, BE);
74625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  else
74725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    AUXV_SCAN (64, LE);
74825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	}
74925b3c049e70834cf33790a28643ab058b507b35cBen Cheng
75025b3c049e70834cf33790a28643ab058b507b35cBen Cheng      /* If we found the phdr dimensions, search phdrs for PT_DYNAMIC.  */
75125b3c049e70834cf33790a28643ab058b507b35cBen Cheng      GElf_Addr dyn_vaddr = 0;
75225b3c049e70834cf33790a28643ab058b507b35cBen Cheng      GElf_Xword dyn_filesz = 0;
75325b3c049e70834cf33790a28643ab058b507b35cBen Cheng      GElf_Addr dyn_bias = (GElf_Addr) -1;
75425b3c049e70834cf33790a28643ab058b507b35cBen Cheng
75525b3c049e70834cf33790a28643ab058b507b35cBen Cheng      inline bool consider_phdr (GElf_Word type,
75625b3c049e70834cf33790a28643ab058b507b35cBen Cheng				 GElf_Addr vaddr, GElf_Xword filesz)
75725b3c049e70834cf33790a28643ab058b507b35cBen Cheng      {
75825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	switch (type)
75925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  {
76025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  case PT_PHDR:
76125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    if (dyn_bias == (GElf_Addr) -1
76225b3c049e70834cf33790a28643ab058b507b35cBen Cheng		/* Do a sanity check on the putative address.  */
76325b3c049e70834cf33790a28643ab058b507b35cBen Cheng		&& ((vaddr & (dwfl->segment_align - 1))
76425b3c049e70834cf33790a28643ab058b507b35cBen Cheng		    == (phdr & (dwfl->segment_align - 1))))
76525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      {
76625b3c049e70834cf33790a28643ab058b507b35cBen Cheng		dyn_bias = phdr - vaddr;
76725b3c049e70834cf33790a28643ab058b507b35cBen Cheng		return dyn_vaddr != 0;
76825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      }
76925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    break;
77025b3c049e70834cf33790a28643ab058b507b35cBen Cheng
77125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  case PT_DYNAMIC:
77225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    dyn_vaddr = vaddr;
77325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    dyn_filesz = filesz;
77425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    return dyn_bias != (GElf_Addr) -1;
77525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  }
77625b3c049e70834cf33790a28643ab058b507b35cBen Cheng
77725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	return false;
77825b3c049e70834cf33790a28643ab058b507b35cBen Cheng      }
77925b3c049e70834cf33790a28643ab058b507b35cBen Cheng
78025b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (phdr != 0 && phnum != 0)
78125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	{
78225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  Dwfl_Module *phdr_mod;
78325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  int phdr_segndx = INTUSE(dwfl_addrsegment) (dwfl, phdr, &phdr_mod);
78425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  Elf_Data in =
78525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    {
78625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      .d_type = ELF_T_PHDR,
78725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      .d_version = EV_CURRENT,
78825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      .d_size = phnum * phent,
78925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      .d_buf = NULL
79025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    };
79103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  bool in_ok = (*memory_callback) (dwfl, phdr_segndx, &in.d_buf,
79203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes					   &in.d_size, phdr, phnum * phent,
79303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes					   memory_callback_arg);
79403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  if (! in_ok && dwfl->executable_for_core != NULL)
79503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	    {
79603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	      /* AUXV -> PHDR -> DYNAMIC
79703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		 Both AUXV and DYNAMIC should be always present in a core file.
79803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		 PHDR may be missing in core file, try to read it from
79903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		 EXECUTABLE_FOR_CORE to find where DYNAMIC is located in the
80003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		 core file.  */
80103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
80203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	      int fd = open (dwfl->executable_for_core, O_RDONLY);
80303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	      Elf *elf;
80403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	      Dwfl_Error error = DWFL_E_ERRNO;
80503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	      if (fd != -1)
80603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		error = __libdw_open_file (&fd, &elf, true, false);
80703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	      if (error != DWFL_E_NOERROR)
80803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		{
80903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		  __libdwfl_seterrno (error);
81003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		  return false;
81103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		}
81203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	      GElf_Ehdr ehdr_mem, *ehdr = gelf_getehdr (elf, &ehdr_mem);
81303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	      if (ehdr == NULL)
81403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		{
81503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		  elf_end (elf);
81603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		  close (fd);
81703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		  __libdwfl_seterrno (DWFL_E_LIBELF);
81803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		  return false;
81903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		}
82003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	      size_t e_phnum;
82103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	      if (elf_getphdrnum (elf, &e_phnum) != 0)
82203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		{
82303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		  elf_end (elf);
82403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		  close (fd);
82503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		  __libdwfl_seterrno (DWFL_E_LIBELF);
82603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		  return false;
82703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		}
82803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	      if (e_phnum != phnum || ehdr->e_phentsize != phent)
82903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		{
83003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		  elf_end (elf);
83103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		  close (fd);
83203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		  __libdwfl_seterrno (DWFL_E_BADELF);
83303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		  return false;
83403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		}
83503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	      off_t off = ehdr->e_phoff;
83603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	      assert (in.d_buf == NULL);
83703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	      assert (in.d_size == phnum * phent);
83803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	      in.d_buf = malloc (in.d_size);
83903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	      if (unlikely (in.d_buf == NULL))
84003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		{
84103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		  elf_end (elf);
84203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		  close (fd);
84303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		  __libdwfl_seterrno (DWFL_E_NOMEM);
84403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		  return false;
84503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		}
84603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	      ssize_t nread = pread_retry (fd, in.d_buf, in.d_size, off);
84703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	      elf_end (elf);
84803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	      close (fd);
84903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	      if (nread != (ssize_t) in.d_size)
85003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		{
85103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		  free (in.d_buf);
85203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		  __libdwfl_seterrno (DWFL_E_ERRNO);
85303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		  return false;
85403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		}
85503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	      in_ok = true;
85603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	    }
85703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  if (in_ok)
85825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    {
85925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      union
86025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      {
86125b3c049e70834cf33790a28643ab058b507b35cBen Cheng		Elf32_Phdr p32;
86225b3c049e70834cf33790a28643ab058b507b35cBen Cheng		Elf64_Phdr p64;
86325b3c049e70834cf33790a28643ab058b507b35cBen Cheng		char data[phnum * phent];
86425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      } buf;
86525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      Elf_Data out =
86625b3c049e70834cf33790a28643ab058b507b35cBen Cheng		{
86725b3c049e70834cf33790a28643ab058b507b35cBen Cheng		  .d_type = ELF_T_PHDR,
86825b3c049e70834cf33790a28643ab058b507b35cBen Cheng		  .d_version = EV_CURRENT,
86925b3c049e70834cf33790a28643ab058b507b35cBen Cheng		  .d_size = phnum * phent,
87025b3c049e70834cf33790a28643ab058b507b35cBen Cheng		  .d_buf = &buf
87125b3c049e70834cf33790a28643ab058b507b35cBen Cheng		};
87225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      in.d_size = out.d_size;
87325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      if (likely ((elfclass == ELFCLASS32
87425b3c049e70834cf33790a28643ab058b507b35cBen Cheng			   ? elf32_xlatetom : elf64_xlatetom)
87525b3c049e70834cf33790a28643ab058b507b35cBen Cheng			  (&out, &in, elfdata) != NULL))
87625b3c049e70834cf33790a28643ab058b507b35cBen Cheng		{
87725b3c049e70834cf33790a28643ab058b507b35cBen Cheng		  /* We are looking for PT_DYNAMIC.  */
87825b3c049e70834cf33790a28643ab058b507b35cBen Cheng		  const union
87925b3c049e70834cf33790a28643ab058b507b35cBen Cheng		  {
88025b3c049e70834cf33790a28643ab058b507b35cBen Cheng		    Elf32_Phdr p32[phnum];
88125b3c049e70834cf33790a28643ab058b507b35cBen Cheng		    Elf64_Phdr p64[phnum];
88225b3c049e70834cf33790a28643ab058b507b35cBen Cheng		  } *u = (void *) &buf;
88325b3c049e70834cf33790a28643ab058b507b35cBen Cheng		  if (elfclass == ELFCLASS32)
88425b3c049e70834cf33790a28643ab058b507b35cBen Cheng		    {
88525b3c049e70834cf33790a28643ab058b507b35cBen Cheng		      for (size_t i = 0; i < phnum; ++i)
88625b3c049e70834cf33790a28643ab058b507b35cBen Cheng			if (consider_phdr (u->p32[i].p_type,
88725b3c049e70834cf33790a28643ab058b507b35cBen Cheng					   u->p32[i].p_vaddr,
88825b3c049e70834cf33790a28643ab058b507b35cBen Cheng					   u->p32[i].p_filesz))
88925b3c049e70834cf33790a28643ab058b507b35cBen Cheng			  break;
89025b3c049e70834cf33790a28643ab058b507b35cBen Cheng		    }
89125b3c049e70834cf33790a28643ab058b507b35cBen Cheng		  else
89225b3c049e70834cf33790a28643ab058b507b35cBen Cheng		    {
89325b3c049e70834cf33790a28643ab058b507b35cBen Cheng		      for (size_t i = 0; i < phnum; ++i)
89425b3c049e70834cf33790a28643ab058b507b35cBen Cheng			if (consider_phdr (u->p64[i].p_type,
89525b3c049e70834cf33790a28643ab058b507b35cBen Cheng					   u->p64[i].p_vaddr,
89625b3c049e70834cf33790a28643ab058b507b35cBen Cheng					   u->p64[i].p_filesz))
89725b3c049e70834cf33790a28643ab058b507b35cBen Cheng			  break;
89825b3c049e70834cf33790a28643ab058b507b35cBen Cheng		    }
89925b3c049e70834cf33790a28643ab058b507b35cBen Cheng		}
90025b3c049e70834cf33790a28643ab058b507b35cBen Cheng
90125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      (*memory_callback) (dwfl, -1, &in.d_buf, &in.d_size, 0, 0,
90225b3c049e70834cf33790a28643ab058b507b35cBen Cheng				  memory_callback_arg);
90325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    }
90425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  else
90525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    /* We could not read the executable's phdrs from the
90625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	       memory image.  If we have a presupplied executable,
90725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	       we can still use the AT_PHDR and AT_ENTRY values to
90825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	       verify it, and to adjust its bias if it's a PIE.
90925b3c049e70834cf33790a28643ab058b507b35cBen Cheng
91025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	       If there was an ET_EXEC module presupplied that contains
91125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	       the AT_PHDR address, then we only consider that one.
91225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	       We'll either accept it if its phdr location and e_entry
91325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	       make sense or reject it if they don't.  If there is no
91425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	       presupplied ET_EXEC, then look for a presupplied module,
91525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	       which might be a PIE (ET_DYN) that needs its bias adjusted.  */
91625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    r_debug_vaddr = ((phdr_mod == NULL
91725b3c049e70834cf33790a28643ab058b507b35cBen Cheng			      || phdr_mod->main.elf == NULL
91825b3c049e70834cf33790a28643ab058b507b35cBen Cheng			      || phdr_mod->e_type != ET_EXEC)
91925b3c049e70834cf33790a28643ab058b507b35cBen Cheng			     ? find_executable (dwfl, phdr, entry,
92025b3c049e70834cf33790a28643ab058b507b35cBen Cheng						&elfclass, &elfdata,
92125b3c049e70834cf33790a28643ab058b507b35cBen Cheng						memory_callback,
92225b3c049e70834cf33790a28643ab058b507b35cBen Cheng						memory_callback_arg)
92325b3c049e70834cf33790a28643ab058b507b35cBen Cheng			     : consider_executable (phdr_mod, phdr, entry,
92425b3c049e70834cf33790a28643ab058b507b35cBen Cheng						    &elfclass, &elfdata,
92525b3c049e70834cf33790a28643ab058b507b35cBen Cheng						    memory_callback,
92625b3c049e70834cf33790a28643ab058b507b35cBen Cheng						    memory_callback_arg));
92725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	}
92825b3c049e70834cf33790a28643ab058b507b35cBen Cheng
92925b3c049e70834cf33790a28643ab058b507b35cBen Cheng      /* If we found PT_DYNAMIC, search it for DT_DEBUG.  */
93025b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (dyn_filesz != 0)
93125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	{
93225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  if (dyn_bias != (GElf_Addr) -1)
93325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    dyn_vaddr += dyn_bias;
93425b3c049e70834cf33790a28643ab058b507b35cBen Cheng
93525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  Elf_Data in =
93625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    {
93725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      .d_type = ELF_T_DYN,
93825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      .d_version = EV_CURRENT,
93925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      .d_size = dyn_filesz,
94025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      .d_buf = NULL
94125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    };
94225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  int dyn_segndx = dwfl_addrsegment (dwfl, dyn_vaddr, NULL);
94325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  if ((*memory_callback) (dwfl, dyn_segndx, &in.d_buf, &in.d_size,
94425b3c049e70834cf33790a28643ab058b507b35cBen Cheng				  dyn_vaddr, dyn_filesz, memory_callback_arg))
94525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    {
94625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      union
94725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      {
94825b3c049e70834cf33790a28643ab058b507b35cBen Cheng		Elf32_Dyn d32;
94925b3c049e70834cf33790a28643ab058b507b35cBen Cheng		Elf64_Dyn d64;
95025b3c049e70834cf33790a28643ab058b507b35cBen Cheng		char data[dyn_filesz];
95125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      } buf;
95225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      Elf_Data out =
95325b3c049e70834cf33790a28643ab058b507b35cBen Cheng		{
95425b3c049e70834cf33790a28643ab058b507b35cBen Cheng		  .d_type = ELF_T_DYN,
95525b3c049e70834cf33790a28643ab058b507b35cBen Cheng		  .d_version = EV_CURRENT,
95625b3c049e70834cf33790a28643ab058b507b35cBen Cheng		  .d_size = dyn_filesz,
95725b3c049e70834cf33790a28643ab058b507b35cBen Cheng		  .d_buf = &buf
95825b3c049e70834cf33790a28643ab058b507b35cBen Cheng		};
95925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      in.d_size = out.d_size;
96025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      if (likely ((elfclass == ELFCLASS32
96125b3c049e70834cf33790a28643ab058b507b35cBen Cheng			   ? elf32_xlatetom : elf64_xlatetom)
96225b3c049e70834cf33790a28643ab058b507b35cBen Cheng			  (&out, &in, elfdata) != NULL))
96325b3c049e70834cf33790a28643ab058b507b35cBen Cheng		{
96425b3c049e70834cf33790a28643ab058b507b35cBen Cheng		  /* We are looking for DT_DEBUG.  */
96525b3c049e70834cf33790a28643ab058b507b35cBen Cheng		  const union
96625b3c049e70834cf33790a28643ab058b507b35cBen Cheng		  {
96725b3c049e70834cf33790a28643ab058b507b35cBen Cheng		    Elf32_Dyn d32[dyn_filesz / sizeof (Elf32_Dyn)];
96825b3c049e70834cf33790a28643ab058b507b35cBen Cheng		    Elf64_Dyn d64[dyn_filesz / sizeof (Elf64_Dyn)];
96925b3c049e70834cf33790a28643ab058b507b35cBen Cheng		  } *u = (void *) &buf;
97025b3c049e70834cf33790a28643ab058b507b35cBen Cheng		  if (elfclass == ELFCLASS32)
97125b3c049e70834cf33790a28643ab058b507b35cBen Cheng		    {
97225b3c049e70834cf33790a28643ab058b507b35cBen Cheng		      size_t n = dyn_filesz / sizeof (Elf32_Dyn);
97325b3c049e70834cf33790a28643ab058b507b35cBen Cheng		      for (size_t i = 0; i < n; ++i)
97425b3c049e70834cf33790a28643ab058b507b35cBen Cheng			if (u->d32[i].d_tag == DT_DEBUG)
97525b3c049e70834cf33790a28643ab058b507b35cBen Cheng			  {
97625b3c049e70834cf33790a28643ab058b507b35cBen Cheng			    r_debug_vaddr = u->d32[i].d_un.d_val;
97725b3c049e70834cf33790a28643ab058b507b35cBen Cheng			    break;
97825b3c049e70834cf33790a28643ab058b507b35cBen Cheng			  }
97925b3c049e70834cf33790a28643ab058b507b35cBen Cheng		    }
98025b3c049e70834cf33790a28643ab058b507b35cBen Cheng		  else
98125b3c049e70834cf33790a28643ab058b507b35cBen Cheng		    {
98225b3c049e70834cf33790a28643ab058b507b35cBen Cheng		      size_t n = dyn_filesz / sizeof (Elf64_Dyn);
98325b3c049e70834cf33790a28643ab058b507b35cBen Cheng		      for (size_t i = 0; i < n; ++i)
98425b3c049e70834cf33790a28643ab058b507b35cBen Cheng			if (u->d64[i].d_tag == DT_DEBUG)
98525b3c049e70834cf33790a28643ab058b507b35cBen Cheng			  {
98625b3c049e70834cf33790a28643ab058b507b35cBen Cheng			    r_debug_vaddr = u->d64[i].d_un.d_val;
98725b3c049e70834cf33790a28643ab058b507b35cBen Cheng			    break;
98825b3c049e70834cf33790a28643ab058b507b35cBen Cheng			  }
98925b3c049e70834cf33790a28643ab058b507b35cBen Cheng		    }
99025b3c049e70834cf33790a28643ab058b507b35cBen Cheng		}
99125b3c049e70834cf33790a28643ab058b507b35cBen Cheng
99225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      (*memory_callback) (dwfl, -1, &in.d_buf, &in.d_size, 0, 0,
99325b3c049e70834cf33790a28643ab058b507b35cBen Cheng				  memory_callback_arg);
99425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    }
99525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	}
99625b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
99725b3c049e70834cf33790a28643ab058b507b35cBen Cheng  else
99825b3c049e70834cf33790a28643ab058b507b35cBen Cheng    /* We have to look for a presupplied executable file to determine
99925b3c049e70834cf33790a28643ab058b507b35cBen Cheng       the vaddr of its dynamic section and DT_DEBUG therein.  */
100025b3c049e70834cf33790a28643ab058b507b35cBen Cheng    r_debug_vaddr = find_executable (dwfl, 0, 0, &elfclass, &elfdata,
100125b3c049e70834cf33790a28643ab058b507b35cBen Cheng				     memory_callback, memory_callback_arg);
100225b3c049e70834cf33790a28643ab058b507b35cBen Cheng
100325b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (r_debug_vaddr == 0)
100425b3c049e70834cf33790a28643ab058b507b35cBen Cheng    return 0;
100525b3c049e70834cf33790a28643ab058b507b35cBen Cheng
100625b3c049e70834cf33790a28643ab058b507b35cBen Cheng  /* For following pointers from struct link_map, we will use an
100725b3c049e70834cf33790a28643ab058b507b35cBen Cheng     integrated memory access callback that can consult module text
100825b3c049e70834cf33790a28643ab058b507b35cBen Cheng     elided from the core file.  This is necessary when the l_name
100925b3c049e70834cf33790a28643ab058b507b35cBen Cheng     pointer for the dynamic linker's own entry is a pointer into the
101025b3c049e70834cf33790a28643ab058b507b35cBen Cheng     executable's .interp section.  */
101125b3c049e70834cf33790a28643ab058b507b35cBen Cheng  struct integrated_memory_callback mcb =
101225b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
101325b3c049e70834cf33790a28643ab058b507b35cBen Cheng      .memory_callback = memory_callback,
101425b3c049e70834cf33790a28643ab058b507b35cBen Cheng      .memory_callback_arg = memory_callback_arg
101525b3c049e70834cf33790a28643ab058b507b35cBen Cheng    };
101625b3c049e70834cf33790a28643ab058b507b35cBen Cheng
101725b3c049e70834cf33790a28643ab058b507b35cBen Cheng  /* Now we can follow the dynamic linker's library list.  */
101825b3c049e70834cf33790a28643ab058b507b35cBen Cheng  return report_r_debug (elfclass, elfdata, dwfl, r_debug_vaddr,
101903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes			 &integrated_memory_callback, &mcb, r_debug_info);
102025b3c049e70834cf33790a28643ab058b507b35cBen Cheng}
102125b3c049e70834cf33790a28643ab058b507b35cBen ChengINTDEF (dwfl_link_map_report)
1022