#include "backtrace_lib.h" #include #include #include #if defined(_linux_) && defined(_x86_64_) #include #include #endif namespace { const size_t Limit = 400; void* Stack[Limit]; // NOLINT(modernize-avoid-c-arrays) struct TDllInfo { const char* Path; ui64 BaseAddress; }; const size_t MaxDLLCnt = 100; TDllInfo DLLs[MaxDLLCnt]; // NOLINT(modernize-avoid-c-arrays) size_t DLLCount = 0; #if defined(_linux_) && defined(_x86_64_) int DlIterCallback(struct dl_phdr_info* info, size_t, void* data) { if (*info->dlpi_name) { if (DLLCount + 1 < MaxDLLCnt) { reinterpret_cast*>(data)[DLLCount++] = {.Path = info->dlpi_name, .BaseAddress = (ui64)info->dlpi_addr}; } } return 0; } #endif bool Comp(const TDllInfo& a, const TDllInfo& b) { return strcmp(a.Path, b.Path) < 0; } } // namespace namespace NYql::NBacktrace { TCollectedFrame::TCollectedFrame(uintptr_t addr) { File = GetPersistentExecPath().c_str(); Address = addr; #if defined(_linux_) && defined(_x86_64_) Dl_info dlInfo; memset(&dlInfo, 0, sizeof(dlInfo)); auto ret = dladdr(reinterpret_cast(addr), &dlInfo); if (ret) { auto it = std::lower_bound(DLLs, DLLs + DLLCount, std::remove_reference_t{dlInfo.dli_fname, {}}, Comp); if (it != DLLs + DLLCount && !strcmp(it->Path, dlInfo.dli_fname)) { File = it->Path; Address -= it->BaseAddress; } } #endif } size_t CollectFrames(TCollectedFrame* frames, void* data) { #if defined(_linux_) && defined(_x86_64_) DLLCount = 0; dl_iterate_phdr(DlIterCallback, &DLLs); #endif std::stable_sort(DLLs, DLLs + DLLCount, Comp); size_t cnt = CollectBacktrace(Stack, Limit, data); return CollectFrames(frames, Stack, cnt); } size_t CollectFrames(TCollectedFrame* frames, void** stack, size_t cnt) { for (size_t i = 0; i < cnt; ++i) { new (frames + i) TCollectedFrame(reinterpret_cast(stack[i])); } return cnt; } } // namespace NYql::NBacktrace