Use libunwind for printing backtrace

This commit is contained in:
Christian Göttsche 2021-05-16 20:45:09 +02:00 committed by BenBE
parent 29983ff83a
commit 29e1fcfa05
2 changed files with 101 additions and 12 deletions

77
CRT.c
View File

@ -21,14 +21,22 @@ in the source distribution for its full text.
#include "ProvideCurses.h" #include "ProvideCurses.h"
#include "XUtils.h" #include "XUtils.h"
#ifdef HAVE_EXECINFO_H
#include <execinfo.h>
#endif
#if !defined(NDEBUG) && defined(HAVE_MEMFD_CREATE) #if !defined(NDEBUG) && defined(HAVE_MEMFD_CREATE)
#include <sys/mman.h> #include <sys/mman.h>
#endif #endif
#if defined(HAVE_LIBUNWIND_H) && defined(HAVE_LIBUNWIND)
# define PRINT_BACKTRACE
# define UNW_LOCAL_ONLY
# include <libunwind.h>
# if defined(HAVE_DLADDR)
# include <dlfcn.h>
# endif
#elif defined(HAVE_EXECINFO_H)
# define PRINT_BACKTRACE
# include <execinfo.h>
#endif
#define ColorIndex(i,j) ((7-(i))*8+(j)) #define ColorIndex(i,j) ((7-(i))*8+(j))
@ -1008,6 +1016,59 @@ void CRT_setColors(int colorScheme) {
CRT_colors = CRT_colorSchemes[colorScheme]; CRT_colors = CRT_colorSchemes[colorScheme];
} }
#ifdef PRINT_BACKTRACE
static void print_backtrace(void) {
#if defined(HAVE_LIBUNWIND_H) && defined(HAVE_LIBUNWIND)
unw_context_t context;
unw_getcontext(&context);
unw_cursor_t cursor;
unw_init_local(&cursor, &context);
unsigned int item = 0;
while (unw_step(&cursor) > 0) {
unw_word_t pc;
unw_get_reg(&cursor, UNW_REG_IP, &pc);
if (pc == 0)
break;
char symbolName[256] = "?";
unw_word_t offset = 0;
unw_get_proc_name(&cursor, symbolName, sizeof(symbolName), &offset);
unw_proc_info_t pip;
pip.unwind_info = NULL;
const char* fname = "?";
const void* ptr = 0;
if (unw_get_proc_info(&cursor, &pip) == 0) {
ptr = (const void*)(pip.start_ip + offset);
#ifdef HAVE_DLADDR
Dl_info dlinfo;
if (dladdr(ptr, &dlinfo) && dlinfo.dli_fname && *dlinfo.dli_fname)
fname = dlinfo.dli_fname;
#endif
}
const char* frame = "";
if (unw_is_signal_frame(&cursor) > 0)
frame = "{signal frame}";
fprintf(stderr, "%2u: %#14lx %s (%s+%#lx) [%p]%s%s\n", item++, pc, fname, symbolName, offset, ptr, frame ? " " : "", frame);
}
#elif defined(HAVE_EXECINFO_H)
void* backtraceArray[256];
size_t size = backtrace(backtraceArray, ARRAYSIZE(backtraceArray));
backtrace_symbols_fd(backtraceArray, size, STDERR_FILENO);
#else
#error No implementation for print_backtrace()!
#endif
}
#endif
void CRT_handleSIGSEGV(int signal) { void CRT_handleSIGSEGV(int signal) {
CRT_done(); CRT_done();
@ -1022,7 +1083,7 @@ void CRT_handleSIGSEGV(int signal) {
" - Likely steps to reproduce (How did it happen?)\n" " - Likely steps to reproduce (How did it happen?)\n"
); );
#ifdef HAVE_EXECINFO_H #ifdef PRINT_BACKTRACE
fprintf(stderr, " - Backtrace of the issue (see below)\n"); fprintf(stderr, " - Backtrace of the issue (see below)\n");
#endif #endif
@ -1048,16 +1109,14 @@ void CRT_handleSIGSEGV(int signal) {
Settings_write(CRT_crashSettings, true); Settings_write(CRT_crashSettings, true);
fprintf(stderr, "\n\n"); fprintf(stderr, "\n\n");
#ifdef HAVE_EXECINFO_H #ifdef PRINT_BACKTRACE
fprintf(stderr, fprintf(stderr,
"Backtrace information:\n" "Backtrace information:\n"
"----------------------\n" "----------------------\n"
); );
void* backtraceArray[256]; print_backtrace();
size_t size = backtrace(backtraceArray, ARRAYSIZE(backtraceArray));
backtrace_symbols_fd(backtraceArray, size, STDERR_FILENO);
fprintf(stderr, fprintf(stderr,
"\n" "\n"
"To make the above information more practical to work with, " "To make the above information more practical to work with, "

View File

@ -253,6 +253,7 @@ AC_SEARCH_LIBS([clock_gettime], [rt])
AC_CHECK_FUNCS([ \ AC_CHECK_FUNCS([ \
clock_gettime \ clock_gettime \
dladdr \
faccessat \ faccessat \
fstatat \ fstatat \
host_get_clock_service \ host_get_clock_service \
@ -261,9 +262,6 @@ AC_CHECK_FUNCS([ \
readlinkat \ readlinkat \
]) ])
# Add -lexecinfo if needed
AC_SEARCH_LIBS([backtrace], [execinfo])
if test "$my_htop_platform" = darwin; then if test "$my_htop_platform" = darwin; then
AC_CHECK_FUNCS([mach_timebase_info]) AC_CHECK_FUNCS([mach_timebase_info])
fi fi
@ -409,6 +407,36 @@ if test "x$enable_affinity" = xyes; then
fi fi
AC_ARG_ENABLE([unwind],
[AS_HELP_STRING([--enable-unwind],
[enable unwind support for printing backtraces; requires libunwind @<:@default=check@:>@])],
[],
[enable_unwind=check])
case "$enable_unwind" in
check)
enable_unwind=yes
if test "$enable_static" = yes; then
AC_CHECK_LIB([lzma], [lzma_index_buffer_decode])
fi
AC_CHECK_LIB([unwind], [backtrace], [], [enable_unwind=no])
AC_CHECK_HEADERS([libunwind.h], [], [enable_unwind=no])
;;
no)
;;
yes)
AC_CHECK_LIB([unwind], [backtrace], [], [AC_MSG_ERROR([can not find required library libunwind])])
AC_CHECK_HEADERS([libunwind.h], [], [AC_MSG_ERROR([can not find require header file libunwind.h])])
;;
*)
AC_MSG_ERROR([bad value '$enable_unwind' for --enable-unwind])
;;
esac
if test "x$enable_unwind" = xno; then
# Fall back to backtrace(3) and add -lexecinfo if needed
AC_SEARCH_LIBS([backtrace], [execinfo])
fi
AC_ARG_ENABLE([hwloc], AC_ARG_ENABLE([hwloc],
[AS_HELP_STRING([--enable-hwloc], [AS_HELP_STRING([--enable-hwloc],
[enable hwloc support for CPU affinity; disables affinity support; requires libhwloc @<:@default=no@:>@])], [enable hwloc support for CPU affinity; disables affinity support; requires libhwloc @<:@default=no@:>@])],
@ -426,6 +454,7 @@ case "$enable_hwloc" in
;; ;;
esac esac
AC_ARG_WITH([os-release], AC_ARG_WITH([os-release],
[AS_HELP_STRING([--with-os-release=FILE], [AS_HELP_STRING([--with-os-release=FILE],
[location of an os-release file @<:@default=/etc/os-release@:>@])], [location of an os-release file @<:@default=/etc/os-release@:>@])],
@ -715,6 +744,7 @@ AC_MSG_RESULT([
(Linux) capabilities: $enable_capabilities (Linux) capabilities: $enable_capabilities
unicode: $enable_unicode unicode: $enable_unicode
affinity: $enable_affinity affinity: $enable_affinity
unwind: $enable_unwind
hwloc: $enable_hwloc hwloc: $enable_hwloc
debug: $enable_debug debug: $enable_debug
static: $enable_static static: $enable_static