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