Add a new option to Platform::LoadImage to install the image

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
This commit is contained in:
Tamas Berghammer 2015-12-08 13:43:59 +00:00
parent 9cbf7dde88
commit 4fbd67ac11
8 changed files with 225 additions and 31 deletions

View 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 &image_spec, lldb::SBError &error);
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 (const lldb::SBFileSpec &local_image_spec,
const lldb::SBFileSpec &remote_image_spec,
lldb::SBError &error);
lldb::SBError
UnloadImage (uint32_t image_token);

View 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);

View 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.

View 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
{

View 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

View 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"(

View 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;

View 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");
}