blob: a4aa26a0e480edf9cc32ae9ce3cc1f1a75310a6c [file] [log] [blame]
Oleksiy Vyalov63acdfd2015-03-10 01:15:28 +00001//===--------------------- ModuleCache.cpp ----------------------*- C++ -*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
Zachary Turner01c32432017-02-14 19:06:07 +000010#include "lldb/Target/ModuleCache.h"
Oleksiy Vyalov63acdfd2015-03-10 01:15:28 +000011
12#include "lldb/Core/Module.h"
Tamas Berghammer257e13a2015-12-10 17:08:23 +000013#include "lldb/Core/ModuleList.h"
Oleksiy Vyaloveda270e2015-03-12 18:18:03 +000014#include "lldb/Core/ModuleSpec.h"
Oleksiy Vyalov919ef9d2015-05-07 15:28:49 +000015#include "lldb/Host/File.h"
Oleksiy Vyalov919ef9d2015-05-07 15:28:49 +000016#include "lldb/Host/LockFile.h"
Zachary Turner6f9e6902017-03-03 20:56:28 +000017#include "lldb/Utility/Log.h"
Oleksiy Vyalov63acdfd2015-03-10 01:15:28 +000018#include "llvm/Support/FileSystem.h"
Oleksiy Vyalov280d8dc2015-04-15 14:35:10 +000019#include "llvm/Support/FileUtilities.h"
Oleksiy Vyalov63acdfd2015-03-10 01:15:28 +000020
21#include <assert.h>
22
23#include <cstdio>
Oleksiy Vyalov919ef9d2015-05-07 15:28:49 +000024
Oleksiy Vyalov63acdfd2015-03-10 01:15:28 +000025using namespace lldb;
26using namespace lldb_private;
27
28namespace {
29
Kate Stoneb9c1b512016-09-06 20:57:50 +000030const char *kModulesSubdir = ".cache";
31const char *kLockDirName = ".lock";
32const char *kTempFileName = ".temp";
33const char *kTempSymFileName = ".symtemp";
34const char *kSymFileExtension = ".sym";
35const char *kFSIllegalChars = "\\/:*?\"<>|";
Oleksiy Vyalov3154e772016-05-24 18:09:05 +000036
Kate Stoneb9c1b512016-09-06 20:57:50 +000037std::string GetEscapedHostname(const char *hostname) {
Jason Molenda14699cf2016-10-21 02:32:08 +000038 if (hostname == nullptr)
39 hostname = "unknown";
Kate Stoneb9c1b512016-09-06 20:57:50 +000040 std::string result(hostname);
41 size_t size = result.size();
42 for (size_t i = 0; i < size; ++i) {
43 if ((result[i] >= 1 && result[i] <= 31) ||
44 strchr(kFSIllegalChars, result[i]) != nullptr)
45 result[i] = '_';
46 }
47 return result;
Oleksiy Vyalov3154e772016-05-24 18:09:05 +000048}
Oleksiy Vyalov63acdfd2015-03-10 01:15:28 +000049
Kate Stoneb9c1b512016-09-06 20:57:50 +000050class ModuleLock {
Oleksiy Vyalov2b38f332015-09-18 18:12:39 +000051private:
Kate Stoneb9c1b512016-09-06 20:57:50 +000052 File m_file;
53 std::unique_ptr<lldb_private::LockFile> m_lock;
54 FileSpec m_file_spec;
Oleksiy Vyalov2b38f332015-09-18 18:12:39 +000055
56public:
Kate Stoneb9c1b512016-09-06 20:57:50 +000057 ModuleLock(const FileSpec &root_dir_spec, const UUID &uuid, Error &error);
58 void Delete();
Oleksiy Vyalov2b38f332015-09-18 18:12:39 +000059};
60
Zachary Turner7d86ee52017-03-08 17:56:08 +000061static FileSpec JoinPath(const FileSpec &path1, const char *path2) {
Kate Stoneb9c1b512016-09-06 20:57:50 +000062 FileSpec result_spec(path1);
63 result_spec.AppendPathComponent(path2);
64 return result_spec;
Oleksiy Vyalov63acdfd2015-03-10 01:15:28 +000065}
66
Zachary Turner7d86ee52017-03-08 17:56:08 +000067static Error MakeDirectory(const FileSpec &dir_path) {
68 namespace fs = llvm::sys::fs;
Oleksiy Vyalov63acdfd2015-03-10 01:15:28 +000069
Zachary Turner7d86ee52017-03-08 17:56:08 +000070 return fs::create_directories(dir_path.GetPath(), true, fs::perms::owner_all);
Oleksiy Vyalov63acdfd2015-03-10 01:15:28 +000071}
72
Kate Stoneb9c1b512016-09-06 20:57:50 +000073FileSpec GetModuleDirectory(const FileSpec &root_dir_spec, const UUID &uuid) {
74 const auto modules_dir_spec = JoinPath(root_dir_spec, kModulesSubdir);
75 return JoinPath(modules_dir_spec, uuid.GetAsString().c_str());
Oleksiy Vyalova9ea0712015-05-08 23:54:34 +000076}
77
Kate Stoneb9c1b512016-09-06 20:57:50 +000078FileSpec GetSymbolFileSpec(const FileSpec &module_file_spec) {
Malcolm Parsons771ef6d2016-11-02 20:34:10 +000079 return FileSpec(module_file_spec.GetPath() + kSymFileExtension, false);
Oleksiy Vyalov2b38f332015-09-18 18:12:39 +000080}
81
Kate Stoneb9c1b512016-09-06 20:57:50 +000082void DeleteExistingModule(const FileSpec &root_dir_spec,
83 const FileSpec &sysroot_module_path_spec) {
84 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_MODULES));
85 UUID module_uuid;
86 {
87 auto module_sp =
88 std::make_shared<Module>(ModuleSpec(sysroot_module_path_spec));
89 module_uuid = module_sp->GetUUID();
90 }
Oleksiy Vyalov2b38f332015-09-18 18:12:39 +000091
Kate Stoneb9c1b512016-09-06 20:57:50 +000092 if (!module_uuid.IsValid())
93 return;
Oleksiy Vyalov2b38f332015-09-18 18:12:39 +000094
Kate Stoneb9c1b512016-09-06 20:57:50 +000095 Error error;
96 ModuleLock lock(root_dir_spec, module_uuid, error);
97 if (error.Fail()) {
98 if (log)
99 log->Printf("Failed to lock module %s: %s",
100 module_uuid.GetAsString().c_str(), error.AsCString());
101 }
Oleksiy Vyalov2b38f332015-09-18 18:12:39 +0000102
Zachary Turner07db3f72017-03-21 05:47:57 +0000103 namespace fs = llvm::sys::fs;
104 fs::file_status st;
105 if (status(sysroot_module_path_spec.GetPath(), st))
Kate Stoneb9c1b512016-09-06 20:57:50 +0000106 return;
Oleksiy Vyalov2b38f332015-09-18 18:12:39 +0000107
Zachary Turner07db3f72017-03-21 05:47:57 +0000108 if (st.getLinkCount() > 2) // module is referred by other hosts.
Kate Stoneb9c1b512016-09-06 20:57:50 +0000109 return;
Oleksiy Vyalov2b38f332015-09-18 18:12:39 +0000110
Kate Stoneb9c1b512016-09-06 20:57:50 +0000111 const auto module_spec_dir = GetModuleDirectory(root_dir_spec, module_uuid);
Zachary Turnerd82067f2017-03-09 05:12:36 +0000112 llvm::sys::fs::remove_directories(module_spec_dir.GetPath());
Kate Stoneb9c1b512016-09-06 20:57:50 +0000113 lock.Delete();
Oleksiy Vyalov2b38f332015-09-18 18:12:39 +0000114}
115
Kate Stoneb9c1b512016-09-06 20:57:50 +0000116void DecrementRefExistingModule(const FileSpec &root_dir_spec,
117 const FileSpec &sysroot_module_path_spec) {
118 // Remove $platform/.cache/$uuid folder if nobody else references it.
119 DeleteExistingModule(root_dir_spec, sysroot_module_path_spec);
Oleksiy Vyalov2b38f332015-09-18 18:12:39 +0000120
Kate Stoneb9c1b512016-09-06 20:57:50 +0000121 // Remove sysroot link.
Zachary Turner07db3f72017-03-21 05:47:57 +0000122 llvm::sys::fs::remove(sysroot_module_path_spec.GetPath());
Oleksiy Vyalov2b38f332015-09-18 18:12:39 +0000123
Kate Stoneb9c1b512016-09-06 20:57:50 +0000124 FileSpec symfile_spec = GetSymbolFileSpec(sysroot_module_path_spec);
Zachary Turner07db3f72017-03-21 05:47:57 +0000125 llvm::sys::fs::remove(symfile_spec.GetPath());
Oleksiy Vyalov2b38f332015-09-18 18:12:39 +0000126}
127
Kate Stoneb9c1b512016-09-06 20:57:50 +0000128Error CreateHostSysRootModuleLink(const FileSpec &root_dir_spec,
129 const char *hostname,
130 const FileSpec &platform_module_spec,
131 const FileSpec &local_module_spec,
132 bool delete_existing) {
133 const auto sysroot_module_path_spec =
134 JoinPath(JoinPath(root_dir_spec, hostname),
135 platform_module_spec.GetPath().c_str());
136 if (sysroot_module_path_spec.Exists()) {
137 if (!delete_existing)
Mehdi Aminic1edf562016-11-11 04:29:25 +0000138 return Error();
Oleksiy Vyalov2b38f332015-09-18 18:12:39 +0000139
Kate Stoneb9c1b512016-09-06 20:57:50 +0000140 DecrementRefExistingModule(root_dir_spec, sysroot_module_path_spec);
141 }
Oleksiy Vyalova9ea0712015-05-08 23:54:34 +0000142
Kate Stoneb9c1b512016-09-06 20:57:50 +0000143 const auto error = MakeDirectory(
144 FileSpec(sysroot_module_path_spec.GetDirectory().AsCString(), false));
145 if (error.Fail())
146 return error;
Oleksiy Vyalova9ea0712015-05-08 23:54:34 +0000147
Zachary Turner07db3f72017-03-21 05:47:57 +0000148 return llvm::sys::fs::create_hard_link(local_module_spec.GetPath(),
149 sysroot_module_path_spec.GetPath());
Oleksiy Vyalova9ea0712015-05-08 23:54:34 +0000150}
151
Kate Stoneb9c1b512016-09-06 20:57:50 +0000152} // namespace
Oleksiy Vyalov2b38f332015-09-18 18:12:39 +0000153
Kate Stoneb9c1b512016-09-06 20:57:50 +0000154ModuleLock::ModuleLock(const FileSpec &root_dir_spec, const UUID &uuid,
155 Error &error) {
156 const auto lock_dir_spec = JoinPath(root_dir_spec, kLockDirName);
157 error = MakeDirectory(lock_dir_spec);
158 if (error.Fail())
159 return;
Oleksiy Vyalov2b38f332015-09-18 18:12:39 +0000160
Kate Stoneb9c1b512016-09-06 20:57:50 +0000161 m_file_spec = JoinPath(lock_dir_spec, uuid.GetAsString().c_str());
162 m_file.Open(m_file_spec.GetCString(), File::eOpenOptionWrite |
163 File::eOpenOptionCanCreate |
164 File::eOpenOptionCloseOnExec);
165 if (!m_file) {
166 error.SetErrorToErrno();
167 return;
168 }
Oleksiy Vyalov2b38f332015-09-18 18:12:39 +0000169
Kate Stoneb9c1b512016-09-06 20:57:50 +0000170 m_lock.reset(new lldb_private::LockFile(m_file.GetDescriptor()));
171 error = m_lock->WriteLock(0, 1);
172 if (error.Fail())
173 error.SetErrorStringWithFormat("Failed to lock file: %s",
174 error.AsCString());
Tamas Berghammerec3f92a2015-08-12 11:10:25 +0000175}
176
Kate Stoneb9c1b512016-09-06 20:57:50 +0000177void ModuleLock::Delete() {
178 if (!m_file)
179 return;
Oleksiy Vyalov2b38f332015-09-18 18:12:39 +0000180
Kate Stoneb9c1b512016-09-06 20:57:50 +0000181 m_file.Close();
Zachary Turner07db3f72017-03-21 05:47:57 +0000182 llvm::sys::fs::remove(m_file_spec.GetPath());
Oleksiy Vyalov2b38f332015-09-18 18:12:39 +0000183}
184
185/////////////////////////////////////////////////////////////////////////
Oleksiy Vyalov63acdfd2015-03-10 01:15:28 +0000186
Kate Stoneb9c1b512016-09-06 20:57:50 +0000187Error ModuleCache::Put(const FileSpec &root_dir_spec, const char *hostname,
188 const ModuleSpec &module_spec, const FileSpec &tmp_file,
189 const FileSpec &target_file) {
190 const auto module_spec_dir =
191 GetModuleDirectory(root_dir_spec, module_spec.GetUUID());
192 const auto module_file_path =
193 JoinPath(module_spec_dir, target_file.GetFilename().AsCString());
Oleksiy Vyalov63acdfd2015-03-10 01:15:28 +0000194
Kate Stoneb9c1b512016-09-06 20:57:50 +0000195 const auto tmp_file_path = tmp_file.GetPath();
Malcolm Parsons771ef6d2016-11-02 20:34:10 +0000196 const auto err_code =
197 llvm::sys::fs::rename(tmp_file_path, module_file_path.GetPath());
Kate Stoneb9c1b512016-09-06 20:57:50 +0000198 if (err_code)
199 return Error("Failed to rename file %s to %s: %s", tmp_file_path.c_str(),
200 module_file_path.GetPath().c_str(),
201 err_code.message().c_str());
Oleksiy Vyalov63acdfd2015-03-10 01:15:28 +0000202
Kate Stoneb9c1b512016-09-06 20:57:50 +0000203 const auto error = CreateHostSysRootModuleLink(
204 root_dir_spec, hostname, target_file, module_file_path, true);
205 if (error.Fail())
206 return Error("Failed to create link to %s: %s",
207 module_file_path.GetPath().c_str(), error.AsCString());
Mehdi Aminic1edf562016-11-11 04:29:25 +0000208 return Error();
Oleksiy Vyalov63acdfd2015-03-10 01:15:28 +0000209}
210
Kate Stoneb9c1b512016-09-06 20:57:50 +0000211Error ModuleCache::Get(const FileSpec &root_dir_spec, const char *hostname,
212 const ModuleSpec &module_spec,
213 ModuleSP &cached_module_sp, bool *did_create_ptr) {
214 const auto find_it =
215 m_loaded_modules.find(module_spec.GetUUID().GetAsString());
216 if (find_it != m_loaded_modules.end()) {
217 cached_module_sp = (*find_it).second.lock();
218 if (cached_module_sp)
Mehdi Aminic1edf562016-11-11 04:29:25 +0000219 return Error();
Kate Stoneb9c1b512016-09-06 20:57:50 +0000220 m_loaded_modules.erase(find_it);
221 }
Oleksiy Vyaloveda270e2015-03-12 18:18:03 +0000222
Kate Stoneb9c1b512016-09-06 20:57:50 +0000223 const auto module_spec_dir =
224 GetModuleDirectory(root_dir_spec, module_spec.GetUUID());
225 const auto module_file_path = JoinPath(
226 module_spec_dir, module_spec.GetFileSpec().GetFilename().AsCString());
Oleksiy Vyaloveda270e2015-03-12 18:18:03 +0000227
Kate Stoneb9c1b512016-09-06 20:57:50 +0000228 if (!module_file_path.Exists())
229 return Error("Module %s not found", module_file_path.GetPath().c_str());
230 if (module_file_path.GetByteSize() != module_spec.GetObjectSize())
231 return Error("Module %s has invalid file size",
232 module_file_path.GetPath().c_str());
Oleksiy Vyalov63acdfd2015-03-10 01:15:28 +0000233
Kate Stoneb9c1b512016-09-06 20:57:50 +0000234 // We may have already cached module but downloaded from an another host - in
235 // this case let's create a link to it.
236 auto error = CreateHostSysRootModuleLink(root_dir_spec, hostname,
237 module_spec.GetFileSpec(),
238 module_file_path, false);
239 if (error.Fail())
240 return Error("Failed to create link to %s: %s",
241 module_file_path.GetPath().c_str(), error.AsCString());
Oleksiy Vyalov63acdfd2015-03-10 01:15:28 +0000242
Kate Stoneb9c1b512016-09-06 20:57:50 +0000243 auto cached_module_spec(module_spec);
244 cached_module_spec.GetUUID().Clear(); // Clear UUID since it may contain md5
245 // content hash instead of real UUID.
246 cached_module_spec.GetFileSpec() = module_file_path;
247 cached_module_spec.GetPlatformFileSpec() = module_spec.GetFileSpec();
Tamas Berghammerec3f92a2015-08-12 11:10:25 +0000248
Kate Stoneb9c1b512016-09-06 20:57:50 +0000249 error = ModuleList::GetSharedModule(cached_module_spec, cached_module_sp,
250 nullptr, nullptr, did_create_ptr, false);
251 if (error.Fail())
252 return error;
Tamas Berghammerec3f92a2015-08-12 11:10:25 +0000253
Kate Stoneb9c1b512016-09-06 20:57:50 +0000254 FileSpec symfile_spec = GetSymbolFileSpec(cached_module_sp->GetFileSpec());
255 if (symfile_spec.Exists())
256 cached_module_sp->SetSymbolFileFileSpec(symfile_spec);
Oleksiy Vyaloveda270e2015-03-12 18:18:03 +0000257
Kate Stoneb9c1b512016-09-06 20:57:50 +0000258 m_loaded_modules.insert(
259 std::make_pair(module_spec.GetUUID().GetAsString(), cached_module_sp));
260
Mehdi Aminic1edf562016-11-11 04:29:25 +0000261 return Error();
Oleksiy Vyalov63acdfd2015-03-10 01:15:28 +0000262}
263
Kate Stoneb9c1b512016-09-06 20:57:50 +0000264Error ModuleCache::GetAndPut(const FileSpec &root_dir_spec,
265 const char *hostname,
266 const ModuleSpec &module_spec,
267 const ModuleDownloader &module_downloader,
268 const SymfileDownloader &symfile_downloader,
269 lldb::ModuleSP &cached_module_sp,
270 bool *did_create_ptr) {
271 const auto module_spec_dir =
272 GetModuleDirectory(root_dir_spec, module_spec.GetUUID());
273 auto error = MakeDirectory(module_spec_dir);
274 if (error.Fail())
275 return error;
Oleksiy Vyalov919ef9d2015-05-07 15:28:49 +0000276
Kate Stoneb9c1b512016-09-06 20:57:50 +0000277 ModuleLock lock(root_dir_spec, module_spec.GetUUID(), error);
278 if (error.Fail())
279 return Error("Failed to lock module %s: %s",
280 module_spec.GetUUID().GetAsString().c_str(),
281 error.AsCString());
Oleksiy Vyalov919ef9d2015-05-07 15:28:49 +0000282
Kate Stoneb9c1b512016-09-06 20:57:50 +0000283 const auto escaped_hostname(GetEscapedHostname(hostname));
284 // Check local cache for a module.
285 error = Get(root_dir_spec, escaped_hostname.c_str(), module_spec,
286 cached_module_sp, did_create_ptr);
287 if (error.Success())
288 return error;
Oleksiy Vyalov280d8dc2015-04-15 14:35:10 +0000289
Kate Stoneb9c1b512016-09-06 20:57:50 +0000290 const auto tmp_download_file_spec = JoinPath(module_spec_dir, kTempFileName);
291 error = module_downloader(module_spec, tmp_download_file_spec);
Malcolm Parsons771ef6d2016-11-02 20:34:10 +0000292 llvm::FileRemover tmp_file_remover(tmp_download_file_spec.GetPath());
Kate Stoneb9c1b512016-09-06 20:57:50 +0000293 if (error.Fail())
294 return Error("Failed to download module: %s", error.AsCString());
Oleksiy Vyalov280d8dc2015-04-15 14:35:10 +0000295
Kate Stoneb9c1b512016-09-06 20:57:50 +0000296 // Put downloaded file into local module cache.
297 error = Put(root_dir_spec, escaped_hostname.c_str(), module_spec,
298 tmp_download_file_spec, module_spec.GetFileSpec());
299 if (error.Fail())
300 return Error("Failed to put module into cache: %s", error.AsCString());
Oleksiy Vyalov280d8dc2015-04-15 14:35:10 +0000301
Kate Stoneb9c1b512016-09-06 20:57:50 +0000302 tmp_file_remover.releaseFile();
303 error = Get(root_dir_spec, escaped_hostname.c_str(), module_spec,
304 cached_module_sp, did_create_ptr);
305 if (error.Fail())
306 return error;
Tamas Berghammerec3f92a2015-08-12 11:10:25 +0000307
Kate Stoneb9c1b512016-09-06 20:57:50 +0000308 // Fetching a symbol file for the module
309 const auto tmp_download_sym_file_spec =
310 JoinPath(module_spec_dir, kTempSymFileName);
311 error = symfile_downloader(cached_module_sp, tmp_download_sym_file_spec);
Malcolm Parsons771ef6d2016-11-02 20:34:10 +0000312 llvm::FileRemover tmp_symfile_remover(tmp_download_sym_file_spec.GetPath());
Kate Stoneb9c1b512016-09-06 20:57:50 +0000313 if (error.Fail())
314 // Failed to download a symfile but fetching the module was successful. The
315 // module might
316 // contain the necessary symbols and the debugging is also possible without
317 // a symfile.
Mehdi Aminic1edf562016-11-11 04:29:25 +0000318 return Error();
Tamas Berghammerec3f92a2015-08-12 11:10:25 +0000319
Kate Stoneb9c1b512016-09-06 20:57:50 +0000320 error = Put(root_dir_spec, escaped_hostname.c_str(), module_spec,
321 tmp_download_sym_file_spec,
322 GetSymbolFileSpec(module_spec.GetFileSpec()));
323 if (error.Fail())
324 return Error("Failed to put symbol file into cache: %s", error.AsCString());
Tamas Berghammerec3f92a2015-08-12 11:10:25 +0000325
Kate Stoneb9c1b512016-09-06 20:57:50 +0000326 tmp_symfile_remover.releaseFile();
327
328 FileSpec symfile_spec = GetSymbolFileSpec(cached_module_sp->GetFileSpec());
329 cached_module_sp->SetSymbolFileFileSpec(symfile_spec);
Mehdi Aminic1edf562016-11-11 04:29:25 +0000330 return Error();
Oleksiy Vyalov280d8dc2015-04-15 14:35:10 +0000331}