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
17namespace llvm {
18namespace jitlink {
19
20EHFrameSplitter::EHFrameSplitter(StringRef EHFrameSectionName)
21    : EHFrameSectionName(EHFrameSectionName) {}
22
23Error 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
65Error 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
119EHFrameEdgeFixer::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
125Error 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
168Error 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
257Error 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
383Error 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
543Expected<EHFrameEdgeFixer::AugmentationInfo>
544EHFrameEdgeFixer::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
584Expected<JITTargetAddress>
585EHFrameEdgeFixer::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
603Expected<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
642extern "C" void __register_frame(const void *);
643extern "C" void __deregister_frame(const void *);
644
645Error registerFrameWrapper(const void *P) {
646  __register_frame(P);
647  return Error::success();
648}
649
650Error 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.
661static 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
677static 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
697template <typename HandleFDEFn>
698Error 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
736Error 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
753Error 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
764EHFrameRegistrar::~EHFrameRegistrar() {}
765
766InProcessEHFrameRegistrar &InProcessEHFrameRegistrar::getInstance() {
767  static InProcessEHFrameRegistrar Instance;
768  return Instance;
769}
770
771InProcessEHFrameRegistrar::InProcessEHFrameRegistrar() {}
772
773LinkGraphPassFunction
774createEHFrameRecorderPass(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