summaryrefslogtreecommitdiffstats
path: root/lldb/source/Target/Platform.cpp
diff options
context:
space:
mode:
authorOleksiy Vyalov <ovyalov@google.com>2015-03-10 01:15:28 +0000
committerOleksiy Vyalov <ovyalov@google.com>2015-03-10 01:15:28 +0000
commit63acdfdeb26616dfa1d9657fa666afc9b9440a2a (patch)
treee16c9b93f68e2a5ddd835845a4801ec1dead78c5 /lldb/source/Target/Platform.cpp
parent8fb05ac9987bb2fe210e3d0d02ef762793524c45 (diff)
downloadbcm5719-llvm-63acdfdeb26616dfa1d9657fa666afc9b9440a2a.tar.gz
bcm5719-llvm-63acdfdeb26616dfa1d9657fa666afc9b9440a2a.zip
Add Utility/ModuleCache class and integrate it with PlatformGDBRemoteServer - in order to allow modules caching from remote targets.
http://reviews.llvm.org/D8037 llvm-svn: 231734
Diffstat (limited to 'lldb/source/Target/Platform.cpp')
-rw-r--r--lldb/source/Target/Platform.cpp276
1 files changed, 266 insertions, 10 deletions
diff --git a/lldb/source/Target/Platform.cpp b/lldb/source/Target/Platform.cpp
index 3b76e57f888..955ae66a87c 100644
--- a/lldb/source/Target/Platform.cpp
+++ b/lldb/source/Target/Platform.cpp
@@ -10,13 +10,19 @@
#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/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"
@@ -24,9 +30,16 @@
#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 "llvm/Support/FileUtilities.h"
+
+#include "Utility/ModuleCache.h"
using namespace lldb;
using namespace lldb_private;
@@ -48,6 +61,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.
///
@@ -97,6 +177,13 @@ Platform::Terminate ()
}
}
+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)
{
@@ -165,20 +252,37 @@ Platform::GetSharedModule (const ModuleSpec &module_spec,
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;
+ if (!IsHost () && GetGlobalPlatformProperties ()->GetUseModuleCache ())
+ {
+ // Use caching only when talking to a remote platform.
+ if (GetCachedSharedModule (module_spec, module_sp))
+ {
+ if (did_create_ptr)
+ *did_create_ptr = true;
+
+ return Error ();
+ }
+ }
return ModuleList::GetSharedModule (module_spec,
module_sp,
module_search_paths_ptr,
old_module_sp_ptr,
did_create_ptr,
- always_create);
+ false);
+}
+
+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
@@ -321,7 +425,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)
@@ -1647,3 +1752,154 @@ Platform::GetTrapHandlerSymbolNames ()
return m_trap_handlers;
}
+bool
+Platform::GetCachedSharedModule (const ModuleSpec &module_spec,
+ lldb::ModuleSP &module_sp)
+{
+ 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));
+
+ return true;
+ }
+ return false;
+}
+
+bool
+Platform::GetFileFromLocalCache (const ModuleSpec& module_spec,
+ FileSpec &cached_file_spec)
+{
+ Log *log = GetLogIfAnyCategoriesSet (LIBLLDB_LOG_PLATFORM);
+
+ // Get module information from a target.
+ ModuleSpec resolved_module_spec;
+ if (!GetModuleSpec (module_spec.GetFileSpec (), module_spec.GetArchitecture (), resolved_module_spec))
+ return false;
+
+ // Check local cache for a module.
+ auto error = m_module_cache->Get (GetModuleCacheRoot (),
+ GetHostname (),
+ resolved_module_spec.GetUUID (),
+ resolved_module_spec.GetFileSpec (),
+ cached_file_spec);
+ if (error.Success ())
+ return true;
+
+ if (log)
+ log->Printf("Platform::%s - module %s not found in local cache: %s",
+ __FUNCTION__, resolved_module_spec.GetUUID ().GetAsString ().c_str (), error.AsCString ());
+
+ // Get temporary file name for a downloaded module.
+ llvm::SmallString<PATH_MAX> tmp_download_file_path;
+ const auto err_code = llvm::sys::fs::createTemporaryFile (
+ "lldb", resolved_module_spec.GetUUID ().GetAsString ().c_str (), tmp_download_file_path);
+ if (err_code)
+ {
+ if (log)
+ log->Printf ("Platform::%s - failed to create unique file: %s",
+ __FUNCTION__, 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 (resolved_module_spec.GetFileSpec (),
+ resolved_module_spec.GetObjectOffset (),
+ resolved_module_spec.GetObjectSize (),
+ tmp_download_file_spec);
+ if (error.Fail ())
+ {
+ if (log)
+ log->Printf("Platform::%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 (GetModuleCacheRoot (),
+ GetHostname (),
+ resolved_module_spec.GetUUID (),
+ resolved_module_spec.GetFileSpec (),
+ tmp_download_file_spec);
+ if (error.Fail ())
+ {
+ if (log)
+ log->Printf("Platform::%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 (GetModuleCacheRoot (),
+ GetHostname (),
+ resolved_module_spec.GetUUID (),
+ resolved_module_spec.GetFileSpec (),
+ cached_file_spec);
+ return error.Success ();
+}
+
+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;
+}
OpenPOWER on IntegriCloud