• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Report modules by examining dynamic linker data structures.
2    Copyright (C) 2008-2010 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   for (size_t i = 0; i < size / sizeof (Elf64_auxv_t); ++i)
127     {
128       if (check64 (i))
129 	{
130 	  *elfclass = ELFCLASS64;
131 	  return true;
132 	}
133 
134       if (check32 (i * 2) || check32 (i * 2 + 1))
135 	{
136 	  *elfclass = ELFCLASS32;
137 	  return true;
138 	}
139     }
140 
141   return false;
142 }
143 
144 /* This is a Dwfl_Memory_Callback that wraps another memory callback.
145    If the underlying callback cannot fill the data, then this will
146    fall back to fetching data from module files.  */
147 
148 struct integrated_memory_callback
149 {
150   Dwfl_Memory_Callback *memory_callback;
151   void *memory_callback_arg;
152   void *buffer;
153 };
154 
155 static bool
integrated_memory_callback(Dwfl * dwfl,int ndx,void ** buffer,size_t * buffer_available,GElf_Addr vaddr,size_t minread,void * arg)156 integrated_memory_callback (Dwfl *dwfl, int ndx,
157 			       void **buffer, size_t *buffer_available,
158 			       GElf_Addr vaddr,
159 			       size_t minread,
160 			       void *arg)
161 {
162   struct integrated_memory_callback *info = arg;
163 
164   if (ndx == -1)
165     {
166       /* Called for cleanup.  */
167       if (info->buffer != NULL)
168 	{
169 	  /* The last probe buffer came from the underlying callback.
170 	     Let it do its cleanup.  */
171 	  assert (*buffer == info->buffer); /* XXX */
172 	  *buffer = info->buffer;
173 	  info->buffer = NULL;
174 	  return (*info->memory_callback) (dwfl, ndx, buffer, buffer_available,
175 					   vaddr, minread,
176 					   info->memory_callback_arg);
177 	}
178       *buffer = NULL;
179       *buffer_available = 0;
180       return false;
181     }
182 
183   if (*buffer != NULL)
184     /* For a final-read request, we only use the underlying callback.  */
185     return (*info->memory_callback) (dwfl, ndx, buffer, buffer_available,
186 				     vaddr, minread, info->memory_callback_arg);
187 
188   /* Let the underlying callback try to fill this request.  */
189   if ((*info->memory_callback) (dwfl, ndx, &info->buffer, buffer_available,
190 				vaddr, minread, info->memory_callback_arg))
191     {
192       *buffer = info->buffer;
193       return true;
194     }
195 
196   /* Now look for module text covering this address.  */
197 
198   Dwfl_Module *mod;
199   (void) INTUSE(dwfl_addrsegment) (dwfl, vaddr, &mod);
200   if (mod == NULL)
201     return false;
202 
203   Dwarf_Addr bias;
204   Elf_Scn *scn = INTUSE(dwfl_module_address_section) (mod, &vaddr, &bias);
205   if (unlikely (scn == NULL))
206     {
207 #if 0 // XXX would have to handle ndx=-1 cleanup calls passed down.
208       /* If we have no sections we can try to fill it from the module file
209 	 based on its phdr mappings.  */
210       if (likely (mod->e_type != ET_REL) && mod->main.elf != NULL)
211 	return INTUSE(dwfl_elf_phdr_memory_callback)
212 	  (dwfl, 0, buffer, buffer_available,
213 	   vaddr - mod->main.bias, minread, mod->main.elf);
214 #endif
215       return false;
216     }
217 
218   Elf_Data *data = elf_rawdata (scn, NULL);
219   if (unlikely (data == NULL))
220     // XXX throw error?
221     return false;
222 
223   if (unlikely (data->d_size < vaddr))
224     return false;
225 
226   /* Provide as much data as we have.  */
227   void *contents = data->d_buf + vaddr;
228   size_t avail = data->d_size - vaddr;
229   if (unlikely (avail < minread))
230     return false;
231 
232   /* If probing for a string, make sure it's terminated.  */
233   if (minread == 0 && unlikely (memchr (contents, '\0', avail) == NULL))
234     return false;
235 
236   /* We have it! */
237   *buffer = contents;
238   *buffer_available = avail;
239   return true;
240 }
241 
242 static size_t
addrsize(uint_fast8_t elfclass)243 addrsize (uint_fast8_t elfclass)
244 {
245   return elfclass * 4;
246 }
247 
248 /* Report a module for each struct link_map in the linked list at r_map
249    in the struct r_debug at R_DEBUG_VADDR.
250 
251    For each link_map entry, if an existing module resides at its address,
252    this just modifies that module's name and suggested file name.  If
253    no such module exists, this calls dwfl_report_elf on the l_name string.
254 
255    Returns the number of modules found, or -1 for errors.  */
256 
257 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)258 report_r_debug (uint_fast8_t elfclass, uint_fast8_t elfdata,
259 		Dwfl *dwfl, GElf_Addr r_debug_vaddr,
260 		Dwfl_Memory_Callback *memory_callback,
261 		void *memory_callback_arg)
262 {
263   /* Skip r_version, to aligned r_map field.  */
264   GElf_Addr read_vaddr = r_debug_vaddr + addrsize (elfclass);
265 
266   void *buffer = NULL;
267   size_t buffer_available = 0;
268   inline int release_buffer (int result)
269   {
270     if (buffer != NULL)
271       (void) (*memory_callback) (dwfl, -1, &buffer, &buffer_available, 0, 0,
272 				 memory_callback_arg);
273     return result;
274   }
275 
276   GElf_Addr addrs[4];
277   inline bool read_addrs (GElf_Addr vaddr, size_t n)
278   {
279     size_t nb = n * addrsize (elfclass); /* Address words -> bytes to read.  */
280 
281     /* Read a new buffer if the old one doesn't cover these words.  */
282     if (buffer == NULL
283 	|| vaddr < read_vaddr
284 	|| vaddr - read_vaddr + nb > buffer_available)
285       {
286 	release_buffer (0);
287 
288 	read_vaddr = vaddr;
289 	int segndx = INTUSE(dwfl_addrsegment) (dwfl, vaddr, NULL);
290 	if (unlikely (segndx < 0)
291 	    || unlikely (! (*memory_callback) (dwfl, segndx,
292 					       &buffer, &buffer_available,
293 					       vaddr, nb, memory_callback_arg)))
294 	  return true;
295       }
296 
297     const union
298     {
299       Elf32_Addr a32[n];
300       Elf64_Addr a64[n];
301     } *in = vaddr - read_vaddr + buffer;
302 
303     if (elfclass == ELFCLASS32)
304       {
305 	if (elfdata == ELFDATA2MSB)
306 	  for (size_t i = 0; i < n; ++i)
307 	    addrs[i] = BE32 (in->a32[i]);
308 	else
309 	  for (size_t i = 0; i < n; ++i)
310 	    addrs[i] = LE32 (in->a32[i]);
311       }
312     else
313       {
314 	if (elfdata == ELFDATA2MSB)
315 	  for (size_t i = 0; i < n; ++i)
316 	    addrs[i] = BE64 (in->a64[i]);
317 	else
318 	  for (size_t i = 0; i < n; ++i)
319 	    addrs[i] = LE64 (in->a64[i]);
320       }
321 
322     return false;
323   }
324 
325   if (unlikely (read_addrs (read_vaddr, 1)))
326     return release_buffer (-1);
327 
328   GElf_Addr next = addrs[0];
329 
330   Dwfl_Module **lastmodp = &dwfl->modulelist;
331   int result = 0;
332 
333   /* There can't be more elements in the link_map list than there are
334      segments.  DWFL->lookup_elts is probably twice that number, so it
335      is certainly above the upper bound.  If we iterate too many times,
336      there must be a loop in the pointers due to link_map clobberation.  */
337   size_t iterations = 0;
338   while (next != 0 && ++iterations < dwfl->lookup_elts)
339     {
340       if (read_addrs (next, 4))
341 	return release_buffer (-1);
342 
343       GElf_Addr l_addr = addrs[0];
344       GElf_Addr l_name = addrs[1];
345       GElf_Addr l_ld = addrs[2];
346       next = addrs[3];
347 
348       /* If a clobbered or truncated memory image has no useful pointer,
349 	 just skip this element.  */
350       if (l_ld == 0)
351 	continue;
352 
353       /* Fetch the string at the l_name address.  */
354       const char *name = NULL;
355       if (buffer != NULL
356 	  && read_vaddr <= l_name
357 	  && l_name + 1 - read_vaddr < buffer_available
358 	  && memchr (l_name - read_vaddr + buffer, '\0',
359 		     buffer_available - (l_name - read_vaddr)) != NULL)
360 	name = l_name - read_vaddr + buffer;
361       else
362 	{
363 	  release_buffer (0);
364 	  read_vaddr = l_name;
365 	  int segndx = INTUSE(dwfl_addrsegment) (dwfl, l_name, NULL);
366 	  if (likely (segndx >= 0)
367 	      && (*memory_callback) (dwfl, segndx,
368 				     &buffer, &buffer_available,
369 				     l_name, 0, memory_callback_arg))
370 	    name = buffer;
371 	}
372 
373       if (name != NULL && name[0] == '\0')
374 	name = NULL;
375 
376       /* If content-sniffing already reported a module covering
377 	 the same area, find that existing module to adjust.
378 	 The l_ld address is the only one we know for sure
379 	 to be within the module's own segments (its .dynamic).  */
380       Dwfl_Module *mod = INTUSE(dwfl_addrmodule) (dwfl, l_ld);
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 && mod->main.name == NULL)
402 	    mod->main.name = strdup (name);
403 	}
404       else if (name != NULL)
405 	{
406 	  /* We have to find the file's phdrs to compute along with l_addr
407 	     what its runtime address boundaries are.  */
408 
409 	  // XXX hook for sysroot
410 	  mod = INTUSE(dwfl_report_elf) (dwfl, basename (name),
411 					 name, -1, l_addr);
412 	}
413 
414       if (mod != NULL)
415 	{
416 	  ++result;
417 
418 	  /* Move this module to the end of the list, so that we end
419 	     up with a list in the same order as the link_map chain.  */
420 	  if (mod->next != NULL)
421 	    {
422 	      if (*lastmodp != mod)
423 		{
424 		  lastmodp = &dwfl->modulelist;
425 		  while (*lastmodp != mod)
426 		    lastmodp = &(*lastmodp)->next;
427 		}
428 	      *lastmodp = mod->next;
429 	      mod->next = NULL;
430 	      while (*lastmodp != NULL)
431 		lastmodp = &(*lastmodp)->next;
432 	      *lastmodp = mod;
433 	    }
434 
435 	  lastmodp = &mod->next;
436 	}
437     }
438 
439   return release_buffer (result);
440 }
441 
442 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)443 consider_executable (Dwfl_Module *mod, GElf_Addr at_phdr, GElf_Addr at_entry,
444 		     uint_fast8_t *elfclass, uint_fast8_t *elfdata,
445 		     Dwfl_Memory_Callback *memory_callback,
446 		     void *memory_callback_arg)
447 {
448   GElf_Ehdr ehdr;
449   if (unlikely (gelf_getehdr (mod->main.elf, &ehdr) == NULL))
450     return 0;
451 
452   if (at_entry != 0)
453     {
454       /* If we have an AT_ENTRY value, reject this executable if
455 	 its entry point address could not have supplied that.  */
456 
457       if (ehdr.e_entry == 0)
458 	return 0;
459 
460       if (mod->e_type == ET_EXEC)
461 	{
462 	  if (ehdr.e_entry != at_entry)
463 	    return 0;
464 	}
465       else
466 	{
467 	  /* It could be a PIE.  */
468 	}
469     }
470 
471   // XXX this could be saved in the file cache: phdr vaddr, DT_DEBUG d_val vaddr
472   /* Find the vaddr of the DT_DEBUG's d_ptr.  This is the memory
473      address where &r_debug was written at runtime.  */
474   GElf_Xword align = mod->dwfl->segment_align;
475   GElf_Addr d_val_vaddr = 0;
476   for (uint_fast16_t i = 0; i < ehdr.e_phnum; ++i)
477     {
478       GElf_Phdr phdr_mem;
479       GElf_Phdr *phdr = gelf_getphdr (mod->main.elf, i, &phdr_mem);
480       if (phdr == NULL)
481 	break;
482 
483       if (phdr->p_align > 1 && (align == 0 || phdr->p_align < align))
484 	align = phdr->p_align;
485 
486       if (at_phdr != 0
487 	  && phdr->p_type == PT_LOAD
488 	  && (phdr->p_offset & -align) == (ehdr.e_phoff & -align))
489 	{
490 	  /* This is the segment that would map the phdrs.
491 	     If we have an AT_PHDR value, reject this executable
492 	     if its phdr mapping could not have supplied that.  */
493 	  if (mod->e_type == ET_EXEC)
494 	    {
495 	      if (ehdr.e_phoff - phdr->p_offset + phdr->p_vaddr != at_phdr)
496 		return 0;
497 	    }
498 	  else
499 	    {
500 	      /* It could be a PIE.  If the AT_PHDR value and our
501 		 phdr address don't match modulo ALIGN, then this
502 		 could not have been the right PIE.  */
503 	      if (((ehdr.e_phoff - phdr->p_offset + phdr->p_vaddr) & -align)
504 		  != (at_phdr & -align))
505 		return 0;
506 
507 	      /* Calculate the bias applied to the PIE's p_vaddr values.  */
508 	      GElf_Addr bias = (at_phdr - (ehdr.e_phoff - phdr->p_offset
509 					   + phdr->p_vaddr));
510 
511 	      /* Final sanity check: if we have an AT_ENTRY value,
512 		 reject this PIE unless its biased e_entry matches.  */
513 	      if (at_entry != 0 && at_entry != ehdr.e_entry + bias)
514 		return 0;
515 
516 	      /* If we're changing the module's address range,
517 		 we've just invalidated the module lookup table.  */
518 	      GElf_Addr mod_bias = dwfl_adjusted_address (mod, 0);
519 	      if (bias != mod_bias)
520 		{
521 		  mod->low_addr -= mod_bias;
522 		  mod->high_addr -= mod_bias;
523 		  mod->low_addr += bias;
524 		  mod->high_addr += bias;
525 
526 		  free (mod->dwfl->lookup_module);
527 		  mod->dwfl->lookup_module = NULL;
528 		}
529 	    }
530 	}
531 
532       if (phdr->p_type == PT_DYNAMIC)
533 	{
534 	  Elf_Data *data = elf_getdata_rawchunk (mod->main.elf, phdr->p_offset,
535 						 phdr->p_filesz, ELF_T_DYN);
536 	  if (data == NULL)
537 	    continue;
538 	  const size_t entsize = gelf_fsize (mod->main.elf,
539 					     ELF_T_DYN, 1, EV_CURRENT);
540 	  const size_t n = data->d_size / entsize;
541 	  for (size_t j = 0; j < n; ++j)
542 	    {
543 	      GElf_Dyn dyn_mem;
544 	      GElf_Dyn *dyn = gelf_getdyn (data, j, &dyn_mem);
545 	      if (dyn != NULL && dyn->d_tag == DT_DEBUG)
546 		{
547 		  d_val_vaddr = phdr->p_vaddr + entsize * j + entsize / 2;
548 		  break;
549 		}
550 	    }
551 	}
552     }
553 
554   if (d_val_vaddr != 0)
555     {
556       /* Now we have the final address from which to read &r_debug.  */
557       d_val_vaddr = dwfl_adjusted_address (mod, d_val_vaddr);
558 
559       void *buffer = NULL;
560       size_t buffer_available = addrsize (ehdr.e_ident[EI_CLASS]);
561 
562       int segndx = INTUSE(dwfl_addrsegment) (mod->dwfl, d_val_vaddr, NULL);
563 
564       if ((*memory_callback) (mod->dwfl, segndx,
565 			      &buffer, &buffer_available,
566 			      d_val_vaddr, buffer_available,
567 			      memory_callback_arg))
568 	{
569 	  const union
570 	  {
571 	    Elf32_Addr a32;
572 	    Elf64_Addr a64;
573 	  } *u = buffer;
574 
575 	  GElf_Addr vaddr;
576 	  if (ehdr.e_ident[EI_CLASS] == ELFCLASS32)
577 	    vaddr = (ehdr.e_ident[EI_DATA] == ELFDATA2MSB
578 		     ? BE32 (u->a32) : LE32 (u->a32));
579 	  else
580 	    vaddr = (ehdr.e_ident[EI_DATA] == ELFDATA2MSB
581 		     ? BE64 (u->a64) : LE64 (u->a64));
582 
583 	  (*memory_callback) (mod->dwfl, -1, &buffer, &buffer_available, 0, 0,
584 			      memory_callback_arg);
585 
586 	  if (*elfclass == ELFCLASSNONE)
587 	    *elfclass = ehdr.e_ident[EI_CLASS];
588 	  else if (*elfclass != ehdr.e_ident[EI_CLASS])
589 	    return 0;
590 
591 	  if (*elfdata == ELFDATANONE)
592 	    *elfdata = ehdr.e_ident[EI_DATA];
593 	  else if (*elfdata != ehdr.e_ident[EI_DATA])
594 	    return 0;
595 
596 	  return vaddr;
597 	}
598     }
599 
600   return 0;
601 }
602 
603 /* Try to find an existing executable module with a DT_DEBUG.  */
604 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)605 find_executable (Dwfl *dwfl, GElf_Addr at_phdr, GElf_Addr at_entry,
606 		 uint_fast8_t *elfclass, uint_fast8_t *elfdata,
607 		 Dwfl_Memory_Callback *memory_callback,
608 		 void *memory_callback_arg)
609 {
610   for (Dwfl_Module *mod = dwfl->modulelist; mod != NULL; mod = mod->next)
611     if (mod->main.elf != NULL)
612       {
613 	GElf_Addr r_debug_vaddr = consider_executable (mod, at_phdr, at_entry,
614 						       elfclass, elfdata,
615 						       memory_callback,
616 						       memory_callback_arg);
617 	if (r_debug_vaddr != 0)
618 	  return r_debug_vaddr;
619       }
620 
621   return 0;
622 }
623 
624 
625 int
dwfl_link_map_report(Dwfl * dwfl,const void * auxv,size_t auxv_size,Dwfl_Memory_Callback * memory_callback,void * memory_callback_arg)626 dwfl_link_map_report (Dwfl *dwfl, const void *auxv, size_t auxv_size,
627 		      Dwfl_Memory_Callback *memory_callback,
628 		      void *memory_callback_arg)
629 {
630   GElf_Addr r_debug_vaddr = 0;
631 
632   uint_fast8_t elfclass = ELFCLASSNONE;
633   uint_fast8_t elfdata = ELFDATANONE;
634   if (likely (auxv != NULL)
635       && likely (auxv_format_probe (auxv, auxv_size, &elfclass, &elfdata)))
636     {
637       GElf_Addr entry = 0;
638       GElf_Addr phdr = 0;
639       GElf_Xword phent = 0;
640       GElf_Xword phnum = 0;
641 
642 #define AUXV_SCAN(NN, BL) do					\
643 	{							\
644 	  const Elf##NN##_auxv_t *av = auxv;			\
645 	  for (size_t i = 0; i < auxv_size / sizeof av[0]; ++i)	\
646 	    {							\
647 	      Elf##NN##_Addr val = BL##NN (av[i].a_un.a_val);	\
648 	      if (av[i].a_type == BL##NN (AT_ENTRY))		\
649 		entry = val;					\
650 	      else if (av[i].a_type == BL##NN (AT_PHDR))	\
651 		phdr = val;					\
652 	      else if (av[i].a_type == BL##NN (AT_PHNUM))	\
653 		phnum = val;					\
654 	      else if (av[i].a_type == BL##NN (AT_PHENT))	\
655 		phent = val;					\
656 	      else if (av[i].a_type == BL##NN (AT_PAGESZ))	\
657 		{						\
658 		  if (val > 1					\
659 		      && (dwfl->segment_align == 0		\
660 			  || val < dwfl->segment_align))	\
661 		    dwfl->segment_align = val;			\
662 		}						\
663 	    }							\
664 	}							\
665       while (0)
666 
667       if (elfclass == ELFCLASS32)
668 	{
669 	  if (elfdata == ELFDATA2MSB)
670 	    AUXV_SCAN (32, BE);
671 	  else
672 	    AUXV_SCAN (32, LE);
673 	}
674       else
675 	{
676 	  if (elfdata == ELFDATA2MSB)
677 	    AUXV_SCAN (64, BE);
678 	  else
679 	    AUXV_SCAN (64, LE);
680 	}
681 
682       /* If we found the phdr dimensions, search phdrs for PT_DYNAMIC.  */
683       GElf_Addr dyn_vaddr = 0;
684       GElf_Xword dyn_filesz = 0;
685       GElf_Addr dyn_bias = (GElf_Addr) -1;
686 
687       inline bool consider_phdr (GElf_Word type,
688 				 GElf_Addr vaddr, GElf_Xword filesz)
689       {
690 	switch (type)
691 	  {
692 	  case PT_PHDR:
693 	    if (dyn_bias == (GElf_Addr) -1
694 		/* Do a sanity check on the putative address.  */
695 		&& ((vaddr & (dwfl->segment_align - 1))
696 		    == (phdr & (dwfl->segment_align - 1))))
697 	      {
698 		dyn_bias = phdr - vaddr;
699 		return dyn_vaddr != 0;
700 	      }
701 	    break;
702 
703 	  case PT_DYNAMIC:
704 	    dyn_vaddr = vaddr;
705 	    dyn_filesz = filesz;
706 	    return dyn_bias != (GElf_Addr) -1;
707 	  }
708 
709 	return false;
710       }
711 
712       if (phdr != 0 && phnum != 0)
713 	{
714 	  Dwfl_Module *phdr_mod;
715 	  int phdr_segndx = INTUSE(dwfl_addrsegment) (dwfl, phdr, &phdr_mod);
716 	  Elf_Data in =
717 	    {
718 	      .d_type = ELF_T_PHDR,
719 	      .d_version = EV_CURRENT,
720 	      .d_size = phnum * phent,
721 	      .d_buf = NULL
722 	    };
723 	  if ((*memory_callback) (dwfl, phdr_segndx, &in.d_buf, &in.d_size,
724 				  phdr, phnum * phent, memory_callback_arg))
725 	    {
726 	      union
727 	      {
728 		Elf32_Phdr p32;
729 		Elf64_Phdr p64;
730 		char data[phnum * phent];
731 	      } buf;
732 	      Elf_Data out =
733 		{
734 		  .d_type = ELF_T_PHDR,
735 		  .d_version = EV_CURRENT,
736 		  .d_size = phnum * phent,
737 		  .d_buf = &buf
738 		};
739 	      in.d_size = out.d_size;
740 	      if (likely ((elfclass == ELFCLASS32
741 			   ? elf32_xlatetom : elf64_xlatetom)
742 			  (&out, &in, elfdata) != NULL))
743 		{
744 		  /* We are looking for PT_DYNAMIC.  */
745 		  const union
746 		  {
747 		    Elf32_Phdr p32[phnum];
748 		    Elf64_Phdr p64[phnum];
749 		  } *u = (void *) &buf;
750 		  if (elfclass == ELFCLASS32)
751 		    {
752 		      for (size_t i = 0; i < phnum; ++i)
753 			if (consider_phdr (u->p32[i].p_type,
754 					   u->p32[i].p_vaddr,
755 					   u->p32[i].p_filesz))
756 			  break;
757 		    }
758 		  else
759 		    {
760 		      for (size_t i = 0; i < phnum; ++i)
761 			if (consider_phdr (u->p64[i].p_type,
762 					   u->p64[i].p_vaddr,
763 					   u->p64[i].p_filesz))
764 			  break;
765 		    }
766 		}
767 
768 	      (*memory_callback) (dwfl, -1, &in.d_buf, &in.d_size, 0, 0,
769 				  memory_callback_arg);
770 	    }
771 	  else
772 	    /* We could not read the executable's phdrs from the
773 	       memory image.  If we have a presupplied executable,
774 	       we can still use the AT_PHDR and AT_ENTRY values to
775 	       verify it, and to adjust its bias if it's a PIE.
776 
777 	       If there was an ET_EXEC module presupplied that contains
778 	       the AT_PHDR address, then we only consider that one.
779 	       We'll either accept it if its phdr location and e_entry
780 	       make sense or reject it if they don't.  If there is no
781 	       presupplied ET_EXEC, then look for a presupplied module,
782 	       which might be a PIE (ET_DYN) that needs its bias adjusted.  */
783 	    r_debug_vaddr = ((phdr_mod == NULL
784 			      || phdr_mod->main.elf == NULL
785 			      || phdr_mod->e_type != ET_EXEC)
786 			     ? find_executable (dwfl, phdr, entry,
787 						&elfclass, &elfdata,
788 						memory_callback,
789 						memory_callback_arg)
790 			     : consider_executable (phdr_mod, phdr, entry,
791 						    &elfclass, &elfdata,
792 						    memory_callback,
793 						    memory_callback_arg));
794 	}
795 
796       /* If we found PT_DYNAMIC, search it for DT_DEBUG.  */
797       if (dyn_filesz != 0)
798 	{
799 	  if (dyn_bias != (GElf_Addr) -1)
800 	    dyn_vaddr += dyn_bias;
801 
802 	  Elf_Data in =
803 	    {
804 	      .d_type = ELF_T_DYN,
805 	      .d_version = EV_CURRENT,
806 	      .d_size = dyn_filesz,
807 	      .d_buf = NULL
808 	    };
809 	  int dyn_segndx = dwfl_addrsegment (dwfl, dyn_vaddr, NULL);
810 	  if ((*memory_callback) (dwfl, dyn_segndx, &in.d_buf, &in.d_size,
811 				  dyn_vaddr, dyn_filesz, memory_callback_arg))
812 	    {
813 	      union
814 	      {
815 		Elf32_Dyn d32;
816 		Elf64_Dyn d64;
817 		char data[dyn_filesz];
818 	      } buf;
819 	      Elf_Data out =
820 		{
821 		  .d_type = ELF_T_DYN,
822 		  .d_version = EV_CURRENT,
823 		  .d_size = dyn_filesz,
824 		  .d_buf = &buf
825 		};
826 	      in.d_size = out.d_size;
827 	      if (likely ((elfclass == ELFCLASS32
828 			   ? elf32_xlatetom : elf64_xlatetom)
829 			  (&out, &in, elfdata) != NULL))
830 		{
831 		  /* We are looking for DT_DEBUG.  */
832 		  const union
833 		  {
834 		    Elf32_Dyn d32[dyn_filesz / sizeof (Elf32_Dyn)];
835 		    Elf64_Dyn d64[dyn_filesz / sizeof (Elf64_Dyn)];
836 		  } *u = (void *) &buf;
837 		  if (elfclass == ELFCLASS32)
838 		    {
839 		      size_t n = dyn_filesz / sizeof (Elf32_Dyn);
840 		      for (size_t i = 0; i < n; ++i)
841 			if (u->d32[i].d_tag == DT_DEBUG)
842 			  {
843 			    r_debug_vaddr = u->d32[i].d_un.d_val;
844 			    break;
845 			  }
846 		    }
847 		  else
848 		    {
849 		      size_t n = dyn_filesz / sizeof (Elf64_Dyn);
850 		      for (size_t i = 0; i < n; ++i)
851 			if (u->d64[i].d_tag == DT_DEBUG)
852 			  {
853 			    r_debug_vaddr = u->d64[i].d_un.d_val;
854 			    break;
855 			  }
856 		    }
857 		}
858 
859 	      (*memory_callback) (dwfl, -1, &in.d_buf, &in.d_size, 0, 0,
860 				  memory_callback_arg);
861 	    }
862 	}
863     }
864   else
865     /* We have to look for a presupplied executable file to determine
866        the vaddr of its dynamic section and DT_DEBUG therein.  */
867     r_debug_vaddr = find_executable (dwfl, 0, 0, &elfclass, &elfdata,
868 				     memory_callback, memory_callback_arg);
869 
870   if (r_debug_vaddr == 0)
871     return 0;
872 
873   /* For following pointers from struct link_map, we will use an
874      integrated memory access callback that can consult module text
875      elided from the core file.  This is necessary when the l_name
876      pointer for the dynamic linker's own entry is a pointer into the
877      executable's .interp section.  */
878   struct integrated_memory_callback mcb =
879     {
880       .memory_callback = memory_callback,
881       .memory_callback_arg = memory_callback_arg
882     };
883 
884   /* Now we can follow the dynamic linker's library list.  */
885   return report_r_debug (elfclass, elfdata, dwfl, r_debug_vaddr,
886 			 &integrated_memory_callback, &mcb);
887 }
888 INTDEF (dwfl_link_map_report)
889