brintos

brintos / llvm-project-archived public Read only

0
0
Text · 24.4 KiB · 36dee14 Raw
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 &regex,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 &regex,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