/** 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); }
/** 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 }
/* 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 §ions = 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; }
/** 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()); } } }
/** 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; }
/** 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')); }
/* 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')); } }
/** 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; }
/** 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_")); }
/** 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; }
/* 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); }
/* 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 §ions = 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 §ions = 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(); } }
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); }
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; }
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; }
SgAsmGenericSection * SgAsmGenericFile::best_section_by_va(const SgAsmGenericSectionPtrList §ions, 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; }
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 §ions = 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 §ions = 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(); } }
/* 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; } }