1cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng/* Report modules by examining dynamic linker data structures.
2cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   Copyright (C) 2008 Red Hat, Inc.
3cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   This file is part of Red Hat elfutils.
4cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
5cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   Red Hat elfutils is free software; you can redistribute it and/or modify
6cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   it under the terms of the GNU General Public License as published by the
7cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   Free Software Foundation; version 2 of the License.
8cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
9cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   Red Hat elfutils is distributed in the hope that it will be useful, but
10cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   WITHOUT ANY WARRANTY; without even the implied warranty of
11cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   General Public License for more details.
13cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
14cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   You should have received a copy of the GNU General Public License along
15cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   with Red Hat elfutils; if not, write to the Free Software Foundation,
16cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
17cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
18cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   In addition, as a special exception, Red Hat, Inc. gives You the
19cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   additional right to link the code of Red Hat elfutils with code licensed
20cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   under any Open Source Initiative certified open source license
21cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   (http://www.opensource.org/licenses/index.php) which requires the
22cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   distribution of source code with any binary distribution and to
23cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   distribute linked combinations of the two.  Non-GPL Code permitted under
24cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   this exception must only link to the code of Red Hat elfutils through
25cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   those well defined interfaces identified in the file named EXCEPTION
26cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   found in the source code files (the "Approved Interfaces").  The files
27cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   of Non-GPL Code may instantiate templates or use macros or inline
28cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   functions from the Approved Interfaces without causing the resulting
29cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   work to be covered by the GNU General Public License.  Only Red Hat,
30cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   Inc. may make changes or additions to the list of Approved Interfaces.
31cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   Red Hat's grant of this exception is conditioned upon your not adding
32cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   any new exceptions.  If you wish to add a new Approved Interface or
33cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   exception, please contact Red Hat.  You must obey the GNU General Public
34cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   License in all respects for all of the Red Hat elfutils code and other
35cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   code used in conjunction with Red Hat elfutils except the Non-GPL Code
36cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   covered by this exception.  If you modify this file, you may extend this
37cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   exception to your version of the file, but you are not obligated to do
38cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   so.  If you do not wish to provide this exception without modification,
39cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   you must delete this exception statement from your version and license
40cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   this file solely under the GPL without exception.
41cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
42cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   Red Hat elfutils is an included package of the Open Invention Network.
43cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   An included package of the Open Invention Network is a package for which
44cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   Open Invention Network licensees cross-license their patents.  No patent
45cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   license is granted, either expressly or impliedly, by designation as an
46cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   included package.  Should you wish to participate in the Open Invention
47cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   Network licensing program, please visit www.openinventionnetwork.com
48cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   <http://www.openinventionnetwork.com>.  */
49cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
50cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng#include <config.h>
51cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng#include "libdwflP.h"
52cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
53cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng#include <byteswap.h>
54cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng#include <endian.h>
55cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
56cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng/* This element is always provided and always has a constant value.
57cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   This makes it an easy thing to scan for to discern the format.  */
58cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng#define PROBE_TYPE	AT_PHENT
59cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng#define PROBE_VAL32	sizeof (Elf32_Phdr)
60cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng#define PROBE_VAL64	sizeof (Elf64_Phdr)
61cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
62cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng#if BYTE_ORDER == BIG_ENDIAN
63cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng# define BE32(x)	(x)
64cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng# define BE64(x)	(x)
65cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng# define LE32(x)	bswap_32 (x)
66cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng# define LE64(x)	bswap_64 (x)
67cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng#else
68cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng# define LE32(x)	(x)
69cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng# define LE64(x)	(x)
70cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng# define BE32(x)	bswap_32 (x)
71cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng# define BE64(x)	bswap_64 (x)
72cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng#endif
73cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
74cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
75cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng/* Examine an auxv data block and determine its format.
76cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   Return true iff we figured it out.  */
77cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengstatic bool
78cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengauxv_format_probe (const void *auxv, size_t size,
79cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		   uint_fast8_t *elfclass, uint_fast8_t *elfdata)
80cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng{
81cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  const union
82cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  {
83cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    char buf[size];
84cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    Elf32_auxv_t a32[size / sizeof (Elf32_auxv_t)];
85cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    Elf64_auxv_t a64[size / sizeof (Elf64_auxv_t)];
86cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  } *u = auxv;
87cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
88cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  inline bool check64 (size_t i)
89cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  {
90cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    if (u->a64[i].a_type == BE64 (PROBE_TYPE)
91cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	&& u->a64[i].a_un.a_val == BE64 (PROBE_VAL64))
92cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      {
93cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	*elfdata = ELFDATA2MSB;
94cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	return true;
95cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      }
96cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
97cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    if (u->a64[i].a_type == LE64 (PROBE_TYPE)
98cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	&& u->a64[i].a_un.a_val == LE64 (PROBE_VAL64))
99cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      {
100cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	*elfdata = ELFDATA2LSB;
101cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	return true;
102cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      }
103cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
104cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    return false;
105cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  }
106cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
107cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  inline bool check32 (size_t i)
108cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  {
109cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    if (u->a32[i].a_type == BE32 (PROBE_TYPE)
110cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	&& u->a32[i].a_un.a_val == BE32 (PROBE_VAL32))
111cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      {
112cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	*elfdata = ELFDATA2MSB;
113cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	return true;
114cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      }
115cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
116cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    if (u->a32[i].a_type == LE32 (PROBE_TYPE)
117cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	&& u->a32[i].a_un.a_val == LE32 (PROBE_VAL32))
118cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      {
119cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	*elfdata = ELFDATA2LSB;
120cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	return true;
121cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      }
122cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
123cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    return false;
124cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  }
125cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
126cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  size_t i;
127cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  for (i = 0; i < size / sizeof (Elf64_auxv_t); ++i)
128cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    {
129cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (check64 (i))
130cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	{
131cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  *elfclass = ELFCLASS64;
132cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  return true;
133cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	}
134cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
135cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (check32 (i))
136cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	{
137cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  *elfclass = ELFCLASS32;
138cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  return true;
139cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	}
140cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    }
141cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  for (; i < size / sizeof (Elf64_auxv_t); ++i)
142cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    if (check32 (i))
143cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      {
144cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	*elfclass = ELFCLASS32;
145cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	return true;
146cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      }
147cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
148cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  return false;
149cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng}
150cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
151cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng/* This is a Dwfl_Memory_Callback that wraps another memory callback.
152cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   If the underlying callback cannot fill the data, then this will
153cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   fall back to fetching data from module files.  */
154cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
155cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengstruct integrated_memory_callback
156cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng{
157cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  Dwfl_Memory_Callback *memory_callback;
158cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  void *memory_callback_arg;
159cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  void *buffer;
160cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng};
161cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
162cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengstatic bool
163cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengintegrated_memory_callback (Dwfl *dwfl, int ndx,
164cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			       void **buffer, size_t *buffer_available,
165cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			       GElf_Addr vaddr,
166cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			       size_t minread,
167cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			       void *arg)
168cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng{
169cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  struct integrated_memory_callback *info = arg;
170cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
171cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (ndx == -1)
172cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    {
173cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      /* Called for cleanup.  */
174cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (info->buffer != NULL)
175cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	{
176cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  /* The last probe buffer came from the underlying callback.
177cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	     Let it do its cleanup.  */
178cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  assert (*buffer == info->buffer); /* XXX */
179cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  *buffer = info->buffer;
180cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  info->buffer = NULL;
181cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  return (*info->memory_callback) (dwfl, ndx, buffer, buffer_available,
182cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng					   vaddr, minread,
183cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng					   info->memory_callback_arg);
184cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	}
185cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      *buffer = NULL;
186cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      *buffer_available = 0;
187cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      return false;
188cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    }
189cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
190cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (*buffer != NULL)
191cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    /* For a final-read request, we only use the underlying callback.  */
192cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    return (*info->memory_callback) (dwfl, ndx, buffer, buffer_available,
193cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng				     vaddr, minread, info->memory_callback_arg);
194cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
195cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  /* Let the underlying callback try to fill this request.  */
196cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if ((*info->memory_callback) (dwfl, ndx, &info->buffer, buffer_available,
197cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng				vaddr, minread, info->memory_callback_arg))
198cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    {
199cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      *buffer = info->buffer;
200cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      return true;
201cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    }
202cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
203cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  /* Now look for module text covering this address.  */
204cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
205cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  Dwfl_Module *mod;
206cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  (void) INTUSE(dwfl_addrsegment) (dwfl, vaddr, &mod);
207cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (mod == NULL)
208cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    return false;
209cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
210cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  Dwarf_Addr bias;
211cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  Elf_Scn *scn = INTUSE(dwfl_module_address_section) (mod, &vaddr, &bias);
212cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (unlikely (scn == NULL))
213cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    {
214cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng#if 0 // XXX would have to handle ndx=-1 cleanup calls passed down.
215cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      /* If we have no sections we can try to fill it from the module file
216cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	 based on its phdr mappings.  */
217cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (likely (mod->e_type != ET_REL) && mod->main.elf != NULL)
218cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	return INTUSE(dwfl_elf_phdr_memory_callback)
219cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  (dwfl, 0, buffer, buffer_available,
220cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	   vaddr - mod->main.bias, minread, mod->main.elf);
221cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng#endif
222cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      return false;
223cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    }
224cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
225cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  Elf_Data *data = elf_rawdata (scn, NULL);
226cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (unlikely (data == NULL))
227cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    // XXX throw error?
228cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    return false;
229cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
230cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (unlikely (data->d_size < vaddr))
231cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    return false;
232cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
233cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  /* Provide as much data as we have.  */
234cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  void *contents = data->d_buf + vaddr;
235cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  size_t avail = data->d_size - vaddr;
236cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (unlikely (avail < minread))
237cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    return false;
238cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
239cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  /* If probing for a string, make sure it's terminated.  */
240cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (minread == 0 && unlikely (memchr (contents, '\0', avail) == NULL))
241cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    return false;
242cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
243cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  /* We have it! */
244cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  *buffer = contents;
245cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  *buffer_available = avail;
246cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  return true;
247cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng}
248cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
249cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengstatic size_t
250cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengaddrsize (uint_fast8_t elfclass)
251cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng{
252cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  return elfclass * 4;
253cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng}
254cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
255cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng/* Report a module for each struct link_map in the linked list at r_map
256cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   in the struct r_debug at R_DEBUG_VADDR.
257cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
258cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   For each link_map entry, if an existing module resides at its address,
259cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   this just modifies that module's name and suggested file name.  If
260cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   no such module exists, this calls dwfl_report_elf on the l_name string.
261cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
262cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   Returns the number of modules found, or -1 for errors.  */
263cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
264cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengstatic int
265cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengreport_r_debug (uint_fast8_t elfclass, uint_fast8_t elfdata,
266cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		Dwfl *dwfl, GElf_Addr r_debug_vaddr,
267cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		Dwfl_Memory_Callback *memory_callback,
268cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		void *memory_callback_arg)
269cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng{
270cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  /* Skip r_version, to aligned r_map field.  */
271cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  GElf_Addr read_vaddr = r_debug_vaddr + addrsize (elfclass);
272cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
273cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  void *buffer = NULL;
274cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  size_t buffer_available = 0;
275cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  inline int release_buffer (int result)
276cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  {
277cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    if (buffer != NULL)
278cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      (void) (*memory_callback) (dwfl, -1, &buffer, &buffer_available, 0, 0,
279cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng				 memory_callback_arg);
280cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    return result;
281cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  }
282cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
283cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  GElf_Addr addrs[4];
284cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  inline bool read_addrs (GElf_Addr vaddr, size_t n)
285cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  {
286cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    size_t nb = n * addrsize (elfclass); /* Address words -> bytes to read.  */
287cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
288cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    /* Read a new buffer if the old one doesn't cover these words.  */
289cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    if (buffer == NULL
290cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	|| vaddr < read_vaddr
291cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	|| vaddr - read_vaddr + nb > buffer_available)
292cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      {
293cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	release_buffer (0);
294cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
295cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	read_vaddr = vaddr;
296cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	int segndx = INTUSE(dwfl_addrsegment) (dwfl, vaddr, NULL);
297cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	if (unlikely (segndx < 0)
298cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    || unlikely (! (*memory_callback) (dwfl, segndx,
299cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng					       &buffer, &buffer_available,
300cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng					       vaddr, nb, memory_callback_arg)))
301cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  return true;
302cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      }
303cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
304cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    const union
305cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    {
306cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      Elf32_Addr a32[n];
307cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      Elf64_Addr a64[n];
308cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    } *in = vaddr - read_vaddr + buffer;
309cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
310cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    if (elfclass == ELFCLASS32)
311cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      {
312cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	if (elfdata == ELFDATA2MSB)
313cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  for (size_t i = 0; i < n; ++i)
314cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    addrs[i] = BE32 (in->a32[i]);
315cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	else
316cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  for (size_t i = 0; i < n; ++i)
317cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    addrs[i] = LE32 (in->a32[i]);
318cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      }
319cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    else
320cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      {
321cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	if (elfdata == ELFDATA2MSB)
322cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  for (size_t i = 0; i < n; ++i)
323cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    addrs[i] = BE64 (in->a64[i]);
324cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	else
325cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  for (size_t i = 0; i < n; ++i)
326cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    addrs[i] = LE64 (in->a64[i]);
327cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      }
328cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
329cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    return false;
330cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  }
331cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
332cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (unlikely (read_addrs (read_vaddr, 1)))
333cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    return release_buffer (-1);
334cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
335cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  GElf_Addr next = addrs[0];
336cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
337cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  Dwfl_Module **lastmodp = &dwfl->modulelist;
338cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  int result = 0;
339cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  while (next != 0)
340cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    {
341cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (read_addrs (next, 4))
342cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	return release_buffer (-1);
343cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
344cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      GElf_Addr l_addr = addrs[0];
345cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      GElf_Addr l_name = addrs[1];
346cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      GElf_Addr l_ld = addrs[2];
347cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      next = addrs[3];
348cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
349cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      /* Fetch the string at the l_name address.  */
350cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      const char *name = NULL;
351cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (buffer != NULL
352cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  && read_vaddr <= l_name
353cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  && l_name + 1 - read_vaddr < buffer_available
354cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  && memchr (l_name - read_vaddr + buffer, '\0',
355cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		     buffer_available - (l_name - read_vaddr)) != NULL)
356cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	name = l_name - read_vaddr + buffer;
357cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      else
358cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	{
359cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  release_buffer (0);
360cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  read_vaddr = l_name;
361cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  int segndx = INTUSE(dwfl_addrsegment) (dwfl, l_name, NULL);
362cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  if (likely (segndx >= 0)
363cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      && (*memory_callback) (dwfl, segndx,
364cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng				     &buffer, &buffer_available,
365cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng				     l_name, 0, memory_callback_arg))
366cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    name = buffer;
367cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	}
368cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
369cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (name != NULL && name[0] == '\0')
370cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	name = NULL;
371cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
372cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      /* If content-sniffing already reported a module covering
373cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	 the same area, find that existing module to adjust.
374cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	 The l_ld address is the only one we know for sure
375cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	 to be within the module's own segments (its .dynamic).  */
376cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      Dwfl_Module *mod;
377cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      int segndx = INTUSE(dwfl_addrsegment) (dwfl, l_ld, &mod);
378cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (unlikely (segndx < 0))
379cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	return release_buffer (-1);
380cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
381cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (mod != NULL)
382cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	{
383cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  /* We have a module.  We can give it a better name from l_name.  */
384cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  if (name != NULL && mod->name[0] == '[')
385cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    {
386cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      char *newname = strdup (basename (name));
387cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      if (newname != NULL)
388cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		{
389cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		  free (mod->name);
390cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		  mod->name = newname;
391cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		}
392cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    }
393cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
394cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  if (name == NULL && mod->name[0] == '/')
395cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    name = mod->name;
396cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
397cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  /* If we don't have a file for it already, we can pre-install
398cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	     the full file name from l_name.  Opening the file by this
399cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	     name will be the fallback when no build ID match is found.
400cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	     XXX hook for sysroot */
401cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  if (name != NULL
402cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      && mod->main.elf == NULL
403cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      && mod->main.name == NULL)
404cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    mod->main.name = strdup (name);
405cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	}
406cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      else if (name != NULL)
407cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	{
408cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  /* We have to find the file's phdrs to compute along with l_addr
409cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	     what its runtime address boundaries are.  */
410cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
411cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  // XXX hook for sysroot
412cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  mod = INTUSE(dwfl_report_elf) (dwfl, basename (name),
413cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng					 name, -1, l_addr);
414cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	}
415cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
416cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (mod != NULL)
417cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	{
418cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  ++result;
419cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
420cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  /* Move this module to the end of the list, so that we end
421cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	     up with a list in the same order as the link_map chain.  */
422cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  if (mod->next != NULL)
423cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    {
424cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      if (*lastmodp != mod)
425cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		{
426cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		  lastmodp = &dwfl->modulelist;
427cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		  while (*lastmodp != mod)
428cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		    lastmodp = &(*lastmodp)->next;
429cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		}
430cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      *lastmodp = mod->next;
431cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      mod->next = NULL;
432cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      while (*lastmodp != NULL)
433cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		lastmodp = &(*lastmodp)->next;
434cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      *lastmodp = mod;
435cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    }
436cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
437cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  lastmodp = &mod->next;
438cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	}
439cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    }
440cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
441cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  return release_buffer (result);
442cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng}
443cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
444cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengstatic GElf_Addr
445cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengconsider_executable (Dwfl_Module *mod, GElf_Addr at_phdr, GElf_Addr at_entry,
446cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		     uint_fast8_t *elfclass, uint_fast8_t *elfdata,
447cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		     Dwfl_Memory_Callback *memory_callback,
448cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		     void *memory_callback_arg)
449cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng{
450cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  GElf_Ehdr ehdr;
451cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (unlikely (gelf_getehdr (mod->main.elf, &ehdr) == NULL))
452cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    return 0;
453cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
454cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (at_entry != 0)
455cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    {
456cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      /* If we have an AT_ENTRY value, reject this executable if
457cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	 its entry point address could not have supplied that.  */
458cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
459cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (ehdr.e_entry == 0)
460cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	return 0;
461cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
462cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (mod->e_type == ET_EXEC)
463cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	{
464cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  if (ehdr.e_entry != at_entry)
465cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    return 0;
466cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	}
467cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      else
468cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	{
469cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  /* It could be a PIE.  */
470cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	}
471cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    }
472cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
473cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  // XXX this could be saved in the file cache: phdr vaddr, DT_DEBUG d_val vaddr
474cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  /* Find the vaddr of the DT_DEBUG's d_ptr.  This is the memory
475cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng     address where &r_debug was written at runtime.  */
476cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  GElf_Xword align = mod->dwfl->segment_align;
477cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  GElf_Addr d_val_vaddr = 0;
478cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  for (uint_fast16_t i = 0; i < ehdr.e_phnum; ++i)
479cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    {
480cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      GElf_Phdr phdr_mem;
481cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      GElf_Phdr *phdr = gelf_getphdr (mod->main.elf, i, &phdr_mem);
482cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (phdr == NULL)
483cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	break;
484cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
485cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (phdr->p_align > 1 && (align == 0 || phdr->p_align < align))
486cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	align = phdr->p_align;
487cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
488cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (at_phdr != 0
489cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  && phdr->p_type == PT_LOAD
490cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  && (phdr->p_offset & -align) == (ehdr.e_phoff & -align))
491cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	{
492cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  /* This is the segment that would map the phdrs.
493cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	     If we have an AT_PHDR value, reject this executable
494cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	     if its phdr mapping could not have supplied that.  */
495cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  if (mod->e_type == ET_EXEC)
496cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    {
497cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      if (ehdr.e_phoff - phdr->p_offset + phdr->p_vaddr != at_phdr)
498cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		return 0;
499cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    }
500cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  else
501cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    {
502cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      /* It could be a PIE.  If the AT_PHDR value and our
503cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		 phdr address don't match modulo ALIGN, then this
504cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		 could not have been the right PIE.  */
505cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      if (((ehdr.e_phoff - phdr->p_offset + phdr->p_vaddr) & -align)
506cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		  != (at_phdr & -align))
507cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		return 0;
508cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
509cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      /* Calculate the bias applied to the PIE's p_vaddr values.  */
510cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      GElf_Addr bias = (at_phdr - (ehdr.e_phoff - phdr->p_offset
511cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng					   + phdr->p_vaddr));
512cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
513cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      /* Final sanity check: if we have an AT_ENTRY value,
514cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		 reject this PIE unless its biased e_entry matches.  */
515cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      if (at_entry != 0 && at_entry != ehdr.e_entry + bias)
516cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		return 0;
517cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
518cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      /* If we're changing the module's address range,
519cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		 we've just invalidated the module lookup table.  */
520cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      if (bias != mod->main.bias)
521cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		{
522cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		  mod->low_addr -= mod->main.bias;
523cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		  mod->high_addr -= mod->main.bias;
524cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		  mod->main.bias = bias;
525cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		  mod->low_addr += bias;
526cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		  mod->high_addr += bias;
527cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
528cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		  free (mod->dwfl->lookup_module);
529cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		  mod->dwfl->lookup_module = NULL;
530cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		}
531cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    }
532cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	}
533cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
534cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (phdr->p_type == PT_DYNAMIC)
535cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	{
536cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  Elf_Data *data = elf_getdata_rawchunk (mod->main.elf, phdr->p_offset,
537cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng						 phdr->p_filesz, ELF_T_DYN);
538cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  if (data == NULL)
539cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    continue;
540cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  const size_t entsize = gelf_fsize (mod->main.elf,
541cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng					     ELF_T_DYN, 1, EV_CURRENT);
542cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  const size_t n = data->d_size / entsize;
543cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  for (size_t j = 0; j < n; ++j)
544cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    {
545cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      GElf_Dyn dyn_mem;
546cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      GElf_Dyn *dyn = gelf_getdyn (data, j, &dyn_mem);
547cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      if (dyn != NULL && dyn->d_tag == DT_DEBUG)
548cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		{
549cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		  d_val_vaddr = phdr->p_vaddr + entsize * j + entsize / 2;
550cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		  break;
551cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		}
552cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    }
553cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	}
554cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    }
555cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
556cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (d_val_vaddr != 0)
557cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    {
558cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      /* Now we have the final address from which to read &r_debug.  */
559cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      d_val_vaddr += mod->main.bias;
560cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
561cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      void *buffer = NULL;
562cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      size_t buffer_available = addrsize (ehdr.e_ident[EI_CLASS]);
563cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
564cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      Dwfl_Module *m;
565cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      int segndx = INTUSE(dwfl_addrsegment) (mod->dwfl, d_val_vaddr, &m);
566cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      assert (m == mod);
567cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
568cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if ((*memory_callback) (mod->dwfl, segndx,
569cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			      &buffer, &buffer_available,
570cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			      d_val_vaddr, buffer_available,
571cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			      memory_callback_arg))
572cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	{
573cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  const union
574cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  {
575cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    Elf32_Addr a32;
576cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    Elf64_Addr a64;
577cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  } *u = buffer;
578cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
579cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  GElf_Addr vaddr;
580cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  if (ehdr.e_ident[EI_CLASS] == ELFCLASS32)
581cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    vaddr = (ehdr.e_ident[EI_DATA] == ELFDATA2MSB
582cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		     ? BE32 (u->a32) : LE32 (u->a32));
583cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  else
584cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    vaddr = (ehdr.e_ident[EI_DATA] == ELFDATA2MSB
585cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		     ? BE64 (u->a64) : LE64 (u->a64));
586cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
587cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  (*memory_callback) (mod->dwfl, -1, &buffer, &buffer_available, 0, 0,
588cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			      memory_callback_arg);
589cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
590cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
591cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  if (*elfclass == ELFCLASSNONE)
592cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    *elfclass = ehdr.e_ident[EI_CLASS];
593cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  else if (*elfclass != ehdr.e_ident[EI_CLASS])
594cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    return 0;
595cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
596cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  if (*elfdata == ELFDATANONE)
597cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    *elfdata = ehdr.e_ident[EI_DATA];
598cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  else if (*elfdata != ehdr.e_ident[EI_DATA])
599cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    return 0;
600cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
601cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  return vaddr;
602cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	}
603cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    }
604cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
605cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  return 0;
606cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng}
607cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
608cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng/* Try to find an existing executable module with a DT_DEBUG.  */
609cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengstatic GElf_Addr
610cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengfind_executable (Dwfl *dwfl, GElf_Addr at_phdr, GElf_Addr at_entry,
611cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		 uint_fast8_t *elfclass, uint_fast8_t *elfdata,
612cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		 Dwfl_Memory_Callback *memory_callback,
613cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		 void *memory_callback_arg)
614cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng{
615cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  for (Dwfl_Module *mod = dwfl->modulelist; mod != NULL; mod = mod->next)
616cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    if (mod->main.elf != NULL)
617cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      {
618cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	GElf_Addr r_debug_vaddr = consider_executable (mod, at_phdr, at_entry,
619cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng						       elfclass, elfdata,
620cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng						       memory_callback,
621cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng						       memory_callback_arg);
622cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	if (r_debug_vaddr != 0)
623cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  return r_debug_vaddr;
624cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      }
625cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
626cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  return 0;
627cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng}
628cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
629cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
630cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengint
631cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengdwfl_link_map_report (Dwfl *dwfl, const void *auxv, size_t auxv_size,
632cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		      Dwfl_Memory_Callback *memory_callback,
633cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		      void *memory_callback_arg)
634cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng{
635cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  GElf_Addr r_debug_vaddr = 0;
636cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
637cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  uint_fast8_t elfclass = ELFCLASSNONE;
638cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  uint_fast8_t elfdata = ELFDATANONE;
639cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (likely (auxv != NULL)
640cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      && likely (auxv_format_probe (auxv, auxv_size, &elfclass, &elfdata)))
641cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    {
642cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      GElf_Addr entry = 0;
643cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      GElf_Addr phdr = 0;
644cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      GElf_Xword phent = 0;
645cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      GElf_Xword phnum = 0;
646cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
647cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng#define AUXV_SCAN(NN, BL) do					\
648cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	{							\
649cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  const Elf##NN##_auxv_t *av = auxv;			\
650cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  for (size_t i = 0; i < auxv_size / sizeof av[0]; ++i)	\
651cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    {							\
652cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      Elf##NN##_Addr val = BL##NN (av[i].a_un.a_val);	\
653cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      if (av[i].a_type == BL##NN (AT_ENTRY))		\
654cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		entry = val;					\
655cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      else if (av[i].a_type == BL##NN (AT_PHDR))	\
656cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		phdr = val;					\
657cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      else if (av[i].a_type == BL##NN (AT_PHNUM))	\
658cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		phnum = val;					\
659cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      else if (av[i].a_type == BL##NN (AT_PHENT))	\
660cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		phent = val;					\
661cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      else if (av[i].a_type == BL##NN (AT_PAGESZ))	\
662cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		{						\
663cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		  if (val > 1					\
664cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		      && (dwfl->segment_align == 0		\
665cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			  || val < dwfl->segment_align))	\
666cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		    dwfl->segment_align = val;			\
667cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		}						\
668cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    }							\
669cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	}							\
670cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      while (0)
671cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
672cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (elfclass == ELFCLASS32)
673cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	{
674cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  if (elfdata == ELFDATA2MSB)
675cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    AUXV_SCAN (32, BE);
676cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  else
677cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    AUXV_SCAN (32, LE);
678cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	}
679cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      else
680cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	{
681cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  if (elfdata == ELFDATA2MSB)
682cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    AUXV_SCAN (64, BE);
683cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  else
684cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    AUXV_SCAN (64, LE);
685cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	}
686cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
687cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      /* If we found the phdr dimensions, search phdrs for PT_DYNAMIC.  */
688cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      GElf_Addr dyn_vaddr = 0;
689cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      GElf_Xword dyn_filesz = 0;
690cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (phdr != 0 && phnum != 0)
691cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	{
692cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  Dwfl_Module *phdr_mod;
693cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  int phdr_segndx = INTUSE(dwfl_addrsegment) (dwfl, phdr, &phdr_mod);
694cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  Elf_Data in =
695cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    {
696cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      .d_type = ELF_T_PHDR,
697cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      .d_version = EV_CURRENT,
698cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      .d_size = phnum * phent,
699cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      .d_buf = NULL
700cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    };
701cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  if ((*memory_callback) (dwfl, phdr_segndx, &in.d_buf, &in.d_size,
702cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng				  phdr, phnum * phent, memory_callback_arg))
703cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    {
704cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      union
705cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      {
706cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		Elf32_Phdr p32;
707cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		Elf64_Phdr p64;
708cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		char data[phnum * phent];
709cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      } buf;
710cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      Elf_Data out =
711cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		{
712cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		  .d_type = ELF_T_PHDR,
713cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		  .d_version = EV_CURRENT,
714cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		  .d_size = phnum * phent,
715cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		  .d_buf = &buf
716cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		};
717cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      in.d_size = out.d_size;
718cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      if (likely ((elfclass == ELFCLASS32
719cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			   ? elf32_xlatetom : elf64_xlatetom)
720cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			  (&out, &in, elfdata) != NULL))
721cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		{
722cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		  /* We are looking for PT_DYNAMIC.  */
723cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		  const union
724cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		  {
725cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		    Elf32_Phdr p32[phnum];
726cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		    Elf64_Phdr p64[phnum];
727cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		  } *u = (void *) &buf;
728cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		  if (elfclass == ELFCLASS32)
729cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		    {
730cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		      for (size_t i = 0; i < phnum; ++i)
731cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			if (u->p32[i].p_type == PT_DYNAMIC)
732cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			  {
733cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			    dyn_vaddr = u->p32[i].p_vaddr;
734cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			    dyn_filesz = u->p32[i].p_filesz;
735cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			    break;
736cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			  }
737cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		    }
738cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		  else
739cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		    {
740cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		      for (size_t i = 0; i < phnum; ++i)
741cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			if (u->p64[i].p_type == PT_DYNAMIC)
742cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			  {
743cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			    dyn_vaddr = u->p64[i].p_vaddr;
744cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			    dyn_filesz = u->p64[i].p_filesz;
745cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			    break;
746cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			  }
747cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		    }
748cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		}
749cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
750cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      (*memory_callback) (dwfl, -1, &in.d_buf, &in.d_size, 0, 0,
751cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng				  memory_callback_arg);
752cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    }
753cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  else
754cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    /* We could not read the executable's phdrs from the
755cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	       memory image.  If we have a presupplied executable,
756cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	       we can still use the AT_PHDR and AT_ENTRY values to
757cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	       verify it, and to adjust its bias if it's a PIE.
758cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
759cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	       If there was an ET_EXEC module presupplied that contains
760cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	       the AT_PHDR address, then we only consider that one.
761cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	       We'll either accept it if its phdr location and e_entry
762cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	       make sense or reject it if they don't.  If there is no
763cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	       presupplied ET_EXEC, then look for a presupplied module,
764cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	       which might be a PIE (ET_DYN) that needs its bias adjusted.  */
765cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    r_debug_vaddr = ((phdr_mod == NULL
766cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			      || phdr_mod->main.elf == NULL
767cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			      || phdr_mod->e_type != ET_EXEC)
768cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			     ? find_executable (dwfl, phdr, entry,
769cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng						&elfclass, &elfdata,
770cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng						memory_callback,
771cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng						memory_callback_arg)
772cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			     : consider_executable (phdr_mod, phdr, entry,
773cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng						    &elfclass, &elfdata,
774cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng						    memory_callback,
775cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng						    memory_callback_arg));
776cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	}
777cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
778cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      /* If we found PT_DYNAMIC, search it for DT_DEBUG.  */
779cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (dyn_filesz != 0)
780cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	{
781cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  Elf_Data in =
782cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    {
783cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      .d_type = ELF_T_DYN,
784cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      .d_version = EV_CURRENT,
785cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      .d_size = dyn_filesz,
786cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      .d_buf = NULL
787cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    };
788cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  int dyn_segndx = dwfl_addrsegment (dwfl, dyn_vaddr, NULL);
789cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  if ((*memory_callback) (dwfl, dyn_segndx, &in.d_buf, &in.d_size,
790cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng				  dyn_vaddr, dyn_filesz, memory_callback_arg))
791cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    {
792cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      union
793cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      {
794cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		Elf32_Dyn d32;
795cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		Elf64_Dyn d64;
796cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		char data[dyn_filesz];
797cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      } buf;
798cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      Elf_Data out =
799cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		{
800cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		  .d_type = ELF_T_DYN,
801cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		  .d_version = EV_CURRENT,
802cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		  .d_size = dyn_filesz,
803cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		  .d_buf = &buf
804cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		};
805cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      in.d_size = out.d_size;
806cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      if (likely ((elfclass == ELFCLASS32
807cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			   ? elf32_xlatetom : elf64_xlatetom)
808cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			  (&out, &in, elfdata) != NULL))
809cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		{
810cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		  /* We are looking for PT_DYNAMIC.  */
811cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		  const union
812cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		  {
813cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		    Elf32_Dyn d32[dyn_filesz / sizeof (Elf32_Dyn)];
814cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		    Elf64_Dyn d64[dyn_filesz / sizeof (Elf64_Dyn)];
815cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		  } *u = (void *) &buf;
816cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		  if (elfclass == ELFCLASS32)
817cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		    {
818cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		      size_t n = dyn_filesz / sizeof (Elf32_Dyn);
819cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		      for (size_t i = 0; i < n; ++i)
820cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			if (u->d32[i].d_tag == DT_DEBUG)
821cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			  {
822cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			    r_debug_vaddr = u->d32[i].d_un.d_val;
823cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			    break;
824cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			  }
825cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		    }
826cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		  else
827cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		    {
828cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		      size_t n = dyn_filesz / sizeof (Elf64_Dyn);
829cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		      for (size_t i = 0; i < n; ++i)
830cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			if (u->d64[i].d_tag == DT_DEBUG)
831cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			  {
832cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			    r_debug_vaddr = u->d64[i].d_un.d_val;
833cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			    break;
834cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			  }
835cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		    }
836cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		}
837cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
838cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      (*memory_callback) (dwfl, -1, &in.d_buf, &in.d_size, 0, 0,
839cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng				  memory_callback_arg);
840cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    }
841cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	}
842cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    }
843cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  else
844cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    /* We have to look for a presupplied executable file to determine
845cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng       the vaddr of its dynamic section and DT_DEBUG therein.  */
846cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    r_debug_vaddr = find_executable (dwfl, 0, 0, &elfclass, &elfdata,
847cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng				     memory_callback, memory_callback_arg);
848cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
849cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (r_debug_vaddr == 0)
850cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    return 0;
851cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
852cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  /* For following pointers from struct link_map, we will use an
853cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng     integrated memory access callback that can consult module text
854cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng     elided from the core file.  This is necessary when the l_name
855cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng     pointer for the dynamic linker's own entry is a pointer into the
856cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng     executable's .interp section.  */
857cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  struct integrated_memory_callback mcb =
858cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    {
859cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      .memory_callback = memory_callback,
860cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      .memory_callback_arg = memory_callback_arg
861cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    };
862cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
863cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  /* Now we can follow the dynamic linker's library list.  */
864cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  return report_r_debug (elfclass, elfdata, dwfl, r_debug_vaddr,
865cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			 &integrated_memory_callback, &mcb);
866cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng}
867cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben ChengINTDEF (dwfl_link_map_report)
868