summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libdwfl/ChangeLog3
-rw-r--r--libdwfl/link_map.c50
2 files changed, 41 insertions, 12 deletions
diff --git a/libdwfl/ChangeLog b/libdwfl/ChangeLog
index 9f4a745d..f7a3b847 100644
--- a/libdwfl/ChangeLog
+++ b/libdwfl/ChangeLog
@@ -1,5 +1,8 @@
2010-05-04 Roland McGrath <roland@redhat.com>
+ * link_map.c (dwfl_link_map_report): Detect bias of embedded phdrs and
+ apply it to PT_DYNAMIC p_vaddr so we handle a PIE correctly.
+
* core-file.c (dwfl_core_file_report): Return any nonzero count of
modules reported, even if link_map grovelling failed and only sniffing
found anything.
diff --git a/libdwfl/link_map.c b/libdwfl/link_map.c
index fe7f40ce..403b2df6 100644
--- a/libdwfl/link_map.c
+++ b/libdwfl/link_map.c
@@ -684,6 +684,33 @@ dwfl_link_map_report (Dwfl *dwfl, const void *auxv, size_t auxv_size,
/* 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;
@@ -725,22 +752,18 @@ dwfl_link_map_report (Dwfl *dwfl, const void *auxv, size_t auxv_size,
if (elfclass == ELFCLASS32)
{
for (size_t i = 0; i < phnum; ++i)
- if (u->p32[i].p_type == PT_DYNAMIC)
- {
- dyn_vaddr = u->p32[i].p_vaddr;
- dyn_filesz = u->p32[i].p_filesz;
- break;
- }
+ 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 (u->p64[i].p_type == PT_DYNAMIC)
- {
- dyn_vaddr = u->p64[i].p_vaddr;
- dyn_filesz = u->p64[i].p_filesz;
- break;
- }
+ if (consider_phdr (u->p64[i].p_type,
+ u->p64[i].p_vaddr,
+ u->p64[i].p_filesz))
+ break;
}
}
@@ -775,6 +798,9 @@ dwfl_link_map_report (Dwfl *dwfl, const void *auxv, size_t auxv_size,
/* 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,