diff --git a/llvm/docs/CommandGuide/llvm-objdump.rst b/llvm/docs/CommandGuide/llvm-objdump.rst --- a/llvm/docs/CommandGuide/llvm-objdump.rst +++ b/llvm/docs/CommandGuide/llvm-objdump.rst @@ -125,6 +125,11 @@ Specify the target architecture when disassembling. Use :option:`--version` for a list of available targets. +.. option:: --build-id= + + 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. diff --git a/llvm/test/tools/llvm-objdump/debuginfod.test b/llvm/test/tools/llvm-objdump/debuginfod.test --- a/llvm/test/tools/llvm-objdump/debuginfod.test +++ b/llvm/test/tools/llvm-objdump/debuginfod.test @@ -30,6 +30,23 @@ RUN: %t/stripped | \ RUN: FileCheck %s --check-prefix=FOUND +# 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. +RUN: not env DEBUGINFOD_CACHE_PATH=%t llvm-objdump -d --source \ +RUN: --build-id foo 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 \ +RUN: --build-id abc 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 replace very-stripped binaries entirely. RUN: llvm-strip --strip-sections %t/stripped RUN: env DEBUGINFOD_CACHE_PATH=%t llvm-objdump -d --debuginfod \ diff --git a/llvm/tools/llvm-objdump/ObjdumpOpts.td b/llvm/tools/llvm-objdump/ObjdumpOpts.td --- a/llvm/tools/llvm-objdump/ObjdumpOpts.td +++ b/llvm/tools/llvm-objdump/ObjdumpOpts.td @@ -38,6 +38,10 @@ 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<"">; + def : Flag<["-"], "a">, Alias, HelpText<"Alias for --archive-headers">; diff --git a/llvm/tools/llvm-objdump/llvm-objdump.cpp b/llvm/tools/llvm-objdump/llvm-objdump.cpp --- a/llvm/tools/llvm-objdump/llvm-objdump.cpp +++ b/llvm/tools/llvm-objdump/llvm-objdump.cpp @@ -2790,6 +2790,17 @@ } } +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 BuildID(reinterpret_cast(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() + "'"); @@ -2956,6 +2967,17 @@ 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 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"); @@ -3023,15 +3045,11 @@ return 0; } - if (Is("otool")) - parseOtoolOptions(InputArgs); - else - parseObjdumpOptions(InputArgs); - // Initialize debuginfod. const bool ShouldUseDebuginfodByDefault = - HTTPClient::isAvailable() && - !ExitOnErr(getDefaultDebuginfodUrls()).empty(); + InputArgs.hasArg(OBJDUMP_build_id) || + (HTTPClient::isAvailable() && + !ExitOnErr(getDefaultDebuginfodUrls()).empty()); if (InputArgs.hasFlag(OBJDUMP_debuginfod, OBJDUMP_no_debuginfod, ShouldUseDebuginfodByDefault)) { HTTPClient::initialize(); @@ -3040,6 +3058,11 @@ BIDFetcher = std::make_unique(DebugFileDirectories); } + if (Is("otool")) + parseOtoolOptions(InputArgs); + else + parseObjdumpOptions(InputArgs); + if (StartAddress >= StopAddress) reportCmdLineError("start address should be less than stop address");