symbolizer_linux.cpp 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. #include "symbolizer.h"
  2. #include <contrib/libs/backtrace/backtrace.h>
  3. #include <util/generic/string.h>
  4. #include <util/generic/vector.h>
  5. #include <util/system/type_name.h>
  6. #include <util/system/execpath.h>
  7. #include <util/string/builder.h>
  8. #include <mutex>
  9. #include <numeric>
  10. #include <algorithm>
  11. #include <util/stream/mem.h>
  12. #ifdef __GNUC__
  13. #include <cxxabi.h>
  14. #endif
  15. namespace {
  16. const size_t MaxStrLen = 512;
  17. const size_t MaxDemangleLen = 1024 * 1024;
  18. char Buff[MaxDemangleLen];
  19. class TNoThrowingMemoryOutput : public TMemoryOutput {
  20. public:
  21. TNoThrowingMemoryOutput(void* c, size_t l) : TMemoryOutput(c, l) {}
  22. void Truncate() {
  23. *(Buf_ - 1) = '.';
  24. *(Buf_ - 2) = '.';
  25. *(Buf_ - 3) = '.';
  26. }
  27. void DoWrite(const void* buf, size_t len) override {
  28. bool truncated = Buf_ + len > End_;
  29. if (truncated) {
  30. len = std::min(len, (size_t)(End_ - Buf_));
  31. }
  32. memcpy(Buf_, buf, len);
  33. Buf_ += len;
  34. if (truncated) {
  35. Truncate();
  36. }
  37. }
  38. void DoWriteC(char c) override {
  39. if (Buf_ == End_) {
  40. Truncate();
  41. } else {
  42. *Buf_++ = c;
  43. }
  44. }
  45. };
  46. void HandleLibBacktraceError(void* data, const char* msg, int) {
  47. if (!data) {
  48. Cerr << msg;
  49. return;
  50. }
  51. TNoThrowingMemoryOutput out(data, MaxStrLen - 1);
  52. out << msg;
  53. }
  54. const char* Demangle(const char* name) {
  55. #ifndef __GNUC__
  56. return name;
  57. #else
  58. int status;
  59. size_t len = MaxDemangleLen - 1;
  60. const char* res = __cxxabiv1::__cxa_demangle(name, Buff, &len, &status);
  61. if (!res) {
  62. return name;
  63. }
  64. return res;
  65. #endif
  66. }
  67. int HandleLibBacktraceFrame(void* data, uintptr_t, const char* filename, int lineno, const char* function) {
  68. TNoThrowingMemoryOutput out(data, MaxStrLen - 1);
  69. const char* fileName = filename ? filename : "???";
  70. const char* functionName = function ? Demangle(function) : "???";
  71. out << functionName << " at " << fileName << ":" << lineno << ":0";
  72. return 0;
  73. }
  74. }
  75. namespace NYql {
  76. namespace NBacktrace {
  77. namespace {
  78. std::mutex Mutex;
  79. char* Result[Limit];
  80. size_t Order[Limit];
  81. char TmpBuffer[MaxStrLen * Limit]{};
  82. auto CreateState(const char* filename) {
  83. return backtrace_create_state(
  84. filename,
  85. 0,
  86. HandleLibBacktraceError,
  87. nullptr
  88. );
  89. }
  90. }
  91. void Symbolize(const TStackFrame* frames, size_t count, IOutputStream* out) {
  92. if (!count) {
  93. return;
  94. }
  95. memset(TmpBuffer, 0, sizeof(TmpBuffer));
  96. Result[0] = TmpBuffer;
  97. for (size_t i = 1; i < Limit; ++i) {
  98. Result[i] = Result[i - 1] + MaxStrLen;
  99. }
  100. const std::lock_guard lock{Mutex};
  101. std::iota(Order, Order + count, 0u);
  102. std::sort(Order, Order + count, [&frames](auto a, auto b) { return strcmp(frames[a].File, frames[b].File) < 0; });
  103. struct backtrace_state* state = nullptr;
  104. for (size_t i = 0; i < count; ++i) {
  105. if (!i || frames[Order[i - 1]].File != frames[Order[i]].File) {
  106. state = CreateState(frames[Order[i]].File);
  107. }
  108. if (!state) {
  109. Result[Order[i]] = nullptr; // File not found
  110. continue;
  111. }
  112. int status = backtrace_pcinfo(
  113. state,
  114. reinterpret_cast<uintptr_t>(frames[Order[i]].Address) - 1, // last byte of the call instruction
  115. HandleLibBacktraceFrame,
  116. HandleLibBacktraceError,
  117. reinterpret_cast<void*>(Result[Order[i]]));
  118. if (0 != status) {
  119. break;
  120. }
  121. }
  122. for (size_t i = 0; i < count; ++i) {
  123. if (Result[i]) {
  124. *out << Result[i] << "\n";
  125. } else {
  126. *out << "File `" << frames[i].File << "` not found\n";
  127. }
  128. }
  129. }
  130. }
  131. }