예제 #1
0
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();
    }
예제 #2
0
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;
}
예제 #3
0
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;
}
예제 #4
0
  /// 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;
  }
예제 #5
0
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();
    }
예제 #6
0
  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;
    }
  }
예제 #7
0
  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();
  }
예제 #8
0
  /// 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;
    });
  }
예제 #9
0
  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);
      }
    }
  }
예제 #10
0
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;
  }
}
예제 #11
0
파일: StubsPass.cpp 프로젝트: sas/lld
  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();
  }
예제 #12
0
파일: ObjCPass.cpp 프로젝트: sas/lld
  std::error_code perform(SimpleFile &mergedFile) override {
    // Add the image info.
    mergedFile.addAtom(*getImageInfo());

    return std::error_code();
  }
예제 #13
0
  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();
  }