stacktrace_emscripten-inl.inc (4036B)
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_EMSCRIPTEN_INL_H_ 21 #define ABSL_DEBUGGING_INTERNAL_STACKTRACE_EMSCRIPTEN_INL_H_ 22 23 #include <emscripten.h> 24 #include <stdint.h> 25 26 #include <atomic> 27 #include <cstring> 28 29 #include "absl/base/attributes.h" 30 #include "absl/debugging/stacktrace.h" 31 32 extern "C" { 33 uintptr_t emscripten_stack_snapshot(); 34 uint32_t emscripten_stack_unwind_buffer(uintptr_t pc, void *buffer, 35 uint32_t depth); 36 } 37 38 // Sometimes, we can try to get a stack trace from within a stack 39 // trace, which can cause a self-deadlock. 40 // Protect against such reentrant call by failing to get a stack trace. 41 // 42 // We use __thread here because the code here is extremely low level -- it is 43 // called while collecting stack traces from within malloc and mmap, and thus 44 // can not call anything which might call malloc or mmap itself. 45 static __thread int recursive = 0; 46 47 // The stack trace function might be invoked very early in the program's 48 // execution (e.g. from the very first malloc). 49 // As such, we suppress usage of backtrace during this early stage of execution. 50 static std::atomic<bool> disable_stacktraces(true); // Disabled until healthy. 51 // Waiting until static initializers run seems to be late enough. 52 // This file is included into stacktrace.cc so this will only run once. 53 ABSL_ATTRIBUTE_UNUSED static int stacktraces_enabler = []() { 54 // Check if we can even create stacktraces. If not, bail early and leave 55 // disable_stacktraces set as-is. 56 // clang-format off 57 if (!EM_ASM_INT({ return (typeof wasmOffsetConverter !== 'undefined'); })) { 58 return 0; 59 } 60 // clang-format on 61 disable_stacktraces.store(false, std::memory_order_relaxed); 62 return 0; 63 }(); 64 65 template <bool IS_STACK_FRAMES, bool IS_WITH_CONTEXT> 66 static int UnwindImpl(void **result, uintptr_t *frames, int *sizes, 67 int max_depth, int skip_count, const void *ucp, 68 int *min_dropped_frames) { 69 if (recursive || disable_stacktraces.load(std::memory_order_relaxed)) { 70 return 0; 71 } 72 ++recursive; 73 74 static_cast<void>(ucp); // Unused. 75 constexpr int kStackLength = 64; 76 void *stack[kStackLength]; 77 78 int size; 79 uintptr_t pc = emscripten_stack_snapshot(); 80 size = emscripten_stack_unwind_buffer(pc, stack, kStackLength); 81 82 int result_count = size - skip_count; 83 if (result_count < 0) result_count = 0; 84 if (result_count > max_depth) result_count = max_depth; 85 for (int i = 0; i < result_count; i++) result[i] = stack[i + skip_count]; 86 87 if (IS_STACK_FRAMES) { 88 // No implementation for finding out the stack frames yet. 89 if (frames != nullptr) { 90 memset(frames, 0, sizeof(*frames) * result_count); 91 } 92 if (sizes != nullptr) { 93 memset(sizes, 0, sizeof(*sizes) * result_count); 94 } 95 } 96 if (min_dropped_frames != nullptr) { 97 if (size - skip_count - max_depth > 0) { 98 *min_dropped_frames = size - skip_count - max_depth; 99 } else { 100 *min_dropped_frames = 0; 101 } 102 } 103 104 --recursive; 105 106 return result_count; 107 } 108 109 namespace absl { 110 ABSL_NAMESPACE_BEGIN 111 namespace debugging_internal { 112 bool StackTraceWorksForTest() { return true; } 113 } // namespace debugging_internal 114 ABSL_NAMESPACE_END 115 } // namespace absl 116 117 #endif // ABSL_DEBUGGING_INTERNAL_STACKTRACE_EMSCRIPTEN_INL_H_