1*9356374aSAndroid Build Coastguard Worker// Copyright 2017 The Abseil Authors. 2*9356374aSAndroid Build Coastguard Worker// 3*9356374aSAndroid Build Coastguard Worker// Licensed under the Apache License, Version 2.0 (the "License"); 4*9356374aSAndroid Build Coastguard Worker// you may not use this file except in compliance with the License. 5*9356374aSAndroid Build Coastguard Worker// You may obtain a copy of the License at 6*9356374aSAndroid Build Coastguard Worker// 7*9356374aSAndroid Build Coastguard Worker// https://www.apache.org/licenses/LICENSE-2.0 8*9356374aSAndroid Build Coastguard Worker// 9*9356374aSAndroid Build Coastguard Worker// Unless required by applicable law or agreed to in writing, software 10*9356374aSAndroid Build Coastguard Worker// distributed under the License is distributed on an "AS IS" BASIS, 11*9356374aSAndroid Build Coastguard Worker// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12*9356374aSAndroid Build Coastguard Worker// See the License for the specific language governing permissions and 13*9356374aSAndroid Build Coastguard Worker// limitations under the License. 14*9356374aSAndroid Build Coastguard Worker// 15*9356374aSAndroid Build Coastguard Worker// Portable implementation - just use glibc 16*9356374aSAndroid Build Coastguard Worker// 17*9356374aSAndroid Build Coastguard Worker// Note: The glibc implementation may cause a call to malloc. 18*9356374aSAndroid Build Coastguard Worker// This can cause a deadlock in HeapProfiler. 19*9356374aSAndroid Build Coastguard Worker 20*9356374aSAndroid Build Coastguard Worker#ifndef ABSL_DEBUGGING_INTERNAL_STACKTRACE_EMSCRIPTEN_INL_H_ 21*9356374aSAndroid Build Coastguard Worker#define ABSL_DEBUGGING_INTERNAL_STACKTRACE_EMSCRIPTEN_INL_H_ 22*9356374aSAndroid Build Coastguard Worker 23*9356374aSAndroid Build Coastguard Worker#include <emscripten.h> 24*9356374aSAndroid Build Coastguard Worker 25*9356374aSAndroid Build Coastguard Worker#include <atomic> 26*9356374aSAndroid Build Coastguard Worker#include <cstring> 27*9356374aSAndroid Build Coastguard Worker 28*9356374aSAndroid Build Coastguard Worker#include "absl/base/attributes.h" 29*9356374aSAndroid Build Coastguard Worker#include "absl/debugging/stacktrace.h" 30*9356374aSAndroid Build Coastguard Worker 31*9356374aSAndroid Build Coastguard Workerextern "C" { 32*9356374aSAndroid Build Coastguard Workeruintptr_t emscripten_stack_snapshot(); 33*9356374aSAndroid Build Coastguard Workeruint32_t emscripten_stack_unwind_buffer(uintptr_t pc, void *buffer, 34*9356374aSAndroid Build Coastguard Worker uint32_t depth); 35*9356374aSAndroid Build Coastguard Worker} 36*9356374aSAndroid Build Coastguard Worker 37*9356374aSAndroid Build Coastguard Worker// Sometimes, we can try to get a stack trace from within a stack 38*9356374aSAndroid Build Coastguard Worker// trace, which can cause a self-deadlock. 39*9356374aSAndroid Build Coastguard Worker// Protect against such reentrant call by failing to get a stack trace. 40*9356374aSAndroid Build Coastguard Worker// 41*9356374aSAndroid Build Coastguard Worker// We use __thread here because the code here is extremely low level -- it is 42*9356374aSAndroid Build Coastguard Worker// called while collecting stack traces from within malloc and mmap, and thus 43*9356374aSAndroid Build Coastguard Worker// can not call anything which might call malloc or mmap itself. 44*9356374aSAndroid Build Coastguard Workerstatic __thread int recursive = 0; 45*9356374aSAndroid Build Coastguard Worker 46*9356374aSAndroid Build Coastguard Worker// The stack trace function might be invoked very early in the program's 47*9356374aSAndroid Build Coastguard Worker// execution (e.g. from the very first malloc). 48*9356374aSAndroid Build Coastguard Worker// As such, we suppress usage of backtrace during this early stage of execution. 49*9356374aSAndroid Build Coastguard Workerstatic std::atomic<bool> disable_stacktraces(true); // Disabled until healthy. 50*9356374aSAndroid Build Coastguard Worker// Waiting until static initializers run seems to be late enough. 51*9356374aSAndroid Build Coastguard Worker// This file is included into stacktrace.cc so this will only run once. 52*9356374aSAndroid Build Coastguard WorkerABSL_ATTRIBUTE_UNUSED static int stacktraces_enabler = []() { 53*9356374aSAndroid Build Coastguard Worker // Check if we can even create stacktraces. If not, bail early and leave 54*9356374aSAndroid Build Coastguard Worker // disable_stacktraces set as-is. 55*9356374aSAndroid Build Coastguard Worker // clang-format off 56*9356374aSAndroid Build Coastguard Worker if (!EM_ASM_INT({ return (typeof wasmOffsetConverter !== 'undefined'); })) { 57*9356374aSAndroid Build Coastguard Worker return 0; 58*9356374aSAndroid Build Coastguard Worker } 59*9356374aSAndroid Build Coastguard Worker // clang-format on 60*9356374aSAndroid Build Coastguard Worker disable_stacktraces.store(false, std::memory_order_relaxed); 61*9356374aSAndroid Build Coastguard Worker return 0; 62*9356374aSAndroid Build Coastguard Worker}(); 63*9356374aSAndroid Build Coastguard Worker 64*9356374aSAndroid Build Coastguard Workertemplate <bool IS_STACK_FRAMES, bool IS_WITH_CONTEXT> 65*9356374aSAndroid Build Coastguard Workerstatic int UnwindImpl(void **result, int *sizes, int max_depth, int skip_count, 66*9356374aSAndroid Build Coastguard Worker const void *ucp, int *min_dropped_frames) { 67*9356374aSAndroid Build Coastguard Worker if (recursive || disable_stacktraces.load(std::memory_order_relaxed)) { 68*9356374aSAndroid Build Coastguard Worker return 0; 69*9356374aSAndroid Build Coastguard Worker } 70*9356374aSAndroid Build Coastguard Worker ++recursive; 71*9356374aSAndroid Build Coastguard Worker 72*9356374aSAndroid Build Coastguard Worker static_cast<void>(ucp); // Unused. 73*9356374aSAndroid Build Coastguard Worker constexpr int kStackLength = 64; 74*9356374aSAndroid Build Coastguard Worker void *stack[kStackLength]; 75*9356374aSAndroid Build Coastguard Worker 76*9356374aSAndroid Build Coastguard Worker int size; 77*9356374aSAndroid Build Coastguard Worker uintptr_t pc = emscripten_stack_snapshot(); 78*9356374aSAndroid Build Coastguard Worker size = emscripten_stack_unwind_buffer(pc, stack, kStackLength); 79*9356374aSAndroid Build Coastguard Worker 80*9356374aSAndroid Build Coastguard Worker int result_count = size - skip_count; 81*9356374aSAndroid Build Coastguard Worker if (result_count < 0) result_count = 0; 82*9356374aSAndroid Build Coastguard Worker if (result_count > max_depth) result_count = max_depth; 83*9356374aSAndroid Build Coastguard Worker for (int i = 0; i < result_count; i++) result[i] = stack[i + skip_count]; 84*9356374aSAndroid Build Coastguard Worker 85*9356374aSAndroid Build Coastguard Worker if (IS_STACK_FRAMES) { 86*9356374aSAndroid Build Coastguard Worker // No implementation for finding out the stack frame sizes yet. 87*9356374aSAndroid Build Coastguard Worker memset(sizes, 0, sizeof(*sizes) * result_count); 88*9356374aSAndroid Build Coastguard Worker } 89*9356374aSAndroid Build Coastguard Worker if (min_dropped_frames != nullptr) { 90*9356374aSAndroid Build Coastguard Worker if (size - skip_count - max_depth > 0) { 91*9356374aSAndroid Build Coastguard Worker *min_dropped_frames = size - skip_count - max_depth; 92*9356374aSAndroid Build Coastguard Worker } else { 93*9356374aSAndroid Build Coastguard Worker *min_dropped_frames = 0; 94*9356374aSAndroid Build Coastguard Worker } 95*9356374aSAndroid Build Coastguard Worker } 96*9356374aSAndroid Build Coastguard Worker 97*9356374aSAndroid Build Coastguard Worker --recursive; 98*9356374aSAndroid Build Coastguard Worker 99*9356374aSAndroid Build Coastguard Worker return result_count; 100*9356374aSAndroid Build Coastguard Worker} 101*9356374aSAndroid Build Coastguard Worker 102*9356374aSAndroid Build Coastguard Workernamespace absl { 103*9356374aSAndroid Build Coastguard WorkerABSL_NAMESPACE_BEGIN 104*9356374aSAndroid Build Coastguard Workernamespace debugging_internal { 105*9356374aSAndroid Build Coastguard Workerbool StackTraceWorksForTest() { return true; } 106*9356374aSAndroid Build Coastguard Worker} // namespace debugging_internal 107*9356374aSAndroid Build Coastguard WorkerABSL_NAMESPACE_END 108*9356374aSAndroid Build Coastguard Worker} // namespace absl 109*9356374aSAndroid Build Coastguard Worker 110*9356374aSAndroid Build Coastguard Worker#endif // ABSL_DEBUGGING_INTERNAL_STACKTRACE_EMSCRIPTEN_INL_H_ 111