Index: lldb/trunk/test/tools/lldb-mi/control/TestMiExec.py =================================================================== --- lldb/trunk/test/tools/lldb-mi/control/TestMiExec.py +++ lldb/trunk/test/tools/lldb-mi/control/TestMiExec.py @@ -13,6 +13,26 @@ @lldbmi_test @skipIfWindows #llvm.org/pr24452: Get lldb-mi tests working on Windows @skipIfFreeBSD # llvm.org/pr22411: Failure presumably due to known thread races + @expectedFailureLinux # llvm.org/pr25000: lldb-mi does not receive broadcasted notification from Core/Process about process stopped + def test_lldbmi_exec_run(self): + """Test that 'lldb-mi --interpreter' can stop at entry.""" + + self.spawnLldbMi(args = None) + + # Load executable + self.runCmd("-file-exec-and-symbols %s" % self.myexe) + self.expect("\^done") + + # Test that program is stopped at entry + self.runCmd("-exec-run --start") + self.expect("\^running") + self.expect("\*stopped,reason=\"signal-received\",signal-name=\"SIGSTOP\",signal-meaning=\"Stop\",.*?thread-id=\"1\",stopped-threads=\"all\"") + # Test that lldb-mi is ready to execute next commands + self.expect(self.child_prompt, exactly = True) + + @lldbmi_test + @skipIfWindows #llvm.org/pr24452: Get lldb-mi tests working on Windows + @skipIfFreeBSD # llvm.org/pr22411: Failure presumably due to known thread races @expectedFailureAll("llvm.org/pr23139", oslist=["linux"], compiler="gcc", compiler_version=[">=","4.9"], archs=["i386"]) def test_lldbmi_exec_abort(self): """Test that 'lldb-mi --interpreter' works for -exec-abort.""" Index: lldb/trunk/tools/lldb-mi/MICmdCmdExec.h =================================================================== --- lldb/trunk/tools/lldb-mi/MICmdCmdExec.h +++ lldb/trunk/tools/lldb-mi/MICmdCmdExec.h @@ -55,11 +55,13 @@ // From CMICmdInvoker::ICmd bool Execute() override; bool Acknowledge() override; + bool ParseArgs() override; // From CMICmnBase /* dtor */ ~CMICmdCmdExecRun() override; // Attributes: private: + const CMIUtilString m_constStrArgStart; // StopAtEntry - run to first instruction or main() if specified lldb::SBCommandReturnObject m_lldbResult; }; Index: lldb/trunk/tools/lldb-mi/MICmdCmdExec.cpp =================================================================== --- lldb/trunk/tools/lldb-mi/MICmdCmdExec.cpp +++ lldb/trunk/tools/lldb-mi/MICmdCmdExec.cpp @@ -48,6 +48,7 @@ // Throws: None. //-- CMICmdCmdExecRun::CMICmdCmdExecRun() + : m_constStrArgStart("start") { // Command factory matches this name with that received from the stdin stream m_strMiCmd = "exec-run"; @@ -68,6 +69,23 @@ } //++ ------------------------------------------------------------------------------------ +// Details: The invoker requires this function. It parses the command line options' +// arguments to extract values for each of those arguments. +// Type: Overridden. +// Args: None. +// Return: MIstatus::success - Functional succeeded. +// MIstatus::failure - Functional failed. +// Throws: None. +//-- +bool +CMICmdCmdExecRun::ParseArgs() +{ + m_setCmdArgs.Add( + new CMICmdArgValOptionLong(m_constStrArgStart, false, true, CMICmdArgValListBase::eArgValType_OptionLong, 0)); + return 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. @@ -84,6 +102,14 @@ lldb::SBStream errMsg; lldb::SBLaunchInfo launchInfo = rSessionInfo.GetTarget().GetLaunchInfo(); launchInfo.SetListener(rSessionInfo.GetListener()); + + // Run to first instruction or main() requested? + CMICMDBASE_GETOPTION(pArgStart, OptionLong, m_constStrArgStart); + if (pArgStart->GetFound()) + { + launchInfo.SetLaunchFlags(launchInfo.GetLaunchFlags() | lldb::eLaunchFlagStopAtEntry); + } + lldb::SBProcess process = rSessionInfo.GetTarget().Launch(launchInfo, error); if ((!process.IsValid()) || (error.Fail())) { @@ -103,6 +129,7 @@ //++ ------------------------------------------------------------------------------------ // Details: The invoker requires this function. The command prepares a MI Record Result // for the work carried out in the Execute(). +// Called only if Execute() set status as successful on completion. // Type: Overridden. // Args: None. // Return: MIstatus::success - Functional succeeded. @@ -112,31 +139,21 @@ bool CMICmdCmdExecRun::Acknowledge() { - if (m_lldbResult.GetErrorSize() > 0) - { - const CMICmnMIValueConst miValueConst(m_lldbResult.GetError()); - const CMICmnMIValueResult miValueResult("message", miValueConst); - const CMICmnMIResultRecord miRecordResult(m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Error, miValueResult); - m_miResultRecord = miRecordResult; - } - else - { - const CMICmnMIResultRecord miRecordResult(m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Running); - m_miResultRecord = miRecordResult; + const CMICmnMIResultRecord miRecordResult(m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Running); + m_miResultRecord = miRecordResult; - CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); - lldb::pid_t pid = rSessionInfo.GetProcess().GetProcessID(); - // Give the client '=thread-group-started,id="i1" pid="xyz"' - m_bHasResultRecordExtra = true; - const CMICmnMIValueConst miValueConst2("i1"); - const CMICmnMIValueResult miValueResult2("id", miValueConst2); - const CMIUtilString strPid(CMIUtilString::Format("%lld", pid)); - const CMICmnMIValueConst miValueConst(strPid); - const CMICmnMIValueResult miValueResult("pid", miValueConst); - CMICmnMIOutOfBandRecord miOutOfBand(CMICmnMIOutOfBandRecord::eOutOfBand_ThreadGroupStarted, miValueResult2); - miOutOfBand.Add(miValueResult); - m_miResultRecordExtra = miOutOfBand.GetString(); - } + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); + lldb::pid_t pid = rSessionInfo.GetProcess().GetProcessID(); + // Give the client '=thread-group-started,id="i1" pid="xyz"' + m_bHasResultRecordExtra = true; + const CMICmnMIValueConst miValueConst2("i1"); + const CMICmnMIValueResult miValueResult2("id", miValueConst2); + const CMIUtilString strPid(CMIUtilString::Format("%lld", pid)); + const CMICmnMIValueConst miValueConst(strPid); + const CMICmnMIValueResult miValueResult("pid", miValueConst); + CMICmnMIOutOfBandRecord miOutOfBand(CMICmnMIOutOfBandRecord::eOutOfBand_ThreadGroupStarted, miValueResult2); + miOutOfBand.Add(miValueResult); + m_miResultRecordExtra = miOutOfBand.GetString(); return MIstatus::success; } Index: lldb/trunk/tools/lldb-mi/MICmdCmdSupportList.cpp =================================================================== --- lldb/trunk/tools/lldb-mi/MICmdCmdSupportList.cpp +++ lldb/trunk/tools/lldb-mi/MICmdCmdSupportList.cpp @@ -71,8 +71,13 @@ bool CMICmdCmdSupportListFeatures::Acknowledge() { - const CMICmnMIValueConst miValueConst("data-read-memory-bytes"); - const CMICmnMIValueList miValueList(miValueConst); + // Declare supported features here + const CMICmnMIValueConst miValueConst1("data-read-memory-bytes"); + const CMICmnMIValueConst miValueConst2("exec-run-start-option"); + // Some features may depend on host and/or target, decide what to add below + CMICmnMIValueList miValueList(true); + miValueList.Add(miValueConst1); + miValueList.Add(miValueConst2); const CMICmnMIValueResult miValueResult("features", miValueList); const CMICmnMIResultRecord miRecordResult(m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done, miValueResult); m_miResultRecord = miRecordResult;