Index: /home/seurer/llvm/llvm-test/projects/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace.h =================================================================== --- /home/seurer/llvm/llvm-test/projects/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace.h +++ /home/seurer/llvm/llvm-test/projects/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace.h @@ -19,8 +19,7 @@ static const u32 kStackTraceMax = 256; -#if SANITIZER_LINUX && (defined(__aarch64__) || defined(__powerpc__) || \ - defined(__powerpc64__) || defined(__sparc__) || \ +#if SANITIZER_LINUX && (defined(__aarch64__) || defined(__sparc__) || \ defined(__mips__)) # define SANITIZER_CAN_FAST_UNWIND 0 #elif SANITIZER_WINDOWS @@ -48,6 +47,18 @@ static const int TAG_DEALLOC = 2; static const int TAG_CUSTOM = 100; // Tool specific tags start here. +#if defined(__powerpc__) || defined(__powerpc64__) + static const int OFFSET_TO_PC_IN_FRAME = 2; + // The stack will include functions called after the function that + // triggered the stack unwinding. To match what slow unwinding does + // set FAST_UNWIND_SHOULD_POP_FRAMES_TO_PC to true to pop those "extra" + // frames. + static const bool FAST_UNWIND_SHOULD_POP_FRAMES_TO_PC = true; +#else + static const int OFFSET_TO_PC_IN_FRAME = 1; + static const bool FAST_UNWIND_SHOULD_POP_FRAMES_TO_PC = false; +#endif + StackTrace() : trace(nullptr), size(0), tag(0) {} StackTrace(const uptr *trace, u32 size) : trace(trace), size(size), tag(0) {} StackTrace(const uptr *trace, u32 size, u32 tag) @@ -105,7 +116,7 @@ void SlowUnwindStack(uptr pc, u32 max_depth); void SlowUnwindStackWithContext(uptr pc, void *context, u32 max_depth); - void PopStackFrames(uptr count); + void PopStackFramesToPc(uptr pc); uptr LocatePcInTrace(uptr pc); BufferedStackTrace(const BufferedStackTrace &); Index: /home/seurer/llvm/llvm-test/projects/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace.cc =================================================================== --- /home/seurer/llvm/llvm-test/projects/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace.cc +++ /home/seurer/llvm/llvm-test/projects/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace.cc @@ -81,25 +81,40 @@ while (IsValidFrame((uptr)frame, stack_top, bottom) && IsAligned((uptr)frame, sizeof(*frame)) && size < max_depth) { - uhwptr pc1 = frame[1]; + uhwptr pc1 = frame[OFFSET_TO_PC_IN_FRAME]; if (pc1 != pc) { trace_buffer[size++] = (uptr) pc1; } bottom = (uptr)frame; frame = GetCanonicFrame((uptr)frame[0], stack_top, bottom); } + + if (FAST_UNWIND_SHOULD_POP_FRAMES_TO_PC) { + PopStackFramesToPc(pc); + } } static bool MatchPc(uptr cur_pc, uptr trace_pc, uptr threshold) { return cur_pc - trace_pc <= threshold || trace_pc - cur_pc <= threshold; } -void BufferedStackTrace::PopStackFrames(uptr count) { - CHECK_LT(count, size); - size -= count; +void BufferedStackTrace::PopStackFramesToPc(uptr pc) { + uptr to_pop = LocatePcInTrace(pc); + // trace_buffer[0] belongs to the current function so we always pop it, + // unless there is only 1 frame in the stack trace (1 frame is always better + // than 0!). + // 1-frame stacks don't normally happen, but this depends on the actual + // unwinder implementation (libgcc, libunwind, etc) which is outside of our + // control. + if (to_pop == 0 && size > 1) + to_pop = 1; + + CHECK_LT(to_pop, size); + size -= to_pop; for (uptr i = 0; i < size; ++i) { - trace_buffer[i] = trace_buffer[i + count]; + trace_buffer[i] = trace_buffer[i + to_pop]; } + trace_buffer[0] = pc; } uptr BufferedStackTrace::LocatePcInTrace(uptr pc) { Index: /home/seurer/llvm/llvm-test/projects/compiler-rt/lib/sanitizer_common/sanitizer_unwind_posix_libcdep.cc =================================================================== --- /home/seurer/llvm/llvm-test/projects/compiler-rt/lib/sanitizer_common/sanitizer_unwind_posix_libcdep.cc +++ /home/seurer/llvm/llvm-test/projects/compiler-rt/lib/sanitizer_common/sanitizer_unwind_posix_libcdep.cc @@ -113,18 +113,9 @@ size = 0; UnwindTraceArg arg = {this, Min(max_depth + 1, kStackTraceMax)}; _Unwind_Backtrace(Unwind_Trace, &arg); + // We need to pop a few frames so that pc is on top. - uptr to_pop = LocatePcInTrace(pc); - // trace_buffer[0] belongs to the current function so we always pop it, - // unless there is only 1 frame in the stack trace (1 frame is always better - // than 0!). - // 1-frame stacks don't normally happen, but this depends on the actual - // unwinder implementation (libgcc, libunwind, etc) which is outside of our - // control. - if (to_pop == 0 && size > 1) - to_pop = 1; - PopStackFrames(to_pop); - trace_buffer[0] = pc; + PopStackFramesToPc(pc); } void BufferedStackTrace::SlowUnwindStackWithContext(uptr pc, void *context,