[PATCH 6/9] Implement libbacktrace provider

Alexander Monakov amonakov at ispras.ru
Sun May 19 07:39:52 PDT 2013


---
 common/trace_backtrace.cpp | 92 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 92 insertions(+)

diff --git a/common/trace_backtrace.cpp b/common/trace_backtrace.cpp
index 93991a9..831de68 100644
--- a/common/trace_backtrace.cpp
+++ b/common/trace_backtrace.cpp
@@ -272,6 +272,8 @@ std::vector<RawStackFrame> get_backtrace() {
 /* end ANDROID */
 #elif defined __linux__
 
+#include <stdint.h>
+#include <dlfcn.h>
 #include <execinfo.h>
 #include <string.h>
 #include <stdlib.h>
@@ -279,6 +281,8 @@ std::vector<RawStackFrame> get_backtrace() {
 #include <vector>
 #include <stdio.h>
 
+#include "backtrace.h"
+
 namespace trace {
 
 
@@ -286,6 +290,94 @@ namespace trace {
 
 #define BT_DEPTH 10
 
+class libbacktraceProvider {
+    struct backtrace_state *state;
+    int skipFrames;
+    Id nextFrameId;
+    std::map<uintptr_t, std::vector<RawStackFrame> > cache;
+    std::vector<RawStackFrame> *current, *current_frames;
+    RawStackFrame *current_frame;
+
+    static void bt_err_callback(void *vdata, const char *msg, int errnum)
+    {
+        if (errnum == -1)
+            return;// no debug/sym info
+        else if (errnum)
+            os::log("libbacktrace: %s: %s\n", msg, strerror(errnum));
+        else
+            os::log("libbacktrace: %s\n", msg);
+    }
+
+    static int bt_countskip(void *vdata, uintptr_t pc)
+    {
+        libbacktraceProvider *this_ = (libbacktraceProvider*)vdata;
+        Dl_info info1, info2;
+        if (!dladdr((void*)bt_countskip, &info2)) {
+            os::log("dladdr failed, cannot cull stack traces\n");
+            return 1;
+        }
+        if (!dladdr((void*)pc, &info1))
+            return 1;
+        if (info1.dli_fbase != info2.dli_fbase)
+            return 1;
+        this_->skipFrames++;
+        return 0;
+    }
+
+    static int bt_full_callback(void *vdata, uintptr_t pc,
+                                 const char *file, int line, const char *func)
+    {
+        libbacktraceProvider *this_ = (libbacktraceProvider*)vdata;
+        RawStackFrame frame = *this_->current_frame;
+        frame.id = this_->nextFrameId++;
+        frame.filename = file;
+        frame.linenumber = line;
+        if (func)
+            frame.function = func;
+        this_->current_frames->push_back(frame);
+        return 0;
+    }
+
+    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;
+            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;
+    }
+
+public:
+    libbacktraceProvider():
+        state(backtrace_create_state(NULL, 0, bt_err_callback, NULL))
+    {
+        backtrace_simple(state, 0, bt_countskip, bt_err_callback, this);
+    }
+
+    std::vector<RawStackFrame> getParsedBacktrace()
+    {
+        std::vector<RawStackFrame> parsedBacktrace;
+        current = &parsedBacktrace;
+        backtrace_simple(state, skipFrames, bt_callback, bt_err_callback, this);
+        return parsedBacktrace;
+    }
+};
+
 class GlibcBacktraceProvider {
 private:
     std::map<void*, RawStackFrame*> cache;
-- 
1.8.1.2



More information about the apitrace mailing list