80 : CompactUnwindSectionName(CompactUnwindSectionName),
81 UnwindInfoSectionName(UnwindInfoSectionName),
82 EHFrameSectionName(EHFrameSectionName) {}
92 Section *CUSec =
G.findSectionByName(CompactUnwindSectionName);
93 if (!CUSec || CUSec->
empty()) {
95 dbgs() <<
"Compact unwind: No compact unwind info for " <<
G.getName()
102 dbgs() <<
"Compact unwind: preparing " <<
G.getName() <<
" for prune\n";
105 Section *EHFrameSec =
G.findSectionByName(EHFrameSectionName);
112 << CompactUnwindSectionName <<
"\n";
115 for (
auto *
B : CUSec->
blocks()) {
118 Edge *PCBeginEdge =
nullptr;
119 for (
auto &
E :
B->edges_at(CURecTraits::FnFieldOffset)) {
126 "In " +
G.getName() +
", compact unwind record at " +
127 formatv(
"{0:x}",
B->getAddress()) +
" has no pc-begin edge");
131 "In " +
G.getName() +
", compact unwind record at " +
132 formatv(
"{0:x}",
B->getAddress()) +
" points at external symbol " +
137 if (!Fn.isDefined()) {
139 dbgs() <<
"In " << CompactUnwindSectionName <<
" for " <<
G.getName()
140 <<
" encountered unexpected pc-edge to undefined symbol "
141 << Fn.getName() <<
"\n";
146 uint32_t Encoding = CURecTraits::readEncoding(
B->getContent());
147 bool NeedsDWARF = CURecTraits::encodingSpecifiesDWARF(Encoding);
150 dbgs() <<
" Found record for function ";
152 dbgs() << Fn.getName();
154 dbgs() <<
"<anon @ " << Fn.getAddress() <<
'>';
155 dbgs() <<
": encoding = " <<
formatv(
"{0:x}", Encoding);
157 dbgs() <<
" (needs DWARF)";
162 G.addAnonymousSymbol(*
B, 0, CURecTraits::Size,
false,
false);
164 bool KeepAliveAlreadyPresent =
false;
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) {
181 KeepAliveAlreadyPresent =
true;
184 dbgs() <<
" Adding keep-alive edge to FDE at "
185 << FDE.getAddress() <<
"\n";
187 B->addEdge(Edge::KeepAlive, 0, FDE, 0);
192 "In " +
G.getName() +
", compact unwind recard ot " +
194 " needs DWARF, but no FDE was found");
199 "In " +
G.getName() +
", compact unwind recard ot " +
200 formatv(
"{0:x}",
B->getAddress()) +
" needs DWARF, but no " +
201 EHFrameSectionName +
" section exists");
204 if (!KeepAliveAlreadyPresent) {
207 Fn.getBlock().addEdge(Edge::KeepAlive, 0, CURecSym, 0);
217 Section *CUSec =
G.findSectionByName(CompactUnwindSectionName);
227 if (
auto Err = getOrCreateCompactUnwindBase(
G))
232 if (
G.findSectionByName(UnwindInfoSectionName))
234 UnwindInfoSectionName +
239 if (
auto Err = processCompactUnwind(
G, *CUSec))
243 size_t UnwindInfoSectionSize =
244 UnwindInfoSectionHeaderSize +
245 Personalities.size() * PersonalityEntrySize +
246 (NumSecondLevelPages + 1) * IndexEntrySize + NumLSDAs * LSDAEntrySize +
247 NumSecondLevelPages * SecondLevelPageHeaderSize +
248 Records.size() * SecondLevelPageEntrySize;
251 dbgs() <<
"In " <<
G.getName() <<
", reserving "
252 <<
formatv(
"{0:x}", UnwindInfoSectionSize) <<
" bytes for "
253 << UnwindInfoSectionName <<
"\n";
260 auto UnwindInfoSectionContent =
G.allocateBuffer(UnwindInfoSectionSize);
261 memset(UnwindInfoSectionContent.data(), 0, UnwindInfoSectionContent.size());
262 auto &
B =
G.createMutableContentBlock(
267 for (
auto &R : Records)
268 B.addEdge(Edge::KeepAlive, 0, *R.Fn, 0);
274 Section *CUSec =
G.findSectionByName(CompactUnwindSectionName);
275 if (!CUSec || CUSec->
empty())
278 Section *UnwindInfoSec =
G.findSectionByName(UnwindInfoSectionName);
281 UnwindInfoSectionName +
282 " missing after allocation");
286 "In " +
G.getName() +
", " + UnwindInfoSectionName +
287 " contains more than one block post-allocation");
290 {
dbgs() <<
"Writing unwind info for " <<
G.getName() <<
"...\n"; });
294 auto &UnwindInfoBlock = **UnwindInfoSec->
blocks().
begin();
295 auto Content = UnwindInfoBlock.getMutableContent(
G);
297 {
reinterpret_cast<uint8_t *
>(Content.data()), Content.size()},
298 CURecTraits::Endianness);
318 if (
auto Err = writeHeader(
G, Writer))
323 if (
auto Err = writePersonalities(
G, Writer))
327 size_t SectionOffsetToLSDAs =
328 Writer.
getOffset() + (NumSecondLevelPages + 1) * IndexEntrySize;
331 size_t SectionOffsetToSecondLevelPages =
332 SectionOffsetToLSDAs + NumLSDAs * LSDAEntrySize;
334 if (
auto Err = writeIndexes(
G, Writer, SectionOffsetToLSDAs,
335 SectionOffsetToSecondLevelPages))
338 if (
auto Err = writeLSDAs(
G, Writer))
341 if (
auto Err = writeSecondLevelPages(
G, Writer))
345 dbgs() <<
" Wrote " <<
formatv(
"{0:x}", Writer.getOffset())
346 <<
" bytes of unwind info.\n";
354 static constexpr size_t MaxPersonalities = 4;
355 static constexpr size_t PersonalityShift = 28;
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;
368 struct CompactUnwindRecord {
376 Error processCompactUnwind(LinkGraph &
G, Section &CUSec) {
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.");
384 NonUniquedRecords.
reserve(CUSec.blocks_size());
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:
395 if (
E.getKind() == Edge::KeepAlive)
396 R.FDE = &
E.getTarget();
398 R.Fn = &
E.getTarget();
400 case CURecTraits::PersonalityFieldOffset: {
403 size_t PersonalityIdx = 0;
404 for (; PersonalityIdx != Personalities.size(); ++PersonalityIdx)
405 if (Personalities[PersonalityIdx] == &
E.getTarget())
407 if (PersonalityIdx == MaxPersonalities)
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());
415 R.Encoding |= (PersonalityIdx + 1) << PersonalityShift;
418 case CURecTraits::LSDAFieldOffset:
420 R.LSDA = &
E.getTarget();
424 ", compact unwind record at " +
426 " has unrecognized edge at offset " +
430 Records.push_back(R);
435 const CompactUnwindRecord &
RHS) {
436 return LHS.Fn->getAddress() <
RHS.Fn->getAddress();
440 NumSecondLevelPages = (Records.size() + NumRecordsPerSecondLevelPage - 1) /
441 NumRecordsPerSecondLevelPage;
444 typename CURecTraits::GOTManager
GOT(
G);
445 for (
auto &Personality : Personalities)
446 Personality = &
GOT.getEntryForTarget(
G, *Personality);
449 dbgs() <<
" In " <<
G.getName() <<
", " << CompactUnwindSectionName
450 <<
": raw records = " << Records.size()
451 <<
", personalities = " << Personalities.size()
452 <<
", lsdas = " << NumLSDAs <<
"\n";
458 void mergeRecords() {
459 SmallVector<CompactUnwindRecord> NonUniqued = std::move(Records);
460 Records.reserve(NonUniqued.size());
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();
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);
475 NumSecondLevelPages = (Records.size() + NumRecordsPerSecondLevelPage - 1) /
476 NumRecordsPerSecondLevelPage;
479 Error writeHeader(LinkGraph &
G, BinaryStreamWriter &W) {
482 UnwindInfoSectionName +
483 "second-level pages required");
486 size_t IndexArrayOffset = UnwindInfoSectionHeaderSize +
487 Personalities.size() * PersonalityEntrySize;
490 cantFail(
W.writeInteger<uint32_t>(UnwindInfoSectionHeaderSize));
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));
500 Error writePersonalities(LinkGraph &
G, BinaryStreamWriter &W) {
502 for (
auto *PSym : Personalities) {
503 auto Delta = PSym->getAddress() - CompactUnwindBase->getAddress();
505 return makePersonalityRangeError(
G, *PSym);
506 cantFail(
W.writeInteger<uint32_t>(Delta));
511 Error writeIndexes(LinkGraph &
G, BinaryStreamWriter &W,
512 size_t SectionOffsetToLSDAs,
513 size_t SectionOffsetToSecondLevelPages) {
518 size_t RecordIdx = 0;
519 size_t NumPreviousLSDAs = 0;
520 for (
auto &R : Records) {
522 if (RecordIdx % NumRecordsPerSecondLevelPage == 0) {
523 auto FnDelta =
R.Fn->getAddress() - CompactUnwindBase->getAddress();
524 auto SecondLevelPageOffset =
525 SectionOffsetToSecondLevelPages +
526 SecondLevelPageSize * (RecordIdx / NumRecordsPerSecondLevelPage);
528 SectionOffsetToLSDAs + NumPreviousLSDAs * LSDAEntrySize;
530 cantFail(
W.writeInteger<uint32_t>(FnDelta));
531 cantFail(
W.writeInteger<uint32_t>(SecondLevelPageOffset));
532 cantFail(
W.writeInteger<uint32_t>(LSDAOffset));
542 Records.back().Fn->getRange().End - CompactUnwindBase->getAddress();
546 "In " +
G.getName() +
" " + UnwindInfoSectionName +
547 ", delta to end of functions " +
548 formatv(
"{0:x}", Records.back().Fn->getRange().End) +
551 cantFail(
W.writeInteger<uint32_t>(FnEndDelta));
553 cantFail(
W.writeInteger<uint32_t>(SectionOffsetToSecondLevelPages));
559 Error writeLSDAs(LinkGraph &
G, BinaryStreamWriter &W) {
561 for (
auto &R : Records) {
563 auto FnDelta =
R.Fn->getAddress() - CompactUnwindBase->getAddress();
564 auto LSDADelta =
R.LSDA->getAddress() - CompactUnwindBase->getAddress();
568 "In " +
G.getName() +
" " + UnwindInfoSectionName +
569 ", delta to lsda at " +
formatv(
"{0:x}",
R.LSDA->getAddress()) +
572 cantFail(
W.writeInteger<uint32_t>(FnDelta));
573 cantFail(
W.writeInteger<uint32_t>(LSDADelta));
580 Error writeSecondLevelPages(LinkGraph &
G, BinaryStreamWriter &W) {
581 size_t RecordIdx = 0;
583 for (
auto &R : Records) {
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);
595 cantFail(
W.writeInteger<uint32_t>(SecondLevelPageHeaderKind));
596 cantFail(
W.writeInteger<uint16_t>(SecondLevelPageHeaderSize));
597 cantFail(
W.writeInteger<uint16_t>(SecondLevelPageNumEntries));
601 auto FnDelta =
R.Fn->getAddress() - CompactUnwindBase->getAddress();
605 "In " +
G.getName() +
" " + UnwindInfoSectionName +
606 ", delta to function at " +
formatv(
"{0:x}",
R.Fn->getAddress()) +
609 auto Encoding =
R.Encoding;
611 if (
LLVM_UNLIKELY(CURecTraits::encodingSpecifiesDWARF(
R.Encoding))) {
613 EHFrameBase = SectionRange(
R.FDE->getSection()).getStart();
614 auto FDEDelta =
R.FDE->getAddress() - EHFrameBase;
616 if (
auto EncodedFDEDelta = CURecTraits::encodeDWARFOffset(FDEDelta))
617 Encoding |= *EncodedFDEDelta;
620 "In " +
G.getName() +
" " + UnwindInfoSectionName +
621 ", cannot encode delta " +
formatv(
"{0:x}", FDEDelta) +
622 " to FDE at " +
formatv(
"{0:x}",
R.FDE->getAddress()));
625 cantFail(
W.writeInteger<uint32_t>(FnDelta));
626 cantFail(
W.writeInteger<uint32_t>(Encoding));
634 Error getOrCreateCompactUnwindBase(LinkGraph &
G) {
635 auto Name =
G.intern(
"__jitlink$libunwind_dso_base");
636 CompactUnwindBase =
G.findAbsoluteSymbolByName(Name);
637 if (!CompactUnwindBase) {
639 CompactUnwindBase = &*LocalCUBase;
640 auto &
B = LocalCUBase->getBlock();
644 return LocalCUBase.takeError();
646 CompactUnwindBase->setLive(
true);
650 Error makePersonalityRangeError(LinkGraph &
G, Symbol &PSym) {
653 raw_string_ostream ErrStream(ErrMsg);
654 ErrStream <<
"In " <<
G.getName() <<
" " << UnwindInfoSectionName
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();
665 StringRef CompactUnwindSectionName;
666 StringRef UnwindInfoSectionName;
667 StringRef EHFrameSectionName;
668 Symbol *CompactUnwindBase =
nullptr;
669 orc::ExecutorAddr EHFrameBase;
672 size_t NumSecondLevelPages = 0;
674 SmallVector<CompactUnwindRecord> Records;