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