summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAliaksey Kandratsenka <alk@tut.by>2013-05-18 17:11:58 -0700
committerAliaksey Kandratsenka <alk@tut.by>2014-01-18 17:21:00 -0800
commit64bc1baa1f4723d73ba40cd730b72896bd45a810 (patch)
treec5eb1b50b51e09e56f04189d9369928e2f0a2733
parent185bf3fcc36f8cb3839abdfe652f615bfb5306d1 (diff)
downloadgperftools-64bc1baa1f4723d73ba40cd730b72896bd45a810.tar.gz
issue-{66,547}: use signal's ucontext when unwinding backtrace
In issue-66 (and readme) it is pointed out that sometimes there are some issues grabbing backtrace across signal handler boundary. This code attempts to fix it by grabbing backtrace from signal's ucontext which clearly does not include signal handler boundary. We're using "feature" of libunwind that for some important platforms libunwind's context is same as libc's ucontext_t which is given to us as part of calling signal handler.
-rw-r--r--src/stacktrace_libunwind-inl.h23
1 files changed, 22 insertions, 1 deletions
diff --git a/src/stacktrace_libunwind-inl.h b/src/stacktrace_libunwind-inl.h
index cfa5aee..d75bc18 100644
--- a/src/stacktrace_libunwind-inl.h
+++ b/src/stacktrace_libunwind-inl.h
@@ -58,6 +58,10 @@ extern "C" {
// cases, we return 0 to indicate the situation.
static __thread int recursive;
+#if (defined(__i386__) || defined(__x86_64__)) && defined(__GNU_LIBRARY__)
+#define BASE_STACKTRACE_UNW_CONTEXT_IS_UCONTEXT 1
+#endif
+
#endif // BASE_STACKTRACE_LIBINWIND_INL_H_
// Note: this part of the file is included several times.
@@ -88,10 +92,27 @@ int GET_STACK_TRACE_OR_FRAMES {
}
++recursive;
+#if (IS_WITH_CONTEXT && defined(BASE_STACKTRACE_UNW_CONTEXT_IS_UCONTEXT))
+ if (ucp) {
+ uc = *(static_cast<unw_context_t *>(const_cast<void *>(ucp)));
+ /* this is a bit weird. profiler.cc calls us with signal's ucontext
+ * yet passing us 2 as skip_count and essentially assuming we won't
+ * use ucontext. */
+ /* In order to fix that I'm going to assume that if ucp is
+ * non-null we're asked to ignore skip_count in case we're
+ * able to use ucp */
+ skip_count = 0;
+ } else {
+ unw_getcontext(&uc);
+ skip_count++; // Do not include current frame
+ }
+#else
unw_getcontext(&uc);
+ skip_count++; // Do not include current frame
+#endif
+
int ret = unw_init_local(&cursor, &uc);
assert(ret >= 0);
- skip_count++; // Do not include current frame
while (skip_count--) {
if (unw_step(&cursor) <= 0) {