Index: include/llvm/BinaryFormat/ELF.h =================================================================== --- include/llvm/BinaryFormat/ELF.h +++ include/llvm/BinaryFormat/ELF.h @@ -1483,6 +1483,20 @@ Elf64_Xword ch_addralign; }; +// Node header for ELF32. +struct Elf32_Nhdr { + Elf32_Word n_namesz; + Elf32_Word n_descsz; + Elf32_Word n_type; +}; + +// Node header for ELF64. +struct Elf64_Nhdr { + Elf64_Word n_namesz; + Elf64_Word n_descsz; + Elf64_Word n_type; +}; + // Legal values for ch_type field of compressed section header. enum { ELFCOMPRESS_ZLIB = 1, // ZLIB/DEFLATE algorithm. Index: include/llvm/Object/ELF.h =================================================================== --- include/llvm/Object/ELF.h +++ include/llvm/Object/ELF.h @@ -67,12 +67,14 @@ using Elf_Versym = typename ELFT::Versym; using Elf_Hash = typename ELFT::Hash; using Elf_GnuHash = typename ELFT::GnuHash; + using Elf_Nhdr = typename ELFT::Nhdr; using Elf_Dyn_Range = typename ELFT::DynRange; using Elf_Shdr_Range = typename ELFT::ShdrRange; using Elf_Sym_Range = typename ELFT::SymRange; using Elf_Rel_Range = typename ELFT::RelRange; using Elf_Rela_Range = typename ELFT::RelaRange; using Elf_Phdr_Range = typename ELFT::PhdrRange; + using Elf_Nhdr_Iterator = typename ELFT::NhdrIterator; const uint8_t *base() const { return reinterpret_cast(Buf.data()); @@ -155,6 +157,69 @@ return makeArrayRef(Begin, Begin + getHeader()->e_phnum); } + /// Get an iterator over notes in a program header. + /// + /// The program header must be of type \c PT_NOTE. + /// + /// \param Phdr the program header to iterate over. + /// \param Err [out] an error to support fallible iteration, which should + /// be checked after iteration ends. + Elf_Nhdr_Iterator notes_begin(const Elf_Phdr &Phdr, Error &Err) const { + if (Phdr.p_type != ELF::PT_NOTE) { + Err = createError("attempt to iterate notes of non-note program header"); + return Elf_Nhdr_Iterator(&Err); + } + return Elf_Nhdr_Iterator( + reinterpret_cast(base() + Phdr.p_offset), + base() + Phdr.p_offset + Phdr.p_filesz, &Err); + } + + /// Get an iterator over notes in a section. + /// + /// The section must be of type \c SHT_NOTE. + /// + /// \param Shdr the section to iterate over. + /// \param Err [out] an error to support fallible iteration, which should + /// be checked after iteration ends. + Elf_Nhdr_Iterator notes_begin(const Elf_Shdr &Shdr, Error &Err) const { + if (Shdr.sh_type != ELF::SHT_NOTE) { + Err = createError("attempt to iterate notes of non-note section"); + return Elf_Nhdr_Iterator(&Err); + } + return Elf_Nhdr_Iterator( + reinterpret_cast(base() + Shdr.sh_offset), + base() + Shdr.sh_offset + Shdr.sh_size, &Err); + } + + /// Get the end iterator for notes. + Elf_Nhdr_Iterator notes_end() const { + return Elf_Nhdr_Iterator(); + } + + /// Get an iterator range over notes of a program header. + /// + /// The program header must be of type \c PT_NOTE. + /// + /// \param Phdr the program header to iterate over. + /// \param Err [out] an error to support fallible iteration, which should + /// be checked after iteration ends. + iterator_range notes(const Elf_Phdr &Phdr, + Error &Err) const { + return make_range(notes_begin(Phdr, Err), notes_end()); + } + + /// Get an iterator range over notes of a section. + /// + /// The section must be of type \c SHT_NOTE. + /// + /// \param Shdr the section to iterate over. + /// \param Err [out] an error to support fallible iteration, which should + /// be checked after iteration ends. + iterator_range notes(const Elf_Shdr &Shdr, + Error &Err) const { + return make_range(notes_begin(Shdr, Err), notes_end()); + } + Expected getSectionStringTable(Elf_Shdr_Range Sections) const; Expected getSectionIndex(const Elf_Sym *Sym, Elf_Sym_Range Syms, ArrayRef ShndxTable) const; Index: include/llvm/Object/ELFTypes.h =================================================================== --- include/llvm/Object/ELFTypes.h +++ include/llvm/Object/ELFTypes.h @@ -40,6 +40,8 @@ template struct Elf_Hash_Impl; template struct Elf_GnuHash_Impl; template struct Elf_Chdr_Impl; +template struct Elf_Nhdr_Impl; +template class Elf_Nhdr_Iterator_Impl; template struct ELFType { private: @@ -66,6 +68,8 @@ using Hash = Elf_Hash_Impl>; using GnuHash = Elf_GnuHash_Impl>; using Chdr = Elf_Chdr_Impl>; + using Nhdr = Elf_Nhdr_Impl>; + using NhdrIterator = Elf_Nhdr_Iterator_Impl>; using DynRange = ArrayRef; using ShdrRange = ArrayRef; using SymRange = ArrayRef; @@ -551,6 +555,92 @@ Elf_Xword ch_addralign; }; +/// Note header +template +struct Elf_Nhdr_Impl { + LLVM_ELF_IMPORT_TYPES_ELFT(ELFT) + Elf_Word n_namesz; + Elf_Word n_descsz; + Elf_Word n_type; + + /// The alignment of the name and descriptor. + /// + /// Implementations differ from the specification here: in practice all + /// variants align both the name and descriptor to 4-bytes. + static const unsigned int Align = 4; + + /// Get the note's name, excluding the terminating null byte. + const StringRef getName() const { + if (!n_namesz) + return StringRef(); + return StringRef(reinterpret_cast(this) + + sizeof(Elf_Nhdr_Impl), + n_namesz - 1); + } + + /// Get the note's descriptor. + const ArrayRef getDesc() const { + if (!n_descsz) + return ArrayRef(); + return ArrayRef(reinterpret_cast( + getName().data() + alignTo(n_namesz)), + n_descsz); + } +}; + +template +class Elf_Nhdr_Iterator_Impl + : std::iterator *> { + const Elf_Nhdr_Impl *Nhdr; + const uint8_t *To; + Error *Err; + + template friend class ELFFile; + + size_t size() const { + return sizeof(Elf_Nhdr_Impl) + + alignTo::Align>(Nhdr->n_namesz) + + alignTo::Align>(Nhdr->n_descsz); + } + + void checkBounds() { + if (Nhdr && reinterpret_cast(Nhdr) + size() > To) { + Nhdr = nullptr; + *Err = make_error("ELF Note overflows container", + object_error::parse_failed); + } + } + + Elf_Nhdr_Iterator_Impl() + : Elf_Nhdr_Iterator_Impl(nullptr, nullptr, nullptr) {} + explicit Elf_Nhdr_Iterator_Impl(Error *Err) + : Elf_Nhdr_Iterator_Impl(nullptr, nullptr, Err) {} + Elf_Nhdr_Iterator_Impl(const Elf_Nhdr_Impl *From, const uint8_t *To, + Error *Err) + : Nhdr(From), To(To), Err(Err) { + checkBounds(); + } + +public: + Elf_Nhdr_Iterator_Impl &operator++() { + const uint8_t *NhdrPosition = reinterpret_cast(Nhdr); + NhdrPosition += size(); + if (NhdrPosition == To) + Nhdr = nullptr; + else + Nhdr = reinterpret_cast *>(NhdrPosition); + checkBounds(); + return *this; + } + bool operator==(Elf_Nhdr_Iterator_Impl Other) const { + return Nhdr == Other.Nhdr; + } + bool operator!=(Elf_Nhdr_Iterator_Impl Other) const { + return !(*this == Other); + } + const Elf_Nhdr_Impl *operator*() const { return Nhdr; } +}; + // MIPS .reginfo section template struct Elf_Mips_RegInfo; Index: tools/llvm-readobj/ELFDumper.cpp =================================================================== --- tools/llvm-readobj/ELFDumper.cpp +++ tools/llvm-readobj/ELFDumper.cpp @@ -92,6 +92,7 @@ using Elf_Word = typename ELFT::Word; \ using Elf_Hash = typename ELFT::Hash; \ using Elf_GnuHash = typename ELFT::GnuHash; \ + using Elf_Nhdr = typename ELFT::Nhdr; \ using Elf_Sym_Range = typename ELFT::SymRange; \ using Elf_Versym = typename ELFT::Versym; \ using Elf_Verneed = typename ELFT::Verneed; \ @@ -3534,62 +3535,56 @@ const Elf_Ehdr *e = Obj->getHeader(); bool IsCore = e->e_type == ELF::ET_CORE; - auto process = [&](const typename ELFT::Off Offset, - const typename ELFT::Addr Size) { - if (Size <= 0) - return; - - const auto *P = static_cast(Obj->base() + Offset); - const auto *E = P + Size; - + auto PrintHeader = [&](const typename ELFT::Off Offset, + const typename ELFT::Addr Size) { OS << "Displaying notes found at file offset " << format_hex(Offset, 10) << " with length " << format_hex(Size, 10) << ":\n" << " Owner Data size\tDescription\n"; + }; - while (P < E) { - const Elf_Word *Words = reinterpret_cast(&P[0]); - - uint32_t NameSize = Words[0]; - uint32_t DescriptorSize = Words[1]; - uint32_t Type = Words[2]; - - ArrayRef Descriptor(&Words[3 + (alignTo<4>(NameSize) / 4)], - alignTo<4>(DescriptorSize) / 4); - - StringRef Name; - if (NameSize) - Name = - StringRef(reinterpret_cast(&Words[3]), NameSize - 1); - - OS << " " << Name << std::string(22 - NameSize, ' ') - << format_hex(DescriptorSize, 10) << '\t'; - - if (Name == "GNU") { - OS << getGNUNoteTypeName(Type) << '\n'; - printGNUNote(OS, Type, Descriptor, DescriptorSize); - } else if (Name == "FreeBSD") { - OS << getFreeBSDNoteTypeName(Type) << '\n'; - } else if (Name == "AMD") { - OS << getAMDGPUNoteTypeName(Type) << '\n'; - printAMDGPUNote(OS, Type, Descriptor, DescriptorSize); - } else { - OS << "Unknown note type: (" << format_hex(Type, 10) << ')'; - } - OS << '\n'; - - P = P + 3 * sizeof(Elf_Word) + alignTo<4>(NameSize) + - alignTo<4>(DescriptorSize); + auto ProcessNote = [&](const Elf_Nhdr *Note) { + StringRef Name = Note->getName(); + ArrayRef Descriptor = Note->getDesc(); + + OS << " " << Name << std::string(22 - Name.size(), ' ') + << format_hex(Descriptor.size(), 10) << '\t'; + + if (Name == "GNU") { + OS << getGNUNoteTypeName(Note->n_type) << '\n'; + printGNUNote(OS, Note->n_type, Descriptor, Descriptor.size()); + } else if (Name == "FreeBSD") { + OS << getFreeBSDNoteTypeName(Note->n_type) << '\n'; + } else if (Name == "AMD") { + OS << getAMDGPUNoteTypeName(Note->n_type) << '\n'; + printAMDGPUNote(OS, Note->n_type, Descriptor, Descriptor.size()); + } else { + OS << "Unknown note type: (" << format_hex(Note->n_type, 10) << ')'; } + OS << '\n'; }; if (IsCore) { - for (const auto &P : unwrapOrError(Obj->program_headers())) - if (P.p_type == PT_NOTE) - process(P.p_offset, P.p_filesz); + for (const auto &P : unwrapOrError(Obj->program_headers())) { + if (P.p_type != PT_NOTE) + continue; + PrintHeader(P.p_offset, P.p_filesz); + Error Err = Error::success(); + for (const Elf_Nhdr *Note : Obj->notes(P, Err)) + ProcessNote(Note); + if (Err) + error(std::move(Err)); + } } else { - for (const auto &S : unwrapOrError(Obj->sections())) - if (S.sh_type == SHT_NOTE) - process(S.sh_offset, S.sh_size); + for (const auto &S : unwrapOrError(Obj->sections())) { + if (S.sh_type != SHT_NOTE) + continue; + PrintHeader(S.sh_offset, S.sh_size); + Error Err = Error::success(); + for (const Elf_Nhdr *Note : Obj->notes(S, Err)) + ProcessNote(Note); + if (Err) + error(std::move(Err)); + } } }