diff --git a/llvm/include/llvm/ObjectYAML/ELFYAML.h b/llvm/include/llvm/ObjectYAML/ELFYAML.h --- a/llvm/include/llvm/ObjectYAML/ELFYAML.h +++ b/llvm/include/llvm/ObjectYAML/ELFYAML.h @@ -124,6 +124,12 @@ 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 @@ RawContent, Relocation, NoBits, + Note, Hash, Verdef, Verneed, @@ -222,6 +229,15 @@ } }; +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 @@ 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 @@ 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 --- a/llvm/include/llvm/Support/YAMLTraits.h +++ b/llvm/include/llvm/Support/YAMLTraits.h @@ -649,8 +649,7 @@ 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 --- a/llvm/lib/ObjectYAML/ELFEmitter.cpp +++ b/llvm/lib/ObjectYAML/ELFEmitter.cpp @@ -36,6 +36,16 @@ 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 @@ 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 @@ 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 @@ 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 @@ } } +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 --- a/llvm/lib/ObjectYAML/ELFYAML.cpp +++ b/llvm/lib/ObjectYAML/ELFYAML.cpp @@ -1032,6 +1032,13 @@ 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 @@ 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 @@ 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 @@ 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 --- 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 @@ - 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 --- a/llvm/test/tools/llvm-readobj/elf-section-types.test +++ b/llvm/test/tools/llvm-readobj/elf-section-types.test @@ -155,6 +155,7 @@ 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 --- a/llvm/test/tools/llvm-readobj/gnu-notes.test +++ b/llvm/test/tools/llvm-readobj/gnu-notes.test @@ -119,6 +119,7 @@ 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 @@ - 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 @@ 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 @@ 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 --- a/llvm/test/tools/llvm-size/elf-sysv.test +++ b/llvm/test/tools/llvm-size/elf-sysv.test @@ -74,6 +74,7 @@ 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 --- a/llvm/test/tools/yaml2obj/implicit-sections-types.test +++ b/llvm/test/tools/yaml2obj/implicit-sections-types.test @@ -63,6 +63,7 @@ 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 --- a/llvm/tools/obj2yaml/elf2yaml.cpp +++ b/llvm/tools/obj2yaml/elf2yaml.cpp @@ -27,6 +27,8 @@ 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 @@ 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 @@ 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 @@ } 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();