/** Write just the specified regions back to the file */ void SgAsmGenericSection::unparse(std::ostream &f, const ExtentMap &map) const { for (ExtentMap::const_iterator i=map.begin(); i!=map.end(); ++i) { Extent e = i->first; assert(e.first()+e.size() <= get_size()); const unsigned char *extent_data; if (e.first() >= p_data.size()) { extent_data = NULL; } else if (e.first() + e.size() > p_data.size()) { extent_data = &p_data[e.first()]; } else { extent_data = &p_data[e.first()]; } if (extent_data) write(f, e.first(), e.size(), extent_data); } }
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); }
AddressIntervalSet toAddressIntervalSet(const ExtentMap &x) { AddressIntervalSet retval; for (ExtentMap::const_iterator iter=x.begin(); iter!=x.end(); ++iter) retval.insert(toAddressInterval(iter->first)); return retval; }