Closed
Description
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
- Program
func main() {
for i := 0; true; i++ {
fmt.Println("===== i", i)
time.Sleep(2 * time.Second) // set breakpoint here while running
}
}
Launch.json
"request": "launch",
"mode": "auto",
"stopOnEntry": false,
- Start the debug session (do NOT set any breakpoints in advance)
- While the program is running, click to set a breakpoint in the middle of the loop
- The program will continue to this breakpoint, but a stopped event will not be sent
- 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