Branch data Line data Source code
1 : : /* Report modules by examining dynamic linker data structures.
2 : : Copyright (C) 2008-2016 Red Hat, Inc.
3 : : Copyright (C) 2021 Mark J. Wielaard <mark@klomp.org>
4 : : This file is part of elfutils.
5 : :
6 : : This file is free software; you can redistribute it and/or modify
7 : : it under the terms of either
8 : :
9 : : * the GNU Lesser General Public License as published by the Free
10 : : Software Foundation; either version 3 of the License, or (at
11 : : your option) any later version
12 : :
13 : : or
14 : :
15 : : * the GNU General Public License as published by the Free
16 : : Software Foundation; either version 2 of the License, or (at
17 : : your option) any later version
18 : :
19 : : or both in parallel, as here.
20 : :
21 : : elfutils is distributed in the hope that it will be useful, but
22 : : WITHOUT ANY WARRANTY; without even the implied warranty of
23 : : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
24 : : General Public License for more details.
25 : :
26 : : You should have received copies of the GNU General Public License and
27 : : the GNU Lesser General Public License along with this program. If
28 : : not, see <http://www.gnu.org/licenses/>. */
29 : :
30 : : #include <config.h>
31 : : #include "libdwflP.h"
32 : : #include "memory-access.h"
33 : : #include "system.h"
34 : :
35 : : #include <fcntl.h>
36 : :
37 : : /* This element is always provided and always has a constant value.
38 : : This makes it an easy thing to scan for to discern the format. */
39 : : #define PROBE_TYPE AT_PHENT
40 : : #define PROBE_VAL32 sizeof (Elf32_Phdr)
41 : : #define PROBE_VAL64 sizeof (Elf64_Phdr)
42 : :
43 : :
44 : : static inline bool
45 : 464 : do_check64 (const char *a64, uint_fast8_t *elfdata)
46 : : {
47 : : /* The AUXV pointer might not even be naturally aligned for 64-bit
48 : : data, because note payloads in a core file are not aligned. */
49 : 464 : const char *typep = a64 + offsetof (Elf64_auxv_t, a_type);
50 : 464 : uint64_t type = read_8ubyte_unaligned_noncvt (typep);
51 : 464 : const char *valp = a64 + offsetof (Elf64_auxv_t, a_un.a_val);
52 : 464 : uint64_t val = read_8ubyte_unaligned_noncvt (valp);
53 : :
54 [ + + ]: 464 : if (type == BE64 (PROBE_TYPE)
55 [ + - ]: 8 : && val == BE64 (PROBE_VAL64))
56 : : {
57 : 8 : *elfdata = ELFDATA2MSB;
58 : 8 : return true;
59 : : }
60 : :
61 : 456 : if (type == LE64 (PROBE_TYPE)
62 [ + + ]: 456 : && val == LE64 (PROBE_VAL64))
63 : : {
64 : 54 : *elfdata = ELFDATA2LSB;
65 : 54 : return true;
66 : : }
67 : :
68 : : return false;
69 : : }
70 : :
71 : : static inline bool
72 : 794 : do_check32 (const char *a32, uint_fast8_t *elfdata)
73 : : {
74 : : /* The AUXV pointer might not even be naturally aligned for 32-bit
75 : : data, because note payloads in a core file are not aligned. */
76 : 794 : const char *typep = a32 + offsetof (Elf32_auxv_t, a_type);
77 : 794 : uint32_t type = read_4ubyte_unaligned_noncvt (typep);
78 : 794 : const char *valp = a32 + offsetof (Elf32_auxv_t, a_un.a_val);
79 : 794 : uint32_t val = read_4ubyte_unaligned_noncvt (valp);
80 : :
81 [ + + ]: 794 : if (type == BE32 (PROBE_TYPE)
82 [ + - ]: 6 : && val == BE32 (PROBE_VAL32))
83 : : {
84 : 6 : *elfdata = ELFDATA2MSB;
85 : 6 : return true;
86 : : }
87 : :
88 : 788 : if (type == LE32 (PROBE_TYPE)
89 [ + + ]: 788 : && val == LE32 (PROBE_VAL32))
90 : : {
91 : 8 : *elfdata = ELFDATA2LSB;
92 : 8 : return true;
93 : : }
94 : :
95 : : return false;
96 : : }
97 : :
98 : : /* Examine an auxv data block and determine its format.
99 : : Return true iff we figured it out. */
100 : : static bool
101 : 76 : auxv_format_probe (const void *auxv, size_t size,
102 : : uint_fast8_t *elfclass, uint_fast8_t *elfdata)
103 : : {
104 [ + - ]: 464 : for (size_t i = 0; i < size / sizeof (Elf64_auxv_t); ++i)
105 : : {
106 [ + + ]: 464 : if (do_check64 (auxv + i * sizeof (Elf64_auxv_t), elfdata))
107 : : {
108 : 62 : *elfclass = ELFCLASS64;
109 : 62 : return true;
110 : : }
111 : :
112 [ + + ]: 402 : if (do_check32 (auxv + (i * 2) * sizeof (Elf32_auxv_t), elfdata)
113 [ + + ]: 392 : || do_check32 (auxv + (i * 2 + 1) * sizeof (Elf32_auxv_t), elfdata))
114 : : {
115 : 14 : *elfclass = ELFCLASS32;
116 : 14 : return true;
117 : : }
118 : : }
119 : :
120 : : return false;
121 : : }
122 : :
123 : : /* This is a Dwfl_Memory_Callback that wraps another memory callback.
124 : : If the underlying callback cannot fill the data, then this will
125 : : fall back to fetching data from module files. */
126 : :
127 : : struct integrated_memory_callback
128 : : {
129 : : Dwfl_Memory_Callback *memory_callback;
130 : : void *memory_callback_arg;
131 : : void *buffer;
132 : : };
133 : :
134 : : static bool
135 : 1136 : integrated_memory_callback (Dwfl *dwfl, int ndx,
136 : : void **buffer, size_t *buffer_available,
137 : : GElf_Addr vaddr,
138 : : size_t minread,
139 : : void *arg)
140 : : {
141 : 1136 : struct integrated_memory_callback *info = arg;
142 : :
143 [ + + ]: 1136 : if (ndx == -1)
144 : : {
145 : : /* Called for cleanup. */
146 [ + + ]: 538 : if (info->buffer != NULL)
147 : : {
148 : : /* The last probe buffer came from the underlying callback.
149 : : Let it do its cleanup. */
150 [ - + ]: 506 : assert (*buffer == info->buffer); /* XXX */
151 : 506 : *buffer = info->buffer;
152 : 506 : info->buffer = NULL;
153 : 506 : return (*info->memory_callback) (dwfl, ndx, buffer, buffer_available,
154 : : vaddr, minread,
155 : : info->memory_callback_arg);
156 : : }
157 : 32 : *buffer = NULL;
158 : 32 : *buffer_available = 0;
159 : 32 : return false;
160 : : }
161 : :
162 [ - + ]: 598 : if (*buffer != NULL)
163 : : /* For a final-read request, we only use the underlying callback. */
164 : 0 : return (*info->memory_callback) (dwfl, ndx, buffer, buffer_available,
165 : : vaddr, minread, info->memory_callback_arg);
166 : :
167 : : /* Let the underlying callback try to fill this request. */
168 [ + + ]: 598 : if ((*info->memory_callback) (dwfl, ndx, &info->buffer, buffer_available,
169 : : vaddr, minread, info->memory_callback_arg))
170 : : {
171 : 506 : *buffer = info->buffer;
172 : 506 : return true;
173 : : }
174 : :
175 : : /* Now look for module text covering this address. */
176 : :
177 : 92 : Dwfl_Module *mod;
178 : 92 : (void) INTUSE(dwfl_addrsegment) (dwfl, vaddr, &mod);
179 [ + - ]: 92 : if (mod == NULL)
180 : : return false;
181 : :
182 : 0 : Dwarf_Addr bias;
183 : 0 : Elf_Scn *scn = INTUSE(dwfl_module_address_section) (mod, &vaddr, &bias);
184 [ # # ]: 0 : if (unlikely (scn == NULL))
185 : : {
186 : : #if 0 // XXX would have to handle ndx=-1 cleanup calls passed down.
187 : : /* If we have no sections we can try to fill it from the module file
188 : : based on its phdr mappings. */
189 : : if (likely (mod->e_type != ET_REL) && mod->main.elf != NULL)
190 : : return INTUSE(dwfl_elf_phdr_memory_callback)
191 : : (dwfl, 0, buffer, buffer_available,
192 : : vaddr - mod->main.bias, minread, mod->main.elf);
193 : : #endif
194 : : return false;
195 : : }
196 : :
197 : 0 : Elf_Data *data = elf_rawdata (scn, NULL);
198 [ # # ]: 0 : if (unlikely (data == NULL))
199 : : // XXX throw error?
200 : : return false;
201 : :
202 [ # # ]: 0 : if (unlikely (data->d_size < vaddr))
203 : : return false;
204 : :
205 : : /* Provide as much data as we have. */
206 : 0 : void *contents = data->d_buf + vaddr;
207 : 0 : size_t avail = data->d_size - vaddr;
208 [ # # ]: 0 : if (unlikely (avail < minread))
209 : : return false;
210 : :
211 : : /* If probing for a string, make sure it's terminated. */
212 [ # # # # ]: 0 : if (minread == 0 && unlikely (memchr (contents, '\0', avail) == NULL))
213 : : return false;
214 : :
215 : : /* We have it! */
216 : 0 : *buffer = contents;
217 : 0 : *buffer_available = avail;
218 : 0 : return true;
219 : : }
220 : :
221 : : static size_t
222 : 382 : addrsize (uint_fast8_t elfclass)
223 : : {
224 : 382 : return elfclass * 4;
225 : : }
226 : :
227 : : struct memory_closure
228 : : {
229 : : Dwfl *dwfl;
230 : : Dwfl_Memory_Callback *callback;
231 : : void *arg;
232 : : };
233 : :
234 : : static inline int
235 : 716 : release_buffer (struct memory_closure *closure,
236 : : void **buffer, size_t *buffer_available, int result)
237 : : {
238 [ + + ]: 716 : if (*buffer != NULL)
239 : 506 : (*closure->callback) (closure->dwfl, -1, buffer, buffer_available, 0, 0,
240 : : closure->arg);
241 : :
242 : 716 : return result;
243 : : }
244 : :
245 : : static inline bool
246 : 332 : read_addrs (struct memory_closure *closure,
247 : : uint_fast8_t elfclass, uint_fast8_t elfdata,
248 : : void **buffer, size_t *buffer_available,
249 : : GElf_Addr vaddr, GElf_Addr *read_vaddr,
250 : : size_t n, GElf_Addr *addrs /* [4] */)
251 : : {
252 : 332 : size_t nb = n * addrsize (elfclass); /* Address words -> bytes to read. */
253 : 332 : Dwfl *dwfl = closure->dwfl;
254 : :
255 : : /* Read a new buffer if the old one doesn't cover these words. */
256 [ + + ]: 332 : if (*buffer == NULL
257 [ + + ]: 192 : || vaddr < *read_vaddr
258 [ + + ]: 104 : || nb > *buffer_available
259 [ + + ]: 56 : || vaddr - (*read_vaddr) > *buffer_available - nb)
260 : : {
261 : 286 : release_buffer (closure, buffer, buffer_available, 0);
262 : :
263 : 286 : *read_vaddr = vaddr;
264 : 286 : int segndx = INTUSE(dwfl_addrsegment) (dwfl, vaddr, NULL);
265 [ + - ]: 286 : if (unlikely (segndx < 0)
266 [ - + ]: 286 : || unlikely (! (*closure->callback) (dwfl, segndx,
267 : : buffer, buffer_available,
268 : : vaddr, nb, closure->arg)))
269 : 0 : return true;
270 : : }
271 : :
272 : 332 : unsigned char *addr = vaddr - (*read_vaddr) + (*buffer);
273 : :
274 [ + + ]: 332 : if (elfclass == ELFCLASS32)
275 : : {
276 [ + + ]: 28 : if (elfdata == ELFDATA2MSB)
277 [ + + ]: 64 : for (size_t i = 0; i < n; ++i)
278 : 50 : addrs[i] = BE32 (read_4ubyte_unaligned_noncvt (addr + i * 4));
279 : : else
280 [ + + ]: 64 : for (size_t i = 0; i < n; ++i)
281 : 50 : addrs[i] = LE32 (read_4ubyte_unaligned_noncvt (addr + i * 4));
282 : : }
283 : : else
284 : : {
285 [ + + ]: 304 : if (elfdata == ELFDATA2MSB)
286 [ + + ]: 48 : for (size_t i = 0; i < n; ++i)
287 : 36 : addrs[i] = BE64 (read_8ubyte_unaligned_noncvt (addr + i * 8));
288 : : else
289 [ + + ]: 1334 : for (size_t i = 0; i < n; ++i)
290 : 1042 : addrs[i] = LE64 (read_8ubyte_unaligned_noncvt (addr + i * 8));
291 : : }
292 : :
293 : : return false;
294 : : }
295 : :
296 : : /* Report a module for each struct link_map in the linked list at r_map
297 : : in the struct r_debug at R_DEBUG_VADDR. For r_debug_info description
298 : : see dwfl_link_map_report in libdwflP.h. If R_DEBUG_INFO is not NULL then no
299 : : modules get added to DWFL, caller has to add them from filled in
300 : : R_DEBUG_INFO.
301 : :
302 : : For each link_map entry, if an existing module resides at its address,
303 : : this just modifies that module's name and suggested file name. If
304 : : no such module exists, this calls dwfl_report_elf on the l_name string.
305 : :
306 : : Returns the number of modules found, or -1 for errors. */
307 : :
308 : : static int
309 : 50 : report_r_debug (uint_fast8_t elfclass, uint_fast8_t elfdata,
310 : : Dwfl *dwfl, GElf_Addr r_debug_vaddr,
311 : : Dwfl_Memory_Callback *memory_callback,
312 : : void *memory_callback_arg,
313 : : struct r_debug_info *r_debug_info)
314 : : {
315 : : /* Skip r_version, to aligned r_map field. */
316 : 50 : GElf_Addr read_vaddr = r_debug_vaddr + addrsize (elfclass);
317 : :
318 : 50 : void *buffer = NULL;
319 : 50 : size_t buffer_available = 0;
320 : 50 : GElf_Addr addrs[4];
321 : 50 : struct memory_closure memory_closure = { dwfl, memory_callback,
322 : : memory_callback_arg };
323 [ - + ]: 50 : if (unlikely (read_addrs (&memory_closure, elfclass, elfdata,
324 : : &buffer, &buffer_available, read_vaddr, &read_vaddr,
325 : : 1, addrs)))
326 : 0 : return release_buffer (&memory_closure, &buffer, &buffer_available, -1);
327 : :
328 : 50 : GElf_Addr next = addrs[0];
329 : :
330 : 50 : Dwfl_Module **lastmodp = &dwfl->modulelist;
331 : 50 : int result = 0;
332 : :
333 : : /* There can't be more elements in the link_map list than there are
334 : : segments. A segment is created for each PT_LOAD and there can be
335 : : up to 5 per module (-z separate-code, tends to create four LOAD
336 : : segments, gold has -z text-unlikely-segment, which might result
337 : : in creating that number of load segments) DWFL->lookup_elts is
338 : : probably twice the number of modules, so that multiplied by max
339 : : PT_LOADs is certainly above the upper bound. If we iterate too
340 : : many times, there must be a loop in the pointers due to link_map
341 : : clobberation. */
342 : : #define MAX_PT_LOAD 5
343 : 50 : size_t iterations = 0;
344 [ + + + - ]: 332 : while (next != 0 && ++iterations < dwfl->lookup_elts * MAX_PT_LOAD)
345 : : {
346 [ - + ]: 282 : if (read_addrs (&memory_closure, elfclass, elfdata,
347 : : &buffer, &buffer_available, next, &read_vaddr,
348 : : 4, addrs))
349 : 0 : return release_buffer (&memory_closure, &buffer, &buffer_available, -1);
350 : :
351 : : /* Unused: l_addr is the difference between the address in memory
352 : : and the ELF file when the core was created. We need to
353 : : recalculate the difference below because the ELF file we use
354 : : might be differently pre-linked. */
355 : : // GElf_Addr l_addr = addrs[0];
356 : 282 : GElf_Addr l_name = addrs[1];
357 : 282 : GElf_Addr l_ld = addrs[2];
358 : 282 : next = addrs[3];
359 : :
360 : : /* If a clobbered or truncated memory image has no useful pointer,
361 : : just skip this element. */
362 [ + + ]: 282 : if (l_ld == 0)
363 : 2 : continue;
364 : :
365 : : /* Fetch the string at the l_name address. */
366 : 280 : const char *name = NULL;
367 [ + - ]: 280 : if (buffer != NULL
368 [ + + ]: 280 : && read_vaddr <= l_name
369 [ + + ]: 36 : && l_name + 1 - read_vaddr < buffer_available
370 : 4 : && memchr (l_name - read_vaddr + buffer, '\0',
371 [ - + ]: 4 : buffer_available - (l_name - read_vaddr)) != NULL)
372 : : name = l_name - read_vaddr + buffer;
373 : : else
374 : : {
375 : 276 : release_buffer (&memory_closure, &buffer, &buffer_available, 0);
376 : 276 : read_vaddr = l_name;
377 : 276 : int segndx = INTUSE(dwfl_addrsegment) (dwfl, l_name, NULL);
378 [ + - ]: 276 : if (likely (segndx >= 0)
379 [ + + ]: 276 : && (*memory_callback) (dwfl, segndx,
380 : : &buffer, &buffer_available,
381 : : l_name, 0, memory_callback_arg))
382 : 184 : name = buffer;
383 : : }
384 : :
385 [ - + + + ]: 188 : if (name != NULL && name[0] == '\0')
386 : 94 : name = NULL;
387 : :
388 [ + + ]: 280 : if (iterations == 1
389 [ + + ]: 46 : && dwfl->user_core != NULL
390 [ - + ]: 36 : && dwfl->user_core->executable_for_core != NULL)
391 : 280 : name = dwfl->user_core->executable_for_core;
392 : :
393 : 280 : struct r_debug_info_module *r_debug_info_module = NULL;
394 [ + - ]: 280 : if (r_debug_info != NULL)
395 : : {
396 : : /* Save link map information about valid shared library (or
397 : : executable) which has not been found on disk. */
398 [ + + ]: 280 : const char *name1 = name == NULL ? "" : name;
399 : 280 : r_debug_info_module = malloc (sizeof (*r_debug_info_module)
400 : 280 : + strlen (name1) + 1);
401 [ - + ]: 280 : if (unlikely (r_debug_info_module == NULL))
402 : 0 : release_buffer (&memory_closure, &buffer,
403 : : &buffer_available, result);
404 : 280 : r_debug_info_module->fd = -1;
405 : 280 : r_debug_info_module->elf = NULL;
406 : 280 : r_debug_info_module->l_ld = l_ld;
407 : 280 : r_debug_info_module->start = 0;
408 : 280 : r_debug_info_module->end = 0;
409 : 280 : r_debug_info_module->disk_file_has_build_id = false;
410 : 280 : strcpy (r_debug_info_module->name, name1);
411 : 280 : r_debug_info_module->next = r_debug_info->module;
412 : 280 : r_debug_info->module = r_debug_info_module;
413 : : }
414 : :
415 : 280 : Dwfl_Module *mod = NULL;
416 [ + + ]: 280 : if (name != NULL)
417 : : {
418 : : /* This code is mostly inlined dwfl_report_elf. */
419 : 222 : char *sysroot_name = NULL;
420 : 222 : const char *sysroot = dwfl->sysroot;
421 : :
422 : : /* Don't use the sysroot if the path is already inside it. */
423 [ + + + - ]: 222 : bool name_in_sysroot = sysroot && startswith (name, sysroot);
424 : :
425 [ + + ]: 222 : if (sysroot && !name_in_sysroot)
426 : : {
427 [ - + ]: 8 : if (asprintf (&sysroot_name, "%s%s", sysroot, name) < 0)
428 : 0 : return release_buffer (&memory_closure, &buffer, &buffer_available, -1);
429 : :
430 : 8 : name = sysroot_name;
431 : : }
432 : :
433 : 222 : int fd = open (name, O_RDONLY);
434 [ + + ]: 222 : if (fd >= 0)
435 : : {
436 : 74 : Elf *elf;
437 : 74 : Dwfl_Error error = __libdw_open_file (&fd, &elf, true, false);
438 : 74 : GElf_Addr elf_dynamic_vaddr;
439 [ - + ]: 74 : if (error == DWFL_E_NOERROR
440 [ - + ]: 74 : && __libdwfl_dynamic_vaddr_get (elf, &elf_dynamic_vaddr))
441 : : {
442 : 74 : const void *build_id_bits;
443 : 74 : GElf_Addr build_id_elfaddr;
444 : 74 : int build_id_len;
445 : 74 : bool valid = true;
446 : :
447 [ + + ]: 74 : if (__libdwfl_find_elf_build_id (NULL, elf, &build_id_bits,
448 : : &build_id_elfaddr,
449 : : &build_id_len) > 0
450 [ + - ]: 68 : && build_id_elfaddr != 0)
451 : : {
452 [ + - ]: 68 : if (r_debug_info_module != NULL)
453 : 68 : r_debug_info_module->disk_file_has_build_id = true;
454 : 68 : GElf_Addr build_id_vaddr = (build_id_elfaddr
455 : 68 : - elf_dynamic_vaddr + l_ld);
456 : :
457 : 68 : release_buffer (&memory_closure, &buffer,
458 : : &buffer_available, 0);
459 : 68 : int segndx = INTUSE(dwfl_addrsegment) (dwfl,
460 : : build_id_vaddr,
461 : : NULL);
462 [ + + ]: 68 : if (! (*memory_callback) (dwfl, segndx,
463 : : &buffer, &buffer_available,
464 : : build_id_vaddr, build_id_len,
465 : : memory_callback_arg))
466 : : {
467 : : /* File has valid build-id which cannot be read from
468 : : memory. This happens for core files without bit 4
469 : : (0x10) set in Linux /proc/PID/coredump_filter. */
470 : : }
471 : : else
472 : : {
473 [ - + ]: 36 : if (memcmp (build_id_bits, buffer, build_id_len) != 0)
474 : : /* File has valid build-id which does not match
475 : : the one in memory. */
476 : 0 : valid = false;
477 : 36 : release_buffer (&memory_closure, &buffer,
478 : : &buffer_available, 0);
479 : :
480 : : }
481 : : }
482 : :
483 [ - + ]: 36 : if (valid)
484 : : {
485 : : // It is like l_addr but it handles differently prelinked
486 : : // files at core dumping vs. core loading time.
487 : 74 : GElf_Addr base = l_ld - elf_dynamic_vaddr;
488 [ - + ]: 74 : if (r_debug_info_module == NULL)
489 : : {
490 : : // XXX hook for sysroot
491 : 0 : mod = __libdwfl_report_elf (dwfl, xbasename (name),
492 : : name, fd, elf, base,
493 : : true, true);
494 [ # # ]: 0 : if (mod != NULL)
495 : : {
496 : 0 : elf = NULL;
497 : 0 : fd = -1;
498 : : }
499 : : }
500 [ - + ]: 74 : else if (__libdwfl_elf_address_range (elf, base, true,
501 : : true, NULL, NULL,
502 : : &r_debug_info_module->start,
503 : : &r_debug_info_module->end,
504 : : NULL, NULL))
505 : : {
506 : 74 : r_debug_info_module->elf = elf;
507 : 74 : r_debug_info_module->fd = fd;
508 : 74 : elf = NULL;
509 : 74 : fd = -1;
510 : : }
511 : : }
512 [ - + ]: 74 : if (elf != NULL)
513 : 0 : elf_end (elf);
514 [ - + ]: 74 : if (fd != -1)
515 : 0 : close (fd);
516 : : }
517 : : }
518 : 222 : free(sysroot_name);
519 : : }
520 : :
521 [ + - ]: 280 : if (mod != NULL)
522 : : {
523 : 0 : ++result;
524 : :
525 : : /* Move this module to the end of the list, so that we end
526 : : up with a list in the same order as the link_map chain. */
527 [ # # ]: 0 : if (mod->next != NULL)
528 : : {
529 [ # # ]: 0 : if (*lastmodp != mod)
530 : : {
531 : : lastmodp = &dwfl->modulelist;
532 [ # # ]: 0 : while (*lastmodp != mod)
533 : 0 : lastmodp = &(*lastmodp)->next;
534 : : }
535 : 0 : *lastmodp = mod->next;
536 : 0 : mod->next = NULL;
537 [ # # ]: 0 : while (*lastmodp != NULL)
538 : 0 : lastmodp = &(*lastmodp)->next;
539 : 0 : *lastmodp = mod;
540 : : }
541 : :
542 : 0 : lastmodp = &mod->next;
543 : : }
544 : : }
545 : :
546 : 50 : return release_buffer (&memory_closure, &buffer, &buffer_available, result);
547 : : }
548 : :
549 : : static GElf_Addr
550 : 0 : consider_executable (Dwfl_Module *mod, GElf_Addr at_phdr, GElf_Addr at_entry,
551 : : uint_fast8_t *elfclass, uint_fast8_t *elfdata,
552 : : Dwfl_Memory_Callback *memory_callback,
553 : : void *memory_callback_arg)
554 : : {
555 : 0 : GElf_Ehdr ehdr;
556 [ # # ]: 0 : if (unlikely (gelf_getehdr (mod->main.elf, &ehdr) == NULL))
557 : : return 0;
558 : :
559 [ # # ]: 0 : if (at_entry != 0)
560 : : {
561 : : /* If we have an AT_ENTRY value, reject this executable if
562 : : its entry point address could not have supplied that. */
563 : :
564 [ # # ]: 0 : if (ehdr.e_entry == 0)
565 : : return 0;
566 : :
567 [ # # ]: 0 : if (mod->e_type == ET_EXEC)
568 : : {
569 [ # # ]: 0 : if (ehdr.e_entry != at_entry)
570 : : return 0;
571 : : }
572 : : else
573 : : {
574 : : /* It could be a PIE. */
575 : 0 : }
576 : : }
577 : :
578 : : // XXX this could be saved in the file cache: phdr vaddr, DT_DEBUG d_val vaddr
579 : : /* Find the vaddr of the DT_DEBUG's d_ptr. This is the memory
580 : : address where &r_debug was written at runtime. */
581 : 0 : GElf_Xword align = mod->dwfl->segment_align;
582 : 0 : GElf_Addr d_val_vaddr = 0;
583 : 0 : size_t phnum;
584 [ # # ]: 0 : if (elf_getphdrnum (mod->main.elf, &phnum) != 0)
585 : : return 0;
586 : :
587 [ # # ]: 0 : for (size_t i = 0; i < phnum; ++i)
588 : : {
589 : 0 : GElf_Phdr phdr_mem;
590 : 0 : GElf_Phdr *phdr = gelf_getphdr (mod->main.elf, i, &phdr_mem);
591 [ # # ]: 0 : if (phdr == NULL)
592 : : break;
593 : :
594 [ # # # # ]: 0 : if (phdr->p_align > 1 && (align == 0 || phdr->p_align < align))
595 : 0 : align = phdr->p_align;
596 : :
597 [ # # ]: 0 : if (at_phdr != 0
598 [ # # ]: 0 : && phdr->p_type == PT_LOAD
599 [ # # ]: 0 : && (phdr->p_offset & -align) == (ehdr.e_phoff & -align))
600 : : {
601 : : /* This is the segment that would map the phdrs.
602 : : If we have an AT_PHDR value, reject this executable
603 : : if its phdr mapping could not have supplied that. */
604 [ # # ]: 0 : if (mod->e_type == ET_EXEC)
605 : : {
606 [ # # ]: 0 : if (ehdr.e_phoff - phdr->p_offset + phdr->p_vaddr != at_phdr)
607 : 0 : return 0;
608 : : }
609 : : else
610 : : {
611 : : /* It could be a PIE. If the AT_PHDR value and our
612 : : phdr address don't match modulo ALIGN, then this
613 : : could not have been the right PIE. */
614 : 0 : if (((ehdr.e_phoff - phdr->p_offset + phdr->p_vaddr) & -align)
615 [ # # ]: 0 : != (at_phdr & -align))
616 : : return 0;
617 : :
618 : : /* Calculate the bias applied to the PIE's p_vaddr values. */
619 : 0 : GElf_Addr bias = (at_phdr - (ehdr.e_phoff - phdr->p_offset
620 : 0 : + phdr->p_vaddr));
621 : :
622 : : /* Final sanity check: if we have an AT_ENTRY value,
623 : : reject this PIE unless its biased e_entry matches. */
624 [ # # # # ]: 0 : if (at_entry != 0 && at_entry != ehdr.e_entry + bias)
625 : : return 0;
626 : :
627 : : /* If we're changing the module's address range,
628 : : we've just invalidated the module lookup table. */
629 [ # # ]: 0 : GElf_Addr mod_bias = dwfl_adjusted_address (mod, 0);
630 [ # # ]: 0 : if (bias != mod_bias)
631 : : {
632 : 0 : mod->low_addr -= mod_bias;
633 : 0 : mod->high_addr -= mod_bias;
634 : 0 : mod->low_addr += bias;
635 : 0 : mod->high_addr += bias;
636 : :
637 : 0 : free (mod->dwfl->lookup_module);
638 : 0 : mod->dwfl->lookup_module = NULL;
639 : : }
640 : : }
641 : : }
642 : :
643 [ # # ]: 0 : if (phdr->p_type == PT_DYNAMIC)
644 : : {
645 : 0 : Elf_Data *data = elf_getdata_rawchunk (mod->main.elf, phdr->p_offset,
646 : : phdr->p_filesz, ELF_T_DYN);
647 [ # # ]: 0 : if (data == NULL)
648 : 0 : continue;
649 : 0 : const size_t entsize = gelf_fsize (mod->main.elf,
650 : : ELF_T_DYN, 1, EV_CURRENT);
651 : 0 : const size_t n = data->d_size / entsize;
652 [ # # ]: 0 : for (size_t j = 0; j < n; ++j)
653 : : {
654 : 0 : GElf_Dyn dyn_mem;
655 : 0 : GElf_Dyn *dyn = gelf_getdyn (data, j, &dyn_mem);
656 [ # # # # ]: 0 : if (dyn != NULL && dyn->d_tag == DT_DEBUG)
657 : : {
658 : 0 : d_val_vaddr = phdr->p_vaddr + entsize * j + entsize / 2;
659 : 0 : break;
660 : : }
661 : : }
662 : : }
663 : : }
664 : :
665 [ # # ]: 0 : if (d_val_vaddr != 0)
666 : : {
667 : : /* Now we have the final address from which to read &r_debug. */
668 : 0 : d_val_vaddr = dwfl_adjusted_address (mod, d_val_vaddr);
669 : :
670 : 0 : void *buffer = NULL;
671 : 0 : size_t buffer_available = addrsize (ehdr.e_ident[EI_CLASS]);
672 : :
673 : 0 : int segndx = INTUSE(dwfl_addrsegment) (mod->dwfl, d_val_vaddr, NULL);
674 : :
675 [ # # ]: 0 : if ((*memory_callback) (mod->dwfl, segndx,
676 : : &buffer, &buffer_available,
677 : : d_val_vaddr, buffer_available,
678 : : memory_callback_arg))
679 : : {
680 : 0 : const union
681 : : {
682 : : Elf32_Addr a32;
683 : : Elf64_Addr a64;
684 : 0 : } *u = buffer;
685 : :
686 : 0 : GElf_Addr vaddr;
687 [ # # ]: 0 : if (ehdr.e_ident[EI_CLASS] == ELFCLASS32)
688 : 0 : vaddr = (ehdr.e_ident[EI_DATA] == ELFDATA2MSB
689 [ # # ]: 0 : ? BE32 (u->a32) : LE32 (u->a32));
690 : : else
691 : 0 : vaddr = (ehdr.e_ident[EI_DATA] == ELFDATA2MSB
692 [ # # ]: 0 : ? BE64 (u->a64) : LE64 (u->a64));
693 : :
694 : 0 : (*memory_callback) (mod->dwfl, -1, &buffer, &buffer_available, 0, 0,
695 : : memory_callback_arg);
696 : :
697 [ # # ]: 0 : if (*elfclass == ELFCLASSNONE)
698 : 0 : *elfclass = ehdr.e_ident[EI_CLASS];
699 [ # # ]: 0 : else if (*elfclass != ehdr.e_ident[EI_CLASS])
700 : 0 : return 0;
701 : :
702 [ # # ]: 0 : if (*elfdata == ELFDATANONE)
703 : 0 : *elfdata = ehdr.e_ident[EI_DATA];
704 [ # # ]: 0 : else if (*elfdata != ehdr.e_ident[EI_DATA])
705 : : return 0;
706 : :
707 : 0 : return vaddr;
708 : : }
709 : : }
710 : :
711 : : return 0;
712 : : }
713 : :
714 : : /* Try to find an existing executable module with a DT_DEBUG. */
715 : : static GElf_Addr
716 : 0 : find_executable (Dwfl *dwfl, GElf_Addr at_phdr, GElf_Addr at_entry,
717 : : uint_fast8_t *elfclass, uint_fast8_t *elfdata,
718 : : Dwfl_Memory_Callback *memory_callback,
719 : : void *memory_callback_arg)
720 : : {
721 [ # # ]: 0 : for (Dwfl_Module *mod = dwfl->modulelist; mod != NULL; mod = mod->next)
722 [ # # ]: 0 : if (mod->main.elf != NULL)
723 : : {
724 : 0 : GElf_Addr r_debug_vaddr = consider_executable (mod, at_phdr, at_entry,
725 : : elfclass, elfdata,
726 : : memory_callback,
727 : : memory_callback_arg);
728 [ # # ]: 0 : if (r_debug_vaddr != 0)
729 : 0 : return r_debug_vaddr;
730 : : }
731 : :
732 : : return 0;
733 : : }
734 : :
735 : :
736 : : int
737 : 76 : dwfl_link_map_report (Dwfl *dwfl, const void *auxv, size_t auxv_size,
738 : : Dwfl_Memory_Callback *memory_callback,
739 : : void *memory_callback_arg,
740 : : struct r_debug_info *r_debug_info)
741 : : {
742 : 76 : GElf_Addr r_debug_vaddr = 0;
743 : :
744 : 76 : uint_fast8_t elfclass = ELFCLASSNONE;
745 : 76 : uint_fast8_t elfdata = ELFDATANONE;
746 [ + - ]: 76 : if (likely (auxv != NULL)
747 [ + - ]: 76 : && likely (auxv_format_probe (auxv, auxv_size, &elfclass, &elfdata)))
748 : : {
749 : 76 : GElf_Addr entry = 0;
750 : 76 : GElf_Addr phdr = 0;
751 : 76 : GElf_Xword phent = 0;
752 : 76 : GElf_Xword phnum = 0;
753 : :
754 : : #define READ_AUXV32(ptr) read_4ubyte_unaligned_noncvt (ptr)
755 : : #define READ_AUXV64(ptr) read_8ubyte_unaligned_noncvt (ptr)
756 : : #define AUXV_SCAN(NN, BL) do \
757 : : { \
758 : : const Elf##NN##_auxv_t *av = auxv; \
759 : : for (size_t i = 0; i < auxv_size / sizeof av[0]; ++i) \
760 : : { \
761 : : const char *typep = auxv + i * sizeof (Elf##NN##_auxv_t); \
762 : : typep += offsetof (Elf##NN##_auxv_t, a_type); \
763 : : uint##NN##_t type = READ_AUXV##NN (typep); \
764 : : const char *valp = auxv + i * sizeof (Elf##NN##_auxv_t); \
765 : : valp += offsetof (Elf##NN##_auxv_t, a_un.a_val); \
766 : : uint##NN##_t val = BL##NN (READ_AUXV##NN (valp)); \
767 : : if (type == BL##NN (AT_ENTRY)) \
768 : : entry = val; \
769 : : else if (type == BL##NN (AT_PHDR)) \
770 : : phdr = val; \
771 : : else if (type == BL##NN (AT_PHNUM)) \
772 : : phnum = val; \
773 : : else if (type == BL##NN (AT_PHENT)) \
774 : : phent = val; \
775 : : else if (type == BL##NN (AT_PAGESZ)) \
776 : : { \
777 : : if (val > 1 \
778 : : && (dwfl->segment_align == 0 \
779 : : || val < dwfl->segment_align)) \
780 : : dwfl->segment_align = val; \
781 : : } \
782 : : } \
783 : : } \
784 : : while (0)
785 : :
786 [ + + ]: 76 : if (elfclass == ELFCLASS32)
787 : : {
788 [ + + ]: 14 : if (elfdata == ELFDATA2MSB)
789 [ + + + + : 146 : AUXV_SCAN (32, BE);
+ + + + +
+ - + + -
+ - + + ]
790 : : else
791 [ + + + + : 166 : AUXV_SCAN (32, LE);
+ + + + +
+ - + + -
+ - + + ]
792 : : }
793 : : else
794 : : {
795 [ + + ]: 62 : if (elfdata == ELFDATA2MSB)
796 [ + + + + : 182 : AUXV_SCAN (64, BE);
+ + + + +
+ - + + -
+ - + + ]
797 : : else
798 [ + + + + : 1106 : AUXV_SCAN (64, LE);
+ + + + +
+ - + + -
+ - + + ]
799 : : }
800 : :
801 : : /* If we found the phdr dimensions, search phdrs for PT_DYNAMIC. */
802 : 76 : GElf_Addr dyn_vaddr = 0;
803 : 76 : GElf_Xword dyn_filesz = 0;
804 : 76 : GElf_Addr dyn_bias = (GElf_Addr) -1;
805 : :
806 [ + - ]: 76 : if (phdr != 0 && phnum != 0
807 [ + + - + ]: 76 : && ((elfclass == ELFCLASS32 && phent == sizeof (Elf32_Phdr))
808 [ + - + - ]: 62 : || (elfclass == ELFCLASS64 && phent == sizeof (Elf64_Phdr))))
809 : : {
810 : 76 : Dwfl_Module *phdr_mod;
811 : 76 : int phdr_segndx = INTUSE(dwfl_addrsegment) (dwfl, phdr, &phdr_mod);
812 : 76 : Elf_Data in =
813 : : {
814 : : .d_type = ELF_T_PHDR,
815 : : .d_version = EV_CURRENT,
816 : 76 : .d_size = phnum * phent,
817 : : .d_buf = NULL
818 : : };
819 : 76 : bool in_ok = (*memory_callback) (dwfl, phdr_segndx, &in.d_buf,
820 : : &in.d_size, phdr, phnum * phent,
821 : : memory_callback_arg);
822 : 76 : bool in_from_exec = false;
823 [ + + ]: 76 : if (! in_ok
824 [ + - ]: 4 : && dwfl->user_core != NULL
825 [ + - ]: 4 : && dwfl->user_core->executable_for_core != NULL)
826 : : {
827 : : /* AUXV -> PHDR -> DYNAMIC
828 : : Both AUXV and DYNAMIC should be always present in a core file.
829 : : PHDR may be missing in core file, try to read it from
830 : : EXECUTABLE_FOR_CORE to find where DYNAMIC is located in the
831 : : core file. */
832 : :
833 : 4 : int fd = open (dwfl->user_core->executable_for_core, O_RDONLY);
834 : 4 : Elf *elf;
835 : 4 : Dwfl_Error error = DWFL_E_ERRNO;
836 [ + - ]: 4 : if (fd != -1)
837 : 4 : error = __libdw_open_file (&fd, &elf, true, false);
838 [ - + ]: 4 : if (error != DWFL_E_NOERROR)
839 : : {
840 : 0 : __libdwfl_seterrno (error);
841 : 0 : return false;
842 : : }
843 : 4 : GElf_Ehdr ehdr_mem, *ehdr = gelf_getehdr (elf, &ehdr_mem);
844 [ - + ]: 4 : if (ehdr == NULL)
845 : : {
846 : 0 : elf_end (elf);
847 : 0 : close (fd);
848 : 0 : __libdwfl_seterrno (DWFL_E_LIBELF);
849 : 0 : return false;
850 : : }
851 : 4 : size_t e_phnum;
852 [ - + ]: 4 : if (elf_getphdrnum (elf, &e_phnum) != 0)
853 : : {
854 : 0 : elf_end (elf);
855 : 0 : close (fd);
856 : 0 : __libdwfl_seterrno (DWFL_E_LIBELF);
857 : 0 : return false;
858 : : }
859 [ + - - + ]: 4 : if (e_phnum != phnum || ehdr->e_phentsize != phent)
860 : : {
861 : 0 : elf_end (elf);
862 : 0 : close (fd);
863 : 0 : __libdwfl_seterrno (DWFL_E_BADELF);
864 : 0 : return false;
865 : : }
866 : 4 : off_t off = ehdr->e_phoff;
867 [ - + ]: 4 : assert (in.d_buf == NULL);
868 : : /* Note this in the !in_ok path. That means memory_callback
869 : : failed. But the callback might still have reset the d_size
870 : : value (to zero). So explicitly set it here again. */
871 [ - + ]: 4 : if (unlikely (phnum > SIZE_MAX / phent))
872 : : {
873 : 0 : __libdwfl_seterrno (DWFL_E_NOMEM);
874 : 0 : return false;
875 : : }
876 : 4 : in.d_size = phnum * phent;
877 : 4 : in.d_buf = malloc (in.d_size);
878 [ - + ]: 4 : if (unlikely (in.d_buf == NULL))
879 : : {
880 : 0 : elf_end (elf);
881 : 0 : close (fd);
882 : 0 : __libdwfl_seterrno (DWFL_E_NOMEM);
883 : 0 : return false;
884 : : }
885 : 4 : ssize_t nread = pread_retry (fd, in.d_buf, in.d_size, off);
886 : 4 : elf_end (elf);
887 : 4 : close (fd);
888 [ - + ]: 4 : if (nread != (ssize_t) in.d_size)
889 : : {
890 : 0 : free (in.d_buf);
891 : 0 : __libdwfl_seterrno (DWFL_E_ERRNO);
892 : 0 : return false;
893 : : }
894 : 4 : in_ok = true;
895 : 4 : in_from_exec = true;
896 : : }
897 : 4 : if (in_ok)
898 : : {
899 [ - + ]: 76 : if (unlikely (phnum > SIZE_MAX / phent))
900 : : {
901 : 0 : __libdwfl_seterrno (DWFL_E_NOMEM);
902 : 0 : return false;
903 : : }
904 : 76 : size_t nbytes = phnum * phent;
905 : : /* We can only process as many bytes/phnum as there are
906 : : in in.d_size. The data might have been truncated. */
907 [ - + ]: 76 : if (nbytes > in.d_size)
908 : : {
909 : 0 : nbytes = in.d_size;
910 : 0 : phnum = nbytes / phent;
911 [ # # ]: 0 : if (phnum == 0)
912 : : {
913 : 0 : __libdwfl_seterrno (DWFL_E_BADELF);
914 : 0 : return false;
915 : : }
916 : : }
917 : 76 : void *buf = malloc (nbytes);
918 : 76 : Elf32_Phdr (*p32)[phnum] = buf;
919 : 76 : Elf64_Phdr (*p64)[phnum] = buf;
920 [ - + ]: 76 : if (unlikely (buf == NULL))
921 : : {
922 : 0 : __libdwfl_seterrno (DWFL_E_NOMEM);
923 : 0 : return false;
924 : : }
925 : 76 : Elf_Data out =
926 : : {
927 : : .d_type = ELF_T_PHDR,
928 : : .d_version = EV_CURRENT,
929 : : .d_size = nbytes,
930 : : .d_buf = buf
931 : : };
932 [ + + ]: 76 : if (in.d_size > out.d_size)
933 : : {
934 : 70 : in.d_size = out.d_size;
935 : 70 : phnum = in.d_size / phent;
936 [ - + ]: 70 : if (phnum == 0)
937 : : {
938 : 0 : free (buf);
939 : 0 : __libdwfl_seterrno (DWFL_E_BADELF);
940 : 0 : return false;
941 : : }
942 : : }
943 : 76 : bool is32 = (elfclass == ELFCLASS32);
944 : 152 : size_t phdr_align = (is32
945 : : ? __alignof__ (Elf32_Phdr)
946 [ + + ]: 76 : : __alignof__ (Elf64_Phdr));
947 [ + + ]: 76 : if (!in_from_exec
948 [ - + ]: 72 : && ((uintptr_t) in.d_buf & (phdr_align - 1)) != 0)
949 : : {
950 : 0 : memcpy (out.d_buf, in.d_buf, in.d_size);
951 : 0 : in.d_buf = out.d_buf;
952 : : }
953 [ + + + - ]: 138 : if (likely ((elfclass == ELFCLASS32
954 : : ? elf32_xlatetom : elf64_xlatetom)
955 : : (&out, &in, elfdata) != NULL))
956 : : {
957 [ + + ]: 410 : for (size_t i = 0; i < phnum; ++i)
958 : : {
959 : 768 : GElf_Word type = (is32
960 : : ? (*p32)[i].p_type
961 [ + + ]: 384 : : (*p64)[i].p_type);
962 : 768 : GElf_Addr vaddr = (is32
963 : 74 : ? (*p32)[i].p_vaddr
964 [ + + ]: 384 : : (*p64)[i].p_vaddr);
965 : 768 : GElf_Xword filesz = (is32
966 : 74 : ? (*p32)[i].p_filesz
967 [ + + ]: 384 : : (*p64)[i].p_filesz);
968 : :
969 [ + + ]: 384 : if (type == PT_PHDR)
970 : : {
971 [ + - ]: 50 : if (dyn_bias == (GElf_Addr) -1
972 : : /* Do a sanity check on the putative address. */
973 : 50 : && ((vaddr & (dwfl->segment_align - 1))
974 [ + - ]: 50 : == (phdr & (dwfl->segment_align - 1))))
975 : : {
976 : 50 : dyn_bias = phdr - vaddr;
977 [ + - ]: 50 : if (dyn_vaddr != 0)
978 : : break;
979 : : }
980 : :
981 : : }
982 [ + + ]: 334 : else if (type == PT_DYNAMIC)
983 : : {
984 : 50 : dyn_vaddr = vaddr;
985 : 50 : dyn_filesz = filesz;
986 [ - + ]: 50 : if (dyn_bias != (GElf_Addr) -1)
987 : : break;
988 : : }
989 : : }
990 : : }
991 : :
992 [ + + ]: 76 : if (in_from_exec)
993 : 4 : free (in.d_buf);
994 : : else
995 : 72 : (*memory_callback) (dwfl, -1, &in.d_buf, &in.d_size, 0, 0,
996 : : memory_callback_arg);
997 : 76 : free (buf);
998 : : }
999 : : else
1000 : : /* We could not read the executable's phdrs from the
1001 : : memory image. If we have a presupplied executable,
1002 : : we can still use the AT_PHDR and AT_ENTRY values to
1003 : : verify it, and to adjust its bias if it's a PIE.
1004 : :
1005 : : If there was an ET_EXEC module presupplied that contains
1006 : : the AT_PHDR address, then we only consider that one.
1007 : : We'll either accept it if its phdr location and e_entry
1008 : : make sense or reject it if they don't. If there is no
1009 : : presupplied ET_EXEC, then look for a presupplied module,
1010 : : which might be a PIE (ET_DYN) that needs its bias adjusted. */
1011 : 0 : r_debug_vaddr = ((phdr_mod == NULL
1012 [ # # ]: 0 : || phdr_mod->main.elf == NULL
1013 [ # # ]: 0 : || phdr_mod->e_type != ET_EXEC)
1014 : 0 : ? find_executable (dwfl, phdr, entry,
1015 : : &elfclass, &elfdata,
1016 : : memory_callback,
1017 : : memory_callback_arg)
1018 [ # # ]: 0 : : consider_executable (phdr_mod, phdr, entry,
1019 : : &elfclass, &elfdata,
1020 : : memory_callback,
1021 : : memory_callback_arg));
1022 : : }
1023 : :
1024 : : /* If we found PT_DYNAMIC, search it for DT_DEBUG. */
1025 [ + + ]: 76 : if (dyn_filesz != 0)
1026 : : {
1027 [ + - ]: 50 : if (dyn_bias != (GElf_Addr) -1)
1028 : 50 : dyn_vaddr += dyn_bias;
1029 : :
1030 : 50 : Elf_Data in =
1031 : : {
1032 : : .d_type = ELF_T_DYN,
1033 : : .d_version = EV_CURRENT,
1034 : : .d_size = dyn_filesz,
1035 : : .d_buf = NULL
1036 : : };
1037 : 50 : int dyn_segndx = dwfl_addrsegment (dwfl, dyn_vaddr, NULL);
1038 [ + - ]: 50 : if ((*memory_callback) (dwfl, dyn_segndx, &in.d_buf, &in.d_size,
1039 : : dyn_vaddr, dyn_filesz, memory_callback_arg))
1040 : : {
1041 : 100 : size_t entsize = (elfclass == ELFCLASS32
1042 [ + + ]: 50 : ? sizeof (Elf32_Dyn) : sizeof (Elf64_Dyn));
1043 [ - + ]: 50 : if (unlikely (dyn_filesz > SIZE_MAX / entsize))
1044 : : {
1045 : 0 : __libdwfl_seterrno (DWFL_E_NOMEM);
1046 : 0 : return false;
1047 : : }
1048 : : /* We can only process as many bytes as there are in
1049 : : in.d_size. The data might have been truncated. */
1050 : 50 : if (dyn_filesz > in.d_size)
1051 : : dyn_filesz = in.d_size;
1052 [ - + ]: 50 : if (dyn_filesz / entsize == 0)
1053 : : {
1054 : 0 : __libdwfl_seterrno (DWFL_E_BADELF);
1055 : 0 : return false;
1056 : : }
1057 : 50 : void *buf = malloc (dyn_filesz);
1058 [ - + ]: 50 : if (unlikely (buf == NULL))
1059 : : {
1060 : 0 : __libdwfl_seterrno (DWFL_E_NOMEM);
1061 : 0 : return false;
1062 : : }
1063 : 50 : Elf_Data out =
1064 : : {
1065 : : .d_type = ELF_T_DYN,
1066 : : .d_version = EV_CURRENT,
1067 : : .d_size = dyn_filesz,
1068 : : .d_buf = buf
1069 : : };
1070 [ + + ]: 50 : if (in.d_size > out.d_size)
1071 : 48 : in.d_size = out.d_size;
1072 : 100 : size_t dyn_align = (elfclass == ELFCLASS32
1073 : : ? __alignof__ (Elf32_Dyn)
1074 [ + + ]: 50 : : __alignof__ (Elf64_Dyn));
1075 [ - + ]: 50 : if (((uintptr_t) in.d_buf & (dyn_align - 1)) != 0)
1076 : : {
1077 : 0 : memcpy (out.d_buf, in.d_buf, in.d_size);
1078 : 0 : in.d_buf = out.d_buf;
1079 : : }
1080 [ + + + - ]: 96 : if (likely ((elfclass == ELFCLASS32
1081 : : ? elf32_xlatetom : elf64_xlatetom)
1082 : : (&out, &in, elfdata) != NULL))
1083 : : {
1084 : : /* We are looking for DT_DEBUG. */
1085 [ + + ]: 50 : if (elfclass == ELFCLASS32)
1086 : : {
1087 : 4 : Elf32_Dyn (*d32)[dyn_filesz / sizeof (Elf32_Dyn)] = buf;
1088 : 4 : size_t n = dyn_filesz / sizeof (Elf32_Dyn);
1089 [ + - ]: 56 : for (size_t i = 0; i < n; ++i)
1090 [ + + ]: 56 : if ((*d32)[i].d_tag == DT_DEBUG)
1091 : : {
1092 : 4 : r_debug_vaddr = (*d32)[i].d_un.d_val;
1093 : 4 : break;
1094 : : }
1095 : : }
1096 : : else
1097 : : {
1098 : 46 : Elf64_Dyn (*d64)[dyn_filesz / sizeof (Elf64_Dyn)] = buf;
1099 : 46 : size_t n = dyn_filesz / sizeof (Elf64_Dyn);
1100 [ + - ]: 634 : for (size_t i = 0; i < n; ++i)
1101 [ + + ]: 634 : if ((*d64)[i].d_tag == DT_DEBUG)
1102 : : {
1103 : 46 : r_debug_vaddr = (*d64)[i].d_un.d_val;
1104 : 46 : break;
1105 : : }
1106 : : }
1107 : : }
1108 : :
1109 : 50 : (*memory_callback) (dwfl, -1, &in.d_buf, &in.d_size, 0, 0,
1110 : : memory_callback_arg);
1111 : 50 : free (buf);
1112 : : }
1113 : : }
1114 : : }
1115 : : else
1116 : : /* We have to look for a presupplied executable file to determine
1117 : : the vaddr of its dynamic section and DT_DEBUG therein. */
1118 : 0 : r_debug_vaddr = find_executable (dwfl, 0, 0, &elfclass, &elfdata,
1119 : : memory_callback, memory_callback_arg);
1120 : :
1121 [ + + ]: 76 : if (r_debug_vaddr == 0)
1122 : : return 0;
1123 : :
1124 : : /* For following pointers from struct link_map, we will use an
1125 : : integrated memory access callback that can consult module text
1126 : : elided from the core file. This is necessary when the l_name
1127 : : pointer for the dynamic linker's own entry is a pointer into the
1128 : : executable's .interp section. */
1129 : 50 : struct integrated_memory_callback mcb =
1130 : : {
1131 : : .memory_callback = memory_callback,
1132 : : .memory_callback_arg = memory_callback_arg
1133 : : };
1134 : :
1135 : : /* Now we can follow the dynamic linker's library list. */
1136 : 50 : return report_r_debug (elfclass, elfdata, dwfl, r_debug_vaddr,
1137 : : &integrated_memory_callback, &mcb, r_debug_info);
1138 : : }
1139 : : INTDEF (dwfl_link_map_report)
|