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