elf.c (backtrace_initialize): Always set *fileline_fn.
authorIan Lance Taylor <iant@golang.org>
Mon, 12 Jun 2017 03:25:04 +0000 (03:25 +0000)
committerIan Lance Taylor <ian@gcc.gnu.org>
Mon, 12 Jun 2017 03:25:04 +0000 (03:25 +0000)
* elf.c (backtrace_initialize): Always set *fileline_fn.
* ttest.c: New file.
* btest.c: Move support functions into testlib.c.  Change calls to
check to pass file name.
* testlib.c: New file, copied from (part of) btest.c.
* testlib.h: New file, declarations for testlib.c.
* edtest.c: Use testlib.h and testlib.c.
* configure.ac: Test for -pthread, set HAVE_PTHREAD conditional.
* Makefile.am (btest_SOURCES): Add testlib.c.
(edtest_SOURCES): Likewise.
(CHECK_PROGRAMS): Add ttest if HAVE_PTHREAD.
(ttest_SOURCES, ttest_CFLAGS, ttest_LDADD): Define.
* configure, Makefile.in: Rebuild.

From-SVN: r249111

libbacktrace/ChangeLog
libbacktrace/Makefile.am
libbacktrace/Makefile.in
libbacktrace/btest.c
libbacktrace/configure
libbacktrace/configure.ac
libbacktrace/edtest.c
libbacktrace/elf.c
libbacktrace/testlib.c [new file with mode: 0644]
libbacktrace/testlib.h [new file with mode: 0644]
libbacktrace/ttest.c [new file with mode: 0644]

index 60a2f0f99dd9de4402e0b4ea13c1bf76d61e63bc..15e7017a490576ff4f35ae22e32ece1b3f934515 100644 (file)
@@ -1,3 +1,19 @@
+2017-06-11  Ian Lance Taylor  <iant@golang.org>
+
+       * elf.c (backtrace_initialize): Always set *fileline_fn.
+       * ttest.c: New file.
+       * btest.c: Move support functions into testlib.c.  Change calls to
+       check to pass file name.
+       * testlib.c: New file, copied from (part of) btest.c.
+       * testlib.h: New file, declarations for testlib.c.
+       * edtest.c: Use testlib.h and testlib.c.
+       * configure.ac: Test for -pthread, set HAVE_PTHREAD conditional.
+       * Makefile.am (btest_SOURCES): Add testlib.c.
+       (edtest_SOURCES): Likewise.
+       (CHECK_PROGRAMS): Add ttest if HAVE_PTHREAD.
+       (ttest_SOURCES, ttest_CFLAGS, ttest_LDADD): Define.
+       * configure, Makefile.in: Rebuild.
+
 2017-05-19  Than McIntosh  <thanm@google.com>
 
        * dwarf.c (free_line_header): Don't free dirs if dirs_count == 0.
index 0c6dac3df02d5302a11addd06f47ef71badbfa36..640eeec5e22428cde304a8cf42d7745b48fbc670 100644 (file)
@@ -89,7 +89,7 @@ TESTS = $(check_PROGRAMS)
 
 if NATIVE
 
-btest_SOURCES = btest.c
+btest_SOURCES = btest.c testlib.c
 btest_CFLAGS = $(AM_CFLAGS) -g -O
 btest_LDADD = libbacktrace.la
 
@@ -100,7 +100,7 @@ stest_LDADD = libbacktrace.la
 
 check_PROGRAMS += stest
 
-edtest_SOURCES = edtest.c edtest2_build.c
+edtest_SOURCES = edtest.c edtest2_build.c testlib.c
 edtest_LDADD = libbacktrace.la
 
 check_PROGRAMS += edtest
@@ -111,6 +111,16 @@ gen_edtest2_build: $(srcdir)/edtest2.c
        $(SHELL) $(srcdir)/../move-if-change tmp-edtest2_build.c edtest2_build.c
        echo timestamp > $@
 
+if HAVE_PTHREAD
+
+check_PROGRAMS += ttest
+
+ttest_SOURCES = ttest.c testlib.c
+ttest_CFLAGS = -pthread
+ttest_LDADD = libbacktrace.la
+
+endif HAVE_PTHREAD
+
 endif NATIVE
 
 # We can't use automake's automatic dependency tracking, because it
index a66359e610620140bf953f722716bbe22b998eb8..a57dc235b33d8c57cf5af834890e0d30343c2216 100644 (file)
@@ -83,8 +83,9 @@ POST_UNINSTALL = :
 build_triplet = @build@
 host_triplet = @host@
 target_triplet = @target@
-check_PROGRAMS = $(am__EXEEXT_1)
+check_PROGRAMS = $(am__EXEEXT_1) $(am__EXEEXT_2)
 @NATIVE_TRUE@am__append_1 = btest stest edtest
+@HAVE_PTHREAD_TRUE@@NATIVE_TRUE@am__append_2 = ttest
 subdir = .
 DIST_COMMON = README ChangeLog $(srcdir)/Makefile.in \
        $(srcdir)/Makefile.am $(top_srcdir)/configure \
@@ -115,19 +116,29 @@ am_libbacktrace_la_OBJECTS = atomic.lo dwarf.lo fileline.lo posix.lo \
 libbacktrace_la_OBJECTS = $(am_libbacktrace_la_OBJECTS)
 @NATIVE_TRUE@am__EXEEXT_1 = btest$(EXEEXT) stest$(EXEEXT) \
 @NATIVE_TRUE@  edtest$(EXEEXT)
-@NATIVE_TRUE@am_btest_OBJECTS = btest-btest.$(OBJEXT)
+@HAVE_PTHREAD_TRUE@@NATIVE_TRUE@am__EXEEXT_2 = ttest$(EXEEXT)
+@NATIVE_TRUE@am_btest_OBJECTS = btest-btest.$(OBJEXT) \
+@NATIVE_TRUE@  btest-testlib.$(OBJEXT)
 btest_OBJECTS = $(am_btest_OBJECTS)
 @NATIVE_TRUE@btest_DEPENDENCIES = libbacktrace.la
 btest_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
        --mode=link $(CCLD) $(btest_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
        $(LDFLAGS) -o $@
 @NATIVE_TRUE@am_edtest_OBJECTS = edtest.$(OBJEXT) \
-@NATIVE_TRUE@  edtest2_build.$(OBJEXT)
+@NATIVE_TRUE@  edtest2_build.$(OBJEXT) testlib.$(OBJEXT)
 edtest_OBJECTS = $(am_edtest_OBJECTS)
 @NATIVE_TRUE@edtest_DEPENDENCIES = libbacktrace.la
 @NATIVE_TRUE@am_stest_OBJECTS = stest.$(OBJEXT)
 stest_OBJECTS = $(am_stest_OBJECTS)
 @NATIVE_TRUE@stest_DEPENDENCIES = libbacktrace.la
+@HAVE_PTHREAD_TRUE@@NATIVE_TRUE@am_ttest_OBJECTS =  \
+@HAVE_PTHREAD_TRUE@@NATIVE_TRUE@       ttest-ttest.$(OBJEXT) \
+@HAVE_PTHREAD_TRUE@@NATIVE_TRUE@       ttest-testlib.$(OBJEXT)
+ttest_OBJECTS = $(am_ttest_OBJECTS)
+@HAVE_PTHREAD_TRUE@@NATIVE_TRUE@ttest_DEPENDENCIES = libbacktrace.la
+ttest_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+       --mode=link $(CCLD) $(ttest_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
+       $(LDFLAGS) -o $@
 DEFAULT_INCLUDES = -I.@am__isrc@
 depcomp =
 am__depfiles_maybe =
@@ -141,7 +152,8 @@ LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
        --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
        $(LDFLAGS) -o $@
 SOURCES = $(libbacktrace_la_SOURCES) $(EXTRA_libbacktrace_la_SOURCES) \
-       $(btest_SOURCES) $(edtest_SOURCES) $(stest_SOURCES)
+       $(btest_SOURCES) $(edtest_SOURCES) $(stest_SOURCES) \
+       $(ttest_SOURCES)
 MULTISRCTOP = 
 MULTIBUILDTOP = 
 MULTIDIRS = 
@@ -218,6 +230,7 @@ PACKAGE_URL = @PACKAGE_URL@
 PACKAGE_VERSION = @PACKAGE_VERSION@
 PATH_SEPARATOR = @PATH_SEPARATOR@
 PIC_FLAG = @PIC_FLAG@
+PTHREAD_CFLAGS = @PTHREAD_CFLAGS@
 RANLIB = @RANLIB@
 SED = @SED@
 SET_MAKE = @SET_MAKE@
@@ -330,13 +343,16 @@ libbacktrace_la_LIBADD = \
 
 libbacktrace_la_DEPENDENCIES = $(libbacktrace_la_LIBADD)
 TESTS = $(check_PROGRAMS)
-@NATIVE_TRUE@btest_SOURCES = btest.c
+@NATIVE_TRUE@btest_SOURCES = btest.c testlib.c
 @NATIVE_TRUE@btest_CFLAGS = $(AM_CFLAGS) -g -O
 @NATIVE_TRUE@btest_LDADD = libbacktrace.la
 @NATIVE_TRUE@stest_SOURCES = stest.c
 @NATIVE_TRUE@stest_LDADD = libbacktrace.la
-@NATIVE_TRUE@edtest_SOURCES = edtest.c edtest2_build.c
+@NATIVE_TRUE@edtest_SOURCES = edtest.c edtest2_build.c testlib.c
 @NATIVE_TRUE@edtest_LDADD = libbacktrace.la
+@HAVE_PTHREAD_TRUE@@NATIVE_TRUE@ttest_SOURCES = ttest.c testlib.c
+@HAVE_PTHREAD_TRUE@@NATIVE_TRUE@ttest_CFLAGS = -pthread
+@HAVE_PTHREAD_TRUE@@NATIVE_TRUE@ttest_LDADD = libbacktrace.la
 
 # We can't use automake's automatic dependency tracking, because it
 # breaks when using bootstrap-lean.  Automatic dependency tracking
@@ -435,6 +451,9 @@ edtest$(EXEEXT): $(edtest_OBJECTS) $(edtest_DEPENDENCIES) $(EXTRA_edtest_DEPENDE
 stest$(EXEEXT): $(stest_OBJECTS) $(stest_DEPENDENCIES) $(EXTRA_stest_DEPENDENCIES) 
        @rm -f stest$(EXEEXT)
        $(LINK) $(stest_OBJECTS) $(stest_LDADD) $(LIBS)
+ttest$(EXEEXT): $(ttest_OBJECTS) $(ttest_DEPENDENCIES) $(EXTRA_ttest_DEPENDENCIES) 
+       @rm -f ttest$(EXEEXT)
+       $(ttest_LINK) $(ttest_OBJECTS) $(ttest_LDADD) $(LIBS)
 
 mostlyclean-compile:
        -rm -f *.$(OBJEXT)
@@ -457,6 +476,24 @@ btest-btest.o: btest.c
 btest-btest.obj: btest.c
        $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(btest_CFLAGS) $(CFLAGS) -c -o btest-btest.obj `if test -f 'btest.c'; then $(CYGPATH_W) 'btest.c'; else $(CYGPATH_W) '$(srcdir)/btest.c'; fi`
 
+btest-testlib.o: testlib.c
+       $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(btest_CFLAGS) $(CFLAGS) -c -o btest-testlib.o `test -f 'testlib.c' || echo '$(srcdir)/'`testlib.c
+
+btest-testlib.obj: testlib.c
+       $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(btest_CFLAGS) $(CFLAGS) -c -o btest-testlib.obj `if test -f 'testlib.c'; then $(CYGPATH_W) 'testlib.c'; else $(CYGPATH_W) '$(srcdir)/testlib.c'; fi`
+
+ttest-ttest.o: ttest.c
+       $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ttest_CFLAGS) $(CFLAGS) -c -o ttest-ttest.o `test -f 'ttest.c' || echo '$(srcdir)/'`ttest.c
+
+ttest-ttest.obj: ttest.c
+       $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ttest_CFLAGS) $(CFLAGS) -c -o ttest-ttest.obj `if test -f 'ttest.c'; then $(CYGPATH_W) 'ttest.c'; else $(CYGPATH_W) '$(srcdir)/ttest.c'; fi`
+
+ttest-testlib.o: testlib.c
+       $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ttest_CFLAGS) $(CFLAGS) -c -o ttest-testlib.o `test -f 'testlib.c' || echo '$(srcdir)/'`testlib.c
+
+ttest-testlib.obj: testlib.c
+       $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ttest_CFLAGS) $(CFLAGS) -c -o ttest-testlib.obj `if test -f 'testlib.c'; then $(CYGPATH_W) 'testlib.c'; else $(CYGPATH_W) '$(srcdir)/testlib.c'; fi`
+
 mostlyclean-libtool:
        -rm -f *.lo
 
index 92cb325fdce0fe802f59ad82d16e2ca2d8bb011e..30d9e14526cf69d29e250d5f62b9619dc5d823e9 100644 (file)
@@ -43,237 +43,7 @@ POSSIBILITY OF SUCH DAMAGE.  */
 #include "backtrace.h"
 #include "backtrace-supported.h"
 
-/* Portable attribute syntax.  Actually some of these tests probably
-   won't work if the attributes are not recognized.  */
-
-#ifndef GCC_VERSION
-# define GCC_VERSION (__GNUC__ * 1000 + __GNUC_MINOR__)
-#endif
-
-#if (GCC_VERSION < 2007)
-# define __attribute__(x)
-#endif
-
-#ifndef ATTRIBUTE_UNUSED
-# define ATTRIBUTE_UNUSED __attribute__ ((__unused__))
-#endif
-
-/* Used to collect backtrace info.  */
-
-struct info
-{
-  char *filename;
-  int lineno;
-  char *function;
-};
-
-/* Passed to backtrace callback function.  */
-
-struct bdata
-{
-  struct info *all;
-  size_t index;
-  size_t max;
-  int failed;
-};
-
-/* Passed to backtrace_simple callback function.  */
-
-struct sdata
-{
-  uintptr_t *addrs;
-  size_t index;
-  size_t max;
-  int failed;
-};
-
-/* Passed to backtrace_syminfo callback function.  */
-
-struct symdata
-{
-  const char *name;
-  uintptr_t val, size;
-  int failed;
-};
-
-/* The backtrace state.  */
-
-static void *state;
-
-/* The number of failures.  */
-
-static int failures;
-
-/* Return the base name in a path.  */
-
-static const char *
-base (const char *p)
-{
-  const char *last;
-  const char *s;
-
-  last = NULL;
-  for (s = p; *s != '\0'; ++s)
-    {
-      if (IS_DIR_SEPARATOR (*s))
-       last = s + 1;
-    }
-  return last != NULL ? last : p;
-}
-
-/* Check an entry in a struct info array.  */
-
-static void
-check (const char *name, int index, const struct info *all, int want_lineno,
-       const char *want_function, int *failed)
-{
-  if (*failed)
-    return;
-  if (all[index].filename == NULL || all[index].function == NULL)
-    {
-      fprintf (stderr, "%s: [%d]: missing file name or function name\n",
-              name, index);
-      *failed = 1;
-      return;
-    }
-  if (strcmp (base (all[index].filename), "btest.c") != 0)
-    {
-      fprintf (stderr, "%s: [%d]: got %s expected test.c\n", name, index,
-              all[index].filename);
-      *failed = 1;
-    }
-  if (all[index].lineno != want_lineno)
-    {
-      fprintf (stderr, "%s: [%d]: got %d expected %d\n", name, index,
-              all[index].lineno, want_lineno);
-      *failed = 1;
-    }
-  if (strcmp (all[index].function, want_function) != 0)
-    {
-      fprintf (stderr, "%s: [%d]: got %s expected %s\n", name, index,
-              all[index].function, want_function);
-      *failed = 1;
-    }
-}
-
-/* The backtrace callback function.  */
-
-static int
-callback_one (void *vdata, uintptr_t pc ATTRIBUTE_UNUSED,
-             const char *filename, int lineno, const char *function)
-{
-  struct bdata *data = (struct bdata *) vdata;
-  struct info *p;
-
-  if (data->index >= data->max)
-    {
-      fprintf (stderr, "callback_one: callback called too many times\n");
-      data->failed = 1;
-      return 1;
-    }
-
-  p = &data->all[data->index];
-  if (filename == NULL)
-    p->filename = NULL;
-  else
-    {
-      p->filename = strdup (filename);
-      assert (p->filename != NULL);
-    }
-  p->lineno = lineno;
-  if (function == NULL)
-    p->function = NULL;
-  else
-    {
-      p->function = strdup (function);
-      assert (p->function != NULL);
-    }
-  ++data->index;
-
-  return 0;
-}
-
-/* An error callback passed to backtrace.  */
-
-static void
-error_callback_one (void *vdata, const char *msg, int errnum)
-{
-  struct bdata *data = (struct bdata *) vdata;
-
-  fprintf (stderr, "%s", msg);
-  if (errnum > 0)
-    fprintf (stderr, ": %s", strerror (errnum));
-  fprintf (stderr, "\n");
-  data->failed = 1;
-}
-
-/* The backtrace_simple callback function.  */
-
-static int
-callback_two (void *vdata, uintptr_t pc)
-{
-  struct sdata *data = (struct sdata *) vdata;
-
-  if (data->index >= data->max)
-    {
-      fprintf (stderr, "callback_two: callback called too many times\n");
-      data->failed = 1;
-      return 1;
-    }
-
-  data->addrs[data->index] = pc;
-  ++data->index;
-
-  return 0;
-}
-
-/* An error callback passed to backtrace_simple.  */
-
-static void
-error_callback_two (void *vdata, const char *msg, int errnum)
-{
-  struct sdata *data = (struct sdata *) vdata;
-
-  fprintf (stderr, "%s", msg);
-  if (errnum > 0)
-    fprintf (stderr, ": %s", strerror (errnum));
-  fprintf (stderr, "\n");
-  data->failed = 1;
-}
-
-/* The backtrace_syminfo callback function.  */
-
-static void
-callback_three (void *vdata, uintptr_t pc ATTRIBUTE_UNUSED,
-               const char *symname, uintptr_t symval,
-               uintptr_t symsize)
-{
-  struct symdata *data = (struct symdata *) vdata;
-
-  if (symname == NULL)
-    data->name = NULL;
-  else
-    {
-      data->name = strdup (symname);
-      assert (data->name != NULL);
-    }
-  data->val = symval;
-  data->size = symsize;
-}
-
-/* The backtrace_syminfo error callback function.  */
-
-static void
-error_callback_three (void *vdata, const char *msg, int errnum)
-{
-  struct symdata *data = (struct symdata *) vdata;
-
-  fprintf (stderr, "%s", msg);
-  if (errnum > 0)
-    fprintf (stderr, ": %s", strerror (errnum));
-  fprintf (stderr, "\n");
-  data->failed = 1;
-}
+#include "testlib.h"
 
 /* Test the backtrace function with non-inlined functions.  */
 
@@ -325,9 +95,9 @@ f3 (int f1line, int f2line)
       data.failed = 1;
     }
 
-  check ("test1", 0, all, f3line, "f3", &data.failed);
-  check ("test1", 1, all, f2line, "f2", &data.failed);
-  check ("test1", 2, all, f1line, "test1", &data.failed);
+  check ("test1", 0, all, f3line, "f3", "btest.c", &data.failed);
+  check ("test1", 1, all, f2line, "f2", "btest.c", &data.failed);
+  check ("test1", 2, all, f1line, "test1", "btest.c", &data.failed);
 
   printf ("%s: backtrace_full noinline\n", data.failed ? "FAIL" : "PASS");
 
@@ -377,9 +147,9 @@ f13 (int f1line, int f2line)
       data.failed = 1;
     }
 
-  check ("test2", 0, all, f3line, "f13", &data.failed);
-  check ("test2", 1, all, f2line, "f12", &data.failed);
-  check ("test2", 2, all, f1line, "test2", &data.failed);
+  check ("test2", 0, all, f3line, "f13", "btest.c", &data.failed);
+  check ("test2", 1, all, f2line, "f12", "btest.c", &data.failed);
+  check ("test2", 2, all, f1line, "test2", "btest.c", &data.failed);
 
   printf ("%s: backtrace_full inline\n", data.failed ? "FAIL" : "PASS");
 
@@ -462,9 +232,9 @@ f23 (int f1line, int f2line)
            }
        }
 
-      check ("test3", 0, all, f3line, "f23", &bdata.failed);
-      check ("test3", 1, all, f2line, "f22", &bdata.failed);
-      check ("test3", 2, all, f1line, "test3", &bdata.failed);
+      check ("test3", 0, all, f3line, "f23", "btest.c", &bdata.failed);
+      check ("test3", 1, all, f2line, "f22", "btest.c", &bdata.failed);
+      check ("test3", 2, all, f1line, "test3", "btest.c", &bdata.failed);
 
       if (bdata.failed)
        data.failed = 1;
@@ -600,9 +370,9 @@ f33 (int f1line, int f2line)
          bdata.failed = 1;
        }
 
-      check ("test4", 0, all, f3line, "f33", &bdata.failed);
-      check ("test4", 1, all, f2line, "f32", &bdata.failed);
-      check ("test4", 2, all, f1line, "test4", &bdata.failed);
+      check ("test4", 0, all, f3line, "f33", "btest.c", &bdata.failed);
+      check ("test4", 1, all, f2line, "f32", "btest.c", &bdata.failed);
+      check ("test4", 2, all, f1line, "test4", "btest.c", &bdata.failed);
 
       if (bdata.failed)
        data.failed = 1;
@@ -686,17 +456,6 @@ test5 (void)
   return failures;
 }
 
-static void
-error_callback_create (void *data ATTRIBUTE_UNUSED, const char *msg,
-                      int errnum)
-{
-  fprintf (stderr, "%s", msg);
-  if (errnum > 0)
-    fprintf (stderr, ": %s", strerror (errnum));
-  fprintf (stderr, "\n");
-  exit (EXIT_FAILURE);
-}
-
 /* Run all the tests.  */
 
 int
index ee90bc6dea0735a3ccd9b20f168a0b9a781c5d1b..a9c75dab15fc0043c8f4623861ff43a739733564 100755 (executable)
@@ -604,6 +604,9 @@ LTLIBOBJS
 LIBOBJS
 NATIVE_FALSE
 NATIVE_TRUE
+HAVE_PTHREAD_FALSE
+HAVE_PTHREAD_TRUE
+PTHREAD_CFLAGS
 BACKTRACE_USES_MALLOC
 ALLOC_FILE
 VIEW_FILE
@@ -11131,7 +11134,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 11134 "configure"
+#line 11137 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -11237,7 +11240,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 11240 "configure"
+#line 11243 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -12458,6 +12461,42 @@ $as_echo "#define HAVE_GETEXECNAME 1" >>confdefs.h
 
 fi
 
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -pthread is supported" >&5
+$as_echo_n "checking whether -pthread is supported... " >&6; }
+if test "${libgo_cv_lib_pthread+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  CFLAGS_hold=$CFLAGS
+CFLAGS="$CFLAGS -pthread"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+int i;
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  libgo_cv_lib_pthread=yes
+else
+  libgo_cv_lib_pthread=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+CFLAGS=$CFLAGS_hold
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libgo_cv_lib_pthread" >&5
+$as_echo "$libgo_cv_lib_pthread" >&6; }
+PTHREAD_CFLAGS=
+if test "$libgo_cv_lib_pthread" = yes; then
+  PTHREAD_CFLAGS=-pthread
+fi
+
+
+ if test "$libgo_cv_lib_pthread" = yes; then
+  HAVE_PTHREAD_TRUE=
+  HAVE_PTHREAD_FALSE='#'
+else
+  HAVE_PTHREAD_TRUE='#'
+  HAVE_PTHREAD_FALSE=
+fi
+
+
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether tests can run" >&5
 $as_echo_n "checking whether tests can run... " >&6; }
 if test "${libbacktrace_cv_sys_native+set}" = set; then :
@@ -12620,6 +12659,10 @@ if test -z "${MAINTAINER_MODE_TRUE}" && test -z "${MAINTAINER_MODE_FALSE}"; then
   as_fn_error "conditional \"MAINTAINER_MODE\" was never defined.
 Usually this means the macro was only invoked conditionally." "$LINENO" 5
 fi
+if test -z "${HAVE_PTHREAD_TRUE}" && test -z "${HAVE_PTHREAD_FALSE}"; then
+  as_fn_error "conditional \"HAVE_PTHREAD\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
 if test -z "${NATIVE_TRUE}" && test -z "${NATIVE_FALSE}"; then
   as_fn_error "conditional \"NATIVE\" was never defined.
 Usually this means the macro was only invoked conditionally." "$LINENO" 5
index f9cad2144474fa68a6b6b91c54084431906e3e1f..75a8ed8f0ffc6a547bc44450fb9660f1ae89d0a4 100644 (file)
@@ -355,6 +355,23 @@ if test "$have_getexecname" = "yes"; then
   AC_DEFINE(HAVE_GETEXECNAME, 1, [Define if getexecname is available.])
 fi
 
+dnl Test whether the compiler supports the -pthread option.
+AC_CACHE_CHECK([whether -pthread is supported],
+[libgo_cv_lib_pthread],
+[CFLAGS_hold=$CFLAGS
+CFLAGS="$CFLAGS -pthread"
+AC_COMPILE_IFELSE([[int i;]],
+[libgo_cv_lib_pthread=yes],
+[libgo_cv_lib_pthread=no])
+CFLAGS=$CFLAGS_hold])
+PTHREAD_CFLAGS=
+if test "$libgo_cv_lib_pthread" = yes; then
+  PTHREAD_CFLAGS=-pthread
+fi
+AC_SUBST(PTHREAD_CFLAGS)
+
+AM_CONDITIONAL(HAVE_PTHREAD, test "$libgo_cv_lib_pthread" = yes)
+
 AC_CACHE_CHECK([whether tests can run],
   [libbacktrace_cv_sys_native],
   [AC_RUN_IFELSE([AC_LANG_PROGRAM([], [return 0;])],
index daf4dd9f0be425429ee992a9bdd55be2d59d23b2..54c705cb1ba358231f40d574f54eaa963e23bedf 100644 (file)
@@ -41,19 +41,7 @@ POSSIBILITY OF SUCH DAMAGE.  */
 #include "backtrace-supported.h"
 #include "internal.h"
 
-#if defined(__MSDOS__) || defined(_WIN32) || defined(__OS2__) || defined (__CYGWIN__)
-# define IS_DIR_SEPARATOR(c) ((c) == '/' || (c) == '\\')
-#else
-# define IS_DIR_SEPARATOR(c) ((c) == '/')
-#endif
-
-/* The backtrace state.  */
-
-static void *state;
-
-/* The number of failures.  */
-
-int failures = 0;
+#include "testlib.h"
 
 static int test1 (void) __attribute__ ((noinline, unused));
 static int test1 (void) __attribute__ ((noinline, unused));
@@ -68,128 +56,6 @@ test1 (void)
   return f2 (__LINE__) + 1;
 }
 
-/* Used to collect backtrace info.  */
-
-struct info
-{
-  char *filename;
-  int lineno;
-  char *function;
-};
-
-/* Return the base name in a path.  */
-
-static const char *
-base (const char *p)
-{
-  const char *last;
-  const char *s;
-
-  last = NULL;
-  for (s = p; *s != '\0'; ++s)
-    {
-      if (IS_DIR_SEPARATOR (*s))
-        last = s + 1;
-    }
-  return last != NULL ? last : p;
-}
-
-/* Check an entry in a struct info array.  */
-
-static void
-check (const char *name, int index, const struct info *all, int want_lineno,
-       const char *want_function, const char *want_file, int *failed)
-{
-  if (*failed)
-    return;
-  if (all[index].filename == NULL || all[index].function == NULL)
-    {
-      fprintf (stderr, "%s: [%d]: missing file name or function name\n",
-               name, index);
-      *failed = 1;
-      return;
-    }
-  if (strcmp (base (all[index].filename), want_file) != 0)
-    {
-      fprintf (stderr, "%s: [%d]: got %s expected %s\n", name, index,
-               all[index].filename, want_file);
-      *failed = 1;
-    }
-  if (all[index].lineno != want_lineno)
-    {
-      fprintf (stderr, "%s: [%d]: got %d expected %d\n", name, index,
-               all[index].lineno, want_lineno);
-      *failed = 1;
-    }
-  if (strcmp (all[index].function, want_function) != 0)
-    {
-      fprintf (stderr, "%s: [%d]: got %s expected %s\n", name, index,
-               all[index].function, want_function);
-      *failed = 1;
-    }
-}
-
-/* Passed to backtrace callback function.  */
-
-struct bdata
-{
-  struct info *all;
-  size_t index;
-  size_t max;
-  int failed;
-};
-
-/* An error callback passed to backtrace.  */
-
-static void
-error_callback_one (void *vdata, const char *msg, int errnum)
-{
-  struct bdata *data = (struct bdata *) vdata;
-
-  fprintf (stderr, "%s", msg);
-  if (errnum > 0)
-    fprintf (stderr, ": %s", strerror (errnum));
-  fprintf (stderr, "\n");
-  data->failed = 1;
-}
-
-/* The backtrace callback function.  */
-
-static int
-callback_one (void *vdata, uintptr_t pc ATTRIBUTE_UNUSED,
-              const char *filename, int lineno, const char *function)
-{
-  struct bdata *data = (struct bdata *) vdata;
-  struct info *p;
-
-  if (data->index >= data->max)
-    {
-      fprintf (stderr, "callback_one: callback called too many times\n");
-      data->failed = 1;
-      return 1;
-    }
-
-  p = &data->all[data->index];
-  if (filename == NULL)
-    p->filename = NULL;
-  else
-    {
-      p->filename = strdup (filename);
-      assert (p->filename != NULL);
-    }
-  p->lineno = lineno;
-  if (function == NULL)
-    p->function = NULL;
-  else
-    {
-      p->function = strdup (function);
-      assert (p->function != NULL);
-    }
-  ++data->index;
-
-  return 0;
-}
-
 int
 f3 (int f1line, int f2line)
 {
@@ -232,17 +98,6 @@ f3 (int f1line, int f2line)
   return failures;
 }
 
-static void
-error_callback_create (void *data ATTRIBUTE_UNUSED, const char *msg,
-                       int errnum)
-{
-  fprintf (stderr, "%s", msg);
-  if (errnum > 0)
-    fprintf (stderr, ": %s", strerror (errnum));
-  fprintf (stderr, "\n");
-  exit (EXIT_FAILURE);
-}
-
 int
 main (int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED)
 {
index 89ed42b80219c9246ad1694e5d02b5c031bd922c..8e169715d32eb0c2a631f0a4bf9094fdba0d8620 100644 (file)
@@ -962,18 +962,12 @@ backtrace_initialize (struct backtrace_state *state, int descriptor,
     }
 
   if (!state->threaded)
-    {
-      if (state->fileline_fn == NULL || state->fileline_fn == elf_nodebug)
-       *fileline_fn = elf_fileline_fn;
-    }
+    *fileline_fn = state->fileline_fn;
   else
-    {
-      fileline current_fn;
+    *fileline_fn = backtrace_atomic_load_pointer (&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;
-    }
+  if (*fileline_fn == NULL || *fileline_fn == elf_nodebug)
+    *fileline_fn = elf_fileline_fn;
 
   return 1;
 }
diff --git a/libbacktrace/testlib.c b/libbacktrace/testlib.c
new file mode 100644 (file)
index 0000000..05420ca
--- /dev/null
@@ -0,0 +1,234 @@
+/* testlib.c -- test functions for libbacktrace library
+   Copyright (C) 2012-2017 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 <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "filenames.h"
+
+#include "backtrace.h"
+
+#include "testlib.h"
+
+/* The backtrace state.  */
+
+void *state;
+
+/* The number of failures.  */
+
+int failures;
+
+/* Return the base name in a path.  */
+
+const char *
+base (const char *p)
+{
+  const char *last;
+  const char *s;
+
+  last = NULL;
+  for (s = p; *s != '\0'; ++s)
+    {
+      if (IS_DIR_SEPARATOR (*s))
+       last = s + 1;
+    }
+  return last != NULL ? last : p;
+}
+
+/* Check an entry in a struct info array.  */
+
+void
+check (const char *name, int index, const struct info *all, int want_lineno,
+       const char *want_function, const char *want_file, int *failed)
+{
+  if (*failed)
+    return;
+  if (all[index].filename == NULL || all[index].function == NULL)
+    {
+      fprintf (stderr, "%s: [%d]: missing file name or function name\n",
+              name, index);
+      *failed = 1;
+      return;
+    }
+  if (strcmp (base (all[index].filename), want_file) != 0)
+    {
+      fprintf (stderr, "%s: [%d]: got %s expected %s\n", name, index,
+              all[index].filename, want_file);
+      *failed = 1;
+    }
+  if (all[index].lineno != want_lineno)
+    {
+      fprintf (stderr, "%s: [%d]: got %d expected %d\n", name, index,
+              all[index].lineno, want_lineno);
+      *failed = 1;
+    }
+  if (strcmp (all[index].function, want_function) != 0)
+    {
+      fprintf (stderr, "%s: [%d]: got %s expected %s\n", name, index,
+              all[index].function, want_function);
+      *failed = 1;
+    }
+}
+
+/* The backtrace callback function.  */
+
+int
+callback_one (void *vdata, uintptr_t pc ATTRIBUTE_UNUSED,
+             const char *filename, int lineno, const char *function)
+{
+  struct bdata *data = (struct bdata *) vdata;
+  struct info *p;
+
+  if (data->index >= data->max)
+    {
+      fprintf (stderr, "callback_one: callback called too many times\n");
+      data->failed = 1;
+      return 1;
+    }
+
+  p = &data->all[data->index];
+  if (filename == NULL)
+    p->filename = NULL;
+  else
+    {
+      p->filename = strdup (filename);
+      assert (p->filename != NULL);
+    }
+  p->lineno = lineno;
+  if (function == NULL)
+    p->function = NULL;
+  else
+    {
+      p->function = strdup (function);
+      assert (p->function != NULL);
+    }
+  ++data->index;
+
+  return 0;
+}
+
+/* An error callback passed to backtrace.  */
+
+void
+error_callback_one (void *vdata, const char *msg, int errnum)
+{
+  struct bdata *data = (struct bdata *) vdata;
+
+  fprintf (stderr, "%s", msg);
+  if (errnum > 0)
+    fprintf (stderr, ": %s", strerror (errnum));
+  fprintf (stderr, "\n");
+  data->failed = 1;
+}
+
+/* The backtrace_simple callback function.  */
+
+int
+callback_two (void *vdata, uintptr_t pc)
+{
+  struct sdata *data = (struct sdata *) vdata;
+
+  if (data->index >= data->max)
+    {
+      fprintf (stderr, "callback_two: callback called too many times\n");
+      data->failed = 1;
+      return 1;
+    }
+
+  data->addrs[data->index] = pc;
+  ++data->index;
+
+  return 0;
+}
+
+/* An error callback passed to backtrace_simple.  */
+
+void
+error_callback_two (void *vdata, const char *msg, int errnum)
+{
+  struct sdata *data = (struct sdata *) vdata;
+
+  fprintf (stderr, "%s", msg);
+  if (errnum > 0)
+    fprintf (stderr, ": %s", strerror (errnum));
+  fprintf (stderr, "\n");
+  data->failed = 1;
+}
+
+/* The backtrace_syminfo callback function.  */
+
+void
+callback_three (void *vdata, uintptr_t pc ATTRIBUTE_UNUSED,
+               const char *symname, uintptr_t symval,
+               uintptr_t symsize)
+{
+  struct symdata *data = (struct symdata *) vdata;
+
+  if (symname == NULL)
+    data->name = NULL;
+  else
+    {
+      data->name = strdup (symname);
+      assert (data->name != NULL);
+    }
+  data->val = symval;
+  data->size = symsize;
+}
+
+/* The backtrace_syminfo error callback function.  */
+
+void
+error_callback_three (void *vdata, const char *msg, int errnum)
+{
+  struct symdata *data = (struct symdata *) vdata;
+
+  fprintf (stderr, "%s", msg);
+  if (errnum > 0)
+    fprintf (stderr, ": %s", strerror (errnum));
+  fprintf (stderr, "\n");
+  data->failed = 1;
+}
+
+/* The backtrace_create_state error callback function.  */
+
+void
+error_callback_create (void *data ATTRIBUTE_UNUSED, const char *msg,
+                       int errnum)
+{
+  fprintf (stderr, "%s", msg);
+  if (errnum > 0)
+    fprintf (stderr, ": %s", strerror (errnum));
+  fprintf (stderr, "\n");
+  exit (EXIT_FAILURE);
+}
diff --git a/libbacktrace/testlib.h b/libbacktrace/testlib.h
new file mode 100644 (file)
index 0000000..2bfe62f
--- /dev/null
@@ -0,0 +1,110 @@
+/* testlib.h -- Header for test functions for libbacktrace library
+   Copyright (C) 2012-2017 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.  */
+
+#ifndef LIBBACKTRACE_TESTLIB_H
+#define LIBBACKTRACE_TESTLIB_H
+
+/* Portable attribute syntax.  Actually some of these tests probably
+   won't work if the attributes are not recognized.  */
+
+#ifndef GCC_VERSION
+# define GCC_VERSION (__GNUC__ * 1000 + __GNUC_MINOR__)
+#endif
+
+#if (GCC_VERSION < 2007)
+# define __attribute__(x)
+#endif
+
+#ifndef ATTRIBUTE_UNUSED
+# define ATTRIBUTE_UNUSED __attribute__ ((__unused__))
+#endif
+
+/* Used to collect backtrace info.  */
+
+struct info
+{
+  char *filename;
+  int lineno;
+  char *function;
+};
+
+/* Passed to backtrace callback function.  */
+
+struct bdata
+{
+  struct info *all;
+  size_t index;
+  size_t max;
+  int failed;
+};
+
+/* Passed to backtrace_simple callback function.  */
+
+struct sdata
+{
+  uintptr_t *addrs;
+  size_t index;
+  size_t max;
+  int failed;
+};
+
+/* Passed to backtrace_syminfo callback function.  */
+
+struct symdata
+{
+  const char *name;
+  uintptr_t val, size;
+  int failed;
+};
+
+/* The backtrace state.  */
+
+extern void *state;
+
+/* The number of failures.  */
+
+extern int failures;
+
+extern const char *base (const char *p);
+extern void check (const char *name, int index, const struct info *all,
+                  int want_lineno, const char *want_function,
+                  const char *want_file, int *failed);
+extern int callback_one (void *, uintptr_t, const char *, int, const char *);
+extern void error_callback_one (void *, const char *, int);
+extern int callback_two (void *, uintptr_t);
+extern void error_callback_two (void *, const char *, int);
+extern void callback_three (void *, uintptr_t, const char *, uintptr_t,
+                           uintptr_t);
+extern void error_callback_three (void *, const char *, int);
+extern void error_callback_create (void *, const char *, int);
+
+#endif /* !defined(LIBBACKTRACE_TESTLIB_H) */
diff --git a/libbacktrace/ttest.c b/libbacktrace/ttest.c
new file mode 100644 (file)
index 0000000..6c2d26c
--- /dev/null
@@ -0,0 +1,161 @@
+/* ttest.c -- Test for libbacktrace library
+   Copyright (C) 2017 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.  */
+
+/* Test using the libbacktrace library from multiple threads.  */
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <pthread.h>
+
+#include "filenames.h"
+
+#include "backtrace.h"
+#include "backtrace-supported.h"
+
+#include "testlib.h"
+
+static int f2 (int) __attribute__ ((noinline));
+static int f3 (int, int) __attribute__ ((noinline));
+
+/* Test that a simple backtrace works.  This is called via
+   pthread_create.  It returns the number of failures, as void *.  */
+
+static void *
+test1_thread (void *arg ATTRIBUTE_UNUSED)
+{
+  /* Returning a value here and elsewhere avoids a tailcall which
+     would mess up the backtrace.  */
+  return (void *) (uintptr_t) (f2 (__LINE__) - 2);
+}
+
+static int
+f2 (int f1line)
+{
+  return f3 (f1line, __LINE__) + 2;
+}
+
+static int
+f3 (int f1line, int f2line)
+{
+  struct info all[20];
+  struct bdata data;
+  int f3line;
+  int i;
+
+  data.all = &all[0];
+  data.index = 0;
+  data.max = 20;
+  data.failed = 0;
+
+  f3line = __LINE__ + 1;
+  i = backtrace_full (state, 0, callback_one, error_callback_one, &data);
+
+  if (i != 0)
+    {
+      fprintf (stderr, "test1: unexpected return value %d\n", i);
+      data.failed = 1;
+    }
+
+  if (data.index < 3)
+    {
+      fprintf (stderr,
+              "test1: not enough frames; got %zu, expected at least 3\n",
+              data.index);
+      data.failed = 1;
+    }
+
+  check ("test1", 0, all, f3line, "f3", "ttest.c", &data.failed);
+  check ("test1", 1, all, f2line, "f2", "ttest.c", &data.failed);
+  check ("test1", 2, all, f1line, "test1_thread", "ttest.c", &data.failed);
+
+  return data.failed;
+}
+
+/* Run the test with 10 threads simultaneously.  */
+
+#define THREAD_COUNT 10
+
+static void test1 (void) __attribute__ ((unused));
+
+static void
+test1 (void)
+{
+  pthread_t atid[THREAD_COUNT];
+  int i;
+  int errnum;
+  int this_fail;
+  void *ret;
+
+  for (i = 0; i < THREAD_COUNT; i++)
+    {
+      errnum = pthread_create (&atid[i], NULL, test1_thread, NULL);
+      if (errnum != 0)
+       {
+         fprintf (stderr, "pthread_create %d: %s\n", i, strerror (errnum));
+         exit (EXIT_FAILURE);
+       }
+    }
+
+  this_fail = 0;
+  for (i = 0; i < THREAD_COUNT; i++)
+    {
+      errnum = pthread_join (atid[i], &ret);
+      if (errnum != 0)
+       {
+         fprintf (stderr, "pthread_join %d: %s\n", i, strerror (errnum));
+         exit (EXIT_FAILURE);
+       }
+      this_fail += (int) (uintptr_t) ret;
+    }
+
+  printf ("%s: threaded backtrace_full noinline\n", this_fail > 0 ? "FAIL" : "PASS");
+
+  failures += this_fail;
+}
+
+int
+main (int argc ATTRIBUTE_UNUSED, char **argv)
+{
+  state = backtrace_create_state (argv[0], BACKTRACE_SUPPORTS_THREADS,
+                                 error_callback_create, NULL);
+
+#if BACKTRACE_SUPPORTED
+#if BACKTRACE_SUPPORTS_THREADS
+  test1 ();
+#endif
+#endif
+
+  exit (failures ? EXIT_FAILURE : EXIT_SUCCESS);
+}