[ORC] Add std::tuple support to SimplePackedSerialization.
[llvm-project.git] / llvm / lib / ExecutionEngine / JITLink / EHFrameSupport.cpp
blob8f64a0ad4d7b42aa7bf87ea10f12718231c5abd4
1 //===-------- JITLink_EHFrameSupport.cpp - JITLink eh-frame utils ---------===//
2 //
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
6 //
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"
18 namespace llvm {
19 namespace jitlink {
21 EHFrameSplitter::EHFrameSplitter(StringRef EHFrameSectionName)
22 : EHFrameSectionName(EHFrameSectionName) {}
24 Error EHFrameSplitter::operator()(LinkGraph &G) {
25 auto *EHFrame = G.findSectionByName(EHFrameSectionName);
27 if (!EHFrame) {
28 LLVM_DEBUG({
29 dbgs() << "EHFrameSplitter: No " << EHFrameSectionName
30 << " section. Nothing to do\n";
31 });
32 return Error::success();
35 LLVM_DEBUG({
36 dbgs() << "EHFrameSplitter: Processing " << EHFrameSectionName << "...\n";
37 });
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();
50 });
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) {
57 auto &B = *KV.first;
58 auto &BCache = KV.second;
59 if (auto Err = processBlock(G, B, BCache))
60 return Err;
63 return Error::success();
66 Error EHFrameSplitter::processBlock(LinkGraph &G, Block &B,
67 LinkGraph::SplitBlockCache &Cache) {
68 LLVM_DEBUG({
69 dbgs() << " Processing block at " << formatv("{0:x16}", B.getAddress())
70 << "\n";
71 });
73 // eh-frame should not contain zero-fill blocks.
74 if (B.isZeroFill())
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()),
85 G.getEndianness());
87 while (true) {
88 uint64_t RecordStartOffset = BlockReader.getOffset();
90 LLVM_DEBUG({
91 dbgs() << " Processing CFI record at "
92 << formatv("{0:x16}", B.getAddress()) << "\n";
93 });
95 uint32_t Length;
96 if (auto Err = BlockReader.readInteger(Length))
97 return Err;
98 if (Length != 0xffffffff) {
99 if (auto Err = BlockReader.skip(Length))
100 return Err;
101 } else {
102 uint64_t ExtendedLength;
103 if (auto Err = BlockReader.readInteger(ExtendedLength))
104 return Err;
105 if (auto Err = BlockReader.skip(ExtendedLength))
106 return Err;
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);
117 (void)NewBlock;
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);
131 if (!EHFrame) {
132 LLVM_DEBUG({
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");
144 LLVM_DEBUG({
145 dbgs() << "EHFrameEdgeFixer: Processing " << EHFrameSectionName << "...\n";
148 ParseContext PC(G);
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))
156 return Err;
159 // Sort eh-frame blocks into address order to ensure we visit CIEs before
160 // their child FDEs.
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))
171 return Err;
173 return Error::success();
176 Error EHFrameEdgeFixer::processBlock(ParseContext &PC, Block &B) {
178 LLVM_DEBUG({
179 dbgs() << " Processing block at " << formatv("{0:x16}", B.getAddress())
180 << "\n";
183 // eh-frame should not contain zero-fill blocks.
184 if (B.isZeroFill())
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();
213 LLVM_DEBUG({
214 dbgs() << " Processing CFI record at "
215 << formatv("{0:x16}", B.getAddress() + RecordStartOffset) << "\n";
218 // Get the record length.
219 size_t RecordRemaining;
221 uint32_t Length;
222 if (auto Err = BlockReader.readInteger(Length))
223 return Err;
224 // If Length < 0xffffffff then use the regular length field, otherwise
225 // read the extended length field.
226 if (Length != 0xffffffff)
227 RecordRemaining = Length;
228 else {
229 uint64_t ExtendedLength;
230 if (auto Err = BlockReader.readInteger(ExtendedLength))
231 return Err;
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;
243 uint32_t CIEDelta;
244 if (auto Err = BlockReader.readInteger(CIEDelta))
245 return Err;
247 if (CIEDelta == 0) {
248 if (auto Err = processCIE(PC, B, RecordStartOffset,
249 CIEDeltaFieldOffset + RecordRemaining,
250 CIEDeltaFieldOffset))
251 return Err;
252 } else {
253 if (auto Err = processFDE(PC, B, RecordStartOffset,
254 CIEDeltaFieldOffset + RecordRemaining,
255 CIEDeltaFieldOffset, CIEDelta, BlockEdges))
256 return Err;
259 // Move to the next record.
260 BlockReader.setOffset(RecordStartOffset + CIEDeltaFieldOffset +
261 RecordRemaining);
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);
281 auto &CIESymbol =
282 PC.G.addAnonymousSymbol(B, RecordOffset, RecordLength, false, false);
283 CIEInformation CIEInfo(CIESymbol);
285 uint8_t Version = 0;
286 if (auto Err = RecordReader.readInteger(Version))
287 return Err;
289 if (Version != 0x01)
290 return make_error<JITLinkError>("Bad CIE version " + Twine(Version) +
291 " (should be 0x01) in eh-frame");
293 auto AugInfo = parseAugmentationString(RecordReader);
294 if (!AugInfo)
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()))
300 return Err;
302 // Read and sanity check the code alignment factor.
304 uint64_t CodeAlignmentFactor = 0;
305 if (auto Err = RecordReader.readULEB128(CodeAlignmentFactor))
306 return Err;
307 if (CodeAlignmentFactor != 1)
308 return make_error<JITLinkError>("Unsupported CIE code alignment factor " +
309 Twine(CodeAlignmentFactor) +
310 " (expected 1)");
313 // Read and sanity check the data alignment factor.
315 int64_t DataAlignmentFactor = 0;
316 if (auto Err = RecordReader.readSLEB128(DataAlignmentFactor))
317 return Err;
318 if (DataAlignmentFactor != -8)
319 return make_error<JITLinkError>("Unsupported CIE data alignment factor " +
320 Twine(DataAlignmentFactor) +
321 " (expected -8)");
324 // Skip the return address register field.
325 if (auto Err = RecordReader.skip(1))
326 return Err;
328 uint64_t AugmentationDataLength = 0;
329 if (auto Err = RecordReader.readULEB128(AugmentationDataLength))
330 return Err;
332 uint32_t AugmentationDataStartOffset = RecordReader.getOffset();
334 uint8_t *NextField = &AugInfo->Fields[0];
335 while (uint8_t Field = *NextField++) {
336 switch (Field) {
337 case 'L': {
338 CIEInfo.FDEsHaveLSDAField = true;
339 uint8_t LSDAPointerEncoding;
340 if (auto Err = RecordReader.readInteger(LSDAPointerEncoding))
341 return Err;
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;
348 break;
350 case 'P': {
351 uint8_t PersonalityPointerEncoding = 0;
352 if (auto Err = RecordReader.readInteger(PersonalityPointerEncoding))
353 return Err;
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 "
359 "encoding " +
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))
364 return Err;
365 break;
367 case 'R': {
368 uint8_t FDEPointerEncoding;
369 if (auto Err = RecordReader.readInteger(FDEPointerEncoding))
370 return Err;
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;
377 break;
379 default:
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,
399 uint32_t CIEDelta,
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);
413 auto &FDESymbol =
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()) {
425 LLVM_DEBUG({
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;
432 else
433 return CIEInfoOrErr.takeError();
434 assert(CIEInfo->CIESymbol && "CIEInfo has no CIE symbol set");
435 B.addEdge(NegDelta32, RecordOffset + CIEDeltaFieldOffset,
436 *CIEInfo->CIESymbol, 0);
437 } else {
438 LLVM_DEBUG({
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;
444 if (EI.Addend)
445 return make_error<JITLinkError>(
446 "CIE edge at " +
447 formatv("{0:x16}", RecordAddress + CIEDeltaFieldOffset) +
448 " has non-zero addend");
449 if (auto CIEInfoOrErr = PC.findCIEInfo(EI.Target->getAddress()))
450 CIEInfo = *CIEInfoOrErr;
451 else
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);
465 if (!PCBeginPtrInfo)
466 return PCBeginPtrInfo.takeError();
467 JITTargetAddress PCBegin = PCBeginPtrInfo->first;
468 Edge::Kind PCBeginEdgeKind = PCBeginPtrInfo->second;
469 LLVM_DEBUG({
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);
475 if (!PCBeginSym)
476 return PCBeginSym.takeError();
477 B.addEdge(PCBeginEdgeKind, RecordOffset + PCBeginFieldOffset, *PCBeginSym,
479 PCBeginBlock = &PCBeginSym->getBlock();
480 } else {
481 auto &EI = PCEdgeItr->second;
482 LLVM_DEBUG({
483 dbgs() << " Already has edge at "
484 << formatv("{0:x16}", RecordAddress + PCBeginFieldOffset)
485 << " to PC at " << formatv("{0:x16}", EI.Target->getAddress());
486 if (EI.Addend)
487 dbgs() << " + " << formatv("{0:x16}", EI.Addend);
488 dbgs() << "\n";
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)))
501 return Err;
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");
507 LLVM_DEBUG({
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)))
518 return Err;
520 if (CIEInfo->FDEsHaveLSDAField) {
521 uint64_t AugmentationDataSize;
522 if (auto Err = RecordReader.readULEB128(AugmentationDataSize))
523 return Err;
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);
536 if (!LSDASym)
537 return LSDASym.takeError();
538 LLVM_DEBUG({
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);
544 } else {
545 LLVM_DEBUG({
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());
550 if (EI.Addend)
551 dbgs() << " + " << formatv("{0:x16}", EI.Addend);
552 dbgs() << "\n";
554 if (auto Err = RecordReader.skip(AugmentationDataSize))
555 return Err;
557 } else {
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;
567 uint8_t NextChar;
568 uint8_t *NextField = &AugInfo.Fields[0];
570 if (auto Err = RecordReader.readInteger(NextChar))
571 return std::move(Err);
573 while (NextChar != 0) {
574 switch (NextChar) {
575 case 'z':
576 AugInfo.AugmentationDataPresent = true;
577 break;
578 case 'e':
579 if (auto Err = RecordReader.readInteger(NextChar))
580 return std::move(Err);
581 if (NextChar != 'h')
582 return make_error<JITLinkError>("Unrecognized substring e" +
583 Twine(NextChar) +
584 " in augmentation string");
585 AugInfo.EHDataFieldPresent = true;
586 break;
587 case 'L':
588 case 'P':
589 case 'R':
590 *NextField++ = NextChar;
591 break;
592 default:
593 return make_error<JITLinkError>("Unrecognized character " +
594 Twine(NextChar) +
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)
610 return false;
612 // readEncodedPointer does not handle indirect.
613 if (PointerEncoding & DW_EH_PE_indirect)
614 return false;
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:
623 return true;
626 return false;
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:
636 return PointerSize;
637 case DW_EH_PE_udata4:
638 case DW_EH_PE_sdata4:
639 return 4;
640 case DW_EH_PE_udata8:
641 case DW_EH_PE_sdata8:
642 return 8;
643 default:
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: {
670 uint32_t Val;
671 if (auto Err = RecordReader.readInteger(Val))
672 return std::move(Err);
673 Addr = PointerFieldAddress + Val;
674 PointerEdgeKind = Delta32;
675 break;
677 case DW_EH_PE_udata8: {
678 uint64_t Val;
679 if (auto Err = RecordReader.readInteger(Val))
680 return std::move(Err);
681 Addr = PointerFieldAddress + Val;
682 PointerEdgeKind = Delta64;
683 break;
685 case DW_EH_PE_sdata4: {
686 int32_t Val;
687 if (auto Err = RecordReader.readInteger(Val))
688 return std::move(Err);
689 Addr = PointerFieldAddress + Val;
690 PointerEdgeKind = Delta32;
691 break;
693 case DW_EH_PE_sdata8: {
694 int64_t Val;
695 if (auto Err = RecordReader.readInteger(Val))
696 return std::move(Err);
697 Addr = PointerFieldAddress + Val;
698 PointerEdgeKind = Delta64;
699 break;
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())
720 CanonicalSym = Sym;
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.
728 if (CanonicalSym)
729 return *CanonicalSym;
731 // Otherwise search for a block covering the address and create a new symbol.
732 auto *B = PC.AddrToBlock.getBlockCovering(Addr);
733 if (!B)
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);
748 if (!EHFrame)
749 return Error::success();
751 LLVM_DEBUG({
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),
768 EHFrameSectionSize);
771 Error InProcessEHFrameRegistrar::deregisterEHFrames(
772 JITTargetAddress EHFrameSectionAddr, size_t EHFrameSectionSize) {
773 return orc::deregisterEHFrameSection(
774 jitTargetAddressToPointer<void *>(EHFrameSectionAddr),
775 EHFrameSectionSize);
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";
784 else
785 EHFrameSectionName = ".eh_frame";
787 auto RecordEHFrame =
788 [EHFrameSectionName,
789 StoreFrameRange = std::move(StoreRangeAddress)](LinkGraph &G) -> Error {
790 // Search for a non-empty eh-frame and record the address of the first
791 // symbol in it.
792 JITTargetAddress Addr = 0;
793 size_t Size = 0;
794 if (auto *S = G.findSectionByName(EHFrameSectionName)) {
795 auto R = SectionRange(*S);
796 Addr = R.getStart();
797 Size = R.getSize();
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