From 2a5696befce6be00fa655b751af5ce2924ea45ae Mon Sep 17 00:00:00 2001 From: Alexander Monakov Date: Sat, 13 Jul 2013 00:37:17 +0400 Subject: [PATCH] common: dump backtrace on signals --- CMakeLists.txt | 2 +- cli/CMakeLists.txt | 1 + common/os_backtrace.cpp | 105 +++++++++++++++++++++++++++++++++++++--- common/os_backtrace.hpp | 10 ++++ common/os_posix.cpp | 9 ++-- gui/CMakeLists.txt | 1 + retrace/CMakeLists.txt | 1 + 7 files changed, 116 insertions(+), 13 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b2de6bb..15fff3f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -268,7 +268,7 @@ endif () if (CMAKE_EXECUTABLE_FORMAT STREQUAL "ELF") add_subdirectory (thirdparty/libbacktrace) include_directories (${CMAKE_CURRENT_SOURCE_DIR}/thirdparty/libbacktrace) - set (LIBBACKTRACE_LIBRARIES backtrace) + set (LIBBACKTRACE_LIBRARIES dl backtrace) endif () # Always use bundled QJSon. diff --git a/cli/CMakeLists.txt b/cli/CMakeLists.txt index 299c398..e2b4d72 100644 --- a/cli/CMakeLists.txt +++ b/cli/CMakeLists.txt @@ -32,6 +32,7 @@ target_link_libraries (apitrace ${ZLIB_LIBRARIES} ${SNAPPY_LIBRARIES} ${GETOPT_LIBRARIES} + ${LIBBACKTRACE_LIBRARIES} ) if (NOT CMAKE_CROSSCOMPILING) diff --git a/common/os_backtrace.cpp b/common/os_backtrace.cpp index 7f19495..fbe7445 100644 --- a/common/os_backtrace.cpp +++ b/common/os_backtrace.cpp @@ -277,6 +277,7 @@ std::vector get_backtrace() { #include #include +#include #include #include #include @@ -285,7 +286,52 @@ std::vector get_backtrace() { namespace os { +static char* format(uintptr_t num, int base, char *buf, int maxlen) +{ + static const char digits[] = "0123456789abcdef"; + buf += maxlen; + do { + *--buf = digits[num % base]; + num /= base; + maxlen--; + } while (num != 0 && maxlen != 0); + return buf; +} + +static void dump(const char *str, int len) +{ + static int fd = dup(STDERR_FILENO); + if (write(fd, str, len) != len) { + // Do nothing + } +} +static void dumpFrame(const RawStackFrame &frame) +{ + char buf[sizeof(long long) * 2], *p; +#define DUMP(string) dump(string, strlen(string)) + DUMP(frame.module ? frame.module : "?"); + if (frame.function) { + DUMP(": "); + DUMP(frame.function); + } + if (frame.offset >= 0) { + DUMP("+0x"); + p = format((uintptr_t) frame.offset, 16, buf, sizeof(buf)); + dump(p, buf + sizeof(buf) - p); + } + if (frame.filename) { + DUMP(": "); + DUMP(frame.filename); + if (frame.linenumber >= 0) { + DUMP(":"); + p = format((uintptr_t) frame.linenumber, 10, buf, sizeof(buf)); + dump(p, buf + sizeof(buf) - p); + } + } + DUMP("\n"); +#undef DUMP +} #define BT_DEPTH 10 @@ -297,11 +343,13 @@ class libbacktraceProvider { std::map > cache; std::vector *current, *current_frames; RawStackFrame *current_frame; + bool missingDwarf; static void bt_err_callback(void *vdata, const char *msg, int errnum) { + libbacktraceProvider *this_ = (libbacktraceProvider*)vdata; if (errnum == -1) - return;// no debug/sym info + this_->missingDwarf = true; else if (errnum) os::log("libbacktrace: %s: %s\n", msg, strerror(errnum)); else @@ -341,30 +389,61 @@ class libbacktraceProvider { return 0; } + static void dl_fill(RawStackFrame *frame, uintptr_t pc) + { + Dl_info info = {0}; + dladdr((void*)pc, &info); + frame->module = info.dli_fname; + frame->function = info.dli_sname; + frame->offset = info.dli_saddr ? pc - (uintptr_t)info.dli_saddr + : pc - (uintptr_t)info.dli_fbase; + } + static int bt_callback(void *vdata, uintptr_t pc) { libbacktraceProvider *this_ = (libbacktraceProvider*)vdata; std::vector &frames = this_->cache[pc]; if (!frames.size()) { RawStackFrame frame; - Dl_info info = {0}; - dladdr((void*)pc, &info); - frame.module = info.dli_fname; - frame.function = info.dli_sname; - frame.offset = info.dli_saddr ? pc - (uintptr_t)info.dli_saddr - : pc - (uintptr_t)info.dli_fbase; + dl_fill(&frame, pc); this_->current_frame = &frame; this_->current_frames = &frames; backtrace_pcinfo(this_->state, pc, bt_full_callback, bt_err_callback, vdata); if (!frames.size()) { frame.id = this_->nextFrameId++; frames.push_back(frame); - } + } } this_->current->insert(this_->current->end(), frames.begin(), frames.end()); return this_->current->size() >= BT_DEPTH; } + static int bt_full_dump_callback(void *vdata, uintptr_t pc, + const char *file, int line, const char *func) + { + libbacktraceProvider *this_ = (libbacktraceProvider*)vdata; + RawStackFrame *frame = this_->current_frame; + frame->filename = file; + frame->linenumber = line; + if (func) + frame->function = func; + dumpFrame(*frame); + return 0; + } + + static int bt_dump_callback(void *vdata, uintptr_t pc) + { + libbacktraceProvider *this_ = (libbacktraceProvider*)vdata; + RawStackFrame frame; + dl_fill(&frame, pc); + this_->current_frame = &frame; + this_->missingDwarf = false; + backtrace_pcinfo(this_->state, pc, bt_full_dump_callback, bt_err_callback, vdata); + if (this_->missingDwarf) + dumpFrame(frame); + return 0; + } + public: libbacktraceProvider(): state(backtrace_create_state(NULL, 0, bt_err_callback, NULL)) @@ -379,6 +458,11 @@ public: backtrace_simple(state, skipFrames, bt_callback, bt_err_callback, this); return parsedBacktrace; } + + void dumpBacktrace() + { + backtrace_simple(state, 0, bt_dump_callback, bt_err_callback, this); + } }; std::vector get_backtrace() { @@ -386,6 +470,11 @@ std::vector get_backtrace() { return backtraceProvider.getParsedBacktrace(); } +void dump_backtrace() { + static libbacktraceProvider backtraceProvider; + backtraceProvider.dumpBacktrace(); +} + } /* namespace os */ diff --git a/common/os_backtrace.hpp b/common/os_backtrace.hpp index 43dbb41..ae1c831 100644 --- a/common/os_backtrace.hpp +++ b/common/os_backtrace.hpp @@ -53,6 +53,16 @@ static inline bool backtrace_is_needed(const char*) { #endif +#if defined(__ELF__) + +void dump_backtrace(); + +#else + +static inline void dump_backtrace() {} + +#endif + } /* namespace os */ #endif diff --git a/common/os_posix.cpp b/common/os_posix.cpp index 967d12e..5d6bffe 100644 --- a/common/os_posix.cpp +++ b/common/os_posix.cpp @@ -56,6 +56,7 @@ #include "os.hpp" #include "os_string.hpp" +#include "os_backtrace.hpp" namespace os { @@ -243,11 +244,11 @@ signalHandler(int sig, siginfo_t *info, void *context) if (recursion_count) { log("apitrace: warning: recursion handling signal %i\n", sig); } else { - if (gCallback) { - ++recursion_count; + ++recursion_count; + if (gCallback) gCallback(); - --recursion_count; - } + os::dump_backtrace(); + --recursion_count; } struct sigaction *old_action; diff --git a/gui/CMakeLists.txt b/gui/CMakeLists.txt index ad13475..a36ab47 100644 --- a/gui/CMakeLists.txt +++ b/gui/CMakeLists.txt @@ -79,6 +79,7 @@ target_link_libraries (qapitrace common ${ZLIB_LIBRARIES} ${SNAPPY_LIBRARIES} + ${LIBBACKTRACE_LIBRARIES} ${QJSON_LIBRARIES} ${QT_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} diff --git a/retrace/CMakeLists.txt b/retrace/CMakeLists.txt index 78cceae..fcb8f18 100644 --- a/retrace/CMakeLists.txt +++ b/retrace/CMakeLists.txt @@ -46,6 +46,7 @@ target_link_libraries (retrace_common ${ZLIB_LIBRARIES} ${SNAPPY_LIBRARIES} ${GETOPT_LIBRARIES} + ${LIBBACKTRACE_LIBRARIES} ) add_library (glretrace_common STATIC -- 2.43.0