vscode-go
vscode-go copied to clipboard
Take advantage of suspending breakpoint provided by delve
What version of Go, VS Code & VS Code Go extension are you using?
Version Information
- Run
go versionto get version of Go from the VS Code integrated terminal.- go version go1.24.0 linux/amd64
- Run
gopls -v versionto get version of Gopls from the VS Code integrated terminal.- golang.org/x/tools/gopls v0.18.1
- Run
code -vorcode-insiders -vto get version of VS Code or VS Code Insiders.- 1.98.0 6609ac3d66f4eade5cf376d1cb76f13985724bcb x64
- Check your installed extensions to get the version of the VS Code Go extension
- 0.46.1
- Run Ctrl+Shift+P (Cmd+Shift+P on Mac OS) >
Go: Locate Configured Go Toolscommand. - the dlv is the version not released yet in https://github.com/Lslightly/delve/tree/followExecByDefault which enabletarget follow-exec -onby default and fixed some other bugs(see service/debugger: fix FindLocation with child processes by aarzilli · Pull Request #3937 · go-delve/delve).
Environment
GOBIN: undefined toolsGopath: gopath: /home/lqw/go GOROOT: /home/lqw/go1.24.0 PATH: /home/lqw/.vscode-server/bin/6609ac3d66f4eade5cf376d1cb76f13985724bcb/bin/remote-cli:/home/lqw/.rvm/gems/ruby-3.0.0/bin:/home/lqw/.rvm/gems/ruby-3.0.0@global/bin:/home/lqw/.rvm/rubies/ruby-3.0.0/bin:/home/lqw/mygit/delve:/home/lqw/go/bin:/home/lqw/go1.24.0/bin:/home/lqw/scripts:/home/lqw/cmake/bin:/home/lqw/.local/bin:/home/lqw/miniconda3/bin:/home/lqw/miniconda3/condabin:/home/lqw/.opam/default/bin:/home/lqw/.elan/bin:/home/lqw/.cargo/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/usr/lib/wsl/lib:/home/lqw/.rvm/bin
Tools
go: /home/lqw/go1.24.0/bin/go: go version go1.24.0 linux/amd64
gopls: /home/lqw/go/bin/gopls (version: v0.18.1 built with go: go1.24.1)
gotests: not installed
gomodifytags: not installed
impl: not installed
goplay: not installed
dlv: /home/lqw/go/bin/dlv (version: v0.0.0-20250311114909-570f5725d595+dirty built with go: go1.24.0)
staticcheck: /home/lqw/go/bin/staticcheck (version: v0.6.0 built with go: go1.24.0)
Go env
Workspace Folder (delve): /home/lqw/mygit/delve
AR='ar'
CC='gcc'
CGO_CFLAGS='-O2 -g'
CGO_CPPFLAGS=''
CGO_CXXFLAGS='-O2 -g'
CGO_ENABLED='1'
CGO_FFLAGS='-O2 -g'
CGO_LDFLAGS='-O2 -g'
CXX='g++'
GCCGO='gccgo'
GO111MODULE='on'
GOAMD64='v1'
GOARCH='amd64'
GOAUTH='netrc'
GOBIN=''
GOCACHE='/home/lqw/.cache/go-build'
GOCACHEPROG=''
GODEBUG=''
GOENV='/home/lqw/.config/go/env'
GOEXE=''
GOEXPERIMENT=''
GOFIPS140='off'
GOFLAGS=''
GOGCCFLAGS='-fPIC -m64 -pthread -Wl,--no-gc-sections -fmessage-length=0 -ffile-prefix-map=/tmp/go-build4247711127=/tmp/go-build -gno-record-gcc-switches'
GOHOSTARCH='amd64'
GOHOSTOS='linux'
GOINSECURE=''
GOMOD='/home/lqw/mygit/delve/go.mod'
GOMODCACHE='/home/lqw/go/pkg/mod'
GONOPROXY=''
GONOSUMDB=''
GOOS='linux'
GOPATH='/home/lqw/go'
GOPRIVATE=''
GOPROXY='https://goproxy.cn,direct'
GOROOT='/home/lqw/go1.24.0'
GOSUMDB='sum.golang.org'
GOTELEMETRY='local'
GOTELEMETRYDIR='/home/lqw/.config/go/telemetry'
GOTMPDIR=''
GOTOOLCHAIN='auto'
GOTOOLDIR='/home/lqw/go1.24.0/pkg/tool/linux_amd64'
GOVCS=''
GOVERSION='go1.24.0'
GOWORK=''
PKG_CONFIG='pkg-config'
Share the Go related settings you have added/edited
Run Preferences: Open Settings (JSON) command to open your settings.json file.
Share all the settings with the go. or ["go"] or gopls prefixes.
"go.alternateTools": {
"dlv": "<modified dlv mentioned above>"
}
Describe the bug
A clear and concise description of what the bug. A clear and concise description of what you expected to happen.
Bug: The suspended argument is always false when CreateBreakpoint is invoked in delve server through RPC call by vscode-go debug adapter. The consequence is that when the location of a breakpoint is not found in the delve debugger, the breakpoint will be deleted in service/debugger/debugger.go#L792-L797 as shown in the following code, which makes vscode frontend fail to set the breakpoint. Current interface not fully utilizes the ability of suspending breakpoints in delve, which can limit vscode-go debug adapter's ability in cases like multiple process debugging even if FollowExec is enabled.
if suspended {
logflags.DebuggerLogger().Debugf("could not enable new breakpoint: %v (breakpoint will be suspended)", err)
} else {
delete(d.target.LogicalBreakpoints, lbp.LogicalID)
return nil, err
}
What I expected to see: suspended is always sent true so that when the location of a breakpoint is not found, the breakpoint can still be suspended. In the future, the breakpoint will be valid.
The interfaces in both sides are:
- vscode-go extension/src/debugAdapter/goDebug.ts: https://github.com/golang/vscode-go/blob/1a21ede94c3ffd440d24ccc128ef9e4d7786dd08/extension/src/debugAdapter/goDebug.ts#L2189
- delve:
argv = reflect.New(mtype.ArgType)at https://github.com/go-delve/delve/blob/570f5725d595dc698d257f91326e677b9eda89df/service/rpccommon/server.go#L238function.Call([]reflect.Value{argv, reflect.ValueOf(ctl)})at https://github.com/go-delve/delve/blob/570f5725d595dc698d257f91326e677b9eda89df/service/rpccommon/server.go#L295s.debugger.CreateBreakpoint(&arg.Breakpoint, arg.LocExpr, arg.SubstitutePathRules, arg.Suspended)at https://github.com/go-delve/delve/blob/570f5725d595dc698d257f91326e677b9eda89df/service/rpc2/server.go#L263
Current interface in delve is:
- https://github.com/go-delve/delve/blob/570f5725d595dc698d257f91326e677b9eda89df/service/api/types.go#L74-L141
- https://github.com/go-delve/delve/blob/570f5725d595dc698d257f91326e677b9eda89df/service/rpc2/server.go#L243-L249
Code of delve
// Breakpoint addresses a set of locations at which process execution may be
// suspended.
type Breakpoint struct {
// ID is a unique identifier for the breakpoint.
ID int `json:"id"`
// User defined name of the breakpoint.
Name string `json:"name"`
// Addr is deprecated, use Addrs.
Addr uint64 `json:"addr"`
// Addrs is the list of addresses for this breakpoint.
Addrs []uint64 `json:"addrs"`
// AddrPid[i] is the PID associated with by Addrs[i], when debugging a
// single target process this is optional, otherwise it is mandatory.
AddrPid []int `json:"addrpid"`
// File is the source file for the breakpoint.
File string `json:"file"`
// Line is a line in File for the breakpoint.
Line int `json:"line"`
// FunctionName is the name of the function at the current breakpoint, and
// may not always be available.
FunctionName string `json:"functionName,omitempty"`
// ExprString is the string that will be used to set a suspended breakpoint.
ExprString string
// Breakpoint condition
Cond string
// Breakpoint hit count condition.
// Supported hit count conditions are "NUMBER" and "OP NUMBER".
HitCond string
// HitCondPerG use per goroutine hitcount as HitCond operand, instead of total hitcount
HitCondPerG bool
// Tracepoint flag, signifying this is a tracepoint.
Tracepoint bool `json:"continue"`
// TraceReturn flag signifying this is a breakpoint set at a return
// statement in a traced function.
TraceReturn bool `json:"traceReturn"`
// retrieve goroutine information
Goroutine bool `json:"goroutine"`
// number of stack frames to retrieve
Stacktrace int `json:"stacktrace"`
// expressions to evaluate
Variables []string `json:"variables,omitempty"`
// LoadArgs requests loading function arguments when the breakpoint is hit
LoadArgs *LoadConfig
// LoadLocals requests loading function locals when the breakpoint is hit
LoadLocals *LoadConfig
// WatchExpr is the expression used to create this watchpoint
WatchExpr string
WatchType WatchType
VerboseDescr []string `json:"VerboseDescr,omitempty"`
// number of times a breakpoint has been reached in a certain goroutine
HitCount map[string]uint64 `json:"hitCount"`
// number of times a breakpoint has been reached
TotalHitCount uint64 `json:"totalHitCount"`
// Disabled flag, signifying the state of the breakpoint
Disabled bool `json:"disabled"`
UserData interface{} `json:"-"`
// RootFuncName is the Root function from where tracing needs to be done
RootFuncName string
// TraceFollowCalls indicates the Depth of tracing
TraceFollowCalls int
}
type CreateBreakpointIn struct {
Breakpoint api.Breakpoint
LocExpr string
SubstitutePathRules [][2]string
Suspended bool
}
Describe the solution you'd like A clear and concise description of what you want to happen.
add suspended in RPC pack. vscode-go always send suspended=true to delve.
Describe alternatives you've considered A clear and concise description of any alternative solutions or features you've considered.
nothing yet.
Additional context Add any other context or screenshots about the feature request here.
This issue is blocking #3712. #3712 is a promising enhancement.
Related PR: https://github.com/go-delve/delve/pull/3900