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::__anone828e58a0111::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::__anone828e58a0111::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