12#include "llvm/Config/config.h"
15#define DEBUG_TYPE "jitlink"
21 unsigned PointerSize, Edge::Kind Pointer32,
22 Edge::Kind Pointer64, Edge::Kind Delta32,
23 Edge::Kind Delta64, Edge::Kind NegDelta32)
24 : EHFrameSectionName(EHFrameSectionName), PointerSize(PointerSize),
25 Pointer32(Pointer32), Pointer64(Pointer64), Delta32(Delta32),
26 Delta64(Delta64), NegDelta32(NegDelta32) {}
29 auto *EHFrame =
G.findSectionByName(EHFrameSectionName);
33 dbgs() <<
"EHFrameEdgeFixer: No " << EHFrameSectionName
34 <<
" section in \"" <<
G.getName() <<
"\". Nothing to do.\n";
40 if (
G.getPointerSize() != 4 &&
G.getPointerSize() != 8)
42 "EHFrameEdgeFixer only supports 32 and 64 bit targets");
45 dbgs() <<
"EHFrameEdgeFixer: Processing " << EHFrameSectionName <<
" in \""
46 <<
G.getName() <<
"\"...\n";
53 for (
auto &Sec :
G.sections()) {
56 for (
auto *Sym : Sec.symbols()) {
57 auto &CurSym = PC.AddrToSym[Sym->getAddress()];
58 if (!CurSym || (std::make_tuple(Sym->getLinkage(), Sym->getScope(),
59 !Sym->hasName(), Sym->getName()) <
60 std::make_tuple(CurSym->getLinkage(), CurSym->getScope(),
61 !CurSym->hasName(), CurSym->getName())))
64 if (
auto Err = PC.AddrToBlock.addBlocks(Sec.blocks(),
71 std::vector<Block *> EHFrameBlocks;
74 return LHS->getAddress() <
RHS->getAddress();
78 for (
auto *
B : EHFrameBlocks)
79 if (
auto Err = processBlock(PC, *
B))
88 if (
auto Err = R.readInteger(
Length))
89 return std::move(Err);
97 if (
auto Err = R.readInteger(ExtendedLength))
98 return std::move(Err);
100 if (ExtendedLength > std::numeric_limits<size_t>::max())
102 "In CFI record at " +
103 formatv(
"{0:x}",
B.getAddress() + R.getOffset() - 12) +
104 ", extended length of " +
formatv(
"{0:x}", ExtendedLength) +
105 " exceeds address-range max (" +
106 formatv(
"{0:x}", std::numeric_limits<size_t>::max()));
108 return ExtendedLength;
111Error EHFrameEdgeFixer::processBlock(ParseContext &PC,
Block &
B) {
113 LLVM_DEBUG(
dbgs() <<
" Processing block at " <<
B.getAddress() <<
"\n");
118 EHFrameSectionName +
" section");
120 if (
B.getSize() == 0) {
126 BlockEdgesInfo BlockEdges;
127 for (
auto &
E :
B.edges())
128 if (
E.isRelocation()) {
130 if (BlockEdges.Multiple.contains(
E.getOffset()))
136 auto [It, Inserted] = BlockEdges.TargetMap.try_emplace(
E.getOffset(),
E);
138 BlockEdges.TargetMap.erase(It);
139 BlockEdges.Multiple.insert(
E.getOffset());
143 BinaryStreamReader BlockReader(
144 StringRef(
B.getContent().data(),
B.getContent().size()),
145 PC.G.getEndianness());
149 if (!RecordRemaining)
150 return RecordRemaining.takeError();
154 if (BlockReader.bytesRemaining() != *RecordRemaining)
156 formatv(
"{0:x16}",
B.getAddress()));
159 uint64_t CIEDeltaFieldOffset = BlockReader.getOffset();
161 if (
auto Err = BlockReader.readInteger(CIEDelta))
165 if (
auto Err = processCIE(PC,
B, CIEDeltaFieldOffset, BlockEdges))
168 if (
auto Err = processFDE(PC,
B, CIEDeltaFieldOffset, CIEDelta, BlockEdges))
175Error EHFrameEdgeFixer::processCIE(ParseContext &PC,
Block &
B,
176 size_t CIEDeltaFieldOffset,
177 const BlockEdgesInfo &BlockEdges) {
181 BinaryStreamReader RecordReader(
182 StringRef(
B.getContent().data(),
B.getContent().size()),
183 PC.G.getEndianness());
186 RecordReader.setOffset(CIEDeltaFieldOffset + 4);
188 auto &CIESymbol = PC.G.addAnonymousSymbol(
B, 0,
B.getSize(),
false,
false);
189 CIEInformation CIEInfo(CIESymbol);
192 if (
auto Err = RecordReader.readInteger(
Version))
197 " (should be 0x01) in eh-frame");
199 auto AugInfo = parseAugmentationString(RecordReader);
201 return AugInfo.takeError();
204 if (AugInfo->EHDataFieldPresent)
205 if (
auto Err = RecordReader.skip(PC.G.getPointerSize()))
211 if (
auto Err = RecordReader.readULEB128(CodeAlignmentFactor))
217 int64_t DataAlignmentFactor = 0;
218 if (
auto Err = RecordReader.readSLEB128(DataAlignmentFactor))
223 if (
auto Err = RecordReader.skip(1))
226 if (AugInfo->AugmentationDataPresent) {
228 CIEInfo.AugmentationDataPresent =
true;
230 uint64_t AugmentationDataLength = 0;
231 if (
auto Err = RecordReader.readULEB128(AugmentationDataLength))
234 uint32_t AugmentationDataStartOffset = RecordReader.getOffset();
236 uint8_t *NextField = &AugInfo->Fields[0];
237 while (uint8_t
Field = *NextField++) {
240 CIEInfo.LSDAPresent =
true;
241 if (
auto PE = readPointerEncoding(RecordReader,
B,
"LSDA"))
242 CIEInfo.LSDAEncoding = *PE;
244 return PE.takeError();
247 auto PersonalityPointerEncoding =
248 readPointerEncoding(RecordReader,
B,
"personality");
249 if (!PersonalityPointerEncoding)
250 return PersonalityPointerEncoding.takeError();
252 getOrCreateEncodedPointerEdge(
253 PC, BlockEdges, *PersonalityPointerEncoding, RecordReader,
254 B, RecordReader.getOffset(),
"personality")
260 if (
auto PE = readPointerEncoding(RecordReader,
B,
"address")) {
261 CIEInfo.AddressEncoding = *PE;
264 "Invalid address encoding DW_EH_PE_omit in CIE at " +
265 formatv(
"{0:x}",
B.getAddress().getValue()));
267 return PE.takeError();
274 if (RecordReader.getOffset() - AugmentationDataStartOffset >
275 AugmentationDataLength)
277 "data while parsing fields");
280 assert(!PC.CIEInfos.count(CIESymbol.getAddress()) &&
281 "Multiple CIEs recorded at the same address?");
282 PC.CIEInfos[CIESymbol.getAddress()] = std::move(CIEInfo);
287Error EHFrameEdgeFixer::processFDE(ParseContext &PC,
Block &
B,
288 size_t CIEDeltaFieldOffset,
290 const BlockEdgesInfo &BlockEdges) {
293 orc::ExecutorAddr RecordAddress =
B.getAddress();
295 BinaryStreamReader RecordReader(
296 StringRef(
B.getContent().data(),
B.getContent().size()),
297 PC.G.getEndianness());
300 RecordReader.setOffset(CIEDeltaFieldOffset + 4);
302 auto &FDESymbol = PC.G.addAnonymousSymbol(
B, 0,
B.getSize(),
false,
false);
304 CIEInformation *CIEInfo =
nullptr;
308 if (BlockEdges.Multiple.contains(CIEDeltaFieldOffset))
310 "CIE pointer field already has multiple edges at " +
311 formatv(
"{0:x16}", RecordAddress + CIEDeltaFieldOffset));
313 auto CIEEdgeItr = BlockEdges.TargetMap.find(CIEDeltaFieldOffset);
315 orc::ExecutorAddr CIEAddress =
318 if (CIEEdgeItr == BlockEdges.TargetMap.end()) {
320 dbgs() <<
" Adding edge at "
321 << (RecordAddress + CIEDeltaFieldOffset)
322 <<
" to CIE at: " << CIEAddress <<
"\n";
324 if (
auto CIEInfoOrErr = PC.findCIEInfo(CIEAddress))
325 CIEInfo = *CIEInfoOrErr;
327 return CIEInfoOrErr.takeError();
328 assert(CIEInfo->CIESymbol &&
"CIEInfo has no CIE symbol set");
329 B.addEdge(NegDelta32, CIEDeltaFieldOffset, *CIEInfo->CIESymbol, 0);
332 dbgs() <<
" Already has edge at "
333 << (RecordAddress + CIEDeltaFieldOffset) <<
" to CIE at "
334 << CIEAddress <<
"\n";
336 auto &EI = CIEEdgeItr->second;
340 formatv(
"{0:x16}", RecordAddress + CIEDeltaFieldOffset) +
341 " has non-zero addend");
342 if (
auto CIEInfoOrErr = PC.findCIEInfo(EI.Target->getAddress()))
343 CIEInfo = *CIEInfoOrErr;
345 return CIEInfoOrErr.takeError();
351 dbgs() <<
" Processing PC-begin at "
352 << (RecordAddress + RecordReader.getOffset()) <<
"\n";
354 if (
auto PCBegin = getOrCreateEncodedPointerEdge(
355 PC, BlockEdges, CIEInfo->AddressEncoding, RecordReader,
B,
356 RecordReader.getOffset(),
"PC begin")) {
357 assert(*PCBegin &&
"PC-begin symbol not set");
358 if ((*PCBegin)->isDefined()) {
362 dbgs() <<
" Adding keep-alive edge from target at "
363 << (*PCBegin)->getBlock().getAddress() <<
" to FDE at "
364 << RecordAddress <<
"\n";
366 (*PCBegin)->getBlock().addEdge(Edge::KeepAlive, 0, FDESymbol, 0);
369 dbgs() <<
" WARNING: Not adding keep-alive edge to FDE at "
370 << RecordAddress <<
", which points to "
371 << ((*PCBegin)->isExternal() ?
"external" :
"absolute")
372 <<
" symbol \"" << (*PCBegin)->getName()
373 <<
"\" -- FDE must be kept alive manually or it will be "
374 <<
"dead stripped.\n";
378 return PCBegin.takeError();
381 if (
auto Err = skipEncodedPointer(CIEInfo->AddressEncoding, RecordReader))
384 if (CIEInfo->AugmentationDataPresent) {
386 if (
auto Err = RecordReader.readULEB128(AugmentationDataSize))
389 if (CIEInfo->LSDAPresent)
390 if (
auto Err = getOrCreateEncodedPointerEdge(
391 PC, BlockEdges, CIEInfo->LSDAEncoding, RecordReader,
B,
392 RecordReader.getOffset(),
"LSDA")
402Expected<EHFrameEdgeFixer::AugmentationInfo>
403EHFrameEdgeFixer::parseAugmentationString(BinaryStreamReader &RecordReader) {
404 AugmentationInfo AugInfo;
406 uint8_t *NextField = &AugInfo.Fields[0];
408 if (
auto Err = RecordReader.readInteger(NextChar))
409 return std::move(Err);
411 while (NextChar != 0) {
414 AugInfo.AugmentationDataPresent =
true;
417 if (
auto Err = RecordReader.readInteger(NextChar))
418 return std::move(Err);
422 " in augmentation string");
423 AugInfo.EHDataFieldPresent =
true;
428 *NextField++ = NextChar;
433 " in augmentation string");
436 if (
auto Err = RecordReader.readInteger(NextChar))
437 return std::move(Err);
440 return std::move(AugInfo);
443Expected<uint8_t> EHFrameEdgeFixer::readPointerEncoding(BinaryStreamReader &R,
445 const char *FieldName) {
446 using namespace dwarf;
448 uint8_t PointerEncoding;
449 if (
auto Err =
R.readInteger(PointerEncoding))
450 return std::move(Err);
452 bool Supported =
true;
453 switch (PointerEncoding & 0xf) {
462 switch (PointerEncoding & 0x70) {
473 return PointerEncoding;
476 formatv(
"{0:x2}", PointerEncoding) +
" for " +
477 FieldName +
"in CFI record at " +
481Error EHFrameEdgeFixer::skipEncodedPointer(uint8_t PointerEncoding,
482 BinaryStreamReader &RecordReader) {
483 using namespace dwarf;
486 if ((PointerEncoding & 0xf) == DW_EH_PE_absptr)
487 PointerEncoding |= (PointerSize == 8) ? DW_EH_PE_udata8 :
DW_EH_PE_udata4;
489 switch (PointerEncoding & 0xf) {
492 if (
auto Err = RecordReader.skip(4))
497 if (
auto Err = RecordReader.skip(8))
506Expected<Symbol *> EHFrameEdgeFixer::getOrCreateEncodedPointerEdge(
507 ParseContext &PC,
const BlockEdgesInfo &BlockEdges, uint8_t PointerEncoding,
508 BinaryStreamReader &RecordReader,
Block &BlockToFix,
509 size_t PointerFieldOffset,
const char *FieldName) {
510 using namespace dwarf;
512 if (PointerEncoding == DW_EH_PE_omit)
518 auto EdgeI = BlockEdges.TargetMap.find(PointerFieldOffset);
519 if (EdgeI != BlockEdges.TargetMap.end()) {
521 dbgs() <<
" Existing edge at "
522 << (BlockToFix.getAddress() + PointerFieldOffset) <<
" to "
523 << FieldName <<
" at " << EdgeI->second.Target->getAddress();
524 if (EdgeI->second.Target->hasName())
525 dbgs() <<
" (" << EdgeI->second.Target->getName() <<
")";
528 if (
auto Err = skipEncodedPointer(PointerEncoding, RecordReader))
529 return std::move(Err);
530 return EdgeI->second.Target;
533 if (BlockEdges.Multiple.contains(PointerFieldOffset))
535 formatv(
"{0:x16}", PointerFieldOffset));
539 if ((PointerEncoding & 0xf) == DW_EH_PE_absptr)
540 PointerEncoding |= (PointerSize == 8) ? DW_EH_PE_udata8 :
DW_EH_PE_udata4;
544 bool Is64Bit =
false;
545 switch (PointerEncoding & 0xf) {
548 if (
auto Err = RecordReader.readInteger(Val))
549 return std::move(Err);
555 if (
auto Err = RecordReader.readInteger(Val))
556 return std::move(Err);
563 if (
auto Err = RecordReader.readInteger(FieldValue))
564 return std::move(Err);
572 Edge::Kind PtrEdgeKind = Edge::Invalid;
573 if ((PointerEncoding & 0x70) == DW_EH_PE_pcrel) {
574 Target = BlockToFix.getAddress() + PointerFieldOffset;
575 PtrEdgeKind = Is64Bit ? Delta64 : Delta32;
577 PtrEdgeKind = Is64Bit ? Pointer64 : Pointer32;
581 auto TargetSym = getOrCreateSymbol(PC, Target);
583 return TargetSym.takeError();
584 BlockToFix.addEdge(PtrEdgeKind, PointerFieldOffset, *TargetSym, 0);
587 dbgs() <<
" Adding edge at "
588 << (BlockToFix.getAddress() + PointerFieldOffset) <<
" to "
589 << FieldName <<
" at " << TargetSym->getAddress();
590 if (TargetSym->hasName())
591 dbgs() <<
" (" << TargetSym->getName() <<
")";
598Expected<Symbol &> EHFrameEdgeFixer::getOrCreateSymbol(ParseContext &PC,
599 orc::ExecutorAddr Addr) {
601 auto CanonicalSymI = PC.AddrToSym.find(Addr);
602 if (CanonicalSymI != PC.AddrToSym.end())
603 return *CanonicalSymI->second;
606 auto *
B = PC.AddrToBlock.getBlockCovering(Addr);
612 PC.G.addAnonymousSymbol(*
B, Addr -
B->getAddress(), 0,
false,
false);
613 PC.AddrToSym[S.getAddress()] = &S;
617char EHFrameNullTerminator::NullTerminatorBlockContent[4] = {0, 0, 0, 0};
620 : EHFrameSectionName(EHFrameSectionName) {}
623 auto *EHFrame =
G.findSectionByName(EHFrameSectionName);
629 dbgs() <<
"EHFrameNullTerminator adding null terminator to "
630 << EHFrameSectionName <<
"\n";
633 auto &NullTerminatorBlock =
634 G.createContentBlock(*EHFrame, NullTerminatorBlockContent,
636 G.addAnonymousSymbol(NullTerminatorBlock, 0, 4,
false,
true);
642 return EHFrameCFIBlockInspector(
nullptr);
643 if (
B.edges_size() == 1)
644 return EHFrameCFIBlockInspector(&*
B.edges().begin());
646 assert(Es.
size() >= 2 && Es.
size() <= 3 &&
"Unexpected number of edges");
648 return LHS->getOffset() <
RHS->getOffset();
650 return EHFrameCFIBlockInspector(*Es[0], *Es[1],
651 Es.
size() == 3 ? Es[2] :
nullptr);
652 return EHFrameCFIBlockInspector(
nullptr);
655EHFrameCFIBlockInspector::EHFrameCFIBlockInspector(
Edge *PersonalityEdge)
656 : PersonalityEdge(PersonalityEdge) {}
658EHFrameCFIBlockInspector::EHFrameCFIBlockInspector(Edge &CIEEdge,
661 : CIEEdge(&CIEEdge), PCBeginEdge(&PCBeginEdge), LSDAEdge(LSDAEdge) {}
664 const char *EHFrameSectionName =
nullptr;
665 switch (
G.getTargetTriple().getObjectFormat()) {
667 EHFrameSectionName =
"__TEXT,__eh_frame";
670 EHFrameSectionName =
".eh_frame";
676 if (
auto *S =
G.findSectionByName(EHFrameSectionName))
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
This file contains constants used for implementing Dwarf debug support.
OptimizedStructLayoutField Field
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.
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Represent a constant reference to a string, i.e.
static bool includeNonNull(const Block &B)
A block predicate that always includes blocks with non-null addresses.
An Addressable with content and edges.
static LLVM_ABI 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.
Represents fixups and constraints in the LinkGraph.
Represents an object file section.
Represents an address in the executor process.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
LLVM_ABI Section * getEHFrameSection(LinkGraph &G)
Returns a pointer to the DWARF eh-frame section if the graph contains a non-empty one,...
static Expected< size_t > readCFIRecordLength(const Block &B, BinaryStreamReader &R)
uint64_t ExecutorAddrDiff
This is an optimization pass for GlobalISel generic memory operations.
void append_range(Container &C, Range &&R)
Wrapper function to append range R to container C.
auto formatv(bool Validate, const char *Fmt, Ts &&...Vals)
void sort(IteratorTy Start, IteratorTy End)
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Error make_error(ArgTs &&... Args)
Make a Error instance representing failure using the given error info type.
iterator_range< pointer_iterator< WrappedIteratorT > > make_pointer_range(RangeT &&Range)