Index: include/lldb/Core/ModuleSpec.h =================================================================== --- include/lldb/Core/ModuleSpec.h +++ include/lldb/Core/ModuleSpec.h @@ -14,6 +14,7 @@ #include "lldb/Core/Stream.h" #include "lldb/Core/UUID.h" #include "lldb/Host/FileSpec.h" +#include "lldb/Host/Mutex.h" #include "lldb/Target/PathMappingList.h" namespace lldb_private { Index: lldb.xcodeproj/project.pbxproj =================================================================== --- lldb.xcodeproj/project.pbxproj +++ lldb.xcodeproj/project.pbxproj @@ -98,6 +98,8 @@ 254FBB971A81B03100BD6378 /* SBLaunchInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 254FBB961A81B03100BD6378 /* SBLaunchInfo.h */; settings = {ATTRIBUTES = (Public, ); }; }; 254FBBA31A9166F100BD6378 /* SBAttachInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 254FBBA21A9166F100BD6378 /* SBAttachInfo.h */; settings = {ATTRIBUTES = (Public, ); }; }; 254FBBA51A91670E00BD6378 /* SBAttachInfo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 254FBBA41A91670E00BD6378 /* SBAttachInfo.cpp */; }; + 257E47171AA56C2000A62F81 /* ModuleCache.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 257E47151AA56C2000A62F81 /* ModuleCache.cpp */; }; + 257E47181AA56C2000A62F81 /* ModuleCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 257E47161AA56C2000A62F81 /* ModuleCache.h */; }; 260157C61885F51C00F875CF /* libpanel.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 260157C41885F4FF00F875CF /* libpanel.dylib */; }; 260157C81885F53100F875CF /* libpanel.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 260157C41885F4FF00F875CF /* libpanel.dylib */; }; 2606EDDF184E68A10034641B /* liblldb-core.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 2689FFCA13353D7A00698AC0 /* liblldb-core.a */; }; @@ -1211,6 +1213,8 @@ 254FBBA21A9166F100BD6378 /* SBAttachInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SBAttachInfo.h; path = include/lldb/API/SBAttachInfo.h; sourceTree = ""; }; 254FBBA41A91670E00BD6378 /* SBAttachInfo.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SBAttachInfo.cpp; path = source/API/SBAttachInfo.cpp; sourceTree = ""; }; 254FBBA61A91672800BD6378 /* SBAttachInfo.i */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c.preprocessed; path = SBAttachInfo.i; sourceTree = ""; }; + 257E47151AA56C2000A62F81 /* ModuleCache.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ModuleCache.cpp; path = source/Utility/ModuleCache.cpp; sourceTree = ""; }; + 257E47161AA56C2000A62F81 /* ModuleCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ModuleCache.h; path = source/Utility/ModuleCache.h; sourceTree = ""; }; 260157C41885F4FF00F875CF /* libpanel.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libpanel.dylib; path = /usr/lib/libpanel.dylib; sourceTree = ""; }; 260223E7115F06D500A601A2 /* SBCommunication.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SBCommunication.h; path = include/lldb/API/SBCommunication.h; sourceTree = ""; }; 260223E8115F06E500A601A2 /* SBCommunication.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SBCommunication.cpp; path = source/API/SBCommunication.cpp; sourceTree = ""; }; @@ -3442,6 +3446,8 @@ 2682F168115ED9C800CCFF99 /* Utility */ = { isa = PBXGroup; children = ( + 257E47151AA56C2000A62F81 /* ModuleCache.cpp */, + 257E47161AA56C2000A62F81 /* ModuleCache.h */, 33064C9B1A5C7A490033D415 /* UriParser.h */, 33064C991A5C7A330033D415 /* UriParser.cpp */, AF9107E91685709A00DBCD3C /* ARM64_GCC_Registers.h */, @@ -5202,6 +5208,7 @@ buildActionMask = 2147483647; files = ( 26A527C214E24F5F00F3A14A /* ProcessMachCore.h in Headers */, + 257E47181AA56C2000A62F81 /* ModuleCache.h in Headers */, 26BC17AC18C7F4CB00D2196D /* ProcessElfCore.h in Headers */, 26A527C414E24F5F00F3A14A /* ThreadMachCore.h in Headers */, 26474CD318D0CB710073DEBA /* RegisterInfos_i386.h in Headers */, @@ -5965,6 +5972,7 @@ 25420ED21A649D88009ADBCB /* PipeBase.cpp in Sources */, 2689007313353E1A00698AC0 /* Symbols.cpp in Sources */, 26474CBC18D0CB2D0073DEBA /* RegisterContextMach_arm.cpp in Sources */, + 257E47171AA56C2000A62F81 /* ModuleCache.cpp in Sources */, 2689007413353E1A00698AC0 /* Terminal.cpp in Sources */, 2689007513353E1A00698AC0 /* TimeValue.cpp in Sources */, 2689007613353E1A00698AC0 /* CFCBundle.cpp in Sources */, Index: source/API/SBPlatform.cpp =================================================================== --- source/API/SBPlatform.cpp +++ source/API/SBPlatform.cpp @@ -347,6 +347,12 @@ Args args; args.AppendArgument(connect_options.GetURL()); sb_error.ref() = platform_sp->ConnectRemote(args); + + if (sb_error.Success()) + { + if (connect_options.GetLocalCacheDirectory()) + platform_sp->SetLocalCacheDirectory (connect_options.GetLocalCacheDirectory()); + } } else { Index: source/Core/UUID.cpp =================================================================== --- source/Core/UUID.cpp +++ source/Core/UUID.cpp @@ -234,7 +234,10 @@ // If we successfully decoded a UUID, return the amount of characters that // were consumed if (uuid_byte_idx == num_uuid_bytes) + { + m_num_uuid_bytes = num_uuid_bytes; return p - cstr; + } // Else return zero to indicate we were not able to parse a UUID value return 0; Index: source/Plugins/Platform/POSIX/PlatformPOSIX.h =================================================================== --- source/Plugins/Platform/POSIX/PlatformPOSIX.h +++ source/Plugins/Platform/POSIX/PlatformPOSIX.h @@ -31,6 +31,14 @@ //------------------------------------------------------------ // lldb_private::Platform functions //------------------------------------------------------------ + + lldb_private::Error + GetSharedModule (const lldb_private::ModuleSpec &module_spec, + lldb::ModuleSP &module_sp, + const lldb_private::FileSpecList *module_search_paths_ptr, + lldb::ModuleSP *old_module_sp_ptr, + bool *did_create_ptr) override; + virtual lldb_private::OptionGroupOptions *GetConnectionOptions( lldb_private::CommandInterpreter &interpreter) override; @@ -115,7 +123,10 @@ 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) override;// Timeout in seconds to wait for shell program to finish - + + virtual void + SetLocalCacheDirectory (const char* local) override; + virtual lldb_private::Error MakeDirectory (const char *path, uint32_t mode) override; Index: source/Plugins/Platform/POSIX/PlatformPOSIX.cpp =================================================================== --- source/Plugins/Platform/POSIX/PlatformPOSIX.cpp +++ source/Plugins/Platform/POSIX/PlatformPOSIX.cpp @@ -49,6 +49,27 @@ { } +Error +PlatformPOSIX::GetSharedModule (const ModuleSpec &module_spec, + ModuleSP &module_sp, + const FileSpecList *module_search_paths_ptr, + ModuleSP *old_module_sp_ptr, + bool *did_create_ptr) +{ + if (m_remote_platform_sp) + return m_remote_platform_sp->GetSharedModule (module_spec, + module_sp, + module_search_paths_ptr, + old_module_sp_ptr, + did_create_ptr); + + return Platform::GetSharedModule (module_spec, + module_sp, + module_search_paths_ptr, + old_module_sp_ptr, + did_create_ptr); +} + lldb_private::OptionGroupOptions* PlatformPOSIX::GetConnectionOptions (lldb_private::CommandInterpreter& interpreter) { @@ -91,6 +112,15 @@ } } +void +PlatformPOSIX::SetLocalCacheDirectory (const char* local) +{ + if (m_remote_platform_sp) + m_remote_platform_sp->SetLocalCacheDirectory (local); + else + Platform::SetLocalCacheDirectory (local); +} + Error PlatformPOSIX::MakeDirectory (const char *path, uint32_t file_permissions) { Index: source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h =================================================================== --- source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h +++ source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h @@ -12,13 +12,22 @@ // C Includes // C++ Includes +#include #include // Other libraries and framework includes // Project includes +#include "lldb/Core/UUID.h" #include "lldb/Target/Platform.h" #include "../../Process/gdb-remote/GDBRemoteCommunicationClient.h" +namespace lldb_private +{ + +class ModuleCache; + +} + class PlatformRemoteGDBServer : public lldb_private::Platform { public: @@ -68,6 +77,13 @@ lldb::ModuleSP &module_sp, const lldb_private::FileSpecList *module_search_paths_ptr); + virtual lldb_private::Error + GetSharedModule (const lldb_private::ModuleSpec &module_spec, + lldb::ModuleSP &module_sp, + const lldb_private::FileSpecList *module_search_paths_ptr, + lldb::ModuleSP *old_module_sp_ptr, + bool *did_create_ptr); + virtual const char * GetDescription (); @@ -127,7 +143,6 @@ virtual bool SetRemoteWorkingDirectory(const lldb_private::ConstString &path); - // Remote subclasses should override this and return a valid instance // name if connected. @@ -210,12 +225,30 @@ uint32_t timeout_sec); // Timeout in seconds to wait for shell program to finish virtual void + SetLocalCacheDirectory (const char* local); + + virtual void CalculateTrapHandlerSymbolNames (); protected: + struct ModuleInfo + { + lldb_private::UUID m_uuid; + lldb_private::ArchSpec m_arch; + uint64_t file_offset; + uint64_t file_size; + + ModuleInfo () + : file_offset (0), + file_size (0) + { + } + }; + GDBRemoteCommunicationClient m_gdb_client; std::string m_platform_description; // After we connect we can get a more complete description of what we are connected to std::string m_platform_hostname; + std::unique_ptr m_module_cache; // Launch the lldb-gdbserver on the remote host and return the port it is listening on or 0 on // failure. Subclasses should override this method if they want to do extra actions before or @@ -226,6 +259,21 @@ virtual bool KillSpawnedProcess (lldb::pid_t pid); + void InitModuleCache (const char* local_cache_dir); + + bool + GetModuleInfo (const lldb_private::ModuleSpec& module_spec, ModuleInfo& module_info); + + lldb_private::Error + DownloadModuleSlice (const lldb_private::FileSpec& src_file_spec, + const uint64_t src_offset, + const uint64_t src_size, + const lldb_private::FileSpec& dst_file_spec); + + bool + GetFileFromLocalCache (const lldb_private::ModuleSpec& module_spec, + lldb_private::FileSpec &cached_file_spec); + private: DISALLOW_COPY_AND_ASSIGN (PlatformRemoteGDBServer); Index: source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp =================================================================== --- source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp +++ source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp @@ -27,11 +27,20 @@ #include "lldb/Host/ConnectionFileDescriptor.h" #include "lldb/Host/FileSpec.h" #include "lldb/Host/Host.h" +#include "lldb/Host/HostInfo.h" +#include "lldb/Host/StringConvert.h" #include "lldb/Target/Process.h" #include "lldb/Target/Target.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/FileUtilities.h" +#include "Utility/ModuleCache.h" #include "Utility/UriParser.h" +#include +#include +#include + using namespace lldb; using namespace lldb_private; @@ -196,6 +205,222 @@ return error; } +lldb_private::Error +PlatformRemoteGDBServer::GetSharedModule (const lldb_private::ModuleSpec &module_spec, + lldb::ModuleSP &module_sp, + const lldb_private::FileSpecList *module_search_paths_ptr, + lldb::ModuleSP *old_module_sp_ptr, + bool *did_create_ptr) +{ + FileSpec cached_file_spec; + if (m_module_cache && GetFileFromLocalCache (module_spec, cached_file_spec)) + { + auto cached_module_spec (module_spec); + cached_module_spec.GetFileSpec () = cached_file_spec; + cached_module_spec.GetPlatformFileSpec () = module_spec.GetFileSpec (); + module_sp.reset (new Module (cached_module_spec)); + + if (did_create_ptr) + *did_create_ptr = true; + + return Error (); + } + + return Platform::GetSharedModule (module_spec, + module_sp, + module_search_paths_ptr, + old_module_sp_ptr, + did_create_ptr); +} + +bool +PlatformRemoteGDBServer::GetFileFromLocalCache (const ModuleSpec& module_spec, + FileSpec &cached_file_spec) +{ + Log *log = GetLogIfAnyCategoriesSet (LIBLLDB_LOG_PLATFORM); + + // Get module information from a target. + ModuleInfo module_info; + if (!GetModuleInfo (module_spec, module_info)) + return false; + + auto resolved_module_spec (module_spec); + resolved_module_spec.GetUUID () = module_info.m_uuid; + resolved_module_spec.GetArchitecture () = module_info.m_arch; + + // Check local cache for a module. + auto error = m_module_cache->Get (module_info.m_uuid, module_spec.GetFileSpec (), cached_file_spec); + if (error.Success ()) + return true; + + if (log) + log->Printf("PlatformRemoteGDBServer::%s - module %s not found in local cache: %s", + __FUNCTION__, module_info.m_uuid.GetAsString ().c_str (), error.AsCString ()); + + // Get temporary file name for a downloaded module. + FileSpec tmp_dir_spec; + if (!HostInfo::GetLLDBPath (ePathTypeLLDBTempSystemDir, tmp_dir_spec)) + { + if (log) + log->Printf ("PlatformRemoteGDBServer::%s - failed to get temp directory", __FUNCTION__); + return false; + } + + const std::string tmp_path_pattern (module_info.m_uuid.GetAsString () + ".%%%%%%"); + tmp_dir_spec.AppendPathComponent (tmp_path_pattern.c_str ()); + llvm::SmallString tmp_download_file_path; + const auto err_code = llvm::sys::fs::createUniqueFile (tmp_dir_spec.GetPath ().c_str (), tmp_download_file_path); + if (err_code) + { + if (log) + log->Printf ("PlatformRemoteGDBServer::%s - failed to create unique file in %s: %s", + __FUNCTION__, tmp_dir_spec.GetPath ().c_str (), err_code.message ().c_str ()); + return false; + } + + llvm::FileRemover tmp_file_remover (tmp_download_file_path.c_str ()); + + const FileSpec tmp_download_file_spec (tmp_download_file_path.c_str (), true); + // Download a module file. + error = DownloadModuleSlice (module_spec.GetFileSpec (), + module_info.file_offset, + module_info.file_size, + tmp_download_file_spec); + if (error.Fail ()) + { + if (log) + log->Printf("PlatformRemoteGDBServer::%s - failed to download %s to %s: %s", + __FUNCTION__, module_spec.GetFileSpec ().GetPath ().c_str (), + tmp_download_file_path.c_str (), error.AsCString ()); + return false; + } + + // Put downloaded file into local module cache. + error = m_module_cache->Put (module_info.m_uuid, module_spec.GetFileSpec (), tmp_download_file_spec); + if (error.Fail ()) + { + if (log) + log->Printf("PlatformRemoteGDBServer::%s - failed to put module %s into cache: %s", + __FUNCTION__, resolved_module_spec.GetUUID ().GetAsString ().c_str (), + error.AsCString ()); + return false; + } + + error = m_module_cache->Get (module_info.m_uuid, module_spec.GetFileSpec (), cached_file_spec); + return error.Success (); +} + +Error +PlatformRemoteGDBServer::DownloadModuleSlice (const lldb_private::FileSpec& src_file_spec, + const uint64_t src_offset, + const uint64_t src_size, + const lldb_private::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 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(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; +} + +bool +PlatformRemoteGDBServer::GetModuleInfo (const ModuleSpec& module_spec, ModuleInfo& module_info) +{ + Log *log = GetLogIfAnyCategoriesSet (LIBLLDB_LOG_PLATFORM); + + const auto module_path = module_spec.GetFileSpec ().GetPath (); + + StringExtractorGDBRemote response; + if (!m_gdb_client.GetModuleInfo (module_path.c_str (), module_spec.GetArchitecture (), response)) + { + if (log) + log->Printf ("PlatformRemoteGDBServer::%s - failed to get module info for %s:%s", + __FUNCTION__, module_path.c_str (), module_spec.GetArchitecture ().GetTriple ().getTriple ().c_str ()); + return false; + } + + std::string name; + std::string value; + bool success; + StringExtractor extractor; + + while (response.GetNameColonValue (name, value)) + { + if (name == "uuid" || name == "md5") + { + extractor.GetStringRef ().swap (value); + extractor.SetFilePos (0); + extractor.GetHexByteString (value); + module_info.m_uuid.SetFromCString (value.c_str(), value.size() / 2); + } + else if (name == "triple") + { + extractor.GetStringRef ().swap (value); + extractor.SetFilePos (0); + extractor.GetHexByteString (value); + module_info.m_arch.SetTriple (value.c_str ()); + } + else if (name == "file_offset") + { + const auto ival = StringConvert::ToUInt64 (value.c_str (), 0, 16, &success); + if (success) + module_info.file_offset = ival; + } + else if (name == "file_size") + { + const auto ival = StringConvert::ToUInt64 (value.c_str (), 0, 16, &success); + if (success) + module_info.file_size = ival; + } + } + + if (log) + log->Printf ("PlatformRemoteGDBServer::%s - got module info for %s:%s, uuid=%s, triple=%s, file_offset=%llu, file_size=%llu", + __FUNCTION__, module_path.c_str (), module_spec.GetArchitecture ().GetTriple ().getTriple ().c_str (), + module_info.m_uuid.GetAsString ().c_str (), module_info.m_arch.GetTriple ().getTriple ().c_str (), + module_info.file_offset, module_info.file_size); + + return true; +} + Error PlatformRemoteGDBServer::GetFileWithUUID (const FileSpec &platform_file, const UUID *uuid_ptr, @@ -346,7 +571,6 @@ { const char *url = args.GetArgumentAtIndex(0); m_gdb_client.SetConnection (new ConnectionFileDescriptor()); - // we're going to reuse the hostname when we connect to the debugserver std::string scheme; int port; @@ -380,7 +604,6 @@ error.SetErrorString ("\"platform connect\" takes a single argument: "); } } - return error; } @@ -837,7 +1060,43 @@ } void +PlatformRemoteGDBServer::SetLocalCacheDirectory (const char* local) +{ + Platform::SetLocalCacheDirectory (local); + + if (!m_local_cache_directory.empty ()) + InitModuleCache (m_local_cache_directory.c_str ()); +} + +void PlatformRemoteGDBServer::CalculateTrapHandlerSymbolNames () { m_trap_handlers.push_back (ConstString ("_sigtramp")); -} +} + +void +PlatformRemoteGDBServer::InitModuleCache (const char* local_cache_dir) +{ + Log *log = GetLogIfAnyCategoriesSet (LIBLLDB_LOG_PLATFORM); + + if (log) + log->Printf ("PlatformRemoteGDBServer::%s - %s", __FUNCTION__, local_cache_dir); + + ModuleCache::Options options; + options.m_root_dir = FileSpec (local_cache_dir, true); + auto module_cache = llvm::make_unique (options); + const auto error = module_cache->Init (); + if (error.Fail ()) + { + if (log) + { + log->Printf ("PlatformRemoteGDBServer::%s - failed to init ModuleCache(%s): %s", + __FUNCTION__, + local_cache_dir, + error.AsCString ()); + } + return; + } + + m_module_cache = std::move (module_cache); +} Index: source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp =================================================================== --- source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp +++ source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp @@ -3719,5 +3719,6 @@ const auto& tripple = arch_spec.GetTriple().getTriple(); packet.PutBytesAsRawHex8(tripple.c_str(), tripple.size()); - return SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false) == PacketResult::Success; + return SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false) == PacketResult::Success && + !response.IsErrorResponse (); } Index: source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp =================================================================== --- source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp +++ source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp @@ -1157,7 +1157,7 @@ StreamGDBRemote response; - const auto uuid_str = module->GetUUID().GetAsString(); + const auto uuid_str = module->GetUUID().GetAsString(""); if (uuid_str.empty()) { std::string md5_hash; Index: source/Utility/CMakeLists.txt =================================================================== --- source/Utility/CMakeLists.txt +++ source/Utility/CMakeLists.txt @@ -5,6 +5,7 @@ ARM64_DWARF_Registers.cpp JSON.cpp KQueue.cpp + ModuleCache.cpp PseudoTerminal.cpp Range.cpp RegisterNumber.cpp Index: source/Utility/ModuleCache.h =================================================================== --- /dev/null +++ source/Utility/ModuleCache.h @@ -0,0 +1,56 @@ +//===-- ModuleCache.h -------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef utility_ModuleCache_h_ +#define utility_ModuleCache_h_ + +#include "lldb/lldb-types.h" +#include "lldb/lldb-forward.h" + +#include "lldb/Core/Error.h" +#include "lldb/Host/FileSpec.h" + +#include + +namespace lldb_private { + +class UUID; + +class ModuleCache +{ +public: + struct Options + { + FileSpec m_root_dir; + uint64_t m_max_size; + }; + + explicit ModuleCache (const Options &options); + + Error + Init (); + + Error + Put (const UUID &uuid, const FileSpec &platform_module_spec, const FileSpec &tmp_file); + + Error + Get (const UUID &uuid, const FileSpec &platform_module_spec, FileSpec &cached_module_spec); + +private: + const Options m_options; + FileSpec m_modules_root; + bool m_initialized; + + FileSpec + GetModuleDirectory (const UUID &uuid) const; +}; + +} // namespace lldb_private + +#endif // utility_ModuleCache_h_ Index: source/Utility/ModuleCache.cpp =================================================================== --- /dev/null +++ source/Utility/ModuleCache.cpp @@ -0,0 +1,129 @@ +//===--------------------- ModuleCache.cpp ----------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "ModuleCache.h" + +#include "lldb/Core/Module.h" +#include "lldb/Host/FileSystem.h" +#include "llvm/Support/FileSystem.h" + +#include + +#include +#include + +using namespace lldb; +using namespace lldb_private; + +namespace { + +const char* kModulesSubdir = "modules"; + +FileSpec +JoinPath (const FileSpec &path1, const FileSpec &path2) +{ + std::ostringstream path_stream; + path_stream << path1.GetPath () << "/" << path2.GetPath (); + return FileSpec (path_stream.str ().c_str (), true); +} + +Error +MakeDirectory (const FileSpec &dir_path) +{ + if (dir_path.Exists ()) + { + if (!dir_path.IsDirectory ()) + return Error ("Invalid existing path"); + + return Error (); + } + + return FileSystem::MakeDirectory (dir_path.GetPath ().c_str (), + eFilePermissionsDirectoryDefault); +} + +} // namespace + +ModuleCache::ModuleCache (const Options &options) + : m_options (options), + m_initialized (false) +{ +} + +Error +ModuleCache::Init () +{ + assert (!m_initialized); + + auto error = MakeDirectory (m_options.m_root_dir); + if (error.Success ()) + { + m_modules_root = JoinPath (m_options.m_root_dir, FileSpec (kModulesSubdir, false)); + error = MakeDirectory (m_modules_root); + } + + m_initialized = error.Success (); + return error; +} + +Error +ModuleCache::Put (const UUID &uuid, const FileSpec &platform_module_spec, const FileSpec &tmp_file) +{ + assert (m_initialized); + + const auto module_dir = GetModuleDirectory (uuid); + auto error = MakeDirectory (module_dir); + if (error.Fail ()) + return error; + + const auto module_file_path = JoinPath (module_dir,platform_module_spec); + + const FileSpec module_file_dir (module_file_path.GetDirectory ().AsCString (), true); + error = MakeDirectory (module_file_dir); + if (error.Fail ()) + return error; + + const auto tmp_file_path = tmp_file.GetPath (); + const auto err_code = llvm::sys::fs::copy_file (tmp_file_path.c_str (), module_file_path.GetPath ().c_str ()); + if (err_code) + { + error.SetErrorStringWithFormat ("failed to rename file %s to %s: %s", + tmp_file_path.c_str (), + module_file_path.GetPath ().c_str (), + err_code.message ().c_str ()); + } + + return error; +} + +Error +ModuleCache::Get (const UUID &uuid, const FileSpec &platform_module_spec, FileSpec &cached_module_spec) +{ + assert (m_initialized); + + cached_module_spec.Clear (); + + Error error; + const auto module_file_path = JoinPath (GetModuleDirectory (uuid), + platform_module_spec); + if (module_file_path.Exists ()) + { + cached_module_spec = module_file_path; + } + else + error.SetErrorStringWithFormat ("module %s not found", module_file_path.GetPath ().c_str ()); + + return error; +} + +FileSpec +ModuleCache::GetModuleDirectory (const UUID &uuid) const +{ + return JoinPath (m_modules_root, FileSpec (uuid.GetAsString ().c_str (), false)); +} Index: test/dotest.py =================================================================== --- test/dotest.py +++ test/dotest.py @@ -28,6 +28,7 @@ import signal import subprocess import sys +import tempfile import textwrap import time import inspect @@ -1335,7 +1336,10 @@ if lldb_platform_url: # We must connect to a remote platform if a LLDB platform URL was specified print "Connecting to remote platform '%s' at '%s'..." % (lldb_platform_name, lldb_platform_url) - platform_connect_options = lldb.SBPlatformConnectOptions(lldb_platform_url); + platform_connect_options = lldb.SBPlatformConnectOptions(lldb_platform_url) + local_cache_dir = os.path.join(tempfile.gettempdir(), "lldb/cache") + print "Setting local cache directory '%s'" % (local_cache_dir) + platform_connect_options.SetLocalCacheDirectory(local_cache_dir) err = lldb.remote_platform.ConnectRemote(platform_connect_options) if err.Success(): print "Connected." Index: test/python_api/hello_world/TestHelloWorld.py =================================================================== --- test/python_api/hello_world/TestHelloWorld.py +++ test/python_api/hello_world/TestHelloWorld.py @@ -46,7 +46,6 @@ self.setTearDownCleanup(dictionary=self.d) self.hello_world_attach_with_id_api() - @not_remote_testsuite_ready @python_api_test @dwarf_test @expectedFailurei386 # llvm.org/pr17384: lldb needs to be aware of linux-vdso.so to unwind stacks properly @@ -72,7 +71,6 @@ self.setTearDownCleanup(dictionary=self.d) self.hello_world_attach_with_name_api() - @not_remote_testsuite_ready @python_api_test @dwarf_test @expectedFailurei386 # llvm.org/pr17384: lldb needs to be aware of linux-vdso.so to unwind stacks properly