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