[NFC] [Object] Create library to fetch debug info by build ID.
authorDaniel Thornburgh <dthorn@google.com>
Tue, 23 Aug 2022 20:39:33 +0000 (13:39 -0700)
committerDaniel Thornburgh <dthorn@google.com>
Wed, 28 Sep 2022 20:35:35 +0000 (13:35 -0700)
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

18 files changed:
llvm/include/llvm/DebugInfo/Symbolize/DIFetcher.h [deleted file]
llvm/include/llvm/DebugInfo/Symbolize/Symbolize.h
llvm/include/llvm/Debuginfod/BuildIDFetcher.h [moved from llvm/include/llvm/Debuginfod/DIFetcher.h with 55% similarity]
llvm/include/llvm/Debuginfod/Debuginfod.h
llvm/include/llvm/Object/BuildID.h [new file with mode: 0644]
llvm/include/llvm/Object/ObjectFile.h
llvm/lib/DebugInfo/Symbolize/CMakeLists.txt
llvm/lib/DebugInfo/Symbolize/DIFetcher.cpp [deleted file]
llvm/lib/DebugInfo/Symbolize/Symbolize.cpp
llvm/lib/Debuginfod/BuildIDFetcher.cpp [moved from llvm/lib/Debuginfod/DIFetcher.cpp with 74% similarity]
llvm/lib/Debuginfod/CMakeLists.txt
llvm/lib/Debuginfod/Debuginfod.cpp
llvm/lib/Object/BuildID.cpp [new file with mode: 0644]
llvm/lib/Object/CMakeLists.txt
llvm/lib/Object/ObjectFile.cpp
llvm/tools/llvm-debuginfod-find/CMakeLists.txt
llvm/tools/llvm-debuginfod-find/llvm-debuginfod-find.cpp
llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp

diff --git a/llvm/include/llvm/DebugInfo/Symbolize/DIFetcher.h b/llvm/include/llvm/DebugInfo/Symbolize/DIFetcher.h
deleted file mode 100644 (file)
index c5340b5..0000000
+++ /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 <cstdint>
-#include <string>
-
-#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<std::string>
-  fetchBuildID(ArrayRef<uint8_t> BuildID) const = 0;
-};
-
-/// LocalDIFetcher searches local cache directories for debug info.
-class LocalDIFetcher : public DIFetcher {
-public:
-  LocalDIFetcher(ArrayRef<std::string> DebugFileDirectory)
-      : DebugFileDirectory(DebugFileDirectory){};
-  virtual ~LocalDIFetcher() = default;
-
-  Optional<std::string> fetchBuildID(ArrayRef<uint8_t> BuildID) const override;
-
-private:
-  const ArrayRef<std::string> DebugFileDirectory;
-};
-
-} // end namespace symbolize
-} // end namespace llvm
-
-#endif // LLVM_DEBUGINFO_SYMBOLIZE_DIFETCHER_H
index f233a18..c633c89 100644 (file)
@@ -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 <algorithm>
 #include <cstdint>
@@ -115,8 +115,8 @@ public:
   DemangleName(const std::string &Name,
                const SymbolizableModule *DbiModuleDescriptor);
 
-  void addDIFetcher(std::unique_ptr<DIFetcher> Fetcher) {
-    DIFetchers.push_back(std::move(Fetcher));
+  void setBuildIDFetcher(std::unique_ptr<BuildIDFetcher> Fetcher) {
+    BIDFetcher = std::move(Fetcher);
   }
 
 private:
@@ -211,7 +211,7 @@ private:
 
   Options Opts;
 
-  SmallVector<std::unique_ptr<DIFetcher>> DIFetchers;
+  std::unique_ptr<BuildIDFetcher> BIDFetcher;
 };
 
 // A binary intrusively linked into a LRU cache list. If the binary is empty,
@@ -243,8 +243,6 @@ private:
   std::function<void()> Evictor;
 };
 
-Optional<ArrayRef<uint8_t>> getBuildID(const ELFObjectFileBase *Obj);
-
 } // end namespace symbolize
 } // end namespace llvm
 
similarity index 55%
rename from llvm/include/llvm/Debuginfod/DIFetcher.h
rename to llvm/include/llvm/Debuginfod/BuildIDFetcher.h
index d398fd9..505db58 100644 (file)
@@ -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<std::string> 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<std::string> fetchBuildID(ArrayRef<uint8_t> BuildID) const override;
+  /// the resulting file.
+  Optional<std::string> fetch(object::BuildIDRef BuildID) const override;
 };
 
 } // namespace llvm
index 496b24c..df7fd9f 100644 (file)
 #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"
 
 namespace llvm {
 
-typedef ArrayRef<uint8_t> BuildIDRef;
-
-typedef SmallVector<uint8_t, 10> BuildID;
-
 /// Finds default array of Debuginfod server URLs by checking DEBUGINFOD_URLS
 /// environment variable.
 Expected<SmallVector<StringRef>> 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<std::string> getCachedOrDownloadSource(BuildIDRef ID,
+Expected<std::string> getCachedOrDownloadSource(object::BuildIDRef ID,
                                                 StringRef SourceFilePath);
 
 /// Fetches an executable by searching the default local cache directory and
 /// server URLs.
-Expected<std::string> getCachedOrDownloadExecutable(BuildIDRef ID);
+Expected<std::string> getCachedOrDownloadExecutable(object::BuildIDRef ID);
 
 /// Fetches a debug binary by searching the default local cache directory and
 /// server URLs.
-Expected<std::string> getCachedOrDownloadDebuginfo(BuildIDRef ID);
+Expected<std::string> 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<std::string> DebugBinaries;
   Error findBinaries(StringRef Path);
-  Expected<Optional<std::string>> getDebugBinaryPath(BuildIDRef);
-  Expected<Optional<std::string>> getBinaryPath(BuildIDRef);
+  Expected<Optional<std::string>> getDebugBinaryPath(object::BuildIDRef);
+  Expected<Optional<std::string>> 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<std::string> findDebugBinaryPath(BuildIDRef);
-  Expected<std::string> findBinaryPath(BuildIDRef);
+  Expected<std::string> findDebugBinaryPath(object::BuildIDRef);
+  Expected<std::string> 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 (file)
index 0000000..22f2b9a
--- /dev/null
@@ -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<uint8_t, 10> BuildID;
+
+/// A reference to a BuildID in binary form.
+typedef ArrayRef<uint8_t> BuildIDRef;
+
+class ObjectFile;
+
+/// Returns the build ID, if any, contained in the given object file.
+Optional<BuildIDRef> getBuildID(const ObjectFile *Obj);
+
+/// BuildIDFetcher searches local cache directories for debug info.
+class BuildIDFetcher {
+public:
+  BuildIDFetcher(std::vector<std::string> DebugFileDirectories)
+      : DebugFileDirectories(std::move(DebugFileDirectories)) {}
+  virtual ~BuildIDFetcher() = default;
+
+  /// Returns the path to the debug file with the given build ID.
+  virtual Optional<std::string> fetch(BuildIDRef BuildID) const;
+
+private:
+  const std::vector<std::string> DebugFileDirectories;
+};
+
+} // namespace object
+} // namespace llvm
+
+#endif // LLVM_DEBUGINFO_OBJECT_BUILDID_H
index 8754c22..7d81bc8 100644 (file)
@@ -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;
index 47cb424..1d39cc6 100644 (file)
@@ -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 (file)
index 119830d..0000000
+++ /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<std::string>
-LocalDIFetcher::fetchBuildID(ArrayRef<uint8_t> 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 <debug-file-directory>/.build-id/../...
-      SmallString<128> Path = GetDebugPath(Directory);
-      if (llvm::sys::fs::exists(Path))
-        return std::string(Path);
-    }
-  }
-  return None;
-}
-
-} // namespace symbolize
-} // namespace llvm
index c239d4c..497b24a 100644 (file)
@@ -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<BuildIDFetcher>(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 <typename ELFT>
-Optional<ArrayRef<uint8_t>> getBuildID(const ELFFile<ELFT> &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<ArrayRef<uint8_t>> getBuildID(const ELFObjectFileBase *Obj) {
-  Optional<ArrayRef<uint8_t>> BuildID;
-  if (auto *O = dyn_cast<ELFObjectFile<ELF32LE>>(Obj))
-    BuildID = getBuildID(O->getELFFile());
-  else if (auto *O = dyn_cast<ELFObjectFile<ELF32BE>>(Obj))
-    BuildID = getBuildID(O->getELFFile());
-  else if (auto *O = dyn_cast<ELFObjectFile<ELF64LE>>(Obj))
-    BuildID = getBuildID(O->getELFFile());
-  else if (auto *O = dyn_cast<ELFObjectFile<ELF64BE>>(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<uint8_t> BuildID,
     Result = I->second;
     return true;
   }
-  auto recordPath = [&](StringRef Path) {
-    Result = Path.str();
+  if (!BIDFetcher)
+    return false;
+  if (Optional<std::string> Path = BIDFetcher->fetch(BuildID)) {
+    Result = *Path;
     auto InsertResult = BuildIDPaths.insert({BuildIDStr, Result});
     assert(InsertResult.second);
     (void)InsertResult;
-  };
-
-  Optional<std::string> Path;
-  Path = LocalDIFetcher(Opts.DebugFileDirectory).fetchBuildID(BuildID);
-  if (Path) {
-    recordPath(*Path);
     return true;
   }
 
-  // Try caller-provided debug info fetchers.
-  for (const std::unique_ptr<DIFetcher> &Fetcher : DIFetchers) {
-    Path = Fetcher->fetchBuildID(BuildID);
-    if (Path) {
-      recordPath(*Path);
-      return true;
-    }
-  }
-
   return false;
 }
 
similarity index 74%
rename from llvm/lib/Debuginfod/DIFetcher.cpp
rename to llvm/lib/Debuginfod/BuildIDFetcher.cpp
index f0c1346..3b74877 100644 (file)
@@ -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.
 ///
 //===----------------------------------------------------------------------===//
 
-#include "llvm/Debuginfod/DIFetcher.h"
+#include "llvm/Debuginfod/BuildIDFetcher.h"
 
 #include "llvm/Debuginfod/Debuginfod.h"
 
 using namespace llvm;
 
 Optional<std::string>
-DebuginfodDIFetcher::fetchBuildID(ArrayRef<uint8_t> BuildID) const {
+DebuginfodFetcher::fetch(ArrayRef<uint8_t> BuildID) const {
+  if (Optional<std::string> Path = BuildIDFetcher::fetch(BuildID))
+    return std::move(*Path);
+
   Expected<std::string> PathOrErr = getCachedOrDownloadDebuginfo(BuildID);
   if (PathOrErr)
     return *PathOrErr;
index 0bd6ad1..b1329bd 100644 (file)
@@ -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
 
index 29fdd6f..ee5cc51 100644 (file)
@@ -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 <thread>
 
 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<DWARFContext> 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<BuildIDRef> ID = symbolize::getBuildID(Object);
+        Optional<BuildIDRef> ID = getBuildID(Object);
         if (!ID)
           continue;
 
         std::string IDString = buildIDToString(ID.value());
-        if (isDebugBinary(Object)) {
+        if (Object->hasDebugInfo()) {
           std::lock_guard<sys::RWMutex> 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<std::string> 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<std::string> 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 (file)
index 0000000..68b6f43
--- /dev/null
@@ -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 <typename ELFT>
+Optional<BuildIDRef> getBuildID(const ELFFile<ELFT> &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<BuildIDRef> getBuildID(const ObjectFile *Obj) {
+  if (auto *O = dyn_cast<ELFObjectFile<ELF32LE>>(Obj))
+    return getBuildID(O->getELFFile());
+  if (auto *O = dyn_cast<ELFObjectFile<ELF32BE>>(Obj))
+    return getBuildID(O->getELFFile());
+  if (auto *O = dyn_cast<ELFObjectFile<ELF64LE>>(Obj))
+    return getBuildID(O->getELFFile());
+  if (auto *O = dyn_cast<ELFObjectFile<ELF64BE>>(Obj))
+    return getBuildID(O->getELFFile());
+  return None;
+}
+
+Optional<std::string> 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 <debug-file-directory>/.build-id/../...
+      SmallString<128> Path = GetDebugPath(Directory);
+      if (llvm::sys::fs::exists(Path))
+        return std::string(Path);
+    }
+  }
+  return None;
+}
+
+} // namespace object
+} // namespace llvm
index 3dce083..5742176 100644 (file)
@@ -2,6 +2,7 @@ add_llvm_component_library(LLVMObject
   Archive.cpp
   ArchiveWriter.cpp
   Binary.cpp
+  BuildID.cpp
   COFFImportFile.cpp
   COFFModuleDefinition.cpp
   COFFObjectFile.cpp
index bc8e602..56a1d09 100644 (file)
@@ -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<section_iterator>
 ObjectFile::getRelocatedSection(DataRefImpl Sec) const {
   return section_iterator(SectionRef(Sec, this));
index a045560..b98c431 100644 (file)
@@ -1,6 +1,6 @@
 set(LLVM_LINK_COMPONENTS
+  Object
   Support
-  Symbolize
   )
 add_llvm_tool(llvm-debuginfod-find
   llvm-debuginfod-find.cpp
index 373353c..86b4b22 100644 (file)
@@ -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<std::string> DebugFileDirectory(
 
 ExitOnError ExitOnErr;
 
-static std::string fetchDebugInfo(ArrayRef<uint8_t> 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<uint8_t> BuildID) {
-  if (!DebugFileDirectory.empty()) {
-    symbolize::LocalDIFetcher Fetcher(DebugFileDirectory);
-    if (Optional<std::string> 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<std::string> Path =
+          DebuginfodFetcher(DebugFileDirectory).fetch(BuildID))
+    return *Path;
+  errs() << "Build ID " << llvm::toHex(BuildID, /*Lowercase=*/true)
+         << " could not be found.";
+  exit(1);
 }
index 138b069..a59364a 100644 (file)
@@ -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<DebuginfodDIFetcher>());
+  Symbolizer.setBuildIDFetcher(std::make_unique<DebuginfodFetcher>(
+      Args.getAllArgValues(OPT_debug_file_directory_EQ)));
   // The HTTPClient must be initialized for use by the debuginfod client.
   HTTPClient::initialize();
 }
 
-static SmallVector<uint8_t> parseBuildID(StringRef Str) {
+static object::BuildID parseBuildID(StringRef Str) {
   std::string Bytes;
   if (!tryGetFromHex(Str, Bytes))
     return {};
   ArrayRef<uint8_t> BuildID(reinterpret_cast<const uint8_t *>(Bytes.data()),
                             Bytes.size());
-  return SmallVector<uint8_t>(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<uint8_t> &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<uint8_t> IncomingBuildID,
+                           object::BuildIDRef IncomingBuildID,
                            uint64_t AdjustVMA, bool IsAddr2Line,
                            OutputStyle Style, StringRef InputString,
                            LLVMSymbolizer &Symbolizer, DIPrinter &Printer) {
   Command Cmd;
   std::string ModuleName;
-  SmallVector<uint8_t> 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<bool> parseColorArg(const opt::InputArgList &Args) {
   return None;
 }
 
-static SmallVector<uint8_t> 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<uint8_t> 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<uint8_t> BuildID = parseBuildIDArg(Args, OPT_build_id_EQ);
+  object::BuildID BuildID = parseBuildIDArg(Args, OPT_build_id_EQ);
 
   std::unique_ptr<DIPrinter> Printer;
   if (Style == OutputStyle::GNU)