15ffd83dbSDimitry Andric //===-- AppleDWARFIndex.cpp -----------------------------------------------===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric 90b57cec5SDimitry Andric #include "Plugins/SymbolFile/DWARF/AppleDWARFIndex.h" 100b57cec5SDimitry Andric #include "Plugins/SymbolFile/DWARF/DWARFDeclContext.h" 110b57cec5SDimitry Andric #include "Plugins/SymbolFile/DWARF/DWARFUnit.h" 120b57cec5SDimitry Andric #include "Plugins/SymbolFile/DWARF/LogChannelDWARF.h" 130b57cec5SDimitry Andric 140b57cec5SDimitry Andric #include "lldb/Core/Module.h" 150b57cec5SDimitry Andric #include "lldb/Symbol/Function.h" 1606c3fb27SDimitry Andric #include "llvm/Support/DJB.h" 170b57cec5SDimitry Andric 180b57cec5SDimitry Andric using namespace lldb_private; 190b57cec5SDimitry Andric using namespace lldb; 2081ad6265SDimitry Andric using namespace lldb_private::dwarf; 215f757f3fSDimitry Andric using namespace lldb_private::plugin::dwarf; 220b57cec5SDimitry Andric 230b57cec5SDimitry Andric std::unique_ptr<AppleDWARFIndex> AppleDWARFIndex::Create( 240b57cec5SDimitry Andric Module &module, DWARFDataExtractor apple_names, 250b57cec5SDimitry Andric DWARFDataExtractor apple_namespaces, DWARFDataExtractor apple_types, 260b57cec5SDimitry Andric DWARFDataExtractor apple_objc, DWARFDataExtractor debug_str) { 2706c3fb27SDimitry Andric 2806c3fb27SDimitry Andric llvm::DataExtractor llvm_debug_str = debug_str.GetAsLLVM(); 2906c3fb27SDimitry Andric 3006c3fb27SDimitry Andric auto apple_names_table_up = std::make_unique<llvm::AppleAcceleratorTable>( 3106c3fb27SDimitry Andric apple_names.GetAsLLVMDWARF(), llvm_debug_str); 320b57cec5SDimitry Andric 330b57cec5SDimitry Andric auto apple_namespaces_table_up = 3406c3fb27SDimitry Andric std::make_unique<llvm::AppleAcceleratorTable>( 3506c3fb27SDimitry Andric apple_namespaces.GetAsLLVMDWARF(), llvm_debug_str); 360b57cec5SDimitry Andric 3706c3fb27SDimitry Andric auto apple_types_table_up = std::make_unique<llvm::AppleAcceleratorTable>( 3806c3fb27SDimitry Andric apple_types.GetAsLLVMDWARF(), llvm_debug_str); 390b57cec5SDimitry Andric 4006c3fb27SDimitry Andric auto apple_objc_table_up = std::make_unique<llvm::AppleAcceleratorTable>( 4106c3fb27SDimitry Andric apple_objc.GetAsLLVMDWARF(), llvm_debug_str); 4206c3fb27SDimitry Andric 4306c3fb27SDimitry Andric auto extract_and_check = [](auto &TablePtr) { 4406c3fb27SDimitry Andric if (auto E = TablePtr->extract()) { 4506c3fb27SDimitry Andric llvm::consumeError(std::move(E)); 4606c3fb27SDimitry Andric TablePtr.reset(); 4706c3fb27SDimitry Andric } 4806c3fb27SDimitry Andric }; 4906c3fb27SDimitry Andric 5006c3fb27SDimitry Andric extract_and_check(apple_names_table_up); 5106c3fb27SDimitry Andric extract_and_check(apple_namespaces_table_up); 5206c3fb27SDimitry Andric extract_and_check(apple_types_table_up); 5306c3fb27SDimitry Andric extract_and_check(apple_objc_table_up); 545f757f3fSDimitry Andric assert(apple_names.GetByteSize() == 0 || apple_names.GetSharedDataBuffer()); 555f757f3fSDimitry Andric assert(apple_namespaces.GetByteSize() == 0 || 565f757f3fSDimitry Andric apple_namespaces.GetSharedDataBuffer()); 575f757f3fSDimitry Andric assert(apple_types.GetByteSize() == 0 || apple_types.GetSharedDataBuffer()); 585f757f3fSDimitry Andric assert(apple_objc.GetByteSize() == 0 || apple_objc.GetSharedDataBuffer()); 590b57cec5SDimitry Andric 60e8d8bef9SDimitry Andric if (apple_names_table_up || apple_namespaces_table_up || 61e8d8bef9SDimitry Andric apple_types_table_up || apple_objc_table_up) 629dba64beSDimitry Andric return std::make_unique<AppleDWARFIndex>( 630b57cec5SDimitry Andric module, std::move(apple_names_table_up), 640b57cec5SDimitry Andric std::move(apple_namespaces_table_up), std::move(apple_types_table_up), 655f757f3fSDimitry Andric std::move(apple_objc_table_up), apple_names.GetSharedDataBuffer(), 665f757f3fSDimitry Andric apple_namespaces.GetSharedDataBuffer(), 675f757f3fSDimitry Andric apple_types.GetSharedDataBuffer(), apple_objc.GetSharedDataBuffer()); 680b57cec5SDimitry Andric 690b57cec5SDimitry Andric return nullptr; 700b57cec5SDimitry Andric } 710b57cec5SDimitry Andric 7206c3fb27SDimitry Andric /// Returns true if `tag` is a class_type of structure_type tag. 7306c3fb27SDimitry Andric static bool IsClassOrStruct(dw_tag_t tag) { 7406c3fb27SDimitry Andric return tag == DW_TAG_class_type || tag == DW_TAG_structure_type; 7506c3fb27SDimitry Andric } 7606c3fb27SDimitry Andric 7706c3fb27SDimitry Andric /// Returns true if `entry` has an extractable DW_ATOM_qual_name_hash and it 7806c3fb27SDimitry Andric /// matches `expected_hash`. 7906c3fb27SDimitry Andric static bool 8006c3fb27SDimitry Andric EntryHasMatchingQualhash(const llvm::AppleAcceleratorTable::Entry &entry, 8106c3fb27SDimitry Andric uint32_t expected_hash) { 8206c3fb27SDimitry Andric std::optional<llvm::DWARFFormValue> form_value = 8306c3fb27SDimitry Andric entry.lookup(dwarf::DW_ATOM_qual_name_hash); 8406c3fb27SDimitry Andric if (!form_value) 8506c3fb27SDimitry Andric return false; 8606c3fb27SDimitry Andric std::optional<uint64_t> hash = form_value->getAsUnsignedConstant(); 8706c3fb27SDimitry Andric return hash && (*hash == expected_hash); 8806c3fb27SDimitry Andric } 8906c3fb27SDimitry Andric 9006c3fb27SDimitry Andric /// Returns true if `entry` has an extractable DW_ATOM_die_tag and it matches 9106c3fb27SDimitry Andric /// `expected_tag`. We also consider it a match if the tags are different but 9206c3fb27SDimitry Andric /// in the set of {TAG_class_type, TAG_struct_type}. 9306c3fb27SDimitry Andric static bool EntryHasMatchingTag(const llvm::AppleAcceleratorTable::Entry &entry, 9406c3fb27SDimitry Andric dw_tag_t expected_tag) { 9506c3fb27SDimitry Andric std::optional<llvm::DWARFFormValue> form_value = 9606c3fb27SDimitry Andric entry.lookup(dwarf::DW_ATOM_die_tag); 9706c3fb27SDimitry Andric if (!form_value) 9806c3fb27SDimitry Andric return false; 9906c3fb27SDimitry Andric std::optional<uint64_t> maybe_tag = form_value->getAsUnsignedConstant(); 10006c3fb27SDimitry Andric if (!maybe_tag) 10106c3fb27SDimitry Andric return false; 10206c3fb27SDimitry Andric auto tag = static_cast<dw_tag_t>(*maybe_tag); 10306c3fb27SDimitry Andric return tag == expected_tag || 10406c3fb27SDimitry Andric (IsClassOrStruct(tag) && IsClassOrStruct(expected_tag)); 10506c3fb27SDimitry Andric } 10606c3fb27SDimitry Andric 10706c3fb27SDimitry Andric /// Returns true if `entry` has an extractable DW_ATOM_type_flags and the flag 10806c3fb27SDimitry Andric /// "DW_FLAG_type_implementation" is set. 10906c3fb27SDimitry Andric static bool 11006c3fb27SDimitry Andric HasImplementationFlag(const llvm::AppleAcceleratorTable::Entry &entry) { 11106c3fb27SDimitry Andric std::optional<llvm::DWARFFormValue> form_value = 11206c3fb27SDimitry Andric entry.lookup(dwarf::DW_ATOM_type_flags); 11306c3fb27SDimitry Andric if (!form_value) 11406c3fb27SDimitry Andric return false; 11506c3fb27SDimitry Andric std::optional<uint64_t> Flags = form_value->getAsUnsignedConstant(); 11606c3fb27SDimitry Andric return Flags && 11706c3fb27SDimitry Andric (*Flags & llvm::dwarf::AcceleratorTable::DW_FLAG_type_implementation); 11806c3fb27SDimitry Andric } 11906c3fb27SDimitry Andric 12006c3fb27SDimitry Andric void AppleDWARFIndex::SearchFor(const llvm::AppleAcceleratorTable &table, 12106c3fb27SDimitry Andric llvm::StringRef name, 12206c3fb27SDimitry Andric llvm::function_ref<bool(DWARFDIE die)> callback, 12306c3fb27SDimitry Andric std::optional<dw_tag_t> search_for_tag, 12406c3fb27SDimitry Andric std::optional<uint32_t> search_for_qualhash) { 12506c3fb27SDimitry Andric auto converted_cb = DIERefCallback(callback, name); 12606c3fb27SDimitry Andric for (const auto &entry : table.equal_range(name)) { 12706c3fb27SDimitry Andric if (search_for_qualhash && 12806c3fb27SDimitry Andric !EntryHasMatchingQualhash(entry, *search_for_qualhash)) 12906c3fb27SDimitry Andric continue; 13006c3fb27SDimitry Andric if (search_for_tag && !EntryHasMatchingTag(entry, *search_for_tag)) 13106c3fb27SDimitry Andric continue; 13206c3fb27SDimitry Andric if (!converted_cb(entry)) 13306c3fb27SDimitry Andric break; 13406c3fb27SDimitry Andric } 13506c3fb27SDimitry Andric } 13606c3fb27SDimitry Andric 1375ffd83dbSDimitry Andric void AppleDWARFIndex::GetGlobalVariables( 1385ffd83dbSDimitry Andric ConstString basename, llvm::function_ref<bool(DWARFDIE die)> callback) { 1395ffd83dbSDimitry Andric if (!m_apple_names_up) 1405ffd83dbSDimitry Andric return; 14106c3fb27SDimitry Andric SearchFor(*m_apple_names_up, basename, callback); 1420b57cec5SDimitry Andric } 1430b57cec5SDimitry Andric 1445ffd83dbSDimitry Andric void AppleDWARFIndex::GetGlobalVariables( 1455ffd83dbSDimitry Andric const RegularExpression ®ex, 1465ffd83dbSDimitry Andric llvm::function_ref<bool(DWARFDIE die)> callback) { 1470b57cec5SDimitry Andric if (!m_apple_names_up) 1480b57cec5SDimitry Andric return; 1490b57cec5SDimitry Andric 15006c3fb27SDimitry Andric DIERefCallbackImpl converted_cb = DIERefCallback(callback, regex.GetText()); 15106c3fb27SDimitry Andric 15206c3fb27SDimitry Andric for (const auto &entry : m_apple_names_up->entries()) 15306c3fb27SDimitry Andric if (std::optional<llvm::StringRef> name = entry.readName(); 15406c3fb27SDimitry Andric name && Mangled(*name).NameMatches(regex)) 15506c3fb27SDimitry Andric if (!converted_cb(entry.BaseEntry)) 15606c3fb27SDimitry Andric return; 1570b57cec5SDimitry Andric } 1580b57cec5SDimitry Andric 1595ffd83dbSDimitry Andric void AppleDWARFIndex::GetGlobalVariables( 160349cc55cSDimitry Andric DWARFUnit &cu, llvm::function_ref<bool(DWARFDIE die)> callback) { 1610b57cec5SDimitry Andric if (!m_apple_names_up) 1620b57cec5SDimitry Andric return; 1630b57cec5SDimitry Andric 164349cc55cSDimitry Andric const DWARFUnit &non_skeleton_cu = cu.GetNonSkeletonUnit(); 16506c3fb27SDimitry Andric dw_offset_t lower_bound = non_skeleton_cu.GetOffset(); 16606c3fb27SDimitry Andric dw_offset_t upper_bound = non_skeleton_cu.GetNextUnitOffset(); 16706c3fb27SDimitry Andric auto is_in_range = [lower_bound, upper_bound](std::optional<uint32_t> val) { 16806c3fb27SDimitry Andric return val.has_value() && *val >= lower_bound && *val < upper_bound; 16906c3fb27SDimitry Andric }; 17006c3fb27SDimitry Andric 17106c3fb27SDimitry Andric DIERefCallbackImpl converted_cb = DIERefCallback(callback); 17206c3fb27SDimitry Andric for (auto entry : m_apple_names_up->entries()) { 17306c3fb27SDimitry Andric if (is_in_range(entry.BaseEntry.getDIESectionOffset())) 17406c3fb27SDimitry Andric if (!converted_cb(entry.BaseEntry)) 17506c3fb27SDimitry Andric return; 17606c3fb27SDimitry Andric } 1770b57cec5SDimitry Andric } 1780b57cec5SDimitry Andric 1795ffd83dbSDimitry Andric void AppleDWARFIndex::GetObjCMethods( 1805ffd83dbSDimitry Andric ConstString class_name, llvm::function_ref<bool(DWARFDIE die)> callback) { 1815ffd83dbSDimitry Andric if (!m_apple_objc_up) 1825ffd83dbSDimitry Andric return; 18306c3fb27SDimitry Andric SearchFor(*m_apple_objc_up, class_name, callback); 1840b57cec5SDimitry Andric } 1850b57cec5SDimitry Andric 1865ffd83dbSDimitry Andric void AppleDWARFIndex::GetCompleteObjCClass( 1875ffd83dbSDimitry Andric ConstString class_name, bool must_be_implementation, 1885ffd83dbSDimitry Andric llvm::function_ref<bool(DWARFDIE die)> callback) { 1895ffd83dbSDimitry Andric if (!m_apple_types_up) 1905ffd83dbSDimitry Andric return; 19106c3fb27SDimitry Andric 19206c3fb27SDimitry Andric llvm::SmallVector<DIERef> decl_dies; 19306c3fb27SDimitry Andric auto converted_cb = DIERefCallback(callback, class_name); 19406c3fb27SDimitry Andric 19506c3fb27SDimitry Andric for (const auto &entry : m_apple_types_up->equal_range(class_name)) { 19606c3fb27SDimitry Andric if (HasImplementationFlag(entry)) { 19706c3fb27SDimitry Andric converted_cb(entry); 19806c3fb27SDimitry Andric return; 19906c3fb27SDimitry Andric } 20006c3fb27SDimitry Andric 20106c3fb27SDimitry Andric decl_dies.emplace_back(std::nullopt, DIERef::Section::DebugInfo, 20206c3fb27SDimitry Andric *entry.getDIESectionOffset()); 20306c3fb27SDimitry Andric } 20406c3fb27SDimitry Andric 20506c3fb27SDimitry Andric if (must_be_implementation) 20606c3fb27SDimitry Andric return; 20706c3fb27SDimitry Andric for (DIERef ref : decl_dies) 20806c3fb27SDimitry Andric if (!converted_cb(ref)) 20906c3fb27SDimitry Andric return; 2100b57cec5SDimitry Andric } 2110b57cec5SDimitry Andric 2125ffd83dbSDimitry Andric void AppleDWARFIndex::GetTypes( 2135ffd83dbSDimitry Andric ConstString name, llvm::function_ref<bool(DWARFDIE die)> callback) { 2145ffd83dbSDimitry Andric if (!m_apple_types_up) 2155ffd83dbSDimitry Andric return; 21606c3fb27SDimitry Andric SearchFor(*m_apple_types_up, name, callback); 2170b57cec5SDimitry Andric } 2180b57cec5SDimitry Andric 2195ffd83dbSDimitry Andric void AppleDWARFIndex::GetTypes( 2205ffd83dbSDimitry Andric const DWARFDeclContext &context, 2215ffd83dbSDimitry Andric llvm::function_ref<bool(DWARFDIE die)> callback) { 2220b57cec5SDimitry Andric if (!m_apple_types_up) 2230b57cec5SDimitry Andric return; 2240b57cec5SDimitry Andric 2251fd87a68SDimitry Andric Log *log = GetLog(DWARFLog::TypeCompletion | DWARFLog::Lookups); 22606c3fb27SDimitry Andric const bool entries_have_tag = 22706c3fb27SDimitry Andric m_apple_types_up->containsAtomType(DW_ATOM_die_tag); 22806c3fb27SDimitry Andric const bool entries_have_qual_hash = 22906c3fb27SDimitry Andric m_apple_types_up->containsAtomType(DW_ATOM_qual_name_hash); 2309dba64beSDimitry Andric 23106c3fb27SDimitry Andric llvm::StringRef expected_name = context[0].name; 23206c3fb27SDimitry Andric 23306c3fb27SDimitry Andric if (entries_have_tag && entries_have_qual_hash) { 23406c3fb27SDimitry Andric const dw_tag_t expected_tag = context[0].tag; 23506c3fb27SDimitry Andric const uint32_t expected_qualname_hash = 23606c3fb27SDimitry Andric llvm::djbHash(context.GetQualifiedName()); 2370b57cec5SDimitry Andric if (log) 2380b57cec5SDimitry Andric m_module.LogMessage(log, "FindByNameAndTagAndQualifiedNameHash()"); 23906c3fb27SDimitry Andric SearchFor(*m_apple_types_up, expected_name, callback, expected_tag, 24006c3fb27SDimitry Andric expected_qualname_hash); 2419dba64beSDimitry Andric return; 2429dba64beSDimitry Andric } 2439dba64beSDimitry Andric 24406c3fb27SDimitry Andric // Historically, if there are no tags, we also ignore qual_hash (why?) 24506c3fb27SDimitry Andric if (!entries_have_tag) { 24606c3fb27SDimitry Andric SearchFor(*m_apple_names_up, expected_name, callback); 24706c3fb27SDimitry Andric return; 24806c3fb27SDimitry Andric } 24906c3fb27SDimitry Andric 25006c3fb27SDimitry Andric // We have a tag but no qual hash. 25106c3fb27SDimitry Andric 2529dba64beSDimitry Andric // When searching for a scoped type (for example, 2539dba64beSDimitry Andric // "std::vector<int>::const_iterator") searching for the innermost 2549dba64beSDimitry Andric // name alone ("const_iterator") could yield many false 2559dba64beSDimitry Andric // positives. By searching for the parent type ("vector<int>") 2569dba64beSDimitry Andric // first we can avoid extracting type DIEs from object files that 2579dba64beSDimitry Andric // would fail the filter anyway. 25806c3fb27SDimitry Andric if ((context.GetSize() > 1) && IsClassOrStruct(context[1].tag)) 25906c3fb27SDimitry Andric if (m_apple_types_up->equal_range(context[1].name).empty()) 2609dba64beSDimitry Andric return; 2619dba64beSDimitry Andric 2620b57cec5SDimitry Andric if (log) 2630b57cec5SDimitry Andric m_module.LogMessage(log, "FindByNameAndTag()"); 26406c3fb27SDimitry Andric const dw_tag_t expected_tag = context[0].tag; 26506c3fb27SDimitry Andric SearchFor(*m_apple_types_up, expected_name, callback, expected_tag); 2669dba64beSDimitry Andric return; 2679dba64beSDimitry Andric } 2689dba64beSDimitry Andric 2695ffd83dbSDimitry Andric void AppleDWARFIndex::GetNamespaces( 2705ffd83dbSDimitry Andric ConstString name, llvm::function_ref<bool(DWARFDIE die)> callback) { 2715ffd83dbSDimitry Andric if (!m_apple_namespaces_up) 2725ffd83dbSDimitry Andric return; 27306c3fb27SDimitry Andric SearchFor(*m_apple_namespaces_up, name, callback); 2740b57cec5SDimitry Andric } 2750b57cec5SDimitry Andric 2765ffd83dbSDimitry Andric void AppleDWARFIndex::GetFunctions( 277bdd1243dSDimitry Andric const Module::LookupInfo &lookup_info, SymbolFileDWARF &dwarf, 278bdd1243dSDimitry Andric const CompilerDeclContext &parent_decl_ctx, 2795ffd83dbSDimitry Andric llvm::function_ref<bool(DWARFDIE die)> callback) { 28006c3fb27SDimitry Andric if (!m_apple_names_up) 28106c3fb27SDimitry Andric return; 28206c3fb27SDimitry Andric 283bdd1243dSDimitry Andric ConstString name = lookup_info.GetLookupName(); 28406c3fb27SDimitry Andric for (const auto &entry : m_apple_names_up->equal_range(name)) { 28506c3fb27SDimitry Andric DIERef die_ref(std::nullopt, DIERef::Section::DebugInfo, 28606c3fb27SDimitry Andric *entry.getDIESectionOffset()); 287*0fca6ea1SDimitry Andric DWARFDIE die = dwarf.GetDIE(die_ref); 288*0fca6ea1SDimitry Andric if (!die) { 289*0fca6ea1SDimitry Andric ReportInvalidDIERef(die_ref, name); 290*0fca6ea1SDimitry Andric continue; 291*0fca6ea1SDimitry Andric } 292*0fca6ea1SDimitry Andric if (!ProcessFunctionDIE(lookup_info, die, parent_decl_ctx, callback)) 29306c3fb27SDimitry Andric return; 29406c3fb27SDimitry Andric } 2950b57cec5SDimitry Andric } 2960b57cec5SDimitry Andric 2975ffd83dbSDimitry Andric void AppleDWARFIndex::GetFunctions( 2985ffd83dbSDimitry Andric const RegularExpression ®ex, 2995ffd83dbSDimitry Andric llvm::function_ref<bool(DWARFDIE die)> callback) { 30006c3fb27SDimitry Andric return GetGlobalVariables(regex, callback); 3010b57cec5SDimitry Andric } 3020b57cec5SDimitry Andric 3030b57cec5SDimitry Andric void AppleDWARFIndex::Dump(Stream &s) { 3040b57cec5SDimitry Andric if (m_apple_names_up) 3050b57cec5SDimitry Andric s.PutCString(".apple_names index present\n"); 3060b57cec5SDimitry Andric if (m_apple_namespaces_up) 3070b57cec5SDimitry Andric s.PutCString(".apple_namespaces index present\n"); 3080b57cec5SDimitry Andric if (m_apple_types_up) 3090b57cec5SDimitry Andric s.PutCString(".apple_types index present\n"); 3100b57cec5SDimitry Andric if (m_apple_objc_up) 3110b57cec5SDimitry Andric s.PutCString(".apple_objc index present\n"); 3120b57cec5SDimitry Andric // TODO: Dump index contents 3130b57cec5SDimitry Andric } 314