Skip to content

Commit 051460b

Browse files
robnbehlendorf
authored andcommitted
libspl/assert: use libunwind for backtrace when available
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 <[email protected]> Signed-off-by: Rob Norris <[email protected]> Sponsored-by: https://despairlabs.com/sponsor/ Closes #16140
1 parent 2152c40 commit 051460b

File tree

4 files changed

+79
-3
lines changed

4 files changed

+79
-3
lines changed

config/user-libunwind.m4

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
dnl
2+
dnl Checks for libunwind, which usually does a better job than backtrace() when
3+
dnl resolving symbols in the stack backtrace. Newer versions have support for
4+
dnl getting info about the object file the function came from, so we look for
5+
dnl that too and use it if found.
6+
dnl
7+
AC_DEFUN([ZFS_AC_CONFIG_USER_LIBUNWIND], [
8+
AC_ARG_WITH([libunwind],
9+
AS_HELP_STRING([--with-libunwind],
10+
[use libunwind for backtraces in userspace assertions]),
11+
[],
12+
[with_libunwind=auto])
13+
14+
AS_IF([test "x$with_libunwind" != "xno"], [
15+
ZFS_AC_FIND_SYSTEM_LIBRARY(LIBUNWIND, [libunwind], [libunwind.h], [], [unwind], [], [
16+
dnl unw_get_elf_filename() is sometimes a macro, other
17+
dnl times a proper symbol, so we can't just do a link
18+
dnl check; we need to include the header properly.
19+
AX_SAVE_FLAGS
20+
CFLAGS="$CFLAGS $LIBUNWIND_CFLAGS"
21+
LIBS="$LIBS $LIBUNWIND_LIBS"
22+
AC_MSG_CHECKING([for unw_get_elf_filename in libunwind])
23+
AC_LINK_IFELSE([
24+
AC_LANG_PROGRAM([
25+
#define UNW_LOCAL_ONLY
26+
#include <libunwind.h>
27+
], [
28+
unw_get_elf_filename(0, 0, 0, 0);
29+
])
30+
], [
31+
AC_MSG_RESULT([yes])
32+
AC_DEFINE(HAVE_LIBUNWIND_ELF, 1,
33+
[libunwind has unw_get_elf_filename])
34+
], [
35+
AC_MSG_RESULT([no])
36+
])
37+
AX_RESTORE_FLAGS
38+
], [
39+
AS_IF([test "x$with_libunwind" = "xyes"], [
40+
AC_MSG_FAILURE([--with-libunwind was given, but libunwind is not available, try installing libunwind-devel])
41+
])
42+
])
43+
])
44+
])

config/user.m4

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ AC_DEFUN([ZFS_AC_CONFIG_USER], [
2727
ZFS_AC_CONFIG_USER_CLOCK_GETTIME
2828
ZFS_AC_CONFIG_USER_PAM
2929
ZFS_AC_CONFIG_USER_BACKTRACE
30+
ZFS_AC_CONFIG_USER_LIBUNWIND
3031
ZFS_AC_CONFIG_USER_RUNSTATEDIR
3132
ZFS_AC_CONFIG_USER_MAKEDEV_IN_SYSMACROS
3233
ZFS_AC_CONFIG_USER_MAKEDEV_IN_MKDEV

lib/libspl/Makefile.am

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
include $(srcdir)/%D%/include/Makefile.am
22

3-
libspl_assert_la_CFLAGS = $(AM_CFLAGS) $(LIBRARY_CFLAGS)
3+
libspl_assert_la_CFLAGS = $(AM_CFLAGS) $(LIBRARY_CFLAGS) $(LIBUNWIND_CFLAGS)
44
libspl_la_CFLAGS = $(libspl_assert_la_CFLAGS)
55

66
noinst_LTLIBRARIES += libspl_assert.la libspl.la
@@ -44,4 +44,4 @@ libspl_la_LIBADD = \
4444

4545
libspl_la_LIBADD += $(LIBATOMIC_LIBS) $(LIBCLOCK_GETTIME)
4646

47-
libspl_assert_la_LIBADD = $(BACKTRACE_LIBS)
47+
libspl_assert_la_LIBADD = $(BACKTRACE_LIBS) $(LIBUNWIND_LIBS)

lib/libspl/assert.c

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,38 @@
4949
pthread_getname_np(pthread_self(), buf, len);
5050
#endif
5151

52-
#if defined(HAVE_BACKTRACE)
52+
#if defined(HAVE_LIBUNWIND)
53+
#define UNW_LOCAL_ONLY
54+
#include <libunwind.h>
55+
56+
static inline void
57+
libspl_dump_backtrace(void)
58+
{
59+
unw_context_t uc;
60+
unw_cursor_t cp;
61+
unw_word_t ip, off;
62+
char funcname[128];
63+
#ifdef HAVE_LIBUNWIND_ELF
64+
char objname[128];
65+
unw_word_t objoff;
66+
#endif
67+
68+
fprintf(stderr, "Call trace:\n");
69+
unw_getcontext(&uc);
70+
unw_init_local(&cp, &uc);
71+
while (unw_step(&cp) > 0) {
72+
unw_get_reg(&cp, UNW_REG_IP, &ip);
73+
unw_get_proc_name(&cp, funcname, sizeof (funcname), &off);
74+
#ifdef HAVE_LIBUNWIND_ELF
75+
unw_get_elf_filename(&cp, objname, sizeof (objname), &objoff);
76+
fprintf(stderr, " [0x%08lx] %s+0x%2lx (in %s +0x%2lx)\n",
77+
ip, funcname, off, objname, objoff);
78+
#else
79+
fprintf(stderr, " [0x%08lx] %s+0x%2lx\n", ip, funcname, off);
80+
#endif
81+
}
82+
}
83+
#elif defined(HAVE_BACKTRACE)
5384
#include <execinfo.h>
5485

5586
static inline void

0 commit comments

Comments
 (0)