Path: blob/main/contrib/llvm-project/llvm/lib/ExecutionEngine/JITLink/EHFrameSupport.cpp
35271 views
//===-------- JITLink_EHFrameSupport.cpp - JITLink eh-frame utils ---------===//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//===----------------------------------------------------------------------===//78#include "EHFrameSupportImpl.h"910#include "llvm/BinaryFormat/Dwarf.h"11#include "llvm/Config/config.h"12#include "llvm/ExecutionEngine/JITLink/DWARFRecordSectionSplitter.h"13#include "llvm/ExecutionEngine/Orc/TargetProcess/RegisterEHFrames.h"14#include "llvm/Support/DynamicLibrary.h"1516#define DEBUG_TYPE "jitlink"1718namespace llvm {19namespace jitlink {2021EHFrameEdgeFixer::EHFrameEdgeFixer(StringRef EHFrameSectionName,22unsigned PointerSize, Edge::Kind Pointer32,23Edge::Kind Pointer64, Edge::Kind Delta32,24Edge::Kind Delta64, Edge::Kind NegDelta32)25: EHFrameSectionName(EHFrameSectionName), PointerSize(PointerSize),26Pointer32(Pointer32), Pointer64(Pointer64), Delta32(Delta32),27Delta64(Delta64), NegDelta32(NegDelta32) {}2829Error EHFrameEdgeFixer::operator()(LinkGraph &G) {30auto *EHFrame = G.findSectionByName(EHFrameSectionName);3132if (!EHFrame) {33LLVM_DEBUG({34dbgs() << "EHFrameEdgeFixer: No " << EHFrameSectionName35<< " section in \"" << G.getName() << "\". Nothing to do.\n";36});37return Error::success();38}3940// Check that we support the graph's pointer size.41if (G.getPointerSize() != 4 && G.getPointerSize() != 8)42return make_error<JITLinkError>(43"EHFrameEdgeFixer only supports 32 and 64 bit targets");4445LLVM_DEBUG({46dbgs() << "EHFrameEdgeFixer: Processing " << EHFrameSectionName << " in \""47<< G.getName() << "\"...\n";48});4950ParseContext PC(G);5152// Build a map of all blocks and symbols in the text sections. We will use53// these for finding / building edge targets when processing FDEs.54for (auto &Sec : G.sections()) {55// Just record the most-canonical symbol (for eh-frame purposes) at each56// address.57for (auto *Sym : Sec.symbols()) {58auto &CurSym = PC.AddrToSym[Sym->getAddress()];59if (!CurSym || (std::make_tuple(Sym->getLinkage(), Sym->getScope(),60!Sym->hasName(), Sym->getName()) <61std::make_tuple(CurSym->getLinkage(), CurSym->getScope(),62!CurSym->hasName(), CurSym->getName())))63CurSym = Sym;64}65if (auto Err = PC.AddrToBlock.addBlocks(Sec.blocks(),66BlockAddressMap::includeNonNull))67return Err;68}6970// Sort eh-frame blocks into address order to ensure we visit CIEs before71// their child FDEs.72std::vector<Block *> EHFrameBlocks;73for (auto *B : EHFrame->blocks())74EHFrameBlocks.push_back(B);75llvm::sort(EHFrameBlocks, [](const Block *LHS, const Block *RHS) {76return LHS->getAddress() < RHS->getAddress();77});7879// Loop over the blocks in address order.80for (auto *B : EHFrameBlocks)81if (auto Err = processBlock(PC, *B))82return Err;8384return Error::success();85}8687static Expected<size_t> readCFIRecordLength(const Block &B,88BinaryStreamReader &R) {89uint32_t Length;90if (auto Err = R.readInteger(Length))91return std::move(Err);9293// If Length < 0xffffffff then use the regular length field, otherwise94// read the extended length field.95if (Length != 0xffffffff)96return Length;9798uint64_t ExtendedLength;99if (auto Err = R.readInteger(ExtendedLength))100return std::move(Err);101102if (ExtendedLength > std::numeric_limits<size_t>::max())103return make_error<JITLinkError>(104"In CFI record at " +105formatv("{0:x}", B.getAddress() + R.getOffset() - 12) +106", extended length of " + formatv("{0:x}", ExtendedLength) +107" exceeds address-range max (" +108formatv("{0:x}", std::numeric_limits<size_t>::max()));109110return ExtendedLength;111}112113Error EHFrameEdgeFixer::processBlock(ParseContext &PC, Block &B) {114115LLVM_DEBUG(dbgs() << " Processing block at " << B.getAddress() << "\n");116117// eh-frame should not contain zero-fill blocks.118if (B.isZeroFill())119return make_error<JITLinkError>("Unexpected zero-fill block in " +120EHFrameSectionName + " section");121122if (B.getSize() == 0) {123LLVM_DEBUG(dbgs() << " Block is empty. Skipping.\n");124return Error::success();125}126127// Find the offsets of any existing edges from this block.128BlockEdgesInfo BlockEdges;129for (auto &E : B.edges())130if (E.isRelocation()) {131// Check if we already saw more than one relocation at this offset.132if (BlockEdges.Multiple.contains(E.getOffset()))133continue;134135// Otherwise check if we previously had exactly one relocation at this136// offset. If so, we now have a second one and move it from the TargetMap137// into the Multiple set.138auto It = BlockEdges.TargetMap.find(E.getOffset());139if (It != BlockEdges.TargetMap.end()) {140BlockEdges.TargetMap.erase(It);141BlockEdges.Multiple.insert(E.getOffset());142} else {143BlockEdges.TargetMap[E.getOffset()] = EdgeTarget(E);144}145}146147BinaryStreamReader BlockReader(148StringRef(B.getContent().data(), B.getContent().size()),149PC.G.getEndianness());150151// Get the record length.152Expected<size_t> RecordRemaining = readCFIRecordLength(B, BlockReader);153if (!RecordRemaining)154return RecordRemaining.takeError();155156// We expect DWARFRecordSectionSplitter to split each CFI record into its own157// block.158if (BlockReader.bytesRemaining() != *RecordRemaining)159return make_error<JITLinkError>("Incomplete CFI record at " +160formatv("{0:x16}", B.getAddress()));161162// Read the CIE delta for this record.163uint64_t CIEDeltaFieldOffset = BlockReader.getOffset();164uint32_t CIEDelta;165if (auto Err = BlockReader.readInteger(CIEDelta))166return Err;167168if (CIEDelta == 0) {169if (auto Err = processCIE(PC, B, CIEDeltaFieldOffset, BlockEdges))170return Err;171} else {172if (auto Err = processFDE(PC, B, CIEDeltaFieldOffset, CIEDelta, BlockEdges))173return Err;174}175176return Error::success();177}178179Error EHFrameEdgeFixer::processCIE(ParseContext &PC, Block &B,180size_t CIEDeltaFieldOffset,181const BlockEdgesInfo &BlockEdges) {182183LLVM_DEBUG(dbgs() << " Record is CIE\n");184185BinaryStreamReader RecordReader(186StringRef(B.getContent().data(), B.getContent().size()),187PC.G.getEndianness());188189// Skip past the CIE delta field: we've already processed this far.190RecordReader.setOffset(CIEDeltaFieldOffset + 4);191192auto &CIESymbol = PC.G.addAnonymousSymbol(B, 0, B.getSize(), false, false);193CIEInformation CIEInfo(CIESymbol);194195uint8_t Version = 0;196if (auto Err = RecordReader.readInteger(Version))197return Err;198199if (Version != 0x01)200return make_error<JITLinkError>("Bad CIE version " + Twine(Version) +201" (should be 0x01) in eh-frame");202203auto AugInfo = parseAugmentationString(RecordReader);204if (!AugInfo)205return AugInfo.takeError();206207// Skip the EH Data field if present.208if (AugInfo->EHDataFieldPresent)209if (auto Err = RecordReader.skip(PC.G.getPointerSize()))210return Err;211212// Read and validate the code alignment factor.213{214uint64_t CodeAlignmentFactor = 0;215if (auto Err = RecordReader.readULEB128(CodeAlignmentFactor))216return Err;217}218219// Read and validate the data alignment factor.220{221int64_t DataAlignmentFactor = 0;222if (auto Err = RecordReader.readSLEB128(DataAlignmentFactor))223return Err;224}225226// Skip the return address register field.227if (auto Err = RecordReader.skip(1))228return Err;229230if (AugInfo->AugmentationDataPresent) {231232CIEInfo.AugmentationDataPresent = true;233234uint64_t AugmentationDataLength = 0;235if (auto Err = RecordReader.readULEB128(AugmentationDataLength))236return Err;237238uint32_t AugmentationDataStartOffset = RecordReader.getOffset();239240uint8_t *NextField = &AugInfo->Fields[0];241while (uint8_t Field = *NextField++) {242switch (Field) {243case 'L':244CIEInfo.LSDAPresent = true;245if (auto PE = readPointerEncoding(RecordReader, B, "LSDA"))246CIEInfo.LSDAEncoding = *PE;247else248return PE.takeError();249break;250case 'P': {251auto PersonalityPointerEncoding =252readPointerEncoding(RecordReader, B, "personality");253if (!PersonalityPointerEncoding)254return PersonalityPointerEncoding.takeError();255if (auto Err =256getOrCreateEncodedPointerEdge(257PC, BlockEdges, *PersonalityPointerEncoding, RecordReader,258B, RecordReader.getOffset(), "personality")259.takeError())260return Err;261break;262}263case 'R':264if (auto PE = readPointerEncoding(RecordReader, B, "address")) {265CIEInfo.AddressEncoding = *PE;266if (CIEInfo.AddressEncoding == dwarf::DW_EH_PE_omit)267return make_error<JITLinkError>(268"Invalid address encoding DW_EH_PE_omit in CIE at " +269formatv("{0:x}", B.getAddress().getValue()));270} else271return PE.takeError();272break;273default:274llvm_unreachable("Invalid augmentation string field");275}276}277278if (RecordReader.getOffset() - AugmentationDataStartOffset >279AugmentationDataLength)280return make_error<JITLinkError>("Read past the end of the augmentation "281"data while parsing fields");282}283284assert(!PC.CIEInfos.count(CIESymbol.getAddress()) &&285"Multiple CIEs recorded at the same address?");286PC.CIEInfos[CIESymbol.getAddress()] = std::move(CIEInfo);287288return Error::success();289}290291Error EHFrameEdgeFixer::processFDE(ParseContext &PC, Block &B,292size_t CIEDeltaFieldOffset,293uint32_t CIEDelta,294const BlockEdgesInfo &BlockEdges) {295LLVM_DEBUG(dbgs() << " Record is FDE\n");296297orc::ExecutorAddr RecordAddress = B.getAddress();298299BinaryStreamReader RecordReader(300StringRef(B.getContent().data(), B.getContent().size()),301PC.G.getEndianness());302303// Skip past the CIE delta field: we've already read this far.304RecordReader.setOffset(CIEDeltaFieldOffset + 4);305306auto &FDESymbol = PC.G.addAnonymousSymbol(B, 0, B.getSize(), false, false);307308CIEInformation *CIEInfo = nullptr;309310{311// Process the CIE pointer field.312if (BlockEdges.Multiple.contains(CIEDeltaFieldOffset))313return make_error<JITLinkError>(314"CIE pointer field already has multiple edges at " +315formatv("{0:x16}", RecordAddress + CIEDeltaFieldOffset));316317auto CIEEdgeItr = BlockEdges.TargetMap.find(CIEDeltaFieldOffset);318319orc::ExecutorAddr CIEAddress =320RecordAddress + orc::ExecutorAddrDiff(CIEDeltaFieldOffset) -321orc::ExecutorAddrDiff(CIEDelta);322if (CIEEdgeItr == BlockEdges.TargetMap.end()) {323LLVM_DEBUG({324dbgs() << " Adding edge at "325<< (RecordAddress + CIEDeltaFieldOffset)326<< " to CIE at: " << CIEAddress << "\n";327});328if (auto CIEInfoOrErr = PC.findCIEInfo(CIEAddress))329CIEInfo = *CIEInfoOrErr;330else331return CIEInfoOrErr.takeError();332assert(CIEInfo->CIESymbol && "CIEInfo has no CIE symbol set");333B.addEdge(NegDelta32, CIEDeltaFieldOffset, *CIEInfo->CIESymbol, 0);334} else {335LLVM_DEBUG({336dbgs() << " Already has edge at "337<< (RecordAddress + CIEDeltaFieldOffset) << " to CIE at "338<< CIEAddress << "\n";339});340auto &EI = CIEEdgeItr->second;341if (EI.Addend)342return make_error<JITLinkError>(343"CIE edge at " +344formatv("{0:x16}", RecordAddress + CIEDeltaFieldOffset) +345" has non-zero addend");346if (auto CIEInfoOrErr = PC.findCIEInfo(EI.Target->getAddress()))347CIEInfo = *CIEInfoOrErr;348else349return CIEInfoOrErr.takeError();350}351}352353// Process the PC-Begin field.354LLVM_DEBUG({355dbgs() << " Processing PC-begin at "356<< (RecordAddress + RecordReader.getOffset()) << "\n";357});358if (auto PCBegin = getOrCreateEncodedPointerEdge(359PC, BlockEdges, CIEInfo->AddressEncoding, RecordReader, B,360RecordReader.getOffset(), "PC begin")) {361assert(*PCBegin && "PC-begin symbol not set");362if ((*PCBegin)->isDefined()) {363// Add a keep-alive edge from the FDE target to the FDE to ensure that the364// FDE is kept alive if its target is.365LLVM_DEBUG({366dbgs() << " Adding keep-alive edge from target at "367<< (*PCBegin)->getBlock().getAddress() << " to FDE at "368<< RecordAddress << "\n";369});370(*PCBegin)->getBlock().addEdge(Edge::KeepAlive, 0, FDESymbol, 0);371} else {372LLVM_DEBUG({373dbgs() << " WARNING: Not adding keep-alive edge to FDE at "374<< RecordAddress << ", which points to "375<< ((*PCBegin)->isExternal() ? "external" : "absolute")376<< " symbol \"" << (*PCBegin)->getName()377<< "\" -- FDE must be kept alive manually or it will be "378<< "dead stripped.\n";379});380}381} else382return PCBegin.takeError();383384// Skip over the PC range size field.385if (auto Err = skipEncodedPointer(CIEInfo->AddressEncoding, RecordReader))386return Err;387388if (CIEInfo->AugmentationDataPresent) {389uint64_t AugmentationDataSize;390if (auto Err = RecordReader.readULEB128(AugmentationDataSize))391return Err;392393if (CIEInfo->LSDAPresent)394if (auto Err = getOrCreateEncodedPointerEdge(395PC, BlockEdges, CIEInfo->LSDAEncoding, RecordReader, B,396RecordReader.getOffset(), "LSDA")397.takeError())398return Err;399} else {400LLVM_DEBUG(dbgs() << " Record does not have LSDA field.\n");401}402403return Error::success();404}405406Expected<EHFrameEdgeFixer::AugmentationInfo>407EHFrameEdgeFixer::parseAugmentationString(BinaryStreamReader &RecordReader) {408AugmentationInfo AugInfo;409uint8_t NextChar;410uint8_t *NextField = &AugInfo.Fields[0];411412if (auto Err = RecordReader.readInteger(NextChar))413return std::move(Err);414415while (NextChar != 0) {416switch (NextChar) {417case 'z':418AugInfo.AugmentationDataPresent = true;419break;420case 'e':421if (auto Err = RecordReader.readInteger(NextChar))422return std::move(Err);423if (NextChar != 'h')424return make_error<JITLinkError>("Unrecognized substring e" +425Twine(NextChar) +426" in augmentation string");427AugInfo.EHDataFieldPresent = true;428break;429case 'L':430case 'P':431case 'R':432*NextField++ = NextChar;433break;434default:435return make_error<JITLinkError>("Unrecognized character " +436Twine(NextChar) +437" in augmentation string");438}439440if (auto Err = RecordReader.readInteger(NextChar))441return std::move(Err);442}443444return std::move(AugInfo);445}446447Expected<uint8_t> EHFrameEdgeFixer::readPointerEncoding(BinaryStreamReader &R,448Block &InBlock,449const char *FieldName) {450using namespace dwarf;451452uint8_t PointerEncoding;453if (auto Err = R.readInteger(PointerEncoding))454return std::move(Err);455456bool Supported = true;457switch (PointerEncoding & 0xf) {458case DW_EH_PE_uleb128:459case DW_EH_PE_udata2:460case DW_EH_PE_sleb128:461case DW_EH_PE_sdata2:462Supported = false;463break;464}465if (Supported) {466switch (PointerEncoding & 0x70) {467case DW_EH_PE_textrel:468case DW_EH_PE_datarel:469case DW_EH_PE_funcrel:470case DW_EH_PE_aligned:471Supported = false;472break;473}474}475476if (Supported)477return PointerEncoding;478479return make_error<JITLinkError>("Unsupported pointer encoding " +480formatv("{0:x2}", PointerEncoding) + " for " +481FieldName + "in CFI record at " +482formatv("{0:x16}", InBlock.getAddress()));483}484485Error EHFrameEdgeFixer::skipEncodedPointer(uint8_t PointerEncoding,486BinaryStreamReader &RecordReader) {487using namespace dwarf;488489// Switch absptr to corresponding udata encoding.490if ((PointerEncoding & 0xf) == DW_EH_PE_absptr)491PointerEncoding |= (PointerSize == 8) ? DW_EH_PE_udata8 : DW_EH_PE_udata4;492493switch (PointerEncoding & 0xf) {494case DW_EH_PE_udata4:495case DW_EH_PE_sdata4:496if (auto Err = RecordReader.skip(4))497return Err;498break;499case DW_EH_PE_udata8:500case DW_EH_PE_sdata8:501if (auto Err = RecordReader.skip(8))502return Err;503break;504default:505llvm_unreachable("Unrecognized encoding");506}507return Error::success();508}509510Expected<Symbol *> EHFrameEdgeFixer::getOrCreateEncodedPointerEdge(511ParseContext &PC, const BlockEdgesInfo &BlockEdges, uint8_t PointerEncoding,512BinaryStreamReader &RecordReader, Block &BlockToFix,513size_t PointerFieldOffset, const char *FieldName) {514using namespace dwarf;515516if (PointerEncoding == DW_EH_PE_omit)517return nullptr;518519// If there's already an edge here then just skip the encoded pointer and520// return the edge's target.521{522auto EdgeI = BlockEdges.TargetMap.find(PointerFieldOffset);523if (EdgeI != BlockEdges.TargetMap.end()) {524LLVM_DEBUG({525dbgs() << " Existing edge at "526<< (BlockToFix.getAddress() + PointerFieldOffset) << " to "527<< FieldName << " at " << EdgeI->second.Target->getAddress();528if (EdgeI->second.Target->hasName())529dbgs() << " (" << EdgeI->second.Target->getName() << ")";530dbgs() << "\n";531});532if (auto Err = skipEncodedPointer(PointerEncoding, RecordReader))533return std::move(Err);534return EdgeI->second.Target;535}536537if (BlockEdges.Multiple.contains(PointerFieldOffset))538return make_error<JITLinkError>("Multiple relocations at offset " +539formatv("{0:x16}", PointerFieldOffset));540}541542// Switch absptr to corresponding udata encoding.543if ((PointerEncoding & 0xf) == DW_EH_PE_absptr)544PointerEncoding |= (PointerSize == 8) ? DW_EH_PE_udata8 : DW_EH_PE_udata4;545546// We need to create an edge. Start by reading the field value.547uint64_t FieldValue;548bool Is64Bit = false;549switch (PointerEncoding & 0xf) {550case DW_EH_PE_udata4: {551uint32_t Val;552if (auto Err = RecordReader.readInteger(Val))553return std::move(Err);554FieldValue = Val;555break;556}557case DW_EH_PE_sdata4: {558uint32_t Val;559if (auto Err = RecordReader.readInteger(Val))560return std::move(Err);561FieldValue = Val;562break;563}564case DW_EH_PE_udata8:565case DW_EH_PE_sdata8:566Is64Bit = true;567if (auto Err = RecordReader.readInteger(FieldValue))568return std::move(Err);569break;570default:571llvm_unreachable("Unsupported encoding");572}573574// Find the edge target and edge kind to use.575orc::ExecutorAddr Target;576Edge::Kind PtrEdgeKind = Edge::Invalid;577if ((PointerEncoding & 0x70) == DW_EH_PE_pcrel) {578Target = BlockToFix.getAddress() + PointerFieldOffset;579PtrEdgeKind = Is64Bit ? Delta64 : Delta32;580} else581PtrEdgeKind = Is64Bit ? Pointer64 : Pointer32;582Target += FieldValue;583584// Find or create a symbol to point the edge at.585auto TargetSym = getOrCreateSymbol(PC, Target);586if (!TargetSym)587return TargetSym.takeError();588BlockToFix.addEdge(PtrEdgeKind, PointerFieldOffset, *TargetSym, 0);589590LLVM_DEBUG({591dbgs() << " Adding edge at "592<< (BlockToFix.getAddress() + PointerFieldOffset) << " to "593<< FieldName << " at " << TargetSym->getAddress();594if (TargetSym->hasName())595dbgs() << " (" << TargetSym->getName() << ")";596dbgs() << "\n";597});598599return &*TargetSym;600}601602Expected<Symbol &> EHFrameEdgeFixer::getOrCreateSymbol(ParseContext &PC,603orc::ExecutorAddr Addr) {604// See whether we have a canonical symbol for the given address already.605auto CanonicalSymI = PC.AddrToSym.find(Addr);606if (CanonicalSymI != PC.AddrToSym.end())607return *CanonicalSymI->second;608609// Otherwise search for a block covering the address and create a new symbol.610auto *B = PC.AddrToBlock.getBlockCovering(Addr);611if (!B)612return make_error<JITLinkError>("No symbol or block covering address " +613formatv("{0:x16}", Addr));614615auto &S =616PC.G.addAnonymousSymbol(*B, Addr - B->getAddress(), 0, false, false);617PC.AddrToSym[S.getAddress()] = &S;618return S;619}620621char EHFrameNullTerminator::NullTerminatorBlockContent[4] = {0, 0, 0, 0};622623EHFrameNullTerminator::EHFrameNullTerminator(StringRef EHFrameSectionName)624: EHFrameSectionName(EHFrameSectionName) {}625626Error EHFrameNullTerminator::operator()(LinkGraph &G) {627auto *EHFrame = G.findSectionByName(EHFrameSectionName);628629if (!EHFrame)630return Error::success();631632LLVM_DEBUG({633dbgs() << "EHFrameNullTerminator adding null terminator to "634<< EHFrameSectionName << "\n";635});636637auto &NullTerminatorBlock =638G.createContentBlock(*EHFrame, NullTerminatorBlockContent,639orc::ExecutorAddr(~uint64_t(4)), 1, 0);640G.addAnonymousSymbol(NullTerminatorBlock, 0, 4, false, true);641return Error::success();642}643644EHFrameRegistrar::~EHFrameRegistrar() = default;645646Error InProcessEHFrameRegistrar::registerEHFrames(647orc::ExecutorAddrRange EHFrameSection) {648return orc::registerEHFrameSection(EHFrameSection.Start.toPtr<void *>(),649EHFrameSection.size());650}651652Error InProcessEHFrameRegistrar::deregisterEHFrames(653orc::ExecutorAddrRange EHFrameSection) {654return orc::deregisterEHFrameSection(EHFrameSection.Start.toPtr<void *>(),655EHFrameSection.size());656}657658EHFrameCFIBlockInspector EHFrameCFIBlockInspector::FromEdgeScan(Block &B) {659if (B.edges_empty())660return EHFrameCFIBlockInspector(nullptr);661if (B.edges_size() == 1)662return EHFrameCFIBlockInspector(&*B.edges().begin());663SmallVector<Edge *, 3> Es;664for (auto &E : B.edges())665Es.push_back(&E);666assert(Es.size() >= 2 && Es.size() <= 3 && "Unexpected number of edges");667llvm::sort(Es, [](const Edge *LHS, const Edge *RHS) {668return LHS->getOffset() < RHS->getOffset();669});670return EHFrameCFIBlockInspector(*Es[0], *Es[1],671Es.size() == 3 ? Es[2] : nullptr);672return EHFrameCFIBlockInspector(nullptr);673}674675EHFrameCFIBlockInspector::EHFrameCFIBlockInspector(Edge *PersonalityEdge)676: PersonalityEdge(PersonalityEdge) {}677678EHFrameCFIBlockInspector::EHFrameCFIBlockInspector(Edge &CIEEdge,679Edge &PCBeginEdge,680Edge *LSDAEdge)681: CIEEdge(&CIEEdge), PCBeginEdge(&PCBeginEdge), LSDAEdge(LSDAEdge) {}682683LinkGraphPassFunction684createEHFrameRecorderPass(const Triple &TT,685StoreFrameRangeFunction StoreRangeAddress) {686const char *EHFrameSectionName = nullptr;687if (TT.getObjectFormat() == Triple::MachO)688EHFrameSectionName = "__TEXT,__eh_frame";689else690EHFrameSectionName = ".eh_frame";691692auto RecordEHFrame =693[EHFrameSectionName,694StoreFrameRange = std::move(StoreRangeAddress)](LinkGraph &G) -> Error {695// Search for a non-empty eh-frame and record the address of the first696// symbol in it.697orc::ExecutorAddr Addr;698size_t Size = 0;699if (auto *S = G.findSectionByName(EHFrameSectionName)) {700auto R = SectionRange(*S);701Addr = R.getStart();702Size = R.getSize();703}704if (!Addr && Size != 0)705return make_error<JITLinkError>(706StringRef(EHFrameSectionName) +707" section can not have zero address with non-zero size");708StoreFrameRange(Addr, Size);709return Error::success();710};711712return RecordEHFrame;713}714715} // end namespace jitlink716} // end namespace llvm717718719