xref: /freebsd/contrib/llvm-project/llvm/lib/ExecutionEngine/JITLink/EHFrameSupport.cpp (revision 5def4c47d4bd90b209b9b4a4ba9faec15846d8fd)
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                                    unsigned PointerSize, Edge::Kind Delta64,
123                                    Edge::Kind Delta32, Edge::Kind NegDelta32)
124     : EHFrameSectionName(EHFrameSectionName), PointerSize(PointerSize),
125       Delta64(Delta64), Delta32(Delta32), NegDelta32(NegDelta32) {}
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   // Check that we support the graph's pointer size.
139   if (G.getPointerSize() != 4 && G.getPointerSize() != 8)
140     return make_error<JITLinkError>(
141         "EHFrameEdgeFixer only supports 32 and 64 bit targets");
142 
143   LLVM_DEBUG({
144     dbgs() << "EHFrameEdgeFixer: Processing " << EHFrameSectionName << "...\n";
145   });
146 
147   ParseContext PC(G);
148 
149   // Build a map of all blocks and symbols in the text sections. We will use
150   // these for finding / building edge targets when processing FDEs.
151   for (auto &Sec : G.sections()) {
152     PC.AddrToSyms.addSymbols(Sec.symbols());
153     if (auto Err = PC.AddrToBlock.addBlocks(Sec.blocks(),
154                                             BlockAddressMap::includeNonNull))
155       return Err;
156   }
157 
158   // Sort eh-frame blocks into address order to ensure we visit CIEs before
159   // their child FDEs.
160   std::vector<Block *> EHFrameBlocks;
161   for (auto *B : EHFrame->blocks())
162     EHFrameBlocks.push_back(B);
163   llvm::sort(EHFrameBlocks, [](const Block *LHS, const Block *RHS) {
164     return LHS->getAddress() < RHS->getAddress();
165   });
166 
167   // Loop over the blocks in address order.
168   for (auto *B : EHFrameBlocks)
169     if (auto Err = processBlock(PC, *B))
170       return Err;
171 
172   return Error::success();
173 }
174 
175 Error EHFrameEdgeFixer::processBlock(ParseContext &PC, Block &B) {
176 
177   LLVM_DEBUG({
178     dbgs() << "  Processing block at " << formatv("{0:x16}", B.getAddress())
179            << "\n";
180   });
181 
182   // eh-frame should not contain zero-fill blocks.
183   if (B.isZeroFill())
184     return make_error<JITLinkError>("Unexpected zero-fill block in " +
185                                     EHFrameSectionName + " section");
186 
187   if (B.getSize() == 0) {
188     LLVM_DEBUG(dbgs() << "    Block is empty. Skipping.\n");
189     return Error::success();
190   }
191 
192   // Find the offsets of any existing edges from this block.
193   BlockEdgeMap BlockEdges;
194   for (auto &E : B.edges())
195     if (E.isRelocation()) {
196       if (BlockEdges.count(E.getOffset()))
197         return make_error<JITLinkError>(
198             "Multiple relocations at offset " +
199             formatv("{0:x16}", E.getOffset()) + " in " + EHFrameSectionName +
200             " block at address " + formatv("{0:x16}", B.getAddress()));
201 
202       BlockEdges[E.getOffset()] = EdgeTarget(E);
203     }
204 
205   CIEInfosMap CIEInfos;
206   BinaryStreamReader BlockReader(B.getContent(), PC.G.getEndianness());
207   while (!BlockReader.empty()) {
208     size_t RecordStartOffset = BlockReader.getOffset();
209 
210     LLVM_DEBUG({
211       dbgs() << "    Processing CFI record at "
212              << formatv("{0:x16}", B.getAddress() + RecordStartOffset) << "\n";
213     });
214 
215     // Get the record length.
216     size_t RecordRemaining;
217     {
218       uint32_t Length;
219       if (auto Err = BlockReader.readInteger(Length))
220         return Err;
221       // If Length < 0xffffffff then use the regular length field, otherwise
222       // read the extended length field.
223       if (Length != 0xffffffff)
224         RecordRemaining = Length;
225       else {
226         uint64_t ExtendedLength;
227         if (auto Err = BlockReader.readInteger(ExtendedLength))
228           return Err;
229         RecordRemaining = ExtendedLength;
230       }
231     }
232 
233     if (BlockReader.bytesRemaining() < RecordRemaining)
234       return make_error<JITLinkError>(
235           "Incomplete CFI record at " +
236           formatv("{0:x16}", B.getAddress() + RecordStartOffset));
237 
238     // Read the CIE delta for this record.
239     uint64_t CIEDeltaFieldOffset = BlockReader.getOffset() - RecordStartOffset;
240     uint32_t CIEDelta;
241     if (auto Err = BlockReader.readInteger(CIEDelta))
242       return Err;
243 
244     if (CIEDelta == 0) {
245       if (auto Err = processCIE(PC, B, RecordStartOffset,
246                                 CIEDeltaFieldOffset + RecordRemaining,
247                                 CIEDeltaFieldOffset))
248         return Err;
249     } else {
250       if (auto Err = processFDE(PC, B, RecordStartOffset,
251                                 CIEDeltaFieldOffset + RecordRemaining,
252                                 CIEDeltaFieldOffset, CIEDelta, BlockEdges))
253         return Err;
254     }
255 
256     // Move to the next record.
257     BlockReader.setOffset(RecordStartOffset + CIEDeltaFieldOffset +
258                           RecordRemaining);
259   }
260 
261   return Error::success();
262 }
263 
264 Error EHFrameEdgeFixer::processCIE(ParseContext &PC, Block &B,
265                                    size_t RecordOffset, size_t RecordLength,
266                                    size_t CIEDeltaFieldOffset) {
267 
268   LLVM_DEBUG(dbgs() << "      Record is CIE\n");
269 
270   auto RecordContent = B.getContent().substr(RecordOffset, RecordLength);
271   BinaryStreamReader RecordReader(RecordContent, PC.G.getEndianness());
272 
273   // Skip past the CIE delta field: we've already processed this far.
274   RecordReader.setOffset(CIEDeltaFieldOffset + 4);
275 
276   auto &CIESymbol =
277       PC.G.addAnonymousSymbol(B, RecordOffset, RecordLength, false, false);
278   CIEInformation CIEInfo(CIESymbol);
279 
280   uint8_t Version = 0;
281   if (auto Err = RecordReader.readInteger(Version))
282     return Err;
283 
284   if (Version != 0x01)
285     return make_error<JITLinkError>("Bad CIE version " + Twine(Version) +
286                                     " (should be 0x01) in eh-frame");
287 
288   auto AugInfo = parseAugmentationString(RecordReader);
289   if (!AugInfo)
290     return AugInfo.takeError();
291 
292   // Skip the EH Data field if present.
293   if (AugInfo->EHDataFieldPresent)
294     if (auto Err = RecordReader.skip(PC.G.getPointerSize()))
295       return Err;
296 
297   // Read and sanity check the code alignment factor.
298   {
299     uint64_t CodeAlignmentFactor = 0;
300     if (auto Err = RecordReader.readULEB128(CodeAlignmentFactor))
301       return Err;
302     if (CodeAlignmentFactor != 1)
303       return make_error<JITLinkError>("Unsupported CIE code alignment factor " +
304                                       Twine(CodeAlignmentFactor) +
305                                       " (expected 1)");
306   }
307 
308   // Read and sanity check the data alignment factor.
309   {
310     int64_t DataAlignmentFactor = 0;
311     if (auto Err = RecordReader.readSLEB128(DataAlignmentFactor))
312       return Err;
313     if (DataAlignmentFactor != -8)
314       return make_error<JITLinkError>("Unsupported CIE data alignment factor " +
315                                       Twine(DataAlignmentFactor) +
316                                       " (expected -8)");
317   }
318 
319   // Skip the return address register field.
320   if (auto Err = RecordReader.skip(1))
321     return Err;
322 
323   uint64_t AugmentationDataLength = 0;
324   if (auto Err = RecordReader.readULEB128(AugmentationDataLength))
325     return Err;
326 
327   uint32_t AugmentationDataStartOffset = RecordReader.getOffset();
328 
329   uint8_t *NextField = &AugInfo->Fields[0];
330   while (uint8_t Field = *NextField++) {
331     switch (Field) {
332     case 'L': {
333       CIEInfo.FDEsHaveLSDAField = true;
334       uint8_t LSDAPointerEncoding;
335       if (auto Err = RecordReader.readInteger(LSDAPointerEncoding))
336         return Err;
337       if (!isSupportedPointerEncoding(LSDAPointerEncoding))
338         return make_error<JITLinkError>(
339             "Unsupported LSDA pointer encoding " +
340             formatv("{0:x2}", LSDAPointerEncoding) + " in CIE at " +
341             formatv("{0:x16}", CIESymbol.getAddress()));
342       CIEInfo.LSDAPointerEncoding = LSDAPointerEncoding;
343       break;
344     }
345     case 'P': {
346       uint8_t PersonalityPointerEncoding = 0;
347       if (auto Err = RecordReader.readInteger(PersonalityPointerEncoding))
348         return Err;
349       if (PersonalityPointerEncoding !=
350           (dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_pcrel |
351            dwarf::DW_EH_PE_sdata4))
352         return make_error<JITLinkError>(
353             "Unspported personality pointer "
354             "encoding " +
355             formatv("{0:x2}", PersonalityPointerEncoding) + " in CIE at " +
356             formatv("{0:x16}", CIESymbol.getAddress()));
357       uint32_t PersonalityPointerAddress;
358       if (auto Err = RecordReader.readInteger(PersonalityPointerAddress))
359         return Err;
360       break;
361     }
362     case 'R': {
363       uint8_t FDEPointerEncoding;
364       if (auto Err = RecordReader.readInteger(FDEPointerEncoding))
365         return Err;
366       if (!isSupportedPointerEncoding(FDEPointerEncoding))
367         return make_error<JITLinkError>(
368             "Unsupported FDE pointer encoding " +
369             formatv("{0:x2}", FDEPointerEncoding) + " in CIE at " +
370             formatv("{0:x16}", CIESymbol.getAddress()));
371       CIEInfo.FDEPointerEncoding = FDEPointerEncoding;
372       break;
373     }
374     default:
375       llvm_unreachable("Invalid augmentation string field");
376     }
377   }
378 
379   if (RecordReader.getOffset() - AugmentationDataStartOffset >
380       AugmentationDataLength)
381     return make_error<JITLinkError>("Read past the end of the augmentation "
382                                     "data while parsing fields");
383 
384   assert(!PC.CIEInfos.count(CIESymbol.getAddress()) &&
385          "Multiple CIEs recorded at the same address?");
386   PC.CIEInfos[CIESymbol.getAddress()] = std::move(CIEInfo);
387 
388   return Error::success();
389 }
390 
391 Error EHFrameEdgeFixer::processFDE(ParseContext &PC, Block &B,
392                                    size_t RecordOffset, size_t RecordLength,
393                                    size_t CIEDeltaFieldOffset,
394                                    uint32_t CIEDelta,
395                                    BlockEdgeMap &BlockEdges) {
396   LLVM_DEBUG(dbgs() << "      Record is FDE\n");
397 
398   JITTargetAddress RecordAddress = B.getAddress() + RecordOffset;
399 
400   auto RecordContent = B.getContent().substr(RecordOffset, RecordLength);
401   BinaryStreamReader RecordReader(RecordContent, PC.G.getEndianness());
402 
403   // Skip past the CIE delta field: we've already read this far.
404   RecordReader.setOffset(CIEDeltaFieldOffset + 4);
405 
406   auto &FDESymbol =
407       PC.G.addAnonymousSymbol(B, RecordOffset, RecordLength, false, false);
408 
409   CIEInformation *CIEInfo = nullptr;
410 
411   {
412     // Process the CIE pointer field.
413     auto CIEEdgeItr = BlockEdges.find(RecordOffset + CIEDeltaFieldOffset);
414     JITTargetAddress CIEAddress =
415         RecordAddress + CIEDeltaFieldOffset - CIEDelta;
416     if (CIEEdgeItr == BlockEdges.end()) {
417 
418       LLVM_DEBUG({
419         dbgs() << "        Adding edge at "
420                << formatv("{0:x16}", RecordAddress + CIEDeltaFieldOffset)
421                << " to CIE at: " << formatv("{0:x16}", CIEAddress) << "\n";
422       });
423       if (auto CIEInfoOrErr = PC.findCIEInfo(CIEAddress))
424         CIEInfo = *CIEInfoOrErr;
425       else
426         return CIEInfoOrErr.takeError();
427       assert(CIEInfo->CIESymbol && "CIEInfo has no CIE symbol set");
428       B.addEdge(NegDelta32, RecordOffset + CIEDeltaFieldOffset,
429                 *CIEInfo->CIESymbol, 0);
430     } else {
431       LLVM_DEBUG({
432         dbgs() << "        Already has edge at "
433                << formatv("{0:x16}", RecordAddress + CIEDeltaFieldOffset)
434                << " to CIE at " << formatv("{0:x16}", CIEAddress) << "\n";
435       });
436       auto &EI = CIEEdgeItr->second;
437       if (EI.Addend)
438         return make_error<JITLinkError>(
439             "CIE edge at " +
440             formatv("{0:x16}", RecordAddress + CIEDeltaFieldOffset) +
441             " has non-zero addend");
442       if (auto CIEInfoOrErr = PC.findCIEInfo(EI.Target->getAddress()))
443         CIEInfo = *CIEInfoOrErr;
444       else
445         return CIEInfoOrErr.takeError();
446     }
447   }
448 
449   {
450     // Process the PC-Begin field.
451     Block *PCBeginBlock = nullptr;
452     JITTargetAddress PCBeginFieldOffset = RecordReader.getOffset();
453     auto PCEdgeItr = BlockEdges.find(RecordOffset + PCBeginFieldOffset);
454     if (PCEdgeItr == BlockEdges.end()) {
455       auto PCBeginPtrInfo =
456           readEncodedPointer(CIEInfo->FDEPointerEncoding,
457                              RecordAddress + PCBeginFieldOffset, RecordReader);
458       if (!PCBeginPtrInfo)
459         return PCBeginPtrInfo.takeError();
460       JITTargetAddress PCBegin = PCBeginPtrInfo->first;
461       Edge::Kind PCBeginEdgeKind = PCBeginPtrInfo->second;
462       LLVM_DEBUG({
463         dbgs() << "        Adding edge at "
464                << formatv("{0:x16}", RecordAddress + PCBeginFieldOffset)
465                << " to PC at " << formatv("{0:x16}", PCBegin) << "\n";
466       });
467       auto PCBeginSym = getOrCreateSymbol(PC, PCBegin);
468       if (!PCBeginSym)
469         return PCBeginSym.takeError();
470       B.addEdge(PCBeginEdgeKind, RecordOffset + PCBeginFieldOffset, *PCBeginSym,
471                 0);
472       PCBeginBlock = &PCBeginSym->getBlock();
473     } else {
474       auto &EI = PCEdgeItr->second;
475       LLVM_DEBUG({
476         dbgs() << "        Already has edge at "
477                << formatv("{0:x16}", RecordAddress + PCBeginFieldOffset)
478                << " to PC at " << formatv("{0:x16}", EI.Target->getAddress());
479         if (EI.Addend)
480           dbgs() << " + " << formatv("{0:x16}", EI.Addend);
481         dbgs() << "\n";
482       });
483 
484       // Make sure the existing edge points at a defined block.
485       if (!EI.Target->isDefined()) {
486         auto EdgeAddr = RecordAddress + PCBeginFieldOffset;
487         return make_error<JITLinkError>("FDE edge at " +
488                                         formatv("{0:x16}", EdgeAddr) +
489                                         " points at external block");
490       }
491       PCBeginBlock = &EI.Target->getBlock();
492       if (auto Err = RecordReader.skip(
493               getPointerEncodingDataSize(CIEInfo->FDEPointerEncoding)))
494         return Err;
495     }
496 
497     // Add a keep-alive edge from the FDE target to the FDE to ensure that the
498     // FDE is kept alive if its target is.
499     assert(PCBeginBlock && "PC-begin block not recorded");
500     LLVM_DEBUG({
501       dbgs() << "        Adding keep-alive edge from target at "
502              << formatv("{0:x16}", PCBeginBlock->getAddress()) << " to FDE at "
503              << formatv("{0:x16}", RecordAddress) << "\n";
504     });
505     PCBeginBlock->addEdge(Edge::KeepAlive, 0, FDESymbol, 0);
506   }
507 
508   // Skip over the PC range size field.
509   if (auto Err = RecordReader.skip(
510           getPointerEncodingDataSize(CIEInfo->FDEPointerEncoding)))
511     return Err;
512 
513   if (CIEInfo->FDEsHaveLSDAField) {
514     uint64_t AugmentationDataSize;
515     if (auto Err = RecordReader.readULEB128(AugmentationDataSize))
516       return Err;
517 
518     JITTargetAddress LSDAFieldOffset = RecordReader.getOffset();
519     auto LSDAEdgeItr = BlockEdges.find(RecordOffset + LSDAFieldOffset);
520     if (LSDAEdgeItr == BlockEdges.end()) {
521       auto LSDAPointerInfo =
522           readEncodedPointer(CIEInfo->LSDAPointerEncoding,
523                              RecordAddress + LSDAFieldOffset, RecordReader);
524       if (!LSDAPointerInfo)
525         return LSDAPointerInfo.takeError();
526       JITTargetAddress LSDA = LSDAPointerInfo->first;
527       Edge::Kind LSDAEdgeKind = LSDAPointerInfo->second;
528       auto LSDASym = getOrCreateSymbol(PC, LSDA);
529       if (!LSDASym)
530         return LSDASym.takeError();
531       LLVM_DEBUG({
532         dbgs() << "        Adding edge at "
533                << formatv("{0:x16}", RecordAddress + LSDAFieldOffset)
534                << " to LSDA at " << formatv("{0:x16}", LSDA) << "\n";
535       });
536       B.addEdge(LSDAEdgeKind, RecordOffset + LSDAFieldOffset, *LSDASym, 0);
537     } else {
538       LLVM_DEBUG({
539         auto &EI = LSDAEdgeItr->second;
540         dbgs() << "        Already has edge at "
541                << formatv("{0:x16}", RecordAddress + LSDAFieldOffset)
542                << " to LSDA at " << formatv("{0:x16}", EI.Target->getAddress());
543         if (EI.Addend)
544           dbgs() << " + " << formatv("{0:x16}", EI.Addend);
545         dbgs() << "\n";
546       });
547       if (auto Err = RecordReader.skip(AugmentationDataSize))
548         return Err;
549     }
550   } else {
551     LLVM_DEBUG(dbgs() << "        Record does not have LSDA field.\n");
552   }
553 
554   return Error::success();
555 }
556 
557 Expected<EHFrameEdgeFixer::AugmentationInfo>
558 EHFrameEdgeFixer::parseAugmentationString(BinaryStreamReader &RecordReader) {
559   AugmentationInfo AugInfo;
560   uint8_t NextChar;
561   uint8_t *NextField = &AugInfo.Fields[0];
562 
563   if (auto Err = RecordReader.readInteger(NextChar))
564     return std::move(Err);
565 
566   while (NextChar != 0) {
567     switch (NextChar) {
568     case 'z':
569       AugInfo.AugmentationDataPresent = true;
570       break;
571     case 'e':
572       if (auto Err = RecordReader.readInteger(NextChar))
573         return std::move(Err);
574       if (NextChar != 'h')
575         return make_error<JITLinkError>("Unrecognized substring e" +
576                                         Twine(NextChar) +
577                                         " in augmentation string");
578       AugInfo.EHDataFieldPresent = true;
579       break;
580     case 'L':
581     case 'P':
582     case 'R':
583       *NextField++ = NextChar;
584       break;
585     default:
586       return make_error<JITLinkError>("Unrecognized character " +
587                                       Twine(NextChar) +
588                                       " in augmentation string");
589     }
590 
591     if (auto Err = RecordReader.readInteger(NextChar))
592       return std::move(Err);
593   }
594 
595   return std::move(AugInfo);
596 }
597 
598 bool EHFrameEdgeFixer::isSupportedPointerEncoding(uint8_t PointerEncoding) {
599   using namespace dwarf;
600 
601   // We only support PC-rel for now.
602   if ((PointerEncoding & 0x70) != DW_EH_PE_pcrel)
603     return false;
604 
605   // readEncodedPointer does not handle indirect.
606   if (PointerEncoding & DW_EH_PE_indirect)
607     return false;
608 
609   // Supported datatypes.
610   switch (PointerEncoding & 0xf) {
611   case DW_EH_PE_absptr:
612   case DW_EH_PE_udata4:
613   case DW_EH_PE_udata8:
614   case DW_EH_PE_sdata4:
615   case DW_EH_PE_sdata8:
616     return true;
617   }
618 
619   return false;
620 }
621 
622 unsigned EHFrameEdgeFixer::getPointerEncodingDataSize(uint8_t PointerEncoding) {
623   using namespace dwarf;
624 
625   assert(isSupportedPointerEncoding(PointerEncoding) &&
626          "Unsupported pointer encoding");
627   switch (PointerEncoding & 0xf) {
628   case DW_EH_PE_absptr:
629     return PointerSize;
630   case DW_EH_PE_udata4:
631   case DW_EH_PE_sdata4:
632     return 4;
633   case DW_EH_PE_udata8:
634   case DW_EH_PE_sdata8:
635     return 8;
636   default:
637     llvm_unreachable("Unsupported encoding");
638   }
639 }
640 
641 Expected<std::pair<JITTargetAddress, Edge::Kind>>
642 EHFrameEdgeFixer::readEncodedPointer(uint8_t PointerEncoding,
643                                      JITTargetAddress PointerFieldAddress,
644                                      BinaryStreamReader &RecordReader) {
645   static_assert(sizeof(JITTargetAddress) == sizeof(uint64_t),
646                 "Result must be able to hold a uint64_t");
647   assert(isSupportedPointerEncoding(PointerEncoding) &&
648          "Unsupported pointer encoding");
649 
650   using namespace dwarf;
651 
652   // Isolate data type, remap absptr to udata4 or udata8. This relies on us
653   // having verified that the graph uses 32-bit or 64-bit pointers only at the
654   // start of this pass.
655   uint8_t EffectiveType = PointerEncoding & 0xf;
656   if (EffectiveType == DW_EH_PE_absptr)
657     EffectiveType = (PointerSize == 8) ? DW_EH_PE_udata8 : DW_EH_PE_udata4;
658 
659   JITTargetAddress Addr;
660   Edge::Kind PointerEdgeKind;
661   switch (EffectiveType) {
662   case DW_EH_PE_udata4: {
663     uint32_t Val;
664     if (auto Err = RecordReader.readInteger(Val))
665       return std::move(Err);
666     Addr = PointerFieldAddress + Val;
667     PointerEdgeKind = Delta32;
668     break;
669   }
670   case DW_EH_PE_udata8: {
671     uint64_t Val;
672     if (auto Err = RecordReader.readInteger(Val))
673       return std::move(Err);
674     Addr = PointerFieldAddress + Val;
675     PointerEdgeKind = Delta64;
676     break;
677   }
678   case DW_EH_PE_sdata4: {
679     int32_t Val;
680     if (auto Err = RecordReader.readInteger(Val))
681       return std::move(Err);
682     Addr = PointerFieldAddress + Val;
683     PointerEdgeKind = Delta32;
684     break;
685   }
686   case DW_EH_PE_sdata8: {
687     int64_t Val;
688     if (auto Err = RecordReader.readInteger(Val))
689       return std::move(Err);
690     Addr = PointerFieldAddress + Val;
691     PointerEdgeKind = Delta64;
692     break;
693   }
694   }
695 
696   if (PointerEdgeKind == Edge::Invalid)
697     return make_error<JITLinkError>(
698         "Unspported edge kind for encoded pointer at " +
699         formatv("{0:x}", PointerFieldAddress));
700 
701   return std::make_pair(Addr, Delta64);
702 }
703 
704 Expected<Symbol &> EHFrameEdgeFixer::getOrCreateSymbol(ParseContext &PC,
705                                                        JITTargetAddress Addr) {
706   Symbol *CanonicalSym = nullptr;
707 
708   auto UpdateCanonicalSym = [&](Symbol *Sym) {
709     if (!CanonicalSym || Sym->getLinkage() < CanonicalSym->getLinkage() ||
710         Sym->getScope() < CanonicalSym->getScope() ||
711         (Sym->hasName() && !CanonicalSym->hasName()) ||
712         Sym->getName() < CanonicalSym->getName())
713       CanonicalSym = Sym;
714   };
715 
716   if (auto *SymbolsAtAddr = PC.AddrToSyms.getSymbolsAt(Addr))
717     for (auto *Sym : *SymbolsAtAddr)
718       UpdateCanonicalSym(Sym);
719 
720   // If we found an existing symbol at the given address then use it.
721   if (CanonicalSym)
722     return *CanonicalSym;
723 
724   // Otherwise search for a block covering the address and create a new symbol.
725   auto *B = PC.AddrToBlock.getBlockCovering(Addr);
726   if (!B)
727     return make_error<JITLinkError>("No symbol or block covering address " +
728                                     formatv("{0:x16}", Addr));
729 
730   return PC.G.addAnonymousSymbol(*B, Addr - B->getAddress(), 0, false, false);
731 }
732 
733 EHFrameRegistrar::~EHFrameRegistrar() {}
734 
735 Error InProcessEHFrameRegistrar::registerEHFrames(
736     JITTargetAddress EHFrameSectionAddr, size_t EHFrameSectionSize) {
737   return orc::registerEHFrameSection(
738       jitTargetAddressToPointer<void *>(EHFrameSectionAddr),
739       EHFrameSectionSize);
740 }
741 
742 Error InProcessEHFrameRegistrar::deregisterEHFrames(
743     JITTargetAddress EHFrameSectionAddr, size_t EHFrameSectionSize) {
744   return orc::deregisterEHFrameSection(
745       jitTargetAddressToPointer<void *>(EHFrameSectionAddr),
746       EHFrameSectionSize);
747 }
748 
749 LinkGraphPassFunction
750 createEHFrameRecorderPass(const Triple &TT,
751                           StoreFrameRangeFunction StoreRangeAddress) {
752   const char *EHFrameSectionName = nullptr;
753   if (TT.getObjectFormat() == Triple::MachO)
754     EHFrameSectionName = "__eh_frame";
755   else
756     EHFrameSectionName = ".eh_frame";
757 
758   auto RecordEHFrame =
759       [EHFrameSectionName,
760        StoreFrameRange = std::move(StoreRangeAddress)](LinkGraph &G) -> Error {
761     // Search for a non-empty eh-frame and record the address of the first
762     // symbol in it.
763     JITTargetAddress Addr = 0;
764     size_t Size = 0;
765     if (auto *S = G.findSectionByName(EHFrameSectionName)) {
766       auto R = SectionRange(*S);
767       Addr = R.getStart();
768       Size = R.getSize();
769     }
770     if (Addr == 0 && Size != 0)
771       return make_error<JITLinkError>("__eh_frame section can not have zero "
772                                       "address with non-zero size");
773     StoreFrameRange(Addr, Size);
774     return Error::success();
775   };
776 
777   return RecordEHFrame;
778 }
779 
780 } // end namespace jitlink
781 } // end namespace llvm
782