1 //===-- ManualDWARFIndex.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/ManualDWARFIndex.h" 10 #include "Plugins/Language/ObjC/ObjCLanguage.h" 11 #include "Plugins/SymbolFile/DWARF/DWARFDebugInfo.h" 12 #include "Plugins/SymbolFile/DWARF/DWARFDeclContext.h" 13 #include "Plugins/SymbolFile/DWARF/LogChannelDWARF.h" 14 #include "Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.h" 15 #include "lldb/Core/Module.h" 16 #include "lldb/Host/TaskPool.h" 17 #include "lldb/Symbol/ObjectFile.h" 18 #include "lldb/Utility/Stream.h" 19 #include "lldb/Utility/Timer.h" 20 21 using namespace lldb_private; 22 using namespace lldb; 23 24 void ManualDWARFIndex::Index() { 25 if (!m_dwarf) 26 return; 27 28 SymbolFileDWARF &main_dwarf = *m_dwarf; 29 m_dwarf = nullptr; 30 31 static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); 32 Timer scoped_timer(func_cat, "%p", static_cast<void *>(&main_dwarf)); 33 34 DWARFDebugInfo &main_info = main_dwarf.DebugInfo(); 35 SymbolFileDWARFDwo *dwp_dwarf = main_dwarf.GetDwpSymbolFile().get(); 36 DWARFDebugInfo *dwp_info = dwp_dwarf ? &dwp_dwarf->DebugInfo() : nullptr; 37 38 std::vector<DWARFUnit *> units_to_index; 39 units_to_index.reserve(main_info.GetNumUnits() + 40 (dwp_info ? dwp_info->GetNumUnits() : 0)); 41 42 // Process all units in the main file, as well as any type units in the dwp 43 // file. Type units in dwo files are handled when we reach the dwo file in 44 // IndexUnit. 45 for (size_t U = 0; U < main_info.GetNumUnits(); ++U) { 46 DWARFUnit *unit = main_info.GetUnitAtIndex(U); 47 if (unit && m_units_to_avoid.count(unit->GetOffset()) == 0) 48 units_to_index.push_back(unit); 49 } 50 if (dwp_info && dwp_info->ContainsTypeUnits()) { 51 for (size_t U = 0; U < dwp_info->GetNumUnits(); ++U) { 52 if (auto *tu = llvm::dyn_cast<DWARFTypeUnit>(dwp_info->GetUnitAtIndex(U))) 53 units_to_index.push_back(tu); 54 } 55 } 56 57 if (units_to_index.empty()) 58 return; 59 60 std::vector<IndexSet> sets(units_to_index.size()); 61 62 // Keep memory down by clearing DIEs for any units if indexing 63 // caused us to load the unit's DIEs. 64 std::vector<llvm::Optional<DWARFUnit::ScopedExtractDIEs>> clear_cu_dies( 65 units_to_index.size()); 66 auto parser_fn = [&](size_t cu_idx) { 67 IndexUnit(*units_to_index[cu_idx], dwp_dwarf, sets[cu_idx]); 68 }; 69 70 auto extract_fn = [&units_to_index, &clear_cu_dies](size_t cu_idx) { 71 clear_cu_dies[cu_idx] = units_to_index[cu_idx]->ExtractDIEsScoped(); 72 }; 73 74 // Create a task runner that extracts dies for each DWARF unit in a 75 // separate thread 76 // First figure out which units didn't have their DIEs already 77 // parsed and remember this. If no DIEs were parsed prior to this index 78 // function call, we are going to want to clear the CU dies after we are 79 // done indexing to make sure we don't pull in all DWARF dies, but we need 80 // to wait until all units have been indexed in case a DIE in one 81 // unit refers to another and the indexes accesses those DIEs. 82 TaskMapOverInt(0, units_to_index.size(), extract_fn); 83 84 // Now create a task runner that can index each DWARF unit in a 85 // separate thread so we can index quickly. 86 87 TaskMapOverInt(0, units_to_index.size(), parser_fn); 88 89 auto finalize_fn = [this, &sets](NameToDIE(IndexSet::*index)) { 90 NameToDIE &result = m_set.*index; 91 for (auto &set : sets) 92 result.Append(set.*index); 93 result.Finalize(); 94 }; 95 96 TaskPool::RunTasks([&]() { finalize_fn(&IndexSet::function_basenames); }, 97 [&]() { finalize_fn(&IndexSet::function_fullnames); }, 98 [&]() { finalize_fn(&IndexSet::function_methods); }, 99 [&]() { finalize_fn(&IndexSet::function_selectors); }, 100 [&]() { finalize_fn(&IndexSet::objc_class_selectors); }, 101 [&]() { finalize_fn(&IndexSet::globals); }, 102 [&]() { finalize_fn(&IndexSet::types); }, 103 [&]() { finalize_fn(&IndexSet::namespaces); }); 104 } 105 106 void ManualDWARFIndex::IndexUnit(DWARFUnit &unit, SymbolFileDWARFDwo *dwp, 107 IndexSet &set) { 108 Log *log = LogChannelDWARF::GetLogIfAll(DWARF_LOG_LOOKUPS); 109 110 if (log) { 111 m_module.LogMessage( 112 log, "ManualDWARFIndex::IndexUnit for unit at .debug_info[0x%8.8x]", 113 unit.GetOffset()); 114 } 115 116 const LanguageType cu_language = SymbolFileDWARF::GetLanguage(unit); 117 118 IndexUnitImpl(unit, cu_language, set); 119 120 if (SymbolFileDWARFDwo *dwo_symbol_file = unit.GetDwoSymbolFile()) { 121 // Type units in a dwp file are indexed separately, so we just need to 122 // process the split unit here. However, if the split unit is in a dwo file, 123 // then we need to process type units here. 124 if (dwo_symbol_file == dwp) { 125 IndexUnitImpl(unit.GetNonSkeletonUnit(), cu_language, set); 126 } else { 127 DWARFDebugInfo &dwo_info = dwo_symbol_file->DebugInfo(); 128 for (size_t i = 0; i < dwo_info.GetNumUnits(); ++i) 129 IndexUnitImpl(*dwo_info.GetUnitAtIndex(i), cu_language, set); 130 } 131 } 132 } 133 134 void ManualDWARFIndex::IndexUnitImpl(DWARFUnit &unit, 135 const LanguageType cu_language, 136 IndexSet &set) { 137 for (const DWARFDebugInfoEntry &die : unit.dies()) { 138 const dw_tag_t tag = die.Tag(); 139 140 switch (tag) { 141 case DW_TAG_array_type: 142 case DW_TAG_base_type: 143 case DW_TAG_class_type: 144 case DW_TAG_constant: 145 case DW_TAG_enumeration_type: 146 case DW_TAG_inlined_subroutine: 147 case DW_TAG_namespace: 148 case DW_TAG_string_type: 149 case DW_TAG_structure_type: 150 case DW_TAG_subprogram: 151 case DW_TAG_subroutine_type: 152 case DW_TAG_typedef: 153 case DW_TAG_union_type: 154 case DW_TAG_unspecified_type: 155 case DW_TAG_variable: 156 break; 157 158 default: 159 continue; 160 } 161 162 DWARFAttributes attributes; 163 const char *name = nullptr; 164 const char *mangled_cstr = nullptr; 165 bool is_declaration = false; 166 // bool is_artificial = false; 167 bool has_address = false; 168 bool has_location_or_const_value = false; 169 bool is_global_or_static_variable = false; 170 171 DWARFFormValue specification_die_form; 172 const size_t num_attributes = die.GetAttributes(&unit, attributes); 173 if (num_attributes > 0) { 174 for (uint32_t i = 0; i < num_attributes; ++i) { 175 dw_attr_t attr = attributes.AttributeAtIndex(i); 176 DWARFFormValue form_value; 177 switch (attr) { 178 case DW_AT_name: 179 if (attributes.ExtractFormValueAtIndex(i, form_value)) 180 name = form_value.AsCString(); 181 break; 182 183 case DW_AT_declaration: 184 if (attributes.ExtractFormValueAtIndex(i, form_value)) 185 is_declaration = form_value.Unsigned() != 0; 186 break; 187 188 case DW_AT_MIPS_linkage_name: 189 case DW_AT_linkage_name: 190 if (attributes.ExtractFormValueAtIndex(i, form_value)) 191 mangled_cstr = form_value.AsCString(); 192 break; 193 194 case DW_AT_low_pc: 195 case DW_AT_high_pc: 196 case DW_AT_ranges: 197 has_address = true; 198 break; 199 200 case DW_AT_entry_pc: 201 has_address = true; 202 break; 203 204 case DW_AT_location: 205 case DW_AT_const_value: 206 has_location_or_const_value = true; 207 is_global_or_static_variable = die.IsGlobalOrStaticVariable(); 208 209 break; 210 211 case DW_AT_specification: 212 if (attributes.ExtractFormValueAtIndex(i, form_value)) 213 specification_die_form = form_value; 214 break; 215 } 216 } 217 } 218 219 DIERef ref = *DWARFDIE(&unit, &die).GetDIERef(); 220 switch (tag) { 221 case DW_TAG_inlined_subroutine: 222 case DW_TAG_subprogram: 223 if (has_address) { 224 if (name) { 225 bool is_objc_method = false; 226 if (cu_language == eLanguageTypeObjC || 227 cu_language == eLanguageTypeObjC_plus_plus) { 228 ObjCLanguage::MethodName objc_method(name, true); 229 if (objc_method.IsValid(true)) { 230 is_objc_method = true; 231 ConstString class_name_with_category( 232 objc_method.GetClassNameWithCategory()); 233 ConstString objc_selector_name(objc_method.GetSelector()); 234 ConstString objc_fullname_no_category_name( 235 objc_method.GetFullNameWithoutCategory(true)); 236 ConstString class_name_no_category(objc_method.GetClassName()); 237 set.function_fullnames.Insert(ConstString(name), ref); 238 if (class_name_with_category) 239 set.objc_class_selectors.Insert(class_name_with_category, ref); 240 if (class_name_no_category && 241 class_name_no_category != class_name_with_category) 242 set.objc_class_selectors.Insert(class_name_no_category, ref); 243 if (objc_selector_name) 244 set.function_selectors.Insert(objc_selector_name, ref); 245 if (objc_fullname_no_category_name) 246 set.function_fullnames.Insert(objc_fullname_no_category_name, 247 ref); 248 } 249 } 250 // If we have a mangled name, then the DW_AT_name attribute is 251 // usually the method name without the class or any parameters 252 bool is_method = DWARFDIE(&unit, &die).IsMethod(); 253 254 if (is_method) 255 set.function_methods.Insert(ConstString(name), ref); 256 else 257 set.function_basenames.Insert(ConstString(name), ref); 258 259 if (!is_method && !mangled_cstr && !is_objc_method) 260 set.function_fullnames.Insert(ConstString(name), ref); 261 } 262 if (mangled_cstr) { 263 // Make sure our mangled name isn't the same string table entry as 264 // our name. If it starts with '_', then it is ok, else compare the 265 // string to make sure it isn't the same and we don't end up with 266 // duplicate entries 267 if (name && name != mangled_cstr && 268 ((mangled_cstr[0] == '_') || 269 (::strcmp(name, mangled_cstr) != 0))) { 270 set.function_fullnames.Insert(ConstString(mangled_cstr), ref); 271 } 272 } 273 } 274 break; 275 276 case DW_TAG_array_type: 277 case DW_TAG_base_type: 278 case DW_TAG_class_type: 279 case DW_TAG_constant: 280 case DW_TAG_enumeration_type: 281 case DW_TAG_string_type: 282 case DW_TAG_structure_type: 283 case DW_TAG_subroutine_type: 284 case DW_TAG_typedef: 285 case DW_TAG_union_type: 286 case DW_TAG_unspecified_type: 287 if (name && !is_declaration) 288 set.types.Insert(ConstString(name), ref); 289 if (mangled_cstr && !is_declaration) 290 set.types.Insert(ConstString(mangled_cstr), ref); 291 break; 292 293 case DW_TAG_namespace: 294 if (name) 295 set.namespaces.Insert(ConstString(name), ref); 296 break; 297 298 case DW_TAG_variable: 299 if (name && has_location_or_const_value && is_global_or_static_variable) { 300 set.globals.Insert(ConstString(name), ref); 301 // Be sure to include variables by their mangled and demangled names if 302 // they have any since a variable can have a basename "i", a mangled 303 // named "_ZN12_GLOBAL__N_11iE" and a demangled mangled name 304 // "(anonymous namespace)::i"... 305 306 // Make sure our mangled name isn't the same string table entry as our 307 // name. If it starts with '_', then it is ok, else compare the string 308 // to make sure it isn't the same and we don't end up with duplicate 309 // entries 310 if (mangled_cstr && name != mangled_cstr && 311 ((mangled_cstr[0] == '_') || (::strcmp(name, mangled_cstr) != 0))) { 312 set.globals.Insert(ConstString(mangled_cstr), ref); 313 } 314 } 315 break; 316 317 default: 318 continue; 319 } 320 } 321 } 322 323 void ManualDWARFIndex::GetGlobalVariables( 324 ConstString basename, llvm::function_ref<bool(DIERef ref)> callback) { 325 Index(); 326 m_set.globals.Find(basename, callback); 327 } 328 329 void ManualDWARFIndex::GetGlobalVariables( 330 const RegularExpression ®ex, 331 llvm::function_ref<bool(DIERef ref)> callback) { 332 Index(); 333 m_set.globals.Find(regex, callback); 334 } 335 336 void ManualDWARFIndex::GetGlobalVariables( 337 const DWARFUnit &unit, llvm::function_ref<bool(DIERef ref)> callback) { 338 Index(); 339 m_set.globals.FindAllEntriesForUnit(unit, callback); 340 } 341 342 void ManualDWARFIndex::GetObjCMethods( 343 ConstString class_name, llvm::function_ref<bool(DIERef ref)> callback) { 344 Index(); 345 m_set.objc_class_selectors.Find(class_name, callback); 346 } 347 348 void ManualDWARFIndex::GetCompleteObjCClass( 349 ConstString class_name, bool must_be_implementation, 350 llvm::function_ref<bool(DIERef ref)> callback) { 351 Index(); 352 m_set.types.Find(class_name, callback); 353 } 354 355 void ManualDWARFIndex::GetTypes(ConstString name, 356 llvm::function_ref<bool(DIERef ref)> callback) { 357 Index(); 358 m_set.types.Find(name, callback); 359 } 360 361 void ManualDWARFIndex::GetTypes(const DWARFDeclContext &context, 362 llvm::function_ref<bool(DIERef ref)> callback) { 363 Index(); 364 m_set.types.Find(ConstString(context[0].name), callback); 365 } 366 367 void ManualDWARFIndex::GetNamespaces( 368 ConstString name, llvm::function_ref<bool(DIERef ref)> callback) { 369 Index(); 370 m_set.namespaces.Find(name, callback); 371 } 372 373 void ManualDWARFIndex::GetFunctions( 374 ConstString name, SymbolFileDWARF &dwarf, 375 const CompilerDeclContext &parent_decl_ctx, uint32_t name_type_mask, 376 llvm::function_ref<bool(DWARFDIE die)> callback) { 377 Index(); 378 379 if (name_type_mask & eFunctionNameTypeFull) { 380 if (!m_set.function_fullnames.Find(name, [&](DIERef die_ref) { 381 DWARFDIE die = dwarf.GetDIE(die_ref); 382 if (!die) 383 return true; 384 if (!SymbolFileDWARF::DIEInDeclContext(parent_decl_ctx, die)) 385 return true; 386 return callback(die); 387 })) 388 return; 389 } 390 if (name_type_mask & eFunctionNameTypeBase) { 391 if (!m_set.function_basenames.Find(name, [&](DIERef die_ref) { 392 DWARFDIE die = dwarf.GetDIE(die_ref); 393 if (!die) 394 return true; 395 if (!SymbolFileDWARF::DIEInDeclContext(parent_decl_ctx, die)) 396 return true; 397 return callback(die); 398 })) 399 return; 400 } 401 402 if (name_type_mask & eFunctionNameTypeMethod && !parent_decl_ctx.IsValid()) { 403 if (!m_set.function_methods.Find(name, [&](DIERef die_ref) { 404 DWARFDIE die = dwarf.GetDIE(die_ref); 405 if (!die) 406 return true; 407 return callback(die); 408 })) 409 return; 410 } 411 412 if (name_type_mask & eFunctionNameTypeSelector && 413 !parent_decl_ctx.IsValid()) { 414 if (!m_set.function_selectors.Find(name, [&](DIERef die_ref) { 415 DWARFDIE die = dwarf.GetDIE(die_ref); 416 if (!die) 417 return true; 418 return callback(die); 419 })) 420 return; 421 } 422 } 423 424 void ManualDWARFIndex::GetFunctions( 425 const RegularExpression ®ex, 426 llvm::function_ref<bool(DIERef ref)> callback) { 427 Index(); 428 429 if (!m_set.function_basenames.Find(regex, callback)) 430 return; 431 if (!m_set.function_fullnames.Find(regex, callback)) 432 return; 433 } 434 435 void ManualDWARFIndex::Dump(Stream &s) { 436 s.Format("Manual DWARF index for ({0}) '{1:F}':", 437 m_module.GetArchitecture().GetArchitectureName(), 438 m_module.GetObjectFile()->GetFileSpec()); 439 s.Printf("\nFunction basenames:\n"); 440 m_set.function_basenames.Dump(&s); 441 s.Printf("\nFunction fullnames:\n"); 442 m_set.function_fullnames.Dump(&s); 443 s.Printf("\nFunction methods:\n"); 444 m_set.function_methods.Dump(&s); 445 s.Printf("\nFunction selectors:\n"); 446 m_set.function_selectors.Dump(&s); 447 s.Printf("\nObjective-C class selectors:\n"); 448 m_set.objc_class_selectors.Dump(&s); 449 s.Printf("\nGlobals and statics:\n"); 450 m_set.globals.Dump(&s); 451 s.Printf("\nTypes:\n"); 452 m_set.types.Dump(&s); 453 s.Printf("\nNamespaces:\n"); 454 m_set.namespaces.Dump(&s); 455 } 456