stacktrace_generic-inl.inc (3596B)
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 // Portable implementation - just use glibc 16 // 17 // Note: The glibc implementation may cause a call to malloc. 18 // This can cause a deadlock in HeapProfiler. 19 20 #ifndef ABSL_DEBUGGING_INTERNAL_STACKTRACE_GENERIC_INL_H_ 21 #define ABSL_DEBUGGING_INTERNAL_STACKTRACE_GENERIC_INL_H_ 22 23 #include <execinfo.h> 24 #include <atomic> 25 #include <cstring> 26 27 #include "absl/debugging/stacktrace.h" 28 #include "absl/base/attributes.h" 29 30 // Sometimes, we can try to get a stack trace from within a stack 31 // trace, because we don't block signals inside this code (which would be too 32 // expensive: the two extra system calls per stack trace do matter here). 33 // That can cause a self-deadlock. 34 // Protect against such reentrant call by failing to get a stack trace. 35 // 36 // We use __thread here because the code here is extremely low level -- it is 37 // called while collecting stack traces from within malloc and mmap, and thus 38 // can not call anything which might call malloc or mmap itself. 39 static __thread int recursive = 0; 40 41 // The stack trace function might be invoked very early in the program's 42 // execution (e.g. from the very first malloc if using tcmalloc). Also, the 43 // glibc implementation itself will trigger malloc the first time it is called. 44 // As such, we suppress usage of backtrace during this early stage of execution. 45 static std::atomic<bool> disable_stacktraces(true); // Disabled until healthy. 46 47 template <bool IS_STACK_FRAMES, bool IS_WITH_CONTEXT> 48 static int UnwindImpl(void** result, uintptr_t* frames, int* sizes, 49 int max_depth, int skip_count, const void* ucp, 50 int* min_dropped_frames) { 51 if (recursive || disable_stacktraces.load(std::memory_order_relaxed)) { 52 return 0; 53 } 54 ++recursive; 55 56 static_cast<void>(ucp); // Unused. 57 static const int kStackLength = 64; 58 void * stack[kStackLength]; 59 int size; 60 61 size = backtrace(stack, kStackLength); 62 skip_count++; // we want to skip the current frame as well 63 int result_count = size - skip_count; 64 if (result_count < 0) 65 result_count = 0; 66 if (result_count > max_depth) 67 result_count = max_depth; 68 for (int i = 0; i < result_count; i++) 69 result[i] = stack[i + skip_count]; 70 71 if (IS_STACK_FRAMES) { 72 // No implementation for finding out the stack frames yet. 73 if (frames != nullptr) { 74 memset(frames, 0, sizeof(*frames) * static_cast<size_t>(result_count)); 75 } 76 if (sizes != nullptr) { 77 memset(sizes, 0, sizeof(*sizes) * static_cast<size_t>(result_count)); 78 } 79 } 80 if (min_dropped_frames != nullptr) { 81 if (size - skip_count - max_depth > 0) { 82 *min_dropped_frames = size - skip_count - max_depth; 83 } else { 84 *min_dropped_frames = 0; 85 } 86 } 87 88 --recursive; 89 90 return result_count; 91 } 92 93 namespace absl { 94 ABSL_NAMESPACE_BEGIN 95 namespace debugging_internal { 96 bool StackTraceWorksForTest() { 97 return false; 98 } 99 } // namespace debugging_internal 100 ABSL_NAMESPACE_END 101 } // namespace absl 102 103 #endif // ABSL_DEBUGGING_INTERNAL_STACKTRACE_GENERIC_INL_H_