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

Reply via email to