summaryrefslogtreecommitdiff
path: root/libbacktrace
diff options
context:
space:
mode:
authorIan Lance Taylor <iant@google.com>2013-11-19 01:09:47 +0000
committerIan Lance Taylor <ian@gcc.gnu.org>2013-11-19 01:09:47 +0000
commit49579c7e20da4cf0dc82bf1c8458bf4fc7a38007 (patch)
treea715cbe6fb809ff31f1487b709ea67a6f616cec5 /libbacktrace
parent7f369373da8aa1cfe4aa172d29ae2180a2b31139 (diff)
downloadgcc-49579c7e20da4cf0dc82bf1c8458bf4fc7a38007.tar.gz
configure.ac: Check for support of __atomic extensions.
* configure.ac: Check for support of __atomic extensions. * internal.h: Declare or #define atomic functions for use in backtrace code. * atomic.c: New file. * dwarf.c (dwarf_lookup_pc): Use atomic functions. (dwarf_fileline, backtrace_dwarf_add): Likewise. * elf.c (elf_add_syminfo_data, elf_syminfo): Likewise. (backtrace_initialize): Likewise. * fileline.c (fileline_initialize): Likewise. * Makefile.am (libbacktrace_la_SOURCES): Add atomic.c. * configure, config.h.in, Makefile.in: Rebuild. From-SVN: r204994
Diffstat (limited to 'libbacktrace')
-rw-r--r--libbacktrace/ChangeLog14
-rw-r--r--libbacktrace/Makefile.am1
-rw-r--r--libbacktrace/Makefile.in7
-rw-r--r--libbacktrace/atomic.c111
-rw-r--r--libbacktrace/config.h.in3
-rwxr-xr-xlibbacktrace/configure38
-rw-r--r--libbacktrace/configure.ac18
-rw-r--r--libbacktrace/dwarf.c36
-rw-r--r--libbacktrace/elf.c31
-rw-r--r--libbacktrace/fileline.c40
-rw-r--r--libbacktrace/internal.h43
11 files changed, 263 insertions, 79 deletions
diff --git a/libbacktrace/ChangeLog b/libbacktrace/ChangeLog
index c06194df3e4..134d9a71752 100644
--- a/libbacktrace/ChangeLog
+++ b/libbacktrace/ChangeLog
@@ -1,3 +1,17 @@
+2013-11-18 Ian Lance Taylor <iant@google.com>
+
+ * configure.ac: Check for support of __atomic extensions.
+ * internal.h: Declare or #define atomic functions for use in
+ backtrace code.
+ * atomic.c: New file.
+ * dwarf.c (dwarf_lookup_pc): Use atomic functions.
+ (dwarf_fileline, backtrace_dwarf_add): Likewise.
+ * elf.c (elf_add_syminfo_data, elf_syminfo): Likewise.
+ (backtrace_initialize): Likewise.
+ * fileline.c (fileline_initialize): Likewise.
+ * Makefile.am (libbacktrace_la_SOURCES): Add atomic.c.
+ * configure, config.h.in, Makefile.in: Rebuild.
+
2013-11-18 Jakub Jelinek <jakub@redhat.com>
* elf.c (SHN_UNDEF): Define.
diff --git a/libbacktrace/Makefile.am b/libbacktrace/Makefile.am
index 035986bbf96..20dbde480c5 100644
--- a/libbacktrace/Makefile.am
+++ b/libbacktrace/Makefile.am
@@ -40,6 +40,7 @@ noinst_LTLIBRARIES = libbacktrace.la
libbacktrace_la_SOURCES = \
backtrace.h \
+ atomic.c \
dwarf.c \
fileline.c \
internal.h \
diff --git a/libbacktrace/Makefile.in b/libbacktrace/Makefile.in
index 971406bf6da..a1e144aca17 100644
--- a/libbacktrace/Makefile.in
+++ b/libbacktrace/Makefile.in
@@ -16,7 +16,7 @@
@SET_MAKE@
# Makefile.am -- Backtrace Makefile.
-# Copyright (C) 2012 Free Software Foundation, Inc.
+# Copyright (C) 2012-2013 Free Software Foundation, Inc.
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
@@ -93,8 +93,8 @@ CONFIG_CLEAN_FILES = backtrace-supported.h
CONFIG_CLEAN_VPATH_FILES =
LTLIBRARIES = $(noinst_LTLIBRARIES)
am__DEPENDENCIES_1 =
-am_libbacktrace_la_OBJECTS = dwarf.lo fileline.lo posix.lo print.lo \
- state.lo
+am_libbacktrace_la_OBJECTS = atomic.lo dwarf.lo fileline.lo posix.lo \
+ print.lo state.lo
libbacktrace_la_OBJECTS = $(am_libbacktrace_la_OBJECTS)
@NATIVE_TRUE@am__EXEEXT_1 = btest$(EXEEXT)
@NATIVE_TRUE@am_btest_OBJECTS = btest-btest.$(OBJEXT)
@@ -258,6 +258,7 @@ AM_CFLAGS = $(EXTRA_FLAGS) $(WARN_FLAGS) $(PIC_FLAG)
noinst_LTLIBRARIES = libbacktrace.la
libbacktrace_la_SOURCES = \
backtrace.h \
+ atomic.c \
dwarf.c \
fileline.c \
internal.h \
diff --git a/libbacktrace/atomic.c b/libbacktrace/atomic.c
new file mode 100644
index 00000000000..44fa5521ad4
--- /dev/null
+++ b/libbacktrace/atomic.c
@@ -0,0 +1,111 @@
+/* atomic.c -- Support for atomic functions if not present.
+ Copyright (C) 2013 Free Software Foundation, Inc.
+ Written by Ian Lance Taylor, Google.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ (1) Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ (2) Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+
+ (3) The name of the author may not be used to
+ endorse or promote products derived from this software without
+ specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE. */
+
+#include "config.h"
+
+#include "backtrace.h"
+#include "backtrace-supported.h"
+#include "internal.h"
+
+/* This file holds implementations of the atomic functions that are
+ used if the host compiler has the sync functions but not the atomic
+ functions, as is true of versions of GCC before 4.7. */
+
+#if !defined (HAVE_ATOMIC_FUNCTIONS) && defined (HAVE_SYNC_FUNCTIONS)
+
+/* Do an atomic load of a pointer. */
+
+void *
+backtrace_atomic_load_pointer (void *arg)
+{
+ void **pp;
+ void *p;
+
+ pp = (void **) arg;
+ p = *pp;
+ while (!__sync_bool_compare_and_swap (pp, p, p))
+ p = *pp;
+ return p;
+}
+
+/* Do an atomic load of an int. */
+
+int
+backtrace_atomic_load_int (int *p)
+{
+ int i;
+
+ i = *p;
+ while (!__sync_bool_compare_and_swap (p, i, i))
+ i = *p;
+ return i;
+}
+
+/* Do an atomic store of a pointer. */
+
+void
+backtrace_atomic_store_pointer (void *arg, void *p)
+{
+ void **pp;
+ void *old;
+
+ pp = (void **) arg;
+ old = *pp;
+ while (!__sync_bool_compare_and_swap (pp, old, p))
+ old = *pp;
+}
+
+/* Do an atomic store of a size_t value. */
+
+void
+backtrace_atomic_store_size_t (size_t *p, size_t v)
+{
+ size_t old;
+
+ old = *p;
+ while (!__sync_bool_compare_and_swap (p, old, v))
+ old = *p;
+}
+
+/* Do an atomic store of a int value. */
+
+void
+backtrace_atomic_store_int (int *p, int v)
+{
+ size_t old;
+
+ old = *p;
+ while (!__sync_bool_compare_and_swap (p, old, v))
+ old = *p;
+}
+
+#endif
diff --git a/libbacktrace/config.h.in b/libbacktrace/config.h.in
index 48ff63fdc05..87cb805984d 100644
--- a/libbacktrace/config.h.in
+++ b/libbacktrace/config.h.in
@@ -3,6 +3,9 @@
/* ELF size: 32 or 64 */
#undef BACKTRACE_ELF_SIZE
+/* Define to 1 if you have the __atomic functions */
+#undef HAVE_ATOMIC_FUNCTIONS
+
/* Define to 1 if you have the declaration of `strnlen', and to 0 if you
don't. */
#undef HAVE_DECL_STRNLEN
diff --git a/libbacktrace/configure b/libbacktrace/configure
index e6b13c0b706..d6bda6e67b6 100755
--- a/libbacktrace/configure
+++ b/libbacktrace/configure
@@ -11748,6 +11748,44 @@ $as_echo "#define HAVE_SYNC_FUNCTIONS 1" >>confdefs.h
fi
+# Test for __atomic support.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking __atomic extensions" >&5
+$as_echo_n "checking __atomic extensions... " >&6; }
+if test "${libbacktrace_cv_sys_atomic+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "${with_target_subdir}"; then
+ libbacktrace_cv_sys_atomic=yes
+ else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+int i;
+int
+main ()
+{
+__atomic_load_n (&i, __ATOMIC_ACQUIRE);
+ __atomic_store_n (&i, 1, __ATOMIC_RELEASE);
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ libbacktrace_cv_sys_atomic=yes
+else
+ libbacktrace_cv_sys_atomic=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libbacktrace_cv_sys_atomic" >&5
+$as_echo "$libbacktrace_cv_sys_atomic" >&6; }
+if test "$libbacktrace_cv_sys_atomic" = "yes"; then
+
+$as_echo "#define HAVE_ATOMIC_FUNCTIONS 1" >>confdefs.h
+
+fi
+
# The library needs to be able to read the executable itself. Compile
# a file to determine the executable format. The awk script
# filetype.awk prints out the file type.
diff --git a/libbacktrace/configure.ac b/libbacktrace/configure.ac
index 48c86203837..f97afbc8b74 100644
--- a/libbacktrace/configure.ac
+++ b/libbacktrace/configure.ac
@@ -194,6 +194,24 @@ if test "$libbacktrace_cv_sys_sync" = "yes"; then
fi
AC_SUBST(BACKTRACE_SUPPORTS_THREADS)
+# Test for __atomic support.
+AC_CACHE_CHECK([__atomic extensions],
+[libbacktrace_cv_sys_atomic],
+[if test -n "${with_target_subdir}"; then
+ libbacktrace_cv_sys_atomic=yes
+ else
+ AC_LINK_IFELSE(
+ [AC_LANG_PROGRAM([int i;],
+ [__atomic_load_n (&i, __ATOMIC_ACQUIRE);
+ __atomic_store_n (&i, 1, __ATOMIC_RELEASE);])],
+ [libbacktrace_cv_sys_atomic=yes],
+ [libbacktrace_cv_sys_atomic=no])
+ fi])
+if test "$libbacktrace_cv_sys_atomic" = "yes"; then
+ AC_DEFINE([HAVE_ATOMIC_FUNCTIONS], 1,
+ [Define to 1 if you have the __atomic functions])
+fi
+
# The library needs to be able to read the executable itself. Compile
# a file to determine the executable format. The awk script
# filetype.awk prints out the file type.
diff --git a/libbacktrace/dwarf.c b/libbacktrace/dwarf.c
index 501afe553d2..0aba2d3f574 100644
--- a/libbacktrace/dwarf.c
+++ b/libbacktrace/dwarf.c
@@ -2643,12 +2643,7 @@ dwarf_lookup_pc (struct backtrace_state *state, struct dwarf_data *ddata,
&& pc < (entry - 1)->high)
{
if (state->threaded)
- {
- /* Use __sync_bool_compare_and_swap to do a
- load-acquire. */
- while (!__sync_bool_compare_and_swap (&u->lines, lines, lines))
- lines = u->lines;
- }
+ lines = (struct line *) backtrace_atomic_load_pointer (&u->lines);
if (lines != (struct line *) (uintptr_t) -1)
break;
@@ -2659,13 +2654,8 @@ dwarf_lookup_pc (struct backtrace_state *state, struct dwarf_data *ddata,
lines = u->lines;
}
- /* Do a load-acquire of u->lines. */
if (state->threaded)
- {
- /* Use __sync_bool_compare_and_swap to do an atomic load. */
- while (!__sync_bool_compare_and_swap (&u->lines, lines, lines))
- lines = u->lines;
- }
+ lines = backtrace_atomic_load_pointer (&u->lines);
new_data = 0;
if (lines == NULL)
@@ -2713,12 +2703,11 @@ dwarf_lookup_pc (struct backtrace_state *state, struct dwarf_data *ddata,
}
else
{
- __sync_bool_compare_and_swap (&u->lines_count, 0, count);
- __sync_bool_compare_and_swap (&u->function_addrs, NULL,
- function_addrs);
- __sync_bool_compare_and_swap (&u->function_addrs_count, 0,
- function_addrs_count);
- __sync_bool_compare_and_swap (&u->lines, NULL, lines);
+ backtrace_atomic_store_size_t (&u->lines_count, count);
+ backtrace_atomic_store_pointer (&u->function_addrs, function_addrs);
+ backtrace_atomic_store_size_t (&u->function_addrs_count,
+ function_addrs_count);
+ backtrace_atomic_store_pointer (&u->lines, lines);
}
}
@@ -2849,11 +2838,7 @@ dwarf_fileline (struct backtrace_state *state, uintptr_t pc,
pp = (struct dwarf_data **) (void *) &state->fileline_data;
while (1)
{
- ddata = *pp;
- /* Atomic load. */
- while (!__sync_bool_compare_and_swap (pp, ddata, ddata))
- ddata = *pp;
-
+ ddata = backtrace_atomic_load_pointer (pp);
if (ddata == NULL)
break;
@@ -2985,10 +2970,7 @@ backtrace_dwarf_add (struct backtrace_state *state,
{
struct dwarf_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;
diff --git a/libbacktrace/elf.c b/libbacktrace/elf.c
index 659b349f73b..981ce7f831c 100644
--- a/libbacktrace/elf.c
+++ b/libbacktrace/elf.c
@@ -442,10 +442,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 +487,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;
@@ -902,7 +895,6 @@ backtrace_initialize (struct backtrace_state *state, int descriptor,
{
int found_sym;
int found_dwarf;
- syminfo elf_syminfo_fn;
fileline elf_fileline_fn;
struct phdr_data pd;
@@ -919,18 +911,19 @@ backtrace_initialize (struct backtrace_state *state, int descriptor,
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 +935,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;
}
diff --git a/libbacktrace/fileline.c b/libbacktrace/fileline.c
index e5c39be8e0e..cc063f52c0d 100644
--- a/libbacktrace/fileline.c
+++ b/libbacktrace/fileline.c
@@ -58,15 +58,10 @@ fileline_initialize (struct backtrace_state *state,
int called_error_callback;
int descriptor;
- failed = state->fileline_initialization_failed;
-
- if (state->threaded)
- {
- /* Use __sync_bool_compare_and_swap to do an atomic load. */
- while (!__sync_bool_compare_and_swap
- (&state->fileline_initialization_failed, failed, failed))
- failed = state->fileline_initialization_failed;
- }
+ if (!state->threaded)
+ failed = state->fileline_initialization_failed;
+ else
+ failed = backtrace_atomic_load_int (&state->fileline_initialization_failed);
if (failed)
{
@@ -74,13 +69,10 @@ fileline_initialize (struct backtrace_state *state,
return 0;
}
- fileline_fn = state->fileline_fn;
- if (state->threaded)
- {
- while (!__sync_bool_compare_and_swap (&state->fileline_fn, fileline_fn,
- fileline_fn))
- fileline_fn = state->fileline_fn;
- }
+ if (!state->threaded)
+ fileline_fn = state->fileline_fn;
+ else
+ fileline_fn = backtrace_atomic_load_pointer (&state->fileline_fn);
if (fileline_fn != NULL)
return 1;
@@ -151,8 +143,7 @@ fileline_initialize (struct backtrace_state *state,
if (!state->threaded)
state->fileline_initialization_failed = 1;
else
- __sync_bool_compare_and_swap (&state->fileline_initialization_failed,
- 0, failed);
+ backtrace_atomic_store_int (&state->fileline_initialization_failed, 1);
return 0;
}
@@ -160,15 +151,10 @@ fileline_initialize (struct backtrace_state *state,
state->fileline_fn = fileline_fn;
else
{
- __sync_bool_compare_and_swap (&state->fileline_fn, NULL, fileline_fn);
-
- /* At this point we know that state->fileline_fn is not NULL.
- Either we stored our value, or some other thread stored its
- value. If some other thread stored its value, we leak the
- one we just initialized. Either way, state->fileline_fn is
- initialized. The compare_and_swap is a full memory barrier,
- so we should have full access to that value even if it was
- created by another thread. */
+ backtrace_atomic_store_pointer (&state->fileline_fn, fileline_fn);
+
+ /* Note that if two threads initialize at once, one of the data
+ sets may be leaked. */
}
return 1;
diff --git a/libbacktrace/internal.h b/libbacktrace/internal.h
index 1ea664a0bcd..c93e89f36f4 100644
--- a/libbacktrace/internal.h
+++ b/libbacktrace/internal.h
@@ -65,7 +65,48 @@ POSSIBILITY OF SUCH DAMAGE. */
#define __sync_lock_test_and_set(A, B) (abort(), 0)
#define __sync_lock_release(A) abort()
-#endif /* !defined(HAVE_SYNC_FUNCTIONS) */
+#endif /* !defined (HAVE_SYNC_FUNCTIONS) */
+
+#ifdef HAVE_ATOMIC_FUNCTIONS
+
+/* We have the atomic builtin functions. */
+
+#define backtrace_atomic_load_pointer(p) \
+ __atomic_load_n ((p), __ATOMIC_ACQUIRE)
+#define backtrace_atomic_load_int(p) \
+ __atomic_load_n ((p), __ATOMIC_ACQUIRE)
+#define backtrace_atomic_store_pointer(p, v) \
+ __atomic_store_n ((p), (v), __ATOMIC_RELEASE)
+#define backtrace_atomic_store_size_t(p, v) \
+ __atomic_store_n ((p), (v), __ATOMIC_RELEASE)
+#define backtrace_atomic_store_int(p, v) \
+ __atomic_store_n ((p), (v), __ATOMIC_RELEASE)
+
+#else /* !defined (HAVE_ATOMIC_FUNCTIONS) */
+#ifdef HAVE_SYNC_FUNCTIONS
+
+/* We have the sync functions but not the atomic functions. Define
+ the atomic ones in terms of the sync ones. */
+
+extern void *backtrace_atomic_load_pointer (void *);
+extern int backtrace_atomic_load_int (int *);
+extern void backtrace_atomic_store_pointer (void *, void *);
+extern void backtrace_atomic_store_size_t (size_t *, size_t);
+extern void backtrace_atomic_store_int (int *, int);
+
+#else /* !defined (HAVE_SYNC_FUNCTIONS) */
+
+/* We have neither the sync nor the atomic functions. These will
+ never be called. */
+
+#define backtrace_atomic_load_pointer(p) (abort(), 0)
+#define backtrace_atomic_load_int(p) (abort(), 0)
+#define backtrace_atomic_store_pointer(p, v) abort()
+#define backtrace_atomic_store_size_t(p, v) abort()
+#define backtrace_atomic_store_int(p, v) abort()
+
+#endif /* !defined (HAVE_SYNC_FUNCTIONS) */
+#endif /* !defined (HAVE_ATOMIC_FUNCTIONS) */
/* The type of the function that collects file/line information. This
is like backtrace_pcinfo. */