Store a Dwfl_Module's ebl field atomically in __libdwfl_module_getebl while holding the associated Dwfl load_lock.
Change usage of the ebl field so that before using it's either been atomically read or else it's used after __libdwfl_module_getebl returns DWFL_E_NOERROR. In __libdwfl_getsym also initialize the backend before calling ebl_func_addr_mask and return early if it fails. Also fix a bug where ebl wasn't initialized before calling ebl_func_addr_mask. Signed-off-by: Aaron Merey <[email protected]> --- v2 changes: Initialize the backend before calling ebl_func_addr_mask. libdwfl/dwfl_module_getdwarf.c | 24 +++++++++++++++------ libdwfl/dwfl_module_getsym.c | 24 ++++++++++++--------- libdwfl/dwfl_module_register_names.c | 11 ++++------ libdwfl/dwfl_module_return_value_location.c | 11 ++++------ 4 files changed, 40 insertions(+), 30 deletions(-) diff --git a/libdwfl/dwfl_module_getdwarf.c b/libdwfl/dwfl_module_getdwarf.c index 77af5189..8420ba20 100644 --- a/libdwfl/dwfl_module_getdwarf.c +++ b/libdwfl/dwfl_module_getdwarf.c @@ -1345,17 +1345,29 @@ Dwfl_Error internal_function __libdwfl_module_getebl (Dwfl_Module *mod) { + if (likely (atomic_load_acquire (&mod->ebl) != NULL)) + return DWFL_E_NOERROR; + + Dwfl_Error ret = DWFL_E_NOERROR; + mutex_lock (mod->dwfl->load_lock); + if (mod->ebl == NULL) { __libdwfl_getelf (mod); - if (mod->elferr != DWFL_E_NOERROR) - return mod->elferr; + ret = mod->elferr; - mod->ebl = ebl_openbackend (mod->main.elf); - if (mod->ebl == NULL) - return DWFL_E_LIBEBL; + if (ret == DWFL_E_NOERROR) + { + Ebl *ebl = ebl_openbackend (mod->main.elf); + if (ebl == NULL) + ret = DWFL_E_LIBEBL; + else + atomic_store_release (&mod->ebl, ebl); + } } - return DWFL_E_NOERROR; + + mutex_unlock (mod->dwfl->load_lock); + return ret; } /* Try to start up libdw on DEBUGFILE. */ diff --git a/libdwfl/dwfl_module_getsym.c b/libdwfl/dwfl_module_getsym.c index 2bb07fd8..3a364a76 100644 --- a/libdwfl/dwfl_module_getsym.c +++ b/libdwfl/dwfl_module_getsym.c @@ -123,6 +123,13 @@ __libdwfl_getsym (Dwfl_Module *mod, int ndx, GElf_Sym *sym, GElf_Addr *addr, might know where the real value is (e.g. for function descriptors). */ + Dwfl_Error error = __libdwfl_module_getebl (mod); + if (unlikely (error != DWFL_E_NOERROR)) + { + __libdwfl_seterrno (error); + return NULL; + } + char *ident; GElf_Addr st_value = sym->st_value & ebl_func_addr_mask (mod->ebl); *resolved = false; @@ -132,18 +139,15 @@ __libdwfl_getsym (Dwfl_Module *mod, int ndx, GElf_Sym *sym, GElf_Addr *addr, && (ident = elf_getident (elf, NULL)) != NULL && ident[EI_OSABI] == ELFOSABI_LINUX))) { - if (likely (__libdwfl_module_getebl (mod) == DWFL_E_NOERROR)) + if (elf != mod->main.elf) { - if (elf != mod->main.elf) - { - st_value = dwfl_adjusted_st_value (mod, elf, st_value); - st_value = dwfl_deadjust_st_value (mod, mod->main.elf, st_value); - } - - *resolved = ebl_resolve_sym_value (mod->ebl, &st_value); - if (! *resolved) - st_value = sym->st_value; + st_value = dwfl_adjusted_st_value (mod, elf, st_value); + st_value = dwfl_deadjust_st_value (mod, mod->main.elf, st_value); } + + *resolved = ebl_resolve_sym_value (mod->ebl, &st_value); + if (! *resolved) + st_value = sym->st_value; } if (shndxp != NULL) diff --git a/libdwfl/dwfl_module_register_names.c b/libdwfl/dwfl_module_register_names.c index 9ea09371..a8aa8a65 100644 --- a/libdwfl/dwfl_module_register_names.c +++ b/libdwfl/dwfl_module_register_names.c @@ -43,14 +43,11 @@ dwfl_module_register_names (Dwfl_Module *mod, if (unlikely (mod == NULL)) return -1; - if (unlikely (mod->ebl == NULL)) + Dwfl_Error error = __libdwfl_module_getebl (mod); + if (unlikely (error != DWFL_E_NOERROR)) { - Dwfl_Error error = __libdwfl_module_getebl (mod); - if (error != DWFL_E_NOERROR) - { - __libdwfl_seterrno (error); - return -1; - } + __libdwfl_seterrno (error); + return -1; } int nregs = ebl_register_info (mod->ebl, -1, NULL, 0, diff --git a/libdwfl/dwfl_module_return_value_location.c b/libdwfl/dwfl_module_return_value_location.c index ff6f56f8..8a3e63a9 100644 --- a/libdwfl/dwfl_module_return_value_location.c +++ b/libdwfl/dwfl_module_return_value_location.c @@ -40,14 +40,11 @@ dwfl_module_return_value_location (Dwfl_Module *mod, Dwarf_Die *functypedie, if (mod == NULL) return -1; - if (mod->ebl == NULL) + Dwfl_Error error = __libdwfl_module_getebl (mod); + if (error != DWFL_E_NOERROR) { - Dwfl_Error error = __libdwfl_module_getebl (mod); - if (error != DWFL_E_NOERROR) - { - __libdwfl_seterrno (error); - return -1; - } + __libdwfl_seterrno (error); + return -1; } int nops = ebl_return_value_location (mod->ebl, functypedie, locops); -- 2.56.0
