void BinaryLoader::addSectionsForRemap(SgAsmGenericHeader* header, SgAsmGenericSectionPtrList &allSections) { allSections.insert(allSections.end(), header->get_sections()->get_sections().begin(), header->get_sections()->get_sections().end()); }
SgAsmGenericSectionPtrList SgAsmGenericFile::get_sections_by_va(rose_addr_t va) const { SgAsmGenericSectionPtrList retval; /* Holes (probably not mapped anyway) */ for (SgAsmGenericSectionPtrList::iterator i=p_holes->get_sections().begin(); i!=p_holes->get_sections().end(); ++i) { rose_addr_t rva = va; /* Holes don't belong to any header and therefore have a zero base_va */ if ((*i)->is_mapped() && rva >= (*i)->get_mapped_preferred_rva() && rva < (*i)->get_mapped_preferred_rva() + (*i)->get_mapped_size()) retval.push_back(*i); } /* Headers and their sections */ for (SgAsmGenericHeaderPtrList::iterator i=p_headers->get_headers().begin(); i!=p_headers->get_headers().end(); ++i) { /* Headers probably aren't mapped, but just in case... */ rose_addr_t rva = va; /* Headers don't belong to any header and therefore have a zero base_va */ if ((*i)->is_mapped() && rva >= (*i)->get_mapped_preferred_rva() && rva < (*i)->get_mapped_preferred_rva() + (*i)->get_mapped_size()) retval.push_back(*i); /* Header sections */ const SgAsmGenericSectionPtrList &recurse = (*i)->get_sections_by_va(va, true); retval.insert(retval.end(), recurse.begin(), recurse.end()); } return retval; }
SgAsmGenericSectionPtrList SgAsmGenericFile::get_sections(bool include_holes) const { SgAsmGenericSectionPtrList retval; /* Start with headers and holes */ retval.insert(retval.end(), p_headers->get_headers().begin(), p_headers->get_headers().end()); if (include_holes) retval.insert(retval.end(), p_holes->get_sections().begin(), p_holes->get_sections().end()); /* Add sections pointed to by headers. */ for (SgAsmGenericHeaderPtrList::iterator i=p_headers->get_headers().begin(); i!=p_headers->get_headers().end(); ++i) { if ((*i)->get_sections()!=NULL) { const SgAsmGenericSectionPtrList &recurse = (*i)->get_sections()->get_sections(); retval.insert(retval.end(), recurse.begin(), recurse.end()); } } return retval; }
rose_addr_t SgAsmGenericFile::get_current_size() const { rose_addr_t retval=0; SgAsmGenericSectionPtrList sections = get_sections(); for (SgAsmGenericSectionPtrList::iterator i=sections.begin(); i!=sections.end(); ++i) { retval = std::max(retval, (*i)->get_end_offset()); } return retval; }
SgAsmGenericSectionPtrList SgAsmGenericFile::get_sections_by_id(int id) const { SgAsmGenericSectionPtrList retval; /* Holes */ for (SgAsmGenericSectionPtrList::iterator i=p_holes->get_sections().begin(); i!=p_holes->get_sections().end(); ++i) { if ((*i)->get_id()==id) retval.push_back(*i); } /* Headers and their sections */ for (SgAsmGenericHeaderPtrList::iterator i=p_headers->get_headers().begin(); i!=p_headers->get_headers().end(); ++i) { if ((*i)->get_id()==id) retval.push_back(*i); const SgAsmGenericSectionPtrList &recurse = (*i)->get_sections_by_id(id); retval.insert(retval.end(), recurse.begin(), recurse.end()); } return retval; }
SgAsmGenericSectionPtrList SgAsmGenericFile::get_sections_by_name(std::string name, char sep/*or NUL*/) const { SgAsmGenericSectionPtrList retval; /* Truncate name */ if (sep) { size_t pos = name.find(sep); if (pos!=name.npos) name.erase(pos); } /* Holes */ for (SgAsmGenericSectionPtrList::iterator i=p_holes->get_sections().begin(); i!=p_holes->get_sections().end(); ++i) { std::string secname = (*i)->get_name()->get_string(); if (sep) { size_t pos = secname.find(sep); if (pos!=secname.npos) secname.erase(pos); } if (0==secname.compare(name)) retval.push_back(*i); } /* Headers and their sections */ for (SgAsmGenericHeaderPtrList::iterator i=p_headers->get_headers().begin(); i!=p_headers->get_headers().end(); ++i) { std::string secname = (*i)->get_name()->get_string(); if (sep) { size_t pos = secname.find(sep); if (pos!=secname.npos) secname.erase(pos); } if (0==secname.compare(name)) retval.push_back(*i); const SgAsmGenericSectionPtrList &recurse = (*i)->get_sections_by_name(name, sep); retval.insert(retval.end(), recurse.begin(), recurse.end()); } return retval; }
SgAsmGenericSectionPtrList SgAsmGenericFile::get_sections_by_rva(rose_addr_t rva) const { SgAsmGenericSectionPtrList retval; /* Holes (probably not mapped anyway) */ for (SgAsmGenericSectionPtrList::iterator i=p_holes->get_sections().begin(); i!=p_holes->get_sections().end(); ++i) { if ((*i)->is_mapped() && rva >= (*i)->get_mapped_preferred_rva() && rva < (*i)->get_mapped_preferred_rva() + (*i)->get_mapped_size()) retval.push_back(*i); } /* Headers and their sections */ for (SgAsmGenericHeaderPtrList::iterator i=p_headers->get_headers().begin(); i!=p_headers->get_headers().end(); ++i) { if ((*i)->is_mapped() && rva >= (*i)->get_mapped_preferred_rva() && rva < (*i)->get_mapped_preferred_rva() + (*i)->get_mapped_size()) retval.push_back(*i); const SgAsmGenericSectionPtrList &recurse = (*i)->get_sections_by_rva(rva); retval.insert(retval.end(), recurse.begin(), recurse.end()); } return retval; }
SgAsmGenericSectionPtrList SgAsmGenericFile::get_sections_by_offset(rose_addr_t offset, rose_addr_t size) const { SgAsmGenericSectionPtrList retval; /* Holes */ for (SgAsmGenericSectionPtrList::iterator i=p_holes->get_sections().begin(); i!=p_holes->get_sections().end(); ++i) { if (offset >= (*i)->get_offset() && offset < (*i)->get_offset()+(*i)->get_size() && offset-(*i)->get_offset() + size <= (*i)->get_size()) retval.push_back(*i); } /* Headers and their sections */ for (SgAsmGenericHeaderPtrList::iterator i=p_headers->get_headers().begin(); i!=p_headers->get_headers().end(); ++i) { if (offset >= (*i)->get_offset() && offset < (*i)->get_offset()+(*i)->get_size() && offset-(*i)->get_offset() + size <= (*i)->get_size()) retval.push_back(*i); const SgAsmGenericSectionPtrList &recurse = (*i)->get_sections_by_offset(offset, size); retval.insert(retval.end(), recurse.begin(), recurse.end()); } return retval; }
/* 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; } }