In C# the executing program can detect if it\'s running in the debugger using:
System.Diagnostics.Debugger.IsAttached
Is there an equivalen
If you assume that the debugger used will be Delve, you can check on the Delve process(es). There are at least two cases to consider (maybe more).
os.Getppid()
to get the pid of your parent process, that process will be Delve.os.Getpid()
. This relies on the assumption that you're not finding an old Delve, running with an older PID that happens to match yours. (I forget what the rules on on reuse of PIDs by the OS). Note that the os functions used by 1 and 2 are different. One gets the parent PID, the other gets your PID.
Some very basic code to do 1 looks like this:
func isLaunchedByDebugger() bool {
// gops executable must be in the path. See https://github.com/google/gops
gopsOut, err := exec.Command("gops", strconv.Itoa(os.Getppid())).Output()
if err == nil && strings.Contains(string(gopsOut), "\\dlv.exe") {
// our parent process is (probably) the Delve debugger
return true
}
return false
}
As far as I know, there is no built-in way to do this in the manner you described. But you can do more or less the same using build tags to indicate that the delve debugger is running. You can pass build tags to dlv
with the --build-flags
argument. This is basically the same technique as I described in How can I check if the race detector is enabled at runtime?
isdelve/delve.go
// +build delve
package isdelve
const Enabled = true
isdelve/nodelve.go
:
// +build !delve
package isdelve
const Enabled = false
a.go
:
package main
import (
"isdelve"
"fmt"
)
func main() {
fmt.Println("delve", isdelve.Enabled)
}
In Goland, you can enable this under 'Run/Debug Configurations', by adding the following into 'Go tool arguments:'
-tags=delve
If you are outside of Goland, running go run a.go
will report delve false
, if you want to run dlv on its own, use
dlv debug --build-flags='-tags=delve' a.go
; this will report delve true
.
Alternatively, you can use delve's set
command to manually set a variable after starting the debugger.
For case 2 we can set the program to wait for some signal (SIGUSR1) and attach debugger during this wait.
The code of main.go can be like this:
package main
import (
"os"
"os/signal"
"syscall"
"fmt"
"github.com/my/repo/cmd"
)
const (
waitForSignalEnv = "WAIT_FOR_DEBUGGER"
debuggerPort = "4321"
)
func main() {
// Waiting for debugger attach in case if waitForSignalEnv!=""
if os.Getenv(waitForSignalEnv) != "" {
sigs := make(chan os.Signal, 1)
goOn := make(chan bool, 1)
signal.Notify(sigs, syscall.SIGTERM, syscall.SIGINT, syscall.SIGUSR1)
go func() {
sig := <-sigs
if sig == syscall.SIGUSR1 {
goOn <- true
} else if (sig == syscall.SIGTERM || sig == syscall.SIGINT ){
fmt.Printf("Exiting ...")
os.Exit(0)
}
}()
fmt.Printf("%s env is set, waiting SIGUSR1.\nYou can run remote debug in vscode and attach dlv debugger:\n\n", waitForSignalEnv)
pid := os.Getpid()
fmt.Printf("dlv attach --continue --accept-multiclient --headless --listen=:%s %d\n", debuggerPort, pid)
fmt.Printf("\nLaunch remote debugger in vscode to port %d and then give SIGUSR1 to the process\n", debuggerPort)
fmt.Printf("kill -SIGUSR1 %d\n", pid)
<-goOn
fmt.Printf("Continue ...")
}
cmd.Execute()
}
launch.json of vscode:
{
"name": "myprog-remote-debug",
"type": "go",
"request": "launch",
"remotePath": "${env:GOPATH}/src/github.com/my/repo",
"mode": "remote",
"port": 4321,
"host": "127.0.0.1",
"program": "${env:GOPATH}/src/github.com/my/repo",
"showLog": true,
"trace": "verbose"
}
Explanation: we launch the program with env WAIT_FOR_DEBUGGER=true, for example
export WAIT_FOR_DEBUGGER=true
./myprog -f values.yaml
It will output dlv attach ...
command and kill -SIGUSR <pid>
:
WAIT_FOR_DEBUGGER env is set, waiting SIGUSR1.
You can run remote debug in vscode and attach dlv debugger:
dlv attach --continue --accept-multiclient --headless --listen=:4321 556127
Launch remote debugger in vscode to port 4321 and then give SIGUSR1 to the process
kill -SIGUSR1 556127
Run the dlv attach ...
above
Then go to VS Code and run myprog-remote-debug. Set breakpoints before
Then give him kill -SIGUSR1 556127
and breakpoints will work