diff options
| -rw-r--r-- | lldb/test/tools/lldb-mi/startup_options/TestMiStartupOptions.py | 99 | ||||
| -rw-r--r-- | lldb/test/tools/lldb-mi/startup_options/main.cpp | 3 | ||||
| -rw-r--r-- | lldb/test/tools/lldb-mi/startup_options/start_script | 5 | ||||
| -rw-r--r-- | lldb/test/tools/lldb-mi/startup_options/start_script_error | 2 | ||||
| -rw-r--r-- | lldb/test/tools/lldb-mi/startup_options/start_script_exit | 7 | ||||
| -rw-r--r-- | lldb/tools/lldb-mi/MIDriver.cpp | 105 | ||||
| -rw-r--r-- | lldb/tools/lldb-mi/MIDriver.h | 3 | 
7 files changed, 219 insertions, 5 deletions
| diff --git a/lldb/test/tools/lldb-mi/startup_options/TestMiStartupOptions.py b/lldb/test/tools/lldb-mi/startup_options/TestMiStartupOptions.py index a38df68dfbf..088fea7f0e4 100644 --- a/lldb/test/tools/lldb-mi/startup_options/TestMiStartupOptions.py +++ b/lldb/test/tools/lldb-mi/startup_options/TestMiStartupOptions.py @@ -127,6 +127,105 @@ class MiStartupOptionsTestCase(lldbmi_testcase.MiTestCaseBase):          # Test that lldb-mi is ready when executable was loaded          self.expect(self.child_prompt, exactly = True) + +    @lldbmi_test +    @expectedFailureWindows("llvm.org/pr22274: need a pexpect replacement for windows") +    def test_lldbmi_source_option_start_script(self): +        """Test that 'lldb-mi --interpreter' can execute user's commands after initial commands were executed.""" + +        # Prepared source file +        sourceFile = "start_script" + +        self.spawnLldbMi(args = "--source %s" % sourceFile) + +        # After '-file-exec-and-symbols a.out' +        self.expect("-file-exec-and-symbols %s" % self.myexe) +        self.expect("\^done") + +        # After '-break-insert -f main' +        self.expect("-break-insert -f main") +        self.expect("\^done,bkpt={number=\"1\"") + +        # After '-exec-run' +        self.expect("-exec-run") +        self.expect("\^running") + +        # After '-break-insert main.cpp:BP_return' +        line = line_number('main.cpp', '// BP_return') +        self.expect("-break-insert main.cpp:%d" % line) +        self.expect("\^done,bkpt={number=\"2\"") + +        # After '-exec-continue' +        self.expect("-exec-continue") +        self.expect("\^running") + +        # Test that lldb-mi is ready after execution of --source start_script +        self.expect(self.child_prompt, exactly = True) + +        # Try to evaluate 'a' expression +        self.runCmd("-data-evaluate-expression a") +        self.expect("\^done,value=\"10\"") +        self.expect(self.child_prompt, exactly = True) + +    @lldbmi_test +    @expectedFailureWindows("llvm.org/pr22274: need a pexpect replacement for windows") +    def test_lldbmi_source_option_start_script_exit(self): +        """Test that 'lldb-mi --interpreter' can execute a prepared file which passed via --source option.""" + +        # Prepared source file +        sourceFile = "start_script_exit" + +        self.spawnLldbMi(args = "--source %s" % sourceFile) + +        # After '-file-exec-and-symbols a.out' +        self.expect("-file-exec-and-symbols %s" % self.myexe) +        self.expect("\^done") + +        # After '-break-insert -f main' +        self.expect("-break-insert -f main") +        self.expect("\^done,bkpt={number=\"1\"") + +        # After '-exec-run' +        self.expect("-exec-run") +        self.expect("\^running") + +        # After '-break-insert main.cpp:BP_return' +        line = line_number('main.cpp', '// BP_return') +        self.expect("-break-insert main.cpp:%d" % line) +        self.expect("\^done,bkpt={number=\"2\"") + +        # After '-exec-continue' +        self.expect("-exec-continue") +        self.expect("\^running") + +        # After '-data-evaluate-expression a' +        self.expect("-data-evaluate-expression a") +        self.expect("\^done,value=\"10\"") + +        # After '-gdb-exit' +        self.expect("-gdb-exit") +        self.expect("\^exit") + +    @lldbmi_test +    @expectedFailureWindows("llvm.org/pr22274: need a pexpect replacement for windows") +    def test_lldbmi_source_option_start_script_error(self): +        """Test that 'lldb-mi --interpreter' stops execution of initial commands in case of error.""" + +        # Prepared source file +        sourceFile = "start_script_error" + +        self.spawnLldbMi(args = "--source %s" % sourceFile) + +        # After '-file-exec-and-symbols a.out' +        self.expect("-file-exec-and-symbols %s" % self.myexe) +        self.expect("\^done") + +        # After '-break-ins -f main' +        self.expect("-break-ins -f main") +        self.expect("\^error") + +        # Test that lldb-mi is ready after execution of --source start_script +        self.expect(self.child_prompt, exactly = True)      @lldbmi_test      @expectedFailureWindows("llvm.org/pr22274: need a pexpect replacement for windows") diff --git a/lldb/test/tools/lldb-mi/startup_options/main.cpp b/lldb/test/tools/lldb-mi/startup_options/main.cpp index 1e27c641e5c..8b9e2d0b34b 100644 --- a/lldb/test/tools/lldb-mi/startup_options/main.cpp +++ b/lldb/test/tools/lldb-mi/startup_options/main.cpp @@ -10,5 +10,6 @@  int  main(int argc, char const *argv[])  { -    return 0; +    int a = 10; +    return 0; // BP_return  } diff --git a/lldb/test/tools/lldb-mi/startup_options/start_script b/lldb/test/tools/lldb-mi/startup_options/start_script new file mode 100644 index 00000000000..511c0224825 --- /dev/null +++ b/lldb/test/tools/lldb-mi/startup_options/start_script @@ -0,0 +1,5 @@ +-file-exec-and-symbols a.out +-break-insert -f main +-exec-run +-break-insert main.cpp:14 +-exec-continue diff --git a/lldb/test/tools/lldb-mi/startup_options/start_script_error b/lldb/test/tools/lldb-mi/startup_options/start_script_error new file mode 100644 index 00000000000..d834e7407c5 --- /dev/null +++ b/lldb/test/tools/lldb-mi/startup_options/start_script_error @@ -0,0 +1,2 @@ +-file-exec-and-symbols a.out +-break-ins -f main diff --git a/lldb/test/tools/lldb-mi/startup_options/start_script_exit b/lldb/test/tools/lldb-mi/startup_options/start_script_exit new file mode 100644 index 00000000000..8379018c29d --- /dev/null +++ b/lldb/test/tools/lldb-mi/startup_options/start_script_exit @@ -0,0 +1,7 @@ +-file-exec-and-symbols a.out +-break-insert -f main +-exec-run +-break-insert main.cpp:14 +-exec-continue +-data-evaluate-expression a +-gdb-exit diff --git a/lldb/tools/lldb-mi/MIDriver.cpp b/lldb/tools/lldb-mi/MIDriver.cpp index 7d1d9e45b6d..55f9a6ce3a8 100644 --- a/lldb/tools/lldb-mi/MIDriver.cpp +++ b/lldb/tools/lldb-mi/MIDriver.cpp @@ -8,6 +8,7 @@  //===----------------------------------------------------------------------===//  // Third party headers: +#include <fstream>  #include "lldb/API/SBError.h"  // In-house headers: @@ -54,6 +55,7 @@ CMIDriver::CMIDriver(void)      , m_eCurrentDriverState(eDriverState_NotRunning)      , m_bHaveExecutableFileNamePathOnCmdLine(false)      , m_bDriverDebuggingArgExecutable(false) +    , m_bHaveCommandFileNamePathOnCmdLine(false)  {  } @@ -407,20 +409,40 @@ CMIDriver::ParseArgs(const int argc, const char *argv[], FILE *vpStdOut, bool &v      if (bHaveArgs)      { -        // Search right to left to look for the executable +        // Search right to left to look for filenames          for (MIint i = argc - 1; i > 0; i--)          {              const CMIUtilString strArg(argv[i]);              const CMICmdArgValFile argFile; + +            // Check for a filename              if (argFile.IsFilePath(strArg) || CMICmdArgValString(true, false, true).IsStringArg(strArg))              { +                // Is this the command file for the '-s' or '--source' options? +                const CMIUtilString strPrevArg(argv[i - 1]); +                if (strPrevArg.compare("-s") == 0 || strPrevArg.compare("--source") == 0) +                { +                    m_strCmdLineArgCommandFileNamePath = strArg; +                    m_bHaveCommandFileNamePathOnCmdLine = true; +                    i--; // skip '-s' on the next loop +                    continue; +                } +                // Else, must be the executable                  bHaveExecutableFileNamePath = true;                  m_strCmdLineArgExecuteableFileNamePath = strArg;                  m_bHaveExecutableFileNamePathOnCmdLine = true;              } -            // This argument is also check for in CMIDriverMgr::ParseArgs() -            if (0 == strArg.compare("--executable")) // Used to specify that there is executable argument also on the command line -            {                                        // See fn description. +            // Report error if no command file was specified for the '-s' or '--source' options +            else if (strArg.compare("-s") == 0 || strArg.compare("--source") == 0) +            { +                vwbExiting = true; +                const CMIUtilString errMsg = CMIUtilString::Format(MIRSRC(IDS_CMD_ARGS_ERR_VALIDATION_MISSING_INF), strArg.c_str()); +                errStatus.SetErrorString(errMsg.c_str()); +                break; +            } +            // This argument is also checked for in CMIDriverMgr::ParseArgs() +            else if (strArg.compare("--executable") == 0) // Used to specify that there is executable argument also on the command line +            {                                             // See fn description.                  bHaveExecutableLongOption = true;              }          } @@ -526,6 +548,13 @@ CMIDriver::DoMainLoop(void)      // App is not quitting currently      m_bExitApp = false; +    // Handle source file +    if (m_bHaveCommandFileNamePathOnCmdLine) +    { +        const bool bAsyncMode = false; +        ExecuteCommandFile(bAsyncMode); +    } +      // While the app is active      while (bOk && !m_bExitApp)      { @@ -1229,6 +1258,74 @@ CMIDriver::IsDriverDebuggingArgExecutable(void) const  }  //++ ------------------------------------------------------------------------------------ +// Details: Execute commands from prepared source file +// Type:    Method. +// Args:    vbAsyncMode       - (R) True = execute commands in asynchronous mode, false = otherwise. +// Return:  MIstatus::success - Function succeeded. +//          MIstatus::failure - Function failed. +// Throws:  None. +//-- +bool +CMIDriver::ExecuteCommandFile(const bool vbAsyncMode) +{ +    std::ifstream ifsStartScript(m_strCmdLineArgCommandFileNamePath.c_str()); +    if (!ifsStartScript.is_open()) +    { +        const CMIUtilString errMsg( +            CMIUtilString::Format(MIRSRC(IDS_UTIL_FILE_ERR_OPENING_FILE_UNKNOWN), m_strCmdLineArgCommandFileNamePath.c_str())); +        SetErrorDescription(errMsg.c_str()); +        const bool bForceExit = true; +        SetExitApplicationFlag(bForceExit); +        return MIstatus::failure; +    } + +    // Switch lldb to synchronous mode +    CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +    const bool bAsyncSetting = rSessionInfo.GetDebugger().GetAsync(); +    rSessionInfo.GetDebugger().SetAsync(vbAsyncMode); + +    // Execute commands from file +    bool bOk = MIstatus::success; +    CMIUtilString strCommand; +    while (!m_bExitApp && std::getline(ifsStartScript, strCommand)) +    { +        // Print command +        bOk = CMICmnStreamStdout::TextToStdout(strCommand); + +        // Skip if it's a comment or empty line +        if (strCommand.empty() || strCommand[0] == '#') +            continue; + +        // Execute if no error +        if (bOk) +        { +            CMIUtilThreadLock lock(rSessionInfo.GetSessionMutex()); +            bOk = InterpretCommand(strCommand); +        } + +        // Draw the prompt after command will be executed (if enabled) +        if (bOk && m_rStdin.GetEnablePrompt()) +            bOk = m_rStdOut.WriteMIResponse(m_rStdin.GetPrompt()); + +        // Exit if there is an error +        if (!bOk) +        { +            const bool bForceExit = true; +            SetExitApplicationFlag(bForceExit); +            break; +        } + +        // Wait while the handler thread handles incoming events +        CMICmnLLDBDebugger::Instance().WaitForHandleEvent(); +    } + +    // Switch lldb back to initial mode +    rSessionInfo.GetDebugger().SetAsync(bAsyncSetting); + +    return bOk; +} + +//++ ------------------------------------------------------------------------------------  // Details: Gets called when lldb-mi gets a signal. Stops the process if it was SIGINT.  //  // Type:    Method. diff --git a/lldb/tools/lldb-mi/MIDriver.h b/lldb/tools/lldb-mi/MIDriver.h index 66e5d5bc20d..795549e0f4a 100644 --- a/lldb/tools/lldb-mi/MIDriver.h +++ b/lldb/tools/lldb-mi/MIDriver.h @@ -137,6 +137,7 @@ class CMIDriver : public CMICmnBase,      bool InitClientIDEToMIDriver(void) const;      bool InitClientIDEEclipse(void) const;      bool LocalDebugSessionStartupExecuteCommands(void); +    bool ExecuteCommandFile(const bool vbAsyncMode);      // Overridden:    private: @@ -161,4 +162,6 @@ class CMIDriver : public CMICmnBase,      CMIUtilString m_strCmdLineArgExecuteableFileNamePath;      bool m_bDriverDebuggingArgExecutable; // True = the MI Driver (MI mode) is debugging executable passed as argument,                                            // false = running via a client (e.g. Eclipse) +    bool m_bHaveCommandFileNamePathOnCmdLine; // True = file with initial commands given as one of the parameters to the MI Driver, false = not found +    CMIUtilString m_strCmdLineArgCommandFileNamePath;  }; | 

