Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit bb751686 authored by Lukács T. Berki's avatar Lukács T. Berki Committed by Automerger Merge Worker
Browse files

Merge "Call Delve using exec() instead of "dlv attach"." am: ad373047

Change-Id: I453fa205399d208591e30e6e665c2d4be1220349
parents d3205312 ad373047
Loading
Loading
Loading
Loading
+37 −4
Original line number Diff line number Diff line
@@ -15,9 +15,11 @@
package android

import (
	"fmt"
	"os"
	"os/exec"
	"strings"
	"syscall"

	"android/soong/env"
)
@@ -30,28 +32,59 @@ import (
// a manifest regeneration.

var originalEnv map[string]string
var SoongDelveListen string
var SoongDelvePath string
var soongDelveListen string
var soongDelvePath string
var soongDelveEnv []string

func init() {
	// Delve support needs to read this environment variable very early, before NewConfig has created a way to
	// access originalEnv with dependencies.  Store the value where soong_build can find it, it will manually
	// ensure the dependencies are created.
	SoongDelveListen = os.Getenv("SOONG_DELVE")
	SoongDelvePath, _ = exec.LookPath("dlv")
	soongDelveListen = os.Getenv("SOONG_DELVE")
	soongDelvePath, _ = exec.LookPath("dlv")

	originalEnv = make(map[string]string)
	soongDelveEnv = []string{}
	for _, env := range os.Environ() {
		idx := strings.IndexRune(env, '=')
		if idx != -1 {
			originalEnv[env[:idx]] = env[idx+1:]
			if env[:idx] != "SOONG_DELVE" {
				soongDelveEnv = append(soongDelveEnv, env)
			}
		}
	}

	// Clear the environment to prevent use of os.Getenv(), which would not provide dependencies on environment
	// variable values.  The environment is available through ctx.Config().Getenv, ctx.Config().IsEnvTrue, etc.
	os.Clearenv()
}

func ReexecWithDelveMaybe() {
	if soongDelveListen == "" {
		return
	}

	if soongDelvePath == "" {
		fmt.Fprintln(os.Stderr, "SOONG_DELVE is set but failed to find dlv")
		os.Exit(1)
	}
	dlvArgv := []string{
		soongDelvePath,
		"--listen=:" + soongDelveListen,
		"--headless=true",
		"--api-version=2",
		"exec",
		os.Args[0],
		"--",
	}
	dlvArgv = append(dlvArgv, os.Args[1:]...)
	os.Chdir(absSrcDir)
	syscall.Exec(soongDelvePath, dlvArgv, soongDelveEnv)
	fmt.Fprintln(os.Stderr, "exec() failed while trying to reexec with Delve")
	os.Exit(1)
}

// getenv checks either os.Getenv or originalEnv so that it works before or after the init()
// function above.  It doesn't add any dependencies on the environment variable, so it should
// only be used for values that won't change.  For values that might change use ctx.Config().Getenv.
+1 −41
Original line number Diff line number Diff line
@@ -18,12 +18,7 @@ import (
	"flag"
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"strconv"
	"strings"
	"syscall"
	"time"

	"github.com/google/blueprint/bootstrap"

@@ -55,42 +50,7 @@ func newNameResolver(config android.Config) *android.NameResolver {
}

func main() {
	if android.SoongDelveListen != "" {
		if android.SoongDelvePath == "" {
			fmt.Fprintln(os.Stderr, "SOONG_DELVE is set but failed to find dlv")
			os.Exit(1)
		}
		pid := strconv.Itoa(os.Getpid())
		cmd := []string{android.SoongDelvePath,
			"attach", pid,
			"--headless",
			"-l", android.SoongDelveListen,
			"--api-version=2",
			"--accept-multiclient",
			"--log",
		}

		fmt.Println("Starting", strings.Join(cmd, " "))
		dlv := exec.Command(cmd[0], cmd[1:]...)
		dlv.Stdout = os.Stdout
		dlv.Stderr = os.Stderr
		dlv.Stdin = nil

		// Put dlv into its own process group so we can kill it and the child process it starts.
		dlv.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}

		err := dlv.Start()
		if err != nil {
			// Print the error starting dlv and continue.
			fmt.Println(err)
		} else {
			// Kill the process group for dlv when soong_build exits.
			defer syscall.Kill(-dlv.Process.Pid, syscall.SIGKILL)
			// Wait to give dlv a chance to connect and pause the process.
			time.Sleep(time.Second)
		}
	}

	android.ReexecWithDelveMaybe()
	flag.Parse()

	// The top-level Blueprints file is passed as the first argument.