1 //===-------- JITLink_EHFrameSupport.cpp - JITLink eh-frame utils ---------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 #include "EHFrameSupportImpl.h"
11 #include "llvm/BinaryFormat/Dwarf.h"
12 #include "llvm/Config/config.h"
13 #include "llvm/ExecutionEngine/JITLink/DWARFRecordSectionSplitter.h"
14 #include "llvm/ExecutionEngine/Orc/TargetProcess/RegisterEHFrames.h"
15 #include "llvm/Support/DynamicLibrary.h"
17 #define DEBUG_TYPE "jitlink"
22 EHFrameEdgeFixer::EHFrameEdgeFixer(StringRef EHFrameSectionName
,
23 unsigned PointerSize
, Edge::Kind Pointer32
,
24 Edge::Kind Pointer64
, Edge::Kind Delta32
,
25 Edge::Kind Delta64
, Edge::Kind NegDelta32
)
26 : EHFrameSectionName(EHFrameSectionName
), PointerSize(PointerSize
),
27 Pointer32(Pointer32
), Pointer64(Pointer64
), Delta32(Delta32
),
28 Delta64(Delta64
), NegDelta32(NegDelta32
) {}
30 Error
EHFrameEdgeFixer::operator()(LinkGraph
&G
) {
31 auto *EHFrame
= G
.findSectionByName(EHFrameSectionName
);
35 dbgs() << "EHFrameEdgeFixer: No " << EHFrameSectionName
36 << " section in \"" << G
.getName() << "\". Nothing to do.\n";
38 return Error::success();
41 // Check that we support the graph's pointer size.
42 if (G
.getPointerSize() != 4 && G
.getPointerSize() != 8)
43 return make_error
<JITLinkError
>(
44 "EHFrameEdgeFixer only supports 32 and 64 bit targets");
47 dbgs() << "EHFrameEdgeFixer: Processing " << EHFrameSectionName
<< " in \""
48 << G
.getName() << "\"...\n";
53 // Build a map of all blocks and symbols in the text sections. We will use
54 // these for finding / building edge targets when processing FDEs.
55 for (auto &Sec
: G
.sections()) {
56 // Just record the most-canonical symbol (for eh-frame purposes) at each
58 for (auto *Sym
: Sec
.symbols()) {
59 auto &CurSym
= PC
.AddrToSym
[Sym
->getAddress()];
60 if (!CurSym
|| (std::make_tuple(Sym
->getLinkage(), Sym
->getScope(),
61 !Sym
->hasName(), Sym
->getName()) <
62 std::make_tuple(CurSym
->getLinkage(), CurSym
->getScope(),
63 !CurSym
->hasName(), CurSym
->getName())))
66 if (auto Err
= PC
.AddrToBlock
.addBlocks(Sec
.blocks(),
67 BlockAddressMap::includeNonNull
))
71 // Sort eh-frame blocks into address order to ensure we visit CIEs before
73 std::vector
<Block
*> EHFrameBlocks
;
74 for (auto *B
: EHFrame
->blocks())
75 EHFrameBlocks
.push_back(B
);
76 llvm::sort(EHFrameBlocks
, [](const Block
*LHS
, const Block
*RHS
) {
77 return LHS
->getAddress() < RHS
->getAddress();
80 // Loop over the blocks in address order.
81 for (auto *B
: EHFrameBlocks
)
82 if (auto Err
= processBlock(PC
, *B
))
85 return Error::success();
88 static Expected
<size_t> readCFIRecordLength(const Block
&B
,
89 BinaryStreamReader
&R
) {
91 if (auto Err
= R
.readInteger(Length
))
92 return std::move(Err
);
94 // If Length < 0xffffffff then use the regular length field, otherwise
95 // read the extended length field.
96 if (Length
!= 0xffffffff)
99 uint64_t ExtendedLength
;
100 if (auto Err
= R
.readInteger(ExtendedLength
))
101 return std::move(Err
);
103 if (ExtendedLength
> std::numeric_limits
<size_t>::max())
104 return make_error
<JITLinkError
>(
105 "In CFI record at " +
106 formatv("{0:x}", B
.getAddress() + R
.getOffset() - 12) +
107 ", extended length of " + formatv("{0:x}", ExtendedLength
) +
108 " exceeds address-range max (" +
109 formatv("{0:x}", std::numeric_limits
<size_t>::max()));
111 return ExtendedLength
;
114 Error
EHFrameEdgeFixer::processBlock(ParseContext
&PC
, Block
&B
) {
116 LLVM_DEBUG(dbgs() << " Processing block at " << B
.getAddress() << "\n");
118 // eh-frame should not contain zero-fill blocks.
120 return make_error
<JITLinkError
>("Unexpected zero-fill block in " +
121 EHFrameSectionName
+ " section");
123 if (B
.getSize() == 0) {
124 LLVM_DEBUG(dbgs() << " Block is empty. Skipping.\n");
125 return Error::success();
128 // Find the offsets of any existing edges from this block.
129 BlockEdgesInfo BlockEdges
;
130 for (auto &E
: B
.edges())
131 if (E
.isRelocation()) {
132 // Check if we already saw more than one relocation at this offset.
133 if (BlockEdges
.Multiple
.contains(E
.getOffset()))
136 // Otherwise check if we previously had exactly one relocation at this
137 // offset. If so, we now have a second one and move it from the TargetMap
138 // into the Multiple set.
139 auto It
= BlockEdges
.TargetMap
.find(E
.getOffset());
140 if (It
!= BlockEdges
.TargetMap
.end()) {
141 BlockEdges
.TargetMap
.erase(It
);
142 BlockEdges
.Multiple
.insert(E
.getOffset());
144 BlockEdges
.TargetMap
[E
.getOffset()] = EdgeTarget(E
);
148 BinaryStreamReader
BlockReader(
149 StringRef(B
.getContent().data(), B
.getContent().size()),
150 PC
.G
.getEndianness());
152 // Get the record length.
153 Expected
<size_t> RecordRemaining
= readCFIRecordLength(B
, BlockReader
);
154 if (!RecordRemaining
)
155 return RecordRemaining
.takeError();
157 // We expect DWARFRecordSectionSplitter to split each CFI record into its own
159 if (BlockReader
.bytesRemaining() != *RecordRemaining
)
160 return make_error
<JITLinkError
>("Incomplete CFI record at " +
161 formatv("{0:x16}", B
.getAddress()));
163 // Read the CIE delta for this record.
164 uint64_t CIEDeltaFieldOffset
= BlockReader
.getOffset();
166 if (auto Err
= BlockReader
.readInteger(CIEDelta
))
170 if (auto Err
= processCIE(PC
, B
, CIEDeltaFieldOffset
, BlockEdges
))
173 if (auto Err
= processFDE(PC
, B
, CIEDeltaFieldOffset
, CIEDelta
, BlockEdges
))
177 return Error::success();
180 Error
EHFrameEdgeFixer::processCIE(ParseContext
&PC
, Block
&B
,
181 size_t CIEDeltaFieldOffset
,
182 const BlockEdgesInfo
&BlockEdges
) {
184 LLVM_DEBUG(dbgs() << " Record is CIE\n");
186 BinaryStreamReader
RecordReader(
187 StringRef(B
.getContent().data(), B
.getContent().size()),
188 PC
.G
.getEndianness());
190 // Skip past the CIE delta field: we've already processed this far.
191 RecordReader
.setOffset(CIEDeltaFieldOffset
+ 4);
193 auto &CIESymbol
= PC
.G
.addAnonymousSymbol(B
, 0, B
.getSize(), false, false);
194 CIEInformation
CIEInfo(CIESymbol
);
197 if (auto Err
= RecordReader
.readInteger(Version
))
201 return make_error
<JITLinkError
>("Bad CIE version " + Twine(Version
) +
202 " (should be 0x01) in eh-frame");
204 auto AugInfo
= parseAugmentationString(RecordReader
);
206 return AugInfo
.takeError();
208 // Skip the EH Data field if present.
209 if (AugInfo
->EHDataFieldPresent
)
210 if (auto Err
= RecordReader
.skip(PC
.G
.getPointerSize()))
213 // Read and validate the code alignment factor.
215 uint64_t CodeAlignmentFactor
= 0;
216 if (auto Err
= RecordReader
.readULEB128(CodeAlignmentFactor
))
220 // Read and validate the data alignment factor.
222 int64_t DataAlignmentFactor
= 0;
223 if (auto Err
= RecordReader
.readSLEB128(DataAlignmentFactor
))
227 // Skip the return address register field.
228 if (auto Err
= RecordReader
.skip(1))
231 if (AugInfo
->AugmentationDataPresent
) {
233 CIEInfo
.AugmentationDataPresent
= true;
235 uint64_t AugmentationDataLength
= 0;
236 if (auto Err
= RecordReader
.readULEB128(AugmentationDataLength
))
239 uint32_t AugmentationDataStartOffset
= RecordReader
.getOffset();
241 uint8_t *NextField
= &AugInfo
->Fields
[0];
242 while (uint8_t Field
= *NextField
++) {
245 CIEInfo
.LSDAPresent
= true;
246 if (auto PE
= readPointerEncoding(RecordReader
, B
, "LSDA"))
247 CIEInfo
.LSDAEncoding
= *PE
;
249 return PE
.takeError();
252 auto PersonalityPointerEncoding
=
253 readPointerEncoding(RecordReader
, B
, "personality");
254 if (!PersonalityPointerEncoding
)
255 return PersonalityPointerEncoding
.takeError();
257 getOrCreateEncodedPointerEdge(
258 PC
, BlockEdges
, *PersonalityPointerEncoding
, RecordReader
,
259 B
, RecordReader
.getOffset(), "personality")
265 if (auto PE
= readPointerEncoding(RecordReader
, B
, "address")) {
266 CIEInfo
.AddressEncoding
= *PE
;
267 if (CIEInfo
.AddressEncoding
== dwarf::DW_EH_PE_omit
)
268 return make_error
<JITLinkError
>(
269 "Invalid address encoding DW_EH_PE_omit in CIE at " +
270 formatv("{0:x}", B
.getAddress().getValue()));
272 return PE
.takeError();
275 llvm_unreachable("Invalid augmentation string field");
279 if (RecordReader
.getOffset() - AugmentationDataStartOffset
>
280 AugmentationDataLength
)
281 return make_error
<JITLinkError
>("Read past the end of the augmentation "
282 "data while parsing fields");
285 assert(!PC
.CIEInfos
.count(CIESymbol
.getAddress()) &&
286 "Multiple CIEs recorded at the same address?");
287 PC
.CIEInfos
[CIESymbol
.getAddress()] = std::move(CIEInfo
);
289 return Error::success();
292 Error
EHFrameEdgeFixer::processFDE(ParseContext
&PC
, Block
&B
,
293 size_t CIEDeltaFieldOffset
,
295 const BlockEdgesInfo
&BlockEdges
) {
296 LLVM_DEBUG(dbgs() << " Record is FDE\n");
298 orc::ExecutorAddr RecordAddress
= B
.getAddress();
300 BinaryStreamReader
RecordReader(
301 StringRef(B
.getContent().data(), B
.getContent().size()),
302 PC
.G
.getEndianness());
304 // Skip past the CIE delta field: we've already read this far.
305 RecordReader
.setOffset(CIEDeltaFieldOffset
+ 4);
307 auto &FDESymbol
= PC
.G
.addAnonymousSymbol(B
, 0, B
.getSize(), false, false);
309 CIEInformation
*CIEInfo
= nullptr;
312 // Process the CIE pointer field.
313 if (BlockEdges
.Multiple
.contains(CIEDeltaFieldOffset
))
314 return make_error
<JITLinkError
>(
315 "CIE pointer field already has multiple edges at " +
316 formatv("{0:x16}", RecordAddress
+ CIEDeltaFieldOffset
));
318 auto CIEEdgeItr
= BlockEdges
.TargetMap
.find(CIEDeltaFieldOffset
);
320 orc::ExecutorAddr CIEAddress
=
321 RecordAddress
+ orc::ExecutorAddrDiff(CIEDeltaFieldOffset
) -
322 orc::ExecutorAddrDiff(CIEDelta
);
323 if (CIEEdgeItr
== BlockEdges
.TargetMap
.end()) {
325 dbgs() << " Adding edge at "
326 << (RecordAddress
+ CIEDeltaFieldOffset
)
327 << " to CIE at: " << CIEAddress
<< "\n";
329 if (auto CIEInfoOrErr
= PC
.findCIEInfo(CIEAddress
))
330 CIEInfo
= *CIEInfoOrErr
;
332 return CIEInfoOrErr
.takeError();
333 assert(CIEInfo
->CIESymbol
&& "CIEInfo has no CIE symbol set");
334 B
.addEdge(NegDelta32
, CIEDeltaFieldOffset
, *CIEInfo
->CIESymbol
, 0);
337 dbgs() << " Already has edge at "
338 << (RecordAddress
+ CIEDeltaFieldOffset
) << " to CIE at "
339 << CIEAddress
<< "\n";
341 auto &EI
= CIEEdgeItr
->second
;
343 return make_error
<JITLinkError
>(
345 formatv("{0:x16}", RecordAddress
+ CIEDeltaFieldOffset
) +
346 " has non-zero addend");
347 if (auto CIEInfoOrErr
= PC
.findCIEInfo(EI
.Target
->getAddress()))
348 CIEInfo
= *CIEInfoOrErr
;
350 return CIEInfoOrErr
.takeError();
354 // Process the PC-Begin field.
356 dbgs() << " Processing PC-begin at "
357 << (RecordAddress
+ RecordReader
.getOffset()) << "\n";
359 if (auto PCBegin
= getOrCreateEncodedPointerEdge(
360 PC
, BlockEdges
, CIEInfo
->AddressEncoding
, RecordReader
, B
,
361 RecordReader
.getOffset(), "PC begin")) {
362 assert(*PCBegin
&& "PC-begin symbol not set");
363 if ((*PCBegin
)->isDefined()) {
364 // Add a keep-alive edge from the FDE target to the FDE to ensure that the
365 // FDE is kept alive if its target is.
367 dbgs() << " Adding keep-alive edge from target at "
368 << (*PCBegin
)->getBlock().getAddress() << " to FDE at "
369 << RecordAddress
<< "\n";
371 (*PCBegin
)->getBlock().addEdge(Edge::KeepAlive
, 0, FDESymbol
, 0);
374 dbgs() << " WARNING: Not adding keep-alive edge to FDE at "
375 << RecordAddress
<< ", which points to "
376 << ((*PCBegin
)->isExternal() ? "external" : "absolute")
377 << " symbol \"" << (*PCBegin
)->getName()
378 << "\" -- FDE must be kept alive manually or it will be "
379 << "dead stripped.\n";
383 return PCBegin
.takeError();
385 // Skip over the PC range size field.
386 if (auto Err
= skipEncodedPointer(CIEInfo
->AddressEncoding
, RecordReader
))
389 if (CIEInfo
->AugmentationDataPresent
) {
390 uint64_t AugmentationDataSize
;
391 if (auto Err
= RecordReader
.readULEB128(AugmentationDataSize
))
394 if (CIEInfo
->LSDAPresent
)
395 if (auto Err
= getOrCreateEncodedPointerEdge(
396 PC
, BlockEdges
, CIEInfo
->LSDAEncoding
, RecordReader
, B
,
397 RecordReader
.getOffset(), "LSDA")
401 LLVM_DEBUG(dbgs() << " Record does not have LSDA field.\n");
404 return Error::success();
407 Expected
<EHFrameEdgeFixer::AugmentationInfo
>
408 EHFrameEdgeFixer::parseAugmentationString(BinaryStreamReader
&RecordReader
) {
409 AugmentationInfo AugInfo
;
411 uint8_t *NextField
= &AugInfo
.Fields
[0];
413 if (auto Err
= RecordReader
.readInteger(NextChar
))
414 return std::move(Err
);
416 while (NextChar
!= 0) {
419 AugInfo
.AugmentationDataPresent
= true;
422 if (auto Err
= RecordReader
.readInteger(NextChar
))
423 return std::move(Err
);
425 return make_error
<JITLinkError
>("Unrecognized substring e" +
427 " in augmentation string");
428 AugInfo
.EHDataFieldPresent
= true;
433 *NextField
++ = NextChar
;
436 return make_error
<JITLinkError
>("Unrecognized character " +
438 " in augmentation string");
441 if (auto Err
= RecordReader
.readInteger(NextChar
))
442 return std::move(Err
);
445 return std::move(AugInfo
);
448 Expected
<uint8_t> EHFrameEdgeFixer::readPointerEncoding(BinaryStreamReader
&R
,
450 const char *FieldName
) {
451 using namespace dwarf
;
453 uint8_t PointerEncoding
;
454 if (auto Err
= R
.readInteger(PointerEncoding
))
455 return std::move(Err
);
457 bool Supported
= true;
458 switch (PointerEncoding
& 0xf) {
459 case DW_EH_PE_uleb128
:
460 case DW_EH_PE_udata2
:
461 case DW_EH_PE_sleb128
:
462 case DW_EH_PE_sdata2
:
467 switch (PointerEncoding
& 0x70) {
468 case DW_EH_PE_textrel
:
469 case DW_EH_PE_datarel
:
470 case DW_EH_PE_funcrel
:
471 case DW_EH_PE_aligned
:
478 return PointerEncoding
;
480 return make_error
<JITLinkError
>("Unsupported pointer encoding " +
481 formatv("{0:x2}", PointerEncoding
) + " for " +
482 FieldName
+ "in CFI record at " +
483 formatv("{0:x16}", InBlock
.getAddress()));
486 Error
EHFrameEdgeFixer::skipEncodedPointer(uint8_t PointerEncoding
,
487 BinaryStreamReader
&RecordReader
) {
488 using namespace dwarf
;
490 // Switch absptr to corresponding udata encoding.
491 if ((PointerEncoding
& 0xf) == DW_EH_PE_absptr
)
492 PointerEncoding
|= (PointerSize
== 8) ? DW_EH_PE_udata8
: DW_EH_PE_udata4
;
494 switch (PointerEncoding
& 0xf) {
495 case DW_EH_PE_udata4
:
496 case DW_EH_PE_sdata4
:
497 if (auto Err
= RecordReader
.skip(4))
500 case DW_EH_PE_udata8
:
501 case DW_EH_PE_sdata8
:
502 if (auto Err
= RecordReader
.skip(8))
506 llvm_unreachable("Unrecognized encoding");
508 return Error::success();
511 Expected
<Symbol
*> EHFrameEdgeFixer::getOrCreateEncodedPointerEdge(
512 ParseContext
&PC
, const BlockEdgesInfo
&BlockEdges
, uint8_t PointerEncoding
,
513 BinaryStreamReader
&RecordReader
, Block
&BlockToFix
,
514 size_t PointerFieldOffset
, const char *FieldName
) {
515 using namespace dwarf
;
517 if (PointerEncoding
== DW_EH_PE_omit
)
520 // If there's already an edge here then just skip the encoded pointer and
521 // return the edge's target.
523 auto EdgeI
= BlockEdges
.TargetMap
.find(PointerFieldOffset
);
524 if (EdgeI
!= BlockEdges
.TargetMap
.end()) {
526 dbgs() << " Existing edge at "
527 << (BlockToFix
.getAddress() + PointerFieldOffset
) << " to "
528 << FieldName
<< " at " << EdgeI
->second
.Target
->getAddress();
529 if (EdgeI
->second
.Target
->hasName())
530 dbgs() << " (" << EdgeI
->second
.Target
->getName() << ")";
533 if (auto Err
= skipEncodedPointer(PointerEncoding
, RecordReader
))
534 return std::move(Err
);
535 return EdgeI
->second
.Target
;
538 if (BlockEdges
.Multiple
.contains(PointerFieldOffset
))
539 return make_error
<JITLinkError
>("Multiple relocations at offset " +
540 formatv("{0:x16}", PointerFieldOffset
));
543 // Switch absptr to corresponding udata encoding.
544 if ((PointerEncoding
& 0xf) == DW_EH_PE_absptr
)
545 PointerEncoding
|= (PointerSize
== 8) ? DW_EH_PE_udata8
: DW_EH_PE_udata4
;
547 // We need to create an edge. Start by reading the field value.
549 bool Is64Bit
= false;
550 switch (PointerEncoding
& 0xf) {
551 case DW_EH_PE_udata4
: {
553 if (auto Err
= RecordReader
.readInteger(Val
))
554 return std::move(Err
);
558 case DW_EH_PE_sdata4
: {
560 if (auto Err
= RecordReader
.readInteger(Val
))
561 return std::move(Err
);
565 case DW_EH_PE_udata8
:
566 case DW_EH_PE_sdata8
:
568 if (auto Err
= RecordReader
.readInteger(FieldValue
))
569 return std::move(Err
);
572 llvm_unreachable("Unsupported encoding");
575 // Find the edge target and edge kind to use.
576 orc::ExecutorAddr Target
;
577 Edge::Kind PtrEdgeKind
= Edge::Invalid
;
578 if ((PointerEncoding
& 0x70) == DW_EH_PE_pcrel
) {
579 Target
= BlockToFix
.getAddress() + PointerFieldOffset
;
580 PtrEdgeKind
= Is64Bit
? Delta64
: Delta32
;
582 PtrEdgeKind
= Is64Bit
? Pointer64
: Pointer32
;
583 Target
+= FieldValue
;
585 // Find or create a symbol to point the edge at.
586 auto TargetSym
= getOrCreateSymbol(PC
, Target
);
588 return TargetSym
.takeError();
589 BlockToFix
.addEdge(PtrEdgeKind
, PointerFieldOffset
, *TargetSym
, 0);
592 dbgs() << " Adding edge at "
593 << (BlockToFix
.getAddress() + PointerFieldOffset
) << " to "
594 << FieldName
<< " at " << TargetSym
->getAddress();
595 if (TargetSym
->hasName())
596 dbgs() << " (" << TargetSym
->getName() << ")";
603 Expected
<Symbol
&> EHFrameEdgeFixer::getOrCreateSymbol(ParseContext
&PC
,
604 orc::ExecutorAddr Addr
) {
605 // See whether we have a canonical symbol for the given address already.
606 auto CanonicalSymI
= PC
.AddrToSym
.find(Addr
);
607 if (CanonicalSymI
!= PC
.AddrToSym
.end())
608 return *CanonicalSymI
->second
;
610 // Otherwise search for a block covering the address and create a new symbol.
611 auto *B
= PC
.AddrToBlock
.getBlockCovering(Addr
);
613 return make_error
<JITLinkError
>("No symbol or block covering address " +
614 formatv("{0:x16}", Addr
));
617 PC
.G
.addAnonymousSymbol(*B
, Addr
- B
->getAddress(), 0, false, false);
618 PC
.AddrToSym
[S
.getAddress()] = &S
;
622 char EHFrameNullTerminator::NullTerminatorBlockContent
[4] = {0, 0, 0, 0};
624 EHFrameNullTerminator::EHFrameNullTerminator(StringRef EHFrameSectionName
)
625 : EHFrameSectionName(EHFrameSectionName
) {}
627 Error
EHFrameNullTerminator::operator()(LinkGraph
&G
) {
628 auto *EHFrame
= G
.findSectionByName(EHFrameSectionName
);
631 return Error::success();
634 dbgs() << "EHFrameNullTerminator adding null terminator to "
635 << EHFrameSectionName
<< "\n";
638 auto &NullTerminatorBlock
=
639 G
.createContentBlock(*EHFrame
, NullTerminatorBlockContent
,
640 orc::ExecutorAddr(~uint64_t(4)), 1, 0);
641 G
.addAnonymousSymbol(NullTerminatorBlock
, 0, 4, false, true);
642 return Error::success();
645 EHFrameRegistrar::~EHFrameRegistrar() = default;
647 Error
InProcessEHFrameRegistrar::registerEHFrames(
648 orc::ExecutorAddrRange EHFrameSection
) {
649 return orc::registerEHFrameSection(EHFrameSection
.Start
.toPtr
<void *>(),
650 EHFrameSection
.size());
653 Error
InProcessEHFrameRegistrar::deregisterEHFrames(
654 orc::ExecutorAddrRange EHFrameSection
) {
655 return orc::deregisterEHFrameSection(EHFrameSection
.Start
.toPtr
<void *>(),
656 EHFrameSection
.size());
659 EHFrameCFIBlockInspector
EHFrameCFIBlockInspector::FromEdgeScan(Block
&B
) {
661 return EHFrameCFIBlockInspector(nullptr);
662 if (B
.edges_size() == 1)
663 return EHFrameCFIBlockInspector(&*B
.edges().begin());
664 SmallVector
<Edge
*, 3> Es
;
665 for (auto &E
: B
.edges())
667 assert(Es
.size() >= 2 && Es
.size() <= 3 && "Unexpected number of edges");
668 llvm::sort(Es
, [](const Edge
*LHS
, const Edge
*RHS
) {
669 return LHS
->getOffset() < RHS
->getOffset();
671 return EHFrameCFIBlockInspector(*Es
[0], *Es
[1],
672 Es
.size() == 3 ? Es
[2] : nullptr);
673 return EHFrameCFIBlockInspector(nullptr);
676 EHFrameCFIBlockInspector::EHFrameCFIBlockInspector(Edge
*PersonalityEdge
)
677 : PersonalityEdge(PersonalityEdge
) {}
679 EHFrameCFIBlockInspector::EHFrameCFIBlockInspector(Edge
&CIEEdge
,
682 : CIEEdge(&CIEEdge
), PCBeginEdge(&PCBeginEdge
), LSDAEdge(LSDAEdge
) {}
684 LinkGraphPassFunction
685 createEHFrameRecorderPass(const Triple
&TT
,
686 StoreFrameRangeFunction StoreRangeAddress
) {
687 const char *EHFrameSectionName
= nullptr;
688 if (TT
.getObjectFormat() == Triple::MachO
)
689 EHFrameSectionName
= "__TEXT,__eh_frame";
691 EHFrameSectionName
= ".eh_frame";
695 StoreFrameRange
= std::move(StoreRangeAddress
)](LinkGraph
&G
) -> Error
{
696 // Search for a non-empty eh-frame and record the address of the first
698 orc::ExecutorAddr Addr
;
700 if (auto *S
= G
.findSectionByName(EHFrameSectionName
)) {
701 auto R
= SectionRange(*S
);
705 if (!Addr
&& Size
!= 0)
706 return make_error
<JITLinkError
>(
707 StringRef(EHFrameSectionName
) +
708 " section can not have zero address with non-zero size");
709 StoreFrameRange(Addr
, Size
);
710 return Error::success();
713 return RecordEHFrame
;
716 } // end namespace jitlink
717 } // end namespace llvm