diff --git a/llvm/include/llvm/ObjectYAML/CovMap.h b/llvm/include/llvm/ObjectYAML/CovMap.h
index 644ea38a08364..697145154d9cc 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"
@@ -35,14 +36,67 @@
 #include <optional>
 #include <string>
 #include <utility>
+#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.
@@ -54,14 +108,24 @@ struct CounterTy {
     Add,
   };
 
-  TagTy Tag;
-  uint64_t Val;
+  /// Optional in detailed view, since most Tag can be determined from
+  /// other optional fields.
+  std::optional<TagTy> Tag;
+
+  /// Internal use.
+  std::optional<uint64_t> Val;
+
+  std::optional<uint64_t> RefOpt;
+  std::optional<uint64_t> SubOpt;
+  std::optional<uint64_t> AddOpt;
 
   virtual ~CounterTy() {}
 
   virtual void mapping(llvm::yaml::IO &IO);
 
-  uint64_t getExtTagVal() const { return (Tag == Zero && Val != 0 ? Val : 0); }
+  uint64_t getExtTagVal() const {
+    return (((!Tag || *Tag == Zero) && Val && *Val != 0) ? *Val : 0);
+  }
 
   /// Holds Val for extensions.
   Error decodeOrTag(DecoderContext &Data);
@@ -120,28 +184,35 @@ struct RecTy : CounterTy {
   /// Stored in ColumnEnd:31.
   std::optional<bool> isGap;
 
-  LocTy dLoc; ///< Differential line numbers.
+  std::optional<LocTy> Loc;  ///< Absolute line numbers.
+  std::optional<LocTy> dLoc; ///< Differential line numbers.
 
   void mapping(llvm::yaml::IO &IO) override;
 
   Error decode(DecoderContext &Data);
 
-  void encode(raw_ostream &OS) const;
+  void encode(uint64_t &StartLoc, raw_ostream &OS) const;
 };
 
 /// {NumRecs, Recs...}
 struct FileRecsTy {
+  std::optional<unsigned> Index;       ///< Shown in detailed view.
+  std::optional<std::string> Filename; ///< Resolved by FileIDs.
   std::vector<RecTy> Recs;
 
   void mapping(llvm::yaml::IO &IO);
 };
 
+/// Key is FilenamesRef.
+using CovMapByRefTy = llvm::DenseMap<uint64_t, struct CovMapTy *>;
+
 /// An element of CovFun array.
 struct CovFunTy {
-  llvm::yaml::Hex64 NameRef;      ///< Hash value of the symbol.
-  llvm::yaml::Hex64 FuncHash;     ///< Signature of this function.
-  llvm::yaml::Hex64 FilenamesRef; ///< Pointer to CovMap
-  std::vector<unsigned> FileIDs;  ///< Resolved by CovMap
+  std::optional<llvm::yaml::Hex64> NameRef;     ///< Hash value of the symbol.
+  std::optional<std::string> FuncName;          ///< Resolved by symtab.
+  llvm::yaml::Hex64 FuncHash;                   ///< Signature of this function.
+  llvm::yaml::Hex64 FilenamesRef;               ///< Pointer to CovMap
+  std::optional<std::vector<unsigned>> FileIDs; ///< Resolved by CovMap
   std::vector<ExpressionTy> Expressions;
   std::vector<FileRecsTy> Files; ///< 2-dimension array of Recs.
 
@@ -149,7 +220,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;
 };
@@ -160,24 +232,63 @@ struct CovMapTy {
   /// format. Calculate and store with Filenames.
   llvm::yaml::Hex64 FilenamesRef;
 
-  uint32_t Version;
+  std::optional<uint32_t> Version;
 
   /// Raw Filenames (and storage of Files)
-  std::vector<std::string> Filenames;
+  std::optional<std::vector<std::string>> Filenames;
+
+  /// Since Version5: Filenames[0] is the working directory (or
+  /// zero-length string). Note that indices in CovFun::FileIDs is
+  /// base on Filenames. (Then, +0, as WD, is not expected to appear)
+  std::optional<std::string> WD;
+  /// 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<VectorOrRef<std::string>> Files;
 
   void mapping(llvm::yaml::IO &IO);
 
+  bool useWD() const { return (!Version || *Version >= 4); }
+  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.
+  std::vector<std::string>
+  generateAccFilenames(const std::optional<ArrayRef<StringRef>> &AccFilesOpt =
+                           std::nullopt) const;
+  /// Regenerate Filenames with WD.
+  /// Use Files if it is not None. Or given AccFiles is used.
+  void
+  regenerateFilenames(const std::optional<ArrayRef<StringRef>> &AccFilesOpt);
 
   /// Encode Filenames. This is mostly used just to obtain FilenamesRef.
-  std::pair<uint64_t, std::string> encodeFilenames(bool Compress = false) const;
+  std::pair<uint64_t, std::string> encodeFilenames(
+      const std::optional<ArrayRef<StringRef>> &AccFilesOpt = std::nullopt,
+      bool Compress = false) const;
 
   void encode(raw_ostream &OS, endianness Endianness) const;
 };
 
 } // 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)
@@ -233,22 +344,46 @@ 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;
 };
 
+class Encoder {
+protected:
+  endianness Endianness;
+
+public:
+  Encoder(endianness Endianness) : Endianness(Endianness) {}
+  virtual ~Encoder() {}
+
+  /// Returns EncoderImpl.
+  static std::unique_ptr<Encoder> get(endianness Endianness);
+
+  /// Called from the Sections loop.
+  virtual void collect(ELFYAML::Chunk *Chunk) = 0;
+
+  /// Resolves names from CovFuns in advance of Emitter. It'd be too
+  /// late to resolve sections in Emitter since they are immutable
+  /// then.
+  virtual void fixup() = 0;
+};
+
 /// Returns whether Name is interested.
 bool nameMatches(StringRef Name);
 
diff --git a/llvm/lib/ObjectYAML/CovMap.cpp b/llvm/lib/ObjectYAML/CovMap.cpp
index 267ea0223659a..e59046ade5423 100644
--- a/llvm/lib/ObjectYAML/CovMap.cpp
+++ b/llvm/lib/ObjectYAML/CovMap.cpp
@@ -12,8 +12,11 @@
 
 #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"
@@ -24,8 +27,10 @@
 #include "llvm/Support/MD5.h"
 #include "llvm/Support/YAMLTraits.h"
 #include "llvm/Support/raw_ostream.h"
+#include <algorithm>
 #include <cstdint>
 #include <memory>
+#include <optional>
 #include <string>
 #include <utility>
 #include <vector>
@@ -41,10 +46,15 @@ bool Decoder::enabled;
 Decoder::~Decoder() {}
 
 // DataExtractor w/ single Cursor
-struct coverage::yaml::DecoderContext : DataExtractor, DataExtractor::Cursor {
-  DecoderContext(const ArrayRef<uint8_t> Content, bool IsLE)
+struct coverage::yaml::DecoderContext : DataExtractor,
+                                        DataExtractor::Cursor,
+                                        DecoderParam {
+  uint64_t LineStart = 0;
+
+  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); }
@@ -59,15 +69,52 @@ struct coverage::yaml::DecoderContext : DataExtractor, DataExtractor::Cursor {
 };
 
 void CounterTy::encode(raw_ostream &OS) const {
-  encodeULEB128(Tag | (Val << 2), OS);
+  std::pair<unsigned, uint64_t> C;
+  if (RefOpt)
+    C = {Ref, *RefOpt};
+  else if (SubOpt)
+    C = {Sub, *SubOpt};
+  else if (AddOpt)
+    C = {Add, *AddOpt};
+  else if (Tag && Val)
+    C = {*Tag, *Val};
+  else if (Tag && *Tag == Zero)
+    C = {Zero, 0u};
+  else
+    llvm_unreachable("Null value cannot be met");
+
+  encodeULEB128(C.first | (C.second << 2), OS);
 }
 
 Error CounterTy::decodeOrTag(DecoderContext &Data) {
   auto COrErr = Data.getULEB128();
   if (!COrErr)
     return COrErr.takeError();
-  Tag = static_cast<TagTy>(*COrErr & 0x03);
-  Val = (*COrErr >> 2);
+  auto T = static_cast<TagTy>(*COrErr & 0x03);
+  auto V = (*COrErr >> 2);
+  if (Data.Raw) {
+    Tag = T;
+    Val = V;
+  } else {
+    switch (T) {
+    case Zero:
+      if (V)
+        Val = V;
+      else
+        Tag = Zero;
+      break;
+    case Ref:
+      RefOpt = V;
+      break;
+    case Sub:
+      SubOpt = V;
+      break;
+    case Add:
+      AddOpt = V;
+      break;
+    }
+  }
+
   return Error::success();
 }
 
@@ -100,7 +147,7 @@ Error DecisionTy::decode(DecoderContext &Data) {
   return Error::success();
 }
 
-void RecTy::encode(raw_ostream &OS) const {
+void RecTy::encode(uint64_t &StartLoc, raw_ostream &OS) const {
   if (Expansion) {
     encodeULEB128(4 + (*Expansion << 3), OS);
   } else if (ExtTag && *ExtTag == Skip) {
@@ -130,10 +177,18 @@ void RecTy::encode(raw_ostream &OS) const {
 
   assert((!isGap || *isGap) && "Don't set isGap=false");
   uint32_t Gap = (isGap ? (1u << 31) : 0u);
-  encodeULEB128(dLoc[0], OS);
-  encodeULEB128(dLoc[1], OS);
-  encodeULEB128(dLoc[2], OS);
-  encodeULEB128(dLoc[3] | Gap, OS);
+  if (Loc) {
+    encodeULEB128((*Loc)[0] - StartLoc, OS);
+    encodeULEB128((*Loc)[1], OS);
+    encodeULEB128((*Loc)[2] - (*Loc)[0], OS);
+    encodeULEB128((*Loc)[3] | Gap, OS);
+    StartLoc = (*Loc)[0];
+  } else {
+    encodeULEB128((*dLoc)[0], OS);
+    encodeULEB128((*dLoc)[1], OS);
+    encodeULEB128((*dLoc)[2], OS);
+    encodeULEB128((*dLoc)[3] | Gap, OS);
+  }
 }
 
 Error RecTy::decode(DecoderContext &Data) {
@@ -165,8 +220,18 @@ Error RecTy::decode(DecoderContext &Data) {
     // Compatible to CounterTy
   } else if (V & 1u) {
     Expansion = (V >> 1);
+    if (!Data.Raw) {
+      assert(!this->Tag || *this->Tag == Zero);
+      this->Tag.reset();
+      this->Val.reset();
+    }
   } else {
     auto Tag = (V >> 1);
+    if (!Data.Raw) {
+      assert(!this->Tag || *this->Tag == Zero);
+      this->Tag.reset();
+      this->Val.reset();
+    }
     switch (Tag) {
     case Skip:
       ExtTag = Skip; // w/o Val
@@ -174,12 +239,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())
@@ -194,7 +261,8 @@ Error RecTy::decode(DecoderContext &Data) {
       if (!I2OrErr)
         return I2OrErr.takeError();
       MCDC = {*I0OrErr, *I1OrErr, *I2OrErr};
-      ExtTag = MCDCBranch;
+      if (Data.Raw)
+        ExtTag = MCDCBranch;
       break;
     }
     default:
@@ -208,6 +276,7 @@ Error RecTy::decode(DecoderContext &Data) {
   auto LSDeltaOrErr = Data.getULEB128();
   if (!LSDeltaOrErr)
     return LSDeltaOrErr.takeError();
+  Data.LineStart += *LSDeltaOrErr;
 
   auto CSOrErr = Data.getULEB128();
   if (!CSOrErr)
@@ -216,6 +285,7 @@ Error RecTy::decode(DecoderContext &Data) {
   auto NLOrErr = Data.getULEB128();
   if (!NLOrErr)
     return NLOrErr.takeError();
+  auto LineEnd = Data.LineStart + *NLOrErr;
 
   auto CEOrErr = Data.getULEB128();
   if (!CEOrErr)
@@ -228,6 +298,7 @@ Error RecTy::decode(DecoderContext &Data) {
   ColumnEnd &= ((1u << 31) - 1);
 
   dLoc = {*LSDeltaOrErr, *CSOrErr, *NLOrErr, ColumnEnd};
+  Loc = {Data.LineStart, *CSOrErr, LineEnd, ColumnEnd};
 
   return Error::success();
 }
@@ -237,6 +308,8 @@ void CovFunTy::encode(raw_ostream &OS, endianness Endianness) const {
   std::string Body;
   raw_string_ostream SS(Body);
 
+  assert(this->FileIDs);
+  auto &FileIDs = *this->FileIDs;
   encodeULEB128(FileIDs.size(), SS);
   for (auto I : FileIDs)
     encodeULEB128(I, SS);
@@ -249,12 +322,14 @@ void CovFunTy::encode(raw_ostream &OS, endianness Endianness) const {
 
   for (const auto &File : Files) {
     encodeULEB128(File.Recs.size(), SS);
+    uint64_t StartLoc = 0;
     for (const auto &Rec : File.Recs)
-      Rec.encode(SS);
+      Rec.encode(StartLoc, SS);
   }
 
   // Emit the Header
-  uint64_t NameRef = this->NameRef;
+  uint64_t NameRef = (this->NameRef ? static_cast<uint64_t>(*this->NameRef)
+                                    : MD5Hash(*this->FuncName));
   uint32_t DataSize = Body.size();
   uint64_t FuncHash = this->FuncHash;
   char CoverageMapping = 0; // dummy
@@ -271,18 +346,60 @@ void CovFunTy::encode(raw_ostream &OS, endianness Endianness) const {
   OS << std::move(Body);
 }
 
+std::vector<std::string> CovMapTy::generateAccFilenames(
+    const std::optional<ArrayRef<StringRef>> &AccFilesOpt) const {
+  std::vector<std::string> Result;
+  if (useWD())
+    Result.push_back(getWD().str());
+  // Returns {WD} if AccFiles is None.
+  if (AccFilesOpt) {
+    for (auto &Filename : *AccFilesOpt)
+      Result.push_back(Filename.str());
+  }
+  return Result;
+}
+
+void CovMapTy::regenerateFilenames(
+    const std::optional<ArrayRef<StringRef>> &AccFilesOpt) {
+  assert(!this->Filenames);
+  if (this->Files) {
+    auto &CovMapFilenames = this->Filenames.emplace(generateAccFilenames());
+    assert(CovMapFilenames.size() <= 1);
+    for (auto &&File : *this->Files)
+      CovMapFilenames.push_back(std::move(File));
+  } else {
+    // Encode Accfiles, that comes from CovFun.
+    this->Filenames = generateAccFilenames(AccFilesOpt);
+  }
+}
+
 std::pair<uint64_t, std::string>
-CovMapTy::encodeFilenames(bool Compress) const {
+CovMapTy::encodeFilenames(const std::optional<ArrayRef<StringRef>> &AccFilesOpt,
+                          bool Compress) const {
+  ArrayRef<std::string> TempFilenames;
+  std::vector<std::string> AccFilenames; // Storage
+
+  if (AccFilesOpt) {
+    AccFilenames = generateAccFilenames(AccFilesOpt);
+    TempFilenames = AccFilenames;
+  } else {
+    assert(this->Filenames);
+    TempFilenames = ArrayRef(*this->Filenames);
+  }
+
   std::string FilenamesBlob;
   llvm::raw_string_ostream OS(FilenamesBlob);
-  CoverageFilenamesSectionWriter(this->Filenames).write(OS, Compress);
+  CoverageFilenamesSectionWriter(TempFilenames).write(OS, Compress);
 
   return {llvm::IndexedInstrProf::ComputeHash(FilenamesBlob), FilenamesBlob};
 }
 
 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;
@@ -301,9 +418,19 @@ 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];
+  auto &FileIDs = this->FileIDs.emplace();
+
   auto NumFilesOrErr = Data.getULEB128();
   if (!NumFilesOrErr)
     return NumFilesOrErr.takeError();
@@ -330,15 +457,30 @@ 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;
     for (unsigned I = 0; I != *NumRegionsOrErr; ++I) {
       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)
+    this->FileIDs.reset();
+
   assert(Data.tell() == ExpectedEndOffset);
   return Data.tell();
 }
@@ -349,7 +491,8 @@ void CovMapTy::encode(raw_ostream &OS, endianness Endianness) const {
   uint32_t NRecords = 0;
   uint32_t FilenamesSize = FilenamesBlob.size();
   uint32_t CoverageSize = 0;
-  uint32_t Version = this->Version;
+  uint32_t Version =
+      (this->Version ? *this->Version : INSTR_PROF_COVMAP_VERSION);
   struct {
 #define COVMAP_HEADER(Type, LLVMType, Name, Initializer) Type Name;
 #include "llvm/ProfileData/InstrProfData.inc"
@@ -368,8 +511,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)                       \
@@ -388,17 +532,31 @@ Expected<uint64_t> CovMapTy::decode(const ArrayRef<uint8_t> Content,
   if (!Data)
     return Data.takeError();
   this->FilenamesRef = MD5Hash(FnBlob);
+  auto &Filenames = this->Filenames.emplace();
   if (auto E = RawCoverageFilenamesReader(FnBlob, Filenames)
                    .read(static_cast<CovMapVersion>(Version)))
     return E;
 
+  if (Param.Detailed && useWD()) {
+    assert(Filenames.size() >= 1);
+    auto FilenamesI = Filenames.begin();
+    StringRef WD = *FilenamesI++;
+    if (!WD.empty())
+      this->WD = WD;
+    // Use Filenames as a storage.
+    this->Files.emplace(MutableArrayRef(&*FilenamesI, &*Filenames.end()));
+  }
+
   Offset = Data.tell();
   return Offset;
 }
 
 void CounterTy::mapping(llvm::yaml::IO &IO) {
-  IO.mapRequired("Tag", Tag);
-  IO.mapRequired("Val", Val);
+  IO.mapOptional("Tag", Tag);
+  IO.mapOptional("Val", Val);
+  IO.mapOptional("Ref", RefOpt);
+  IO.mapOptional("Sub", SubOpt);
+  IO.mapOptional("Add", AddOpt);
 }
 
 void DecisionTy::mapping(llvm::yaml::IO &IO) {
@@ -407,7 +565,8 @@ void DecisionTy::mapping(llvm::yaml::IO &IO) {
 }
 
 void RecTy::mapping(llvm::yaml::IO &IO) {
-  IO.mapRequired("dLoc", dLoc);
+  IO.mapOptional("Loc", Loc);
+  IO.mapOptional("dLoc", dLoc);
   IO.mapOptional("isGap", isGap);
   CounterTy::mapping(IO);
   IO.mapOptional("ExtTag", ExtTag);
@@ -418,22 +577,32 @@ void RecTy::mapping(llvm::yaml::IO &IO) {
 }
 
 void FileRecsTy::mapping(llvm::yaml::IO &IO) {
+  IO.mapOptional("Index", Index);
+  IO.mapOptional("Filename", Filename);
   IO.mapRequired("Regions", Recs);
 }
 
 void CovFunTy::mapping(llvm::yaml::IO &IO) {
-  IO.mapRequired("NameRef", NameRef);
+  IO.mapOptional("NameRef", NameRef);
+  IO.mapOptional("FuncName", FuncName);
   IO.mapRequired("FuncHash", FuncHash);
   IO.mapRequired("FilenamesRef", FilenamesRef);
-  IO.mapRequired("FileIDs", FileIDs);
+  IO.mapOptional("FileIDs", FileIDs);
   IO.mapRequired("Expressions", Expressions);
   IO.mapRequired("Files", Files);
 }
 
 void CovMapTy::mapping(llvm::yaml::IO &IO) {
   IO.mapRequired("FilenamesRef", FilenamesRef);
-  IO.mapRequired("Version", Version);
-  IO.mapRequired("Filenames", Filenames);
+  IO.mapOptional("Version", Version);
+
+  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);
 }
 
 #define ECase(N, X) IO.enumCase(Value, #X, N::X)
@@ -496,7 +665,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) {
@@ -505,7 +674,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();
       }
@@ -541,9 +710,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;
 
@@ -553,7 +723,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();
 
@@ -574,17 +745,127 @@ struct CovFunSection : ELFYAML::CovMapSectionBase {
   }
 };
 
-class DecoderImpl : public Decoder {
+class CovMapFilenamesResolver {
+  DenseMap<uint64_t, SetVector<StringRef>> FilenamesByCovMap;
+  std::vector<CovFunTy *> UnresolvedCovFuns;
+
+protected:
+  CovMapByRefTy CovMapByRef;
+  std::vector<CovMapTy> TempCovMaps; // For Decoder
+
+public:
+  void collectCovMap(std::vector<CovMapTy> &CovMaps) {
+    for (auto &CovMap : CovMaps)
+      CovMapByRef[CovMap.FilenamesRef] = &CovMap;
+  }
+
+  void moveAndCollectCovMap(std::vector<CovMapTy> &&CovMaps) {
+    TempCovMaps = std::move(CovMaps);
+    collectCovMap(TempCovMaps);
+  }
+
+  void collectCovFunFilenames(std::vector<CovFunTy> &CovFuns) {
+    for (auto &CovFun : CovFuns) {
+      auto &Filenames = FilenamesByCovMap[CovFun.FilenamesRef];
+      for (const auto &File : CovFun.Files) {
+        if (!File.Filename)
+          goto skip;
+        Filenames.insert(*File.Filename);
+      }
+      UnresolvedCovFuns.push_back(&CovFun);
+    skip:;
+    }
+  }
+
+  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);
+      if (FilenamesI != FilenamesByCovMap.end()) {
+        // Check Filenames satisfies covfuns
+        DenseSet<StringRef> FilenamesSet;
+        if (CovMap->Files) {
+          for (const auto &Filename : *CovMap->Files)
+            FilenamesSet.insert(Filename);
+        } else if (CovMap->Filenames) {
+          for (const auto &Filename : *CovMap->Filenames)
+            FilenamesSet.insert(Filename);
+        }
+
+        for (const auto &Filename : FilenamesI->second) {
+          if (!FilenamesSet.contains(Filename)) {
+            // If not, regenerate Filenames.
+            CovMap->Files.reset();
+            CovMap->Filenames.reset();
+            break;
+          }
+        }
+      }
+
+      if (!CovMap->Filenames) {
+        // Regenerate.
+        // Use Files if exists.
+        // Use CovFuns (FilenamesI) otherwise.
+        assert(CovMap->Files || FilenamesI != FilenamesByCovMap.end());
+        CovMap->regenerateFilenames(
+            CovMap->Files ? std::nullopt : FilenamesI->second.getArrayRef());
+      }
+      auto [FilenamesRef, FilenamesBlob] = CovMap->encodeFilenames();
+      assert(CovMap->FilenamesRef == FilenamesRef);
+    }
+
+    // Fill FileIDs
+    for (auto *CovFun : UnresolvedCovFuns) {
+      assert(CovMapByRef[CovFun->FilenamesRef]);
+      assert(CovMapByRef[CovFun->FilenamesRef]->Filenames);
+      const auto &CovMapFilenames =
+          *CovMapByRef[CovFun->FilenamesRef]->Filenames;
+      auto &FileIDs = CovFun->FileIDs.emplace();
+      for (const auto &File : CovFun->Files) {
+        auto I = std::find(CovMapFilenames.begin(), CovMapFilenames.end(),
+                           File.Filename);
+        assert(I != CovMapFilenames.end());
+        FileIDs.push_back(std::distance(CovMapFilenames.begin(), I));
+      }
+      assert(CovFun->Files.size() == FileIDs.size());
+    }
+  }
+};
+
+class DecoderImpl : public Decoder, CovMapFilenamesResolver {
+  DecoderParam Param;
+
   std::unique_ptr<InstrProfSymtab> ProfileNames;
-  std::vector<CovMapTy> TempCovMaps;
+
+  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)
@@ -594,44 +875,82 @@ class DecoderImpl : public Decoder {
       // 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;
-      TempCovMaps = std::move(TempCovMap->CovMaps);
+      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();
     }
 
     llvm_unreachable("Unknown Section");
   }
 };
+
+class EncoderImpl : public Encoder, CovMapFilenamesResolver {
+public:
+  EncoderImpl(endianness Endianness) : Encoder(Endianness) {}
+
+  void collect(ELFYAML::Chunk *Chunk) override {
+    if (auto S = dyn_cast<CovMapSection>(Chunk)) {
+      collectCovMap(S->CovMaps);
+    } else if (auto S = dyn_cast<CovFunSection>(Chunk)) {
+      collectCovFunFilenames(S->CovFuns);
+    }
+  }
+
+  void fixup() override { encFixup(); }
+};
 } // 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) {
+  return std::make_unique<EncoderImpl>(Endianness);
 }
 
 bool covmap::nameMatches(StringRef Name) {
diff --git a/llvm/lib/ObjectYAML/ELFEmitter.cpp b/llvm/lib/ObjectYAML/ELFEmitter.cpp
index e55daa72b3cee..d13ab60822a02 100644
--- a/llvm/lib/ObjectYAML/ELFEmitter.cpp
+++ b/llvm/lib/ObjectYAML/ELFEmitter.cpp
@@ -772,6 +772,13 @@ void ELFState<ELFT>::initSectionHeaders(std::vector<Elf_Shdr> &SHeaders,
   // valid SHN_UNDEF entry since SHT_NULL == 0.
   SHeaders.resize(Doc.getSections().size());
 
+  auto CovMapEncoder = covmap::Encoder::get(ELFT::Endianness);
+  for (auto &Chunk : Doc.Chunks) {
+    if (isa<ELFYAML::CovMapSectionBase>(Chunk.get()))
+      CovMapEncoder->collect(Chunk.get());
+  }
+  CovMapEncoder->fixup();
+
   for (const std::unique_ptr<ELFYAML::Chunk> &D : Doc.Chunks) {
     if (ELFYAML::Fill *S = dyn_cast<ELFYAML::Fill>(D.get())) {
       S->Offset = alignToOffset(CBA, /*Align=*/1, S->Offset);
diff --git a/llvm/test/tools/obj2yaml/ELF/covmap-be.yaml b/llvm/test/tools/obj2yaml/ELF/covmap-be.yaml
index 4456bbbcb4a86..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
@@ -19,45 +26,48 @@ Sections:
     Flags:           [ SHF_GNU_RETAIN ]
     AddressAlign:    0x8
     CovFun:
-      - NameRef:         0xA72DB7A33048E6A3
+      - FuncName:        _Z4funci
         FuncHash:        0xAFC772D567676299
         FilenamesRef:    0x70DA2CAFD8CE198E
-        FileIDs:         [ 1, 1 ]
         Expressions:
-          - [ { Tag: Ref, Val: 0 }, { Tag: Ref, Val: 1 } ]
-          - [ { Tag: Add, Val: 0 }, { Tag: Ref, Val: 2 } ]
-          - [ { Tag: Add, Val: 0 }, { Tag: Ref, Val: 2 } ]
-          - [ { Tag: Add, Val: 0 }, { Tag: Ref, Val: 2 } ]
-          - [ { Tag: Ref, Val: 0 }, { Tag: Ref, Val: 2 } ]
-          - [ { Tag: Ref, Val: 0 }, { Tag: Ref, Val: 2 } ]
-          - [ { Tag: Ref, Val: 0 }, { Tag: Ref, Val: 2 } ]
-          - [ { Tag: Add, Val: 0 }, { Tag: Ref, Val: 5 } ]
+          - [ { Ref: 0 }, { Ref: 1 } ]
+          - [ { Add: 0 }, { Ref: 2 } ]
+          - [ { Add: 0 }, { Ref: 2 } ]
+          - [ { Add: 0 }, { Ref: 2 } ]
+          - [ { Ref: 0 }, { Ref: 2 } ]
+          - [ { Ref: 0 }, { Ref: 2 } ]
+          - [ { Ref: 0 }, { Ref: 2 } ]
+          - [ { Add: 0 }, { Ref: 5 } ]
         Files:
-          - Regions:
-              - { dLoc: [ 3, 17, 11, 2 ], Tag: Ref, Val: 0 }
-              - { dLoc: [ 3, 6, 5, 4 ], Tag: Add, Val: 0 }
-              - { dLoc: [ 1, 9, 0, 13 ], Tag: Zero, Val: 3, Expansion: 1 }
-              - { dLoc: [ 0, 23, 1, 7 ], isGap: true, Tag: Ref, Val: 2 }
-              - { dLoc: [ 1, 7, 0, 16 ], Tag: Ref, Val: 2 }
-              - { dLoc: [ 0, 17, 2, 5 ], isGap: true, Tag: Sub, Val: 3 }
-              - { dLoc: [ 1, 1, 0, 1 ], Tag: Zero, Val: 4, ExtTag: Skip }
-              - { dLoc: [ 1, 5, 1, 4 ], Tag: Sub, Val: 3 }
-              - { dLoc: [ 1, 12, 0, 17 ], Tag: Sub, Val: 3 }
-              - { dLoc: [ 0, 12, 0, 17 ], Tag: Zero, Val: 8, ExtTag: Branch, Branch: [ { Tag: Ref, Val: 1 }, { Tag: Sub, Val: 6 } ] }
-              - { dLoc: [ 0, 19, 1, 3 ], isGap: true, Tag: Sub, Val: 6 }
-              - { dLoc: [ 1, 3, 0, 11 ], Tag: Sub, Val: 6 }
-              - { dLoc: [ 0, 12, 1, 3 ], isGap: true, Tag: Zero, Val: 0 }
-              - { dLoc: [ 1, 3, 0, 12 ], Tag: Zero, Val: 0 }
-          - Regions:
-              - { dLoc: [ 1, 17, 0, 41 ], Tag: Add, Val: 0 }
-              - { dLoc: [ 0, 18, 0, 32 ], Tag: Add, Val: 0 }
-              - { dLoc: [ 0, 18, 0, 40 ], Tag: Zero, Val: 10, ExtTag: Decision, Decision: { BIdx: 5, NCond: 3 } }
-              - { dLoc: [ 0, 19, 0, 22 ], Tag: Add, Val: 0 }
-              - { dLoc: [ 0, 19, 0, 22 ], Tag: Zero, Val: 12, ExtTag: MCDCBranch, Branch: [ { Tag: Sub, Val: 7 }, { Tag: Ref, Val: 5 } ], MCDC: [ 1, 2, 3 ] }
-              - { dLoc: [ 0, 26, 0, 31 ], Tag: Ref, Val: 5 }
-              - { dLoc: [ 0, 26, 0, 31 ], Tag: Zero, Val: 12, ExtTag: MCDCBranch, Branch: [ { Tag: Zero, Val: 0 }, { Tag: Ref, Val: 6 } ], MCDC: [ 3, 2, 0 ] }
-              - { dLoc: [ 0, 36, 0, 40 ], Tag: Ref, Val: 3 }
-              - { dLoc: [ 0, 36, 0, 40 ], Tag: Zero, Val: 12, ExtTag: MCDCBranch, Branch: [ { Tag: Ref, Val: 4 }, { Tag: Zero, Val: 0 } ], MCDC: [ 2, 0, 0 ] }
+          - Index:           0
+            Filename:        func.cpp
+            Regions:
+              - { Loc: [ 3, 17, 14, 2 ], Ref: 0 }
+              - { Loc: [ 6, 6, 11, 4 ], Add: 0 }
+              - { Loc: [ 7, 9, 7, 13 ], Expansion: 1 }
+              - { Loc: [ 7, 23, 8, 7 ], isGap: true, Ref: 2 }
+              - { Loc: [ 8, 7, 8, 16 ], Ref: 2 }
+              - { Loc: [ 8, 17, 10, 5 ], isGap: true, Sub: 3 }
+              - { Loc: [ 9, 1, 9, 1 ], ExtTag: Skip }
+              - { Loc: [ 10, 5, 11, 4 ], Sub: 3 }
+              - { Loc: [ 11, 12, 11, 17 ], Sub: 3 }
+              - { Loc: [ 11, 12, 11, 17 ], Branch: [ { Ref: 1 }, { Sub: 6 } ] }
+              - { Loc: [ 11, 19, 12, 3 ], isGap: true, Sub: 6 }
+              - { Loc: [ 12, 3, 12, 11 ], Sub: 6 }
+              - { Loc: [ 12, 12, 13, 3 ], isGap: true, Tag: Zero }
+              - { Loc: [ 13, 3, 13, 12 ], Tag: Zero }
+          - Index:           1
+            Filename:        func.cpp
+            Regions:
+              - { Loc: [ 1, 17, 1, 41 ], Add: 0 }
+              - { Loc: [ 1, 18, 1, 32 ], Add: 0 }
+              - { Loc: [ 1, 18, 1, 40 ], Decision: { BIdx: 5, NCond: 3 } }
+              - { Loc: [ 1, 19, 1, 22 ], Add: 0 }
+              - { Loc: [ 1, 19, 1, 22 ], Branch: [ { Sub: 7 }, { Ref: 5 } ], MCDC: [ 1, 2, 3 ] }
+              - { Loc: [ 1, 26, 1, 31 ], Ref: 5 }
+              - { Loc: [ 1, 26, 1, 31 ], Branch: [ { Tag: Zero }, { Ref: 6 } ], MCDC: [ 3, 2, 0 ] }
+              - { Loc: [ 1, 36, 1, 40 ], Ref: 3 }
+              - { Loc: [ 1, 36, 1, 40 ], Branch: [ { Ref: 4 }, { Tag: Zero } ], MCDC: [ 2, 0, 0 ] }
   - Name:            __llvm_covmap
     Type:            SHT_PROGBITS
     Flags:           [ SHF_GNU_RETAIN ]
@@ -65,9 +75,6 @@ Sections:
     CovMap:
       - FilenamesRef:    0x70DA2CAFD8CE198E
         Version:         6
-        Filenames:
-          - ''
-          - func.cpp
   - Name:            __llvm_prf_names
     Type:            SHT_PROGBITS
     Flags:           [ SHF_ALLOC, SHF_GNU_RETAIN ]
diff --git a/llvm/test/tools/obj2yaml/ELF/covmap.yaml b/llvm/test/tools/obj2yaml/ELF/covmap.yaml
index 09bcf86b44f47..1876492351d6a 100644
--- a/llvm/test/tools/obj2yaml/ELF/covmap.yaml
+++ b/llvm/test/tools/obj2yaml/ELF/covmap.yaml
@@ -1,9 +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: sed -E '/^(#.*)?$/d' %s | diff %t.raw.yaml -
+# 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:
@@ -23,74 +29,91 @@ Sections:
 # COVMAP: CovFun:
     CovFun:
 # RAW:- NameRef:         0xA72DB7A33048E6A3
-      - NameRef:         0xA72DB7A33048E6A3
+      - FuncName:        _Z4funci
 # COVMAP: FuncHash:      0xAFC772D567676299
         FuncHash:        0xAFC772D567676299
         FilenamesRef:    0x70DA2CAFD8CE198E
 # RAW:  FileIDs:         [ 1, 1 ]
-        FileIDs:         [ 1, 1 ]
 # COVMAP: Expressions:
         Expressions:
 # RAW:    - [ { Tag: Ref, Val: 0 }, { Tag: Ref, Val: 1 } ]
-          - [ { Tag: Ref, Val: 0 }, { Tag: Ref, Val: 1 } ]
-          - [ { Tag: Add, Val: 0 }, { Tag: Ref, Val: 2 } ]
-          - [ { Tag: Add, Val: 0 }, { Tag: Ref, Val: 2 } ]
-          - [ { Tag: Add, Val: 0 }, { Tag: Ref, Val: 2 } ]
-          - [ { Tag: Ref, Val: 0 }, { Tag: Ref, Val: 2 } ]
-          - [ { Tag: Ref, Val: 0 }, { Tag: Ref, Val: 2 } ]
-          - [ { Tag: Ref, Val: 0 }, { Tag: Ref, Val: 2 } ]
-          - [ { Tag: Add, Val: 0 }, { Tag: Ref, Val: 5 } ]
+          - [ { Ref: 0 }, { Ref: 1 } ]
+          - [ { Add: 0 }, { Ref: 2 } ]
+          - [ { Add: 0 }, { Ref: 2 } ]
+          - [ { Add: 0 }, { Ref: 2 } ]
+          - [ { Ref: 0 }, { Ref: 2 } ]
+          - [ { Ref: 0 }, { Ref: 2 } ]
+          - [ { Ref: 0 }, { Ref: 2 } ]
+          - [ { Add: 0 }, { Ref: 5 } ]
 # COVMAP: Files:
         Files:
+# DET:    - Index:           0
+          - Index:           0
+# DET:      Filename:        func.cpp
+            Filename:        func.cpp
 # COVMAP:   Regions:
-          - Regions:
+            Regions:
+# LOC:     Loc: [ 3, 17, 14, 2 ]
 # RAWONLY-NOT: Loc: [ 3, 17, 14, 2 ]
 # DLOC:   dLoc: [ 3, 17, 11, 2 ]
 # RAW:     Tag: Ref, Val: 0
-              - { dLoc: [ 3, 17, 11, 2 ], Tag: Ref, Val: 0 }
+# DETONLY: Ref: 0
+              - { Loc: [ 3, 17, 14, 2 ], Ref: 0 }
+# LOC:     Loc: [ 6, 6, 11, 4 ]
 # DLOC:   dLoc: [ 3, 6, 5, 4 ]
 # RAW:     Tag: Add, Val: 0
-              - { dLoc: [ 3, 6, 5, 4 ], Tag: Add, Val: 0 }
+# DETONLY: Add: 0
+              - { Loc: [ 6, 6, 11, 4 ], Add: 0 }
 # RAW:    Tag: Zero, Val: 3,
 # COVMAP: Expansion: 1
-              - { dLoc: [ 1, 9, 0, 13 ], Tag: Zero, Val: 3, Expansion: 1 }
+              - { Loc: [ 7, 9, 7, 13 ], Expansion: 1 }
 # COVMAP: isGap: true
 # RAW:      Tag: Ref, Val: 2
-              - { dLoc: [ 0, 23, 1, 7 ], isGap: true, Tag: Ref, Val: 2 }
-              - { dLoc: [ 1, 7, 0, 16 ], Tag: Ref, Val: 2 }
+# DETONLY:  Ref: 2
+              - { Loc: [ 7, 23, 8, 7 ], isGap: true, Ref: 2 }
+              - { Loc: [ 8, 7, 8, 16 ], Ref: 2 }
 # COVMAP: isGap: true
 # RAW:      Tag: Sub, Val: 3
-              - { dLoc: [ 0, 17, 2, 5 ], isGap: true, Tag: Sub, Val: 3 }
+# DETONLY:  Sub: 3
+              - { Loc: [ 8, 17, 10, 5 ], isGap: true, Sub: 3 }
 # RAW:    Tag: Zero, Val: 4,
 # COVMAP: ExtTag: Skip
-              - { dLoc: [ 1, 1, 0, 1 ], Tag: Zero, Val: 4, ExtTag: Skip }
-              - { dLoc: [ 1, 5, 1, 4 ], Tag: Sub, Val: 3 }
-              - { dLoc: [ 1, 12, 0, 17 ], Tag: Sub, Val: 3 }
+              - { Loc: [ 9, 1, 9, 1 ], ExtTag: Skip }
+              - { Loc: [ 10, 5, 11, 4 ], Sub: 3 }
+              - { Loc: [ 11, 12, 11, 17 ], Sub: 3 }
 # RAW:    Tag: Zero, Val: 8, ExtTag: Branch, Branch: [ { Tag: Ref, Val: 1 }, { Tag: Sub, Val: 6 } ] }
-              - { dLoc: [ 0, 12, 0, 17 ], Tag: Zero, Val: 8, ExtTag: Branch, Branch: [ { Tag: Ref, Val: 1 }, { Tag: Sub, Val: 6 } ] }
-              - { dLoc: [ 0, 19, 1, 3 ], isGap: true, Tag: Sub, Val: 6 }
-              - { dLoc: [ 1, 3, 0, 11 ], Tag: Sub, Val: 6 }
+# DETONLY: Branch: [ { Ref: 1 }, { Sub: 6 } ]
+              - { Loc: [ 11, 12, 11, 17 ], Branch: [ { Ref: 1 }, { Sub: 6 } ] }
+              - { Loc: [ 11, 19, 12, 3 ], isGap: true, Sub: 6 }
+              - { Loc: [ 12, 3, 12, 11 ], Sub: 6 }
+              - { Loc: [ 12, 12, 13, 3 ], isGap: true, Tag: Zero }
+# LOC:    Loc: [ 13, 3, 13, 12 ]
 # DLOC:  dLoc: [ 1, 3, 0, 12 ]
 # COVMAP: Tag: Zero
 # RAW:    Val: 0
-              - { dLoc: [ 0, 12, 1, 3 ], isGap: true, Tag: Zero, Val: 0 }
-              - { dLoc: [ 1, 3, 0, 12 ], Tag: Zero, Val: 0 }
+              - { Loc: [ 13, 3, 13, 12 ], Tag: Zero }
+# DET:    - Index:           1
+          - Index:           1
+# DET:      Filename:        func.cpp
+            Filename:        func.cpp
 # COVMAP:   Regions:
-          - Regions:
-              - { dLoc: [ 1, 17, 0, 41 ], Tag: Add, Val: 0 }
-              - { dLoc: [ 0, 18, 0, 32 ], Tag: Add, Val: 0 }
+            Regions:
+              - { Loc: [ 1, 17, 1, 41 ], Add: 0 }
+              - { Loc: [ 1, 18, 1, 32 ], Add: 0 }
 # RAW:    Tag: Zero, Val: 10, ExtTag: Decision
 # COVMAP: Decision: { BIdx: 5, NCond: 3 } }
-              - { dLoc: [ 0, 18, 0, 40 ], Tag: Zero, Val: 10, ExtTag: Decision, Decision: { BIdx: 5, NCond: 3 } }
-              - { dLoc: [ 0, 19, 0, 22 ], Tag: Add, Val: 0 }
+              - { Loc: [ 1, 18, 1, 40 ], Decision: { BIdx: 5, NCond: 3 } }
+              - { Loc: [ 1, 19, 1, 22 ], Add: 0 }
 # RAW:    Tag: Zero, Val: 12, ExtTag: MCDCBranch, Branch: [ { Tag: Sub, Val: 7 }, { Tag: Ref, Val: 5 } ]
+# DETONLY: Branch: [ { Sub: 7 }, { Ref: 5 } ]
 # COVMAP: MCDC: [ 1, 2, 3 ]
-              - { dLoc: [ 0, 19, 0, 22 ], Tag: Zero, Val: 12, ExtTag: MCDCBranch, Branch: [ { Tag: Sub, Val: 7 }, { Tag: Ref, Val: 5 } ], MCDC: [ 1, 2, 3 ] }
-              - { dLoc: [ 0, 26, 0, 31 ], Tag: Ref, Val: 5 }
-              - { dLoc: [ 0, 26, 0, 31 ], Tag: Zero, Val: 12, ExtTag: MCDCBranch, Branch: [ { Tag: Zero, Val: 0 }, { Tag: Ref, Val: 6 } ], MCDC: [ 3, 2, 0 ] }
-              - { dLoc: [ 0, 36, 0, 40 ], Tag: Ref, Val: 3 }
+              - { Loc: [ 1, 19, 1, 22 ], Branch: [ { Sub: 7 }, { Ref: 5 } ], MCDC: [ 1, 2, 3 ] }
+              - { Loc: [ 1, 26, 1, 31 ], Ref: 5 }
+              - { Loc: [ 1, 26, 1, 31 ], Branch: [ { Tag: Zero }, { Ref: 6 } ], MCDC: [ 3, 2, 0 ] }
+              - { Loc: [ 1, 36, 1, 40 ], Ref: 3 }
+# LOC:     Loc: [ 1, 36, 1, 40 ]
 # DLOC:   dLoc: [ 0, 36, 0, 40 ]
-              - { dLoc: [ 0, 36, 0, 40 ], Tag: Zero, Val: 12, ExtTag: MCDCBranch, Branch: [ { Tag: Ref, Val: 4 }, { Tag: Zero, Val: 0 } ], MCDC: [ 2, 0, 0 ] }
+              - { Loc: [ 1, 36, 1, 40 ], Branch: [ { Ref: 4 }, { Tag: Zero } ], MCDC: [ 2, 0, 0 ] }
 # CHECK:             __llvm_covmap
   - Name:            __llvm_covmap
     Type:            SHT_PROGBITS
@@ -104,11 +127,8 @@ Sections:
 # COVMAP: Version:
         Version:         6
 # RAWONLY: Filenames:
-        Filenames:
 # RAWONLY:    - ''
-          - ''
 # RAWONLY:    - func.cpp
-          - func.cpp
 # CHECK:             __llvm_prf_names
   - Name:            __llvm_prf_names
     Type:            SHT_PROGBITS
diff --git a/llvm/tools/obj2yaml/elf2yaml.cpp b/llvm/tools/obj2yaml/elf2yaml.cpp
index aba494c0f1173..4a072b528a5ea 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();