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());
481 Records.push_back(NonUniqued.front());
482 for (
size_t I = 1;
I != NonUniqued.size(); ++
I) {
483 auto &
Next = NonUniqued[
I];
484 auto &
Last = Records.back();
486 bool CanBeMerged = CURecTraits::encodingCanBeMerged(
Next.Encoding);
487 if (!CanBeMerged || (
Next.Encoding !=
Last.Encoding) ||
Next.LSDA ||
489 Records.push_back(
Next);
493 NumSecondLevelPages = (Records.size() + NumRecordsPerSecondLevelPage - 1) /
494 NumRecordsPerSecondLevelPage;
497 Error writeHeader(LinkGraph &
G, BinaryStreamWriter &W) {
500 UnwindInfoSectionName +
501 "second-level pages required");
504 size_t IndexArrayOffset = UnwindInfoSectionHeaderSize +
505 Personalities.size() * PersonalityEntrySize;
508 cantFail(
W.writeInteger<uint32_t>(UnwindInfoSectionHeaderSize));
510 cantFail(
W.writeInteger<uint32_t>(UnwindInfoSectionHeaderSize));
511 cantFail(
W.writeInteger<uint32_t>(Personalities.size()));
512 cantFail(
W.writeInteger<uint32_t>(IndexArrayOffset));
513 cantFail(
W.writeInteger<uint32_t>(NumSecondLevelPages + 1));
518 Error writePersonalities(LinkGraph &
G, BinaryStreamWriter &W) {
520 for (
auto *PSym : Personalities) {
521 auto Delta = PSym->getAddress() - CompactUnwindBase->getAddress();
523 return makePersonalityRangeError(
G, *PSym);
524 cantFail(
W.writeInteger<uint32_t>(Delta));
529 Error writeIndexes(LinkGraph &
G, BinaryStreamWriter &W,
530 size_t SectionOffsetToLSDAs,
531 size_t SectionOffsetToSecondLevelPages) {
536 size_t RecordIdx = 0;
537 size_t NumPreviousLSDAs = 0;
538 for (
auto &R : Records) {
540 if (RecordIdx % NumRecordsPerSecondLevelPage == 0) {
541 auto FnDelta =
R.Fn->getAddress() - CompactUnwindBase->getAddress();
542 auto SecondLevelPageOffset =
543 SectionOffsetToSecondLevelPages +
544 SecondLevelPageSize * (RecordIdx / NumRecordsPerSecondLevelPage);
546 SectionOffsetToLSDAs + NumPreviousLSDAs * LSDAEntrySize;
548 cantFail(
W.writeInteger<uint32_t>(FnDelta));
549 cantFail(
W.writeInteger<uint32_t>(SecondLevelPageOffset));
550 cantFail(
W.writeInteger<uint32_t>(LSDAOffset));
560 Records.back().Fn->getRange().End - CompactUnwindBase->getAddress();
564 "In " +
G.getName() +
" " + UnwindInfoSectionName +
565 ", delta to end of functions " +
566 formatv(
"{0:x}", Records.back().Fn->getRange().End) +
569 cantFail(
W.writeInteger<uint32_t>(FnEndDelta));
571 cantFail(
W.writeInteger<uint32_t>(SectionOffsetToSecondLevelPages));
577 Error writeLSDAs(LinkGraph &
G, BinaryStreamWriter &W) {
579 for (
auto &R : Records) {
581 auto FnDelta =
R.Fn->getAddress() - CompactUnwindBase->getAddress();
582 auto LSDADelta =
R.LSDA->getAddress() - CompactUnwindBase->getAddress();
586 "In " +
G.getName() +
" " + UnwindInfoSectionName +
587 ", delta to lsda at " +
formatv(
"{0:x}",
R.LSDA->getAddress()) +
590 cantFail(
W.writeInteger<uint32_t>(FnDelta));
591 cantFail(
W.writeInteger<uint32_t>(LSDADelta));
598 Error writeSecondLevelPages(LinkGraph &
G, BinaryStreamWriter &W) {
599 size_t RecordIdx = 0;
601 for (
auto &R : Records) {
607 if (RecordIdx % NumRecordsPerSecondLevelPage == 0) {
608 constexpr uint32_t SecondLevelPageHeaderKind = 2;
609 constexpr uint16_t SecondLevelPageHeaderSize = 8;
610 uint16_t SecondLevelPageNumEntries =
611 std::min(Records.size() - RecordIdx, NumRecordsPerSecondLevelPage);
613 cantFail(
W.writeInteger<uint32_t>(SecondLevelPageHeaderKind));
614 cantFail(
W.writeInteger<uint16_t>(SecondLevelPageHeaderSize));
615 cantFail(
W.writeInteger<uint16_t>(SecondLevelPageNumEntries));
619 auto FnDelta =
R.Fn->getAddress() - CompactUnwindBase->getAddress();
623 "In " +
G.getName() +
" " + UnwindInfoSectionName +
624 ", delta to function at " +
formatv(
"{0:x}",
R.Fn->getAddress()) +
627 auto Encoding =
R.Encoding;
629 if (
LLVM_UNLIKELY(CURecTraits::encodingSpecifiesDWARF(
R.Encoding))) {
631 EHFrameBase = SectionRange(
R.FDE->getSection()).getStart();
632 auto FDEDelta =
R.FDE->getAddress() - EHFrameBase;
634 if (
auto EncodedFDEDelta = CURecTraits::encodeDWARFOffset(FDEDelta))
635 Encoding |= *EncodedFDEDelta;
638 "In " +
G.getName() +
" " + UnwindInfoSectionName +
639 ", cannot encode delta " +
formatv(
"{0:x}", FDEDelta) +
640 " to FDE at " +
formatv(
"{0:x}",
R.FDE->getAddress()));
643 cantFail(
W.writeInteger<uint32_t>(FnDelta));
644 cantFail(
W.writeInteger<uint32_t>(Encoding));
652 Error getOrCreateCompactUnwindBase(LinkGraph &
G) {
653 auto Name =
G.intern(
"__jitlink$libunwind_dso_base");
654 CompactUnwindBase =
G.findAbsoluteSymbolByName(Name);
655 if (!CompactUnwindBase) {
657 CompactUnwindBase = &*LocalCUBase;
658 auto &
B = LocalCUBase->getBlock();
662 return LocalCUBase.takeError();
664 CompactUnwindBase->setLive(
true);
668 Error makePersonalityRangeError(LinkGraph &
G, Symbol &PSym) {
671 raw_string_ostream ErrStream(ErrMsg);
672 ErrStream <<
"In " <<
G.getName() <<
" " << UnwindInfoSectionName
675 ErrStream << PSym.getName() <<
" ";
676 ErrStream <<
"at " << PSym.getAddress()
677 <<
" is out of 32-bit delta range of compact-unwind base at "
678 << CompactUnwindBase->getAddress();
683 StringRef CompactUnwindSectionName;
684 StringRef UnwindInfoSectionName;
685 StringRef EHFrameSectionName;
686 Symbol *CompactUnwindBase =
nullptr;
687 orc::ExecutorAddr EHFrameBase;
690 size_t NumSecondLevelPages = 0;
692 SmallVector<CompactUnwindRecord> Records;