[llvm-branch-commits] [llvm] obj2yaml: Add "detailed" output in CovMap dump (PR #129473)

NAKAMURA Takumi via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Thu Mar 6 19:44:46 PST 2025


https://github.com/chapuni updated https://github.com/llvm/llvm-project/pull/129473

>From e2dd98690a0f43b35ee22d59efeb04d2c7fead68 Mon Sep 17 00:00:00 2001
From: NAKAMURA Takumi <geek4civic at gmail.com>
Date: Mon, 3 Mar 2025 12:26:08 +0900
Subject: [PATCH] detailed

---
 llvm/include/llvm/ObjectYAML/CovMap.h       |  97 ++++++++--
 llvm/lib/ObjectYAML/CovMap.cpp              | 190 ++++++++++++++++----
 llvm/test/tools/obj2yaml/ELF/covmap-be.yaml |   7 +
 llvm/test/tools/obj2yaml/ELF/covmap.yaml    |   7 +
 llvm/tools/obj2yaml/elf2yaml.cpp            |  25 ++-
 5 files changed, 269 insertions(+), 57 deletions(-)

diff --git a/llvm/include/llvm/ObjectYAML/CovMap.h b/llvm/include/llvm/ObjectYAML/CovMap.h
index 406204ee024fb..b55d902f999e8 100644
--- a/llvm/include/llvm/ObjectYAML/CovMap.h
+++ b/llvm/include/llvm/ObjectYAML/CovMap.h
@@ -24,6 +24,7 @@
 #define LLVM_OBJECTYAML_COVMAP_H
 
 #include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/ObjectYAML/ELFYAML.h"
 #include "llvm/Support/Endian.h"
@@ -34,14 +35,67 @@
 #include <memory>
 #include <optional>
 #include <string>
+#include <variant>
 #include <vector>
 
 namespace llvm {
+class InstrProfSymtab;
 class raw_ostream;
 } // namespace llvm
 
 namespace llvm::coverage::yaml {
 
+/// This works like vector container but can be replaced with
+/// MutableArrayRef. See also SequenceTraits<VectorOrRef>.
+template <typename T, typename Vec = std::vector<T>> class VectorOrRef {
+  using Ref = MutableArrayRef<T>;
+
+  /// Holds vector type initially.
+  std::variant<Vec, Ref> Array;
+
+public:
+  // FIXME: Iterator impl is minimal easy.
+  using iterator = T *;
+
+  iterator begin() {
+    if (auto *V = std::get_if<Vec>(&Array))
+      return &V->front();
+    return &std::get<Ref>(Array).front();
+  }
+
+  iterator end() {
+    if (auto *V = std::get_if<Vec>(&Array))
+      return &V->back() + 1;
+    return &std::get<Ref>(Array).back() + 1;
+  }
+
+  size_t size() const {
+    if (const auto *V = std::get_if<Vec>(&Array))
+      return V->size();
+    return std::get<Ref>(Array).size();
+  }
+
+  T &operator[](int Idx) {
+    if (auto *V = std::get_if<Vec>(&Array))
+      return (*V)[Idx];
+    return std::get<Ref>(Array)[Idx];
+  }
+
+  void resize(size_t Size) { std::get<Vec>(Array).resize(Size); }
+
+  VectorOrRef() = default;
+
+  /// Initialize with MutableArrayRef.
+  VectorOrRef(Ref &&Tmp) : Array(std::move(Tmp)) {}
+};
+
+/// Options for Decoder.
+struct DecoderParam {
+  bool Detailed; ///< Generate and show processed records.
+  bool Raw;      ///< Show raw data oriented records.
+  bool dLoc;     ///< Show raw dLoc (differential Loc).
+};
+
 struct DecoderContext;
 
 /// Base Counter, corresponding to coverage::Counter.
@@ -143,6 +197,9 @@ struct FileRecsTy {
   void mapping(llvm::yaml::IO &IO);
 };
 
+/// Key is FilenamesRef.
+using CovMapByRefTy = llvm::DenseMap<uint64_t, struct CovMapTy *>;
+
 /// An element of CovFun array.
 struct CovFunTy {
   std::optional<llvm::yaml::Hex64> NameRef;     ///< Hash value of the symbol.
@@ -157,7 +214,8 @@ struct CovFunTy {
 
   /// Depends on CovMap and SymTab(IPSK_names)
   Expected<uint64_t> decode(const ArrayRef<uint8_t> Content, uint64_t Offset,
-                            endianness Endianness);
+                            endianness Endianness, CovMapByRefTy &CovMapByRef,
+                            InstrProfSymtab *SymTab, const DecoderParam &Param);
 
   void encode(raw_ostream &OS, endianness Endianness) const;
 };
@@ -180,7 +238,7 @@ struct CovMapTy {
   /// This may be ArrayRef in Decoder since Filenames has been
   /// filled. On the other hand in Encoder, this should be a vector
   /// since YAML parser doesn't endorse references.
-  std::optional<std::vector<std::string>> Files;
+  std::optional<VectorOrRef<std::string>> Files;
 
   void mapping(llvm::yaml::IO &IO);
 
@@ -188,7 +246,7 @@ struct CovMapTy {
   StringRef getWD() const { return (WD ? *WD : StringRef()); }
 
   Expected<uint64_t> decode(const ArrayRef<uint8_t> Content, uint64_t Offset,
-                            endianness Endianness);
+                            endianness Endianness, const DecoderParam &Param);
 
   /// Generate Accumulated list with WD.
   /// Returns a single element {WD} if AccFiles is not given.
@@ -210,6 +268,21 @@ struct CovMapTy {
 
 } // namespace llvm::coverage::yaml
 
+namespace llvm::yaml {
+template <typename T>
+struct SequenceTraits<llvm::coverage::yaml::VectorOrRef<T>> {
+  static size_t size(IO &io, llvm::coverage::yaml::VectorOrRef<T> &seq) {
+    return seq.size();
+  }
+  static T &element(IO &, llvm::coverage::yaml::VectorOrRef<T> &seq,
+                    size_t index) {
+    if (index >= seq.size())
+      seq.resize(index + 1);
+    return seq[index];
+  }
+};
+} // namespace llvm::yaml
+
 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::coverage::yaml::CovMapTy)
 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::coverage::yaml::CovFunTy)
 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::coverage::yaml::ExpressionTy)
@@ -265,17 +338,21 @@ class Decoder {
   virtual ~Decoder() {}
 
   /// Returns DecoderImpl.
-  static std::unique_ptr<Decoder> get(endianness Endianness,
-                                      bool CovMapEnabled);
+  static std::unique_ptr<Decoder>
+  get(endianness Endianness, const coverage::yaml::DecoderParam &Param);
 
   /// Called from the Sections loop in advance of the final dump.
-  /// Decoder predecodes CovMap for Version info.
-  virtual Error acquire(unsigned AddressAlign, StringRef Name,
+  /// Decoder predecodes Names and CovMap, and captures Contents of
+  /// CovFuns.
+  virtual Error acquire(uint64_t Offset, unsigned AddressAlign, StringRef Name,
                         ArrayRef<uint8_t> Content) = 0;
 
-  /// Make contents on ELFYAML object. CovMap is predecoded.
-  virtual Error make(ELFYAML::CovMapSectionBase *Base,
-                     ArrayRef<uint8_t> Content) = 0;
+  /// Called before the final dump after `acquire`.
+  /// Decode contents partially and resolve names.
+  virtual Error fixup() = 0;
+
+  /// Make contents on ELFYAML object with predecoded contents.
+  virtual Error make(ELFYAML::CovMapSectionBase *Base, uint64_t Offset) = 0;
 
   /// Suppress emission of CovMap unless enabled.
   static bool enabled;
diff --git a/llvm/lib/ObjectYAML/CovMap.cpp b/llvm/lib/ObjectYAML/CovMap.cpp
index dcf90f7b109cb..94970cd41d5a7 100644
--- a/llvm/lib/ObjectYAML/CovMap.cpp
+++ b/llvm/lib/ObjectYAML/CovMap.cpp
@@ -13,8 +13,10 @@
 #include "llvm/ObjectYAML/CovMap.h"
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/MapVector.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/ObjectYAML/ELFYAML.h"
+#include "llvm/ProfileData/Coverage/CoverageMapping.h"
 #include "llvm/ProfileData/Coverage/CoverageMappingReader.h"
 #include "llvm/ProfileData/Coverage/CoverageMappingWriter.h"
 #include "llvm/ProfileData/InstrProf.h"
@@ -42,12 +44,15 @@ using namespace llvm::covmap;
 bool Decoder::enabled;
 
 // DataExtractor w/ single Cursor
-struct coverage::yaml::DecoderContext : DataExtractor, DataExtractor::Cursor {
+struct coverage::yaml::DecoderContext : DataExtractor,
+                                        DataExtractor::Cursor,
+                                        DecoderParam {
   uint64_t LineStart = 0;
 
-  DecoderContext(const ArrayRef<uint8_t> Content, bool IsLE)
+  DecoderContext(const ArrayRef<uint8_t> Content, bool IsLE,
+                 const DecoderParam &Param)
       : DataExtractor(Content, IsLE, /*AddressSize=*/0),
-        DataExtractor::Cursor(0) {}
+        DataExtractor::Cursor(0), DecoderParam(Param) {}
 
   bool eof() { return DataExtractor::eof(*this); }
   uint32_t getU32() { return DataExtractor::getU32(*this); }
@@ -91,8 +96,24 @@ Error CounterTy::decodeOrTag(DecoderContext &Data) {
     else
       Val = V; // w/o Tag
   } else {
-    Tag = T;
-    Val = V;
+    if (Data.Raw) {
+      Tag = T;
+      Val = V;
+    } else {
+      switch (T) {
+      case Zero:
+        llvm_unreachable("Zero should be handled in advance");
+      case Ref:
+        RefOpt = V;
+        break;
+      case Sub:
+        SubOpt = V;
+        break;
+      case Add:
+        AddOpt = V;
+        break;
+      }
+    }
   }
 
   return Error::success();
@@ -211,12 +232,14 @@ Error RecTy::decode(DecoderContext &Data) {
     case Decision:
       if (auto E = DecisionOpt.emplace().decode(Data))
         return E;
-      ExtTag = Decision;
+      if (Data.Raw)
+        ExtTag = Decision;
       break;
     case Branch:
       if (auto E = decodeBranch())
         return E;
-      ExtTag = Branch;
+      if (Data.Raw)
+        ExtTag = Branch;
       break;
     case MCDCBranch: {
       if (auto E = decodeBranch())
@@ -231,7 +254,8 @@ Error RecTy::decode(DecoderContext &Data) {
       if (!I2OrErr)
         return I2OrErr.takeError();
       MCDC = {*I0OrErr, *I1OrErr, *I2OrErr};
-      ExtTag = MCDCBranch;
+      if (Data.Raw)
+        ExtTag = MCDCBranch;
       break;
     }
     default:
@@ -363,8 +387,11 @@ CovMapTy::encodeFilenames(const std::optional<ArrayRef<StringRef>> &AccFilesOpt,
 }
 
 Expected<uint64_t> CovFunTy::decode(const ArrayRef<uint8_t> Content,
-                                    uint64_t Offset, endianness Endianness) {
-  DecoderContext Data(Content, (Endianness == endianness::little));
+                                    uint64_t Offset, endianness Endianness,
+                                    CovMapByRefTy &CovMapByRef,
+                                    InstrProfSymtab *Symtab,
+                                    const DecoderParam &Param) {
+  DecoderContext Data(Content, (Endianness == endianness::little), Param);
   Data.seek(Offset);
 
   uint32_t DataSize;
@@ -383,9 +410,17 @@ Expected<uint64_t> CovFunTy::decode(const ArrayRef<uint8_t> Content,
   if (!Data)
     return Data.takeError();
 
+  if (Data.Detailed)
+    FuncName = Symtab->getFuncOrVarNameIfDefined(*NameRef);
+
+  if (!Data.Raw)
+    NameRef.reset();
+
   [[maybe_unused]] auto ExpectedEndOffset = Data.tell() + DataSize;
 
   // Decode body.
+  assert(CovMapByRef.contains(this->FilenamesRef));
+  auto &CovMap = *CovMapByRef[this->FilenamesRef];
   FileIDs.emplace();
 
   auto NumFilesOrErr = Data.getULEB128();
@@ -414,6 +449,10 @@ Expected<uint64_t> CovFunTy::decode(const ArrayRef<uint8_t> Content,
     if (!NumRegionsOrErr)
       return NumRegionsOrErr.takeError();
     auto &File = Files.emplace_back();
+    if (Data.Detailed) {
+      File.Index = FileIdx; // Sequential number.
+      File.Filename = (*CovMap.Filenames)[(*FileIDs)[FileIdx]];
+    }
 
     // Decode subarray.
     Data.LineStart = 0;
@@ -421,9 +460,19 @@ Expected<uint64_t> CovFunTy::decode(const ArrayRef<uint8_t> Content,
       auto &Rec = File.Recs.emplace_back();
       if (auto E = Rec.decode(Data))
         return std::move(E);
+
+      // Hide either Loc or dLoc.
+      if (!Data.Detailed || Data.dLoc)
+        Rec.Loc.reset();
+      else if (!Data.Raw)
+        Rec.dLoc.reset();
     }
   }
 
+  // Hide FileIDs.
+  if (!Data.Raw)
+    FileIDs.reset();
+
   assert(Data.tell() == ExpectedEndOffset);
   return Data.tell();
 }
@@ -454,8 +503,9 @@ void CovMapTy::encode(raw_ostream &OS, endianness Endianness) const {
 }
 
 Expected<uint64_t> CovMapTy::decode(const ArrayRef<uint8_t> Content,
-                                    uint64_t Offset, endianness Endianness) {
-  DecoderContext Data(Content, (Endianness == endianness::little));
+                                    uint64_t Offset, endianness Endianness,
+                                    const DecoderParam &Param) {
+  DecoderContext Data(Content, (Endianness == endianness::little), Param);
   Data.seek(Offset);
 
 #define COVMAP_HEADER(Type, LLVMType, Name, Initializer)                       \
@@ -479,6 +529,17 @@ Expected<uint64_t> CovMapTy::decode(const ArrayRef<uint8_t> Content,
                    .read(static_cast<CovMapVersion>(Version)))
     return E;
 
+  if (Param.Detailed && useWD()) {
+    assert(this->Filenames->size() >= 1);
+    auto FilenamesI = this->Filenames->begin();
+    StringRef WD = *FilenamesI++;
+    if (!WD.empty())
+      this->WD = WD;
+    // Use Filenames as a storage.
+    this->Files.emplace(
+        MutableArrayRef(&*FilenamesI, &*this->Filenames->end()));
+  }
+
   Offset = Data.tell();
   return Offset;
 }
@@ -527,7 +588,12 @@ void CovFunTy::mapping(llvm::yaml::IO &IO) {
 void CovMapTy::mapping(llvm::yaml::IO &IO) {
   IO.mapRequired("FilenamesRef", FilenamesRef);
   IO.mapOptional("Version", Version);
-  IO.mapOptional("Filenames", Filenames);
+
+  if (!WD && !Files)
+    // Suppress this regardless of (Detailed && Raw).
+    // Since it is obviously redundant.
+    IO.mapOptional("Filenames", Filenames);
+
   IO.mapOptional("WD", WD);
   IO.mapOptional("Files", Files);
 }
@@ -592,7 +658,7 @@ struct CovMapSection : ELFYAML::CovMapSectionBase {
   }
 
   Error decode(ArrayRef<uint8_t> Blob, unsigned AddressAlign,
-               endianness Endianness) {
+               endianness Endianness, const DecoderParam &Param) {
     uint64_t Offset = 0;
 
     while (true) {
@@ -601,7 +667,7 @@ struct CovMapSection : ELFYAML::CovMapSectionBase {
         break;
       }
       auto &CovMap = CovMaps.emplace_back();
-      auto Result = CovMap.decode(Blob, Offset, Endianness);
+      auto Result = CovMap.decode(Blob, Offset, Endianness, Param);
       if (!Result) {
         return Result.takeError();
       }
@@ -637,9 +703,10 @@ struct CovFunSection : ELFYAML::CovMapSectionBase {
     IO.mapOptional("CovFun", CovFuns);
   }
 
-  static Expected<std::vector<CovFunTy>> decode(ArrayRef<uint8_t> CovFunA,
-                                                unsigned AddressAlign,
-                                                endianness Endianness) {
+  static Expected<std::vector<CovFunTy>>
+  decode(ArrayRef<uint8_t> CovFunA, unsigned AddressAlign,
+         endianness Endianness, CovMapByRefTy &CovMapByRef,
+         InstrProfSymtab *Symtab, const DecoderParam &Param) {
     std::vector<CovFunTy> CovFuns;
     uint64_t Offset = 0;
 
@@ -649,7 +716,8 @@ struct CovFunSection : ELFYAML::CovMapSectionBase {
         break;
 
       auto &CovFun = CovFuns.emplace_back();
-      auto Result = CovFun.decode(CovFunA, Offset, Endianness);
+      auto Result = CovFun.decode(CovFunA, Offset, Endianness, CovMapByRef,
+                                  Symtab, Param);
       if (!Result)
         return Result.takeError();
 
@@ -675,7 +743,7 @@ class CovMapFilenamesResolver {
   std::vector<CovFunTy *> UnresolvedCovFuns;
 
 protected:
-  DenseMap<uint64_t, struct CovMapTy *> CovMapByRef;
+  CovMapByRefTy CovMapByRef;
   std::vector<CovMapTy> TempCovMaps; // For Decoder
 
 public:
@@ -702,6 +770,23 @@ class CovMapFilenamesResolver {
     }
   }
 
+  void decMaybeResetFilenames(std::vector<CovMapTy> &CovMaps) {
+    for (auto &CovMap : CovMaps) {
+      auto FilenamesI = FilenamesByCovMap.find(CovMap.FilenamesRef);
+      if (FilenamesI == FilenamesByCovMap.end())
+        continue;
+
+      // Calculate FilenamesRef with Filenames from CovFuns.
+      // If matches, hide Filenames from CovMap.
+      auto [AccFilenamesRef, _] =
+          CovMap.encodeFilenames(FilenamesI->second.getArrayRef());
+      if (CovMap.FilenamesRef == AccFilenamesRef) {
+        CovMap.Files.reset();
+        CovMap.Filenames.reset(); // FilenamesI has been invalidated.
+      }
+    }
+  }
+
   void encFixup() {
     for (auto &[_, CovMap] : CovMapByRef) {
       auto FilenamesI = FilenamesByCovMap.find(CovMap->FilenamesRef);
@@ -757,15 +842,23 @@ class CovMapFilenamesResolver {
 };
 
 class DecoderImpl : public Decoder, CovMapFilenamesResolver {
+  DecoderParam Param;
+
   std::unique_ptr<InstrProfSymtab> ProfileNames;
 
+  InstrProfSymtab::PrfNamesChunksTy PrfNames;
+
+  MapVector<uint64_t, std::pair<ArrayRef<uint8_t>, unsigned>> CovFunBlobs;
+  DenseMap<uint64_t, std::vector<CovFunTy>> TempCovFuns;
+
 public:
-  DecoderImpl(endianness Endianness, bool CovMapEnabled)
-      : Decoder(Endianness), ProfileNames(std::make_unique<InstrProfSymtab>()) {
-    enabled = CovMapEnabled;
+  DecoderImpl(endianness Endianness, const DecoderParam &Param)
+      : Decoder(Endianness), Param(Param),
+        ProfileNames(std::make_unique<InstrProfSymtab>()) {
+    enabled = (Param.Detailed || Param.Raw);
   }
 
-  Error acquire(unsigned AddressAlign, StringRef Name,
+  Error acquire(uint64_t Offset, unsigned AddressAlign, StringRef Name,
                 ArrayRef<uint8_t> Content) override {
     // Don't register anything.
     if (!enabled)
@@ -775,33 +868,52 @@ class DecoderImpl : public Decoder, CovMapFilenamesResolver {
       // Decode CovMaps in advance, since only CovMap knows its Version.
       // CovMaps is restored (into CovMapSection) later.
       auto TempCovMap = std::make_unique<CovMapSection>();
-      if (auto E = TempCovMap->decode(Content, AddressAlign, Endianness))
+      if (auto E = TempCovMap->decode(Content, AddressAlign, Endianness, Param))
         return E;
       moveAndCollectCovMap(std::move(TempCovMap->CovMaps));
+    } else if (PrfNamesSection::nameMatches(Name)) {
+      // Decode PrfNames in advance since CovFun depends on it.
+      auto PrfNamesOrErr = ProfileNames->createAndGetList(Content);
+      if (!PrfNamesOrErr)
+        return PrfNamesOrErr.takeError();
+      PrfNames = std::move(*PrfNamesOrErr);
+    } else if (CovFunSection::nameMatches(Name)) {
+      // Will be decoded after CovMap is met.
+      CovFunBlobs[Offset] = {Content, AddressAlign};
     }
 
     return Error::success();
   }
 
-  Error make(ELFYAML::CovMapSectionBase *Base,
-             ArrayRef<uint8_t> Content) override {
+  Error fixup() override {
+    // Decode CovFun(s) with predecoded PrfNames and CovMap.
+    for (const auto &[Offset, CovFunBlob] : CovFunBlobs) {
+      auto CovFunsOrErr =
+          CovFunSection::decode(CovFunBlob.first, CovFunBlob.second, Endianness,
+                                CovMapByRef, ProfileNames.get(), Param);
+      if (!CovFunsOrErr)
+        return CovFunsOrErr.takeError();
+      TempCovFuns[Offset] = std::move(*CovFunsOrErr);
+      collectCovFunFilenames(TempCovFuns[Offset]);
+    }
+    // Hide Filenames if it is reproducible from CovFuns.
+    if (Param.Detailed)
+      decMaybeResetFilenames(TempCovMaps);
+    return Error::success();
+  }
+
+  Error make(ELFYAML::CovMapSectionBase *Base, uint64_t Offset) override {
     if (auto *S = dyn_cast<CovMapSection>(Base)) {
       // Store predecoded CovMaps.
       S->CovMaps = std::move(TempCovMaps);
       return Error::success();
     } else if (auto *S = dyn_cast<PrfNamesSection>(Base)) {
-      // Decode PrfNames in advance since CovFun depends on it.
-      auto PrfNamesOrErr = ProfileNames->createAndGetList(Content);
-      if (!PrfNamesOrErr)
-        return PrfNamesOrErr.takeError();
-      S->PrfNames = std::move(*PrfNamesOrErr);
+      S->PrfNames = std::move(PrfNames);
       return Error::success();
     } else if (auto *S = dyn_cast<CovFunSection>(Base)) {
-      auto CovFunsOrErr =
-          CovFunSection::decode(Content, S->AddressAlign, Endianness);
-      if (!CovFunsOrErr)
-        return CovFunsOrErr.takeError();
-      S->CovFuns = std::move(*CovFunsOrErr);
+      assert(S->CovFuns.empty());
+      assert(TempCovFuns.contains(Offset));
+      S->CovFuns = std::move(TempCovFuns[Offset]);
       return Error::success();
     }
 
@@ -826,8 +938,8 @@ class EncoderImpl : public Encoder, CovMapFilenamesResolver {
 } // namespace
 
 std::unique_ptr<Decoder> Decoder::get(endianness Endianness,
-                                      bool CovMapEnabled) {
-  return std::make_unique<DecoderImpl>(Endianness, CovMapEnabled);
+                                      const DecoderParam &Param) {
+  return std::make_unique<DecoderImpl>(Endianness, Param);
 }
 
 std::unique_ptr<Encoder> Encoder::get(endianness Endianness) {
diff --git a/llvm/test/tools/obj2yaml/ELF/covmap-be.yaml b/llvm/test/tools/obj2yaml/ELF/covmap-be.yaml
index 8423f1ad5f765..ec1352b40a9cc 100644
--- a/llvm/test/tools/obj2yaml/ELF/covmap-be.yaml
+++ b/llvm/test/tools/obj2yaml/ELF/covmap-be.yaml
@@ -1,8 +1,15 @@
 # RUN: yaml2obj %s -o %t.o
 # RUN: obj2yaml %t.o > %t.plain.yaml
 # RUN: obj2yaml --covmap-raw %t.o > %t.raw.yaml
+# RUN: obj2yaml --covmap --covmap-raw %t.o > %t.mixed.yaml
+# RUN: obj2yaml --covmap --covmap-dloc %t.o > %t.dloc.yaml
+# RUN: obj2yaml --covmap %t.o > %t.covmap.yaml
+# RUN: sed -E '/^(#.*)?$/d' %s | diff %t.covmap.yaml -
 # RUN: yaml2obj %t.plain.yaml -o - | cmp %t.o -
 # RUN: yaml2obj %t.raw.yaml -o - | cmp %t.o -
+# RUN: yaml2obj %t.mixed.yaml -o - | cmp %t.o -
+# RUN: yaml2obj %t.dloc.yaml -o - | cmp %t.o -
+# RUN: yaml2obj %t.covmap.yaml -o - | cmp %t.o -
 
 # FIXME: This is synthetically created. s/ELFDATA2LSB/ELF2DATAMSB/ s/EM_X86_64/EM_PPC64/
 --- !ELF
diff --git a/llvm/test/tools/obj2yaml/ELF/covmap.yaml b/llvm/test/tools/obj2yaml/ELF/covmap.yaml
index db30d373d5be1..fc77a3d02f909 100644
--- a/llvm/test/tools/obj2yaml/ELF/covmap.yaml
+++ b/llvm/test/tools/obj2yaml/ELF/covmap.yaml
@@ -1,8 +1,15 @@
 # RUN: yaml2obj %s -o %t.o
 # RUN: obj2yaml %t.o | tee %t.plain.yaml | FileCheck %s --check-prefixes=CHECK,PLAIN
 # RUN: obj2yaml --covmap-raw %t.o | tee %t.raw.yaml | FileCheck %s --check-prefixes=CHECK,COVMAP,RAWONLY,RAW,DLOC
+# RUN: obj2yaml --covmap --covmap-raw %t.o | tee %t.mixed.yaml | FileCheck %s --check-prefixes=CHECK,COVMAP,RAW,DET,LOC,DLOC
+# RUN: obj2yaml --covmap --covmap-dloc %t.o | tee %t.dloc.yaml | FileCheck %s --check-prefixes=CHECK,COVMAP,DET,DETONLY,DLOC
+# RUN: obj2yaml --covmap %t.o | tee %t.covmap.yaml | FileCheck %s --check-prefixes=CHECK,COVMAP,DET,DETONLY,LOC
+# RUN: sed -E '/^(#.*)?$/d' %s | diff %t.covmap.yaml -
 # RUN: yaml2obj %t.plain.yaml -o - | cmp %t.o -
 # RUN: yaml2obj %t.raw.yaml -o - | cmp %t.o -
+# RUN: yaml2obj %t.mixed.yaml -o - | cmp %t.o -
+# RUN: yaml2obj %t.dloc.yaml -o - | cmp %t.o -
+# RUN: yaml2obj %t.covmap.yaml -o - | cmp %t.o -
 
 --- !ELF
 FileHeader:
diff --git a/llvm/tools/obj2yaml/elf2yaml.cpp b/llvm/tools/obj2yaml/elf2yaml.cpp
index 50fd92e24aa3d..c8522636b6240 100644
--- a/llvm/tools/obj2yaml/elf2yaml.cpp
+++ b/llvm/tools/obj2yaml/elf2yaml.cpp
@@ -23,9 +23,15 @@
 
 using namespace llvm;
 
+static cl::opt<bool>
+    CovMapDetailed("covmap", cl::desc("Dump detailed YAML in Coverage Map."),
+                   cl::cat(Cat));
 static cl::opt<bool> CovMapRaw("covmap-raw",
                                cl::desc("Dump raw YAML in Coverage Map."),
                                cl::cat(Cat));
+static cl::opt<bool> CovMapDLoc("covmap-dloc",
+                                cl::desc("Prefer dLoc over absolute Loc."),
+                                cl::cat(Cat));
 
 namespace {
 
@@ -588,7 +594,11 @@ ELFDumper<ELFT>::dumpSections() {
     return Error::success();
   };
 
-  auto CovMapDecoder = covmap::Decoder::get(ELFT::Endianness, CovMapRaw);
+  coverage::yaml::DecoderParam Param;
+  Param.Detailed = CovMapDetailed;
+  Param.Raw = CovMapRaw;
+  Param.dLoc = CovMapDLoc;
+  auto CovMapDecoder = covmap::Decoder::get(ELFT::Endianness, Param);
   if (covmap::Decoder::enabled) {
     // Look up covmap-related sections in advance.
     for (const auto &Sec : Sections) {
@@ -606,10 +616,13 @@ ELFDumper<ELFT>::dumpSections() {
       if (!ContentOrErr)
         return ContentOrErr.takeError();
 
-      if (auto E = CovMapDecoder->acquire(Sec.sh_addralign, *NameOrErr,
-                                          *ContentOrErr))
+      if (auto E = CovMapDecoder->acquire(Sec.sh_offset, Sec.sh_addralign,
+                                          *NameOrErr, *ContentOrErr))
         return std::move(E);
     }
+
+    if (auto E = CovMapDecoder->fixup())
+      return std::move(E);
   }
 
   auto GetDumper = [this](unsigned Type)
@@ -1708,11 +1721,7 @@ ELFDumper<ELFT>::dumpCovMap(const Elf_Shdr *Shdr, StringRef Name,
   if (Error E = dumpCommonSection(Shdr, *S))
     return std::move(E);
 
-  auto ContentOrErr = Obj.getSectionContents(*Shdr);
-  if (!ContentOrErr)
-    return ContentOrErr.takeError();
-
-  if (auto E = CovMapDecoder->make(S.get(), *ContentOrErr))
+  if (auto E = CovMapDecoder->make(S.get(), Shdr->sh_offset))
     return std::move(E);
 
   return S.release();



More information about the llvm-branch-commits mailing list