From: Alexander Monakov Date: Sun, 19 May 2013 10:53:52 +0000 (+0400) Subject: Implement libbacktrace provider X-Git-Url: https://git.cworth.org/git?a=commitdiff_plain;h=1beb93552d7dab96e4e2dd1b84d831c019ae7fb9;p=apitrace Implement libbacktrace provider --- 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 get_backtrace() { /* end ANDROID */ #elif defined __linux__ +#include +#include #include #include #include @@ -279,6 +281,8 @@ std::vector get_backtrace() { #include #include +#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 > cache; + std::vector *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 &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 getParsedBacktrace() + { + std::vector parsedBacktrace; + current = &parsedBacktrace; + backtrace_simple(state, skipFrames, bt_callback, bt_err_callback, this); + return parsedBacktrace; + } +}; + class GlibcBacktraceProvider { private: std::map cache;