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