683 lines · c
1//===- CompactUnwindSupportImpl.h - Compact Unwind format impl --*- 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-exception6//7//===----------------------------------------------------------------------===//8//9// Compact Unwind format support implementation details.10//11//===----------------------------------------------------------------------===//12 13#ifndef LIB_EXECUTIONENGINE_JITLINK_COMPACTUNWINDSUPPORTIMPL_H14#define LIB_EXECUTIONENGINE_JITLINK_COMPACTUNWINDSUPPORTIMPL_H15 16#include "llvm/ADT/STLExtras.h"17#include "llvm/ExecutionEngine/JITLink/MachO.h"18#include "llvm/Support/Debug.h"19#include "llvm/Support/Endian.h"20 21#define DEBUG_TYPE "jitlink_cu"22 23namespace llvm {24namespace jitlink {25 26/// Split blocks in an __LD,__compact_unwind section on record boundaries.27/// When this function returns edges within each record are guaranteed to be28/// sorted by offset.29Error splitCompactUnwindBlocks(LinkGraph &G, Section &CompactUnwindSection,30 size_t RecordSize);31 32/// CRTP base for compact unwind traits classes. Automatically provides derived33/// constants.34///35/// FIXME: Passing PtrSize as a template parameter is a hack to work around a36/// bug in older MSVC compilers (until at least MSVC 15) where constexpr37/// fields in the CRTP impl class were not visible to the base class.38/// Once we no longer need to support these compilers the PtrSize39/// template argument should be removed and PointerSize should be40/// defined as a member in the CRTP Impl classes.41template <typename CRTPImpl, size_t PtrSize> struct CompactUnwindTraits {42 static constexpr size_t PointerSize = PtrSize;43 static constexpr size_t Size = 3 * PointerSize + 2 * 4;44 static constexpr size_t FnFieldOffset = 0;45 static constexpr size_t SizeFieldOffset = FnFieldOffset + PointerSize;46 static constexpr size_t EncodingFieldOffset = SizeFieldOffset + 4;47 static constexpr size_t PersonalityFieldOffset = EncodingFieldOffset + 4;48 static constexpr size_t LSDAFieldOffset =49 PersonalityFieldOffset + PointerSize;50 51 static uint32_t readPCRangeSize(ArrayRef<char> RecordContent) {52 assert(SizeFieldOffset + 4 <= RecordContent.size() &&53 "Truncated CU record?");54 return support::endian::read32<CRTPImpl::Endianness>(RecordContent.data() +55 SizeFieldOffset);56 }57 58 static uint32_t readEncoding(ArrayRef<char> RecordContent) {59 assert(EncodingFieldOffset + 4 <= RecordContent.size() &&60 "Truncated CU record?");61 return support::endian::read32<CRTPImpl::Endianness>(RecordContent.data() +62 EncodingFieldOffset);63 }64 65 static std::optional<uint32_t> encodeDWARFOffset(size_t Delta) {66 uint32_t Encoded =67 static_cast<uint32_t>(Delta) & CRTPImpl::DWARFSectionOffsetMask;68 if (Encoded != Delta)69 return std::nullopt;70 return Encoded;71 }72};73 74/// Architecture specific implementation of CompactUnwindManager.75template <typename CURecTraits> class CompactUnwindManager {76public:77 CompactUnwindManager(StringRef CompactUnwindSectionName,78 StringRef UnwindInfoSectionName,79 StringRef EHFrameSectionName)80 : CompactUnwindSectionName(CompactUnwindSectionName),81 UnwindInfoSectionName(UnwindInfoSectionName),82 EHFrameSectionName(EHFrameSectionName) {}83 84 // Split compact unwind records, add keep-alive edges from functions to85 // compact unwind records, and from compact unwind records to FDEs where86 // needed.87 //88 // This method must be called *after* __eh_frame has been processed: it89 // assumes that eh-frame records have been split up and keep-alive edges have90 // been inserted.91 Error prepareForPrune(LinkGraph &G) {92 Section *CUSec = G.findSectionByName(CompactUnwindSectionName);93 if (!CUSec || CUSec->empty()) {94 LLVM_DEBUG({95 dbgs() << "Compact unwind: No compact unwind info for " << G.getName()96 << "\n";97 });98 return Error::success();99 }100 101 LLVM_DEBUG({102 dbgs() << "Compact unwind: preparing " << G.getName() << " for prune\n";103 });104 105 Section *EHFrameSec = G.findSectionByName(EHFrameSectionName);106 107 if (auto Err = splitCompactUnwindBlocks(G, *CUSec, CURecTraits::Size))108 return Err;109 110 LLVM_DEBUG({111 dbgs() << " Preparing " << CUSec->blocks_size() << " blocks in "112 << CompactUnwindSectionName << "\n";113 });114 115 for (auto *B : CUSec->blocks()) {116 117 // Find target function edge.118 Edge *PCBeginEdge = nullptr;119 for (auto &E : B->edges_at(CURecTraits::FnFieldOffset)) {120 PCBeginEdge = &E;121 break;122 }123 124 if (!PCBeginEdge)125 return make_error<JITLinkError>(126 "In " + G.getName() + ", compact unwind record at " +127 formatv("{0:x}", B->getAddress()) + " has no pc-begin edge");128 129 if (!PCBeginEdge->getTarget().isDefined())130 return make_error<JITLinkError>(131 "In " + G.getName() + ", compact unwind record at " +132 formatv("{0:x}", B->getAddress()) + " points at external symbol " +133 *PCBeginEdge->getTarget().getName());134 135 auto &Fn = PCBeginEdge->getTarget();136 137 if (!Fn.isDefined()) {138 LLVM_DEBUG({139 dbgs() << "In " << CompactUnwindSectionName << " for " << G.getName()140 << " encountered unexpected pc-edge to undefined symbol "141 << Fn.getName() << "\n";142 });143 continue;144 }145 146 uint32_t Encoding = CURecTraits::readEncoding(B->getContent());147 bool NeedsDWARF = CURecTraits::encodingSpecifiesDWARF(Encoding);148 149 LLVM_DEBUG({150 dbgs() << " Found record for function ";151 if (Fn.hasName())152 dbgs() << Fn.getName();153 else154 dbgs() << "<anon @ " << Fn.getAddress() << '>';155 dbgs() << ": encoding = " << formatv("{0:x}", Encoding);156 if (NeedsDWARF)157 dbgs() << " (needs DWARF)";158 dbgs() << "\n";159 });160 161 auto &CURecSym =162 G.addAnonymousSymbol(*B, 0, CURecTraits::Size, false, false);163 164 bool KeepAliveAlreadyPresent = false;165 if (EHFrameSec) {166 Edge *KeepAliveEdge = nullptr;167 for (auto &E : Fn.getBlock().edges_at(0)) {168 if (E.getKind() == Edge::KeepAlive && E.getTarget().isDefined() &&169 &E.getTarget().getSection() == EHFrameSec) {170 KeepAliveEdge = &E;171 break;172 }173 }174 175 if (KeepAliveEdge) {176 // Found a keep-alive edge to an FDE in the eh-frame. Switch the keep177 // alive edge to point to the CU and if the CU needs DWARF then add178 // an extra keep-alive edge from the CU to the FDE.179 auto &FDE = KeepAliveEdge->getTarget();180 KeepAliveEdge->setTarget(CURecSym);181 KeepAliveAlreadyPresent = true;182 if (NeedsDWARF) {183 LLVM_DEBUG({184 dbgs() << " Adding keep-alive edge to FDE at "185 << FDE.getAddress() << "\n";186 });187 B->addEdge(Edge::KeepAlive, 0, FDE, 0);188 }189 } else {190 if (NeedsDWARF)191 return make_error<JITLinkError>(192 "In " + G.getName() + ", compact unwind recard ot " +193 formatv("{0:x}", B->getAddress()) +194 " needs DWARF, but no FDE was found");195 }196 } else {197 if (NeedsDWARF)198 return make_error<JITLinkError>(199 "In " + G.getName() + ", compact unwind recard ot " +200 formatv("{0:x}", B->getAddress()) + " needs DWARF, but no " +201 EHFrameSectionName + " section exists");202 }203 204 if (!KeepAliveAlreadyPresent) {205 // No FDE edge. We'll need to add a new edge from the function back206 // to the CU record.207 Fn.getBlock().addEdge(Edge::KeepAlive, 0, CURecSym, 0);208 }209 }210 211 return Error::success();212 }213 214 /// Process all __compact_unwind records and reserve space for __unwind_info.215 Error processAndReserveUnwindInfo(LinkGraph &G) {216 // Bail out early if no unwind info.217 Section *CUSec = G.findSectionByName(CompactUnwindSectionName);218 if (!CUSec)219 return Error::success();220 221 // The __LD/__compact_unwind section is only used as input for the linker.222 // We'll create a new __TEXT,__unwind_info section for unwind info output.223 CUSec->setMemLifetime(orc::MemLifetime::NoAlloc);224 225 // Find / make a mach-header to act as the base for unwind-info offsets226 // (and to report the arch / subarch to libunwind).227 if (auto Err = getOrCreateCompactUnwindBase(G))228 return Err;229 230 // Error out if there's already unwind-info in the graph: We have no idea231 // how to merge unwind-info sections.232 if (G.findSectionByName(UnwindInfoSectionName))233 return make_error<JITLinkError>("In " + G.getName() + ", " +234 UnwindInfoSectionName +235 " already exists");236 237 // Process the __compact_unwind section to build the Records vector that238 // we'll use for writing the __unwind_info section.239 if (auto Err = processCompactUnwind(G, *CUSec))240 return Err;241 242 // Calculate the size of __unwind_info.243 size_t UnwindInfoSectionSize =244 UnwindInfoSectionHeaderSize +245 Personalities.size() * PersonalityEntrySize +246 (NumSecondLevelPages + 1) * IndexEntrySize + NumLSDAs * LSDAEntrySize +247 NumSecondLevelPages * SecondLevelPageHeaderSize +248 Records.size() * SecondLevelPageEntrySize;249 250 LLVM_DEBUG({251 dbgs() << "In " << G.getName() << ", reserving "252 << formatv("{0:x}", UnwindInfoSectionSize) << " bytes for "253 << UnwindInfoSectionName << "\n";254 });255 256 // Create the __unwind_info section and reserve space for it.257 Section &UnwindInfoSec =258 G.createSection(UnwindInfoSectionName, orc::MemProt::Read);259 260 auto UnwindInfoSectionContent = G.allocateBuffer(UnwindInfoSectionSize);261 memset(UnwindInfoSectionContent.data(), 0, UnwindInfoSectionContent.size());262 auto &B = G.createMutableContentBlock(263 UnwindInfoSec, UnwindInfoSectionContent, orc::ExecutorAddr(), 8, 0);264 265 // Add Keep-alive edges from the __unwind_info block to all of the target266 // functions.267 for (auto &R : Records)268 B.addEdge(Edge::KeepAlive, 0, *R.Fn, 0);269 270 return Error::success();271 }272 273 Error writeUnwindInfo(LinkGraph &G) {274 Section *CUSec = G.findSectionByName(CompactUnwindSectionName);275 if (!CUSec || CUSec->empty())276 return Error::success();277 278 Section *UnwindInfoSec = G.findSectionByName(UnwindInfoSectionName);279 if (!UnwindInfoSec)280 return make_error<JITLinkError>("In " + G.getName() + ", " +281 UnwindInfoSectionName +282 " missing after allocation");283 284 if (UnwindInfoSec->blocks_size() != 1)285 return make_error<JITLinkError>(286 "In " + G.getName() + ", " + UnwindInfoSectionName +287 " contains more than one block post-allocation");288 289 LLVM_DEBUG(290 { dbgs() << "Writing unwind info for " << G.getName() << "...\n"; });291 292 mergeRecords();293 294 auto &UnwindInfoBlock = **UnwindInfoSec->blocks().begin();295 auto Content = UnwindInfoBlock.getMutableContent(G);296 BinaryStreamWriter Writer(297 {reinterpret_cast<uint8_t *>(Content.data()), Content.size()},298 CURecTraits::Endianness);299 300 // __unwind_info format, from mach-o/compact_unwind_encoding.h on Darwin:301 //302 // #define UNWIND_SECTION_VERSION 1303 // struct unwind_info_section_header304 // {305 // uint32_t version; // UNWIND_SECTION_VERSION306 // uint32_t commonEncodingsArraySectionOffset;307 // uint32_t commonEncodingsArrayCount;308 // uint32_t personalityArraySectionOffset;309 // uint32_t personalityArrayCount;310 // uint32_t indexSectionOffset;311 // uint32_t indexCount;312 // // compact_unwind_encoding_t[]313 // // uint32_t personalities[]314 // // unwind_info_section_header_index_entry[]315 // // unwind_info_section_header_lsda_index_entry[]316 // };317 318 if (auto Err = writeHeader(G, Writer))319 return Err;320 321 // Skip common encodings: JITLink doesn't use them.322 323 if (auto Err = writePersonalities(G, Writer))324 return Err;325 326 // Calculate the offset to the LSDAs.327 size_t SectionOffsetToLSDAs =328 Writer.getOffset() + (NumSecondLevelPages + 1) * IndexEntrySize;329 330 // Calculate offset to the 1st second-level page.331 size_t SectionOffsetToSecondLevelPages =332 SectionOffsetToLSDAs + NumLSDAs * LSDAEntrySize;333 334 if (auto Err = writeIndexes(G, Writer, SectionOffsetToLSDAs,335 SectionOffsetToSecondLevelPages))336 return Err;337 338 if (auto Err = writeLSDAs(G, Writer))339 return Err;340 341 if (auto Err = writeSecondLevelPages(G, Writer))342 return Err;343 344 LLVM_DEBUG({345 dbgs() << " Wrote " << formatv("{0:x}", Writer.getOffset())346 << " bytes of unwind info.\n";347 });348 349 return Error::success();350 }351 352private:353 // Calculate the size of unwind-info.354 static constexpr size_t MaxPersonalities = 4;355 static constexpr size_t PersonalityShift = 28;356 357 static constexpr size_t UnwindInfoSectionHeaderSize = 4 * 7;358 static constexpr size_t PersonalityEntrySize = 4;359 static constexpr size_t IndexEntrySize = 3 * 4;360 static constexpr size_t LSDAEntrySize = 2 * 4;361 static constexpr size_t SecondLevelPageSize = 4096;362 static constexpr size_t SecondLevelPageHeaderSize = 8;363 static constexpr size_t SecondLevelPageEntrySize = 8;364 static constexpr size_t NumRecordsPerSecondLevelPage =365 (SecondLevelPageSize - SecondLevelPageHeaderSize) /366 SecondLevelPageEntrySize;367 368 struct CompactUnwindRecord {369 Symbol *Fn = nullptr;370 uint32_t Size = 0;371 uint32_t Encoding = 0;372 Symbol *LSDA = nullptr;373 Symbol *FDE = nullptr;374 };375 376 Error processCompactUnwind(LinkGraph &G, Section &CUSec) {377 // TODO: Reset NumLSDAs, Personalities and CompactUnwindRecords if378 // processing more than once.379 assert(NumLSDAs == 0 && "NumLSDAs should be zero");380 assert(Records.empty() && "CompactUnwindRecords vector should be empty.");381 assert(Personalities.empty() && "Personalities vector should be empty.");382 383 SmallVector<CompactUnwindRecord> NonUniquedRecords;384 NonUniquedRecords.reserve(CUSec.blocks_size());385 386 // Process __compact_unwind blocks.387 for (auto *B : CUSec.blocks()) {388 CompactUnwindRecord R;389 R.Encoding = CURecTraits::readEncoding(B->getContent());390 for (auto &E : B->edges()) {391 switch (E.getOffset()) {392 case CURecTraits::FnFieldOffset:393 // This could be the function-pointer, or the FDE keep-alive. Check394 // the type to decide.395 if (E.getKind() == Edge::KeepAlive)396 R.FDE = &E.getTarget();397 else398 R.Fn = &E.getTarget();399 break;400 case CURecTraits::PersonalityFieldOffset: {401 // Add the Personality to the Personalities map and update the402 // encoding.403 size_t PersonalityIdx = 0;404 for (; PersonalityIdx != Personalities.size(); ++PersonalityIdx)405 if (Personalities[PersonalityIdx] == &E.getTarget())406 break;407 if (PersonalityIdx == MaxPersonalities)408 return make_error<JITLinkError>(409 "In " + G.getName() +410 ", __compact_unwind contains too many personalities (max " +411 formatv("{}", MaxPersonalities) + ")");412 if (PersonalityIdx == Personalities.size())413 Personalities.push_back(&E.getTarget());414 415 R.Encoding |= (PersonalityIdx + 1) << PersonalityShift;416 break;417 }418 case CURecTraits::LSDAFieldOffset:419 ++NumLSDAs;420 R.LSDA = &E.getTarget();421 break;422 default:423 return make_error<JITLinkError>("In " + G.getName() +424 ", compact unwind record at " +425 formatv("{0:x}", B->getAddress()) +426 " has unrecognized edge at offset " +427 formatv("{0:x}", E.getOffset()));428 }429 }430 Records.push_back(R);431 }432 433 // Sort the records into ascending order.434 llvm::sort(Records, [](const CompactUnwindRecord &LHS,435 const CompactUnwindRecord &RHS) {436 return LHS.Fn->getAddress() < RHS.Fn->getAddress();437 });438 439 // Calculate the number of second-level pages required.440 NumSecondLevelPages = (Records.size() + NumRecordsPerSecondLevelPage - 1) /441 NumRecordsPerSecondLevelPage;442 443 // Convert personality symbols to GOT entry pointers.444 typename CURecTraits::GOTManager GOT(G);445 for (auto &Personality : Personalities)446 Personality = &GOT.getEntryForTarget(G, *Personality);447 448 LLVM_DEBUG({449 dbgs() << " In " << G.getName() << ", " << CompactUnwindSectionName450 << ": raw records = " << Records.size()451 << ", personalities = " << Personalities.size()452 << ", lsdas = " << NumLSDAs << "\n";453 });454 455 return Error::success();456 }457 458 void mergeRecords() {459 SmallVector<CompactUnwindRecord> NonUniqued = std::move(Records);460 Records.reserve(NonUniqued.size());461 462 Records.push_back(NonUniqued.front());463 for (size_t I = 1; I != NonUniqued.size(); ++I) {464 auto &Next = NonUniqued[I];465 auto &Last = Records.back();466 467 bool NextNeedsDWARF = CURecTraits::encodingSpecifiesDWARF(Next.Encoding);468 bool CannotBeMerged = CURecTraits::encodingCannotBeMerged(Next.Encoding);469 if (NextNeedsDWARF || (Next.Encoding != Last.Encoding) ||470 CannotBeMerged || Next.LSDA || Last.LSDA)471 Records.push_back(Next);472 }473 474 // Recalculate derived values that may have changed.475 NumSecondLevelPages = (Records.size() + NumRecordsPerSecondLevelPage - 1) /476 NumRecordsPerSecondLevelPage;477 }478 479 Error writeHeader(LinkGraph &G, BinaryStreamWriter &W) {480 if (!isUInt<32>(NumSecondLevelPages + 1))481 return make_error<JITLinkError>("In " + G.getName() + ", too many " +482 UnwindInfoSectionName +483 "second-level pages required");484 485 // Write __unwind_info header.486 size_t IndexArrayOffset = UnwindInfoSectionHeaderSize +487 Personalities.size() * PersonalityEntrySize;488 489 cantFail(W.writeInteger<uint32_t>(1));490 cantFail(W.writeInteger<uint32_t>(UnwindInfoSectionHeaderSize));491 cantFail(W.writeInteger<uint32_t>(0));492 cantFail(W.writeInteger<uint32_t>(UnwindInfoSectionHeaderSize));493 cantFail(W.writeInteger<uint32_t>(Personalities.size()));494 cantFail(W.writeInteger<uint32_t>(IndexArrayOffset));495 cantFail(W.writeInteger<uint32_t>(NumSecondLevelPages + 1));496 497 return Error::success();498 }499 500 Error writePersonalities(LinkGraph &G, BinaryStreamWriter &W) {501 // Write personalities.502 for (auto *PSym : Personalities) {503 auto Delta = PSym->getAddress() - CompactUnwindBase->getAddress();504 if (!isUInt<32>(Delta))505 return makePersonalityRangeError(G, *PSym);506 cantFail(W.writeInteger<uint32_t>(Delta));507 }508 return Error::success();509 }510 511 Error writeIndexes(LinkGraph &G, BinaryStreamWriter &W,512 size_t SectionOffsetToLSDAs,513 size_t SectionOffsetToSecondLevelPages) {514 // Assume that function deltas are ok in this method -- we'll error515 // check all of them when we write the second level pages.516 517 // Write the header index entries.518 size_t RecordIdx = 0;519 size_t NumPreviousLSDAs = 0;520 for (auto &R : Records) {521 // If this record marks the start of a new second level page.522 if (RecordIdx % NumRecordsPerSecondLevelPage == 0) {523 auto FnDelta = R.Fn->getAddress() - CompactUnwindBase->getAddress();524 auto SecondLevelPageOffset =525 SectionOffsetToSecondLevelPages +526 SecondLevelPageSize * (RecordIdx / NumRecordsPerSecondLevelPage);527 auto LSDAOffset =528 SectionOffsetToLSDAs + NumPreviousLSDAs * LSDAEntrySize;529 530 cantFail(W.writeInteger<uint32_t>(FnDelta));531 cantFail(W.writeInteger<uint32_t>(SecondLevelPageOffset));532 cantFail(W.writeInteger<uint32_t>(LSDAOffset));533 }534 if (R.LSDA)535 ++NumPreviousLSDAs;536 ++RecordIdx;537 }538 539 // Write the index array terminator.540 {541 auto FnEndDelta =542 Records.back().Fn->getRange().End - CompactUnwindBase->getAddress();543 544 if (LLVM_UNLIKELY(!isUInt<32>(FnEndDelta)))545 return make_error<JITLinkError>(546 "In " + G.getName() + " " + UnwindInfoSectionName +547 ", delta to end of functions " +548 formatv("{0:x}", Records.back().Fn->getRange().End) +549 " exceeds 32 bits");550 551 cantFail(W.writeInteger<uint32_t>(FnEndDelta));552 cantFail(W.writeInteger<uint32_t>(0));553 cantFail(W.writeInteger<uint32_t>(SectionOffsetToSecondLevelPages));554 }555 556 return Error::success();557 }558 559 Error writeLSDAs(LinkGraph &G, BinaryStreamWriter &W) {560 // As with writeIndexes, assume that function deltas are ok for now.561 for (auto &R : Records) {562 if (R.LSDA) {563 auto FnDelta = R.Fn->getAddress() - CompactUnwindBase->getAddress();564 auto LSDADelta = R.LSDA->getAddress() - CompactUnwindBase->getAddress();565 566 if (LLVM_UNLIKELY(!isUInt<32>(LSDADelta)))567 return make_error<JITLinkError>(568 "In " + G.getName() + " " + UnwindInfoSectionName +569 ", delta to lsda at " + formatv("{0:x}", R.LSDA->getAddress()) +570 " exceeds 32 bits");571 572 cantFail(W.writeInteger<uint32_t>(FnDelta));573 cantFail(W.writeInteger<uint32_t>(LSDADelta));574 }575 }576 577 return Error::success();578 }579 580 Error writeSecondLevelPages(LinkGraph &G, BinaryStreamWriter &W) {581 size_t RecordIdx = 0;582 583 for (auto &R : Records) {584 // When starting a new second-level page, write the page header:585 //586 // 2 : uint32_t -- UNWIND_SECOND_LEVEL_REGULAR587 // 8 : uint16_t -- size of second level page table header588 // count : uint16_t -- num entries in this second-level page589 if (RecordIdx % NumRecordsPerSecondLevelPage == 0) {590 constexpr uint32_t SecondLevelPageHeaderKind = 2;591 constexpr uint16_t SecondLevelPageHeaderSize = 8;592 uint16_t SecondLevelPageNumEntries =593 std::min(Records.size() - RecordIdx, NumRecordsPerSecondLevelPage);594 595 cantFail(W.writeInteger<uint32_t>(SecondLevelPageHeaderKind));596 cantFail(W.writeInteger<uint16_t>(SecondLevelPageHeaderSize));597 cantFail(W.writeInteger<uint16_t>(SecondLevelPageNumEntries));598 }599 600 // Write entry.601 auto FnDelta = R.Fn->getAddress() - CompactUnwindBase->getAddress();602 603 if (LLVM_UNLIKELY(!isUInt<32>(FnDelta)))604 return make_error<JITLinkError>(605 "In " + G.getName() + " " + UnwindInfoSectionName +606 ", delta to function at " + formatv("{0:x}", R.Fn->getAddress()) +607 " exceeds 32 bits");608 609 auto Encoding = R.Encoding;610 611 if (LLVM_UNLIKELY(CURecTraits::encodingSpecifiesDWARF(R.Encoding))) {612 if (!EHFrameBase)613 EHFrameBase = SectionRange(R.FDE->getSection()).getStart();614 auto FDEDelta = R.FDE->getAddress() - EHFrameBase;615 616 if (auto EncodedFDEDelta = CURecTraits::encodeDWARFOffset(FDEDelta))617 Encoding |= *EncodedFDEDelta;618 else619 return make_error<JITLinkError>(620 "In " + G.getName() + " " + UnwindInfoSectionName +621 ", cannot encode delta " + formatv("{0:x}", FDEDelta) +622 " to FDE at " + formatv("{0:x}", R.FDE->getAddress()));623 }624 625 cantFail(W.writeInteger<uint32_t>(FnDelta));626 cantFail(W.writeInteger<uint32_t>(Encoding));627 628 ++RecordIdx;629 }630 631 return Error::success();632 }633 634 Error getOrCreateCompactUnwindBase(LinkGraph &G) {635 auto Name = G.intern("__jitlink$libunwind_dso_base");636 CompactUnwindBase = G.findAbsoluteSymbolByName(Name);637 if (!CompactUnwindBase) {638 if (auto LocalCUBase = getOrCreateLocalMachOHeader(G)) {639 CompactUnwindBase = &*LocalCUBase;640 auto &B = LocalCUBase->getBlock();641 G.addDefinedSymbol(B, 0, *Name, B.getSize(), Linkage::Strong,642 Scope::Local, false, true);643 } else644 return LocalCUBase.takeError();645 }646 CompactUnwindBase->setLive(true);647 return Error::success();648 }649 650 Error makePersonalityRangeError(LinkGraph &G, Symbol &PSym) {651 std::string ErrMsg;652 {653 raw_string_ostream ErrStream(ErrMsg);654 ErrStream << "In " << G.getName() << " " << UnwindInfoSectionName655 << ", personality ";656 if (PSym.hasName())657 ErrStream << PSym.getName() << " ";658 ErrStream << "at " << PSym.getAddress()659 << " is out of 32-bit delta range of compact-unwind base at "660 << CompactUnwindBase->getAddress();661 }662 return make_error<JITLinkError>(std::move(ErrMsg));663 }664 665 StringRef CompactUnwindSectionName;666 StringRef UnwindInfoSectionName;667 StringRef EHFrameSectionName;668 Symbol *CompactUnwindBase = nullptr;669 orc::ExecutorAddr EHFrameBase;670 671 size_t NumLSDAs = 0;672 size_t NumSecondLevelPages = 0;673 SmallVector<Symbol *, MaxPersonalities> Personalities;674 SmallVector<CompactUnwindRecord> Records;675};676 677} // end namespace jitlink678} // end namespace llvm679 680#undef DEBUG_TYPE681 682#endif // LIB_EXECUTIONENGINE_JITLINK_COMPACTUNWINDSUPPORTIMPL_H683