brintos

brintos / llvm-project-archived public Read only

0
0
Text · 25.4 KiB · c3f8834 Raw
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