chromium/base/debug/stack_trace.cc

// 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 "base/debug/stack_trace.h"

#include <string.h>

#include <algorithm>
#include <sstream>
#include <utility>

#include "base/check_op.h"
#include "base/debug/debugging_buildflags.h"
#include "build/build_config.h"
#include "build/config/compiler/compiler_buildflags.h"

#if BUILDFLAG(CAN_UNWIND_WITH_FRAME_POINTERS)
#include <optional>

#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID)
#include <pthread.h>

#include "base/process/process_handle.h"
#include "base/threading/platform_thread.h"
#endif

#if BUILDFLAG(IS_APPLE)
#include <pthread.h>
#endif

#if (BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)) && defined(__GLIBC__)
extern "C" void* __libc_stack_end;
#endif

#endif  // BUILDFLAG(CAN_UNWIND_WITH_FRAME_POINTERS)

namespace base {
namespace debug {

namespace {

#if 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) {}

// Links stack frame |fp| to |parent_fp|, so that during stack unwinding
// TraceStackFramePointers() visits |parent_fp| after visiting |fp|.
// Both frame pointers must come from __builtin_frame_address().
// Returns previous stack frame |fp| was linked to.
void* LinkStackFrames(void* fpp, void* parent_fp) {}

#endif  // BUILDFLAG(CAN_UNWIND_WITH_FRAME_POINTERS)

// A message to be emitted in place of a symbolized stack trace. Ordinarily used
// in death test child processes to inform a developer that they may rerun a
// failing test with a switch to prevent the test launcher from suppressing
// stacks in such processes.
std::string* g_stack_trace_message =;

// True if an OverrideStackTraceOutputForTesting instance is alive to force
// or prevent generation of symbolized stack traces despite a suppression
// message having been set (or not).
OverrideStackTraceOutputForTesting::Mode g_override_suppression =;

}  // namespace

#if BUILDFLAG(CAN_UNWIND_WITH_FRAME_POINTERS)
uintptr_t GetStackEnd() {}
#endif  // BUILDFLAG(CAN_UNWIND_WITH_FRAME_POINTERS)

StackTrace::StackTrace() :{}

StackTrace::StackTrace(size_t count)
    :{}

StackTrace::StackTrace(span<const void* const> trace)
    :{}

// static
bool StackTrace::WillSymbolizeToStreamForTesting() {}

void StackTrace::Print() const {}

void StackTrace::PrintWithPrefix(cstring_view prefix_string) const {}

void StackTrace::OutputToStream(std::ostream* os) const {}

void StackTrace::OutputToStreamWithPrefix(std::ostream* os,
                                          cstring_view prefix_string) const {}

std::string StackTrace::ToString() const {}

std::string StackTrace::ToStringWithPrefix(cstring_view prefix_string) const {}

// static
void StackTrace::SuppressStackTracesWithMessageForTesting(std::string message) {}

// static
bool StackTrace::ShouldSuppressOutput() {}

std::ostream& operator<<(std::ostream& os, const StackTrace& s) {}

OverrideStackTraceOutputForTesting::OverrideStackTraceOutputForTesting(
    Mode mode) {}

OverrideStackTraceOutputForTesting::~OverrideStackTraceOutputForTesting() {}

#if BUILDFLAG(CAN_UNWIND_WITH_FRAME_POINTERS)

struct AddressRange {};

bool IsWithinRange(uintptr_t address, const AddressRange& range) {}

NOINLINE size_t TraceStackFramePointers(span<const void*> out_trace,
                                        size_t skip_initial,
                                        bool enable_scanning) {}

ScopedStackFrameLinker::ScopedStackFrameLinker(void* fp, void* parent_fp)
    :{}

ScopedStackFrameLinker::~ScopedStackFrameLinker() {}

#endif  // BUILDFLAG(CAN_UNWIND_WITH_FRAME_POINTERS)

}  // namespace debug
}  // namespace base