Index: lldb/trunk/source/Plugins/SymbolFile/DWARF/DWARFASTParser.h =================================================================== --- lldb/trunk/source/Plugins/SymbolFile/DWARF/DWARFASTParser.h +++ lldb/trunk/source/Plugins/SymbolFile/DWARF/DWARFASTParser.h @@ -28,7 +28,6 @@ virtual lldb::TypeSP ParseTypeFromDWARF(const lldb_private::SymbolContext &sc, const DWARFDIE &die, - lldb_private::Log *log, bool *type_is_new_ptr) = 0; virtual lldb_private::Function * Index: lldb/trunk/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h =================================================================== --- lldb/trunk/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h +++ lldb/trunk/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h @@ -15,7 +15,10 @@ #include "llvm/ADT/SmallVector.h" #include "DWARFASTParser.h" +#include "DWARFDIE.h" #include "DWARFDefines.h" +#include "DWARFFormValue.h" +#include "LogChannelDWARF.h" #include "lldb/Core/ClangForward.h" #include "lldb/Core/PluginInterface.h" #include "lldb/Symbol/ClangASTContext.h" @@ -29,6 +32,8 @@ class DWARFDebugInfoEntry; class SymbolFileDWARF; +struct ParsedDWARFTypeAttributes; + class DWARFASTParserClang : public DWARFASTParser { public: DWARFASTParserClang(lldb_private::ClangASTContext &ast); @@ -37,7 +42,7 @@ // DWARFASTParser interface. lldb::TypeSP ParseTypeFromDWARF(const lldb_private::SymbolContext &sc, - const DWARFDIE &die, lldb_private::Log *log, + const DWARFDIE &die, bool *type_is_new_ptr) override; lldb_private::Function * @@ -122,6 +127,10 @@ bool is_signed, uint32_t enumerator_byte_size, const DWARFDIE &parent_die); + /// Parse a structure, class, or union type DIE. + lldb::TypeSP ParseStructureLikeDIE(const DWARFDIE &die, + ParsedDWARFTypeAttributes &attrs); + lldb_private::Type *GetTypeForDIE(const DWARFDIE &die); clang::Decl *GetClangDeclForDIE(const DWARFDIE &die); @@ -142,6 +151,14 @@ void LinkDeclToDIE(clang::Decl *decl, const DWARFDIE &die); + /// If \p type_sp is valid, calculate and set its symbol context scope, and + /// update the type list for its backing symbol file. + /// + /// Returns \p type_sp. + lldb::TypeSP + UpdateSymbolContextScopeForType(const lldb_private::SymbolContext &sc, + const DWARFDIE &die, lldb::TypeSP type_sp); + lldb::TypeSP ParseTypeFromDWO(const DWARFDIE &die, lldb_private::Log *log); // Return true if this type is a declaration to a type in an external @@ -149,4 +166,37 @@ lldb::ModuleSP GetModuleForType(const DWARFDIE &die); }; +/// Parsed form of all attributes that are relevant for type reconstruction. +/// Some attributes are relevant for all kinds of types (declaration), while +/// others are only meaningful to a specific type (is_virtual) +struct ParsedDWARFTypeAttributes { + explicit ParsedDWARFTypeAttributes(const DWARFDIE &die); + + lldb::AccessType accessibility = lldb::eAccessNone; + bool is_artificial = false; + bool is_complete_objc_class = false; + bool is_explicit = false; + bool is_forward_declaration = false; + bool is_inline = false; + bool is_scoped_enum = false; + bool is_vector = false; + bool is_virtual = false; + clang::StorageClass storage = clang::SC_None; + const char *mangled_name = nullptr; + lldb_private::ConstString name; + lldb_private::Declaration decl; + DWARFDIE object_pointer; + DWARFFormValue abstract_origin; + DWARFFormValue containing_type; + DWARFFormValue signature; + DWARFFormValue specification; + DWARFFormValue type; + lldb::LanguageType class_language = lldb::eLanguageTypeUnknown; + llvm::Optional byte_size; + size_t calling_convention = llvm::dwarf::DW_CC_normal; + uint32_t bit_stride = 0; + uint32_t byte_stride = 0; + uint32_t encoding = 0; +}; + #endif // SymbolFileDWARF_DWARFASTParserClang_h_ Index: lldb/trunk/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp =================================================================== --- lldb/trunk/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp +++ lldb/trunk/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp @@ -9,7 +9,6 @@ #include #include "DWARFASTParserClang.h" -#include "DWARFDIE.h" #include "DWARFDebugInfo.h" #include "DWARFDeclContext.h" #include "DWARFDefines.h" @@ -232,42 +231,7 @@ } } -namespace { -/// Parsed form of all attributes that are relevant for type reconstruction. -/// Some attributes are relevant for all kinds of types (declaration), while -/// others are only meaningful to a specific type (is_virtual) -struct ParsedTypeAttributes { - explicit ParsedTypeAttributes(const DWARFDIE &die); - - AccessType accessibility = eAccessNone; - bool is_artificial = false; - bool is_complete_objc_class = false; - bool is_explicit = false; - bool is_forward_declaration = false; - bool is_inline = false; - bool is_scoped_enum = false; - bool is_vector = false; - bool is_virtual = false; - clang::StorageClass storage = clang::SC_None; - const char *mangled_name = nullptr; - ConstString name; - Declaration decl; - DWARFDIE object_pointer; - DWARFFormValue abstract_origin; - DWARFFormValue containing_type; - DWARFFormValue signature; - DWARFFormValue specification; - DWARFFormValue type; - LanguageType class_language = eLanguageTypeUnknown; - llvm::Optional byte_size; - size_t calling_convention = llvm::dwarf::DW_CC_normal; - uint32_t bit_stride = 0; - uint32_t byte_stride = 0; - uint32_t encoding = 0; -}; -} // namespace - -ParsedTypeAttributes::ParsedTypeAttributes(const DWARFDIE &die) { +ParsedDWARFTypeAttributes::ParsedDWARFTypeAttributes(const DWARFDIE &die) { DWARFAttributes attributes; size_t num_attributes = die.GetAttributes(attributes); for (size_t i = 0; i < num_attributes; ++i) { @@ -394,13 +358,17 @@ } TypeSP DWARFASTParserClang::ParseTypeFromDWARF(const SymbolContext &sc, - const DWARFDIE &die, Log *log, + const DWARFDIE &die, bool *type_is_new_ptr) { if (type_is_new_ptr) *type_is_new_ptr = false; if (!die) return nullptr; + + Log *log(LogChannelDWARF::GetLogIfAny(DWARF_LOG_TYPE_COMPLETION | + DWARF_LOG_LOOKUPS)); + SymbolFileDWARF *dwarf = die.GetDWARF(); if (log) { DWARFDIE context_die; @@ -424,11 +392,11 @@ // Set a bit that lets us know that we are currently parsing this dwarf->GetDIEToType()[die.GetDIE()] = DIE_IS_BEING_PARSED; - ParsedTypeAttributes attrs(die); + ParsedDWARFTypeAttributes attrs(die); if (DWARFDIE signature_die = attrs.signature.Reference()) { if (TypeSP type_sp = - ParseTypeFromDWARF(sc, signature_die, log, type_is_new_ptr)) { + ParseTypeFromDWARF(sc, signature_die, type_is_new_ptr)) { dwarf->GetDIEToType()[die.GetDIE()] = type_sp.get(); if (clang::DeclContext *decl_ctx = GetCachedClangDeclContextForDIE(signature_die)) @@ -438,7 +406,6 @@ return nullptr; } - TypeList &type_list = dwarf->GetTypeList(); if (type_is_new_ptr) *type_is_new_ptr = true; @@ -566,7 +533,7 @@ bool function_type_is_new_pointer; TypeSP lldb_function_type_sp = ParseTypeFromDWARF( - sc, function_type, log, &function_type_is_new_pointer); + sc, function_type, &function_type_is_new_pointer); if (lldb_function_type_sp) { clang_type = m_ast.CreateBlockPointerType( @@ -664,372 +631,11 @@ case DW_TAG_structure_type: case DW_TAG_union_type: case DW_TAG_class_type: { - // UniqueDWARFASTType is large, so don't create a local variables on - // the stack, put it on the heap. This function is often called - // recursively and clang isn't good and sharing the stack space for - // variables in different blocks. - std::unique_ptr unique_ast_entry_up( - new UniqueDWARFASTType()); - - ConstString unique_typename(attrs.name); - Declaration unique_decl(attrs.decl); - - if (attrs.name) { - if (Language::LanguageIsCPlusPlus(cu_language)) { - // For C++, we rely solely upon the one definition rule that says - // only one thing can exist at a given decl context. We ignore the - // file and line that things are declared on. - std::string qualified_name; - if (die.GetQualifiedName(qualified_name)) - unique_typename = ConstString(qualified_name); - unique_decl.Clear(); - } - - if (dwarf->GetUniqueDWARFASTTypeMap().Find( - unique_typename, die, unique_decl, attrs.byte_size.getValueOr(-1), - *unique_ast_entry_up)) { - type_sp = unique_ast_entry_up->m_type_sp; - if (type_sp) { - dwarf->GetDIEToType()[die.GetDIE()] = type_sp.get(); - LinkDeclContextToDIE( - GetCachedClangDeclContextForDIE(unique_ast_entry_up->m_die), die); - return type_sp; - } - } - } - - DEBUG_PRINTF("0x%8.8" PRIx64 ": %s (\"%s\")\n", die.GetID(), - DW_TAG_value_to_name(tag), type_name_cstr); - - int tag_decl_kind = -1; - AccessType default_accessibility = eAccessNone; - if (tag == DW_TAG_structure_type) { - tag_decl_kind = clang::TTK_Struct; - default_accessibility = eAccessPublic; - } else if (tag == DW_TAG_union_type) { - tag_decl_kind = clang::TTK_Union; - default_accessibility = eAccessPublic; - } else if (tag == DW_TAG_class_type) { - tag_decl_kind = clang::TTK_Class; - default_accessibility = eAccessPrivate; - } - - if (attrs.byte_size && *attrs.byte_size == 0 && attrs.name && - !die.HasChildren() && cu_language == eLanguageTypeObjC) { - // Work around an issue with clang at the moment where forward - // declarations for objective C classes are emitted as: - // DW_TAG_structure_type [2] - // DW_AT_name( "ForwardObjcClass" ) - // DW_AT_byte_size( 0x00 ) - // DW_AT_decl_file( "..." ) - // DW_AT_decl_line( 1 ) - // - // Note that there is no DW_AT_declaration and there are no children, - // and the byte size is zero. - attrs.is_forward_declaration = true; - } - - if (attrs.class_language == eLanguageTypeObjC || - attrs.class_language == eLanguageTypeObjC_plus_plus) { - if (!attrs.is_complete_objc_class && - die.Supports_DW_AT_APPLE_objc_complete_type()) { - // We have a valid eSymbolTypeObjCClass class symbol whose name - // matches the current objective C class that we are trying to find - // and this DIE isn't the complete definition (we checked - // is_complete_objc_class above and know it is false), so the real - // definition is in here somewhere - type_sp = - dwarf->FindCompleteObjCDefinitionTypeForDIE(die, attrs.name, true); - - if (!type_sp) { - SymbolFileDWARFDebugMap *debug_map_symfile = - dwarf->GetDebugMapSymfile(); - if (debug_map_symfile) { - // We weren't able to find a full declaration in this DWARF, - // see if we have a declaration anywhere else... - type_sp = debug_map_symfile->FindCompleteObjCDefinitionTypeForDIE( - die, attrs.name, true); - } - } - - if (type_sp) { - if (log) { - dwarf->GetObjectFile()->GetModule()->LogMessage( - log, - "SymbolFileDWARF(%p) - 0x%8.8x: %s type \"%s\" is an " - "incomplete objc type, complete type is 0x%8.8" PRIx64, - static_cast(this), die.GetOffset(), - DW_TAG_value_to_name(tag), attrs.name.GetCString(), - type_sp->GetID()); - } - - // We found a real definition for this type elsewhere so lets use - // it and cache the fact that we found a complete type for this - // die - dwarf->GetDIEToType()[die.GetDIE()] = type_sp.get(); - return type_sp; - } - } - } - - if (attrs.is_forward_declaration) { - // We have a forward declaration to a type and we need to try and - // find a full declaration. We look in the current type index just in - // case we have a forward declaration followed by an actual - // declarations in the DWARF. If this fails, we need to look - // elsewhere... - if (log) { - dwarf->GetObjectFile()->GetModule()->LogMessage( - log, - "SymbolFileDWARF(%p) - 0x%8.8x: %s type \"%s\" is a " - "forward declaration, trying to find complete type", - static_cast(this), die.GetOffset(), - DW_TAG_value_to_name(tag), attrs.name.GetCString()); - } - - // See if the type comes from a DWO module and if so, track down that - // type. - type_sp = ParseTypeFromDWO(die, log); - if (type_sp) - return type_sp; - - DWARFDeclContext die_decl_ctx; - die.GetDWARFDeclContext(die_decl_ctx); - - // type_sp = FindDefinitionTypeForDIE (dwarf_cu, die, - // type_name_const_str); - type_sp = dwarf->FindDefinitionTypeForDWARFDeclContext(die_decl_ctx); - - if (!type_sp) { - SymbolFileDWARFDebugMap *debug_map_symfile = - dwarf->GetDebugMapSymfile(); - if (debug_map_symfile) { - // We weren't able to find a full declaration in this DWARF, see - // if we have a declaration anywhere else... - type_sp = debug_map_symfile->FindDefinitionTypeForDWARFDeclContext( - die_decl_ctx); - } - } - - if (type_sp) { - if (log) { - dwarf->GetObjectFile()->GetModule()->LogMessage( - log, - "SymbolFileDWARF(%p) - 0x%8.8x: %s type \"%s\" is a " - "forward declaration, complete type is 0x%8.8" PRIx64, - static_cast(this), die.GetOffset(), - DW_TAG_value_to_name(tag), attrs.name.GetCString(), - type_sp->GetID()); - } - - // We found a real definition for this type elsewhere so lets use - // it and cache the fact that we found a complete type for this die - dwarf->GetDIEToType()[die.GetDIE()] = type_sp.get(); - clang::DeclContext *defn_decl_ctx = - GetCachedClangDeclContextForDIE(dwarf->GetDIE(type_sp->GetID())); - if (defn_decl_ctx) - LinkDeclContextToDIE(defn_decl_ctx, die); - return type_sp; - } - } - assert(tag_decl_kind != -1); - bool clang_type_was_created = false; - clang_type.SetCompilerType( - &m_ast, dwarf->GetForwardDeclDieToClangType().lookup(die.GetDIE())); - if (!clang_type) { - clang::DeclContext *decl_ctx = - GetClangDeclContextContainingDIE(die, nullptr); - - // If your decl context is a record that was imported from another - // AST context (in the gmodules case), we need to make sure the type - // backing the Decl is complete before adding children to it. This is - // not an issue in the non-gmodules case because the debug info will - // always contain a full definition of parent types in that case. - CompleteExternalTagDeclType(GetClangASTImporter(), decl_ctx, die, - attrs.name.GetCString()); - - if (attrs.accessibility == eAccessNone && decl_ctx) { - // Check the decl context that contains this class/struct/union. If - // it is a class we must give it an accessibility. - const clang::Decl::Kind containing_decl_kind = decl_ctx->getDeclKind(); - if (DeclKindIsCXXClass(containing_decl_kind)) - attrs.accessibility = default_accessibility; - } - - ClangASTMetadata metadata; - metadata.SetUserID(die.GetID()); - metadata.SetIsDynamicCXXType(dwarf->ClassOrStructIsVirtual(die)); - - if (attrs.name.GetStringRef().contains('<')) { - ClangASTContext::TemplateParameterInfos template_param_infos; - if (ParseTemplateParameterInfos(die, template_param_infos)) { - clang::ClassTemplateDecl *class_template_decl = - m_ast.ParseClassTemplateDecl(decl_ctx, attrs.accessibility, - attrs.name.GetCString(), - tag_decl_kind, template_param_infos); - if (!class_template_decl) { - if (log) { - dwarf->GetObjectFile()->GetModule()->LogMessage( - log, - "SymbolFileDWARF(%p) - 0x%8.8x: %s type \"%s\" " - "clang::ClassTemplateDecl failed to return a decl.", - static_cast(this), die.GetOffset(), - DW_TAG_value_to_name(tag), attrs.name.GetCString()); - } - return TypeSP(); - } - - clang::ClassTemplateSpecializationDecl *class_specialization_decl = - m_ast.CreateClassTemplateSpecializationDecl( - decl_ctx, class_template_decl, tag_decl_kind, - template_param_infos); - clang_type = m_ast.CreateClassTemplateSpecializationType( - class_specialization_decl); - clang_type_was_created = true; - - m_ast.SetMetadata(class_template_decl, metadata); - m_ast.SetMetadata(class_specialization_decl, metadata); - } - } - - if (!clang_type_was_created) { - clang_type_was_created = true; - clang_type = m_ast.CreateRecordType( - decl_ctx, attrs.accessibility, attrs.name.GetCString(), - tag_decl_kind, attrs.class_language, &metadata); - } - } - - // Store a forward declaration to this class type in case any - // parameters in any class methods need it for the clang types for - // function prototypes. - LinkDeclContextToDIE(m_ast.GetDeclContextForType(clang_type), die); - type_sp = std::make_shared(die.GetID(), dwarf, attrs.name, - attrs.byte_size, nullptr, LLDB_INVALID_UID, - Type::eEncodingIsUID, &attrs.decl, clang_type, - Type::eResolveStateForward); - - type_sp->SetIsCompleteObjCClass(attrs.is_complete_objc_class); - - // Add our type to the unique type map so we don't end up creating many - // copies of the same type over and over in the ASTContext for our - // module - unique_ast_entry_up->m_type_sp = type_sp; - unique_ast_entry_up->m_die = die; - unique_ast_entry_up->m_declaration = unique_decl; - unique_ast_entry_up->m_byte_size = attrs.byte_size.getValueOr(0); - dwarf->GetUniqueDWARFASTTypeMap().Insert(unique_typename, - *unique_ast_entry_up); - - if (attrs.is_forward_declaration && die.HasChildren()) { - // Check to see if the DIE actually has a definition, some version of - // GCC will - // emit DIEs with DW_AT_declaration set to true, but yet still have - // subprogram, members, or inheritance, so we can't trust it - DWARFDIE child_die = die.GetFirstChild(); - while (child_die) { - switch (child_die.Tag()) { - case DW_TAG_inheritance: - case DW_TAG_subprogram: - case DW_TAG_member: - case DW_TAG_APPLE_property: - case DW_TAG_class_type: - case DW_TAG_structure_type: - case DW_TAG_enumeration_type: - case DW_TAG_typedef: - case DW_TAG_union_type: - child_die.Clear(); - attrs.is_forward_declaration = false; - break; - default: - child_die = child_die.GetSibling(); - break; - } - } - } - - if (!attrs.is_forward_declaration) { - // Always start the definition for a class type so that if the class - // has child classes or types that require the class to be created - // for use as their decl contexts the class will be ready to accept - // these child definitions. - if (!die.HasChildren()) { - // No children for this struct/union/class, lets finish it - if (ClangASTContext::StartTagDeclarationDefinition(clang_type)) { - ClangASTContext::CompleteTagDeclarationDefinition(clang_type); - } else { - dwarf->GetObjectFile()->GetModule()->ReportError( - "DWARF DIE at 0x%8.8x named \"%s\" was not able to start its " - "definition.\nPlease file a bug and attach the file at the " - "start of this error message", - die.GetOffset(), attrs.name.GetCString()); - } - - if (tag == DW_TAG_structure_type) // this only applies in C - { - clang::RecordDecl *record_decl = - ClangASTContext::GetAsRecordDecl(clang_type); - - if (record_decl) { - GetClangASTImporter().InsertRecordDecl( - record_decl, ClangASTImporter::LayoutInfo()); - } - } - } else if (clang_type_was_created) { - // Start the definition if the class is not objective C since the - // underlying decls respond to isCompleteDefinition(). Objective - // C decls don't respond to isCompleteDefinition() so we can't - // start the declaration definition right away. For C++ - // class/union/structs we want to start the definition in case the - // class is needed as the declaration context for a contained class - // or type without the need to complete that type.. - - if (attrs.class_language != eLanguageTypeObjC && - attrs.class_language != eLanguageTypeObjC_plus_plus) - ClangASTContext::StartTagDeclarationDefinition(clang_type); - - // Leave this as a forward declaration until we need to know the - // details of the type. lldb_private::Type will automatically call - // the SymbolFile virtual function - // "SymbolFileDWARF::CompleteType(Type *)" When the definition - // needs to be defined. - assert(!dwarf->GetForwardDeclClangTypeToDie().count( - ClangUtil::RemoveFastQualifiers(clang_type) - .GetOpaqueQualType()) && - "Type already in the forward declaration map!"); - // Can't assume m_ast.GetSymbolFile() is actually a - // SymbolFileDWARF, it can be a SymbolFileDWARFDebugMap for Apple - // binaries. - dwarf->GetForwardDeclDieToClangType()[die.GetDIE()] = - clang_type.GetOpaqueQualType(); - dwarf->GetForwardDeclClangTypeToDie() - [ClangUtil::RemoveFastQualifiers(clang_type).GetOpaqueQualType()] = - die.GetID(); - m_ast.SetHasExternalStorage(clang_type.GetOpaqueQualType(), true); - } - } - - // If we made a clang type, set the trivial abi if applicable: We only - // do this for pass by value - which implies the Trivial ABI. There - // isn't a way to assert that something that would normally be pass by - // value is pass by reference, so we ignore that attribute if set. - if (attrs.calling_convention == llvm::dwarf::DW_CC_pass_by_value) { - clang::CXXRecordDecl *record_decl = - m_ast.GetAsCXXRecordDecl(clang_type.GetOpaqueQualType()); - if (record_decl && record_decl->getDefinition()) { - record_decl->setHasTrivialSpecialMemberForCall(); - } - } - - if (attrs.calling_convention == llvm::dwarf::DW_CC_pass_by_reference) { - clang::CXXRecordDecl *record_decl = - m_ast.GetAsCXXRecordDecl(clang_type.GetOpaqueQualType()); - if (record_decl) - record_decl->setArgPassingRestrictions( - clang::RecordDecl::APK_CannotPassInRegs); - } - - } break; + assert((!type_sp && !clang_type) && + "Did not expect partially computed structure-like type"); + TypeSP struct_like_type_sp = ParseStructureLikeDIE(die, attrs); + return UpdateSymbolContextScopeForType(sc, die, struct_like_type_sp); + } case DW_TAG_enumeration_type: { if (attrs.is_forward_declaration) { @@ -1656,31 +1262,418 @@ break; } - if (type_sp.get()) { - DWARFDIE sc_parent_die = SymbolFileDWARF::GetParentSymbolContextDIE(die); - dw_tag_t sc_parent_tag = sc_parent_die.Tag(); - - SymbolContextScope *symbol_context_scope = NULL; - if (sc_parent_tag == DW_TAG_compile_unit || - sc_parent_tag == DW_TAG_partial_unit) { - symbol_context_scope = sc.comp_unit; - } else if (sc.function != NULL && sc_parent_die) { - symbol_context_scope = - sc.function->GetBlock(true).FindBlockByID(sc_parent_die.GetID()); - if (symbol_context_scope == NULL) - symbol_context_scope = sc.function; - } else - symbol_context_scope = sc.module_sp.get(); - - if (symbol_context_scope != NULL) { - type_sp->SetSymbolContextScope(symbol_context_scope); - } - - // We are ready to put this type into the uniqued list up at the module - // level - type_list.Insert(type_sp); + // TODO: We should consider making the switch above exhaustive to simplify + // control flow in ParseTypeFromDWARF. Then, we could simply replace this + // return statement with a call to llvm_unreachable. + return UpdateSymbolContextScopeForType(sc, die, type_sp); +} - dwarf->GetDIEToType()[die.GetDIE()] = type_sp.get(); +TypeSP DWARFASTParserClang::UpdateSymbolContextScopeForType( + const SymbolContext &sc, const DWARFDIE &die, TypeSP type_sp) { + if (!type_sp) + return type_sp; + + SymbolFileDWARF *dwarf = die.GetDWARF(); + TypeList &type_list = dwarf->GetTypeList(); + DWARFDIE sc_parent_die = SymbolFileDWARF::GetParentSymbolContextDIE(die); + dw_tag_t sc_parent_tag = sc_parent_die.Tag(); + + SymbolContextScope *symbol_context_scope = NULL; + if (sc_parent_tag == DW_TAG_compile_unit || + sc_parent_tag == DW_TAG_partial_unit) { + symbol_context_scope = sc.comp_unit; + } else if (sc.function != NULL && sc_parent_die) { + symbol_context_scope = + sc.function->GetBlock(true).FindBlockByID(sc_parent_die.GetID()); + if (symbol_context_scope == NULL) + symbol_context_scope = sc.function; + } else { + symbol_context_scope = sc.module_sp.get(); + } + + if (symbol_context_scope != NULL) + type_sp->SetSymbolContextScope(symbol_context_scope); + + // We are ready to put this type into the uniqued list up at the module + // level. + type_list.Insert(type_sp); + + dwarf->GetDIEToType()[die.GetDIE()] = type_sp.get(); + return type_sp; +} + +TypeSP +DWARFASTParserClang::ParseStructureLikeDIE(const DWARFDIE &die, + ParsedDWARFTypeAttributes &attrs) { + TypeSP type_sp; + CompilerType clang_type; + const dw_tag_t tag = die.Tag(); + SymbolFileDWARF *dwarf = die.GetDWARF(); + LanguageType cu_language = die.GetLanguage(); + Log *log = LogChannelDWARF::GetLogIfAll(DWARF_LOG_TYPE_COMPLETION | + DWARF_LOG_LOOKUPS); + + // UniqueDWARFASTType is large, so don't create a local variables on the + // stack, put it on the heap. This function is often called recursively and + // clang isn't good at sharing the stack space for variables in different + // blocks. + auto unique_ast_entry_up = std::make_unique(); + + ConstString unique_typename(attrs.name); + Declaration unique_decl(attrs.decl); + + if (attrs.name) { + if (Language::LanguageIsCPlusPlus(cu_language)) { + // For C++, we rely solely upon the one definition rule that says + // only one thing can exist at a given decl context. We ignore the + // file and line that things are declared on. + std::string qualified_name; + if (die.GetQualifiedName(qualified_name)) + unique_typename = ConstString(qualified_name); + unique_decl.Clear(); + } + + if (dwarf->GetUniqueDWARFASTTypeMap().Find( + unique_typename, die, unique_decl, attrs.byte_size.getValueOr(-1), + *unique_ast_entry_up)) { + type_sp = unique_ast_entry_up->m_type_sp; + if (type_sp) { + dwarf->GetDIEToType()[die.GetDIE()] = type_sp.get(); + LinkDeclContextToDIE( + GetCachedClangDeclContextForDIE(unique_ast_entry_up->m_die), die); + return type_sp; + } + } + } + + DEBUG_PRINTF("0x%8.8" PRIx64 ": %s (\"%s\")\n", die.GetID(), + DW_TAG_value_to_name(tag), type_name_cstr); + + int tag_decl_kind = -1; + AccessType default_accessibility = eAccessNone; + if (tag == DW_TAG_structure_type) { + tag_decl_kind = clang::TTK_Struct; + default_accessibility = eAccessPublic; + } else if (tag == DW_TAG_union_type) { + tag_decl_kind = clang::TTK_Union; + default_accessibility = eAccessPublic; + } else if (tag == DW_TAG_class_type) { + tag_decl_kind = clang::TTK_Class; + default_accessibility = eAccessPrivate; + } + + if (attrs.byte_size && *attrs.byte_size == 0 && attrs.name && + !die.HasChildren() && cu_language == eLanguageTypeObjC) { + // Work around an issue with clang at the moment where forward + // declarations for objective C classes are emitted as: + // DW_TAG_structure_type [2] + // DW_AT_name( "ForwardObjcClass" ) + // DW_AT_byte_size( 0x00 ) + // DW_AT_decl_file( "..." ) + // DW_AT_decl_line( 1 ) + // + // Note that there is no DW_AT_declaration and there are no children, + // and the byte size is zero. + attrs.is_forward_declaration = true; + } + + if (attrs.class_language == eLanguageTypeObjC || + attrs.class_language == eLanguageTypeObjC_plus_plus) { + if (!attrs.is_complete_objc_class && + die.Supports_DW_AT_APPLE_objc_complete_type()) { + // We have a valid eSymbolTypeObjCClass class symbol whose name + // matches the current objective C class that we are trying to find + // and this DIE isn't the complete definition (we checked + // is_complete_objc_class above and know it is false), so the real + // definition is in here somewhere + type_sp = + dwarf->FindCompleteObjCDefinitionTypeForDIE(die, attrs.name, true); + + if (!type_sp) { + SymbolFileDWARFDebugMap *debug_map_symfile = + dwarf->GetDebugMapSymfile(); + if (debug_map_symfile) { + // We weren't able to find a full declaration in this DWARF, + // see if we have a declaration anywhere else... + type_sp = debug_map_symfile->FindCompleteObjCDefinitionTypeForDIE( + die, attrs.name, true); + } + } + + if (type_sp) { + if (log) { + dwarf->GetObjectFile()->GetModule()->LogMessage( + log, + "SymbolFileDWARF(%p) - 0x%8.8x: %s type \"%s\" is an " + "incomplete objc type, complete type is 0x%8.8" PRIx64, + static_cast(this), die.GetOffset(), + DW_TAG_value_to_name(tag), attrs.name.GetCString(), + type_sp->GetID()); + } + + // We found a real definition for this type elsewhere so lets use + // it and cache the fact that we found a complete type for this + // die + dwarf->GetDIEToType()[die.GetDIE()] = type_sp.get(); + return type_sp; + } + } + } + + if (attrs.is_forward_declaration) { + // We have a forward declaration to a type and we need to try and + // find a full declaration. We look in the current type index just in + // case we have a forward declaration followed by an actual + // declarations in the DWARF. If this fails, we need to look + // elsewhere... + if (log) { + dwarf->GetObjectFile()->GetModule()->LogMessage( + log, + "SymbolFileDWARF(%p) - 0x%8.8x: %s type \"%s\" is a " + "forward declaration, trying to find complete type", + static_cast(this), die.GetOffset(), DW_TAG_value_to_name(tag), + attrs.name.GetCString()); + } + + // See if the type comes from a DWO module and if so, track down that + // type. + type_sp = ParseTypeFromDWO(die, log); + if (type_sp) + return type_sp; + + DWARFDeclContext die_decl_ctx; + die.GetDWARFDeclContext(die_decl_ctx); + + // type_sp = FindDefinitionTypeForDIE (dwarf_cu, die, + // type_name_const_str); + type_sp = dwarf->FindDefinitionTypeForDWARFDeclContext(die_decl_ctx); + + if (!type_sp) { + SymbolFileDWARFDebugMap *debug_map_symfile = dwarf->GetDebugMapSymfile(); + if (debug_map_symfile) { + // We weren't able to find a full declaration in this DWARF, see + // if we have a declaration anywhere else... + type_sp = debug_map_symfile->FindDefinitionTypeForDWARFDeclContext( + die_decl_ctx); + } + } + + if (type_sp) { + if (log) { + dwarf->GetObjectFile()->GetModule()->LogMessage( + log, + "SymbolFileDWARF(%p) - 0x%8.8x: %s type \"%s\" is a " + "forward declaration, complete type is 0x%8.8" PRIx64, + static_cast(this), die.GetOffset(), + DW_TAG_value_to_name(tag), attrs.name.GetCString(), + type_sp->GetID()); + } + + // We found a real definition for this type elsewhere so lets use + // it and cache the fact that we found a complete type for this die + dwarf->GetDIEToType()[die.GetDIE()] = type_sp.get(); + clang::DeclContext *defn_decl_ctx = + GetCachedClangDeclContextForDIE(dwarf->GetDIE(type_sp->GetID())); + if (defn_decl_ctx) + LinkDeclContextToDIE(defn_decl_ctx, die); + return type_sp; + } + } + assert(tag_decl_kind != -1); + bool clang_type_was_created = false; + clang_type.SetCompilerType( + &m_ast, dwarf->GetForwardDeclDieToClangType().lookup(die.GetDIE())); + if (!clang_type) { + clang::DeclContext *decl_ctx = + GetClangDeclContextContainingDIE(die, nullptr); + + // If your decl context is a record that was imported from another + // AST context (in the gmodules case), we need to make sure the type + // backing the Decl is complete before adding children to it. This is + // not an issue in the non-gmodules case because the debug info will + // always contain a full definition of parent types in that case. + CompleteExternalTagDeclType(GetClangASTImporter(), decl_ctx, die, + attrs.name.GetCString()); + + if (attrs.accessibility == eAccessNone && decl_ctx) { + // Check the decl context that contains this class/struct/union. If + // it is a class we must give it an accessibility. + const clang::Decl::Kind containing_decl_kind = decl_ctx->getDeclKind(); + if (DeclKindIsCXXClass(containing_decl_kind)) + attrs.accessibility = default_accessibility; + } + + ClangASTMetadata metadata; + metadata.SetUserID(die.GetID()); + metadata.SetIsDynamicCXXType(dwarf->ClassOrStructIsVirtual(die)); + + if (attrs.name.GetStringRef().contains('<')) { + ClangASTContext::TemplateParameterInfos template_param_infos; + if (ParseTemplateParameterInfos(die, template_param_infos)) { + clang::ClassTemplateDecl *class_template_decl = + m_ast.ParseClassTemplateDecl(decl_ctx, attrs.accessibility, + attrs.name.GetCString(), tag_decl_kind, + template_param_infos); + if (!class_template_decl) { + if (log) { + dwarf->GetObjectFile()->GetModule()->LogMessage( + log, + "SymbolFileDWARF(%p) - 0x%8.8x: %s type \"%s\" " + "clang::ClassTemplateDecl failed to return a decl.", + static_cast(this), die.GetOffset(), + DW_TAG_value_to_name(tag), attrs.name.GetCString()); + } + return TypeSP(); + } + + clang::ClassTemplateSpecializationDecl *class_specialization_decl = + m_ast.CreateClassTemplateSpecializationDecl( + decl_ctx, class_template_decl, tag_decl_kind, + template_param_infos); + clang_type = m_ast.CreateClassTemplateSpecializationType( + class_specialization_decl); + clang_type_was_created = true; + + m_ast.SetMetadata(class_template_decl, metadata); + m_ast.SetMetadata(class_specialization_decl, metadata); + } + } + + if (!clang_type_was_created) { + clang_type_was_created = true; + clang_type = m_ast.CreateRecordType( + decl_ctx, attrs.accessibility, attrs.name.GetCString(), tag_decl_kind, + attrs.class_language, &metadata); + } + } + + // Store a forward declaration to this class type in case any + // parameters in any class methods need it for the clang types for + // function prototypes. + LinkDeclContextToDIE(m_ast.GetDeclContextForType(clang_type), die); + type_sp = std::make_shared(die.GetID(), dwarf, attrs.name, + attrs.byte_size, nullptr, LLDB_INVALID_UID, + Type::eEncodingIsUID, &attrs.decl, + clang_type, Type::eResolveStateForward); + + type_sp->SetIsCompleteObjCClass(attrs.is_complete_objc_class); + + // Add our type to the unique type map so we don't end up creating many + // copies of the same type over and over in the ASTContext for our + // module + unique_ast_entry_up->m_type_sp = type_sp; + unique_ast_entry_up->m_die = die; + unique_ast_entry_up->m_declaration = unique_decl; + unique_ast_entry_up->m_byte_size = attrs.byte_size.getValueOr(0); + dwarf->GetUniqueDWARFASTTypeMap().Insert(unique_typename, + *unique_ast_entry_up); + + if (attrs.is_forward_declaration && die.HasChildren()) { + // Check to see if the DIE actually has a definition, some version of + // GCC will + // emit DIEs with DW_AT_declaration set to true, but yet still have + // subprogram, members, or inheritance, so we can't trust it + DWARFDIE child_die = die.GetFirstChild(); + while (child_die) { + switch (child_die.Tag()) { + case DW_TAG_inheritance: + case DW_TAG_subprogram: + case DW_TAG_member: + case DW_TAG_APPLE_property: + case DW_TAG_class_type: + case DW_TAG_structure_type: + case DW_TAG_enumeration_type: + case DW_TAG_typedef: + case DW_TAG_union_type: + child_die.Clear(); + attrs.is_forward_declaration = false; + break; + default: + child_die = child_die.GetSibling(); + break; + } + } + } + + if (!attrs.is_forward_declaration) { + // Always start the definition for a class type so that if the class + // has child classes or types that require the class to be created + // for use as their decl contexts the class will be ready to accept + // these child definitions. + if (!die.HasChildren()) { + // No children for this struct/union/class, lets finish it + if (ClangASTContext::StartTagDeclarationDefinition(clang_type)) { + ClangASTContext::CompleteTagDeclarationDefinition(clang_type); + } else { + dwarf->GetObjectFile()->GetModule()->ReportError( + "DWARF DIE at 0x%8.8x named \"%s\" was not able to start its " + "definition.\nPlease file a bug and attach the file at the " + "start of this error message", + die.GetOffset(), attrs.name.GetCString()); + } + + if (tag == DW_TAG_structure_type) // this only applies in C + { + clang::RecordDecl *record_decl = + ClangASTContext::GetAsRecordDecl(clang_type); + + if (record_decl) { + GetClangASTImporter().InsertRecordDecl( + record_decl, ClangASTImporter::LayoutInfo()); + } + } + } else if (clang_type_was_created) { + // Start the definition if the class is not objective C since the + // underlying decls respond to isCompleteDefinition(). Objective + // C decls don't respond to isCompleteDefinition() so we can't + // start the declaration definition right away. For C++ + // class/union/structs we want to start the definition in case the + // class is needed as the declaration context for a contained class + // or type without the need to complete that type.. + + if (attrs.class_language != eLanguageTypeObjC && + attrs.class_language != eLanguageTypeObjC_plus_plus) + ClangASTContext::StartTagDeclarationDefinition(clang_type); + + // Leave this as a forward declaration until we need to know the + // details of the type. lldb_private::Type will automatically call + // the SymbolFile virtual function + // "SymbolFileDWARF::CompleteType(Type *)" When the definition + // needs to be defined. + assert(!dwarf->GetForwardDeclClangTypeToDie().count( + ClangUtil::RemoveFastQualifiers(clang_type) + .GetOpaqueQualType()) && + "Type already in the forward declaration map!"); + // Can't assume m_ast.GetSymbolFile() is actually a + // SymbolFileDWARF, it can be a SymbolFileDWARFDebugMap for Apple + // binaries. + dwarf->GetForwardDeclDieToClangType()[die.GetDIE()] = + clang_type.GetOpaqueQualType(); + dwarf->GetForwardDeclClangTypeToDie() + [ClangUtil::RemoveFastQualifiers(clang_type).GetOpaqueQualType()] = + die.GetID(); + m_ast.SetHasExternalStorage(clang_type.GetOpaqueQualType(), true); + } + } + + // If we made a clang type, set the trivial abi if applicable: We only + // do this for pass by value - which implies the Trivial ABI. There + // isn't a way to assert that something that would normally be pass by + // value is pass by reference, so we ignore that attribute if set. + if (attrs.calling_convention == llvm::dwarf::DW_CC_pass_by_value) { + clang::CXXRecordDecl *record_decl = + m_ast.GetAsCXXRecordDecl(clang_type.GetOpaqueQualType()); + if (record_decl && record_decl->getDefinition()) { + record_decl->setHasTrivialSpecialMemberForCall(); + } + } + + if (attrs.calling_convention == llvm::dwarf::DW_CC_pass_by_reference) { + clang::CXXRecordDecl *record_decl = + m_ast.GetAsCXXRecordDecl(clang_type.GetOpaqueQualType()); + if (record_decl) + record_decl->setArgPassingRestrictions( + clang::RecordDecl::APK_CannotPassInRegs); } return type_sp; } Index: lldb/trunk/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp =================================================================== --- lldb/trunk/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp +++ lldb/trunk/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp @@ -3001,8 +3001,7 @@ if (!dwarf_ast) return {}; - Log *log = LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_INFO); - TypeSP type_sp = dwarf_ast->ParseTypeFromDWARF(sc, die, log, type_is_new_ptr); + TypeSP type_sp = dwarf_ast->ParseTypeFromDWARF(sc, die, type_is_new_ptr); if (type_sp) { GetTypeList().Insert(type_sp);