From d823135d24e061b6b6c71a0f6701395649993f9f Mon Sep 17 00:00:00 2001 From: Alexey Milovidov Date: Fri, 23 Jun 2017 08:16:34 +0300 Subject: [PATCH] Using libunwind for stack trace from signal handler [#CLICKHOUSE-3094]. --- contrib/CMakeLists.txt | 1 + libs/libdaemon/CMakeLists.txt | 3 ++- libs/libdaemon/src/BaseDaemon.cpp | 37 ++++++++++++++++++++++++++----- 3 files changed, 34 insertions(+), 7 deletions(-) diff --git a/contrib/CMakeLists.txt b/contrib/CMakeLists.txt index d5ed783e2cc..855751ea336 100644 --- a/contrib/CMakeLists.txt +++ b/contrib/CMakeLists.txt @@ -32,6 +32,7 @@ add_subdirectory (libcityhash) add_subdirectory (libfarmhash) add_subdirectory (libmetrohash) add_subdirectory (libbtrie) +add_subdirectory (libunwind) if (USE_INTERNAL_ZLIB_LIBRARY) add_subdirectory (libzlib-ng) diff --git a/libs/libdaemon/CMakeLists.txt b/libs/libdaemon/CMakeLists.txt index 64738726258..8c857a3a855 100644 --- a/libs/libdaemon/CMakeLists.txt +++ b/libs/libdaemon/CMakeLists.txt @@ -1,4 +1,5 @@ include_directories (include) +include_directories (${ClickHouse_SOURCE_DIR}/contrib/libunwind/include) include(${ClickHouse_SOURCE_DIR}/cmake/dbms_include.cmake) add_library (daemon @@ -11,4 +12,4 @@ add_library (daemon include/daemon/OwnPatternFormatter.h ) -target_link_libraries (daemon dbms) +target_link_libraries (daemon dbms unwind) diff --git a/libs/libdaemon/src/BaseDaemon.cpp b/libs/libdaemon/src/BaseDaemon.cpp index a6846012d70..51bc500881a 100644 --- a/libs/libdaemon/src/BaseDaemon.cpp +++ b/libs/libdaemon/src/BaseDaemon.cpp @@ -11,11 +11,16 @@ #include #include #include + +#define UNW_LOCAL_ONLY +#include + #ifdef __APPLE__ // ucontext is not available without _XOPEN_SOURCE #define _XOPEN_SOURCE #endif #include + #include #include #include @@ -175,6 +180,30 @@ static void faultSignalHandler(int sig, siginfo_t * info, void * context) static bool already_printed_stack_trace = false; +size_t backtraceLibUnwind(void ** out_frames, size_t max_frames, ucontext_t & context) +{ + if (already_printed_stack_trace) + return 0; + + unw_cursor_t cursor; + + if (unw_init_local_signal(&cursor, &context) < 0) + return 0; + + size_t i = 0; + for (; i < max_frames; ++i) + { + unw_word_t ip; + unw_get_reg(&cursor, UNW_REG_IP, &ip); + out_frames[i] = reinterpret_cast(ip); + if (!unw_step(&cursor)) + break; + } + + return i; +} + + /** Получает информацию через pipe. * При получении сигнала HUP / USR1 закрывает лог-файлы. * При получении информации из std::terminate, выводит её в лог. @@ -293,14 +322,10 @@ private: static const int max_frames = 50; void * frames[max_frames]; - int frames_size = backtrace(frames, max_frames); + int frames_size = backtraceLibUnwind(frames, max_frames, context); - if (frames_size >= 2) + if (frames_size) { - /// Overwrite sigaction with caller's address - if (caller_address && (frames_size < 3 || caller_address != frames[2])) - frames[1] = caller_address; - char ** symbols = backtrace_symbols(frames, frames_size); if (!symbols)