99 : CompactUnwindSectionName(CompactUnwindSectionName),
100 UnwindInfoSectionName(UnwindInfoSectionName),
101 EHFrameSectionName(EHFrameSectionName) {}
111 Section *CUSec =
G.findSectionByName(CompactUnwindSectionName);
112 if (!CUSec || CUSec->
empty()) {
114 dbgs() <<
"Compact unwind: No compact unwind info for " <<
G.getName()
121 dbgs() <<
"Compact unwind: preparing " <<
G.getName() <<
" for prune\n";
124 Section *EHFrameSec =
G.findSectionByName(EHFrameSectionName);
131 << CompactUnwindSectionName <<
"\n";
134 for (
auto *
B : CUSec->
blocks()) {
137 Edge *PCBeginEdge =
nullptr;
138 for (
auto &
E :
B->edges_at(CURecTraits::FnFieldOffset)) {
145 "In " +
G.getName() +
", compact unwind record at " +
146 formatv(
"{0:x}",
B->getAddress()) +
" has no pc-begin edge");
150 "In " +
G.getName() +
", compact unwind record at " +
151 formatv(
"{0:x}",
B->getAddress()) +
" points at external symbol " +
156 if (!Fn.isDefined()) {
158 dbgs() <<
"In " << CompactUnwindSectionName <<
" for " <<
G.getName()
159 <<
" encountered unexpected pc-edge to undefined symbol "
160 << Fn.getName() <<
"\n";
165 uint32_t Encoding = CURecTraits::readEncoding(
B->getContent());
166 bool NeedsDWARF = CURecTraits::encodingSpecifiesDWARF(Encoding);
169 dbgs() <<
" Found record for function ";
171 dbgs() << Fn.getName();
173 dbgs() <<
"<anon @ " << Fn.getAddress() <<
'>';
174 dbgs() <<
": encoding = " <<
formatv(
"{0:x}", Encoding);
176 dbgs() <<
" (needs DWARF)";
181 G.addAnonymousSymbol(*
B, 0, CURecTraits::Size,
false,
false);
183 bool KeepAliveAlreadyPresent =
false;
185 Edge *KeepAliveEdge =
nullptr;
186 for (
auto &
E : Fn.getBlock().edges_at(0)) {
187 if (
E.getKind() == Edge::KeepAlive &&
E.getTarget().isDefined() &&
188 &
E.getTarget().getSection() == EHFrameSec) {
200 KeepAliveAlreadyPresent =
true;
203 dbgs() <<
" Adding keep-alive edge to FDE at "
204 << FDE.getAddress() <<
"\n";
206 B->addEdge(Edge::KeepAlive, 0, FDE, 0);
211 "In " +
G.getName() +
", compact unwind recard ot " +
213 " needs DWARF, but no FDE was found");
218 "In " +
G.getName() +
", compact unwind recard ot " +
219 formatv(
"{0:x}",
B->getAddress()) +
" needs DWARF, but no " +
220 EHFrameSectionName +
" section exists");
223 if (!KeepAliveAlreadyPresent) {
226 Fn.getBlock().addEdge(Edge::KeepAlive, 0, CURecSym, 0);
236 Section *CUSec =
G.findSectionByName(CompactUnwindSectionName);
246 if (
auto Err = getOrCreateCompactUnwindBase(
G))
251 if (
G.findSectionByName(UnwindInfoSectionName))
253 UnwindInfoSectionName +
258 if (
auto Err = processCompactUnwind(
G, *CUSec))
262 size_t UnwindInfoSectionSize =
263 UnwindInfoSectionHeaderSize +
264 Personalities.size() * PersonalityEntrySize +
265 (NumSecondLevelPages + 1) * IndexEntrySize + NumLSDAs * LSDAEntrySize +
266 NumSecondLevelPages * SecondLevelPageHeaderSize +
267 Records.size() * SecondLevelPageEntrySize;
270 dbgs() <<
"In " <<
G.getName() <<
", reserving "
271 <<
formatv(
"{0:x}", UnwindInfoSectionSize) <<
" bytes for "
272 << UnwindInfoSectionName <<
"\n";
279 auto UnwindInfoSectionContent =
G.allocateBuffer(UnwindInfoSectionSize);
280 memset(UnwindInfoSectionContent.data(), 0, UnwindInfoSectionContent.size());
281 auto &
B =
G.createMutableContentBlock(
286 for (
auto &R : Records)
287 B.addEdge(Edge::KeepAlive, 0, *R.Fn, 0);
293 Section *CUSec =
G.findSectionByName(CompactUnwindSectionName);
294 if (!CUSec || CUSec->
empty())
297 Section *UnwindInfoSec =
G.findSectionByName(UnwindInfoSectionName);
300 UnwindInfoSectionName +
301 " missing after allocation");
305 "In " +
G.getName() +
", " + UnwindInfoSectionName +
306 " contains more than one block post-allocation");
309 {
dbgs() <<
"Writing unwind info for " <<
G.getName() <<
"...\n"; });
313 auto &UnwindInfoBlock = **UnwindInfoSec->
blocks().
begin();
314 auto Content = UnwindInfoBlock.getMutableContent(
G);
316 {
reinterpret_cast<uint8_t *
>(Content.data()), Content.size()},
317 CURecTraits::Endianness);
337 if (
auto Err = writeHeader(
G, Writer))
342 if (
auto Err = writePersonalities(
G, Writer))
346 size_t SectionOffsetToLSDAs =
347 Writer.
getOffset() + (NumSecondLevelPages + 1) * IndexEntrySize;
350 size_t SectionOffsetToSecondLevelPages =
351 SectionOffsetToLSDAs + NumLSDAs * LSDAEntrySize;
353 if (
auto Err = writeIndexes(
G, Writer, SectionOffsetToLSDAs,
354 SectionOffsetToSecondLevelPages))
357 if (
auto Err = writeLSDAs(
G, Writer))
360 if (
auto Err = writeSecondLevelPages(
G, Writer))
364 dbgs() <<
" Wrote " <<
formatv(
"{0:x}", Writer.getOffset())
365 <<
" bytes of unwind info.\n";
373 static constexpr size_t MaxPersonalities = 4;
374 static constexpr size_t PersonalityShift = 28;
376 static constexpr size_t UnwindInfoSectionHeaderSize = 4 * 7;
377 static constexpr size_t PersonalityEntrySize = 4;
378 static constexpr size_t IndexEntrySize = 3 * 4;
379 static constexpr size_t LSDAEntrySize = 2 * 4;
380 static constexpr size_t SecondLevelPageSize = 4096;
381 static constexpr size_t SecondLevelPageHeaderSize = 8;
382 static constexpr size_t SecondLevelPageEntrySize = 8;
383 static constexpr size_t NumRecordsPerSecondLevelPage =
384 (SecondLevelPageSize - SecondLevelPageHeaderSize) /
385 SecondLevelPageEntrySize;
387 struct CompactUnwindRecord {
395 Error processCompactUnwind(LinkGraph &
G, Section &CUSec) {
398 assert(NumLSDAs == 0 &&
"NumLSDAs should be zero");
399 assert(Records.
empty() &&
"CompactUnwindRecords vector should be empty.");
400 assert(Personalities.empty() &&
"Personalities vector should be empty.");
403 NonUniquedRecords.
reserve(CUSec.blocks_size());
406 for (
auto *
B : CUSec.blocks()) {
407 CompactUnwindRecord R;
408 R.Encoding = CURecTraits::readEncoding(
B->getContent());
409 for (
auto &
E :
B->edges()) {
410 switch (
E.getOffset()) {
411 case CURecTraits::FnFieldOffset:
414 if (
E.getKind() == Edge::KeepAlive)
415 R.FDE = &
E.getTarget();
417 R.Fn = &
E.getTarget();
419 case CURecTraits::PersonalityFieldOffset: {
422 size_t PersonalityIdx = 0;
423 for (; PersonalityIdx != Personalities.size(); ++PersonalityIdx)
424 if (Personalities[PersonalityIdx] == &
E.getTarget())
426 if (PersonalityIdx == MaxPersonalities)
428 "In " +
G.getName() +
429 ", __compact_unwind contains too many personalities (max " +
430 formatv(
"{}", MaxPersonalities) +
")");
431 if (PersonalityIdx == Personalities.size())
432 Personalities.push_back(&
E.getTarget());
434 R.Encoding |= (PersonalityIdx + 1) << PersonalityShift;
437 case CURecTraits::LSDAFieldOffset:
439 R.LSDA = &
E.getTarget();
443 ", compact unwind record at " +
445 " has unrecognized edge at offset " +
449 Records.push_back(R);
454 const CompactUnwindRecord &
RHS) {
455 return LHS.Fn->getAddress() <
RHS.Fn->getAddress();
459 NumSecondLevelPages = (Records.size() + NumRecordsPerSecondLevelPage - 1) /
460 NumRecordsPerSecondLevelPage;
463 typename CURecTraits::GOTManager
GOT(
G);
464 for (
auto &Personality : Personalities)
465 Personality = &
GOT.getEntryForTarget(
G, *Personality);
468 dbgs() <<
" In " <<
G.getName() <<
", " << CompactUnwindSectionName
469 <<
": raw records = " << Records.size()
470 <<
", personalities = " << Personalities.size()
471 <<
", lsdas = " << NumLSDAs <<
"\n";
477 void mergeRecords() {
478 SmallVector<CompactUnwindRecord> NonUniqued = std::move(Records);
479 Records.reserve(NonUniqued.size());
482 LastFunction = NonUniqued.back().Fn;
483 Records.push_back(NonUniqued.front());
484 for (
size_t I = 1;
I != NonUniqued.size(); ++
I) {
485 auto &
Next = NonUniqued[
I];
486 auto &
Last = Records.back();
488 bool CanBeMerged = CURecTraits::encodingCanBeMerged(
Next.Encoding);
489 if (!CanBeMerged || (
Next.Encoding !=
Last.Encoding) ||
Next.LSDA ||
491 Records.push_back(
Next);
495 NumSecondLevelPages = (Records.size() + NumRecordsPerSecondLevelPage - 1) /
496 NumRecordsPerSecondLevelPage;
499 Error writeHeader(LinkGraph &
G, BinaryStreamWriter &W) {
502 UnwindInfoSectionName +
503 "second-level pages required");
506 size_t IndexArrayOffset = UnwindInfoSectionHeaderSize +
507 Personalities.size() * PersonalityEntrySize;
510 cantFail(
W.writeInteger<uint32_t>(UnwindInfoSectionHeaderSize));
512 cantFail(
W.writeInteger<uint32_t>(UnwindInfoSectionHeaderSize));
513 cantFail(
W.writeInteger<uint32_t>(Personalities.size()));
514 cantFail(
W.writeInteger<uint32_t>(IndexArrayOffset));
515 cantFail(
W.writeInteger<uint32_t>(NumSecondLevelPages + 1));
520 Error writePersonalities(LinkGraph &
G, BinaryStreamWriter &W) {
522 for (
auto *PSym : Personalities) {
523 auto Delta = PSym->getAddress() - CompactUnwindBase->getAddress();
525 return makePersonalityRangeError(
G, *PSym);
526 cantFail(
W.writeInteger<uint32_t>(Delta));
531 Error writeIndexes(LinkGraph &
G, BinaryStreamWriter &W,
532 size_t SectionOffsetToLSDAs,
533 size_t SectionOffsetToSecondLevelPages) {
538 size_t RecordIdx = 0;
539 size_t NumPreviousLSDAs = 0;
540 for (
auto &R : Records) {
542 if (RecordIdx % NumRecordsPerSecondLevelPage == 0) {
543 auto FnDelta =
R.Fn->getAddress() - CompactUnwindBase->getAddress();
544 auto SecondLevelPageOffset =
545 SectionOffsetToSecondLevelPages +
546 SecondLevelPageSize * (RecordIdx / NumRecordsPerSecondLevelPage);
548 SectionOffsetToLSDAs + NumPreviousLSDAs * LSDAEntrySize;
550 cantFail(
W.writeInteger<uint32_t>(FnDelta));
551 cantFail(
W.writeInteger<uint32_t>(SecondLevelPageOffset));
552 cantFail(
W.writeInteger<uint32_t>(LSDAOffset));
562 LastFunction->getRange().End - CompactUnwindBase->getAddress();
566 "In " +
G.getName() +
" " + UnwindInfoSectionName +
567 ", delta to end of functions " +
568 formatv(
"{0:x}", LastFunction->getRange().End) +
571 cantFail(
W.writeInteger<uint32_t>(FnEndDelta));
573 cantFail(
W.writeInteger<uint32_t>(SectionOffsetToSecondLevelPages));
579 Error writeLSDAs(LinkGraph &
G, BinaryStreamWriter &W) {
581 for (
auto &R : Records) {
583 auto FnDelta =
R.Fn->getAddress() - CompactUnwindBase->getAddress();
584 auto LSDADelta =
R.LSDA->getAddress() - CompactUnwindBase->getAddress();
588 "In " +
G.getName() +
" " + UnwindInfoSectionName +
589 ", delta to lsda at " +
formatv(
"{0:x}",
R.LSDA->getAddress()) +
592 cantFail(
W.writeInteger<uint32_t>(FnDelta));
593 cantFail(
W.writeInteger<uint32_t>(LSDADelta));
600 Error writeSecondLevelPages(LinkGraph &
G, BinaryStreamWriter &W) {
601 size_t RecordIdx = 0;
603 for (
auto &R : Records) {
609 if (RecordIdx % NumRecordsPerSecondLevelPage == 0) {
610 constexpr uint32_t SecondLevelPageHeaderKind = 2;
611 constexpr uint16_t SecondLevelPageHeaderSize = 8;
612 uint16_t SecondLevelPageNumEntries =
613 std::min(Records.size() - RecordIdx, NumRecordsPerSecondLevelPage);
615 cantFail(
W.writeInteger<uint32_t>(SecondLevelPageHeaderKind));
616 cantFail(
W.writeInteger<uint16_t>(SecondLevelPageHeaderSize));
617 cantFail(
W.writeInteger<uint16_t>(SecondLevelPageNumEntries));
621 auto FnDelta =
R.Fn->getAddress() - CompactUnwindBase->getAddress();
625 "In " +
G.getName() +
" " + UnwindInfoSectionName +
626 ", delta to function at " +
formatv(
"{0:x}",
R.Fn->getAddress()) +
629 auto Encoding =
R.Encoding;
631 if (
LLVM_UNLIKELY(CURecTraits::encodingSpecifiesDWARF(
R.Encoding))) {
633 EHFrameBase = SectionRange(
R.FDE->getSection()).getStart();
634 auto FDEDelta =
R.FDE->getAddress() - EHFrameBase;
636 if (
auto EncodedFDEDelta = CURecTraits::encodeDWARFOffset(FDEDelta))
637 Encoding |= *EncodedFDEDelta;
640 "In " +
G.getName() +
" " + UnwindInfoSectionName +
641 ", cannot encode delta " +
formatv(
"{0:x}", FDEDelta) +
642 " to FDE at " +
formatv(
"{0:x}",
R.FDE->getAddress()));
645 cantFail(
W.writeInteger<uint32_t>(FnDelta));
646 cantFail(
W.writeInteger<uint32_t>(Encoding));
654 Error getOrCreateCompactUnwindBase(LinkGraph &
G) {
655 auto Name =
G.intern(
"__jitlink$libunwind_dso_base");
656 CompactUnwindBase =
G.findAbsoluteSymbolByName(Name);
657 if (!CompactUnwindBase) {
659 CompactUnwindBase = &*LocalCUBase;
660 auto &
B = LocalCUBase->getBlock();
664 return LocalCUBase.takeError();
666 CompactUnwindBase->setLive(
true);
670 Error makePersonalityRangeError(LinkGraph &
G, Symbol &PSym) {
673 raw_string_ostream ErrStream(ErrMsg);
674 ErrStream <<
"In " <<
G.getName() <<
" " << UnwindInfoSectionName
677 ErrStream << PSym.getName() <<
" ";
678 ErrStream <<
"at " << PSym.getAddress()
679 <<
" is out of 32-bit delta range of compact-unwind base at "
680 << CompactUnwindBase->getAddress();
685 StringRef CompactUnwindSectionName;
686 StringRef UnwindInfoSectionName;
687 StringRef EHFrameSectionName;
688 Symbol *CompactUnwindBase =
nullptr;
689 orc::ExecutorAddr EHFrameBase;
692 size_t NumSecondLevelPages = 0;
693 Symbol *LastFunction =
nullptr;
695 SmallVector<CompactUnwindRecord> Records;