[llvm] [llvm-cov] Add --debug-info flag to llvm-cov to lookup debug info file. (PR #66798)

via llvm-commits llvm-commits at lists.llvm.org
Tue Sep 19 11:32:33 PDT 2023


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-pgo

<details>
<summary>Changes</summary>

In https://reviews.llvm.org/D157913, I was assuming the debug info is always in the binary, which is not valid on Mac.

1. This adds the same --debug-info flag as llvm-profdata has to llvm-cov to lookup debug info file.
2. If a section size is 0, do not return it from lookupSections as some sections could have 0 size on Mac.

---
Full diff: https://github.com/llvm/llvm-project/pull/66798.diff


8 Files Affected:

- (added) compiler-rt/test/profile/Darwin/coverage-debug-info-correlate.cpp (+78) 
- (modified) compiler-rt/test/profile/Linux/coverage-debug-info-correlate.cpp (+2-2) 
- (modified) llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h (+3-2) 
- (modified) llvm/include/llvm/ProfileData/Coverage/CoverageMappingReader.h (+2-3) 
- (modified) llvm/lib/ProfileData/Coverage/CoverageMapping.cpp (+11-7) 
- (modified) llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp (+15-14) 
- (modified) llvm/tools/llvm-cov/CodeCoverage.cpp (+9-2) 
- (modified) llvm/tools/llvm-cov/CoverageViewOptions.h (+1) 


``````````diff
diff --git a/compiler-rt/test/profile/Darwin/coverage-debug-info-correlate.cpp b/compiler-rt/test/profile/Darwin/coverage-debug-info-correlate.cpp
new file mode 100644
index 000000000000000..3849a7f57aa43d8
--- /dev/null
+++ b/compiler-rt/test/profile/Darwin/coverage-debug-info-correlate.cpp
@@ -0,0 +1,78 @@
+// Test debug info correlate with clang coverage.
+
+// Test the case when there is no __llvm_prf_names in the binary.
+// RUN: %clang_profgen -o %t.normal -fcoverage-mapping %S/../Inputs/instrprof-debug-info-correlate-main.cpp %S/../Inputs/instrprof-debug-info-correlate-foo.cpp
+// RUN: env LLVM_PROFILE_FILE=%t.profraw %run %t.normal
+// RUN: llvm-profdata merge -o %t.normal.profdata %t.profraw
+
+// RUN: %clang_profgen -o %t -g -mllvm --debug-info-correlate -fcoverage-mapping %S/../Inputs/instrprof-debug-info-correlate-main.cpp %S/../Inputs/instrprof-debug-info-correlate-foo.cpp
+// RUN: env LLVM_PROFILE_FILE=%t.proflite %run %t
+// RUN: llvm-profdata merge -o %t.profdata --debug-info=%t.dSYM %t.proflite
+
+// RUN: diff <(llvm-profdata show --all-functions --counts %t.normal.profdata) <(llvm-profdata show --all-functions --counts %t.profdata)
+
+// RUN: llvm-cov report --instr-profile=%t.profdata %t | FileCheck %s -check-prefix=NONAME
+
+// Test debug info correlate with clang coverage (online merging).
+
+// RUN: env LLVM_PROFILE_FILE=%t-1.profraw %run %t.normal
+// RUN: env LLVM_PROFILE_FILE=%t-2.profraw %run %t.normal
+// RUN: llvm-profdata merge -o %t.normal.profdata %t-1.profraw %t-2.profraw
+
+// RUN: rm -rf %t.profdir && mkdir %t.profdir
+// RUN: env LLVM_PROFILE_FILE=%t.profdir/%m.proflite %run %t
+// RUN: env LLVM_PROFILE_FILE=%t.profdir/%m.proflite %run %t
+// RUN: llvm-profdata merge -o %t.profdata --debug-info=%t.dSYM %t.profdir
+
+// RUN: diff <(llvm-profdata show --all-functions --counts %t.normal.profdata) <(llvm-profdata show --all-functions --counts %t.profdata)
+
+// RUN: llvm-cov report --instr-profile=%t.profdata %t | FileCheck %s -check-prefix=NONAME
+// RUN: llvm-cov report --instr-profile=%t.normal.profdata %t | FileCheck %s -check-prefix=NONAME
+
+// NONAME:      Filename                                    Regions    Missed Regions     Cover   Functions  Missed Functions  Executed       Lines      Missed Lines     Cover    Branches   Missed Branches     Cover
+// NONAME-NEXT: --
+// NONAME-NEXT: instrprof-debug-info-correlate-bar.h              3                 1    66.67%           1                 0   100.00%           5                 1    80.00%           2                 1    50.00%
+// NONAME-NEXT: instrprof-debug-info-correlate-foo.cpp            5                 2    60.00%           2                 1    50.00%           6                 2    66.67%           2                 1    50.00%
+// NONAME-NEXT: instrprof-debug-info-correlate-main.cpp           4                 0   100.00%           1                 0   100.00%           5                 0   100.00%           2                 0   100.00%
+// NONAME-NEXT: --
+// NONAME-NEXT: TOTAL                                            12                 3    75.00%           4                 1    75.00%          16                 3    81.25%           6                 2    66.67%
+
+// Test the case when there is __llvm_prf_names in the binary (those are names of uninstrumented functions).
+// RUN: %clang_profgen -o %t.normal -fcoverage-mapping -mllvm -enable-name-compression=false %s
+// RUN: env LLVM_PROFILE_FILE=%t.profraw %run %t.normal
+// RUN: llvm-profdata merge -o %t.normal.profdata %t.profraw
+
+// RUN: %clang_profgen -o %t -g -mllvm --debug-info-correlate -fcoverage-mapping -mllvm -enable-name-compression=false %s
+// RUN: env LLVM_PROFILE_FILE=%t.proflite %run %t
+// RUN: llvm-profdata merge -o %t.profdata --debug-info=%t.dSYM %t.proflite
+
+// RUN: diff <(llvm-profdata show --all-functions --counts %t.normal.profdata) <(llvm-profdata show --all-functions --counts %t.profdata)
+
+// RUN: llvm-cov export --format=lcov --instr-profile=%t.profdata %t --debug-info=%t.dSYM | FileCheck %s -check-prefix=NAME
+
+// Test debug info correlate with clang coverage (online merging).
+
+// RUN: env LLVM_PROFILE_FILE=%t-1.profraw %run %t.normal
+// RUN: env LLVM_PROFILE_FILE=%t-2.profraw %run %t.normal
+// RUN: llvm-profdata merge -o %t.normal.profdata %t-1.profraw %t-2.profraw
+
+// RUN: rm -rf %t.profdir && mkdir %t.profdir
+// RUN: env LLVM_PROFILE_FILE=%t.profdir/%m.proflite %run %t
+// RUN: env LLVM_PROFILE_FILE=%t.profdir/%m.proflite %run %t
+// RUN: llvm-profdata merge -o %t.profdata --debug-info=%t.dSYM %t.profdir
+
+// RUN: diff <(llvm-profdata show --all-functions --counts %t.normal.profdata) <(llvm-profdata show --all-functions --counts %t.profdata)
+
+// RUN: llvm-cov export --format=lcov --instr-profile=%t.profdata %t --debug-info=%t.dSYM | FileCheck %s -check-prefix=NAME
+// NAME: _Z9used_funcv
+// NAME: main
+// NAME: _ZN1A11unused_funcEv
+
+struct A {
+  void unused_func() {}
+};
+void used_func() {}
+int main() {
+  used_func();
+  return 0;
+}
diff --git a/compiler-rt/test/profile/Linux/coverage-debug-info-correlate.cpp b/compiler-rt/test/profile/Linux/coverage-debug-info-correlate.cpp
index 06901de4a24291a..d44e258ce3a9868 100644
--- a/compiler-rt/test/profile/Linux/coverage-debug-info-correlate.cpp
+++ b/compiler-rt/test/profile/Linux/coverage-debug-info-correlate.cpp
@@ -48,7 +48,7 @@
 
 // RUN: diff <(llvm-profdata show --all-functions --counts %t.normal.profdata) <(llvm-profdata show --all-functions --counts %t.profdata)
 
-// RUN: llvm-cov export --format=lcov --instr-profile=%t.profdata %t | FileCheck %s -check-prefix=NAME
+// RUN: llvm-cov export --format=lcov --instr-profile=%t.profdata %t --debug-info=%t | FileCheck %s -check-prefix=NAME
 
 // Test debug info correlate with clang coverage (online merging).
 
@@ -63,7 +63,7 @@
 
 // RUN: diff <(llvm-profdata show --all-functions --counts %t.normal.profdata) <(llvm-profdata show --all-functions --counts %t.profdata)
 
-// RUN: llvm-cov export --format=lcov --instr-profile=%t.profdata %t | FileCheck %s -check-prefix=NAME
+// RUN: llvm-cov export --format=lcov --instr-profile=%t.profdata %t --debug-info=%t | FileCheck %s -check-prefix=NAME
 // NAME: _Z9used_funcv
 // NAME: main
 // NAME: _ZN1A11unused_funcEv
diff --git a/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h b/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h
index b407fe277c543b8..9a12e4e6f464173 100644
--- a/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h
+++ b/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h
@@ -594,6 +594,7 @@ class CoverageMapping {
   // Load coverage records from file.
   static Error
   loadFromFile(StringRef Filename, StringRef Arch, StringRef CompilationDir,
+               StringRef DebugInfoFilename,
                IndexedInstrProfReader &ProfileReader, CoverageMapping &Coverage,
                bool &DataFound,
                SmallVectorImpl<object::BuildID> *FoundBinaryIDs = nullptr);
@@ -623,8 +624,8 @@ class CoverageMapping {
   /// Ignores non-instrumented object files unless all are not instrumented.
   static Expected<std::unique_ptr<CoverageMapping>>
   load(ArrayRef<StringRef> ObjectFilenames, StringRef ProfileFilename,
-       vfs::FileSystem &FS, ArrayRef<StringRef> Arches = std::nullopt,
-       StringRef CompilationDir = "",
+       vfs::FileSystem &FS, StringRef DebugInfoFilename = "",
+       ArrayRef<StringRef> Arches = std::nullopt, StringRef CompilationDir = "",
        const object::BuildIDFetcher *BIDFetcher = nullptr,
        bool CheckBinaryIDs = false);
 
diff --git a/llvm/include/llvm/ProfileData/Coverage/CoverageMappingReader.h b/llvm/include/llvm/ProfileData/Coverage/CoverageMappingReader.h
index 41935ae6bb39881..82395595eb8f89e 100644
--- a/llvm/include/llvm/ProfileData/Coverage/CoverageMappingReader.h
+++ b/llvm/include/llvm/ProfileData/Coverage/CoverageMappingReader.h
@@ -203,10 +203,9 @@ class BinaryCoverageReader : public CoverageMappingReader {
   BinaryCoverageReader &operator=(const BinaryCoverageReader &) = delete;
 
   static Expected<std::vector<std::unique_ptr<BinaryCoverageReader>>>
-  create(MemoryBufferRef ObjectBuffer,
-         StringRef Arch,
+  create(MemoryBufferRef ObjectBuffer, StringRef Arch,
          SmallVectorImpl<std::unique_ptr<MemoryBuffer>> &ObjectFileBuffers,
-         InstrProfSymtab& IndexedProfSymTab,
+         StringRef DebugInfoFilename, InstrProfSymtab &ProfSymTab,
          StringRef CompilationDir = "",
          SmallVectorImpl<object::BuildIDRef> *BinaryIDs = nullptr);
 
diff --git a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
index a99785ee0df5427..94bcaa98c950066 100644
--- a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
+++ b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
@@ -349,8 +349,9 @@ static Error handleMaybeNoDataFoundError(Error E) {
 
 Error CoverageMapping::loadFromFile(
     StringRef Filename, StringRef Arch, StringRef CompilationDir,
-    IndexedInstrProfReader &ProfileReader, CoverageMapping &Coverage,
-    bool &DataFound, SmallVectorImpl<object::BuildID> *FoundBinaryIDs) {
+    StringRef DebugInfoFilename, IndexedInstrProfReader &ProfileReader,
+    CoverageMapping &Coverage, bool &DataFound,
+    SmallVectorImpl<object::BuildID> *FoundBinaryIDs) {
   auto CovMappingBufOrErr = MemoryBuffer::getFileOrSTDIN(
       Filename, /*IsText=*/false, /*RequiresNullTerminator=*/false);
   if (std::error_code EC = CovMappingBufOrErr.getError())
@@ -362,7 +363,7 @@ Error CoverageMapping::loadFromFile(
 
   SmallVector<object::BuildIDRef> BinaryIDs;
   auto CoverageReadersOrErr = BinaryCoverageReader::create(
-      CovMappingBufRef, Arch, Buffers, ProfSymTab,
+      CovMappingBufRef, Arch, Buffers, DebugInfoFilename, ProfSymTab,
       CompilationDir, FoundBinaryIDs ? &BinaryIDs : nullptr);
   if (Error E = CoverageReadersOrErr.takeError()) {
     E = handleMaybeNoDataFoundError(std::move(E));
@@ -388,7 +389,8 @@ Error CoverageMapping::loadFromFile(
 
 Expected<std::unique_ptr<CoverageMapping>> CoverageMapping::load(
     ArrayRef<StringRef> ObjectFilenames, StringRef ProfileFilename,
-    vfs::FileSystem &FS, ArrayRef<StringRef> Arches, StringRef CompilationDir,
+    vfs::FileSystem &FS, StringRef DebugInfoFilename,
+    ArrayRef<StringRef> Arches, StringRef CompilationDir,
     const object::BuildIDFetcher *BIDFetcher, bool CheckBinaryIDs) {
   auto ProfileReaderOrErr = IndexedInstrProfReader::create(ProfileFilename, FS);
   if (Error E = ProfileReaderOrErr.takeError())
@@ -409,7 +411,8 @@ Expected<std::unique_ptr<CoverageMapping>> CoverageMapping::load(
   for (const auto &File : llvm::enumerate(ObjectFilenames)) {
     if (Error E =
             loadFromFile(File.value(), GetArch(File.index()), CompilationDir,
-                         *ProfileReader, *Coverage, DataFound, &FoundBinaryIDs))
+                         DebugInfoFilename, *ProfileReader, *Coverage,
+                         DataFound, &FoundBinaryIDs))
       return std::move(E);
   }
 
@@ -436,8 +439,9 @@ Expected<std::unique_ptr<CoverageMapping>> CoverageMapping::load(
       if (PathOpt) {
         std::string Path = std::move(*PathOpt);
         StringRef Arch = Arches.size() == 1 ? Arches.front() : StringRef();
-        if (Error E = loadFromFile(Path, Arch, CompilationDir, *ProfileReader,
-                                  *Coverage, DataFound))
+        if (Error E =
+                loadFromFile(Path, Arch, DebugInfoFilename, CompilationDir,
+                             *ProfileReader, *Coverage, DataFound))
           return std::move(E);
       } else if (CheckBinaryIDs) {
         return createFileError(
diff --git a/llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp b/llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp
index b17caaf99807357..962202238ba3983 100644
--- a/llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp
+++ b/llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp
@@ -1014,7 +1014,7 @@ static Expected<std::vector<SectionRef>> lookupSections(ObjectFile &OF,
     Expected<StringRef> NameOrErr = Section.getName();
     if (!NameOrErr)
       return NameOrErr.takeError();
-    if (stripSuffix(*NameOrErr) == Name)
+    if (stripSuffix(*NameOrErr) == Name && Section.getSize() != 0)
       Sections.push_back(Section);
   }
   if (Sections.empty())
@@ -1022,10 +1022,10 @@ static Expected<std::vector<SectionRef>> lookupSections(ObjectFile &OF,
   return Sections;
 }
 
-static Error getProfileNamesFromDebugInfo(StringRef FileName,
+static Error getProfileNamesFromDebugInfo(StringRef DebugInfoFilename,
                                           InstrProfSymtab &ProfileNames) {
   std::unique_ptr<InstrProfCorrelator> Correlator;
-  if (auto E = InstrProfCorrelator::get(FileName).moveInto(Correlator))
+  if (auto E = InstrProfCorrelator::get(DebugInfoFilename).moveInto(Correlator))
     return E;
   if (auto E = Correlator->correlateCovUnusedFuncNames(0))
     return E;
@@ -1038,7 +1038,8 @@ static Error getProfileNamesFromDebugInfo(StringRef FileName,
 
 static Expected<std::unique_ptr<BinaryCoverageReader>>
 loadBinaryFormat(std::unique_ptr<Binary> Bin, StringRef Arch,
-                 InstrProfSymtab &ProfSymTab, StringRef CompilationDir = "",
+                 StringRef DebugInfoFilename, InstrProfSymtab &ProfSymTab,
+                 StringRef CompilationDir = "",
                  object::BuildIDRef *BinaryID = nullptr) {
   std::unique_ptr<ObjectFile> OF;
   if (auto *Universal = dyn_cast<MachOUniversalBinary>(Bin.get())) {
@@ -1077,9 +1078,9 @@ loadBinaryFormat(std::unique_ptr<Binary> Bin, StringRef Arch,
       lookupSections(*OF, getInstrProfSectionName(IPSK_name, ObjFormat,
                                                   /*AddSegmentInfo=*/false));
   if (auto E = NamesSection.takeError()) {
-    if (OF->hasDebugInfo()) {
+    if (!DebugInfoFilename.empty()) {
       if (auto E =
-              getProfileNamesFromDebugInfo(OF->getFileName(), ProfileNames))
+              getProfileNamesFromDebugInfo(DebugInfoFilename, ProfileNames))
         return make_error<CoverageMapError>(coveragemap_error::malformed);
     }
     consumeError(std::move(E));
@@ -1176,8 +1177,8 @@ Expected<std::vector<std::unique_ptr<BinaryCoverageReader>>>
 BinaryCoverageReader::create(
     MemoryBufferRef ObjectBuffer, StringRef Arch,
     SmallVectorImpl<std::unique_ptr<MemoryBuffer>> &ObjectFileBuffers,
-    InstrProfSymtab &ProfSymTab, StringRef CompilationDir,
-    SmallVectorImpl<object::BuildIDRef> *BinaryIDs) {
+    StringRef DebugInfoFilename, InstrProfSymtab &ProfSymTab,
+    StringRef CompilationDir, SmallVectorImpl<object::BuildIDRef> *BinaryIDs) {
   std::vector<std::unique_ptr<BinaryCoverageReader>> Readers;
 
   if (ObjectBuffer.getBuffer().size() > sizeof(TestingFormatMagic)) {
@@ -1221,8 +1222,8 @@ BinaryCoverageReader::create(
       }
 
       return BinaryCoverageReader::create(
-          ArchiveOrErr.get()->getMemoryBufferRef(), Arch,
-          ObjectFileBuffers, ProfSymTab, CompilationDir, BinaryIDs);
+          ArchiveOrErr.get()->getMemoryBufferRef(), Arch, ObjectFileBuffers,
+          DebugInfoFilename, ProfSymTab, CompilationDir, BinaryIDs);
     }
   }
 
@@ -1235,8 +1236,8 @@ BinaryCoverageReader::create(
         return ChildBufOrErr.takeError();
 
       auto ChildReadersOrErr = BinaryCoverageReader::create(
-          ChildBufOrErr.get(), Arch, ObjectFileBuffers, ProfSymTab,
-          CompilationDir, BinaryIDs);
+          ChildBufOrErr.get(), Arch, ObjectFileBuffers, DebugInfoFilename,
+          ProfSymTab, CompilationDir, BinaryIDs);
       if (!ChildReadersOrErr)
         return ChildReadersOrErr.takeError();
       for (auto &Reader : ChildReadersOrErr.get())
@@ -1257,8 +1258,8 @@ BinaryCoverageReader::create(
 
   object::BuildIDRef BinaryID;
   auto ReaderOrErr =
-      loadBinaryFormat(std::move(Bin), Arch, ProfSymTab, CompilationDir,
-                       BinaryIDs ? &BinaryID : nullptr);
+      loadBinaryFormat(std::move(Bin), Arch, DebugInfoFilename, ProfSymTab,
+                       CompilationDir, BinaryIDs ? &BinaryID : nullptr);
   if (!ReaderOrErr)
     return ReaderOrErr.takeError();
   Readers.push_back(std::move(ReaderOrErr.get()));
diff --git a/llvm/tools/llvm-cov/CodeCoverage.cpp b/llvm/tools/llvm-cov/CodeCoverage.cpp
index b5d763d8643cd7d..9a8bbfa291a679c 100644
--- a/llvm/tools/llvm-cov/CodeCoverage.cpp
+++ b/llvm/tools/llvm-cov/CodeCoverage.cpp
@@ -444,8 +444,9 @@ std::unique_ptr<CoverageMapping> CodeCoverageTool::load() {
               ObjectFilename);
   auto FS = vfs::getRealFileSystem();
   auto CoverageOrErr = CoverageMapping::load(
-      ObjectFilenames, PGOFilename, *FS, CoverageArches,
-      ViewOpts.CompilationDirectory, BIDFetcher.get(), CheckBinaryIDs);
+      ObjectFilenames, PGOFilename, *FS, ViewOpts.DebugInfoFilename,
+      CoverageArches, ViewOpts.CompilationDirectory, BIDFetcher.get(),
+      CheckBinaryIDs);
   if (Error E = CoverageOrErr.takeError()) {
     error("failed to load coverage: " + toString(std::move(E)));
     return nullptr;
@@ -774,6 +775,11 @@ int CodeCoverageTool::run(Command Cmd, int argc, const char **argv) {
       "check-binary-ids", cl::desc("Fail if an object couldn't be found for a "
                                    "binary ID in the profile"));
 
+  cl::opt<std::string> DebugInfoFilename(
+      "debug-info", cl::init(""),
+      cl::desc("Read and extract profile metadata from debug info and show "
+               "the functions it found."));
+
   auto commandLineParser = [&, this](int argc, const char **argv) -> int {
     cl::ParseCommandLineOptions(argc, argv, "LLVM code coverage tool\n");
     ViewOpts.Debug = DebugDump;
@@ -929,6 +935,7 @@ int CodeCoverageTool::run(Command Cmd, int argc, const char **argv) {
     ViewOpts.ExportSummaryOnly = SummaryOnly;
     ViewOpts.NumThreads = NumThreads;
     ViewOpts.CompilationDirectory = CompilationDirectory;
+    ViewOpts.DebugInfoFilename = DebugInfoFilename;
 
     return 0;
   };
diff --git a/llvm/tools/llvm-cov/CoverageViewOptions.h b/llvm/tools/llvm-cov/CoverageViewOptions.h
index eb852859e9cbe46..f0e37848a455059 100644
--- a/llvm/tools/llvm-cov/CoverageViewOptions.h
+++ b/llvm/tools/llvm-cov/CoverageViewOptions.h
@@ -54,6 +54,7 @@ struct CoverageViewOptions {
   std::string CompilationDirectory;
   float HighCovWatermark;
   float LowCovWatermark;
+  std::string DebugInfoFilename;
 
   /// Change the output's stream color if the colors are enabled.
   ColoredRawOstream colored_ostream(raw_ostream &OS,

``````````

</details>


https://github.com/llvm/llvm-project/pull/66798


More information about the llvm-commits mailing list