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