Index: test/tools/lldb-mi/TestMiStack.py =================================================================== --- test/tools/lldb-mi/TestMiStack.py +++ test/tools/lldb-mi/TestMiStack.py @@ -242,5 +242,61 @@ self.runCmd("-stack-list-frames 0 0") self.expect("\^done,stack=\[frame=\{level=\"0\",addr=\".+\",func=\"main\",file=\"main\.c\",fullname=\".*main\.c\",line=\".+\"\}\]") + @lldbmi_test + @expectedFailureWindows("llvm.org/pr22274: need a pexpect replacement for windows") + @skipIfFreeBSD # llvm.org/pr22411: Failure presumably due to known thread races + @skipIfLinux # llvm.org/pr22411: Failure presumably due to known thread races + def test_lldbmi_stack_select_frame(self): + """Test that 'lldb-mi --interpreter' can choose current frame.""" + + self.spawnLldbMi(args = None) + + # Load executable + self.runCmd("-file-exec-and-symbols %s" % self.myexe) + self.expect("\^done") + + # Run to main + self.runCmd("-break-insert -f main") + self.expect("\^done,bkpt={number=\"1\"") + self.runCmd("-exec-run") + self.expect("\^running") + self.expect("\*stopped,reason=\"breakpoint-hit\"") + + # Test that -stack-select-frame requires 1 mandatory argument + self.runCmd("-stack-select-frame") + self.expect("\^error,msg=\"Command 'stack-select-frame'. Command Args. Missing options, 1 or more required\"") + + # Test that -stack-select-frame fails on invalid frame number + self.runCmd("-stack-select-frame 99") + self.expect("\^error,msg=\"Command 'stack-select-frame'. Frame ID invalid\"") + + # Test that current frame is #0 + self.runCmd("-stack-info-frame") + self.expect("\^done,frame=\{level=\"0\",addr=\".+\",func=\"main\",file=\"main\.c\",fullname=\".*main\.c\",line=\"\d+\"\}") + + # Test that -stack-select-frame can select the selected frame + self.runCmd("-stack-select-frame 0") + self.expect("\^done") + + # Test that current frame is still #0 + self.runCmd("-stack-info-frame") + self.expect("\^done,frame=\{level=\"0\",addr=\".+\",func=\"main\",file=\"main\.c\",fullname=\".*main\.c\",line=\"\d+\"\}") + + # Test that -stack-select-frame can select frame #1 (parent frame) + self.runCmd("-stack-select-frame 1") + self.expect("\^done") + + # Test that current frame is #1 + self.runCmd("-stack-info-frame") + self.expect("\^done,frame=\{level=\"1\",addr=\".+\",func=\".+\",file=\"\?\?\",fullname=\"\?\?\",line=\"-1\"\}") + + # Test that -stack-select-frame can select frame #0 (child frame) + self.runCmd("-stack-select-frame 0") + self.expect("\^done") + + # Test that current frame is #0 and it has the same information + self.runCmd("-stack-info-frame") + self.expect("\^done,frame=\{level=\"0\",addr=\".+\",func=\"main\",file=\"main\.c\",fullname=\".*main\.c\",line=\"\d+\"\}") + if __name__ == '__main__': unittest2.main() Index: tools/lldb-mi/MICmdCmdStack.h =================================================================== --- tools/lldb-mi/MICmdCmdStack.h +++ tools/lldb-mi/MICmdCmdStack.h @@ -15,6 +15,7 @@ // CMICmdCmdStackListFrames interface. // CMICmdCmdStackListArguments interface. // CMICmdCmdStackListLocals interface. +// CMICmdCmdStackSelectFrame 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 @@ -182,6 +183,36 @@ //++ ============================================================================ // Details: MI command class. MI commands derived from the command base class. +// *this class implements MI command "stack-select-frame". +//-- +class CMICmdCmdStackSelectFrame : public CMICmdBase +{ + // Statics: + public: + // Required by the CMICmdFactory when registering *this command + static CMICmdBase *CreateSelf(void); + + // Methods: + public: + /* ctor */ CMICmdCmdStackSelectFrame(void); + + // Overridden: + public: + // From CMICmdInvoker::ICmd + virtual bool Execute(void); + virtual bool Acknowledge(void); + virtual bool ParseArgs(void); + // From CMICmnBase + /* dtor */ virtual ~CMICmdCmdStackSelectFrame(void); + + // Attributes: + private: + bool m_bFrameInvalid; // True = yes invalid frame, false = ok + const CMIUtilString m_constStrArgFrame; +}; + +//++ ============================================================================ +// Details: MI command class. MI commands derived from the command base class. // *this class implements MI command "stack-list-locals". // Gotchas: None. // Authors: Illya Rudkin 24/03/2014. Index: tools/lldb-mi/MICmdCmdStack.cpp =================================================================== --- tools/lldb-mi/MICmdCmdStack.cpp +++ tools/lldb-mi/MICmdCmdStack.cpp @@ -15,6 +15,7 @@ // CMICmdCmdStackListFrames implementation. // CMICmdCmdStackListArguments implementation. // CMICmdCmdStackListLocals implementation. +// CMICmdCmdStackSelectFrame implementation. // // Environment: Compilers: Visual C++ 12. // gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1 @@ -825,3 +826,124 @@ { return new CMICmdCmdStackListLocals(); } + +//--------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------- + +//++ ------------------------------------------------------------------------------------ +// Details: CMICmdCmdStackSelectFrame constructor. +// Type: Method. +// Args: None. +// Return: None. +// Throws: None. +//-- +CMICmdCmdStackSelectFrame::CMICmdCmdStackSelectFrame(void) + : m_bFrameInvalid(false) + , m_constStrArgFrame("frame") +{ + // Command factory matches this name with that received from the stdin stream + m_strMiCmd = "stack-select-frame"; + + // Required by the CMICmdFactory when registering *this command + m_pSelfCreatorFn = &CMICmdCmdStackSelectFrame::CreateSelf; +} + +//++ ------------------------------------------------------------------------------------ +// Details: CMICmdCmdStackSelectFrame destructor. +// Type: Overrideable. +// Args: None. +// Return: None. +// Throws: None. +//-- +CMICmdCmdStackSelectFrame::~CMICmdCmdStackSelectFrame(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 +CMICmdCmdStackSelectFrame::ParseArgs(void) +{ + bool bOk = m_setCmdArgs.Add(*(new CMICmdArgValNumber(m_constStrArgFrame, true, false))); + 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 +CMICmdCmdStackSelectFrame::Execute(void) +{ + CMICMDBASE_GETOPTION(pArgFrame, Number, m_constStrArgFrame); + + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); + lldb::SBThread sbThread = rSessionInfo.GetProcess().GetSelectedThread(); + + const MIuint nFrameId = pArgFrame->GetValue(); + m_bFrameInvalid = (nFrameId >= sbThread.GetNumFrames()); + if (m_bFrameInvalid) + return MIstatus::success; + + lldb::SBFrame sbFrame = sbThread.SetSelectedFrame(nFrameId); + m_bFrameInvalid = !sbFrame.IsValid(); + + 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 +CMICmdCmdStackSelectFrame::Acknowledge(void) +{ + if (m_bFrameInvalid) + { + // MI print "%s^error,msg=\"Command '-stack-select-frame'. Frame ID invalid\"" + const CMICmnMIValueConst miValueConst( + CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_FRAME_INVALID), m_cmdData.strMiCmd.c_str())); + const CMICmnMIValueResult miValueResult("msg", miValueConst); + const CMICmnMIResultRecord miRecordResult(m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Error, miValueResult); + m_miResultRecord = miRecordResult; + + return MIstatus::success; + } + + 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 * +CMICmdCmdStackSelectFrame::CreateSelf(void) +{ + return new CMICmdCmdStackSelectFrame(); +} Index: tools/lldb-mi/MICmdCommands.cpp =================================================================== --- tools/lldb-mi/MICmdCommands.cpp +++ tools/lldb-mi/MICmdCommands.cpp @@ -121,6 +121,7 @@ bOk &= Register(); bOk &= Register(); bOk &= Register(); + bOk &= Register(); bOk &= Register(); bOk &= Register(); bOk &= Register();