stacktrace.cc 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. // Copyright 2017 The Abseil Authors.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // https://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. // Produce stack trace.
  15. //
  16. // There are three different ways we can try to get the stack trace:
  17. //
  18. // 1) Our hand-coded stack-unwinder. This depends on a certain stack
  19. // layout, which is used by gcc (and those systems using a
  20. // gcc-compatible ABI) on x86 systems, at least since gcc 2.95.
  21. // It uses the frame pointer to do its work.
  22. //
  23. // 2) The libunwind library. This is still in development, and as a
  24. // separate library adds a new dependency, but doesn't need a frame
  25. // pointer. It also doesn't call malloc.
  26. //
  27. // 3) The gdb unwinder -- also the one used by the c++ exception code.
  28. // It's obviously well-tested, but has a fatal flaw: it can call
  29. // malloc() from the unwinder. This is a problem because we're
  30. // trying to use the unwinder to instrument malloc().
  31. //
  32. // Note: if you add a new implementation here, make sure it works
  33. // correctly when absl::GetStackTrace() is called with max_depth == 0.
  34. // Some code may do that.
  35. #include "absl/debugging/stacktrace.h"
  36. #include <atomic>
  37. #include "absl/base/attributes.h"
  38. #include "absl/base/port.h"
  39. #include "absl/debugging/internal/stacktrace_config.h"
  40. #if defined(ABSL_STACKTRACE_INL_HEADER)
  41. #include ABSL_STACKTRACE_INL_HEADER
  42. #else
  43. # error Cannot calculate stack trace: will need to write for your environment
  44. # include "absl/debugging/internal/stacktrace_aarch64-inl.inc"
  45. # include "absl/debugging/internal/stacktrace_arm-inl.inc"
  46. # include "absl/debugging/internal/stacktrace_emscripten-inl.inc"
  47. # include "absl/debugging/internal/stacktrace_generic-inl.inc"
  48. # include "absl/debugging/internal/stacktrace_powerpc-inl.inc"
  49. # include "absl/debugging/internal/stacktrace_riscv-inl.inc"
  50. # include "absl/debugging/internal/stacktrace_unimplemented-inl.inc"
  51. # include "absl/debugging/internal/stacktrace_win32-inl.inc"
  52. # include "absl/debugging/internal/stacktrace_x86-inl.inc"
  53. #endif
  54. namespace absl {
  55. ABSL_NAMESPACE_BEGIN
  56. namespace {
  57. typedef int (*Unwinder)(void**, int*, int, int, const void*, int*);
  58. std::atomic<Unwinder> custom;
  59. template <bool IS_STACK_FRAMES, bool IS_WITH_CONTEXT>
  60. ABSL_ATTRIBUTE_ALWAYS_INLINE inline int Unwind(void** result, int* sizes,
  61. int max_depth, int skip_count,
  62. const void* uc,
  63. int* min_dropped_frames) {
  64. Unwinder f = &UnwindImpl<IS_STACK_FRAMES, IS_WITH_CONTEXT>;
  65. Unwinder g = custom.load(std::memory_order_acquire);
  66. if (g != nullptr) f = g;
  67. // Add 1 to skip count for the unwinder function itself
  68. int size = (*f)(result, sizes, max_depth, skip_count + 1, uc,
  69. min_dropped_frames);
  70. // To disable tail call to (*f)(...)
  71. ABSL_BLOCK_TAIL_CALL_OPTIMIZATION();
  72. return size;
  73. }
  74. } // anonymous namespace
  75. ABSL_ATTRIBUTE_NOINLINE ABSL_ATTRIBUTE_NO_TAIL_CALL int GetStackFrames(
  76. void** result, int* sizes, int max_depth, int skip_count) {
  77. return Unwind<true, false>(result, sizes, max_depth, skip_count, nullptr,
  78. nullptr);
  79. }
  80. ABSL_ATTRIBUTE_NOINLINE ABSL_ATTRIBUTE_NO_TAIL_CALL int
  81. GetStackFramesWithContext(void** result, int* sizes, int max_depth,
  82. int skip_count, const void* uc,
  83. int* min_dropped_frames) {
  84. return Unwind<true, true>(result, sizes, max_depth, skip_count, uc,
  85. min_dropped_frames);
  86. }
  87. ABSL_ATTRIBUTE_NOINLINE ABSL_ATTRIBUTE_NO_TAIL_CALL int GetStackTrace(
  88. void** result, int max_depth, int skip_count) {
  89. return Unwind<false, false>(result, nullptr, max_depth, skip_count, nullptr,
  90. nullptr);
  91. }
  92. ABSL_ATTRIBUTE_NOINLINE ABSL_ATTRIBUTE_NO_TAIL_CALL int
  93. GetStackTraceWithContext(void** result, int max_depth, int skip_count,
  94. const void* uc, int* min_dropped_frames) {
  95. return Unwind<false, true>(result, nullptr, max_depth, skip_count, uc,
  96. min_dropped_frames);
  97. }
  98. void SetStackUnwinder(Unwinder w) {
  99. custom.store(w, std::memory_order_release);
  100. }
  101. int DefaultStackUnwinder(void** pcs, int* sizes, int depth, int skip,
  102. const void* uc, int* min_dropped_frames) {
  103. skip++; // For this function
  104. Unwinder f = nullptr;
  105. if (sizes == nullptr) {
  106. if (uc == nullptr) {
  107. f = &UnwindImpl<false, false>;
  108. } else {
  109. f = &UnwindImpl<false, true>;
  110. }
  111. } else {
  112. if (uc == nullptr) {
  113. f = &UnwindImpl<true, false>;
  114. } else {
  115. f = &UnwindImpl<true, true>;
  116. }
  117. }
  118. volatile int x = 0;
  119. int n = (*f)(pcs, sizes, depth, skip, uc, min_dropped_frames);
  120. x = 1; (void) x; // To disable tail call to (*f)(...)
  121. return n;
  122. }
  123. ABSL_NAMESPACE_END
  124. } // namespace absl