Example #1
0
/** Attaches a previously unattached PE Section to the PE Section Table. This method complements
 *  SgAsmPESection::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. */
void
SgAsmPESectionTable::add_section(SgAsmPESection *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 */
    
    SgAsmPEFileHeader *fhdr = dynamic_cast<SgAsmPEFileHeader*>(get_header());
    ROSE_ASSERT(fhdr!=NULL);
    
    /* Assign an ID if there isn't one yet. */
    if (section->get_id()<0) {
        SgAsmGenericSectionList *seclist = fhdr->get_sections();;
        int max_id=0; /*assume zero is used so we start at one*/
        for (size_t i=0; i<seclist->get_sections().size(); i++) {
            SgAsmGenericSection *s = seclist->get_sections()[i];

                        max_id = std::max(max_id, s->get_id());

                }
        section->set_id(max_id+1);
    }
    
    /* Create a new section table entry. */
    SgAsmPESectionTableEntry *entry = new SgAsmPESectionTableEntry;
    entry->update_from_section(section);
    section->set_section_entry(entry);
}
Example #2
0
/** Returns the base address of an addressable IR node. */
uint64_t
SgAsmIntegerValueExpression::virtual_address(SgNode *node)
{
    if (!node)
        return 0;
    if (isSgAsmFunction(node))
        return isSgAsmFunction(node)->get_entry_va();
    if (isSgAsmStatement(node)) // instructions, block, function, staticdata, ...
        return isSgAsmStatement(node)->get_address();
    if (isSgAsmGenericSymbol(node))
        return isSgAsmGenericSymbol(node)->get_value();
    if (isSgAsmPEImportItem(node))
        return isSgAsmPEImportItem(node)->get_bound_rva().get_va();
    if (isSgAsmPERVASizePair(node))
        return isSgAsmPERVASizePair(node)->get_e_rva().get_va();
    if (isSgAsmGenericSection(node)) {
        SgAsmGenericSection *section = isSgAsmGenericSection(node);
        if (section->is_mapped())
            return section->get_mapped_actual_va();
        return 0;
    }

    std::cerr <<"SgAsmIntegerValueExpression::virtual_address: non-addressable node type: "
              <<stringifyVariantT(node->variantT(), "V_") <<std::endl;
    assert(!"need addressable node type"); // to get location info in error messsage
    abort(); // if asserts are disabled
}
Example #3
0
/* Creates the storage item for the string at the specified offset. If "shared" is true then attempt to re-use a previous storage
 * object, otherwise create a new one. Each storage object is considered to be a separate string, therefore when two strings
 * share the same storage object, changing one string changes the other. */
SgAsmStringStorage *
SgAsmCoffStrtab::create_storage(rose_addr_t offset, bool shared)
{
    ROSE_ASSERT(offset!=SgAsmGenericString::unallocated);
    SgAsmGenericSection *container = get_container();

    /* Has the string already been created? */
    if (shared) {
        for (referenced_t::iterator i=p_storage_list.begin(); i!=p_storage_list.end(); ++i) {
            if ((*i)->get_offset()==offset && (*i)!=p_dont_free)
                return *i;
        }
    }

    /* Read string length byte */
    unsigned char byte;
    container->read_content_local(offset, &byte, 1);
    unsigned len = byte;

    /* Make sure new storage isn't inside some other string. (We don't support nested strings in COFF where the length byte of
     * the nested string is one of the characters of the outer string.) */
    for (referenced_t::iterator i=p_storage_list.begin(); i!=p_storage_list.end(); ++i) {
        ROSE_ASSERT((*i)->get_offset()==SgAsmGenericString::unallocated ||
                    offset + 1 + len <= (*i)->get_offset() ||
                    offset >= 1 + (*i)->get_string().size());
    }

    /* Create storage object */
    char *buf = new char[len];
    container->read_content_local(offset+1, buf, len);
    SgAsmStringStorage *storage = new SgAsmStringStorage(this, std::string(buf, len), offset);
    delete[] buf;

    /* It's a bad idea to free (e.g., modify) strings before we've identified all the strings in the table. Consider
     * the case where two strings have the same value and point to the same offset (i.e., they share storage). If we modify one
     * before we know about the other then (at best) we modify the other one also.
     *
     * The only time we can guarantee this is OK is when the new storage points to the same file location as "dont_free"
     * since the latter is guaranteed to never be freed or shared. This exception is used when creating a new, unallocated
     * string (see SgAsmStoredString(SgAsmGenericStrtab,const std::string&)). */
    if (p_num_freed>0 && (!p_dont_free || offset!=p_dont_free->get_offset())) {
        fprintf(stderr,
                "SgAsmCoffStrtab::create_storage(%"PRIu64"): %zu other string%s (of %zu created) in [%d] \"%s\""
                " %s been modified and/or reallocated!\n",
                offset, p_num_freed, 1==p_num_freed?"":"s", p_storage_list.size(),
                container->get_id(), container->get_name()->get_string(true).c_str(),
                1==p_num_freed?"has":"have");
        ROSE_ASSERT(0==p_num_freed);
    }

    set_isModified(true);
    p_storage_list.push_back(storage);
    return storage;
}
/* Same as parent, but also includes sections that aren't mapped but which contain code. */
SgAsmGenericSectionPtrList
BinaryLoaderElfObj::get_remap_sections(SgAsmGenericHeader *header)
{
    SgAsmGenericSectionPtrList retval = BinaryLoaderElf::get_remap_sections(header);
    const SgAsmGenericSectionPtrList &sections = header->get_sections()->get_sections();
    for (SgAsmGenericSectionPtrList::const_iterator si=sections.begin(); si!=sections.end(); ++si) {
        SgAsmGenericSection *section = *si;
        if (!section->is_mapped() && section->get_contains_code())
            retval.push_back(section);
    }
    return retval;
}
Example #5
0
/** Update all the RVA/Size pair info from the section to which it points. */
void
SgAsmPEFileHeader::update_rvasize_pairs()
{
    for (size_t i=0; i<get_rvasize_pairs()->get_pairs().size(); i++) {
        SgAsmPERVASizePair *pair = get_rvasize_pairs()->get_pairs()[i];
        SgAsmGenericSection *section = pair->get_section();
        if (section) {
            pair->set_e_rva(rose_rva_t(section->get_mapped_preferred_rva(), section));
            pair->set_e_size(section->get_mapped_size());
        }
    }
}
Example #6
0
/** Returns sections that have a preferred mapping that includes the specified relative virtual address. */
SgAsmGenericSectionPtrList
SgAsmGenericHeader::get_sections_by_rva(rose_addr_t rva) const
{
    SgAsmGenericSectionPtrList retval;
    for (SgAsmGenericSectionPtrList::iterator i = p_sections->get_sections().begin(); i!=p_sections->get_sections().end(); ++i) {
        SgAsmGenericSection *section = *i;
        if (section->is_mapped() &&
            rva >= section->get_mapped_preferred_rva() && rva < section->get_mapped_preferred_rva() + section->get_mapped_size()) {
            retval.push_back(section);
        }
    }
    return retval;
}
Example #7
0
/** Write string table back to disk. Free space is zeroed out; holes are left as they are. */
void
SgAsmElfStrtab::unparse(std::ostream &f) const
{
    SgAsmGenericSection *container = get_container();
    
    /* Write strings with NUL termination. Shared strings will be written more than once, but that's OK. */
    for (size_t i=0; i<p_storage_list.size(); i++) {
        SgAsmStringStorage *storage = p_storage_list[i];
        ROSE_ASSERT(storage->get_offset()!=SgAsmGenericString::unallocated);
        rose_addr_t at = container->write(f, storage->get_offset(), storage->get_string());
        container->write(f, at, '\0');
    }
    
    /* Fill free areas with zero */
    BOOST_FOREACH (const AddressInterval &interval, get_freelist().intervals())
        container->write(f, interval.least(), std::string(interval.size(), '\0'));
}
Example #8
0
/* Write string table back to disk. Free space is zeroed out; holes are left as they are. */
void
SgAsmCoffStrtab::unparse(std::ostream &f) const
{
    SgAsmGenericSection *container = get_container();

    /* Write length coded strings. Shared strings will be written more than once, but that's OK. */
    for (size_t i=0; i<p_storage_list.size(); i++) {
        SgAsmStringStorage *storage = p_storage_list[i];
        ROSE_ASSERT(storage->get_offset()!=SgAsmGenericString::unallocated);
        rose_addr_t at = container->write(f, storage->get_offset(), storage->get_string());
        container->write(f, at, '\0');
    }

    /* Fill free areas with zero */
    for (ExtentMap::const_iterator i=get_freelist().begin(); i!=get_freelist().end(); ++i) {
        container->write(f, i->first.first(), std::string(i->first.size(), '\0'));
    }
}
Example #9
0
/** Returns sections having a preferred or actual mapping that includes the specified virtual address.  If @p use_preferred is
 *  set, then the condition is evaluated by looking at the section's preferred mapping, otherwise the actual mapping is used.
 *  If an actual mapping is used, the specified virtual address must be part of the actual mapped section, not merely in the
 *  memory region that was also mapped to satisfy alignment constraints. */
SgAsmGenericSectionPtrList
SgAsmGenericHeader::get_sections_by_va(rose_addr_t va, bool use_preferred) const
{
    if (use_preferred) {
        if (va < get_base_va())
            return SgAsmGenericSectionPtrList();
        rose_addr_t rva = va - get_base_va();
        return get_sections_by_rva(rva);
    }
     
    SgAsmGenericSectionPtrList retval;
    for (size_t i=0; i<p_sections->get_sections().size(); i++) {
        SgAsmGenericSection *section = p_sections->get_sections()[i];
        if (section->is_mapped() &&
            va>=section->get_mapped_actual_va() && va<section->get_mapped_actual_va()+section->get_mapped_size())
            retval.push_back(section);
    }
    return retval;
}
Example #10
0
/** Class method that prints info about offsets into known sections */
void
SgAsmGenericSection::dump_containing_sections(FILE *f, const std::string &prefix, rose_rva_t rva,
                                              const SgAsmGenericSectionPtrList &slist)
{
    for (size_t i=0; i<slist.size(); i++) {
        SgAsmGenericSection *s = slist[i];
        if (s->is_mapped() && rva>=s->get_mapped_preferred_rva() && rva<s->get_mapped_preferred_rva()+s->get_mapped_size()) {
            rose_addr_t offset = rva - s->get_mapped_preferred_rva();
            fprintf(f, "%-*s   is 0x%08"PRIx64" (%"PRIu64") bytes into section [%d] \"%s\"\n",
                    DUMP_FIELD_WIDTH, prefix.c_str(), offset, offset, s->get_id(), s->get_name()->get_string(true).c_str());
        }
    }
}
/** Returns the base address of an addressable IR node. */
uint64_t
SgAsmIntegerValueExpression::virtualAddress(SgNode *node)
{
    if (!node)
        return 0;
    if (isSgAsmFunction(node))
        return isSgAsmFunction(node)->get_entry_va();
    if (isSgAsmStatement(node)) // instructions, block, function, staticdata, ...
        return isSgAsmStatement(node)->get_address();
    if (isSgAsmGenericSymbol(node))
        return isSgAsmGenericSymbol(node)->get_value();
    if (isSgAsmPEImportItem(node))
        return isSgAsmPEImportItem(node)->get_bound_rva().get_va();
    if (isSgAsmPERVASizePair(node))
        return isSgAsmPERVASizePair(node)->get_e_rva().get_va();
    if (isSgAsmGenericSection(node)) {
        SgAsmGenericSection *section = isSgAsmGenericSection(node);
        if (section->is_mapped())
            return section->get_mapped_actual_va();
        return 0;
    }

    ASSERT_not_reachable("need addressable node type, got " + stringifyVariantT(node->variantT(), "V_"));
}
Example #12
0
/** Returns sectons in this header that contain all of the specified portion of the file. */
SgAsmGenericSectionPtrList
SgAsmGenericHeader::get_sections_by_offset(rose_addr_t offset, rose_addr_t size) const
{
    SgAsmGenericSectionPtrList retval;
    for (SgAsmGenericSectionPtrList::iterator i=p_sections->get_sections().begin(); i!=p_sections->get_sections().end(); ++i) {
        SgAsmGenericSection *section = *i;
        if (offset >= section->get_offset() &&
            offset < section->get_offset()+section->get_size() &&
            offset-section->get_offset() + size <= section->get_size())
            retval.push_back(section);
    }
    return retval;
}
Example #13
0
/* Print some debugging info */
void
SgAsmGenericHeader::dump(FILE *f, const char *prefix, ssize_t idx) const
{
    char p[4096];
    if (idx>=0) {
        sprintf(p, "%sHeader[%zd].", prefix, idx);
    } else {
        sprintf(p, "%sHeader.", prefix);
    }
    const int w = std::max(1, DUMP_FIELD_WIDTH-(int)strlen(p));

    SgAsmGenericSection::dump(f, p, -1);

    ROSE_ASSERT(p_exec_format != NULL);
    p_exec_format->dump(f, p, -1);

    fprintf(f, "%s%-*s = 0x%x (%s)\n", p, w, "ins_arch",
            p_isa, stringifySgAsmExecutableFileFormatInsSetArchitecture(p_isa).c_str());

    fprintf(f, "%s%-*s = \"", p, w, "magic");
    for (size_t i = 0; i < p_magic.size(); i++) {
        switch (p_magic[i]) {
          case '\\': fputs("\\\\", f); break;
          case '\n': fputs("\\n", f); break;
          case '\r': fputs("\\r", f); break;
          case '\t': fputs("\\t", f); break;
          default:
            if (isprint(p_magic[i])) {
                fputc(p_magic[i], f);
            } else {
                fprintf(f, "\\%03o", (unsigned)p_magic[i]);
            }
            break;
        }
    }
    fputs("\"\n", f);

    /* Base virtual address and entry addresses */
    fprintf(f, "%s%-*s = 0x%08" PRIx64" (%" PRIu64")\n", p, w, "base_va", get_base_va(), get_base_va());
    fprintf(f, "%s%-*s = %" PRIuPTR " entry points\n", p, w, "entry_rva.size", p_entry_rvas.size());
    for (size_t i = 0; i < p_entry_rvas.size(); i++) {
        char label[64];
        sprintf(label, "entry_rva[%" PRIuPTR "]", i);
        rose_addr_t entry_rva = p_entry_rvas[i].get_rva();
        fprintf(f, "%s%-*s = 0x%08" PRIx64 " (%" PRIu64 ")\n", p, w, label, entry_rva, entry_rva);
        SgAsmGenericSectionPtrList sections = get_file()->get_sections();
        dump_containing_sections(f, std::string(p)+label, entry_rva, sections);
    }

    fprintf(f, "%s%-*s = %" PRIuPTR " sections\n", p, w, "section", p_sections->get_sections().size());
    for (size_t i=0; i<p_sections->get_sections().size(); i++) {
        SgAsmGenericSection *section = p_sections->get_sections()[i];
        char label[1024];
        sprintf(label, "section[%" PRIuPTR "]", i);
        fprintf(f, "%s%-*s = [%d] \"%s\"\n", p, w, label, section->get_id(), section->get_name()->get_string(true).c_str());
    }
    
    fprintf(f, "%s%-*s = %" PRIuPTR " entries\n", p, w, "DLL.size", p_dlls->get_dlls().size());
    for (size_t i = 0; i < p_dlls->get_dlls().size(); i++)
        p_dlls->get_dlls()[i]->dump(f, p, i);
}
Example #14
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();
    }
}
Example #15
0
void
SgAsmGenericFile::shift_extend(SgAsmGenericSection *s, rose_addr_t sa, rose_addr_t sn, AddressSpace space, Elasticity elasticity)
{
    ROSE_ASSERT(s!=NULL);
    ROSE_ASSERT(s->get_file()==this);
    ROSE_ASSERT((space & (ADDRSP_FILE|ADDRSP_MEMORY)) != 0);

    const bool debug = false;
    static size_t ncalls=0;
    char p[256];

    if (debug) {
        const char *space_s="unknown";
        if (space & ADDRSP_FILE) {
            space_s = "file";
        } else if (space & ADDRSP_MEMORY) {
            space_s = "memory";
        }
        sprintf(p, "SgAsmGenericFile::shift_extend[%" PRIuPTR "]: ", ncalls++);
        fprintf(stderr, "%s    -- START --\n", p);
        fprintf(stderr, "%s    S = [%d] \"%s\"\n", p, s->get_id(), s->get_name()->get_string(true).c_str());
        fprintf(stderr, "%s    %s Sa=0x%08" PRIx64 " (%" PRIu64 "), Sn=0x%08" PRIx64 " (%" PRIu64 ")\n",
                p, space_s, sa, sa, sn, sn);
        fprintf(stderr, "%s    elasticity = %s\n", p, (ELASTIC_NONE==elasticity ? "none" :
                                                       ELASTIC_UNREF==elasticity ? "unref" :
                                                       ELASTIC_HOLE==elasticity ? "unref+holes" :
                                                       "unknown"));
    }

    /* No-op case */
    if (0==sa && 0==sn) {
        if (debug) {
            fprintf(stderr, "%s    No change necessary.\n", p);
            fprintf(stderr, "%s    -- END --\n", p);
        }
        return;
    }

    bool filespace = (space & ADDRSP_FILE)!=0;
    bool memspace = (space & ADDRSP_MEMORY)!=0;
    rose_addr_t align=1, aligned_sa, aligned_sasn;
    SgAsmGenericSectionPtrList neighbors, villagers;
    ExtentMap amap; /* address mappings for all extents */
    Extent sp;

    /* Get a list of all sections that may need to be adjusted. */
    SgAsmGenericSectionPtrList all;
    switch (elasticity) {
      case ELASTIC_NONE:
      case ELASTIC_UNREF:
        all = filespace ? get_sections() : get_mapped_sections();
        break;
      case ELASTIC_HOLE:
        all = filespace ? get_sections(false) : get_mapped_sections();
        break;
    }
    if (debug) {
        fprintf(stderr, "%s    Following sections are in 'all' set:\n", p);
        for (size_t i=0; i<all.size(); i++) {
            Extent ep;
            if (filespace) {
                ep = all[i]->get_file_extent();
            } else {
                ROSE_ASSERT(all[i]->is_mapped());
                ep = all[i]->get_mapped_preferred_extent();
            }
            fprintf(stderr, "%s        0x%08" PRIx64 " 0x%08" PRIx64 " 0x%08" PRIx64 " [%d] \"%s\"\n",
                    p, ep.relaxed_first(), ep.size(), ep.relaxed_first()+ep.size(), all[i]->get_id(),
                    all[i]->get_name()->get_string(true).c_str());
        }
    }

    for (size_t pass=0; pass<2; pass++) {
        if (debug) {
            fprintf(stderr, "%s    -- %s --\n",
                    p, 0==pass?"FIRST PASS":"******");
        }

        /* S offset and size in file or memory address space */
        if (filespace) {
            sp = s->get_file_extent();
        } else if (!memspace || !s->is_mapped()) {
            return; /*nothing to do*/
        } else {
            sp = s->get_mapped_preferred_extent();
        }

        /* Build address map */
        for (size_t i=0; i<all.size(); i++) {
            if (filespace) {
                amap.insert(all[i]->get_file_extent());
            } else {
                ROSE_ASSERT(all[i]->is_mapped());
                amap.insert(all[i]->get_mapped_preferred_extent());
            }
        }
        if (debug) {
            fprintf(stderr, "%s    Address map:\n", p);
            amap.dump_extents(stderr, (std::string(p)+"        ").c_str(), "amap");
            fprintf(stderr, "%s    Extent of S:\n", p);
            fprintf(stderr, "%s        start=0x%08" PRIx64 " size=0x%08" PRIx64 " end=0x%08" PRIx64 "\n",
                    p, sp.relaxed_first(), sp.size(), sp.relaxed_first()+sp.size());
        }

        /* Neighborhood (nhs) of S is a single extent. However, if S is zero size then nhs might be empty.  The neighborhood of
         * S is S plus all sections that overlap with S and all sections that are right-contiguous with S. */
        ExtentMap nhs_map;
        for (ExtentMap::iterator amapi=amap.begin(); amapi!=amap.end(); ++amapi) {
            if (amapi->first.relaxed_first() <= sp.relaxed_first()+sp.size() &&
                amapi->first.relaxed_first()+amapi->first.size() > sp.relaxed_first())
                nhs_map.insert(amapi->first, amapi->second);
        }
        if (debug) {
            fprintf(stderr, "%s    Neighborhood of S:\n", p);
            nhs_map.dump_extents(stderr, (std::string(p)+"        ").c_str(), "nhs_map");
        }
        Extent nhs;
        if (nhs_map.size()>0) {
            assert(nhs_map.nranges()==1);
            nhs = nhs_map.begin()->first;
        } else {
            nhs = sp;
        }

        /* What sections are in the neighborhood (including S), and right of the neighborhood? */
        neighbors.clear(); /*sections in neighborhood*/
        neighbors.push_back(s);
        villagers.clear(); /*sections right of neighborhood*/
        if (debug)
            fprintf(stderr, "%s    Ignoring left (L) sections:\n", p);
        for (size_t i=0; i<all.size(); i++) {
            SgAsmGenericSection *a = all[i];
            if (a==s) continue; /*already pushed onto neighbors*/
            Extent ap;
            if (filespace) {
                ap = a->get_file_extent();
            } else if (!a->is_mapped()) {
                continue;
            } else {
                ap = a->get_mapped_preferred_extent();
            }
            switch (ExtentMap::category(ap, nhs)) {
              case 'L':
                if (debug)
                    fprintf(stderr, "%s        L 0x%08" PRIx64 " 0x%08" PRIx64 " 0x%08" PRIx64 " [%d] \"%s\"\n",
                            p, ap.relaxed_first(), ap.size(), ap.relaxed_first()+ap.size(),
                            a->get_id(), a->get_name()->get_string(true).c_str());
                break;
              case 'R':
                  if (ap.relaxed_first()==nhs.relaxed_first()+nhs.size() && 0==ap.size()) {
                    /* Empty sections immediately right of the neighborhood of S should actually be considered part of the
                     * neighborhood rather than right of it. */
                    neighbors.push_back(a);
                } else if (elasticity!=ELASTIC_NONE) {
                    /* If holes are elastic then treat things right of the hole as being part of the right village; otherwise
                     * add those sections to the neighborhood of S even though they fall outside 'nhs' (it's OK because this
                     * partitioning of sections is the only thing we use 'nhs' for anyway. */
                    villagers.push_back(a);
                } else if ('L'==ExtentMap::category(ap, sp)) {
                    /*ignore sections left of S*/
                } else {
                    neighbors.push_back(a);
                }
                break;
              default:
                if ('L'!=ExtentMap::category(ap, sp)) /*ignore sections left of S*/
                    neighbors.push_back(a);
                break;
            }
        }
        if (debug) {
            fprintf(stderr, "%s    Neighbors:\n", p);
            for (size_t i=0; i<neighbors.size(); i++) {
                SgAsmGenericSection *a = neighbors[i];
                Extent ap = filespace ? a->get_file_extent() : a->get_mapped_preferred_extent();
                rose_addr_t align = filespace ? a->get_file_alignment() : a->get_mapped_alignment();
                char cat = ExtentMap::category(ap, sp);
                fprintf(stderr, "%s        %c %c0x%08" PRIx64 " 0x%08" PRIx64 " 0x%08" PRIx64,
                        p, cat, 0==ap.relaxed_first() % (align?align:1) ? ' ' : '!',
                        ap.relaxed_first(), ap.size(), ap.relaxed_first()+ap.size());
                if (strchr("RICE", cat)) {
                    fprintf(stderr, " align=0x%08" PRIx64, align);
                } else {
                    fputs("                 ", stderr);
                }
                fprintf(stderr, " [%2d] \"%s\"\n", a->get_id(), a->get_name()->get_string(true).c_str());
            }
            if (villagers.size()>0) fprintf(stderr, "%s    Villagers:\n", p);
            for (size_t i=0; i<villagers.size(); i++) {
                SgAsmGenericSection *a = villagers[i];
                Extent ap = filespace ? a->get_file_extent() : a->get_mapped_preferred_extent();
                rose_addr_t align = filespace ? a->get_file_alignment() : a->get_mapped_alignment();
                fprintf(stderr, "%s        %c %c0x%08" PRIx64 " 0x%08" PRIx64 " 0x%08" PRIx64,
                        p, ExtentMap::category(ap, sp), /*cat should always be R*/
                        0==ap.relaxed_first() % (align?align:1) ? ' ' : '!',
                        ap.relaxed_first(), ap.size(), ap.relaxed_first()+ap.size());
                fputs("                 ", stderr);
                fprintf(stderr, " [%2d] \"%s\"\n", a->get_id(), a->get_name()->get_string(true).c_str());
            }
        }

        /* Adjust Sa to satisfy all alignment constraints in neighborhood(S) for sections that will move (cats R, I, C, and E). */
        align = 1;
        for (size_t i=0; i<neighbors.size(); i++) {
            SgAsmGenericSection *a = neighbors[i];
            Extent ap = filespace ? a->get_file_extent() : a->get_mapped_preferred_extent();
            if (strchr("RICE", ExtentMap::category(ap, sp))) {
                rose_addr_t x = filespace ? a->get_file_alignment() : a->get_mapped_alignment();
#if BOOST_VERSION < 106900
                align = boost::math::lcm(align, x?x:1); // deprecated in boost-1.69.0
#else
                align = boost::integer::lcm(align, x?x:1); // not present before boost-1.60.0
#endif
            }
        }
        aligned_sa = (sa/align + (sa%align?1:0))*align;
        aligned_sasn = ((sa+sn)/align + ((sa+sn)%align?1:0))*align;
        if (debug) {
            fprintf(stderr, "%s    Alignment LCM = 0x%08" PRIx64 " (%" PRIu64 ")\n", p, align, align);
            fprintf(stderr, "%s    Aligned Sa    = 0x%08" PRIx64 " (%" PRIu64 ")\n", p, aligned_sa, aligned_sa);
            fprintf(stderr, "%s    Aligned Sa+Sn = 0x%08" PRIx64 " (%" PRIu64 ")\n", p, aligned_sasn, aligned_sasn);
        }

        /* Are there any sections to the right of neighborhood(S)? If so, find the one with the lowest start address and use
         * that to define the size of the hole right of neighborhood(S). */
        if (0==villagers.size()) break;
        SgAsmGenericSection *after_hole = NULL;
        Extent hp(0, 0);
        for (size_t i=0; i<villagers.size(); i++) {
            SgAsmGenericSection *a = villagers[i];
            Extent ap = filespace ? a->get_file_extent() : a->get_mapped_preferred_extent();
            if (!after_hole || ap.relaxed_first()<hp.relaxed_first()) {
                after_hole = a;
                hp = ap;
            }
        }
        ROSE_ASSERT(after_hole);
        ROSE_ASSERT(hp.relaxed_first() > nhs.relaxed_first()+nhs.size());
        rose_addr_t hole_size = hp.relaxed_first() - (nhs.relaxed_first()+nhs.size());
        if (debug) {
            fprintf(stderr, "%s    hole size = 0x%08" PRIx64 " (%" PRIu64 "); need 0x%08" PRIx64 " (%" PRIu64 "); %s\n",
                    p, hole_size, hole_size, aligned_sasn, aligned_sasn,
                    hole_size>=aligned_sasn ? "large enough" : "not large enough");
        }
        if (hole_size >= aligned_sasn) break;
        rose_addr_t need_more = aligned_sasn - hole_size;

        /* Hole is not large enough. We need to recursively move things that are right of our neighborhood, then recompute the
         * all-sections address map and neighborhood(S). */
        ROSE_ASSERT(0==pass); /*logic problem since the recursive call should have enlarged the hole enough*/
        if (debug) {
            fprintf(stderr, "%s    Calling recursively to increase hole size by 0x%08" PRIx64 " (%" PRIu64 ") bytes\n",
                    p, need_more, need_more);
        }
        shift_extend(after_hole, need_more, 0, space, elasticity);
        if (debug) fprintf(stderr, "%s    Returned from recursive call\n", p);
    }

    /* Consider sections that are in the same neighborhood as S */
    if (debug) fprintf(stderr, "%s    -- ADJUSTING --\n", p);
    bool resized_mem = false;
    for (size_t i=0; i<neighbors.size(); i++) {
        SgAsmGenericSection *a = neighbors[i];
        Extent ap = filespace ? a->get_file_extent() : a->get_mapped_preferred_extent();
        switch (ExtentMap::category(ap, sp)) {
          case 'L':
            break;
          case 'R':
            if (filespace) {
                a->set_offset(a->get_offset()+aligned_sasn);
            } else {
                a->set_mapped_preferred_rva(a->get_mapped_preferred_rva()+aligned_sasn);
            }
            break;
          case 'C': /*including S itself*/
          case 'E':
            if (filespace) {
                a->set_offset(a->get_offset()+aligned_sa);
                a->set_size(a->get_size()+sn);
                if (memspace && !resized_mem && a->is_mapped()) {
                    shift_extend(a, 0, sn, ADDRSP_MEMORY, elasticity);
                    resized_mem = true;
                }
            } else {
                a->set_mapped_preferred_rva(a->get_mapped_preferred_rva()+aligned_sa);
                a->set_mapped_size(a->get_mapped_size()+sn);
            }
            break;
          case 'O':
              if (ap.relaxed_first()==sp.relaxed_first()) {
                if (filespace) {
                    a->set_offset(a->get_offset()+aligned_sa);
                    a->set_size(a->get_size()+sn);
                } else {
                    a->set_mapped_preferred_rva(a->get_mapped_preferred_rva()+aligned_sa);
                    a->set_mapped_size(a->get_mapped_size()+sn);
                }
            } else {
                if (filespace) {
                    a->set_size(a->get_size()+aligned_sasn);
                    if (memspace && !resized_mem && a->is_mapped()) {
                        shift_extend(a, 0, aligned_sasn, ADDRSP_MEMORY, elasticity);
                        resized_mem = true;
                    }
                } else {
                    a->set_mapped_size(a->get_mapped_size()+aligned_sasn);
                }
            }
            break;
          case 'I':
            if (filespace) {
                a->set_offset(a->get_offset()+aligned_sa);
            } else {
                a->set_mapped_preferred_rva(a->get_mapped_preferred_rva()+aligned_sa);
            }
            break;
          case 'B':
            if (filespace) {
                a->set_size(a->get_size()+sn);
                if (memspace && !resized_mem && a->is_mapped()) {
                    shift_extend(a, 0, sn, ADDRSP_MEMORY, elasticity);
                    resized_mem = true;
                }
            } else {
                a->set_mapped_size(a->get_size()+sn);
            }
            break;
          default:
            ROSE_ASSERT(!"invalid extent category");
            break;
        }
        if (debug) {
            const char *space_name = filespace ? "file" : "mem";
            rose_addr_t x = filespace ? a->get_file_alignment() : a->get_mapped_alignment();
            fprintf(stderr, "%s   %4s-%c %c0x%08" PRIx64 " 0x%08" PRIx64 " 0x%08" PRIx64,
                    p, space_name, ExtentMap::category(ap, sp),
                    0==ap.relaxed_first()%(x?x:1)?' ':'!',
                    ap.relaxed_first(), ap.size(), ap.relaxed_first()+ap.size());
            Extent newap = filespace ? a->get_file_extent() : a->get_mapped_preferred_extent();
            fprintf(stderr, " -> %c0x%08" PRIx64 " 0x%08" PRIx64 " 0x%08" PRIx64,
                    0==newap.relaxed_first()%(x?x:1)?' ':'!',
                    newap.relaxed_first(), newap.size(), newap.relaxed_first()+newap.size());
            fprintf(stderr, " [%2d] \"%s\"\n", a->get_id(), a->get_name()->get_string(true).c_str());
        }
    }
    if (debug) fprintf(stderr, "%s    -- END --\n", p);
}
Example #16
0
DOTSynthesizedAttribute
AstDOTGeneration::evaluateSynthesizedAttribute(SgNode* node, DOTInheritedAttribute ia, SubTreeSynthesizedAttributes l)
   {
     SubTreeSynthesizedAttributes::iterator iter;
     ROSE_ASSERT(node);

  // printf ("AstDOTGeneration::evaluateSynthesizedAttribute(): node = %s \n",node->class_name().c_str());

  // DQ (5/3/2006): Skip this IR node if it is specified as such in the inherited attribute
     if (ia.skipSubTree == true)
        {
       // I am unclear if I should return NULL or node as a parameter to DOTSynthesizedAttribute
       // Figured this out: if we return a valid pointer then we get a node in the DOT graph 
       // (with just the pointer value as a label), where as if we return a DOTSynthesizedAttribute 
       // with a NUL pointer then the node will NOT appear in the DOT graph.
       // return DOTSynthesizedAttribute(node);
          return DOTSynthesizedAttribute(NULL);
        }

     string nodeoption;
     if(AstTests::isProblematic(node))
        {
       // cout << "problematic node found." << endl;
          nodeoption="color=\"orange\" ";
        }
     string nodelabel=string("\\n")+node->class_name();

  // DQ (1/24/2009): Added support for output of isForward flag in the dot graph.
     SgDeclarationStatement* genericDeclaration = isSgDeclarationStatement(node);
     if (genericDeclaration != NULL)
        {
       // At the moment the mnemonic name is stored, but it could be computed in the 
       // future from the kind and the tostring() function.
          string name = (genericDeclaration->isForward() == true) ? "isForward" : "!isForward";
          ROSE_ASSERT(name.empty() == false);

       // DQ (3/20/2011): Added class names to the generated dot file graphs of the AST.
          SgClassDeclaration* classDeclaration = isSgClassDeclaration(genericDeclaration);
          if (classDeclaration != NULL)
             {
               nodelabel += string("\\n") + classDeclaration->get_name();
             }

       // DQ (3/20/2011): Added function names to the generated dot file graphs of the AST.
          SgFunctionDeclaration* functionDeclaration = isSgFunctionDeclaration(genericDeclaration);
          if (functionDeclaration != NULL)
             {
               nodelabel += string("\\n") + functionDeclaration->get_name();
             }

          nodelabel += string("\\n") + name;
        }

  // DQ (4/6/2011): Added support for output of the name for SgInitializedName IR nodes.
     SgInitializedName* initializedName = isSgInitializedName(node);
     if (initializedName != NULL)
        {
          nodelabel += string("\\n") + initializedName->get_name();
        }

  // DQ (4/6/2011): Added support for output of the name for SgInitializedName IR nodes.
     SgIntVal* intValue = isSgIntVal(node);
     if (intValue != NULL)
        {
          nodelabel += string("\\n value = ") + StringUtility::numberToString(intValue->get_value());
        }

  // DQ (4/6/2011): Added support for output of the name for SgInitializedName IR nodes.
     SgVarRefExp* varRefExp = isSgVarRefExp(node);
     if (varRefExp != NULL)
        {
          SgVariableSymbol* variableSymbol = varRefExp->get_symbol();
          ROSE_ASSERT(variableSymbol != NULL);
          string name = variableSymbol->get_name();
          nodelabel += string("\\n name = ") + name;
        }

  // DQ (1/19/2009): Added support for output of what specific instrcution this is in the dot graph.
     SgAsmInstruction* genericInstruction = isSgAsmInstruction(node);
     if (genericInstruction != NULL)
        {
#ifdef ROSE_BUILD_BINARY_ANALYSIS_SUPPORT
       // At the moment the mnemonic name is stored, but it could be computed in the 
       // future from the kind and the tostring() function.
#if 1
          string unparsedInstruction = unparseInstruction(genericInstruction);
          string addressString       = StringUtility::numberToString( (void*) genericInstruction->get_address() );
       // string name = genericInstruction->get_mnemonic();
          string name = unparsedInstruction + "\\n address: " + addressString;
#else
          string name = unparsedInstruction + "\\n" + addressString;
#endif
          ROSE_ASSERT(name.empty() == false);

          nodelabel += string("\\n") + name;
#else
          printf ("Warning: In AstDOTGeneration.C ROSE_BUILD_BINARY_ANALYSIS_SUPPORT is not defined \n");
#endif
        }

     SgAsmExpression* genericExpression = isSgAsmExpression(node);
     if (genericExpression != NULL)
        {
#ifdef ROSE_BUILD_BINARY_ANALYSIS_SUPPORT
          string name = unparseExpression(genericExpression, NULL, NULL);
          ROSE_ASSERT(name.empty() == false);
          nodelabel += string("\\n") + name;
#else
          printf ("Warning: In AstDOTGeneration.C ROSE_BUILD_BINARY_ANALYSIS_SUPPORT is not defined \n");
#endif
        }

  // DQ (10/29/2008): Added some support for additional output of internal names for specific IR nodes.
  // In generall there are long list of these IR nodes in the binary and this helps make some sense of 
  // the lists (sections, symbols, etc.).
     SgAsmExecutableFileFormat* binaryFileFormatNode = isSgAsmExecutableFileFormat(node);
     if (binaryFileFormatNode != NULL)
        {
#ifdef ROSE_BUILD_BINARY_ANALYSIS_SUPPORT
       // The case of binary file format IR nodes can be especially confusing so we want the 
       // default to output some more specific information for some IR nodes (e.g. sections).
          string name;

          SgAsmGenericSection* genericSection = isSgAsmGenericSection(node);
          if (genericSection != NULL)
             {
               SgAsmGenericString* genericString = genericSection->get_name();
               ROSE_ASSERT(genericString != NULL);

               name = genericString->get_string();
             }

          SgAsmGenericSymbol* genericSymbol = isSgAsmGenericSymbol(node);
          if (genericSymbol != NULL)
             {
               SgAsmGenericString* genericString = genericSymbol->get_name();
               ROSE_ASSERT(genericString != NULL);

               name = genericString->get_string();

               if (name.empty() == true)
                    name = "no_name_for_symbol";
             }

          SgAsmGenericDLL* genericDLL = isSgAsmGenericDLL(node);
          if (genericDLL != NULL)
             {
               SgAsmGenericString* genericString = genericDLL->get_name();
               ROSE_ASSERT(genericString != NULL);

               name = genericString->get_string();
             }

          SgAsmPEImportItem* peImportItem = isSgAsmPEImportItem(node);
          if (peImportItem != NULL)
             {
               SgAsmGenericString* genericString = peImportItem->get_name();
               ROSE_ASSERT(genericString != NULL);

               name = genericString->get_string();
             }

          SgAsmDwarfLine* asmDwarfLine = isSgAsmDwarfLine(node);
          if (asmDwarfLine != NULL)
             {
               char buffer[100];

            // It does not work to embed the "\n" into the single sprintf parameter.
            // sprintf(buffer," Addr: 0x%08"PRIx64" \n line: %d col: %d ",asmDwarfLine->get_address(),asmDwarfLine->get_line(),asmDwarfLine->get_column());

               sprintf(buffer,"Addr: 0x%08"PRIx64,asmDwarfLine->get_address());
               name = buffer;
               sprintf(buffer,"line: %d col: %d",asmDwarfLine->get_line(),asmDwarfLine->get_column());
               name += string("\\n") + buffer;
             }

          SgAsmDwarfConstruct* asmDwarfConstruct = isSgAsmDwarfConstruct(node);
          if (asmDwarfConstruct != NULL)
             {
               name = asmDwarfConstruct->get_name();
             }

#if 0
       // This might not be the best way to implement this, since we want to detect common base classes of IR nodes.
          switch (node->variantT())
             {
               case V_SgAsmElfSection:
                  {
                    SgAsmElfSection* n = isSgAsmElfSection(node);
                    name = n->get_name();
                    break;
                  }

               default:
                  {
                 // No additional information is suggested for the default case!
                  }
             }
#endif

          if (name.empty() == false)
               nodelabel += string("\\n") + name;
#else
          printf ("Warning: In AstDOTGeneration.C ROSE_BUILD_BINARY_ANALYSIS_SUPPORT is not defined \n");
#endif
        }

  // DQ (11/29/2008): Output the directives in the label of the IR node.
     SgC_PreprocessorDirectiveStatement* preprocessorDirective = isSgC_PreprocessorDirectiveStatement(node);
     if (preprocessorDirective != NULL)
        {
          string s = preprocessorDirective->get_directiveString();

       // Change any double quotes to single quotes so that DOT will not misunderstand the generated lables.
          while (s.find("\"") != string::npos)
             {
               s.replace(s.find("\""),1,"\'");
             }

          if (s.empty() == false)
               nodelabel += string("\\n") + s;
        }

     nodelabel += additionalNodeInfo(node);

  // DQ (11/1/2003) added mechanism to add additional options (to add color, etc.)
  // nodeoption += additionalNodeOptions(node);
     string additionalOptions = additionalNodeOptions(node);
  // printf ("nodeoption = %s size() = %ld \n",nodeoption.c_str(),nodeoption.size());
  // printf ("additionalOptions = %s size() = %ld \n",additionalOptions.c_str(),additionalOptions.size());

     string x;
     string y;
     x += additionalOptions;

     nodeoption += additionalOptions;

     DOTSynthesizedAttribute d(0);

  // DQ (7/27/2008): Added mechanism to support pruning of AST
     bool commentoutNode = commentOutNodeInGraph(node);
     if (commentoutNode == true)
        {
       // DQ (11/10/2008): Fixed to only output message when (verbose_level > 0); command-line option.
       // DQ (7/27/2008): For now just return to test this mechanism, then we want to add comment "//" propoerly to generated DOT file.
          if (SgProject::get_verbose() > 0)
             {
               printf ("Skipping the use of this IR node in the DOT Graph \n");
             }
        }
       else
        {

// **************************

     switch(traversal)
        {
          case TOPDOWNBOTTOMUP:
               dotrep.addNode(node,dotrep.traceFormat(ia.tdbuTracePos,tdbuTrace)+nodelabel,nodeoption);
               break;
          case PREORDER:
          case TOPDOWN:
               dotrep.addNode(node,dotrep.traceFormat(ia.tdTracePos)+nodelabel,nodeoption);
               break;
          case POSTORDER:
          case BOTTOMUP:
               dotrep.addNode(node,dotrep.traceFormat(buTrace)+nodelabel,nodeoption);
               break;
          default:
               assert(false);
        }
  
     ++tdbuTrace;
     ++buTrace;

  // add edges or null values
     int testnum=0;
     for (iter = l.begin(); iter != l.end(); iter++)
        {
          string edgelabel = string(node->get_traversalSuccessorNamesContainer()[testnum]);
          string toErasePrefix = "p_";

          if (AstTests::isPrefix(toErasePrefix,edgelabel))
             {
               edgelabel.erase(0, toErasePrefix.size());
             }

          if ( iter->node == NULL)
             {
            // SgNode* snode=node->get_traversalSuccessorContainer()[testnum];
               AstSuccessorsSelectors::SuccessorsContainer c;
               AstSuccessorsSelectors::selectDefaultSuccessors(node,c);
               SgNode* snode=c[testnum];

            // isDefault shows that the default constructor for synth attribute was used
               if (l[testnum].isDefault() && snode && (visitedNodes.find(snode) != visitedNodes.end()) )
                  {
                 // handle bugs in SAGE
                    dotrep.addEdge(node,edgelabel,snode,"dir=forward arrowhead=\"odot\" color=red ");
                  }
                 else
                  {
                    if (snode == NULL)
                       {
                         dotrep.addNullValue(node,"",edgelabel,"");
                       }
                  }
             }
            else
             {
            // DQ (3/5/2007) added mechanism to add additional options (to add color, etc.)
               string edgeoption = additionalEdgeOptions(node,iter->node,edgelabel);

               switch(traversal)
                  {
                    case TOPDOWNBOTTOMUP:
                         dotrep.addEdge(node,edgelabel,(*iter).node,edgeoption + "dir=both");
                         break;
                    case PREORDER:
                    case TOPDOWN:
                         dotrep.addEdge(node,edgelabel,(*iter).node,edgeoption + "dir=forward");
                         break;
                    case POSTORDER:
                    case BOTTOMUP:
                         dotrep.addEdge(node,edgelabel,(*iter).node,edgeoption + "dir=back");
                         break;
                    default:
                         assert(false);
                  }
             }

          testnum++;
        }

// **************************
        }



  // DQ (7/4/2008): Support for edges specified in AST attributes
     AstAttributeMechanism* astAttributeContainer = node->get_attributeMechanism();
     if (astAttributeContainer != NULL)
        {
       // Loop over all the attributes at this IR node
          for (AstAttributeMechanism::iterator i = astAttributeContainer->begin(); i != astAttributeContainer->end(); i++)
             {
            // std::string name = i->first;
               AstAttribute* attribute = i->second;
               ROSE_ASSERT(attribute != NULL);

            // This can return a non-empty list in user-defined attributes (derived from AstAttribute).
            // printf ("Calling attribute->additionalNodeInfo() \n");
               std::vector<AstAttribute::AttributeNodeInfo> nodeList = attribute->additionalNodeInfo();
            // printf ("nodeList.size() = %lu \n",nodeList.size());

               for (std::vector<AstAttribute::AttributeNodeInfo>::iterator i_node = nodeList.begin(); i_node != nodeList.end(); i_node++)
                  {
                    SgNode* nodePtr   = i_node->nodePtr;
                    string nodelabel  = i_node->label;
                    string nodeoption = i_node->options;
                 // printf ("In AstDOTGeneration::evaluateSynthesizedAttribute(): Adding a node nodelabel = %s nodeoption = %s \n",nodelabel.c_str(),nodeoption.c_str());
                 // dotrep.addNode(NULL,dotrep.traceFormat(ia.tdTracePos)+nodelabel,nodeoption);
                    dotrep.addNode( nodePtr, dotrep.traceFormat(ia.tdTracePos) + nodelabel, nodeoption );
                  }

            // printf ("Calling attribute->additionalEdgeInfo() \n");
               std::vector<AstAttribute::AttributeEdgeInfo> edgeList = attribute->additionalEdgeInfo();
            // printf ("edgeList.size() = %lu \n",edgeList.size());
               for (std::vector<AstAttribute::AttributeEdgeInfo>::iterator i_edge = edgeList.begin(); i_edge != edgeList.end(); i_edge++)
                  {
                    string edgelabel  = i_edge->label;
                    string edgeoption = i_edge->options;
                 // printf ("In AstDOTGeneration::evaluateSynthesizedAttribute(): Adding an edge from i_edge->fromNode = %p to i_edge->toNode = %p edgelabel = %s edgeoption = %s \n",i_edge->fromNode,i_edge->toNode,edgelabel.c_str(),edgeoption.c_str());
                    dotrep.addEdge(i_edge->fromNode,edgelabel,i_edge->toNode,edgeoption + "dir=forward");
                  }
             }
        }



     switch(node->variantT())
        {
       // DQ (9/1/2008): Added case for output of SgProject rooted DOT file.
       // This allows source code and binary files to be combined into the same DOT file.
          case V_SgProject: 
             {
               SgProject* project = dynamic_cast<SgProject*>(node);
               ROSE_ASSERT(project != NULL);

               string generatedProjectName = SageInterface::generateProjectName( project );
            // printf ("generatedProjectName (from SgProject) = %s \n",generatedProjectName.c_str());
               if (generatedProjectName.length() > 40)
                  {
                 // printf ("Warning: generatedProjectName (from SgProject) = %s \n",generatedProjectName.c_str());
                    generatedProjectName = "aggregatedFileNameTooLong";
                    printf ("Proposed (generated) filename is too long, shortened to: %s \n",generatedProjectName.c_str());
                  }

               string filename = string("./") + generatedProjectName + ".dot";

            // printf ("generated filename for dot file (from SgProject) = %s \n",filename.c_str());
               if ( SgProject::get_verbose() >= 1 )
                    printf ("Output the DOT graph from the SgProject IR node (filename = %s) \n",filename.c_str());

               dotrep.writeToFileAsGraph(filename);
               break;
             }

       // case V_SgFile: 
          case V_SgSourceFile: 
          case V_SgBinaryComposite: 
             {
               SgFile* file = dynamic_cast<SgFile*>(node);
               ROSE_ASSERT(file != NULL);

               string original_filename = file->getFileName();

            // DQ (7/4/2008): Fix filenamePostfix to go before the "."
            // string filename = string("./") + ROSE::stripPathFromFileName(original_filename) + "."+filenamePostfix+"dot";
               string filename = string("./") + ROSE::stripPathFromFileName(original_filename) + filenamePostfix + ".dot";

            // printf ("generated filename for dot file (from SgSourceFile or SgBinaryComposite) = %s file->get_parent() = %p \n",filename.c_str(),file->get_parent());

            // printf ("file->get_parent() = %p \n",file->get_parent());
            // cout << "generating DOT file (from SgSourceFile or SgBinaryComposite): " << filename2 << " ... ";

            // DQ (9/1/2008): this effects the output of DOT files when multiple files are specified 
            // on the command line.  A SgProject is still built even when a single file is specificed 
            // on the command line, however there are cases where a SgFile can be built without a 
            // SgProject and this case allows those SgFile rooted subtrees to be output as DOT files.
            // If there is a SgProject then output the dot file from there, else output as a SgFile.
               if (file->get_parent() == NULL)
                  {
                 // If there is no SgProject then output the file now!
                    if ( SgProject::get_verbose() >= 1 )
                         printf ("Output the DOT graph from the SgFile IR node (no SgProject available) \n");

                    dotrep.writeToFileAsGraph(filename);
                  }
                 else
                  {
                 // There is a SgProject IR node, but if we will be traversing it we want to output the 
                 // graph then (so that the graph will include the SgProject IR nodes and connect multiple 
                 // files (SgSourceFile or SgBinaryComposite IR nodes).
                    if ( visitedNodes.find(file->get_parent()) == visitedNodes.end() )
                       {
                      // This SgProject node was not input as part of the traversal, 
                      // so we will not be traversing the SgProject IR nodes and we 
                      // have to output the graph now!

                         if ( SgProject::get_verbose() >= 1 )
                              printf ("Output the DOT graph from the SgFile IR node (SgProject was not traversed) \n");

                         dotrep.writeToFileAsGraph(filename);
                       }
                      else
                       {
                         if ( SgProject::get_verbose() >= 1 )
                              printf ("Skip the output of the DOT graph from the SgFile IR node (SgProject will be traversed) \n");
                       }
                  }
               
            // cout << "done." << endl;
               break;
             }

       // DQ (7/23/2005): Implemented default case to avoid g++ warnings 
       // about enum values not handled by this switch
          default: 
             {
            // nothing to do here
               break;
             }
        }

     d.node = node;
     return d;
   }
Example #17
0
SgAsmGenericSection *
SgAsmGenericFile::get_best_possible_section_by_va(rose_addr_t va)
{
  // This function is implemented for use in:
  //      "DisassemblerCommon::AsmFileWithData::getSectionOfAddress(uint64_t addr)"
  // It supports a more restrictive selection of valid sections to associate with
  // a given address so that we can avoid disassembly of sections that are not code.

     const std::vector<SgAsmGenericSection*> &possible = get_sections_by_va(va);

     if (0 == possible.size())
        {
          return NULL;
        }
       else
        {
          if (1 == possible.size())
             {
            // printf ("Only one alternative: va = %p possible[0] id = %d name = %s (return %s) \n",
            //      (void*)va,possible[0]->get_id(),possible[0]->get_name().c_str(),(possible[0]->get_id() < 0) ? "NULL" : "it");
            // return possible[0];
               if (possible[0]->get_id() < 0)
                    return NULL;
                 else
                    return possible[0];
             }
        }

#if 0
     printf ("Select from %" PRIuPTR " alternatives \n",possible.size());
     for (size_t i = 0; i < possible.size(); i++)
        {
          printf ("   va = %p possible[%" PRIuPTR "] id = %d name = %s \n",(void*)va,i,possible[i]->get_id(),possible[i]->get_name().c_str());
        }
#endif

  /* Choose the "best" section to return. */
     SgAsmGenericSection *best = possible[0];
     rose_addr_t fo0 = possible[0]->get_va_offset(va);
     for (size_t i = 1; i < possible.size(); i++)
        {
          if (fo0 != possible[i]->get_va_offset(va))
            return NULL; /* all possible sections must map the VA to the same file offset */

          if (best->get_id() < 0 && possible[i]->get_id() > 0)
             {
               best = possible[i]; /*prefer sections defined in a section or object table*/
             }
            else
               if (best->get_mapped_size() > possible[i]->get_mapped_size())
                  {
                    best = possible[i]; /*prefer sections with a smaller mapped size*/
                  }
                 else
                     if (best->get_name()->get_string().size()==0 && possible[i]->get_name()->get_string().size()>0)
                       {
                         best = possible[i]; /*prefer sections having a name*/
                       }
                      else
                       {
                      /* prefer section defined earlier*/

                       }
        }

     ROSE_ASSERT(best != NULL);

  // Add a few things that we just don't want to disassemble
     if (best->get_name()->get_string() == "ELF Segment Table")
          return NULL;

  // printf ("   best: va = %p id = %d name = %s \n",(void*)va,best->get_id(),best->get_name().c_str());

     return best;
}
Example #18
0
SgAsmGenericSection *
SgAsmGenericFile::best_section_by_va(const SgAsmGenericSectionPtrList &sections, rose_addr_t va)
{
    SgAsmGenericSection *best = NULL;
    rose_addr_t file_offset = 0;
    for (SgAsmGenericSectionPtrList::const_iterator si=sections.begin(); si!=sections.end(); ++si) {
        SgAsmGenericSection *section = *si;
        if (!section->is_mapped() || va<section->get_mapped_actual_va() ||
            va>=section->get_mapped_actual_va()+section->get_mapped_size()) {
            // section does not contain virtual address
        } else if (!best) {
            best = section;
            file_offset = section->get_offset() + (va - section->get_mapped_actual_va());
        } else if (file_offset != section->get_offset() + (va - section->get_mapped_actual_va())) {
            return NULL; // error
        } else if (best->get_mapped_size() > section->get_mapped_size()) {
            best = section;
        } else if (best->get_name()->get_string().empty() && !section->get_name()->get_string().empty()) {
            best = section;
        } else {
            // prefer section defined earlier
        }
    }
    return best;
}
Example #19
0
void
SgAsmGenericFile::dump(FILE *f) const
{
    fprintf(f, "Encoding: %s\n", get_data_converter() ? escapeString(get_data_converter()->name()).c_str() : "none");

    SgAsmGenericSectionPtrList sections = get_sections();
    if (sections.size()==0) {
        fprintf(f, "No sections defined for file.\n");
        return;
    }

    /* Sort sections by offset (lowest to highest), then size (largest to smallest but zero-sized entries first) */
    for (size_t i = 1; i < sections.size(); i++) {
        for (size_t j=0; j<i; j++) {
            if (sections[j]->get_offset() == sections[i]->get_offset()) {
                rose_addr_t size_i = sections[i]->get_size();
                if (0==size_i) size_i = ~(rose_addr_t)0;
                rose_addr_t size_j = sections[j]->get_size();
                if (0==size_j) size_j = ~(rose_addr_t)0;
                if (size_j < size_i) {
                    SgAsmGenericSection *x = sections[j];
                    sections[j] = sections[i];
                    sections[i] = x;
                }
            } else if (sections[j]->get_offset() > sections[i]->get_offset()) {
                SgAsmGenericSection *x = sections[j];
                sections[j] = sections[i];
                sections[i] = x;
            }
        }
    }

    /* Print results */
    fprintf(f, "File sections:\n");
    fprintf(f, "  Flg File-Addr  File-Size  File-End    Base-VA    Start-RVA  Virt-Size  End-RVA    Perm  ID Name\n");
    fprintf(f, "  --- ---------- ---------- ----------  ---------- ---------- ---------- ---------- ---- --- -----------------\n");
    rose_addr_t high_water = 0;
    for (size_t i=0; i<sections.size(); i++) {
        SgAsmGenericSection *section = sections[i];

        /* Does section overlap with any other (before or after)? */
        char overlap[4] = "   "; /* status characters: overlap prior, overlap subsequent, hole */
        for (size_t j=0; overlap[0]==' ' && j<i; j++) {
            if (sections[j]->get_offset()+sections[j]->get_size() > section->get_offset()) {
                overlap[0] = '<';
            }
        }
        for (size_t j=i+1; overlap[1]==' ' && j<sections.size(); j++) {
            if (section->get_offset()+section->get_size() > sections[j]->get_offset()) {
                overlap[1] = '>';
            }
        }

        /* Is there a hole before section[i]? */
        if (high_water < section->get_offset()) {
            overlap[2] = 'H'; /* truly unaccounted region of the file */
        } else if (i>0 && sections[i-1]->get_offset()+sections[i-1]->get_size() < section->get_offset()) {
            overlap[2] = 'h'; /* unaccounted only if overlaps are not allowed */
        }
        high_water = std::max(high_water, section->get_offset() + section->get_size());
        fprintf(f, "  %3s", overlap);

        /* File addresses */
        fprintf(f, "%c0x%08" PRIx64 " 0x%08" PRIx64 " 0x%08" PRIx64,
                section->get_file_alignment()==0 || section->get_offset()%section->get_file_alignment()==0?' ':'!',
                section->get_offset(), section->get_size(), section->get_offset()+section->get_size());

        /* Mapped addresses */
        if (section->is_mapped()) {
            fprintf(f, " %c0x%08" PRIx64 " 0x%08" PRIx64 " 0x%08" PRIx64 " 0x%08" PRIx64,
                    (section->get_mapped_alignment()==0 ||
                     section->get_mapped_preferred_rva()%section->get_mapped_alignment()==0?' ':'!'),
                    section->get_base_va(), section->get_mapped_preferred_rva(), section->get_mapped_size(),
                    section->get_mapped_preferred_rva()+section->get_mapped_size());
        } else {
            fprintf(f, " %*s", 4*11, "");
        }

        /* Permissions */
        if (section->is_mapped()) {
            fprintf(f, " %c%c%c ",
                    section->get_mapped_rperm()?'r':'-',
                    section->get_mapped_wperm()?'w':'-',
                    section->get_mapped_xperm()?'x':'-');
        } else {
            fputs("     ", f);
        }

        /* Section ID, name */
        if (section->get_id()>=0) {
            fprintf(f, " %3d", section->get_id());
        } else {
            fputs("    ", f);
        }
        fprintf(f, " %s\n", section->get_name()->get_string(true).c_str());
    }

    char overlap[4] = "   ";
    if (high_water < get_current_size()) {
        overlap[2] = 'H';
    } else if (sections.back()->get_offset() + sections.back()->get_size() < get_current_size()) {
        overlap[2] = 'h';
    }
    fprintf(f, "  %3s 0x%08" PRIx64 "%*s EOF", overlap, get_current_size(), 76, "");
    if (get_current_size()!=p_data.size())
        fprintf(f, " (original EOF was 0x%08zx)", p_data.size());
    if (get_truncate_zeros())
        fputs(" [ztrunc]", f);
    fputc('\n', f);
    fprintf(f, "  --- ---------- ---------- ----------  ---------- ---------- ---------- ---------- ---- --- -----------------\n");

    /* Show what part of the file has not been referenced */
    AddressIntervalSet holes = get_unreferenced_extents();
    if (holes.size()>0) {
        fprintf(f, "These parts of the file have not been referenced during parsing:\n");
        BOOST_FOREACH (const AddressInterval &interval, holes.intervals()) {
            std::ostringstream ss;
            using namespace StringUtility;
            ss <<"    " <<toHex(interval.least()) <<" + " <<toHex(interval.size()) <<" = " <<toHex(interval.greatest()+1) <<"\n";
            fputs(ss.str().c_str(), f);
        }
    }
/* 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();
    }
}
Example #21
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;
    }
}