diff --git a/lldb/test/API/tools/lldb-vscode/disconnect/Makefile b/lldb/test/API/tools/lldb-vscode/disconnect/Makefile new file mode 100644 --- /dev/null +++ b/lldb/test/API/tools/lldb-vscode/disconnect/Makefile @@ -0,0 +1,3 @@ +CXX_SOURCES := main.cpp + +include Makefile.rules diff --git a/lldb/test/API/tools/lldb-vscode/disconnect/TestVSCode_disconnect.py b/lldb/test/API/tools/lldb-vscode/disconnect/TestVSCode_disconnect.py new file mode 100644 --- /dev/null +++ b/lldb/test/API/tools/lldb-vscode/disconnect/TestVSCode_disconnect.py @@ -0,0 +1,80 @@ +""" +Test lldb-vscode disconnect request +""" + + +import unittest2 +import vscode +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil +import lldbvscode_testcase +import subprocess +import time +import os + + +class TestVSCode_launch(lldbvscode_testcase.VSCodeTestCaseBase): + + mydir = TestBase.compute_mydir(__file__) + source = 'main.cpp' + + def disconnect_and_assert_no_output_printed(self): + self.vscode.request_disconnect() + # verify we didn't get any input after disconnect + time.sleep(2) + output = self.get_stdout() + self.assertTrue(output is None or len(output) == 0) + + @skipIfWindows + @skipIfRemote + def test_launch(self): + """ + This test launches a process that would output some text to stdout, but + we disconnect before printing, so stdout should be empty. + """ + program = self.getBuildArtifact("a.out") + self.build_and_launch(program) + + # We set a breakpoint right before the printing happens + self.set_source_breakpoints(self.source, [line_number(self.source, '// breakpoint')]) + self.continue_to_next_stop() + + self.disconnect_and_assert_no_output_printed() + + + @skipIfWindows + @skipIfRemote + def test_attach(self): + """ + This test attaches to a process that would output some text to stdout, but + we disconnect before printing, so stdout should be empty. + """ + self.build_and_create_debug_adaptor() + program = self.getBuildArtifact("a.out") + + # Use a file as a synchronization point between test and inferior. + sync_file_path = lldbutil.append_to_process_working_directory(self, + "sync_file_%d" % (int(time.time()))) + self.addTearDownHook( + lambda: self.run_platform_command( + "rm %s" % + (sync_file_path))) + + self.process = subprocess.Popen([program, sync_file_path], + universal_newlines=True, + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + lldbutil.wait_for_file_on_target(self, sync_file_path) + + self.attach(pid=self.process.pid) + + # We set a breakpoint right before the printing happens + self.set_source_breakpoints(self.source, [line_number(self.source, '// breakpoint')]) + + self.process.stdin.write("42 ") + self.process.stdin.flush() + self.continue_to_next_stop() + + self.disconnect_and_assert_no_output_printed() diff --git a/lldb/test/API/tools/lldb-vscode/disconnect/main.cpp b/lldb/test/API/tools/lldb-vscode/disconnect/main.cpp new file mode 100644 --- /dev/null +++ b/lldb/test/API/tools/lldb-vscode/disconnect/main.cpp @@ -0,0 +1,33 @@ +#include +#include + +void print(int x) { + printf("%d\n", x); // breakpoint +} + +void handle_launch() { + print(0); +} + +void handle_attach(char *sync_file_path) { + lldb_enable_attach(); + + { + // Create a file to signal that this process has started up. + std::ofstream sync_file; + sync_file.open(sync_file_path); + } + + // We wait for some input in order to proceed + int x; + scanf("%d", &x); + print(x); +} + +int main(int argc, char **args) { + if (argc == 1) + handle_launch(); + else + handle_attach(args[1]); + return 0; +} 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 @@ -89,6 +89,7 @@ lldb::tid_t focus_tid; bool sent_terminated_event; bool stop_at_entry; + bool is_attach; // Keep track of the last stop thread index IDs as threads won't go away // unless we send a "thread" event to indicate the thread exited. llvm::DenseSet thread_ids; 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 @@ -38,7 +38,7 @@ {"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) { + stop_at_entry(false), is_attach(false) { const char *log_file_path = getenv("LLDBVSCODE_LOG"); #if defined(_WIN32) // Windows opens stdout and stdin in text mode which converts \n to 13,10 diff --git a/lldb/tools/lldb-vscode/lldb-vscode.cpp b/lldb/tools/lldb-vscode/lldb-vscode.cpp --- a/lldb/tools/lldb-vscode/lldb-vscode.cpp +++ b/lldb/tools/lldb-vscode/lldb-vscode.cpp @@ -514,6 +514,7 @@ // }] // } void request_attach(const llvm::json::Object &request) { + g_vsc.is_attach = true; llvm::json::Object response; lldb::SBError error; FillResponse(request, response); @@ -769,7 +770,9 @@ FillResponse(request, response); auto arguments = request.getObject("arguments"); - bool terminateDebuggee = GetBoolean(arguments, "terminateDebuggee", false); + bool defaultTerminateDebuggee = g_vsc.is_attach ? false : true; + bool terminateDebuggee = + GetBoolean(arguments, "terminateDebuggee", defaultTerminateDebuggee); lldb::SBProcess process = g_vsc.target.GetProcess(); auto state = process.GetState(); @@ -788,10 +791,9 @@ case lldb::eStateStopped: case lldb::eStateRunning: g_vsc.debugger.SetAsync(false); - if (terminateDebuggee) - process.Kill(); - else - process.Detach(); + lldb::SBError error = terminateDebuggee ? process.Kill() : process.Detach(); + if (!error.Success()) + response.try_emplace("error", error.GetCString()); g_vsc.debugger.SetAsync(true); break; } @@ -1357,6 +1359,7 @@ // }] // } void request_launch(const llvm::json::Object &request) { + g_vsc.is_attach = false; llvm::json::Object response; lldb::SBError error; FillResponse(request, response);