diff --git a/compiler-rt/lib/asan/asan_linux.cc b/compiler-rt/lib/asan/asan_linux.cc index 148b5f053b46..17bb4ca5f01c 100644 --- a/compiler-rt/lib/asan/asan_linux.cc +++ b/compiler-rt/lib/asan/asan_linux.cc @@ -102,24 +102,6 @@ void AsanPlatformThreadInit() { // Nothing here for now. } -void GetStackTrace(StackTrace *stack, uptr max_s, uptr pc, uptr bp, bool fast) { -#if defined(__arm__) || \ - defined(__powerpc__) || defined(__powerpc64__) || \ - defined(__sparc__) - fast = false; -#endif - if (!fast) - return stack->SlowUnwindStack(pc, max_s); - stack->size = 0; - stack->trace[0] = pc; - if (max_s > 1) { - stack->max_size = max_s; - if (!asan_inited) return; - if (AsanThread *t = GetCurrentThread()) - stack->FastUnwindStack(pc, bp, t->stack_top(), t->stack_bottom()); - } -} - #if !SANITIZER_ANDROID void ReadContextStack(void *context, uptr *stack, uptr *ssize) { ucontext_t *ucp = (ucontext_t*)context; diff --git a/compiler-rt/lib/asan/asan_mac.cc b/compiler-rt/lib/asan/asan_mac.cc index 63fb5f6dd31b..4313534008e7 100644 --- a/compiler-rt/lib/asan/asan_mac.cc +++ b/compiler-rt/lib/asan/asan_mac.cc @@ -229,18 +229,6 @@ bool AsanInterceptsSignal(int signum) { void AsanPlatformThreadInit() { } -void GetStackTrace(StackTrace *stack, uptr max_s, uptr pc, uptr bp, bool fast) { - (void)fast; - stack->size = 0; - stack->trace[0] = pc; - if ((max_s) > 1) { - stack->max_size = max_s; - if (!asan_inited) return; - if (AsanThread *t = GetCurrentThread()) - stack->FastUnwindStack(pc, bp, t->stack_top(), t->stack_bottom()); - } -} - void ReadContextStack(void *context, uptr *stack, uptr *ssize) { UNIMPLEMENTED(); } diff --git a/compiler-rt/lib/asan/asan_stack.h b/compiler-rt/lib/asan/asan_stack.h index cd30abbb4b21..176aa183c93b 100644 --- a/compiler-rt/lib/asan/asan_stack.h +++ b/compiler-rt/lib/asan/asan_stack.h @@ -15,12 +15,12 @@ #define ASAN_STACK_H #include "asan_flags.h" +#include "asan_thread.h" #include "sanitizer_common/sanitizer_flags.h" #include "sanitizer_common/sanitizer_stacktrace.h" namespace __asan { -void GetStackTrace(StackTrace *stack, uptr max_s, uptr pc, uptr bp, bool fast); void PrintStack(StackTrace *stack); } // namespace __asan @@ -28,10 +28,24 @@ void PrintStack(StackTrace *stack); // Get the stack trace with the given pc and bp. // 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. -// fast_unwind is currently unused. +#if SANITIZER_WINDOWS #define GET_STACK_TRACE_WITH_PC_AND_BP(max_s, pc, bp, fast) \ StackTrace stack; \ - GetStackTrace(&stack, max_s, pc, bp, fast) + GetStackTrace(&stack, max_s, pc, bp, 0, 0, fast) +#else +#define GET_STACK_TRACE_WITH_PC_AND_BP(max_s, pc, bp, fast) \ + StackTrace stack; \ + { \ + uptr stack_top = 0, stack_bottom = 0; \ + AsanThread *t; \ + if (asan_inited && (t = GetCurrentThread())) { \ + stack_top = t->stack_top(); \ + stack_bottom = t->stack_bottom(); \ + } \ + GetStackTrace(&stack, max_s, pc, bp, \ + stack_top, stack_bottom, fast); \ + } +#endif // SANITIZER_WINDOWS // NOTE: A Rule of thumb is to retrieve stack trace in the interceptors // as early as possible (in functions exposed to the user), as we generally diff --git a/compiler-rt/lib/asan/asan_win.cc b/compiler-rt/lib/asan/asan_win.cc index 49a389971c43..f74de7227ed2 100644 --- a/compiler-rt/lib/asan/asan_win.cc +++ b/compiler-rt/lib/asan/asan_win.cc @@ -32,30 +32,6 @@ static BlockingMutex dbghelp_lock(LINKER_INITIALIZED); static bool dbghelp_initialized = false; #pragma comment(lib, "dbghelp.lib") -void GetStackTrace(StackTrace *stack, uptr max_s, uptr pc, uptr bp, bool fast) { - (void)fast; - stack->max_size = max_s; - void *tmp[kStackTraceMax]; - - // FIXME: CaptureStackBackTrace might be too slow for us. - // FIXME: Compare with StackWalk64. - // FIXME: Look at LLVMUnhandledExceptionFilter in Signals.inc - uptr cs_ret = CaptureStackBackTrace(1, stack->max_size, tmp, 0); - uptr offset = 0; - // Skip the RTL frames by searching for the PC in the stacktrace. - // FIXME: this doesn't work well for the malloc/free stacks yet. - for (uptr i = 0; i < cs_ret; i++) { - if (pc != (uptr)tmp[i]) - continue; - offset = i; - break; - } - - stack->size = cs_ret - offset; - for (uptr i = 0; i < stack->size; i++) - stack->trace[i] = (uptr)tmp[i + offset]; -} - // ---------------------- TSD ---------------- {{{1 static bool tsd_key_inited = false; diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_posix.cc b/compiler-rt/lib/sanitizer_common/sanitizer_posix.cc index 2aae414fefe9..7fec5cf4c366 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_posix.cc +++ b/compiler-rt/lib/sanitizer_common/sanitizer_posix.cc @@ -18,6 +18,7 @@ #include "sanitizer_common.h" #include "sanitizer_libc.h" #include "sanitizer_procmaps.h" +#include "sanitizer_stacktrace.h" #include #include @@ -228,6 +229,26 @@ int internal_isatty(fd_t fd) { return isatty(fd); } +void GetStackTrace(StackTrace *stack, uptr max_s, uptr pc, uptr bp, + uptr stack_top, uptr stack_bottom, bool fast) { +#if !SANITIZER_CAN_FAST_UNWIND + fast = false; +#endif +#if SANITIZER_MAC + // Always unwind fast on Mac. + (void)fast; +#else + if (!fast || (stack_top == stack_bottom)) + return stack->SlowUnwindStack(pc, max_s); +#endif // SANITIZER_MAC + stack->size = 0; + stack->trace[0] = pc; + if (max_s > 1) { + stack->max_size = max_s; + stack->FastUnwindStack(pc, bp, stack_top, stack_bottom); + } +} + } // namespace __sanitizer -#endif // SANITIZER_LINUX || __APPLE_ +#endif // SANITIZER_LINUX || SANITIZER_MAC diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace.h b/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace.h index b9ea9b43592d..fcfdd7e0b59b 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace.h @@ -19,6 +19,14 @@ namespace __sanitizer { static const uptr kStackTraceMax = 256; +#if SANITIZER_LINUX && (defined(__arm__) || \ + defined(__powerpc__) || defined(__powerpc64__) || \ + defined(__sparc__)) +#define SANITIZER_CAN_FAST_UNWIND 0 +#else +#define SANITIZER_CAN_FAST_UNWIND 1 +#endif + struct StackTrace { typedef bool (*SymbolizeCallback)(const void *pc, char *out_buffer, int out_size); @@ -61,6 +69,9 @@ struct StackTrace { const char *StripPathPrefix(const char *filepath, const char *strip_file_prefix); +void GetStackTrace(StackTrace *stack, uptr max_s, uptr pc, uptr bp, + uptr stack_top, uptr stack_bottom, bool fast); + } // namespace __sanitizer // Use this macro if you want to print stack trace with the caller diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_win.cc b/compiler-rt/lib/sanitizer_common/sanitizer_win.cc index 48874a1dc8eb..95445be65461 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_win.cc +++ b/compiler-rt/lib/sanitizer_common/sanitizer_win.cc @@ -23,8 +23,9 @@ #include "sanitizer_common.h" #include "sanitizer_libc.h" -#include "sanitizer_placement_new.h" #include "sanitizer_mutex.h" +#include "sanitizer_placement_new.h" +#include "sanitizer_stacktrace.h" namespace __sanitizer { @@ -346,6 +347,33 @@ void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size, *tls_size = 0; } +void GetStackTrace(StackTrace *stack, uptr max_s, uptr pc, uptr bp, + uptr stack_top, uptr stack_bottom, bool fast) { + (void)fast; + (void)stack_top; + (void)stack_bottom; + stack->max_size = max_s; + void *tmp[kStackTraceMax]; + + // FIXME: CaptureStackBackTrace might be too slow for us. + // FIXME: Compare with StackWalk64. + // FIXME: Look at LLVMUnhandledExceptionFilter in Signals.inc + uptr cs_ret = CaptureStackBackTrace(1, stack->max_size, tmp, 0); + uptr offset = 0; + // Skip the RTL frames by searching for the PC in the stacktrace. + // FIXME: this doesn't work well for the malloc/free stacks yet. + for (uptr i = 0; i < cs_ret; i++) { + if (pc != (uptr)tmp[i]) + continue; + offset = i; + break; + } + + stack->size = cs_ret - offset; + for (uptr i = 0; i < stack->size; i++) + stack->trace[i] = (uptr)tmp[i + offset]; +} + } // namespace __sanitizer #endif // _WIN32