LLVM: lib/ExecutionEngine/JITLink/CompactUnwindSupport.h Source File (original) (raw)
50
53 "Truncated CU record?");
56 }
57
60 "Truncated CU record?");
63 }
64
67 static_cast<uint32_t>(Delta) & CRTPImpl::DWARFSectionOffsetMask;
68 if (Encoded != Delta)
69 return std::nullopt;
70 return Encoded;
71 }
72};
76public:
80 : CompactUnwindSectionName(CompactUnwindSectionName),
81 UnwindInfoSectionName(UnwindInfoSectionName),
82 EHFrameSectionName(EHFrameSectionName) {}
83
84
85
86
87
88
89
90
92 Section *CUSec = G.findSectionByName(CompactUnwindSectionName);
93 if (!CUSec || CUSec->empty()) {
95 dbgs() << "Compact unwind: No compact unwind info for " << G.getName()
96 << "\n";
97 });
99 }
100
102 dbgs() << "Compact unwind: preparing " << G.getName() << " for prune\n";
103 });
104
105 Section *EHFrameSec = G.findSectionByName(EHFrameSectionName);
106
108 return Err;
109
111 dbgs() << " Preparing " << CUSec->blocks_size() << " blocks in "
112 << CompactUnwindSectionName << "\n";
113 });
114
115 for (auto *B : CUSec->blocks()) {
116
117
118 Edge *PCBeginEdge = nullptr;
119 for (auto &E : B->edges_at(CURecTraits::FnFieldOffset)) {
120 PCBeginEdge = &E;
121 break;
122 }
123
124 if (!PCBeginEdge)
126 "In " + G.getName() + ", compact unwind record at " +
127 formatv("{0:x}", B->getAddress()) + " has no pc-begin edge");
128
131 "In " + G.getName() + ", compact unwind record at " +
132 formatv("{0:x}", B->getAddress()) + " points at external symbol " +
134
135 auto &Fn = PCBeginEdge->getTarget();
136
137 if (!Fn.isDefined()) {
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
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
177
178
179 auto &FDE = KeepAliveEdge->getTarget();
180 KeepAliveEdge->setTarget(CURecSym);
181 KeepAliveAlreadyPresent = true;
182 if (NeedsDWARF) {
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)
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)
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
206
207 Fn.getBlock().addEdge(Edge::KeepAlive, 0, CURecSym, 0);
208 }
209 }
210
212 }
213
214
216
217 Section *CUSec = G.findSectionByName(CompactUnwindSectionName);
218 if (!CUSec)
220
221
222
224
225
226
227 if (auto Err = getOrCreateCompactUnwindBase(G))
228 return Err;
229
230
231
232 if (G.findSectionByName(UnwindInfoSectionName))
234 UnwindInfoSectionName +
235 " already exists");
236
237
238
239 if (auto Err = processCompactUnwind(G, *CUSec))
240 return Err;
241
242
243 size_t UnwindInfoSectionSize =
244 UnwindInfoSectionHeaderSize +
245 Personalities.size() * PersonalityEntrySize +
246 (NumSecondLevelPages + 1) * IndexEntrySize + NumLSDAs * LSDAEntrySize +
247 NumSecondLevelPages * SecondLevelPageHeaderSize +
248 Records.size() * SecondLevelPageEntrySize;
249
251 dbgs() << "In " << G.getName() << ", reserving "
252 << formatv("{0:x}", UnwindInfoSectionSize) << " bytes for "
253 << UnwindInfoSectionName << "\n";
254 });
255
256
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
266
267 for (auto &R : Records)
268 B.addEdge(Edge::KeepAlive, 0, *R.Fn, 0);
269
271 }
272
274 Section *CUSec = G.findSectionByName(CompactUnwindSectionName);
275 if (!CUSec || CUSec->empty())
277
278 Section *UnwindInfoSec = G.findSectionByName(UnwindInfoSectionName);
279 if (!UnwindInfoSec)
281 UnwindInfoSectionName +
282 " missing after allocation");
283
286 "In " + G.getName() + ", " + UnwindInfoSectionName +
287 " contains more than one block post-allocation");
288
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);
297 {reinterpret_cast<uint8_t *>(Content.data()), Content.size()},
298 CURecTraits::Endianness);
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318 if (auto Err = writeHeader(G, Writer))
319 return Err;
320
321
322
323 if (auto Err = writePersonalities(G, Writer))
324 return Err;
325
326
327 size_t SectionOffsetToLSDAs =
328 Writer.getOffset() + (NumSecondLevelPages + 1) * IndexEntrySize;
329
330
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
345 dbgs() << " Wrote " << formatv("{0:x}", Writer.getOffset())
346 << " bytes of unwind info.\n";
347 });
348
350 }
351
352private:
353
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;
372 Symbol *LSDA = nullptr;
373 Symbol *FDE = nullptr;
374 };
375
376 Error processCompactUnwind(LinkGraph &G, Section &CUSec) {
377
378
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
384 NonUniquedRecords.reserve(CUSec.blocks_size());
385
386
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
394
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
402
403 size_t PersonalityIdx = 0;
404 for (; PersonalityIdx != Personalities.size(); ++PersonalityIdx)
405 if (Personalities[PersonalityIdx] == &E.getTarget())
406 break;
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());
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:
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
434 llvm::sort(Records, [](const CompactUnwindRecord &LHS,
435 const CompactUnwindRecord &RHS) {
436 return LHS.Fn->getAddress() < RHS.Fn->getAddress();
437 });
438
439
440 NumSecondLevelPages = (Records.size() + NumRecordsPerSecondLevelPage - 1) /
441 NumRecordsPerSecondLevelPage;
442
443
444 typename CURecTraits::GOTManager GOT(G);
445 for (auto &Personality : Personalities)
446 Personality = &GOT.getEntryForTarget(G, *Personality);
447
449 dbgs() << " In " << G.getName() << ", " << CompactUnwindSectionName
450 << ": raw records = " << Records.size()
451 << ", personalities = " << Personalities.size()
452 << ", lsdas = " << NumLSDAs << "\n";
453 });
454
456 }
457
458 void mergeRecords() {
459 SmallVector 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
475 NumSecondLevelPages = (Records.size() + NumRecordsPerSecondLevelPage - 1) /
476 NumRecordsPerSecondLevelPage;
477 }
478
479 Error writeHeader(LinkGraph &G, BinaryStreamWriter &W) {
480 if ((NumSecondLevelPages + 1))
482 UnwindInfoSectionName +
483 "second-level pages required");
484
485
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
498 }
499
500 Error writePersonalities(LinkGraph &G, BinaryStreamWriter &W) {
501
502 for (auto *PSym : Personalities) {
503 auto Delta = PSym->getAddress() - CompactUnwindBase->getAddress();
505 return makePersonalityRangeError(G, *PSym);
506 cantFail(W.writeInteger<uint32_t>(Delta));
507 }
509 }
510
511 Error writeIndexes(LinkGraph &G, BinaryStreamWriter &W,
512 size_t SectionOffsetToLSDAs,
513 size_t SectionOffsetToSecondLevelPages) {
514
515
516
517
518 size_t RecordIdx = 0;
519 size_t NumPreviousLSDAs = 0;
520 for (auto &R : Records) {
521
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
540 {
541 auto FnEndDelta =
542 Records.back().Fn->getRange().End - CompactUnwindBase->getAddress();
543
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
557 }
558
559 Error writeLSDAs(LinkGraph &G, BinaryStreamWriter &W) {
560
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
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
578 }
579
580 Error writeSecondLevelPages(LinkGraph &G, BinaryStreamWriter &W) {
581 size_t RecordIdx = 0;
582
583 for (auto &R : Records) {
584
585
586
587
588
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
601 auto FnDelta = R.Fn->getAddress() - CompactUnwindBase->getAddress();
602
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
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
632 }
633
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();
643 } else
644 return LocalCUBase.takeError();
645 }
646 CompactUnwindBase->setLive(true);
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 }
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;
674 SmallVector Records;
675};