]>
Commit | Line | Data |
---|---|---|
f35db108 WM |
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 | ||
696d846a | 18 | static const u32 kStackTraceMax = 256; |
f35db108 | 19 | |
696d846a | 20 | #if SANITIZER_LINUX && (defined(__sparc__) || defined(__mips__)) |
df77f0e4 KS |
21 | # define SANITIZER_CAN_FAST_UNWIND 0 |
22 | #elif SANITIZER_WINDOWS | |
23 | # define SANITIZER_CAN_FAST_UNWIND 0 | |
eac97531 ML |
24 | #elif SANITIZER_OPENBSD |
25 | # define SANITIZER_CAN_FAST_UNWIND 0 | |
ef1b3fda | 26 | #else |
df77f0e4 | 27 | # define SANITIZER_CAN_FAST_UNWIND 1 |
ef1b3fda KS |
28 | #endif |
29 | ||
c5be964a KS |
30 | // Fast unwind is the only option on Mac for now; we will need to |
31 | // revisit this macro when slow unwind works on Mac, see | |
10189819 | 32 | // https://github.com/google/sanitizers/issues/137 |
eac97531 | 33 | #if SANITIZER_MAC || SANITIZER_OPENBSD || SANITIZER_RTEMS |
c5be964a KS |
34 | # define SANITIZER_CAN_SLOW_UNWIND 0 |
35 | #else | |
36 | # define SANITIZER_CAN_SLOW_UNWIND 1 | |
37 | #endif | |
38 | ||
f35db108 | 39 | struct StackTrace { |
c5be964a | 40 | const uptr *trace; |
696d846a MO |
41 | u32 size; |
42 | u32 tag; | |
df77f0e4 | 43 | |
696d846a MO |
44 | static const int TAG_UNKNOWN = 0; |
45 | static const int TAG_ALLOC = 1; | |
46 | static const int TAG_DEALLOC = 2; | |
47 | static const int TAG_CUSTOM = 100; // Tool specific tags start here. | |
48 | ||
49 | StackTrace() : trace(nullptr), size(0), tag(0) {} | |
50 | StackTrace(const uptr *trace, u32 size) : trace(trace), size(size), tag(0) {} | |
51 | StackTrace(const uptr *trace, u32 size, u32 tag) | |
52 | : trace(trace), size(size), tag(tag) {} | |
f35db108 | 53 | |
c5be964a KS |
54 | // Prints a symbolized stacktrace, followed by an empty line. |
55 | void Print() const; | |
f35db108 | 56 | |
df77f0e4 | 57 | static bool WillUseFastUnwind(bool request_fast_unwind) { |
df77f0e4 KS |
58 | if (!SANITIZER_CAN_FAST_UNWIND) |
59 | return false; | |
c5be964a | 60 | else if (!SANITIZER_CAN_SLOW_UNWIND) |
df77f0e4 KS |
61 | return true; |
62 | return request_fast_unwind; | |
63 | } | |
f35db108 WM |
64 | |
65 | static uptr GetCurrentPc(); | |
696d846a MO |
66 | static inline uptr GetPreviousInstructionPc(uptr pc); |
67 | static uptr GetNextInstructionPc(uptr pc); | |
c5be964a KS |
68 | typedef bool (*SymbolizeCallback)(const void *pc, char *out_buffer, |
69 | int out_size); | |
70 | }; | |
71 | ||
696d846a MO |
72 | // Performance-critical, must be in the header. |
73 | ALWAYS_INLINE | |
74 | uptr StackTrace::GetPreviousInstructionPc(uptr pc) { | |
75 | #if defined(__arm__) | |
eac97531 ML |
76 | // T32 (Thumb) branch instructions might be 16 or 32 bit long, |
77 | // so we return (pc-2) in that case in order to be safe. | |
78 | // For A32 mode we return (pc-4) because all instructions are 32 bit long. | |
79 | return (pc - 3) & (~1); | |
80 | #elif defined(__powerpc__) || defined(__powerpc64__) || defined(__aarch64__) | |
696d846a MO |
81 | // PCs are always 4 byte aligned. |
82 | return pc - 4; | |
83 | #elif defined(__sparc__) || defined(__mips__) | |
84 | return pc - 8; | |
85 | #else | |
86 | return pc - 1; | |
87 | #endif | |
88 | } | |
89 | ||
c5be964a KS |
90 | // StackTrace that owns the buffer used to store the addresses. |
91 | struct BufferedStackTrace : public StackTrace { | |
92 | uptr trace_buffer[kStackTraceMax]; | |
93 | uptr top_frame_bp; // Optional bp of a top frame. | |
94 | ||
95 | BufferedStackTrace() : StackTrace(trace_buffer, 0), top_frame_bp(0) {} | |
96 | ||
97 | void Init(const uptr *pcs, uptr cnt, uptr extra_top_pc = 0); | |
696d846a | 98 | void Unwind(u32 max_depth, uptr pc, uptr bp, void *context, uptr stack_top, |
c5be964a | 99 | uptr stack_bottom, bool request_fast_unwind); |
f35db108 | 100 | |
5d3805fc JJ |
101 | void Reset() { |
102 | *static_cast<StackTrace *>(this) = StackTrace(trace_buffer, 0); | |
103 | top_frame_bp = 0; | |
104 | } | |
105 | ||
df77f0e4 KS |
106 | private: |
107 | void FastUnwindStack(uptr pc, uptr bp, uptr stack_top, uptr stack_bottom, | |
696d846a MO |
108 | u32 max_depth); |
109 | void SlowUnwindStack(uptr pc, u32 max_depth); | |
dee5ea7a | 110 | void SlowUnwindStackWithContext(uptr pc, void *context, |
696d846a | 111 | u32 max_depth); |
df77f0e4 KS |
112 | void PopStackFrames(uptr count); |
113 | uptr LocatePcInTrace(uptr pc); | |
c5be964a | 114 | |
5d3805fc JJ |
115 | BufferedStackTrace(const BufferedStackTrace &) = delete; |
116 | void operator=(const BufferedStackTrace &) = delete; | |
f35db108 WM |
117 | }; |
118 | ||
10189819 MO |
119 | // Check if given pointer points into allocated stack area. |
120 | static inline bool IsValidFrame(uptr frame, uptr stack_top, uptr stack_bottom) { | |
121 | return frame > stack_bottom && frame < stack_top - 2 * sizeof (uhwptr); | |
122 | } | |
123 | ||
f35db108 WM |
124 | } // namespace __sanitizer |
125 | ||
126 | // Use this macro if you want to print stack trace with the caller | |
127 | // of the current function in the top frame. | |
128 | #define GET_CALLER_PC_BP_SP \ | |
129 | uptr bp = GET_CURRENT_FRAME(); \ | |
130 | uptr pc = GET_CALLER_PC(); \ | |
131 | uptr local_stack; \ | |
132 | uptr sp = (uptr)&local_stack | |
133 | ||
866e32ad KS |
134 | #define GET_CALLER_PC_BP \ |
135 | uptr bp = GET_CURRENT_FRAME(); \ | |
136 | uptr pc = GET_CALLER_PC(); | |
137 | ||
f35db108 WM |
138 | // Use this macro if you want to print stack trace with the current |
139 | // function in the top frame. | |
140 | #define GET_CURRENT_PC_BP_SP \ | |
141 | uptr bp = GET_CURRENT_FRAME(); \ | |
142 | uptr pc = StackTrace::GetCurrentPc(); \ | |
143 | uptr local_stack; \ | |
144 | uptr sp = (uptr)&local_stack | |
145 | ||
146 | ||
147 | #endif // SANITIZER_STACKTRACE_H |