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/Orc/TargetProcess/RegisterEHFrames.h"
14 #include "llvm/Support/DynamicLibrary.h"
16 #define DEBUG_TYPE "jitlink"
21 EHFrameSplitter::EHFrameSplitter(StringRef EHFrameSectionName
)
22 : EHFrameSectionName(EHFrameSectionName
) {}
24 Error
EHFrameSplitter::operator()(LinkGraph
&G
) {
25 auto *EHFrame
= G
.findSectionByName(EHFrameSectionName
);
29 dbgs() << "EHFrameSplitter: No " << EHFrameSectionName
30 << " section. Nothing to do\n";
32 return Error::success();
36 dbgs() << "EHFrameSplitter: Processing " << EHFrameSectionName
<< "...\n";
39 DenseMap
<Block
*, LinkGraph::SplitBlockCache
> Caches
;
42 // Pre-build the split caches.
43 for (auto *B
: EHFrame
->blocks())
44 Caches
[B
] = LinkGraph::SplitBlockCache::value_type();
45 for (auto *Sym
: EHFrame
->symbols())
46 Caches
[&Sym
->getBlock()]->push_back(Sym
);
47 for (auto *B
: EHFrame
->blocks())
48 llvm::sort(*Caches
[B
], [](const Symbol
*LHS
, const Symbol
*RHS
) {
49 return LHS
->getOffset() > RHS
->getOffset();
53 // Iterate over blocks (we do this by iterating over Caches entries rather
54 // than EHFrame->blocks() as we will be inserting new blocks along the way,
55 // which would invalidate iterators in the latter sequence.
56 for (auto &KV
: Caches
) {
58 auto &BCache
= KV
.second
;
59 if (auto Err
= processBlock(G
, B
, BCache
))
63 return Error::success();
66 Error
EHFrameSplitter::processBlock(LinkGraph
&G
, Block
&B
,
67 LinkGraph::SplitBlockCache
&Cache
) {
69 dbgs() << " Processing block at " << formatv("{0:x16}", B
.getAddress())
73 // eh-frame should not contain zero-fill blocks.
75 return make_error
<JITLinkError
>("Unexpected zero-fill block in " +
76 EHFrameSectionName
+ " section");
78 if (B
.getSize() == 0) {
79 LLVM_DEBUG(dbgs() << " Block is empty. Skipping.\n");
80 return Error::success();
83 BinaryStreamReader
BlockReader(
84 StringRef(B
.getContent().data(), B
.getContent().size()),
88 uint64_t RecordStartOffset
= BlockReader
.getOffset();
91 dbgs() << " Processing CFI record at "
92 << formatv("{0:x16}", B
.getAddress()) << "\n";
96 if (auto Err
= BlockReader
.readInteger(Length
))
98 if (Length
!= 0xffffffff) {
99 if (auto Err
= BlockReader
.skip(Length
))
102 uint64_t ExtendedLength
;
103 if (auto Err
= BlockReader
.readInteger(ExtendedLength
))
105 if (auto Err
= BlockReader
.skip(ExtendedLength
))
109 // If this was the last block then there's nothing to split
110 if (BlockReader
.empty()) {
111 LLVM_DEBUG(dbgs() << " Extracted " << B
<< "\n");
112 return Error::success();
115 uint64_t BlockSize
= BlockReader
.getOffset() - RecordStartOffset
;
116 auto &NewBlock
= G
.splitBlock(B
, BlockSize
);
118 LLVM_DEBUG(dbgs() << " Extracted " << NewBlock
<< "\n");
122 EHFrameEdgeFixer::EHFrameEdgeFixer(StringRef EHFrameSectionName
,
123 unsigned PointerSize
, Edge::Kind Delta64
,
124 Edge::Kind Delta32
, Edge::Kind NegDelta32
)
125 : EHFrameSectionName(EHFrameSectionName
), PointerSize(PointerSize
),
126 Delta64(Delta64
), Delta32(Delta32
), NegDelta32(NegDelta32
) {}
128 Error
EHFrameEdgeFixer::operator()(LinkGraph
&G
) {
129 auto *EHFrame
= G
.findSectionByName(EHFrameSectionName
);
133 dbgs() << "EHFrameEdgeFixer: No " << EHFrameSectionName
134 << " section. Nothing to do\n";
136 return Error::success();
139 // Check that we support the graph's pointer size.
140 if (G
.getPointerSize() != 4 && G
.getPointerSize() != 8)
141 return make_error
<JITLinkError
>(
142 "EHFrameEdgeFixer only supports 32 and 64 bit targets");
145 dbgs() << "EHFrameEdgeFixer: Processing " << EHFrameSectionName
<< "...\n";
150 // Build a map of all blocks and symbols in the text sections. We will use
151 // these for finding / building edge targets when processing FDEs.
152 for (auto &Sec
: G
.sections()) {
153 PC
.AddrToSyms
.addSymbols(Sec
.symbols());
154 if (auto Err
= PC
.AddrToBlock
.addBlocks(Sec
.blocks(),
155 BlockAddressMap::includeNonNull
))
159 // Sort eh-frame blocks into address order to ensure we visit CIEs before
161 std::vector
<Block
*> EHFrameBlocks
;
162 for (auto *B
: EHFrame
->blocks())
163 EHFrameBlocks
.push_back(B
);
164 llvm::sort(EHFrameBlocks
, [](const Block
*LHS
, const Block
*RHS
) {
165 return LHS
->getAddress() < RHS
->getAddress();
168 // Loop over the blocks in address order.
169 for (auto *B
: EHFrameBlocks
)
170 if (auto Err
= processBlock(PC
, *B
))
173 return Error::success();
176 Error
EHFrameEdgeFixer::processBlock(ParseContext
&PC
, Block
&B
) {
179 dbgs() << " Processing block at " << formatv("{0:x16}", B
.getAddress())
183 // eh-frame should not contain zero-fill blocks.
185 return make_error
<JITLinkError
>("Unexpected zero-fill block in " +
186 EHFrameSectionName
+ " section");
188 if (B
.getSize() == 0) {
189 LLVM_DEBUG(dbgs() << " Block is empty. Skipping.\n");
190 return Error::success();
193 // Find the offsets of any existing edges from this block.
194 BlockEdgeMap BlockEdges
;
195 for (auto &E
: B
.edges())
196 if (E
.isRelocation()) {
197 if (BlockEdges
.count(E
.getOffset()))
198 return make_error
<JITLinkError
>(
199 "Multiple relocations at offset " +
200 formatv("{0:x16}", E
.getOffset()) + " in " + EHFrameSectionName
+
201 " block at address " + formatv("{0:x16}", B
.getAddress()));
203 BlockEdges
[E
.getOffset()] = EdgeTarget(E
);
206 CIEInfosMap CIEInfos
;
207 BinaryStreamReader
BlockReader(
208 StringRef(B
.getContent().data(), B
.getContent().size()),
209 PC
.G
.getEndianness());
210 while (!BlockReader
.empty()) {
211 size_t RecordStartOffset
= BlockReader
.getOffset();
214 dbgs() << " Processing CFI record at "
215 << formatv("{0:x16}", B
.getAddress() + RecordStartOffset
) << "\n";
218 // Get the record length.
219 size_t RecordRemaining
;
222 if (auto Err
= BlockReader
.readInteger(Length
))
224 // If Length < 0xffffffff then use the regular length field, otherwise
225 // read the extended length field.
226 if (Length
!= 0xffffffff)
227 RecordRemaining
= Length
;
229 uint64_t ExtendedLength
;
230 if (auto Err
= BlockReader
.readInteger(ExtendedLength
))
232 RecordRemaining
= ExtendedLength
;
236 if (BlockReader
.bytesRemaining() < RecordRemaining
)
237 return make_error
<JITLinkError
>(
238 "Incomplete CFI record at " +
239 formatv("{0:x16}", B
.getAddress() + RecordStartOffset
));
241 // Read the CIE delta for this record.
242 uint64_t CIEDeltaFieldOffset
= BlockReader
.getOffset() - RecordStartOffset
;
244 if (auto Err
= BlockReader
.readInteger(CIEDelta
))
248 if (auto Err
= processCIE(PC
, B
, RecordStartOffset
,
249 CIEDeltaFieldOffset
+ RecordRemaining
,
250 CIEDeltaFieldOffset
))
253 if (auto Err
= processFDE(PC
, B
, RecordStartOffset
,
254 CIEDeltaFieldOffset
+ RecordRemaining
,
255 CIEDeltaFieldOffset
, CIEDelta
, BlockEdges
))
259 // Move to the next record.
260 BlockReader
.setOffset(RecordStartOffset
+ CIEDeltaFieldOffset
+
264 return Error::success();
267 Error
EHFrameEdgeFixer::processCIE(ParseContext
&PC
, Block
&B
,
268 size_t RecordOffset
, size_t RecordLength
,
269 size_t CIEDeltaFieldOffset
) {
271 LLVM_DEBUG(dbgs() << " Record is CIE\n");
273 auto RecordContent
= B
.getContent().slice(RecordOffset
, RecordLength
);
274 BinaryStreamReader
RecordReader(
275 StringRef(RecordContent
.data(), RecordContent
.size()),
276 PC
.G
.getEndianness());
278 // Skip past the CIE delta field: we've already processed this far.
279 RecordReader
.setOffset(CIEDeltaFieldOffset
+ 4);
282 PC
.G
.addAnonymousSymbol(B
, RecordOffset
, RecordLength
, false, false);
283 CIEInformation
CIEInfo(CIESymbol
);
286 if (auto Err
= RecordReader
.readInteger(Version
))
290 return make_error
<JITLinkError
>("Bad CIE version " + Twine(Version
) +
291 " (should be 0x01) in eh-frame");
293 auto AugInfo
= parseAugmentationString(RecordReader
);
295 return AugInfo
.takeError();
297 // Skip the EH Data field if present.
298 if (AugInfo
->EHDataFieldPresent
)
299 if (auto Err
= RecordReader
.skip(PC
.G
.getPointerSize()))
302 // Read and sanity check the code alignment factor.
304 uint64_t CodeAlignmentFactor
= 0;
305 if (auto Err
= RecordReader
.readULEB128(CodeAlignmentFactor
))
307 if (CodeAlignmentFactor
!= 1)
308 return make_error
<JITLinkError
>("Unsupported CIE code alignment factor " +
309 Twine(CodeAlignmentFactor
) +
313 // Read and sanity check the data alignment factor.
315 int64_t DataAlignmentFactor
= 0;
316 if (auto Err
= RecordReader
.readSLEB128(DataAlignmentFactor
))
318 if (DataAlignmentFactor
!= -8)
319 return make_error
<JITLinkError
>("Unsupported CIE data alignment factor " +
320 Twine(DataAlignmentFactor
) +
324 // Skip the return address register field.
325 if (auto Err
= RecordReader
.skip(1))
328 uint64_t AugmentationDataLength
= 0;
329 if (auto Err
= RecordReader
.readULEB128(AugmentationDataLength
))
332 uint32_t AugmentationDataStartOffset
= RecordReader
.getOffset();
334 uint8_t *NextField
= &AugInfo
->Fields
[0];
335 while (uint8_t Field
= *NextField
++) {
338 CIEInfo
.FDEsHaveLSDAField
= true;
339 uint8_t LSDAPointerEncoding
;
340 if (auto Err
= RecordReader
.readInteger(LSDAPointerEncoding
))
342 if (!isSupportedPointerEncoding(LSDAPointerEncoding
))
343 return make_error
<JITLinkError
>(
344 "Unsupported LSDA pointer encoding " +
345 formatv("{0:x2}", LSDAPointerEncoding
) + " in CIE at " +
346 formatv("{0:x16}", CIESymbol
.getAddress()));
347 CIEInfo
.LSDAPointerEncoding
= LSDAPointerEncoding
;
351 uint8_t PersonalityPointerEncoding
= 0;
352 if (auto Err
= RecordReader
.readInteger(PersonalityPointerEncoding
))
354 if (PersonalityPointerEncoding
!=
355 (dwarf::DW_EH_PE_indirect
| dwarf::DW_EH_PE_pcrel
|
356 dwarf::DW_EH_PE_sdata4
))
357 return make_error
<JITLinkError
>(
358 "Unspported personality pointer "
360 formatv("{0:x2}", PersonalityPointerEncoding
) + " in CIE at " +
361 formatv("{0:x16}", CIESymbol
.getAddress()));
362 uint32_t PersonalityPointerAddress
;
363 if (auto Err
= RecordReader
.readInteger(PersonalityPointerAddress
))
368 uint8_t FDEPointerEncoding
;
369 if (auto Err
= RecordReader
.readInteger(FDEPointerEncoding
))
371 if (!isSupportedPointerEncoding(FDEPointerEncoding
))
372 return make_error
<JITLinkError
>(
373 "Unsupported FDE pointer encoding " +
374 formatv("{0:x2}", FDEPointerEncoding
) + " in CIE at " +
375 formatv("{0:x16}", CIESymbol
.getAddress()));
376 CIEInfo
.FDEPointerEncoding
= FDEPointerEncoding
;
380 llvm_unreachable("Invalid augmentation string field");
384 if (RecordReader
.getOffset() - AugmentationDataStartOffset
>
385 AugmentationDataLength
)
386 return make_error
<JITLinkError
>("Read past the end of the augmentation "
387 "data while parsing fields");
389 assert(!PC
.CIEInfos
.count(CIESymbol
.getAddress()) &&
390 "Multiple CIEs recorded at the same address?");
391 PC
.CIEInfos
[CIESymbol
.getAddress()] = std::move(CIEInfo
);
393 return Error::success();
396 Error
EHFrameEdgeFixer::processFDE(ParseContext
&PC
, Block
&B
,
397 size_t RecordOffset
, size_t RecordLength
,
398 size_t CIEDeltaFieldOffset
,
400 BlockEdgeMap
&BlockEdges
) {
401 LLVM_DEBUG(dbgs() << " Record is FDE\n");
403 JITTargetAddress RecordAddress
= B
.getAddress() + RecordOffset
;
405 auto RecordContent
= B
.getContent().slice(RecordOffset
, RecordLength
);
406 BinaryStreamReader
RecordReader(
407 StringRef(RecordContent
.data(), RecordContent
.size()),
408 PC
.G
.getEndianness());
410 // Skip past the CIE delta field: we've already read this far.
411 RecordReader
.setOffset(CIEDeltaFieldOffset
+ 4);
414 PC
.G
.addAnonymousSymbol(B
, RecordOffset
, RecordLength
, false, false);
416 CIEInformation
*CIEInfo
= nullptr;
419 // Process the CIE pointer field.
420 auto CIEEdgeItr
= BlockEdges
.find(RecordOffset
+ CIEDeltaFieldOffset
);
421 JITTargetAddress CIEAddress
=
422 RecordAddress
+ CIEDeltaFieldOffset
- CIEDelta
;
423 if (CIEEdgeItr
== BlockEdges
.end()) {
426 dbgs() << " Adding edge at "
427 << formatv("{0:x16}", RecordAddress
+ CIEDeltaFieldOffset
)
428 << " to CIE at: " << formatv("{0:x16}", CIEAddress
) << "\n";
430 if (auto CIEInfoOrErr
= PC
.findCIEInfo(CIEAddress
))
431 CIEInfo
= *CIEInfoOrErr
;
433 return CIEInfoOrErr
.takeError();
434 assert(CIEInfo
->CIESymbol
&& "CIEInfo has no CIE symbol set");
435 B
.addEdge(NegDelta32
, RecordOffset
+ CIEDeltaFieldOffset
,
436 *CIEInfo
->CIESymbol
, 0);
439 dbgs() << " Already has edge at "
440 << formatv("{0:x16}", RecordAddress
+ CIEDeltaFieldOffset
)
441 << " to CIE at " << formatv("{0:x16}", CIEAddress
) << "\n";
443 auto &EI
= CIEEdgeItr
->second
;
445 return make_error
<JITLinkError
>(
447 formatv("{0:x16}", RecordAddress
+ CIEDeltaFieldOffset
) +
448 " has non-zero addend");
449 if (auto CIEInfoOrErr
= PC
.findCIEInfo(EI
.Target
->getAddress()))
450 CIEInfo
= *CIEInfoOrErr
;
452 return CIEInfoOrErr
.takeError();
457 // Process the PC-Begin field.
458 Block
*PCBeginBlock
= nullptr;
459 JITTargetAddress PCBeginFieldOffset
= RecordReader
.getOffset();
460 auto PCEdgeItr
= BlockEdges
.find(RecordOffset
+ PCBeginFieldOffset
);
461 if (PCEdgeItr
== BlockEdges
.end()) {
462 auto PCBeginPtrInfo
=
463 readEncodedPointer(CIEInfo
->FDEPointerEncoding
,
464 RecordAddress
+ PCBeginFieldOffset
, RecordReader
);
466 return PCBeginPtrInfo
.takeError();
467 JITTargetAddress PCBegin
= PCBeginPtrInfo
->first
;
468 Edge::Kind PCBeginEdgeKind
= PCBeginPtrInfo
->second
;
470 dbgs() << " Adding edge at "
471 << formatv("{0:x16}", RecordAddress
+ PCBeginFieldOffset
)
472 << " to PC at " << formatv("{0:x16}", PCBegin
) << "\n";
474 auto PCBeginSym
= getOrCreateSymbol(PC
, PCBegin
);
476 return PCBeginSym
.takeError();
477 B
.addEdge(PCBeginEdgeKind
, RecordOffset
+ PCBeginFieldOffset
, *PCBeginSym
,
479 PCBeginBlock
= &PCBeginSym
->getBlock();
481 auto &EI
= PCEdgeItr
->second
;
483 dbgs() << " Already has edge at "
484 << formatv("{0:x16}", RecordAddress
+ PCBeginFieldOffset
)
485 << " to PC at " << formatv("{0:x16}", EI
.Target
->getAddress());
487 dbgs() << " + " << formatv("{0:x16}", EI
.Addend
);
491 // Make sure the existing edge points at a defined block.
492 if (!EI
.Target
->isDefined()) {
493 auto EdgeAddr
= RecordAddress
+ PCBeginFieldOffset
;
494 return make_error
<JITLinkError
>("FDE edge at " +
495 formatv("{0:x16}", EdgeAddr
) +
496 " points at external block");
498 PCBeginBlock
= &EI
.Target
->getBlock();
499 if (auto Err
= RecordReader
.skip(
500 getPointerEncodingDataSize(CIEInfo
->FDEPointerEncoding
)))
504 // Add a keep-alive edge from the FDE target to the FDE to ensure that the
505 // FDE is kept alive if its target is.
506 assert(PCBeginBlock
&& "PC-begin block not recorded");
508 dbgs() << " Adding keep-alive edge from target at "
509 << formatv("{0:x16}", PCBeginBlock
->getAddress()) << " to FDE at "
510 << formatv("{0:x16}", RecordAddress
) << "\n";
512 PCBeginBlock
->addEdge(Edge::KeepAlive
, 0, FDESymbol
, 0);
515 // Skip over the PC range size field.
516 if (auto Err
= RecordReader
.skip(
517 getPointerEncodingDataSize(CIEInfo
->FDEPointerEncoding
)))
520 if (CIEInfo
->FDEsHaveLSDAField
) {
521 uint64_t AugmentationDataSize
;
522 if (auto Err
= RecordReader
.readULEB128(AugmentationDataSize
))
525 JITTargetAddress LSDAFieldOffset
= RecordReader
.getOffset();
526 auto LSDAEdgeItr
= BlockEdges
.find(RecordOffset
+ LSDAFieldOffset
);
527 if (LSDAEdgeItr
== BlockEdges
.end()) {
528 auto LSDAPointerInfo
=
529 readEncodedPointer(CIEInfo
->LSDAPointerEncoding
,
530 RecordAddress
+ LSDAFieldOffset
, RecordReader
);
531 if (!LSDAPointerInfo
)
532 return LSDAPointerInfo
.takeError();
533 JITTargetAddress LSDA
= LSDAPointerInfo
->first
;
534 Edge::Kind LSDAEdgeKind
= LSDAPointerInfo
->second
;
535 auto LSDASym
= getOrCreateSymbol(PC
, LSDA
);
537 return LSDASym
.takeError();
539 dbgs() << " Adding edge at "
540 << formatv("{0:x16}", RecordAddress
+ LSDAFieldOffset
)
541 << " to LSDA at " << formatv("{0:x16}", LSDA
) << "\n";
543 B
.addEdge(LSDAEdgeKind
, RecordOffset
+ LSDAFieldOffset
, *LSDASym
, 0);
546 auto &EI
= LSDAEdgeItr
->second
;
547 dbgs() << " Already has edge at "
548 << formatv("{0:x16}", RecordAddress
+ LSDAFieldOffset
)
549 << " to LSDA at " << formatv("{0:x16}", EI
.Target
->getAddress());
551 dbgs() << " + " << formatv("{0:x16}", EI
.Addend
);
554 if (auto Err
= RecordReader
.skip(AugmentationDataSize
))
558 LLVM_DEBUG(dbgs() << " Record does not have LSDA field.\n");
561 return Error::success();
564 Expected
<EHFrameEdgeFixer::AugmentationInfo
>
565 EHFrameEdgeFixer::parseAugmentationString(BinaryStreamReader
&RecordReader
) {
566 AugmentationInfo AugInfo
;
568 uint8_t *NextField
= &AugInfo
.Fields
[0];
570 if (auto Err
= RecordReader
.readInteger(NextChar
))
571 return std::move(Err
);
573 while (NextChar
!= 0) {
576 AugInfo
.AugmentationDataPresent
= true;
579 if (auto Err
= RecordReader
.readInteger(NextChar
))
580 return std::move(Err
);
582 return make_error
<JITLinkError
>("Unrecognized substring e" +
584 " in augmentation string");
585 AugInfo
.EHDataFieldPresent
= true;
590 *NextField
++ = NextChar
;
593 return make_error
<JITLinkError
>("Unrecognized character " +
595 " in augmentation string");
598 if (auto Err
= RecordReader
.readInteger(NextChar
))
599 return std::move(Err
);
602 return std::move(AugInfo
);
605 bool EHFrameEdgeFixer::isSupportedPointerEncoding(uint8_t PointerEncoding
) {
606 using namespace dwarf
;
608 // We only support PC-rel for now.
609 if ((PointerEncoding
& 0x70) != DW_EH_PE_pcrel
)
612 // readEncodedPointer does not handle indirect.
613 if (PointerEncoding
& DW_EH_PE_indirect
)
616 // Supported datatypes.
617 switch (PointerEncoding
& 0xf) {
618 case DW_EH_PE_absptr
:
619 case DW_EH_PE_udata4
:
620 case DW_EH_PE_udata8
:
621 case DW_EH_PE_sdata4
:
622 case DW_EH_PE_sdata8
:
629 unsigned EHFrameEdgeFixer::getPointerEncodingDataSize(uint8_t PointerEncoding
) {
630 using namespace dwarf
;
632 assert(isSupportedPointerEncoding(PointerEncoding
) &&
633 "Unsupported pointer encoding");
634 switch (PointerEncoding
& 0xf) {
635 case DW_EH_PE_absptr
:
637 case DW_EH_PE_udata4
:
638 case DW_EH_PE_sdata4
:
640 case DW_EH_PE_udata8
:
641 case DW_EH_PE_sdata8
:
644 llvm_unreachable("Unsupported encoding");
648 Expected
<std::pair
<JITTargetAddress
, Edge::Kind
>>
649 EHFrameEdgeFixer::readEncodedPointer(uint8_t PointerEncoding
,
650 JITTargetAddress PointerFieldAddress
,
651 BinaryStreamReader
&RecordReader
) {
652 static_assert(sizeof(JITTargetAddress
) == sizeof(uint64_t),
653 "Result must be able to hold a uint64_t");
654 assert(isSupportedPointerEncoding(PointerEncoding
) &&
655 "Unsupported pointer encoding");
657 using namespace dwarf
;
659 // Isolate data type, remap absptr to udata4 or udata8. This relies on us
660 // having verified that the graph uses 32-bit or 64-bit pointers only at the
661 // start of this pass.
662 uint8_t EffectiveType
= PointerEncoding
& 0xf;
663 if (EffectiveType
== DW_EH_PE_absptr
)
664 EffectiveType
= (PointerSize
== 8) ? DW_EH_PE_udata8
: DW_EH_PE_udata4
;
666 JITTargetAddress Addr
;
667 Edge::Kind PointerEdgeKind
;
668 switch (EffectiveType
) {
669 case DW_EH_PE_udata4
: {
671 if (auto Err
= RecordReader
.readInteger(Val
))
672 return std::move(Err
);
673 Addr
= PointerFieldAddress
+ Val
;
674 PointerEdgeKind
= Delta32
;
677 case DW_EH_PE_udata8
: {
679 if (auto Err
= RecordReader
.readInteger(Val
))
680 return std::move(Err
);
681 Addr
= PointerFieldAddress
+ Val
;
682 PointerEdgeKind
= Delta64
;
685 case DW_EH_PE_sdata4
: {
687 if (auto Err
= RecordReader
.readInteger(Val
))
688 return std::move(Err
);
689 Addr
= PointerFieldAddress
+ Val
;
690 PointerEdgeKind
= Delta32
;
693 case DW_EH_PE_sdata8
: {
695 if (auto Err
= RecordReader
.readInteger(Val
))
696 return std::move(Err
);
697 Addr
= PointerFieldAddress
+ Val
;
698 PointerEdgeKind
= Delta64
;
703 if (PointerEdgeKind
== Edge::Invalid
)
704 return make_error
<JITLinkError
>(
705 "Unspported edge kind for encoded pointer at " +
706 formatv("{0:x}", PointerFieldAddress
));
708 return std::make_pair(Addr
, Delta64
);
711 Expected
<Symbol
&> EHFrameEdgeFixer::getOrCreateSymbol(ParseContext
&PC
,
712 JITTargetAddress Addr
) {
713 Symbol
*CanonicalSym
= nullptr;
715 auto UpdateCanonicalSym
= [&](Symbol
*Sym
) {
716 if (!CanonicalSym
|| Sym
->getLinkage() < CanonicalSym
->getLinkage() ||
717 Sym
->getScope() < CanonicalSym
->getScope() ||
718 (Sym
->hasName() && !CanonicalSym
->hasName()) ||
719 Sym
->getName() < CanonicalSym
->getName())
723 if (auto *SymbolsAtAddr
= PC
.AddrToSyms
.getSymbolsAt(Addr
))
724 for (auto *Sym
: *SymbolsAtAddr
)
725 UpdateCanonicalSym(Sym
);
727 // If we found an existing symbol at the given address then use it.
729 return *CanonicalSym
;
731 // Otherwise search for a block covering the address and create a new symbol.
732 auto *B
= PC
.AddrToBlock
.getBlockCovering(Addr
);
734 return make_error
<JITLinkError
>("No symbol or block covering address " +
735 formatv("{0:x16}", Addr
));
737 return PC
.G
.addAnonymousSymbol(*B
, Addr
- B
->getAddress(), 0, false, false);
740 char EHFrameNullTerminator::NullTerminatorBlockContent
[4] = {0, 0, 0, 0};
742 EHFrameNullTerminator::EHFrameNullTerminator(StringRef EHFrameSectionName
)
743 : EHFrameSectionName(EHFrameSectionName
) {}
745 Error
EHFrameNullTerminator::operator()(LinkGraph
&G
) {
746 auto *EHFrame
= G
.findSectionByName(EHFrameSectionName
);
749 return Error::success();
752 dbgs() << "EHFrameNullTerminator adding null terminator to "
753 << EHFrameSectionName
<< "\n";
756 auto &NullTerminatorBlock
= G
.createContentBlock(
757 *EHFrame
, NullTerminatorBlockContent
, 0xfffffffffffffffc, 1, 0);
758 G
.addAnonymousSymbol(NullTerminatorBlock
, 0, 4, false, true);
759 return Error::success();
762 EHFrameRegistrar::~EHFrameRegistrar() {}
764 Error
InProcessEHFrameRegistrar::registerEHFrames(
765 JITTargetAddress EHFrameSectionAddr
, size_t EHFrameSectionSize
) {
766 return orc::registerEHFrameSection(
767 jitTargetAddressToPointer
<void *>(EHFrameSectionAddr
),
771 Error
InProcessEHFrameRegistrar::deregisterEHFrames(
772 JITTargetAddress EHFrameSectionAddr
, size_t EHFrameSectionSize
) {
773 return orc::deregisterEHFrameSection(
774 jitTargetAddressToPointer
<void *>(EHFrameSectionAddr
),
778 LinkGraphPassFunction
779 createEHFrameRecorderPass(const Triple
&TT
,
780 StoreFrameRangeFunction StoreRangeAddress
) {
781 const char *EHFrameSectionName
= nullptr;
782 if (TT
.getObjectFormat() == Triple::MachO
)
783 EHFrameSectionName
= "__TEXT,__eh_frame";
785 EHFrameSectionName
= ".eh_frame";
789 StoreFrameRange
= std::move(StoreRangeAddress
)](LinkGraph
&G
) -> Error
{
790 // Search for a non-empty eh-frame and record the address of the first
792 JITTargetAddress Addr
= 0;
794 if (auto *S
= G
.findSectionByName(EHFrameSectionName
)) {
795 auto R
= SectionRange(*S
);
799 if (Addr
== 0 && Size
!= 0)
800 return make_error
<JITLinkError
>(
801 StringRef(EHFrameSectionName
) +
802 " section can not have zero address with non-zero size");
803 StoreFrameRange(Addr
, Size
);
804 return Error::success();
807 return RecordEHFrame
;
810 } // end namespace jitlink
811 } // end namespace llvm