[compiler-rt] r201151 - [sanitizer] Use system unwinder in signal handlers on Android.

Evgeniy Stepanov eugeni.stepanov at gmail.com
Tue Feb 11 05:38:58 PST 2014


Author: eugenis
Date: Tue Feb 11 07:38:57 2014
New Revision: 201151

URL: http://llvm.org/viewvc/llvm-project?rev=201151&view=rev
Log:
[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.

Modified:
    compiler-rt/trunk/lib/asan/asan_posix.cc
    compiler-rt/trunk/lib/asan/asan_report.cc
    compiler-rt/trunk/lib/asan/asan_report.h
    compiler-rt/trunk/lib/asan/asan_rtl.cc
    compiler-rt/trunk/lib/asan/asan_stack.h
    compiler-rt/trunk/lib/msan/msan.cc
    compiler-rt/trunk/lib/sanitizer_common/sanitizer_common.h
    compiler-rt/trunk/lib/sanitizer_common/sanitizer_linux_libcdep.cc
    compiler-rt/trunk/lib/sanitizer_common/sanitizer_stacktrace.h
    compiler-rt/trunk/lib/sanitizer_common/sanitizer_stacktrace_libcdep.cc
    compiler-rt/trunk/lib/tsan/rtl/tsan_rtl_report.cc

Modified: compiler-rt/trunk/lib/asan/asan_posix.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/asan_posix.cc?rev=201151&r1=201150&r2=201151&view=diff
==============================================================================
--- compiler-rt/trunk/lib/asan/asan_posix.cc (original)
+++ compiler-rt/trunk/lib/asan/asan_posix.cc Tue Feb 11 07:38:57 2014
@@ -38,7 +38,7 @@ void AsanOnSIGSEGV(int, void *siginfo, v
   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

Modified: compiler-rt/trunk/lib/asan/asan_report.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/asan_report.cc?rev=201151&r1=201150&r2=201151&view=diff
==============================================================================
--- compiler-rt/trunk/lib/asan/asan_report.cc (original)
+++ compiler-rt/trunk/lib/asan/asan_report.cc Tue Feb 11 07:38:57 2014
@@ -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, upt
              (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);

Modified: compiler-rt/trunk/lib/asan/asan_report.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/asan_report.h?rev=201151&r1=201150&r2=201151&view=diff
==============================================================================
--- compiler-rt/trunk/lib/asan/asan_report.h (original)
+++ compiler-rt/trunk/lib/asan/asan_report.h Tue Feb 11 07:38:57 2014
@@ -32,7 +32,8 @@ void DescribeAddress(uptr addr, uptr acc
 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,

Modified: compiler-rt/trunk/lib/asan/asan_rtl.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/asan_rtl.cc?rev=201151&r1=201150&r2=201151&view=diff
==============================================================================
--- compiler-rt/trunk/lib/asan/asan_rtl.cc (original)
+++ compiler-rt/trunk/lib/asan/asan_rtl.cc Tue Feb 11 07:38:57 2014
@@ -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();

Modified: compiler-rt/trunk/lib/asan/asan_stack.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/asan_stack.h?rev=201151&r1=201150&r2=201151&view=diff
==============================================================================
--- compiler-rt/trunk/lib/asan/asan_stack.h (original)
+++ compiler-rt/trunk/lib/asan/asan_stack.h Tue Feb 11 07:38:57 2014
@@ -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)

Modified: compiler-rt/trunk/lib/msan/msan.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/msan/msan.cc?rev=201151&r1=201150&r2=201151&view=diff
==============================================================================
--- compiler-rt/trunk/lib/msan/msan.cc (original)
+++ compiler-rt/trunk/lib/msan/msan.cc Tue Feb 11 07:38:57 2014
@@ -154,11 +154,11 @@ void GetStackTrace(StackTrace *stack, up
   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) {

Modified: compiler-rt/trunk/lib/sanitizer_common/sanitizer_common.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/sanitizer_common/sanitizer_common.h?rev=201151&r1=201150&r2=201151&view=diff
==============================================================================
--- compiler-rt/trunk/lib/sanitizer_common/sanitizer_common.h (original)
+++ compiler-rt/trunk/lib/sanitizer_common/sanitizer_common.h Tue Feb 11 07:38:57 2014
@@ -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
 

Modified: compiler-rt/trunk/lib/sanitizer_common/sanitizer_linux_libcdep.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/sanitizer_common/sanitizer_linux_libcdep.cc?rev=201151&r1=201150&r2=201151&view=diff
==============================================================================
--- compiler-rt/trunk/lib/sanitizer_common/sanitizer_linux_libcdep.cc (original)
+++ compiler-rt/trunk/lib/sanitizer_common/sanitizer_linux_libcdep.cc Tue Feb 11 07:38:57 2014
@@ -142,6 +142,51 @@ bool SanitizerGetThreadName(char *name,
 
 #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
   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;

Modified: compiler-rt/trunk/lib/sanitizer_common/sanitizer_stacktrace.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/sanitizer_common/sanitizer_stacktrace.h?rev=201151&r1=201150&r2=201151&view=diff
==============================================================================
--- compiler-rt/trunk/lib/sanitizer_common/sanitizer_stacktrace.h (original)
+++ compiler-rt/trunk/lib/sanitizer_common/sanitizer_stacktrace.h Tue Feb 11 07:38:57 2014
@@ -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);
 };

Modified: compiler-rt/trunk/lib/sanitizer_common/sanitizer_stacktrace_libcdep.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/sanitizer_common/sanitizer_stacktrace_libcdep.cc?rev=201151&r1=201150&r2=201151&view=diff
==============================================================================
--- compiler-rt/trunk/lib/sanitizer_common/sanitizer_stacktrace_libcdep.cc (original)
+++ compiler-rt/trunk/lib/sanitizer_common/sanitizer_stacktrace_libcdep.cc Tue Feb 11 07:38:57 2014
@@ -63,12 +63,17 @@ void StackTrace::PrintStack(const uptr *
   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;
 }

Modified: compiler-rt/trunk/lib/tsan/rtl/tsan_rtl_report.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/rtl/tsan_rtl_report.cc?rev=201151&r1=201150&r2=201151&view=diff
==============================================================================
--- compiler-rt/trunk/lib/tsan/rtl/tsan_rtl_report.cc (original)
+++ compiler-rt/trunk/lib/tsan/rtl/tsan_rtl_report.cc Tue Feb 11 07:38:57 2014
@@ -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];





More information about the llvm-commits mailing list