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

debug: setting breakpoint while running causes skipped stopped event at next breakpoint #759

Closed
polinasok opened this issue Oct 9, 2020 · 3 comments
Assignees
Labels
Debug Issues related to the debugging functionality of the extension. FrozenDueToAge release-blocker must be fixed before the next release.

Comments

@polinasok
Copy link
Contributor

polinasok commented Oct 9, 2020

This is cause by https://golang.org/cl/253578.
This came up as part of remote Theia debugging by @quoctruong (see https://golang.org/cl/257337).
I was able to reproduce this locally at HEAD (7d5f58a).

Steps to reproduce

  1. Program
func main() {
	for i := 0; true; i++ {
		fmt.Println("===== i", i)
		time.Sleep(2 * time.Second) // set breakpoint here while running
	}
}
  1. Launch.json
            "request": "launch",
            "mode": "auto",
            "stopOnEntry": false,
  1. Start the debug session (do NOT set any breakpoints in advance)
  2. While the program is running, click to set a breakpoint in the middle of the loop
  3. The program will continue to this breakpoint, but a stopped event will not be sent
  4. As a result, the continue button will be unavailable and CALL STACK and VARIABLES will be empty

Logs with detailed explanations

After:

### Continue request is made
  2020-10-08T22:04:14-07:00 debug layer=rpc (async 3) <- 
  RPCServer.Command(api.DebuggerCommand{"name":"continue","ReturnInfoLoadConfig":null})
### While target is running
  2020-10-08T22:04:14-07:00 debug layer=debugger continuing
### Breakpoint is being set
  From client: setBreakpoints({"source":{"name":"foo.go","path":"/Users/polina/go/src/foo/foo.go"},"lines":[11],"breakpoints":[{"line":11}],"sourceModified":false})
  SetBreakPointsRequest
### SetBreakpoint handler detects that target is running
  2020-10-08T22:05:29-07:00 debug layer=rpc (async 4) <- RPCServer.State(rpc2.StateIn{"NonBlocking":true})
  2020-10-08T22:05:29-07:00 debug layer=rpc (async 4) -> rpc2.StateOut{"State":{"Running":true,"Recording":false,"Threads":null,"NextInProgress":false,"exited":false,"exitStatus":0,"When":""}} error: ""
### So it must halt delve to issue a blocking breakpoint rpc. Since this will not be a user-triggered pause,
### it wants to do this behind the scenes and not trigger a stopped event, so it uses skipStopEventOnce flag.
### this.skipStopEventOnce = true
  2020-10-08T22:05:29-07:00 debug layer=rpc (async 5) <- 
  RPCServer.Command(api.DebuggerCommand{"name":"halt","ReturnInfoLoadConfig":null})
  2020-10-08T22:05:29-07:00 debug layer=debugger halting
### Continue returns
  2020-10-08T22:05:29-07:00 debug layer=rpc (async 3) -> rpc2.CommandOut{"State":{"Running":false,…}} error: ""
### Halt returns
  2020-10-08T22:05:29-07:00 debug layer=rpc (async 5) -> rpc2.CommandOut{"State":{"Running":false,…}} error: “”
### Halt callback calls setBreakPoints() 
  All cleared
  Creating on: /Users/polina/go/src/foo/foo.go:11
### Continue callback calls handleReenterDebug(“breakpoint”)
  2020-10-08T22:05:29-07:00 debug layer=rpc <- RPCServer.ListGoroutines(rpc2.ListGoroutinesIn{"Start":0,"Count":1})
  2020-10-08T22:05:29-07:00 debug layer=rpc -> *rpc2.ListGoroutinesOut{"Goroutines”:[…],”Nextg":1} error: ""
### Back to setBreakPoints() to create the breakpoint
  2020-10-08T22:05:29-07:00 debug layer=rpc <- RPCServer.CreateBreakpoint(…}
  2020-10-08T22:05:29-07:00 debug layer=rpc -> *rpc2.CreateBreakpointOut{…} error: ""
### Back to handleReenterDebug(), where skipStopEventOnce=true is detected and stop event is skipped
### skipStopEventOnce is reset back to false
### Back to setBreakPoints()
  All set:[…]
  To client: {"seq":0,"type":"response","request_seq":5,"command":"setBreakpoints","success":true,"body":{"breakpoints":[{"verified":true,"line":11}]}}
  SetBreakPointsResponse
### Halt callback triggers continue to get the target back to the running state as before the breakpoint was set
  2020-10-08T22:05:35-07:00 debug layer=rpc (async 8) <- 
  RPCServer.Command(api.DebuggerCommand{"name":"continue","ReturnInfoLoadConfig":null})
  2020-10-08T22:05:35-07:00 debug layer=debugger continuing
### Eventually execution stops at the breakpoint we just set
  2020-10-08T22:05:35-07:00 debug layer=rpc (async 8) -> rpc2.CommandOut{"State":{"Running":false,…}} error: ""
  2020-10-08T22:05:35-07:00 debug layer=rpc <- RPCServer.ListGoroutines(rpc2.ListGoroutinesIn{"Start":0,"Count":1})
  2020-10-08T22:05:35-07:00 debug layer=rpc -> *rpc2.ListGoroutinesOut{…}
### And an explicit stopped event is sent to the editor because skipStopEventOnce was reset to false
  To client: {"seq":0,"type":"event","event":"stopped","body":{"reason":"breakpoint","threadId":1,"allThreadsStopped":true}}
  StoppedEvent("breakpoint")
### This triggers the waterfall of requests (threads, stackTrace, scopes, variables) to populate all the panes in the UI

Before:

### Continue
  2020-10-09T00:17:10-07:00 debug layer=rpc (async 3) <- RPCServer.Command(api.DebuggerCommand{"name":"continue","ReturnInfoLoadConfig":null})
  2020-10-09T00:17:10-07:00 debug layer=debugger continuing
### Set breakpoint while target is running
  From client: setBreakpoints({"source":{"name":"foo.go","path":"/Users/polina/go/src/foo/foo.go"},"lines":[11],"breakpoints":[{"line":11}],"sourceModified":false})
  SetBreakPointsRequest
  2020-10-09T00:17:19-07:00 debug layer=rpc (async 4) <- RPCServer.State(rpc2.StateIn{"NonBlocking":true})
  2020-10-09T00:17:19-07:00 debug layer=rpc (async 4) -> rpc2.StateOut{"State":{"Running":true,"Recording":false,"Threads":null,"NextInProgress":false,"exited":false,"exitStatus":0,"When":""}} error: ""
### Set skipStopEventOnce=true, halt delve
  2020-10-09T00:17:19-07:00 debug layer=rpc (async 5) <- 
  RPCServer.Command(api.DebuggerCommand{"name":"halt","ReturnInfoLoadConfig":null})
  2020-10-09T00:17:19-07:00 debug layer=debugger halting
### Continue returns
  2020-10-09T00:17:19-07:00 debug layer=rpc (async 3) -> rpc2.CommandOut{"State":{"Running":false,…}} error: ""
### Halt returns
  2020-10-09T00:17:19-07:00 debug layer=rpc (async 5) -> rpc2.CommandOut{"State":{"Running":false,…}} error: ""
### Continue callback skips handleReenterDebug() because the stop is not due to breakpoint
### Halt callback calls setBreakPoints() 
  All cleared
  Creating on: /Users/polina/go/src/foo/foo.go:11
  2020-10-09T00:17:19-07:00 debug layer=rpc <- RPCServer.CreateBreakpoint(…)
  2020-10-09T00:17:19-07:00 debug layer=rpc -> *rpc2.CreateBreakpointOut{…} error: ""
  All set:[…]
  To client: {"seq":0,"type":"response","request_seq":5,"command":"setBreakpoints","success":true,"body":{"breakpoints":[{"verified":true,"line":11}]}}
  SetBreakPointsResponse
### Halt callback continues to return to running state
  2020-10-09T00:17:19-07:00 debug layer=rpc (async 7) <- RPCServer.Command(api.DebuggerCommand{"name":"continue","ReturnInfoLoadConfig":null})
  2020-10-09T00:17:19-07:00 debug layer=debugger continuing
### Program stops at the breakpoint we set
  2020-10-09T00:17:20-07:00 debug layer=rpc (async 7) -> rpc2.CommandOut{"State":{"Running":false,…} error:””
### Continue callback calls handleReenterDebug(“breakpoint”)
  2020-10-09T00:17:20-07:00 debug layer=rpc <- RPCServer.ListGoroutines(rpc2.ListGoroutinesIn{"Start":0,"Count":1})
  2020-10-09T00:17:20-07:00 debug layer=rpc -> *rpc2.ListGoroutinesOut{…} error: ""
### skipStopEventOnce is still false
### No stop event is sent and no requests get issued for threads, stackTrace, scopes and variables
### UI does not enable Continue button
@polinasok polinasok added the Debug Issues related to the debugging functionality of the extension. label Oct 9, 2020
@gopherbot
Copy link
Collaborator

Change https://golang.org/cl/261078 mentions this issue: src/debugAdapter: remove skipStopEventOnce logic

@hyangah hyangah added the release-blocker must be fixed before the next release. label Oct 12, 2020
@gopherbot
Copy link
Collaborator

Change https://golang.org/cl/262257 mentions this issue: src/debugAdapter: revert cl/253578

gopherbot pushed a commit that referenced this issue Oct 14, 2020
There were some issues caused by not sending a stopped event to
the client every time that the continue callback was called. This
change reverts the logic to skip calling handleReenterDebug in
order to get back to a state where the debugger issues stopped events
every time. This should fix issues with the debugger appearing to
be running when it is stopped.

Updates #149, #172, and #759

Change-Id: I70aae05bc3bf50499b046594a43d972ec01091cf
Reviewed-on: https://go-review.googlesource.com/c/vscode-go/+/262257
Run-TryBot: Suzy Mueller <suzmue@golang.org>
TryBot-Result: kokoro <noreply+kokoro@google.com>
Trust: Suzy Mueller <suzmue@golang.org>
Trust: Hyang-Ah Hana Kim <hyangah@gmail.com>
Reviewed-by: Hyang-Ah Hana Kim <hyangah@gmail.com>
@polinasok
Copy link
Contributor Author

I believe this has been fixed by the CL that reverted the original change that caused this.
I verified and after setting a breakpoint at the sleep line, I see "Continue", call stack and variables when it is hit.

@golang golang locked and limited conversation to collaborators Dec 1, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Debug Issues related to the debugging functionality of the extension. FrozenDueToAge release-blocker must be fixed before the next release.
Projects
None yet
Development

No branches or pull requests

4 participants