[llvm-objdump] Add --build-id flag for debuginfod lookups without binary.
authorDaniel Thornburgh <dthorn@google.com>
Tue, 20 Sep 2022 17:51:14 +0000 (10:51 -0700)
committerDaniel Thornburgh <dthorn@google.com>
Tue, 4 Oct 2022 20:44:25 +0000 (13:44 -0700)
Adding a --build-id flag allows handling binaries that are referenced in
logs from remote systems, but that aren't necessarily present on the
local machine. These are fetched via debuginfod and handled as if they
were input filenames.

Reviewed By: jhenderson, MaskRay

Differential Revision: https://reviews.llvm.org/D133992

llvm/docs/CommandGuide/llvm-objdump.rst
llvm/test/tools/llvm-objdump/debuginfod.test
llvm/tools/llvm-objdump/ObjdumpOpts.td
llvm/tools/llvm-objdump/llvm-objdump.cpp

index 654a48f..7879ac1 100644 (file)
@@ -125,6 +125,11 @@ OPTIONS
   Specify the target architecture when disassembling. Use :option:`--version`
   for a list of available targets.
 
+.. option:: --build-id=<string>
+
+  Look up the object using the given build ID, specified as a hexadecimal
+  string. The found object is handled as if it were an input filename.
+
 .. option:: -C, --demangle
 
   Demangle symbol names in the output.
index c8f871d..a2ef5a9 100644 (file)
@@ -61,6 +61,23 @@ RUN:   --debuginfod %t/stripped 2> %t.err | \
 RUN:   FileCheck %s --check-prefix=NOTFOUND
 RUN: count 0 < %t.err
 
+# Use debuginfod to look up build IDs.
+RUN: env DEBUGINFOD_CACHE_PATH=%t llvm-objdump -d --source \
+RUN:   --build-id 1512f769114c011387393822af15dd660c080295 | \
+RUN:   FileCheck %s --check-prefix=FOUND
+
+# Produce an error if malformed (not a hex string).
+RUN: not env DEBUGINFOD_CACHE_PATH=%t llvm-objdump -d --source --build-id foo \
+RUN:   2> %t.err
+RUN: FileCheck %s --check-prefix=MALFORMEDERROR --input-file %t.err
+MALFORMEDERROR: error: --build-id: expected a build ID, but got 'foo'
+
+# Produce an error if not found.
+RUN: not env DEBUGINFOD_CACHE_PATH=%t llvm-objdump -d --source --build-id abc \
+RUN:   2> %t.err
+RUN: FileCheck %s --check-prefix=NOTFOUNDERROR --input-file %t.err
+NOTFOUNDERROR: error: --build-id: could not find build ID 'abc'
+
 # Use debuginfod to recover symbols.
 RUN: llvm-strip --strip-sections %t/stripped
 RUN: env DEBUGINFOD_CACHE_PATH=%t llvm-objdump -d --debuginfod \
index 178267d..01bad81 100644 (file)
@@ -38,6 +38,10 @@ def arch_name_EQ : Joined<["--"], "arch-name=">,
 def archive_headers : Flag<["--"], "archive-headers">,
   HelpText<"Display archive header information">;
 
+defm build_id :
+  Eq<"build-id", "Build ID to look up. Once found, added as an input file">,
+  MetaVarName<"<dir>">;
+
 def : Flag<["-"], "a">, Alias<archive_headers>,
   HelpText<"Alias for --archive-headers">;
 
index 689aa0a..f7d6666 100644 (file)
@@ -2916,6 +2916,17 @@ static void parseIntArg(const llvm::opt::InputArgList &InputArgs, int ID,
   }
 }
 
+static object::BuildID parseBuildIDArg(const opt::Arg *A) {
+  StringRef V(A->getValue());
+  std::string Bytes;
+  if (!tryGetFromHex(V, Bytes))
+    reportCmdLineError(A->getSpelling() + ": expected a build ID, but got '" +
+                       V + "'");
+  ArrayRef<uint8_t> BuildID(reinterpret_cast<const uint8_t *>(Bytes.data()),
+                            Bytes.size());
+  return object::BuildID(BuildID.begin(), BuildID.end());
+}
+
 static void invalidArgValue(const opt::Arg *A) {
   reportCmdLineError("'" + StringRef(A->getValue()) +
                      "' is not a valid value for '" + A->getSpelling() + "'");
@@ -3084,6 +3095,17 @@ static void parseObjdumpOptions(const llvm::opt::InputArgList &InputArgs) {
     llvm::cl::ParseCommandLineOptions(2, Argv);
   }
 
+  // Look up any provided build IDs, then append them to the input filenames.
+  for (const opt::Arg *A : InputArgs.filtered(OBJDUMP_build_id)) {
+    object::BuildID BuildID = parseBuildIDArg(A);
+    Optional<std::string> Path = BIDFetcher->fetch(BuildID);
+    if (!Path) {
+      reportCmdLineError(A->getSpelling() + ": could not find build ID '" +
+                         A->getValue() + "'");
+    }
+    InputFilenames.push_back(std::move(*Path));
+  }
+
   // objdump defaults to a.out if no filenames specified.
   if (InputFilenames.empty())
     InputFilenames.push_back("a.out");
@@ -3153,8 +3175,9 @@ int main(int argc, char **argv) {
 
   // Initialize debuginfod.
   const bool ShouldUseDebuginfodByDefault =
-      HTTPClient::isAvailable() &&
-      !ExitOnErr(getDefaultDebuginfodUrls()).empty();
+      InputArgs.hasArg(OBJDUMP_build_id) ||
+      (HTTPClient::isAvailable() &&
+       !ExitOnErr(getDefaultDebuginfodUrls()).empty());
   std::vector<std::string> DebugFileDirectories =
       InputArgs.getAllArgValues(OBJDUMP_debug_file_directory);
   if (InputArgs.hasFlag(OBJDUMP_debuginfod, OBJDUMP_no_debuginfod,