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