decl.c (gnat_to_gnu_entity): Move down code applying atomic checks to the object.
[gcc.git] / libbacktrace / elf.c
index 518e125a101c5e55d13ee41a4707c72c08f0acf6..3f14b11a43c8388f9220122ce8b3e47e1137e0b5 100644 (file)
@@ -1,5 +1,5 @@
 /* elf.c -- Get debug data from an ELF file for backtraces.
-   Copyright (C) 2012 Free Software Foundation, Inc.
+   Copyright (C) 2012-2015 Free Software Foundation, Inc.
    Written by Ian Lance Taylor, Google.
 
 Redistribution and use in source and binary forms, with or without
@@ -96,34 +96,37 @@ dl_iterate_phdr (int (*callback) (struct dl_phdr_info *,
 #undef ELFDATA2LSB
 #undef ELFDATA2MSB
 #undef EV_CURRENT
+#undef ET_DYN
 #undef SHN_LORESERVE
 #undef SHN_XINDEX
+#undef SHN_UNDEF
 #undef SHT_SYMTAB
 #undef SHT_STRTAB
 #undef SHT_DYNSYM
+#undef STT_OBJECT
 #undef STT_FUNC
 
 /* Basic types.  */
 
-typedef uint16_t Elf_Half;
-typedef uint32_t Elf_Word;
-typedef int32_t  Elf_Sword;
+typedef uint16_t b_elf_half;    /* Elf_Half.  */
+typedef uint32_t b_elf_word;    /* Elf_Word.  */
+typedef int32_t  b_elf_sword;   /* Elf_Sword.  */
 
 #if BACKTRACE_ELF_SIZE == 32
 
-typedef uint32_t Elf_Addr;
-typedef uint32_t Elf_Off;
+typedef uint32_t b_elf_addr;    /* Elf_Addr.  */
+typedef uint32_t b_elf_off;     /* Elf_Off.  */
 
-typedef uint32_t Elf_WXword;
+typedef uint32_t b_elf_wxword;  /* 32-bit Elf_Word, 64-bit ELF_Xword.  */
 
 #else
 
-typedef uint64_t Elf_Addr;
-typedef uint64_t Elf_Off;
-typedef uint64_t Elf_Xword;
-typedef int64_t  Elf_Sxword;
+typedef uint64_t b_elf_addr;    /* Elf_Addr.  */
+typedef uint64_t b_elf_off;     /* Elf_Off.  */
+typedef uint64_t b_elf_xword;   /* Elf_Xword.  */
+typedef int64_t  b_elf_sxword;  /* Elf_Sxword.  */
 
-typedef uint64_t Elf_WXword;
+typedef uint64_t b_elf_wxword;  /* 32-bit Elf_Word, 64-bit ELF_Xword.  */
 
 #endif
 
@@ -133,20 +136,20 @@ typedef uint64_t Elf_WXword;
 
 typedef struct {
   unsigned char        e_ident[EI_NIDENT];     /* ELF "magic number" */
-  Elf_Half     e_type;                 /* Identifies object file type */
-  Elf_Half     e_machine;              /* Specifies required architecture */
-  Elf_Word     e_version;              /* Identifies object file version */
-  Elf_Addr     e_entry;                /* Entry point virtual address */
-  Elf_Off      e_phoff;                /* Program header table file offset */
-  Elf_Off      e_shoff;                /* Section header table file offset */
-  Elf_Word     e_flags;                /* Processor-specific flags */
-  Elf_Half     e_ehsize;               /* ELF header size in bytes */
-  Elf_Half     e_phentsize;            /* Program header table entry size */
-  Elf_Half     e_phnum;                /* Program header table entry count */
-  Elf_Half     e_shentsize;            /* Section header table entry size */
-  Elf_Half     e_shnum;                /* Section header table entry count */
-  Elf_Half     e_shstrndx;             /* Section header string table index */
-} Elf_Ehdr;
+  b_elf_half   e_type;                 /* Identifies object file type */
+  b_elf_half   e_machine;              /* Specifies required architecture */
+  b_elf_word   e_version;              /* Identifies object file version */
+  b_elf_addr   e_entry;                /* Entry point virtual address */
+  b_elf_off    e_phoff;                /* Program header table file offset */
+  b_elf_off    e_shoff;                /* Section header table file offset */
+  b_elf_word   e_flags;                /* Processor-specific flags */
+  b_elf_half   e_ehsize;               /* ELF header size in bytes */
+  b_elf_half   e_phentsize;            /* Program header table entry size */
+  b_elf_half   e_phnum;                /* Program header table entry count */
+  b_elf_half   e_shentsize;            /* Section header table entry size */
+  b_elf_half   e_shnum;                /* Section header table entry count */
+  b_elf_half   e_shstrndx;             /* Section header string table index */
+} b_elf_ehdr;  /* Elf_Ehdr.  */
 
 #define EI_MAG0 0
 #define EI_MAG1 1
@@ -169,19 +172,22 @@ typedef struct {
 
 #define EV_CURRENT 1
 
-typedef struct {
-  Elf_Word     sh_name;                /* Section name, index in string tbl */
-  Elf_Word     sh_type;                /* Type of section */
-  Elf_WXword   sh_flags;               /* Miscellaneous section attributes */
-  Elf_Addr     sh_addr;                /* Section virtual addr at execution */
-  Elf_Off      sh_offset;              /* Section file offset */
-  Elf_WXword   sh_size;                /* Size of section in bytes */
-  Elf_Word     sh_link;                /* Index of another section */
-  Elf_Word     sh_info;                /* Additional section information */
-  Elf_WXword   sh_addralign;           /* Section alignment */
-  Elf_WXword   sh_entsize;             /* Entry size if section holds table */
-} Elf_Shdr;
+#define ET_DYN 3
 
+typedef struct {
+  b_elf_word   sh_name;                /* Section name, index in string tbl */
+  b_elf_word   sh_type;                /* Type of section */
+  b_elf_wxword sh_flags;               /* Miscellaneous section attributes */
+  b_elf_addr   sh_addr;                /* Section virtual addr at execution */
+  b_elf_off    sh_offset;              /* Section file offset */
+  b_elf_wxword sh_size;                /* Size of section in bytes */
+  b_elf_word   sh_link;                /* Index of another section */
+  b_elf_word   sh_info;                /* Additional section information */
+  b_elf_wxword sh_addralign;           /* Section alignment */
+  b_elf_wxword sh_entsize;             /* Entry size if section holds table */
+} b_elf_shdr;  /* Elf_Shdr.  */
+
+#define SHN_UNDEF      0x0000          /* Undefined section */
 #define SHN_LORESERVE  0xFF00          /* Begin range of reserved indices */
 #define SHN_XINDEX     0xFFFF          /* Section index is held elsewhere */
 
@@ -193,28 +199,29 @@ typedef struct {
 
 typedef struct
 {
-  Elf_Word     st_name;                /* Symbol name, index in string tbl */
-  Elf_Addr     st_value;               /* Symbol value */
-  Elf_Word     st_size;                /* Symbol size */
+  b_elf_word   st_name;                /* Symbol name, index in string tbl */
+  b_elf_addr   st_value;               /* Symbol value */
+  b_elf_word   st_size;                /* Symbol size */
   unsigned char        st_info;                /* Symbol binding and type */
   unsigned char        st_other;               /* Visibility and other data */
-  Elf_Half     st_shndx;               /* Symbol section index */
-} Elf_Sym;
+  b_elf_half   st_shndx;               /* Symbol section index */
+} b_elf_sym;  /* Elf_Sym.  */
 
 #else /* BACKTRACE_ELF_SIZE != 32 */
 
 typedef struct
 {
-  Elf_Word     st_name;                /* Symbol name, index in string tbl */
+  b_elf_word   st_name;                /* Symbol name, index in string tbl */
   unsigned char        st_info;                /* Symbol binding and type */
   unsigned char        st_other;               /* Visibility and other data */
-  Elf_Half     st_shndx;               /* Symbol section index */
-  Elf_Addr     st_value;               /* Symbol value */
-  Elf_Xword    st_size;                /* Symbol size */
-} Elf_Sym;
+  b_elf_half   st_shndx;               /* Symbol section index */
+  b_elf_addr   st_value;               /* Symbol value */
+  b_elf_xword  st_size;                /* Symbol size */
+} b_elf_sym;  /* Elf_Sym.  */
 
 #endif /* BACKTRACE_ELF_SIZE != 32 */
 
+#define STT_OBJECT 1
 #define STT_FUNC 2
 
 /* An index of ELF sections we care about.  */
@@ -293,7 +300,7 @@ elf_nodebug (struct backtrace_state *state ATTRIBUTE_UNUSED,
 
 static void
 elf_nosyms (struct backtrace_state *state ATTRIBUTE_UNUSED,
-           uintptr_t pc ATTRIBUTE_UNUSED,
+           uintptr_t addr ATTRIBUTE_UNUSED,
            backtrace_syminfo_callback callback ATTRIBUTE_UNUSED,
            backtrace_error_callback error_callback, void *data)
 {
@@ -316,7 +323,7 @@ elf_symbol_compare (const void *v1, const void *v2)
     return 0;
 }
 
-/* Compare a PC against an elf_symbol for bsearch.  We allocate one
+/* Compare an ADDR against an elf_symbol for bsearch.  We allocate one
    extra entry in the array so that this can look safely at the next
    entry.  */
 
@@ -325,12 +332,12 @@ elf_symbol_search (const void *vkey, const void *ventry)
 {
   const uintptr_t *key = (const uintptr_t *) vkey;
   const struct elf_symbol *entry = (const struct elf_symbol *) ventry;
-  uintptr_t pc;
+  uintptr_t addr;
 
-  pc = *key;
-  if (pc < entry->address)
+  addr = *key;
+  if (addr < entry->address)
     return -1;
-  else if (pc >= entry->address + entry->size)
+  else if (addr >= entry->address + entry->size)
     return 1;
   else
     return 0;
@@ -340,27 +347,32 @@ elf_symbol_search (const void *vkey, const void *ventry)
 
 static int
 elf_initialize_syminfo (struct backtrace_state *state,
+                       uintptr_t base_address,
                        const unsigned char *symtab_data, size_t symtab_size,
                        const unsigned char *strtab, size_t strtab_size,
                        backtrace_error_callback error_callback,
                        void *data, struct elf_syminfo_data *sdata)
 {
   size_t sym_count;
-  const Elf_Sym *sym;
+  const b_elf_sym *sym;
   size_t elf_symbol_count;
   size_t elf_symbol_size;
   struct elf_symbol *elf_symbols;
   size_t i;
   unsigned int j;
 
-  sym_count = symtab_size / sizeof (Elf_Sym);
+  sym_count = symtab_size / sizeof (b_elf_sym);
 
   /* We only care about function symbols.  Count them.  */
-  sym = (const Elf_Sym *) symtab_data;
+  sym = (const b_elf_sym *) symtab_data;
   elf_symbol_count = 0;
   for (i = 0; i < sym_count; ++i, ++sym)
     {
-      if ((sym->st_info & 0xf) == STT_FUNC)
+      int info;
+
+      info = sym->st_info & 0xf;
+      if ((info == STT_FUNC || info == STT_OBJECT)
+         && sym->st_shndx != SHN_UNDEF)
        ++elf_symbol_count;
     }
 
@@ -371,11 +383,16 @@ elf_initialize_syminfo (struct backtrace_state *state,
   if (elf_symbols == NULL)
     return 0;
 
-  sym = (const Elf_Sym *) symtab_data;
+  sym = (const b_elf_sym *) symtab_data;
   j = 0;
   for (i = 0; i < sym_count; ++i, ++sym)
     {
-      if ((sym->st_info & 0xf) != STT_FUNC)
+      int info;
+
+      info = sym->st_info & 0xf;
+      if (info != STT_FUNC && info != STT_OBJECT)
+       continue;
+      if (sym->st_shndx == SHN_UNDEF)
        continue;
       if (sym->st_name >= strtab_size)
        {
@@ -385,13 +402,13 @@ elf_initialize_syminfo (struct backtrace_state *state,
          return 0;
        }
       elf_symbols[j].name = (const char *) strtab + sym->st_name;
-      elf_symbols[j].address = sym->st_value;
+      elf_symbols[j].address = sym->st_value + base_address;
       elf_symbols[j].size = sym->st_size;
       ++j;
     }
 
-  qsort (elf_symbols, elf_symbol_count, sizeof (struct elf_symbol),
-        elf_symbol_compare);
+  backtrace_qsort (elf_symbols, elf_symbol_count, sizeof (struct elf_symbol),
+                  elf_symbol_compare);
 
   sdata->next = NULL;
   sdata->symbols = elf_symbols;
@@ -428,10 +445,7 @@ elf_add_syminfo_data (struct backtrace_state *state,
            {
              struct elf_syminfo_data *p;
 
-             /* Atomic load.  */
-             p = *pp;
-             while (!__sync_bool_compare_and_swap (pp, p, p))
-               p = *pp;
+             p = backtrace_atomic_load_pointer (pp);
 
              if (p == NULL)
                break;
@@ -445,43 +459,77 @@ elf_add_syminfo_data (struct backtrace_state *state,
     }
 }
 
-/* Return the symbol name and value for a PC.  */
+/* Return the symbol name and value for an ADDR.  */
 
 static void
-elf_syminfo (struct backtrace_state *state, uintptr_t pc,
+elf_syminfo (struct backtrace_state *state, uintptr_t addr,
             backtrace_syminfo_callback callback,
             backtrace_error_callback error_callback ATTRIBUTE_UNUSED,
             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 != NULL;
+          edata = edata->next)
+       {
+         sym = ((struct elf_symbol *)
+                bsearch (&addr, 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 = backtrace_atomic_load_pointer (pp);
+         if (edata == NULL)
+           break;
+
+         sym = ((struct elf_symbol *)
+                bsearch (&addr, 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);
+    callback (data, addr, NULL, 0, 0);
   else
-    callback (data, pc, sym->name, sym->address);
+    callback (data, addr, sym->name, sym->address, sym->size);
 }
 
-/* Add the backtrace data for one ELF file.  */
+/* Add the backtrace data for one ELF file.  Returns 1 on success,
+   0 on failure (in both cases descriptor is closed) or -1 if exe
+   is non-zero and the ELF file is ET_DYN, which tells the caller that
+   elf_add will need to be called on the descriptor again after
+   base_address is determined.  */
 
 static int
 elf_add (struct backtrace_state *state, int descriptor, uintptr_t base_address,
         backtrace_error_callback error_callback, void *data,
-        fileline *fileline_fn, int *found_sym, int *found_dwarf)
+        fileline *fileline_fn, int *found_sym, int *found_dwarf, int exe)
 {
   struct backtrace_view ehdr_view;
-  Elf_Ehdr ehdr;
+  b_elf_ehdr ehdr;
   off_t shoff;
   unsigned int shnum;
   unsigned int shstrndx;
   struct backtrace_view shdrs_view;
   int shdrs_view_valid;
-  const Elf_Shdr *shdrs;
-  const Elf_Shdr *shstrhdr;
+  const b_elf_shdr *shdrs;
+  const b_elf_shdr *shstrhdr;
   size_t shstr_size;
   off_t shstr_off;
   struct backtrace_view names_view;
@@ -550,6 +598,12 @@ elf_add (struct backtrace_state *state, int descriptor, uintptr_t base_address,
       goto fail;
     }
 
+  /* If the executable is ET_DYN, it is either a PIE, or we are running
+     directly a shared library with .interp.  We need to wait for
+     dl_iterate_phdr in that case to determine the actual base_address.  */
+  if (exe && ehdr.e_type == ET_DYN)
+    return -1;
+
   shoff = ehdr.e_shoff;
   shnum = ehdr.e_shnum;
   shstrndx = ehdr.e_shstrndx;
@@ -558,13 +612,13 @@ elf_add (struct backtrace_state *state, int descriptor, uintptr_t base_address,
       && shoff != 0)
     {
       struct backtrace_view shdr_view;
-      const Elf_Shdr *shdr;
+      const b_elf_shdr *shdr;
 
       if (!backtrace_get_view (state, descriptor, shoff, sizeof shdr,
                               error_callback, data, &shdr_view))
        goto fail;
 
-      shdr = (const Elf_Shdr *) shdr_view.data;
+      shdr = (const b_elf_shdr *) shdr_view.data;
 
       if (shnum == 0)
        shnum = shdr->sh_size;
@@ -596,12 +650,12 @@ elf_add (struct backtrace_state *state, int descriptor, uintptr_t base_address,
 
   /* Read the section headers, skipping the first one.  */
 
-  if (!backtrace_get_view (state, descriptor, shoff + sizeof (Elf_Shdr),
-                          (shnum - 1) * sizeof (Elf_Shdr),
+  if (!backtrace_get_view (state, descriptor, shoff + sizeof (b_elf_shdr),
+                          (shnum - 1) * sizeof (b_elf_shdr),
                           error_callback, data, &shdrs_view))
     goto fail;
   shdrs_view_valid = 1;
-  shdrs = (const Elf_Shdr *) shdrs_view.data;
+  shdrs = (const b_elf_shdr *) shdrs_view.data;
 
   /* Read the section names.  */
 
@@ -623,7 +677,7 @@ elf_add (struct backtrace_state *state, int descriptor, uintptr_t base_address,
   /* Look for the symbol table.  */
   for (i = 1; i < shnum; ++i)
     {
-      const Elf_Shdr *shdr;
+      const b_elf_shdr *shdr;
       unsigned int sh_name;
       const char *name;
       int j;
@@ -659,9 +713,9 @@ elf_add (struct backtrace_state *state, int descriptor, uintptr_t base_address,
     symtab_shndx = dynsym_shndx;
   if (symtab_shndx != 0)
     {
-      const Elf_Shdr *symtab_shdr;
+      const b_elf_shdr *symtab_shdr;
       unsigned int strtab_shndx;
-      const Elf_Shdr *strtab_shdr;
+      const b_elf_shdr *strtab_shdr;
       struct elf_syminfo_data *sdata;
 
       symtab_shdr = &shdrs[symtab_shndx - 1];
@@ -691,7 +745,7 @@ elf_add (struct backtrace_state *state, int descriptor, uintptr_t base_address,
       if (sdata == NULL)
        goto fail;
 
-      if (!elf_initialize_syminfo (state,
+      if (!elf_initialize_syminfo (state, base_address,
                                   symtab_view.data, symtab_shdr->sh_size,
                                   strtab_view.data, strtab_shdr->sh_size,
                                   error_callback, data, sdata))
@@ -725,6 +779,8 @@ elf_add (struct backtrace_state *state, int descriptor, uintptr_t base_address,
     {
       off_t end;
 
+      if (sections[i].size == 0)
+       continue;
       if (min_offset == 0 || sections[i].offset < min_offset)
        min_offset = sections[i].offset;
       end = sections[i].offset + sections[i].size;
@@ -751,8 +807,13 @@ elf_add (struct backtrace_state *state, int descriptor, uintptr_t base_address,
   descriptor = -1;
 
   for (i = 0; i < (int) DEBUG_MAX; ++i)
-    sections[i].data = ((const unsigned char *) debug_view.data
-                       + (sections[i].offset - min_offset));
+    {
+      if (sections[i].size == 0)
+       sections[i].data = NULL;
+      else
+       sections[i].data = ((const unsigned char *) debug_view.data
+                           + (sections[i].offset - min_offset));
+    }
 
   if (!backtrace_dwarf_add (state, base_address,
                            sections[DEBUG_INFO].data,
@@ -799,6 +860,7 @@ struct phdr_data
   fileline *fileline_fn;
   int *found_sym;
   int *found_dwarf;
+  int exe_descriptor;
 };
 
 /* Callback passed to dl_iterate_phdr.  Load debug info from shared
@@ -810,23 +872,36 @@ phdr_callback (struct dl_phdr_info *info, size_t size ATTRIBUTE_UNUSED,
 {
   struct phdr_data *pd = (struct phdr_data *) pdata;
   int descriptor;
+  int does_not_exist;
   fileline elf_fileline_fn;
   int found_dwarf;
 
-  /* There is not much we can do if we don't have the module name.  If
-     the base address is 0, this is probably the executable, which we
-     already loaded.  */
-  if (info->dlpi_name == NULL
-      || info->dlpi_name[0] == '\0'
-      || info->dlpi_addr == 0)
-    return 0;
+  /* There is not much we can do if we don't have the module name,
+     unless executable is ET_DYN, where we expect the very first
+     phdr_callback to be for the PIE.  */
+  if (info->dlpi_name == NULL || info->dlpi_name[0] == '\0')
+    {
+      if (pd->exe_descriptor == -1)
+       return 0;
+      descriptor = pd->exe_descriptor;
+      pd->exe_descriptor = -1;
+    }
+  else
+    {
+      if (pd->exe_descriptor != -1)
+       {
+         backtrace_close (pd->exe_descriptor, pd->error_callback, pd->data);
+         pd->exe_descriptor = -1;
+       }
 
-  descriptor = backtrace_open (info->dlpi_name, pd->error_callback, pd->data);
-  if (descriptor < 0)
-    return 0;
+      descriptor = backtrace_open (info->dlpi_name, pd->error_callback,
+                                  pd->data, &does_not_exist);
+      if (descriptor < 0)
+       return 0;
+    }
 
   if (elf_add (pd->state, descriptor, info->dlpi_addr, pd->error_callback,
-              pd->data, &elf_fileline_fn, pd->found_sym, &found_dwarf))
+              pd->data, &elf_fileline_fn, pd->found_sym, &found_dwarf, 0))
     {
       if (found_dwarf)
        {
@@ -847,37 +922,40 @@ backtrace_initialize (struct backtrace_state *state, int descriptor,
                      backtrace_error_callback error_callback,
                      void *data, fileline *fileline_fn)
 {
+  int ret;
   int found_sym;
   int found_dwarf;
-  syminfo elf_syminfo_fn;
   fileline elf_fileline_fn;
   struct phdr_data pd;
 
-  if (!elf_add (state, descriptor, 0, error_callback, data, &elf_fileline_fn,
-               &found_sym, &found_dwarf))
+  ret = elf_add (state, descriptor, 0, error_callback, data, &elf_fileline_fn,
+                &found_sym, &found_dwarf, 1);
+  if (!ret)
     return 0;
 
   pd.state = state;
   pd.error_callback = error_callback;
   pd.data = data;
-  pd.fileline_fn = fileline_fn;
+  pd.fileline_fn = &elf_fileline_fn;
   pd.found_sym = &found_sym;
   pd.found_dwarf = &found_dwarf;
+  pd.exe_descriptor = ret < 0 ? descriptor : -1;
 
   dl_iterate_phdr (phdr_callback, (void *) &pd);
 
-  elf_syminfo_fn = found_sym ? elf_syminfo : elf_nosyms;
   if (!state->threaded)
     {
-      if (state->syminfo_fn == NULL || found_sym)
-       state->syminfo_fn = elf_syminfo_fn;
+      if (found_sym)
+       state->syminfo_fn = elf_syminfo;
+      else if (state->syminfo_fn == NULL)
+       state->syminfo_fn = elf_nosyms;
     }
   else
     {
-      __sync_bool_compare_and_swap (&state->syminfo_fn, NULL, elf_syminfo_fn);
       if (found_sym)
-       __sync_bool_compare_and_swap (&state->syminfo_fn, elf_nosyms,
-                                     elf_syminfo_fn);
+       backtrace_atomic_store_pointer (&state->syminfo_fn, elf_syminfo);
+      else
+       __sync_bool_compare_and_swap (&state->syminfo_fn, NULL, elf_nosyms);
     }
 
   if (!state->threaded)
@@ -889,11 +967,7 @@ backtrace_initialize (struct backtrace_state *state, int descriptor,
     {
       fileline current_fn;
 
-      /* Atomic load.  */
-      current_fn = state->fileline_fn;
-      while (!__sync_bool_compare_and_swap (&state->fileline_fn, current_fn,
-                                           current_fn))
-       current_fn = state->fileline_fn;
+      current_fn = backtrace_atomic_load_pointer (&state->fileline_fn);
       if (current_fn == NULL || current_fn == elf_nodebug)
        *fileline_fn = elf_fileline_fn;
     }