From e61d89efd78b17f4969c9a394f480367307c7132 Mon Sep 17 00:00:00 2001 From: Daniel Thornburgh Date: Tue, 23 Aug 2022 13:39:33 -0700 Subject: [PATCH] [NFC] [Object] Create library to fetch debug info by build ID. This creates a library for fetching debug info by build ID, whether locally or remotely via debuginfod. The functionality was refactored out of existing code in the Symboliize library. Existing utilities were refactored to use this library. Reviewed By: phosek Differential Revision: https://reviews.llvm.org/D132504 --- llvm/include/llvm/DebugInfo/Symbolize/DIFetcher.h | 51 ------------ llvm/include/llvm/DebugInfo/Symbolize/Symbolize.h | 10 +-- .../Debuginfod/{DIFetcher.h => BuildIDFetcher.h} | 19 ++--- llvm/include/llvm/Debuginfod/Debuginfod.h | 22 +++-- llvm/include/llvm/Object/BuildID.h | 52 ++++++++++++ llvm/include/llvm/Object/ObjectFile.h | 2 + llvm/lib/DebugInfo/Symbolize/CMakeLists.txt | 1 - llvm/lib/DebugInfo/Symbolize/DIFetcher.cpp | 57 ------------- llvm/lib/DebugInfo/Symbolize/Symbolize.cpp | 62 ++------------- .../{DIFetcher.cpp => BuildIDFetcher.cpp} | 9 ++- llvm/lib/Debuginfod/CMakeLists.txt | 2 +- llvm/lib/Debuginfod/Debuginfod.cpp | 24 ++---- llvm/lib/Object/BuildID.cpp | 93 ++++++++++++++++++++++ llvm/lib/Object/CMakeLists.txt | 1 + llvm/lib/Object/ObjectFile.cpp | 5 ++ llvm/tools/llvm-debuginfod-find/CMakeLists.txt | 2 +- .../llvm-debuginfod-find/llvm-debuginfod-find.cpp | 22 ++--- llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp | 30 +++---- 18 files changed, 227 insertions(+), 237 deletions(-) delete mode 100644 llvm/include/llvm/DebugInfo/Symbolize/DIFetcher.h rename llvm/include/llvm/Debuginfod/{DIFetcher.h => BuildIDFetcher.h} (55%) create mode 100644 llvm/include/llvm/Object/BuildID.h delete mode 100644 llvm/lib/DebugInfo/Symbolize/DIFetcher.cpp rename llvm/lib/Debuginfod/{DIFetcher.cpp => BuildIDFetcher.cpp} (74%) create mode 100644 llvm/lib/Object/BuildID.cpp diff --git a/llvm/include/llvm/DebugInfo/Symbolize/DIFetcher.h b/llvm/include/llvm/DebugInfo/Symbolize/DIFetcher.h deleted file mode 100644 index c5340b5..0000000 --- a/llvm/include/llvm/DebugInfo/Symbolize/DIFetcher.h +++ /dev/null @@ -1,51 +0,0 @@ -//===-- llvm/DebugInfo/Symbolize/DIFetcher.h --------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -/// -/// \file -/// This file declares a DIFetcher abstraction for obtaining debug info from an -/// arbitrary outside source. -/// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_DEBUGINFO_SYMBOLIZE_DIFETCHER_H -#define LLVM_DEBUGINFO_SYMBOLIZE_DIFETCHER_H - -#include -#include - -#include "llvm/ADT/ArrayRef.h" - -namespace llvm { -namespace symbolize { - -/// The DIFetcher interface provides arbitrary mechanisms for obtaining debug -/// info from an outside source. -class DIFetcher { -public: - virtual ~DIFetcher() = default; - virtual Optional - fetchBuildID(ArrayRef BuildID) const = 0; -}; - -/// LocalDIFetcher searches local cache directories for debug info. -class LocalDIFetcher : public DIFetcher { -public: - LocalDIFetcher(ArrayRef DebugFileDirectory) - : DebugFileDirectory(DebugFileDirectory){}; - virtual ~LocalDIFetcher() = default; - - Optional fetchBuildID(ArrayRef BuildID) const override; - -private: - const ArrayRef DebugFileDirectory; -}; - -} // end namespace symbolize -} // end namespace llvm - -#endif // LLVM_DEBUGINFO_SYMBOLIZE_DIFETCHER_H diff --git a/llvm/include/llvm/DebugInfo/Symbolize/Symbolize.h b/llvm/include/llvm/DebugInfo/Symbolize/Symbolize.h index f233a18..c633c89 100644 --- a/llvm/include/llvm/DebugInfo/Symbolize/Symbolize.h +++ b/llvm/include/llvm/DebugInfo/Symbolize/Symbolize.h @@ -17,8 +17,8 @@ #include "llvm/ADT/ilist_node.h" #include "llvm/ADT/simple_ilist.h" #include "llvm/DebugInfo/DIContext.h" -#include "llvm/DebugInfo/Symbolize/DIFetcher.h" #include "llvm/Object/Binary.h" +#include "llvm/Object/BuildID.h" #include "llvm/Support/Error.h" #include #include @@ -115,8 +115,8 @@ public: DemangleName(const std::string &Name, const SymbolizableModule *DbiModuleDescriptor); - void addDIFetcher(std::unique_ptr Fetcher) { - DIFetchers.push_back(std::move(Fetcher)); + void setBuildIDFetcher(std::unique_ptr Fetcher) { + BIDFetcher = std::move(Fetcher); } private: @@ -211,7 +211,7 @@ private: Options Opts; - SmallVector> DIFetchers; + std::unique_ptr BIDFetcher; }; // A binary intrusively linked into a LRU cache list. If the binary is empty, @@ -243,8 +243,6 @@ private: std::function Evictor; }; -Optional> getBuildID(const ELFObjectFileBase *Obj); - } // end namespace symbolize } // end namespace llvm diff --git a/llvm/include/llvm/Debuginfod/DIFetcher.h b/llvm/include/llvm/Debuginfod/BuildIDFetcher.h similarity index 55% rename from llvm/include/llvm/Debuginfod/DIFetcher.h rename to llvm/include/llvm/Debuginfod/BuildIDFetcher.h index d398fd9..505db58 100644 --- a/llvm/include/llvm/Debuginfod/DIFetcher.h +++ b/llvm/include/llvm/Debuginfod/BuildIDFetcher.h @@ -1,4 +1,4 @@ -//===- llvm/DebugInfod/DIFetcher.h - Debug info fetcher----------*- C++ -*-===// +//===- llvm/DebugInfod/BuildIDFetcher.h - Build ID fetcher ------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -7,26 +7,27 @@ //===----------------------------------------------------------------------===// /// /// \file -/// This file declares a DIFetcher implementation for obtaining debug info from -/// debuginfod. +/// This file declares a Build ID fetcher implementation for obtaining debug +/// info from debuginfod. /// //===----------------------------------------------------------------------===// #ifndef LLVM_DEBUGINFOD_DIFETCHER_H #define LLVM_DEBUGINFOD_DIFETCHER_H -#include "llvm/ADT/ArrayRef.h" -#include "llvm/DebugInfo/Symbolize/DIFetcher.h" +#include "llvm/Object/BuildID.h" namespace llvm { -class DebuginfodDIFetcher : public symbolize::DIFetcher { +class DebuginfodFetcher : public object::BuildIDFetcher { public: - virtual ~DebuginfodDIFetcher() = default; + DebuginfodFetcher(std::vector DebugFileDirectories) + : BuildIDFetcher(std::move(DebugFileDirectories)) {} + virtual ~DebuginfodFetcher() = default; /// Fetches the given Build ID using debuginfod and returns a local path to - /// the resulting debug binary. - Optional fetchBuildID(ArrayRef BuildID) const override; + /// the resulting file. + Optional fetch(object::BuildIDRef BuildID) const override; }; } // namespace llvm diff --git a/llvm/include/llvm/Debuginfod/Debuginfod.h b/llvm/include/llvm/Debuginfod/Debuginfod.h index 496b24c..df7fd9f 100644 --- a/llvm/include/llvm/Debuginfod/Debuginfod.h +++ b/llvm/include/llvm/Debuginfod/Debuginfod.h @@ -20,10 +20,12 @@ #ifndef LLVM_DEBUGINFOD_DEBUGINFOD_H #define LLVM_DEBUGINFOD_DEBUGINFOD_H +#include "HTTPServer.h" + #include "llvm/ADT/Optional.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" -#include "llvm/Debuginfod/HTTPServer.h" +#include "llvm/Object/BuildID.h" #include "llvm/Support/Error.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Mutex.h" @@ -36,10 +38,6 @@ namespace llvm { -typedef ArrayRef BuildIDRef; - -typedef SmallVector BuildID; - /// Finds default array of Debuginfod server URLs by checking DEBUGINFOD_URLS /// environment variable. Expected> getDefaultDebuginfodUrls(); @@ -54,16 +52,16 @@ std::chrono::milliseconds getDefaultDebuginfodTimeout(); /// Fetches a specified source file by searching the default local cache /// directory and server URLs. -Expected getCachedOrDownloadSource(BuildIDRef ID, +Expected getCachedOrDownloadSource(object::BuildIDRef ID, StringRef SourceFilePath); /// Fetches an executable by searching the default local cache directory and /// server URLs. -Expected getCachedOrDownloadExecutable(BuildIDRef ID); +Expected getCachedOrDownloadExecutable(object::BuildIDRef ID); /// Fetches a debug binary by searching the default local cache directory and /// server URLs. -Expected getCachedOrDownloadDebuginfo(BuildIDRef ID); +Expected getCachedOrDownloadDebuginfo(object::BuildIDRef ID); /// Fetches any debuginfod artifact using the default local cache directory and /// server URLs. @@ -108,8 +106,8 @@ class DebuginfodCollection { sys::RWMutex DebugBinariesMutex; StringMap DebugBinaries; Error findBinaries(StringRef Path); - Expected> getDebugBinaryPath(BuildIDRef); - Expected> getBinaryPath(BuildIDRef); + Expected> getDebugBinaryPath(object::BuildIDRef); + Expected> getBinaryPath(object::BuildIDRef); // If the collection has not been updated since MinInterval, call update() and // return true. Otherwise return false. If update returns an error, return the // error. @@ -128,8 +126,8 @@ public: ThreadPool &Pool, double MinInterval); Error update(); Error updateForever(std::chrono::milliseconds Interval); - Expected findDebugBinaryPath(BuildIDRef); - Expected findBinaryPath(BuildIDRef); + Expected findDebugBinaryPath(object::BuildIDRef); + Expected findBinaryPath(object::BuildIDRef); }; struct DebuginfodServer { diff --git a/llvm/include/llvm/Object/BuildID.h b/llvm/include/llvm/Object/BuildID.h new file mode 100644 index 0000000..22f2b9a --- /dev/null +++ b/llvm/include/llvm/Object/BuildID.h @@ -0,0 +1,52 @@ +//===- llvm/Object/BuildID.h - Build ID -------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file declares a library for handling Build IDs and using them to find +/// debug info. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_OBJECT_BUILDID_H +#define LLVM_DEBUGINFO_OBJECT_BUILDID_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/SmallVector.h" + +namespace llvm { +namespace object { + +/// A build ID in binary form. +typedef SmallVector BuildID; + +/// A reference to a BuildID in binary form. +typedef ArrayRef BuildIDRef; + +class ObjectFile; + +/// Returns the build ID, if any, contained in the given object file. +Optional getBuildID(const ObjectFile *Obj); + +/// BuildIDFetcher searches local cache directories for debug info. +class BuildIDFetcher { +public: + BuildIDFetcher(std::vector DebugFileDirectories) + : DebugFileDirectories(std::move(DebugFileDirectories)) {} + virtual ~BuildIDFetcher() = default; + + /// Returns the path to the debug file with the given build ID. + virtual Optional fetch(BuildIDRef BuildID) const; + +private: + const std::vector DebugFileDirectories; +}; + +} // namespace object +} // namespace llvm + +#endif // LLVM_DEBUGINFO_OBJECT_BUILDID_H diff --git a/llvm/include/llvm/Object/ObjectFile.h b/llvm/include/llvm/Object/ObjectFile.h index 8754c22..7d81bc8 100644 --- a/llvm/include/llvm/Object/ObjectFile.h +++ b/llvm/include/llvm/Object/ObjectFile.h @@ -328,6 +328,8 @@ public: return section_iterator_range(section_begin(), section_end()); } + virtual bool hasDebugInfo() const; + /// The number of bytes used to represent an address in this object /// file format. virtual uint8_t getBytesInAddress() const = 0; diff --git a/llvm/lib/DebugInfo/Symbolize/CMakeLists.txt b/llvm/lib/DebugInfo/Symbolize/CMakeLists.txt index 47cb424..1d39cc6 100644 --- a/llvm/lib/DebugInfo/Symbolize/CMakeLists.txt +++ b/llvm/lib/DebugInfo/Symbolize/CMakeLists.txt @@ -1,5 +1,4 @@ add_llvm_component_library(LLVMSymbolize - DIFetcher.cpp DIPrinter.cpp Markup.cpp MarkupFilter.cpp diff --git a/llvm/lib/DebugInfo/Symbolize/DIFetcher.cpp b/llvm/lib/DebugInfo/Symbolize/DIFetcher.cpp deleted file mode 100644 index 119830d..0000000 --- a/llvm/lib/DebugInfo/Symbolize/DIFetcher.cpp +++ /dev/null @@ -1,57 +0,0 @@ -//===-- lib/DebugInfo/Symbolize/DIFetcher.cpp -----------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -/// -/// \file -/// This file defines the implementation of the local debug info fetcher, which -/// searches cache directories. -/// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/Symbolize/DIFetcher.h" - -#include "llvm/Support/FileSystem.h" -#include "llvm/Support/Path.h" - -namespace llvm { -namespace symbolize { - -Optional -LocalDIFetcher::fetchBuildID(ArrayRef BuildID) const { - auto GetDebugPath = [&](StringRef Directory) { - SmallString<128> Path{Directory}; - 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()) { - 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)) - return std::string(Path); - } else { - for (const auto &Directory : DebugFileDirectory) { - // Try /.build-id/../... - SmallString<128> Path = GetDebugPath(Directory); - if (llvm::sys::fs::exists(Path)) - return std::string(Path); - } - } - return None; -} - -} // namespace symbolize -} // namespace llvm diff --git a/llvm/lib/DebugInfo/Symbolize/Symbolize.cpp b/llvm/lib/DebugInfo/Symbolize/Symbolize.cpp index c239d4c..497b24a 100644 --- a/llvm/lib/DebugInfo/Symbolize/Symbolize.cpp +++ b/llvm/lib/DebugInfo/Symbolize/Symbolize.cpp @@ -16,9 +16,9 @@ #include "llvm/DebugInfo/DWARF/DWARFContext.h" #include "llvm/DebugInfo/PDB/PDB.h" #include "llvm/DebugInfo/PDB/PDBContext.h" -#include "llvm/DebugInfo/Symbolize/DIFetcher.h" #include "llvm/DebugInfo/Symbolize/SymbolizableObjectFile.h" #include "llvm/Demangle/Demangle.h" +#include "llvm/Object/BuildID.h" #include "llvm/Object/COFF.h" #include "llvm/Object/ELFObjectFile.h" #include "llvm/Object/MachO.h" @@ -45,7 +45,9 @@ namespace symbolize { LLVMSymbolizer::LLVMSymbolizer() = default; -LLVMSymbolizer::LLVMSymbolizer(const Options &Opts) : Opts(Opts) {} +LLVMSymbolizer::LLVMSymbolizer(const Options &Opts) + : Opts(Opts), + BIDFetcher(std::make_unique(Opts.DebugFileDirectory)) {} LLVMSymbolizer::~LLVMSymbolizer() = default; @@ -307,43 +309,8 @@ bool darwinDsymMatchesBinary(const MachOObjectFile *DbgObj, return !memcmp(dbg_uuid.data(), bin_uuid.data(), dbg_uuid.size()); } -template -Optional> getBuildID(const ELFFile &Obj) { - auto PhdrsOrErr = Obj.program_headers(); - if (!PhdrsOrErr) { - consumeError(PhdrsOrErr.takeError()); - return {}; - } - for (const auto &P : *PhdrsOrErr) { - if (P.p_type != ELF::PT_NOTE) - continue; - Error Err = Error::success(); - for (auto N : Obj.notes(P, Err)) - if (N.getType() == ELF::NT_GNU_BUILD_ID && - N.getName() == ELF::ELF_NOTE_GNU) - return N.getDesc(); - consumeError(std::move(Err)); - } - return {}; -} - } // 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) { @@ -471,29 +438,16 @@ bool LLVMSymbolizer::getOrFindDebugBinary(const ArrayRef BuildID, Result = I->second; return true; } - auto recordPath = [&](StringRef Path) { - Result = Path.str(); + if (!BIDFetcher) + return false; + if (Optional Path = BIDFetcher->fetch(BuildID)) { + Result = *Path; auto InsertResult = BuildIDPaths.insert({BuildIDStr, Result}); assert(InsertResult.second); (void)InsertResult; - }; - - Optional Path; - Path = LocalDIFetcher(Opts.DebugFileDirectory).fetchBuildID(BuildID); - if (Path) { - recordPath(*Path); return true; } - // Try caller-provided debug info fetchers. - for (const std::unique_ptr &Fetcher : DIFetchers) { - Path = Fetcher->fetchBuildID(BuildID); - if (Path) { - recordPath(*Path); - return true; - } - } - return false; } diff --git a/llvm/lib/Debuginfod/DIFetcher.cpp b/llvm/lib/Debuginfod/BuildIDFetcher.cpp similarity index 74% rename from llvm/lib/Debuginfod/DIFetcher.cpp rename to llvm/lib/Debuginfod/BuildIDFetcher.cpp index f0c1346..3b74877 100644 --- a/llvm/lib/Debuginfod/DIFetcher.cpp +++ b/llvm/lib/Debuginfod/BuildIDFetcher.cpp @@ -1,4 +1,4 @@ -//===- llvm/DebugInfod/DIFetcher.cpp - Debug info fetcher -----------------===// +//===- llvm/DebugInfod/BuildIDFetcher.cpp - Build ID fetcher --------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -12,14 +12,17 @@ /// //===----------------------------------------------------------------------===// -#include "llvm/Debuginfod/DIFetcher.h" +#include "llvm/Debuginfod/BuildIDFetcher.h" #include "llvm/Debuginfod/Debuginfod.h" using namespace llvm; Optional -DebuginfodDIFetcher::fetchBuildID(ArrayRef BuildID) const { +DebuginfodFetcher::fetch(ArrayRef BuildID) const { + if (Optional Path = BuildIDFetcher::fetch(BuildID)) + return std::move(*Path); + Expected PathOrErr = getCachedOrDownloadDebuginfo(BuildID); if (PathOrErr) return *PathOrErr; diff --git a/llvm/lib/Debuginfod/CMakeLists.txt b/llvm/lib/Debuginfod/CMakeLists.txt index 0bd6ad1..b1329bd 100644 --- a/llvm/lib/Debuginfod/CMakeLists.txt +++ b/llvm/lib/Debuginfod/CMakeLists.txt @@ -16,8 +16,8 @@ endif() # Note: This isn't a component, since that could potentially add a libcurl # dependency to libLLVM. add_llvm_library(LLVMDebuginfod + BuildIDFetcher.cpp Debuginfod.cpp - DIFetcher.cpp HTTPClient.cpp HTTPServer.cpp diff --git a/llvm/lib/Debuginfod/Debuginfod.cpp b/llvm/lib/Debuginfod/Debuginfod.cpp index 29fdd6f..ee5cc51 100644 --- a/llvm/lib/Debuginfod/Debuginfod.cpp +++ b/llvm/lib/Debuginfod/Debuginfod.cpp @@ -27,9 +27,8 @@ #include "llvm/DebugInfo/DWARF/DWARFContext.h" #include "llvm/DebugInfo/Symbolize/Symbolize.h" #include "llvm/Debuginfod/HTTPClient.h" -#include "llvm/Object/Binary.h" +#include "llvm/Object/BuildID.h" #include "llvm/Object/ELFObjectFile.h" -#include "llvm/Object/ObjectFile.h" #include "llvm/Support/CachePruning.h" #include "llvm/Support/Caching.h" #include "llvm/Support/Errc.h" @@ -43,6 +42,9 @@ #include namespace llvm { + +using llvm::object::BuildIDRef; + static std::string uniqueKey(llvm::StringRef S) { return utostr(xxHash64(S)); } // Returns a binary BuildID as a normalized hex string. @@ -301,16 +303,6 @@ Error DebuginfodCollection::updateForever(std::chrono::milliseconds Interval) { llvm_unreachable("updateForever loop should never end"); } -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); @@ -370,12 +362,12 @@ Error DebuginfodCollection::findBinaries(StringRef Path) { if (!Object) continue; - Optional ID = symbolize::getBuildID(Object); + Optional ID = getBuildID(Object); if (!ID) continue; std::string IDString = buildIDToString(ID.value()); - if (isDebugBinary(Object)) { + if (Object->hasDebugInfo()) { std::lock_guard DebugBinariesGuard(DebugBinariesMutex); DebugBinaries[IDString] = FilePath; } else { @@ -485,7 +477,7 @@ DebuginfodServer::DebuginfodServer(DebuginfodLog &Log, {404, "text/plain", "Build ID is not a hex string\n"}); return; } - BuildID ID(IDString.begin(), IDString.end()); + object::BuildID ID(IDString.begin(), IDString.end()); Expected PathOrErr = Collection.findDebugBinaryPath(ID); if (Error Err = PathOrErr.takeError()) { consumeError(std::move(Err)); @@ -503,7 +495,7 @@ DebuginfodServer::DebuginfodServer(DebuginfodLog &Log, {404, "text/plain", "Build ID is not a hex string\n"}); return; } - BuildID ID(IDString.begin(), IDString.end()); + object::BuildID ID(IDString.begin(), IDString.end()); Expected PathOrErr = Collection.findBinaryPath(ID); if (Error Err = PathOrErr.takeError()) { consumeError(std::move(Err)); diff --git a/llvm/lib/Object/BuildID.cpp b/llvm/lib/Object/BuildID.cpp new file mode 100644 index 0000000..68b6f43 --- /dev/null +++ b/llvm/lib/Object/BuildID.cpp @@ -0,0 +1,93 @@ +//===- llvm/Object/BuildID.cpp - Build ID ---------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file defines a library for handling Build IDs and using them to find +/// debug info. +/// +//===----------------------------------------------------------------------===// + +#include "llvm/Object/BuildID.h" + +#include "llvm/Object/ELFObjectFile.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Path.h" + +namespace llvm { +namespace object { + +namespace { + +template +Optional getBuildID(const ELFFile &Obj) { + auto PhdrsOrErr = Obj.program_headers(); + if (!PhdrsOrErr) { + consumeError(PhdrsOrErr.takeError()); + return {}; + } + for (const auto &P : *PhdrsOrErr) { + if (P.p_type != ELF::PT_NOTE) + continue; + Error Err = Error::success(); + for (auto N : Obj.notes(P, Err)) + if (N.getType() == ELF::NT_GNU_BUILD_ID && + N.getName() == ELF::ELF_NOTE_GNU) + return N.getDesc(); + consumeError(std::move(Err)); + } + return {}; +} + +} // namespace + +Optional getBuildID(const ObjectFile *Obj) { + if (auto *O = dyn_cast>(Obj)) + return getBuildID(O->getELFFile()); + if (auto *O = dyn_cast>(Obj)) + return getBuildID(O->getELFFile()); + if (auto *O = dyn_cast>(Obj)) + return getBuildID(O->getELFFile()); + if (auto *O = dyn_cast>(Obj)) + return getBuildID(O->getELFFile()); + return None; +} + +Optional BuildIDFetcher::fetch(BuildIDRef BuildID) const { + auto GetDebugPath = [&](StringRef Directory) { + SmallString<128> Path{Directory}; + sys::path::append(Path, ".build-id", + llvm::toHex(BuildID[0], /*LowerCase=*/true), + llvm::toHex(BuildID.slice(1), /*LowerCase=*/true)); + Path += ".debug"; + return Path; + }; + if (DebugFileDirectories.empty()) { + 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)) + return std::string(Path); + } else { + for (const auto &Directory : DebugFileDirectories) { + // Try /.build-id/../... + SmallString<128> Path = GetDebugPath(Directory); + if (llvm::sys::fs::exists(Path)) + return std::string(Path); + } + } + return None; +} + +} // namespace object +} // namespace llvm diff --git a/llvm/lib/Object/CMakeLists.txt b/llvm/lib/Object/CMakeLists.txt index 3dce083..5742176 100644 --- a/llvm/lib/Object/CMakeLists.txt +++ b/llvm/lib/Object/CMakeLists.txt @@ -2,6 +2,7 @@ add_llvm_component_library(LLVMObject Archive.cpp ArchiveWriter.cpp Binary.cpp + BuildID.cpp COFFImportFile.cpp COFFModuleDefinition.cpp COFFObjectFile.cpp diff --git a/llvm/lib/Object/ObjectFile.cpp b/llvm/lib/Object/ObjectFile.cpp index bc8e602..56a1d09 100644 --- a/llvm/lib/Object/ObjectFile.cpp +++ b/llvm/lib/Object/ObjectFile.cpp @@ -96,6 +96,11 @@ bool ObjectFile::isBerkeleyData(DataRefImpl Sec) const { bool ObjectFile::isDebugSection(DataRefImpl Sec) const { return false; } +bool ObjectFile::hasDebugInfo() const { + return any_of(sections(), + [](SectionRef Sec) { return Sec.isDebugSection(); }); +} + Expected ObjectFile::getRelocatedSection(DataRefImpl Sec) const { return section_iterator(SectionRef(Sec, this)); diff --git a/llvm/tools/llvm-debuginfod-find/CMakeLists.txt b/llvm/tools/llvm-debuginfod-find/CMakeLists.txt index a045560..b98c431 100644 --- a/llvm/tools/llvm-debuginfod-find/CMakeLists.txt +++ b/llvm/tools/llvm-debuginfod-find/CMakeLists.txt @@ -1,6 +1,6 @@ set(LLVM_LINK_COMPONENTS + Object Support - Symbolize ) add_llvm_tool(llvm-debuginfod-find llvm-debuginfod-find.cpp diff --git a/llvm/tools/llvm-debuginfod-find/llvm-debuginfod-find.cpp b/llvm/tools/llvm-debuginfod-find/llvm-debuginfod-find.cpp index 373353c..86b4b22 100644 --- a/llvm/tools/llvm-debuginfod-find/llvm-debuginfod-find.cpp +++ b/llvm/tools/llvm-debuginfod-find/llvm-debuginfod-find.cpp @@ -15,7 +15,7 @@ /// //===----------------------------------------------------------------------===// -#include "llvm/DebugInfo/Symbolize/DIFetcher.h" +#include "llvm/Debuginfod/BuildIDFetcher.h" #include "llvm/Debuginfod/Debuginfod.h" #include "llvm/Debuginfod/HTTPClient.h" #include "llvm/Support/CommandLine.h" @@ -67,7 +67,7 @@ static cl::list DebugFileDirectory( ExitOnError ExitOnErr; -static std::string fetchDebugInfo(ArrayRef BuildID); +static std::string fetchDebugInfo(object::BuildIDRef BuildID); int main(int argc, char **argv) { InitLLVM X(argc, argv); @@ -92,7 +92,7 @@ int main(int argc, char **argv) { errs() << "Build ID " << InputBuildID << " is not a hex string.\n"; exit(1); } - BuildID ID(IDString.begin(), IDString.end()); + object::BuildID ID(IDString.begin(), IDString.end()); std::string Path; if (FetchSource != "") @@ -116,12 +116,12 @@ int main(int argc, char **argv) { outs() << Path << "\n"; } -// Find a debug binary in local build ID directories and via debuginfod. -std::string fetchDebugInfo(ArrayRef BuildID) { - if (!DebugFileDirectory.empty()) { - symbolize::LocalDIFetcher Fetcher(DebugFileDirectory); - if (Optional LocalPath = Fetcher.fetchBuildID(BuildID)) - return *LocalPath; - } - return ExitOnErr(getCachedOrDownloadDebuginfo(BuildID)); +// Find a debug file in local build ID directories and via debuginfod. +std::string fetchDebugInfo(object::BuildIDRef BuildID) { + if (Optional Path = + DebuginfodFetcher(DebugFileDirectory).fetch(BuildID)) + return *Path; + errs() << "Build ID " << llvm::toHex(BuildID, /*Lowercase=*/true) + << " could not be found."; + exit(1); } diff --git a/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp b/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp index 138b069..a59364a 100644 --- a/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp +++ b/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp @@ -23,7 +23,7 @@ #include "llvm/DebugInfo/Symbolize/MarkupFilter.h" #include "llvm/DebugInfo/Symbolize/SymbolizableModule.h" #include "llvm/DebugInfo/Symbolize/Symbolize.h" -#include "llvm/Debuginfod/DIFetcher.h" +#include "llvm/Debuginfod/BuildIDFetcher.h" #include "llvm/Debuginfod/Debuginfod.h" #include "llvm/Debuginfod/HTTPClient.h" #include "llvm/Option/Arg.h" @@ -109,30 +109,31 @@ enum class Command { Frame, }; -static void enableDebuginfod(LLVMSymbolizer &Symbolizer) { +static void enableDebuginfod(LLVMSymbolizer &Symbolizer, + const opt::ArgList &Args) { static bool IsEnabled = false; if (IsEnabled) return; IsEnabled = true; // Look up symbols using the debuginfod client. - Symbolizer.addDIFetcher(std::make_unique()); + Symbolizer.setBuildIDFetcher(std::make_unique( + Args.getAllArgValues(OPT_debug_file_directory_EQ))); // The HTTPClient must be initialized for use by the debuginfod client. HTTPClient::initialize(); } -static SmallVector parseBuildID(StringRef Str) { +static object::BuildID parseBuildID(StringRef Str) { std::string Bytes; if (!tryGetFromHex(Str, Bytes)) return {}; ArrayRef BuildID(reinterpret_cast(Bytes.data()), Bytes.size()); - return SmallVector(BuildID.begin(), BuildID.end()); + return object::BuildID(BuildID.begin(), BuildID.end()); } static bool parseCommand(StringRef BinaryName, bool IsAddr2Line, StringRef InputString, Command &Cmd, - std::string &ModuleName, - SmallVectorImpl &BuildID, + std::string &ModuleName, object::BuildID &BuildID, uint64_t &ModuleOffset) { const char kDelimiters[] = " \n\r"; ModuleName = ""; @@ -249,13 +250,13 @@ void executeCommand(StringRef ModuleName, const T &ModuleSpec, Command Cmd, } static void symbolizeInput(const opt::InputArgList &Args, - ArrayRef IncomingBuildID, + object::BuildIDRef IncomingBuildID, uint64_t AdjustVMA, bool IsAddr2Line, OutputStyle Style, StringRef InputString, LLVMSymbolizer &Symbolizer, DIPrinter &Printer) { Command Cmd; std::string ModuleName; - SmallVector BuildID(IncomingBuildID.begin(), IncomingBuildID.end()); + object::BuildID BuildID(IncomingBuildID.begin(), IncomingBuildID.end()); uint64_t Offset = 0; if (!parseCommand(Args.getLastArgValue(OPT_obj_EQ), IsAddr2Line, StringRef(InputString), Cmd, ModuleName, BuildID, Offset)) { @@ -266,7 +267,7 @@ static void symbolizeInput(const opt::InputArgList &Args, if (!BuildID.empty()) { assert(ModuleName.empty()); if (!Args.hasArg(OPT_no_debuginfod)) - enableDebuginfod(Symbolizer); + enableDebuginfod(Symbolizer, Args); std::string BuildIDStr = toHex(BuildID); executeCommand(BuildIDStr, BuildID, Cmd, Offset, AdjustVMA, ShouldInline, Style, Symbolizer, Printer); @@ -351,14 +352,13 @@ static Optional parseColorArg(const opt::InputArgList &Args) { return None; } -static SmallVector parseBuildIDArg(const opt::InputArgList &Args, - int ID) { +static object::BuildID parseBuildIDArg(const opt::InputArgList &Args, int ID) { const opt::Arg *A = Args.getLastArg(ID); if (!A) return {}; StringRef V(A->getValue()); - SmallVector BuildID = parseBuildID(V); + object::BuildID BuildID = parseBuildID(V); if (BuildID.empty()) { errs() << A->getSpelling() + ": expected a build ID, but got '" + V + "'\n"; exit(1); @@ -447,7 +447,7 @@ int main(int argc, char **argv) { !ExitOnErr(getDefaultDebuginfodUrls()).empty(); if (Args.hasFlag(OPT_debuginfod, OPT_no_debuginfod, ShouldUseDebuginfodByDefault)) - enableDebuginfod(Symbolizer); + enableDebuginfod(Symbolizer, Args); if (Args.hasArg(OPT_filter_markup)) { filterMarkup(Args, Symbolizer); @@ -468,7 +468,7 @@ int main(int argc, char **argv) { errs() << "error: cannot specify both --build-id and --obj\n"; return EXIT_FAILURE; } - SmallVector BuildID = parseBuildIDArg(Args, OPT_build_id_EQ); + object::BuildID BuildID = parseBuildIDArg(Args, OPT_build_id_EQ); std::unique_ptr Printer; if (Style == OutputStyle::GNU) -- 2.7.4