backtrace.cpp 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. #include "backtrace.h"
  2. #include "backtrace_lib.h"
  3. #include "symbolizer.h"
  4. #include <library/cpp/deprecated/atomic/atomic.h>
  5. #include <library/cpp/malloc/api/malloc.h>
  6. #include <util/generic/string.h>
  7. #include <util/generic/xrange.h>
  8. #include <util/generic/yexception.h>
  9. #include <util/stream/format.h>
  10. #include <util/stream/output.h>
  11. #include <util/system/backtrace.h>
  12. #include <util/system/type_name.h>
  13. #include <util/system/execpath.h>
  14. #include <util/system/platform.h>
  15. #include <util/system/mlock.h>
  16. #ifdef _linux_
  17. #include <signal.h>
  18. #endif
  19. #include <functional>
  20. #include <vector>
  21. #include <sstream>
  22. #include <iostream>
  23. #ifndef _win_
  24. bool SetSignalHandler(int signo, void (*handler)(int)) {
  25. struct sigaction sa;
  26. memset(&sa, 0, sizeof(sa));
  27. sa.sa_flags = SA_RESETHAND;
  28. sa.sa_handler = handler;
  29. sigfillset(&sa.sa_mask);
  30. return sigaction(signo, &sa, nullptr) != -1;
  31. }
  32. namespace {
  33. #if defined(_linux_) && defined(_x86_64_)
  34. bool SetSignalAction(int signo, void (*handler)(int, siginfo_t*, void*)) {
  35. struct sigaction sa;
  36. memset(&sa, 0, sizeof(sa));
  37. sa.sa_flags = SA_RESETHAND | SA_SIGINFO;
  38. sa.sa_sigaction = (decltype(sa.sa_sigaction))handler;
  39. sigfillset(&sa.sa_mask);
  40. return sigaction(signo, &sa, nullptr) != -1;
  41. }
  42. #endif
  43. } // namespace
  44. #endif // _win_
  45. TAtomic BacktraceStarted = 0;
  46. void SetFatalSignalHandler(void (*handler)(int)) {
  47. Y_UNUSED(handler);
  48. #ifndef _win_
  49. for (int signo: {SIGSEGV, SIGILL, SIGABRT, SIGFPE}) {
  50. if (!SetSignalHandler(signo, handler)) {
  51. ythrow TSystemError() << "Cannot set handler for signal " << strsignal(signo);
  52. }
  53. }
  54. #endif
  55. }
  56. #if defined(_linux_) && defined(_x86_64_)
  57. void SetFatalSignalAction(void (*sigaction)(int, siginfo_t*, void*))
  58. {
  59. for (int signo: {SIGSEGV, SIGILL, SIGABRT, SIGFPE}) {
  60. if (!SetSignalAction(signo, sigaction)) {
  61. ythrow TSystemError() << "Cannot set sigaction for signal " << strsignal(signo);
  62. }
  63. }
  64. }
  65. #endif
  66. namespace {
  67. std::vector<std::function<void(int)>> Before, After;
  68. bool KikimrSymbolize = false;
  69. NYql::NBacktrace::TCollectedFrame Frames[NYql::NBacktrace::Limit];
  70. void CallCallbacks(decltype(Before)& where, int signum) {
  71. for (const auto &fn: where) {
  72. if (fn) {
  73. fn(signum);
  74. }
  75. }
  76. }
  77. void PrintFrames(IOutputStream* out, const NYql::NBacktrace::TCollectedFrame* frames, size_t cnt);
  78. void DoBacktrace(IOutputStream* out, void* data) {
  79. auto cnt = NYql::NBacktrace::CollectFrames(Frames, data);
  80. PrintFrames(out, Frames, cnt);
  81. }
  82. void DoBacktrace(IOutputStream* out, void** stack, size_t cnt) {
  83. Y_UNUSED(NYql::NBacktrace::CollectFrames(Frames, stack, cnt));
  84. PrintFrames(out, Frames, cnt);
  85. }
  86. void SignalHandler(int signum) {
  87. CallCallbacks(Before, signum);
  88. if (!NMalloc::IsAllocatorCorrupted) {
  89. if (!AtomicTryLock(&BacktraceStarted)) {
  90. return;
  91. }
  92. UnlockAllMemory();
  93. DoBacktrace(&Cerr, nullptr);
  94. }
  95. CallCallbacks(After, signum);
  96. raise(signum);
  97. }
  98. #if defined(_linux_) && defined(_x86_64_)
  99. void SignalAction(int signum, siginfo_t*, void* context) {
  100. Y_UNUSED(SignalHandler);
  101. CallCallbacks(Before, signum);
  102. if (!NMalloc::IsAllocatorCorrupted) {
  103. if (!AtomicTryLock(&BacktraceStarted)) {
  104. return;
  105. }
  106. UnlockAllMemory();
  107. DoBacktrace(&Cerr, context);
  108. }
  109. CallCallbacks(After, signum);
  110. raise(signum);
  111. }
  112. #endif
  113. }
  114. namespace NYql {
  115. namespace NBacktrace {
  116. THashMap<TString, TString> Mapping;
  117. void SetModulesMapping(const THashMap<TString, TString>& mapping) {
  118. Mapping = mapping;
  119. }
  120. void AddBeforeFatalCallback(const std::function<void(int)>& before) {
  121. Before.push_back(before);
  122. }
  123. void AddAfterFatalCallback(const std::function<void(int)>& after) {
  124. After.push_back(after);
  125. }
  126. void RegisterKikimrFatalActions() {
  127. #if defined(_linux_) && defined(_x86_64_)
  128. SetFatalSignalAction(SignalAction);
  129. #else
  130. SetFatalSignalHandler(SignalHandler);
  131. #endif
  132. }
  133. void EnableKikimrSymbolize() {
  134. KikimrSymbolize = true;
  135. }
  136. void KikimrBackTrace() {
  137. FormatBackTrace(&Cerr);
  138. }
  139. void KikimrBackTraceFormatImpl(IOutputStream* out) {
  140. KikimrSymbolize = true;
  141. UnlockAllMemory();
  142. DoBacktrace(out, nullptr);
  143. }
  144. void KikimrBacktraceFormatImpl(IOutputStream* out, void* const* stack, size_t stackSize) {
  145. KikimrSymbolize = true;
  146. DoBacktrace(out, (void**)stack, stackSize);
  147. }
  148. }
  149. }
  150. void EnableKikimrBacktraceFormat() {
  151. SetFormatBackTraceFn(NYql::NBacktrace::KikimrBacktraceFormatImpl);
  152. }
  153. namespace {
  154. NYql::NBacktrace::TStackFrame SFrames[NYql::NBacktrace::Limit];
  155. void PrintFrames(IOutputStream* out, const NYql::NBacktrace::TCollectedFrame* frames, size_t count) {
  156. auto& outp = *out;
  157. Y_UNUSED(SFrames);
  158. #if defined(_linux_) && defined(_x86_64_)
  159. if (KikimrSymbolize) {
  160. for (size_t i = 0; i < count; ++i) {
  161. SFrames[i] = NYql::NBacktrace::TStackFrame{frames[i].File, frames[i].Address};
  162. }
  163. NYql::NBacktrace::Symbolize(SFrames, count, out);
  164. return;
  165. }
  166. #endif
  167. outp << "StackFrames: " << count << "\n";
  168. for (size_t i = 0; i < count; ++i) {
  169. auto& frame = frames[i];
  170. auto fileName = frame.File;
  171. if (!strcmp(fileName, "/proc/self/exe")) {
  172. fileName = "EXE";
  173. }
  174. auto it = NYql::NBacktrace::Mapping.find(fileName);
  175. outp << "StackFrame: " << (it == NYql::NBacktrace::Mapping.end() ? fileName : it->second) << " " << frame.Address << " 0\n";
  176. }
  177. }
  178. }