diff --git a/llvm/include/llvm/ObjectYAML/ELFYAML.h b/llvm/include/llvm/ObjectYAML/ELFYAML.h index 26ab09806dadf4..927afc2287a7f9 100644 --- a/llvm/include/llvm/ObjectYAML/ELFYAML.h +++ b/llvm/include/llvm/ObjectYAML/ELFYAML.h @@ -130,8 +130,8 @@ struct NoteEntry { llvm::yaml::Hex32 Type; }; -struct Section { - enum class SectionKind { +struct Chunk { + enum class ChunkKind { Dynamic, Group, RawContent, @@ -146,10 +146,18 @@ struct Section { SymtabShndxSection, Symver, MipsABIFlags, - Addrsig + Addrsig, + Fill }; - SectionKind Kind; + + ChunkKind Kind; StringRef Name; + + Chunk(ChunkKind K) : Kind(K) {} + virtual ~Chunk(); +}; + +struct Section : public Chunk { ELF_SHT Type; Optional Flags; llvm::yaml::Hex64 Address; @@ -161,9 +169,10 @@ struct Section { // When they are, this flag is used to signal about that. bool IsImplicit; - Section(SectionKind Kind, bool IsImplicit = false) - : Kind(Kind), IsImplicit(IsImplicit) {} - virtual ~Section(); + Section(ChunkKind Kind, bool IsImplicit = false) + : Chunk(Kind), IsImplicit(IsImplicit) {} + + static bool classof(const Chunk *S) { return S->Kind != ChunkKind::Fill; } // The following members are used to override section fields which is // useful for creating invalid objects. @@ -181,15 +190,32 @@ struct Section { Optional ShSize; }; +// Fill is a block of data which is placed outside of sections. It is +// not present in the sections header table, but it might affect the output file +// size and program headers produced. +struct Fill : Chunk { + Optional Pattern; + llvm::yaml::Hex64 Size; + + // We have to remember the offset of the fill, because it does not have + // a corresponding section header, unlike a section. We might need this + // information when writing the output. + uint64_t ShOffset; + + Fill() : Chunk(ChunkKind::Fill) {} + + static bool classof(const Chunk *S) { return S->Kind == ChunkKind::Fill; } +}; + struct StackSizesSection : Section { Optional Content; Optional Size; Optional> Entries; - StackSizesSection() : Section(SectionKind::StackSizes) {} + StackSizesSection() : Section(ChunkKind::StackSizes) {} - static bool classof(const Section *S) { - return S->Kind == SectionKind::StackSizes; + static bool classof(const Chunk *S) { + return S->Kind == ChunkKind::StackSizes; } static bool nameMatches(StringRef Name) { @@ -201,11 +227,9 @@ struct DynamicSection : Section { std::vector Entries; Optional Content; - DynamicSection() : Section(SectionKind::Dynamic) {} + DynamicSection() : Section(ChunkKind::Dynamic) {} - static bool classof(const Section *S) { - return S->Kind == SectionKind::Dynamic; - } + static bool classof(const Chunk *S) { return S->Kind == ChunkKind::Dynamic; } }; struct RawContentSection : Section { @@ -213,21 +237,19 @@ struct RawContentSection : Section { Optional Size; Optional Info; - RawContentSection() : Section(SectionKind::RawContent) {} + RawContentSection() : Section(ChunkKind::RawContent) {} - static bool classof(const Section *S) { - return S->Kind == SectionKind::RawContent; + static bool classof(const Chunk *S) { + return S->Kind == ChunkKind::RawContent; } }; struct NoBitsSection : Section { llvm::yaml::Hex64 Size; - NoBitsSection() : Section(SectionKind::NoBits) {} + NoBitsSection() : Section(ChunkKind::NoBits) {} - static bool classof(const Section *S) { - return S->Kind == SectionKind::NoBits; - } + static bool classof(const Chunk *S) { return S->Kind == ChunkKind::NoBits; } }; struct NoteSection : Section { @@ -235,8 +257,9 @@ struct NoteSection : Section { Optional Size; Optional> Notes; - NoteSection() : Section(SectionKind::Note) {} - static bool classof(const Section *S) { return S->Kind == SectionKind::Note; } + NoteSection() : Section(ChunkKind::Note) {} + + static bool classof(const Chunk *S) { return S->Kind == ChunkKind::Note; } }; struct HashSection : Section { @@ -245,9 +268,9 @@ struct HashSection : Section { Optional> Bucket; Optional> Chain; - HashSection() : Section(SectionKind::Hash) {} + HashSection() : Section(ChunkKind::Hash) {} - static bool classof(const Section *S) { return S->Kind == SectionKind::Hash; } + static bool classof(const Chunk *S) { return S->Kind == ChunkKind::Hash; } }; struct GnuHashHeader { @@ -278,9 +301,9 @@ struct GnuHashSection : Section { Optional> HashBuckets; Optional> HashValues; - GnuHashSection() : Section(SectionKind::GnuHash) {} + GnuHashSection() : Section(ChunkKind::GnuHash) {} - static bool classof(const Section *S) { return S->Kind == SectionKind::GnuHash; } + static bool classof(const Chunk *S) { return S->Kind == ChunkKind::GnuHash; } }; struct VernauxEntry { @@ -300,10 +323,10 @@ struct VerneedSection : Section { std::vector VerneedV; llvm::yaml::Hex64 Info; - VerneedSection() : Section(SectionKind::Verneed) {} + VerneedSection() : Section(ChunkKind::Verneed) {} - static bool classof(const Section *S) { - return S->Kind == SectionKind::Verneed; + static bool classof(const Chunk *S) { + return S->Kind == ChunkKind::Verneed; } }; @@ -321,20 +344,17 @@ struct AddrsigSection : Section { Optional Size; Optional> Symbols; - AddrsigSection() : Section(SectionKind::Addrsig) {} - static bool classof(const Section *S) { - return S->Kind == SectionKind::Addrsig; - } + AddrsigSection() : Section(ChunkKind::Addrsig) {} + + static bool classof(const Chunk *S) { return S->Kind == ChunkKind::Addrsig; } }; struct SymverSection : Section { std::vector Entries; - SymverSection() : Section(SectionKind::Symver) {} + SymverSection() : Section(ChunkKind::Symver) {} - static bool classof(const Section *S) { - return S->Kind == SectionKind::Symver; - } + static bool classof(const Chunk *S) { return S->Kind == ChunkKind::Symver; } }; struct VerdefEntry { @@ -349,11 +369,9 @@ struct VerdefSection : Section { std::vector Entries; llvm::yaml::Hex64 Info; - VerdefSection() : Section(SectionKind::Verdef) {} + VerdefSection() : Section(ChunkKind::Verdef) {} - static bool classof(const Section *S) { - return S->Kind == SectionKind::Verdef; - } + static bool classof(const Chunk *S) { return S->Kind == ChunkKind::Verdef; } }; struct Group : Section { @@ -362,11 +380,9 @@ struct Group : Section { std::vector Members; Optional Signature; /* Info */ - Group() : Section(SectionKind::Group) {} + Group() : Section(ChunkKind::Group) {} - static bool classof(const Section *S) { - return S->Kind == SectionKind::Group; - } + static bool classof(const Chunk *S) { return S->Kind == ChunkKind::Group; } }; struct Relocation { @@ -380,20 +396,20 @@ struct RelocationSection : Section { std::vector Relocations; StringRef RelocatableSec; /* Info */ - RelocationSection() : Section(SectionKind::Relocation) {} + RelocationSection() : Section(ChunkKind::Relocation) {} - static bool classof(const Section *S) { - return S->Kind == SectionKind::Relocation; + static bool classof(const Chunk *S) { + return S->Kind == ChunkKind::Relocation; } }; struct SymtabShndxSection : Section { std::vector Entries; - SymtabShndxSection() : Section(SectionKind::SymtabShndxSection) {} + SymtabShndxSection() : Section(ChunkKind::SymtabShndxSection) {} - static bool classof(const Section *S) { - return S->Kind == SectionKind::SymtabShndxSection; + static bool classof(const Chunk *S) { + return S->Kind == ChunkKind::SymtabShndxSection; } }; @@ -411,23 +427,35 @@ struct MipsABIFlags : Section { MIPS_AFL_FLAGS1 Flags1; llvm::yaml::Hex32 Flags2; - MipsABIFlags() : Section(SectionKind::MipsABIFlags) {} + MipsABIFlags() : Section(ChunkKind::MipsABIFlags) {} - static bool classof(const Section *S) { - return S->Kind == SectionKind::MipsABIFlags; + static bool classof(const Chunk *S) { + return S->Kind == ChunkKind::MipsABIFlags; } }; struct Object { FileHeader Header; std::vector ProgramHeaders; - std::vector> Sections; + + // An object might contain output section descriptions as well as + // custom data that does not belong to any section. + std::vector> Chunks; + // Although in reality the symbols reside in a section, it is a lot // cleaner and nicer if we read them from the YAML as a separate // top-level key, which automatically ensures that invariants like there // being a single SHT_SYMTAB section are upheld. Optional> Symbols; std::vector DynamicSymbols; + + std::vector
getSections() { + std::vector
Ret; + for (const std::unique_ptr &Sec : Chunks) + if (auto S = dyn_cast(Sec.get())) + Ret.push_back(S); + return Ret; + } }; } // end namespace ELFYAML @@ -438,7 +466,7 @@ LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::StackSizeEntry) LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::DynamicEntry) LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::NoteEntry) LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::ProgramHeader) -LLVM_YAML_IS_SEQUENCE_VECTOR(std::unique_ptr) +LLVM_YAML_IS_SEQUENCE_VECTOR(std::unique_ptr) LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::Symbol) LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::VerdefEntry) LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::VernauxEntry) @@ -607,10 +635,9 @@ template <> struct MappingTraits { static void mapping(IO &IO, ELFYAML::Relocation &Rel); }; -template <> -struct MappingTraits> { - static void mapping(IO &IO, std::unique_ptr &Section); - static StringRef validate(IO &io, std::unique_ptr &Section); +template <> struct MappingTraits> { + static void mapping(IO &IO, std::unique_ptr &C); + static StringRef validate(IO &io, std::unique_ptr &C); }; template <> diff --git a/llvm/include/llvm/ObjectYAML/YAML.h b/llvm/include/llvm/ObjectYAML/YAML.h index 37014109a61540..3bf6527a7e2da6 100644 --- a/llvm/include/llvm/ObjectYAML/YAML.h +++ b/llvm/include/llvm/ObjectYAML/YAML.h @@ -85,7 +85,8 @@ class BinaryRef { /// Write the contents (regardless of whether it is binary or a /// hex string) as binary to the given raw_ostream. - void writeAsBinary(raw_ostream &OS) const; + /// N can be used to specify the maximum number of bytes. + void writeAsBinary(raw_ostream &OS, uint64_t N = UINT64_MAX) const; /// Write the contents (regardless of whether it is binary or a /// hex string) as hex to the given raw_ostream. diff --git a/llvm/lib/ObjectYAML/ELFEmitter.cpp b/llvm/lib/ObjectYAML/ELFEmitter.cpp index be733dca6969f8..214318f2813588 100644 --- a/llvm/lib/ObjectYAML/ELFEmitter.cpp +++ b/llvm/lib/ObjectYAML/ELFEmitter.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/DenseMap.h" #include "llvm/ADT/StringSet.h" #include "llvm/BinaryFormat/ELF.h" #include "llvm/MC/StringTableBuilder.h" @@ -88,6 +89,15 @@ class NameToIdxMap { unsigned size() const { return Map.size(); } }; +namespace { +struct Fragment { + uint64_t Offset; + uint64_t Size; + uint32_t Type; + uint64_t AddrAlign; +}; +}; // namespace + /// "Single point of truth" for the ELF file construction. /// TODO: This class still has a ways to go before it is truly a "single /// point of truth". @@ -142,6 +152,11 @@ template class ELFState { ELFYAML::Section *YAMLSec); void setProgramHeaderLayout(std::vector &PHeaders, std::vector &SHeaders); + + std::vector + getPhdrFragments(const ELFYAML::ProgramHeader &Phdr, + ArrayRef SHeaders); + void finalizeStrings(); void writeELFHeader(ContiguousBlobAccumulator &CBA, raw_ostream &OS); void writeSectionContent(Elf_Shdr &SHeader, @@ -186,6 +201,8 @@ template class ELFState { const ELFYAML::GnuHashSection &Section, ContiguousBlobAccumulator &CBA); + void writeFill(ELFYAML::Fill &Fill, ContiguousBlobAccumulator &CBA); + ELFState(ELFYAML::Object &D, yaml::ErrorHandler EH); public: @@ -207,17 +224,18 @@ template static void zero(T &Obj) { memset(&Obj, 0, sizeof(Obj)); } template ELFState::ELFState(ELFYAML::Object &D, yaml::ErrorHandler EH) : Doc(D), ErrHandler(EH) { + std::vector Sections = Doc.getSections(); StringSet<> DocSections; - for (std::unique_ptr &D : Doc.Sections) - if (!D->Name.empty()) - DocSections.insert(D->Name); + for (const ELFYAML::Section *Sec : Sections) + if (!Sec->Name.empty()) + DocSections.insert(Sec->Name); // Insert SHT_NULL section implicitly when it is not defined in YAML. - if (Doc.Sections.empty() || Doc.Sections.front()->Type != ELF::SHT_NULL) - Doc.Sections.insert( - Doc.Sections.begin(), + if (Sections.empty() || Sections.front()->Type != ELF::SHT_NULL) + Doc.Chunks.insert( + Doc.Chunks.begin(), std::make_unique( - ELFYAML::Section::SectionKind::RawContent, /*IsImplicit=*/true)); + ELFYAML::Chunk::ChunkKind::RawContent, /*IsImplicit=*/true)); std::vector ImplicitSections; if (Doc.Symbols) @@ -233,10 +251,10 @@ ELFState::ELFState(ELFYAML::Object &D, yaml::ErrorHandler EH) if (DocSections.count(SecName)) continue; - std::unique_ptr Sec = std::make_unique( - ELFYAML::Section::SectionKind::RawContent, true /*IsImplicit*/); + std::unique_ptr Sec = std::make_unique( + ELFYAML::Chunk::ChunkKind::RawContent, true /*IsImplicit*/); Sec->Name = SecName; - Doc.Sections.push_back(std::move(Sec)); + Doc.Chunks.push_back(std::move(Sec)); } } @@ -274,7 +292,7 @@ void ELFState::writeELFHeader(ContiguousBlobAccumulator &CBA, raw_ostream Header.e_shoff = Doc.Header.SHOff ? typename ELFT::uint(*Doc.Header.SHOff) : SHOff; Header.e_shnum = - Doc.Header.SHNum ? (uint16_t)*Doc.Header.SHNum : Doc.Sections.size(); + Doc.Header.SHNum ? (uint16_t)*Doc.Header.SHNum : Doc.getSections().size(); Header.e_shstrndx = Doc.Header.SHStrNdx ? (uint16_t)*Doc.Header.SHStrNdx : SN2I.get(".shstrtab"); @@ -371,18 +389,25 @@ void ELFState::initSectionHeaders(std::vector &SHeaders, ContiguousBlobAccumulator &CBA) { // Ensure SHN_UNDEF entry is present. An all-zero section header is a // valid SHN_UNDEF entry since SHT_NULL == 0. - SHeaders.resize(Doc.Sections.size()); + SHeaders.resize(Doc.getSections().size()); + + size_t SecNdx = -1; + for (const std::unique_ptr &D : Doc.Chunks) { + if (auto S = dyn_cast(D.get())) { + writeFill(*S, CBA); + continue; + } - for (size_t I = 0; I < Doc.Sections.size(); ++I) { - ELFYAML::Section *Sec = Doc.Sections[I].get(); - if (I == 0 && Sec->IsImplicit) + ++SecNdx; + ELFYAML::Section *Sec = cast(D.get()); + if (SecNdx == 0 && Sec->IsImplicit) continue; // We have a few sections like string or symbol tables that are usually // added implicitly to the end. However, if they are explicitly specified // in the YAML, we need to write them here. This ensures the file offset // remains correct. - Elf_Shdr &SHeader = SHeaders[I]; + Elf_Shdr &SHeader = SHeaders[SecNdx]; if (initImplicitHeader(CBA, SHeader, Sec->Name, Sec->IsImplicit ? nullptr : Sec)) continue; @@ -401,7 +426,7 @@ void ELFState::initSectionHeaders(std::vector &SHeaders, if (!Sec->Link.empty()) SHeader.sh_link = toSectionIndex(Sec->Link, Sec->Name); - if (I == 0) { + if (SecNdx == 0) { if (auto RawSec = dyn_cast(Sec)) { // We do not write any content for special SHN_UNDEF section. if (RawSec->Size) @@ -640,23 +665,44 @@ template void ELFState::reportError(const Twine &Msg) { HasError = true; } +template +std::vector +ELFState::getPhdrFragments(const ELFYAML::ProgramHeader &Phdr, + ArrayRef SHeaders) { + DenseMap NameToFill; + for (const std::unique_ptr &D : Doc.Chunks) + if (auto S = dyn_cast(D.get())) + NameToFill[S->Name] = S; + + std::vector Ret; + for (const ELFYAML::SectionName &SecName : Phdr.Sections) { + unsigned Index; + if (SN2I.lookup(SecName.Section, Index)) { + const typename ELFT::Shdr &H = SHeaders[Index]; + Ret.push_back({H.sh_offset, H.sh_size, H.sh_type, H.sh_addralign}); + continue; + } + + if (ELFYAML::Fill *Fill = NameToFill.lookup(SecName.Section)) { + Ret.push_back({Fill->ShOffset, Fill->Size, llvm::ELF::SHT_PROGBITS, + /*ShAddrAlign=*/1}); + continue; + } + + reportError("unknown section or fill referenced: '" + SecName.Section + + "' by program header"); + } + + return Ret; +} + template void ELFState::setProgramHeaderLayout(std::vector &PHeaders, std::vector &SHeaders) { uint32_t PhdrIdx = 0; for (auto &YamlPhdr : Doc.ProgramHeaders) { Elf_Phdr &PHeader = PHeaders[PhdrIdx++]; - - std::vector Sections; - for (const ELFYAML::SectionName &SecName : YamlPhdr.Sections) { - unsigned Index; - if (!SN2I.lookup(SecName.Section, Index)) { - reportError("unknown section referenced: '" + SecName.Section + - "' by program header"); - continue; - } - Sections.push_back(&SHeaders[Index]); - } + std::vector Fragments = getPhdrFragments(YamlPhdr, SHeaders); if (YamlPhdr.Offset) { PHeader.p_offset = *YamlPhdr.Offset; @@ -667,19 +713,19 @@ void ELFState::setProgramHeaderLayout(std::vector &PHeaders, PHeader.p_offset = 0; // Find the minimum offset for the program header. - for (Elf_Shdr *SHeader : Sections) - PHeader.p_offset = std::min(PHeader.p_offset, SHeader->sh_offset); + for (const Fragment &F : Fragments) + PHeader.p_offset = std::min((uint64_t)PHeader.p_offset, F.Offset); } // Find the maximum offset of the end of a section in order to set p_filesz // and p_memsz. When setting p_filesz, trailing SHT_NOBITS sections are not // counted. uint64_t FileOffset = PHeader.p_offset, MemOffset = PHeader.p_offset; - for (Elf_Shdr *SHeader : Sections) { - uint64_t End = SHeader->sh_offset + SHeader->sh_size; + for (const Fragment &F : Fragments) { + uint64_t End = F.Offset + F.Size; MemOffset = std::max(MemOffset, End); - if (SHeader->sh_type != llvm::ELF::SHT_NOBITS) + if (F.Type != llvm::ELF::SHT_NOBITS) FileOffset = std::max(FileOffset, End); } @@ -696,8 +742,8 @@ void ELFState::setProgramHeaderLayout(std::vector &PHeaders, // sections so that by default the segment has a valid and sensible // alignment. PHeader.p_align = 1; - for (Elf_Shdr *SHeader : Sections) - PHeader.p_align = std::max(PHeader.p_align, SHeader->sh_addralign); + for (const Fragment &F : Fragments) + PHeader.p_align = std::max((uint64_t)PHeader.p_align, F.AddrAlign); } } } @@ -1160,16 +1206,45 @@ void ELFState::writeSectionContent(Elf_Shdr &SHeader, Section.HashValues->size() * 4; } +template +void ELFState::writeFill(ELFYAML::Fill &Fill, + ContiguousBlobAccumulator &CBA) { + raw_ostream &OS = CBA.getOSAndAlignedOffset(Fill.ShOffset, /*Align=*/1); + + size_t PatternSize = Fill.Pattern ? Fill.Pattern->binary_size() : 0; + if (!PatternSize) { + OS.write_zeros(Fill.Size); + return; + } + + // Fill the content with the specified pattern. + uint64_t Written = 0; + for (; Written + PatternSize <= Fill.Size; Written += PatternSize) + Fill.Pattern->writeAsBinary(OS); + Fill.Pattern->writeAsBinary(OS, Fill.Size - Written); +} + template void ELFState::buildSectionIndex() { - for (unsigned I = 0, E = Doc.Sections.size(); I != E; ++I) { - StringRef Name = Doc.Sections[I]->Name; - if (Name.empty()) + size_t SecNdx = -1; + StringSet<> Seen; + for (size_t I = 0; I < Doc.Chunks.size(); ++I) { + const std::unique_ptr &C = Doc.Chunks[I]; + bool IsSection = isa(C.get()); + if (IsSection) + ++SecNdx; + + if (C->Name.empty()) continue; - DotShStrtab.add(ELFYAML::dropUniqueSuffix(Name)); - if (!SN2I.addName(Name, I)) - reportError("repeated section name: '" + Name + - "' at YAML section number " + Twine(I)); + if (!Seen.insert(C->Name).second) + reportError("repeated section/fill name: '" + C->Name + + "' at YAML section/fill number " + Twine(I)); + if (!IsSection || HasError) + continue; + + if (!SN2I.addName(C->Name, SecNdx)) + llvm_unreachable("buildSectionIndex() failed"); + DotShStrtab.add(ELFYAML::dropUniqueSuffix(C->Name)); } DotShStrtab.finalize(); @@ -1202,14 +1277,14 @@ template void ELFState::finalizeStrings() { // SHT_GNU_verdef and SHT_GNU_verneed sections might also // add strings to .dynstr section. - for (const std::unique_ptr &Sec : Doc.Sections) { - if (auto VerNeed = dyn_cast(Sec.get())) { + for (const ELFYAML::Chunk *Sec : Doc.getSections()) { + if (auto VerNeed = dyn_cast(Sec)) { for (const ELFYAML::VerneedEntry &VE : VerNeed->VerneedV) { DotDynstr.add(VE.File); for (const ELFYAML::VernauxEntry &Aux : VE.AuxV) DotDynstr.add(Aux.Name); } - } else if (auto VerDef = dyn_cast(Sec.get())) { + } else if (auto VerDef = dyn_cast(Sec)) { for (const ELFYAML::VerdefEntry &E : VerDef->Entries) for (StringRef Name : E.VerNames) DotDynstr.add(Name); @@ -1230,6 +1305,9 @@ bool ELFState::writeELF(raw_ostream &OS, ELFYAML::Object &Doc, State.finalizeStrings(); State.buildSectionIndex(); + if (State.HasError) + return false; + State.buildSymbolIndexes(); std::vector PHeaders; diff --git a/llvm/lib/ObjectYAML/ELFYAML.cpp b/llvm/lib/ObjectYAML/ELFYAML.cpp index 5872cbbe5150e1..b50f842bba5be9 100644 --- a/llvm/lib/ObjectYAML/ELFYAML.cpp +++ b/llvm/lib/ObjectYAML/ELFYAML.cpp @@ -24,7 +24,7 @@ namespace llvm { -ELFYAML::Section::~Section() = default; +ELFYAML::Chunk::~Chunk() = default; namespace yaml { @@ -1094,6 +1094,12 @@ static void sectionMapping(IO &IO, ELFYAML::AddrsigSection &Section) { IO.mapOptional("Symbols", Section.Symbols); } +static void fillMapping(IO &IO, ELFYAML::Fill &Fill) { + IO.mapOptional("Name", Fill.Name, StringRef()); + IO.mapOptional("Pattern", Fill.Pattern); + IO.mapRequired("Size", Fill.Size); +} + void MappingTraits::mapping( IO &IO, ELFYAML::SectionOrType §ionOrType) { IO.mapRequired("SectionOrType", sectionOrType.sectionNameOrType); @@ -1124,15 +1130,27 @@ static void sectionMapping(IO &IO, ELFYAML::MipsABIFlags &Section) { IO.mapOptional("Flags2", Section.Flags2, Hex32(0)); } -void MappingTraits>::mapping( - IO &IO, std::unique_ptr &Section) { - ELFYAML::ELF_SHT sectionType; - if (IO.outputting()) - sectionType = Section->Type; - else - IO.mapRequired("Type", sectionType); +void MappingTraits>::mapping( + IO &IO, std::unique_ptr &Section) { + ELFYAML::ELF_SHT Type; + if (IO.outputting()) { + Type = cast(Section.get())->Type; + } else { + // When the Type string does not have a "SHT_" prefix, we know it is not a + // description of a regular ELF output section. Currently, we have one + // special type named "Fill". See comments for Fill. + StringRef StrType; + IO.mapRequired("Type", StrType); + if (StrType == "Fill") { + Section.reset(new ELFYAML::Fill()); + fillMapping(IO, *cast(Section.get())); + return; + } + + IO.mapRequired("Type", Type); + } - switch (sectionType) { + switch (Type) { case ELF::SHT_DYNAMIC: if (!IO.outputting()) Section.reset(new ELFYAML::DynamicSection()); @@ -1218,17 +1236,17 @@ void MappingTraits>::mapping( } } -StringRef MappingTraits>::validate( - IO &io, std::unique_ptr &Section) { +StringRef MappingTraits>::validate( + IO &io, std::unique_ptr &C) { if (const auto *RawSection = - dyn_cast(Section.get())) { + dyn_cast(C.get())) { if (RawSection->Size && RawSection->Content && (uint64_t)(*RawSection->Size) < RawSection->Content->binary_size()) return "Section size must be greater than or equal to the content size"; return {}; } - if (const auto *SS = dyn_cast(Section.get())) { + if (const auto *SS = dyn_cast(C.get())) { if (!SS->Entries && !SS->Content && !SS->Size) return ".stack_sizes: one of Content, Entries and Size must be specified"; @@ -1248,7 +1266,7 @@ StringRef MappingTraits>::validate( return {}; } - if (const auto *HS = dyn_cast(Section.get())) { + if (const auto *HS = dyn_cast(C.get())) { if (!HS->Content && !HS->Bucket && !HS->Chain && !HS->Size) return "one of \"Content\", \"Size\", \"Bucket\" or \"Chain\" must be " "specified"; @@ -1271,7 +1289,7 @@ StringRef MappingTraits>::validate( return {}; } - if (const auto *Sec = dyn_cast(Section.get())) { + if (const auto *Sec = dyn_cast(C.get())) { if (!Sec->Symbols && !Sec->Content && !Sec->Size) return "one of \"Content\", \"Size\" or \"Symbols\" must be specified"; @@ -1296,7 +1314,7 @@ StringRef MappingTraits>::validate( return {}; } - if (const auto *NS = dyn_cast(Section.get())) { + if (const auto *NS = dyn_cast(C.get())) { if (!NS->Content && !NS->Size && !NS->Notes) return "one of \"Content\", \"Size\" or \"Notes\" must be " "specified"; @@ -1314,7 +1332,7 @@ StringRef MappingTraits>::validate( return {}; } - if (const auto *Sec = dyn_cast(Section.get())) { + if (const auto *Sec = dyn_cast(C.get())) { if (!Sec->Content && !Sec->Header && !Sec->BloomFilter && !Sec->HashBuckets && !Sec->HashValues) return "either \"Content\" or \"Header\", \"BloomFilter\", " @@ -1337,6 +1355,14 @@ StringRef MappingTraits>::validate( return {}; } + if (const auto *F = dyn_cast(C.get())) { + if (!F->Pattern) + return {}; + if (F->Pattern->binary_size() != 0 && !F->Size) + return "\"Size\" can't be 0 when \"Pattern\" is not empty"; + return {}; + } + return {}; } @@ -1455,7 +1481,7 @@ void MappingTraits::mapping(IO &IO, ELFYAML::Object &Object) { IO.mapTag("!ELF", true); IO.mapRequired("FileHeader", Object.Header); IO.mapOptional("ProgramHeaders", Object.ProgramHeaders); - IO.mapOptional("Sections", Object.Sections); + IO.mapOptional("Sections", Object.Chunks); IO.mapOptional("Symbols", Object.Symbols); IO.mapOptional("DynamicSymbols", Object.DynamicSymbols); IO.setContext(nullptr); diff --git a/llvm/lib/ObjectYAML/YAML.cpp b/llvm/lib/ObjectYAML/YAML.cpp index 6eba16e36c2a21..54d5f79bdcabf0 100644 --- a/llvm/lib/ObjectYAML/YAML.cpp +++ b/llvm/lib/ObjectYAML/YAML.cpp @@ -37,15 +37,16 @@ StringRef yaml::ScalarTraits::input(StringRef Scalar, void *, return {}; } -void yaml::BinaryRef::writeAsBinary(raw_ostream &OS) const { +void yaml::BinaryRef::writeAsBinary(raw_ostream &OS, uint64_t N) const { if (!DataIsHexString) { - OS.write((const char *)Data.data(), Data.size()); + OS.write((const char *)Data.data(), std::min(N, Data.size())); return; } - for (unsigned I = 0, N = Data.size(); I != N; I += 2) { - uint8_t Byte = llvm::hexDigitValue(Data[I]); + + for (uint64_t I = 0, E = std::min(N, Data.size() / 2); I != E; ++I) { + uint8_t Byte = llvm::hexDigitValue(Data[I * 2]); Byte <<= 4; - Byte |= llvm::hexDigitValue(Data[I + 1]); + Byte |= llvm::hexDigitValue(Data[I * 2 + 1]); OS.write(Byte); } } diff --git a/llvm/test/tools/yaml2obj/custom-fill.yaml b/llvm/test/tools/yaml2obj/custom-fill.yaml new file mode 100644 index 00000000000000..8dfc2fdae3c26b --- /dev/null +++ b/llvm/test/tools/yaml2obj/custom-fill.yaml @@ -0,0 +1,298 @@ +## Here we check that we are able to define sections with a type of "Fill". +## Fills are custom pieces of data that can be placed anywhere just like normal +## output sections, but they are not real output sections and you'll never see them in +## the section headers. + +## Check we can create named and unnamed fills and use "Pattern" and "Size" fields +## to describe the data emitted. +## Check the data emitted and how it affects regular sections offsets. +## Check that the "Name" field is optional for fills. +## Check that "Size" can be greater than or equal to the pattern data size. + +# RUN: yaml2obj --docnum=1 %s -o %t1 +# RUN: llvm-readelf --sections --headers %t1 | FileCheck %s --check-prefix=BASIC + +# BASIC: Number of section headers: 5 +# BASIC: Section Headers: +# BASIC-NEXT: [Nr] Name Type Address Off Size ES Flg Lk Inf Al +# BASIC-NEXT: [ 0] NULL 0000000000000000 000000 000000 00 0 0 0 +# BASIC-NEXT: [ 1] .foo PROGBITS 0000000000000000 000043 000002 00 0 0 0 +# BASIC-NEXT: [ 2] .bar PROGBITS 0000000000000000 000049 000001 00 0 0 0 +# BASIC-NEXT: [ 3] .strtab STRTAB 0000000000000000 00004b 000001 00 0 0 1 +# BASIC-NEXT: [ 4] .shstrtab STRTAB 0000000000000000 00004c 00001d 00 0 0 1 + +## The fill we dump starts at (offset of .foo - 3), which is (0x43 - 3) = 0x40. +# RUN: od -t x1 -v -j 0x40 -N 11 %t1 | FileCheck %s --ignore-case --check-prefix=DATA +# DATA: aa bb aa 11 22 cc dd cc dd ff ee + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_DYN + Machine: EM_X86_64 +Sections: + - Type: Fill + Pattern: "AABB" + Size: 0x3 + - Name: .foo + Type: SHT_PROGBITS + Content: "1122" + - Type: Fill + Name: unusedName + Pattern: "CCDD" + Size: 4 + - Name: .bar + Type: SHT_PROGBITS + Content: "FF" + - Type: Fill + Pattern: "EE" + Size: 1 + +## Check we can have no explicit regular sections in the YAML description, and can +## describe the content with the use of fills only. +## Check that "Size" can be less than the pattern data size. + +# RUN: yaml2obj --docnum=2 %s -o %t2 +# RUN: llvm-readelf --sections --headers %t2 | FileCheck %s --check-prefix=NOSECTIONS + +## The fill we dump starts at (offset of .strtab - 3 - 2), which is (0x45 - 5) = 0x40. +# RUN: od -t x1 -v -j 0x40 -N 6 %t2 | FileCheck %s --ignore-case --check-prefix=NOSECTIONS-DATA + +# NOSECTIONS: Number of section headers: 3 +# NOSECTIONS: Section Headers: +# NOSECTIONS-NEXT: [Nr] Name Type Address Off Size ES Flg Lk Inf Al +# NOSECTIONS-NEXT: [ 0] NULL 0000000000000000 000000 000000 00 0 0 0 +# NOSECTIONS-NEXT: [ 1] .strtab STRTAB 0000000000000000 000045 000001 00 0 0 1 +# NOSECTIONS-NEXT: [ 2] .shstrtab STRTAB 0000000000000000 000046 000013 00 0 0 1 + +## .strtab that follows fills starts at 0x46 and always has a null character at the begining. +# NOSECTIONS-DATA: aa bb cc dd ee 00 + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_DYN + Machine: EM_X86_64 +Sections: + - Type: Fill + Pattern: "AABBCCFF" + Size: 0x3 + - Type: Fill + Pattern: "DDEEFF" + Size: 0x2 + +## Check we can use named fills when describing program headers. +## Check that fills consume the file size and therefore affect the p_filesz fields of segments. +## Check that the fill does not affect the p_align field of the segment. + +# RUN: yaml2obj --docnum=3 %s -o %t3 +# RUN: llvm-readelf --sections --program-headers %t3 | FileCheck %s --check-prefix=PHDR + +# PHDR: [Nr] Name Type Address Off Size ES Flg Lk Inf Al +# PHDR: [ 0] NULL 0000000000000000 000000 000000 00 0 0 0 +# PHDR: [ 1] .bar PROGBITS 0000000000000100 0000c0 000005 00 0 0 2 +# PHDR: [ 2] .strtab STRTAB 0000000000000000 00010a 000001 00 0 0 1 +# PHDR: [ 3] .shstrtab STRTAB 0000000000000000 00010b 000018 00 0 0 1 + +# PHDR: Program Headers: +# PHDR: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align +# PHDR: LOAD 0x0000b0 0x0000000000000100 0x0000000000000100 0x00005a 0x00005a 0x2 +# PHDR: GNU_RELRO 0x0000c5 0x0000000000000105 0x0000000000000105 0x000045 0x000045 0x1 + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_DYN + Machine: EM_X86_64 +Sections: + - Type: Fill + Name: fill1 + Pattern: "" + Size: 0x10 + - Name: .bar + Type: SHT_PROGBITS + Size: 0x5 + Address: 0x100 + AddressAlign: 2 + - Type: Fill + Name: fill2 + Pattern: "" + Size: 0x45 +ProgramHeaders: + - Type: PT_LOAD + VAddr: 0x100 + PAddr: 0x100 + Sections: + - Section: fill1 + - Section: .bar + - Section: fill2 + - Type: PT_GNU_RELRO + VAddr: 0x105 + PAddr: 0x105 + Sections: + - Section: fill2 + +## Check that the "Pattern" field is not mandatory. +# RUN: yaml2obj --docnum=4 2>&1 -o %t4 %s +# RUN: llvm-readelf --sections %t4 | FileCheck %s --check-prefix=NOPATTERN + +## The fill we dump starts at (offset of .strtab - 1 - 3 - 1), which is (0x45 - 5) = 0x40. +# RUN: od -t x1 -v -j 0x40 -N 5 %t4 | FileCheck %s --ignore-case --check-prefix=NOPATTERN-DATA + +# NOPATTERN: [Nr] Name Type Address Off +# NOPATTERN: [ 1] .strtab STRTAB 0000000000000000 000045 + +# NOPATTERN-DATA: aa 00 00 00 bb + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_DYN + Machine: EM_X86_64 +Sections: + - Type: Fill + Size: 0x1 + Pattern: "AA" + - Type: Fill + Size: 0x3 + - Type: Fill + Size: 0x1 + Pattern: "BB" + +## Check that the "Size" field is mandatory. +# RUN: not yaml2obj --docnum=5 2>&1 %s | FileCheck %s --check-prefix=NOSIZE + +## NOSIZE: error: missing required key 'Size' + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_DYN + Machine: EM_X86_64 +Sections: + - Type: Fill + Pattern: "00" + +## Check that fills are not allowed to have duplicate names. +# RUN: not yaml2obj --docnum=6 2>&1 %s | FileCheck %s --check-prefix=UNIQUE-NAME + +# UNIQUE-NAME: error: repeated section/fill name: 'foo' at YAML section/fill number 2 +# UNIQUE-NAME: error: repeated section/fill name: 'foo' at YAML section/fill number 3 + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_DYN + Machine: EM_X86_64 +Sections: + - Type: Fill + Name: foo + Pattern: "00" + Size: 1 + - Type: Fill + Name: foo + Pattern: "00" + Size: 1 + - Name: foo + Type: SHT_PROGBITS + +## Check that "Pattern" can be empty, when "Size" is zero. +# RUN: yaml2obj --docnum=7 2>&1 %s -o %t7 +# RUN: llvm-readelf --sections %t7 | FileCheck %s --check-prefix=NOOP + +# NOOP: [Nr] Name Type Address Off +# NOOP: [ 1] begin PROGBITS 0000000000000000 000040 +# NOOP: [ 2] end PROGBITS 0000000000000000 000041 + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_DYN + Machine: EM_X86_64 +Sections: + - Name: begin + Type: SHT_PROGBITS + Size: 1 + - Type: Fill + Pattern: "" + Size: 0 + - Name: end + Type: SHT_PROGBITS + Size: 1 + +## Check that we can have an empty "Pattern", but have non-zero "Size". +## In this case we emit Size number of zeroes to the output. + +# RUN: yaml2obj --docnum=8 2>&1 -o %t8 %s +# RUN: llvm-readelf --sections %t8 | FileCheck %s --check-prefix=EMPTY-PATTERN + +## The fill we dump starts at (offset of .strtab - 1 - 3 - 1), which is (0x45 - 5) = 0x40. +# RUN: od -t x1 -v -j 0x40 -N 5 %t8 | FileCheck %s --ignore-case --check-prefix=EMPTY-PATTERN-DATA + +# EMPTY-PATTERN: Section Headers: +# EMPTY-PATTERN-NEXT: [Nr] Name Type Address Off Size ES Flg Lk Inf Al +# EMPTY-PATTERN-NEXT: [ 0] NULL 0000000000000000 000000 000000 00 0 0 0 +# EMPTY-PATTERN-NEXT: [ 1] .strtab STRTAB 0000000000000000 000045 000001 00 0 0 1 + +# EMPTY-PATTERN-DATA: aa 00 00 00 bb + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_DYN + Machine: EM_X86_64 +Sections: + - Type: Fill + Pattern: "AA" + Size: 0x1 + - Type: Fill + Size: 3 + Pattern: "" + - Type: Fill + Pattern: "BB" + Size: 0x1 + +## Check that "Size" can't be 0, when "Pattern" is not empty. +# RUN: not yaml2obj --docnum=9 2>&1 %s | FileCheck %s --check-prefix=ZERO-SIZE-ERR + +# ZERO-SIZE-ERR: error: "Size" can't be 0 when "Pattern" is not empty + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_DYN + Machine: EM_X86_64 +Sections: + - Type: Fill + Pattern: "00" + Size: 0 + +## Check we report an error when a program header references +## an unknown section or fill and have at least one Fill defined. + +# RUN: not yaml2obj --docnum=10 2>&1 %s | FileCheck %s --check-prefix=UNKNOWN-ERR +# UNKNOWN-ERR: error: unknown section or fill referenced: 'fill' by program header + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_DYN + Machine: EM_X86_64 +Sections: + - Type: Fill + Pattern: "" + Size: 0 +ProgramHeaders: + - Type: PT_LOAD + Sections: + - Section: fill diff --git a/llvm/test/tools/yaml2obj/duplicate-section-names.test b/llvm/test/tools/yaml2obj/duplicate-section-names.test index 4765179755e060..8b21511a281f5a 100644 --- a/llvm/test/tools/yaml2obj/duplicate-section-names.test +++ b/llvm/test/tools/yaml2obj/duplicate-section-names.test @@ -29,8 +29,8 @@ Sections: ## sections with equal names and suffixes. # RUN: not yaml2obj --docnum=2 %s 2>&1 | FileCheck %s --check-prefix=CASE2 -# CASE2: error: repeated section name: '.foo [1]' at YAML section number 2 -# CASE2: error: repeated section name: '.foo [1]' at YAML section number 3 +# CASE2: error: repeated section/fill name: '.foo [1]' at YAML section/fill number 2 +# CASE2: error: repeated section/fill name: '.foo [1]' at YAML section/fill number 3 --- !ELF FileHeader: @@ -51,7 +51,7 @@ Sections: ## names are equal. # RUN: not yaml2obj --docnum=3 %s 2>&1 | FileCheck %s --check-prefix=CASE3 -# CASE3: error: repeated section name: '.foo' at YAML section number 2 +# CASE3: error: repeated section/fill name: '.foo' at YAML section/fill number 2 --- !ELF FileHeader: diff --git a/llvm/test/tools/yaml2obj/program-header.yaml b/llvm/test/tools/yaml2obj/program-header.yaml index aaada115a2cdfa..dbffafc465fa29 100644 --- a/llvm/test/tools/yaml2obj/program-header.yaml +++ b/llvm/test/tools/yaml2obj/program-header.yaml @@ -81,8 +81,8 @@ ProgramHeaders: ## Check we do not allow referencing sections that do not exist. # RUN: not yaml2obj --docnum=2 %s -o %t 2>&1 | FileCheck %s --check-prefix=ERR -# ERR: error: unknown section referenced: '.foo' by program header -# ERR: error: unknown section referenced: '.bar' by program header +# ERR: error: unknown section or fill referenced: '.foo' by program header +# ERR: error: unknown section or fill referenced: '.bar' by program header --- !ELF FileHeader: diff --git a/llvm/tools/obj2yaml/elf2yaml.cpp b/llvm/tools/obj2yaml/elf2yaml.cpp index 495de166723d99..13469804b98304 100644 --- a/llvm/tools/obj2yaml/elf2yaml.cpp +++ b/llvm/tools/obj2yaml/elf2yaml.cpp @@ -78,7 +78,7 @@ class ELFDumper { Expected dumpStackSizesSection(const Elf_Shdr *Shdr); - Expected dumpSpecialSection(const Elf_Shdr *Shdr); + Expected dumpSpecialSection(const Elf_Shdr *Shdr); public: ELFDumper(const object::ELFFile &O); @@ -221,7 +221,7 @@ template Expected ELFDumper::dump() { Expected SecOrErr = dumpDynamicSection(&Sec); if (!SecOrErr) return SecOrErr.takeError(); - Y->Sections.emplace_back(*SecOrErr); + Y->Chunks.emplace_back(*SecOrErr); break; } case ELF::SHT_STRTAB: @@ -234,7 +234,7 @@ template Expected ELFDumper::dump() { dumpSymtabShndxSection(&Sec); if (!SecOrErr) return SecOrErr.takeError(); - Y->Sections.emplace_back(*SecOrErr); + Y->Chunks.emplace_back(*SecOrErr); break; } case ELF::SHT_REL: @@ -242,77 +242,77 @@ template Expected ELFDumper::dump() { Expected SecOrErr = dumpRelocSection(&Sec); if (!SecOrErr) return SecOrErr.takeError(); - Y->Sections.emplace_back(*SecOrErr); + Y->Chunks.emplace_back(*SecOrErr); break; } case ELF::SHT_GROUP: { Expected GroupOrErr = dumpGroup(&Sec); if (!GroupOrErr) return GroupOrErr.takeError(); - Y->Sections.emplace_back(*GroupOrErr); + Y->Chunks.emplace_back(*GroupOrErr); break; } case ELF::SHT_MIPS_ABIFLAGS: { Expected SecOrErr = dumpMipsABIFlags(&Sec); if (!SecOrErr) return SecOrErr.takeError(); - Y->Sections.emplace_back(*SecOrErr); + Y->Chunks.emplace_back(*SecOrErr); break; } case ELF::SHT_NOBITS: { Expected SecOrErr = dumpNoBitsSection(&Sec); if (!SecOrErr) return SecOrErr.takeError(); - Y->Sections.emplace_back(*SecOrErr); + Y->Chunks.emplace_back(*SecOrErr); break; } case ELF::SHT_NOTE: { Expected SecOrErr = dumpNoteSection(&Sec); if (!SecOrErr) return SecOrErr.takeError(); - Y->Sections.emplace_back(*SecOrErr); + Y->Chunks.emplace_back(*SecOrErr); break; } case ELF::SHT_HASH: { Expected SecOrErr = dumpHashSection(&Sec); if (!SecOrErr) return SecOrErr.takeError(); - Y->Sections.emplace_back(*SecOrErr); + Y->Chunks.emplace_back(*SecOrErr); break; } case ELF::SHT_GNU_HASH: { Expected SecOrErr = dumpGnuHashSection(&Sec); if (!SecOrErr) return SecOrErr.takeError(); - Y->Sections.emplace_back(*SecOrErr); + Y->Chunks.emplace_back(*SecOrErr); break; } case ELF::SHT_GNU_verdef: { Expected SecOrErr = dumpVerdefSection(&Sec); if (!SecOrErr) return SecOrErr.takeError(); - Y->Sections.emplace_back(*SecOrErr); + Y->Chunks.emplace_back(*SecOrErr); break; } case ELF::SHT_GNU_versym: { Expected SecOrErr = dumpSymverSection(&Sec); if (!SecOrErr) return SecOrErr.takeError(); - Y->Sections.emplace_back(*SecOrErr); + Y->Chunks.emplace_back(*SecOrErr); break; } case ELF::SHT_GNU_verneed: { Expected SecOrErr = dumpVerneedSection(&Sec); if (!SecOrErr) return SecOrErr.takeError(); - Y->Sections.emplace_back(*SecOrErr); + Y->Chunks.emplace_back(*SecOrErr); break; } case ELF::SHT_LLVM_ADDRSIG: { Expected SecOrErr = dumpAddrsigSection(&Sec); if (!SecOrErr) return SecOrErr.takeError(); - Y->Sections.emplace_back(*SecOrErr); + Y->Chunks.emplace_back(*SecOrErr); break; } case ELF::SHT_NULL: { @@ -330,11 +330,11 @@ template Expected ELFDumper::dump() { default: { // Recognize some special SHT_PROGBITS sections by name. if (Sec.sh_type == ELF::SHT_PROGBITS) { - Expected SpecialSecOrErr = dumpSpecialSection(&Sec); + Expected SpecialSecOrErr = dumpSpecialSection(&Sec); if (!SpecialSecOrErr) return SpecialSecOrErr.takeError(); if (*SpecialSecOrErr) { - Y->Sections.emplace_back(*SpecialSecOrErr); + Y->Chunks.emplace_back(*SpecialSecOrErr); break; } } @@ -343,7 +343,7 @@ template Expected ELFDumper::dump() { dumpContentSection(&Sec); if (!SecOrErr) return SecOrErr.takeError(); - Y->Sections.emplace_back(*SecOrErr); + Y->Chunks.emplace_back(*SecOrErr); } } } @@ -486,7 +486,7 @@ Error ELFDumper::dumpCommonSection(const Elf_Shdr *Shdr, } template -Expected +Expected ELFDumper::dumpSpecialSection(const Elf_Shdr *Shdr) { auto NameOrErr = getUniquedSectionName(Shdr); if (!NameOrErr)