// Copyright 2012 The Chromium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "partition_alloc/partition_alloc_base/debug/stack_trace.h" #include <cstdint> #include "partition_alloc/build_config.h" #include "partition_alloc/partition_alloc_base/check.h" #include "partition_alloc/partition_alloc_base/compiler_specific.h" #include "partition_alloc/partition_alloc_base/process/process_handle.h" #include "partition_alloc/partition_alloc_base/threading/platform_thread.h" #if (PA_BUILDFLAG(IS_LINUX) || PA_BUILDFLAG(IS_CHROMEOS)) && defined(__GLIBC__) extern "C" void* __libc_stack_end; #endif namespace partition_alloc::internal::base::debug { namespace { #if PA_BUILDFLAG(CAN_UNWIND_WITH_FRAME_POINTERS) #if defined(__arm__) && defined(__GNUC__) && !defined(__clang__) // GCC and LLVM generate slightly different frames on ARM, see // https://llvm.org/bugs/show_bug.cgi?id=18505 - LLVM generates // x86-compatible frame, while GCC needs adjustment. constexpr size_t kStackFrameAdjustment = sizeof(uintptr_t); #else constexpr size_t kStackFrameAdjustment = …; #endif // On Arm-v8.3+ systems with pointer authentication codes (PAC), signature bits // are set in the top bits of the pointer, which confuses test assertions. // Because the signature size can vary based on the system configuration, use // the xpaclri instruction to remove the signature. static uintptr_t StripPointerAuthenticationBits(uintptr_t ptr) { … } uintptr_t GetNextStackFrame(uintptr_t fp) { … } uintptr_t GetStackFramePC(uintptr_t fp) { … } bool IsStackFrameValid(uintptr_t fp, uintptr_t prev_fp, uintptr_t stack_end) { … } // ScanStackForNextFrame() scans the stack for a valid frame to allow unwinding // past system libraries. Only supported on Linux where system libraries are // usually in the middle of the trace: // // TraceStackFramePointers // <more frames from Chrome> // base::WorkSourceDispatch <-- unwinding stops (next frame is invalid), // g_main_context_dispatch ScanStackForNextFrame() is called // <more frames from glib> // g_main_context_iteration // base::MessagePumpGlib::Run <-- ScanStackForNextFrame() finds valid frame, // base::RunLoop::Run unwinding resumes // <more frames from Chrome> // __libc_start_main // // ScanStackForNextFrame() returns 0 if it couldn't find a valid frame // (or if stack scanning is not supported on the current platform). uintptr_t ScanStackForNextFrame(uintptr_t fp, uintptr_t stack_end) { … } #endif // PA_BUILDFLAG(CAN_UNWIND_WITH_FRAME_POINTERS) } // namespace #if PA_BUILDFLAG(CAN_UNWIND_WITH_FRAME_POINTERS) // We force this function to be inlined into its callers (e.g. // TraceStackFramePointers()) in all build modes so we don't have to worry about // conditionally skipping a frame based on potential inlining or tail calls. __attribute__((always_inline)) size_t TraceStackFramePointersInternal( uintptr_t fp, uintptr_t stack_end, size_t max_depth, size_t skip_initial, bool enable_scanning, const void** out_trace) { … } PA_NOINLINE size_t TraceStackFramePointers(const void** out_trace, size_t max_depth, size_t skip_initial, bool enable_scanning) { … } #endif // BUILDFLAG(CAN_UNWIND_WITH_FRAME_POINTERS) #if PA_BUILDFLAG(CAN_UNWIND_WITH_FRAME_POINTERS) uintptr_t GetStackEnd() { … } #endif // BUILDFLAG(CAN_UNWIND_WITH_FRAME_POINTERS) } // namespace partition_alloc::internal::base::debug