decl.c (gnat_to_gnu_entity): Move down code applying atomic checks to the object.
[gcc.git] / libbacktrace / elf.c
index 659b349f73b7cc7acac6a60c6466f15881c91ffe..3f14b11a43c8388f9220122ce8b3e47e1137e0b5 100644 (file)
@@ -1,5 +1,5 @@
 /* elf.c -- Get debug data from an ELF file for backtraces.
-   Copyright (C) 2012-2013 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,6 +96,7 @@ 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
@@ -171,6 +172,8 @@ typedef struct {
 
 #define EV_CURRENT 1
 
+#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 */
@@ -404,8 +407,8 @@ elf_initialize_syminfo (struct backtrace_state *state,
       ++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;
@@ -442,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;
@@ -490,11 +490,7 @@ elf_syminfo (struct backtrace_state *state, uintptr_t addr,
       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;
-
+         edata = backtrace_atomic_load_pointer (pp);
          if (edata == NULL)
            break;
 
@@ -509,17 +505,21 @@ elf_syminfo (struct backtrace_state *state, uintptr_t addr,
     }
 
   if (sym == NULL)
-    callback (data, addr, NULL, 0);
+    callback (data, addr, NULL, 0, 0);
   else
-    callback (data, addr, 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;
   b_elf_ehdr ehdr;
@@ -598,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;
@@ -854,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
@@ -869,17 +876,32 @@ phdr_callback (struct dl_phdr_info *info, size_t size ATTRIBUTE_UNUSED,
   fileline elf_fileline_fn;
   int found_dwarf;
 
-  /* There is not much we can do if we don't have the module name.  */
+  /* 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')
-    return 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,
-                              &does_not_exist);
-  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)
        {
@@ -900,14 +922,15 @@ 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;
@@ -916,21 +939,23 @@ backtrace_initialize (struct backtrace_state *state, int descriptor,
   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)
@@ -942,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;
     }