[lldb-mi] Add support for StopAtEntry in MI via "-exec-run --start".

This patch adds a --start option to the lldb-mi -exec-run command for
getting process stopped at entry point after launch.  It is equivelent
to the -s option in the lldb command line interpreter:
    process launch -s
and is therefore not supported on all hosts and/or targets.  To check
if the --start option is supported, see if the corresponding feature
"exec-run-start-option" is in the list of options reported by the lldb-mi
"-list-features" command.

Patch from engineer.developer@gmail.com (Kirill Lapshin)
Reviewed by: ki.stfu
Subscribers: lldb-commits
Differential Revision: http://reviews.llvm.org/D12977

llvm-svn: 249072
This commit is contained in:
Dawn Perchik 2015-10-01 21:15:43 +00:00
parent 52bf0ebfdf
commit 8587212085
4 changed files with 70 additions and 26 deletions

View File

@ -10,6 +10,26 @@ class MiExecTestCase(lldbmi_testcase.MiTestCaseBase):
mydir = TestBase.compute_mydir(__file__)
@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

View File

@ -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";
@ -67,6 +68,23 @@ CMICmdCmdExecRun::~CMICmdCmdExecRun()
{
}
//++ ------------------------------------------------------------------------------------
// 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.
@ -84,6 +102,14 @@ CMICmdCmdExecRun::Execute()
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 @@ CMICmdCmdExecRun::Execute()
//++ ------------------------------------------------------------------------------------
// 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 @@ CMICmdCmdExecRun::Execute()
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;
}

View File

@ -55,11 +55,13 @@ class CMICmdCmdExecRun : public CMICmdBase
// 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;
};

View File

@ -71,8 +71,13 @@ CMICmdCmdSupportListFeatures::Execute()
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;