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