From: Omar Sandoval <osan...@fb.com> dwfl_addrmodule matches a module if the address lies within low_addr and high_addr. This is incorrect for relocatable files, particularly kernel modules: sections of different modules can be intermingled within the same range of addresses. Instead, we should index each section independently.
Signed-off-by: Omar Sandoval <osan...@fb.com> --- libdwfl/ChangeLog | 6 ++++++ libdwfl/derelocate.c | 24 ++++++------------------ libdwfl/dwfl_addrmodule.c | 25 +++++++++++++++++++++---- libdwfl/libdwflP.h | 17 +++++++++++++++++ 4 files changed, 50 insertions(+), 22 deletions(-) diff --git a/libdwfl/ChangeLog b/libdwfl/ChangeLog index 8dc20961..d55aeb47 100644 --- a/libdwfl/ChangeLog +++ b/libdwfl/ChangeLog @@ -4,6 +4,8 @@ (Dwfl_Module): Remove coalescing state. Rename lookup_tail_ndx to next_segndx. Rename segment member to lookup. + (struct dwfl_relocation): Move from derelocate.c + (__libdwfl_cache_sections): Add. (Dwfl): Replace module lookup table with new definition. * relocate.c (__libdwfl_relocate_value): Return DWFL_E_NOT_LOADED if section is not loaded. @@ -14,6 +16,7 @@ (dwfl_addrsegment): Use dwfl_addrmodule to get module. * libdwfl.h (dwfl_report_segment): Document that IDENT is now ignored. * dwfl_addrmodule.c: Add new module lookup table implementation. + Index sections for relocatable files instead of full address range. (dwfl_addrmodule): Use new module lookup table instead of dwfl_addrsegment. * dwfl_getmodules.c (dwfl_getmodules): Use new module lookup table. @@ -21,6 +24,9 @@ (use): Likewise. * link_map.c: Use dwfl_addrmodule instead of dwfl_addrsegment when segment index is not needed. + * derelocate.c (struct dwfl_relocation): Move to libdwflP.h. + (cache_sections): Rename to __libdwfl_cache_sections and make + non-static. 2019-12-05 Mark Wielaard <m...@klomp.org> diff --git a/libdwfl/derelocate.c b/libdwfl/derelocate.c index 2f80b20f..238aa6e2 100644 --- a/libdwfl/derelocate.c +++ b/libdwfl/derelocate.c @@ -32,19 +32,6 @@ #include "libdwflP.h" -struct dwfl_relocation -{ - size_t count; - struct - { - Elf_Scn *scn; - Elf_Scn *relocs; - const char *name; - GElf_Addr start, end; - } refs[0]; -}; - - struct secref { struct secref *next; @@ -76,8 +63,9 @@ compare_secrefs (const void *a, const void *b) return elf_ndxscn ((*p1)->scn) - elf_ndxscn ((*p2)->scn); } -static int -cache_sections (Dwfl_Module *mod) +int +internal_function +__libdwfl_cache_sections (Dwfl_Module *mod) { if (likely (mod->reloc_info != NULL)) return mod->reloc_info->count; @@ -242,7 +230,7 @@ dwfl_module_relocations (Dwfl_Module *mod) switch (mod->e_type) { case ET_REL: - return cache_sections (mod); + return __libdwfl_cache_sections (mod); case ET_DYN: return 1; @@ -278,7 +266,7 @@ dwfl_module_relocation_info (Dwfl_Module *mod, unsigned int idx, return NULL; } - if (cache_sections (mod) < 0) + if (__libdwfl_cache_sections (mod) < 0) return NULL; struct dwfl_relocation *sections = mod->reloc_info; @@ -330,7 +318,7 @@ check_module (Dwfl_Module *mod) static int find_section (Dwfl_Module *mod, Dwarf_Addr *addr) { - if (cache_sections (mod) < 0) + if (__libdwfl_cache_sections (mod) < 0) return -1; struct dwfl_relocation *sections = mod->reloc_info; diff --git a/libdwfl/dwfl_addrmodule.c b/libdwfl/dwfl_addrmodule.c index 21db4883..1eb45317 100644 --- a/libdwfl/dwfl_addrmodule.c +++ b/libdwfl/dwfl_addrmodule.c @@ -74,10 +74,27 @@ create_lookup_module (Dwfl *dwfl) for (Dwfl_Module *mod = dwfl->modulelist; mod != NULL; mod = mod->next) if (! mod->gc) { - GElf_Addr start = __libdwfl_segment_start(dwfl, mod->low_addr); - GElf_Addr end = __libdwfl_segment_end(dwfl, mod->high_addr); - if (append_lookup_module(dwfl, mod, start, end)) - return true; + Dwarf_Addr bias; + if (mod->dwfl->callbacks->find_elf + && dwfl_module_getdwarf(mod, &bias) + && mod->e_type == ET_REL) + { + if (__libdwfl_cache_sections (mod) < 0) + return true; + + struct dwfl_relocation *sections = mod->reloc_info; + for (size_t i = 0; i < sections->count; i++) + if (append_lookup_module(dwfl, mod, sections->refs[i].start, + sections->refs[i].end)) + return true; + } + else + { + GElf_Addr start = __libdwfl_segment_start(dwfl, mod->low_addr); + GElf_Addr end = __libdwfl_segment_end(dwfl, mod->high_addr); + if (append_lookup_module(dwfl, mod, start, end)) + return true; + } } qsort (dwfl->lookup_module, dwfl->lookup_module_elts, diff --git a/libdwfl/libdwflP.h b/libdwfl/libdwflP.h index 6661cc4c..2589eb66 100644 --- a/libdwfl/libdwflP.h +++ b/libdwfl/libdwflP.h @@ -169,6 +169,18 @@ struct dwfl_file GElf_Addr address_sync; }; +struct dwfl_relocation +{ + size_t count; + struct + { + Elf_Scn *scn; + Elf_Scn *relocs; + const char *name; + GElf_Addr start, end; + } refs[0]; +}; + struct Dwfl_Module { Dwfl *dwfl; @@ -486,6 +498,11 @@ extern void __libdwfl_getelf (Dwfl_Module *mod) internal_function; extern Dwfl_Error __libdwfl_relocate (Dwfl_Module *mod, Elf *file, bool debug) internal_function; +/* Cache SHF_ALLOC sections in MOD->reloc_info. Returns the number of sections + on success or -1 on error. */ +extern int __libdwfl_cache_sections (Dwfl_Module *mod) + internal_function; + /* Find the section index in mod->main.elf that contains the given *ADDR. Adjusts *ADDR to be section relative on success, returns SHN_UNDEF on failure. */ -- 2.24.0