10b57cec5SDimitry Andric //===-------- JITLink_EHFrameSupport.cpp - JITLink eh-frame utils ---------===//
20b57cec5SDimitry Andric //
3349cc55cSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4349cc55cSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5349cc55cSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric 
90b57cec5SDimitry Andric #include "EHFrameSupportImpl.h"
100b57cec5SDimitry Andric 
110b57cec5SDimitry Andric #include "llvm/BinaryFormat/Dwarf.h"
12e8d8bef9SDimitry Andric #include "llvm/Config/config.h"
1381ad6265SDimitry Andric #include "llvm/ExecutionEngine/JITLink/DWARFRecordSectionSplitter.h"
14e8d8bef9SDimitry Andric #include "llvm/ExecutionEngine/Orc/TargetProcess/RegisterEHFrames.h"
150b57cec5SDimitry Andric #include "llvm/Support/DynamicLibrary.h"
160b57cec5SDimitry Andric 
170b57cec5SDimitry Andric #define DEBUG_TYPE "jitlink"
180b57cec5SDimitry Andric 
190b57cec5SDimitry Andric namespace llvm {
200b57cec5SDimitry Andric namespace jitlink {
210b57cec5SDimitry Andric 
EHFrameEdgeFixer(StringRef EHFrameSectionName,unsigned PointerSize,Edge::Kind Pointer32,Edge::Kind Pointer64,Edge::Kind Delta32,Edge::Kind Delta64,Edge::Kind NegDelta32)22480093f4SDimitry Andric EHFrameEdgeFixer::EHFrameEdgeFixer(StringRef EHFrameSectionName,
2381ad6265SDimitry Andric                                    unsigned PointerSize, Edge::Kind Pointer32,
2481ad6265SDimitry Andric                                    Edge::Kind Pointer64, Edge::Kind Delta32,
2581ad6265SDimitry Andric                                    Edge::Kind Delta64, Edge::Kind NegDelta32)
26e8d8bef9SDimitry Andric     : EHFrameSectionName(EHFrameSectionName), PointerSize(PointerSize),
2781ad6265SDimitry Andric       Pointer32(Pointer32), Pointer64(Pointer64), Delta32(Delta32),
2881ad6265SDimitry Andric       Delta64(Delta64), NegDelta32(NegDelta32) {}
29480093f4SDimitry Andric 
operator ()(LinkGraph & G)30480093f4SDimitry Andric Error EHFrameEdgeFixer::operator()(LinkGraph &G) {
31480093f4SDimitry Andric   auto *EHFrame = G.findSectionByName(EHFrameSectionName);
32480093f4SDimitry Andric 
33480093f4SDimitry Andric   if (!EHFrame) {
34480093f4SDimitry Andric     LLVM_DEBUG({
35480093f4SDimitry Andric       dbgs() << "EHFrameEdgeFixer: No " << EHFrameSectionName
36753f127fSDimitry Andric              << " section in \"" << G.getName() << "\". Nothing to do.\n";
37480093f4SDimitry Andric     });
38480093f4SDimitry Andric     return Error::success();
39480093f4SDimitry Andric   }
40480093f4SDimitry Andric 
41e8d8bef9SDimitry Andric   // Check that we support the graph's pointer size.
42e8d8bef9SDimitry Andric   if (G.getPointerSize() != 4 && G.getPointerSize() != 8)
43e8d8bef9SDimitry Andric     return make_error<JITLinkError>(
44e8d8bef9SDimitry Andric         "EHFrameEdgeFixer only supports 32 and 64 bit targets");
45e8d8bef9SDimitry Andric 
46480093f4SDimitry Andric   LLVM_DEBUG({
47753f127fSDimitry Andric     dbgs() << "EHFrameEdgeFixer: Processing " << EHFrameSectionName << " in \""
48753f127fSDimitry Andric            << G.getName() << "\"...\n";
49480093f4SDimitry Andric   });
50480093f4SDimitry Andric 
51480093f4SDimitry Andric   ParseContext PC(G);
52480093f4SDimitry Andric 
53480093f4SDimitry Andric   // Build a map of all blocks and symbols in the text sections. We will use
54480093f4SDimitry Andric   // these for finding / building edge targets when processing FDEs.
55480093f4SDimitry Andric   for (auto &Sec : G.sections()) {
5681ad6265SDimitry Andric     // Just record the most-canonical symbol (for eh-frame purposes) at each
5781ad6265SDimitry Andric     // address.
5881ad6265SDimitry Andric     for (auto *Sym : Sec.symbols()) {
5981ad6265SDimitry Andric       auto &CurSym = PC.AddrToSym[Sym->getAddress()];
6081ad6265SDimitry Andric       if (!CurSym || (std::make_tuple(Sym->getLinkage(), Sym->getScope(),
6181ad6265SDimitry Andric                                       !Sym->hasName(), Sym->getName()) <
6281ad6265SDimitry Andric                       std::make_tuple(CurSym->getLinkage(), CurSym->getScope(),
6381ad6265SDimitry Andric                                       !CurSym->hasName(), CurSym->getName())))
6481ad6265SDimitry Andric         CurSym = Sym;
6581ad6265SDimitry Andric     }
66480093f4SDimitry Andric     if (auto Err = PC.AddrToBlock.addBlocks(Sec.blocks(),
67480093f4SDimitry Andric                                             BlockAddressMap::includeNonNull))
68480093f4SDimitry Andric       return Err;
69480093f4SDimitry Andric   }
70480093f4SDimitry Andric 
71480093f4SDimitry Andric   // Sort eh-frame blocks into address order to ensure we visit CIEs before
72480093f4SDimitry Andric   // their child FDEs.
73480093f4SDimitry Andric   std::vector<Block *> EHFrameBlocks;
74480093f4SDimitry Andric   for (auto *B : EHFrame->blocks())
75480093f4SDimitry Andric     EHFrameBlocks.push_back(B);
76480093f4SDimitry Andric   llvm::sort(EHFrameBlocks, [](const Block *LHS, const Block *RHS) {
77480093f4SDimitry Andric     return LHS->getAddress() < RHS->getAddress();
78480093f4SDimitry Andric   });
79480093f4SDimitry Andric 
80480093f4SDimitry Andric   // Loop over the blocks in address order.
81480093f4SDimitry Andric   for (auto *B : EHFrameBlocks)
82480093f4SDimitry Andric     if (auto Err = processBlock(PC, *B))
83480093f4SDimitry Andric       return Err;
84480093f4SDimitry Andric 
85480093f4SDimitry Andric   return Error::success();
86480093f4SDimitry Andric }
87480093f4SDimitry Andric 
readCFIRecordLength(const Block & B,BinaryStreamReader & R)88bdd1243dSDimitry Andric static Expected<size_t> readCFIRecordLength(const Block &B,
89bdd1243dSDimitry Andric                                             BinaryStreamReader &R) {
90bdd1243dSDimitry Andric   uint32_t Length;
91bdd1243dSDimitry Andric   if (auto Err = R.readInteger(Length))
92bdd1243dSDimitry Andric     return std::move(Err);
93bdd1243dSDimitry Andric 
94bdd1243dSDimitry Andric   // If Length < 0xffffffff then use the regular length field, otherwise
95bdd1243dSDimitry Andric   // read the extended length field.
96bdd1243dSDimitry Andric   if (Length != 0xffffffff)
97bdd1243dSDimitry Andric     return Length;
98bdd1243dSDimitry Andric 
99bdd1243dSDimitry Andric   uint64_t ExtendedLength;
100bdd1243dSDimitry Andric   if (auto Err = R.readInteger(ExtendedLength))
101bdd1243dSDimitry Andric     return std::move(Err);
102bdd1243dSDimitry Andric 
103bdd1243dSDimitry Andric   if (ExtendedLength > std::numeric_limits<size_t>::max())
104bdd1243dSDimitry Andric     return make_error<JITLinkError>(
105bdd1243dSDimitry Andric         "In CFI record at " +
106bdd1243dSDimitry Andric         formatv("{0:x}", B.getAddress() + R.getOffset() - 12) +
107bdd1243dSDimitry Andric         ", extended length of " + formatv("{0:x}", ExtendedLength) +
108bdd1243dSDimitry Andric         " exceeds address-range max (" +
109bdd1243dSDimitry Andric         formatv("{0:x}", std::numeric_limits<size_t>::max()));
110bdd1243dSDimitry Andric 
111bdd1243dSDimitry Andric   return ExtendedLength;
112bdd1243dSDimitry Andric }
113bdd1243dSDimitry Andric 
processBlock(ParseContext & PC,Block & B)114480093f4SDimitry Andric Error EHFrameEdgeFixer::processBlock(ParseContext &PC, Block &B) {
115480093f4SDimitry Andric 
11681ad6265SDimitry Andric   LLVM_DEBUG(dbgs() << "  Processing block at " << B.getAddress() << "\n");
117480093f4SDimitry Andric 
118480093f4SDimitry Andric   // eh-frame should not contain zero-fill blocks.
119480093f4SDimitry Andric   if (B.isZeroFill())
120480093f4SDimitry Andric     return make_error<JITLinkError>("Unexpected zero-fill block in " +
121480093f4SDimitry Andric                                     EHFrameSectionName + " section");
122480093f4SDimitry Andric 
123480093f4SDimitry Andric   if (B.getSize() == 0) {
124480093f4SDimitry Andric     LLVM_DEBUG(dbgs() << "    Block is empty. Skipping.\n");
125480093f4SDimitry Andric     return Error::success();
126480093f4SDimitry Andric   }
127480093f4SDimitry Andric 
128480093f4SDimitry Andric   // Find the offsets of any existing edges from this block.
1295f757f3fSDimitry Andric   BlockEdgesInfo BlockEdges;
130480093f4SDimitry Andric   for (auto &E : B.edges())
131480093f4SDimitry Andric     if (E.isRelocation()) {
1325f757f3fSDimitry Andric       // Check if we already saw more than one relocation at this offset.
1335f757f3fSDimitry Andric       if (BlockEdges.Multiple.contains(E.getOffset()))
1345f757f3fSDimitry Andric         continue;
135480093f4SDimitry Andric 
1365f757f3fSDimitry Andric       // Otherwise check if we previously had exactly one relocation at this
1375f757f3fSDimitry Andric       // offset. If so, we now have a second one and move it from the TargetMap
1385f757f3fSDimitry Andric       // into the Multiple set.
1395f757f3fSDimitry Andric       auto It = BlockEdges.TargetMap.find(E.getOffset());
1405f757f3fSDimitry Andric       if (It != BlockEdges.TargetMap.end()) {
1415f757f3fSDimitry Andric         BlockEdges.TargetMap.erase(It);
1425f757f3fSDimitry Andric         BlockEdges.Multiple.insert(E.getOffset());
1435f757f3fSDimitry Andric       } else {
1445f757f3fSDimitry Andric         BlockEdges.TargetMap[E.getOffset()] = EdgeTarget(E);
1455f757f3fSDimitry Andric       }
146480093f4SDimitry Andric     }
147480093f4SDimitry Andric 
148fe6060f1SDimitry Andric   BinaryStreamReader BlockReader(
149fe6060f1SDimitry Andric       StringRef(B.getContent().data(), B.getContent().size()),
150fe6060f1SDimitry Andric       PC.G.getEndianness());
151480093f4SDimitry Andric 
152480093f4SDimitry Andric   // Get the record length.
153bdd1243dSDimitry Andric   Expected<size_t> RecordRemaining = readCFIRecordLength(B, BlockReader);
154bdd1243dSDimitry Andric   if (!RecordRemaining)
155bdd1243dSDimitry Andric     return RecordRemaining.takeError();
156480093f4SDimitry Andric 
1575f757f3fSDimitry Andric   // We expect DWARFRecordSectionSplitter to split each CFI record into its own
1585f757f3fSDimitry Andric   // block.
1595f757f3fSDimitry Andric   if (BlockReader.bytesRemaining() != *RecordRemaining)
1605f757f3fSDimitry Andric     return make_error<JITLinkError>("Incomplete CFI record at " +
1615f757f3fSDimitry Andric                                     formatv("{0:x16}", B.getAddress()));
162480093f4SDimitry Andric 
163480093f4SDimitry Andric   // Read the CIE delta for this record.
1645f757f3fSDimitry Andric   uint64_t CIEDeltaFieldOffset = BlockReader.getOffset();
165480093f4SDimitry Andric   uint32_t CIEDelta;
166480093f4SDimitry Andric   if (auto Err = BlockReader.readInteger(CIEDelta))
167480093f4SDimitry Andric     return Err;
168480093f4SDimitry Andric 
169480093f4SDimitry Andric   if (CIEDelta == 0) {
1705f757f3fSDimitry Andric     if (auto Err = processCIE(PC, B, CIEDeltaFieldOffset, BlockEdges))
171480093f4SDimitry Andric       return Err;
172480093f4SDimitry Andric   } else {
1735f757f3fSDimitry Andric     if (auto Err = processFDE(PC, B, CIEDeltaFieldOffset, CIEDelta, BlockEdges))
174480093f4SDimitry Andric       return Err;
175480093f4SDimitry Andric   }
176480093f4SDimitry Andric 
177480093f4SDimitry Andric   return Error::success();
178480093f4SDimitry Andric }
179480093f4SDimitry Andric 
processCIE(ParseContext & PC,Block & B,size_t CIEDeltaFieldOffset,const BlockEdgesInfo & BlockEdges)180480093f4SDimitry Andric Error EHFrameEdgeFixer::processCIE(ParseContext &PC, Block &B,
18181ad6265SDimitry Andric                                    size_t CIEDeltaFieldOffset,
1825f757f3fSDimitry Andric                                    const BlockEdgesInfo &BlockEdges) {
183480093f4SDimitry Andric 
184480093f4SDimitry Andric   LLVM_DEBUG(dbgs() << "    Record is CIE\n");
185480093f4SDimitry Andric 
186fe6060f1SDimitry Andric   BinaryStreamReader RecordReader(
1875f757f3fSDimitry Andric       StringRef(B.getContent().data(), B.getContent().size()),
188fe6060f1SDimitry Andric       PC.G.getEndianness());
189480093f4SDimitry Andric 
190480093f4SDimitry Andric   // Skip past the CIE delta field: we've already processed this far.
191480093f4SDimitry Andric   RecordReader.setOffset(CIEDeltaFieldOffset + 4);
192480093f4SDimitry Andric 
1935f757f3fSDimitry Andric   auto &CIESymbol = PC.G.addAnonymousSymbol(B, 0, B.getSize(), false, false);
194480093f4SDimitry Andric   CIEInformation CIEInfo(CIESymbol);
195480093f4SDimitry Andric 
196480093f4SDimitry Andric   uint8_t Version = 0;
197480093f4SDimitry Andric   if (auto Err = RecordReader.readInteger(Version))
198480093f4SDimitry Andric     return Err;
199480093f4SDimitry Andric 
200480093f4SDimitry Andric   if (Version != 0x01)
201480093f4SDimitry Andric     return make_error<JITLinkError>("Bad CIE version " + Twine(Version) +
202480093f4SDimitry Andric                                     " (should be 0x01) in eh-frame");
203480093f4SDimitry Andric 
204480093f4SDimitry Andric   auto AugInfo = parseAugmentationString(RecordReader);
205480093f4SDimitry Andric   if (!AugInfo)
206480093f4SDimitry Andric     return AugInfo.takeError();
207480093f4SDimitry Andric 
208480093f4SDimitry Andric   // Skip the EH Data field if present.
209480093f4SDimitry Andric   if (AugInfo->EHDataFieldPresent)
210480093f4SDimitry Andric     if (auto Err = RecordReader.skip(PC.G.getPointerSize()))
211480093f4SDimitry Andric       return Err;
212480093f4SDimitry Andric 
213349cc55cSDimitry Andric   // Read and validate the code alignment factor.
214480093f4SDimitry Andric   {
215480093f4SDimitry Andric     uint64_t CodeAlignmentFactor = 0;
216480093f4SDimitry Andric     if (auto Err = RecordReader.readULEB128(CodeAlignmentFactor))
217480093f4SDimitry Andric       return Err;
218480093f4SDimitry Andric   }
219480093f4SDimitry Andric 
220349cc55cSDimitry Andric   // Read and validate the data alignment factor.
221480093f4SDimitry Andric   {
222480093f4SDimitry Andric     int64_t DataAlignmentFactor = 0;
223480093f4SDimitry Andric     if (auto Err = RecordReader.readSLEB128(DataAlignmentFactor))
224480093f4SDimitry Andric       return Err;
225480093f4SDimitry Andric   }
226480093f4SDimitry Andric 
227480093f4SDimitry Andric   // Skip the return address register field.
228480093f4SDimitry Andric   if (auto Err = RecordReader.skip(1))
229480093f4SDimitry Andric     return Err;
230480093f4SDimitry Andric 
23181ad6265SDimitry Andric   if (AugInfo->AugmentationDataPresent) {
23281ad6265SDimitry Andric 
23381ad6265SDimitry Andric     CIEInfo.AugmentationDataPresent = true;
23481ad6265SDimitry Andric 
235480093f4SDimitry Andric     uint64_t AugmentationDataLength = 0;
236480093f4SDimitry Andric     if (auto Err = RecordReader.readULEB128(AugmentationDataLength))
237480093f4SDimitry Andric       return Err;
238480093f4SDimitry Andric 
239480093f4SDimitry Andric     uint32_t AugmentationDataStartOffset = RecordReader.getOffset();
240480093f4SDimitry Andric 
241480093f4SDimitry Andric     uint8_t *NextField = &AugInfo->Fields[0];
242480093f4SDimitry Andric     while (uint8_t Field = *NextField++) {
243480093f4SDimitry Andric       switch (Field) {
24481ad6265SDimitry Andric       case 'L':
24581ad6265SDimitry Andric         CIEInfo.LSDAPresent = true;
24681ad6265SDimitry Andric         if (auto PE = readPointerEncoding(RecordReader, B, "LSDA"))
24781ad6265SDimitry Andric           CIEInfo.LSDAEncoding = *PE;
24881ad6265SDimitry Andric         else
24981ad6265SDimitry Andric           return PE.takeError();
250480093f4SDimitry Andric         break;
251480093f4SDimitry Andric       case 'P': {
25281ad6265SDimitry Andric         auto PersonalityPointerEncoding =
25381ad6265SDimitry Andric             readPointerEncoding(RecordReader, B, "personality");
25481ad6265SDimitry Andric         if (!PersonalityPointerEncoding)
25581ad6265SDimitry Andric           return PersonalityPointerEncoding.takeError();
25681ad6265SDimitry Andric         if (auto Err =
25781ad6265SDimitry Andric                 getOrCreateEncodedPointerEdge(
25881ad6265SDimitry Andric                     PC, BlockEdges, *PersonalityPointerEncoding, RecordReader,
2595f757f3fSDimitry Andric                     B, RecordReader.getOffset(), "personality")
26081ad6265SDimitry Andric                     .takeError())
261480093f4SDimitry Andric           return Err;
262480093f4SDimitry Andric         break;
263480093f4SDimitry Andric       }
26481ad6265SDimitry Andric       case 'R':
26581ad6265SDimitry Andric         if (auto PE = readPointerEncoding(RecordReader, B, "address")) {
26681ad6265SDimitry Andric           CIEInfo.AddressEncoding = *PE;
26781ad6265SDimitry Andric           if (CIEInfo.AddressEncoding == dwarf::DW_EH_PE_omit)
268480093f4SDimitry Andric             return make_error<JITLinkError>(
26981ad6265SDimitry Andric                 "Invalid address encoding DW_EH_PE_omit in CIE at " +
2705f757f3fSDimitry Andric                 formatv("{0:x}", B.getAddress().getValue()));
27181ad6265SDimitry Andric         } else
27281ad6265SDimitry Andric           return PE.takeError();
273480093f4SDimitry Andric         break;
274480093f4SDimitry Andric       default:
275480093f4SDimitry Andric         llvm_unreachable("Invalid augmentation string field");
276480093f4SDimitry Andric       }
277480093f4SDimitry Andric     }
278480093f4SDimitry Andric 
279480093f4SDimitry Andric     if (RecordReader.getOffset() - AugmentationDataStartOffset >
280480093f4SDimitry Andric         AugmentationDataLength)
281480093f4SDimitry Andric       return make_error<JITLinkError>("Read past the end of the augmentation "
282480093f4SDimitry Andric                                       "data while parsing fields");
28381ad6265SDimitry Andric   }
284480093f4SDimitry Andric 
285480093f4SDimitry Andric   assert(!PC.CIEInfos.count(CIESymbol.getAddress()) &&
286480093f4SDimitry Andric          "Multiple CIEs recorded at the same address?");
287480093f4SDimitry Andric   PC.CIEInfos[CIESymbol.getAddress()] = std::move(CIEInfo);
288480093f4SDimitry Andric 
289480093f4SDimitry Andric   return Error::success();
290480093f4SDimitry Andric }
291480093f4SDimitry Andric 
processFDE(ParseContext & PC,Block & B,size_t CIEDeltaFieldOffset,uint32_t CIEDelta,const BlockEdgesInfo & BlockEdges)292480093f4SDimitry Andric Error EHFrameEdgeFixer::processFDE(ParseContext &PC, Block &B,
293480093f4SDimitry Andric                                    size_t CIEDeltaFieldOffset,
294480093f4SDimitry Andric                                    uint32_t CIEDelta,
2955f757f3fSDimitry Andric                                    const BlockEdgesInfo &BlockEdges) {
296480093f4SDimitry Andric   LLVM_DEBUG(dbgs() << "    Record is FDE\n");
297480093f4SDimitry Andric 
2985f757f3fSDimitry Andric   orc::ExecutorAddr RecordAddress = B.getAddress();
299480093f4SDimitry Andric 
300fe6060f1SDimitry Andric   BinaryStreamReader RecordReader(
3015f757f3fSDimitry Andric       StringRef(B.getContent().data(), B.getContent().size()),
302fe6060f1SDimitry Andric       PC.G.getEndianness());
303480093f4SDimitry Andric 
304480093f4SDimitry Andric   // Skip past the CIE delta field: we've already read this far.
305480093f4SDimitry Andric   RecordReader.setOffset(CIEDeltaFieldOffset + 4);
306480093f4SDimitry Andric 
3075f757f3fSDimitry Andric   auto &FDESymbol = PC.G.addAnonymousSymbol(B, 0, B.getSize(), false, false);
308480093f4SDimitry Andric 
309480093f4SDimitry Andric   CIEInformation *CIEInfo = nullptr;
310480093f4SDimitry Andric 
311480093f4SDimitry Andric   {
312480093f4SDimitry Andric     // Process the CIE pointer field.
3135f757f3fSDimitry Andric     if (BlockEdges.Multiple.contains(CIEDeltaFieldOffset))
3145f757f3fSDimitry Andric       return make_error<JITLinkError>(
3155f757f3fSDimitry Andric           "CIE pointer field already has multiple edges at " +
3165f757f3fSDimitry Andric           formatv("{0:x16}", RecordAddress + CIEDeltaFieldOffset));
3175f757f3fSDimitry Andric 
3185f757f3fSDimitry Andric     auto CIEEdgeItr = BlockEdges.TargetMap.find(CIEDeltaFieldOffset);
3195f757f3fSDimitry Andric 
32004eeddc0SDimitry Andric     orc::ExecutorAddr CIEAddress =
32104eeddc0SDimitry Andric         RecordAddress + orc::ExecutorAddrDiff(CIEDeltaFieldOffset) -
32204eeddc0SDimitry Andric         orc::ExecutorAddrDiff(CIEDelta);
3235f757f3fSDimitry Andric     if (CIEEdgeItr == BlockEdges.TargetMap.end()) {
324480093f4SDimitry Andric       LLVM_DEBUG({
325480093f4SDimitry Andric         dbgs() << "        Adding edge at "
32681ad6265SDimitry Andric                << (RecordAddress + CIEDeltaFieldOffset)
32781ad6265SDimitry Andric                << " to CIE at: " << CIEAddress << "\n";
328480093f4SDimitry Andric       });
329480093f4SDimitry Andric       if (auto CIEInfoOrErr = PC.findCIEInfo(CIEAddress))
330480093f4SDimitry Andric         CIEInfo = *CIEInfoOrErr;
331480093f4SDimitry Andric       else
332480093f4SDimitry Andric         return CIEInfoOrErr.takeError();
333480093f4SDimitry Andric       assert(CIEInfo->CIESymbol && "CIEInfo has no CIE symbol set");
3345f757f3fSDimitry Andric       B.addEdge(NegDelta32, CIEDeltaFieldOffset, *CIEInfo->CIESymbol, 0);
335480093f4SDimitry Andric     } else {
336480093f4SDimitry Andric       LLVM_DEBUG({
337480093f4SDimitry Andric         dbgs() << "        Already has edge at "
33881ad6265SDimitry Andric                << (RecordAddress + CIEDeltaFieldOffset) << " to CIE at "
33981ad6265SDimitry Andric                << CIEAddress << "\n";
340480093f4SDimitry Andric       });
341480093f4SDimitry Andric       auto &EI = CIEEdgeItr->second;
342480093f4SDimitry Andric       if (EI.Addend)
343480093f4SDimitry Andric         return make_error<JITLinkError>(
344480093f4SDimitry Andric             "CIE edge at " +
345480093f4SDimitry Andric             formatv("{0:x16}", RecordAddress + CIEDeltaFieldOffset) +
346480093f4SDimitry Andric             " has non-zero addend");
347480093f4SDimitry Andric       if (auto CIEInfoOrErr = PC.findCIEInfo(EI.Target->getAddress()))
348480093f4SDimitry Andric         CIEInfo = *CIEInfoOrErr;
349480093f4SDimitry Andric       else
350480093f4SDimitry Andric         return CIEInfoOrErr.takeError();
351480093f4SDimitry Andric     }
352480093f4SDimitry Andric   }
353480093f4SDimitry Andric 
354480093f4SDimitry Andric   // Process the PC-Begin field.
355480093f4SDimitry Andric   LLVM_DEBUG({
35681ad6265SDimitry Andric     dbgs() << "      Processing PC-begin at "
35781ad6265SDimitry Andric            << (RecordAddress + RecordReader.getOffset()) << "\n";
358480093f4SDimitry Andric   });
35981ad6265SDimitry Andric   if (auto PCBegin = getOrCreateEncodedPointerEdge(
36081ad6265SDimitry Andric           PC, BlockEdges, CIEInfo->AddressEncoding, RecordReader, B,
36181ad6265SDimitry Andric           RecordReader.getOffset(), "PC begin")) {
36281ad6265SDimitry Andric     assert(*PCBegin && "PC-begin symbol not set");
363bdd1243dSDimitry Andric     if ((*PCBegin)->isDefined()) {
364480093f4SDimitry Andric       // Add a keep-alive edge from the FDE target to the FDE to ensure that the
365480093f4SDimitry Andric       // FDE is kept alive if its target is.
366e8d8bef9SDimitry Andric       LLVM_DEBUG({
367e8d8bef9SDimitry Andric         dbgs() << "      Adding keep-alive edge from target at "
36881ad6265SDimitry Andric                << (*PCBegin)->getBlock().getAddress() << " to FDE at "
36981ad6265SDimitry Andric                << RecordAddress << "\n";
370e8d8bef9SDimitry Andric       });
37181ad6265SDimitry Andric       (*PCBegin)->getBlock().addEdge(Edge::KeepAlive, 0, FDESymbol, 0);
372bdd1243dSDimitry Andric     } else {
373bdd1243dSDimitry Andric       LLVM_DEBUG({
374bdd1243dSDimitry Andric         dbgs() << "      WARNING: Not adding keep-alive edge to FDE at "
375bdd1243dSDimitry Andric                << RecordAddress << ", which points to "
376bdd1243dSDimitry Andric                << ((*PCBegin)->isExternal() ? "external" : "absolute")
377bdd1243dSDimitry Andric                << " symbol \"" << (*PCBegin)->getName()
378bdd1243dSDimitry Andric                << "\" -- FDE must be kept alive manually or it will be "
379bdd1243dSDimitry Andric                << "dead stripped.\n";
380bdd1243dSDimitry Andric       });
381bdd1243dSDimitry Andric     }
38281ad6265SDimitry Andric   } else
38381ad6265SDimitry Andric     return PCBegin.takeError();
384480093f4SDimitry Andric 
385480093f4SDimitry Andric   // Skip over the PC range size field.
38681ad6265SDimitry Andric   if (auto Err = skipEncodedPointer(CIEInfo->AddressEncoding, RecordReader))
387480093f4SDimitry Andric     return Err;
388480093f4SDimitry Andric 
38981ad6265SDimitry Andric   if (CIEInfo->AugmentationDataPresent) {
390480093f4SDimitry Andric     uint64_t AugmentationDataSize;
391480093f4SDimitry Andric     if (auto Err = RecordReader.readULEB128(AugmentationDataSize))
392480093f4SDimitry Andric       return Err;
393480093f4SDimitry Andric 
39481ad6265SDimitry Andric     if (CIEInfo->LSDAPresent)
39581ad6265SDimitry Andric       if (auto Err = getOrCreateEncodedPointerEdge(
39681ad6265SDimitry Andric                          PC, BlockEdges, CIEInfo->LSDAEncoding, RecordReader, B,
39781ad6265SDimitry Andric                          RecordReader.getOffset(), "LSDA")
39881ad6265SDimitry Andric                          .takeError())
399480093f4SDimitry Andric         return Err;
400480093f4SDimitry Andric   } else {
401480093f4SDimitry Andric     LLVM_DEBUG(dbgs() << "      Record does not have LSDA field.\n");
402480093f4SDimitry Andric   }
403480093f4SDimitry Andric 
404480093f4SDimitry Andric   return Error::success();
405480093f4SDimitry Andric }
406480093f4SDimitry Andric 
407480093f4SDimitry Andric Expected<EHFrameEdgeFixer::AugmentationInfo>
parseAugmentationString(BinaryStreamReader & RecordReader)408480093f4SDimitry Andric EHFrameEdgeFixer::parseAugmentationString(BinaryStreamReader &RecordReader) {
4090b57cec5SDimitry Andric   AugmentationInfo AugInfo;
4100b57cec5SDimitry Andric   uint8_t NextChar;
4110b57cec5SDimitry Andric   uint8_t *NextField = &AugInfo.Fields[0];
4120b57cec5SDimitry Andric 
413480093f4SDimitry Andric   if (auto Err = RecordReader.readInteger(NextChar))
4140b57cec5SDimitry Andric     return std::move(Err);
4150b57cec5SDimitry Andric 
4160b57cec5SDimitry Andric   while (NextChar != 0) {
4170b57cec5SDimitry Andric     switch (NextChar) {
4180b57cec5SDimitry Andric     case 'z':
4190b57cec5SDimitry Andric       AugInfo.AugmentationDataPresent = true;
4200b57cec5SDimitry Andric       break;
4210b57cec5SDimitry Andric     case 'e':
422480093f4SDimitry Andric       if (auto Err = RecordReader.readInteger(NextChar))
4230b57cec5SDimitry Andric         return std::move(Err);
4240b57cec5SDimitry Andric       if (NextChar != 'h')
4250b57cec5SDimitry Andric         return make_error<JITLinkError>("Unrecognized substring e" +
4260b57cec5SDimitry Andric                                         Twine(NextChar) +
4270b57cec5SDimitry Andric                                         " in augmentation string");
4280b57cec5SDimitry Andric       AugInfo.EHDataFieldPresent = true;
4290b57cec5SDimitry Andric       break;
4300b57cec5SDimitry Andric     case 'L':
4310b57cec5SDimitry Andric     case 'P':
4320b57cec5SDimitry Andric     case 'R':
4330b57cec5SDimitry Andric       *NextField++ = NextChar;
4340b57cec5SDimitry Andric       break;
4350b57cec5SDimitry Andric     default:
4360b57cec5SDimitry Andric       return make_error<JITLinkError>("Unrecognized character " +
4370b57cec5SDimitry Andric                                       Twine(NextChar) +
4380b57cec5SDimitry Andric                                       " in augmentation string");
4390b57cec5SDimitry Andric     }
4400b57cec5SDimitry Andric 
441480093f4SDimitry Andric     if (auto Err = RecordReader.readInteger(NextChar))
4420b57cec5SDimitry Andric       return std::move(Err);
4430b57cec5SDimitry Andric   }
4440b57cec5SDimitry Andric 
4450b57cec5SDimitry Andric   return std::move(AugInfo);
4460b57cec5SDimitry Andric }
4470b57cec5SDimitry Andric 
readPointerEncoding(BinaryStreamReader & R,Block & InBlock,const char * FieldName)44881ad6265SDimitry Andric Expected<uint8_t> EHFrameEdgeFixer::readPointerEncoding(BinaryStreamReader &R,
44981ad6265SDimitry Andric                                                         Block &InBlock,
45081ad6265SDimitry Andric                                                         const char *FieldName) {
451e8d8bef9SDimitry Andric   using namespace dwarf;
452e8d8bef9SDimitry Andric 
45381ad6265SDimitry Andric   uint8_t PointerEncoding;
45481ad6265SDimitry Andric   if (auto Err = R.readInteger(PointerEncoding))
45581ad6265SDimitry Andric     return std::move(Err);
456e8d8bef9SDimitry Andric 
45781ad6265SDimitry Andric   bool Supported = true;
458e8d8bef9SDimitry Andric   switch (PointerEncoding & 0xf) {
45981ad6265SDimitry Andric   case DW_EH_PE_uleb128:
46081ad6265SDimitry Andric   case DW_EH_PE_udata2:
46181ad6265SDimitry Andric   case DW_EH_PE_sleb128:
46281ad6265SDimitry Andric   case DW_EH_PE_sdata2:
46381ad6265SDimitry Andric     Supported = false;
46481ad6265SDimitry Andric     break;
465e8d8bef9SDimitry Andric   }
46681ad6265SDimitry Andric   if (Supported) {
46781ad6265SDimitry Andric     switch (PointerEncoding & 0x70) {
46881ad6265SDimitry Andric     case DW_EH_PE_textrel:
46981ad6265SDimitry Andric     case DW_EH_PE_datarel:
47081ad6265SDimitry Andric     case DW_EH_PE_funcrel:
47181ad6265SDimitry Andric     case DW_EH_PE_aligned:
47281ad6265SDimitry Andric       Supported = false;
47381ad6265SDimitry Andric       break;
474e8d8bef9SDimitry Andric     }
475e8d8bef9SDimitry Andric   }
476e8d8bef9SDimitry Andric 
47781ad6265SDimitry Andric   if (Supported)
47881ad6265SDimitry Andric     return PointerEncoding;
47981ad6265SDimitry Andric 
48081ad6265SDimitry Andric   return make_error<JITLinkError>("Unsupported pointer encoding " +
48181ad6265SDimitry Andric                                   formatv("{0:x2}", PointerEncoding) + " for " +
48281ad6265SDimitry Andric                                   FieldName + "in CFI record at " +
48381ad6265SDimitry Andric                                   formatv("{0:x16}", InBlock.getAddress()));
48481ad6265SDimitry Andric }
48581ad6265SDimitry Andric 
skipEncodedPointer(uint8_t PointerEncoding,BinaryStreamReader & RecordReader)48681ad6265SDimitry Andric Error EHFrameEdgeFixer::skipEncodedPointer(uint8_t PointerEncoding,
487480093f4SDimitry Andric                                            BinaryStreamReader &RecordReader) {
488e8d8bef9SDimitry Andric   using namespace dwarf;
489e8d8bef9SDimitry Andric 
49081ad6265SDimitry Andric   // Switch absptr to corresponding udata encoding.
49181ad6265SDimitry Andric   if ((PointerEncoding & 0xf) == DW_EH_PE_absptr)
49281ad6265SDimitry Andric     PointerEncoding |= (PointerSize == 8) ? DW_EH_PE_udata8 : DW_EH_PE_udata4;
493e8d8bef9SDimitry Andric 
49481ad6265SDimitry Andric   switch (PointerEncoding & 0xf) {
49581ad6265SDimitry Andric   case DW_EH_PE_udata4:
49681ad6265SDimitry Andric   case DW_EH_PE_sdata4:
49781ad6265SDimitry Andric     if (auto Err = RecordReader.skip(4))
49881ad6265SDimitry Andric       return Err;
49981ad6265SDimitry Andric     break;
50081ad6265SDimitry Andric   case DW_EH_PE_udata8:
50181ad6265SDimitry Andric   case DW_EH_PE_sdata8:
50281ad6265SDimitry Andric     if (auto Err = RecordReader.skip(8))
50381ad6265SDimitry Andric       return Err;
50481ad6265SDimitry Andric     break;
50581ad6265SDimitry Andric   default:
50681ad6265SDimitry Andric     llvm_unreachable("Unrecognized encoding");
50781ad6265SDimitry Andric   }
50881ad6265SDimitry Andric   return Error::success();
50981ad6265SDimitry Andric }
51081ad6265SDimitry Andric 
getOrCreateEncodedPointerEdge(ParseContext & PC,const BlockEdgesInfo & BlockEdges,uint8_t PointerEncoding,BinaryStreamReader & RecordReader,Block & BlockToFix,size_t PointerFieldOffset,const char * FieldName)51181ad6265SDimitry Andric Expected<Symbol *> EHFrameEdgeFixer::getOrCreateEncodedPointerEdge(
5125f757f3fSDimitry Andric     ParseContext &PC, const BlockEdgesInfo &BlockEdges, uint8_t PointerEncoding,
51381ad6265SDimitry Andric     BinaryStreamReader &RecordReader, Block &BlockToFix,
51481ad6265SDimitry Andric     size_t PointerFieldOffset, const char *FieldName) {
51581ad6265SDimitry Andric   using namespace dwarf;
51681ad6265SDimitry Andric 
51781ad6265SDimitry Andric   if (PointerEncoding == DW_EH_PE_omit)
51881ad6265SDimitry Andric     return nullptr;
51981ad6265SDimitry Andric 
52081ad6265SDimitry Andric   // If there's already an edge here then just skip the encoded pointer and
52181ad6265SDimitry Andric   // return the edge's target.
52281ad6265SDimitry Andric   {
5235f757f3fSDimitry Andric     auto EdgeI = BlockEdges.TargetMap.find(PointerFieldOffset);
5245f757f3fSDimitry Andric     if (EdgeI != BlockEdges.TargetMap.end()) {
52581ad6265SDimitry Andric       LLVM_DEBUG({
52681ad6265SDimitry Andric         dbgs() << "      Existing edge at "
52781ad6265SDimitry Andric                << (BlockToFix.getAddress() + PointerFieldOffset) << " to "
52881ad6265SDimitry Andric                << FieldName << " at " << EdgeI->second.Target->getAddress();
52981ad6265SDimitry Andric         if (EdgeI->second.Target->hasName())
53081ad6265SDimitry Andric           dbgs() << " (" << EdgeI->second.Target->getName() << ")";
53181ad6265SDimitry Andric         dbgs() << "\n";
53281ad6265SDimitry Andric       });
53381ad6265SDimitry Andric       if (auto Err = skipEncodedPointer(PointerEncoding, RecordReader))
53481ad6265SDimitry Andric         return std::move(Err);
53581ad6265SDimitry Andric       return EdgeI->second.Target;
53681ad6265SDimitry Andric     }
5375f757f3fSDimitry Andric 
5385f757f3fSDimitry Andric     if (BlockEdges.Multiple.contains(PointerFieldOffset))
5395f757f3fSDimitry Andric       return make_error<JITLinkError>("Multiple relocations at offset " +
5405f757f3fSDimitry Andric                                       formatv("{0:x16}", PointerFieldOffset));
54181ad6265SDimitry Andric   }
54281ad6265SDimitry Andric 
54381ad6265SDimitry Andric   // Switch absptr to corresponding udata encoding.
54481ad6265SDimitry Andric   if ((PointerEncoding & 0xf) == DW_EH_PE_absptr)
54581ad6265SDimitry Andric     PointerEncoding |= (PointerSize == 8) ? DW_EH_PE_udata8 : DW_EH_PE_udata4;
54681ad6265SDimitry Andric 
54781ad6265SDimitry Andric   // We need to create an edge. Start by reading the field value.
54881ad6265SDimitry Andric   uint64_t FieldValue;
54981ad6265SDimitry Andric   bool Is64Bit = false;
55081ad6265SDimitry Andric   switch (PointerEncoding & 0xf) {
551e8d8bef9SDimitry Andric   case DW_EH_PE_udata4: {
552e8d8bef9SDimitry Andric     uint32_t Val;
553e8d8bef9SDimitry Andric     if (auto Err = RecordReader.readInteger(Val))
5540b57cec5SDimitry Andric       return std::move(Err);
55581ad6265SDimitry Andric     FieldValue = Val;
556e8d8bef9SDimitry Andric     break;
557e8d8bef9SDimitry Andric   }
558e8d8bef9SDimitry Andric   case DW_EH_PE_sdata4: {
55981ad6265SDimitry Andric     uint32_t Val;
560e8d8bef9SDimitry Andric     if (auto Err = RecordReader.readInteger(Val))
561e8d8bef9SDimitry Andric       return std::move(Err);
56281ad6265SDimitry Andric     FieldValue = Val;
563e8d8bef9SDimitry Andric     break;
564e8d8bef9SDimitry Andric   }
56581ad6265SDimitry Andric   case DW_EH_PE_udata8:
56681ad6265SDimitry Andric   case DW_EH_PE_sdata8:
56781ad6265SDimitry Andric     Is64Bit = true;
56881ad6265SDimitry Andric     if (auto Err = RecordReader.readInteger(FieldValue))
569e8d8bef9SDimitry Andric       return std::move(Err);
570e8d8bef9SDimitry Andric     break;
57181ad6265SDimitry Andric   default:
57281ad6265SDimitry Andric     llvm_unreachable("Unsupported encoding");
573e8d8bef9SDimitry Andric   }
574e8d8bef9SDimitry Andric 
57581ad6265SDimitry Andric   // Find the edge target and edge kind to use.
57681ad6265SDimitry Andric   orc::ExecutorAddr Target;
57781ad6265SDimitry Andric   Edge::Kind PtrEdgeKind = Edge::Invalid;
57881ad6265SDimitry Andric   if ((PointerEncoding & 0x70) == DW_EH_PE_pcrel) {
57981ad6265SDimitry Andric     Target = BlockToFix.getAddress() + PointerFieldOffset;
58081ad6265SDimitry Andric     PtrEdgeKind = Is64Bit ? Delta64 : Delta32;
58181ad6265SDimitry Andric   } else
58281ad6265SDimitry Andric     PtrEdgeKind = Is64Bit ? Pointer64 : Pointer32;
58381ad6265SDimitry Andric   Target += FieldValue;
584e8d8bef9SDimitry Andric 
58581ad6265SDimitry Andric   // Find or create a symbol to point the edge at.
58681ad6265SDimitry Andric   auto TargetSym = getOrCreateSymbol(PC, Target);
58781ad6265SDimitry Andric   if (!TargetSym)
58881ad6265SDimitry Andric     return TargetSym.takeError();
58981ad6265SDimitry Andric   BlockToFix.addEdge(PtrEdgeKind, PointerFieldOffset, *TargetSym, 0);
59081ad6265SDimitry Andric 
59181ad6265SDimitry Andric   LLVM_DEBUG({
59281ad6265SDimitry Andric     dbgs() << "      Adding edge at "
59381ad6265SDimitry Andric            << (BlockToFix.getAddress() + PointerFieldOffset) << " to "
59481ad6265SDimitry Andric            << FieldName << " at " << TargetSym->getAddress();
59581ad6265SDimitry Andric     if (TargetSym->hasName())
59681ad6265SDimitry Andric       dbgs() << " (" << TargetSym->getName() << ")";
59781ad6265SDimitry Andric     dbgs() << "\n";
59881ad6265SDimitry Andric   });
59981ad6265SDimitry Andric 
60081ad6265SDimitry Andric   return &*TargetSym;
6010b57cec5SDimitry Andric }
6020b57cec5SDimitry Andric 
getOrCreateSymbol(ParseContext & PC,orc::ExecutorAddr Addr)603480093f4SDimitry Andric Expected<Symbol &> EHFrameEdgeFixer::getOrCreateSymbol(ParseContext &PC,
60404eeddc0SDimitry Andric                                                        orc::ExecutorAddr Addr) {
60581ad6265SDimitry Andric   // See whether we have a canonical symbol for the given address already.
60681ad6265SDimitry Andric   auto CanonicalSymI = PC.AddrToSym.find(Addr);
60781ad6265SDimitry Andric   if (CanonicalSymI != PC.AddrToSym.end())
60881ad6265SDimitry Andric     return *CanonicalSymI->second;
6090b57cec5SDimitry Andric 
610480093f4SDimitry Andric   // Otherwise search for a block covering the address and create a new symbol.
611480093f4SDimitry Andric   auto *B = PC.AddrToBlock.getBlockCovering(Addr);
612480093f4SDimitry Andric   if (!B)
613480093f4SDimitry Andric     return make_error<JITLinkError>("No symbol or block covering address " +
614480093f4SDimitry Andric                                     formatv("{0:x16}", Addr));
6150b57cec5SDimitry Andric 
61681ad6265SDimitry Andric   auto &S =
61781ad6265SDimitry Andric       PC.G.addAnonymousSymbol(*B, Addr - B->getAddress(), 0, false, false);
61881ad6265SDimitry Andric   PC.AddrToSym[S.getAddress()] = &S;
61981ad6265SDimitry Andric   return S;
6200b57cec5SDimitry Andric }
6210b57cec5SDimitry Andric 
622fe6060f1SDimitry Andric char EHFrameNullTerminator::NullTerminatorBlockContent[4] = {0, 0, 0, 0};
623fe6060f1SDimitry Andric 
EHFrameNullTerminator(StringRef EHFrameSectionName)624fe6060f1SDimitry Andric EHFrameNullTerminator::EHFrameNullTerminator(StringRef EHFrameSectionName)
625fe6060f1SDimitry Andric     : EHFrameSectionName(EHFrameSectionName) {}
626fe6060f1SDimitry Andric 
operator ()(LinkGraph & G)627fe6060f1SDimitry Andric Error EHFrameNullTerminator::operator()(LinkGraph &G) {
628fe6060f1SDimitry Andric   auto *EHFrame = G.findSectionByName(EHFrameSectionName);
629fe6060f1SDimitry Andric 
630fe6060f1SDimitry Andric   if (!EHFrame)
631fe6060f1SDimitry Andric     return Error::success();
632fe6060f1SDimitry Andric 
633fe6060f1SDimitry Andric   LLVM_DEBUG({
634fe6060f1SDimitry Andric     dbgs() << "EHFrameNullTerminator adding null terminator to "
635fe6060f1SDimitry Andric            << EHFrameSectionName << "\n";
636fe6060f1SDimitry Andric   });
637fe6060f1SDimitry Andric 
63804eeddc0SDimitry Andric   auto &NullTerminatorBlock =
63904eeddc0SDimitry Andric       G.createContentBlock(*EHFrame, NullTerminatorBlockContent,
64004eeddc0SDimitry Andric                            orc::ExecutorAddr(~uint64_t(4)), 1, 0);
641fe6060f1SDimitry Andric   G.addAnonymousSymbol(NullTerminatorBlock, 0, 4, false, true);
642fe6060f1SDimitry Andric   return Error::success();
643fe6060f1SDimitry Andric }
644fe6060f1SDimitry Andric 
64581ad6265SDimitry Andric EHFrameRegistrar::~EHFrameRegistrar() = default;
6460b57cec5SDimitry Andric 
registerEHFrames(orc::ExecutorAddrRange EHFrameSection)647e8d8bef9SDimitry Andric Error InProcessEHFrameRegistrar::registerEHFrames(
64804eeddc0SDimitry Andric     orc::ExecutorAddrRange EHFrameSection) {
64904eeddc0SDimitry Andric   return orc::registerEHFrameSection(EHFrameSection.Start.toPtr<void *>(),
65004eeddc0SDimitry Andric                                      EHFrameSection.size());
6510b57cec5SDimitry Andric }
6520b57cec5SDimitry Andric 
deregisterEHFrames(orc::ExecutorAddrRange EHFrameSection)653e8d8bef9SDimitry Andric Error InProcessEHFrameRegistrar::deregisterEHFrames(
65404eeddc0SDimitry Andric     orc::ExecutorAddrRange EHFrameSection) {
65504eeddc0SDimitry Andric   return orc::deregisterEHFrameSection(EHFrameSection.Start.toPtr<void *>(),
65604eeddc0SDimitry Andric                                        EHFrameSection.size());
657e8d8bef9SDimitry Andric }
6580b57cec5SDimitry Andric 
FromEdgeScan(Block & B)659bdd1243dSDimitry Andric EHFrameCFIBlockInspector EHFrameCFIBlockInspector::FromEdgeScan(Block &B) {
660bdd1243dSDimitry Andric   if (B.edges_empty())
661bdd1243dSDimitry Andric     return EHFrameCFIBlockInspector(nullptr);
662bdd1243dSDimitry Andric   if (B.edges_size() == 1)
663bdd1243dSDimitry Andric     return EHFrameCFIBlockInspector(&*B.edges().begin());
664bdd1243dSDimitry Andric   SmallVector<Edge *, 3> Es;
665bdd1243dSDimitry Andric   for (auto &E : B.edges())
666bdd1243dSDimitry Andric     Es.push_back(&E);
667bdd1243dSDimitry Andric   assert(Es.size() >= 2 && Es.size() <= 3 && "Unexpected number of edges");
668bdd1243dSDimitry Andric   llvm::sort(Es, [](const Edge *LHS, const Edge *RHS) {
669bdd1243dSDimitry Andric     return LHS->getOffset() < RHS->getOffset();
670bdd1243dSDimitry Andric   });
671bdd1243dSDimitry Andric   return EHFrameCFIBlockInspector(*Es[0], *Es[1],
672bdd1243dSDimitry Andric                                   Es.size() == 3 ? Es[2] : nullptr);
673bdd1243dSDimitry Andric   return EHFrameCFIBlockInspector(nullptr);
674bdd1243dSDimitry Andric }
675bdd1243dSDimitry Andric 
EHFrameCFIBlockInspector(Edge * PersonalityEdge)676bdd1243dSDimitry Andric EHFrameCFIBlockInspector::EHFrameCFIBlockInspector(Edge *PersonalityEdge)
677bdd1243dSDimitry Andric     : PersonalityEdge(PersonalityEdge) {}
678bdd1243dSDimitry Andric 
EHFrameCFIBlockInspector(Edge & CIEEdge,Edge & PCBeginEdge,Edge * LSDAEdge)679bdd1243dSDimitry Andric EHFrameCFIBlockInspector::EHFrameCFIBlockInspector(Edge &CIEEdge,
680bdd1243dSDimitry Andric                                                    Edge &PCBeginEdge,
681bdd1243dSDimitry Andric                                                    Edge *LSDAEdge)
682bdd1243dSDimitry Andric     : CIEEdge(&CIEEdge), PCBeginEdge(&PCBeginEdge), LSDAEdge(LSDAEdge) {}
683bdd1243dSDimitry Andric 
6848bcb0991SDimitry Andric LinkGraphPassFunction
createEHFrameRecorderPass(const Triple & TT,StoreFrameRangeFunction StoreRangeAddress)6850b57cec5SDimitry Andric createEHFrameRecorderPass(const Triple &TT,
6868bcb0991SDimitry Andric                           StoreFrameRangeFunction StoreRangeAddress) {
6870b57cec5SDimitry Andric   const char *EHFrameSectionName = nullptr;
6880b57cec5SDimitry Andric   if (TT.getObjectFormat() == Triple::MachO)
689fe6060f1SDimitry Andric     EHFrameSectionName = "__TEXT,__eh_frame";
6900b57cec5SDimitry Andric   else
6910b57cec5SDimitry Andric     EHFrameSectionName = ".eh_frame";
6920b57cec5SDimitry Andric 
6938bcb0991SDimitry Andric   auto RecordEHFrame =
6948bcb0991SDimitry Andric       [EHFrameSectionName,
6958bcb0991SDimitry Andric        StoreFrameRange = std::move(StoreRangeAddress)](LinkGraph &G) -> Error {
6968bcb0991SDimitry Andric     // Search for a non-empty eh-frame and record the address of the first
6978bcb0991SDimitry Andric     // symbol in it.
69804eeddc0SDimitry Andric     orc::ExecutorAddr Addr;
6998bcb0991SDimitry Andric     size_t Size = 0;
7008bcb0991SDimitry Andric     if (auto *S = G.findSectionByName(EHFrameSectionName)) {
7018bcb0991SDimitry Andric       auto R = SectionRange(*S);
7028bcb0991SDimitry Andric       Addr = R.getStart();
7038bcb0991SDimitry Andric       Size = R.getSize();
7048bcb0991SDimitry Andric     }
70504eeddc0SDimitry Andric     if (!Addr && Size != 0)
706fe6060f1SDimitry Andric       return make_error<JITLinkError>(
707fe6060f1SDimitry Andric           StringRef(EHFrameSectionName) +
708fe6060f1SDimitry Andric           " section can not have zero address with non-zero size");
7098bcb0991SDimitry Andric     StoreFrameRange(Addr, Size);
7100b57cec5SDimitry Andric     return Error::success();
7110b57cec5SDimitry Andric   };
7120b57cec5SDimitry Andric 
7130b57cec5SDimitry Andric   return RecordEHFrame;
7140b57cec5SDimitry Andric }
7150b57cec5SDimitry Andric 
7160b57cec5SDimitry Andric } // end namespace jitlink
7170b57cec5SDimitry Andric } // end namespace llvm
718