diff options
author | Devtools Arcadia <arcadia-devtools@yandex-team.ru> | 2022-02-07 18:08:42 +0300 |
---|---|---|
committer | Devtools Arcadia <arcadia-devtools@mous.vla.yp-c.yandex.net> | 2022-02-07 18:08:42 +0300 |
commit | 1110808a9d39d4b808aef724c861a2e1a38d2a69 (patch) | |
tree | e26c9fed0de5d9873cce7e00bc214573dc2195b7 /util/system/backtrace.cpp | |
download | ydb-1110808a9d39d4b808aef724c861a2e1a38d2a69.tar.gz |
intermediate changes
ref:cde9a383711a11544ce7e107a78147fb96cc4029
Diffstat (limited to 'util/system/backtrace.cpp')
-rw-r--r-- | util/system/backtrace.cpp | 307 |
1 files changed, 307 insertions, 0 deletions
diff --git a/util/system/backtrace.cpp b/util/system/backtrace.cpp new file mode 100644 index 0000000000..b77fe58fb1 --- /dev/null +++ b/util/system/backtrace.cpp @@ -0,0 +1,307 @@ +#include "dynlib.h" +#include "demangle_impl.h" +#include "platform.h" +#include "backtrace.h" + +#include <util/stream/output.h> +#include <util/stream/format.h> +#include <util/generic/array_ref.h> +#include <util/generic/string.h> + +#ifdef _win_ + #include "mutex.h" + + #ifndef OPTIONAL + #define OPTIONAL + #endif + #include <dbghelp.h> +#endif + +#if defined(_bionic_) +//TODO +#else + #if !defined(HAVE_BACKTRACE) && defined(_cygwin_) + #define CaptureStackBackTrace RtlCaptureStackBackTrace +extern "C" __stdcall unsigned short CaptureStackBackTrace(unsigned long FramesToSkip, unsigned long FramesToCapture, void** BackTrace, unsigned long* BackTraceHash); + + #define USE_WIN_BACKTRACE + #define HAVE_BACKTRACE + #endif + + #if !defined(HAVE_BACKTRACE) && defined(__IOS__) + #define USE_GLIBC_BACKTRACE + #define HAVE_BACKTRACE + #endif + + #if !defined(HAVE_BACKTRACE) && defined(__GNUC__) + #define USE_GCC_BACKTRACE + #define HAVE_BACKTRACE + #endif + + #if !defined(HAVE_BACKTRACE) && defined(_win_) + #define USE_WIN_BACKTRACE + #define HAVE_BACKTRACE + #endif + + #if !defined(HAVE_BACKTRACE) && defined(_glibc_) + #define USE_GLIBC_BACKTRACE + #define HAVE_BACKTRACE + #endif +#endif + +#if defined(USE_GLIBC_BACKTRACE) + #include <execinfo.h> + +size_t BackTrace(void** p, size_t len) { + return (size_t)backtrace(p, len); +} +#endif + +#if defined(USE_GCC_BACKTRACE) + #include <cxxabi.h> + #include <unwind.h> + +namespace { + namespace NGCCBacktrace { + struct TBackTraceContext { + void** sym; + size_t cnt; + size_t size; + }; + + static _Unwind_Reason_Code Helper(struct _Unwind_Context* c, void* h) { + TBackTraceContext* bt = (TBackTraceContext*)h; + + if (bt->cnt != 0) { + bt->sym[bt->cnt - 1] = (void*)_Unwind_GetIP(c); + } + + if (bt->cnt == bt->size) { + return _URC_END_OF_STACK; + } + + ++bt->cnt; + + return _URC_NO_REASON; + } + + static inline size_t BackTrace(void** p, size_t len) { + if (len >= 1) { + TBackTraceContext bt = {p, 0, len}; + + _Unwind_Backtrace(Helper, &bt); + + return bt.cnt - 1; + } + + return 0; + } + } +} + +size_t BackTrace(void** p, size_t len) { + return NGCCBacktrace::BackTrace(p, len); +} +#endif + +#if defined(USE_WIN_BACKTRACE) +size_t BackTrace(void** p, size_t len) { + return CaptureStackBackTrace(0, len, p, nullptr); +} +#endif + +#if !defined(HAVE_BACKTRACE) +size_t BackTrace(void**, size_t) { + return 0; +} +#endif + +#if defined(_unix_) && !defined(_cygwin_) + #include <util/generic/strfcpy.h> + + #include <dlfcn.h> + + #if defined(_darwin_) + #include <execinfo.h> + #endif + +static inline const char* CopyTo(const char* from, char* buf, size_t len) { + strfcpy(buf, from, len); + + return buf; +} + +TResolvedSymbol ResolveSymbol(void* sym, char* buf, size_t len) { + TResolvedSymbol ret = { + "??", + sym, + }; + + Dl_info dli; + + Zero(dli); + + if (dladdr(sym, &dli) && dli.dli_sname) { + ret.Name = CopyTo(NPrivate::TCppDemangler().Demangle(dli.dli_sname), buf, len); + ret.NearestSymbol = dli.dli_saddr; + } + + return ret; +} +#elif defined(_win_) + #include <util/generic/singleton.h> + +namespace { + struct TWinSymbolResolverImpl { + typedef BOOL(WINAPI* TSymInitializeFunc)(HANDLE, PCSTR, BOOL); + typedef BOOL(WINAPI* TSymCleanupFunc)(HANDLE); + typedef BOOL(WINAPI* TSymFromAddrFunc)(HANDLE, DWORD64, PDWORD64, PSYMBOL_INFO); + + TWinSymbolResolverImpl() + : InitOk(FALSE) + { + Library = LoadLibraryA("Dbghelp.dll"); + if (!Library) { + return; + } + + SymInitializeFunc = (TSymInitializeFunc)GetProcAddress(Library, "SymInitialize"); + SymCleanupFunc = (TSymCleanupFunc)GetProcAddress(Library, "SymCleanup"); + SymFromAddrFunc = (TSymFromAddrFunc)GetProcAddress(Library, "SymFromAddr"); + if (SymInitializeFunc && SymCleanupFunc && SymFromAddrFunc) { + InitOk = SymInitializeFunc(GetCurrentProcess(), nullptr, TRUE); + } + } + + ~TWinSymbolResolverImpl() { + if (InitOk) { + SymCleanupFunc(GetCurrentProcess()); + } + + if (Library) { + FreeLibrary(Library); + } + } + + TResolvedSymbol Resolve(void* sym, char* buf, size_t len) { + TGuard<TMutex> guard(Mutex); + + TResolvedSymbol ret = { + "??", + sym}; + + if (!InitOk || (len <= 1 + sizeof(SYMBOL_INFO))) { + return ret; + } + + SYMBOL_INFO* symbol = (SYMBOL_INFO*)buf; + Zero(*symbol); + + symbol->MaxNameLen = len - sizeof(SYMBOL_INFO) - 1; + symbol->SizeOfStruct = sizeof(SYMBOL_INFO); + + DWORD64 displacement = 0; + BOOL res = SymFromAddrFunc(GetCurrentProcess(), (DWORD64)sym, &displacement, symbol); + if (res) { + ret.NearestSymbol = (void*)symbol->Address; + ret.Name = symbol->Name; + } + + return ret; + } + + TMutex Mutex; + HMODULE Library; + TSymInitializeFunc SymInitializeFunc; + TSymCleanupFunc SymCleanupFunc; + TSymFromAddrFunc SymFromAddrFunc; + BOOL InitOk; + }; +} + +TResolvedSymbol ResolveSymbol(void* sym, char* buf, size_t len) { + return Singleton<TWinSymbolResolverImpl>()->Resolve(sym, buf, len); +} +#else +TResolvedSymbol ResolveSymbol(void* sym, char*, size_t) { + TResolvedSymbol ret = { + "??", + sym, + }; + + return ret; +} +#endif + +void FormatBackTrace(IOutputStream* out, void* const* backtrace, size_t backtraceSize) { + char tmpBuf[1024]; + + for (size_t i = 0; i < backtraceSize; ++i) { + TResolvedSymbol rs = ResolveSymbol(backtrace[i], tmpBuf, sizeof(tmpBuf)); + + *out << rs.Name << "+" << ((ptrdiff_t)backtrace[i] - (ptrdiff_t)rs.NearestSymbol) << " (" << Hex((ptrdiff_t)backtrace[i], HF_ADDX) << ')' << '\n'; + } +} + +TFormatBackTraceFn FormatBackTraceFn = FormatBackTrace; + +TFormatBackTraceFn SetFormatBackTraceFn(TFormatBackTraceFn f) { + TFormatBackTraceFn prevFn = FormatBackTraceFn; + FormatBackTraceFn = f; + return prevFn; +} + +void FormatBackTrace(IOutputStream* out) { + void* array[300]; + const size_t s = BackTrace(array, Y_ARRAY_SIZE(array)); + FormatBackTraceFn(out, array, s); +} + +TFormatBackTraceFn GetFormatBackTraceFn() { + return FormatBackTraceFn; +} + +void PrintBackTrace() { + FormatBackTrace(&Cerr); +} + +TBackTrace::TBackTrace() + : Size(0) +{ +} + +void TBackTrace::Capture() { + Size = BackTrace(Data, CAPACITY); +} + +void TBackTrace::PrintTo(IOutputStream& out) const { + FormatBackTraceFn(&out, Data, Size); +} + +TString TBackTrace::PrintToString() const { + TStringStream ss; + PrintTo(ss); + return ss.Str(); +} + +size_t TBackTrace::size() const { + return Size; +} + +const void* const* TBackTrace::data() const { + return Data; +} + +TBackTrace::operator TBackTraceView() const { + return TBackTraceView(Data, Size); +} + +TBackTrace TBackTrace::FromCurrentException() { +#ifdef _YNDX_LIBUNWIND_EXCEPTION_BACKTRACE_SIZE + TBackTrace result; + result.Size = __cxxabiv1::__cxa_collect_current_exception_backtrace(result.Data, CAPACITY); + return result; +#else + return TBackTrace(); +#endif +} |