Documentation: add DAP API page (#2856)

* Documentation: add DAP API page

* Respond to review feedback

* Clarify about Ctrl-C

* Add hidden TODO for more things to document

Co-authored-by: Polina Sokolova <polinasok@users.noreply.github.com>
This commit is contained in:
polinasok 2022-01-06 08:58:08 -08:00 committed by GitHub
parent 4c1f8b4b25
commit 7afe640773
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 123 additions and 6 deletions

@ -1,20 +1,20 @@
# API Documentation
# Server/Client API Documentation
Delve exposes an API interface so that other programs, mostly IDEs and editors, can interact with Delve programmatically. The API is used by the terminal client, so will always stay up to date in lockstep regardless of new features.
Delve exposes two API interfaces, JSON-RPC and DAP, so that frontends other than the built-in [terminal client](../cli/README.md), such as [IDEs and editors](../EditorIntegration.md), can interact with Delve programmatically. The [JSON-RPC API](json-rpc/README.md) is used by the [terminal client](../cli/README.md), and will always stay up to date in lockstep regardless of new features. The [DAP API](dap/README.md) is a popular generic API already in use by many [tools](https://microsoft.github.io/debug-adapter-protocol/implementors/tools/).
## Usage
In order to run Delve in "API mode", simply invoke with one of the standard commands, providing the `--headless` flag, like so:
```
$ dlv debug --headless --api-version=2 --log --listen=127.0.0.1:8181
$ dlv debug --headless --api-version=2 --log --log-output=debugger,dap,rpc --listen=127.0.0.1:8181
```
This will start the debugger in a non-interactive mode, listening on the specified address, and will enable logging. The last two flags are optional, of course.
This will start the debugger in a non-interactive mode, listening on the specified address, and will enable logging. The logging flags as well as the server address are optional, of course.
Optionally, you may also specify the `--accept-multiclient` flag if you would like to connect multiple clients to the API.
Optionally, you may also specify the `--accept-multiclient` flag if you would like to connect multiple JSON-RPC or DAP clients to the API.
You can connect the headless debugger from Delve itself using the `connect` subcommand:
You can connect to the headless debugger from Delve itself using the `connect` subcommand:
```
$ dlv connect 127.0.0.1:8181
@ -29,3 +29,4 @@ Delve has been architected in such a way as to allow multiple client/server impl
### Current API Interfaces
- [JSON-RPC](json-rpc/README.md)
- [DAP](dap/README.md)

@ -0,0 +1,116 @@
# DAP Interface
Delve exposes a [DAP](https://microsoft.github.io/debug-adapter-protocol/overview) API interface.
This interface is served over a streaming TCP socket using `dlv` server in one of the two headless modes:
* `dlv dap` - starts a single-use DAP-only server that waits for a client to specify launch/attach configuration for starting the debug session.
* `dlv --headless <command> <debugee>` - starts a general server, enters a debug session for the specified debuggee and waits for a [JSON-RPC](../json-rpc/README.md) or a [DAP](https://microsoft.github.io/debug-adapter-protocol/overview) client to begin interactive debugging. Can be used in multi-client mode with the following options:
* `--accept-multiclient` - use to support connections from multiple clients
* `--continue` - use to resume debuggee execution as soon as server session starts
The primary user of this mode is [VS Code Go](https://github.com/golang/vscode-go). Please see its
detailed [debugging documentation](https://github.com/golang/vscode-go/blob/master/docs/debugging.md) for additional information.
## Debug Adapter Protocol
[DAP](https://microsoft.github.io/debug-adapter-protocol/specification) is a general debugging protocol supported by many [tools](https://microsoft.github.io/debug-adapter-protocol/implementors/tools/) and [programming languages](https://microsoft.github.io/debug-adapter-protocol/implementors/adapters/). We tailored it to Go specifics, such as mapping [threads request](https://microsoft.github.io/debug-adapter-protocol/specification#Requests_Threads) to communicate goroutines and [exceptionInfo request](https://microsoft.github.io/debug-adapter-protocol/specification#Requests_ExceptionInfo) to support panics and fatal errors.
See [dap.Server.handleRequest](https://github.com/go-delve/delve/search?q=handleRequest) and capabilities set in [dap.Server.onInitializeRequest](https://github.com/go-delve/delve/search?q=onInitializeRequest) for an up-to-date list of supported requests and options.
## Launch and Attach Configurations
In addition to the general [DAP spec](https://microsoft.github.io/debug-adapter-protocol/specification), the server supports the following implementation-specific configuration options for starting the debug session:
* [AttachRequestArguments](https://microsoft.github.io/debug-adapter-protocol/specification#Requests_Attach) - see [AttachConfig godoc](https://pkg.go.dev/github.com/go-delve/delve/service/dap#AttachConfig)
* [LaunchRequestArguments](https://microsoft.github.io/debug-adapter-protocol/specification#Requests_Launch) - see [LaunchConfig godoc](https://pkg.go.dev/github.com/go-delve/delve/service/dap#LaunchConfig)
Not all of the configurations are supported by each of the two available DAP servers:
<table border=1>
<tr>
<th>request<th>"mode":<th>`dlv dap`<th>`dlv --headless`
</tr>
<tr>
<td>launch<td>"debug"<br>"test"<br>"exec"<br>...<td>supported<td>NOT supported
<tr>
<td>attach<td>"local"<td>supported<td>NOT supported
</tr>
<tr>
<td>attach<td>"remote"<td>NOT supported<td>supported
</tr>
</table>
## Disconnect and Shutdown
### Single-Client Mode
When used with `dlv dap` or `dlv --headless --accept-multiclient=false` (default), the DAP server will shut itself down at the end of the debug session, when the client sends a [disconnect request](https://microsoft.github.io/debug-adapter-protocol/specification#Requests_Disconnect). If the debuggee was launched, it will be taken down as well. If the debugee was attached to, `terminateDebuggee` option will be respected.
When the program terminates, we send a [terminated event](https://microsoft.github.io/debug-adapter-protocol/specification#Events_Terminated), which is expected to trigger a [disconnect request](https://microsoft.github.io/debug-adapter-protocol/specification#Requests_Disconnect) from the client for a session and a server shutdown. The [restart request](https://microsoft.github.io/debug-adapter-protocol/specification#Requests_Restart) is not yet supported.
The server also shuts down in case of a client connection error or SIGTERM signal, taking down a launched process, but letting an attached process continue.
Pressing Ctrl-C on the terminal where a headless server is running sends SIGINT to the debuggee, foregrounded in headless mode to support debugging interactive programs.
### Multi-Client Mode
When used with `dlv --headless --accept-multiclient=true`, the DAP server will honor the multi-client mode when a client [disconnects](https://microsoft.github.io/debug-adapter-protocol/specification#Requests_Disconnect)) or client connection fails. The server will remain running and ready for a new client connection, and the debuggee will remain in whatever state it was at the time of disconnect - running or halted. Once [`suspendDebuggee`](https://microsoft.github.io/debug-adapter-protocol/specification#Requests_Disconnect) option is supported by frontends like VS Code ([vscode/issues/134412](https://github.com/microsoft/vscode/issues/134412)), we will update the server to offer this as a way to specify debuggee state on disconnect.
The client may request full shutdown of the server and the debuggee with [`terminateDebuggee`](https://microsoft.github.io/debug-adapter-protocol/specification#Requests_Disconnect) option.
The server shuts down in response to a SIGTERM signal, taking down a launched process, but letting an attached process continue.
Pressing Ctrl-C on the terminal where a headless server is running sends SIGINT to the debuggee, foregrounded in headless mode to support debugging interactive programs.
## Debugger Output
The debugger always logs one of the following on start-up to stdout:
* `dlv dap`:
* `DAP server listening at: <host>:<port>`
* `dlv --headless`:
* `API server listening at: <host>:<port>`
This can be used to confirm that server start-up succeeded.
The server uses [output events](https://microsoft.github.io/debug-adapter-protocol/specification#Events_Output) to communicate errors and select status messages to the client. For example:
```
Step interrupted by a breakpoint. Use 'Continue' to resume the original step command.
invalid command: Unable to step while the previous step is interrupted by a breakpoint.
Use 'Continue' to resume the original step command.
Detaching and terminating target process
```
More detailed logging can be enabled with `--log --log-output=dap` as part of the [`dlv` command](../../usage/dlv.md).
It will record the server-side DAP message traffic. For example,
```
2022-01-04T00:27:57-08:00 debug layer=dap [<- from client]{"seq":1,"type":"request","command":"initialize","arguments":{"clientID":"vscode","clientName":"Visual Studio Code","adapterID":"go","locale":"en-us","linesStartAt1":true,"columnsStartAt1":true,"pathFormat":"path","supportsVariableType":true,"supportsVariablePaging":true,"supportsRunInTerminalRequest":true,"supportsMemoryReferences":true,"supportsProgressReporting":true,"supportsInvalidatedEvent":true}}
2022-01-04T00:27:57-08:00 debug layer=dap [-> to client]{"seq":0,"type":"response","request_seq":1,"success":true,"command":"initialize","body":{"supportsConfigurationDoneRequest":true,"supportsFunctionBreakpoints":true,"supportsConditionalBreakpoints":true,"supportsEvaluateForHovers":true,"supportsSetVariable":true,"supportsExceptionInfoRequest":true,"supportTerminateDebuggee":true,"supportsDelayedStackTraceLoading":true,"supportsLogPoints":true,"supportsDisassembleRequest":true,"supportsClipboardContext":true,"supportsSteppingGranularity":true,"supportsInstructionBreakpoints":true}}
2022-01-04T00:27:57-08:00 debug layer=dap [<- from client]{"seq":2,"type":"request","command":"launch","arguments":{"name":"Launch file","type":"go","request":"launch","mode":"debug","program":"./temp.go","hideSystemGoroutines":true,"__buildDir":"/Users/polina/go/src","__sessionId":"2ad0f0c1-a1fd-4fff-9fff-b8bc9a933fe5"}}
2022-01-04T00:27:57-08:00 debug layer=dap parsed launch config: {
"mode": "debug",
"program": "./temp.go",
"backend": "default",
"stackTraceDepth": 50,
"hideSystemGoroutines": true
}
...
```
This logging is written to stderr and is not forwarded via
[output events](https://microsoft.github.io/debug-adapter-protocol/specification#Events_Output).
## Debuggee Output
Debuggee's stdout and stderr are written to stdout and stderr respectfully and are not forwarded via
[output events](https://microsoft.github.io/debug-adapter-protocol/specification#Events_Output).
## Versions
The initial DAP support was released in v1.6.1 with many additional improvements in subsequent versions. The [remote attach](https://github.com/go-delve/delve/issues/2328) support was added in v1.7.3.
The DAP API changes are backward-compatible as all new features are opt-in only. To update to a new [DAP version](https://microsoft.github.io/debug-adapter-protocol/changelog) and import a new DAP feature into delve,
one must first update the [go-dap](https://github.com/google/go-dap) dependency.
<!--- TODO:
- most requests are handled synchronously and block
- hence many commands not supported when running, but setting breakpoints is
--->