blob: de02b984f4c892aa9124aea8f6c6b4075750ed9c [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
Oleksiy Vyalov2b38f332015-09-18 18:12:39 +000012#include "lldb/Core/Log.h"
Oleksiy Vyalov63acdfd2015-03-10 01:15:28 +000013#include "lldb/Core/Module.h"
Tamas Berghammer257e13a2015-12-10 17:08:23 +000014#include "lldb/Core/ModuleList.h"
Oleksiy Vyaloveda270e2015-03-12 18:18:03 +000015#include "lldb/Core/ModuleSpec.h"
Oleksiy Vyalov919ef9d2015-05-07 15:28:49 +000016#include "lldb/Host/File.h"
Oleksiy Vyalov63acdfd2015-03-10 01:15:28 +000017#include "lldb/Host/FileSystem.h"
Oleksiy Vyalov919ef9d2015-05-07 15:28:49 +000018#include "lldb/Host/LockFile.h"
Oleksiy Vyalov63acdfd2015-03-10 01:15:28 +000019#include "llvm/Support/FileSystem.h"
Oleksiy Vyalov280d8dc2015-04-15 14:35:10 +000020#include "llvm/Support/FileUtilities.h"
Oleksiy Vyalov63acdfd2015-03-10 01:15:28 +000021
22#include <assert.h>
23
24#include <cstdio>
Oleksiy Vyalov919ef9d2015-05-07 15:28:49 +000025
Oleksiy Vyalov63acdfd2015-03-10 01:15:28 +000026using namespace lldb;
27using namespace lldb_private;
28
29namespace {
30
Kate Stoneb9c1b512016-09-06 20:57:50 +000031const char *kModulesSubdir = ".cache";
32const char *kLockDirName = ".lock";
33const char *kTempFileName = ".temp";
34const char *kTempSymFileName = ".symtemp";
35const char *kSymFileExtension = ".sym";
36const char *kFSIllegalChars = "\\/:*?\"<>|";
Oleksiy Vyalov3154e772016-05-24 18:09:05 +000037
Kate Stoneb9c1b512016-09-06 20:57:50 +000038std::string GetEscapedHostname(const char *hostname) {
Jason Molenda14699cf2016-10-21 02:32:08 +000039 if (hostname == nullptr)
40 hostname = "unknown";
Kate Stoneb9c1b512016-09-06 20:57:50 +000041 std::string result(hostname);
42 size_t size = result.size();
43 for (size_t i = 0; i < size; ++i) {
44 if ((result[i] >= 1 && result[i] <= 31) ||
45 strchr(kFSIllegalChars, result[i]) != nullptr)
46 result[i] = '_';
47 }
48 return result;
Oleksiy Vyalov3154e772016-05-24 18:09:05 +000049}
Oleksiy Vyalov63acdfd2015-03-10 01:15:28 +000050
Kate Stoneb9c1b512016-09-06 20:57:50 +000051class ModuleLock {
Oleksiy Vyalov2b38f332015-09-18 18:12:39 +000052private:
Kate Stoneb9c1b512016-09-06 20:57:50 +000053 File m_file;
54 std::unique_ptr<lldb_private::LockFile> m_lock;
55 FileSpec m_file_spec;
Oleksiy Vyalov2b38f332015-09-18 18:12:39 +000056
57public:
Kate Stoneb9c1b512016-09-06 20:57:50 +000058 ModuleLock(const FileSpec &root_dir_spec, const UUID &uuid, Error &error);
59 void Delete();
Oleksiy Vyalov2b38f332015-09-18 18:12:39 +000060};
61
Kate Stoneb9c1b512016-09-06 20:57:50 +000062FileSpec JoinPath(const FileSpec &path1, const char *path2) {
63 FileSpec result_spec(path1);
64 result_spec.AppendPathComponent(path2);
65 return result_spec;
Oleksiy Vyalov63acdfd2015-03-10 01:15:28 +000066}
67
Kate Stoneb9c1b512016-09-06 20:57:50 +000068Error MakeDirectory(const FileSpec &dir_path) {
69 if (dir_path.Exists()) {
70 if (!dir_path.IsDirectory())
71 return Error("Invalid existing path");
Oleksiy Vyalov63acdfd2015-03-10 01:15:28 +000072
Mehdi Aminic1edf562016-11-11 04:29:25 +000073 return Error();
Kate Stoneb9c1b512016-09-06 20:57:50 +000074 }
Oleksiy Vyalov63acdfd2015-03-10 01:15:28 +000075
Kate Stoneb9c1b512016-09-06 20:57:50 +000076 return FileSystem::MakeDirectory(dir_path, eFilePermissionsDirectoryDefault);
Oleksiy Vyalov63acdfd2015-03-10 01:15:28 +000077}
78
Kate Stoneb9c1b512016-09-06 20:57:50 +000079FileSpec GetModuleDirectory(const FileSpec &root_dir_spec, const UUID &uuid) {
80 const auto modules_dir_spec = JoinPath(root_dir_spec, kModulesSubdir);
81 return JoinPath(modules_dir_spec, uuid.GetAsString().c_str());
Oleksiy Vyalova9ea0712015-05-08 23:54:34 +000082}
83
Kate Stoneb9c1b512016-09-06 20:57:50 +000084FileSpec GetSymbolFileSpec(const FileSpec &module_file_spec) {
Malcolm Parsons771ef6d2016-11-02 20:34:10 +000085 return FileSpec(module_file_spec.GetPath() + kSymFileExtension, false);
Oleksiy Vyalov2b38f332015-09-18 18:12:39 +000086}
87
Kate Stoneb9c1b512016-09-06 20:57:50 +000088void DeleteExistingModule(const FileSpec &root_dir_spec,
89 const FileSpec &sysroot_module_path_spec) {
90 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_MODULES));
91 UUID module_uuid;
92 {
93 auto module_sp =
94 std::make_shared<Module>(ModuleSpec(sysroot_module_path_spec));
95 module_uuid = module_sp->GetUUID();
96 }
Oleksiy Vyalov2b38f332015-09-18 18:12:39 +000097
Kate Stoneb9c1b512016-09-06 20:57:50 +000098 if (!module_uuid.IsValid())
99 return;
Oleksiy Vyalov2b38f332015-09-18 18:12:39 +0000100
Kate Stoneb9c1b512016-09-06 20:57:50 +0000101 Error error;
102 ModuleLock lock(root_dir_spec, module_uuid, error);
103 if (error.Fail()) {
104 if (log)
105 log->Printf("Failed to lock module %s: %s",
106 module_uuid.GetAsString().c_str(), error.AsCString());
107 }
Oleksiy Vyalov2b38f332015-09-18 18:12:39 +0000108
Kate Stoneb9c1b512016-09-06 20:57:50 +0000109 auto link_count = FileSystem::GetHardlinkCount(sysroot_module_path_spec);
110 if (link_count == -1)
111 return;
Oleksiy Vyalov2b38f332015-09-18 18:12:39 +0000112
Kate Stoneb9c1b512016-09-06 20:57:50 +0000113 if (link_count > 2) // module is referred by other hosts.
114 return;
Oleksiy Vyalov2b38f332015-09-18 18:12:39 +0000115
Kate Stoneb9c1b512016-09-06 20:57:50 +0000116 const auto module_spec_dir = GetModuleDirectory(root_dir_spec, module_uuid);
117 FileSystem::DeleteDirectory(module_spec_dir, true);
118 lock.Delete();
Oleksiy Vyalov2b38f332015-09-18 18:12:39 +0000119}
120
Kate Stoneb9c1b512016-09-06 20:57:50 +0000121void DecrementRefExistingModule(const FileSpec &root_dir_spec,
122 const FileSpec &sysroot_module_path_spec) {
123 // Remove $platform/.cache/$uuid folder if nobody else references it.
124 DeleteExistingModule(root_dir_spec, sysroot_module_path_spec);
Oleksiy Vyalov2b38f332015-09-18 18:12:39 +0000125
Kate Stoneb9c1b512016-09-06 20:57:50 +0000126 // Remove sysroot link.
127 FileSystem::Unlink(sysroot_module_path_spec);
Oleksiy Vyalov2b38f332015-09-18 18:12:39 +0000128
Kate Stoneb9c1b512016-09-06 20:57:50 +0000129 FileSpec symfile_spec = GetSymbolFileSpec(sysroot_module_path_spec);
130 if (symfile_spec.Exists()) // delete module's symbol file if exists.
131 FileSystem::Unlink(symfile_spec);
Oleksiy Vyalov2b38f332015-09-18 18:12:39 +0000132}
133
Kate Stoneb9c1b512016-09-06 20:57:50 +0000134Error CreateHostSysRootModuleLink(const FileSpec &root_dir_spec,
135 const char *hostname,
136 const FileSpec &platform_module_spec,
137 const FileSpec &local_module_spec,
138 bool delete_existing) {
139 const auto sysroot_module_path_spec =
140 JoinPath(JoinPath(root_dir_spec, hostname),
141 platform_module_spec.GetPath().c_str());
142 if (sysroot_module_path_spec.Exists()) {
143 if (!delete_existing)
Mehdi Aminic1edf562016-11-11 04:29:25 +0000144 return Error();
Oleksiy Vyalov2b38f332015-09-18 18:12:39 +0000145
Kate Stoneb9c1b512016-09-06 20:57:50 +0000146 DecrementRefExistingModule(root_dir_spec, sysroot_module_path_spec);
147 }
Oleksiy Vyalova9ea0712015-05-08 23:54:34 +0000148
Kate Stoneb9c1b512016-09-06 20:57:50 +0000149 const auto error = MakeDirectory(
150 FileSpec(sysroot_module_path_spec.GetDirectory().AsCString(), false));
151 if (error.Fail())
152 return error;
Oleksiy Vyalova9ea0712015-05-08 23:54:34 +0000153
Kate Stoneb9c1b512016-09-06 20:57:50 +0000154 return FileSystem::Hardlink(sysroot_module_path_spec, local_module_spec);
Oleksiy Vyalova9ea0712015-05-08 23:54:34 +0000155}
156
Kate Stoneb9c1b512016-09-06 20:57:50 +0000157} // namespace
Oleksiy Vyalov2b38f332015-09-18 18:12:39 +0000158
Kate Stoneb9c1b512016-09-06 20:57:50 +0000159ModuleLock::ModuleLock(const FileSpec &root_dir_spec, const UUID &uuid,
160 Error &error) {
161 const auto lock_dir_spec = JoinPath(root_dir_spec, kLockDirName);
162 error = MakeDirectory(lock_dir_spec);
163 if (error.Fail())
164 return;
Oleksiy Vyalov2b38f332015-09-18 18:12:39 +0000165
Kate Stoneb9c1b512016-09-06 20:57:50 +0000166 m_file_spec = JoinPath(lock_dir_spec, uuid.GetAsString().c_str());
167 m_file.Open(m_file_spec.GetCString(), File::eOpenOptionWrite |
168 File::eOpenOptionCanCreate |
169 File::eOpenOptionCloseOnExec);
170 if (!m_file) {
171 error.SetErrorToErrno();
172 return;
173 }
Oleksiy Vyalov2b38f332015-09-18 18:12:39 +0000174
Kate Stoneb9c1b512016-09-06 20:57:50 +0000175 m_lock.reset(new lldb_private::LockFile(m_file.GetDescriptor()));
176 error = m_lock->WriteLock(0, 1);
177 if (error.Fail())
178 error.SetErrorStringWithFormat("Failed to lock file: %s",
179 error.AsCString());
Tamas Berghammerec3f92a2015-08-12 11:10:25 +0000180}
181
Kate Stoneb9c1b512016-09-06 20:57:50 +0000182void ModuleLock::Delete() {
183 if (!m_file)
184 return;
Oleksiy Vyalov2b38f332015-09-18 18:12:39 +0000185
Kate Stoneb9c1b512016-09-06 20:57:50 +0000186 m_file.Close();
187 FileSystem::Unlink(m_file_spec);
Oleksiy Vyalov2b38f332015-09-18 18:12:39 +0000188}
189
190/////////////////////////////////////////////////////////////////////////
Oleksiy Vyalov63acdfd2015-03-10 01:15:28 +0000191
Kate Stoneb9c1b512016-09-06 20:57:50 +0000192Error ModuleCache::Put(const FileSpec &root_dir_spec, const char *hostname,
193 const ModuleSpec &module_spec, const FileSpec &tmp_file,
194 const FileSpec &target_file) {
195 const auto module_spec_dir =
196 GetModuleDirectory(root_dir_spec, module_spec.GetUUID());
197 const auto module_file_path =
198 JoinPath(module_spec_dir, target_file.GetFilename().AsCString());
Oleksiy Vyalov63acdfd2015-03-10 01:15:28 +0000199
Kate Stoneb9c1b512016-09-06 20:57:50 +0000200 const auto tmp_file_path = tmp_file.GetPath();
Malcolm Parsons771ef6d2016-11-02 20:34:10 +0000201 const auto err_code =
202 llvm::sys::fs::rename(tmp_file_path, module_file_path.GetPath());
Kate Stoneb9c1b512016-09-06 20:57:50 +0000203 if (err_code)
204 return Error("Failed to rename file %s to %s: %s", tmp_file_path.c_str(),
205 module_file_path.GetPath().c_str(),
206 err_code.message().c_str());
Oleksiy Vyalov63acdfd2015-03-10 01:15:28 +0000207
Kate Stoneb9c1b512016-09-06 20:57:50 +0000208 const auto error = CreateHostSysRootModuleLink(
209 root_dir_spec, hostname, target_file, module_file_path, true);
210 if (error.Fail())
211 return Error("Failed to create link to %s: %s",
212 module_file_path.GetPath().c_str(), error.AsCString());
Mehdi Aminic1edf562016-11-11 04:29:25 +0000213 return Error();
Oleksiy Vyalov63acdfd2015-03-10 01:15:28 +0000214}
215
Kate Stoneb9c1b512016-09-06 20:57:50 +0000216Error ModuleCache::Get(const FileSpec &root_dir_spec, const char *hostname,
217 const ModuleSpec &module_spec,
218 ModuleSP &cached_module_sp, bool *did_create_ptr) {
219 const auto find_it =
220 m_loaded_modules.find(module_spec.GetUUID().GetAsString());
221 if (find_it != m_loaded_modules.end()) {
222 cached_module_sp = (*find_it).second.lock();
223 if (cached_module_sp)
Mehdi Aminic1edf562016-11-11 04:29:25 +0000224 return Error();
Kate Stoneb9c1b512016-09-06 20:57:50 +0000225 m_loaded_modules.erase(find_it);
226 }
Oleksiy Vyaloveda270e2015-03-12 18:18:03 +0000227
Kate Stoneb9c1b512016-09-06 20:57:50 +0000228 const auto module_spec_dir =
229 GetModuleDirectory(root_dir_spec, module_spec.GetUUID());
230 const auto module_file_path = JoinPath(
231 module_spec_dir, module_spec.GetFileSpec().GetFilename().AsCString());
Oleksiy Vyaloveda270e2015-03-12 18:18:03 +0000232
Kate Stoneb9c1b512016-09-06 20:57:50 +0000233 if (!module_file_path.Exists())
234 return Error("Module %s not found", module_file_path.GetPath().c_str());
235 if (module_file_path.GetByteSize() != module_spec.GetObjectSize())
236 return Error("Module %s has invalid file size",
237 module_file_path.GetPath().c_str());
Oleksiy Vyalov63acdfd2015-03-10 01:15:28 +0000238
Kate Stoneb9c1b512016-09-06 20:57:50 +0000239 // We may have already cached module but downloaded from an another host - in
240 // this case let's create a link to it.
241 auto error = CreateHostSysRootModuleLink(root_dir_spec, hostname,
242 module_spec.GetFileSpec(),
243 module_file_path, false);
244 if (error.Fail())
245 return Error("Failed to create link to %s: %s",
246 module_file_path.GetPath().c_str(), error.AsCString());
Oleksiy Vyalov63acdfd2015-03-10 01:15:28 +0000247
Kate Stoneb9c1b512016-09-06 20:57:50 +0000248 auto cached_module_spec(module_spec);
249 cached_module_spec.GetUUID().Clear(); // Clear UUID since it may contain md5
250 // content hash instead of real UUID.
251 cached_module_spec.GetFileSpec() = module_file_path;
252 cached_module_spec.GetPlatformFileSpec() = module_spec.GetFileSpec();
Tamas Berghammerec3f92a2015-08-12 11:10:25 +0000253
Kate Stoneb9c1b512016-09-06 20:57:50 +0000254 error = ModuleList::GetSharedModule(cached_module_spec, cached_module_sp,
255 nullptr, nullptr, did_create_ptr, false);
256 if (error.Fail())
257 return error;
Tamas Berghammerec3f92a2015-08-12 11:10:25 +0000258
Kate Stoneb9c1b512016-09-06 20:57:50 +0000259 FileSpec symfile_spec = GetSymbolFileSpec(cached_module_sp->GetFileSpec());
260 if (symfile_spec.Exists())
261 cached_module_sp->SetSymbolFileFileSpec(symfile_spec);
Oleksiy Vyaloveda270e2015-03-12 18:18:03 +0000262
Kate Stoneb9c1b512016-09-06 20:57:50 +0000263 m_loaded_modules.insert(
264 std::make_pair(module_spec.GetUUID().GetAsString(), cached_module_sp));
265
Mehdi Aminic1edf562016-11-11 04:29:25 +0000266 return Error();
Oleksiy Vyalov63acdfd2015-03-10 01:15:28 +0000267}
268
Kate Stoneb9c1b512016-09-06 20:57:50 +0000269Error ModuleCache::GetAndPut(const FileSpec &root_dir_spec,
270 const char *hostname,
271 const ModuleSpec &module_spec,
272 const ModuleDownloader &module_downloader,
273 const SymfileDownloader &symfile_downloader,
274 lldb::ModuleSP &cached_module_sp,
275 bool *did_create_ptr) {
276 const auto module_spec_dir =
277 GetModuleDirectory(root_dir_spec, module_spec.GetUUID());
278 auto error = MakeDirectory(module_spec_dir);
279 if (error.Fail())
280 return error;
Oleksiy Vyalov919ef9d2015-05-07 15:28:49 +0000281
Kate Stoneb9c1b512016-09-06 20:57:50 +0000282 ModuleLock lock(root_dir_spec, module_spec.GetUUID(), error);
283 if (error.Fail())
284 return Error("Failed to lock module %s: %s",
285 module_spec.GetUUID().GetAsString().c_str(),
286 error.AsCString());
Oleksiy Vyalov919ef9d2015-05-07 15:28:49 +0000287
Kate Stoneb9c1b512016-09-06 20:57:50 +0000288 const auto escaped_hostname(GetEscapedHostname(hostname));
289 // Check local cache for a module.
290 error = Get(root_dir_spec, escaped_hostname.c_str(), module_spec,
291 cached_module_sp, did_create_ptr);
292 if (error.Success())
293 return error;
Oleksiy Vyalov280d8dc2015-04-15 14:35:10 +0000294
Kate Stoneb9c1b512016-09-06 20:57:50 +0000295 const auto tmp_download_file_spec = JoinPath(module_spec_dir, kTempFileName);
296 error = module_downloader(module_spec, tmp_download_file_spec);
Malcolm Parsons771ef6d2016-11-02 20:34:10 +0000297 llvm::FileRemover tmp_file_remover(tmp_download_file_spec.GetPath());
Kate Stoneb9c1b512016-09-06 20:57:50 +0000298 if (error.Fail())
299 return Error("Failed to download module: %s", error.AsCString());
Oleksiy Vyalov280d8dc2015-04-15 14:35:10 +0000300
Kate Stoneb9c1b512016-09-06 20:57:50 +0000301 // Put downloaded file into local module cache.
302 error = Put(root_dir_spec, escaped_hostname.c_str(), module_spec,
303 tmp_download_file_spec, module_spec.GetFileSpec());
304 if (error.Fail())
305 return Error("Failed to put module into cache: %s", error.AsCString());
Oleksiy Vyalov280d8dc2015-04-15 14:35:10 +0000306
Kate Stoneb9c1b512016-09-06 20:57:50 +0000307 tmp_file_remover.releaseFile();
308 error = Get(root_dir_spec, escaped_hostname.c_str(), module_spec,
309 cached_module_sp, did_create_ptr);
310 if (error.Fail())
311 return error;
Tamas Berghammerec3f92a2015-08-12 11:10:25 +0000312
Kate Stoneb9c1b512016-09-06 20:57:50 +0000313 // Fetching a symbol file for the module
314 const auto tmp_download_sym_file_spec =
315 JoinPath(module_spec_dir, kTempSymFileName);
316 error = symfile_downloader(cached_module_sp, tmp_download_sym_file_spec);
Malcolm Parsons771ef6d2016-11-02 20:34:10 +0000317 llvm::FileRemover tmp_symfile_remover(tmp_download_sym_file_spec.GetPath());
Kate Stoneb9c1b512016-09-06 20:57:50 +0000318 if (error.Fail())
319 // Failed to download a symfile but fetching the module was successful. The
320 // module might
321 // contain the necessary symbols and the debugging is also possible without
322 // a symfile.
Mehdi Aminic1edf562016-11-11 04:29:25 +0000323 return Error();
Tamas Berghammerec3f92a2015-08-12 11:10:25 +0000324
Kate Stoneb9c1b512016-09-06 20:57:50 +0000325 error = Put(root_dir_spec, escaped_hostname.c_str(), module_spec,
326 tmp_download_sym_file_spec,
327 GetSymbolFileSpec(module_spec.GetFileSpec()));
328 if (error.Fail())
329 return Error("Failed to put symbol file into cache: %s", error.AsCString());
Tamas Berghammerec3f92a2015-08-12 11:10:25 +0000330
Kate Stoneb9c1b512016-09-06 20:57:50 +0000331 tmp_symfile_remover.releaseFile();
332
333 FileSpec symfile_spec = GetSymbolFileSpec(cached_module_sp->GetFileSpec());
334 cached_module_sp->SetSymbolFileFileSpec(symfile_spec);
Mehdi Aminic1edf562016-11-11 04:29:25 +0000335 return Error();
Oleksiy Vyalov280d8dc2015-04-15 14:35:10 +0000336}