Path: blob/main/contrib/llvm-project/llvm/lib/ExecutionEngine/JITLink/CompactUnwindSupport.h
213799 views
//===- CompactUnwindSupportImpl.h - Compact Unwind format impl --*- C++ -*-===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// Compact Unwind format support implementation details.9//10//===----------------------------------------------------------------------===//1112#ifndef LIB_EXECUTIONENGINE_JITLINK_COMPACTUNWINDSUPPORTIMPL_H13#define LIB_EXECUTIONENGINE_JITLINK_COMPACTUNWINDSUPPORTIMPL_H1415#include "llvm/ADT/STLExtras.h"16#include "llvm/ExecutionEngine/JITLink/MachO.h"17#include "llvm/Support/Debug.h"18#include "llvm/Support/Endian.h"1920#define DEBUG_TYPE "jitlink_cu"2122namespace llvm {23namespace jitlink {2425/// Split blocks in an __LD,__compact_unwind section on record boundaries.26/// When this function returns edges within each record are guaranteed to be27/// sorted by offset.28Error splitCompactUnwindBlocks(LinkGraph &G, Section &CompactUnwindSection,29size_t RecordSize);3031/// CRTP base for compact unwind traits classes. Automatically provides derived32/// constants.33///34/// FIXME: Passing PtrSize as a template parameter is a hack to work around a35/// bug in older MSVC compilers (until at least MSVC 15) where constexpr36/// fields in the CRTP impl class were not visible to the base class.37/// Once we no longer need to support these compilers the PtrSize38/// template argument should be removed and PointerSize should be39/// defined as a member in the CRTP Impl classes.40template <typename CRTPImpl, size_t PtrSize> struct CompactUnwindTraits {41static constexpr size_t PointerSize = PtrSize;42static constexpr size_t Size = 3 * PointerSize + 2 * 4;43static constexpr size_t FnFieldOffset = 0;44static constexpr size_t SizeFieldOffset = FnFieldOffset + PointerSize;45static constexpr size_t EncodingFieldOffset = SizeFieldOffset + 4;46static constexpr size_t PersonalityFieldOffset = EncodingFieldOffset + 4;47static constexpr size_t LSDAFieldOffset =48PersonalityFieldOffset + PointerSize;4950static uint32_t readPCRangeSize(ArrayRef<char> RecordContent) {51assert(SizeFieldOffset + 4 <= RecordContent.size() &&52"Truncated CU record?");53return support::endian::read32<CRTPImpl::Endianness>(RecordContent.data() +54SizeFieldOffset);55}5657static uint32_t readEncoding(ArrayRef<char> RecordContent) {58assert(EncodingFieldOffset + 4 <= RecordContent.size() &&59"Truncated CU record?");60return support::endian::read32<CRTPImpl::Endianness>(RecordContent.data() +61EncodingFieldOffset);62}6364static std::optional<uint32_t> encodeDWARFOffset(size_t Delta) {65uint32_t Encoded =66static_cast<uint32_t>(Delta) & CRTPImpl::DWARFSectionOffsetMask;67if (Encoded != Delta)68return std::nullopt;69return Encoded;70}71};7273/// Architecture specific implementation of CompactUnwindManager.74template <typename CURecTraits> class CompactUnwindManager {75public:76CompactUnwindManager(StringRef CompactUnwindSectionName,77StringRef UnwindInfoSectionName,78StringRef EHFrameSectionName)79: CompactUnwindSectionName(CompactUnwindSectionName),80UnwindInfoSectionName(UnwindInfoSectionName),81EHFrameSectionName(EHFrameSectionName) {}8283// Split compact unwind records, add keep-alive edges from functions to84// compact unwind records, and from compact unwind records to FDEs where85// needed.86//87// This method must be called *after* __eh_frame has been processed: it88// assumes that eh-frame records have been split up and keep-alive edges have89// been inserted.90Error prepareForPrune(LinkGraph &G) {91Section *CUSec = G.findSectionByName(CompactUnwindSectionName);92if (!CUSec || CUSec->empty()) {93LLVM_DEBUG({94dbgs() << "Compact unwind: No compact unwind info for " << G.getName()95<< "\n";96});97return Error::success();98}99100LLVM_DEBUG({101dbgs() << "Compact unwind: preparing " << G.getName() << " for prune\n";102});103104Section *EHFrameSec = G.findSectionByName(EHFrameSectionName);105106if (auto Err = splitCompactUnwindBlocks(G, *CUSec, CURecTraits::Size))107return Err;108109LLVM_DEBUG({110dbgs() << " Preparing " << CUSec->blocks_size() << " blocks in "111<< CompactUnwindSectionName << "\n";112});113114for (auto *B : CUSec->blocks()) {115116// Find target function edge.117Edge *PCBeginEdge = nullptr;118for (auto &E : B->edges_at(CURecTraits::FnFieldOffset)) {119PCBeginEdge = &E;120break;121}122123if (!PCBeginEdge)124return make_error<JITLinkError>(125"In " + G.getName() + ", compact unwind record at " +126formatv("{0:x}", B->getAddress()) + " has no pc-begin edge");127128if (!PCBeginEdge->getTarget().isDefined())129return make_error<JITLinkError>(130"In " + G.getName() + ", compact unwind record at " +131formatv("{0:x}", B->getAddress()) + " points at external symbol " +132*PCBeginEdge->getTarget().getName());133134auto &Fn = PCBeginEdge->getTarget();135136if (!Fn.isDefined()) {137LLVM_DEBUG({138dbgs() << "In " << CompactUnwindSectionName << " for " << G.getName()139<< " encountered unexpected pc-edge to undefined symbol "140<< Fn.getName() << "\n";141});142continue;143}144145uint32_t Encoding = CURecTraits::readEncoding(B->getContent());146bool NeedsDWARF = CURecTraits::encodingSpecifiesDWARF(Encoding);147148LLVM_DEBUG({149dbgs() << " Found record for function ";150if (Fn.hasName())151dbgs() << Fn.getName();152else153dbgs() << "<anon @ " << Fn.getAddress() << '>';154dbgs() << ": encoding = " << formatv("{0:x}", Encoding);155if (NeedsDWARF)156dbgs() << " (needs DWARF)";157dbgs() << "\n";158});159160auto &CURecSym =161G.addAnonymousSymbol(*B, 0, CURecTraits::Size, false, false);162163bool KeepAliveAlreadyPresent = false;164if (EHFrameSec) {165Edge *KeepAliveEdge = nullptr;166for (auto &E : Fn.getBlock().edges_at(0)) {167if (E.getKind() == Edge::KeepAlive && E.getTarget().isDefined() &&168&E.getTarget().getSection() == EHFrameSec) {169KeepAliveEdge = &E;170break;171}172}173174if (KeepAliveEdge) {175// Found a keep-alive edge to an FDE in the eh-frame. Switch the keep176// alive edge to point to the CU and if the CU needs DWARF then add177// an extra keep-alive edge from the CU to the FDE.178auto &FDE = KeepAliveEdge->getTarget();179KeepAliveEdge->setTarget(CURecSym);180KeepAliveAlreadyPresent = true;181if (NeedsDWARF) {182LLVM_DEBUG({183dbgs() << " Adding keep-alive edge to FDE at "184<< FDE.getAddress() << "\n";185});186B->addEdge(Edge::KeepAlive, 0, FDE, 0);187}188} else {189if (NeedsDWARF)190return make_error<JITLinkError>(191"In " + G.getName() + ", compact unwind recard ot " +192formatv("{0:x}", B->getAddress()) +193" needs DWARF, but no FDE was found");194}195} else {196if (NeedsDWARF)197return make_error<JITLinkError>(198"In " + G.getName() + ", compact unwind recard ot " +199formatv("{0:x}", B->getAddress()) + " needs DWARF, but no " +200EHFrameSectionName + " section exists");201}202203if (!KeepAliveAlreadyPresent) {204// No FDE edge. We'll need to add a new edge from the function back205// to the CU record.206Fn.getBlock().addEdge(Edge::KeepAlive, 0, CURecSym, 0);207}208}209210return Error::success();211}212213/// Process all __compact_unwind records and reserve space for __unwind_info.214Error processAndReserveUnwindInfo(LinkGraph &G) {215// Bail out early if no unwind info.216Section *CUSec = G.findSectionByName(CompactUnwindSectionName);217if (!CUSec)218return Error::success();219220// The __LD/__compact_unwind section is only used as input for the linker.221// We'll create a new __TEXT,__unwind_info section for unwind info output.222CUSec->setMemLifetime(orc::MemLifetime::NoAlloc);223224// Find / make a mach-header to act as the base for unwind-info offsets225// (and to report the arch / subarch to libunwind).226if (auto Err = getOrCreateCompactUnwindBase(G))227return Err;228229// Error out if there's already unwind-info in the graph: We have no idea230// how to merge unwind-info sections.231if (G.findSectionByName(UnwindInfoSectionName))232return make_error<JITLinkError>("In " + G.getName() + ", " +233UnwindInfoSectionName +234" already exists");235236// Process the __compact_unwind section to build the Records vector that237// we'll use for writing the __unwind_info section.238if (auto Err = processCompactUnwind(G, *CUSec))239return Err;240241// Calculate the size of __unwind_info.242size_t UnwindInfoSectionSize =243UnwindInfoSectionHeaderSize +244Personalities.size() * PersonalityEntrySize +245(NumSecondLevelPages + 1) * IndexEntrySize + NumLSDAs * LSDAEntrySize +246NumSecondLevelPages * SecondLevelPageHeaderSize +247Records.size() * SecondLevelPageEntrySize;248249LLVM_DEBUG({250dbgs() << "In " << G.getName() << ", reserving "251<< formatv("{0:x}", UnwindInfoSectionSize) << " bytes for "252<< UnwindInfoSectionName << "\n";253});254255// Create the __unwind_info section and reserve space for it.256Section &UnwindInfoSec =257G.createSection(UnwindInfoSectionName, orc::MemProt::Read);258259auto UnwindInfoSectionContent = G.allocateBuffer(UnwindInfoSectionSize);260memset(UnwindInfoSectionContent.data(), 0, UnwindInfoSectionContent.size());261auto &B = G.createMutableContentBlock(262UnwindInfoSec, UnwindInfoSectionContent, orc::ExecutorAddr(), 8, 0);263264// Add Keep-alive edges from the __unwind_info block to all of the target265// functions.266for (auto &R : Records)267B.addEdge(Edge::KeepAlive, 0, *R.Fn, 0);268269return Error::success();270}271272Error writeUnwindInfo(LinkGraph &G) {273Section *CUSec = G.findSectionByName(CompactUnwindSectionName);274if (!CUSec || CUSec->empty())275return Error::success();276277Section *UnwindInfoSec = G.findSectionByName(UnwindInfoSectionName);278if (!UnwindInfoSec)279return make_error<JITLinkError>("In " + G.getName() + ", " +280UnwindInfoSectionName +281" missing after allocation");282283if (UnwindInfoSec->blocks_size() != 1)284return make_error<JITLinkError>(285"In " + G.getName() + ", " + UnwindInfoSectionName +286" contains more than one block post-allocation");287288LLVM_DEBUG(289{ dbgs() << "Writing unwind info for " << G.getName() << "...\n"; });290291mergeRecords();292293auto &UnwindInfoBlock = **UnwindInfoSec->blocks().begin();294auto Content = UnwindInfoBlock.getMutableContent(G);295BinaryStreamWriter Writer(296{reinterpret_cast<uint8_t *>(Content.data()), Content.size()},297CURecTraits::Endianness);298299// __unwind_info format, from mach-o/compact_unwind_encoding.h on Darwin:300//301// #define UNWIND_SECTION_VERSION 1302// struct unwind_info_section_header303// {304// uint32_t version; // UNWIND_SECTION_VERSION305// uint32_t commonEncodingsArraySectionOffset;306// uint32_t commonEncodingsArrayCount;307// uint32_t personalityArraySectionOffset;308// uint32_t personalityArrayCount;309// uint32_t indexSectionOffset;310// uint32_t indexCount;311// // compact_unwind_encoding_t[]312// // uint32_t personalities[]313// // unwind_info_section_header_index_entry[]314// // unwind_info_section_header_lsda_index_entry[]315// };316317if (auto Err = writeHeader(G, Writer))318return Err;319320// Skip common encodings: JITLink doesn't use them.321322if (auto Err = writePersonalities(G, Writer))323return Err;324325// Calculate the offset to the LSDAs.326size_t SectionOffsetToLSDAs =327Writer.getOffset() + (NumSecondLevelPages + 1) * IndexEntrySize;328329// Calculate offset to the 1st second-level page.330size_t SectionOffsetToSecondLevelPages =331SectionOffsetToLSDAs + NumLSDAs * LSDAEntrySize;332333if (auto Err = writeIndexes(G, Writer, SectionOffsetToLSDAs,334SectionOffsetToSecondLevelPages))335return Err;336337if (auto Err = writeLSDAs(G, Writer))338return Err;339340if (auto Err = writeSecondLevelPages(G, Writer))341return Err;342343LLVM_DEBUG({344dbgs() << " Wrote " << formatv("{0:x}", Writer.getOffset())345<< " bytes of unwind info.\n";346});347348return Error::success();349}350351private:352// Calculate the size of unwind-info.353static constexpr size_t MaxPersonalities = 4;354static constexpr size_t PersonalityShift = 28;355356static constexpr size_t UnwindInfoSectionHeaderSize = 4 * 7;357static constexpr size_t PersonalityEntrySize = 4;358static constexpr size_t IndexEntrySize = 3 * 4;359static constexpr size_t LSDAEntrySize = 2 * 4;360static constexpr size_t SecondLevelPageSize = 4096;361static constexpr size_t SecondLevelPageHeaderSize = 8;362static constexpr size_t SecondLevelPageEntrySize = 8;363static constexpr size_t NumRecordsPerSecondLevelPage =364(SecondLevelPageSize - SecondLevelPageHeaderSize) /365SecondLevelPageEntrySize;366367struct CompactUnwindRecord {368Symbol *Fn = nullptr;369uint32_t Size = 0;370uint32_t Encoding = 0;371Symbol *LSDA = nullptr;372Symbol *FDE = nullptr;373};374375Error processCompactUnwind(LinkGraph &G, Section &CUSec) {376// TODO: Reset NumLSDAs, Personalities and CompactUnwindRecords if377// processing more than once.378assert(NumLSDAs == 0 && "NumLSDAs should be zero");379assert(Records.empty() && "CompactUnwindRecords vector should be empty.");380assert(Personalities.empty() && "Personalities vector should be empty.");381382SmallVector<CompactUnwindRecord> NonUniquedRecords;383NonUniquedRecords.reserve(CUSec.blocks_size());384385// Process __compact_unwind blocks.386for (auto *B : CUSec.blocks()) {387CompactUnwindRecord R;388R.Encoding = CURecTraits::readEncoding(B->getContent());389for (auto &E : B->edges()) {390switch (E.getOffset()) {391case CURecTraits::FnFieldOffset:392// This could be the function-pointer, or the FDE keep-alive. Check393// the type to decide.394if (E.getKind() == Edge::KeepAlive)395R.FDE = &E.getTarget();396else397R.Fn = &E.getTarget();398break;399case CURecTraits::PersonalityFieldOffset: {400// Add the Personality to the Personalities map and update the401// encoding.402size_t PersonalityIdx = 0;403for (; PersonalityIdx != Personalities.size(); ++PersonalityIdx)404if (Personalities[PersonalityIdx] == &E.getTarget())405break;406if (PersonalityIdx == MaxPersonalities)407return make_error<JITLinkError>(408"In " + G.getName() +409", __compact_unwind contains too many personalities (max " +410formatv("{}", MaxPersonalities) + ")");411if (PersonalityIdx == Personalities.size())412Personalities.push_back(&E.getTarget());413414R.Encoding |= (PersonalityIdx + 1) << PersonalityShift;415break;416}417case CURecTraits::LSDAFieldOffset:418++NumLSDAs;419R.LSDA = &E.getTarget();420break;421default:422return make_error<JITLinkError>("In " + G.getName() +423", compact unwind record at " +424formatv("{0:x}", B->getAddress()) +425" has unrecognized edge at offset " +426formatv("{0:x}", E.getOffset()));427}428}429Records.push_back(R);430}431432// Sort the records into ascending order.433llvm::sort(Records, [](const CompactUnwindRecord &LHS,434const CompactUnwindRecord &RHS) {435return LHS.Fn->getAddress() < RHS.Fn->getAddress();436});437438// Calculate the number of second-level pages required.439NumSecondLevelPages = (Records.size() + NumRecordsPerSecondLevelPage - 1) /440NumRecordsPerSecondLevelPage;441442// Convert personality symbols to GOT entry pointers.443typename CURecTraits::GOTManager GOT(G);444for (auto &Personality : Personalities)445Personality = &GOT.getEntryForTarget(G, *Personality);446447LLVM_DEBUG({448dbgs() << " In " << G.getName() << ", " << CompactUnwindSectionName449<< ": raw records = " << Records.size()450<< ", personalities = " << Personalities.size()451<< ", lsdas = " << NumLSDAs << "\n";452});453454return Error::success();455}456457void mergeRecords() {458SmallVector<CompactUnwindRecord> NonUniqued = std::move(Records);459Records.reserve(NonUniqued.size());460461Records.push_back(NonUniqued.front());462for (size_t I = 1; I != NonUniqued.size(); ++I) {463auto &Next = NonUniqued[I];464auto &Last = Records.back();465466bool NextNeedsDWARF = CURecTraits::encodingSpecifiesDWARF(Next.Encoding);467bool CannotBeMerged = CURecTraits::encodingCannotBeMerged(Next.Encoding);468if (NextNeedsDWARF || (Next.Encoding != Last.Encoding) ||469CannotBeMerged || Next.LSDA || Last.LSDA)470Records.push_back(Next);471}472473// Recalculate derived values that may have changed.474NumSecondLevelPages = (Records.size() + NumRecordsPerSecondLevelPage - 1) /475NumRecordsPerSecondLevelPage;476}477478Error writeHeader(LinkGraph &G, BinaryStreamWriter &W) {479if (!isUInt<32>(NumSecondLevelPages + 1))480return make_error<JITLinkError>("In " + G.getName() + ", too many " +481UnwindInfoSectionName +482"second-level pages required");483484// Write __unwind_info header.485size_t IndexArrayOffset = UnwindInfoSectionHeaderSize +486Personalities.size() * PersonalityEntrySize;487488cantFail(W.writeInteger<uint32_t>(1));489cantFail(W.writeInteger<uint32_t>(UnwindInfoSectionHeaderSize));490cantFail(W.writeInteger<uint32_t>(0));491cantFail(W.writeInteger<uint32_t>(UnwindInfoSectionHeaderSize));492cantFail(W.writeInteger<uint32_t>(Personalities.size()));493cantFail(W.writeInteger<uint32_t>(IndexArrayOffset));494cantFail(W.writeInteger<uint32_t>(NumSecondLevelPages + 1));495496return Error::success();497}498499Error writePersonalities(LinkGraph &G, BinaryStreamWriter &W) {500// Write personalities.501for (auto *PSym : Personalities) {502auto Delta = PSym->getAddress() - CompactUnwindBase->getAddress();503if (!isUInt<32>(Delta))504return makePersonalityRangeError(G, *PSym);505cantFail(W.writeInteger<uint32_t>(Delta));506}507return Error::success();508}509510Error writeIndexes(LinkGraph &G, BinaryStreamWriter &W,511size_t SectionOffsetToLSDAs,512size_t SectionOffsetToSecondLevelPages) {513// Assume that function deltas are ok in this method -- we'll error514// check all of them when we write the second level pages.515516// Write the header index entries.517size_t RecordIdx = 0;518size_t NumPreviousLSDAs = 0;519for (auto &R : Records) {520// If this record marks the start of a new second level page.521if (RecordIdx % NumRecordsPerSecondLevelPage == 0) {522auto FnDelta = R.Fn->getAddress() - CompactUnwindBase->getAddress();523auto SecondLevelPageOffset =524SectionOffsetToSecondLevelPages +525SecondLevelPageSize * (RecordIdx / NumRecordsPerSecondLevelPage);526auto LSDAOffset =527SectionOffsetToLSDAs + NumPreviousLSDAs * LSDAEntrySize;528529cantFail(W.writeInteger<uint32_t>(FnDelta));530cantFail(W.writeInteger<uint32_t>(SecondLevelPageOffset));531cantFail(W.writeInteger<uint32_t>(LSDAOffset));532}533if (R.LSDA)534++NumPreviousLSDAs;535++RecordIdx;536}537538// Write the index array terminator.539{540auto FnEndDelta =541Records.back().Fn->getRange().End - CompactUnwindBase->getAddress();542543if (LLVM_UNLIKELY(!isUInt<32>(FnEndDelta)))544return make_error<JITLinkError>(545"In " + G.getName() + " " + UnwindInfoSectionName +546", delta to end of functions " +547formatv("{0:x}", Records.back().Fn->getRange().End) +548" exceeds 32 bits");549550cantFail(W.writeInteger<uint32_t>(FnEndDelta));551cantFail(W.writeInteger<uint32_t>(0));552cantFail(W.writeInteger<uint32_t>(SectionOffsetToSecondLevelPages));553}554555return Error::success();556}557558Error writeLSDAs(LinkGraph &G, BinaryStreamWriter &W) {559// As with writeIndexes, assume that function deltas are ok for now.560for (auto &R : Records) {561if (R.LSDA) {562auto FnDelta = R.Fn->getAddress() - CompactUnwindBase->getAddress();563auto LSDADelta = R.LSDA->getAddress() - CompactUnwindBase->getAddress();564565if (LLVM_UNLIKELY(!isUInt<32>(LSDADelta)))566return make_error<JITLinkError>(567"In " + G.getName() + " " + UnwindInfoSectionName +568", delta to lsda at " + formatv("{0:x}", R.LSDA->getAddress()) +569" exceeds 32 bits");570571cantFail(W.writeInteger<uint32_t>(FnDelta));572cantFail(W.writeInteger<uint32_t>(LSDADelta));573}574}575576return Error::success();577}578579Error writeSecondLevelPages(LinkGraph &G, BinaryStreamWriter &W) {580size_t RecordIdx = 0;581582for (auto &R : Records) {583// When starting a new second-level page, write the page header:584//585// 2 : uint32_t -- UNWIND_SECOND_LEVEL_REGULAR586// 8 : uint16_t -- size of second level page table header587// count : uint16_t -- num entries in this second-level page588if (RecordIdx % NumRecordsPerSecondLevelPage == 0) {589constexpr uint32_t SecondLevelPageHeaderKind = 2;590constexpr uint16_t SecondLevelPageHeaderSize = 8;591uint16_t SecondLevelPageNumEntries =592std::min(Records.size() - RecordIdx, NumRecordsPerSecondLevelPage);593594cantFail(W.writeInteger<uint32_t>(SecondLevelPageHeaderKind));595cantFail(W.writeInteger<uint16_t>(SecondLevelPageHeaderSize));596cantFail(W.writeInteger<uint16_t>(SecondLevelPageNumEntries));597}598599// Write entry.600auto FnDelta = R.Fn->getAddress() - CompactUnwindBase->getAddress();601602if (LLVM_UNLIKELY(!isUInt<32>(FnDelta)))603return make_error<JITLinkError>(604"In " + G.getName() + " " + UnwindInfoSectionName +605", delta to function at " + formatv("{0:x}", R.Fn->getAddress()) +606" exceeds 32 bits");607608auto Encoding = R.Encoding;609610if (LLVM_UNLIKELY(CURecTraits::encodingSpecifiesDWARF(R.Encoding))) {611if (!EHFrameBase)612EHFrameBase = SectionRange(R.FDE->getSection()).getStart();613auto FDEDelta = R.FDE->getAddress() - EHFrameBase;614615if (auto EncodedFDEDelta = CURecTraits::encodeDWARFOffset(FDEDelta))616Encoding |= *EncodedFDEDelta;617else618return make_error<JITLinkError>(619"In " + G.getName() + " " + UnwindInfoSectionName +620", cannot encode delta " + formatv("{0:x}", FDEDelta) +621" to FDE at " + formatv("{0:x}", R.FDE->getAddress()));622}623624cantFail(W.writeInteger<uint32_t>(FnDelta));625cantFail(W.writeInteger<uint32_t>(Encoding));626627++RecordIdx;628}629630return Error::success();631}632633Error getOrCreateCompactUnwindBase(LinkGraph &G) {634auto Name = G.intern("__jitlink$libunwind_dso_base");635CompactUnwindBase = G.findAbsoluteSymbolByName(Name);636if (!CompactUnwindBase) {637if (auto LocalCUBase = getOrCreateLocalMachOHeader(G)) {638CompactUnwindBase = &*LocalCUBase;639auto &B = LocalCUBase->getBlock();640G.addDefinedSymbol(B, 0, *Name, B.getSize(), Linkage::Strong,641Scope::Local, false, true);642} else643return LocalCUBase.takeError();644}645CompactUnwindBase->setLive(true);646return Error::success();647}648649Error makePersonalityRangeError(LinkGraph &G, Symbol &PSym) {650std::string ErrMsg;651{652raw_string_ostream ErrStream(ErrMsg);653ErrStream << "In " << G.getName() << " " << UnwindInfoSectionName654<< ", personality ";655if (PSym.hasName())656ErrStream << PSym.getName() << " ";657ErrStream << "at " << PSym.getAddress()658<< " is out of 32-bit delta range of compact-unwind base at "659<< CompactUnwindBase->getAddress();660}661return make_error<JITLinkError>(std::move(ErrMsg));662}663664StringRef CompactUnwindSectionName;665StringRef UnwindInfoSectionName;666StringRef EHFrameSectionName;667Symbol *CompactUnwindBase = nullptr;668orc::ExecutorAddr EHFrameBase;669670size_t NumLSDAs = 0;671size_t NumSecondLevelPages = 0;672SmallVector<Symbol *, MaxPersonalities> Personalities;673SmallVector<CompactUnwindRecord> Records;674};675676} // end namespace jitlink677} // end namespace llvm678679#undef DEBUG_TYPE680681#endif // LIB_EXECUTIONENGINE_JITLINK_COMPACTUNWINDSUPPORTIMPL_H682683684