1 //===- CompactUnwindSupportImpl.h - Compact Unwind format impl --*- C++ -*-===// 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 // Compact Unwind format support implementation details. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #ifndef LIB_EXECUTIONENGINE_JITLINK_COMPACTUNWINDSUPPORTIMPL_H 14 #define LIB_EXECUTIONENGINE_JITLINK_COMPACTUNWINDSUPPORTIMPL_H 15 16 #include "llvm/ADT/STLExtras.h" 17 #include "llvm/ExecutionEngine/JITLink/MachO.h" 18 #include "llvm/Support/Debug.h" 19 #include "llvm/Support/Endian.h" 20 21 #define DEBUG_TYPE "jitlink_cu" 22 23 namespace llvm { 24 namespace jitlink { 25 26 /// Split blocks in an __LD,__compact_unwind section on record boundaries. 27 /// When this function returns edges within each record are guaranteed to be 28 /// sorted by offset. 29 Error splitCompactUnwindBlocks(LinkGraph &G, Section &CompactUnwindSection, 30 size_t RecordSize); 31 32 /// CRTP base for compact unwind traits classes. Automatically provides derived 33 /// constants. 34 /// 35 /// FIXME: Passing PtrSize as a template parameter is a hack to work around a 36 /// bug in older MSVC compilers (until at least MSVC 15) where constexpr 37 /// fields in the CRTP impl class were not visible to the base class. 38 /// Once we no longer need to support these compilers the PtrSize 39 /// template argument should be removed and PointerSize should be 40 /// defined as a member in the CRTP Impl classes. 41 template <typename CRTPImpl, size_t PtrSize> struct CompactUnwindTraits { 42 static constexpr size_t PointerSize = PtrSize; 43 static constexpr size_t Size = 3 * PointerSize + 2 * 4; 44 static constexpr size_t FnFieldOffset = 0; 45 static constexpr size_t SizeFieldOffset = FnFieldOffset + PointerSize; 46 static constexpr size_t EncodingFieldOffset = SizeFieldOffset + 4; 47 static constexpr size_t PersonalityFieldOffset = EncodingFieldOffset + 4; 48 static constexpr size_t LSDAFieldOffset = 49 PersonalityFieldOffset + PointerSize; 50 51 static uint32_t readPCRangeSize(ArrayRef<char> RecordContent) { 52 assert(SizeFieldOffset + 4 <= RecordContent.size() && 53 "Truncated CU record?"); 54 return support::endian::read32<CRTPImpl::Endianness>(RecordContent.data() + 55 SizeFieldOffset); 56 } 57 58 static uint32_t readEncoding(ArrayRef<char> RecordContent) { 59 assert(EncodingFieldOffset + 4 <= RecordContent.size() && 60 "Truncated CU record?"); 61 return support::endian::read32<CRTPImpl::Endianness>(RecordContent.data() + 62 EncodingFieldOffset); 63 } 64 65 static std::optional<uint32_t> encodeDWARFOffset(size_t Delta) { 66 uint32_t Encoded = 67 static_cast<uint32_t>(Delta) & CRTPImpl::DWARFSectionOffsetMask; 68 if (Encoded != Delta) 69 return std::nullopt; 70 return Encoded; 71 } 72 }; 73 74 /// Architecture specific implementation of CompactUnwindManager. 75 template <typename CURecTraits> class CompactUnwindManager { 76 public: 77 CompactUnwindManager(StringRef CompactUnwindSectionName, 78 StringRef UnwindInfoSectionName, 79 StringRef EHFrameSectionName) 80 : CompactUnwindSectionName(CompactUnwindSectionName), 81 UnwindInfoSectionName(UnwindInfoSectionName), 82 EHFrameSectionName(EHFrameSectionName) {} 83 84 // Split compact unwind records, add keep-alive edges from functions to 85 // compact unwind records, and from compact unwind records to FDEs where 86 // needed. 87 // 88 // This method must be called *after* __eh_frame has been processed: it 89 // assumes that eh-frame records have been split up and keep-alive edges have 90 // been inserted. 91 Error prepareForPrune(LinkGraph &G) { 92 Section *CUSec = G.findSectionByName(CompactUnwindSectionName); 93 if (!CUSec || CUSec->empty()) { 94 LLVM_DEBUG({ 95 dbgs() << "Compact unwind: No compact unwind info for " << G.getName() 96 << "\n"; 97 }); 98 return Error::success(); 99 } 100 101 LLVM_DEBUG({ 102 dbgs() << "Compact unwind: preparing " << G.getName() << " for prune\n"; 103 }); 104 105 Section *EHFrameSec = G.findSectionByName(EHFrameSectionName); 106 107 if (auto Err = splitCompactUnwindBlocks(G, *CUSec, CURecTraits::Size)) 108 return Err; 109 110 LLVM_DEBUG({ 111 dbgs() << " Preparing " << CUSec->blocks_size() << " blocks in " 112 << CompactUnwindSectionName << "\n"; 113 }); 114 115 for (auto *B : CUSec->blocks()) { 116 117 // Find target function edge. 118 Edge *PCBeginEdge = nullptr; 119 for (auto &E : B->edges_at(CURecTraits::FnFieldOffset)) { 120 PCBeginEdge = &E; 121 break; 122 } 123 124 if (!PCBeginEdge) 125 return make_error<JITLinkError>( 126 "In " + G.getName() + ", compact unwind record at " + 127 formatv("{0:x}", B->getAddress()) + " has no pc-begin edge"); 128 129 if (!PCBeginEdge->getTarget().isDefined()) 130 return make_error<JITLinkError>( 131 "In " + G.getName() + ", compact unwind record at " + 132 formatv("{0:x}", B->getAddress()) + " points at external symbol " + 133 *PCBeginEdge->getTarget().getName()); 134 135 auto &Fn = PCBeginEdge->getTarget(); 136 137 if (!Fn.isDefined()) { 138 LLVM_DEBUG({ 139 dbgs() << "In " << CompactUnwindSectionName << " for " << G.getName() 140 << " encountered unexpected pc-edge to undefined symbol " 141 << Fn.getName() << "\n"; 142 }); 143 continue; 144 } 145 146 uint32_t Encoding = CURecTraits::readEncoding(B->getContent()); 147 bool NeedsDWARF = CURecTraits::encodingSpecifiesDWARF(Encoding); 148 149 LLVM_DEBUG({ 150 dbgs() << " Found record for function "; 151 if (Fn.hasName()) 152 dbgs() << Fn.getName(); 153 else 154 dbgs() << "<anon @ " << Fn.getAddress() << '>'; 155 dbgs() << ": encoding = " << formatv("{0:x}", Encoding); 156 if (NeedsDWARF) 157 dbgs() << " (needs DWARF)"; 158 dbgs() << "\n"; 159 }); 160 161 auto &CURecSym = 162 G.addAnonymousSymbol(*B, 0, CURecTraits::Size, false, false); 163 164 bool KeepAliveAlreadyPresent = false; 165 if (EHFrameSec) { 166 Edge *KeepAliveEdge = nullptr; 167 for (auto &E : Fn.getBlock().edges_at(0)) { 168 if (E.getKind() == Edge::KeepAlive && E.getTarget().isDefined() && 169 &E.getTarget().getSection() == EHFrameSec) { 170 KeepAliveEdge = &E; 171 break; 172 } 173 } 174 175 if (KeepAliveEdge) { 176 // Found a keep-alive edge to an FDE in the eh-frame. Switch the keep 177 // alive edge to point to the CU and if the CU needs DWARF then add 178 // an extra keep-alive edge from the CU to the FDE. 179 auto &FDE = KeepAliveEdge->getTarget(); 180 KeepAliveEdge->setTarget(CURecSym); 181 KeepAliveAlreadyPresent = true; 182 if (NeedsDWARF) { 183 LLVM_DEBUG({ 184 dbgs() << " Adding keep-alive edge to FDE at " 185 << FDE.getAddress() << "\n"; 186 }); 187 B->addEdge(Edge::KeepAlive, 0, FDE, 0); 188 } 189 } else { 190 if (NeedsDWARF) 191 return make_error<JITLinkError>( 192 "In " + G.getName() + ", compact unwind recard ot " + 193 formatv("{0:x}", B->getAddress()) + 194 " needs DWARF, but no FDE was found"); 195 } 196 } else { 197 if (NeedsDWARF) 198 return make_error<JITLinkError>( 199 "In " + G.getName() + ", compact unwind recard ot " + 200 formatv("{0:x}", B->getAddress()) + " needs DWARF, but no " + 201 EHFrameSectionName + " section exists"); 202 } 203 204 if (!KeepAliveAlreadyPresent) { 205 // No FDE edge. We'll need to add a new edge from the function back 206 // to the CU record. 207 Fn.getBlock().addEdge(Edge::KeepAlive, 0, CURecSym, 0); 208 } 209 } 210 211 return Error::success(); 212 } 213 214 /// Process all __compact_unwind records and reserve space for __unwind_info. 215 Error processAndReserveUnwindInfo(LinkGraph &G) { 216 // Bail out early if no unwind info. 217 Section *CUSec = G.findSectionByName(CompactUnwindSectionName); 218 if (!CUSec) 219 return Error::success(); 220 221 // The __LD/__compact_unwind section is only used as input for the linker. 222 // We'll create a new __TEXT,__unwind_info section for unwind info output. 223 CUSec->setMemLifetime(orc::MemLifetime::NoAlloc); 224 225 // Find / make a mach-header to act as the base for unwind-info offsets 226 // (and to report the arch / subarch to libunwind). 227 if (auto Err = getOrCreateCompactUnwindBase(G)) 228 return Err; 229 230 // Error out if there's already unwind-info in the graph: We have no idea 231 // how to merge unwind-info sections. 232 if (G.findSectionByName(UnwindInfoSectionName)) 233 return make_error<JITLinkError>("In " + G.getName() + ", " + 234 UnwindInfoSectionName + 235 " already exists"); 236 237 // Process the __compact_unwind section to build the Records vector that 238 // we'll use for writing the __unwind_info section. 239 if (auto Err = processCompactUnwind(G, *CUSec)) 240 return Err; 241 242 // Calculate the size of __unwind_info. 243 size_t UnwindInfoSectionSize = 244 UnwindInfoSectionHeaderSize + 245 Personalities.size() * PersonalityEntrySize + 246 (NumSecondLevelPages + 1) * IndexEntrySize + NumLSDAs * LSDAEntrySize + 247 NumSecondLevelPages * SecondLevelPageHeaderSize + 248 Records.size() * SecondLevelPageEntrySize; 249 250 LLVM_DEBUG({ 251 dbgs() << "In " << G.getName() << ", reserving " 252 << formatv("{0:x}", UnwindInfoSectionSize) << " bytes for " 253 << UnwindInfoSectionName << "\n"; 254 }); 255 256 // Create the __unwind_info section and reserve space for it. 257 Section &UnwindInfoSec = 258 G.createSection(UnwindInfoSectionName, orc::MemProt::Read); 259 260 auto UnwindInfoSectionContent = G.allocateBuffer(UnwindInfoSectionSize); 261 memset(UnwindInfoSectionContent.data(), 0, UnwindInfoSectionContent.size()); 262 auto &B = G.createMutableContentBlock( 263 UnwindInfoSec, UnwindInfoSectionContent, orc::ExecutorAddr(), 8, 0); 264 265 // Add Keep-alive edges from the __unwind_info block to all of the target 266 // functions. 267 for (auto &R : Records) 268 B.addEdge(Edge::KeepAlive, 0, *R.Fn, 0); 269 270 return Error::success(); 271 } 272 273 Error writeUnwindInfo(LinkGraph &G) { 274 Section *CUSec = G.findSectionByName(CompactUnwindSectionName); 275 if (!CUSec || CUSec->empty()) 276 return Error::success(); 277 278 Section *UnwindInfoSec = G.findSectionByName(UnwindInfoSectionName); 279 if (!UnwindInfoSec) 280 return make_error<JITLinkError>("In " + G.getName() + ", " + 281 UnwindInfoSectionName + 282 " missing after allocation"); 283 284 if (UnwindInfoSec->blocks_size() != 1) 285 return make_error<JITLinkError>( 286 "In " + G.getName() + ", " + UnwindInfoSectionName + 287 " contains more than one block post-allocation"); 288 289 LLVM_DEBUG( 290 { dbgs() << "Writing unwind info for " << G.getName() << "...\n"; }); 291 292 mergeRecords(); 293 294 auto &UnwindInfoBlock = **UnwindInfoSec->blocks().begin(); 295 auto Content = UnwindInfoBlock.getMutableContent(G); 296 BinaryStreamWriter Writer( 297 {reinterpret_cast<uint8_t *>(Content.data()), Content.size()}, 298 CURecTraits::Endianness); 299 300 // __unwind_info format, from mach-o/compact_unwind_encoding.h on Darwin: 301 // 302 // #define UNWIND_SECTION_VERSION 1 303 // struct unwind_info_section_header 304 // { 305 // uint32_t version; // UNWIND_SECTION_VERSION 306 // uint32_t commonEncodingsArraySectionOffset; 307 // uint32_t commonEncodingsArrayCount; 308 // uint32_t personalityArraySectionOffset; 309 // uint32_t personalityArrayCount; 310 // uint32_t indexSectionOffset; 311 // uint32_t indexCount; 312 // // compact_unwind_encoding_t[] 313 // // uint32_t personalities[] 314 // // unwind_info_section_header_index_entry[] 315 // // unwind_info_section_header_lsda_index_entry[] 316 // }; 317 318 if (auto Err = writeHeader(G, Writer)) 319 return Err; 320 321 // Skip common encodings: JITLink doesn't use them. 322 323 if (auto Err = writePersonalities(G, Writer)) 324 return Err; 325 326 // Calculate the offset to the LSDAs. 327 size_t SectionOffsetToLSDAs = 328 Writer.getOffset() + (NumSecondLevelPages + 1) * IndexEntrySize; 329 330 // Calculate offset to the 1st second-level page. 331 size_t SectionOffsetToSecondLevelPages = 332 SectionOffsetToLSDAs + NumLSDAs * LSDAEntrySize; 333 334 if (auto Err = writeIndexes(G, Writer, SectionOffsetToLSDAs, 335 SectionOffsetToSecondLevelPages)) 336 return Err; 337 338 if (auto Err = writeLSDAs(G, Writer)) 339 return Err; 340 341 if (auto Err = writeSecondLevelPages(G, Writer)) 342 return Err; 343 344 LLVM_DEBUG({ 345 dbgs() << " Wrote " << formatv("{0:x}", Writer.getOffset()) 346 << " bytes of unwind info.\n"; 347 }); 348 349 return Error::success(); 350 } 351 352 private: 353 // Calculate the size of unwind-info. 354 static constexpr size_t MaxPersonalities = 4; 355 static constexpr size_t PersonalityShift = 28; 356 357 static constexpr size_t UnwindInfoSectionHeaderSize = 4 * 7; 358 static constexpr size_t PersonalityEntrySize = 4; 359 static constexpr size_t IndexEntrySize = 3 * 4; 360 static constexpr size_t LSDAEntrySize = 2 * 4; 361 static constexpr size_t SecondLevelPageSize = 4096; 362 static constexpr size_t SecondLevelPageHeaderSize = 8; 363 static constexpr size_t SecondLevelPageEntrySize = 8; 364 static constexpr size_t NumRecordsPerSecondLevelPage = 365 (SecondLevelPageSize - SecondLevelPageHeaderSize) / 366 SecondLevelPageEntrySize; 367 368 struct CompactUnwindRecord { 369 Symbol *Fn = nullptr; 370 uint32_t Size = 0; 371 uint32_t Encoding = 0; 372 Symbol *LSDA = nullptr; 373 Symbol *FDE = nullptr; 374 }; 375 376 Error processCompactUnwind(LinkGraph &G, Section &CUSec) { 377 // TODO: Reset NumLSDAs, Personalities and CompactUnwindRecords if 378 // processing more than once. 379 assert(NumLSDAs == 0 && "NumLSDAs should be zero"); 380 assert(Records.empty() && "CompactUnwindRecords vector should be empty."); 381 assert(Personalities.empty() && "Personalities vector should be empty."); 382 383 SmallVector<CompactUnwindRecord> NonUniquedRecords; 384 NonUniquedRecords.reserve(CUSec.blocks_size()); 385 386 // Process __compact_unwind blocks. 387 for (auto *B : CUSec.blocks()) { 388 CompactUnwindRecord R; 389 R.Encoding = CURecTraits::readEncoding(B->getContent()); 390 for (auto &E : B->edges()) { 391 switch (E.getOffset()) { 392 case CURecTraits::FnFieldOffset: 393 // This could be the function-pointer, or the FDE keep-alive. Check 394 // the type to decide. 395 if (E.getKind() == Edge::KeepAlive) 396 R.FDE = &E.getTarget(); 397 else 398 R.Fn = &E.getTarget(); 399 break; 400 case CURecTraits::PersonalityFieldOffset: { 401 // Add the Personality to the Personalities map and update the 402 // encoding. 403 size_t PersonalityIdx = 0; 404 for (; PersonalityIdx != Personalities.size(); ++PersonalityIdx) 405 if (Personalities[PersonalityIdx] == &E.getTarget()) 406 break; 407 if (PersonalityIdx == MaxPersonalities) 408 return make_error<JITLinkError>( 409 "In " + G.getName() + 410 ", __compact_unwind contains too many personalities (max " + 411 formatv("{}", MaxPersonalities) + ")"); 412 if (PersonalityIdx == Personalities.size()) 413 Personalities.push_back(&E.getTarget()); 414 415 R.Encoding |= (PersonalityIdx + 1) << PersonalityShift; 416 break; 417 } 418 case CURecTraits::LSDAFieldOffset: 419 ++NumLSDAs; 420 R.LSDA = &E.getTarget(); 421 break; 422 default: 423 return make_error<JITLinkError>("In " + G.getName() + 424 ", compact unwind record at " + 425 formatv("{0:x}", B->getAddress()) + 426 " has unrecognized edge at offset " + 427 formatv("{0:x}", E.getOffset())); 428 } 429 } 430 Records.push_back(R); 431 } 432 433 // Sort the records into ascending order. 434 llvm::sort(Records, [](const CompactUnwindRecord &LHS, 435 const CompactUnwindRecord &RHS) { 436 return LHS.Fn->getAddress() < RHS.Fn->getAddress(); 437 }); 438 439 // Calculate the number of second-level pages required. 440 NumSecondLevelPages = (Records.size() + NumRecordsPerSecondLevelPage - 1) / 441 NumRecordsPerSecondLevelPage; 442 443 // Convert personality symbols to GOT entry pointers. 444 typename CURecTraits::GOTManager GOT(G); 445 for (auto &Personality : Personalities) 446 Personality = &GOT.getEntryForTarget(G, *Personality); 447 448 LLVM_DEBUG({ 449 dbgs() << " In " << G.getName() << ", " << CompactUnwindSectionName 450 << ": raw records = " << Records.size() 451 << ", personalities = " << Personalities.size() 452 << ", lsdas = " << NumLSDAs << "\n"; 453 }); 454 455 return Error::success(); 456 } 457 458 void mergeRecords() { 459 SmallVector<CompactUnwindRecord> NonUniqued = std::move(Records); 460 Records.reserve(NonUniqued.size()); 461 462 Records.push_back(NonUniqued.front()); 463 for (size_t I = 1; I != NonUniqued.size(); ++I) { 464 auto &Next = NonUniqued[I]; 465 auto &Last = Records.back(); 466 467 bool NextNeedsDWARF = CURecTraits::encodingSpecifiesDWARF(Next.Encoding); 468 bool CannotBeMerged = CURecTraits::encodingCannotBeMerged(Next.Encoding); 469 if (NextNeedsDWARF || (Next.Encoding != Last.Encoding) || 470 CannotBeMerged || Next.LSDA || Last.LSDA) 471 Records.push_back(Next); 472 } 473 474 // Recalculate derived values that may have changed. 475 NumSecondLevelPages = (Records.size() + NumRecordsPerSecondLevelPage - 1) / 476 NumRecordsPerSecondLevelPage; 477 } 478 479 Error writeHeader(LinkGraph &G, BinaryStreamWriter &W) { 480 if (!isUInt<32>(NumSecondLevelPages + 1)) 481 return make_error<JITLinkError>("In " + G.getName() + ", too many " + 482 UnwindInfoSectionName + 483 "second-level pages required"); 484 485 // Write __unwind_info header. 486 size_t IndexArrayOffset = UnwindInfoSectionHeaderSize + 487 Personalities.size() * PersonalityEntrySize; 488 489 cantFail(W.writeInteger<uint32_t>(1)); 490 cantFail(W.writeInteger<uint32_t>(UnwindInfoSectionHeaderSize)); 491 cantFail(W.writeInteger<uint32_t>(0)); 492 cantFail(W.writeInteger<uint32_t>(UnwindInfoSectionHeaderSize)); 493 cantFail(W.writeInteger<uint32_t>(Personalities.size())); 494 cantFail(W.writeInteger<uint32_t>(IndexArrayOffset)); 495 cantFail(W.writeInteger<uint32_t>(NumSecondLevelPages + 1)); 496 497 return Error::success(); 498 } 499 500 Error writePersonalities(LinkGraph &G, BinaryStreamWriter &W) { 501 // Write personalities. 502 for (auto *PSym : Personalities) { 503 auto Delta = PSym->getAddress() - CompactUnwindBase->getAddress(); 504 if (!isUInt<32>(Delta)) 505 return makePersonalityRangeError(G, *PSym); 506 cantFail(W.writeInteger<uint32_t>(Delta)); 507 } 508 return Error::success(); 509 } 510 511 Error writeIndexes(LinkGraph &G, BinaryStreamWriter &W, 512 size_t SectionOffsetToLSDAs, 513 size_t SectionOffsetToSecondLevelPages) { 514 // Assume that function deltas are ok in this method -- we'll error 515 // check all of them when we write the second level pages. 516 517 // Write the header index entries. 518 size_t RecordIdx = 0; 519 size_t NumPreviousLSDAs = 0; 520 for (auto &R : Records) { 521 // If this record marks the start of a new second level page. 522 if (RecordIdx % NumRecordsPerSecondLevelPage == 0) { 523 auto FnDelta = R.Fn->getAddress() - CompactUnwindBase->getAddress(); 524 auto SecondLevelPageOffset = 525 SectionOffsetToSecondLevelPages + 526 SecondLevelPageSize * (RecordIdx / NumRecordsPerSecondLevelPage); 527 auto LSDAOffset = 528 SectionOffsetToLSDAs + NumPreviousLSDAs * LSDAEntrySize; 529 530 cantFail(W.writeInteger<uint32_t>(FnDelta)); 531 cantFail(W.writeInteger<uint32_t>(SecondLevelPageOffset)); 532 cantFail(W.writeInteger<uint32_t>(LSDAOffset)); 533 } 534 if (R.LSDA) 535 ++NumPreviousLSDAs; 536 ++RecordIdx; 537 } 538 539 // Write the index array terminator. 540 { 541 auto FnEndDelta = 542 Records.back().Fn->getRange().End - CompactUnwindBase->getAddress(); 543 544 if (LLVM_UNLIKELY(!isUInt<32>(FnEndDelta))) 545 return make_error<JITLinkError>( 546 "In " + G.getName() + " " + UnwindInfoSectionName + 547 ", delta to end of functions " + 548 formatv("{0:x}", Records.back().Fn->getRange().End) + 549 " exceeds 32 bits"); 550 551 cantFail(W.writeInteger<uint32_t>(FnEndDelta)); 552 cantFail(W.writeInteger<uint32_t>(0)); 553 cantFail(W.writeInteger<uint32_t>(SectionOffsetToSecondLevelPages)); 554 } 555 556 return Error::success(); 557 } 558 559 Error writeLSDAs(LinkGraph &G, BinaryStreamWriter &W) { 560 // As with writeIndexes, assume that function deltas are ok for now. 561 for (auto &R : Records) { 562 if (R.LSDA) { 563 auto FnDelta = R.Fn->getAddress() - CompactUnwindBase->getAddress(); 564 auto LSDADelta = R.LSDA->getAddress() - CompactUnwindBase->getAddress(); 565 566 if (LLVM_UNLIKELY(!isUInt<32>(LSDADelta))) 567 return make_error<JITLinkError>( 568 "In " + G.getName() + " " + UnwindInfoSectionName + 569 ", delta to lsda at " + formatv("{0:x}", R.LSDA->getAddress()) + 570 " exceeds 32 bits"); 571 572 cantFail(W.writeInteger<uint32_t>(FnDelta)); 573 cantFail(W.writeInteger<uint32_t>(LSDADelta)); 574 } 575 } 576 577 return Error::success(); 578 } 579 580 Error writeSecondLevelPages(LinkGraph &G, BinaryStreamWriter &W) { 581 size_t RecordIdx = 0; 582 583 for (auto &R : Records) { 584 // When starting a new second-level page, write the page header: 585 // 586 // 2 : uint32_t -- UNWIND_SECOND_LEVEL_REGULAR 587 // 8 : uint16_t -- size of second level page table header 588 // count : uint16_t -- num entries in this second-level page 589 if (RecordIdx % NumRecordsPerSecondLevelPage == 0) { 590 constexpr uint32_t SecondLevelPageHeaderKind = 2; 591 constexpr uint16_t SecondLevelPageHeaderSize = 8; 592 uint16_t SecondLevelPageNumEntries = 593 std::min(Records.size() - RecordIdx, NumRecordsPerSecondLevelPage); 594 595 cantFail(W.writeInteger<uint32_t>(SecondLevelPageHeaderKind)); 596 cantFail(W.writeInteger<uint16_t>(SecondLevelPageHeaderSize)); 597 cantFail(W.writeInteger<uint16_t>(SecondLevelPageNumEntries)); 598 } 599 600 // Write entry. 601 auto FnDelta = R.Fn->getAddress() - CompactUnwindBase->getAddress(); 602 603 if (LLVM_UNLIKELY(!isUInt<32>(FnDelta))) 604 return make_error<JITLinkError>( 605 "In " + G.getName() + " " + UnwindInfoSectionName + 606 ", delta to function at " + formatv("{0:x}", R.Fn->getAddress()) + 607 " exceeds 32 bits"); 608 609 auto Encoding = R.Encoding; 610 611 if (LLVM_UNLIKELY(CURecTraits::encodingSpecifiesDWARF(R.Encoding))) { 612 if (!EHFrameBase) 613 EHFrameBase = SectionRange(R.FDE->getSection()).getStart(); 614 auto FDEDelta = R.FDE->getAddress() - EHFrameBase; 615 616 if (auto EncodedFDEDelta = CURecTraits::encodeDWARFOffset(FDEDelta)) 617 Encoding |= *EncodedFDEDelta; 618 else 619 return make_error<JITLinkError>( 620 "In " + G.getName() + " " + UnwindInfoSectionName + 621 ", cannot encode delta " + formatv("{0:x}", FDEDelta) + 622 " to FDE at " + formatv("{0:x}", R.FDE->getAddress())); 623 } 624 625 cantFail(W.writeInteger<uint32_t>(FnDelta)); 626 cantFail(W.writeInteger<uint32_t>(Encoding)); 627 628 ++RecordIdx; 629 } 630 631 return Error::success(); 632 } 633 634 Error getOrCreateCompactUnwindBase(LinkGraph &G) { 635 auto Name = G.intern("__jitlink$libunwind_dso_base"); 636 CompactUnwindBase = G.findAbsoluteSymbolByName(Name); 637 if (!CompactUnwindBase) { 638 if (auto LocalCUBase = getOrCreateLocalMachOHeader(G)) { 639 CompactUnwindBase = &*LocalCUBase; 640 auto &B = LocalCUBase->getBlock(); 641 G.addDefinedSymbol(B, 0, *Name, B.getSize(), Linkage::Strong, 642 Scope::Local, false, true); 643 } else 644 return LocalCUBase.takeError(); 645 } 646 CompactUnwindBase->setLive(true); 647 return Error::success(); 648 } 649 650 Error makePersonalityRangeError(LinkGraph &G, Symbol &PSym) { 651 std::string ErrMsg; 652 { 653 raw_string_ostream ErrStream(ErrMsg); 654 ErrStream << "In " << G.getName() << " " << UnwindInfoSectionName 655 << ", personality "; 656 if (PSym.hasName()) 657 ErrStream << PSym.getName() << " "; 658 ErrStream << "at " << PSym.getAddress() 659 << " is out of 32-bit delta range of compact-unwind base at " 660 << CompactUnwindBase->getAddress(); 661 } 662 return make_error<JITLinkError>(std::move(ErrMsg)); 663 } 664 665 StringRef CompactUnwindSectionName; 666 StringRef UnwindInfoSectionName; 667 StringRef EHFrameSectionName; 668 Symbol *CompactUnwindBase = nullptr; 669 orc::ExecutorAddr EHFrameBase; 670 671 size_t NumLSDAs = 0; 672 size_t NumSecondLevelPages = 0; 673 SmallVector<Symbol *, MaxPersonalities> Personalities; 674 SmallVector<CompactUnwindRecord> Records; 675 }; 676 677 } // end namespace jitlink 678 } // end namespace llvm 679 680 #undef DEBUG_TYPE 681 682 #endif // LIB_EXECUTIONENGINE_JITLINK_COMPACTUNWINDSUPPORTIMPL_H 683