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