657 lines · cpp
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-exception6//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 "lldb/lldb-private-enumerations.h"25#include "llvm/Support/ThreadPool.h"26#include <atomic>27#include <optional>28 29using namespace lldb_private;30using namespace lldb;31using namespace lldb_private::plugin::dwarf;32using namespace llvm::dwarf;33 34void ManualDWARFIndex::Index() {35 std::call_once(m_indexed_flag, [this]() { IndexImpl(); });36}37 38void ManualDWARFIndex::IndexImpl() {39 ElapsedTime elapsed(m_index_time);40 LLDB_SCOPED_TIMERF("%p", static_cast<void *>(m_dwarf));41 if (LoadFromCache()) {42 m_dwarf->SetDebugInfoIndexWasLoadedFromCache();43 return;44 }45 46 DWARFDebugInfo &main_info = m_dwarf->DebugInfo();47 SymbolFileDWARFDwo *dwp_dwarf = m_dwarf->GetDwpSymbolFile().get();48 DWARFDebugInfo *dwp_info = dwp_dwarf ? &dwp_dwarf->DebugInfo() : nullptr;49 50 std::vector<DWARFUnit *> units_to_index;51 units_to_index.reserve(main_info.GetNumUnits() +52 (dwp_info ? dwp_info->GetNumUnits() : 0));53 54 // Process all units in the main file, as well as any type units in the dwp55 // file. Type units in dwo files are handled when we reach the dwo file in56 // IndexUnit.57 for (size_t U = 0; U < main_info.GetNumUnits(); ++U) {58 DWARFUnit *unit = main_info.GetUnitAtIndex(U);59 if (unit && m_units_to_avoid.count(unit->GetOffset()) == 0)60 units_to_index.push_back(unit);61 }62 if (dwp_info && dwp_info->ContainsTypeUnits()) {63 for (size_t U = 0; U < dwp_info->GetNumUnits(); ++U) {64 if (auto *tu =65 llvm::dyn_cast<DWARFTypeUnit>(dwp_info->GetUnitAtIndex(U))) {66 if (!m_type_sigs_to_avoid.contains(tu->GetTypeHash()))67 units_to_index.push_back(tu);68 }69 }70 }71 72 if (units_to_index.empty())73 return;74 75 StreamString module_desc;76 m_module.GetDescription(module_desc.AsRawOstream(),77 lldb::eDescriptionLevelBrief);78 79 // Include 2 passes per unit to index for extracting DIEs from the unit and80 // indexing the unit, and then extra entries for finalizing each index in the81 // set.82 const auto indices = IndexSet<NameToDIE>::Indices();83 const uint64_t total_progress = units_to_index.size() * 2 + indices.size();84 Progress progress("Manually indexing DWARF", module_desc.GetData(),85 total_progress, /*debugger=*/nullptr,86 Progress::kDefaultHighFrequencyReportTime);87 88 // Share one thread pool across operations to avoid the overhead of89 // recreating the threads.90 llvm::ThreadPoolTaskGroup task_group(Debugger::GetThreadPool());91 const size_t num_threads = Debugger::GetThreadPool().getMaxConcurrency();92 93 // Run a function for each compile unit in parallel using as many threads as94 // are available. This is significantly faster than submiting a new task for95 // each unit.96 auto for_each_unit = [&](auto &&fn) {97 std::atomic<size_t> next_cu_idx = 0;98 auto wrapper = [&fn, &next_cu_idx, &units_to_index,99 &progress](size_t worker_id) {100 size_t cu_idx;101 while ((cu_idx = next_cu_idx.fetch_add(1, std::memory_order_relaxed)) <102 units_to_index.size()) {103 fn(worker_id, cu_idx, units_to_index[cu_idx]);104 progress.Increment();105 }106 };107 108 for (size_t i = 0; i < num_threads; ++i)109 task_group.async(wrapper, i);110 111 task_group.wait();112 };113 114 // Extract dies for all DWARFs unit in parallel. Figure out which units115 // didn't have their DIEs already parsed and remember this. If no DIEs were116 // parsed prior to this index function call, we are going to want to clear the117 // CU dies after we are done indexing to make sure we don't pull in all DWARF118 // dies, but we need to wait until all units have been indexed in case a DIE119 // in one unit refers to another and the indexes accesses those DIEs.120 std::vector<std::optional<DWARFUnit::ScopedExtractDIEs>> clear_cu_dies(121 units_to_index.size());122 for_each_unit([&clear_cu_dies](size_t, size_t idx, DWARFUnit *unit) {123 clear_cu_dies[idx] = unit->ExtractDIEsScoped();124 });125 126 // Now index all DWARF unit in parallel.127 std::vector<IndexSet<NameToDIE>> sets(num_threads);128 for_each_unit(129 [this, dwp_dwarf, &sets](size_t worker_id, size_t, DWARFUnit *unit) {130 IndexUnit(*unit, dwp_dwarf, sets[worker_id]);131 });132 133 // Merge partial indexes into a single index. Process each index in a set in134 // parallel.135 for (NameToDIE IndexSet<NameToDIE>::*index : indices) {136 task_group.async([this, &sets, index, &progress]() {137 NameToDIE &result = m_set.*index;138 for (auto &set : sets)139 result.Append(set.*index);140 result.Finalize();141 progress.Increment();142 });143 }144 task_group.wait();145 146 SaveToCache();147}148 149void ManualDWARFIndex::IndexUnit(DWARFUnit &unit, SymbolFileDWARFDwo *dwp,150 IndexSet<NameToDIE> &set) {151 Log *log = GetLog(DWARFLog::Lookups);152 153 if (log) {154 m_module.LogMessage(155 log, "ManualDWARFIndex::IndexUnit for unit at .debug_info[{0:x16}]",156 unit.GetOffset());157 }158 159 const LanguageType cu_language = SymbolFileDWARF::GetLanguage(unit);160 161 // First check if the unit has a DWO ID. If it does then we only want to index162 // the .dwo file or nothing at all. If we have a compile unit where we can't163 // locate the .dwo/.dwp file we don't want to index anything from the skeleton164 // compile unit because it is usally has no children unless165 // -fsplit-dwarf-inlining was used at compile time. This option will add a166 // copy of all DW_TAG_subprogram and any contained DW_TAG_inline_subroutine167 // DIEs so that symbolication will still work in the absence of the .dwo/.dwp168 // file, but the functions have no return types and all arguments and locals169 // have been removed. So we don't want to index any of these hacked up170 // function types. Types can still exist in the skeleton compile unit DWARF171 // though as some functions have template parameter types and other things172 // that cause extra copies of types to be included, but we should find these173 // types in the .dwo file only as methods could have return types removed and174 // we don't have to index incomplete types from the skeleton compile unit.175 if (unit.GetDWOId()) {176 // Index the .dwo or dwp instead of the skeleton unit.177 if (SymbolFileDWARFDwo *dwo_symbol_file = unit.GetDwoSymbolFile()) {178 // Type units in a dwp file are indexed separately, so we just need to179 // process the split unit here. However, if the split unit is in a dwo180 // file, then we need to process type units here.181 if (dwo_symbol_file == dwp) {182 IndexUnitImpl(unit.GetNonSkeletonUnit(), cu_language, set);183 } else {184 DWARFDebugInfo &dwo_info = dwo_symbol_file->DebugInfo();185 for (size_t i = 0; i < dwo_info.GetNumUnits(); ++i)186 IndexUnitImpl(*dwo_info.GetUnitAtIndex(i), cu_language, set);187 }188 return;189 }190 // This was a DWARF5 skeleton CU and the .dwo file couldn't be located.191 if (unit.GetVersion() >= 5 && unit.IsSkeletonUnit())192 return;193 194 // Either this is a DWARF 4 + fission CU with the .dwo file195 // missing, or it's a -gmodules pch or pcm. Try to detect the196 // latter by checking whether the first DIE is a DW_TAG_module.197 // If it's a pch/pcm, continue indexing it.198 if (unit.GetDIE(unit.GetFirstDIEOffset()).GetFirstChild().Tag() !=199 llvm::dwarf::DW_TAG_module)200 return;201 }202 // We have a normal compile unit which we want to index.203 IndexUnitImpl(unit, cu_language, set);204}205 206void ManualDWARFIndex::IndexUnitImpl(DWARFUnit &unit,207 const LanguageType cu_language,208 IndexSet<NameToDIE> &set) {209 for (const DWARFDebugInfoEntry &die : unit.dies()) {210 const dw_tag_t tag = die.Tag();211 212 switch (tag) {213 case DW_TAG_array_type:214 case DW_TAG_base_type:215 case DW_TAG_class_type:216 case DW_TAG_constant:217 case DW_TAG_enumeration_type:218 case DW_TAG_inlined_subroutine:219 case DW_TAG_namespace:220 case DW_TAG_imported_declaration:221 case DW_TAG_string_type:222 case DW_TAG_structure_type:223 case DW_TAG_subprogram:224 case DW_TAG_subroutine_type:225 case DW_TAG_typedef:226 case DW_TAG_union_type:227 case DW_TAG_unspecified_type:228 case DW_TAG_variable:229 break;230 231 case DW_TAG_member:232 // Only in DWARF 4 and earlier `static const` members of a struct, a class233 // or a union have an entry tag `DW_TAG_member`234 if (unit.GetVersion() >= 5)235 continue;236 break;237 238 default:239 continue;240 }241 242 const char *name = nullptr;243 const char *mangled_cstr = nullptr;244 bool is_declaration = false;245 bool has_address = false;246 bool has_location_or_const_value = false;247 bool is_global_or_static_variable = false;248 249 DWARFFormValue specification_die_form;250 DWARFAttributes attributes = die.GetAttributes(&unit);251 for (size_t i = 0; i < attributes.Size(); ++i) {252 dw_attr_t attr = attributes.AttributeAtIndex(i);253 DWARFFormValue form_value;254 switch (attr) {255 default:256 break;257 case DW_AT_name:258 if (attributes.ExtractFormValueAtIndex(i, form_value))259 name = form_value.AsCString();260 break;261 262 case DW_AT_declaration:263 if (attributes.ExtractFormValueAtIndex(i, form_value))264 is_declaration = form_value.Unsigned() != 0;265 break;266 267 case DW_AT_MIPS_linkage_name:268 case DW_AT_linkage_name:269 if (attributes.ExtractFormValueAtIndex(i, form_value))270 mangled_cstr = form_value.AsCString();271 break;272 273 case DW_AT_low_pc:274 case DW_AT_high_pc:275 case DW_AT_ranges:276 has_address = true;277 break;278 279 case DW_AT_entry_pc:280 has_address = true;281 break;282 283 case DW_AT_location:284 case DW_AT_const_value:285 has_location_or_const_value = true;286 is_global_or_static_variable = die.IsGlobalOrStaticScopeVariable();287 288 break;289 290 case DW_AT_specification:291 if (attributes.ExtractFormValueAtIndex(i, form_value))292 specification_die_form = form_value;293 break;294 }295 }296 297 DIERef ref = *DWARFDIE(&unit, &die).GetDIERef();298 switch (tag) {299 case DW_TAG_inlined_subroutine:300 case DW_TAG_subprogram:301 if (has_address) {302 if (name) {303 bool is_objc_method = false;304 if (cu_language == eLanguageTypeObjC ||305 cu_language == eLanguageTypeObjC_plus_plus) {306 std::optional<const ObjCLanguage::ObjCMethodName> objc_method =307 ObjCLanguage::ObjCMethodName::Create(name, true);308 if (objc_method) {309 is_objc_method = true;310 ConstString class_name_with_category(311 objc_method->GetClassNameWithCategory());312 ConstString objc_selector_name(objc_method->GetSelector());313 ConstString objc_fullname_no_category_name(314 objc_method->GetFullNameWithoutCategory().c_str());315 ConstString class_name_no_category(objc_method->GetClassName());316 set.function_fullnames.Insert(ConstString(name), ref);317 if (class_name_with_category)318 set.objc_class_selectors.Insert(class_name_with_category, ref);319 if (class_name_no_category &&320 class_name_no_category != class_name_with_category)321 set.objc_class_selectors.Insert(class_name_no_category, ref);322 if (objc_selector_name)323 set.function_selectors.Insert(objc_selector_name, ref);324 if (objc_fullname_no_category_name)325 set.function_fullnames.Insert(objc_fullname_no_category_name,326 ref);327 }328 }329 // If we have a mangled name, then the DW_AT_name attribute is330 // usually the method name without the class or any parameters331 bool is_method = DWARFDIE(&unit, &die).IsMethod();332 333 if (is_method)334 set.function_methods.Insert(ConstString(name), ref);335 else336 set.function_basenames.Insert(ConstString(name), ref);337 338 if (!is_method && !mangled_cstr && !is_objc_method)339 set.function_fullnames.Insert(ConstString(name), ref);340 }341 if (mangled_cstr) {342 // Make sure our mangled name isn't the same string table entry as343 // our name. If it starts with '_', then it is ok, else compare the344 // string to make sure it isn't the same and we don't end up with345 // duplicate entries346 if (name && name != mangled_cstr &&347 ((mangled_cstr[0] == '_') ||348 (::strcmp(name, mangled_cstr) != 0))) {349 set.function_fullnames.Insert(ConstString(mangled_cstr), ref);350 }351 }352 }353 break;354 355 case DW_TAG_array_type:356 case DW_TAG_base_type:357 case DW_TAG_class_type:358 case DW_TAG_constant:359 case DW_TAG_enumeration_type:360 case DW_TAG_string_type:361 case DW_TAG_structure_type:362 case DW_TAG_subroutine_type:363 case DW_TAG_typedef:364 case DW_TAG_union_type:365 case DW_TAG_unspecified_type:366 if (name && !is_declaration)367 set.types.Insert(ConstString(name), ref);368 if (mangled_cstr && !is_declaration)369 set.types.Insert(ConstString(mangled_cstr), ref);370 break;371 372 case DW_TAG_namespace:373 case DW_TAG_imported_declaration:374 if (name)375 set.namespaces.Insert(ConstString(name), ref);376 break;377 378 case DW_TAG_member: {379 // In DWARF 4 and earlier `static const` members of a struct, a class or a380 // union have an entry tag `DW_TAG_member`, and are also tagged as381 // `DW_AT_declaration`, but otherwise follow the same rules as382 // `DW_TAG_variable`.383 bool parent_is_class_type = false;384 if (auto parent = die.GetParent())385 parent_is_class_type = DWARFDIE(&unit, parent).IsStructUnionOrClass();386 if (!parent_is_class_type || !is_declaration)387 break;388 [[fallthrough]];389 }390 case DW_TAG_variable:391 if (name && has_location_or_const_value && is_global_or_static_variable) {392 set.globals.Insert(ConstString(name), ref);393 // Be sure to include variables by their mangled and demangled names if394 // they have any since a variable can have a basename "i", a mangled395 // named "_ZN12_GLOBAL__N_11iE" and a demangled mangled name396 // "(anonymous namespace)::i"...397 398 // Make sure our mangled name isn't the same string table entry as our399 // name. If it starts with '_', then it is ok, else compare the string400 // to make sure it isn't the same and we don't end up with duplicate401 // entries402 if (mangled_cstr && name != mangled_cstr &&403 ((mangled_cstr[0] == '_') || (::strcmp(name, mangled_cstr) != 0))) {404 set.globals.Insert(ConstString(mangled_cstr), ref);405 }406 }407 break;408 409 default:410 continue;411 }412 }413}414 415void ManualDWARFIndex::GetGlobalVariables(416 ConstString basename,417 llvm::function_ref<IterationAction(DWARFDIE die)> callback) {418 Index();419 m_set.globals.Find(basename,420 DIERefCallback(callback, basename.GetStringRef()));421}422 423void ManualDWARFIndex::GetGlobalVariables(424 const RegularExpression ®ex,425 llvm::function_ref<IterationAction(DWARFDIE die)> callback) {426 Index();427 m_set.globals.Find(regex, DIERefCallback(callback, regex.GetText()));428}429 430void ManualDWARFIndex::GetGlobalVariables(431 DWARFUnit &unit,432 llvm::function_ref<IterationAction(DWARFDIE die)> callback) {433 Index();434 m_set.globals.FindAllEntriesForUnit(unit, DIERefCallback(callback));435}436 437void ManualDWARFIndex::GetObjCMethods(438 ConstString class_name,439 llvm::function_ref<IterationAction(DWARFDIE die)> callback) {440 Index();441 m_set.objc_class_selectors.Find(442 class_name, DIERefCallback(callback, class_name.GetStringRef()));443}444 445void ManualDWARFIndex::GetCompleteObjCClass(446 ConstString class_name, bool must_be_implementation,447 llvm::function_ref<IterationAction(DWARFDIE die)> callback) {448 Index();449 m_set.types.Find(class_name,450 DIERefCallback(callback, class_name.GetStringRef()));451}452 453void ManualDWARFIndex::GetTypes(454 ConstString name,455 llvm::function_ref<IterationAction(DWARFDIE die)> callback) {456 Index();457 m_set.types.Find(name, DIERefCallback(callback, name.GetStringRef()));458}459 460void ManualDWARFIndex::GetTypes(461 const DWARFDeclContext &context,462 llvm::function_ref<IterationAction(DWARFDIE die)> callback) {463 Index();464 auto name = context[0].name;465 m_set.types.Find(ConstString(name),466 DIERefCallback(callback, llvm::StringRef(name)));467}468 469void ManualDWARFIndex::GetNamespaces(470 ConstString name,471 llvm::function_ref<IterationAction(DWARFDIE die)> callback) {472 Index();473 m_set.namespaces.Find(name, DIERefCallback(callback, name.GetStringRef()));474}475 476void ManualDWARFIndex::GetFunctions(477 const Module::LookupInfo &lookup_info, SymbolFileDWARF &dwarf,478 const CompilerDeclContext &parent_decl_ctx,479 llvm::function_ref<IterationAction(DWARFDIE die)> callback) {480 Index();481 ConstString name = lookup_info.GetLookupName();482 FunctionNameType name_type_mask = lookup_info.GetNameTypeMask();483 484 if (name_type_mask & eFunctionNameTypeFull) {485 if (!m_set.function_fullnames.Find(486 name, DIERefCallback(487 [&](DWARFDIE die) {488 if (!SymbolFileDWARF::DIEInDeclContext(parent_decl_ctx,489 die))490 return IterationAction::Continue;491 return callback(die);492 },493 name.GetStringRef())))494 return;495 }496 if (name_type_mask & eFunctionNameTypeBase) {497 if (!m_set.function_basenames.Find(498 name, DIERefCallback(499 [&](DWARFDIE die) {500 if (!SymbolFileDWARF::DIEInDeclContext(parent_decl_ctx,501 die))502 return IterationAction::Continue;503 return callback(die);504 },505 name.GetStringRef())))506 return;507 }508 509 if (name_type_mask & eFunctionNameTypeMethod && !parent_decl_ctx.IsValid()) {510 if (!m_set.function_methods.Find(511 name, DIERefCallback(callback, name.GetStringRef())))512 return;513 }514 515 if (name_type_mask & eFunctionNameTypeSelector &&516 !parent_decl_ctx.IsValid()) {517 if (!m_set.function_selectors.Find(518 name, DIERefCallback(callback, name.GetStringRef())))519 return;520 }521}522 523void ManualDWARFIndex::GetFunctions(524 const RegularExpression ®ex,525 llvm::function_ref<IterationAction(DWARFDIE die)> callback) {526 Index();527 528 if (!m_set.function_basenames.Find(regex,529 DIERefCallback(callback, regex.GetText())))530 return;531 if (!m_set.function_fullnames.Find(regex,532 DIERefCallback(callback, regex.GetText())))533 return;534}535 536void ManualDWARFIndex::Dump(Stream &s) {537 s.Format("Manual DWARF index for ({0}) '{1:F}':",538 m_module.GetArchitecture().GetArchitectureName(),539 m_module.GetObjectFile()->GetFileSpec());540 s.Printf("\nFunction basenames:\n");541 m_set.function_basenames.Dump(&s);542 s.Printf("\nFunction fullnames:\n");543 m_set.function_fullnames.Dump(&s);544 s.Printf("\nFunction methods:\n");545 m_set.function_methods.Dump(&s);546 s.Printf("\nFunction selectors:\n");547 m_set.function_selectors.Dump(&s);548 s.Printf("\nObjective-C class selectors:\n");549 m_set.objc_class_selectors.Dump(&s);550 s.Printf("\nGlobals and statics:\n");551 m_set.globals.Dump(&s);552 s.Printf("\nTypes:\n");553 m_set.types.Dump(&s);554 s.Printf("\nNamespaces:\n");555 m_set.namespaces.Dump(&s);556}557 558bool ManualDWARFIndex::Decode(const DataExtractor &data,559 lldb::offset_t *offset_ptr,560 bool &signature_mismatch) {561 signature_mismatch = false;562 CacheSignature signature;563 if (!signature.Decode(data, offset_ptr))564 return false;565 if (CacheSignature(m_dwarf->GetObjectFile()) != signature) {566 signature_mismatch = true;567 return false;568 }569 std::optional<IndexSet<NameToDIE>> set = DecodeIndexSet(data, offset_ptr);570 if (!set)571 return false;572 m_set = std::move(*set);573 return true;574}575 576bool ManualDWARFIndex::Encode(DataEncoder &encoder) const {577 CacheSignature signature(m_dwarf->GetObjectFile());578 if (!signature.Encode(encoder))579 return false;580 EncodeIndexSet(m_set, encoder);581 return true;582}583 584bool ManualDWARFIndex::IsPartial() const {585 // If we have units or type units to skip, then this index is partial.586 return !m_units_to_avoid.empty() || !m_type_sigs_to_avoid.empty();587}588 589std::string ManualDWARFIndex::GetCacheKey() {590 std::string key;591 llvm::raw_string_ostream strm(key);592 // DWARF Index can come from different object files for the same module. A593 // module can have one object file as the main executable and might have594 // another object file in a separate symbol file, or we might have a .dwo file595 // that claims its module is the main executable.596 597 // This class can be used to index all of the DWARF, or part of the DWARF598 // when there is a .debug_names index where some compile or type units were599 // built without .debug_names. So we need to know when we have a full manual600 // DWARF index or a partial manual DWARF index and save them to different601 // cache files. Before this fix we might end up debugging a binary with602 // .debug_names where some of the compile or type units weren't indexed, and603 // find an issue with the .debug_names tables (bugs or being incomplete), and604 // then we disable loading the .debug_names by setting a setting in LLDB by605 // running "settings set plugin.symbol-file.dwarf.ignore-file-indexes 0" in606 // another LLDB instance. The problem arose when there was an index cache from607 // a previous run where .debug_names was enabled and it had saved a cache file608 // that only covered the missing compile and type units from the .debug_names,609 // and with the setting that disables the loading of the cache files we would610 // load partial cache index cache. So we need to pick a unique cache suffix611 // name that indicates if the cache is partial or full to avoid this problem.612 llvm::StringRef dwarf_index_suffix(IsPartial() ? "partial-" : "full-");613 ObjectFile *objfile = m_dwarf->GetObjectFile();614 strm << objfile->GetModule()->GetCacheKey() << "-dwarf-index-"615 << dwarf_index_suffix << llvm::format_hex(objfile->GetCacheHash(), 10);616 return key;617}618 619bool ManualDWARFIndex::LoadFromCache() {620 DataFileCache *cache = Module::GetIndexCache();621 if (!cache)622 return false;623 ObjectFile *objfile = m_dwarf->GetObjectFile();624 if (!objfile)625 return false;626 std::unique_ptr<llvm::MemoryBuffer> mem_buffer_up =627 cache->GetCachedData(GetCacheKey());628 if (!mem_buffer_up)629 return false;630 DataExtractor data(mem_buffer_up->getBufferStart(),631 mem_buffer_up->getBufferSize(),632 endian::InlHostByteOrder(),633 objfile->GetAddressByteSize());634 bool signature_mismatch = false;635 lldb::offset_t offset = 0;636 const bool result = Decode(data, &offset, signature_mismatch);637 if (signature_mismatch)638 cache->RemoveCacheFile(GetCacheKey());639 return result;640}641 642void ManualDWARFIndex::SaveToCache() {643 DataFileCache *cache = Module::GetIndexCache();644 if (!cache)645 return; // Caching is not enabled.646 ObjectFile *objfile = m_dwarf->GetObjectFile();647 if (!objfile)648 return;649 DataEncoder file(endian::InlHostByteOrder(), objfile->GetAddressByteSize());650 // Encode will return false if the object file doesn't have anything to make651 // a signature from.652 if (Encode(file)) {653 if (cache->SetCachedData(GetCacheKey(), file.GetData()))654 m_dwarf->SetDebugInfoIndexWasSavedToCache();655 }656}657