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 //===----------------------------------------------------------------------===// 8 9 #include "EHFrameSupportImpl.h" 10 11 #include "llvm/BinaryFormat/Dwarf.h" 12 #include "llvm/Config/config.h" 13 #include "llvm/ExecutionEngine/JITLink/DWARFRecordSectionSplitter.h" 14 #include "llvm/ExecutionEngine/Orc/TargetProcess/RegisterEHFrames.h" 15 #include "llvm/Support/DynamicLibrary.h" 16 17 #define DEBUG_TYPE "jitlink" 18 19 namespace llvm { 20 namespace jitlink { 21 22 EHFrameEdgeFixer::EHFrameEdgeFixer(StringRef EHFrameSectionName, 23 unsigned PointerSize, Edge::Kind Pointer32, 24 Edge::Kind Pointer64, Edge::Kind Delta32, 25 Edge::Kind Delta64, Edge::Kind NegDelta32) 26 : EHFrameSectionName(EHFrameSectionName), PointerSize(PointerSize), 27 Pointer32(Pointer32), Pointer64(Pointer64), Delta32(Delta32), 28 Delta64(Delta64), NegDelta32(NegDelta32) {} 29 30 Error EHFrameEdgeFixer::operator()(LinkGraph &G) { 31 auto *EHFrame = G.findSectionByName(EHFrameSectionName); 32 33 if (!EHFrame) { 34 LLVM_DEBUG({ 35 dbgs() << "EHFrameEdgeFixer: No " << EHFrameSectionName 36 << " section in \"" << G.getName() << "\". Nothing to do.\n"; 37 }); 38 return Error::success(); 39 } 40 41 // Check that we support the graph's pointer size. 42 if (G.getPointerSize() != 4 && G.getPointerSize() != 8) 43 return make_error<JITLinkError>( 44 "EHFrameEdgeFixer only supports 32 and 64 bit targets"); 45 46 LLVM_DEBUG({ 47 dbgs() << "EHFrameEdgeFixer: Processing " << EHFrameSectionName << " in \"" 48 << G.getName() << "\"...\n"; 49 }); 50 51 ParseContext PC(G); 52 53 // Build a map of all blocks and symbols in the text sections. We will use 54 // these for finding / building edge targets when processing FDEs. 55 for (auto &Sec : G.sections()) { 56 // Just record the most-canonical symbol (for eh-frame purposes) at each 57 // address. 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()))) 64 CurSym = Sym; 65 } 66 if (auto Err = PC.AddrToBlock.addBlocks(Sec.blocks(), 67 BlockAddressMap::includeNonNull)) 68 return Err; 69 } 70 71 // Sort eh-frame blocks into address order to ensure we visit CIEs before 72 // their child FDEs. 73 std::vector<Block *> EHFrameBlocks; 74 for (auto *B : EHFrame->blocks()) 75 EHFrameBlocks.push_back(B); 76 llvm::sort(EHFrameBlocks, [](const Block *LHS, const Block *RHS) { 77 return LHS->getAddress() < RHS->getAddress(); 78 }); 79 80 // Loop over the blocks in address order. 81 for (auto *B : EHFrameBlocks) 82 if (auto Err = processBlock(PC, *B)) 83 return Err; 84 85 return Error::success(); 86 } 87 88 Error EHFrameEdgeFixer::processBlock(ParseContext &PC, Block &B) { 89 90 LLVM_DEBUG(dbgs() << " Processing block at " << B.getAddress() << "\n"); 91 92 // eh-frame should not contain zero-fill blocks. 93 if (B.isZeroFill()) 94 return make_error<JITLinkError>("Unexpected zero-fill block in " + 95 EHFrameSectionName + " section"); 96 97 if (B.getSize() == 0) { 98 LLVM_DEBUG(dbgs() << " Block is empty. Skipping.\n"); 99 return Error::success(); 100 } 101 102 // Find the offsets of any existing edges from this block. 103 BlockEdgeMap BlockEdges; 104 for (auto &E : B.edges()) 105 if (E.isRelocation()) { 106 if (BlockEdges.count(E.getOffset())) 107 return make_error<JITLinkError>( 108 "Multiple relocations at offset " + 109 formatv("{0:x16}", E.getOffset()) + " in " + EHFrameSectionName + 110 " block at address " + formatv("{0:x16}", B.getAddress())); 111 112 BlockEdges[E.getOffset()] = EdgeTarget(E); 113 } 114 115 CIEInfosMap CIEInfos; 116 BinaryStreamReader BlockReader( 117 StringRef(B.getContent().data(), B.getContent().size()), 118 PC.G.getEndianness()); 119 while (!BlockReader.empty()) { 120 size_t RecordStartOffset = BlockReader.getOffset(); 121 122 LLVM_DEBUG({ 123 dbgs() << " Processing CFI record at " 124 << (B.getAddress() + RecordStartOffset) << "\n"; 125 }); 126 127 // Get the record length. 128 size_t RecordRemaining; 129 { 130 uint32_t Length; 131 if (auto Err = BlockReader.readInteger(Length)) 132 return Err; 133 // If Length < 0xffffffff then use the regular length field, otherwise 134 // read the extended length field. 135 if (Length != 0xffffffff) 136 RecordRemaining = Length; 137 else { 138 uint64_t ExtendedLength; 139 if (auto Err = BlockReader.readInteger(ExtendedLength)) 140 return Err; 141 RecordRemaining = ExtendedLength; 142 } 143 } 144 145 if (BlockReader.bytesRemaining() < RecordRemaining) 146 return make_error<JITLinkError>( 147 "Incomplete CFI record at " + 148 formatv("{0:x16}", B.getAddress() + RecordStartOffset)); 149 150 // Read the CIE delta for this record. 151 uint64_t CIEDeltaFieldOffset = BlockReader.getOffset() - RecordStartOffset; 152 uint32_t CIEDelta; 153 if (auto Err = BlockReader.readInteger(CIEDelta)) 154 return Err; 155 156 if (CIEDelta == 0) { 157 if (auto Err = processCIE(PC, B, RecordStartOffset, 158 CIEDeltaFieldOffset + RecordRemaining, 159 CIEDeltaFieldOffset, BlockEdges)) 160 return Err; 161 } else { 162 if (auto Err = processFDE(PC, B, RecordStartOffset, 163 CIEDeltaFieldOffset + RecordRemaining, 164 CIEDeltaFieldOffset, CIEDelta, BlockEdges)) 165 return Err; 166 } 167 168 // Move to the next record. 169 BlockReader.setOffset(RecordStartOffset + CIEDeltaFieldOffset + 170 RecordRemaining); 171 } 172 173 return Error::success(); 174 } 175 176 Error EHFrameEdgeFixer::processCIE(ParseContext &PC, Block &B, 177 size_t RecordOffset, size_t RecordLength, 178 size_t CIEDeltaFieldOffset, 179 const BlockEdgeMap &BlockEdges) { 180 181 LLVM_DEBUG(dbgs() << " Record is CIE\n"); 182 183 auto RecordContent = B.getContent().slice(RecordOffset, RecordLength); 184 BinaryStreamReader RecordReader( 185 StringRef(RecordContent.data(), RecordContent.size()), 186 PC.G.getEndianness()); 187 188 // Skip past the CIE delta field: we've already processed this far. 189 RecordReader.setOffset(CIEDeltaFieldOffset + 4); 190 191 auto &CIESymbol = 192 PC.G.addAnonymousSymbol(B, RecordOffset, RecordLength, false, false); 193 CIEInformation CIEInfo(CIESymbol); 194 195 uint8_t Version = 0; 196 if (auto Err = RecordReader.readInteger(Version)) 197 return Err; 198 199 if (Version != 0x01) 200 return make_error<JITLinkError>("Bad CIE version " + Twine(Version) + 201 " (should be 0x01) in eh-frame"); 202 203 auto AugInfo = parseAugmentationString(RecordReader); 204 if (!AugInfo) 205 return AugInfo.takeError(); 206 207 // Skip the EH Data field if present. 208 if (AugInfo->EHDataFieldPresent) 209 if (auto Err = RecordReader.skip(PC.G.getPointerSize())) 210 return Err; 211 212 // Read and validate the code alignment factor. 213 { 214 uint64_t CodeAlignmentFactor = 0; 215 if (auto Err = RecordReader.readULEB128(CodeAlignmentFactor)) 216 return Err; 217 } 218 219 // Read and validate the data alignment factor. 220 { 221 int64_t DataAlignmentFactor = 0; 222 if (auto Err = RecordReader.readSLEB128(DataAlignmentFactor)) 223 return Err; 224 } 225 226 // Skip the return address register field. 227 if (auto Err = RecordReader.skip(1)) 228 return Err; 229 230 if (AugInfo->AugmentationDataPresent) { 231 232 CIEInfo.AugmentationDataPresent = true; 233 234 uint64_t AugmentationDataLength = 0; 235 if (auto Err = RecordReader.readULEB128(AugmentationDataLength)) 236 return Err; 237 238 uint32_t AugmentationDataStartOffset = RecordReader.getOffset(); 239 240 uint8_t *NextField = &AugInfo->Fields[0]; 241 while (uint8_t Field = *NextField++) { 242 switch (Field) { 243 case 'L': 244 CIEInfo.LSDAPresent = true; 245 if (auto PE = readPointerEncoding(RecordReader, B, "LSDA")) 246 CIEInfo.LSDAEncoding = *PE; 247 else 248 return PE.takeError(); 249 break; 250 case 'P': { 251 auto PersonalityPointerEncoding = 252 readPointerEncoding(RecordReader, B, "personality"); 253 if (!PersonalityPointerEncoding) 254 return PersonalityPointerEncoding.takeError(); 255 if (auto Err = 256 getOrCreateEncodedPointerEdge( 257 PC, BlockEdges, *PersonalityPointerEncoding, RecordReader, 258 B, RecordOffset + RecordReader.getOffset(), "personality") 259 .takeError()) 260 return Err; 261 break; 262 } 263 case 'R': 264 if (auto PE = readPointerEncoding(RecordReader, B, "address")) { 265 CIEInfo.AddressEncoding = *PE; 266 if (CIEInfo.AddressEncoding == dwarf::DW_EH_PE_omit) 267 return make_error<JITLinkError>( 268 "Invalid address encoding DW_EH_PE_omit in CIE at " + 269 formatv("{0:x}", (B.getAddress() + RecordOffset).getValue())); 270 } else 271 return PE.takeError(); 272 break; 273 default: 274 llvm_unreachable("Invalid augmentation string field"); 275 } 276 } 277 278 if (RecordReader.getOffset() - AugmentationDataStartOffset > 279 AugmentationDataLength) 280 return make_error<JITLinkError>("Read past the end of the augmentation " 281 "data while parsing fields"); 282 } 283 284 assert(!PC.CIEInfos.count(CIESymbol.getAddress()) && 285 "Multiple CIEs recorded at the same address?"); 286 PC.CIEInfos[CIESymbol.getAddress()] = std::move(CIEInfo); 287 288 return Error::success(); 289 } 290 291 Error EHFrameEdgeFixer::processFDE(ParseContext &PC, Block &B, 292 size_t RecordOffset, size_t RecordLength, 293 size_t CIEDeltaFieldOffset, 294 uint32_t CIEDelta, 295 const BlockEdgeMap &BlockEdges) { 296 LLVM_DEBUG(dbgs() << " Record is FDE\n"); 297 298 orc::ExecutorAddr RecordAddress = B.getAddress() + RecordOffset; 299 300 auto RecordContent = B.getContent().slice(RecordOffset, RecordLength); 301 BinaryStreamReader RecordReader( 302 StringRef(RecordContent.data(), RecordContent.size()), 303 PC.G.getEndianness()); 304 305 // Skip past the CIE delta field: we've already read this far. 306 RecordReader.setOffset(CIEDeltaFieldOffset + 4); 307 308 auto &FDESymbol = 309 PC.G.addAnonymousSymbol(B, RecordOffset, RecordLength, false, false); 310 311 CIEInformation *CIEInfo = nullptr; 312 313 { 314 // Process the CIE pointer field. 315 auto CIEEdgeItr = BlockEdges.find(RecordOffset + CIEDeltaFieldOffset); 316 orc::ExecutorAddr CIEAddress = 317 RecordAddress + orc::ExecutorAddrDiff(CIEDeltaFieldOffset) - 318 orc::ExecutorAddrDiff(CIEDelta); 319 if (CIEEdgeItr == BlockEdges.end()) { 320 321 LLVM_DEBUG({ 322 dbgs() << " Adding edge at " 323 << (RecordAddress + CIEDeltaFieldOffset) 324 << " to CIE at: " << CIEAddress << "\n"; 325 }); 326 if (auto CIEInfoOrErr = PC.findCIEInfo(CIEAddress)) 327 CIEInfo = *CIEInfoOrErr; 328 else 329 return CIEInfoOrErr.takeError(); 330 assert(CIEInfo->CIESymbol && "CIEInfo has no CIE symbol set"); 331 B.addEdge(NegDelta32, RecordOffset + CIEDeltaFieldOffset, 332 *CIEInfo->CIESymbol, 0); 333 } else { 334 LLVM_DEBUG({ 335 dbgs() << " Already has edge at " 336 << (RecordAddress + CIEDeltaFieldOffset) << " to CIE at " 337 << CIEAddress << "\n"; 338 }); 339 auto &EI = CIEEdgeItr->second; 340 if (EI.Addend) 341 return make_error<JITLinkError>( 342 "CIE edge at " + 343 formatv("{0:x16}", RecordAddress + CIEDeltaFieldOffset) + 344 " has non-zero addend"); 345 if (auto CIEInfoOrErr = PC.findCIEInfo(EI.Target->getAddress())) 346 CIEInfo = *CIEInfoOrErr; 347 else 348 return CIEInfoOrErr.takeError(); 349 } 350 } 351 352 // Process the PC-Begin field. 353 LLVM_DEBUG({ 354 dbgs() << " Processing PC-begin at " 355 << (RecordAddress + RecordReader.getOffset()) << "\n"; 356 }); 357 if (auto PCBegin = getOrCreateEncodedPointerEdge( 358 PC, BlockEdges, CIEInfo->AddressEncoding, RecordReader, B, 359 RecordReader.getOffset(), "PC begin")) { 360 assert(*PCBegin && "PC-begin symbol not set"); 361 // Add a keep-alive edge from the FDE target to the FDE to ensure that the 362 // FDE is kept alive if its target is. 363 LLVM_DEBUG({ 364 dbgs() << " Adding keep-alive edge from target at " 365 << (*PCBegin)->getBlock().getAddress() << " to FDE at " 366 << RecordAddress << "\n"; 367 }); 368 (*PCBegin)->getBlock().addEdge(Edge::KeepAlive, 0, FDESymbol, 0); 369 } else 370 return PCBegin.takeError(); 371 372 // Skip over the PC range size field. 373 if (auto Err = skipEncodedPointer(CIEInfo->AddressEncoding, RecordReader)) 374 return Err; 375 376 if (CIEInfo->AugmentationDataPresent) { 377 uint64_t AugmentationDataSize; 378 if (auto Err = RecordReader.readULEB128(AugmentationDataSize)) 379 return Err; 380 381 if (CIEInfo->LSDAPresent) 382 if (auto Err = getOrCreateEncodedPointerEdge( 383 PC, BlockEdges, CIEInfo->LSDAEncoding, RecordReader, B, 384 RecordReader.getOffset(), "LSDA") 385 .takeError()) 386 return Err; 387 } else { 388 LLVM_DEBUG(dbgs() << " Record does not have LSDA field.\n"); 389 } 390 391 return Error::success(); 392 } 393 394 Expected<EHFrameEdgeFixer::AugmentationInfo> 395 EHFrameEdgeFixer::parseAugmentationString(BinaryStreamReader &RecordReader) { 396 AugmentationInfo AugInfo; 397 uint8_t NextChar; 398 uint8_t *NextField = &AugInfo.Fields[0]; 399 400 if (auto Err = RecordReader.readInteger(NextChar)) 401 return std::move(Err); 402 403 while (NextChar != 0) { 404 switch (NextChar) { 405 case 'z': 406 AugInfo.AugmentationDataPresent = true; 407 break; 408 case 'e': 409 if (auto Err = RecordReader.readInteger(NextChar)) 410 return std::move(Err); 411 if (NextChar != 'h') 412 return make_error<JITLinkError>("Unrecognized substring e" + 413 Twine(NextChar) + 414 " in augmentation string"); 415 AugInfo.EHDataFieldPresent = true; 416 break; 417 case 'L': 418 case 'P': 419 case 'R': 420 *NextField++ = NextChar; 421 break; 422 default: 423 return make_error<JITLinkError>("Unrecognized character " + 424 Twine(NextChar) + 425 " in augmentation string"); 426 } 427 428 if (auto Err = RecordReader.readInteger(NextChar)) 429 return std::move(Err); 430 } 431 432 return std::move(AugInfo); 433 } 434 435 Expected<uint8_t> EHFrameEdgeFixer::readPointerEncoding(BinaryStreamReader &R, 436 Block &InBlock, 437 const char *FieldName) { 438 using namespace dwarf; 439 440 uint8_t PointerEncoding; 441 if (auto Err = R.readInteger(PointerEncoding)) 442 return std::move(Err); 443 444 bool Supported = true; 445 switch (PointerEncoding & 0xf) { 446 case DW_EH_PE_uleb128: 447 case DW_EH_PE_udata2: 448 case DW_EH_PE_sleb128: 449 case DW_EH_PE_sdata2: 450 Supported = false; 451 break; 452 } 453 if (Supported) { 454 switch (PointerEncoding & 0x70) { 455 case DW_EH_PE_textrel: 456 case DW_EH_PE_datarel: 457 case DW_EH_PE_funcrel: 458 case DW_EH_PE_aligned: 459 Supported = false; 460 break; 461 } 462 } 463 464 if (Supported) 465 return PointerEncoding; 466 467 return make_error<JITLinkError>("Unsupported pointer encoding " + 468 formatv("{0:x2}", PointerEncoding) + " for " + 469 FieldName + "in CFI record at " + 470 formatv("{0:x16}", InBlock.getAddress())); 471 } 472 473 Error EHFrameEdgeFixer::skipEncodedPointer(uint8_t PointerEncoding, 474 BinaryStreamReader &RecordReader) { 475 using namespace dwarf; 476 477 // Switch absptr to corresponding udata encoding. 478 if ((PointerEncoding & 0xf) == DW_EH_PE_absptr) 479 PointerEncoding |= (PointerSize == 8) ? DW_EH_PE_udata8 : DW_EH_PE_udata4; 480 481 switch (PointerEncoding & 0xf) { 482 case DW_EH_PE_udata4: 483 case DW_EH_PE_sdata4: 484 if (auto Err = RecordReader.skip(4)) 485 return Err; 486 break; 487 case DW_EH_PE_udata8: 488 case DW_EH_PE_sdata8: 489 if (auto Err = RecordReader.skip(8)) 490 return Err; 491 break; 492 default: 493 llvm_unreachable("Unrecognized encoding"); 494 } 495 return Error::success(); 496 } 497 498 Expected<Symbol *> EHFrameEdgeFixer::getOrCreateEncodedPointerEdge( 499 ParseContext &PC, const BlockEdgeMap &BlockEdges, uint8_t PointerEncoding, 500 BinaryStreamReader &RecordReader, Block &BlockToFix, 501 size_t PointerFieldOffset, const char *FieldName) { 502 using namespace dwarf; 503 504 if (PointerEncoding == DW_EH_PE_omit) 505 return nullptr; 506 507 // If there's already an edge here then just skip the encoded pointer and 508 // return the edge's target. 509 { 510 auto EdgeI = BlockEdges.find(PointerFieldOffset); 511 if (EdgeI != BlockEdges.end()) { 512 LLVM_DEBUG({ 513 dbgs() << " Existing edge at " 514 << (BlockToFix.getAddress() + PointerFieldOffset) << " to " 515 << FieldName << " at " << EdgeI->second.Target->getAddress(); 516 if (EdgeI->second.Target->hasName()) 517 dbgs() << " (" << EdgeI->second.Target->getName() << ")"; 518 dbgs() << "\n"; 519 }); 520 if (auto Err = skipEncodedPointer(PointerEncoding, RecordReader)) 521 return std::move(Err); 522 return EdgeI->second.Target; 523 } 524 } 525 526 // Switch absptr to corresponding udata encoding. 527 if ((PointerEncoding & 0xf) == DW_EH_PE_absptr) 528 PointerEncoding |= (PointerSize == 8) ? DW_EH_PE_udata8 : DW_EH_PE_udata4; 529 530 // We need to create an edge. Start by reading the field value. 531 uint64_t FieldValue; 532 bool Is64Bit = false; 533 switch (PointerEncoding & 0xf) { 534 case DW_EH_PE_udata4: { 535 uint32_t Val; 536 if (auto Err = RecordReader.readInteger(Val)) 537 return std::move(Err); 538 FieldValue = Val; 539 break; 540 } 541 case DW_EH_PE_sdata4: { 542 uint32_t Val; 543 if (auto Err = RecordReader.readInteger(Val)) 544 return std::move(Err); 545 FieldValue = Val; 546 break; 547 } 548 case DW_EH_PE_udata8: 549 case DW_EH_PE_sdata8: 550 Is64Bit = true; 551 if (auto Err = RecordReader.readInteger(FieldValue)) 552 return std::move(Err); 553 break; 554 default: 555 llvm_unreachable("Unsupported encoding"); 556 } 557 558 // Find the edge target and edge kind to use. 559 orc::ExecutorAddr Target; 560 Edge::Kind PtrEdgeKind = Edge::Invalid; 561 if ((PointerEncoding & 0x70) == DW_EH_PE_pcrel) { 562 Target = BlockToFix.getAddress() + PointerFieldOffset; 563 PtrEdgeKind = Is64Bit ? Delta64 : Delta32; 564 } else 565 PtrEdgeKind = Is64Bit ? Pointer64 : Pointer32; 566 Target += FieldValue; 567 568 // Find or create a symbol to point the edge at. 569 auto TargetSym = getOrCreateSymbol(PC, Target); 570 if (!TargetSym) 571 return TargetSym.takeError(); 572 BlockToFix.addEdge(PtrEdgeKind, PointerFieldOffset, *TargetSym, 0); 573 574 LLVM_DEBUG({ 575 dbgs() << " Adding edge at " 576 << (BlockToFix.getAddress() + PointerFieldOffset) << " to " 577 << FieldName << " at " << TargetSym->getAddress(); 578 if (TargetSym->hasName()) 579 dbgs() << " (" << TargetSym->getName() << ")"; 580 dbgs() << "\n"; 581 }); 582 583 return &*TargetSym; 584 } 585 586 Expected<Symbol &> EHFrameEdgeFixer::getOrCreateSymbol(ParseContext &PC, 587 orc::ExecutorAddr Addr) { 588 // See whether we have a canonical symbol for the given address already. 589 auto CanonicalSymI = PC.AddrToSym.find(Addr); 590 if (CanonicalSymI != PC.AddrToSym.end()) 591 return *CanonicalSymI->second; 592 593 // Otherwise search for a block covering the address and create a new symbol. 594 auto *B = PC.AddrToBlock.getBlockCovering(Addr); 595 if (!B) 596 return make_error<JITLinkError>("No symbol or block covering address " + 597 formatv("{0:x16}", Addr)); 598 599 auto &S = 600 PC.G.addAnonymousSymbol(*B, Addr - B->getAddress(), 0, false, false); 601 PC.AddrToSym[S.getAddress()] = &S; 602 return S; 603 } 604 605 char EHFrameNullTerminator::NullTerminatorBlockContent[4] = {0, 0, 0, 0}; 606 607 EHFrameNullTerminator::EHFrameNullTerminator(StringRef EHFrameSectionName) 608 : EHFrameSectionName(EHFrameSectionName) {} 609 610 Error EHFrameNullTerminator::operator()(LinkGraph &G) { 611 auto *EHFrame = G.findSectionByName(EHFrameSectionName); 612 613 if (!EHFrame) 614 return Error::success(); 615 616 LLVM_DEBUG({ 617 dbgs() << "EHFrameNullTerminator adding null terminator to " 618 << EHFrameSectionName << "\n"; 619 }); 620 621 auto &NullTerminatorBlock = 622 G.createContentBlock(*EHFrame, NullTerminatorBlockContent, 623 orc::ExecutorAddr(~uint64_t(4)), 1, 0); 624 G.addAnonymousSymbol(NullTerminatorBlock, 0, 4, false, true); 625 return Error::success(); 626 } 627 628 EHFrameRegistrar::~EHFrameRegistrar() = default; 629 630 Error InProcessEHFrameRegistrar::registerEHFrames( 631 orc::ExecutorAddrRange EHFrameSection) { 632 return orc::registerEHFrameSection(EHFrameSection.Start.toPtr<void *>(), 633 EHFrameSection.size()); 634 } 635 636 Error InProcessEHFrameRegistrar::deregisterEHFrames( 637 orc::ExecutorAddrRange EHFrameSection) { 638 return orc::deregisterEHFrameSection(EHFrameSection.Start.toPtr<void *>(), 639 EHFrameSection.size()); 640 } 641 642 LinkGraphPassFunction 643 createEHFrameRecorderPass(const Triple &TT, 644 StoreFrameRangeFunction StoreRangeAddress) { 645 const char *EHFrameSectionName = nullptr; 646 if (TT.getObjectFormat() == Triple::MachO) 647 EHFrameSectionName = "__TEXT,__eh_frame"; 648 else 649 EHFrameSectionName = ".eh_frame"; 650 651 auto RecordEHFrame = 652 [EHFrameSectionName, 653 StoreFrameRange = std::move(StoreRangeAddress)](LinkGraph &G) -> Error { 654 // Search for a non-empty eh-frame and record the address of the first 655 // symbol in it. 656 orc::ExecutorAddr Addr; 657 size_t Size = 0; 658 if (auto *S = G.findSectionByName(EHFrameSectionName)) { 659 auto R = SectionRange(*S); 660 Addr = R.getStart(); 661 Size = R.getSize(); 662 } 663 if (!Addr && Size != 0) 664 return make_error<JITLinkError>( 665 StringRef(EHFrameSectionName) + 666 " section can not have zero address with non-zero size"); 667 StoreFrameRange(Addr, Size); 668 return Error::success(); 669 }; 670 671 return RecordEHFrame; 672 } 673 674 } // end namespace jitlink 675 } // end namespace llvm 676