[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