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