From 06456daa9e59ffddc634e4f1aa592161653fbd36 Mon Sep 17 00:00:00 2001 From: Georgii Rymar Date: Fri, 1 Nov 2019 15:24:58 +0300 Subject: [PATCH] [yaml2obj] - Add a way to describe the custom data that is not part of an output section. Currently there is no way to describe the data that is not a part of an output section. It can be a data used to align sections or to fill the gaps with something, or another kind of custom data. In this patch I suggest a way to describe it. It looks like that: ``` Sections: - Type: CustomFiller Pattern: "CCDD" Size: 4 - Name: .bar Type: SHT_PROGBITS Content: "FF" ``` I.e. I've added a kind of synthetic section with a synthetic type "CustomFiller". In the code it is called a "SyntheticFiller", which is "a synthetic section which might be used to write the custom data around regular output sections. It does not present in the sections header table, but it might affect the output file size and program headers produced. Think about it as about piece of data." `SyntheticFiller` currently has a `Pattern` field and a `Size` field + an optional `Name`. When written, `Size` of bytes in the output will be filled with a `Pattern`. It is possible to reference a named filler it by name from the program headers description, just like any other normal section. Differential revision: https://reviews.llvm.org/D69709 --- llvm/include/llvm/ObjectYAML/ELFYAML.h | 149 ++++++----- llvm/include/llvm/ObjectYAML/YAML.h | 3 +- llvm/lib/ObjectYAML/ELFEmitter.cpp | 168 ++++++++---- llvm/lib/ObjectYAML/ELFYAML.cpp | 62 +++-- llvm/lib/ObjectYAML/YAML.cpp | 11 +- llvm/test/tools/yaml2obj/custom-fill.yaml | 298 +++++++++++++++++++++ .../tools/yaml2obj/duplicate-section-names.test | 6 +- llvm/test/tools/yaml2obj/program-header.yaml | 4 +- llvm/tools/obj2yaml/elf2yaml.cpp | 36 +-- 9 files changed, 584 insertions(+), 153 deletions(-) create mode 100644 llvm/test/tools/yaml2obj/custom-fill.yaml diff --git a/llvm/include/llvm/ObjectYAML/ELFYAML.h b/llvm/include/llvm/ObjectYAML/ELFYAML.h index 26ab098..927afc2 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 3701410..3bf6527 100644 --- a/llvm/include/llvm/ObjectYAML/YAML.h +++ b/llvm/include/llvm/ObjectYAML/YAML.h @@ -85,7 +85,8 @@ public: /// 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 be733dc..214318f 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 @@ public: 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) @@ -641,22 +666,43 @@ template void ELFState::reportError(const Twine &Msg) { } 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 5872cbb..b50f842 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 6eba16e..54d5f79 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 0000000..8dfc2fd --- /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 4765179..8b21511 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 aaada11..dbffafc 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 495de16..1346980 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) -- 2.7.4