]>
Commit | Line | Data |
---|---|---|
b667dd70 | 1 | //===-- sanitizer_stacktrace.cpp ------------------------------------------===// |
f35db108 | 2 | // |
b667dd70 ML |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. | |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
f35db108 WM |
6 | // |
7 | //===----------------------------------------------------------------------===// | |
8 | // | |
9 | // This file is shared between AddressSanitizer and ThreadSanitizer | |
10 | // run-time libraries. | |
11 | //===----------------------------------------------------------------------===// | |
12 | ||
13 | #include "sanitizer_common.h" | |
df77f0e4 | 14 | #include "sanitizer_flags.h" |
f35db108 | 15 | #include "sanitizer_stacktrace.h" |
f35db108 WM |
16 | |
17 | namespace __sanitizer { | |
f35db108 | 18 | |
696d846a | 19 | uptr StackTrace::GetNextInstructionPc(uptr pc) { |
017abbe3 | 20 | #if defined(__sparc__) || defined(__mips__) |
696d846a | 21 | return pc + 8; |
017abbe3 | 22 | #elif defined(__powerpc__) || defined(__arm__) || defined(__aarch64__) |
696d846a | 23 | return pc + 4; |
e297eb60 | 24 | #else |
696d846a | 25 | return pc + 1; |
e297eb60 | 26 | #endif |
f35db108 WM |
27 | } |
28 | ||
f35db108 WM |
29 | uptr StackTrace::GetCurrentPc() { |
30 | return GET_CALLER_PC(); | |
31 | } | |
32 | ||
c5be964a KS |
33 | void BufferedStackTrace::Init(const uptr *pcs, uptr cnt, uptr extra_top_pc) { |
34 | size = cnt + !!extra_top_pc; | |
35 | CHECK_LE(size, kStackTraceMax); | |
36 | internal_memcpy(trace_buffer, pcs, cnt * sizeof(trace_buffer[0])); | |
37 | if (extra_top_pc) | |
38 | trace_buffer[cnt] = extra_top_pc; | |
39 | top_frame_bp = 0; | |
40 | } | |
41 | ||
eac97531 ML |
42 | // Sparc implemention is in its own file. |
43 | #if !defined(__sparc__) | |
44 | ||
866e32ad KS |
45 | // In GCC on ARM bp points to saved lr, not fp, so we should check the next |
46 | // cell in stack to be a saved frame pointer. GetCanonicFrame returns the | |
47 | // pointer to saved frame pointer in any case. | |
48 | static inline uhwptr *GetCanonicFrame(uptr bp, | |
49 | uptr stack_top, | |
50 | uptr stack_bottom) { | |
b667dd70 | 51 | CHECK_GT(stack_top, stack_bottom); |
866e32ad KS |
52 | #ifdef __arm__ |
53 | if (!IsValidFrame(bp, stack_top, stack_bottom)) return 0; | |
54 | uhwptr *bp_prev = (uhwptr *)bp; | |
55 | if (IsValidFrame((uptr)bp_prev[0], stack_top, stack_bottom)) return bp_prev; | |
c5be964a KS |
56 | // The next frame pointer does not look right. This could be a GCC frame, step |
57 | // back by 1 word and try again. | |
58 | if (IsValidFrame((uptr)bp_prev[-1], stack_top, stack_bottom)) | |
59 | return bp_prev - 1; | |
60 | // Nope, this does not look right either. This means the frame after next does | |
61 | // not have a valid frame pointer, but we can still extract the caller PC. | |
62 | // Unfortunately, there is no way to decide between GCC and LLVM frame | |
f18ab180 ML |
63 | // layouts. Assume GCC. |
64 | return bp_prev - 1; | |
866e32ad KS |
65 | #else |
66 | return (uhwptr*)bp; | |
67 | #endif | |
68 | } | |
69 | ||
b667dd70 ML |
70 | void BufferedStackTrace::UnwindFast(uptr pc, uptr bp, uptr stack_top, |
71 | uptr stack_bottom, u32 max_depth) { | |
72 | // TODO(yln): add arg sanity check for stack_top/stack_bottom | |
dee5ea7a | 73 | CHECK_GE(max_depth, 2); |
b667dd70 | 74 | const uptr kPageSize = GetPageSizeCached(); |
c5be964a | 75 | trace_buffer[0] = pc; |
f35db108 | 76 | size = 1; |
ef1b3fda | 77 | if (stack_top < 4096) return; // Sanity check for stack top. |
866e32ad | 78 | uhwptr *frame = GetCanonicFrame(bp, stack_top, stack_bottom); |
c5be964a KS |
79 | // Lowest possible address that makes sense as the next frame pointer. |
80 | // Goes up as we walk the stack. | |
81 | uptr bottom = stack_bottom; | |
7df59255 | 82 | // Avoid infinite loop when frame == frame[0] by using frame > prev_frame. |
c5be964a | 83 | while (IsValidFrame((uptr)frame, stack_top, bottom) && |
ef1b3fda | 84 | IsAligned((uptr)frame, sizeof(*frame)) && |
df77f0e4 | 85 | size < max_depth) { |
3d61d875 | 86 | #ifdef __powerpc__ |
f18ab180 ML |
87 | // PowerPC ABIs specify that the return address is saved on the |
88 | // *caller's* stack frame. Thus we must dereference the back chain | |
89 | // to find the caller frame before extracting it. | |
3d61d875 BS |
90 | uhwptr *caller_frame = (uhwptr*)frame[0]; |
91 | if (!IsValidFrame((uptr)caller_frame, stack_top, bottom) || | |
696d846a | 92 | !IsAligned((uptr)caller_frame, sizeof(uhwptr))) |
3d61d875 | 93 | break; |
f18ab180 ML |
94 | // For most ABIs the offset where the return address is saved is two |
95 | // register sizes. The exception is the SVR4 ABI, which uses an | |
96 | // offset of only one register size. | |
97 | #ifdef _CALL_SYSV | |
98 | uhwptr pc1 = caller_frame[1]; | |
99 | #else | |
3d61d875 | 100 | uhwptr pc1 = caller_frame[2]; |
f18ab180 | 101 | #endif |
10189819 MO |
102 | #elif defined(__s390__) |
103 | uhwptr pc1 = frame[14]; | |
3d61d875 | 104 | #else |
d1caed14 | 105 | uhwptr pc1 = frame[1]; |
3d61d875 | 106 | #endif |
10189819 MO |
107 | // Let's assume that any pointer in the 0th page (i.e. <0x1000 on i386 and |
108 | // x86_64) is invalid and stop unwinding here. If we're adding support for | |
109 | // a platform where this isn't true, we need to reconsider this check. | |
110 | if (pc1 < kPageSize) | |
111 | break; | |
f35db108 | 112 | if (pc1 != pc) { |
c5be964a | 113 | trace_buffer[size++] = (uptr) pc1; |
f35db108 | 114 | } |
c5be964a KS |
115 | bottom = (uptr)frame; |
116 | frame = GetCanonicFrame((uptr)frame[0], stack_top, bottom); | |
f35db108 WM |
117 | } |
118 | } | |
119 | ||
eac97531 ML |
120 | #endif // !defined(__sparc__) |
121 | ||
c5be964a | 122 | void BufferedStackTrace::PopStackFrames(uptr count) { |
dee5ea7a | 123 | CHECK_LT(count, size); |
e297eb60 | 124 | size -= count; |
dee5ea7a | 125 | for (uptr i = 0; i < size; ++i) { |
c5be964a | 126 | trace_buffer[i] = trace_buffer[i + count]; |
e297eb60 KS |
127 | } |
128 | } | |
129 | ||
5d3805fc JJ |
130 | static uptr Distance(uptr a, uptr b) { return a < b ? b - a : a - b; } |
131 | ||
c5be964a | 132 | uptr BufferedStackTrace::LocatePcInTrace(uptr pc) { |
5d3805fc JJ |
133 | uptr best = 0; |
134 | for (uptr i = 1; i < size; ++i) { | |
135 | if (Distance(trace[i], pc) < Distance(trace[best], pc)) best = i; | |
f35db108 | 136 | } |
5d3805fc | 137 | return best; |
f35db108 WM |
138 | } |
139 | ||
140 | } // namespace __sanitizer |