diff options
Diffstat (limited to 'source/Plugins/SymbolFile')
38 files changed, 3152 insertions, 774 deletions
diff --git a/source/Plugins/SymbolFile/CMakeLists.txt b/source/Plugins/SymbolFile/CMakeLists.txt index add6697389f97..98510704ce730 100644 --- a/source/Plugins/SymbolFile/CMakeLists.txt +++ b/source/Plugins/SymbolFile/CMakeLists.txt @@ -1,2 +1,3 @@ add_subdirectory(DWARF) add_subdirectory(Symtab) +add_subdirectory(PDB) diff --git a/source/Plugins/SymbolFile/DWARF/CMakeLists.txt b/source/Plugins/SymbolFile/DWARF/CMakeLists.txt index b4658115dfeb8..ac69243b65c09 100644 --- a/source/Plugins/SymbolFile/DWARF/CMakeLists.txt +++ b/source/Plugins/SymbolFile/DWARF/CMakeLists.txt @@ -3,6 +3,7 @@ add_lldb_library(lldbPluginSymbolFileDWARF DWARFAbbreviationDeclaration.cpp DWARFASTParserClang.cpp DWARFASTParserGo.cpp + DWARFASTParserJava.cpp DWARFAttribute.cpp DWARFCompileUnit.cpp DWARFDataExtractor.cpp diff --git a/source/Plugins/SymbolFile/DWARF/DIERef.cpp b/source/Plugins/SymbolFile/DWARF/DIERef.cpp index c0754a1fdd542..5fe0cc4d416e1 100644 --- a/source/Plugins/SymbolFile/DWARF/DIERef.cpp +++ b/source/Plugins/SymbolFile/DWARF/DIERef.cpp @@ -10,26 +10,49 @@ #include "DIERef.h" #include "DWARFCompileUnit.h" #include "DWARFFormValue.h" +#include "DWARFDebugInfo.h" +#include "SymbolFileDWARF.h" +#include "SymbolFileDWARFDebugMap.h" DIERef::DIERef() : cu_offset(DW_INVALID_OFFSET), die_offset(DW_INVALID_OFFSET) {} -DIERef::DIERef(dw_offset_t d) : - cu_offset(DW_INVALID_OFFSET), - die_offset(d) -{} - DIERef::DIERef(dw_offset_t c, dw_offset_t d) : cu_offset(c), die_offset(d) {} -DIERef::DIERef(lldb::user_id_t uid) : - cu_offset(uid>>32), +DIERef::DIERef(lldb::user_id_t uid, SymbolFileDWARF *dwarf) : + cu_offset(DW_INVALID_OFFSET), die_offset(uid&0xffffffff) -{} +{ + SymbolFileDWARFDebugMap *debug_map = dwarf->GetDebugMapSymfile(); + if (debug_map) + { + const uint32_t oso_idx = debug_map->GetOSOIndexFromUserID(uid); + SymbolFileDWARF *actual_dwarf = debug_map->GetSymbolFileByOSOIndex(oso_idx); + if (actual_dwarf) + { + DWARFDebugInfo *debug_info = actual_dwarf->DebugInfo(); + if (debug_info) + { + DWARFCompileUnit *dwarf_cu = debug_info->GetCompileUnitContainingDIEOffset(die_offset); + if (dwarf_cu) + { + cu_offset = dwarf_cu->GetOffset(); + return; + } + } + } + die_offset = DW_INVALID_OFFSET; + } + else + { + cu_offset = uid>>32; + } +} DIERef::DIERef(const DWARFFormValue& form_value) : cu_offset(DW_INVALID_OFFSET), @@ -50,7 +73,19 @@ DIERef::DIERef(const DWARFFormValue& form_value) : } lldb::user_id_t -DIERef::GetUID() const +DIERef::GetUID(SymbolFileDWARF *dwarf) const { - return ((lldb::user_id_t)cu_offset) << 32 | die_offset; + //---------------------------------------------------------------------- + // Each SymbolFileDWARF will set its ID to what is expected. + // + // SymbolFileDWARF, when used for DWARF with .o files on MacOSX, has the + // ID set to the compile unit index. + // + // SymbolFileDWARFDwo sets the ID to the compile unit offset. + //---------------------------------------------------------------------- + if (dwarf) + return dwarf->GetID() | die_offset; + else + return LLDB_INVALID_UID; } + diff --git a/source/Plugins/SymbolFile/DWARF/DIERef.h b/source/Plugins/SymbolFile/DWARF/DIERef.h index 3df07d511749d..ad4ad45623a3d 100644 --- a/source/Plugins/SymbolFile/DWARF/DIERef.h +++ b/source/Plugins/SymbolFile/DWARF/DIERef.h @@ -14,24 +14,34 @@ #include "lldb/lldb-defines.h" class DWARFFormValue; +class SymbolFileDWARF; struct DIERef { DIERef(); - explicit - DIERef(dw_offset_t d); - DIERef(dw_offset_t c, dw_offset_t d); + //---------------------------------------------------------------------- + // In order to properly decode a lldb::user_id_t back into a DIERef we + // need the DWARF file since it knows if DWARF in .o files is being used + // (MacOSX) or if DWO files are being used. The encoding of the user ID + // differs between the two types of DWARF. + //---------------------------------------------------------------------- explicit - DIERef(lldb::user_id_t uid); + DIERef(lldb::user_id_t uid, SymbolFileDWARF *dwarf); explicit DIERef(const DWARFFormValue& form_value); + //---------------------------------------------------------------------- + // In order to properly encode a DIERef unto a lldb::user_id_t we need + // the DWARF file since it knows if DWARF in .o files is being used + // (MacOSX) or if DWO files are being used. The encoding of the user ID + // differs between the two types of DWARF. + //---------------------------------------------------------------------- lldb::user_id_t - GetUID() const; + GetUID(SymbolFileDWARF *dwarf) const; bool operator< (const DIERef &ref) const diff --git a/source/Plugins/SymbolFile/DWARF/DWARFASTParser.h b/source/Plugins/SymbolFile/DWARF/DWARFASTParser.h index ab20844bfcfde..2fb360440f632 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFASTParser.h +++ b/source/Plugins/SymbolFile/DWARF/DWARFASTParser.h @@ -33,18 +33,6 @@ public: const DWARFDIE &die) = 0; virtual bool - CanCompleteType (const lldb_private::CompilerType &compiler_type) - { - return false; - } - - virtual bool - CompleteType (const lldb_private::CompilerType &compiler_type) - { - return false; - } - - virtual bool CompleteTypeFromDWARF (const DWARFDIE &die, lldb_private::Type *type, lldb_private::CompilerType &compiler_type) = 0; diff --git a/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp b/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp index 74b54d614aa25..23381df3297a8 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp +++ b/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp @@ -7,6 +7,8 @@ // //===----------------------------------------------------------------------===// +#include <stdlib.h> + #include "DWARFASTParserClang.h" #include "DWARFCompileUnit.h" #include "DWARFDebugInfo.h" @@ -18,14 +20,16 @@ #include "SymbolFileDWARFDebugMap.h" #include "UniqueDWARFASTType.h" -#include "lldb/Interpreter/Args.h" +#include "Plugins/Language/ObjC/ObjCLanguage.h" #include "lldb/Core/Log.h" #include "lldb/Core/Module.h" #include "lldb/Core/StreamString.h" #include "lldb/Core/Value.h" #include "lldb/Host/Host.h" +#include "lldb/Interpreter/Args.h" #include "lldb/Symbol/ClangASTImporter.h" #include "lldb/Symbol/ClangExternalASTSourceCommon.h" +#include "lldb/Symbol/ClangUtil.h" #include "lldb/Symbol/CompileUnit.h" #include "lldb/Symbol/Function.h" #include "lldb/Symbol/ObjectFile.h" @@ -33,7 +37,7 @@ #include "lldb/Symbol/TypeList.h" #include "lldb/Symbol/TypeMap.h" #include "lldb/Target/Language.h" -#include "Plugins/Language/ObjC/ObjCLanguage.h" +#include "lldb/Utility/LLDBAssert.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" @@ -97,9 +101,9 @@ struct BitfieldInfo uint64_t bit_size; uint64_t bit_offset; - BitfieldInfo () : - bit_size (LLDB_INVALID_ADDRESS), - bit_offset (LLDB_INVALID_ADDRESS) + BitfieldInfo() : + bit_size(LLDB_INVALID_ADDRESS), + bit_offset(LLDB_INVALID_ADDRESS) { } @@ -110,10 +114,28 @@ struct BitfieldInfo bit_offset = LLDB_INVALID_ADDRESS; } - bool IsValid () + bool + IsValid() const { return (bit_size != LLDB_INVALID_ADDRESS) && - (bit_offset != 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; + } } }; @@ -252,11 +274,11 @@ DWARFASTParserClang::ParseTypeFromDWARF (const SymbolContext& sc, switch (tag) { + case DW_TAG_typedef: case DW_TAG_base_type: case DW_TAG_pointer_type: case DW_TAG_reference_type: case DW_TAG_rvalue_reference_type: - case DW_TAG_typedef: case DW_TAG_const_type: case DW_TAG_restrict_type: case DW_TAG_volatile_type: @@ -267,7 +289,7 @@ DWARFASTParserClang::ParseTypeFromDWARF (const SymbolContext& sc, const size_t num_attributes = die.GetAttributes (attributes); uint32_t encoding = 0; - lldb::user_id_t encoding_uid = LLDB_INVALID_UID; + DWARFFormValue encoding_uid; if (num_attributes > 0) { @@ -297,7 +319,7 @@ DWARFASTParserClang::ParseTypeFromDWARF (const SymbolContext& sc, break; case DW_AT_byte_size: byte_size = form_value.Unsigned(); break; case DW_AT_encoding: encoding = form_value.Unsigned(); break; - case DW_AT_type: encoding_uid = DIERef(form_value).GetUID(); break; + case DW_AT_type: encoding_uid = form_value; break; default: case DW_AT_sibling: break; @@ -306,7 +328,43 @@ DWARFASTParserClang::ParseTypeFromDWARF (const SymbolContext& sc, } } - 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); + if (tag == DW_TAG_typedef && encoding_uid.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 = dwarf->GetDIE(DIERef(encoding_uid)); + + // 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; + } + } + + 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) { @@ -322,6 +380,7 @@ DWARFASTParserClang::ParseTypeFromDWARF (const SymbolContext& sc, 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; @@ -341,6 +400,44 @@ DWARFASTParserClang::ParseTypeFromDWARF (const SymbolContext& sc, if (!clang_type && (encoding_data_type == Type::eEncodingIsPointerUID || encoding_data_type == Type::eEncodingIsTypedefUID) && sc.comp_unit != NULL) { + 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, log, &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; + encoding_uid.Clear(); + resolve_state = Type::eResolveStateFull; + } + } + + break; + } + } + } + } + bool translation_unit_is_objc = (sc.comp_unit->GetLanguage() == eLanguageTypeObjC || sc.comp_unit->GetLanguage() == eLanguageTypeObjC_plus_plus); if (translation_unit_is_objc) @@ -361,7 +458,7 @@ DWARFASTParserClang::ParseTypeFromDWARF (const SymbolContext& sc, die.GetName()); clang_type = m_ast.GetBasicType(eBasicTypeObjCID); encoding_data_type = Type::eEncodingIsUID; - encoding_uid = LLDB_INVALID_UID; + encoding_uid.Clear(); resolve_state = Type::eResolveStateFull; } @@ -375,7 +472,7 @@ DWARFASTParserClang::ParseTypeFromDWARF (const SymbolContext& sc, die.GetName()); clang_type = m_ast.GetBasicType(eBasicTypeObjCClass); encoding_data_type = Type::eEncodingIsUID; - encoding_uid = LLDB_INVALID_UID; + encoding_uid.Clear(); resolve_state = Type::eResolveStateFull; } else if (type_name_const_str == g_objc_type_name_selector) @@ -388,15 +485,15 @@ DWARFASTParserClang::ParseTypeFromDWARF (const SymbolContext& sc, die.GetName()); clang_type = m_ast.GetBasicType(eBasicTypeObjCSel); encoding_data_type = Type::eEncodingIsUID; - encoding_uid = LLDB_INVALID_UID; + encoding_uid.Clear(); resolve_state = Type::eResolveStateFull; } } - else if (encoding_data_type == Type::eEncodingIsPointerUID && encoding_uid != LLDB_INVALID_UID) + else if (encoding_data_type == Type::eEncodingIsPointerUID && encoding_uid.IsValid()) { // Clang sometimes erroneously emits id as objc_object*. In that case we fix up the type to "id". - const DWARFDIE encoding_die = die.GetDIE(encoding_uid); + const DWARFDIE encoding_die = dwarf->GetDIE(DIERef(encoding_uid)); if (encoding_die && encoding_die.Tag() == DW_TAG_structure_type) { @@ -412,7 +509,7 @@ DWARFASTParserClang::ParseTypeFromDWARF (const SymbolContext& sc, die.GetName()); clang_type = m_ast.GetBasicType(eBasicTypeObjCID); encoding_data_type = Type::eEncodingIsUID; - encoding_uid = LLDB_INVALID_UID; + encoding_uid.Clear(); resolve_state = Type::eResolveStateFull; } } @@ -426,7 +523,7 @@ DWARFASTParserClang::ParseTypeFromDWARF (const SymbolContext& sc, type_name_const_str, byte_size, NULL, - encoding_uid, + DIERef(encoding_uid).GetUID(dwarf), encoding_data_type, &decl, clang_type, @@ -532,43 +629,32 @@ DWARFASTParserClang::ParseTypeFromDWARF (const SymbolContext& sc, // and clang isn't good and sharing the stack space for variables in different blocks. std::unique_ptr<UniqueDWARFASTType> unique_ast_entry_ap(new UniqueDWARFASTType()); + ConstString unique_typename(type_name_const_str); + Declaration unique_decl(decl); + if (type_name_const_str) { LanguageType die_language = die.GetLanguage(); - bool handled = false; if (Language::LanguageIsCPlusPlus(die_language)) { + // For C++, we rely solely upon the one definition rule that says only + // one thing can exist at a given decl context. We ignore the file and + // line that things are declared on. std::string qualified_name; if (die.GetQualifiedName(qualified_name)) - { - handled = true; - ConstString const_qualified_name(qualified_name); - if (dwarf->GetUniqueDWARFASTTypeMap().Find(const_qualified_name, die, Declaration(), - byte_size_valid ? byte_size : -1, - *unique_ast_entry_ap)) - { - type_sp = unique_ast_entry_ap->m_type_sp; - if (type_sp) - { - dwarf->GetDIEToType()[die.GetDIE()] = type_sp.get(); - return type_sp; - } - } - } + unique_typename = ConstString(qualified_name); + unique_decl.Clear(); } - if (!handled) + if (dwarf->GetUniqueDWARFASTTypeMap().Find(unique_typename, die, unique_decl, + byte_size_valid ? byte_size : -1, + *unique_ast_entry_ap)) { - if (dwarf->GetUniqueDWARFASTTypeMap().Find(type_name_const_str, die, decl, - byte_size_valid ? byte_size : -1, - *unique_ast_entry_ap)) + type_sp = unique_ast_entry_ap->m_type_sp; + if (type_sp) { - type_sp = unique_ast_entry_ap->m_type_sp; - if (type_sp) - { - dwarf->GetDIEToType()[die.GetDIE()] = type_sp.get(); - return type_sp; - } + dwarf->GetDIEToType()[die.GetDIE()] = type_sp.get(); + return type_sp; } } } @@ -716,7 +802,7 @@ DWARFASTParserClang::ParseTypeFromDWARF (const SymbolContext& sc, // a complete type for this die dwarf->GetDIEToType()[die.GetDIE()] = type_sp.get(); clang::DeclContext *defn_decl_ctx = GetCachedClangDeclContextForDIE( - dwarf->DebugInfo()->GetDIE(DIERef(type_sp->GetID()))); + dwarf->DebugInfo()->GetDIE(DIERef(type_sp->GetID(), dwarf))); if (defn_decl_ctx) LinkDeclContextToDIE(defn_decl_ctx, die); return type_sp; @@ -799,9 +885,9 @@ DWARFASTParserClang::ParseTypeFromDWARF (const SymbolContext& sc, // and over in the ASTContext for our module unique_ast_entry_ap->m_type_sp = type_sp; unique_ast_entry_ap->m_die = die; - unique_ast_entry_ap->m_declaration = decl; + unique_ast_entry_ap->m_declaration = unique_decl; unique_ast_entry_ap->m_byte_size = byte_size; - dwarf->GetUniqueDWARFASTTypeMap().Insert (type_name_const_str, + dwarf->GetUniqueDWARFASTTypeMap().Insert (unique_typename, *unique_ast_entry_ap); if (is_forward_declaration && die.HasChildren()) @@ -842,15 +928,25 @@ DWARFASTParserClang::ParseTypeFromDWARF (const SymbolContext& sc, if (die.HasChildren() == false) { // No children for this struct/union/class, lets finish it - ClangASTContext::StartTagDeclarationDefinition (clang_type); - ClangASTContext::CompleteTagDeclarationDefinition (clang_type); + if (ClangASTContext::StartTagDeclarationDefinition (clang_type)) + { + ClangASTContext::CompleteTagDeclarationDefinition (clang_type); + } + else + { + dwarf->GetObjectFile()->GetModule()->ReportError("DWARF DIE at 0x%8.8x named \"%s\" was not able to start its definition.\nPlease file a bug and attach the file at the start of this error message", + die.GetOffset(), + type_name_cstr); + } if (tag == DW_TAG_structure_type) // this only applies in C { clang::RecordDecl *record_decl = ClangASTContext::GetAsRecordDecl(clang_type); if (record_decl) - m_record_decl_to_layout_map.insert(std::make_pair(record_decl, LayoutInfo())); + { + GetClangASTImporter().InsertRecordDecl(record_decl, ClangASTImporter::LayoutInfo()); + } } } else if (clang_type_was_created) @@ -872,12 +968,14 @@ DWARFASTParserClang::ParseTypeFromDWARF (const SymbolContext& sc, // will automatically call the SymbolFile virtual function // "SymbolFileDWARF::CompleteType(Type *)" // When the definition needs to be defined. - assert(!dwarf->GetForwardDeclClangTypeToDie().count(ClangASTContext::RemoveFastQualifiers(clang_type).GetOpaqueQualType()) && + assert(!dwarf->GetForwardDeclClangTypeToDie().count( + ClangUtil::RemoveFastQualifiers(clang_type).GetOpaqueQualType()) && "Type already in the forward declaration map!"); - assert(((SymbolFileDWARF*)m_ast.GetSymbolFile())->UserIDMatches(die.GetDIERef().GetUID()) && - "Adding incorrect type to forward declaration map"); + // Can't assume m_ast.GetSymbolFile() is actually a SymbolFileDWARF, it can be a + // SymbolFileDWARFDebugMap for Apple binaries. dwarf->GetForwardDeclDieToClangType()[die.GetDIE()] = clang_type.GetOpaqueQualType(); - dwarf->GetForwardDeclClangTypeToDie()[ClangASTContext::RemoveFastQualifiers(clang_type).GetOpaqueQualType()] = die.GetDIERef(); + dwarf->GetForwardDeclClangTypeToDie()[ClangUtil::RemoveFastQualifiers(clang_type) + .GetOpaqueQualType()] = die.GetDIERef(); m_ast.SetHasExternalStorage (clang_type.GetOpaqueQualType(), true); } } @@ -970,8 +1068,7 @@ DWARFASTParserClang::ParseTypeFromDWARF (const SymbolContext& sc, // 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->DebugInfo()->GetDIE(DIERef(type_sp->GetID()))); + clang::DeclContext *defn_decl_ctx = GetCachedClangDeclContextForDIE(dwarf->DebugInfo()->GetDIE(DIERef(type_sp->GetID(), dwarf))); if (defn_decl_ctx) LinkDeclContextToDIE(defn_decl_ctx, die); return type_sp; @@ -986,15 +1083,24 @@ DWARFASTParserClang::ParseTypeFromDWARF (const SymbolContext& sc, { if (encoding_form.IsValid()) { - Type *enumerator_type = dwarf->ResolveTypeUID(DIERef(encoding_form).GetUID()); + Type *enumerator_type = dwarf->ResolveTypeUID(DIERef(encoding_form)); if (enumerator_type) enumerator_clang_type = enumerator_type->GetFullCompilerType (); } if (!enumerator_clang_type) - enumerator_clang_type = m_ast.GetBuiltinTypeForDWARFEncodingAndBitSize (NULL, - DW_ATE_signed, - byte_size * 8); + { + if (byte_size > 0) + { + enumerator_clang_type = m_ast.GetBuiltinTypeForDWARFEncodingAndBitSize(NULL, + DW_ATE_signed, + byte_size * 8); + } + else + { + enumerator_clang_type = m_ast.GetBasicType(eBasicTypeInt); + } + } clang_type = m_ast.CreateEnumerationType (type_name_cstr, GetClangDeclContextContainingDIE (die, nullptr), @@ -1013,21 +1119,29 @@ DWARFASTParserClang::ParseTypeFromDWARF (const SymbolContext& sc, type_name_const_str, byte_size, NULL, - DIERef(encoding_form).GetUID(), + DIERef(encoding_form).GetUID(dwarf), Type::eEncodingIsUID, &decl, clang_type, Type::eResolveStateForward)); - ClangASTContext::StartTagDeclarationDefinition (clang_type); - if (die.HasChildren()) + if (ClangASTContext::StartTagDeclarationDefinition (clang_type)) { - SymbolContext cu_sc(die.GetLLDBCompileUnit()); - bool is_signed = false; - enumerator_clang_type.IsIntegerType(is_signed); - ParseChildEnumerators(cu_sc, clang_type, is_signed, type_sp->GetByteSize(), die); + if (die.HasChildren()) + { + SymbolContext cu_sc(die.GetLLDBCompileUnit()); + bool is_signed = false; + enumerator_clang_type.IsIntegerType(is_signed); + ParseChildEnumerators(cu_sc, clang_type, is_signed, type_sp->GetByteSize(), 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(), + type_name_cstr); } - ClangASTContext::CompleteTagDeclarationDefinition (clang_type); } } break; @@ -1046,6 +1160,7 @@ DWARFASTParserClang::ParseTypeFromDWARF (const SymbolContext& sc, bool is_virtual = false; bool is_explicit = false; bool is_artificial = false; + bool has_template_params = false; DWARFFormValue specification_die_form; DWARFFormValue abstract_origin_die_form; dw_offset_t object_pointer_die_offset = DW_INVALID_OFFSET; @@ -1153,7 +1268,7 @@ DWARFASTParserClang::ParseTypeFromDWARF (const SymbolContext& sc, Type *func_type = NULL; if (type_die_form.IsValid()) - func_type = dwarf->ResolveTypeUID(DIERef(type_die_form).GetUID()); + func_type = dwarf->ResolveTypeUID(DIERef(type_die_form)); if (func_type) return_clang_type = func_type->GetForwardCompilerType (); @@ -1170,11 +1285,13 @@ DWARFASTParserClang::ParseTypeFromDWARF (const SymbolContext& sc, clang::DeclContext *containing_decl_ctx = GetClangDeclContextContainingDIE (die, &decl_ctx_die); const clang::Decl::Kind containing_decl_kind = containing_decl_ctx->getDeclKind(); - const bool is_cxx_method = DeclKindIsCXXClass (containing_decl_kind); + 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()) { @@ -1185,11 +1302,26 @@ DWARFASTParserClang::ParseTypeFromDWARF (const SymbolContext& sc, 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(), @@ -1197,7 +1329,6 @@ DWARFASTParserClang::ParseTypeFromDWARF (const SymbolContext& sc, is_variadic, type_quals); - bool ignore_containing_context = false; if (type_name_cstr) { @@ -1233,7 +1364,8 @@ DWARFASTParserClang::ParseTypeFromDWARF (const SymbolContext& sc, type_name_cstr, clang_type, accessibility, - is_artificial); + is_artificial, + is_variadic); type_handled = objc_method_decl != NULL; if (type_handled) { @@ -1272,12 +1404,12 @@ DWARFASTParserClang::ParseTypeFromDWARF (const SymbolContext& sc, if (debug_map_symfile) { class_symfile = debug_map_symfile->GetSymbolFileByOSOIndex(SymbolFileDWARFDebugMap::GetOSOIndexFromUserID(class_type->GetID())); - class_type_die = class_symfile->DebugInfo()->GetDIE (DIERef(class_type->GetID())); + class_type_die = class_symfile->DebugInfo()->GetDIE (DIERef(class_type->GetID(), dwarf)); } else { class_symfile = dwarf; - class_type_die = dwarf->DebugInfo()->GetDIE (DIERef(class_type->GetID())); + class_type_die = dwarf->DebugInfo()->GetDIE (DIERef(class_type->GetID(), dwarf)); } if (class_type_die) { @@ -1378,7 +1510,8 @@ DWARFASTParserClang::ParseTypeFromDWARF (const SymbolContext& sc, clang::CXXMethodDecl *method_decl = *method_iter; if (method_decl->getNameInfo().getAsString() == std::string(type_name_cstr)) { - if (method_decl->getType() == ClangASTContext::GetQualType(clang_type)) + if (method_decl->getType() == + ClangUtil::GetQualType(clang_type)) { add_method = false; LinkDeclContextToDIE(ClangASTContext::GetAsDeclContext(method_decl), die); @@ -1483,44 +1616,72 @@ DWARFASTParserClang::ParseTypeFromDWARF (const SymbolContext& sc, if (!type_handled) { - // We just have a function that isn't part of a class - clang::FunctionDecl *function_decl = m_ast.CreateFunctionDeclaration (ignore_containing_context ? m_ast.GetTranslationUnitDecl() : containing_decl_ctx, - type_name_cstr, - clang_type, - storage, - is_inline); - - // if (template_param_infos.GetSize() > 0) - // { - // clang::FunctionTemplateDecl *func_template_decl = CreateFunctionTemplateDecl (containing_decl_ctx, - // function_decl, - // type_name_cstr, - // template_param_infos); - // - // CreateFunctionTemplateSpecializationInfo (function_decl, - // func_template_decl, - // template_param_infos); - // } - // Add the decl to our DIE to decl context map - assert (function_decl); - LinkDeclContextToDIE(function_decl, die); - if (!function_param_decls.empty()) - m_ast.SetFunctionParameters (function_decl, - &function_param_decls.front(), - function_param_decls.size()); + clang::FunctionDecl *function_decl = nullptr; + + if (abstract_origin_die_form.IsValid()) + { + DWARFDIE abs_die = dwarf->DebugInfo()->GetDIE (DIERef(abstract_origin_die_form)); - ClangASTMetadata metadata; - metadata.SetUserID(die.GetID()); + SymbolContext sc; + + 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 (!object_pointer_name.empty()) + if (!function_decl) { - metadata.SetObjectPtrName(object_pointer_name.c_str()); - if (log) - log->Printf ("Setting object pointer name: %s on function object %p.", - object_pointer_name.c_str(), - static_cast<void*>(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, + type_name_cstr, + clang_type, + storage, + is_inline); + + // if (template_param_infos.GetSize() > 0) + // { + // clang::FunctionTemplateDecl *func_template_decl = CreateFunctionTemplateDecl (containing_decl_ctx, + // function_decl, + // type_name_cstr, + // template_param_infos); + // + // CreateFunctionTemplateSpecializationInfo (function_decl, + // func_template_decl, + // template_param_infos); + // } + // Add the decl to our DIE to decl context map + + lldbassert (function_decl); + + if (function_decl) + { + LinkDeclContextToDIE(function_decl, die); + + if (!function_param_decls.empty()) + m_ast.SetFunctionParameters (function_decl, + &function_param_decls.front(), + function_param_decls.size()); + + ClangASTMetadata metadata; + metadata.SetUserID(die.GetID()); + + if (!object_pointer_name.empty()) + { + metadata.SetObjectPtrName(object_pointer_name.c_str()); + if (log) + log->Printf ("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); + } } - m_ast.SetMetadata (function_decl, metadata); } } type_sp.reset( new Type (die.GetID(), @@ -1591,7 +1752,8 @@ DWARFASTParserClang::ParseTypeFromDWARF (const SymbolContext& sc, DEBUG_PRINTF ("0x%8.8" PRIx64 ": %s (\"%s\")\n", die.GetID(), DW_TAG_value_to_name(tag), type_name_cstr); - Type *element_type = dwarf->ResolveTypeUID(DIERef(type_die_form).GetUID()); + DIERef type_die_ref(type_die_form); + Type *element_type = dwarf->ResolveTypeUID(type_die_ref); if (element_type) { @@ -1600,6 +1762,39 @@ DWARFASTParserClang::ParseTypeFromDWARF (const SymbolContext& sc, if (byte_stride == 0 && bit_stride == 0) byte_stride = element_type->GetByteSize(); CompilerType array_element_type = element_type->GetForwardCompilerType (); + + if (ClangASTContext::IsCXXClassType(array_element_type) && array_element_type.GetCompleteType() == false) + { + ModuleSP module_sp = die.GetModule(); + if (module_sp) + { + if (die.GetCU()->GetProducer() == DWARFCompileUnit::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 -fno-limit-debug-info or disable -gmodule", + die.GetOffset(), + type_die_ref.die_offset); + 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_ref.die_offset, + die.GetLLDBCompileUnit() ? die.GetLLDBCompileUnit()->GetPath().c_str() : "the source file"); + } + + // 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_ref.die_offset); + } + } + uint64_t array_element_bit_stride = byte_stride * 8 + bit_stride; if (element_orders.size() > 0) { @@ -1628,7 +1823,7 @@ DWARFASTParserClang::ParseTypeFromDWARF (const SymbolContext& sc, empty_name, array_element_bit_stride / 8, NULL, - DIERef(type_die_form).GetUID(), + DIERef(type_die_form).GetUID(dwarf), Type::eEncodingIsUID, &decl, clang_type, @@ -1663,8 +1858,8 @@ DWARFASTParserClang::ParseTypeFromDWARF (const SymbolContext& sc, } } - Type *pointee_type = dwarf->ResolveTypeUID(DIERef(type_die_form).GetUID()); - Type *class_type = dwarf->ResolveTypeUID(DIERef(containing_type_die_form).GetUID()); + Type *pointee_type = dwarf->ResolveTypeUID(DIERef(type_die_form)); + Type *class_type = dwarf->ResolveTypeUID(DIERef(containing_type_die_form)); CompilerType pointee_clang_type = pointee_type->GetForwardCompilerType (); CompilerType class_clang_type = class_type->GetLayoutCompilerType (); @@ -1812,8 +2007,7 @@ DWARFASTParserClang::ParseTemplateDIE (const DWARFDIE &die, { DWARFAttributes attributes; const size_t num_attributes = die.GetAttributes (attributes); - const char *name = NULL; - Type *lldb_type = NULL; + const char *name = nullptr; CompilerType clang_type; uint64_t uval64 = 0; bool uval64_valid = false; @@ -1834,7 +2028,7 @@ DWARFASTParserClang::ParseTemplateDIE (const DWARFDIE &die, case DW_AT_type: if (attributes.ExtractFormValueAtIndex(i, form_value)) { - lldb_type = die.ResolveTypeUID(DIERef(form_value).GetUID()); + Type *lldb_type = die.ResolveTypeUID(DIERef(form_value)); if (lldb_type) clang_type = lldb_type->GetForwardCompilerType (); } @@ -1864,19 +2058,19 @@ DWARFASTParserClang::ParseTemplateDIE (const DWARFDIE &die, else template_param_infos.names.push_back(NULL); - if (tag == DW_TAG_template_value_parameter && - lldb_type != NULL && - clang_type.IsIntegerType (is_signed) && - uval64_valid) + // Get the signed value for any integer or enumeration if available + clang_type.IsIntegerOrEnumerationType (is_signed); + + if (tag == DW_TAG_template_value_parameter && uval64_valid) { - llvm::APInt apint (lldb_type->GetByteSize() * 8, uval64, is_signed); - template_param_infos.args.push_back (clang::TemplateArgument (*ast, - llvm::APSInt(apint), - ClangASTContext::GetQualType(clang_type))); + llvm::APInt apint (clang_type.GetBitSize(nullptr), uval64, is_signed); + template_param_infos.args.push_back( + clang::TemplateArgument(*ast, llvm::APSInt(apint, !is_signed), ClangUtil::GetQualType(clang_type))); } else { - template_param_infos.args.push_back (clang::TemplateArgument (ClangASTContext::GetQualType(clang_type))); + template_param_infos.args.push_back( + clang::TemplateArgument(ClangUtil::GetQualType(clang_type))); } } else @@ -1926,37 +2120,12 @@ DWARFASTParserClang::ParseTemplateParameterInfos (const DWARFDIE &parent_die, } bool -DWARFASTParserClang::CanCompleteType (const lldb_private::CompilerType &compiler_type) +DWARFASTParserClang::CompleteTypeFromDWARF(const DWARFDIE &die, lldb_private::Type *type, CompilerType &clang_type) { - if (m_clang_ast_importer_ap) - return ClangASTContext::CanImport(compiler_type, GetClangASTImporter()); - else - return false; -} + SymbolFileDWARF *dwarf = die.GetDWARF(); -bool -DWARFASTParserClang::CompleteType (const lldb_private::CompilerType &compiler_type) -{ - if (CanCompleteType(compiler_type)) - { - if (ClangASTContext::Import(compiler_type, GetClangASTImporter())) - { - ClangASTContext::CompleteTagDeclarationDefinition(compiler_type); - return true; - } - else - { - ClangASTContext::SetHasExternalStorage (compiler_type.GetOpaqueQualType(), false); - } - } - return false; -} + std::lock_guard<std::recursive_mutex> guard(dwarf->GetObjectFile()->GetModule()->GetMutex()); -bool -DWARFASTParserClang::CompleteTypeFromDWARF (const DWARFDIE &die, - lldb_private::Type *type, - CompilerType &clang_type) -{ // Disable external storage for this type so we don't get anymore // clang::ExternalASTSource queries for this type. m_ast.SetHasExternalStorage (clang_type.GetOpaqueQualType(), false); @@ -1964,9 +2133,45 @@ DWARFASTParserClang::CompleteTypeFromDWARF (const DWARFDIE &die, if (!die) return false; - const dw_tag_t tag = die.Tag(); +#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 - SymbolFileDWARF *dwarf = die.GetDWARF(); + const dw_tag_t tag = die.Tag(); Log *log = nullptr; // (LogChannelDWARF::GetLogIfAny(DWARF_LOG_DEBUG_INFO|DWARF_LOG_TYPE_COMPLETION)); if (log) @@ -1983,7 +2188,7 @@ DWARFASTParserClang::CompleteTypeFromDWARF (const DWARFDIE &die, case DW_TAG_union_type: case DW_TAG_class_type: { - LayoutInfo layout_info; + ClangASTImporter::LayoutInfo layout_info; { if (die.HasChildren()) @@ -2080,7 +2285,7 @@ DWARFASTParserClang::CompleteTypeFromDWARF (const DWARFDIE &die, if (class_language != eLanguageTypeObjC) { if (is_a_class && tag_decl_kind != clang::TTK_Class) - m_ast.SetTagTypeKind (ClangASTContext::GetQualType(clang_type), clang::TTK_Class); + m_ast.SetTagTypeKind(ClangUtil::GetQualType(clang_type), clang::TTK_Class); } // Since DW_TAG_structure_type gets used for both classes @@ -2130,8 +2335,10 @@ DWARFASTParserClang::CompleteTypeFromDWARF (const DWARFDIE &die, // 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. - ClangASTContext::StartTagDeclarationDefinition (base_class_type); - ClangASTContext::CompleteTagDeclarationDefinition (base_class_type); + if (ClangASTContext::StartTagDeclarationDefinition (base_class_type)) + { + ClangASTContext::CompleteTagDeclarationDefinition (base_class_type); + } } } } @@ -2219,7 +2426,7 @@ DWARFASTParserClang::CompleteTypeFromDWARF (const DWARFDIE &die, } } - m_record_decl_to_layout_map.insert(std::make_pair(record_decl, layout_info)); + GetClangASTImporter().InsertRecordDecl(record_decl, layout_info); } } } @@ -2227,15 +2434,17 @@ DWARFASTParserClang::CompleteTypeFromDWARF (const DWARFDIE &die, return (bool)clang_type; case DW_TAG_enumeration_type: - ClangASTContext::StartTagDeclarationDefinition (clang_type); - if (die.HasChildren()) + if (ClangASTContext::StartTagDeclarationDefinition (clang_type)) { - SymbolContext sc(die.GetLLDBCompileUnit()); - bool is_signed = false; - clang_type.IsIntegerType(is_signed); - ParseChildEnumerators(sc, clang_type, is_signed, type->GetByteSize(), die); + if (die.HasChildren()) + { + SymbolContext sc(die.GetLLDBCompileUnit()); + bool is_signed = false; + clang_type.IsIntegerType(is_signed); + ParseChildEnumerators(sc, clang_type, is_signed, type->GetByteSize(), die); + } + ClangASTContext::CompleteTagDeclarationDefinition (clang_type); } - ClangASTContext::CompleteTagDeclarationDefinition (clang_type); return (bool)clang_type; default: @@ -2484,6 +2693,7 @@ DWARFASTParserClang::ParseFunctionFromDWARF (const SymbolContext& sc, // never mangled. bool is_static = false; bool is_variadic = false; + bool has_template_params = false; unsigned type_quals = 0; std::vector<CompilerType> param_types; std::vector<clang::ParmVarDecl*> param_decls; @@ -2500,6 +2710,7 @@ DWARFASTParserClang::ParseFunctionFromDWARF (const SymbolContext& sc, true, is_static, is_variadic, + has_template_params, param_types, param_decls, type_quals); @@ -2557,23 +2768,22 @@ DWARFASTParserClang::ParseFunctionFromDWARF (const SymbolContext& sc, return NULL; } - bool -DWARFASTParserClang::ParseChildMembers (const SymbolContext& sc, - const DWARFDIE &parent_die, - CompilerType &class_clang_type, - const LanguageType class_language, - std::vector<clang::CXXBaseSpecifier *>& base_classes, - std::vector<int>& member_accessibilities, - DWARFDIECollection& member_function_dies, - DelayedPropertyList& delayed_properties, - AccessType& default_accessibility, - bool &is_a_class, - LayoutInfo &layout_info) +DWARFASTParserClang::ParseChildMembers(const SymbolContext &sc, const DWARFDIE &parent_die, + CompilerType &class_clang_type, const LanguageType class_language, + std::vector<clang::CXXBaseSpecifier *> &base_classes, + std::vector<int> &member_accessibilities, + DWARFDIECollection &member_function_dies, + DelayedPropertyList &delayed_properties, AccessType &default_accessibility, + bool &is_a_class, ClangASTImporter::LayoutInfo &layout_info) { if (!parent_die) return 0; + // 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) * 8; + 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; @@ -2607,9 +2817,10 @@ DWARFASTParserClang::ParseChildMembers (const SymbolContext& sc, bool is_artificial = false; DWARFFormValue encoding_form; AccessType accessibility = eAccessNone; - uint32_t member_byte_offset = UINT32_MAX; + uint32_t member_byte_offset = (parent_die.Tag() == DW_TAG_union_type) ? 0 : UINT32_MAX; size_t byte_size = 0; - size_t bit_offset = 0; + 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; @@ -2626,9 +2837,10 @@ DWARFASTParserClang::ParseChildMembers (const SymbolContext& sc, case DW_AT_decl_column: decl.SetColumn(form_value.Unsigned()); break; 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.Unsigned(); 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()) { @@ -2637,10 +2849,10 @@ DWARFASTParserClang::ParseChildMembers (const SymbolContext& sc, const DWARFDataExtractor& debug_info_data = die.GetDWARF()->get_debug_info_data(); uint32_t block_length = form_value.Unsigned(); uint32_t block_offset = form_value.BlockData() - debug_info_data.GetDataStart(); - if (DWARFExpression::Evaluate(NULL, // ExecutionContext * - NULL, // ClangExpressionVariableList * - NULL, // ClangExpressionDeclMap * - NULL, // RegisterContext * + if (DWARFExpression::Evaluate(nullptr, // ExecutionContext * + nullptr, // ClangExpressionVariableList * + nullptr, // ClangExpressionDeclMap * + nullptr, // RegisterContext * module_sp, debug_info_data, die.GetCU(), @@ -2648,8 +2860,9 @@ DWARFASTParserClang::ParseChildMembers (const SymbolContext& sc, block_length, eRegisterKindDWARF, &initialValue, + nullptr, memberOffset, - NULL)) + nullptr)) { member_byte_offset = memberOffset.ResolveValue(NULL).UInt(); } @@ -2739,7 +2952,7 @@ DWARFASTParserClang::ParseChildMembers (const SymbolContext& sc, // type in an expression when clang becomes unhappy with its // recycled debug info. - if (bit_offset > 128) + if (byte_size == 0 && bit_offset < 0) { bit_size = 0; bit_offset = 0; @@ -2764,7 +2977,7 @@ DWARFASTParserClang::ParseChildMembers (const SymbolContext& sc, // Handle static members if (is_external && member_byte_offset == UINT32_MAX) { - Type *var_type = die.ResolveTypeUID(DIERef(encoding_form).GetUID()); + Type *var_type = die.ResolveTypeUID(DIERef(encoding_form)); if (var_type) { @@ -2780,7 +2993,7 @@ DWARFASTParserClang::ParseChildMembers (const SymbolContext& sc, if (is_artificial == false) { - Type *member_type = die.ResolveTypeUID(DIERef(encoding_form).GetUID()); + Type *member_type = die.ResolveTypeUID(DIERef(encoding_form)); clang::FieldDecl *field_decl = NULL; if (tag == DW_TAG_member) @@ -2815,17 +3028,38 @@ DWARFASTParserClang::ParseChildMembers (const SymbolContext& sc, // AT_bit_size indicates the size of the field in bits. ///////////////////////////////////////////////////////////// - if (byte_size == 0) - byte_size = member_type->GetByteSize(); - - if (die.GetDWARF()->GetObjectFile()->GetByteOrder() == eByteOrderLittle) + if (data_bit_offset != UINT64_MAX) { - this_field_info.bit_offset += byte_size * 8; - this_field_info.bit_offset -= (bit_offset + bit_size); + this_field_info.bit_offset = data_bit_offset; } else { - this_field_info.bit_offset += bit_offset; + if (byte_size == 0) + byte_size = member_type->GetByteSize(); + + ObjectFile *objfile = die.GetDWARF()->GetObjectFile(); + if (objfile->GetByteOrder() == eByteOrderLittle) + { + this_field_info.bit_offset += byte_size * 8; + this_field_info.bit_offset -= (bit_offset + bit_size); + } + else + { + this_field_info.bit_offset += bit_offset; + } + } + + 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, + sc.comp_unit ? sc.comp_unit->GetPath().c_str() : "the source file"); + this_field_info.Clear(); + continue; } // Update the field bit offset we will report for layout @@ -2962,8 +3196,18 @@ DWARFASTParserClang::ParseChildMembers (const SymbolContext& sc, // 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. - ClangASTContext::StartTagDeclarationDefinition(member_clang_type); - ClangASTContext::CompleteTagDeclarationDefinition(member_clang_type); + 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); + } } field_decl = ClangASTContext::AddFieldToRecordType (class_clang_type, @@ -3063,10 +3307,10 @@ DWARFASTParserClang::ParseChildMembers (const SymbolContext& sc, const DWARFDataExtractor& debug_info_data = die.GetDWARF()->get_debug_info_data(); uint32_t block_length = form_value.Unsigned(); uint32_t block_offset = form_value.BlockData() - debug_info_data.GetDataStart(); - if (DWARFExpression::Evaluate (NULL, - NULL, - NULL, - NULL, + if (DWARFExpression::Evaluate (nullptr, + nullptr, + nullptr, + nullptr, module_sp, debug_info_data, die.GetCU(), @@ -3074,8 +3318,9 @@ DWARFASTParserClang::ParseChildMembers (const SymbolContext& sc, block_length, eRegisterKindDWARF, &initialValue, + nullptr, memberOffset, - NULL)) + nullptr)) { member_byte_offset = memberOffset.ResolveValue(NULL).UInt(); } @@ -3106,7 +3351,7 @@ DWARFASTParserClang::ParseChildMembers (const SymbolContext& sc, } } - Type *base_class_type = die.ResolveTypeUID(DIERef(encoding_form).GetUID()); + Type *base_class_type = die.ResolveTypeUID(DIERef(encoding_form)); if (base_class_type == NULL) { module_sp->ReportError("0x%8.8x: DW_TAG_inheritance failed to resolve the base class at 0x%8.8" PRIx64 " from enclosing type 0x%8.8x. \nPlease file a bug and attach the file at the start of this error message", @@ -3166,6 +3411,7 @@ DWARFASTParserClang::ParseChildParameters (const SymbolContext& sc, bool skip_artificial, bool &is_static, bool &is_variadic, + bool &has_template_params, std::vector<CompilerType>& function_param_types, std::vector<clang::ParmVarDecl*>& function_param_decls, unsigned &type_quals) @@ -3251,7 +3497,7 @@ DWARFASTParserClang::ParseChildParameters (const SymbolContext& sc, // being in the formal parameter DIE... if (name == NULL || ::strcmp(name, "this")==0) { - Type *this_type = die.ResolveTypeUID (DIERef(param_type_die_form).GetUID()); + Type *this_type = die.ResolveTypeUID (DIERef(param_type_die_form)); if (this_type) { uint32_t encoding_mask = this_type->GetEncodingMask(); @@ -3294,7 +3540,7 @@ DWARFASTParserClang::ParseChildParameters (const SymbolContext& sc, if (!skip) { - Type *type = die.ResolveTypeUID(DIERef(param_type_die_form).GetUID()); + Type *type = die.ResolveTypeUID(DIERef(param_type_die_form)); if (type) { function_param_types.push_back (type->GetForwardCompilerType ()); @@ -3324,6 +3570,7 @@ DWARFASTParserClang::ParseChildParameters (const SymbolContext& sc, // in SymbolFileDWARF::ParseType() so this was removed. If we ever need // the template params back, we can add them back. // ParseTemplateDIE (dwarf_cu, die, template_param_infos); + has_template_params = true; break; default: @@ -3440,7 +3687,7 @@ DWARFASTParserClang::GetTypeForDIE (const DWARFDIE &die) DWARFFormValue form_value; if (attr == DW_AT_type && attributes.ExtractFormValueAtIndex(i, form_value)) - return dwarf->ResolveTypeUID(DIERef(form_value).GetUID()); + return dwarf->ResolveTypeUID(dwarf->GetDIE (DIERef(form_value)), true); } } } @@ -3477,6 +3724,14 @@ DWARFASTParserClang::GetClangDeclForDIE (const DWARFDIE &die) m_decl_to_die[decl].insert(die.GetDIE()); return decl; } + + if (DWARFDIE abstract_origin_die = die.GetReferencedDIE(DW_AT_abstract_origin)) + { + clang::Decl *decl = GetClangDeclForDIE(abstract_origin_die); + m_die_to_decl[die.GetDIE()] = decl; + m_decl_to_die[decl].insert(die.GetDIE()); + return decl; + } clang::Decl *decl = nullptr; switch (die.Tag()) @@ -3487,22 +3742,23 @@ DWARFASTParserClang::GetClangDeclForDIE (const DWARFDIE &die) { SymbolFileDWARF *dwarf = die.GetDWARF(); Type *type = GetTypeForDIE(die); - const char *name = die.GetName(); - clang::DeclContext *decl_context = ClangASTContext::DeclContextGetAsDeclContext(dwarf->GetDeclContextContainingUID(die.GetID())); - decl = m_ast.CreateVariableDeclaration( - decl_context, - name, - ClangASTContext::GetQualType(type->GetForwardCompilerType())); + if (dwarf && type) + { + const char *name = die.GetName(); + clang::DeclContext *decl_context = + ClangASTContext::DeclContextGetAsDeclContext(dwarf->GetDeclContextContainingUID(die.GetID())); + decl = m_ast.CreateVariableDeclaration(decl_context, name, + ClangUtil::GetQualType(type->GetForwardCompilerType())); + } break; } case DW_TAG_imported_declaration: { SymbolFileDWARF *dwarf = die.GetDWARF(); - lldb::user_id_t imported_uid = die.GetAttributeValueAsReference(DW_AT_import, DW_INVALID_OFFSET); - - if (dwarf->UserIDMatches(imported_uid)) + DWARFDIE imported_uid = die.GetAttributeValueAsReferenceDIE(DW_AT_import); + if (imported_uid) { - CompilerDecl imported_decl = dwarf->GetDeclForUID(imported_uid); + CompilerDecl imported_decl = imported_uid.GetDecl(); if (imported_decl) { clang::DeclContext *decl_context = ClangASTContext::DeclContextGetAsDeclContext(dwarf->GetDeclContextContainingUID(die.GetID())); @@ -3515,15 +3771,15 @@ DWARFASTParserClang::GetClangDeclForDIE (const DWARFDIE &die) case DW_TAG_imported_module: { SymbolFileDWARF *dwarf = die.GetDWARF(); - lldb::user_id_t imported_uid = die.GetAttributeValueAsReference(DW_AT_import, DW_INVALID_OFFSET); + DWARFDIE imported_uid = die.GetAttributeValueAsReferenceDIE(DW_AT_import); - if (dwarf->UserIDMatches(imported_uid)) + if (imported_uid) { - CompilerDeclContext imported_decl = dwarf->GetDeclContextForUID(imported_uid); - if (imported_decl) + CompilerDeclContext imported_decl_ctx = imported_uid.GetDeclContext(); + if (imported_decl_ctx) { clang::DeclContext *decl_context = ClangASTContext::DeclContextGetAsDeclContext(dwarf->GetDeclContextContainingUID(die.GetID())); - if (clang::NamespaceDecl *ns_decl = ClangASTContext::DeclContextGetAsNamespaceDecl(imported_decl)) + if (clang::NamespaceDecl *ns_decl = ClangASTContext::DeclContextGetAsNamespaceDecl(imported_decl_ctx)) decl = m_ast.CreateUsingDirectiveDeclaration(decl_context, ns_decl); } } @@ -4001,34 +4257,3 @@ DWARFASTParserClang::CopyUniqueClassMethodTypes (const DWARFDIE &src_class_die, return (failures.Size() != 0); } - -bool -DWARFASTParserClang::LayoutRecordType(const clang::RecordDecl *record_decl, - uint64_t &bit_size, - uint64_t &alignment, - llvm::DenseMap<const clang::FieldDecl *, uint64_t> &field_offsets, - llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits> &base_offsets, - llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits> &vbase_offsets) -{ - RecordDeclToLayoutMap::iterator pos = m_record_decl_to_layout_map.find (record_decl); - bool success = false; - base_offsets.clear(); - vbase_offsets.clear(); - if (pos != m_record_decl_to_layout_map.end()) - { - bit_size = pos->second.bit_size; - alignment = pos->second.alignment; - field_offsets.swap(pos->second.field_offsets); - base_offsets.swap (pos->second.base_offsets); - vbase_offsets.swap (pos->second.vbase_offsets); - m_record_decl_to_layout_map.erase(pos); - success = true; - } - else - { - bit_size = 0; - alignment = 0; - field_offsets.clear(); - } - return success; -} diff --git a/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h b/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h index 3814758fdd2cf..0826423b0359f 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h +++ b/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h @@ -19,11 +19,12 @@ #include "clang/AST/CharUnits.h" // Project includes +#include "DWARFASTParser.h" +#include "DWARFDefines.h" #include "lldb/Core/ClangForward.h" #include "lldb/Core/PluginInterface.h" #include "lldb/Symbol/ClangASTContext.h" -#include "DWARFDefines.h" -#include "DWARFASTParser.h" +#include "lldb/Symbol/ClangASTImporter.h" class DWARFDebugInfoEntry; class DWARFDIECollection; @@ -35,6 +36,7 @@ public: ~DWARFASTParserClang() override; + // DWARFASTParser interface. lldb::TypeSP ParseTypeFromDWARF (const lldb_private::SymbolContext& sc, const DWARFDIE &die, @@ -47,12 +49,6 @@ public: const DWARFDIE &die) override; bool - CanCompleteType (const lldb_private::CompilerType &compiler_type) override; - - bool - CompleteType (const lldb_private::CompilerType &compiler_type) override; - - bool CompleteTypeFromDWARF (const DWARFDIE &die, lldb_private::Type *type, lldb_private::CompilerType &compiler_type) override; @@ -69,43 +65,19 @@ public: lldb_private::CompilerDeclContext GetDeclContextContainingUIDFromDWARF (const DWARFDIE &die) override; - bool - LayoutRecordType(const clang::RecordDecl *record_decl, - uint64_t &bit_size, - uint64_t &alignment, - llvm::DenseMap<const clang::FieldDecl *, uint64_t> &field_offsets, - llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits> &base_offsets, - llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits> &vbase_offsets); + lldb_private::ClangASTImporter & + GetClangASTImporter(); protected: class DelayedAddObjCClassProperty; typedef std::vector <DelayedAddObjCClassProperty> DelayedPropertyList; - struct LayoutInfo - { - LayoutInfo () : - bit_size(0), - alignment(0), - field_offsets(), - base_offsets(), - vbase_offsets() - { - } - uint64_t bit_size; - uint64_t alignment; - llvm::DenseMap<const clang::FieldDecl *, uint64_t> field_offsets; - llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits> base_offsets; - llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits> vbase_offsets; - }; - clang::BlockDecl * ResolveBlockDIE (const DWARFDIE &die); clang::NamespaceDecl * ResolveNamespaceDIE (const DWARFDIE &die); - typedef llvm::DenseMap<const clang::RecordDecl *, LayoutInfo> RecordDeclToLayoutMap; - bool ParseTemplateDIE (const DWARFDIE &die, lldb_private::ClangASTContext::TemplateParameterInfos &template_param_infos); @@ -114,17 +86,12 @@ protected: lldb_private::ClangASTContext::TemplateParameterInfos &template_param_infos); bool - ParseChildMembers (const lldb_private::SymbolContext& sc, - const DWARFDIE &die, - lldb_private::CompilerType &class_compiler_type, - const lldb::LanguageType class_language, - std::vector<clang::CXXBaseSpecifier *>& base_classes, - std::vector<int>& member_accessibilities, - DWARFDIECollection& member_function_dies, - DelayedPropertyList& delayed_properties, - lldb::AccessType &default_accessibility, - bool &is_a_class, - LayoutInfo &layout_info); + ParseChildMembers(const lldb_private::SymbolContext &sc, const DWARFDIE &die, + lldb_private::CompilerType &class_compiler_type, const lldb::LanguageType class_language, + std::vector<clang::CXXBaseSpecifier *> &base_classes, std::vector<int> &member_accessibilities, + DWARFDIECollection &member_function_dies, DelayedPropertyList &delayed_properties, + lldb::AccessType &default_accessibility, bool &is_a_class, + lldb_private::ClangASTImporter::LayoutInfo &layout_info); size_t ParseChildParameters (const lldb_private::SymbolContext& sc, @@ -133,6 +100,7 @@ protected: bool skip_artificial, bool &is_static, bool &is_variadic, + bool &has_template_params, std::vector<lldb_private::CompilerType>& function_args, std::vector<clang::ParmVarDecl*>& function_param_decls, unsigned &type_quals); @@ -181,9 +149,6 @@ protected: void LinkDeclToDIE (clang::Decl *decl, const DWARFDIE &die); - lldb_private::ClangASTImporter & - GetClangASTImporter(); - lldb::TypeSP ParseTypeFromDWO (const DWARFDIE &die, lldb_private::Log *log); @@ -206,7 +171,6 @@ protected: DeclToDIEMap m_decl_to_die; DIEToDeclContextMap m_die_to_decl_ctx; DeclContextToDIEMap m_decl_ctx_to_die; - RecordDeclToLayoutMap m_record_decl_to_layout_map; std::unique_ptr<lldb_private::ClangASTImporter> m_clang_ast_importer_ap; }; diff --git a/source/Plugins/SymbolFile/DWARF/DWARFASTParserGo.cpp b/source/Plugins/SymbolFile/DWARF/DWARFASTParserGo.cpp index bde2694461e2e..346e2d63b9082 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFASTParserGo.cpp +++ b/source/Plugins/SymbolFile/DWARF/DWARFASTParserGo.cpp @@ -144,7 +144,7 @@ DWARFASTParserGo::ParseTypeFromDWARF(const lldb_private::SymbolContext &sc, cons } } - DEBUG_PRINTF("0x%8.8" PRIx64 ": %s (\"%s\") type => 0x%8.8lx\n", dwarf->MakeUserID(die.GetOffset()), + 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); switch (tag) @@ -183,7 +183,7 @@ DWARFASTParserGo::ParseTypeFromDWARF(const lldb_private::SymbolContext &sc, cons break; } - type_sp.reset(new Type(dwarf->MakeUserID(die.GetOffset()), dwarf, type_name_const_str, byte_size, + type_sp.reset(new Type(die.GetID(), dwarf, type_name_const_str, byte_size, NULL, encoding_uid, encoding_data_type, &decl, compiler_type, resolve_state)); dwarf->m_die_to_type[die.GetDIE()] = type_sp.get(); @@ -254,7 +254,7 @@ DWARFASTParserGo::ParseTypeFromDWARF(const lldb_private::SymbolContext &sc, cons } } - DEBUG_PRINTF("0x%8.8" PRIx64 ": %s (\"%s\")\n", dwarf->MakeUserID(die.GetOffset()), + DEBUG_PRINTF("0x%8.8" PRIx64 ": %s (\"%s\")\n", die.GetID(), DW_TAG_value_to_name(tag), type_name_cstr); bool compiler_type_was_created = false; @@ -265,7 +265,7 @@ DWARFASTParserGo::ParseTypeFromDWARF(const lldb_private::SymbolContext &sc, cons compiler_type = m_ast.CreateStructType(go_kind, type_name_const_str, byte_size); } - type_sp.reset(new Type(dwarf->MakeUserID(die.GetOffset()), dwarf, type_name_const_str, byte_size, + type_sp.reset(new Type(die.GetID(), dwarf, type_name_const_str, byte_size, NULL, LLDB_INVALID_UID, Type::eEncodingIsUID, &decl, compiler_type, Type::eResolveStateForward)); @@ -347,7 +347,7 @@ DWARFASTParserGo::ParseTypeFromDWARF(const lldb_private::SymbolContext &sc, cons } } - DEBUG_PRINTF("0x%8.8" PRIx64 ": %s (\"%s\")\n", dwarf->MakeUserID(die.GetOffset()), + DEBUG_PRINTF("0x%8.8" PRIx64 ": %s (\"%s\")\n", die.GetID(), DW_TAG_value_to_name(tag), type_name_cstr); std::vector<CompilerType> function_param_types; @@ -363,7 +363,7 @@ DWARFASTParserGo::ParseTypeFromDWARF(const lldb_private::SymbolContext &sc, cons compiler_type = m_ast.CreateFunctionType(type_name_const_str, function_param_types.data(), function_param_types.size(), is_variadic); - type_sp.reset(new Type(dwarf->MakeUserID(die.GetOffset()), dwarf, type_name_const_str, 0, NULL, + type_sp.reset(new Type(die.GetID(), dwarf, type_name_const_str, 0, NULL, LLDB_INVALID_UID, Type::eEncodingIsUID, &decl, compiler_type, Type::eResolveStateFull)); assert(type_sp.get()); @@ -410,7 +410,7 @@ DWARFASTParserGo::ParseTypeFromDWARF(const lldb_private::SymbolContext &sc, cons } } - DEBUG_PRINTF("0x%8.8" PRIx64 ": %s (\"%s\")\n", dwarf->MakeUserID(die.GetOffset()), + DEBUG_PRINTF("0x%8.8" PRIx64 ": %s (\"%s\")\n", die.GetID(), DW_TAG_value_to_name(tag), type_name_cstr); Type *element_type = dwarf->ResolveTypeUID(type_die_offset); @@ -433,7 +433,7 @@ DWARFASTParserGo::ParseTypeFromDWARF(const lldb_private::SymbolContext &sc, cons { compiler_type = m_ast.CreateArrayType(type_name_const_str, array_element_type, 0); } - type_sp.reset(new Type(dwarf->MakeUserID(die.GetOffset()), dwarf, type_name_const_str, + type_sp.reset(new Type(die.GetID(), dwarf, type_name_const_str, byte_stride, NULL, type_die_offset, Type::eEncodingIsUID, &decl, compiler_type, Type::eResolveStateFull)); type_sp->SetEncodingType(element_type); @@ -463,7 +463,7 @@ DWARFASTParserGo::ParseTypeFromDWARF(const lldb_private::SymbolContext &sc, cons else if (sc.function != NULL && sc_parent_die) { symbol_context_scope = - sc.function->GetBlock(true).FindBlockByID(dwarf->MakeUserID(sc_parent_die.GetOffset())); + sc.function->GetBlock(true).FindBlockByID(sc_parent_die.GetID()); if (symbol_context_scope == NULL) symbol_context_scope = sc.function; } @@ -510,7 +510,7 @@ DWARFASTParserGo::ParseChildParameters(const SymbolContext &sc, if (num_attributes > 0) { Declaration decl; - dw_offset_t param_type_die_offset = DW_INVALID_OFFSET; + DWARFFormValue param_type_die_offset; uint32_t i; for (i = 0; i < num_attributes; ++i) @@ -525,7 +525,7 @@ DWARFASTParserGo::ParseChildParameters(const SymbolContext &sc, // = form_value.AsCString(); break; case DW_AT_type: - param_type_die_offset = form_value.Reference(); + param_type_die_offset = form_value; break; case DW_AT_location: // if (form_value.BlockData()) @@ -547,7 +547,7 @@ DWARFASTParserGo::ParseChildParameters(const SymbolContext &sc, } } - Type *type = parent_die.ResolveTypeUID(param_type_die_offset); + Type *type = parent_die.ResolveTypeUID(DIERef(param_type_die_offset)); if (type) { function_param_types.push_back(type->GetForwardCompilerType()); @@ -628,7 +628,7 @@ DWARFASTParserGo::CompleteTypeFromDWARF(const DWARFDIE &die, lldb_private::Type Log *log = nullptr; // (LogChannelDWARF::GetLogIfAny(DWARF_LOG_DEBUG_INFO|DWARF_LOG_TYPE_COMPLETION)); if (log) dwarf->GetObjectFile()->GetModule()->LogMessageVerboseBacktrace( - log, "0x%8.8" PRIx64 ": %s '%s' resolving forward declaration...", dwarf->MakeUserID(die.GetOffset()), + log, "0x%8.8" PRIx64 ": %s '%s' resolving forward declaration...", die.GetID(), DW_TAG_value_to_name(tag), type->GetName().AsCString()); assert(compiler_type); DWARFAttributes attributes; @@ -683,7 +683,7 @@ DWARFASTParserGo::ParseChildMembers(const SymbolContext &sc, const DWARFDIE &par Declaration decl; const char *name = NULL; - lldb::user_id_t encoding_uid = LLDB_INVALID_UID; + DWARFFormValue encoding_uid; uint32_t member_byte_offset = UINT32_MAX; uint32_t i; for (i = 0; i < num_attributes; ++i) @@ -698,7 +698,7 @@ DWARFASTParserGo::ParseChildMembers(const SymbolContext &sc, const DWARFDIE &par name = form_value.AsCString(); break; case DW_AT_type: - encoding_uid = form_value.Reference(); + encoding_uid = form_value; break; case DW_AT_data_member_location: if (form_value.BlockData()) @@ -715,7 +715,7 @@ DWARFASTParserGo::ParseChildMembers(const SymbolContext &sc, const DWARFDIE &par NULL, // RegisterContext * module_sp, debug_info_data, die.GetCU(), block_offset, block_length, eRegisterKindDWARF, - &initialValue, memberOffset, NULL)) + &initialValue, NULL, memberOffset, NULL)) { member_byte_offset = memberOffset.ResolveValue(NULL).UInt(); } @@ -735,7 +735,7 @@ DWARFASTParserGo::ParseChildMembers(const SymbolContext &sc, const DWARFDIE &par } } - Type *member_type = die.ResolveTypeUID(encoding_uid); + Type *member_type = die.ResolveTypeUID(DIERef(encoding_uid)); if (member_type) { CompilerType member_go_type = member_type->GetFullCompilerType(); @@ -808,10 +808,12 @@ DWARFASTParserGo::ParseFunctionFromDWARF(const SymbolContext &sc, const DWARFDIE if (dwarf->FixupAddress(func_range.GetBaseAddress())) { - const user_id_t func_user_id = dwarf->MakeUserID(die.GetOffset()); + const user_id_t func_user_id = die.GetID(); func_sp.reset(new Function(sc.comp_unit, - dwarf->MakeUserID(func_user_id), // UserID is the DIE offset - dwarf->MakeUserID(func_user_id), func_name, func_type, + func_user_id, // UserID is the DIE offset + func_user_id, + func_name, + func_type, func_range)); // first address range if (func_sp.get() != NULL) diff --git a/source/Plugins/SymbolFile/DWARF/DWARFASTParserJava.cpp b/source/Plugins/SymbolFile/DWARF/DWARFASTParserJava.cpp new file mode 100644 index 0000000000000..b21bf2ded4899 --- /dev/null +++ b/source/Plugins/SymbolFile/DWARF/DWARFASTParserJava.cpp @@ -0,0 +1,555 @@ +//===-- DWARFASTParserJava.cpp ----------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "DWARFASTParserJava.h" +#include "DWARFAttribute.h" +#include "DWARFCompileUnit.h" +#include "DWARFDebugInfoEntry.h" +#include "DWARFDebugInfoEntry.h" +#include "DWARFDeclContext.h" +#include "SymbolFileDWARF.h" + +#include "lldb/Core/Module.h" +#include "lldb/Symbol/CompileUnit.h" +#include "lldb/Symbol/SymbolContextScope.h" +#include "lldb/Symbol/TypeList.h" + +using namespace lldb; +using namespace lldb_private; + +DWARFASTParserJava::DWARFASTParserJava(JavaASTContext &ast) : m_ast(ast) +{ +} + +DWARFASTParserJava::~DWARFASTParserJava() +{ +} + +TypeSP +DWARFASTParserJava::ParseBaseTypeFromDIE(const DWARFDIE &die) +{ + SymbolFileDWARF *dwarf = die.GetDWARF(); + dwarf->m_die_to_type[die.GetDIE()] = DIE_IS_BEING_PARSED; + + ConstString type_name; + uint64_t byte_size = 0; + + DWARFAttributes attributes; + const size_t num_attributes = die.GetAttributes(attributes); + for (uint32_t i = 0; i < num_attributes; ++i) + { + DWARFFormValue form_value; + dw_attr_t attr = attributes.AttributeAtIndex(i); + if (attributes.ExtractFormValueAtIndex(i, form_value)) + { + switch (attr) + { + case DW_AT_name: + type_name.SetCString(form_value.AsCString()); + break; + case DW_AT_byte_size: + byte_size = form_value.Unsigned(); + break; + case DW_AT_encoding: + break; + default: + assert(false && "Unsupported attribute for DW_TAG_base_type"); + } + } + } + + Declaration decl; + CompilerType compiler_type = m_ast.CreateBaseType(type_name); + return std::make_shared<Type>(die.GetID(), dwarf, type_name, byte_size, nullptr, LLDB_INVALID_UID, + Type::eEncodingIsUID, decl, compiler_type, Type::eResolveStateFull); +} + +TypeSP +DWARFASTParserJava::ParseArrayTypeFromDIE(const DWARFDIE &die) +{ + SymbolFileDWARF *dwarf = die.GetDWARF(); + dwarf->m_die_to_type[die.GetDIE()] = DIE_IS_BEING_PARSED; + + ConstString linkage_name; + DWARFFormValue type_attr_value; + lldb::addr_t data_offset = LLDB_INVALID_ADDRESS; + DWARFExpression length_expression(die.GetCU()); + + DWARFAttributes attributes; + const size_t num_attributes = die.GetAttributes(attributes); + for (uint32_t i = 0; i < num_attributes; ++i) + { + DWARFFormValue form_value; + dw_attr_t attr = attributes.AttributeAtIndex(i); + if (attributes.ExtractFormValueAtIndex(i, form_value)) + { + switch (attr) + { + case DW_AT_linkage_name: + linkage_name.SetCString(form_value.AsCString()); + break; + case DW_AT_type: + type_attr_value = form_value; + break; + case DW_AT_data_member_location: + data_offset = form_value.Unsigned(); + break; + case DW_AT_declaration: + break; + default: + assert(false && "Unsupported attribute for DW_TAG_array_type"); + } + } + } + + for (DWARFDIE child_die = die.GetFirstChild(); child_die.IsValid(); child_die = child_die.GetSibling()) + { + if (child_die.Tag() == DW_TAG_subrange_type) + { + DWARFAttributes attributes; + const size_t num_attributes = child_die.GetAttributes(attributes); + for (uint32_t i = 0; i < num_attributes; ++i) + { + DWARFFormValue form_value; + dw_attr_t attr = attributes.AttributeAtIndex(i); + if (attributes.ExtractFormValueAtIndex(i, form_value)) + { + switch (attr) + { + case DW_AT_count: + if (form_value.BlockData()) + length_expression.CopyOpcodeData(form_value.BlockData(), form_value.Unsigned(), + child_die.GetCU()->GetByteOrder(), + child_die.GetCU()->GetAddressByteSize()); + break; + default: + assert(false && "Unsupported attribute for DW_TAG_subrange_type"); + } + } + } + } + else + { + assert(false && "Unsupported child for DW_TAG_array_type"); + } + } + + DIERef type_die_ref(type_attr_value); + Type *element_type = dwarf->ResolveTypeUID(type_die_ref); + if (!element_type) + return nullptr; + + CompilerType element_compiler_type = element_type->GetForwardCompilerType(); + CompilerType array_compiler_type = + m_ast.CreateArrayType(linkage_name, element_compiler_type, length_expression, data_offset); + + Declaration decl; + TypeSP type_sp(new Type(die.GetID(), dwarf, array_compiler_type.GetTypeName(), -1, nullptr, + type_die_ref.GetUID(dwarf), Type::eEncodingIsUID, &decl, + array_compiler_type, Type::eResolveStateFull)); + type_sp->SetEncodingType(element_type); + return type_sp; +} + +TypeSP +DWARFASTParserJava::ParseReferenceTypeFromDIE(const DWARFDIE &die) +{ + SymbolFileDWARF *dwarf = die.GetDWARF(); + dwarf->m_die_to_type[die.GetDIE()] = DIE_IS_BEING_PARSED; + + Declaration decl; + DWARFFormValue type_attr_value; + + DWARFAttributes attributes; + const size_t num_attributes = die.GetAttributes(attributes); + for (uint32_t i = 0; i < num_attributes; ++i) + { + DWARFFormValue form_value; + dw_attr_t attr = attributes.AttributeAtIndex(i); + if (attributes.ExtractFormValueAtIndex(i, form_value)) + { + switch (attr) + { + case DW_AT_type: + type_attr_value = form_value; + break; + default: + assert(false && "Unsupported attribute for DW_TAG_array_type"); + } + } + } + + DIERef type_die_ref(type_attr_value); + Type *pointee_type = dwarf->ResolveTypeUID(type_die_ref); + if (!pointee_type) + return nullptr; + + CompilerType pointee_compiler_type = pointee_type->GetForwardCompilerType(); + CompilerType reference_compiler_type = m_ast.CreateReferenceType(pointee_compiler_type); + TypeSP type_sp(new Type(die.GetID(), dwarf, reference_compiler_type.GetTypeName(), -1, nullptr, + type_die_ref.GetUID(dwarf), Type::eEncodingIsUID, &decl, + reference_compiler_type, Type::eResolveStateFull)); + type_sp->SetEncodingType(pointee_type); + return type_sp; +} + +lldb::TypeSP +DWARFASTParserJava::ParseClassTypeFromDIE(const DWARFDIE &die, bool &is_new_type) +{ + SymbolFileDWARF *dwarf = die.GetDWARF(); + dwarf->m_die_to_type[die.GetDIE()] = DIE_IS_BEING_PARSED; + + Declaration decl; + ConstString name; + ConstString linkage_name; + bool is_forward_declaration = false; + uint32_t byte_size = 0; + + DWARFAttributes attributes; + const size_t num_attributes = die.GetAttributes(attributes); + for (uint32_t i = 0; i < num_attributes; ++i) + { + DWARFFormValue form_value; + dw_attr_t attr = attributes.AttributeAtIndex(i); + if (attributes.ExtractFormValueAtIndex(i, form_value)) + { + switch (attr) + { + case DW_AT_name: + name.SetCString(form_value.AsCString()); + break; + case DW_AT_declaration: + is_forward_declaration = form_value.Boolean(); + break; + case DW_AT_byte_size: + byte_size = form_value.Unsigned(); + break; + case DW_AT_linkage_name: + linkage_name.SetCString(form_value.AsCString()); + break; + default: + assert(false && "Unsupported attribute for DW_TAG_class_type"); + } + } + } + + UniqueDWARFASTType unique_ast_entry; + if (name) + { + std::string qualified_name; + if (die.GetQualifiedName(qualified_name)) + { + name.SetCString(qualified_name.c_str()); + if (dwarf->GetUniqueDWARFASTTypeMap().Find(name, die, Declaration(), -1, unique_ast_entry)) + { + if (unique_ast_entry.m_type_sp) + { + dwarf->GetDIEToType()[die.GetDIE()] = unique_ast_entry.m_type_sp.get(); + is_new_type = false; + return unique_ast_entry.m_type_sp; + } + } + } + } + + if (is_forward_declaration) + { + DWARFDeclContext die_decl_ctx; + die.GetDWARFDeclContext(die_decl_ctx); + + TypeSP type_sp = dwarf->FindDefinitionTypeForDWARFDeclContext(die_decl_ctx); + if (type_sp) + { + // We found a real definition for this type elsewhere so lets use it + dwarf->GetDIEToType()[die.GetDIE()] = type_sp.get(); + is_new_type = false; + return type_sp; + } + } + + CompilerType compiler_type(&m_ast, dwarf->GetForwardDeclDieToClangType().lookup(die.GetDIE())); + if (!compiler_type) + compiler_type = m_ast.CreateObjectType(name, linkage_name, byte_size); + + is_new_type = true; + TypeSP type_sp(new Type(die.GetID(), dwarf, name, + -1, // byte size isn't specified + nullptr, LLDB_INVALID_UID, Type::eEncodingIsUID, &decl, compiler_type, + Type::eResolveStateForward)); + + // Add our type to the unique type map + unique_ast_entry.m_type_sp = type_sp; + unique_ast_entry.m_die = die; + unique_ast_entry.m_declaration = decl; + unique_ast_entry.m_byte_size = -1; + dwarf->GetUniqueDWARFASTTypeMap().Insert(name, unique_ast_entry); + + if (!is_forward_declaration) + { + // Leave this as a forward declaration until we need to know the details of the type + dwarf->GetForwardDeclDieToClangType()[die.GetDIE()] = compiler_type.GetOpaqueQualType(); + dwarf->GetForwardDeclClangTypeToDie()[compiler_type.GetOpaqueQualType()] = die.GetDIERef(); + } + return type_sp; +} + +lldb::TypeSP +DWARFASTParserJava::ParseTypeFromDWARF(const lldb_private::SymbolContext &sc, const DWARFDIE &die, + lldb_private::Log *log, bool *type_is_new_ptr) +{ + if (type_is_new_ptr) + *type_is_new_ptr = false; + + if (!die) + return nullptr; + + SymbolFileDWARF *dwarf = die.GetDWARF(); + + Type *type_ptr = dwarf->m_die_to_type.lookup(die.GetDIE()); + if (type_ptr == DIE_IS_BEING_PARSED) + return nullptr; + if (type_ptr != nullptr) + return type_ptr->shared_from_this(); + + TypeSP type_sp; + if (type_is_new_ptr) + *type_is_new_ptr = true; + + switch (die.Tag()) + { + case DW_TAG_base_type: + { + type_sp = ParseBaseTypeFromDIE(die); + break; + } + case DW_TAG_array_type: + { + type_sp = ParseArrayTypeFromDIE(die); + break; + } + case DW_TAG_class_type: + { + bool is_new_type = false; + type_sp = ParseClassTypeFromDIE(die, is_new_type); + if (!is_new_type) + return type_sp; + break; + } + case DW_TAG_reference_type: + { + type_sp = ParseReferenceTypeFromDIE(die); + break; + } + } + + if (!type_sp) + return nullptr; + + DWARFDIE sc_parent_die = SymbolFileDWARF::GetParentSymbolContextDIE(die); + dw_tag_t sc_parent_tag = sc_parent_die.Tag(); + + SymbolContextScope *symbol_context_scope = nullptr; + if (sc_parent_tag == DW_TAG_compile_unit) + { + symbol_context_scope = sc.comp_unit; + } + else if (sc.function != nullptr && sc_parent_die) + { + symbol_context_scope = sc.function->GetBlock(true).FindBlockByID(sc_parent_die.GetID()); + if (symbol_context_scope == nullptr) + symbol_context_scope = sc.function; + } + + if (symbol_context_scope != nullptr) + type_sp->SetSymbolContextScope(symbol_context_scope); + + dwarf->GetTypeList()->Insert(type_sp); + dwarf->m_die_to_type[die.GetDIE()] = type_sp.get(); + + return type_sp; +} + +lldb_private::Function * +DWARFASTParserJava::ParseFunctionFromDWARF(const lldb_private::SymbolContext &sc, const DWARFDIE &die) +{ + assert(die.Tag() == DW_TAG_subprogram); + + const char *name = nullptr; + const char *mangled = nullptr; + int decl_file = 0; + int decl_line = 0; + int decl_column = 0; + int call_file = 0; + int call_line = 0; + int call_column = 0; + DWARFRangeList func_ranges; + DWARFExpression frame_base(die.GetCU()); + + if (die.GetDIENamesAndRanges(name, mangled, func_ranges, decl_file, decl_line, decl_column, call_file, call_line, + call_column, &frame_base)) + { + // Union of all ranges in the function DIE (if the function is discontiguous) + AddressRange func_range; + lldb::addr_t lowest_func_addr = func_ranges.GetMinRangeBase(0); + lldb::addr_t highest_func_addr = func_ranges.GetMaxRangeEnd(0); + if (lowest_func_addr != LLDB_INVALID_ADDRESS && lowest_func_addr <= highest_func_addr) + { + ModuleSP module_sp(die.GetModule()); + func_range.GetBaseAddress().ResolveAddressUsingFileSections(lowest_func_addr, module_sp->GetSectionList()); + if (func_range.GetBaseAddress().IsValid()) + func_range.SetByteSize(highest_func_addr - lowest_func_addr); + } + + if (func_range.GetBaseAddress().IsValid()) + { + std::unique_ptr<Declaration> decl_ap; + if (decl_file != 0 || decl_line != 0 || decl_column != 0) + decl_ap.reset(new Declaration(sc.comp_unit->GetSupportFiles().GetFileSpecAtIndex(decl_file), decl_line, + decl_column)); + + if (die.GetDWARF()->FixupAddress(func_range.GetBaseAddress())) + { + FunctionSP func_sp(new Function(sc.comp_unit, die.GetID(), die.GetID(), + Mangled(ConstString(name), false), + nullptr, // No function types in java + func_range)); + if (frame_base.IsValid()) + func_sp->GetFrameBaseExpression() = frame_base; + sc.comp_unit->AddFunction(func_sp); + + return func_sp.get(); + } + } + } + return nullptr; +} + +bool +DWARFASTParserJava::CompleteTypeFromDWARF(const DWARFDIE &die, lldb_private::Type *type, + lldb_private::CompilerType &java_type) +{ + switch (die.Tag()) + { + case DW_TAG_class_type: + { + if (die.GetAttributeValueAsUnsigned(DW_AT_declaration, 0) == 0) + { + if (die.HasChildren()) + ParseChildMembers(die, java_type); + m_ast.CompleteObjectType(java_type); + return java_type.IsValid(); + } + } + break; + default: + assert(false && "Not a forward java type declaration!"); + break; + } + return false; +} + +void +DWARFASTParserJava::ParseChildMembers(const DWARFDIE &parent_die, CompilerType &compiler_type) +{ + DWARFCompileUnit *dwarf_cu = parent_die.GetCU(); + for (DWARFDIE die = parent_die.GetFirstChild(); die.IsValid(); die = die.GetSibling()) + { + switch (die.Tag()) + { + case DW_TAG_member: + { + const char *name = nullptr; + DWARFFormValue encoding_uid; + uint32_t member_byte_offset = UINT32_MAX; + DWARFExpression member_location_expression(dwarf_cu); + + DWARFAttributes attributes; + size_t num_attributes = die.GetAttributes(attributes); + for (size_t i = 0; i < num_attributes; ++i) + { + DWARFFormValue form_value; + if (attributes.ExtractFormValueAtIndex(i, form_value)) + { + switch (attributes.AttributeAtIndex(i)) + { + case DW_AT_name: + name = form_value.AsCString(); + break; + case DW_AT_type: + encoding_uid = form_value; + break; + case DW_AT_data_member_location: + if (form_value.BlockData()) + member_location_expression.CopyOpcodeData( + form_value.BlockData(), form_value.Unsigned(), dwarf_cu->GetByteOrder(), + dwarf_cu->GetAddressByteSize()); + else + member_byte_offset = form_value.Unsigned(); + break; + case DW_AT_artificial: + static_cast<void>(form_value.Boolean()); + break; + case DW_AT_accessibility: + // TODO: Handle when needed + break; + default: + assert(false && "Unhandled attribute for DW_TAG_member"); + break; + } + } + } + + if (strcmp(name, ".dynamic_type") == 0) + m_ast.SetDynamicTypeId(compiler_type, member_location_expression); + else + { + if (Type *member_type = die.ResolveTypeUID(DIERef(encoding_uid))) + m_ast.AddMemberToObject(compiler_type, ConstString(name), member_type->GetFullCompilerType(), + member_byte_offset); + } + break; + } + case DW_TAG_inheritance: + { + DWARFFormValue encoding_uid; + uint32_t member_byte_offset = UINT32_MAX; + + DWARFAttributes attributes; + size_t num_attributes = die.GetAttributes(attributes); + for (size_t i = 0; i < num_attributes; ++i) + { + DWARFFormValue form_value; + if (attributes.ExtractFormValueAtIndex(i, form_value)) + { + switch (attributes.AttributeAtIndex(i)) + { + case DW_AT_type: + encoding_uid = form_value; + break; + case DW_AT_data_member_location: + member_byte_offset = form_value.Unsigned(); + break; + case DW_AT_accessibility: + // In java all base class is public so we can ignore this attribute + break; + default: + assert(false && "Unhandled attribute for DW_TAG_member"); + break; + } + } + } + if (Type *base_type = die.ResolveTypeUID(DIERef(encoding_uid))) + m_ast.AddBaseClassToObject(compiler_type, base_type->GetFullCompilerType(), member_byte_offset); + break; + } + default: + break; + } + } +} diff --git a/source/Plugins/SymbolFile/DWARF/DWARFASTParserJava.h b/source/Plugins/SymbolFile/DWARF/DWARFASTParserJava.h new file mode 100644 index 0000000000000..6a7eee75e6f7b --- /dev/null +++ b/source/Plugins/SymbolFile/DWARF/DWARFASTParserJava.h @@ -0,0 +1,90 @@ +//===-- DWARFASTParserJava.h ------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef SymbolFileDWARF_DWARFASTParserJava_h_ +#define SymbolFileDWARF_DWARFASTParserJava_h_ + +// C Includes +// C++ Includes +// Other libraries and framework includes +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/SmallVector.h" + +// Project includes +#include "DWARFASTParser.h" +#include "DWARFDIE.h" +#include "DWARFDefines.h" +#include "lldb/Core/PluginInterface.h" +#include "lldb/Symbol/JavaASTContext.h" + +class DWARFDebugInfoEntry; +class DWARFDIECollection; + +class DWARFASTParserJava : public DWARFASTParser +{ +public: + DWARFASTParserJava(lldb_private::JavaASTContext &ast); + ~DWARFASTParserJava() override; + + lldb::TypeSP + ParseTypeFromDWARF(const lldb_private::SymbolContext &sc, const DWARFDIE &die, lldb_private::Log *log, + bool *type_is_new_ptr) override; + + lldb_private::Function * + ParseFunctionFromDWARF(const lldb_private::SymbolContext &sc, const DWARFDIE &die) override; + + bool + CompleteTypeFromDWARF(const DWARFDIE &die, lldb_private::Type *type, + lldb_private::CompilerType &java_type) override; + + lldb_private::CompilerDeclContext + GetDeclContextForUIDFromDWARF(const DWARFDIE &die) override + { + return lldb_private::CompilerDeclContext(); + } + + lldb_private::CompilerDeclContext + GetDeclContextContainingUIDFromDWARF(const DWARFDIE &die) override + { + return lldb_private::CompilerDeclContext(); + } + + lldb_private::CompilerDecl + GetDeclForUIDFromDWARF(const DWARFDIE &die) override + { + return lldb_private::CompilerDecl(); + } + + std::vector<DWARFDIE> + GetDIEForDeclContext(lldb_private::CompilerDeclContext decl_context) override + { + return std::vector<DWARFDIE>(); + } + + void + ParseChildMembers(const DWARFDIE &parent_die, lldb_private::CompilerType &class_compiler_type); + +private: + lldb_private::JavaASTContext &m_ast; + + lldb::TypeSP + ParseBaseTypeFromDIE(const DWARFDIE &die); + + lldb::TypeSP + ParseArrayTypeFromDIE(const DWARFDIE &die); + + lldb::TypeSP + ParseReferenceTypeFromDIE(const DWARFDIE &die); + + lldb::TypeSP + ParseClassTypeFromDIE(const DWARFDIE &die, bool &is_new_type); +}; + +#endif // SymbolFileDWARF_DWARFASTParserJava_h_ diff --git a/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp b/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp index e7cb2b413ad7a..c5d7568b52729 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp +++ b/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp @@ -311,46 +311,12 @@ DWARFCompileUnit::AddCompileUnitDIE(DWARFDebugInfoEntry& die) { assert (m_die_array.empty() && "Compile unit DIE already added"); AddDIE(die); - - DWARFDebugInfoEntry& cu_die = m_die_array.front(); - - const char* dwo_name = cu_die.GetAttributeValueAsString(m_dwarf2Data, - this, - DW_AT_GNU_dwo_name, - nullptr); - if (!dwo_name) - return; - - FileSpec dwo_file(dwo_name, true); - if (dwo_file.IsRelative()) - { - const char* comp_dir = cu_die.GetAttributeValueAsString(m_dwarf2Data, - this, - DW_AT_comp_dir, - nullptr); - if (!comp_dir) - return; - - dwo_file.SetFile(comp_dir, true); - dwo_file.AppendPathComponent(dwo_name); - } - - if (!dwo_file.Exists()) - return; - DataBufferSP dwo_file_data_sp; - lldb::offset_t dwo_file_data_offset = 0; - ObjectFileSP dwo_obj_file = ObjectFile::FindPlugin(m_dwarf2Data->GetObjectFile()->GetModule(), - &dwo_file, - 0 /* file_offset */, - dwo_file.GetByteSize(), - dwo_file_data_sp, - dwo_file_data_offset); - if (dwo_obj_file == nullptr) + const DWARFDebugInfoEntry &cu_die = m_die_array.front(); + std::unique_ptr<SymbolFileDWARFDwo> dwo_symbol_file = m_dwarf2Data->GetDwoSymbolFileForCompileUnit(*this, cu_die); + if (!dwo_symbol_file) return; - std::unique_ptr<SymbolFileDWARFDwo> dwo_symbol_file(new SymbolFileDWARFDwo(dwo_obj_file, this)); - DWARFCompileUnit* dwo_cu = dwo_symbol_file->GetCompileUnit(); if (!dwo_cu) return; // Can't fetch the compile unit from the dwo file. @@ -467,7 +433,7 @@ DWARFCompileUnit::GetID () const { dw_offset_t local_id = m_base_obj_offset != DW_INVALID_OFFSET ? m_base_obj_offset : m_offset; if (m_dwarf2Data) - return m_dwarf2Data->MakeUserID(local_id); + return DIERef(local_id, local_id).GetUID(m_dwarf2Data); else return local_id; } @@ -665,7 +631,7 @@ DWARFCompileUnit::GetDIE (dw_offset_t die_offset) { // Don't specify the compile unit offset as we don't know it because the DIE belongs to // a different compile unit in the same symbol file. - return m_dwarf2Data->DebugInfo()->GetDIE (DIERef(die_offset)); + return m_dwarf2Data->DebugInfo()->GetDIEForDIEOffset(die_offset); } } return DWARFDIE(); // Not found @@ -789,20 +755,21 @@ DWARFCompileUnit::IndexPrivate (DWARFCompileUnit* dwarf_cu, switch (tag) { - case DW_TAG_subprogram: - case DW_TAG_inlined_subroutine: + case DW_TAG_array_type: case DW_TAG_base_type: case DW_TAG_class_type: case DW_TAG_constant: case DW_TAG_enumeration_type: + case DW_TAG_inlined_subroutine: + case DW_TAG_namespace: case DW_TAG_string_type: - case DW_TAG_subroutine_type: case DW_TAG_structure_type: - case DW_TAG_union_type: + case DW_TAG_subprogram: + case DW_TAG_subroutine_type: case DW_TAG_typedef: - case DW_TAG_namespace: - case DW_TAG_variable: + case DW_TAG_union_type: case DW_TAG_unspecified_type: + case DW_TAG_variable: break; default: @@ -977,7 +944,7 @@ DWARFCompileUnit::IndexPrivate (DWARFCompileUnit* dwarf_cu, // as our name. If it starts with '_', then it is ok, else compare // the string to make sure it isn't the same and we don't end up // with duplicate entries - if (name != mangled_cstr && ((mangled_cstr[0] == '_') || (name && ::strcmp(name, mangled_cstr) != 0))) + if (name && name != mangled_cstr && ((mangled_cstr[0] == '_') || (::strcmp(name, mangled_cstr) != 0))) { Mangled mangled (ConstString(mangled_cstr), true); func_fullnames.Insert (mangled.GetMangledName(), DIERef(cu_offset, die.GetOffset())); @@ -1000,7 +967,7 @@ DWARFCompileUnit::IndexPrivate (DWARFCompileUnit* dwarf_cu, // as our name. If it starts with '_', then it is ok, else compare // the string to make sure it isn't the same and we don't end up // with duplicate entries - if (name != mangled_cstr && ((mangled_cstr[0] == '_') || (::strcmp(name, mangled_cstr) != 0))) + if (name && name != mangled_cstr && ((mangled_cstr[0] == '_') || (::strcmp(name, mangled_cstr) != 0))) { Mangled mangled (ConstString(mangled_cstr), true); func_fullnames.Insert (mangled.GetMangledName(), DIERef(cu_offset, die.GetOffset())); @@ -1014,20 +981,21 @@ DWARFCompileUnit::IndexPrivate (DWARFCompileUnit* dwarf_cu, } break; + case DW_TAG_array_type: case DW_TAG_base_type: case DW_TAG_class_type: case DW_TAG_constant: case DW_TAG_enumeration_type: case DW_TAG_string_type: - case DW_TAG_subroutine_type: case DW_TAG_structure_type: - case DW_TAG_union_type: + case DW_TAG_subroutine_type: case DW_TAG_typedef: + case DW_TAG_union_type: case DW_TAG_unspecified_type: - if (name && is_declaration == false) - { + if (name && !is_declaration) types.Insert (ConstString(name), DIERef(cu_offset, die.GetOffset())); - } + if (mangled_cstr && !is_declaration) + types.Insert (ConstString(mangled_cstr), DIERef(cu_offset, die.GetOffset())); break; case DW_TAG_namespace: @@ -1180,7 +1148,7 @@ DWARFCompileUnit::LanguageTypeFromDWARF(uint64_t val) { case DW_LANG_Mips_Assembler: return eLanguageTypeMipsAssembler; - case 0x8e57: // FIXME: needs to be added to llvm + case DW_LANG_GOOGLE_RenderScript: return eLanguageTypeExtRenderScript; default: return static_cast<LanguageType>(val); @@ -1259,3 +1227,9 @@ DWARFCompileUnit::SetAddrBase(dw_addr_t addr_base, dw_offset_t base_obj_offset) m_addr_base = addr_base; m_base_obj_offset = base_obj_offset; } + +lldb::ByteOrder +DWARFCompileUnit::GetByteOrder() const +{ + return m_dwarf2Data->GetObjectFile()->GetByteOrder(); +} diff --git a/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.h b/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.h index 0fcaaca09ed8c..8d96e3698ab26 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.h +++ b/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.h @@ -59,6 +59,8 @@ public: void BuildAddressRangeTable (SymbolFileDWARF* dwarf2Data, DWARFDebugAranges* debug_aranges); + lldb::ByteOrder + GetByteOrder() const; lldb_private::TypeSystem * GetTypeSystem(); diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDIE.cpp b/source/Plugins/SymbolFile/DWARF/DWARFDIE.cpp index 0564de9e5dd1f..0f02c74fd2ebd 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFDIE.cpp +++ b/source/Plugins/SymbolFile/DWARF/DWARFDIE.cpp @@ -9,6 +9,7 @@ #include "DWARFDIE.h" +#include "DWARFASTParser.h" #include "DWARFCompileUnit.h" #include "DWARFDebugAbbrev.h" #include "DWARFDebugAranges.h" @@ -127,6 +128,21 @@ DWARFDIE::GetAttributeValueAsSigned (const dw_attr_t attr, int64_t fail_value) c return fail_value; } +DWARFDIE +DWARFDIE::GetAttributeValueAsReferenceDIE (const dw_attr_t attr) const +{ + if (IsValid()) + { + DWARFCompileUnit *cu = GetCU(); + SymbolFileDWARF *dwarf = cu->GetSymbolFileDWARF(); + const bool check_specification_or_abstract_origin = true; + DWARFFormValue form_value; + if (m_die->GetAttributeValue(dwarf, cu, attr, form_value, nullptr, check_specification_or_abstract_origin)) + return dwarf->GetDIE(DIERef(form_value)); + } + return DWARFDIE(); +} + uint64_t DWARFDIE::GetAttributeValueAsReference (const dw_attr_t attr, uint64_t fail_value) const { @@ -166,7 +182,7 @@ DWARFDIE::LookupDeepestBlock (lldb::addr_t file_addr) const if (cu->ContainsDIEOffset(block_die->GetOffset())) return DWARFDIE(cu, block_die); else - return DWARFDIE(dwarf->DebugInfo()->GetCompileUnitContainingDIE(DIERef(cu->GetOffset(), block_die->GetOffset())), block_die); + return DWARFDIE(dwarf->DebugInfo()->GetCompileUnit(DIERef(cu->GetOffset(), block_die->GetOffset())), block_die); } } } @@ -176,27 +192,7 @@ DWARFDIE::LookupDeepestBlock (lldb::addr_t file_addr) const lldb::user_id_t DWARFDIE::GetID () const { - const dw_offset_t die_offset = GetOffset(); - if (die_offset != DW_INVALID_OFFSET) - { - lldb::user_id_t id = 0; - SymbolFileDWARF *dwarf = GetDWARF(); - if (dwarf) - id = dwarf->MakeUserID(die_offset); - else - id = die_offset; - - if (m_cu) - { - lldb::user_id_t cu_id = m_cu->GetID()&0xffffffff00000000ull; - assert ((id&0xffffffff00000000ull) == 0 || - (cu_id&0xffffffff00000000ll) == 0 || - (id&0xffffffff00000000ull) == (cu_id&0xffffffff00000000ll)); - id |= cu_id; - } - return id; - } - return LLDB_INVALID_UID; + return GetDIERef().GetUID(GetDWARF()); } const char * @@ -274,11 +270,11 @@ DWARFDIE::ResolveType () const } lldb_private::Type * -DWARFDIE::ResolveTypeUID (lldb::user_id_t uid) const +DWARFDIE::ResolveTypeUID (const DIERef &die_ref) const { SymbolFileDWARF *dwarf = GetDWARF(); if (dwarf) - return dwarf->ResolveTypeUID(uid); + return dwarf->ResolveTypeUID(dwarf->GetDIE(die_ref), true); else return nullptr; } @@ -302,6 +298,7 @@ DWARFDIE::GetDWARFDeclContext (DWARFDeclContext &dwarf_decl_ctx) const { if (IsValid()) { + dwarf_decl_ctx.SetLanguage(GetLanguage()); m_die->GetDWARFDeclContext (GetDWARF(), GetCU(), dwarf_decl_ctx); } else @@ -530,6 +527,36 @@ DWARFDIE::Dump (lldb_private::Stream *s, const uint32_t recurse_depth) const } +CompilerDecl +DWARFDIE::GetDecl () const +{ + DWARFASTParser *dwarf_ast = GetDWARFParser(); + if (dwarf_ast) + return dwarf_ast->GetDeclForUIDFromDWARF(*this); + else + return CompilerDecl(); +} + +CompilerDeclContext +DWARFDIE::GetDeclContext () const +{ + DWARFASTParser *dwarf_ast = GetDWARFParser(); + if (dwarf_ast) + return dwarf_ast->GetDeclContextForUIDFromDWARF(*this); + else + return CompilerDeclContext(); +} + +CompilerDeclContext +DWARFDIE::GetContainingDeclContext () const +{ + DWARFASTParser *dwarf_ast = GetDWARFParser(); + if (dwarf_ast) + return dwarf_ast->GetDeclContextContainingUIDFromDWARF(*this); + else + return CompilerDeclContext(); +} + bool operator == (const DWARFDIE &lhs, const DWARFDIE &rhs) { return lhs.GetDIE() == rhs.GetDIE() && lhs.GetCU() == rhs.GetCU(); diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDIE.h b/source/Plugins/SymbolFile/DWARF/DWARFDIE.h index db37a45ad01a8..2dcd1d7dc43e1 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFDIE.h +++ b/source/Plugins/SymbolFile/DWARF/DWARFDIE.h @@ -58,7 +58,7 @@ public: //---------------------------------------------------------------------- // Tests //---------------------------------------------------------------------- - operator bool () const + explicit operator bool () const { return IsValid(); } @@ -180,9 +180,11 @@ public: lldb_private::Type * ResolveType () const; + //---------------------------------------------------------------------- // Resolve a type by UID using this DIE's DWARF file + //---------------------------------------------------------------------- lldb_private::Type * - ResolveTypeUID (lldb::user_id_t uid) const; + ResolveTypeUID (const DIERef &die_ref) const; //---------------------------------------------------------------------- // Functions for obtaining DIE relations and references @@ -245,6 +247,9 @@ public: uint64_t GetAttributeValueAsReference (const dw_attr_t attr, uint64_t fail_value) const; + DWARFDIE + GetAttributeValueAsReferenceDIE (const dw_attr_t attr) const; + uint64_t GetAttributeValueAsAddress (const dw_attr_t attr, uint64_t fail_value) const; @@ -270,6 +275,15 @@ public: void Dump (lldb_private::Stream *s, const uint32_t recurse_depth) const; + lldb_private::CompilerDecl + GetDecl () const; + + lldb_private::CompilerDeclContext + GetDeclContext() const; + + lldb_private::CompilerDeclContext + GetContainingDeclContext() const; + protected: DWARFCompileUnit *m_cu; DWARFDebugInfoEntry *m_die; diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDIECollection.cpp b/source/Plugins/SymbolFile/DWARF/DWARFDIECollection.cpp index 9e021c7185bd6..e9f09fd8776ce 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFDIECollection.cpp +++ b/source/Plugins/SymbolFile/DWARF/DWARFDIECollection.cpp @@ -16,17 +16,6 @@ using namespace lldb_private; using namespace std; -bool -DWARFDIECollection::Insert(const DWARFDIE &die) -{ - iterator end_pos = m_dies.end(); - iterator insert_pos = upper_bound(m_dies.begin(), end_pos, die); - if (insert_pos != end_pos && (*insert_pos == die)) - return false; - m_dies.insert(insert_pos, die); - return true; -} - void DWARFDIECollection::Append (const DWARFDIE &die) { diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDIECollection.h b/source/Plugins/SymbolFile/DWARF/DWARFDIECollection.h index e39e1aa4ccda3..83d58ec49300f 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFDIECollection.h +++ b/source/Plugins/SymbolFile/DWARF/DWARFDIECollection.h @@ -33,9 +33,6 @@ public: DWARFDIE GetDIEAtIndex (uint32_t idx) const; - bool - Insert(const DWARFDIE &die); - size_t Size() const; diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp b/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp index a1b00d1892e91..417f2cd79bdac 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp +++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp @@ -209,48 +209,51 @@ DWARFDebugInfo::GetCompileUnit(dw_offset_t cu_offset, uint32_t* idx_ptr) } DWARFCompileUnit * -DWARFDebugInfo::GetCompileUnitContainingDIE (const DIERef& die_ref) +DWARFDebugInfo::GetCompileUnit (const DIERef& die_ref) { - dw_offset_t search_offset = die_ref.die_offset; - bool is_cu_offset = false; - if (m_dwarf2Data->GetID() == 0 && die_ref.cu_offset != DW_INVALID_OFFSET) - { - is_cu_offset = true; - search_offset = die_ref.cu_offset; - } + if (die_ref.cu_offset == DW_INVALID_OFFSET) + return GetCompileUnitContainingDIEOffset(die_ref.die_offset); + else + return GetCompileUnit(die_ref.cu_offset); +} + +DWARFCompileUnit* +DWARFDebugInfo::GetCompileUnitContainingDIEOffset(dw_offset_t die_offset) +{ + ParseCompileUnitHeadersIfNeeded(); DWARFCompileUnitSP cu_sp; - if (search_offset != DW_INVALID_OFFSET) - { - ParseCompileUnitHeadersIfNeeded(); - // Watch out for single compile unit executable as they are pretty common - const size_t num_cus = m_compile_units.size(); - if (num_cus == 1) - { - if ((is_cu_offset && m_compile_units[0]->GetOffset() == search_offset) || - (!is_cu_offset && m_compile_units[0]->ContainsDIEOffset(search_offset))) - { - cu_sp = m_compile_units[0]; - } - } - else if (num_cus) + // Watch out for single compile unit executable as they are pretty common + const size_t num_cus = m_compile_units.size(); + if (num_cus == 1) + { + if (m_compile_units[0]->ContainsDIEOffset(die_offset)) + return m_compile_units[0].get(); + } + else if (num_cus) + { + CompileUnitColl::const_iterator end_pos = m_compile_units.end(); + CompileUnitColl::const_iterator begin_pos = m_compile_units.begin(); + CompileUnitColl::const_iterator pos = std::upper_bound(begin_pos, end_pos, die_offset, OffsetLessThanCompileUnitOffset); + if (pos != begin_pos) { - CompileUnitColl::const_iterator end_pos = m_compile_units.end(); - CompileUnitColl::const_iterator begin_pos = m_compile_units.begin(); - CompileUnitColl::const_iterator pos = std::upper_bound(begin_pos, end_pos, search_offset, OffsetLessThanCompileUnitOffset); - if (pos != begin_pos) - { - --pos; - if ((is_cu_offset && (*pos)->GetOffset() == search_offset) || - (!is_cu_offset && (*pos)->ContainsDIEOffset(search_offset))) - { - cu_sp = *pos; - } - } + --pos; + if ((*pos)->ContainsDIEOffset(die_offset)) + return (*pos).get(); } } - return cu_sp.get(); + + return nullptr; +} + +DWARFDIE +DWARFDebugInfo::GetDIEForDIEOffset(dw_offset_t die_offset) +{ + DWARFCompileUnit* cu = GetCompileUnitContainingDIEOffset(die_offset); + if (cu) + return cu->GetDIE(die_offset); + return DWARFDIE(); } //---------------------------------------------------------------------- @@ -261,7 +264,7 @@ DWARFDebugInfo::GetCompileUnitContainingDIE (const DIERef& die_ref) DWARFDIE DWARFDebugInfo::GetDIE(const DIERef& die_ref) { - DWARFCompileUnit *cu = GetCompileUnitContainingDIE(die_ref); + DWARFCompileUnit *cu = GetCompileUnit(die_ref); if (cu) return cu->GetDIE (die_ref.die_offset); return DWARFDIE(); // Not found diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.h b/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.h index ea2e204db7029..7783135bdb95b 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.h +++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.h @@ -39,9 +39,10 @@ public: size_t GetNumCompileUnits(); bool ContainsCompileUnit (const DWARFCompileUnit *cu) const; DWARFCompileUnit* GetCompileUnitAtIndex (uint32_t idx); - DWARFCompileUnit* GetCompileUnit (dw_offset_t cu_offset, uint32_t* idx_ptr = NULL); - DWARFCompileUnit* GetCompileUnitContainingDIE (const DIERef& die_ref); - + DWARFCompileUnit* GetCompileUnit(dw_offset_t cu_offset, uint32_t* idx_ptr = NULL); + DWARFCompileUnit* GetCompileUnitContainingDIEOffset (dw_offset_t die_offset); + DWARFCompileUnit* GetCompileUnit(const DIERef& die_ref); + DWARFDIE GetDIEForDIEOffset(dw_offset_t die_offset); DWARFDIE GetDIE (const DIERef& die_ref); void Dump(lldb_private::Stream *s, const uint32_t die_offset, const uint32_t recurse_depth); diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp b/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp index b9d825489aef9..f48d8fc9eeb29 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp +++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp @@ -482,11 +482,19 @@ DWARFDebugInfoEntry::GetDIENamesAndRanges case DW_AT_ranges: { const DWARFDebugRanges* debug_ranges = dwarf2Data->DebugRanges(); - debug_ranges->FindRanges(form_value.Unsigned(), ranges); - // All DW_AT_ranges are relative to the base address of the - // compile unit. We add the compile unit base address to make - // sure all the addresses are properly fixed up. - ranges.Slide(cu->GetBaseAddress()); + if (debug_ranges) + { + debug_ranges->FindRanges(form_value.Unsigned(), ranges); + // All DW_AT_ranges are relative to the base address of the + // compile unit. We add the compile unit base address to make + // sure all the addresses are properly fixed up. + ranges.Slide(cu->GetBaseAddress()); + } + else + { + cu->GetSymbolFileDWARF()->GetObjectFile()->GetModule()->ReportError ("{0x%8.8x}: DIE has DW_AT_ranges(0x%" PRIx64 ") attribute yet DWARF has no .debug_ranges, please file a bug and attach the file at the start of this error message", + m_offset, form_value.Unsigned()); + } } break; @@ -602,7 +610,7 @@ DWARFDebugInfoEntry::GetDIENamesAndRanges { if (die_ref.die_offset != DW_INVALID_OFFSET) { - DWARFDIE die = dwarf2Data->DebugInfo()->GetDIE(die_ref); + DWARFDIE die = dwarf2Data->GetDIE(die_ref); if (die) die.GetDIE()->GetDIENamesAndRanges(die.GetDWARF(), die.GetCU(), name, mangled, ranges, decl_file, decl_line, decl_column, call_file, call_line, call_column); } @@ -934,7 +942,7 @@ DWARFDebugInfoEntry::GetAttributes (const DWARFCompileUnit* cu, // referencing this DIE because curr_depth is not zero break; } - // Fall through... + LLVM_FALLTHROUGH; default: attributes.Append(cu, offset, attr, form); break; diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h b/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h index 02bbff8defc0a..27b4fe93bc332 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h +++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h @@ -115,6 +115,13 @@ public: DWARFAttributes& attrs, uint32_t curr_depth = 0) const; // "curr_depth" for internal use only, don't set this yourself!!! + dw_offset_t GetAttributeValue(SymbolFileDWARF* dwarf2Data, + const DWARFCompileUnit* cu, + const dw_attr_t attr, + DWARFFormValue& formValue, + dw_offset_t* end_attr_offset_ptr = nullptr, + bool check_specification_or_abstract_origin = false) const; + const char* GetAttributeValueAsString( SymbolFileDWARF* dwarf2Data, const DWARFCompileUnit* cu, @@ -382,12 +389,6 @@ public: DWARFDebugInfoEntry::collection &die_collection); protected: - dw_offset_t GetAttributeValue(SymbolFileDWARF* dwarf2Data, - const DWARFCompileUnit* cu, - const dw_attr_t attr, - DWARFFormValue& formValue, - dw_offset_t* end_attr_offset_ptr = nullptr, - bool check_specification_or_abstract_origin = false) const; dw_offset_t m_offset; // Offset within the .debug_info of the start of this entry uint32_t m_parent_idx; // How many to subtract from "this" to get the parent. If zero this die has no parent diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDeclContext.h b/source/Plugins/SymbolFile/DWARF/DWARFDeclContext.h index 4c29447b47bb8..2452274a293be 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFDeclContext.h +++ b/source/Plugins/SymbolFile/DWARF/DWARFDeclContext.h @@ -64,7 +64,8 @@ public: }; DWARFDeclContext () : - m_entries() + m_entries(), + m_language(lldb::eLanguageTypeUnknown) { } @@ -115,10 +116,23 @@ public: m_qualified_name.clear(); } + lldb::LanguageType + GetLanguage() const + { + return m_language; + } + + void + SetLanguage(lldb::LanguageType language) + { + m_language = language; + } + protected: typedef std::vector<Entry> collection; collection m_entries; mutable std::string m_qualified_name; + lldb::LanguageType m_language; }; #endif // SymbolFileDWARF_DWARFDeclContext_h_ diff --git a/source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp b/source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp index a0ed9731a565d..addc14858461f 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp +++ b/source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp @@ -167,6 +167,14 @@ DWARFFormValue::DWARFFormValue(const DWARFCompileUnit* cu, dw_form_t form) : { } +void +DWARFFormValue::Clear() +{ + m_cu = nullptr; + m_form = 0; + memset(&m_value, 0, sizeof(m_value)); +} + bool DWARFFormValue::ExtractValue(const DWARFDataExtractor& data, lldb::offset_t* offset_ptr) { diff --git a/source/Plugins/SymbolFile/DWARF/DWARFFormValue.h b/source/Plugins/SymbolFile/DWARF/DWARFFormValue.h index b10f4d3a0ac97..07bd038d94865 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFFormValue.h +++ b/source/Plugins/SymbolFile/DWARF/DWARFFormValue.h @@ -101,6 +101,7 @@ public: static FixedFormSizes GetFixedFormSizesForAddressSize (uint8_t addr_size, bool is_dwarf64); static int Compare (const DWARFFormValue& a, const DWARFFormValue& b); + void Clear(); protected: const DWARFCompileUnit* m_cu; // Compile unit for this form dw_form_t m_form; // Form for this value diff --git a/source/Plugins/SymbolFile/DWARF/HashedNameToDIE.cpp b/source/Plugins/SymbolFile/DWARF/HashedNameToDIE.cpp index 0db416054ae8e..12e1e89c36bdb 100644 --- a/source/Plugins/SymbolFile/DWARF/HashedNameToDIE.cpp +++ b/source/Plugins/SymbolFile/DWARF/HashedNameToDIE.cpp @@ -220,7 +220,7 @@ DWARFMappedHash::Prologue::AppendAtom (AtomType type, dw_form_t form) case DW_FORM_GNU_addr_index: case DW_FORM_GNU_str_index: hash_data_has_fixed_byte_size = false; - // Fall through to the cases below... + LLVM_FALLTHROUGH; case DW_FORM_flag: case DW_FORM_data1: case DW_FORM_ref1: @@ -230,7 +230,7 @@ DWARFMappedHash::Prologue::AppendAtom (AtomType type, dw_form_t form) case DW_FORM_block2: hash_data_has_fixed_byte_size = false; - // Fall through to the cases below... + LLVM_FALLTHROUGH; case DW_FORM_data2: case DW_FORM_ref2: min_hash_data_byte_size += 2; @@ -238,7 +238,7 @@ DWARFMappedHash::Prologue::AppendAtom (AtomType type, dw_form_t form) case DW_FORM_block4: hash_data_has_fixed_byte_size = false; - // Fall through to the cases below... + LLVM_FALLTHROUGH; case DW_FORM_data4: case DW_FORM_ref4: case DW_FORM_addr: @@ -346,7 +346,8 @@ DWARFMappedHash::Header::Read (const lldb_private::DWARFDataExtractor &data, case eAtomTypeTag: // DW_TAG value for the DIE hash_data.tag = (dw_tag_t)form_value.Unsigned (); - + break; + case eAtomTypeTypeFlags: // Flags from enum TypeFlags hash_data.type_flags = (uint32_t)form_value.Unsigned (); break; @@ -671,6 +672,9 @@ DWARFMappedHash::MemoryTable::AppendAllDIEsInRange (const uint32_t die_offset_st size_t DWARFMappedHash::MemoryTable::FindByName (const char *name, DIEArray &die_offsets) { + if (!name || !name[0]) + return 0; + DIEInfoArray die_info_array; if (FindByName(name, die_info_array)) DWARFMappedHash::ExtractDIEArray (die_info_array, die_offsets); @@ -736,6 +740,9 @@ DWARFMappedHash::MemoryTable::FindCompleteObjCClassByName (const char *name, size_t DWARFMappedHash::MemoryTable::FindByName (const char *name, DIEInfoArray &die_info_array) { + if (!name || !name[0]) + return 0; + Pair kv_pair; size_t old_size = die_info_array.size(); if (Find (name, kv_pair)) diff --git a/source/Plugins/SymbolFile/DWARF/Makefile b/source/Plugins/SymbolFile/DWARF/Makefile deleted file mode 100644 index 509065650ab9e..0000000000000 --- a/source/Plugins/SymbolFile/DWARF/Makefile +++ /dev/null @@ -1,14 +0,0 @@ -##===- source/Plugins/SymbolFile/DWARF/Makefile ------------*- Makefile -*-===## -# -# The LLVM Compiler Infrastructure -# -# This file is distributed under the University of Illinois Open Source -# License. See LICENSE.TXT for details. -# -##===----------------------------------------------------------------------===## - -LLDB_LEVEL := ../../../.. -LIBRARYNAME := lldbPluginSymbolFileDWARF -BUILD_ARCHIVE = 1 - -include $(LLDB_LEVEL)/Makefile diff --git a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp index 2088864bf6b19..942a5d62d9b45 100644 --- a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp +++ b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp @@ -35,16 +35,17 @@ #include "lldb/Symbol/Block.h" #include "lldb/Symbol/ClangASTContext.h" +#include "lldb/Symbol/ClangUtil.h" +#include "lldb/Symbol/CompileUnit.h" #include "lldb/Symbol/CompilerDecl.h" #include "lldb/Symbol/CompilerDeclContext.h" -#include "lldb/Symbol/CompileUnit.h" -#include "lldb/Symbol/LineTable.h" #include "lldb/Symbol/DebugMacros.h" +#include "lldb/Symbol/LineTable.h" #include "lldb/Symbol/ObjectFile.h" #include "lldb/Symbol/SymbolVendor.h" +#include "lldb/Symbol/TypeMap.h" #include "lldb/Symbol/TypeSystem.h" #include "lldb/Symbol/VariableList.h" -#include "lldb/Symbol/TypeMap.h" #include "Plugins/Language/CPlusPlus/CPlusPlusLanguage.h" #include "Plugins/Language/ObjC/ObjCLanguage.h" @@ -54,7 +55,9 @@ #include "lldb/Utility/TaskPool.h" #include "DWARFASTParser.h" +#include "DWARFASTParserClang.h" #include "DWARFCompileUnit.h" +#include "DWARFDIECollection.h" #include "DWARFDebugAbbrev.h" #include "DWARFDebugAranges.h" #include "DWARFDebugInfo.h" @@ -63,11 +66,10 @@ #include "DWARFDebugPubnames.h" #include "DWARFDebugRanges.h" #include "DWARFDeclContext.h" -#include "DWARFDIECollection.h" #include "DWARFFormValue.h" #include "LogChannelDWARF.h" -#include "SymbolFileDWARFDwo.h" #include "SymbolFileDWARFDebugMap.h" +#include "SymbolFileDWARFDwo.h" #include <map> @@ -277,9 +279,11 @@ SymbolFileDWARF::CreateInstance (ObjectFile* obj_file) TypeList * SymbolFileDWARF::GetTypeList () { - if (GetDebugMapSymfile ()) - return m_debug_map_symfile->GetTypeList(); - return m_obj_file->GetModule()->GetTypeList(); + SymbolFileDWARFDebugMap *debug_map_symfile = GetDebugMapSymfile(); + if (debug_map_symfile) + return debug_map_symfile->GetTypeList(); + else + return m_obj_file->GetModule()->GetTypeList(); } void @@ -483,15 +487,17 @@ GetDWARFMachOSegmentName () UniqueDWARFASTTypeMap & SymbolFileDWARF::GetUniqueDWARFASTTypeMap () { - if (GetDebugMapSymfile ()) - return m_debug_map_symfile->GetUniqueDWARFASTTypeMap (); - return m_unique_ast_type_map; + SymbolFileDWARFDebugMap *debug_map_symfile = GetDebugMapSymfile(); + if (debug_map_symfile) + return debug_map_symfile->GetUniqueDWARFASTTypeMap (); + else + return m_unique_ast_type_map; } TypeSystem * SymbolFileDWARF::GetTypeSystemForLanguage (LanguageType language) { - SymbolFileDWARFDebugMap * debug_map_symfile = GetDebugMapSymfile (); + SymbolFileDWARFDebugMap *debug_map_symfile = GetDebugMapSymfile(); TypeSystem *type_system; if (debug_map_symfile) { @@ -823,30 +829,13 @@ SymbolFileDWARF::GetDWARFCompileUnit(lldb_private::CompileUnit *comp_unit) DWARFDebugInfo* info = DebugInfo(); if (info) { - if (GetDebugMapSymfile ()) - { - // The debug map symbol file made the compile units for this DWARF - // file which is .o file with DWARF in it, and we should have - // only 1 compile unit which is at offset zero in the DWARF. - // TODO: modify to support LTO .o files where each .o file might - // have multiple DW_TAG_compile_unit tags. - - DWARFCompileUnit *dwarf_cu = info->GetCompileUnit(0); - if (dwarf_cu && dwarf_cu->GetUserData() == NULL) - dwarf_cu->SetUserData(comp_unit); - return dwarf_cu; - } - else - { - // Just a normal DWARF file whose user ID for the compile unit is - // the DWARF offset itself + // Just a normal DWARF file whose user ID for the compile unit is + // the DWARF offset itself - DWARFCompileUnit *dwarf_cu = info->GetCompileUnit((dw_offset_t)comp_unit->GetID()); - if (dwarf_cu && dwarf_cu->GetUserData() == NULL) - dwarf_cu->SetUserData(comp_unit); - return dwarf_cu; - - } + DWARFCompileUnit *dwarf_cu = info->GetCompileUnit((dw_offset_t)comp_unit->GetID()); + if (dwarf_cu && dwarf_cu->GetUserData() == NULL) + dwarf_cu->SetUserData(comp_unit); + return dwarf_cu; } return NULL; } @@ -893,7 +882,7 @@ SymbolFileDWARF::ParseCompileUnit (DWARFCompileUnit* dwarf_cu, uint32_t cu_idx) { return dwarf_cu->GetSymbolFileDWARF()->ParseCompileUnit(dwarf_cu, cu_idx); } - else if (GetDebugMapSymfile ()) + else if (dwarf_cu->GetOffset() == 0 && GetDebugMapSymfile ()) { // Let the debug map create the compile unit cu_sp = m_debug_map_symfile->GetCompileUnit(this); @@ -926,12 +915,8 @@ SymbolFileDWARF::ParseCompileUnit (DWARFCompileUnit* dwarf_cu, uint32_t cu_idx) LanguageType cu_language = DWARFCompileUnit::LanguageTypeFromDWARF(cu_die.GetAttributeValueAsUnsigned(DW_AT_language, 0)); bool is_optimized = dwarf_cu->GetIsOptimized (); - cu_sp.reset(new CompileUnit (module_sp, - dwarf_cu, - cu_file_spec, - dwarf_cu->GetID(), - cu_language, - is_optimized)); + cu_sp.reset(new CompileUnit(module_sp, dwarf_cu, cu_file_spec, dwarf_cu->GetID(), cu_language, + is_optimized ? eLazyBoolYes : eLazyBoolNo)); if (cu_sp) { // If we just created a compile unit with an invalid file spec, try and get the @@ -1007,7 +992,7 @@ SymbolFileDWARF::ParseCompileUnitFunction (const SymbolContext& sc, const DWARFD bool SymbolFileDWARF::FixupAddress (Address &addr) { - SymbolFileDWARFDebugMap * debug_map_symfile = GetDebugMapSymfile (); + SymbolFileDWARFDebugMap * debug_map_symfile = GetDebugMapSymfile(); if (debug_map_symfile) { return debug_map_symfile->LinkOSOAddress(addr); @@ -1063,7 +1048,6 @@ SymbolFileDWARF::ParseCompileUnitSupportFiles (const SymbolContext& sc, FileSpec if (cu_die) { const char * cu_comp_dir = resolveCompDir(cu_die.GetAttributeValueAsString(DW_AT_comp_dir, nullptr)); - const dw_offset_t stmt_list = cu_die.GetAttributeValueAsUnsigned(DW_AT_stmt_list, DW_INVALID_OFFSET); if (stmt_list != DW_INVALID_OFFSET) { @@ -1082,7 +1066,17 @@ SymbolFileDWARF::ParseCompileUnitSupportFiles (const SymbolContext& sc, FileSpec } bool -SymbolFileDWARF::ParseImportedModules (const lldb_private::SymbolContext &sc, std::vector<lldb_private::ConstString> &imported_modules) +SymbolFileDWARF::ParseCompileUnitIsOptimized(const lldb_private::SymbolContext &sc) +{ + DWARFCompileUnit *dwarf_cu = GetDWARFCompileUnit(sc.comp_unit); + if (dwarf_cu) + return dwarf_cu->GetIsOptimized(); + return false; +} + +bool +SymbolFileDWARF::ParseImportedModules(const lldb_private::SymbolContext &sc, + std::vector<lldb_private::ConstString> &imported_modules) { assert (sc.comp_unit); DWARFCompileUnit* dwarf_cu = GetDWARFCompileUnit(sc.comp_unit); @@ -1091,9 +1085,40 @@ SymbolFileDWARF::ParseImportedModules (const lldb_private::SymbolContext &sc, st if (ClangModulesDeclVendor::LanguageSupportsClangModules(sc.comp_unit->GetLanguage())) { UpdateExternalModuleListIfNeeded(); - for (const auto &pair : m_external_type_modules) + + if (sc.comp_unit) { - imported_modules.push_back(pair.first); + const DWARFDIE die = dwarf_cu->GetCompileUnitDIEOnly(); + + if (die) + { + for (DWARFDIE child_die = die.GetFirstChild(); + child_die; + child_die = child_die.GetSibling()) + { + if (child_die.Tag() == DW_TAG_imported_declaration) + { + if (DWARFDIE module_die = child_die.GetReferencedDIE(DW_AT_import)) + { + if (module_die.Tag() == DW_TAG_module) + { + if (const char *name = module_die.GetAttributeValueAsString(DW_AT_name, nullptr)) + { + ConstString const_name(name); + imported_modules.push_back(const_name); + } + } + } + } + } + } + } + else + { + for (const auto &pair : m_external_type_modules) + { + imported_modules.push_back(pair.first); + } } } } @@ -1198,13 +1223,14 @@ SymbolFileDWARF::ParseCompileUnitLineTable (const SymbolContext &sc) lldb::offset_t offset = cu_line_offset; DWARFDebugLine::ParseStatementTable(get_debug_line_data(), &offset, ParseDWARFLineTableCallback, &info); - if (m_debug_map_symfile) + SymbolFileDWARFDebugMap *debug_map_symfile = GetDebugMapSymfile(); + if (debug_map_symfile) { // We have an object file that has a line table with addresses // that are not linked. We need to link the line table and convert // the addresses that are relative to the .o file into addresses // for the main executable. - sc.comp_unit->SetLineTable (m_debug_map_symfile->LinkOSOLineTable (this, line_table_ap.get())); + sc.comp_unit->SetLineTable (debug_map_symfile->LinkOSOLineTable (this, line_table_ap.get())); } else { @@ -1439,63 +1465,71 @@ SymbolFileDWARF::ParseDeclsForContext (CompilerDeclContext decl_ctx) ast_parser->GetDeclForUIDFromDWARF(decl); } +SymbolFileDWARF * +SymbolFileDWARF::GetDWARFForUID (lldb::user_id_t uid) +{ + // Anytime we get a "lldb::user_id_t" from an lldb_private::SymbolFile API + // we must make sure we use the correct DWARF file when resolving things. + // On MacOSX, when using SymbolFileDWARFDebugMap, we will use multiple + // SymbolFileDWARF classes, one for each .o file. We can often end up + // with references to other DWARF objects and we must be ready to receive + // a "lldb::user_id_t" that specifies a DIE from another SymbolFileDWARF + // instance. + SymbolFileDWARFDebugMap *debug_map = GetDebugMapSymfile(); + if (debug_map) + return debug_map->GetSymbolFileByOSOIndex(debug_map->GetOSOIndexFromUserID(uid)); + return this; +} + +DWARFDIE +SymbolFileDWARF::GetDIEFromUID (lldb::user_id_t uid) +{ + // Anytime we get a "lldb::user_id_t" from an lldb_private::SymbolFile API + // we must make sure we use the correct DWARF file when resolving things. + // On MacOSX, when using SymbolFileDWARFDebugMap, we will use multiple + // SymbolFileDWARF classes, one for each .o file. We can often end up + // with references to other DWARF objects and we must be ready to receive + // a "lldb::user_id_t" that specifies a DIE from another SymbolFileDWARF + // instance. + SymbolFileDWARF *dwarf = GetDWARFForUID(uid); + if (dwarf) + return dwarf->GetDIE(DIERef(uid, dwarf)); + return DWARFDIE(); +} + CompilerDecl SymbolFileDWARF::GetDeclForUID (lldb::user_id_t type_uid) { - if (UserIDMatches(type_uid)) - { - DWARFDebugInfo* debug_info = DebugInfo(); - if (debug_info) - { - DWARFDIE die = debug_info->GetDIE(DIERef(type_uid)); - if (die) - { - DWARFASTParser *dwarf_ast = die.GetDWARFParser(); - if (dwarf_ast) - return dwarf_ast->GetDeclForUIDFromDWARF(die); - } - } - } + // Anytime we have a lldb::user_id_t, we must get the DIE by + // calling SymbolFileDWARF::GetDIEFromUID(). See comments inside + // the SymbolFileDWARF::GetDIEFromUID() for details. + DWARFDIE die = GetDIEFromUID(type_uid); + if (die) + return die.GetDecl(); return CompilerDecl(); } CompilerDeclContext SymbolFileDWARF::GetDeclContextForUID (lldb::user_id_t type_uid) { - if (UserIDMatches(type_uid)) - { - DWARFDebugInfo* debug_info = DebugInfo(); - if (debug_info) - { - DWARFDIE die = debug_info->GetDIE(DIERef(type_uid)); - if (die) - { - DWARFASTParser *dwarf_ast = die.GetDWARFParser(); - if (dwarf_ast) - return dwarf_ast->GetDeclContextForUIDFromDWARF(die); - } - } - } + // Anytime we have a lldb::user_id_t, we must get the DIE by + // calling SymbolFileDWARF::GetDIEFromUID(). See comments inside + // the SymbolFileDWARF::GetDIEFromUID() for details. + DWARFDIE die = GetDIEFromUID(type_uid); + if (die) + return die.GetDeclContext(); return CompilerDeclContext(); } CompilerDeclContext SymbolFileDWARF::GetDeclContextContainingUID (lldb::user_id_t type_uid) { - if (UserIDMatches(type_uid)) - { - DWARFDebugInfo* debug_info = DebugInfo(); - if (debug_info) - { - DWARFDIE die = debug_info->GetDIE(DIERef(type_uid)); - if (die) - { - DWARFASTParser *dwarf_ast = die.GetDWARFParser(); - if (dwarf_ast) - return dwarf_ast->GetDeclContextContainingUIDFromDWARF(die); - } - } - } + // Anytime we have a lldb::user_id_t, we must get the DIE by + // calling SymbolFileDWARF::GetDIEFromUID(). See comments inside + // the SymbolFileDWARF::GetDIEFromUID() for details. + DWARFDIE die = GetDIEFromUID(type_uid); + if (die) + return die.GetContainingDeclContext(); return CompilerDeclContext(); } @@ -1503,20 +1537,20 @@ SymbolFileDWARF::GetDeclContextContainingUID (lldb::user_id_t type_uid) Type* SymbolFileDWARF::ResolveTypeUID (lldb::user_id_t type_uid) { - if (UserIDMatches(type_uid)) - { - DWARFDebugInfo* debug_info = DebugInfo(); - if (debug_info) - { - DWARFDIE type_die = debug_info->GetDIE (DIERef(type_uid)); - if (type_die) - { - const bool assert_not_being_parsed = true; - return ResolveTypeUID (type_die, assert_not_being_parsed); - } - } - } - return NULL; + // Anytime we have a lldb::user_id_t, we must get the DIE by + // calling SymbolFileDWARF::GetDIEFromUID(). See comments inside + // the SymbolFileDWARF::GetDIEFromUID() for details. + DWARFDIE type_die = GetDIEFromUID(type_uid); + if (type_die) + return type_die.ResolveType(); + else + return nullptr; +} + +Type* +SymbolFileDWARF::ResolveTypeUID (const DIERef &die_ref) +{ + return ResolveType (GetDIE(die_ref), true); } Type* @@ -1573,35 +1607,36 @@ SymbolFileDWARF::ResolveTypeUID (const DWARFDIE &die, bool assert_not_being_pars bool SymbolFileDWARF::HasForwardDeclForClangType (const CompilerType &compiler_type) { - CompilerType compiler_type_no_qualifiers = ClangASTContext::RemoveFastQualifiers(compiler_type); + CompilerType compiler_type_no_qualifiers = ClangUtil::RemoveFastQualifiers(compiler_type); if (GetForwardDeclClangTypeToDie().count (compiler_type_no_qualifiers.GetOpaqueQualType())) { return true; } TypeSystem *type_system = compiler_type.GetTypeSystem(); - if (type_system) - { - DWARFASTParser *dwarf_ast = type_system->GetDWARFParser(); - if (dwarf_ast) - return dwarf_ast->CanCompleteType(compiler_type); - } - return false; + + ClangASTContext *clang_type_system = llvm::dyn_cast_or_null<ClangASTContext>(type_system); + if (!clang_type_system) + return false; + DWARFASTParserClang *ast_parser = static_cast<DWARFASTParserClang *>(clang_type_system->GetDWARFParser()); + return ast_parser->GetClangASTImporter().CanImport(compiler_type); } bool SymbolFileDWARF::CompleteType (CompilerType &compiler_type) { - TypeSystem *type_system = compiler_type.GetTypeSystem(); - if (type_system) + std::lock_guard<std::recursive_mutex> guard(GetObjectFile()->GetModule()->GetMutex()); + + ClangASTContext *clang_type_system = llvm::dyn_cast_or_null<ClangASTContext>(compiler_type.GetTypeSystem()); + if (clang_type_system) { - DWARFASTParser *dwarf_ast = type_system->GetDWARFParser(); - if (dwarf_ast && dwarf_ast->CanCompleteType(compiler_type)) - return dwarf_ast->CompleteType(compiler_type); + DWARFASTParserClang *ast_parser = static_cast<DWARFASTParserClang *>(clang_type_system->GetDWARFParser()); + if (ast_parser && ast_parser->GetClangASTImporter().CanImport(compiler_type)) + return ast_parser->GetClangASTImporter().CompleteType(compiler_type); } // We have a struct/union/class/enum that needs to be fully resolved. - CompilerType compiler_type_no_qualifiers = ClangASTContext::RemoveFastQualifiers(compiler_type); + CompilerType compiler_type_no_qualifiers = ClangUtil::RemoveFastQualifiers(compiler_type); auto die_it = GetForwardDeclClangTypeToDie().find (compiler_type_no_qualifiers.GetOpaqueQualType()); if (die_it == GetForwardDeclClangTypeToDie().end()) { @@ -1609,30 +1644,29 @@ SymbolFileDWARF::CompleteType (CompilerType &compiler_type) return true; } - DWARFDebugInfo* debug_info = DebugInfo(); - DWARFDIE dwarf_die = debug_info->GetDIE(die_it->getSecond()); - - assert(UserIDMatches(die_it->getSecond().GetUID()) && "CompleteType called on the wrong SymbolFile"); - - // Once we start resolving this type, remove it from the forward declaration - // map in case anyone child members or other types require this type to get resolved. - // The type will get resolved when all of the calls to SymbolFileDWARF::ResolveClangOpaqueTypeDefinition - // are done. - GetForwardDeclClangTypeToDie().erase (die_it); + DWARFDIE dwarf_die = GetDIE(die_it->getSecond()); + if (dwarf_die) + { + // Once we start resolving this type, remove it from the forward declaration + // map in case anyone child members or other types require this type to get resolved. + // The type will get resolved when all of the calls to SymbolFileDWARF::ResolveClangOpaqueTypeDefinition + // are done. + GetForwardDeclClangTypeToDie().erase (die_it); - Type *type = GetDIEToType().lookup (dwarf_die.GetDIE()); + Type *type = GetDIEToType().lookup (dwarf_die.GetDIE()); - Log *log (LogChannelDWARF::GetLogIfAny(DWARF_LOG_DEBUG_INFO|DWARF_LOG_TYPE_COMPLETION)); - if (log) - GetObjectFile()->GetModule()->LogMessageVerboseBacktrace (log, - "0x%8.8" PRIx64 ": %s '%s' resolving forward declaration...", - dwarf_die.GetID(), - dwarf_die.GetTagAsCString(), - type->GetName().AsCString()); - assert (compiler_type); - DWARFASTParser *dwarf_ast = dwarf_die.GetDWARFParser(); - if (dwarf_ast) - return dwarf_ast->CompleteTypeFromDWARF (dwarf_die, type, compiler_type); + Log *log (LogChannelDWARF::GetLogIfAny(DWARF_LOG_DEBUG_INFO|DWARF_LOG_TYPE_COMPLETION)); + if (log) + GetObjectFile()->GetModule()->LogMessageVerboseBacktrace (log, + "0x%8.8" PRIx64 ": %s '%s' resolving forward declaration...", + dwarf_die.GetID(), + dwarf_die.GetTagAsCString(), + type->GetName().AsCString()); + assert (compiler_type); + DWARFASTParser *dwarf_ast = dwarf_die.GetDWARFParser(); + if (dwarf_ast) + return dwarf_ast->CompleteTypeFromDWARF (dwarf_die, type, compiler_type); + } return false; } @@ -1641,10 +1675,7 @@ SymbolFileDWARF::ResolveType (const DWARFDIE &die, bool assert_not_being_parsed, { if (die) { - Type *type = GetDIEToType().lookup (die.GetDIE()); - - if (type == NULL) - type = GetTypeForDIE (die, resolve_function_context).get(); + Type *type = GetTypeForDIE (die, resolve_function_context).get(); if (assert_not_being_parsed) { @@ -1730,6 +1761,55 @@ SymbolFileDWARF::GetDWOModule (ConstString name) return lldb::ModuleSP(); } +DWARFDIE +SymbolFileDWARF::GetDIE (const DIERef &die_ref) +{ + DWARFDebugInfo * debug_info = DebugInfo(); + if (debug_info) + return debug_info->GetDIE(die_ref); + else + return DWARFDIE(); +} + + +std::unique_ptr<SymbolFileDWARFDwo> +SymbolFileDWARF::GetDwoSymbolFileForCompileUnit(DWARFCompileUnit &dwarf_cu, const DWARFDebugInfoEntry &cu_die) +{ + // If we are using a dSYM file, we never want the standard DWO files since + // the -gmodule support uses the same DWO machanism to specify full debug + // info files for modules. + if (GetDebugMapSymfile()) + return nullptr; + + const char *dwo_name = cu_die.GetAttributeValueAsString(this, &dwarf_cu, DW_AT_GNU_dwo_name, nullptr); + if (!dwo_name) + return nullptr; + + FileSpec dwo_file(dwo_name, true); + if (dwo_file.IsRelative()) + { + const char *comp_dir = cu_die.GetAttributeValueAsString(this, &dwarf_cu, DW_AT_comp_dir, nullptr); + if (!comp_dir) + return nullptr; + + dwo_file.SetFile(comp_dir, true); + dwo_file.AppendPathComponent(dwo_name); + } + + if (!dwo_file.Exists()) + return nullptr; + + const lldb::offset_t file_offset = 0; + DataBufferSP dwo_file_data_sp; + lldb::offset_t dwo_file_data_offset = 0; + ObjectFileSP dwo_obj_file = ObjectFile::FindPlugin(GetObjectFile()->GetModule(), &dwo_file, file_offset, + dwo_file.GetByteSize(), dwo_file_data_sp, dwo_file_data_offset); + if (dwo_obj_file == nullptr) + return nullptr; + + return llvm::make_unique<SymbolFileDWARFDwo>(dwo_obj_file, &dwarf_cu); +} + void SymbolFileDWARF::UpdateExternalModuleListIfNeeded() { @@ -1760,9 +1840,25 @@ SymbolFileDWARF::UpdateExternalModuleListIfNeeded() { ModuleSpec dwo_module_spec; dwo_module_spec.GetFileSpec().SetFile(dwo_path, false); + 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, true); + dwo_module_spec.GetFileSpec().AppendPathComponent(dwo_path); + } + } dwo_module_spec.GetArchitecture() = m_obj_file->GetModule()->GetArchitecture(); //printf ("Loading dwo = '%s'\n", dwo_path); Error error = ModuleList::GetSharedModule (dwo_module_spec, module_sp, NULL, NULL, NULL); + 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; } @@ -1799,7 +1895,7 @@ SymbolFileDWARF::GetGlobalAranges() const DWARFExpression &location = var_sp->LocationExpression(); Value location_result; Error error; - if (location.Evaluate(NULL, NULL, NULL, LLDB_INVALID_ADDRESS, NULL, location_result, &error)) + if (location.Evaluate(nullptr, nullptr, nullptr, LLDB_INVALID_ADDRESS, nullptr, nullptr, location_result, &error)) { if (location_result.GetValueType() == Value::eValueTypeFileAddress) { @@ -2094,6 +2190,9 @@ SymbolFileDWARF::Index () if (debug_info) { const uint32_t num_compile_units = GetNumCompileUnits(); + if (num_compile_units == 0) + return; + std::vector<NameToDIE> function_basename_index(num_compile_units); std::vector<NameToDIE> function_fullname_index(num_compile_units); std::vector<NameToDIE> function_method_index(num_compile_units); @@ -2102,7 +2201,8 @@ SymbolFileDWARF::Index () std::vector<NameToDIE> global_index(num_compile_units); std::vector<NameToDIE> type_index(num_compile_units); std::vector<NameToDIE> namespace_index(num_compile_units); - + + std::vector<bool> clear_cu_dies(num_compile_units, false); auto parser_fn = [this, debug_info, &function_basename_index, @@ -2115,25 +2215,62 @@ SymbolFileDWARF::Index () &namespace_index](uint32_t cu_idx) { DWARFCompileUnit* dwarf_cu = debug_info->GetCompileUnitAtIndex(cu_idx); - bool clear_dies = dwarf_cu->ExtractDIEsIfNeeded(false) > 1; - - dwarf_cu->Index(function_basename_index[cu_idx], - function_fullname_index[cu_idx], - function_method_index[cu_idx], - function_selector_index[cu_idx], - objc_class_selectors_index[cu_idx], - global_index[cu_idx], - type_index[cu_idx], - namespace_index[cu_idx]); - - // Keep memory down by clearing DIEs if this generate function - // caused them to be parsed - if (clear_dies) - dwarf_cu->ClearDIEs(true); - + if (dwarf_cu) + { + dwarf_cu->Index(function_basename_index[cu_idx], + function_fullname_index[cu_idx], + function_method_index[cu_idx], + function_selector_index[cu_idx], + objc_class_selectors_index[cu_idx], + global_index[cu_idx], + type_index[cu_idx], + namespace_index[cu_idx]); + } return cu_idx; }; + auto extract_fn = [this, + debug_info, + num_compile_units](uint32_t cu_idx) + { + DWARFCompileUnit* dwarf_cu = debug_info->GetCompileUnitAtIndex(cu_idx); + if (dwarf_cu) + { + // dwarf_cu->ExtractDIEsIfNeeded(false) will return zero if the + // DIEs for a compile unit have already been parsed. + return std::make_pair(cu_idx, dwarf_cu->ExtractDIEsIfNeeded(false) > 1); + } + return std::make_pair(cu_idx, false); + }; + + // Create a task runner that extracts dies for each DWARF compile unit in a separate thread + TaskRunner<std::pair<uint32_t, bool>> task_runner_extract; + for (uint32_t cu_idx = 0; cu_idx < num_compile_units; ++cu_idx) + task_runner_extract.AddTask(extract_fn, cu_idx); + + //---------------------------------------------------------------------- + // First figure out which compile units didn't have their DIEs already + // parsed and remember this. If no DIEs were parsed prior to this index + // function call, we are going to want to clear the CU dies after we + // are done indexing to make sure we don't pull in all DWARF dies, but + // we need to wait until all compile units have been indexed in case + // a DIE in one compile unit refers to another and the indexes accesses + // those DIEs. + //---------------------------------------------------------------------- + while (true) + { + auto f = task_runner_extract.WaitForNextCompletedTask(); + if (!f.valid()) + break; + unsigned cu_idx; + bool clear; + std::tie(cu_idx, clear) = f.get(); + clear_cu_dies[cu_idx] = clear; + } + + // Now create a task runner that can index each DWARF compile unit in a separate + // thread so we can index quickly. + TaskRunner<uint32_t> task_runner; for (uint32_t cu_idx = 0; cu_idx < num_compile_units; ++cu_idx) task_runner.AddTask(parser_fn, cu_idx); @@ -2165,6 +2302,16 @@ SymbolFileDWARF::Index () [&]() { m_type_index.Finalize(); }, [&]() { m_namespace_index.Finalize(); }); + //---------------------------------------------------------------------- + // Keep memory down by clearing DIEs for any compile units if indexing + // caused us to load the compile unit's DIEs. + //---------------------------------------------------------------------- + for (uint32_t cu_idx = 0; cu_idx < num_compile_units; ++cu_idx) + { + if (clear_cu_dies[cu_idx]) + debug_info->GetCompileUnitAtIndex(cu_idx)->ClearDIEs(true); + } + #if defined (ENABLE_DEBUG_PRINTF) StreamFile s(stdout, false); s.Printf ("DWARF index for '%s':", @@ -2265,12 +2412,11 @@ SymbolFileDWARF::FindGlobalVariables (const ConstString &name, const CompilerDec sc.module_sp = m_obj_file->GetModule(); assert (sc.module_sp); - DWARFDebugInfo* debug_info = DebugInfo(); bool done = false; for (size_t i=0; i<num_die_matches && !done; ++i) { const DIERef& die_ref = die_offsets[i]; - DWARFDIE die = debug_info->GetDIE (die_ref); + DWARFDIE die = GetDIE (die_ref); if (die) { @@ -2383,11 +2529,10 @@ SymbolFileDWARF::FindGlobalVariables(const RegularExpression& regex, bool append const size_t num_matches = die_offsets.size(); if (num_matches) { - DWARFDebugInfo* debug_info = DebugInfo(); for (size_t i=0; i<num_matches; ++i) { const DIERef& die_ref = die_offsets[i]; - DWARFDIE die = debug_info->GetDIE (die_ref); + DWARFDIE die = GetDIE (die_ref); if (die) { @@ -2971,9 +3116,20 @@ SymbolFileDWARF::FindTypes (const SymbolContext& sc, const ConstString &name, const CompilerDeclContext *parent_decl_ctx, bool append, - uint32_t max_matches, + uint32_t max_matches, + llvm::DenseSet<lldb_private::SymbolFile *> &searched_symbol_files, TypeMap& types) { + // If we aren't appending the results to this list, then clear the list + if (!append) + types.Clear(); + + // Make sure we haven't already searched this SymbolFile before... + if (searched_symbol_files.count(this)) + return 0; + else + searched_symbol_files.insert(this); + DWARFDebugInfo* info = DebugInfo(); if (info == NULL) return 0; @@ -2996,10 +3152,6 @@ SymbolFileDWARF::FindTypes (const SymbolContext& sc, max_matches); } - // If we aren't appending the results to this list, then clear the list - if (!append) - types.Clear(); - if (!DeclContextMatchesThisSymbolFile(parent_decl_ctx)) return 0; @@ -3026,11 +3178,10 @@ SymbolFileDWARF::FindTypes (const SymbolContext& sc, if (num_die_matches) { const uint32_t initial_types_size = types.GetSize(); - DWARFDebugInfo* debug_info = DebugInfo(); for (size_t i=0; i<num_die_matches; ++i) { const DIERef& die_ref = die_offsets[i]; - DWARFDIE die = debug_info->GetDIE (die_ref); + DWARFDIE die = GetDIE (die_ref); if (die) { @@ -3097,6 +3248,7 @@ SymbolFileDWARF::FindTypes (const SymbolContext& sc, parent_decl_ctx, append, max_matches, + searched_symbol_files, types); if (num_external_matches) return num_external_matches; @@ -3124,6 +3276,9 @@ SymbolFileDWARF::FindTypes (const std::vector<CompilerContext> &context, ConstString name = context.back().name; + if (!name) + return 0; + if (m_using_apple_tables) { if (m_apple_types_ap.get()) @@ -3145,11 +3300,10 @@ SymbolFileDWARF::FindTypes (const std::vector<CompilerContext> &context, if (num_die_matches) { size_t num_matches = 0; - DWARFDebugInfo* debug_info = DebugInfo(); for (size_t i=0; i<num_die_matches; ++i) { const DIERef& die_ref = die_offsets[i]; - DWARFDIE die = debug_info->GetDIE (die_ref); + DWARFDIE die = GetDIE (die_ref); if (die) { @@ -3228,11 +3382,10 @@ SymbolFileDWARF::FindNamespace (const SymbolContext& sc, const size_t num_matches = die_offsets.size(); if (num_matches) { - DWARFDebugInfo* debug_info = DebugInfo(); for (size_t i=0; i<num_matches; ++i) { const DIERef& die_ref = die_offsets[i]; - DWARFDIE die = debug_info->GetDIE (die_ref); + DWARFDIE die = GetDIE (die_ref); if (die) { @@ -3447,11 +3600,10 @@ SymbolFileDWARF::FindCompleteObjCDefinitionTypeForDIE (const DWARFDIE &die, if (num_matches) { - DWARFDebugInfo* debug_info = DebugInfo(); for (size_t i=0; i<num_matches; ++i) { const DIERef& die_ref = die_offsets[i]; - DWARFDIE type_die = debug_info->GetDIE (die_ref); + DWARFDIE type_die = GetDIE (die_ref); if (type_die) { @@ -3667,18 +3819,26 @@ SymbolFileDWARF::FindDefinitionTypeForDWARFDeclContext (const DWARFDeclContext & } const size_t num_matches = die_offsets.size(); - - + + // Get the type system that we are looking to find a type for. We will use this + // to ensure any matches we find are in a language that this type system supports + const LanguageType language = dwarf_decl_ctx.GetLanguage(); + TypeSystem *type_system = (language == eLanguageTypeUnknown) ? nullptr : GetTypeSystemForLanguage(language); + if (num_matches) { - DWARFDebugInfo* debug_info = DebugInfo(); for (size_t i=0; i<num_matches; ++i) { const DIERef& die_ref = die_offsets[i]; - DWARFDIE type_die = debug_info->GetDIE (die_ref); + DWARFDIE type_die = GetDIE (die_ref); if (type_die) { + // Make sure type_die's langauge matches the type system we are looking for. + // We don't want to find a "Foo" type from Java if we are looking for a "Foo" + // type for C, C++, ObjC, or ObjC++. + if (type_system && !type_system->SupportsLanguage(type_die.GetLanguage())) + continue; bool try_resolving_type = false; // Don't try and resolve the DIE we are looking for with the DIE itself! @@ -3919,7 +4079,7 @@ SymbolFileDWARF::ParseVariablesForContext (const SymbolContext& sc) if (sc.function) { - DWARFDIE function_die = info->GetDIE(DIERef(sc.function->GetID())); + DWARFDIE function_die = info->GetDIE(DIERef(sc.function->GetID(), this)); const dw_addr_t func_lo_pc = function_die.GetAttributeValueAsAddress (DW_AT_low_pc, LLDB_INVALID_ADDRESS); if (func_lo_pc != LLDB_INVALID_ADDRESS) @@ -3974,11 +4134,10 @@ SymbolFileDWARF::ParseVariablesForContext (const SymbolContext& sc) const size_t num_matches = die_offsets.size(); if (num_matches) { - DWARFDebugInfo* debug_info = DebugInfo(); for (size_t i=0; i<num_matches; ++i) { const DIERef& die_ref = die_offsets[i]; - DWARFDIE die = debug_info->GetDIE (die_ref); + DWARFDIE die = GetDIE (die_ref); if (die) { VariableSP var_sp (ParseVariableDIE(sc, die, LLDB_INVALID_ADDRESS)); @@ -4047,6 +4206,7 @@ SymbolFileDWARF::ParseVariableDIE bool location_is_const_value_data = false; bool has_explicit_location = false; DWARFFormValue const_value; + Variable::RangeList scope_ranges; //AccessType accessibility = eAccessNone; for (i=0; i<num_attributes; ++i) @@ -4156,19 +4316,47 @@ SymbolFileDWARF::ParseVariableDIE } break; case DW_AT_specification: - { - DWARFDebugInfo* debug_info = DebugInfo(); - if (debug_info) - spec_die = debug_info->GetDIE(DIERef(form_value)); + spec_die = GetDIE(DIERef(form_value)); + break; + case DW_AT_start_scope: + { + if (form_value.Form() == DW_FORM_sec_offset) + { + DWARFRangeList dwarf_scope_ranges; + const DWARFDebugRanges* debug_ranges = DebugRanges(); + debug_ranges->FindRanges(form_value.Unsigned(), dwarf_scope_ranges); + + // All DW_AT_start_scope are relative to the base address of the + // compile unit. We add the compile unit base address to make + // sure all the addresses are properly fixed up. + for (size_t i = 0, count = dwarf_scope_ranges.GetSize(); i < count; ++i) + { + const DWARFRangeList::Entry& range = dwarf_scope_ranges.GetEntryRef(i); + scope_ranges.Append(range.GetRangeBase() + die.GetCU()->GetBaseAddress(), + range.GetByteSize()); + } + } + else + { + // TODO: Handle the case when DW_AT_start_scope have form constant. The + // dwarf spec is a bit ambiguous about what is the expected behavior in + // case the enclosing block have a non coninious address range and the + // DW_AT_start_scope entry have a form constant. + GetObjectFile()->GetModule()->ReportWarning ("0x%8.8" PRIx64 ": DW_AT_start_scope has unsupported form type (0x%x)\n", + die.GetID(), + form_value.Form()); + } + + scope_ranges.Sort(); + scope_ranges.CombineConsecutiveRanges(); + } break; - } case DW_AT_artificial: is_artificial = form_value.Boolean(); break; case DW_AT_accessibility: break; //accessibility = DW_ACCESS_to_AccessType(form_value.Unsigned()); break; case DW_AT_declaration: case DW_AT_description: case DW_AT_endianity: case DW_AT_segment: - case DW_AT_start_scope: case DW_AT_visibility: default: case DW_AT_abstract_origin: @@ -4232,6 +4420,7 @@ SymbolFileDWARF::ParseVariableDIE GetObjectFile()->GetModule()->ReportError ("0x%8.8x: %s has an invalid location: %s", die.GetOffset(), die.GetTagAsCString(), strm.GetString().c_str()); } } + SymbolFileDWARFDebugMap *debug_map_symfile = GetDebugMapSymfile(); if (location_DW_OP_addr != LLDB_INVALID_ADDRESS) { @@ -4240,9 +4429,6 @@ SymbolFileDWARF::ParseVariableDIE else scope = eValueTypeVariableStatic; - - SymbolFileDWARFDebugMap *debug_map_symfile = GetDebugMapSymfile (); - if (debug_map_symfile) { // When leaving the DWARF in the .o files on darwin, @@ -4320,7 +4506,22 @@ SymbolFileDWARF::ParseVariableDIE if (location_is_const_value_data) scope = eValueTypeVariableStatic; else + { scope = eValueTypeVariableLocal; + if (debug_map_symfile) + { + // We need to check for TLS addresses that we need to fixup + if (location.ContainsThreadLocalStorage()) + { + location.LinkThreadLocalStorage( + debug_map_symfile->GetObjectFile()->GetModule(), + [this, debug_map_symfile](lldb::addr_t unlinked_file_addr) -> lldb::addr_t { + return debug_map_symfile->LinkOSOFileAddress(this, unlinked_file_addr); + }); + scope = eValueTypeVariableThreadLocal; + } + } + } } } @@ -4347,20 +4548,21 @@ SymbolFileDWARF::ParseVariableDIE if (symbol_context_scope) { - SymbolFileTypeSP type_sp(new SymbolFileType(*this, DIERef(type_die_form).GetUID())); - + SymbolFileTypeSP type_sp(new SymbolFileType(*this, DIERef(type_die_form).GetUID(this))); + if (const_value.Form() && type_sp && type_sp->GetType()) location.CopyOpcodeData(const_value.Unsigned(), type_sp->GetType()->GetByteSize(), die.GetCU()->GetAddressByteSize()); - + var_sp.reset (new Variable (die.GetID(), - name, + name, mangled, type_sp, - scope, - symbol_context_scope, - &decl, - location, - is_external, + scope, + symbol_context_scope, + scope_ranges, + &decl, + location, + is_external, is_artificial, is_static_member)); @@ -4505,7 +4707,7 @@ SymbolFileDWARF::ParseVariables (const SymbolContext& sc, // a concrete block counterpart in the current function. We need // to find the concrete block so we can correctly add the // variable to it - const DWARFDIE concrete_block_die = FindBlockContainingSpecification (DIERef(sc.function->GetID()), + const DWARFDIE concrete_block_die = FindBlockContainingSpecification (DIERef(sc.function->GetID(), this), sc_parent_die.GetOffset()); if (concrete_block_die) block = sc.function->GetBlock(true).FindBlockByID(concrete_block_die.GetID()); @@ -4596,7 +4798,7 @@ SymbolFileDWARF::DumpIndexes () SymbolFileDWARFDebugMap * -SymbolFileDWARF::GetDebugMapSymfile () +SymbolFileDWARF::GetDebugMapSymfile() { if (m_debug_map_symfile == NULL && !m_debug_map_module_wp.expired()) { diff --git a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h index be097595346ec..865e589627003 100644 --- a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h +++ b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h @@ -58,6 +58,7 @@ class DWARFDeclContext; class DWARFDIECollection; class DWARFFormValue; class SymbolFileDWARFDebugMap; +class SymbolFileDWARFDwo; #define DIE_IS_BEING_PARSED ((lldb_private::Type*)1) @@ -67,9 +68,12 @@ public: friend class SymbolFileDWARFDebugMap; friend class SymbolFileDWARFDwo; friend class DebugMapModule; + friend struct DIERef; friend class DWARFCompileUnit; + friend class DWARFDIE; friend class DWARFASTParserClang; friend class DWARFASTParserGo; + friend class DWARFASTParserJava; //------------------------------------------------------------------ // Static Functions @@ -133,8 +137,11 @@ public: lldb_private::FileSpecList& support_files) override; bool - ParseImportedModules (const lldb_private::SymbolContext &sc, - std::vector<lldb_private::ConstString> &imported_modules) override; + ParseCompileUnitIsOptimized(const lldb_private::SymbolContext &sc) override; + + bool + ParseImportedModules(const lldb_private::SymbolContext &sc, + std::vector<lldb_private::ConstString> &imported_modules) override; size_t ParseFunctionBlocks (const lldb_private::SymbolContext& sc) override; @@ -156,6 +163,12 @@ public: bool assert_not_being_parsed = true, bool resolve_function_context = false); + SymbolFileDWARF * + GetDWARFForUID (lldb::user_id_t uid); + + DWARFDIE + GetDIEFromUID (lldb::user_id_t uid); + lldb_private::CompilerDecl GetDeclForUID (lldb::user_id_t uid) override; @@ -218,6 +231,7 @@ public: const lldb_private::CompilerDeclContext *parent_decl_ctx, bool append, uint32_t max_matches, + llvm::DenseSet<lldb_private::SymbolFile *> &searched_symbol_files, lldb_private::TypeMap& types) override; size_t @@ -299,12 +313,6 @@ public: GetCompUnitForDWARFCompUnit(DWARFCompileUnit* dwarf_cu, uint32_t cu_idx = UINT32_MAX); - lldb::user_id_t - MakeUserID (dw_offset_t die_offset) const - { - return GetID() | die_offset; - } - size_t GetObjCMethodDIEOffsets (lldb_private::ConstString class_name, DIEArray &method_die_offsets); @@ -327,6 +335,12 @@ public: lldb::ModuleSP GetDWOModule (lldb_private::ConstString name); + virtual DWARFDIE + GetDIE(const DIERef &die_ref); + + virtual std::unique_ptr<SymbolFileDWARFDwo> + GetDwoSymbolFileForCompileUnit(DWARFCompileUnit &dwarf_cu, const DWARFDebugInfoEntry &cu_die); + protected: typedef llvm::DenseMap<const DWARFDebugInfoEntry *, lldb_private::Type *> DIEToTypePtr; typedef llvm::DenseMap<const DWARFDebugInfoEntry *, lldb::VariableSP> DIEToVariableSP; @@ -387,8 +401,10 @@ protected: bool *type_is_new); lldb_private::Type * - ResolveTypeUID (const DWARFDIE &die, - bool assert_not_being_parsed); + ResolveTypeUID(const DWARFDIE &die, bool assert_not_being_parsed); + + lldb_private::Type * + ResolveTypeUID(const DIERef &die_ref); lldb::VariableSP ParseVariableDIE(const lldb_private::SymbolContext& sc, @@ -483,15 +499,6 @@ protected: GetUniqueDWARFASTTypeMap (); bool - UserIDMatches (lldb::user_id_t uid) const - { - const lldb::user_id_t high_uid = uid & 0xffffffff00000000ull; - if (high_uid != 0 && GetID() != 0) - return high_uid == GetID(); - return true; - } - - bool DIEDeclContextsMatch (const DWARFDIE &die1, const DWARFDIE &die2); diff --git a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp index be25dfc99deea..ca819624c715d 100644 --- a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp +++ b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp @@ -123,8 +123,9 @@ SymbolFileDWARFDebugMap::CompileUnitInfo::GetFileRangeMap(SymbolFileDWARFDebugMa // Add the inverse OSO file address to debug map entry mapping exe_symfile->AddOSOFileRange (this, exe_symbol->GetAddressRef().GetFileAddress(), + exe_symbol->GetByteSize(), oso_fun_symbol->GetAddressRef().GetFileAddress(), - std::min<addr_t>(exe_symbol->GetByteSize(), oso_fun_symbol->GetByteSize())); + oso_fun_symbol->GetByteSize()); } } @@ -157,8 +158,9 @@ SymbolFileDWARFDebugMap::CompileUnitInfo::GetFileRangeMap(SymbolFileDWARFDebugMa // Add the inverse OSO file address to debug map entry mapping exe_symfile->AddOSOFileRange (this, exe_symbol->GetAddressRef().GetFileAddress(), + exe_symbol->GetByteSize(), oso_gsym_symbol->GetAddressRef().GetFileAddress(), - std::min<addr_t>(exe_symbol->GetByteSize(), oso_gsym_symbol->GetByteSize())); + oso_gsym_symbol->GetByteSize()); } } break; @@ -206,7 +208,7 @@ public: ObjectFile *oso_objfile = GetObjectFile (); if (oso_objfile) { - Mutex::Locker locker (m_mutex); + std::lock_guard<std::recursive_mutex> guard(m_mutex); SymbolVendor* symbol_vendor = Module::GetSymbolVendor(can_create, feedback_strm); if (symbol_vendor) { @@ -635,13 +637,9 @@ SymbolFileDWARFDebugMap::ParseCompileUnitAtIndex(uint32_t cu_idx) // zero in each .o file since each .o file can only have // one compile unit for now. lldb::user_id_t cu_id = 0; - m_compile_unit_infos[cu_idx].compile_unit_sp.reset(new CompileUnit (m_obj_file->GetModule(), - NULL, - so_file_spec, - cu_id, - eLanguageTypeUnknown, - false)); - + m_compile_unit_infos[cu_idx].compile_unit_sp.reset(new CompileUnit( + m_obj_file->GetModule(), NULL, so_file_spec, cu_id, eLanguageTypeUnknown, eLazyBoolCalculate)); + if (m_compile_unit_infos[cu_idx].compile_unit_sp) { // Let our symbol vendor know about this compile unit @@ -725,7 +723,16 @@ SymbolFileDWARFDebugMap::ParseCompileUnitSupportFiles (const SymbolContext& sc, } bool -SymbolFileDWARFDebugMap::ParseImportedModules (const SymbolContext &sc, std::vector<ConstString> &imported_modules) +SymbolFileDWARFDebugMap::ParseCompileUnitIsOptimized(const lldb_private::SymbolContext &sc) +{ + SymbolFileDWARF *oso_dwarf = GetSymbolFile(sc); + if (oso_dwarf) + return oso_dwarf->ParseCompileUnitIsOptimized(sc); + return false; +} + +bool +SymbolFileDWARFDebugMap::ParseImportedModules(const SymbolContext &sc, std::vector<ConstString> &imported_modules) { SymbolFileDWARF *oso_dwarf = GetSymbolFile (sc); if (oso_dwarf) @@ -1276,7 +1283,8 @@ SymbolFileDWARFDebugMap::FindTypes const ConstString &name, const CompilerDeclContext *parent_decl_ctx, bool append, - uint32_t max_matches, + uint32_t max_matches, + llvm::DenseSet<lldb_private::SymbolFile *> &searched_symbol_files, TypeMap& types ) { @@ -1290,13 +1298,16 @@ SymbolFileDWARFDebugMap::FindTypes { oso_dwarf = GetSymbolFile (sc); if (oso_dwarf) - return oso_dwarf->FindTypes (sc, name, parent_decl_ctx, append, max_matches, types); + return oso_dwarf->FindTypes (sc, name, parent_decl_ctx, append, max_matches, searched_symbol_files, types); } else { ForEachSymbolFile([&](SymbolFileDWARF *oso_dwarf) -> bool { - oso_dwarf->FindTypes (sc, name, parent_decl_ctx, append, max_matches, types); - return false; + oso_dwarf->FindTypes (sc, name, parent_decl_ctx, append, max_matches, searched_symbol_files, types); + if (types.GetSize() >= max_matches) + return true; + else + return false; }); } @@ -1452,6 +1463,7 @@ SymbolFileDWARFDebugMap::ParseDeclsForContext (lldb_private::CompilerDeclContext bool SymbolFileDWARFDebugMap::AddOSOFileRange (CompileUnitInfo *cu_info, lldb::addr_t exe_file_addr, + lldb::addr_t exe_byte_size, lldb::addr_t oso_file_addr, lldb::addr_t oso_byte_size) { @@ -1460,7 +1472,14 @@ SymbolFileDWARFDebugMap::AddOSOFileRange (CompileUnitInfo *cu_info, { DebugMap::Entry *debug_map_entry = m_debug_map.FindEntryThatContains(exe_file_addr); debug_map_entry->data.SetOSOFileAddress(oso_file_addr); - cu_info->file_range_map.Append(FileRangeMap::Entry(oso_file_addr, oso_byte_size, exe_file_addr)); + addr_t range_size = std::min<addr_t>(exe_byte_size, oso_byte_size); + if (range_size == 0) + { + range_size = std::max<addr_t>(exe_byte_size, oso_byte_size); + if (range_size == 0) + range_size = 1; + } + cu_info->file_range_map.Append(FileRangeMap::Entry(oso_file_addr, range_size, exe_file_addr)); return true; } return false; diff --git a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h index 1eb33c927bdfb..fcf02975a58fb 100644 --- a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h +++ b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h @@ -65,6 +65,8 @@ public: bool ParseCompileUnitLineTable (const lldb_private::SymbolContext& sc) override; bool ParseCompileUnitDebugMacros (const lldb_private::SymbolContext& sc) override; bool ParseCompileUnitSupportFiles (const lldb_private::SymbolContext& sc, lldb_private::FileSpecList &support_files) override; + bool + ParseCompileUnitIsOptimized(const lldb_private::SymbolContext &sc) override; bool ParseImportedModules (const lldb_private::SymbolContext &sc, std::vector<lldb_private::ConstString> &imported_modules) override; size_t ParseFunctionBlocks (const lldb_private::SymbolContext& sc) override; size_t ParseTypes (const lldb_private::SymbolContext& sc) override; @@ -82,7 +84,7 @@ public: uint32_t FindGlobalVariables (const lldb_private::RegularExpression& regex, bool append, uint32_t max_matches, lldb_private::VariableList& variables) override; uint32_t FindFunctions (const lldb_private::ConstString &name, const lldb_private::CompilerDeclContext *parent_decl_ctx, uint32_t name_type_mask, bool include_inlines, bool append, lldb_private::SymbolContextList& sc_list) override; uint32_t FindFunctions (const lldb_private::RegularExpression& regex, bool include_inlines, bool append, lldb_private::SymbolContextList& sc_list) override; - uint32_t FindTypes (const lldb_private::SymbolContext& sc, const lldb_private::ConstString &name, const lldb_private::CompilerDeclContext *parent_decl_ctx, bool append, uint32_t max_matches, lldb_private::TypeMap& types) override; + uint32_t FindTypes (const lldb_private::SymbolContext& sc, const lldb_private::ConstString &name, const lldb_private::CompilerDeclContext *parent_decl_ctx, bool append, uint32_t max_matches, llvm::DenseSet<lldb_private::SymbolFile *> &searched_symbol_files, lldb_private::TypeMap& types) override; lldb_private::CompilerDeclContext FindNamespace (const lldb_private::SymbolContext& sc, const lldb_private::ConstString &name, @@ -107,10 +109,11 @@ protected: kNumFlags }; - friend class DWARFCompileUnit; - friend class SymbolFileDWARF; friend class DebugMapModule; + friend struct DIERef; friend class DWARFASTParserClang; + friend class DWARFCompileUnit; + friend class SymbolFileDWARF; struct OSOInfo { lldb::ModuleSP module_sp; @@ -348,6 +351,7 @@ protected: bool AddOSOFileRange (CompileUnitInfo *cu_info, lldb::addr_t exe_file_addr, + lldb::addr_t exe_byte_size, lldb::addr_t oso_file_addr, lldb::addr_t oso_byte_size); diff --git a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.cpp b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.cpp index 326c397c83d56..14603aa460c9e 100644 --- a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.cpp +++ b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.cpp @@ -12,6 +12,7 @@ #include "lldb/Core/Section.h" #include "lldb/Expression/DWARFExpression.h" #include "lldb/Symbol/ObjectFile.h" +#include "lldb/Utility/LLDBAssert.h" #include "DWARFCompileUnit.h" #include "DWARFDebugInfo.h" @@ -129,3 +130,10 @@ SymbolFileDWARFDwo::GetTypeSystemForLanguage(LanguageType language) { return GetBaseSymbolFile()->GetTypeSystemForLanguage(language); } + +DWARFDIE +SymbolFileDWARFDwo::GetDIE(const DIERef &die_ref) +{ + lldbassert(m_base_dwarf_cu->GetOffset() == die_ref.cu_offset); + return DebugInfo()->GetDIEForDIEOffset(die_ref.die_offset); +} diff --git a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.h b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.h index 39ed6502229b5..9391a28249482 100644 --- a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.h +++ b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.h @@ -38,6 +38,15 @@ public: lldb_private::TypeSystem* GetTypeSystemForLanguage(lldb::LanguageType language) override; + DWARFDIE + GetDIE(const DIERef &die_ref) override; + + std::unique_ptr<SymbolFileDWARFDwo> + GetDwoSymbolFileForCompileUnit(DWARFCompileUnit &dwarf_cu, const DWARFDebugInfoEntry &cu_die) override + { + return nullptr; + } + protected: void LoadSectionData (lldb::SectionType sect_type, lldb_private::DWARFDataExtractor& data) override; diff --git a/source/Plugins/SymbolFile/PDB/CMakeLists.txt b/source/Plugins/SymbolFile/PDB/CMakeLists.txt new file mode 100644 index 0000000000000..79d8a25d6979d --- /dev/null +++ b/source/Plugins/SymbolFile/PDB/CMakeLists.txt @@ -0,0 +1,7 @@ +set(LLVM_PRIVATE_LINK_COMPONENTS + DebugInfoPDB) + +add_lldb_library(lldbPluginSymbolFilePDB + PDBASTParser.cpp + SymbolFilePDB.cpp + ) diff --git a/source/Plugins/SymbolFile/PDB/PDBASTParser.cpp b/source/Plugins/SymbolFile/PDB/PDBASTParser.cpp new file mode 100644 index 0000000000000..1e8e040fd47c9 --- /dev/null +++ b/source/Plugins/SymbolFile/PDB/PDBASTParser.cpp @@ -0,0 +1,237 @@ +//===-- PDBASTParser.cpp ----------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "PDBASTParser.h" + +#include "clang/AST/CharUnits.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclCXX.h" + +#include "lldb/Symbol/ClangASTContext.h" +#include "lldb/Symbol/ClangUtil.h" +#include "lldb/Symbol/Declaration.h" +#include "lldb/Symbol/SymbolFile.h" +#include "lldb/Symbol/TypeSystem.h" + +#include "llvm/DebugInfo/PDB/PDBSymbol.h" +#include "llvm/DebugInfo/PDB/PDBSymbolData.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeArray.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeBuiltin.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeFunctionArg.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeFunctionSig.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeTypedef.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h" + +using namespace lldb; +using namespace lldb_private; +using namespace llvm; +using namespace llvm::pdb; + +namespace +{ +int +TranslateUdtKind(PDB_UdtType pdb_kind) +{ + switch (pdb_kind) + { + case PDB_UdtType::Class: + return clang::TTK_Class; + case PDB_UdtType::Struct: + return clang::TTK_Struct; + case PDB_UdtType::Union: + return clang::TTK_Union; + case PDB_UdtType::Interface: + return clang::TTK_Interface; + } + return clang::TTK_Class; +} + +lldb::Encoding +TranslateBuiltinEncoding(PDB_BuiltinType type) +{ + switch (type) + { + case PDB_BuiltinType::Float: + return lldb::eEncodingIEEE754; + case PDB_BuiltinType::Int: + case PDB_BuiltinType::Long: + case PDB_BuiltinType::Char: + return lldb::eEncodingSint; + case PDB_BuiltinType::Bool: + case PDB_BuiltinType::UInt: + case PDB_BuiltinType::ULong: + case PDB_BuiltinType::HResult: + return lldb::eEncodingUint; + default: + return lldb::eEncodingInvalid; + } +} +} + +PDBASTParser::PDBASTParser(lldb_private::ClangASTContext &ast) : m_ast(ast) +{ +} + +PDBASTParser::~PDBASTParser() +{ +} + +// DebugInfoASTParser interface + +lldb::TypeSP +PDBASTParser::CreateLLDBTypeFromPDBType(const PDBSymbol &type) +{ + // PDB doesn't maintain enough information to robustly rebuild the entire + // tree, and this is most problematic when it comes to figure out the + // right DeclContext to put a type in. So for now, everything goes in + // the translation unit decl as a fully qualified type. + clang::DeclContext *tu_decl_ctx = m_ast.GetTranslationUnitDecl(); + Declaration decl; + + if (auto udt = llvm::dyn_cast<PDBSymbolTypeUDT>(&type)) + { + AccessType access = lldb::eAccessPublic; + PDB_UdtType udt_kind = udt->getUdtKind(); + + if (udt_kind == PDB_UdtType::Class) + access = lldb::eAccessPrivate; + + CompilerType clang_type = + m_ast.CreateRecordType(tu_decl_ctx, access, udt->getName().c_str(), TranslateUdtKind(udt_kind), + lldb::eLanguageTypeC_plus_plus, nullptr); + + m_ast.SetHasExternalStorage(clang_type.GetOpaqueQualType(), true); + + return std::make_shared<Type>(type.getSymIndexId(), m_ast.GetSymbolFile(), ConstString(udt->getName()), + udt->getLength(), nullptr, LLDB_INVALID_UID, Type::eEncodingIsUID, decl, + clang_type, Type::eResolveStateForward); + } + else if (auto enum_type = llvm::dyn_cast<PDBSymbolTypeEnum>(&type)) + { + std::string name = enum_type->getName(); + lldb::Encoding encoding = TranslateBuiltinEncoding(enum_type->getBuiltinType()); + uint64_t bytes = enum_type->getLength(); + CompilerType builtin_type = m_ast.GetBuiltinTypeForEncodingAndBitSize(encoding, bytes * 8); + + CompilerType ast_enum = m_ast.CreateEnumerationType(name.c_str(), tu_decl_ctx, decl, builtin_type); + auto enum_values = enum_type->findAllChildren<PDBSymbolData>(); + while (auto enum_value = enum_values->getNext()) + { + if (enum_value->getDataKind() != PDB_DataKind::Constant) + continue; + AddEnumValue(ast_enum, *enum_value); + } + + return std::make_shared<Type>(type.getSymIndexId(), m_ast.GetSymbolFile(), ConstString(name), bytes, nullptr, + LLDB_INVALID_UID, Type::eEncodingIsUID, decl, ast_enum, Type::eResolveStateFull); + } + else if (auto type_def = llvm::dyn_cast<PDBSymbolTypeTypedef>(&type)) + { + Type *target_type = m_ast.GetSymbolFile()->ResolveTypeUID(type_def->getTypeId()); + std::string name = type_def->getName(); + uint64_t bytes = type_def->getLength(); + if (!target_type) + return nullptr; + CompilerType target_ast_type = target_type->GetFullCompilerType(); + CompilerDeclContext target_decl_ctx = m_ast.GetSymbolFile()->GetDeclContextForUID(target_type->GetID()); + CompilerType ast_typedef = m_ast.CreateTypedefType(target_ast_type, name.c_str(), target_decl_ctx); + return std::make_shared<Type>(type_def->getSymIndexId(), m_ast.GetSymbolFile(), ConstString(name), bytes, + nullptr, target_type->GetID(), Type::eEncodingIsTypedefUID, decl, ast_typedef, + Type::eResolveStateFull); + } + else if (auto func_sig = llvm::dyn_cast<PDBSymbolTypeFunctionSig>(&type)) + { + auto arg_enum = func_sig->getArguments(); + uint32_t num_args = arg_enum->getChildCount(); + std::vector<CompilerType> arg_list(num_args); + while (auto arg = arg_enum->getNext()) + { + Type *arg_type = m_ast.GetSymbolFile()->ResolveTypeUID(arg->getSymIndexId()); + // If there's some error looking up one of the dependent types of this function signature, bail. + if (!arg_type) + return nullptr; + CompilerType arg_ast_type = arg_type->GetFullCompilerType(); + arg_list.push_back(arg_ast_type); + } + auto pdb_return_type = func_sig->getReturnType(); + Type *return_type = m_ast.GetSymbolFile()->ResolveTypeUID(pdb_return_type->getSymIndexId()); + // If there's some error looking up one of the dependent types of this function signature, bail. + if (!return_type) + return nullptr; + CompilerType return_ast_type = return_type->GetFullCompilerType(); + uint32_t type_quals = 0; + if (func_sig->isConstType()) + type_quals |= clang::Qualifiers::Const; + if (func_sig->isVolatileType()) + type_quals |= clang::Qualifiers::Volatile; + CompilerType func_sig_ast_type = + m_ast.CreateFunctionType(return_ast_type, &arg_list[0], num_args, false, type_quals); + + return std::make_shared<Type>(func_sig->getSymIndexId(), m_ast.GetSymbolFile(), ConstString(), 0, nullptr, + LLDB_INVALID_UID, Type::eEncodingIsUID, decl, func_sig_ast_type, + Type::eResolveStateFull); + } + else if (auto array_type = llvm::dyn_cast<PDBSymbolTypeArray>(&type)) + { + uint32_t num_elements = array_type->getCount(); + uint32_t element_uid = array_type->getElementType()->getSymIndexId(); + uint32_t bytes = array_type->getLength(); + + Type *element_type = m_ast.GetSymbolFile()->ResolveTypeUID(element_uid); + CompilerType element_ast_type = element_type->GetFullCompilerType(); + CompilerType array_ast_type = m_ast.CreateArrayType(element_ast_type, num_elements, false); + return std::make_shared<Type>(array_type->getSymIndexId(), m_ast.GetSymbolFile(), ConstString(), bytes, nullptr, + LLDB_INVALID_UID, Type::eEncodingIsUID, decl, array_ast_type, + Type::eResolveStateFull); + } + return nullptr; +} + +bool +PDBASTParser::AddEnumValue(CompilerType enum_type, const PDBSymbolData &enum_value) const +{ + Declaration decl; + Variant v = enum_value.getValue(); + std::string name = enum_value.getName(); + int64_t raw_value; + switch (v.Type) + { + case PDB_VariantType::Int8: + raw_value = v.Value.Int8; + break; + case PDB_VariantType::Int16: + raw_value = v.Value.Int16; + break; + case PDB_VariantType::Int32: + raw_value = v.Value.Int32; + break; + case PDB_VariantType::Int64: + raw_value = v.Value.Int64; + break; + case PDB_VariantType::UInt8: + raw_value = v.Value.UInt8; + break; + case PDB_VariantType::UInt16: + raw_value = v.Value.UInt16; + break; + case PDB_VariantType::UInt32: + raw_value = v.Value.UInt32; + break; + case PDB_VariantType::UInt64: + raw_value = v.Value.UInt64; + break; + default: + return false; + } + CompilerType underlying_type = m_ast.GetEnumerationIntegerType(enum_type.GetOpaqueQualType()); + uint32_t byte_size = m_ast.getASTContext()->getTypeSize(ClangUtil::GetQualType(underlying_type)); + return m_ast.AddEnumerationValueToEnumerationType(enum_type.GetOpaqueQualType(), underlying_type, decl, + name.c_str(), raw_value, byte_size * 8); +} diff --git a/source/Plugins/SymbolFile/PDB/PDBASTParser.h b/source/Plugins/SymbolFile/PDB/PDBASTParser.h new file mode 100644 index 0000000000000..ca425c17c4515 --- /dev/null +++ b/source/Plugins/SymbolFile/PDB/PDBASTParser.h @@ -0,0 +1,58 @@ +//===-- PDBASTParser.h ------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_PLUGINS_SYMBOLFILE_PDB_PDBASTPARSER_H +#define LLDB_PLUGINS_SYMBOLFILE_PDB_PDBASTPARSER_H + +#include "lldb/lldb-forward.h" + +#include "lldb/Symbol/ClangASTImporter.h" + +namespace clang +{ +class CharUnits; +class CXXRecordDecl; +class FieldDecl; +class RecordDecl; +} + +namespace lldb_private +{ +class ClangASTContext; +class CompilerType; +} + +namespace llvm +{ +namespace pdb +{ +class PDBSymbol; +class PDBSymbolData; +class PDBSymbolTypeBuiltin; +} +} + +class PDBASTParser +{ +public: + PDBASTParser(lldb_private::ClangASTContext &ast); + ~PDBASTParser(); + + lldb::TypeSP + CreateLLDBTypeFromPDBType(const llvm::pdb::PDBSymbol &type); + +private: + bool + AddEnumValue(lldb_private::CompilerType enum_type, const llvm::pdb::PDBSymbolData &data) const; + + lldb_private::ClangASTContext &m_ast; + lldb_private::ClangASTImporter m_ast_importer; +}; + +#endif // SymbolFileDWARF_DWARFASTParserClang_h_ diff --git a/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp b/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp new file mode 100644 index 0000000000000..d8092c011acb6 --- /dev/null +++ b/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp @@ -0,0 +1,733 @@ +//===-- SymbolFilePDB.cpp ---------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "SymbolFilePDB.h" + +#include "clang/Lex/Lexer.h" + +#include "lldb/Core/Module.h" +#include "lldb/Core/PluginManager.h" +#include "lldb/Symbol/ClangASTContext.h" +#include "lldb/Symbol/CompileUnit.h" +#include "lldb/Symbol/LineTable.h" +#include "lldb/Symbol/ObjectFile.h" +#include "lldb/Symbol/SymbolContext.h" +#include "lldb/Symbol/TypeMap.h" + +#include "llvm/DebugInfo/PDB/GenericError.h" +#include "llvm/DebugInfo/PDB/IPDBEnumChildren.h" +#include "llvm/DebugInfo/PDB/IPDBLineNumber.h" +#include "llvm/DebugInfo/PDB/IPDBSourceFile.h" +#include "llvm/DebugInfo/PDB/PDBSymbol.h" +#include "llvm/DebugInfo/PDB/PDBSymbolCompiland.h" +#include "llvm/DebugInfo/PDB/PDBSymbolCompilandDetails.h" +#include "llvm/DebugInfo/PDB/PDBSymbolExe.h" +#include "llvm/DebugInfo/PDB/PDBSymbolFunc.h" +#include "llvm/DebugInfo/PDB/PDBSymbolFuncDebugEnd.h" +#include "llvm/DebugInfo/PDB/PDBSymbolFuncDebugStart.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeTypedef.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h" + +#include "Plugins/SymbolFile/PDB/PDBASTParser.h" + +#include <regex> + +using namespace lldb_private; +using namespace llvm::pdb; + +namespace +{ +lldb::LanguageType +TranslateLanguage(PDB_Lang lang) +{ + switch (lang) + { + case PDB_Lang::Cpp: + return lldb::LanguageType::eLanguageTypeC_plus_plus; + case PDB_Lang::C: + return lldb::LanguageType::eLanguageTypeC; + default: + return lldb::LanguageType::eLanguageTypeUnknown; + } + } + + bool + ShouldAddLine(uint32_t requested_line, uint32_t actual_line, uint32_t addr_length) + { + return ((requested_line == 0 || actual_line == requested_line) && addr_length > 0); + } +} + +void +SymbolFilePDB::Initialize() +{ + PluginManager::RegisterPlugin(GetPluginNameStatic(), GetPluginDescriptionStatic(), CreateInstance, + DebuggerInitialize); +} + +void +SymbolFilePDB::Terminate() +{ + PluginManager::UnregisterPlugin(CreateInstance); +} + +void +SymbolFilePDB::DebuggerInitialize(lldb_private::Debugger &debugger) +{ +} + +lldb_private::ConstString +SymbolFilePDB::GetPluginNameStatic() +{ + static ConstString g_name("pdb"); + return g_name; +} + +const char * +SymbolFilePDB::GetPluginDescriptionStatic() +{ + return "Microsoft PDB debug symbol file reader."; +} + +lldb_private::SymbolFile * +SymbolFilePDB::CreateInstance(lldb_private::ObjectFile *obj_file) +{ + return new SymbolFilePDB(obj_file); +} + +SymbolFilePDB::SymbolFilePDB(lldb_private::ObjectFile *object_file) + : SymbolFile(object_file), m_cached_compile_unit_count(0) +{ +} + +SymbolFilePDB::~SymbolFilePDB() +{ +} + +uint32_t +SymbolFilePDB::CalculateAbilities() +{ + if (!m_session_up) + { + // Lazily load and match the PDB file, but only do this once. + std::string exePath = m_obj_file->GetFileSpec().GetPath(); + auto error = loadDataForEXE(PDB_ReaderType::DIA, llvm::StringRef(exePath), m_session_up); + if (error) + { + llvm::consumeError(std::move(error)); + return 0; + } + } + return CompileUnits | LineTables; +} + +void +SymbolFilePDB::InitializeObject() +{ + lldb::addr_t obj_load_address = m_obj_file->GetFileOffset(); + m_session_up->setLoadAddress(obj_load_address); + + TypeSystem *type_system = GetTypeSystemForLanguage(lldb::eLanguageTypeC_plus_plus); + ClangASTContext *clang_type_system = llvm::dyn_cast_or_null<ClangASTContext>(type_system); + m_tu_decl_ctx_up = llvm::make_unique<CompilerDeclContext>(type_system, clang_type_system->GetTranslationUnitDecl()); +} + +uint32_t +SymbolFilePDB::GetNumCompileUnits() +{ + if (m_cached_compile_unit_count == 0) + { + auto global = m_session_up->getGlobalScope(); + auto compilands = global->findAllChildren<PDBSymbolCompiland>(); + m_cached_compile_unit_count = compilands->getChildCount(); + + // The linker can inject an additional "dummy" compilation unit into the PDB. + // Ignore this special compile unit for our purposes, if it is there. It is + // always the last one. + auto last_cu = compilands->getChildAtIndex(m_cached_compile_unit_count - 1); + std::string name = last_cu->getName(); + if (name == "* Linker *") + --m_cached_compile_unit_count; + } + return m_cached_compile_unit_count; +} + +lldb::CompUnitSP +SymbolFilePDB::ParseCompileUnitAtIndex(uint32_t index) +{ + auto global = m_session_up->getGlobalScope(); + auto compilands = global->findAllChildren<PDBSymbolCompiland>(); + auto cu = compilands->getChildAtIndex(index); + + uint32_t id = cu->getSymIndexId(); + + return ParseCompileUnitForSymIndex(id); +} + +lldb::LanguageType +SymbolFilePDB::ParseCompileUnitLanguage(const lldb_private::SymbolContext &sc) +{ + // What fields should I expect to be filled out on the SymbolContext? Is it + // safe to assume that `sc.comp_unit` is valid? + if (!sc.comp_unit) + return lldb::eLanguageTypeUnknown; + + auto cu = m_session_up->getConcreteSymbolById<PDBSymbolCompiland>(sc.comp_unit->GetID()); + if (!cu) + return lldb::eLanguageTypeUnknown; + auto details = cu->findOneChild<PDBSymbolCompilandDetails>(); + if (!details) + return lldb::eLanguageTypeUnknown; + return TranslateLanguage(details->getLanguage()); +} + +size_t +SymbolFilePDB::ParseCompileUnitFunctions(const lldb_private::SymbolContext &sc) +{ + // TODO: Implement this + return size_t(); +} + +bool +SymbolFilePDB::ParseCompileUnitLineTable(const lldb_private::SymbolContext &sc) +{ + return ParseCompileUnitLineTable(sc, 0); +} + +bool +SymbolFilePDB::ParseCompileUnitDebugMacros(const lldb_private::SymbolContext &sc) +{ + // PDB doesn't contain information about macros + return false; +} + +bool +SymbolFilePDB::ParseCompileUnitSupportFiles(const lldb_private::SymbolContext &sc, + lldb_private::FileSpecList &support_files) +{ + if (!sc.comp_unit) + return false; + + // In theory this is unnecessary work for us, because all of this information is easily + // (and quickly) accessible from DebugInfoPDB, so caching it a second time seems like a waste. + // Unfortunately, there's no good way around this short of a moderate refactor, since SymbolVendor + // depends on being able to cache this list. + auto cu = m_session_up->getConcreteSymbolById<PDBSymbolCompiland>(sc.comp_unit->GetID()); + if (!cu) + return false; + auto files = m_session_up->getSourceFilesForCompiland(*cu); + if (!files || files->getChildCount() == 0) + return false; + + while (auto file = files->getNext()) + { + FileSpec spec(file->getFileName(), false); + support_files.Append(spec); + } + return true; +} + +bool +SymbolFilePDB::ParseImportedModules(const lldb_private::SymbolContext &sc, + std::vector<lldb_private::ConstString> &imported_modules) +{ + // PDB does not yet support module debug info + return false; +} + +size_t +SymbolFilePDB::ParseFunctionBlocks(const lldb_private::SymbolContext &sc) +{ + // TODO: Implement this + return size_t(); +} + +size_t +SymbolFilePDB::ParseTypes(const lldb_private::SymbolContext &sc) +{ + // TODO: Implement this + return size_t(); +} + +size_t +SymbolFilePDB::ParseVariablesForContext(const lldb_private::SymbolContext &sc) +{ + // TODO: Implement this + return size_t(); +} + +lldb_private::Type * +SymbolFilePDB::ResolveTypeUID(lldb::user_id_t type_uid) +{ + auto find_result = m_types.find(type_uid); + if (find_result != m_types.end()) + return find_result->second.get(); + + TypeSystem *type_system = GetTypeSystemForLanguage(lldb::eLanguageTypeC_plus_plus); + ClangASTContext *clang_type_system = llvm::dyn_cast_or_null<ClangASTContext>(type_system); + if (!clang_type_system) + return nullptr; + PDBASTParser *pdb = llvm::dyn_cast<PDBASTParser>(clang_type_system->GetPDBParser()); + if (!pdb) + return nullptr; + + auto pdb_type = m_session_up->getSymbolById(type_uid); + if (pdb_type == nullptr) + return nullptr; + + lldb::TypeSP result = pdb->CreateLLDBTypeFromPDBType(*pdb_type); + m_types.insert(std::make_pair(type_uid, result)); + return result.get(); +} + +bool +SymbolFilePDB::CompleteType(lldb_private::CompilerType &compiler_type) +{ + // TODO: Implement this + return false; +} + +lldb_private::CompilerDecl +SymbolFilePDB::GetDeclForUID(lldb::user_id_t uid) +{ + return lldb_private::CompilerDecl(); +} + +lldb_private::CompilerDeclContext +SymbolFilePDB::GetDeclContextForUID(lldb::user_id_t uid) +{ + // PDB always uses the translation unit decl context for everything. We can improve this later + // but it's not easy because PDB doesn't provide a high enough level of type fidelity in this area. + return *m_tu_decl_ctx_up; +} + +lldb_private::CompilerDeclContext +SymbolFilePDB::GetDeclContextContainingUID(lldb::user_id_t uid) +{ + return *m_tu_decl_ctx_up; +} + +void +SymbolFilePDB::ParseDeclsForContext(lldb_private::CompilerDeclContext decl_ctx) +{ +} + +uint32_t +SymbolFilePDB::ResolveSymbolContext(const lldb_private::Address &so_addr, uint32_t resolve_scope, + lldb_private::SymbolContext &sc) +{ + return uint32_t(); +} + +uint32_t +SymbolFilePDB::ResolveSymbolContext(const lldb_private::FileSpec &file_spec, uint32_t line, bool check_inlines, + uint32_t resolve_scope, lldb_private::SymbolContextList &sc_list) +{ + if (resolve_scope & lldb::eSymbolContextCompUnit) + { + // Locate all compilation units with line numbers referencing the specified file. For example, if + // `file_spec` is <vector>, then this should return all source files and header files that reference + // <vector>, either directly or indirectly. + auto compilands = + m_session_up->findCompilandsForSourceFile(file_spec.GetPath(), PDB_NameSearchFlags::NS_CaseInsensitive); + + // For each one, either find get its previously parsed data, or parse it afresh and add it to + // the symbol context list. + while (auto compiland = compilands->getNext()) + { + // If we're not checking inlines, then don't add line information for this file unless the FileSpec + // matches. + if (!check_inlines) + { + // `getSourceFileName` returns the basename of the original source file used to generate this compiland. + // It does not return the full path. Currently the only way to get that is to do a basename lookup to + // get the IPDBSourceFile, but this is ambiguous in the case of two source files with the same name + // contributing to the same compiland. This is a moderately extreme edge case, so we consider this ok + // for now, although we need to find a long term solution. + std::string source_file = compiland->getSourceFileName(); + auto pdb_file = m_session_up->findOneSourceFile(compiland.get(), source_file, + PDB_NameSearchFlags::NS_CaseInsensitive); + source_file = pdb_file->getFileName(); + FileSpec this_spec(source_file, false, FileSpec::ePathSyntaxWindows); + if (!file_spec.FileEquals(this_spec)) + continue; + } + + SymbolContext sc; + auto cu = ParseCompileUnitForSymIndex(compiland->getSymIndexId()); + sc.comp_unit = cu.get(); + sc.module_sp = cu->GetModule(); + sc_list.Append(sc); + + // If we were asked to resolve line entries, add all entries to the line table that match the requested + // line (or all lines if `line` == 0) + if (resolve_scope & lldb::eSymbolContextLineEntry) + ParseCompileUnitLineTable(sc, line); + } + } + return sc_list.GetSize(); +} + +uint32_t +SymbolFilePDB::FindGlobalVariables(const lldb_private::ConstString &name, + const lldb_private::CompilerDeclContext *parent_decl_ctx, bool append, + uint32_t max_matches, lldb_private::VariableList &variables) +{ + return uint32_t(); +} + +uint32_t +SymbolFilePDB::FindGlobalVariables(const lldb_private::RegularExpression ®ex, bool append, uint32_t max_matches, + lldb_private::VariableList &variables) +{ + return uint32_t(); +} + +uint32_t +SymbolFilePDB::FindFunctions(const lldb_private::ConstString &name, + const lldb_private::CompilerDeclContext *parent_decl_ctx, uint32_t name_type_mask, + bool include_inlines, bool append, lldb_private::SymbolContextList &sc_list) +{ + return uint32_t(); +} + +uint32_t +SymbolFilePDB::FindFunctions(const lldb_private::RegularExpression ®ex, bool include_inlines, bool append, + lldb_private::SymbolContextList &sc_list) +{ + return uint32_t(); +} + +void +SymbolFilePDB::GetMangledNamesForFunction(const std::string &scope_qualified_name, + std::vector<lldb_private::ConstString> &mangled_names) +{ +} + +uint32_t +SymbolFilePDB::FindTypes(const lldb_private::SymbolContext &sc, const lldb_private::ConstString &name, + const lldb_private::CompilerDeclContext *parent_decl_ctx, bool append, uint32_t max_matches, + llvm::DenseSet<lldb_private::SymbolFile *> &searched_symbol_files, + lldb_private::TypeMap &types) +{ + if (!append) + types.Clear(); + if (!name) + return 0; + + searched_symbol_files.clear(); + searched_symbol_files.insert(this); + + std::string name_str = name.AsCString(); + + // If this might be a regex, we have to return EVERY symbol and process them one by one, which is going + // to destroy performance on large PDB files. So try really hard not to use a regex match. + if (name_str.find_first_of("[]?*.-+\\") != std::string::npos) + FindTypesByRegex(name_str, max_matches, types); + else + FindTypesByName(name_str, max_matches, types); + return types.GetSize(); +} + +void +SymbolFilePDB::FindTypesByRegex(const std::string ®ex, uint32_t max_matches, lldb_private::TypeMap &types) +{ + // When searching by regex, we need to go out of our way to limit the search space as much as possible, since + // the way this is implemented is by searching EVERYTHING in the PDB and manually doing a regex compare. PDB + // library isn't optimized for regex searches or searches across multiple symbol types at the same time, so the + // best we can do is to search enums, then typedefs, then classes one by one, and do a regex compare against all + // of them. + PDB_SymType tags_to_search[] = {PDB_SymType::Enum, PDB_SymType::Typedef, PDB_SymType::UDT}; + auto global = m_session_up->getGlobalScope(); + std::unique_ptr<IPDBEnumSymbols> results; + + std::regex re(regex); + + uint32_t matches = 0; + + for (auto tag : tags_to_search) + { + results = global->findAllChildren(tag); + while (auto result = results->getNext()) + { + if (max_matches > 0 && matches >= max_matches) + break; + + std::string type_name; + if (auto enum_type = llvm::dyn_cast<PDBSymbolTypeEnum>(result.get())) + type_name = enum_type->getName(); + else if (auto typedef_type = llvm::dyn_cast<PDBSymbolTypeTypedef>(result.get())) + type_name = typedef_type->getName(); + else if (auto class_type = llvm::dyn_cast<PDBSymbolTypeUDT>(result.get())) + type_name = class_type->getName(); + else + { + // We're only looking for types that have names. Skip symbols, as well as + // unnamed types such as arrays, pointers, etc. + continue; + } + + if (!std::regex_match(type_name, re)) + continue; + + // This should cause the type to get cached and stored in the `m_types` lookup. + if (!ResolveTypeUID(result->getSymIndexId())) + continue; + + auto iter = m_types.find(result->getSymIndexId()); + if (iter == m_types.end()) + continue; + types.Insert(iter->second); + ++matches; + } + } +} + +void +SymbolFilePDB::FindTypesByName(const std::string &name, uint32_t max_matches, lldb_private::TypeMap &types) +{ + auto global = m_session_up->getGlobalScope(); + std::unique_ptr<IPDBEnumSymbols> results; + results = global->findChildren(PDB_SymType::None, name.c_str(), PDB_NameSearchFlags::NS_Default); + + uint32_t matches = 0; + + while (auto result = results->getNext()) + { + if (max_matches > 0 && matches >= max_matches) + break; + switch (result->getSymTag()) + { + case PDB_SymType::Enum: + case PDB_SymType::UDT: + case PDB_SymType::Typedef: + break; + default: + // We're only looking for types that have names. Skip symbols, as well as + // unnamed types such as arrays, pointers, etc. + continue; + } + + // This should cause the type to get cached and stored in the `m_types` lookup. + if (!ResolveTypeUID(result->getSymIndexId())) + continue; + + auto iter = m_types.find(result->getSymIndexId()); + if (iter == m_types.end()) + continue; + types.Insert(iter->second); + ++matches; + } +} + +size_t +SymbolFilePDB::FindTypes(const std::vector<lldb_private::CompilerContext> &contexts, bool append, + lldb_private::TypeMap &types) +{ + return 0; +} + +lldb_private::TypeList * +SymbolFilePDB::GetTypeList() +{ + return nullptr; +} + +size_t +SymbolFilePDB::GetTypes(lldb_private::SymbolContextScope *sc_scope, uint32_t type_mask, + lldb_private::TypeList &type_list) +{ + return size_t(); +} + +lldb_private::TypeSystem * +SymbolFilePDB::GetTypeSystemForLanguage(lldb::LanguageType language) +{ + auto type_system = m_obj_file->GetModule()->GetTypeSystemForLanguage(language); + if (type_system) + type_system->SetSymbolFile(this); + return type_system; +} + +lldb_private::CompilerDeclContext +SymbolFilePDB::FindNamespace(const lldb_private::SymbolContext &sc, const lldb_private::ConstString &name, + const lldb_private::CompilerDeclContext *parent_decl_ctx) +{ + return lldb_private::CompilerDeclContext(); +} + +lldb_private::ConstString +SymbolFilePDB::GetPluginName() +{ + static ConstString g_name("pdb"); + return g_name; +} + +uint32_t +SymbolFilePDB::GetPluginVersion() +{ + return 1; +} + +IPDBSession & +SymbolFilePDB::GetPDBSession() +{ + return *m_session_up; +} + +const IPDBSession & +SymbolFilePDB::GetPDBSession() const +{ + return *m_session_up; +} + +lldb::CompUnitSP +SymbolFilePDB::ParseCompileUnitForSymIndex(uint32_t id) +{ + auto found_cu = m_comp_units.find(id); + if (found_cu != m_comp_units.end()) + return found_cu->second; + + auto cu = m_session_up->getConcreteSymbolById<PDBSymbolCompiland>(id); + + // `getSourceFileName` returns the basename of the original source file used to generate this compiland. It does + // not return the full path. Currently the only way to get that is to do a basename lookup to get the + // IPDBSourceFile, but this is ambiguous in the case of two source files with the same name contributing to the + // same compiland. This is a moderately extreme edge case, so we consider this ok for now, although we need to find + // a long term solution. + auto file = + m_session_up->findOneSourceFile(cu.get(), cu->getSourceFileName(), PDB_NameSearchFlags::NS_CaseInsensitive); + std::string path = file->getFileName(); + + lldb::LanguageType lang; + auto details = cu->findOneChild<PDBSymbolCompilandDetails>(); + if (!details) + lang = lldb::eLanguageTypeC_plus_plus; + else + lang = TranslateLanguage(details->getLanguage()); + + // Don't support optimized code for now, DebugInfoPDB does not return this information. + LazyBool optimized = eLazyBoolNo; + auto result = std::make_shared<CompileUnit>(m_obj_file->GetModule(), nullptr, path.c_str(), id, lang, optimized); + m_comp_units.insert(std::make_pair(id, result)); + return result; +} + +bool +SymbolFilePDB::ParseCompileUnitLineTable(const lldb_private::SymbolContext &sc, uint32_t match_line) +{ + auto global = m_session_up->getGlobalScope(); + auto cu = m_session_up->getConcreteSymbolById<PDBSymbolCompiland>(sc.comp_unit->GetID()); + + // LineEntry needs the *index* of the file into the list of support files returned by + // ParseCompileUnitSupportFiles. But the underlying SDK gives us a globally unique + // idenfitifier in the namespace of the PDB. So, we have to do a mapping so that we + // can hand out indices. + llvm::DenseMap<uint32_t, uint32_t> index_map; + BuildSupportFileIdToSupportFileIndexMap(*cu, index_map); + auto line_table = llvm::make_unique<LineTable>(sc.comp_unit); + + // Find contributions to `cu` from all source and header files. + std::string path = sc.comp_unit->GetPath(); + auto files = m_session_up->getSourceFilesForCompiland(*cu); + + // For each source and header file, create a LineSequence for contributions to the cu + // from that file, and add the sequence. + while (auto file = files->getNext()) + { + std::unique_ptr<LineSequence> sequence(line_table->CreateLineSequenceContainer()); + auto lines = m_session_up->findLineNumbers(*cu, *file); + int entry_count = lines->getChildCount(); + + uint64_t prev_addr; + uint32_t prev_length; + uint32_t prev_line; + uint32_t prev_source_idx; + + for (int i = 0; i < entry_count; ++i) + { + auto line = lines->getChildAtIndex(i); + + uint64_t lno = line->getLineNumber(); + uint64_t addr = line->getVirtualAddress(); + uint32_t length = line->getLength(); + uint32_t source_id = line->getSourceFileId(); + uint32_t col = line->getColumnNumber(); + uint32_t source_idx = index_map[source_id]; + + // There was a gap between the current entry and the previous entry if the addresses don't perfectly line + // up. + bool is_gap = (i > 0) && (prev_addr + prev_length < addr); + + // Before inserting the current entry, insert a terminal entry at the end of the previous entry's address + // range if the current entry resulted in a gap from the previous entry. + if (is_gap && ShouldAddLine(match_line, prev_line, prev_length)) + { + line_table->AppendLineEntryToSequence(sequence.get(), prev_addr + prev_length, prev_line, 0, + prev_source_idx, false, false, false, false, true); + } + + if (ShouldAddLine(match_line, lno, length)) + { + bool is_statement = line->isStatement(); + bool is_prologue = false; + bool is_epilogue = false; + auto func = m_session_up->findSymbolByAddress(addr, PDB_SymType::Function); + if (func) + { + auto prologue = func->findOneChild<PDBSymbolFuncDebugStart>(); + is_prologue = (addr == prologue->getVirtualAddress()); + + auto epilogue = func->findOneChild<PDBSymbolFuncDebugEnd>(); + is_epilogue = (addr == epilogue->getVirtualAddress()); + } + + line_table->AppendLineEntryToSequence(sequence.get(), addr, lno, col, source_idx, is_statement, false, + is_prologue, is_epilogue, false); + } + + prev_addr = addr; + prev_length = length; + prev_line = lno; + prev_source_idx = source_idx; + } + + if (entry_count > 0 && ShouldAddLine(match_line, prev_line, prev_length)) + { + // The end is always a terminal entry, so insert it regardless. + line_table->AppendLineEntryToSequence(sequence.get(), prev_addr + prev_length, prev_line, 0, + prev_source_idx, false, false, false, false, true); + } + + line_table->InsertSequence(sequence.release()); + } + + sc.comp_unit->SetLineTable(line_table.release()); + return true; +} + +void +SymbolFilePDB::BuildSupportFileIdToSupportFileIndexMap(const PDBSymbolCompiland &cu, + llvm::DenseMap<uint32_t, uint32_t> &index_map) const +{ + // This is a hack, but we need to convert the source id into an index into the support + // files array. We don't want to do path comparisons to avoid basename / full path + // issues that may or may not even be a problem, so we use the globally unique source + // file identifiers. Ideally we could use the global identifiers everywhere, but LineEntry + // currently assumes indices. + auto source_files = m_session_up->getSourceFilesForCompiland(cu); + int index = 0; + + while (auto file = source_files->getNext()) + { + uint32_t source_id = file->getUniqueId(); + index_map[source_id] = index++; + } +} diff --git a/source/Plugins/SymbolFile/PDB/SymbolFilePDB.h b/source/Plugins/SymbolFile/PDB/SymbolFilePDB.h new file mode 100644 index 0000000000000..cf75de8ac78e3 --- /dev/null +++ b/source/Plugins/SymbolFile/PDB/SymbolFilePDB.h @@ -0,0 +1,204 @@ +//===-- SymbolFilePDB.h -------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef lldb_Plugins_SymbolFile_PDB_SymbolFilePDB_h_ +#define lldb_Plugins_SymbolFile_PDB_SymbolFilePDB_h_ + +#include "lldb/Core/UserID.h" +#include "lldb/Symbol/SymbolFile.h" + +#include "llvm/ADT/DenseMap.h" +#include "llvm/DebugInfo/PDB/IPDBSession.h" +#include "llvm/DebugInfo/PDB/PDB.h" + +class SymbolFilePDB : public lldb_private::SymbolFile +{ +public: + //------------------------------------------------------------------ + // Static Functions + //------------------------------------------------------------------ + static void + Initialize(); + + static void + Terminate(); + + static void + DebuggerInitialize(lldb_private::Debugger &debugger); + + static lldb_private::ConstString + GetPluginNameStatic(); + + static const char * + GetPluginDescriptionStatic(); + + static lldb_private::SymbolFile * + CreateInstance(lldb_private::ObjectFile *obj_file); + + //------------------------------------------------------------------ + // Constructors and Destructors + //------------------------------------------------------------------ + SymbolFilePDB(lldb_private::ObjectFile *ofile); + + ~SymbolFilePDB() override; + + uint32_t + CalculateAbilities() override; + + void + InitializeObject() override; + + //------------------------------------------------------------------ + // Compile Unit function calls + //------------------------------------------------------------------ + + uint32_t + GetNumCompileUnits() override; + + lldb::CompUnitSP + ParseCompileUnitAtIndex(uint32_t index) override; + + lldb::LanguageType + ParseCompileUnitLanguage(const lldb_private::SymbolContext &sc) override; + + size_t + ParseCompileUnitFunctions(const lldb_private::SymbolContext &sc) override; + + bool + ParseCompileUnitLineTable(const lldb_private::SymbolContext &sc) override; + + bool + ParseCompileUnitDebugMacros(const lldb_private::SymbolContext &sc) override; + + bool + ParseCompileUnitSupportFiles(const lldb_private::SymbolContext &sc, + lldb_private::FileSpecList &support_files) override; + + bool + ParseImportedModules(const lldb_private::SymbolContext &sc, + std::vector<lldb_private::ConstString> &imported_modules) override; + + size_t + ParseFunctionBlocks(const lldb_private::SymbolContext &sc) override; + + size_t + ParseTypes(const lldb_private::SymbolContext &sc) override; + + size_t + ParseVariablesForContext(const lldb_private::SymbolContext &sc) override; + + lldb_private::Type * + ResolveTypeUID(lldb::user_id_t type_uid) override; + + bool + CompleteType(lldb_private::CompilerType &compiler_type) override; + + lldb_private::CompilerDecl + GetDeclForUID(lldb::user_id_t uid) override; + + lldb_private::CompilerDeclContext + GetDeclContextForUID(lldb::user_id_t uid) override; + + lldb_private::CompilerDeclContext + GetDeclContextContainingUID(lldb::user_id_t uid) override; + + void + ParseDeclsForContext(lldb_private::CompilerDeclContext decl_ctx) override; + + uint32_t + ResolveSymbolContext(const lldb_private::Address &so_addr, uint32_t resolve_scope, + lldb_private::SymbolContext &sc) override; + + uint32_t + ResolveSymbolContext(const lldb_private::FileSpec &file_spec, uint32_t line, bool check_inlines, + uint32_t resolve_scope, lldb_private::SymbolContextList &sc_list) override; + + uint32_t + FindGlobalVariables(const lldb_private::ConstString &name, const lldb_private::CompilerDeclContext *parent_decl_ctx, + bool append, uint32_t max_matches, lldb_private::VariableList &variables) override; + + uint32_t + FindGlobalVariables(const lldb_private::RegularExpression ®ex, bool append, uint32_t max_matches, + lldb_private::VariableList &variables) override; + + uint32_t + FindFunctions(const lldb_private::ConstString &name, const lldb_private::CompilerDeclContext *parent_decl_ctx, + uint32_t name_type_mask, bool include_inlines, bool append, + lldb_private::SymbolContextList &sc_list) override; + + uint32_t + FindFunctions(const lldb_private::RegularExpression ®ex, bool include_inlines, bool append, + lldb_private::SymbolContextList &sc_list) override; + + void + GetMangledNamesForFunction(const std::string &scope_qualified_name, + std::vector<lldb_private::ConstString> &mangled_names) override; + + uint32_t + FindTypes(const lldb_private::SymbolContext &sc, const lldb_private::ConstString &name, + const lldb_private::CompilerDeclContext *parent_decl_ctx, bool append, uint32_t max_matches, + llvm::DenseSet<lldb_private::SymbolFile *> &searched_symbol_files, lldb_private::TypeMap &types) override; + + size_t + FindTypes(const std::vector<lldb_private::CompilerContext> &context, bool append, + lldb_private::TypeMap &types) override; + + lldb_private::TypeList * + GetTypeList() override; + + size_t + GetTypes(lldb_private::SymbolContextScope *sc_scope, uint32_t type_mask, + lldb_private::TypeList &type_list) override; + + lldb_private::TypeSystem * + GetTypeSystemForLanguage(lldb::LanguageType language) override; + + lldb_private::CompilerDeclContext + FindNamespace(const lldb_private::SymbolContext &sc, const lldb_private::ConstString &name, + const lldb_private::CompilerDeclContext *parent_decl_ctx) override; + + lldb_private::ConstString + GetPluginName() override; + + uint32_t + GetPluginVersion() override; + + llvm::pdb::IPDBSession & + GetPDBSession(); + + const llvm::pdb::IPDBSession & + GetPDBSession() const; + +private: + lldb::CompUnitSP + ParseCompileUnitForSymIndex(uint32_t id); + + bool + ParseCompileUnitLineTable(const lldb_private::SymbolContext &sc, uint32_t match_line); + + void + BuildSupportFileIdToSupportFileIndexMap(const llvm::pdb::PDBSymbolCompiland &cu, + llvm::DenseMap<uint32_t, uint32_t> &index_map) const; + + void + FindTypesByRegex(const std::string ®ex, uint32_t max_matches, lldb_private::TypeMap &types); + + void + FindTypesByName(const std::string &name, uint32_t max_matches, lldb_private::TypeMap &types); + + llvm::DenseMap<uint32_t, lldb::CompUnitSP> m_comp_units; + llvm::DenseMap<uint32_t, lldb::TypeSP> m_types; + + std::vector<lldb::TypeSP> m_builtin_types; + std::unique_ptr<llvm::pdb::IPDBSession> m_session_up; + uint32_t m_cached_compile_unit_count; + std::unique_ptr<lldb_private::CompilerDeclContext> m_tu_decl_ctx_up; +}; + +#endif // lldb_Plugins_SymbolFile_PDB_SymbolFilePDB_h_ diff --git a/source/Plugins/SymbolFile/Symtab/Makefile b/source/Plugins/SymbolFile/Symtab/Makefile deleted file mode 100644 index 2c3dbb6d86ab7..0000000000000 --- a/source/Plugins/SymbolFile/Symtab/Makefile +++ /dev/null @@ -1,14 +0,0 @@ -##===- source/Plugins/SymbolFile/Symtab/Makefile -----------*- Makefile -*-===## -# -# The LLVM Compiler Infrastructure -# -# This file is distributed under the University of Illinois Open Source -# License. See LICENSE.TXT for details. -# -##===----------------------------------------------------------------------===## - -LLDB_LEVEL := ../../../.. -LIBRARYNAME := lldbPluginSymbolFileSymtab -BUILD_ARCHIVE = 1 - -include $(LLDB_LEVEL)/Makefile diff --git a/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.cpp b/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.cpp index d3dd1ae923e02..24175079c95f2 100644 --- a/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.cpp +++ b/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.cpp @@ -153,7 +153,8 @@ SymbolFileSymtab::ParseCompileUnitAtIndex(uint32_t idx) { const Symbol *cu_symbol = m_obj_file->GetSymtab()->SymbolAtIndex(m_source_indexes[idx]); if (cu_symbol) - cu_sp.reset(new CompileUnit (m_obj_file->GetModule(), NULL, cu_symbol->GetName().AsCString(), 0, eLanguageTypeUnknown, false)); + cu_sp.reset(new CompileUnit(m_obj_file->GetModule(), NULL, cu_symbol->GetName().AsCString(), 0, + eLanguageTypeUnknown, eLazyBoolNo)); } return cu_sp; } |