Add a new option to Platform::LoadImage to install the image
authorTamas Berghammer <tberghammer@google.com>
Tue, 8 Dec 2015 13:43:59 +0000 (13:43 +0000)
committerTamas Berghammer <tberghammer@google.com>
Tue, 8 Dec 2015 13:43:59 +0000 (13:43 +0000)
This change introduce 3 different working mode for Platform::LoadImage
depending on the file specs specified.
* If only a remote file is specified then the remote file is loaded on
  the target (same behavior as before)
* If only a local file is specified then the local file is installed to
  the current working directory and then loaded from there.
* If both local and remote file is specified then the local file is
  installed to the specified location and then loaded from there.

The same options are exposed on the SB API with a new method LoadImage
method while the old signature presers its meaning.

On the command line the installation of the shared library can be specified
with the "--install" option of "process load".

Differential revision: http://reviews.llvm.org/D15152

llvm-svn: 255014

lldb/include/lldb/API/SBProcess.h
lldb/include/lldb/Target/Platform.h
lldb/packages/Python/lldbsuite/test/functionalities/load_unload/TestLoadUnload.py
lldb/source/API/SBProcess.cpp
lldb/source/Commands/CommandObjectProcess.cpp
lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp
lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.h
lldb/source/Target/Platform.cpp

index 6ea3d79..1a9cc80 100644 (file)
@@ -294,8 +294,56 @@ public:
     uint32_t
     GetNumSupportedHardwareWatchpoints (lldb::SBError &error) const;
 
+    //------------------------------------------------------------------
+    /// Load a shared library into this process.
+    ///
+    /// @param[in] remote_image_spec
+    ///     The path for the shared library on the target what you want
+    ///     to load.
+    ///
+    /// @param[out] error
+    ///     An error object that gets filled in with any errors that
+    ///     might occur when trying to load the shared library.
+    ///
+    /// @return
+    ///     A token that represents the shared library that can be
+    ///     later used to unload the shared library. A value of
+    ///     LLDB_INVALID_IMAGE_TOKEN will be returned if the shared
+    ///     library can't be opened.
+    //------------------------------------------------------------------
+    uint32_t
+    LoadImage (lldb::SBFileSpec &remote_image_spec, lldb::SBError &error);
+
+    //------------------------------------------------------------------
+    /// Load a shared library into this process.
+    ///
+    /// @param[in] local_image_spec
+    ///     The file spec that points to the shared library that you
+    ///     want to load if the library is located on the host. The
+    ///     library will be copied over to the location specified by
+    ///     remote_image_spec or into the current working directory with
+    ///     the same filename if the remote_image_spec isn't specified.
+    ///
+    /// @param[in] remote_image_spec
+    ///     If local_image_spec is specified then the location where the
+    ///     library should be copied over from the host. If
+    ///     local_image_spec isn't specified, then the path for the
+    ///     shared library on the target what you want to load.
+    ///
+    /// @param[out] error
+    ///     An error object that gets filled in with any errors that
+    ///     might occur when trying to load the shared library.
+    ///
+    /// @return
+    ///     A token that represents the shared library that can be
+    ///     later used to unload the shared library. A value of
+    ///     LLDB_INVALID_IMAGE_TOKEN will be returned if the shared
+    ///     library can't be opened.
+    //------------------------------------------------------------------
     uint32_t
-    LoadImage (lldb::SBFileSpec &image_spec, lldb::SBError &error);
+    LoadImage (const lldb::SBFileSpec &local_image_spec,
+               const lldb::SBFileSpec &remote_image_spec,
+               lldb::SBError &error);
     
     lldb::SBError
     UnloadImage (uint32_t image_token);
index f843735..9649ccd 100644 (file)
@@ -997,9 +997,18 @@ class ModuleCache;
         /// @param[in] process
         ///     The process to load the image.
         ///
-        /// @param[in] image_spec
-        ///     The image file spec that points to the shared library that
-        ///     you want to load.
+        /// @param[in] local_file
+        ///     The file spec that points to the shared library that you want
+        ///     to load if the library is located on the host. The library will
+        ///     be copied over to the location specified by remote_file or into
+        ///     the current working directory with the same filename if the
+        ///     remote_file isn't specified.
+        ///
+        /// @param[in] remote_file
+        ///     If local_file is specified then the location where the library
+        ///     should be copied over from the host. If local_file isn't
+        ///     specified, then the path for the shared library on the target
+        ///     what you want to load.
         ///
         /// @param[out] error
         ///     An error object that gets filled in with any errors that
@@ -1011,11 +1020,17 @@ class ModuleCache;
         ///     LLDB_INVALID_IMAGE_TOKEN will be returned if the shared
         ///     library can't be opened.
         //------------------------------------------------------------------
-        virtual uint32_t
+        uint32_t
         LoadImage (lldb_private::Process* process,
-                   const lldb_private::FileSpec& image_spec,
+                   const lldb_private::FileSpec& local_file,
+                   const lldb_private::FileSpec& remote_file,
                    lldb_private::Error& error);
 
+        virtual uint32_t
+        DoLoadImage (lldb_private::Process* process,
+                     const lldb_private::FileSpec& remote_file,
+                     lldb_private::Error& error);
+
         virtual Error
         UnloadImage (lldb_private::Process* process, uint32_t image_token);
 
index 2afb8ed..10e7e50 100644 (file)
@@ -210,19 +210,13 @@ class LoadUnloadTestCase(TestBase):
         else:
             dylibName = 'libloadunload_a.so'
 
-        if lldb.remote_platform:
-            # Don't use os.path.join as we have to use the path separator for the target
-            dylibPath = shlib_dir + '/' + dylibName
-        else:
-            dylibPath = dylibName
-
         # Make sure that a_function does not exist at this point.
         self.expect("image lookup -n a_function", "a_function should not exist yet",
                     error=True, matching=False, patterns = ["1 match found"])
 
         # Use lldb 'process load' to load the dylib.
-        self.expect("process load %s" % dylibPath, "%s loaded correctly" % dylibPath,
-            patterns = ['Loading "%s".*ok' % dylibPath,
+        self.expect("process load %s --install" % dylibName, "%s loaded correctly" % dylibName,
+            patterns = ['Loading "%s".*ok' % dylibName,
                         'Image [0-9]+ loaded'])
 
         # Search for and match the "Image ([0-9]+) loaded" pattern.
index aadb51e..dceadec 100644 (file)
@@ -1288,7 +1288,15 @@ SBProcess::GetNumSupportedHardwareWatchpoints (lldb::SBError &sb_error) const
 }
 
 uint32_t
-SBProcess::LoadImage (lldb::SBFileSpec &sb_image_spec, lldb::SBError &sb_error)
+SBProcess::LoadImage (lldb::SBFileSpec &sb_remote_image_spec, lldb::SBError &sb_error)
+{
+    return LoadImage(SBFileSpec(), sb_remote_image_spec, sb_error);
+}
+
+uint32_t
+SBProcess::LoadImage (const lldb::SBFileSpec &sb_local_image_spec,
+                      const lldb::SBFileSpec &sb_remote_image_spec,
+                      lldb::SBError &sb_error)
 {
     ProcessSP process_sp(GetSP());
     if (process_sp)
@@ -1298,7 +1306,10 @@ SBProcess::LoadImage (lldb::SBFileSpec &sb_image_spec, lldb::SBError &sb_error)
         {
             Mutex::Locker api_locker (process_sp->GetTarget().GetAPIMutex());
             PlatformSP platform_sp = process_sp->GetTarget().GetPlatform();
-            return platform_sp->LoadImage (process_sp.get(), *sb_image_spec, sb_error.ref());
+            return platform_sp->LoadImage (process_sp.get(),
+                                           *sb_local_image_spec,
+                                           *sb_remote_image_spec,
+                                           sb_error.ref());
         }
         else
         {
index 4c8fe20..293b762 100644 (file)
@@ -1174,6 +1174,57 @@ public:
 class CommandObjectProcessLoad : public CommandObjectParsed
 {
 public:
+    class CommandOptions : public Options
+    {
+    public:
+        CommandOptions (CommandInterpreter &interpreter) :
+            Options(interpreter)
+        {
+            // Keep default values of all options in one place: OptionParsingStarting ()
+            OptionParsingStarting ();
+        }
+
+        ~CommandOptions () override = default;
+
+        Error
+        SetOptionValue (uint32_t option_idx, const char *option_arg) override
+        {
+            Error error;
+            const int short_option = m_getopt_table[option_idx].val;
+            switch (short_option)
+            {
+            case 'i':
+                do_install = true;
+                if (option_arg && option_arg[0])
+                    install_path.SetFile(option_arg, false);
+                break;
+            default:
+                error.SetErrorStringWithFormat("invalid short option character '%c'", short_option);
+                break;
+            }
+            return error;
+        }
+
+        void
+        OptionParsingStarting () override
+        {
+            do_install = false;
+            install_path.Clear();
+        }
+
+        const OptionDefinition*
+        GetDefinitions () override
+        {
+            return g_option_table;
+        }
+
+        // Options table: Required for subclasses of Options.
+        static OptionDefinition g_option_table[];
+
+        // Instance variables to hold the values for command options.
+        bool do_install;
+        FileSpec install_path;
+    };
 
     CommandObjectProcessLoad (CommandInterpreter &interpreter) :
         CommandObjectParsed (interpreter,
@@ -1183,12 +1234,17 @@ public:
                              eCommandRequiresProcess       |
                              eCommandTryTargetAPILock      |
                              eCommandProcessMustBeLaunched |
-                             eCommandProcessMustBePaused   )
+                             eCommandProcessMustBePaused   ),
+        m_options (interpreter)
     {
     }
 
-    ~CommandObjectProcessLoad () override
+    ~CommandObjectProcessLoad () override = default;
+
+    Options *
+    GetOptions () override
     {
+        return &m_options;
     }
 
 protected:
@@ -1198,18 +1254,34 @@ protected:
         Process *process = m_exe_ctx.GetProcessPtr();
 
         const size_t argc = command.GetArgumentCount();
-        
         for (uint32_t i=0; i<argc; ++i)
         {
             Error error;
-            const char *image_path = command.GetArgumentAtIndex(i);
-            FileSpec image_spec (image_path, false);
             PlatformSP platform = process->GetTarget().GetPlatform();
-            platform->ResolveRemotePath(image_spec, image_spec);
-            uint32_t image_token = platform->LoadImage(process, image_spec, error);
+            const char *image_path = command.GetArgumentAtIndex(i);
+            uint32_t image_token = LLDB_INVALID_IMAGE_TOKEN;
+
+            if (!m_options.do_install)
+            {
+                FileSpec image_spec (image_path, false);
+                platform->ResolveRemotePath(image_spec, image_spec);
+                image_token = platform->LoadImage(process, FileSpec(), image_spec, error);
+            }
+            else if (m_options.install_path)
+            {
+                FileSpec image_spec (image_path, true);
+                platform->ResolveRemotePath(m_options.install_path, m_options.install_path);
+                image_token = platform->LoadImage(process, image_spec, m_options.install_path, error);
+            }
+            else
+            {
+                FileSpec image_spec (image_path, true);
+                image_token = platform->LoadImage(process, image_spec, FileSpec(), error);
+            }
+
             if (image_token != LLDB_INVALID_IMAGE_TOKEN)
             {
-                result.AppendMessageWithFormat ("Loading \"%s\"...ok\nImage %u loaded.\n", image_path, image_token);  
+                result.AppendMessageWithFormat ("Loading \"%s\"...ok\nImage %u loaded.\n", image_path, image_token);
                 result.SetStatus (eReturnStatusSuccessFinishResult);
             }
             else
@@ -1220,8 +1292,16 @@ protected:
         }
         return result.Succeeded();
     }
+    
+    CommandOptions m_options;
 };
 
+OptionDefinition
+CommandObjectProcessLoad::CommandOptions::g_option_table[] =
+{
+    { LLDB_OPT_SET_ALL, false, "install", 'i', OptionParser::eOptionalArgument, nullptr, nullptr, 0, eArgTypePath, "Install the shared library to the target. If specified without an argument then the library will installed in the current working directory."},
+    { 0,                false, nullptr,    0 , 0,                               nullptr, nullptr, 0, eArgTypeNone, nullptr }
+};
 
 //-------------------------------------------------------------------------
 // CommandObjectProcessUnload
index 95447f1..6983e3d 100644 (file)
@@ -898,10 +898,12 @@ PlatformPOSIX::EvaluateLibdlExpression(lldb_private::Process* process,
 }
 
 uint32_t
-PlatformPOSIX::LoadImage(lldb_private::Process* process, const FileSpec& image_spec, Error& error)
+PlatformPOSIX::DoLoadImage(lldb_private::Process* process,
+                           const lldb_private::FileSpec& remote_file,
+                           lldb_private::Error& error)
 {
     char path[PATH_MAX];
-    image_spec.GetPath(path, sizeof(path));
+    remote_file.GetPath(path, sizeof(path));
 
     StreamString expr;
     expr.Printf(R"(
index 8207c8e..6dabeed 100644 (file)
@@ -174,9 +174,9 @@ public:
     DisconnectRemote () override;
 
     uint32_t
-    LoadImage (lldb_private::Process* process,
-               const lldb_private::FileSpec& image_spec,
-               lldb_private::Error& error) override;
+    DoLoadImage (lldb_private::Process* process,
+                 const lldb_private::FileSpec& remote_file,
+                 lldb_private::Error& error) override;
 
     lldb_private::Error
     UnloadImage (lldb_private::Process* process, uint32_t image_token) override;
index fa0f9db..8a82f5e 100644 (file)
@@ -1985,7 +1985,51 @@ Platform::GetUnixSignals()
 }
 
 uint32_t
-Platform::LoadImage(lldb_private::Process* process, const FileSpec& image_spec, Error& error)
+Platform::LoadImage(lldb_private::Process* process,
+                    const lldb_private::FileSpec& local_file,
+                    const lldb_private::FileSpec& remote_file,
+                    lldb_private::Error& error)
+{
+    if (local_file && remote_file)
+    {
+        // Both local and remote file was specified. Install the local file to the given location.
+        if (IsRemote() || local_file != remote_file)
+        {
+            error = Install(local_file, remote_file);
+            if (error.Fail())
+                return LLDB_INVALID_IMAGE_TOKEN;
+        }
+        return DoLoadImage(process, remote_file, error);
+    }
+
+    if (local_file)
+    {
+        // Only local file was specified. Install it to the current working directory.
+        FileSpec target_file = GetWorkingDirectory();
+        target_file.AppendPathComponent(local_file.GetFilename().AsCString());
+        if (IsRemote() || local_file != target_file)
+        {
+            error = Install(local_file, target_file);
+            if (error.Fail())
+                return LLDB_INVALID_IMAGE_TOKEN;
+        }
+        return DoLoadImage(process, target_file, error);
+    }
+
+    if (remote_file)
+    {
+        // Only remote file was specified so we don't have to do any copying
+        return DoLoadImage(process, remote_file, error);
+    }
+
+    error.SetErrorString("Neither local nor remote file was specified");
+    return LLDB_INVALID_IMAGE_TOKEN;
+}
+
+uint32_t
+Platform::DoLoadImage (lldb_private::Process* process,
+                       const lldb_private::FileSpec& remote_file,
+                       lldb_private::Error& error)
 {
     error.SetErrorString("LoadImage is not supported on the current platform");
     return LLDB_INVALID_IMAGE_TOKEN;
@@ -1994,5 +2038,5 @@ Platform::LoadImage(lldb_private::Process* process, const FileSpec& image_spec,
 Error
 Platform::UnloadImage(lldb_private::Process* process, uint32_t image_token)
 {
-    return Error("UnLoadImage is not supported on the current platform");
+    return Error("UnloadImage is not supported on the current platform");
 }