From de3cef1d5d33212059164d6095aca5c5b0284001 Mon Sep 17 00:00:00 2001 From: georgerim Date: Fri, 25 Oct 2019 13:03:19 +0300 Subject: [PATCH] [yaml2obj, obj2yaml] - Add support for SHT_NOTE sections. MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit SHT_NOTE is the section that consists of namesz, descsz, type, name + padding, desc + padding data. This patch teaches yaml2obj, obj2yaml to dump and parse them. This patch implements the section how it is described here: https://docs.oracle.com/cd/E23824_01/html/819-0690/chapter6-18048.html Which says: "For 64–bit objects and 32–bit objects, each entry is an array of 4-byte words in the format of the target processor" The official specification is different http://www.sco.com/developers/gabi/latest/ch5.pheader.html#note_section And says: "n 64-bit objects (files with e_ident[EI_CLASS] equal to ELFCLASS64), each entry is an array of 8-byte words in the format of the target processor. In 32-bit objects (files with e_ident[EI_CLASS] equal to ELFCLASS32), each entry is an array of 4-byte words in the format of the target processor" Since LLVM uses the first, 32-bit way, this patch follows it. Differential revision: https://reviews.llvm.org/D68983 --- llvm/include/llvm/ObjectYAML/ELFYAML.h | 21 +++++++ llvm/include/llvm/Support/YAMLTraits.h | 3 +- llvm/lib/ObjectYAML/ELFEmitter.cpp | 72 +++++++++++++++++++--- llvm/lib/ObjectYAML/ELFYAML.cpp | 38 ++++++++++++ .../llvm-objcopy/ELF/set-section-alignment.test | 1 + .../test/tools/llvm-readobj/elf-section-types.test | 1 + llvm/test/tools/llvm-readobj/gnu-notes.test | 12 ++-- llvm/test/tools/llvm-size/elf-sysv.test | 1 + .../tools/yaml2obj/implicit-sections-types.test | 1 + llvm/tools/obj2yaml/elf2yaml.cpp | 46 ++++++++++++++ 10 files changed, 182 insertions(+), 14 deletions(-) diff --git a/llvm/include/llvm/ObjectYAML/ELFYAML.h b/llvm/include/llvm/ObjectYAML/ELFYAML.h index 0898a0e..57f802c 100644 --- a/llvm/include/llvm/ObjectYAML/ELFYAML.h +++ b/llvm/include/llvm/ObjectYAML/ELFYAML.h @@ -124,6 +124,12 @@ struct StackSizeEntry { llvm::yaml::Hex64 Size; }; +struct NoteEntry { + StringRef Name; + yaml::BinaryRef Desc; + llvm::yaml::Hex32 Type; +}; + struct Section { enum class SectionKind { Dynamic, @@ -131,6 +137,7 @@ struct Section { RawContent, Relocation, NoBits, + Note, Hash, Verdef, Verneed, @@ -222,6 +229,15 @@ struct NoBitsSection : Section { } }; +struct NoteSection : Section { + Optional Content; + Optional Size; + Optional> Notes; + + NoteSection() : Section(SectionKind::Note) {} + static bool classof(const Section *S) { return S->Kind == SectionKind::Note; } +}; + struct HashSection : Section { Optional Content; Optional Size; @@ -386,6 +402,7 @@ struct Object { LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::AddrsigSymbol) 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(llvm::ELFYAML::Symbol) @@ -528,6 +545,10 @@ template <> struct MappingTraits { static void mapping(IO &IO, ELFYAML::DynamicEntry &Rel); }; +template <> struct MappingTraits { + static void mapping(IO &IO, ELFYAML::NoteEntry &N); +}; + template <> struct MappingTraits { static void mapping(IO &IO, ELFYAML::VerdefEntry &E); }; diff --git a/llvm/include/llvm/Support/YAMLTraits.h b/llvm/include/llvm/Support/YAMLTraits.h index a3bfa7d..656020e 100644 --- a/llvm/include/llvm/Support/YAMLTraits.h +++ b/llvm/include/llvm/Support/YAMLTraits.h @@ -649,8 +649,7 @@ inline bool isBool(StringRef S) { inline QuotingType needsQuotes(StringRef S) { if (S.empty()) return QuotingType::Single; - if (isspace(static_cast(S.front())) || - isspace(static_cast(S.back()))) + if (isspace(S.front()) || isspace(S.back())) return QuotingType::Single; if (isNull(S)) return QuotingType::Single; diff --git a/llvm/lib/ObjectYAML/ELFEmitter.cpp b/llvm/lib/ObjectYAML/ELFEmitter.cpp index 8ba1608..dae3f39 100644 --- a/llvm/lib/ObjectYAML/ELFEmitter.cpp +++ b/llvm/lib/ObjectYAML/ELFEmitter.cpp @@ -36,6 +36,16 @@ class ContiguousBlobAccumulator { SmallVector Buf; raw_svector_ostream OS; +public: + ContiguousBlobAccumulator(uint64_t InitialOffset_) + : InitialOffset(InitialOffset_), Buf(), OS(Buf) {} + + template + raw_ostream &getOSAndAlignedOffset(Integer &Offset, unsigned Align) { + Offset = padToAlignment(Align); + return OS; + } + /// \returns The new offset. uint64_t padToAlignment(unsigned Align) { if (Align == 0) @@ -46,14 +56,6 @@ class ContiguousBlobAccumulator { return AlignedOffset; // == CurrentOffset; } -public: - ContiguousBlobAccumulator(uint64_t InitialOffset_) - : InitialOffset(InitialOffset_), Buf(), OS(Buf) {} - template - raw_ostream &getOSAndAlignedOffset(Integer &Offset, unsigned Align) { - Offset = padToAlignment(Align); - return OS; - } void writeBlobToStream(raw_ostream &Out) { Out << OS.str(); } }; @@ -177,6 +179,9 @@ template class ELFState { void writeSectionContent(Elf_Shdr &SHeader, const ELFYAML::AddrsigSection &Section, ContiguousBlobAccumulator &CBA); + void writeSectionContent(Elf_Shdr &SHeader, + const ELFYAML::NoteSection &Section, + ContiguousBlobAccumulator &CBA); ELFState(ELFYAML::Object &D, yaml::ErrorHandler EH); @@ -440,6 +445,8 @@ void ELFState::initSectionHeaders(std::vector &SHeaders, writeSectionContent(SHeader, *S, CBA); } else if (auto S = dyn_cast(Sec)) { writeSectionContent(SHeader, *S, CBA); + } else if (auto S = dyn_cast(Sec)) { + writeSectionContent(SHeader, *S, CBA); } else { llvm_unreachable("Unknown section type"); } @@ -1035,6 +1042,55 @@ void ELFState::writeSectionContent(Elf_Shdr &SHeader, } } +template +void ELFState::writeSectionContent(Elf_Shdr &SHeader, + const ELFYAML::NoteSection &Section, + ContiguousBlobAccumulator &CBA) { + raw_ostream &OS = + CBA.getOSAndAlignedOffset(SHeader.sh_offset, SHeader.sh_addralign); + uint64_t Offset = OS.tell(); + + if (Section.Content || Section.Size) { + SHeader.sh_size = writeContent(OS, Section.Content, Section.Size); + return; + } + + for (const ELFYAML::NoteEntry &NE : *Section.Notes) { + // Write name size. + if (NE.Name.empty()) + support::endian::write(OS, 0, ELFT::TargetEndianness); + else + support::endian::write(OS, NE.Name.size() + 1, + ELFT::TargetEndianness); + + // Write description size. + if (NE.Desc.binary_size() == 0) + support::endian::write(OS, 0, ELFT::TargetEndianness); + else + support::endian::write(OS, NE.Desc.binary_size(), + ELFT::TargetEndianness); + + // Write type. + support::endian::write(OS, NE.Type, ELFT::TargetEndianness); + + // Write name, null terminator and padding. + if (!NE.Name.empty()) { + support::endian::write(OS, arrayRefFromStringRef(NE.Name), + ELFT::TargetEndianness); + support::endian::write(OS, 0, ELFT::TargetEndianness); + CBA.padToAlignment(4); + } + + // Write description and padding. + if (NE.Desc.binary_size() != 0) { + NE.Desc.writeAsBinary(OS); + CBA.padToAlignment(4); + } + } + + SHeader.sh_size = OS.tell() - Offset; +} + template void ELFState::buildSectionIndex() { for (unsigned I = 0, E = Doc.Sections.size(); I != E; ++I) { StringRef Name = Doc.Sections[I]->Name; diff --git a/llvm/lib/ObjectYAML/ELFYAML.cpp b/llvm/lib/ObjectYAML/ELFYAML.cpp index 29585ab..ad316be 100644 --- a/llvm/lib/ObjectYAML/ELFYAML.cpp +++ b/llvm/lib/ObjectYAML/ELFYAML.cpp @@ -1032,6 +1032,13 @@ static void sectionMapping(IO &IO, ELFYAML::HashSection &Section) { IO.mapOptional("Size", Section.Size); } +static void sectionMapping(IO &IO, ELFYAML::NoteSection &Section) { + commonSectionMapping(IO, Section); + IO.mapOptional("Content", Section.Content); + IO.mapOptional("Size", Section.Size); + IO.mapOptional("Notes", Section.Notes); +} + static void sectionMapping(IO &IO, ELFYAML::NoBitsSection &Section) { commonSectionMapping(IO, Section); IO.mapOptional("Size", Section.Size, Hex64(0)); @@ -1143,6 +1150,11 @@ void MappingTraits>::mapping( Section.reset(new ELFYAML::HashSection()); sectionMapping(IO, *cast(Section.get())); break; + case ELF::SHT_NOTE: + if (!IO.outputting()) + Section.reset(new ELFYAML::NoteSection()); + sectionMapping(IO, *cast(Section.get())); + break; case ELF::SHT_MIPS_ABIFLAGS: if (!IO.outputting()) Section.reset(new ELFYAML::MipsABIFlags()); @@ -1270,6 +1282,24 @@ StringRef MappingTraits>::validate( return {}; } + if (const auto *NS = dyn_cast(Section.get())) { + if (!NS->Content && !NS->Size && !NS->Notes) + return "one of \"Content\", \"Size\" or \"Notes\" must be " + "specified"; + + if (!NS->Content && !NS->Size) + return {}; + + if (NS->Size && NS->Content && + (uint64_t)*NS->Size < NS->Content->binary_size()) + return "\"Size\" must be greater than or equal to the content " + "size"; + + if (NS->Notes) + return "\"Notes\" cannot be used with \"Content\" or \"Size\""; + return {}; + } + return {}; } @@ -1313,6 +1343,14 @@ void MappingTraits::mapping(IO &IO, IO.mapRequired("Value", Rel.Val); } +void MappingTraits::mapping(IO &IO, ELFYAML::NoteEntry &N) { + assert(IO.getContext() && "The IO context is not initialized"); + + IO.mapOptional("Name", N.Name); + IO.mapOptional("Desc", N.Desc); + IO.mapRequired("Type", N.Type); +} + void MappingTraits::mapping(IO &IO, ELFYAML::VerdefEntry &E) { assert(IO.getContext() && "The IO context is not initialized"); diff --git a/llvm/test/tools/llvm-objcopy/ELF/set-section-alignment.test b/llvm/test/tools/llvm-objcopy/ELF/set-section-alignment.test index 79c7edd..d992a82 100644 --- a/llvm/test/tools/llvm-objcopy/ELF/set-section-alignment.test +++ b/llvm/test/tools/llvm-objcopy/ELF/set-section-alignment.test @@ -52,3 +52,4 @@ Sections: - Name: .baz Type: SHT_NOTE AddressAlign: 4 + Notes: [] diff --git a/llvm/test/tools/llvm-readobj/elf-section-types.test b/llvm/test/tools/llvm-readobj/elf-section-types.test index 20b8812..fe1f0d3c 100644 --- a/llvm/test/tools/llvm-readobj/elf-section-types.test +++ b/llvm/test/tools/llvm-readobj/elf-section-types.test @@ -155,6 +155,7 @@ Sections: Type: SHT_DYNAMIC - Name: note Type: SHT_NOTE + Notes: [] - Name: nobits Type: SHT_NOBITS - Name: rel diff --git a/llvm/test/tools/llvm-readobj/gnu-notes.test b/llvm/test/tools/llvm-readobj/gnu-notes.test index b3801f5..a625c02 100644 --- a/llvm/test/tools/llvm-readobj/gnu-notes.test +++ b/llvm/test/tools/llvm-readobj/gnu-notes.test @@ -119,6 +119,7 @@ FileHeader: Sections: - Name: .note Type: SHT_NOTE + Notes: [] ShOffset: 0xffff0000 ## Test tools report an error if a note section has invalid size @@ -140,6 +141,7 @@ Sections: - Name: .note Type: SHT_NOTE ShSize: 0xffff0000 + Notes: [] ## Test tools report an error if a note program header has an invalid offset that ## goes past the end of file. @@ -157,8 +159,9 @@ FileHeader: Type: ET_CORE Machine: EM_X86_64 Sections: - - Name: .note - Type: SHT_NOTE + - Name: .note + Type: SHT_NOTE + Notes: [] ProgramHeaders: - Type: PT_NOTE Offset: 0xffff0000 @@ -181,8 +184,9 @@ FileHeader: Type: ET_CORE Machine: EM_X86_64 Sections: - - Name: .note - Type: SHT_NOTE + - Name: .note + Type: SHT_NOTE + Notes: [] ProgramHeaders: - Type: PT_NOTE FileSize: 0xffff0000 diff --git a/llvm/test/tools/llvm-size/elf-sysv.test b/llvm/test/tools/llvm-size/elf-sysv.test index 54f9780..434cd5b 100644 --- a/llvm/test/tools/llvm-size/elf-sysv.test +++ b/llvm/test/tools/llvm-size/elf-sysv.test @@ -74,6 +74,7 @@ Sections: Type: SHT_NOTE ShSize: 0x100 Address: 0x4000 + Notes: [] - Name: .nobits Type: SHT_NOBITS ShSize: 0x200 diff --git a/llvm/test/tools/yaml2obj/implicit-sections-types.test b/llvm/test/tools/yaml2obj/implicit-sections-types.test index 2860fa3..4d22dea 100644 --- a/llvm/test/tools/yaml2obj/implicit-sections-types.test +++ b/llvm/test/tools/yaml2obj/implicit-sections-types.test @@ -63,6 +63,7 @@ Sections: Type: SHT_PROGBITS - Name: .dynsym Type: SHT_NOTE + Size: 0 - Name: .dynstr Type: SHT_NOBITS ## Needed to set the proper content size for .symtab, so diff --git a/llvm/tools/obj2yaml/elf2yaml.cpp b/llvm/tools/obj2yaml/elf2yaml.cpp index 3e10e50..496822a 100644 --- a/llvm/tools/obj2yaml/elf2yaml.cpp +++ b/llvm/tools/obj2yaml/elf2yaml.cpp @@ -27,6 +27,8 @@ class ELFDumper { typedef typename ELFT::Word Elf_Word; typedef typename ELFT::Rel Elf_Rel; typedef typename ELFT::Rela Elf_Rela; + using Elf_Nhdr = typename ELFT::Nhdr; + using Elf_Note = typename ELFT::Note; ArrayRef Sections; ArrayRef SymTable; @@ -66,6 +68,7 @@ class ELFDumper { dumpSymtabShndxSection(const Elf_Shdr *Shdr); Expected dumpNoBitsSection(const Elf_Shdr *Shdr); Expected dumpHashSection(const Elf_Shdr *Shdr); + Expected dumpNoteSection(const Elf_Shdr *Shdr); Expected dumpVerdefSection(const Elf_Shdr *Shdr); Expected dumpSymverSection(const Elf_Shdr *Shdr); Expected dumpVerneedSection(const Elf_Shdr *Shdr); @@ -262,6 +265,13 @@ template Expected ELFDumper::dump() { Y->Sections.emplace_back(*SecOrErr); break; } + case ELF::SHT_NOTE: { + Expected SecOrErr = dumpNoteSection(&Sec); + if (!SecOrErr) + return SecOrErr.takeError(); + Y->Sections.emplace_back(*SecOrErr); + break; + } case ELF::SHT_HASH: { Expected SecOrErr = dumpHashSection(&Sec); if (!SecOrErr) @@ -676,6 +686,42 @@ ELFDumper::dumpNoBitsSection(const Elf_Shdr *Shdr) { } template +Expected +ELFDumper::dumpNoteSection(const Elf_Shdr *Shdr) { + auto S = std::make_unique(); + if (Error E = dumpCommonSection(Shdr, *S)) + return std::move(E); + + auto ContentOrErr = Obj.getSectionContents(Shdr); + if (!ContentOrErr) + return ContentOrErr.takeError(); + + std::vector Entries; + ArrayRef Content = *ContentOrErr; + while (!Content.empty()) { + if (Content.size() < sizeof(Elf_Nhdr)) { + S->Content = yaml::BinaryRef(*ContentOrErr); + return S.release(); + } + + const Elf_Nhdr *Header = reinterpret_cast(Content.data()); + if (Content.size() < Header->getSize()) { + S->Content = yaml::BinaryRef(*ContentOrErr); + return S.release(); + } + + Elf_Note Note(*Header); + Entries.push_back( + {Note.getName(), Note.getDesc(), (llvm::yaml::Hex32)Note.getType()}); + + Content = Content.drop_front(Header->getSize()); + } + + S->Notes = std::move(Entries); + return S.release(); +} + +template Expected ELFDumper::dumpHashSection(const Elf_Shdr *Shdr) { auto S = std::make_unique(); -- 2.7.4