Index: llvm/include/llvm/DebugInfo/Symbolize/Symbolize.h =================================================================== --- llvm/include/llvm/DebugInfo/Symbolize/Symbolize.h +++ llvm/include/llvm/DebugInfo/Symbolize/Symbolize.h @@ -154,6 +154,8 @@ Options Opts; }; +Optional> getBuildID(const ELFObjectFileBase *Obj); + } // end namespace symbolize } // end namespace llvm Index: llvm/include/llvm/Debuginfod/Debuginfod.h =================================================================== --- llvm/include/llvm/Debuginfod/Debuginfod.h +++ llvm/include/llvm/Debuginfod/Debuginfod.h @@ -19,6 +19,7 @@ #ifndef LLVM_DEBUGINFOD_DEBUGINFOD_H #define LLVM_DEBUGINFOD_DEBUGINFOD_H +#include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/Error.h" #include "llvm/Support/MemoryBuffer.h" @@ -67,6 +68,19 @@ StringRef CacheDirectoryPath, ArrayRef DebuginfodUrls, long Timeout); +/// Tracks a collection of debuginfod artifacts on the local filesystem. +class DebuginfodCollection { + SmallVector Paths; + StringMap Binaries; + StringMap DebugBinaries; + Error findBinaries(StringRef Path); + +public: + DebuginfodCollection(ArrayRef Paths); + Error update(); + Expected getDebugBinaryPath(BuildIDRef); + Expected getBinaryPath(BuildIDRef); +}; } // end namespace llvm #endif Index: llvm/lib/DebugInfo/Symbolize/Symbolize.cpp =================================================================== --- llvm/lib/DebugInfo/Symbolize/Symbolize.cpp +++ llvm/lib/DebugInfo/Symbolize/Symbolize.cpp @@ -335,21 +335,6 @@ return {}; } -Optional> getBuildID(const ELFObjectFileBase *Obj) { - Optional> BuildID; - if (auto *O = dyn_cast>(Obj)) - BuildID = getBuildID(O->getELFFile()); - else if (auto *O = dyn_cast>(Obj)) - BuildID = getBuildID(O->getELFFile()); - else if (auto *O = dyn_cast>(Obj)) - BuildID = getBuildID(O->getELFFile()); - else if (auto *O = dyn_cast>(Obj)) - BuildID = getBuildID(O->getELFFile()); - else - llvm_unreachable("unsupported file format"); - return BuildID; -} - bool findDebugBinary(const std::vector &DebugFileDirectory, const ArrayRef BuildID, std::string &Result) { auto getDebugPath = [&](StringRef Directory) { @@ -389,6 +374,21 @@ } // end anonymous namespace +Optional> getBuildID(const ELFObjectFileBase *Obj) { + Optional> BuildID; + if (auto *O = dyn_cast>(Obj)) + BuildID = getBuildID(O->getELFFile()); + else if (auto *O = dyn_cast>(Obj)) + BuildID = getBuildID(O->getELFFile()); + else if (auto *O = dyn_cast>(Obj)) + BuildID = getBuildID(O->getELFFile()); + else if (auto *O = dyn_cast>(Obj)) + BuildID = getBuildID(O->getELFFile()); + else + llvm_unreachable("unsupported file format"); + return BuildID; +} + ObjectFile *LLVMSymbolizer::lookUpDsymFile(const std::string &ExePath, const MachOObjectFile *MachExeObj, const std::string &ArchName) { Index: llvm/lib/Debuginfod/CMakeLists.txt =================================================================== --- llvm/lib/Debuginfod/CMakeLists.txt +++ llvm/lib/Debuginfod/CMakeLists.txt @@ -6,4 +6,6 @@ LINK_COMPONENTS Support + Symbolize + DebugInfoDWARF ) Index: llvm/lib/Debuginfod/Debuginfod.cpp =================================================================== --- llvm/lib/Debuginfod/Debuginfod.cpp +++ llvm/lib/Debuginfod/Debuginfod.cpp @@ -17,14 +17,20 @@ //===----------------------------------------------------------------------===// #include "llvm/Debuginfod/Debuginfod.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/Support/CachePruning.h" +#include "llvm/BinaryFormat/Magic.h" +#include "llvm/DebugInfo/DWARF/DWARFContext.h" +#include "llvm/DebugInfo/Symbolize/Symbolize.h" +#include "llvm/Object/Binary.h" +#include "llvm/Object/ELFObjectFile.h" +#include "llvm/Object/ObjectFile.h" #include "llvm/Support/Caching.h" #include "llvm/Support/Error.h" #include "llvm/Support/FileUtilities.h" #include "llvm/Support/HTTPClient.h" #include "llvm/Support/xxhash.h" +#define DEBUG_TYPE "Debuginfod" + using namespace llvm; static std::string uniqueKey(llvm::StringRef S) { return utostr(xxHash64(S)); } @@ -178,4 +184,116 @@ return createStringError(errc::argument_out_of_domain, "build id not found"); } +DebuginfodCollection::DebuginfodCollection(ArrayRef PathsRef) { + for (auto Path : PathsRef) + Paths.push_back(Path.str()); +} + +Error DebuginfodCollection::update() { + for (auto Path : Paths) + if (Error Err = findBinaries(Path)) + return Err; + return Error::success(); +} + +static bool isDebugBinary(object::ObjectFile *Object) { + // TODO: handle PDB debuginfo + std::unique_ptr Context = DWARFContext::create( + *Object, DWARFContext::ProcessDebugRelocations::Process); + const DWARFObject &DObj = Context->getDWARFObj(); + unsigned NumSections = 0; + DObj.forEachInfoSections([&](const DWARFSection &S) { NumSections++; }); + return NumSections; +} + +static bool hasELFMagic(StringRef FilePath) { + file_magic Type; + std::error_code EC = identify_magic(FilePath, Type); + if (EC) + return false; + switch (Type) { + case file_magic::elf: + case file_magic::elf_relocatable: + case file_magic::elf_executable: + case file_magic::elf_shared_object: + case file_magic::elf_core: + return true; + default: + return false; + } +} + +Error DebuginfodCollection::findBinaries(StringRef Path) { + std::error_code ec; + for (sys::fs::recursive_directory_iterator i(Twine(Path), ec), e; i != e; + i.increment(ec)) { + if (ec) + return errorCodeToError(ec); + + StringRef FilePath = StringRef(i->path()); + LLVM_DEBUG(dbgs() << FilePath << "\n";); + std::string StrFilePath = std::string(FilePath); + + if (!hasELFMagic(FilePath)) + continue; + + Expected> BinOrErr = + object::createBinary(FilePath); + if (!BinOrErr) { + consumeError(BinOrErr.takeError()); + continue; + } + object::Binary *Bin = std::move(BinOrErr.get().getBinary()); + if (!Bin->isObject()) + continue; + + // TODO: Support non-ELF binaries + object::ELFObjectFileBase *Object = + dyn_cast(Bin); + if (!Object) + continue; + + Optional ID = symbolize::getBuildID(Object); + if (!ID) + continue; + + std::string IDString = buildIDToString(ID.getValue()); + LLVM_DEBUG(outs() << StringRef(i->path()) + << " is an object file with BuildID " << IDString + << "\n";); + + if (isDebugBinary(Object)) { + LLVM_DEBUG(outs() << StringRef(i->path()) << " is a debug binary.\n";); + DebugBinaries[IDString] = FilePath.str(); + } else { + LLVM_DEBUG(outs() << StringRef(i->path()) + << " is not a debug binary.\n";); + Binaries[IDString] = FilePath.str(); + } + } + return Error::success(); +} + +Expected DebuginfodCollection::getBinaryPath(BuildIDRef ID) { + LLVM_DEBUG(dbgs() << "getting binary path of ID " << buildIDToString(ID) + << "\n";); + auto Loc = Binaries.find(buildIDToString(ID)); + if (Loc != Binaries.end()) { + return Loc->getValue(); + } + LLVM_DEBUG(dbgs() << "falling back to debug binary\n";); + return getDebugBinaryPath(ID); +} + +Expected DebuginfodCollection::getDebugBinaryPath(BuildIDRef ID) { + LLVM_DEBUG(dbgs() << "getting debug binary path of ID " << buildIDToString(ID) + << "\n";); + auto Loc = DebugBinaries.find(buildIDToString(ID)); + if (Loc != DebugBinaries.end()) { + return Loc->getValue(); + } + return createStringError(errc::no_such_file_or_directory, + "No matching binary available"); +} + } // namespace llvm