dynload_symbolizer.cpp 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. #include <library/cpp/yt/backtrace/backtrace.h>
  2. #include <library/cpp/yt/string/raw_formatter.h>
  3. #include <util/system/compiler.h>
  4. #include <dlfcn.h>
  5. #include <cxxabi.h>
  6. namespace NYT::NBacktrace {
  7. ////////////////////////////////////////////////////////////////////////////////
  8. namespace {
  9. int GetSymbolInfo(const void* pc, char* buffer, int length)
  10. {
  11. TBaseFormatter formatter(buffer, length);
  12. // See http://www.codesourcery.com/cxx-abi/abi.html#mangling
  13. // And, yes, dladdr() is not async signal safe. We can substitute it
  14. // with hand-written symbolization code from google-glog in case of any trouble.
  15. Dl_info info;
  16. if (!dladdr(pc, &info)) {
  17. return 0;
  18. }
  19. /*
  20. * typedef struct {
  21. * const char *dli_fname; // Pathname of shared object that
  22. * // contains address
  23. * void *dli_fbase; // Address at which shared object
  24. * // is loaded
  25. * const char *dli_sname; // Name of nearest symbol with address
  26. * // lower than addr
  27. * void *dli_saddr; // Exact address of symbol named
  28. * // in dli_sname
  29. * } Dl_info;
  30. *
  31. * If no symbol matching addr could be found, then dli_sname and dli_saddr are set to NULL.
  32. */
  33. if (info.dli_sname && info.dli_saddr) {
  34. formatter.AppendString("<");
  35. int demangleStatus = 0;
  36. if (info.dli_sname[0] == '_' && info.dli_sname[1] == 'Z') {
  37. // This is also not async signal safe.
  38. // But (ta-dah!) we can replace it with symbolization code from google-glob.
  39. char* demangledName = abi::__cxa_demangle(info.dli_sname, 0, 0, &demangleStatus);
  40. if (demangleStatus == 0) {
  41. formatter.AppendString(demangledName);
  42. } else {
  43. formatter.AppendString(info.dli_sname);
  44. }
  45. free(demangledName);
  46. } else {
  47. formatter.AppendString(info.dli_sname);
  48. }
  49. formatter.AppendString("+");
  50. formatter.AppendNumber((char*)pc - (char*)info.dli_saddr);
  51. formatter.AppendString(">");
  52. formatter.AppendString(" ");
  53. }
  54. if (info.dli_fname && info.dli_fbase) {
  55. formatter.AppendString("(");
  56. formatter.AppendString(info.dli_fname);
  57. formatter.AppendString("+");
  58. formatter.AppendNumber((char*)pc - (char*)info.dli_fbase);
  59. formatter.AppendString(")");
  60. }
  61. return formatter.GetBytesWritten();
  62. }
  63. void DumpStackFrameInfo(TBaseFormatter* formatter, const void* pc)
  64. {
  65. formatter->AppendString("@ ");
  66. const int width = (sizeof(void*) == 8 ? 12 : 8) + 2;
  67. // +2 for "0x"; 12 for x86_64 because higher bits are always zeroed.
  68. formatter->AppendNumberAsHexWithPadding(reinterpret_cast<uintptr_t>(pc), width);
  69. formatter->AppendString(" ");
  70. // Get the symbol from the previous address of PC,
  71. // because PC may be in the next function.
  72. formatter->Advance(GetSymbolInfo(
  73. reinterpret_cast<const char*>(pc) - 1,
  74. formatter->GetCursor(),
  75. formatter->GetBytesRemaining()));
  76. if (formatter->GetBytesRemaining() == 0) {
  77. formatter->Revert(1);
  78. }
  79. formatter->AppendString("\n");
  80. }
  81. } // namespace
  82. Y_WEAK void SymbolizeBacktrace(
  83. TBacktrace backtrace,
  84. const std::function<void(TStringBuf)>& frameCallback)
  85. {
  86. for (int i = 0; i < std::ssize(backtrace); ++i) {
  87. TRawFormatter<1024> formatter;
  88. formatter.Reset();
  89. formatter.AppendNumber(i + 1, 10, 2);
  90. formatter.AppendString(". ");
  91. DumpStackFrameInfo(&formatter, backtrace[i]);
  92. frameCallback(formatter.GetBuffer());
  93. }
  94. }
  95. ////////////////////////////////////////////////////////////////////////////////
  96. } // namespace NYT::NBacktrace