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     // Just record the most-canonical symbol (for eh-frame purposes) at each
54     // address.
55     for (auto *Sym : Sec.symbols()) {
56       auto &CurSym = PC.AddrToSym[Sym->getAddress()];
57       if (!CurSym || (std::make_tuple(Sym->getLinkage(), Sym->getScope(),
58                                       !Sym->hasName(), Sym->getName()) <
59                       std::make_tuple(CurSym->getLinkage(), CurSym->getScope(),
60                                       !CurSym->hasName(), CurSym->getName())))
61         CurSym = Sym;
62     }
63     if (auto Err = PC.AddrToBlock.addBlocks(Sec.blocks(),
64                                             BlockAddressMap::includeNonNull))
65       return Err;
66   }
67 
68   // Sort eh-frame blocks into address order to ensure we visit CIEs before
69   // their child FDEs.
70   std::vector<Block *> EHFrameBlocks;
71   for (auto *B : EHFrame->blocks())
72     EHFrameBlocks.push_back(B);
73   llvm::sort(EHFrameBlocks, [](const Block *LHS, const Block *RHS) {
74     return LHS->getAddress() < RHS->getAddress();
75   });
76 
77   // Loop over the blocks in address order.
78   for (auto *B : EHFrameBlocks)
79     if (auto Err = processBlock(PC, *B))
80       return Err;
81 
82   return Error::success();
83 }
84 
85 Error EHFrameEdgeFixer::processBlock(ParseContext &PC, Block &B) {
86 
87   LLVM_DEBUG({
88     dbgs() << "  Processing block at " << formatv("{0:x16}", B.getAddress())
89            << "\n";
90   });
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              << formatv("{0:x16}", 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))
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 
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   uint64_t AugmentationDataLength = 0;
238   if (auto Err = RecordReader.readULEB128(AugmentationDataLength))
239     return Err;
240 
241   uint32_t AugmentationDataStartOffset = RecordReader.getOffset();
242 
243   uint8_t *NextField = &AugInfo->Fields[0];
244   while (uint8_t Field = *NextField++) {
245     switch (Field) {
246     case 'L': {
247       CIEInfo.FDEsHaveLSDAField = true;
248       uint8_t LSDAPointerEncoding;
249       if (auto Err = RecordReader.readInteger(LSDAPointerEncoding))
250         return Err;
251       if (!isSupportedPointerEncoding(LSDAPointerEncoding))
252         return make_error<JITLinkError>(
253             "Unsupported LSDA pointer encoding " +
254             formatv("{0:x2}", LSDAPointerEncoding) + " in CIE at " +
255             formatv("{0:x16}", CIESymbol.getAddress()));
256       CIEInfo.LSDAPointerEncoding = LSDAPointerEncoding;
257       break;
258     }
259     case 'P': {
260       uint8_t PersonalityPointerEncoding = 0;
261       if (auto Err = RecordReader.readInteger(PersonalityPointerEncoding))
262         return Err;
263       if (PersonalityPointerEncoding !=
264           (dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_pcrel |
265            dwarf::DW_EH_PE_sdata4))
266         return make_error<JITLinkError>(
267             "Unspported personality pointer "
268             "encoding " +
269             formatv("{0:x2}", PersonalityPointerEncoding) + " in CIE at " +
270             formatv("{0:x16}", CIESymbol.getAddress()));
271       uint32_t PersonalityPointerAddress;
272       if (auto Err = RecordReader.readInteger(PersonalityPointerAddress))
273         return Err;
274       break;
275     }
276     case 'R': {
277       uint8_t FDEPointerEncoding;
278       if (auto Err = RecordReader.readInteger(FDEPointerEncoding))
279         return Err;
280       if (!isSupportedPointerEncoding(FDEPointerEncoding))
281         return make_error<JITLinkError>(
282             "Unsupported FDE pointer encoding " +
283             formatv("{0:x2}", FDEPointerEncoding) + " in CIE at " +
284             formatv("{0:x16}", CIESymbol.getAddress()));
285       CIEInfo.FDEPointerEncoding = FDEPointerEncoding;
286       break;
287     }
288     default:
289       llvm_unreachable("Invalid augmentation string field");
290     }
291   }
292 
293   if (RecordReader.getOffset() - AugmentationDataStartOffset >
294       AugmentationDataLength)
295     return make_error<JITLinkError>("Read past the end of the augmentation "
296                                     "data while parsing fields");
297 
298   assert(!PC.CIEInfos.count(CIESymbol.getAddress()) &&
299          "Multiple CIEs recorded at the same address?");
300   PC.CIEInfos[CIESymbol.getAddress()] = std::move(CIEInfo);
301 
302   return Error::success();
303 }
304 
305 Error EHFrameEdgeFixer::processFDE(ParseContext &PC, Block &B,
306                                    size_t RecordOffset, size_t RecordLength,
307                                    size_t CIEDeltaFieldOffset,
308                                    uint32_t CIEDelta,
309                                    BlockEdgeMap &BlockEdges) {
310   LLVM_DEBUG(dbgs() << "      Record is FDE\n");
311 
312   orc::ExecutorAddr RecordAddress = B.getAddress() + RecordOffset;
313 
314   auto RecordContent = B.getContent().slice(RecordOffset, RecordLength);
315   BinaryStreamReader RecordReader(
316       StringRef(RecordContent.data(), RecordContent.size()),
317       PC.G.getEndianness());
318 
319   // Skip past the CIE delta field: we've already read this far.
320   RecordReader.setOffset(CIEDeltaFieldOffset + 4);
321 
322   auto &FDESymbol =
323       PC.G.addAnonymousSymbol(B, RecordOffset, RecordLength, false, false);
324 
325   CIEInformation *CIEInfo = nullptr;
326 
327   {
328     // Process the CIE pointer field.
329     auto CIEEdgeItr = BlockEdges.find(RecordOffset + CIEDeltaFieldOffset);
330     orc::ExecutorAddr CIEAddress =
331         RecordAddress + orc::ExecutorAddrDiff(CIEDeltaFieldOffset) -
332         orc::ExecutorAddrDiff(CIEDelta);
333     if (CIEEdgeItr == BlockEdges.end()) {
334 
335       LLVM_DEBUG({
336         dbgs() << "        Adding edge at "
337                << formatv("{0:x16}", RecordAddress + CIEDeltaFieldOffset)
338                << " to CIE at: " << formatv("{0:x16}", CIEAddress) << "\n";
339       });
340       if (auto CIEInfoOrErr = PC.findCIEInfo(CIEAddress))
341         CIEInfo = *CIEInfoOrErr;
342       else
343         return CIEInfoOrErr.takeError();
344       assert(CIEInfo->CIESymbol && "CIEInfo has no CIE symbol set");
345       B.addEdge(NegDelta32, RecordOffset + CIEDeltaFieldOffset,
346                 *CIEInfo->CIESymbol, 0);
347     } else {
348       LLVM_DEBUG({
349         dbgs() << "        Already has edge at "
350                << formatv("{0:x16}", RecordAddress + CIEDeltaFieldOffset)
351                << " to CIE at " << formatv("{0:x16}", CIEAddress) << "\n";
352       });
353       auto &EI = CIEEdgeItr->second;
354       if (EI.Addend)
355         return make_error<JITLinkError>(
356             "CIE edge at " +
357             formatv("{0:x16}", RecordAddress + CIEDeltaFieldOffset) +
358             " has non-zero addend");
359       if (auto CIEInfoOrErr = PC.findCIEInfo(EI.Target->getAddress()))
360         CIEInfo = *CIEInfoOrErr;
361       else
362         return CIEInfoOrErr.takeError();
363     }
364   }
365 
366   {
367     // Process the PC-Begin field.
368     Block *PCBeginBlock = nullptr;
369     orc::ExecutorAddrDiff PCBeginFieldOffset = RecordReader.getOffset();
370     auto PCEdgeItr = BlockEdges.find(RecordOffset + PCBeginFieldOffset);
371     if (PCEdgeItr == BlockEdges.end()) {
372       auto PCBeginPtrInfo =
373           readEncodedPointer(CIEInfo->FDEPointerEncoding,
374                              RecordAddress + PCBeginFieldOffset, RecordReader);
375       if (!PCBeginPtrInfo)
376         return PCBeginPtrInfo.takeError();
377       orc::ExecutorAddr PCBegin = PCBeginPtrInfo->first;
378       Edge::Kind PCBeginEdgeKind = PCBeginPtrInfo->second;
379       LLVM_DEBUG({
380         dbgs() << "        Adding edge at "
381                << (RecordAddress + PCBeginFieldOffset) << " to PC at "
382                << formatv("{0:x16}", PCBegin) << "\n";
383       });
384       auto PCBeginSym = getOrCreateSymbol(PC, PCBegin);
385       if (!PCBeginSym)
386         return PCBeginSym.takeError();
387       B.addEdge(PCBeginEdgeKind, RecordOffset + PCBeginFieldOffset, *PCBeginSym,
388                 0);
389       PCBeginBlock = &PCBeginSym->getBlock();
390     } else {
391       auto &EI = PCEdgeItr->second;
392       LLVM_DEBUG({
393         dbgs() << "        Already has edge at "
394                << formatv("{0:x16}", RecordAddress + PCBeginFieldOffset)
395                << " to PC at " << formatv("{0:x16}", EI.Target->getAddress());
396         if (EI.Addend)
397           dbgs() << " + " << formatv("{0:x16}", EI.Addend);
398         dbgs() << "\n";
399       });
400 
401       // Make sure the existing edge points at a defined block.
402       if (!EI.Target->isDefined()) {
403         auto EdgeAddr = RecordAddress + PCBeginFieldOffset;
404         return make_error<JITLinkError>("FDE edge at " +
405                                         formatv("{0:x16}", EdgeAddr) +
406                                         " points at external block");
407       }
408       PCBeginBlock = &EI.Target->getBlock();
409       if (auto Err = RecordReader.skip(
410               getPointerEncodingDataSize(CIEInfo->FDEPointerEncoding)))
411         return Err;
412     }
413 
414     // Add a keep-alive edge from the FDE target to the FDE to ensure that the
415     // FDE is kept alive if its target is.
416     assert(PCBeginBlock && "PC-begin block not recorded");
417     LLVM_DEBUG({
418       dbgs() << "        Adding keep-alive edge from target at "
419              << formatv("{0:x16}", PCBeginBlock->getAddress()) << " to FDE at "
420              << formatv("{0:x16}", RecordAddress) << "\n";
421     });
422     PCBeginBlock->addEdge(Edge::KeepAlive, 0, FDESymbol, 0);
423   }
424 
425   // Skip over the PC range size field.
426   if (auto Err = RecordReader.skip(
427           getPointerEncodingDataSize(CIEInfo->FDEPointerEncoding)))
428     return Err;
429 
430   if (CIEInfo->FDEsHaveLSDAField) {
431     uint64_t AugmentationDataSize;
432     if (auto Err = RecordReader.readULEB128(AugmentationDataSize))
433       return Err;
434 
435     orc::ExecutorAddrDiff LSDAFieldOffset = RecordReader.getOffset();
436     auto LSDAEdgeItr = BlockEdges.find(RecordOffset + LSDAFieldOffset);
437     if (LSDAEdgeItr == BlockEdges.end()) {
438       auto LSDAPointerInfo =
439           readEncodedPointer(CIEInfo->LSDAPointerEncoding,
440                              RecordAddress + LSDAFieldOffset, RecordReader);
441       if (!LSDAPointerInfo)
442         return LSDAPointerInfo.takeError();
443       orc::ExecutorAddr LSDA = LSDAPointerInfo->first;
444       Edge::Kind LSDAEdgeKind = LSDAPointerInfo->second;
445       auto LSDASym = getOrCreateSymbol(PC, LSDA);
446       if (!LSDASym)
447         return LSDASym.takeError();
448       LLVM_DEBUG({
449         dbgs() << "        Adding edge at "
450                << formatv("{0:x16}", RecordAddress + LSDAFieldOffset)
451                << " to LSDA at " << formatv("{0:x16}", LSDA) << "\n";
452       });
453       B.addEdge(LSDAEdgeKind, RecordOffset + LSDAFieldOffset, *LSDASym, 0);
454     } else {
455       LLVM_DEBUG({
456         auto &EI = LSDAEdgeItr->second;
457         dbgs() << "        Already has edge at "
458                << formatv("{0:x16}", RecordAddress + LSDAFieldOffset)
459                << " to LSDA at " << formatv("{0:x16}", EI.Target->getAddress());
460         if (EI.Addend)
461           dbgs() << " + " << formatv("{0:x16}", EI.Addend);
462         dbgs() << "\n";
463       });
464       if (auto Err = RecordReader.skip(AugmentationDataSize))
465         return Err;
466     }
467   } else {
468     LLVM_DEBUG(dbgs() << "        Record does not have LSDA field.\n");
469   }
470 
471   return Error::success();
472 }
473 
474 Expected<EHFrameEdgeFixer::AugmentationInfo>
475 EHFrameEdgeFixer::parseAugmentationString(BinaryStreamReader &RecordReader) {
476   AugmentationInfo AugInfo;
477   uint8_t NextChar;
478   uint8_t *NextField = &AugInfo.Fields[0];
479 
480   if (auto Err = RecordReader.readInteger(NextChar))
481     return std::move(Err);
482 
483   while (NextChar != 0) {
484     switch (NextChar) {
485     case 'z':
486       AugInfo.AugmentationDataPresent = true;
487       break;
488     case 'e':
489       if (auto Err = RecordReader.readInteger(NextChar))
490         return std::move(Err);
491       if (NextChar != 'h')
492         return make_error<JITLinkError>("Unrecognized substring e" +
493                                         Twine(NextChar) +
494                                         " in augmentation string");
495       AugInfo.EHDataFieldPresent = true;
496       break;
497     case 'L':
498     case 'P':
499     case 'R':
500       *NextField++ = NextChar;
501       break;
502     default:
503       return make_error<JITLinkError>("Unrecognized character " +
504                                       Twine(NextChar) +
505                                       " in augmentation string");
506     }
507 
508     if (auto Err = RecordReader.readInteger(NextChar))
509       return std::move(Err);
510   }
511 
512   return std::move(AugInfo);
513 }
514 
515 bool EHFrameEdgeFixer::isSupportedPointerEncoding(uint8_t PointerEncoding) {
516   using namespace dwarf;
517 
518   // We only support PC-rel for now.
519   if ((PointerEncoding & 0x70) != DW_EH_PE_pcrel)
520     return false;
521 
522   // readEncodedPointer does not handle indirect.
523   if (PointerEncoding & DW_EH_PE_indirect)
524     return false;
525 
526   // Supported datatypes.
527   switch (PointerEncoding & 0xf) {
528   case DW_EH_PE_absptr:
529   case DW_EH_PE_udata4:
530   case DW_EH_PE_udata8:
531   case DW_EH_PE_sdata4:
532   case DW_EH_PE_sdata8:
533     return true;
534   }
535 
536   return false;
537 }
538 
539 unsigned EHFrameEdgeFixer::getPointerEncodingDataSize(uint8_t PointerEncoding) {
540   using namespace dwarf;
541 
542   assert(isSupportedPointerEncoding(PointerEncoding) &&
543          "Unsupported pointer encoding");
544   switch (PointerEncoding & 0xf) {
545   case DW_EH_PE_absptr:
546     return PointerSize;
547   case DW_EH_PE_udata4:
548   case DW_EH_PE_sdata4:
549     return 4;
550   case DW_EH_PE_udata8:
551   case DW_EH_PE_sdata8:
552     return 8;
553   default:
554     llvm_unreachable("Unsupported encoding");
555   }
556 }
557 
558 Expected<std::pair<orc::ExecutorAddr, Edge::Kind>>
559 EHFrameEdgeFixer::readEncodedPointer(uint8_t PointerEncoding,
560                                      orc::ExecutorAddr PointerFieldAddress,
561                                      BinaryStreamReader &RecordReader) {
562   assert(isSupportedPointerEncoding(PointerEncoding) &&
563          "Unsupported pointer encoding");
564 
565   using namespace dwarf;
566 
567   // Isolate data type, remap absptr to udata4 or udata8. This relies on us
568   // having verified that the graph uses 32-bit or 64-bit pointers only at the
569   // start of this pass.
570   uint8_t EffectiveType = PointerEncoding & 0xf;
571   if (EffectiveType == DW_EH_PE_absptr)
572     EffectiveType = (PointerSize == 8) ? DW_EH_PE_udata8 : DW_EH_PE_udata4;
573 
574   orc::ExecutorAddr Addr;
575   Edge::Kind PointerEdgeKind = Edge::Invalid;
576   switch (EffectiveType) {
577   case DW_EH_PE_udata4: {
578     uint32_t Val;
579     if (auto Err = RecordReader.readInteger(Val))
580       return std::move(Err);
581     Addr = PointerFieldAddress + Val;
582     PointerEdgeKind = Delta32;
583     break;
584   }
585   case DW_EH_PE_udata8: {
586     uint64_t Val;
587     if (auto Err = RecordReader.readInteger(Val))
588       return std::move(Err);
589     Addr = PointerFieldAddress + Val;
590     PointerEdgeKind = Delta64;
591     break;
592   }
593   case DW_EH_PE_sdata4: {
594     int32_t Val;
595     if (auto Err = RecordReader.readInteger(Val))
596       return std::move(Err);
597     Addr = PointerFieldAddress + Val;
598     PointerEdgeKind = Delta32;
599     break;
600   }
601   case DW_EH_PE_sdata8: {
602     int64_t Val;
603     if (auto Err = RecordReader.readInteger(Val))
604       return std::move(Err);
605     Addr = PointerFieldAddress + Val;
606     PointerEdgeKind = Delta64;
607     break;
608   }
609   }
610 
611   if (PointerEdgeKind == Edge::Invalid)
612     return make_error<JITLinkError>(
613         "Unspported edge kind for encoded pointer at " +
614         formatv("{0:x}", PointerFieldAddress));
615 
616   return std::make_pair(Addr, Delta64);
617 }
618 
619 Expected<Symbol &> EHFrameEdgeFixer::getOrCreateSymbol(ParseContext &PC,
620                                                        orc::ExecutorAddr Addr) {
621   // See whether we have a canonical symbol for the given address already.
622   auto CanonicalSymI = PC.AddrToSym.find(Addr);
623   if (CanonicalSymI != PC.AddrToSym.end())
624     return *CanonicalSymI->second;
625 
626   // Otherwise search for a block covering the address and create a new symbol.
627   auto *B = PC.AddrToBlock.getBlockCovering(Addr);
628   if (!B)
629     return make_error<JITLinkError>("No symbol or block covering address " +
630                                     formatv("{0:x16}", Addr));
631 
632   auto &S =
633       PC.G.addAnonymousSymbol(*B, Addr - B->getAddress(), 0, false, false);
634   PC.AddrToSym[S.getAddress()] = &S;
635   return S;
636 }
637 
638 char EHFrameNullTerminator::NullTerminatorBlockContent[4] = {0, 0, 0, 0};
639 
640 EHFrameNullTerminator::EHFrameNullTerminator(StringRef EHFrameSectionName)
641     : EHFrameSectionName(EHFrameSectionName) {}
642 
643 Error EHFrameNullTerminator::operator()(LinkGraph &G) {
644   auto *EHFrame = G.findSectionByName(EHFrameSectionName);
645 
646   if (!EHFrame)
647     return Error::success();
648 
649   LLVM_DEBUG({
650     dbgs() << "EHFrameNullTerminator adding null terminator to "
651            << EHFrameSectionName << "\n";
652   });
653 
654   auto &NullTerminatorBlock =
655       G.createContentBlock(*EHFrame, NullTerminatorBlockContent,
656                            orc::ExecutorAddr(~uint64_t(4)), 1, 0);
657   G.addAnonymousSymbol(NullTerminatorBlock, 0, 4, false, true);
658   return Error::success();
659 }
660 
661 EHFrameRegistrar::~EHFrameRegistrar() = default;
662 
663 Error InProcessEHFrameRegistrar::registerEHFrames(
664     orc::ExecutorAddrRange EHFrameSection) {
665   return orc::registerEHFrameSection(EHFrameSection.Start.toPtr<void *>(),
666                                      EHFrameSection.size());
667 }
668 
669 Error InProcessEHFrameRegistrar::deregisterEHFrames(
670     orc::ExecutorAddrRange EHFrameSection) {
671   return orc::deregisterEHFrameSection(EHFrameSection.Start.toPtr<void *>(),
672                                        EHFrameSection.size());
673 }
674 
675 LinkGraphPassFunction
676 createEHFrameRecorderPass(const Triple &TT,
677                           StoreFrameRangeFunction StoreRangeAddress) {
678   const char *EHFrameSectionName = nullptr;
679   if (TT.getObjectFormat() == Triple::MachO)
680     EHFrameSectionName = "__TEXT,__eh_frame";
681   else
682     EHFrameSectionName = ".eh_frame";
683 
684   auto RecordEHFrame =
685       [EHFrameSectionName,
686        StoreFrameRange = std::move(StoreRangeAddress)](LinkGraph &G) -> Error {
687     // Search for a non-empty eh-frame and record the address of the first
688     // symbol in it.
689     orc::ExecutorAddr Addr;
690     size_t Size = 0;
691     if (auto *S = G.findSectionByName(EHFrameSectionName)) {
692       auto R = SectionRange(*S);
693       Addr = R.getStart();
694       Size = R.getSize();
695     }
696     if (!Addr && Size != 0)
697       return make_error<JITLinkError>(
698           StringRef(EHFrameSectionName) +
699           " section can not have zero address with non-zero size");
700     StoreFrameRange(Addr, Size);
701     return Error::success();
702   };
703 
704   return RecordEHFrame;
705 }
706 
707 } // end namespace jitlink
708 } // end namespace llvm
709