1 //===-- DebugNamesDWARFIndex.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/DebugNamesDWARFIndex.h" 10 #include "Plugins/SymbolFile/DWARF/DWARFDebugInfo.h" 11 #include "Plugins/SymbolFile/DWARF/DWARFDeclContext.h" 12 #include "Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.h" 13 #include "lldb/Utility/RegularExpression.h" 14 #include "lldb/Utility/Stream.h" 15 16 using namespace lldb_private; 17 using namespace lldb; 18 19 llvm::Expected<std::unique_ptr<DebugNamesDWARFIndex>> 20 DebugNamesDWARFIndex::Create(Module &module, DWARFDataExtractor debug_names, 21 DWARFDataExtractor debug_str, 22 SymbolFileDWARF &dwarf) { 23 auto index_up = std::make_unique<DebugNames>(debug_names.GetAsLLVM(), 24 debug_str.GetAsLLVM()); 25 if (llvm::Error E = index_up->extract()) 26 return std::move(E); 27 28 return std::unique_ptr<DebugNamesDWARFIndex>(new DebugNamesDWARFIndex( 29 module, std::move(index_up), debug_names, debug_str, dwarf)); 30 } 31 32 llvm::DenseSet<dw_offset_t> 33 DebugNamesDWARFIndex::GetUnits(const DebugNames &debug_names) { 34 llvm::DenseSet<dw_offset_t> result; 35 for (const DebugNames::NameIndex &ni : debug_names) { 36 for (uint32_t cu = 0; cu < ni.getCUCount(); ++cu) 37 result.insert(ni.getCUOffset(cu)); 38 } 39 return result; 40 } 41 42 llvm::Optional<DIERef> 43 DebugNamesDWARFIndex::ToDIERef(const DebugNames::Entry &entry) { 44 llvm::Optional<uint64_t> cu_offset = entry.getCUOffset(); 45 if (!cu_offset) 46 return llvm::None; 47 48 DWARFUnit *cu = m_debug_info.GetUnitAtOffset(DIERef::Section::DebugInfo, *cu_offset); 49 if (!cu) 50 return llvm::None; 51 52 cu = &cu->GetNonSkeletonUnit(); 53 if (llvm::Optional<uint64_t> die_offset = entry.getDIEUnitOffset()) 54 return DIERef(cu->GetSymbolFileDWARF().GetDwoNum(), 55 DIERef::Section::DebugInfo, cu->GetOffset() + *die_offset); 56 57 return llvm::None; 58 } 59 60 bool DebugNamesDWARFIndex::ProcessEntry( 61 const DebugNames::Entry &entry, 62 llvm::function_ref<bool(DIERef ref)> callback) { 63 if (llvm::Optional<DIERef> ref = ToDIERef(entry)) 64 return callback(*ref); 65 return true; 66 } 67 68 void DebugNamesDWARFIndex::MaybeLogLookupError(llvm::Error error, 69 const DebugNames::NameIndex &ni, 70 llvm::StringRef name) { 71 // Ignore SentinelErrors, log everything else. 72 LLDB_LOG_ERROR( 73 LogChannelDWARF::GetLogIfAll(DWARF_LOG_LOOKUPS), 74 handleErrors(std::move(error), [](const DebugNames::SentinelError &) {}), 75 "Failed to parse index entries for index at {1:x}, name {2}: {0}", 76 ni.getUnitOffset(), name); 77 } 78 79 void DebugNamesDWARFIndex::GetGlobalVariables( 80 ConstString basename, llvm::function_ref<bool(DIERef ref)> callback) { 81 for (const DebugNames::Entry &entry : 82 m_debug_names_up->equal_range(basename.GetStringRef())) { 83 if (entry.tag() != DW_TAG_variable) 84 continue; 85 86 if (!ProcessEntry(entry, callback)) 87 return; 88 } 89 90 m_fallback.GetGlobalVariables(basename, callback); 91 } 92 93 void DebugNamesDWARFIndex::GetGlobalVariables( 94 const RegularExpression ®ex, 95 llvm::function_ref<bool(DIERef ref)> callback) { 96 for (const DebugNames::NameIndex &ni: *m_debug_names_up) { 97 for (DebugNames::NameTableEntry nte: ni) { 98 if (!regex.Execute(nte.getString())) 99 continue; 100 101 uint64_t entry_offset = nte.getEntryOffset(); 102 llvm::Expected<DebugNames::Entry> entry_or = ni.getEntry(&entry_offset); 103 for (; entry_or; entry_or = ni.getEntry(&entry_offset)) { 104 if (entry_or->tag() != DW_TAG_variable) 105 continue; 106 107 if (!ProcessEntry(*entry_or, callback)) 108 return; 109 } 110 MaybeLogLookupError(entry_or.takeError(), ni, nte.getString()); 111 } 112 } 113 114 m_fallback.GetGlobalVariables(regex, callback); 115 } 116 117 void DebugNamesDWARFIndex::GetGlobalVariables( 118 const DWARFUnit &cu, llvm::function_ref<bool(DIERef ref)> callback) { 119 uint64_t cu_offset = cu.GetOffset(); 120 for (const DebugNames::NameIndex &ni: *m_debug_names_up) { 121 for (DebugNames::NameTableEntry nte: ni) { 122 uint64_t entry_offset = nte.getEntryOffset(); 123 llvm::Expected<DebugNames::Entry> entry_or = ni.getEntry(&entry_offset); 124 for (; entry_or; entry_or = ni.getEntry(&entry_offset)) { 125 if (entry_or->tag() != DW_TAG_variable) 126 continue; 127 if (entry_or->getCUOffset() != cu_offset) 128 continue; 129 130 if (!ProcessEntry(*entry_or, callback)) 131 return; 132 } 133 MaybeLogLookupError(entry_or.takeError(), ni, nte.getString()); 134 } 135 } 136 137 m_fallback.GetGlobalVariables(cu, callback); 138 } 139 140 void DebugNamesDWARFIndex::GetCompleteObjCClass( 141 ConstString class_name, bool must_be_implementation, 142 llvm::function_ref<bool(DIERef ref)> callback) { 143 // Keep a list of incomplete types as fallback for when we don't find the 144 // complete type. 145 DIEArray incomplete_types; 146 147 for (const DebugNames::Entry &entry : 148 m_debug_names_up->equal_range(class_name.GetStringRef())) { 149 if (entry.tag() != DW_TAG_structure_type && 150 entry.tag() != DW_TAG_class_type) 151 continue; 152 153 llvm::Optional<DIERef> ref = ToDIERef(entry); 154 if (!ref) 155 continue; 156 157 DWARFUnit *cu = m_debug_info.GetUnit(*ref); 158 if (!cu || !cu->Supports_DW_AT_APPLE_objc_complete_type()) { 159 incomplete_types.push_back(*ref); 160 continue; 161 } 162 163 // FIXME: We should return DWARFDIEs so we don't have to resolve it twice. 164 DWARFDIE die = m_debug_info.GetDIE(*ref); 165 if (!die) 166 continue; 167 168 if (die.GetAttributeValueAsUnsigned(DW_AT_APPLE_objc_complete_type, 0)) { 169 // If we find the complete version we're done. 170 callback(*ref); 171 return; 172 } 173 incomplete_types.push_back(*ref); 174 } 175 176 for (DIERef ref : incomplete_types) 177 if (!callback(ref)) 178 return; 179 180 m_fallback.GetCompleteObjCClass(class_name, must_be_implementation, callback); 181 } 182 183 void DebugNamesDWARFIndex::GetTypes( 184 ConstString name, llvm::function_ref<bool(DIERef ref)> callback) { 185 for (const DebugNames::Entry &entry : 186 m_debug_names_up->equal_range(name.GetStringRef())) { 187 if (isType(entry.tag())) { 188 if (!ProcessEntry(entry, callback)) 189 return; 190 } 191 } 192 193 m_fallback.GetTypes(name, callback); 194 } 195 196 void DebugNamesDWARFIndex::GetTypes( 197 const DWARFDeclContext &context, 198 llvm::function_ref<bool(DIERef ref)> callback) { 199 for (const DebugNames::Entry &entry : 200 m_debug_names_up->equal_range(context[0].name)) { 201 if (entry.tag() == context[0].tag) { 202 if (!ProcessEntry(entry, callback)) 203 return; 204 } 205 } 206 207 m_fallback.GetTypes(context, callback); 208 } 209 210 void DebugNamesDWARFIndex::GetNamespaces( 211 ConstString name, llvm::function_ref<bool(DIERef ref)> callback) { 212 for (const DebugNames::Entry &entry : 213 m_debug_names_up->equal_range(name.GetStringRef())) { 214 if (entry.tag() == DW_TAG_namespace) { 215 if (!ProcessEntry(entry, callback)) 216 return; 217 } 218 } 219 220 m_fallback.GetNamespaces(name, callback); 221 } 222 223 void DebugNamesDWARFIndex::GetFunctions( 224 ConstString name, SymbolFileDWARF &dwarf, 225 const CompilerDeclContext &parent_decl_ctx, uint32_t name_type_mask, 226 llvm::function_ref<bool(DWARFDIE die)> callback) { 227 228 std::set<DWARFDebugInfoEntry *> seen; 229 for (const DebugNames::Entry &entry : 230 m_debug_names_up->equal_range(name.GetStringRef())) { 231 Tag tag = entry.tag(); 232 if (tag != DW_TAG_subprogram && tag != DW_TAG_inlined_subroutine) 233 continue; 234 235 if (llvm::Optional<DIERef> ref = ToDIERef(entry)) { 236 if (!ProcessFunctionDIE(name.GetStringRef(), *ref, dwarf, parent_decl_ctx, 237 name_type_mask, [&](DWARFDIE die) { 238 if (!seen.insert(die.GetDIE()).second) 239 return true; 240 return callback(die); 241 })) 242 return; 243 } 244 } 245 246 m_fallback.GetFunctions(name, dwarf, parent_decl_ctx, name_type_mask, 247 callback); 248 } 249 250 void DebugNamesDWARFIndex::GetFunctions( 251 const RegularExpression ®ex, 252 llvm::function_ref<bool(DIERef ref)> callback) { 253 for (const DebugNames::NameIndex &ni: *m_debug_names_up) { 254 for (DebugNames::NameTableEntry nte: ni) { 255 if (!regex.Execute(nte.getString())) 256 continue; 257 258 uint64_t entry_offset = nte.getEntryOffset(); 259 llvm::Expected<DebugNames::Entry> entry_or = ni.getEntry(&entry_offset); 260 for (; entry_or; entry_or = ni.getEntry(&entry_offset)) { 261 Tag tag = entry_or->tag(); 262 if (tag != DW_TAG_subprogram && tag != DW_TAG_inlined_subroutine) 263 continue; 264 265 if (!ProcessEntry(*entry_or, callback)) 266 return; 267 } 268 MaybeLogLookupError(entry_or.takeError(), ni, nte.getString()); 269 } 270 } 271 272 m_fallback.GetFunctions(regex, callback); 273 } 274 275 void DebugNamesDWARFIndex::Dump(Stream &s) { 276 m_fallback.Dump(s); 277 278 std::string data; 279 llvm::raw_string_ostream os(data); 280 m_debug_names_up->dump(os); 281 s.PutCString(os.str()); 282 } 283