forked from OSchip/llvm-project
2279 lines
84 KiB
C++
2279 lines
84 KiB
C++
//===-- CommandObjectPlatform.cpp -------------------------------*- C++ -*-===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "CommandObjectPlatform.h"
|
|
|
|
// C Includes
|
|
// C++ Includes
|
|
// Other libraries and framework includes
|
|
// Project includes
|
|
#include "lldb/Core/DataExtractor.h"
|
|
#include "lldb/Core/Debugger.h"
|
|
#include "lldb/Core/Module.h"
|
|
#include "lldb/Core/PluginManager.h"
|
|
#include "lldb/Host/StringConvert.h"
|
|
#include "lldb/Interpreter/Args.h"
|
|
#include "lldb/Interpreter/CommandInterpreter.h"
|
|
#include "lldb/Interpreter/CommandOptionValidators.h"
|
|
#include "lldb/Interpreter/CommandReturnObject.h"
|
|
#include "lldb/Interpreter/OptionGroupFile.h"
|
|
#include "lldb/Interpreter/OptionGroupPlatform.h"
|
|
#include "lldb/Target/ExecutionContext.h"
|
|
#include "lldb/Target/Platform.h"
|
|
#include "lldb/Target/Process.h"
|
|
#include "lldb/Utility/Utils.h"
|
|
|
|
using namespace lldb;
|
|
using namespace lldb_private;
|
|
|
|
static mode_t
|
|
ParsePermissionString(const char* permissions)
|
|
{
|
|
if (strlen(permissions) != 9)
|
|
return (mode_t)(-1);
|
|
bool user_r,user_w,user_x,
|
|
group_r,group_w,group_x,
|
|
world_r,world_w,world_x;
|
|
|
|
user_r = (permissions[0] == 'r');
|
|
user_w = (permissions[1] == 'w');
|
|
user_x = (permissions[2] == 'x');
|
|
|
|
group_r = (permissions[3] == 'r');
|
|
group_w = (permissions[4] == 'w');
|
|
group_x = (permissions[5] == 'x');
|
|
|
|
world_r = (permissions[6] == 'r');
|
|
world_w = (permissions[7] == 'w');
|
|
world_x = (permissions[8] == 'x');
|
|
|
|
mode_t user,group,world;
|
|
user = (user_r ? 4 : 0) | (user_w ? 2 : 0) | (user_x ? 1 : 0);
|
|
group = (group_r ? 4 : 0) | (group_w ? 2 : 0) | (group_x ? 1 : 0);
|
|
world = (world_r ? 4 : 0) | (world_w ? 2 : 0) | (world_x ? 1 : 0);
|
|
|
|
return user | group | world;
|
|
}
|
|
|
|
static OptionDefinition
|
|
g_permissions_options[] =
|
|
{
|
|
{ LLDB_OPT_SET_ALL, false, "permissions-value", 'v', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypePermissionsNumber , "Give out the numeric value for permissions (e.g. 757)" },
|
|
{ LLDB_OPT_SET_ALL, false, "permissions-string", 's', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypePermissionsString , "Give out the string value for permissions (e.g. rwxr-xr--)." },
|
|
{ LLDB_OPT_SET_ALL, false, "user-read", 'r', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone , "Allow user to read." },
|
|
{ LLDB_OPT_SET_ALL, false, "user-write", 'w', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone , "Allow user to write." },
|
|
{ LLDB_OPT_SET_ALL, false, "user-exec", 'x', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone , "Allow user to execute." },
|
|
|
|
{ LLDB_OPT_SET_ALL, false, "group-read", 'R', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone , "Allow group to read." },
|
|
{ LLDB_OPT_SET_ALL, false, "group-write", 'W', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone , "Allow group to write." },
|
|
{ LLDB_OPT_SET_ALL, false, "group-exec", 'X', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone , "Allow group to execute." },
|
|
|
|
{ LLDB_OPT_SET_ALL, false, "world-read", 'd', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone , "Allow world to read." },
|
|
{ LLDB_OPT_SET_ALL, false, "world-write", 't', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone , "Allow world to write." },
|
|
{ LLDB_OPT_SET_ALL, false, "world-exec", 'e', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone , "Allow world to execute." },
|
|
};
|
|
|
|
class OptionPermissions : public lldb_private::OptionGroup
|
|
{
|
|
public:
|
|
OptionPermissions ()
|
|
{
|
|
}
|
|
|
|
~OptionPermissions () override
|
|
{
|
|
}
|
|
|
|
lldb_private::Error
|
|
SetOptionValue (CommandInterpreter &interpreter,
|
|
uint32_t option_idx,
|
|
const char *option_arg) override
|
|
{
|
|
Error error;
|
|
char short_option = (char) GetDefinitions()[option_idx].short_option;
|
|
switch (short_option)
|
|
{
|
|
case 'v':
|
|
{
|
|
bool ok;
|
|
uint32_t perms = StringConvert::ToUInt32(option_arg, 777, 8, &ok);
|
|
if (!ok)
|
|
error.SetErrorStringWithFormat("invalid value for permissions: %s", option_arg);
|
|
else
|
|
m_permissions = perms;
|
|
}
|
|
break;
|
|
case 's':
|
|
{
|
|
mode_t perms = ParsePermissionString(option_arg);
|
|
if (perms == (mode_t)-1)
|
|
error.SetErrorStringWithFormat("invalid value for permissions: %s", option_arg);
|
|
else
|
|
m_permissions = perms;
|
|
}
|
|
case 'r':
|
|
m_permissions |= lldb::eFilePermissionsUserRead;
|
|
break;
|
|
case 'w':
|
|
m_permissions |= lldb::eFilePermissionsUserWrite;
|
|
break;
|
|
case 'x':
|
|
m_permissions |= lldb::eFilePermissionsUserExecute;
|
|
break;
|
|
case 'R':
|
|
m_permissions |= lldb::eFilePermissionsGroupRead;
|
|
break;
|
|
case 'W':
|
|
m_permissions |= lldb::eFilePermissionsGroupWrite;
|
|
break;
|
|
case 'X':
|
|
m_permissions |= lldb::eFilePermissionsGroupExecute;
|
|
break;
|
|
case 'd':
|
|
m_permissions |= lldb::eFilePermissionsWorldRead;
|
|
break;
|
|
case 't':
|
|
m_permissions |= lldb::eFilePermissionsWorldWrite;
|
|
break;
|
|
case 'e':
|
|
m_permissions |= lldb::eFilePermissionsWorldExecute;
|
|
break;
|
|
|
|
default:
|
|
error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option);
|
|
break;
|
|
}
|
|
|
|
return error;
|
|
}
|
|
|
|
void
|
|
OptionParsingStarting (CommandInterpreter &interpreter) override
|
|
{
|
|
m_permissions = 0;
|
|
}
|
|
|
|
uint32_t
|
|
GetNumDefinitions () override
|
|
{
|
|
return llvm::array_lengthof(g_permissions_options);
|
|
}
|
|
|
|
const lldb_private::OptionDefinition*
|
|
GetDefinitions () override
|
|
{
|
|
return g_permissions_options;
|
|
}
|
|
|
|
// Instance variables to hold the values for command options.
|
|
|
|
uint32_t m_permissions;
|
|
private:
|
|
DISALLOW_COPY_AND_ASSIGN(OptionPermissions);
|
|
};
|
|
|
|
//----------------------------------------------------------------------
|
|
// "platform select <platform-name>"
|
|
//----------------------------------------------------------------------
|
|
class CommandObjectPlatformSelect : public CommandObjectParsed
|
|
{
|
|
public:
|
|
CommandObjectPlatformSelect (CommandInterpreter &interpreter) :
|
|
CommandObjectParsed (interpreter,
|
|
"platform select",
|
|
"Create a platform if needed and select it as the current platform.",
|
|
"platform select <platform-name>",
|
|
0),
|
|
m_option_group (interpreter),
|
|
m_platform_options (false) // Don't include the "--platform" option by passing false
|
|
{
|
|
m_option_group.Append (&m_platform_options, LLDB_OPT_SET_ALL, 1);
|
|
m_option_group.Finalize();
|
|
}
|
|
|
|
~CommandObjectPlatformSelect () override
|
|
{
|
|
}
|
|
|
|
int
|
|
HandleCompletion (Args &input,
|
|
int &cursor_index,
|
|
int &cursor_char_position,
|
|
int match_start_point,
|
|
int max_return_elements,
|
|
bool &word_complete,
|
|
StringList &matches) override
|
|
{
|
|
std::string completion_str (input.GetArgumentAtIndex(cursor_index));
|
|
completion_str.erase (cursor_char_position);
|
|
|
|
CommandCompletions::PlatformPluginNames (m_interpreter,
|
|
completion_str.c_str(),
|
|
match_start_point,
|
|
max_return_elements,
|
|
NULL,
|
|
word_complete,
|
|
matches);
|
|
return matches.GetSize();
|
|
}
|
|
|
|
Options *
|
|
GetOptions () override
|
|
{
|
|
return &m_option_group;
|
|
}
|
|
|
|
protected:
|
|
bool
|
|
DoExecute (Args& args, CommandReturnObject &result) override
|
|
{
|
|
if (args.GetArgumentCount() == 1)
|
|
{
|
|
const char *platform_name = args.GetArgumentAtIndex (0);
|
|
if (platform_name && platform_name[0])
|
|
{
|
|
const bool select = true;
|
|
m_platform_options.SetPlatformName (platform_name);
|
|
Error error;
|
|
ArchSpec platform_arch;
|
|
PlatformSP platform_sp (m_platform_options.CreatePlatformWithOptions (m_interpreter, ArchSpec(), select, error, platform_arch));
|
|
if (platform_sp)
|
|
{
|
|
m_interpreter.GetDebugger().GetPlatformList().SetSelectedPlatform(platform_sp);
|
|
|
|
platform_sp->GetStatus (result.GetOutputStream());
|
|
result.SetStatus (eReturnStatusSuccessFinishResult);
|
|
}
|
|
else
|
|
{
|
|
result.AppendError(error.AsCString());
|
|
result.SetStatus (eReturnStatusFailed);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
result.AppendError ("invalid platform name");
|
|
result.SetStatus (eReturnStatusFailed);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
result.AppendError ("platform create takes a platform name as an argument\n");
|
|
result.SetStatus (eReturnStatusFailed);
|
|
}
|
|
return result.Succeeded();
|
|
}
|
|
|
|
OptionGroupOptions m_option_group;
|
|
OptionGroupPlatform m_platform_options;
|
|
};
|
|
|
|
//----------------------------------------------------------------------
|
|
// "platform list"
|
|
//----------------------------------------------------------------------
|
|
class CommandObjectPlatformList : public CommandObjectParsed
|
|
{
|
|
public:
|
|
CommandObjectPlatformList (CommandInterpreter &interpreter) :
|
|
CommandObjectParsed (interpreter,
|
|
"platform list",
|
|
"List all platforms that are available.",
|
|
NULL,
|
|
0)
|
|
{
|
|
}
|
|
|
|
~CommandObjectPlatformList () override
|
|
{
|
|
}
|
|
|
|
protected:
|
|
bool
|
|
DoExecute (Args& args, CommandReturnObject &result) override
|
|
{
|
|
Stream &ostrm = result.GetOutputStream();
|
|
ostrm.Printf("Available platforms:\n");
|
|
|
|
PlatformSP host_platform_sp (Platform::GetHostPlatform());
|
|
ostrm.Printf ("%s: %s\n",
|
|
host_platform_sp->GetPluginName().GetCString(),
|
|
host_platform_sp->GetDescription());
|
|
|
|
uint32_t idx;
|
|
for (idx = 0; 1; ++idx)
|
|
{
|
|
const char *plugin_name = PluginManager::GetPlatformPluginNameAtIndex (idx);
|
|
if (plugin_name == NULL)
|
|
break;
|
|
const char *plugin_desc = PluginManager::GetPlatformPluginDescriptionAtIndex (idx);
|
|
if (plugin_desc == NULL)
|
|
break;
|
|
ostrm.Printf("%s: %s\n", plugin_name, plugin_desc);
|
|
}
|
|
|
|
if (idx == 0)
|
|
{
|
|
result.AppendError ("no platforms are available\n");
|
|
result.SetStatus (eReturnStatusFailed);
|
|
}
|
|
else
|
|
result.SetStatus (eReturnStatusSuccessFinishResult);
|
|
return result.Succeeded();
|
|
}
|
|
};
|
|
|
|
//----------------------------------------------------------------------
|
|
// "platform status"
|
|
//----------------------------------------------------------------------
|
|
class CommandObjectPlatformStatus : public CommandObjectParsed
|
|
{
|
|
public:
|
|
CommandObjectPlatformStatus (CommandInterpreter &interpreter) :
|
|
CommandObjectParsed (interpreter,
|
|
"platform status",
|
|
"Display status for the currently selected platform.",
|
|
NULL,
|
|
0)
|
|
{
|
|
}
|
|
|
|
~CommandObjectPlatformStatus () override
|
|
{
|
|
}
|
|
|
|
protected:
|
|
bool
|
|
DoExecute (Args& args, CommandReturnObject &result) override
|
|
{
|
|
Stream &ostrm = result.GetOutputStream();
|
|
|
|
Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
|
|
PlatformSP platform_sp;
|
|
if (target)
|
|
{
|
|
platform_sp = target->GetPlatform();
|
|
}
|
|
if (!platform_sp)
|
|
{
|
|
platform_sp = m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform();
|
|
}
|
|
if (platform_sp)
|
|
{
|
|
platform_sp->GetStatus (ostrm);
|
|
result.SetStatus (eReturnStatusSuccessFinishResult);
|
|
}
|
|
else
|
|
{
|
|
result.AppendError ("no platform us currently selected\n");
|
|
result.SetStatus (eReturnStatusFailed);
|
|
}
|
|
return result.Succeeded();
|
|
}
|
|
};
|
|
|
|
//----------------------------------------------------------------------
|
|
// "platform connect <connect-url>"
|
|
//----------------------------------------------------------------------
|
|
class CommandObjectPlatformConnect : public CommandObjectParsed
|
|
{
|
|
public:
|
|
CommandObjectPlatformConnect (CommandInterpreter &interpreter) :
|
|
CommandObjectParsed (interpreter,
|
|
"platform connect",
|
|
"Connect a platform by name to be the currently selected platform.",
|
|
"platform connect <connect-url>",
|
|
0)
|
|
{
|
|
}
|
|
|
|
~CommandObjectPlatformConnect () override
|
|
{
|
|
}
|
|
|
|
protected:
|
|
bool
|
|
DoExecute (Args& args, CommandReturnObject &result) override
|
|
{
|
|
Stream &ostrm = result.GetOutputStream();
|
|
|
|
PlatformSP platform_sp (m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform());
|
|
if (platform_sp)
|
|
{
|
|
Error error (platform_sp->ConnectRemote (args));
|
|
if (error.Success())
|
|
{
|
|
platform_sp->GetStatus (ostrm);
|
|
result.SetStatus (eReturnStatusSuccessFinishResult);
|
|
|
|
platform_sp->ConnectToWaitingProcesses(m_interpreter.GetDebugger(), error);
|
|
if (error.Fail())
|
|
{
|
|
result.AppendError (error.AsCString());
|
|
result.SetStatus (eReturnStatusFailed);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
result.AppendErrorWithFormat ("%s\n", error.AsCString());
|
|
result.SetStatus (eReturnStatusFailed);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
result.AppendError ("no platform is currently selected\n");
|
|
result.SetStatus (eReturnStatusFailed);
|
|
}
|
|
return result.Succeeded();
|
|
}
|
|
|
|
Options *
|
|
GetOptions () override
|
|
{
|
|
PlatformSP platform_sp (m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform());
|
|
OptionGroupOptions* m_platform_options = NULL;
|
|
if (platform_sp)
|
|
{
|
|
m_platform_options = platform_sp->GetConnectionOptions(m_interpreter);
|
|
if (m_platform_options != NULL && !m_platform_options->m_did_finalize)
|
|
m_platform_options->Finalize();
|
|
}
|
|
return m_platform_options;
|
|
}
|
|
|
|
};
|
|
|
|
//----------------------------------------------------------------------
|
|
// "platform disconnect"
|
|
//----------------------------------------------------------------------
|
|
class CommandObjectPlatformDisconnect : public CommandObjectParsed
|
|
{
|
|
public:
|
|
CommandObjectPlatformDisconnect (CommandInterpreter &interpreter) :
|
|
CommandObjectParsed (interpreter,
|
|
"platform disconnect",
|
|
"Disconnect a platform by name to be the currently selected platform.",
|
|
"platform disconnect",
|
|
0)
|
|
{
|
|
}
|
|
|
|
~CommandObjectPlatformDisconnect () override
|
|
{
|
|
}
|
|
|
|
protected:
|
|
bool
|
|
DoExecute (Args& args, CommandReturnObject &result) override
|
|
{
|
|
PlatformSP platform_sp (m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform());
|
|
if (platform_sp)
|
|
{
|
|
if (args.GetArgumentCount() == 0)
|
|
{
|
|
Error error;
|
|
|
|
if (platform_sp->IsConnected())
|
|
{
|
|
// Cache the instance name if there is one since we are
|
|
// about to disconnect and the name might go with it.
|
|
const char *hostname_cstr = platform_sp->GetHostname();
|
|
std::string hostname;
|
|
if (hostname_cstr)
|
|
hostname.assign (hostname_cstr);
|
|
|
|
error = platform_sp->DisconnectRemote ();
|
|
if (error.Success())
|
|
{
|
|
Stream &ostrm = result.GetOutputStream();
|
|
if (hostname.empty())
|
|
ostrm.Printf ("Disconnected from \"%s\"\n", platform_sp->GetPluginName().GetCString());
|
|
else
|
|
ostrm.Printf ("Disconnected from \"%s\"\n", hostname.c_str());
|
|
result.SetStatus (eReturnStatusSuccessFinishResult);
|
|
}
|
|
else
|
|
{
|
|
result.AppendErrorWithFormat ("%s", error.AsCString());
|
|
result.SetStatus (eReturnStatusFailed);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Not connected...
|
|
result.AppendErrorWithFormat ("not connected to '%s'", platform_sp->GetPluginName().GetCString());
|
|
result.SetStatus (eReturnStatusFailed);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Bad args
|
|
result.AppendError ("\"platform disconnect\" doesn't take any arguments");
|
|
result.SetStatus (eReturnStatusFailed);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
result.AppendError ("no platform is currently selected");
|
|
result.SetStatus (eReturnStatusFailed);
|
|
}
|
|
return result.Succeeded();
|
|
}
|
|
};
|
|
|
|
//----------------------------------------------------------------------
|
|
// "platform settings"
|
|
//----------------------------------------------------------------------
|
|
class CommandObjectPlatformSettings : public CommandObjectParsed
|
|
{
|
|
public:
|
|
CommandObjectPlatformSettings (CommandInterpreter &interpreter) :
|
|
CommandObjectParsed (interpreter,
|
|
"platform settings",
|
|
"Set settings for the current target's platform, or for a platform by name.",
|
|
"platform settings",
|
|
0),
|
|
m_options (interpreter),
|
|
m_option_working_dir (LLDB_OPT_SET_1, false, "working-dir", 'w', 0, eArgTypePath, "The working directory for the platform.")
|
|
{
|
|
m_options.Append (&m_option_working_dir, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
|
|
}
|
|
|
|
~CommandObjectPlatformSettings () override
|
|
{
|
|
}
|
|
|
|
protected:
|
|
bool
|
|
DoExecute (Args& args, CommandReturnObject &result) override
|
|
{
|
|
PlatformSP platform_sp (m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform());
|
|
if (platform_sp)
|
|
{
|
|
if (m_option_working_dir.GetOptionValue().OptionWasSet())
|
|
platform_sp->SetWorkingDirectory(m_option_working_dir.GetOptionValue().GetCurrentValue());
|
|
}
|
|
else
|
|
{
|
|
result.AppendError ("no platform is currently selected");
|
|
result.SetStatus (eReturnStatusFailed);
|
|
}
|
|
return result.Succeeded();
|
|
}
|
|
|
|
Options *
|
|
GetOptions () override
|
|
{
|
|
if (m_options.DidFinalize() == false)
|
|
m_options.Finalize();
|
|
return &m_options;
|
|
}
|
|
protected:
|
|
|
|
OptionGroupOptions m_options;
|
|
OptionGroupFile m_option_working_dir;
|
|
|
|
};
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
// "platform mkdir"
|
|
//----------------------------------------------------------------------
|
|
class CommandObjectPlatformMkDir : public CommandObjectParsed
|
|
{
|
|
public:
|
|
CommandObjectPlatformMkDir (CommandInterpreter &interpreter) :
|
|
CommandObjectParsed (interpreter,
|
|
"platform mkdir",
|
|
"Make a new directory on the remote end.",
|
|
NULL,
|
|
0),
|
|
m_options(interpreter)
|
|
{
|
|
}
|
|
|
|
~CommandObjectPlatformMkDir () override
|
|
{
|
|
}
|
|
|
|
bool
|
|
DoExecute (Args& args, CommandReturnObject &result) override
|
|
{
|
|
PlatformSP platform_sp (m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform());
|
|
if (platform_sp)
|
|
{
|
|
std::string cmd_line;
|
|
args.GetCommandString(cmd_line);
|
|
uint32_t mode;
|
|
const OptionPermissions* options_permissions = (const OptionPermissions*)m_options.GetGroupWithOption('r');
|
|
if (options_permissions)
|
|
mode = options_permissions->m_permissions;
|
|
else
|
|
mode = lldb::eFilePermissionsUserRWX | lldb::eFilePermissionsGroupRWX | lldb::eFilePermissionsWorldRX;
|
|
Error error = platform_sp->MakeDirectory(FileSpec{cmd_line, false}, mode);
|
|
if (error.Success())
|
|
{
|
|
result.SetStatus (eReturnStatusSuccessFinishResult);
|
|
}
|
|
else
|
|
{
|
|
result.AppendError(error.AsCString());
|
|
result.SetStatus (eReturnStatusFailed);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
result.AppendError ("no platform currently selected\n");
|
|
result.SetStatus (eReturnStatusFailed);
|
|
}
|
|
return result.Succeeded();
|
|
}
|
|
|
|
Options *
|
|
GetOptions () override
|
|
{
|
|
if (m_options.DidFinalize() == false)
|
|
{
|
|
m_options.Append(new OptionPermissions());
|
|
m_options.Finalize();
|
|
}
|
|
return &m_options;
|
|
}
|
|
OptionGroupOptions m_options;
|
|
|
|
};
|
|
|
|
//----------------------------------------------------------------------
|
|
// "platform fopen"
|
|
//----------------------------------------------------------------------
|
|
class CommandObjectPlatformFOpen : public CommandObjectParsed
|
|
{
|
|
public:
|
|
CommandObjectPlatformFOpen (CommandInterpreter &interpreter) :
|
|
CommandObjectParsed (interpreter,
|
|
"platform file open",
|
|
"Open a file on the remote end.",
|
|
NULL,
|
|
0),
|
|
m_options(interpreter)
|
|
{
|
|
}
|
|
|
|
~CommandObjectPlatformFOpen () override
|
|
{
|
|
}
|
|
|
|
bool
|
|
DoExecute (Args& args, CommandReturnObject &result) override
|
|
{
|
|
PlatformSP platform_sp (m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform());
|
|
if (platform_sp)
|
|
{
|
|
Error error;
|
|
std::string cmd_line;
|
|
args.GetCommandString(cmd_line);
|
|
mode_t perms;
|
|
const OptionPermissions* options_permissions = (const OptionPermissions*)m_options.GetGroupWithOption('r');
|
|
if (options_permissions)
|
|
perms = options_permissions->m_permissions;
|
|
else
|
|
perms = lldb::eFilePermissionsUserRW | lldb::eFilePermissionsGroupRW | lldb::eFilePermissionsWorldRead;
|
|
lldb::user_id_t fd = platform_sp->OpenFile(FileSpec(cmd_line.c_str(),false),
|
|
File::eOpenOptionRead | File::eOpenOptionWrite |
|
|
File::eOpenOptionAppend | File::eOpenOptionCanCreate,
|
|
perms,
|
|
error);
|
|
if (error.Success())
|
|
{
|
|
result.AppendMessageWithFormat("File Descriptor = %" PRIu64 "\n",fd);
|
|
result.SetStatus (eReturnStatusSuccessFinishResult);
|
|
}
|
|
else
|
|
{
|
|
result.AppendError(error.AsCString());
|
|
result.SetStatus (eReturnStatusFailed);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
result.AppendError ("no platform currently selected\n");
|
|
result.SetStatus (eReturnStatusFailed);
|
|
}
|
|
return result.Succeeded();
|
|
}
|
|
Options *
|
|
GetOptions () override
|
|
{
|
|
if (m_options.DidFinalize() == false)
|
|
{
|
|
m_options.Append(new OptionPermissions());
|
|
m_options.Finalize();
|
|
}
|
|
return &m_options;
|
|
}
|
|
OptionGroupOptions m_options;
|
|
};
|
|
|
|
//----------------------------------------------------------------------
|
|
// "platform fclose"
|
|
//----------------------------------------------------------------------
|
|
class CommandObjectPlatformFClose : public CommandObjectParsed
|
|
{
|
|
public:
|
|
CommandObjectPlatformFClose (CommandInterpreter &interpreter) :
|
|
CommandObjectParsed (interpreter,
|
|
"platform file close",
|
|
"Close a file on the remote end.",
|
|
NULL,
|
|
0)
|
|
{
|
|
}
|
|
|
|
~CommandObjectPlatformFClose () override
|
|
{
|
|
}
|
|
|
|
bool
|
|
DoExecute (Args& args, CommandReturnObject &result) override
|
|
{
|
|
PlatformSP platform_sp (m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform());
|
|
if (platform_sp)
|
|
{
|
|
std::string cmd_line;
|
|
args.GetCommandString(cmd_line);
|
|
const lldb::user_id_t fd = StringConvert::ToUInt64(cmd_line.c_str(), UINT64_MAX);
|
|
Error error;
|
|
bool success = platform_sp->CloseFile(fd, error);
|
|
if (success)
|
|
{
|
|
result.AppendMessageWithFormat("file %" PRIu64 " closed.\n", fd);
|
|
result.SetStatus (eReturnStatusSuccessFinishResult);
|
|
}
|
|
else
|
|
{
|
|
result.AppendError(error.AsCString());
|
|
result.SetStatus (eReturnStatusFailed);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
result.AppendError ("no platform currently selected\n");
|
|
result.SetStatus (eReturnStatusFailed);
|
|
}
|
|
return result.Succeeded();
|
|
}
|
|
};
|
|
|
|
//----------------------------------------------------------------------
|
|
// "platform fread"
|
|
//----------------------------------------------------------------------
|
|
class CommandObjectPlatformFRead : public CommandObjectParsed
|
|
{
|
|
public:
|
|
CommandObjectPlatformFRead (CommandInterpreter &interpreter) :
|
|
CommandObjectParsed (interpreter,
|
|
"platform file read",
|
|
"Read data from a file on the remote end.",
|
|
NULL,
|
|
0),
|
|
m_options (interpreter)
|
|
{
|
|
}
|
|
|
|
~CommandObjectPlatformFRead () override
|
|
{
|
|
}
|
|
|
|
bool
|
|
DoExecute (Args& args, CommandReturnObject &result) override
|
|
{
|
|
PlatformSP platform_sp (m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform());
|
|
if (platform_sp)
|
|
{
|
|
std::string cmd_line;
|
|
args.GetCommandString(cmd_line);
|
|
const lldb::user_id_t fd = StringConvert::ToUInt64(cmd_line.c_str(), UINT64_MAX);
|
|
std::string buffer(m_options.m_count,0);
|
|
Error error;
|
|
uint32_t retcode = platform_sp->ReadFile(fd, m_options.m_offset, &buffer[0], m_options.m_count, error);
|
|
result.AppendMessageWithFormat("Return = %d\n",retcode);
|
|
result.AppendMessageWithFormat("Data = \"%s\"\n",buffer.c_str());
|
|
result.SetStatus (eReturnStatusSuccessFinishResult);
|
|
}
|
|
else
|
|
{
|
|
result.AppendError ("no platform currently selected\n");
|
|
result.SetStatus (eReturnStatusFailed);
|
|
}
|
|
return result.Succeeded();
|
|
}
|
|
Options *
|
|
GetOptions () override
|
|
{
|
|
return &m_options;
|
|
}
|
|
|
|
protected:
|
|
class CommandOptions : public Options
|
|
{
|
|
public:
|
|
|
|
CommandOptions (CommandInterpreter &interpreter) :
|
|
Options (interpreter)
|
|
{
|
|
}
|
|
|
|
~CommandOptions () override
|
|
{
|
|
}
|
|
|
|
Error
|
|
SetOptionValue (uint32_t option_idx, const char *option_arg) override
|
|
{
|
|
Error error;
|
|
char short_option = (char) m_getopt_table[option_idx].val;
|
|
bool success = false;
|
|
|
|
switch (short_option)
|
|
{
|
|
case 'o':
|
|
m_offset = StringConvert::ToUInt32(option_arg, 0, 0, &success);
|
|
if (!success)
|
|
error.SetErrorStringWithFormat("invalid offset: '%s'", option_arg);
|
|
break;
|
|
case 'c':
|
|
m_count = StringConvert::ToUInt32(option_arg, 0, 0, &success);
|
|
if (!success)
|
|
error.SetErrorStringWithFormat("invalid offset: '%s'", option_arg);
|
|
break;
|
|
|
|
default:
|
|
error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option);
|
|
break;
|
|
}
|
|
|
|
return error;
|
|
}
|
|
|
|
void
|
|
OptionParsingStarting () override
|
|
{
|
|
m_offset = 0;
|
|
m_count = 1;
|
|
}
|
|
|
|
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.
|
|
|
|
uint32_t m_offset;
|
|
uint32_t m_count;
|
|
};
|
|
CommandOptions m_options;
|
|
};
|
|
OptionDefinition
|
|
CommandObjectPlatformFRead::CommandOptions::g_option_table[] =
|
|
{
|
|
{ LLDB_OPT_SET_1, false, "offset" , 'o', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeIndex , "Offset into the file at which to start reading." },
|
|
{ LLDB_OPT_SET_1, false, "count" , 'c', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeCount , "Number of bytes to read from the file." },
|
|
{ 0 , false, NULL , 0 , 0 , NULL, NULL, 0, eArgTypeNone , NULL }
|
|
};
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
// "platform fwrite"
|
|
//----------------------------------------------------------------------
|
|
class CommandObjectPlatformFWrite : public CommandObjectParsed
|
|
{
|
|
public:
|
|
CommandObjectPlatformFWrite (CommandInterpreter &interpreter) :
|
|
CommandObjectParsed (interpreter,
|
|
"platform file write",
|
|
"Write data to a file on the remote end.",
|
|
NULL,
|
|
0),
|
|
m_options (interpreter)
|
|
{
|
|
}
|
|
|
|
~CommandObjectPlatformFWrite () override
|
|
{
|
|
}
|
|
|
|
bool
|
|
DoExecute (Args& args, CommandReturnObject &result) override
|
|
{
|
|
PlatformSP platform_sp (m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform());
|
|
if (platform_sp)
|
|
{
|
|
std::string cmd_line;
|
|
args.GetCommandString(cmd_line);
|
|
Error error;
|
|
const lldb::user_id_t fd = StringConvert::ToUInt64(cmd_line.c_str(), UINT64_MAX);
|
|
uint32_t retcode = platform_sp->WriteFile (fd,
|
|
m_options.m_offset,
|
|
&m_options.m_data[0],
|
|
m_options.m_data.size(),
|
|
error);
|
|
result.AppendMessageWithFormat("Return = %d\n",retcode);
|
|
result.SetStatus (eReturnStatusSuccessFinishResult);
|
|
}
|
|
else
|
|
{
|
|
result.AppendError ("no platform currently selected\n");
|
|
result.SetStatus (eReturnStatusFailed);
|
|
}
|
|
return result.Succeeded();
|
|
}
|
|
Options *
|
|
GetOptions () override
|
|
{
|
|
return &m_options;
|
|
}
|
|
|
|
protected:
|
|
class CommandOptions : public Options
|
|
{
|
|
public:
|
|
|
|
CommandOptions (CommandInterpreter &interpreter) :
|
|
Options (interpreter)
|
|
{
|
|
}
|
|
|
|
~CommandOptions () override
|
|
{
|
|
}
|
|
|
|
Error
|
|
SetOptionValue (uint32_t option_idx, const char *option_arg) override
|
|
{
|
|
Error error;
|
|
char short_option = (char) m_getopt_table[option_idx].val;
|
|
bool success = false;
|
|
|
|
switch (short_option)
|
|
{
|
|
case 'o':
|
|
m_offset = StringConvert::ToUInt32(option_arg, 0, 0, &success);
|
|
if (!success)
|
|
error.SetErrorStringWithFormat("invalid offset: '%s'", option_arg);
|
|
break;
|
|
case 'd':
|
|
m_data.assign(option_arg);
|
|
break;
|
|
|
|
default:
|
|
error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option);
|
|
break;
|
|
}
|
|
|
|
return error;
|
|
}
|
|
|
|
void
|
|
OptionParsingStarting () override
|
|
{
|
|
m_offset = 0;
|
|
m_data.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.
|
|
|
|
uint32_t m_offset;
|
|
std::string m_data;
|
|
};
|
|
CommandOptions m_options;
|
|
};
|
|
OptionDefinition
|
|
CommandObjectPlatformFWrite::CommandOptions::g_option_table[] =
|
|
{
|
|
{ LLDB_OPT_SET_1, false, "offset" , 'o', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeIndex , "Offset into the file at which to start reading." },
|
|
{ LLDB_OPT_SET_1, false, "data" , 'd', OptionParser::eRequiredArgument , NULL, NULL, 0, eArgTypeValue , "Text to write to the file." },
|
|
{ 0 , false, NULL , 0 , 0 , NULL, NULL, 0, eArgTypeNone , NULL }
|
|
};
|
|
|
|
class CommandObjectPlatformFile : public CommandObjectMultiword
|
|
{
|
|
public:
|
|
//------------------------------------------------------------------
|
|
// Constructors and Destructors
|
|
//------------------------------------------------------------------
|
|
CommandObjectPlatformFile (CommandInterpreter &interpreter) :
|
|
CommandObjectMultiword (interpreter,
|
|
"platform file",
|
|
"A set of commands to manage file access through a platform",
|
|
"platform file [open|close|read|write] ...")
|
|
{
|
|
LoadSubCommand ("open", CommandObjectSP (new CommandObjectPlatformFOpen (interpreter)));
|
|
LoadSubCommand ("close", CommandObjectSP (new CommandObjectPlatformFClose (interpreter)));
|
|
LoadSubCommand ("read", CommandObjectSP (new CommandObjectPlatformFRead (interpreter)));
|
|
LoadSubCommand ("write", CommandObjectSP (new CommandObjectPlatformFWrite (interpreter)));
|
|
}
|
|
|
|
~CommandObjectPlatformFile () override
|
|
{
|
|
}
|
|
|
|
private:
|
|
//------------------------------------------------------------------
|
|
// For CommandObjectPlatform only
|
|
//------------------------------------------------------------------
|
|
DISALLOW_COPY_AND_ASSIGN (CommandObjectPlatformFile);
|
|
};
|
|
|
|
//----------------------------------------------------------------------
|
|
// "platform get-file remote-file-path host-file-path"
|
|
//----------------------------------------------------------------------
|
|
class CommandObjectPlatformGetFile : public CommandObjectParsed
|
|
{
|
|
public:
|
|
CommandObjectPlatformGetFile (CommandInterpreter &interpreter) :
|
|
CommandObjectParsed (interpreter,
|
|
"platform get-file",
|
|
"Transfer a file from the remote end to the local host.",
|
|
"platform get-file <remote-file-spec> <local-file-spec>",
|
|
0)
|
|
{
|
|
SetHelpLong(
|
|
R"(Examples:
|
|
|
|
(lldb) platform get-file /the/remote/file/path /the/local/file/path
|
|
|
|
Transfer a file from the remote end with file path /the/remote/file/path to the local host.)"
|
|
);
|
|
|
|
CommandArgumentEntry arg1, arg2;
|
|
CommandArgumentData file_arg_remote, file_arg_host;
|
|
|
|
// Define the first (and only) variant of this arg.
|
|
file_arg_remote.arg_type = eArgTypeFilename;
|
|
file_arg_remote.arg_repetition = eArgRepeatPlain;
|
|
// There is only one variant this argument could be; put it into the argument entry.
|
|
arg1.push_back (file_arg_remote);
|
|
|
|
// Define the second (and only) variant of this arg.
|
|
file_arg_host.arg_type = eArgTypeFilename;
|
|
file_arg_host.arg_repetition = eArgRepeatPlain;
|
|
// There is only one variant this argument could be; put it into the argument entry.
|
|
arg2.push_back (file_arg_host);
|
|
|
|
// Push the data for the first and the second arguments into the m_arguments vector.
|
|
m_arguments.push_back (arg1);
|
|
m_arguments.push_back (arg2);
|
|
}
|
|
|
|
~CommandObjectPlatformGetFile () override
|
|
{
|
|
}
|
|
|
|
bool
|
|
DoExecute (Args& args, CommandReturnObject &result) override
|
|
{
|
|
// If the number of arguments is incorrect, issue an error message.
|
|
if (args.GetArgumentCount() != 2)
|
|
{
|
|
result.GetErrorStream().Printf("error: required arguments missing; specify both the source and destination file paths\n");
|
|
result.SetStatus(eReturnStatusFailed);
|
|
return false;
|
|
}
|
|
|
|
PlatformSP platform_sp (m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform());
|
|
if (platform_sp)
|
|
{
|
|
const char *remote_file_path = args.GetArgumentAtIndex(0);
|
|
const char *local_file_path = args.GetArgumentAtIndex(1);
|
|
Error error = platform_sp->GetFile(FileSpec(remote_file_path, false),
|
|
FileSpec(local_file_path, false));
|
|
if (error.Success())
|
|
{
|
|
result.AppendMessageWithFormat("successfully get-file from %s (remote) to %s (host)\n",
|
|
remote_file_path, local_file_path);
|
|
result.SetStatus (eReturnStatusSuccessFinishResult);
|
|
}
|
|
else
|
|
{
|
|
result.AppendMessageWithFormat("get-file failed: %s\n", error.AsCString());
|
|
result.SetStatus (eReturnStatusFailed);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
result.AppendError ("no platform currently selected\n");
|
|
result.SetStatus (eReturnStatusFailed);
|
|
}
|
|
return result.Succeeded();
|
|
}
|
|
};
|
|
|
|
//----------------------------------------------------------------------
|
|
// "platform get-size remote-file-path"
|
|
//----------------------------------------------------------------------
|
|
class CommandObjectPlatformGetSize : public CommandObjectParsed
|
|
{
|
|
public:
|
|
CommandObjectPlatformGetSize (CommandInterpreter &interpreter) :
|
|
CommandObjectParsed (interpreter,
|
|
"platform get-size",
|
|
"Get the file size from the remote end.",
|
|
"platform get-size <remote-file-spec>",
|
|
0)
|
|
{
|
|
SetHelpLong(
|
|
R"(Examples:
|
|
|
|
(lldb) platform get-size /the/remote/file/path
|
|
|
|
Get the file size from the remote end with path /the/remote/file/path.)"
|
|
);
|
|
|
|
CommandArgumentEntry arg1;
|
|
CommandArgumentData file_arg_remote;
|
|
|
|
// Define the first (and only) variant of this arg.
|
|
file_arg_remote.arg_type = eArgTypeFilename;
|
|
file_arg_remote.arg_repetition = eArgRepeatPlain;
|
|
// There is only one variant this argument could be; put it into the argument entry.
|
|
arg1.push_back (file_arg_remote);
|
|
|
|
// Push the data for the first argument into the m_arguments vector.
|
|
m_arguments.push_back (arg1);
|
|
}
|
|
|
|
~CommandObjectPlatformGetSize () override
|
|
{
|
|
}
|
|
|
|
bool
|
|
DoExecute (Args& args, CommandReturnObject &result) override
|
|
{
|
|
// If the number of arguments is incorrect, issue an error message.
|
|
if (args.GetArgumentCount() != 1)
|
|
{
|
|
result.GetErrorStream().Printf("error: required argument missing; specify the source file path as the only argument\n");
|
|
result.SetStatus(eReturnStatusFailed);
|
|
return false;
|
|
}
|
|
|
|
PlatformSP platform_sp (m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform());
|
|
if (platform_sp)
|
|
{
|
|
std::string remote_file_path(args.GetArgumentAtIndex(0));
|
|
user_id_t size = platform_sp->GetFileSize(FileSpec(remote_file_path.c_str(), false));
|
|
if (size != UINT64_MAX)
|
|
{
|
|
result.AppendMessageWithFormat("File size of %s (remote): %" PRIu64 "\n", remote_file_path.c_str(), size);
|
|
result.SetStatus (eReturnStatusSuccessFinishResult);
|
|
}
|
|
else
|
|
{
|
|
result.AppendMessageWithFormat("Error getting file size of %s (remote)\n", remote_file_path.c_str());
|
|
result.SetStatus (eReturnStatusFailed);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
result.AppendError ("no platform currently selected\n");
|
|
result.SetStatus (eReturnStatusFailed);
|
|
}
|
|
return result.Succeeded();
|
|
}
|
|
};
|
|
|
|
//----------------------------------------------------------------------
|
|
// "platform put-file"
|
|
//----------------------------------------------------------------------
|
|
class CommandObjectPlatformPutFile : public CommandObjectParsed
|
|
{
|
|
public:
|
|
CommandObjectPlatformPutFile (CommandInterpreter &interpreter) :
|
|
CommandObjectParsed (interpreter,
|
|
"platform put-file",
|
|
"Transfer a file from this system to the remote end.",
|
|
NULL,
|
|
0)
|
|
{
|
|
}
|
|
|
|
~CommandObjectPlatformPutFile () override
|
|
{
|
|
}
|
|
|
|
bool
|
|
DoExecute (Args& args, CommandReturnObject &result) override
|
|
{
|
|
const char* src = args.GetArgumentAtIndex(0);
|
|
const char* dst = args.GetArgumentAtIndex(1);
|
|
|
|
FileSpec src_fs(src, true);
|
|
FileSpec dst_fs(dst ? dst : src_fs.GetFilename().GetCString(), false);
|
|
|
|
PlatformSP platform_sp (m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform());
|
|
if (platform_sp)
|
|
{
|
|
Error error (platform_sp->PutFile(src_fs, dst_fs));
|
|
if (error.Success())
|
|
{
|
|
result.SetStatus (eReturnStatusSuccessFinishNoResult);
|
|
}
|
|
else
|
|
{
|
|
result.AppendError (error.AsCString());
|
|
result.SetStatus (eReturnStatusFailed);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
result.AppendError ("no platform currently selected\n");
|
|
result.SetStatus (eReturnStatusFailed);
|
|
}
|
|
return result.Succeeded();
|
|
}
|
|
};
|
|
|
|
//----------------------------------------------------------------------
|
|
// "platform process launch"
|
|
//----------------------------------------------------------------------
|
|
class CommandObjectPlatformProcessLaunch : public CommandObjectParsed
|
|
{
|
|
public:
|
|
CommandObjectPlatformProcessLaunch (CommandInterpreter &interpreter) :
|
|
CommandObjectParsed (interpreter,
|
|
"platform process launch",
|
|
"Launch a new process on a remote platform.",
|
|
"platform process launch program",
|
|
eCommandRequiresTarget | eCommandTryTargetAPILock),
|
|
m_options (interpreter)
|
|
{
|
|
}
|
|
|
|
~CommandObjectPlatformProcessLaunch () override
|
|
{
|
|
}
|
|
|
|
Options *
|
|
GetOptions () override
|
|
{
|
|
return &m_options;
|
|
}
|
|
|
|
protected:
|
|
bool
|
|
DoExecute (Args& args, CommandReturnObject &result) override
|
|
{
|
|
Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
|
|
PlatformSP platform_sp;
|
|
if (target)
|
|
{
|
|
platform_sp = target->GetPlatform();
|
|
}
|
|
if (!platform_sp)
|
|
{
|
|
platform_sp = m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform();
|
|
}
|
|
|
|
if (platform_sp)
|
|
{
|
|
Error error;
|
|
const size_t argc = args.GetArgumentCount();
|
|
Target *target = m_exe_ctx.GetTargetPtr();
|
|
Module *exe_module = target->GetExecutableModulePointer();
|
|
if (exe_module)
|
|
{
|
|
m_options.launch_info.GetExecutableFile () = exe_module->GetFileSpec();
|
|
char exe_path[PATH_MAX];
|
|
if (m_options.launch_info.GetExecutableFile ().GetPath (exe_path, sizeof(exe_path)))
|
|
m_options.launch_info.GetArguments().AppendArgument (exe_path);
|
|
m_options.launch_info.GetArchitecture() = exe_module->GetArchitecture();
|
|
}
|
|
|
|
if (argc > 0)
|
|
{
|
|
if (m_options.launch_info.GetExecutableFile ())
|
|
{
|
|
// We already have an executable file, so we will use this
|
|
// and all arguments to this function are extra arguments
|
|
m_options.launch_info.GetArguments().AppendArguments (args);
|
|
}
|
|
else
|
|
{
|
|
// We don't have any file yet, so the first argument is our
|
|
// executable, and the rest are program arguments
|
|
const bool first_arg_is_executable = true;
|
|
m_options.launch_info.SetArguments (args, first_arg_is_executable);
|
|
}
|
|
}
|
|
|
|
if (m_options.launch_info.GetExecutableFile ())
|
|
{
|
|
Debugger &debugger = m_interpreter.GetDebugger();
|
|
|
|
if (argc == 0)
|
|
target->GetRunArguments(m_options.launch_info.GetArguments());
|
|
|
|
ProcessSP process_sp (platform_sp->DebugProcess (m_options.launch_info,
|
|
debugger,
|
|
target,
|
|
error));
|
|
if (process_sp && process_sp->IsAlive())
|
|
{
|
|
result.SetStatus (eReturnStatusSuccessFinishNoResult);
|
|
return true;
|
|
}
|
|
|
|
if (error.Success())
|
|
result.AppendError ("process launch failed");
|
|
else
|
|
result.AppendError (error.AsCString());
|
|
result.SetStatus (eReturnStatusFailed);
|
|
}
|
|
else
|
|
{
|
|
result.AppendError ("'platform process launch' uses the current target file and arguments, or the executable and its arguments can be specified in this command");
|
|
result.SetStatus (eReturnStatusFailed);
|
|
return false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
result.AppendError ("no platform is selected\n");
|
|
}
|
|
return result.Succeeded();
|
|
}
|
|
|
|
protected:
|
|
ProcessLaunchCommandOptions m_options;
|
|
};
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
// "platform process list"
|
|
//----------------------------------------------------------------------
|
|
class CommandObjectPlatformProcessList : public CommandObjectParsed
|
|
{
|
|
public:
|
|
CommandObjectPlatformProcessList (CommandInterpreter &interpreter) :
|
|
CommandObjectParsed (interpreter,
|
|
"platform process list",
|
|
"List processes on a remote platform by name, pid, or many other matching attributes.",
|
|
"platform process list",
|
|
0),
|
|
m_options (interpreter)
|
|
{
|
|
}
|
|
|
|
~CommandObjectPlatformProcessList () override
|
|
{
|
|
}
|
|
|
|
Options *
|
|
GetOptions () override
|
|
{
|
|
return &m_options;
|
|
}
|
|
|
|
protected:
|
|
bool
|
|
DoExecute (Args& args, CommandReturnObject &result) override
|
|
{
|
|
Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
|
|
PlatformSP platform_sp;
|
|
if (target)
|
|
{
|
|
platform_sp = target->GetPlatform();
|
|
}
|
|
if (!platform_sp)
|
|
{
|
|
platform_sp = m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform();
|
|
}
|
|
|
|
if (platform_sp)
|
|
{
|
|
Error error;
|
|
if (args.GetArgumentCount() == 0)
|
|
{
|
|
|
|
if (platform_sp)
|
|
{
|
|
Stream &ostrm = result.GetOutputStream();
|
|
|
|
lldb::pid_t pid = m_options.match_info.GetProcessInfo().GetProcessID();
|
|
if (pid != LLDB_INVALID_PROCESS_ID)
|
|
{
|
|
ProcessInstanceInfo proc_info;
|
|
if (platform_sp->GetProcessInfo (pid, proc_info))
|
|
{
|
|
ProcessInstanceInfo::DumpTableHeader (ostrm, platform_sp.get(), m_options.show_args, m_options.verbose);
|
|
proc_info.DumpAsTableRow(ostrm, platform_sp.get(), m_options.show_args, m_options.verbose);
|
|
result.SetStatus (eReturnStatusSuccessFinishResult);
|
|
}
|
|
else
|
|
{
|
|
result.AppendErrorWithFormat ("no process found with pid = %" PRIu64 "\n", pid);
|
|
result.SetStatus (eReturnStatusFailed);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ProcessInstanceInfoList proc_infos;
|
|
const uint32_t matches = platform_sp->FindProcesses (m_options.match_info, proc_infos);
|
|
const char *match_desc = NULL;
|
|
const char *match_name = m_options.match_info.GetProcessInfo().GetName();
|
|
if (match_name && match_name[0])
|
|
{
|
|
switch (m_options.match_info.GetNameMatchType())
|
|
{
|
|
case eNameMatchIgnore: break;
|
|
case eNameMatchEquals: match_desc = "matched"; break;
|
|
case eNameMatchContains: match_desc = "contained"; break;
|
|
case eNameMatchStartsWith: match_desc = "started with"; break;
|
|
case eNameMatchEndsWith: match_desc = "ended with"; break;
|
|
case eNameMatchRegularExpression: match_desc = "matched the regular expression"; break;
|
|
}
|
|
}
|
|
|
|
if (matches == 0)
|
|
{
|
|
if (match_desc)
|
|
result.AppendErrorWithFormat ("no processes were found that %s \"%s\" on the \"%s\" platform\n",
|
|
match_desc,
|
|
match_name,
|
|
platform_sp->GetPluginName().GetCString());
|
|
else
|
|
result.AppendErrorWithFormat ("no processes were found on the \"%s\" platform\n", platform_sp->GetPluginName().GetCString());
|
|
result.SetStatus (eReturnStatusFailed);
|
|
}
|
|
else
|
|
{
|
|
result.AppendMessageWithFormat ("%u matching process%s found on \"%s\"",
|
|
matches,
|
|
matches > 1 ? "es were" : " was",
|
|
platform_sp->GetName().GetCString());
|
|
if (match_desc)
|
|
result.AppendMessageWithFormat (" whose name %s \"%s\"",
|
|
match_desc,
|
|
match_name);
|
|
result.AppendMessageWithFormat ("\n");
|
|
ProcessInstanceInfo::DumpTableHeader (ostrm, platform_sp.get(), m_options.show_args, m_options.verbose);
|
|
for (uint32_t i=0; i<matches; ++i)
|
|
{
|
|
proc_infos.GetProcessInfoAtIndex(i).DumpAsTableRow(ostrm, platform_sp.get(), m_options.show_args, m_options.verbose);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
result.AppendError ("invalid args: process list takes only options\n");
|
|
result.SetStatus (eReturnStatusFailed);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
result.AppendError ("no platform is selected\n");
|
|
result.SetStatus (eReturnStatusFailed);
|
|
}
|
|
return result.Succeeded();
|
|
}
|
|
|
|
class CommandOptions : public Options
|
|
{
|
|
public:
|
|
|
|
CommandOptions (CommandInterpreter &interpreter) :
|
|
Options (interpreter),
|
|
match_info ()
|
|
{
|
|
}
|
|
|
|
~CommandOptions () override
|
|
{
|
|
}
|
|
|
|
Error
|
|
SetOptionValue (uint32_t option_idx, const char *option_arg) override
|
|
{
|
|
Error error;
|
|
const int short_option = m_getopt_table[option_idx].val;
|
|
bool success = false;
|
|
|
|
switch (short_option)
|
|
{
|
|
case 'p':
|
|
match_info.GetProcessInfo().SetProcessID (StringConvert::ToUInt32 (option_arg, LLDB_INVALID_PROCESS_ID, 0, &success));
|
|
if (!success)
|
|
error.SetErrorStringWithFormat("invalid process ID string: '%s'", option_arg);
|
|
break;
|
|
|
|
case 'P':
|
|
match_info.GetProcessInfo().SetParentProcessID (StringConvert::ToUInt32 (option_arg, LLDB_INVALID_PROCESS_ID, 0, &success));
|
|
if (!success)
|
|
error.SetErrorStringWithFormat("invalid parent process ID string: '%s'", option_arg);
|
|
break;
|
|
|
|
case 'u':
|
|
match_info.GetProcessInfo().SetUserID (StringConvert::ToUInt32 (option_arg, UINT32_MAX, 0, &success));
|
|
if (!success)
|
|
error.SetErrorStringWithFormat("invalid user ID string: '%s'", option_arg);
|
|
break;
|
|
|
|
case 'U':
|
|
match_info.GetProcessInfo().SetEffectiveUserID (StringConvert::ToUInt32 (option_arg, UINT32_MAX, 0, &success));
|
|
if (!success)
|
|
error.SetErrorStringWithFormat("invalid effective user ID string: '%s'", option_arg);
|
|
break;
|
|
|
|
case 'g':
|
|
match_info.GetProcessInfo().SetGroupID (StringConvert::ToUInt32 (option_arg, UINT32_MAX, 0, &success));
|
|
if (!success)
|
|
error.SetErrorStringWithFormat("invalid group ID string: '%s'", option_arg);
|
|
break;
|
|
|
|
case 'G':
|
|
match_info.GetProcessInfo().SetEffectiveGroupID (StringConvert::ToUInt32 (option_arg, UINT32_MAX, 0, &success));
|
|
if (!success)
|
|
error.SetErrorStringWithFormat("invalid effective group ID string: '%s'", option_arg);
|
|
break;
|
|
|
|
case 'a':
|
|
match_info.GetProcessInfo().GetArchitecture().SetTriple (option_arg, m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform().get());
|
|
break;
|
|
|
|
case 'n':
|
|
match_info.GetProcessInfo().GetExecutableFile().SetFile (option_arg, false);
|
|
match_info.SetNameMatchType (eNameMatchEquals);
|
|
break;
|
|
|
|
case 'e':
|
|
match_info.GetProcessInfo().GetExecutableFile().SetFile (option_arg, false);
|
|
match_info.SetNameMatchType (eNameMatchEndsWith);
|
|
break;
|
|
|
|
case 's':
|
|
match_info.GetProcessInfo().GetExecutableFile().SetFile (option_arg, false);
|
|
match_info.SetNameMatchType (eNameMatchStartsWith);
|
|
break;
|
|
|
|
case 'c':
|
|
match_info.GetProcessInfo().GetExecutableFile().SetFile (option_arg, false);
|
|
match_info.SetNameMatchType (eNameMatchContains);
|
|
break;
|
|
|
|
case 'r':
|
|
match_info.GetProcessInfo().GetExecutableFile().SetFile (option_arg, false);
|
|
match_info.SetNameMatchType (eNameMatchRegularExpression);
|
|
break;
|
|
|
|
case 'A':
|
|
show_args = true;
|
|
break;
|
|
|
|
case 'v':
|
|
verbose = true;
|
|
break;
|
|
|
|
default:
|
|
error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option);
|
|
break;
|
|
}
|
|
|
|
return error;
|
|
}
|
|
|
|
void
|
|
OptionParsingStarting () override
|
|
{
|
|
match_info.Clear();
|
|
show_args = false;
|
|
verbose = false;
|
|
}
|
|
|
|
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.
|
|
|
|
ProcessInstanceInfoMatch match_info;
|
|
bool show_args;
|
|
bool verbose;
|
|
};
|
|
CommandOptions m_options;
|
|
};
|
|
|
|
namespace
|
|
{
|
|
PosixPlatformCommandOptionValidator g_posix_validator;
|
|
}
|
|
|
|
OptionDefinition
|
|
CommandObjectPlatformProcessList::CommandOptions::g_option_table[] =
|
|
{
|
|
{ LLDB_OPT_SET_1 , false, "pid" , 'p', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypePid , "List the process info for a specific process ID." },
|
|
{ LLDB_OPT_SET_2 , true , "name" , 'n', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeProcessName , "Find processes with executable basenames that match a string." },
|
|
{ LLDB_OPT_SET_3 , true , "ends-with" , 'e', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeProcessName , "Find processes with executable basenames that end with a string." },
|
|
{ LLDB_OPT_SET_4 , true , "starts-with", 's', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeProcessName , "Find processes with executable basenames that start with a string." },
|
|
{ LLDB_OPT_SET_5 , true , "contains" , 'c', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeProcessName , "Find processes with executable basenames that contain a string." },
|
|
{ LLDB_OPT_SET_6 , true , "regex" , 'r', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeRegularExpression, "Find processes with executable basenames that match a regular expression." },
|
|
{ LLDB_OPT_SET_FROM_TO(2, 6), false, "parent" , 'P', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypePid , "Find processes that have a matching parent process ID." },
|
|
{ LLDB_OPT_SET_FROM_TO(2, 6), false, "uid" , 'u', OptionParser::eRequiredArgument, &g_posix_validator, NULL, 0, eArgTypeUnsignedInteger , "Find processes that have a matching user ID." },
|
|
{ LLDB_OPT_SET_FROM_TO(2, 6), false, "euid" , 'U', OptionParser::eRequiredArgument, &g_posix_validator, NULL, 0, eArgTypeUnsignedInteger , "Find processes that have a matching effective user ID." },
|
|
{ LLDB_OPT_SET_FROM_TO(2, 6), false, "gid" , 'g', OptionParser::eRequiredArgument, &g_posix_validator, NULL, 0, eArgTypeUnsignedInteger , "Find processes that have a matching group ID." },
|
|
{ LLDB_OPT_SET_FROM_TO(2, 6), false, "egid" , 'G', OptionParser::eRequiredArgument, &g_posix_validator, NULL, 0, eArgTypeUnsignedInteger , "Find processes that have a matching effective group ID." },
|
|
{ LLDB_OPT_SET_FROM_TO(2, 6), false, "arch" , 'a', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeArchitecture , "Find processes that have a matching architecture." },
|
|
{ LLDB_OPT_SET_FROM_TO(1, 6), false, "show-args" , 'A', OptionParser::eNoArgument , NULL, NULL, 0, eArgTypeNone , "Show process arguments instead of the process executable basename." },
|
|
{ LLDB_OPT_SET_FROM_TO(1, 6), false, "verbose" , 'v', OptionParser::eNoArgument , NULL, NULL, 0, eArgTypeNone , "Enable verbose output." },
|
|
{ 0 , false, NULL , 0 , 0 , NULL, NULL, 0, eArgTypeNone , NULL }
|
|
};
|
|
|
|
//----------------------------------------------------------------------
|
|
// "platform process info"
|
|
//----------------------------------------------------------------------
|
|
class CommandObjectPlatformProcessInfo : public CommandObjectParsed
|
|
{
|
|
public:
|
|
CommandObjectPlatformProcessInfo (CommandInterpreter &interpreter) :
|
|
CommandObjectParsed (interpreter,
|
|
"platform process info",
|
|
"Get detailed information for one or more process by process ID.",
|
|
"platform process info <pid> [<pid> <pid> ...]",
|
|
0)
|
|
{
|
|
CommandArgumentEntry arg;
|
|
CommandArgumentData pid_args;
|
|
|
|
// Define the first (and only) variant of this arg.
|
|
pid_args.arg_type = eArgTypePid;
|
|
pid_args.arg_repetition = eArgRepeatStar;
|
|
|
|
// There is only one variant this argument could be; put it into the argument entry.
|
|
arg.push_back (pid_args);
|
|
|
|
// Push the data for the first argument into the m_arguments vector.
|
|
m_arguments.push_back (arg);
|
|
}
|
|
|
|
~CommandObjectPlatformProcessInfo () override
|
|
{
|
|
}
|
|
|
|
protected:
|
|
bool
|
|
DoExecute (Args& args, CommandReturnObject &result) override
|
|
{
|
|
Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
|
|
PlatformSP platform_sp;
|
|
if (target)
|
|
{
|
|
platform_sp = target->GetPlatform();
|
|
}
|
|
if (!platform_sp)
|
|
{
|
|
platform_sp = m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform();
|
|
}
|
|
|
|
if (platform_sp)
|
|
{
|
|
const size_t argc = args.GetArgumentCount();
|
|
if (argc > 0)
|
|
{
|
|
Error error;
|
|
|
|
if (platform_sp->IsConnected())
|
|
{
|
|
Stream &ostrm = result.GetOutputStream();
|
|
bool success;
|
|
for (size_t i=0; i<argc; ++ i)
|
|
{
|
|
const char *arg = args.GetArgumentAtIndex(i);
|
|
lldb::pid_t pid = StringConvert::ToUInt32 (arg, LLDB_INVALID_PROCESS_ID, 0, &success);
|
|
if (success)
|
|
{
|
|
ProcessInstanceInfo proc_info;
|
|
if (platform_sp->GetProcessInfo (pid, proc_info))
|
|
{
|
|
ostrm.Printf ("Process information for process %" PRIu64 ":\n", pid);
|
|
proc_info.Dump (ostrm, platform_sp.get());
|
|
}
|
|
else
|
|
{
|
|
ostrm.Printf ("error: no process information is available for process %" PRIu64 "\n", pid);
|
|
}
|
|
ostrm.EOL();
|
|
}
|
|
else
|
|
{
|
|
result.AppendErrorWithFormat ("invalid process ID argument '%s'", arg);
|
|
result.SetStatus (eReturnStatusFailed);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Not connected...
|
|
result.AppendErrorWithFormat ("not connected to '%s'", platform_sp->GetPluginName().GetCString());
|
|
result.SetStatus (eReturnStatusFailed);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// No args
|
|
result.AppendError ("one or more process id(s) must be specified");
|
|
result.SetStatus (eReturnStatusFailed);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
result.AppendError ("no platform is currently selected");
|
|
result.SetStatus (eReturnStatusFailed);
|
|
}
|
|
return result.Succeeded();
|
|
}
|
|
};
|
|
|
|
class CommandObjectPlatformProcessAttach : 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
|
|
{
|
|
}
|
|
|
|
Error
|
|
SetOptionValue (uint32_t option_idx, const char *option_arg) override
|
|
{
|
|
Error error;
|
|
char short_option = (char) m_getopt_table[option_idx].val;
|
|
bool success = false;
|
|
switch (short_option)
|
|
{
|
|
case 'p':
|
|
{
|
|
lldb::pid_t pid = StringConvert::ToUInt32 (option_arg, LLDB_INVALID_PROCESS_ID, 0, &success);
|
|
if (!success || pid == LLDB_INVALID_PROCESS_ID)
|
|
{
|
|
error.SetErrorStringWithFormat("invalid process ID '%s'", option_arg);
|
|
}
|
|
else
|
|
{
|
|
attach_info.SetProcessID (pid);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 'P':
|
|
attach_info.SetProcessPluginName (option_arg);
|
|
break;
|
|
|
|
case 'n':
|
|
attach_info.GetExecutableFile().SetFile(option_arg, false);
|
|
break;
|
|
|
|
case 'w':
|
|
attach_info.SetWaitForLaunch(true);
|
|
break;
|
|
|
|
default:
|
|
error.SetErrorStringWithFormat("invalid short option character '%c'", short_option);
|
|
break;
|
|
}
|
|
return error;
|
|
}
|
|
|
|
void
|
|
OptionParsingStarting () override
|
|
{
|
|
attach_info.Clear();
|
|
}
|
|
|
|
const OptionDefinition*
|
|
GetDefinitions () override
|
|
{
|
|
return g_option_table;
|
|
}
|
|
|
|
bool
|
|
HandleOptionArgumentCompletion (Args &input,
|
|
int cursor_index,
|
|
int char_pos,
|
|
OptionElementVector &opt_element_vector,
|
|
int opt_element_index,
|
|
int match_start_point,
|
|
int max_return_elements,
|
|
bool &word_complete,
|
|
StringList &matches) override
|
|
{
|
|
int opt_arg_pos = opt_element_vector[opt_element_index].opt_arg_pos;
|
|
int opt_defs_index = opt_element_vector[opt_element_index].opt_defs_index;
|
|
|
|
// We are only completing the name option for now...
|
|
|
|
const OptionDefinition *opt_defs = GetDefinitions();
|
|
if (opt_defs[opt_defs_index].short_option == 'n')
|
|
{
|
|
// Are we in the name?
|
|
|
|
// Look to see if there is a -P argument provided, and if so use that plugin, otherwise
|
|
// use the default plugin.
|
|
|
|
const char *partial_name = NULL;
|
|
partial_name = input.GetArgumentAtIndex(opt_arg_pos);
|
|
|
|
PlatformSP platform_sp (m_interpreter.GetPlatform (true));
|
|
if (platform_sp)
|
|
{
|
|
ProcessInstanceInfoList process_infos;
|
|
ProcessInstanceInfoMatch match_info;
|
|
if (partial_name)
|
|
{
|
|
match_info.GetProcessInfo().GetExecutableFile().SetFile(partial_name, false);
|
|
match_info.SetNameMatchType(eNameMatchStartsWith);
|
|
}
|
|
platform_sp->FindProcesses (match_info, process_infos);
|
|
const uint32_t num_matches = process_infos.GetSize();
|
|
if (num_matches > 0)
|
|
{
|
|
for (uint32_t i=0; i<num_matches; ++i)
|
|
{
|
|
matches.AppendString (process_infos.GetProcessNameAtIndex(i),
|
|
process_infos.GetProcessNameLengthAtIndex(i));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
// Options table: Required for subclasses of Options.
|
|
|
|
static OptionDefinition g_option_table[];
|
|
|
|
// Instance variables to hold the values for command options.
|
|
|
|
ProcessAttachInfo attach_info;
|
|
};
|
|
|
|
CommandObjectPlatformProcessAttach (CommandInterpreter &interpreter) :
|
|
CommandObjectParsed (interpreter,
|
|
"platform process attach",
|
|
"Attach to a process.",
|
|
"platform process attach <cmd-options>"),
|
|
m_options (interpreter)
|
|
{
|
|
}
|
|
|
|
~CommandObjectPlatformProcessAttach () override
|
|
{
|
|
}
|
|
|
|
bool
|
|
DoExecute (Args& command,
|
|
CommandReturnObject &result) override
|
|
{
|
|
PlatformSP platform_sp (m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform());
|
|
if (platform_sp)
|
|
{
|
|
Error err;
|
|
ProcessSP remote_process_sp =
|
|
platform_sp->Attach(m_options.attach_info, m_interpreter.GetDebugger(), NULL, err);
|
|
if (err.Fail())
|
|
{
|
|
result.AppendError(err.AsCString());
|
|
result.SetStatus (eReturnStatusFailed);
|
|
}
|
|
else if (remote_process_sp.get() == NULL)
|
|
{
|
|
result.AppendError("could not attach: unknown reason");
|
|
result.SetStatus (eReturnStatusFailed);
|
|
}
|
|
else
|
|
result.SetStatus (eReturnStatusSuccessFinishResult);
|
|
}
|
|
else
|
|
{
|
|
result.AppendError ("no platform is currently selected");
|
|
result.SetStatus (eReturnStatusFailed);
|
|
}
|
|
return result.Succeeded();
|
|
}
|
|
|
|
Options *
|
|
GetOptions () override
|
|
{
|
|
return &m_options;
|
|
}
|
|
|
|
protected:
|
|
|
|
CommandOptions m_options;
|
|
};
|
|
|
|
|
|
OptionDefinition
|
|
CommandObjectPlatformProcessAttach::CommandOptions::g_option_table[] =
|
|
{
|
|
{ LLDB_OPT_SET_ALL, false, "plugin", 'P' , OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypePlugin, "Name of the process plugin you want to use."},
|
|
{ LLDB_OPT_SET_1, false, "pid", 'p' , OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypePid, "The process ID of an existing process to attach to."},
|
|
{ LLDB_OPT_SET_2, false, "name", 'n' , OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeProcessName, "The name of the process to attach to."},
|
|
{ LLDB_OPT_SET_2, false, "waitfor", 'w' , OptionParser::eNoArgument , NULL, NULL, 0, eArgTypeNone, "Wait for the process with <process-name> to launch."},
|
|
{ 0, false, NULL , 0 , 0 , NULL, NULL, 0, eArgTypeNone, NULL }
|
|
};
|
|
|
|
|
|
class CommandObjectPlatformProcess : public CommandObjectMultiword
|
|
{
|
|
public:
|
|
//------------------------------------------------------------------
|
|
// Constructors and Destructors
|
|
//------------------------------------------------------------------
|
|
CommandObjectPlatformProcess (CommandInterpreter &interpreter) :
|
|
CommandObjectMultiword (interpreter,
|
|
"platform process",
|
|
"A set of commands to query, launch and attach to platform processes",
|
|
"platform process [attach|launch|list] ...")
|
|
{
|
|
LoadSubCommand ("attach", CommandObjectSP (new CommandObjectPlatformProcessAttach (interpreter)));
|
|
LoadSubCommand ("launch", CommandObjectSP (new CommandObjectPlatformProcessLaunch (interpreter)));
|
|
LoadSubCommand ("info" , CommandObjectSP (new CommandObjectPlatformProcessInfo (interpreter)));
|
|
LoadSubCommand ("list" , CommandObjectSP (new CommandObjectPlatformProcessList (interpreter)));
|
|
|
|
}
|
|
|
|
~CommandObjectPlatformProcess () override
|
|
{
|
|
}
|
|
|
|
private:
|
|
//------------------------------------------------------------------
|
|
// For CommandObjectPlatform only
|
|
//------------------------------------------------------------------
|
|
DISALLOW_COPY_AND_ASSIGN (CommandObjectPlatformProcess);
|
|
};
|
|
|
|
//----------------------------------------------------------------------
|
|
// "platform shell"
|
|
//----------------------------------------------------------------------
|
|
class CommandObjectPlatformShell : public CommandObjectRaw
|
|
{
|
|
public:
|
|
|
|
class CommandOptions : public Options
|
|
{
|
|
public:
|
|
|
|
CommandOptions (CommandInterpreter &interpreter) :
|
|
Options(interpreter),
|
|
timeout(10)
|
|
{
|
|
}
|
|
|
|
~CommandOptions () override
|
|
{
|
|
}
|
|
|
|
virtual uint32_t
|
|
GetNumDefinitions ()
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
const OptionDefinition*
|
|
GetDefinitions () override
|
|
{
|
|
return g_option_table;
|
|
}
|
|
|
|
Error
|
|
SetOptionValue (uint32_t option_idx,
|
|
const char *option_value) override
|
|
{
|
|
Error error;
|
|
|
|
const char short_option = (char) g_option_table[option_idx].short_option;
|
|
|
|
switch (short_option)
|
|
{
|
|
case 't':
|
|
{
|
|
bool success;
|
|
timeout = StringConvert::ToUInt32(option_value, 10, 10, &success);
|
|
if (!success)
|
|
error.SetErrorStringWithFormat("could not convert \"%s\" to a numeric value.", option_value);
|
|
break;
|
|
}
|
|
default:
|
|
error.SetErrorStringWithFormat("invalid short option character '%c'", short_option);
|
|
break;
|
|
}
|
|
|
|
return error;
|
|
}
|
|
|
|
void
|
|
OptionParsingStarting () override
|
|
{
|
|
}
|
|
|
|
// Options table: Required for subclasses of Options.
|
|
|
|
static OptionDefinition g_option_table[];
|
|
uint32_t timeout;
|
|
};
|
|
|
|
CommandObjectPlatformShell (CommandInterpreter &interpreter) :
|
|
CommandObjectRaw (interpreter,
|
|
"platform shell",
|
|
"Run a shell command on the selected platform.",
|
|
"platform shell <shell-command>",
|
|
0),
|
|
m_options(interpreter)
|
|
{
|
|
}
|
|
|
|
~CommandObjectPlatformShell () override
|
|
{
|
|
}
|
|
|
|
Options *
|
|
GetOptions () override
|
|
{
|
|
return &m_options;
|
|
}
|
|
|
|
bool
|
|
DoExecute (const char *raw_command_line, CommandReturnObject &result) override
|
|
{
|
|
m_options.NotifyOptionParsingStarting();
|
|
|
|
const char* expr = NULL;
|
|
|
|
// Print out an usage syntax on an empty command line.
|
|
if (raw_command_line[0] == '\0')
|
|
{
|
|
result.GetOutputStream().Printf("%s\n", this->GetSyntax());
|
|
return true;
|
|
}
|
|
|
|
if (raw_command_line[0] == '-')
|
|
{
|
|
// We have some options and these options MUST end with --.
|
|
const char *end_options = NULL;
|
|
const char *s = raw_command_line;
|
|
while (s && s[0])
|
|
{
|
|
end_options = ::strstr (s, "--");
|
|
if (end_options)
|
|
{
|
|
end_options += 2; // Get past the "--"
|
|
if (::isspace (end_options[0]))
|
|
{
|
|
expr = end_options;
|
|
while (::isspace (*expr))
|
|
++expr;
|
|
break;
|
|
}
|
|
}
|
|
s = end_options;
|
|
}
|
|
|
|
if (end_options)
|
|
{
|
|
Args args (llvm::StringRef(raw_command_line, end_options - raw_command_line));
|
|
if (!ParseOptions (args, result))
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (expr == NULL)
|
|
expr = raw_command_line;
|
|
|
|
PlatformSP platform_sp (m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform());
|
|
Error error;
|
|
if (platform_sp)
|
|
{
|
|
FileSpec working_dir{};
|
|
std::string output;
|
|
int status = -1;
|
|
int signo = -1;
|
|
error = (platform_sp->RunShellCommand (expr, working_dir, &status, &signo, &output, m_options.timeout));
|
|
if (!output.empty())
|
|
result.GetOutputStream().PutCString(output.c_str());
|
|
if (status > 0)
|
|
{
|
|
if (signo > 0)
|
|
{
|
|
const char *signo_cstr = Host::GetSignalAsCString(signo);
|
|
if (signo_cstr)
|
|
result.GetOutputStream().Printf("error: command returned with status %i and signal %s\n", status, signo_cstr);
|
|
else
|
|
result.GetOutputStream().Printf("error: command returned with status %i and signal %i\n", status, signo);
|
|
}
|
|
else
|
|
result.GetOutputStream().Printf("error: command returned with status %i\n", status);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
result.GetOutputStream().Printf("error: cannot run remote shell commands without a platform\n");
|
|
error.SetErrorString("error: cannot run remote shell commands without a platform");
|
|
}
|
|
|
|
if (error.Fail())
|
|
{
|
|
result.AppendError(error.AsCString());
|
|
result.SetStatus (eReturnStatusFailed);
|
|
}
|
|
else
|
|
{
|
|
result.SetStatus (eReturnStatusSuccessFinishResult);
|
|
}
|
|
return true;
|
|
}
|
|
CommandOptions m_options;
|
|
};
|
|
|
|
OptionDefinition
|
|
CommandObjectPlatformShell::CommandOptions::g_option_table[] =
|
|
{
|
|
{ LLDB_OPT_SET_ALL, false, "timeout", 't', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeValue, "Seconds to wait for the remote host to finish running the command."},
|
|
{ 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL }
|
|
};
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
// "platform install" - install a target to a remote end
|
|
//----------------------------------------------------------------------
|
|
class CommandObjectPlatformInstall : public CommandObjectParsed
|
|
{
|
|
public:
|
|
CommandObjectPlatformInstall (CommandInterpreter &interpreter) :
|
|
CommandObjectParsed (interpreter,
|
|
"platform target-install",
|
|
"Install a target (bundle or executable file) to the remote end.",
|
|
"platform target-install <local-thing> <remote-sandbox>",
|
|
0)
|
|
{
|
|
}
|
|
|
|
~CommandObjectPlatformInstall () override
|
|
{
|
|
}
|
|
|
|
bool
|
|
DoExecute (Args& args, CommandReturnObject &result) override
|
|
{
|
|
if (args.GetArgumentCount() != 2)
|
|
{
|
|
result.AppendError("platform target-install takes two arguments");
|
|
result.SetStatus(eReturnStatusFailed);
|
|
return false;
|
|
}
|
|
// TODO: move the bulk of this code over to the platform itself
|
|
FileSpec src(args.GetArgumentAtIndex(0), true);
|
|
FileSpec dst(args.GetArgumentAtIndex(1), false);
|
|
if (src.Exists() == false)
|
|
{
|
|
result.AppendError("source location does not exist or is not accessible");
|
|
result.SetStatus(eReturnStatusFailed);
|
|
return false;
|
|
}
|
|
PlatformSP platform_sp (m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform());
|
|
if (!platform_sp)
|
|
{
|
|
result.AppendError ("no platform currently selected");
|
|
result.SetStatus (eReturnStatusFailed);
|
|
return false;
|
|
}
|
|
|
|
Error error = platform_sp->Install(src, dst);
|
|
if (error.Success())
|
|
{
|
|
result.SetStatus(eReturnStatusSuccessFinishNoResult);
|
|
}
|
|
else
|
|
{
|
|
result.AppendErrorWithFormat("install failed: %s", error.AsCString());
|
|
result.SetStatus(eReturnStatusFailed);
|
|
}
|
|
return result.Succeeded();
|
|
}
|
|
private:
|
|
|
|
};
|
|
|
|
//----------------------------------------------------------------------
|
|
// CommandObjectPlatform constructor
|
|
//----------------------------------------------------------------------
|
|
CommandObjectPlatform::CommandObjectPlatform(CommandInterpreter &interpreter) :
|
|
CommandObjectMultiword (interpreter,
|
|
"platform",
|
|
"A set of commands to manage and create platforms.",
|
|
"platform [connect|disconnect|info|list|status|select] ...")
|
|
{
|
|
LoadSubCommand ("select", CommandObjectSP (new CommandObjectPlatformSelect (interpreter)));
|
|
LoadSubCommand ("list" , CommandObjectSP (new CommandObjectPlatformList (interpreter)));
|
|
LoadSubCommand ("status", CommandObjectSP (new CommandObjectPlatformStatus (interpreter)));
|
|
LoadSubCommand ("connect", CommandObjectSP (new CommandObjectPlatformConnect (interpreter)));
|
|
LoadSubCommand ("disconnect", CommandObjectSP (new CommandObjectPlatformDisconnect (interpreter)));
|
|
LoadSubCommand ("settings", CommandObjectSP (new CommandObjectPlatformSettings (interpreter)));
|
|
LoadSubCommand ("mkdir", CommandObjectSP (new CommandObjectPlatformMkDir (interpreter)));
|
|
LoadSubCommand ("file", CommandObjectSP (new CommandObjectPlatformFile (interpreter)));
|
|
LoadSubCommand ("get-file", CommandObjectSP (new CommandObjectPlatformGetFile (interpreter)));
|
|
LoadSubCommand ("get-size", CommandObjectSP (new CommandObjectPlatformGetSize (interpreter)));
|
|
LoadSubCommand ("put-file", CommandObjectSP (new CommandObjectPlatformPutFile (interpreter)));
|
|
LoadSubCommand ("process", CommandObjectSP (new CommandObjectPlatformProcess (interpreter)));
|
|
LoadSubCommand ("shell", CommandObjectSP (new CommandObjectPlatformShell (interpreter)));
|
|
LoadSubCommand ("target-install", CommandObjectSP (new CommandObjectPlatformInstall (interpreter)));
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// Destructor
|
|
//----------------------------------------------------------------------
|
|
CommandObjectPlatform::~CommandObjectPlatform()
|
|
{
|
|
}
|