stacktrace_aarch64-inl.inc 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. #ifndef ABSL_DEBUGGING_INTERNAL_STACKTRACE_AARCH64_INL_H_
  2. #define ABSL_DEBUGGING_INTERNAL_STACKTRACE_AARCH64_INL_H_
  3. // Generate stack tracer for aarch64
  4. #if defined(__linux__)
  5. #include <sys/mman.h>
  6. #include <ucontext.h>
  7. #include <unistd.h>
  8. #endif
  9. #include <atomic>
  10. #include <cassert>
  11. #include <cstdint>
  12. #include <iostream>
  13. #include "absl/base/attributes.h"
  14. #include "absl/debugging/internal/address_is_readable.h"
  15. #include "absl/debugging/internal/vdso_support.h" // a no-op on non-elf or non-glibc systems
  16. #include "absl/debugging/stacktrace.h"
  17. static const uintptr_t kUnknownFrameSize = 0;
  18. #if defined(__linux__)
  19. // Returns the address of the VDSO __kernel_rt_sigreturn function, if present.
  20. static const unsigned char* GetKernelRtSigreturnAddress() {
  21. constexpr uintptr_t kImpossibleAddress = 1;
  22. ABSL_CONST_INIT static std::atomic<uintptr_t> memoized{kImpossibleAddress};
  23. uintptr_t address = memoized.load(std::memory_order_relaxed);
  24. if (address != kImpossibleAddress) {
  25. return reinterpret_cast<const unsigned char*>(address);
  26. }
  27. address = reinterpret_cast<uintptr_t>(nullptr);
  28. #ifdef ABSL_HAVE_VDSO_SUPPORT
  29. absl::debugging_internal::VDSOSupport vdso;
  30. if (vdso.IsPresent()) {
  31. absl::debugging_internal::VDSOSupport::SymbolInfo symbol_info;
  32. auto lookup = [&](int type) {
  33. return vdso.LookupSymbol("__kernel_rt_sigreturn", "LINUX_2.6.39", type,
  34. &symbol_info);
  35. };
  36. if ((!lookup(STT_FUNC) && !lookup(STT_NOTYPE)) ||
  37. symbol_info.address == nullptr) {
  38. // Unexpected: VDSO is present, yet the expected symbol is missing
  39. // or null.
  40. assert(false && "VDSO is present, but doesn't have expected symbol");
  41. } else {
  42. if (reinterpret_cast<uintptr_t>(symbol_info.address) !=
  43. kImpossibleAddress) {
  44. address = reinterpret_cast<uintptr_t>(symbol_info.address);
  45. } else {
  46. assert(false && "VDSO returned invalid address");
  47. }
  48. }
  49. }
  50. #endif
  51. memoized.store(address, std::memory_order_relaxed);
  52. return reinterpret_cast<const unsigned char*>(address);
  53. }
  54. #endif // __linux__
  55. // Compute the size of a stack frame in [low..high). We assume that
  56. // low < high. Return size of kUnknownFrameSize.
  57. template<typename T>
  58. static inline uintptr_t ComputeStackFrameSize(const T* low,
  59. const T* high) {
  60. const char* low_char_ptr = reinterpret_cast<const char *>(low);
  61. const char* high_char_ptr = reinterpret_cast<const char *>(high);
  62. return low < high ? high_char_ptr - low_char_ptr : kUnknownFrameSize;
  63. }
  64. // Given a pointer to a stack frame, locate and return the calling
  65. // stackframe, or return null if no stackframe can be found. Perform sanity
  66. // checks (the strictness of which is controlled by the boolean parameter
  67. // "STRICT_UNWINDING") to reduce the chance that a bad pointer is returned.
  68. template<bool STRICT_UNWINDING, bool WITH_CONTEXT>
  69. ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS // May read random elements from stack.
  70. ABSL_ATTRIBUTE_NO_SANITIZE_MEMORY // May read random elements from stack.
  71. static void **NextStackFrame(void **old_frame_pointer, const void *uc) {
  72. void **new_frame_pointer = reinterpret_cast<void**>(*old_frame_pointer);
  73. bool check_frame_size = true;
  74. #if defined(__linux__)
  75. if (WITH_CONTEXT && uc != nullptr) {
  76. // Check to see if next frame's return address is __kernel_rt_sigreturn.
  77. if (old_frame_pointer[1] == GetKernelRtSigreturnAddress()) {
  78. const ucontext_t *ucv = static_cast<const ucontext_t *>(uc);
  79. // old_frame_pointer[0] is not suitable for unwinding, look at
  80. // ucontext to discover frame pointer before signal.
  81. void **const pre_signal_frame_pointer =
  82. reinterpret_cast<void **>(ucv->uc_mcontext.regs[29]);
  83. // Check that alleged frame pointer is actually readable. This is to
  84. // prevent "double fault" in case we hit the first fault due to e.g.
  85. // stack corruption.
  86. if (!absl::debugging_internal::AddressIsReadable(
  87. pre_signal_frame_pointer))
  88. return nullptr;
  89. // Alleged frame pointer is readable, use it for further unwinding.
  90. new_frame_pointer = pre_signal_frame_pointer;
  91. // Skip frame size check if we return from a signal. We may be using a
  92. // an alternate stack for signals.
  93. check_frame_size = false;
  94. }
  95. }
  96. #endif
  97. // aarch64 ABI requires stack pointer to be 16-byte-aligned.
  98. if ((reinterpret_cast<uintptr_t>(new_frame_pointer) & 15) != 0)
  99. return nullptr;
  100. // Check frame size. In strict mode, we assume frames to be under
  101. // 100,000 bytes. In non-strict mode, we relax the limit to 1MB.
  102. if (check_frame_size) {
  103. const uintptr_t max_size = STRICT_UNWINDING ? 100000 : 1000000;
  104. const uintptr_t frame_size =
  105. ComputeStackFrameSize(old_frame_pointer, new_frame_pointer);
  106. if (frame_size == kUnknownFrameSize || frame_size > max_size)
  107. return nullptr;
  108. }
  109. return new_frame_pointer;
  110. }
  111. template <bool IS_STACK_FRAMES, bool IS_WITH_CONTEXT>
  112. ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS // May read random elements from stack.
  113. ABSL_ATTRIBUTE_NO_SANITIZE_MEMORY // May read random elements from stack.
  114. static int UnwindImpl(void** result, int* sizes, int max_depth, int skip_count,
  115. const void *ucp, int *min_dropped_frames) {
  116. #ifdef __GNUC__
  117. void **frame_pointer = reinterpret_cast<void**>(__builtin_frame_address(0));
  118. #else
  119. # error reading stack point not yet supported on this platform.
  120. #endif
  121. skip_count++; // Skip the frame for this function.
  122. int n = 0;
  123. // The frame pointer points to low address of a frame. The first 64-bit
  124. // word of a frame points to the next frame up the call chain, which normally
  125. // is just after the high address of the current frame. The second word of
  126. // a frame contains return adress of to the caller. To find a pc value
  127. // associated with the current frame, we need to go down a level in the call
  128. // chain. So we remember return the address of the last frame seen. This
  129. // does not work for the first stack frame, which belongs to UnwindImp() but
  130. // we skip the frame for UnwindImp() anyway.
  131. void* prev_return_address = nullptr;
  132. while (frame_pointer && n < max_depth) {
  133. // The absl::GetStackFrames routine is called when we are in some
  134. // informational context (the failure signal handler for example).
  135. // Use the non-strict unwinding rules to produce a stack trace
  136. // that is as complete as possible (even if it contains a few bogus
  137. // entries in some rare cases).
  138. void **next_frame_pointer =
  139. NextStackFrame<!IS_STACK_FRAMES, IS_WITH_CONTEXT>(frame_pointer, ucp);
  140. if (skip_count > 0) {
  141. skip_count--;
  142. } else {
  143. result[n] = prev_return_address;
  144. if (IS_STACK_FRAMES) {
  145. sizes[n] = ComputeStackFrameSize(frame_pointer, next_frame_pointer);
  146. }
  147. n++;
  148. }
  149. prev_return_address = frame_pointer[1];
  150. frame_pointer = next_frame_pointer;
  151. }
  152. if (min_dropped_frames != nullptr) {
  153. // Implementation detail: we clamp the max of frames we are willing to
  154. // count, so as not to spend too much time in the loop below.
  155. const int kMaxUnwind = 200;
  156. int j = 0;
  157. for (; frame_pointer != nullptr && j < kMaxUnwind; j++) {
  158. frame_pointer =
  159. NextStackFrame<!IS_STACK_FRAMES, IS_WITH_CONTEXT>(frame_pointer, ucp);
  160. }
  161. *min_dropped_frames = j;
  162. }
  163. return n;
  164. }
  165. namespace absl {
  166. ABSL_NAMESPACE_BEGIN
  167. namespace debugging_internal {
  168. bool StackTraceWorksForTest() {
  169. return true;
  170. }
  171. } // namespace debugging_internal
  172. ABSL_NAMESPACE_END
  173. } // namespace absl
  174. #endif // ABSL_DEBUGGING_INTERNAL_STACKTRACE_AARCH64_INL_H_