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