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