Kostya Serebryany | c7be407 | 2012-08-28 14:27:06 +0000 | [diff] [blame] | 1 | //===-- 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 Serebryany | 9ada1f3 | 2012-08-28 14:48:28 +0000 | [diff] [blame] | 16 | #include "sanitizer_internal_defs.h" |
Kostya Serebryany | c7be407 | 2012-08-28 14:27:06 +0000 | [diff] [blame] | 17 | |
| 18 | namespace __sanitizer { |
| 19 | |
Kostya Serebryany | 6d924fa | 2012-09-06 10:57:03 +0000 | [diff] [blame] | 20 | static const uptr kStackTraceMax = 256; |
Kostya Serebryany | c7be407 | 2012-08-28 14:27:06 +0000 | [diff] [blame] | 21 | |
Sergey Matveev | 736cf49 | 2013-05-08 12:45:55 +0000 | [diff] [blame] | 22 | #if SANITIZER_LINUX && (defined(__arm__) || \ |
| 23 | defined(__powerpc__) || defined(__powerpc64__) || \ |
Kostya Serebryany | 40527a5 | 2013-06-03 14:49:25 +0000 | [diff] [blame] | 24 | defined(__sparc__) || \ |
| 25 | defined(__mips__)) |
Alexey Samsonov | e74968c | 2013-11-07 06:33:06 +0000 | [diff] [blame] | 26 | # define SANITIZER_CAN_FAST_UNWIND 0 |
| 27 | #elif SANITIZER_WINDOWS |
| 28 | # define SANITIZER_CAN_FAST_UNWIND 0 |
Sergey Matveev | 736cf49 | 2013-05-08 12:45:55 +0000 | [diff] [blame] | 29 | #else |
Alexey Samsonov | e74968c | 2013-11-07 06:33:06 +0000 | [diff] [blame] | 30 | # define SANITIZER_CAN_FAST_UNWIND 1 |
Sergey Matveev | 736cf49 | 2013-05-08 12:45:55 +0000 | [diff] [blame] | 31 | #endif |
| 32 | |
Kostya Serebryany | c7be407 | 2012-08-28 14:27:06 +0000 | [diff] [blame] | 33 | struct StackTrace { |
| 34 | typedef bool (*SymbolizeCallback)(const void *pc, char *out_buffer, |
| 35 | int out_size); |
Alexey Samsonov | 1b17f5b | 2013-11-13 14:46:58 +0000 | [diff] [blame] | 36 | uptr top_frame_bp; |
Kostya Serebryany | c7be407 | 2012-08-28 14:27:06 +0000 | [diff] [blame] | 37 | uptr size; |
Kostya Serebryany | c7be407 | 2012-08-28 14:27:06 +0000 | [diff] [blame] | 38 | uptr trace[kStackTraceMax]; |
Alexey Samsonov | 3e0b8ff | 2013-10-12 12:40:47 +0000 | [diff] [blame] | 39 | |
Alexey Samsonov | a96c4dc | 2013-11-01 00:19:46 +0000 | [diff] [blame] | 40 | // Prints a symbolized stacktrace, followed by an empty line. |
Alexey Samsonov | 7996a2e | 2013-10-29 05:31:25 +0000 | [diff] [blame] | 41 | static void PrintStack(const uptr *addr, uptr size, |
| 42 | SymbolizeCallback symbolize_callback = 0); |
Kostya Serebryany | c7be407 | 2012-08-28 14:27:06 +0000 | [diff] [blame] | 43 | |
Alexey Samsonov | d09c91a | 2013-10-14 07:36:10 +0000 | [diff] [blame] | 44 | void CopyFrom(const uptr *src, uptr src_size) { |
Alexey Samsonov | 1b17f5b | 2013-11-13 14:46:58 +0000 | [diff] [blame] | 45 | top_frame_bp = 0; |
Alexey Samsonov | d09c91a | 2013-10-14 07:36:10 +0000 | [diff] [blame] | 46 | size = src_size; |
| 47 | if (size > kStackTraceMax) size = kStackTraceMax; |
| 48 | for (uptr i = 0; i < size; i++) |
| 49 | trace[i] = src[i]; |
| 50 | } |
Kostya Serebryany | c7be407 | 2012-08-28 14:27:06 +0000 | [diff] [blame] | 51 | |
Alexey Samsonov | f16dc42 | 2013-11-07 07:28:33 +0000 | [diff] [blame] | 52 | static bool WillUseFastUnwind(bool request_fast_unwind) { |
| 53 | // Check if fast unwind is available. Fast unwind is the only option on Mac. |
| 54 | if (!SANITIZER_CAN_FAST_UNWIND) |
| 55 | return false; |
| 56 | else if (SANITIZER_MAC) |
| 57 | return true; |
| 58 | return request_fast_unwind; |
| 59 | } |
Kostya Serebryany | c7be407 | 2012-08-28 14:27:06 +0000 | [diff] [blame] | 60 | |
Alexey Samsonov | f16dc42 | 2013-11-07 07:28:33 +0000 | [diff] [blame] | 61 | void Unwind(uptr max_depth, uptr pc, uptr bp, uptr stack_top, |
| 62 | uptr stack_bottom, bool request_fast_unwind); |
Kostya Serebryany | d7d4650 | 2012-11-20 07:00:42 +0000 | [diff] [blame] | 63 | |
Kostya Serebryany | c7be407 | 2012-08-28 14:27:06 +0000 | [diff] [blame] | 64 | static uptr GetCurrentPc(); |
Alexey Samsonov | d2f08ff | 2012-12-18 09:57:34 +0000 | [diff] [blame] | 65 | static uptr GetPreviousInstructionPc(uptr pc); |
Alexey Samsonov | f16dc42 | 2013-11-07 07:28:33 +0000 | [diff] [blame] | 66 | |
| 67 | private: |
| 68 | void FastUnwindStack(uptr pc, uptr bp, uptr stack_top, uptr stack_bottom, |
| 69 | uptr max_depth); |
| 70 | void SlowUnwindStack(uptr pc, uptr max_depth); |
| 71 | void PopStackFrames(uptr count); |
Alexey Samsonov | 6a58b00 | 2013-11-15 10:57:56 +0000 | [diff] [blame^] | 72 | uptr LocatePcInTrace(uptr pc); |
Kostya Serebryany | c7be407 | 2012-08-28 14:27:06 +0000 | [diff] [blame] | 73 | }; |
| 74 | |
Kostya Serebryany | c7be407 | 2012-08-28 14:27:06 +0000 | [diff] [blame] | 75 | } // namespace __sanitizer |
| 76 | |
| 77 | // Use this macro if you want to print stack trace with the caller |
| 78 | // of the current function in the top frame. |
| 79 | #define GET_CALLER_PC_BP_SP \ |
| 80 | uptr bp = GET_CURRENT_FRAME(); \ |
| 81 | uptr pc = GET_CALLER_PC(); \ |
| 82 | uptr local_stack; \ |
| 83 | uptr sp = (uptr)&local_stack |
| 84 | |
| 85 | // Use this macro if you want to print stack trace with the current |
| 86 | // function in the top frame. |
| 87 | #define GET_CURRENT_PC_BP_SP \ |
| 88 | uptr bp = GET_CURRENT_FRAME(); \ |
| 89 | uptr pc = StackTrace::GetCurrentPc(); \ |
| 90 | uptr local_stack; \ |
| 91 | uptr sp = (uptr)&local_stack |
| 92 | |
| 93 | |
| 94 | #endif // SANITIZER_STACKTRACE_H |