diff --git a/lldb/packages/Python/lldbsuite/test/tools/lldb-vscode/vscode.py b/lldb/packages/Python/lldbsuite/test/tools/lldb-vscode/vscode.py --- a/lldb/packages/Python/lldbsuite/test/tools/lldb-vscode/vscode.py +++ b/lldb/packages/Python/lldbsuite/test/tools/lldb-vscode/vscode.py @@ -228,6 +228,9 @@ # 'stopped' event. We need to remember the thread stop # reasons since the 'threads' command doesn't return # that information. + if not self.configuration_done_sent: + raise ValueError("'stopped' event received before " + "configuationDone packet was sent") self._process_stopped() tid = body['threadId'] self.thread_stop_reasons[tid] = body diff --git a/lldb/test/API/tools/lldb-vscode/launch/TestVSCode_launch.py b/lldb/test/API/tools/lldb-vscode/launch/TestVSCode_launch.py --- a/lldb/test/API/tools/lldb-vscode/launch/TestVSCode_launch.py +++ b/lldb/test/API/tools/lldb-vscode/launch/TestVSCode_launch.py @@ -374,7 +374,7 @@ @skipIfRemote def test_extra_launch_commands(self): ''' - Tests the "luanchCommands" with extra launching settings + Tests the "launchCommands" with extra launching settings ''' self.build_and_create_debug_adaptor() program = self.getBuildArtifact("a.out") diff --git a/lldb/tools/lldb-vscode/VSCode.h b/lldb/tools/lldb-vscode/VSCode.h --- a/lldb/tools/lldb-vscode/VSCode.h +++ b/lldb/tools/lldb-vscode/VSCode.h @@ -145,6 +145,7 @@ bool sent_terminated_event; bool stop_at_entry; bool is_attach; + bool configuration_done_sent; uint32_t reverse_request_seq; std::map request_handlers; bool waiting_for_run_in_terminal; @@ -243,6 +244,15 @@ /// Debuggee will continue from stopped state. void WillContinue() { variables.Clear(); } + /// Poll the process to wait for eStateStopped. This is needed when we use + /// "launchCommands" or "attachCommands" to launch a process. + /// + /// \param[in] seconds + /// The number of seconds to poll the process to wait until it is stopped. + /// + /// \return Error if waiting for the process fails, no error if succeeds. + lldb::SBError WaitForProcessToStop(uint32_t seconds); + private: // Send the JSON in "json_str" to the "out" stream. Correctly send the // "Content-Length:" field followed by the length, followed by the raw diff --git a/lldb/tools/lldb-vscode/VSCode.cpp b/lldb/tools/lldb-vscode/VSCode.cpp --- a/lldb/tools/lldb-vscode/VSCode.cpp +++ b/lldb/tools/lldb-vscode/VSCode.cpp @@ -6,6 +6,7 @@ // //===----------------------------------------------------------------------===// +#include #include #include #include @@ -39,8 +40,8 @@ {"swift_catch", "Swift Catch", lldb::eLanguageTypeSwift}, {"swift_throw", "Swift Throw", lldb::eLanguageTypeSwift}}), focus_tid(LLDB_INVALID_THREAD_ID), sent_terminated_event(false), - stop_at_entry(false), is_attach(false), reverse_request_seq(0), - waiting_for_run_in_terminal(false), + stop_at_entry(false), is_attach(false), configuration_done_sent(false), + reverse_request_seq(0), waiting_for_run_in_terminal(false), progress_event_reporter( [&](const ProgressEvent &event) { SendJSON(event.ToJSON()); }) { const char *log_file_path = getenv("LLDBVSCODE_LOG"); @@ -528,6 +529,52 @@ request_handlers[request] = callback; } +lldb::SBError VSCode::WaitForProcessToStop(uint32_t seconds) { + // Wait for the process hit a stopped state. When running a launch (with or + // without "launchCommands") or attach (with or without)= "attachCommands"), + // the calls might take some time to stop at the entry point since the command + // is asynchronous. So we need to sync up with the process and make sure it is + // stopped before we proceed to do anything else as we will soon be asked to + // set breakpoints and other things that require the process to be stopped. + lldb::SBError error; + lldb::SBProcess process = target.GetProcess(); + if (!process.IsValid()) { + error.SetErrorString("invalid process"); + return error; + } + const useconds_t usleep_interval = 250 * 10000; // 250 ms internal + const useconds_t count = (seconds * 1000 * 1000)/usleep_interval; + for (useconds_t i=0; i