Index: include/lldb/API/SBLaunchInfo.h =================================================================== --- include/lldb/API/SBLaunchInfo.h +++ include/lldb/API/SBLaunchInfo.h @@ -184,6 +184,9 @@ lldb_private::ProcessLaunchInfo & ref (); + const lldb_private::ProcessLaunchInfo & + ref () const; + ProcessLaunchInfoSP m_opaque_sp; }; Index: include/lldb/API/SBTarget.h =================================================================== --- include/lldb/API/SBTarget.h +++ include/lldb/API/SBTarget.h @@ -888,6 +888,12 @@ lldb::addr_t GetStackRedZoneSize(); + + lldb::SBLaunchInfo + GetLaunchInfo () const; + + void + SetLaunchInfo (const lldb::SBLaunchInfo &launch_info); protected: friend class SBAddress; Index: include/lldb/Target/Target.h =================================================================== --- include/lldb/Target/Target.h +++ include/lldb/Target/Target.h @@ -36,6 +36,7 @@ #include "lldb/Target/ABI.h" #include "lldb/Target/ExecutionContextScope.h" #include "lldb/Target/PathMappingList.h" +#include "lldb/Target/ProcessLaunchInfo.h" #include "lldb/Target/SectionLoadHistory.h" namespace lldb_private { @@ -117,7 +118,10 @@ size_t GetEnvironmentAsArgs (Args &env) const; - + + void + SetEnvironmentFromArgs (const Args &env); + bool GetSkipPrologue() const; @@ -195,6 +199,33 @@ void SetDisplayRuntimeSupportValues (bool b); + + const ProcessLaunchInfo & + GetProcessLaunchInfo() const; + + void + SetProcessLaunchInfo(const ProcessLaunchInfo &launch_info); + +private: + //------------------------------------------------------------------ + // Callbacks for m_launch_info. + //------------------------------------------------------------------ + static void Arg0ValueChangedCallback(void *target_property_ptr, OptionValue *); + static void RunArgsValueChangedCallback(void *target_property_ptr, OptionValue *); + static void EnvVarsValueChangedCallback(void *target_property_ptr, OptionValue *); + static void InheritEnvValueChangedCallback(void *target_property_ptr, OptionValue *); + static void InputPathValueChangedCallback(void *target_property_ptr, OptionValue *); + static void OutputPathValueChangedCallback(void *target_property_ptr, OptionValue *); + static void ErrorPathValueChangedCallback(void *target_property_ptr, OptionValue *); + static void DetachOnErrorValueChangedCallback(void *target_property_ptr, OptionValue *); + static void DisableASLRValueChangedCallback(void *target_property_ptr, OptionValue *); + static void DisableSTDIOValueChangedCallback(void *target_property_ptr, OptionValue *); + +private: + //------------------------------------------------------------------ + // Member variables. + //------------------------------------------------------------------ + ProcessLaunchInfo m_launch_info; }; typedef std::shared_ptr TargetPropertiesSP; Index: source/API/SBLaunchInfo.cpp =================================================================== --- source/API/SBLaunchInfo.cpp +++ source/API/SBLaunchInfo.cpp @@ -36,6 +36,12 @@ return *m_opaque_sp; } +const lldb_private::ProcessLaunchInfo & +SBLaunchInfo::ref () const +{ + return *m_opaque_sp; +} + lldb::pid_t SBLaunchInfo::GetProcessID() { Index: source/API/SBTarget.cpp =================================================================== --- source/API/SBTarget.cpp +++ source/API/SBTarget.cpp @@ -2568,3 +2568,21 @@ } return 0; } + +lldb::SBLaunchInfo +SBTarget::GetLaunchInfo () const +{ + lldb::SBLaunchInfo launch_info(NULL); + TargetSP target_sp(GetSP()); + if (target_sp) + launch_info.ref() = m_opaque_sp->GetProcessLaunchInfo(); + return launch_info; +} + +void +SBTarget::SetLaunchInfo (const lldb::SBLaunchInfo &launch_info) +{ + TargetSP target_sp(GetSP()); + if (target_sp) + m_opaque_sp->SetProcessLaunchInfo(launch_info.ref()); +} Index: source/Commands/CommandObjectProcess.cpp =================================================================== --- source/Commands/CommandObjectProcess.cpp +++ source/Commands/CommandObjectProcess.cpp @@ -221,6 +221,7 @@ disable_aslr = target->GetDisableASLR (); } + m_options.launch_info = target->GetProcessLaunchInfo(); if (disable_aslr) m_options.launch_info.GetFlags().Set (eLaunchFlagDisableASLR); else Index: source/Interpreter/OptionValueArray.cpp =================================================================== --- source/Interpreter/OptionValueArray.cpp +++ source/Interpreter/OptionValueArray.cpp @@ -77,8 +77,10 @@ OptionValueArray::SetValueFromCString (const char *value, VarSetOperationType op) { Args args(value); - NotifyValueChanged(); - return SetArgs (args, op); + Error error = SetArgs (args, op); + if (error.Success()) + NotifyValueChanged(); + return error; } Index: source/Target/Target.cpp =================================================================== --- source/Target/Target.cpp +++ source/Target/Target.cpp @@ -3040,7 +3040,8 @@ // TargetProperties //---------------------------------------------------------------------- TargetProperties::TargetProperties (Target *target) : - Properties () + Properties (), + m_launch_info () { if (target) { @@ -3055,6 +3056,28 @@ true, Process::GetGlobalProperties()->GetValueProperties()); } + + // Set callbacks to update launch_info whenever "settins set" updated any of these properties + m_collection_sp->SetValueChangedCallback(ePropertyArg0, TargetProperties::Arg0ValueChangedCallback, this); + m_collection_sp->SetValueChangedCallback(ePropertyRunArgs, TargetProperties::RunArgsValueChangedCallback, this); + m_collection_sp->SetValueChangedCallback(ePropertyEnvVars, TargetProperties::EnvVarsValueChangedCallback, this); + m_collection_sp->SetValueChangedCallback(ePropertyInputPath, TargetProperties::InputPathValueChangedCallback, this); + m_collection_sp->SetValueChangedCallback(ePropertyOutputPath, TargetProperties::OutputPathValueChangedCallback, this); + m_collection_sp->SetValueChangedCallback(ePropertyErrorPath, TargetProperties::ErrorPathValueChangedCallback, this); + m_collection_sp->SetValueChangedCallback(ePropertyDetachOnError, TargetProperties::DetachOnErrorValueChangedCallback, this); + m_collection_sp->SetValueChangedCallback(ePropertyDisableASLR, TargetProperties::DisableASLRValueChangedCallback, this); + m_collection_sp->SetValueChangedCallback(ePropertyDisableSTDIO, TargetProperties::DisableSTDIOValueChangedCallback, this); + + // Update m_launch_info once it was created + Arg0ValueChangedCallback(this, NULL); + RunArgsValueChangedCallback(this, NULL); + EnvVarsValueChangedCallback(this, NULL); + InputPathValueChangedCallback(this, NULL); + OutputPathValueChangedCallback(this, NULL); + ErrorPathValueChangedCallback(this, NULL); + DetachOnErrorValueChangedCallback(this, NULL); + DisableASLRValueChangedCallback(this, NULL); + DisableSTDIOValueChangedCallback(this, NULL); } TargetProperties::~TargetProperties () @@ -3179,6 +3202,13 @@ return m_collection_sp->GetPropertyAtIndexAsArgs (NULL, idx, env); } +void +TargetProperties::SetEnvironmentFromArgs (const Args &env) +{ + const uint32_t idx = ePropertyEnvVars; + m_collection_sp->SetPropertyAtIndexFromArgs (NULL, idx, env); +} + bool TargetProperties::GetSkipPrologue() const { @@ -3375,6 +3405,121 @@ m_collection_sp->SetPropertyAtIndexAsBoolean (NULL, idx, b); } +const ProcessLaunchInfo & +TargetProperties::GetProcessLaunchInfo () const +{ + return m_launch_info; +} + +void +TargetProperties::SetProcessLaunchInfo(const ProcessLaunchInfo &launch_info) +{ + m_launch_info = launch_info; + SetArg0(launch_info.GetArg0()); + SetRunArguments(launch_info.GetArguments()); + SetEnvironmentFromArgs(launch_info.GetEnvironmentEntries()); + const FileAction *input_file_action = launch_info.GetFileActionForFD(STDIN_FILENO); + if (input_file_action) + { + const char *input_path = input_file_action->GetPath(); + if (input_path) + SetStandardInputPath(input_path); + } + const FileAction *output_file_action = launch_info.GetFileActionForFD(STDOUT_FILENO); + if (output_file_action) + { + const char *output_path = output_file_action->GetPath(); + if (output_path) + SetStandardOutputPath(output_path); + } + const FileAction *error_file_action = launch_info.GetFileActionForFD(STDERR_FILENO); + if (error_file_action) + { + const char *error_path = error_file_action->GetPath(); + if (error_path) + SetStandardErrorPath(error_path); + } + SetDetachOnError(launch_info.GetFlags().Test(lldb::eLaunchFlagDetachOnError)); + SetDisableASLR(launch_info.GetFlags().Test(lldb::eLaunchFlagDisableASLR)); + SetDisableSTDIO(launch_info.GetFlags().Test(lldb::eLaunchFlagDisableSTDIO)); +} + +void +TargetProperties::Arg0ValueChangedCallback(void *target_property_ptr, OptionValue *) +{ + TargetProperties *this_ = reinterpret_cast(target_property_ptr); + this_->m_launch_info.SetArg0(this_->GetArg0()); +} + +void +TargetProperties::RunArgsValueChangedCallback(void *target_property_ptr, OptionValue *) +{ + TargetProperties *this_ = reinterpret_cast(target_property_ptr); + Args args; + if (this_->GetRunArguments(args)) + this_->m_launch_info.GetArguments() = args; +} + +void +TargetProperties::EnvVarsValueChangedCallback(void *target_property_ptr, OptionValue *) +{ + TargetProperties *this_ = reinterpret_cast(target_property_ptr); + Args args; + if (this_->GetEnvironmentAsArgs(args)) + this_->m_launch_info.GetEnvironmentEntries() = args; +} + +void +TargetProperties::InputPathValueChangedCallback(void *target_property_ptr, OptionValue *) +{ + TargetProperties *this_ = reinterpret_cast(target_property_ptr); + this_->m_launch_info.AppendOpenFileAction(STDIN_FILENO, this_->GetStandardInputPath().GetPath().c_str(), true, false); +} + +void +TargetProperties::OutputPathValueChangedCallback(void *target_property_ptr, OptionValue *) +{ + TargetProperties *this_ = reinterpret_cast(target_property_ptr); + this_->m_launch_info.AppendOpenFileAction(STDOUT_FILENO, this_->GetStandardOutputPath().GetPath().c_str(), false, true); +} + +void +TargetProperties::ErrorPathValueChangedCallback(void *target_property_ptr, OptionValue *) +{ + TargetProperties *this_ = reinterpret_cast(target_property_ptr); + this_->m_launch_info.AppendOpenFileAction(STDERR_FILENO, this_->GetStandardErrorPath().GetPath().c_str(), false, true); +} + +void +TargetProperties::DetachOnErrorValueChangedCallback(void *target_property_ptr, OptionValue *) +{ + TargetProperties *this_ = reinterpret_cast(target_property_ptr); + if (this_->GetDetachOnError()) + this_->m_launch_info.GetFlags().Set(lldb::eLaunchFlagDetachOnError); + else + this_->m_launch_info.GetFlags().Clear(lldb::eLaunchFlagDetachOnError); +} + +void +TargetProperties::DisableASLRValueChangedCallback(void *target_property_ptr, OptionValue *) +{ + TargetProperties *this_ = reinterpret_cast(target_property_ptr); + if (this_->GetDisableASLR()) + this_->m_launch_info.GetFlags().Set(lldb::eLaunchFlagDisableASLR); + else + this_->m_launch_info.GetFlags().Clear(lldb::eLaunchFlagDisableASLR); +} + +void +TargetProperties::DisableSTDIOValueChangedCallback(void *target_property_ptr, OptionValue *) +{ + TargetProperties *this_ = reinterpret_cast(target_property_ptr); + if (this_->GetDisableSTDIO()) + this_->m_launch_info.GetFlags().Set(lldb::eLaunchFlagDisableSTDIO); + else + this_->m_launch_info.GetFlags().Clear(lldb::eLaunchFlagDisableSTDIO); +} + //---------------------------------------------------------------------- // Target::TargetEventData //---------------------------------------------------------------------- Index: test/tools/lldb-mi/TestMiExec.py =================================================================== --- test/tools/lldb-mi/TestMiExec.py +++ test/tools/lldb-mi/TestMiExec.py @@ -60,7 +60,6 @@ @lldbmi_test @expectedFailureWindows("llvm.org/pr22274: need a pexpect replacement for windows") - @unittest2.skip("reviews.llvm.org/D6965: requires this patch") def test_lldbmi_exec_arguments_set(self): """Test that 'lldb-mi --interpreter' can pass args using -exec-arguments.""" @@ -91,7 +90,8 @@ #self.runCmd("-data-evaluate-expression argv[2]") #self.expect("\^done,value=\"2nd arg\"") self.runCmd("-interpreter-exec command \"print argv[2]\"") - self.expect("\"2nd arg\"") + #FIXME: lldb-mi doesn't handle inner quotes + self.expect("\"\\\\\\\"2nd arg\\\\\\\"\"") #FIXME: self.expect("\"2nd arg\"") #self.runCmd("-data-evaluate-expression argv[3]") #self.expect("\^done,value=\"third_arg\"") self.runCmd("-interpreter-exec command \"print argv[3]\"") @@ -103,7 +103,6 @@ @lldbmi_test @expectedFailureWindows("llvm.org/pr22274: need a pexpect replacement for windows") - @unittest2.skip("reviews.llvm.org/D6965: requires this patch") def test_lldbmi_exec_arguments_reset(self): """Test that 'lldb-mi --interpreter' can reset previously set args using -exec-arguments.""" @@ -363,7 +362,6 @@ @lldbmi_test @expectedFailureWindows("llvm.org/pr22274: need a pexpect replacement for windows") - @unittest2.skip("reviews.llvm.org/D6965: requires this patch") def test_lldbmi_exec_finish(self): """Test that 'lldb-mi --interpreter' works for -exec-finish.""" Index: test/tools/lldb-mi/TestMiInterpreterExec.py =================================================================== --- test/tools/lldb-mi/TestMiInterpreterExec.py +++ test/tools/lldb-mi/TestMiInterpreterExec.py @@ -49,7 +49,6 @@ @lldbmi_test @expectedFailureWindows("llvm.org/pr22274: need a pexpect replacement for windows") - @unittest2.skip("reviews.llvm.org/D6965: requires this patch") def test_lldbmi_settings_set_target_run_args(self): """Test that 'lldb-mi --interpreter' can set target arguments by 'setting set target.run-args' command.""" Index: tools/lldb-mi/MICmdArgValListOfN.h =================================================================== --- tools/lldb-mi/MICmdArgValListOfN.h +++ tools/lldb-mi/MICmdArgValListOfN.h @@ -56,7 +56,7 @@ const ArgValType_e veType); // const VecArgObjPtr_t &GetExpectedOptions(void) const; - template bool GetExpectedOption(T2 &vrwValue) const; + template bool GetExpectedOption(T2 &vrwValue, const VecArgObjPtr_t::size_type vnAt = 0) const; // Overridden: public: @@ -76,6 +76,7 @@ // parsed from the command's options string. // Type: Template method. // Args: vrwValue - (W) Templated type return value. +// vnAt - (R) Value at the specific position. // T1 - The argument value's class type of the data hold in the list of options. // T2 - The type pf the variable which holds the value wanted. // Return: MIstatus::success - Functional succeeded. @@ -84,10 +85,13 @@ //-- template bool -CMICmdArgValListOfN::GetExpectedOption(T2 &vrwValue) const +CMICmdArgValListOfN::GetExpectedOption(T2 &vrwValue, const VecArgObjPtr_t::size_type vnAt) const { const VecArgObjPtr_t &rVecOptions(GetExpectedOptions()); - VecArgObjPtr_t::const_iterator it2 = rVecOptions.begin(); + if (rVecOptions.size() <= vnAt) + return MIstatus::failure; + + VecArgObjPtr_t::const_iterator it2 = rVecOptions.begin() + vnAt; if (it2 != rVecOptions.end()) { const T1 *pOption = static_cast(*it2); Index: tools/lldb-mi/MICmdCmdExec.h =================================================================== --- tools/lldb-mi/MICmdCmdExec.h +++ tools/lldb-mi/MICmdCmdExec.h @@ -18,6 +18,7 @@ // CMICmdCmdExecStepInstruction interface. // CMICmdCmdExecFinish interface. // CMICmdCmdExecInterrupt interface. +// CMICmdCmdExecArguments interface. // // To implement new MI commands derive a new command class from the command base // class. To enable the new command for interpretation add the new command class @@ -307,3 +308,35 @@ private: lldb::SBCommandReturnObject m_lldbResult; }; + +//++ ============================================================================ +// Details: MI command class. MI commands derived from the command base class. +// *this class implements MI command "exec-arguments". +// Gotchas: None. +// Authors: Ilia Kirianovskii 25/11/2014. +// Changes: None. +//-- +class CMICmdCmdExecArguments : public CMICmdBase +{ + // Statics: + public: + // Required by the CMICmdFactory when registering *this command + static CMICmdBase *CreateSelf(void); + + // Methods: + public: + /* ctor */ CMICmdCmdExecArguments(void); + + // Overridden: + public: + // From CMICmdInvoker::ICmd + virtual bool Execute(void); + virtual bool Acknowledge(void); + virtual bool ParseArgs(void); + // From CMICmnBase + /* dtor */ virtual ~CMICmdCmdExecArguments(void); + + // Attributes: + private: + const CMIUtilString m_constStrArgArguments; +}; Index: tools/lldb-mi/MICmdCmdExec.cpp =================================================================== --- tools/lldb-mi/MICmdCmdExec.cpp +++ tools/lldb-mi/MICmdCmdExec.cpp @@ -18,6 +18,7 @@ // CMICmdCmdExecStepInstruction implementation. // CMICmdCmdExecFinish implementation. // CMICmdCmdExecInterrupt implementation. +// CMICmdCmdExecArguments implementation. // // Environment: Compilers: Visual C++ 12. // gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1 @@ -90,10 +91,9 @@ CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); lldb::SBError error; lldb::SBStream errMsg; - uint32_t launch_flags = lldb::LaunchFlags::eLaunchFlagDebug; - lldb::SBProcess process = rSessionInfo.GetTarget().Launch(rSessionInfo.GetListener(), nullptr, nullptr, nullptr, nullptr, - nullptr, nullptr, launch_flags, false, error); - + lldb::SBLaunchInfo launchInfo = rSessionInfo.GetTarget().GetLaunchInfo(); + launchInfo.SetListener(rSessionInfo.GetListener()); + lldb::SBProcess process = rSessionInfo.GetTarget().Launch(launchInfo, error); if ((!process.IsValid()) || (error.Fail())) { SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_INVALID_PROCESS), m_cmdData.strMiCmd.c_str(), errMsg.GetData())); @@ -1016,3 +1016,123 @@ { return new CMICmdCmdExecInterrupt(); } + +//--------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------- + +//++ ------------------------------------------------------------------------------------ +// Details: CMICmdCmdExecArguments constructor. +// Type: Method. +// Args: None. +// Return: None. +// Throws: None. +//-- +CMICmdCmdExecArguments::CMICmdCmdExecArguments(void) + : m_constStrArgArguments("arguments") +{ + // Command factory matches this name with that received from the stdin stream + m_strMiCmd = "exec-arguments"; + + // Required by the CMICmdFactory when registering *this command + m_pSelfCreatorFn = &CMICmdCmdExecArguments::CreateSelf; +} + +//++ ------------------------------------------------------------------------------------ +// Details: CMICmdCmdExecArguments destructor. +// Type: Overrideable. +// Args: None. +// Return: None. +// Throws: None. +//-- +CMICmdCmdExecArguments::~CMICmdCmdExecArguments(void) +{ +} + +//++ ------------------------------------------------------------------------------------ +// Details: The invoker requires this function. The parses the command line options +// arguments to extract values for each of those arguments. +// Type: Overridden. +// Args: None. +// Return: MIstatus::success - Function succeeded. +// MIstatus::failure - Function failed. +// Throws: None. +//-- +bool +CMICmdCmdExecArguments::ParseArgs(void) +{ + bool bOk = m_setCmdArgs.Add( + *(new CMICmdArgValListOfN(m_constStrArgArguments, false, true, CMICmdArgValListBase::eArgValType_StringAnything))); + return (bOk && ParseValidateCmdOptions()); +} + +//++ ------------------------------------------------------------------------------------ +// Details: The invoker requires this function. The command does work in this function. +// The command is likely to communicate with the LLDB SBDebugger in here. +// Type: Overridden. +// Args: None. +// Return: MIstatus::success - Function succeeded. +// MIstatus::failure - Function failed. +// Throws: None. +//-- +bool +CMICmdCmdExecArguments::Execute(void) +{ + CMICMDBASE_GETOPTION(pArgArguments, ListOfN, m_constStrArgArguments); + + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); + lldb::SBTarget sbTarget = rSessionInfo.GetTarget(); + if (!sbTarget.IsValid()) + { + SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_INVALID_TARGET_CURRENT), m_cmdData.strMiCmd.c_str())); + return MIstatus::failure; + } + + lldb::SBLaunchInfo sbLaunchInfo = sbTarget.GetLaunchInfo(); + sbLaunchInfo.SetArguments(NULL, false); + + CMIUtilString strArg; + size_t nArgIndex = 0; + while (pArgArguments->GetExpectedOption(strArg, nArgIndex)) + { + const char *argv[2] = { strArg.c_str(), NULL }; + sbLaunchInfo.SetArguments(argv, true); + ++nArgIndex; + } + + sbTarget.SetLaunchInfo(sbLaunchInfo); + + return MIstatus::success; +} + +//++ ------------------------------------------------------------------------------------ +// Details: The invoker requires this function. The command prepares a MI Record Result +// for the work carried out in the Execute(). +// Type: Overridden. +// Args: None. +// Return: MIstatus::success - Function succeeded. +// MIstatus::failure - Function failed. +// Throws: None. +//-- +bool +CMICmdCmdExecArguments::Acknowledge(void) +{ + const CMICmnMIResultRecord miRecordResult(m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done); + m_miResultRecord = miRecordResult; + + return MIstatus::success; +} + +//++ ------------------------------------------------------------------------------------ +// Details: Required by the CMICmdFactory when registering *this command. The factory +// calls this function to create an instance of *this command. +// Type: Static method. +// Args: None. +// Return: CMICmdBase * - Pointer to a new command. +// Throws: None. +//-- +CMICmdBase * +CMICmdCmdExecArguments::CreateSelf(void) +{ + return new CMICmdCmdExecArguments(); +} Index: tools/lldb-mi/MICmdCommands.cpp =================================================================== --- tools/lldb-mi/MICmdCommands.cpp +++ tools/lldb-mi/MICmdCommands.cpp @@ -98,6 +98,7 @@ bOk &= Register(); bOk &= Register(); bOk &= Register(); + bOk &= Register(); bOk &= Register(); bOk &= Register(); bOk &= Register();