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