blob: 6c3a1511f337c40efe6c3188876d566bebc2af5a [file] [log] [blame]
Kostya Serebryanyc7be4072012-08-28 14:27:06 +00001//===-- sanitizer_stacktrace.h ----------------------------------*- C++ -*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file is shared between AddressSanitizer and ThreadSanitizer
11// run-time libraries.
12//===----------------------------------------------------------------------===//
13#ifndef SANITIZER_STACKTRACE_H
14#define SANITIZER_STACKTRACE_H
15
Kostya Serebryany9ada1f32012-08-28 14:48:28 +000016#include "sanitizer_internal_defs.h"
Kostya Serebryanyc7be4072012-08-28 14:27:06 +000017
18namespace __sanitizer {
19
Stephen Hines86277eb2015-03-23 12:06:32 -070020static const u32 kStackTraceMax = 256;
Kostya Serebryanyc7be4072012-08-28 14:27:06 +000021
Stephen Hines2d1fdb22014-05-28 23:58:16 -070022#if SANITIZER_LINUX && (defined(__aarch64__) || defined(__powerpc__) || \
23 defined(__powerpc64__) || defined(__sparc__) || \
24 defined(__mips__))
Alexey Samsonove74968c2013-11-07 06:33:06 +000025# define SANITIZER_CAN_FAST_UNWIND 0
26#elif SANITIZER_WINDOWS
27# define SANITIZER_CAN_FAST_UNWIND 0
Sergey Matveev736cf492013-05-08 12:45:55 +000028#else
Alexey Samsonove74968c2013-11-07 06:33:06 +000029# define SANITIZER_CAN_FAST_UNWIND 1
Sergey Matveev736cf492013-05-08 12:45:55 +000030#endif
31
Stephen Hines6d186232014-11-26 17:56:19 -080032// Fast unwind is the only option on Mac for now; we will need to
33// revisit this macro when slow unwind works on Mac, see
34// https://code.google.com/p/address-sanitizer/issues/detail?id=137
35#if SANITIZER_MAC
36# define SANITIZER_CAN_SLOW_UNWIND 0
37#else
38# define SANITIZER_CAN_SLOW_UNWIND 1
39#endif
40
Kostya Serebryanyc7be4072012-08-28 14:27:06 +000041struct StackTrace {
Stephen Hines6d186232014-11-26 17:56:19 -080042 const uptr *trace;
Stephen Hines86277eb2015-03-23 12:06:32 -070043 u32 size;
44 u32 tag;
Stephen Hines6d186232014-11-26 17:56:19 -080045
Stephen Hines86277eb2015-03-23 12:06:32 -070046 static const int TAG_UNKNOWN = 0;
47 static const int TAG_ALLOC = 1;
48 static const int TAG_DEALLOC = 2;
49 static const int TAG_CUSTOM = 100; // Tool specific tags start here.
50
51 StackTrace() : trace(nullptr), size(0), tag(0) {}
52 StackTrace(const uptr *trace, u32 size) : trace(trace), size(size), tag(0) {}
53 StackTrace(const uptr *trace, u32 size, u32 tag)
54 : trace(trace), size(size), tag(tag) {}
Alexey Samsonov3e0b8ff2013-10-12 12:40:47 +000055
Alexey Samsonova96c4dc2013-11-01 00:19:46 +000056 // Prints a symbolized stacktrace, followed by an empty line.
Stephen Hines6d186232014-11-26 17:56:19 -080057 void Print() const;
Kostya Serebryanyc7be4072012-08-28 14:27:06 +000058
Alexey Samsonovf16dc422013-11-07 07:28:33 +000059 static bool WillUseFastUnwind(bool request_fast_unwind) {
Alexey Samsonovf16dc422013-11-07 07:28:33 +000060 if (!SANITIZER_CAN_FAST_UNWIND)
61 return false;
Stephen Hines6d186232014-11-26 17:56:19 -080062 else if (!SANITIZER_CAN_SLOW_UNWIND)
Alexey Samsonovf16dc422013-11-07 07:28:33 +000063 return true;
64 return request_fast_unwind;
65 }
Kostya Serebryanyc7be4072012-08-28 14:27:06 +000066
Kostya Serebryanyc7be4072012-08-28 14:27:06 +000067 static uptr GetCurrentPc();
Stephen Hines86277eb2015-03-23 12:06:32 -070068 static inline uptr GetPreviousInstructionPc(uptr pc);
Stephen Hines6d186232014-11-26 17:56:19 -080069 static uptr GetNextInstructionPc(uptr pc);
70 typedef bool (*SymbolizeCallback)(const void *pc, char *out_buffer,
71 int out_size);
72};
73
Stephen Hines86277eb2015-03-23 12:06:32 -070074// Performance-critical, must be in the header.
75ALWAYS_INLINE
76uptr StackTrace::GetPreviousInstructionPc(uptr pc) {
77#if defined(__arm__)
78 // Cancel Thumb bit.
79 pc = pc & (~1);
80#endif
81#if defined(__powerpc__) || defined(__powerpc64__)
82 // PCs are always 4 byte aligned.
83 return pc - 4;
84#elif defined(__sparc__) || defined(__mips__)
85 return pc - 8;
86#else
87 return pc - 1;
88#endif
89}
90
Stephen Hines6d186232014-11-26 17:56:19 -080091// StackTrace that owns the buffer used to store the addresses.
92struct BufferedStackTrace : public StackTrace {
93 uptr trace_buffer[kStackTraceMax];
94 uptr top_frame_bp; // Optional bp of a top frame.
95
96 BufferedStackTrace() : StackTrace(trace_buffer, 0), top_frame_bp(0) {}
97
98 void Init(const uptr *pcs, uptr cnt, uptr extra_top_pc = 0);
Stephen Hines86277eb2015-03-23 12:06:32 -070099 void Unwind(u32 max_depth, uptr pc, uptr bp, void *context, uptr stack_top,
Stephen Hines6d186232014-11-26 17:56:19 -0800100 uptr stack_bottom, bool request_fast_unwind);
Alexey Samsonovf16dc422013-11-07 07:28:33 +0000101
102 private:
103 void FastUnwindStack(uptr pc, uptr bp, uptr stack_top, uptr stack_bottom,
Stephen Hines86277eb2015-03-23 12:06:32 -0700104 u32 max_depth);
105 void SlowUnwindStack(uptr pc, u32 max_depth);
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700106 void SlowUnwindStackWithContext(uptr pc, void *context,
Stephen Hines86277eb2015-03-23 12:06:32 -0700107 u32 max_depth);
Bill Wendling4b206b32013-12-11 06:28:27 +0000108 void PopStackFrames(uptr count);
Alexey Samsonov6a58b002013-11-15 10:57:56 +0000109 uptr LocatePcInTrace(uptr pc);
Stephen Hines6d186232014-11-26 17:56:19 -0800110
111 BufferedStackTrace(const BufferedStackTrace &);
112 void operator=(const BufferedStackTrace &);
Kostya Serebryanyc7be4072012-08-28 14:27:06 +0000113};
114
Kostya Serebryanyc7be4072012-08-28 14:27:06 +0000115} // namespace __sanitizer
116
117// Use this macro if you want to print stack trace with the caller
118// of the current function in the top frame.
119#define GET_CALLER_PC_BP_SP \
120 uptr bp = GET_CURRENT_FRAME(); \
121 uptr pc = GET_CALLER_PC(); \
122 uptr local_stack; \
123 uptr sp = (uptr)&local_stack
124
Stephen Hines6d186232014-11-26 17:56:19 -0800125#define GET_CALLER_PC_BP \
126 uptr bp = GET_CURRENT_FRAME(); \
127 uptr pc = GET_CALLER_PC();
128
Kostya Serebryanyc7be4072012-08-28 14:27:06 +0000129// Use this macro if you want to print stack trace with the current
130// function in the top frame.
131#define GET_CURRENT_PC_BP_SP \
132 uptr bp = GET_CURRENT_FRAME(); \
133 uptr pc = StackTrace::GetCurrentPc(); \
134 uptr local_stack; \
135 uptr sp = (uptr)&local_stack
136
137
138#endif // SANITIZER_STACKTRACE_H