1package shared
2
3import (
4	"fmt"
5	"os"
6	"os/exec"
7	"strings"
8	"syscall"
9)
10
11var (
12	isDebugging bool
13)
14
15// Finds the Delve binary to use. Either uses the SOONG_DELVE_PATH environment
16// variable or if that is unset, looks at $PATH.
17func ResolveDelveBinary() string {
18	result := os.Getenv("SOONG_DELVE_PATH")
19	if result == "" {
20		result, _ = exec.LookPath("dlv")
21	}
22
23	return result
24}
25
26// Returns whether the current process is running under Delve due to
27// ReexecWithDelveMaybe().
28func IsDebugging() bool {
29	return isDebugging
30}
31
32// Re-executes the binary in question under the control of Delve when
33// delveListen is not the empty string. delvePath gives the path to the Delve.
34func ReexecWithDelveMaybe(delveListen, delvePath string) {
35	isDebugging = os.Getenv("SOONG_DELVE_REEXECUTED") == "true"
36	if isDebugging || delveListen == "" {
37		return
38	}
39
40	if delvePath == "" {
41		fmt.Fprintln(os.Stderr, "Delve debugging requested but failed to find dlv")
42		os.Exit(1)
43	}
44
45	soongDelveEnv := []string{}
46	for _, env := range os.Environ() {
47		idx := strings.IndexRune(env, '=')
48		if idx != -1 {
49			soongDelveEnv = append(soongDelveEnv, env)
50		}
51	}
52
53	soongDelveEnv = append(soongDelveEnv, "SOONG_DELVE_REEXECUTED=true")
54
55	dlvArgv := []string{
56		delvePath,
57		"--listen=:" + delveListen,
58		"--headless=true",
59		"--api-version=2",
60		"exec",
61		os.Args[0],
62		"--",
63	}
64
65	dlvArgv = append(dlvArgv, os.Args[1:]...)
66	syscall.Exec(delvePath, dlvArgv, soongDelveEnv)
67	fmt.Fprintln(os.Stderr, "exec() failed while trying to reexec with Delve")
68	os.Exit(1)
69}
70