vscpde The Go extension allows you to launch or attach to Go programs for debugging. You can inspect variables and stacks, setting breakpoints, and do other debugging activities using VS Code’s Debugging UI.
These debugging features are possible by using Delve, the Go debugger.
The Go extension has been communicating with Delve through a custom debug adapter program (legacy
mode).
As the new Delve
's native DAP implementation becomes available,
the Go extension is transitioning to skip the legacy debug adapter and directly communicate with Delve for local debugging.
Delve DAP implementation's s klss support for remote debugging is still a work in progress and the Go extension still uses
the legacy debug adapter for the debug configuration with the "remote"
mode.
Many features and settings described in this document may be available only with the new dlv-dap
mode.
For troubleshooting and configuring the legacy debug adapter, see the legacy debug adapter documentation.
Open a file to debug (either package main
source file or the test file) in the editor, and select the Run and Debug
button from the Run view. Alternatively, you can start debugging using Start Debugging (F5)
command from the Run menu or from the Command Palette (Linux/Windows: Ctrl+Shift+P, Mac: ⇧+⌘+P).
When no configuration is configured yet (no .vscode/launch.json
file), the extension will choose a default configuration based on the file open in the editor.
If you already have launch configurations for the project (.vscode/launch.json
), the Run view will display the configuration list to choose from.
❗ When you start debugging in `dlv-dap` mode for the first time, the extension will ask to install Delve built from head (`dlv-dap`). Please follow the instructions to install, and then start the debugging session again (i.e. selecting the source file, pressing F5 or click the codelens).
Watch "Go: Writing and debugging fast, reliable, and efficient software" to learn more about debugging features.
Please review the Features section that provides an overview of the debug UI and available features.
Delve’s native DAP implementation is under active development, so take advantage of the most recent features and bug fixes by using Delve built from its master branch. The Go extension maintains this newest version of Delve separately from the officially released version of dlv
and installs it with the name dlv-dap
.
The easiest way to update dlv-dap
on demand is to use the "Go: Install/Update Tools"
command from the Command Palette (Linux/Windows: Ctrl+Shift+P, Mac: ⇧+⌘+P). The command will show dlv-dap
in the tool list. Select dlv-dap
, and the extension will build the tool at master.
Once dlv-dap
is installed on your system, the extension will prompt you for update whenever installing a newer version is necessary (usually after the Go extension upgrade). You can set the go.toolsManagement.autoUpdate
setting so the extension can update dlv-dap
automatically for you.
If you need to install dlv-dap
manually outside of VS Code (for example, you are building a dev container with necessary tools preinstalled), please see the Manual Installation section.
If you need to use the legacy debug adapter (legacy
mode) by default,
add the following in your VSCode settings.
Note that the extension still uses the legacy debug adapter for remote debugging.
"go.delveConfig": {
"debugAdapter": "legacy",
}
If you want to switch to legacy
for only a subset of your launch configurations, you can use the debugAdapter
attribute to switch between "dlv-dap"
and "legacy"
mode.
If you chose to switch to legacy because of bugs in the new debug adapter, please open an issue to help us improve the new debug adapter.
For general debugging features such as inspecting variables, setting breakpoints, and other activities that aren't language-dependent, review VS Code debugging.
When you need more than the default debugging setup, you can create a launch configuration file for the project by clicking the "create a launch.json file" link in the Run view. Then, choose from the debug configuration drop-down menu. VS Code will create a launch.json
file in a .vscode folder in your workspace (project root folder) or in your user settings or workspace settings.
If you already have a launch.json
for your project, you can open it using Open launch.json
.
To add a new configuration to an existing launch.json
, choose the "Add Configuration…" button to invoke the snippet IntelliSense.
There are many configuration attributes (see the Launch.json attributes section). IntelliSense in VS Code’s launch.json editor will help you navigate available options and documentation.
You can choose "Start Debugging (F5)" and "Run Without Debugging (^F5)" a.k.a the noDebug
mode. This feature uses a launch
request type configuration. Its program
attribute needs to be either the go file or folder of the main package or test file. In this mode, the Go extension will start the debug session by building and launching the program. The launched program will be terminated when the debug session ends.
- Supported modes
debug
: build and debug a main packagetest
: build and debug a testexec
: debug a precompiled binary. The binary needs to be built with-gcflags=all="-N -l"
flags to avoid stripping debugging information.auto
: automatically choose betweendebug
andtest
depending on the open file.
You can debug an already running program using the attach
request type configuration. With the attach
request, the Go extension starts dlv-dap
and configures it to attach to the specified process. Users can select the process to debug with one of the following options:
- Specifying the numeric process id (PID) with the
processId
attribute. - Specifying the target program name in the
processId
attribute. If there are multiple processes matching the specified program name, the extension will show the list of matching processes at the start of the debug session. - Specifying
0
in theprocessId
attribute and selecting the process from the drop-down menu at the start of the debug session.
When you end the debug session, the debug UI allows you to choose to either
- Disconnect: detach and leave the process running. (default)
- Terminate: terminate the attached process.
Once a debug session starts, the Debug toolbar will appear on the top of the editor.
- Continue / Pause F5
- Step Over (aka
next
in Delve) F10 - Step Into (aka
step
in Delve) F11 - Step Out (aka
stepout
in Delve) Shift+F11 or ⇧F11 - Restart (currently this is "Stop + Start") Ctrl+Shift+F5 or ⇧⌘F5
- Stop (terminate the debugee. Available in Launch request) Shift+F5 or ⇧F5
- Disconnect (detach from the debugee. Available only in Attach request) Shift+F5 or ⇧F5
- Terminate (terminate the debugee. Available only in Attach request) Alt+Shift+F5 or ⌥⇧F5
See VS Code’s Debug Documentation on Breakpoints to get familiar with VS Code’s UI. The Go debugger supports multiple ways to configure breakpoints.
- Breakpoints: you can set breakpoints by clicking on the editor margin or using F9 on the current line. If the breakpoints can’t be set by Delve, VS Code will show the failure reason and grey out the dot.
- Conditional breakpoints: you can specify breakpoint conditions (similar to Delve’s
condition
command).- Expression condition: takes a boolean expression.
- Hit count: supports comparison operators (
>
,>=
,<
,<=
,==
,!=
) with an integer value.% n
form means we should stop at the breakpoint when the hitcount is a multiple ofn
.
- Function Breakpoints: breakpoints can be set based on function names. Press the + button in the BREAKPOINTS section header and enter the location in the form of
<function>[:<line>]
. This sets the breakpoint in theline
inside thefunction
. The full syntax forfunction
is<package>.(*<receiver type>).<function_name>
as specified in Delve’s location spec. Function breakpoints are shown with a red triangle in the BREAKPOINTS section.
- Logpoint (WIP)
You can inspect variables in the VARIABLES section of the Run view or by hovering over their source in the editor. Variable values and expression evaluation are relative to the selected stack frame in the CALL section.
By default, the VARIABLES section hides global variables, and shows only local variables and function arguments. However, you can still inspect global variables from the DEBUG CONSOLE panel. If you prefer to have the VARIABLES section show global variables, set the showGlobalVariables
attribute in the launch.json
configuration, or set it in the go.delveConfig
setting.
When you select a variable and right click from the VARIABLES section, the context menu will present shortcuts to features such as:
- Set Value: you can set/modify simple string, numeric, pointer values. Using composite literals, or memory allocation is not supported.
- Copy Value: this copies the value in clipboard.
- Copy as Expression: this is useful when you need to query from the REPL in the DEBUG CONSOLE panel.
- Add to Watch: this will automatically add the expression to the WATCH section.
Shadowed variables will be marked with ()
.
dlv-dap
mode uses a different approach. It takes advantage of the interactive UI features to provide on-demand loading of individual variables, paging of arrays, slices and maps and increased string limits depending on the context. We continue to explore additional interactive features to balance performance and usability of variable loading and look forward to your feedback.
You can inspect variables and evaluate expressions from the DEBUG CONSOLE panel too. Acceptable expressions are either
- A valid Delve expression, or
call <function_call_expression>
to call functions.
Variables and expressions accepted in DEBUG CONSOLE can be also registered in the Run view’s WATCH section, so they can be evaluated automatically as you debug. The "Add to Watch" feature from the VARIABLES section is convenient when you want to register interesting variables.
Hover over variables in editors during debugging shows the value of the variable. For this feature, VS Code extracts the variable expression and makes a request to the debugger to evaluate the expression. Delve evaluates the expression relative to the highlighted stack frame chosen in the CALL STACK. By default, that is the current top-most frame.
- VS Code heuristically determines the variable expression without full understanding of the scope & the currently selected frame. Delve tries to evaluate the provided expression in the selected frame. As a result, hover over variables outside the selected frame’s function may present incorrect information.
You can inspect all goroutines and their stacks in the CALL STACK section. The CALL STACK section UI allows switching between goroutines or selecting a different stack frame. As a different stack frame or different goroutine is selected, the scope shown in the VARIABLE section will be updated for the newly selected stack frame, and the expressions in the WATCH section will be automatically reevaluated relative to the newly selected stack frame.
- Goroutine stacks are annotated with their internal goroutine IDs.
- The current goroutine is marked with
*
. If multiple goroutines stop (e.g. hit breakpoints) concurrently, Delve will pick one randomly. There also might not be a current goroutine (e.g. deadlock, pause or internal breakpoint hit by a system thread not running a goroutine). - If you click a goroutine call stack from the CALL STACK section, the goroutine is selected.
- You can select a frame of the selected goroutine. The VARIABLE and WATCH sections will be updated accordingly and the cursor in the editor will be moved to the corresponding location in the source code.
- Runtime stack frames are deemphasized (greyed out or collapsed).
- Thread IDs are shown for scheduled goroutines.
- Stop reason. It’s possible that there are multiple reasons goroutines were stopped, but currently only one reason is presented.
- File name and line number of the frame.
- You can trigger a debug action with the selected goroutine. Note: Resuming or stopping only a single goroutine (Go Issue 25578, 31132) is currently not supported, so the action will cause all the goroutines to get activated or paused.
- Function name of the frame.
When the program stops due to exception, panic, or bad access error, the CALL STACK shows the stop reason and the editor highlights the source location with more details.
There are many attributes that you can adjust in the launch and attach debug configuration. The following general attributes are mandatory for all launch configurations.
name
: the name of your configuration as it appears in the drop-down in the Run view.type
: the debugging type VS Code uses to decide which debugging extension should be used. Always leave this set to"go"
.request
:launch
orattach
.
Here is the list of attributes specific to Go debugging.
Property | Launch | Attach |
---|---|---|
args |
Command line arguments passed to the debugged program. |
n/a |
backend |
Backend used by delve. Maps to dlv 's --backend flag.Allowed Values: |
same as Launch |
buildFlags |
Build flags, to be passed to the Go compiler. Maps to dlv's --build-flags flag.(Default: "" ) |
n/a |
coreFilePath |
Path to the core dump file to open. For use on 'core' mode only (Default: "" ) |
n/a |
cwd |
Workspace relative or absolute path to the working directory of the program being debugged if a non-empty value is specified. The program folder is used as the working directory if cwd is omitted or empty.(Default: "" ) |
Workspace relative or absolute path to the working directory of the program being debugged. Default is the current workspace. (Default: "${workspaceFolder}" ) |
debugAdapter |
Select which debug adapter to use with this launch configuration. Allowed Values: |
same as Launch |
dlvFlags |
Extra flags for dlv . See dlv help for the full list of supported. Flags such as --log-output , --log , --log-dest , --api-version , --output , --backend already have corresponding properties in the debug configuration, and flags such as --listen and --headless are used internally. If they are specified in dlvFlags , they may be ignored or cause an error. |
same as Launch |
env |
Environment variables passed to the program. |
n/a |
envFile |
Absolute path to a file containing environment variable definitions. Multiple files can be specified by provided an array of absolute paths (Default: ${workspaceFolder}/.env ) |
n/a |
host |
The host name of the machine the delve debugger will be listening on. (Default: "127.0.0.1" ) |
same as Launch |
logDest |
dlv's --log-dest flag. See dlv log for details. Number argument is not allowed. Supported only in dlv-dap mode, and on Linux and Mac OS. |
dlv's --log-dest flag. See dlv log for details. Number argument is not allowed. Supported only in dlv-dap mode and on Linux and Mac OS. |
logOutput |
Comma separated list of components that should produce debug output. Maps to dlv's --log-output flag. Check dlv log for details.Allowed Values: |
same as Launch |
mode |
One of auto , debug , test , exec , replay , core . In auto mode, the extension will choose either debug or test depending on active editor window.Allowed Values: |
Indicates local or remote debugging. Local maps to the dlv attach command, remote maps to connect . remote is not supported in dlv-dap mode currently. Use host and port instead.Allowed Values: |
output |
Output path for the binary of the debugee. (Default: "debug" ) |
n/a |
port |
The port that the delve debugger will be listening on. (Default: 2345 ) |
same as Launch |
processId |
n/a | Option 1: Use process picker to select a process to attach, or Process ID as integer. Allowed Values: Option 2: Attach to a process by name. If more than one process matches the name, use the process picker to select a process. Option 3: The numeric ID of the process to be debugged. If 0, use the process picker to select a process. |
program |
Path to the program folder (or any go file within that folder) when in debug or test mode, and to the pre-built binary file to debug in exec mode. If it is not an absolute path, the extension interpretes it as a workspace relative path.(Default: "${workspaceFolder}" ) |
n/a |
remotePath |
n/a | (Deprecated) Use substitutePath instead.The path to the source code on the remote machine, when the remote path is different from the local machine. If specified, becomes the first entry in substitutePath. (Default: "" ) |
showGlobalVariables |
Boolean value to indicate whether global package variables should be shown in the variables pane or not. (Default: false ) |
same as Launch |
showLog |
Show log output from the delve debugger. Maps to dlv's --log flag.(Default: false ) |
same as Launch |
stackTraceDepth |
Maximum depth of stack trace collected from Delve. (Default: 50 ) |
same as Launch |
stopOnEntry |
Automatically stop program after launch. (Default: false ) |
Automatically stop program after attach. (Default: false ) |
substitutePath |
An array of mappings from a local path (editor) to the remote path (debugee). This setting is useful when working in a file system with symbolic links, running remote debugging, or debugging an executable compiled externally. The debug adapter will replace the local path with the remote path in all of the calls.
|
An array of mappings from a local path (editor) to the remote path (debugee). This setting is useful when working in a file system with symbolic links, running remote debugging, or debugging an executable compiled externally. The debug adapter will replace the local path with the remote path in all of the calls. Overriden by remotePath .
|
trace |
Various levels of logging shown in the debug console & 'Go Debug' output channel. When using the legacy debug adapter, the logs will also be written to a file if it is set to a value other than error .Allowed Values: |
same as Launch |
traceDirPath |
Directory in which the record trace is located or to be created for a new output trace. For use on 'replay' mode only (Default: "" ) |
n/a |
dlv-dap
needs file or directory values in the launch configuration to be absolute paths. When configuring those values, use the VS Code variables substitution - VS Code will resolve the variables inside strings in launch.json
before passing the configuration to the Go extension and dlv-dap
. For example, ${workspaceFolder}
will be replaced with the absolute path to the workspace root folder. When appropriate, the Go extension will resolve relative paths or home directory (~) before sending the configuration to dlv-dap
.
Since the debugger and go compiler use the actual filenames, extra configuration is required to debug symlinked directories. Use the substitutePath property to tell the debugAdapter
how to properly translate the paths. For example, if your project lives in /path/to/actual/helloWorld
, but the project is open in vscode under the linked folder /path/to/hello
, you can add the following to your config to set breakpoints in the files in /path/to/hello
:
{
"name": "Launch remote",
"type": "go",
"request": "launch",
"mode": "debug",
"program": "/path/to/actual/helloWorld",
"substitutePath": [
{
"from": "/path/to/hello",
"to": "/path/to/actual/helloWorld",
},
],
}
You can adjust the default value of the following configuration properties using go.delveConfig
settings. These default values are useful when you choose to run a debug session without the launch configuration set in launch.json
. For example, debug sessions started using the Debug Test
code lenses use the adjusted values from these settings.
go.delveConfig
debugAdapter
: Controls which debug adapter to use (default:legacy
). Select ‘dlv-dap’.showGlobalVariables
: Show global variables in the Debug view (default:false
).substitutePath
: Path mappings to apply to get from a path in the editor to a path in the compiled program (default:[]
).
dlvLoadConfig
setting? Delve debugger imposes variable loading limits to avoid loading too many variables at once and negatively impacting debugging latency. The legacy adapter supported dlvLoadConfig
to adjust these limits for the duration of the session. The user therefore had to come up with a one-size-fits-all limit if the default behavior was not satisfactory. dlv-dap
mode uses a different approach as described in the Data Inspection section. If this setting is configured and dlv-dap
mode is used, the extension will show a warning prompt now. If the current variable loading behavior and internal limits are not working for you, please open an issue and share your feedback.
VS Code implements a generic, language-agnostic debugger UI based on Debug Adapter Protocol (DAP), an abstract protocol for communicating with debugger backend. Previously, the Go extension used an intermediary typescript program (legacy debug adapter) to launch Delve and adapt Delve to DAP. With the new, native DAP implementation in Delve, the intermediary program is no longer necessary, and efficient and tight integration with Delve becomes possible.
For information on debugging using the legacy debug adapter, please see the old Debugging Documentation. Note that many new or enhanced features discussed in this document may not be available with the legacy debug adapter.
On rare occasions, you may want to install dlv-dap
by yourself instead of letting the extension handle its installation.
First, find where the Go extension finds tools. Like other tools the extension uses, the Go extension searches the dlv-dap
executable from ${GOPATH}/bin
, ${GOBIN}
and ${PATH}
(or Path
in Windows). So, install dlv-dap
in the directory. The easiest way to check the tool installation location the Go extension uses is currently by running the Go: Locate Configured Go Tools
command from the command palette (⇧+⌘+P or Ctrl+Shift+P).
The following commands download the source of Delve from the master branch, build & store as dlv-dap
in ~/go/bin/
directory assuming the directory is the place you found from the first step.
If your Go version is 1.16 or newer:
$ GOBIN=/tmp/ go install github.com/go-delve/delve/cmd/dlv@master
$ mv /tmp/dlv $GOPATH/bin/dlv-dap
If your Go version is older than 1.16:
$ cd $(mktemp -d)
$ GO111MODULE=on GOBIN=/tmp/ go get github.com/go-delve/delve/cmd/dlv@master
$ mv /tmp/dlv $GOPATH/bin/dlv-dap
If you want to explicitly specify the location of the delve binary, use the go.alternateTools
setting:
"go.alternateTools": {
"dlv-dap": "<absolute path to your dlv binary>"
}
If you are able to use the Remote Development extensions and VS Code’s universal remote development capabilities, that is the recommended way to debug Go programs remotely. Check out Getting started section and Remote tutorials to learn more.
🚧 Remote debugging is the debug mode intended to work with a debugger and target running on a different machine or a container. Support for remote debugging using Delve’s native DAP implementation is still a work-in-progress. Please fall back to the legacy
debug adapter.
Sometimes you’d like to launch the program for debugging outside VS Code (e.g., as a workaround of the missing console
support), there are currently two options.
- Compile and run the program from the external terminal and use the "attach" configuration.
- Launch the server externally; run
dlv-dap dap --listen=:<port>
from the external terminal, and set the"debugServer": <port>
attribute in your launch configuration.
When you are having issues in dlv-dap
mode, first check if the problems are reproducible after updating dlv-dap
. It's possible that the problems are already fixed. Follow the instruction for updating dlv-dap) and updating extension.
Please report issues in our issue tracker with the following information.
go version
go version -m <path/to/dlv-dap>
- VS Code and VS Code Go version (e.g.
code --version
) - Instructions to reproduce the issue (code snippets, your
launch.json
, screenshot) - DAP trace (See the instruction)
{
"name": "Launch file",
"type": "go",
"trace": "verbose",
"showLog": true,
"logOutput": "dap",
...
}
The logOutput
and showLog
attributes in launch.json
enable Delve-side logging (server-side) and DAP message tracing. The trace
attribute controls the verbosity of Go extension's side logging (client-side).
The logging will appear in the Go Debug
output channel (Command Palette -> "View: Toggle Output" -> Select "Go Debug" from the dropdown menu). By nature, debug logs may contain sensitive information. Please review the logs carefully before sharing debug logs.
The core part of Delve DAP implementation is in the service/dap
package. Follow Delve project's contribution guideline to send PRs.
Code for integration with the Go extension is mostly in src/goDebugFactory.ts
and tests are in test/integration/goDebug.test.ts
. Please take a look at VS Code Go project's contribution guideline to learn about how to prepare a change and send it for review.
For simple launch cases, build the delve binary, and configure "go.alternateTools"
setting.
"go.alternateTools": {
"dlv-dap": <path_to_your_delve>
}
$ dlv-dap dap --listen=:12345 --log --log-output=dap
{
"name": "Launch file",
"type": "go",
"request": "launch",
"debugAdapter": "dlv-dap",
...
"debugServer": 12345,
}
To support being able to set breakpoints while the program is running, the debug adapter needs to stop the program. Due to the extra synchronization required to correctly resume the program, the debug adapter currently sends a stopped event. This means that if you are editing breakpoints while the program is running, you will need to hit continue to continue your debug session. We plan to change the behavior of the debug adapter for more seamless editing of breakpoints. You can track the progress here.