diff options
Diffstat (limited to 'source/Target/Platform.cpp')
-rw-r--r-- | source/Target/Platform.cpp | 498 |
1 files changed, 420 insertions, 78 deletions
diff --git a/source/Target/Platform.cpp b/source/Target/Platform.cpp index 09c9efc..6758ecf 100644 --- a/source/Target/Platform.cpp +++ b/source/Target/Platform.cpp @@ -10,25 +10,47 @@ #include "lldb/Target/Platform.h" // C Includes + // C++ Includes +#include <algorithm> +#include <fstream> +#include <vector> + // Other libraries and framework includes // Project includes #include "lldb/Breakpoint/BreakpointIDList.h" +#include "lldb/Core/DataBufferHeap.h" +#include "lldb/Core/Debugger.h" #include "lldb/Core/Error.h" #include "lldb/Core/Log.h" +#include "lldb/Core/Module.h" #include "lldb/Core/ModuleSpec.h" #include "lldb/Core/PluginManager.h" +#include "lldb/Core/StructuredData.h" #include "lldb/Host/FileSpec.h" #include "lldb/Host/FileSystem.h" #include "lldb/Host/Host.h" #include "lldb/Host/HostInfo.h" +#include "lldb/Interpreter/OptionValueProperties.h" +#include "lldb/Interpreter/Property.h" +#include "lldb/Symbol/ObjectFile.h" #include "lldb/Target/Process.h" #include "lldb/Target/Target.h" #include "lldb/Utility/Utils.h" +#include "llvm/Support/FileSystem.h" + +#include "Utility/ModuleCache.h" + +// Define these constants from POSIX mman.h rather than include the file +// so that they will be correct even when compiled on Linux. +#define MAP_PRIVATE 2 +#define MAP_ANON 0x1000 using namespace lldb; using namespace lldb_private; - + +static uint32_t g_initialize_count = 0; + // Use a singleton function for g_local_platform_sp to avoid init // constructors since LLDB is often part of a shared library static PlatformSP& @@ -44,6 +66,73 @@ Platform::GetHostPlatformName () return "host"; } +namespace { + + PropertyDefinition + g_properties[] = + { + { "use-module-cache" , OptionValue::eTypeBoolean , true, true, nullptr, nullptr, "Use module cache." }, + { "module-cache-directory", OptionValue::eTypeFileSpec, true, 0 , nullptr, nullptr, "Root directory for cached modules." }, + { nullptr , OptionValue::eTypeInvalid , false, 0, nullptr, nullptr, nullptr } + }; + + enum + { + ePropertyUseModuleCache, + ePropertyModuleCacheDirectory + }; + +} // namespace + + +ConstString +PlatformProperties::GetSettingName () +{ + static ConstString g_setting_name("platform"); + return g_setting_name; +} + +PlatformProperties::PlatformProperties () +{ + m_collection_sp.reset (new OptionValueProperties (GetSettingName ())); + m_collection_sp->Initialize (g_properties); + + auto module_cache_dir = GetModuleCacheDirectory (); + if (!module_cache_dir) + { + if (!HostInfo::GetLLDBPath (ePathTypeGlobalLLDBTempSystemDir, module_cache_dir)) + module_cache_dir = FileSpec ("/tmp/lldb", false); + module_cache_dir.AppendPathComponent ("module_cache"); + SetModuleCacheDirectory (module_cache_dir); + } +} + +bool +PlatformProperties::GetUseModuleCache () const +{ + const auto idx = ePropertyUseModuleCache; + return m_collection_sp->GetPropertyAtIndexAsBoolean ( + nullptr, idx, g_properties[idx].default_uint_value != 0); +} + +bool +PlatformProperties::SetUseModuleCache (bool use_module_cache) +{ + return m_collection_sp->SetPropertyAtIndexAsBoolean (nullptr, ePropertyUseModuleCache, use_module_cache); +} + +FileSpec +PlatformProperties::GetModuleCacheDirectory () const +{ + return m_collection_sp->GetPropertyAtIndexAsFileSpec (nullptr, ePropertyModuleCacheDirectory); +} + +bool +PlatformProperties::SetModuleCacheDirectory (const FileSpec& dir_spec) +{ + return m_collection_sp->SetPropertyAtIndexAsFileSpec (nullptr, ePropertyModuleCacheDirectory, dir_spec); +} + //------------------------------------------------------------------ /// Get the native host platform plug-in. /// @@ -75,6 +164,32 @@ GetPlatformListMutex () } void +Platform::Initialize () +{ + g_initialize_count++; +} + +void +Platform::Terminate () +{ + if (g_initialize_count > 0) + { + if (--g_initialize_count == 0) + { + Mutex::Locker locker(GetPlatformListMutex ()); + GetPlatformList().clear(); + } + } +} + +const PlatformPropertiesSP & +Platform::GetGlobalPlatformProperties () +{ + static const auto g_settings_sp (std::make_shared<PlatformProperties> ()); + return g_settings_sp; +} + +void Platform::SetHostPlatform (const lldb::PlatformSP &platform_sp) { // The native platform should use its static void Platform::Initialize() @@ -137,25 +252,43 @@ Platform::LocateExecutableScriptingResources (Target *target, Module &module, St Error Platform::GetSharedModule (const ModuleSpec &module_spec, + Process* process, ModuleSP &module_sp, const FileSpecList *module_search_paths_ptr, ModuleSP *old_module_sp_ptr, bool *did_create_ptr) { - // Don't do any path remapping for the default implementation - // of the platform GetSharedModule function, just call through - // to our static ModuleList function. Platform subclasses that - // implement remote debugging, might have a developer kits - // installed that have cached versions of the files for the - // remote target, or might implement a download and cache - // locally implementation. - const bool always_create = false; - return ModuleList::GetSharedModule (module_spec, - module_sp, - module_search_paths_ptr, - old_module_sp_ptr, - did_create_ptr, - always_create); + if (IsHost ()) + return ModuleList::GetSharedModule (module_spec, + module_sp, + module_search_paths_ptr, + old_module_sp_ptr, + did_create_ptr, + false); + + return GetRemoteSharedModule (module_spec, + process, + module_sp, + [&](const ModuleSpec &spec) + { + return ModuleList::GetSharedModule ( + spec, module_sp, module_search_paths_ptr, old_module_sp_ptr, did_create_ptr, false); + }, + did_create_ptr); +} + +bool +Platform::GetModuleSpec (const FileSpec& module_file_spec, + const ArchSpec& arch, + ModuleSpec &module_spec) +{ + ModuleSpecList module_specs; + if (ObjectFile::GetModuleSpecifications (module_file_spec, 0, 0, module_specs) == 0) + return false; + + ModuleSpec matched_module_spec; + return module_specs.FindMatchingModuleSpec (ModuleSpec (module_file_spec, arch), + module_spec); } PlatformSP @@ -298,7 +431,8 @@ Platform::Platform (bool is_host) : m_ssh_opts (), m_ignores_remote_hostname (false), m_trap_handlers(), - m_calculated_trap_handlers (false) + m_calculated_trap_handlers (false), + m_module_cache (llvm::make_unique<ModuleCache> ()) { Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_OBJECT)); if (log) @@ -476,16 +610,16 @@ Platform::AddClangModuleCompilationOptions (Target *target, std::vector<std::str } -ConstString +FileSpec Platform::GetWorkingDirectory () { if (IsHost()) { char cwd[PATH_MAX]; if (getcwd(cwd, sizeof(cwd))) - return ConstString(cwd); + return FileSpec{cwd, true}; else - return ConstString(); + return FileSpec{}; } else { @@ -524,11 +658,11 @@ RecurseCopy_Callback (void *baton, FileSpec dst_dir = rc_baton->dst; if (!dst_dir.GetFilename()) dst_dir.GetFilename() = src.GetLastPathComponent(); - std::string dst_dir_path (dst_dir.GetPath()); - Error error = rc_baton->platform_ptr->MakeDirectory(dst_dir_path.c_str(), lldb::eFilePermissionsDirectoryDefault); + Error error = rc_baton->platform_ptr->MakeDirectory(dst_dir, lldb::eFilePermissionsDirectoryDefault); if (error.Fail()) { - rc_baton->error.SetErrorStringWithFormat("unable to setup directory %s on remote end", dst_dir_path.c_str()); + rc_baton->error.SetErrorStringWithFormat("unable to setup directory %s on remote end", + dst_dir.GetCString()); return FileSpec::eEnumerateDirectoryResultQuit; // got an error, bail out } @@ -556,15 +690,15 @@ RecurseCopy_Callback (void *baton, FileSpec dst_file = rc_baton->dst; if (!dst_file.GetFilename()) dst_file.GetFilename() = src.GetFilename(); - - char buf[PATH_MAX]; - rc_baton->error = FileSystem::Readlink(src.GetPath().c_str(), buf, sizeof(buf)); + FileSpec src_resolved; + + rc_baton->error = FileSystem::Readlink(src, src_resolved); if (rc_baton->error.Fail()) return FileSpec::eEnumerateDirectoryResultQuit; // got an error, bail out - - rc_baton->error = rc_baton->platform_ptr->CreateSymlink(dst_file.GetPath().c_str(), buf); + + rc_baton->error = rc_baton->platform_ptr->CreateSymlink(dst_file, src_resolved); if (rc_baton->error.Fail()) return FileSpec::eEnumerateDirectoryResultQuit; // got an error, bail out @@ -611,7 +745,7 @@ Platform::Install (const FileSpec& src, const FileSpec& dst) if (!fixed_dst.GetFilename()) fixed_dst.GetFilename() = src.GetFilename(); - ConstString working_dir = GetWorkingDirectory(); + FileSpec working_dir = GetWorkingDirectory(); if (dst) { @@ -631,8 +765,8 @@ Platform::Install (const FileSpec& src, const FileSpec& dst) std::string path; if (working_dir) { - relative_spec.SetFile(working_dir.GetCString(), false); - relative_spec.AppendPathComponent(dst.GetPath().c_str()); + relative_spec = working_dir; + relative_spec.AppendPathComponent(dst.GetPath()); fixed_dst.GetDirectory() = relative_spec.GetDirectory(); } else @@ -646,7 +780,7 @@ Platform::Install (const FileSpec& src, const FileSpec& dst) { if (working_dir) { - fixed_dst.GetDirectory() = working_dir; + fixed_dst.GetDirectory().SetCString(working_dir.GetCString()); } else { @@ -659,7 +793,7 @@ Platform::Install (const FileSpec& src, const FileSpec& dst) { if (working_dir) { - fixed_dst.GetDirectory() = working_dir; + fixed_dst.GetDirectory().SetCString(working_dir.GetCString()); } else { @@ -682,18 +816,17 @@ Platform::Install (const FileSpec& src, const FileSpec& dst) case FileSpec::eFileTypeDirectory: { if (GetFileExists (fixed_dst)) - Unlink (fixed_dst.GetPath().c_str()); + Unlink(fixed_dst); uint32_t permissions = src.GetPermissions(); if (permissions == 0) permissions = eFilePermissionsDirectoryDefault; - std::string dst_dir_path(fixed_dst.GetPath()); - error = MakeDirectory(dst_dir_path.c_str(), permissions); + error = MakeDirectory(fixed_dst, permissions); if (error.Success()) { // Make a filespec that only fills in the directory of a FileSpec so // when we enumerate we can quickly fill in the filename for dst copies FileSpec recurse_dst; - recurse_dst.GetDirectory().SetCString(dst_dir_path.c_str()); + recurse_dst.GetDirectory().SetCString(fixed_dst.GetCString()); std::string src_dir_path (src.GetPath()); RecurseCopyBaton baton = { recurse_dst, this, Error() }; FileSpec::EnumerateDirectory(src_dir_path.c_str(), true, true, true, RecurseCopy_Callback, &baton); @@ -704,18 +837,18 @@ Platform::Install (const FileSpec& src, const FileSpec& dst) case FileSpec::eFileTypeRegular: if (GetFileExists (fixed_dst)) - Unlink (fixed_dst.GetPath().c_str()); + Unlink(fixed_dst); error = PutFile(src, fixed_dst); break; case FileSpec::eFileTypeSymbolicLink: { if (GetFileExists (fixed_dst)) - Unlink (fixed_dst.GetPath().c_str()); - char buf[PATH_MAX]; - error = FileSystem::Readlink(src.GetPath().c_str(), buf, sizeof(buf)); + Unlink(fixed_dst); + FileSpec src_resolved; + error = FileSystem::Readlink(src, src_resolved); if (error.Success()) - error = CreateSymlink(dst.GetPath().c_str(), buf); + error = CreateSymlink(dst, src_resolved); } break; case FileSpec::eFileTypePipe: @@ -735,37 +868,33 @@ Platform::Install (const FileSpec& src, const FileSpec& dst) } bool -Platform::SetWorkingDirectory (const ConstString &path) +Platform::SetWorkingDirectory(const FileSpec &file_spec) { if (IsHost()) { Log *log = GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM); if (log) - log->Printf("Platform::SetWorkingDirectory('%s')", path.GetCString()); -#ifdef _WIN32 - // Not implemented on Windows - return false; -#else - if (path) + log->Printf("Platform::SetWorkingDirectory('%s')", + file_spec.GetCString()); + if (file_spec) { - if (chdir(path.GetCString()) == 0) + if (::chdir(file_spec.GetCString()) == 0) return true; } return false; -#endif } else { m_working_dir.Clear(); - return SetRemoteWorkingDirectory(path); + return SetRemoteWorkingDirectory(file_spec); } } Error -Platform::MakeDirectory (const char *path, uint32_t permissions) +Platform::MakeDirectory(const FileSpec &file_spec, uint32_t permissions) { if (IsHost()) - return FileSystem::MakeDirectory(path, permissions); + return FileSystem::MakeDirectory(file_spec, permissions); else { Error error; @@ -775,10 +904,10 @@ Platform::MakeDirectory (const char *path, uint32_t permissions) } Error -Platform::GetFilePermissions (const char *path, uint32_t &file_permissions) +Platform::GetFilePermissions(const FileSpec &file_spec, uint32_t &file_permissions) { if (IsHost()) - return FileSystem::GetFilePermissions(path, file_permissions); + return FileSystem::GetFilePermissions(file_spec, file_permissions); else { Error error; @@ -788,10 +917,10 @@ Platform::GetFilePermissions (const char *path, uint32_t &file_permissions) } Error -Platform::SetFilePermissions (const char *path, uint32_t file_permissions) +Platform::SetFilePermissions(const FileSpec &file_spec, uint32_t file_permissions) { if (IsHost()) - return FileSystem::SetFilePermissions(path, file_permissions); + return FileSystem::SetFilePermissions(file_spec, file_permissions); else { Error error; @@ -818,12 +947,13 @@ Platform::GetHostname () } bool -Platform::SetRemoteWorkingDirectory(const ConstString &path) +Platform::SetRemoteWorkingDirectory(const FileSpec &working_dir) { Log *log = GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM); if (log) - log->Printf("Platform::SetRemoteWorkingDirectory('%s')", path.GetCString()); - m_working_dir = path; + log->Printf("Platform::SetRemoteWorkingDirectory('%s')", + working_dir.GetCString()); + m_working_dir = working_dir; return true; } @@ -1092,6 +1222,12 @@ Platform::LaunchProcess (ProcessLaunchInfo &launch_info) num_resumes)) return error; } + else if (launch_info.GetFlags().Test(eLaunchFlagShellExpandArguments)) + { + error = ShellExpandArguments(launch_info); + if (error.Fail()) + return error; + } if (log) log->Printf ("Platform::%s final launch_info resume count: %" PRIu32, __FUNCTION__, launch_info.GetResumeCount ()); @@ -1104,16 +1240,41 @@ Platform::LaunchProcess (ProcessLaunchInfo &launch_info) } Error +Platform::ShellExpandArguments (ProcessLaunchInfo &launch_info) +{ + if (IsHost()) + return Host::ShellExpandArguments(launch_info); + return Error("base lldb_private::Platform class can't expand arguments"); +} + +Error Platform::KillProcess (const lldb::pid_t pid) { Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PLATFORM)); if (log) log->Printf ("Platform::%s, pid %" PRIu64, __FUNCTION__, pid); - if (!IsHost ()) - return Error ("base lldb_private::Platform class can't launch remote processes"); + // Try to find a process plugin to handle this Kill request. If we can't, fall back to + // the default OS implementation. + size_t num_debuggers = Debugger::GetNumDebuggers(); + for (size_t didx = 0; didx < num_debuggers; ++didx) + { + DebuggerSP debugger = Debugger::GetDebuggerAtIndex(didx); + lldb_private::TargetList &targets = debugger->GetTargetList(); + for (int tidx = 0; tidx < targets.GetNumTargets(); ++tidx) + { + ProcessSP process = targets.GetTargetAtIndex(tidx)->GetProcessSP(); + if (process->GetID() == pid) + return process->Destroy(true); + } + } - Host::Kill (pid, SIGTERM); + if (!IsHost()) + { + return Error("base lldb_private::Platform class can't kill remote processes unless " + "they are controlled by a process plugin"); + } + Host::Kill(pid, SIGTERM); return Error(); } @@ -1251,7 +1412,7 @@ Platform::PutFile (const FileSpec& source, if (log) log->Printf("[PutFile] Using block by block transfer....\n"); - uint32_t source_open_options = File::eOpenOptionRead; + uint32_t source_open_options = File::eOpenOptionRead | File::eOpenOptionCloseOnExec; if (source.GetFileType() == FileSpec::eFileTypeSymbolicLink) source_open_options |= File::eOpenoptionDontFollowSymlinks; @@ -1266,7 +1427,8 @@ Platform::PutFile (const FileSpec& source, lldb::user_id_t dest_file = OpenFile (destination, File::eOpenOptionCanCreate | File::eOpenOptionWrite | - File::eOpenOptionTruncate, + File::eOpenOptionTruncate | + File::eOpenOptionCloseOnExec, permissions, error); if (log) @@ -1309,43 +1471,52 @@ Platform::PutFile (const FileSpec& source, } Error -Platform::GetFile (const FileSpec& source, - const FileSpec& destination) +Platform::GetFile(const FileSpec &source, + const FileSpec &destination) { Error error("unimplemented"); return error; } Error -Platform::CreateSymlink (const char *src, // The name of the link is in src - const char *dst)// The symlink points to dst +Platform::CreateSymlink(const FileSpec &src, // The name of the link is in src + const FileSpec &dst) // The symlink points to dst { Error error("unimplemented"); return error; } bool -Platform::GetFileExists (const lldb_private::FileSpec& file_spec) +Platform::GetFileExists(const lldb_private::FileSpec &file_spec) { return false; } Error -Platform::Unlink (const char *path) +Platform::Unlink(const FileSpec &path) { Error error("unimplemented"); return error; } - +uint64_t +Platform::ConvertMmapFlagsToPlatform(const ArchSpec &arch, unsigned flags) +{ + uint64_t flags_platform = 0; + if (flags & eMmapFlagsPrivate) + flags_platform |= MAP_PRIVATE; + if (flags & eMmapFlagsAnon) + flags_platform |= MAP_ANON; + return flags_platform; +} lldb_private::Error -Platform::RunShellCommand (const char *command, // Shouldn't be NULL - const char *working_dir, // Pass NULL to use the current working directory - int *status_ptr, // Pass NULL if you don't want the process exit status - int *signo_ptr, // Pass NULL if you don't want the signal that caused the process to exit - std::string *command_output, // Pass NULL if you don't want the command output - uint32_t timeout_sec) // Timeout in seconds to wait for shell program to finish +Platform::RunShellCommand(const char *command, // Shouldn't be NULL + const FileSpec &working_dir, // Pass empty FileSpec to use the current working directory + int *status_ptr, // Pass NULL if you don't want the process exit status + int *signo_ptr, // Pass NULL if you don't want the signal that caused the process to exit + std::string *command_output, // Pass NULL if you don't want the command output + uint32_t timeout_sec) // Timeout in seconds to wait for shell program to finish { if (IsHost()) return Host::RunShellCommand (command, working_dir, status_ptr, signo_ptr, command_output, timeout_sec); @@ -1609,3 +1780,174 @@ Platform::GetTrapHandlerSymbolNames () return m_trap_handlers; } +Error +Platform::GetCachedExecutable (ModuleSpec &module_spec, + lldb::ModuleSP &module_sp, + const FileSpecList *module_search_paths_ptr, + Platform &remote_platform) +{ + const auto platform_spec = module_spec.GetFileSpec (); + const auto error = LoadCachedExecutable (module_spec, + module_sp, + module_search_paths_ptr, + remote_platform); + if (error.Success ()) + { + module_spec.GetFileSpec () = module_sp->GetFileSpec (); + module_spec.GetPlatformFileSpec () = platform_spec; + } + + return error; +} + +Error +Platform::LoadCachedExecutable (const ModuleSpec &module_spec, + lldb::ModuleSP &module_sp, + const FileSpecList *module_search_paths_ptr, + Platform &remote_platform) +{ + return GetRemoteSharedModule (module_spec, + nullptr, + module_sp, + [&](const ModuleSpec &spec) + { + return remote_platform.ResolveExecutable ( + spec, module_sp, module_search_paths_ptr); + }, + nullptr); +} + +Error +Platform::GetRemoteSharedModule (const ModuleSpec &module_spec, + Process* process, + lldb::ModuleSP &module_sp, + const ModuleResolver &module_resolver, + bool *did_create_ptr) +{ + // Get module information from a target. + ModuleSpec resolved_module_spec; + bool got_module_spec = false; + if (process) + { + // Try to get module information from the process + if (process->GetModuleSpec (module_spec.GetFileSpec (), module_spec.GetArchitecture (), resolved_module_spec)) + got_module_spec = true; + } + + if (!got_module_spec) + { + // Get module information from a target. + if (!GetModuleSpec (module_spec.GetFileSpec (), module_spec.GetArchitecture (), resolved_module_spec)) + return module_resolver (module_spec); + } + + // Trying to find a module by UUID on local file system. + const auto error = module_resolver (resolved_module_spec); + if (error.Fail ()) + { + if (GetCachedSharedModule (resolved_module_spec, module_sp, did_create_ptr)) + return Error (); + } + + return error; +} + +bool +Platform::GetCachedSharedModule (const ModuleSpec &module_spec, + lldb::ModuleSP &module_sp, + bool *did_create_ptr) +{ + if (IsHost() || + !GetGlobalPlatformProperties ()->GetUseModuleCache ()) + return false; + + Log *log = GetLogIfAnyCategoriesSet (LIBLLDB_LOG_PLATFORM); + + // Check local cache for a module. + auto error = m_module_cache->GetAndPut ( + GetModuleCacheRoot (), + GetCacheHostname (), + module_spec, + [=](const ModuleSpec &module_spec, const FileSpec &tmp_download_file_spec) + { + return DownloadModuleSlice (module_spec.GetFileSpec (), + module_spec.GetObjectOffset (), + module_spec.GetObjectSize (), + tmp_download_file_spec); + + }, + module_sp, + did_create_ptr); + if (error.Success ()) + return true; + + if (log) + log->Printf("Platform::%s - module %s not found in local cache: %s", + __FUNCTION__, module_spec.GetUUID ().GetAsString ().c_str (), error.AsCString ()); + return false; +} + +Error +Platform::DownloadModuleSlice (const FileSpec& src_file_spec, + const uint64_t src_offset, + const uint64_t src_size, + const FileSpec& dst_file_spec) +{ + Error error; + + std::ofstream dst (dst_file_spec.GetPath(), std::ios::out | std::ios::binary); + if (!dst.is_open()) + { + error.SetErrorStringWithFormat ("unable to open destination file: %s", dst_file_spec.GetPath ().c_str ()); + return error; + } + + auto src_fd = OpenFile (src_file_spec, + File::eOpenOptionRead, + lldb::eFilePermissionsFileDefault, + error); + + if (error.Fail ()) + { + error.SetErrorStringWithFormat ("unable to open source file: %s", error.AsCString ()); + return error; + } + + std::vector<char> buffer (1024); + auto offset = src_offset; + uint64_t total_bytes_read = 0; + while (total_bytes_read < src_size) + { + const auto to_read = std::min (static_cast<uint64_t>(buffer.size ()), src_size - total_bytes_read); + const uint64_t n_read = ReadFile (src_fd, offset, &buffer[0], to_read, error); + if (error.Fail ()) + break; + if (n_read == 0) + { + error.SetErrorString ("read 0 bytes"); + break; + } + offset += n_read; + total_bytes_read += n_read; + dst.write (&buffer[0], n_read); + } + + Error close_error; + CloseFile (src_fd, close_error); // Ignoring close error. + + return error; +} + +FileSpec +Platform::GetModuleCacheRoot () +{ + auto dir_spec = GetGlobalPlatformProperties ()->GetModuleCacheDirectory (); + dir_spec.AppendPathComponent (GetName ().AsCString ()); + return dir_spec; +} + +const char * +Platform::GetCacheHostname () +{ + return GetHostname (); +} |