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