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 30namespace lld { 31namespace mach_o { 32 33namespace { 34struct 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 50 CompactUnwindEntry(const DefinedAtom *function) 51 : rangeStart(function), personalityFunction(nullptr), 52 lsdaLocation(nullptr), ehFrame(nullptr), rangeLength(function->size()), 53 encoding(0) {} 54 55 CompactUnwindEntry() 56 : rangeStart(nullptr), personalityFunction(nullptr), 57 lsdaLocation(nullptr), ehFrame(nullptr), rangeLength(0), encoding(0) {} 58}; 59 60struct UnwindInfoPage { 61 ArrayRef<CompactUnwindEntry> entries; 62}; 63} 64 65class UnwindInfoAtom : public SimpleDefinedAtom { 66public: 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 92 ContentType contentType() const override { 93 return DefinedAtom::typeProcessedUnwindInfo; 94 } 95 96 Alignment alignment() const override { return 4; } 97 98 uint64_t size() const override { return _contents.size(); } 99 100 ContentPermissions permissions() const override { 101 return DefinedAtom::permR__; 102 } 103 104 ArrayRef<uint8_t> rawContent() const override { return _contents; } 105 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. 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 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 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 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 208 void addSecondLevelPages(std::vector<UnwindInfoPage> &pages) { 209 for (auto &page : pages) { 210 addRegularSecondLevelPage(page); 211 } 212 } 213 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 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 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 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 260private: 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/// 273class CompactUnwindPass : public Pass { 274public: 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 282private: 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 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 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 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. 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. 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 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 574void addCompactUnwindPass(PassManager &pm, const MachOLinkingContext &ctx) { 575 assert(ctx.needsCompactUnwindPass()); 576 pm.add(std::make_unique<CompactUnwindPass>(ctx)); 577} 578 579} // end namesapce mach_o 580} // end namesapce lld 581