summaryrefslogtreecommitdiff
path: root/libdwfl
diff options
context:
space:
mode:
authorRoland McGrath <roland@redhat.com>2011-02-01 16:58:32 -0800
committerRoland McGrath <roland@redhat.com>2011-02-01 16:58:32 -0800
commit0ef402035d71bf68c818e7b070d4c6d9744f951d (patch)
treee7322523db5d07c5f4543a4d45f4eaeb06061d5e /libdwfl
parent9fdd461bda5fe2921dc0ce91aaba9e21805bbdd2 (diff)
downloadelfutils-0ef402035d71bf68c818e7b070d4c6d9744f951d.tar.gz
libdwfl: Discover PT_INTERP p_vaddr separately from main phdrs and undo phdrs.
Diffstat (limited to 'libdwfl')
-rw-r--r--libdwfl/ChangeLog3
-rw-r--r--libdwfl/dwfl_module_getdwarf.c40
2 files changed, 34 insertions, 9 deletions
diff --git a/libdwfl/ChangeLog b/libdwfl/ChangeLog
index 81b4fcdd..1958cc74 100644
--- a/libdwfl/ChangeLog
+++ b/libdwfl/ChangeLog
@@ -1,5 +1,8 @@
2011-02-01 Roland McGrath <roland@redhat.com>
+ * dwfl_module_getdwarf.c (find_prelink_address_sync): Discover
+ PT_INTERP p_vaddr separately from main phdrs and undo phdrs.
+
* dwfl_module_getdwarf.c (find_prelink_address_sync): Fix pasto in
last change, so we recognize PT_INTERP in ELFCLASS64 correctly.
diff --git a/libdwfl/dwfl_module_getdwarf.c b/libdwfl/dwfl_module_getdwarf.c
index 83ca8535..c7ff8ab9 100644
--- a/libdwfl/dwfl_module_getdwarf.c
+++ b/libdwfl/dwfl_module_getdwarf.c
@@ -395,11 +395,29 @@ find_prelink_address_sync (Dwfl_Module *mod)
the SHT_PROGBITS section whose address matches the PT_INTERP p_vaddr.
For this reason, we must examine the phdrs first to find PT_INTERP. */
+ GElf_Addr main_interp = 0;
+ {
+ size_t main_phnum;
+ if (unlikely (elf_getphdrnum (mod->main.elf, &main_phnum)))
+ return DWFL_E_LIBELF;
+ for (size_t i = 0; i < main_phnum; ++i)
+ {
+ GElf_Phdr phdr;
+ if (unlikely (gelf_getphdr (mod->main.elf, i, &phdr) == NULL))
+ return DWFL_E_LIBELF;
+ if (phdr.p_type == PT_INTERP)
+ {
+ main_interp = phdr.p_vaddr;
+ break;
+ }
+ }
+ }
+
src.d_buf += src.d_size;
src.d_type = ELF_T_PHDR;
src.d_size = phnum * phentsize;
- GElf_Addr interp = 0;
+ GElf_Addr undo_interp = 0;
{
union
{
@@ -416,7 +434,7 @@ find_prelink_address_sync (Dwfl_Module *mod)
for (uint_fast16_t i = 0; i < phnum; ++i)
if (phdr.p32[i].p_type == PT_INTERP)
{
- interp = phdr.p32[i].p_vaddr;
+ undo_interp = phdr.p32[i].p_vaddr;
break;
}
}
@@ -425,12 +443,15 @@ find_prelink_address_sync (Dwfl_Module *mod)
for (uint_fast16_t i = 0; i < phnum; ++i)
if (phdr.p64[i].p_type == PT_INTERP)
{
- interp = phdr.p64[i].p_vaddr;
+ undo_interp = phdr.p64[i].p_vaddr;
break;
}
}
}
+ if (unlikely ((main_interp == 0) != (undo_interp == 0)))
+ return DWFL_E_BAD_PRELINK;
+
src.d_buf += src.d_size;
src.d_type = ELF_T_SHDR;
src.d_size = gelf_fsize (mod->main.elf, ELF_T_SHDR, shnum - 1, EV_CURRENT);
@@ -455,7 +476,8 @@ find_prelink_address_sync (Dwfl_Module *mod)
GElf_Addr highest;
- inline void consider_shdr (GElf_Word sh_type,
+ inline void consider_shdr (GElf_Addr interp,
+ GElf_Word sh_type,
GElf_Xword sh_flags,
GElf_Addr sh_addr)
{
@@ -476,7 +498,7 @@ find_prelink_address_sync (Dwfl_Module *mod)
GElf_Shdr *sh = gelf_getshdr (scn, &sh_mem);
if (unlikely (sh == NULL))
return DWFL_E_LIBELF;
- consider_shdr (sh->sh_type, sh->sh_flags, sh->sh_addr);
+ consider_shdr (main_interp, sh->sh_type, sh->sh_flags, sh->sh_addr);
}
if (highest > mod->main.vaddr)
{
@@ -485,12 +507,12 @@ find_prelink_address_sync (Dwfl_Module *mod)
highest = 0;
if (ehdr.e32.e_ident[EI_CLASS] == ELFCLASS32)
for (size_t i = 0; i < shnum - 1; ++i)
- consider_shdr (shdr.s32[i].sh_type, shdr.s32[i].sh_flags,
- shdr.s32[i].sh_addr);
+ consider_shdr (undo_interp, shdr.s32[i].sh_type,
+ shdr.s32[i].sh_flags, shdr.s32[i].sh_addr);
else
for (size_t i = 0; i < shnum - 1; ++i)
- consider_shdr (shdr.s64[i].sh_type, shdr.s64[i].sh_flags,
- shdr.s64[i].sh_addr);
+ consider_shdr (undo_interp, shdr.s64[i].sh_type,
+ shdr.s64[i].sh_flags, shdr.s64[i].sh_addr);
if (highest > mod->debug.vaddr)
mod->debug.address_sync = highest;