LLVM 24.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 // Retain the final raw record: merging may remove it.
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();
487
488 bool CanBeMerged = CURecTraits::encodingCanBeMerged(Next.Encoding);
489 if (!CanBeMerged || (Next.Encoding != Last.Encoding) || Next.LSDA ||
490 Last.LSDA)
491 Records.push_back(Next);
492 }
493
494 // Recalculate derived values that may have changed.
495 NumSecondLevelPages = (Records.size() + NumRecordsPerSecondLevelPage - 1) /
496 NumRecordsPerSecondLevelPage;
497 }
498
499 Error writeHeader(LinkGraph &G, BinaryStreamWriter &W) {
500 if (!isUInt<32>(NumSecondLevelPages + 1))
501 return make_error<JITLinkError>("In " + G.getName() + ", too many " +
502 UnwindInfoSectionName +
503 "second-level pages required");
504
505 // Write __unwind_info header.
506 size_t IndexArrayOffset = UnwindInfoSectionHeaderSize +
507 Personalities.size() * PersonalityEntrySize;
508
509 cantFail(W.writeInteger<uint32_t>(1));
510 cantFail(W.writeInteger<uint32_t>(UnwindInfoSectionHeaderSize));
511 cantFail(W.writeInteger<uint32_t>(0));
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));
516
517 return Error::success();
518 }
519
520 Error writePersonalities(LinkGraph &G, BinaryStreamWriter &W) {
521 // Write personalities.
522 for (auto *PSym : Personalities) {
523 auto Delta = PSym->getAddress() - CompactUnwindBase->getAddress();
524 if (!isUInt<32>(Delta))
525 return makePersonalityRangeError(G, *PSym);
526 cantFail(W.writeInteger<uint32_t>(Delta));
527 }
528 return Error::success();
529 }
530
531 Error writeIndexes(LinkGraph &G, BinaryStreamWriter &W,
532 size_t SectionOffsetToLSDAs,
533 size_t SectionOffsetToSecondLevelPages) {
534 // Assume that function deltas are ok in this method -- we'll error
535 // check all of them when we write the second level pages.
536
537 // Write the header index entries.
538 size_t RecordIdx = 0;
539 size_t NumPreviousLSDAs = 0;
540 for (auto &R : Records) {
541 // If this record marks the start of a new second level page.
542 if (RecordIdx % NumRecordsPerSecondLevelPage == 0) {
543 auto FnDelta = R.Fn->getAddress() - CompactUnwindBase->getAddress();
544 auto SecondLevelPageOffset =
545 SectionOffsetToSecondLevelPages +
546 SecondLevelPageSize * (RecordIdx / NumRecordsPerSecondLevelPage);
547 auto LSDAOffset =
548 SectionOffsetToLSDAs + NumPreviousLSDAs * LSDAEntrySize;
549
550 cantFail(W.writeInteger<uint32_t>(FnDelta));
551 cantFail(W.writeInteger<uint32_t>(SecondLevelPageOffset));
552 cantFail(W.writeInteger<uint32_t>(LSDAOffset));
553 }
554 if (R.LSDA)
555 ++NumPreviousLSDAs;
556 ++RecordIdx;
557 }
558
559 // Write the index array terminator.
560 {
561 auto FnEndDelta =
562 LastFunction->getRange().End - CompactUnwindBase->getAddress();
563
564 if (LLVM_UNLIKELY(!isUInt<32>(FnEndDelta)))
566 "In " + G.getName() + " " + UnwindInfoSectionName +
567 ", delta to end of functions " +
568 formatv("{0:x}", LastFunction->getRange().End) +
569 " exceeds 32 bits");
570
571 cantFail(W.writeInteger<uint32_t>(FnEndDelta));
572 cantFail(W.writeInteger<uint32_t>(0));
573 cantFail(W.writeInteger<uint32_t>(SectionOffsetToSecondLevelPages));
574 }
575
576 return Error::success();
577 }
578
579 Error writeLSDAs(LinkGraph &G, BinaryStreamWriter &W) {
580 // As with writeIndexes, assume that function deltas are ok for now.
581 for (auto &R : Records) {
582 if (R.LSDA) {
583 auto FnDelta = R.Fn->getAddress() - CompactUnwindBase->getAddress();
584 auto LSDADelta = R.LSDA->getAddress() - CompactUnwindBase->getAddress();
585
586 if (LLVM_UNLIKELY(!isUInt<32>(LSDADelta)))
588 "In " + G.getName() + " " + UnwindInfoSectionName +
589 ", delta to lsda at " + formatv("{0:x}", R.LSDA->getAddress()) +
590 " exceeds 32 bits");
591
592 cantFail(W.writeInteger<uint32_t>(FnDelta));
593 cantFail(W.writeInteger<uint32_t>(LSDADelta));
594 }
595 }
596
597 return Error::success();
598 }
599
600 Error writeSecondLevelPages(LinkGraph &G, BinaryStreamWriter &W) {
601 size_t RecordIdx = 0;
602
603 for (auto &R : Records) {
604 // When starting a new second-level page, write the page header:
605 //
606 // 2 : uint32_t -- UNWIND_SECOND_LEVEL_REGULAR
607 // 8 : uint16_t -- size of second level page table header
608 // count : uint16_t -- num entries in this second-level page
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);
614
615 cantFail(W.writeInteger<uint32_t>(SecondLevelPageHeaderKind));
616 cantFail(W.writeInteger<uint16_t>(SecondLevelPageHeaderSize));
617 cantFail(W.writeInteger<uint16_t>(SecondLevelPageNumEntries));
618 }
619
620 // Write entry.
621 auto FnDelta = R.Fn->getAddress() - CompactUnwindBase->getAddress();
622
623 if (LLVM_UNLIKELY(!isUInt<32>(FnDelta)))
625 "In " + G.getName() + " " + UnwindInfoSectionName +
626 ", delta to function at " + formatv("{0:x}", R.Fn->getAddress()) +
627 " exceeds 32 bits");
628
629 auto Encoding = R.Encoding;
630
631 if (LLVM_UNLIKELY(CURecTraits::encodingSpecifiesDWARF(R.Encoding))) {
632 if (!EHFrameBase)
633 EHFrameBase = SectionRange(R.FDE->getSection()).getStart();
634 auto FDEDelta = R.FDE->getAddress() - EHFrameBase;
635
636 if (auto EncodedFDEDelta = CURecTraits::encodeDWARFOffset(FDEDelta))
637 Encoding |= *EncodedFDEDelta;
638 else
640 "In " + G.getName() + " " + UnwindInfoSectionName +
641 ", cannot encode delta " + formatv("{0:x}", FDEDelta) +
642 " to FDE at " + formatv("{0:x}", R.FDE->getAddress()));
643 }
644
645 cantFail(W.writeInteger<uint32_t>(FnDelta));
646 cantFail(W.writeInteger<uint32_t>(Encoding));
647
648 ++RecordIdx;
649 }
650
651 return Error::success();
652 }
653
654 Error getOrCreateCompactUnwindBase(LinkGraph &G) {
655 auto Name = G.intern("__jitlink$libunwind_dso_base");
656 CompactUnwindBase = G.findAbsoluteSymbolByName(Name);
657 if (!CompactUnwindBase) {
658 if (auto LocalCUBase = getOrCreateLocalMachOHeader(G)) {
659 CompactUnwindBase = &*LocalCUBase;
660 auto &B = LocalCUBase->getBlock();
661 G.addDefinedSymbol(B, 0, *Name, B.getSize(), Linkage::Strong,
662 Scope::Local, false, true);
663 } else
664 return LocalCUBase.takeError();
665 }
666 CompactUnwindBase->setLive(true);
667 return Error::success();
668 }
669
670 Error makePersonalityRangeError(LinkGraph &G, Symbol &PSym) {
671 std::string ErrMsg;
672 {
673 raw_string_ostream ErrStream(ErrMsg);
674 ErrStream << "In " << G.getName() << " " << UnwindInfoSectionName
675 << ", personality ";
676 if (PSym.hasName())
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();
681 }
682 return make_error<JITLinkError>(std::move(ErrMsg));
683 }
684
685 StringRef CompactUnwindSectionName;
686 StringRef UnwindInfoSectionName;
687 StringRef EHFrameSectionName;
688 Symbol *CompactUnwindBase = nullptr;
689 orc::ExecutorAddr EHFrameBase;
690
691 size_t NumLSDAs = 0;
692 size_t NumSecondLevelPages = 0;
693 Symbol *LastFunction = nullptr;
695 SmallVector<CompactUnwindRecord> Records;
696};
697
698} // end namespace jitlink
699} // end namespace llvm
700
701#undef DEBUG_TYPE
702
703#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:344
#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:119
Value * RHS
Value * LHS
Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition ArrayRef.h:40
size_t size() const
Get the array size.
Definition ArrayRef.h:141
const T * data() const
Definition ArrayRef.h:138
Provides write only access to a subclass of WritableBinaryStream.
Lightweight error class with error context and mandatory checking.
Definition Error.h:159
static ErrorSuccess success()
Create a success value.
Definition Error.h:336
void reserve(size_type N)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Represent a constant reference to a string, i.e.
Definition StringRef.h:56
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:392
This is an optimization pass for GlobalISel generic memory operations.
auto formatv(bool Validate, const char *Fmt, Ts &&...Vals)
void sort(IteratorTy Start, IteratorTy End)
Definition STLExtras.h:1636
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition Debug.cpp:209
constexpr bool isUInt(uint64_t x)
Checks if an unsigned integer fits into the given bit width.
Definition MathExtras.h:190
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:340
void cantFail(Error Err, const char *Msg=nullptr)
Report a fatal error if Err is a failure value.
Definition Error.h:769
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Next
Definition InstrProf.h:147