1 //===-- sanitizer_stacktrace.cc -------------------------------------------===//
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
14 #include "sanitizer_common.h"
15 #include "sanitizer_flags.h"
16 #include "sanitizer_stacktrace.h"
17
18 namespace __sanitizer {
19
GetPreviousInstructionPc(uptr pc)20 uptr StackTrace::GetPreviousInstructionPc(uptr pc) {
21 #if defined(__arm__)
22 // Cancel Thumb bit.
23 pc = pc & (~1);
24 #endif
25 #if defined(__powerpc__) || defined(__powerpc64__)
26 // PCs are always 4 byte aligned.
27 return pc - 4;
28 #elif defined(__sparc__)
29 return pc - 8;
30 #else
31 return pc - 1;
32 #endif
33 }
34
GetCurrentPc()35 uptr StackTrace::GetCurrentPc() {
36 return GET_CALLER_PC();
37 }
38
FastUnwindStack(uptr pc,uptr bp,uptr stack_top,uptr stack_bottom,uptr max_depth)39 void StackTrace::FastUnwindStack(uptr pc, uptr bp,
40 uptr stack_top, uptr stack_bottom,
41 uptr max_depth) {
42 CHECK_GE(max_depth, 2);
43 trace[0] = pc;
44 size = 1;
45 uhwptr *frame = (uhwptr *)bp;
46 uhwptr *prev_frame = frame - 1;
47 if (stack_top < 4096) return; // Sanity check for stack top.
48 // Avoid infinite loop when frame == frame[0] by using frame > prev_frame.
49 while (frame > prev_frame &&
50 frame < (uhwptr *)stack_top - 2 &&
51 frame > (uhwptr *)stack_bottom &&
52 IsAligned((uptr)frame, sizeof(*frame)) &&
53 size < max_depth) {
54 uhwptr pc1 = frame[1];
55 if (pc1 != pc) {
56 trace[size++] = (uptr) pc1;
57 }
58 prev_frame = frame;
59 frame = (uhwptr *)frame[0];
60 }
61 }
62
MatchPc(uptr cur_pc,uptr trace_pc,uptr threshold)63 static bool MatchPc(uptr cur_pc, uptr trace_pc, uptr threshold) {
64 return cur_pc - trace_pc <= threshold || trace_pc - cur_pc <= threshold;
65 }
66
PopStackFrames(uptr count)67 void StackTrace::PopStackFrames(uptr count) {
68 CHECK_LT(count, size);
69 size -= count;
70 for (uptr i = 0; i < size; ++i) {
71 trace[i] = trace[i + count];
72 }
73 }
74
LocatePcInTrace(uptr pc)75 uptr StackTrace::LocatePcInTrace(uptr pc) {
76 // Use threshold to find PC in stack trace, as PC we want to unwind from may
77 // slightly differ from return address in the actual unwinded stack trace.
78 const int kPcThreshold = 288;
79 for (uptr i = 0; i < size; ++i) {
80 if (MatchPc(pc, trace[i], kPcThreshold))
81 return i;
82 }
83 return 0;
84 }
85
86 } // namespace __sanitizer
87