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