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