summaryrefslogtreecommitdiffstats
path: root/src/libdwfl/link_map.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/libdwfl/link_map.c')
-rw-r--r--src/libdwfl/link_map.c1021
1 files changed, 0 insertions, 1021 deletions
diff --git a/src/libdwfl/link_map.c b/src/libdwfl/link_map.c
deleted file mode 100644
index eaf43b57..00000000
--- a/src/libdwfl/link_map.c
+++ /dev/null
@@ -1,1021 +0,0 @@
-/* Report modules by examining dynamic linker data structures.
- Copyright (C) 2008-2014 Red Hat, Inc.
- This file is part of elfutils.
-
- This file is free software; you can redistribute it and/or modify
- it under the terms of either
-
- * the GNU Lesser General Public License as published by the Free
- Software Foundation; either version 3 of the License, or (at
- your option) any later version
-
- or
-
- * the GNU General Public License as published by the Free
- Software Foundation; either version 2 of the License, or (at
- your option) any later version
-
- or both in parallel, as here.
-
- elfutils is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received copies of the GNU General Public License and
- the GNU Lesser General Public License along with this program. If
- not, see <http://www.gnu.org/licenses/>. */
-
-#include <config.h>
-#include "libdwflP.h"
-#include "../libdw/memory-access.h"
-#include "system.h"
-
-#include <byteswap.h>
-#include <endian.h>
-#include <fcntl.h>
-
-/* This element is always provided and always has a constant value.
- This makes it an easy thing to scan for to discern the format. */
-#define PROBE_TYPE AT_PHENT
-#define PROBE_VAL32 sizeof (Elf32_Phdr)
-#define PROBE_VAL64 sizeof (Elf64_Phdr)
-
-
-/* Examine an auxv data block and determine its format.
- Return true iff we figured it out. */
-static bool
-auxv_format_probe (const void *auxv, size_t size,
- uint_fast8_t *elfclass, uint_fast8_t *elfdata)
-{
- const union
- {
- char buf[size];
- Elf32_auxv_t a32[size / sizeof (Elf32_auxv_t)];
- Elf64_auxv_t a64[size / sizeof (Elf64_auxv_t)];
- } *u = auxv;
-
- inline bool check64 (size_t i)
- {
- /* The AUXV pointer might not even be naturally aligned for 64-bit
- data, because note payloads in a core file are not aligned.
- But we assume the data is 32-bit aligned. */
-
- uint64_t type = read_8ubyte_unaligned_noncvt (&u->a64[i].a_type);
- uint64_t val = read_8ubyte_unaligned_noncvt (&u->a64[i].a_un.a_val);
-
- if (type == BE64 (PROBE_TYPE)
- && val == BE64 (PROBE_VAL64))
- {
- *elfdata = ELFDATA2MSB;
- return true;
- }
-
- if (type == LE64 (PROBE_TYPE)
- && val == LE64 (PROBE_VAL64))
- {
- *elfdata = ELFDATA2LSB;
- return true;
- }
-
- return false;
- }
-
- inline bool check32 (size_t i)
- {
- if (u->a32[i].a_type == BE32 (PROBE_TYPE)
- && u->a32[i].a_un.a_val == BE32 (PROBE_VAL32))
- {
- *elfdata = ELFDATA2MSB;
- return true;
- }
-
- if (u->a32[i].a_type == LE32 (PROBE_TYPE)
- && u->a32[i].a_un.a_val == LE32 (PROBE_VAL32))
- {
- *elfdata = ELFDATA2LSB;
- return true;
- }
-
- return false;
- }
-
- for (size_t i = 0; i < size / sizeof (Elf64_auxv_t); ++i)
- {
- if (check64 (i))
- {
- *elfclass = ELFCLASS64;
- return true;
- }
-
- if (check32 (i * 2) || check32 (i * 2 + 1))
- {
- *elfclass = ELFCLASS32;
- return true;
- }
- }
-
- return false;
-}
-
-/* This is a Dwfl_Memory_Callback that wraps another memory callback.
- If the underlying callback cannot fill the data, then this will
- fall back to fetching data from module files. */
-
-struct integrated_memory_callback
-{
- Dwfl_Memory_Callback *memory_callback;
- void *memory_callback_arg;
- void *buffer;
-};
-
-static bool
-integrated_memory_callback (Dwfl *dwfl, int ndx,
- void **buffer, size_t *buffer_available,
- GElf_Addr vaddr,
- size_t minread,
- void *arg)
-{
- struct integrated_memory_callback *info = arg;
-
- if (ndx == -1)
- {
- /* Called for cleanup. */
- if (info->buffer != NULL)
- {
- /* The last probe buffer came from the underlying callback.
- Let it do its cleanup. */
- assert (*buffer == info->buffer); /* XXX */
- *buffer = info->buffer;
- info->buffer = NULL;
- return (*info->memory_callback) (dwfl, ndx, buffer, buffer_available,
- vaddr, minread,
- info->memory_callback_arg);
- }
- *buffer = NULL;
- *buffer_available = 0;
- return false;
- }
-
- if (*buffer != NULL)
- /* For a final-read request, we only use the underlying callback. */
- return (*info->memory_callback) (dwfl, ndx, buffer, buffer_available,
- vaddr, minread, info->memory_callback_arg);
-
- /* Let the underlying callback try to fill this request. */
- if ((*info->memory_callback) (dwfl, ndx, &info->buffer, buffer_available,
- vaddr, minread, info->memory_callback_arg))
- {
- *buffer = info->buffer;
- return true;
- }
-
- /* Now look for module text covering this address. */
-
- Dwfl_Module *mod;
- (void) INTUSE(dwfl_addrsegment) (dwfl, vaddr, &mod);
- if (mod == NULL)
- return false;
-
- Dwarf_Addr bias;
- Elf_Scn *scn = INTUSE(dwfl_module_address_section) (mod, &vaddr, &bias);
- if (unlikely (scn == NULL))
- {
-#if 0 // XXX would have to handle ndx=-1 cleanup calls passed down.
- /* If we have no sections we can try to fill it from the module file
- based on its phdr mappings. */
- if (likely (mod->e_type != ET_REL) && mod->main.elf != NULL)
- return INTUSE(dwfl_elf_phdr_memory_callback)
- (dwfl, 0, buffer, buffer_available,
- vaddr - mod->main.bias, minread, mod->main.elf);
-#endif
- return false;
- }
-
- Elf_Data *data = elf_rawdata (scn, NULL);
- if (unlikely (data == NULL))
- // XXX throw error?
- return false;
-
- if (unlikely (data->d_size < vaddr))
- return false;
-
- /* Provide as much data as we have. */
- void *contents = data->d_buf + vaddr;
- size_t avail = data->d_size - vaddr;
- if (unlikely (avail < minread))
- return false;
-
- /* If probing for a string, make sure it's terminated. */
- if (minread == 0 && unlikely (memchr (contents, '\0', avail) == NULL))
- return false;
-
- /* We have it! */
- *buffer = contents;
- *buffer_available = avail;
- return true;
-}
-
-static size_t
-addrsize (uint_fast8_t elfclass)
-{
- return elfclass * 4;
-}
-
-/* Report a module for each struct link_map in the linked list at r_map
- in the struct r_debug at R_DEBUG_VADDR. For r_debug_info description
- see dwfl_link_map_report in libdwflP.h. If R_DEBUG_INFO is not NULL then no
- modules get added to DWFL, caller has to add them from filled in
- R_DEBUG_INFO.
-
- For each link_map entry, if an existing module resides at its address,
- this just modifies that module's name and suggested file name. If
- no such module exists, this calls dwfl_report_elf on the l_name string.
-
- Returns the number of modules found, or -1 for errors. */
-
-static int
-report_r_debug (uint_fast8_t elfclass, uint_fast8_t elfdata,
- Dwfl *dwfl, GElf_Addr r_debug_vaddr,
- Dwfl_Memory_Callback *memory_callback,
- void *memory_callback_arg,
- struct r_debug_info *r_debug_info)
-{
- /* Skip r_version, to aligned r_map field. */
- GElf_Addr read_vaddr = r_debug_vaddr + addrsize (elfclass);
-
- void *buffer = NULL;
- size_t buffer_available = 0;
- inline int release_buffer (int result)
- {
- if (buffer != NULL)
- (void) (*memory_callback) (dwfl, -1, &buffer, &buffer_available, 0, 0,
- memory_callback_arg);
- return result;
- }
-
- GElf_Addr addrs[4];
- inline bool read_addrs (GElf_Addr vaddr, size_t n)
- {
- size_t nb = n * addrsize (elfclass); /* Address words -> bytes to read. */
-
- /* Read a new buffer if the old one doesn't cover these words. */
- if (buffer == NULL
- || vaddr < read_vaddr
- || vaddr - read_vaddr + nb > buffer_available)
- {
- release_buffer (0);
-
- read_vaddr = vaddr;
- int segndx = INTUSE(dwfl_addrsegment) (dwfl, vaddr, NULL);
- if (unlikely (segndx < 0)
- || unlikely (! (*memory_callback) (dwfl, segndx,
- &buffer, &buffer_available,
- vaddr, nb, memory_callback_arg)))
- return true;
- }
-
- const union
- {
- Elf32_Addr a32[n];
- Elf64_Addr a64[n];
- } *in = vaddr - read_vaddr + buffer;
-
- if (elfclass == ELFCLASS32)
- {
- if (elfdata == ELFDATA2MSB)
- for (size_t i = 0; i < n; ++i)
- addrs[i] = BE32 (in->a32[i]);
- else
- for (size_t i = 0; i < n; ++i)
- addrs[i] = LE32 (in->a32[i]);
- }
- else
- {
- if (elfdata == ELFDATA2MSB)
- for (size_t i = 0; i < n; ++i)
- addrs[i] = BE64 (in->a64[i]);
- else
- for (size_t i = 0; i < n; ++i)
- addrs[i] = LE64 (in->a64[i]);
- }
-
- return false;
- }
-
- if (unlikely (read_addrs (read_vaddr, 1)))
- return release_buffer (-1);
-
- GElf_Addr next = addrs[0];
-
- Dwfl_Module **lastmodp = &dwfl->modulelist;
- int result = 0;
-
- /* There can't be more elements in the link_map list than there are
- segments. DWFL->lookup_elts is probably twice that number, so it
- is certainly above the upper bound. If we iterate too many times,
- there must be a loop in the pointers due to link_map clobberation. */
- size_t iterations = 0;
- while (next != 0 && ++iterations < dwfl->lookup_elts)
- {
- if (read_addrs (next, 4))
- return release_buffer (-1);
-
- /* Unused: l_addr is the difference between the address in memory
- and the ELF file when the core was created. We need to
- recalculate the difference below because the ELF file we use
- might be differently pre-linked. */
- // GElf_Addr l_addr = addrs[0];
- GElf_Addr l_name = addrs[1];
- GElf_Addr l_ld = addrs[2];
- next = addrs[3];
-
- /* If a clobbered or truncated memory image has no useful pointer,
- just skip this element. */
- if (l_ld == 0)
- continue;
-
- /* Fetch the string at the l_name address. */
- const char *name = NULL;
- if (buffer != NULL
- && read_vaddr <= l_name
- && l_name + 1 - read_vaddr < buffer_available
- && memchr (l_name - read_vaddr + buffer, '\0',
- buffer_available - (l_name - read_vaddr)) != NULL)
- name = l_name - read_vaddr + buffer;
- else
- {
- release_buffer (0);
- read_vaddr = l_name;
- int segndx = INTUSE(dwfl_addrsegment) (dwfl, l_name, NULL);
- if (likely (segndx >= 0)
- && (*memory_callback) (dwfl, segndx,
- &buffer, &buffer_available,
- l_name, 0, memory_callback_arg))
- name = buffer;
- }
-
- if (name != NULL && name[0] == '\0')
- name = NULL;
-
- if (iterations == 1 && dwfl->executable_for_core != NULL)
- name = dwfl->executable_for_core;
-
- struct r_debug_info_module *r_debug_info_module = NULL;
- if (r_debug_info != NULL)
- {
- /* Save link map information about valid shared library (or
- executable) which has not been found on disk. */
- const char *name1 = name == NULL ? "" : name;
- r_debug_info_module = malloc (sizeof (*r_debug_info_module)
- + strlen (name1) + 1);
- if (r_debug_info_module == NULL)
- return release_buffer (result);
- r_debug_info_module->fd = -1;
- r_debug_info_module->elf = NULL;
- r_debug_info_module->l_ld = l_ld;
- r_debug_info_module->start = 0;
- r_debug_info_module->end = 0;
- r_debug_info_module->disk_file_has_build_id = false;
- strcpy (r_debug_info_module->name, name1);
- r_debug_info_module->next = r_debug_info->module;
- r_debug_info->module = r_debug_info_module;
- }
-
- Dwfl_Module *mod = NULL;
- if (name != NULL)
- {
- /* This code is mostly inlined dwfl_report_elf. */
- // XXX hook for sysroot
- int fd = open64 (name, O_RDONLY);
- if (fd >= 0)
- {
- Elf *elf;
- Dwfl_Error error = __libdw_open_file (&fd, &elf, true, false);
- GElf_Addr elf_dynamic_vaddr;
- if (error == DWFL_E_NOERROR
- && __libdwfl_dynamic_vaddr_get (elf, &elf_dynamic_vaddr))
- {
- const void *build_id_bits;
- GElf_Addr build_id_elfaddr;
- int build_id_len;
- bool valid = true;
-
- if (__libdwfl_find_elf_build_id (NULL, elf, &build_id_bits,
- &build_id_elfaddr,
- &build_id_len) > 0
- && build_id_elfaddr != 0)
- {
- if (r_debug_info_module != NULL)
- r_debug_info_module->disk_file_has_build_id = true;
- GElf_Addr build_id_vaddr = (build_id_elfaddr
- - elf_dynamic_vaddr + l_ld);
-
- release_buffer (0);
- int segndx = INTUSE(dwfl_addrsegment) (dwfl,
- build_id_vaddr,
- NULL);
- if (! (*memory_callback) (dwfl, segndx,
- &buffer, &buffer_available,
- build_id_vaddr, build_id_len,
- memory_callback_arg))
- {
- /* File has valid build-id which cannot be read from
- memory. This happens for core files without bit 4
- (0x10) set in Linux /proc/PID/coredump_filter. */
- }
- else
- {
- if (memcmp (build_id_bits, buffer, build_id_len) != 0)
- /* File has valid build-id which does not match
- the one in memory. */
- valid = false;
- release_buffer (0);
- }
- }
-
- if (valid)
- {
- // It is like l_addr but it handles differently prelinked
- // files at core dumping vs. core loading time.
- GElf_Addr base = l_ld - elf_dynamic_vaddr;
- if (r_debug_info_module == NULL)
- {
- // XXX hook for sysroot
- mod = __libdwfl_report_elf (dwfl, basename (name),
- name, fd, elf, base,
- true, true);
- if (mod != NULL)
- {
- elf = NULL;
- fd = -1;
- }
- }
- else if (__libdwfl_elf_address_range (elf, base, true,
- true, NULL, NULL,
- &r_debug_info_module->start,
- &r_debug_info_module->end,
- NULL, NULL))
- {
- r_debug_info_module->elf = elf;
- r_debug_info_module->fd = fd;
- elf = NULL;
- fd = -1;
- }
- }
- if (elf != NULL)
- elf_end (elf);
- if (fd != -1)
- close (fd);
- }
- }
- }
-
- if (mod != NULL)
- {
- ++result;
-
- /* Move this module to the end of the list, so that we end
- up with a list in the same order as the link_map chain. */
- if (mod->next != NULL)
- {
- if (*lastmodp != mod)
- {
- lastmodp = &dwfl->modulelist;
- while (*lastmodp != mod)
- lastmodp = &(*lastmodp)->next;
- }
- *lastmodp = mod->next;
- mod->next = NULL;
- while (*lastmodp != NULL)
- lastmodp = &(*lastmodp)->next;
- *lastmodp = mod;
- }
-
- lastmodp = &mod->next;
- }
- }
-
- return release_buffer (result);
-}
-
-static GElf_Addr
-consider_executable (Dwfl_Module *mod, GElf_Addr at_phdr, GElf_Addr at_entry,
- uint_fast8_t *elfclass, uint_fast8_t *elfdata,
- Dwfl_Memory_Callback *memory_callback,
- void *memory_callback_arg)
-{
- GElf_Ehdr ehdr;
- if (unlikely (gelf_getehdr (mod->main.elf, &ehdr) == NULL))
- return 0;
-
- if (at_entry != 0)
- {
- /* If we have an AT_ENTRY value, reject this executable if
- its entry point address could not have supplied that. */
-
- if (ehdr.e_entry == 0)
- return 0;
-
- if (mod->e_type == ET_EXEC)
- {
- if (ehdr.e_entry != at_entry)
- return 0;
- }
- else
- {
- /* It could be a PIE. */
- }
- }
-
- // XXX this could be saved in the file cache: phdr vaddr, DT_DEBUG d_val vaddr
- /* Find the vaddr of the DT_DEBUG's d_ptr. This is the memory
- address where &r_debug was written at runtime. */
- GElf_Xword align = mod->dwfl->segment_align;
- GElf_Addr d_val_vaddr = 0;
- size_t phnum;
- if (elf_getphdrnum (mod->main.elf, &phnum) != 0)
- return 0;
-
- for (size_t i = 0; i < phnum; ++i)
- {
- GElf_Phdr phdr_mem;
- GElf_Phdr *phdr = gelf_getphdr (mod->main.elf, i, &phdr_mem);
- if (phdr == NULL)
- break;
-
- if (phdr->p_align > 1 && (align == 0 || phdr->p_align < align))
- align = phdr->p_align;
-
- if (at_phdr != 0
- && phdr->p_type == PT_LOAD
- && (phdr->p_offset & -align) == (ehdr.e_phoff & -align))
- {
- /* This is the segment that would map the phdrs.
- If we have an AT_PHDR value, reject this executable
- if its phdr mapping could not have supplied that. */
- if (mod->e_type == ET_EXEC)
- {
- if (ehdr.e_phoff - phdr->p_offset + phdr->p_vaddr != at_phdr)
- return 0;
- }
- else
- {
- /* It could be a PIE. If the AT_PHDR value and our
- phdr address don't match modulo ALIGN, then this
- could not have been the right PIE. */
- if (((ehdr.e_phoff - phdr->p_offset + phdr->p_vaddr) & -align)
- != (at_phdr & -align))
- return 0;
-
- /* Calculate the bias applied to the PIE's p_vaddr values. */
- GElf_Addr bias = (at_phdr - (ehdr.e_phoff - phdr->p_offset
- + phdr->p_vaddr));
-
- /* Final sanity check: if we have an AT_ENTRY value,
- reject this PIE unless its biased e_entry matches. */
- if (at_entry != 0 && at_entry != ehdr.e_entry + bias)
- return 0;
-
- /* If we're changing the module's address range,
- we've just invalidated the module lookup table. */
- GElf_Addr mod_bias = dwfl_adjusted_address (mod, 0);
- if (bias != mod_bias)
- {
- mod->low_addr -= mod_bias;
- mod->high_addr -= mod_bias;
- mod->low_addr += bias;
- mod->high_addr += bias;
-
- free (mod->dwfl->lookup_module);
- mod->dwfl->lookup_module = NULL;
- }
- }
- }
-
- if (phdr->p_type == PT_DYNAMIC)
- {
- Elf_Data *data = elf_getdata_rawchunk (mod->main.elf, phdr->p_offset,
- phdr->p_filesz, ELF_T_DYN);
- if (data == NULL)
- continue;
- const size_t entsize = gelf_fsize (mod->main.elf,
- ELF_T_DYN, 1, EV_CURRENT);
- const size_t n = data->d_size / entsize;
- for (size_t j = 0; j < n; ++j)
- {
- GElf_Dyn dyn_mem;
- GElf_Dyn *dyn = gelf_getdyn (data, j, &dyn_mem);
- if (dyn != NULL && dyn->d_tag == DT_DEBUG)
- {
- d_val_vaddr = phdr->p_vaddr + entsize * j + entsize / 2;
- break;
- }
- }
- }
- }
-
- if (d_val_vaddr != 0)
- {
- /* Now we have the final address from which to read &r_debug. */
- d_val_vaddr = dwfl_adjusted_address (mod, d_val_vaddr);
-
- void *buffer = NULL;
- size_t buffer_available = addrsize (ehdr.e_ident[EI_CLASS]);
-
- int segndx = INTUSE(dwfl_addrsegment) (mod->dwfl, d_val_vaddr, NULL);
-
- if ((*memory_callback) (mod->dwfl, segndx,
- &buffer, &buffer_available,
- d_val_vaddr, buffer_available,
- memory_callback_arg))
- {
- const union
- {
- Elf32_Addr a32;
- Elf64_Addr a64;
- } *u = buffer;
-
- GElf_Addr vaddr;
- if (ehdr.e_ident[EI_CLASS] == ELFCLASS32)
- vaddr = (ehdr.e_ident[EI_DATA] == ELFDATA2MSB
- ? BE32 (u->a32) : LE32 (u->a32));
- else
- vaddr = (ehdr.e_ident[EI_DATA] == ELFDATA2MSB
- ? BE64 (u->a64) : LE64 (u->a64));
-
- (*memory_callback) (mod->dwfl, -1, &buffer, &buffer_available, 0, 0,
- memory_callback_arg);
-
- if (*elfclass == ELFCLASSNONE)
- *elfclass = ehdr.e_ident[EI_CLASS];
- else if (*elfclass != ehdr.e_ident[EI_CLASS])
- return 0;
-
- if (*elfdata == ELFDATANONE)
- *elfdata = ehdr.e_ident[EI_DATA];
- else if (*elfdata != ehdr.e_ident[EI_DATA])
- return 0;
-
- return vaddr;
- }
- }
-
- return 0;
-}
-
-/* Try to find an existing executable module with a DT_DEBUG. */
-static GElf_Addr
-find_executable (Dwfl *dwfl, GElf_Addr at_phdr, GElf_Addr at_entry,
- uint_fast8_t *elfclass, uint_fast8_t *elfdata,
- Dwfl_Memory_Callback *memory_callback,
- void *memory_callback_arg)
-{
- for (Dwfl_Module *mod = dwfl->modulelist; mod != NULL; mod = mod->next)
- if (mod->main.elf != NULL)
- {
- GElf_Addr r_debug_vaddr = consider_executable (mod, at_phdr, at_entry,
- elfclass, elfdata,
- memory_callback,
- memory_callback_arg);
- if (r_debug_vaddr != 0)
- return r_debug_vaddr;
- }
-
- return 0;
-}
-
-
-int
-dwfl_link_map_report (Dwfl *dwfl, const void *auxv, size_t auxv_size,
- Dwfl_Memory_Callback *memory_callback,
- void *memory_callback_arg,
- struct r_debug_info *r_debug_info)
-{
- GElf_Addr r_debug_vaddr = 0;
-
- uint_fast8_t elfclass = ELFCLASSNONE;
- uint_fast8_t elfdata = ELFDATANONE;
- if (likely (auxv != NULL)
- && likely (auxv_format_probe (auxv, auxv_size, &elfclass, &elfdata)))
- {
- GElf_Addr entry = 0;
- GElf_Addr phdr = 0;
- GElf_Xword phent = 0;
- GElf_Xword phnum = 0;
-
-#define READ_AUXV32(ptr) read_4ubyte_unaligned_noncvt (ptr)
-#define READ_AUXV64(ptr) read_8ubyte_unaligned_noncvt (ptr)
-#define AUXV_SCAN(NN, BL) do \
- { \
- const Elf##NN##_auxv_t *av = auxv; \
- for (size_t i = 0; i < auxv_size / sizeof av[0]; ++i) \
- { \
- uint##NN##_t type = READ_AUXV##NN (&av[i].a_type); \
- uint##NN##_t val = BL##NN (READ_AUXV##NN (&av[i].a_un.a_val)); \
- if (type == BL##NN (AT_ENTRY)) \
- entry = val; \
- else if (type == BL##NN (AT_PHDR)) \
- phdr = val; \
- else if (type == BL##NN (AT_PHNUM)) \
- phnum = val; \
- else if (type == BL##NN (AT_PHENT)) \
- phent = val; \
- else if (type == BL##NN (AT_PAGESZ)) \
- { \
- if (val > 1 \
- && (dwfl->segment_align == 0 \
- || val < dwfl->segment_align)) \
- dwfl->segment_align = val; \
- } \
- } \
- } \
- while (0)
-
- if (elfclass == ELFCLASS32)
- {
- if (elfdata == ELFDATA2MSB)
- AUXV_SCAN (32, BE);
- else
- AUXV_SCAN (32, LE);
- }
- else
- {
- if (elfdata == ELFDATA2MSB)
- AUXV_SCAN (64, BE);
- else
- AUXV_SCAN (64, LE);
- }
-
- /* If we found the phdr dimensions, search phdrs for PT_DYNAMIC. */
- GElf_Addr dyn_vaddr = 0;
- GElf_Xword dyn_filesz = 0;
- GElf_Addr dyn_bias = (GElf_Addr) -1;
-
- inline bool consider_phdr (GElf_Word type,
- GElf_Addr vaddr, GElf_Xword filesz)
- {
- switch (type)
- {
- case PT_PHDR:
- if (dyn_bias == (GElf_Addr) -1
- /* Do a sanity check on the putative address. */
- && ((vaddr & (dwfl->segment_align - 1))
- == (phdr & (dwfl->segment_align - 1))))
- {
- dyn_bias = phdr - vaddr;
- return dyn_vaddr != 0;
- }
- break;
-
- case PT_DYNAMIC:
- dyn_vaddr = vaddr;
- dyn_filesz = filesz;
- return dyn_bias != (GElf_Addr) -1;
- }
-
- return false;
- }
-
- if (phdr != 0 && phnum != 0)
- {
- Dwfl_Module *phdr_mod;
- int phdr_segndx = INTUSE(dwfl_addrsegment) (dwfl, phdr, &phdr_mod);
- Elf_Data in =
- {
- .d_type = ELF_T_PHDR,
- .d_version = EV_CURRENT,
- .d_size = phnum * phent,
- .d_buf = NULL
- };
- bool in_ok = (*memory_callback) (dwfl, phdr_segndx, &in.d_buf,
- &in.d_size, phdr, phnum * phent,
- memory_callback_arg);
- if (! in_ok && dwfl->executable_for_core != NULL)
- {
- /* AUXV -> PHDR -> DYNAMIC
- Both AUXV and DYNAMIC should be always present in a core file.
- PHDR may be missing in core file, try to read it from
- EXECUTABLE_FOR_CORE to find where DYNAMIC is located in the
- core file. */
-
- int fd = open (dwfl->executable_for_core, O_RDONLY);
- Elf *elf;
- Dwfl_Error error = DWFL_E_ERRNO;
- if (fd != -1)
- error = __libdw_open_file (&fd, &elf, true, false);
- if (error != DWFL_E_NOERROR)
- {
- __libdwfl_seterrno (error);
- return false;
- }
- GElf_Ehdr ehdr_mem, *ehdr = gelf_getehdr (elf, &ehdr_mem);
- if (ehdr == NULL)
- {
- elf_end (elf);
- close (fd);
- __libdwfl_seterrno (DWFL_E_LIBELF);
- return false;
- }
- size_t e_phnum;
- if (elf_getphdrnum (elf, &e_phnum) != 0)
- {
- elf_end (elf);
- close (fd);
- __libdwfl_seterrno (DWFL_E_LIBELF);
- return false;
- }
- if (e_phnum != phnum || ehdr->e_phentsize != phent)
- {
- elf_end (elf);
- close (fd);
- __libdwfl_seterrno (DWFL_E_BADELF);
- return false;
- }
- off_t off = ehdr->e_phoff;
- assert (in.d_buf == NULL);
- assert (in.d_size == phnum * phent);
- in.d_buf = malloc (in.d_size);
- if (unlikely (in.d_buf == NULL))
- {
- elf_end (elf);
- close (fd);
- __libdwfl_seterrno (DWFL_E_NOMEM);
- return false;
- }
- ssize_t nread = pread_retry (fd, in.d_buf, in.d_size, off);
- elf_end (elf);
- close (fd);
- if (nread != (ssize_t) in.d_size)
- {
- free (in.d_buf);
- __libdwfl_seterrno (DWFL_E_ERRNO);
- return false;
- }
- in_ok = true;
- }
- if (in_ok)
- {
- union
- {
- Elf32_Phdr p32;
- Elf64_Phdr p64;
- char data[phnum * phent];
- } buf;
- Elf_Data out =
- {
- .d_type = ELF_T_PHDR,
- .d_version = EV_CURRENT,
- .d_size = phnum * phent,
- .d_buf = &buf
- };
- in.d_size = out.d_size;
- if (likely ((elfclass == ELFCLASS32
- ? elf32_xlatetom : elf64_xlatetom)
- (&out, &in, elfdata) != NULL))
- {
- /* We are looking for PT_DYNAMIC. */
- const union
- {
- Elf32_Phdr p32[phnum];
- Elf64_Phdr p64[phnum];
- } *u = (void *) &buf;
- if (elfclass == ELFCLASS32)
- {
- for (size_t i = 0; i < phnum; ++i)
- if (consider_phdr (u->p32[i].p_type,
- u->p32[i].p_vaddr,
- u->p32[i].p_filesz))
- break;
- }
- else
- {
- for (size_t i = 0; i < phnum; ++i)
- if (consider_phdr (u->p64[i].p_type,
- u->p64[i].p_vaddr,
- u->p64[i].p_filesz))
- break;
- }
- }
-
- (*memory_callback) (dwfl, -1, &in.d_buf, &in.d_size, 0, 0,
- memory_callback_arg);
- }
- else
- /* We could not read the executable's phdrs from the
- memory image. If we have a presupplied executable,
- we can still use the AT_PHDR and AT_ENTRY values to
- verify it, and to adjust its bias if it's a PIE.
-
- If there was an ET_EXEC module presupplied that contains
- the AT_PHDR address, then we only consider that one.
- We'll either accept it if its phdr location and e_entry
- make sense or reject it if they don't. If there is no
- presupplied ET_EXEC, then look for a presupplied module,
- which might be a PIE (ET_DYN) that needs its bias adjusted. */
- r_debug_vaddr = ((phdr_mod == NULL
- || phdr_mod->main.elf == NULL
- || phdr_mod->e_type != ET_EXEC)
- ? find_executable (dwfl, phdr, entry,
- &elfclass, &elfdata,
- memory_callback,
- memory_callback_arg)
- : consider_executable (phdr_mod, phdr, entry,
- &elfclass, &elfdata,
- memory_callback,
- memory_callback_arg));
- }
-
- /* If we found PT_DYNAMIC, search it for DT_DEBUG. */
- if (dyn_filesz != 0)
- {
- if (dyn_bias != (GElf_Addr) -1)
- dyn_vaddr += dyn_bias;
-
- Elf_Data in =
- {
- .d_type = ELF_T_DYN,
- .d_version = EV_CURRENT,
- .d_size = dyn_filesz,
- .d_buf = NULL
- };
- int dyn_segndx = dwfl_addrsegment (dwfl, dyn_vaddr, NULL);
- if ((*memory_callback) (dwfl, dyn_segndx, &in.d_buf, &in.d_size,
- dyn_vaddr, dyn_filesz, memory_callback_arg))
- {
- union
- {
- Elf32_Dyn d32;
- Elf64_Dyn d64;
- char data[dyn_filesz];
- } buf;
- Elf_Data out =
- {
- .d_type = ELF_T_DYN,
- .d_version = EV_CURRENT,
- .d_size = dyn_filesz,
- .d_buf = &buf
- };
- in.d_size = out.d_size;
- if (likely ((elfclass == ELFCLASS32
- ? elf32_xlatetom : elf64_xlatetom)
- (&out, &in, elfdata) != NULL))
- {
- /* We are looking for DT_DEBUG. */
- const union
- {
- Elf32_Dyn d32[dyn_filesz / sizeof (Elf32_Dyn)];
- Elf64_Dyn d64[dyn_filesz / sizeof (Elf64_Dyn)];
- } *u = (void *) &buf;
- if (elfclass == ELFCLASS32)
- {
- size_t n = dyn_filesz / sizeof (Elf32_Dyn);
- for (size_t i = 0; i < n; ++i)
- if (u->d32[i].d_tag == DT_DEBUG)
- {
- r_debug_vaddr = u->d32[i].d_un.d_val;
- break;
- }
- }
- else
- {
- size_t n = dyn_filesz / sizeof (Elf64_Dyn);
- for (size_t i = 0; i < n; ++i)
- if (u->d64[i].d_tag == DT_DEBUG)
- {
- r_debug_vaddr = u->d64[i].d_un.d_val;
- break;
- }
- }
- }
-
- (*memory_callback) (dwfl, -1, &in.d_buf, &in.d_size, 0, 0,
- memory_callback_arg);
- }
- }
- }
- else
- /* We have to look for a presupplied executable file to determine
- the vaddr of its dynamic section and DT_DEBUG therein. */
- r_debug_vaddr = find_executable (dwfl, 0, 0, &elfclass, &elfdata,
- memory_callback, memory_callback_arg);
-
- if (r_debug_vaddr == 0)
- return 0;
-
- /* For following pointers from struct link_map, we will use an
- integrated memory access callback that can consult module text
- elided from the core file. This is necessary when the l_name
- pointer for the dynamic linker's own entry is a pointer into the
- executable's .interp section. */
- struct integrated_memory_callback mcb =
- {
- .memory_callback = memory_callback,
- .memory_callback_arg = memory_callback_arg
- };
-
- /* Now we can follow the dynamic linker's library list. */
- return report_r_debug (elfclass, elfdata, dwfl, r_debug_vaddr,
- &integrated_memory_callback, &mcb, r_debug_info);
-}
-INTDEF (dwfl_link_map_report)