Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

service/dap: support terminateDebuggee option for attach only #2940

Merged
merged 2 commits into from
Mar 22, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions cmd/dlv/dlv_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down
10 changes: 9 additions & 1 deletion service/dap/daptest/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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)
Expand Down
10 changes: 8 additions & 2 deletions service/dap/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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")
Expand All @@ -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))
Expand Down
10 changes: 9 additions & 1 deletion service/dap/server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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},
Expand Down Expand Up @@ -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()
Expand All @@ -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()
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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"
Expand Down Expand Up @@ -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()
Expand Down