diff --git a/lldb/source/Plugins/SymbolFile/DWARF/AppleDWARFIndex.h b/lldb/source/Plugins/SymbolFile/DWARF/AppleDWARFIndex.h --- a/lldb/source/Plugins/SymbolFile/DWARF/AppleDWARFIndex.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/AppleDWARFIndex.h @@ -24,7 +24,7 @@ AppleDWARFIndex(Module &module, std::unique_ptr apple_names, std::unique_ptr apple_namespaces, - std::unique_ptr apple_types, + std::unique_ptr apple_types, std::unique_ptr apple_objc) : DWARFIndex(module), m_apple_names_up(std::move(apple_names)), m_apple_namespaces_up(std::move(apple_namespaces)), @@ -65,7 +65,7 @@ private: std::unique_ptr m_apple_names_up; std::unique_ptr m_apple_namespaces_up; - std::unique_ptr m_apple_types_up; + std::unique_ptr m_apple_types_up; std::unique_ptr m_apple_objc_up; /// Search for entries whose name is `name` in `table`, calling `callback` for diff --git a/lldb/source/Plugins/SymbolFile/DWARF/AppleDWARFIndex.cpp b/lldb/source/Plugins/SymbolFile/DWARF/AppleDWARFIndex.cpp --- a/lldb/source/Plugins/SymbolFile/DWARF/AppleDWARFIndex.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/AppleDWARFIndex.cpp @@ -32,10 +32,8 @@ std::make_unique( apple_namespaces.GetAsLLVMDWARF(), llvm_debug_str); - auto apple_types_table_up = std::make_unique( - apple_types, debug_str, ".apple_types"); - if (!apple_types_table_up->IsValid()) - apple_types_table_up.reset(); + auto apple_types_table_up = std::make_unique( + apple_types.GetAsLLVMDWARF(), llvm_debug_str); auto apple_objc_table_up = std::make_unique( apple_objc, debug_str, ".apple_objc"); @@ -51,6 +49,7 @@ extract_and_check(apple_names_table_up); extract_and_check(apple_namespaces_table_up); + extract_and_check(apple_types_table_up); if (apple_names_table_up || apple_namespaces_table_up || apple_types_table_up || apple_objc_table_up) @@ -62,16 +61,69 @@ return nullptr; } +/// Returns true if `tag` is a class_type of structure_type tag. +static bool IsClassOrStruct(dw_tag_t tag) { + return tag == DW_TAG_class_type || tag == DW_TAG_structure_type; +} + +/// Returns true if `entry` has an extractable DW_ATOM_qual_name_hash and it +/// matches `expected_hash`. +static bool +EntryHasMatchingQualhash(const llvm::AppleAcceleratorTable::Entry &entry, + uint32_t expected_hash) { + std::optional form_value = + entry.lookup(dwarf::DW_ATOM_qual_name_hash); + if (!form_value) + return false; + std::optional hash = form_value->getAsUnsignedConstant(); + return hash && (*hash == expected_hash); +} + +/// Returns true if `entry` has an extractable DW_ATOM_die_tag and it matches +/// `expected_tag`. We also consider it a match if the tags are different but +/// in the set of {TAG_class_type, TAG_struct_type}. +static bool EntryHasMatchingTag(const llvm::AppleAcceleratorTable::Entry &entry, + dw_tag_t expected_tag) { + std::optional form_value = + entry.lookup(dwarf::DW_ATOM_die_tag); + if (!form_value) + return false; + std::optional maybe_tag = form_value->getAsUnsignedConstant(); + if (!maybe_tag) + return false; + auto tag = static_cast(*maybe_tag); + return tag == expected_tag || + (IsClassOrStruct(tag) && IsClassOrStruct(expected_tag)); +} + +/// Returns true if `entry` has an extractable DW_ATOM_type_flags and the flag +/// "DW_FLAG_type_implementation" is set. +static bool +HasImplementationFlag(const llvm::AppleAcceleratorTable::Entry &entry) { + std::optional form_value = + entry.lookup(dwarf::DW_ATOM_type_flags); + if (!form_value) + return false; + std::optional Flags = form_value->getAsUnsignedConstant(); + return Flags && + (*Flags & llvm::dwarf::AcceleratorTable::DW_FLAG_type_implementation); +} + void AppleDWARFIndex::SearchFor(const llvm::AppleAcceleratorTable &table, llvm::StringRef name, llvm::function_ref callback, std::optional search_for_tag, std::optional search_for_qualhash) { - assert(!search_for_tag && !search_for_qualhash && "not yet implemented"); auto converted_cb = DIERefCallback(callback, name); - for (const auto &entry : table.equal_range(name)) + for (const auto &entry : table.equal_range(name)) { + if (search_for_qualhash && + !EntryHasMatchingQualhash(entry, *search_for_qualhash)) + continue; + if (search_for_tag && !EntryHasMatchingTag(entry, *search_for_tag)) + continue; if (!converted_cb(entry)) break; + } } void AppleDWARFIndex::GetGlobalVariables( @@ -130,18 +182,32 @@ llvm::function_ref callback) { if (!m_apple_types_up) return; - m_apple_types_up->FindCompleteObjCClassByName( - class_name.GetStringRef(), - DIERefCallback(callback, class_name.GetStringRef()), - must_be_implementation); + + llvm::SmallVector decl_dies; + auto converted_cb = DIERefCallback(callback, class_name); + + for (const auto &entry : m_apple_types_up->equal_range(class_name)) { + if (HasImplementationFlag(entry)) { + converted_cb(entry); + return; + } + + decl_dies.emplace_back(std::nullopt, DIERef::Section::DebugInfo, + *entry.getDIESectionOffset()); + } + + if (must_be_implementation) + return; + for (DIERef ref : decl_dies) + if (!converted_cb(ref)) + return; } void AppleDWARFIndex::GetTypes( ConstString name, llvm::function_ref callback) { if (!m_apple_types_up) return; - m_apple_types_up->FindByName(name.GetStringRef(), - DIERefCallback(callback, name.GetStringRef())); + SearchFor(*m_apple_types_up, name, callback); } void AppleDWARFIndex::GetTypes( @@ -151,51 +217,47 @@ return; Log *log = GetLog(DWARFLog::TypeCompletion | DWARFLog::Lookups); - const bool has_tag = m_apple_types_up->GetHeader().header_data.ContainsAtom( - DWARFMappedHash::eAtomTypeTag); - const bool has_qualified_name_hash = - m_apple_types_up->GetHeader().header_data.ContainsAtom( - DWARFMappedHash::eAtomTypeQualNameHash); - - const ConstString type_name(context[0].name); - const dw_tag_t tag = context[0].tag; - if (has_tag && has_qualified_name_hash) { - const char *qualified_name = context.GetQualifiedName(); - const uint32_t qualified_name_hash = llvm::djbHash(qualified_name); + const bool entries_have_tag = + m_apple_types_up->containsAtomType(DW_ATOM_die_tag); + const bool entries_have_qual_hash = + m_apple_types_up->containsAtomType(DW_ATOM_qual_name_hash); + + llvm::StringRef expected_name = context[0].name; + + if (entries_have_tag && entries_have_qual_hash) { + const dw_tag_t expected_tag = context[0].tag; + const uint32_t expected_qualname_hash = + llvm::djbHash(context.GetQualifiedName()); if (log) m_module.LogMessage(log, "FindByNameAndTagAndQualifiedNameHash()"); - m_apple_types_up->FindByNameAndTagAndQualifiedNameHash( - type_name.GetStringRef(), tag, qualified_name_hash, - DIERefCallback(callback, type_name.GetStringRef())); + SearchFor(*m_apple_types_up, expected_name, callback, expected_tag, + expected_qualname_hash); return; } - if (has_tag) { - // When searching for a scoped type (for example, - // "std::vector::const_iterator") searching for the innermost - // name alone ("const_iterator") could yield many false - // positives. By searching for the parent type ("vector") - // first we can avoid extracting type DIEs from object files that - // would fail the filter anyway. - if (!has_qualified_name_hash && (context.GetSize() > 1) && - (context[1].tag == DW_TAG_class_type || - context[1].tag == DW_TAG_structure_type)) { - if (m_apple_types_up->FindByName(context[1].name, - [&](DIERef ref) { return false; })) - return; - } - - if (log) - m_module.LogMessage(log, "FindByNameAndTag()"); - m_apple_types_up->FindByNameAndTag( - type_name.GetStringRef(), tag, - DIERefCallback(callback, type_name.GetStringRef())); + // Historically, if there are no tags, we also ignore qual_hash (why?) + if (!entries_have_tag) { + SearchFor(*m_apple_names_up, expected_name, callback); return; } - m_apple_types_up->FindByName( - type_name.GetStringRef(), - DIERefCallback(callback, type_name.GetStringRef())); + // We have a tag but no qual hash. + + // When searching for a scoped type (for example, + // "std::vector::const_iterator") searching for the innermost + // name alone ("const_iterator") could yield many false + // positives. By searching for the parent type ("vector") + // first we can avoid extracting type DIEs from object files that + // would fail the filter anyway. + if ((context.GetSize() > 1) && IsClassOrStruct(context[1].tag)) + if (m_apple_types_up->equal_range(context[1].name).empty()) + return; + + if (log) + m_module.LogMessage(log, "FindByNameAndTag()"); + const dw_tag_t expected_tag = context[0].tag; + SearchFor(*m_apple_types_up, expected_name, callback, expected_tag); + return; } void AppleDWARFIndex::GetNamespaces( diff --git a/lldb/source/Plugins/SymbolFile/DWARF/HashedNameToDIE.h b/lldb/source/Plugins/SymbolFile/DWARF/HashedNameToDIE.h --- a/lldb/source/Plugins/SymbolFile/DWARF/HashedNameToDIE.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/HashedNameToDIE.h @@ -135,19 +135,6 @@ bool FindByName(llvm::StringRef name, llvm::function_ref callback); - void FindByNameAndTag(llvm::StringRef name, const dw_tag_t tag, - llvm::function_ref callback); - - void FindByNameAndTagAndQualifiedNameHash( - llvm::StringRef name, const dw_tag_t tag, - const uint32_t qualified_name_hash, - llvm::function_ref callback); - - void - FindCompleteObjCClassByName(llvm::StringRef name, - llvm::function_ref callback, - bool must_be_implementation); - protected: void FindByName(llvm::StringRef name, DIEInfoArray &die_info_array); @@ -164,25 +151,6 @@ llvm::function_ref callback); protected: - static void ExtractDIEArray(const DIEInfoArray &die_info_array, - const dw_tag_t tag, - llvm::function_ref callback); - - static void ExtractDIEArray(const DIEInfoArray &die_info_array, - const dw_tag_t tag, - const uint32_t qualified_name_hash, - llvm::function_ref callback); - - static void - ExtractClassOrStructDIEArray(const DIEInfoArray &die_info_array, - bool return_implementation_only_if_available, - llvm::function_ref callback); - - static void - ExtractTypesFromDIEArray(const DIEInfoArray &die_info_array, - uint32_t type_flag_mask, uint32_t type_flag_value, - llvm::function_ref callback); - static const char *GetAtomTypeName(uint16_t atom); }; diff --git a/lldb/source/Plugins/SymbolFile/DWARF/HashedNameToDIE.cpp b/lldb/source/Plugins/SymbolFile/DWARF/HashedNameToDIE.cpp --- a/lldb/source/Plugins/SymbolFile/DWARF/HashedNameToDIE.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/HashedNameToDIE.cpp @@ -23,92 +23,6 @@ return true; } -void DWARFMappedHash::ExtractDIEArray( - const DIEInfoArray &die_info_array, const dw_tag_t tag, - llvm::function_ref callback) { - if (tag == 0) { - ExtractDIEArray(die_info_array, callback); - return; - } - - const size_t count = die_info_array.size(); - for (size_t i = 0; i < count; ++i) { - const dw_tag_t die_tag = die_info_array[i].tag; - bool tag_matches = die_tag == 0 || tag == die_tag; - if (!tag_matches) { - if (die_tag == DW_TAG_class_type || die_tag == DW_TAG_structure_type) - tag_matches = tag == DW_TAG_structure_type || tag == DW_TAG_class_type; - } - if (tag_matches) { - if (!callback(DIERef(die_info_array[i]))) - return; - } - } -} - -void DWARFMappedHash::ExtractDIEArray( - const DIEInfoArray &die_info_array, const dw_tag_t tag, - const uint32_t qualified_name_hash, - llvm::function_ref callback) { - if (tag == 0) { - ExtractDIEArray(die_info_array, callback); - return; - } - - const size_t count = die_info_array.size(); - for (size_t i = 0; i < count; ++i) { - if (qualified_name_hash != die_info_array[i].qualified_name_hash) - continue; - const dw_tag_t die_tag = die_info_array[i].tag; - bool tag_matches = die_tag == 0 || tag == die_tag; - if (!tag_matches) { - if (die_tag == DW_TAG_class_type || die_tag == DW_TAG_structure_type) - tag_matches = tag == DW_TAG_structure_type || tag == DW_TAG_class_type; - } - if (tag_matches) { - if (!callback(DIERef(die_info_array[i]))) - return; - } - } -} - -void DWARFMappedHash::ExtractClassOrStructDIEArray( - const DIEInfoArray &die_info_array, - bool return_implementation_only_if_available, - llvm::function_ref callback) { - const size_t count = die_info_array.size(); - for (size_t i = 0; i < count; ++i) { - const dw_tag_t die_tag = die_info_array[i].tag; - if (!(die_tag == 0 || die_tag == DW_TAG_class_type || - die_tag == DW_TAG_structure_type)) - continue; - bool is_implementation = - (die_info_array[i].type_flags & eTypeFlagClassIsImplementation) != 0; - if (is_implementation != return_implementation_only_if_available) - continue; - if (return_implementation_only_if_available) { - // We found the one true definition for this class, so only return - // that - callback(DIERef(die_info_array[i])); - return; - } - if (!callback(DIERef(die_info_array[i]))) - return; - } -} - -void DWARFMappedHash::ExtractTypesFromDIEArray( - const DIEInfoArray &die_info_array, uint32_t type_flag_mask, - uint32_t type_flag_value, llvm::function_ref callback) { - const size_t count = die_info_array.size(); - for (size_t i = 0; i < count; ++i) { - if ((die_info_array[i].type_flags & type_flag_mask) == type_flag_value) { - if (!callback(DIERef(die_info_array[i]))) - return; - } - } -} - const char *DWARFMappedHash::GetAtomTypeName(uint16_t atom) { switch (atom) { case eAtomTypeNULL: @@ -414,56 +328,6 @@ return DWARFMappedHash::ExtractDIEArray(die_info_array, callback); } -void DWARFMappedHash::MemoryTable::FindByNameAndTag( - llvm::StringRef name, const dw_tag_t tag, - llvm::function_ref callback) { - DIEInfoArray die_info_array; - FindByName(name, die_info_array); - DWARFMappedHash::ExtractDIEArray(die_info_array, tag, callback); -} - -void DWARFMappedHash::MemoryTable::FindByNameAndTagAndQualifiedNameHash( - llvm::StringRef name, const dw_tag_t tag, - const uint32_t qualified_name_hash, - llvm::function_ref callback) { - DIEInfoArray die_info_array; - FindByName(name, die_info_array); - DWARFMappedHash::ExtractDIEArray(die_info_array, tag, qualified_name_hash, - callback); -} - -void DWARFMappedHash::MemoryTable::FindCompleteObjCClassByName( - llvm::StringRef name, llvm::function_ref callback, - bool must_be_implementation) { - DIEInfoArray die_info_array; - FindByName(name, die_info_array); - if (must_be_implementation && - GetHeader().header_data.ContainsAtom(eAtomTypeTypeFlags)) { - // If we have two atoms, then we have the DIE offset and the type flags - // so we can find the objective C class efficiently. - DWARFMappedHash::ExtractTypesFromDIEArray( - die_info_array, UINT32_MAX, eTypeFlagClassIsImplementation, callback); - return; - } - // We don't only want the one true definition, so try and see what we can - // find, and only return class or struct DIEs. If we do have the full - // implementation, then return it alone, else return all possible - // matches. - bool found_implementation = false; - DWARFMappedHash::ExtractClassOrStructDIEArray( - die_info_array, true /*return_implementation_only_if_available*/, - [&](DIERef ref) { - found_implementation = true; - // Here the return value does not matter as we are called at most once. - return callback(ref); - }); - if (found_implementation) - return; - DWARFMappedHash::ExtractClassOrStructDIEArray( - die_info_array, false /*return_implementation_only_if_available*/, - callback); -} - void DWARFMappedHash::MemoryTable::FindByName(llvm::StringRef name, DIEInfoArray &die_info_array) { if (name.empty()) diff --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h b/llvm/include/llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h --- a/llvm/include/llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h +++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h @@ -314,6 +314,13 @@ /// Return the Atom description, which can be used to interpret the raw values /// of the Accelerator Entries in this table. ArrayRef> getAtomsDesc(); + + /// Returns true iff `AtomTy` is one of the atoms available in Entries of this + /// table. + bool containsAtomType(HeaderData::AtomType AtomTy) const { + return is_contained(make_first_range(HdrData.Atoms), AtomTy); + } + bool validateForms(); /// Return information related to the DWARF DIE we're looking for when