aboutsummaryrefslogtreecommitdiffstats
path: root/util/system/backtrace.cpp
diff options
context:
space:
mode:
authorDevtools Arcadia <arcadia-devtools@yandex-team.ru>2022-02-07 18:08:42 +0300
committerDevtools Arcadia <arcadia-devtools@mous.vla.yp-c.yandex.net>2022-02-07 18:08:42 +0300
commit1110808a9d39d4b808aef724c861a2e1a38d2a69 (patch)
treee26c9fed0de5d9873cce7e00bc214573dc2195b7 /util/system/backtrace.cpp
downloadydb-1110808a9d39d4b808aef724c861a2e1a38d2a69.tar.gz
intermediate changes
ref:cde9a383711a11544ce7e107a78147fb96cc4029
Diffstat (limited to 'util/system/backtrace.cpp')
-rw-r--r--util/system/backtrace.cpp307
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
+}