diff options
Diffstat (limited to 'lldb/source/Plugins/SymbolFile/DWARF')
26 files changed, 2246 insertions, 2229 deletions
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp index 636e6032b877..232063a6f339 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp @@ -22,7 +22,7 @@ #include "lldb/Core/Value.h" #include "lldb/Host/Host.h" #include "lldb/Symbol/ClangASTImporter.h" -#include "lldb/Symbol/ClangExternalASTSourceCommon.h" +#include "lldb/Symbol/ClangASTMetadata.h" #include "lldb/Symbol/ClangUtil.h" #include "lldb/Symbol/CompileUnit.h" #include "lldb/Symbol/Function.h" @@ -135,61 +135,111 @@ static bool IsClangModuleFwdDecl(const DWARFDIE &Die) { return false; } -TypeSP DWARFASTParserClang::ParseTypeFromDWO(const DWARFDIE &die, Log *log) { - ModuleSP dwo_module_sp = die.GetContainingDWOModule(); - if (!dwo_module_sp) +static DWARFDIE GetContainingClangModuleDIE(const DWARFDIE &die) { + if (die.IsValid()) { + DWARFDIE top_module_die; + // Now make sure this DIE is scoped in a DW_TAG_module tag and return true + // if so + for (DWARFDIE parent = die.GetParent(); parent.IsValid(); + parent = parent.GetParent()) { + const dw_tag_t tag = parent.Tag(); + if (tag == DW_TAG_module) + top_module_die = parent; + else if (tag == DW_TAG_compile_unit || tag == DW_TAG_partial_unit) + break; + } + + return top_module_die; + } + return DWARFDIE(); +} + +static lldb::ModuleSP GetContainingClangModule(const DWARFDIE &die) { + if (die.IsValid()) { + DWARFDIE clang_module_die = GetContainingClangModuleDIE(die); + + if (clang_module_die) { + const char *module_name = clang_module_die.GetName(); + if (module_name) + return die.GetDWARF()->GetExternalModule( + lldb_private::ConstString(module_name)); + } + } + return lldb::ModuleSP(); +} + +TypeSP DWARFASTParserClang::ParseTypeFromClangModule(const SymbolContext &sc, + const DWARFDIE &die, + Log *log) { + ModuleSP clang_module_sp = GetContainingClangModule(die); + if (!clang_module_sp) return TypeSP(); - // If this type comes from a Clang module, look in the DWARF section - // of the pcm file in the module cache. Clang generates DWO skeleton - // units as breadcrumbs to find them. + // If this type comes from a Clang module, recursively look in the + // DWARF section of the .pcm file in the module cache. Clang + // generates DWO skeleton units as breadcrumbs to find them. llvm::SmallVector<CompilerContext, 4> decl_context; die.GetDeclContext(decl_context); - TypeMap dwo_types; + TypeMap pcm_types; // The type in the Clang module must have the same language as the current CU. LanguageSet languages; languages.Insert(die.GetCU()->GetLanguageType()); - dwo_module_sp->GetSymbolFile()->FindTypes(decl_context, languages, dwo_types); - if (dwo_types.Empty()) { - if (!IsClangModuleFwdDecl(die)) - return TypeSP(); - + llvm::DenseSet<SymbolFile *> searched_symbol_files; + clang_module_sp->GetSymbolFile()->FindTypes(decl_context, languages, + searched_symbol_files, pcm_types); + if (pcm_types.Empty()) { // Since this type is defined in one of the Clang modules imported - // by this symbol file, search all of them. + // by this symbol file, search all of them. Instead of calling + // sym_file->FindTypes(), which would return this again, go straight + // to the imported modules. auto &sym_file = die.GetCU()->GetSymbolFileDWARF(); - for (const auto &name_module : sym_file.getExternalTypeModules()) { - if (!name_module.second) - continue; - name_module.second->GetSymbolFile()->FindTypes(decl_context, - languages, dwo_types); - if (dwo_types.GetSize()) - break; - } + + // Well-formed clang modules never form cycles; guard against corrupted + // ones by inserting the current file. + searched_symbol_files.insert(&sym_file); + sym_file.ForEachExternalModule( + *sc.comp_unit, searched_symbol_files, [&](Module &module) { + module.GetSymbolFile()->FindTypes(decl_context, languages, + searched_symbol_files, pcm_types); + return pcm_types.GetSize(); + }); } - if (dwo_types.GetSize() != 1) + if (!pcm_types.GetSize()) return TypeSP(); // We found a real definition for this type in the Clang module, so lets use // it and cache the fact that we found a complete type for this die. - TypeSP dwo_type_sp = dwo_types.GetTypeAtIndex(0); - if (!dwo_type_sp) + TypeSP pcm_type_sp = pcm_types.GetTypeAtIndex(0); + if (!pcm_type_sp) return TypeSP(); - lldb_private::CompilerType dwo_type = dwo_type_sp->GetForwardCompilerType(); - + lldb_private::CompilerType pcm_type = pcm_type_sp->GetForwardCompilerType(); lldb_private::CompilerType type = - GetClangASTImporter().CopyType(m_ast, dwo_type); + GetClangASTImporter().CopyType(m_ast, pcm_type); if (!type) return TypeSP(); + // Under normal operation pcm_type is a shallow forward declaration + // that gets completed later. This is necessary to support cyclic + // data structures. If, however, pcm_type is already complete (for + // example, because it was loaded for a different target before), + // the definition needs to be imported right away, too. + // Type::ResolveClangType() effectively ignores the ResolveState + // inside type_sp and only looks at IsDefined(), so it never calls + // ClangASTImporter::ASTImporterDelegate::ImportDefinitionTo(), + // which does extra work for Objective-C classes. This would result + // in only the forward declaration to be visible. + if (pcm_type.IsDefined()) + GetClangASTImporter().RequireCompleteType(ClangUtil::GetQualType(type)); + SymbolFileDWARF *dwarf = die.GetDWARF(); TypeSP type_sp(new Type( - die.GetID(), dwarf, dwo_type_sp->GetName(), dwo_type_sp->GetByteSize(), + die.GetID(), dwarf, pcm_type_sp->GetName(), pcm_type_sp->GetByteSize(), nullptr, LLDB_INVALID_UID, Type::eEncodingInvalid, - &dwo_type_sp->GetDeclaration(), type, Type::eResolveStateForward)); + &pcm_type_sp->GetDeclaration(), type, Type::ResolveState::Forward)); dwarf->GetTypeList().Insert(type_sp); dwarf->GetDIEToType()[die.GetDIE()] = type_sp.get(); @@ -205,7 +255,8 @@ TypeSP DWARFASTParserClang::ParseTypeFromDWO(const DWARFDIE &die, Log *log) { return type_sp; } -static void CompleteExternalTagDeclType(ClangASTImporter &ast_importer, +static void CompleteExternalTagDeclType(ClangASTContext &ast, + ClangASTImporter &ast_importer, clang::DeclContext *decl_ctx, DWARFDIE die, const char *type_name_cstr) { @@ -214,7 +265,7 @@ static void CompleteExternalTagDeclType(ClangASTImporter &ast_importer, return; // If this type was not imported from an external AST, there's nothing to do. - CompilerType type = ClangASTContext::GetTypeForDecl(tag_decl_ctx); + CompilerType type = ast.GetTypeForDecl(tag_decl_ctx); if (!type || !ast_importer.CanImport(type)) return; @@ -340,6 +391,10 @@ ParsedDWARFTypeAttributes::ParsedDWARFTypeAttributes(const DWARFDIE &die) { is_complete_objc_class = form_value.Signed(); break; + case DW_AT_APPLE_objc_direct: + is_objc_direct_call = true; + break; + case DW_AT_APPLE_runtime_class: class_language = (LanguageType)form_value.Signed(); break; @@ -347,6 +402,9 @@ ParsedDWARFTypeAttributes::ParsedDWARFTypeAttributes(const DWARFDIE &die) { case DW_AT_GNU_vector: is_vector = form_value.Boolean(); break; + case DW_AT_export_symbols: + exports_symbols = form_value.Boolean(); + break; } } } @@ -377,13 +435,12 @@ TypeSP DWARFASTParserClang::ParseTypeFromDWARF(const SymbolContext &sc, dwarf->GetObjectFile()->GetModule()->LogMessage( log, - "SymbolFileDWARF::ParseType (die = 0x%8.8x, decl_ctx = %p (die " - "0x%8.8x)) %s name = '%s')", + "DWARFASTParserClang::ParseTypeFromDWARF " + "(die = 0x%8.8x, decl_ctx = %p (die 0x%8.8x)) %s name = '%s')", die.GetOffset(), static_cast<void *>(context), context_die.GetOffset(), die.GetTagAsCString(), die.GetName()); } - Type *type_ptr = dwarf->GetDIEToType().lookup(die.GetDIE()); if (type_ptr == DIE_IS_BEING_PARSED) return nullptr; @@ -411,13 +468,8 @@ TypeSP DWARFASTParserClang::ParseTypeFromDWARF(const SymbolContext &sc, const dw_tag_t tag = die.Tag(); - Type::ResolveState resolve_state = Type::eResolveStateUnresolved; - - Type::EncodingDataType encoding_data_type = Type::eEncodingIsUID; - CompilerType clang_type; - TypeSP type_sp; - LanguageType cu_language = die.GetLanguage(); + switch (tag) { case DW_TAG_typedef: case DW_TAG_base_type: @@ -427,848 +479,895 @@ TypeSP DWARFASTParserClang::ParseTypeFromDWARF(const SymbolContext &sc, case DW_TAG_const_type: case DW_TAG_restrict_type: case DW_TAG_volatile_type: + case DW_TAG_atomic_type: case DW_TAG_unspecified_type: { - if (tag == DW_TAG_typedef && attrs.type.IsValid()) { - // Try to parse a typedef from the DWO file first as modules can - // contain typedef'ed structures that have no names like: - // - // typedef struct { int a; } Foo; - // - // In this case we will have a structure with no name and a typedef - // named "Foo" that points to this unnamed structure. The name in the - // typedef is the only identifier for the struct, so always try to - // get typedefs from DWO files if possible. - // - // The type_sp returned will be empty if the typedef doesn't exist in - // a DWO file, so it is cheap to call this function just to check. - // - // If we don't do this we end up creating a TypeSP that says this is - // a typedef to type 0x123 (the DW_AT_type value would be 0x123 in - // the DW_TAG_typedef), and this is the unnamed structure type. We - // will have a hard time tracking down an unnammed structure type in - // the module DWO file, so we make sure we don't get into this - // situation by always resolving typedefs from the DWO file. - const DWARFDIE encoding_die = attrs.type.Reference(); - - // First make sure that the die that this is typedef'ed to _is_ just - // a declaration (DW_AT_declaration == 1), not a full definition - // since template types can't be represented in modules since only - // concrete instances of templates are ever emitted and modules won't - // contain those - if (encoding_die && - encoding_die.GetAttributeValueAsUnsigned(DW_AT_declaration, 0) == 1) { - type_sp = ParseTypeFromDWO(die, log); - if (type_sp) - return type_sp; - } - } + type_sp = ParseTypeModifier(sc, die, attrs); + break; + } - DEBUG_PRINTF("0x%8.8" PRIx64 ": %s (\"%s\") type => 0x%8.8lx\n", - die.GetID(), DW_TAG_value_to_name(tag), type_name_cstr, - encoding_uid.Reference()); + case DW_TAG_structure_type: + case DW_TAG_union_type: + case DW_TAG_class_type: { + type_sp = ParseStructureLikeDIE(sc, die, attrs); + break; + } - switch (tag) { - default: - break; + case DW_TAG_enumeration_type: { + type_sp = ParseEnum(sc, die, attrs); + break; + } - case DW_TAG_unspecified_type: - if (attrs.name == "nullptr_t" || attrs.name == "decltype(nullptr)") { - resolve_state = Type::eResolveStateFull; - clang_type = m_ast.GetBasicType(eBasicTypeNullPtr); - break; - } - // Fall through to base type below in case we can handle the type - // there... - LLVM_FALLTHROUGH; - - case DW_TAG_base_type: - resolve_state = Type::eResolveStateFull; - clang_type = m_ast.GetBuiltinTypeForDWARFEncodingAndBitSize( - attrs.name.GetCString(), attrs.encoding, - attrs.byte_size.getValueOr(0) * 8); - break; + case DW_TAG_inlined_subroutine: + case DW_TAG_subprogram: + case DW_TAG_subroutine_type: { + type_sp = ParseSubroutine(die, attrs); + break; + } + case DW_TAG_array_type: { + type_sp = ParseArrayType(die, attrs); + break; + } + case DW_TAG_ptr_to_member_type: { + type_sp = ParsePointerToMemberType(die, attrs); + break; + } + default: + dwarf->GetObjectFile()->GetModule()->ReportError( + "{0x%8.8x}: unhandled type tag 0x%4.4x (%s), please file a bug and " + "attach the file at the start of this error message", + die.GetOffset(), tag, DW_TAG_value_to_name(tag)); + break; + } - case DW_TAG_pointer_type: - encoding_data_type = Type::eEncodingIsPointerUID; - break; - case DW_TAG_reference_type: - encoding_data_type = Type::eEncodingIsLValueReferenceUID; - break; - case DW_TAG_rvalue_reference_type: - encoding_data_type = Type::eEncodingIsRValueReferenceUID; - break; - case DW_TAG_typedef: - encoding_data_type = Type::eEncodingIsTypedefUID; - break; - case DW_TAG_const_type: - encoding_data_type = Type::eEncodingIsConstUID; - break; - case DW_TAG_restrict_type: - encoding_data_type = Type::eEncodingIsRestrictUID; - break; - case DW_TAG_volatile_type: - encoding_data_type = Type::eEncodingIsVolatileUID; + // 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); +} + +lldb::TypeSP +DWARFASTParserClang::ParseTypeModifier(const SymbolContext &sc, + const DWARFDIE &die, + ParsedDWARFTypeAttributes &attrs) { + Log *log(LogChannelDWARF::GetLogIfAny(DWARF_LOG_TYPE_COMPLETION | + DWARF_LOG_LOOKUPS)); + SymbolFileDWARF *dwarf = die.GetDWARF(); + const dw_tag_t tag = die.Tag(); + LanguageType cu_language = die.GetLanguage(); + Type::ResolveState resolve_state = Type::ResolveState::Unresolved; + Type::EncodingDataType encoding_data_type = Type::eEncodingIsUID; + TypeSP type_sp; + CompilerType clang_type; + + if (tag == DW_TAG_typedef && attrs.type.IsValid()) { + // Try to parse a typedef from the (DWARF embedded in the) Clang + // module file first as modules can contain typedef'ed + // structures that have no names like: + // + // typedef struct { int a; } Foo; + // + // In this case we will have a structure with no name and a + // typedef named "Foo" that points to this unnamed + // structure. The name in the typedef is the only identifier for + // the struct, so always try to get typedefs from Clang modules + // if possible. + // + // The type_sp returned will be empty if the typedef doesn't + // exist in a module file, so it is cheap to call this function + // just to check. + // + // If we don't do this we end up creating a TypeSP that says + // this is a typedef to type 0x123 (the DW_AT_type value would + // be 0x123 in the DW_TAG_typedef), and this is the unnamed + // structure type. We will have a hard time tracking down an + // unnammed structure type in the module debug info, so we make + // sure we don't get into this situation by always resolving + // typedefs from the module. + const DWARFDIE encoding_die = attrs.type.Reference(); + + // First make sure that the die that this is typedef'ed to _is_ + // just a declaration (DW_AT_declaration == 1), not a full + // definition since template types can't be represented in + // modules since only concrete instances of templates are ever + // emitted and modules won't contain those + if (encoding_die && + encoding_die.GetAttributeValueAsUnsigned(DW_AT_declaration, 0) == 1) { + type_sp = ParseTypeFromClangModule(sc, die, log); + if (type_sp) + return type_sp; + } + } + + DEBUG_PRINTF("0x%8.8" PRIx64 ": %s (\"%s\") type => 0x%8.8lx\n", die.GetID(), + DW_TAG_value_to_name(tag), type_name_cstr, + encoding_uid.Reference()); + + switch (tag) { + default: + break; + + case DW_TAG_unspecified_type: + if (attrs.name == "nullptr_t" || attrs.name == "decltype(nullptr)") { + resolve_state = Type::ResolveState::Full; + clang_type = m_ast.GetBasicType(eBasicTypeNullPtr); break; } + // Fall through to base type below in case we can handle the type + // there... + LLVM_FALLTHROUGH; - if (!clang_type && (encoding_data_type == Type::eEncodingIsPointerUID || - encoding_data_type == Type::eEncodingIsTypedefUID)) { - if (tag == DW_TAG_pointer_type) { - DWARFDIE target_die = die.GetReferencedDIE(DW_AT_type); - - if (target_die.GetAttributeValueAsUnsigned(DW_AT_APPLE_block, 0)) { - // Blocks have a __FuncPtr inside them which is a pointer to a - // function of the proper type. - - for (DWARFDIE child_die = target_die.GetFirstChild(); - child_die.IsValid(); child_die = child_die.GetSibling()) { - if (!strcmp(child_die.GetAttributeValueAsString(DW_AT_name, ""), - "__FuncPtr")) { - DWARFDIE function_pointer_type = - child_die.GetReferencedDIE(DW_AT_type); - - if (function_pointer_type) { - DWARFDIE function_type = - function_pointer_type.GetReferencedDIE(DW_AT_type); - - bool function_type_is_new_pointer; - TypeSP lldb_function_type_sp = ParseTypeFromDWARF( - sc, function_type, &function_type_is_new_pointer); - - if (lldb_function_type_sp) { - clang_type = m_ast.CreateBlockPointerType( - lldb_function_type_sp->GetForwardCompilerType()); - encoding_data_type = Type::eEncodingIsUID; - attrs.type.Clear(); - resolve_state = Type::eResolveStateFull; - } - } + case DW_TAG_base_type: + resolve_state = Type::ResolveState::Full; + clang_type = m_ast.GetBuiltinTypeForDWARFEncodingAndBitSize( + attrs.name.GetStringRef(), attrs.encoding, + attrs.byte_size.getValueOr(0) * 8); + break; - break; + case DW_TAG_pointer_type: + encoding_data_type = Type::eEncodingIsPointerUID; + break; + case DW_TAG_reference_type: + encoding_data_type = Type::eEncodingIsLValueReferenceUID; + break; + case DW_TAG_rvalue_reference_type: + encoding_data_type = Type::eEncodingIsRValueReferenceUID; + break; + case DW_TAG_typedef: + encoding_data_type = Type::eEncodingIsTypedefUID; + break; + case DW_TAG_const_type: + encoding_data_type = Type::eEncodingIsConstUID; + break; + case DW_TAG_restrict_type: + encoding_data_type = Type::eEncodingIsRestrictUID; + break; + case DW_TAG_volatile_type: + encoding_data_type = Type::eEncodingIsVolatileUID; + break; + case DW_TAG_atomic_type: + encoding_data_type = Type::eEncodingIsAtomicUID; + break; + } + + if (!clang_type && (encoding_data_type == Type::eEncodingIsPointerUID || + encoding_data_type == Type::eEncodingIsTypedefUID)) { + if (tag == DW_TAG_pointer_type) { + DWARFDIE target_die = die.GetReferencedDIE(DW_AT_type); + + if (target_die.GetAttributeValueAsUnsigned(DW_AT_APPLE_block, 0)) { + // Blocks have a __FuncPtr inside them which is a pointer to a + // function of the proper type. + + for (DWARFDIE child_die = target_die.GetFirstChild(); + child_die.IsValid(); child_die = child_die.GetSibling()) { + if (!strcmp(child_die.GetAttributeValueAsString(DW_AT_name, ""), + "__FuncPtr")) { + DWARFDIE function_pointer_type = + child_die.GetReferencedDIE(DW_AT_type); + + if (function_pointer_type) { + DWARFDIE function_type = + function_pointer_type.GetReferencedDIE(DW_AT_type); + + bool function_type_is_new_pointer; + TypeSP lldb_function_type_sp = ParseTypeFromDWARF( + sc, function_type, &function_type_is_new_pointer); + + if (lldb_function_type_sp) { + clang_type = m_ast.CreateBlockPointerType( + lldb_function_type_sp->GetForwardCompilerType()); + encoding_data_type = Type::eEncodingIsUID; + attrs.type.Clear(); + resolve_state = Type::ResolveState::Full; + } } + + break; } } } + } - if (cu_language == eLanguageTypeObjC || - cu_language == eLanguageTypeObjC_plus_plus) { - if (attrs.name) { - static ConstString g_objc_type_name_id("id"); - static ConstString g_objc_type_name_Class("Class"); - static ConstString g_objc_type_name_selector("SEL"); + if (cu_language == eLanguageTypeObjC || + cu_language == eLanguageTypeObjC_plus_plus) { + if (attrs.name) { + if (attrs.name == "id") { + if (log) + dwarf->GetObjectFile()->GetModule()->LogMessage( + log, + "SymbolFileDWARF::ParseType (die = 0x%8.8x) %s '%s' " + "is Objective-C 'id' built-in type.", + die.GetOffset(), die.GetTagAsCString(), die.GetName()); + clang_type = m_ast.GetBasicType(eBasicTypeObjCID); + encoding_data_type = Type::eEncodingIsUID; + attrs.type.Clear(); + resolve_state = Type::ResolveState::Full; + } else if (attrs.name == "Class") { + if (log) + dwarf->GetObjectFile()->GetModule()->LogMessage( + log, + "SymbolFileDWARF::ParseType (die = 0x%8.8x) %s '%s' " + "is Objective-C 'Class' built-in type.", + die.GetOffset(), die.GetTagAsCString(), die.GetName()); + clang_type = m_ast.GetBasicType(eBasicTypeObjCClass); + encoding_data_type = Type::eEncodingIsUID; + attrs.type.Clear(); + resolve_state = Type::ResolveState::Full; + } else if (attrs.name == "SEL") { + if (log) + dwarf->GetObjectFile()->GetModule()->LogMessage( + log, + "SymbolFileDWARF::ParseType (die = 0x%8.8x) %s '%s' " + "is Objective-C 'selector' built-in type.", + die.GetOffset(), die.GetTagAsCString(), die.GetName()); + clang_type = m_ast.GetBasicType(eBasicTypeObjCSel); + encoding_data_type = Type::eEncodingIsUID; + attrs.type.Clear(); + resolve_state = Type::ResolveState::Full; + } + } else if (encoding_data_type == Type::eEncodingIsPointerUID && + attrs.type.IsValid()) { + // Clang sometimes erroneously emits id as objc_object*. In that + // case we fix up the type to "id". - if (attrs.name == g_objc_type_name_id) { - if (log) - dwarf->GetObjectFile()->GetModule()->LogMessage( - log, - "SymbolFileDWARF::ParseType (die = 0x%8.8x) %s '%s' " - "is Objective-C 'id' built-in type.", - die.GetOffset(), die.GetTagAsCString(), die.GetName()); - clang_type = m_ast.GetBasicType(eBasicTypeObjCID); - encoding_data_type = Type::eEncodingIsUID; - attrs.type.Clear(); - resolve_state = Type::eResolveStateFull; + const DWARFDIE encoding_die = attrs.type.Reference(); - } else if (attrs.name == g_objc_type_name_Class) { + if (encoding_die && encoding_die.Tag() == DW_TAG_structure_type) { + llvm::StringRef struct_name = encoding_die.GetName(); + if (struct_name == "objc_object") { if (log) dwarf->GetObjectFile()->GetModule()->LogMessage( log, - "SymbolFileDWARF::ParseType (die = 0x%8.8x) %s '%s' " - "is Objective-C 'Class' built-in type.", + "SymbolFileDWARF::ParseType (die = 0x%8.8x) %s " + "'%s' is 'objc_object*', which we overrode to " + "'id'.", die.GetOffset(), die.GetTagAsCString(), die.GetName()); - clang_type = m_ast.GetBasicType(eBasicTypeObjCClass); - encoding_data_type = Type::eEncodingIsUID; - attrs.type.Clear(); - resolve_state = Type::eResolveStateFull; - } else if (attrs.name == g_objc_type_name_selector) { - if (log) - dwarf->GetObjectFile()->GetModule()->LogMessage( - log, - "SymbolFileDWARF::ParseType (die = 0x%8.8x) %s '%s' " - "is Objective-C 'selector' built-in type.", - die.GetOffset(), die.GetTagAsCString(), die.GetName()); - clang_type = m_ast.GetBasicType(eBasicTypeObjCSel); + clang_type = m_ast.GetBasicType(eBasicTypeObjCID); encoding_data_type = Type::eEncodingIsUID; attrs.type.Clear(); - resolve_state = Type::eResolveStateFull; - } - } else if (encoding_data_type == Type::eEncodingIsPointerUID && - attrs.type.IsValid()) { - // Clang sometimes erroneously emits id as objc_object*. In that - // case we fix up the type to "id". - - const DWARFDIE encoding_die = attrs.type.Reference(); - - if (encoding_die && encoding_die.Tag() == DW_TAG_structure_type) { - if (const char *struct_name = encoding_die.GetName()) { - if (!strcmp(struct_name, "objc_object")) { - if (log) - dwarf->GetObjectFile()->GetModule()->LogMessage( - log, - "SymbolFileDWARF::ParseType (die = 0x%8.8x) %s " - "'%s' is 'objc_object*', which we overrode to " - "'id'.", - die.GetOffset(), die.GetTagAsCString(), die.GetName()); - clang_type = m_ast.GetBasicType(eBasicTypeObjCID); - encoding_data_type = Type::eEncodingIsUID; - attrs.type.Clear(); - resolve_state = Type::eResolveStateFull; - } - } + resolve_state = Type::ResolveState::Full; } } } } - - type_sp = std::make_shared<Type>( - die.GetID(), dwarf, attrs.name, attrs.byte_size, nullptr, - dwarf->GetUID(attrs.type.Reference()), encoding_data_type, &attrs.decl, - clang_type, resolve_state); - - dwarf->GetDIEToType()[die.GetDIE()] = type_sp.get(); - } break; - - case DW_TAG_structure_type: - case DW_TAG_union_type: - case DW_TAG_class_type: { - 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) { - type_sp = ParseTypeFromDWO(die, log); - if (type_sp) - return type_sp; + type_sp = std::make_shared<Type>( + die.GetID(), dwarf, attrs.name, attrs.byte_size, nullptr, + dwarf->GetUID(attrs.type.Reference()), encoding_data_type, &attrs.decl, + clang_type, resolve_state); - DWARFDeclContext die_decl_ctx; - die.GetDWARFDeclContext(die_decl_ctx); + dwarf->GetDIEToType()[die.GetDIE()] = type_sp.get(); + return type_sp; +} - type_sp = dwarf->FindDefinitionTypeForDWARFDeclContext(die_decl_ctx); +TypeSP DWARFASTParserClang::ParseEnum(const SymbolContext &sc, + const DWARFDIE &die, + ParsedDWARFTypeAttributes &attrs) { + Log *log(LogChannelDWARF::GetLogIfAny(DWARF_LOG_TYPE_COMPLETION | + DWARF_LOG_LOOKUPS)); + SymbolFileDWARF *dwarf = die.GetDWARF(); + const dw_tag_t tag = die.Tag(); + TypeSP type_sp; - 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 (attrs.is_forward_declaration) { + type_sp = ParseTypeFromClangModule(sc, die, log); + if (type_sp) + return type_sp; - 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<void *>(this), die.GetOffset(), - DW_TAG_value_to_name(tag), attrs.name.GetCString(), - type_sp->GetID()); - } + DWARFDeclContext die_decl_ctx; + die.GetDWARFDeclContext(die_decl_ctx); - // 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; + 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); } } - DEBUG_PRINTF("0x%8.8" PRIx64 ": %s (\"%s\")\n", die.GetID(), - DW_TAG_value_to_name(tag), type_name_cstr); - - CompilerType enumerator_clang_type; - clang_type.SetCompilerType( - &m_ast, dwarf->GetForwardDeclDieToClangType().lookup(die.GetDIE())); - if (!clang_type) { - if (attrs.type.IsValid()) { - Type *enumerator_type = - dwarf->ResolveTypeUID(attrs.type.Reference(), true); - if (enumerator_type) - enumerator_clang_type = enumerator_type->GetFullCompilerType(); - } - if (!enumerator_clang_type) { - if (attrs.byte_size) { - enumerator_clang_type = - m_ast.GetBuiltinTypeForDWARFEncodingAndBitSize( - NULL, DW_ATE_signed, *attrs.byte_size * 8); - } else { - enumerator_clang_type = m_ast.GetBasicType(eBasicTypeInt); - } + 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<void *>(this), die.GetOffset(), + DW_TAG_value_to_name(tag), attrs.name.GetCString(), + type_sp->GetID()); } - clang_type = m_ast.CreateEnumerationType( - attrs.name.GetCString(), - GetClangDeclContextContainingDIE(die, nullptr), attrs.decl, - enumerator_clang_type, attrs.is_scoped_enum); - } else { - enumerator_clang_type = - m_ast.GetEnumerationIntegerType(clang_type.GetOpaqueQualType()); + // 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; } + } + DEBUG_PRINTF("0x%8.8" PRIx64 ": %s (\"%s\")\n", die.GetID(), + DW_TAG_value_to_name(tag), type_name_cstr); - LinkDeclContextToDIE(ClangASTContext::GetDeclContextForType(clang_type), - die); - - type_sp = std::make_shared<Type>( - die.GetID(), dwarf, attrs.name, attrs.byte_size, nullptr, - dwarf->GetUID(attrs.type.Reference()), Type::eEncodingIsUID, - &attrs.decl, clang_type, Type::eResolveStateForward); + CompilerType enumerator_clang_type; + CompilerType clang_type; + clang_type.SetCompilerType( + &m_ast, dwarf->GetForwardDeclDieToClangType().lookup(die.GetDIE())); + if (!clang_type) { + if (attrs.type.IsValid()) { + Type *enumerator_type = + dwarf->ResolveTypeUID(attrs.type.Reference(), true); + if (enumerator_type) + enumerator_clang_type = enumerator_type->GetFullCompilerType(); + } - if (ClangASTContext::StartTagDeclarationDefinition(clang_type)) { - if (die.HasChildren()) { - bool is_signed = false; - enumerator_clang_type.IsIntegerType(is_signed); - ParseChildEnumerators(clang_type, is_signed, - type_sp->GetByteSize().getValueOr(0), die); + if (!enumerator_clang_type) { + if (attrs.byte_size) { + enumerator_clang_type = m_ast.GetBuiltinTypeForDWARFEncodingAndBitSize( + "", DW_ATE_signed, *attrs.byte_size * 8); + } else { + enumerator_clang_type = m_ast.GetBasicType(eBasicTypeInt); } - 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()); } - } break; - case DW_TAG_inlined_subroutine: - case DW_TAG_subprogram: - case DW_TAG_subroutine_type: { - bool is_variadic = false; - bool is_static = false; - bool has_template_params = false; + clang_type = m_ast.CreateEnumerationType( + attrs.name.GetCString(), GetClangDeclContextContainingDIE(die, nullptr), + attrs.decl, enumerator_clang_type, attrs.is_scoped_enum); + } else { + enumerator_clang_type = + m_ast.GetEnumerationIntegerType(clang_type.GetOpaqueQualType()); + } - unsigned type_quals = 0; + LinkDeclContextToDIE(ClangASTContext::GetDeclContextForType(clang_type), die); - std::string object_pointer_name; - if (attrs.object_pointer) { - const char *object_pointer_name_cstr = attrs.object_pointer.GetName(); - if (object_pointer_name_cstr) - object_pointer_name = object_pointer_name_cstr; - } + type_sp = std::make_shared<Type>( + die.GetID(), dwarf, attrs.name, attrs.byte_size, nullptr, + dwarf->GetUID(attrs.type.Reference()), Type::eEncodingIsUID, &attrs.decl, + clang_type, Type::ResolveState::Forward); - DEBUG_PRINTF("0x%8.8" PRIx64 ": %s (\"%s\")\n", die.GetID(), - DW_TAG_value_to_name(tag), type_name_cstr); + if (ClangASTContext::StartTagDeclarationDefinition(clang_type)) { + if (die.HasChildren()) { + bool is_signed = false; + enumerator_clang_type.IsIntegerType(is_signed); + ParseChildEnumerators(clang_type, is_signed, + type_sp->GetByteSize().getValueOr(0), die); + } + 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()); + } + return type_sp; +} - CompilerType return_clang_type; - Type *func_type = NULL; +TypeSP DWARFASTParserClang::ParseSubroutine(const DWARFDIE &die, + ParsedDWARFTypeAttributes &attrs) { + Log *log(LogChannelDWARF::GetLogIfAny(DWARF_LOG_TYPE_COMPLETION | + DWARF_LOG_LOOKUPS)); - if (attrs.type.IsValid()) - func_type = dwarf->ResolveTypeUID(attrs.type.Reference(), true); + SymbolFileDWARF *dwarf = die.GetDWARF(); + const dw_tag_t tag = die.Tag(); - if (func_type) - return_clang_type = func_type->GetForwardCompilerType(); - else - return_clang_type = m_ast.GetBasicType(eBasicTypeVoid); + bool is_variadic = false; + bool is_static = false; + bool has_template_params = false; - std::vector<CompilerType> function_param_types; - std::vector<clang::ParmVarDecl *> function_param_decls; + unsigned type_quals = 0; - // Parse the function children for the parameters + std::string object_pointer_name; + if (attrs.object_pointer) { + const char *object_pointer_name_cstr = attrs.object_pointer.GetName(); + if (object_pointer_name_cstr) + object_pointer_name = object_pointer_name_cstr; + } - DWARFDIE decl_ctx_die; - clang::DeclContext *containing_decl_ctx = - GetClangDeclContextContainingDIE(die, &decl_ctx_die); - const clang::Decl::Kind containing_decl_kind = - containing_decl_ctx->getDeclKind(); + DEBUG_PRINTF("0x%8.8" PRIx64 ": %s (\"%s\")\n", die.GetID(), + DW_TAG_value_to_name(tag), type_name_cstr); - bool is_cxx_method = DeclKindIsCXXClass(containing_decl_kind); - // Start off static. This will be set to false in - // ParseChildParameters(...) if we find a "this" parameters as the - // first parameter - if (is_cxx_method) { - is_static = true; - } + CompilerType return_clang_type; + Type *func_type = NULL; + + if (attrs.type.IsValid()) + func_type = dwarf->ResolveTypeUID(attrs.type.Reference(), true); + + if (func_type) + return_clang_type = func_type->GetForwardCompilerType(); + else + return_clang_type = m_ast.GetBasicType(eBasicTypeVoid); + + std::vector<CompilerType> function_param_types; + std::vector<clang::ParmVarDecl *> function_param_decls; + + // Parse the function children for the parameters + + DWARFDIE decl_ctx_die; + clang::DeclContext *containing_decl_ctx = + GetClangDeclContextContainingDIE(die, &decl_ctx_die); + const clang::Decl::Kind containing_decl_kind = + containing_decl_ctx->getDeclKind(); + + bool is_cxx_method = DeclKindIsCXXClass(containing_decl_kind); + // Start off static. This will be set to false in + // ParseChildParameters(...) if we find a "this" parameters as the + // first parameter + if (is_cxx_method) { + is_static = true; + } + + if (die.HasChildren()) { + bool skip_artificial = true; + ParseChildParameters(containing_decl_ctx, die, skip_artificial, is_static, + is_variadic, has_template_params, + function_param_types, function_param_decls, + type_quals); + } + + bool ignore_containing_context = false; + // Check for templatized class member functions. If we had any + // DW_TAG_template_type_parameter or DW_TAG_template_value_parameter + // the DW_TAG_subprogram DIE, then we can't let this become a method in + // a class. Why? Because templatized functions are only emitted if one + // of the templatized methods is used in the current compile unit and + // we will end up with classes that may or may not include these member + // functions and this means one class won't match another class + // definition and it affects our ability to use a class in the clang + // expression parser. So for the greater good, we currently must not + // allow any template member functions in a class definition. + if (is_cxx_method && has_template_params) { + ignore_containing_context = true; + is_cxx_method = false; + } + + // clang_type will get the function prototype clang type after this + // call + CompilerType clang_type = m_ast.CreateFunctionType( + return_clang_type, function_param_types.data(), + function_param_types.size(), is_variadic, type_quals); - if (die.HasChildren()) { - bool skip_artificial = true; - ParseChildParameters(containing_decl_ctx, die, skip_artificial, is_static, - is_variadic, has_template_params, - function_param_types, function_param_decls, - type_quals); - } - - bool ignore_containing_context = false; - // Check for templatized class member functions. If we had any - // DW_TAG_template_type_parameter or DW_TAG_template_value_parameter - // the DW_TAG_subprogram DIE, then we can't let this become a method in - // a class. Why? Because templatized functions are only emitted if one - // of the templatized methods is used in the current compile unit and - // we will end up with classes that may or may not include these member - // functions and this means one class won't match another class - // definition and it affects our ability to use a class in the clang - // expression parser. So for the greater good, we currently must not - // allow any template member functions in a class definition. - if (is_cxx_method && has_template_params) { - ignore_containing_context = true; - is_cxx_method = false; - } - - // clang_type will get the function prototype clang type after this - // call - clang_type = m_ast.CreateFunctionType( - return_clang_type, function_param_types.data(), - function_param_types.size(), is_variadic, type_quals); - - if (attrs.name) { - bool type_handled = false; - if (tag == DW_TAG_subprogram || tag == DW_TAG_inlined_subroutine) { - ObjCLanguage::MethodName objc_method(attrs.name.GetStringRef(), true); - if (objc_method.IsValid(true)) { - CompilerType class_opaque_type; - ConstString class_name(objc_method.GetClassName()); - if (class_name) { - TypeSP complete_objc_class_type_sp( - dwarf->FindCompleteObjCDefinitionTypeForDIE(DWARFDIE(), - class_name, false)); - - if (complete_objc_class_type_sp) { - CompilerType type_clang_forward_type = - complete_objc_class_type_sp->GetForwardCompilerType(); - if (ClangASTContext::IsObjCObjectOrInterfaceType( - type_clang_forward_type)) - class_opaque_type = type_clang_forward_type; - } + if (attrs.name) { + bool type_handled = false; + if (tag == DW_TAG_subprogram || tag == DW_TAG_inlined_subroutine) { + ObjCLanguage::MethodName objc_method(attrs.name.GetStringRef(), true); + if (objc_method.IsValid(true)) { + CompilerType class_opaque_type; + ConstString class_name(objc_method.GetClassName()); + if (class_name) { + TypeSP complete_objc_class_type_sp( + dwarf->FindCompleteObjCDefinitionTypeForDIE(DWARFDIE(), + class_name, false)); + + if (complete_objc_class_type_sp) { + CompilerType type_clang_forward_type = + complete_objc_class_type_sp->GetForwardCompilerType(); + if (ClangASTContext::IsObjCObjectOrInterfaceType( + type_clang_forward_type)) + class_opaque_type = type_clang_forward_type; } + } - if (class_opaque_type) { - // If accessibility isn't set to anything valid, assume public - // for now... - if (attrs.accessibility == eAccessNone) - attrs.accessibility = eAccessPublic; - - clang::ObjCMethodDecl *objc_method_decl = - m_ast.AddMethodToObjCObjectType( - class_opaque_type, attrs.name.GetCString(), clang_type, - attrs.accessibility, attrs.is_artificial, is_variadic); - type_handled = objc_method_decl != NULL; - if (type_handled) { - LinkDeclContextToDIE( - ClangASTContext::GetAsDeclContext(objc_method_decl), die); - m_ast.SetMetadataAsUserID(objc_method_decl, die.GetID()); - } else { - dwarf->GetObjectFile()->GetModule()->ReportError( - "{0x%8.8x}: invalid Objective-C method 0x%4.4x (%s), " - "please file a bug and attach the file at the start of " - "this error message", - die.GetOffset(), tag, DW_TAG_value_to_name(tag)); - } + if (class_opaque_type) { + // If accessibility isn't set to anything valid, assume public + // for now... + if (attrs.accessibility == eAccessNone) + attrs.accessibility = eAccessPublic; + + clang::ObjCMethodDecl *objc_method_decl = + m_ast.AddMethodToObjCObjectType( + class_opaque_type, attrs.name.GetCString(), clang_type, + attrs.accessibility, attrs.is_artificial, is_variadic, + attrs.is_objc_direct_call); + type_handled = objc_method_decl != NULL; + if (type_handled) { + LinkDeclContextToDIE(objc_method_decl, die); + m_ast.SetMetadataAsUserID(objc_method_decl, die.GetID()); + } else { + dwarf->GetObjectFile()->GetModule()->ReportError( + "{0x%8.8x}: invalid Objective-C method 0x%4.4x (%s), " + "please file a bug and attach the file at the start of " + "this error message", + die.GetOffset(), tag, DW_TAG_value_to_name(tag)); } - } else if (is_cxx_method) { - // Look at the parent of this DIE and see if is is a class or - // struct and see if this is actually a C++ method - Type *class_type = dwarf->ResolveType(decl_ctx_die); - if (class_type) { - bool alternate_defn = false; - if (class_type->GetID() != decl_ctx_die.GetID() || - decl_ctx_die.GetContainingDWOModuleDIE()) { - alternate_defn = true; - - // We uniqued the parent class of this function to another - // class so we now need to associate all dies under - // "decl_ctx_die" to DIEs in the DIE for "class_type"... - DWARFDIE class_type_die = dwarf->GetDIE(class_type->GetID()); - - if (class_type_die) { - std::vector<DWARFDIE> failures; - - CopyUniqueClassMethodTypes(decl_ctx_die, class_type_die, - class_type, failures); - - // FIXME do something with these failures that's smarter - // than - // just dropping them on the ground. Unfortunately classes - // don't like having stuff added to them after their - // definitions are complete... - - type_ptr = dwarf->GetDIEToType()[die.GetDIE()]; - if (type_ptr && type_ptr != DIE_IS_BEING_PARSED) { - type_sp = type_ptr->shared_from_this(); - break; - } + } + } else if (is_cxx_method) { + // Look at the parent of this DIE and see if is is a class or + // struct and see if this is actually a C++ method + Type *class_type = dwarf->ResolveType(decl_ctx_die); + if (class_type) { + bool alternate_defn = false; + if (class_type->GetID() != decl_ctx_die.GetID() || + IsClangModuleFwdDecl(decl_ctx_die)) { + alternate_defn = true; + + // We uniqued the parent class of this function to another + // class so we now need to associate all dies under + // "decl_ctx_die" to DIEs in the DIE for "class_type"... + DWARFDIE class_type_die = dwarf->GetDIE(class_type->GetID()); + + if (class_type_die) { + std::vector<DWARFDIE> failures; + + CopyUniqueClassMethodTypes(decl_ctx_die, class_type_die, + class_type, failures); + + // FIXME do something with these failures that's + // smarter than just dropping them on the ground. + // Unfortunately classes don't like having stuff added + // to them after their definitions are complete... + + Type *type_ptr = dwarf->GetDIEToType()[die.GetDIE()]; + if (type_ptr && type_ptr != DIE_IS_BEING_PARSED) { + return type_ptr->shared_from_this(); } } + } - if (attrs.specification.IsValid()) { - // We have a specification which we are going to base our - // function prototype off of, so we need this type to be - // completed so that the m_die_to_decl_ctx for the method in - // the specification has a valid clang decl context. - class_type->GetForwardCompilerType(); - // If we have a specification, then the function type should - // have been made with the specification and not with this - // die. - DWARFDIE spec_die = attrs.specification.Reference(); - clang::DeclContext *spec_clang_decl_ctx = - GetClangDeclContextForDIE(spec_die); - if (spec_clang_decl_ctx) { - LinkDeclContextToDIE(spec_clang_decl_ctx, die); - } else { - dwarf->GetObjectFile()->GetModule()->ReportWarning( - "0x%8.8" PRIx64 ": DW_AT_specification(0x%8.8x" - ") has no decl\n", - die.GetID(), spec_die.GetOffset()); - } - type_handled = true; - } else if (attrs.abstract_origin.IsValid()) { - // We have a specification which we are going to base our - // function prototype off of, so we need this type to be - // completed so that the m_die_to_decl_ctx for the method in - // the abstract origin has a valid clang decl context. - class_type->GetForwardCompilerType(); - - DWARFDIE abs_die = attrs.abstract_origin.Reference(); - clang::DeclContext *abs_clang_decl_ctx = - GetClangDeclContextForDIE(abs_die); - if (abs_clang_decl_ctx) { - LinkDeclContextToDIE(abs_clang_decl_ctx, die); - } else { - dwarf->GetObjectFile()->GetModule()->ReportWarning( - "0x%8.8" PRIx64 ": DW_AT_abstract_origin(0x%8.8x" - ") has no decl\n", - die.GetID(), abs_die.GetOffset()); - } - type_handled = true; + if (attrs.specification.IsValid()) { + // We have a specification which we are going to base our + // function prototype off of, so we need this type to be + // completed so that the m_die_to_decl_ctx for the method in + // the specification has a valid clang decl context. + class_type->GetForwardCompilerType(); + // If we have a specification, then the function type should + // have been made with the specification and not with this + // die. + DWARFDIE spec_die = attrs.specification.Reference(); + clang::DeclContext *spec_clang_decl_ctx = + GetClangDeclContextForDIE(spec_die); + if (spec_clang_decl_ctx) { + LinkDeclContextToDIE(spec_clang_decl_ctx, die); + } else { + dwarf->GetObjectFile()->GetModule()->ReportWarning( + "0x%8.8" PRIx64 ": DW_AT_specification(0x%8.8x" + ") has no decl\n", + die.GetID(), spec_die.GetOffset()); + } + type_handled = true; + } else if (attrs.abstract_origin.IsValid()) { + // We have a specification which we are going to base our + // function prototype off of, so we need this type to be + // completed so that the m_die_to_decl_ctx for the method in + // the abstract origin has a valid clang decl context. + class_type->GetForwardCompilerType(); + + DWARFDIE abs_die = attrs.abstract_origin.Reference(); + clang::DeclContext *abs_clang_decl_ctx = + GetClangDeclContextForDIE(abs_die); + if (abs_clang_decl_ctx) { + LinkDeclContextToDIE(abs_clang_decl_ctx, die); } else { - CompilerType class_opaque_type = - class_type->GetForwardCompilerType(); - if (ClangASTContext::IsCXXClassType(class_opaque_type)) { - if (class_opaque_type.IsBeingDefined() || alternate_defn) { - if (!is_static && !die.HasChildren()) { - // We have a C++ member function with no children (this - // pointer!) and clang will get mad if we try and make - // a function that isn't well formed in the DWARF, so - // we will just skip it... - type_handled = true; - } else { - bool add_method = true; - if (alternate_defn) { - // If an alternate definition for the class exists, - // then add the method only if an equivalent is not - // already present. - clang::CXXRecordDecl *record_decl = - m_ast.GetAsCXXRecordDecl( - class_opaque_type.GetOpaqueQualType()); - if (record_decl) { - for (auto method_iter = record_decl->method_begin(); - method_iter != record_decl->method_end(); - method_iter++) { - clang::CXXMethodDecl *method_decl = *method_iter; - if (method_decl->getNameInfo().getAsString() == - attrs.name.GetStringRef()) { - if (method_decl->getType() == - ClangUtil::GetQualType(clang_type)) { - add_method = false; - LinkDeclContextToDIE( - ClangASTContext::GetAsDeclContext( - method_decl), - die); - type_handled = true; - - break; - } + dwarf->GetObjectFile()->GetModule()->ReportWarning( + "0x%8.8" PRIx64 ": DW_AT_abstract_origin(0x%8.8x" + ") has no decl\n", + die.GetID(), abs_die.GetOffset()); + } + type_handled = true; + } else { + CompilerType class_opaque_type = + class_type->GetForwardCompilerType(); + if (ClangASTContext::IsCXXClassType(class_opaque_type)) { + if (class_opaque_type.IsBeingDefined() || alternate_defn) { + if (!is_static && !die.HasChildren()) { + // We have a C++ member function with no children (this + // pointer!) and clang will get mad if we try and make + // a function that isn't well formed in the DWARF, so + // we will just skip it... + type_handled = true; + } else { + bool add_method = true; + if (alternate_defn) { + // If an alternate definition for the class exists, + // then add the method only if an equivalent is not + // already present. + clang::CXXRecordDecl *record_decl = + m_ast.GetAsCXXRecordDecl( + class_opaque_type.GetOpaqueQualType()); + if (record_decl) { + for (auto method_iter = record_decl->method_begin(); + method_iter != record_decl->method_end(); + method_iter++) { + clang::CXXMethodDecl *method_decl = *method_iter; + if (method_decl->getNameInfo().getAsString() == + attrs.name.GetStringRef()) { + if (method_decl->getType() == + ClangUtil::GetQualType(clang_type)) { + add_method = false; + LinkDeclContextToDIE(method_decl, die); + type_handled = true; + + break; } } } } + } - if (add_method) { - llvm::PrettyStackTraceFormat stack_trace( - "SymbolFileDWARF::ParseType() is adding a method " - "%s to class %s in DIE 0x%8.8" PRIx64 " from %s", - attrs.name.GetCString(), - class_type->GetName().GetCString(), die.GetID(), - dwarf->GetObjectFile() - ->GetFileSpec() - .GetPath() - .c_str()); - - const bool is_attr_used = false; - // Neither GCC 4.2 nor clang++ currently set a valid - // accessibility in the DWARF for C++ methods... - // Default to public for now... - if (attrs.accessibility == eAccessNone) - attrs.accessibility = eAccessPublic; - - clang::CXXMethodDecl *cxx_method_decl = - m_ast.AddMethodToCXXRecordType( - class_opaque_type.GetOpaqueQualType(), - attrs.name.GetCString(), attrs.mangled_name, - clang_type, attrs.accessibility, attrs.is_virtual, - is_static, attrs.is_inline, attrs.is_explicit, - is_attr_used, attrs.is_artificial); - - type_handled = cxx_method_decl != NULL; - // Artificial methods are always handled even when we - // don't create a new declaration for them. - type_handled |= attrs.is_artificial; - - if (cxx_method_decl) { - LinkDeclContextToDIE( - ClangASTContext::GetAsDeclContext(cxx_method_decl), - die); - - ClangASTMetadata metadata; - metadata.SetUserID(die.GetID()); - - if (!object_pointer_name.empty()) { - metadata.SetObjectPtrName( - object_pointer_name.c_str()); - LLDB_LOGF(log, - "Setting object pointer name: %s on method " - "object %p.\n", - object_pointer_name.c_str(), - static_cast<void *>(cxx_method_decl)); - } - m_ast.SetMetadata(cxx_method_decl, metadata); - } else { - ignore_containing_context = true; + if (add_method) { + llvm::PrettyStackTraceFormat stack_trace( + "SymbolFileDWARF::ParseType() is adding a method " + "%s to class %s in DIE 0x%8.8" PRIx64 " from %s", + attrs.name.GetCString(), + class_type->GetName().GetCString(), die.GetID(), + dwarf->GetObjectFile() + ->GetFileSpec() + .GetPath() + .c_str()); + + const bool is_attr_used = false; + // Neither GCC 4.2 nor clang++ currently set a valid + // accessibility in the DWARF for C++ methods... + // Default to public for now... + if (attrs.accessibility == eAccessNone) + attrs.accessibility = eAccessPublic; + + clang::CXXMethodDecl *cxx_method_decl = + m_ast.AddMethodToCXXRecordType( + class_opaque_type.GetOpaqueQualType(), + attrs.name.GetCString(), attrs.mangled_name, + clang_type, attrs.accessibility, attrs.is_virtual, + is_static, attrs.is_inline, attrs.is_explicit, + is_attr_used, attrs.is_artificial); + + type_handled = cxx_method_decl != NULL; + // Artificial methods are always handled even when we + // don't create a new declaration for them. + type_handled |= attrs.is_artificial; + + if (cxx_method_decl) { + LinkDeclContextToDIE(cxx_method_decl, die); + + ClangASTMetadata metadata; + metadata.SetUserID(die.GetID()); + + if (!object_pointer_name.empty()) { + metadata.SetObjectPtrName( + object_pointer_name.c_str()); + LLDB_LOGF(log, + "Setting object pointer name: %s on method " + "object %p.\n", + object_pointer_name.c_str(), + static_cast<void *>(cxx_method_decl)); } + m_ast.SetMetadata(cxx_method_decl, metadata); + } else { + ignore_containing_context = true; } } - } else { - // We were asked to parse the type for a method in a - // class, yet the class hasn't been asked to complete - // itself through the clang::ExternalASTSource protocol, - // so we need to just have the class complete itself and - // do things the right way, then our - // DIE should then have an entry in the - // dwarf->GetDIEToType() map. First - // we need to modify the dwarf->GetDIEToType() so it - // doesn't think we are trying to parse this DIE - // anymore... - dwarf->GetDIEToType()[die.GetDIE()] = NULL; - - // Now we get the full type to force our class type to - // complete itself using the clang::ExternalASTSource - // protocol which will parse all base classes and all - // methods (including the method for this DIE). - class_type->GetFullCompilerType(); - - // The type for this DIE should have been filled in the - // function call above - type_ptr = dwarf->GetDIEToType()[die.GetDIE()]; - if (type_ptr && type_ptr != DIE_IS_BEING_PARSED) { - type_sp = type_ptr->shared_from_this(); - break; - } - - // FIXME This is fixing some even uglier behavior but we - // really need to - // uniq the methods of each class as well as the class - // itself. <rdar://problem/11240464> - type_handled = true; } + } else { + // We were asked to parse the type for a method in a + // class, yet the class hasn't been asked to complete + // itself through the clang::ExternalASTSource protocol, + // so we need to just have the class complete itself and + // do things the right way, then our + // DIE should then have an entry in the + // dwarf->GetDIEToType() map. First + // we need to modify the dwarf->GetDIEToType() so it + // doesn't think we are trying to parse this DIE + // anymore... + dwarf->GetDIEToType()[die.GetDIE()] = NULL; + + // Now we get the full type to force our class type to + // complete itself using the clang::ExternalASTSource + // protocol which will parse all base classes and all + // methods (including the method for this DIE). + class_type->GetFullCompilerType(); + + // The type for this DIE should have been filled in the + // function call above + Type *type_ptr = dwarf->GetDIEToType()[die.GetDIE()]; + if (type_ptr && type_ptr != DIE_IS_BEING_PARSED) { + return type_ptr->shared_from_this(); + } + + // FIXME This is fixing some even uglier behavior but we + // really need to + // uniq the methods of each class as well as the class + // itself. <rdar://problem/11240464> + type_handled = true; } } } } } + } - if (!type_handled) { - clang::FunctionDecl *function_decl = nullptr; - clang::FunctionDecl *template_function_decl = nullptr; + if (!type_handled) { + clang::FunctionDecl *function_decl = nullptr; + clang::FunctionDecl *template_function_decl = nullptr; - if (attrs.abstract_origin.IsValid()) { - DWARFDIE abs_die = attrs.abstract_origin.Reference(); + if (attrs.abstract_origin.IsValid()) { + DWARFDIE abs_die = attrs.abstract_origin.Reference(); - if (dwarf->ResolveType(abs_die)) { - function_decl = llvm::dyn_cast_or_null<clang::FunctionDecl>( - GetCachedClangDeclContextForDIE(abs_die)); + if (dwarf->ResolveType(abs_die)) { + function_decl = llvm::dyn_cast_or_null<clang::FunctionDecl>( + GetCachedClangDeclContextForDIE(abs_die)); - if (function_decl) { - LinkDeclContextToDIE(function_decl, die); - } + if (function_decl) { + LinkDeclContextToDIE(function_decl, die); } } + } - if (!function_decl) { - // We just have a function that isn't part of a class - function_decl = m_ast.CreateFunctionDeclaration( + if (!function_decl) { + // We just have a function that isn't part of a class + function_decl = m_ast.CreateFunctionDeclaration( + ignore_containing_context ? m_ast.GetTranslationUnitDecl() + : containing_decl_ctx, + attrs.name.GetCString(), clang_type, attrs.storage, + attrs.is_inline); + + if (has_template_params) { + ClangASTContext::TemplateParameterInfos template_param_infos; + ParseTemplateParameterInfos(die, template_param_infos); + template_function_decl = m_ast.CreateFunctionDeclaration( ignore_containing_context ? m_ast.GetTranslationUnitDecl() : containing_decl_ctx, attrs.name.GetCString(), clang_type, attrs.storage, attrs.is_inline); + clang::FunctionTemplateDecl *func_template_decl = + m_ast.CreateFunctionTemplateDecl( + containing_decl_ctx, template_function_decl, + attrs.name.GetCString(), template_param_infos); + m_ast.CreateFunctionTemplateSpecializationInfo( + function_decl, func_template_decl, template_param_infos); + } - if (has_template_params) { - ClangASTContext::TemplateParameterInfos template_param_infos; - ParseTemplateParameterInfos(die, template_param_infos); - template_function_decl = m_ast.CreateFunctionDeclaration( - ignore_containing_context ? m_ast.GetTranslationUnitDecl() - : containing_decl_ctx, - attrs.name.GetCString(), clang_type, attrs.storage, - attrs.is_inline); - clang::FunctionTemplateDecl *func_template_decl = - m_ast.CreateFunctionTemplateDecl( - containing_decl_ctx, template_function_decl, - attrs.name.GetCString(), template_param_infos); - m_ast.CreateFunctionTemplateSpecializationInfo( - function_decl, func_template_decl, template_param_infos); - } - - lldbassert(function_decl); + lldbassert(function_decl); - if (function_decl) { - LinkDeclContextToDIE(function_decl, die); + if (function_decl) { + LinkDeclContextToDIE(function_decl, die); - if (!function_param_decls.empty()) { - m_ast.SetFunctionParameters(function_decl, + if (!function_param_decls.empty()) { + m_ast.SetFunctionParameters(function_decl, + &function_param_decls.front(), + function_param_decls.size()); + if (template_function_decl) + m_ast.SetFunctionParameters(template_function_decl, &function_param_decls.front(), function_param_decls.size()); - if (template_function_decl) - m_ast.SetFunctionParameters(template_function_decl, - &function_param_decls.front(), - function_param_decls.size()); - } + } - ClangASTMetadata metadata; - metadata.SetUserID(die.GetID()); + ClangASTMetadata metadata; + metadata.SetUserID(die.GetID()); - if (!object_pointer_name.empty()) { - metadata.SetObjectPtrName(object_pointer_name.c_str()); - LLDB_LOGF(log, - "Setting object pointer name: %s on function " - "object %p.", - object_pointer_name.c_str(), - static_cast<void *>(function_decl)); - } - m_ast.SetMetadata(function_decl, metadata); + if (!object_pointer_name.empty()) { + metadata.SetObjectPtrName(object_pointer_name.c_str()); + LLDB_LOGF(log, + "Setting object pointer name: %s on function " + "object %p.", + object_pointer_name.c_str(), + static_cast<void *>(function_decl)); } + m_ast.SetMetadata(function_decl, metadata); } } } - type_sp = std::make_shared<Type>( - die.GetID(), dwarf, attrs.name, llvm::None, nullptr, LLDB_INVALID_UID, - Type::eEncodingIsUID, &attrs.decl, clang_type, Type::eResolveStateFull); - assert(type_sp.get()); - } break; + } + return std::make_shared<Type>( + die.GetID(), dwarf, attrs.name, llvm::None, nullptr, LLDB_INVALID_UID, + Type::eEncodingIsUID, &attrs.decl, clang_type, Type::ResolveState::Full); +} - case DW_TAG_array_type: { - DEBUG_PRINTF("0x%8.8" PRIx64 ": %s (\"%s\")\n", die.GetID(), - DW_TAG_value_to_name(tag), type_name_cstr); +TypeSP DWARFASTParserClang::ParseArrayType(const DWARFDIE &die, + ParsedDWARFTypeAttributes &attrs) { + SymbolFileDWARF *dwarf = die.GetDWARF(); - DWARFDIE type_die = attrs.type.Reference(); - Type *element_type = dwarf->ResolveTypeUID(type_die, true); + DEBUG_PRINTF("0x%8.8" PRIx64 ": %s (\"%s\")\n", die.GetID(), + DW_TAG_value_to_name(tag), type_name_cstr); - if (element_type) { - auto array_info = ParseChildArrayInfo(die); - if (array_info) { - attrs.byte_stride = array_info->byte_stride; - attrs.bit_stride = array_info->bit_stride; - } - if (attrs.byte_stride == 0 && attrs.bit_stride == 0) - attrs.byte_stride = element_type->GetByteSize().getValueOr(0); - CompilerType array_element_type = element_type->GetForwardCompilerType(); - - if (ClangASTContext::IsCXXClassType(array_element_type) && - !array_element_type.GetCompleteType()) { - ModuleSP module_sp = die.GetModule(); - if (module_sp) { - if (die.GetCU()->GetProducer() == eProducerClang) - module_sp->ReportError( - "DWARF DW_TAG_array_type DIE at 0x%8.8x has a " - "class/union/struct element type DIE 0x%8.8x that is a " - "forward declaration, not a complete definition.\nTry " - "compiling the source file with -fstandalone-debug or " - "disable -gmodules", - die.GetOffset(), type_die.GetOffset()); - else - module_sp->ReportError( - "DWARF DW_TAG_array_type DIE at 0x%8.8x has a " - "class/union/struct element type DIE 0x%8.8x that is a " - "forward declaration, not a complete definition.\nPlease " - "file a bug against the compiler and include the " - "preprocessed output for %s", - die.GetOffset(), type_die.GetOffset(), - GetUnitName(die).c_str()); - } + DWARFDIE type_die = attrs.type.Reference(); + Type *element_type = dwarf->ResolveTypeUID(type_die, true); - // We have no choice other than to pretend that the element class - // type is complete. If we don't do this, clang will crash when - // trying to layout the class. Since we provide layout - // assistance, all ivars in this class and other classes will be - // fine, this is the best we can do short of crashing. - if (ClangASTContext::StartTagDeclarationDefinition( - array_element_type)) { - ClangASTContext::CompleteTagDeclarationDefinition(array_element_type); - } else { - module_sp->ReportError("DWARF DIE at 0x%8.8x was not able to " - "start its definition.\nPlease file a " - "bug and attach the file at the start " - "of this error message", - type_die.GetOffset()); - } - } + if (!element_type) + return nullptr; - uint64_t array_element_bit_stride = - attrs.byte_stride * 8 + attrs.bit_stride; - if (array_info && array_info->element_orders.size() > 0) { - uint64_t num_elements = 0; - auto end = array_info->element_orders.rend(); - for (auto pos = array_info->element_orders.rbegin(); pos != end; - ++pos) { - num_elements = *pos; - clang_type = m_ast.CreateArrayType(array_element_type, num_elements, - attrs.is_vector); - array_element_type = clang_type; - array_element_bit_stride = - num_elements ? array_element_bit_stride * num_elements - : array_element_bit_stride; - } - } else { - clang_type = m_ast.CreateArrayType(array_element_type, 0, attrs.is_vector); - } - ConstString empty_name; - type_sp = std::make_shared<Type>( - die.GetID(), dwarf, empty_name, array_element_bit_stride / 8, nullptr, - dwarf->GetUID(type_die), Type::eEncodingIsUID, &attrs.decl, - clang_type, Type::eResolveStateFull); - type_sp->SetEncodingType(element_type); - m_ast.SetMetadataAsUserID(clang_type.GetOpaqueQualType(), die.GetID()); + llvm::Optional<SymbolFile::ArrayInfo> array_info = ParseChildArrayInfo(die); + if (array_info) { + attrs.byte_stride = array_info->byte_stride; + attrs.bit_stride = array_info->bit_stride; + } + if (attrs.byte_stride == 0 && attrs.bit_stride == 0) + attrs.byte_stride = element_type->GetByteSize().getValueOr(0); + CompilerType array_element_type = element_type->GetForwardCompilerType(); + + if (ClangASTContext::IsCXXClassType(array_element_type) && + !array_element_type.GetCompleteType()) { + ModuleSP module_sp = die.GetModule(); + if (module_sp) { + if (die.GetCU()->GetProducer() == eProducerClang) + module_sp->ReportError( + "DWARF DW_TAG_array_type DIE at 0x%8.8x has a " + "class/union/struct element type DIE 0x%8.8x that is a " + "forward declaration, not a complete definition.\nTry " + "compiling the source file with -fstandalone-debug or " + "disable -gmodules", + die.GetOffset(), type_die.GetOffset()); + else + module_sp->ReportError( + "DWARF DW_TAG_array_type DIE at 0x%8.8x has a " + "class/union/struct element type DIE 0x%8.8x that is a " + "forward declaration, not a complete definition.\nPlease " + "file a bug against the compiler and include the " + "preprocessed output for %s", + die.GetOffset(), type_die.GetOffset(), GetUnitName(die).c_str()); + } + + // We have no choice other than to pretend that the element class + // type is complete. If we don't do this, clang will crash when + // trying to layout the class. Since we provide layout + // assistance, all ivars in this class and other classes will be + // fine, this is the best we can do short of crashing. + if (ClangASTContext::StartTagDeclarationDefinition(array_element_type)) { + ClangASTContext::CompleteTagDeclarationDefinition(array_element_type); + } else { + module_sp->ReportError("DWARF DIE at 0x%8.8x was not able to " + "start its definition.\nPlease file a " + "bug and attach the file at the start " + "of this error message", + type_die.GetOffset()); } - } break; + } - case DW_TAG_ptr_to_member_type: { - Type *pointee_type = dwarf->ResolveTypeUID(attrs.type.Reference(), true); - Type *class_type = - dwarf->ResolveTypeUID(attrs.containing_type.Reference(), true); + uint64_t array_element_bit_stride = + attrs.byte_stride * 8 + attrs.bit_stride; + CompilerType clang_type; + if (array_info && array_info->element_orders.size() > 0) { + uint64_t num_elements = 0; + auto end = array_info->element_orders.rend(); + for (auto pos = array_info->element_orders.rbegin(); pos != end; ++pos) { + num_elements = *pos; + clang_type = m_ast.CreateArrayType(array_element_type, num_elements, + attrs.is_vector); + array_element_type = clang_type; + array_element_bit_stride = num_elements + ? array_element_bit_stride * num_elements + : array_element_bit_stride; + } + } else { + clang_type = + m_ast.CreateArrayType(array_element_type, 0, attrs.is_vector); + } + ConstString empty_name; + TypeSP type_sp = std::make_shared<Type>( + die.GetID(), dwarf, empty_name, array_element_bit_stride / 8, nullptr, + dwarf->GetUID(type_die), Type::eEncodingIsUID, &attrs.decl, clang_type, + Type::ResolveState::Full); + type_sp->SetEncodingType(element_type); + const clang::Type *type = ClangUtil::GetQualType(clang_type).getTypePtr(); + m_ast.SetMetadataAsUserID(type, die.GetID()); + return type_sp; +} - CompilerType pointee_clang_type = pointee_type->GetForwardCompilerType(); - CompilerType class_clang_type = class_type->GetLayoutCompilerType(); +TypeSP DWARFASTParserClang::ParsePointerToMemberType( + const DWARFDIE &die, const ParsedDWARFTypeAttributes &attrs) { + SymbolFileDWARF *dwarf = die.GetDWARF(); + Type *pointee_type = dwarf->ResolveTypeUID(attrs.type.Reference(), true); + Type *class_type = + dwarf->ResolveTypeUID(attrs.containing_type.Reference(), true); - clang_type = ClangASTContext::CreateMemberPointerType(class_clang_type, - pointee_clang_type); + CompilerType pointee_clang_type = pointee_type->GetForwardCompilerType(); + CompilerType class_clang_type = class_type->GetLayoutCompilerType(); - if (llvm::Optional<uint64_t> clang_type_size = - clang_type.GetByteSize(nullptr)) { - type_sp = std::make_shared<Type>( - die.GetID(), dwarf, attrs.name, *clang_type_size, nullptr, - LLDB_INVALID_UID, Type::eEncodingIsUID, nullptr, clang_type, - Type::eResolveStateForward); - } + CompilerType clang_type = ClangASTContext::CreateMemberPointerType( + class_clang_type, pointee_clang_type); - break; - } - default: - dwarf->GetObjectFile()->GetModule()->ReportError( - "{0x%8.8x}: unhandled type tag 0x%4.4x (%s), please file a bug and " - "attach the file at the start of this error message", - die.GetOffset(), tag, DW_TAG_value_to_name(tag)); - break; + if (llvm::Optional<uint64_t> clang_type_size = + clang_type.GetByteSize(nullptr)) { + return std::make_shared<Type>(die.GetID(), dwarf, attrs.name, + *clang_type_size, nullptr, LLDB_INVALID_UID, + Type::eEncodingIsUID, nullptr, clang_type, + Type::ResolveState::Forward); } - - // 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); + return nullptr; } TypeSP DWARFASTParserClang::UpdateSymbolContextScopeForType( @@ -1281,20 +1380,20 @@ TypeSP DWARFASTParserClang::UpdateSymbolContextScopeForType( DWARFDIE sc_parent_die = SymbolFileDWARF::GetParentSymbolContextDIE(die); dw_tag_t sc_parent_tag = sc_parent_die.Tag(); - SymbolContextScope *symbol_context_scope = NULL; + SymbolContextScope *symbol_context_scope = nullptr; 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) { + } else if (sc.function != nullptr && sc_parent_die) { symbol_context_scope = sc.function->GetBlock(true).FindBlockByID(sc_parent_die.GetID()); - if (symbol_context_scope == NULL) + if (symbol_context_scope == nullptr) symbol_context_scope = sc.function; } else { symbol_context_scope = sc.module_sp.get(); } - if (symbol_context_scope != NULL) + if (symbol_context_scope != nullptr) type_sp->SetSymbolContextScope(symbol_context_scope); // We are ready to put this type into the uniqued list up at the module @@ -1306,7 +1405,8 @@ TypeSP DWARFASTParserClang::UpdateSymbolContextScopeForType( } TypeSP -DWARFASTParserClang::ParseStructureLikeDIE(const DWARFDIE &die, +DWARFASTParserClang::ParseStructureLikeDIE(const SymbolContext &sc, + const DWARFDIE &die, ParsedDWARFTypeAttributes &attrs) { TypeSP type_sp; CompilerType clang_type; @@ -1438,9 +1538,9 @@ DWARFASTParserClang::ParseStructureLikeDIE(const DWARFDIE &die, attrs.name.GetCString()); } - // See if the type comes from a DWO module and if so, track down that - // type. - type_sp = ParseTypeFromDWO(die, log); + // See if the type comes from a Clang module and if so, track down + // that type. + type_sp = ParseTypeFromClangModule(sc, die, log); if (type_sp) return type_sp; @@ -1495,7 +1595,7 @@ DWARFASTParserClang::ParseStructureLikeDIE(const DWARFDIE &die, // 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, + CompleteExternalTagDeclType(m_ast, GetClangASTImporter(), decl_ctx, die, attrs.name.GetCString()); if (attrs.accessibility == eAccessNone && decl_ctx) { @@ -1546,7 +1646,7 @@ DWARFASTParserClang::ParseStructureLikeDIE(const DWARFDIE &die, clang_type_was_created = true; clang_type = m_ast.CreateRecordType( decl_ctx, attrs.accessibility, attrs.name.GetCString(), tag_decl_kind, - attrs.class_language, &metadata); + attrs.class_language, &metadata, attrs.exports_symbols); } } @@ -1557,7 +1657,7 @@ DWARFASTParserClang::ParseStructureLikeDIE(const DWARFDIE &die, type_sp = std::make_shared<Type>(die.GetID(), dwarf, attrs.name, attrs.byte_size, nullptr, LLDB_INVALID_UID, Type::eEncodingIsUID, &attrs.decl, - clang_type, Type::eResolveStateForward); + clang_type, Type::ResolveState::Forward); type_sp->SetIsCompleteObjCClass(attrs.is_complete_objc_class); @@ -1621,7 +1721,7 @@ DWARFASTParserClang::ParseStructureLikeDIE(const DWARFDIE &die, ClangASTContext::GetAsRecordDecl(clang_type); if (record_decl) { - GetClangASTImporter().InsertRecordDecl( + GetClangASTImporter().SetRecordLayout( record_decl, ClangASTImporter::LayoutInfo()); } } @@ -1810,7 +1910,7 @@ bool DWARFASTParserClang::ParseTemplateDIE( } } - clang::ASTContext *ast = m_ast.getASTContext(); + clang::ASTContext &ast = m_ast.getASTContext(); if (!clang_type) clang_type = m_ast.GetBasicType(eBasicTypeVoid); @@ -1830,7 +1930,7 @@ bool DWARFASTParserClang::ParseTemplateDIE( return false; llvm::APInt apint(*size, uval64, is_signed); template_param_infos.args.push_back( - clang::TemplateArgument(*ast, llvm::APSInt(apint, !is_signed), + clang::TemplateArgument(ast, llvm::APSInt(apint, !is_signed), ClangUtil::GetQualType(clang_type))); } else { template_param_infos.args.push_back( @@ -1880,6 +1980,182 @@ bool DWARFASTParserClang::ParseTemplateParameterInfos( return template_param_infos.args.size() == template_param_infos.names.size(); } +bool DWARFASTParserClang::CompleteRecordType(const DWARFDIE &die, + lldb_private::Type *type, + CompilerType &clang_type) { + const dw_tag_t tag = die.Tag(); + SymbolFileDWARF *dwarf = die.GetDWARF(); + + ClangASTImporter::LayoutInfo layout_info; + + { + if (die.HasChildren()) { + LanguageType class_language = eLanguageTypeUnknown; + if (ClangASTContext::IsObjCObjectOrInterfaceType(clang_type)) { + class_language = eLanguageTypeObjC; + // For objective C we don't start the definition when the class is + // created. + ClangASTContext::StartTagDeclarationDefinition(clang_type); + } + + 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; + } + + std::vector<std::unique_ptr<clang::CXXBaseSpecifier>> bases; + std::vector<int> member_accessibilities; + bool is_a_class = false; + // Parse members and base classes first + std::vector<DWARFDIE> member_function_dies; + + DelayedPropertyList delayed_properties; + ParseChildMembers(die, clang_type, class_language, bases, + member_accessibilities, member_function_dies, + delayed_properties, default_accessibility, is_a_class, + layout_info); + + // Now parse any methods if there were any... + for (const DWARFDIE &die : member_function_dies) + dwarf->ResolveType(die); + + if (class_language == eLanguageTypeObjC) { + ConstString class_name(clang_type.GetTypeName()); + if (class_name) { + DIEArray method_die_offsets; + dwarf->GetObjCMethodDIEOffsets(class_name, method_die_offsets); + + if (!method_die_offsets.empty()) { + DWARFDebugInfo *debug_info = dwarf->DebugInfo(); + + const size_t num_matches = method_die_offsets.size(); + for (size_t i = 0; i < num_matches; ++i) { + const DIERef &die_ref = method_die_offsets[i]; + DWARFDIE method_die = debug_info->GetDIE(die_ref); + + if (method_die) + method_die.ResolveType(); + } + } + + for (DelayedPropertyList::iterator pi = delayed_properties.begin(), + pe = delayed_properties.end(); + pi != pe; ++pi) + pi->Finalize(); + } + } + + // If we have a DW_TAG_structure_type instead of a DW_TAG_class_type we + // need to tell the clang type it is actually a class. + if (class_language != eLanguageTypeObjC) { + if (is_a_class && tag_decl_kind != clang::TTK_Class) + m_ast.SetTagTypeKind(ClangUtil::GetQualType(clang_type), + clang::TTK_Class); + } + + // Since DW_TAG_structure_type gets used for both classes and + // structures, we may need to set any DW_TAG_member fields to have a + // "private" access if none was specified. When we parsed the child + // members we tracked that actual accessibility value for each + // DW_TAG_member in the "member_accessibilities" array. If the value + // for the member is zero, then it was set to the + // "default_accessibility" which for structs was "public". Below we + // correct this by setting any fields to "private" that weren't + // correctly set. + if (is_a_class && !member_accessibilities.empty()) { + // This is a class and all members that didn't have their access + // specified are private. + m_ast.SetDefaultAccessForRecordFields( + m_ast.GetAsRecordDecl(clang_type), eAccessPrivate, + &member_accessibilities.front(), member_accessibilities.size()); + } + + if (!bases.empty()) { + // Make sure all base classes refer to complete types and not forward + // declarations. If we don't do this, clang will crash with an + // assertion in the call to clang_type.TransferBaseClasses() + for (const auto &base_class : bases) { + clang::TypeSourceInfo *type_source_info = + base_class->getTypeSourceInfo(); + if (type_source_info) { + CompilerType base_class_type = + m_ast.GetType(type_source_info->getType()); + if (!base_class_type.GetCompleteType()) { + auto module = dwarf->GetObjectFile()->GetModule(); + module->ReportError(":: Class '%s' has a base class '%s' which " + "does not have a complete definition.", + die.GetName(), + base_class_type.GetTypeName().GetCString()); + if (die.GetCU()->GetProducer() == eProducerClang) + module->ReportError(":: Try compiling the source file with " + "-fstandalone-debug."); + + // We have no choice other than to pretend that the base class + // is complete. If we don't do this, clang will crash when we + // call setBases() inside of + // "clang_type.TransferBaseClasses()" below. Since we + // provide layout assistance, all ivars in this class and other + // classes will be fine, this is the best we can do short of + // crashing. + if (ClangASTContext::StartTagDeclarationDefinition( + base_class_type)) { + ClangASTContext::CompleteTagDeclarationDefinition( + base_class_type); + } + } + } + } + + m_ast.TransferBaseClasses(clang_type.GetOpaqueQualType(), + std::move(bases)); + } + } + } + + m_ast.AddMethodOverridesForCXXRecordType(clang_type.GetOpaqueQualType()); + ClangASTContext::BuildIndirectFields(clang_type); + ClangASTContext::CompleteTagDeclarationDefinition(clang_type); + + if (!layout_info.field_offsets.empty() || !layout_info.base_offsets.empty() || + !layout_info.vbase_offsets.empty()) { + if (type) + layout_info.bit_size = type->GetByteSize().getValueOr(0) * 8; + if (layout_info.bit_size == 0) + layout_info.bit_size = + die.GetAttributeValueAsUnsigned(DW_AT_byte_size, 0) * 8; + + clang::CXXRecordDecl *record_decl = + m_ast.GetAsCXXRecordDecl(clang_type.GetOpaqueQualType()); + if (record_decl) + GetClangASTImporter().SetRecordLayout(record_decl, layout_info); + } + + return (bool)clang_type; +} + +bool DWARFASTParserClang::CompleteEnumType(const DWARFDIE &die, + lldb_private::Type *type, + CompilerType &clang_type) { + if (ClangASTContext::StartTagDeclarationDefinition(clang_type)) { + if (die.HasChildren()) { + bool is_signed = false; + clang_type.IsIntegerType(is_signed); + ParseChildEnumerators(clang_type, is_signed, + type->GetByteSize().getValueOr(0), die); + } + ClangASTContext::CompleteTagDeclarationDefinition(clang_type); + } + return (bool)clang_type; +} + bool DWARFASTParserClang::CompleteTypeFromDWARF(const DWARFDIE &die, lldb_private::Type *type, CompilerType &clang_type) { @@ -1895,39 +2171,6 @@ bool DWARFASTParserClang::CompleteTypeFromDWARF(const DWARFDIE &die, if (!die) return false; -#if defined LLDB_CONFIGURATION_DEBUG - // For debugging purposes, the LLDB_DWARF_DONT_COMPLETE_TYPENAMES environment - // variable can be set with one or more typenames separated by ';' - // characters. This will cause this function to not complete any types whose - // names match. - // - // Examples of setting this environment variable: - // - // LLDB_DWARF_DONT_COMPLETE_TYPENAMES=Foo - // LLDB_DWARF_DONT_COMPLETE_TYPENAMES=Foo;Bar;Baz - const char *dont_complete_typenames_cstr = - getenv("LLDB_DWARF_DONT_COMPLETE_TYPENAMES"); - if (dont_complete_typenames_cstr && dont_complete_typenames_cstr[0]) { - const char *die_name = die.GetName(); - if (die_name && die_name[0]) { - const char *match = strstr(dont_complete_typenames_cstr, die_name); - if (match) { - size_t die_name_length = strlen(die_name); - while (match) { - const char separator_char = ';'; - const char next_char = match[die_name_length]; - if (next_char == '\0' || next_char == separator_char) { - if (match == dont_complete_typenames_cstr || - match[-1] == separator_char) - return false; - } - match = strstr(match + 1, die_name); - } - } - } - } -#endif - const dw_tag_t tag = die.Tag(); Log *log = @@ -1941,239 +2184,10 @@ bool DWARFASTParserClang::CompleteTypeFromDWARF(const DWARFDIE &die, switch (tag) { case DW_TAG_structure_type: case DW_TAG_union_type: - case DW_TAG_class_type: { - ClangASTImporter::LayoutInfo layout_info; - - { - if (die.HasChildren()) { - LanguageType class_language = eLanguageTypeUnknown; - if (ClangASTContext::IsObjCObjectOrInterfaceType(clang_type)) { - class_language = eLanguageTypeObjC; - // For objective C we don't start the definition when the class is - // created. - ClangASTContext::StartTagDeclarationDefinition(clang_type); - } - - 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; - } - - std::vector<std::unique_ptr<clang::CXXBaseSpecifier>> bases; - std::vector<int> member_accessibilities; - bool is_a_class = false; - // Parse members and base classes first - std::vector<DWARFDIE> member_function_dies; - - DelayedPropertyList delayed_properties; - ParseChildMembers(die, clang_type, class_language, bases, - member_accessibilities, member_function_dies, - delayed_properties, default_accessibility, is_a_class, - layout_info); - - // Now parse any methods if there were any... - for (const DWARFDIE &die : member_function_dies) - dwarf->ResolveType(die); - - if (class_language == eLanguageTypeObjC) { - ConstString class_name(clang_type.GetTypeName()); - if (class_name) { - DIEArray method_die_offsets; - dwarf->GetObjCMethodDIEOffsets(class_name, method_die_offsets); - - if (!method_die_offsets.empty()) { - DWARFDebugInfo *debug_info = dwarf->DebugInfo(); - - const size_t num_matches = method_die_offsets.size(); - for (size_t i = 0; i < num_matches; ++i) { - const DIERef &die_ref = method_die_offsets[i]; - DWARFDIE method_die = debug_info->GetDIE(die_ref); - - if (method_die) - method_die.ResolveType(); - } - } - - for (DelayedPropertyList::iterator pi = delayed_properties.begin(), - pe = delayed_properties.end(); - pi != pe; ++pi) - pi->Finalize(); - } - } - - // If we have a DW_TAG_structure_type instead of a DW_TAG_class_type we - // need to tell the clang type it is actually a class. - if (class_language != eLanguageTypeObjC) { - if (is_a_class && tag_decl_kind != clang::TTK_Class) - m_ast.SetTagTypeKind(ClangUtil::GetQualType(clang_type), - clang::TTK_Class); - } - - // Since DW_TAG_structure_type gets used for both classes and - // structures, we may need to set any DW_TAG_member fields to have a - // "private" access if none was specified. When we parsed the child - // members we tracked that actual accessibility value for each - // DW_TAG_member in the "member_accessibilities" array. If the value - // for the member is zero, then it was set to the - // "default_accessibility" which for structs was "public". Below we - // correct this by setting any fields to "private" that weren't - // correctly set. - if (is_a_class && !member_accessibilities.empty()) { - // This is a class and all members that didn't have their access - // specified are private. - m_ast.SetDefaultAccessForRecordFields( - m_ast.GetAsRecordDecl(clang_type), eAccessPrivate, - &member_accessibilities.front(), member_accessibilities.size()); - } - - if (!bases.empty()) { - // Make sure all base classes refer to complete types and not forward - // declarations. If we don't do this, clang will crash with an - // assertion in the call to clang_type.TransferBaseClasses() - for (const auto &base_class : bases) { - clang::TypeSourceInfo *type_source_info = - base_class->getTypeSourceInfo(); - if (type_source_info) { - CompilerType base_class_type( - &m_ast, type_source_info->getType().getAsOpaquePtr()); - if (!base_class_type.GetCompleteType()) { - auto module = dwarf->GetObjectFile()->GetModule(); - module->ReportError(":: Class '%s' has a base class '%s' which " - "does not have a complete definition.", - die.GetName(), - base_class_type.GetTypeName().GetCString()); - if (die.GetCU()->GetProducer() == eProducerClang) - module->ReportError(":: Try compiling the source file with " - "-fstandalone-debug."); - - // We have no choice other than to pretend that the base class - // is complete. If we don't do this, clang will crash when we - // call setBases() inside of - // "clang_type.TransferBaseClasses()" below. Since we - // provide layout assistance, all ivars in this class and other - // classes will be fine, this is the best we can do short of - // crashing. - if (ClangASTContext::StartTagDeclarationDefinition( - base_class_type)) { - ClangASTContext::CompleteTagDeclarationDefinition( - base_class_type); - } - } - } - } - - m_ast.TransferBaseClasses(clang_type.GetOpaqueQualType(), - std::move(bases)); - } - } - } - - m_ast.AddMethodOverridesForCXXRecordType(clang_type.GetOpaqueQualType()); - ClangASTContext::BuildIndirectFields(clang_type); - ClangASTContext::CompleteTagDeclarationDefinition(clang_type); - - if (!layout_info.field_offsets.empty() || - !layout_info.base_offsets.empty() || - !layout_info.vbase_offsets.empty()) { - if (type) - layout_info.bit_size = type->GetByteSize().getValueOr(0) * 8; - if (layout_info.bit_size == 0) - layout_info.bit_size = - die.GetAttributeValueAsUnsigned(DW_AT_byte_size, 0) * 8; - - clang::CXXRecordDecl *record_decl = - m_ast.GetAsCXXRecordDecl(clang_type.GetOpaqueQualType()); - if (record_decl) { - if (log) { - ModuleSP module_sp = dwarf->GetObjectFile()->GetModule(); - - if (module_sp) { - module_sp->LogMessage( - log, - "ClangASTContext::CompleteTypeFromDWARF (clang_type = %p) " - "caching layout info for record_decl = %p, bit_size = %" PRIu64 - ", alignment = %" PRIu64 - ", field_offsets[%u], base_offsets[%u], vbase_offsets[%u])", - static_cast<void *>(clang_type.GetOpaqueQualType()), - static_cast<void *>(record_decl), layout_info.bit_size, - layout_info.alignment, - static_cast<uint32_t>(layout_info.field_offsets.size()), - static_cast<uint32_t>(layout_info.base_offsets.size()), - static_cast<uint32_t>(layout_info.vbase_offsets.size())); - - uint32_t idx; - { - llvm::DenseMap<const clang::FieldDecl *, uint64_t>::const_iterator - pos, - end = layout_info.field_offsets.end(); - for (idx = 0, pos = layout_info.field_offsets.begin(); pos != end; - ++pos, ++idx) { - module_sp->LogMessage( - log, "ClangASTContext::CompleteTypeFromDWARF (clang_type = " - "%p) field[%u] = { bit_offset=%u, name='%s' }", - static_cast<void *>(clang_type.GetOpaqueQualType()), idx, - static_cast<uint32_t>(pos->second), - pos->first->getNameAsString().c_str()); - } - } - - { - llvm::DenseMap<const clang::CXXRecordDecl *, - clang::CharUnits>::const_iterator base_pos, - base_end = layout_info.base_offsets.end(); - for (idx = 0, base_pos = layout_info.base_offsets.begin(); - base_pos != base_end; ++base_pos, ++idx) { - module_sp->LogMessage( - log, "ClangASTContext::CompleteTypeFromDWARF (clang_type = " - "%p) base[%u] = { byte_offset=%u, name='%s' }", - clang_type.GetOpaqueQualType(), idx, - (uint32_t)base_pos->second.getQuantity(), - base_pos->first->getNameAsString().c_str()); - } - } - { - llvm::DenseMap<const clang::CXXRecordDecl *, - clang::CharUnits>::const_iterator vbase_pos, - vbase_end = layout_info.vbase_offsets.end(); - for (idx = 0, vbase_pos = layout_info.vbase_offsets.begin(); - vbase_pos != vbase_end; ++vbase_pos, ++idx) { - module_sp->LogMessage( - log, "ClangASTContext::CompleteTypeFromDWARF (clang_type = " - "%p) vbase[%u] = { byte_offset=%u, name='%s' }", - static_cast<void *>(clang_type.GetOpaqueQualType()), idx, - static_cast<uint32_t>(vbase_pos->second.getQuantity()), - vbase_pos->first->getNameAsString().c_str()); - } - } - } - } - GetClangASTImporter().InsertRecordDecl(record_decl, layout_info); - } - } - } - - return (bool)clang_type; - + case DW_TAG_class_type: + return CompleteRecordType(die, type, clang_type); case DW_TAG_enumeration_type: - if (ClangASTContext::StartTagDeclarationDefinition(clang_type)) { - if (die.HasChildren()) { - bool is_signed = false; - clang_type.IsIntegerType(is_signed); - ParseChildEnumerators(clang_type, is_signed, - type->GetByteSize().getValueOr(0), die); - } - ClangASTContext::CompleteTagDeclarationDefinition(clang_type); - } - return (bool)clang_type; - + return CompleteEnumType(die, type, clang_type); default: assert(false && "not a forward clang type decl!"); break; @@ -2205,7 +2219,7 @@ CompilerDeclContext DWARFASTParserClang::GetDeclContextForUIDFromDWARF(const DWARFDIE &die) { clang::DeclContext *clang_decl_ctx = GetClangDeclContextForDIE(die); if (clang_decl_ctx) - return CompilerDeclContext(&m_ast, clang_decl_ctx); + return m_ast.CreateDeclContext(clang_decl_ctx); return CompilerDeclContext(); } @@ -2214,7 +2228,7 @@ DWARFASTParserClang::GetDeclContextContainingUIDFromDWARF(const DWARFDIE &die) { clang::DeclContext *clang_decl_ctx = GetClangDeclContextContainingDIE(die, nullptr); if (clang_decl_ctx) - return CompilerDeclContext(&m_ast, clang_decl_ctx); + return m_ast.CreateDeclContext(clang_decl_ctx); return CompilerDeclContext(); } @@ -2284,54 +2298,6 @@ size_t DWARFASTParserClang::ParseChildEnumerators( return enumerators_added; } -#if defined(LLDB_CONFIGURATION_DEBUG) || defined(LLDB_CONFIGURATION_RELEASE) - -class DIEStack { -public: - void Push(const DWARFDIE &die) { m_dies.push_back(die); } - - void LogDIEs(Log *log) { - StreamString log_strm; - const size_t n = m_dies.size(); - log_strm.Printf("DIEStack[%" PRIu64 "]:\n", (uint64_t)n); - for (size_t i = 0; i < n; i++) { - std::string qualified_name; - const DWARFDIE &die = m_dies[i]; - die.GetQualifiedName(qualified_name); - log_strm.Printf("[%" PRIu64 "] 0x%8.8x: %s name='%s'\n", (uint64_t)i, - die.GetOffset(), die.GetTagAsCString(), - qualified_name.c_str()); - } - log->PutCString(log_strm.GetData()); - } - void Pop() { m_dies.pop_back(); } - - class ScopedPopper { - public: - ScopedPopper(DIEStack &die_stack) - : m_die_stack(die_stack), m_valid(false) {} - - void Push(const DWARFDIE &die) { - m_valid = true; - m_die_stack.Push(die); - } - - ~ScopedPopper() { - if (m_valid) - m_die_stack.Pop(); - } - - protected: - DIEStack &m_die_stack; - bool m_valid; - }; - -protected: - typedef std::vector<DWARFDIE> Stack; - Stack m_dies; -}; -#endif - Function *DWARFASTParserClang::ParseFunctionFromDWARF(CompileUnit &comp_unit, const DWARFDIE &die) { DWARFRangeList func_ranges; @@ -2445,495 +2411,499 @@ Function *DWARFASTParserClang::ParseFunctionFromDWARF(CompileUnit &comp_unit, return nullptr; } -bool DWARFASTParserClang::ParseChildMembers( - const DWARFDIE &parent_die, CompilerType &class_clang_type, - const LanguageType class_language, - std::vector<std::unique_ptr<clang::CXXBaseSpecifier>> &base_classes, +void DWARFASTParserClang::ParseSingleMember( + const DWARFDIE &die, const DWARFDIE &parent_die, + lldb_private::CompilerType &class_clang_type, + const lldb::LanguageType class_language, std::vector<int> &member_accessibilities, - std::vector<DWARFDIE> &member_function_dies, - DelayedPropertyList &delayed_properties, AccessType &default_accessibility, - bool &is_a_class, ClangASTImporter::LayoutInfo &layout_info) { - if (!parent_die) - return false; - + lldb::AccessType &default_accessibility, + DelayedPropertyList &delayed_properties, + lldb_private::ClangASTImporter::LayoutInfo &layout_info, + BitfieldInfo &last_field_info) { + ModuleSP module_sp = parent_die.GetDWARF()->GetObjectFile()->GetModule(); + const dw_tag_t tag = die.Tag(); // Get the parent byte size so we can verify any members will fit const uint64_t parent_byte_size = parent_die.GetAttributeValueAsUnsigned(DW_AT_byte_size, UINT64_MAX); const uint64_t parent_bit_size = parent_byte_size == UINT64_MAX ? UINT64_MAX : parent_byte_size * 8; - uint32_t member_idx = 0; - BitfieldInfo last_field_info; - - ModuleSP module_sp = parent_die.GetDWARF()->GetObjectFile()->GetModule(); - ClangASTContext *ast = - llvm::dyn_cast_or_null<ClangASTContext>(class_clang_type.GetTypeSystem()); - if (ast == nullptr) - return false; - - for (DWARFDIE die = parent_die.GetFirstChild(); die.IsValid(); - die = die.GetSibling()) { - dw_tag_t tag = die.Tag(); - - switch (tag) { - case DW_TAG_member: - case DW_TAG_APPLE_property: { - DWARFAttributes attributes; - const size_t num_attributes = die.GetAttributes(attributes); - if (num_attributes > 0) { - const char *name = nullptr; - const char *prop_name = nullptr; - const char *prop_getter_name = nullptr; - const char *prop_setter_name = nullptr; - uint32_t prop_attributes = 0; - - bool is_artificial = false; - DWARFFormValue encoding_form; - AccessType accessibility = eAccessNone; - uint32_t member_byte_offset = - (parent_die.Tag() == DW_TAG_union_type) ? 0 : UINT32_MAX; - llvm::Optional<uint64_t> byte_size; - int64_t bit_offset = 0; - uint64_t data_bit_offset = UINT64_MAX; - size_t bit_size = 0; - bool is_external = - false; // On DW_TAG_members, this means the member is static - uint32_t i; - for (i = 0; i < num_attributes && !is_artificial; ++i) { - const dw_attr_t attr = attributes.AttributeAtIndex(i); - DWARFFormValue form_value; - if (attributes.ExtractFormValueAtIndex(i, form_value)) { - switch (attr) { - case DW_AT_name: - name = form_value.AsCString(); - break; - case DW_AT_type: - encoding_form = form_value; - break; - case DW_AT_bit_offset: - bit_offset = form_value.Signed(); - break; - case DW_AT_bit_size: - bit_size = form_value.Unsigned(); - break; - case DW_AT_byte_size: - byte_size = form_value.Unsigned(); - break; - case DW_AT_data_bit_offset: - data_bit_offset = form_value.Unsigned(); - break; - case DW_AT_data_member_location: - if (form_value.BlockData()) { - Value initialValue(0); - Value memberOffset(0); - const DWARFDataExtractor &debug_info_data = die.GetData(); - uint32_t block_length = form_value.Unsigned(); - uint32_t block_offset = - form_value.BlockData() - debug_info_data.GetDataStart(); - if (DWARFExpression::Evaluate( - nullptr, // ExecutionContext * - nullptr, // RegisterContext * - module_sp, - DataExtractor(debug_info_data, block_offset, - block_length), - die.GetCU(), eRegisterKindDWARF, &initialValue, nullptr, - memberOffset, nullptr)) { - member_byte_offset = - memberOffset.ResolveValue(nullptr).UInt(); - } - } else { - // With DWARF 3 and later, if the value is an integer constant, - // this form value is the offset in bytes from the beginning of - // the containing entity. - member_byte_offset = form_value.Unsigned(); - } - break; - - case DW_AT_accessibility: - accessibility = DW_ACCESS_to_AccessType(form_value.Unsigned()); - break; - case DW_AT_artificial: - is_artificial = form_value.Boolean(); - break; - case DW_AT_APPLE_property_name: - prop_name = form_value.AsCString(); - break; - case DW_AT_APPLE_property_getter: - prop_getter_name = form_value.AsCString(); - break; - case DW_AT_APPLE_property_setter: - prop_setter_name = form_value.AsCString(); - break; - case DW_AT_APPLE_property_attribute: - prop_attributes = form_value.Unsigned(); - break; - case DW_AT_external: - is_external = form_value.Boolean(); - break; - - default: - case DW_AT_declaration: - case DW_AT_description: - case DW_AT_mutable: - case DW_AT_visibility: - case DW_AT_sibling: - break; + DWARFAttributes attributes; + const size_t num_attributes = die.GetAttributes(attributes); + if (num_attributes > 0) { + const char *name = nullptr; + const char *prop_name = nullptr; + const char *prop_getter_name = nullptr; + const char *prop_setter_name = nullptr; + uint32_t prop_attributes = 0; + + bool is_artificial = false; + DWARFFormValue encoding_form; + AccessType accessibility = eAccessNone; + uint32_t member_byte_offset = + (parent_die.Tag() == DW_TAG_union_type) ? 0 : UINT32_MAX; + llvm::Optional<uint64_t> byte_size; + int64_t bit_offset = 0; + uint64_t data_bit_offset = UINT64_MAX; + size_t bit_size = 0; + bool is_external = + false; // On DW_TAG_members, this means the member is static + uint32_t i; + for (i = 0; i < num_attributes && !is_artificial; ++i) { + const dw_attr_t attr = attributes.AttributeAtIndex(i); + DWARFFormValue form_value; + if (attributes.ExtractFormValueAtIndex(i, form_value)) { + switch (attr) { + case DW_AT_name: + name = form_value.AsCString(); + break; + case DW_AT_type: + encoding_form = form_value; + break; + case DW_AT_bit_offset: + bit_offset = form_value.Signed(); + break; + case DW_AT_bit_size: + bit_size = form_value.Unsigned(); + break; + case DW_AT_byte_size: + byte_size = form_value.Unsigned(); + break; + case DW_AT_data_bit_offset: + data_bit_offset = form_value.Unsigned(); + break; + case DW_AT_data_member_location: + if (form_value.BlockData()) { + Value initialValue(0); + Value memberOffset(0); + const DWARFDataExtractor &debug_info_data = die.GetData(); + uint32_t block_length = form_value.Unsigned(); + uint32_t block_offset = + form_value.BlockData() - debug_info_data.GetDataStart(); + if (DWARFExpression::Evaluate( + nullptr, // ExecutionContext * + nullptr, // RegisterContext * + module_sp, + DataExtractor(debug_info_data, block_offset, block_length), + die.GetCU(), eRegisterKindDWARF, &initialValue, nullptr, + memberOffset, nullptr)) { + member_byte_offset = memberOffset.ResolveValue(nullptr).UInt(); } + } else { + // With DWARF 3 and later, if the value is an integer constant, + // this form value is the offset in bytes from the beginning of + // the containing entity. + member_byte_offset = form_value.Unsigned(); } - } - - if (prop_name) { - ConstString fixed_getter; - ConstString fixed_setter; - - // Check if the property getter/setter were provided as full names. - // We want basenames, so we extract them. - - if (prop_getter_name && prop_getter_name[0] == '-') { - ObjCLanguage::MethodName prop_getter_method(prop_getter_name, true); - prop_getter_name = prop_getter_method.GetSelector().GetCString(); - } + break; - if (prop_setter_name && prop_setter_name[0] == '-') { - ObjCLanguage::MethodName prop_setter_method(prop_setter_name, true); - prop_setter_name = prop_setter_method.GetSelector().GetCString(); - } + case DW_AT_accessibility: + accessibility = DW_ACCESS_to_AccessType(form_value.Unsigned()); + break; + case DW_AT_artificial: + is_artificial = form_value.Boolean(); + break; + case DW_AT_APPLE_property_name: + prop_name = form_value.AsCString(); + break; + case DW_AT_APPLE_property_getter: + prop_getter_name = form_value.AsCString(); + break; + case DW_AT_APPLE_property_setter: + prop_setter_name = form_value.AsCString(); + break; + case DW_AT_APPLE_property_attribute: + prop_attributes = form_value.Unsigned(); + break; + case DW_AT_external: + is_external = form_value.Boolean(); + break; - // If the names haven't been provided, they need to be filled in. + default: + case DW_AT_declaration: + case DW_AT_description: + case DW_AT_mutable: + case DW_AT_visibility: + case DW_AT_sibling: + break; + } + } + } - if (!prop_getter_name) { - prop_getter_name = prop_name; - } - if (!prop_setter_name && prop_name[0] && - !(prop_attributes & DW_APPLE_PROPERTY_readonly)) { - StreamString ss; + if (prop_name) { + ConstString fixed_setter; - ss.Printf("set%c%s:", toupper(prop_name[0]), &prop_name[1]); + // Check if the property getter/setter were provided as full names. + // We want basenames, so we extract them. - fixed_setter.SetString(ss.GetString()); - prop_setter_name = fixed_setter.GetCString(); - } - } + if (prop_getter_name && prop_getter_name[0] == '-') { + ObjCLanguage::MethodName prop_getter_method(prop_getter_name, true); + prop_getter_name = prop_getter_method.GetSelector().GetCString(); + } - // Clang has a DWARF generation bug where sometimes it represents - // fields that are references with bad byte size and bit size/offset - // information such as: - // - // DW_AT_byte_size( 0x00 ) - // DW_AT_bit_size( 0x40 ) - // DW_AT_bit_offset( 0xffffffffffffffc0 ) - // - // So check the bit offset to make sure it is sane, and if the values - // are not sane, remove them. If we don't do this then we will end up - // with a crash if we try to use this type in an expression when clang - // becomes unhappy with its recycled debug info. - - if (byte_size.getValueOr(0) == 0 && bit_offset < 0) { - bit_size = 0; - bit_offset = 0; - } + if (prop_setter_name && prop_setter_name[0] == '-') { + ObjCLanguage::MethodName prop_setter_method(prop_setter_name, true); + prop_setter_name = prop_setter_method.GetSelector().GetCString(); + } - // FIXME: Make Clang ignore Objective-C accessibility for expressions - if (class_language == eLanguageTypeObjC || - class_language == eLanguageTypeObjC_plus_plus) - accessibility = eAccessNone; - - // Handle static members - if (is_external && member_byte_offset == UINT32_MAX) { - Type *var_type = die.ResolveTypeUID(encoding_form.Reference()); - - if (var_type) { - if (accessibility == eAccessNone) - accessibility = eAccessPublic; - ClangASTContext::AddVariableToRecordType( - class_clang_type, name, var_type->GetLayoutCompilerType(), - accessibility); - } - break; - } + // If the names haven't been provided, they need to be filled in. - if (!is_artificial) { - Type *member_type = die.ResolveTypeUID(encoding_form.Reference()); - - clang::FieldDecl *field_decl = nullptr; - if (tag == DW_TAG_member) { - if (member_type) { - if (accessibility == eAccessNone) - accessibility = default_accessibility; - member_accessibilities.push_back(accessibility); - - uint64_t field_bit_offset = - (member_byte_offset == UINT32_MAX ? 0 - : (member_byte_offset * 8)); - if (bit_size > 0) { - - BitfieldInfo this_field_info; - this_field_info.bit_offset = field_bit_offset; - this_field_info.bit_size = bit_size; - - ///////////////////////////////////////////////////////////// - // How to locate a field given the DWARF debug information - // - // AT_byte_size indicates the size of the word in which the bit - // offset must be interpreted. - // - // AT_data_member_location indicates the byte offset of the - // word from the base address of the structure. - // - // AT_bit_offset indicates how many bits into the word - // (according to the host endianness) the low-order bit of the - // field starts. AT_bit_offset can be negative. - // - // AT_bit_size indicates the size of the field in bits. - ///////////////////////////////////////////////////////////// - - if (data_bit_offset != UINT64_MAX) { - this_field_info.bit_offset = data_bit_offset; - } else { - if (!byte_size) - byte_size = member_type->GetByteSize(); - - ObjectFile *objfile = die.GetDWARF()->GetObjectFile(); - if (objfile->GetByteOrder() == eByteOrderLittle) { - this_field_info.bit_offset += byte_size.getValueOr(0) * 8; - this_field_info.bit_offset -= (bit_offset + bit_size); - } else { - this_field_info.bit_offset += bit_offset; - } - } + if (!prop_getter_name) { + prop_getter_name = prop_name; + } + if (!prop_setter_name && prop_name[0] && + !(prop_attributes & DW_APPLE_PROPERTY_readonly)) { + StreamString ss; - if ((this_field_info.bit_offset >= parent_bit_size) || - !last_field_info.NextBitfieldOffsetIsValid( - this_field_info.bit_offset)) { - ObjectFile *objfile = die.GetDWARF()->GetObjectFile(); - objfile->GetModule()->ReportWarning( - "0x%8.8" PRIx64 ": %s bitfield named \"%s\" has invalid " - "bit offset (0x%8.8" PRIx64 - ") member will be ignored. Please file a bug against the " - "compiler and include the preprocessed output for %s\n", - die.GetID(), DW_TAG_value_to_name(tag), name, - this_field_info.bit_offset, - GetUnitName(parent_die).c_str()); - this_field_info.Clear(); - continue; - } + ss.Printf("set%c%s:", toupper(prop_name[0]), &prop_name[1]); - // Update the field bit offset we will report for layout - field_bit_offset = this_field_info.bit_offset; - - // If the member to be emitted did not start on a character - // boundary and there is empty space between the last field and - // this one, then we need to emit an anonymous member filling - // up the space up to its start. There are three cases here: - // - // 1 If the previous member ended on a character boundary, then - // we can emit an - // anonymous member starting at the most recent character - // boundary. - // - // 2 If the previous member did not end on a character boundary - // and the distance - // from the end of the previous member to the current member - // is less than a - // word width, then we can emit an anonymous member starting - // right after the - // previous member and right before this member. - // - // 3 If the previous member did not end on a character boundary - // and the distance - // from the end of the previous member to the current member - // is greater than - // or equal a word width, then we act as in Case 1. - - const uint64_t character_width = 8; - const uint64_t word_width = 32; - - // Objective-C has invalid DW_AT_bit_offset values in older - // versions of clang, so we have to be careful and only insert - // unnamed bitfields if we have a new enough clang. - bool detect_unnamed_bitfields = true; - - if (class_language == eLanguageTypeObjC || - class_language == eLanguageTypeObjC_plus_plus) - detect_unnamed_bitfields = - die.GetCU()->Supports_unnamed_objc_bitfields(); - - if (detect_unnamed_bitfields) { - BitfieldInfo anon_field_info; - - if ((this_field_info.bit_offset % character_width) != - 0) // not char aligned - { - uint64_t last_field_end = 0; - - if (last_field_info.IsValid()) - last_field_end = - last_field_info.bit_offset + last_field_info.bit_size; - - if (this_field_info.bit_offset != last_field_end) { - if (((last_field_end % character_width) == 0) || // case 1 - (this_field_info.bit_offset - last_field_end >= - word_width)) // case 3 - { - anon_field_info.bit_size = - this_field_info.bit_offset % character_width; - anon_field_info.bit_offset = - this_field_info.bit_offset - - anon_field_info.bit_size; - } else // case 2 - { - anon_field_info.bit_size = - this_field_info.bit_offset - last_field_end; - anon_field_info.bit_offset = last_field_end; - } - } - } + fixed_setter.SetString(ss.GetString()); + prop_setter_name = fixed_setter.GetCString(); + } + } - if (anon_field_info.IsValid()) { - clang::FieldDecl *unnamed_bitfield_decl = - ClangASTContext::AddFieldToRecordType( - class_clang_type, llvm::StringRef(), - m_ast.GetBuiltinTypeForEncodingAndBitSize( - eEncodingSint, word_width), - accessibility, anon_field_info.bit_size); + // Clang has a DWARF generation bug where sometimes it represents + // fields that are references with bad byte size and bit size/offset + // information such as: + // + // DW_AT_byte_size( 0x00 ) + // DW_AT_bit_size( 0x40 ) + // DW_AT_bit_offset( 0xffffffffffffffc0 ) + // + // So check the bit offset to make sure it is sane, and if the values + // are not sane, remove them. If we don't do this then we will end up + // with a crash if we try to use this type in an expression when clang + // becomes unhappy with its recycled debug info. + + if (byte_size.getValueOr(0) == 0 && bit_offset < 0) { + bit_size = 0; + bit_offset = 0; + } + + // FIXME: Make Clang ignore Objective-C accessibility for expressions + if (class_language == eLanguageTypeObjC || + class_language == eLanguageTypeObjC_plus_plus) + accessibility = eAccessNone; + + // Handle static members + if (is_external && member_byte_offset == UINT32_MAX) { + Type *var_type = die.ResolveTypeUID(encoding_form.Reference()); + + if (var_type) { + if (accessibility == eAccessNone) + accessibility = eAccessPublic; + ClangASTContext::AddVariableToRecordType( + class_clang_type, name, var_type->GetLayoutCompilerType(), + accessibility); + } + return; + } + + if (!is_artificial) { + Type *member_type = die.ResolveTypeUID(encoding_form.Reference()); + + clang::FieldDecl *field_decl = nullptr; + if (tag == DW_TAG_member) { + if (member_type) { + if (accessibility == eAccessNone) + accessibility = default_accessibility; + member_accessibilities.push_back(accessibility); + + uint64_t field_bit_offset = + (member_byte_offset == UINT32_MAX ? 0 : (member_byte_offset * 8)); + if (bit_size > 0) { + + BitfieldInfo this_field_info; + this_field_info.bit_offset = field_bit_offset; + this_field_info.bit_size = bit_size; + + ///////////////////////////////////////////////////////////// + // How to locate a field given the DWARF debug information + // + // AT_byte_size indicates the size of the word in which the bit + // offset must be interpreted. + // + // AT_data_member_location indicates the byte offset of the + // word from the base address of the structure. + // + // AT_bit_offset indicates how many bits into the word + // (according to the host endianness) the low-order bit of the + // field starts. AT_bit_offset can be negative. + // + // AT_bit_size indicates the size of the field in bits. + ///////////////////////////////////////////////////////////// + + if (data_bit_offset != UINT64_MAX) { + this_field_info.bit_offset = data_bit_offset; + } else { + if (!byte_size) + byte_size = member_type->GetByteSize(); - layout_info.field_offsets.insert(std::make_pair( - unnamed_bitfield_decl, anon_field_info.bit_offset)); - } - } - last_field_info = this_field_info; + ObjectFile *objfile = die.GetDWARF()->GetObjectFile(); + if (objfile->GetByteOrder() == eByteOrderLittle) { + this_field_info.bit_offset += byte_size.getValueOr(0) * 8; + this_field_info.bit_offset -= (bit_offset + bit_size); } else { - last_field_info.Clear(); + this_field_info.bit_offset += bit_offset; } + } - CompilerType member_clang_type = - member_type->GetLayoutCompilerType(); - if (!member_clang_type.IsCompleteType()) - member_clang_type.GetCompleteType(); + if ((this_field_info.bit_offset >= parent_bit_size) || + !last_field_info.NextBitfieldOffsetIsValid( + this_field_info.bit_offset)) { + ObjectFile *objfile = die.GetDWARF()->GetObjectFile(); + objfile->GetModule()->ReportWarning( + "0x%8.8" PRIx64 ": %s bitfield named \"%s\" has invalid " + "bit offset (0x%8.8" PRIx64 + ") member will be ignored. Please file a bug against the " + "compiler and include the preprocessed output for %s\n", + die.GetID(), DW_TAG_value_to_name(tag), name, + this_field_info.bit_offset, GetUnitName(parent_die).c_str()); + this_field_info.Clear(); + return; + } + // Update the field bit offset we will report for layout + field_bit_offset = this_field_info.bit_offset; + + // If the member to be emitted did not start on a character + // boundary and there is empty space between the last field and + // this one, then we need to emit an anonymous member filling + // up the space up to its start. There are three cases here: + // + // 1 If the previous member ended on a character boundary, then + // we can emit an + // anonymous member starting at the most recent character + // boundary. + // + // 2 If the previous member did not end on a character boundary + // and the distance + // from the end of the previous member to the current member + // is less than a + // word width, then we can emit an anonymous member starting + // right after the + // previous member and right before this member. + // + // 3 If the previous member did not end on a character boundary + // and the distance + // from the end of the previous member to the current member + // is greater than + // or equal a word width, then we act as in Case 1. + + const uint64_t character_width = 8; + const uint64_t word_width = 32; + + // Objective-C has invalid DW_AT_bit_offset values in older + // versions of clang, so we have to be careful and only insert + // unnamed bitfields if we have a new enough clang. + bool detect_unnamed_bitfields = true; + + if (class_language == eLanguageTypeObjC || + class_language == eLanguageTypeObjC_plus_plus) + detect_unnamed_bitfields = + die.GetCU()->Supports_unnamed_objc_bitfields(); + + if (detect_unnamed_bitfields) { + BitfieldInfo anon_field_info; + + if ((this_field_info.bit_offset % character_width) != + 0) // not char aligned { - // Older versions of clang emit array[0] and array[1] in the - // same way (<rdar://problem/12566646>). If the current field - // is at the end of the structure, then there is definitely no - // room for extra elements and we override the type to - // array[0]. - - CompilerType member_array_element_type; - uint64_t member_array_size; - bool member_array_is_incomplete; - - if (member_clang_type.IsArrayType( - &member_array_element_type, &member_array_size, - &member_array_is_incomplete) && - !member_array_is_incomplete) { - uint64_t parent_byte_size = - parent_die.GetAttributeValueAsUnsigned(DW_AT_byte_size, - UINT64_MAX); - - if (member_byte_offset >= parent_byte_size) { - if (member_array_size != 1 && - (member_array_size != 0 || - member_byte_offset > parent_byte_size)) { - module_sp->ReportError( - "0x%8.8" PRIx64 - ": DW_TAG_member '%s' refers to type 0x%8.8x" - " which extends beyond the bounds of 0x%8.8" PRIx64, - die.GetID(), name, - encoding_form.Reference().GetOffset(), - parent_die.GetID()); - } + uint64_t last_field_end = 0; + + if (last_field_info.IsValid()) + last_field_end = + last_field_info.bit_offset + last_field_info.bit_size; - member_clang_type = m_ast.CreateArrayType( - member_array_element_type, 0, false); + if (this_field_info.bit_offset != last_field_end) { + if (((last_field_end % character_width) == 0) || // case 1 + (this_field_info.bit_offset - last_field_end >= + word_width)) // case 3 + { + anon_field_info.bit_size = + this_field_info.bit_offset % character_width; + anon_field_info.bit_offset = + this_field_info.bit_offset - anon_field_info.bit_size; + } else // case 2 + { + anon_field_info.bit_size = + this_field_info.bit_offset - last_field_end; + anon_field_info.bit_offset = last_field_end; } } } - if (ClangASTContext::IsCXXClassType(member_clang_type) && - !member_clang_type.GetCompleteType()) { - if (die.GetCU()->GetProducer() == eProducerClang) - module_sp->ReportError( - "DWARF DIE at 0x%8.8x (class %s) has a member variable " - "0x%8.8x (%s) whose type is a forward declaration, not a " - "complete definition.\nTry compiling the source file " - "with -fstandalone-debug", - parent_die.GetOffset(), parent_die.GetName(), - die.GetOffset(), name); - else - module_sp->ReportError( - "DWARF DIE at 0x%8.8x (class %s) has a member variable " - "0x%8.8x (%s) whose type is a forward declaration, not a " - "complete definition.\nPlease file a bug against the " - "compiler and include the preprocessed output for %s", - parent_die.GetOffset(), parent_die.GetName(), - die.GetOffset(), name, GetUnitName(parent_die).c_str()); - // We have no choice other than to pretend that the member - // class is complete. If we don't do this, clang will crash - // when trying to layout the class. Since we provide layout - // assistance, all ivars in this class and other classes will - // be fine, this is the best we can do short of crashing. - if (ClangASTContext::StartTagDeclarationDefinition( - member_clang_type)) { - ClangASTContext::CompleteTagDeclarationDefinition( - member_clang_type); - } else { - module_sp->ReportError( - "DWARF DIE at 0x%8.8x (class %s) has a member variable " - "0x%8.8x (%s) whose type claims to be a C++ class but we " - "were not able to start its definition.\nPlease file a " - "bug and attach the file at the start of this error " - "message", - parent_die.GetOffset(), parent_die.GetName(), - die.GetOffset(), name); - } + if (anon_field_info.IsValid()) { + clang::FieldDecl *unnamed_bitfield_decl = + ClangASTContext::AddFieldToRecordType( + class_clang_type, llvm::StringRef(), + m_ast.GetBuiltinTypeForEncodingAndBitSize(eEncodingSint, + word_width), + accessibility, anon_field_info.bit_size); + + layout_info.field_offsets.insert(std::make_pair( + unnamed_bitfield_decl, anon_field_info.bit_offset)); } + } + last_field_info = this_field_info; + } else { + last_field_info.Clear(); + } - field_decl = ClangASTContext::AddFieldToRecordType( - class_clang_type, name, member_clang_type, accessibility, - bit_size); + CompilerType member_clang_type = member_type->GetLayoutCompilerType(); + if (!member_clang_type.IsCompleteType()) + member_clang_type.GetCompleteType(); + + { + // Older versions of clang emit array[0] and array[1] in the + // same way (<rdar://problem/12566646>). If the current field + // is at the end of the structure, then there is definitely no + // room for extra elements and we override the type to + // array[0]. + + CompilerType member_array_element_type; + uint64_t member_array_size; + bool member_array_is_incomplete; + + if (member_clang_type.IsArrayType(&member_array_element_type, + &member_array_size, + &member_array_is_incomplete) && + !member_array_is_incomplete) { + uint64_t parent_byte_size = + parent_die.GetAttributeValueAsUnsigned(DW_AT_byte_size, + UINT64_MAX); + + if (member_byte_offset >= parent_byte_size) { + if (member_array_size != 1 && + (member_array_size != 0 || + member_byte_offset > parent_byte_size)) { + module_sp->ReportError( + "0x%8.8" PRIx64 + ": DW_TAG_member '%s' refers to type 0x%8.8x" + " which extends beyond the bounds of 0x%8.8" PRIx64, + die.GetID(), name, encoding_form.Reference().GetOffset(), + parent_die.GetID()); + } - m_ast.SetMetadataAsUserID(field_decl, die.GetID()); + member_clang_type = + m_ast.CreateArrayType(member_array_element_type, 0, false); + } + } + } - layout_info.field_offsets.insert( - std::make_pair(field_decl, field_bit_offset)); + if (ClangASTContext::IsCXXClassType(member_clang_type) && + !member_clang_type.GetCompleteType()) { + if (die.GetCU()->GetProducer() == eProducerClang) + module_sp->ReportError( + "DWARF DIE at 0x%8.8x (class %s) has a member variable " + "0x%8.8x (%s) whose type is a forward declaration, not a " + "complete definition.\nTry compiling the source file " + "with -fstandalone-debug", + parent_die.GetOffset(), parent_die.GetName(), die.GetOffset(), + name); + else + module_sp->ReportError( + "DWARF DIE at 0x%8.8x (class %s) has a member variable " + "0x%8.8x (%s) whose type is a forward declaration, not a " + "complete definition.\nPlease file a bug against the " + "compiler and include the preprocessed output for %s", + parent_die.GetOffset(), parent_die.GetName(), die.GetOffset(), + name, GetUnitName(parent_die).c_str()); + // We have no choice other than to pretend that the member + // class is complete. If we don't do this, clang will crash + // when trying to layout the class. Since we provide layout + // assistance, all ivars in this class and other classes will + // be fine, this is the best we can do short of crashing. + if (ClangASTContext::StartTagDeclarationDefinition( + member_clang_type)) { + ClangASTContext::CompleteTagDeclarationDefinition( + member_clang_type); } else { - if (name) - module_sp->ReportError( - "0x%8.8" PRIx64 - ": DW_TAG_member '%s' refers to type 0x%8.8x" - " which was unable to be parsed", - die.GetID(), name, encoding_form.Reference().GetOffset()); - else - module_sp->ReportError( - "0x%8.8" PRIx64 ": DW_TAG_member refers to type 0x%8.8x" - " which was unable to be parsed", - die.GetID(), encoding_form.Reference().GetOffset()); + module_sp->ReportError( + "DWARF DIE at 0x%8.8x (class %s) has a member variable " + "0x%8.8x (%s) whose type claims to be a C++ class but we " + "were not able to start its definition.\nPlease file a " + "bug and attach the file at the start of this error " + "message", + parent_die.GetOffset(), parent_die.GetName(), die.GetOffset(), + name); } } - if (prop_name != nullptr && member_type) { - clang::ObjCIvarDecl *ivar_decl = nullptr; + field_decl = ClangASTContext::AddFieldToRecordType( + class_clang_type, name, member_clang_type, accessibility, + bit_size); - if (field_decl) { - ivar_decl = clang::dyn_cast<clang::ObjCIvarDecl>(field_decl); - assert(ivar_decl != nullptr); - } + m_ast.SetMetadataAsUserID(field_decl, die.GetID()); - ClangASTMetadata metadata; - metadata.SetUserID(die.GetID()); - delayed_properties.push_back(DelayedAddObjCClassProperty( - class_clang_type, prop_name, - member_type->GetLayoutCompilerType(), ivar_decl, - prop_setter_name, prop_getter_name, prop_attributes, - &metadata)); + layout_info.field_offsets.insert( + std::make_pair(field_decl, field_bit_offset)); + } else { + if (name) + module_sp->ReportError( + "0x%8.8" PRIx64 ": DW_TAG_member '%s' refers to type 0x%8.8x" + " which was unable to be parsed", + die.GetID(), name, encoding_form.Reference().GetOffset()); + else + module_sp->ReportError( + "0x%8.8" PRIx64 ": DW_TAG_member refers to type 0x%8.8x" + " which was unable to be parsed", + die.GetID(), encoding_form.Reference().GetOffset()); + } + } - if (ivar_decl) - m_ast.SetMetadataAsUserID(ivar_decl, die.GetID()); - } + if (prop_name != nullptr && member_type) { + clang::ObjCIvarDecl *ivar_decl = nullptr; + + if (field_decl) { + ivar_decl = clang::dyn_cast<clang::ObjCIvarDecl>(field_decl); + assert(ivar_decl != nullptr); } + + ClangASTMetadata metadata; + metadata.SetUserID(die.GetID()); + delayed_properties.push_back(DelayedAddObjCClassProperty( + class_clang_type, prop_name, member_type->GetLayoutCompilerType(), + ivar_decl, prop_setter_name, prop_getter_name, prop_attributes, + &metadata)); + + if (ivar_decl) + m_ast.SetMetadataAsUserID(ivar_decl, die.GetID()); } - ++member_idx; - } break; + } + } +} + +bool DWARFASTParserClang::ParseChildMembers( + const DWARFDIE &parent_die, CompilerType &class_clang_type, + const LanguageType class_language, + std::vector<std::unique_ptr<clang::CXXBaseSpecifier>> &base_classes, + std::vector<int> &member_accessibilities, + std::vector<DWARFDIE> &member_function_dies, + DelayedPropertyList &delayed_properties, AccessType &default_accessibility, + bool &is_a_class, ClangASTImporter::LayoutInfo &layout_info) { + if (!parent_die) + return false; + + BitfieldInfo last_field_info; + + ModuleSP module_sp = parent_die.GetDWARF()->GetObjectFile()->GetModule(); + ClangASTContext *ast = + llvm::dyn_cast_or_null<ClangASTContext>(class_clang_type.GetTypeSystem()); + if (ast == nullptr) + return false; + + for (DWARFDIE die = parent_die.GetFirstChild(); die.IsValid(); + die = die.GetSibling()) { + dw_tag_t tag = die.Tag(); + + switch (tag) { + case DW_TAG_member: + case DW_TAG_APPLE_property: + ParseSingleMember(die, parent_die, class_clang_type, class_language, + member_accessibilities, default_accessibility, + delayed_properties, layout_info, last_field_info); + break; case DW_TAG_subprogram: // Let the type parsing code handle this one for us. @@ -3552,18 +3522,20 @@ DWARFASTParserClang::ResolveNamespaceDIE(const DWARFDIE &die) { SymbolFileDWARF *dwarf = die.GetDWARF(); if (namespace_name) { dwarf->GetObjectFile()->GetModule()->LogMessage( - log, "ASTContext => %p: 0x%8.8" PRIx64 - ": DW_TAG_namespace with DW_AT_name(\"%s\") => " - "clang::NamespaceDecl *%p (original = %p)", - static_cast<void *>(m_ast.getASTContext()), die.GetID(), + log, + "ASTContext => %p: 0x%8.8" PRIx64 + ": DW_TAG_namespace with DW_AT_name(\"%s\") => " + "clang::NamespaceDecl *%p (original = %p)", + static_cast<void *>(&m_ast.getASTContext()), die.GetID(), namespace_name, static_cast<void *>(namespace_decl), static_cast<void *>(namespace_decl->getOriginalNamespace())); } else { dwarf->GetObjectFile()->GetModule()->LogMessage( - log, "ASTContext => %p: 0x%8.8" PRIx64 - ": DW_TAG_namespace (anonymous) => clang::NamespaceDecl *%p " - "(original = %p)", - static_cast<void *>(m_ast.getASTContext()), die.GetID(), + log, + "ASTContext => %p: 0x%8.8" PRIx64 + ": DW_TAG_namespace (anonymous) => clang::NamespaceDecl *%p " + "(original = %p)", + static_cast<void *>(&m_ast.getASTContext()), die.GetID(), static_cast<void *>(namespace_decl), static_cast<void *>(namespace_decl->getOriginalNamespace())); } diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h index 106f9254a449..4ad757247c3e 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h @@ -128,7 +128,8 @@ protected: const DWARFDIE &parent_die); /// Parse a structure, class, or union type DIE. - lldb::TypeSP ParseStructureLikeDIE(const DWARFDIE &die, + lldb::TypeSP ParseStructureLikeDIE(const lldb_private::SymbolContext &sc, + const DWARFDIE &die, ParsedDWARFTypeAttributes &attrs); lldb_private::Type *GetTypeForDIE(const DWARFDIE &die); @@ -159,11 +160,73 @@ protected: UpdateSymbolContextScopeForType(const lldb_private::SymbolContext &sc, const DWARFDIE &die, lldb::TypeSP type_sp); - lldb::TypeSP ParseTypeFromDWO(const DWARFDIE &die, lldb_private::Log *log); + /// Follow Clang Module Skeleton CU references to find a type definition. + lldb::TypeSP ParseTypeFromClangModule(const lldb_private::SymbolContext &sc, + const DWARFDIE &die, + lldb_private::Log *log); // Return true if this type is a declaration to a type in an external // module. lldb::ModuleSP GetModuleForType(const DWARFDIE &die); + +private: + struct BitfieldInfo { + uint64_t bit_size; + uint64_t bit_offset; + + BitfieldInfo() + : bit_size(LLDB_INVALID_ADDRESS), bit_offset(LLDB_INVALID_ADDRESS) {} + + void Clear() { + bit_size = LLDB_INVALID_ADDRESS; + bit_offset = LLDB_INVALID_ADDRESS; + } + + bool IsValid() const { + return (bit_size != LLDB_INVALID_ADDRESS) && + (bit_offset != LLDB_INVALID_ADDRESS); + } + + bool NextBitfieldOffsetIsValid(const uint64_t next_bit_offset) const { + if (IsValid()) { + // This bitfield info is valid, so any subsequent bitfields must not + // overlap and must be at a higher bit offset than any previous bitfield + // + size. + return (bit_size + bit_offset) <= next_bit_offset; + } else { + // If the this BitfieldInfo is not valid, then any offset isOK + return true; + } + } + }; + + void + ParseSingleMember(const DWARFDIE &die, const DWARFDIE &parent_die, + lldb_private::CompilerType &class_clang_type, + const lldb::LanguageType class_language, + std::vector<int> &member_accessibilities, + lldb::AccessType &default_accessibility, + DelayedPropertyList &delayed_properties, + lldb_private::ClangASTImporter::LayoutInfo &layout_info, + BitfieldInfo &last_field_info); + + bool CompleteRecordType(const DWARFDIE &die, lldb_private::Type *type, + lldb_private::CompilerType &clang_type); + bool CompleteEnumType(const DWARFDIE &die, lldb_private::Type *type, + lldb_private::CompilerType &clang_type); + + lldb::TypeSP ParseTypeModifier(const lldb_private::SymbolContext &sc, + const DWARFDIE &die, + ParsedDWARFTypeAttributes &attrs); + lldb::TypeSP ParseEnum(const lldb_private::SymbolContext &sc, + const DWARFDIE &die, ParsedDWARFTypeAttributes &attrs); + lldb::TypeSP ParseSubroutine(const DWARFDIE &die, + ParsedDWARFTypeAttributes &attrs); + // FIXME: attrs should be passed as a const reference. + lldb::TypeSP ParseArrayType(const DWARFDIE &die, + ParsedDWARFTypeAttributes &attrs); + lldb::TypeSP ParsePointerToMemberType(const DWARFDIE &die, + const ParsedDWARFTypeAttributes &attrs); }; /// Parsed form of all attributes that are relevant for type reconstruction. @@ -181,6 +244,8 @@ struct ParsedDWARFTypeAttributes { bool is_scoped_enum = false; bool is_vector = false; bool is_virtual = false; + bool is_objc_direct_call = false; + bool exports_symbols = false; clang::StorageClass storage = clang::SC_None; const char *mangled_name = nullptr; lldb_private::ConstString name; diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.h index 75647dbb082f..454637ef981c 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.h @@ -24,8 +24,8 @@ private: DWARFCompileUnit(SymbolFileDWARF &dwarf, lldb::user_id_t uid, const DWARFUnitHeader &header, const DWARFAbbreviationDeclarationSet &abbrevs, - DIERef::Section section) - : DWARFUnit(dwarf, uid, header, abbrevs, section) {} + DIERef::Section section, bool is_dwo) + : DWARFUnit(dwarf, uid, header, abbrevs, section, is_dwo) {} DISALLOW_COPY_AND_ASSIGN(DWARFCompileUnit); diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFContext.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFContext.cpp index eb307ce1cce1..5052b825fea6 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFContext.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFContext.cpp @@ -70,6 +70,17 @@ const DWARFDataExtractor &DWARFContext::getOrLoadLineStrData() { m_data_debug_line_str); } +const DWARFDataExtractor &DWARFContext::getOrLoadLocData() { + return LoadOrGetSection(eSectionTypeDWARFDebugLoc, + eSectionTypeDWARFDebugLocDwo, m_data_debug_loc); +} + +const DWARFDataExtractor &DWARFContext::getOrLoadLocListsData() { + return LoadOrGetSection(eSectionTypeDWARFDebugLocLists, + eSectionTypeDWARFDebugLocListsDwo, + m_data_debug_loclists); +} + const DWARFDataExtractor &DWARFContext::getOrLoadMacroData() { return LoadOrGetSection(eSectionTypeDWARFDebugMacro, llvm::None, m_data_debug_macro); @@ -81,7 +92,8 @@ const DWARFDataExtractor &DWARFContext::getOrLoadRangesData() { } const DWARFDataExtractor &DWARFContext::getOrLoadRngListsData() { - return LoadOrGetSection(eSectionTypeDWARFDebugRngLists, llvm::None, + return LoadOrGetSection(eSectionTypeDWARFDebugRngLists, + eSectionTypeDWARFDebugRngListsDwo, m_data_debug_rnglists); } diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFContext.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFContext.h index add042384039..8691001b1b76 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFContext.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFContext.h @@ -34,6 +34,8 @@ private: SectionData m_data_debug_info; SectionData m_data_debug_line; SectionData m_data_debug_line_str; + SectionData m_data_debug_loc; + SectionData m_data_debug_loclists; SectionData m_data_debug_macro; SectionData m_data_debug_ranges; SectionData m_data_debug_rnglists; @@ -41,8 +43,6 @@ private: SectionData m_data_debug_str_offsets; SectionData m_data_debug_types; - bool isDwo() { return m_dwo_section_list != nullptr; } - const DWARFDataExtractor & LoadOrGetSection(lldb::SectionType main_section_type, llvm::Optional<lldb::SectionType> dwo_section_type, @@ -60,6 +60,8 @@ public: const DWARFDataExtractor &getOrLoadDebugInfoData(); const DWARFDataExtractor &getOrLoadLineData(); const DWARFDataExtractor &getOrLoadLineStrData(); + const DWARFDataExtractor &getOrLoadLocData(); + const DWARFDataExtractor &getOrLoadLocListsData(); const DWARFDataExtractor &getOrLoadMacroData(); const DWARFDataExtractor &getOrLoadRangesData(); const DWARFDataExtractor &getOrLoadRngListsData(); @@ -67,6 +69,8 @@ public: const DWARFDataExtractor &getOrLoadStrOffsetsData(); const DWARFDataExtractor &getOrLoadDebugTypesData(); + bool isDwo() { return m_dwo_section_list != nullptr; } + llvm::DWARFContext &GetAsLLVM(); }; } // namespace lldb_private diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.cpp index 5ee0687995a1..c5411a17f274 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.cpp @@ -406,39 +406,6 @@ bool DWARFDIE::IsMethod() const { return false; } -DWARFDIE -DWARFDIE::GetContainingDWOModuleDIE() const { - if (IsValid()) { - DWARFDIE top_module_die; - // Now make sure this DIE is scoped in a DW_TAG_module tag and return true - // if so - for (DWARFDIE parent = GetParent(); parent.IsValid(); - parent = parent.GetParent()) { - const dw_tag_t tag = parent.Tag(); - if (tag == DW_TAG_module) - top_module_die = parent; - else if (tag == DW_TAG_compile_unit || tag == DW_TAG_partial_unit) - break; - } - - return top_module_die; - } - return DWARFDIE(); -} - -lldb::ModuleSP DWARFDIE::GetContainingDWOModule() const { - if (IsValid()) { - DWARFDIE dwo_module_die = GetContainingDWOModuleDIE(); - - if (dwo_module_die) { - const char *module_name = dwo_module_die.GetName(); - if (module_name) - return GetDWARF()->GetDWOModule(lldb_private::ConstString(module_name)); - } - } - return lldb::ModuleSP(); -} - bool DWARFDIE::GetDIENamesAndRanges( const char *&name, const char *&mangled, DWARFRangeList &ranges, int &decl_file, int &decl_line, int &decl_column, int &call_file, diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.h index a779c589611a..87d52eee9dd9 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.h @@ -22,10 +22,6 @@ public: bool IsMethod() const; // Accessors - lldb::ModuleSP GetContainingDWOModule() const; - - DWARFDIE - GetContainingDWOModuleDIE() const; // Accessing information about a DIE const char *GetMangledName() const; diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.h index d1b066ffe80c..056cf33a202f 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.h @@ -16,7 +16,6 @@ #include "DWARFTypeUnit.h" #include "DWARFUnit.h" #include "SymbolFileDWARF.h" -#include "lldb/Core/STLUtils.h" #include "lldb/lldb-private.h" #include "llvm/Support/Error.h" @@ -24,11 +23,6 @@ namespace lldb_private { class DWARFContext; } -typedef std::multimap<const char *, dw_offset_t, CStringCompareFunctionObject> - CStringToDIEMap; -typedef CStringToDIEMap::iterator CStringToDIEMapIter; -typedef CStringToDIEMap::const_iterator CStringToDIEMapConstIter; - class DWARFDebugInfo { public: typedef dw_offset_t (*Callback)(SymbolFileDWARF *dwarf2Data, diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp index 8c0fbeb4b717..320500fe608d 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp @@ -156,6 +156,7 @@ bool DWARFDebugInfoEntry::Extract(const DWARFDataExtractor &data, // signed or unsigned LEB 128 values case DW_FORM_addrx: + case DW_FORM_loclistx: case DW_FORM_rnglistx: case DW_FORM_sdata: case DW_FORM_udata: @@ -200,7 +201,7 @@ bool DWARFDebugInfoEntry::Extract(const DWARFDataExtractor &data, return false; } -static DWARFRangeList GetRangesOrReportError(const DWARFUnit &unit, +static DWARFRangeList GetRangesOrReportError(DWARFUnit &unit, const DWARFDebugInfoEntry &die, const DWARFFormValue &value) { llvm::Expected<DWARFRangeList> expected_ranges = @@ -223,7 +224,7 @@ static DWARFRangeList GetRangesOrReportError(const DWARFUnit &unit, // Gets the valid address ranges for a given DIE by looking for a // DW_AT_low_pc/DW_AT_high_pc pair, DW_AT_entry_pc, or DW_AT_ranges attributes. bool DWARFDebugInfoEntry::GetDIENamesAndRanges( - const DWARFUnit *cu, const char *&name, const char *&mangled, + DWARFUnit *cu, const char *&name, const char *&mangled, DWARFRangeList &ranges, int &decl_file, int &decl_line, int &decl_column, int &call_file, int &call_line, int &call_column, DWARFExpression *frame_base) const { @@ -343,15 +344,15 @@ bool DWARFDebugInfoEntry::GetDIENamesAndRanges( *frame_base = DWARFExpression( module, DataExtractor(data, block_offset, block_length), cu); } else { - DataExtractor data = dwarf.DebugLocData(); + DataExtractor data = cu->GetLocationData(); const dw_offset_t offset = form_value.Unsigned(); if (data.ValidOffset(offset)) { data = DataExtractor(data, offset, data.GetByteSize() - offset); *frame_base = DWARFExpression(module, data, cu); if (lo_pc != LLDB_INVALID_ADDRESS) { assert(lo_pc >= cu->GetBaseAddress()); - frame_base->SetLocationListSlide(lo_pc - - cu->GetBaseAddress()); + frame_base->SetLocationListAddresses(cu->GetBaseAddress(), + lo_pc); } else { set_frame_base_loclist_addr = true; } @@ -379,7 +380,7 @@ bool DWARFDebugInfoEntry::GetDIENamesAndRanges( if (set_frame_base_loclist_addr) { dw_addr_t lowest_range_pc = ranges.GetMinRangeBase(0); assert(lowest_range_pc >= cu->GetBaseAddress()); - frame_base->SetLocationListSlide(lowest_range_pc - cu->GetBaseAddress()); + frame_base->SetLocationListAddresses(cu->GetBaseAddress(), lowest_range_pc); } if (ranges.IsEmpty() || name == nullptr || mangled == nullptr) { @@ -477,8 +478,6 @@ void DWARFDebugInfoEntry::DumpAttribute( s.PutCString("( "); - SymbolFileDWARF &dwarf = cu->GetSymbolFileDWARF(); - // Check to see if we have any special attribute formatters switch (attr) { case DW_AT_stmt_list: @@ -508,7 +507,7 @@ void DWARFDebugInfoEntry::DumpAttribute( // We have a location list offset as the value that is the offset into // the .debug_loc section that describes the value over it's lifetime uint64_t debug_loc_offset = form_value.Unsigned(); - DWARFExpression::PrintDWARFLocationList(s, cu, dwarf.DebugLocData(), + DWARFExpression::PrintDWARFLocationList(s, cu, cu->GetLocationData(), debug_loc_offset); } } break; @@ -646,25 +645,7 @@ dw_offset_t DWARFDebugInfoEntry::GetAttributeValue( } } } - - // If we're a unit DIE, also check the attributes of the dwo unit (if any). - if (GetParent()) - return 0; - SymbolFileDWARFDwo *dwo_symbol_file = cu->GetDwoSymbolFile(); - if (!dwo_symbol_file) - return 0; - - DWARFCompileUnit *dwo_cu = dwo_symbol_file->GetCompileUnit(); - if (!dwo_cu) - return 0; - - DWARFBaseDIE dwo_cu_die = dwo_cu->GetUnitDIEOnly(); - if (!dwo_cu_die.IsValid()) - return 0; - - return dwo_cu_die.GetDIE()->GetAttributeValue( - dwo_cu, attr, form_value, end_attr_offset_ptr, - check_specification_or_abstract_origin); + return 0; } // GetAttributeValueAsString @@ -766,7 +747,7 @@ bool DWARFDebugInfoEntry::GetAttributeAddressRange( } size_t DWARFDebugInfoEntry::GetAttributeAddressRanges( - const DWARFUnit *cu, DWARFRangeList &ranges, bool check_hi_lo_pc, + DWARFUnit *cu, DWARFRangeList &ranges, bool check_hi_lo_pc, bool check_specification_or_abstract_origin) const { ranges.Clear(); @@ -1012,8 +993,7 @@ DWARFDebugInfoEntry::GetQualifiedName(DWARFUnit *cu, return storage.c_str(); } -bool DWARFDebugInfoEntry::LookupAddress(const dw_addr_t address, - const DWARFUnit *cu, +bool DWARFDebugInfoEntry::LookupAddress(const dw_addr_t address, DWARFUnit *cu, DWARFDebugInfoEntry **function_die, DWARFDebugInfoEntry **block_die) { bool found_address = false; diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h index 25c885608d85..f35af6e7d498 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h @@ -23,6 +23,10 @@ class DWARFDeclContext; #define DIE_SIBLING_IDX_BITSIZE 31 +/// DWARFDebugInfoEntry objects assume that they are living in one big +/// vector and do pointer arithmetic on their this pointers. Don't +/// pass them by value. Due to the way they are constructed in a +/// std::vector, we cannot delete the copy constructor. class DWARFDebugInfoEntry { public: typedef std::vector<DWARFDebugInfoEntry> collection; @@ -46,7 +50,7 @@ public: bool Extract(const lldb_private::DWARFDataExtractor &data, const DWARFUnit *cu, lldb::offset_t *offset_ptr); - bool LookupAddress(const dw_addr_t address, const DWARFUnit *cu, + bool LookupAddress(const dw_addr_t address, DWARFUnit *cu, DWARFDebugInfoEntry **function_die, DWARFDebugInfoEntry **block_die); @@ -87,7 +91,7 @@ public: bool check_specification_or_abstract_origin = false) const; size_t GetAttributeAddressRanges( - const DWARFUnit *cu, DWARFRangeList &ranges, bool check_hi_lo_pc, + DWARFUnit *cu, DWARFRangeList &ranges, bool check_hi_lo_pc, bool check_specification_or_abstract_origin = false) const; const char *GetName(const DWARFUnit *cu) const; @@ -112,7 +116,7 @@ public: dw_attr_t attr, DWARFFormValue &form_value); bool GetDIENamesAndRanges( - const DWARFUnit *cu, const char *&name, const char *&mangled, + DWARFUnit *cu, const char *&name, const char *&mangled, DWARFRangeList &rangeList, int &decl_file, int &decl_line, int &decl_column, int &call_file, int &call_line, int &call_column, lldb_private::DWARFExpression *frame_base = nullptr) const; diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.cpp index 0b08fa09f906..6c074002cb20 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.cpp @@ -95,13 +95,15 @@ void DWARFDebugRanges::Dump(Stream &s, } else if (begin == LLDB_INVALID_ADDRESS) { // A base address selection entry base_addr = end; - s.Address(base_addr, sizeof(dw_addr_t), " Base address = "); + DumpAddress(s.AsRawOstream(), base_addr, sizeof(dw_addr_t), + " Base address = "); } else { // Convert from offset to an address dw_addr_t begin_addr = begin + base_addr; dw_addr_t end_addr = end + base_addr; - s.AddressRange(begin_addr, end_addr, sizeof(dw_addr_t), nullptr); + DumpAddressRange(s.AsRawOstream(), begin_addr, end_addr, + sizeof(dw_addr_t), nullptr); } } } @@ -122,164 +124,3 @@ bool DWARFDebugRanges::FindRanges(const DWARFUnit *cu, } return false; } - -bool DWARFDebugRngLists::ExtractRangeList( - const DWARFDataExtractor &data, uint8_t addrSize, - lldb::offset_t *offset_ptr, std::vector<RngListEntry> &rangeList) { - rangeList.clear(); - - bool error = false; - while (!error) { - switch (data.GetU8(offset_ptr)) { - case DW_RLE_end_of_list: - return true; - - case DW_RLE_start_length: { - dw_addr_t begin = data.GetMaxU64(offset_ptr, addrSize); - dw_addr_t len = data.GetULEB128(offset_ptr); - rangeList.push_back({DW_RLE_start_length, begin, len}); - break; - } - - case DW_RLE_start_end: { - dw_addr_t begin = data.GetMaxU64(offset_ptr, addrSize); - dw_addr_t end = data.GetMaxU64(offset_ptr, addrSize); - rangeList.push_back({DW_RLE_start_end, begin, end}); - break; - } - - case DW_RLE_base_address: { - dw_addr_t base = data.GetMaxU64(offset_ptr, addrSize); - rangeList.push_back({DW_RLE_base_address, base, 0}); - break; - } - - case DW_RLE_offset_pair: { - dw_addr_t begin = data.GetULEB128(offset_ptr); - dw_addr_t end = data.GetULEB128(offset_ptr); - rangeList.push_back({DW_RLE_offset_pair, begin, end}); - break; - } - - case DW_RLE_base_addressx: { - dw_addr_t base = data.GetULEB128(offset_ptr); - rangeList.push_back({DW_RLE_base_addressx, base, 0}); - break; - } - - case DW_RLE_startx_endx: { - dw_addr_t start = data.GetULEB128(offset_ptr); - dw_addr_t end = data.GetULEB128(offset_ptr); - rangeList.push_back({DW_RLE_startx_endx, start, end}); - break; - } - - case DW_RLE_startx_length: { - dw_addr_t start = data.GetULEB128(offset_ptr); - dw_addr_t length = data.GetULEB128(offset_ptr); - rangeList.push_back({DW_RLE_startx_length, start, length}); - break; - } - - default: - lldbassert(0 && "unknown range list entry encoding"); - error = true; - } - } - - return false; -} - -static uint64_t ReadAddressFromDebugAddrSection(const DWARFUnit *cu, - uint32_t index) { - uint32_t index_size = cu->GetAddressByteSize(); - dw_offset_t addr_base = cu->GetAddrBase(); - lldb::offset_t offset = addr_base + index * index_size; - return cu->GetSymbolFileDWARF() - .GetDWARFContext() - .getOrLoadAddrData() - .GetMaxU64(&offset, index_size); -} - -bool DWARFDebugRngLists::FindRanges(const DWARFUnit *cu, - dw_offset_t debug_ranges_offset, - DWARFRangeList &range_list) const { - range_list.Clear(); - dw_addr_t debug_ranges_address = cu->GetRangesBase() + debug_ranges_offset; - auto pos = m_range_map.find(debug_ranges_address); - if (pos != m_range_map.end()) { - dw_addr_t BaseAddr = cu->GetBaseAddress(); - for (const RngListEntry &E : pos->second) { - switch (E.encoding) { - case DW_RLE_start_length: - range_list.Append(DWARFRangeList::Entry(E.value0, E.value1)); - break; - case DW_RLE_base_address: - BaseAddr = E.value0; - break; - case DW_RLE_start_end: - range_list.Append(DWARFRangeList::Entry(E.value0, E.value1 - E.value0)); - break; - case DW_RLE_offset_pair: - range_list.Append( - DWARFRangeList::Entry(BaseAddr + E.value0, E.value1 - E.value0)); - break; - case DW_RLE_base_addressx: { - BaseAddr = ReadAddressFromDebugAddrSection(cu, E.value0); - break; - } - case DW_RLE_startx_endx: { - dw_addr_t start = ReadAddressFromDebugAddrSection(cu, E.value0); - dw_addr_t end = ReadAddressFromDebugAddrSection(cu, E.value1); - range_list.Append(DWARFRangeList::Entry(start, end - start)); - break; - } - case DW_RLE_startx_length: { - dw_addr_t start = ReadAddressFromDebugAddrSection(cu, E.value0); - range_list.Append(DWARFRangeList::Entry(start, E.value1)); - break; - } - default: - llvm_unreachable("unexpected encoding"); - } - } - return true; - } - return false; -} - -void DWARFDebugRngLists::Extract(DWARFContext &context) { - const DWARFDataExtractor &data = context.getOrLoadRngListsData(); - lldb::offset_t offset = 0; - - uint64_t length = data.GetU32(&offset); - // FIXME: Handle DWARF64. - lldb::offset_t end = offset + length; - - // Check version. - if (data.GetU16(&offset) < 5) - return; - - uint8_t addrSize = data.GetU8(&offset); - - // We do not support non-zero segment selector size. - if (data.GetU8(&offset) != 0) { - lldbassert(0 && "not implemented"); - return; - } - - uint32_t offsetsAmount = data.GetU32(&offset); - for (uint32_t i = 0; i < offsetsAmount; ++i) - Offsets.push_back(data.GetMaxU64(&offset, 4)); - - lldb::offset_t listOffset = offset; - std::vector<RngListEntry> rangeList; - while (offset < end && ExtractRangeList(data, addrSize, &offset, rangeList)) { - m_range_map[listOffset] = rangeList; - listOffset = offset; - } -} - -uint64_t DWARFDebugRngLists::GetOffset(size_t Index) const { - return Offsets[Index]; -} diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.h index c398259056b3..1888a7760f27 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.h @@ -17,22 +17,13 @@ namespace lldb_private { class DWARFContext; } -class DWARFDebugRangesBase { -public: - virtual ~DWARFDebugRangesBase(){}; - - virtual void Extract(lldb_private::DWARFContext &context) = 0; - virtual bool FindRanges(const DWARFUnit *cu, dw_offset_t debug_ranges_offset, - DWARFRangeList &range_list) const = 0; -}; - -class DWARFDebugRanges final : public DWARFDebugRangesBase { +class DWARFDebugRanges { public: DWARFDebugRanges(); - void Extract(lldb_private::DWARFContext &context) override; + void Extract(lldb_private::DWARFContext &context); bool FindRanges(const DWARFUnit *cu, dw_offset_t debug_ranges_offset, - DWARFRangeList &range_list) const override; + DWARFRangeList &range_list) const; static void Dump(lldb_private::Stream &s, const lldb_private::DWARFDataExtractor &debug_ranges_data, @@ -48,27 +39,4 @@ protected: range_map m_range_map; }; -// DWARF v5 .debug_rnglists section. -class DWARFDebugRngLists final : public DWARFDebugRangesBase { - struct RngListEntry { - uint8_t encoding; - uint64_t value0; - uint64_t value1; - }; - -public: - void Extract(lldb_private::DWARFContext &context) override; - bool FindRanges(const DWARFUnit *cu, dw_offset_t debug_ranges_offset, - DWARFRangeList &range_list) const override; - uint64_t GetOffset(size_t Index) const; - -protected: - bool ExtractRangeList(const lldb_private::DWARFDataExtractor &data, - uint8_t addrSize, lldb::offset_t *offset_ptr, - std::vector<RngListEntry> &list); - - std::vector<uint64_t> Offsets; - std::map<dw_offset_t, std::vector<RngListEntry>> m_range_map; -}; - #endif // SymbolFileDWARF_DWARFDebugRanges_h_ diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDeclContext.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDeclContext.h index 6501ac27f27d..348b33464a54 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDeclContext.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDeclContext.h @@ -63,7 +63,7 @@ public: const char *GetQualifiedName() const; - // Same as GetQaulifiedName, but the life time of the returned string will + // Same as GetQualifiedName, but the life time of the returned string will // be that of the LLDB session. lldb_private::ConstString GetQualifiedNameAsConstString() const { return lldb_private::ConstString(GetQualifiedName()); diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp index 046ae67446af..f660cc32b3f8 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp @@ -107,6 +107,7 @@ bool DWARFFormValue::ExtractValue(const DWARFDataExtractor &data, m_value.value.uval = data.GetU64(offset_ptr); break; case DW_FORM_addrx: + case DW_FORM_loclistx: case DW_FORM_rnglistx: case DW_FORM_strx: case DW_FORM_udata: @@ -305,6 +306,7 @@ bool DWARFFormValue::SkipValue(dw_form_t form, // signed or unsigned LEB 128 values case DW_FORM_addrx: + case DW_FORM_loclistx: case DW_FORM_rnglistx: case DW_FORM_sdata: case DW_FORM_udata: @@ -333,7 +335,7 @@ void DWARFFormValue::Dump(Stream &s) const { switch (m_form) { case DW_FORM_addr: - s.Address(uvalue, sizeof(uint64_t)); + DumpAddress(s.AsRawOstream(), uvalue, sizeof(uint64_t)); break; case DW_FORM_flag: case DW_FORM_data1: @@ -409,10 +411,11 @@ void DWARFFormValue::Dump(Stream &s) const { assert(m_unit); // Unit must be valid for DW_FORM_ref_addr objects or we // will get this wrong if (m_unit->GetVersion() <= 2) - s.Address(uvalue, sizeof(uint64_t) * 2); + DumpAddress(s.AsRawOstream(), uvalue, sizeof(uint64_t) * 2); else - s.Address(uvalue, 4 * 2); // 4 for DWARF32, 8 for DWARF64, but we don't - // support DWARF64 yet + DumpAddress(s.AsRawOstream(), uvalue, + 4 * 2); // 4 for DWARF32, 8 for DWARF64, but we don't + // support DWARF64 yet break; } case DW_FORM_ref1: @@ -599,105 +602,11 @@ bool DWARFFormValue::IsDataForm(const dw_form_t form) { return false; } -int DWARFFormValue::Compare(const DWARFFormValue &a_value, - const DWARFFormValue &b_value) { - dw_form_t a_form = a_value.Form(); - dw_form_t b_form = b_value.Form(); - if (a_form < b_form) - return -1; - if (a_form > b_form) - return 1; - switch (a_form) { - case DW_FORM_addr: - case DW_FORM_addrx: - case DW_FORM_flag: - case DW_FORM_data1: - case DW_FORM_data2: - case DW_FORM_data4: - case DW_FORM_data8: - case DW_FORM_udata: - case DW_FORM_ref_addr: - case DW_FORM_sec_offset: - case DW_FORM_flag_present: - case DW_FORM_ref_sig8: - case DW_FORM_GNU_addr_index: { - uint64_t a = a_value.Unsigned(); - uint64_t b = b_value.Unsigned(); - if (a < b) - return -1; - if (a > b) - return 1; - return 0; - } - - case DW_FORM_sdata: { - int64_t a = a_value.Signed(); - int64_t b = b_value.Signed(); - if (a < b) - return -1; - if (a > b) - return 1; - return 0; - } - - case DW_FORM_string: - case DW_FORM_strp: - case DW_FORM_GNU_str_index: { - const char *a_string = a_value.AsCString(); - const char *b_string = b_value.AsCString(); - if (a_string == b_string) - return 0; - else if (a_string && b_string) - return strcmp(a_string, b_string); - else if (a_string == nullptr) - return -1; // A string is NULL, and B is valid - else - return 1; // A string valid, and B is NULL - } - - case DW_FORM_block: - case DW_FORM_block1: - case DW_FORM_block2: - case DW_FORM_block4: - case DW_FORM_exprloc: { - uint64_t a_len = a_value.Unsigned(); - uint64_t b_len = b_value.Unsigned(); - if (a_len < b_len) - return -1; - if (a_len > b_len) - return 1; - // The block lengths are the same - return memcmp(a_value.BlockData(), b_value.BlockData(), a_value.Unsigned()); - } break; - - case DW_FORM_ref1: - case DW_FORM_ref2: - case DW_FORM_ref4: - case DW_FORM_ref8: - case DW_FORM_ref_udata: { - uint64_t a = a_value.m_value.value.uval; - uint64_t b = b_value.m_value.value.uval; - if (a < b) - return -1; - if (a > b) - return 1; - return 0; - } - - case DW_FORM_indirect: - llvm_unreachable( - "This shouldn't happen after the form has been extracted..."); - - default: - llvm_unreachable("Unhandled DW_FORM"); - } - return -1; -} - bool DWARFFormValue::FormIsSupported(dw_form_t form) { switch (form) { case DW_FORM_addr: case DW_FORM_addrx: + case DW_FORM_loclistx: case DW_FORM_rnglistx: case DW_FORM_block2: case DW_FORM_block4: diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFTypeUnit.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFTypeUnit.h index 6ff73ecd8efa..8967509c081a 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFTypeUnit.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFTypeUnit.h @@ -28,8 +28,8 @@ private: DWARFTypeUnit(SymbolFileDWARF &dwarf, lldb::user_id_t uid, const DWARFUnitHeader &header, const DWARFAbbreviationDeclarationSet &abbrevs, - DIERef::Section section) - : DWARFUnit(dwarf, uid, header, abbrevs, section) {} + DIERef::Section section, bool is_dwo) + : DWARFUnit(dwarf, uid, header, abbrevs, section, is_dwo) {} friend class DWARFUnit; }; diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp index 9964cf4b893c..22e3e40dac93 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp @@ -32,9 +32,9 @@ extern int g_verbose; DWARFUnit::DWARFUnit(SymbolFileDWARF &dwarf, lldb::user_id_t uid, const DWARFUnitHeader &header, const DWARFAbbreviationDeclarationSet &abbrevs, - DIERef::Section section) + DIERef::Section section, bool is_dwo) : UserID(uid), m_dwarf(dwarf), m_header(header), m_abbrevs(&abbrevs), - m_cancel_scopes(false), m_section(section) {} + m_cancel_scopes(false), m_section(section), m_is_dwo(is_dwo) {} DWARFUnit::~DWARFUnit() = default; @@ -287,15 +287,27 @@ void DWARFUnit::AddUnitDIE(const DWARFDebugInfoEntry &cu_die) { DWARFAttributes attributes; size_t num_attributes = cu_die.GetAttributes(this, attributes); + + // Extract DW_AT_addr_base first, as other attributes may need it. + for (size_t i = 0; i < num_attributes; ++i) { + if (attributes.AttributeAtIndex(i) != DW_AT_addr_base) + continue; + DWARFFormValue form_value; + if (attributes.ExtractFormValueAtIndex(i, form_value)) { + addr_base = form_value.Unsigned(); + SetAddrBase(*addr_base); + break; + } + } + for (size_t i = 0; i < num_attributes; ++i) { dw_attr_t attr = attributes.AttributeAtIndex(i); DWARFFormValue form_value; if (!attributes.ExtractFormValueAtIndex(i, form_value)) continue; switch (attr) { - case DW_AT_addr_base: - addr_base = form_value.Unsigned(); - SetAddrBase(*addr_base); + case DW_AT_loclists_base: + SetLoclistsBase(form_value.Unsigned()); break; case DW_AT_rnglists_base: ranges_base = form_value.Unsigned(); @@ -324,6 +336,9 @@ void DWARFUnit::AddUnitDIE(const DWARFDebugInfoEntry &cu_die) { } } + if (m_is_dwo) + return; + std::unique_ptr<SymbolFileDWARFDwo> dwo_symbol_file = m_dwarf.GetDwoSymbolFileForCompileUnit(*this, cu_die); if (!dwo_symbol_file) @@ -358,10 +373,18 @@ void DWARFUnit::AddUnitDIE(const DWARFDebugInfoEntry &cu_die) { else if (gnu_addr_base) dwo_cu->SetAddrBase(*gnu_addr_base); - if (ranges_base) - dwo_cu->SetRangesBase(*ranges_base); - else if (gnu_ranges_base) + if (GetVersion() <= 4 && gnu_ranges_base) dwo_cu->SetRangesBase(*gnu_ranges_base); + else if (m_dwo_symbol_file->GetDWARFContext() + .getOrLoadRngListsData() + .GetByteSize() > 0) + dwo_cu->SetRangesBase(llvm::DWARFListTableHeader::getHeaderSize(DWARF32)); + + if (GetVersion() >= 5 && m_dwo_symbol_file->GetDWARFContext() + .getOrLoadLocListsData() + .GetByteSize() > 0) + dwo_cu->SetLoclistsBase(llvm::DWARFListTableHeader::getHeaderSize(DWARF32)); + dwo_cu->SetBaseAddress(GetBaseAddress()); for (size_t i = 0; i < m_dwo_symbol_file->DebugInfo()->GetNumUnits(); ++i) { DWARFUnit *unit = m_dwo_symbol_file->DebugInfo()->GetUnitAtIndex(i); @@ -380,24 +403,6 @@ DWARFDIE DWARFUnit::LookupAddress(const dw_addr_t address) { return DWARFDIE(); } -size_t DWARFUnit::AppendDIEsWithTag(const dw_tag_t tag, - std::vector<DWARFDIE> &dies, - uint32_t depth) const { - size_t old_size = dies.size(); - { - llvm::sys::ScopedReader lock(m_die_array_mutex); - DWARFDebugInfoEntry::const_iterator pos; - DWARFDebugInfoEntry::const_iterator end = m_die_array.end(); - for (pos = m_die_array.begin(); pos != end; ++pos) { - if (pos->Tag() == tag) - dies.emplace_back(this, &(*pos)); - } - } - - // Return the number of DIEs added to the collection - return dies.size() - old_size; -} - size_t DWARFUnit::GetDebugInfoSize() const { return GetLengthByteSize() + GetLength() - GetHeaderByteSize(); } @@ -417,8 +422,79 @@ dw_offset_t DWARFUnit::GetLineTableOffset() { void DWARFUnit::SetAddrBase(dw_addr_t addr_base) { m_addr_base = addr_base; } +// Parse the rangelist table header, including the optional array of offsets +// following it (DWARF v5 and later). +template <typename ListTableType> +static llvm::Expected<ListTableType> +ParseListTableHeader(const llvm::DWARFDataExtractor &data, uint64_t offset, + DwarfFormat format) { + // We are expected to be called with Offset 0 or pointing just past the table + // header. Correct Offset in the latter case so that it points to the start + // of the header. + if (offset > 0) { + uint64_t HeaderSize = llvm::DWARFListTableHeader::getHeaderSize(format); + if (offset < HeaderSize) + return llvm::createStringError(errc::invalid_argument, + "did not detect a valid" + " list table with base = 0x%" PRIx64 "\n", + offset); + offset -= HeaderSize; + } + ListTableType Table; + if (llvm::Error E = Table.extractHeaderAndOffsets(data, &offset)) + return std::move(E); + return Table; +} + +void DWARFUnit::SetLoclistsBase(dw_addr_t loclists_base) { + m_loclists_base = loclists_base; + + uint64_t header_size = llvm::DWARFListTableHeader::getHeaderSize(DWARF32); + if (loclists_base < header_size) + return; + + m_loclist_table_header.emplace(".debug_loclists", "locations"); + uint64_t offset = loclists_base - header_size; + if (llvm::Error E = m_loclist_table_header->extract( + m_dwarf.GetDWARFContext().getOrLoadLocListsData().GetAsLLVM(), + &offset)) { + GetSymbolFileDWARF().GetObjectFile()->GetModule()->ReportError( + "Failed to extract location list table at offset 0x%" PRIx64 ": %s", + loclists_base, toString(std::move(E)).c_str()); + } +} + +std::unique_ptr<llvm::DWARFLocationTable> +DWARFUnit::GetLocationTable(const DataExtractor &data) const { + llvm::DWARFDataExtractor llvm_data( + toStringRef(data.GetData()), + data.GetByteOrder() == lldb::eByteOrderLittle, data.GetAddressByteSize()); + + if (m_is_dwo || GetVersion() >= 5) + return std::make_unique<llvm::DWARFDebugLoclists>(llvm_data, GetVersion()); + return std::make_unique<llvm::DWARFDebugLoc>(llvm_data); +} + +const DWARFDataExtractor &DWARFUnit::GetLocationData() const { + DWARFContext &Ctx = GetSymbolFileDWARF().GetDWARFContext(); + return GetVersion() >= 5 ? Ctx.getOrLoadLocListsData() + : Ctx.getOrLoadLocData(); +} + void DWARFUnit::SetRangesBase(dw_addr_t ranges_base) { m_ranges_base = ranges_base; + + if (GetVersion() < 5) + return; + + if (auto table_or_error = ParseListTableHeader<llvm::DWARFDebugRnglistTable>( + m_dwarf.GetDWARFContext().getOrLoadRngListsData().GetAsLLVM(), + ranges_base, DWARF32)) + m_rnglist_table = std::move(table_or_error.get()); + else + GetSymbolFileDWARF().GetObjectFile()->GetModule()->ReportError( + "Failed to extract range list table at offset 0x%" PRIx64 ": %s", + ranges_base, toString(table_or_error.takeError()).c_str()); } void DWARFUnit::SetStrOffsetsBase(dw_offset_t str_offsets_base) { @@ -646,6 +722,8 @@ FileSpec DWARFUnit::GetFile(size_t file_idx) { // Remove the host part if present. static llvm::StringRef removeHostnameFromPathname(llvm::StringRef path_from_dwarf) { + if (!path_from_dwarf.contains(':')) + return path_from_dwarf; llvm::StringRef host, path; std::tie(host, path) = path_from_dwarf.split(':'); @@ -715,7 +793,8 @@ void DWARFUnit::ComputeAbsolutePath() { m_file_spec->MakeAbsolute(GetCompilationDirectory()); } -SymbolFileDWARFDwo *DWARFUnit::GetDwoSymbolFile() const { +SymbolFileDWARFDwo *DWARFUnit::GetDwoSymbolFile() { + ExtractUnitDIEIfNeeded(); return m_dwo_symbol_file.get(); } @@ -816,11 +895,12 @@ DWARFUnit::extract(SymbolFileDWARF &dwarf, user_id_t uid, return llvm::make_error<llvm::object::GenericBinaryError>( "No abbrev exists at the specified offset."); + bool is_dwo = dwarf.GetDWARFContext().isDwo(); if (expected_header->IsTypeUnit()) - return DWARFUnitSP( - new DWARFTypeUnit(dwarf, uid, *expected_header, *abbrevs, section)); - return DWARFUnitSP( - new DWARFCompileUnit(dwarf, uid, *expected_header, *abbrevs, section)); + return DWARFUnitSP(new DWARFTypeUnit(dwarf, uid, *expected_header, *abbrevs, + section, is_dwo)); + return DWARFUnitSP(new DWARFCompileUnit(dwarf, uid, *expected_header, + *abbrevs, section, is_dwo)); } const lldb_private::DWARFDataExtractor &DWARFUnit::GetData() const { @@ -845,30 +925,56 @@ uint32_t DWARFUnit::GetHeaderByteSize() const { } llvm::Expected<DWARFRangeList> -DWARFUnit::FindRnglistFromOffset(dw_offset_t offset) const { - const DWARFDebugRangesBase *debug_ranges; - llvm::StringRef section; +DWARFUnit::FindRnglistFromOffset(dw_offset_t offset) { if (GetVersion() <= 4) { - debug_ranges = m_dwarf.GetDebugRanges(); - section = "debug_ranges"; - } else { - debug_ranges = m_dwarf.GetDebugRngLists(); - section = "debug_rnglists"; + const DWARFDebugRanges *debug_ranges = m_dwarf.GetDebugRanges(); + if (!debug_ranges) + return llvm::make_error<llvm::object::GenericBinaryError>( + "No debug_ranges section"); + DWARFRangeList ranges; + debug_ranges->FindRanges(this, offset, ranges); + return ranges; } - if (!debug_ranges) - return llvm::make_error<llvm::object::GenericBinaryError>("No " + section + - " section"); + + if (!m_rnglist_table) + return llvm::createStringError(errc::invalid_argument, + "missing or invalid range list table"); + + auto range_list_or_error = m_rnglist_table->findList( + m_dwarf.GetDWARFContext().getOrLoadRngListsData().GetAsLLVM(), offset); + if (!range_list_or_error) + return range_list_or_error.takeError(); + + llvm::Expected<llvm::DWARFAddressRangesVector> llvm_ranges = + range_list_or_error->getAbsoluteRanges( + llvm::object::SectionedAddress{GetBaseAddress()}, + [&](uint32_t index) { + uint32_t index_size = GetAddressByteSize(); + dw_offset_t addr_base = GetAddrBase(); + lldb::offset_t offset = addr_base + index * index_size; + return llvm::object::SectionedAddress{ + m_dwarf.GetDWARFContext().getOrLoadAddrData().GetMaxU64( + &offset, index_size)}; + }); + if (!llvm_ranges) + return llvm_ranges.takeError(); DWARFRangeList ranges; - debug_ranges->FindRanges(this, offset, ranges); + for (const llvm::DWARFAddressRange &llvm_range : *llvm_ranges) { + ranges.Append(DWARFRangeList::Entry(llvm_range.LowPC, + llvm_range.HighPC - llvm_range.LowPC)); + } return ranges; } llvm::Expected<DWARFRangeList> -DWARFUnit::FindRnglistFromIndex(uint32_t index) const { - const DWARFDebugRngLists *debug_rnglists = m_dwarf.GetDebugRngLists(); - if (!debug_rnglists) - return llvm::make_error<llvm::object::GenericBinaryError>( - "No debug_rnglists section"); - return FindRnglistFromOffset(debug_rnglists->GetOffset(index)); +DWARFUnit::FindRnglistFromIndex(uint32_t index) { + if (llvm::Optional<uint64_t> offset = GetRnglistOffset(index)) + return FindRnglistFromOffset(*offset); + if (m_rnglist_table) + return llvm::createStringError(errc::invalid_argument, + "invalid range list table index %d", index); + + return llvm::createStringError(errc::invalid_argument, + "missing or invalid range list table"); } diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h index 87e0de283de4..217f9bb89ace 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h @@ -95,8 +95,6 @@ public: ScopedExtractDIEs ExtractDIEsScoped(); DWARFDIE LookupAddress(const dw_addr_t address); - size_t AppendDIEsWithTag(const dw_tag_t tag, std::vector<DWARFDIE> &dies, - uint32_t depth = UINT32_MAX) const; bool Verify(lldb_private::Stream *s) const; virtual void Dump(lldb_private::Stream *s) const = 0; /// Get the data that contains the DIE information for this unit. @@ -147,6 +145,7 @@ public: dw_addr_t GetRangesBase() const { return m_ranges_base; } dw_addr_t GetStrOffsetsBase() const { return m_str_offsets_base; } void SetAddrBase(dw_addr_t addr_base); + void SetLoclistsBase(dw_addr_t loclists_base); void SetRangesBase(dw_addr_t ranges_base); void SetStrOffsetsBase(dw_offset_t str_offsets_base); virtual void BuildAddressRangeTable(DWARFDebugAranges *debug_aranges) = 0; @@ -202,7 +201,7 @@ public: lldb_private::FileSpec GetFile(size_t file_idx); lldb_private::FileSpec::Style GetPathStyle(); - SymbolFileDWARFDwo *GetDwoSymbolFile() const; + SymbolFileDWARFDwo *GetDwoSymbolFile(); die_iterator_range dies() { ExtractDIEsIfNeeded(); @@ -216,18 +215,46 @@ public: /// Return a list of address ranges resulting from a (possibly encoded) /// range list starting at a given offset in the appropriate ranges section. - llvm::Expected<DWARFRangeList> FindRnglistFromOffset(dw_offset_t offset) const; + llvm::Expected<DWARFRangeList> FindRnglistFromOffset(dw_offset_t offset); /// Return a list of address ranges retrieved from an encoded range /// list whose offset is found via a table lookup given an index (DWARF v5 /// and later). - llvm::Expected<DWARFRangeList> FindRnglistFromIndex(uint32_t index) const; + llvm::Expected<DWARFRangeList> FindRnglistFromIndex(uint32_t index); + + /// Return a rangelist's offset based on an index. The index designates + /// an entry in the rangelist table's offset array and is supplied by + /// DW_FORM_rnglistx. + llvm::Optional<uint64_t> GetRnglistOffset(uint32_t Index) const { + if (!m_rnglist_table) + return llvm::None; + if (llvm::Optional<uint64_t> off = m_rnglist_table->getOffsetEntry(Index)) + return *off + m_ranges_base; + return llvm::None; + } + + llvm::Optional<uint64_t> GetLoclistOffset(uint32_t Index) { + if (!m_loclist_table_header) + return llvm::None; + + llvm::Optional<uint64_t> Offset = m_loclist_table_header->getOffsetEntry(Index); + if (!Offset) + return llvm::None; + return *Offset + m_loclists_base; + } + + /// Return the location table for parsing the given location list data. The + /// format is chosen according to the unit type. Never returns null. + std::unique_ptr<llvm::DWARFLocationTable> + GetLocationTable(const lldb_private::DataExtractor &data) const; + + const lldb_private::DWARFDataExtractor &GetLocationData() const; protected: DWARFUnit(SymbolFileDWARF &dwarf, lldb::user_id_t uid, const DWARFUnitHeader &header, const DWARFAbbreviationDeclarationSet &abbrevs, - DIERef::Section section); + DIERef::Section section, bool is_dwo); llvm::Error ExtractHeader(SymbolFileDWARF &dwarf, const lldb_private::DWARFDataExtractor &data, @@ -281,14 +308,20 @@ protected: lldb_private::LazyBool m_is_optimized = lldb_private::eLazyBoolCalculate; llvm::Optional<lldb_private::FileSpec> m_comp_dir; llvm::Optional<lldb_private::FileSpec> m_file_spec; - dw_addr_t m_addr_base = 0; // Value of DW_AT_addr_base - dw_addr_t m_ranges_base = 0; // Value of DW_AT_ranges_base + dw_addr_t m_addr_base = 0; ///< Value of DW_AT_addr_base. + dw_addr_t m_loclists_base = 0; ///< Value of DW_AT_loclists_base. + dw_addr_t m_ranges_base = 0; ///< Value of DW_AT_rnglists_base. /// Value of DW_AT_stmt_list. dw_offset_t m_line_table_offset = DW_INVALID_OFFSET; dw_offset_t m_str_offsets_base = 0; // Value of DW_AT_str_offsets_base. + + llvm::Optional<llvm::DWARFDebugRnglistTable> m_rnglist_table; + llvm::Optional<llvm::DWARFListTableHeader> m_loclist_table_header; + const DIERef::Section m_section; + bool m_is_dwo; private: void ParseProducerInfo(); diff --git a/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp b/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp index aff8b5d8c15f..1e5927bd14f0 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp @@ -401,8 +401,6 @@ void ManualDWARFIndex::GetFunctions(ConstString name, SymbolFileDWARF &dwarf, if (name_type_mask & eFunctionNameTypeFull) { DIEArray offsets; - m_set.function_basenames.Find(name, offsets); - m_set.function_methods.Find(name, offsets); m_set.function_fullnames.Find(name, offsets); for (const DIERef &die_ref: offsets) { DWARFDIE die = dwarf.GetDIE(die_ref); diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp index c982d59c2830..d45a8b56efe4 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp @@ -94,6 +94,8 @@ using namespace lldb; using namespace lldb_private; +char SymbolFileDWARF::ID; + // static inline bool // child_requires_parent_class_union_or_struct_to_be_completed (dw_tag_t tag) //{ @@ -179,36 +181,46 @@ ParseLLVMLineTable(lldb_private::DWARFContext &context, return *line_table; } -static FileSpecList ParseSupportFilesFromPrologue( - const lldb::ModuleSP &module, - const llvm::DWARFDebugLine::Prologue &prologue, FileSpec::Style style, - llvm::StringRef compile_dir = {}, FileSpec first_file = {}) { +static llvm::Optional<std::string> +GetFileByIndex(const llvm::DWARFDebugLine::Prologue &prologue, size_t idx, + llvm::StringRef compile_dir, FileSpec::Style style) { + // Try to get an absolute path first. + std::string abs_path; + auto absolute = llvm::DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath; + if (prologue.getFileNameByIndex(idx, compile_dir, absolute, abs_path, style)) + return std::move(abs_path); + + // Otherwise ask for a relative path. + std::string rel_path; + auto relative = llvm::DILineInfoSpecifier::FileLineInfoKind::Default; + if (!prologue.getFileNameByIndex(idx, compile_dir, relative, rel_path, style)) + return {}; + return std::move(rel_path); +} + +static FileSpecList +ParseSupportFilesFromPrologue(const lldb::ModuleSP &module, + const llvm::DWARFDebugLine::Prologue &prologue, + FileSpec::Style style, + llvm::StringRef compile_dir = {}) { FileSpecList support_files; - support_files.Append(first_file); + size_t first_file = 0; + if (prologue.getVersion() <= 4) { + // File index 0 is not valid before DWARF v5. Add a dummy entry to ensure + // support file list indices match those we get from the debug info and line + // tables. + support_files.Append(FileSpec()); + first_file = 1; + } const size_t number_of_files = prologue.FileNames.size(); - for (size_t idx = 1; idx <= number_of_files; ++idx) { - std::string original_file; - if (!prologue.getFileNameByIndex( - idx, compile_dir, - llvm::DILineInfoSpecifier::FileLineInfoKind::Default, original_file, - style)) { - // Always add an entry so the indexes remain correct. - support_files.EmplaceBack(); - continue; - } - + for (size_t idx = first_file; idx <= number_of_files; ++idx) { std::string remapped_file; - if (!prologue.getFileNameByIndex( - idx, compile_dir, - llvm::DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath, - remapped_file, style)) { - // Always add an entry so the indexes remain correct. - support_files.EmplaceBack(original_file, style); - continue; - } + if (auto file_path = GetFileByIndex(prologue, idx, compile_dir, style)) + if (!module->RemapSourceFile(llvm::StringRef(*file_path), remapped_file)) + remapped_file = std::move(*file_path); - module->RemapSourceFile(llvm::StringRef(original_file), remapped_file); + // Unconditionally add an entry, so the indices match up. support_files.EmplaceBack(remapped_file, style); } @@ -585,22 +597,6 @@ void SymbolFileDWARF::LoadSectionData(lldb::SectionType sect_type, m_objfile_sp->ReadSectionData(section_sp.get(), data); } -const DWARFDataExtractor &SymbolFileDWARF::DebugLocData() { - const DWARFDataExtractor &debugLocData = get_debug_loc_data(); - if (debugLocData.GetByteSize() > 0) - return debugLocData; - return get_debug_loclists_data(); -} - -const DWARFDataExtractor &SymbolFileDWARF::get_debug_loc_data() { - return GetCachedSectionData(eSectionTypeDWARFDebugLoc, m_data_debug_loc); -} - -const DWARFDataExtractor &SymbolFileDWARF::get_debug_loclists_data() { - return GetCachedSectionData(eSectionTypeDWARFDebugLocLists, - m_data_debug_loclists); -} - DWARFDebugAbbrev *SymbolFileDWARF::DebugAbbrev() { if (m_abbr) return m_abbr.get(); @@ -672,21 +668,6 @@ DWARFDebugRanges *SymbolFileDWARF::GetDebugRanges() { return m_ranges.get(); } -DWARFDebugRngLists *SymbolFileDWARF::GetDebugRngLists() { - if (!m_rnglists) { - static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); - Timer scoped_timer(func_cat, "%s this = %p", LLVM_PRETTY_FUNCTION, - static_cast<void *>(this)); - - if (m_context.getOrLoadRngListsData().GetByteSize() > 0) - m_rnglists.reset(new DWARFDebugRngLists()); - - if (m_rnglists) - m_rnglists->Extract(m_context); - } - return m_rnglists.get(); -} - lldb::CompUnitSP SymbolFileDWARF::ParseCompileUnit(DWARFCompileUnit &dwarf_cu) { CompUnitSP cu_sp; CompileUnit *comp_unit = (CompileUnit *)dwarf_cu.GetUserData(); @@ -703,7 +684,8 @@ lldb::CompUnitSP SymbolFileDWARF::ParseCompileUnit(DWARFCompileUnit &dwarf_cu) { } else { ModuleSP module_sp(m_objfile_sp->GetModule()); if (module_sp) { - const DWARFDIE cu_die = dwarf_cu.DIE(); + const DWARFBaseDIE cu_die = + dwarf_cu.GetNonSkeletonUnit().GetUnitDIEOnly(); if (cu_die) { FileSpec cu_file_spec(cu_die.GetName(), dwarf_cu.GetPathStyle()); if (cu_file_spec) { @@ -721,7 +703,7 @@ lldb::CompUnitSP SymbolFileDWARF::ParseCompileUnit(DWARFCompileUnit &dwarf_cu) { LanguageType cu_language = DWARFUnit::LanguageTypeFromDWARF( cu_die.GetAttributeValueAsUnsigned(DW_AT_language, 0)); - bool is_optimized = dwarf_cu.GetIsOptimized(); + bool is_optimized = dwarf_cu.GetNonSkeletonUnit().GetIsOptimized(); BuildCuTranslationTable(); cu_sp = std::make_shared<CompileUnit>( module_sp, &dwarf_cu, cu_file_spec, @@ -828,15 +810,20 @@ lldb::LanguageType SymbolFileDWARF::ParseLanguage(CompileUnit &comp_unit) { } size_t SymbolFileDWARF::ParseFunctions(CompileUnit &comp_unit) { + static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); + Timer scoped_timer(func_cat, "SymbolFileDWARF::ParseFunctions"); std::lock_guard<std::recursive_mutex> guard(GetModuleMutex()); DWARFUnit *dwarf_cu = GetDWARFCompileUnit(&comp_unit); if (!dwarf_cu) return 0; size_t functions_added = 0; - std::vector<DWARFDIE> function_dies; - dwarf_cu->AppendDIEsWithTag(DW_TAG_subprogram, function_dies); - for (const DWARFDIE &die : function_dies) { + dwarf_cu = &dwarf_cu->GetNonSkeletonUnit(); + for (DWARFDebugInfoEntry &entry : dwarf_cu->dies()) { + if (entry.Tag() != DW_TAG_subprogram) + continue; + + DWARFDIE die(dwarf_cu, &entry); if (comp_unit.FindFunctionByUID(die.GetID())) continue; if (ParseFunction(comp_unit, die)) @@ -846,16 +833,32 @@ size_t SymbolFileDWARF::ParseFunctions(CompileUnit &comp_unit) { return functions_added; } -void SymbolFileDWARF::ForEachExternalModule( - CompileUnit &comp_unit, llvm::function_ref<void(ModuleSP)> f) { - UpdateExternalModuleListIfNeeded(); +bool SymbolFileDWARF::ForEachExternalModule( + CompileUnit &comp_unit, + llvm::DenseSet<lldb_private::SymbolFile *> &visited_symbol_files, + llvm::function_ref<bool(Module &)> lambda) { + // Only visit each symbol file once. + if (!visited_symbol_files.insert(this).second) + return false; + UpdateExternalModuleListIfNeeded(); for (auto &p : m_external_type_modules) { ModuleSP module = p.second; - f(module); - for (std::size_t i = 0; i < module->GetNumCompileUnits(); ++i) - module->GetCompileUnitAtIndex(i)->ForEachExternalModule(f); + if (!module) + continue; + + // Invoke the action and potentially early-exit. + if (lambda(*module)) + return true; + + for (std::size_t i = 0; i < module->GetNumCompileUnits(); ++i) { + auto cu = module->GetCompileUnitAtIndex(i); + bool early_exit = cu->ForEachExternalModule(visited_symbol_files, lambda); + if (early_exit) + return true; + } } + return false; } bool SymbolFileDWARF::ParseSupportFiles(CompileUnit &comp_unit, @@ -961,7 +964,7 @@ bool SymbolFileDWARF::ParseImportedModules( DW_AT_LLVM_include_path, nullptr)) module.search_path = ConstString(include_path); if (const char *sysroot = module_die.GetAttributeValueAsString( - DW_AT_LLVM_isysroot, nullptr)) + DW_AT_LLVM_sysroot, nullptr)) module.sysroot = ConstString(sysroot); imported_modules.push_back(module); } @@ -1023,7 +1026,7 @@ bool SymbolFileDWARF::ParseLineTable(CompileUnit &comp_unit) { comp_unit.SetSupportFiles(ParseSupportFilesFromPrologue( comp_unit.GetModule(), line_table->Prologue, dwarf_cu->GetPathStyle(), - dwarf_cu->GetCompilationDirectory().GetCString(), FileSpec(comp_unit))); + dwarf_cu->GetCompilationDirectory().GetCString())); return true; } @@ -1507,7 +1510,7 @@ bool SymbolFileDWARF::GetFunction(const DWARFDIE &die, SymbolContext &sc) { return false; } -lldb::ModuleSP SymbolFileDWARF::GetDWOModule(ConstString name) { +lldb::ModuleSP SymbolFileDWARF::GetExternalModule(ConstString name) { UpdateExternalModuleListIfNeeded(); const auto &pos = m_external_type_modules.find(name); if (pos != m_external_type_modules.end()) @@ -1532,12 +1535,48 @@ SymbolFileDWARF::GetDIE(const DIERef &die_ref) { return DWARFDIE(); } +/// Return the DW_AT_(GNU_)dwo_name. +static const char *GetDWOName(DWARFCompileUnit &dwarf_cu, + const DWARFDebugInfoEntry &cu_die) { + const char *dwo_name = + cu_die.GetAttributeValueAsString(&dwarf_cu, DW_AT_GNU_dwo_name, nullptr); + if (!dwo_name) + dwo_name = + cu_die.GetAttributeValueAsString(&dwarf_cu, DW_AT_dwo_name, nullptr); + return dwo_name; +} + +/// Return the DW_AT_(GNU_)dwo_id. +/// FIXME: Technically 0 is a valid hash. +static uint64_t GetDWOId(DWARFCompileUnit &dwarf_cu, + const DWARFDebugInfoEntry &cu_die) { + uint64_t dwo_id = + cu_die.GetAttributeValueAsUnsigned(&dwarf_cu, DW_AT_GNU_dwo_id, 0); + if (!dwo_id) + dwo_id = cu_die.GetAttributeValueAsUnsigned(&dwarf_cu, DW_AT_dwo_id, 0); + return dwo_id; +} + +llvm::Optional<uint64_t> SymbolFileDWARF::GetDWOId() { + if (GetNumCompileUnits() == 1) { + if (auto comp_unit = GetCompileUnitAtIndex(0)) + if (DWARFCompileUnit *cu = llvm::dyn_cast_or_null<DWARFCompileUnit>( + GetDWARFCompileUnit(comp_unit.get()))) + if (DWARFDebugInfoEntry *cu_die = cu->DIE().GetDIE()) + if (uint64_t dwo_id = ::GetDWOId(*cu, *cu_die)) + return dwo_id; + } + return {}; +} + std::unique_ptr<SymbolFileDWARFDwo> SymbolFileDWARF::GetDwoSymbolFileForCompileUnit( DWARFUnit &unit, const DWARFDebugInfoEntry &cu_die) { - // If we are using a dSYM file, we never want the standard DWO files since - // the -gmodules support uses the same DWO machanism to specify full debug - // info files for modules. + // If this is a Darwin-style debug map (non-.dSYM) symbol file, + // never attempt to load ELF-style DWO files since the -gmodules + // support uses the same DWO machanism to specify full debug info + // files for modules. This is handled in + // UpdateExternalModuleListIfNeeded(). if (GetDebugMapSymfile()) return nullptr; @@ -1546,15 +1585,13 @@ SymbolFileDWARF::GetDwoSymbolFileForCompileUnit( if (!dwarf_cu) return nullptr; - const char *dwo_name = - cu_die.GetAttributeValueAsString(dwarf_cu, DW_AT_GNU_dwo_name, nullptr); + const char *dwo_name = GetDWOName(*dwarf_cu, cu_die); if (!dwo_name) return nullptr; SymbolFileDWARFDwp *dwp_symfile = GetDwpSymbolFile(); if (dwp_symfile) { - uint64_t dwo_id = - cu_die.GetAttributeValueAsUnsigned(dwarf_cu, DW_AT_GNU_dwo_id, 0); + uint64_t dwo_id = ::GetDWOId(*dwarf_cu, cu_die); std::unique_ptr<SymbolFileDWARFDwo> dwo_symfile = dwp_symfile->GetSymbolFileForDwoId(*dwarf_cu, dwo_id); if (dwo_symfile) @@ -1594,76 +1631,101 @@ void SymbolFileDWARF::UpdateExternalModuleListIfNeeded() { if (m_fetched_external_modules) return; m_fetched_external_modules = true; - DWARFDebugInfo *debug_info = DebugInfo(); + // Follow DWO skeleton unit breadcrumbs. const uint32_t num_compile_units = GetNumCompileUnits(); for (uint32_t cu_idx = 0; cu_idx < num_compile_units; ++cu_idx) { - DWARFUnit *dwarf_cu = debug_info->GetUnitAtIndex(cu_idx); + auto *dwarf_cu = + llvm::dyn_cast<DWARFCompileUnit>(debug_info->GetUnitAtIndex(cu_idx)); + if (!dwarf_cu) + continue; const DWARFBaseDIE die = dwarf_cu->GetUnitDIEOnly(); - if (die && !die.HasChildren()) { - const char *name = die.GetAttributeValueAsString(DW_AT_name, nullptr); - - if (name) { - ConstString const_name(name); - if (m_external_type_modules.find(const_name) == - m_external_type_modules.end()) { - ModuleSP module_sp; - const char *dwo_path = - die.GetAttributeValueAsString(DW_AT_GNU_dwo_name, nullptr); - if (dwo_path) { - ModuleSpec dwo_module_spec; - dwo_module_spec.GetFileSpec().SetFile(dwo_path, - FileSpec::Style::native); - if (dwo_module_spec.GetFileSpec().IsRelative()) { - const char *comp_dir = - die.GetAttributeValueAsString(DW_AT_comp_dir, nullptr); - if (comp_dir) { - dwo_module_spec.GetFileSpec().SetFile(comp_dir, - FileSpec::Style::native); - FileSystem::Instance().Resolve(dwo_module_spec.GetFileSpec()); - dwo_module_spec.GetFileSpec().AppendPathComponent(dwo_path); - } - } - dwo_module_spec.GetArchitecture() = - m_objfile_sp->GetModule()->GetArchitecture(); - - // When LLDB loads "external" modules it looks at the presence of - // DW_AT_GNU_dwo_name. However, when the already created module - // (corresponding to .dwo itself) is being processed, it will see - // the presence of DW_AT_GNU_dwo_name (which contains the name of - // dwo file) and will try to call ModuleList::GetSharedModule - // again. In some cases (i.e. for empty files) Clang 4.0 generates - // a *.dwo file which has DW_AT_GNU_dwo_name, but no - // DW_AT_comp_dir. In this case the method - // ModuleList::GetSharedModule will fail and the warning will be - // printed. However, as one can notice in this case we don't - // actually need to try to load the already loaded module - // (corresponding to .dwo) so we simply skip it. - if (m_objfile_sp->GetFileSpec().GetFileNameExtension() == ".dwo" && - llvm::StringRef(m_objfile_sp->GetFileSpec().GetPath()) - .endswith(dwo_module_spec.GetFileSpec().GetPath())) { - continue; - } + if (!die || die.HasChildren() || !die.GetDIE()) + continue; - Status error = ModuleList::GetSharedModule( - dwo_module_spec, module_sp, nullptr, nullptr, nullptr); - if (!module_sp) { - GetObjectFile()->GetModule()->ReportWarning( - "0x%8.8x: unable to locate module needed for external types: " - "%s\nerror: %s\nDebugging will be degraded due to missing " - "types. Rebuilding your project will regenerate the needed " - "module files.", - die.GetOffset(), - dwo_module_spec.GetFileSpec().GetPath().c_str(), - error.AsCString("unknown error")); - } - } - m_external_type_modules[const_name] = module_sp; - } + const char *name = die.GetAttributeValueAsString(DW_AT_name, nullptr); + if (!name) + continue; + + ConstString const_name(name); + ModuleSP &module_sp = m_external_type_modules[const_name]; + if (module_sp) + continue; + + const char *dwo_path = GetDWOName(*dwarf_cu, *die.GetDIE()); + if (!dwo_path) + continue; + + ModuleSpec dwo_module_spec; + dwo_module_spec.GetFileSpec().SetFile(dwo_path, FileSpec::Style::native); + if (dwo_module_spec.GetFileSpec().IsRelative()) { + const char *comp_dir = + die.GetAttributeValueAsString(DW_AT_comp_dir, nullptr); + if (comp_dir) { + dwo_module_spec.GetFileSpec().SetFile(comp_dir, + FileSpec::Style::native); + FileSystem::Instance().Resolve(dwo_module_spec.GetFileSpec()); + dwo_module_spec.GetFileSpec().AppendPathComponent(dwo_path); } } + dwo_module_spec.GetArchitecture() = + m_objfile_sp->GetModule()->GetArchitecture(); + + // When LLDB loads "external" modules it looks at the presence of + // DW_AT_dwo_name. However, when the already created module + // (corresponding to .dwo itself) is being processed, it will see + // the presence of DW_AT_dwo_name (which contains the name of dwo + // file) and will try to call ModuleList::GetSharedModule + // again. In some cases (i.e., for empty files) Clang 4.0 + // generates a *.dwo file which has DW_AT_dwo_name, but no + // DW_AT_comp_dir. In this case the method + // ModuleList::GetSharedModule will fail and the warning will be + // printed. However, as one can notice in this case we don't + // actually need to try to load the already loaded module + // (corresponding to .dwo) so we simply skip it. + if (m_objfile_sp->GetFileSpec().GetFileNameExtension() == ".dwo" && + llvm::StringRef(m_objfile_sp->GetFileSpec().GetPath()) + .endswith(dwo_module_spec.GetFileSpec().GetPath())) { + continue; + } + + Status error = ModuleList::GetSharedModule(dwo_module_spec, module_sp, + nullptr, nullptr, nullptr); + if (!module_sp) { + GetObjectFile()->GetModule()->ReportWarning( + "0x%8.8x: unable to locate module needed for external types: " + "%s\nerror: %s\nDebugging will be degraded due to missing " + "types. Rebuilding the project will regenerate the needed " + "module files.", + die.GetOffset(), dwo_module_spec.GetFileSpec().GetPath().c_str(), + error.AsCString("unknown error")); + continue; + } + + // Verify the DWO hash. + // FIXME: Technically "0" is a valid hash. + uint64_t dwo_id = ::GetDWOId(*dwarf_cu, *die.GetDIE()); + if (!dwo_id) + continue; + + auto *dwo_symfile = + llvm::dyn_cast_or_null<SymbolFileDWARF>(module_sp->GetSymbolFile()); + if (!dwo_symfile) + continue; + llvm::Optional<uint64_t> dwo_dwo_id = dwo_symfile->GetDWOId(); + if (!dwo_dwo_id) + continue; + + if (dwo_id != dwo_dwo_id) { + GetObjectFile()->GetModule()->ReportWarning( + "0x%8.8x: Module %s is out-of-date (hash mismatch). Type information " + "from this module may be incomplete or inconsistent with the rest of " + "the program. Rebuilding the project will regenerate the needed " + "module files.", + die.GetOffset(), dwo_module_spec.GetFileSpec().GetPath().c_str()); + } } } @@ -1867,9 +1929,8 @@ uint32_t SymbolFileDWARF::ResolveSymbolContext(const FileSpec &file_spec, if (!dc_cu) continue; - const bool full_match = (bool)file_spec.GetDirectory(); bool file_spec_matches_cu_file_spec = - FileSpec::Equal(file_spec, *dc_cu, full_match); + FileSpec::Match(file_spec, dc_cu->GetPrimaryFile()); if (check_inlines || file_spec_matches_cu_file_spec) { SymbolContext sc(m_objfile_sp->GetModule()); sc.comp_unit = dc_cu; @@ -2208,9 +2269,12 @@ bool SymbolFileDWARF::ResolveFunction(const DWARFDIE &orig_die, addr = sc.function->GetAddressRange().GetBaseAddress(); } - if (addr.IsValid()) { - sc_list.Append(sc); - return true; + + if (auto section_sp = addr.GetSection()) { + if (section_sp->GetPermissions() & ePermissionsExecutable) { + sc_list.Append(sc); + return true; + } } } @@ -2364,12 +2428,10 @@ void SymbolFileDWARF::FindTypes( llvm::DenseSet<lldb_private::SymbolFile *> &searched_symbol_files, TypeMap &types) { std::lock_guard<std::recursive_mutex> guard(GetModuleMutex()); - // Make sure we haven't already searched this SymbolFile before... - if (searched_symbol_files.count(this)) + // Make sure we haven't already searched this SymbolFile before. + if (!searched_symbol_files.insert(this).second) return; - searched_symbol_files.insert(this); - DWARFDebugInfo *info = DebugInfo(); if (!info) return; @@ -2451,8 +2513,13 @@ void SymbolFileDWARF::FindTypes( } } -void SymbolFileDWARF::FindTypes(llvm::ArrayRef<CompilerContext> pattern, - LanguageSet languages, TypeMap &types) { +void SymbolFileDWARF::FindTypes( + llvm::ArrayRef<CompilerContext> pattern, LanguageSet languages, + llvm::DenseSet<SymbolFile *> &searched_symbol_files, TypeMap &types) { + // Make sure we haven't already searched this SymbolFile before. + if (!searched_symbol_files.insert(this).second) + return; + std::lock_guard<std::recursive_mutex> guard(GetModuleMutex()); if (pattern.empty()) return; @@ -2482,11 +2549,22 @@ void SymbolFileDWARF::FindTypes(llvm::ArrayRef<CompilerContext> pattern, if (!contextMatches(die_context, pattern)) continue; - if (Type *matching_type = ResolveType(die, true, true)) + if (Type *matching_type = ResolveType(die, true, true)) { // We found a type pointer, now find the shared pointer form our type // list. types.InsertUnique(matching_type->shared_from_this()); + } } + + // Next search through the reachable Clang modules. This only applies for + // DWARF objects compiled with -gmodules that haven't been processed by + // dsymutil. + UpdateExternalModuleListIfNeeded(); + + for (const auto &pair : m_external_type_modules) + if (ModuleSP external_module_sp = pair.second) + external_module_sp->FindTypes(pattern, languages, searched_symbol_files, + types); } CompilerDeclContext @@ -3268,15 +3346,17 @@ VariableSP SymbolFileDWARF::ParseVariableDIE(const SymbolContext &sc, module, DataExtractor(data, block_offset, block_length), die.GetCU()); } else { - DataExtractor data = DebugLocData(); - const dw_offset_t offset = form_value.Unsigned(); + DataExtractor data = die.GetCU()->GetLocationData(); + dw_offset_t offset = form_value.Unsigned(); + if (form_value.Form() == DW_FORM_loclistx) + offset = die.GetCU()->GetLoclistOffset(offset).getValueOr(-1); if (data.ValidOffset(offset)) { data = DataExtractor(data, offset, data.GetByteSize() - offset); location = DWARFExpression(module, data, die.GetCU()); assert(func_low_pc != LLDB_INVALID_ADDRESS); - location.SetLocationListSlide( - func_low_pc - - attributes.CompileUnitAtIndex(i)->GetBaseAddress()); + location.SetLocationListAddresses( + attributes.CompileUnitAtIndex(i)->GetBaseAddress(), + func_low_pc); } } } break; @@ -3685,8 +3765,8 @@ CollectCallSiteParameters(ModuleSP module, DWARFDIE call_site_die) { if (child.Tag() != DW_TAG_call_site_parameter) continue; - llvm::Optional<DWARFExpression> LocationInCallee = {}; - llvm::Optional<DWARFExpression> LocationInCaller = {}; + llvm::Optional<DWARFExpression> LocationInCallee; + llvm::Optional<DWARFExpression> LocationInCaller; DWARFAttributes attributes; const size_t num_attributes = child.GetAttributes(attributes); @@ -3725,7 +3805,7 @@ CollectCallSiteParameters(ModuleSP module, DWARFDIE call_site_die) { } /// Collect call graph edges present in a function DIE. -static std::vector<lldb_private::CallEdge> +static std::vector<std::unique_ptr<lldb_private::CallEdge>> CollectCallEdges(ModuleSP module, DWARFDIE function_die) { // Check if the function has a supported call site-related attribute. // TODO: In the future it may be worthwhile to support call_all_source_calls. @@ -3743,32 +3823,87 @@ CollectCallEdges(ModuleSP module, DWARFDIE function_die) { // to be DWARF5-compliant. This may need to be done lazily to be performant. // For now, assume that all entries are nested directly under the subprogram // (this is the kind of DWARF LLVM produces) and parse them eagerly. - std::vector<CallEdge> call_edges; + std::vector<std::unique_ptr<CallEdge>> call_edges; for (DWARFDIE child = function_die.GetFirstChild(); child.IsValid(); child = child.GetSibling()) { if (child.Tag() != DW_TAG_call_site) continue; - // Extract DW_AT_call_origin (the call target's DIE). - DWARFDIE call_origin = child.GetReferencedDIE(DW_AT_call_origin); - if (!call_origin.IsValid()) { - LLDB_LOG(log, "CollectCallEdges: Invalid call origin in {0}", - function_die.GetPubname()); + llvm::Optional<DWARFDIE> call_origin; + llvm::Optional<DWARFExpression> call_target; + addr_t return_pc = LLDB_INVALID_ADDRESS; + + DWARFAttributes attributes; + const size_t num_attributes = child.GetAttributes(attributes); + for (size_t i = 0; i < num_attributes; ++i) { + DWARFFormValue form_value; + if (!attributes.ExtractFormValueAtIndex(i, form_value)) { + LLDB_LOG(log, "CollectCallEdges: Could not extract TAG_call_site form"); + break; + } + + dw_attr_t attr = attributes.AttributeAtIndex(i); + + // Extract DW_AT_call_origin (the call target's DIE). + if (attr == DW_AT_call_origin) { + call_origin = form_value.Reference(); + if (!call_origin->IsValid()) { + LLDB_LOG(log, "CollectCallEdges: Invalid call origin in {0}", + function_die.GetPubname()); + break; + } + } + + // Extract DW_AT_call_return_pc (the PC the call returns to) if it's + // available. It should only ever be unavailable for tail call edges, in + // which case use LLDB_INVALID_ADDRESS. + if (attr == DW_AT_call_return_pc) + return_pc = form_value.Address(); + + // Extract DW_AT_call_target (the location of the address of the indirect + // call). + if (attr == DW_AT_call_target) { + if (!DWARFFormValue::IsBlockForm(form_value.Form())) { + LLDB_LOG(log, + "CollectCallEdges: AT_call_target does not have block form"); + break; + } + + auto data = child.GetData(); + uint32_t block_offset = form_value.BlockData() - data.GetDataStart(); + uint32_t block_length = form_value.Unsigned(); + call_target = DWARFExpression( + module, DataExtractor(data, block_offset, block_length), + child.GetCU()); + } + } + if (!call_origin && !call_target) { + LLDB_LOG(log, "CollectCallEdges: call site without any call target"); continue; } - // Extract DW_AT_call_return_pc (the PC the call returns to) if it's - // available. It should only ever be unavailable for tail call edges, in - // which case use LLDB_INVALID_ADDRESS. - addr_t return_pc = child.GetAttributeValueAsAddress(DW_AT_call_return_pc, - LLDB_INVALID_ADDRESS); - // Extract call site parameters. CallSiteParameterArray parameters = CollectCallSiteParameters(module, child); - LLDB_LOG(log, "CollectCallEdges: Found call origin: {0} (retn-PC: {1:x})", - call_origin.GetPubname(), return_pc); + std::unique_ptr<CallEdge> edge; + if (call_origin) { + LLDB_LOG(log, "CollectCallEdges: Found call origin: {0} (retn-PC: {1:x})", + call_origin->GetPubname(), return_pc); + edge = std::make_unique<DirectCallEdge>(call_origin->GetMangledName(), + return_pc, std::move(parameters)); + } else { + if (log) { + StreamString call_target_desc; + call_target->GetDescription(&call_target_desc, eDescriptionLevelBrief, + LLDB_INVALID_ADDRESS, nullptr); + LLDB_LOG(log, "CollectCallEdges: Found indirect call target: {0}", + call_target_desc.GetString()); + } + edge = std::make_unique<IndirectCallEdge>(*call_target, return_pc, + std::move(parameters)); + } + if (log && parameters.size()) { for (const CallSiteParameter ¶m : parameters) { StreamString callee_loc_desc, caller_loc_desc; @@ -3783,13 +3918,12 @@ CollectCallEdges(ModuleSP module, DWARFDIE function_die) { } } - call_edges.emplace_back(call_origin.GetMangledName(), return_pc, - std::move(parameters)); + call_edges.push_back(std::move(edge)); } return call_edges; } -std::vector<lldb_private::CallEdge> +std::vector<std::unique_ptr<lldb_private::CallEdge>> SymbolFileDWARF::ParseCallEdgesInFunction(UserID func_id) { DWARFDIE func_die = GetDIE(func_id.GetID()); if (func_die.IsValid()) @@ -3829,13 +3963,6 @@ SymbolFileDWARFDebugMap *SymbolFileDWARF::GetDebugMapSymfile() { return m_debug_map_symfile; } -DWARFExpression::LocationListFormat -SymbolFileDWARF::GetLocationListFormat() const { - if (m_data_debug_loclists.m_data.GetByteSize() > 0) - return DWARFExpression::LocLists; - return DWARFExpression::RegularLocationList; -} - SymbolFileDWARFDwp *SymbolFileDWARF::GetDwpSymbolFile() { llvm::call_once(m_dwp_symfile_once_flag, [this]() { ModuleSpec module_spec; diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h index 04cb11d426be..23e26732453f 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h @@ -21,7 +21,6 @@ #include "lldb/Core/UniqueCStringMap.h" #include "lldb/Core/dwarf.h" -#include "lldb/Expression/DWARFExpression.h" #include "lldb/Symbol/DebugMacros.h" #include "lldb/Symbol/SymbolContext.h" #include "lldb/Symbol/SymbolFile.h" @@ -47,7 +46,6 @@ class DWARFDebugInfo; class DWARFDebugInfoEntry; class DWARFDebugLine; class DWARFDebugRanges; -class DWARFDebugRngLists; class DWARFDeclContext; class DWARFFormValue; class DWARFTypeUnit; @@ -59,7 +57,18 @@ class SymbolFileDWARFDwp; class SymbolFileDWARF : public lldb_private::SymbolFile, public lldb_private::UserID { + /// LLVM RTTI support. + static char ID; + public: + /// LLVM RTTI support. + /// \{ + bool isA(const void *ClassID) const override { + return ClassID == &ID || SymbolFile::isA(ClassID); + } + static bool classof(const SymbolFile *obj) { return obj->isA(&ID); } + /// \} + friend class SymbolFileDWARFDebugMap; friend class SymbolFileDWARFDwo; friend class DebugMapModule; @@ -105,9 +114,9 @@ public: bool ParseDebugMacros(lldb_private::CompileUnit &comp_unit) override; - void - ForEachExternalModule(lldb_private::CompileUnit &comp_unit, - llvm::function_ref<void(lldb::ModuleSP)> f) override; + bool ForEachExternalModule( + lldb_private::CompileUnit &, llvm::DenseSet<lldb_private::SymbolFile *> &, + llvm::function_ref<bool(lldb_private::Module &)>) override; bool ParseSupportFiles(lldb_private::CompileUnit &comp_unit, lldb_private::FileSpecList &support_files) override; @@ -190,6 +199,7 @@ public: void FindTypes(llvm::ArrayRef<lldb_private::CompilerContext> pattern, lldb_private::LanguageSet languages, + llvm::DenseSet<SymbolFile *> &searched_symbol_files, lldb_private::TypeMap &types) override; void GetTypes(lldb_private::SymbolContextScope *sc_scope, @@ -212,9 +222,6 @@ public: uint32_t GetPluginVersion() override; - const lldb_private::DWARFDataExtractor &get_debug_loc_data(); - const lldb_private::DWARFDataExtractor &get_debug_loclists_data(); - DWARFDebugAbbrev *DebugAbbrev(); const DWARFDebugAbbrev *DebugAbbrev() const; @@ -224,9 +231,6 @@ public: const DWARFDebugInfo *DebugInfo() const; DWARFDebugRanges *GetDebugRanges(); - DWARFDebugRngLists *GetDebugRngLists(); - - const lldb_private::DWARFDataExtractor &DebugLocData(); static bool SupportedVersion(uint16_t version); @@ -250,10 +254,7 @@ public: virtual lldb::CompUnitSP ParseCompileUnit(DWARFCompileUnit &dwarf_cu); - virtual lldb_private::DWARFExpression::LocationListFormat - GetLocationListFormat() const; - - lldb::ModuleSP GetDWOModule(lldb_private::ConstString name); + lldb::ModuleSP GetExternalModule(lldb_private::ConstString name); typedef std::map<lldb_private::ConstString, lldb::ModuleSP> ExternalTypeModuleMap; @@ -277,7 +278,7 @@ public: lldb::user_id_t GetUID(DIERef ref); - virtual std::unique_ptr<SymbolFileDWARFDwo> + std::unique_ptr<SymbolFileDWARFDwo> GetDwoSymbolFileForCompileUnit(DWARFUnit &dwarf_cu, const DWARFDebugInfoEntry &cu_die); @@ -288,11 +289,14 @@ public: virtual llvm::Optional<uint32_t> GetDwoNum() { return llvm::None; } + /// If this is a DWARF object with a single CU, return its DW_AT_dwo_id. + llvm::Optional<uint64_t> GetDWOId(); + static bool DIEInDeclContext(const lldb_private::CompilerDeclContext *parent_decl_ctx, const DWARFDIE &die); - std::vector<lldb_private::CallEdge> + std::vector<std::unique_ptr<lldb_private::CallEdge>> ParseCallEdgesInFunction(UserID func_id) override; void Dump(lldb_private::Stream &s) override; @@ -484,7 +488,6 @@ protected: typedef llvm::StringMap<DIERefSet> NameToOffsetMap; NameToOffsetMap m_function_scope_qualified_name_map; std::unique_ptr<DWARFDebugRanges> m_ranges; - std::unique_ptr<DWARFDebugRngLists> m_rnglists; UniqueDWARFASTTypeMap m_unique_ast_type_map; DIEToTypePtr m_die_to_type; DIEToVariableSP m_die_to_variable_sp; diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp index a50d4e460bae..cce666a222d0 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp @@ -39,6 +39,8 @@ using namespace lldb; using namespace lldb_private; +char SymbolFileDWARFDebugMap::ID; + // Subclass lldb_private::Module so we can intercept the // "Module::GetObjectFile()" (so we can fixup the object file sections) and // also for "Module::GetSymbolFile()" (so we can fixup the symbol file id. @@ -602,7 +604,7 @@ SymbolFileDWARFDebugMap::CompileUnitInfo * SymbolFileDWARFDebugMap::GetCompUnitInfo(const CompileUnit &comp_unit) { const uint32_t cu_count = GetNumCompileUnits(); for (uint32_t i = 0; i < cu_count; ++i) { - if (comp_unit == m_compile_unit_infos[i].compile_unit_sp.get()) + if (&comp_unit == m_compile_unit_infos[i].compile_unit_sp.get()) return &m_compile_unit_infos[i]; } return nullptr; @@ -652,12 +654,15 @@ bool SymbolFileDWARFDebugMap::ParseDebugMacros(CompileUnit &comp_unit) { return false; } -void SymbolFileDWARFDebugMap::ForEachExternalModule( - CompileUnit &comp_unit, llvm::function_ref<void(ModuleSP)> f) { +bool SymbolFileDWARFDebugMap::ForEachExternalModule( + CompileUnit &comp_unit, + llvm::DenseSet<lldb_private::SymbolFile *> &visited_symbol_files, + llvm::function_ref<bool(Module &)> f) { std::lock_guard<std::recursive_mutex> guard(GetModuleMutex()); SymbolFileDWARF *oso_dwarf = GetSymbolFile(comp_unit); if (oso_dwarf) - oso_dwarf->ForEachExternalModule(comp_unit, f); + return oso_dwarf->ForEachExternalModule(comp_unit, visited_symbol_files, f); + return false; } bool SymbolFileDWARFDebugMap::ParseSupportFiles(CompileUnit &comp_unit, @@ -807,12 +812,8 @@ uint32_t SymbolFileDWARFDebugMap::ResolveSymbolContext( if (!resolve) { FileSpec so_file_spec; - if (GetFileSpecForSO(i, so_file_spec)) { - // Match the full path if the incoming file_spec has a directory (not - // just a basename) - const bool full_match = (bool)file_spec.GetDirectory(); - resolve = FileSpec::Equal(file_spec, so_file_spec, full_match); - } + if (GetFileSpecForSO(i, so_file_spec)) + resolve = FileSpec::Match(file_spec, so_file_spec); } if (resolve) { SymbolFileDWARF *oso_dwarf = GetSymbolFileByOSOIndex(i); @@ -1071,7 +1072,7 @@ void SymbolFileDWARFDebugMap::GetTypes(SymbolContextScope *sc_scope, } } -std::vector<lldb_private::CallEdge> +std::vector<std::unique_ptr<lldb_private::CallEdge>> SymbolFileDWARFDebugMap::ParseCallEdgesInFunction(UserID func_id) { uint32_t oso_idx = GetOSOIndexFromUserID(func_id.GetID()); SymbolFileDWARF *oso_dwarf = GetSymbolFileByOSOIndex(oso_idx); @@ -1183,6 +1184,16 @@ void SymbolFileDWARFDebugMap::FindTypes( }); } +void SymbolFileDWARFDebugMap::FindTypes( + llvm::ArrayRef<CompilerContext> context, LanguageSet languages, + llvm::DenseSet<lldb_private::SymbolFile *> &searched_symbol_files, + TypeMap &types) { + ForEachSymbolFile([&](SymbolFileDWARF *oso_dwarf) -> bool { + oso_dwarf->FindTypes(context, languages, searched_symbol_files, types); + return false; + }); +} + // // uint32_t // SymbolFileDWARFDebugMap::FindTypes (const SymbolContext& sc, const diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h index 7adee1b356ce..035a902498be 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h @@ -23,7 +23,18 @@ class DWARFDebugAranges; class DWARFDeclContext; class SymbolFileDWARFDebugMap : public lldb_private::SymbolFile { + /// LLVM RTTI support. + static char ID; + public: + /// LLVM RTTI support. + /// \{ + bool isA(const void *ClassID) const override { + return ClassID == &ID || SymbolFile::isA(ClassID); + } + static bool classof(const SymbolFile *obj) { return obj->isA(&ID); } + /// \} + // Static Functions static void Initialize(); @@ -53,9 +64,9 @@ public: bool ParseDebugMacros(lldb_private::CompileUnit &comp_unit) override; - void - ForEachExternalModule(lldb_private::CompileUnit &comp_unit, - llvm::function_ref<void(lldb::ModuleSP)> f) override; + bool ForEachExternalModule( + lldb_private::CompileUnit &, llvm::DenseSet<lldb_private::SymbolFile *> &, + llvm::function_ref<bool(lldb_private::Module &)>) override; bool ParseSupportFiles(lldb_private::CompileUnit &comp_unit, lldb_private::FileSpecList &support_files) override; @@ -114,13 +125,18 @@ public: uint32_t max_matches, llvm::DenseSet<lldb_private::SymbolFile *> &searched_symbol_files, lldb_private::TypeMap &types) override; + void + FindTypes(llvm::ArrayRef<lldb_private::CompilerContext> context, + lldb_private::LanguageSet languages, + llvm::DenseSet<lldb_private::SymbolFile *> &searched_symbol_files, + lldb_private::TypeMap &types) override; lldb_private::CompilerDeclContext FindNamespace( lldb_private::ConstString name, const lldb_private::CompilerDeclContext *parent_decl_ctx) override; void GetTypes(lldb_private::SymbolContextScope *sc_scope, lldb::TypeClass type_mask, lldb_private::TypeList &type_list) override; - std::vector<lldb_private::CallEdge> + std::vector<std::unique_ptr<lldb_private::CallEdge>> ParseCallEdgesInFunction(lldb_private::UserID func_id) override; void DumpClangAST(lldb_private::Stream &s) override; @@ -348,8 +364,8 @@ protected: /// \param[in] oso_symfile /// The DWARF symbol file that produced the \a line_table /// - /// \param[in] addr - /// A section offset address from a .o file + /// \param[in] line_table + /// A pointer to the line table. /// /// \return /// Returns a valid line table full of linked addresses, or NULL diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.cpp index b0f7e813d4f8..f75f06f31e2d 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.cpp @@ -21,6 +21,8 @@ using namespace lldb; using namespace lldb_private; +char SymbolFileDWARFDwo::ID; + SymbolFileDWARFDwo::SymbolFileDWARFDwo(ObjectFileSP objfile, DWARFCompileUnit &dwarf_cu) : SymbolFileDWARF(objfile, objfile->GetSectionList( @@ -135,11 +137,6 @@ SymbolFileDWARF &SymbolFileDWARFDwo::GetBaseSymbolFile() { return m_base_dwarf_cu.GetSymbolFileDWARF(); } -DWARFExpression::LocationListFormat -SymbolFileDWARFDwo::GetLocationListFormat() const { - return DWARFExpression::SplitDwarfLocationList; -} - llvm::Expected<TypeSystem &> SymbolFileDWARFDwo::GetTypeSystemForLanguage(LanguageType language) { return GetBaseSymbolFile().GetTypeSystemForLanguage(language); diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.h b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.h index ad290cdcf65e..0855dba044e4 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.h @@ -12,7 +12,18 @@ #include "SymbolFileDWARF.h" class SymbolFileDWARFDwo : public SymbolFileDWARF { + /// LLVM RTTI support. + static char ID; + public: + /// LLVM RTTI support. + /// \{ + bool isA(const void *ClassID) const override { + return ClassID == &ID || SymbolFileDWARF::isA(ClassID); + } + static bool classof(const SymbolFile *obj) { return obj->isA(&ID); } + /// \} + SymbolFileDWARFDwo(lldb::ObjectFileSP objfile, DWARFCompileUnit &dwarf_cu); ~SymbolFileDWARFDwo() override = default; @@ -24,9 +35,6 @@ public: DWARFUnit * GetDWARFCompileUnit(lldb_private::CompileUnit *comp_unit) override; - lldb_private::DWARFExpression::LocationListFormat - GetLocationListFormat() const override; - size_t GetObjCMethodDIEOffsets(lldb_private::ConstString class_name, DIEArray &method_die_offsets) override; @@ -36,12 +44,6 @@ public: DWARFDIE GetDIE(const DIERef &die_ref) override; - std::unique_ptr<SymbolFileDWARFDwo> - GetDwoSymbolFileForCompileUnit(DWARFUnit &dwarf_cu, - const DWARFDebugInfoEntry &cu_die) override { - return nullptr; - } - DWARFCompileUnit *GetBaseCompileUnit() override { return &m_base_dwarf_cu; } llvm::Optional<uint32_t> GetDwoNum() override { return GetID() >> 32; } diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwoDwp.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwoDwp.cpp index efea192b17ce..4288dcb5c9bd 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwoDwp.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwoDwp.cpp @@ -19,6 +19,8 @@ using namespace lldb; using namespace lldb_private; +char SymbolFileDWARFDwoDwp::ID; + SymbolFileDWARFDwoDwp::SymbolFileDWARFDwoDwp(SymbolFileDWARFDwp *dwp_symfile, ObjectFileSP objfile, DWARFCompileUnit &dwarf_cu, diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwoDwp.h b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwoDwp.h index 2105e1a8f6cb..a55795ba5950 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwoDwp.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwoDwp.h @@ -13,7 +13,17 @@ #include "SymbolFileDWARFDwp.h" class SymbolFileDWARFDwoDwp : public SymbolFileDWARFDwo { + /// LLVM RTTI support. + static char ID; + public: + /// LLVM RTTI support. + /// \{ + bool isA(const void *ClassID) const override { + return ClassID == &ID || SymbolFileDWARFDwo::isA(ClassID); + } + static bool classof(const SymbolFile *obj) { return obj->isA(&ID); } + /// \} SymbolFileDWARFDwoDwp(SymbolFileDWARFDwp *dwp_symfile, lldb::ObjectFileSP objfile, DWARFCompileUnit &dwarf_cu, uint64_t dwo_id); |