]> git.proxmox.com Git - mirror_zfs.git/commitdiff
libspl/assert: use libunwind for backtrace when available
authorRob Norris <robn@despairlabs.com>
Tue, 30 Apr 2024 00:37:29 +0000 (10:37 +1000)
committerBrian Behlendorf <behlendorf1@llnl.gov>
Wed, 1 May 2024 17:52:05 +0000 (10:52 -0700)
libunwind seems to do a better job of resolving a symbols than
backtrace(), and is also useful on platforms that don't have backtrace()
(eg musl). If it's available, use it.

Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: Rob Norris <robn@despairlabs.com>
Sponsored-by: https://despairlabs.com/sponsor/
Closes #16140

config/user-libunwind.m4 [new file with mode: 0644]
config/user.m4
lib/libspl/Makefile.am
lib/libspl/assert.c

diff --git a/config/user-libunwind.m4 b/config/user-libunwind.m4
new file mode 100644 (file)
index 0000000..99ba3dc
--- /dev/null
@@ -0,0 +1,44 @@
+dnl
+dnl Checks for libunwind, which usually does a better job than backtrace() when
+dnl resolving symbols in the stack backtrace. Newer versions have support for
+dnl getting info about the object file the function came from, so we look for
+dnl that too and use it if found.
+dnl
+AC_DEFUN([ZFS_AC_CONFIG_USER_LIBUNWIND], [
+       AC_ARG_WITH([libunwind],
+           AS_HELP_STRING([--with-libunwind],
+               [use libunwind for backtraces in userspace assertions]),
+           [],
+           [with_libunwind=auto])
+
+       AS_IF([test "x$with_libunwind" != "xno"], [
+               ZFS_AC_FIND_SYSTEM_LIBRARY(LIBUNWIND, [libunwind], [libunwind.h], [], [unwind], [], [
+                       dnl unw_get_elf_filename() is sometimes a macro, other
+                       dnl times a proper symbol, so we can't just do a link
+                       dnl check; we need to include the header properly.
+                       AX_SAVE_FLAGS
+                       CFLAGS="$CFLAGS $LIBUNWIND_CFLAGS"
+                       LIBS="$LIBS $LIBUNWIND_LIBS"
+                       AC_MSG_CHECKING([for unw_get_elf_filename in libunwind])
+                       AC_LINK_IFELSE([
+                               AC_LANG_PROGRAM([
+                                       #define UNW_LOCAL_ONLY
+                                       #include <libunwind.h>
+                               ], [
+                                       unw_get_elf_filename(0, 0, 0, 0);
+                               ])
+                       ], [
+                               AC_MSG_RESULT([yes])
+                               AC_DEFINE(HAVE_LIBUNWIND_ELF, 1,
+                                   [libunwind has unw_get_elf_filename])
+                       ], [
+                               AC_MSG_RESULT([no])
+                       ])
+                       AX_RESTORE_FLAGS
+               ], [
+                       AS_IF([test "x$with_libunwind" = "xyes"], [
+                               AC_MSG_FAILURE([--with-libunwind was given, but libunwind is not available, try installing libunwind-devel])
+                       ])
+               ])
+       ])
+])
index 8d11e031ba2eb211e19f9b00811d254bca1ef80d..badd920d2b8a15f059f480f9c2facafe0c51bef3 100644 (file)
@@ -27,6 +27,7 @@ AC_DEFUN([ZFS_AC_CONFIG_USER], [
        ZFS_AC_CONFIG_USER_CLOCK_GETTIME
        ZFS_AC_CONFIG_USER_PAM
        ZFS_AC_CONFIG_USER_BACKTRACE
+       ZFS_AC_CONFIG_USER_LIBUNWIND
        ZFS_AC_CONFIG_USER_RUNSTATEDIR
        ZFS_AC_CONFIG_USER_MAKEDEV_IN_SYSMACROS
        ZFS_AC_CONFIG_USER_MAKEDEV_IN_MKDEV
index 9f413b08c16f49a246d605a7be402f18ef3b2a84..eb2377305aca3c0c5331f5261d4257b428d064a8 100644 (file)
@@ -1,6 +1,6 @@
 include $(srcdir)/%D%/include/Makefile.am
 
-libspl_assert_la_CFLAGS = $(AM_CFLAGS) $(LIBRARY_CFLAGS)
+libspl_assert_la_CFLAGS = $(AM_CFLAGS) $(LIBRARY_CFLAGS) $(LIBUNWIND_CFLAGS)
 libspl_la_CFLAGS        = $(libspl_assert_la_CFLAGS)
 
 noinst_LTLIBRARIES += libspl_assert.la libspl.la
@@ -44,4 +44,4 @@ libspl_la_LIBADD = \
 
 libspl_la_LIBADD += $(LIBATOMIC_LIBS) $(LIBCLOCK_GETTIME)
 
-libspl_assert_la_LIBADD = $(BACKTRACE_LIBS)
+libspl_assert_la_LIBADD = $(BACKTRACE_LIBS) $(LIBUNWIND_LIBS)
index 4acf687f4b237ee0444218c61b7f578cf5a96585..e6e3008f0aa67db4c1c4cf8ffc34bf0ac66f2354 100644 (file)
        pthread_getname_np(pthread_self(), buf, len);
 #endif
 
-#if defined(HAVE_BACKTRACE)
+#if defined(HAVE_LIBUNWIND)
+#define        UNW_LOCAL_ONLY
+#include <libunwind.h>
+
+static inline void
+libspl_dump_backtrace(void)
+{
+       unw_context_t uc;
+       unw_cursor_t cp;
+       unw_word_t ip, off;
+       char funcname[128];
+#ifdef HAVE_LIBUNWIND_ELF
+       char objname[128];
+       unw_word_t objoff;
+#endif
+
+       fprintf(stderr, "Call trace:\n");
+       unw_getcontext(&uc);
+       unw_init_local(&cp, &uc);
+       while (unw_step(&cp) > 0) {
+               unw_get_reg(&cp, UNW_REG_IP, &ip);
+               unw_get_proc_name(&cp, funcname, sizeof (funcname), &off);
+#ifdef HAVE_LIBUNWIND_ELF
+               unw_get_elf_filename(&cp, objname, sizeof (objname), &objoff);
+               fprintf(stderr, "  [0x%08lx] %s+0x%2lx (in %s +0x%2lx)\n",
+                   ip, funcname, off, objname, objoff);
+#else
+               fprintf(stderr, "  [0x%08lx] %s+0x%2lx\n", ip, funcname, off);
+#endif
+       }
+}
+#elif defined(HAVE_BACKTRACE)
 #include <execinfo.h>
 
 static inline void