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