From 29e1fcfa0517a7c5770b2a95fe7fbc0bc197c360 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20G=C3=B6ttsche?= Date: Sun, 16 May 2021 20:45:09 +0200 Subject: [PATCH] Use libunwind for printing backtrace --- CRT.c | 77 ++++++++++++++++++++++++++++++++++++++++++++++------ configure.ac | 36 ++++++++++++++++++++++-- 2 files changed, 101 insertions(+), 12 deletions(-) diff --git a/CRT.c b/CRT.c index 2533f613..5f1d5dd0 100644 --- a/CRT.c +++ b/CRT.c @@ -21,14 +21,22 @@ in the source distribution for its full text. #include "ProvideCurses.h" #include "XUtils.h" -#ifdef HAVE_EXECINFO_H -#include -#endif - #if !defined(NDEBUG) && defined(HAVE_MEMFD_CREATE) #include #endif +#if defined(HAVE_LIBUNWIND_H) && defined(HAVE_LIBUNWIND) +# define PRINT_BACKTRACE +# define UNW_LOCAL_ONLY +# include +# if defined(HAVE_DLADDR) +# include +# endif +#elif defined(HAVE_EXECINFO_H) +# define PRINT_BACKTRACE +# include +#endif + #define ColorIndex(i,j) ((7-(i))*8+(j)) @@ -1008,6 +1016,59 @@ void CRT_setColors(int 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) { CRT_done(); @@ -1022,7 +1083,7 @@ void CRT_handleSIGSEGV(int signal) { " - 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"); #endif @@ -1048,16 +1109,14 @@ void CRT_handleSIGSEGV(int signal) { Settings_write(CRT_crashSettings, true); fprintf(stderr, "\n\n"); -#ifdef HAVE_EXECINFO_H +#ifdef PRINT_BACKTRACE fprintf(stderr, "Backtrace information:\n" "----------------------\n" ); - void* backtraceArray[256]; + print_backtrace(); - size_t size = backtrace(backtraceArray, ARRAYSIZE(backtraceArray)); - backtrace_symbols_fd(backtraceArray, size, STDERR_FILENO); fprintf(stderr, "\n" "To make the above information more practical to work with, " diff --git a/configure.ac b/configure.ac index e93afbd9..b6361ead 100644 --- a/configure.ac +++ b/configure.ac @@ -253,6 +253,7 @@ AC_SEARCH_LIBS([clock_gettime], [rt]) AC_CHECK_FUNCS([ \ clock_gettime \ + dladdr \ faccessat \ fstatat \ host_get_clock_service \ @@ -261,9 +262,6 @@ AC_CHECK_FUNCS([ \ readlinkat \ ]) -# Add -lexecinfo if needed -AC_SEARCH_LIBS([backtrace], [execinfo]) - if test "$my_htop_platform" = darwin; then AC_CHECK_FUNCS([mach_timebase_info]) fi @@ -409,6 +407,36 @@ if test "x$enable_affinity" = xyes; then 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], [AS_HELP_STRING([--enable-hwloc], [enable hwloc support for CPU affinity; disables affinity support; requires libhwloc @<:@default=no@:>@])], @@ -426,6 +454,7 @@ case "$enable_hwloc" in ;; esac + AC_ARG_WITH([os-release], [AS_HELP_STRING([--with-os-release=FILE], [location of an os-release file @<:@default=/etc/os-release@:>@])], @@ -715,6 +744,7 @@ AC_MSG_RESULT([ (Linux) capabilities: $enable_capabilities unicode: $enable_unicode affinity: $enable_affinity + unwind: $enable_unwind hwloc: $enable_hwloc debug: $enable_debug static: $enable_static