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/DataFileCache.h" 16 #include "lldb/Core/Debugger.h" 17 #include "lldb/Core/Module.h" 18 #include "lldb/Core/Progress.h" 19 #include "lldb/Symbol/ObjectFile.h" 20 #include "lldb/Utility/DataEncoder.h" 21 #include "lldb/Utility/DataExtractor.h" 22 #include "lldb/Utility/Stream.h" 23 #include "lldb/Utility/Timer.h" 24 #include "llvm/Support/FormatVariadic.h" 25 #include "llvm/Support/ThreadPool.h" 26 #include <optional> 27 28 using namespace lldb_private; 29 using namespace lldb; 30 using namespace lldb_private::dwarf; 31 using namespace lldb_private::plugin::dwarf; 32 33 void ManualDWARFIndex::Index() { 34 if (m_indexed) 35 return; 36 m_indexed = true; 37 38 ElapsedTime elapsed(m_index_time); 39 LLDB_SCOPED_TIMERF("%p", static_cast<void *>(m_dwarf)); 40 if (LoadFromCache()) { 41 m_dwarf->SetDebugInfoIndexWasLoadedFromCache(); 42 return; 43 } 44 45 DWARFDebugInfo &main_info = m_dwarf->DebugInfo(); 46 SymbolFileDWARFDwo *dwp_dwarf = m_dwarf->GetDwpSymbolFile().get(); 47 DWARFDebugInfo *dwp_info = dwp_dwarf ? &dwp_dwarf->DebugInfo() : nullptr; 48 49 std::vector<DWARFUnit *> units_to_index; 50 units_to_index.reserve(main_info.GetNumUnits() + 51 (dwp_info ? dwp_info->GetNumUnits() : 0)); 52 53 // Process all units in the main file, as well as any type units in the dwp 54 // file. Type units in dwo files are handled when we reach the dwo file in 55 // IndexUnit. 56 for (size_t U = 0; U < main_info.GetNumUnits(); ++U) { 57 DWARFUnit *unit = main_info.GetUnitAtIndex(U); 58 if (unit && m_units_to_avoid.count(unit->GetOffset()) == 0) 59 units_to_index.push_back(unit); 60 } 61 if (dwp_info && dwp_info->ContainsTypeUnits()) { 62 for (size_t U = 0; U < dwp_info->GetNumUnits(); ++U) { 63 if (auto *tu = llvm::dyn_cast<DWARFTypeUnit>(dwp_info->GetUnitAtIndex(U))) 64 units_to_index.push_back(tu); 65 } 66 } 67 68 if (units_to_index.empty()) 69 return; 70 71 StreamString module_desc; 72 m_module.GetDescription(module_desc.AsRawOstream(), 73 lldb::eDescriptionLevelBrief); 74 75 // Include 2 passes per unit to index for extracting DIEs from the unit and 76 // indexing the unit, and then 8 extra entries for finalizing each index set. 77 const uint64_t total_progress = units_to_index.size() * 2 + 8; 78 Progress progress( 79 llvm::formatv("Manually indexing DWARF for {0}", module_desc.GetData()), 80 total_progress); 81 82 std::vector<IndexSet> sets(units_to_index.size()); 83 84 // Keep memory down by clearing DIEs for any units if indexing 85 // caused us to load the unit's DIEs. 86 std::vector<std::optional<DWARFUnit::ScopedExtractDIEs>> clear_cu_dies( 87 units_to_index.size()); 88 auto parser_fn = [&](size_t cu_idx) { 89 IndexUnit(*units_to_index[cu_idx], dwp_dwarf, sets[cu_idx]); 90 progress.Increment(); 91 }; 92 93 auto extract_fn = [&](size_t cu_idx) { 94 clear_cu_dies[cu_idx] = units_to_index[cu_idx]->ExtractDIEsScoped(); 95 progress.Increment(); 96 }; 97 98 // Share one thread pool across operations to avoid the overhead of 99 // recreating the threads. 100 llvm::ThreadPoolTaskGroup task_group(Debugger::GetThreadPool()); 101 102 // Create a task runner that extracts dies for each DWARF unit in a 103 // separate thread. 104 // First figure out which units didn't have their DIEs already 105 // parsed and remember this. If no DIEs were parsed prior to this index 106 // function call, we are going to want to clear the CU dies after we are 107 // done indexing to make sure we don't pull in all DWARF dies, but we need 108 // to wait until all units have been indexed in case a DIE in one 109 // unit refers to another and the indexes accesses those DIEs. 110 for (size_t i = 0; i < units_to_index.size(); ++i) 111 task_group.async(extract_fn, i); 112 task_group.wait(); 113 114 // Now create a task runner that can index each DWARF unit in a 115 // separate thread so we can index quickly. 116 for (size_t i = 0; i < units_to_index.size(); ++i) 117 task_group.async(parser_fn, i); 118 task_group.wait(); 119 120 auto finalize_fn = [this, &sets, &progress](NameToDIE(IndexSet::*index)) { 121 NameToDIE &result = m_set.*index; 122 for (auto &set : sets) 123 result.Append(set.*index); 124 result.Finalize(); 125 progress.Increment(); 126 }; 127 128 task_group.async(finalize_fn, &IndexSet::function_basenames); 129 task_group.async(finalize_fn, &IndexSet::function_fullnames); 130 task_group.async(finalize_fn, &IndexSet::function_methods); 131 task_group.async(finalize_fn, &IndexSet::function_selectors); 132 task_group.async(finalize_fn, &IndexSet::objc_class_selectors); 133 task_group.async(finalize_fn, &IndexSet::globals); 134 task_group.async(finalize_fn, &IndexSet::types); 135 task_group.async(finalize_fn, &IndexSet::namespaces); 136 task_group.wait(); 137 138 SaveToCache(); 139 } 140 141 void ManualDWARFIndex::IndexUnit(DWARFUnit &unit, SymbolFileDWARFDwo *dwp, 142 IndexSet &set) { 143 Log *log = GetLog(DWARFLog::Lookups); 144 145 if (log) { 146 m_module.LogMessage( 147 log, "ManualDWARFIndex::IndexUnit for unit at .debug_info[{0:x16}]", 148 unit.GetOffset()); 149 } 150 151 const LanguageType cu_language = SymbolFileDWARF::GetLanguage(unit); 152 153 // First check if the unit has a DWO ID. If it does then we only want to index 154 // the .dwo file or nothing at all. If we have a compile unit where we can't 155 // locate the .dwo/.dwp file we don't want to index anything from the skeleton 156 // compile unit because it is usally has no children unless 157 // -fsplit-dwarf-inlining was used at compile time. This option will add a 158 // copy of all DW_TAG_subprogram and any contained DW_TAG_inline_subroutine 159 // DIEs so that symbolication will still work in the absence of the .dwo/.dwp 160 // file, but the functions have no return types and all arguments and locals 161 // have been removed. So we don't want to index any of these hacked up 162 // function types. Types can still exist in the skeleton compile unit DWARF 163 // though as some functions have template parameter types and other things 164 // that cause extra copies of types to be included, but we should find these 165 // types in the .dwo file only as methods could have return types removed and 166 // we don't have to index incomplete types from the skeleton compile unit. 167 if (unit.GetDWOId()) { 168 // Index the .dwo or dwp instead of the skeleton unit. 169 if (SymbolFileDWARFDwo *dwo_symbol_file = unit.GetDwoSymbolFile()) { 170 // Type units in a dwp file are indexed separately, so we just need to 171 // process the split unit here. However, if the split unit is in a dwo 172 // file, then we need to process type units here. 173 if (dwo_symbol_file == dwp) { 174 IndexUnitImpl(unit.GetNonSkeletonUnit(), cu_language, set); 175 } else { 176 DWARFDebugInfo &dwo_info = dwo_symbol_file->DebugInfo(); 177 for (size_t i = 0; i < dwo_info.GetNumUnits(); ++i) 178 IndexUnitImpl(*dwo_info.GetUnitAtIndex(i), cu_language, set); 179 } 180 return; 181 } 182 // This was a DWARF5 skeleton CU and the .dwo file couldn't be located. 183 if (unit.GetVersion() >= 5 && unit.IsSkeletonUnit()) 184 return; 185 186 // Either this is a DWARF 4 + fission CU with the .dwo file 187 // missing, or it's a -gmodules pch or pcm. Try to detect the 188 // latter by checking whether the first DIE is a DW_TAG_module. 189 // If it's a pch/pcm, continue indexing it. 190 if (unit.GetDIE(unit.GetFirstDIEOffset()).GetFirstChild().Tag() != 191 llvm::dwarf::DW_TAG_module) 192 return; 193 } 194 // We have a normal compile unit which we want to index. 195 IndexUnitImpl(unit, cu_language, set); 196 } 197 198 void ManualDWARFIndex::IndexUnitImpl(DWARFUnit &unit, 199 const LanguageType cu_language, 200 IndexSet &set) { 201 for (const DWARFDebugInfoEntry &die : unit.dies()) { 202 const dw_tag_t tag = die.Tag(); 203 204 switch (tag) { 205 case DW_TAG_array_type: 206 case DW_TAG_base_type: 207 case DW_TAG_class_type: 208 case DW_TAG_constant: 209 case DW_TAG_enumeration_type: 210 case DW_TAG_inlined_subroutine: 211 case DW_TAG_namespace: 212 case DW_TAG_imported_declaration: 213 case DW_TAG_string_type: 214 case DW_TAG_structure_type: 215 case DW_TAG_subprogram: 216 case DW_TAG_subroutine_type: 217 case DW_TAG_typedef: 218 case DW_TAG_union_type: 219 case DW_TAG_unspecified_type: 220 case DW_TAG_variable: 221 break; 222 223 default: 224 continue; 225 } 226 227 const char *name = nullptr; 228 const char *mangled_cstr = nullptr; 229 bool is_declaration = false; 230 bool has_address = false; 231 bool has_location_or_const_value = false; 232 bool is_global_or_static_variable = false; 233 234 DWARFFormValue specification_die_form; 235 DWARFAttributes attributes = die.GetAttributes(&unit); 236 for (size_t i = 0; i < attributes.Size(); ++i) { 237 dw_attr_t attr = attributes.AttributeAtIndex(i); 238 DWARFFormValue form_value; 239 switch (attr) { 240 default: 241 break; 242 case DW_AT_name: 243 if (attributes.ExtractFormValueAtIndex(i, form_value)) 244 name = form_value.AsCString(); 245 break; 246 247 case DW_AT_declaration: 248 if (attributes.ExtractFormValueAtIndex(i, form_value)) 249 is_declaration = form_value.Unsigned() != 0; 250 break; 251 252 case DW_AT_MIPS_linkage_name: 253 case DW_AT_linkage_name: 254 if (attributes.ExtractFormValueAtIndex(i, form_value)) 255 mangled_cstr = form_value.AsCString(); 256 break; 257 258 case DW_AT_low_pc: 259 case DW_AT_high_pc: 260 case DW_AT_ranges: 261 has_address = true; 262 break; 263 264 case DW_AT_entry_pc: 265 has_address = true; 266 break; 267 268 case DW_AT_location: 269 case DW_AT_const_value: 270 has_location_or_const_value = true; 271 is_global_or_static_variable = die.IsGlobalOrStaticScopeVariable(); 272 273 break; 274 275 case DW_AT_specification: 276 if (attributes.ExtractFormValueAtIndex(i, form_value)) 277 specification_die_form = form_value; 278 break; 279 } 280 } 281 282 DIERef ref = *DWARFDIE(&unit, &die).GetDIERef(); 283 switch (tag) { 284 case DW_TAG_inlined_subroutine: 285 case DW_TAG_subprogram: 286 if (has_address) { 287 if (name) { 288 bool is_objc_method = false; 289 if (cu_language == eLanguageTypeObjC || 290 cu_language == eLanguageTypeObjC_plus_plus) { 291 std::optional<const ObjCLanguage::MethodName> objc_method = 292 ObjCLanguage::MethodName::Create(name, true); 293 if (objc_method) { 294 is_objc_method = true; 295 ConstString class_name_with_category( 296 objc_method->GetClassNameWithCategory()); 297 ConstString objc_selector_name(objc_method->GetSelector()); 298 ConstString objc_fullname_no_category_name( 299 objc_method->GetFullNameWithoutCategory().c_str()); 300 ConstString class_name_no_category(objc_method->GetClassName()); 301 set.function_fullnames.Insert(ConstString(name), ref); 302 if (class_name_with_category) 303 set.objc_class_selectors.Insert(class_name_with_category, ref); 304 if (class_name_no_category && 305 class_name_no_category != class_name_with_category) 306 set.objc_class_selectors.Insert(class_name_no_category, ref); 307 if (objc_selector_name) 308 set.function_selectors.Insert(objc_selector_name, ref); 309 if (objc_fullname_no_category_name) 310 set.function_fullnames.Insert(objc_fullname_no_category_name, 311 ref); 312 } 313 } 314 // If we have a mangled name, then the DW_AT_name attribute is 315 // usually the method name without the class or any parameters 316 bool is_method = DWARFDIE(&unit, &die).IsMethod(); 317 318 if (is_method) 319 set.function_methods.Insert(ConstString(name), ref); 320 else 321 set.function_basenames.Insert(ConstString(name), ref); 322 323 if (!is_method && !mangled_cstr && !is_objc_method) 324 set.function_fullnames.Insert(ConstString(name), ref); 325 } 326 if (mangled_cstr) { 327 // Make sure our mangled name isn't the same string table entry as 328 // our name. If it starts with '_', then it is ok, else compare the 329 // string to make sure it isn't the same and we don't end up with 330 // duplicate entries 331 if (name && name != mangled_cstr && 332 ((mangled_cstr[0] == '_') || 333 (::strcmp(name, mangled_cstr) != 0))) { 334 set.function_fullnames.Insert(ConstString(mangled_cstr), ref); 335 } 336 } 337 } 338 break; 339 340 case DW_TAG_array_type: 341 case DW_TAG_base_type: 342 case DW_TAG_class_type: 343 case DW_TAG_constant: 344 case DW_TAG_enumeration_type: 345 case DW_TAG_string_type: 346 case DW_TAG_structure_type: 347 case DW_TAG_subroutine_type: 348 case DW_TAG_typedef: 349 case DW_TAG_union_type: 350 case DW_TAG_unspecified_type: 351 if (name && !is_declaration) 352 set.types.Insert(ConstString(name), ref); 353 if (mangled_cstr && !is_declaration) 354 set.types.Insert(ConstString(mangled_cstr), ref); 355 break; 356 357 case DW_TAG_namespace: 358 case DW_TAG_imported_declaration: 359 if (name) 360 set.namespaces.Insert(ConstString(name), ref); 361 break; 362 363 case DW_TAG_variable: 364 if (name && has_location_or_const_value && is_global_or_static_variable) { 365 set.globals.Insert(ConstString(name), ref); 366 // Be sure to include variables by their mangled and demangled names if 367 // they have any since a variable can have a basename "i", a mangled 368 // named "_ZN12_GLOBAL__N_11iE" and a demangled mangled name 369 // "(anonymous namespace)::i"... 370 371 // Make sure our mangled name isn't the same string table entry as our 372 // name. If it starts with '_', then it is ok, else compare the string 373 // to make sure it isn't the same and we don't end up with duplicate 374 // entries 375 if (mangled_cstr && name != mangled_cstr && 376 ((mangled_cstr[0] == '_') || (::strcmp(name, mangled_cstr) != 0))) { 377 set.globals.Insert(ConstString(mangled_cstr), ref); 378 } 379 } 380 break; 381 382 default: 383 continue; 384 } 385 } 386 } 387 388 void ManualDWARFIndex::GetGlobalVariables( 389 ConstString basename, llvm::function_ref<bool(DWARFDIE die)> callback) { 390 Index(); 391 m_set.globals.Find(basename, 392 DIERefCallback(callback, basename.GetStringRef())); 393 } 394 395 void ManualDWARFIndex::GetGlobalVariables( 396 const RegularExpression ®ex, 397 llvm::function_ref<bool(DWARFDIE die)> callback) { 398 Index(); 399 m_set.globals.Find(regex, DIERefCallback(callback, regex.GetText())); 400 } 401 402 void ManualDWARFIndex::GetGlobalVariables( 403 DWARFUnit &unit, llvm::function_ref<bool(DWARFDIE die)> callback) { 404 Index(); 405 m_set.globals.FindAllEntriesForUnit(unit, DIERefCallback(callback)); 406 } 407 408 void ManualDWARFIndex::GetObjCMethods( 409 ConstString class_name, llvm::function_ref<bool(DWARFDIE die)> callback) { 410 Index(); 411 m_set.objc_class_selectors.Find( 412 class_name, DIERefCallback(callback, class_name.GetStringRef())); 413 } 414 415 void ManualDWARFIndex::GetCompleteObjCClass( 416 ConstString class_name, bool must_be_implementation, 417 llvm::function_ref<bool(DWARFDIE die)> callback) { 418 Index(); 419 m_set.types.Find(class_name, 420 DIERefCallback(callback, class_name.GetStringRef())); 421 } 422 423 void ManualDWARFIndex::GetTypes( 424 ConstString name, llvm::function_ref<bool(DWARFDIE die)> callback) { 425 Index(); 426 m_set.types.Find(name, DIERefCallback(callback, name.GetStringRef())); 427 } 428 429 void ManualDWARFIndex::GetTypes( 430 const DWARFDeclContext &context, 431 llvm::function_ref<bool(DWARFDIE die)> callback) { 432 Index(); 433 auto name = context[0].name; 434 m_set.types.Find(ConstString(name), 435 DIERefCallback(callback, llvm::StringRef(name))); 436 } 437 438 void ManualDWARFIndex::GetNamespaces( 439 ConstString name, llvm::function_ref<bool(DWARFDIE die)> callback) { 440 Index(); 441 m_set.namespaces.Find(name, DIERefCallback(callback, name.GetStringRef())); 442 } 443 444 void ManualDWARFIndex::GetFunctions( 445 const Module::LookupInfo &lookup_info, SymbolFileDWARF &dwarf, 446 const CompilerDeclContext &parent_decl_ctx, 447 llvm::function_ref<bool(DWARFDIE die)> callback) { 448 Index(); 449 ConstString name = lookup_info.GetLookupName(); 450 FunctionNameType name_type_mask = lookup_info.GetNameTypeMask(); 451 452 if (name_type_mask & eFunctionNameTypeFull) { 453 if (!m_set.function_fullnames.Find( 454 name, DIERefCallback( 455 [&](DWARFDIE die) { 456 if (!SymbolFileDWARF::DIEInDeclContext(parent_decl_ctx, 457 die)) 458 return true; 459 return callback(die); 460 }, 461 name.GetStringRef()))) 462 return; 463 } 464 if (name_type_mask & eFunctionNameTypeBase) { 465 if (!m_set.function_basenames.Find( 466 name, DIERefCallback( 467 [&](DWARFDIE die) { 468 if (!SymbolFileDWARF::DIEInDeclContext(parent_decl_ctx, 469 die)) 470 return true; 471 return callback(die); 472 }, 473 name.GetStringRef()))) 474 return; 475 } 476 477 if (name_type_mask & eFunctionNameTypeMethod && !parent_decl_ctx.IsValid()) { 478 if (!m_set.function_methods.Find( 479 name, DIERefCallback(callback, name.GetStringRef()))) 480 return; 481 } 482 483 if (name_type_mask & eFunctionNameTypeSelector && 484 !parent_decl_ctx.IsValid()) { 485 if (!m_set.function_selectors.Find( 486 name, DIERefCallback(callback, name.GetStringRef()))) 487 return; 488 } 489 } 490 491 void ManualDWARFIndex::GetFunctions( 492 const RegularExpression ®ex, 493 llvm::function_ref<bool(DWARFDIE die)> callback) { 494 Index(); 495 496 if (!m_set.function_basenames.Find(regex, 497 DIERefCallback(callback, regex.GetText()))) 498 return; 499 if (!m_set.function_fullnames.Find(regex, 500 DIERefCallback(callback, regex.GetText()))) 501 return; 502 } 503 504 void ManualDWARFIndex::Dump(Stream &s) { 505 s.Format("Manual DWARF index for ({0}) '{1:F}':", 506 m_module.GetArchitecture().GetArchitectureName(), 507 m_module.GetObjectFile()->GetFileSpec()); 508 s.Printf("\nFunction basenames:\n"); 509 m_set.function_basenames.Dump(&s); 510 s.Printf("\nFunction fullnames:\n"); 511 m_set.function_fullnames.Dump(&s); 512 s.Printf("\nFunction methods:\n"); 513 m_set.function_methods.Dump(&s); 514 s.Printf("\nFunction selectors:\n"); 515 m_set.function_selectors.Dump(&s); 516 s.Printf("\nObjective-C class selectors:\n"); 517 m_set.objc_class_selectors.Dump(&s); 518 s.Printf("\nGlobals and statics:\n"); 519 m_set.globals.Dump(&s); 520 s.Printf("\nTypes:\n"); 521 m_set.types.Dump(&s); 522 s.Printf("\nNamespaces:\n"); 523 m_set.namespaces.Dump(&s); 524 } 525 526 constexpr llvm::StringLiteral kIdentifierManualDWARFIndex("DIDX"); 527 // Define IDs for the different tables when encoding and decoding the 528 // ManualDWARFIndex NameToDIE objects so we can avoid saving any empty maps. 529 enum DataID { 530 kDataIDFunctionBasenames = 1u, 531 kDataIDFunctionFullnames, 532 kDataIDFunctionMethods, 533 kDataIDFunctionSelectors, 534 kDataIDFunctionObjcClassSelectors, 535 kDataIDGlobals, 536 kDataIDTypes, 537 kDataIDNamespaces, 538 kDataIDEnd = 255u, 539 540 }; 541 542 // Version 2 changes the encoding of DIERef objects used in the DWARF manual 543 // index name tables. See DIERef class for details. 544 constexpr uint32_t CURRENT_CACHE_VERSION = 2; 545 546 bool ManualDWARFIndex::IndexSet::Decode(const DataExtractor &data, 547 lldb::offset_t *offset_ptr) { 548 StringTableReader strtab; 549 // We now decode the string table for all strings in the data cache file. 550 if (!strtab.Decode(data, offset_ptr)) 551 return false; 552 553 llvm::StringRef identifier((const char *)data.GetData(offset_ptr, 4), 4); 554 if (identifier != kIdentifierManualDWARFIndex) 555 return false; 556 const uint32_t version = data.GetU32(offset_ptr); 557 if (version != CURRENT_CACHE_VERSION) 558 return false; 559 560 bool done = false; 561 while (!done) { 562 switch (data.GetU8(offset_ptr)) { 563 default: 564 // If we got here, this is not expected, we expect the data IDs to match 565 // one of the values from the DataID enumeration. 566 return false; 567 case kDataIDFunctionBasenames: 568 if (!function_basenames.Decode(data, offset_ptr, strtab)) 569 return false; 570 break; 571 case kDataIDFunctionFullnames: 572 if (!function_fullnames.Decode(data, offset_ptr, strtab)) 573 return false; 574 break; 575 case kDataIDFunctionMethods: 576 if (!function_methods.Decode(data, offset_ptr, strtab)) 577 return false; 578 break; 579 case kDataIDFunctionSelectors: 580 if (!function_selectors.Decode(data, offset_ptr, strtab)) 581 return false; 582 break; 583 case kDataIDFunctionObjcClassSelectors: 584 if (!objc_class_selectors.Decode(data, offset_ptr, strtab)) 585 return false; 586 break; 587 case kDataIDGlobals: 588 if (!globals.Decode(data, offset_ptr, strtab)) 589 return false; 590 break; 591 case kDataIDTypes: 592 if (!types.Decode(data, offset_ptr, strtab)) 593 return false; 594 break; 595 case kDataIDNamespaces: 596 if (!namespaces.Decode(data, offset_ptr, strtab)) 597 return false; 598 break; 599 case kDataIDEnd: 600 // We got to the end of our NameToDIE encodings. 601 done = true; 602 break; 603 } 604 } 605 // Success! 606 return true; 607 } 608 609 void ManualDWARFIndex::IndexSet::Encode(DataEncoder &encoder) const { 610 ConstStringTable strtab; 611 612 // Encoder the DWARF index into a separate encoder first. This allows us 613 // gather all of the strings we willl need in "strtab" as we will need to 614 // write the string table out before the symbol table. 615 DataEncoder index_encoder(encoder.GetByteOrder(), 616 encoder.GetAddressByteSize()); 617 618 index_encoder.AppendData(kIdentifierManualDWARFIndex); 619 // Encode the data version. 620 index_encoder.AppendU32(CURRENT_CACHE_VERSION); 621 622 if (!function_basenames.IsEmpty()) { 623 index_encoder.AppendU8(kDataIDFunctionBasenames); 624 function_basenames.Encode(index_encoder, strtab); 625 } 626 if (!function_fullnames.IsEmpty()) { 627 index_encoder.AppendU8(kDataIDFunctionFullnames); 628 function_fullnames.Encode(index_encoder, strtab); 629 } 630 if (!function_methods.IsEmpty()) { 631 index_encoder.AppendU8(kDataIDFunctionMethods); 632 function_methods.Encode(index_encoder, strtab); 633 } 634 if (!function_selectors.IsEmpty()) { 635 index_encoder.AppendU8(kDataIDFunctionSelectors); 636 function_selectors.Encode(index_encoder, strtab); 637 } 638 if (!objc_class_selectors.IsEmpty()) { 639 index_encoder.AppendU8(kDataIDFunctionObjcClassSelectors); 640 objc_class_selectors.Encode(index_encoder, strtab); 641 } 642 if (!globals.IsEmpty()) { 643 index_encoder.AppendU8(kDataIDGlobals); 644 globals.Encode(index_encoder, strtab); 645 } 646 if (!types.IsEmpty()) { 647 index_encoder.AppendU8(kDataIDTypes); 648 types.Encode(index_encoder, strtab); 649 } 650 if (!namespaces.IsEmpty()) { 651 index_encoder.AppendU8(kDataIDNamespaces); 652 namespaces.Encode(index_encoder, strtab); 653 } 654 index_encoder.AppendU8(kDataIDEnd); 655 656 // Now that all strings have been gathered, we will emit the string table. 657 strtab.Encode(encoder); 658 // Followed by the symbol table data. 659 encoder.AppendData(index_encoder.GetData()); 660 } 661 662 bool ManualDWARFIndex::Decode(const DataExtractor &data, 663 lldb::offset_t *offset_ptr, 664 bool &signature_mismatch) { 665 signature_mismatch = false; 666 CacheSignature signature; 667 if (!signature.Decode(data, offset_ptr)) 668 return false; 669 if (CacheSignature(m_dwarf->GetObjectFile()) != signature) { 670 signature_mismatch = true; 671 return false; 672 } 673 IndexSet set; 674 if (!set.Decode(data, offset_ptr)) 675 return false; 676 m_set = std::move(set); 677 return true; 678 } 679 680 bool ManualDWARFIndex::Encode(DataEncoder &encoder) const { 681 CacheSignature signature(m_dwarf->GetObjectFile()); 682 if (!signature.Encode(encoder)) 683 return false; 684 m_set.Encode(encoder); 685 return true; 686 } 687 688 std::string ManualDWARFIndex::GetCacheKey() { 689 std::string key; 690 llvm::raw_string_ostream strm(key); 691 // DWARF Index can come from different object files for the same module. A 692 // module can have one object file as the main executable and might have 693 // another object file in a separate symbol file, or we might have a .dwo file 694 // that claims its module is the main executable. 695 ObjectFile *objfile = m_dwarf->GetObjectFile(); 696 strm << objfile->GetModule()->GetCacheKey() << "-dwarf-index-" 697 << llvm::format_hex(objfile->GetCacheHash(), 10); 698 return strm.str(); 699 } 700 701 bool ManualDWARFIndex::LoadFromCache() { 702 DataFileCache *cache = Module::GetIndexCache(); 703 if (!cache) 704 return false; 705 ObjectFile *objfile = m_dwarf->GetObjectFile(); 706 if (!objfile) 707 return false; 708 std::unique_ptr<llvm::MemoryBuffer> mem_buffer_up = 709 cache->GetCachedData(GetCacheKey()); 710 if (!mem_buffer_up) 711 return false; 712 DataExtractor data(mem_buffer_up->getBufferStart(), 713 mem_buffer_up->getBufferSize(), 714 endian::InlHostByteOrder(), 715 objfile->GetAddressByteSize()); 716 bool signature_mismatch = false; 717 lldb::offset_t offset = 0; 718 const bool result = Decode(data, &offset, signature_mismatch); 719 if (signature_mismatch) 720 cache->RemoveCacheFile(GetCacheKey()); 721 return result; 722 } 723 724 void ManualDWARFIndex::SaveToCache() { 725 DataFileCache *cache = Module::GetIndexCache(); 726 if (!cache) 727 return; // Caching is not enabled. 728 ObjectFile *objfile = m_dwarf->GetObjectFile(); 729 if (!objfile) 730 return; 731 DataEncoder file(endian::InlHostByteOrder(), objfile->GetAddressByteSize()); 732 // Encode will return false if the object file doesn't have anything to make 733 // a signature from. 734 if (Encode(file)) { 735 if (cache->SetCachedData(GetCacheKey(), file.GetData())) 736 m_dwarf->SetDebugInfoIndexWasSavedToCache(); 737 } 738 } 739