1245614Sandrew//===-- sanitizer_stacktrace.h ----------------------------------*- C++ -*-===// 2245614Sandrew// 3245614Sandrew// The LLVM Compiler Infrastructure 4245614Sandrew// 5245614Sandrew// This file is distributed under the University of Illinois Open Source 6245614Sandrew// License. See LICENSE.TXT for details. 7245614Sandrew// 8245614Sandrew//===----------------------------------------------------------------------===// 9245614Sandrew// 10245614Sandrew// This file is shared between AddressSanitizer and ThreadSanitizer 11245614Sandrew// run-time libraries. 12245614Sandrew//===----------------------------------------------------------------------===// 13245614Sandrew#ifndef SANITIZER_STACKTRACE_H 14245614Sandrew#define SANITIZER_STACKTRACE_H 15245614Sandrew 16245614Sandrew#include "sanitizer_internal_defs.h" 17245614Sandrew 18245614Sandrewnamespace __sanitizer { 19245614Sandrew 20280031Sdimstatic const u32 kStackTraceMax = 256; 21245614Sandrew 22296417Sdim#if SANITIZER_LINUX && (defined(__sparc__) || defined(__mips__)) 23274201Sdim# define SANITIZER_CAN_FAST_UNWIND 0 24274201Sdim#elif SANITIZER_WINDOWS 25274201Sdim# define SANITIZER_CAN_FAST_UNWIND 0 26251034Sed#else 27274201Sdim# define SANITIZER_CAN_FAST_UNWIND 1 28251034Sed#endif 29251034Sed 30276789Sdim// Fast unwind is the only option on Mac for now; we will need to 31276789Sdim// revisit this macro when slow unwind works on Mac, see 32296417Sdim// https://github.com/google/sanitizers/issues/137 33276789Sdim#if SANITIZER_MAC 34276789Sdim# define SANITIZER_CAN_SLOW_UNWIND 0 35276789Sdim#else 36276789Sdim# define SANITIZER_CAN_SLOW_UNWIND 1 37276789Sdim#endif 38276789Sdim 39245614Sandrewstruct StackTrace { 40276789Sdim const uptr *trace; 41280031Sdim u32 size; 42280031Sdim u32 tag; 43274201Sdim 44280031Sdim static const int TAG_UNKNOWN = 0; 45280031Sdim static const int TAG_ALLOC = 1; 46280031Sdim static const int TAG_DEALLOC = 2; 47280031Sdim static const int TAG_CUSTOM = 100; // Tool specific tags start here. 48276789Sdim 49280031Sdim StackTrace() : trace(nullptr), size(0), tag(0) {} 50280031Sdim StackTrace(const uptr *trace, u32 size) : trace(trace), size(size), tag(0) {} 51280031Sdim StackTrace(const uptr *trace, u32 size, u32 tag) 52280031Sdim : trace(trace), size(size), tag(tag) {} 53280031Sdim 54274201Sdim // Prints a symbolized stacktrace, followed by an empty line. 55276789Sdim void Print() const; 56245614Sandrew 57274201Sdim static bool WillUseFastUnwind(bool request_fast_unwind) { 58274201Sdim if (!SANITIZER_CAN_FAST_UNWIND) 59274201Sdim return false; 60276789Sdim else if (!SANITIZER_CAN_SLOW_UNWIND) 61274201Sdim return true; 62274201Sdim return request_fast_unwind; 63274201Sdim } 64245614Sandrew 65245614Sandrew static uptr GetCurrentPc(); 66280031Sdim static inline uptr GetPreviousInstructionPc(uptr pc); 67276789Sdim static uptr GetNextInstructionPc(uptr pc); 68276789Sdim typedef bool (*SymbolizeCallback)(const void *pc, char *out_buffer, 69276789Sdim int out_size); 70276789Sdim}; 71245614Sandrew 72280031Sdim// Performance-critical, must be in the header. 73280031SdimALWAYS_INLINE 74280031Sdimuptr StackTrace::GetPreviousInstructionPc(uptr pc) { 75280031Sdim#if defined(__arm__) 76280031Sdim // Cancel Thumb bit. 77280031Sdim pc = pc & (~1); 78280031Sdim#endif 79280031Sdim#if defined(__powerpc__) || defined(__powerpc64__) 80280031Sdim // PCs are always 4 byte aligned. 81280031Sdim return pc - 4; 82280031Sdim#elif defined(__sparc__) || defined(__mips__) 83280031Sdim return pc - 8; 84280031Sdim#else 85280031Sdim return pc - 1; 86280031Sdim#endif 87280031Sdim} 88280031Sdim 89276789Sdim// StackTrace that owns the buffer used to store the addresses. 90276789Sdimstruct BufferedStackTrace : public StackTrace { 91276789Sdim uptr trace_buffer[kStackTraceMax]; 92276789Sdim uptr top_frame_bp; // Optional bp of a top frame. 93276789Sdim 94276789Sdim BufferedStackTrace() : StackTrace(trace_buffer, 0), top_frame_bp(0) {} 95276789Sdim 96276789Sdim void Init(const uptr *pcs, uptr cnt, uptr extra_top_pc = 0); 97280031Sdim void Unwind(u32 max_depth, uptr pc, uptr bp, void *context, uptr stack_top, 98276789Sdim uptr stack_bottom, bool request_fast_unwind); 99276789Sdim 100274201Sdim private: 101274201Sdim void FastUnwindStack(uptr pc, uptr bp, uptr stack_top, uptr stack_bottom, 102280031Sdim u32 max_depth); 103280031Sdim void SlowUnwindStack(uptr pc, u32 max_depth); 104276789Sdim void SlowUnwindStackWithContext(uptr pc, void *context, 105280031Sdim u32 max_depth); 106274201Sdim void PopStackFrames(uptr count); 107274201Sdim uptr LocatePcInTrace(uptr pc); 108276789Sdim 109276789Sdim BufferedStackTrace(const BufferedStackTrace &); 110276789Sdim void operator=(const BufferedStackTrace &); 111245614Sandrew}; 112245614Sandrew 113245614Sandrew} // namespace __sanitizer 114245614Sandrew 115245614Sandrew// Use this macro if you want to print stack trace with the caller 116245614Sandrew// of the current function in the top frame. 117245614Sandrew#define GET_CALLER_PC_BP_SP \ 118245614Sandrew uptr bp = GET_CURRENT_FRAME(); \ 119245614Sandrew uptr pc = GET_CALLER_PC(); \ 120245614Sandrew uptr local_stack; \ 121245614Sandrew uptr sp = (uptr)&local_stack 122245614Sandrew 123276789Sdim#define GET_CALLER_PC_BP \ 124276789Sdim uptr bp = GET_CURRENT_FRAME(); \ 125276789Sdim uptr pc = GET_CALLER_PC(); 126276789Sdim 127245614Sandrew// Use this macro if you want to print stack trace with the current 128245614Sandrew// function in the top frame. 129245614Sandrew#define GET_CURRENT_PC_BP_SP \ 130245614Sandrew uptr bp = GET_CURRENT_FRAME(); \ 131245614Sandrew uptr pc = StackTrace::GetCurrentPc(); \ 132245614Sandrew uptr local_stack; \ 133245614Sandrew uptr sp = (uptr)&local_stack 134245614Sandrew 135245614Sandrew 136245614Sandrew#endif // SANITIZER_STACKTRACE_H 137