]> git.cworth.org Git - apitrace/commitdiff
common: dump backtrace on signals
authorAlexander Monakov <amonakov@ispras.ru>
Fri, 12 Jul 2013 20:37:17 +0000 (00:37 +0400)
committerJosé Fonseca <jfonseca@vmware.com>
Fri, 20 Sep 2013 13:52:04 +0000 (14:52 +0100)
CMakeLists.txt
cli/CMakeLists.txt
common/os_backtrace.cpp
common/os_backtrace.hpp
common/os_posix.cpp
gui/CMakeLists.txt
retrace/CMakeLists.txt

index b2de6bbc0844c16c6786c84bcc04781d24a8d406..15fff3f337f6e8d9282dcd1f4acee7fbd646387e 100644 (file)
@@ -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.
index 299c3985a3284c120f8b33bf83df16fa77c98d92..e2b4d720beed16d6ed12c705dba817cc146a9d3f 100644 (file)
@@ -32,6 +32,7 @@ target_link_libraries (apitrace
     ${ZLIB_LIBRARIES}
     ${SNAPPY_LIBRARIES}
     ${GETOPT_LIBRARIES}
+    ${LIBBACKTRACE_LIBRARIES}
 )
 
 if (NOT CMAKE_CROSSCOMPILING)
index 7f194951760c8732337ede2f5f4f2f12e98bd7da..fbe74455b867ebe2967308f5a9fa01c640192d0b 100644 (file)
@@ -277,6 +277,7 @@ std::vector<RawStackFrame> get_backtrace() {
 
 #include <stdint.h>
 #include <dlfcn.h>
+#include <unistd.h>
 #include <map>
 #include <vector>
 #include <cxxabi.h>
@@ -285,7 +286,52 @@ std::vector<RawStackFrame> 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<uintptr_t, std::vector<RawStackFrame> > cache;
     std::vector<RawStackFrame> *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<RawStackFrame> &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<RawStackFrame> get_backtrace() {
@@ -386,6 +470,11 @@ std::vector<RawStackFrame> get_backtrace() {
     return backtraceProvider.getParsedBacktrace();
 }
 
+void dump_backtrace() {
+    static libbacktraceProvider backtraceProvider;
+    backtraceProvider.dumpBacktrace();
+}
+
 
 } /* namespace os */
 
index 43dbb41719241e11e48426a57d40cdd2857202b4..ae1c831ac4a4059573be924e1ffefb9b49deedb0 100644 (file)
@@ -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
index 967d12eba4116ddccd8f1c3389f165c7c8edc4c0..5d6bffe5dcdab406a23624692b965e1d0730305b 100644 (file)
@@ -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;
index ad13475ece3398181e6d8c9ae9b54317df874b5b..a36ab47baef485ac1747feee574447b1babbbc8d 100644 (file)
@@ -79,6 +79,7 @@ target_link_libraries (qapitrace
     common
     ${ZLIB_LIBRARIES}
     ${SNAPPY_LIBRARIES}
+    ${LIBBACKTRACE_LIBRARIES}
     ${QJSON_LIBRARIES}
     ${QT_LIBRARIES}
     ${CMAKE_THREAD_LIBS_INIT}
index 78cceae33bd7c1aa67b51573d2e139d855c2b043..fcb8f187659bbc0b70f41b223ab5c525d9a26bfd 100644 (file)
@@ -46,6 +46,7 @@ target_link_libraries (retrace_common
     ${ZLIB_LIBRARIES}
     ${SNAPPY_LIBRARIES}
     ${GETOPT_LIBRARIES}
+    ${LIBBACKTRACE_LIBRARIES}
 )
 
 add_library (glretrace_common STATIC