brintos

brintos / llvm-project-archived public Read only

0
0
Text · 22.9 KiB · 44c9ec0 Raw
686 lines · cpp
1//===-------- JITLink_EHFrameSupport.cpp - JITLink eh-frame utils ---------===//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#include "EHFrameSupportImpl.h"10 11#include "llvm/BinaryFormat/Dwarf.h"12#include "llvm/Config/config.h"13#include "llvm/ExecutionEngine/Orc/TargetProcess/RegisterEHFrames.h"14#include "llvm/Support/DynamicLibrary.h"15 16#define DEBUG_TYPE "jitlink"17 18namespace llvm {19namespace jitlink {20 21EHFrameEdgeFixer::EHFrameEdgeFixer(StringRef EHFrameSectionName,22                                   unsigned PointerSize, Edge::Kind Pointer32,23                                   Edge::Kind Pointer64, Edge::Kind Delta32,24                                   Edge::Kind Delta64, Edge::Kind NegDelta32)25    : EHFrameSectionName(EHFrameSectionName), PointerSize(PointerSize),26      Pointer32(Pointer32), Pointer64(Pointer64), Delta32(Delta32),27      Delta64(Delta64), NegDelta32(NegDelta32) {}28 29Error EHFrameEdgeFixer::operator()(LinkGraph &G) {30  auto *EHFrame = G.findSectionByName(EHFrameSectionName);31 32  if (!EHFrame) {33    LLVM_DEBUG({34      dbgs() << "EHFrameEdgeFixer: No " << EHFrameSectionName35             << " section in \"" << G.getName() << "\". Nothing to do.\n";36    });37    return Error::success();38  }39 40  // Check that we support the graph's pointer size.41  if (G.getPointerSize() != 4 && G.getPointerSize() != 8)42    return make_error<JITLinkError>(43        "EHFrameEdgeFixer only supports 32 and 64 bit targets");44 45  LLVM_DEBUG({46    dbgs() << "EHFrameEdgeFixer: Processing " << EHFrameSectionName << " in \""47           << G.getName() << "\"...\n";48  });49 50  ParseContext PC(G);51 52  // Build a map of all blocks and symbols in the text sections. We will use53  // these for finding / building edge targets when processing FDEs.54  for (auto &Sec : G.sections()) {55    // Just record the most-canonical symbol (for eh-frame purposes) at each56    // address.57    for (auto *Sym : Sec.symbols()) {58      auto &CurSym = PC.AddrToSym[Sym->getAddress()];59      if (!CurSym || (std::make_tuple(Sym->getLinkage(), Sym->getScope(),60                                      !Sym->hasName(), Sym->getName()) <61                      std::make_tuple(CurSym->getLinkage(), CurSym->getScope(),62                                      !CurSym->hasName(), CurSym->getName())))63        CurSym = Sym;64    }65    if (auto Err = PC.AddrToBlock.addBlocks(Sec.blocks(),66                                            BlockAddressMap::includeNonNull))67      return Err;68  }69 70  // Sort eh-frame blocks into address order to ensure we visit CIEs before71  // their child FDEs.72  std::vector<Block *> EHFrameBlocks;73  llvm::append_range(EHFrameBlocks, EHFrame->blocks());74  llvm::sort(EHFrameBlocks, [](const Block *LHS, const Block *RHS) {75    return LHS->getAddress() < RHS->getAddress();76  });77 78  // Loop over the blocks in address order.79  for (auto *B : EHFrameBlocks)80    if (auto Err = processBlock(PC, *B))81      return Err;82 83  return Error::success();84}85 86static Expected<size_t> readCFIRecordLength(const Block &B,87                                            BinaryStreamReader &R) {88  uint32_t Length;89  if (auto Err = R.readInteger(Length))90    return std::move(Err);91 92  // If Length < 0xffffffff then use the regular length field, otherwise93  // read the extended length field.94  if (Length != 0xffffffff)95    return Length;96 97  uint64_t ExtendedLength;98  if (auto Err = R.readInteger(ExtendedLength))99    return std::move(Err);100 101  if (ExtendedLength > std::numeric_limits<size_t>::max())102    return make_error<JITLinkError>(103        "In CFI record at " +104        formatv("{0:x}", B.getAddress() + R.getOffset() - 12) +105        ", extended length of " + formatv("{0:x}", ExtendedLength) +106        " exceeds address-range max (" +107        formatv("{0:x}", std::numeric_limits<size_t>::max()));108 109  return ExtendedLength;110}111 112Error EHFrameEdgeFixer::processBlock(ParseContext &PC, Block &B) {113 114  LLVM_DEBUG(dbgs() << "  Processing block at " << B.getAddress() << "\n");115 116  // eh-frame should not contain zero-fill blocks.117  if (B.isZeroFill())118    return make_error<JITLinkError>("Unexpected zero-fill block in " +119                                    EHFrameSectionName + " section");120 121  if (B.getSize() == 0) {122    LLVM_DEBUG(dbgs() << "    Block is empty. Skipping.\n");123    return Error::success();124  }125 126  // Find the offsets of any existing edges from this block.127  BlockEdgesInfo BlockEdges;128  for (auto &E : B.edges())129    if (E.isRelocation()) {130      // Check if we already saw more than one relocation at this offset.131      if (BlockEdges.Multiple.contains(E.getOffset()))132        continue;133 134      // Otherwise check if we previously had exactly one relocation at this135      // offset. If so, we now have a second one and move it from the TargetMap136      // into the Multiple set.137      auto [It, Inserted] = BlockEdges.TargetMap.try_emplace(E.getOffset(), E);138      if (!Inserted) {139        BlockEdges.TargetMap.erase(It);140        BlockEdges.Multiple.insert(E.getOffset());141      }142    }143 144  BinaryStreamReader BlockReader(145      StringRef(B.getContent().data(), B.getContent().size()),146      PC.G.getEndianness());147 148  // Get the record length.149  Expected<size_t> RecordRemaining = readCFIRecordLength(B, BlockReader);150  if (!RecordRemaining)151    return RecordRemaining.takeError();152 153  // We expect DWARFRecordSectionSplitter to split each CFI record into its own154  // block.155  if (BlockReader.bytesRemaining() != *RecordRemaining)156    return make_error<JITLinkError>("Incomplete CFI record at " +157                                    formatv("{0:x16}", B.getAddress()));158 159  // Read the CIE delta for this record.160  uint64_t CIEDeltaFieldOffset = BlockReader.getOffset();161  uint32_t CIEDelta;162  if (auto Err = BlockReader.readInteger(CIEDelta))163    return Err;164 165  if (CIEDelta == 0) {166    if (auto Err = processCIE(PC, B, CIEDeltaFieldOffset, BlockEdges))167      return Err;168  } else {169    if (auto Err = processFDE(PC, B, CIEDeltaFieldOffset, CIEDelta, BlockEdges))170      return Err;171  }172 173  return Error::success();174}175 176Error EHFrameEdgeFixer::processCIE(ParseContext &PC, Block &B,177                                   size_t CIEDeltaFieldOffset,178                                   const BlockEdgesInfo &BlockEdges) {179 180  LLVM_DEBUG(dbgs() << "    Record is CIE\n");181 182  BinaryStreamReader RecordReader(183      StringRef(B.getContent().data(), B.getContent().size()),184      PC.G.getEndianness());185 186  // Skip past the CIE delta field: we've already processed this far.187  RecordReader.setOffset(CIEDeltaFieldOffset + 4);188 189  auto &CIESymbol = PC.G.addAnonymousSymbol(B, 0, B.getSize(), false, false);190  CIEInformation CIEInfo(CIESymbol);191 192  uint8_t Version = 0;193  if (auto Err = RecordReader.readInteger(Version))194    return Err;195 196  if (Version != 0x01)197    return make_error<JITLinkError>("Bad CIE version " + Twine(Version) +198                                    " (should be 0x01) in eh-frame");199 200  auto AugInfo = parseAugmentationString(RecordReader);201  if (!AugInfo)202    return AugInfo.takeError();203 204  // Skip the EH Data field if present.205  if (AugInfo->EHDataFieldPresent)206    if (auto Err = RecordReader.skip(PC.G.getPointerSize()))207      return Err;208 209  // Read and validate the code alignment factor.210  {211    uint64_t CodeAlignmentFactor = 0;212    if (auto Err = RecordReader.readULEB128(CodeAlignmentFactor))213      return Err;214  }215 216  // Read and validate the data alignment factor.217  {218    int64_t DataAlignmentFactor = 0;219    if (auto Err = RecordReader.readSLEB128(DataAlignmentFactor))220      return Err;221  }222 223  // Skip the return address register field.224  if (auto Err = RecordReader.skip(1))225    return Err;226 227  if (AugInfo->AugmentationDataPresent) {228 229    CIEInfo.AugmentationDataPresent = true;230 231    uint64_t AugmentationDataLength = 0;232    if (auto Err = RecordReader.readULEB128(AugmentationDataLength))233      return Err;234 235    uint32_t AugmentationDataStartOffset = RecordReader.getOffset();236 237    uint8_t *NextField = &AugInfo->Fields[0];238    while (uint8_t Field = *NextField++) {239      switch (Field) {240      case 'L':241        CIEInfo.LSDAPresent = true;242        if (auto PE = readPointerEncoding(RecordReader, B, "LSDA"))243          CIEInfo.LSDAEncoding = *PE;244        else245          return PE.takeError();246        break;247      case 'P': {248        auto PersonalityPointerEncoding =249            readPointerEncoding(RecordReader, B, "personality");250        if (!PersonalityPointerEncoding)251          return PersonalityPointerEncoding.takeError();252        if (auto Err =253                getOrCreateEncodedPointerEdge(254                    PC, BlockEdges, *PersonalityPointerEncoding, RecordReader,255                    B, RecordReader.getOffset(), "personality")256                    .takeError())257          return Err;258        break;259      }260      case 'R':261        if (auto PE = readPointerEncoding(RecordReader, B, "address")) {262          CIEInfo.AddressEncoding = *PE;263          if (CIEInfo.AddressEncoding == dwarf::DW_EH_PE_omit)264            return make_error<JITLinkError>(265                "Invalid address encoding DW_EH_PE_omit in CIE at " +266                formatv("{0:x}", B.getAddress().getValue()));267        } else268          return PE.takeError();269        break;270      default:271        llvm_unreachable("Invalid augmentation string field");272      }273    }274 275    if (RecordReader.getOffset() - AugmentationDataStartOffset >276        AugmentationDataLength)277      return make_error<JITLinkError>("Read past the end of the augmentation "278                                      "data while parsing fields");279  }280 281  assert(!PC.CIEInfos.count(CIESymbol.getAddress()) &&282         "Multiple CIEs recorded at the same address?");283  PC.CIEInfos[CIESymbol.getAddress()] = std::move(CIEInfo);284 285  return Error::success();286}287 288Error EHFrameEdgeFixer::processFDE(ParseContext &PC, Block &B,289                                   size_t CIEDeltaFieldOffset,290                                   uint32_t CIEDelta,291                                   const BlockEdgesInfo &BlockEdges) {292  LLVM_DEBUG(dbgs() << "    Record is FDE\n");293 294  orc::ExecutorAddr RecordAddress = B.getAddress();295 296  BinaryStreamReader RecordReader(297      StringRef(B.getContent().data(), B.getContent().size()),298      PC.G.getEndianness());299 300  // Skip past the CIE delta field: we've already read this far.301  RecordReader.setOffset(CIEDeltaFieldOffset + 4);302 303  auto &FDESymbol = PC.G.addAnonymousSymbol(B, 0, B.getSize(), false, false);304 305  CIEInformation *CIEInfo = nullptr;306 307  {308    // Process the CIE pointer field.309    if (BlockEdges.Multiple.contains(CIEDeltaFieldOffset))310      return make_error<JITLinkError>(311          "CIE pointer field already has multiple edges at " +312          formatv("{0:x16}", RecordAddress + CIEDeltaFieldOffset));313 314    auto CIEEdgeItr = BlockEdges.TargetMap.find(CIEDeltaFieldOffset);315 316    orc::ExecutorAddr CIEAddress =317        RecordAddress + orc::ExecutorAddrDiff(CIEDeltaFieldOffset) -318        orc::ExecutorAddrDiff(CIEDelta);319    if (CIEEdgeItr == BlockEdges.TargetMap.end()) {320      LLVM_DEBUG({321        dbgs() << "        Adding edge at "322               << (RecordAddress + CIEDeltaFieldOffset)323               << " to CIE at: " << CIEAddress << "\n";324      });325      if (auto CIEInfoOrErr = PC.findCIEInfo(CIEAddress))326        CIEInfo = *CIEInfoOrErr;327      else328        return CIEInfoOrErr.takeError();329      assert(CIEInfo->CIESymbol && "CIEInfo has no CIE symbol set");330      B.addEdge(NegDelta32, CIEDeltaFieldOffset, *CIEInfo->CIESymbol, 0);331    } else {332      LLVM_DEBUG({333        dbgs() << "        Already has edge at "334               << (RecordAddress + CIEDeltaFieldOffset) << " to CIE at "335               << CIEAddress << "\n";336      });337      auto &EI = CIEEdgeItr->second;338      if (EI.Addend)339        return make_error<JITLinkError>(340            "CIE edge at " +341            formatv("{0:x16}", RecordAddress + CIEDeltaFieldOffset) +342            " has non-zero addend");343      if (auto CIEInfoOrErr = PC.findCIEInfo(EI.Target->getAddress()))344        CIEInfo = *CIEInfoOrErr;345      else346        return CIEInfoOrErr.takeError();347    }348  }349 350  // Process the PC-Begin field.351  LLVM_DEBUG({352    dbgs() << "      Processing PC-begin at "353           << (RecordAddress + RecordReader.getOffset()) << "\n";354  });355  if (auto PCBegin = getOrCreateEncodedPointerEdge(356          PC, BlockEdges, CIEInfo->AddressEncoding, RecordReader, B,357          RecordReader.getOffset(), "PC begin")) {358    assert(*PCBegin && "PC-begin symbol not set");359    if ((*PCBegin)->isDefined()) {360      // Add a keep-alive edge from the FDE target to the FDE to ensure that the361      // FDE is kept alive if its target is.362      LLVM_DEBUG({363        dbgs() << "        Adding keep-alive edge from target at "364               << (*PCBegin)->getBlock().getAddress() << " to FDE at "365               << RecordAddress << "\n";366      });367      (*PCBegin)->getBlock().addEdge(Edge::KeepAlive, 0, FDESymbol, 0);368    } else {369      LLVM_DEBUG({370        dbgs() << "        WARNING: Not adding keep-alive edge to FDE at "371               << RecordAddress << ", which points to "372               << ((*PCBegin)->isExternal() ? "external" : "absolute")373               << " symbol \"" << (*PCBegin)->getName()374               << "\" -- FDE must be kept alive manually or it will be "375               << "dead stripped.\n";376      });377    }378  } else379    return PCBegin.takeError();380 381  // Skip over the PC range size field.382  if (auto Err = skipEncodedPointer(CIEInfo->AddressEncoding, RecordReader))383    return Err;384 385  if (CIEInfo->AugmentationDataPresent) {386    uint64_t AugmentationDataSize;387    if (auto Err = RecordReader.readULEB128(AugmentationDataSize))388      return Err;389 390    if (CIEInfo->LSDAPresent)391      if (auto Err = getOrCreateEncodedPointerEdge(392                         PC, BlockEdges, CIEInfo->LSDAEncoding, RecordReader, B,393                         RecordReader.getOffset(), "LSDA")394                         .takeError())395        return Err;396  } else {397    LLVM_DEBUG(dbgs() << "        Record does not have LSDA field.\n");398  }399 400  return Error::success();401}402 403Expected<EHFrameEdgeFixer::AugmentationInfo>404EHFrameEdgeFixer::parseAugmentationString(BinaryStreamReader &RecordReader) {405  AugmentationInfo AugInfo;406  uint8_t NextChar;407  uint8_t *NextField = &AugInfo.Fields[0];408 409  if (auto Err = RecordReader.readInteger(NextChar))410    return std::move(Err);411 412  while (NextChar != 0) {413    switch (NextChar) {414    case 'z':415      AugInfo.AugmentationDataPresent = true;416      break;417    case 'e':418      if (auto Err = RecordReader.readInteger(NextChar))419        return std::move(Err);420      if (NextChar != 'h')421        return make_error<JITLinkError>("Unrecognized substring e" +422                                        Twine(NextChar) +423                                        " in augmentation string");424      AugInfo.EHDataFieldPresent = true;425      break;426    case 'L':427    case 'P':428    case 'R':429      *NextField++ = NextChar;430      break;431    default:432      return make_error<JITLinkError>("Unrecognized character " +433                                      Twine(NextChar) +434                                      " in augmentation string");435    }436 437    if (auto Err = RecordReader.readInteger(NextChar))438      return std::move(Err);439  }440 441  return std::move(AugInfo);442}443 444Expected<uint8_t> EHFrameEdgeFixer::readPointerEncoding(BinaryStreamReader &R,445                                                        Block &InBlock,446                                                        const char *FieldName) {447  using namespace dwarf;448 449  uint8_t PointerEncoding;450  if (auto Err = R.readInteger(PointerEncoding))451    return std::move(Err);452 453  bool Supported = true;454  switch (PointerEncoding & 0xf) {455  case DW_EH_PE_uleb128:456  case DW_EH_PE_udata2:457  case DW_EH_PE_sleb128:458  case DW_EH_PE_sdata2:459    Supported = false;460    break;461  }462  if (Supported) {463    switch (PointerEncoding & 0x70) {464    case DW_EH_PE_textrel:465    case DW_EH_PE_datarel:466    case DW_EH_PE_funcrel:467    case DW_EH_PE_aligned:468      Supported = false;469      break;470    }471  }472 473  if (Supported)474    return PointerEncoding;475 476  return make_error<JITLinkError>("Unsupported pointer encoding " +477                                  formatv("{0:x2}", PointerEncoding) + " for " +478                                  FieldName + "in CFI record at " +479                                  formatv("{0:x16}", InBlock.getAddress()));480}481 482Error EHFrameEdgeFixer::skipEncodedPointer(uint8_t PointerEncoding,483                                           BinaryStreamReader &RecordReader) {484  using namespace dwarf;485 486  // Switch absptr to corresponding udata encoding.487  if ((PointerEncoding & 0xf) == DW_EH_PE_absptr)488    PointerEncoding |= (PointerSize == 8) ? DW_EH_PE_udata8 : DW_EH_PE_udata4;489 490  switch (PointerEncoding & 0xf) {491  case DW_EH_PE_udata4:492  case DW_EH_PE_sdata4:493    if (auto Err = RecordReader.skip(4))494      return Err;495    break;496  case DW_EH_PE_udata8:497  case DW_EH_PE_sdata8:498    if (auto Err = RecordReader.skip(8))499      return Err;500    break;501  default:502    llvm_unreachable("Unrecognized encoding");503  }504  return Error::success();505}506 507Expected<Symbol *> EHFrameEdgeFixer::getOrCreateEncodedPointerEdge(508    ParseContext &PC, const BlockEdgesInfo &BlockEdges, uint8_t PointerEncoding,509    BinaryStreamReader &RecordReader, Block &BlockToFix,510    size_t PointerFieldOffset, const char *FieldName) {511  using namespace dwarf;512 513  if (PointerEncoding == DW_EH_PE_omit)514    return nullptr;515 516  // If there's already an edge here then just skip the encoded pointer and517  // return the edge's target.518  {519    auto EdgeI = BlockEdges.TargetMap.find(PointerFieldOffset);520    if (EdgeI != BlockEdges.TargetMap.end()) {521      LLVM_DEBUG({522        dbgs() << "      Existing edge at "523               << (BlockToFix.getAddress() + PointerFieldOffset) << " to "524               << FieldName << " at " << EdgeI->second.Target->getAddress();525        if (EdgeI->second.Target->hasName())526          dbgs() << " (" << EdgeI->second.Target->getName() << ")";527        dbgs() << "\n";528      });529      if (auto Err = skipEncodedPointer(PointerEncoding, RecordReader))530        return std::move(Err);531      return EdgeI->second.Target;532    }533 534    if (BlockEdges.Multiple.contains(PointerFieldOffset))535      return make_error<JITLinkError>("Multiple relocations at offset " +536                                      formatv("{0:x16}", PointerFieldOffset));537  }538 539  // Switch absptr to corresponding udata encoding.540  if ((PointerEncoding & 0xf) == DW_EH_PE_absptr)541    PointerEncoding |= (PointerSize == 8) ? DW_EH_PE_udata8 : DW_EH_PE_udata4;542 543  // We need to create an edge. Start by reading the field value.544  uint64_t FieldValue;545  bool Is64Bit = false;546  switch (PointerEncoding & 0xf) {547  case DW_EH_PE_udata4: {548    uint32_t Val;549    if (auto Err = RecordReader.readInteger(Val))550      return std::move(Err);551    FieldValue = Val;552    break;553  }554  case DW_EH_PE_sdata4: {555    uint32_t Val;556    if (auto Err = RecordReader.readInteger(Val))557      return std::move(Err);558    FieldValue = Val;559    break;560  }561  case DW_EH_PE_udata8:562  case DW_EH_PE_sdata8:563    Is64Bit = true;564    if (auto Err = RecordReader.readInteger(FieldValue))565      return std::move(Err);566    break;567  default:568    llvm_unreachable("Unsupported encoding");569  }570 571  // Find the edge target and edge kind to use.572  orc::ExecutorAddr Target;573  Edge::Kind PtrEdgeKind = Edge::Invalid;574  if ((PointerEncoding & 0x70) == DW_EH_PE_pcrel) {575    Target = BlockToFix.getAddress() + PointerFieldOffset;576    PtrEdgeKind = Is64Bit ? Delta64 : Delta32;577  } else578    PtrEdgeKind = Is64Bit ? Pointer64 : Pointer32;579  Target += FieldValue;580 581  // Find or create a symbol to point the edge at.582  auto TargetSym = getOrCreateSymbol(PC, Target);583  if (!TargetSym)584    return TargetSym.takeError();585  BlockToFix.addEdge(PtrEdgeKind, PointerFieldOffset, *TargetSym, 0);586 587  LLVM_DEBUG({588    dbgs() << "      Adding edge at "589           << (BlockToFix.getAddress() + PointerFieldOffset) << " to "590           << FieldName << " at " << TargetSym->getAddress();591    if (TargetSym->hasName())592      dbgs() << " (" << TargetSym->getName() << ")";593    dbgs() << "\n";594  });595 596  return &*TargetSym;597}598 599Expected<Symbol &> EHFrameEdgeFixer::getOrCreateSymbol(ParseContext &PC,600                                                       orc::ExecutorAddr Addr) {601  // See whether we have a canonical symbol for the given address already.602  auto CanonicalSymI = PC.AddrToSym.find(Addr);603  if (CanonicalSymI != PC.AddrToSym.end())604    return *CanonicalSymI->second;605 606  // Otherwise search for a block covering the address and create a new symbol.607  auto *B = PC.AddrToBlock.getBlockCovering(Addr);608  if (!B)609    return make_error<JITLinkError>("No symbol or block covering address " +610                                    formatv("{0:x16}", Addr));611 612  auto &S =613      PC.G.addAnonymousSymbol(*B, Addr - B->getAddress(), 0, false, false);614  PC.AddrToSym[S.getAddress()] = &S;615  return S;616}617 618char EHFrameNullTerminator::NullTerminatorBlockContent[4] = {0, 0, 0, 0};619 620EHFrameNullTerminator::EHFrameNullTerminator(StringRef EHFrameSectionName)621    : EHFrameSectionName(EHFrameSectionName) {}622 623Error EHFrameNullTerminator::operator()(LinkGraph &G) {624  auto *EHFrame = G.findSectionByName(EHFrameSectionName);625 626  if (!EHFrame)627    return Error::success();628 629  LLVM_DEBUG({630    dbgs() << "EHFrameNullTerminator adding null terminator to "631           << EHFrameSectionName << "\n";632  });633 634  auto &NullTerminatorBlock =635      G.createContentBlock(*EHFrame, NullTerminatorBlockContent,636                           orc::ExecutorAddr(~uint64_t(4)), 1, 0);637  G.addAnonymousSymbol(NullTerminatorBlock, 0, 4, false, true);638  return Error::success();639}640 641EHFrameCFIBlockInspector EHFrameCFIBlockInspector::FromEdgeScan(Block &B) {642  if (B.edges_empty())643    return EHFrameCFIBlockInspector(nullptr);644  if (B.edges_size() == 1)645    return EHFrameCFIBlockInspector(&*B.edges().begin());646  SmallVector<Edge *, 3> Es(llvm::make_pointer_range(B.edges()));647  assert(Es.size() >= 2 && Es.size() <= 3 && "Unexpected number of edges");648  llvm::sort(Es, [](const Edge *LHS, const Edge *RHS) {649    return LHS->getOffset() < RHS->getOffset();650  });651  return EHFrameCFIBlockInspector(*Es[0], *Es[1],652                                  Es.size() == 3 ? Es[2] : nullptr);653  return EHFrameCFIBlockInspector(nullptr);654}655 656EHFrameCFIBlockInspector::EHFrameCFIBlockInspector(Edge *PersonalityEdge)657    : PersonalityEdge(PersonalityEdge) {}658 659EHFrameCFIBlockInspector::EHFrameCFIBlockInspector(Edge &CIEEdge,660                                                   Edge &PCBeginEdge,661                                                   Edge *LSDAEdge)662    : CIEEdge(&CIEEdge), PCBeginEdge(&PCBeginEdge), LSDAEdge(LSDAEdge) {}663 664Section *getEHFrameSection(LinkGraph &G) {665  const char *EHFrameSectionName = nullptr;666  switch (G.getTargetTriple().getObjectFormat()) {667  case Triple::MachO:668    EHFrameSectionName = "__TEXT,__eh_frame";669    break;670  case Triple::ELF:671    EHFrameSectionName = ".eh_frame";672    break;673  default:674    return nullptr;675  }676 677  if (auto *S = G.findSectionByName(EHFrameSectionName))678    if (!S->empty())679      return S;680 681  return nullptr;682}683 684} // end namespace jitlink685} // end namespace llvm686