diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserSwift.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserSwift.h index 06e0d2ea977423..9226281ec27ccd 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserSwift.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserSwift.h @@ -89,8 +89,13 @@ class DWARFASTParserSwift : public lldb_private::plugin::dwarf::DWARFASTParser, std::unique_ptr getBuiltinTypeDescriptor(const swift::reflection::TypeRef *TR) override; +private: + /// Returns the canonical demangle tree of a die's type. + NodePointer GetCanonicalDemangleTree(DWARFDIE &die); + protected: lldb_private::TypeSystemSwiftTypeRef &m_swift_typesystem; + swift::Demangle::Demangler m_dem; }; #endif // SymbolFileDWARF_DWARFASTParserSwift_h_ diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserSwiftDescriptorFinder.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserSwiftDescriptorFinder.cpp index 417ad62782e341..bf862eb71b8b52 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserSwiftDescriptorFinder.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserSwiftDescriptorFinder.cpp @@ -13,16 +13,19 @@ // //===----------------------------------------------------------------------===// +#include + +#include "DWARFDebugInfo.h" #include "DWARFASTParserSwift.h" #include "DWARFDIE.h" -#include "DWARFDebugInfo.h" -#include "Plugins/LanguageRuntime/Swift/SwiftLanguageRuntime.h" #include "Plugins/TypeSystem/Swift/TypeSystemSwiftTypeRef.h" - #include "swift/RemoteInspection/TypeLowering.h" +#include "lldb/Utility/LLDBLog.h" +#include "lldb/Utility/Log.h" +#include "lldb/Target/Target.h" using namespace lldb; using namespace lldb_private; @@ -38,30 +41,46 @@ getTypeAndDie(TypeSystemSwiftTypeRef &ts, swift::Demangle::Demangler dem; swift::Demangle::NodePointer node = TR->getDemangling(dem); auto type = ts.RemangleAsType(dem, node); - if (!type) + if (!type) { + if (auto log = GetLog(LLDBLog::Types)) { + std::stringstream ss; + TR->dump(ss); + LLDB_LOG(log, "Could not find type for typeref: {0}", ss.str()); + } return {}; + } auto *dwarf = llvm::cast_or_null(ts.GetSymbolFile()); if (!dwarf) return {}; auto lldb_type = ts.FindTypeInModule(type.GetOpaqueQualType()); - if (!lldb_type) + if (!lldb_type) { // TODO: for embedded Swift this is fine but consult other modules here for // general case? + LLDB_LOGV(GetLog(LLDBLog::Types), "Could not find type {0} in module", + type.GetMangledTypeName()); return {}; + } auto die = dwarf->GetDIE(lldb_type->GetID()); return {{type, die}}; } static std::optional -getFieldDescriptorKindForDie(DWARFDIE &die) { - if (die.Tag() == DW_TAG_structure_type) { - if (die.HasChildren() && die.GetFirstChild().Tag() == llvm::dwarf::DW_TAG_variant_part) - return swift::reflection::FieldDescriptorKind::Enum; +getFieldDescriptorKindForDie(CompilerType type) { + auto type_class = type.GetTypeClass(); + switch (type_class) { + case lldb::eTypeClassClass: + return swift::reflection::FieldDescriptorKind::Class; + case lldb::eTypeClassStruct: return swift::reflection::FieldDescriptorKind::Struct; + case lldb::eTypeClassEnumeration: + return swift::reflection::FieldDescriptorKind::Enum; + default: + LLDB_LOG(GetLog(LLDBLog::Types), + "Could not determine file descriptor kind for type: {0}", + type.GetMangledTypeName()); + return {}; } - // TODO: handle more cases, for now we only support structs and enums. - return {}; } namespace { @@ -108,20 +127,23 @@ class DWARFFieldDescriptorImpl : public swift::reflection::FieldDescriptorBase { TypeSystemSwiftTypeRef &m_type_system; ConstString m_mangled_name; DIERef m_die_ref; + NodePointer m_superclass_node; public: DWARFFieldDescriptorImpl(swift::reflection::FieldDescriptorKind kind, - bool has_superclass, + NodePointer superclass_node, TypeSystemSwiftTypeRef &type_system, ConstString mangled_name, DIERef die_ref) - : swift::reflection::FieldDescriptorBase(kind, has_superclass), + : swift::reflection::FieldDescriptorBase(kind, + superclass_node != nullptr), m_type_system(type_system), m_mangled_name(mangled_name), - m_die_ref(die_ref) {} + m_die_ref(die_ref), m_superclass_node(superclass_node) {} ~DWARFFieldDescriptorImpl() override = default; - // TODO: implement this. - swift::Demangle::NodePointer demangleSuperclass() override { return nullptr; } + swift::Demangle::NodePointer demangleSuperclass() override { + return m_superclass_node; + } std::vector> getFieldRecords() override { @@ -139,17 +161,22 @@ class DWARFFieldDescriptorImpl : public swift::reflection::FieldDescriptorBase { switch (Kind) { case swift::reflection::FieldDescriptorKind::Struct: - return getFieldRecordsFromStruct(die, dwarf_parser); + case swift::reflection::FieldDescriptorKind::Class: + return getFieldRecordsFromStructOrClass(die, dwarf_parser); case swift::reflection::FieldDescriptorKind::Enum: return getFieldRecordsFromEnum(die, dwarf_parser); default: // TODO: handle more cases. + LLDB_LOG(GetLog(LLDBLog::Types), + "Trying to get field records of unexpected kind: {0}", + (uint8_t)Kind); + assert(false && "Trying to get field records of unexpected kind"); return {}; } } std::vector> - getFieldRecordsFromStruct(const DWARFDIE &die, + getFieldRecordsFromStructOrClass(const DWARFDIE &die, plugin::dwarf::DWARFASTParser *dwarf_parser) { std::vector> fields; for (DWARFDIE child_die : die.children()) { @@ -221,12 +248,14 @@ DWARFASTParserSwift::getBuiltinTypeDescriptor( return nullptr; auto &[type, die] = *pair; - if (die.Tag() == llvm::dwarf::DW_TAG_structure_type) { - auto child = die.GetFirstChild(); - if (child.Tag() != llvm::dwarf::DW_TAG_variant_part) + if (!TypeSystemSwiftTypeRef::IsBuiltinType(type)) { + if (die.Tag() == llvm::dwarf::DW_TAG_structure_type) { + auto child = die.GetFirstChild(); + if (child.Tag() != llvm::dwarf::DW_TAG_variant_part) + return nullptr; + } else if (die.Tag() != llvm::dwarf::DW_TAG_base_type) return nullptr; - } else if (die.Tag() != llvm::dwarf::DW_TAG_base_type) - return nullptr; + } auto byte_size = die.GetAttributeValueAsUnsigned(DW_AT_byte_size, LLDB_INVALID_ADDRESS); @@ -249,6 +278,35 @@ DWARFASTParserSwift::getBuiltinTypeDescriptor( type.GetMangledTypeName()); } +namespace { +DWARFDIE FindSuperClassDIE(DWARFDIE &die) { + const auto inheritance_die_it = + llvm::find_if(die.children(), [&](const DWARFDIE &child_die) { + return child_die.Tag() == llvm::dwarf::DW_TAG_inheritance; + }); + + if (inheritance_die_it == die.children().end()) + return {}; + + auto inheritance_die = *inheritance_die_it; + const auto superclass_type_die = + inheritance_die.GetAttributeValueAsReferenceDIE(llvm::dwarf::DW_AT_type); + return superclass_type_die; +} +} // namespace + +NodePointer DWARFASTParserSwift::GetCanonicalDemangleTree(DWARFDIE &die) { + const auto name = StringRef( + die.GetAttributeValueAsString(llvm::dwarf::DW_AT_linkage_name, "")); + + if (name.empty()) + return nullptr; + + auto *node = + m_swift_typesystem.GetCanonicalDemangleTree(m_dem, name); + return node; +} + std::unique_ptr DWARFASTParserSwift::getFieldDescriptor(const swift::reflection::TypeRef *TR) { if (!Target::GetGlobalProperties().GetSwiftEnableFullDwarfDebugging()) @@ -260,12 +318,14 @@ DWARFASTParserSwift::getFieldDescriptor(const swift::reflection::TypeRef *TR) { auto [type, die] = *pair; if (!die) return nullptr; - auto kind = getFieldDescriptorKindForDie(die); + auto kind = getFieldDescriptorKindForDie(type); if (!kind) return nullptr; -// TODO: encode this in DWARF, maybe as a DW_AT_containing_type? - bool has_superclass = false; + + DWARFDIE superclass_die = FindSuperClassDIE(die); + NodePointer superclass_pointer = GetCanonicalDemangleTree(superclass_die); + return std::make_unique( - *kind, has_superclass, m_swift_typesystem, type.GetMangledTypeName(), + *kind, superclass_pointer, m_swift_typesystem, type.GetMangledTypeName(), *die.GetDIERef()); } diff --git a/lldb/source/Plugins/TypeSystem/Swift/TypeSystemSwiftTypeRef.cpp b/lldb/source/Plugins/TypeSystem/Swift/TypeSystemSwiftTypeRef.cpp index 5466c02c6ea95f..76462696545a62 100644 --- a/lldb/source/Plugins/TypeSystem/Swift/TypeSystemSwiftTypeRef.cpp +++ b/lldb/source/Plugins/TypeSystem/Swift/TypeSystemSwiftTypeRef.cpp @@ -474,6 +474,17 @@ GetNominal(swift::Demangle::Demangler &dem, swift::Demangle::NodePointer node) { return {}; } +bool +TypeSystemSwiftTypeRef::IsBuiltinType(CompilerType type) { + assert(type.GetTypeSystem().isa_and_nonnull() && + "Unexpected type system!"); + Demangler dem; + auto *node = GetDemangledType(dem, type.GetMangledTypeName()); + if (!node) + return false; + return node->getKind() == Node::Kind::BuiltinTypeName; +} + /// Return a pair of module name and type name, given a mangled name. static llvm::Optional> GetNominal(llvm::StringRef mangled_name, swift::Demangle::Demangler &dem) { @@ -1830,7 +1841,8 @@ TypeSystemSwiftTypeRef::FindTypeInModule(opaque_compiler_type_t opaque_type) { ConstString module(module_type->first); ConstString type(module_type->second); llvm::SmallVector decl_context; - decl_context.push_back({CompilerContextKind::Module, module}); + if (!module.IsEmpty()) + decl_context.push_back({CompilerContextKind::Module, module}); decl_context.push_back({CompilerContextKind::AnyType, type}); TypeQuery query(decl_context, TypeQueryOptions::e_find_one | @@ -3329,6 +3341,12 @@ CompilerType TypeSystemSwiftTypeRef::GetChildCompilerTypeAtIndex( return impl(); #ifndef NDEBUG auto result = impl(); + if (ShouldSkipValidation(type)) + return result; + + if (!ModuleList::GetGlobalModuleListProperties().GetSwiftValidateTypeSystem()) + return result; + // FIXME: // No point comparing the results if the reflection data has more // information. There's a nasty chicken & egg problem buried here: @@ -3339,8 +3357,6 @@ CompilerType TypeSystemSwiftTypeRef::GetChildCompilerTypeAtIndex( runtime->GetNumChildren({weak_from_this(), type}, exe_scope) .value_or(0)) return result; - if (ShouldSkipValidation(type)) - return result; // When the child compiler type is an anonymous clang type, // GetChildCompilerTypeAtIndex will return the clang type directly. In this // case validation will fail as it can't correctly compare the mangled @@ -3359,9 +3375,6 @@ CompilerType TypeSystemSwiftTypeRef::GetChildCompilerTypeAtIndex( bool ast_child_is_deref_of_parent = false; uint64_t ast_language_flags = 0; auto defer = llvm::make_scope_exit([&] { - if (!ModuleList::GetGlobalModuleListProperties() - .GetSwiftValidateTypeSystem()) - return; // Ignore if SwiftASTContext got no result. if (ast_child_name.empty()) return; diff --git a/lldb/source/Plugins/TypeSystem/Swift/TypeSystemSwiftTypeRef.h b/lldb/source/Plugins/TypeSystem/Swift/TypeSystemSwiftTypeRef.h index f6a959c714bf0b..8e582ae7189e2a 100644 --- a/lldb/source/Plugins/TypeSystem/Swift/TypeSystemSwiftTypeRef.h +++ b/lldb/source/Plugins/TypeSystem/Swift/TypeSystemSwiftTypeRef.h @@ -318,6 +318,10 @@ class TypeSystemSwiftTypeRef : public TypeSystemSwift { llvm::Optional GetTupleElement(lldb::opaque_compiler_type_t type, size_t idx); + /// Returns true if the compiler type is a Builtin (belongs to the "Builtin + /// module"). + static bool IsBuiltinType(CompilerType type); + /// Creates a GenericTypeParamType with the desired depth and index. CompilerType CreateGenericTypeParamType(unsigned int depth, unsigned int index) override; diff --git a/lldb/test/API/lang/swift/embedded/frame_variable/TestSwiftEmbeddedFrameVariable.py b/lldb/test/API/lang/swift/embedded/frame_variable/TestSwiftEmbeddedFrameVariable.py index 550481beb0bf72..a8ff4f4a7a31d5 100644 --- a/lldb/test/API/lang/swift/embedded/frame_variable/TestSwiftEmbeddedFrameVariable.py +++ b/lldb/test/API/lang/swift/embedded/frame_variable/TestSwiftEmbeddedFrameVariable.py @@ -31,3 +31,8 @@ def test(self): ) # TODO: test enums when "rdar://119343683 (Embedded Swift trivial case enum fails to link)" is solved + + self.expect("frame variable sup", substrs=["Sup) sup = ", "supField = 42"]) + self.expect("frame variable sub", substrs=["Sub) sub = ", "Sup = {", "supField = 42", "subField = {", "a = (field = 4.2000000000000002", "b = 123456"]) + 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)"]) + diff --git a/lldb/test/API/lang/swift/embedded/frame_variable/main.swift b/lldb/test/API/lang/swift/embedded/frame_variable/main.swift index 0844742722f416..ce9e7cffc68e0a 100644 --- a/lldb/test/API/lang/swift/embedded/frame_variable/main.swift +++ b/lldb/test/API/lang/swift/embedded/frame_variable/main.swift @@ -26,6 +26,18 @@ struct B { // case nonPayloadTwo // } +class Sup { + var supField: Int8 = 42 +} + +class Sub: Sup { + var subField = B() +} + +class SubSub: Sub { + var subSubField = A() +} + let varB = B() let tuple = (A(), B()) // let trivial = TrivialEnum.theCase @@ -33,6 +45,10 @@ let tuple = (A(), B()) // let nonPayload2 = NonPayloadEnum.two // let singlePayload = SinglePayloadEnum.payload(B()) // let emptySinglePayload = SinglePayloadEnum.nonPayloadTwo +let sup = Sup() +let sub = Sub() +let subSub = SubSub() +let sup2: Sup = SubSub() // Dummy statement to set breakpoint print can't be used in embedded Swift for now. let dummy = A() // break here