Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/llvm/lib/ExecutionEngine/JITLink/CompactUnwindSupport.h
213799 views
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"
17
#include "llvm/ExecutionEngine/JITLink/MachO.h"
18
#include "llvm/Support/Debug.h"
19
#include "llvm/Support/Endian.h"
20
21
#define DEBUG_TYPE "jitlink_cu"
22
23
namespace llvm {
24
namespace 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.
29
Error 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
/// FIXME: Passing PtrSize as a template parameter is a hack to work around a
36
/// bug in older MSVC compilers (until at least MSVC 15) where constexpr
37
/// fields in the CRTP impl class were not visible to the base class.
38
/// Once we no longer need to support these compilers the PtrSize
39
/// template argument should be removed and PointerSize should be
40
/// defined as a member in the CRTP Impl classes.
41
template <typename CRTPImpl, size_t PtrSize> struct CompactUnwindTraits {
42
static constexpr size_t PointerSize = PtrSize;
43
static constexpr size_t Size = 3 * PointerSize + 2 * 4;
44
static constexpr size_t FnFieldOffset = 0;
45
static constexpr size_t SizeFieldOffset = FnFieldOffset + PointerSize;
46
static constexpr size_t EncodingFieldOffset = SizeFieldOffset + 4;
47
static constexpr size_t PersonalityFieldOffset = EncodingFieldOffset + 4;
48
static constexpr size_t LSDAFieldOffset =
49
PersonalityFieldOffset + PointerSize;
50
51
static uint32_t readPCRangeSize(ArrayRef<char> RecordContent) {
52
assert(SizeFieldOffset + 4 <= RecordContent.size() &&
53
"Truncated CU record?");
54
return support::endian::read32<CRTPImpl::Endianness>(RecordContent.data() +
55
SizeFieldOffset);
56
}
57
58
static uint32_t readEncoding(ArrayRef<char> RecordContent) {
59
assert(EncodingFieldOffset + 4 <= RecordContent.size() &&
60
"Truncated CU record?");
61
return support::endian::read32<CRTPImpl::Endianness>(RecordContent.data() +
62
EncodingFieldOffset);
63
}
64
65
static std::optional<uint32_t> encodeDWARFOffset(size_t Delta) {
66
uint32_t Encoded =
67
static_cast<uint32_t>(Delta) & CRTPImpl::DWARFSectionOffsetMask;
68
if (Encoded != Delta)
69
return std::nullopt;
70
return Encoded;
71
}
72
};
73
74
/// Architecture specific implementation of CompactUnwindManager.
75
template <typename CURecTraits> class CompactUnwindManager {
76
public:
77
CompactUnwindManager(StringRef CompactUnwindSectionName,
78
StringRef UnwindInfoSectionName,
79
StringRef EHFrameSectionName)
80
: CompactUnwindSectionName(CompactUnwindSectionName),
81
UnwindInfoSectionName(UnwindInfoSectionName),
82
EHFrameSectionName(EHFrameSectionName) {}
83
84
// Split compact unwind records, add keep-alive edges from functions to
85
// compact unwind records, and from compact unwind records to FDEs where
86
// needed.
87
//
88
// This method must be called *after* __eh_frame has been processed: it
89
// assumes that eh-frame records have been split up and keep-alive edges have
90
// been inserted.
91
Error prepareForPrune(LinkGraph &G) {
92
Section *CUSec = G.findSectionByName(CompactUnwindSectionName);
93
if (!CUSec || CUSec->empty()) {
94
LLVM_DEBUG({
95
dbgs() << "Compact unwind: No compact unwind info for " << G.getName()
96
<< "\n";
97
});
98
return Error::success();
99
}
100
101
LLVM_DEBUG({
102
dbgs() << "Compact unwind: preparing " << G.getName() << " for prune\n";
103
});
104
105
Section *EHFrameSec = G.findSectionByName(EHFrameSectionName);
106
107
if (auto Err = splitCompactUnwindBlocks(G, *CUSec, CURecTraits::Size))
108
return Err;
109
110
LLVM_DEBUG({
111
dbgs() << " Preparing " << CUSec->blocks_size() << " blocks in "
112
<< CompactUnwindSectionName << "\n";
113
});
114
115
for (auto *B : CUSec->blocks()) {
116
117
// Find target function edge.
118
Edge *PCBeginEdge = nullptr;
119
for (auto &E : B->edges_at(CURecTraits::FnFieldOffset)) {
120
PCBeginEdge = &E;
121
break;
122
}
123
124
if (!PCBeginEdge)
125
return make_error<JITLinkError>(
126
"In " + G.getName() + ", compact unwind record at " +
127
formatv("{0:x}", B->getAddress()) + " has no pc-begin edge");
128
129
if (!PCBeginEdge->getTarget().isDefined())
130
return make_error<JITLinkError>(
131
"In " + G.getName() + ", compact unwind record at " +
132
formatv("{0:x}", B->getAddress()) + " points at external symbol " +
133
*PCBeginEdge->getTarget().getName());
134
135
auto &Fn = PCBeginEdge->getTarget();
136
137
if (!Fn.isDefined()) {
138
LLVM_DEBUG({
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
149
LLVM_DEBUG({
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
// Found a keep-alive edge to an FDE in the eh-frame. Switch the keep
177
// alive edge to point to the CU and if the CU needs DWARF then add
178
// an extra keep-alive edge from the CU to the FDE.
179
auto &FDE = KeepAliveEdge->getTarget();
180
KeepAliveEdge->setTarget(CURecSym);
181
KeepAliveAlreadyPresent = true;
182
if (NeedsDWARF) {
183
LLVM_DEBUG({
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)
191
return make_error<JITLinkError>(
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)
198
return make_error<JITLinkError>(
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
// No FDE edge. We'll need to add a new edge from the function back
206
// to the CU record.
207
Fn.getBlock().addEdge(Edge::KeepAlive, 0, CURecSym, 0);
208
}
209
}
210
211
return Error::success();
212
}
213
214
/// Process all __compact_unwind records and reserve space for __unwind_info.
215
Error processAndReserveUnwindInfo(LinkGraph &G) {
216
// Bail out early if no unwind info.
217
Section *CUSec = G.findSectionByName(CompactUnwindSectionName);
218
if (!CUSec)
219
return Error::success();
220
221
// The __LD/__compact_unwind section is only used as input for the linker.
222
// We'll create a new __TEXT,__unwind_info section for unwind info output.
223
CUSec->setMemLifetime(orc::MemLifetime::NoAlloc);
224
225
// Find / make a mach-header to act as the base for unwind-info offsets
226
// (and to report the arch / subarch to libunwind).
227
if (auto Err = getOrCreateCompactUnwindBase(G))
228
return Err;
229
230
// Error out if there's already unwind-info in the graph: We have no idea
231
// how to merge unwind-info sections.
232
if (G.findSectionByName(UnwindInfoSectionName))
233
return make_error<JITLinkError>("In " + G.getName() + ", " +
234
UnwindInfoSectionName +
235
" already exists");
236
237
// Process the __compact_unwind section to build the Records vector that
238
// we'll use for writing the __unwind_info section.
239
if (auto Err = processCompactUnwind(G, *CUSec))
240
return Err;
241
242
// Calculate the size of __unwind_info.
243
size_t UnwindInfoSectionSize =
244
UnwindInfoSectionHeaderSize +
245
Personalities.size() * PersonalityEntrySize +
246
(NumSecondLevelPages + 1) * IndexEntrySize + NumLSDAs * LSDAEntrySize +
247
NumSecondLevelPages * SecondLevelPageHeaderSize +
248
Records.size() * SecondLevelPageEntrySize;
249
250
LLVM_DEBUG({
251
dbgs() << "In " << G.getName() << ", reserving "
252
<< formatv("{0:x}", UnwindInfoSectionSize) << " bytes for "
253
<< UnwindInfoSectionName << "\n";
254
});
255
256
// Create the __unwind_info section and reserve space for it.
257
Section &UnwindInfoSec =
258
G.createSection(UnwindInfoSectionName, orc::MemProt::Read);
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
// Add Keep-alive edges from the __unwind_info block to all of the target
266
// functions.
267
for (auto &R : Records)
268
B.addEdge(Edge::KeepAlive, 0, *R.Fn, 0);
269
270
return Error::success();
271
}
272
273
Error writeUnwindInfo(LinkGraph &G) {
274
Section *CUSec = G.findSectionByName(CompactUnwindSectionName);
275
if (!CUSec || CUSec->empty())
276
return Error::success();
277
278
Section *UnwindInfoSec = G.findSectionByName(UnwindInfoSectionName);
279
if (!UnwindInfoSec)
280
return make_error<JITLinkError>("In " + G.getName() + ", " +
281
UnwindInfoSectionName +
282
" missing after allocation");
283
284
if (UnwindInfoSec->blocks_size() != 1)
285
return make_error<JITLinkError>(
286
"In " + G.getName() + ", " + UnwindInfoSectionName +
287
" contains more than one block post-allocation");
288
289
LLVM_DEBUG(
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);
296
BinaryStreamWriter Writer(
297
{reinterpret_cast<uint8_t *>(Content.data()), Content.size()},
298
CURecTraits::Endianness);
299
300
// __unwind_info format, from mach-o/compact_unwind_encoding.h on Darwin:
301
//
302
// #define UNWIND_SECTION_VERSION 1
303
// struct unwind_info_section_header
304
// {
305
// uint32_t version; // UNWIND_SECTION_VERSION
306
// uint32_t commonEncodingsArraySectionOffset;
307
// uint32_t commonEncodingsArrayCount;
308
// uint32_t personalityArraySectionOffset;
309
// uint32_t personalityArrayCount;
310
// uint32_t indexSectionOffset;
311
// uint32_t indexCount;
312
// // compact_unwind_encoding_t[]
313
// // uint32_t personalities[]
314
// // unwind_info_section_header_index_entry[]
315
// // unwind_info_section_header_lsda_index_entry[]
316
// };
317
318
if (auto Err = writeHeader(G, Writer))
319
return Err;
320
321
// Skip common encodings: JITLink doesn't use them.
322
323
if (auto Err = writePersonalities(G, Writer))
324
return Err;
325
326
// Calculate the offset to the LSDAs.
327
size_t SectionOffsetToLSDAs =
328
Writer.getOffset() + (NumSecondLevelPages + 1) * IndexEntrySize;
329
330
// Calculate offset to the 1st second-level page.
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
344
LLVM_DEBUG({
345
dbgs() << " Wrote " << formatv("{0:x}", Writer.getOffset())
346
<< " bytes of unwind info.\n";
347
});
348
349
return Error::success();
350
}
351
352
private:
353
// Calculate the size of unwind-info.
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;
370
uint32_t Size = 0;
371
uint32_t Encoding = 0;
372
Symbol *LSDA = nullptr;
373
Symbol *FDE = nullptr;
374
};
375
376
Error processCompactUnwind(LinkGraph &G, Section &CUSec) {
377
// TODO: Reset NumLSDAs, Personalities and CompactUnwindRecords if
378
// processing more than once.
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
383
SmallVector<CompactUnwindRecord> NonUniquedRecords;
384
NonUniquedRecords.reserve(CUSec.blocks_size());
385
386
// Process __compact_unwind blocks.
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
// This could be the function-pointer, or the FDE keep-alive. Check
394
// the type to decide.
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
// Add the Personality to the Personalities map and update the
402
// encoding.
403
size_t PersonalityIdx = 0;
404
for (; PersonalityIdx != Personalities.size(); ++PersonalityIdx)
405
if (Personalities[PersonalityIdx] == &E.getTarget())
406
break;
407
if (PersonalityIdx == MaxPersonalities)
408
return make_error<JITLinkError>(
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:
423
return make_error<JITLinkError>("In " + G.getName() +
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
// Sort the records into ascending order.
434
llvm::sort(Records, [](const CompactUnwindRecord &LHS,
435
const CompactUnwindRecord &RHS) {
436
return LHS.Fn->getAddress() < RHS.Fn->getAddress();
437
});
438
439
// Calculate the number of second-level pages required.
440
NumSecondLevelPages = (Records.size() + NumRecordsPerSecondLevelPage - 1) /
441
NumRecordsPerSecondLevelPage;
442
443
// Convert personality symbols to GOT entry pointers.
444
typename CURecTraits::GOTManager GOT(G);
445
for (auto &Personality : Personalities)
446
Personality = &GOT.getEntryForTarget(G, *Personality);
447
448
LLVM_DEBUG({
449
dbgs() << " In " << G.getName() << ", " << CompactUnwindSectionName
450
<< ": raw records = " << Records.size()
451
<< ", personalities = " << Personalities.size()
452
<< ", lsdas = " << NumLSDAs << "\n";
453
});
454
455
return Error::success();
456
}
457
458
void mergeRecords() {
459
SmallVector<CompactUnwindRecord> 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
// Recalculate derived values that may have changed.
475
NumSecondLevelPages = (Records.size() + NumRecordsPerSecondLevelPage - 1) /
476
NumRecordsPerSecondLevelPage;
477
}
478
479
Error writeHeader(LinkGraph &G, BinaryStreamWriter &W) {
480
if (!isUInt<32>(NumSecondLevelPages + 1))
481
return make_error<JITLinkError>("In " + G.getName() + ", too many " +
482
UnwindInfoSectionName +
483
"second-level pages required");
484
485
// Write __unwind_info header.
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
497
return Error::success();
498
}
499
500
Error writePersonalities(LinkGraph &G, BinaryStreamWriter &W) {
501
// Write personalities.
502
for (auto *PSym : Personalities) {
503
auto Delta = PSym->getAddress() - CompactUnwindBase->getAddress();
504
if (!isUInt<32>(Delta))
505
return makePersonalityRangeError(G, *PSym);
506
cantFail(W.writeInteger<uint32_t>(Delta));
507
}
508
return Error::success();
509
}
510
511
Error writeIndexes(LinkGraph &G, BinaryStreamWriter &W,
512
size_t SectionOffsetToLSDAs,
513
size_t SectionOffsetToSecondLevelPages) {
514
// Assume that function deltas are ok in this method -- we'll error
515
// check all of them when we write the second level pages.
516
517
// Write the header index entries.
518
size_t RecordIdx = 0;
519
size_t NumPreviousLSDAs = 0;
520
for (auto &R : Records) {
521
// If this record marks the start of a new second level page.
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
// Write the index array terminator.
540
{
541
auto FnEndDelta =
542
Records.back().Fn->getRange().End - CompactUnwindBase->getAddress();
543
544
if (LLVM_UNLIKELY(!isUInt<32>(FnEndDelta)))
545
return make_error<JITLinkError>(
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
556
return Error::success();
557
}
558
559
Error writeLSDAs(LinkGraph &G, BinaryStreamWriter &W) {
560
// As with writeIndexes, assume that function deltas are ok for now.
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
566
if (LLVM_UNLIKELY(!isUInt<32>(LSDADelta)))
567
return make_error<JITLinkError>(
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
577
return Error::success();
578
}
579
580
Error writeSecondLevelPages(LinkGraph &G, BinaryStreamWriter &W) {
581
size_t RecordIdx = 0;
582
583
for (auto &R : Records) {
584
// When starting a new second-level page, write the page header:
585
//
586
// 2 : uint32_t -- UNWIND_SECOND_LEVEL_REGULAR
587
// 8 : uint16_t -- size of second level page table header
588
// count : uint16_t -- num entries in this second-level page
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
// Write entry.
601
auto FnDelta = R.Fn->getAddress() - CompactUnwindBase->getAddress();
602
603
if (LLVM_UNLIKELY(!isUInt<32>(FnDelta)))
604
return make_error<JITLinkError>(
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
619
return make_error<JITLinkError>(
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
631
return Error::success();
632
}
633
634
Error getOrCreateCompactUnwindBase(LinkGraph &G) {
635
auto Name = G.intern("__jitlink$libunwind_dso_base");
636
CompactUnwindBase = G.findAbsoluteSymbolByName(Name);
637
if (!CompactUnwindBase) {
638
if (auto LocalCUBase = getOrCreateLocalMachOHeader(G)) {
639
CompactUnwindBase = &*LocalCUBase;
640
auto &B = LocalCUBase->getBlock();
641
G.addDefinedSymbol(B, 0, *Name, B.getSize(), Linkage::Strong,
642
Scope::Local, false, true);
643
} else
644
return LocalCUBase.takeError();
645
}
646
CompactUnwindBase->setLive(true);
647
return Error::success();
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
}
662
return make_error<JITLinkError>(std::move(ErrMsg));
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;
673
SmallVector<Symbol *, MaxPersonalities> Personalities;
674
SmallVector<CompactUnwindRecord> Records;
675
};
676
677
} // end namespace jitlink
678
} // end namespace llvm
679
680
#undef DEBUG_TYPE
681
682
#endif // LIB_EXECUTIONENGINE_JITLINK_COMPACTUNWINDSUPPORTIMPL_H
683
684