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