bool CppFileContents::write(OovStringRef const fn) { SimpleFile file; eOpenStatus openStat = file.open(fn, M_WriteExclusiveTrunc, OE_Binary); OovStatus status(openStat == OS_Opened, SC_File); if(status.ok()) { OovString includeCov = "#include \"OovCoverage.h\""; appendLineEnding(includeCov); updateMemory(); status = file.write(includeCov.c_str(), includeCov.length()); } if(status.ok()) { status = file.write(mFileContents.data(), mFileContents.size()); } if(!status.ok()) { OovString str = "Unable to write %s "; str += fn; str += "\n"; status.report(ET_Error, str.getStr()); } return status.ok(); }
SaveStateList CProjectItem::getSavegameList(const Common::String &target) { Common::SaveFileManager *saveFileMan = g_system->getSavefileManager(); Common::StringArray filenames; Common::String saveDesc; Common::String pattern = Common::String::format("%s.0??", target.c_str()); TitanicSavegameHeader header; filenames = saveFileMan->listSavefiles(pattern); sort(filenames.begin(), filenames.end()); // Sort to get the files in numerical order SaveStateList saveList; for (Common::StringArray::const_iterator file = filenames.begin(); file != filenames.end(); ++file) { const char *ext = strrchr(file->c_str(), '.'); int slot = ext ? atoi(ext + 1) : -1; if (slot >= 0 && slot < MAX_SAVEGAME_SLOTS) { Common::InSaveFile *in = g_system->getSavefileManager()->openForLoading(*file); if (in) { SimpleFile f; f.open(in); if (!readSavegameHeader(&f, header)) continue; saveList.push_back(SaveStateDescriptor(slot, header._saveName)); header._thumbnail->free(); delete header._thumbnail; delete in; } } } return saveList; }
SimpleFile *STtitleEngine::open(const CString &name) { Common::SeekableReadStream *stream = g_vm->_filesManager->getResource( CString::format("TEXT/%s", name.c_str())); assert(stream); SimpleFile *file = new SimpleFile(); file->open(stream); return file; }
/// Every atom defined in __TEXT,__text needs an entry in the final /// __unwind_info section (in order). These comes from two sources: /// + Input __compact_unwind sections where possible (after adding the /// personality function offset which is only known now). /// + A synthesised reference to __eh_frame if there's no __compact_unwind /// or too many personality functions to be accommodated. std::vector<CompactUnwindEntry> createUnwindInfoEntries( const SimpleFile &mergedFile, const std::map<const Atom *, CompactUnwindEntry> &unwindLocs, const std::vector<const Atom *> &personalities, const std::map<const Atom *, const Atom *> &dwarfFrames) { std::vector<CompactUnwindEntry> unwindInfos; DEBUG(llvm::dbgs() << " Creating __unwind_info entries\n"); // The final order in the __unwind_info section must be derived from the // order of typeCode atoms, since that's how they'll be put into the object // file eventually (yuck!). for (const DefinedAtom *atom : mergedFile.defined()) { if (atom->contentType() != DefinedAtom::typeCode) continue; unwindInfos.push_back(finalizeUnwindInfoEntryForAtom( atom, unwindLocs, personalities, dwarfFrames)); DEBUG(llvm::dbgs() << " Entry for " << atom->name() << ", final encoding=" << llvm::format("0x%08x", unwindInfos.back().encoding) << '\n'); } return unwindInfos; }
bool CppFileContents::read(char const *fn) { SimpleFile file; eOpenStatus openStat = file.open(fn, M_ReadWriteExclusive, OE_Binary); OovStatus status(openStat == OS_Opened, SC_File); if(status.ok()) { int size = file.getSize(); mFileContents.resize(size); int actual = 0; status = file.read(mFileContents.data(), size, actual); } if(!status.ok()) { OovString str = "Unable to read %s "; str += fn; str += "\n"; status.report(ET_Error, str.getStr()); } return status.ok(); }
void collectDwarfFrameEntries(const SimpleFile &mergedFile, std::map<const Atom *, const Atom *> &dwarfFrames) { for (const DefinedAtom *ehFrameAtom : mergedFile.defined()) { if (ehFrameAtom->contentType() != DefinedAtom::typeCFI) continue; if (ArchHandler::isDwarfCIE(_isBig, ehFrameAtom)) continue; if (const Atom *function = _archHandler.fdeTargetFunction(ehFrameAtom)) dwarfFrames[function] = ehFrameAtom; } }
llvm::Error perform(SimpleFile &mergedFile) override { // Scan all references in all atoms. for (const DefinedAtom *atom : mergedFile.defined()) { for (const Reference *ref : *atom) { // Look at instructions accessing the GOT. bool canBypassGOT; if (!_archHandler.isGOTAccess(*ref, canBypassGOT)) continue; const Atom *target = ref->target(); assert(target != nullptr); if (!shouldReplaceTargetWithGOTAtom(target, canBypassGOT)) { // Update reference kind to reflect that target is a direct accesss. _archHandler.updateReferenceToGOT(ref, false); } else { // Replace the target with a reference to a GOT entry. const DefinedAtom *gotEntry = makeGOTEntry(target); const_cast<Reference *>(ref)->setTarget(gotEntry); // Update reference kind to reflect that target is now a GOT entry. _archHandler.updateReferenceToGOT(ref, true); } } } // Sort and add all created GOT Atoms to master file std::vector<const GOTEntryAtom *> entries; entries.reserve(_targetToGOT.size()); for (auto &it : _targetToGOT) entries.push_back(it.second); std::sort(entries.begin(), entries.end(), [](const GOTEntryAtom *left, const GOTEntryAtom *right) { return (left->slotName().compare(right->slotName()) < 0); }); for (const GOTEntryAtom *slot : entries) mergedFile.addAtom(*slot); return llvm::Error::success(); }
/// Remove unused EH frames. /// /// An EH frame is considered unused if there is a corresponding compact /// unwind atom that doesn't require the EH frame. void pruneUnusedEHFrames( SimpleFile &mergedFile, const std::vector<CompactUnwindEntry> &unwindInfos, const std::map<const Atom *, CompactUnwindEntry> &unwindLocs, const std::map<const Atom *, const Atom *> &dwarfFrames) { // Worklist of all 'used' FDEs. std::vector<const DefinedAtom *> usedDwarfWorklist; // We have to check two conditions when building the worklist: // (1) EH frames used by compact unwind entries. for (auto &entry : unwindInfos) if (entry.ehFrame) usedDwarfWorklist.push_back(cast<DefinedAtom>(entry.ehFrame)); // (2) EH frames that reference functions with no corresponding compact // unwind info. for (auto &entry : dwarfFrames) if (!unwindLocs.count(entry.first)) usedDwarfWorklist.push_back(cast<DefinedAtom>(entry.second)); // Add all transitively referenced CFI atoms by processing the worklist. std::set<const Atom *> usedDwarfFrames; while (!usedDwarfWorklist.empty()) { const DefinedAtom *cfiAtom = usedDwarfWorklist.back(); usedDwarfWorklist.pop_back(); usedDwarfFrames.insert(cfiAtom); for (const auto *ref : *cfiAtom) { const DefinedAtom *cfiTarget = dyn_cast<DefinedAtom>(ref->target()); if (cfiTarget->contentType() == DefinedAtom::typeCFI) usedDwarfWorklist.push_back(cfiTarget); } } // Finally, delete all unreferenced CFI atoms. mergedFile.removeDefinedAtomsIf([&](const DefinedAtom *atom) { if ((atom->contentType() == DefinedAtom::typeCFI) && !usedDwarfFrames.count(atom)) return true; return false; }); }
void collectCompactUnwindEntries( const SimpleFile &mergedFile, std::map<const Atom *, CompactUnwindEntry> &unwindLocs, std::vector<const Atom *> &personalities, uint32_t &numLSDAs) { DEBUG(llvm::dbgs() << " Collecting __compact_unwind entries\n"); for (const DefinedAtom *atom : mergedFile.defined()) { if (atom->contentType() != DefinedAtom::typeCompactUnwindInfo) continue; auto unwindEntry = extractCompactUnwindEntry(atom); unwindLocs.insert(std::make_pair(unwindEntry.rangeStart, unwindEntry)); DEBUG(llvm::dbgs() << " Entry for " << unwindEntry.rangeStart->name() << ", encoding=" << llvm::format("0x%08x", unwindEntry.encoding)); if (unwindEntry.personalityFunction) DEBUG(llvm::dbgs() << ", personality=" << unwindEntry.personalityFunction->name() << ", lsdaLoc=" << unwindEntry.lsdaLocation->name()); DEBUG(llvm::dbgs() << '\n'); // Count number of LSDAs we see, since we need to know how big the index // will be while laying out the section. if (unwindEntry.lsdaLocation) ++numLSDAs; // Gather the personality functions now, so that they're in deterministic // order (derived from the DefinedAtom order). if (unwindEntry.personalityFunction) { auto pFunc = std::find(personalities.begin(), personalities.end(), unwindEntry.personalityFunction); if (pFunc == personalities.end()) personalities.push_back(unwindEntry.personalityFunction); } } }
bool RigidObject::Load(const char* fn) { const char* ext=FileExtension(fn); if(ext && strcmp(ext,"obj")==0) { SimpleFile f; f.AllowItem("mesh"); f.AllowItem("geomscale"); f.AllowItem("geomtranslate"); f.AllowItem("T"); f.AllowItem("mass"); f.AllowItem("inertia"); f.AllowItem("com"); f.AllowItem("kFriction"); f.AllowItem("kRestitution"); f.AllowItem("kStiffness"); f.AllowItem("kDamping"); f.AllowItem("autoMass"); if(!f.Load(fn)) return false; if(!f.CheckSize("mesh",1,fn)) return false; if(!f.CheckType("mesh",PrimitiveValue::String,fn)) return false; string fnPath = GetFilePath(fn); geomFile = f["mesh"][0].AsString(); string geomfn = fnPath + geomFile; if(!LoadGeometry(geomfn.c_str())) return false; f.erase("mesh"); Matrix4 ident; ident.setIdentity(); Matrix4 geomT=ident; if(f.count("geomscale") != 0) { if(!f.CheckType("geomscale",PrimitiveValue::Double,fn)) return false; vector<double> scale = f.AsDouble("geomscale"); if(scale.size()==1) { geomT(0,0)=geomT(1,1)=geomT(2,2)=scale[0]; } else if(scale.size()==3) { geomT(0,0)=scale[0]; geomT(1,1)=scale[1]; geomT(2,2)=scale[2]; } else { fprintf(stderr,"Invalid number of geomscale components in %s\n",fn); return false; } f.erase("geomscale"); } if(f.count("geomtranslate") != 0) { if(!f.CheckType("geomtranslate",PrimitiveValue::Double,fn)) return false; if(!f.CheckSize("geomtranslate",3,fn)) return false; vector<double> trans = f.AsDouble("geomtranslate"); geomT(0,3)=trans[0]; geomT(1,3)=trans[1]; geomT(2,3)=trans[2]; f.erase("geomtranslate"); } if(!(ident == geomT)) { geometry.TransformGeometry(geomT); } if(f.count("T")==0) { T.setIdentity(); } else { if(!f.CheckType("T",PrimitiveValue::Double,fn)) return false; vector<double> items = f.AsDouble("T"); if(items.size()==12) { //read 4 columns of 3 Vector3 x(items[0],items[1],items[2]); Vector3 y(items[3],items[4],items[5]); Vector3 z(items[6],items[7],items[8]); Vector3 t(items[9],items[10],items[11]); T.R.set(x,y,z); T.t=t; } else if(items.size()==16) { //read 4 columns of 4 Vector3 x(items[0],items[1],items[2]); Vector3 y(items[4],items[5],items[6]); Vector3 z(items[8],items[9],items[10]); Vector3 t(items[12],items[13],items[14]); T.R.set(x,y,z); T.t=t; } else { fprintf(stderr,"Invalid number of transformation components in %s\n",fn); return false; } f.erase("T"); } if(f.count("mass")==0) { mass=1.0; } else { if(!f.CheckSize("mass",1)) return false; if(!f.CheckType("mass",PrimitiveValue::Double)) return false; mass = f["mass"][0].AsDouble(); f.erase("mass"); } bool hasCOM = false; if(f.count("com")==0) { com.setZero(); } else { if(!f.CheckSize("com",3)) return false; if(!f.CheckType("com",PrimitiveValue::Double)) return false; hasCOM = true; com.set(f["com"][0].AsDouble(),f["com"][1].AsDouble(),f["com"][2].AsDouble()); f.erase("com"); } if(f.count("inertia")==0) inertia.setIdentity(); else { if(!f.CheckType("inertia",PrimitiveValue::Double,fn)) return false; vector<double> items = f.AsDouble("inertia"); if(items.size() == 3) inertia.setDiagonal(Vector3(items[0],items[1],items[2])); else if(items.size() == 9) { inertia(0,0)=items[0]; inertia(0,1)=items[1]; inertia(0,2)=items[2]; inertia(1,0)=items[3]; inertia(1,1)=items[4]; inertia(1,2)=items[5]; inertia(2,0)=items[6]; inertia(2,1)=items[7]; inertia(2,2)=items[8]; } else { fprintf(stderr,"Invalid number of inertia matrix components in %s\n",fn); return false; } f.erase("inertia"); } if(f.count("kFriction")==0) kFriction = 0.5; else { if(!f.CheckSize("kFriction",1,fn)) return false; if(!f.CheckType("kFriction",PrimitiveValue::Double,fn)) return false; kFriction = f.AsDouble("kFriction")[0]; f.erase("kFriction"); } if(f.count("kRestitution")==0) kRestitution = 0.5; else { if(!f.CheckSize("kRestitution",1,fn)) return false; if(!f.CheckType("kRestitution",PrimitiveValue::Double,fn)) return false; kRestitution = f.AsDouble("kRestitution")[0]; f.erase("kRestitution"); } if(f.count("kStiffness")==0) kStiffness=Inf; else { if(!f.CheckSize("kStiffness",1,fn)) return false; if(!f.CheckType("kStiffness",PrimitiveValue::Double,fn)) return false; kStiffness = f.AsDouble("kStiffness")[0]; f.erase("kStiffness"); } if(f.count("kDamping")==0) kDamping=Inf; else { if(!f.CheckSize("kDamping",1,fn)) return false; if(!f.CheckType("kDamping",PrimitiveValue::Double,fn)) return false; kDamping = f.AsDouble("kDamping")[0]; f.erase("kDamping"); } if(f.count("autoMass")!=0) { if(hasCOM) //com specified, compute inertia about given com inertia = Inertia(*geometry,com,mass); else SetMassFromGeometry(mass); f.erase("autoMass"); } if(!f.empty()) { for(map<string,vector<PrimitiveValue> >::const_iterator i=f.entries.begin();i!=f.entries.end();i++) fprintf(stderr,"Unknown entry %s in object file %s\n",i->first.c_str(),fn); } return true; } else { if(!LoadGeometry(fn)) { printf("LoadGeometry %s failed\n",fn); return false; } T.setIdentity(); mass=1.0; com.setZero(); inertia.setZero(); kFriction = 0.5; kRestitution = 0.5; kStiffness=Inf; kDamping=Inf; if(ext) fprintf(stderr,"Warning, loading object from .%s file %s. Setting COM and inertia matrix from geometry.\n",ext,fn); else fprintf(stderr,"Warning, loading object from file %s. Setting COM and inertia matrix from geometry.\n",fn); SetMassFromGeometry(1.0); return true; } }
std::error_code perform(SimpleFile &mergedFile) override { // Skip this pass if output format uses text relocations instead of stubs. if (!this->noTextRelocs()) return std::error_code(); // Scan all references in all atoms. for (const DefinedAtom *atom : mergedFile.defined()) { for (const Reference *ref : *atom) { // Look at call-sites. if (!this->isCallSite(*ref)) continue; const Atom *target = ref->target(); assert(target != nullptr); if (isa<SharedLibraryAtom>(target)) { // Calls to shared libraries go through stubs. _targetToUses[target].push_back(ref); continue; } const DefinedAtom *defTarget = dyn_cast<DefinedAtom>(target); if (defTarget && defTarget->interposable() != DefinedAtom::interposeNo){ // Calls to interposable functions in same linkage unit must also go // through a stub. assert(defTarget->scope() != DefinedAtom::scopeTranslationUnit); _targetToUses[target].push_back(ref); } } } // Exit early if no stubs needed. if (_targetToUses.empty()) return std::error_code(); // First add help-common and GOT slots used by lazy binding. SimpleDefinedAtom *helperCommonAtom = new (_file.allocator()) StubHelperCommonAtom(_file, _stubInfo); SimpleDefinedAtom *helperCacheNLPAtom = new (_file.allocator()) NonLazyPointerAtom(_file, _ctx.is64Bit()); SimpleDefinedAtom *helperBinderNLPAtom = new (_file.allocator()) NonLazyPointerAtom(_file, _ctx.is64Bit()); addReference(helperCommonAtom, _stubInfo.stubHelperCommonReferenceToCache, helperCacheNLPAtom); addOptReference( helperCommonAtom, _stubInfo.stubHelperCommonReferenceToCache, _stubInfo.optStubHelperCommonReferenceToCache, helperCacheNLPAtom); addReference(helperCommonAtom, _stubInfo.stubHelperCommonReferenceToBinder, helperBinderNLPAtom); addOptReference( helperCommonAtom, _stubInfo.stubHelperCommonReferenceToBinder, _stubInfo.optStubHelperCommonReferenceToBinder, helperBinderNLPAtom); mergedFile.addAtom(*helperCommonAtom); mergedFile.addAtom(*helperBinderNLPAtom); mergedFile.addAtom(*helperCacheNLPAtom); // Add reference to dyld_stub_binder in libSystem.dylib auto I = std::find_if( mergedFile.sharedLibrary().begin(), mergedFile.sharedLibrary().end(), [&](const SharedLibraryAtom *atom) { return atom->name().equals(_stubInfo.binderSymbolName); }); assert(I != mergedFile.sharedLibrary().end() && "dyld_stub_binder not found"); addReference(helperBinderNLPAtom, _stubInfo.nonLazyPointerReferenceToBinder, *I); // Sort targets by name, so stubs and lazy pointers are consistent std::vector<const Atom *> targetsNeedingStubs; for (auto it : _targetToUses) targetsNeedingStubs.push_back(it.first); std::sort(targetsNeedingStubs.begin(), targetsNeedingStubs.end(), [](const Atom * left, const Atom * right) { return (left->name().compare(right->name()) < 0); }); // Make and append stubs, lazy pointers, and helpers in alphabetical order. unsigned lazyOffset = 0; for (const Atom *target : targetsNeedingStubs) { auto *stub = new (_file.allocator()) StubAtom(_file, _stubInfo); auto *lp = new (_file.allocator()) LazyPointerAtom(_file, _ctx.is64Bit()); auto *helper = new (_file.allocator()) StubHelperAtom(_file, _stubInfo); addReference(stub, _stubInfo.stubReferenceToLP, lp); addOptReference(stub, _stubInfo.stubReferenceToLP, _stubInfo.optStubReferenceToLP, lp); addReference(lp, _stubInfo.lazyPointerReferenceToHelper, helper); addReference(lp, _stubInfo.lazyPointerReferenceToFinal, target); addReference(helper, _stubInfo.stubHelperReferenceToImm, helper); addReferenceAddend(helper, _stubInfo.stubHelperReferenceToImm, helper, lazyOffset); addReference(helper, _stubInfo.stubHelperReferenceToHelperCommon, helperCommonAtom); mergedFile.addAtom(*stub); mergedFile.addAtom(*lp); mergedFile.addAtom(*helper); // Update each reference to use stub. for (const Reference *ref : _targetToUses[target]) { assert(ref->target() == target); // Switch call site to reference stub atom instead. const_cast<Reference *>(ref)->setTarget(stub); } // Calculate new offset lazyOffset += target->name().size() + 12; } return std::error_code(); }
std::error_code perform(SimpleFile &mergedFile) override { // Add the image info. mergedFile.addAtom(*getImageInfo()); return std::error_code(); }
llvm::Error perform(SimpleFile &mergedFile) override { DEBUG(llvm::dbgs() << "MachO Compact Unwind pass\n"); std::map<const Atom *, CompactUnwindEntry> unwindLocs; std::map<const Atom *, const Atom *> dwarfFrames; std::vector<const Atom *> personalities; uint32_t numLSDAs = 0; // First collect all __compact_unwind and __eh_frame entries, addressable by // the function referred to. collectCompactUnwindEntries(mergedFile, unwindLocs, personalities, numLSDAs); collectDwarfFrameEntries(mergedFile, dwarfFrames); // Skip rest of pass if no unwind info. if (unwindLocs.empty() && dwarfFrames.empty()) return llvm::Error::success(); // FIXME: if there are more than 4 personality functions then we need to // defer to DWARF info for the ones we don't put in the list. They should // also probably be sorted by frequency. assert(personalities.size() <= 4); // TODO: Find commmon encodings for use by compressed pages. std::vector<uint32_t> commonEncodings; // Now sort the entries by final address and fixup the compact encoding to // its final form (i.e. set personality function bits & create DWARF // references where needed). std::vector<CompactUnwindEntry> unwindInfos = createUnwindInfoEntries( mergedFile, unwindLocs, personalities, dwarfFrames); // Remove any unused eh-frame atoms. pruneUnusedEHFrames(mergedFile, unwindInfos, unwindLocs, dwarfFrames); // Finally, we can start creating pages based on these entries. DEBUG(llvm::dbgs() << " Splitting entries into pages\n"); // FIXME: we split the entries into pages naively: lots of 4k pages followed // by a small one. ld64 tried to minimize space and align them to real 4k // boundaries. That might be worth doing, or perhaps we could perform some // minor balancing for expected number of lookups. std::vector<UnwindInfoPage> pages; auto remainingInfos = llvm::makeArrayRef(unwindInfos); do { pages.push_back(UnwindInfoPage()); // FIXME: we only create regular pages at the moment. These can hold up to // 1021 entries according to the documentation. unsigned entriesInPage = std::min(1021U, (unsigned)remainingInfos.size()); pages.back().entries = remainingInfos.slice(0, entriesInPage); remainingInfos = remainingInfos.slice(entriesInPage); DEBUG(llvm::dbgs() << " Page from " << pages.back().entries[0].rangeStart->name() << " to " << pages.back().entries.back().rangeStart->name() << " + " << llvm::format("0x%x", pages.back().entries.back().rangeLength) << " has " << entriesInPage << " entries\n"); } while (!remainingInfos.empty()); auto *unwind = new (_file.allocator()) UnwindInfoAtom(_archHandler, _file, _isBig, personalities, commonEncodings, pages, numLSDAs); mergedFile.addAtom(*unwind); // Finally, remove all __compact_unwind atoms now that we've processed them. mergedFile.removeDefinedAtomsIf([](const DefinedAtom *atom) { return atom->contentType() == DefinedAtom::typeCompactUnwindInfo; }); return llvm::Error::success(); }