1 //===- lib/ReaderWriter/MachO/CompactUnwindPass.cpp -------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 ///
9 /// \file A pass to convert MachO's __compact_unwind sections into the final
10 /// __unwind_info format used during runtime. See
11 /// mach-o/compact_unwind_encoding.h for more details on the formats involved.
12 ///
13 //===----------------------------------------------------------------------===//
14 
15 #include "ArchHandler.h"
16 #include "File.h"
17 #include "MachONormalizedFileBinaryUtils.h"
18 #include "MachOPasses.h"
19 #include "lld/Common/LLVM.h"
20 #include "lld/Core/DefinedAtom.h"
21 #include "lld/Core/File.h"
22 #include "lld/Core/Reference.h"
23 #include "lld/Core/Simple.h"
24 #include "llvm/ADT/DenseMap.h"
25 #include "llvm/Support/Debug.h"
26 #include "llvm/Support/Format.h"
27 
28 #define DEBUG_TYPE "macho-compact-unwind"
29 
30 namespace lld {
31 namespace mach_o {
32 
33 namespace {
34 struct CompactUnwindEntry {
35   const Atom *rangeStart;
36   const Atom *personalityFunction;
37   const Atom *lsdaLocation;
38   const Atom *ehFrame;
39 
40   uint32_t rangeLength;
41 
42   // There are 3 types of compact unwind entry, distinguished by the encoding
43   // value: 0 indicates a function with no unwind info;
44   // _archHandler.dwarfCompactUnwindType() indicates that the entry defers to
45   // __eh_frame, and that the ehFrame entry will be valid; any other value is a
46   // real compact unwind entry -- personalityFunction will be set and
47   // lsdaLocation may be.
48   uint32_t encoding;
49 
CompactUnwindEntrylld::mach_o::__anon4550cecc0111::CompactUnwindEntry50   CompactUnwindEntry(const DefinedAtom *function)
51       : rangeStart(function), personalityFunction(nullptr),
52         lsdaLocation(nullptr), ehFrame(nullptr), rangeLength(function->size()),
53         encoding(0) {}
54 
CompactUnwindEntrylld::mach_o::__anon4550cecc0111::CompactUnwindEntry55   CompactUnwindEntry()
56       : rangeStart(nullptr), personalityFunction(nullptr),
57         lsdaLocation(nullptr), ehFrame(nullptr), rangeLength(0), encoding(0) {}
58 };
59 
60 struct UnwindInfoPage {
61   ArrayRef<CompactUnwindEntry> entries;
62 };
63 }
64 
65 class UnwindInfoAtom : public SimpleDefinedAtom {
66 public:
UnwindInfoAtom(ArchHandler & archHandler,const File & file,bool isBig,std::vector<const Atom * > & personalities,std::vector<uint32_t> & commonEncodings,std::vector<UnwindInfoPage> & pages,uint32_t numLSDAs)67   UnwindInfoAtom(ArchHandler &archHandler, const File &file, bool isBig,
68                  std::vector<const Atom *> &personalities,
69                  std::vector<uint32_t> &commonEncodings,
70                  std::vector<UnwindInfoPage> &pages, uint32_t numLSDAs)
71       : SimpleDefinedAtom(file), _archHandler(archHandler),
72         _commonEncodingsOffset(7 * sizeof(uint32_t)),
73         _personalityArrayOffset(_commonEncodingsOffset +
74                                 commonEncodings.size() * sizeof(uint32_t)),
75         _topLevelIndexOffset(_personalityArrayOffset +
76                              personalities.size() * sizeof(uint32_t)),
77         _lsdaIndexOffset(_topLevelIndexOffset +
78                          3 * (pages.size() + 1) * sizeof(uint32_t)),
79         _firstPageOffset(_lsdaIndexOffset + 2 * numLSDAs * sizeof(uint32_t)),
80         _isBig(isBig) {
81 
82     addHeader(commonEncodings.size(), personalities.size(), pages.size());
83     addCommonEncodings(commonEncodings);
84     addPersonalityFunctions(personalities);
85     addTopLevelIndexes(pages);
86     addLSDAIndexes(pages, numLSDAs);
87     addSecondLevelPages(pages);
88   }
89 
90   ~UnwindInfoAtom() override = default;
91 
contentType() const92   ContentType contentType() const override {
93     return DefinedAtom::typeProcessedUnwindInfo;
94   }
95 
alignment() const96   Alignment alignment() const override { return 4; }
97 
size() const98   uint64_t size() const override { return _contents.size(); }
99 
permissions() const100   ContentPermissions permissions() const override {
101     return DefinedAtom::permR__;
102   }
103 
rawContent() const104   ArrayRef<uint8_t> rawContent() const override { return _contents; }
105 
addHeader(uint32_t numCommon,uint32_t numPersonalities,uint32_t numPages)106   void addHeader(uint32_t numCommon, uint32_t numPersonalities,
107                  uint32_t numPages) {
108     using normalized::write32;
109 
110     uint32_t headerSize = 7 * sizeof(uint32_t);
111     _contents.resize(headerSize);
112 
113     uint8_t *headerEntries = _contents.data();
114     // version
115     write32(headerEntries, 1, _isBig);
116     // commonEncodingsArraySectionOffset
117     write32(headerEntries + sizeof(uint32_t), _commonEncodingsOffset, _isBig);
118     // commonEncodingsArrayCount
119     write32(headerEntries + 2 * sizeof(uint32_t), numCommon, _isBig);
120     // personalityArraySectionOffset
121     write32(headerEntries + 3 * sizeof(uint32_t), _personalityArrayOffset,
122             _isBig);
123     // personalityArrayCount
124     write32(headerEntries + 4 * sizeof(uint32_t), numPersonalities, _isBig);
125     // indexSectionOffset
126     write32(headerEntries + 5 * sizeof(uint32_t), _topLevelIndexOffset, _isBig);
127     // indexCount
128     write32(headerEntries + 6 * sizeof(uint32_t), numPages + 1, _isBig);
129   }
130 
131   /// Add the list of common encodings to the section; this is simply an array
132   /// of uint32_t compact values. Size has already been specified in the header.
addCommonEncodings(std::vector<uint32_t> & commonEncodings)133   void addCommonEncodings(std::vector<uint32_t> &commonEncodings) {
134     using normalized::write32;
135 
136     _contents.resize(_commonEncodingsOffset +
137                      commonEncodings.size() * sizeof(uint32_t));
138     uint8_t *commonEncodingsArea =
139         reinterpret_cast<uint8_t *>(_contents.data() + _commonEncodingsOffset);
140 
141     for (uint32_t encoding : commonEncodings) {
142       write32(commonEncodingsArea, encoding, _isBig);
143       commonEncodingsArea += sizeof(uint32_t);
144     }
145   }
146 
addPersonalityFunctions(std::vector<const Atom * > personalities)147   void addPersonalityFunctions(std::vector<const Atom *> personalities) {
148     _contents.resize(_personalityArrayOffset +
149                      personalities.size() * sizeof(uint32_t));
150 
151     for (unsigned i = 0; i < personalities.size(); ++i)
152       addImageReferenceIndirect(_personalityArrayOffset + i * sizeof(uint32_t),
153                                 personalities[i]);
154   }
155 
addTopLevelIndexes(std::vector<UnwindInfoPage> & pages)156   void addTopLevelIndexes(std::vector<UnwindInfoPage> &pages) {
157     using normalized::write32;
158 
159     uint32_t numIndexes = pages.size() + 1;
160     _contents.resize(_topLevelIndexOffset + numIndexes * 3 * sizeof(uint32_t));
161 
162     uint32_t pageLoc = _firstPageOffset;
163 
164     // The most difficult job here is calculating the LSDAs; everything else
165     // follows fairly naturally, but we can't state where the first
166     uint8_t *indexData = &_contents[_topLevelIndexOffset];
167     uint32_t numLSDAs = 0;
168     for (unsigned i = 0; i < pages.size(); ++i) {
169       // functionOffset
170       addImageReference(_topLevelIndexOffset + 3 * i * sizeof(uint32_t),
171                         pages[i].entries[0].rangeStart);
172       // secondLevelPagesSectionOffset
173       write32(indexData + (3 * i + 1) * sizeof(uint32_t), pageLoc, _isBig);
174       write32(indexData + (3 * i + 2) * sizeof(uint32_t),
175               _lsdaIndexOffset + numLSDAs * 2 * sizeof(uint32_t), _isBig);
176 
177       for (auto &entry : pages[i].entries)
178         if (entry.lsdaLocation)
179           ++numLSDAs;
180     }
181 
182     // Finally, write out the final sentinel index
183     auto &finalEntry = pages[pages.size() - 1].entries.back();
184     addImageReference(_topLevelIndexOffset +
185                           3 * pages.size() * sizeof(uint32_t),
186                       finalEntry.rangeStart, finalEntry.rangeLength);
187     // secondLevelPagesSectionOffset => 0
188     write32(indexData + (3 * pages.size() + 2) * sizeof(uint32_t),
189             _lsdaIndexOffset + numLSDAs * 2 * sizeof(uint32_t), _isBig);
190   }
191 
addLSDAIndexes(std::vector<UnwindInfoPage> & pages,uint32_t numLSDAs)192   void addLSDAIndexes(std::vector<UnwindInfoPage> &pages, uint32_t numLSDAs) {
193     _contents.resize(_lsdaIndexOffset + numLSDAs * 2 * sizeof(uint32_t));
194 
195     uint32_t curOffset = _lsdaIndexOffset;
196     for (auto &page : pages) {
197       for (auto &entry : page.entries) {
198         if (!entry.lsdaLocation)
199           continue;
200 
201         addImageReference(curOffset, entry.rangeStart);
202         addImageReference(curOffset + sizeof(uint32_t), entry.lsdaLocation);
203         curOffset += 2 * sizeof(uint32_t);
204       }
205     }
206   }
207 
addSecondLevelPages(std::vector<UnwindInfoPage> & pages)208   void addSecondLevelPages(std::vector<UnwindInfoPage> &pages) {
209     for (auto &page : pages) {
210       addRegularSecondLevelPage(page);
211     }
212   }
213 
addRegularSecondLevelPage(const UnwindInfoPage & page)214   void addRegularSecondLevelPage(const UnwindInfoPage &page) {
215     uint32_t curPageOffset = _contents.size();
216     const int16_t headerSize = sizeof(uint32_t) + 2 * sizeof(uint16_t);
217     uint32_t curPageSize =
218         headerSize + 2 * page.entries.size() * sizeof(uint32_t);
219     _contents.resize(curPageOffset + curPageSize);
220 
221     using normalized::write32;
222     using normalized::write16;
223     // 2 => regular page
224     write32(&_contents[curPageOffset], 2, _isBig);
225     // offset of 1st entry
226     write16(&_contents[curPageOffset + 4], headerSize, _isBig);
227     write16(&_contents[curPageOffset + 6], page.entries.size(), _isBig);
228 
229     uint32_t pagePos = curPageOffset + headerSize;
230     for (auto &entry : page.entries) {
231       addImageReference(pagePos, entry.rangeStart);
232 
233       write32(_contents.data() + pagePos + sizeof(uint32_t), entry.encoding,
234               _isBig);
235       if ((entry.encoding & 0x0f000000U) ==
236           _archHandler.dwarfCompactUnwindType())
237         addEhFrameReference(pagePos + sizeof(uint32_t), entry.ehFrame);
238 
239       pagePos += 2 * sizeof(uint32_t);
240     }
241   }
242 
addEhFrameReference(uint32_t offset,const Atom * dest,Reference::Addend addend=0)243   void addEhFrameReference(uint32_t offset, const Atom *dest,
244                            Reference::Addend addend = 0) {
245     addReference(Reference::KindNamespace::mach_o, _archHandler.kindArch(),
246                  _archHandler.unwindRefToEhFrameKind(), offset, dest, addend);
247   }
248 
addImageReference(uint32_t offset,const Atom * dest,Reference::Addend addend=0)249   void addImageReference(uint32_t offset, const Atom *dest,
250                          Reference::Addend addend = 0) {
251     addReference(Reference::KindNamespace::mach_o, _archHandler.kindArch(),
252                  _archHandler.imageOffsetKind(), offset, dest, addend);
253   }
254 
addImageReferenceIndirect(uint32_t offset,const Atom * dest)255   void addImageReferenceIndirect(uint32_t offset, const Atom *dest) {
256     addReference(Reference::KindNamespace::mach_o, _archHandler.kindArch(),
257                  _archHandler.imageOffsetKindIndirect(), offset, dest, 0);
258   }
259 
260 private:
261   mach_o::ArchHandler &_archHandler;
262   std::vector<uint8_t> _contents;
263   uint32_t _commonEncodingsOffset;
264   uint32_t _personalityArrayOffset;
265   uint32_t _topLevelIndexOffset;
266   uint32_t _lsdaIndexOffset;
267   uint32_t _firstPageOffset;
268   bool _isBig;
269 };
270 
271 /// Pass for instantiating and optimizing GOT slots.
272 ///
273 class CompactUnwindPass : public Pass {
274 public:
CompactUnwindPass(const MachOLinkingContext & context)275   CompactUnwindPass(const MachOLinkingContext &context)
276       : _ctx(context), _archHandler(_ctx.archHandler()),
277         _file(*_ctx.make_file<MachOFile>("<mach-o Compact Unwind Pass>")),
278         _isBig(MachOLinkingContext::isBigEndian(_ctx.arch())) {
279     _file.setOrdinal(_ctx.getNextOrdinalAndIncrement());
280   }
281 
282 private:
perform(SimpleFile & mergedFile)283   llvm::Error perform(SimpleFile &mergedFile) override {
284     LLVM_DEBUG(llvm::dbgs() << "MachO Compact Unwind pass\n");
285 
286     std::map<const Atom *, CompactUnwindEntry> unwindLocs;
287     std::map<const Atom *, const Atom *> dwarfFrames;
288     std::vector<const Atom *> personalities;
289     uint32_t numLSDAs = 0;
290 
291     // First collect all __compact_unwind and __eh_frame entries, addressable by
292     // the function referred to.
293     collectCompactUnwindEntries(mergedFile, unwindLocs, personalities,
294                                 numLSDAs);
295 
296     collectDwarfFrameEntries(mergedFile, dwarfFrames);
297 
298     // Skip rest of pass if no unwind info.
299     if (unwindLocs.empty() && dwarfFrames.empty())
300       return llvm::Error::success();
301 
302     // FIXME: if there are more than 4 personality functions then we need to
303     // defer to DWARF info for the ones we don't put in the list. They should
304     // also probably be sorted by frequency.
305     assert(personalities.size() <= 4);
306 
307     // TODO: Find common encodings for use by compressed pages.
308     std::vector<uint32_t> commonEncodings;
309 
310     // Now sort the entries by final address and fixup the compact encoding to
311     // its final form (i.e. set personality function bits & create DWARF
312     // references where needed).
313     std::vector<CompactUnwindEntry> unwindInfos = createUnwindInfoEntries(
314         mergedFile, unwindLocs, personalities, dwarfFrames);
315 
316     // Remove any unused eh-frame atoms.
317     pruneUnusedEHFrames(mergedFile, unwindInfos, unwindLocs, dwarfFrames);
318 
319     // Finally, we can start creating pages based on these entries.
320 
321     LLVM_DEBUG(llvm::dbgs() << "  Splitting entries into pages\n");
322     // FIXME: we split the entries into pages naively: lots of 4k pages followed
323     // by a small one. ld64 tried to minimize space and align them to real 4k
324     // boundaries. That might be worth doing, or perhaps we could perform some
325     // minor balancing for expected number of lookups.
326     std::vector<UnwindInfoPage> pages;
327     auto remainingInfos = llvm::makeArrayRef(unwindInfos);
328     do {
329       pages.push_back(UnwindInfoPage());
330 
331       // FIXME: we only create regular pages at the moment. These can hold up to
332       // 1021 entries according to the documentation.
333       unsigned entriesInPage = std::min(1021U, (unsigned)remainingInfos.size());
334 
335       pages.back().entries = remainingInfos.slice(0, entriesInPage);
336       remainingInfos = remainingInfos.slice(entriesInPage);
337 
338       LLVM_DEBUG(llvm::dbgs()
339                  << "    Page from "
340                  << pages.back().entries[0].rangeStart->name() << " to "
341                  << pages.back().entries.back().rangeStart->name() << " + "
342                  << llvm::format("0x%x",
343                                  pages.back().entries.back().rangeLength)
344                  << " has " << entriesInPage << " entries\n");
345     } while (!remainingInfos.empty());
346 
347     auto *unwind = new (_file.allocator())
348         UnwindInfoAtom(_archHandler, _file, _isBig, personalities,
349                        commonEncodings, pages, numLSDAs);
350     mergedFile.addAtom(*unwind);
351 
352     // Finally, remove all __compact_unwind atoms now that we've processed them.
353     mergedFile.removeDefinedAtomsIf([](const DefinedAtom *atom) {
354       return atom->contentType() == DefinedAtom::typeCompactUnwindInfo;
355     });
356 
357     return llvm::Error::success();
358   }
359 
collectCompactUnwindEntries(const SimpleFile & mergedFile,std::map<const Atom *,CompactUnwindEntry> & unwindLocs,std::vector<const Atom * > & personalities,uint32_t & numLSDAs)360   void collectCompactUnwindEntries(
361       const SimpleFile &mergedFile,
362       std::map<const Atom *, CompactUnwindEntry> &unwindLocs,
363       std::vector<const Atom *> &personalities, uint32_t &numLSDAs) {
364     LLVM_DEBUG(llvm::dbgs() << "  Collecting __compact_unwind entries\n");
365 
366     for (const DefinedAtom *atom : mergedFile.defined()) {
367       if (atom->contentType() != DefinedAtom::typeCompactUnwindInfo)
368         continue;
369 
370       auto unwindEntry = extractCompactUnwindEntry(atom);
371       unwindLocs.insert(std::make_pair(unwindEntry.rangeStart, unwindEntry));
372 
373       LLVM_DEBUG(llvm::dbgs() << "    Entry for "
374                               << unwindEntry.rangeStart->name() << ", encoding="
375                               << llvm::format("0x%08x", unwindEntry.encoding));
376       if (unwindEntry.personalityFunction)
377         LLVM_DEBUG(llvm::dbgs()
378                    << ", personality="
379                    << unwindEntry.personalityFunction->name()
380                    << ", lsdaLoc=" << unwindEntry.lsdaLocation->name());
381       LLVM_DEBUG(llvm::dbgs() << '\n');
382 
383       // Count number of LSDAs we see, since we need to know how big the index
384       // will be while laying out the section.
385       if (unwindEntry.lsdaLocation)
386         ++numLSDAs;
387 
388       // Gather the personality functions now, so that they're in deterministic
389       // order (derived from the DefinedAtom order).
390       if (unwindEntry.personalityFunction &&
391           !llvm::count(personalities, unwindEntry.personalityFunction))
392         personalities.push_back(unwindEntry.personalityFunction);
393     }
394   }
395 
extractCompactUnwindEntry(const DefinedAtom * atom)396   CompactUnwindEntry extractCompactUnwindEntry(const DefinedAtom *atom) {
397     CompactUnwindEntry entry;
398 
399     for (const Reference *ref : *atom) {
400       switch (ref->offsetInAtom()) {
401       case 0:
402         // FIXME: there could legitimately be functions with multiple encoding
403         // entries. However, nothing produces them at the moment.
404         assert(ref->addend() == 0 && "unexpected offset into function");
405         entry.rangeStart = ref->target();
406         break;
407       case 0x10:
408         assert(ref->addend() == 0 && "unexpected offset into personality fn");
409         entry.personalityFunction = ref->target();
410         break;
411       case 0x18:
412         assert(ref->addend() == 0 && "unexpected offset into LSDA atom");
413         entry.lsdaLocation = ref->target();
414         break;
415       }
416     }
417 
418     if (atom->rawContent().size() < 4 * sizeof(uint32_t))
419       return entry;
420 
421     using normalized::read32;
422     entry.rangeLength =
423         read32(atom->rawContent().data() + 2 * sizeof(uint32_t), _isBig);
424     entry.encoding =
425         read32(atom->rawContent().data() + 3 * sizeof(uint32_t), _isBig);
426     return entry;
427   }
428 
429   void
collectDwarfFrameEntries(const SimpleFile & mergedFile,std::map<const Atom *,const Atom * > & dwarfFrames)430   collectDwarfFrameEntries(const SimpleFile &mergedFile,
431                            std::map<const Atom *, const Atom *> &dwarfFrames) {
432     for (const DefinedAtom *ehFrameAtom : mergedFile.defined()) {
433       if (ehFrameAtom->contentType() != DefinedAtom::typeCFI)
434         continue;
435       if (ArchHandler::isDwarfCIE(_isBig, ehFrameAtom))
436         continue;
437 
438       if (const Atom *function = _archHandler.fdeTargetFunction(ehFrameAtom))
439         dwarfFrames[function] = ehFrameAtom;
440     }
441   }
442 
443   /// Every atom defined in __TEXT,__text needs an entry in the final
444   /// __unwind_info section (in order). These comes from two sources:
445   ///   + Input __compact_unwind sections where possible (after adding the
446   ///      personality function offset which is only known now).
447   ///   + A synthesised reference to __eh_frame if there's no __compact_unwind
448   ///     or too many personality functions to be accommodated.
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)449   std::vector<CompactUnwindEntry> createUnwindInfoEntries(
450       const SimpleFile &mergedFile,
451       const std::map<const Atom *, CompactUnwindEntry> &unwindLocs,
452       const std::vector<const Atom *> &personalities,
453       const std::map<const Atom *, const Atom *> &dwarfFrames) {
454     std::vector<CompactUnwindEntry> unwindInfos;
455 
456     LLVM_DEBUG(llvm::dbgs() << "  Creating __unwind_info entries\n");
457     // The final order in the __unwind_info section must be derived from the
458     // order of typeCode atoms, since that's how they'll be put into the object
459     // file eventually (yuck!).
460     for (const DefinedAtom *atom : mergedFile.defined()) {
461       if (atom->contentType() != DefinedAtom::typeCode)
462         continue;
463 
464       unwindInfos.push_back(finalizeUnwindInfoEntryForAtom(
465           atom, unwindLocs, personalities, dwarfFrames));
466 
467       LLVM_DEBUG(llvm::dbgs()
468                  << "    Entry for " << atom->name() << ", final encoding="
469                  << llvm::format("0x%08x", unwindInfos.back().encoding)
470                  << '\n');
471     }
472 
473     return unwindInfos;
474   }
475 
476   /// Remove unused EH frames.
477   ///
478   /// An EH frame is considered unused if there is a corresponding compact
479   /// unwind atom that doesn't require the EH frame.
pruneUnusedEHFrames(SimpleFile & mergedFile,const std::vector<CompactUnwindEntry> & unwindInfos,const std::map<const Atom *,CompactUnwindEntry> & unwindLocs,const std::map<const Atom *,const Atom * > & dwarfFrames)480   void pruneUnusedEHFrames(
481                    SimpleFile &mergedFile,
482                    const std::vector<CompactUnwindEntry> &unwindInfos,
483                    const std::map<const Atom *, CompactUnwindEntry> &unwindLocs,
484                    const std::map<const Atom *, const Atom *> &dwarfFrames) {
485 
486     // Worklist of all 'used' FDEs.
487     std::vector<const DefinedAtom *> usedDwarfWorklist;
488 
489     // We have to check two conditions when building the worklist:
490     // (1) EH frames used by compact unwind entries.
491     for (auto &entry : unwindInfos)
492       if (entry.ehFrame)
493         usedDwarfWorklist.push_back(cast<DefinedAtom>(entry.ehFrame));
494 
495     // (2) EH frames that reference functions with no corresponding compact
496     //     unwind info.
497     for (auto &entry : dwarfFrames)
498       if (!unwindLocs.count(entry.first))
499         usedDwarfWorklist.push_back(cast<DefinedAtom>(entry.second));
500 
501     // Add all transitively referenced CFI atoms by processing the worklist.
502     std::set<const Atom *> usedDwarfFrames;
503     while (!usedDwarfWorklist.empty()) {
504       const DefinedAtom *cfiAtom = usedDwarfWorklist.back();
505       usedDwarfWorklist.pop_back();
506       usedDwarfFrames.insert(cfiAtom);
507       for (const auto *ref : *cfiAtom) {
508         const DefinedAtom *cfiTarget = dyn_cast<DefinedAtom>(ref->target());
509         if (cfiTarget->contentType() == DefinedAtom::typeCFI)
510           usedDwarfWorklist.push_back(cfiTarget);
511       }
512     }
513 
514     // Finally, delete all unreferenced CFI atoms.
515     mergedFile.removeDefinedAtomsIf([&](const DefinedAtom *atom) {
516       if ((atom->contentType() == DefinedAtom::typeCFI) &&
517           !usedDwarfFrames.count(atom))
518         return true;
519       return false;
520     });
521   }
522 
finalizeUnwindInfoEntryForAtom(const DefinedAtom * function,const std::map<const Atom *,CompactUnwindEntry> & unwindLocs,const std::vector<const Atom * > & personalities,const std::map<const Atom *,const Atom * > & dwarfFrames)523   CompactUnwindEntry finalizeUnwindInfoEntryForAtom(
524       const DefinedAtom *function,
525       const std::map<const Atom *, CompactUnwindEntry> &unwindLocs,
526       const std::vector<const Atom *> &personalities,
527       const std::map<const Atom *, const Atom *> &dwarfFrames) {
528     auto unwindLoc = unwindLocs.find(function);
529 
530     CompactUnwindEntry entry;
531     if (unwindLoc == unwindLocs.end()) {
532       // Default entry has correct encoding (0 => no unwind), but we need to
533       // synthesise the function.
534       entry.rangeStart = function;
535       entry.rangeLength = function->size();
536     } else
537       entry = unwindLoc->second;
538 
539 
540     // If there's no __compact_unwind entry, or it explicitly says to use
541     // __eh_frame, we need to try and fill in the correct DWARF atom.
542     if (entry.encoding == _archHandler.dwarfCompactUnwindType() ||
543         entry.encoding == 0) {
544       auto dwarfFrame = dwarfFrames.find(function);
545       if (dwarfFrame != dwarfFrames.end()) {
546         entry.encoding = _archHandler.dwarfCompactUnwindType();
547         entry.ehFrame = dwarfFrame->second;
548       }
549     }
550 
551     auto personality = llvm::find(personalities, entry.personalityFunction);
552     uint32_t personalityIdx = personality == personalities.end()
553                                   ? 0
554                                   : personality - personalities.begin() + 1;
555 
556     // FIXME: We should also use DWARF when there isn't enough room for the
557     // personality function in the compact encoding.
558     assert(personalityIdx < 4 && "too many personality functions");
559 
560     entry.encoding |= personalityIdx << 28;
561 
562     if (entry.lsdaLocation)
563       entry.encoding |= 1U << 30;
564 
565     return entry;
566   }
567 
568   const MachOLinkingContext &_ctx;
569   mach_o::ArchHandler &_archHandler;
570   MachOFile &_file;
571   bool _isBig;
572 };
573 
addCompactUnwindPass(PassManager & pm,const MachOLinkingContext & ctx)574 void addCompactUnwindPass(PassManager &pm, const MachOLinkingContext &ctx) {
575   assert(ctx.needsCompactUnwindPass());
576   pm.add(std::make_unique<CompactUnwindPass>(ctx));
577 }
578 
579 } // end namespace mach_o
580 } // end namespace lld
581