xref: /src/contrib/llvm-project/lldb/source/Target/ModuleCache.cpp (revision 81ad626541db97eb356e2c1d4a20eb2a26a766ab)
1cfca06d7SDimitry Andric //===-- ModuleCache.cpp ---------------------------------------------------===//
25e95aa85SEd Maste //
35f29bb8aSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
45f29bb8aSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
55f29bb8aSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
65e95aa85SEd Maste //
75e95aa85SEd Maste //===----------------------------------------------------------------------===//
85e95aa85SEd Maste 
974a628f7SDimitry Andric #include "lldb/Target/ModuleCache.h"
105e95aa85SEd Maste 
115e95aa85SEd Maste #include "lldb/Core/Module.h"
12e81d9d49SDimitry Andric #include "lldb/Core/ModuleList.h"
135e95aa85SEd Maste #include "lldb/Core/ModuleSpec.h"
145e95aa85SEd Maste #include "lldb/Host/File.h"
155e95aa85SEd Maste #include "lldb/Host/LockFile.h"
16145449b1SDimitry Andric #include "lldb/Utility/LLDBLog.h"
1774a628f7SDimitry Andric #include "lldb/Utility/Log.h"
185e95aa85SEd Maste #include "llvm/Support/FileSystem.h"
195e95aa85SEd Maste #include "llvm/Support/FileUtilities.h"
205e95aa85SEd Maste 
21344a3780SDimitry Andric #include <cassert>
225e95aa85SEd Maste 
235e95aa85SEd Maste #include <cstdio>
245e95aa85SEd Maste 
255e95aa85SEd Maste using namespace lldb;
265e95aa85SEd Maste using namespace lldb_private;
275e95aa85SEd Maste 
285e95aa85SEd Maste namespace {
295e95aa85SEd Maste 
305e95aa85SEd Maste const char *kModulesSubdir = ".cache";
31e81d9d49SDimitry Andric const char *kLockDirName = ".lock";
325e95aa85SEd Maste const char *kTempFileName = ".temp";
33e81d9d49SDimitry Andric const char *kTempSymFileName = ".symtemp";
34e81d9d49SDimitry Andric const char *kSymFileExtension = ".sym";
35f3fbd1c0SDimitry Andric const char *kFSIllegalChars = "\\/:*?\"<>|";
36f3fbd1c0SDimitry Andric 
GetEscapedHostname(const char * hostname)3714f1b3e8SDimitry Andric std::string GetEscapedHostname(const char *hostname) {
3814f1b3e8SDimitry Andric   if (hostname == nullptr)
3914f1b3e8SDimitry Andric     hostname = "unknown";
40f3fbd1c0SDimitry Andric   std::string result(hostname);
41f3fbd1c0SDimitry Andric   size_t size = result.size();
4214f1b3e8SDimitry Andric   for (size_t i = 0; i < size; ++i) {
43f3fbd1c0SDimitry Andric     if ((result[i] >= 1 && result[i] <= 31) ||
44f3fbd1c0SDimitry Andric         strchr(kFSIllegalChars, result[i]) != nullptr)
45f3fbd1c0SDimitry Andric       result[i] = '_';
46f3fbd1c0SDimitry Andric   }
47f3fbd1c0SDimitry Andric   return result;
48f3fbd1c0SDimitry Andric }
49e81d9d49SDimitry Andric 
5014f1b3e8SDimitry Andric class ModuleLock {
51e81d9d49SDimitry Andric private:
52ead24645SDimitry Andric   FileUP m_file_up;
53e81d9d49SDimitry Andric   std::unique_ptr<lldb_private::LockFile> m_lock;
54e81d9d49SDimitry Andric   FileSpec m_file_spec;
55e81d9d49SDimitry Andric 
56e81d9d49SDimitry Andric public:
57b76161e4SDimitry Andric   ModuleLock(const FileSpec &root_dir_spec, const UUID &uuid, Status &error);
58e81d9d49SDimitry Andric   void Delete();
59e81d9d49SDimitry Andric };
605e95aa85SEd Maste 
JoinPath(const FileSpec & path1,const char * path2)6174a628f7SDimitry Andric static FileSpec JoinPath(const FileSpec &path1, const char *path2) {
625e95aa85SEd Maste   FileSpec result_spec(path1);
635e95aa85SEd Maste   result_spec.AppendPathComponent(path2);
645e95aa85SEd Maste   return result_spec;
655e95aa85SEd Maste }
665e95aa85SEd Maste 
MakeDirectory(const FileSpec & dir_path)67b76161e4SDimitry Andric static Status MakeDirectory(const FileSpec &dir_path) {
6874a628f7SDimitry Andric   namespace fs = llvm::sys::fs;
695e95aa85SEd Maste 
7074a628f7SDimitry Andric   return fs::create_directories(dir_path.GetPath(), true, fs::perms::owner_all);
715e95aa85SEd Maste }
725e95aa85SEd Maste 
GetModuleDirectory(const FileSpec & root_dir_spec,const UUID & uuid)7314f1b3e8SDimitry Andric FileSpec GetModuleDirectory(const FileSpec &root_dir_spec, const UUID &uuid) {
745e95aa85SEd Maste   const auto modules_dir_spec = JoinPath(root_dir_spec, kModulesSubdir);
755e95aa85SEd Maste   return JoinPath(modules_dir_spec, uuid.GetAsString().c_str());
765e95aa85SEd Maste }
775e95aa85SEd Maste 
GetSymbolFileSpec(const FileSpec & module_file_spec)7814f1b3e8SDimitry Andric FileSpec GetSymbolFileSpec(const FileSpec &module_file_spec) {
7994994d37SDimitry Andric   return FileSpec(module_file_spec.GetPath() + kSymFileExtension);
80e81d9d49SDimitry Andric }
81e81d9d49SDimitry Andric 
DeleteExistingModule(const FileSpec & root_dir_spec,const FileSpec & sysroot_module_path_spec)8214f1b3e8SDimitry Andric void DeleteExistingModule(const FileSpec &root_dir_spec,
8314f1b3e8SDimitry Andric                           const FileSpec &sysroot_module_path_spec) {
84145449b1SDimitry Andric   Log *log = GetLog(LLDBLog::Modules);
85e81d9d49SDimitry Andric   UUID module_uuid;
86e81d9d49SDimitry Andric   {
8714f1b3e8SDimitry Andric     auto module_sp =
8814f1b3e8SDimitry Andric         std::make_shared<Module>(ModuleSpec(sysroot_module_path_spec));
89e81d9d49SDimitry Andric     module_uuid = module_sp->GetUUID();
90e81d9d49SDimitry Andric   }
91e81d9d49SDimitry Andric 
92e81d9d49SDimitry Andric   if (!module_uuid.IsValid())
93e81d9d49SDimitry Andric     return;
94e81d9d49SDimitry Andric 
95b76161e4SDimitry Andric   Status error;
96e81d9d49SDimitry Andric   ModuleLock lock(root_dir_spec, module_uuid, error);
9714f1b3e8SDimitry Andric   if (error.Fail()) {
98ead24645SDimitry Andric     LLDB_LOGF(log, "Failed to lock module %s: %s",
9914f1b3e8SDimitry Andric               module_uuid.GetAsString().c_str(), error.AsCString());
100e81d9d49SDimitry Andric   }
101e81d9d49SDimitry Andric 
10274a628f7SDimitry Andric   namespace fs = llvm::sys::fs;
10374a628f7SDimitry Andric   fs::file_status st;
10474a628f7SDimitry Andric   if (status(sysroot_module_path_spec.GetPath(), st))
105e81d9d49SDimitry Andric     return;
106e81d9d49SDimitry Andric 
10774a628f7SDimitry Andric   if (st.getLinkCount() > 2) // module is referred by other hosts.
108e81d9d49SDimitry Andric     return;
109e81d9d49SDimitry Andric 
110e81d9d49SDimitry Andric   const auto module_spec_dir = GetModuleDirectory(root_dir_spec, module_uuid);
11174a628f7SDimitry Andric   llvm::sys::fs::remove_directories(module_spec_dir.GetPath());
112e81d9d49SDimitry Andric   lock.Delete();
113e81d9d49SDimitry Andric }
114e81d9d49SDimitry Andric 
DecrementRefExistingModule(const FileSpec & root_dir_spec,const FileSpec & sysroot_module_path_spec)11514f1b3e8SDimitry Andric void DecrementRefExistingModule(const FileSpec &root_dir_spec,
11614f1b3e8SDimitry Andric                                 const FileSpec &sysroot_module_path_spec) {
117e81d9d49SDimitry Andric   // Remove $platform/.cache/$uuid folder if nobody else references it.
118e81d9d49SDimitry Andric   DeleteExistingModule(root_dir_spec, sysroot_module_path_spec);
119e81d9d49SDimitry Andric 
120e81d9d49SDimitry Andric   // Remove sysroot link.
12174a628f7SDimitry Andric   llvm::sys::fs::remove(sysroot_module_path_spec.GetPath());
122e81d9d49SDimitry Andric 
123e81d9d49SDimitry Andric   FileSpec symfile_spec = GetSymbolFileSpec(sysroot_module_path_spec);
12474a628f7SDimitry Andric   llvm::sys::fs::remove(symfile_spec.GetPath());
125e81d9d49SDimitry Andric }
126e81d9d49SDimitry Andric 
CreateHostSysRootModuleLink(const FileSpec & root_dir_spec,const char * hostname,const FileSpec & platform_module_spec,const FileSpec & local_module_spec,bool delete_existing)127b76161e4SDimitry Andric Status CreateHostSysRootModuleLink(const FileSpec &root_dir_spec,
12814f1b3e8SDimitry Andric                                    const char *hostname,
129e81d9d49SDimitry Andric                                    const FileSpec &platform_module_spec,
130e81d9d49SDimitry Andric                                    const FileSpec &local_module_spec,
13114f1b3e8SDimitry Andric                                    bool delete_existing) {
13214f1b3e8SDimitry Andric   const auto sysroot_module_path_spec =
13314f1b3e8SDimitry Andric       JoinPath(JoinPath(root_dir_spec, hostname),
13414f1b3e8SDimitry Andric                platform_module_spec.GetPath().c_str());
13594994d37SDimitry Andric   if (FileSystem::Instance().Exists(sysroot_module_path_spec)) {
136e81d9d49SDimitry Andric     if (!delete_existing)
137b76161e4SDimitry Andric       return Status();
1385e95aa85SEd Maste 
139e81d9d49SDimitry Andric     DecrementRefExistingModule(root_dir_spec, sysroot_module_path_spec);
140e81d9d49SDimitry Andric   }
141e81d9d49SDimitry Andric 
14214f1b3e8SDimitry Andric   const auto error = MakeDirectory(
14394994d37SDimitry Andric       FileSpec(sysroot_module_path_spec.GetDirectory().AsCString()));
1445e95aa85SEd Maste   if (error.Fail())
1455e95aa85SEd Maste     return error;
1465e95aa85SEd Maste 
14774a628f7SDimitry Andric   return llvm::sys::fs::create_hard_link(local_module_spec.GetPath(),
14874a628f7SDimitry Andric                                          sysroot_module_path_spec.GetPath());
1495e95aa85SEd Maste }
1505e95aa85SEd Maste 
1515e95aa85SEd Maste } // namespace
1525e95aa85SEd Maste 
ModuleLock(const FileSpec & root_dir_spec,const UUID & uuid,Status & error)15314f1b3e8SDimitry Andric ModuleLock::ModuleLock(const FileSpec &root_dir_spec, const UUID &uuid,
154b76161e4SDimitry Andric                        Status &error) {
155e81d9d49SDimitry Andric   const auto lock_dir_spec = JoinPath(root_dir_spec, kLockDirName);
156e81d9d49SDimitry Andric   error = MakeDirectory(lock_dir_spec);
157e81d9d49SDimitry Andric   if (error.Fail())
158e81d9d49SDimitry Andric     return;
159e81d9d49SDimitry Andric 
160e81d9d49SDimitry Andric   m_file_spec = JoinPath(lock_dir_spec, uuid.GetAsString().c_str());
161ead24645SDimitry Andric 
162ead24645SDimitry Andric   auto file = FileSystem::Instance().Open(
163c0981da4SDimitry Andric       m_file_spec, File::eOpenOptionWriteOnly | File::eOpenOptionCanCreate |
16414f1b3e8SDimitry Andric                        File::eOpenOptionCloseOnExec);
165ead24645SDimitry Andric   if (file)
166ead24645SDimitry Andric     m_file_up = std::move(file.get());
167ead24645SDimitry Andric   else {
168ead24645SDimitry Andric     m_file_up.reset();
169ead24645SDimitry Andric     error = Status(file.takeError());
170e81d9d49SDimitry Andric     return;
171e81d9d49SDimitry Andric   }
172e81d9d49SDimitry Andric 
173cfca06d7SDimitry Andric   m_lock = std::make_unique<lldb_private::LockFile>(m_file_up->GetDescriptor());
174e81d9d49SDimitry Andric   error = m_lock->WriteLock(0, 1);
175e81d9d49SDimitry Andric   if (error.Fail())
17614f1b3e8SDimitry Andric     error.SetErrorStringWithFormat("Failed to lock file: %s",
17714f1b3e8SDimitry Andric                                    error.AsCString());
178e81d9d49SDimitry Andric }
179e81d9d49SDimitry Andric 
Delete()18014f1b3e8SDimitry Andric void ModuleLock::Delete() {
181ead24645SDimitry Andric   if (!m_file_up)
182e81d9d49SDimitry Andric     return;
183e81d9d49SDimitry Andric 
184ead24645SDimitry Andric   m_file_up->Close();
185ead24645SDimitry Andric   m_file_up.reset();
18674a628f7SDimitry Andric   llvm::sys::fs::remove(m_file_spec.GetPath());
187e81d9d49SDimitry Andric }
188e81d9d49SDimitry Andric 
189e81d9d49SDimitry Andric /////////////////////////////////////////////////////////////////////////
190e81d9d49SDimitry Andric 
Put(const FileSpec & root_dir_spec,const char * hostname,const ModuleSpec & module_spec,const FileSpec & tmp_file,const FileSpec & target_file)191b76161e4SDimitry Andric Status ModuleCache::Put(const FileSpec &root_dir_spec, const char *hostname,
19214f1b3e8SDimitry Andric                         const ModuleSpec &module_spec, const FileSpec &tmp_file,
19314f1b3e8SDimitry Andric                         const FileSpec &target_file) {
19414f1b3e8SDimitry Andric   const auto module_spec_dir =
19514f1b3e8SDimitry Andric       GetModuleDirectory(root_dir_spec, module_spec.GetUUID());
19614f1b3e8SDimitry Andric   const auto module_file_path =
19714f1b3e8SDimitry Andric       JoinPath(module_spec_dir, target_file.GetFilename().AsCString());
1985e95aa85SEd Maste 
1995e95aa85SEd Maste   const auto tmp_file_path = tmp_file.GetPath();
20014f1b3e8SDimitry Andric   const auto err_code =
20114f1b3e8SDimitry Andric       llvm::sys::fs::rename(tmp_file_path, module_file_path.GetPath());
2025e95aa85SEd Maste   if (err_code)
203b76161e4SDimitry Andric     return Status("Failed to rename file %s to %s: %s", tmp_file_path.c_str(),
20414f1b3e8SDimitry Andric                   module_file_path.GetPath().c_str(),
20514f1b3e8SDimitry Andric                   err_code.message().c_str());
2065e95aa85SEd Maste 
20714f1b3e8SDimitry Andric   const auto error = CreateHostSysRootModuleLink(
20814f1b3e8SDimitry Andric       root_dir_spec, hostname, target_file, module_file_path, true);
2095e95aa85SEd Maste   if (error.Fail())
210b76161e4SDimitry Andric     return Status("Failed to create link to %s: %s",
21114f1b3e8SDimitry Andric                   module_file_path.GetPath().c_str(), error.AsCString());
212b76161e4SDimitry Andric   return Status();
2135e95aa85SEd Maste }
2145e95aa85SEd Maste 
Get(const FileSpec & root_dir_spec,const char * hostname,const ModuleSpec & module_spec,ModuleSP & cached_module_sp,bool * did_create_ptr)215b76161e4SDimitry Andric Status ModuleCache::Get(const FileSpec &root_dir_spec, const char *hostname,
2165e95aa85SEd Maste                         const ModuleSpec &module_spec,
21714f1b3e8SDimitry Andric                         ModuleSP &cached_module_sp, bool *did_create_ptr) {
21814f1b3e8SDimitry Andric   const auto find_it =
21914f1b3e8SDimitry Andric       m_loaded_modules.find(module_spec.GetUUID().GetAsString());
22014f1b3e8SDimitry Andric   if (find_it != m_loaded_modules.end()) {
2215e95aa85SEd Maste     cached_module_sp = (*find_it).second.lock();
2225e95aa85SEd Maste     if (cached_module_sp)
223b76161e4SDimitry Andric       return Status();
2245e95aa85SEd Maste     m_loaded_modules.erase(find_it);
2255e95aa85SEd Maste   }
2265e95aa85SEd Maste 
22714f1b3e8SDimitry Andric   const auto module_spec_dir =
22814f1b3e8SDimitry Andric       GetModuleDirectory(root_dir_spec, module_spec.GetUUID());
22914f1b3e8SDimitry Andric   const auto module_file_path = JoinPath(
23014f1b3e8SDimitry Andric       module_spec_dir, module_spec.GetFileSpec().GetFilename().AsCString());
2315e95aa85SEd Maste 
23294994d37SDimitry Andric   if (!FileSystem::Instance().Exists(module_file_path))
233b76161e4SDimitry Andric     return Status("Module %s not found", module_file_path.GetPath().c_str());
23494994d37SDimitry Andric   if (FileSystem::Instance().GetByteSize(module_file_path) !=
23594994d37SDimitry Andric       module_spec.GetObjectSize())
236b76161e4SDimitry Andric     return Status("Module %s has invalid file size",
23714f1b3e8SDimitry Andric                   module_file_path.GetPath().c_str());
2385e95aa85SEd Maste 
23914f1b3e8SDimitry Andric   // We may have already cached module but downloaded from an another host - in
24014f1b3e8SDimitry Andric   // this case let's create a link to it.
24114f1b3e8SDimitry Andric   auto error = CreateHostSysRootModuleLink(root_dir_spec, hostname,
24214f1b3e8SDimitry Andric                                            module_spec.GetFileSpec(),
24314f1b3e8SDimitry Andric                                            module_file_path, false);
2445e95aa85SEd Maste   if (error.Fail())
245b76161e4SDimitry Andric     return Status("Failed to create link to %s: %s",
24614f1b3e8SDimitry Andric                   module_file_path.GetPath().c_str(), error.AsCString());
2475e95aa85SEd Maste 
2485e95aa85SEd Maste   auto cached_module_spec(module_spec);
24914f1b3e8SDimitry Andric   cached_module_spec.GetUUID().Clear(); // Clear UUID since it may contain md5
25014f1b3e8SDimitry Andric                                         // content hash instead of real UUID.
2515e95aa85SEd Maste   cached_module_spec.GetFileSpec() = module_file_path;
2525e95aa85SEd Maste   cached_module_spec.GetPlatformFileSpec() = module_spec.GetFileSpec();
253e81d9d49SDimitry Andric 
25414f1b3e8SDimitry Andric   error = ModuleList::GetSharedModule(cached_module_spec, cached_module_sp,
25514f1b3e8SDimitry Andric                                       nullptr, nullptr, did_create_ptr, false);
256e81d9d49SDimitry Andric   if (error.Fail())
257e81d9d49SDimitry Andric     return error;
258e81d9d49SDimitry Andric 
259e81d9d49SDimitry Andric   FileSpec symfile_spec = GetSymbolFileSpec(cached_module_sp->GetFileSpec());
26094994d37SDimitry Andric   if (FileSystem::Instance().Exists(symfile_spec))
261e81d9d49SDimitry Andric     cached_module_sp->SetSymbolFileFileSpec(symfile_spec);
2625e95aa85SEd Maste 
26314f1b3e8SDimitry Andric   m_loaded_modules.insert(
26414f1b3e8SDimitry Andric       std::make_pair(module_spec.GetUUID().GetAsString(), cached_module_sp));
2655e95aa85SEd Maste 
266b76161e4SDimitry Andric   return Status();
2675e95aa85SEd Maste }
2685e95aa85SEd Maste 
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)269b76161e4SDimitry Andric Status ModuleCache::GetAndPut(const FileSpec &root_dir_spec,
2705e95aa85SEd Maste                               const char *hostname,
2715e95aa85SEd Maste                               const ModuleSpec &module_spec,
272e81d9d49SDimitry Andric                               const ModuleDownloader &module_downloader,
273e81d9d49SDimitry Andric                               const SymfileDownloader &symfile_downloader,
2745e95aa85SEd Maste                               lldb::ModuleSP &cached_module_sp,
27514f1b3e8SDimitry Andric                               bool *did_create_ptr) {
27614f1b3e8SDimitry Andric   const auto module_spec_dir =
27714f1b3e8SDimitry Andric       GetModuleDirectory(root_dir_spec, module_spec.GetUUID());
2785e95aa85SEd Maste   auto error = MakeDirectory(module_spec_dir);
2795e95aa85SEd Maste   if (error.Fail())
2805e95aa85SEd Maste     return error;
2815e95aa85SEd Maste 
282e81d9d49SDimitry Andric   ModuleLock lock(root_dir_spec, module_spec.GetUUID(), error);
2835e95aa85SEd Maste   if (error.Fail())
284b76161e4SDimitry Andric     return Status("Failed to lock module %s: %s",
28514f1b3e8SDimitry Andric                   module_spec.GetUUID().GetAsString().c_str(),
28614f1b3e8SDimitry Andric                   error.AsCString());
2875e95aa85SEd Maste 
288f3fbd1c0SDimitry Andric   const auto escaped_hostname(GetEscapedHostname(hostname));
2895e95aa85SEd Maste   // Check local cache for a module.
29014f1b3e8SDimitry Andric   error = Get(root_dir_spec, escaped_hostname.c_str(), module_spec,
29114f1b3e8SDimitry Andric               cached_module_sp, did_create_ptr);
2925e95aa85SEd Maste   if (error.Success())
2935e95aa85SEd Maste     return error;
2945e95aa85SEd Maste 
2955e95aa85SEd Maste   const auto tmp_download_file_spec = JoinPath(module_spec_dir, kTempFileName);
296e81d9d49SDimitry Andric   error = module_downloader(module_spec, tmp_download_file_spec);
29714f1b3e8SDimitry Andric   llvm::FileRemover tmp_file_remover(tmp_download_file_spec.GetPath());
2985e95aa85SEd Maste   if (error.Fail())
299b76161e4SDimitry Andric     return Status("Failed to download module: %s", error.AsCString());
3005e95aa85SEd Maste 
3015e95aa85SEd Maste   // Put downloaded file into local module cache.
30214f1b3e8SDimitry Andric   error = Put(root_dir_spec, escaped_hostname.c_str(), module_spec,
30314f1b3e8SDimitry Andric               tmp_download_file_spec, module_spec.GetFileSpec());
3045e95aa85SEd Maste   if (error.Fail())
305b76161e4SDimitry Andric     return Status("Failed to put module into cache: %s", error.AsCString());
3065e95aa85SEd Maste 
3075e95aa85SEd Maste   tmp_file_remover.releaseFile();
30814f1b3e8SDimitry Andric   error = Get(root_dir_spec, escaped_hostname.c_str(), module_spec,
30914f1b3e8SDimitry Andric               cached_module_sp, did_create_ptr);
310e81d9d49SDimitry Andric   if (error.Fail())
311e81d9d49SDimitry Andric     return error;
312e81d9d49SDimitry Andric 
313e81d9d49SDimitry Andric   // Fetching a symbol file for the module
31414f1b3e8SDimitry Andric   const auto tmp_download_sym_file_spec =
31514f1b3e8SDimitry Andric       JoinPath(module_spec_dir, kTempSymFileName);
316e81d9d49SDimitry Andric   error = symfile_downloader(cached_module_sp, tmp_download_sym_file_spec);
31714f1b3e8SDimitry Andric   llvm::FileRemover tmp_symfile_remover(tmp_download_sym_file_spec.GetPath());
318e81d9d49SDimitry Andric   if (error.Fail())
31914f1b3e8SDimitry Andric     // Failed to download a symfile but fetching the module was successful. The
320f73363f1SDimitry Andric     // module might contain the necessary symbols and the debugging is also
321f73363f1SDimitry Andric     // possible without a symfile.
322b76161e4SDimitry Andric     return Status();
323e81d9d49SDimitry Andric 
32414f1b3e8SDimitry Andric   error = Put(root_dir_spec, escaped_hostname.c_str(), module_spec,
32514f1b3e8SDimitry Andric               tmp_download_sym_file_spec,
32614f1b3e8SDimitry Andric               GetSymbolFileSpec(module_spec.GetFileSpec()));
327e81d9d49SDimitry Andric   if (error.Fail())
328b76161e4SDimitry Andric     return Status("Failed to put symbol file into cache: %s",
329b76161e4SDimitry Andric                   error.AsCString());
330e81d9d49SDimitry Andric 
331e81d9d49SDimitry Andric   tmp_symfile_remover.releaseFile();
332e81d9d49SDimitry Andric 
333e81d9d49SDimitry Andric   FileSpec symfile_spec = GetSymbolFileSpec(cached_module_sp->GetFileSpec());
334e81d9d49SDimitry Andric   cached_module_sp->SetSymbolFileFileSpec(symfile_spec);
335b76161e4SDimitry Andric   return Status();
3365e95aa85SEd Maste }
337