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