Back to index

enigmail  1.4.3
Public Member Functions | Private Attributes
Elf Class Reference

#include <elfxx.h>

Collaboration diagram for Elf:
Collaboration graph
[legend]

List of all members.

Public Member Functions

 Elf (std::ifstream &file)
 ~Elf ()
ElfSectiongetSection (int index)
ElfSectiongetSectionAt (unsigned int offset)
ElfSegmentgetSegmentByType (unsigned int type)
ElfDynamic_SectiongetDynSection ()
void write (std::ofstream &file)
char getClass ()
char getData ()
char getType ()
char getMachine ()
unsigned int getSize ()

Private Attributes

Elf_Ehdrehdr
ElfLocation eh_entry
ElfStrtab_Sectioneh_shstrndx
ElfSection ** sections
std::vector< ElfSegment * > segments
ElfSectionshdr_section
ElfSectionphdr_section
Elf_Shdr ** tmp_shdr
std::ifstream * tmp_file

Detailed Description

Definition at line 291 of file elfxx.h.


Constructor & Destructor Documentation

Elf::Elf ( std::ifstream &  file)

Definition at line 147 of file elf.cpp.

{
    if (!file.is_open())
        throw std::runtime_error("Error opening file");

    file.exceptions(std::ifstream::eofbit | std::ifstream::failbit | std::ifstream::badbit);
    // Read ELF magic number and identification information
    char e_ident[EI_VERSION];
    file.seekg(0);
    file.read(e_ident, sizeof(e_ident));
    file.seekg(0);
    ehdr = new Elf_Ehdr(file, e_ident[EI_CLASS], e_ident[EI_DATA]);

    // ELFOSABI_LINUX is kept unsupported because I haven't looked whether
    // STB_GNU_UNIQUE or STT_GNU_IFUNC would need special casing.
    if ((ehdr->e_ident[EI_OSABI] != ELFOSABI_NONE) && (ehdr->e_ident[EI_ABIVERSION] != 0))
        throw std::runtime_error("unsupported ELF ABI");

    if (ehdr->e_version != 1)
        throw std::runtime_error("unsupported ELF version");

    // Sanity checks
    if (ehdr->e_shnum == 0)
        throw std::runtime_error("sstripped ELF files aren't supported");

    if (ehdr->e_ehsize != Elf_Ehdr::size(e_ident[EI_CLASS]))
        throw std::runtime_error("unsupported ELF inconsistency: ehdr.e_ehsize != sizeof(ehdr)");

    if (ehdr->e_shentsize != Elf_Shdr::size(e_ident[EI_CLASS]))
        throw std::runtime_error("unsupported ELF inconsistency: ehdr.e_shentsize != sizeof(shdr)");

    if (ehdr->e_phnum == 0) {
        if (ehdr->e_phoff != 0)
            throw std::runtime_error("unsupported ELF inconsistency: e_phnum == 0 && e_phoff != 0");
        if (ehdr->e_phentsize != 0)
            throw std::runtime_error("unsupported ELF inconsistency: e_phnum == 0 && e_phentsize != 0");
    } else if (ehdr->e_phoff != ehdr->e_ehsize)
        throw std::runtime_error("unsupported ELF inconsistency: ehdr->e_phoff != ehdr->e_ehsize");
    else if (ehdr->e_phentsize != Elf_Phdr::size(e_ident[EI_CLASS]))
        throw std::runtime_error("unsupported ELF inconsistency: ehdr->e_phentsize != sizeof(phdr)");

    // Read section headers
    Elf_Shdr **shdr = new Elf_Shdr *[ehdr->e_shnum];
    file.seekg(ehdr->e_shoff);
    for (int i = 0; i < ehdr->e_shnum; i++)
        shdr[i] = new Elf_Shdr(file, e_ident[EI_CLASS], e_ident[EI_DATA]);

    // Sanity check in section header for index 0
    if ((shdr[0]->sh_name != 0) || (shdr[0]->sh_type != SHT_NULL) ||
        (shdr[0]->sh_flags != 0) || (shdr[0]->sh_addr != 0) ||
        (shdr[0]->sh_offset != 0) || (shdr[0]->sh_size != 0) ||
        (shdr[0]->sh_link != SHN_UNDEF) || (shdr[0]->sh_info != 0) ||
        (shdr[0]->sh_addralign != 0) || (shdr[0]->sh_entsize != 0))
        throw std::runtime_error("Section header for index 0 contains unsupported values");

    if ((shdr[ehdr->e_shstrndx]->sh_link != 0) || (shdr[ehdr->e_shstrndx]->sh_info != 0))
        throw std::runtime_error("unsupported ELF content: string table with sh_link != 0 || sh_info != 0");

    // Store these temporarily
    tmp_shdr = shdr;
    tmp_file = &file;

    // Fill sections list
    sections = new ElfSection *[ehdr->e_shnum];
    for (int i = 0; i < ehdr->e_shnum; i++)
        sections[i] = NULL;
    for (int i = 1; i < ehdr->e_shnum; i++) {
        if (sections[i] != NULL)
            continue;
        getSection(i);
    }
    Elf_Shdr s;
    s.sh_name = 0;
    s.sh_type = SHT_NULL;
    s.sh_flags = 0;
    s.sh_addr = 0;
    s.sh_offset = ehdr->e_shoff;
    s.sh_entsize = Elf_Shdr::size(e_ident[EI_CLASS]);
    s.sh_size = s.sh_entsize * ehdr->e_shnum;
    s.sh_link = 0;
    s.sh_info = 0;
    s.sh_addralign = (e_ident[EI_CLASS] == ELFCLASS32) ? 4 : 8;
    shdr_section = new ElfSection(s, NULL, NULL);

    // Fake section for program headers
    s.sh_offset = ehdr->e_phoff;
    s.sh_addr = ehdr->e_phoff;
    s.sh_entsize = Elf_Phdr::size(e_ident[EI_CLASS]);
    s.sh_size = s.sh_entsize * ehdr->e_phnum;
    phdr_section = new ElfSection(s, NULL, NULL);

    phdr_section->insertAfter(ehdr, false);

    sections[1]->insertAfter(phdr_section, false);
    for (int i = 2; i < ehdr->e_shnum; i++) {
        // TODO: this should be done in a better way
        if ((shdr_section->getPrevious() == NULL) && (shdr[i]->sh_offset > ehdr->e_shoff)) {
            shdr_section->insertAfter(sections[i - 1], false);
            sections[i]->insertAfter(shdr_section, false);
        } else
            sections[i]->insertAfter(sections[i - 1], false);
    }
    if (shdr_section->getPrevious() == NULL)
        shdr_section->insertAfter(sections[ehdr->e_shnum - 1], false);

    tmp_file = NULL;
    tmp_shdr = NULL;
    for (int i = 0; i < ehdr->e_shnum; i++)
        delete shdr[i];
    delete[] shdr;

    eh_shstrndx = (ElfStrtab_Section *)sections[ehdr->e_shstrndx];

    // Skip reading program headers if there aren't any
    if (ehdr->e_phnum == 0)
        return;

    // Read program headers
    file.seekg(ehdr->e_phoff);
    for (int i = 0; i < ehdr->e_phnum; i++) {
        Elf_Phdr phdr(file, e_ident[EI_CLASS], e_ident[EI_DATA]);
        if (phdr.p_type == PT_LOAD) {
            // Default alignment for PT_LOAD on x86-64 prevents elfhack from
            // doing anything useful. However, the system doesn't actually
            // require such a big alignment, so in order for elfhack to work
            // efficiently, reduce alignment when it's originally the default
            // one.
            if ((ehdr->e_machine == EM_X86_64) && (phdr.p_align == 0x200000))
              phdr.p_align = 0x1000;
        }
        ElfSegment *segment = new ElfSegment(&phdr);
        // Some segments aren't entirely filled (if at all) by sections
        // For those, we use fake sections
        if ((phdr.p_type == PT_LOAD) && (phdr.p_offset == 0)) {
            // Use a fake section for ehdr and phdr
            ehdr->getShdr().sh_addr = phdr.p_vaddr;
            phdr_section->getShdr().sh_addr += phdr.p_vaddr;
            segment->addSection(ehdr);
            segment->addSection(phdr_section);
        }
        if (phdr.p_type == PT_PHDR)
            segment->addSection(phdr_section);
        for (int j = 1; j < ehdr->e_shnum; j++)
            if (phdr.contains(sections[j]))
                segment->addSection(sections[j]);
        // Make sure that our view of segments corresponds to the original
        // ELF file.
        assert(segment->getFileSize() == phdr.p_filesz);
        assert(segment->getMemSize() == phdr.p_memsz);
        segments.push_back(segment);
    }

    new (&eh_entry) ElfLocation(ehdr->e_entry, this);
}

Here is the call graph for this function:

Elf::~Elf ( )

Definition at line 302 of file elf.cpp.

{
    for (std::vector<ElfSegment *>::iterator seg = segments.begin(); seg != segments.end(); seg++)
        delete *seg;
    delete[] sections;
    ElfSection *section = ehdr;
    while (section != NULL) {
        ElfSection *next = section->getNext();
        delete section;
        section = next;
    }
}

Here is the call graph for this function:


Member Function Documentation

char Elf::getClass ( ) [inline]

Definition at line 633 of file elfxx.h.

                          {
    return ehdr->e_ident[EI_CLASS];
}

Here is the caller graph for this function:

char Elf::getData ( ) [inline]

Definition at line 637 of file elfxx.h.

                         {
    return ehdr->e_ident[EI_DATA];
}

Here is the caller graph for this function:

Definition at line 373 of file elf.cpp.

{
    for (std::vector<ElfSegment *>::iterator seg = segments.begin(); seg != segments.end(); seg++)
        if (((*seg)->getType() == PT_DYNAMIC) && ((*seg)->getFirstSection() != NULL) &&
            (*seg)->getFirstSection()->getType() == SHT_DYNAMIC)
            return (ElfDynamic_Section *)(*seg)->getFirstSection();

    return NULL;
}

Here is the caller graph for this function:

char Elf::getMachine ( ) [inline]

Definition at line 645 of file elfxx.h.

                            {
    return ehdr->e_machine;
}

Here is the caller graph for this function:

ElfSection * Elf::getSection ( int  index)

Definition at line 316 of file elf.cpp.

{
    if ((index < -1) || (index >= ehdr->e_shnum))
        throw std::runtime_error("Section index out of bounds");
    if (index == -1)
        index = ehdr->e_shstrndx; // TODO: should be fixed to use the actual current number
    // Special case: the section at index 0 is void
    if (index == 0)
        return NULL;
    // Infinite recursion guard
    if (sections[index] == (ElfSection *)this)
        return NULL;
    if (sections[index] == NULL) {
        sections[index] = (ElfSection *)this;
        switch (tmp_shdr[index]->sh_type) {
        case SHT_DYNAMIC:
            sections[index] = new ElfDynamic_Section(*tmp_shdr[index], tmp_file, this);
            break;
        case SHT_REL:
            sections[index] = new ElfRel_Section<Elf_Rel>(*tmp_shdr[index], tmp_file, this);
            break;
        case SHT_RELA:
            sections[index] = new ElfRel_Section<Elf_Rela>(*tmp_shdr[index], tmp_file, this);
            break;
        case SHT_DYNSYM:
        case SHT_SYMTAB:
            sections[index] = new ElfSymtab_Section(*tmp_shdr[index], tmp_file, this);
            break;
        case SHT_STRTAB:
            sections[index] = new ElfStrtab_Section(*tmp_shdr[index], tmp_file, this);
            break;
        default:
            sections[index] = new ElfSection(*tmp_shdr[index], tmp_file, this);
        }
    }
    return sections[index];
}

Here is the caller graph for this function:

ElfSection * Elf::getSectionAt ( unsigned int  offset)

Definition at line 354 of file elf.cpp.

{
    for (int i = 1; i < ehdr->e_shnum; i++) {
        ElfSection *section = getSection(i);
        if ((section != NULL) && (section->getFlags() & SHF_ALLOC) && !(section->getFlags() & SHF_TLS) &&
            (offset >= section->getAddr()) && (offset < section->getAddr() + section->getSize()))
            return section;
    }
    return NULL;
}

Here is the call graph for this function:

Here is the caller graph for this function:

ElfSegment * Elf::getSegmentByType ( unsigned int  type)

Definition at line 365 of file elf.cpp.

{
    for (std::vector<ElfSegment *>::iterator seg = segments.begin(); seg != segments.end(); seg++)
        if ((*seg)->getType() == type)
            return *seg;
    return NULL;
}

Here is the caller graph for this function:

unsigned int Elf::getSize ( ) [inline]

Definition at line 649 of file elfxx.h.

                                 {
    ElfSection *section;
    for (section = shdr_section /* It's usually not far from the end */;
        section->getNext() != NULL; section = section->getNext());
    return section->getOffset() + section->getSize();
}

Here is the call graph for this function:

Here is the caller graph for this function:

char Elf::getType ( ) [inline]

Definition at line 641 of file elfxx.h.

                         {
    return ehdr->e_type;
}

Here is the caller graph for this function:

void Elf::write ( std::ofstream &  file)

Definition at line 383 of file elf.cpp.

{
    // fixup section headers sh_name; TODO: that should be done by sections
    // themselves
    for (ElfSection *section = ehdr; section != NULL; section = section->getNext()) {
        if (section->getIndex() == 0)
            continue;
        else
            ehdr->e_shnum = section->getIndex() + 1;
        section->getShdr().sh_name = eh_shstrndx->getStrIndex(section->getName());
    }
    ehdr->markDirty();
    // Adjust PT_LOAD segments
    int i = 0;
    for (std::vector<ElfSegment *>::iterator seg = segments.begin(); seg != segments.end(); seg++, i++) {
        if ((*seg)->getType() == PT_LOAD) {
            std::list<ElfSection *>::iterator it = (*seg)->begin();
            for (ElfSection *last = *(it++); it != (*seg)->end(); last = *(it++)) {
               if (((*it)->getType() != SHT_NOBITS) &&
                   ((*it)->getAddr() - last->getAddr()) != ((*it)->getOffset() - last->getOffset())) {
                   std::vector<ElfSegment *>::iterator next = seg;
                   segments.insert(++next, (*seg)->splitBefore(*it));
                   seg = segments.begin() + i;
                   break;
               }
           }
        }
    }
    // fixup ehdr before writing
    if (ehdr->e_phnum != segments.size()) {
        ehdr->e_phnum = segments.size();
        phdr_section->getShdr().sh_size = segments.size() * Elf_Phdr::size(ehdr->e_ident[EI_CLASS]);
        phdr_section->getNext()->markDirty();
    }
    // fixup shdr before writing
    if (ehdr->e_shnum != shdr_section->getSize() / shdr_section->getEntSize())
        shdr_section->getShdr().sh_size = ehdr->e_shnum * Elf_Shdr::size(ehdr->e_ident[EI_CLASS]);
    ehdr->e_shoff = shdr_section->getOffset();
    ehdr->e_entry = eh_entry.getValue();
    ehdr->e_shstrndx = eh_shstrndx->getIndex();
    for (ElfSection *section = ehdr;
         section != NULL; section = section->getNext()) {
        file.seekp(section->getOffset());
        if (section == phdr_section) {
            for (std::vector<ElfSegment *>::iterator seg = segments.begin(); seg != segments.end(); seg++) {
                Elf_Phdr phdr;
                phdr.p_type = (*seg)->getType();
                phdr.p_flags = (*seg)->getFlags();
                phdr.p_offset = (*seg)->getOffset();
                phdr.p_vaddr = (*seg)->getAddr();
                phdr.p_paddr = phdr.p_vaddr + (*seg)->getVPDiff();
                phdr.p_filesz = (*seg)->getFileSize();
                phdr.p_memsz = (*seg)->getMemSize();
                phdr.p_align = (*seg)->getAlign();
                phdr.serialize(file, ehdr->e_ident[EI_CLASS], ehdr->e_ident[EI_DATA]);
            }
        } else if (section == shdr_section) {
            null_section.serialize(file, ehdr->e_ident[EI_CLASS], ehdr->e_ident[EI_DATA]);
            for (ElfSection *sec = ehdr; sec!= NULL; sec = sec->getNext()) {
                if (sec->getType() != SHT_NULL)
                    sec->getShdr().serialize(file, ehdr->e_ident[EI_CLASS], ehdr->e_ident[EI_DATA]);
            }
        } else
           section->serialize(file, ehdr->e_ident[EI_CLASS], ehdr->e_ident[EI_DATA]);
    }
}

Here is the call graph for this function:

Here is the caller graph for this function:


Member Data Documentation

Definition at line 314 of file elfxx.h.

Definition at line 315 of file elfxx.h.

Elf_Ehdr* Elf::ehdr [private]

Definition at line 313 of file elfxx.h.

Definition at line 318 of file elfxx.h.

Definition at line 316 of file elfxx.h.

std::vector<ElfSegment *> Elf::segments [private]

Definition at line 317 of file elfxx.h.

Definition at line 318 of file elfxx.h.

std::ifstream* Elf::tmp_file [private]

Definition at line 321 of file elfxx.h.

Elf_Shdr** Elf::tmp_shdr [private]

Definition at line 320 of file elfxx.h.


The documentation for this class was generated from the following files: