xref: /freebsd-src/contrib/llvm-project/lldb/source/Target/ModuleCache.cpp (revision 81ad626541db97eb356e2c1d4a20eb2a26a766ab)
15ffd83dbSDimitry Andric //===-- ModuleCache.cpp ---------------------------------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric 
90b57cec5SDimitry Andric #include "lldb/Target/ModuleCache.h"
100b57cec5SDimitry Andric 
110b57cec5SDimitry Andric #include "lldb/Core/Module.h"
120b57cec5SDimitry Andric #include "lldb/Core/ModuleList.h"
130b57cec5SDimitry Andric #include "lldb/Core/ModuleSpec.h"
140b57cec5SDimitry Andric #include "lldb/Host/File.h"
150b57cec5SDimitry Andric #include "lldb/Host/LockFile.h"
16*81ad6265SDimitry Andric #include "lldb/Utility/LLDBLog.h"
170b57cec5SDimitry Andric #include "lldb/Utility/Log.h"
180b57cec5SDimitry Andric #include "llvm/Support/FileSystem.h"
190b57cec5SDimitry Andric #include "llvm/Support/FileUtilities.h"
200b57cec5SDimitry Andric 
21fe6060f1SDimitry Andric #include <cassert>
220b57cec5SDimitry Andric 
230b57cec5SDimitry Andric #include <cstdio>
240b57cec5SDimitry Andric 
250b57cec5SDimitry Andric using namespace lldb;
260b57cec5SDimitry Andric using namespace lldb_private;
270b57cec5SDimitry Andric 
280b57cec5SDimitry Andric namespace {
290b57cec5SDimitry Andric 
300b57cec5SDimitry Andric const char *kModulesSubdir = ".cache";
310b57cec5SDimitry Andric const char *kLockDirName = ".lock";
320b57cec5SDimitry Andric const char *kTempFileName = ".temp";
330b57cec5SDimitry Andric const char *kTempSymFileName = ".symtemp";
340b57cec5SDimitry Andric const char *kSymFileExtension = ".sym";
350b57cec5SDimitry Andric const char *kFSIllegalChars = "\\/:*?\"<>|";
360b57cec5SDimitry Andric 
GetEscapedHostname(const char * hostname)370b57cec5SDimitry Andric std::string GetEscapedHostname(const char *hostname) {
380b57cec5SDimitry Andric   if (hostname == nullptr)
390b57cec5SDimitry Andric     hostname = "unknown";
400b57cec5SDimitry Andric   std::string result(hostname);
410b57cec5SDimitry Andric   size_t size = result.size();
420b57cec5SDimitry Andric   for (size_t i = 0; i < size; ++i) {
430b57cec5SDimitry Andric     if ((result[i] >= 1 && result[i] <= 31) ||
440b57cec5SDimitry Andric         strchr(kFSIllegalChars, result[i]) != nullptr)
450b57cec5SDimitry Andric       result[i] = '_';
460b57cec5SDimitry Andric   }
470b57cec5SDimitry Andric   return result;
480b57cec5SDimitry Andric }
490b57cec5SDimitry Andric 
500b57cec5SDimitry Andric class ModuleLock {
510b57cec5SDimitry Andric private:
529dba64beSDimitry Andric   FileUP m_file_up;
530b57cec5SDimitry Andric   std::unique_ptr<lldb_private::LockFile> m_lock;
540b57cec5SDimitry Andric   FileSpec m_file_spec;
550b57cec5SDimitry Andric 
560b57cec5SDimitry Andric public:
570b57cec5SDimitry Andric   ModuleLock(const FileSpec &root_dir_spec, const UUID &uuid, Status &error);
580b57cec5SDimitry Andric   void Delete();
590b57cec5SDimitry Andric };
600b57cec5SDimitry Andric 
JoinPath(const FileSpec & path1,const char * path2)610b57cec5SDimitry Andric static FileSpec JoinPath(const FileSpec &path1, const char *path2) {
620b57cec5SDimitry Andric   FileSpec result_spec(path1);
630b57cec5SDimitry Andric   result_spec.AppendPathComponent(path2);
640b57cec5SDimitry Andric   return result_spec;
650b57cec5SDimitry Andric }
660b57cec5SDimitry Andric 
MakeDirectory(const FileSpec & dir_path)670b57cec5SDimitry Andric static Status MakeDirectory(const FileSpec &dir_path) {
680b57cec5SDimitry Andric   namespace fs = llvm::sys::fs;
690b57cec5SDimitry Andric 
700b57cec5SDimitry Andric   return fs::create_directories(dir_path.GetPath(), true, fs::perms::owner_all);
710b57cec5SDimitry Andric }
720b57cec5SDimitry Andric 
GetModuleDirectory(const FileSpec & root_dir_spec,const UUID & uuid)730b57cec5SDimitry Andric FileSpec GetModuleDirectory(const FileSpec &root_dir_spec, const UUID &uuid) {
740b57cec5SDimitry Andric   const auto modules_dir_spec = JoinPath(root_dir_spec, kModulesSubdir);
750b57cec5SDimitry Andric   return JoinPath(modules_dir_spec, uuid.GetAsString().c_str());
760b57cec5SDimitry Andric }
770b57cec5SDimitry Andric 
GetSymbolFileSpec(const FileSpec & module_file_spec)780b57cec5SDimitry Andric FileSpec GetSymbolFileSpec(const FileSpec &module_file_spec) {
790b57cec5SDimitry Andric   return FileSpec(module_file_spec.GetPath() + kSymFileExtension);
800b57cec5SDimitry Andric }
810b57cec5SDimitry Andric 
DeleteExistingModule(const FileSpec & root_dir_spec,const FileSpec & sysroot_module_path_spec)820b57cec5SDimitry Andric void DeleteExistingModule(const FileSpec &root_dir_spec,
830b57cec5SDimitry Andric                           const FileSpec &sysroot_module_path_spec) {
84*81ad6265SDimitry Andric   Log *log = GetLog(LLDBLog::Modules);
850b57cec5SDimitry Andric   UUID module_uuid;
860b57cec5SDimitry Andric   {
870b57cec5SDimitry Andric     auto module_sp =
880b57cec5SDimitry Andric         std::make_shared<Module>(ModuleSpec(sysroot_module_path_spec));
890b57cec5SDimitry Andric     module_uuid = module_sp->GetUUID();
900b57cec5SDimitry Andric   }
910b57cec5SDimitry Andric 
920b57cec5SDimitry Andric   if (!module_uuid.IsValid())
930b57cec5SDimitry Andric     return;
940b57cec5SDimitry Andric 
950b57cec5SDimitry Andric   Status error;
960b57cec5SDimitry Andric   ModuleLock lock(root_dir_spec, module_uuid, error);
970b57cec5SDimitry Andric   if (error.Fail()) {
989dba64beSDimitry Andric     LLDB_LOGF(log, "Failed to lock module %s: %s",
990b57cec5SDimitry Andric               module_uuid.GetAsString().c_str(), error.AsCString());
1000b57cec5SDimitry Andric   }
1010b57cec5SDimitry Andric 
1020b57cec5SDimitry Andric   namespace fs = llvm::sys::fs;
1030b57cec5SDimitry Andric   fs::file_status st;
1040b57cec5SDimitry Andric   if (status(sysroot_module_path_spec.GetPath(), st))
1050b57cec5SDimitry Andric     return;
1060b57cec5SDimitry Andric 
1070b57cec5SDimitry Andric   if (st.getLinkCount() > 2) // module is referred by other hosts.
1080b57cec5SDimitry Andric     return;
1090b57cec5SDimitry Andric 
1100b57cec5SDimitry Andric   const auto module_spec_dir = GetModuleDirectory(root_dir_spec, module_uuid);
1110b57cec5SDimitry Andric   llvm::sys::fs::remove_directories(module_spec_dir.GetPath());
1120b57cec5SDimitry Andric   lock.Delete();
1130b57cec5SDimitry Andric }
1140b57cec5SDimitry Andric 
DecrementRefExistingModule(const FileSpec & root_dir_spec,const FileSpec & sysroot_module_path_spec)1150b57cec5SDimitry Andric void DecrementRefExistingModule(const FileSpec &root_dir_spec,
1160b57cec5SDimitry Andric                                 const FileSpec &sysroot_module_path_spec) {
1170b57cec5SDimitry Andric   // Remove $platform/.cache/$uuid folder if nobody else references it.
1180b57cec5SDimitry Andric   DeleteExistingModule(root_dir_spec, sysroot_module_path_spec);
1190b57cec5SDimitry Andric 
1200b57cec5SDimitry Andric   // Remove sysroot link.
1210b57cec5SDimitry Andric   llvm::sys::fs::remove(sysroot_module_path_spec.GetPath());
1220b57cec5SDimitry Andric 
1230b57cec5SDimitry Andric   FileSpec symfile_spec = GetSymbolFileSpec(sysroot_module_path_spec);
1240b57cec5SDimitry Andric   llvm::sys::fs::remove(symfile_spec.GetPath());
1250b57cec5SDimitry Andric }
1260b57cec5SDimitry Andric 
CreateHostSysRootModuleLink(const FileSpec & root_dir_spec,const char * hostname,const FileSpec & platform_module_spec,const FileSpec & local_module_spec,bool delete_existing)1270b57cec5SDimitry Andric Status CreateHostSysRootModuleLink(const FileSpec &root_dir_spec,
1280b57cec5SDimitry Andric                                    const char *hostname,
1290b57cec5SDimitry Andric                                    const FileSpec &platform_module_spec,
1300b57cec5SDimitry Andric                                    const FileSpec &local_module_spec,
1310b57cec5SDimitry Andric                                    bool delete_existing) {
1320b57cec5SDimitry Andric   const auto sysroot_module_path_spec =
1330b57cec5SDimitry Andric       JoinPath(JoinPath(root_dir_spec, hostname),
1340b57cec5SDimitry Andric                platform_module_spec.GetPath().c_str());
1350b57cec5SDimitry Andric   if (FileSystem::Instance().Exists(sysroot_module_path_spec)) {
1360b57cec5SDimitry Andric     if (!delete_existing)
1370b57cec5SDimitry Andric       return Status();
1380b57cec5SDimitry Andric 
1390b57cec5SDimitry Andric     DecrementRefExistingModule(root_dir_spec, sysroot_module_path_spec);
1400b57cec5SDimitry Andric   }
1410b57cec5SDimitry Andric 
1420b57cec5SDimitry Andric   const auto error = MakeDirectory(
1430b57cec5SDimitry Andric       FileSpec(sysroot_module_path_spec.GetDirectory().AsCString()));
1440b57cec5SDimitry Andric   if (error.Fail())
1450b57cec5SDimitry Andric     return error;
1460b57cec5SDimitry Andric 
1470b57cec5SDimitry Andric   return llvm::sys::fs::create_hard_link(local_module_spec.GetPath(),
1480b57cec5SDimitry Andric                                          sysroot_module_path_spec.GetPath());
1490b57cec5SDimitry Andric }
1500b57cec5SDimitry Andric 
1510b57cec5SDimitry Andric } // namespace
1520b57cec5SDimitry Andric 
ModuleLock(const FileSpec & root_dir_spec,const UUID & uuid,Status & error)1530b57cec5SDimitry Andric ModuleLock::ModuleLock(const FileSpec &root_dir_spec, const UUID &uuid,
1540b57cec5SDimitry Andric                        Status &error) {
1550b57cec5SDimitry Andric   const auto lock_dir_spec = JoinPath(root_dir_spec, kLockDirName);
1560b57cec5SDimitry Andric   error = MakeDirectory(lock_dir_spec);
1570b57cec5SDimitry Andric   if (error.Fail())
1580b57cec5SDimitry Andric     return;
1590b57cec5SDimitry Andric 
1600b57cec5SDimitry Andric   m_file_spec = JoinPath(lock_dir_spec, uuid.GetAsString().c_str());
1619dba64beSDimitry Andric 
1629dba64beSDimitry Andric   auto file = FileSystem::Instance().Open(
163349cc55cSDimitry Andric       m_file_spec, File::eOpenOptionWriteOnly | File::eOpenOptionCanCreate |
1640b57cec5SDimitry Andric                        File::eOpenOptionCloseOnExec);
1659dba64beSDimitry Andric   if (file)
1669dba64beSDimitry Andric     m_file_up = std::move(file.get());
1679dba64beSDimitry Andric   else {
1689dba64beSDimitry Andric     m_file_up.reset();
1699dba64beSDimitry Andric     error = Status(file.takeError());
1700b57cec5SDimitry Andric     return;
1710b57cec5SDimitry Andric   }
1720b57cec5SDimitry Andric 
1735ffd83dbSDimitry Andric   m_lock = std::make_unique<lldb_private::LockFile>(m_file_up->GetDescriptor());
1740b57cec5SDimitry Andric   error = m_lock->WriteLock(0, 1);
1750b57cec5SDimitry Andric   if (error.Fail())
1760b57cec5SDimitry Andric     error.SetErrorStringWithFormat("Failed to lock file: %s",
1770b57cec5SDimitry Andric                                    error.AsCString());
1780b57cec5SDimitry Andric }
1790b57cec5SDimitry Andric 
Delete()1800b57cec5SDimitry Andric void ModuleLock::Delete() {
1819dba64beSDimitry Andric   if (!m_file_up)
1820b57cec5SDimitry Andric     return;
1830b57cec5SDimitry Andric 
1849dba64beSDimitry Andric   m_file_up->Close();
1859dba64beSDimitry Andric   m_file_up.reset();
1860b57cec5SDimitry Andric   llvm::sys::fs::remove(m_file_spec.GetPath());
1870b57cec5SDimitry Andric }
1880b57cec5SDimitry Andric 
1890b57cec5SDimitry Andric /////////////////////////////////////////////////////////////////////////
1900b57cec5SDimitry Andric 
Put(const FileSpec & root_dir_spec,const char * hostname,const ModuleSpec & module_spec,const FileSpec & tmp_file,const FileSpec & target_file)1910b57cec5SDimitry Andric Status ModuleCache::Put(const FileSpec &root_dir_spec, const char *hostname,
1920b57cec5SDimitry Andric                         const ModuleSpec &module_spec, const FileSpec &tmp_file,
1930b57cec5SDimitry Andric                         const FileSpec &target_file) {
1940b57cec5SDimitry Andric   const auto module_spec_dir =
1950b57cec5SDimitry Andric       GetModuleDirectory(root_dir_spec, module_spec.GetUUID());
1960b57cec5SDimitry Andric   const auto module_file_path =
1970b57cec5SDimitry Andric       JoinPath(module_spec_dir, target_file.GetFilename().AsCString());
1980b57cec5SDimitry Andric 
1990b57cec5SDimitry Andric   const auto tmp_file_path = tmp_file.GetPath();
2000b57cec5SDimitry Andric   const auto err_code =
2010b57cec5SDimitry Andric       llvm::sys::fs::rename(tmp_file_path, module_file_path.GetPath());
2020b57cec5SDimitry Andric   if (err_code)
2030b57cec5SDimitry Andric     return Status("Failed to rename file %s to %s: %s", tmp_file_path.c_str(),
2040b57cec5SDimitry Andric                   module_file_path.GetPath().c_str(),
2050b57cec5SDimitry Andric                   err_code.message().c_str());
2060b57cec5SDimitry Andric 
2070b57cec5SDimitry Andric   const auto error = CreateHostSysRootModuleLink(
2080b57cec5SDimitry Andric       root_dir_spec, hostname, target_file, module_file_path, true);
2090b57cec5SDimitry Andric   if (error.Fail())
2100b57cec5SDimitry Andric     return Status("Failed to create link to %s: %s",
2110b57cec5SDimitry Andric                   module_file_path.GetPath().c_str(), error.AsCString());
2120b57cec5SDimitry Andric   return Status();
2130b57cec5SDimitry Andric }
2140b57cec5SDimitry Andric 
Get(const FileSpec & root_dir_spec,const char * hostname,const ModuleSpec & module_spec,ModuleSP & cached_module_sp,bool * did_create_ptr)2150b57cec5SDimitry Andric Status ModuleCache::Get(const FileSpec &root_dir_spec, const char *hostname,
2160b57cec5SDimitry Andric                         const ModuleSpec &module_spec,
2170b57cec5SDimitry Andric                         ModuleSP &cached_module_sp, bool *did_create_ptr) {
2180b57cec5SDimitry Andric   const auto find_it =
2190b57cec5SDimitry Andric       m_loaded_modules.find(module_spec.GetUUID().GetAsString());
2200b57cec5SDimitry Andric   if (find_it != m_loaded_modules.end()) {
2210b57cec5SDimitry Andric     cached_module_sp = (*find_it).second.lock();
2220b57cec5SDimitry Andric     if (cached_module_sp)
2230b57cec5SDimitry Andric       return Status();
2240b57cec5SDimitry Andric     m_loaded_modules.erase(find_it);
2250b57cec5SDimitry Andric   }
2260b57cec5SDimitry Andric 
2270b57cec5SDimitry Andric   const auto module_spec_dir =
2280b57cec5SDimitry Andric       GetModuleDirectory(root_dir_spec, module_spec.GetUUID());
2290b57cec5SDimitry Andric   const auto module_file_path = JoinPath(
2300b57cec5SDimitry Andric       module_spec_dir, module_spec.GetFileSpec().GetFilename().AsCString());
2310b57cec5SDimitry Andric 
2320b57cec5SDimitry Andric   if (!FileSystem::Instance().Exists(module_file_path))
2330b57cec5SDimitry Andric     return Status("Module %s not found", module_file_path.GetPath().c_str());
2340b57cec5SDimitry Andric   if (FileSystem::Instance().GetByteSize(module_file_path) !=
2350b57cec5SDimitry Andric       module_spec.GetObjectSize())
2360b57cec5SDimitry Andric     return Status("Module %s has invalid file size",
2370b57cec5SDimitry Andric                   module_file_path.GetPath().c_str());
2380b57cec5SDimitry Andric 
2390b57cec5SDimitry Andric   // We may have already cached module but downloaded from an another host - in
2400b57cec5SDimitry Andric   // this case let's create a link to it.
2410b57cec5SDimitry Andric   auto error = CreateHostSysRootModuleLink(root_dir_spec, hostname,
2420b57cec5SDimitry Andric                                            module_spec.GetFileSpec(),
2430b57cec5SDimitry Andric                                            module_file_path, false);
2440b57cec5SDimitry Andric   if (error.Fail())
2450b57cec5SDimitry Andric     return Status("Failed to create link to %s: %s",
2460b57cec5SDimitry Andric                   module_file_path.GetPath().c_str(), error.AsCString());
2470b57cec5SDimitry Andric 
2480b57cec5SDimitry Andric   auto cached_module_spec(module_spec);
2490b57cec5SDimitry Andric   cached_module_spec.GetUUID().Clear(); // Clear UUID since it may contain md5
2500b57cec5SDimitry Andric                                         // content hash instead of real UUID.
2510b57cec5SDimitry Andric   cached_module_spec.GetFileSpec() = module_file_path;
2520b57cec5SDimitry Andric   cached_module_spec.GetPlatformFileSpec() = module_spec.GetFileSpec();
2530b57cec5SDimitry Andric 
2540b57cec5SDimitry Andric   error = ModuleList::GetSharedModule(cached_module_spec, cached_module_sp,
2550b57cec5SDimitry Andric                                       nullptr, nullptr, did_create_ptr, false);
2560b57cec5SDimitry Andric   if (error.Fail())
2570b57cec5SDimitry Andric     return error;
2580b57cec5SDimitry Andric 
2590b57cec5SDimitry Andric   FileSpec symfile_spec = GetSymbolFileSpec(cached_module_sp->GetFileSpec());
2600b57cec5SDimitry Andric   if (FileSystem::Instance().Exists(symfile_spec))
2610b57cec5SDimitry Andric     cached_module_sp->SetSymbolFileFileSpec(symfile_spec);
2620b57cec5SDimitry Andric 
2630b57cec5SDimitry Andric   m_loaded_modules.insert(
2640b57cec5SDimitry Andric       std::make_pair(module_spec.GetUUID().GetAsString(), cached_module_sp));
2650b57cec5SDimitry Andric 
2660b57cec5SDimitry Andric   return Status();
2670b57cec5SDimitry Andric }
2680b57cec5SDimitry Andric 
GetAndPut(const FileSpec & root_dir_spec,const char * hostname,const ModuleSpec & module_spec,const ModuleDownloader & module_downloader,const SymfileDownloader & symfile_downloader,lldb::ModuleSP & cached_module_sp,bool * did_create_ptr)2690b57cec5SDimitry Andric Status ModuleCache::GetAndPut(const FileSpec &root_dir_spec,
2700b57cec5SDimitry Andric                               const char *hostname,
2710b57cec5SDimitry Andric                               const ModuleSpec &module_spec,
2720b57cec5SDimitry Andric                               const ModuleDownloader &module_downloader,
2730b57cec5SDimitry Andric                               const SymfileDownloader &symfile_downloader,
2740b57cec5SDimitry Andric                               lldb::ModuleSP &cached_module_sp,
2750b57cec5SDimitry Andric                               bool *did_create_ptr) {
2760b57cec5SDimitry Andric   const auto module_spec_dir =
2770b57cec5SDimitry Andric       GetModuleDirectory(root_dir_spec, module_spec.GetUUID());
2780b57cec5SDimitry Andric   auto error = MakeDirectory(module_spec_dir);
2790b57cec5SDimitry Andric   if (error.Fail())
2800b57cec5SDimitry Andric     return error;
2810b57cec5SDimitry Andric 
2820b57cec5SDimitry Andric   ModuleLock lock(root_dir_spec, module_spec.GetUUID(), error);
2830b57cec5SDimitry Andric   if (error.Fail())
2840b57cec5SDimitry Andric     return Status("Failed to lock module %s: %s",
2850b57cec5SDimitry Andric                   module_spec.GetUUID().GetAsString().c_str(),
2860b57cec5SDimitry Andric                   error.AsCString());
2870b57cec5SDimitry Andric 
2880b57cec5SDimitry Andric   const auto escaped_hostname(GetEscapedHostname(hostname));
2890b57cec5SDimitry Andric   // Check local cache for a module.
2900b57cec5SDimitry Andric   error = Get(root_dir_spec, escaped_hostname.c_str(), module_spec,
2910b57cec5SDimitry Andric               cached_module_sp, did_create_ptr);
2920b57cec5SDimitry Andric   if (error.Success())
2930b57cec5SDimitry Andric     return error;
2940b57cec5SDimitry Andric 
2950b57cec5SDimitry Andric   const auto tmp_download_file_spec = JoinPath(module_spec_dir, kTempFileName);
2960b57cec5SDimitry Andric   error = module_downloader(module_spec, tmp_download_file_spec);
2970b57cec5SDimitry Andric   llvm::FileRemover tmp_file_remover(tmp_download_file_spec.GetPath());
2980b57cec5SDimitry Andric   if (error.Fail())
2990b57cec5SDimitry Andric     return Status("Failed to download module: %s", error.AsCString());
3000b57cec5SDimitry Andric 
3010b57cec5SDimitry Andric   // Put downloaded file into local module cache.
3020b57cec5SDimitry Andric   error = Put(root_dir_spec, escaped_hostname.c_str(), module_spec,
3030b57cec5SDimitry Andric               tmp_download_file_spec, module_spec.GetFileSpec());
3040b57cec5SDimitry Andric   if (error.Fail())
3050b57cec5SDimitry Andric     return Status("Failed to put module into cache: %s", error.AsCString());
3060b57cec5SDimitry Andric 
3070b57cec5SDimitry Andric   tmp_file_remover.releaseFile();
3080b57cec5SDimitry Andric   error = Get(root_dir_spec, escaped_hostname.c_str(), module_spec,
3090b57cec5SDimitry Andric               cached_module_sp, did_create_ptr);
3100b57cec5SDimitry Andric   if (error.Fail())
3110b57cec5SDimitry Andric     return error;
3120b57cec5SDimitry Andric 
3130b57cec5SDimitry Andric   // Fetching a symbol file for the module
3140b57cec5SDimitry Andric   const auto tmp_download_sym_file_spec =
3150b57cec5SDimitry Andric       JoinPath(module_spec_dir, kTempSymFileName);
3160b57cec5SDimitry Andric   error = symfile_downloader(cached_module_sp, tmp_download_sym_file_spec);
3170b57cec5SDimitry Andric   llvm::FileRemover tmp_symfile_remover(tmp_download_sym_file_spec.GetPath());
3180b57cec5SDimitry Andric   if (error.Fail())
3190b57cec5SDimitry Andric     // Failed to download a symfile but fetching the module was successful. The
3200b57cec5SDimitry Andric     // module might contain the necessary symbols and the debugging is also
3210b57cec5SDimitry Andric     // possible without a symfile.
3220b57cec5SDimitry Andric     return Status();
3230b57cec5SDimitry Andric 
3240b57cec5SDimitry Andric   error = Put(root_dir_spec, escaped_hostname.c_str(), module_spec,
3250b57cec5SDimitry Andric               tmp_download_sym_file_spec,
3260b57cec5SDimitry Andric               GetSymbolFileSpec(module_spec.GetFileSpec()));
3270b57cec5SDimitry Andric   if (error.Fail())
3280b57cec5SDimitry Andric     return Status("Failed to put symbol file into cache: %s",
3290b57cec5SDimitry Andric                   error.AsCString());
3300b57cec5SDimitry Andric 
3310b57cec5SDimitry Andric   tmp_symfile_remover.releaseFile();
3320b57cec5SDimitry Andric 
3330b57cec5SDimitry Andric   FileSpec symfile_spec = GetSymbolFileSpec(cached_module_sp->GetFileSpec());
3340b57cec5SDimitry Andric   cached_module_sp->SetSymbolFileFileSpec(symfile_spec);
3350b57cec5SDimitry Andric   return Status();
3360b57cec5SDimitry Andric }
337