-
Notifications
You must be signed in to change notification settings - Fork 2.1k
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: supports noDebug launch requests #2400
Conversation
baf719f
to
b421d7f
Compare
Finally, all checks have passed. |
Can you bring some context here as to the motivation behind this change? I'm unsure of why we would want Delve to handle simple process creation without debugging that process at all. |
@derekparker This is a strange side of DAP spec. :-( https://microsoft.github.io/debug-adapter-protocol/specification
|
@hyangah ack, thanks for the explanation! Can you please rebase this PR to solve the conflicts. |
If the launch requests has noDebug attribute set, run the built binary directly. The launch request handler will block until the binary terminates, so the editor won't send additional requests like breakpoint setting etc. Still disconnect or restart requests can flow in though and they should trigger killing of the target process if it's still running. In order to run the binary using os/exec on windows, the target binary has to have .exe as its extension. So, add .exe to the default output name if it is on windows. I am not sure though yet we want to modify the user-specified output or not yet. Considering how go commands behave (not automatically append .exe for 'go build -o') I think respecting what user specified is right, but the failure (file not exist) may be mysterious.
@derekparker Thanks. Rebased. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
If the launch requests has noDebug attribute set, run the built binary directly. The launch request handler will block until the binary terminates, so the editor won't send additional requests like breakpoint setting etc. Still disconnect or restart requests can flow in though and they should trigger killing of the target process if it's still running. In order to run the binary using os/exec on windows, the target binary has to have .exe as its extension. So, add .exe to the default output name if it is on windows. I am not sure though yet we want to modify the user-specified output or not yet. Considering how go commands behave (not automatically append .exe for 'go build -o') I think respecting what user specified is right, but the failure (file not exist) may be mysterious.
PR go-delve#2400 added support for noDebug launch requests - that was done by directly starting the target program using os/exec.Cmd and blocking the launch request indefinitely until the program terminates or is stopped with a disconnect request (when dlv dap can support it). Even though the approach seemed to work for user, that adds an extra control flow and complexity to the codebase. This change takes a different approach to implement the noDebug launch feature. Instead of using os/exec.Cmd, this uses the existing debug launch path, but avoids setting breakpoints. Finally, the program will start upon receiving onConfigurationDoneRequest and blocks there until the program terminates. This simplifies the code. The DAP spec does not explicitly specify what to do about other requests. It seems like VSCode can issue evaluate requests or other requests after the configuration done request. Currently they are blocked because the program is in running state. We can consider checking s.noDebug and responding with an error in the future if we want/need to. See the log below for a typical DAP request/response sequence: 2021-03-29T01:42:53-04:00 debug layer=dap building binary at /Users/hakim/projects/s/__debug_bin 2021-03-29T01:42:55-04:00 info layer=debugger launching process with args: [/Users/hakim/projects/s/__debug_bin] 2021-03-29T01:42:55-04:00 debug layer=dap [-> to client]{"seq":0,"type":"event","event":"initialized"} 2021-03-29T01:42:55-04:00 debug layer=dap [-> to client]{"seq":0,"type":"response","request_seq":2,"success":true,"command":"launch"} 2021-03-29T01:42:55-04:00 debug layer=dap [<- from client]{"seq":3,"type":"request","command":"setBreakpoints","arguments":{"source":{"name":"main.go","path":"/Users/hakim/projects/s/main.go"},"breakpoints":[{"line":9}],"lines":[9]}} 2021-03-29T01:42:55-04:00 error layer=dap Unable to set or clear breakpoints: running in noDebug mode 2021-03-29T01:42:55-04:00 debug layer=dap [-> to client]{"seq":0,"type":"response","request_seq":3,"success":false,"command":"setBreakpoints","message":"Unable to set or clear breakpoints","body":{"error":{"id":2002,"format":"Unable to set or clear breakpoints: running in noDebug mode"}}} 2021-03-29T01:42:55-04:00 debug layer=dap [<- from client]{"seq":4,"type":"request","command":"configurationDone","arguments":{}} 2021-03-29T01:42:55-04:00 debug layer=dap [-> to client]{"seq":0,"type":"response","request_seq":4,"success":true,"command":"configurationDone"} 2021-03-29T01:42:55-04:00 debug layer=debugger continuing Hello 2021-03-29T01:43:00-04:00 debug layer=dap [-> to client]{"seq":0,"type":"event","event":"terminated","body":{}} 2021-03-29T01:43:00-04:00 debug layer=dap [<- from client]{"seq":5,"type":"request","command":"threads"} 2021-03-29T01:43:00-04:00 debug layer=dap [-> to client]{"seq":0,"type":"response","request_seq":5,"success":true,"command":"threads","body":{"threads":null}} 2021-03-29T01:43:00-04:00 debug layer=dap [<- from client]{"seq":6,"type":"request","command":"disconnect","arguments":{}} 2021-03-29T01:43:00-04:00 debug layer=dap [-> to client]{"seq":0,"type":"response","request_seq":6,"success":true,"command":"disconnect"} 2021-03-29T01:43:00-04:00 debug layer=debugger halting 2021-03-29T01:43:00-04:00 error layer=dap Process 27219 has exited with status 0 2021-03-29T01:43:00-04:00 debug layer=debugger detaching Updates golang/vscode-go#1111
PR go-delve#2400 added support for noDebug launch requests - that was done by directly starting the target program using os/exec.Cmd and blocking the launch request indefinitely until the program terminates or is stopped with a disconnect request (when dlv dap can support it). Even though the approach seemed to work for user, that adds an extra control flow and complexity to the codebase. This change takes a different approach to implement the noDebug launch feature. Instead of using os/exec.Cmd, this uses the existing debug launch path, but avoids setting breakpoints. Finally, the program will start upon receiving onConfigurationDoneRequest and blocks there until the program terminates. This simplifies the code. The DAP spec does not explicitly specify what to do about other requests. It seems like VSCode can issue evaluate requests or other requests after the configuration done request. Currently they are blocked because the program is in running state. We can consider checking s.noDebug and responding with an error in the future if we want/need to. See the log below for a typical DAP request/response sequence: 2021-03-29T01:42:53-04:00 debug layer=dap building binary at /Users/hakim/projects/s/__debug_bin 2021-03-29T01:42:55-04:00 info layer=debugger launching process with args: [/Users/hakim/projects/s/__debug_bin] 2021-03-29T01:42:55-04:00 debug layer=dap [-> to client]{"seq":0,"type":"event","event":"initialized"} 2021-03-29T01:42:55-04:00 debug layer=dap [-> to client]{"seq":0,"type":"response","request_seq":2,"success":true,"command":"launch"} 2021-03-29T01:42:55-04:00 debug layer=dap [<- from client]{"seq":3,"type":"request","command":"setBreakpoints","arguments":{"source":{"name":"main.go","path":"/Users/hakim/projects/s/main.go"},"breakpoints":[{"line":9}],"lines":[9]}} 2021-03-29T01:42:55-04:00 error layer=dap Unable to set or clear breakpoints: running in noDebug mode 2021-03-29T01:42:55-04:00 debug layer=dap [-> to client]{"seq":0,"type":"response","request_seq":3,"success":false,"command":"setBreakpoints","message":"Unable to set or clear breakpoints","body":{"error":{"id":2002,"format":"Unable to set or clear breakpoints: running in noDebug mode"}}} 2021-03-29T01:42:55-04:00 debug layer=dap [<- from client]{"seq":4,"type":"request","command":"configurationDone","arguments":{}} 2021-03-29T01:42:55-04:00 debug layer=dap [-> to client]{"seq":0,"type":"response","request_seq":4,"success":true,"command":"configurationDone"} 2021-03-29T01:42:55-04:00 debug layer=debugger continuing Hello 2021-03-29T01:43:00-04:00 debug layer=dap [-> to client]{"seq":0,"type":"event","event":"terminated","body":{}} 2021-03-29T01:43:00-04:00 debug layer=dap [<- from client]{"seq":5,"type":"request","command":"threads"} 2021-03-29T01:43:00-04:00 debug layer=dap [-> to client]{"seq":0,"type":"response","request_seq":5,"success":true,"command":"threads","body":{"threads":null}} 2021-03-29T01:43:00-04:00 debug layer=dap [<- from client]{"seq":6,"type":"request","command":"disconnect","arguments":{}} 2021-03-29T01:43:00-04:00 debug layer=dap [-> to client]{"seq":0,"type":"response","request_seq":6,"success":true,"command":"disconnect"} 2021-03-29T01:43:00-04:00 debug layer=debugger halting 2021-03-29T01:43:00-04:00 error layer=dap Process 27219 has exited with status 0 2021-03-29T01:43:00-04:00 debug layer=debugger detaching Updates golang/vscode-go#1111
PR go-delve#2400 added support for noDebug launch requests - that was done by directly starting the target program using os/exec.Cmd and blocking the launch request indefinitely until the program terminates or is stopped with a disconnect request (when dlv dap can support it). Even though the approach seemed to work for user, that adds an extra control flow and complexity to the codebase. This change takes a different approach to implement the noDebug launch feature. Instead of using os/exec.Cmd, this uses the existing debug launch path, but avoids setting breakpoints. Finally, the program will start upon receiving onConfigurationDoneRequest and blocks there until the program terminates. This simplifies the code. The DAP spec does not explicitly specify what to do about other requests. It seems like VSCode can issue evaluate requests or other requests after the configuration done request. Currently they are blocked because the program is in running state. We can consider checking s.noDebug and responding with an error in the future if we want/need to. See the log below for a typical DAP request/response sequence: 2021-03-29T01:42:53-04:00 debug layer=dap building binary at /Users/hakim/projects/s/__debug_bin 2021-03-29T01:42:55-04:00 info layer=debugger launching process with args: [/Users/hakim/projects/s/__debug_bin] 2021-03-29T01:42:55-04:00 debug layer=dap [-> to client]{"seq":0,"type":"event","event":"initialized"} 2021-03-29T01:42:55-04:00 debug layer=dap [-> to client]{"seq":0,"type":"response","request_seq":2,"success":true,"command":"launch"} 2021-03-29T01:42:55-04:00 debug layer=dap [<- from client]{"seq":3,"type":"request","command":"setBreakpoints","arguments":{"source":{"name":"main.go","path":"/Users/hakim/projects/s/main.go"},"breakpoints":[{"line":9}],"lines":[9]}} 2021-03-29T01:42:55-04:00 error layer=dap Unable to set or clear breakpoints: running in noDebug mode 2021-03-29T01:42:55-04:00 debug layer=dap [-> to client]{"seq":0,"type":"response","request_seq":3,"success":false,"command":"setBreakpoints","message":"Unable to set or clear breakpoints","body":{"error":{"id":2002,"format":"Unable to set or clear breakpoints: running in noDebug mode"}}} 2021-03-29T01:42:55-04:00 debug layer=dap [<- from client]{"seq":4,"type":"request","command":"configurationDone","arguments":{}} 2021-03-29T01:42:55-04:00 debug layer=dap [-> to client]{"seq":0,"type":"response","request_seq":4,"success":true,"command":"configurationDone"} 2021-03-29T01:42:55-04:00 debug layer=debugger continuing Hello 2021-03-29T01:43:00-04:00 debug layer=dap [-> to client]{"seq":0,"type":"event","event":"terminated","body":{}} 2021-03-29T01:43:00-04:00 debug layer=dap [<- from client]{"seq":5,"type":"request","command":"threads"} 2021-03-29T01:43:00-04:00 debug layer=dap [-> to client]{"seq":0,"type":"response","request_seq":5,"success":true,"command":"threads","body":{"threads":null}} 2021-03-29T01:43:00-04:00 debug layer=dap [<- from client]{"seq":6,"type":"request","command":"disconnect","arguments":{}} 2021-03-29T01:43:00-04:00 debug layer=dap [-> to client]{"seq":0,"type":"response","request_seq":6,"success":true,"command":"disconnect"} 2021-03-29T01:43:00-04:00 debug layer=debugger halting 2021-03-29T01:43:00-04:00 error layer=dap Process 27219 has exited with status 0 2021-03-29T01:43:00-04:00 debug layer=debugger detaching Updates golang/vscode-go#1111
* dap: change how noDebug launch request is served PR #2400 added support for noDebug launch requests - that was done by directly starting the target program using os/exec.Cmd and blocking the launch request indefinitely until the program terminates or is stopped with a disconnect request (when dlv dap can support it). Even though the approach seemed to work for user, that adds an extra control flow and complexity to the codebase. This change takes a different approach to implement the noDebug launch feature. Instead of using os/exec.Cmd, this uses the existing debug launch path, but avoids setting breakpoints. Finally, the program will start upon receiving onConfigurationDoneRequest and blocks there until the program terminates. This simplifies the code. The DAP spec does not explicitly specify what to do about other requests. It seems like VSCode can issue evaluate requests or other requests after the configuration done request. Currently they are blocked because the program is in running state. We can consider checking s.noDebug and responding with an error in the future if we want/need to. See the log below for a typical DAP request/response sequence: 2021-03-29T01:42:53-04:00 debug layer=dap building binary at /Users/hakim/projects/s/__debug_bin 2021-03-29T01:42:55-04:00 info layer=debugger launching process with args: [/Users/hakim/projects/s/__debug_bin] 2021-03-29T01:42:55-04:00 debug layer=dap [-> to client]{"seq":0,"type":"event","event":"initialized"} 2021-03-29T01:42:55-04:00 debug layer=dap [-> to client]{"seq":0,"type":"response","request_seq":2,"success":true,"command":"launch"} 2021-03-29T01:42:55-04:00 debug layer=dap [<- from client]{"seq":3,"type":"request","command":"setBreakpoints","arguments":{"source":{"name":"main.go","path":"/Users/hakim/projects/s/main.go"},"breakpoints":[{"line":9}],"lines":[9]}} 2021-03-29T01:42:55-04:00 error layer=dap Unable to set or clear breakpoints: running in noDebug mode 2021-03-29T01:42:55-04:00 debug layer=dap [-> to client]{"seq":0,"type":"response","request_seq":3,"success":false,"command":"setBreakpoints","message":"Unable to set or clear breakpoints","body":{"error":{"id":2002,"format":"Unable to set or clear breakpoints: running in noDebug mode"}}} 2021-03-29T01:42:55-04:00 debug layer=dap [<- from client]{"seq":4,"type":"request","command":"configurationDone","arguments":{}} 2021-03-29T01:42:55-04:00 debug layer=dap [-> to client]{"seq":0,"type":"response","request_seq":4,"success":true,"command":"configurationDone"} 2021-03-29T01:42:55-04:00 debug layer=debugger continuing Hello 2021-03-29T01:43:00-04:00 debug layer=dap [-> to client]{"seq":0,"type":"event","event":"terminated","body":{}} 2021-03-29T01:43:00-04:00 debug layer=dap [<- from client]{"seq":5,"type":"request","command":"threads"} 2021-03-29T01:43:00-04:00 debug layer=dap [-> to client]{"seq":0,"type":"response","request_seq":5,"success":true,"command":"threads","body":{"threads":null}} 2021-03-29T01:43:00-04:00 debug layer=dap [<- from client]{"seq":6,"type":"request","command":"disconnect","arguments":{}} 2021-03-29T01:43:00-04:00 debug layer=dap [-> to client]{"seq":0,"type":"response","request_seq":6,"success":true,"command":"disconnect"} 2021-03-29T01:43:00-04:00 debug layer=debugger halting 2021-03-29T01:43:00-04:00 error layer=dap Process 27219 has exited with status 0 2021-03-29T01:43:00-04:00 debug layer=debugger detaching Updates golang/vscode-go#1111 * service/dap: address polina's comments for noDebug logic Reworked so the noDebug launch request again blocks launch request handler after responding with the launch response. By skipping the initialized event, it should prevent well-behaving clients from sending any further requests. Currently, doesn't matter because the handler goroutine will be blocked until the program termination anyway. Placed mutex back, since I noticed that's the only way to prevent racing between Stop and the handler goroutine. The synchronization lotic (in particular, during teardown) should be revisited after asynchronous request support work is done. * dap: address more comments
Following the DAP spec
https://microsoft.github.io/debug-adapter-protocol/specification
Launch Request
This launch request is sent from the client to the debug adapter to
start the debuggee with or without debugging (if ‘noDebug’ is true).
This is admittedly strange to be implemented inside delve (debugger),
but implementing this outside
dlv dap
(from the editor plugin side)implies the need for another DAP layer, which isn't desirable either.
If the launch requests has noDebug attribute set, run the built
binary directly. The launch request handler will block until
the binary terminates, so the editor won't send additional requests
like breakpoint setting etc. Still disconnect or restart requests
can flow in though and they should trigger killing of the target
process if it's still running.
In order to run the binary using os/exec on windows, the target
binary has to have .exe as its extension. So, add .exe to the default
output name if it is on windows. I am not sure though yet we want
to modify the user-specified output or not yet. Considering how
go commands behave (not automatically append .exe for 'go build -o')
I think respecting what user specified is right, but the failure
(file not exist) may be mysterious.