stacktrace.cc
Go to the documentation of this file.
00001 // Copyright 2017 The Abseil Authors.
00002 //
00003 // Licensed under the Apache License, Version 2.0 (the "License");
00004 // you may not use this file except in compliance with the License.
00005 // You may obtain a copy of the License at
00006 //
00007 //      https://www.apache.org/licenses/LICENSE-2.0
00008 //
00009 // Unless required by applicable law or agreed to in writing, software
00010 // distributed under the License is distributed on an "AS IS" BASIS,
00011 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00012 // See the License for the specific language governing permissions and
00013 // limitations under the License.
00014 
00015 // Produce stack trace.
00016 //
00017 // There are three different ways we can try to get the stack trace:
00018 //
00019 // 1) Our hand-coded stack-unwinder.  This depends on a certain stack
00020 //    layout, which is used by gcc (and those systems using a
00021 //    gcc-compatible ABI) on x86 systems, at least since gcc 2.95.
00022 //    It uses the frame pointer to do its work.
00023 //
00024 // 2) The libunwind library.  This is still in development, and as a
00025 //    separate library adds a new dependency, but doesn't need a frame
00026 //    pointer.  It also doesn't call malloc.
00027 //
00028 // 3) The gdb unwinder -- also the one used by the c++ exception code.
00029 //    It's obviously well-tested, but has a fatal flaw: it can call
00030 //    malloc() from the unwinder.  This is a problem because we're
00031 //    trying to use the unwinder to instrument malloc().
00032 //
00033 // Note: if you add a new implementation here, make sure it works
00034 // correctly when absl::GetStackTrace() is called with max_depth == 0.
00035 // Some code may do that.
00036 
00037 #include "absl/debugging/stacktrace.h"
00038 
00039 #include <atomic>
00040 
00041 #include "absl/base/attributes.h"
00042 #include "absl/base/port.h"
00043 #include "absl/debugging/internal/stacktrace_config.h"
00044 
00045 #if defined(ABSL_STACKTRACE_INL_HEADER)
00046 #include ABSL_STACKTRACE_INL_HEADER
00047 #else
00048 # error Cannot calculate stack trace: will need to write for your environment
00049 
00050 # include "absl/debugging/internal/stacktrace_aarch64-inl.inc"
00051 # include "absl/debugging/internal/stacktrace_arm-inl.inc"
00052 # include "absl/debugging/internal/stacktrace_generic-inl.inc"
00053 # include "absl/debugging/internal/stacktrace_powerpc-inl.inc"
00054 # include "absl/debugging/internal/stacktrace_unimplemented-inl.inc"
00055 # include "absl/debugging/internal/stacktrace_win32-inl.inc"
00056 # include "absl/debugging/internal/stacktrace_x86-inl.inc"
00057 #endif
00058 
00059 namespace absl {
00060 namespace {
00061 
00062 typedef int (*Unwinder)(void**, int*, int, int, const void*, int*);
00063 std::atomic<Unwinder> custom;
00064 
00065 template <bool IS_STACK_FRAMES, bool IS_WITH_CONTEXT>
00066 ABSL_ATTRIBUTE_ALWAYS_INLINE inline int Unwind(void** result, int* sizes,
00067                                                int max_depth, int skip_count,
00068                                                const void* uc,
00069                                                int* min_dropped_frames) {
00070   Unwinder f = &UnwindImpl<IS_STACK_FRAMES, IS_WITH_CONTEXT>;
00071   Unwinder g = custom.load(std::memory_order_acquire);
00072   if (g != nullptr) f = g;
00073 
00074   // Add 1 to skip count for the unwinder function itself
00075   int size = (*f)(result, sizes, max_depth, skip_count + 1, uc,
00076                   min_dropped_frames);
00077   // To disable tail call to (*f)(...)
00078   ABSL_BLOCK_TAIL_CALL_OPTIMIZATION();
00079   return size;
00080 }
00081 
00082 }  // anonymous namespace
00083 
00084 ABSL_ATTRIBUTE_NOINLINE ABSL_ATTRIBUTE_NO_TAIL_CALL int GetStackFrames(
00085     void** result, int* sizes, int max_depth, int skip_count) {
00086   return Unwind<true, false>(result, sizes, max_depth, skip_count, nullptr,
00087                              nullptr);
00088 }
00089 
00090 ABSL_ATTRIBUTE_NOINLINE ABSL_ATTRIBUTE_NO_TAIL_CALL int
00091 GetStackFramesWithContext(void** result, int* sizes, int max_depth,
00092                           int skip_count, const void* uc,
00093                           int* min_dropped_frames) {
00094   return Unwind<true, true>(result, sizes, max_depth, skip_count, uc,
00095                             min_dropped_frames);
00096 }
00097 
00098 ABSL_ATTRIBUTE_NOINLINE ABSL_ATTRIBUTE_NO_TAIL_CALL int GetStackTrace(
00099     void** result, int max_depth, int skip_count) {
00100   return Unwind<false, false>(result, nullptr, max_depth, skip_count, nullptr,
00101                               nullptr);
00102 }
00103 
00104 ABSL_ATTRIBUTE_NOINLINE ABSL_ATTRIBUTE_NO_TAIL_CALL int
00105 GetStackTraceWithContext(void** result, int max_depth, int skip_count,
00106                          const void* uc, int* min_dropped_frames) {
00107   return Unwind<false, true>(result, nullptr, max_depth, skip_count, uc,
00108                              min_dropped_frames);
00109 }
00110 
00111 void SetStackUnwinder(Unwinder w) {
00112   custom.store(w, std::memory_order_release);
00113 }
00114 
00115 int DefaultStackUnwinder(void** pcs, int* sizes, int depth, int skip,
00116                          const void* uc, int* min_dropped_frames) {
00117   skip++;  // For this function
00118   Unwinder f = nullptr;
00119   if (sizes == nullptr) {
00120     if (uc == nullptr) {
00121       f = &UnwindImpl<false, false>;
00122     } else {
00123       f = &UnwindImpl<false, true>;
00124     }
00125   } else {
00126     if (uc == nullptr) {
00127       f = &UnwindImpl<true, false>;
00128     } else {
00129       f = &UnwindImpl<true, true>;
00130     }
00131   }
00132   volatile int x = 0;
00133   int n = (*f)(pcs, sizes, depth, skip, uc, min_dropped_frames);
00134   x = 1; (void) x;  // To disable tail call to (*f)(...)
00135   return n;
00136 }
00137 
00138 }  // namespace absl


abseil_cpp
Author(s):
autogenerated on Wed Jun 19 2019 19:42:15