1 //===-- sanitizer_stacktrace.h ----------------------------------*- C++ -*-===// 2 // 3 // This file is distributed under the University of Illinois Open Source 4 // License. See LICENSE.TXT for details. 5 // 6 //===----------------------------------------------------------------------===// 7 // 8 // This file is shared between AddressSanitizer and ThreadSanitizer 9 // run-time libraries. 10 //===----------------------------------------------------------------------===// 11 #ifndef SANITIZER_STACKTRACE_H 12 #define SANITIZER_STACKTRACE_H 13 14 #include "sanitizer_internal_defs.h" 15 16 namespace __sanitizer { 17 18 static const u32 kStackTraceMax = 256; 19 20 #if SANITIZER_LINUX && (defined(__sparc__) || defined(__mips__)) 21 # define SANITIZER_CAN_FAST_UNWIND 0 22 #elif SANITIZER_WINDOWS 23 # define SANITIZER_CAN_FAST_UNWIND 0 24 #else 25 # define SANITIZER_CAN_FAST_UNWIND 1 26 #endif 27 28 // Fast unwind is the only option on Mac for now; we will need to 29 // revisit this macro when slow unwind works on Mac, see 30 // https://code.google.com/p/address-sanitizer/issues/detail?id=137 31 #if SANITIZER_MAC 32 # define SANITIZER_CAN_SLOW_UNWIND 0 33 #else 34 # define SANITIZER_CAN_SLOW_UNWIND 1 35 #endif 36 37 struct StackTrace { 38 const uptr *trace; 39 u32 size; 40 u32 tag; 41 42 static const int TAG_UNKNOWN = 0; 43 static const int TAG_ALLOC = 1; 44 static const int TAG_DEALLOC = 2; 45 static const int TAG_CUSTOM = 100; // Tool specific tags start here. 46 47 StackTrace() : trace(nullptr), size(0), tag(0) {} 48 StackTrace(const uptr *trace, u32 size) : trace(trace), size(size), tag(0) {} 49 StackTrace(const uptr *trace, u32 size, u32 tag) 50 : trace(trace), size(size), tag(tag) {} 51 52 // Prints a symbolized stacktrace, followed by an empty line. 53 void Print() const; 54 55 static bool WillUseFastUnwind(bool request_fast_unwind) { 56 if (!SANITIZER_CAN_FAST_UNWIND) 57 return false; 58 else if (!SANITIZER_CAN_SLOW_UNWIND) 59 return true; 60 return request_fast_unwind; 61 } 62 63 static uptr GetCurrentPc(); 64 static inline uptr GetPreviousInstructionPc(uptr pc); 65 static uptr GetNextInstructionPc(uptr pc); 66 typedef bool (*SymbolizeCallback)(const void *pc, char *out_buffer, 67 int out_size); 68 }; 69 70 // Performance-critical, must be in the header. 71 ALWAYS_INLINE 72 uptr StackTrace::GetPreviousInstructionPc(uptr pc) { 73 #if defined(__arm__) 74 // Cancel Thumb bit. 75 pc = pc & (~1); 76 #endif 77 #if defined(__powerpc__) || defined(__powerpc64__) 78 // PCs are always 4 byte aligned. 79 return pc - 4; 80 #elif defined(__sparc__) || defined(__mips__) 81 return pc - 8; 82 #else 83 return pc - 1; 84 #endif 85 } 86 87 // StackTrace that owns the buffer used to store the addresses. 88 struct BufferedStackTrace : public StackTrace { 89 uptr trace_buffer[kStackTraceMax]; 90 uptr top_frame_bp; // Optional bp of a top frame. 91 92 BufferedStackTrace() : StackTrace(trace_buffer, 0), top_frame_bp(0) {} 93 94 void Init(const uptr *pcs, uptr cnt, uptr extra_top_pc = 0); 95 void Unwind(u32 max_depth, uptr pc, uptr bp, void *context, uptr stack_top, 96 uptr stack_bottom, bool request_fast_unwind); 97 98 private: 99 void FastUnwindStack(uptr pc, uptr bp, uptr stack_top, uptr stack_bottom, 100 u32 max_depth); 101 void SlowUnwindStack(uptr pc, u32 max_depth); 102 void SlowUnwindStackWithContext(uptr pc, void *context, 103 u32 max_depth); 104 void PopStackFrames(uptr count); 105 uptr LocatePcInTrace(uptr pc); 106 107 BufferedStackTrace(const BufferedStackTrace &); 108 void operator=(const BufferedStackTrace &); 109 }; 110 111 } // namespace __sanitizer 112 113 // Use this macro if you want to print stack trace with the caller 114 // of the current function in the top frame. 115 #define GET_CALLER_PC_BP_SP \ 116 uptr bp = GET_CURRENT_FRAME(); \ 117 uptr pc = GET_CALLER_PC(); \ 118 uptr local_stack; \ 119 uptr sp = (uptr)&local_stack 120 121 #define GET_CALLER_PC_BP \ 122 uptr bp = GET_CURRENT_FRAME(); \ 123 uptr pc = GET_CALLER_PC(); 124 125 // Use this macro if you want to print stack trace with the current 126 // function in the top frame. 127 #define GET_CURRENT_PC_BP_SP \ 128 uptr bp = GET_CURRENT_FRAME(); \ 129 uptr pc = StackTrace::GetCurrentPc(); \ 130 uptr local_stack; \ 131 uptr sp = (uptr)&local_stack 132 133 134 #endif // SANITIZER_STACKTRACE_H 135