12#include "llvm/Config/config.h"
17#define DEBUG_TYPE "jitlink"
26 : EHFrameSectionName(EHFrameSectionName), PointerSize(PointerSize),
27 Pointer32(Pointer32), Pointer64(Pointer64), Delta32(Delta32),
28 Delta64(Delta64), NegDelta32(NegDelta32) {}
31 auto *EHFrame =
G.findSectionByName(EHFrameSectionName);
35 dbgs() <<
"EHFrameEdgeFixer: No " << EHFrameSectionName
36 <<
" section in \"" <<
G.getName() <<
"\". Nothing to do.\n";
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";
55 for (
auto &Sec :
G.sections()) {
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(),
73 std::vector<Block *> EHFrameBlocks;
74 for (
auto *
B : EHFrame->blocks())
75 EHFrameBlocks.push_back(
B);
77 return LHS->getAddress() <
RHS->getAddress();
81 for (
auto *
B : EHFrameBlocks)
82 if (
auto Err = processBlock(PC, *
B))
91 if (
auto Err = R.readInteger(
Length))
92 return std::move(Err);
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;
114Error EHFrameEdgeFixer::processBlock(ParseContext &PC, Block &
B) {
116 LLVM_DEBUG(
dbgs() <<
" Processing block at " <<
B.getAddress() <<
"\n");
120 return make_error<JITLinkError>(
"Unexpected zero-fill block in " +
121 EHFrameSectionName +
" section");
123 if (
B.getSize() == 0) {
129 BlockEdgesInfo BlockEdges;
130 for (
auto &
E :
B.edges())
131 if (
E.isRelocation()) {
133 if (BlockEdges.Multiple.contains(
E.getOffset()))
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());
154 if (!RecordRemaining)
155 return RecordRemaining.takeError();
159 if (BlockReader.bytesRemaining() != *RecordRemaining)
160 return make_error<JITLinkError>(
"Incomplete CFI record at " +
161 formatv(
"{0:x16}",
B.getAddress()));
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))
180Error EHFrameEdgeFixer::processCIE(ParseContext &PC, Block &
B,
181 size_t CIEDeltaFieldOffset,
182 const BlockEdgesInfo &BlockEdges) {
186 BinaryStreamReader RecordReader(
187 StringRef(
B.getContent().data(),
B.getContent().size()),
188 PC.G.getEndianness());
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();
209 if (AugInfo->EHDataFieldPresent)
210 if (
auto Err = RecordReader.skip(PC.G.getPointerSize()))
216 if (
auto Err = RecordReader.readULEB128(CodeAlignmentFactor))
222 int64_t DataAlignmentFactor = 0;
223 if (
auto Err = RecordReader.readSLEB128(DataAlignmentFactor))
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;
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();
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);
292Error EHFrameEdgeFixer::processFDE(ParseContext &PC, Block &
B,
293 size_t CIEDeltaFieldOffset,
295 const BlockEdgesInfo &BlockEdges) {
298 orc::ExecutorAddr RecordAddress =
B.getAddress();
300 BinaryStreamReader RecordReader(
301 StringRef(
B.getContent().data(),
B.getContent().size()),
302 PC.G.getEndianness());
305 RecordReader.setOffset(CIEDeltaFieldOffset + 4);
307 auto &FDESymbol = PC.G.addAnonymousSymbol(
B, 0,
B.getSize(),
false,
false);
309 CIEInformation *CIEInfo =
nullptr;
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 =
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();
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()) {
367 dbgs() <<
" Adding keep-alive edge from target at "
368 << (*PCBegin)->getBlock().getAddress() <<
" to FDE at "
369 << RecordAddress <<
"\n";
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();
386 if (
auto Err = skipEncodedPointer(CIEInfo->AddressEncoding, RecordReader))
389 if (CIEInfo->AugmentationDataPresent) {
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")
407Expected<EHFrameEdgeFixer::AugmentationInfo>
408EHFrameEdgeFixer::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);
448Expected<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) {
467 switch (PointerEncoding & 0x70) {
478 return PointerEncoding;
480 return make_error<JITLinkError>(
"Unsupported pointer encoding " +
481 formatv(
"{0:x2}", PointerEncoding) +
" for " +
482 FieldName +
"in CFI record at " +
486Error EHFrameEdgeFixer::skipEncodedPointer(uint8_t PointerEncoding,
487 BinaryStreamReader &RecordReader) {
488 using namespace dwarf;
494 switch (PointerEncoding & 0xf) {
497 if (
auto Err = RecordReader.skip(4))
502 if (
auto Err = RecordReader.skip(8))
511Expected<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;
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));
549 bool Is64Bit =
false;
550 switch (PointerEncoding & 0xf) {
553 if (
auto Err = RecordReader.readInteger(Val))
554 return std::move(Err);
560 if (
auto Err = RecordReader.readInteger(Val))
561 return std::move(Err);
568 if (
auto Err = RecordReader.readInteger(FieldValue))
569 return std::move(Err);
579 Target = BlockToFix.getAddress() + PointerFieldOffset;
580 PtrEdgeKind = Is64Bit ? Delta64 : Delta32;
582 PtrEdgeKind = Is64Bit ? Pointer64 : Pointer32;
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() <<
")";
603Expected<Symbol &> EHFrameEdgeFixer::getOrCreateSymbol(ParseContext &PC,
604 orc::ExecutorAddr
Addr) {
606 auto CanonicalSymI = PC.AddrToSym.find(
Addr);
607 if (CanonicalSymI != PC.AddrToSym.end())
608 return *CanonicalSymI->second;
611 auto *
B = PC.AddrToBlock.getBlockCovering(
Addr);
613 return make_error<JITLinkError>(
"No symbol or block covering address " +
617 PC.G.addAnonymousSymbol(*
B,
Addr -
B->getAddress(), 0,
false,
false);
618 PC.AddrToSym[S.getAddress()] = &S;
622char EHFrameNullTerminator::NullTerminatorBlockContent[4] = {0, 0, 0, 0};
625 : EHFrameSectionName(EHFrameSectionName) {}
628 auto *EHFrame =
G.findSectionByName(EHFrameSectionName);
634 dbgs() <<
"EHFrameNullTerminator adding null terminator to "
635 << EHFrameSectionName <<
"\n";
638 auto &NullTerminatorBlock =
639 G.createContentBlock(*EHFrame, NullTerminatorBlockContent,
641 G.addAnonymousSymbol(NullTerminatorBlock, 0, 4,
false,
true);
650 EHFrameSection.
size());
656 EHFrameSection.
size());
662 if (
B.edges_size() == 1)
665 for (
auto &
E :
B.edges())
667 assert(Es.
size() >= 2 && Es.
size() <= 3 &&
"Unexpected number of edges");
669 return LHS->getOffset() <
RHS->getOffset();
672 Es.
size() == 3 ? Es[2] :
nullptr);
676EHFrameCFIBlockInspector::EHFrameCFIBlockInspector(
Edge *PersonalityEdge)
677 : PersonalityEdge(PersonalityEdge) {}
679EHFrameCFIBlockInspector::EHFrameCFIBlockInspector(Edge &CIEEdge,
682 : CIEEdge(&CIEEdge), PCBeginEdge(&PCBeginEdge), LSDAEdge(LSDAEdge) {}
687 const char *EHFrameSectionName =
nullptr;
689 EHFrameSectionName =
"__TEXT,__eh_frame";
691 EHFrameSectionName =
".eh_frame";
695 StoreFrameRange = std::move(StoreRangeAddress)](
LinkGraph &
G) ->
Error {
700 if (
auto *S =
G.findSectionByName(EHFrameSectionName)) {
706 return make_error<JITLinkError>(
708 " section can not have zero address with non-zero size");
713 return RecordEHFrame;
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
This file contains constants used for implementing Dwarf debug support.
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
static bool InBlock(const Value *V, const BasicBlock *BB)
Provides read only access to a subclass of BinaryStream.
Lightweight error class with error context and mandatory checking.
static ErrorSuccess success()
Create a success value.
Tagged union holding either a T or a Error.
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
StringRef - Represent a constant reference to a string, i.e.
Triple - Helper class for working with autoconf configuration names.
static bool includeNonNull(const Block &B)
A block predicate that always includes blocks with non-null addresses.
An Addressable with content and edges.
Inspect an eh-frame CFI record.
static EHFrameCFIBlockInspector FromEdgeScan(Block &B)
Identify CFI record type and edges based on number and order of edges in the given block only.
Error operator()(LinkGraph &G)
EHFrameEdgeFixer(StringRef EHFrameSectionName, unsigned PointerSize, Edge::Kind Pointer32, Edge::Kind Pointer64, Edge::Kind Delta32, Edge::Kind Delta64, Edge::Kind NegDelta32)
Create an eh-frame edge fixer.
virtual ~EHFrameRegistrar()
Represents fixups and constraints in the LinkGraph.
Error registerEHFrames(orc::ExecutorAddrRange EHFrameSection) override
Error deregisterEHFrames(orc::ExecutorAddrRange EHFrameSection) override
Represents a section address range via a pair of Block pointers to the first and last Blocks in the s...
Represents an address in the executor process.
std::enable_if_t< std::is_pointer< T >::value, T > toPtr(WrapFn &&Wrap=WrapFn()) const
Cast this ExecutorAddr to a pointer of the given type.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
std::function< void(orc::ExecutorAddr EHFrameSectionAddr, size_t EHFrameSectionSize)> StoreFrameRangeFunction
static Expected< size_t > readCFIRecordLength(const Block &B, BinaryStreamReader &R)
LinkGraphPassFunction createEHFrameRecorderPass(const Triple &TT, StoreFrameRangeFunction StoreFrameRange)
Creates a pass that records the address and size of the EH frame section.
unique_function< Error(LinkGraph &)> LinkGraphPassFunction
A function for mutating LinkGraphs.
Error deregisterEHFrameSection(const void *EHFrameSectionAddr, size_t EHFrameSectionSize)
Unregister frames in the given eh-frame section with libunwind.
Error registerEHFrameSection(const void *EHFrameSectionAddr, size_t EHFrameSectionSize)
Register frames in the given eh-frame section with libunwind.
uint64_t ExecutorAddrDiff
This is an optimization pass for GlobalISel generic memory operations.
auto formatv(const char *Fmt, Ts &&...Vals) -> formatv_object< decltype(std::make_tuple(support::detail::build_format_adapter(std::forward< Ts >(Vals))...))>
void sort(IteratorTy Start, IteratorTy End)
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Represents an address range in the exceutor process.
ExecutorAddrDiff size() const