Skip to content

Commit 3f5ee9c

Browse files
authored
Merge pull request #8243 from augusto2112/spare-bits-spec
[lldb] Emit specification and spare_bits_mask in debug info, consume them in lldb
2 parents 3ffb6c4 + 5be181d commit 3f5ee9c

File tree

22 files changed

+631
-141
lines changed

22 files changed

+631
-141
lines changed

lldb/source/Plugins/LanguageRuntime/Swift/ReflectionContext.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,12 @@ struct DescriptorFinderForwarder : public swift::reflection::DescriptorFinder {
4444
return nullptr;
4545
}
4646

47+
std::unique_ptr<swift::reflection::MultiPayloadEnumDescriptorBase>
48+
getMultiPayloadEnumDescriptor(const swift::reflection::TypeRef *TR) override {
49+
if (m_descriptor_finder)
50+
return m_descriptor_finder->getMultiPayloadEnumDescriptor(TR);
51+
return nullptr;
52+
}
4753
void SetExternalDescriptorFinder(
4854
swift::reflection::DescriptorFinder *desciptor_finder) {
4955
m_descriptor_finder = desciptor_finder;

lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserSwift.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,10 @@ class DWARFASTParserSwift : public lldb_private::plugin::dwarf::DWARFASTParser,
8989
std::unique_ptr<swift::reflection::BuiltinTypeDescriptorBase>
9090
getBuiltinTypeDescriptor(const swift::reflection::TypeRef *TR) override;
9191

92+
/// Returns a builtin descriptor constructed from DWARF info.
93+
std::unique_ptr<swift::reflection::MultiPayloadEnumDescriptorBase>
94+
getMultiPayloadEnumDescriptor(const swift::reflection::TypeRef *TR) override;
95+
9296
private:
9397
/// Returns the canonical demangle tree of a die's type.
9498
NodePointer GetCanonicalDemangleTree(DWARFDIE &die);

lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserSwiftDescriptorFinder.cpp

Lines changed: 148 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ getFieldDescriptorKindForDie(CompilerType type) {
7373
return swift::reflection::FieldDescriptorKind::Class;
7474
case lldb::eTypeClassStruct:
7575
return swift::reflection::FieldDescriptorKind::Struct;
76-
case lldb::eTypeClassEnumeration:
76+
case lldb::eTypeClassUnion:
7777
return swift::reflection::FieldDescriptorKind::Enum;
7878
default:
7979
LLDB_LOG(GetLog(LLDBLog::Types),
@@ -203,7 +203,12 @@ class DWARFFieldDescriptorImpl : public swift::reflection::FieldDescriptorBase {
203203
std::vector<std::unique_ptr<swift::reflection::FieldRecordBase>>
204204
getFieldRecordsFromEnum(const DWARFDIE &die,
205205
plugin::dwarf::DWARFASTParser *dwarf_parser) {
206-
std::vector<std::unique_ptr<swift::reflection::FieldRecordBase>> fields;
206+
// Type lowering expects the payload fields to come before the non-payload
207+
// ones.
208+
std::vector<std::unique_ptr<swift::reflection::FieldRecordBase>>
209+
payload_fields;
210+
std::vector<std::unique_ptr<swift::reflection::FieldRecordBase>>
211+
non_payload_fields;
207212
auto variant_part = die.GetFirstChild();
208213
for (DWARFDIE child_die : variant_part.children()) {
209214
auto tag = child_die.Tag();
@@ -227,11 +232,69 @@ class DWARFFieldDescriptorImpl : public swift::reflection::FieldDescriptorBase {
227232
bool is_indirect_case = false;
228233
// Unused by type info construction.
229234
bool is_var = false;
230-
fields.emplace_back(std::make_unique<DWARFFieldRecordImpl>(
231-
is_indirect_case, is_var, ConstString(member_field_name),
232-
member_mangled_typename));
235+
236+
// If there is a type, this case has a payload.
237+
if (member_type)
238+
payload_fields.emplace_back(std::make_unique<DWARFFieldRecordImpl>(
239+
is_indirect_case, is_var, ConstString(member_field_name),
240+
member_mangled_typename));
241+
else
242+
non_payload_fields.emplace_back(std::make_unique<DWARFFieldRecordImpl>(
243+
is_indirect_case, is_var, ConstString(member_field_name),
244+
member_mangled_typename));
233245
}
234-
return fields;
246+
// Add the non-payload cases to the end.
247+
payload_fields.insert(payload_fields.end(),
248+
std::make_move_iterator(non_payload_fields.begin()),
249+
std::make_move_iterator(non_payload_fields.end()));
250+
return payload_fields;
251+
}
252+
};
253+
254+
class DWARFMultiPayloadEnumDescriptorImpl
255+
: public swift::reflection::MultiPayloadEnumDescriptorBase {
256+
ConstString m_mangled_name;
257+
DIERef m_die_ref;
258+
std::vector<uint8_t> m_spare_bits_mask;
259+
uint64_t m_byte_offset;
260+
261+
public:
262+
~DWARFMultiPayloadEnumDescriptorImpl() override = default;
263+
264+
DWARFMultiPayloadEnumDescriptorImpl(ConstString mangled_name, DIERef die_ref,
265+
std::vector<uint8_t> &&spare_bits_mask,
266+
uint64_t byte_offset)
267+
: swift::reflection::MultiPayloadEnumDescriptorBase(),
268+
m_mangled_name(mangled_name), m_die_ref(die_ref),
269+
m_spare_bits_mask(std::move(spare_bits_mask)),
270+
m_byte_offset(byte_offset) {}
271+
272+
llvm::StringRef getMangledTypeName() override {
273+
return m_mangled_name.GetStringRef();
274+
}
275+
276+
uint32_t getContentsSizeInWords() const override {
277+
return m_spare_bits_mask.size() / 4;
278+
}
279+
280+
size_t getSizeInBytes() const override { return m_spare_bits_mask.size(); }
281+
282+
uint32_t getFlags() const override { return usesPayloadSpareBits(); }
283+
284+
bool usesPayloadSpareBits() const override {
285+
return !m_spare_bits_mask.empty();
286+
}
287+
288+
uint32_t getPayloadSpareBitMaskByteOffset() const override {
289+
return m_byte_offset;
290+
}
291+
292+
uint32_t getPayloadSpareBitMaskByteCount() const override {
293+
return getSizeInBytes();
294+
}
295+
296+
const uint8_t *getPayloadSpareBits() const override {
297+
return m_spare_bits_mask.data();
235298
}
236299
};
237300
} // namespace
@@ -261,8 +324,8 @@ DWARFASTParserSwift::getBuiltinTypeDescriptor(
261324
die.GetAttributeValueAsUnsigned(DW_AT_byte_size, LLDB_INVALID_ADDRESS);
262325
if (byte_size == LLDB_INVALID_ADDRESS)
263326
return {};
264-
auto alignment = die.GetAttributeValueAsUnsigned(
265-
DW_AT_alignment, byte_size == 0 ? 1 : byte_size);
327+
328+
auto alignment = die.GetAttributeValueAsUnsigned(DW_AT_alignment, 8);
266329

267330
// TODO: this seems simple to calculate but maybe we should encode the stride
268331
// in DWARF? That's what reflection metadata does.
@@ -278,6 +341,83 @@ DWARFASTParserSwift::getBuiltinTypeDescriptor(
278341
type.GetMangledTypeName());
279342
}
280343

344+
std::unique_ptr<swift::reflection::MultiPayloadEnumDescriptorBase>
345+
DWARFASTParserSwift::getMultiPayloadEnumDescriptor(
346+
const swift::reflection::TypeRef *TR) {
347+
if (!Target::GetGlobalProperties().GetSwiftEnableFullDwarfDebugging())
348+
return nullptr;
349+
350+
auto pair = getTypeAndDie(m_swift_typesystem, TR);
351+
if (!pair)
352+
return nullptr;
353+
354+
auto [type, die] = *pair;
355+
if (!die)
356+
return nullptr;
357+
358+
auto kind = getFieldDescriptorKindForDie(type);
359+
if (!kind)
360+
return nullptr;
361+
362+
auto child_die = die.GetFirstChild();
363+
auto bit_offset =
364+
child_die.GetAttributeValueAsUnsigned(llvm::dwarf::DW_AT_bit_offset, 0);
365+
366+
auto byte_offset = (bit_offset + 7) / 8;
367+
368+
const auto &attributes = child_die.GetAttributes();
369+
auto spare_bits_mask_idx =
370+
attributes.FindAttributeIndex(llvm::dwarf::DW_AT_APPLE_spare_bits_mask);
371+
if (spare_bits_mask_idx == UINT32_MAX)
372+
return nullptr;
373+
374+
DWARFFormValue form_value;
375+
attributes.ExtractFormValueAtIndex(spare_bits_mask_idx, form_value);
376+
377+
if (!form_value.IsValid()) {
378+
if (auto *log = GetLog(LLDBLog::Types)) {
379+
std::stringstream ss;
380+
TR->dump(ss);
381+
LLDB_LOG(log,
382+
"Could not produce MultiPayloadEnumTypeInfo for typeref: {0}",
383+
ss.str());
384+
}
385+
return nullptr;
386+
}
387+
// If there's a block data, this is a number bigger than 64 bits already
388+
// encoded as an array.
389+
if (form_value.BlockData()) {
390+
uint64_t block_length = form_value.Unsigned();
391+
std::vector<uint8_t> bytes(form_value.BlockData(),
392+
form_value.BlockData() + block_length);
393+
return std::make_unique<DWARFMultiPayloadEnumDescriptorImpl>(
394+
type.GetMangledTypeName(), *die.GetDIERef(),
395+
std::move(bytes), byte_offset);
396+
}
397+
398+
// If there is no block data, the spare bits mask is encoded as a single 64
399+
// bit number. Convert this to a byte array with only the amount of bytes
400+
// necessary to cover the whole number (see
401+
// MultiPayloadEnumDescriptorBuilder::layout on GenReflection.cpp for a
402+
// similar calculation when emitting this into metadata).
403+
llvm::APInt bits(64, form_value.Unsigned());
404+
auto bitsInMask = bits.getActiveBits();
405+
uint32_t bytesInMask = (bitsInMask + 7) / 8;
406+
auto wordsInMask = (bytesInMask + 3) / 4;
407+
bits = bits.zextOrTrunc(wordsInMask * 32);
408+
409+
std::vector<uint8_t> bytes;
410+
for (size_t i = 0; i < bytesInMask; ++i) {
411+
uint8_t byte = bits.extractBitsAsZExtValue(8, 0);
412+
bytes.push_back(byte);
413+
bits.lshrInPlace(8);
414+
}
415+
416+
return std::make_unique<DWARFMultiPayloadEnumDescriptorImpl>(
417+
type.GetMangledTypeName(), *die.GetDIERef(), std::move(bytes),
418+
byte_offset);
419+
}
420+
281421
namespace {
282422
DWARFDIE FindSuperClassDIE(DWARFDIE &die) {
283423
const auto inheritance_die_it =

lldb/source/Plugins/TypeSystem/Swift/TypeSystemSwiftTypeRef.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3443,6 +3443,9 @@ size_t TypeSystemSwiftTypeRef::GetIndexOfChildMemberWithName(
34433443
#ifndef NDEBUG
34443444
// This block is a custom VALIDATE_AND_RETURN implementation to support
34453445
// checking the return value, plus the by-ref `child_indexes`.
3446+
if (!ModuleList::GetGlobalModuleListProperties()
3447+
.GetSwiftValidateTypeSystem())
3448+
return index_size;
34463449
if (!GetSwiftASTContextFromExecutionContext(exe_ctx))
34473450
return index_size;
34483451
auto swift_scratch_ctx_lock = SwiftScratchContextLock(exe_ctx);

lldb/test/API/lang/swift/embedded/frame_variable/TestSwiftEmbeddedFrameVariable.py

Lines changed: 97 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,102 @@ def test(self):
3030
],
3131
)
3232

33-
# TODO: test enums when "rdar://119343683 (Embedded Swift trivial case enum fails to link)" is solved
33+
self.expect(
34+
"frame variable nonPayload1", substrs=["NonPayloadEnum) nonPayload1 = one"]
35+
)
36+
self.expect(
37+
"frame variable nonPayload2", substrs=["NonPayloadEnum) nonPayload2 = two"]
38+
)
39+
self.expect(
40+
"frame variable singlePayload",
41+
substrs=[
42+
"SinglePayloadEnum) singlePayload = ",
43+
"payload {",
44+
"a = (field = 4.2000000000000002)",
45+
"b = 123456",
46+
],
47+
)
48+
self.expect(
49+
"frame variable emptySinglePayload",
50+
substrs=["SinglePayloadEnum) emptySinglePayload = nonPayloadTwo"],
51+
)
3452

35-
self.expect("frame variable sup", substrs=["Sup) sup = ", "supField = 42"])
36-
self.expect("frame variable sub", substrs=["Sub) sub = ", "Sup = {", "supField = 42", "subField = {", "a = (field = 4.2000000000000002", "b = 123456"])
37-
self.expect("frame variable subSub", substrs=["SubSub) subSub =", "a.Sub = {", "a.Sup = {", "supField = 42", "subField = {", "a = (field = 4.2000000000000002", "b = 123456", "subSubField = (field = 4.2000000000000002)"])
53+
self.expect(
54+
"frame variable smallMultipayloadEnum1",
55+
substrs=[
56+
"SmallMultipayloadEnum) smallMultipayloadEnum1 = one {",
57+
"one = two",
58+
],
59+
)
60+
self.expect(
61+
"frame variable smallMultipayloadEnum2",
62+
substrs=[
63+
"SmallMultipayloadEnum) smallMultipayloadEnum2 = two {",
64+
"two = one",
65+
],
66+
)
67+
self.expect(
68+
"frame variable bigMultipayloadEnum1",
69+
substrs=[
70+
"BigMultipayloadEnum) bigMultipayloadEnum1 = one {",
71+
"0 = ",
72+
"(supField = 42)",
73+
"1 = ",
74+
"(supField = 43)",
75+
"2 = ",
76+
"(supField = 44)",
77+
],
78+
)
79+
80+
self.expect(
81+
"frame variable fullMultipayloadEnum1",
82+
substrs=["FullMultipayloadEnum) fullMultipayloadEnum1 = ", "(one = 120)"],
83+
)
84+
self.expect(
85+
"frame variable fullMultipayloadEnum2",
86+
substrs=[
87+
"FullMultipayloadEnum) fullMultipayloadEnum2 = ",
88+
"(two = 9.2100000000000008)",
89+
],
90+
)
91+
92+
self.expect(
93+
"frame variable bigFullMultipayloadEnum1",
94+
substrs=[
95+
"a.BigFullMultipayloadEnum) bigFullMultipayloadEnum1 = one {",
96+
"one = (0 = 209, 1 = 315)",
97+
],
98+
)
99+
self.expect(
100+
"frame variable bigFullMultipayloadEnum2",
101+
substrs=[
102+
"a.BigFullMultipayloadEnum) bigFullMultipayloadEnum2 = two {",
103+
"two = (0 = 452.19999999999999, 1 = 753.89999999999998)",
104+
],
105+
)
38106

107+
self.expect("frame variable sup", substrs=["Sup) sup = ", "supField = 42"])
108+
self.expect(
109+
"frame variable sub",
110+
substrs=[
111+
"Sub) sub = ",
112+
"Sup = {",
113+
"supField = 42",
114+
"subField = {",
115+
"a = (field = 4.2000000000000002",
116+
"b = 123456",
117+
],
118+
)
119+
self.expect(
120+
"frame variable subSub",
121+
substrs=[
122+
"SubSub) subSub =",
123+
"a.Sub = {",
124+
"a.Sup = {",
125+
"supField = 42",
126+
"subField = {",
127+
"a = (field = 4.2000000000000002",
128+
"b = 123456",
129+
"subSubField = (field = 4.2000000000000002)",
130+
],
131+
)

0 commit comments

Comments
 (0)