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 if (tag == DW_TAG_variable) { 208 const DWARFDebugInfoEntry *parent_die = die.GetParent(); 209 while (parent_die != nullptr) { 210 switch (parent_die->Tag()) { 211 case DW_TAG_subprogram: 212 case DW_TAG_lexical_block: 213 case DW_TAG_inlined_subroutine: 214 // Even if this is a function level static, we don't add it. We 215 // could theoretically add these if we wanted to by 216 // introspecting into the DW_AT_location and seeing if the 217 // location describes a hard coded address, but we don't want 218 // the performance penalty of that right now. 219 is_global_or_static_variable = false; 220 parent_die = nullptr; // Terminate the while loop. 221 break; 222 223 case DW_TAG_compile_unit: 224 case DW_TAG_partial_unit: 225 is_global_or_static_variable = true; 226 parent_die = nullptr; // Terminate the while loop. 227 break; 228 229 default: 230 parent_die = 231 parent_die->GetParent(); // Keep going in the while loop. 232 break; 233 } 234 } 235 } 236 break; 237 238 case DW_AT_specification: 239 if (attributes.ExtractFormValueAtIndex(i, form_value)) 240 specification_die_form = form_value; 241 break; 242 } 243 } 244 } 245 246 DIERef ref = *DWARFDIE(&unit, &die).GetDIERef(); 247 switch (tag) { 248 case DW_TAG_inlined_subroutine: 249 case DW_TAG_subprogram: 250 if (has_address) { 251 if (name) { 252 bool is_objc_method = false; 253 if (cu_language == eLanguageTypeObjC || 254 cu_language == eLanguageTypeObjC_plus_plus) { 255 ObjCLanguage::MethodName objc_method(name, true); 256 if (objc_method.IsValid(true)) { 257 is_objc_method = true; 258 ConstString class_name_with_category( 259 objc_method.GetClassNameWithCategory()); 260 ConstString objc_selector_name(objc_method.GetSelector()); 261 ConstString objc_fullname_no_category_name( 262 objc_method.GetFullNameWithoutCategory(true)); 263 ConstString class_name_no_category(objc_method.GetClassName()); 264 set.function_fullnames.Insert(ConstString(name), ref); 265 if (class_name_with_category) 266 set.objc_class_selectors.Insert(class_name_with_category, ref); 267 if (class_name_no_category && 268 class_name_no_category != class_name_with_category) 269 set.objc_class_selectors.Insert(class_name_no_category, ref); 270 if (objc_selector_name) 271 set.function_selectors.Insert(objc_selector_name, ref); 272 if (objc_fullname_no_category_name) 273 set.function_fullnames.Insert(objc_fullname_no_category_name, 274 ref); 275 } 276 } 277 // If we have a mangled name, then the DW_AT_name attribute is 278 // usually the method name without the class or any parameters 279 bool is_method = DWARFDIE(&unit, &die).IsMethod(); 280 281 if (is_method) 282 set.function_methods.Insert(ConstString(name), ref); 283 else 284 set.function_basenames.Insert(ConstString(name), ref); 285 286 if (!is_method && !mangled_cstr && !is_objc_method) 287 set.function_fullnames.Insert(ConstString(name), ref); 288 } 289 if (mangled_cstr) { 290 // Make sure our mangled name isn't the same string table entry as 291 // our name. If it starts with '_', then it is ok, else compare the 292 // string to make sure it isn't the same and we don't end up with 293 // duplicate entries 294 if (name && name != mangled_cstr && 295 ((mangled_cstr[0] == '_') || 296 (::strcmp(name, mangled_cstr) != 0))) { 297 set.function_fullnames.Insert(ConstString(mangled_cstr), ref); 298 } 299 } 300 } 301 break; 302 303 case DW_TAG_array_type: 304 case DW_TAG_base_type: 305 case DW_TAG_class_type: 306 case DW_TAG_constant: 307 case DW_TAG_enumeration_type: 308 case DW_TAG_string_type: 309 case DW_TAG_structure_type: 310 case DW_TAG_subroutine_type: 311 case DW_TAG_typedef: 312 case DW_TAG_union_type: 313 case DW_TAG_unspecified_type: 314 if (name && !is_declaration) 315 set.types.Insert(ConstString(name), ref); 316 if (mangled_cstr && !is_declaration) 317 set.types.Insert(ConstString(mangled_cstr), ref); 318 break; 319 320 case DW_TAG_namespace: 321 if (name) 322 set.namespaces.Insert(ConstString(name), ref); 323 break; 324 325 case DW_TAG_variable: 326 if (name && has_location_or_const_value && is_global_or_static_variable) { 327 set.globals.Insert(ConstString(name), ref); 328 // Be sure to include variables by their mangled and demangled names if 329 // they have any since a variable can have a basename "i", a mangled 330 // named "_ZN12_GLOBAL__N_11iE" and a demangled mangled name 331 // "(anonymous namespace)::i"... 332 333 // Make sure our mangled name isn't the same string table entry as our 334 // name. If it starts with '_', then it is ok, else compare the string 335 // to make sure it isn't the same and we don't end up with duplicate 336 // entries 337 if (mangled_cstr && name != mangled_cstr && 338 ((mangled_cstr[0] == '_') || (::strcmp(name, mangled_cstr) != 0))) { 339 set.globals.Insert(ConstString(mangled_cstr), ref); 340 } 341 } 342 break; 343 344 default: 345 continue; 346 } 347 } 348 } 349 350 void ManualDWARFIndex::GetGlobalVariables(ConstString basename, DIEArray &offsets) { 351 Index(); 352 m_set.globals.Find(basename, offsets); 353 } 354 355 void ManualDWARFIndex::GetGlobalVariables(const RegularExpression ®ex, 356 DIEArray &offsets) { 357 Index(); 358 m_set.globals.Find(regex, offsets); 359 } 360 361 void ManualDWARFIndex::GetGlobalVariables(const DWARFUnit &unit, 362 DIEArray &offsets) { 363 Index(); 364 m_set.globals.FindAllEntriesForUnit(unit, offsets); 365 } 366 367 void ManualDWARFIndex::GetObjCMethods(ConstString class_name, 368 DIEArray &offsets) { 369 Index(); 370 m_set.objc_class_selectors.Find(class_name, offsets); 371 } 372 373 void ManualDWARFIndex::GetCompleteObjCClass(ConstString class_name, 374 bool must_be_implementation, 375 DIEArray &offsets) { 376 Index(); 377 m_set.types.Find(class_name, offsets); 378 } 379 380 void ManualDWARFIndex::GetTypes(ConstString name, DIEArray &offsets) { 381 Index(); 382 m_set.types.Find(name, offsets); 383 } 384 385 void ManualDWARFIndex::GetTypes(const DWARFDeclContext &context, 386 DIEArray &offsets) { 387 Index(); 388 m_set.types.Find(ConstString(context[0].name), offsets); 389 } 390 391 void ManualDWARFIndex::GetNamespaces(ConstString name, DIEArray &offsets) { 392 Index(); 393 m_set.namespaces.Find(name, offsets); 394 } 395 396 void ManualDWARFIndex::GetFunctions(ConstString name, SymbolFileDWARF &dwarf, 397 const CompilerDeclContext &parent_decl_ctx, 398 uint32_t name_type_mask, 399 std::vector<DWARFDIE> &dies) { 400 Index(); 401 402 if (name_type_mask & eFunctionNameTypeFull) { 403 DIEArray offsets; 404 m_set.function_fullnames.Find(name, offsets); 405 for (const DIERef &die_ref: offsets) { 406 DWARFDIE die = dwarf.GetDIE(die_ref); 407 if (!die) 408 continue; 409 if (!SymbolFileDWARF::DIEInDeclContext(parent_decl_ctx, die)) 410 continue; 411 dies.push_back(die); 412 } 413 } 414 if (name_type_mask & eFunctionNameTypeBase) { 415 DIEArray offsets; 416 m_set.function_basenames.Find(name, offsets); 417 for (const DIERef &die_ref: offsets) { 418 DWARFDIE die = dwarf.GetDIE(die_ref); 419 if (!die) 420 continue; 421 if (!SymbolFileDWARF::DIEInDeclContext(parent_decl_ctx, die)) 422 continue; 423 dies.push_back(die); 424 } 425 } 426 427 if (name_type_mask & eFunctionNameTypeMethod && !parent_decl_ctx.IsValid()) { 428 DIEArray offsets; 429 m_set.function_methods.Find(name, offsets); 430 for (const DIERef &die_ref: offsets) { 431 DWARFDIE die = dwarf.GetDIE(die_ref); 432 if (!die) 433 continue; 434 dies.push_back(die); 435 } 436 } 437 438 if (name_type_mask & eFunctionNameTypeSelector && 439 !parent_decl_ctx.IsValid()) { 440 DIEArray offsets; 441 m_set.function_selectors.Find(name, offsets); 442 for (const DIERef &die_ref: offsets) { 443 DWARFDIE die = dwarf.GetDIE(die_ref); 444 if (!die) 445 continue; 446 dies.push_back(die); 447 } 448 } 449 } 450 451 void ManualDWARFIndex::GetFunctions(const RegularExpression ®ex, 452 DIEArray &offsets) { 453 Index(); 454 455 m_set.function_basenames.Find(regex, offsets); 456 m_set.function_fullnames.Find(regex, offsets); 457 } 458 459 void ManualDWARFIndex::Dump(Stream &s) { 460 s.Format("Manual DWARF index for ({0}) '{1:F}':", 461 m_module.GetArchitecture().GetArchitectureName(), 462 m_module.GetObjectFile()->GetFileSpec()); 463 s.Printf("\nFunction basenames:\n"); 464 m_set.function_basenames.Dump(&s); 465 s.Printf("\nFunction fullnames:\n"); 466 m_set.function_fullnames.Dump(&s); 467 s.Printf("\nFunction methods:\n"); 468 m_set.function_methods.Dump(&s); 469 s.Printf("\nFunction selectors:\n"); 470 m_set.function_selectors.Dump(&s); 471 s.Printf("\nObjective-C class selectors:\n"); 472 m_set.objc_class_selectors.Dump(&s); 473 s.Printf("\nGlobals and statics:\n"); 474 m_set.globals.Dump(&s); 475 s.Printf("\nTypes:\n"); 476 m_set.types.Dump(&s); 477 s.Printf("\nNamespaces:\n"); 478 m_set.namespaces.Dump(&s); 479 } 480