backtrace.cpp 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306
  1. #include "demangle_impl.h"
  2. #include "platform.h"
  3. #include "backtrace.h"
  4. #include <util/stream/output.h>
  5. #include <util/stream/format.h>
  6. #include <util/generic/array_ref.h>
  7. #include <util/generic/string.h>
  8. #ifdef _win_
  9. #include "mutex.h"
  10. #ifndef OPTIONAL
  11. #define OPTIONAL
  12. #endif
  13. #include <dbghelp.h>
  14. #endif
  15. #if defined(_bionic_)
  16. // TODO
  17. #else
  18. #if !defined(HAVE_BACKTRACE) && defined(_cygwin_)
  19. #define CaptureStackBackTrace RtlCaptureStackBackTrace
  20. extern "C" __stdcall unsigned short CaptureStackBackTrace(unsigned long FramesToSkip, unsigned long FramesToCapture, void** BackTrace, unsigned long* BackTraceHash);
  21. #define USE_WIN_BACKTRACE
  22. #define HAVE_BACKTRACE
  23. #endif
  24. #if !defined(HAVE_BACKTRACE) && defined(__IOS__)
  25. #define USE_GLIBC_BACKTRACE
  26. #define HAVE_BACKTRACE
  27. #endif
  28. #if !defined(HAVE_BACKTRACE) && defined(__GNUC__)
  29. #define USE_GCC_BACKTRACE
  30. #define HAVE_BACKTRACE
  31. #endif
  32. #if !defined(HAVE_BACKTRACE) && defined(_win_)
  33. #define USE_WIN_BACKTRACE
  34. #define HAVE_BACKTRACE
  35. #endif
  36. #if !defined(HAVE_BACKTRACE) && defined(_glibc_)
  37. #define USE_GLIBC_BACKTRACE
  38. #define HAVE_BACKTRACE
  39. #endif
  40. #endif
  41. #if defined(USE_GLIBC_BACKTRACE)
  42. #include <execinfo.h>
  43. size_t BackTrace(void** p, size_t len) {
  44. return (size_t)backtrace(p, len);
  45. }
  46. #endif
  47. #if defined(USE_GCC_BACKTRACE)
  48. #include <cxxabi.h>
  49. #include <unwind.h>
  50. namespace {
  51. namespace NGCCBacktrace {
  52. struct TBackTraceContext {
  53. void** sym;
  54. size_t cnt;
  55. size_t size;
  56. };
  57. static _Unwind_Reason_Code Helper(struct _Unwind_Context* c, void* h) {
  58. TBackTraceContext* bt = (TBackTraceContext*)h;
  59. if (bt->cnt != 0) {
  60. bt->sym[bt->cnt - 1] = (void*)_Unwind_GetIP(c);
  61. }
  62. if (bt->cnt == bt->size) {
  63. return _URC_END_OF_STACK;
  64. }
  65. ++bt->cnt;
  66. return _URC_NO_REASON;
  67. }
  68. static inline size_t BackTrace(void** p, size_t len) {
  69. if (len >= 1) {
  70. TBackTraceContext bt = {p, 0, len};
  71. _Unwind_Backtrace(Helper, &bt);
  72. return bt.cnt - 1;
  73. }
  74. return 0;
  75. }
  76. } // namespace NGCCBacktrace
  77. } // namespace
  78. size_t BackTrace(void** p, size_t len) {
  79. return NGCCBacktrace::BackTrace(p, len);
  80. }
  81. #endif
  82. #if defined(USE_WIN_BACKTRACE)
  83. size_t BackTrace(void** p, size_t len) {
  84. return CaptureStackBackTrace(0, len, p, nullptr);
  85. }
  86. #endif
  87. #if !defined(HAVE_BACKTRACE)
  88. size_t BackTrace(void**, size_t) {
  89. return 0;
  90. }
  91. #endif
  92. #if defined(_unix_) && !defined(_cygwin_)
  93. #include <util/generic/strfcpy.h>
  94. #include <dlfcn.h>
  95. #if defined(_darwin_)
  96. #include <execinfo.h>
  97. #endif
  98. static inline const char* CopyTo(const char* from, char* buf, size_t len) {
  99. strfcpy(buf, from, len);
  100. return buf;
  101. }
  102. TResolvedSymbol ResolveSymbol(void* sym, char* buf, size_t len) {
  103. TResolvedSymbol ret = {
  104. "??",
  105. sym,
  106. };
  107. Dl_info dli;
  108. Zero(dli);
  109. if (dladdr(sym, &dli) && dli.dli_sname) {
  110. ret.Name = CopyTo(NPrivate::TCppDemangler().Demangle(dli.dli_sname), buf, len);
  111. ret.NearestSymbol = dli.dli_saddr;
  112. }
  113. return ret;
  114. }
  115. #elif defined(_win_)
  116. #include <util/generic/singleton.h>
  117. namespace {
  118. struct TWinSymbolResolverImpl {
  119. typedef BOOL(WINAPI* TSymInitializeFunc)(HANDLE, PCSTR, BOOL);
  120. typedef BOOL(WINAPI* TSymCleanupFunc)(HANDLE);
  121. typedef BOOL(WINAPI* TSymFromAddrFunc)(HANDLE, DWORD64, PDWORD64, PSYMBOL_INFO);
  122. TWinSymbolResolverImpl()
  123. : InitOk(FALSE)
  124. {
  125. Library = LoadLibraryA("Dbghelp.dll");
  126. if (!Library) {
  127. return;
  128. }
  129. SymInitializeFunc = (TSymInitializeFunc)GetProcAddress(Library, "SymInitialize");
  130. SymCleanupFunc = (TSymCleanupFunc)GetProcAddress(Library, "SymCleanup");
  131. SymFromAddrFunc = (TSymFromAddrFunc)GetProcAddress(Library, "SymFromAddr");
  132. if (SymInitializeFunc && SymCleanupFunc && SymFromAddrFunc) {
  133. InitOk = SymInitializeFunc(GetCurrentProcess(), nullptr, TRUE);
  134. }
  135. }
  136. ~TWinSymbolResolverImpl() {
  137. if (InitOk) {
  138. SymCleanupFunc(GetCurrentProcess());
  139. }
  140. if (Library) {
  141. FreeLibrary(Library);
  142. }
  143. }
  144. TResolvedSymbol Resolve(void* sym, char* buf, size_t len) {
  145. TGuard<TMutex> guard(Mutex);
  146. TResolvedSymbol ret = {
  147. "??",
  148. sym};
  149. if (!InitOk || (len <= 1 + sizeof(SYMBOL_INFO))) {
  150. return ret;
  151. }
  152. SYMBOL_INFO* symbol = (SYMBOL_INFO*)buf;
  153. Zero(*symbol);
  154. symbol->MaxNameLen = len - sizeof(SYMBOL_INFO) - 1;
  155. symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
  156. DWORD64 displacement = 0;
  157. BOOL res = SymFromAddrFunc(GetCurrentProcess(), (DWORD64)sym, &displacement, symbol);
  158. if (res) {
  159. ret.NearestSymbol = (void*)symbol->Address;
  160. ret.Name = symbol->Name;
  161. }
  162. return ret;
  163. }
  164. TMutex Mutex;
  165. HMODULE Library;
  166. TSymInitializeFunc SymInitializeFunc;
  167. TSymCleanupFunc SymCleanupFunc;
  168. TSymFromAddrFunc SymFromAddrFunc;
  169. BOOL InitOk;
  170. };
  171. } // namespace
  172. TResolvedSymbol ResolveSymbol(void* sym, char* buf, size_t len) {
  173. return Singleton<TWinSymbolResolverImpl>()->Resolve(sym, buf, len);
  174. }
  175. #else
  176. TResolvedSymbol ResolveSymbol(void* sym, char*, size_t) {
  177. TResolvedSymbol ret = {
  178. "??",
  179. sym,
  180. };
  181. return ret;
  182. }
  183. #endif
  184. void FormatBackTrace(IOutputStream* out, void* const* backtrace, size_t backtraceSize) {
  185. char tmpBuf[1024];
  186. for (size_t i = 0; i < backtraceSize; ++i) {
  187. TResolvedSymbol rs = ResolveSymbol(backtrace[i], tmpBuf, sizeof(tmpBuf));
  188. *out << rs.Name << "+" << ((ptrdiff_t)backtrace[i] - (ptrdiff_t)rs.NearestSymbol) << " (" << Hex((ptrdiff_t)backtrace[i], HF_ADDX) << ')' << '\n';
  189. }
  190. }
  191. TFormatBackTraceFn FormatBackTraceFn = FormatBackTrace;
  192. TFormatBackTraceFn SetFormatBackTraceFn(TFormatBackTraceFn f) {
  193. TFormatBackTraceFn prevFn = FormatBackTraceFn;
  194. FormatBackTraceFn = f;
  195. return prevFn;
  196. }
  197. void FormatBackTrace(IOutputStream* out) {
  198. void* array[300];
  199. const size_t s = BackTrace(array, Y_ARRAY_SIZE(array));
  200. FormatBackTraceFn(out, array, s);
  201. }
  202. TFormatBackTraceFn GetFormatBackTraceFn() {
  203. return FormatBackTraceFn;
  204. }
  205. void PrintBackTrace() {
  206. FormatBackTrace(&Cerr);
  207. }
  208. TBackTrace::TBackTrace()
  209. : Size(0)
  210. {
  211. }
  212. void TBackTrace::Capture() {
  213. Size = BackTrace(Data, CAPACITY);
  214. }
  215. void TBackTrace::PrintTo(IOutputStream& out) const {
  216. FormatBackTraceFn(&out, Data, Size);
  217. }
  218. TString TBackTrace::PrintToString() const {
  219. TStringStream ss;
  220. PrintTo(ss);
  221. return ss.Str();
  222. }
  223. size_t TBackTrace::size() const {
  224. return Size;
  225. }
  226. const void* const* TBackTrace::data() const {
  227. return Data;
  228. }
  229. TBackTrace::operator TBackTraceView() const {
  230. return TBackTraceView(Data, Size);
  231. }
  232. TBackTrace TBackTrace::FromCurrentException() {
  233. #ifdef _YNDX_LIBUNWIND_EXCEPTION_BACKTRACE_SIZE
  234. TBackTrace result;
  235. result.Size = __cxxabiv1::__cxa_collect_current_exception_backtrace(result.Data, CAPACITY);
  236. return result;
  237. #else
  238. return TBackTrace();
  239. #endif
  240. }