1*68d75effSDimitry Andric //===-- sanitizer_stacktrace.cpp ------------------------------------------===// 2*68d75effSDimitry Andric // 3*68d75effSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*68d75effSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*68d75effSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*68d75effSDimitry Andric // 7*68d75effSDimitry Andric //===----------------------------------------------------------------------===// 8*68d75effSDimitry Andric // 9*68d75effSDimitry Andric // This file is shared between AddressSanitizer and ThreadSanitizer 10*68d75effSDimitry Andric // run-time libraries. 11*68d75effSDimitry Andric //===----------------------------------------------------------------------===// 12*68d75effSDimitry Andric 13*68d75effSDimitry Andric #include "sanitizer_common.h" 14*68d75effSDimitry Andric #include "sanitizer_flags.h" 15*68d75effSDimitry Andric #include "sanitizer_stacktrace.h" 16*68d75effSDimitry Andric 17*68d75effSDimitry Andric namespace __sanitizer { 18*68d75effSDimitry Andric 19*68d75effSDimitry Andric uptr StackTrace::GetNextInstructionPc(uptr pc) { 20*68d75effSDimitry Andric #if defined(__sparc__) || defined(__mips__) 21*68d75effSDimitry Andric return pc + 8; 22*68d75effSDimitry Andric #elif defined(__powerpc__) || defined(__arm__) || defined(__aarch64__) 23*68d75effSDimitry Andric return pc + 4; 24*68d75effSDimitry Andric #else 25*68d75effSDimitry Andric return pc + 1; 26*68d75effSDimitry Andric #endif 27*68d75effSDimitry Andric } 28*68d75effSDimitry Andric 29*68d75effSDimitry Andric uptr StackTrace::GetCurrentPc() { 30*68d75effSDimitry Andric return GET_CALLER_PC(); 31*68d75effSDimitry Andric } 32*68d75effSDimitry Andric 33*68d75effSDimitry Andric void BufferedStackTrace::Init(const uptr *pcs, uptr cnt, uptr extra_top_pc) { 34*68d75effSDimitry Andric size = cnt + !!extra_top_pc; 35*68d75effSDimitry Andric CHECK_LE(size, kStackTraceMax); 36*68d75effSDimitry Andric internal_memcpy(trace_buffer, pcs, cnt * sizeof(trace_buffer[0])); 37*68d75effSDimitry Andric if (extra_top_pc) 38*68d75effSDimitry Andric trace_buffer[cnt] = extra_top_pc; 39*68d75effSDimitry Andric top_frame_bp = 0; 40*68d75effSDimitry Andric } 41*68d75effSDimitry Andric 42*68d75effSDimitry Andric // Sparc implemention is in its own file. 43*68d75effSDimitry Andric #if !defined(__sparc__) 44*68d75effSDimitry Andric 45*68d75effSDimitry Andric // In GCC on ARM bp points to saved lr, not fp, so we should check the next 46*68d75effSDimitry Andric // cell in stack to be a saved frame pointer. GetCanonicFrame returns the 47*68d75effSDimitry Andric // pointer to saved frame pointer in any case. 48*68d75effSDimitry Andric static inline uhwptr *GetCanonicFrame(uptr bp, 49*68d75effSDimitry Andric uptr stack_top, 50*68d75effSDimitry Andric uptr stack_bottom) { 51*68d75effSDimitry Andric CHECK_GT(stack_top, stack_bottom); 52*68d75effSDimitry Andric #ifdef __arm__ 53*68d75effSDimitry Andric if (!IsValidFrame(bp, stack_top, stack_bottom)) return 0; 54*68d75effSDimitry Andric uhwptr *bp_prev = (uhwptr *)bp; 55*68d75effSDimitry Andric if (IsValidFrame((uptr)bp_prev[0], stack_top, stack_bottom)) return bp_prev; 56*68d75effSDimitry Andric // The next frame pointer does not look right. This could be a GCC frame, step 57*68d75effSDimitry Andric // back by 1 word and try again. 58*68d75effSDimitry Andric if (IsValidFrame((uptr)bp_prev[-1], stack_top, stack_bottom)) 59*68d75effSDimitry Andric return bp_prev - 1; 60*68d75effSDimitry Andric // Nope, this does not look right either. This means the frame after next does 61*68d75effSDimitry Andric // not have a valid frame pointer, but we can still extract the caller PC. 62*68d75effSDimitry Andric // Unfortunately, there is no way to decide between GCC and LLVM frame 63*68d75effSDimitry Andric // layouts. Assume LLVM. 64*68d75effSDimitry Andric return bp_prev; 65*68d75effSDimitry Andric #else 66*68d75effSDimitry Andric return (uhwptr*)bp; 67*68d75effSDimitry Andric #endif 68*68d75effSDimitry Andric } 69*68d75effSDimitry Andric 70*68d75effSDimitry Andric void BufferedStackTrace::UnwindFast(uptr pc, uptr bp, uptr stack_top, 71*68d75effSDimitry Andric uptr stack_bottom, u32 max_depth) { 72*68d75effSDimitry Andric // TODO(yln): add arg sanity check for stack_top/stack_bottom 73*68d75effSDimitry Andric CHECK_GE(max_depth, 2); 74*68d75effSDimitry Andric const uptr kPageSize = GetPageSizeCached(); 75*68d75effSDimitry Andric trace_buffer[0] = pc; 76*68d75effSDimitry Andric size = 1; 77*68d75effSDimitry Andric if (stack_top < 4096) return; // Sanity check for stack top. 78*68d75effSDimitry Andric uhwptr *frame = GetCanonicFrame(bp, stack_top, stack_bottom); 79*68d75effSDimitry Andric // Lowest possible address that makes sense as the next frame pointer. 80*68d75effSDimitry Andric // Goes up as we walk the stack. 81*68d75effSDimitry Andric uptr bottom = stack_bottom; 82*68d75effSDimitry Andric // Avoid infinite loop when frame == frame[0] by using frame > prev_frame. 83*68d75effSDimitry Andric while (IsValidFrame((uptr)frame, stack_top, bottom) && 84*68d75effSDimitry Andric IsAligned((uptr)frame, sizeof(*frame)) && 85*68d75effSDimitry Andric size < max_depth) { 86*68d75effSDimitry Andric #ifdef __powerpc__ 87*68d75effSDimitry Andric // PowerPC ABIs specify that the return address is saved at offset 88*68d75effSDimitry Andric // 16 of the *caller's* stack frame. Thus we must dereference the 89*68d75effSDimitry Andric // back chain to find the caller frame before extracting it. 90*68d75effSDimitry Andric uhwptr *caller_frame = (uhwptr*)frame[0]; 91*68d75effSDimitry Andric if (!IsValidFrame((uptr)caller_frame, stack_top, bottom) || 92*68d75effSDimitry Andric !IsAligned((uptr)caller_frame, sizeof(uhwptr))) 93*68d75effSDimitry Andric break; 94*68d75effSDimitry Andric uhwptr pc1 = caller_frame[2]; 95*68d75effSDimitry Andric #elif defined(__s390__) 96*68d75effSDimitry Andric uhwptr pc1 = frame[14]; 97*68d75effSDimitry Andric #else 98*68d75effSDimitry Andric uhwptr pc1 = frame[1]; 99*68d75effSDimitry Andric #endif 100*68d75effSDimitry Andric // Let's assume that any pointer in the 0th page (i.e. <0x1000 on i386 and 101*68d75effSDimitry Andric // x86_64) is invalid and stop unwinding here. If we're adding support for 102*68d75effSDimitry Andric // a platform where this isn't true, we need to reconsider this check. 103*68d75effSDimitry Andric if (pc1 < kPageSize) 104*68d75effSDimitry Andric break; 105*68d75effSDimitry Andric if (pc1 != pc) { 106*68d75effSDimitry Andric trace_buffer[size++] = (uptr) pc1; 107*68d75effSDimitry Andric } 108*68d75effSDimitry Andric bottom = (uptr)frame; 109*68d75effSDimitry Andric frame = GetCanonicFrame((uptr)frame[0], stack_top, bottom); 110*68d75effSDimitry Andric } 111*68d75effSDimitry Andric } 112*68d75effSDimitry Andric 113*68d75effSDimitry Andric #endif // !defined(__sparc__) 114*68d75effSDimitry Andric 115*68d75effSDimitry Andric void BufferedStackTrace::PopStackFrames(uptr count) { 116*68d75effSDimitry Andric CHECK_LT(count, size); 117*68d75effSDimitry Andric size -= count; 118*68d75effSDimitry Andric for (uptr i = 0; i < size; ++i) { 119*68d75effSDimitry Andric trace_buffer[i] = trace_buffer[i + count]; 120*68d75effSDimitry Andric } 121*68d75effSDimitry Andric } 122*68d75effSDimitry Andric 123*68d75effSDimitry Andric static uptr Distance(uptr a, uptr b) { return a < b ? b - a : a - b; } 124*68d75effSDimitry Andric 125*68d75effSDimitry Andric uptr BufferedStackTrace::LocatePcInTrace(uptr pc) { 126*68d75effSDimitry Andric uptr best = 0; 127*68d75effSDimitry Andric for (uptr i = 1; i < size; ++i) { 128*68d75effSDimitry Andric if (Distance(trace[i], pc) < Distance(trace[best], pc)) best = i; 129*68d75effSDimitry Andric } 130*68d75effSDimitry Andric return best; 131*68d75effSDimitry Andric } 132*68d75effSDimitry Andric 133*68d75effSDimitry Andric } // namespace __sanitizer 134