12#include "llvm/Config/config.h"
16#define DEBUG_TYPE "jitlink"
22 unsigned PointerSize, Edge::Kind Pointer32,
23 Edge::Kind Pointer64, Edge::Kind Delta32,
24 Edge::Kind Delta64, Edge::Kind NegDelta32)
25 : EHFrameSectionName(EHFrameSectionName), PointerSize(PointerSize),
26 Pointer32(Pointer32), Pointer64(Pointer64), Delta32(Delta32),
27 Delta64(Delta64), NegDelta32(NegDelta32) {}
30 auto *EHFrame =
G.findSectionByName(EHFrameSectionName);
34 dbgs() <<
"EHFrameEdgeFixer: No " << EHFrameSectionName
35 <<
" section in \"" <<
G.getName() <<
"\". Nothing to do.\n";
41 if (
G.getPointerSize() != 4 &&
G.getPointerSize() != 8)
42 return make_error<JITLinkError>(
43 "EHFrameEdgeFixer only supports 32 and 64 bit targets");
46 dbgs() <<
"EHFrameEdgeFixer: Processing " << EHFrameSectionName <<
" in \""
47 <<
G.getName() <<
"\"...\n";
54 for (
auto &Sec :
G.sections()) {
57 for (
auto *
Sym : Sec.symbols()) {
58 auto &CurSym = PC.AddrToSym[
Sym->getAddress()];
59 if (!CurSym || (std::make_tuple(
Sym->getLinkage(),
Sym->getScope(),
60 !
Sym->hasName(),
Sym->getName()) <
61 std::make_tuple(CurSym->getLinkage(), CurSym->getScope(),
62 !CurSym->hasName(), CurSym->getName())))
65 if (
auto Err = PC.AddrToBlock.addBlocks(Sec.blocks(),
72 std::vector<Block *> EHFrameBlocks;
75 return LHS->getAddress() <
RHS->getAddress();
79 for (
auto *
B : EHFrameBlocks)
80 if (
auto Err = processBlock(PC, *
B))
89 if (
auto Err = R.readInteger(
Length))
90 return std::move(Err);
98 if (
auto Err = R.readInteger(ExtendedLength))
99 return std::move(Err);
101 if (ExtendedLength > std::numeric_limits<size_t>::max())
102 return make_error<JITLinkError>(
103 "In CFI record at " +
104 formatv(
"{0:x}",
B.getAddress() + R.getOffset() - 12) +
105 ", extended length of " +
formatv(
"{0:x}", ExtendedLength) +
106 " exceeds address-range max (" +
107 formatv(
"{0:x}", std::numeric_limits<size_t>::max()));
109 return ExtendedLength;
112Error EHFrameEdgeFixer::processBlock(ParseContext &PC, Block &
B) {
114 LLVM_DEBUG(
dbgs() <<
" Processing block at " <<
B.getAddress() <<
"\n");
118 return make_error<JITLinkError>(
"Unexpected zero-fill block in " +
119 EHFrameSectionName +
" section");
121 if (
B.getSize() == 0) {
127 BlockEdgesInfo BlockEdges;
128 for (
auto &
E :
B.edges())
129 if (
E.isRelocation()) {
131 if (BlockEdges.Multiple.contains(
E.getOffset()))
137 auto [It, Inserted] = BlockEdges.TargetMap.try_emplace(
E.getOffset(),
E);
139 BlockEdges.TargetMap.erase(It);
140 BlockEdges.Multiple.insert(
E.getOffset());
144 BinaryStreamReader BlockReader(
145 StringRef(
B.getContent().data(),
B.getContent().size()),
146 PC.G.getEndianness());
150 if (!RecordRemaining)
151 return RecordRemaining.takeError();
155 if (BlockReader.bytesRemaining() != *RecordRemaining)
156 return make_error<JITLinkError>(
"Incomplete CFI record at " +
157 formatv(
"{0:x16}",
B.getAddress()));
160 uint64_t CIEDeltaFieldOffset = BlockReader.getOffset();
162 if (
auto Err = BlockReader.readInteger(CIEDelta))
166 if (
auto Err = processCIE(PC,
B, CIEDeltaFieldOffset, BlockEdges))
169 if (
auto Err = processFDE(PC,
B, CIEDeltaFieldOffset, CIEDelta, BlockEdges))
176Error EHFrameEdgeFixer::processCIE(ParseContext &PC, Block &
B,
177 size_t CIEDeltaFieldOffset,
178 const BlockEdgesInfo &BlockEdges) {
182 BinaryStreamReader RecordReader(
183 StringRef(
B.getContent().data(),
B.getContent().size()),
184 PC.G.getEndianness());
187 RecordReader.setOffset(CIEDeltaFieldOffset + 4);
189 auto &CIESymbol = PC.G.addAnonymousSymbol(
B, 0,
B.getSize(),
false,
false);
190 CIEInformation CIEInfo(CIESymbol);
193 if (
auto Err = RecordReader.readInteger(
Version))
197 return make_error<JITLinkError>(
"Bad CIE version " + Twine(
Version) +
198 " (should be 0x01) in eh-frame");
200 auto AugInfo = parseAugmentationString(RecordReader);
202 return AugInfo.takeError();
205 if (AugInfo->EHDataFieldPresent)
206 if (
auto Err = RecordReader.skip(PC.G.getPointerSize()))
212 if (
auto Err = RecordReader.readULEB128(CodeAlignmentFactor))
218 int64_t DataAlignmentFactor = 0;
219 if (
auto Err = RecordReader.readSLEB128(DataAlignmentFactor))
224 if (
auto Err = RecordReader.skip(1))
227 if (AugInfo->AugmentationDataPresent) {
229 CIEInfo.AugmentationDataPresent =
true;
231 uint64_t AugmentationDataLength = 0;
232 if (
auto Err = RecordReader.readULEB128(AugmentationDataLength))
235 uint32_t AugmentationDataStartOffset = RecordReader.getOffset();
237 uint8_t *NextField = &AugInfo->Fields[0];
241 CIEInfo.LSDAPresent =
true;
242 if (
auto PE = readPointerEncoding(RecordReader,
B,
"LSDA"))
243 CIEInfo.LSDAEncoding = *PE;
245 return PE.takeError();
248 auto PersonalityPointerEncoding =
249 readPointerEncoding(RecordReader,
B,
"personality");
250 if (!PersonalityPointerEncoding)
251 return PersonalityPointerEncoding.takeError();
253 getOrCreateEncodedPointerEdge(
254 PC, BlockEdges, *PersonalityPointerEncoding, RecordReader,
255 B, RecordReader.getOffset(),
"personality")
261 if (
auto PE = readPointerEncoding(RecordReader,
B,
"address")) {
262 CIEInfo.AddressEncoding = *PE;
264 return make_error<JITLinkError>(
265 "Invalid address encoding DW_EH_PE_omit in CIE at " +
266 formatv(
"{0:x}",
B.getAddress().getValue()));
268 return PE.takeError();
275 if (RecordReader.getOffset() - AugmentationDataStartOffset >
276 AugmentationDataLength)
277 return make_error<JITLinkError>(
"Read past the end of the augmentation "
278 "data while parsing fields");
281 assert(!PC.CIEInfos.count(CIESymbol.getAddress()) &&
282 "Multiple CIEs recorded at the same address?");
283 PC.CIEInfos[CIESymbol.getAddress()] = std::move(CIEInfo);
288Error EHFrameEdgeFixer::processFDE(ParseContext &PC, Block &
B,
289 size_t CIEDeltaFieldOffset,
291 const BlockEdgesInfo &BlockEdges) {
294 orc::ExecutorAddr RecordAddress =
B.getAddress();
296 BinaryStreamReader RecordReader(
297 StringRef(
B.getContent().data(),
B.getContent().size()),
298 PC.G.getEndianness());
301 RecordReader.setOffset(CIEDeltaFieldOffset + 4);
303 auto &FDESymbol = PC.G.addAnonymousSymbol(
B, 0,
B.getSize(),
false,
false);
305 CIEInformation *CIEInfo =
nullptr;
309 if (BlockEdges.Multiple.contains(CIEDeltaFieldOffset))
310 return make_error<JITLinkError>(
311 "CIE pointer field already has multiple edges at " +
312 formatv(
"{0:x16}", RecordAddress + CIEDeltaFieldOffset));
314 auto CIEEdgeItr = BlockEdges.TargetMap.find(CIEDeltaFieldOffset);
316 orc::ExecutorAddr CIEAddress =
319 if (CIEEdgeItr == BlockEdges.TargetMap.end()) {
321 dbgs() <<
" Adding edge at "
322 << (RecordAddress + CIEDeltaFieldOffset)
323 <<
" to CIE at: " << CIEAddress <<
"\n";
325 if (
auto CIEInfoOrErr = PC.findCIEInfo(CIEAddress))
326 CIEInfo = *CIEInfoOrErr;
328 return CIEInfoOrErr.takeError();
329 assert(CIEInfo->CIESymbol &&
"CIEInfo has no CIE symbol set");
330 B.addEdge(NegDelta32, CIEDeltaFieldOffset, *CIEInfo->CIESymbol, 0);
333 dbgs() <<
" Already has edge at "
334 << (RecordAddress + CIEDeltaFieldOffset) <<
" to CIE at "
335 << CIEAddress <<
"\n";
337 auto &EI = CIEEdgeItr->second;
339 return make_error<JITLinkError>(
341 formatv(
"{0:x16}", RecordAddress + CIEDeltaFieldOffset) +
342 " has non-zero addend");
343 if (
auto CIEInfoOrErr = PC.findCIEInfo(EI.Target->getAddress()))
344 CIEInfo = *CIEInfoOrErr;
346 return CIEInfoOrErr.takeError();
352 dbgs() <<
" Processing PC-begin at "
353 << (RecordAddress + RecordReader.getOffset()) <<
"\n";
355 if (
auto PCBegin = getOrCreateEncodedPointerEdge(
356 PC, BlockEdges, CIEInfo->AddressEncoding, RecordReader,
B,
357 RecordReader.getOffset(),
"PC begin")) {
358 assert(*PCBegin &&
"PC-begin symbol not set");
359 if ((*PCBegin)->isDefined()) {
363 dbgs() <<
" Adding keep-alive edge from target at "
364 << (*PCBegin)->getBlock().getAddress() <<
" to FDE at "
365 << RecordAddress <<
"\n";
367 (*PCBegin)->getBlock().addEdge(Edge::KeepAlive, 0, FDESymbol, 0);
370 dbgs() <<
" WARNING: Not adding keep-alive edge to FDE at "
371 << RecordAddress <<
", which points to "
372 << ((*PCBegin)->isExternal() ?
"external" :
"absolute")
373 <<
" symbol \"" << (*PCBegin)->getName()
374 <<
"\" -- FDE must be kept alive manually or it will be "
375 <<
"dead stripped.\n";
379 return PCBegin.takeError();
382 if (
auto Err = skipEncodedPointer(CIEInfo->AddressEncoding, RecordReader))
385 if (CIEInfo->AugmentationDataPresent) {
387 if (
auto Err = RecordReader.readULEB128(AugmentationDataSize))
390 if (CIEInfo->LSDAPresent)
391 if (
auto Err = getOrCreateEncodedPointerEdge(
392 PC, BlockEdges, CIEInfo->LSDAEncoding, RecordReader,
B,
393 RecordReader.getOffset(),
"LSDA")
403Expected<EHFrameEdgeFixer::AugmentationInfo>
404EHFrameEdgeFixer::parseAugmentationString(BinaryStreamReader &RecordReader) {
405 AugmentationInfo AugInfo;
407 uint8_t *NextField = &AugInfo.Fields[0];
409 if (
auto Err = RecordReader.readInteger(NextChar))
410 return std::move(Err);
412 while (NextChar != 0) {
415 AugInfo.AugmentationDataPresent =
true;
418 if (
auto Err = RecordReader.readInteger(NextChar))
419 return std::move(Err);
421 return make_error<JITLinkError>(
"Unrecognized substring e" +
423 " in augmentation string");
424 AugInfo.EHDataFieldPresent =
true;
429 *NextField++ = NextChar;
432 return make_error<JITLinkError>(
"Unrecognized character " +
434 " in augmentation string");
437 if (
auto Err = RecordReader.readInteger(NextChar))
438 return std::move(Err);
441 return std::move(AugInfo);
444Expected<uint8_t> EHFrameEdgeFixer::readPointerEncoding(BinaryStreamReader &R,
446 const char *FieldName) {
447 using namespace dwarf;
450 if (
auto Err =
R.readInteger(PointerEncoding))
451 return std::move(Err);
453 bool Supported =
true;
454 switch (PointerEncoding & 0xf) {
463 switch (PointerEncoding & 0x70) {
474 return PointerEncoding;
476 return make_error<JITLinkError>(
"Unsupported pointer encoding " +
477 formatv(
"{0:x2}", PointerEncoding) +
" for " +
478 FieldName +
"in CFI record at " +
482Error EHFrameEdgeFixer::skipEncodedPointer(
uint8_t PointerEncoding,
483 BinaryStreamReader &RecordReader) {
484 using namespace dwarf;
487 if ((PointerEncoding & 0xf) == DW_EH_PE_absptr)
488 PointerEncoding |= (PointerSize == 8) ? DW_EH_PE_udata8 : DW_EH_PE_udata4;
490 switch (PointerEncoding & 0xf) {
493 if (
auto Err = RecordReader.skip(4))
498 if (
auto Err = RecordReader.skip(8))
507Expected<Symbol *> EHFrameEdgeFixer::getOrCreateEncodedPointerEdge(
508 ParseContext &PC,
const BlockEdgesInfo &BlockEdges,
uint8_t PointerEncoding,
509 BinaryStreamReader &RecordReader, Block &BlockToFix,
510 size_t PointerFieldOffset,
const char *FieldName) {
511 using namespace dwarf;
513 if (PointerEncoding == DW_EH_PE_omit)
519 auto EdgeI = BlockEdges.TargetMap.find(PointerFieldOffset);
520 if (EdgeI != BlockEdges.TargetMap.end()) {
522 dbgs() <<
" Existing edge at "
523 << (BlockToFix.getAddress() + PointerFieldOffset) <<
" to "
524 << FieldName <<
" at " << EdgeI->second.Target->getAddress();
525 if (EdgeI->second.Target->hasName())
526 dbgs() <<
" (" << EdgeI->second.Target->getName() <<
")";
529 if (
auto Err = skipEncodedPointer(PointerEncoding, RecordReader))
530 return std::move(Err);
531 return EdgeI->second.Target;
534 if (BlockEdges.Multiple.contains(PointerFieldOffset))
535 return make_error<JITLinkError>(
"Multiple relocations at offset " +
536 formatv(
"{0:x16}", PointerFieldOffset));
545 bool Is64Bit =
false;
546 switch (PointerEncoding & 0xf) {
549 if (
auto Err = RecordReader.readInteger(Val))
550 return std::move(Err);
556 if (
auto Err = RecordReader.readInteger(Val))
557 return std::move(Err);
564 if (
auto Err = RecordReader.readInteger(FieldValue))
565 return std::move(Err);
573 Edge::Kind PtrEdgeKind = Edge::Invalid;
574 if ((PointerEncoding & 0x70) == DW_EH_PE_pcrel) {
575 Target = BlockToFix.getAddress() + PointerFieldOffset;
576 PtrEdgeKind = Is64Bit ? Delta64 : Delta32;
578 PtrEdgeKind = Is64Bit ? Pointer64 : Pointer32;
582 auto TargetSym = getOrCreateSymbol(PC, Target);
584 return TargetSym.takeError();
585 BlockToFix.addEdge(PtrEdgeKind, PointerFieldOffset, *TargetSym, 0);
588 dbgs() <<
" Adding edge at "
589 << (BlockToFix.getAddress() + PointerFieldOffset) <<
" to "
590 << FieldName <<
" at " << TargetSym->getAddress();
591 if (TargetSym->hasName())
592 dbgs() <<
" (" << TargetSym->getName() <<
")";
599Expected<Symbol &> EHFrameEdgeFixer::getOrCreateSymbol(ParseContext &PC,
600 orc::ExecutorAddr
Addr) {
602 auto CanonicalSymI = PC.AddrToSym.find(
Addr);
603 if (CanonicalSymI != PC.AddrToSym.end())
604 return *CanonicalSymI->second;
607 auto *
B = PC.AddrToBlock.getBlockCovering(
Addr);
609 return make_error<JITLinkError>(
"No symbol or block covering address " +
613 PC.G.addAnonymousSymbol(*
B,
Addr -
B->getAddress(), 0,
false,
false);
614 PC.AddrToSym[S.getAddress()] = &S;
618char EHFrameNullTerminator::NullTerminatorBlockContent[4] = {0, 0, 0, 0};
621 : EHFrameSectionName(EHFrameSectionName) {}
624 auto *EHFrame =
G.findSectionByName(EHFrameSectionName);
630 dbgs() <<
"EHFrameNullTerminator adding null terminator to "
631 << EHFrameSectionName <<
"\n";
634 auto &NullTerminatorBlock =
635 G.createContentBlock(*EHFrame, NullTerminatorBlockContent,
637 G.addAnonymousSymbol(NullTerminatorBlock, 0, 4,
false,
true);
644 if (
B.edges_size() == 1)
647 assert(Es.
size() >= 2 && Es.
size() <= 3 &&
"Unexpected number of edges");
649 return LHS->getOffset() <
RHS->getOffset();
652 Es.
size() == 3 ? Es[2] :
nullptr);
656EHFrameCFIBlockInspector::EHFrameCFIBlockInspector(
Edge *PersonalityEdge)
657 : PersonalityEdge(PersonalityEdge) {}
659EHFrameCFIBlockInspector::EHFrameCFIBlockInspector(Edge &CIEEdge,
662 : CIEEdge(&CIEEdge), PCBeginEdge(&PCBeginEdge), LSDAEdge(LSDAEdge) {}
665 const char *EHFrameSectionName =
nullptr;
666 switch (
G.getTargetTriple().getObjectFormat()) {
668 EHFrameSectionName =
"__TEXT,__eh_frame";
671 EHFrameSectionName =
".eh_frame";
677 if (
auto *S =
G.findSectionByName(EHFrameSectionName))
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
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.
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.
StringRef - 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.
Inspect an eh-frame CFI record.
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.
iterator_range< pointer_iterator< WrappedIteratorT > > make_pointer_range(RangeT &&Range)