diff options
author | mrlolthe1st <[email protected]> | 2023-05-30 12:59:50 +0300 |
---|---|---|
committer | mrlolthe1st <[email protected]> | 2023-05-30 12:59:50 +0300 |
commit | c8a8db8913f60129a2a00675acf6fd49310e3ec3 (patch) | |
tree | 9c51e92125b76a494da051a1bbe8406c8ff6d2d4 | |
parent | 1ec4b6e4f22d1d72a94d51e2b68760f70bed233f (diff) |
YQL-15996: Omit error messages from LLVM
omit errors from LLVM
fix?
8 files changed, 565 insertions, 110 deletions
diff --git a/ydb/library/yql/utils/backtrace/CMakeLists.linux-x86_64.txt b/ydb/library/yql/utils/backtrace/CMakeLists.linux-x86_64.txt index 941290fc59d..a872609481d 100644 --- a/ydb/library/yql/utils/backtrace/CMakeLists.linux-x86_64.txt +++ b/ydb/library/yql/utils/backtrace/CMakeLists.linux-x86_64.txt @@ -6,12 +6,14 @@ # original buildsystem will not be accepted. +add_subdirectory(fake_llvm_symbolizer) add_library(yql-utils-backtrace) target_link_libraries(yql-utils-backtrace PUBLIC contrib-libs-linux-headers contrib-libs-cxxsupp yutil + utils-backtrace-fake_llvm_symbolizer contrib-libs-libunwind lib-DebugInfo-Symbolize cpp-deprecated-atomic diff --git a/ydb/library/yql/utils/backtrace/fake_llvm_symbolizer/CMakeLists.linux-x86_64.txt b/ydb/library/yql/utils/backtrace/fake_llvm_symbolizer/CMakeLists.linux-x86_64.txt new file mode 100644 index 00000000000..940fe1c6bee --- /dev/null +++ b/ydb/library/yql/utils/backtrace/fake_llvm_symbolizer/CMakeLists.linux-x86_64.txt @@ -0,0 +1,19 @@ + +# This file was generated by the build system used internally in the Yandex monorepo. +# Only simple modifications are allowed (adding source-files to targets, adding simple properties +# like target_include_directories). These modifications will be ported to original +# ya.make files by maintainers. Any complex modifications which can't be ported back to the +# original buildsystem will not be accepted. + + + +add_library(utils-backtrace-fake_llvm_symbolizer) +target_link_libraries(utils-backtrace-fake_llvm_symbolizer PUBLIC + contrib-libs-linux-headers + contrib-libs-cxxsupp + yutil + lib-DebugInfo-Symbolize +) +target_sources(utils-backtrace-fake_llvm_symbolizer PRIVATE + ${CMAKE_SOURCE_DIR}/ydb/library/yql/utils/backtrace/fake_llvm_symbolizer/fake_llvm_symbolizer.cpp +) diff --git a/ydb/library/yql/utils/backtrace/fake_llvm_symbolizer/CMakeLists.txt b/ydb/library/yql/utils/backtrace/fake_llvm_symbolizer/CMakeLists.txt new file mode 100644 index 00000000000..67bf46faf4d --- /dev/null +++ b/ydb/library/yql/utils/backtrace/fake_llvm_symbolizer/CMakeLists.txt @@ -0,0 +1,11 @@ + +# This file was generated by the build system used internally in the Yandex monorepo. +# Only simple modifications are allowed (adding source-files to targets, adding simple properties +# like target_include_directories). These modifications will be ported to original +# ya.make files by maintainers. Any complex modifications which can't be ported back to the +# original buildsystem will not be accepted. + + +if (CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64" AND NOT HAVE_CUDA) + include(CMakeLists.linux-x86_64.txt) +endif() diff --git a/ydb/library/yql/utils/backtrace/fake_llvm_symbolizer/fake_llvm_symbolizer.cpp b/ydb/library/yql/utils/backtrace/fake_llvm_symbolizer/fake_llvm_symbolizer.cpp new file mode 100644 index 00000000000..5e14bdef503 --- /dev/null +++ b/ydb/library/yql/utils/backtrace/fake_llvm_symbolizer/fake_llvm_symbolizer.cpp @@ -0,0 +1,499 @@ +#include "fake_llvm_symbolizer.h" + +#include <contrib/libs/llvm12/lib/DebugInfo/Symbolize/SymbolizableObjectFile.h> +#include <llvm/DebugInfo/Symbolize/DIPrinter.h> +#include "llvm/DebugInfo/Symbolize/SymbolizableModule.h" +#include "llvm/DebugInfo/DWARF/DWARFContext.h" +#include "llvm/Object/Binary.h" +#include "llvm/Object/ObjectFile.h" +#include "llvm/Object/ELFObjectFile.h" +#include "llvm/Object/COFF.h" +#include "llvm/Object/MachO.h" +#include "llvm/Object/MachOUniversal.h" +#include "llvm/Demangle/Demangle.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/CRC.h" +#include <llvm/Support/raw_ostream.h> +#include <algorithm> +#include <cstdint> +#include <map> +#include <memory> +#include <string> +#include <sstream> +#include <utility> +#include <vector> + +namespace NYql { +namespace NBacktrace { +namespace { + +using ObjectPair = std::pair<const llvm::object::ObjectFile *, const llvm::object::ObjectFile *>; +std::map<std::string, std::unique_ptr<llvm::symbolize::SymbolizableModule>, std::less<>> + Modules; +std::map<std::pair<std::string, std::string>, ObjectPair> + ObjectPairForPathArch; +std::map<std::string, llvm::object::OwningBinary<llvm::object::Binary>> BinaryForPath; +std::map<std::pair<std::string, std::string>, std::unique_ptr<llvm::object::ObjectFile>> + ObjectForUBPathAndArch; + +// Fuctions are from llvm's Symbolize.cpp +llvm::Expected<llvm::object::ObjectFile *> GetOrCreateObject(const std::string &Path, const std::string &ArchName) { + llvm::object::Binary *Bin; + auto Pair = BinaryForPath.emplace(Path, llvm::object::OwningBinary<llvm::object::Binary>()); + if (!Pair.second) { + Bin = Pair.first->second.getBinary(); + } else { + llvm::Expected<llvm::object::OwningBinary<llvm::object::Binary>> BinOrErr = llvm::object::createBinary(Path); + if (!BinOrErr) + return BinOrErr.takeError(); + Pair.first->second = std::move(BinOrErr.get()); + Bin = Pair.first->second.getBinary(); + } + + if (!Bin) + return static_cast<llvm::object::ObjectFile *>(nullptr); + + if (llvm::object::MachOUniversalBinary *UB = llvm::dyn_cast_or_null<llvm::object::MachOUniversalBinary>(Bin)) { + auto I = ObjectForUBPathAndArch.find(std::make_pair(Path, ArchName)); + if (I != ObjectForUBPathAndArch.end()) + return I->second.get(); + + llvm::Expected<std::unique_ptr<llvm::object::ObjectFile>> ObjOrErr = + UB->getMachOObjectForArch(ArchName); + if (!ObjOrErr) { + ObjectForUBPathAndArch.emplace(std::make_pair(Path, ArchName), + std::unique_ptr<llvm::object::ObjectFile>()); + return ObjOrErr.takeError(); + } + llvm::object::ObjectFile *Res = ObjOrErr->get(); + ObjectForUBPathAndArch.emplace(std::make_pair(Path, ArchName), + std::move(ObjOrErr.get())); + return Res; + } + if (Bin->isObject()) { + return llvm::cast<llvm::object::ObjectFile>(Bin); + } + return llvm::errorCodeToError(llvm::object::object_error::arch_not_found); +} + +bool CheckFileCRC(llvm::StringRef Path, uint32_t CRCHash) { + llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> MB = + llvm::MemoryBuffer::getFileOrSTDIN(Path); + if (!MB) + return false; + return CRCHash == llvm::crc32(arrayRefFromStringRef(MB.get()->getBuffer())); +} + +bool FindDebugBinary(const std::string &OrigPath, const std::string &DebuglinkName, uint32_t CRCHash, const std::string &FallbackDebugPath, std::string &Result) { + llvm::SmallString<16> OrigDir(OrigPath); + llvm::sys::path::remove_filename(OrigDir); + llvm::SmallString<16> DebugPath = OrigDir; + // Try relative/path/to/original_binary/debuglink_name + llvm::sys::path::append(DebugPath, DebuglinkName); + if (CheckFileCRC(DebugPath, CRCHash)) { + Result = std::string(DebugPath.str()); + return true; + } + // Try relative/path/to/original_binary/.debug/debuglink_name + DebugPath = OrigDir; + llvm::sys::path::append(DebugPath, ".debug", DebuglinkName); + if (CheckFileCRC(DebugPath, CRCHash)) { + Result = std::string(DebugPath.str()); + return true; + } + // Make the path absolute so that lookups will go to + // "/usr/lib/debug/full/path/to/debug", not + // "/usr/lib/debug/to/debug" + llvm::sys::fs::make_absolute(OrigDir); + if (!FallbackDebugPath.empty()) { + // Try <FallbackDebugPath>/absolute/path/to/original_binary/debuglink_name + DebugPath = FallbackDebugPath; + } else { + #if defined(__NetBSD__) + // Try /usr/libdata/debug/absolute/path/to/original_binary/debuglink_name + DebugPath = "/usr/libdata/debug"; + #else + // Try /usr/lib/debug/absolute/path/to/original_binary/debuglink_name + DebugPath = "/usr/lib/debug"; + #endif + } + llvm::sys::path::append(DebugPath, llvm::sys::path::relative_path(OrigDir), + DebuglinkName); + if (CheckFileCRC(DebugPath, CRCHash)) { + Result = std::string(DebugPath.str()); + return true; + } + return false; +} + +template <typename ELFT> +llvm::Optional<llvm::ArrayRef<uint8_t>> GetBuildID(const llvm::object::ELFFile<ELFT> &Obj) { + auto PhdrsOrErr = Obj.program_headers(); + if (!PhdrsOrErr) { + consumeError(PhdrsOrErr.takeError()); + return {}; + } + for (const auto &P : *PhdrsOrErr) { + if (P.p_type != llvm::ELF::PT_NOTE) + continue; + llvm::Error Err = llvm::Error::success(); + for (auto N : Obj.notes(P, Err)) + if (N.getType() == llvm::ELF::NT_GNU_BUILD_ID && N.getName() == llvm::ELF::ELF_NOTE_GNU) + return N.getDesc(); + consumeError(std::move(Err)); + } + return {}; +} + +llvm::Optional<llvm::ArrayRef<uint8_t>> GetBuildID(const llvm::object::ELFObjectFileBase *Obj) { + llvm::Optional<llvm::ArrayRef<uint8_t>> BuildID; + if (auto *O = llvm::dyn_cast<llvm::object::ELFObjectFile<llvm::object::ELF32LE>>(Obj)) + BuildID = GetBuildID(O->getELFFile()); + else if (auto *O = llvm::dyn_cast<llvm::object::ELFObjectFile<llvm::object::ELF32BE>>(Obj)) + BuildID = GetBuildID(O->getELFFile()); + else if (auto *O = llvm::dyn_cast<llvm::object::ELFObjectFile<llvm::object::ELF64LE>>(Obj)) + BuildID = GetBuildID(O->getELFFile()); + else if (auto *O = llvm::dyn_cast<llvm::object::ELFObjectFile<llvm::object::ELF64BE>>(Obj)) + BuildID = GetBuildID(O->getELFFile()); + else + llvm_unreachable("unsupported file format"); + return BuildID; +} + +std::string GetDarwinDWARFResourceForPath(const std::string &Path, const std::string &Basename) { + llvm::SmallString<16> ResourceName = llvm::StringRef(Path); + if (llvm::sys::path::extension(Path) != ".dSYM") { + ResourceName += ".dSYM"; + } + llvm::sys::path::append(ResourceName, "Contents", "Resources", "DWARF"); + llvm::sys::path::append(ResourceName, Basename); + return std::string(ResourceName.str()); +} + +bool DarwinDsymMatchesBinary(const llvm::object::MachOObjectFile *DbgObj, const llvm::object::MachOObjectFile *Obj) { + llvm::ArrayRef<uint8_t> dbg_uuid = DbgObj->getUuid(); + llvm::ArrayRef<uint8_t> bin_uuid = Obj->getUuid(); + if (dbg_uuid.empty() || bin_uuid.empty()) + return false; + return !memcmp(dbg_uuid.data(), bin_uuid.data(), dbg_uuid.size()); +} + +llvm::object::ObjectFile* LookUpDsymFile(const std::string &ExePath, const llvm::object::MachOObjectFile *MachExeObj, const std::string &ArchName) { + // On Darwin we may find DWARF in separate object file in + // resource directory. + std::vector<std::string> DsymPaths; + llvm::StringRef Filename = llvm::sys::path::filename(ExePath); + DsymPaths.push_back( + GetDarwinDWARFResourceForPath(ExePath, std::string(Filename))); + for (const auto &Path : DsymPaths) { + auto DbgObjOrErr = GetOrCreateObject(Path, ArchName); + if (!DbgObjOrErr) { + // Ignore errors, the file might not exist. + consumeError(DbgObjOrErr.takeError()); + continue; + } + llvm::object::ObjectFile *DbgObj = DbgObjOrErr.get(); + if (!DbgObj) + continue; + const llvm::object::MachOObjectFile *MachDbgObj = llvm::dyn_cast<const llvm::object::MachOObjectFile>(DbgObj); + if (!MachDbgObj) + continue; + if (DarwinDsymMatchesBinary(MachDbgObj, MachExeObj)) + return DbgObj; + } + return nullptr; +} + +bool GetGNUDebuglinkContents(const llvm::object::ObjectFile *Obj, std::string &DebugName, uint32_t &CRCHash) { + if (!Obj) + return false; + for (const llvm::object::SectionRef &Section : Obj->sections()) { + llvm::StringRef Name; + if (llvm::Expected<llvm::StringRef> NameOrErr = Section.getName()) + Name = *NameOrErr; + else + consumeError(NameOrErr.takeError()); + + Name = Name.substr(Name.find_first_not_of("._")); + if (Name == "gnu_debuglink") { + llvm::Expected<llvm::StringRef> ContentsOrErr = Section.getContents(); + if (!ContentsOrErr) { + consumeError(ContentsOrErr.takeError()); + return false; + } + llvm::DataExtractor DE(*ContentsOrErr, Obj->isLittleEndian(), 0); + uint64_t Offset = 0; + if (const char *DebugNameStr = DE.getCStr(&Offset)) { + // 4-byte align the offset. + Offset = (Offset + 3) & ~0x3; + if (DE.isValidOffsetForDataOfSize(Offset, 4)) { + DebugName = DebugNameStr; + CRCHash = DE.getU32(&Offset); + return true; + } + } + break; + } + } + return false; +} + +llvm::object::ObjectFile* LookUpDebuglinkObject(const std::string &Path, const llvm::object::ObjectFile *Obj, const std::string &ArchName) { + std::string DebuglinkName; + uint32_t CRCHash; + std::string DebugBinaryPath; + if (!GetGNUDebuglinkContents(Obj, DebuglinkName, CRCHash)) + return nullptr; + if (!FindDebugBinary(Path, DebuglinkName, CRCHash, "", DebugBinaryPath)) + return nullptr; + auto DbgObjOrErr = GetOrCreateObject(DebugBinaryPath, ArchName); + if (!DbgObjOrErr) { + // Ignore errors, the file might not exist. + consumeError(DbgObjOrErr.takeError()); + return nullptr; + } + return DbgObjOrErr.get(); +} + +bool FindDebugBinary(const std::vector<std::string> &DebugFileDirectory, const llvm::ArrayRef<uint8_t> BuildID, std::string &Result) { + auto getDebugPath = [&](llvm::StringRef Directory) { + llvm::SmallString<128> Path{Directory}; + llvm::sys::path::append(Path, ".build-id", + llvm::toHex(BuildID[0], /*LowerCase=*/true), + llvm::toHex(BuildID.slice(1), /*LowerCase=*/true)); + Path += ".debug"; + return Path; + }; + if (DebugFileDirectory.empty()) { + llvm::SmallString<128> Path = getDebugPath( + #if defined(__NetBSD__) + // Try /usr/libdata/debug/.build-id/../... + "/usr/libdata/debug" + #else + // Try /usr/lib/debug/.build-id/../... + "/usr/lib/debug" + #endif + ); + if (llvm::sys::fs::exists(Path)) { + Result = std::string(Path.str()); + return true; + } + } else { + for (const auto &Directory : DebugFileDirectory) { + // Try <debug-file-directory>/.build-id/../... + llvm::SmallString<128> Path = getDebugPath(Directory); + if (llvm::sys::fs::exists(Path)) { + Result = std::string(Path.str()); + return true; + } + } + } + return false; +} + +llvm::object::ObjectFile* LookUpBuildIDObject(const std::string &Path, const llvm::object::ELFObjectFileBase *Obj, const std::string &ArchName) { + Y_UNUSED(Path); + auto BuildID = GetBuildID(Obj); + if (!BuildID) + return nullptr; + if (BuildID->size() < 2) + return nullptr; + std::string DebugBinaryPath; + if (!FindDebugBinary({}, *BuildID, DebugBinaryPath)) + return nullptr; + auto DbgObjOrErr = GetOrCreateObject(DebugBinaryPath, ArchName); + if (!DbgObjOrErr) { + consumeError(DbgObjOrErr.takeError()); + return nullptr; + } + return DbgObjOrErr.get(); +} + +llvm::Expected<ObjectPair> GetOrCreateObjectPair(const std::string &Path, const std::string &ArchName) { + auto I = ObjectPairForPathArch.find(std::make_pair(Path, ArchName)); + if (I != ObjectPairForPathArch.end()) + return I->second; + + auto ObjOrErr = GetOrCreateObject(Path, ArchName); + if (!ObjOrErr) { + ObjectPairForPathArch.emplace(std::make_pair(Path, ArchName), + ObjectPair(nullptr, nullptr)); + return ObjOrErr.takeError(); + } + + llvm::object::ObjectFile *Obj = ObjOrErr.get(); + assert(Obj != nullptr); + llvm::object::ObjectFile *DbgObj = nullptr; + + if (auto MachObj = llvm::dyn_cast<const llvm::object::MachOObjectFile>(Obj)) + DbgObj = LookUpDsymFile(Path, MachObj, ArchName); + else if (auto ELFObj = llvm::dyn_cast<const llvm::object::ELFObjectFileBase>(Obj)) + DbgObj = LookUpBuildIDObject(Path, ELFObj, ArchName); + if (!DbgObj) + DbgObj = LookUpDebuglinkObject(Path, Obj, ArchName); + if (!DbgObj) + DbgObj = Obj; + ObjectPair Res = std::make_pair(Obj, DbgObj); + ObjectPairForPathArch.emplace(std::make_pair(Path, ArchName), Res); + return Res; +} + +llvm::Expected<llvm::symbolize::SymbolizableModule *> CreateModuleInfo(const llvm::object::ObjectFile *Obj, std::unique_ptr<llvm::DIContext> Context, llvm::StringRef ModuleName) { + auto InfoOrErr = llvm::symbolize::SymbolizableObjectFile::create(Obj, std::move(Context), false); + std::unique_ptr<llvm::symbolize::SymbolizableModule> SymMod; + if (InfoOrErr) + SymMod = std::move(*InfoOrErr); + auto InsertResult = Modules.insert( + std::make_pair(std::string(ModuleName), std::move(SymMod))); + assert(InsertResult.second); + if (!InfoOrErr) + return InfoOrErr.takeError(); + return InsertResult.first->second.get(); +} + +void DoNothing(llvm::Error) { +}; + +llvm::Expected<llvm::symbolize::SymbolizableModule*> GetOrCreateModuleInfo(const std::string &ModuleName) { + auto I = Modules.find(ModuleName); + if (I != Modules.end()) + return I->second.get(); + + std::string BinaryName = ModuleName; + std::string ArchName = ""; // (!) is set to empty + size_t ColonPos = ModuleName.find_last_of(':'); + // Verify that substring after colon form a valid arch name. + if (ColonPos != std::string::npos) { + std::string ArchStr = ModuleName.substr(ColonPos + 1); + if (llvm::Triple(ArchStr).getArch() != llvm::Triple::UnknownArch) { + BinaryName = ModuleName.substr(0, ColonPos); + ArchName = ArchStr; + } + } + + auto ObjectsOrErr = GetOrCreateObjectPair(BinaryName, ArchName); + if (!ObjectsOrErr) { + // Failed to find valid object file. + Modules.emplace(ModuleName, std::unique_ptr<llvm::symbolize::SymbolizableModule>()); + return ObjectsOrErr.takeError(); + } + + ObjectPair Objects = ObjectsOrErr.get(); + + // Only DWARF available on linux + std::unique_ptr<llvm::DIContext> Context = llvm::DWARFContext::create(*Objects.second, nullptr, "", DoNothing, DoNothing); + return CreateModuleInfo(Objects.first, std::move(Context), ModuleName); +} + +llvm::StringRef DemanglePE32ExternCFunc(llvm::StringRef SymbolName) { + // Remove any '_' or '@' prefix. + char Front = SymbolName.empty() ? '\0' : SymbolName[0]; + if (Front == '_' || Front == '@') + SymbolName = SymbolName.drop_front(); + + // Remove any '@[0-9]+' suffix. + if (Front != '?') { + size_t AtPos = SymbolName.rfind('@'); + if (AtPos != llvm::StringRef::npos && + all_of(drop_begin(SymbolName, AtPos + 1), llvm::isDigit)) + SymbolName = SymbolName.substr(0, AtPos); + } + + // Remove any ending '@' for vectorcall. + if (SymbolName.endswith("@")) + SymbolName = SymbolName.drop_back(); + + return SymbolName; +} + +std::string DemangleName(const std::string &Name, const llvm::symbolize::SymbolizableModule *DbiModuleDescriptor) { + // We can spoil names of symbols with C linkage, so use an heuristic + // approach to check if the name should be demangled. + if (Name.substr(0, 2) == "_Z") { + int status = 0; + char *DemangledName = llvm::itaniumDemangle(Name.c_str(), nullptr, nullptr, &status); + if (status != 0) + return Name; + std::string Result = DemangledName; + free(DemangledName); + return Result; + } + + if (!Name.empty() && Name.front() == '?') { + // Only do MSVC C++ demangling on symbols starting with '?'. + int status = 0; + char *DemangledName = microsoftDemangle( + Name.c_str(), nullptr, nullptr, nullptr, &status, + llvm::MSDemangleFlags(llvm::MSDF_NoAccessSpecifier | llvm::MSDF_NoCallingConvention | + llvm::MSDF_NoMemberType | llvm::MSDF_NoReturnType)); + if (status != 0) + return Name; + std::string Result = DemangledName; + free(DemangledName); + return Result; + } + + if (DbiModuleDescriptor && DbiModuleDescriptor->isWin32Module()) + return std::string(DemanglePE32ExternCFunc(Name)); + return Name; +} + +llvm::Expected<llvm::DILineInfo> SymbolizeCodeCommon(llvm::symbolize::SymbolizableModule *Info, llvm::object::SectionedAddress ModuleOffset) { + // A null module means an error has already been reported. Return an empty + // result. + if (!Info) + return llvm::DILineInfo(); + + llvm::DILineInfo LineInfo = Info->symbolizeCode( + ModuleOffset, llvm::DILineInfoSpecifier(llvm::DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath, llvm::DILineInfoSpecifier::FunctionNameKind::LinkageName), + true); + LineInfo.FunctionName = DemangleName(LineInfo.FunctionName, Info); + return LineInfo; +} + +class TRawOStreamProxy: public llvm::raw_ostream { +public: + TRawOStreamProxy(std::ostream& out) + : llvm::raw_ostream(true) // unbuffered + , Slave_(out) + { + } + void write_impl(const char* ptr, size_t size) override { + Slave_.write(ptr, size); + } + uint64_t current_pos() const override { + return 0; + } + size_t preferred_buffer_size() const override { + return 0; + } +private: + std::ostream& Slave_; +}; + +} + +TString SymbolizeAndDumpToString(const std::string &moduleName, llvm::object::SectionedAddress moduleOffset, ui64 offset) { + llvm::Expected<llvm::symbolize::SymbolizableModule *> InfoOrErr = GetOrCreateModuleInfo(moduleName); + if (!InfoOrErr) + return "Can't create module info"; + auto resOrErr = SymbolizeCodeCommon(*InfoOrErr, moduleOffset); + if (resOrErr) { + auto value = resOrErr.get(); + if (value.FileName == "<invalid>" && offset > 0) { + value.FileName = moduleName; + } + + std::stringstream ss; + TRawOStreamProxy stream_proxy(ss); + llvm::symbolize::DIPrinter printer(stream_proxy, true, true, false); + printer << value; + ss.flush(); + + return ss.str(); + } else { + return "LLVMSymbolizer: error reading file..."; + } +} +} +} diff --git a/ydb/library/yql/utils/backtrace/fake_llvm_symbolizer/fake_llvm_symbolizer.h b/ydb/library/yql/utils/backtrace/fake_llvm_symbolizer/fake_llvm_symbolizer.h new file mode 100644 index 00000000000..11925672491 --- /dev/null +++ b/ydb/library/yql/utils/backtrace/fake_llvm_symbolizer/fake_llvm_symbolizer.h @@ -0,0 +1,11 @@ +#pragma once + +#include <util/generic/string.h> +#include <util/system/types.h> +#include "llvm/Object/ObjectFile.h" + +namespace NYql { +namespace NBacktrace { +TString SymbolizeAndDumpToString(const std::string &moduleName, llvm::object::SectionedAddress moduleOffset, ui64 offset); +} +} diff --git a/ydb/library/yql/utils/backtrace/symbolize.cpp b/ydb/library/yql/utils/backtrace/symbolize.cpp index 4e43326a97f..85706e24f4d 100644 --- a/ydb/library/yql/utils/backtrace/symbolize.cpp +++ b/ydb/library/yql/utils/backtrace/symbolize.cpp @@ -1,11 +1,7 @@ #include "backtrace.h" #include "symbolizer.h" -#ifdef _linux_ -#include <llvm/DebugInfo/Symbolize/Symbolize.h> -#include <llvm/DebugInfo/Symbolize/DIPrinter.h> -#include <llvm/Support/raw_ostream.h> -#endif +#include "fake_llvm_symbolizer/fake_llvm_symbolizer.h" #include <util/string/split.h> #include <util/stream/str.h> @@ -20,41 +16,10 @@ struct TStackFrame { ui64 Offset; }; -#ifdef _linux_ -class TRawOStreamProxy: public llvm::raw_ostream { -public: - TRawOStreamProxy(IOutputStream& out) - : llvm::raw_ostream(true) // unbuffered - , Slave_(out) - { - } - void write_impl(const char* ptr, size_t size) override { - Slave_.Write(ptr, size); - } - uint64_t current_pos() const override { - return 0; - } - size_t preferred_buffer_size() const override { - return 0; - } -private: - IOutputStream& Slave_; -}; -#endif - TString Symbolize(const TString& input, const THashMap<TString, TString>& mapping) { TString output; TStringOutput out(output); -#ifdef _linux_ - TRawOStreamProxy outStream(out); - llvm::symbolize::LLVMSymbolizer::Options opts; - llvm::symbolize::LLVMSymbolizer symbolyzer(opts); - llvm::symbolize::DIPrinter printer(outStream, true, true, false); -#else - auto& outStream = out; -#endif - i64 stackSize = -1; TVector<TStackFrame> frames; for (TStringBuf line: StringSplitter(input).SplitByString("\n").SkipEmpty()) { @@ -82,32 +47,21 @@ TString Symbolize(const TString& input, const THashMap<TString, TString>& mappin frames.emplace_back(TStackFrame{modulePath, address, offset}); } } else { - outStream << line << "\n"; + out << line << "\n"; } } if (stackSize == 0) { - outStream << "Empty stack trace\n"; + out << "Empty stack trace\n"; } for (const auto& frame : frames) { #ifdef _linux_ llvm::object::SectionedAddress secAddr; secAddr.Address = frame.Address - frame.Offset; - auto resOrErr = symbolyzer.symbolizeCode(frame.ModulePath, secAddr); - if (resOrErr) { - auto value = resOrErr.get(); - if (value.FileName == "<invalid>" && frame.Offset > 0) { - value.FileName = frame.ModulePath; - } - - printer << value; - } else { - logAllUnhandledErrors(resOrErr.takeError(), outStream, - "LLVMSymbolizer: error reading file: "); - } + out << NYql::NBacktrace::SymbolizeAndDumpToString(frame.ModulePath, secAddr, frame.Offset) << Endl; #else - outStream << "StackFrame: " << frame.ModulePath << " " << frame.Address << " " << frame.Offset << Endl; + out << "StackFrame: " << frame.ModulePath << " " << frame.Address << " " << frame.Offset << Endl; #endif } return output; diff --git a/ydb/library/yql/utils/backtrace/symbolizer_dummy.cpp b/ydb/library/yql/utils/backtrace/symbolizer_dummy.cpp index 3370410e3da..505fc36394e 100644 --- a/ydb/library/yql/utils/backtrace/symbolizer_dummy.cpp +++ b/ydb/library/yql/utils/backtrace/symbolizer_dummy.cpp @@ -31,22 +31,22 @@ class TBacktraceSymbolizer : public IBacktraceSymbolizer { public: TBacktraceSymbolizer() : IBacktraceSymbolizer() { #ifdef _linux_ - dl_iterate_phdr(DlIterCallback, &DLLs); + dl_iterate_phdr(DlIterCallback, &DLLs_); #endif } TString SymbolizeFrame(void* ptr) override { ui64 address = (ui64)ptr - 1; // last byte of the call instruction ui64 offset = 0; - TString modulePath = BinaryPath; + TString modulePath = BinaryPath_; #ifdef _linux_ Dl_info dlInfo; memset(&dlInfo, 0, sizeof(dlInfo)); auto ret = dladdr((void*)address, &dlInfo); if (ret) { auto path = dlInfo.dli_fname; - auto it = DLLs.find(path); - if (it != DLLs.end()) { + auto it = DLLs_.find(path); + if (it != DLLs_.end()) { modulePath = path; offset = it->second.BaseAddress; } @@ -65,8 +65,8 @@ public: } private: - TString BinaryPath = "EXE"; - THashMap<TString, TDllInfo> DLLs; + TString BinaryPath_ = "EXE"; + THashMap<TString, TDllInfo> DLLs_; }; std::unique_ptr<IBacktraceSymbolizer> BuildSymbolizer(bool) { diff --git a/ydb/library/yql/utils/backtrace/symbolizer_linux.cpp b/ydb/library/yql/utils/backtrace/symbolizer_linux.cpp index 3a5cac0cc67..1058092865c 100644 --- a/ydb/library/yql/utils/backtrace/symbolizer_linux.cpp +++ b/ydb/library/yql/utils/backtrace/symbolizer_linux.cpp @@ -1,8 +1,5 @@ #include "symbolizer.h" - -#include <llvm/DebugInfo/Symbolize/Symbolize.h> -#include <llvm/DebugInfo/Symbolize/DIPrinter.h> -#include <llvm/Support/raw_ostream.h> +#include "fake_llvm_symbolizer/fake_llvm_symbolizer.h" #include <library/cpp/deprecated/atomic/atomic.h> #include <library/cpp/malloc/api/malloc.h> @@ -38,73 +35,37 @@ int DlIterCallback(struct dl_phdr_info *info, size_t size, void *data) return 0; } -class TRawOStreamProxy: public llvm::raw_ostream { -public: - TRawOStreamProxy(std::ostream& out) - : llvm::raw_ostream(true) // unbuffered - , Slave_(out) - { - } - void write_impl(const char* ptr, size_t size) override { - Slave_.write(ptr, size); - } - uint64_t current_pos() const override { - return 0; - } - size_t preferred_buffer_size() const override { - return 0; - } -private: - std::ostream& Slave_; -}; - class TBacktraceSymbolizer : public IBacktraceSymbolizer { public: - TBacktraceSymbolizer(bool kikimrFormat) : IBacktraceSymbolizer(), Symbolyzer(Opts), KikimrFormat(kikimrFormat) { - dl_iterate_phdr(DlIterCallback, &DLLs); + TBacktraceSymbolizer(bool kikimrFormat) : IBacktraceSymbolizer(), KikimrFormat_(kikimrFormat) { + dl_iterate_phdr(DlIterCallback, &DLLs_); } TString SymbolizeFrame(void* ptr) override { ui64 address = (ui64)ptr - 1; ui64 offset = 0; - TString modulePath = BinaryPath; + TString modulePath = BinaryPath_; #ifdef _linux_ Dl_info dlInfo; memset(&dlInfo, 0, sizeof(dlInfo)); auto ret = dladdr((void*)address, &dlInfo); if (ret) { auto path = dlInfo.dli_fname; - auto it = DLLs.find(path); - if (it != DLLs.end()) { + auto it = DLLs_.find(path); + if (it != DLLs_.end()) { modulePath = path; offset = it->second.BaseAddress; } } #endif - if (!KikimrFormat) { + if (!KikimrFormat_) { return "StackFrame: " + modulePath + " " + address + " " + offset + "\n"; } - llvm::symbolize::SectionedAddress secAddr; + llvm::object::SectionedAddress secAddr; secAddr.Address = address - offset; - auto resOrErr = Symbolyzer.symbolizeCode(modulePath, secAddr); - if (resOrErr) { - auto value = resOrErr.get(); - if (value.FileName == "<invalid>" && offset > 0) { - value.FileName = modulePath; - } - - std::stringstream ss; - TRawOStreamProxy stream_proxy(ss); - llvm::symbolize::DIPrinter printer(stream_proxy, true, true, false); - printer << value; - ss.flush(); - - return ss.str(); - } else { - return "LLVMSymbolizer: error reading file..."; - } + return NYql::NBacktrace::SymbolizeAndDumpToString(modulePath, secAddr, offset); } ~TBacktraceSymbolizer() override { @@ -112,11 +73,9 @@ public: } private: - THashMap<TString, TDllInfo> DLLs; - llvm::symbolize::LLVMSymbolizer::Options Opts; - llvm::symbolize::LLVMSymbolizer Symbolyzer; - TString BinaryPath = GetPersistentExecPath(); - bool KikimrFormat; + THashMap<TString, TDllInfo> DLLs_; + TString BinaryPath_ = GetPersistentExecPath(); + bool KikimrFormat_; }; std::unique_ptr<IBacktraceSymbolizer> BuildSymbolizer(bool format) { |