blob: 207a2573a7a466fd5cf5b99542ab8ce6912c3d44 [file] [log] [blame]
Brian Silverman86497922018-02-10 19:28:39 -05001/* 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 <endian.h>
39#include <unistd.h>
40#include <fcntl.h>
41
42#include <system.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. */
60static int
61addr_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
86static bool
87buf_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
95static bool
96buf_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
132static const char *
133handle_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
207static bool
208invalid_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
235int
236dwfl_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 /* We might have to reserve some memory for the phdrs. Set to NULL
282 here so we can always safely free it. */
283 void *phdrsp = NULL;
284
285 inline int finish (void)
286 {
287 free (phdrsp);
288 release_buffer (&buffer, &buffer_available);
289 if (elf != NULL)
290 elf_end (elf);
291 if (fd != -1)
292 close (fd);
293 return ndx;
294 }
295
296 if (segment_read (ndx, &buffer, &buffer_available,
297 start, sizeof (Elf64_Ehdr))
298 || memcmp (buffer, ELFMAG, SELFMAG) != 0)
299 return finish ();
300
301 inline bool read_portion (void **data, size_t *data_size,
302 GElf_Addr vaddr, size_t filesz)
303 {
304 if (vaddr - start + filesz > buffer_available
305 /* If we're in string mode, then don't consider the buffer we have
306 sufficient unless it contains the terminator of the string. */
307 || (filesz == 0 && memchr (vaddr - start + buffer, '\0',
308 buffer_available - (vaddr - start)) == NULL))
309 {
310 *data = NULL;
311 *data_size = filesz;
312 return segment_read (addr_segndx (dwfl, segment, vaddr, false),
313 data, data_size, vaddr, filesz);
314 }
315
316 /* We already have this whole note segment from our initial read. */
317 *data = vaddr - start + buffer;
318 *data_size = 0;
319 return false;
320 }
321
322 inline void finish_portion (void **data, size_t *data_size)
323 {
324 if (*data_size != 0)
325 release_buffer (data, data_size);
326 }
327
328 /* Extract the information we need from the file header. */
329 const unsigned char *e_ident;
330 unsigned char ei_class;
331 unsigned char ei_data;
332 uint16_t e_type;
333 union
334 {
335 Elf32_Ehdr e32;
336 Elf64_Ehdr e64;
337 } ehdr;
338 GElf_Off phoff;
339 uint_fast16_t phnum;
340 uint_fast16_t phentsize;
341 GElf_Off shdrs_end;
342 Elf_Data xlatefrom =
343 {
344 .d_type = ELF_T_EHDR,
345 .d_buf = (void *) buffer,
346 .d_version = EV_CURRENT,
347 };
348 Elf_Data xlateto =
349 {
350 .d_type = ELF_T_EHDR,
351 .d_buf = &ehdr,
352 .d_size = sizeof ehdr,
353 .d_version = EV_CURRENT,
354 };
355 e_ident = ((const unsigned char *) buffer);
356 ei_class = e_ident[EI_CLASS];
357 ei_data = e_ident[EI_DATA];
358 switch (ei_class)
359 {
360 case ELFCLASS32:
361 xlatefrom.d_size = sizeof (Elf32_Ehdr);
362 if (elf32_xlatetom (&xlateto, &xlatefrom, ei_data) == NULL)
363 return finish ();
364 e_type = ehdr.e32.e_type;
365 phoff = ehdr.e32.e_phoff;
366 phnum = ehdr.e32.e_phnum;
367 phentsize = ehdr.e32.e_phentsize;
368 if (phentsize != sizeof (Elf32_Phdr))
369 return finish ();
370 shdrs_end = ehdr.e32.e_shoff + ehdr.e32.e_shnum * ehdr.e32.e_shentsize;
371 break;
372
373 case ELFCLASS64:
374 xlatefrom.d_size = sizeof (Elf64_Ehdr);
375 if (elf64_xlatetom (&xlateto, &xlatefrom, ei_data) == NULL)
376 return finish ();
377 e_type = ehdr.e64.e_type;
378 phoff = ehdr.e64.e_phoff;
379 phnum = ehdr.e64.e_phnum;
380 phentsize = ehdr.e64.e_phentsize;
381 if (phentsize != sizeof (Elf64_Phdr))
382 return finish ();
383 shdrs_end = ehdr.e64.e_shoff + ehdr.e64.e_shnum * ehdr.e64.e_shentsize;
384 break;
385
386 default:
387 return finish ();
388 }
389
390 /* The file header tells where to find the program headers.
391 These are what we need to find the boundaries of the module.
392 Without them, we don't have a module to report. */
393
394 if (phnum == 0)
395 return finish ();
396
397 xlatefrom.d_type = xlateto.d_type = ELF_T_PHDR;
398 xlatefrom.d_size = phnum * phentsize;
399
400 void *ph_buffer = NULL;
401 size_t ph_buffer_size = 0;
402 if (read_portion (&ph_buffer, &ph_buffer_size,
403 start + phoff, xlatefrom.d_size))
404 return finish ();
405
406 xlatefrom.d_buf = ph_buffer;
407
408 bool class32 = ei_class == ELFCLASS32;
409 size_t phdr_size = class32 ? sizeof (Elf32_Phdr) : sizeof (Elf64_Phdr);
410 if (unlikely (phnum > SIZE_MAX / phdr_size))
411 return finish ();
412 const size_t phdrsp_bytes = phnum * phdr_size;
413 phdrsp = malloc (phdrsp_bytes);
414 if (unlikely (phdrsp == NULL))
415 return finish ();
416
417 xlateto.d_buf = phdrsp;
418 xlateto.d_size = phdrsp_bytes;
419
420 /* Track the bounds of the file visible in memory. */
421 GElf_Off file_trimmed_end = 0; /* Proper p_vaddr + p_filesz end. */
422 GElf_Off file_end = 0; /* Rounded up to effective page size. */
423 GElf_Off contiguous = 0; /* Visible as contiguous file from START. */
424 GElf_Off total_filesz = 0; /* Total size of data to read. */
425
426 /* Collect the bias between START and the containing PT_LOAD's p_vaddr. */
427 GElf_Addr bias = 0;
428 bool found_bias = false;
429
430 /* Collect the unbiased bounds of the module here. */
431 GElf_Addr module_start = -1l;
432 GElf_Addr module_end = 0;
433 GElf_Addr module_address_sync = 0;
434
435 /* If we see PT_DYNAMIC, record it here. */
436 GElf_Addr dyn_vaddr = 0;
437 GElf_Xword dyn_filesz = 0;
438
439 /* Collect the build ID bits here. */
440 void *build_id = NULL;
441 size_t build_id_len = 0;
442 GElf_Addr build_id_vaddr = 0;
443
444 /* Consider a PT_NOTE we've found in the image. */
445 inline void consider_notes (GElf_Addr vaddr, GElf_Xword filesz)
446 {
447 /* If we have already seen a build ID, we don't care any more. */
448 if (build_id != NULL || filesz == 0)
449 return;
450
451 void *data;
452 size_t data_size;
453 if (read_portion (&data, &data_size, vaddr, filesz))
454 return;
455
456 assert (sizeof (Elf32_Nhdr) == sizeof (Elf64_Nhdr));
457
458 void *notes;
459 if (ei_data == MY_ELFDATA)
460 notes = data;
461 else
462 {
463 notes = malloc (filesz);
464 if (unlikely (notes == NULL))
465 return;
466 xlatefrom.d_type = xlateto.d_type = ELF_T_NHDR;
467 xlatefrom.d_buf = (void *) data;
468 xlatefrom.d_size = filesz;
469 xlateto.d_buf = notes;
470 xlateto.d_size = filesz;
471 if (elf32_xlatetom (&xlateto, &xlatefrom,
472 ehdr.e32.e_ident[EI_DATA]) == NULL)
473 goto done;
474 }
475
476 const GElf_Nhdr *nh = notes;
477 while ((const void *) nh < (const void *) notes + filesz)
478 {
479 const void *note_name = nh + 1;
480 const void *note_desc = note_name + NOTE_ALIGN (nh->n_namesz);
481 if (unlikely ((size_t) ((const void *) notes + filesz
482 - note_desc) < nh->n_descsz))
483 break;
484
485 if (nh->n_type == NT_GNU_BUILD_ID
486 && nh->n_descsz > 0
487 && nh->n_namesz == sizeof "GNU"
488 && !memcmp (note_name, "GNU", sizeof "GNU"))
489 {
490 build_id_vaddr = note_desc - (const void *) notes + vaddr;
491 build_id_len = nh->n_descsz;
492 build_id = malloc (nh->n_descsz);
493 if (likely (build_id != NULL))
494 memcpy (build_id, note_desc, build_id_len);
495 break;
496 }
497
498 nh = note_desc + NOTE_ALIGN (nh->n_descsz);
499 }
500
501 done:
502 if (notes != data)
503 free (notes);
504 finish_portion (&data, &data_size);
505 }
506
507 /* Consider each of the program headers we've read from the image. */
508 inline void consider_phdr (GElf_Word type,
509 GElf_Addr vaddr, GElf_Xword memsz,
510 GElf_Off offset, GElf_Xword filesz,
511 GElf_Xword align)
512 {
513 switch (type)
514 {
515 case PT_DYNAMIC:
516 dyn_vaddr = vaddr;
517 dyn_filesz = filesz;
518 break;
519
520 case PT_NOTE:
521 /* We calculate from the p_offset of the note segment,
522 because we don't yet know the bias for its p_vaddr. */
523 consider_notes (start + offset, filesz);
524 break;
525
526 case PT_LOAD:
527 align = dwfl->segment_align > 1 ? dwfl->segment_align : align ?: 1;
528
529 GElf_Addr vaddr_end = (vaddr + memsz + align - 1) & -align;
530 GElf_Addr filesz_vaddr = filesz < memsz ? vaddr + filesz : vaddr_end;
531 GElf_Off filesz_offset = filesz_vaddr - vaddr + offset;
532
533 if (file_trimmed_end < offset + filesz)
534 {
535 file_trimmed_end = offset + filesz;
536
537 /* Trim the last segment so we don't bother with zeros
538 in the last page that are off the end of the file.
539 However, if the extra bit in that page includes the
540 section headers, keep them. */
541 if (shdrs_end <= filesz_offset && shdrs_end > file_trimmed_end)
542 {
543 filesz += shdrs_end - file_trimmed_end;
544 file_trimmed_end = shdrs_end;
545 }
546 }
547
548 total_filesz += filesz;
549
550 if (file_end < filesz_offset)
551 {
552 file_end = filesz_offset;
553 if (filesz_vaddr - start == filesz_offset)
554 contiguous = file_end;
555 }
556
557 if (!found_bias && (offset & -align) == 0
558 && likely (filesz_offset >= phoff + phnum * phentsize))
559 {
560 bias = start - vaddr;
561 found_bias = true;
562 }
563
564 if ((vaddr & -align) < module_start)
565 {
566 module_start = vaddr & -align;
567 module_address_sync = vaddr + memsz;
568 }
569
570 if (module_end < vaddr_end)
571 module_end = vaddr_end;
572 break;
573 }
574 }
575
576 Elf32_Phdr (*p32)[phnum] = phdrsp;
577 Elf64_Phdr (*p64)[phnum] = phdrsp;
578 if (ei_class == ELFCLASS32)
579 {
580 if (elf32_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 ((*p32)[i].p_type,
585 (*p32)[i].p_vaddr, (*p32)[i].p_memsz,
586 (*p32)[i].p_offset, (*p32)[i].p_filesz,
587 (*p32)[i].p_align);
588 }
589 else
590 {
591 if (elf64_xlatetom (&xlateto, &xlatefrom, ei_data) == NULL)
592 found_bias = false; /* Trigger error check. */
593 else
594 for (uint_fast16_t i = 0; i < phnum; ++i)
595 consider_phdr ((*p64)[i].p_type,
596 (*p64)[i].p_vaddr, (*p64)[i].p_memsz,
597 (*p64)[i].p_offset, (*p64)[i].p_filesz,
598 (*p64)[i].p_align);
599 }
600
601 finish_portion (&ph_buffer, &ph_buffer_size);
602
603 /* We must have seen the segment covering offset 0, or else the ELF
604 header we read at START was not produced by these program headers. */
605 if (unlikely (!found_bias))
606 {
607 free (build_id);
608 return finish ();
609 }
610
611 /* Now we know enough to report a module for sure: its bounds. */
612 module_start += bias;
613 module_end += bias;
614
615 dyn_vaddr += bias;
616
617 /* NAME found from link map has precedence over DT_SONAME possibly read
618 below. */
619 bool name_is_final = false;
620
621 /* Try to match up DYN_VADDR against L_LD as found in link map.
622 Segments sniffing may guess invalid address as the first read-only memory
623 mapping may not be dumped to the core file (if ELF headers are not dumped)
624 and the ELF header is dumped first with the read/write mapping of the same
625 file at higher addresses. */
626 if (r_debug_info != NULL)
627 for (const struct r_debug_info_module *module = r_debug_info->module;
628 module != NULL; module = module->next)
629 if (module_start <= module->l_ld && module->l_ld < module_end)
630 {
631 /* L_LD read from link map must be right while DYN_VADDR is unsafe.
632 Therefore subtract DYN_VADDR and add L_LD to get a possibly
633 corrective displacement for all addresses computed so far. */
634 GElf_Addr fixup = module->l_ld - dyn_vaddr;
635 if ((fixup & (dwfl->segment_align - 1)) == 0
636 && module_start + fixup <= module->l_ld
637 && module->l_ld < module_end + fixup)
638 {
639 module_start += fixup;
640 module_end += fixup;
641 dyn_vaddr += fixup;
642 bias += fixup;
643 if (module->name[0] != '\0')
644 {
645 name = basename (module->name);
646 name_is_final = true;
647 }
648 break;
649 }
650 }
651
652 if (r_debug_info != NULL)
653 {
654 bool skip_this_module = false;
655 for (struct r_debug_info_module *module = r_debug_info->module;
656 module != NULL; module = module->next)
657 if ((module_end > module->start && module_start < module->end)
658 || dyn_vaddr == module->l_ld)
659 {
660 if (module->elf != NULL
661 && invalid_elf (module->elf, module->disk_file_has_build_id,
662 build_id, build_id_len))
663 {
664 elf_end (module->elf);
665 close (module->fd);
666 module->elf = NULL;
667 module->fd = -1;
668 }
669 if (module->elf != NULL)
670 {
671 /* Ignore this found module if it would conflict in address
672 space with any already existing module of DWFL. */
673 skip_this_module = true;
674 }
675 }
676 if (skip_this_module)
677 {
678 free (build_id);
679 return finish ();
680 }
681 }
682
683 const char *file_note_name = handle_file_note (module_start, module_end,
684 ei_class, ei_data,
685 note_file, note_file_size);
686 if (file_note_name)
687 {
688 name = file_note_name;
689 name_is_final = true;
690 bool invalid = false;
691 fd = open (name, O_RDONLY);
692 if (fd >= 0)
693 {
694 Dwfl_Error error = __libdw_open_file (&fd, &elf, true, false);
695 if (error == DWFL_E_NOERROR)
696 invalid = invalid_elf (elf, true /* disk_file_has_build_id */,
697 build_id, build_id_len);
698 }
699 if (invalid)
700 {
701 /* The file was there, but the build_id didn't match. We
702 still want to report the module, but need to get the ELF
703 some other way if possible. */
704 close (fd);
705 fd = -1;
706 elf_end (elf);
707 elf = NULL;
708 }
709 }
710
711 /* Our return value now says to skip the segments contained
712 within the module. */
713 ndx = addr_segndx (dwfl, segment, module_end, true);
714
715 /* Examine its .dynamic section to get more interesting details.
716 If it has DT_SONAME, we'll use that as the module name.
717 If it has a DT_DEBUG, then it's actually a PIE rather than a DSO.
718 We need its DT_STRTAB and DT_STRSZ to decipher DT_SONAME,
719 and they also tell us the essential portion of the file
720 for fetching symbols. */
721 GElf_Addr soname_stroff = 0;
722 GElf_Addr dynstr_vaddr = 0;
723 GElf_Xword dynstrsz = 0;
724 bool execlike = false;
725 inline bool consider_dyn (GElf_Sxword tag, GElf_Xword val)
726 {
727 switch (tag)
728 {
729 default:
730 return false;
731
732 case DT_DEBUG:
733 execlike = true;
734 break;
735
736 case DT_SONAME:
737 soname_stroff = val;
738 break;
739
740 case DT_STRTAB:
741 dynstr_vaddr = val;
742 break;
743
744 case DT_STRSZ:
745 dynstrsz = val;
746 break;
747 }
748
749 return soname_stroff != 0 && dynstr_vaddr != 0 && dynstrsz != 0;
750 }
751
752 const size_t dyn_entsize = (ei_class == ELFCLASS32
753 ? sizeof (Elf32_Dyn) : sizeof (Elf64_Dyn));
754 void *dyn_data = NULL;
755 size_t dyn_data_size = 0;
756 if (dyn_filesz != 0 && dyn_filesz % dyn_entsize == 0
757 && ! read_portion (&dyn_data, &dyn_data_size, dyn_vaddr, dyn_filesz))
758 {
759 void *dyns = malloc (dyn_filesz);
760 Elf32_Dyn (*d32)[dyn_filesz / sizeof (Elf32_Dyn)] = dyns;
761 Elf64_Dyn (*d64)[dyn_filesz / sizeof (Elf64_Dyn)] = dyns;
762 if (unlikely (dyns == NULL))
763 return finish ();
764
765 xlatefrom.d_type = xlateto.d_type = ELF_T_DYN;
766 xlatefrom.d_buf = (void *) dyn_data;
767 xlatefrom.d_size = dyn_filesz;
768 xlateto.d_buf = dyns;
769 xlateto.d_size = dyn_filesz;
770
771 if (ei_class == ELFCLASS32)
772 {
773 if (elf32_xlatetom (&xlateto, &xlatefrom, ei_data) != NULL)
774 for (size_t i = 0; i < dyn_filesz / sizeof (Elf32_Dyn); ++i)
775 if (consider_dyn ((*d32)[i].d_tag, (*d32)[i].d_un.d_val))
776 break;
777 }
778 else
779 {
780 if (elf64_xlatetom (&xlateto, &xlatefrom, ei_data) != NULL)
781 for (size_t i = 0; i < dyn_filesz / sizeof (Elf64_Dyn); ++i)
782 if (consider_dyn ((*d64)[i].d_tag, (*d64)[i].d_un.d_val))
783 break;
784 }
785 free (dyns);
786 }
787 finish_portion (&dyn_data, &dyn_data_size);
788
789 /* We'll use the name passed in or a stupid default if not DT_SONAME. */
790 if (name == NULL)
791 name = e_type == ET_EXEC ? "[exe]" : execlike ? "[pie]" : "[dso]";
792
793 void *soname = NULL;
794 size_t soname_size = 0;
795 if (! name_is_final && dynstrsz != 0 && dynstr_vaddr != 0)
796 {
797 /* We know the bounds of the .dynstr section.
798
799 The DYNSTR_VADDR pointer comes from the .dynamic section
800 (DT_STRTAB, detected above). Ordinarily the dynamic linker
801 will have adjusted this pointer in place so it's now an
802 absolute address. But sometimes .dynamic is read-only (in
803 vDSOs and odd architectures), and sometimes the adjustment
804 just hasn't happened yet in the memory image we looked at.
805 So treat DYNSTR_VADDR as an absolute address if it falls
806 within the module bounds, or try applying the phdr bias
807 when that adjusts it to fall within the module bounds. */
808
809 if ((dynstr_vaddr < module_start || dynstr_vaddr >= module_end)
810 && dynstr_vaddr + bias >= module_start
811 && dynstr_vaddr + bias < module_end)
812 dynstr_vaddr += bias;
813
814 if (unlikely (dynstr_vaddr + dynstrsz > module_end))
815 dynstrsz = 0;
816
817 /* Try to get the DT_SONAME string. */
818 if (soname_stroff != 0 && soname_stroff + 1 < dynstrsz
819 && ! read_portion (&soname, &soname_size,
820 dynstr_vaddr + soname_stroff, 0))
821 name = soname;
822 }
823
824 /* Now that we have chosen the module's name and bounds, report it.
825 If we found a build ID, report that too. */
826
827 Dwfl_Module *mod = INTUSE(dwfl_report_module) (dwfl, name,
828 module_start, module_end);
829
830 // !execlike && ET_EXEC is PIE.
831 // execlike && !ET_EXEC is a static executable.
832 if (mod != NULL && (execlike || ehdr.e32.e_type == ET_EXEC))
833 mod->is_executable = true;
834
835 if (likely (mod != NULL) && build_id != NULL
836 && unlikely (INTUSE(dwfl_module_report_build_id) (mod,
837 build_id,
838 build_id_len,
839 build_id_vaddr)))
840 {
841 mod->gc = true;
842 mod = NULL;
843 }
844
845 /* At this point we do not need BUILD_ID or NAME any more.
846 They have been copied. */
847 free (build_id);
848 finish_portion (&soname, &soname_size);
849
850 if (unlikely (mod == NULL))
851 {
852 ndx = -1;
853 return finish ();
854 }
855
856 /* We have reported the module. Now let the caller decide whether we
857 should read the whole thing in right now. */
858
859 const GElf_Off cost = (contiguous < file_trimmed_end ? total_filesz
860 : buffer_available >= contiguous ? 0
861 : contiguous - buffer_available);
862 const GElf_Off worthwhile = ((dynstr_vaddr == 0 || dynstrsz == 0) ? 0
863 : dynstr_vaddr + dynstrsz - start);
864 const GElf_Off whole = MAX (file_trimmed_end, shdrs_end);
865
866 if (elf == NULL
867 && (*read_eagerly) (MODCB_ARGS (mod), &buffer, &buffer_available,
868 cost, worthwhile, whole, contiguous,
869 read_eagerly_arg, &elf)
870 && elf == NULL)
871 {
872 /* The caller wants to read the whole file in right now, but hasn't
873 done it for us. Fill in a local image of the virtual file. */
874
875 void *contents = calloc (1, file_trimmed_end);
876 if (unlikely (contents == NULL))
877 return finish ();
878
879 inline void final_read (size_t offset, GElf_Addr vaddr, size_t size)
880 {
881 void *into = contents + offset;
882 size_t read_size = size;
883 (void) segment_read (addr_segndx (dwfl, segment, vaddr, false),
884 &into, &read_size, vaddr, size);
885 }
886
887 if (contiguous < file_trimmed_end)
888 {
889 /* We can't use the memory image verbatim as the file image.
890 So we'll be reading into a local image of the virtual file. */
891
892 inline void read_phdr (GElf_Word type, GElf_Addr vaddr,
893 GElf_Off offset, GElf_Xword filesz)
894 {
895 if (type == PT_LOAD)
896 final_read (offset, vaddr + bias, filesz);
897 }
898
899 if (ei_class == ELFCLASS32)
900 for (uint_fast16_t i = 0; i < phnum; ++i)
901 read_phdr ((*p32)[i].p_type, (*p32)[i].p_vaddr,
902 (*p32)[i].p_offset, (*p32)[i].p_filesz);
903 else
904 for (uint_fast16_t i = 0; i < phnum; ++i)
905 read_phdr ((*p64)[i].p_type, (*p64)[i].p_vaddr,
906 (*p64)[i].p_offset, (*p64)[i].p_filesz);
907 }
908 else
909 {
910 /* The whole file sits contiguous in memory,
911 but the caller didn't want to just do it. */
912
913 const size_t have = MIN (buffer_available, file_trimmed_end);
914 memcpy (contents, buffer, have);
915
916 if (have < file_trimmed_end)
917 final_read (have, start + have, file_trimmed_end - have);
918 }
919
920 elf = elf_memory (contents, file_trimmed_end);
921 if (unlikely (elf == NULL))
922 free (contents);
923 else
924 elf->flags |= ELF_F_MALLOCED;
925 }
926
927 if (elf != NULL)
928 {
929 /* Install the file in the module. */
930 mod->main.elf = elf;
931 elf = NULL;
932 fd = -1;
933 mod->main.vaddr = module_start - bias;
934 mod->main.address_sync = module_address_sync;
935 mod->main_bias = bias;
936 }
937
938 return finish ();
939}