diff options
Diffstat (limited to 'elfutils/libdwfl/dwfl_module_getdwarf.c')
-rw-r--r-- | elfutils/libdwfl/dwfl_module_getdwarf.c | 57 |
1 files changed, 54 insertions, 3 deletions
diff --git a/elfutils/libdwfl/dwfl_module_getdwarf.c b/elfutils/libdwfl/dwfl_module_getdwarf.c index b084673e..41ed0730 100644 --- a/elfutils/libdwfl/dwfl_module_getdwarf.c +++ b/elfutils/libdwfl/dwfl_module_getdwarf.c @@ -75,6 +75,8 @@ open_elf (Dwfl_Module *mod, struct dwfl_file *file) } else if (unlikely (elf_kind (file->elf) != ELF_K_ELF)) { + elf_end (file->elf); + file->elf = NULL; close (file->fd); file->fd = -1; return DWFL_E_BADELF; @@ -84,6 +86,8 @@ open_elf (Dwfl_Module *mod, struct dwfl_file *file) if (ehdr == NULL) { elf_error: + elf_end (file->elf); + file->elf = NULL; close (file->fd); file->fd = -1; return DWFL_E (LIBELF, elf_errno ()); @@ -108,8 +112,16 @@ open_elf (Dwfl_Module *mod, struct dwfl_file *file) goto elf_error; if (ph->p_type == PT_LOAD) { - file->bias = ((mod->low_addr & -ph->p_align) - - (ph->p_vaddr & -ph->p_align)); + GElf_Addr align = mod->dwfl->segment_align; + if (align <= 1) + { + if ((mod->low_addr & (ph->p_align - 1)) == 0) + align = ph->p_align; + else + align = ((GElf_Addr) 1 << ffsll (mod->low_addr)) >> 1; + } + + file->bias = ((mod->low_addr & -align) - (ph->p_vaddr & -align)); break; } } @@ -137,9 +149,12 @@ __libdwfl_getelf (Dwfl_Module *mod) mod->main.fd = (*mod->dwfl->callbacks->find_elf) (MODCB_ARGS (mod), &mod->main.name, &mod->main.elf); + const bool fallback = mod->main.elf == NULL && mod->main.fd < 0; mod->elferr = open_elf (mod, &mod->main); + if (mod->elferr != DWFL_E_NOERROR) + return; - if (mod->elferr == DWFL_E_NOERROR && !mod->main.valid) + if (!mod->main.valid) { /* Clear any explicitly reported build ID, just in case it was wrong. We'll fetch it from the file when asked. */ @@ -147,6 +162,42 @@ __libdwfl_getelf (Dwfl_Module *mod) mod->build_id_bits = NULL; mod->build_id_len = 0; } + else if (fallback) + { + /* We have an authoritative build ID for this module, so + don't use a file by name that doesn't match that ID. */ + + assert (mod->build_id_len > 0); + + switch (__builtin_expect (__libdwfl_find_build_id (mod, false, + mod->main.elf), 2)) + { + case 2: + /* Build ID matches as it should. */ + return; + + case -1: /* ELF error. */ + mod->elferr = INTUSE(dwfl_errno) (); + break; + + case 0: /* File has no build ID note. */ + case 1: /* FIle has a build ID that does not match. */ + mod->elferr = DWFL_E_WRONG_ID_ELF; + break; + + default: + abort (); + } + + /* We get here when it was the right ELF file. Clear it out. */ + elf_end (mod->main.elf); + mod->main.elf = NULL; + if (mod->main.fd >= 0) + { + close (mod->main.fd); + mod->main.fd = -1; + } + } } /* Search an ELF file for a ".gnu_debuglink" section. */ |