forked from OSchip/llvm-project
[llvm-readobj][ELF] Move ELF note parsing into libObject
Clean up the parsing of notes in llvm-readobj, improve bounds checking, and allow the parsing code to be reused. Differential Revision: https://reviews.llvm.org/D43958 llvm-svn: 327320
This commit is contained in:
parent
cd4f385795
commit
77a5f21f0e
|
@ -1483,6 +1483,20 @@ struct Elf64_Chdr {
|
|||
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.
|
||||
|
|
|
@ -67,6 +67,9 @@ public:
|
|||
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_Note = typename ELFT::Note;
|
||||
using Elf_Note_Iterator = typename ELFT::NoteIterator;
|
||||
using Elf_Dyn_Range = typename ELFT::DynRange;
|
||||
using Elf_Shdr_Range = typename ELFT::ShdrRange;
|
||||
using Elf_Sym_Range = typename ELFT::SymRange;
|
||||
|
@ -155,6 +158,73 @@ public:
|
|||
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_Note_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_Note_Iterator(Err);
|
||||
}
|
||||
if (Phdr.p_offset + Phdr.p_filesz > getBufSize()) {
|
||||
Err = createError("invalid program header offset/size");
|
||||
return Elf_Note_Iterator(Err);
|
||||
}
|
||||
return Elf_Note_Iterator(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_Note_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_Note_Iterator(Err);
|
||||
}
|
||||
if (Shdr.sh_offset + Shdr.sh_size > getBufSize()) {
|
||||
Err = createError("invalid section offset/size");
|
||||
return Elf_Note_Iterator(Err);
|
||||
}
|
||||
return Elf_Note_Iterator(base() + Shdr.sh_offset, Shdr.sh_size, Err);
|
||||
}
|
||||
|
||||
/// Get the end iterator for notes.
|
||||
Elf_Note_Iterator notes_end() const {
|
||||
return Elf_Note_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<Elf_Note_Iterator> 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<Elf_Note_Iterator> notes(const Elf_Shdr &Shdr,
|
||||
Error &Err) const {
|
||||
return make_range(notes_begin(Shdr, Err), notes_end());
|
||||
}
|
||||
|
||||
Expected<StringRef> getSectionStringTable(Elf_Shdr_Range Sections) const;
|
||||
Expected<uint32_t> getSectionIndex(const Elf_Sym *Sym, Elf_Sym_Range Syms,
|
||||
ArrayRef<Elf_Word> ShndxTable) const;
|
||||
|
|
|
@ -40,6 +40,9 @@ template <class ELFT> struct Elf_Versym_Impl;
|
|||
template <class ELFT> struct Elf_Hash_Impl;
|
||||
template <class ELFT> struct Elf_GnuHash_Impl;
|
||||
template <class ELFT> struct Elf_Chdr_Impl;
|
||||
template <class ELFT> struct Elf_Nhdr_Impl;
|
||||
template <class ELFT> class Elf_Note_Impl;
|
||||
template <class ELFT> class Elf_Note_Iterator_Impl;
|
||||
|
||||
template <endianness E, bool Is64> struct ELFType {
|
||||
private:
|
||||
|
@ -66,6 +69,9 @@ public:
|
|||
using Hash = Elf_Hash_Impl<ELFType<E, Is64>>;
|
||||
using GnuHash = Elf_GnuHash_Impl<ELFType<E, Is64>>;
|
||||
using Chdr = Elf_Chdr_Impl<ELFType<E, Is64>>;
|
||||
using Nhdr = Elf_Nhdr_Impl<ELFType<E, Is64>>;
|
||||
using Note = Elf_Note_Impl<ELFType<E, Is64>>;
|
||||
using NoteIterator = Elf_Note_Iterator_Impl<ELFType<E, Is64>>;
|
||||
using DynRange = ArrayRef<Dyn>;
|
||||
using ShdrRange = ArrayRef<Shdr>;
|
||||
using SymRange = ArrayRef<Sym>;
|
||||
|
@ -551,6 +557,127 @@ struct Elf_Chdr_Impl<ELFType<TargetEndianness, true>> {
|
|||
Elf_Xword ch_addralign;
|
||||
};
|
||||
|
||||
/// Note header
|
||||
template <class ELFT>
|
||||
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 size of the note, including name, descriptor, and padding.
|
||||
size_t getSize() const {
|
||||
return sizeof(*this) + alignTo<Align>(n_namesz) + alignTo<Align>(n_descsz);
|
||||
}
|
||||
};
|
||||
|
||||
/// An ELF note.
|
||||
///
|
||||
/// Wraps a note header, providing methods for accessing the name and
|
||||
/// descriptor safely.
|
||||
template <class ELFT>
|
||||
class Elf_Note_Impl {
|
||||
LLVM_ELF_IMPORT_TYPES_ELFT(ELFT)
|
||||
|
||||
const Elf_Nhdr_Impl<ELFT> &Nhdr;
|
||||
|
||||
template <class NoteIteratorELFT> friend class Elf_Note_Iterator_Impl;
|
||||
|
||||
Elf_Note_Impl(const Elf_Nhdr_Impl<ELFT> &Nhdr) : Nhdr(Nhdr) {}
|
||||
|
||||
public:
|
||||
/// Get the note's name, excluding the terminating null byte.
|
||||
StringRef getName() const {
|
||||
if (!Nhdr.n_namesz)
|
||||
return StringRef();
|
||||
return StringRef(reinterpret_cast<const char *>(&Nhdr) + sizeof(Nhdr),
|
||||
Nhdr.n_namesz - 1);
|
||||
}
|
||||
|
||||
/// Get the note's descriptor.
|
||||
ArrayRef<Elf_Word> getDesc() const {
|
||||
if (!Nhdr.n_descsz)
|
||||
return ArrayRef<Elf_Word>();
|
||||
return ArrayRef<Elf_Word>(
|
||||
reinterpret_cast<const Elf_Word *>(
|
||||
reinterpret_cast<const uint8_t *>(&Nhdr) + sizeof(Nhdr) +
|
||||
alignTo<Elf_Nhdr_Impl<ELFT>::Align>(Nhdr.n_namesz)),
|
||||
Nhdr.n_descsz);
|
||||
}
|
||||
|
||||
/// Get the note's type.
|
||||
Elf_Word getType() const { return Nhdr.n_type; }
|
||||
};
|
||||
|
||||
template <class ELFT>
|
||||
class Elf_Note_Iterator_Impl
|
||||
: std::iterator<std::forward_iterator_tag, Elf_Note_Impl<ELFT>> {
|
||||
// Nhdr being a nullptr marks the end of iteration.
|
||||
const Elf_Nhdr_Impl<ELFT> *Nhdr = nullptr;
|
||||
size_t RemainingSize = 0u;
|
||||
Error *Err = nullptr;
|
||||
|
||||
template <class ELFFileELFT> friend class ELFFile;
|
||||
|
||||
// Stop iteration and indicate an overflow.
|
||||
void stopWithOverflowError() {
|
||||
Nhdr = nullptr;
|
||||
*Err = make_error<StringError>("ELF note overflows container",
|
||||
object_error::parse_failed);
|
||||
}
|
||||
|
||||
// Advance Nhdr by NoteSize bytes, starting from NhdrPos.
|
||||
//
|
||||
// Assumes NoteSize <= RemainingSize. Ensures Nhdr->getSize() <= RemainingSize
|
||||
// upon returning. Handles stopping iteration when reaching the end of the
|
||||
// container, either cleanly or with an overflow error.
|
||||
void advanceNhdr(const uint8_t *NhdrPos, size_t NoteSize) {
|
||||
RemainingSize -= NoteSize;
|
||||
if (RemainingSize == 0u)
|
||||
Nhdr = nullptr;
|
||||
else if (sizeof(*Nhdr) > RemainingSize)
|
||||
stopWithOverflowError();
|
||||
else {
|
||||
Nhdr = reinterpret_cast<const Elf_Nhdr_Impl<ELFT> *>(NhdrPos + NoteSize);
|
||||
if (Nhdr->getSize() > RemainingSize)
|
||||
stopWithOverflowError();
|
||||
}
|
||||
}
|
||||
|
||||
Elf_Note_Iterator_Impl() {}
|
||||
explicit Elf_Note_Iterator_Impl(Error &Err) : Err(&Err) {}
|
||||
Elf_Note_Iterator_Impl(const uint8_t *Start, size_t Size, Error &Err)
|
||||
: RemainingSize(Size), Err(&Err) {
|
||||
assert(Start && "ELF note iterator starting at NULL");
|
||||
advanceNhdr(Start, 0u);
|
||||
}
|
||||
|
||||
public:
|
||||
Elf_Note_Iterator_Impl &operator++() {
|
||||
assert(Nhdr && "incremented ELF note end iterator");
|
||||
const uint8_t *NhdrPos = reinterpret_cast<const uint8_t *>(Nhdr);
|
||||
size_t NoteSize = Nhdr->getSize();
|
||||
advanceNhdr(NhdrPos, NoteSize);
|
||||
return *this;
|
||||
}
|
||||
bool operator==(Elf_Note_Iterator_Impl Other) const {
|
||||
return Nhdr == Other.Nhdr;
|
||||
}
|
||||
bool operator!=(Elf_Note_Iterator_Impl Other) const {
|
||||
return !(*this == Other);
|
||||
}
|
||||
Elf_Note_Impl<ELFT> operator*() const {
|
||||
assert(Nhdr && "dereferenced ELF note end iterator");
|
||||
return Elf_Note_Impl<ELFT>(*Nhdr);
|
||||
}
|
||||
};
|
||||
|
||||
// MIPS .reginfo section
|
||||
template <class ELFT>
|
||||
struct Elf_Mips_RegInfo;
|
||||
|
|
|
@ -93,6 +93,7 @@ using namespace ELF;
|
|||
using Elf_Word = typename ELFT::Word; \
|
||||
using Elf_Hash = typename ELFT::Hash; \
|
||||
using Elf_GnuHash = typename ELFT::GnuHash; \
|
||||
using Elf_Note = typename ELFT::Note; \
|
||||
using Elf_Sym_Range = typename ELFT::SymRange; \
|
||||
using Elf_Versym = typename ELFT::Versym; \
|
||||
using Elf_Verneed = typename ELFT::Verneed; \
|
||||
|
@ -3540,62 +3541,57 @@ void GNUStyle<ELFT>::printNotes(const ELFFile<ELFT> *Obj) {
|
|||
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<const uint8_t *>(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<const Elf_Word *>(&P[0]);
|
||||
auto ProcessNote = [&](const Elf_Note &Note) {
|
||||
StringRef Name = Note.getName();
|
||||
ArrayRef<Elf_Word> Descriptor = Note.getDesc();
|
||||
Elf_Word Type = Note.getType();
|
||||
|
||||
uint32_t NameSize = Words[0];
|
||||
uint32_t DescriptorSize = Words[1];
|
||||
uint32_t Type = Words[2];
|
||||
OS << " " << Name << std::string(22 - Name.size(), ' ')
|
||||
<< format_hex(Descriptor.size(), 10) << '\t';
|
||||
|
||||
ArrayRef<Elf_Word> Descriptor(&Words[3 + (alignTo<4>(NameSize) / 4)],
|
||||
alignTo<4>(DescriptorSize) / 4);
|
||||
|
||||
StringRef Name;
|
||||
if (NameSize)
|
||||
Name =
|
||||
StringRef(reinterpret_cast<const char *>(&Words[3]), NameSize - 1);
|
||||
|
||||
OS << " " << Name << std::string(22 - NameSize, ' ')
|
||||
<< format_hex(DescriptorSize, 10) << '\t';
|
||||
|
||||
if (Name == "GNU") {
|
||||
OS << getGNUNoteTypeName(Type) << '\n';
|
||||
printGNUNote<ELFT>(OS, Type, Descriptor, DescriptorSize);
|
||||
} else if (Name == "FreeBSD") {
|
||||
OS << getFreeBSDNoteTypeName(Type) << '\n';
|
||||
} else if (Name == "AMD") {
|
||||
OS << getAMDGPUNoteTypeName(Type) << '\n';
|
||||
printAMDGPUNote<ELFT>(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);
|
||||
if (Name == "GNU") {
|
||||
OS << getGNUNoteTypeName(Type) << '\n';
|
||||
printGNUNote<ELFT>(OS, Type, Descriptor, Descriptor.size());
|
||||
} else if (Name == "FreeBSD") {
|
||||
OS << getFreeBSDNoteTypeName(Type) << '\n';
|
||||
} else if (Name == "AMD") {
|
||||
OS << getAMDGPUNoteTypeName(Type) << '\n';
|
||||
printAMDGPUNote<ELFT>(OS, Type, Descriptor, Descriptor.size());
|
||||
} else {
|
||||
OS << "Unknown note type: (" << format_hex(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 auto &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 auto &Note : Obj->notes(S, Err))
|
||||
ProcessNote(Note);
|
||||
if (Err)
|
||||
error(std::move(Err));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue