| 1 | //===-- DWARFIndex.cpp ----------------------------------------------------===// |
| 2 | // |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| 4 | // See https://llvm.org/LICENSE.txt for license information. |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| 6 | // |
| 7 | //===----------------------------------------------------------------------===// |
| 8 | |
| 9 | #include "Plugins/SymbolFile/DWARF/DWARFIndex.h" |
| 10 | #include "DWARFDebugInfoEntry.h" |
| 11 | #include "DWARFDeclContext.h" |
| 12 | #include "Plugins/Language/ObjC/ObjCLanguage.h" |
| 13 | #include "Plugins/SymbolFile/DWARF/DWARFDIE.h" |
| 14 | #include "Plugins/SymbolFile/DWARF/SymbolFileDWARF.h" |
| 15 | |
| 16 | #include "lldb/Core/Mangled.h" |
| 17 | #include "lldb/Core/Module.h" |
| 18 | #include "lldb/Target/Language.h" |
| 19 | |
| 20 | using namespace lldb_private; |
| 21 | using namespace lldb; |
| 22 | using namespace lldb_private::plugin::dwarf; |
| 23 | |
| 24 | DWARFIndex::~DWARFIndex() = default; |
| 25 | |
| 26 | bool DWARFIndex::ProcessFunctionDIE( |
| 27 | const Module::LookupInfo &lookup_info, DWARFDIE die, |
| 28 | const CompilerDeclContext &parent_decl_ctx, |
| 29 | llvm::function_ref<bool(DWARFDIE die)> callback) { |
| 30 | llvm::StringRef name = lookup_info.GetLookupName().GetStringRef(); |
| 31 | FunctionNameType name_type_mask = lookup_info.GetNameTypeMask(); |
| 32 | |
| 33 | if (!(name_type_mask & eFunctionNameTypeFull)) { |
| 34 | ConstString name_to_match_against; |
| 35 | if (const char *mangled_die_name = die.GetMangledName()) { |
| 36 | name_to_match_against = ConstString(mangled_die_name); |
| 37 | } else { |
| 38 | SymbolFileDWARF *symbols = die.GetDWARF(); |
| 39 | if (ConstString demangled_die_name = |
| 40 | symbols->ConstructFunctionDemangledName(die)) |
| 41 | name_to_match_against = demangled_die_name; |
| 42 | } |
| 43 | |
| 44 | if (!lookup_info.NameMatchesLookupInfo(function_name: name_to_match_against, |
| 45 | language_type: lookup_info.GetLanguageType())) |
| 46 | return true; |
| 47 | } |
| 48 | |
| 49 | // Exit early if we're searching exclusively for methods or selectors and |
| 50 | // we have a context specified (no methods in namespaces). |
| 51 | uint32_t looking_for_nonmethods = |
| 52 | name_type_mask & ~(eFunctionNameTypeMethod | eFunctionNameTypeSelector); |
| 53 | if (!looking_for_nonmethods && parent_decl_ctx.IsValid()) |
| 54 | return true; |
| 55 | |
| 56 | // Otherwise, we need to also check that the context matches. If it does not |
| 57 | // match, we do nothing. |
| 58 | if (!SymbolFileDWARF::DIEInDeclContext(parent_decl_ctx, die)) |
| 59 | return true; |
| 60 | |
| 61 | // In case of a full match, we just insert everything we find. |
| 62 | if (name_type_mask & eFunctionNameTypeFull && die.GetMangledName() == name) |
| 63 | return callback(die); |
| 64 | |
| 65 | // If looking for ObjC selectors, we need to also check if the name is a |
| 66 | // possible selector. |
| 67 | if (name_type_mask & eFunctionNameTypeSelector && |
| 68 | ObjCLanguage::IsPossibleObjCMethodName(name: die.GetName())) |
| 69 | return callback(die); |
| 70 | |
| 71 | bool looking_for_methods = name_type_mask & lldb::eFunctionNameTypeMethod; |
| 72 | bool looking_for_functions = name_type_mask & lldb::eFunctionNameTypeBase; |
| 73 | if (looking_for_methods || looking_for_functions) { |
| 74 | // If we're looking for either methods or functions, we definitely want this |
| 75 | // die. Otherwise, only keep it if the die type matches what we are |
| 76 | // searching for. |
| 77 | if ((looking_for_methods && looking_for_functions) || |
| 78 | looking_for_methods == die.IsMethod()) |
| 79 | return callback(die); |
| 80 | } |
| 81 | |
| 82 | return true; |
| 83 | } |
| 84 | |
| 85 | DWARFIndex::DIERefCallbackImpl::DIERefCallbackImpl( |
| 86 | const DWARFIndex &index, llvm::function_ref<bool(DWARFDIE die)> callback, |
| 87 | llvm::StringRef name) |
| 88 | : m_index(index), |
| 89 | m_dwarf(*llvm::cast<SymbolFileDWARF>( |
| 90 | Val: index.m_module.GetSymbolFile()->GetBackingSymbolFile())), |
| 91 | m_callback(callback), m_name(name) {} |
| 92 | |
| 93 | bool DWARFIndex::DIERefCallbackImpl::operator()(DIERef ref) const { |
| 94 | if (DWARFDIE die = m_dwarf.GetDIE(die_ref: ref)) |
| 95 | return m_callback(die); |
| 96 | m_index.ReportInvalidDIERef(ref, name: m_name); |
| 97 | return true; |
| 98 | } |
| 99 | |
| 100 | bool DWARFIndex::DIERefCallbackImpl::operator()( |
| 101 | const llvm::AppleAcceleratorTable::Entry &entry) const { |
| 102 | return this->operator()(ref: DIERef(std::nullopt, DIERef::Section::DebugInfo, |
| 103 | *entry.getDIESectionOffset())); |
| 104 | } |
| 105 | |
| 106 | void DWARFIndex::ReportInvalidDIERef(DIERef ref, llvm::StringRef name) const { |
| 107 | m_module.ReportErrorIfModifyDetected( |
| 108 | format: "the DWARF debug information has been modified (accelerator table had " |
| 109 | "bad die {0:x16} for '{1}')\n" , |
| 110 | args: ref.die_offset(), args: name.str().c_str()); |
| 111 | } |
| 112 | |
| 113 | void DWARFIndex::GetFullyQualifiedType( |
| 114 | const DWARFDeclContext &context, |
| 115 | llvm::function_ref<bool(DWARFDIE die)> callback) { |
| 116 | GetTypes(context, callback: [&](DWARFDIE die) { |
| 117 | return GetFullyQualifiedTypeImpl(context, die, callback); |
| 118 | }); |
| 119 | } |
| 120 | |
| 121 | bool DWARFIndex::GetFullyQualifiedTypeImpl( |
| 122 | const DWARFDeclContext &context, DWARFDIE die, |
| 123 | llvm::function_ref<bool(DWARFDIE die)> callback) { |
| 124 | DWARFDeclContext dwarf_decl_ctx = die.GetDWARFDeclContext(); |
| 125 | if (dwarf_decl_ctx == context) |
| 126 | return callback(die); |
| 127 | return true; |
| 128 | } |
| 129 | |
| 130 | void DWARFIndex::GetTypesWithQuery( |
| 131 | TypeQuery &query, llvm::function_ref<bool(DWARFDIE die)> callback) { |
| 132 | GetTypes(name: query.GetTypeBasename(), callback: [&](DWARFDIE die) { |
| 133 | return ProcessTypeDIEMatchQuery(query, die, callback); |
| 134 | }); |
| 135 | } |
| 136 | |
| 137 | bool DWARFIndex::ProcessTypeDIEMatchQuery( |
| 138 | TypeQuery &query, DWARFDIE die, |
| 139 | llvm::function_ref<bool(DWARFDIE die)> callback) { |
| 140 | // Check the language, but only if we have a language filter. |
| 141 | if (query.HasLanguage() && |
| 142 | !query.LanguageMatches(language: SymbolFileDWARF::GetLanguageFamily(unit&: *die.GetCU()))) |
| 143 | return true; // Keep iterating over index types, language mismatch. |
| 144 | |
| 145 | // Since mangled names are unique, we only need to check if the names are |
| 146 | // the same. |
| 147 | if (query.GetSearchByMangledName()) { |
| 148 | if (die.GetMangledName(/*substitute_name_allowed=*/false) != |
| 149 | query.GetTypeBasename().GetStringRef()) |
| 150 | return true; // Keep iterating over index types, mangled name mismatch. |
| 151 | return callback(die); |
| 152 | } |
| 153 | |
| 154 | std::vector<lldb_private::CompilerContext> die_context; |
| 155 | if (query.GetModuleSearch()) |
| 156 | die_context = die.GetDeclContext(); |
| 157 | else |
| 158 | die_context = die.GetTypeLookupContext(); |
| 159 | |
| 160 | if (!query.ContextMatches(context: die_context)) |
| 161 | return true; |
| 162 | return callback(die); |
| 163 | } |
| 164 | |
| 165 | void DWARFIndex::GetNamespacesWithParents( |
| 166 | ConstString name, const CompilerDeclContext &parent_decl_ctx, |
| 167 | llvm::function_ref<bool(DWARFDIE die)> callback) { |
| 168 | GetNamespaces(name, callback: [&](DWARFDIE die) { |
| 169 | return ProcessNamespaceDieMatchParents(parent_decl_ctx, die, callback); |
| 170 | }); |
| 171 | } |
| 172 | |
| 173 | bool DWARFIndex::ProcessNamespaceDieMatchParents( |
| 174 | const CompilerDeclContext &parent_decl_ctx, DWARFDIE die, |
| 175 | llvm::function_ref<bool(DWARFDIE die)> callback) { |
| 176 | if (!SymbolFileDWARF::DIEInDeclContext(parent_decl_ctx, die)) |
| 177 | return true; |
| 178 | return callback(die); |
| 179 | } |
| 180 | |