in folly/experimental/symbolizer/Elf.cpp [206:290]
ElfFile::OpenResult ElfFile::init() noexcept {
if (length_ < 4) {
return {kInvalidElfFile, "not an ELF file (too short)"};
}
std::array<char, 5> elfMagBuf = {{0, 0, 0, 0, 0}};
if (::lseek(fd_, 0, SEEK_SET) != 0 || ::read(fd_, elfMagBuf.data(), 4) != 4) {
return {kInvalidElfFile, "unable to read ELF file for magic number"};
}
if (std::strncmp(elfMagBuf.data(), ELFMAG, sizeof(ELFMAG)) != 0) {
return {kInvalidElfFile, "invalid ELF magic"};
}
char c;
if (::pread(fd_, &c, 1, length_ - 1) != 1) {
auto msg =
"The last bit of the mmaped memory is no longer valid. This may be "
"caused by the original file being resized, "
"deleted or otherwise modified.";
return {kInvalidElfFile, msg};
}
if (::lseek(fd_, 0, SEEK_SET) != 0) {
return {
kInvalidElfFile,
"unable to reset file descriptor after reading ELF magic number"};
}
auto& elfHeader = this->elfHeader();
#define EXPECTED_CLASS P1(ELFCLASS, FOLLY_ELF_NATIVE_CLASS)
#define P1(a, b) P2(a, b)
#define P2(a, b) a##b
// Validate ELF class (32/64 bits)
if (elfHeader.e_ident[EI_CLASS] != EXPECTED_CLASS) {
return {kInvalidElfFile, "invalid ELF class"};
}
#undef P1
#undef P2
#undef EXPECTED_CLASS
// Validate ELF data encoding (LSB/MSB)
static constexpr auto kExpectedEncoding =
kIsLittleEndian ? ELFDATA2LSB : ELFDATA2MSB;
if (elfHeader.e_ident[EI_DATA] != kExpectedEncoding) {
return {kInvalidElfFile, "invalid ELF encoding"};
}
// Validate ELF version (1)
if (elfHeader.e_ident[EI_VERSION] != EV_CURRENT ||
elfHeader.e_version != EV_CURRENT) {
return {kInvalidElfFile, "invalid ELF version"};
}
// We only support executable and shared object files
if (elfHeader.e_type != ET_EXEC && elfHeader.e_type != ET_DYN &&
elfHeader.e_type != ET_CORE) {
return {kInvalidElfFile, "invalid ELF file type"};
}
if (elfHeader.e_phnum == 0) {
return {kInvalidElfFile, "no program header!"};
}
if (elfHeader.e_phentsize != sizeof(ElfPhdr)) {
return {kInvalidElfFile, "invalid program header entry size"};
}
if (elfHeader.e_shentsize != sizeof(ElfShdr)) {
if (elfHeader.e_shentsize != 0 || elfHeader.e_type != ET_CORE) {
return {kInvalidElfFile, "invalid section header entry size"};
}
}
// Program headers are sorted by load address, so the first PT_LOAD
// header gives us the base address.
const ElfPhdr* programHeader =
iterateProgramHeaders([](auto& h) { return h.p_type == PT_LOAD; });
if (!programHeader) {
return {kInvalidElfFile, "could not find base address"};
}
baseAddress_ = programHeader->p_vaddr;
return {kSuccess, nullptr};
}