On Mon, 22 Jul 2013, Ian Lance Taylor wrote:
> Thanks for noticing the problem.  This patch isn't enough by itself.
> The code has to protect itself against the list changing in
> mid-stream.  See dwarf_fileline in dwarf.c.

Thank you.  Here's the updated patch, however I have to admit it's not
entirely clear to me what __sync_bool_compare_and_swap should achieve.  Is it
only to ensure that we do not use a partially updated pointer (which shouldn't
happen with a naturally aligned pointer on hardware that updates cache lines
atomically)?

2013-07-22  Alexander Monakov  <amona...@ispras.ru>

        * elf.c (elf_syminfo): Loop over the elf_syminfo_data chain.

diff --git a/libbacktrace/elf.c b/libbacktrace/elf.c
index ef9bcdf..1d64a1f 100644
--- a/libbacktrace/elf.c
+++ b/libbacktrace/elf.c
@@ -454,12 +454,46 @@ elf_syminfo (struct backtrace_state *state, uintptr_t pc,
             void *data)
 {
   struct elf_syminfo_data *edata;
-  struct elf_symbol *sym;
+  struct elf_symbol *sym = NULL;
+
+  if (!state->threaded)
+    {
+      for (edata = (struct elf_syminfo_data *) state->syminfo_data;
+          edata;
+          edata = edata->next)
+       {
+         sym = ((struct elf_symbol *)
+                bsearch (&pc, edata->symbols, edata->count,
+                         sizeof (struct elf_symbol), elf_symbol_search));
+         if (sym != NULL)
+           break;
+       }
+    }
+  else
+    {
+      struct elf_syminfo_data **pp;
+
+      pp = (struct elf_syminfo_data **) (void *) &state->syminfo_data;
+      while (1)
+       {
+         edata = *pp;
+         /* Atomic load.  */
+         while (!__sync_bool_compare_and_swap (pp, edata, edata))
+           edata = *pp;
+
+         if (edata == NULL)
+           break;
+
+         sym = ((struct elf_symbol *)
+                bsearch (&pc, edata->symbols, edata->count,
+                         sizeof (struct elf_symbol), elf_symbol_search));
+         if (sym != NULL)
+           break;
+
+         pp = &edata->next;
+       }
+    }

-  edata = (struct elf_syminfo_data *) state->syminfo_data;
-  sym = ((struct elf_symbol *)
-        bsearch (&pc, edata->symbols, edata->count,
-                 sizeof (struct elf_symbol), elf_symbol_search));
   if (sym == NULL)
     callback (data, pc, NULL, 0);
   else

Reply via email to