Exemplo n.º 1
0
/** Pre-unparsing updates */
bool
SgAsmElfSegmentTable::reallocate()
{
    bool reallocated = false;

    /* Resize based on word size from ELF File Header */
    size_t opt_size, nentries;
    rose_addr_t need = calculate_sizes(NULL, NULL, &opt_size, &nentries);
    if (need < get_size()) {
        if (is_mapped()) {
            ROSE_ASSERT(get_mapped_size()==get_size());
            set_mapped_size(need);
        }
        set_size(need);
        reallocated = true;
    } else if (need > get_size()) {
        get_file()->shift_extend(this, 0, need-get_size(), SgAsmGenericFile::ADDRSP_ALL, SgAsmGenericFile::ELASTIC_HOLE);
        reallocated = true;
    }

    /* Update data members in the ELF File Header. No need to return true for these changes. */
    SgAsmElfFileHeader *fhdr = dynamic_cast<SgAsmElfFileHeader*>(get_header());
    fhdr->set_phextrasz(opt_size);
    fhdr->set_e_phnum(nentries);

    return reallocated;
}
Exemplo n.º 2
0
rose_addr_t
SgAsmElfSection::calculate_sizes(size_t r32size, size_t r64size,       /*size of required parts*/
                                 const std::vector<size_t> &optsizes,  /*size of optional parts and number of parts parsed*/
                                 size_t *entsize, size_t *required, size_t *optional, size_t *entcount) const
{
    size_t struct_size = 0;
    size_t extra_size = 0;
    size_t entry_size = 0;
    size_t nentries = 0;
    SgAsmElfFileHeader *fhdr = get_elf_header();

    /* Assume ELF Section Table Entry is correct for now for the size of each entry in the table. */
    ROSE_ASSERT(get_section_entry()!=NULL);
    entry_size = get_section_entry()->get_sh_entsize();

    /* Size of required part of each entry */
    if (0==r32size && 0==r64size) {
        /* Probably called by four-argument SgAsmElfSection::calculate_sizes and we don't know the sizes of the required parts
         * because there isn't a parser for this type of section, or the section doesn't contain a table. In the latter case
         * the ELF Section Table has a zero sh_entsize and we'll treat the section as if it were a table with one huge entry.
         * Otherwise we'll assume that the struct size is the same as the sh_entsize and there's no optional data. */
        struct_size = entry_size>0 ? entry_size : get_size();
    } else if (4==fhdr->get_word_size()) {
        struct_size = r32size;
    } else if (8==fhdr->get_word_size()) {
        struct_size = r64size;
    } else {
        throw FormatError("bad ELF word size");
    }

    /* Entire entry should be at least large enough for the required part. This also takes care of the case when the ELF
     * Section Table Entry has a zero-valued sh_entsize */
    entry_size = std::max(entry_size, struct_size);

    /* Size of optional parts. If we've parsed the table then use the largest optional part, otherwise assume the entry from
     * the ELF Section Table is correct. */
    nentries = optsizes.size();
    if (nentries>0) {
        for (size_t i=0; i<nentries; i++) {
            extra_size = std::max(extra_size, optsizes[i]);
        }
        entry_size = std::min(entry_size, struct_size+extra_size);
    } else {
        extra_size = entry_size - struct_size;
        nentries = entry_size>0 ? get_size() / entry_size : 0;
    }

    /* Return values */
    if (entsize)
        *entsize = entry_size;
    if (required)
        *required = struct_size;
    if (optional)
        *optional = extra_size;
    if (entcount)
        *entcount = nentries;
    return entry_size * nentries;
}
Exemplo n.º 3
0
void
SgAsmElfRelocSection::unparse(std::ostream &f) const
{
    SgAsmElfFileHeader *fhdr = get_elf_header();
    ROSE_ASSERT(fhdr);
    ByteOrder::Endianness sex = fhdr->get_sex();

    size_t entry_size, struct_size, extra_size, nentries;
    calculate_sizes(&entry_size, &struct_size, &extra_size, &nentries);

    /* Adjust the entry size stored in the ELF Section Table */
    get_section_entry()->set_sh_entsize(entry_size);

    /* Write each entry's required part followed by the optional part */
    for (size_t i=0; i<nentries; i++) {
        SgAsmElfRelocEntry::Elf32RelaEntry_disk diska32;
        SgAsmElfRelocEntry::Elf64RelaEntry_disk diska64;
        SgAsmElfRelocEntry::Elf32RelEntry_disk  disk32;
        SgAsmElfRelocEntry::Elf64RelEntry_disk  disk64;
        void *disk  = NULL;

        SgAsmElfRelocEntry *entry = p_entries->get_entries()[i];

        if (4==fhdr->get_word_size()) {
            if (p_uses_addend) {
                disk = entry->encode(sex, &diska32);
            } else {
                disk = entry->encode(sex, &disk32);
            }
        } else if (8==fhdr->get_word_size()) {
            if (p_uses_addend) {
                disk = entry->encode(sex, &diska64);
            } else {
                disk = entry->encode(sex, &disk64);
            }
        } else {
            ROSE_ASSERT(!"unsupported word size");
        }

        rose_addr_t spos = i * entry_size;
        spos = write(f, spos, struct_size, disk);
#if 0 /*FIXME: padding not supported here yet (RPM 2008-10-13)*/
        if (entry->get_extra().size()>0) {
            ROSE_ASSERT(entry->get_extra().size()<=extra_size);
            write(f, spos, entry->get_extra());
        }
#endif
    }

    unparse_holes(f);
}
Exemplo n.º 4
0
/** Non-parsing constructor for an ELF Segment (Program Header) Table */
void
SgAsmElfSegmentTable::ctor()
{
    /* There can be only one ELF Segment Table */
    SgAsmElfFileHeader *fhdr = dynamic_cast<SgAsmElfFileHeader*>(get_header());
    ROSE_ASSERT(fhdr);
    ROSE_ASSERT(fhdr->get_segment_table()==NULL);
    fhdr->set_segment_table(this);
    
    set_synthesized(true);                              /* the segment table isn't part of any explicit section */
    set_name(new SgAsmBasicString("ELF Segment Table"));
    set_purpose(SP_HEADER);

    fhdr->set_segment_table(this);
}
Exemplo n.º 5
0
/** Unparse the Frame Description Entry (FDE) into a string but do not include the leading length field(s) or the CIE back
 *  pointer. */
std::string
SgAsmElfEHFrameEntryFD::unparse(const SgAsmElfEHFrameSection *ehframe, SgAsmElfEHFrameEntryCI *cie) const
{
    SgAsmElfFileHeader *fhdr = ehframe->get_elf_header();
    ROSE_ASSERT(fhdr!=NULL);

    /* Allocate worst-case size for results */
    size_t worst_size = 8 + get_augmentation_data().size() + get_instructions().size() + fhdr->get_word_size();
    unsigned char *buf = new unsigned char[worst_size];

    size_t sz;
    rose_addr_t at = 0;
    uint32_t u32_disk;

    /* PC Begin (begin_rva) and size */
    switch (cie->get_addr_encoding()) {
        case -1:          /* No address encoding specified */
        case 0x01:
        case 0x03:
        case 0x1b: {
            ByteOrder::host_to_le(get_begin_rva().get_rva(), &u32_disk);
            memcpy(buf+at, &u32_disk, 4); at+=4;
            ByteOrder::host_to_le(get_size(), &u32_disk);
            memcpy(buf+at, &u32_disk, 4); at+=4;
            break;
        }
        default:
            /* See parser */
            if (++nwarnings<=WARNING_LIMIT) {
                fprintf(stderr, "%s:%u: warning: unknown FDE address encoding (0x%02x)\n",
                        __FILE__, __LINE__, cie->get_addr_encoding());
                if (WARNING_LIMIT==nwarnings)
                    fprintf(stderr, "    (additional frame warnings will be suppressed)\n");
            }
            break;
    }

    /* Augmentation Data */
    std::string astr = cie->get_augmentation_string();
    if (astr.size()>0 && astr[0]=='z') {
        at = ehframe->write_uleb128(buf, at, get_augmentation_data().size());
        sz = get_augmentation_data().size();
        if (sz>0) {
            memcpy(buf+at, &(get_augmentation_data()[0]), sz);
            at += sz;
        }
    }

    /* Call frame instructions */
    sz = get_instructions().size();
    if (sz>0) {
        memcpy(buf+at, &(get_instructions()[0]), sz);
        at += sz;
    }

    std::string retval((char*)buf, at);
    delete[] buf;
    return retval;
}
Exemplo n.º 6
0
void
MyTraversal::visit(SgNode* astNode)
{
    SgAsmElfFileHeader *fhdr = isSgAsmElfFileHeader(astNode);
    if (fhdr) {
        size_t oldsize = fhdr->get_word_size();
        if (8==oldsize) {
            size_t newsize = 4;
            printf("*** Changing ELF word size from %zu bits to %zu bits\n", 8*oldsize, 8*newsize);
            fhdr->get_exec_format()->set_word_size(newsize);
        } else if (4==oldsize) {
            size_t newsize = 8;
            printf("*** Changing ELF word size from %zu bits to %zu bits\n", 8*oldsize, 8*newsize);
            fhdr->get_exec_format()->set_word_size(newsize);
        }
    }
}
Exemplo n.º 7
0
/** Non-parsing constructor for an ELF Section Table */
void
SgAsmElfSectionTable::ctor()
{
    /* There can be only one ELF Section Table */
    SgAsmElfFileHeader *fhdr = dynamic_cast<SgAsmElfFileHeader*>(get_header());
    ROSE_ASSERT(fhdr);
    ROSE_ASSERT(fhdr->get_section_table()==NULL);

    set_synthesized(true);                              /* the section table isn't really a section itself */
    set_name(new SgAsmBasicString("ELF Section Table"));
    set_purpose(SP_HEADER);

    /* Every section table has a first entry that's all zeros. We don't declare that section here (see parse()) but we do set
     * the section count in the header in order to reserve that first slot. */
    if (fhdr->get_e_shnum()<1)
        fhdr->set_e_shnum(1);

    fhdr->set_section_table(this);
}
Exemplo n.º 8
0
/** Attaches a previously unattached ELF Section to the section table. If @p section is an  ELF String Section
 *  (SgAsmElfStringSection) that contains an ELF String Table (SgAsmElfStringTable) and the ELF Section Table has no
 *  associated string table then the @p section will be used as the string table to hold the section names.
 *
 *  This method complements SgAsmElfSection::init_from_section_table. This method initializes the section table from the
 *  section while init_from_section_table() initializes the section from the section table.
 *
 *  Returns the new section table entry linked into the AST. */
SgAsmElfSectionTableEntry *
SgAsmElfSectionTable::add_section(SgAsmElfSection *section)
{
    ROSE_ASSERT(section!=NULL);
    ROSE_ASSERT(section->get_file()==get_file());
    ROSE_ASSERT(section->get_header()==get_header());
    ROSE_ASSERT(section->get_section_entry()==NULL);            /* must not be in the section table yet */
    
    SgAsmElfFileHeader *fhdr = dynamic_cast<SgAsmElfFileHeader*>(get_header());
    ROSE_ASSERT(fhdr!=NULL);

    /* Assign an ID if there isn't one yet */
    if (section->get_id()<0) {
        int id = fhdr->get_e_shnum();
        fhdr->set_e_shnum(id+1);
        section->set_id(id);
    }

    /* If the supplied section is a string table and the ELF Section Table doesn't have a string table associated with it yet,
     * then use the supplied section as the string table to hold the names of the sections. When this happens, all sections
     * that are already defined in the ELF Section Table should have their names moved into the new string table. */
    SgAsmElfStringSection *strsec = NULL;
    if (fhdr->get_e_shstrndx()==0) {
        strsec = dynamic_cast<SgAsmElfStringSection*>(section);
        if (strsec) {
            fhdr->set_e_shstrndx(section->get_id());
            SgAsmGenericSectionList *all = fhdr->get_sections();
            for (size_t i=0; i<all->get_sections().size(); i++) {
                SgAsmElfSection *s = dynamic_cast<SgAsmElfSection*>(all->get_sections()[i]);
                if (s && s->get_id()>=0 && s->get_section_entry()!=NULL) {
                    s->allocate_name_to_storage(strsec);
                }
            }
        }
    } else {
        strsec = dynamic_cast<SgAsmElfStringSection*>(fhdr->get_section_by_id(fhdr->get_e_shstrndx()));
        ROSE_ASSERT(strsec!=NULL);
    }

    /* Make sure the name is in the correct string table */
    if (strsec)
        section->allocate_name_to_storage(strsec);

    /* Create a new section table entry. */
    SgAsmElfSectionTableEntry *shdr = new SgAsmElfSectionTableEntry;
    shdr->update_from_section(section);
    section->set_section_entry(shdr);

    return shdr;
}
Exemplo n.º 9
0
Arquivo: ElfNote.C Projeto: KurSh/rose
/** Write a note at the specified offset to the section containing the note. Returns the offset for the first byte past the end
 *  of the note. */
rose_addr_t
SgAsmElfNoteEntry::unparse(std::ostream &f, rose_addr_t at)
{
    /* Find the section holding this note */
    SgAsmElfNoteSection *notes = SageInterface::getEnclosingNode<SgAsmElfNoteSection>(this);
    ROSE_ASSERT(notes!=NULL);
    ROSE_ASSERT(at < notes->get_size());
    SgAsmElfFileHeader *fhdr = dynamic_cast<SgAsmElfFileHeader*>(notes->get_header());
    ROSE_ASSERT(fhdr!=NULL);

    /* Name size, including NUL termination */
    uint32_t u32;
    host_to_disk(fhdr->get_sex(), p_name->get_string().size()+1, &u32);
    notes->write(f, at, 4, &u32);
    at += 4;

    /* Payload size */
    host_to_disk(fhdr->get_sex(), p_payload.size(), &u32);
    notes->write(f, at, 4, &u32);
    at += 4;
    
    /* Type */
    host_to_disk(fhdr->get_sex(), p_type, &u32);
    notes->write(f, at, 4, &u32);
    at += 4;
    
    /* Name with NUL termination and padded to a multiple of four bytes */
    std::string name = p_name->get_string();
    while ((name.size()+1) % 4)
        name += '\0';
    notes->write(f, at, name.size()+1, name.c_str());
    at += name.size()+1;
    
    /* Payload */
    notes->write(f, at, p_payload);
    at += p_payload.size();
    
    return at;
}
Exemplo n.º 10
0
Arquivo: ElfNote.C Projeto: KurSh/rose
/** Initialize a note by parsing it from the specified location in the note section. Return value is the offset to the
 *  beginning of the next note. */
rose_addr_t
SgAsmElfNoteEntry::parse(rose_addr_t at)
{
    /* Find the section holding this note */
    SgAsmElfNoteSection *notes = SageInterface::getEnclosingNode<SgAsmElfNoteSection>(this);
    ROSE_ASSERT(notes!=NULL);
    ROSE_ASSERT(at < notes->get_size());
    SgAsmElfFileHeader *fhdr = dynamic_cast<SgAsmElfFileHeader*>(notes->get_header());
    ROSE_ASSERT(fhdr!=NULL);
    
    /* Length of note entry name, including NUL termination */
    uint32_t u32;
    notes->read_content_local(at, &u32, 4);
    size_t name_size = disk_to_host(fhdr->get_sex(), u32);
    at += 4;

    /* Length of note entry description (i.e., the payload) */
    notes->read_content_local(at, &u32, 4);
    size_t payload_size = disk_to_host(fhdr->get_sex(), u32);
    at += 4;

    /* Type of note */
    notes->read_content_local(at, &u32, 4);
    unsigned type = disk_to_host(fhdr->get_sex(), u32);
    at += 4;

    /* NUL-terminated name */
    std::string note_name = notes->read_content_local_str(at);
    ROSE_ASSERT(note_name.size()+1 == name_size);
    at += name_size;
    at = (at+3) & ~0x3; /* payload is aligned on a four-byte offset */

    /* Set properties */
    get_name()->set_string(note_name);
    set_type(type);
    p_payload = notes->read_content_local_ucl(at, payload_size);

    return at + payload_size;
}
Exemplo n.º 11
0
/** Write symbol table sections back to disk */
void
SgAsmElfSymbolSection::unparse(std::ostream &f) const
{
    SgAsmElfFileHeader *fhdr = get_elf_header();
    ROSE_ASSERT(fhdr);
    ByteOrder sex = fhdr->get_sex();

    size_t entry_size, struct_size, extra_size, nentries;
    calculate_sizes(&entry_size, &struct_size, &extra_size, &nentries);
    
    /* Adjust the entry size stored in the ELF Section Table */
    get_section_entry()->set_sh_entsize(entry_size);

    /* Write each entry's required part followed by the optional part */
    for (size_t i=0; i<nentries; i++) {
        SgAsmElfSymbol::Elf32SymbolEntry_disk disk32;
        SgAsmElfSymbol::Elf64SymbolEntry_disk disk64;
        void *disk=NULL;

        SgAsmElfSymbol *entry = p_symbols->get_symbols()[i];
        
        if (4==fhdr->get_word_size()) {
            disk = entry->encode(sex, &disk32);
        } else if (8==fhdr->get_word_size()) {
            disk = entry->encode(sex, &disk64);
        } else {
            ROSE_ASSERT(!"unsupported word size");
        }

        rose_addr_t spos = i * entry_size;
        spos = write(f, spos, struct_size, disk);
        if (entry->get_extra().size()>0) {
            ROSE_ASSERT(entry->get_extra().size()<=extra_size);
            write(f, spos, entry->get_extra());
        }
    }

    unparse_holes(f);
}
Exemplo n.º 12
0
/** Attaches a previously unattached ELF Segment (SgAsmElfSection) to the ELF Segment Table (SgAsmElfSegmentTable). This
 *  method complements SgAsmElfSection::init_from_segment_table. This method initializes the segment table from the segment
 *  while init_from_segment_table() initializes the segment from the segment table.
 *  
 *  ELF Segments are represented by SgAsmElfSection objects since ELF Segments and ELF Sections overlap very much in their
 *  features and thus should share an interface. An SgAsmElfSection can appear in the ELF Section Table and/or the ELF Segment
 *  Table and you can determine where it was located by calling get_section_entry() and get_segment_entry().
 *
 *  Returns the new segment table entry linked into the AST. */
SgAsmElfSegmentTableEntry *
SgAsmElfSegmentTable::add_section(SgAsmElfSection *section)
{
    ROSE_ASSERT(section!=NULL);
    ROSE_ASSERT(section->get_file()==get_file());
    ROSE_ASSERT(section->get_header()==get_header());
    ROSE_ASSERT(section->get_segment_entry()==NULL);            /* must not be in the segment table yet */

    SgAsmElfFileHeader *fhdr = dynamic_cast<SgAsmElfFileHeader*>(get_header());
    ROSE_ASSERT(fhdr);
    
    /* Assign a slot in the segment table */
    int idx = fhdr->get_e_phnum();
    fhdr->set_e_phnum(idx+1);

    /* Create a new segment table entry */
    SgAsmElfSegmentTableEntry *shdr = new SgAsmElfSegmentTableEntry;
    shdr->set_index(idx);
    shdr->update_from_section(section);
    section->set_segment_entry(shdr);

    return shdr;
}
Exemplo n.º 13
0
/** Initializes this ELF Symbol Section by parsing a file. */
SgAsmElfSymbolSection *
SgAsmElfSymbolSection::parse()
{
    SgAsmElfSection::parse();

    SgAsmElfFileHeader *fhdr = get_elf_header();
    ROSE_ASSERT(fhdr!=NULL);
    SgAsmElfSectionTableEntry *shdr = get_section_entry();
    ROSE_ASSERT(shdr!=NULL);
    SgAsmElfStringSection *strsec = dynamic_cast<SgAsmElfStringSection*>(get_linked_section());
    ROSE_ASSERT(strsec!=NULL);

    size_t entry_size, struct_size, extra_size, nentries;
    calculate_sizes(&entry_size, &struct_size, &extra_size, &nentries);
    ROSE_ASSERT(entry_size==shdr->get_sh_entsize());

    /* Parse each entry */
    for (size_t i=0; i<nentries; i++) {
        SgAsmElfSymbol *entry=0;
        if (4==fhdr->get_word_size()) {
            entry = new SgAsmElfSymbol(this); /*adds symbol to this symbol table*/
            SgAsmElfSymbol::Elf32SymbolEntry_disk disk;
            read_content_local(i*entry_size, &disk, struct_size);
            entry->parse(fhdr->get_sex(), &disk);
        } else if (8==fhdr->get_word_size()) {
            entry = new SgAsmElfSymbol(this); /*adds symbol to this symbol table*/
            SgAsmElfSymbol::Elf64SymbolEntry_disk disk;
            read_content_local(i*entry_size, &disk, struct_size);
            entry->parse(fhdr->get_sex(), &disk);
        } else {
            throw FormatError("unsupported ELF word size");
        }
        if (extra_size>0)
            entry->get_extra() = read_content_local_ucl(i*entry_size+struct_size, extra_size);
    }
    return this;
}
Exemplo n.º 14
0
/** Write the section table section back to disk */
void
SgAsmElfSectionTable::unparse(std::ostream &f) const
{
    SgAsmElfFileHeader *fhdr = dynamic_cast<SgAsmElfFileHeader*>(get_header());
    ROSE_ASSERT(fhdr!=NULL);
    ByteOrder::Endianness sex = fhdr->get_sex();
    SgAsmGenericSectionPtrList sections = fhdr->get_sectab_sections();

    /* Write the sections first */
    for (size_t i=0; i<sections.size(); i++)
        sections[i]->unparse(f);
    unparse_holes(f);

    /* Calculate sizes. The ELF File Header should have been updated in reallocate() prior to unparsing. */
    size_t ent_size, struct_size, opt_size, nentries;
    calculate_sizes(&ent_size, &struct_size, &opt_size, &nentries);
    ROSE_ASSERT(fhdr->get_shextrasz()==opt_size);
    ROSE_ASSERT(fhdr->get_e_shnum()==nentries);
    
    /* Write the section table entries */
    for (size_t i=0; i<sections.size(); ++i) {
        SgAsmElfSection *section = dynamic_cast<SgAsmElfSection*>(sections[i]);
        ROSE_ASSERT(section!=NULL);
        SgAsmElfSectionTableEntry *shdr = section->get_section_entry();
        ROSE_ASSERT(shdr!=NULL);
        ROSE_ASSERT(shdr->get_sh_offset()==section->get_offset());/*section table entry should have been updated in reallocate()*/

        int id = section->get_id();
        ROSE_ASSERT(id>=0 && (size_t)id<nentries);

        SgAsmElfSectionTableEntry::Elf32SectionTableEntry_disk disk32;
        SgAsmElfSectionTableEntry::Elf64SectionTableEntry_disk disk64;
        void *disk  = NULL;

        if (4==fhdr->get_word_size()) {
            disk = shdr->encode(sex, &disk32);
        } else if (8==fhdr->get_word_size()) {
            disk = shdr->encode(sex, &disk64);
        } else {
            ROSE_ASSERT(!"invalid word size");
        }

        /* The disk struct */
        rose_addr_t spos = write(f, id*ent_size, struct_size, disk);
        if (shdr->get_extra().size() > 0) {
            ROSE_ASSERT(shdr->get_extra().size()<=opt_size);
            write(f, spos, shdr->get_extra());
        }
    }
}
Exemplo n.º 15
0
/** Returns info about the size of the entries based on information already available. Any or all arguments may be null
 *  pointers if the caller is not interested in the value. */
rose_addr_t
SgAsmElfSectionTable::calculate_sizes(size_t *entsize, size_t *required, size_t *optional, size_t *entcount) const
{
    SgAsmElfFileHeader *fhdr = dynamic_cast<SgAsmElfFileHeader*>(get_header());
    ROSE_ASSERT(fhdr!=NULL);

    size_t struct_size = 0;
    size_t extra_size = fhdr->get_shextrasz();
    size_t entry_size = 0;
    size_t nentries = 0;

    /* Size of required part of each entry */
    if (4==fhdr->get_word_size()) {
        struct_size = sizeof(SgAsmElfSectionTableEntry::Elf32SectionTableEntry_disk);
    } else if (8==fhdr->get_word_size()) {
        struct_size = sizeof(SgAsmElfSectionTableEntry::Elf64SectionTableEntry_disk);
    } else {
        throw FormatError("bad ELF word size");
    }

    /* Entire entry should be at least large enough for the required part. */
    entry_size = struct_size;

    /* Size of optional parts. If we've parsed the table then use the largest optional part, otherwise assume the entry from
     * the ELF File Header is correct. */
    SgAsmGenericSectionPtrList sections = fhdr->get_sections()->get_sections();
    for (size_t i=0; i<sections.size(); i++) {
        SgAsmElfSection *elfsec = dynamic_cast<SgAsmElfSection*>(sections[i]);
        if (elfsec && elfsec->get_section_entry()) {
            ROSE_ASSERT(elfsec->get_id()>=0);
            nentries = std::max(nentries, (size_t)elfsec->get_id()+1);
            extra_size = std::max(extra_size, elfsec->get_section_entry()->get_extra().size());
        }
    }

    /* Total number of entries. Either we haven't parsed the section table yet (nor created the sections it defines) or we
     * have. In the former case we use the setting from the ELF File Header. Otherwise the table has to be large enough to
     * store the section with the largest ID (ID also serves as the index into the ELF Section Table). */
    if (0==nentries)
        nentries = fhdr->get_e_shnum();

    /* Return values */
    if (entsize)
        *entsize = entry_size;
    if (required)
        *required = struct_size;
    if (optional)
        *optional = extra_size;
    if (entcount)
        *entcount = nentries;
    return entry_size * nentries;
}
Exemplo n.º 16
0
SgAsmElfRelocSection *
SgAsmElfRelocSection::parse()
{
    SgAsmElfSection::parse();

    SgAsmElfFileHeader *fhdr = get_elf_header();
    ROSE_ASSERT(fhdr);

    size_t entry_size, struct_size, extra_size, nentries;
    calculate_sizes(&entry_size, &struct_size, &extra_size, &nentries);
    ROSE_ASSERT(extra_size==0);
    
    /* Parse each entry */
    for (size_t i=0; i<nentries; i++) {
        SgAsmElfRelocEntry *entry = 0;
        if (4==fhdr->get_word_size()) {
            if (p_uses_addend) {
                SgAsmElfRelocEntry::Elf32RelaEntry_disk disk;
                read_content_local(i*entry_size, &disk, struct_size);
                entry = new SgAsmElfRelocEntry(this);
                entry->parse(fhdr->get_sex(), &disk);
            } else {
                SgAsmElfRelocEntry::Elf32RelEntry_disk disk;
                read_content_local(i*entry_size, &disk, struct_size);
                entry = new SgAsmElfRelocEntry(this);
                entry->parse(fhdr->get_sex(), &disk);
            }
        } else if (8==fhdr->get_word_size()) {
            if (p_uses_addend) {
                SgAsmElfRelocEntry::Elf64RelaEntry_disk disk;
                read_content_local(i*entry_size, &disk, struct_size);
                entry = new SgAsmElfRelocEntry(this);
                entry->parse(fhdr->get_sex(), &disk);
            } else {
                SgAsmElfRelocEntry::Elf64RelEntry_disk disk;
                read_content_local(i*entry_size, &disk, struct_size);
                entry = new SgAsmElfRelocEntry(this);
                entry->parse(fhdr->get_sex(), &disk);
            }
        } else {
            throw FormatError("unsupported ELF word size");
        }
        if (extra_size>0)
            entry->get_extra() = read_content_local_ucl(i*entry_size+struct_size, extra_size);
    }
    return this;
}
Exemplo n.º 17
0
int
main() 
{
    /* The SgAsmGenericFile is the root of a tree describing a binary file (executable, shared lib, object, core dump).
     * Usually this node appears in a much larger AST containing instructions contexts and other information, but for the
     * purposes of this example, we'll just be generating the ELF Container and not any instructions.  This root will
     * eventually be passed to unparse() to generate the executable file. */
    SgAsmGenericFile *ef = new SgAsmGenericFile;
    
    /* The ELF File Header is the first thing in the file, always at offset zero. The constructors generally take arguments to
     * describe the new object's relationship with existing objects, i.e., its location in the AST. In this case, the
     * SgAsmElfFileHeader is a child of the SgAsmGenericFile (file headers are always children of their respective file).
     *
     * Section constructors (SgAsmElfFileHeader derives from SgAsmGenericSection) always place the new section at the current
     * end-of-file and give it an initial size of one byte.  This ensures that each section has a unique starting address,
     * which is important when file memory is actually allocated for a section and other sections need to be moved out of the
     * way--the allocator needs to know the relative positions of the sections in order to correctly relocate them.
     *
     * If we were parsing an ELF file we would usually use ROSE's frontend() method. However, one can also parse the file by
     * first constructing the SgAsmElfFileHeader and then invoking its parse() method, which parses the ELF File Header and
     * everything that can be reached from that header.
     * 
     * We use 0x400000 as the virtual address of the main LOAD segment, which occupies the first part of the file, up through
     * the end of the .text section (see below). ELF Headers don't actually store a base address, so instead of assigning one
     * to the SgAsmElfFileHeader we'll leave the headers's base address at zero and add base_va explicitly whenever we need
     * it. */
    SgAsmElfFileHeader *fhdr = new SgAsmElfFileHeader(ef);
    fhdr->get_exec_format()->set_word_size(8);                  /* default is 32-bit; we want 64-bit */
    fhdr->set_isa(SgAsmExecutableFileFormat::ISA_X8664_Family); /* instruction set architecture; default is ISA_IA32_386 */
    rose_addr_t base_va = 0x400000;                             /* base virtual address */

    /* ELF executable files always have an ELF Segment Table (also called the ELF Program Header Table) usually appears
     * immediately after the ELF File Header.  The ELF Segment Table describes contiguous regions of the file that should be
     * memory mapped by the loader. ELF Segments don't have names--names are imparted to the segment by virtue of a segment
     * also being described by the ELF Section Table which we'll create later.
     *
     * Note that an SgAsmGenericSection (which represents both ELF Segments and ELF Sections) does not have the ELF Segment
     * Table or ELF Section Table as a parent in the AST, but rather has the ELF File Header as a parent. This allows a single
     * SgAsmGenericSection to represent an ELF Segment, an ELF Section, both, or neither. It also allows us to define ELF
     * Segments and ELF Sections without needing to first define the ELF Segment Table or ELF Section Table, which is
     * particularly useful when one wants one of those tables to appear at the end of the file. */
    SgAsmElfSegmentTable *segtab = new SgAsmElfSegmentTable(fhdr);

#if 1
    /* Create the .text section to hold machine instructions. We'll eventually add it to the ELF Section Table (which will be
     * created at the end of the file) and store its name in an ELF String Section associated with the ELF Section Table. The
     * fact that we haven't created the string table yet doesn't prevent us from giving the section a name.
     *
     * A note about names: Names are represented by SgAsmGenericString objects. The SgAsmGenericString class is virtual and
     * subclasses SgAsmBasicString and SgAsmStoredString represent strings that have no file storage and strings that are
     * stored in the file, respectively.  The stored-string classes are further specialized to handle string tables for
     * various file formats and understand how to map the string into a file, how to allocate and reallocate space, etc.  In
     * general, you want to change the string characters (with set_string()) stored in an SgAsmGenericString that's already
     * present in the AST.
     * 
     * The section constructors and reallocators don't worry about alignment issues--they always allocate from the next
     * available byte. However, instructions typically need to satisfy some alignment constraints. We can easily adjust the
     * file offset chosen by the constructor, but we also need to tell the reallocator about the alignment constraint.
     * 
     * NOTE: There's a slight nuance of the reallocator that must be accounted for if you want to be very precise about where
     *       things are located in the file. When the reallocator shifts sections to make room for a section that needs to
     *       grow, it shifts all affected sections by a uniform amount. This preserves overlaps (like when a segment overlaps
     *       with a bunch of sections) but it also means that the alignment constraint we'll set for ".text" will cause the
     *       ELF Segment Table constructed above at a lower offset to move in tandem with ".text" when the ELF File Header (at
     *       an even lower address) needs to grow to its final size.  This isn't a problem--you just end up with a couple unused
     *       bytes between the header and the segment table that will show up as a "hole" when subsequently parsed. If you're
     *       picky, the correct solution is to give the header a chance to allocate its file space before we construct the
     *       ".text" segment.
     *
     * In order to write the instructions out during the unparse phase, we create a new class from SgAsmElfSection and
     * override the virtual unparse() method.  The reallocate() method is called just before unparsing and we augment that in
     * order to set an ELF-specific bit in the ELF Section Table flags (alternatively, we could have set that bit after the
     * add_section() call below that adds the .text section to the ELF Section Table, but we do it here for demonstration).
     * The calculate_sizes() function is used by SgAsmElfSection::reallocate() to figure out how much space is needed for the
     * section.
     *
     * The instructions correspond to the assembly:
     *     .section .text
     *     .global _start
     * _start:
     *     movl    $1, %eax    # _exit(86)
     *     movl    $86, %ebx
     *     int     $0x80 */
    class TextSection : public SgAsmElfSection {
    public:
        TextSection(SgAsmElfFileHeader *fhdr, size_t ins_size, const unsigned char *ins_bytes)
            : SgAsmElfSection(fhdr), ins_size(ins_size), ins_bytes(ins_bytes)
            {}
        virtual rose_addr_t calculate_sizes(size_t *entsize, size_t *required, size_t *optional, size_t *entcount) const {
            if (entsize)  *entsize  = 1;                        /* an "entry" is one byte of instruction */
            if (required) *required = 1;                        /* each "entry" is also stored in one byte of the file */
            if (optional) *optional = 0;                        /* there is no extra data per instruction byte */
            if (entcount) *entcount = ins_size;                 /* number of "entries" is the total instruction bytes */
            return ins_size;                                    /* return value is section size required */
        }
        virtual bool reallocate() {
            bool retval = SgAsmElfSection::reallocate();        /* returns true if size or position of any section changed */
            SgAsmElfSectionTableEntry *ste = get_section_entry();
            ste->set_sh_flags(ste->get_sh_flags() | SgAsmElfSectionTableEntry::SHF_ALLOC); /* set the SHF_ALLOC bit */
            return retval;
        }
        virtual void unparse(std::ostream &f) const {
            write(f, 0, ins_size, ins_bytes);                   /* Write the instructions at offset zero in section */
        }
        size_t ins_size;
        const unsigned char *ins_bytes;
    };
    ef->reallocate();                                           /* Give existing sections a chance to allocate file space */
    static const unsigned char instructions[] = {0xb8, 0x01, 0x00, 0x00, 0x00, 0xbb, 0x56, 0x00, 0x00, 0x00, 0xcd, 0x80};
    SgAsmElfSection *text = new TextSection(fhdr, NELMTS(instructions), instructions);
    text->set_purpose(SgAsmGenericSection::SP_PROGRAM);         /* Program-supplied text/data/etc. */
    text->set_file_alignment(4);                                /* Tell reallocator about alignment constraint */
    text->set_mapped_alignment(4);                              /* Alignment constraint for memory mapping */
    text->set_mapped_preferred_rva(base_va+text->get_offset()); /* Mapped address is based on file offset */
    text->set_mapped_size(text->get_size());                    /* Mapped size is same as file size */
    text->set_mapped_rperm(true);                               /* Readable */
    text->set_mapped_wperm(false);                              /* Not writable */
    text->set_mapped_xperm(true);                               /* Executable */
    text->get_name()->set_string(".text");                      /* Give section the standard name */
    text->align();                                              /* Because we changed alignment constraints */
#else
    /* Another way to do the same thing without a temporary class. */
    ef->reallocate();
    static const unsigned char instructions[] = {0xb8, 0x01, 0x00, 0x00, 0x00, 0xbb, 0x56, 0x00, 0x00, 0x00, 0xcd, 0x80};
    SgAsmElfSection *text = new SgAsmElfSection(fhdr);
    text->set_purpose(SgAsmGenericSection::SP_PROGRAM);         /* Program-supplied text/data/etc. */
    text->set_file_alignment(4);                                /* Tell reallocator about alignment constraint */
    text->set_size(sizeof instructions);                        /* Give section a specific size */
    text->set_mapped_alignment(4);                              /* Alignment constraint for memory mapping */
    text->set_mapped_preferred_rva(base_va+text->get_offset()); /* Mapped address is based on file offset */
    text->set_mapped_size(text->get_size());                    /* Mapped size is same as file size */
    text->set_mapped_rperm(true);                               /* Readable */
    text->set_mapped_wperm(false);                              /* Not writable */
    text->set_mapped_xperm(true);                               /* Executable */
    text->get_name()->set_string(".text");                      /* Give section the standard name */
    text->align();                                              /* Because we changed alignment constraints */
    unsigned char *content = text->writable_content(sizeof instructions);
    memcpy(content, instructions, sizeof instructions);
#endif


    /* Set the main entry point to be the first virtual address in the text section. A rose_rva_t address is associated
     * with a section (.text in this case) so that if the starting address of the section changes (such as via reallocate())
     * then the rose_rva_t address will also change so as to continue to refer to the same byte of the section. */
    rose_rva_t entry_rva(text->get_mapped_preferred_rva(), text);
    fhdr->add_entry_rva(entry_rva);

    /* We now add an entry to the ELF Segment Table. ELF Segments often overlap multiple sections, and in this case we're
     * going to create a segment that overlaps with the ELF File Header, the ELF Segment Table, and the ".text" section. The
     * functions that reallocate space for sections (since most are born with a size of one byte) understand that things may
     * overlap and make appropriate adjustments. In this case all we need to do is set the starting offset and size. */
    SgAsmElfSection *seg1 = new SgAsmElfSection(fhdr);          /* ELF Segments are represented by SgAsmElfSection */
    seg1->get_name()->set_string("LOAD");                       /* Segment names aren't saved (but useful for debugging) */
    seg1->set_offset(0);                                        /* Starts at beginning of file */
    seg1->set_size(text->get_offset() + text->get_size());      /* Extends to end of .text section */
    seg1->set_mapped_preferred_rva(base_va);                    /* Typically mapped by loader to this memory address */
    seg1->set_mapped_size(seg1->get_size());                    /* Make mapped size match size in the file */
    seg1->set_mapped_rperm(true);                               /* Readable */
    seg1->set_mapped_wperm(false);                              /* Not writable */
    seg1->set_mapped_xperm(true);                               /* Executable */
    segtab->add_section(seg1);                                  /* Add definition to ELF Segment Table */

    /* Add an empty PAX segment as further demonstration of adding an ELF Segment. We need to tell the loader that this
     * section holds PAX Flags. There's no interface (currently) to do this at a generic level, so we make an adjustment
     * directly to the ELF Segment Table entry. */
    SgAsmElfSection *pax = new SgAsmElfSection(fhdr);
    pax->get_name()->set_string("PAX Flags");                   /* Name just for debugging */
    pax->set_offset(0);                                         /* Override address to be at zero rather than EOF */
    pax->set_size(0);                                           /* Override size to be zero rather than one byte */
    segtab->add_section(pax);                                   /* Add definition to ELF Segment Table */
    pax->get_segment_entry()->set_type(SgAsmElfSegmentTableEntry::PT_PAX_FLAGS);
    
    /* In order to give sections names there has to be an ELF String Section where the names are stored. An ELF String Section
     * is a section itself and will appear in the ELF Section Table. The name of this string section will be stored in a
     * string section, possibly this same string section. */
    SgAsmElfStringSection *shstrtab = new SgAsmElfStringSection(fhdr);
    shstrtab->get_name()->set_string(".shstrtab");

    /* Most files have an ELF Section Table that describes the various sections in the file (the code, data, dynamic linking,
     * symbol tables, string tables, etc). The ELF Section Table is a child of the ELF File Header, just as all other sections
     * reachable from the ELF File Header are also children of the header.  The class SgAsmGenericSection is used to represent
     * all types of contiguous file regions, whether they're ELF Sections, ELF Segments, PE Objects, etc.
     * 
     * The first entry of an ELF Section Table should always be an all-zero entry. It is not necessary to explicitly create
     * the zero entry since the unparse() method will do so. When parsing an ELF Section Table, the parser will read the
     * all-zero entry and actually create an empty, no-name, section with ID==0 (this is to handle cases that violate the ELF
     * specification).
     * 
     * Section names are stored in an ELF String Section that's associated with the ELF Section Table. We make that
     * association by adding the ELF String Section to the ELF Section Table. The first string table that's added will be the
     * one that stores section names. */
    SgAsmElfSectionTable *sectab = new SgAsmElfSectionTable(fhdr);
    sectab->add_section(text);                                  /* Add the .text section */
    sectab->add_section(shstrtab);                              /* Add the string table to store section names. */

#if 1 /* This stuff is here for demonstration. It's not necessary for the generated a.out to function properly. */

    /* Create a symbol table. Symbol tables should always be added to the ELF Section Table, and thus have a name. ELF Symbol
     * Tables need to know the section that serves as storage for the symbol names, an ELF String Section. The string table
     * for the section name (set above) does not need to be the same as the string table used for symbol names, although we
     * use the same one here just for brevity. */
    SgAsmElfSymbolSection *symtab = new SgAsmElfSymbolSection(fhdr, shstrtab);
    symtab->get_name()->set_string(".dynsym-test");
    symtab->set_is_dynamic(true);                               /* This is a symbol table for dynamic linking */
    sectab->add_section(symtab);                                /* Make the entry in the ELF Section Table */

    /* Add some symbols to the symbol table. Symbols are born with an empty name pointing into the symbol string table and the
     * names should be adjusted by calling get_name()->set_string("xxx"); there is no need to construct new SgAsmStoredString
     * objects and assign them with set_name(). */
    SgAsmElfSymbol *symbol;

    symbol = new SgAsmElfSymbol(symtab);                        /* New symbol is a child of the symbol table */
    symbol->set_value(0xaabbccdd);                              /* Arbitrary symbol value, often an RVA */
    symbol->set_size(512);                                      /* Arbitrary size of the thing to which the symbol refers */
    symbol->get_name()->set_string("symbolA");                  /* Symbol name */

    symbol = new SgAsmElfSymbol(symtab);
    symbol->set_value(0x11223344);
    symbol->set_size(4);
    symbol->get_name()->set_string("symbolB");

    /* Create a .dynamic section. Dynamic sections are generally added to both the section table and the segment table and are
     * memory mapped with read/write permission. They need an ELF String Table in order to store the library names. In real
     * executables the string table is usually separate from the others, but we'll just use the one we already created. */
    SgAsmElfDynamicSection *dynamic = new SgAsmElfDynamicSection(fhdr, shstrtab);
    dynamic->get_name()->set_string(".dynamic-test");           /* Give section a name */
    dynamic->set_mapped_preferred_rva(0x800000);                /* RVA where loader will map section */
    dynamic->set_mapped_size(dynamic->get_size());              /* Make mapped size same as file size */
    dynamic->set_mapped_rperm(true);                            /* Readable */
    dynamic->set_mapped_wperm(true);                            /* Writable */
    dynamic->set_mapped_xperm(false);                           /* Not executable */
    sectab->add_section(dynamic);                               /* Make an ELF Section Table entry */
    segtab->add_section(dynamic);                               /* Make an ELF Segment Table entry */

    /* Create some entries for the .dynamic section. Entries are born with a null name rather than an empty string since most
     * entries don't have a string value. So an entry that requires a string value (like DT_NEEDED) will need to have a new
     * string constructed. You don't have to worry about placing the new string in a particular string table since
     * reallocate() will eventually take care of that, so you can even use the very simple SgAsmBasicString interface. */
    SgAsmElfDynamicEntry *dynent;

    /* Add some DT_NULL entries */
    dynent = new SgAsmElfDynamicEntry(dynamic);
    dynent = new SgAsmElfDynamicEntry(dynamic);
    dynent = new SgAsmElfDynamicEntry(dynamic);

    /* Add a library name */
    dynent = new SgAsmElfDynamicEntry(dynamic);
    dynent->set_d_tag(SgAsmElfDynamicEntry::DT_NEEDED);
    dynent->set_name(new SgAsmBasicString("testlib"));

    /* Create a relocation table. Relocation tables depend on a symbol table and, indirectly, a string table. */
    SgAsmElfRelocSection *reladyn = new SgAsmElfRelocSection(fhdr, symtab,NULL);
    reladyn->get_name()->set_string(".rela.dyn-test");
    reladyn->set_uses_addend(true);                             /* This is a "rela" table rather than a "rel" table */
    sectab->add_section(reladyn);                               /* Make an ELF Section Table entry */

    /* Add a relocation entry to the relocation table. We create just one here, but in practice you would create as many as
     * you need.  Even REL tabels have a set_r_addend() method, but you should leave the addend at zero for them. The
     * relocation type determines how many bits of the offset are significant (and other details) and are described in the
     * system <elf.h> file (we may eventually change this interface to unify the various file formats). */
    SgAsmElfRelocEntry *relent = new SgAsmElfRelocEntry(reladyn);
    relent->set_r_offset(0x080495ac);                           /* An arbitrary offset */
    relent->set_r_addend(0xaa);                                 /* Arbitrary value to add to relocation address */
    relent->set_sym(symtab->index_of(symbol));                  /* Index of symbol in its symbol table */
    relent->set_type(SgAsmElfRelocEntry::R_386_JMP_SLOT);       /*  */

    /* We can add notes to an executable */
    SgAsmElfNoteSection *notes = new SgAsmElfNoteSection(fhdr);
    notes->set_name(new SgAsmBasicString("ELF Notes"));
    notes->set_mapped_preferred_rva(0x900000);                /* RVA where loader will map section */
    notes->set_mapped_size(notes->get_size());              /* Make mapped size same as file size */
    notes->set_mapped_rperm(true);                            /* Readable */
    notes->set_mapped_wperm(true);                            /* Writable */
    notes->set_mapped_xperm(false);                           /* Not executable */
    SgAsmElfNoteEntry *note = new SgAsmElfNoteEntry(notes);
    note->set_name(new SgAsmBasicString("ROSE"));
    const char *payload = "This is a test note.";
    for (size_t i=0; payload[i]; i++) {
        note->get_payload().push_back(payload[i]);
    }
    segtab->add_section(notes);


    /* Add a Symbol Version section.  This is a gnu extension to elf to support versioning of individual symbols 
       the size of the symver section should match the size of the dynamic symbol section (nominally .dynsym).
       there should also be an entry in the .dynamic section [DT_VERDEFNUM] that matches this same number.
     */
    SgAsmElfSymverSection* symver = new SgAsmElfSymverSection(fhdr);
    symver->get_name()->set_string(".gnu-version-test");       /* Give section a name */
    symver->set_mapped_preferred_rva(0xA00000);                /* RVA where loader will map section */
    symver->set_mapped_size(symver->get_size());               /* Make mapped size same as file size */
    symver->set_mapped_rperm(true);                            /* Readable */
    symver->set_mapped_wperm(false);                           /* Writable */
    symver->set_mapped_xperm(false);                           /* Not executable */
    sectab->add_section(symver);                               /* Make an ELF Section Table entry */

    for(size_t i=0; i < symtab->get_symbols()->get_symbols().size(); ++i){
      SgAsmElfSymverEntry* symver_entry = new SgAsmElfSymverEntry(symver);
      symver_entry->set_value(i);
    }
    
    SgAsmElfSymverDefinedSection* symver_def = new SgAsmElfSymverDefinedSection(fhdr,shstrtab);
    symver_def->get_name()->set_string(".gnu.version_d-test");
    symver_def->set_mapped_preferred_rva(0xB00000);                /* RVA where loader will map section */
    symver_def->set_mapped_size(symver_def->get_size());               /* Make mapped size same as file size */
    symver_def->set_mapped_rperm(true);                            /* Readable */
    symver_def->set_mapped_wperm(false);                           /* Writable */
    symver_def->set_mapped_xperm(false);                           /* Not executable */

    sectab->add_section(symver_def);                               /* Make an ELF Section Table entry */

    /** normal case - one Aux structure*/
    SgAsmElfSymverDefinedEntry* symdefEntry1 = new SgAsmElfSymverDefinedEntry(symver_def);
    symdefEntry1->set_version(1);
    symdefEntry1->set_hash(0xdeadbeef);// need to implement real hash support?
    symdefEntry1->set_flags(0x0);
    
    SgAsmElfSymverDefinedAux* symdefAux1a = new SgAsmElfSymverDefinedAux(symdefEntry1, symver_def);
    symdefAux1a->get_name()->set_string("version-1");

    SgAsmElfSymverDefinedEntry* symdefEntry2 = new SgAsmElfSymverDefinedEntry(symver_def);
    new SgAsmElfSymverDefinedAux(symdefEntry2, symver_def);
    new SgAsmElfSymverDefinedAux(symdefEntry2, symver_def);

    /* Very strange case, but technically legal - zero Aux */
    new SgAsmElfSymverDefinedEntry(symver_def);

    SgAsmElfSymverNeededSection* symver_need = new SgAsmElfSymverNeededSection(fhdr,shstrtab);
    symver_need->get_name()->set_string(".gnu.version_d-test");
    symver_need->set_mapped_preferred_rva(0xC00000);                /* RVA where loader will map section */
    symver_need->set_mapped_size(symver_need->get_size());               /* Make mapped size same as file size */
    symver_need->set_mapped_rperm(true);                            /* Readable */
    symver_need->set_mapped_wperm(false);                           /* Writable */
    symver_need->set_mapped_xperm(false);                           /* Not executable */
    sectab->add_section(symver_need);                               /* Make an ELF Section Table entry */


#endif

    /* Some of the sections we created above have default sizes of one byte because there's no way to determine their true
     * size until we're all done creating sections.  The SgAsmGenericFile::reallocate() traverses the AST and allocates the
     * actual file storage for each section, adjusting other sections to make room and updating various tables and
     * file-based data structures. You can call this function at any time, but it must be called before unparse(). */
    ef->reallocate();

    /* The reallocate() has a shortcoming [as of 2008-12-19] in that it might not correctly update memory mappings in the case
     * where the mapping for a section is inferred from the mapping of a containing segment when the section is shifted in the
     * file to make room for an earlier section that's also in the segment.
     * 
     * We can work around that here by explicitly setting the memory mapping to be relative to the segment. However, we'll
     * need to call reallocate() again because besides moving things around, reallocate() also updates some ELF-specific data
     * structures from values stored in the more generic structures. */
    text->set_mapped_preferred_rva(seg1->get_mapped_preferred_rva()+(text->get_offset()-seg1->get_offset()));
    ef->reallocate(); /*won't resize or move things this time since we didn't modify much since the last call to reallocate()*/

    /* Show some results. This is largely the same output as would be found in the *.dump file produced by many of the other
     * binary analysis tools. */
    ef->dump(stdout);
    SgAsmGenericSectionPtrList all = ef->get_sections(true);
    for (size_t i=0; i<all.size(); i++) {
        fprintf(stdout, "Section %zu:\n", i);
        all[i]->dump(stdout, "    ", -1);
    }

    /* Unparse the AST to generate an executable. */
    std::ofstream f("a.out");
    ef->unparse(f);

    return 0;
}
Exemplo n.º 18
0
/** Initialize by parsing a file. */
SgAsmElfEHFrameSection *
SgAsmElfEHFrameSection::parse()
{
    SgAsmElfSection::parse();
    SgAsmElfFileHeader *fhdr = get_elf_header();
    ROSE_ASSERT(fhdr!=NULL);

    rose_addr_t record_offset=0;
    std::map<rose_addr_t, SgAsmElfEHFrameEntryCI*> cies;

    // This section consists of a Common Information Entry (CIE) followed by one or more Frame Description Entry (FDE) and this
    // pattern is repeated for the entire section or until a termination record is reached.  There is typically one CIE per
    // object file and one FDE per function.  The CIE and FDE together describe how to unwind the caller during an exception if
    // the current instruction pointer is in the range covered by the FDE.

    Sawyer::Optional<rose_addr_t> prevCieOffset;
    while (record_offset<get_size()) {
        rose_addr_t at = record_offset;
        unsigned char u8_disk;
        uint32_t u32_disk;
        uint64_t u64_disk;

        /* Length or extended length */
        rose_addr_t length_field_size = 4; /*number of bytes not counted in length*/
        read_content_local(at, &u32_disk, 4); at += 4;
        rose_addr_t record_size = disk_to_host(fhdr->get_sex(), u32_disk);
        if (record_size==0xffffffff) {
            read_content_local(at, &u64_disk, 8); at += 8;
            record_size = disk_to_host(fhdr->get_sex(), u64_disk);
            length_field_size += 8;                     // length field size is both "length" and "extended length"
        }
        if (0==record_size) {
            record_offset += length_field_size;
            break;
        }

        /* Backward offset to CIE record, or zero if this is a CIE record. */
        read_content_local(at, &u32_disk, 4); at += 4;
        rose_addr_t cie_back_offset = disk_to_host(fhdr->get_sex(), u32_disk);
        if (0==cie_back_offset) {
            /* This is a CIE record */
            SgAsmElfEHFrameEntryCI *cie = new SgAsmElfEHFrameEntryCI(this);
            cies[record_offset] = cie;
            prevCieOffset = record_offset;

            /* Version. This parser was written based on version 1 documentation. */
            uint8_t cie_version;
            read_content_local(at++, &cie_version, 1);
            cie->set_version(cie_version);

            /* Augmentation String */
            std::string astr = read_content_local_str(at);
            at += astr.size() + 1;
            cie->set_augmentation_string(astr);

            /* EH data: 4 or 8 bytes depending on word size, only present "if the augmentation string contains 'eh'". The word
             * "contains" in the documentation apparently means the string is _equal_ to "eh". */
            if (astr == "eh") {
                uint64_t eh_data;
                if (4==fhdr->get_exec_format()->get_word_size()) {
                    read_content_local(at, &u32_disk, 4); at += 4;
                    eh_data = disk_to_host(fhdr->get_sex(), u32_disk);
                } else {
                    read_content_local(at, &u64_disk, 8); at += 8;
                    eh_data = disk_to_host(fhdr->get_sex(), u64_disk);
                }
                cie->set_eh_data(eh_data);
            }
            
            /* Alignment factors:
             * + code_alignment_factor: An unsigned LEB128 encoded value that is factored out of all advance location
             *   instructions that are associated with this CIE or its FDEs. This value shall be multiplied by the delta
             *   argument of an adavance location instruction to obtain the new location value.
             * + data_alignment_factor: A signed LEB128 encoded value that is factored out of all offset instructions that are
             *   associated with this CIE or its FDEs. This value shall be multiplied by the register offset argument of an
             *   offset instruction to obtain the new offset value. */
            cie->set_code_alignment_factor(read_content_local_uleb128(&at));
            cie->set_data_alignment_factor(read_content_local_sleb128(&at));

            /* Augmentation data length. This is apparently the length of the data described by the Augmentation String plus
             * the Initial Instructions plus any padding [RPM 2009-01-15].  This field is present only if the augmentation
             * string starts with the character "z" [Robb P. Matzke 2014-12-15]. */
            if (!astr.empty() && astr[0]=='z')
                cie->set_augmentation_data_length(read_content_local_uleb128(&at));
            
            /* Augmentation data. The format of the augmentation data in the CIE record is determined by reading the
             * characters of the augmentation string. */ 
            if (!astr.empty() && astr[0]=='z') {
                for (size_t i=1; i<astr.size(); i++) {
                    if ('L'==astr[i]) {
                        read_content_local(at++, &u8_disk, 1);
                        cie->set_lsda_encoding(u8_disk);
                    } else if ('P'==astr[i]) {
                        /* The first byte is an encoding method which describes the following bytes, which are the address of
                         * a Personality Routine Handler. There appears to be very little documentation about these fields. */
                        read_content_local(at++, &u8_disk, 1);
                        cie->set_prh_encoding(u8_disk);
                        switch (cie->get_prh_encoding()) {
                            case 0x05:          /* See Ubuntu 32bit /usr/bin/aptitude */
                            case 0x06:          /* See second CIE record for Gentoo-Amd64 /usr/bin/addftinfo */
                            case 0x07:          /* See first CIE record for Gentoo-Amd64 /usr/bin/addftinfo */
                                read_content_local(at++, &u8_disk, 1); /* not sure what this is; arg for __gxx_personality_v0? */
                                cie->set_prh_arg(u8_disk);
                                read_content_local(at, &u32_disk, 4); at+=4; /* address of <__gxx_personality_v0@plt> */
                                cie->set_prh_addr(ByteOrder::le_to_host(u32_disk));
                                break;
                            case 0x09:          /* *.o file generated by gcc-4.0.x */
                                /* FIXME: Cannot find any info about this entry. Fix SgAsmElfEHFrameSection::parse() if we
                                 *        ever figure this out. [RPM 2009-09-29] */
                                /*fallthrough*/
                            case 0x10:          /* See 32-bit version of skype library */
                                /* FIXME[Robb P. Matzke 2014-12-15]: cannot find any info for this entry. */
                                /*fallthrough*/
                            default: {
                                if (++nwarnings<=WARNING_LIMIT) {
                                    fprintf(stderr, "%s:%u: warning: ELF CIE 0x%08"PRIx64" has unknown PRH encoding 0x%02x\n", 
                                            __FILE__, __LINE__, get_offset()+record_offset, cie->get_prh_encoding());
                                    if (WARNING_LIMIT==nwarnings)
                                        fprintf(stderr, "    (additional frame warnings will be suppressed)\n");
                                }
                                break;
                            }
                        }
                    } else if ('R'==astr[i]) {
                        read_content_local(at++, &u8_disk, 1);
                        cie->set_addr_encoding(u8_disk);
                    } else if ('S'==astr[i]) {
                        /* See http://lkml.indiana.edu/hypermail/linux/kernel/0602.3/1144.html and GCC PR #26208*/
                        cie->set_sig_frame(true);
                    } else {
                        /* Some stuff we don't handle yet. Warn about it and don't read anything. */
                        if (++nwarnings<=WARNING_LIMIT) {
                            fprintf(stderr, "%s:%u: warning: ELF CIE 0x%08"PRIx64" has invalid augmentation string \"%s\"\n", 
                                    __FILE__, __LINE__, get_offset()+record_offset, escapeString(astr).c_str());
                            if (WARNING_LIMIT==nwarnings)
                                fprintf(stderr, "    (additional frame warnings will be suppressed)\n");
                        }
                    }
                }
            }

            /* Initial instructions. These are apparently included in the augmentation_data_length. The final instructions can
             * be zero padding (no-op instructions) to bring the record up to a multiple of the word size. */
            rose_addr_t init_insn_size = (length_field_size + record_size) - (at - record_offset);
            cie->get_instructions() = read_content_local_ucl(at, init_insn_size);
            ROSE_ASSERT(cie->get_instructions().size()==init_insn_size);

        } else {
            /* This is a FDE record */
            bool fde_parse_error = false;
            rose_addr_t cie_offset = record_offset + length_field_size - cie_back_offset;
            if (cies.find(cie_offset) == cies.end()) {
                mlog[ERROR] <<"bad CIE offset " <<cie_offset
                            <<" in section \"" <<StringUtility::cEscape(get_name()->get_string()) <<"\"\n";
                mlog[ERROR] <<"  referenced by FDE at offset " <<record_offset
                            <<" having CIE back offset " <<cie_back_offset <<"\n";
                if (prevCieOffset) {
                    mlog[ERROR] <<"  previous CIE was at offset " <<*prevCieOffset <<"\n";
                } else {
                    mlog[ERROR] <<"  there was no previous CIE in this section\n";
                }
                mlog[ERROR] <<"  bailing out early\n";
                break;
            }

            assert(cies.find(cie_offset)!=cies.end());
            SgAsmElfEHFrameEntryCI *cie = cies[cie_offset];
            SgAsmElfEHFrameEntryFD *fde = new SgAsmElfEHFrameEntryFD(cie);

            /* PC Begin (begin_rva) and size */
            switch (cie->get_addr_encoding()) {
              case -1:          /* No address encoding specified */
              case 0x01:
              case 0x03:
              case 0x1b:        /* Address doesn't look valid (e.g., 0xfffd74e8) but still four bytes [RPM 2008-01-16]*/
              {
                  read_content_local(at, &u32_disk, 4); at+=4;
                  fde->set_begin_rva(ByteOrder::le_to_host(u32_disk));
                  read_content_local(at, &u32_disk, 4); at+=4;
                  fde->set_size(ByteOrder::le_to_host(u32_disk));
                  break;
              }
              default:
                fprintf(stderr, "%s:%u: warning: ELF CIE 0x%08"PRIx64", FDE 0x%08"PRIx64": unknown address encoding: 0x%02x\n", 
                        __FILE__, __LINE__, get_offset()+cie_offset, get_offset()+record_offset, cie->get_addr_encoding());
                fde_parse_error = true;
                break;
            }

            // Location of following fields depends on having correctly unparsed the previous stuff which is RLE.
            if (!fde_parse_error) {
                /* Augmentation Data */
                std::string astring = cie->get_augmentation_string();
                if (astring.size()>0 && astring[0]=='z') {
                    rose_addr_t aug_length = read_content_local_uleb128(&at);
                    fde->get_augmentation_data() = read_content_local_ucl(at, aug_length);
                    at += aug_length;
                    ROSE_ASSERT(fde->get_augmentation_data().size()==aug_length);
                }

                /* Call frame instructions */
                rose_addr_t cf_insn_size = (length_field_size + record_size) - (at - record_offset);
                fde->get_instructions() = read_content_local_ucl(at, cf_insn_size);
                ROSE_ASSERT(fde->get_instructions().size()==cf_insn_size);
            }
        }

        record_offset += length_field_size + record_size;
    }

    if (record_offset < get_size()) {
        mlog[WARN] <<"ELF error handling section \"" <<StringUtility::cEscape(get_name()->get_string()) <<"\""
                   <<" contains " <<StringUtility::plural(get_size()-record_offset, "more bytes")
                   <<" that were not parsed\n";
    }

    return this;
}
Exemplo n.º 19
0
/** Parses an ELF Segment (Program Header) Table and constructs and parses all segments reachable from the table. The section
 *  is extended as necessary based on the number of entries and teh size of each entry. */
SgAsmElfSegmentTable *
SgAsmElfSegmentTable::parse()
{
    SgAsmGenericSection::parse();

    SgAsmElfFileHeader *fhdr = dynamic_cast<SgAsmElfFileHeader*>(get_header());
    ROSE_ASSERT(fhdr!=NULL);
    ByteOrder sex = fhdr->get_sex();

    size_t ent_size, struct_size, opt_size, nentries;
    calculate_sizes(&ent_size, &struct_size, &opt_size, &nentries);
    ROSE_ASSERT(opt_size==fhdr->get_phextrasz() && nentries==fhdr->get_e_phnum());

    /* If the current size is very small (0 or 1 byte) then we're coming straight from the constructor and the parsing should
     * also extend this section to hold all the entries. Otherwise the caller must have assigned a specific size for a good
     * reason and we should leave that alone, reading zeros if the entries extend beyond the defined size. */
    if (get_size()<=1 && get_size()<nentries*ent_size)
        extend(nentries*ent_size - get_size());
    
    rose_addr_t offset=0;                                /* w.r.t. the beginning of this section */
    for (size_t i=0; i<nentries; i++, offset+=ent_size) {
        /* Read/decode the segment header */
        SgAsmElfSegmentTableEntry *shdr = NULL;
        if (4==fhdr->get_word_size()) {
            SgAsmElfSegmentTableEntry::Elf32SegmentTableEntry_disk disk;
            read_content_local(offset, &disk, struct_size);
            shdr = new SgAsmElfSegmentTableEntry(sex, &disk);
        } else {
            SgAsmElfSegmentTableEntry::Elf64SegmentTableEntry_disk disk;
            read_content_local(offset, &disk, struct_size);
            shdr = new SgAsmElfSegmentTableEntry(sex, &disk);
        }
        shdr->set_index(i);
        if (opt_size>0)
            shdr->get_extra() = read_content_local_ucl(offset+struct_size, opt_size);

        /* Null segments are just unused slots in the table; no real section to create */
        if (SgAsmElfSegmentTableEntry::PT_NULL == shdr->get_type())
            continue;

        /* Create SgAsmElfSection objects for each ELF Segment. However, if the ELF Segment Table describes a segment
         * that's the same offset and size as a section from the Elf Section Table (and the memory mappings are
         * consistent) then use the preexisting section instead of creating a new one. */
        SgAsmElfSection *s = NULL;
        SgAsmGenericSectionPtrList possible = fhdr->get_file()->get_sections_by_offset(shdr->get_offset(), shdr->get_filesz());
        for (size_t j=0; !s && j<possible.size(); j++) {
            if (possible[j]->get_offset()!=shdr->get_offset() || possible[j]->get_size()!=shdr->get_filesz())
                continue; /*different file extent*/
            if (possible[j]->is_mapped()) {
                if (possible[j]->get_mapped_preferred_rva()!=shdr->get_vaddr() ||
                    possible[j]->get_mapped_size()!=shdr->get_memsz())
                    continue; /*different mapped address or size*/
                unsigned section_perms = (possible[j]->get_mapped_rperm() ? 0x01 : 0x00) |
                                         (possible[j]->get_mapped_wperm() ? 0x02 : 0x00) |
                                         (possible[j]->get_mapped_xperm() ? 0x04 : 0x00);
                unsigned segment_perms = (shdr->get_flags() & SgAsmElfSegmentTableEntry::PF_RPERM ? 0x01 : 0x00) |
                                         (shdr->get_flags() & SgAsmElfSegmentTableEntry::PF_WPERM ? 0x02 : 0x00) |
                                         (shdr->get_flags() & SgAsmElfSegmentTableEntry::PF_XPERM ? 0x04 : 0x00);
                if (section_perms != segment_perms)
                    continue; /*different mapped permissions*/
            }

            /* Found a match. Set memory mapping params only. */
            s = dynamic_cast<SgAsmElfSection*>(possible[j]);
            if (!s) continue; /*potential match was not from the ELF Section or Segment table*/
            if (s->get_segment_entry()) continue; /*potential match is assigned to some other segment table entry*/
            s->init_from_segment_table(shdr, true); /*true=>set memory mapping params only*/
        }

        /* Create a new segment if no matching section was found. */
        if (!s) {
            if (SgAsmElfSegmentTableEntry::PT_NOTE == shdr->get_type()) {
                s = new SgAsmElfNoteSection(fhdr);
            } else {
                s = new SgAsmElfSection(fhdr);
            }
            s->init_from_segment_table(shdr);
            s->parse();
        }
    }
    return this;
}
Exemplo n.º 20
0
/** Unparse one Common Information Entry (CIE) without unparsing the Frame Description Entries (FDE) to which it points. The
 *  initial length fields are not included in the result string. */
std::string
SgAsmElfEHFrameEntryCI::unparse(const SgAsmElfEHFrameSection *ehframe) const 
{
    SgAsmElfFileHeader *fhdr = ehframe->get_elf_header();
    ROSE_ASSERT(fhdr!=NULL);

    /* Allocate worst-case size for results */
    size_t worst_size = (4+
                         1+
                         get_augmentation_string().size()+1+
                         10+
                         10+
                         10+
                         get_augmentation_data_length()+
                         get_instructions().size()+
                         fhdr->get_word_size());
    unsigned char *buf = new unsigned char[worst_size];

    rose_addr_t at = 0;
    uint32_t u32_disk;
    unsigned char u8_disk;

    /* CIE back offset (always zero) */
    u32_disk=0;
    memcpy(buf+at, &u32_disk, 4); at+=4;

    /* Version */
    u8_disk = get_version();
    memcpy(buf+at, &u8_disk, 1); at+=1;

    /* NUL-terminated Augmentation String */
    size_t sz = get_augmentation_string().size()+1;
    memcpy(buf+at, get_augmentation_string().c_str(), sz); at+=sz;

    /* Alignment factors */
    at = ehframe->write_uleb128(buf, at, get_code_alignment_factor());
    at = ehframe->write_sleb128(buf, at, get_data_alignment_factor());

    /* Augmentation data */
    at = ehframe->write_uleb128(buf, at, get_augmentation_data_length());
    std::string astr = get_augmentation_string();
    if (!astr.empty() && astr[0]=='z') {
        for (size_t i=1; i<astr.size(); i++) {
            if ('L'==astr[i]) {
                u8_disk = get_lsda_encoding();
                buf[at++] = u8_disk;
            } else if ('P'==astr[i]) {
                u8_disk = get_prh_encoding();
                buf[at++] = u8_disk;
                switch (get_prh_encoding()) {
                    case 0x05:
                    case 0x06:
                    case 0x07:
                        buf[at++] = get_prh_arg();
                        ByteOrder::host_to_le(get_prh_addr(), &u32_disk);
                        memcpy(buf+at, &u32_disk, 4); at+=4;
                        break;
                    default:
                        /* See parser */
                        if (++nwarnings<=WARNING_LIMIT) {
                            fprintf(stderr, "%s:%u: warning: unknown PRH encoding (0x%02x)\n",
                                    __FILE__, __LINE__, get_prh_encoding());
                            if (WARNING_LIMIT==nwarnings)
                                fprintf(stderr, "    (additional frame warnings will be suppressed)\n");
                        }
                        break;
                }
            } else if ('R'==astr[i]) {
                u8_disk = get_addr_encoding();
                buf[at++] = u8_disk;
            } else if ('S'==astr[i]) {
                /* Signal frame; no auxilliary data */
            } else {
                ROSE_ASSERT(!"invalid .eh_frame augmentation string");
                abort();
            }
        }
    }

    /* Initial instructions */
    sz = get_instructions().size();
    if (sz>0) {
        memcpy(buf+at, &(get_instructions()[0]), sz);
        at += sz;
    }

    std::string retval((char*)buf, at);
    delete[] buf;
    return retval;
}
Exemplo n.º 21
0
/** Parses an ELF Section Table and constructs and parses all sections reachable from the table. The section is extended as
 *  necessary based on the number of entries and the size of each entry. */
SgAsmElfSectionTable *
SgAsmElfSectionTable::parse()
{
    SgAsmGenericSection::parse();

    SgAsmElfFileHeader *fhdr = dynamic_cast<SgAsmElfFileHeader*>(get_header());
    ROSE_ASSERT(fhdr!=NULL);
    ByteOrder::Endianness sex = fhdr->get_sex();

    size_t ent_size, struct_size, opt_size, nentries;
    calculate_sizes(&ent_size, &struct_size, &opt_size, &nentries);
    ROSE_ASSERT(opt_size==fhdr->get_shextrasz() && nentries==fhdr->get_e_shnum());

    /* If the current size is very small (0 or 1 byte) then we're coming straight from the constructor and the parsing should
     * also extend this section to hold all the entries. Otherwise the caller must have assigned a specific size for a good
     * reason and we should leave that alone, reading zeros if the entries extend beyond the defined size. */
    if (get_size()<=1 && get_size()<nentries*ent_size)
        extend(nentries*ent_size - get_size());

    // Read all the section headers.  Section headers are not essential to the Unix loader, which uses only segments. Therefore
    // we should be prepared to handle bad entries.
    std::vector<SgAsmElfSectionTableEntry*> entries;
    rose_addr_t offset = 0;
    try {
        for (size_t i=0; i<nentries; i++, offset+=ent_size) {
            SgAsmElfSectionTableEntry *shdr = NULL;
            if (4 == fhdr->get_word_size()) {
                SgAsmElfSectionTableEntry::Elf32SectionTableEntry_disk disk;
                read_content_local(offset, &disk, struct_size);
                shdr = new SgAsmElfSectionTableEntry(sex, &disk);
            } else {
                SgAsmElfSectionTableEntry::Elf64SectionTableEntry_disk disk;
                read_content_local(offset, &disk, struct_size);
                shdr = new SgAsmElfSectionTableEntry(sex, &disk);
            }
            if (opt_size>0)
                shdr->get_extra() = read_content_local_ucl(offset+struct_size, opt_size);
            entries.push_back(shdr);
        }
    } catch (const ShortRead &error) {
        mlog[ERROR] <<"short read for elf section header #" <<entries.size()
                    <<" at file offset " <<StringUtility::addrToString(error.offset)
                    <<" when reading " <<StringUtility::plural(error.size, "bytes") <<"\n";
        mlog[ERROR] <<"expected " <<StringUtility::plural(nentries, "sections") <<", but bailing out early\n";
        nentries = entries.size();
    }

    /* This vector keeps track of which sections have already been parsed. We could get the same information by calling
     * fhdr->get_section_by_id() and passing the entry number since entry numbers and IDs are one and the same in ELF. However,
     * this is a bit easier. */
    std::vector<SgAsmElfSection*> is_parsed;
    is_parsed.resize(entries.size(), NULL);

    /* All sections implicitly depend on the section string table for their names. */
    SgAsmElfStringSection *section_name_strings=NULL;
    if (fhdr->get_e_shstrndx() > 0 && fhdr->get_e_shstrndx() < entries.size()) {
        SgAsmElfSectionTableEntry *entry = entries[fhdr->get_e_shstrndx()];
        ASSERT_not_null(entry);
        section_name_strings = new SgAsmElfStringSection(fhdr);
        section_name_strings->init_from_section_table(entry, section_name_strings, fhdr->get_e_shstrndx());
        section_name_strings->parse();
        is_parsed[fhdr->get_e_shstrndx()] = section_name_strings;
    }

    /* Read all the sections. Some sections depend on other sections, so we read them in such an order that all dependencies
     * are satisfied first. */
    while (1) {
        bool try_again=false;
        for (size_t i=0; i<entries.size(); i++) {
            SgAsmElfSectionTableEntry *entry = entries[i];
            ROSE_ASSERT(entry->get_sh_link()<entries.size());

            /* Some sections might reference another section through the sh_link member. */
            bool need_linked = entry->get_sh_link() > 0;
            ROSE_ASSERT(!need_linked || entry->get_sh_link()<entries.size());
            SgAsmElfSection *linked = need_linked ? is_parsed[entry->get_sh_link()] : NULL;

            /* Relocation sections might have a second linked section stored in sh_info. */
            bool need_info_linked = (entry->get_sh_type() == SgAsmElfSectionTableEntry::SHT_REL ||
                                     entry->get_sh_type() == SgAsmElfSectionTableEntry::SHT_RELA) &&
                                    entry->get_sh_info() > 0;
            ROSE_ASSERT(!need_info_linked || entry->get_sh_info()<entries.size());
            SgAsmElfSection *info_linked = need_info_linked ? is_parsed[entry->get_sh_info()] : NULL;

            if (is_parsed[i]) {
                /* This section has already been parsed. */
            } else if ((need_linked && !linked) || (need_info_linked && !info_linked)) {
                /* Don't parse this section yet because it depends on something that's not parsed yet. */
                try_again = true;
            } else {
                switch (entry->get_sh_type()) {
                    case SgAsmElfSectionTableEntry::SHT_NULL:
                        /* Null entry. We still create the section just to hold the section header. */
                        is_parsed[i] = new SgAsmElfSection(fhdr);
                        break;
                    case SgAsmElfSectionTableEntry::SHT_NOBITS:
                        /* These types of sections don't occupy any file space (e.g., BSS) */
                        is_parsed[i] = new SgAsmElfSection(fhdr);
                        break;
                    case SgAsmElfSectionTableEntry::SHT_DYNAMIC: {
                        SgAsmElfStringSection *strsec = dynamic_cast<SgAsmElfStringSection*>(linked);
                        ROSE_ASSERT(strsec);
                        is_parsed[i] = new SgAsmElfDynamicSection(fhdr, strsec);
                        break;
                    }
                    case SgAsmElfSectionTableEntry::SHT_DYNSYM: {
                        SgAsmElfStringSection *strsec = dynamic_cast<SgAsmElfStringSection*>(linked);
                        ROSE_ASSERT(strsec);
                        SgAsmElfSymbolSection *symsec = new SgAsmElfSymbolSection(fhdr, strsec);
                        symsec->set_is_dynamic(true);
                        is_parsed[i] = symsec;
                        break;
                    }
                    case SgAsmElfSectionTableEntry::SHT_SYMTAB: {
                        SgAsmElfStringSection *strsec = dynamic_cast<SgAsmElfStringSection*>(linked);
                        ROSE_ASSERT(strsec);
                        SgAsmElfSymbolSection *symsec = new SgAsmElfSymbolSection(fhdr, strsec);
                        symsec->set_is_dynamic(false);
                        is_parsed[i] = symsec;
                        break;
                    }
                    case SgAsmElfSectionTableEntry::SHT_STRTAB:
                        is_parsed[i] = new SgAsmElfStringSection(fhdr);
                        break;
                    case SgAsmElfSectionTableEntry::SHT_REL: {
                        SgAsmElfSymbolSection *symbols = dynamic_cast<SgAsmElfSymbolSection*>(linked);
                        SgAsmElfRelocSection *relocsec = new SgAsmElfRelocSection(fhdr, symbols, info_linked);
                        relocsec->set_uses_addend(false);
                        is_parsed[i] = relocsec;
                        break;
                    }
                    case SgAsmElfSectionTableEntry::SHT_RELA: {
                        SgAsmElfSymbolSection *symbols = dynamic_cast<SgAsmElfSymbolSection*>(linked);
                        SgAsmElfRelocSection *relocsec = new SgAsmElfRelocSection(fhdr, symbols, info_linked);
                        relocsec->set_uses_addend(true);
                        is_parsed[i] = relocsec;
                        break;
                    }
                    case SgAsmElfSectionTableEntry::SHT_PROGBITS: {
                        if (!section_name_strings) {
                            fprintf(stderr, "SgAsmElfSectionTable::parse(): no string table for section table\n");
                            is_parsed[i] = new SgAsmElfSection(fhdr);
                        } else {
                            std::string section_name = section_name_strings->read_content_local_str(entry->get_sh_name());
                            if (section_name == ".eh_frame") {
                                is_parsed[i] = new SgAsmElfEHFrameSection(fhdr);
                            } else {
                                is_parsed[i] = new SgAsmElfSection(fhdr);
                            }
                        }
                        break;
                    }
                    case SgAsmElfSectionTableEntry::SHT_GNU_versym: {
                        is_parsed[i] = new SgAsmElfSymverSection(fhdr);
                        break;
                    }
                    case SgAsmElfSectionTableEntry::SHT_GNU_verdef: {
                        SgAsmElfStringSection *strsec = dynamic_cast<SgAsmElfStringSection*>(linked);
                        ROSE_ASSERT(strsec);
                        is_parsed[i] = new SgAsmElfSymverDefinedSection(fhdr,strsec);
                        break;
                    }
                    case SgAsmElfSectionTableEntry::SHT_GNU_verneed: {
                        SgAsmElfStringSection *strsec = dynamic_cast<SgAsmElfStringSection*>(linked);
                        ROSE_ASSERT(strsec);
                        is_parsed[i] = new SgAsmElfSymverNeededSection(fhdr,strsec);
                        break;
                    }
                    default:
                        is_parsed[i] = new SgAsmElfSection(fhdr);
                        break;
                }
                is_parsed[i]->init_from_section_table(entry, section_name_strings, i);
                is_parsed[i]->parse();
            }
        }
        if (!try_again)
            break;
    }

    /* Initialize links between sections */
    for (size_t i = 0; i < entries.size(); i++) {
        SgAsmElfSectionTableEntry *shdr = entries[i];
        if (shdr->get_sh_link() > 0) {
            SgAsmElfSection *source = isSgAsmElfSection(fhdr->get_file()->get_section_by_id(i));
            SgAsmElfSection *target = isSgAsmElfSection(fhdr->get_file()->get_section_by_id(shdr->get_sh_link()));
            assert(source);     /* because we created it above */
            source->set_linked_section(target);
        }
    }

    /* Finish parsing sections now that we have basic info for all the sections. */
    for (size_t i=0; i<is_parsed.size(); i++)
        is_parsed[i]->finish_parsing();

    return this;
}
Exemplo n.º 22
0
/** Initialize by parsing a file. */
SgAsmElfEHFrameSection *
SgAsmElfEHFrameSection::parse()
{
    SgAsmElfSection::parse();
    SgAsmElfFileHeader *fhdr = get_elf_header();
    ROSE_ASSERT(fhdr!=NULL);

    rose_addr_t record_offset=0;
    std::map<rose_addr_t, SgAsmElfEHFrameEntryCI*> cies;

    while (record_offset<get_size()) {
        rose_addr_t at = record_offset;
        unsigned char u8_disk;
        uint32_t u32_disk;
        uint64_t u64_disk;

        /* Length or extended length */
        rose_addr_t length_field_size = 4; /*number of bytes not counted in length*/
        read_content_local(at, &u32_disk, 4); at += 4;
        rose_addr_t record_size = disk_to_host(fhdr->get_sex(), u32_disk);
        if (record_size==0xffffffff) {
            read_content_local(at, &u64_disk, 8); at += 8;
            record_size = disk_to_host(fhdr->get_sex(), u64_disk);
            length_field_size += 8; /*FIXME: it's not entirely clear whether ExtendedLength includes this field*/
        }
        if (0==record_size)
            break;

        /* Backward offset to CIE record, or zero if this is a CIE record. */
        read_content_local(at, &u32_disk, 4); at += 4;
        rose_addr_t cie_back_offset = disk_to_host(fhdr->get_sex(), u32_disk);
        if (0==cie_back_offset) {
            /* This is a CIE record */
            SgAsmElfEHFrameEntryCI *cie = new SgAsmElfEHFrameEntryCI(this);
            cies[record_offset] = cie;

            /* Version */
            uint8_t cie_version;
            read_content_local(at++, &cie_version, 1);
            cie->set_version(cie_version);

            /* Augmentation String */
            std::string astr = read_content_local_str(at);
            at += astr.size() + 1;
            cie->set_augmentation_string(astr);

            /* Alignment factors */
            cie->set_code_alignment_factor(read_content_local_uleb128(&at));
            cie->set_data_alignment_factor(read_content_local_sleb128(&at));

            /* Augmentation data length. This is apparently the length of the data described by the Augmentation String plus
             * the Initial Instructions plus any padding. [RPM 2009-01-15] */
            cie->set_augmentation_data_length(read_content_local_uleb128(&at));

            /* Augmentation data. The format of the augmentation data in the CIE record is determined by reading the
             * characters of the augmentation string. */ 
            if (!astr.empty() && astr[0]=='z') {
                for (size_t i=1; i<astr.size(); i++) {
                    if ('L'==astr[i]) {
                        read_content_local(at++, &u8_disk, 1);
                        cie->set_lsda_encoding(u8_disk);
                    } else if ('P'==astr[i]) {
                        /* The first byte is an encoding method which describes the following bytes, which are the address of
                         * a Personality Routine Handler. There appears to be very little documentation about these fields. */
                        read_content_local(at++, &u8_disk, 1);
                        cie->set_prh_encoding(u8_disk);
                        switch (cie->get_prh_encoding()) {
                            case 0x05:          /* See Ubuntu 32bit /usr/bin/aptitude */
                            case 0x06:          /* See second CIE record for Gentoo-Amd64 /usr/bin/addftinfo */
                            case 0x07:          /* See first CIE record for Gentoo-Amd64 /usr/bin/addftinfo */
                                read_content_local(at++, &u8_disk, 1); /* not sure what this is; arg for __gxx_personality_v0? */
                                cie->set_prh_arg(u8_disk);
                                read_content_local(at, &u32_disk, 4); at+=4; /* address of <__gxx_personality_v0@plt> */
                                cie->set_prh_addr(ByteOrder::le_to_host(u32_disk));
                                break;
                            case 0x09:          /* *.o file generated by gcc-4.0.x */
                                /* FIXME: Cannot find any info about this entry. Fix SgAsmElfEHFrameSection::parse() if we
                                 *        ever figure this out. [RPM 2009-09-29] */
                                /*fallthrough*/
                            default: {
                                if (++nwarnings<=WARNING_LIMIT) {
                                    fprintf(stderr, "%s:%u: warning: ELF CIE 0x%08"PRIx64" has unknown PRH encoding 0x%02x\n", 
                                            __FILE__, __LINE__, get_offset()+record_offset, cie->get_prh_encoding());
                                    if (WARNING_LIMIT==nwarnings)
                                        fprintf(stderr, "    (additional frame warnings will be suppressed)\n");
                                }
                                break;
                            }
                        }
                    } else if ('R'==astr[i]) {
                        read_content_local(at++, &u8_disk, 1);
                        cie->set_addr_encoding(u8_disk);
                    } else if ('S'==astr[i]) {
                        /* See http://lkml.indiana.edu/hypermail/linux/kernel/0602.3/1144.html and GCC PR #26208*/
                        cie->set_sig_frame(true);
                    } else {
                        /* Some stuff we don't handle yet. Warn about it and don't read anything. */
                        if (++nwarnings<=WARNING_LIMIT) {
                            fprintf(stderr, "%s:%u: warning: ELF CIE 0x%08"PRIx64" has invalid augmentation string \"%s\"\n", 
                                    __FILE__, __LINE__, get_offset()+record_offset, escapeString(astr).c_str());
                            if (WARNING_LIMIT==nwarnings)
                                fprintf(stderr, "    (additional frame warnings will be suppressed)\n");
                        }
                    }
                }
            }

            /* Initial instructions. These are apparently included in the augmentation_data_length. The final instructions can
             * be zero padding (no-op instructions) to bring the record up to a multiple of the word size. */
            rose_addr_t init_insn_size = (length_field_size + record_size) - (at - record_offset);
            cie->get_instructions() = read_content_local_ucl(at, init_insn_size);
            ROSE_ASSERT(cie->get_instructions().size()==init_insn_size);

        } else {
            /* This is a FDE record */
            rose_addr_t cie_offset = record_offset + length_field_size - cie_back_offset;
            assert(cies.find(cie_offset)!=cies.end());
            SgAsmElfEHFrameEntryCI *cie = cies[cie_offset];
            SgAsmElfEHFrameEntryFD *fde = new SgAsmElfEHFrameEntryFD(cie);

            /* PC Begin (begin_rva) and size */
            switch (cie->get_addr_encoding()) {
              case -1:          /* No address encoding specified */
              case 0x01:
              case 0x03:
              case 0x1b:        /* Address doesn't look valid (e.g., 0xfffd74e8) but still four bytes [RPM 2008-01-16]*/
              {
                  read_content_local(at, &u32_disk, 4); at+=4;
                  fde->set_begin_rva(ByteOrder::le_to_host(u32_disk));
                  read_content_local(at, &u32_disk, 4); at+=4;
                  fde->set_size(ByteOrder::le_to_host(u32_disk));
                  break;
              }
              default:
                fprintf(stderr, "%s:%u: ELF CIE 0x%08"PRIx64", FDE 0x%08"PRIx64": unknown address encoding: 0x%02x\n", 
                        __FILE__, __LINE__, get_offset()+cie_offset, get_offset()+record_offset, cie->get_addr_encoding());
                abort();
            }

            /* Augmentation Data */
            std::string astring = cie->get_augmentation_string();
            if (astring.size()>0 && astring[0]=='z') {
                rose_addr_t aug_length = read_content_local_uleb128(&at);
                fde->get_augmentation_data() = read_content_local_ucl(at, aug_length);
                at += aug_length;
                ROSE_ASSERT(fde->get_augmentation_data().size()==aug_length);
            }

            /* Call frame instructions */
            rose_addr_t cf_insn_size = (length_field_size + record_size) - (at - record_offset);
            fde->get_instructions() = read_content_local_ucl(at, cf_insn_size);
            ROSE_ASSERT(fde->get_instructions().size()==cf_insn_size);
        }

        record_offset += length_field_size + record_size;
    }
    return this;
}
Exemplo n.º 23
0
/** Unparses the section into the optional output stream and returns the number of bytes written. If there is no output stream
 *  we still go through the actions but don't write anything. This is the only way to determine the amount of memory required
 *  to store the section since the section is run-length encoded. */
rose_addr_t
SgAsmElfEHFrameSection::unparse(std::ostream *fp) const
{
    SgAsmElfFileHeader *fhdr = get_elf_header();
    ROSE_ASSERT(fhdr!=NULL);

    rose_addr_t at=0;
    uint32_t u32_disk;
    uint64_t u64_disk;

    for (size_t i=0; i<get_ci_entries()->get_entries().size(); i++) {
        rose_addr_t last_cie_offset = at;
        SgAsmElfEHFrameEntryCI *cie = get_ci_entries()->get_entries()[i];
        std::string s = cie->unparse(this);
        if (s.size()<0xffffffff) {
            host_to_disk(fhdr->get_sex(), s.size(), &u32_disk);
            if (fp)
                write(*fp, at, 4, &u32_disk);
            at += 4;
        } else {
            u32_disk = 0xffffffff;
            if (fp)
                write(*fp, at, 4, &u32_disk);
            at += 4;
            host_to_disk(fhdr->get_sex(), s.size(), &u64_disk);
            if (fp)
                write(*fp, at, 8, &u64_disk);
            at += 8;
        }
        if (fp)
            write(*fp, at, s);
        at += s.size();

        for (size_t j=0; j<cie->get_fd_entries()->get_entries().size(); j++) {
            SgAsmElfEHFrameEntryFD *fde = cie->get_fd_entries()->get_entries()[j];
            std::string s = fde->unparse(this, cie);

            /* Record size, not counting run-length coded size field, but counting CIE back offset. */
            rose_addr_t record_size = 4 + s.size();
            if (record_size<0xffffffff) {
                host_to_disk(fhdr->get_sex(), record_size, &u32_disk);
                if (fp)
                    write(*fp, at, 4, &u32_disk);
                at += 4;
            } else {
                u32_disk = 0xffffffff;
                if (fp)
                    write(*fp, at, 4, &u32_disk);
                at += 4;
                host_to_disk(fhdr->get_sex(), record_size, &u64_disk);
                if (fp)
                    write(*fp, at, 8, &u64_disk);
                at += 8;
            }

            /* CIE back offset. Number of bytes from the beginning of the current CIE record (including the Size fields) to
             * the beginning of the FDE record (excluding the Size fields but including the CIE back offset). */
            rose_addr_t cie_back_offset = at - last_cie_offset;
            host_to_disk(fhdr->get_sex(), cie_back_offset, &u32_disk);
            if (fp)
                write(*fp, at, 4, &u32_disk);
            at += 4;

            /* The FDE record itself */
            if (fp)
                write(*fp, at, s);
            at += s.size();
        }
    }

    /* Write a zero length to indicate the end of the CIE list */
    u32_disk = 0;
    if (fp)
        write(*fp, at, 4, &u32_disk);
    at += 4;

    return at;
}