xref: /third_party/elfutils/libdwfl/link_map.c (revision da0c48c4)
1da0c48c4Sopenharmony_ci/* Report modules by examining dynamic linker data structures.
2da0c48c4Sopenharmony_ci   Copyright (C) 2008-2016 Red Hat, Inc.
3da0c48c4Sopenharmony_ci   Copyright (C) 2021 Mark J. Wielaard <mark@klomp.org>
4da0c48c4Sopenharmony_ci   This file is part of elfutils.
5da0c48c4Sopenharmony_ci
6da0c48c4Sopenharmony_ci   This file is free software; you can redistribute it and/or modify
7da0c48c4Sopenharmony_ci   it under the terms of either
8da0c48c4Sopenharmony_ci
9da0c48c4Sopenharmony_ci     * the GNU Lesser General Public License as published by the Free
10da0c48c4Sopenharmony_ci       Software Foundation; either version 3 of the License, or (at
11da0c48c4Sopenharmony_ci       your option) any later version
12da0c48c4Sopenharmony_ci
13da0c48c4Sopenharmony_ci   or
14da0c48c4Sopenharmony_ci
15da0c48c4Sopenharmony_ci     * the GNU General Public License as published by the Free
16da0c48c4Sopenharmony_ci       Software Foundation; either version 2 of the License, or (at
17da0c48c4Sopenharmony_ci       your option) any later version
18da0c48c4Sopenharmony_ci
19da0c48c4Sopenharmony_ci   or both in parallel, as here.
20da0c48c4Sopenharmony_ci
21da0c48c4Sopenharmony_ci   elfutils is distributed in the hope that it will be useful, but
22da0c48c4Sopenharmony_ci   WITHOUT ANY WARRANTY; without even the implied warranty of
23da0c48c4Sopenharmony_ci   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
24da0c48c4Sopenharmony_ci   General Public License for more details.
25da0c48c4Sopenharmony_ci
26da0c48c4Sopenharmony_ci   You should have received copies of the GNU General Public License and
27da0c48c4Sopenharmony_ci   the GNU Lesser General Public License along with this program.  If
28da0c48c4Sopenharmony_ci   not, see <http://www.gnu.org/licenses/>.  */
29da0c48c4Sopenharmony_ci
30da0c48c4Sopenharmony_ci#include <config.h>
31da0c48c4Sopenharmony_ci#include "libdwflP.h"
32da0c48c4Sopenharmony_ci#include "../libdw/memory-access.h"
33da0c48c4Sopenharmony_ci#include "system.h"
34da0c48c4Sopenharmony_ci
35da0c48c4Sopenharmony_ci#include <fcntl.h>
36da0c48c4Sopenharmony_ci
37da0c48c4Sopenharmony_ci/* This element is always provided and always has a constant value.
38da0c48c4Sopenharmony_ci   This makes it an easy thing to scan for to discern the format.  */
39da0c48c4Sopenharmony_ci#define PROBE_TYPE	AT_PHENT
40da0c48c4Sopenharmony_ci#define PROBE_VAL32	sizeof (Elf32_Phdr)
41da0c48c4Sopenharmony_ci#define PROBE_VAL64	sizeof (Elf64_Phdr)
42da0c48c4Sopenharmony_ci
43da0c48c4Sopenharmony_ci
44da0c48c4Sopenharmony_cistatic inline bool
45da0c48c4Sopenharmony_cido_check64 (const char *a64, uint_fast8_t *elfdata)
46da0c48c4Sopenharmony_ci{
47da0c48c4Sopenharmony_ci  /* The AUXV pointer might not even be naturally aligned for 64-bit
48da0c48c4Sopenharmony_ci     data, because note payloads in a core file are not aligned.  */
49da0c48c4Sopenharmony_ci  const char *typep = a64 + offsetof (Elf64_auxv_t, a_type);
50da0c48c4Sopenharmony_ci  uint64_t type = read_8ubyte_unaligned_noncvt (typep);
51da0c48c4Sopenharmony_ci  const char *valp = a64 + offsetof (Elf64_auxv_t, a_un.a_val);
52da0c48c4Sopenharmony_ci  uint64_t val = read_8ubyte_unaligned_noncvt (valp);
53da0c48c4Sopenharmony_ci
54da0c48c4Sopenharmony_ci  if (type == BE64 (PROBE_TYPE)
55da0c48c4Sopenharmony_ci      && val == BE64 (PROBE_VAL64))
56da0c48c4Sopenharmony_ci    {
57da0c48c4Sopenharmony_ci      *elfdata = ELFDATA2MSB;
58da0c48c4Sopenharmony_ci      return true;
59da0c48c4Sopenharmony_ci    }
60da0c48c4Sopenharmony_ci
61da0c48c4Sopenharmony_ci  if (type == LE64 (PROBE_TYPE)
62da0c48c4Sopenharmony_ci      && val == LE64 (PROBE_VAL64))
63da0c48c4Sopenharmony_ci    {
64da0c48c4Sopenharmony_ci      *elfdata = ELFDATA2LSB;
65da0c48c4Sopenharmony_ci      return true;
66da0c48c4Sopenharmony_ci    }
67da0c48c4Sopenharmony_ci
68da0c48c4Sopenharmony_ci  return false;
69da0c48c4Sopenharmony_ci}
70da0c48c4Sopenharmony_ci
71da0c48c4Sopenharmony_cistatic inline bool
72da0c48c4Sopenharmony_cido_check32 (const char *a32, uint_fast8_t *elfdata)
73da0c48c4Sopenharmony_ci{
74da0c48c4Sopenharmony_ci  /* The AUXV pointer might not even be naturally aligned for 32-bit
75da0c48c4Sopenharmony_ci     data, because note payloads in a core file are not aligned.  */
76da0c48c4Sopenharmony_ci  const char *typep = a32 + offsetof (Elf32_auxv_t, a_type);
77da0c48c4Sopenharmony_ci  uint32_t type = read_4ubyte_unaligned_noncvt (typep);
78da0c48c4Sopenharmony_ci  const char *valp = a32 + offsetof (Elf32_auxv_t, a_un.a_val);
79da0c48c4Sopenharmony_ci  uint32_t val = read_4ubyte_unaligned_noncvt (valp);
80da0c48c4Sopenharmony_ci
81da0c48c4Sopenharmony_ci  if (type == BE32 (PROBE_TYPE)
82da0c48c4Sopenharmony_ci      && val == BE32 (PROBE_VAL32))
83da0c48c4Sopenharmony_ci    {
84da0c48c4Sopenharmony_ci      *elfdata = ELFDATA2MSB;
85da0c48c4Sopenharmony_ci      return true;
86da0c48c4Sopenharmony_ci    }
87da0c48c4Sopenharmony_ci
88da0c48c4Sopenharmony_ci  if (type == LE32 (PROBE_TYPE)
89da0c48c4Sopenharmony_ci      && val == LE32 (PROBE_VAL32))
90da0c48c4Sopenharmony_ci    {
91da0c48c4Sopenharmony_ci      *elfdata = ELFDATA2LSB;
92da0c48c4Sopenharmony_ci      return true;
93da0c48c4Sopenharmony_ci    }
94da0c48c4Sopenharmony_ci
95da0c48c4Sopenharmony_ci  return false;
96da0c48c4Sopenharmony_ci}
97da0c48c4Sopenharmony_ci
98da0c48c4Sopenharmony_ci/* Examine an auxv data block and determine its format.
99da0c48c4Sopenharmony_ci   Return true iff we figured it out.  */
100da0c48c4Sopenharmony_cistatic bool
101da0c48c4Sopenharmony_ciauxv_format_probe (const void *auxv, size_t size,
102da0c48c4Sopenharmony_ci		   uint_fast8_t *elfclass, uint_fast8_t *elfdata)
103da0c48c4Sopenharmony_ci{
104da0c48c4Sopenharmony_ci  for (size_t i = 0; i < size / sizeof (Elf64_auxv_t); ++i)
105da0c48c4Sopenharmony_ci    {
106da0c48c4Sopenharmony_ci      if (do_check64 (auxv + i * sizeof (Elf64_auxv_t), elfdata))
107da0c48c4Sopenharmony_ci	{
108da0c48c4Sopenharmony_ci	  *elfclass = ELFCLASS64;
109da0c48c4Sopenharmony_ci	  return true;
110da0c48c4Sopenharmony_ci	}
111da0c48c4Sopenharmony_ci
112da0c48c4Sopenharmony_ci      if (do_check32 (auxv + (i * 2) * sizeof (Elf32_auxv_t), elfdata)
113da0c48c4Sopenharmony_ci	  || do_check32 (auxv + (i * 2 + 1) * sizeof (Elf32_auxv_t), elfdata))
114da0c48c4Sopenharmony_ci	{
115da0c48c4Sopenharmony_ci	  *elfclass = ELFCLASS32;
116da0c48c4Sopenharmony_ci	  return true;
117da0c48c4Sopenharmony_ci	}
118da0c48c4Sopenharmony_ci    }
119da0c48c4Sopenharmony_ci
120da0c48c4Sopenharmony_ci  return false;
121da0c48c4Sopenharmony_ci}
122da0c48c4Sopenharmony_ci
123da0c48c4Sopenharmony_ci/* This is a Dwfl_Memory_Callback that wraps another memory callback.
124da0c48c4Sopenharmony_ci   If the underlying callback cannot fill the data, then this will
125da0c48c4Sopenharmony_ci   fall back to fetching data from module files.  */
126da0c48c4Sopenharmony_ci
127da0c48c4Sopenharmony_cistruct integrated_memory_callback
128da0c48c4Sopenharmony_ci{
129da0c48c4Sopenharmony_ci  Dwfl_Memory_Callback *memory_callback;
130da0c48c4Sopenharmony_ci  void *memory_callback_arg;
131da0c48c4Sopenharmony_ci  void *buffer;
132da0c48c4Sopenharmony_ci};
133da0c48c4Sopenharmony_ci
134da0c48c4Sopenharmony_cistatic bool
135da0c48c4Sopenharmony_ciintegrated_memory_callback (Dwfl *dwfl, int ndx,
136da0c48c4Sopenharmony_ci			       void **buffer, size_t *buffer_available,
137da0c48c4Sopenharmony_ci			       GElf_Addr vaddr,
138da0c48c4Sopenharmony_ci			       size_t minread,
139da0c48c4Sopenharmony_ci			       void *arg)
140da0c48c4Sopenharmony_ci{
141da0c48c4Sopenharmony_ci  struct integrated_memory_callback *info = arg;
142da0c48c4Sopenharmony_ci
143da0c48c4Sopenharmony_ci  if (ndx == -1)
144da0c48c4Sopenharmony_ci    {
145da0c48c4Sopenharmony_ci      /* Called for cleanup.  */
146da0c48c4Sopenharmony_ci      if (info->buffer != NULL)
147da0c48c4Sopenharmony_ci	{
148da0c48c4Sopenharmony_ci	  /* The last probe buffer came from the underlying callback.
149da0c48c4Sopenharmony_ci	     Let it do its cleanup.  */
150da0c48c4Sopenharmony_ci	  assert (*buffer == info->buffer); /* XXX */
151da0c48c4Sopenharmony_ci	  *buffer = info->buffer;
152da0c48c4Sopenharmony_ci	  info->buffer = NULL;
153da0c48c4Sopenharmony_ci	  return (*info->memory_callback) (dwfl, ndx, buffer, buffer_available,
154da0c48c4Sopenharmony_ci					   vaddr, minread,
155da0c48c4Sopenharmony_ci					   info->memory_callback_arg);
156da0c48c4Sopenharmony_ci	}
157da0c48c4Sopenharmony_ci      *buffer = NULL;
158da0c48c4Sopenharmony_ci      *buffer_available = 0;
159da0c48c4Sopenharmony_ci      return false;
160da0c48c4Sopenharmony_ci    }
161da0c48c4Sopenharmony_ci
162da0c48c4Sopenharmony_ci  if (*buffer != NULL)
163da0c48c4Sopenharmony_ci    /* For a final-read request, we only use the underlying callback.  */
164da0c48c4Sopenharmony_ci    return (*info->memory_callback) (dwfl, ndx, buffer, buffer_available,
165da0c48c4Sopenharmony_ci				     vaddr, minread, info->memory_callback_arg);
166da0c48c4Sopenharmony_ci
167da0c48c4Sopenharmony_ci  /* Let the underlying callback try to fill this request.  */
168da0c48c4Sopenharmony_ci  if ((*info->memory_callback) (dwfl, ndx, &info->buffer, buffer_available,
169da0c48c4Sopenharmony_ci				vaddr, minread, info->memory_callback_arg))
170da0c48c4Sopenharmony_ci    {
171da0c48c4Sopenharmony_ci      *buffer = info->buffer;
172da0c48c4Sopenharmony_ci      return true;
173da0c48c4Sopenharmony_ci    }
174da0c48c4Sopenharmony_ci
175da0c48c4Sopenharmony_ci  /* Now look for module text covering this address.  */
176da0c48c4Sopenharmony_ci
177da0c48c4Sopenharmony_ci  Dwfl_Module *mod;
178da0c48c4Sopenharmony_ci  (void) INTUSE(dwfl_addrsegment) (dwfl, vaddr, &mod);
179da0c48c4Sopenharmony_ci  if (mod == NULL)
180da0c48c4Sopenharmony_ci    return false;
181da0c48c4Sopenharmony_ci
182da0c48c4Sopenharmony_ci  Dwarf_Addr bias;
183da0c48c4Sopenharmony_ci  Elf_Scn *scn = INTUSE(dwfl_module_address_section) (mod, &vaddr, &bias);
184da0c48c4Sopenharmony_ci  if (unlikely (scn == NULL))
185da0c48c4Sopenharmony_ci    {
186da0c48c4Sopenharmony_ci#if 0 // XXX would have to handle ndx=-1 cleanup calls passed down.
187da0c48c4Sopenharmony_ci      /* If we have no sections we can try to fill it from the module file
188da0c48c4Sopenharmony_ci	 based on its phdr mappings.  */
189da0c48c4Sopenharmony_ci      if (likely (mod->e_type != ET_REL) && mod->main.elf != NULL)
190da0c48c4Sopenharmony_ci	return INTUSE(dwfl_elf_phdr_memory_callback)
191da0c48c4Sopenharmony_ci	  (dwfl, 0, buffer, buffer_available,
192da0c48c4Sopenharmony_ci	   vaddr - mod->main.bias, minread, mod->main.elf);
193da0c48c4Sopenharmony_ci#endif
194da0c48c4Sopenharmony_ci      return false;
195da0c48c4Sopenharmony_ci    }
196da0c48c4Sopenharmony_ci
197da0c48c4Sopenharmony_ci  Elf_Data *data = elf_rawdata (scn, NULL);
198da0c48c4Sopenharmony_ci  if (unlikely (data == NULL))
199da0c48c4Sopenharmony_ci    // XXX throw error?
200da0c48c4Sopenharmony_ci    return false;
201da0c48c4Sopenharmony_ci
202da0c48c4Sopenharmony_ci  if (unlikely (data->d_size < vaddr))
203da0c48c4Sopenharmony_ci    return false;
204da0c48c4Sopenharmony_ci
205da0c48c4Sopenharmony_ci  /* Provide as much data as we have.  */
206da0c48c4Sopenharmony_ci  void *contents = data->d_buf + vaddr;
207da0c48c4Sopenharmony_ci  size_t avail = data->d_size - vaddr;
208da0c48c4Sopenharmony_ci  if (unlikely (avail < minread))
209da0c48c4Sopenharmony_ci    return false;
210da0c48c4Sopenharmony_ci
211da0c48c4Sopenharmony_ci  /* If probing for a string, make sure it's terminated.  */
212da0c48c4Sopenharmony_ci  if (minread == 0 && unlikely (memchr (contents, '\0', avail) == NULL))
213da0c48c4Sopenharmony_ci    return false;
214da0c48c4Sopenharmony_ci
215da0c48c4Sopenharmony_ci  /* We have it! */
216da0c48c4Sopenharmony_ci  *buffer = contents;
217da0c48c4Sopenharmony_ci  *buffer_available = avail;
218da0c48c4Sopenharmony_ci  return true;
219da0c48c4Sopenharmony_ci}
220da0c48c4Sopenharmony_ci
221da0c48c4Sopenharmony_cistatic size_t
222da0c48c4Sopenharmony_ciaddrsize (uint_fast8_t elfclass)
223da0c48c4Sopenharmony_ci{
224da0c48c4Sopenharmony_ci  return elfclass * 4;
225da0c48c4Sopenharmony_ci}
226da0c48c4Sopenharmony_ci
227da0c48c4Sopenharmony_cistruct memory_closure
228da0c48c4Sopenharmony_ci{
229da0c48c4Sopenharmony_ci  Dwfl *dwfl;
230da0c48c4Sopenharmony_ci  Dwfl_Memory_Callback *callback;
231da0c48c4Sopenharmony_ci  void *arg;
232da0c48c4Sopenharmony_ci};
233da0c48c4Sopenharmony_ci
234da0c48c4Sopenharmony_cistatic inline int
235da0c48c4Sopenharmony_cirelease_buffer (struct memory_closure *closure,
236da0c48c4Sopenharmony_ci                void **buffer, size_t *buffer_available, int result)
237da0c48c4Sopenharmony_ci{
238da0c48c4Sopenharmony_ci  if (*buffer != NULL)
239da0c48c4Sopenharmony_ci    (*closure->callback) (closure->dwfl, -1, buffer, buffer_available, 0, 0,
240da0c48c4Sopenharmony_ci                          closure->arg);
241da0c48c4Sopenharmony_ci
242da0c48c4Sopenharmony_ci  return result;
243da0c48c4Sopenharmony_ci}
244da0c48c4Sopenharmony_ci
245da0c48c4Sopenharmony_cistatic inline bool
246da0c48c4Sopenharmony_ciread_addrs (struct memory_closure *closure,
247da0c48c4Sopenharmony_ci	    uint_fast8_t elfclass, uint_fast8_t elfdata,
248da0c48c4Sopenharmony_ci	    void **buffer, size_t *buffer_available,
249da0c48c4Sopenharmony_ci	    GElf_Addr vaddr, GElf_Addr *read_vaddr,
250da0c48c4Sopenharmony_ci	    size_t n, GElf_Addr *addrs /* [4] */)
251da0c48c4Sopenharmony_ci{
252da0c48c4Sopenharmony_ci  size_t nb = n * addrsize (elfclass); /* Address words -> bytes to read.  */
253da0c48c4Sopenharmony_ci  Dwfl *dwfl = closure->dwfl;
254da0c48c4Sopenharmony_ci
255da0c48c4Sopenharmony_ci  /* Read a new buffer if the old one doesn't cover these words.  */
256da0c48c4Sopenharmony_ci  if (*buffer == NULL
257da0c48c4Sopenharmony_ci      || vaddr < *read_vaddr
258da0c48c4Sopenharmony_ci      || nb > *buffer_available
259da0c48c4Sopenharmony_ci      || vaddr - (*read_vaddr) > *buffer_available - nb)
260da0c48c4Sopenharmony_ci    {
261da0c48c4Sopenharmony_ci      release_buffer (closure, buffer, buffer_available, 0);
262da0c48c4Sopenharmony_ci
263da0c48c4Sopenharmony_ci      *read_vaddr = vaddr;
264da0c48c4Sopenharmony_ci      int segndx = INTUSE(dwfl_addrsegment) (dwfl, vaddr, NULL);
265da0c48c4Sopenharmony_ci      if (unlikely (segndx < 0)
266da0c48c4Sopenharmony_ci	  || unlikely (! (*closure->callback) (dwfl, segndx,
267da0c48c4Sopenharmony_ci					       buffer, buffer_available,
268da0c48c4Sopenharmony_ci					       vaddr, nb, closure->arg)))
269da0c48c4Sopenharmony_ci	return true;
270da0c48c4Sopenharmony_ci    }
271da0c48c4Sopenharmony_ci
272da0c48c4Sopenharmony_ci  unsigned char *addr = vaddr - (*read_vaddr) + (*buffer);
273da0c48c4Sopenharmony_ci
274da0c48c4Sopenharmony_ci  if (elfclass == ELFCLASS32)
275da0c48c4Sopenharmony_ci    {
276da0c48c4Sopenharmony_ci      if (elfdata == ELFDATA2MSB)
277da0c48c4Sopenharmony_ci	for (size_t i = 0; i < n; ++i)
278da0c48c4Sopenharmony_ci	  addrs[i] = BE32 (read_4ubyte_unaligned_noncvt (addr + i * 4));
279da0c48c4Sopenharmony_ci      else
280da0c48c4Sopenharmony_ci	for (size_t i = 0; i < n; ++i)
281da0c48c4Sopenharmony_ci	  addrs[i] = LE32 (read_4ubyte_unaligned_noncvt (addr + i * 4));
282da0c48c4Sopenharmony_ci    }
283da0c48c4Sopenharmony_ci  else
284da0c48c4Sopenharmony_ci    {
285da0c48c4Sopenharmony_ci      if (elfdata == ELFDATA2MSB)
286da0c48c4Sopenharmony_ci	for (size_t i = 0; i < n; ++i)
287da0c48c4Sopenharmony_ci	  addrs[i] = BE64 (read_8ubyte_unaligned_noncvt (addr + i * 8));
288da0c48c4Sopenharmony_ci      else
289da0c48c4Sopenharmony_ci	for (size_t i = 0; i < n; ++i)
290da0c48c4Sopenharmony_ci	  addrs[i] = LE64 (read_8ubyte_unaligned_noncvt (addr + i * 8));
291da0c48c4Sopenharmony_ci    }
292da0c48c4Sopenharmony_ci
293da0c48c4Sopenharmony_ci  return false;
294da0c48c4Sopenharmony_ci}
295da0c48c4Sopenharmony_ci
296da0c48c4Sopenharmony_ci/* Report a module for each struct link_map in the linked list at r_map
297da0c48c4Sopenharmony_ci   in the struct r_debug at R_DEBUG_VADDR.  For r_debug_info description
298da0c48c4Sopenharmony_ci   see dwfl_link_map_report in libdwflP.h.  If R_DEBUG_INFO is not NULL then no
299da0c48c4Sopenharmony_ci   modules get added to DWFL, caller has to add them from filled in
300da0c48c4Sopenharmony_ci   R_DEBUG_INFO.
301da0c48c4Sopenharmony_ci
302da0c48c4Sopenharmony_ci   For each link_map entry, if an existing module resides at its address,
303da0c48c4Sopenharmony_ci   this just modifies that module's name and suggested file name.  If
304da0c48c4Sopenharmony_ci   no such module exists, this calls dwfl_report_elf on the l_name string.
305da0c48c4Sopenharmony_ci
306da0c48c4Sopenharmony_ci   Returns the number of modules found, or -1 for errors.  */
307da0c48c4Sopenharmony_ci
308da0c48c4Sopenharmony_cistatic int
309da0c48c4Sopenharmony_cireport_r_debug (uint_fast8_t elfclass, uint_fast8_t elfdata,
310da0c48c4Sopenharmony_ci		Dwfl *dwfl, GElf_Addr r_debug_vaddr,
311da0c48c4Sopenharmony_ci		Dwfl_Memory_Callback *memory_callback,
312da0c48c4Sopenharmony_ci		void *memory_callback_arg,
313da0c48c4Sopenharmony_ci		struct r_debug_info *r_debug_info)
314da0c48c4Sopenharmony_ci{
315da0c48c4Sopenharmony_ci  /* Skip r_version, to aligned r_map field.  */
316da0c48c4Sopenharmony_ci  GElf_Addr read_vaddr = r_debug_vaddr + addrsize (elfclass);
317da0c48c4Sopenharmony_ci
318da0c48c4Sopenharmony_ci  void *buffer = NULL;
319da0c48c4Sopenharmony_ci  size_t buffer_available = 0;
320da0c48c4Sopenharmony_ci  GElf_Addr addrs[4];
321da0c48c4Sopenharmony_ci  struct memory_closure memory_closure = { dwfl, memory_callback,
322da0c48c4Sopenharmony_ci                                           memory_callback_arg };
323da0c48c4Sopenharmony_ci  if (unlikely (read_addrs (&memory_closure, elfclass, elfdata,
324da0c48c4Sopenharmony_ci			    &buffer, &buffer_available, read_vaddr, &read_vaddr,
325da0c48c4Sopenharmony_ci			    1, addrs)))
326da0c48c4Sopenharmony_ci    return release_buffer (&memory_closure, &buffer, &buffer_available, -1);
327da0c48c4Sopenharmony_ci
328da0c48c4Sopenharmony_ci  GElf_Addr next = addrs[0];
329da0c48c4Sopenharmony_ci
330da0c48c4Sopenharmony_ci  Dwfl_Module **lastmodp = &dwfl->modulelist;
331da0c48c4Sopenharmony_ci  int result = 0;
332da0c48c4Sopenharmony_ci
333da0c48c4Sopenharmony_ci  /* There can't be more elements in the link_map list than there are
334da0c48c4Sopenharmony_ci     segments.  DWFL->lookup_elts is probably twice that number, so it
335da0c48c4Sopenharmony_ci     is certainly above the upper bound.  If we iterate too many times,
336da0c48c4Sopenharmony_ci     there must be a loop in the pointers due to link_map clobberation.  */
337da0c48c4Sopenharmony_ci  size_t iterations = 0;
338da0c48c4Sopenharmony_ci  while (next != 0 && ++iterations < dwfl->lookup_elts)
339da0c48c4Sopenharmony_ci    {
340da0c48c4Sopenharmony_ci      if (read_addrs (&memory_closure, elfclass, elfdata,
341da0c48c4Sopenharmony_ci		      &buffer, &buffer_available, next, &read_vaddr,
342da0c48c4Sopenharmony_ci		      4, addrs))
343da0c48c4Sopenharmony_ci	return release_buffer (&memory_closure, &buffer, &buffer_available, -1);
344da0c48c4Sopenharmony_ci
345da0c48c4Sopenharmony_ci      /* Unused: l_addr is the difference between the address in memory
346da0c48c4Sopenharmony_ci         and the ELF file when the core was created. We need to
347da0c48c4Sopenharmony_ci         recalculate the difference below because the ELF file we use
348da0c48c4Sopenharmony_ci         might be differently pre-linked.  */
349da0c48c4Sopenharmony_ci      // GElf_Addr l_addr = addrs[0];
350da0c48c4Sopenharmony_ci      GElf_Addr l_name = addrs[1];
351da0c48c4Sopenharmony_ci      GElf_Addr l_ld = addrs[2];
352da0c48c4Sopenharmony_ci      next = addrs[3];
353da0c48c4Sopenharmony_ci
354da0c48c4Sopenharmony_ci      /* If a clobbered or truncated memory image has no useful pointer,
355da0c48c4Sopenharmony_ci	 just skip this element.  */
356da0c48c4Sopenharmony_ci      if (l_ld == 0)
357da0c48c4Sopenharmony_ci	continue;
358da0c48c4Sopenharmony_ci
359da0c48c4Sopenharmony_ci      /* Fetch the string at the l_name address.  */
360da0c48c4Sopenharmony_ci      const char *name = NULL;
361da0c48c4Sopenharmony_ci      if (buffer != NULL
362da0c48c4Sopenharmony_ci	  && read_vaddr <= l_name
363da0c48c4Sopenharmony_ci	  && l_name + 1 - read_vaddr < buffer_available
364da0c48c4Sopenharmony_ci	  && memchr (l_name - read_vaddr + buffer, '\0',
365da0c48c4Sopenharmony_ci		     buffer_available - (l_name - read_vaddr)) != NULL)
366da0c48c4Sopenharmony_ci	name = l_name - read_vaddr + buffer;
367da0c48c4Sopenharmony_ci      else
368da0c48c4Sopenharmony_ci	{
369da0c48c4Sopenharmony_ci	  release_buffer (&memory_closure, &buffer, &buffer_available, 0);
370da0c48c4Sopenharmony_ci	  read_vaddr = l_name;
371da0c48c4Sopenharmony_ci	  int segndx = INTUSE(dwfl_addrsegment) (dwfl, l_name, NULL);
372da0c48c4Sopenharmony_ci	  if (likely (segndx >= 0)
373da0c48c4Sopenharmony_ci	      && (*memory_callback) (dwfl, segndx,
374da0c48c4Sopenharmony_ci				     &buffer, &buffer_available,
375da0c48c4Sopenharmony_ci				     l_name, 0, memory_callback_arg))
376da0c48c4Sopenharmony_ci	    name = buffer;
377da0c48c4Sopenharmony_ci	}
378da0c48c4Sopenharmony_ci
379da0c48c4Sopenharmony_ci      if (name != NULL && name[0] == '\0')
380da0c48c4Sopenharmony_ci	name = NULL;
381da0c48c4Sopenharmony_ci
382da0c48c4Sopenharmony_ci      if (iterations == 1
383da0c48c4Sopenharmony_ci	  && dwfl->user_core != NULL
384da0c48c4Sopenharmony_ci	  && dwfl->user_core->executable_for_core != NULL)
385da0c48c4Sopenharmony_ci	name = dwfl->user_core->executable_for_core;
386da0c48c4Sopenharmony_ci
387da0c48c4Sopenharmony_ci      struct r_debug_info_module *r_debug_info_module = NULL;
388da0c48c4Sopenharmony_ci      if (r_debug_info != NULL)
389da0c48c4Sopenharmony_ci	{
390da0c48c4Sopenharmony_ci	  /* Save link map information about valid shared library (or
391da0c48c4Sopenharmony_ci	     executable) which has not been found on disk.  */
392da0c48c4Sopenharmony_ci	  const char *name1 = name == NULL ? "" : name;
393da0c48c4Sopenharmony_ci	  r_debug_info_module = malloc (sizeof (*r_debug_info_module)
394da0c48c4Sopenharmony_ci					+ strlen (name1) + 1);
395da0c48c4Sopenharmony_ci	  if (unlikely (r_debug_info_module == NULL))
396da0c48c4Sopenharmony_ci	    release_buffer (&memory_closure, &buffer,
397da0c48c4Sopenharmony_ci                            &buffer_available, result);
398da0c48c4Sopenharmony_ci	  r_debug_info_module->fd = -1;
399da0c48c4Sopenharmony_ci	  r_debug_info_module->elf = NULL;
400da0c48c4Sopenharmony_ci	  r_debug_info_module->l_ld = l_ld;
401da0c48c4Sopenharmony_ci	  r_debug_info_module->start = 0;
402da0c48c4Sopenharmony_ci	  r_debug_info_module->end = 0;
403da0c48c4Sopenharmony_ci	  r_debug_info_module->disk_file_has_build_id = false;
404da0c48c4Sopenharmony_ci	  strcpy (r_debug_info_module->name, name1);
405da0c48c4Sopenharmony_ci	  r_debug_info_module->next = r_debug_info->module;
406da0c48c4Sopenharmony_ci	  r_debug_info->module = r_debug_info_module;
407da0c48c4Sopenharmony_ci	}
408da0c48c4Sopenharmony_ci
409da0c48c4Sopenharmony_ci      Dwfl_Module *mod = NULL;
410da0c48c4Sopenharmony_ci      if (name != NULL)
411da0c48c4Sopenharmony_ci	{
412da0c48c4Sopenharmony_ci	  /* This code is mostly inlined dwfl_report_elf.  */
413da0c48c4Sopenharmony_ci	  // XXX hook for sysroot
414da0c48c4Sopenharmony_ci	  int fd = open (name, O_RDONLY);
415da0c48c4Sopenharmony_ci	  if (fd >= 0)
416da0c48c4Sopenharmony_ci	    {
417da0c48c4Sopenharmony_ci	      Elf *elf;
418da0c48c4Sopenharmony_ci	      Dwfl_Error error = __libdw_open_file (&fd, &elf, true, false);
419da0c48c4Sopenharmony_ci	      GElf_Addr elf_dynamic_vaddr;
420da0c48c4Sopenharmony_ci	      if (error == DWFL_E_NOERROR
421da0c48c4Sopenharmony_ci		  && __libdwfl_dynamic_vaddr_get (elf, &elf_dynamic_vaddr))
422da0c48c4Sopenharmony_ci		{
423da0c48c4Sopenharmony_ci		  const void *build_id_bits;
424da0c48c4Sopenharmony_ci		  GElf_Addr build_id_elfaddr;
425da0c48c4Sopenharmony_ci		  int build_id_len;
426da0c48c4Sopenharmony_ci		  bool valid = true;
427da0c48c4Sopenharmony_ci
428da0c48c4Sopenharmony_ci		  if (__libdwfl_find_elf_build_id (NULL, elf, &build_id_bits,
429da0c48c4Sopenharmony_ci						   &build_id_elfaddr,
430da0c48c4Sopenharmony_ci						   &build_id_len) > 0
431da0c48c4Sopenharmony_ci		      && build_id_elfaddr != 0)
432da0c48c4Sopenharmony_ci		    {
433da0c48c4Sopenharmony_ci		      if (r_debug_info_module != NULL)
434da0c48c4Sopenharmony_ci			r_debug_info_module->disk_file_has_build_id = true;
435da0c48c4Sopenharmony_ci		      GElf_Addr build_id_vaddr = (build_id_elfaddr
436da0c48c4Sopenharmony_ci						  - elf_dynamic_vaddr + l_ld);
437da0c48c4Sopenharmony_ci
438da0c48c4Sopenharmony_ci		      release_buffer (&memory_closure, &buffer,
439da0c48c4Sopenharmony_ci				      &buffer_available, 0);
440da0c48c4Sopenharmony_ci		      int segndx = INTUSE(dwfl_addrsegment) (dwfl,
441da0c48c4Sopenharmony_ci							     build_id_vaddr,
442da0c48c4Sopenharmony_ci							     NULL);
443da0c48c4Sopenharmony_ci		      if (! (*memory_callback) (dwfl, segndx,
444da0c48c4Sopenharmony_ci						&buffer, &buffer_available,
445da0c48c4Sopenharmony_ci						build_id_vaddr, build_id_len,
446da0c48c4Sopenharmony_ci						memory_callback_arg))
447da0c48c4Sopenharmony_ci			{
448da0c48c4Sopenharmony_ci			  /* File has valid build-id which cannot be read from
449da0c48c4Sopenharmony_ci			     memory.  This happens for core files without bit 4
450da0c48c4Sopenharmony_ci			     (0x10) set in Linux /proc/PID/coredump_filter.  */
451da0c48c4Sopenharmony_ci			}
452da0c48c4Sopenharmony_ci		      else
453da0c48c4Sopenharmony_ci			{
454da0c48c4Sopenharmony_ci			  if (memcmp (build_id_bits, buffer, build_id_len) != 0)
455da0c48c4Sopenharmony_ci			    /* File has valid build-id which does not match
456da0c48c4Sopenharmony_ci			       the one in memory.  */
457da0c48c4Sopenharmony_ci			    valid = false;
458da0c48c4Sopenharmony_ci			  release_buffer (&memory_closure, &buffer,
459da0c48c4Sopenharmony_ci					  &buffer_available, 0);
460da0c48c4Sopenharmony_ci
461da0c48c4Sopenharmony_ci			}
462da0c48c4Sopenharmony_ci		    }
463da0c48c4Sopenharmony_ci
464da0c48c4Sopenharmony_ci		  if (valid)
465da0c48c4Sopenharmony_ci		    {
466da0c48c4Sopenharmony_ci		      // It is like l_addr but it handles differently prelinked
467da0c48c4Sopenharmony_ci		      // files at core dumping vs. core loading time.
468da0c48c4Sopenharmony_ci		      GElf_Addr base = l_ld - elf_dynamic_vaddr;
469da0c48c4Sopenharmony_ci		      if (r_debug_info_module == NULL)
470da0c48c4Sopenharmony_ci			{
471da0c48c4Sopenharmony_ci			  // XXX hook for sysroot
472da0c48c4Sopenharmony_ci			  mod = __libdwfl_report_elf (dwfl, basename (name),
473da0c48c4Sopenharmony_ci						      name, fd, elf, base,
474da0c48c4Sopenharmony_ci						      true, true);
475da0c48c4Sopenharmony_ci			  if (mod != NULL)
476da0c48c4Sopenharmony_ci			    {
477da0c48c4Sopenharmony_ci			      elf = NULL;
478da0c48c4Sopenharmony_ci			      fd = -1;
479da0c48c4Sopenharmony_ci			    }
480da0c48c4Sopenharmony_ci			}
481da0c48c4Sopenharmony_ci		      else if (__libdwfl_elf_address_range (elf, base, true,
482da0c48c4Sopenharmony_ci							    true, NULL, NULL,
483da0c48c4Sopenharmony_ci						    &r_debug_info_module->start,
484da0c48c4Sopenharmony_ci						    &r_debug_info_module->end,
485da0c48c4Sopenharmony_ci							    NULL, NULL))
486da0c48c4Sopenharmony_ci			{
487da0c48c4Sopenharmony_ci			  r_debug_info_module->elf = elf;
488da0c48c4Sopenharmony_ci			  r_debug_info_module->fd = fd;
489da0c48c4Sopenharmony_ci			  elf = NULL;
490da0c48c4Sopenharmony_ci			  fd = -1;
491da0c48c4Sopenharmony_ci			}
492da0c48c4Sopenharmony_ci		    }
493da0c48c4Sopenharmony_ci		  if (elf != NULL)
494da0c48c4Sopenharmony_ci		    elf_end (elf);
495da0c48c4Sopenharmony_ci		  if (fd != -1)
496da0c48c4Sopenharmony_ci		    close (fd);
497da0c48c4Sopenharmony_ci		}
498da0c48c4Sopenharmony_ci	    }
499da0c48c4Sopenharmony_ci	}
500da0c48c4Sopenharmony_ci
501da0c48c4Sopenharmony_ci      if (mod != NULL)
502da0c48c4Sopenharmony_ci	{
503da0c48c4Sopenharmony_ci	  ++result;
504da0c48c4Sopenharmony_ci
505da0c48c4Sopenharmony_ci	  /* Move this module to the end of the list, so that we end
506da0c48c4Sopenharmony_ci	     up with a list in the same order as the link_map chain.  */
507da0c48c4Sopenharmony_ci	  if (mod->next != NULL)
508da0c48c4Sopenharmony_ci	    {
509da0c48c4Sopenharmony_ci	      if (*lastmodp != mod)
510da0c48c4Sopenharmony_ci		{
511da0c48c4Sopenharmony_ci		  lastmodp = &dwfl->modulelist;
512da0c48c4Sopenharmony_ci		  while (*lastmodp != mod)
513da0c48c4Sopenharmony_ci		    lastmodp = &(*lastmodp)->next;
514da0c48c4Sopenharmony_ci		}
515da0c48c4Sopenharmony_ci	      *lastmodp = mod->next;
516da0c48c4Sopenharmony_ci	      mod->next = NULL;
517da0c48c4Sopenharmony_ci	      while (*lastmodp != NULL)
518da0c48c4Sopenharmony_ci		lastmodp = &(*lastmodp)->next;
519da0c48c4Sopenharmony_ci	      *lastmodp = mod;
520da0c48c4Sopenharmony_ci	    }
521da0c48c4Sopenharmony_ci
522da0c48c4Sopenharmony_ci	  lastmodp = &mod->next;
523da0c48c4Sopenharmony_ci	}
524da0c48c4Sopenharmony_ci    }
525da0c48c4Sopenharmony_ci
526da0c48c4Sopenharmony_ci  return release_buffer (&memory_closure, &buffer, &buffer_available, result);
527da0c48c4Sopenharmony_ci}
528da0c48c4Sopenharmony_ci
529da0c48c4Sopenharmony_cistatic GElf_Addr
530da0c48c4Sopenharmony_ciconsider_executable (Dwfl_Module *mod, GElf_Addr at_phdr, GElf_Addr at_entry,
531da0c48c4Sopenharmony_ci		     uint_fast8_t *elfclass, uint_fast8_t *elfdata,
532da0c48c4Sopenharmony_ci		     Dwfl_Memory_Callback *memory_callback,
533da0c48c4Sopenharmony_ci		     void *memory_callback_arg)
534da0c48c4Sopenharmony_ci{
535da0c48c4Sopenharmony_ci  GElf_Ehdr ehdr;
536da0c48c4Sopenharmony_ci  if (unlikely (gelf_getehdr (mod->main.elf, &ehdr) == NULL))
537da0c48c4Sopenharmony_ci    return 0;
538da0c48c4Sopenharmony_ci
539da0c48c4Sopenharmony_ci  if (at_entry != 0)
540da0c48c4Sopenharmony_ci    {
541da0c48c4Sopenharmony_ci      /* If we have an AT_ENTRY value, reject this executable if
542da0c48c4Sopenharmony_ci	 its entry point address could not have supplied that.  */
543da0c48c4Sopenharmony_ci
544da0c48c4Sopenharmony_ci      if (ehdr.e_entry == 0)
545da0c48c4Sopenharmony_ci	return 0;
546da0c48c4Sopenharmony_ci
547da0c48c4Sopenharmony_ci      if (mod->e_type == ET_EXEC)
548da0c48c4Sopenharmony_ci	{
549da0c48c4Sopenharmony_ci	  if (ehdr.e_entry != at_entry)
550da0c48c4Sopenharmony_ci	    return 0;
551da0c48c4Sopenharmony_ci	}
552da0c48c4Sopenharmony_ci      else
553da0c48c4Sopenharmony_ci	{
554da0c48c4Sopenharmony_ci	  /* It could be a PIE.  */
555da0c48c4Sopenharmony_ci	}
556da0c48c4Sopenharmony_ci    }
557da0c48c4Sopenharmony_ci
558da0c48c4Sopenharmony_ci  // XXX this could be saved in the file cache: phdr vaddr, DT_DEBUG d_val vaddr
559da0c48c4Sopenharmony_ci  /* Find the vaddr of the DT_DEBUG's d_ptr.  This is the memory
560da0c48c4Sopenharmony_ci     address where &r_debug was written at runtime.  */
561da0c48c4Sopenharmony_ci  GElf_Xword align = mod->dwfl->segment_align;
562da0c48c4Sopenharmony_ci  GElf_Addr d_val_vaddr = 0;
563da0c48c4Sopenharmony_ci  size_t phnum;
564da0c48c4Sopenharmony_ci  if (elf_getphdrnum (mod->main.elf, &phnum) != 0)
565da0c48c4Sopenharmony_ci    return 0;
566da0c48c4Sopenharmony_ci
567da0c48c4Sopenharmony_ci  for (size_t i = 0; i < phnum; ++i)
568da0c48c4Sopenharmony_ci    {
569da0c48c4Sopenharmony_ci      GElf_Phdr phdr_mem;
570da0c48c4Sopenharmony_ci      GElf_Phdr *phdr = gelf_getphdr (mod->main.elf, i, &phdr_mem);
571da0c48c4Sopenharmony_ci      if (phdr == NULL)
572da0c48c4Sopenharmony_ci	break;
573da0c48c4Sopenharmony_ci
574da0c48c4Sopenharmony_ci      if (phdr->p_align > 1 && (align == 0 || phdr->p_align < align))
575da0c48c4Sopenharmony_ci	align = phdr->p_align;
576da0c48c4Sopenharmony_ci
577da0c48c4Sopenharmony_ci      if (at_phdr != 0
578da0c48c4Sopenharmony_ci	  && phdr->p_type == PT_LOAD
579da0c48c4Sopenharmony_ci	  && (phdr->p_offset & -align) == (ehdr.e_phoff & -align))
580da0c48c4Sopenharmony_ci	{
581da0c48c4Sopenharmony_ci	  /* This is the segment that would map the phdrs.
582da0c48c4Sopenharmony_ci	     If we have an AT_PHDR value, reject this executable
583da0c48c4Sopenharmony_ci	     if its phdr mapping could not have supplied that.  */
584da0c48c4Sopenharmony_ci	  if (mod->e_type == ET_EXEC)
585da0c48c4Sopenharmony_ci	    {
586da0c48c4Sopenharmony_ci	      if (ehdr.e_phoff - phdr->p_offset + phdr->p_vaddr != at_phdr)
587da0c48c4Sopenharmony_ci		return 0;
588da0c48c4Sopenharmony_ci	    }
589da0c48c4Sopenharmony_ci	  else
590da0c48c4Sopenharmony_ci	    {
591da0c48c4Sopenharmony_ci	      /* It could be a PIE.  If the AT_PHDR value and our
592da0c48c4Sopenharmony_ci		 phdr address don't match modulo ALIGN, then this
593da0c48c4Sopenharmony_ci		 could not have been the right PIE.  */
594da0c48c4Sopenharmony_ci	      if (((ehdr.e_phoff - phdr->p_offset + phdr->p_vaddr) & -align)
595da0c48c4Sopenharmony_ci		  != (at_phdr & -align))
596da0c48c4Sopenharmony_ci		return 0;
597da0c48c4Sopenharmony_ci
598da0c48c4Sopenharmony_ci	      /* Calculate the bias applied to the PIE's p_vaddr values.  */
599da0c48c4Sopenharmony_ci	      GElf_Addr bias = (at_phdr - (ehdr.e_phoff - phdr->p_offset
600da0c48c4Sopenharmony_ci					   + phdr->p_vaddr));
601da0c48c4Sopenharmony_ci
602da0c48c4Sopenharmony_ci	      /* Final sanity check: if we have an AT_ENTRY value,
603da0c48c4Sopenharmony_ci		 reject this PIE unless its biased e_entry matches.  */
604da0c48c4Sopenharmony_ci	      if (at_entry != 0 && at_entry != ehdr.e_entry + bias)
605da0c48c4Sopenharmony_ci		return 0;
606da0c48c4Sopenharmony_ci
607da0c48c4Sopenharmony_ci	      /* If we're changing the module's address range,
608da0c48c4Sopenharmony_ci		 we've just invalidated the module lookup table.  */
609da0c48c4Sopenharmony_ci	      GElf_Addr mod_bias = dwfl_adjusted_address (mod, 0);
610da0c48c4Sopenharmony_ci	      if (bias != mod_bias)
611da0c48c4Sopenharmony_ci		{
612da0c48c4Sopenharmony_ci		  mod->low_addr -= mod_bias;
613da0c48c4Sopenharmony_ci		  mod->high_addr -= mod_bias;
614da0c48c4Sopenharmony_ci		  mod->low_addr += bias;
615da0c48c4Sopenharmony_ci		  mod->high_addr += bias;
616da0c48c4Sopenharmony_ci
617da0c48c4Sopenharmony_ci		  free (mod->dwfl->lookup_module);
618da0c48c4Sopenharmony_ci		  mod->dwfl->lookup_module = NULL;
619da0c48c4Sopenharmony_ci		}
620da0c48c4Sopenharmony_ci	    }
621da0c48c4Sopenharmony_ci	}
622da0c48c4Sopenharmony_ci
623da0c48c4Sopenharmony_ci      if (phdr->p_type == PT_DYNAMIC)
624da0c48c4Sopenharmony_ci	{
625da0c48c4Sopenharmony_ci	  Elf_Data *data = elf_getdata_rawchunk (mod->main.elf, phdr->p_offset,
626da0c48c4Sopenharmony_ci						 phdr->p_filesz, ELF_T_DYN);
627da0c48c4Sopenharmony_ci	  if (data == NULL)
628da0c48c4Sopenharmony_ci	    continue;
629da0c48c4Sopenharmony_ci	  const size_t entsize = gelf_fsize (mod->main.elf,
630da0c48c4Sopenharmony_ci					     ELF_T_DYN, 1, EV_CURRENT);
631da0c48c4Sopenharmony_ci	  const size_t n = data->d_size / entsize;
632da0c48c4Sopenharmony_ci	  for (size_t j = 0; j < n; ++j)
633da0c48c4Sopenharmony_ci	    {
634da0c48c4Sopenharmony_ci	      GElf_Dyn dyn_mem;
635da0c48c4Sopenharmony_ci	      GElf_Dyn *dyn = gelf_getdyn (data, j, &dyn_mem);
636da0c48c4Sopenharmony_ci	      if (dyn != NULL && dyn->d_tag == DT_DEBUG)
637da0c48c4Sopenharmony_ci		{
638da0c48c4Sopenharmony_ci		  d_val_vaddr = phdr->p_vaddr + entsize * j + entsize / 2;
639da0c48c4Sopenharmony_ci		  break;
640da0c48c4Sopenharmony_ci		}
641da0c48c4Sopenharmony_ci	    }
642da0c48c4Sopenharmony_ci	}
643da0c48c4Sopenharmony_ci    }
644da0c48c4Sopenharmony_ci
645da0c48c4Sopenharmony_ci  if (d_val_vaddr != 0)
646da0c48c4Sopenharmony_ci    {
647da0c48c4Sopenharmony_ci      /* Now we have the final address from which to read &r_debug.  */
648da0c48c4Sopenharmony_ci      d_val_vaddr = dwfl_adjusted_address (mod, d_val_vaddr);
649da0c48c4Sopenharmony_ci
650da0c48c4Sopenharmony_ci      void *buffer = NULL;
651da0c48c4Sopenharmony_ci      size_t buffer_available = addrsize (ehdr.e_ident[EI_CLASS]);
652da0c48c4Sopenharmony_ci
653da0c48c4Sopenharmony_ci      int segndx = INTUSE(dwfl_addrsegment) (mod->dwfl, d_val_vaddr, NULL);
654da0c48c4Sopenharmony_ci
655da0c48c4Sopenharmony_ci      if ((*memory_callback) (mod->dwfl, segndx,
656da0c48c4Sopenharmony_ci			      &buffer, &buffer_available,
657da0c48c4Sopenharmony_ci			      d_val_vaddr, buffer_available,
658da0c48c4Sopenharmony_ci			      memory_callback_arg))
659da0c48c4Sopenharmony_ci	{
660da0c48c4Sopenharmony_ci	  const union
661da0c48c4Sopenharmony_ci	  {
662da0c48c4Sopenharmony_ci	    Elf32_Addr a32;
663da0c48c4Sopenharmony_ci	    Elf64_Addr a64;
664da0c48c4Sopenharmony_ci	  } *u = buffer;
665da0c48c4Sopenharmony_ci
666da0c48c4Sopenharmony_ci	  GElf_Addr vaddr;
667da0c48c4Sopenharmony_ci	  if (ehdr.e_ident[EI_CLASS] == ELFCLASS32)
668da0c48c4Sopenharmony_ci	    vaddr = (ehdr.e_ident[EI_DATA] == ELFDATA2MSB
669da0c48c4Sopenharmony_ci		     ? BE32 (u->a32) : LE32 (u->a32));
670da0c48c4Sopenharmony_ci	  else
671da0c48c4Sopenharmony_ci	    vaddr = (ehdr.e_ident[EI_DATA] == ELFDATA2MSB
672da0c48c4Sopenharmony_ci		     ? BE64 (u->a64) : LE64 (u->a64));
673da0c48c4Sopenharmony_ci
674da0c48c4Sopenharmony_ci	  (*memory_callback) (mod->dwfl, -1, &buffer, &buffer_available, 0, 0,
675da0c48c4Sopenharmony_ci			      memory_callback_arg);
676da0c48c4Sopenharmony_ci
677da0c48c4Sopenharmony_ci	  if (*elfclass == ELFCLASSNONE)
678da0c48c4Sopenharmony_ci	    *elfclass = ehdr.e_ident[EI_CLASS];
679da0c48c4Sopenharmony_ci	  else if (*elfclass != ehdr.e_ident[EI_CLASS])
680da0c48c4Sopenharmony_ci	    return 0;
681da0c48c4Sopenharmony_ci
682da0c48c4Sopenharmony_ci	  if (*elfdata == ELFDATANONE)
683da0c48c4Sopenharmony_ci	    *elfdata = ehdr.e_ident[EI_DATA];
684da0c48c4Sopenharmony_ci	  else if (*elfdata != ehdr.e_ident[EI_DATA])
685da0c48c4Sopenharmony_ci	    return 0;
686da0c48c4Sopenharmony_ci
687da0c48c4Sopenharmony_ci	  return vaddr;
688da0c48c4Sopenharmony_ci	}
689da0c48c4Sopenharmony_ci    }
690da0c48c4Sopenharmony_ci
691da0c48c4Sopenharmony_ci  return 0;
692da0c48c4Sopenharmony_ci}
693da0c48c4Sopenharmony_ci
694da0c48c4Sopenharmony_ci/* Try to find an existing executable module with a DT_DEBUG.  */
695da0c48c4Sopenharmony_cistatic GElf_Addr
696da0c48c4Sopenharmony_cifind_executable (Dwfl *dwfl, GElf_Addr at_phdr, GElf_Addr at_entry,
697da0c48c4Sopenharmony_ci		 uint_fast8_t *elfclass, uint_fast8_t *elfdata,
698da0c48c4Sopenharmony_ci		 Dwfl_Memory_Callback *memory_callback,
699da0c48c4Sopenharmony_ci		 void *memory_callback_arg)
700da0c48c4Sopenharmony_ci{
701da0c48c4Sopenharmony_ci  for (Dwfl_Module *mod = dwfl->modulelist; mod != NULL; mod = mod->next)
702da0c48c4Sopenharmony_ci    if (mod->main.elf != NULL)
703da0c48c4Sopenharmony_ci      {
704da0c48c4Sopenharmony_ci	GElf_Addr r_debug_vaddr = consider_executable (mod, at_phdr, at_entry,
705da0c48c4Sopenharmony_ci						       elfclass, elfdata,
706da0c48c4Sopenharmony_ci						       memory_callback,
707da0c48c4Sopenharmony_ci						       memory_callback_arg);
708da0c48c4Sopenharmony_ci	if (r_debug_vaddr != 0)
709da0c48c4Sopenharmony_ci	  return r_debug_vaddr;
710da0c48c4Sopenharmony_ci      }
711da0c48c4Sopenharmony_ci
712da0c48c4Sopenharmony_ci  return 0;
713da0c48c4Sopenharmony_ci}
714da0c48c4Sopenharmony_ci
715da0c48c4Sopenharmony_ci
716da0c48c4Sopenharmony_ciint
717da0c48c4Sopenharmony_cidwfl_link_map_report (Dwfl *dwfl, const void *auxv, size_t auxv_size,
718da0c48c4Sopenharmony_ci		      Dwfl_Memory_Callback *memory_callback,
719da0c48c4Sopenharmony_ci		      void *memory_callback_arg,
720da0c48c4Sopenharmony_ci		      struct r_debug_info *r_debug_info)
721da0c48c4Sopenharmony_ci{
722da0c48c4Sopenharmony_ci  GElf_Addr r_debug_vaddr = 0;
723da0c48c4Sopenharmony_ci
724da0c48c4Sopenharmony_ci  uint_fast8_t elfclass = ELFCLASSNONE;
725da0c48c4Sopenharmony_ci  uint_fast8_t elfdata = ELFDATANONE;
726da0c48c4Sopenharmony_ci  if (likely (auxv != NULL)
727da0c48c4Sopenharmony_ci      && likely (auxv_format_probe (auxv, auxv_size, &elfclass, &elfdata)))
728da0c48c4Sopenharmony_ci    {
729da0c48c4Sopenharmony_ci      GElf_Addr entry = 0;
730da0c48c4Sopenharmony_ci      GElf_Addr phdr = 0;
731da0c48c4Sopenharmony_ci      GElf_Xword phent = 0;
732da0c48c4Sopenharmony_ci      GElf_Xword phnum = 0;
733da0c48c4Sopenharmony_ci
734da0c48c4Sopenharmony_ci#define READ_AUXV32(ptr)	read_4ubyte_unaligned_noncvt (ptr)
735da0c48c4Sopenharmony_ci#define READ_AUXV64(ptr)	read_8ubyte_unaligned_noncvt (ptr)
736da0c48c4Sopenharmony_ci#define AUXV_SCAN(NN, BL) do                                            \
737da0c48c4Sopenharmony_ci	{                                                               \
738da0c48c4Sopenharmony_ci	  const Elf##NN##_auxv_t *av = auxv;                            \
739da0c48c4Sopenharmony_ci	  for (size_t i = 0; i < auxv_size / sizeof av[0]; ++i)         \
740da0c48c4Sopenharmony_ci	    {                                                           \
741da0c48c4Sopenharmony_ci	      const char *typep = auxv + i * sizeof (Elf##NN##_auxv_t); \
742da0c48c4Sopenharmony_ci	      typep += offsetof (Elf##NN##_auxv_t, a_type);             \
743da0c48c4Sopenharmony_ci	      uint##NN##_t type = READ_AUXV##NN (typep);                \
744da0c48c4Sopenharmony_ci	      const char *valp = auxv + i * sizeof (Elf##NN##_auxv_t);  \
745da0c48c4Sopenharmony_ci	      valp += offsetof (Elf##NN##_auxv_t, a_un.a_val);          \
746da0c48c4Sopenharmony_ci	      uint##NN##_t val = BL##NN (READ_AUXV##NN (valp));         \
747da0c48c4Sopenharmony_ci	      if (type == BL##NN (AT_ENTRY))                            \
748da0c48c4Sopenharmony_ci		entry = val;                                            \
749da0c48c4Sopenharmony_ci	      else if (type == BL##NN (AT_PHDR))                        \
750da0c48c4Sopenharmony_ci		phdr = val;                                             \
751da0c48c4Sopenharmony_ci	      else if (type == BL##NN (AT_PHNUM))                       \
752da0c48c4Sopenharmony_ci		phnum = val;                                            \
753da0c48c4Sopenharmony_ci	      else if (type == BL##NN (AT_PHENT))                       \
754da0c48c4Sopenharmony_ci		phent = val;                                            \
755da0c48c4Sopenharmony_ci	      else if (type == BL##NN (AT_PAGESZ))                      \
756da0c48c4Sopenharmony_ci		{                                                       \
757da0c48c4Sopenharmony_ci		  if (val > 1                                           \
758da0c48c4Sopenharmony_ci		      && (dwfl->segment_align == 0                      \
759da0c48c4Sopenharmony_ci			  || val < dwfl->segment_align))                \
760da0c48c4Sopenharmony_ci		    dwfl->segment_align = val;                          \
761da0c48c4Sopenharmony_ci		}                                                       \
762da0c48c4Sopenharmony_ci	    }                                                           \
763da0c48c4Sopenharmony_ci	}                                                               \
764da0c48c4Sopenharmony_ci      while (0)
765da0c48c4Sopenharmony_ci
766da0c48c4Sopenharmony_ci      if (elfclass == ELFCLASS32)
767da0c48c4Sopenharmony_ci	{
768da0c48c4Sopenharmony_ci	  if (elfdata == ELFDATA2MSB)
769da0c48c4Sopenharmony_ci	    AUXV_SCAN (32, BE);
770da0c48c4Sopenharmony_ci	  else
771da0c48c4Sopenharmony_ci	    AUXV_SCAN (32, LE);
772da0c48c4Sopenharmony_ci	}
773da0c48c4Sopenharmony_ci      else
774da0c48c4Sopenharmony_ci	{
775da0c48c4Sopenharmony_ci	  if (elfdata == ELFDATA2MSB)
776da0c48c4Sopenharmony_ci	    AUXV_SCAN (64, BE);
777da0c48c4Sopenharmony_ci	  else
778da0c48c4Sopenharmony_ci	    AUXV_SCAN (64, LE);
779da0c48c4Sopenharmony_ci	}
780da0c48c4Sopenharmony_ci
781da0c48c4Sopenharmony_ci      /* If we found the phdr dimensions, search phdrs for PT_DYNAMIC.  */
782da0c48c4Sopenharmony_ci      GElf_Addr dyn_vaddr = 0;
783da0c48c4Sopenharmony_ci      GElf_Xword dyn_filesz = 0;
784da0c48c4Sopenharmony_ci      GElf_Addr dyn_bias = (GElf_Addr) -1;
785da0c48c4Sopenharmony_ci
786da0c48c4Sopenharmony_ci      if (phdr != 0 && phnum != 0
787da0c48c4Sopenharmony_ci	  && ((elfclass == ELFCLASS32 && phent == sizeof (Elf32_Phdr))
788da0c48c4Sopenharmony_ci	      || (elfclass == ELFCLASS64 && phent == sizeof (Elf64_Phdr))))
789da0c48c4Sopenharmony_ci	{
790da0c48c4Sopenharmony_ci	  Dwfl_Module *phdr_mod;
791da0c48c4Sopenharmony_ci	  int phdr_segndx = INTUSE(dwfl_addrsegment) (dwfl, phdr, &phdr_mod);
792da0c48c4Sopenharmony_ci	  Elf_Data in =
793da0c48c4Sopenharmony_ci	    {
794da0c48c4Sopenharmony_ci	      .d_type = ELF_T_PHDR,
795da0c48c4Sopenharmony_ci	      .d_version = EV_CURRENT,
796da0c48c4Sopenharmony_ci	      .d_size = phnum * phent,
797da0c48c4Sopenharmony_ci	      .d_buf = NULL
798da0c48c4Sopenharmony_ci	    };
799da0c48c4Sopenharmony_ci	  bool in_ok = (*memory_callback) (dwfl, phdr_segndx, &in.d_buf,
800da0c48c4Sopenharmony_ci					   &in.d_size, phdr, phnum * phent,
801da0c48c4Sopenharmony_ci					   memory_callback_arg);
802da0c48c4Sopenharmony_ci	  bool in_from_exec = false;
803da0c48c4Sopenharmony_ci	  if (! in_ok
804da0c48c4Sopenharmony_ci	      && dwfl->user_core != NULL
805da0c48c4Sopenharmony_ci	      && dwfl->user_core->executable_for_core != NULL)
806da0c48c4Sopenharmony_ci	    {
807da0c48c4Sopenharmony_ci	      /* AUXV -> PHDR -> DYNAMIC
808da0c48c4Sopenharmony_ci		 Both AUXV and DYNAMIC should be always present in a core file.
809da0c48c4Sopenharmony_ci		 PHDR may be missing in core file, try to read it from
810da0c48c4Sopenharmony_ci		 EXECUTABLE_FOR_CORE to find where DYNAMIC is located in the
811da0c48c4Sopenharmony_ci		 core file.  */
812da0c48c4Sopenharmony_ci
813da0c48c4Sopenharmony_ci	      int fd = open (dwfl->user_core->executable_for_core, O_RDONLY);
814da0c48c4Sopenharmony_ci	      Elf *elf;
815da0c48c4Sopenharmony_ci	      Dwfl_Error error = DWFL_E_ERRNO;
816da0c48c4Sopenharmony_ci	      if (fd != -1)
817da0c48c4Sopenharmony_ci		error = __libdw_open_file (&fd, &elf, true, false);
818da0c48c4Sopenharmony_ci	      if (error != DWFL_E_NOERROR)
819da0c48c4Sopenharmony_ci		{
820da0c48c4Sopenharmony_ci		  __libdwfl_seterrno (error);
821da0c48c4Sopenharmony_ci		  return false;
822da0c48c4Sopenharmony_ci		}
823da0c48c4Sopenharmony_ci	      GElf_Ehdr ehdr_mem, *ehdr = gelf_getehdr (elf, &ehdr_mem);
824da0c48c4Sopenharmony_ci	      if (ehdr == NULL)
825da0c48c4Sopenharmony_ci		{
826da0c48c4Sopenharmony_ci		  elf_end (elf);
827da0c48c4Sopenharmony_ci		  close (fd);
828da0c48c4Sopenharmony_ci		  __libdwfl_seterrno (DWFL_E_LIBELF);
829da0c48c4Sopenharmony_ci		  return false;
830da0c48c4Sopenharmony_ci		}
831da0c48c4Sopenharmony_ci	      size_t e_phnum;
832da0c48c4Sopenharmony_ci	      if (elf_getphdrnum (elf, &e_phnum) != 0)
833da0c48c4Sopenharmony_ci		{
834da0c48c4Sopenharmony_ci		  elf_end (elf);
835da0c48c4Sopenharmony_ci		  close (fd);
836da0c48c4Sopenharmony_ci		  __libdwfl_seterrno (DWFL_E_LIBELF);
837da0c48c4Sopenharmony_ci		  return false;
838da0c48c4Sopenharmony_ci		}
839da0c48c4Sopenharmony_ci	      if (e_phnum != phnum || ehdr->e_phentsize != phent)
840da0c48c4Sopenharmony_ci		{
841da0c48c4Sopenharmony_ci		  elf_end (elf);
842da0c48c4Sopenharmony_ci		  close (fd);
843da0c48c4Sopenharmony_ci		  __libdwfl_seterrno (DWFL_E_BADELF);
844da0c48c4Sopenharmony_ci		  return false;
845da0c48c4Sopenharmony_ci		}
846da0c48c4Sopenharmony_ci	      off_t off = ehdr->e_phoff;
847da0c48c4Sopenharmony_ci	      assert (in.d_buf == NULL);
848da0c48c4Sopenharmony_ci	      /* Note this in the !in_ok path.  That means memory_callback
849da0c48c4Sopenharmony_ci		 failed.  But the callback might still have reset the d_size
850da0c48c4Sopenharmony_ci		 value (to zero).  So explicitly set it here again.  */
851da0c48c4Sopenharmony_ci	      if (unlikely (phnum > SIZE_MAX / phent))
852da0c48c4Sopenharmony_ci		{
853da0c48c4Sopenharmony_ci		  __libdwfl_seterrno (DWFL_E_NOMEM);
854da0c48c4Sopenharmony_ci		  return false;
855da0c48c4Sopenharmony_ci		}
856da0c48c4Sopenharmony_ci	      in.d_size = phnum * phent;
857da0c48c4Sopenharmony_ci	      in.d_buf = malloc (in.d_size);
858da0c48c4Sopenharmony_ci	      if (unlikely (in.d_buf == NULL))
859da0c48c4Sopenharmony_ci		{
860da0c48c4Sopenharmony_ci		  elf_end (elf);
861da0c48c4Sopenharmony_ci		  close (fd);
862da0c48c4Sopenharmony_ci		  __libdwfl_seterrno (DWFL_E_NOMEM);
863da0c48c4Sopenharmony_ci		  return false;
864da0c48c4Sopenharmony_ci		}
865da0c48c4Sopenharmony_ci	      ssize_t nread = pread_retry (fd, in.d_buf, in.d_size, off);
866da0c48c4Sopenharmony_ci	      elf_end (elf);
867da0c48c4Sopenharmony_ci	      close (fd);
868da0c48c4Sopenharmony_ci	      if (nread != (ssize_t) in.d_size)
869da0c48c4Sopenharmony_ci		{
870da0c48c4Sopenharmony_ci		  free (in.d_buf);
871da0c48c4Sopenharmony_ci		  __libdwfl_seterrno (DWFL_E_ERRNO);
872da0c48c4Sopenharmony_ci		  return false;
873da0c48c4Sopenharmony_ci		}
874da0c48c4Sopenharmony_ci	      in_ok = true;
875da0c48c4Sopenharmony_ci	      in_from_exec = true;
876da0c48c4Sopenharmony_ci	    }
877da0c48c4Sopenharmony_ci	  if (in_ok)
878da0c48c4Sopenharmony_ci	    {
879da0c48c4Sopenharmony_ci	      if (unlikely (phnum > SIZE_MAX / phent))
880da0c48c4Sopenharmony_ci		{
881da0c48c4Sopenharmony_ci		  __libdwfl_seterrno (DWFL_E_NOMEM);
882da0c48c4Sopenharmony_ci		  return false;
883da0c48c4Sopenharmony_ci		}
884da0c48c4Sopenharmony_ci	      size_t nbytes = phnum * phent;
885da0c48c4Sopenharmony_ci	      /* We can only process as many bytes/phnum as there are
886da0c48c4Sopenharmony_ci		 in in.d_size. The data might have been truncated.  */
887da0c48c4Sopenharmony_ci	      if (nbytes > in.d_size)
888da0c48c4Sopenharmony_ci		{
889da0c48c4Sopenharmony_ci		  nbytes = in.d_size;
890da0c48c4Sopenharmony_ci		  phnum = nbytes / phent;
891da0c48c4Sopenharmony_ci		  if (phnum == 0)
892da0c48c4Sopenharmony_ci		    {
893da0c48c4Sopenharmony_ci		      __libdwfl_seterrno (DWFL_E_BADELF);
894da0c48c4Sopenharmony_ci		      return false;
895da0c48c4Sopenharmony_ci		    }
896da0c48c4Sopenharmony_ci		}
897da0c48c4Sopenharmony_ci	      void *buf = malloc (nbytes);
898da0c48c4Sopenharmony_ci	      Elf32_Phdr (*p32)[phnum] = buf;
899da0c48c4Sopenharmony_ci	      Elf64_Phdr (*p64)[phnum] = buf;
900da0c48c4Sopenharmony_ci	      if (unlikely (buf == NULL))
901da0c48c4Sopenharmony_ci		{
902da0c48c4Sopenharmony_ci		  __libdwfl_seterrno (DWFL_E_NOMEM);
903da0c48c4Sopenharmony_ci		  return false;
904da0c48c4Sopenharmony_ci		}
905da0c48c4Sopenharmony_ci	      Elf_Data out =
906da0c48c4Sopenharmony_ci		{
907da0c48c4Sopenharmony_ci		  .d_type = ELF_T_PHDR,
908da0c48c4Sopenharmony_ci		  .d_version = EV_CURRENT,
909da0c48c4Sopenharmony_ci		  .d_size = nbytes,
910da0c48c4Sopenharmony_ci		  .d_buf = buf
911da0c48c4Sopenharmony_ci		};
912da0c48c4Sopenharmony_ci	      if (in.d_size > out.d_size)
913da0c48c4Sopenharmony_ci		{
914da0c48c4Sopenharmony_ci		  in.d_size = out.d_size;
915da0c48c4Sopenharmony_ci		  phnum = in.d_size / phent;
916da0c48c4Sopenharmony_ci		  if (phnum == 0)
917da0c48c4Sopenharmony_ci		    {
918da0c48c4Sopenharmony_ci		      free (buf);
919da0c48c4Sopenharmony_ci		      __libdwfl_seterrno (DWFL_E_BADELF);
920da0c48c4Sopenharmony_ci		      return false;
921da0c48c4Sopenharmony_ci		    }
922da0c48c4Sopenharmony_ci		}
923da0c48c4Sopenharmony_ci	      bool is32 = (elfclass == ELFCLASS32);
924da0c48c4Sopenharmony_ci	      size_t phdr_align = (is32
925da0c48c4Sopenharmony_ci				   ? __alignof__ (Elf32_Phdr)
926da0c48c4Sopenharmony_ci				   : __alignof__ (Elf64_Phdr));
927da0c48c4Sopenharmony_ci	      if (!in_from_exec
928da0c48c4Sopenharmony_ci		  && ((uintptr_t) in.d_buf & (phdr_align - 1)) != 0)
929da0c48c4Sopenharmony_ci		{
930da0c48c4Sopenharmony_ci		  memcpy (out.d_buf, in.d_buf, in.d_size);
931da0c48c4Sopenharmony_ci		  in.d_buf = out.d_buf;
932da0c48c4Sopenharmony_ci		}
933da0c48c4Sopenharmony_ci	      if (likely ((elfclass == ELFCLASS32
934da0c48c4Sopenharmony_ci			   ? elf32_xlatetom : elf64_xlatetom)
935da0c48c4Sopenharmony_ci			  (&out, &in, elfdata) != NULL))
936da0c48c4Sopenharmony_ci		{
937da0c48c4Sopenharmony_ci		  for (size_t i = 0; i < phnum; ++i)
938da0c48c4Sopenharmony_ci		    {
939da0c48c4Sopenharmony_ci		      GElf_Word type = (is32
940da0c48c4Sopenharmony_ci					? (*p32)[i].p_type
941da0c48c4Sopenharmony_ci					: (*p64)[i].p_type);
942da0c48c4Sopenharmony_ci		      GElf_Addr vaddr = (is32
943da0c48c4Sopenharmony_ci					 ? (*p32)[i].p_vaddr
944da0c48c4Sopenharmony_ci					 : (*p64)[i].p_vaddr);
945da0c48c4Sopenharmony_ci		      GElf_Xword filesz = (is32
946da0c48c4Sopenharmony_ci					   ? (*p32)[i].p_filesz
947da0c48c4Sopenharmony_ci					   : (*p64)[i].p_filesz);
948da0c48c4Sopenharmony_ci
949da0c48c4Sopenharmony_ci		      if (type == PT_PHDR)
950da0c48c4Sopenharmony_ci			{
951da0c48c4Sopenharmony_ci			  if (dyn_bias == (GElf_Addr) -1
952da0c48c4Sopenharmony_ci			      /* Do a sanity check on the putative address.  */
953da0c48c4Sopenharmony_ci			      && ((vaddr & (dwfl->segment_align - 1))
954da0c48c4Sopenharmony_ci				  == (phdr & (dwfl->segment_align - 1))))
955da0c48c4Sopenharmony_ci			    {
956da0c48c4Sopenharmony_ci			      dyn_bias = phdr - vaddr;
957da0c48c4Sopenharmony_ci			      if (dyn_vaddr != 0)
958da0c48c4Sopenharmony_ci				break;
959da0c48c4Sopenharmony_ci			    }
960da0c48c4Sopenharmony_ci
961da0c48c4Sopenharmony_ci			}
962da0c48c4Sopenharmony_ci		      else if (type == PT_DYNAMIC)
963da0c48c4Sopenharmony_ci			{
964da0c48c4Sopenharmony_ci			  dyn_vaddr = vaddr;
965da0c48c4Sopenharmony_ci			  dyn_filesz = filesz;
966da0c48c4Sopenharmony_ci			  if (dyn_bias != (GElf_Addr) -1)
967da0c48c4Sopenharmony_ci			    break;
968da0c48c4Sopenharmony_ci			}
969da0c48c4Sopenharmony_ci		    }
970da0c48c4Sopenharmony_ci		}
971da0c48c4Sopenharmony_ci
972da0c48c4Sopenharmony_ci	      if (in_from_exec)
973da0c48c4Sopenharmony_ci		free (in.d_buf);
974da0c48c4Sopenharmony_ci	      else
975da0c48c4Sopenharmony_ci		(*memory_callback) (dwfl, -1, &in.d_buf, &in.d_size, 0, 0,
976da0c48c4Sopenharmony_ci				    memory_callback_arg);
977da0c48c4Sopenharmony_ci	      free (buf);
978da0c48c4Sopenharmony_ci	    }
979da0c48c4Sopenharmony_ci	  else
980da0c48c4Sopenharmony_ci	    /* We could not read the executable's phdrs from the
981da0c48c4Sopenharmony_ci	       memory image.  If we have a presupplied executable,
982da0c48c4Sopenharmony_ci	       we can still use the AT_PHDR and AT_ENTRY values to
983da0c48c4Sopenharmony_ci	       verify it, and to adjust its bias if it's a PIE.
984da0c48c4Sopenharmony_ci
985da0c48c4Sopenharmony_ci	       If there was an ET_EXEC module presupplied that contains
986da0c48c4Sopenharmony_ci	       the AT_PHDR address, then we only consider that one.
987da0c48c4Sopenharmony_ci	       We'll either accept it if its phdr location and e_entry
988da0c48c4Sopenharmony_ci	       make sense or reject it if they don't.  If there is no
989da0c48c4Sopenharmony_ci	       presupplied ET_EXEC, then look for a presupplied module,
990da0c48c4Sopenharmony_ci	       which might be a PIE (ET_DYN) that needs its bias adjusted.  */
991da0c48c4Sopenharmony_ci	    r_debug_vaddr = ((phdr_mod == NULL
992da0c48c4Sopenharmony_ci			      || phdr_mod->main.elf == NULL
993da0c48c4Sopenharmony_ci			      || phdr_mod->e_type != ET_EXEC)
994da0c48c4Sopenharmony_ci			     ? find_executable (dwfl, phdr, entry,
995da0c48c4Sopenharmony_ci						&elfclass, &elfdata,
996da0c48c4Sopenharmony_ci						memory_callback,
997da0c48c4Sopenharmony_ci						memory_callback_arg)
998da0c48c4Sopenharmony_ci			     : consider_executable (phdr_mod, phdr, entry,
999da0c48c4Sopenharmony_ci						    &elfclass, &elfdata,
1000da0c48c4Sopenharmony_ci						    memory_callback,
1001da0c48c4Sopenharmony_ci						    memory_callback_arg));
1002da0c48c4Sopenharmony_ci	}
1003da0c48c4Sopenharmony_ci
1004da0c48c4Sopenharmony_ci      /* If we found PT_DYNAMIC, search it for DT_DEBUG.  */
1005da0c48c4Sopenharmony_ci      if (dyn_filesz != 0)
1006da0c48c4Sopenharmony_ci	{
1007da0c48c4Sopenharmony_ci	  if (dyn_bias != (GElf_Addr) -1)
1008da0c48c4Sopenharmony_ci	    dyn_vaddr += dyn_bias;
1009da0c48c4Sopenharmony_ci
1010da0c48c4Sopenharmony_ci	  Elf_Data in =
1011da0c48c4Sopenharmony_ci	    {
1012da0c48c4Sopenharmony_ci	      .d_type = ELF_T_DYN,
1013da0c48c4Sopenharmony_ci	      .d_version = EV_CURRENT,
1014da0c48c4Sopenharmony_ci	      .d_size = dyn_filesz,
1015da0c48c4Sopenharmony_ci	      .d_buf = NULL
1016da0c48c4Sopenharmony_ci	    };
1017da0c48c4Sopenharmony_ci	  int dyn_segndx = dwfl_addrsegment (dwfl, dyn_vaddr, NULL);
1018da0c48c4Sopenharmony_ci	  if ((*memory_callback) (dwfl, dyn_segndx, &in.d_buf, &in.d_size,
1019da0c48c4Sopenharmony_ci				  dyn_vaddr, dyn_filesz, memory_callback_arg))
1020da0c48c4Sopenharmony_ci	    {
1021da0c48c4Sopenharmony_ci	      size_t entsize = (elfclass == ELFCLASS32
1022da0c48c4Sopenharmony_ci				? sizeof (Elf32_Dyn) : sizeof (Elf64_Dyn));
1023da0c48c4Sopenharmony_ci	      if (unlikely (dyn_filesz > SIZE_MAX / entsize))
1024da0c48c4Sopenharmony_ci		{
1025da0c48c4Sopenharmony_ci		  __libdwfl_seterrno (DWFL_E_NOMEM);
1026da0c48c4Sopenharmony_ci		  return false;
1027da0c48c4Sopenharmony_ci		}
1028da0c48c4Sopenharmony_ci	      /* We can only process as many bytes as there are in
1029da0c48c4Sopenharmony_ci	         in.d_size. The data might have been truncated.  */
1030da0c48c4Sopenharmony_ci	      if (dyn_filesz > in.d_size)
1031da0c48c4Sopenharmony_ci		dyn_filesz = in.d_size;
1032da0c48c4Sopenharmony_ci	      if (dyn_filesz / entsize == 0)
1033da0c48c4Sopenharmony_ci		{
1034da0c48c4Sopenharmony_ci		  __libdwfl_seterrno (DWFL_E_BADELF);
1035da0c48c4Sopenharmony_ci		  return false;
1036da0c48c4Sopenharmony_ci		}
1037da0c48c4Sopenharmony_ci	      void *buf = malloc (dyn_filesz);
1038da0c48c4Sopenharmony_ci	      if (unlikely (buf == NULL))
1039da0c48c4Sopenharmony_ci		{
1040da0c48c4Sopenharmony_ci		  __libdwfl_seterrno (DWFL_E_NOMEM);
1041da0c48c4Sopenharmony_ci		  return false;
1042da0c48c4Sopenharmony_ci		}
1043da0c48c4Sopenharmony_ci	      Elf_Data out =
1044da0c48c4Sopenharmony_ci		{
1045da0c48c4Sopenharmony_ci		  .d_type = ELF_T_DYN,
1046da0c48c4Sopenharmony_ci		  .d_version = EV_CURRENT,
1047da0c48c4Sopenharmony_ci		  .d_size = dyn_filesz,
1048da0c48c4Sopenharmony_ci		  .d_buf = buf
1049da0c48c4Sopenharmony_ci		};
1050da0c48c4Sopenharmony_ci	      if (in.d_size > out.d_size)
1051da0c48c4Sopenharmony_ci		in.d_size = out.d_size;
1052da0c48c4Sopenharmony_ci	      size_t dyn_align = (elfclass == ELFCLASS32
1053da0c48c4Sopenharmony_ci			          ? __alignof__ (Elf32_Dyn)
1054da0c48c4Sopenharmony_ci				  : __alignof__ (Elf64_Dyn));
1055da0c48c4Sopenharmony_ci	      if (((uintptr_t) in.d_buf & (dyn_align - 1)) != 0)
1056da0c48c4Sopenharmony_ci		{
1057da0c48c4Sopenharmony_ci		  memcpy (out.d_buf, in.d_buf, in.d_size);
1058da0c48c4Sopenharmony_ci		  in.d_buf = out.d_buf;
1059da0c48c4Sopenharmony_ci		}
1060da0c48c4Sopenharmony_ci	      if (likely ((elfclass == ELFCLASS32
1061da0c48c4Sopenharmony_ci			   ? elf32_xlatetom : elf64_xlatetom)
1062da0c48c4Sopenharmony_ci			  (&out, &in, elfdata) != NULL))
1063da0c48c4Sopenharmony_ci		{
1064da0c48c4Sopenharmony_ci		  /* We are looking for DT_DEBUG.  */
1065da0c48c4Sopenharmony_ci		  if (elfclass == ELFCLASS32)
1066da0c48c4Sopenharmony_ci		    {
1067da0c48c4Sopenharmony_ci		      Elf32_Dyn (*d32)[dyn_filesz / sizeof (Elf32_Dyn)] = buf;
1068da0c48c4Sopenharmony_ci		      size_t n = dyn_filesz / sizeof (Elf32_Dyn);
1069da0c48c4Sopenharmony_ci		      for (size_t i = 0; i < n; ++i)
1070da0c48c4Sopenharmony_ci			if ((*d32)[i].d_tag == DT_DEBUG)
1071da0c48c4Sopenharmony_ci			  {
1072da0c48c4Sopenharmony_ci			    r_debug_vaddr = (*d32)[i].d_un.d_val;
1073da0c48c4Sopenharmony_ci			    break;
1074da0c48c4Sopenharmony_ci			  }
1075da0c48c4Sopenharmony_ci		    }
1076da0c48c4Sopenharmony_ci		  else
1077da0c48c4Sopenharmony_ci		    {
1078da0c48c4Sopenharmony_ci		      Elf64_Dyn (*d64)[dyn_filesz / sizeof (Elf64_Dyn)] = buf;
1079da0c48c4Sopenharmony_ci		      size_t n = dyn_filesz / sizeof (Elf64_Dyn);
1080da0c48c4Sopenharmony_ci		      for (size_t i = 0; i < n; ++i)
1081da0c48c4Sopenharmony_ci			if ((*d64)[i].d_tag == DT_DEBUG)
1082da0c48c4Sopenharmony_ci			  {
1083da0c48c4Sopenharmony_ci			    r_debug_vaddr = (*d64)[i].d_un.d_val;
1084da0c48c4Sopenharmony_ci			    break;
1085da0c48c4Sopenharmony_ci			  }
1086da0c48c4Sopenharmony_ci		    }
1087da0c48c4Sopenharmony_ci		}
1088da0c48c4Sopenharmony_ci
1089da0c48c4Sopenharmony_ci	      (*memory_callback) (dwfl, -1, &in.d_buf, &in.d_size, 0, 0,
1090da0c48c4Sopenharmony_ci				  memory_callback_arg);
1091da0c48c4Sopenharmony_ci	      free (buf);
1092da0c48c4Sopenharmony_ci	    }
1093da0c48c4Sopenharmony_ci	}
1094da0c48c4Sopenharmony_ci    }
1095da0c48c4Sopenharmony_ci  else
1096da0c48c4Sopenharmony_ci    /* We have to look for a presupplied executable file to determine
1097da0c48c4Sopenharmony_ci       the vaddr of its dynamic section and DT_DEBUG therein.  */
1098da0c48c4Sopenharmony_ci    r_debug_vaddr = find_executable (dwfl, 0, 0, &elfclass, &elfdata,
1099da0c48c4Sopenharmony_ci				     memory_callback, memory_callback_arg);
1100da0c48c4Sopenharmony_ci
1101da0c48c4Sopenharmony_ci  if (r_debug_vaddr == 0)
1102da0c48c4Sopenharmony_ci    return 0;
1103da0c48c4Sopenharmony_ci
1104da0c48c4Sopenharmony_ci  /* For following pointers from struct link_map, we will use an
1105da0c48c4Sopenharmony_ci     integrated memory access callback that can consult module text
1106da0c48c4Sopenharmony_ci     elided from the core file.  This is necessary when the l_name
1107da0c48c4Sopenharmony_ci     pointer for the dynamic linker's own entry is a pointer into the
1108da0c48c4Sopenharmony_ci     executable's .interp section.  */
1109da0c48c4Sopenharmony_ci  struct integrated_memory_callback mcb =
1110da0c48c4Sopenharmony_ci    {
1111da0c48c4Sopenharmony_ci      .memory_callback = memory_callback,
1112da0c48c4Sopenharmony_ci      .memory_callback_arg = memory_callback_arg
1113da0c48c4Sopenharmony_ci    };
1114da0c48c4Sopenharmony_ci
1115da0c48c4Sopenharmony_ci  /* Now we can follow the dynamic linker's library list.  */
1116da0c48c4Sopenharmony_ci  return report_r_debug (elfclass, elfdata, dwfl, r_debug_vaddr,
1117da0c48c4Sopenharmony_ci			 &integrated_memory_callback, &mcb, r_debug_info);
1118da0c48c4Sopenharmony_ci}
1119da0c48c4Sopenharmony_ciINTDEF (dwfl_link_map_report)
1120