if (section_names_offset >= elf_size)
        throw Exception("The ELF is truncated (section names string table points after end of file)", ErrorCodes::CANNOT_PARSE_ELF);
    section_names = reinterpret_cast<const char *>(mapped + section_names_offset);
    
    ElfOff program_header_offset = header->e_phoff;
    uint16_t program_header_num_entries = header->e_phnum;
    if (!program_header_offset
        || !program_header_num_entries
        || program_header_offset + program_header_num_entries * sizeof(ElfPhdr) > elf_size)
        throw Exception("The ELF is truncated (program header points after end of file)", ErrorCodes::CANNOT_PARSE_ELF);
    program_headers = reinterpret_cast<const ElfPhdr *>(mapped + program_header_offset);
}
Elf::Section::Section(const ElfShdr & header_, const Elf & elf_)
    : header(header_), elf(elf_)
{
}
bool Elf::iterateSections(std::function<bool(const Section & section, size_t idx)> && pred) const
{
    for (size_t idx = 0; idx < header->e_shnum; ++idx)
    {
        Section section(section_headers[idx], *this);
        
        if (section.header.sh_offset + section.header.sh_size > elf_size)
            continue;
        if (pred(section, idx))
            return true;
    }
    return false;
}
std::optional<Elf::Section> Elf::findSection(std::function<bool(const Section & section, size_t idx)> && pred) const