[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
stack-trace: Use libasan as an alternative to libbacktrace
From: |
Bruno Haible |
Subject: |
stack-trace: Use libasan as an alternative to libbacktrace |
Date: |
Thu, 18 Jul 2024 05:02:27 +0200 |
This patch enables stack traces with file names and line numbers in some
situations, e.g. when using clang on Debian-based distros. (In this
situation, -lbacktrace does not work because libbacktrace.a is installed
in a GCC-private directory, but -lasan works because it is installed in
a global location.)
2024-07-17 Bruno Haible <bruno@clisp.org>
stack-trace: Use libasan as an alternative to libbacktrace.
* m4/stack-trace.m4 (gl_STACK_TRACE_EARLY): As a second choice, use
libasan.
* lib/stack-trace-impl.h (print_stack_trace_to) [HAVE_LIBASAN]:
Implement using libasan.
* lib/stack-trace.c (print_stack_trace): Test also HAVE_LIBASAN.
* lib/abort-debug.c (rpl_abort): Likewise.
diff --git a/lib/abort-debug.c b/lib/abort-debug.c
index ac5ddf15cd..2457ef07c2 100644
--- a/lib/abort-debug.c
+++ b/lib/abort-debug.c
@@ -31,7 +31,7 @@
void
rpl_abort (void)
{
-#if HAVE_LIBBACKTRACE || HAVE_EXECINFO_H
+#if HAVE_LIBBACKTRACE || HAVE_LIBASAN || HAVE_EXECINFO_H
print_stack_trace_to (stderr);
#endif
raise (SIGABRT);
diff --git a/lib/stack-trace-impl.h b/lib/stack-trace-impl.h
index 018563e4cc..529afad7a6 100644
--- a/lib/stack-trace-impl.h
+++ b/lib/stack-trace-impl.h
@@ -28,11 +28,33 @@ 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");
+ /* Pass skip=0, to work around
<https://github.com/ianlancetaylor/libbacktrace/issues/60>. */
backtrace_print (state, 0, stream);
}
+#elif HAVE_LIBASAN
+
+# include <stdio.h>
+
+/* We need only one declaration from <sanitizer/asan_interface.h>. */
+extern
+# ifdef __cplusplus
+"C"
+# endif
+void __sanitizer_print_stack_trace (void);
+
+/* The only supported stream, in this case, is stderr. */
+static inline void
+# if (__GNUC__ >= 3) || (__clang_major__ >= 4)
+__attribute__ ((always_inline))
+# endif
+print_stack_trace_to (FILE *stream)
+{
+ fprintf (stream, "Stack trace:\n");
+ __sanitizer_print_stack_trace ();
+}
+
#elif HAVE_EXECINFO_H
# include <stdio.h>
diff --git a/lib/stack-trace.c b/lib/stack-trace.c
index b4ad37bf78..b08a977064 100644
--- a/lib/stack-trace.c
+++ b/lib/stack-trace.c
@@ -24,7 +24,7 @@
void
print_stack_trace (void)
{
-#if HAVE_LIBBACKTRACE || HAVE_EXECINFO_H
+#if HAVE_LIBBACKTRACE || HAVE_LIBASAN || HAVE_EXECINFO_H
print_stack_trace_to (stderr);
#endif
}
diff --git a/m4/stack-trace.m4 b/m4/stack-trace.m4
index 7184ca7eb2..e102484e0f 100644
--- a/m4/stack-trace.m4
+++ b/m4/stack-trace.m4
@@ -1,5 +1,5 @@
# stack-trace.m4
-# serial 1
+# serial 2
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,
@@ -48,29 +48,56 @@ AC_DEFUN([gl_STACK_TRACE_EARLY]
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
+ dnl The second choice is GCC's libasan, installed as part of GCC.
+ dnl It produces source file names and line numbers, if the binary
+ dnl is compiled with debug information.
+ AC_CACHE_CHECK([for libasan], [gl_cv_lib_asan], [
+ gl_saved_LIBS="$LIBS"
+ LIBS="$gl_saved_LIBS -lasan"
+ AC_LINK_IFELSE(
+ [AC_LANG_PROGRAM(
+ [[extern
+ #ifdef __cplusplus
+ "C"
+ #endif
+ void __sanitizer_print_stack_trace (void);
+ ]],
+ [[__sanitizer_print_stack_trace ();
+ ]])],
+ [gl_cv_lib_asan=yes],
+ [gl_cv_lib_asan=no])
+ LIBS="$gl_saved_LIBS"
+ ])
+ if test $gl_cv_lib_asan = yes; then
+ AC_DEFINE([HAVE_LIBASAN], [1],
+ [Define if you have the libasan library.])
+ CAN_PRINT_STACK_TRACE=1
+ LIBS="$LIBS -lasan"
+ else
+ dnl The third 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
fi
])
- stack-trace: Use libasan as an alternative to libbacktrace,
Bruno Haible <=