summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt2
-rw-r--r--cli/CMakeLists.txt1
-rw-r--r--common/os_backtrace.cpp105
-rw-r--r--common/os_backtrace.hpp10
-rw-r--r--common/os_posix.cpp9
-rw-r--r--gui/CMakeLists.txt1
-rw-r--r--retrace/CMakeLists.txt1
7 files changed, 116 insertions, 13 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index b2de6bbc..15fff3f3 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 299c3985..e2b4d720 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 7f194951..fbe74455 100644
--- a/common/os_backtrace.cpp
+++ b/common/os_backtrace.cpp
@@ -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 */
diff --git a/common/os_backtrace.hpp b/common/os_backtrace.hpp
index 43dbb417..ae1c831a 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 967d12eb..5d6bffe5 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 ad13475e..a36ab47b 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 78cceae3..fcb8f187 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