1 | //===-- backtrace_sanitizer_common.cpp --------------------------*- C++ -*-===// |
2 | // |
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 |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #include <assert.h> |
10 | #include <stddef.h> |
11 | #include <stdint.h> |
12 | #include <string.h> |
13 | |
14 | #include "gwp_asan/optional/backtrace.h" |
15 | #include "gwp_asan/options.h" |
16 | #include "sanitizer_common/sanitizer_common.h" |
17 | #include "sanitizer_common/sanitizer_flag_parser.h" |
18 | #include "sanitizer_common/sanitizer_flags.h" |
19 | #include "sanitizer_common/sanitizer_stacktrace.h" |
20 | |
21 | void __sanitizer::BufferedStackTrace::UnwindImpl(uptr pc, uptr bp, |
22 | void *context, |
23 | bool request_fast, |
24 | u32 max_depth) { |
25 | if (!StackTrace::WillUseFastUnwind(request_fast_unwind: request_fast)) |
26 | return Unwind(max_depth, pc, bp: 0, context, stack_top: 0, stack_bottom: 0, request_fast_unwind: false); |
27 | |
28 | uptr top = 0; |
29 | uptr bottom = 0; |
30 | GetThreadStackTopAndBottom(/*at_initialization*/ false, stack_top: &top, stack_bottom: &bottom); |
31 | |
32 | return Unwind(max_depth, pc, bp, context, stack_top: top, stack_bottom: bottom, request_fast_unwind: request_fast); |
33 | } |
34 | |
35 | namespace { |
36 | size_t BacktraceCommon(uintptr_t *TraceBuffer, size_t Size, void *Context) { |
37 | // Use the slow sanitizer unwinder in the segv handler. Fast frame pointer |
38 | // unwinders can end up dropping frames because the kernel sigreturn() frame's |
39 | // return address is the return address at time of fault. This has the result |
40 | // of never actually capturing the PC where the signal was raised. |
41 | bool UseFastUnwind = (Context == nullptr); |
42 | |
43 | __sanitizer::BufferedStackTrace Trace; |
44 | Trace.Reset(); |
45 | if (Size > __sanitizer::kStackTraceMax) |
46 | Size = __sanitizer::kStackTraceMax; |
47 | |
48 | Trace.Unwind(pc: (__sanitizer::uptr)__builtin_return_address(0), |
49 | bp: (__sanitizer::uptr)__builtin_frame_address(0), context: Context, |
50 | request_fast: UseFastUnwind, max_depth: Size - 1); |
51 | |
52 | memcpy(dest: TraceBuffer, src: Trace.trace, n: Trace.size * sizeof(uintptr_t)); |
53 | return Trace.size; |
54 | } |
55 | |
56 | size_t Backtrace(uintptr_t *TraceBuffer, size_t Size) { |
57 | return BacktraceCommon(TraceBuffer, Size, Context: nullptr); |
58 | } |
59 | |
60 | size_t SegvBacktrace(uintptr_t *TraceBuffer, size_t Size, void *Context) { |
61 | return BacktraceCommon(TraceBuffer, Size, Context); |
62 | } |
63 | |
64 | static void PrintBacktrace(uintptr_t *Trace, size_t TraceLength, |
65 | gwp_asan::Printf_t Printf) { |
66 | __sanitizer::StackTrace StackTrace; |
67 | StackTrace.trace = reinterpret_cast<__sanitizer::uptr *>(Trace); |
68 | StackTrace.size = TraceLength; |
69 | |
70 | if (StackTrace.size == 0) { |
71 | Printf(" <unknown (does your allocator support backtracing?)>\n\n" ); |
72 | return; |
73 | } |
74 | |
75 | __sanitizer::InternalScopedString buffer; |
76 | StackTrace.PrintTo(output: &buffer); |
77 | Printf("%s\n" , buffer.data()); |
78 | } |
79 | } // anonymous namespace |
80 | |
81 | namespace gwp_asan { |
82 | namespace backtrace { |
83 | |
84 | // This function is thread-compatible. It must be synchronised in respect to any |
85 | // other calls to getBacktraceFunction(), calls to getPrintBacktraceFunction(), |
86 | // and calls to either of the functions that they return. Furthermore, this may |
87 | // require synchronisation with any calls to sanitizer_common that use flags. |
88 | // Generally, this function will be called during the initialisation of the |
89 | // allocator, which is done in a thread-compatible manner. |
90 | options::Backtrace_t getBacktraceFunction() { |
91 | // The unwinder requires the default flags to be set. |
92 | __sanitizer::SetCommonFlagsDefaults(); |
93 | __sanitizer::InitializeCommonFlags(); |
94 | return Backtrace; |
95 | } |
96 | |
97 | PrintBacktrace_t getPrintBacktraceFunction() { return PrintBacktrace; } |
98 | SegvBacktrace_t getSegvBacktraceFunction() { return SegvBacktrace; } |
99 | |
100 | } // namespace backtrace |
101 | } // namespace gwp_asan |
102 | |