packaging: update homepage url
[platform/upstream/elfutils.git] / libdwfl / dwfl_segment_report_module.c
1 /* Sniff out modules from ELF headers visible in memory segments.
2    Copyright (C) 2008-2012, 2014, 2015 Red Hat, Inc.
3    This file is part of elfutils.
4
5    This file is free software; you can redistribute it and/or modify
6    it under the terms of either
7
8      * the GNU Lesser General Public License as published by the Free
9        Software Foundation; either version 3 of the License, or (at
10        your option) any later version
11
12    or
13
14      * the GNU General Public License as published by the Free
15        Software Foundation; either version 2 of the License, or (at
16        your option) any later version
17
18    or both in parallel, as here.
19
20    elfutils is distributed in the hope that it will be useful, but
21    WITHOUT ANY WARRANTY; without even the implied warranty of
22    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
23    General Public License for more details.
24
25    You should have received copies of the GNU General Public License and
26    the GNU Lesser General Public License along with this program.  If
27    not, see <http://www.gnu.org/licenses/>.  */
28
29 #include <config.h>
30 #include "../libelf/libelfP.h"  /* For NOTE_ALIGN.  */
31 #undef  _
32 #include "libdwflP.h"
33 #include "common.h"
34
35 #include <elf.h>
36 #include <gelf.h>
37 #include <inttypes.h>
38 #include <sys/param.h>
39 #include <endian.h>
40 #include <unistd.h>
41 #include <fcntl.h>
42
43
44 /* A good size for the initial read from memory, if it's not too costly.
45    This more than covers the phdrs and note segment in the average 64-bit
46    binary.  */
47
48 #define INITIAL_READ    1024
49
50 #if __BYTE_ORDER == __LITTLE_ENDIAN
51 # define MY_ELFDATA     ELFDATA2LSB
52 #else
53 # define MY_ELFDATA     ELFDATA2MSB
54 #endif
55
56 #ifndef MAX
57 # define MAX(a, b) ((a) > (b) ? (a) : (b))
58 #endif
59
60
61 /* Return user segment index closest to ADDR but not above it.
62    If NEXT, return the closest to ADDR but not below it.  */
63 static int
64 addr_segndx (Dwfl *dwfl, size_t segment, GElf_Addr addr, bool next)
65 {
66   int ndx = -1;
67   do
68     {
69       if (dwfl->lookup_segndx[segment] >= 0)
70         ndx = dwfl->lookup_segndx[segment];
71       if (++segment >= dwfl->lookup_elts - 1)
72         return next ? ndx + 1 : ndx;
73     }
74   while (dwfl->lookup_addr[segment] < addr);
75
76   if (next)
77     {
78       while (dwfl->lookup_segndx[segment] < 0)
79         if (++segment >= dwfl->lookup_elts - 1)
80           return ndx + 1;
81       ndx = dwfl->lookup_segndx[segment];
82     }
83
84   return ndx;
85 }
86
87 /* Return whether there is SZ bytes available at PTR till END.  */
88
89 static bool
90 buf_has_data (const void *ptr, const void *end, size_t sz)
91 {
92   return ptr < end && (size_t) (end - ptr) >= sz;
93 }
94
95 /* Read SZ bytes into *RETP from *PTRP (limited by END) in format EI_DATA.
96    Function comes from src/readelf.c .  */
97
98 static bool
99 buf_read_ulong (unsigned char ei_data, size_t sz,
100                 const void **ptrp, const void *end, uint64_t *retp)
101 {
102   if (! buf_has_data (*ptrp, end, sz))
103     return false;
104
105   union
106   {
107     uint64_t u64;
108     uint32_t u32;
109   } u;
110
111   memcpy (&u, *ptrp, sz);
112   (*ptrp) += sz;
113
114   if (retp == NULL)
115     return true;
116
117   if (MY_ELFDATA != ei_data)
118     {
119       if (sz == 4)
120         CONVERT (u.u32);
121       else
122         CONVERT (u.u64);
123     }
124   if (sz == 4)
125     *retp = u.u32;
126   else
127     *retp = u.u64;
128   return true;
129 }
130
131 /* Try to find matching entry for module from address MODULE_START to
132    MODULE_END in NT_FILE note located at NOTE_FILE of NOTE_FILE_SIZE
133    bytes in format EI_CLASS and EI_DATA.  */
134
135 static const char *
136 handle_file_note (GElf_Addr module_start, GElf_Addr module_end,
137                   unsigned char ei_class, unsigned char ei_data,
138                   const void *note_file, size_t note_file_size)
139 {
140   if (note_file == NULL)
141     return NULL;
142
143   size_t sz;
144   switch (ei_class)
145     {
146     case ELFCLASS32:
147       sz = 4;
148       break;
149     case ELFCLASS64:
150       sz = 8;
151       break;
152     default:
153       return NULL;
154     }
155
156   const void *ptr = note_file;
157   const void *end = note_file + note_file_size;
158   uint64_t count;
159   if (! buf_read_ulong (ei_data, sz, &ptr, end, &count))
160     return NULL;
161   if (! buf_read_ulong (ei_data, sz, &ptr, end, NULL)) // page_size
162     return NULL;
163
164   uint64_t maxcount = (size_t) (end - ptr) / (3 * sz);
165   if (count > maxcount)
166     return NULL;
167
168   /* Where file names are stored.  */
169   const char *fptr = ptr + 3 * count * sz;
170
171   ssize_t firstix = -1;
172   ssize_t lastix = -1;
173   for (size_t mix = 0; mix < count; mix++)
174     {
175       uint64_t mstart, mend, moffset;
176       if (! buf_read_ulong (ei_data, sz, &ptr, fptr, &mstart)
177           || ! buf_read_ulong (ei_data, sz, &ptr, fptr, &mend)
178           || ! buf_read_ulong (ei_data, sz, &ptr, fptr, &moffset))
179         return NULL;
180       if (mstart == module_start && moffset == 0)
181         firstix = lastix = mix;
182       if (firstix != -1 && mstart < module_end)
183         lastix = mix;
184       if (mend >= module_end)
185         break;
186     }
187   if (firstix == -1)
188     return NULL;
189
190   const char *retval = NULL;
191   for (ssize_t mix = 0; mix <= lastix; mix++)
192     {
193       const char *fnext = memchr (fptr, 0, (const char *) end - fptr);
194       if (fnext == NULL)
195         return NULL;
196       if (mix == firstix)
197         retval = fptr;
198       if (firstix < mix && mix <= lastix && strcmp (fptr, retval) != 0)
199         return NULL;
200       fptr = fnext + 1;
201     }
202   return retval;
203 }
204
205 /* Return true iff we are certain ELF cannot match BUILD_ID of
206    BUILD_ID_LEN bytes.  Pass DISK_FILE_HAS_BUILD_ID as false if it is
207    certain ELF does not contain build-id (it is only a performance hit
208    to pass it always as true).  */
209
210 static bool
211 invalid_elf (Elf *elf, bool disk_file_has_build_id,
212              const void *build_id, size_t build_id_len)
213 {
214   if (! disk_file_has_build_id && build_id_len > 0)
215     {
216       /* Module found in segments with build-id is more reliable
217          than a module found via DT_DEBUG on disk without any
218          build-id.   */
219       return true;
220     }
221   if (disk_file_has_build_id && build_id_len > 0)
222     {
223       const void *elf_build_id;
224       ssize_t elf_build_id_len;
225
226       /* If there is a build id in the elf file, check it.  */
227       elf_build_id_len = INTUSE(dwelf_elf_gnu_build_id) (elf, &elf_build_id);
228       if (elf_build_id_len > 0)
229         {
230           if (build_id_len != (size_t) elf_build_id_len
231               || memcmp (build_id, elf_build_id, build_id_len) != 0)
232             return true;
233         }
234     }
235   return false;
236 }
237
238 int
239 dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name,
240                             Dwfl_Memory_Callback *memory_callback,
241                             void *memory_callback_arg,
242                             Dwfl_Module_Callback *read_eagerly,
243                             void *read_eagerly_arg,
244                             const void *note_file, size_t note_file_size,
245                             const struct r_debug_info *r_debug_info)
246 {
247   size_t segment = ndx;
248
249   if (segment >= dwfl->lookup_elts)
250     segment = dwfl->lookup_elts - 1;
251
252   while (segment > 0
253          && (dwfl->lookup_segndx[segment] > ndx
254              || dwfl->lookup_segndx[segment] == -1))
255     --segment;
256
257   while (dwfl->lookup_segndx[segment] < ndx)
258     if (++segment == dwfl->lookup_elts)
259       return 0;
260
261   GElf_Addr start = dwfl->lookup_addr[segment];
262
263   inline bool segment_read (int segndx,
264                             void **buffer, size_t *buffer_available,
265                             GElf_Addr addr, size_t minread)
266   {
267     return ! (*memory_callback) (dwfl, segndx, buffer, buffer_available,
268                                  addr, minread, memory_callback_arg);
269   }
270
271   inline void release_buffer (void **buffer, size_t *buffer_available)
272   {
273     if (*buffer != NULL)
274       (void) segment_read (-1, buffer, buffer_available, 0, 0);
275   }
276
277   /* First read in the file header and check its sanity.  */
278
279   void *buffer = NULL;
280   size_t buffer_available = INITIAL_READ;
281   Elf *elf = NULL;
282   int fd = -1;
283
284   /* We might have to reserve some memory for the phdrs.  Set to NULL
285      here so we can always safely free it.  */
286   void *phdrsp = NULL;
287
288   inline int finish (void)
289   {
290     free (phdrsp);
291     release_buffer (&buffer, &buffer_available);
292     if (elf != NULL)
293       elf_end (elf);
294     if (fd != -1)
295       close (fd);
296     return ndx;
297   }
298
299   if (segment_read (ndx, &buffer, &buffer_available,
300                     start, sizeof (Elf64_Ehdr))
301       || memcmp (buffer, ELFMAG, SELFMAG) != 0)
302     return finish ();
303
304   inline bool read_portion (void **data, size_t *data_size,
305                             GElf_Addr vaddr, size_t filesz)
306   {
307     if (vaddr - start + filesz > buffer_available
308         /* If we're in string mode, then don't consider the buffer we have
309            sufficient unless it contains the terminator of the string.  */
310         || (filesz == 0 && memchr (vaddr - start + buffer, '\0',
311                                    buffer_available - (vaddr - start)) == NULL))
312       {
313         *data = NULL;
314         *data_size = filesz;
315         return segment_read (addr_segndx (dwfl, segment, vaddr, false),
316                              data, data_size, vaddr, filesz);
317       }
318
319     /* We already have this whole note segment from our initial read.  */
320     *data = vaddr - start + buffer;
321     *data_size = 0;
322     return false;
323   }
324
325   inline void finish_portion (void **data, size_t *data_size)
326   {
327     if (*data_size != 0)
328       release_buffer (data, data_size);
329   }
330
331   /* Extract the information we need from the file header.  */
332   const unsigned char *e_ident;
333   unsigned char ei_class;
334   unsigned char ei_data;
335   uint16_t e_type;
336   union
337   {
338     Elf32_Ehdr e32;
339     Elf64_Ehdr e64;
340   } ehdr;
341   GElf_Off phoff;
342   uint_fast16_t phnum;
343   uint_fast16_t phentsize;
344   GElf_Off shdrs_end;
345   Elf_Data xlatefrom =
346     {
347       .d_type = ELF_T_EHDR,
348       .d_buf = (void *) buffer,
349       .d_version = EV_CURRENT,
350     };
351   Elf_Data xlateto =
352     {
353       .d_type = ELF_T_EHDR,
354       .d_buf = &ehdr,
355       .d_size = sizeof ehdr,
356       .d_version = EV_CURRENT,
357     };
358   e_ident = ((const unsigned char *) buffer);
359   ei_class = e_ident[EI_CLASS];
360   ei_data = e_ident[EI_DATA];
361   switch (ei_class)
362     {
363     case ELFCLASS32:
364       xlatefrom.d_size = sizeof (Elf32_Ehdr);
365       if (elf32_xlatetom (&xlateto, &xlatefrom, ei_data) == NULL)
366         return finish ();
367       e_type = ehdr.e32.e_type;
368       phoff = ehdr.e32.e_phoff;
369       phnum = ehdr.e32.e_phnum;
370       phentsize = ehdr.e32.e_phentsize;
371       if (phentsize != sizeof (Elf32_Phdr))
372         return finish ();
373       shdrs_end = ehdr.e32.e_shoff + ehdr.e32.e_shnum * ehdr.e32.e_shentsize;
374       break;
375
376     case ELFCLASS64:
377       xlatefrom.d_size = sizeof (Elf64_Ehdr);
378       if (elf64_xlatetom (&xlateto, &xlatefrom, ei_data) == NULL)
379         return finish ();
380       e_type = ehdr.e64.e_type;
381       phoff = ehdr.e64.e_phoff;
382       phnum = ehdr.e64.e_phnum;
383       phentsize = ehdr.e64.e_phentsize;
384       if (phentsize != sizeof (Elf64_Phdr))
385         return finish ();
386       shdrs_end = ehdr.e64.e_shoff + ehdr.e64.e_shnum * ehdr.e64.e_shentsize;
387       break;
388
389     default:
390       return finish ();
391     }
392
393   /* The file header tells where to find the program headers.
394      These are what we need to find the boundaries of the module.
395      Without them, we don't have a module to report.  */
396
397   if (phnum == 0)
398     return finish ();
399
400   xlatefrom.d_type = xlateto.d_type = ELF_T_PHDR;
401   xlatefrom.d_size = phnum * phentsize;
402
403   void *ph_buffer = NULL;
404   size_t ph_buffer_size = 0;
405   if (read_portion (&ph_buffer, &ph_buffer_size,
406                     start + phoff, xlatefrom.d_size))
407     return finish ();
408
409   xlatefrom.d_buf = ph_buffer;
410
411   bool class32 = ei_class == ELFCLASS32;
412   size_t phdr_size = class32 ? sizeof (Elf32_Phdr) : sizeof (Elf64_Phdr);
413   if (unlikely (phnum > SIZE_MAX / phdr_size))
414     return finish ();
415   const size_t phdrsp_bytes = phnum * phdr_size;
416   phdrsp = malloc (phdrsp_bytes);
417   if (unlikely (phdrsp == NULL))
418     return finish ();
419
420   xlateto.d_buf = phdrsp;
421   xlateto.d_size = phdrsp_bytes;
422
423   /* Track the bounds of the file visible in memory.  */
424   GElf_Off file_trimmed_end = 0; /* Proper p_vaddr + p_filesz end.  */
425   GElf_Off file_end = 0;         /* Rounded up to effective page size.  */
426   GElf_Off contiguous = 0;       /* Visible as contiguous file from START.  */
427   GElf_Off total_filesz = 0;     /* Total size of data to read.  */
428
429   /* Collect the bias between START and the containing PT_LOAD's p_vaddr.  */
430   GElf_Addr bias = 0;
431   bool found_bias = false;
432
433   /* Collect the unbiased bounds of the module here.  */
434   GElf_Addr module_start = -1l;
435   GElf_Addr module_end = 0;
436   GElf_Addr module_address_sync = 0;
437
438   /* If we see PT_DYNAMIC, record it here.  */
439   GElf_Addr dyn_vaddr = 0;
440   GElf_Xword dyn_filesz = 0;
441
442   /* Collect the build ID bits here.  */
443   void *build_id = NULL;
444   size_t build_id_len = 0;
445   GElf_Addr build_id_vaddr = 0;
446
447   /* Consider a PT_NOTE we've found in the image.  */
448   inline void consider_notes (GElf_Addr vaddr, GElf_Xword filesz)
449   {
450     /* If we have already seen a build ID, we don't care any more.  */
451     if (build_id != NULL || filesz == 0)
452       return;
453
454     void *data;
455     size_t data_size;
456     if (read_portion (&data, &data_size, vaddr, filesz))
457       return;
458
459     assert (sizeof (Elf32_Nhdr) == sizeof (Elf64_Nhdr));
460
461     void *notes;
462     if (ei_data == MY_ELFDATA)
463       notes = data;
464     else
465       {
466         notes = malloc (filesz);
467         if (unlikely (notes == NULL))
468           return;
469         xlatefrom.d_type = xlateto.d_type = ELF_T_NHDR;
470         xlatefrom.d_buf = (void *) data;
471         xlatefrom.d_size = filesz;
472         xlateto.d_buf = notes;
473         xlateto.d_size = filesz;
474         if (elf32_xlatetom (&xlateto, &xlatefrom,
475                             ehdr.e32.e_ident[EI_DATA]) == NULL)
476           goto done;
477       }
478
479     const GElf_Nhdr *nh = notes;
480     while ((const void *) nh < (const void *) notes + filesz)
481      {
482         const void *note_name = nh + 1;
483         const void *note_desc = note_name + NOTE_ALIGN (nh->n_namesz);
484         if (unlikely ((size_t) ((const void *) notes + filesz
485                                 - note_desc) < nh->n_descsz))
486           break;
487
488         if (nh->n_type == NT_GNU_BUILD_ID
489             && nh->n_descsz > 0
490             && nh->n_namesz == sizeof "GNU"
491             && !memcmp (note_name, "GNU", sizeof "GNU"))
492           {
493             build_id_vaddr = note_desc - (const void *) notes + vaddr;
494             build_id_len = nh->n_descsz;
495             build_id = malloc (nh->n_descsz);
496             if (likely (build_id != NULL))
497               memcpy (build_id, note_desc, build_id_len);
498             break;
499           }
500
501         nh = note_desc + NOTE_ALIGN (nh->n_descsz);
502       }
503
504   done:
505     if (notes != data)
506       free (notes);
507     finish_portion (&data, &data_size);
508   }
509
510   /* Consider each of the program headers we've read from the image.  */
511   inline void consider_phdr (GElf_Word type,
512                              GElf_Addr vaddr, GElf_Xword memsz,
513                              GElf_Off offset, GElf_Xword filesz,
514                              GElf_Xword align)
515   {
516     switch (type)
517       {
518       case PT_DYNAMIC:
519         dyn_vaddr = vaddr;
520         dyn_filesz = filesz;
521         break;
522
523       case PT_NOTE:
524         /* We calculate from the p_offset of the note segment,
525            because we don't yet know the bias for its p_vaddr.  */
526         consider_notes (start + offset, filesz);
527         break;
528
529       case PT_LOAD:
530         align = dwfl->segment_align > 1 ? dwfl->segment_align : align ?: 1;
531
532         GElf_Addr vaddr_end = (vaddr + memsz + align - 1) & -align;
533         GElf_Addr filesz_vaddr = filesz < memsz ? vaddr + filesz : vaddr_end;
534         GElf_Off filesz_offset = filesz_vaddr - vaddr + offset;
535
536         if (file_trimmed_end < offset + filesz)
537           {
538             file_trimmed_end = offset + filesz;
539
540             /* Trim the last segment so we don't bother with zeros
541                in the last page that are off the end of the file.
542                However, if the extra bit in that page includes the
543                section headers, keep them.  */
544             if (shdrs_end <= filesz_offset && shdrs_end > file_trimmed_end)
545               {
546                 filesz += shdrs_end - file_trimmed_end;
547                 file_trimmed_end = shdrs_end;
548               }
549           }
550
551         total_filesz += filesz;
552
553         if (file_end < filesz_offset)
554           {
555             file_end = filesz_offset;
556             if (filesz_vaddr - start == filesz_offset)
557               contiguous = file_end;
558           }
559
560         if (!found_bias && (offset & -align) == 0
561             && likely (filesz_offset >= phoff + phnum * phentsize))
562           {
563             bias = start - vaddr;
564             found_bias = true;
565           }
566
567         if ((vaddr & -align) < module_start)
568           {
569             module_start = vaddr & -align;
570             module_address_sync = vaddr + memsz;
571           }
572
573         if (module_end < vaddr_end)
574           module_end = vaddr_end;
575         break;
576       }
577   }
578
579   Elf32_Phdr (*p32)[phnum] = phdrsp;
580   Elf64_Phdr (*p64)[phnum] = phdrsp;
581   if (ei_class == ELFCLASS32)
582     {
583       if (elf32_xlatetom (&xlateto, &xlatefrom, ei_data) == NULL)
584         found_bias = false;     /* Trigger error check.  */
585       else
586         for (uint_fast16_t i = 0; i < phnum; ++i)
587           consider_phdr ((*p32)[i].p_type,
588                          (*p32)[i].p_vaddr, (*p32)[i].p_memsz,
589                          (*p32)[i].p_offset, (*p32)[i].p_filesz,
590                          (*p32)[i].p_align);
591     }
592   else
593     {
594       if (elf64_xlatetom (&xlateto, &xlatefrom, ei_data) == NULL)
595         found_bias = false;     /* Trigger error check.  */
596       else
597         for (uint_fast16_t i = 0; i < phnum; ++i)
598           consider_phdr ((*p64)[i].p_type,
599                          (*p64)[i].p_vaddr, (*p64)[i].p_memsz,
600                          (*p64)[i].p_offset, (*p64)[i].p_filesz,
601                          (*p64)[i].p_align);
602     }
603
604   finish_portion (&ph_buffer, &ph_buffer_size);
605
606   /* We must have seen the segment covering offset 0, or else the ELF
607      header we read at START was not produced by these program headers.  */
608   if (unlikely (!found_bias))
609     {
610       free (build_id);
611       return finish ();
612     }
613
614   /* Now we know enough to report a module for sure: its bounds.  */
615   module_start += bias;
616   module_end += bias;
617
618   dyn_vaddr += bias;
619
620   /* NAME found from link map has precedence over DT_SONAME possibly read
621      below.  */
622   bool name_is_final = false;
623
624   /* Try to match up DYN_VADDR against L_LD as found in link map.
625      Segments sniffing may guess invalid address as the first read-only memory
626      mapping may not be dumped to the core file (if ELF headers are not dumped)
627      and the ELF header is dumped first with the read/write mapping of the same
628      file at higher addresses.  */
629   if (r_debug_info != NULL)
630     for (const struct r_debug_info_module *module = r_debug_info->module;
631          module != NULL; module = module->next)
632       if (module_start <= module->l_ld && module->l_ld < module_end)
633         {
634           /* L_LD read from link map must be right while DYN_VADDR is unsafe.
635              Therefore subtract DYN_VADDR and add L_LD to get a possibly
636              corrective displacement for all addresses computed so far.  */
637           GElf_Addr fixup = module->l_ld - dyn_vaddr;
638           if ((fixup & (dwfl->segment_align - 1)) == 0
639               && module_start + fixup <= module->l_ld
640               && module->l_ld < module_end + fixup)
641             {
642               module_start += fixup;
643               module_end += fixup;
644               dyn_vaddr += fixup;
645               bias += fixup;
646               if (module->name[0] != '\0')
647                 {
648                   name = basename (module->name);
649                   name_is_final = true;
650                 }
651               break;
652             }
653         }
654
655   if (r_debug_info != NULL)
656     {
657       bool skip_this_module = false;
658       for (struct r_debug_info_module *module = r_debug_info->module;
659            module != NULL; module = module->next)
660         if ((module_end > module->start && module_start < module->end)
661             || dyn_vaddr == module->l_ld)
662           {
663             if (module->elf != NULL
664                 && invalid_elf (module->elf, module->disk_file_has_build_id,
665                                 build_id, build_id_len))
666               {
667                 elf_end (module->elf);
668                 close (module->fd);
669                 module->elf = NULL;
670                 module->fd = -1;
671               }
672             if (module->elf != NULL)
673               {
674                 /* Ignore this found module if it would conflict in address
675                    space with any already existing module of DWFL.  */
676                 skip_this_module = true;
677               }
678           }
679       if (skip_this_module)
680         {
681           free (build_id);
682           return finish ();
683         }
684     }
685
686   const char *file_note_name = handle_file_note (module_start, module_end,
687                                                  ei_class, ei_data,
688                                                  note_file, note_file_size);
689   if (file_note_name)
690     {
691       name = file_note_name;
692       name_is_final = true;
693       bool invalid = false;
694       fd = open (name, O_RDONLY);
695       if (fd >= 0)
696         {
697           Dwfl_Error error = __libdw_open_file (&fd, &elf, true, false);
698           if (error == DWFL_E_NOERROR)
699             invalid = invalid_elf (elf, true /* disk_file_has_build_id */,
700                                    build_id, build_id_len);
701         }
702       if (invalid)
703         {
704           /* The file was there, but the build_id didn't match.  We
705              still want to report the module, but need to get the ELF
706              some other way if possible.  */
707           close (fd);
708           fd = -1;
709           elf_end (elf);
710           elf = NULL;
711         }
712     }
713
714   /* Our return value now says to skip the segments contained
715      within the module.  */
716   ndx = addr_segndx (dwfl, segment, module_end, true);
717
718   /* Examine its .dynamic section to get more interesting details.
719      If it has DT_SONAME, we'll use that as the module name.
720      If it has a DT_DEBUG, then it's actually a PIE rather than a DSO.
721      We need its DT_STRTAB and DT_STRSZ to decipher DT_SONAME,
722      and they also tell us the essential portion of the file
723      for fetching symbols.  */
724   GElf_Addr soname_stroff = 0;
725   GElf_Addr dynstr_vaddr = 0;
726   GElf_Xword dynstrsz = 0;
727   bool execlike = false;
728   inline bool consider_dyn (GElf_Sxword tag, GElf_Xword val)
729   {
730     switch (tag)
731       {
732       default:
733         return false;
734
735       case DT_DEBUG:
736         execlike = true;
737         break;
738
739       case DT_SONAME:
740         soname_stroff = val;
741         break;
742
743       case DT_STRTAB:
744         dynstr_vaddr = val;
745         break;
746
747       case DT_STRSZ:
748         dynstrsz = val;
749         break;
750       }
751
752     return soname_stroff != 0 && dynstr_vaddr != 0 && dynstrsz != 0;
753   }
754
755   const size_t dyn_entsize = (ei_class == ELFCLASS32
756                               ? sizeof (Elf32_Dyn) : sizeof (Elf64_Dyn));
757   void *dyn_data = NULL;
758   size_t dyn_data_size = 0;
759   if (dyn_filesz != 0 && dyn_filesz % dyn_entsize == 0
760       && ! read_portion (&dyn_data, &dyn_data_size, dyn_vaddr, dyn_filesz))
761     {
762       void *dyns = malloc (dyn_filesz);
763       Elf32_Dyn (*d32)[dyn_filesz / sizeof (Elf32_Dyn)] = dyns;
764       Elf64_Dyn (*d64)[dyn_filesz / sizeof (Elf64_Dyn)] = dyns;
765       if (unlikely (dyns == NULL))
766         return finish ();
767
768       xlatefrom.d_type = xlateto.d_type = ELF_T_DYN;
769       xlatefrom.d_buf = (void *) dyn_data;
770       xlatefrom.d_size = dyn_filesz;
771       xlateto.d_buf = dyns;
772       xlateto.d_size = dyn_filesz;
773
774       if (ei_class == ELFCLASS32)
775         {
776           if (elf32_xlatetom (&xlateto, &xlatefrom, ei_data) != NULL)
777             for (size_t i = 0; i < dyn_filesz / sizeof (Elf32_Dyn); ++i)
778               if (consider_dyn ((*d32)[i].d_tag, (*d32)[i].d_un.d_val))
779                 break;
780         }
781       else
782         {
783           if (elf64_xlatetom (&xlateto, &xlatefrom, ei_data) != NULL)
784             for (size_t i = 0; i < dyn_filesz / sizeof (Elf64_Dyn); ++i)
785               if (consider_dyn ((*d64)[i].d_tag, (*d64)[i].d_un.d_val))
786                 break;
787         }
788       free (dyns);
789     }
790   finish_portion (&dyn_data, &dyn_data_size);
791
792   /* We'll use the name passed in or a stupid default if not DT_SONAME.  */
793   if (name == NULL)
794     name = e_type == ET_EXEC ? "[exe]" : execlike ? "[pie]" : "[dso]";
795
796   void *soname = NULL;
797   size_t soname_size = 0;
798   if (! name_is_final && dynstrsz != 0 && dynstr_vaddr != 0)
799     {
800       /* We know the bounds of the .dynstr section.
801
802          The DYNSTR_VADDR pointer comes from the .dynamic section
803          (DT_STRTAB, detected above).  Ordinarily the dynamic linker
804          will have adjusted this pointer in place so it's now an
805          absolute address.  But sometimes .dynamic is read-only (in
806          vDSOs and odd architectures), and sometimes the adjustment
807          just hasn't happened yet in the memory image we looked at.
808          So treat DYNSTR_VADDR as an absolute address if it falls
809          within the module bounds, or try applying the phdr bias
810          when that adjusts it to fall within the module bounds.  */
811
812       if ((dynstr_vaddr < module_start || dynstr_vaddr >= module_end)
813           && dynstr_vaddr + bias >= module_start
814           && dynstr_vaddr + bias < module_end)
815         dynstr_vaddr += bias;
816
817       if (unlikely (dynstr_vaddr + dynstrsz > module_end))
818         dynstrsz = 0;
819
820       /* Try to get the DT_SONAME string.  */
821       if (soname_stroff != 0 && soname_stroff + 1 < dynstrsz
822           && ! read_portion (&soname, &soname_size,
823                              dynstr_vaddr + soname_stroff, 0))
824         name = soname;
825     }
826
827   /* Now that we have chosen the module's name and bounds, report it.
828      If we found a build ID, report that too.  */
829
830   Dwfl_Module *mod = INTUSE(dwfl_report_module) (dwfl, name,
831                                                  module_start, module_end);
832
833   // !execlike && ET_EXEC is PIE.
834   // execlike && !ET_EXEC is a static executable.
835   if (mod != NULL && (execlike || ehdr.e32.e_type == ET_EXEC))
836     mod->is_executable = true;
837
838   if (likely (mod != NULL) && build_id != NULL
839       && unlikely (INTUSE(dwfl_module_report_build_id) (mod,
840                                                         build_id,
841                                                         build_id_len,
842                                                         build_id_vaddr)))
843     {
844       mod->gc = true;
845       mod = NULL;
846     }
847
848   /* At this point we do not need BUILD_ID or NAME any more.
849      They have been copied.  */
850   free (build_id);
851   finish_portion (&soname, &soname_size);
852
853   if (unlikely (mod == NULL))
854     {
855       ndx = -1;
856       return finish ();
857     }
858
859   /* We have reported the module.  Now let the caller decide whether we
860      should read the whole thing in right now.  */
861
862   const GElf_Off cost = (contiguous < file_trimmed_end ? total_filesz
863                          : buffer_available >= contiguous ? 0
864                          : contiguous - buffer_available);
865   const GElf_Off worthwhile = ((dynstr_vaddr == 0 || dynstrsz == 0) ? 0
866                                : dynstr_vaddr + dynstrsz - start);
867   const GElf_Off whole = MAX (file_trimmed_end, shdrs_end);
868
869   if (elf == NULL
870       && (*read_eagerly) (MODCB_ARGS (mod), &buffer, &buffer_available,
871                           cost, worthwhile, whole, contiguous,
872                           read_eagerly_arg, &elf)
873       && elf == NULL)
874     {
875       /* The caller wants to read the whole file in right now, but hasn't
876          done it for us.  Fill in a local image of the virtual file.  */
877
878       void *contents = calloc (1, file_trimmed_end);
879       if (unlikely (contents == NULL))
880         return finish ();
881
882       inline void final_read (size_t offset, GElf_Addr vaddr, size_t size)
883       {
884         void *into = contents + offset;
885         size_t read_size = size;
886         (void) segment_read (addr_segndx (dwfl, segment, vaddr, false),
887                              &into, &read_size, vaddr, size);
888       }
889
890       if (contiguous < file_trimmed_end)
891         {
892           /* We can't use the memory image verbatim as the file image.
893              So we'll be reading into a local image of the virtual file.  */
894
895           inline void read_phdr (GElf_Word type, GElf_Addr vaddr,
896                                  GElf_Off offset, GElf_Xword filesz)
897           {
898             if (type == PT_LOAD)
899               final_read (offset, vaddr + bias, filesz);
900           }
901
902           if (ei_class == ELFCLASS32)
903             for (uint_fast16_t i = 0; i < phnum; ++i)
904               read_phdr ((*p32)[i].p_type, (*p32)[i].p_vaddr,
905                          (*p32)[i].p_offset, (*p32)[i].p_filesz);
906           else
907             for (uint_fast16_t i = 0; i < phnum; ++i)
908               read_phdr ((*p64)[i].p_type, (*p64)[i].p_vaddr,
909                          (*p64)[i].p_offset, (*p64)[i].p_filesz);
910         }
911       else
912         {
913           /* The whole file sits contiguous in memory,
914              but the caller didn't want to just do it.  */
915
916           const size_t have = MIN (buffer_available, file_trimmed_end);
917           memcpy (contents, buffer, have);
918
919           if (have < file_trimmed_end)
920             final_read (have, start + have, file_trimmed_end - have);
921         }
922
923       elf = elf_memory (contents, file_trimmed_end);
924       if (unlikely (elf == NULL))
925         free (contents);
926       else
927         elf->flags |= ELF_F_MALLOCED;
928     }
929
930   if (elf != NULL)
931     {
932       /* Install the file in the module.  */
933       mod->main.elf = elf;
934       elf = NULL;
935       fd = -1;
936       mod->main.vaddr = module_start - bias;
937       mod->main.address_sync = module_address_sync;
938       mod->main_bias = bias;
939     }
940
941   return finish ();
942 }