]>
Commit | Line | Data |
---|---|---|
2fc4da48 | 1 | //===-- sanitizer_stacktrace.cpp ------------------------------------------===// |
549e2197 | 2 | // |
2fc4da48 | 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 | |
549e2197 | 6 | // |
7 | //===----------------------------------------------------------------------===// | |
8 | // | |
9 | // This file is shared between AddressSanitizer and ThreadSanitizer | |
10 | // run-time libraries. | |
11 | //===----------------------------------------------------------------------===// | |
12 | ||
13 | #include "sanitizer_common.h" | |
4fc7b5ac | 14 | #include "sanitizer_flags.h" |
549e2197 | 15 | #include "sanitizer_stacktrace.h" |
549e2197 | 16 | |
17 | namespace __sanitizer { | |
549e2197 | 18 | |
5645a48f | 19 | uptr StackTrace::GetNextInstructionPc(uptr pc) { |
0e7a25e4 | 20 | #if defined(__sparc__) || defined(__mips__) |
5645a48f | 21 | return pc + 8; |
0e7a25e4 | 22 | #elif defined(__powerpc__) || defined(__arm__) || defined(__aarch64__) |
5645a48f | 23 | return pc + 4; |
0d996a11 | 24 | #else |
5645a48f | 25 | return pc + 1; |
0d996a11 | 26 | #endif |
549e2197 | 27 | } |
28 | ||
549e2197 | 29 | uptr StackTrace::GetCurrentPc() { |
30 | return GET_CALLER_PC(); | |
31 | } | |
32 | ||
0328398d | 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 | ||
d2ef4bee | 42 | // Sparc implemention is in its own file. |
43 | #if !defined(__sparc__) | |
44 | ||
a9586c9c | 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) { | |
2fc4da48 | 51 | CHECK_GT(stack_top, stack_bottom); |
a9586c9c | 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; | |
0328398d | 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 | |
731a9deb | 63 | // layouts. Assume GCC. |
64 | return bp_prev - 1; | |
a9586c9c | 65 | #else |
66 | return (uhwptr*)bp; | |
67 | #endif | |
68 | } | |
69 | ||
2fc4da48 | 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 | |
7d752f28 | 73 | CHECK_GE(max_depth, 2); |
2fc4da48 | 74 | const uptr kPageSize = GetPageSizeCached(); |
0328398d | 75 | trace_buffer[0] = pc; |
549e2197 | 76 | size = 1; |
1e80ce41 | 77 | if (stack_top < 4096) return; // Sanity check for stack top. |
a9586c9c | 78 | uhwptr *frame = GetCanonicFrame(bp, stack_top, stack_bottom); |
0328398d | 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; | |
5a59af67 | 82 | // Avoid infinite loop when frame == frame[0] by using frame > prev_frame. |
0328398d | 83 | while (IsValidFrame((uptr)frame, stack_top, bottom) && |
1e80ce41 | 84 | IsAligned((uptr)frame, sizeof(*frame)) && |
4fc7b5ac | 85 | size < max_depth) { |
afd2b956 | 86 | #ifdef __powerpc__ |
731a9deb | 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. | |
afd2b956 | 90 | uhwptr *caller_frame = (uhwptr*)frame[0]; |
91 | if (!IsValidFrame((uptr)caller_frame, stack_top, bottom) || | |
5645a48f | 92 | !IsAligned((uptr)caller_frame, sizeof(uhwptr))) |
afd2b956 | 93 | break; |
731a9deb | 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 | |
afd2b956 | 100 | uhwptr pc1 = caller_frame[2]; |
731a9deb | 101 | #endif |
23e39437 | 102 | #elif defined(__s390__) |
103 | uhwptr pc1 = frame[14]; | |
afd2b956 | 104 | #else |
1ceb064e | 105 | uhwptr pc1 = frame[1]; |
afd2b956 | 106 | #endif |
23e39437 | 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; | |
549e2197 | 112 | if (pc1 != pc) { |
0328398d | 113 | trace_buffer[size++] = (uptr) pc1; |
549e2197 | 114 | } |
0328398d | 115 | bottom = (uptr)frame; |
116 | frame = GetCanonicFrame((uptr)frame[0], stack_top, bottom); | |
549e2197 | 117 | } |
118 | } | |
119 | ||
d2ef4bee | 120 | #endif // !defined(__sparc__) |
121 | ||
0328398d | 122 | void BufferedStackTrace::PopStackFrames(uptr count) { |
7d752f28 | 123 | CHECK_LT(count, size); |
0d996a11 | 124 | size -= count; |
7d752f28 | 125 | for (uptr i = 0; i < size; ++i) { |
0328398d | 126 | trace_buffer[i] = trace_buffer[i + count]; |
0d996a11 | 127 | } |
128 | } | |
129 | ||
36093749 | 130 | static uptr Distance(uptr a, uptr b) { return a < b ? b - a : a - b; } |
131 | ||
0328398d | 132 | uptr BufferedStackTrace::LocatePcInTrace(uptr pc) { |
36093749 | 133 | uptr best = 0; |
134 | for (uptr i = 1; i < size; ++i) { | |
135 | if (Distance(trace[i], pc) < Distance(trace[best], pc)) best = i; | |
549e2197 | 136 | } |
36093749 | 137 | return best; |
549e2197 | 138 | } |
139 | ||
140 | } // namespace __sanitizer |