-
Notifications
You must be signed in to change notification settings - Fork 351
[lldb] Add support for multipayload enums lookup from DWARF #8171
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: stable/20230725
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -73,7 +73,7 @@ getFieldDescriptorKindForDie(CompilerType type) { | |
| return swift::reflection::FieldDescriptorKind::Class; | ||
| case lldb::eTypeClassStruct: | ||
| return swift::reflection::FieldDescriptorKind::Struct; | ||
| case lldb::eTypeClassEnumeration: | ||
| case lldb::eTypeClassUnion: | ||
| return swift::reflection::FieldDescriptorKind::Enum; | ||
| default: | ||
| LLDB_LOG(GetLog(LLDBLog::Types), | ||
|
|
@@ -203,7 +203,12 @@ class DWARFFieldDescriptorImpl : public swift::reflection::FieldDescriptorBase { | |
| std::vector<std::unique_ptr<swift::reflection::FieldRecordBase>> | ||
| getFieldRecordsFromEnum(const DWARFDIE &die, | ||
| plugin::dwarf::DWARFASTParser *dwarf_parser) { | ||
| std::vector<std::unique_ptr<swift::reflection::FieldRecordBase>> fields; | ||
| // Type lowering expects the payload fields to come before the non-payload | ||
| // ones. | ||
| std::vector<std::unique_ptr<swift::reflection::FieldRecordBase>> | ||
| payload_fields; | ||
| std::vector<std::unique_ptr<swift::reflection::FieldRecordBase>> | ||
| non_payload_fields; | ||
| auto variant_part = die.GetFirstChild(); | ||
| for (DWARFDIE child_die : variant_part.children()) { | ||
| auto tag = child_die.Tag(); | ||
|
|
@@ -227,11 +232,69 @@ class DWARFFieldDescriptorImpl : public swift::reflection::FieldDescriptorBase { | |
| bool is_indirect_case = false; | ||
| // Unused by type info construction. | ||
| bool is_var = false; | ||
| fields.emplace_back(std::make_unique<DWARFFieldRecordImpl>( | ||
| is_indirect_case, is_var, ConstString(member_field_name), | ||
| member_mangled_typename)); | ||
|
|
||
| // If there is a type, this case has a payload. | ||
| if (member_type) | ||
| payload_fields.emplace_back(std::make_unique<DWARFFieldRecordImpl>( | ||
| is_indirect_case, is_var, ConstString(member_field_name), | ||
| member_mangled_typename)); | ||
| else | ||
| non_payload_fields.emplace_back(std::make_unique<DWARFFieldRecordImpl>( | ||
| is_indirect_case, is_var, ConstString(member_field_name), | ||
| member_mangled_typename)); | ||
| } | ||
| return fields; | ||
| // Add the non-payload cases to the end. | ||
| payload_fields.insert(payload_fields.end(), | ||
| std::make_move_iterator(non_payload_fields.begin()), | ||
| std::make_move_iterator(non_payload_fields.end())); | ||
| return payload_fields; | ||
| } | ||
| }; | ||
|
|
||
| class DWARFMultiPayloadEnumDescriptorImpl | ||
| : public swift::reflection::MultiPayloadEnumDescriptorBase { | ||
| ConstString m_mangled_name; | ||
| DIERef m_die_ref; | ||
| std::vector<uint8_t> m_spare_bits_mask; | ||
| uint64_t m_byte_offset; | ||
|
|
||
| public: | ||
| ~DWARFMultiPayloadEnumDescriptorImpl() override = default; | ||
|
|
||
| DWARFMultiPayloadEnumDescriptorImpl(ConstString mangled_name, DIERef die_ref, | ||
| std::vector<uint8_t> &&spare_bits_mask, | ||
| uint64_t byte_offset) | ||
| : swift::reflection::MultiPayloadEnumDescriptorBase(), | ||
| m_mangled_name(mangled_name), m_die_ref(die_ref), | ||
| m_spare_bits_mask(std::move(spare_bits_mask)), | ||
| m_byte_offset(byte_offset) {} | ||
|
|
||
| llvm::StringRef getMangledTypeName() override { | ||
| return m_mangled_name.GetStringRef(); | ||
| } | ||
|
|
||
| uint32_t getContentsSizeInWords() const override { | ||
| return m_spare_bits_mask.size() / 4; | ||
| } | ||
|
|
||
| size_t getSizeInBytes() const override { return m_spare_bits_mask.size(); } | ||
|
|
||
| uint32_t getFlags() const override { return usesPayloadSpareBits(); } | ||
|
|
||
| bool usesPayloadSpareBits() const override { | ||
| return !m_spare_bits_mask.empty(); | ||
| } | ||
|
|
||
| uint32_t getPayloadSpareBitMaskByteOffset() const override { | ||
| return m_byte_offset; | ||
| } | ||
|
|
||
| uint32_t getPayloadSpareBitMaskByteCount() const override { | ||
| return getSizeInBytes(); | ||
| } | ||
|
|
||
| const uint8_t *getPayloadSpareBits() const override { | ||
| return m_spare_bits_mask.data(); | ||
| } | ||
| }; | ||
| } // namespace | ||
|
|
@@ -261,8 +324,8 @@ DWARFASTParserSwift::getBuiltinTypeDescriptor( | |
| die.GetAttributeValueAsUnsigned(DW_AT_byte_size, LLDB_INVALID_ADDRESS); | ||
| if (byte_size == LLDB_INVALID_ADDRESS) | ||
| return {}; | ||
| auto alignment = die.GetAttributeValueAsUnsigned( | ||
| DW_AT_alignment, byte_size == 0 ? 1 : byte_size); | ||
|
|
||
| auto alignment = die.GetAttributeValueAsUnsigned(DW_AT_alignment, 8); | ||
|
|
||
| // TODO: this seems simple to calculate but maybe we should encode the stride | ||
| // in DWARF? That's what reflection metadata does. | ||
|
|
@@ -278,6 +341,97 @@ DWARFASTParserSwift::getBuiltinTypeDescriptor( | |
| type.GetMangledTypeName()); | ||
| } | ||
|
|
||
| std::unique_ptr<swift::reflection::MultiPayloadEnumDescriptorBase> | ||
| DWARFASTParserSwift::getMultiPayloadEnumDescriptor( | ||
| const swift::reflection::TypeRef *TR) { | ||
| if (!Target::GetGlobalProperties().GetSwiftEnableFullDwarfDebugging()) | ||
| return nullptr; | ||
|
|
||
| auto pair = getTypeAndDie(m_swift_typesystem, TR); | ||
| if (!pair) | ||
| return nullptr; | ||
|
|
||
| auto [type, die] = *pair; | ||
| if (!die) | ||
| return nullptr; | ||
|
|
||
| auto kind = getFieldDescriptorKindForDie(type); | ||
| if (!kind) | ||
| return nullptr; | ||
|
|
||
| auto child_die = die.GetFirstChild(); | ||
| auto bit_offset = | ||
| child_die.GetAttributeValueAsUnsigned(llvm::dwarf::DW_AT_bit_offset, 0); | ||
|
|
||
| auto byte_offset = (bit_offset + 7) / 8; | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you use an llvm::align function from MatchExtras.h here? |
||
| const auto spare_bits_mask_die_it = | ||
| llvm::find_if(die.children(), [&](const DWARFDIE &child_die) { | ||
| return child_die.Tag() == llvm::dwarf::DW_TAG_APPLE_spare_bits_mask; | ||
| }); | ||
|
|
||
| if (spare_bits_mask_die_it == child_die.children().end()) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think these error cases should probably all go to the dwarf log channel? |
||
| return nullptr; | ||
|
|
||
| auto spare_bits_mask_die = *spare_bits_mask_die_it; | ||
| DWARFAttributes attributes = spare_bits_mask_die.GetAttributes(); | ||
| assert(attributes.Size() == 1 && | ||
| "Unexpected attributes on spare bits mask die"); | ||
| if (attributes.Size() != 1) | ||
| return nullptr; | ||
|
|
||
| dw_attr_t attribute = attributes.AttributeAtIndex(0); | ||
| assert(attribute == llvm::dwarf::DW_AT_const_value && | ||
| "Unexpected attribute type on spare bits mask die"); | ||
| if (attribute != llvm::dwarf::DW_AT_const_value) | ||
| return nullptr; | ||
|
|
||
| DWARFFormValue form_value; | ||
| attributes.ExtractFormValueAtIndex(0, form_value); | ||
|
|
||
| if (!form_value.IsValid()) { | ||
| if (auto *log = GetLog(LLDBLog::Types)) { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Dwarf instead of Types? Or maybe both? |
||
| std::stringstream ss; | ||
| TR->dump(ss); | ||
| LLDB_LOG(log, | ||
| "Could not produce MultiPayloadEnumTypeInfo for typeref: {0}", | ||
| ss.str()); | ||
| } | ||
| return nullptr; | ||
| } | ||
| // If there's a block data, this is a number bigger than 64 bits already | ||
| // encoded as an array. | ||
| if (form_value.BlockData()) { | ||
| uint64_t block_length = form_value.Unsigned(); | ||
| std::vector<uint8_t> bytes(form_value.BlockData(), | ||
| form_value.BlockData() + block_length); | ||
| return std::make_unique<DWARFMultiPayloadEnumDescriptorImpl>( | ||
| type.GetMangledTypeName(), *die.GetDIERef(), | ||
| std::move(bytes), byte_offset); | ||
| } | ||
|
|
||
| // If there is no block data, the spare bits mask is encoded as a single 64 | ||
| // bit number. Convert this to a byte array with only the amount of bytes | ||
| // necessary to cover the whole number (see | ||
| // MultiPayloadEnumDescriptorBuilder::layout on GenReflection.cpp for a | ||
| // similar calculation when emitting this into metadata). | ||
| llvm::APInt bits(64, form_value.Unsigned()); | ||
| auto bitsInMask = bits.getActiveBits(); | ||
| uint32_t bytesInMask = (bitsInMask + 7) / 8; | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. use mathextras? |
||
| auto wordsInMask = (bytesInMask + 3) / 4; | ||
| bits = bits.zextOrTrunc(wordsInMask * 32); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. is this independent of ptrsize? |
||
|
|
||
| std::vector<uint8_t> bytes; | ||
| for (size_t i = 0; i < bytesInMask; ++i) { | ||
| uint8_t byte = bits.extractBitsAsZExtValue(8, 0); | ||
| bytes.push_back(byte); | ||
| bits.lshrInPlace(8); | ||
| } | ||
|
|
||
| return std::make_unique<DWARFMultiPayloadEnumDescriptorImpl>( | ||
| type.GetMangledTypeName(), *die.GetDIERef(), std::move(bytes), | ||
| byte_offset); | ||
| } | ||
|
|
||
| namespace { | ||
| DWARFDIE FindSuperClassDIE(DWARFDIE &die) { | ||
| const auto inheritance_die_it = | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This could benefit from a comment. Why 4; (is this dependent on ptrsize?) is this always divisible?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm using the same terminology as
GenReflectionfor the function name here. A word in this case is 32 bits long so always divisible by 4.