diff options
Diffstat (limited to 'compiler-rt/lib/gwp_asan/optional/backtrace_sanitizer_common.cpp')
| -rw-r--r-- | compiler-rt/lib/gwp_asan/optional/backtrace_sanitizer_common.cpp | 49 |
1 files changed, 34 insertions, 15 deletions
diff --git a/compiler-rt/lib/gwp_asan/optional/backtrace_sanitizer_common.cpp b/compiler-rt/lib/gwp_asan/optional/backtrace_sanitizer_common.cpp index 3ac4b52bfc27..e6cce86e3b7b 100644 --- a/compiler-rt/lib/gwp_asan/optional/backtrace_sanitizer_common.cpp +++ b/compiler-rt/lib/gwp_asan/optional/backtrace_sanitizer_common.cpp @@ -22,30 +22,47 @@ void __sanitizer::BufferedStackTrace::UnwindImpl(uptr pc, uptr bp, void *context, bool request_fast, u32 max_depth) { - if (!StackTrace::WillUseFastUnwind(request_fast)) { - return Unwind(max_depth, pc, bp, context, 0, 0, request_fast); - } - Unwind(max_depth, pc, 0, context, 0, 0, false); + if (!StackTrace::WillUseFastUnwind(request_fast)) + return Unwind(max_depth, pc, 0, context, 0, 0, false); + + uptr top = 0; + uptr bottom = 0; + GetThreadStackTopAndBottom(/*at_initialization*/ false, &top, &bottom); + + return Unwind(max_depth, pc, bp, context, top, bottom, request_fast); } namespace { -size_t Backtrace(uintptr_t *TraceBuffer, size_t Size) { +size_t BacktraceCommon(uintptr_t *TraceBuffer, size_t Size, void *Context) { + // Use the slow sanitizer unwinder in the segv handler. Fast frame pointer + // unwinders can end up dropping frames because the kernel sigreturn() frame's + // return address is the return address at time of fault. This has the result + // of never actually capturing the PC where the signal was raised. + bool UseFastUnwind = (Context == nullptr); + __sanitizer::BufferedStackTrace Trace; Trace.Reset(); if (Size > __sanitizer::kStackTraceMax) Size = __sanitizer::kStackTraceMax; Trace.Unwind((__sanitizer::uptr)__builtin_return_address(0), - (__sanitizer::uptr)__builtin_frame_address(0), - /* ucontext */ nullptr, - /* fast unwind */ true, Size - 1); + (__sanitizer::uptr)__builtin_frame_address(0), Context, + UseFastUnwind, Size - 1); memcpy(TraceBuffer, Trace.trace, Trace.size * sizeof(uintptr_t)); return Trace.size; } +size_t Backtrace(uintptr_t *TraceBuffer, size_t Size) { + return BacktraceCommon(TraceBuffer, Size, nullptr); +} + +size_t SegvBacktrace(uintptr_t *TraceBuffer, size_t Size, void *Context) { + return BacktraceCommon(TraceBuffer, Size, Context); +} + static void PrintBacktrace(uintptr_t *Trace, size_t TraceLength, - gwp_asan::crash_handler::Printf_t Printf) { + gwp_asan::Printf_t Printf) { __sanitizer::StackTrace StackTrace; StackTrace.trace = reinterpret_cast<__sanitizer::uptr *>(Trace); StackTrace.size = TraceLength; @@ -60,21 +77,23 @@ static void PrintBacktrace(uintptr_t *Trace, size_t TraceLength, } // anonymous namespace namespace gwp_asan { -namespace options { +namespace backtrace { + // This function is thread-compatible. It must be synchronised in respect to any // other calls to getBacktraceFunction(), calls to getPrintBacktraceFunction(), // and calls to either of the functions that they return. Furthermore, this may // require synchronisation with any calls to sanitizer_common that use flags. // Generally, this function will be called during the initialisation of the // allocator, which is done in a thread-compatible manner. -Backtrace_t getBacktraceFunction() { +options::Backtrace_t getBacktraceFunction() { // The unwinder requires the default flags to be set. __sanitizer::SetCommonFlagsDefaults(); __sanitizer::InitializeCommonFlags(); return Backtrace; } -crash_handler::PrintBacktrace_t getPrintBacktraceFunction() { - return PrintBacktrace; -} -} // namespace options + +PrintBacktrace_t getPrintBacktraceFunction() { return PrintBacktrace; } +SegvBacktrace_t getSegvBacktraceFunction() { return SegvBacktrace; } + +} // namespace backtrace } // namespace gwp_asan |
