sanitizer_stacktrace.cc revision 2d1fdb26e458c4ddc04155c1d421bced3ba90cd0
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//===-- sanitizer_stacktrace.cc -------------------------------------------===// 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The LLVM Compiler Infrastructure 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This file is distributed under the University of Illinois Open Source 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// License. See LICENSE.TXT for details. 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//===----------------------------------------------------------------------===// 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This file is shared between AddressSanitizer and ThreadSanitizer 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// run-time libraries. 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//===----------------------------------------------------------------------===// 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sanitizer_common.h" 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sanitizer_flags.h" 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sanitizer_stacktrace.h" 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace __sanitizer { 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)uptr StackTrace::GetPreviousInstructionPc(uptr pc) { 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifdef __arm__ 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Cancel Thumb bit. 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pc = pc & (~1); 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(__sparc__) 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return pc - 8; 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return pc - 1; 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)uptr StackTrace::GetCurrentPc() { 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return GET_CALLER_PC(); 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void StackTrace::FastUnwindStack(uptr pc, uptr bp, 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uptr stack_top, uptr stack_bottom, 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uptr max_depth) { 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHECK_GE(max_depth, 2); 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) trace[0] = pc; 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size = 1; 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uhwptr *frame = (uhwptr *)bp; 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uhwptr *prev_frame = frame - 1; 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (stack_top < 4096) return; // Sanity check for stack top. 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Avoid infinite loop when frame == frame[0] by using frame > prev_frame. 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (frame > prev_frame && 476e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) frame < (uhwptr *)stack_top - 2 && 486e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) frame > (uhwptr *)stack_bottom && 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IsAligned((uptr)frame, sizeof(*frame)) && 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size < max_depth) { 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uhwptr pc1 = frame[1]; 52 if (pc1 != pc) { 53 trace[size++] = (uptr) pc1; 54 } 55 prev_frame = frame; 56 frame = (uhwptr *)frame[0]; 57 } 58} 59 60static bool MatchPc(uptr cur_pc, uptr trace_pc, uptr threshold) { 61 return cur_pc - trace_pc <= threshold || trace_pc - cur_pc <= threshold; 62} 63 64void StackTrace::PopStackFrames(uptr count) { 65 CHECK_LT(count, size); 66 size -= count; 67 for (uptr i = 0; i < size; ++i) { 68 trace[i] = trace[i + count]; 69 } 70} 71 72uptr StackTrace::LocatePcInTrace(uptr pc) { 73 // Use threshold to find PC in stack trace, as PC we want to unwind from may 74 // slightly differ from return address in the actual unwinded stack trace. 75 const int kPcThreshold = 288; 76 for (uptr i = 0; i < size; ++i) { 77 if (MatchPc(pc, trace[i], kPcThreshold)) 78 return i; 79 } 80 return 0; 81} 82 83} // namespace __sanitizer 84