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