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