While the 'abort-debug' module is nice, some users may want to have a
print_stack_trace facility that does not come with an override of abort().

This series of patches implements this.


2024-07-17  Bruno Haible  <br...@clisp.org>

        stack-trace: Add tests.
        * tests/test-stack-trace.c: New file.
        * modules/stack-trace-tests: New file.

        stack-trace: New module.
        * lib/stdlib.in.h (print_stack_trace): Make part of the stack-trace
        module.
        * lib/stack-trace-impl.h: New file, based on lib/abort-debug.c.
        * lib/stack-trace.c: New file, based on lib/abort-debug.c.
        * lib/abort-debug.c: Include stack-trace-impl.h. Remove definitions
        moved to stack-trace-impl.h.
        (print_stack_trace): Remove function.
        * m4/stdlib_h.m4 (gl_STDLIB_H_REQUIRE_DEFAULTS): Initialize
        GNULIB_STACK_TRACE.
        (gl_STDLIB_H_DEFAULTS): Initialize CAN_PRINT_STACK_TRACE.
        * m4/stack-trace.m4: New file, based on m4/abort-debug.m4.
        * m4/abort-debug.m4 (gl_ABORT_DEBUG_EARLY): Remove macro.
        (gl_ABORT_DEBUG): Require gl_STDLIB_H_DEFAULTS, gl_STACK_TRACE_EARLY.
        Set REPLACE_ABORT here.
        * modules/stdlib (Makefile.am): Substitute GNULIB_STACK_TRACE,
        CAN_PRINT_STACK_TRACE.
        * modules/stack-trace: New file.
        * modules/abort-debug (Depends-on): Add stack-trace. Remove execinfo.
        (configure.ac-early): Remove section.
        * DEPENDENCIES: Update.

2024-07-17  Bruno Haible  <br...@clisp.org>

        abort-debug: Export the print_stack_trace function.
        * lib/stdlib.in.h (print_stack_trace): Renamed from _gl_pre_abort.
        * lib/abort-debug.c (print_stack_trace_to): Renamed from
        print_stack_trace.
        (print_stack_trace): Renamed from _gl_pre_abort.
        (rpl_abort): Update.
        * tests/macros.h (ASSERT, ASSERT_NO_STDIO): Update.

>From 5e2115332873c8b802afa5d67a3bff1b5fbba2cd Mon Sep 17 00:00:00 2001
From: Bruno Haible <br...@clisp.org>
Date: Thu, 18 Jul 2024 03:07:30 +0200
Subject: [PATCH 1/3] abort-debug: Export the print_stack_trace function.

* lib/stdlib.in.h (print_stack_trace): Renamed from _gl_pre_abort.
* lib/abort-debug.c (print_stack_trace_to): Renamed from
print_stack_trace.
(print_stack_trace): Renamed from _gl_pre_abort.
(rpl_abort): Update.
* tests/macros.h (ASSERT, ASSERT_NO_STDIO): Update.
---
 ChangeLog         | 10 ++++++++++
 lib/abort-debug.c | 12 ++++++------
 lib/stdlib.in.h   |  8 ++++----
 tests/macros.h    |  4 ++--
 4 files changed, 22 insertions(+), 12 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index b80ca078d5..7b39f40541 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,13 @@
+2024-07-17  Bruno Haible  <br...@clisp.org>
+
+	abort-debug: Export the print_stack_trace function.
+	* lib/stdlib.in.h (print_stack_trace): Renamed from _gl_pre_abort.
+	* lib/abort-debug.c (print_stack_trace_to): Renamed from
+	print_stack_trace.
+	(print_stack_trace): Renamed from _gl_pre_abort.
+	(rpl_abort): Update.
+	* tests/macros.h (ASSERT, ASSERT_NO_STDIO): Update.
+
 2024-07-17  Bruno Haible  <br...@clisp.org>
 
 	doc: List library dependencies.
diff --git a/lib/abort-debug.c b/lib/abort-debug.c
index 8252b66def..641fceee2d 100644
--- a/lib/abort-debug.c
+++ b/lib/abort-debug.c
@@ -31,7 +31,7 @@ static inline void
 # if (__GNUC__ >= 3) || (__clang_major__ >= 4)
 __attribute__ ((always_inline))
 # endif
-print_stack_trace (FILE *stream)
+print_stack_trace_to (FILE *stream)
 {
   if (state == NULL)
     state = backtrace_create_state (NULL, 0, NULL, NULL);
@@ -50,7 +50,7 @@ static inline void
 # if (__GNUC__ >= 3) || (__clang_major__ >= 4)
 __attribute__ ((always_inline))
 # endif
-print_stack_trace (FILE *stream)
+print_stack_trace_to (FILE *stream)
 {
   void *buffer[100];
   int max_size = sizeof (buffer) / sizeof (buffer[0]);
@@ -75,23 +75,23 @@ print_stack_trace (FILE *stream)
 #endif
 
 void
-_gl_pre_abort (void)
+print_stack_trace (void)
 {
 #if HAVE_LIBBACKTRACE || HAVE_EXECINFO_H
-  print_stack_trace (stderr);
+  print_stack_trace_to (stderr);
 #endif
 }
 
 /*   rpl_abort ();
    is equivalent to
-     _gl_pre_abort ();
+     print_stack_trace ();
      original abort (); // i.e. raise (SIGABRT);
  */
 void
 rpl_abort (void)
 {
 #if HAVE_LIBBACKTRACE || HAVE_EXECINFO_H
-  print_stack_trace (stderr);
+  print_stack_trace_to (stderr);
 #endif
   raise (SIGABRT);
 }
diff --git a/lib/stdlib.in.h b/lib/stdlib.in.h
index e42368eef2..82e8dcd258 100644
--- a/lib/stdlib.in.h
+++ b/lib/stdlib.in.h
@@ -256,11 +256,11 @@ _GL_CXXALIASWARN (abort);
 # endif
 #endif
 #if @GNULIB_ABORT_DEBUG@ && @REPLACE_ABORT@
-_GL_EXTERN_C void _gl_pre_abort (void);
+_GL_EXTERN_C void print_stack_trace (void);
 #else
-# if !GNULIB_defined_gl_pre_abort
-#  define _gl_pre_abort() /* nothing */
-#  define GNULIB_defined_gl_pre_abort 1
+# if !GNULIB_defined_print_stack_trace
+#  define print_stack_trace() /* nothing */
+#  define GNULIB_defined_print_stack_trace 1
 # endif
 #endif
 
diff --git a/tests/macros.h b/tests/macros.h
index 144905e031..3121b21820 100644
--- a/tests/macros.h
+++ b/tests/macros.h
@@ -82,7 +82,7 @@ int volatile test_exit_status = EXIT_SUCCESS;
           fflush (ASSERT_STREAM);                                            \
           if (CONTINUE_AFTER_ASSERT)                                         \
             {                                                                \
-              _gl_pre_abort ();                                              \
+              print_stack_trace ();                                          \
               test_exit_status = EXIT_FAILURE;                               \
             }                                                                \
           else                                                               \
@@ -106,7 +106,7 @@ int volatile test_exit_status = EXIT_SUCCESS;
           WRITE_TO_STDERR ("' failed\n");                   \
           if (CONTINUE_AFTER_ASSERT)                        \
             {                                               \
-              _gl_pre_abort ();                             \
+              print_stack_trace ();                         \
               test_exit_status = EXIT_FAILURE;              \
             }                                               \
           else                                              \
-- 
2.34.1

>From 97897a6a4216121aab13414421cc74f01cf06489 Mon Sep 17 00:00:00 2001
From: Bruno Haible <br...@clisp.org>
Date: Thu, 18 Jul 2024 04:04:23 +0200
Subject: [PATCH 2/3] stack-trace: New module.

* lib/stdlib.in.h (print_stack_trace): Make part of the stack-trace
module.
* lib/stack-trace-impl.h: New file, based on lib/abort-debug.c.
* lib/stack-trace.c: New file, based on lib/abort-debug.c.
* lib/abort-debug.c: Include stack-trace-impl.h. Remove definitions
moved to stack-trace-impl.h.
(print_stack_trace): Remove function.
* m4/stdlib_h.m4 (gl_STDLIB_H_REQUIRE_DEFAULTS): Initialize
GNULIB_STACK_TRACE.
(gl_STDLIB_H_DEFAULTS): Initialize CAN_PRINT_STACK_TRACE.
* m4/stack-trace.m4: New file, based on m4/abort-debug.m4.
* m4/abort-debug.m4 (gl_ABORT_DEBUG_EARLY): Remove macro.
(gl_ABORT_DEBUG): Require gl_STDLIB_H_DEFAULTS, gl_STACK_TRACE_EARLY.
Set REPLACE_ABORT here.
* modules/stdlib (Makefile.am): Substitute GNULIB_STACK_TRACE,
CAN_PRINT_STACK_TRACE.
* modules/stack-trace: New file.
* modules/abort-debug (Depends-on): Add stack-trace. Remove execinfo.
(configure.ac-early): Remove section.
* DEPENDENCIES: Update.
---
 ChangeLog              | 24 +++++++++++++
 DEPENDENCIES           |  2 +-
 lib/abort-debug.c      | 61 +------------------------------
 lib/stack-trace-impl.h | 68 +++++++++++++++++++++++++++++++++++
 lib/stack-trace.c      | 30 ++++++++++++++++
 lib/stdlib.in.h        | 17 ++++-----
 m4/abort-debug.m4      | 77 ++++-----------------------------------
 m4/stack-trace.m4      | 81 ++++++++++++++++++++++++++++++++++++++++++
 m4/stdlib_h.m4         |  4 ++-
 modules/abort-debug    |  6 +---
 modules/stack-trace    | 34 ++++++++++++++++++
 modules/stdlib         |  2 ++
 12 files changed, 260 insertions(+), 146 deletions(-)
 create mode 100644 lib/stack-trace-impl.h
 create mode 100644 lib/stack-trace.c
 create mode 100644 m4/stack-trace.m4
 create mode 100644 modules/stack-trace

diff --git a/ChangeLog b/ChangeLog
index 7b39f40541..3f3d820c2b 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,27 @@
+2024-07-17  Bruno Haible  <br...@clisp.org>
+
+	stack-trace: New module.
+	* lib/stdlib.in.h (print_stack_trace): Make part of the stack-trace
+	module.
+	* lib/stack-trace-impl.h: New file, based on lib/abort-debug.c.
+	* lib/stack-trace.c: New file, based on lib/abort-debug.c.
+	* lib/abort-debug.c: Include stack-trace-impl.h. Remove definitions
+	moved to stack-trace-impl.h.
+	(print_stack_trace): Remove function.
+	* m4/stdlib_h.m4 (gl_STDLIB_H_REQUIRE_DEFAULTS): Initialize
+	GNULIB_STACK_TRACE.
+	(gl_STDLIB_H_DEFAULTS): Initialize CAN_PRINT_STACK_TRACE.
+	* m4/stack-trace.m4: New file, based on m4/abort-debug.m4.
+	* m4/abort-debug.m4 (gl_ABORT_DEBUG_EARLY): Remove macro.
+	(gl_ABORT_DEBUG): Require gl_STDLIB_H_DEFAULTS, gl_STACK_TRACE_EARLY.
+	Set REPLACE_ABORT here.
+	* modules/stdlib (Makefile.am): Substitute GNULIB_STACK_TRACE,
+	CAN_PRINT_STACK_TRACE.
+	* modules/stack-trace: New file.
+	* modules/abort-debug (Depends-on): Add stack-trace. Remove execinfo.
+	(configure.ac-early): Remove section.
+	* DEPENDENCIES: Update.
+
 2024-07-17  Bruno Haible  <br...@clisp.org>
 
 	abort-debug: Export the print_stack_trace function.
diff --git a/DEPENDENCIES b/DEPENDENCIES
index ce9cf9fb80..fa3bbeb626 100644
--- a/DEPENDENCIES
+++ b/DEPENDENCIES
@@ -300,7 +300,7 @@ Libraries
 Various modules work best with certain libraries installed. These are runtime
 dependencies that are also build dependencies.
 
-For module 'abort-debug':
+For modules 'abort-debug' and 'stack-trace':
   * libbacktrace
     + Recommended.
       Needed for producing C stack traces with source file names and
diff --git a/lib/abort-debug.c b/lib/abort-debug.c
index 641fceee2d..ac5ddf15cd 100644
--- a/lib/abort-debug.c
+++ b/lib/abort-debug.c
@@ -21,66 +21,7 @@
 
 #include <signal.h>
 
-#if HAVE_LIBBACKTRACE
-
-# include <backtrace.h>
-
-static struct backtrace_state *state /* = NULL */;
-
-static inline void
-# if (__GNUC__ >= 3) || (__clang_major__ >= 4)
-__attribute__ ((always_inline))
-# endif
-print_stack_trace_to (FILE *stream)
-{
-  if (state == NULL)
-    state = backtrace_create_state (NULL, 0, NULL, NULL);
-  /* Pass skip=0, to work around <https://github.com/ianlancetaylor/libbacktrace/issues/60>.  */
-  fprintf (stream, "Stack trace:\n");
-  backtrace_print (state, 0, stream);
-}
-
-#elif HAVE_EXECINFO_H
-
-# include <stdio.h>
-
-# include "execinfo.h"
-
-static inline void
-# if (__GNUC__ >= 3) || (__clang_major__ >= 4)
-__attribute__ ((always_inline))
-# endif
-print_stack_trace_to (FILE *stream)
-{
-  void *buffer[100];
-  int max_size = sizeof (buffer) / sizeof (buffer[0]);
-  int size = backtrace (buffer, max_size);
-  if (size > 0)
-    {
-      char **symbols = backtrace_symbols (buffer, size);
-      if (symbols != NULL)
-        {
-          int i;
-
-          fprintf (stream, "Stack trace:\n");
-          for (i = 0; i < size; i++)
-            fprintf (stream, "%s\n", symbols[i]);
-          fflush (stream);
-
-          free (symbols);
-        }
-    }
-}
-
-#endif
-
-void
-print_stack_trace (void)
-{
-#if HAVE_LIBBACKTRACE || HAVE_EXECINFO_H
-  print_stack_trace_to (stderr);
-#endif
-}
+#include "stack-trace-impl.h"
 
 /*   rpl_abort ();
    is equivalent to
diff --git a/lib/stack-trace-impl.h b/lib/stack-trace-impl.h
new file mode 100644
index 0000000000..018563e4cc
--- /dev/null
+++ b/lib/stack-trace-impl.h
@@ -0,0 +1,68 @@
+/* print_stack_trace() function that prints a stack trace.
+   Copyright (C) 2024 Free Software Foundation, Inc.
+
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
+
+   This file is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
+
+#if HAVE_LIBBACKTRACE
+
+# include <backtrace.h>
+
+static struct backtrace_state *state /* = NULL */;
+
+static inline void
+# if (__GNUC__ >= 3) || (__clang_major__ >= 4)
+__attribute__ ((always_inline))
+# endif
+print_stack_trace_to (FILE *stream)
+{
+  if (state == NULL)
+    state = backtrace_create_state (NULL, 0, NULL, NULL);
+  /* Pass skip=0, to work around <https://github.com/ianlancetaylor/libbacktrace/issues/60>.  */
+  fprintf (stream, "Stack trace:\n");
+  backtrace_print (state, 0, stream);
+}
+
+#elif HAVE_EXECINFO_H
+
+# include <stdio.h>
+
+# include "execinfo.h"
+
+static inline void
+# if (__GNUC__ >= 3) || (__clang_major__ >= 4)
+__attribute__ ((always_inline))
+# endif
+print_stack_trace_to (FILE *stream)
+{
+  void *buffer[100];
+  int max_size = sizeof (buffer) / sizeof (buffer[0]);
+  int size = backtrace (buffer, max_size);
+  if (size > 0)
+    {
+      char **symbols = backtrace_symbols (buffer, size);
+      if (symbols != NULL)
+        {
+          int i;
+
+          fprintf (stream, "Stack trace:\n");
+          for (i = 0; i < size; i++)
+            fprintf (stream, "%s\n", symbols[i]);
+          fflush (stream);
+
+          free (symbols);
+        }
+    }
+}
+
+#endif
diff --git a/lib/stack-trace.c b/lib/stack-trace.c
new file mode 100644
index 0000000000..b4ad37bf78
--- /dev/null
+++ b/lib/stack-trace.c
@@ -0,0 +1,30 @@
+/* print_stack_trace() function that prints a stack trace.
+   Copyright (C) 2024 Free Software Foundation, Inc.
+
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
+
+   This file is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
+
+#include <config.h>
+
+/* Specification.  */
+#include <stdlib.h>
+
+#include "stack-trace-impl.h"
+
+void
+print_stack_trace (void)
+{
+#if HAVE_LIBBACKTRACE || HAVE_EXECINFO_H
+  print_stack_trace_to (stderr);
+#endif
+}
diff --git a/lib/stdlib.in.h b/lib/stdlib.in.h
index 82e8dcd258..3de9eba245 100644
--- a/lib/stdlib.in.h
+++ b/lib/stdlib.in.h
@@ -255,14 +255,6 @@ _GL_CXXALIAS_SYS (abort, void, (void));
 _GL_CXXALIASWARN (abort);
 # endif
 #endif
-#if @GNULIB_ABORT_DEBUG@ && @REPLACE_ABORT@
-_GL_EXTERN_C void print_stack_trace (void);
-#else
-# if !GNULIB_defined_print_stack_trace
-#  define print_stack_trace() /* nothing */
-#  define GNULIB_defined_print_stack_trace 1
-# endif
-#endif
 
 
 #if @GNULIB_FREE_POSIX@
@@ -1608,6 +1600,15 @@ _GL_WARN_ON_USE (setenv, "setenv is unportable - "
 # endif
 #endif
 
+#if @GNULIB_STACK_TRACE@ && @CAN_PRINT_STACK_TRACE@
+_GL_EXTERN_C void print_stack_trace (void);
+#else
+# if !GNULIB_defined_print_stack_trace
+#  define print_stack_trace() /* nothing */
+#  define GNULIB_defined_print_stack_trace 1
+# endif
+#endif
+
 #if @GNULIB_STRTOD@
  /* Parse a double from STRING, updating ENDP if appropriate.  */
 # if @REPLACE_STRTOD@
diff --git a/m4/abort-debug.m4 b/m4/abort-debug.m4
index 61716e5a06..9d4c4c8c73 100644
--- a/m4/abort-debug.m4
+++ b/m4/abort-debug.m4
@@ -1,81 +1,16 @@
 # abort-debug.m4
-# serial 2
+# serial 3
 dnl Copyright (C) 2024 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
 dnl with or without modifications, as long as this notice is preserved.
 
-AC_DEFUN([gl_ABORT_DEBUG_EARLY],
+AC_DEFUN([gl_ABORT_DEBUG],
 [
-  AC_MSG_CHECKING([whether to enable debugging facilities on abort])
-  AC_ARG_ENABLE([debug-abort],
-    [AS_HELP_STRING([[--disable-debug-abort]],
-       [turn off debugging facilities])],
-    [case "$enableval" in
-       yes | no) ;;
-       *) AC_MSG_WARN([invalid argument supplied to --enable-debug-abort])
-          enable_debug_abort=yes
-          ;;
-     esac
-    ],
-    [enable_debug_abort=yes])
-  AC_MSG_RESULT([$enable_debug_abort])
-
   AC_REQUIRE([gl_STDLIB_H_DEFAULTS])
-  if test $enable_debug_abort = yes; then
-    dnl The first choice is libbacktrace by Ian Lance Taylor.
-    dnl Maintained at https://github.com/ianlancetaylor/libbacktrace,
-    dnl mirrored into GCC, installed as part of GCC by a few distros.
-    dnl It produces source file names and line numbers, if the binary
-    dnl is compiled with debug information.
-    AC_CACHE_CHECK([for libbacktrace], [gl_cv_lib_backtrace], [
-      gl_saved_LIBS="$LIBS"
-      LIBS="$gl_saved_LIBS -lbacktrace"
-      AC_LINK_IFELSE(
-        [AC_LANG_PROGRAM(
-           [[#include <backtrace.h>
-           ]],
-           [[struct backtrace_state *state =
-               backtrace_create_state (NULL, 0, NULL, NULL);
-           ]])],
-        [gl_cv_lib_backtrace=yes],
-        [gl_cv_lib_backtrace=no])
-      LIBS="$gl_saved_LIBS"
-    ])
-    if test $gl_cv_lib_backtrace = yes; then
-      AC_DEFINE([HAVE_LIBBACKTRACE], [1],
-        [Define if you have the libbacktrace library.])
-      REPLACE_ABORT=1
-      LIBS="$LIBS -lbacktrace"
-    else
-      dnl The second choice is libexecinfo.
-      dnl It does not produce source file names and line numbers, only addresses
-      dnl (which are mostly useless due to ASLR) and _sometimes_ function names.
-      AC_REQUIRE([AC_CANONICAL_HOST])
-      case "$host_os" in
-        *-gnu* | gnu* | darwin* | freebsd* | dragonfly* | netbsd* | openbsd* | solaris*)
-          dnl execinfo might be implemented on this platform.
-          REPLACE_ABORT=1
-          dnl On *BSD system, link all programs with -lexecinfo. Cf. m4/execinfo.m4.
-          case "$host_os" in
-            freebsd* | dragonfly* | netbsd* | openbsd*)
-              LIBS="$LIBS -lexecinfo"
-              ;;
-          esac
-          dnl Link all programs in such a way that the stack trace includes the
-          dnl function names. '-rdynamic' is equivalent to '-Wl,-export-dynamic'.
-          case "$host_os" in
-            *-gnu* | gnu* | openbsd*)
-              LDFLAGS="$LDFLAGS -rdynamic"
-              ;;
-          esac
-          ;;
-      esac
-    fi
+  AC_REQUIRE([gl_STACK_TRACE_EARLY])
+  if test $CAN_PRINT_STACK_TRACE = 1; then
+    REPLACE_ABORT=1
+    AC_REQUIRE([AC_C_INLINE])
   fi
 ])
-
-AC_DEFUN([gl_ABORT_DEBUG],
-[
-  AC_REQUIRE([AC_C_INLINE])
-])
diff --git a/m4/stack-trace.m4 b/m4/stack-trace.m4
new file mode 100644
index 0000000000..7184ca7eb2
--- /dev/null
+++ b/m4/stack-trace.m4
@@ -0,0 +1,81 @@
+# stack-trace.m4
+# serial 1
+dnl Copyright (C) 2024 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([gl_STACK_TRACE_EARLY],
+[
+  AC_MSG_CHECKING([whether to enable debugging facilities])
+  AC_ARG_ENABLE([debug],
+    [AS_HELP_STRING([[--disable-debug]],
+       [turn off debugging facilities])],
+    [case "$enableval" in
+       yes | no) ;;
+       *) AC_MSG_WARN([invalid argument supplied to --enable-debug])
+          enable_debug=yes
+          ;;
+     esac
+    ],
+    [enable_debug=yes])
+  AC_MSG_RESULT([$enable_debug])
+
+  AC_REQUIRE([gl_STDLIB_H_DEFAULTS])
+  if test $enable_debug = yes; then
+    dnl The first choice is libbacktrace by Ian Lance Taylor.
+    dnl Maintained at https://github.com/ianlancetaylor/libbacktrace,
+    dnl mirrored into GCC, installed as part of GCC by a few distros.
+    dnl It produces source file names and line numbers, if the binary
+    dnl is compiled with debug information.
+    AC_CACHE_CHECK([for libbacktrace], [gl_cv_lib_backtrace], [
+      gl_saved_LIBS="$LIBS"
+      LIBS="$gl_saved_LIBS -lbacktrace"
+      AC_LINK_IFELSE(
+        [AC_LANG_PROGRAM(
+           [[#include <backtrace.h>
+           ]],
+           [[struct backtrace_state *state =
+               backtrace_create_state (NULL, 0, NULL, NULL);
+           ]])],
+        [gl_cv_lib_backtrace=yes],
+        [gl_cv_lib_backtrace=no])
+      LIBS="$gl_saved_LIBS"
+    ])
+    if test $gl_cv_lib_backtrace = yes; then
+      AC_DEFINE([HAVE_LIBBACKTRACE], [1],
+        [Define if you have the libbacktrace library.])
+      CAN_PRINT_STACK_TRACE=1
+      LIBS="$LIBS -lbacktrace"
+    else
+      dnl The second choice is libexecinfo.
+      dnl It does not produce source file names and line numbers, only addresses
+      dnl (which are mostly useless due to ASLR) and _sometimes_ function names.
+      AC_REQUIRE([AC_CANONICAL_HOST])
+      case "$host_os" in
+        *-gnu* | gnu* | darwin* | freebsd* | dragonfly* | netbsd* | openbsd* | solaris*)
+          dnl execinfo might be implemented on this platform.
+          CAN_PRINT_STACK_TRACE=1
+          dnl On *BSD system, link all programs with -lexecinfo. Cf. m4/execinfo.m4.
+          case "$host_os" in
+            freebsd* | dragonfly* | netbsd* | openbsd*)
+              LIBS="$LIBS -lexecinfo"
+              ;;
+          esac
+          dnl Link all programs in such a way that the stack trace includes the
+          dnl function names. '-rdynamic' is equivalent to '-Wl,-export-dynamic'.
+          case "$host_os" in
+            *-gnu* | gnu* | openbsd*)
+              LDFLAGS="$LDFLAGS -rdynamic"
+              ;;
+          esac
+          ;;
+      esac
+    fi
+  fi
+])
+
+AC_DEFUN([gl_STACK_TRACE],
+[
+  AC_REQUIRE([AC_C_INLINE])
+])
diff --git a/m4/stdlib_h.m4 b/m4/stdlib_h.m4
index bb5a646041..332669f946 100644
--- a/m4/stdlib_h.m4
+++ b/m4/stdlib_h.m4
@@ -1,5 +1,5 @@
 # stdlib_h.m4
-# serial 78
+# serial 79
 dnl Copyright (C) 2007-2024 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -146,6 +146,7 @@ AC_DEFUN([gl_STDLIB_H_REQUIRE_DEFAULTS]
     gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_RPMATCH])
     gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_SECURE_GETENV])
     gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_SETENV])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STACK_TRACE])
     gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STRTOD])
     gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STRTOF])
     gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STRTOL])
@@ -261,4 +262,5 @@ AC_DEFUN([gl_STDLIB_H_DEFAULTS]
   REPLACE_STRTOULL=0;        AC_SUBST([REPLACE_STRTOULL])
   REPLACE_UNSETENV=0;        AC_SUBST([REPLACE_UNSETENV])
   REPLACE_WCTOMB=0;          AC_SUBST([REPLACE_WCTOMB])
+  CAN_PRINT_STACK_TRACE=0;   AC_SUBST([CAN_PRINT_STACK_TRACE])
 ])
diff --git a/modules/abort-debug b/modules/abort-debug
index 56cbdac5be..5bbe64e372 100644
--- a/modules/abort-debug
+++ b/modules/abort-debug
@@ -7,11 +7,7 @@ m4/abort-debug.m4
 
 Depends-on:
 stdlib
-execinfo
-
-configure.ac-early:
-AC_REQUIRE([gl_ABORT_DEBUG_EARLY])
-export LDFLAGS
+stack-trace
 
 configure.ac:
 gl_ABORT_DEBUG
diff --git a/modules/stack-trace b/modules/stack-trace
new file mode 100644
index 0000000000..122845d610
--- /dev/null
+++ b/modules/stack-trace
@@ -0,0 +1,34 @@
+Description:
+print_stack_trace() function that prints a stack trace.
+
+Files:
+lib/stack-trace-impl.h
+lib/stack-trace.c
+m4/stack-trace.m4
+
+Depends-on:
+stdlib
+execinfo
+
+configure.ac-early:
+AC_REQUIRE([gl_STACK_TRACE_EARLY])
+export LDFLAGS
+
+configure.ac:
+gl_STACK_TRACE
+gl_CONDITIONAL([GL_COND_OBJ_STACK_TRACE], [test $CAN_PRINT_STACK_TRACE = 1])
+gl_STDLIB_MODULE_INDICATOR([stack-trace])
+
+Makefile.am:
+if GL_COND_OBJ_STACK_TRACE
+lib_SOURCES += stack-trace.c
+endif
+
+Include:
+<stdlib.h>
+
+License:
+LGPLv2+
+
+Maintainer:
+all
diff --git a/modules/stdlib b/modules/stdlib
index 4e2b0ff32a..009dec8ee6 100644
--- a/modules/stdlib
+++ b/modules/stdlib
@@ -73,6 +73,7 @@ stdlib.h: stdlib.in.h $(top_builddir)/config.status $(CXXDEFS_H) \
 	      -e 's/@''GNULIB_RPMATCH''@/$(GNULIB_RPMATCH)/g' \
 	      -e 's/@''GNULIB_SECURE_GETENV''@/$(GNULIB_SECURE_GETENV)/g' \
 	      -e 's/@''GNULIB_SETENV''@/$(GNULIB_SETENV)/g' \
+	      -e 's/@''GNULIB_STACK_TRACE''@/$(GNULIB_STACK_TRACE)/g' \
 	      -e 's/@''GNULIB_STRTOD''@/$(GNULIB_STRTOD)/g' \
 	      -e 's/@''GNULIB_STRTOF''@/$(GNULIB_STRTOF)/g' \
 	      -e 's/@''GNULIB_STRTOL''@/$(GNULIB_STRTOL)/g' \
@@ -182,6 +183,7 @@ stdlib.h: stdlib.in.h $(top_builddir)/config.status $(CXXDEFS_H) \
 	      -e 's|@''REPLACE_STRTOULL''@|$(REPLACE_STRTOULL)|g' \
 	      -e 's|@''REPLACE_UNSETENV''@|$(REPLACE_UNSETENV)|g' \
 	      -e 's|@''REPLACE_WCTOMB''@|$(REPLACE_WCTOMB)|g' \
+	      -e 's|@''CAN_PRINT_STACK_TRACE''@|$(CAN_PRINT_STACK_TRACE)|g' \
 	      -e '/definitions of _GL_FUNCDECL_RPL/r $(CXXDEFS_H)' \
 	      -e '/definition of _Noreturn/r $(_NORETURN_H)' \
 	      -e '/definition of _GL_ARG_NONNULL/r $(ARG_NONNULL_H)' \
-- 
2.34.1

>From 0c9a86430dc0a20cb6bc312711f7d2eb115bd1fd Mon Sep 17 00:00:00 2001
From: Bruno Haible <br...@clisp.org>
Date: Thu, 18 Jul 2024 04:15:34 +0200
Subject: [PATCH 3/3] stack-trace: Add tests.

* tests/test-stack-trace.c: New file.
* modules/stack-trace-tests: New file.
---
 ChangeLog                 |  4 ++++
 modules/stack-trace-tests | 11 +++++++++++
 tests/test-stack-trace.c  | 36 ++++++++++++++++++++++++++++++++++++
 3 files changed, 51 insertions(+)
 create mode 100644 modules/stack-trace-tests
 create mode 100644 tests/test-stack-trace.c

diff --git a/ChangeLog b/ChangeLog
index 3f3d820c2b..b1ee1b8e62 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,9 @@
 2024-07-17  Bruno Haible  <br...@clisp.org>
 
+	stack-trace: Add tests.
+	* tests/test-stack-trace.c: New file.
+	* modules/stack-trace-tests: New file.
+
 	stack-trace: New module.
 	* lib/stdlib.in.h (print_stack_trace): Make part of the stack-trace
 	module.
diff --git a/modules/stack-trace-tests b/modules/stack-trace-tests
new file mode 100644
index 0000000000..eac93a9062
--- /dev/null
+++ b/modules/stack-trace-tests
@@ -0,0 +1,11 @@
+Files:
+tests/test-stack-trace.c
+tests/macros.h
+
+Depends-on:
+
+configure.ac:
+
+Makefile.am:
+TESTS += test-stack-trace
+check_PROGRAMS += test-stack-trace
diff --git a/tests/test-stack-trace.c b/tests/test-stack-trace.c
new file mode 100644
index 0000000000..a83efc700c
--- /dev/null
+++ b/tests/test-stack-trace.c
@@ -0,0 +1,36 @@
+/* Test of print_stack_trace() function.
+   Copyright (C) 2024 Free Software Foundation, Inc.
+
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
+
+/* Written by Bruno Haible <br...@clisp.org>, 2024.  */
+
+#include <config.h>
+
+/* Specification.  */
+#include <stdlib.h>
+
+static void
+test_something (void)
+{
+  print_stack_trace ();
+}
+
+int
+main (int argc, char *argv[])
+{
+  test_something ();
+
+  return 0;
+}
-- 
2.34.1

Reply via email to