Example #1
0
/* Maps the sections of a single header. */
void
BinaryLoader::remap(MemoryMap *map, SgAsmGenericHeader *header)
{
    SgAsmGenericFile *file = header->get_file();
    ASSERT_not_null(file);

    Stream trace(mlog[TRACE]);

    trace <<"remapping sections of " <<header->get_file()->get_name() <<"\n";
    SgAsmGenericSectionPtrList sections = get_remap_sections(header);

    rose_addr_t old_base_va = header->get_base_va();
    rose_addr_t new_base_va = rebase(map, header, sections);
    if (new_base_va != old_base_va) {
        trace <<"  temporarily rebasing header from " <<StringUtility::addrToString(old_base_va)
              <<" to " <<StringUtility::addrToString(new_base_va) <<"\n";
        header->set_base_va(new_base_va);
    }

    try {
        for (SgAsmGenericSectionPtrList::iterator si=sections.begin(); si!=sections.end(); ++si) {
            SgAsmGenericSection *section = *si;
            section->set_mapped_actual_va(0); /*reset in case previously mapped*/

            if (trace) {
                trace <<"  mapping section [" <<section->get_id() <<"] \"" <<section->get_name()->get_string(true) <<"\"";
                if (section->get_base_va()!=0)
                    trace <<" with base va " <<StringUtility::addrToString(section->get_base_va());
                trace <<"\n";
                trace <<"    Specified RVA:       " <<StringUtility::addrToString(section->get_mapped_preferred_rva())
                      <<" + " <<StringUtility::addrToString(section->get_mapped_size()) <<" bytes"
                      <<" = " <<StringUtility::addrToString(section->get_mapped_preferred_rva()+section->get_mapped_size())
                      <<"\n";
                if (section->get_base_va()!=0) {
                    trace <<"    Specified  VA:       "
                          <<StringUtility::addrToString(section->get_base_va() + section->get_mapped_preferred_rva()) <<" + "
                          <<StringUtility::addrToString(section->get_mapped_size()) <<" bytes = "
                          <<StringUtility::addrToString(section->get_base_va() + section->get_mapped_preferred_rva() +
                                                        section->get_mapped_size()) <<"\n";
                }
                trace <<"    Specified offset:    "
                      <<StringUtility::addrToString(section->get_offset()) <<" + "
                      <<StringUtility::addrToString(section->get_size()) <<" bytes = "
                      <<StringUtility::addrToString(section->get_offset()+section->get_size()) <<"\n";
                trace <<"    Specified alignment: memory=[" <<section->get_mapped_alignment() <<","
                      <<section->get_mapped_alignment() <<"], file=["
                      <<section->get_file_alignment() <<"," <<section->get_file_alignment() <<"]\n";
            }

            /* Figure out alignment, etc. */
            rose_addr_t malign_lo=1, malign_hi=1, va=0, mem_size=0, offset=0, file_size=0, va_offset=0;
            bool anon_lo=true, anon_hi=true, map_private=false;
            ConflictResolution resolve = RESOLVE_THROW;
            MappingContribution contrib = align_values(section, map,                      /* inputs */
                                                       &malign_lo, &malign_hi,            /* alignment outputs */
                                                       &va, &mem_size,                    /* memory location outputs */
                                                       &offset, &file_size, &map_private, /* file location outputs */
                                                       &va_offset, &anon_lo, &anon_hi,    /* internal location outputs */
                                                       &resolve);                         /* conflict resolution output */
            rose_addr_t falign_lo = std::max(section->get_file_alignment(), (rose_addr_t)1);
            rose_addr_t falign_hi = falign_lo;

            if (trace) {
                if (CONTRIBUTE_NONE==contrib || 0==mem_size) {
                    trace <<"    Does not contribute to map\n";
                } else {
                    trace <<"    Adjusted alignment:  memory=["
                          <<malign_lo <<"," <<malign_hi <<"], file=[" <<falign_lo <<"," <<falign_hi <<"]\n";
                    trace <<"    Aligned VA:          "
                          <<StringUtility::addrToString(va) <<" + "
                          <<StringUtility::addrToString(mem_size) <<" bytes = "
                          <<StringUtility::addrToString(va+mem_size);
                    if (section->get_base_va()+section->get_mapped_preferred_rva()==va &&
                        section->get_mapped_size()==mem_size) {
                        trace <<" (no change)\n";
                    } else {
                        trace <<"\n";
                    }
                    if (va < new_base_va) {
                        trace <<"    WARNING: aligned va " <<StringUtility::addrToString(va) <<" is less than "
                              <<(new_base_va==old_base_va?"":"temporary ") <<"base va "
                              <<StringUtility::addrToString(new_base_va) <<"\n";
                    }
                    if (CONTRIBUTE_ADD==contrib) {
                        trace <<"    Aligned offset:      " <<StringUtility::addrToString(offset) <<" + "
                              <<StringUtility::addrToString(file_size) <<" bytes = "
                              <<StringUtility::addrToString(offset+file_size)
                              <<(section->get_offset()==offset && section->get_size()==file_size ? " (no change)\n" : "\n");
                        trace <<"    Permissions:         "
                              <<(section->get_mapped_rperm()?'r':'-')
                              <<(section->get_mapped_wperm()?'w':'-')
                              <<(section->get_mapped_xperm()?'x':'-') <<"\n";
                        trace <<"    Internal offset:     " <<StringUtility::addrToString(va_offset)
                              <<" (va " <<StringUtility::addrToString(va+va_offset) <<")\n";
                    }
                }
            }

            /* Sanity checks */
            if (CONTRIBUTE_NONE==contrib || 0==mem_size)
                continue;
            ASSERT_require(va_offset<mem_size);
            if (file_size>mem_size) file_size = mem_size;
            ASSERT_require(va + va_offset >= header->get_base_va());
            if (trace) {
                trace <<"    Current memory map (before we map this section)\n";
                map->dump(trace, "        ");
            }

            /* Erase part of the mapping? */
            if (CONTRIBUTE_SUB==contrib) {
                trace <<"    Subtracting contribution\n";
                map->erase(AddressInterval::baseSize(va, mem_size));
                continue;
            }

            /* Resolve mapping conflicts.  The new mapping may have multiple parts, so we test whether all those parts can be
             * mapped by first mapping a region and then removing it.  In this way we can perform the test atomically rather
             * than trying to undo the parts that had been successful. Allocating a large region does not actually allocate any
             * memory. */
            try {
                map->insert(AddressInterval::baseSize(va, mem_size), MemoryMap::Segment::nullInstance(mem_size));
                map->erase(AddressInterval::baseSize(va, mem_size));
            } catch (const MemoryMap::Exception&) {
                switch (resolve) {
                    case RESOLVE_THROW:
                        throw;
                    case RESOLVE_OVERMAP:
                        trace <<"    Conflict: resolved by making a hole\n";
                        map->erase(AddressInterval::baseSize(va, mem_size));
                        break;
                    case RESOLVE_REMAP:
                    case RESOLVE_REMAP_ABOVE: {
                        trace <<"    Unable to map entire desired region.\n";
                        AddressInterval where = AddressInterval::hull(RESOLVE_REMAP_ABOVE==resolve ? va : 0,
                                                                      AddressInterval::whole().greatest());
                        rose_addr_t new_va = 0;
                        if (!map->findFreeSpace(mem_size, malign_lo, where).assignTo(new_va)) {
                            throw MemoryMap::NoFreeSpace("unable to allocate space in specimen memory map",
                                                         map, mem_size);
                        }
                        ASSERT_require2(0 == (new_va+mem_size) % malign_hi, "FIXME: not handled yet [RPM 2010-09-03]");
                        va = new_va;
                        trace <<"    Relocated to VA:     " <<StringUtility::addrToString(va) <<" + "
                              <<StringUtility::addrToString(mem_size) <<" bytes = "
                              <<StringUtility::addrToString(va + mem_size) <<"\n";
                        break;
                    }
                }
            }

            /* Save the virtual address where this section is (will be) mapped.  When a section is mapped more than once
             * (perfectly legal to do so) only the last mapping is saved. */
            section->set_mapped_actual_va(va + va_offset);

            /* Permissions */
            unsigned mapperms=0;
            if (section->get_mapped_rperm())
                mapperms |= MemoryMap::READABLE;
            if (section->get_mapped_wperm())
                mapperms |= MemoryMap::WRITABLE;
            if (section->get_mapped_xperm())
                mapperms |= MemoryMap::EXECUTABLE;

            /* Segment name for debugging. This is the file base name and section name concatenated. */
            std::string::size_type file_basename_pos = file->get_name().find_last_of("/");
            file_basename_pos = file_basename_pos==file->get_name().npos ? 0 : file_basename_pos+1;
            std::string melmt_name = file->get_name().substr(file_basename_pos) + "(" + section->get_name()->get_string() + ")";
            trace <<"    Map element name: " <<escapeString(melmt_name) <<"\n";

            /* Anonymously map the part of memory beyond the physical end of the file */
            SgAsmGenericFile *file = section->get_file();
            rose_addr_t total = file->get_data().size(); /*total size of file*/
            if (offset+mem_size > total) {
                rose_addr_t n, a;
                if (offset >= total) {
                    /* starts beyond EOF */
                    n = mem_size;
                    a = va;
                } else {
                    /* overlaps EOF */
                    n = (offset + mem_size) - total;
                    a = va + total - offset;
                }
                trace <<"    Mapping part beyond EOF(" <<StringUtility::addrToString(total) <<"):      "
                      <<"va=" <<StringUtility::addrToString(a) <<" + " <<StringUtility::addrToString(n) <<" = "
                      <<StringUtility::addrToString(a+n) <<"\n";
                map->insert(AddressInterval::baseSize(a, n),
                            MemoryMap::Segment::anonymousInstance(n, mapperms|MemoryMap::PRIVATE, melmt_name));
                mem_size -= n;
                file_size = std::min(file_size, mem_size);
            }

            /* Anonymously map the part of memory beyond the part of file */
            if (anon_hi && mem_size>file_size) {
                rose_addr_t n = mem_size - file_size;
                rose_addr_t a = va + file_size;
                trace <<"    Mapping part beyond end of section:        va="
                      <<StringUtility::addrToString(a) <<" + " <<StringUtility::addrToString(n) <<" = "
                      <<StringUtility::addrToString(a+n) <<"\n";
                map->insert(AddressInterval::baseSize(a, n),
                            MemoryMap::Segment::anonymousInstance(n, mapperms|MemoryMap::PRIVATE, melmt_name));
                mem_size -= n;
            }

            /* Anonymously map the part of memory before the section */
            if (anon_lo && va_offset>0 && mem_size>0) {
                rose_addr_t n = va_offset - va;
                rose_addr_t a = va;
                trace <<"    Mapping part before beginning of section: va="
                      <<StringUtility::addrToString(a) <<" + " <<StringUtility::addrToString(n) <<" = "
                      <<StringUtility::addrToString(a+n) <<"\n";
                map->insert(AddressInterval::baseSize(a, n),
                            MemoryMap::Segment::anonymousInstance(n, mapperms|MemoryMap::PRIVATE, melmt_name));
                mem_size -= n;
                file_size -= n;
                va += n;
                offset += n;
            }

            /* Map the section. We use the file content as the underlying storage of the map because we might be mapping parts of
             * the file left and right of the actual section. */
            if (mem_size>0) {
                trace <<"    Mapping section:                          va="
                      <<StringUtility::addrToString(va) <<" + " <<StringUtility::addrToString(mem_size) <<" = "
                      <<StringUtility::addrToString(va+mem_size) <<" "
                      <<(map_private?"private":"shared") <<"\n";
                if (map_private) {
                    map->insert(AddressInterval::baseSize(va, mem_size),
                                MemoryMap::Segment::anonymousInstance(mem_size, mapperms|MemoryMap::PRIVATE,
                                                                      melmt_name));
                    map->at(va).limit(mem_size).write(&file->get_data()[offset]);
                } else {
                    // Create the buffer, but the buffer should not take ownership of data from the file.
                    map->insert(AddressInterval::baseSize(va, mem_size),
                                MemoryMap::Segment(MemoryMap::StaticBuffer::instance(&file->get_data()[0],
                                                                                     file->get_data().size()),
                                                   offset, mapperms, melmt_name));
                }
            }

            if (trace) {
                trace <<"    After mapping this section:\n";
                map->dump(trace, "      ");
            }
        }
        header->set_base_va(old_base_va);
    } catch(...) {
        header->set_base_va(old_base_va);
        throw;
    }
}
Example #2
0
/* Looks at the RVA/Size pairs in the PE header and creates an SgAsmGenericSection object for each one.  This must be done
 * after we build the mapping from virtual addresses to file offsets. */
void
SgAsmPEFileHeader::create_table_sections()
{

    /* First, only create the sections. */
    for (size_t i=0; i<p_rvasize_pairs->get_pairs().size(); i++) {
        SgAsmPERVASizePair *pair = p_rvasize_pairs->get_pairs()[i];
        if (0==pair->get_e_size())
            continue;

        /* Table names come from PE file specification and are hard coded by RVA/Size pair index */
        const char *tabname_short;
        std::string tabname = rvasize_pair_name((PairPurpose)i, &tabname_short);

        /* Find the starting offset in the file.
         * FIXME: We have a potential problem here in that ROSE sections are always contiguous in the file but a section created
         *        from an RVA/Size pair is not necessarily contiguous in the file.  Normally such sections are in fact
         *        contiguous and we'll just ignore this for now.  In any case, as long as these sections only ever read their
         *        data via the same MemoryMap that we use here, everything should be fine. [RPM 2009-08-17] */
        MemoryMap *map = get_loader_map();
        ROSE_ASSERT(map!=NULL);
        const MemoryMap::MapElement *elmt = map->find(get_base_va() + pair->get_e_rva());
        if (!elmt) {
            fprintf(stderr, "SgAsmPEFileHeader::create_table_sections: warning: pair-%zu, rva=0x%08"PRIx64", size=%"PRIu64
                    " bytes \"%s\": unable to find a mapping for the virtual address (skipping)\n",
                    i, pair->get_e_rva().get_rva(), pair->get_e_size(), tabname.c_str());
            continue;
        }
        rose_addr_t file_offset = elmt->is_anonymous() ? 0 : elmt->get_va_offset(get_base_va() + pair->get_e_rva(), 1);

        /* Create the new section */
        SgAsmGenericSection *tabsec = NULL;
        switch (i) {
            case 0: {
                /* Sometimes export sections are represented by a ".edata" section, and sometimes they're represented by an
                 * RVA/Size pair, and sometimes both point to the same part of the file. We don't want the exports duplicated
                 * in the AST, so we only create this table as exports if we haven't already seen some other export section. */
                SgAsmGenericSectionPtrList &sections = get_sections()->get_sections();
                bool seen_exports = false;
                for (SgAsmGenericSectionPtrList::iterator si=sections.begin(); !seen_exports && si!=sections.end(); ++si)
                    seen_exports = isSgAsmPEExportSection(*si);
                if (seen_exports) {
                    tabsec = new SgAsmGenericSection(get_file(), this);
                } else {
                    tabsec = new SgAsmPEExportSection(this);
                }
                break;
            }
            case 1: {
                /* Sometimes import sections are represented by a ".idata" section, and sometimes they're represented by an
                 * RVA/Size pair, and sometimes both point to the same part of the file.  We don't want the imports duplicated
                 * in the AST, so we only create this table as imports if we haven't already seen some other import section. */
                SgAsmGenericSectionPtrList &sections = get_sections()->get_sections();
                bool seen_imports = false;
                for (SgAsmGenericSectionPtrList::iterator si=sections.begin(); !seen_imports && si!=sections.end(); ++si)
                    seen_imports = isSgAsmPEImportSection(*si);
                if (seen_imports) {
                    tabsec = new SgAsmGenericSection(get_file(), this);
                } else {
                    tabsec = new SgAsmPEImportSection(this);
                }
                break;
            }
            default: {
                tabsec = new SgAsmGenericSection(get_file(), this);
                break;
            }
        }
        tabsec->set_name(new SgAsmBasicString(tabname));
        tabsec->set_short_name(tabname_short);
        tabsec->set_synthesized(true);
        tabsec->set_purpose(SP_HEADER);

        tabsec->set_offset(file_offset);
        tabsec->set_size(pair->get_e_size());
        tabsec->set_file_alignment(1);

        tabsec->set_mapped_alignment(1);
        tabsec->set_mapped_preferred_rva(pair->get_e_rva().get_rva());
        tabsec->set_mapped_actual_va(pair->get_e_rva().get_rva()+get_base_va()); /*FIXME: not sure this is correct. [RPM 2009-09-11]*/
        tabsec->set_mapped_size(pair->get_e_size());
        tabsec->set_mapped_rperm(true);
        tabsec->set_mapped_wperm(false);
        tabsec->set_mapped_xperm(false);
        pair->set_section(tabsec);
        pair->set_e_rva(pair->get_e_rva().set_section(tabsec));
    }

    /* Now parse the sections */
    for (size_t i=0; i<p_rvasize_pairs->get_pairs().size(); i++) {
        SgAsmPERVASizePair *pair = p_rvasize_pairs->get_pairs()[i];
        SgAsmGenericSection *tabsec = pair->get_section();
        if (tabsec)
            tabsec->parse();
    }
}
/* Looks at the RVA/Size pairs in the PE header and creates an SgAsmGenericSection object for each one.  This must be done
 * after we build the mapping from virtual addresses to file offsets. */
void
SgAsmPEFileHeader::create_table_sections()
{

    /* First, only create the sections. */
    for (size_t i=0; i<p_rvasize_pairs->get_pairs().size(); i++) {
        SgAsmPERVASizePair *pair = p_rvasize_pairs->get_pairs()[i];
        if (0==pair->get_e_size())
            continue;

        /* Table names come from PE file specification and are hard coded by RVA/Size pair index */
        const char *tabname_short;
        std::string tabname = rvasize_pair_name((PairPurpose)i, &tabname_short);

        /* Find the starting offset in the file.
         * FIXME: We have a potential problem here in that ROSE sections are always contiguous in the file but a section created
         *        from an RVA/Size pair is not necessarily contiguous in the file.  Normally such sections are in fact
         *        contiguous and we'll just ignore this for now.  In any case, as long as these sections only ever read their
         *        data via the same MemoryMap that we use here, everything should be fine. [RPM 2009-08-17] */
        rose_addr_t pair_va = get_base_va() + pair->get_e_rva();
        MemoryMap::Ptr map = get_loader_map();
        ROSE_ASSERT(map!=NULL);
        if (!map->baseSize(pair_va, pair->get_e_size()).exists(Sawyer::Container::MATCH_WHOLE)) {
            mlog[WARN] <<"SgAsmPEFileHeader::create_table_sections: pair-" <<i
                       <<", rva=" <<StringUtility::addrToString(pair->get_e_rva().get_rva())
                       <<", size=" <<StringUtility::plural(pair->get_e_size(), "bytes")
                       <<" \"" <<StringUtility::cEscape(tabname) <<"\":"
                       <<" unable to find a mapping for the virtual address (skipping)\n";
            continue;
        }
        const MemoryMap::Node &me = *map->at(pair_va).findNode();
        rose_addr_t file_offset = me.value().offset() + pair_va - me.key().least();

        /* Create the new section */
        SgAsmGenericSection *tabsec = NULL;
        switch (i) {
            case 0: {
                /* Sometimes export sections are represented by a ".edata" section, and sometimes they're represented by an
                 * RVA/Size pair, sometimes both point to the same part of the file, and sometimes the RVA/Size pair points to
                 * a different part of the file. We don't want the exports duplicated in the AST, so we only create this table
                 * as exports if we haven't already seen some other export section. */
                SgAsmGenericSectionPtrList &sections = get_sections()->get_sections();
                bool seen_exports = false;
                for (SgAsmGenericSectionPtrList::iterator si=sections.begin(); !seen_exports && si!=sections.end(); ++si)
                    seen_exports = isSgAsmPEExportSection(*si);
                if (seen_exports) {
                    tabsec = new SgAsmGenericSection(get_file(), this);
                } else {
                    tabsec = new SgAsmPEExportSection(this);
                }
                break;
            }
            case 1: {
                /* Sometimes import sections are represented by a ".idata" section, and sometimes they're represented by an
                 * RVA/Size pair, and sometimes both point to the same part of the file.  We don't want the imports duplicated
                 * in the AST, so we only create this table as imports if we haven't already seen some other import section. */
                SgAsmGenericSectionPtrList &sections = get_sections()->get_sections();
                bool seen_imports = false;
                for (SgAsmGenericSectionPtrList::iterator si=sections.begin(); !seen_imports && si!=sections.end(); ++si)
                    seen_imports = isSgAsmPEImportSection(*si);
                if (seen_imports) {
                    tabsec = new SgAsmGenericSection(get_file(), this);
                } else {
                    tabsec = new SgAsmPEImportSection(this);
                }
                break;
            }
            default: {
                tabsec = new SgAsmGenericSection(get_file(), this);
                break;
            }
        }
        tabsec->set_name(new SgAsmBasicString(tabname));
        tabsec->set_short_name(tabname_short);
        tabsec->set_synthesized(true);
        tabsec->set_purpose(SP_HEADER);

        tabsec->set_offset(file_offset);
        tabsec->set_size(pair->get_e_size());
        tabsec->set_file_alignment(1);

        tabsec->set_mapped_alignment(1);
        tabsec->set_mapped_preferred_rva(pair->get_e_rva().get_rva());
        tabsec->set_mapped_actual_va(pair->get_e_rva().get_rva()+get_base_va()); /*FIXME: not sure this is correct. [RPM 2009-09-11]*/
        tabsec->set_mapped_size(pair->get_e_size());
        tabsec->set_mapped_rperm(true);
        tabsec->set_mapped_wperm(false);
        tabsec->set_mapped_xperm(false);
        pair->set_section(tabsec);
        pair->set_e_rva(pair->get_e_rva().set_section(tabsec));
    }

    /* Now parse the sections */
    for (size_t i=0; i<p_rvasize_pairs->get_pairs().size(); i++) {
        SgAsmPERVASizePair *pair = p_rvasize_pairs->get_pairs()[i];
        SgAsmGenericSection *tabsec = pair->get_section();
        if (tabsec)
            tabsec->parse();
    }
}