1 //===-- ManualDWARFIndex.cpp -----------------------------------*- C++ -*-===// 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_debug_info) 26 return; 27 28 DWARFDebugInfo &debug_info = *m_debug_info; 29 m_debug_info = nullptr; 30 31 static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); 32 Timer scoped_timer(func_cat, "%p", static_cast<void *>(&debug_info)); 33 34 std::vector<DWARFUnit *> units_to_index; 35 units_to_index.reserve(debug_info.GetNumUnits()); 36 for (size_t U = 0; U < debug_info.GetNumUnits(); ++U) { 37 DWARFUnit *unit = debug_info.GetUnitAtIndex(U); 38 if (unit && m_units_to_avoid.count(unit->GetOffset()) == 0) 39 units_to_index.push_back(unit); 40 } 41 if (units_to_index.empty()) 42 return; 43 44 std::vector<IndexSet> sets(units_to_index.size()); 45 46 // Keep memory down by clearing DIEs for any units if indexing 47 // caused us to load the unit's DIEs. 48 std::vector<llvm::Optional<DWARFUnit::ScopedExtractDIEs>> clear_cu_dies( 49 units_to_index.size()); 50 auto parser_fn = [&](size_t cu_idx) { 51 IndexUnit(*units_to_index[cu_idx], sets[cu_idx]); 52 }; 53 54 auto extract_fn = [&units_to_index, &clear_cu_dies](size_t cu_idx) { 55 clear_cu_dies[cu_idx] = units_to_index[cu_idx]->ExtractDIEsScoped(); 56 }; 57 58 // Create a task runner that extracts dies for each DWARF unit in a 59 // separate thread 60 // First figure out which units didn't have their DIEs already 61 // parsed and remember this. If no DIEs were parsed prior to this index 62 // function call, we are going to want to clear the CU dies after we are 63 // done indexing to make sure we don't pull in all DWARF dies, but we need 64 // to wait until all units have been indexed in case a DIE in one 65 // unit refers to another and the indexes accesses those DIEs. 66 TaskMapOverInt(0, units_to_index.size(), extract_fn); 67 68 // Now create a task runner that can index each DWARF unit in a 69 // separate thread so we can index quickly. 70 71 TaskMapOverInt(0, units_to_index.size(), parser_fn); 72 73 auto finalize_fn = [this, &sets](NameToDIE(IndexSet::*index)) { 74 NameToDIE &result = m_set.*index; 75 for (auto &set : sets) 76 result.Append(set.*index); 77 result.Finalize(); 78 }; 79 80 TaskPool::RunTasks([&]() { finalize_fn(&IndexSet::function_basenames); }, 81 [&]() { finalize_fn(&IndexSet::function_fullnames); }, 82 [&]() { finalize_fn(&IndexSet::function_methods); }, 83 [&]() { finalize_fn(&IndexSet::function_selectors); }, 84 [&]() { finalize_fn(&IndexSet::objc_class_selectors); }, 85 [&]() { finalize_fn(&IndexSet::globals); }, 86 [&]() { finalize_fn(&IndexSet::types); }, 87 [&]() { finalize_fn(&IndexSet::namespaces); }); 88 } 89 90 void ManualDWARFIndex::IndexUnit(DWARFUnit &unit, IndexSet &set) { 91 assert( 92 !unit.GetSymbolFileDWARF().GetBaseCompileUnit() && 93 "DWARFUnit associated with .dwo or .dwp should not be indexed directly"); 94 95 Log *log = LogChannelDWARF::GetLogIfAll(DWARF_LOG_LOOKUPS); 96 97 if (log) { 98 m_module.LogMessage( 99 log, "ManualDWARFIndex::IndexUnit for unit at .debug_info[0x%8.8x]", 100 unit.GetOffset()); 101 } 102 103 const LanguageType cu_language = unit.GetLanguageType(); 104 105 IndexUnitImpl(unit, cu_language, set); 106 107 if (SymbolFileDWARFDwo *dwo_symbol_file = unit.GetDwoSymbolFile()) { 108 DWARFDebugInfo &dwo_info = *dwo_symbol_file->DebugInfo(); 109 for (size_t i = 0; i < dwo_info.GetNumUnits(); ++i) 110 IndexUnitImpl(*dwo_info.GetUnitAtIndex(i), cu_language, set); 111 } 112 } 113 114 void ManualDWARFIndex::IndexUnitImpl(DWARFUnit &unit, 115 const LanguageType cu_language, 116 IndexSet &set) { 117 for (const DWARFDebugInfoEntry &die : unit.dies()) { 118 const dw_tag_t tag = die.Tag(); 119 120 switch (tag) { 121 case DW_TAG_array_type: 122 case DW_TAG_base_type: 123 case DW_TAG_class_type: 124 case DW_TAG_constant: 125 case DW_TAG_enumeration_type: 126 case DW_TAG_inlined_subroutine: 127 case DW_TAG_namespace: 128 case DW_TAG_string_type: 129 case DW_TAG_structure_type: 130 case DW_TAG_subprogram: 131 case DW_TAG_subroutine_type: 132 case DW_TAG_typedef: 133 case DW_TAG_union_type: 134 case DW_TAG_unspecified_type: 135 case DW_TAG_variable: 136 break; 137 138 default: 139 continue; 140 } 141 142 DWARFAttributes attributes; 143 const char *name = nullptr; 144 const char *mangled_cstr = nullptr; 145 bool is_declaration = false; 146 // bool is_artificial = false; 147 bool has_address = false; 148 bool has_location_or_const_value = false; 149 bool is_global_or_static_variable = false; 150 151 DWARFFormValue specification_die_form; 152 const size_t num_attributes = die.GetAttributes(&unit, attributes); 153 if (num_attributes > 0) { 154 for (uint32_t i = 0; i < num_attributes; ++i) { 155 dw_attr_t attr = attributes.AttributeAtIndex(i); 156 DWARFFormValue form_value; 157 switch (attr) { 158 case DW_AT_name: 159 if (attributes.ExtractFormValueAtIndex(i, form_value)) 160 name = form_value.AsCString(); 161 break; 162 163 case DW_AT_declaration: 164 if (attributes.ExtractFormValueAtIndex(i, form_value)) 165 is_declaration = form_value.Unsigned() != 0; 166 break; 167 168 // case DW_AT_artificial: 169 // if (attributes.ExtractFormValueAtIndex(i, 170 // form_value)) 171 // is_artificial = form_value.Unsigned() != 0; 172 // break; 173 174 case DW_AT_MIPS_linkage_name: 175 case DW_AT_linkage_name: 176 if (attributes.ExtractFormValueAtIndex(i, form_value)) 177 mangled_cstr = form_value.AsCString(); 178 break; 179 180 case DW_AT_low_pc: 181 case DW_AT_high_pc: 182 case DW_AT_ranges: 183 has_address = true; 184 break; 185 186 case DW_AT_entry_pc: 187 has_address = true; 188 break; 189 190 case DW_AT_location: 191 case DW_AT_const_value: 192 has_location_or_const_value = true; 193 if (tag == DW_TAG_variable) { 194 const DWARFDebugInfoEntry *parent_die = die.GetParent(); 195 while (parent_die != nullptr) { 196 switch (parent_die->Tag()) { 197 case DW_TAG_subprogram: 198 case DW_TAG_lexical_block: 199 case DW_TAG_inlined_subroutine: 200 // Even if this is a function level static, we don't add it. We 201 // could theoretically add these if we wanted to by 202 // introspecting into the DW_AT_location and seeing if the 203 // location describes a hard coded address, but we don't want 204 // the performance penalty of that right now. 205 is_global_or_static_variable = false; 206 // if (attributes.ExtractFormValueAtIndex(dwarf, i, 207 // form_value)) { 208 // // If we have valid block data, then we have location 209 // // expression bytesthat are fixed (not a location list). 210 // const uint8_t *block_data = form_value.BlockData(); 211 // if (block_data) { 212 // uint32_t block_length = form_value.Unsigned(); 213 // if (block_length == 1 + 214 // attributes.UnitAtIndex(i)->GetAddressByteSize()) { 215 // if (block_data[0] == DW_OP_addr) 216 // add_die = true; 217 // } 218 // } 219 // } 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_basenames.Find(name, offsets); 405 m_set.function_methods.Find(name, offsets); 406 m_set.function_fullnames.Find(name, offsets); 407 for (const DIERef &die_ref: offsets) { 408 DWARFDIE die = dwarf.GetDIE(die_ref); 409 if (!die) 410 continue; 411 if (SymbolFileDWARF::DIEInDeclContext(&parent_decl_ctx, die)) 412 dies.push_back(die); 413 } 414 } 415 if (name_type_mask & eFunctionNameTypeBase) { 416 DIEArray offsets; 417 m_set.function_basenames.Find(name, offsets); 418 for (const DIERef &die_ref: offsets) { 419 DWARFDIE die = dwarf.GetDIE(die_ref); 420 if (!die) 421 continue; 422 if (SymbolFileDWARF::DIEInDeclContext(&parent_decl_ctx, die)) 423 dies.push_back(die); 424 } 425 offsets.clear(); 426 } 427 428 if (name_type_mask & eFunctionNameTypeMethod && !parent_decl_ctx.IsValid()) { 429 DIEArray offsets; 430 m_set.function_methods.Find(name, offsets); 431 for (const DIERef &die_ref: offsets) { 432 if (DWARFDIE die = dwarf.GetDIE(die_ref)) 433 dies.push_back(die); 434 } 435 } 436 437 if (name_type_mask & eFunctionNameTypeSelector && 438 !parent_decl_ctx.IsValid()) { 439 DIEArray offsets; 440 m_set.function_selectors.Find(name, offsets); 441 for (const DIERef &die_ref: offsets) { 442 if (DWARFDIE die = dwarf.GetDIE(die_ref)) 443 dies.push_back(die); 444 } 445 } 446 } 447 448 void ManualDWARFIndex::GetFunctions(const RegularExpression ®ex, 449 DIEArray &offsets) { 450 Index(); 451 452 m_set.function_basenames.Find(regex, offsets); 453 m_set.function_fullnames.Find(regex, offsets); 454 } 455 456 void ManualDWARFIndex::Dump(Stream &s) { 457 s.Format("Manual DWARF index for ({0}) '{1:F}':", 458 m_module.GetArchitecture().GetArchitectureName(), 459 m_module.GetObjectFile()->GetFileSpec()); 460 s.Printf("\nFunction basenames:\n"); 461 m_set.function_basenames.Dump(&s); 462 s.Printf("\nFunction fullnames:\n"); 463 m_set.function_fullnames.Dump(&s); 464 s.Printf("\nFunction methods:\n"); 465 m_set.function_methods.Dump(&s); 466 s.Printf("\nFunction selectors:\n"); 467 m_set.function_selectors.Dump(&s); 468 s.Printf("\nObjective-C class selectors:\n"); 469 m_set.objc_class_selectors.Dump(&s); 470 s.Printf("\nGlobals and statics:\n"); 471 m_set.globals.Dump(&s); 472 s.Printf("\nTypes:\n"); 473 m_set.types.Dump(&s); 474 s.Printf("\nNamespaces:\n"); 475 m_set.namespaces.Dump(&s); 476 } 477