aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRob Norris <robn@despairlabs.com>2024-04-27 11:35:05 +0000
committerBrian Behlendorf <behlendorf1@llnl.gov>2024-05-01 17:52:00 +0000
commit2152c405ba6ab0bc9fca482e9a0a968eb35699fb (patch)
tree31a0f5f6d5d97cbfecb97a7f6520ad7f8053e6fb
parentdec697ad683ecfdf9833455af0568ce4ddc7c885 (diff)
downloadsrc-2152c405ba6ab0bc9fca482e9a0a968eb35699fb.tar.gz
src-2152c405ba6ab0bc9fca482e9a0a968eb35699fb.zip
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 <behlendorf1@llnl.gov> Signed-off-by: Rob Norris <robn@despairlabs.com> Sponsored-by: https://despairlabs.com/sponsor/ Closes #16140
-rw-r--r--config/user-backtrace.m414
-rw-r--r--config/user.m41
-rw-r--r--lib/libspl/Makefile.am2
-rw-r--r--lib/libspl/assert.c20
4 files changed, 37 insertions, 0 deletions
diff --git a/config/user-backtrace.m4 b/config/user-backtrace.m4
new file mode 100644
index 000000000000..25706767cdc3
--- /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 3a69086a9d9d..8d11e031ba2e 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 822bef7e7a8d..9f413b08c16f 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 d402462531b6..4acf687f4b23 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 <execinfo.h>
+
+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);