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