Пример #1
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;
    });
  }
Пример #2
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();
  }