123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142 |
- // Copyright 2017 The Abseil Authors.
- //
- // Licensed under the Apache License, Version 2.0 (the "License");
- // you may not use this file except in compliance with the License.
- // You may obtain a copy of the License at
- //
- // https://www.apache.org/licenses/LICENSE-2.0
- //
- // Unless required by applicable law or agreed to in writing, software
- // distributed under the License is distributed on an "AS IS" BASIS,
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- // See the License for the specific language governing permissions and
- // limitations under the License.
- // Produce stack trace.
- //
- // There are three different ways we can try to get the stack trace:
- //
- // 1) Our hand-coded stack-unwinder. This depends on a certain stack
- // layout, which is used by gcc (and those systems using a
- // gcc-compatible ABI) on x86 systems, at least since gcc 2.95.
- // It uses the frame pointer to do its work.
- //
- // 2) The libunwind library. This is still in development, and as a
- // separate library adds a new dependency, but doesn't need a frame
- // pointer. It also doesn't call malloc.
- //
- // 3) The gdb unwinder -- also the one used by the c++ exception code.
- // It's obviously well-tested, but has a fatal flaw: it can call
- // malloc() from the unwinder. This is a problem because we're
- // trying to use the unwinder to instrument malloc().
- //
- // Note: if you add a new implementation here, make sure it works
- // correctly when absl::GetStackTrace() is called with max_depth == 0.
- // Some code may do that.
- #include "absl/debugging/stacktrace.h"
- #include <atomic>
- #include "absl/base/attributes.h"
- #include "absl/base/port.h"
- #include "absl/debugging/internal/stacktrace_config.h"
- #if defined(ABSL_STACKTRACE_INL_HEADER)
- #include ABSL_STACKTRACE_INL_HEADER
- #else
- # error Cannot calculate stack trace: will need to write for your environment
- # include "absl/debugging/internal/stacktrace_aarch64-inl.inc"
- # include "absl/debugging/internal/stacktrace_arm-inl.inc"
- # include "absl/debugging/internal/stacktrace_emscripten-inl.inc"
- # include "absl/debugging/internal/stacktrace_generic-inl.inc"
- # include "absl/debugging/internal/stacktrace_powerpc-inl.inc"
- # include "absl/debugging/internal/stacktrace_riscv-inl.inc"
- # include "absl/debugging/internal/stacktrace_unimplemented-inl.inc"
- # include "absl/debugging/internal/stacktrace_win32-inl.inc"
- # include "absl/debugging/internal/stacktrace_x86-inl.inc"
- #endif
- namespace absl {
- ABSL_NAMESPACE_BEGIN
- namespace {
- typedef int (*Unwinder)(void**, int*, int, int, const void*, int*);
- std::atomic<Unwinder> custom;
- template <bool IS_STACK_FRAMES, bool IS_WITH_CONTEXT>
- ABSL_ATTRIBUTE_ALWAYS_INLINE inline int Unwind(void** result, int* sizes,
- int max_depth, int skip_count,
- const void* uc,
- int* min_dropped_frames) {
- Unwinder f = &UnwindImpl<IS_STACK_FRAMES, IS_WITH_CONTEXT>;
- Unwinder g = custom.load(std::memory_order_acquire);
- if (g != nullptr) f = g;
- // Add 1 to skip count for the unwinder function itself
- int size = (*f)(result, sizes, max_depth, skip_count + 1, uc,
- min_dropped_frames);
- // To disable tail call to (*f)(...)
- ABSL_BLOCK_TAIL_CALL_OPTIMIZATION();
- return size;
- }
- } // anonymous namespace
- ABSL_ATTRIBUTE_NOINLINE ABSL_ATTRIBUTE_NO_TAIL_CALL int GetStackFrames(
- void** result, int* sizes, int max_depth, int skip_count) {
- return Unwind<true, false>(result, sizes, max_depth, skip_count, nullptr,
- nullptr);
- }
- ABSL_ATTRIBUTE_NOINLINE ABSL_ATTRIBUTE_NO_TAIL_CALL int
- GetStackFramesWithContext(void** result, int* sizes, int max_depth,
- int skip_count, const void* uc,
- int* min_dropped_frames) {
- return Unwind<true, true>(result, sizes, max_depth, skip_count, uc,
- min_dropped_frames);
- }
- ABSL_ATTRIBUTE_NOINLINE ABSL_ATTRIBUTE_NO_TAIL_CALL int GetStackTrace(
- void** result, int max_depth, int skip_count) {
- return Unwind<false, false>(result, nullptr, max_depth, skip_count, nullptr,
- nullptr);
- }
- ABSL_ATTRIBUTE_NOINLINE ABSL_ATTRIBUTE_NO_TAIL_CALL int
- GetStackTraceWithContext(void** result, int max_depth, int skip_count,
- const void* uc, int* min_dropped_frames) {
- return Unwind<false, true>(result, nullptr, max_depth, skip_count, uc,
- min_dropped_frames);
- }
- void SetStackUnwinder(Unwinder w) {
- custom.store(w, std::memory_order_release);
- }
- int DefaultStackUnwinder(void** pcs, int* sizes, int depth, int skip,
- const void* uc, int* min_dropped_frames) {
- skip++; // For this function
- Unwinder f = nullptr;
- if (sizes == nullptr) {
- if (uc == nullptr) {
- f = &UnwindImpl<false, false>;
- } else {
- f = &UnwindImpl<false, true>;
- }
- } else {
- if (uc == nullptr) {
- f = &UnwindImpl<true, false>;
- } else {
- f = &UnwindImpl<true, true>;
- }
- }
- volatile int x = 0;
- int n = (*f)(pcs, sizes, depth, skip, uc, min_dropped_frames);
- x = 1; (void) x; // To disable tail call to (*f)(...)
- return n;
- }
- ABSL_NAMESPACE_END
- } // namespace absl
|