summaryrefslogtreecommitdiff
path: root/lib/ReaderWriter/MachO/CompactUnwindPass.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/ReaderWriter/MachO/CompactUnwindPass.cpp')
-rw-r--r--lib/ReaderWriter/MachO/CompactUnwindPass.cpp85
1 files changed, 68 insertions, 17 deletions
diff --git a/lib/ReaderWriter/MachO/CompactUnwindPass.cpp b/lib/ReaderWriter/MachO/CompactUnwindPass.cpp
index fc8608383e5d..4b8644a67e70 100644
--- a/lib/ReaderWriter/MachO/CompactUnwindPass.cpp
+++ b/lib/ReaderWriter/MachO/CompactUnwindPass.cpp
@@ -1,4 +1,4 @@
-//===- lib/ReaderWriter/MachO/CompactUnwindPass.cpp -----------------------===//
+//===- lib/ReaderWriter/MachO/CompactUnwindPass.cpp -------------*- C++ -*-===//
//
// The LLVM Linker
//
@@ -92,7 +92,7 @@ public:
return DefinedAtom::typeProcessedUnwindInfo;
}
- Alignment alignment() const override { return Alignment(2); }
+ Alignment alignment() const override { return 4; }
uint64_t size() const override { return _contents.size(); }
@@ -272,12 +272,12 @@ private:
class CompactUnwindPass : public Pass {
public:
CompactUnwindPass(const MachOLinkingContext &context)
- : _context(context), _archHandler(_context.archHandler()),
+ : _ctx(context), _archHandler(_ctx.archHandler()),
_file("<mach-o Compact Unwind Pass>"),
- _isBig(MachOLinkingContext::isBigEndian(_context.arch())) {}
+ _isBig(MachOLinkingContext::isBigEndian(_ctx.arch())) {}
private:
- void perform(std::unique_ptr<MutableFile> &mergedFile) override {
+ std::error_code perform(SimpleFile &mergedFile) override {
DEBUG(llvm::dbgs() << "MachO Compact Unwind pass\n");
std::map<const Atom *, CompactUnwindEntry> unwindLocs;
@@ -294,7 +294,7 @@ private:
// Skip rest of pass if no unwind info.
if (unwindLocs.empty() && dwarfFrames.empty())
- return;
+ return std::error_code();
// 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
@@ -310,6 +310,9 @@ private:
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");
@@ -339,24 +342,26 @@ private:
<< " has " << entriesInPage << " entries\n");
} while (pageStart < unwindInfos.size());
- UnwindInfoAtom *unwind = new (_file.allocator())
+ auto *unwind = new (_file.allocator())
UnwindInfoAtom(_archHandler, _file, _isBig, personalities,
commonEncodings, pages, numLSDAs);
- mergedFile->addAtom(*unwind);
+ mergedFile.addAtom(*unwind);
// Finally, remove all __compact_unwind atoms now that we've processed them.
- mergedFile->removeDefinedAtomsIf([](const DefinedAtom *atom) {
+ mergedFile.removeDefinedAtomsIf([](const DefinedAtom *atom) {
return atom->contentType() == DefinedAtom::typeCompactUnwindInfo;
});
+
+ return std::error_code();
}
void collectCompactUnwindEntries(
- std::unique_ptr<MutableFile> &mergedFile,
+ 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()) {
+ for (const DefinedAtom *atom : mergedFile.defined()) {
if (atom->contentType() != DefinedAtom::typeCompactUnwindInfo)
continue;
@@ -422,9 +427,9 @@ private:
}
void
- collectDwarfFrameEntries(std::unique_ptr<MutableFile> &mergedFile,
+ collectDwarfFrameEntries(const SimpleFile &mergedFile,
std::map<const Atom *, const Atom *> &dwarfFrames) {
- for (const DefinedAtom *ehFrameAtom : mergedFile->defined()) {
+ for (const DefinedAtom *ehFrameAtom : mergedFile.defined()) {
if (ehFrameAtom->contentType() != DefinedAtom::typeCFI)
continue;
if (ArchHandler::isDwarfCIE(_isBig, ehFrameAtom))
@@ -442,7 +447,7 @@ private:
/// + 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 std::unique_ptr<MutableFile> &mergedFile,
+ const SimpleFile &mergedFile,
const std::map<const Atom *, CompactUnwindEntry> &unwindLocs,
const std::vector<const Atom *> &personalities,
const std::map<const Atom *, const Atom *> &dwarfFrames) {
@@ -452,7 +457,7 @@ private:
// 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()) {
+ for (const DefinedAtom *atom : mergedFile.defined()) {
if (atom->contentType() != DefinedAtom::typeCode)
continue;
@@ -468,6 +473,53 @@ private:
return unwindInfos;
}
+ /// 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;
+ });
+ }
+
CompactUnwindEntry finalizeUnwindInfoEntryForAtom(
const DefinedAtom *function,
const std::map<const Atom *, CompactUnwindEntry> &unwindLocs,
@@ -496,7 +548,6 @@ private:
}
}
-
auto personality = std::find(personalities.begin(), personalities.end(),
entry.personalityFunction);
uint32_t personalityIdx = personality == personalities.end()
@@ -515,7 +566,7 @@ private:
return entry;
}
- const MachOLinkingContext &_context;
+ const MachOLinkingContext &_ctx;
mach_o::ArchHandler &_archHandler;
MachOFile _file;
bool _isBig;