/// 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; }); }
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(); }