From 21f66db67432ad9f6363d0e69fcabb53976a45e4 Mon Sep 17 00:00:00 2001 From: Rob Norris Date: Sat, 27 Apr 2024 21:35:05 +1000 Subject: [PATCH] libspl/assert: dump backtrace in assert Adds a check for the backtrace() function. If available, uses it to show a stack backtrace in the assertion output. Reviewed-by: Brian Behlendorf Signed-off-by: Rob Norris Sponsored-by: https://despairlabs.com/sponsor/ Closes #16140 --- config/user-backtrace.m4 | 14 ++++++++++++++ config/user.m4 | 1 + lib/libspl/Makefile.am | 2 ++ lib/libspl/assert.c | 20 ++++++++++++++++++++ 4 files changed, 37 insertions(+) create mode 100644 config/user-backtrace.m4 diff --git a/config/user-backtrace.m4 b/config/user-backtrace.m4 new file mode 100644 index 0000000000..25706767cd --- /dev/null +++ b/config/user-backtrace.m4 @@ -0,0 +1,14 @@ +dnl +dnl backtrace(), for userspace assertions. glibc has this directly in libc. +dnl FreeBSD and (sometimes) musl have it in a separate -lexecinfo. It's assumed +dnl that this will also get the companion function backtrace_symbols(). +dnl +AC_DEFUN([ZFS_AC_CONFIG_USER_BACKTRACE], [ + AX_SAVE_FLAGS + LIBS="" + AC_SEARCH_LIBS([backtrace], [execinfo], [ + AC_DEFINE(HAVE_BACKTRACE, 1, [backtrace() is available]) + AC_SUBST([BACKTRACE_LIBS], ["$LIBS"]) + ]) + AX_RESTORE_FLAGS +]) diff --git a/config/user.m4 b/config/user.m4 index 3a69086a9d..8d11e031ba 100644 --- a/config/user.m4 +++ b/config/user.m4 @@ -26,6 +26,7 @@ AC_DEFUN([ZFS_AC_CONFIG_USER], [ ZFS_AC_CONFIG_USER_AIO_H ZFS_AC_CONFIG_USER_CLOCK_GETTIME ZFS_AC_CONFIG_USER_PAM + ZFS_AC_CONFIG_USER_BACKTRACE ZFS_AC_CONFIG_USER_RUNSTATEDIR ZFS_AC_CONFIG_USER_MAKEDEV_IN_SYSMACROS ZFS_AC_CONFIG_USER_MAKEDEV_IN_MKDEV diff --git a/lib/libspl/Makefile.am b/lib/libspl/Makefile.am index 822bef7e7a..9f413b08c1 100644 --- a/lib/libspl/Makefile.am +++ b/lib/libspl/Makefile.am @@ -43,3 +43,5 @@ libspl_la_LIBADD = \ libspl_assert.la libspl_la_LIBADD += $(LIBATOMIC_LIBS) $(LIBCLOCK_GETTIME) + +libspl_assert_la_LIBADD = $(BACKTRACE_LIBS) diff --git a/lib/libspl/assert.c b/lib/libspl/assert.c index d402462531..4acf687f4b 100644 --- a/lib/libspl/assert.c +++ b/lib/libspl/assert.c @@ -49,6 +49,24 @@ pthread_getname_np(pthread_self(), buf, len); #endif +#if defined(HAVE_BACKTRACE) +#include + +static inline void +libspl_dump_backtrace(void) +{ + void *btptrs[100]; + size_t nptrs = backtrace(btptrs, 100); + char **bt = backtrace_symbols(btptrs, nptrs); + fprintf(stderr, "Call trace:\n"); + for (size_t i = 0; i < nptrs; i++) + fprintf(stderr, " %s\n", bt[i]); + free(bt); +} +#else +#define libspl_dump_backtrace() +#endif + static boolean_t libspl_assert_ok = B_FALSE; void @@ -83,6 +101,8 @@ libspl_assertf(const char *file, const char *func, int line, getpid(), libspl_getprogname(), libspl_gettid(), tname); + libspl_dump_backtrace(); + #if !__has_feature(attribute_analyzer_noreturn) && !defined(__COVERITY__) if (libspl_assert_ok) { pthread_mutex_unlock(&assert_lock);