#include "ELF.h" #include #include #include #include #include #include #include #include using namespace LibELF; ELFFile::ELFFile(std::string_view path) : m_path(path) { m_fd = open(m_path.c_str(), O_RDONLY); if (m_fd == -1) { std::cerr << "Could not open '" << m_path << "': " << std::strerror(errno) << std::endl; return; } if (fstat(m_fd, &m_stat) == -1) { std::cerr << "Could not stat '" << m_path << "': " << std::strerror(errno) << std::endl; return; } void* mmap_addr = mmap(nullptr, m_stat.st_size, PROT_READ, MAP_PRIVATE, m_fd, 0); if (mmap_addr == MAP_FAILED) { std::cerr << "Could not mmap '" << m_path << "': " << std::strerror(errno) << std::endl; return; } m_mmap = reinterpret_cast(mmap_addr); if (!validate_elf_header()) return; m_success = true; } ELFFile::~ELFFile() { if (m_mmap) munmap(m_mmap, m_stat.st_size); m_mmap = nullptr; if (m_fd != -1) close(m_fd); m_fd = -1; } const ElfNativeFileHeader& ELFFile::elf_header() const { return *reinterpret_cast(m_mmap); } bool ELFFile::validate_elf_header() const { if (m_stat.st_size < sizeof(ElfNativeFileHeader)) { std::cerr << m_path << " is too small to be a ELF executable" << std::endl; return false; } const auto& elf_header = this->elf_header(); if ( elf_header.e_ident[EI_MAG0] != ELFMAG0 || elf_header.e_ident[EI_MAG1] != ELFMAG1 || elf_header.e_ident[EI_MAG2] != ELFMAG2 || elf_header.e_ident[EI_MAG3] != ELFMAG3 ) { std::cerr << m_path << " doesn't have an ELF magic number" << std::endl; return false; } #if ARCH(x86_64) if (elf_header.e_ident[EI_CLASS] != ELFCLASS64) #elif ARCH(i686) if (elf_header.e_ident[EI_CLASS] != ELFCLASS32) #endif { std::cerr << m_path << " architecture doesn't match" << std::endl; return false; } if (elf_header.e_ident[EI_DATA] != ELFDATA2LSB) { std::cerr << m_path << " is not in little endian format" << std::endl; return false; } if (elf_header.e_ident[EI_VERSION] != EV_CURRENT) { std::cerr << m_path << " has unsupported version" << std::endl; return false; } if (elf_header.e_type != ET_EXEC) { std::cerr << m_path << " is not an executable ELF file" << std::endl; return false; } return true; } const ElfNativeSectionHeader& ELFFile::section_header(std::size_t index) const { const auto& elf_header = this->elf_header(); assert(index < elf_header.e_shnum); const uint8_t* section_array_start = m_mmap + elf_header.e_shoff; return *reinterpret_cast(section_array_start + index * elf_header.e_shentsize); } std::string_view ELFFile::section_name(const ElfNativeSectionHeader& section_header) const { const auto& elf_header = this->elf_header(); assert(elf_header.e_shstrndx != SHN_UNDEF); const auto& section_string_table = this->section_header(elf_header.e_shstrndx); const char* string_table_start = reinterpret_cast(m_mmap + section_string_table.sh_offset); return string_table_start + section_header.sh_name; } std::optional> ELFFile::find_section(std::string_view name) const { const auto& elf_header = this->elf_header(); for (std::size_t i = 0; i < elf_header.e_shnum; i++) { const auto& section_header = this->section_header(i); auto section_name = this->section_name(section_header); if (section_name != name) continue; return std::span(m_mmap + section_header.sh_offset, section_header.sh_size); } return {}; }