diff --git a/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h b/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h --- a/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h +++ b/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h @@ -22,6 +22,7 @@ #include "llvm/ADT/StringRef.h" #include "llvm/ADT/iterator.h" #include "llvm/ADT/iterator_range.h" +#include "llvm/Object/BuildID.h" #include "llvm/ProfileData/InstrProf.h" #include "llvm/Support/Alignment.h" #include "llvm/Support/Compiler.h" @@ -43,6 +44,10 @@ class IndexedInstrProfReader; +namespace object { +class BuildIDFetcher; +} // namespace object + namespace coverage { class CoverageMappingReader; @@ -605,7 +610,8 @@ /// Ignores non-instrumented object files unless all are not instrumented. static Expected> load(ArrayRef ObjectFilenames, StringRef ProfileFilename, - ArrayRef Arches = None, StringRef CompilationDir = ""); + ArrayRef Arches = None, StringRef CompilationDir = "", + const object::BuildIDFetcher* BIDFetcher = nullptr); /// The number of functions that couldn't have their profiles mapped. /// diff --git a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp --- a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp +++ b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp @@ -19,6 +19,7 @@ #include "llvm/ADT/SmallBitVector.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" +#include "llvm/Object/BuildID.h" #include "llvm/ProfileData/Coverage/CoverageMappingReader.h" #include "llvm/ProfileData/InstrProfReader.h" #include "llvm/Support/Debug.h" @@ -346,7 +347,8 @@ Expected> CoverageMapping::load(ArrayRef ObjectFilenames, StringRef ProfileFilename, ArrayRef Arches, - StringRef CompilationDir) { + StringRef CompilationDir, + const object::BuildIDFetcher* BIDFetcher) { auto ProfileReaderOrErr = IndexedInstrProfReader::create(ProfileFilename); if (Error E = ProfileReaderOrErr.takeError()) return createFileError(ProfileFilename, std::move(E)); @@ -354,6 +356,20 @@ auto Coverage = std::unique_ptr(new CoverageMapping()); bool DataFound = false; + std::vector BuildIDPaths; + std::vector BuildIDPathRefs; + if (ObjectFilenames.empty() && BIDFetcher) { + std::vector BinaryIDs; + if (Error E = ProfileReader->readBinaryIds(BinaryIDs)) + return createFileError(ProfileFilename, std::move(E)); + for (object::BuildIDRef BuildID : BinaryIDs) + if (Optional Path = BIDFetcher->fetch(BuildID)) + BuildIDPaths.push_back(std::move(*Path)); + for (StringRef Path : BuildIDPaths) + BuildIDPathRefs.push_back(Path); + ObjectFilenames = BuildIDPathRefs; + } + for (const auto &File : llvm::enumerate(ObjectFilenames)) { auto CovMappingBufOrErr = MemoryBuffer::getFileOrSTDIN( File.value(), /*IsText=*/false, /*RequiresNullTerminator=*/false); diff --git a/llvm/tools/llvm-cov/CMakeLists.txt b/llvm/tools/llvm-cov/CMakeLists.txt --- a/llvm/tools/llvm-cov/CMakeLists.txt +++ b/llvm/tools/llvm-cov/CMakeLists.txt @@ -14,3 +14,5 @@ SourceCoverageViewText.cpp TestingSupport.cpp ) + +target_link_libraries(llvm-cov PRIVATE LLVMDebuginfod) diff --git a/llvm/tools/llvm-cov/CodeCoverage.cpp b/llvm/tools/llvm-cov/CodeCoverage.cpp --- a/llvm/tools/llvm-cov/CodeCoverage.cpp +++ b/llvm/tools/llvm-cov/CodeCoverage.cpp @@ -23,6 +23,10 @@ #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Triple.h" +#include "llvm/Debuginfod/BuildIDFetcher.h" +#include "llvm/Debuginfod/Debuginfod.h" +#include "llvm/Debuginfod/HTTPClient.h" +#include "llvm/Object/BuildID.h" #include "llvm/ProfileData/Coverage/CoverageMapping.h" #include "llvm/ProfileData/InstrProfReader.h" #include "llvm/Support/CommandLine.h" @@ -50,7 +54,11 @@ const CoverageViewOptions &Options, raw_ostream &OS); + namespace { + +ExitOnError ExitOnErr; + /// The implementation of the coverage tool. class CodeCoverageTool { public: @@ -178,6 +186,8 @@ /// Allowlist from -name-allowlist to be used for filtering. std::unique_ptr NameAllowlist; + + std::unique_ptr BIDFetcher; }; } @@ -434,7 +444,7 @@ ObjectFilename); auto CoverageOrErr = CoverageMapping::load(ObjectFilenames, PGOFilename, CoverageArches, - ViewOpts.CompilationDirectory); + ViewOpts.CompilationDirectory, BIDFetcher.get()); if (Error E = CoverageOrErr.takeError()) { error("Failed to load coverage: " + toString(std::move(E))); return nullptr; @@ -643,6 +653,15 @@ cl::opt DebugDump("dump", cl::Optional, cl::desc("Show internal debug dump")); + cl::list DebugFileDirectory( + "debug-file-directory", cl::Optional, + cl::desc("Directories to search for object files by build ID")); + cl::opt Debuginfod( + "debuginfod", cl::Optional, + cl::desc("Use debuginfod to look up object files from profile."), + cl::init(HTTPClient::isAvailable() && + ExitOnErr(getDefaultDebuginfodUrls()).empty())); + cl::opt Format( "format", cl::desc("Output format for line-based coverage reports"), cl::values(clEnumValN(CoverageViewOptions::OutputFormat::Text, "text", @@ -745,6 +764,10 @@ auto commandLineParser = [&, this](int argc, const char **argv) -> int { cl::ParseCommandLineOptions(argc, argv, "LLVM code coverage tool\n"); ViewOpts.Debug = DebugDump; + if (Debuginfod) + BIDFetcher = std::make_unique(DebugFileDirectory); + else + BIDFetcher = std::make_unique(DebugFileDirectory); if (!CovFilename.empty()) ObjectFilenames.emplace_back(CovFilename);