summaryrefslogtreecommitdiff
path: root/elfutils/libdwfl/dwfl_module_getdwarf.c
diff options
context:
space:
mode:
Diffstat (limited to 'elfutils/libdwfl/dwfl_module_getdwarf.c')
-rw-r--r--elfutils/libdwfl/dwfl_module_getdwarf.c57
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. */