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 skeletone compile unit. 166 if (unit.GetDWOId()) { 167 if (SymbolFileDWARFDwo *dwo_symbol_file = unit.GetDwoSymbolFile()) { 168 // Type units in a dwp file are indexed separately, so we just need to 169 // process the split unit here. However, if the split unit is in a dwo file, 170 // then we need to process type units here. 171 if (dwo_symbol_file == dwp) { 172 IndexUnitImpl(unit.GetNonSkeletonUnit(), cu_language, set); 173 } else { 174 DWARFDebugInfo &dwo_info = dwo_symbol_file->DebugInfo(); 175 for (size_t i = 0; i < dwo_info.GetNumUnits(); ++i) 176 IndexUnitImpl(*dwo_info.GetUnitAtIndex(i), cu_language, set); 177 } 178 } 179 } else { 180 // We either have a normal compile unit which we want to index. 181 IndexUnitImpl(unit, cu_language, set); 182 } 183 } 184 185 void ManualDWARFIndex::IndexUnitImpl(DWARFUnit &unit, 186 const LanguageType cu_language, 187 IndexSet &set) { 188 for (const DWARFDebugInfoEntry &die : unit.dies()) { 189 const dw_tag_t tag = die.Tag(); 190 191 switch (tag) { 192 case DW_TAG_array_type: 193 case DW_TAG_base_type: 194 case DW_TAG_class_type: 195 case DW_TAG_constant: 196 case DW_TAG_enumeration_type: 197 case DW_TAG_inlined_subroutine: 198 case DW_TAG_namespace: 199 case DW_TAG_string_type: 200 case DW_TAG_structure_type: 201 case DW_TAG_subprogram: 202 case DW_TAG_subroutine_type: 203 case DW_TAG_typedef: 204 case DW_TAG_union_type: 205 case DW_TAG_unspecified_type: 206 case DW_TAG_variable: 207 break; 208 209 default: 210 continue; 211 } 212 213 DWARFAttributes attributes; 214 const char *name = nullptr; 215 const char *mangled_cstr = nullptr; 216 bool is_declaration = false; 217 // bool is_artificial = false; 218 bool has_address = false; 219 bool has_location_or_const_value = false; 220 bool is_global_or_static_variable = false; 221 222 DWARFFormValue specification_die_form; 223 const size_t num_attributes = die.GetAttributes(&unit, attributes); 224 if (num_attributes > 0) { 225 for (uint32_t i = 0; i < num_attributes; ++i) { 226 dw_attr_t attr = attributes.AttributeAtIndex(i); 227 DWARFFormValue form_value; 228 switch (attr) { 229 case DW_AT_name: 230 if (attributes.ExtractFormValueAtIndex(i, form_value)) 231 name = form_value.AsCString(); 232 break; 233 234 case DW_AT_declaration: 235 if (attributes.ExtractFormValueAtIndex(i, form_value)) 236 is_declaration = form_value.Unsigned() != 0; 237 break; 238 239 case DW_AT_MIPS_linkage_name: 240 case DW_AT_linkage_name: 241 if (attributes.ExtractFormValueAtIndex(i, form_value)) 242 mangled_cstr = form_value.AsCString(); 243 break; 244 245 case DW_AT_low_pc: 246 case DW_AT_high_pc: 247 case DW_AT_ranges: 248 has_address = true; 249 break; 250 251 case DW_AT_entry_pc: 252 has_address = true; 253 break; 254 255 case DW_AT_location: 256 case DW_AT_const_value: 257 has_location_or_const_value = true; 258 is_global_or_static_variable = die.IsGlobalOrStaticScopeVariable(); 259 260 break; 261 262 case DW_AT_specification: 263 if (attributes.ExtractFormValueAtIndex(i, form_value)) 264 specification_die_form = form_value; 265 break; 266 } 267 } 268 } 269 270 DIERef ref = *DWARFDIE(&unit, &die).GetDIERef(); 271 switch (tag) { 272 case DW_TAG_inlined_subroutine: 273 case DW_TAG_subprogram: 274 if (has_address) { 275 if (name) { 276 bool is_objc_method = false; 277 if (cu_language == eLanguageTypeObjC || 278 cu_language == eLanguageTypeObjC_plus_plus) { 279 ObjCLanguage::MethodName objc_method(name, true); 280 if (objc_method.IsValid(true)) { 281 is_objc_method = true; 282 ConstString class_name_with_category( 283 objc_method.GetClassNameWithCategory()); 284 ConstString objc_selector_name(objc_method.GetSelector()); 285 ConstString objc_fullname_no_category_name( 286 objc_method.GetFullNameWithoutCategory(true)); 287 ConstString class_name_no_category(objc_method.GetClassName()); 288 set.function_fullnames.Insert(ConstString(name), ref); 289 if (class_name_with_category) 290 set.objc_class_selectors.Insert(class_name_with_category, ref); 291 if (class_name_no_category && 292 class_name_no_category != class_name_with_category) 293 set.objc_class_selectors.Insert(class_name_no_category, ref); 294 if (objc_selector_name) 295 set.function_selectors.Insert(objc_selector_name, ref); 296 if (objc_fullname_no_category_name) 297 set.function_fullnames.Insert(objc_fullname_no_category_name, 298 ref); 299 } 300 } 301 // If we have a mangled name, then the DW_AT_name attribute is 302 // usually the method name without the class or any parameters 303 bool is_method = DWARFDIE(&unit, &die).IsMethod(); 304 305 if (is_method) 306 set.function_methods.Insert(ConstString(name), ref); 307 else 308 set.function_basenames.Insert(ConstString(name), ref); 309 310 if (!is_method && !mangled_cstr && !is_objc_method) 311 set.function_fullnames.Insert(ConstString(name), ref); 312 } 313 if (mangled_cstr) { 314 // Make sure our mangled name isn't the same string table entry as 315 // our name. If it starts with '_', then it is ok, else compare the 316 // string to make sure it isn't the same and we don't end up with 317 // duplicate entries 318 if (name && name != mangled_cstr && 319 ((mangled_cstr[0] == '_') || 320 (::strcmp(name, mangled_cstr) != 0))) { 321 set.function_fullnames.Insert(ConstString(mangled_cstr), ref); 322 } 323 } 324 } 325 break; 326 327 case DW_TAG_array_type: 328 case DW_TAG_base_type: 329 case DW_TAG_class_type: 330 case DW_TAG_constant: 331 case DW_TAG_enumeration_type: 332 case DW_TAG_string_type: 333 case DW_TAG_structure_type: 334 case DW_TAG_subroutine_type: 335 case DW_TAG_typedef: 336 case DW_TAG_union_type: 337 case DW_TAG_unspecified_type: 338 if (name && !is_declaration) 339 set.types.Insert(ConstString(name), ref); 340 if (mangled_cstr && !is_declaration) 341 set.types.Insert(ConstString(mangled_cstr), ref); 342 break; 343 344 case DW_TAG_namespace: 345 if (name) 346 set.namespaces.Insert(ConstString(name), ref); 347 break; 348 349 case DW_TAG_variable: 350 if (name && has_location_or_const_value && is_global_or_static_variable) { 351 set.globals.Insert(ConstString(name), ref); 352 // Be sure to include variables by their mangled and demangled names if 353 // they have any since a variable can have a basename "i", a mangled 354 // named "_ZN12_GLOBAL__N_11iE" and a demangled mangled name 355 // "(anonymous namespace)::i"... 356 357 // Make sure our mangled name isn't the same string table entry as our 358 // name. If it starts with '_', then it is ok, else compare the string 359 // to make sure it isn't the same and we don't end up with duplicate 360 // entries 361 if (mangled_cstr && name != mangled_cstr && 362 ((mangled_cstr[0] == '_') || (::strcmp(name, mangled_cstr) != 0))) { 363 set.globals.Insert(ConstString(mangled_cstr), ref); 364 } 365 } 366 break; 367 368 default: 369 continue; 370 } 371 } 372 } 373 374 void ManualDWARFIndex::GetGlobalVariables( 375 ConstString basename, llvm::function_ref<bool(DWARFDIE die)> callback) { 376 Index(); 377 m_set.globals.Find(basename, 378 DIERefCallback(callback, basename.GetStringRef())); 379 } 380 381 void ManualDWARFIndex::GetGlobalVariables( 382 const RegularExpression ®ex, 383 llvm::function_ref<bool(DWARFDIE die)> callback) { 384 Index(); 385 m_set.globals.Find(regex, DIERefCallback(callback, regex.GetText())); 386 } 387 388 void ManualDWARFIndex::GetGlobalVariables( 389 DWARFUnit &unit, llvm::function_ref<bool(DWARFDIE die)> callback) { 390 lldbassert(!unit.GetSymbolFileDWARF().GetDwoNum()); 391 Index(); 392 m_set.globals.FindAllEntriesForUnit(unit, DIERefCallback(callback)); 393 } 394 395 void ManualDWARFIndex::GetObjCMethods( 396 ConstString class_name, llvm::function_ref<bool(DWARFDIE die)> callback) { 397 Index(); 398 m_set.objc_class_selectors.Find( 399 class_name, DIERefCallback(callback, class_name.GetStringRef())); 400 } 401 402 void ManualDWARFIndex::GetCompleteObjCClass( 403 ConstString class_name, bool must_be_implementation, 404 llvm::function_ref<bool(DWARFDIE die)> callback) { 405 Index(); 406 m_set.types.Find(class_name, 407 DIERefCallback(callback, class_name.GetStringRef())); 408 } 409 410 void ManualDWARFIndex::GetTypes( 411 ConstString name, llvm::function_ref<bool(DWARFDIE die)> callback) { 412 Index(); 413 m_set.types.Find(name, DIERefCallback(callback, name.GetStringRef())); 414 } 415 416 void ManualDWARFIndex::GetTypes( 417 const DWARFDeclContext &context, 418 llvm::function_ref<bool(DWARFDIE die)> callback) { 419 Index(); 420 auto name = context[0].name; 421 m_set.types.Find(ConstString(name), 422 DIERefCallback(callback, llvm::StringRef(name))); 423 } 424 425 void ManualDWARFIndex::GetNamespaces( 426 ConstString name, llvm::function_ref<bool(DWARFDIE die)> callback) { 427 Index(); 428 m_set.namespaces.Find(name, DIERefCallback(callback, name.GetStringRef())); 429 } 430 431 void ManualDWARFIndex::GetFunctions( 432 const Module::LookupInfo &lookup_info, SymbolFileDWARF &dwarf, 433 const CompilerDeclContext &parent_decl_ctx, 434 llvm::function_ref<bool(DWARFDIE die)> callback) { 435 Index(); 436 ConstString name = lookup_info.GetLookupName(); 437 FunctionNameType name_type_mask = lookup_info.GetNameTypeMask(); 438 439 if (name_type_mask & eFunctionNameTypeFull) { 440 if (!m_set.function_fullnames.Find( 441 name, DIERefCallback( 442 [&](DWARFDIE die) { 443 if (!SymbolFileDWARF::DIEInDeclContext(parent_decl_ctx, 444 die)) 445 return true; 446 return callback(die); 447 }, 448 name.GetStringRef()))) 449 return; 450 } 451 if (name_type_mask & eFunctionNameTypeBase) { 452 if (!m_set.function_basenames.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 464 if (name_type_mask & eFunctionNameTypeMethod && !parent_decl_ctx.IsValid()) { 465 if (!m_set.function_methods.Find( 466 name, DIERefCallback(callback, name.GetStringRef()))) 467 return; 468 } 469 470 if (name_type_mask & eFunctionNameTypeSelector && 471 !parent_decl_ctx.IsValid()) { 472 if (!m_set.function_selectors.Find( 473 name, DIERefCallback(callback, name.GetStringRef()))) 474 return; 475 } 476 } 477 478 void ManualDWARFIndex::GetFunctions( 479 const RegularExpression ®ex, 480 llvm::function_ref<bool(DWARFDIE die)> callback) { 481 Index(); 482 483 if (!m_set.function_basenames.Find(regex, 484 DIERefCallback(callback, regex.GetText()))) 485 return; 486 if (!m_set.function_fullnames.Find(regex, 487 DIERefCallback(callback, regex.GetText()))) 488 return; 489 } 490 491 void ManualDWARFIndex::Dump(Stream &s) { 492 s.Format("Manual DWARF index for ({0}) '{1:F}':", 493 m_module.GetArchitecture().GetArchitectureName(), 494 m_module.GetObjectFile()->GetFileSpec()); 495 s.Printf("\nFunction basenames:\n"); 496 m_set.function_basenames.Dump(&s); 497 s.Printf("\nFunction fullnames:\n"); 498 m_set.function_fullnames.Dump(&s); 499 s.Printf("\nFunction methods:\n"); 500 m_set.function_methods.Dump(&s); 501 s.Printf("\nFunction selectors:\n"); 502 m_set.function_selectors.Dump(&s); 503 s.Printf("\nObjective-C class selectors:\n"); 504 m_set.objc_class_selectors.Dump(&s); 505 s.Printf("\nGlobals and statics:\n"); 506 m_set.globals.Dump(&s); 507 s.Printf("\nTypes:\n"); 508 m_set.types.Dump(&s); 509 s.Printf("\nNamespaces:\n"); 510 m_set.namespaces.Dump(&s); 511 } 512 513 constexpr llvm::StringLiteral kIdentifierManualDWARFIndex("DIDX"); 514 // Define IDs for the different tables when encoding and decoding the 515 // ManualDWARFIndex NameToDIE objects so we can avoid saving any empty maps. 516 enum DataID { 517 kDataIDFunctionBasenames = 1u, 518 kDataIDFunctionFullnames, 519 kDataIDFunctionMethods, 520 kDataIDFunctionSelectors, 521 kDataIDFunctionObjcClassSelectors, 522 kDataIDGlobals, 523 kDataIDTypes, 524 kDataIDNamespaces, 525 kDataIDEnd = 255u, 526 527 }; 528 constexpr uint32_t CURRENT_CACHE_VERSION = 1; 529 530 bool ManualDWARFIndex::IndexSet::Decode(const DataExtractor &data, 531 lldb::offset_t *offset_ptr) { 532 StringTableReader strtab; 533 // We now decode the string table for all strings in the data cache file. 534 if (!strtab.Decode(data, offset_ptr)) 535 return false; 536 537 llvm::StringRef identifier((const char *)data.GetData(offset_ptr, 4), 4); 538 if (identifier != kIdentifierManualDWARFIndex) 539 return false; 540 const uint32_t version = data.GetU32(offset_ptr); 541 if (version != CURRENT_CACHE_VERSION) 542 return false; 543 544 bool done = false; 545 while (!done) { 546 switch (data.GetU8(offset_ptr)) { 547 default: 548 // If we got here, this is not expected, we expect the data IDs to match 549 // one of the values from the DataID enumeration. 550 return false; 551 case kDataIDFunctionBasenames: 552 if (!function_basenames.Decode(data, offset_ptr, strtab)) 553 return false; 554 break; 555 case kDataIDFunctionFullnames: 556 if (!function_fullnames.Decode(data, offset_ptr, strtab)) 557 return false; 558 break; 559 case kDataIDFunctionMethods: 560 if (!function_methods.Decode(data, offset_ptr, strtab)) 561 return false; 562 break; 563 case kDataIDFunctionSelectors: 564 if (!function_selectors.Decode(data, offset_ptr, strtab)) 565 return false; 566 break; 567 case kDataIDFunctionObjcClassSelectors: 568 if (!objc_class_selectors.Decode(data, offset_ptr, strtab)) 569 return false; 570 break; 571 case kDataIDGlobals: 572 if (!globals.Decode(data, offset_ptr, strtab)) 573 return false; 574 break; 575 case kDataIDTypes: 576 if (!types.Decode(data, offset_ptr, strtab)) 577 return false; 578 break; 579 case kDataIDNamespaces: 580 if (!namespaces.Decode(data, offset_ptr, strtab)) 581 return false; 582 break; 583 case kDataIDEnd: 584 // We got to the end of our NameToDIE encodings. 585 done = true; 586 break; 587 } 588 } 589 // Success! 590 return true; 591 } 592 593 void ManualDWARFIndex::IndexSet::Encode(DataEncoder &encoder) const { 594 ConstStringTable strtab; 595 596 // Encoder the DWARF index into a separate encoder first. This allows us 597 // gather all of the strings we willl need in "strtab" as we will need to 598 // write the string table out before the symbol table. 599 DataEncoder index_encoder(encoder.GetByteOrder(), 600 encoder.GetAddressByteSize()); 601 602 index_encoder.AppendData(kIdentifierManualDWARFIndex); 603 // Encode the data version. 604 index_encoder.AppendU32(CURRENT_CACHE_VERSION); 605 606 if (!function_basenames.IsEmpty()) { 607 index_encoder.AppendU8(kDataIDFunctionBasenames); 608 function_basenames.Encode(index_encoder, strtab); 609 } 610 if (!function_fullnames.IsEmpty()) { 611 index_encoder.AppendU8(kDataIDFunctionFullnames); 612 function_fullnames.Encode(index_encoder, strtab); 613 } 614 if (!function_methods.IsEmpty()) { 615 index_encoder.AppendU8(kDataIDFunctionMethods); 616 function_methods.Encode(index_encoder, strtab); 617 } 618 if (!function_selectors.IsEmpty()) { 619 index_encoder.AppendU8(kDataIDFunctionSelectors); 620 function_selectors.Encode(index_encoder, strtab); 621 } 622 if (!objc_class_selectors.IsEmpty()) { 623 index_encoder.AppendU8(kDataIDFunctionObjcClassSelectors); 624 objc_class_selectors.Encode(index_encoder, strtab); 625 } 626 if (!globals.IsEmpty()) { 627 index_encoder.AppendU8(kDataIDGlobals); 628 globals.Encode(index_encoder, strtab); 629 } 630 if (!types.IsEmpty()) { 631 index_encoder.AppendU8(kDataIDTypes); 632 types.Encode(index_encoder, strtab); 633 } 634 if (!namespaces.IsEmpty()) { 635 index_encoder.AppendU8(kDataIDNamespaces); 636 namespaces.Encode(index_encoder, strtab); 637 } 638 index_encoder.AppendU8(kDataIDEnd); 639 640 // Now that all strings have been gathered, we will emit the string table. 641 strtab.Encode(encoder); 642 // Followed the the symbol table data. 643 encoder.AppendData(index_encoder.GetData()); 644 } 645 646 bool ManualDWARFIndex::Decode(const DataExtractor &data, 647 lldb::offset_t *offset_ptr, 648 bool &signature_mismatch) { 649 signature_mismatch = false; 650 CacheSignature signature; 651 if (!signature.Decode(data, offset_ptr)) 652 return false; 653 if (CacheSignature(m_dwarf->GetObjectFile()) != signature) { 654 signature_mismatch = true; 655 return false; 656 } 657 IndexSet set; 658 if (!set.Decode(data, offset_ptr)) 659 return false; 660 m_set = std::move(set); 661 return true; 662 } 663 664 bool ManualDWARFIndex::Encode(DataEncoder &encoder) const { 665 CacheSignature signature(m_dwarf->GetObjectFile()); 666 if (!signature.Encode(encoder)) 667 return false; 668 m_set.Encode(encoder); 669 return true; 670 } 671 672 std::string ManualDWARFIndex::GetCacheKey() { 673 std::string key; 674 llvm::raw_string_ostream strm(key); 675 // DWARF Index can come from different object files for the same module. A 676 // module can have one object file as the main executable and might have 677 // another object file in a separate symbol file, or we might have a .dwo file 678 // that claims its module is the main executable. 679 ObjectFile *objfile = m_dwarf->GetObjectFile(); 680 strm << objfile->GetModule()->GetCacheKey() << "-dwarf-index-" 681 << llvm::format_hex(objfile->GetCacheHash(), 10); 682 return strm.str(); 683 } 684 685 bool ManualDWARFIndex::LoadFromCache() { 686 DataFileCache *cache = Module::GetIndexCache(); 687 if (!cache) 688 return false; 689 ObjectFile *objfile = m_dwarf->GetObjectFile(); 690 if (!objfile) 691 return false; 692 std::unique_ptr<llvm::MemoryBuffer> mem_buffer_up = 693 cache->GetCachedData(GetCacheKey()); 694 if (!mem_buffer_up) 695 return false; 696 DataExtractor data(mem_buffer_up->getBufferStart(), 697 mem_buffer_up->getBufferSize(), 698 endian::InlHostByteOrder(), 699 objfile->GetAddressByteSize()); 700 bool signature_mismatch = false; 701 lldb::offset_t offset = 0; 702 const bool result = Decode(data, &offset, signature_mismatch); 703 if (signature_mismatch) 704 cache->RemoveCacheFile(GetCacheKey()); 705 return result; 706 } 707 708 void ManualDWARFIndex::SaveToCache() { 709 DataFileCache *cache = Module::GetIndexCache(); 710 if (!cache) 711 return; // Caching is not enabled. 712 ObjectFile *objfile = m_dwarf->GetObjectFile(); 713 if (!objfile) 714 return; 715 DataEncoder file(endian::InlHostByteOrder(), objfile->GetAddressByteSize()); 716 // Encode will return false if the object file doesn't have anything to make 717 // a signature from. 718 if (Encode(file)) { 719 if (cache->SetCachedData(GetCacheKey(), file.GetData())) 720 m_dwarf->SetDebugInfoIndexWasSavedToCache(); 721 } 722 } 723