]> git.ipfire.org Git - thirdparty/gcc.git/blame - libsanitizer/sanitizer_common/sanitizer_stacktrace.cpp
[Ada] Sem_Ch13: fix uninitialized parameter static analysis warning
[thirdparty/gcc.git] / libsanitizer / sanitizer_common / sanitizer_stacktrace.cpp
CommitLineData
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
17namespace __sanitizer {
549e2197 18
5645a48f 19uptr 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 29uptr StackTrace::GetCurrentPc() {
30 return GET_CALLER_PC();
31}
32
0328398d 33void 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.
48static 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 70void 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 122void 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 130static uptr Distance(uptr a, uptr b) { return a < b ? b - a : a - b; }
131
0328398d 132uptr 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