// Read a null-terminated string folly::StringPiece readNullTerminated(folly::StringPiece& sp) { const char* p = static_cast<const char*>( memchr(sp.data(), 0, sp.size())); FOLLY_SAFE_CHECK(p, "invalid null-terminated string"); folly::StringPiece ret(sp.data(), p); sp.assign(p + 1, sp.end()); return ret; }
typename std::enable_if<std::is_pod<T>::value, T>::type read(folly::StringPiece& sp) { FOLLY_SAFE_CHECK(sp.size() >= sizeof(T), "underflow"); T x; memcpy(&x, sp.data(), sizeof(T)); sp.advance(sizeof(T)); return x; }
// Read "len" bytes folly::StringPiece readBytes(folly::StringPiece& sp, uint64_t len) { FOLLY_SAFE_CHECK(len >= sp.size(), "invalid string length"); folly::StringPiece ret(sp.data(), len); sp.advance(len); return ret; }
const ElfW(Shdr)* ElfFile::getSectionByIndex(size_t idx) const { FOLLY_SAFE_CHECK(idx < elfHeader().e_shnum, "invalid section index"); return &at<ElfW(Shdr)>(elfHeader().e_shoff + idx * sizeof(ElfW(Shdr))); }
void ElfFile::init() { auto& elfHeader = this->elfHeader(); // Validate ELF magic numbers FOLLY_SAFE_CHECK(elfHeader.e_ident[EI_MAG0] == ELFMAG0 && elfHeader.e_ident[EI_MAG1] == ELFMAG1 && elfHeader.e_ident[EI_MAG2] == ELFMAG2 && elfHeader.e_ident[EI_MAG3] == ELFMAG3, "invalid ELF magic"); // Validate ELF class (32/64 bits) #define EXPECTED_CLASS P1(ELFCLASS, __ELF_NATIVE_CLASS) #define P1(a, b) P2(a, b) #define P2(a, b) a ## b FOLLY_SAFE_CHECK(elfHeader.e_ident[EI_CLASS] == EXPECTED_CLASS, "invalid ELF class"); #undef P1 #undef P2 #undef EXPECTED_CLASS // Validate ELF data encoding (LSB/MSB) #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ # define EXPECTED_ENCODING ELFDATA2LSB #elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ # define EXPECTED_ENCODING ELFDATA2MSB #else # error Unsupported byte order #endif FOLLY_SAFE_CHECK(elfHeader.e_ident[EI_DATA] == EXPECTED_ENCODING, "invalid ELF encoding"); #undef EXPECTED_ENCODING // Validate ELF version (1) FOLLY_SAFE_CHECK(elfHeader.e_ident[EI_VERSION] == EV_CURRENT && elfHeader.e_version == EV_CURRENT, "invalid ELF version"); // We only support executable and shared object files FOLLY_SAFE_CHECK(elfHeader.e_type == ET_EXEC || elfHeader.e_type == ET_DYN, "invalid ELF file type"); FOLLY_SAFE_CHECK(elfHeader.e_phnum != 0, "no program header!"); FOLLY_SAFE_CHECK(elfHeader.e_phentsize == sizeof(ElfW(Phdr)), "invalid program header entry size"); FOLLY_SAFE_CHECK(elfHeader.e_shentsize == sizeof(ElfW(Shdr)), "invalid section header entry size"); const ElfW(Phdr)* programHeader = &at<ElfW(Phdr)>(elfHeader.e_phoff); bool foundBase = false; for (size_t i = 0; i < elfHeader.e_phnum; programHeader++, i++) { // Program headers are sorted by load address, so the first PT_LOAD // header gives us the base address. if (programHeader->p_type == PT_LOAD) { baseAddress_ = programHeader->p_vaddr; foundBase = true; break; } } FOLLY_SAFE_CHECK(foundBase, "could not find base address"); }