stacktrace.cc (6748B)
1 // Copyright 2017 The Abseil Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // https://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 // Produce stack trace. 16 // 17 // There are three different ways we can try to get the stack trace: 18 // 19 // 1) Our hand-coded stack-unwinder. This depends on a certain stack 20 // layout, which is used by gcc (and those systems using a 21 // gcc-compatible ABI) on x86 systems, at least since gcc 2.95. 22 // It uses the frame pointer to do its work. 23 // 24 // 2) The libunwind library. This is still in development, and as a 25 // separate library adds a new dependency, but doesn't need a frame 26 // pointer. It also doesn't call malloc. 27 // 28 // 3) The gdb unwinder -- also the one used by the c++ exception code. 29 // It's obviously well-tested, but has a fatal flaw: it can call 30 // malloc() from the unwinder. This is a problem because we're 31 // trying to use the unwinder to instrument malloc(). 32 // 33 // Note: if you add a new implementation here, make sure it works 34 // correctly when absl::GetStackTrace() is called with max_depth == 0. 35 // Some code may do that. 36 37 #include "absl/debugging/stacktrace.h" 38 39 #include <stdint.h> 40 41 #include <algorithm> 42 #include <atomic> 43 44 #include "absl/base/attributes.h" 45 #include "absl/base/config.h" 46 #include "absl/base/optimization.h" 47 #include "absl/base/port.h" 48 #include "absl/debugging/internal/stacktrace_config.h" 49 50 #if defined(ABSL_STACKTRACE_INL_HEADER) 51 #include ABSL_STACKTRACE_INL_HEADER 52 #else 53 # error Cannot calculate stack trace: will need to write for your environment 54 55 # include "absl/debugging/internal/stacktrace_aarch64-inl.inc" 56 # include "absl/debugging/internal/stacktrace_arm-inl.inc" 57 # include "absl/debugging/internal/stacktrace_emscripten-inl.inc" 58 # include "absl/debugging/internal/stacktrace_generic-inl.inc" 59 # include "absl/debugging/internal/stacktrace_powerpc-inl.inc" 60 # include "absl/debugging/internal/stacktrace_riscv-inl.inc" 61 # include "absl/debugging/internal/stacktrace_unimplemented-inl.inc" 62 # include "absl/debugging/internal/stacktrace_win32-inl.inc" 63 # include "absl/debugging/internal/stacktrace_x86-inl.inc" 64 #endif 65 66 namespace absl { 67 ABSL_NAMESPACE_BEGIN 68 namespace { 69 70 typedef int (*Unwinder)(void**, int*, int, int, const void*, int*); 71 std::atomic<Unwinder> custom; 72 73 template <bool IS_STACK_FRAMES, bool IS_WITH_CONTEXT> 74 ABSL_ATTRIBUTE_ALWAYS_INLINE inline int Unwind(void** result, uintptr_t* frames, 75 int* sizes, int max_depth, 76 int skip_count, const void* uc, 77 int* min_dropped_frames) { 78 Unwinder g = custom.load(std::memory_order_acquire); 79 int size; 80 // Add 1 to skip count for the unwinder function itself 81 ++skip_count; 82 if (g != nullptr) { 83 size = (*g)(result, sizes, max_depth, skip_count, uc, min_dropped_frames); 84 // Frame pointers aren't returned by existing hooks, so clear them. 85 if (frames != nullptr) { 86 std::fill(frames, frames + size, uintptr_t()); 87 } 88 } else { 89 size = UnwindImpl<IS_STACK_FRAMES, IS_WITH_CONTEXT>( 90 result, frames, sizes, max_depth, skip_count, uc, min_dropped_frames); 91 } 92 ABSL_BLOCK_TAIL_CALL_OPTIMIZATION(); 93 return size; 94 } 95 96 } // anonymous namespace 97 98 ABSL_ATTRIBUTE_NOINLINE ABSL_ATTRIBUTE_NO_TAIL_CALL int 99 internal_stacktrace::GetStackFrames(void** result, uintptr_t* frames, 100 int* sizes, int max_depth, int skip_count) { 101 return Unwind<true, false>(result, frames, sizes, max_depth, skip_count, 102 nullptr, nullptr); 103 } 104 105 ABSL_ATTRIBUTE_NOINLINE ABSL_ATTRIBUTE_NO_TAIL_CALL int 106 internal_stacktrace::GetStackFramesWithContext(void** result, uintptr_t* frames, 107 int* sizes, int max_depth, 108 int skip_count, const void* uc, 109 int* min_dropped_frames) { 110 return Unwind<true, true>(result, frames, sizes, max_depth, skip_count, uc, 111 min_dropped_frames); 112 } 113 114 ABSL_ATTRIBUTE_NOINLINE ABSL_ATTRIBUTE_NO_TAIL_CALL int GetStackTrace( 115 void** result, int max_depth, int skip_count) { 116 return Unwind<false, false>(result, nullptr, nullptr, max_depth, skip_count, 117 nullptr, nullptr); 118 } 119 120 ABSL_ATTRIBUTE_NOINLINE ABSL_ATTRIBUTE_NO_TAIL_CALL int 121 GetStackTraceWithContext(void** result, int max_depth, int skip_count, 122 const void* uc, int* min_dropped_frames) { 123 return Unwind<false, true>(result, nullptr, nullptr, max_depth, skip_count, 124 uc, min_dropped_frames); 125 } 126 127 void SetStackUnwinder(Unwinder w) { 128 custom.store(w, std::memory_order_release); 129 } 130 131 ABSL_ATTRIBUTE_ALWAYS_INLINE static inline int DefaultStackUnwinderImpl( 132 void** pcs, uintptr_t* frames, int* sizes, int depth, int skip, 133 const void* uc, int* min_dropped_frames) { 134 skip++; // For this function 135 decltype(&UnwindImpl<false, false>) f; 136 if (sizes == nullptr) { 137 if (uc == nullptr) { 138 f = &UnwindImpl<false, false>; 139 } else { 140 f = &UnwindImpl<false, true>; 141 } 142 } else { 143 if (uc == nullptr) { 144 f = &UnwindImpl<true, false>; 145 } else { 146 f = &UnwindImpl<true, true>; 147 } 148 } 149 return (*f)(pcs, frames, sizes, depth, skip, uc, min_dropped_frames); 150 } 151 152 ABSL_ATTRIBUTE_NOINLINE ABSL_ATTRIBUTE_NO_TAIL_CALL int 153 internal_stacktrace::DefaultStackUnwinder(void** pcs, uintptr_t* frames, 154 int* sizes, int depth, int skip, 155 const void* uc, 156 int* min_dropped_frames) { 157 int n = DefaultStackUnwinderImpl(pcs, frames, sizes, depth, skip, uc, 158 min_dropped_frames); 159 ABSL_BLOCK_TAIL_CALL_OPTIMIZATION(); 160 return n; 161 } 162 163 ABSL_ATTRIBUTE_NOINLINE ABSL_ATTRIBUTE_NO_TAIL_CALL int DefaultStackUnwinder( 164 void** pcs, int* sizes, int depth, int skip, const void* uc, 165 int* min_dropped_frames) { 166 int n = DefaultStackUnwinderImpl(pcs, nullptr, sizes, depth, skip, uc, 167 min_dropped_frames); 168 ABSL_BLOCK_TAIL_CALL_OPTIMIZATION(); 169 return n; 170 } 171 172 ABSL_NAMESPACE_END 173 } // namespace absl