diff --git a/lld/lib/ReaderWriter/MachO/MachONormalizedFileYAML.cpp b/lld/lib/ReaderWriter/MachO/MachONormalizedFileYAML.cpp --- a/lld/lib/ReaderWriter/MachO/MachONormalizedFileYAML.cpp +++ b/lld/lib/ReaderWriter/MachO/MachONormalizedFileYAML.cpp @@ -740,9 +740,7 @@ io.mapOptional("exports", file.exportInfo); io.mapOptional("dataInCode", file.dataInCode); } - static StringRef validate(IO &io, NormalizedFile &file) { - return StringRef(); - } + static std::string validate(IO &io, NormalizedFile &file) { return {}; } }; } // namespace llvm diff --git a/llvm/include/llvm/ObjectYAML/DWARFYAML.h b/llvm/include/llvm/ObjectYAML/DWARFYAML.h --- a/llvm/include/llvm/ObjectYAML/DWARFYAML.h +++ b/llvm/include/llvm/ObjectYAML/DWARFYAML.h @@ -359,8 +359,8 @@ template struct MappingTraits> { static void mapping(IO &IO, DWARFYAML::ListEntries &ListEntries); - static StringRef validate(IO &IO, - DWARFYAML::ListEntries &ListEntries); + static std::string validate(IO &IO, + DWARFYAML::ListEntries &ListEntries); }; template <> struct MappingTraits { diff --git a/llvm/include/llvm/ObjectYAML/ELFYAML.h b/llvm/include/llvm/ObjectYAML/ELFYAML.h --- a/llvm/include/llvm/ObjectYAML/ELFYAML.h +++ b/llvm/include/llvm/ObjectYAML/ELFYAML.h @@ -193,6 +193,12 @@ static bool classof(const Chunk *S) { return S->Kind != ChunkKind::Fill; } + // Some derived sections might have own special entries. This method returns + // vector of pairs. It is used for sections validation. + virtual std::vector> getEntries() const { + return {}; + }; + // The following members are used to override section fields which is // useful for creating invalid objects. @@ -235,6 +241,10 @@ StackSizesSection() : Section(ChunkKind::StackSizes) {} + std::vector> getEntries() const override { + return {{"Entries", !!Entries}}; + }; + static bool classof(const Chunk *S) { return S->Kind == ChunkKind::StackSizes; } @@ -249,6 +259,10 @@ DynamicSection() : Section(ChunkKind::Dynamic) {} + std::vector> getEntries() const override { + return {{"Entries", !!Entries}}; + }; + static bool classof(const Chunk *S) { return S->Kind == ChunkKind::Dynamic; } }; @@ -276,6 +290,10 @@ NoteSection() : Section(ChunkKind::Note) {} + std::vector> getEntries() const override { + return {{"Notes", !!Notes}}; + }; + static bool classof(const Chunk *S) { return S->Kind == ChunkKind::Note; } }; @@ -283,6 +301,10 @@ Optional> Bucket; Optional> Chain; + std::vector> getEntries() const override { + return {{"Bucket", !!Bucket}, {"Chain", !!Chain}}; + }; + // The following members are used to override section fields. // This is useful for creating invalid objects. Optional NBucket; @@ -321,6 +343,13 @@ GnuHashSection() : Section(ChunkKind::GnuHash) {} + std::vector> getEntries() const override { + return {{"Header", !!Header}, + {"BloomFilter", !!BloomFilter}, + {"HashBuckets", !!HashBuckets}, + {"HashValues", !!HashValues}}; + }; + static bool classof(const Chunk *S) { return S->Kind == ChunkKind::GnuHash; } }; @@ -343,6 +372,10 @@ VerneedSection() : Section(ChunkKind::Verneed) {} + std::vector> getEntries() const override { + return {{"Dependencies", !!VerneedV}}; + }; + static bool classof(const Chunk *S) { return S->Kind == ChunkKind::Verneed; } @@ -353,6 +386,10 @@ AddrsigSection() : Section(ChunkKind::Addrsig) {} + std::vector> getEntries() const override { + return {{"Symbols", !!Symbols}}; + }; + static bool classof(const Chunk *S) { return S->Kind == ChunkKind::Addrsig; } }; @@ -366,6 +403,10 @@ LinkerOptionsSection() : Section(ChunkKind::LinkerOptions) {} + std::vector> getEntries() const override { + return {{"Options", !!Options}}; + }; + static bool classof(const Chunk *S) { return S->Kind == ChunkKind::LinkerOptions; } @@ -376,6 +417,10 @@ DependentLibrariesSection() : Section(ChunkKind::DependentLibraries) {} + std::vector> getEntries() const override { + return {{"Libraries", !!Libs}}; + }; + static bool classof(const Chunk *S) { return S->Kind == ChunkKind::DependentLibraries; } @@ -396,6 +441,10 @@ CallGraphProfileSection() : Section(ChunkKind::CallGraphProfile) {} + std::vector> getEntries() const override { + return {{"Entries", !!Entries}}; + }; + static bool classof(const Chunk *S) { return S->Kind == ChunkKind::CallGraphProfile; } @@ -406,6 +455,10 @@ SymverSection() : Section(ChunkKind::Symver) {} + std::vector> getEntries() const override { + return {{"Entries", !!Entries}}; + }; + static bool classof(const Chunk *S) { return S->Kind == ChunkKind::Symver; } }; @@ -424,6 +477,10 @@ VerdefSection() : Section(ChunkKind::Verdef) {} + std::vector> getEntries() const override { + return {{"Entries", !!Entries}}; + }; + static bool classof(const Chunk *S) { return S->Kind == ChunkKind::Verdef; } }; @@ -435,6 +492,10 @@ GroupSection() : Section(ChunkKind::Group) {} + std::vector> getEntries() const override { + return {{"Members", !!Members}}; + }; + static bool classof(const Chunk *S) { return S->Kind == ChunkKind::Group; } }; @@ -451,6 +512,10 @@ RelocationSection() : Section(ChunkKind::Relocation) {} + std::vector> getEntries() const override { + return {{"Relocations", !!Relocations}}; + }; + static bool classof(const Chunk *S) { return S->Kind == ChunkKind::Relocation; } @@ -461,6 +526,10 @@ RelrSection() : Section(ChunkKind::Relr) {} + std::vector> getEntries() const override { + return {{"Entries", !!Entries}}; + }; + static bool classof(const Chunk *S) { return S->Kind == ChunkKind::Relr; } @@ -471,6 +540,10 @@ SymtabShndxSection() : Section(ChunkKind::SymtabShndxSection) {} + std::vector> getEntries() const override { + return {{"Entries", !!Entries}}; + }; + static bool classof(const Chunk *S) { return S->Kind == ChunkKind::SymtabShndxSection; } @@ -486,6 +559,10 @@ ARMIndexTableSection() : Section(ChunkKind::ARMIndexTable) {} + std::vector> getEntries() const override { + return {{"Entries", !!Entries}}; + }; + static bool classof(const Chunk *S) { return S->Kind == ChunkKind::ARMIndexTable; } @@ -699,7 +776,7 @@ template <> struct MappingTraits { static void mapping(IO &IO, ELFYAML::SectionHeaderTable &SecHdrTable); - static StringRef validate(IO &IO, ELFYAML::SectionHeaderTable &SecHdrTable); + static std::string validate(IO &IO, ELFYAML::SectionHeaderTable &SecHdrTable); }; template <> struct MappingTraits { @@ -713,7 +790,7 @@ template <> struct MappingTraits { static void mapping(IO &IO, ELFYAML::Symbol &Symbol); - static StringRef validate(IO &IO, ELFYAML::Symbol &Symbol); + static std::string validate(IO &IO, ELFYAML::Symbol &Symbol); }; template <> struct MappingTraits { @@ -762,7 +839,7 @@ template <> struct MappingTraits> { static void mapping(IO &IO, std::unique_ptr &C); - static StringRef validate(IO &io, std::unique_ptr &C); + static std::string validate(IO &io, std::unique_ptr &C); }; template <> diff --git a/llvm/include/llvm/ObjectYAML/MachOYAML.h b/llvm/include/llvm/ObjectYAML/MachOYAML.h --- a/llvm/include/llvm/ObjectYAML/MachOYAML.h +++ b/llvm/include/llvm/ObjectYAML/MachOYAML.h @@ -220,7 +220,7 @@ template <> struct MappingTraits { static void mapping(IO &IO, MachOYAML::Section &Section); - static StringRef validate(IO &io, MachOYAML::Section &Section); + static std::string validate(IO &io, MachOYAML::Section &Section); }; template <> struct MappingTraits { diff --git a/llvm/include/llvm/ObjectYAML/MinidumpYAML.h b/llvm/include/llvm/ObjectYAML/MinidumpYAML.h --- a/llvm/include/llvm/ObjectYAML/MinidumpYAML.h +++ b/llvm/include/llvm/ObjectYAML/MinidumpYAML.h @@ -236,7 +236,7 @@ template <> struct MappingTraits> { static void mapping(IO &IO, std::unique_ptr &S); - static StringRef validate(IO &IO, std::unique_ptr &S); + static std::string validate(IO &IO, std::unique_ptr &S); }; template <> struct MappingContextTraits { diff --git a/llvm/include/llvm/Support/YAMLTraits.h b/llvm/include/llvm/Support/YAMLTraits.h --- a/llvm/include/llvm/Support/YAMLTraits.h +++ b/llvm/include/llvm/Support/YAMLTraits.h @@ -61,7 +61,7 @@ // Must provide: // static void mapping(IO &io, T &fields); // Optionally may provide: - // static StringRef validate(IO &io, T &fields); + // static std::string validate(IO &io, T &fields); // // The optional flow flag will cause generated YAML to use a flow mapping // (e.g. { a: 0, b: 1 }): @@ -83,7 +83,7 @@ // Must provide: // static void mapping(IO &io, T &fields, Context &Ctx); // Optionally may provide: - // static StringRef validate(IO &io, T &fields, Context &Ctx); + // static std::string validate(IO &io, T &fields, Context &Ctx); // // The optional flow flag will cause generated YAML to use a flow mapping // (e.g. { a: 0, b: 1 }): @@ -421,7 +421,7 @@ // Test if MappingContextTraits::validate() is defined on type T. template struct has_MappingValidateTraits { - using Signature_validate = StringRef (*)(class IO &, T &, Context &); + using Signature_validate = std::string (*)(class IO &, T &, Context &); template static char test(SameType*); @@ -435,7 +435,7 @@ // Test if MappingTraits::validate() is defined on type T. template struct has_MappingValidateTraits { - using Signature_validate = StringRef (*)(class IO &, T &); + using Signature_validate = std::string (*)(class IO &, T &); template static char test(SameType *); @@ -1041,7 +1041,7 @@ else io.beginMapping(); if (io.outputting()) { - StringRef Err = MappingTraits::validate(io, Val); + std::string Err = MappingTraits::validate(io, Val); if (!Err.empty()) { errs() << Err << "\n"; assert(Err.empty() && "invalid struct trying to be written as yaml"); @@ -1049,7 +1049,7 @@ } detail::doMapping(io, Val, Ctx); if (!io.outputting()) { - StringRef Err = MappingTraits::validate(io, Val); + std::string Err = MappingTraits::validate(io, Val); if (!Err.empty()) io.setError(Err); } diff --git a/llvm/lib/ObjectYAML/DWARFYAML.cpp b/llvm/lib/ObjectYAML/DWARFYAML.cpp --- a/llvm/lib/ObjectYAML/DWARFYAML.cpp +++ b/llvm/lib/ObjectYAML/DWARFYAML.cpp @@ -304,11 +304,11 @@ } template -StringRef MappingTraits>::validate( +std::string MappingTraits>::validate( IO &IO, DWARFYAML::ListEntries &ListEntries) { if (ListEntries.Entries && ListEntries.Content) return "Entries and Content can't be used together"; - return StringRef(); + return ""; } template diff --git a/llvm/lib/ObjectYAML/ELFYAML.cpp b/llvm/lib/ObjectYAML/ELFYAML.cpp --- a/llvm/lib/ObjectYAML/ELFYAML.cpp +++ b/llvm/lib/ObjectYAML/ELFYAML.cpp @@ -864,14 +864,14 @@ IO.mapOptional("NoHeaders", SectionHeader.NoHeaders); } -StringRef MappingTraits::validate( +std::string MappingTraits::validate( IO &IO, ELFYAML::SectionHeaderTable &SecHdrTable) { if (SecHdrTable.NoHeaders && (SecHdrTable.Sections || SecHdrTable.Excluded)) return "NoHeaders can't be used together with Sections/Excluded"; if (!SecHdrTable.NoHeaders && !SecHdrTable.Sections && !SecHdrTable.Excluded) return "SectionHeaderTable can't be empty. Use 'NoHeaders' key to drop the " "section header table"; - return StringRef(); + return {}; } void MappingTraits::mapping(IO &IO, @@ -1089,11 +1089,11 @@ IO.mapOptional("Other", Keys->Other); } -StringRef MappingTraits::validate(IO &IO, - ELFYAML::Symbol &Symbol) { +std::string MappingTraits::validate(IO &IO, + ELFYAML::Symbol &Symbol) { if (Symbol.Index && Symbol.Section.data()) return "Index and Section cannot both be specified for Symbol"; - return StringRef(); + return {}; } static void commonSectionMapping(IO &IO, ELFYAML::Section &Section) { @@ -1422,7 +1422,7 @@ } } -StringRef MappingTraits>::validate( +std::string MappingTraits>::validate( IO &io, std::unique_ptr &C) { if (const auto *F = dyn_cast(C.get())) { if (F->Pattern && F->Pattern->binary_size() != 0 && !F->Size) @@ -1435,117 +1435,36 @@ (uint64_t)(*Sec.Size) < Sec.Content->binary_size()) return "Section size must be greater than or equal to the content size"; - if (const auto *RawSection = dyn_cast(C.get())) { - if (RawSection->Flags && RawSection->ShFlags) - return "ShFlags and Flags cannot be used together"; - return {}; - } - - if (const auto *SS = dyn_cast(C.get())) { - if ((SS->Content || SS->Size) && SS->Entries) - return "\"Entries\" cannot be used with \"Content\" or \"Size\""; - return {}; - } - - if (const auto *HS = dyn_cast(C.get())) { - if ((HS->Content || HS->Size) && (HS->Bucket || HS->Chain)) - return "\"Bucket\" and \"Chain\" cannot be used with \"Content\" or " - "\"Size\""; - if ((HS->Bucket && !HS->Chain) || (!HS->Bucket && HS->Chain)) - return "\"Bucket\" and \"Chain\" must be used together"; - return {}; - } - - if (const auto *Sec = dyn_cast(C.get())) { - if ((Sec->Content || Sec->Size) && Sec->Symbols) - return "\"Symbols\" cannot be used with \"Content\" or \"Size\""; - return {}; - } - - if (const auto *NS = dyn_cast(C.get())) { - if ((NS->Content || NS->Size) && NS->Notes) - return "\"Notes\" cannot be used with \"Content\" or \"Size\""; - return {}; - } - - if (const auto *Sec = dyn_cast(C.get())) { - const bool HasSpecialFields = - Sec->Header || Sec->BloomFilter || Sec->HashBuckets || Sec->HashValues; - if (HasSpecialFields && (Sec->Content || Sec->Size)) - return "\"Header\", \"BloomFilter\", " - "\"HashBuckets\" and \"HashValues\" can't be used together with " - "\"Content\" or \"Size\""; - - if (HasSpecialFields && (!Sec->Header || !Sec->BloomFilter || - !Sec->HashBuckets || !Sec->HashValues)) - return "\"Header\", \"BloomFilter\", " - "\"HashBuckets\" and \"HashValues\" must be used together"; - return {}; - } - - if (const auto *Sec = dyn_cast(C.get())) { - if ((Sec->Content || Sec->Size) && Sec->Options) - return "\"Options\" cannot be used with \"Content\" or \"Size\""; - return {}; - } - - if (const auto *Sec = dyn_cast(C.get())) { - if ((Sec->Content || Sec->Size) && Sec->Libs) - return "\"Libraries\" cannot be used with \"Content\" or \"Size\""; - return {}; - } - - if (const auto *VD = dyn_cast(C.get())) { - if ((VD->Content || VD->Size) && VD->Entries) - return "\"Entries\" cannot be used with \"Content\" or \"Size\""; - return {}; - } - - if (const auto *VN = dyn_cast(C.get())) { - if ((VN->Content || VN->Size) && VN->VerneedV) - return "\"Dependencies\" cannot be used with \"Content\" or \"Size\""; - return {}; - } - - if (const auto *SV = dyn_cast(C.get())) { - if ((SV->Content || SV->Size) && SV->Entries) - return "\"Entries\" cannot be used with \"Content\" or \"Size\""; - return {}; - } - - if (const auto *RS = dyn_cast(C.get())) { - if ((RS->Content || RS->Size) && RS->Entries) - return "\"Entries\" cannot be used with \"Content\" or \"Size\""; - return {}; - } - - if (const auto *CGP = dyn_cast(C.get())) { - if ((CGP->Content || CGP->Size) && CGP->Entries) - return "\"Entries\" cannot be used with \"Content\" or \"Size\""; - return {}; - } + auto BuildErrPrefix = [](ArrayRef> EntV) { + std::string Msg; + for (size_t I = 0; I < EntV.size(); ++I) { + StringRef Name = EntV[I].first; + if (I == 0) { + Msg = "\"" + Name.str() + "\""; + continue; + } + if (I != EntV.size() - 1) + Msg += ", \"" + Name.str() + "\""; + else + Msg += " and \"" + Name.str() + "\""; + } + return Msg; + }; - if (const auto *IT = dyn_cast(C.get())) { - if ((IT->Content || IT->Size) && IT->Entries) - return "\"Entries\" cannot be used with \"Content\" or \"Size\""; - return {}; - } + std::vector> Entries = Sec.getEntries(); + const size_t NumUsedEntries = llvm::count_if( + Entries, [](const std::pair &P) { return P.second; }); - if (const auto *RS = dyn_cast(C.get())) { - if ((RS->Content || RS->Size) && RS->Relocations) - return "\"Relocations\" cannot be used with \"Content\" or \"Size\""; - return {}; - } + if ((Sec.Size || Sec.Content) && NumUsedEntries > 0) + return BuildErrPrefix(Entries) + + " cannot be used with \"Content\" or \"Size\""; - if (const auto *SS = dyn_cast(C.get())) { - if ((SS->Content || SS->Size) && SS->Entries) - return "\"Entries\" cannot be used with \"Content\" or \"Size\""; - return {}; - } + if (NumUsedEntries > 0 && Entries.size() != NumUsedEntries) + return BuildErrPrefix(Entries) + " must be used together"; - if (const auto *GS = dyn_cast(C.get())) { - if ((GS->Content || GS->Size) && GS->Members) - return "\"Members\" cannot be used with \"Content\" or \"Size\""; + if (const auto *RawSection = dyn_cast(C.get())) { + if (RawSection->Flags && RawSection->ShFlags) + return "ShFlags and Flags cannot be used together"; return {}; } @@ -1555,12 +1474,6 @@ return {}; } - if (const auto *DS = dyn_cast(C.get())) { - if ((DS->Content || DS->Size) && DS->Entries) - return "\"Entries\" cannot be used with \"Content\" or \"Size\""; - return {}; - } - if (const auto *MF = dyn_cast(C.get())) { if (MF->Content) return "\"Content\" key is not implemented for SHT_MIPS_ABIFLAGS " diff --git a/llvm/lib/ObjectYAML/MachOYAML.cpp b/llvm/lib/ObjectYAML/MachOYAML.cpp --- a/llvm/lib/ObjectYAML/MachOYAML.cpp +++ b/llvm/lib/ObjectYAML/MachOYAML.cpp @@ -305,7 +305,7 @@ IO.mapOptional("relocations", Section.relocations); } -StringRef +std::string MappingTraits::validate(IO &IO, MachOYAML::Section &Section) { if (Section.content && Section.size < Section.content->binary_size()) diff --git a/llvm/lib/ObjectYAML/MinidumpYAML.cpp b/llvm/lib/ObjectYAML/MinidumpYAML.cpp --- a/llvm/lib/ObjectYAML/MinidumpYAML.cpp +++ b/llvm/lib/ObjectYAML/MinidumpYAML.cpp @@ -292,7 +292,7 @@ IO.mapOptional("Size", Stream.Size, Stream.Content.binary_size()); } -static StringRef streamValidate(RawContentStream &Stream) { +static std::string streamValidate(RawContentStream &Stream) { if (Stream.Size.value < Stream.Content.binary_size()) return "Stream size must be greater or equal to the content size"; return ""; @@ -434,7 +434,7 @@ } } -StringRef yaml::MappingTraits>::validate( +std::string yaml::MappingTraits>::validate( yaml::IO &IO, std::unique_ptr &S) { switch (S->Kind) { case MinidumpYAML::Stream::StreamKind::RawContent: diff --git a/llvm/test/tools/yaml2obj/ELF/gnu-hash-section.yaml b/llvm/test/tools/yaml2obj/ELF/gnu-hash-section.yaml --- a/llvm/test/tools/yaml2obj/ELF/gnu-hash-section.yaml +++ b/llvm/test/tools/yaml2obj/ELF/gnu-hash-section.yaml @@ -231,7 +231,7 @@ # RUN: not yaml2obj --docnum=11 -DCONTENT="" %s 2>&1 | FileCheck %s --check-prefix=TOGETHER # RUN: not yaml2obj --docnum=11 -DSIZE=0 %s 2>&1 | FileCheck %s --check-prefix=TOGETHER -# TOGETHER: error: "Header", "BloomFilter", "HashBuckets" and "HashValues" can't be used together with "Content" or "Size" +# TOGETHER: error: "Header", "BloomFilter", "HashBuckets" and "HashValues" cannot be used with "Content" or "Size" --- !ELF FileHeader: diff --git a/llvm/unittests/Support/YAMLIOTest.cpp b/llvm/unittests/Support/YAMLIOTest.cpp --- a/llvm/unittests/Support/YAMLIOTest.cpp +++ b/llvm/unittests/Support/YAMLIOTest.cpp @@ -1782,10 +1782,10 @@ static void mapping(IO &io, MyValidation &d) { io.mapRequired("value", d.value); } - static StringRef validate(IO &io, MyValidation &d) { + static std::string validate(IO &io, MyValidation &d) { if (d.value < 0) return "negative value"; - return StringRef(); + return {}; } }; }