IO.mapRequired("name", File.Name);
IO.mapOptional("lines", File.LineRanges);
}
- static StringRef validate(IO &io, FileFilter &File) {
+ static std::string validate(IO &io, FileFilter &File) {
if (File.Name.empty())
return "No file name specified";
for (const FileFilter::LineRange &Range : File.LineRanges) {
if (Range.first <= 0 || Range.second <= 0)
return "Invalid line range";
}
- return StringRef();
+ return "";
}
};
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
template <typename EntryType>
struct MappingTraits<DWARFYAML::ListEntries<EntryType>> {
static void mapping(IO &IO, DWARFYAML::ListEntries<EntryType> &ListEntries);
- static StringRef validate(IO &IO,
- DWARFYAML::ListEntries<EntryType> &ListEntries);
+ static std::string validate(IO &IO,
+ DWARFYAML::ListEntries<EntryType> &ListEntries);
};
template <> struct MappingTraits<DWARFYAML::RnglistEntry> {
static bool classof(const Chunk *S) { return S->Kind != ChunkKind::Fill; }
+ // Some derived sections might have their own special entries. This method
+ // returns a vector of <entry name, is used> pairs. It is used for section
+ // validation.
+ virtual std::vector<std::pair<StringRef, bool>> getEntries() const {
+ return {};
+ };
+
// The following members are used to override section fields which is
// useful for creating invalid objects.
StackSizesSection() : Section(ChunkKind::StackSizes) {}
+ std::vector<std::pair<StringRef, bool>> getEntries() const override {
+ return {{"Entries", Entries.hasValue()}};
+ };
+
static bool classof(const Chunk *S) {
return S->Kind == ChunkKind::StackSizes;
}
DynamicSection() : Section(ChunkKind::Dynamic) {}
+ std::vector<std::pair<StringRef, bool>> getEntries() const override {
+ return {{"Entries", Entries.hasValue()}};
+ };
+
static bool classof(const Chunk *S) { return S->Kind == ChunkKind::Dynamic; }
};
NoteSection() : Section(ChunkKind::Note) {}
+ std::vector<std::pair<StringRef, bool>> getEntries() const override {
+ return {{"Notes", Notes.hasValue()}};
+ };
+
static bool classof(const Chunk *S) { return S->Kind == ChunkKind::Note; }
};
Optional<std::vector<uint32_t>> Bucket;
Optional<std::vector<uint32_t>> Chain;
+ std::vector<std::pair<StringRef, bool>> getEntries() const override {
+ return {{"Bucket", Bucket.hasValue()}, {"Chain", Chain.hasValue()}};
+ };
+
// The following members are used to override section fields.
// This is useful for creating invalid objects.
Optional<llvm::yaml::Hex64> NBucket;
GnuHashSection() : Section(ChunkKind::GnuHash) {}
+ std::vector<std::pair<StringRef, bool>> getEntries() const override {
+ return {{"Header", Header.hasValue()},
+ {"BloomFilter", BloomFilter.hasValue()},
+ {"HashBuckets", HashBuckets.hasValue()},
+ {"HashValues", HashValues.hasValue()}};
+ };
+
static bool classof(const Chunk *S) { return S->Kind == ChunkKind::GnuHash; }
};
VerneedSection() : Section(ChunkKind::Verneed) {}
+ std::vector<std::pair<StringRef, bool>> getEntries() const override {
+ return {{"Dependencies", VerneedV.hasValue()}};
+ };
+
static bool classof(const Chunk *S) {
return S->Kind == ChunkKind::Verneed;
}
AddrsigSection() : Section(ChunkKind::Addrsig) {}
+ std::vector<std::pair<StringRef, bool>> getEntries() const override {
+ return {{"Symbols", Symbols.hasValue()}};
+ };
+
static bool classof(const Chunk *S) { return S->Kind == ChunkKind::Addrsig; }
};
LinkerOptionsSection() : Section(ChunkKind::LinkerOptions) {}
+ std::vector<std::pair<StringRef, bool>> getEntries() const override {
+ return {{"Options", Options.hasValue()}};
+ };
+
static bool classof(const Chunk *S) {
return S->Kind == ChunkKind::LinkerOptions;
}
DependentLibrariesSection() : Section(ChunkKind::DependentLibraries) {}
+ std::vector<std::pair<StringRef, bool>> getEntries() const override {
+ return {{"Libraries", Libs.hasValue()}};
+ };
+
static bool classof(const Chunk *S) {
return S->Kind == ChunkKind::DependentLibraries;
}
CallGraphProfileSection() : Section(ChunkKind::CallGraphProfile) {}
+ std::vector<std::pair<StringRef, bool>> getEntries() const override {
+ return {{"Entries", Entries.hasValue()}};
+ };
+
static bool classof(const Chunk *S) {
return S->Kind == ChunkKind::CallGraphProfile;
}
SymverSection() : Section(ChunkKind::Symver) {}
+ std::vector<std::pair<StringRef, bool>> getEntries() const override {
+ return {{"Entries", Entries.hasValue()}};
+ };
+
static bool classof(const Chunk *S) { return S->Kind == ChunkKind::Symver; }
};
VerdefSection() : Section(ChunkKind::Verdef) {}
+ std::vector<std::pair<StringRef, bool>> getEntries() const override {
+ return {{"Entries", Entries.hasValue()}};
+ };
+
static bool classof(const Chunk *S) { return S->Kind == ChunkKind::Verdef; }
};
GroupSection() : Section(ChunkKind::Group) {}
+ std::vector<std::pair<StringRef, bool>> getEntries() const override {
+ return {{"Members", Members.hasValue()}};
+ };
+
static bool classof(const Chunk *S) { return S->Kind == ChunkKind::Group; }
};
RelocationSection() : Section(ChunkKind::Relocation) {}
+ std::vector<std::pair<StringRef, bool>> getEntries() const override {
+ return {{"Relocations", Relocations.hasValue()}};
+ };
+
static bool classof(const Chunk *S) {
return S->Kind == ChunkKind::Relocation;
}
RelrSection() : Section(ChunkKind::Relr) {}
+ std::vector<std::pair<StringRef, bool>> getEntries() const override {
+ return {{"Entries", Entries.hasValue()}};
+ };
+
static bool classof(const Chunk *S) {
return S->Kind == ChunkKind::Relr;
}
SymtabShndxSection() : Section(ChunkKind::SymtabShndxSection) {}
+ std::vector<std::pair<StringRef, bool>> getEntries() const override {
+ return {{"Entries", Entries.hasValue()}};
+ };
+
static bool classof(const Chunk *S) {
return S->Kind == ChunkKind::SymtabShndxSection;
}
ARMIndexTableSection() : Section(ChunkKind::ARMIndexTable) {}
+ std::vector<std::pair<StringRef, bool>> getEntries() const override {
+ return {{"Entries", Entries.hasValue()}};
+ };
+
static bool classof(const Chunk *S) {
return S->Kind == ChunkKind::ARMIndexTable;
}
template <> struct MappingTraits<ELFYAML::SectionHeaderTable> {
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<ELFYAML::SectionHeader> {
template <>
struct MappingTraits<ELFYAML::Symbol> {
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<ELFYAML::StackSizeEntry> {
template <> struct MappingTraits<std::unique_ptr<ELFYAML::Chunk>> {
static void mapping(IO &IO, std::unique_ptr<ELFYAML::Chunk> &C);
- static StringRef validate(IO &io, std::unique_ptr<ELFYAML::Chunk> &C);
+ static std::string validate(IO &io, std::unique_ptr<ELFYAML::Chunk> &C);
};
template <>
template <> struct MappingTraits<MachOYAML::Section> {
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<MachOYAML::NListEntry> {
template <> struct MappingTraits<std::unique_ptr<MinidumpYAML::Stream>> {
static void mapping(IO &IO, std::unique_ptr<MinidumpYAML::Stream> &S);
- static StringRef validate(IO &IO, std::unique_ptr<MinidumpYAML::Stream> &S);
+ static std::string validate(IO &IO, std::unique_ptr<MinidumpYAML::Stream> &S);
};
template <> struct MappingContextTraits<minidump::MemoryDescriptor, BinaryRef> {
// 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 }):
// 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 }):
// Test if MappingContextTraits<T>::validate() is defined on type T.
template <class T, class Context> struct has_MappingValidateTraits {
- using Signature_validate = StringRef (*)(class IO &, T &, Context &);
+ using Signature_validate = std::string (*)(class IO &, T &, Context &);
template <typename U>
static char test(SameType<Signature_validate, &U::validate>*);
// Test if MappingTraits<T>::validate() is defined on type T.
template <class T> struct has_MappingValidateTraits<T, EmptyContext> {
- using Signature_validate = StringRef (*)(class IO &, T &);
+ using Signature_validate = std::string (*)(class IO &, T &);
template <typename U>
static char test(SameType<Signature_validate, &U::validate> *);
else
io.beginMapping();
if (io.outputting()) {
- StringRef Err = MappingTraits<T>::validate(io, Val);
+ std::string Err = MappingTraits<T>::validate(io, Val);
if (!Err.empty()) {
errs() << Err << "\n";
assert(Err.empty() && "invalid struct trying to be written as yaml");
}
detail::doMapping(io, Val, Ctx);
if (!io.outputting()) {
- StringRef Err = MappingTraits<T>::validate(io, Val);
+ std::string Err = MappingTraits<T>::validate(io, Val);
if (!Err.empty())
io.setError(Err);
}
}
template <typename EntryType>
-StringRef MappingTraits<DWARFYAML::ListEntries<EntryType>>::validate(
+std::string MappingTraits<DWARFYAML::ListEntries<EntryType>>::validate(
IO &IO, DWARFYAML::ListEntries<EntryType> &ListEntries) {
if (ListEntries.Entries && ListEntries.Content)
return "Entries and Content can't be used together";
- return StringRef();
+ return "";
}
template <typename EntryType>
IO.mapOptional("NoHeaders", SectionHeader.NoHeaders);
}
-StringRef MappingTraits<ELFYAML::SectionHeaderTable>::validate(
+std::string MappingTraits<ELFYAML::SectionHeaderTable>::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<ELFYAML::FileHeader>::mapping(IO &IO,
IO.mapOptional("Other", Keys->Other);
}
-StringRef MappingTraits<ELFYAML::Symbol>::validate(IO &IO,
- ELFYAML::Symbol &Symbol) {
+std::string MappingTraits<ELFYAML::Symbol>::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) {
}
}
-StringRef MappingTraits<std::unique_ptr<ELFYAML::Chunk>>::validate(
+std::string MappingTraits<std::unique_ptr<ELFYAML::Chunk>>::validate(
IO &io, std::unique_ptr<ELFYAML::Chunk> &C) {
if (const auto *F = dyn_cast<ELFYAML::Fill>(C.get())) {
if (F->Pattern && F->Pattern->binary_size() != 0 && !F->Size)
return "\"Size\" can't be 0 when \"Pattern\" is not empty";
- return {};
+ return "";
}
const ELFYAML::Section &Sec = *cast<ELFYAML::Section>(C.get());
(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<ELFYAML::RawContentSection>(C.get())) {
- if (RawSection->Flags && RawSection->ShFlags)
- return "ShFlags and Flags cannot be used together";
- return {};
- }
-
- if (const auto *SS = dyn_cast<ELFYAML::StackSizesSection>(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<ELFYAML::HashSection>(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<ELFYAML::AddrsigSection>(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<ELFYAML::NoteSection>(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<ELFYAML::GnuHashSection>(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<ELFYAML::LinkerOptionsSection>(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<ELFYAML::DependentLibrariesSection>(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<ELFYAML::VerdefSection>(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<ELFYAML::VerneedSection>(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<ELFYAML::SymverSection>(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<ELFYAML::RelrSection>(C.get())) {
- if ((RS->Content || RS->Size) && RS->Entries)
- return "\"Entries\" cannot be used with \"Content\" or \"Size\"";
- return {};
- }
+ auto BuildErrPrefix = [](ArrayRef<std::pair<StringRef, bool>> EntV) {
+ std::string Msg;
+ for (size_t I = 0, E = EntV.size(); I != E; ++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 *CGP = dyn_cast<ELFYAML::CallGraphProfileSection>(C.get())) {
- if ((CGP->Content || CGP->Size) && CGP->Entries)
- return "\"Entries\" cannot be used with \"Content\" or \"Size\"";
- return {};
- }
+ std::vector<std::pair<StringRef, bool>> Entries = Sec.getEntries();
+ const size_t NumUsedEntries = llvm::count_if(
+ Entries, [](const std::pair<StringRef, bool> &P) { return P.second; });
- if (const auto *IT = dyn_cast<ELFYAML::ARMIndexTableSection>(C.get())) {
- if ((IT->Content || IT->Size) && IT->Entries)
- return "\"Entries\" 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 *RS = dyn_cast<ELFYAML::RelocationSection>(C.get())) {
- if ((RS->Content || RS->Size) && RS->Relocations)
- return "\"Relocations\" cannot be used with \"Content\" or \"Size\"";
- return {};
- }
+ if (NumUsedEntries > 0 && Entries.size() != NumUsedEntries)
+ return BuildErrPrefix(Entries) + " must be used together";
- if (const auto *SS = dyn_cast<ELFYAML::SymtabShndxSection>(C.get())) {
- if ((SS->Content || SS->Size) && SS->Entries)
- return "\"Entries\" cannot be used with \"Content\" or \"Size\"";
- return {};
- }
-
- if (const auto *GS = dyn_cast<ELFYAML::GroupSection>(C.get())) {
- if ((GS->Content || GS->Size) && GS->Members)
- return "\"Members\" cannot be used with \"Content\" or \"Size\"";
- return {};
+ if (const auto *RawSection = dyn_cast<ELFYAML::RawContentSection>(C.get())) {
+ if (RawSection->Flags && RawSection->ShFlags)
+ return "ShFlags and Flags cannot be used together";
+ return "";
}
if (const auto *NB = dyn_cast<ELFYAML::NoBitsSection>(C.get())) {
if (NB->Content)
return "SHT_NOBITS section cannot have \"Content\"";
- return {};
- }
-
- if (const auto *DS = dyn_cast<ELFYAML::DynamicSection>(C.get())) {
- if ((DS->Content || DS->Size) && DS->Entries)
- return "\"Entries\" cannot be used with \"Content\" or \"Size\"";
- return {};
+ return "";
}
if (const auto *MF = dyn_cast<ELFYAML::MipsABIFlags>(C.get())) {
"sections";
if (MF->Size)
return "\"Size\" key is not implemented for SHT_MIPS_ABIFLAGS sections";
- return {};
+ return "";
}
- return {};
+ return "";
}
namespace {
IO.mapOptional("relocations", Section.relocations);
}
-StringRef
+std::string
MappingTraits<MachOYAML::Section>::validate(IO &IO,
MachOYAML::Section &Section) {
if (Section.content && Section.size < Section.content->binary_size())
return "Section size must be greater than or equal to the content size";
- return {};
+ return "";
}
void MappingTraits<MachO::build_tool_version>::mapping(
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 "";
}
}
-StringRef yaml::MappingTraits<std::unique_ptr<Stream>>::validate(
+std::string yaml::MappingTraits<std::unique_ptr<Stream>>::validate(
yaml::IO &IO, std::unique_ptr<MinidumpYAML::Stream> &S) {
switch (S->Kind) {
case MinidumpYAML::Stream::StreamKind::RawContent:
# 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:
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 {};
}
};
}