summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEvgeniy Stepanov <eugeni.stepanov@gmail.com>2014-02-11 13:38:57 +0000
committerEvgeniy Stepanov <eugeni.stepanov@gmail.com>2014-02-11 13:38:57 +0000
commit1df9cbe3938900c62cad6819fd98f34c58ce0c3f (patch)
tree78c5cfabd60fd09dee31b2a22ef34ff4a3bd8fb3
parent11f9ef758b4505ac5c3d9d38f0cdb01fd13e9a8e (diff)
[sanitizer] Use system unwinder in signal handlers on Android.
Because of the way Bionic sets up signal stack frames, libc unwinder is unable to step through it, resulting in broken SEGV stack traces. Luckily, libcorkscrew.so on Android implements an unwinder that can start with a signal context, thus sidestepping the issue. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@201151 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--lib/asan/asan_posix.cc2
-rw-r--r--lib/asan/asan_report.cc4
-rw-r--r--lib/asan/asan_report.h3
-rw-r--r--lib/asan/asan_rtl.cc1
-rw-r--r--lib/asan/asan_stack.h28
-rw-r--r--lib/msan/msan.cc4
-rw-r--r--lib/sanitizer_common/sanitizer_common.h2
-rw-r--r--lib/sanitizer_common/sanitizer_linux_libcdep.cc70
-rw-r--r--lib/sanitizer_common/sanitizer_stacktrace.h4
-rw-r--r--lib/sanitizer_common/sanitizer_stacktrace_libcdep.cc15
-rw-r--r--lib/tsan/rtl/tsan_rtl_report.cc4
11 files changed, 111 insertions, 26 deletions
diff --git a/lib/asan/asan_posix.cc b/lib/asan/asan_posix.cc
index d4bf84f8e..05064f459 100644
--- a/lib/asan/asan_posix.cc
+++ b/lib/asan/asan_posix.cc
@@ -38,7 +38,7 @@ void AsanOnSIGSEGV(int, void *siginfo, void *context) {
if (13 != internal_write(2, "ASAN:SIGSEGV\n", 13)) Die();
uptr pc, sp, bp;
GetPcSpBp(context, &pc, &sp, &bp);
- ReportSIGSEGV(pc, sp, bp, addr);
+ ReportSIGSEGV(pc, sp, bp, context, addr);
}
// ---------------------- TSD ---------------- {{{1
diff --git a/lib/asan/asan_report.cc b/lib/asan/asan_report.cc
index a09df3922..bd900e8c5 100644
--- a/lib/asan/asan_report.cc
+++ b/lib/asan/asan_report.cc
@@ -570,7 +570,7 @@ class ScopedInErrorReport {
}
};
-void ReportSIGSEGV(uptr pc, uptr sp, uptr bp, uptr addr) {
+void ReportSIGSEGV(uptr pc, uptr sp, uptr bp, void *context, uptr addr) {
ScopedInErrorReport in_report;
Decorator d;
Printf("%s", d.Warning());
@@ -579,7 +579,7 @@ void ReportSIGSEGV(uptr pc, uptr sp, uptr bp, uptr addr) {
(void*)addr, (void*)pc, (void*)sp, (void*)bp,
GetCurrentTidOrInvalid());
Printf("%s", d.EndWarning());
- GET_STACK_TRACE_FATAL(pc, bp);
+ GET_STACK_TRACE_SIGNAL(pc, bp, context);
stack.Print();
Printf("AddressSanitizer can not provide additional info.\n");
ReportErrorSummary("SEGV", &stack);
diff --git a/lib/asan/asan_report.h b/lib/asan/asan_report.h
index b8ebd9b86..c4e8611d2 100644
--- a/lib/asan/asan_report.h
+++ b/lib/asan/asan_report.h
@@ -32,7 +32,8 @@ void DescribeAddress(uptr addr, uptr access_size);
void DescribeThread(AsanThreadContext *context);
// Different kinds of error reports.
-void NORETURN ReportSIGSEGV(uptr pc, uptr sp, uptr bp, uptr addr);
+void NORETURN
+ ReportSIGSEGV(uptr pc, uptr sp, uptr bp, void *context, uptr addr);
void NORETURN ReportDoubleFree(uptr addr, StackTrace *free_stack);
void NORETURN ReportFreeNotMalloced(uptr addr, StackTrace *free_stack);
void NORETURN ReportAllocTypeMismatch(uptr addr, StackTrace *free_stack,
diff --git a/lib/asan/asan_rtl.cc b/lib/asan/asan_rtl.cc
index 478bbf418..1cb22d0ab 100644
--- a/lib/asan/asan_rtl.cc
+++ b/lib/asan/asan_rtl.cc
@@ -532,6 +532,7 @@ static void AsanInitInternal() {
SetCurrentThread(main_thread);
main_thread->ThreadStart(internal_getpid());
force_interface_symbols(); // no-op.
+ SanitizerInitializeUnwinder();
#if CAN_SANITIZE_LEAKS
__lsan::InitCommonLsan();
diff --git a/lib/asan/asan_stack.h b/lib/asan/asan_stack.h
index ac7f275bb..f7abb9335 100644
--- a/lib/asan/asan_stack.h
+++ b/lib/asan/asan_stack.h
@@ -23,11 +23,11 @@
// The pc will be in the position 0 of the resulting stack trace.
// The bp may refer to the current frame or to the caller's frame.
#if SANITIZER_WINDOWS
-#define GET_STACK_TRACE_WITH_PC_AND_BP(max_s, pc, bp, fast) \
- StackTrace stack; \
- stack.Unwind(max_s, pc, bp, 0, 0, fast)
+#define GET_STACK_TRACE_WITH_PC_BP_AND_CONTEXT(max_s, pc, bp, context, fast) \
+ StackTrace stack; \
+ stack.Unwind(max_s, pc, bp, context, 0, 0, fast)
#else
-#define GET_STACK_TRACE_WITH_PC_AND_BP(max_s, pc, bp, fast) \
+#define GET_STACK_TRACE_WITH_PC_BP_AND_CONTEXT(max_s, pc, bp, context, fast) \
StackTrace stack; \
{ \
AsanThread *t; \
@@ -37,10 +37,10 @@
uptr stack_top = t->stack_top(); \
uptr stack_bottom = t->stack_bottom(); \
ScopedUnwinding unwind_scope(t); \
- stack.Unwind(max_s, pc, bp, stack_top, stack_bottom, fast); \
+ stack.Unwind(max_s, pc, bp, context, stack_top, stack_bottom, fast); \
} else if (t == 0 && !fast) { \
/* If GetCurrentThread() has failed, try to do slow unwind anyways. */ \
- stack.Unwind(max_s, pc, bp, 0, 0, false); \
+ stack.Unwind(max_s, pc, bp, context, 0, 0, false); \
} \
} \
}
@@ -50,13 +50,17 @@
// as early as possible (in functions exposed to the user), as we generally
// don't want stack trace to contain functions from ASan internals.
-#define GET_STACK_TRACE(max_size, fast) \
- GET_STACK_TRACE_WITH_PC_AND_BP(max_size, \
- StackTrace::GetCurrentPc(), GET_CURRENT_FRAME(), fast)
+#define GET_STACK_TRACE(max_size, fast) \
+ GET_STACK_TRACE_WITH_PC_BP_AND_CONTEXT(max_size, StackTrace::GetCurrentPc(), \
+ GET_CURRENT_FRAME(), 0, fast)
-#define GET_STACK_TRACE_FATAL(pc, bp) \
- GET_STACK_TRACE_WITH_PC_AND_BP(kStackTraceMax, pc, bp, \
- common_flags()->fast_unwind_on_fatal)
+#define GET_STACK_TRACE_FATAL(pc, bp) \
+ GET_STACK_TRACE_WITH_PC_BP_AND_CONTEXT(kStackTraceMax, pc, bp, 0, \
+ common_flags()->fast_unwind_on_fatal)
+
+#define GET_STACK_TRACE_SIGNAL(pc, bp, context) \
+ GET_STACK_TRACE_WITH_PC_BP_AND_CONTEXT(kStackTraceMax, pc, bp, context, \
+ common_flags()->fast_unwind_on_fatal)
#define GET_STACK_TRACE_FATAL_HERE \
GET_STACK_TRACE(kStackTraceMax, common_flags()->fast_unwind_on_fatal)
diff --git a/lib/msan/msan.cc b/lib/msan/msan.cc
index 6e56657f0..4e9aa57bc 100644
--- a/lib/msan/msan.cc
+++ b/lib/msan/msan.cc
@@ -154,11 +154,11 @@ void GetStackTrace(StackTrace *stack, uptr max_s, uptr pc, uptr bp,
if (!StackTrace::WillUseFastUnwind(request_fast_unwind)) {
// Block reports from our interceptors during _Unwind_Backtrace.
SymbolizerScope sym_scope;
- return stack->Unwind(max_s, pc, bp, 0, 0, request_fast_unwind);
+ return stack->Unwind(max_s, pc, bp, 0, 0, 0, request_fast_unwind);
}
uptr stack_bottom = msan_stack_bounds.stack_addr;
uptr stack_top = stack_bottom + msan_stack_bounds.stack_size;
- stack->Unwind(max_s, pc, bp, stack_top, stack_bottom, request_fast_unwind);
+ stack->Unwind(max_s, pc, bp, 0, stack_top, stack_bottom, request_fast_unwind);
}
void PrintWarning(uptr pc, uptr bp) {
diff --git a/lib/sanitizer_common/sanitizer_common.h b/lib/sanitizer_common/sanitizer_common.h
index 059c40bac..5581fb6ef 100644
--- a/lib/sanitizer_common/sanitizer_common.h
+++ b/lib/sanitizer_common/sanitizer_common.h
@@ -509,9 +509,11 @@ F IndirectExternCall(F f) {
#if SANITIZER_ANDROID
void AndroidLogWrite(const char *buffer);
void GetExtraActivationFlags(char *buf, uptr size);
+void SanitizerInitializeUnwinder();
#else
INLINE void AndroidLogWrite(const char *buffer_unused) {}
INLINE void GetExtraActivationFlags(char *buf, uptr size) { *buf = '\0'; }
+INLINE void SanitizerInitializeUnwinder() {}
#endif
} // namespace __sanitizer
diff --git a/lib/sanitizer_common/sanitizer_linux_libcdep.cc b/lib/sanitizer_common/sanitizer_linux_libcdep.cc
index ac8dfa163..c3724770c 100644
--- a/lib/sanitizer_common/sanitizer_linux_libcdep.cc
+++ b/lib/sanitizer_common/sanitizer_linux_libcdep.cc
@@ -142,6 +142,51 @@ bool SanitizerGetThreadName(char *name, int max_len) {
#ifndef SANITIZER_GO
//------------------------- SlowUnwindStack -----------------------------------
+
+typedef struct {
+ uptr absolute_pc;
+ uptr stack_top;
+ uptr stack_size;
+} backtrace_frame_t;
+
+extern "C" {
+typedef void *(*acquire_my_map_info_list_func)();
+typedef void (*release_my_map_info_list_func)(void *map);
+typedef sptr (*unwind_backtrace_signal_arch_func)(
+ void *siginfo, void *sigcontext, void *map_info_list,
+ backtrace_frame_t *backtrace, uptr ignore_depth, uptr max_depth);
+acquire_my_map_info_list_func acquire_my_map_info_list;
+release_my_map_info_list_func release_my_map_info_list;
+unwind_backtrace_signal_arch_func unwind_backtrace_signal_arch;
+} // extern "C"
+
+#if SANITIZER_ANDROID
+void SanitizerInitializeUnwinder() {
+ void *p = dlopen("libcorkscrew.so", RTLD_LAZY);
+ if (!p) {
+ VReport(1,
+ "Failed to open libcorkscrew.so. You may see broken stack traces "
+ "in SEGV reports.");
+ return;
+ }
+ acquire_my_map_info_list =
+ (acquire_my_map_info_list_func)(uptr)dlsym(p, "acquire_my_map_info_list");
+ release_my_map_info_list =
+ (release_my_map_info_list_func)(uptr)dlsym(p, "release_my_map_info_list");
+ unwind_backtrace_signal_arch = (unwind_backtrace_signal_arch_func)(uptr)dlsym(
+ p, "unwind_backtrace_signal_arch");
+ if (!acquire_my_map_info_list || !release_my_map_info_list ||
+ !unwind_backtrace_signal_arch) {
+ VReport(1,
+ "Failed to find one of the required symbols in libcorkscrew.so. "
+ "You may see broken stack traces in SEGV reports.");
+ acquire_my_map_info_list = NULL;
+ unwind_backtrace_signal_arch = NULL;
+ release_my_map_info_list = NULL;
+ }
+}
+#endif
+
#ifdef __arm__
#define UNWIND_STOP _URC_END_OF_STACK
#define UNWIND_CONTINUE _URC_NO_REASON
@@ -192,6 +237,31 @@ void StackTrace::SlowUnwindStack(uptr pc, uptr max_depth) {
trace[0] = pc;
}
+void StackTrace::SlowUnwindStackWithContext(uptr pc, void *context,
+ uptr max_depth) {
+ if (!unwind_backtrace_signal_arch) {
+ SlowUnwindStack(pc, max_depth);
+ return;
+ }
+
+ size = 0;
+ if (max_depth == 0) return;
+
+ void *map = acquire_my_map_info_list();
+ CHECK(map);
+ backtrace_frame_t frames[kStackTraceMax];
+ // siginfo argument appears to be unused.
+ sptr res =
+ unwind_backtrace_signal_arch(/* siginfo */ NULL, context, map, frames,
+ /* ignore_depth */ 0, max_depth);
+ release_my_map_info_list(map);
+ if (res < 0) return;
+ CHECK((uptr)res <= kStackTraceMax);
+
+ for (sptr i = 0; i < res; ++i)
+ trace[size++] = frames[i].absolute_pc;
+}
+
#endif // !SANITIZER_GO
static uptr g_tls_size;
diff --git a/lib/sanitizer_common/sanitizer_stacktrace.h b/lib/sanitizer_common/sanitizer_stacktrace.h
index b6e827f19..9d067b1c9 100644
--- a/lib/sanitizer_common/sanitizer_stacktrace.h
+++ b/lib/sanitizer_common/sanitizer_stacktrace.h
@@ -58,7 +58,7 @@ struct StackTrace {
return request_fast_unwind;
}
- void Unwind(uptr max_depth, uptr pc, uptr bp, uptr stack_top,
+ void Unwind(uptr max_depth, uptr pc, uptr bp, void *context, uptr stack_top,
uptr stack_bottom, bool request_fast_unwind);
static uptr GetCurrentPc();
@@ -68,6 +68,8 @@ struct StackTrace {
void FastUnwindStack(uptr pc, uptr bp, uptr stack_top, uptr stack_bottom,
uptr max_depth);
void SlowUnwindStack(uptr pc, uptr max_depth);
+ void SlowUnwindStackWithContext(uptr pc, void *context,
+ uptr max_depth);
void PopStackFrames(uptr count);
uptr LocatePcInTrace(uptr pc);
};
diff --git a/lib/sanitizer_common/sanitizer_stacktrace_libcdep.cc b/lib/sanitizer_common/sanitizer_stacktrace_libcdep.cc
index ffc4f2ede..1b16c4dac 100644
--- a/lib/sanitizer_common/sanitizer_stacktrace_libcdep.cc
+++ b/lib/sanitizer_common/sanitizer_stacktrace_libcdep.cc
@@ -63,12 +63,17 @@ void StackTrace::PrintStack(const uptr *addr, uptr size) {
Printf("\n");
}
-void StackTrace::Unwind(uptr max_depth, uptr pc, uptr bp, uptr stack_top,
- uptr stack_bottom, bool request_fast_unwind) {
- if (!WillUseFastUnwind(request_fast_unwind))
- SlowUnwindStack(pc, max_depth);
- else
+void StackTrace::Unwind(uptr max_depth, uptr pc, uptr bp, void *context,
+ uptr stack_top, uptr stack_bottom,
+ bool request_fast_unwind) {
+ if (!WillUseFastUnwind(request_fast_unwind)) {
+ if (context)
+ SlowUnwindStackWithContext(pc, context, max_depth);
+ else
+ SlowUnwindStack(pc, max_depth);
+ } else {
FastUnwindStack(pc, bp, stack_top, stack_bottom, max_depth);
+ }
top_frame_bp = size ? bp : 0;
}
diff --git a/lib/tsan/rtl/tsan_rtl_report.cc b/lib/tsan/rtl/tsan_rtl_report.cc
index c02fe6161..b1741298b 100644
--- a/lib/tsan/rtl/tsan_rtl_report.cc
+++ b/lib/tsan/rtl/tsan_rtl_report.cc
@@ -713,8 +713,8 @@ void PrintCurrentStackSlow() {
#ifndef TSAN_GO
__sanitizer::StackTrace *ptrace = new(internal_alloc(MBlockStackTrace,
sizeof(__sanitizer::StackTrace))) __sanitizer::StackTrace;
- ptrace->Unwind(kStackTraceMax, __sanitizer::StackTrace::GetCurrentPc(),
- 0, 0, 0, false);
+ ptrace->Unwind(kStackTraceMax, __sanitizer::StackTrace::GetCurrentPc(), 0, 0,
+ 0, 0, false);
for (uptr i = 0; i < ptrace->size / 2; i++) {
uptr tmp = ptrace->trace[i];
ptrace->trace[i] = ptrace->trace[ptrace->size - i - 1];