https://github.com/chapuni updated https://github.com/llvm/llvm-project/pull/127432
>From 7e29d6ace39058b631dcfff5533d8aee055de6dd Mon Sep 17 00:00:00 2001 From: NAKAMURA Takumi <geek4ci...@gmail.com> Date: Mon, 3 Mar 2025 12:25:13 +0900 Subject: [PATCH] obj2yaml --- llvm/include/llvm/ObjectYAML/CovMap.h | 47 ++- llvm/include/llvm/ProfileData/InstrProf.h | 6 + llvm/lib/ObjectYAML/CovMap.cpp | 377 +++++++++++++++++++- llvm/lib/ProfileData/InstrProf.cpp | 23 +- llvm/test/tools/obj2yaml/ELF/covmap-be.yaml | 2 + llvm/test/tools/obj2yaml/ELF/covmap.yaml | 2 + llvm/tools/obj2yaml/elf2yaml.cpp | 59 ++- llvm/tools/obj2yaml/obj2yaml.cpp | 2 +- llvm/tools/obj2yaml/obj2yaml.h | 4 + 9 files changed, 512 insertions(+), 10 deletions(-) diff --git a/llvm/include/llvm/ObjectYAML/CovMap.h b/llvm/include/llvm/ObjectYAML/CovMap.h index 3a0b86435d490..406204ee024fb 100644 --- a/llvm/include/llvm/ObjectYAML/CovMap.h +++ b/llvm/include/llvm/ObjectYAML/CovMap.h @@ -16,7 +16,7 @@ // // - llvm::covmap // -// Provides YAML encoder for coverage map. +// Provides YAML encoder and decoder for coverage map. // //===----------------------------------------------------------------------===// @@ -27,6 +27,7 @@ #include "llvm/ADT/StringRef.h" #include "llvm/ObjectYAML/ELFYAML.h" #include "llvm/Support/Endian.h" +#include "llvm/Support/Error.h" #include "llvm/Support/YAMLTraits.h" #include <array> #include <cstdint> @@ -41,6 +42,8 @@ class raw_ostream; namespace llvm::coverage::yaml { +struct DecoderContext; + /// Base Counter, corresponding to coverage::Counter. struct CounterTy { enum TagTy : uint8_t { @@ -65,6 +68,12 @@ struct CounterTy { virtual void mapping(llvm::yaml::IO &IO); + /// Holds Val for extensions. + Error decodeOrTag(DecoderContext &Data); + + /// Raise Error if Val isn't empty. + Error decode(DecoderContext &Data); + void encode(raw_ostream &OS) const; }; @@ -85,6 +94,8 @@ struct DecisionTy { void mapping(llvm::yaml::IO &IO); + Error decode(DecoderContext &Data); + void encode(raw_ostream &OS) const; }; @@ -118,6 +129,8 @@ struct RecTy : CounterTy { void mapping(llvm::yaml::IO &IO) override; + Error decode(DecoderContext &Data); + void encode(uint64_t &StartLoc, raw_ostream &OS) const; }; @@ -142,6 +155,10 @@ struct CovFunTy { void mapping(llvm::yaml::IO &IO); + /// Depends on CovMap and SymTab(IPSK_names) + Expected<uint64_t> decode(const ArrayRef<uint8_t> Content, uint64_t Offset, + endianness Endianness); + void encode(raw_ostream &OS, endianness Endianness) const; }; @@ -170,6 +187,9 @@ struct CovMapTy { 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); + /// Generate Accumulated list with WD. /// Returns a single element {WD} if AccFiles is not given. std::vector<std::string> @@ -236,6 +256,31 @@ LLVM_COVERAGE_YAML_ELEM_MAPPING(CovMapTy) namespace llvm::covmap { +class Decoder { +protected: + endianness Endianness; + +public: + Decoder(endianness Endianness) : Endianness(Endianness) {} + virtual ~Decoder() {} + + /// Returns DecoderImpl. + static std::unique_ptr<Decoder> get(endianness Endianness, + bool CovMapEnabled); + + /// Called from the Sections loop in advance of the final dump. + /// Decoder predecodes CovMap for Version info. + virtual Error acquire(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; + + /// Suppress emission of CovMap unless enabled. + static bool enabled; +}; + class Encoder { protected: endianness Endianness; diff --git a/llvm/include/llvm/ProfileData/InstrProf.h b/llvm/include/llvm/ProfileData/InstrProf.h index 7133c0c6a302c..e20424da3cac2 100644 --- a/llvm/include/llvm/ProfileData/InstrProf.h +++ b/llvm/include/llvm/ProfileData/InstrProf.h @@ -545,6 +545,12 @@ class InstrProfSymtab { /// This method is a wrapper to \c readAndDecodeStrings method. Error create(StringRef NameStrings); + // PrfNames is nested array. + using PrfNamesTy = SmallVector<std::string>; + using PrfNamesChunksTy = SmallVector<PrfNamesTy, 1>; + + Expected<PrfNamesChunksTy> createAndGetList(ArrayRef<uint8_t> Content); + /// Initialize symtab states with function names and vtable names. \c /// FuncNameStrings is a string composed of one or more encoded function name /// strings, and \c VTableNameStrings composes of one or more encoded vtable diff --git a/llvm/lib/ObjectYAML/CovMap.cpp b/llvm/lib/ObjectYAML/CovMap.cpp index 7662284caee76..dcf90f7b109cb 100644 --- a/llvm/lib/ObjectYAML/CovMap.cpp +++ b/llvm/lib/ObjectYAML/CovMap.cpp @@ -6,7 +6,7 @@ // //===----------------------------------------------------------------------===// // -// Implementations of CovMap and encoder. +// Implementations of CovMap, encoder, decoder. // //===----------------------------------------------------------------------===// @@ -15,9 +15,11 @@ #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ObjectYAML/ELFYAML.h" +#include "llvm/ProfileData/Coverage/CoverageMappingReader.h" #include "llvm/ProfileData/Coverage/CoverageMappingWriter.h" #include "llvm/ProfileData/InstrProf.h" #include "llvm/Support/Alignment.h" +#include "llvm/Support/DataExtractor.h" #include "llvm/Support/Endian.h" #include "llvm/Support/LEB128.h" #include "llvm/Support/MD5.h" @@ -37,6 +39,28 @@ using namespace llvm; using namespace llvm::coverage::yaml; using namespace llvm::covmap; +bool Decoder::enabled; + +// DataExtractor w/ single Cursor +struct coverage::yaml::DecoderContext : DataExtractor, DataExtractor::Cursor { + uint64_t LineStart = 0; + + DecoderContext(const ArrayRef<uint8_t> Content, bool IsLE) + : DataExtractor(Content, IsLE, /*AddressSize=*/0), + DataExtractor::Cursor(0) {} + + bool eof() { return DataExtractor::eof(*this); } + uint32_t getU32() { return DataExtractor::getU32(*this); } + uint64_t getU64() { return DataExtractor::getU64(*this); } + Expected<uint64_t> getULEB128() { + uint64_t Result = DataExtractor::getULEB128(*this); + if (!*this) + return takeError(); + return Result; + } + StringRef getBytes(size_t sz) { return DataExtractor::getBytes(*this, sz); } +}; + void CounterTy::encode(raw_ostream &OS) const { std::pair<unsigned, uint64_t> C; if (RefOpt) @@ -55,11 +79,55 @@ void CounterTy::encode(raw_ostream &OS) const { encodeULEB128(C.first | (C.second << 2), OS); } +Error CounterTy::decodeOrTag(DecoderContext &Data) { + auto COrErr = Data.getULEB128(); + if (!COrErr) + return COrErr.takeError(); + auto T = static_cast<TagTy>(*COrErr & 0x03); + auto V = (*COrErr >> 2); + if (T == Zero) { + if (V == 0) + Tag = Zero; // w/o Val + else + Val = V; // w/o Tag + } else { + Tag = T; + Val = V; + } + + return Error::success(); +} + +Error CounterTy::decode(DecoderContext &Data) { + if (auto E = decodeOrTag(Data)) + return E; + if (!this->Tag && this->Val) + return make_error<CoverageMapError>( + coveragemap_error::malformed, + "Counter::Zero shouldn't have the Val: 0x" + + Twine::utohexstr(*this->Val)); + return Error::success(); +} + void DecisionTy::encode(raw_ostream &OS) const { encodeULEB128(BIdx, OS); encodeULEB128(NC, OS); } +Error DecisionTy::decode(DecoderContext &Data) { + auto BIdxOrErr = Data.getULEB128(); + if (!BIdxOrErr) + return BIdxOrErr.takeError(); + BIdx = *BIdxOrErr; + + auto NCOrErr = Data.getULEB128(); + if (!NCOrErr) + return NCOrErr.takeError(); + NC = *NCOrErr; + + return Error::success(); +} + void RecTy::encode(uint64_t &StartLoc, raw_ostream &OS) const { if (Expansion) { encodeULEB128(4 + (*Expansion << 3), OS); @@ -104,6 +172,106 @@ void RecTy::encode(uint64_t &StartLoc, raw_ostream &OS) const { } } +Error RecTy::decode(DecoderContext &Data) { + auto getU16 = [&]() -> Expected<uint16_t> { + auto ValOrErr = Data.getULEB128(); + if (!ValOrErr) + return ValOrErr.takeError(); + if (*ValOrErr > 0x7FFF + 1) + return make_error<CoverageMapError>(coveragemap_error::malformed, + "MC/DC index is out of range: 0x" + + Twine::utohexstr(*ValOrErr)); + return static_cast<uint16_t>(*ValOrErr); + }; + + auto decodeBranch = [&]() -> Error { + auto &B = BranchOpt.emplace(); + if (auto E = B[0].decode(Data)) + return E; + if (auto E = B[1].decode(Data)) + return E; + return Error::success(); + }; + + // Decode tagged CounterTy + if (auto E = CounterTy::decodeOrTag(Data)) + return E; + if (!this->Val || this->Tag) { + // Compatible to CounterTy + } else if (*this->Val & 1u) { + Expansion = (*this->Val >> 1); + this->Val.reset(); + } else { + auto Tag = *this->Val >> 1; + this->Val.reset(); + switch (Tag) { + case Skip: + ExtTag = Skip; // w/o Val + break; + case Decision: + if (auto E = DecisionOpt.emplace().decode(Data)) + return E; + ExtTag = Decision; + break; + case Branch: + if (auto E = decodeBranch()) + return E; + ExtTag = Branch; + break; + case MCDCBranch: { + if (auto E = decodeBranch()) + return E; + auto I0OrErr = getU16(); + if (!I0OrErr) + return I0OrErr.takeError(); + auto I1OrErr = getU16(); + if (!I1OrErr) + return I1OrErr.takeError(); + auto I2OrErr = getU16(); + if (!I2OrErr) + return I2OrErr.takeError(); + MCDC = {*I0OrErr, *I1OrErr, *I2OrErr}; + ExtTag = MCDCBranch; + break; + } + default: + return make_error<CoverageMapError>( + coveragemap_error::malformed, + "Record doesn't have a valid Tag: 0x" + Twine::utohexstr(Tag)); + } + } + + // Decode Loc + auto LSDeltaOrErr = Data.getULEB128(); + if (!LSDeltaOrErr) + return LSDeltaOrErr.takeError(); + Data.LineStart += *LSDeltaOrErr; + + auto CSOrErr = Data.getULEB128(); + if (!CSOrErr) + return CSOrErr.takeError(); + + auto NLOrErr = Data.getULEB128(); + if (!NLOrErr) + return NLOrErr.takeError(); + auto LineEnd = Data.LineStart + *NLOrErr; + + auto CEOrErr = Data.getULEB128(); + if (!CEOrErr) + return CEOrErr.takeError(); + auto ColumnEnd = *CEOrErr; + + // Gap is set in ColumnEnd:31 + if (ColumnEnd & (1u << 31)) + isGap = true; + ColumnEnd &= ((1u << 31) - 1); + + dLoc = {*LSDeltaOrErr, *CSOrErr, *NLOrErr, ColumnEnd}; + Loc = {Data.LineStart, *CSOrErr, LineEnd, ColumnEnd}; + + return Error::success(); +} + void CovFunTy::encode(raw_ostream &OS, endianness Endianness) const { // Encode Body in advance since DataSize should be known. std::string Body; @@ -194,6 +362,72 @@ CovMapTy::encodeFilenames(const std::optional<ArrayRef<StringRef>> &AccFilesOpt, 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)); + Data.seek(Offset); + + uint32_t DataSize; + [[maybe_unused]] char CoverageMapping; // Ignored + +#define COVMAP_FUNC_RECORD(Type, LLVMType, Name, Initializer) \ + if (sizeof(Type) == sizeof(uint64_t)) \ + Name = Data.getU64(); \ + else if (sizeof(Type) == sizeof(uint32_t)) \ + Name = Data.getU32(); \ + else \ + assert(sizeof(Type) == sizeof(CoverageMapping) && "Unknown type"); + +#include "llvm/ProfileData/InstrProfData.inc" + + if (!Data) + return Data.takeError(); + + [[maybe_unused]] auto ExpectedEndOffset = Data.tell() + DataSize; + + // Decode body. + FileIDs.emplace(); + + auto NumFilesOrErr = Data.getULEB128(); + if (!NumFilesOrErr) + return NumFilesOrErr.takeError(); + for (unsigned I = 0, E = *NumFilesOrErr; I != E; ++I) { + if (auto IDOrErr = Data.getULEB128()) + FileIDs->push_back(*IDOrErr); + else + return IDOrErr.takeError(); + } + + auto NumExprOrErr = Data.getULEB128(); + if (!NumExprOrErr) + return NumExprOrErr.takeError(); + Expressions.resize(*NumExprOrErr); + for (auto &[LHS, RHS] : Expressions) { + if (auto E = LHS.decode(Data)) + return std::move(E); + if (auto E = RHS.decode(Data)) + return std::move(E); + } + + for (unsigned FileIdx = 0; FileIdx != *NumFilesOrErr; ++FileIdx) { + auto NumRegionsOrErr = Data.getULEB128(); + if (!NumRegionsOrErr) + return NumRegionsOrErr.takeError(); + auto &File = Files.emplace_back(); + + // 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); + } + } + + assert(Data.tell() == ExpectedEndOffset); + return Data.tell(); +} + void CovMapTy::encode(raw_ostream &OS, endianness Endianness) const { auto [FilenamesRef, FilenamesBlob] = encodeFilenames(); @@ -219,6 +453,36 @@ void CovMapTy::encode(raw_ostream &OS, endianness Endianness) const { OS << FilenamesBlob; } +Expected<uint64_t> CovMapTy::decode(const ArrayRef<uint8_t> Content, + uint64_t Offset, endianness Endianness) { + DecoderContext Data(Content, (Endianness == endianness::little)); + Data.seek(Offset); + +#define COVMAP_HEADER(Type, LLVMType, Name, Initializer) \ + static_assert(sizeof(Type) == sizeof(uint32_t)); \ + Type Name = Data.getU32(); +#include "llvm/ProfileData/InstrProfData.inc" + if (!Data) + return Data.takeError(); + assert(NRecords == 0); + // +1: uint32_t FilenamesSize; + assert(CoverageSize == 0); + this->Version = Version; + + // Decode Body -- Filenames. + StringRef FnBlob = Data.getBytes(FilenamesSize); + if (!Data) + return Data.takeError(); + this->FilenamesRef = MD5Hash(FnBlob); + this->Filenames.emplace(); + if (auto E = RawCoverageFilenamesReader(FnBlob, *this->Filenames) + .read(static_cast<CovMapVersion>(Version))) + return E; + + Offset = Data.tell(); + return Offset; +} + void CounterTy::mapping(llvm::yaml::IO &IO) { IO.mapOptional("Tag", Tag); IO.mapOptional("Val", Val); @@ -289,8 +553,7 @@ void llvm::yaml::ScalarEnumerationTraits<RecTy::ExtTagTy>::enumeration( namespace { struct PrfNamesSection : ELFYAML::CovMapSectionBase { - using PrfNamesTy = SmallVector<std::string>; - SmallVector<PrfNamesTy, 1> PrfNames; + InstrProfSymtab::PrfNamesChunksTy PrfNames; PrfNamesSection() { Name = "__llvm_prf_names"; } static bool nameMatches(StringRef Name) { return Name == "__llvm_prf_names"; } @@ -328,6 +591,26 @@ struct CovMapSection : ELFYAML::CovMapSectionBase { IO.mapOptional("CovMap", CovMaps); } + Error decode(ArrayRef<uint8_t> Blob, unsigned AddressAlign, + endianness Endianness) { + uint64_t Offset = 0; + + while (true) { + Offset = llvm::alignTo(Offset, AddressAlign); + if (Offset >= Blob.size()) { + break; + } + auto &CovMap = CovMaps.emplace_back(); + auto Result = CovMap.decode(Blob, Offset, Endianness); + if (!Result) { + return Result.takeError(); + } + Offset = *Result; + } + + return Error::success(); + } + Error encode(raw_ostream &OS, endianness Endianness) const override { auto BaseOffset = OS.tell(); for (const auto &CovMap : CovMaps) { @@ -354,6 +637,28 @@ struct CovFunSection : ELFYAML::CovMapSectionBase { IO.mapOptional("CovFun", CovFuns); } + static Expected<std::vector<CovFunTy>> decode(ArrayRef<uint8_t> CovFunA, + unsigned AddressAlign, + endianness Endianness) { + std::vector<CovFunTy> CovFuns; + uint64_t Offset = 0; + + while (true) { + Offset = llvm::alignTo(Offset, AddressAlign); + if (Offset >= CovFunA.size()) + break; + + auto &CovFun = CovFuns.emplace_back(); + auto Result = CovFun.decode(CovFunA, Offset, Endianness); + if (!Result) + return Result.takeError(); + + Offset = *Result; + } + + return std::move(CovFuns); + } + Error encode(raw_ostream &OS, endianness Endianness) const override { auto BaseOffset = OS.tell(); for (auto [I, CovFun] : enumerate(CovFuns)) { @@ -371,6 +676,7 @@ class CovMapFilenamesResolver { protected: DenseMap<uint64_t, struct CovMapTy *> CovMapByRef; + std::vector<CovMapTy> TempCovMaps; // For Decoder public: void collectCovMap(std::vector<CovMapTy> &CovMaps) { @@ -378,6 +684,11 @@ class CovMapFilenamesResolver { 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]; @@ -445,6 +756,59 @@ class CovMapFilenamesResolver { } }; +class DecoderImpl : public Decoder, CovMapFilenamesResolver { + std::unique_ptr<InstrProfSymtab> ProfileNames; + +public: + DecoderImpl(endianness Endianness, bool CovMapEnabled) + : Decoder(Endianness), ProfileNames(std::make_unique<InstrProfSymtab>()) { + enabled = CovMapEnabled; + } + + Error acquire(unsigned AddressAlign, StringRef Name, + ArrayRef<uint8_t> Content) override { + // Don't register anything. + if (!enabled) + return Error::success(); + + if (CovMapSection::nameMatches(Name)) { + // 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)) + return E; + moveAndCollectCovMap(std::move(TempCovMap->CovMaps)); + } + + return Error::success(); + } + + Error make(ELFYAML::CovMapSectionBase *Base, + ArrayRef<uint8_t> Content) 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); + 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); + return Error::success(); + } + + llvm_unreachable("Unknown Section"); + } +}; + class EncoderImpl : public Encoder, CovMapFilenamesResolver { public: EncoderImpl(endianness Endianness) : Encoder(Endianness) {} @@ -461,6 +825,11 @@ class EncoderImpl : public Encoder, CovMapFilenamesResolver { }; } // namespace +std::unique_ptr<Decoder> Decoder::get(endianness Endianness, + bool CovMapEnabled) { + return std::make_unique<DecoderImpl>(Endianness, CovMapEnabled); +} + std::unique_ptr<Encoder> Encoder::get(endianness Endianness) { return std::make_unique<EncoderImpl>(Endianness); } @@ -482,4 +851,4 @@ covmap::make_unique(StringRef Name) { return nullptr; } -LLVM_YAML_IS_SEQUENCE_VECTOR(PrfNamesSection::PrfNamesTy) +LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::InstrProfSymtab::PrfNamesTy) diff --git a/llvm/lib/ProfileData/InstrProf.cpp b/llvm/lib/ProfileData/InstrProf.cpp index 819ddd02a24ce..93714a5a05a0d 100644 --- a/llvm/lib/ProfileData/InstrProf.cpp +++ b/llvm/lib/ProfileData/InstrProf.cpp @@ -535,9 +535,9 @@ Error InstrProfSymtab::addVTableWithName(GlobalVariable &VTable, /// \c NameStrings is a string composed of one of more possibly encoded /// sub-strings. The substrings are separated by 0 or more zero bytes. This /// method decodes the string and calls `NameCallback` for each substring. -static Error -readAndDecodeStrings(StringRef NameStrings, - std::function<Error(StringRef)> NameCallback) { +static Error readAndDecodeStrings( + StringRef NameStrings, std::function<Error(StringRef)> NameCallback, + std::function<void(bool)> ChunkCallback = [](bool) {}) { const uint8_t *P = NameStrings.bytes_begin(); const uint8_t *EndP = NameStrings.bytes_end(); while (P < EndP) { @@ -567,6 +567,7 @@ readAndDecodeStrings(StringRef NameStrings, P += UncompressedSize; } // Now parse the name strings. + ChunkCallback(IsCompressed); SmallVector<StringRef, 0> Names; NameStrings.split(Names, getInstrProfNameSeparator()); for (StringRef &Name : Names) @@ -585,6 +586,22 @@ Error InstrProfSymtab::create(StringRef NameStrings) { std::bind(&InstrProfSymtab::addFuncName, this, std::placeholders::_1)); } +Expected<InstrProfSymtab::PrfNamesChunksTy> +InstrProfSymtab::createAndGetList(ArrayRef<uint8_t> Content) { + PrfNamesChunksTy Result; + PrfNamesTy *ArrayP = nullptr; + if (auto E = readAndDecodeStrings( + StringRef(reinterpret_cast<const char *>(Content.data()), + Content.size()), + [&](StringRef Name) { + ArrayP->emplace_back(Name.str()); + return addFuncName(Name); + }, + [&](bool IsCompressed) { ArrayP = &Result.emplace_back(); })) + return E; + return Result; +} + Error InstrProfSymtab::create(StringRef FuncNameStrings, StringRef VTableNameStrings) { if (Error E = readAndDecodeStrings(FuncNameStrings, diff --git a/llvm/test/tools/obj2yaml/ELF/covmap-be.yaml b/llvm/test/tools/obj2yaml/ELF/covmap-be.yaml index b97782153192b..8423f1ad5f765 100644 --- a/llvm/test/tools/obj2yaml/ELF/covmap-be.yaml +++ b/llvm/test/tools/obj2yaml/ELF/covmap-be.yaml @@ -1,6 +1,8 @@ # RUN: yaml2obj %s -o %t.o # RUN: obj2yaml %t.o > %t.plain.yaml +# RUN: obj2yaml --covmap-raw %t.o > %t.raw.yaml # RUN: yaml2obj %t.plain.yaml -o - | cmp %t.o - +# RUN: yaml2obj %t.raw.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 9ec8987c6f93d..db30d373d5be1 100644 --- a/llvm/test/tools/obj2yaml/ELF/covmap.yaml +++ b/llvm/test/tools/obj2yaml/ELF/covmap.yaml @@ -1,6 +1,8 @@ # 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: yaml2obj %t.plain.yaml -o - | cmp %t.o - +# RUN: yaml2obj %t.raw.yaml -o - | cmp %t.o - --- !ELF FileHeader: diff --git a/llvm/tools/obj2yaml/elf2yaml.cpp b/llvm/tools/obj2yaml/elf2yaml.cpp index b1c8032ea2192..50fd92e24aa3d 100644 --- a/llvm/tools/obj2yaml/elf2yaml.cpp +++ b/llvm/tools/obj2yaml/elf2yaml.cpp @@ -11,8 +11,10 @@ #include "llvm/ADT/Twine.h" #include "llvm/DebugInfo/DWARF/DWARFContext.h" #include "llvm/Object/ELFObjectFile.h" +#include "llvm/ObjectYAML/CovMap.h" #include "llvm/ObjectYAML/DWARFYAML.h" #include "llvm/ObjectYAML/ELFYAML.h" +#include "llvm/Support/CommandLine.h" #include "llvm/Support/DataExtractor.h" #include "llvm/Support/Errc.h" #include "llvm/Support/ErrorHandling.h" @@ -21,6 +23,10 @@ using namespace llvm; +static cl::opt<bool> CovMapRaw("covmap-raw", + cl::desc("Dump raw YAML in Coverage Map."), + cl::cat(Cat)); + namespace { template <class ELFT> @@ -97,6 +103,8 @@ class ELFDumper { dumpStackSizesSection(const Elf_Shdr *Shdr); Expected<ELFYAML::BBAddrMapSection *> dumpBBAddrMapSection(const Elf_Shdr *Shdr); + Expected<ELFYAML::Section *> dumpCovMap(const Elf_Shdr *Shdr, StringRef Name, + covmap::Decoder *CovMapDecoder); Expected<ELFYAML::RawContentSection *> dumpPlaceholderSection(const Elf_Shdr *Shdr); @@ -580,6 +588,30 @@ ELFDumper<ELFT>::dumpSections() { return Error::success(); }; + auto CovMapDecoder = covmap::Decoder::get(ELFT::Endianness, CovMapRaw); + if (covmap::Decoder::enabled) { + // Look up covmap-related sections in advance. + for (const auto &Sec : Sections) { + if (Sec.sh_type != ELF::SHT_PROGBITS) + continue; + + auto NameOrErr = Obj.getSectionName(Sec); + if (!NameOrErr) + return NameOrErr.takeError(); + + if (!covmap::nameMatches(*NameOrErr)) + continue; + + auto ContentOrErr = Obj.getSectionContents(Sec); + if (!ContentOrErr) + return ContentOrErr.takeError(); + + if (auto E = CovMapDecoder->acquire(Sec.sh_addralign, *NameOrErr, + *ContentOrErr)) + return std::move(E); + } + } + auto GetDumper = [this](unsigned Type) -> std::function<Expected<ELFYAML::Chunk *>(const Elf_Shdr *)> { if (Obj.getHeader().e_machine == ELF::EM_ARM && Type == ELF::SHT_ARM_EXIDX) @@ -661,6 +693,10 @@ ELFDumper<ELFT>::dumpSections() { if (Error E = Add(dumpStackSizesSection(&Sec))) return std::move(E); continue; + } else if (covmap::Decoder::enabled && covmap::nameMatches(*NameOrErr)) { + if (Error E = Add(dumpCovMap(&Sec, *NameOrErr, CovMapDecoder.get()))) + return std::move(E); + continue; } } @@ -1662,6 +1698,26 @@ ELFDumper<ELFT>::dumpMipsABIFlags(const Elf_Shdr *Shdr) { return S.release(); } +template <class ELFT> +Expected<ELFYAML::Section *> +ELFDumper<ELFT>::dumpCovMap(const Elf_Shdr *Shdr, StringRef Name, + covmap::Decoder *CovMapDecoder) { + auto S = covmap::make_unique(Name); + assert(S); + + 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)) + return std::move(E); + + return S.release(); +} + template <class ELFT> static Error elf2yaml(raw_ostream &Out, const object::ELFFile<ELFT> &Obj, std::unique_ptr<DWARFContext> DWARFCtx) { @@ -1671,7 +1727,8 @@ static Error elf2yaml(raw_ostream &Out, const object::ELFFile<ELFT> &Obj, return YAMLOrErr.takeError(); std::unique_ptr<ELFYAML::Object> YAML(YAMLOrErr.get()); - yaml::Output Yout(Out); + yaml::Output Yout(Out, nullptr, /*WrapColumn*/ + (covmap::Decoder::enabled ? 160 : 70)); Yout << *YAML; return Error::success(); diff --git a/llvm/tools/obj2yaml/obj2yaml.cpp b/llvm/tools/obj2yaml/obj2yaml.cpp index 63c8cc55ee2d4..31018161af531 100644 --- a/llvm/tools/obj2yaml/obj2yaml.cpp +++ b/llvm/tools/obj2yaml/obj2yaml.cpp @@ -20,7 +20,7 @@ using namespace llvm; using namespace llvm::object; -static cl::OptionCategory Cat("obj2yaml Options"); +cl::OptionCategory Cat("obj2yaml Options"); static cl::opt<std::string> InputFilename(cl::Positional, cl::desc("<input file>"), cl::init("-")); diff --git a/llvm/tools/obj2yaml/obj2yaml.h b/llvm/tools/obj2yaml/obj2yaml.h index 03d7db5317acd..ee34919962575 100644 --- a/llvm/tools/obj2yaml/obj2yaml.h +++ b/llvm/tools/obj2yaml/obj2yaml.h @@ -16,11 +16,15 @@ #include "llvm/Object/Minidump.h" #include "llvm/Object/Wasm.h" #include "llvm/Object/XCOFFObjectFile.h" +#include "llvm/Support/CommandLine.h" #include "llvm/Support/MemoryBufferRef.h" #include "llvm/Support/raw_ostream.h" #include <system_error> enum RawSegments : unsigned { none = 0, data = 1, linkedit = 1 << 1 }; + +extern llvm::cl::OptionCategory Cat; + std::error_code coff2yaml(llvm::raw_ostream &Out, const llvm::object::COFFObjectFile &Obj); llvm::Error elf2yaml(llvm::raw_ostream &Out, _______________________________________________ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits