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. Signed-off-by: Aaron Merey <[email protected]> --- libdwfl/dwfl_module_getdwarf.c | 24 +++++++++++++++------ libdwfl/dwfl_module_getsym.c | 3 ++- libdwfl/dwfl_module_register_names.c | 11 ++++------ libdwfl/dwfl_module_return_value_location.c | 11 ++++------ 4 files changed, 28 insertions(+), 21 deletions(-) diff --git a/libdwfl/dwfl_module_getdwarf.c b/libdwfl/dwfl_module_getdwarf.c index 247fbbd2..cb11b1f3 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..4905f019 100644 --- a/libdwfl/dwfl_module_getsym.c +++ b/libdwfl/dwfl_module_getsym.c @@ -124,7 +124,8 @@ __libdwfl_getsym (Dwfl_Module *mod, int ndx, GElf_Sym *sym, GElf_Addr *addr, descriptors). */ char *ident; - GElf_Addr st_value = sym->st_value & ebl_func_addr_mask (mod->ebl); + Ebl *ebl = atomic_load_acquire (&mod->ebl); + GElf_Addr st_value = sym->st_value & ebl_func_addr_mask (ebl); *resolved = false; if (! adjust_st_value && mod->e_type != ET_REL && alloc && (GELF_ST_TYPE (sym->st_info) == STT_FUNC 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
