diff options
| author | Ilia K <ki.stfu@gmail.com> | 2015-05-07 06:51:46 +0000 |
|---|---|---|
| committer | Ilia K <ki.stfu@gmail.com> | 2015-05-07 06:51:46 +0000 |
| commit | d3da77e84ef9d90793e0bf5a748f79b79728506d (patch) | |
| tree | ce5b8bb6f4f9560e2dbc9570752cb0cc7ded923d | |
| parent | 8913012ee97c8911b4bf95784f70ada3dd94ce44 (diff) | |
| download | bcm5719-llvm-d3da77e84ef9d90793e0bf5a748f79b79728506d.tar.gz bcm5719-llvm-d3da77e84ef9d90793e0bf5a748f79b79728506d.zip | |
Add -s/--source option support (MI)
Summary:
This patch adds -s/--source option to execute source file with prepared command.
For example:
```
$ cat start_script
target create ~/p/hello
process launch -s
continue
$ bin/lldb-mi -s start_script
(gdb)
target create ~/p/hello
Current executable set to '~/p/hello' (x86_64).
^done
(gdb)
process launch -s
=shlibs-added,shlib-info=[num="1",name="hello",dyld-addr="-",reason="dyld",path="/Users/IliaK/p/hello",loaded_addr="-",dsym-objpath="/Users/IliaK/p/hello.dSYM/Contents/Resources/DWARF/hello"]
Process 33289 launched: '/Users/IliaK/p/hello' (x86_64)
^done
(gdb)
continue
=thread-created,id="1",group-id="i1"
=thread-selected,id="1"
(gdb)
Process 33289 resuming
Process 33289 exited with status = 0 (0x00000000)
^done
```
Test Plan: ./dotest.py -v --executable $BUILDDIR/bin/lldb tools/lldb-mi/
Reviewers: abidh
Reviewed By: abidh
Subscribers: lldb-commits, abidh
Differential Revision: http://reviews.llvm.org/D9278
llvm-svn: 236703
| -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; }; |

