From 1c0f6f6174d6c86117c64f4c18483c5e7ad9e834 Mon Sep 17 00:00:00 2001 From: Polina Sokolova Date: Tue, 22 Mar 2022 00:12:39 -0700 Subject: [PATCH 1/2] service/dap: support terminateDebuggee option for attach only --- service/dap/daptest/client.go | 10 +++++++++- service/dap/server.go | 10 ++++++++-- service/dap/server_test.go | 10 +++++++++- 3 files changed, 26 insertions(+), 4 deletions(-) diff --git a/service/dap/daptest/client.go b/service/dap/daptest/client.go index eb5770258b..82b3fe05a1 100644 --- a/service/dap/daptest/client.go +++ b/service/dap/daptest/client.go @@ -105,7 +105,6 @@ func (c *Client) ExpectInitializeResponseAndCapabilities(t *testing.T) *dap.Init SupportsConfigurationDoneRequest: true, SupportsConditionalBreakpoints: true, SupportsDelayedStackTraceLoading: true, - SupportTerminateDebuggee: true, SupportsExceptionInfoRequest: true, SupportsSetVariable: true, SupportsFunctionBreakpoints: true, @@ -137,6 +136,15 @@ func (c *Client) ExpectUnsupportedCommandErrorResponse(t *testing.T) *dap.ErrorR return c.ExpectErrorResponseWith(t, 9999, "Unsupported command", false) } +func (c *Client) ExpectCapabilitiesEventSupportTerminateDebuggee(t *testing.T) *dap.CapabilitiesEvent { + t.Helper() + e := c.ExpectCapabilitiesEvent(t) + if !e.Body.Capabilities.SupportTerminateDebuggee { + t.Errorf("\ngot %#v\nwant SupportTerminateDebuggee=true", e.Body.Capabilities.SupportTerminateDebuggee) + } + return e +} + func (c *Client) ExpectOutputEventRegex(t *testing.T, want string) *dap.OutputEvent { t.Helper() e := c.ExpectOutputEvent(t) diff --git a/service/dap/server.go b/service/dap/server.go index 8ef5b1da19..8a06f7be6d 100644 --- a/service/dap/server.go +++ b/service/dap/server.go @@ -834,7 +834,6 @@ func (s *Session) onInitializeRequest(request *dap.InitializeRequest) { response.Body.SupportsConfigurationDoneRequest = true response.Body.SupportsConditionalBreakpoints = true response.Body.SupportsDelayedStackTraceLoading = true - response.Body.SupportTerminateDebuggee = true response.Body.SupportsFunctionBreakpoints = true response.Body.SupportsInstructionBreakpoints = true response.Body.SupportsExceptionInfoRequest = true @@ -844,10 +843,12 @@ func (s *Session) onInitializeRequest(request *dap.InitializeRequest) { response.Body.SupportsSteppingGranularity = true response.Body.SupportsLogPoints = true response.Body.SupportsDisassembleRequest = true + // To be enabled by CapabilitiesEvent based on launch configuration + response.Body.SupportsStepBack = false + response.Body.SupportTerminateDebuggee = false // TODO(polina): support these requests in addition to vscode-go feature parity response.Body.SupportsTerminateRequest = false response.Body.SupportsRestartRequest = false - response.Body.SupportsStepBack = false // To be enabled by CapabilitiesEvent based on configuration response.Body.SupportsSetExpression = false response.Body.SupportsLoadedSourcesRequest = false response.Body.SupportsReadMemoryRequest = false @@ -1749,6 +1750,8 @@ func (s *Session) onAttachRequest(request *dap.AttachRequest) { s.sendShowUserErrorResponse(request.Request, FailedToAttach, "Failed to attach", err.Error()) return } + // Give the user an option to terminate debuggee when client disconnects (default is to leave it) + s.send(&dap.CapabilitiesEvent{Event: *newEvent("capabilities"), Body: dap.CapabilitiesEventBody{Capabilities: dap.Capabilities{SupportTerminateDebuggee: true}}}) case "remote": if s.debugger == nil { s.sendShowUserErrorResponse(request.Request, FailedToAttach, "Failed to attach", "no debugger found") @@ -1767,6 +1770,9 @@ func (s *Session) onAttachRequest(request *dap.AttachRequest) { if s.config.Debugger.Backend == "rr" { s.send(&dap.CapabilitiesEvent{Event: *newEvent("capabilities"), Body: dap.CapabilitiesEventBody{Capabilities: dap.Capabilities{SupportsStepBack: true}}}) } + // Give the user an option to terminate this server when client disconnects (default is to leave it) + s.send(&dap.CapabilitiesEvent{Event: *newEvent("capabilities"), Body: dap.CapabilitiesEventBody{Capabilities: dap.Capabilities{SupportTerminateDebuggee: true}}}) + // TODO(polina); also use SupportSuspendDebuggee when available default: s.sendShowUserErrorResponse(request.Request, FailedToAttach, "Failed to attach", fmt.Sprintf("invalid debug configuration - unsupported 'mode' attribute %q", args.Mode)) diff --git a/service/dap/server_test.go b/service/dap/server_test.go index 671b1c89f7..9d7930ad05 100644 --- a/service/dap/server_test.go +++ b/service/dap/server_test.go @@ -506,6 +506,7 @@ func TestAttachStopOnEntry(t *testing.T) { // 2 >> attach, << initialized, << attach client.AttachRequest( map[string]interface{}{"mode": "local", "processId": cmd.Process.Pid, "stopOnEntry": true, "backend": "default"}) + client.ExpectCapabilitiesEventSupportTerminateDebuggee(t) initEvent := client.ExpectInitializedEvent(t) if initEvent.Seq != 0 { t.Errorf("\ngot %#v\nwant Seq=0", initEvent) @@ -3676,6 +3677,7 @@ func substitutePathTestHelper(t *testing.T, fixture protest.Fixture, client *dap switch request { case "attach": client.AttachRequest(launchAttachConfig) + client.ExpectCapabilitiesEventSupportTerminateDebuggee(t) case "launch": client.LaunchRequestWithArgs(launchAttachConfig) default: @@ -5663,6 +5665,7 @@ func TestAttachRequest(t *testing.T) { func() { client.AttachRequest(map[string]interface{}{ /*"mode": "local" by default*/ "processId": cmd.Process.Pid, "stopOnEntry": false}) + client.ExpectCapabilitiesEventSupportTerminateDebuggee(t) }, // Set breakpoints fixture.Source, []int{8}, @@ -6555,6 +6558,7 @@ func TestAttachRemoteToHaltedTargetStopOnEntry(t *testing.T) { _, dbg := launchDebuggerWithTargetHalted(t, "increment") runTestWithDebugger(t, dbg, func(client *daptest.Client) { client.AttachRequest(map[string]interface{}{"mode": "remote", "stopOnEntry": true}) + client.ExpectCapabilitiesEventSupportTerminateDebuggee(t) client.ExpectInitializedEvent(t) client.ExpectAttachResponse(t) client.ConfigurationDoneRequest() @@ -6568,6 +6572,7 @@ func TestAttachRemoteToHaltedTargetContinueOnEntry(t *testing.T) { _, dbg := launchDebuggerWithTargetHalted(t, "http_server") runTestWithDebugger(t, dbg, func(client *daptest.Client) { client.AttachRequest(map[string]interface{}{"mode": "remote", "stopOnEntry": false}) + client.ExpectCapabilitiesEventSupportTerminateDebuggee(t) client.ExpectInitializedEvent(t) client.ExpectAttachResponse(t) client.ConfigurationDoneRequest() @@ -6584,6 +6589,7 @@ func TestAttachRemoteToRunningTargetStopOnEntry(t *testing.T) { fixture, dbg := launchDebuggerWithTargetRunning(t, "loopprog") runTestWithDebugger(t, dbg, func(client *daptest.Client) { client.AttachRequest(map[string]interface{}{"mode": "remote", "stopOnEntry": true}) + client.ExpectCapabilitiesEventSupportTerminateDebuggee(t) client.ExpectInitializedEvent(t) client.ExpectAttachResponse(t) // Target is halted here @@ -6603,6 +6609,7 @@ func TestAttachRemoteToRunningTargetContinueOnEntry(t *testing.T) { fixture, dbg := launchDebuggerWithTargetRunning(t, "loopprog") runTestWithDebugger(t, dbg, func(client *daptest.Client) { client.AttachRequest(map[string]interface{}{"mode": "remote", "stopOnEntry": false}) + client.ExpectCapabilitiesEventSupportTerminateDebuggee(t) client.ExpectInitializedEvent(t) client.ExpectAttachResponse(t) // Target is halted here @@ -6617,7 +6624,7 @@ func TestAttachRemoteToRunningTargetContinueOnEntry(t *testing.T) { } // TestAttachRemoteMultiClientDisconnect tests that that remote attach doesn't take down -// the server in multi-client mode unless terminateDebugee is explicitely set. +// the server in multi-client mode unless terminateDebuggee is explicitely set. func TestAttachRemoteMultiClientDisconnect(t *testing.T) { closingClientSessionOnly := fmt.Sprintf(daptest.ClosingClient, "halted") detachingAndTerminating := "Detaching and terminating target process" @@ -6651,6 +6658,7 @@ func TestAttachRemoteMultiClientDisconnect(t *testing.T) { client.ExpectInitializeResponseAndCapabilities(t) client.AttachRequest(map[string]interface{}{"mode": "remote", "stopOnEntry": true}) + client.ExpectCapabilitiesEventSupportTerminateDebuggee(t) client.ExpectInitializedEvent(t) client.ExpectAttachResponse(t) client.ConfigurationDoneRequest() From 71715fb73a6d08091304a02ef3787a2e666f150b Mon Sep 17 00:00:00 2001 From: Polina Sokolova Date: Tue, 22 Mar 2022 00:48:30 -0700 Subject: [PATCH 2/2] Update dlv_test --- cmd/dlv/dlv_test.go | 1 + 1 file changed, 1 insertion(+) diff --git a/cmd/dlv/dlv_test.go b/cmd/dlv/dlv_test.go index 5469989022..a8831497d9 100644 --- a/cmd/dlv/dlv_test.go +++ b/cmd/dlv/dlv_test.go @@ -696,6 +696,7 @@ func TestDAPCmd(t *testing.T) { func newDAPRemoteClient(t *testing.T, addr string) *daptest.Client { c := daptest.NewClient(addr) c.AttachRequest(map[string]interface{}{"mode": "remote", "stopOnEntry": true}) + c.ExpectCapabilitiesEventSupportTerminateDebuggee(t) c.ExpectInitializedEvent(t) c.ExpectAttachResponse(t) c.ConfigurationDoneRequest()