summaryrefslogtreecommitdiffstats
path: root/libdwfl/dwfl_module_getdwarf.c
diff options
context:
space:
mode:
authorRoland McGrath <roland@redhat.com>2011-02-01 19:06:21 -0800
committerRoland McGrath <roland@redhat.com>2011-02-01 19:06:21 -0800
commit3a44c9a73887acf982ea2752fa16ce66e42105b7 (patch)
tree8673cf877f39548917e47bcf9d0b16f3649e1e71 /libdwfl/dwfl_module_getdwarf.c
parent0ef402035d71bf68c818e7b070d4c6d9744f951d (diff)
downloadandroid_external_elfutils-3a44c9a73887acf982ea2752fa16ce66e42105b7.tar.gz
android_external_elfutils-3a44c9a73887acf982ea2752fa16ce66e42105b7.tar.bz2
android_external_elfutils-3a44c9a73887acf982ea2752fa16ce66e42105b7.zip
libdwfl: Use the section-end address as the synchronization point, rather than sh_addr.
Diffstat (limited to 'libdwfl/dwfl_module_getdwarf.c')
-rw-r--r--libdwfl/dwfl_module_getdwarf.c30
1 files changed, 21 insertions, 9 deletions
diff --git a/libdwfl/dwfl_module_getdwarf.c b/libdwfl/dwfl_module_getdwarf.c
index c7ff8ab9..dbb1d604 100644
--- a/libdwfl/dwfl_module_getdwarf.c
+++ b/libdwfl/dwfl_module_getdwarf.c
@@ -472,21 +472,32 @@ find_prelink_address_sync (Dwfl_Module *mod)
file sections as they are after prelinking, to calculate the
synchronization address of the main file. Then we'll apply that
same method to the saved section headers, to calculate the matching
- synchronization address of the debug file. */
+ synchronization address of the debug file.
+
+ The method is to consider SHF_ALLOC sections that are either
+ SHT_PROGBITS or SHT_NOBITS, excluding the section whose sh_addr
+ matches the PT_INTERP p_vaddr. The special sections that can be
+ moved by prelink have other types, except for .interp (which
+ becomes PT_INTERP). The "real" sections cannot move as such, but
+ .bss can be split into .dynbss and .bss, with the total memory
+ image remaining the same but being spread across the two sections.
+ So we consider the highest section end, which still matches up. */
GElf_Addr highest;
inline void consider_shdr (GElf_Addr interp,
GElf_Word sh_type,
GElf_Xword sh_flags,
- GElf_Addr sh_addr)
+ GElf_Addr sh_addr,
+ GElf_Xword sh_size)
{
if ((sh_flags & SHF_ALLOC)
&& ((sh_type == SHT_PROGBITS && sh_addr != interp)
|| sh_type == SHT_NOBITS))
{
- if (sh_addr > highest)
- highest = sh_addr;
+ const GElf_Addr sh_end = sh_addr + sh_size;
+ if (sh_end > highest)
+ highest = sh_end;
}
}
@@ -498,7 +509,8 @@ 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 (main_interp, sh->sh_type, sh->sh_flags, sh->sh_addr);
+ consider_shdr (main_interp, sh->sh_type, sh->sh_flags,
+ sh->sh_addr, sh->sh_size);
}
if (highest > mod->main.vaddr)
{
@@ -507,12 +519,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 (undo_interp, 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, shdr.s32[i].sh_size);
else
for (size_t i = 0; i < shnum - 1; ++i)
- consider_shdr (undo_interp, 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, shdr.s64[i].sh_size);
if (highest > mod->debug.vaddr)
mod->debug.address_sync = highest;