
Adds the ability to automatically debug child processes executed by the target to the linux native backend. This commit does not contain user interface or API to access this functionality. Updates #2551
103 lines
2.5 KiB
Go
103 lines
2.5 KiB
Go
//go:build linux || darwin
|
|
// +build linux darwin
|
|
|
|
package proc_test
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"os/exec"
|
|
"runtime"
|
|
"syscall"
|
|
"testing"
|
|
"time"
|
|
|
|
"golang.org/x/sys/unix"
|
|
|
|
"github.com/go-delve/delve/pkg/proc"
|
|
"github.com/go-delve/delve/pkg/proc/native"
|
|
protest "github.com/go-delve/delve/pkg/proc/test"
|
|
)
|
|
|
|
type errIssue419 struct {
|
|
pid int
|
|
err error
|
|
}
|
|
|
|
func (npe errIssue419) Error() string {
|
|
return fmt.Sprintf("Pid is zero or negative: %d", npe.pid)
|
|
}
|
|
|
|
func TestIssue419(t *testing.T) {
|
|
if testBackend == "rr" {
|
|
return
|
|
}
|
|
|
|
errChan := make(chan error, 2)
|
|
|
|
// SIGINT directed at the inferior should be passed along not swallowed by delve
|
|
withTestProcess("issue419", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
|
|
setFunctionBreakpoint(p, t, "main.main")
|
|
assertNoError(grp.Continue(), t, "Continue()")
|
|
resumeChan := make(chan struct{}, 1)
|
|
go func() {
|
|
time.Sleep(500 * time.Millisecond)
|
|
<-resumeChan
|
|
if p.Pid() <= 0 {
|
|
// if we don't stop the inferior the test will never finish
|
|
grp.RequestManualStop()
|
|
err := grp.Detach(true)
|
|
errChan <- errIssue419{pid: p.Pid(), err: err}
|
|
return
|
|
}
|
|
err := syscall.Kill(p.Pid(), syscall.SIGINT)
|
|
errChan <- errIssue419{pid: p.Pid(), err: err}
|
|
}()
|
|
grp.ResumeNotify(resumeChan)
|
|
errChan <- grp.Continue()
|
|
})
|
|
|
|
for i := 0; i < 2; i++ {
|
|
err := <-errChan
|
|
|
|
t.Logf("error %T %#v\n", err, err)
|
|
|
|
if v, ok := err.(errIssue419); ok {
|
|
assertNoError(v.err, t, "syscall.Kill")
|
|
continue
|
|
}
|
|
|
|
if _, exited := err.(proc.ErrProcessExited); !exited {
|
|
t.Fatalf("Unexpected error after Continue(): %v\n", err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestSignalDeath(t *testing.T) {
|
|
if testBackend != "native" || runtime.GOOS != "linux" {
|
|
t.Skip("skipped on non-linux non-native backends")
|
|
}
|
|
var buildFlags protest.BuildFlags
|
|
if buildMode == "pie" {
|
|
buildFlags |= protest.BuildModePIE
|
|
}
|
|
fixture := protest.BuildFixture("loopprog", buildFlags)
|
|
cmd := exec.Command(fixture.Path)
|
|
stdout, err := cmd.StdoutPipe()
|
|
assertNoError(err, t, "StdoutPipe")
|
|
cmd.Stderr = os.Stderr
|
|
assertNoError(cmd.Start(), t, "starting fixture")
|
|
p, err := native.Attach(cmd.Process.Pid, []string{})
|
|
assertNoError(err, t, "Attach")
|
|
stdout.Close() // target will receive SIGPIPE later on
|
|
err = p.Continue()
|
|
t.Logf("error is %v", err)
|
|
exitErr, isexited := err.(proc.ErrProcessExited)
|
|
if !isexited {
|
|
t.Fatal("did not exit")
|
|
}
|
|
if exitErr.Status != -int(unix.SIGPIPE) {
|
|
t.Fatalf("expected SIGPIPE got %d\n", exitErr.Status)
|
|
}
|
|
}
|