From edc906dd6c548510949600f2e083e9940446b9b2 Mon Sep 17 00:00:00 2001 From: Bruno Haible Date: Thu, 18 Jul 2024 04:58:39 +0200 Subject: [PATCH] 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. --- ChangeLog | 10 ++++++ lib/abort-debug.c | 2 +- lib/stack-trace-impl.h | 24 +++++++++++++- lib/stack-trace.c | 2 +- m4/stack-trace.m4 | 75 ++++++++++++++++++++++++++++-------------- 5 files changed, 86 insertions(+), 27 deletions(-) diff --git a/ChangeLog b/ChangeLog index b1ee1b8e62..55ee80723e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,13 @@ +2024-07-17 Bruno Haible + + 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. + 2024-07-17 Bruno Haible stack-trace: Add tests. 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 . */ fprintf (stream, "Stack trace:\n"); + /* Pass skip=0, to work around . */ backtrace_print (state, 0, stream); } +#elif HAVE_LIBASAN + +# include + +/* We need only one declaration from . */ +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 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 ]) -- 2.39.5