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