2015-05-04 13:31:50 +00:00
|
|
|
package test
|
|
|
|
|
|
|
|
import (
|
|
|
|
"crypto/rand"
|
|
|
|
"encoding/hex"
|
2017-11-06 17:44:38 +00:00
|
|
|
"flag"
|
2015-05-04 13:31:50 +00:00
|
|
|
"fmt"
|
|
|
|
"os"
|
|
|
|
"os/exec"
|
|
|
|
"path/filepath"
|
2019-07-31 20:09:00 +00:00
|
|
|
"regexp"
|
2016-01-15 05:26:54 +00:00
|
|
|
"runtime"
|
2017-05-05 22:17:52 +00:00
|
|
|
"strings"
|
|
|
|
"sync"
|
2016-01-26 21:08:05 +00:00
|
|
|
"testing"
|
2017-07-31 12:51:35 +00:00
|
|
|
|
2019-01-04 18:39:25 +00:00
|
|
|
"github.com/go-delve/delve/pkg/goversion"
|
2015-05-04 13:31:50 +00:00
|
|
|
)
|
|
|
|
|
2018-08-31 18:08:18 +00:00
|
|
|
// EnableRace allows to configure whether the race detector is enabled on target process.
|
2017-11-06 17:44:38 +00:00
|
|
|
var EnableRace = flag.Bool("racetarget", false, "Enables race detector on inferior process")
|
|
|
|
|
2018-06-06 15:01:47 +00:00
|
|
|
var runningWithFixtures bool
|
|
|
|
|
2024-10-31 17:19:08 +00:00
|
|
|
var ldFlags string
|
|
|
|
|
|
|
|
func init() {
|
|
|
|
ldFlags = os.Getenv("CGO_LDFLAGS")
|
|
|
|
}
|
|
|
|
|
2015-05-04 13:31:50 +00:00
|
|
|
// Fixture is a test binary.
|
|
|
|
type Fixture struct {
|
|
|
|
// Name is the short name of the fixture.
|
|
|
|
Name string
|
|
|
|
// Path is the absolute path to the test binary.
|
|
|
|
Path string
|
|
|
|
// Source is the absolute path of the test binary source.
|
|
|
|
Source string
|
2019-03-20 17:32:51 +00:00
|
|
|
// BuildDir is the directory where the build command was run.
|
|
|
|
BuildDir string
|
2015-05-04 13:31:50 +00:00
|
|
|
}
|
|
|
|
|
2018-08-31 18:08:18 +00:00
|
|
|
// FixtureKey holds the name and builds flags used for a test fixture.
|
2020-03-26 12:05:09 +00:00
|
|
|
type fixtureKey struct {
|
2018-04-19 07:02:12 +00:00
|
|
|
Name string
|
|
|
|
Flags BuildFlags
|
|
|
|
}
|
|
|
|
|
|
|
|
// Fixtures is a map of fixtureKey{ Fixture.Name, buildFlags } to Fixture.
|
2020-03-26 12:05:09 +00:00
|
|
|
var fixtures = make(map[fixtureKey]Fixture)
|
2015-05-04 13:31:50 +00:00
|
|
|
|
2018-05-29 15:01:51 +00:00
|
|
|
// PathsToRemove is a list of files and directories to remove after running all the tests
|
|
|
|
var PathsToRemove []string
|
|
|
|
|
2018-08-31 18:08:18 +00:00
|
|
|
// FindFixturesDir will search for the directory holding all test fixtures
|
|
|
|
// beginning with the current directory and searching up 10 directories.
|
2015-09-29 16:40:12 +00:00
|
|
|
func FindFixturesDir() string {
|
2015-05-04 13:31:50 +00:00
|
|
|
parent := ".."
|
2015-06-13 04:47:30 +00:00
|
|
|
fixturesDir := "_fixtures"
|
2015-05-04 13:31:50 +00:00
|
|
|
for depth := 0; depth < 10; depth++ {
|
|
|
|
if _, err := os.Stat(fixturesDir); err == nil {
|
|
|
|
break
|
|
|
|
}
|
2015-05-08 22:51:30 +00:00
|
|
|
fixturesDir = filepath.Join(parent, fixturesDir)
|
2015-05-04 13:31:50 +00:00
|
|
|
}
|
2015-09-29 16:40:12 +00:00
|
|
|
return fixturesDir
|
|
|
|
}
|
|
|
|
|
2018-08-31 18:08:18 +00:00
|
|
|
// BuildFlags used to build fixture.
|
2017-08-15 06:21:24 +00:00
|
|
|
type BuildFlags uint32
|
|
|
|
|
|
|
|
const (
|
2021-01-29 17:23:52 +00:00
|
|
|
// LinkStrip enables '-ldflags="-s"'.
|
2017-07-31 12:51:35 +00:00
|
|
|
LinkStrip BuildFlags = 1 << iota
|
2018-08-31 18:08:18 +00:00
|
|
|
// EnableCGOOptimization will build CGO code with optimizations.
|
2017-07-31 12:51:35 +00:00
|
|
|
EnableCGOOptimization
|
2018-08-31 18:08:18 +00:00
|
|
|
// EnableInlining will build a binary with inline optimizations turned on.
|
proc: support inlining
Go 1.10 added inlined calls to debug_info, this commit adds support
for DW_TAG_inlined_call to delve, both for stack traces (where
inlined calls will appear as normal stack frames) and to correct
the behavior of next, step and stepout.
The calls to Next and Frame of stackIterator continue to work
unchanged and only return real stack frames, after reading each line
appendInlinedCalls is called to unpacked all the inlined calls that
involve the current PC.
The fake stack frames produced by appendInlinedCalls are
distinguished from real stack frames by having the Inlined attribute
set to true. Also their Current and Call locations are treated
differently. The Call location will be changed to represent the
position inside the inlined call, while the Current location will
always reference the real stack frame. This is done because:
* next, step and stepout need to access the debug_info entry of
the real function they are stepping through
* we are already manipulating Call in different ways while Current
is just what we read from the call stack
The strategy remains mostly the same, we disassemble the function
and we set a breakpoint on each instruction corresponding to a
different file:line. The function in question will be the one
corresponding to the first real (i.e. non-inlined) stack frame.
* If the current function contains inlined calls, 'next' will not
set any breakpoints on instructions that belong to inlined calls. We
do not do this for 'step'.
* If we are inside an inlined call that makes other inlined
functions, 'next' will not set any breakpoints that belong to
inlined calls that are children of the current inlined call.
* If the current function is inlined the breakpoint on the return
address won't be set, because inlined frames don't have a return
address.
* The code we use for stepout doesn't work at all if we are inside
an inlined call, instead we call 'next' but instruct it to remove
all PCs belonging to the current inlined call.
2017-11-13 15:54:08 +00:00
|
|
|
EnableInlining
|
2018-08-31 18:08:18 +00:00
|
|
|
// EnableOptimization will build a binary with default optimizations.
|
2018-06-20 08:06:12 +00:00
|
|
|
EnableOptimization
|
2018-08-31 18:08:18 +00:00
|
|
|
// EnableDWZCompression will enable DWZ compression of DWARF sections.
|
2018-05-21 14:41:28 +00:00
|
|
|
EnableDWZCompression
|
2018-05-29 15:01:51 +00:00
|
|
|
BuildModePIE
|
2019-03-20 17:32:51 +00:00
|
|
|
BuildModePlugin
|
2021-01-29 17:23:52 +00:00
|
|
|
BuildModeExternalLinker
|
2019-06-30 17:34:47 +00:00
|
|
|
AllNonOptimized
|
2022-04-01 17:31:23 +00:00
|
|
|
// LinkDisableDWARF enables '-ldflags="-w"'.
|
|
|
|
LinkDisableDWARF
|
2017-08-15 06:21:24 +00:00
|
|
|
)
|
|
|
|
|
2022-08-22 19:48:34 +00:00
|
|
|
// TempFile makes a (good enough) random temporary file name
|
|
|
|
func TempFile(name string) string {
|
|
|
|
r := make([]byte, 4)
|
|
|
|
rand.Read(r)
|
|
|
|
return filepath.Join(os.TempDir(), fmt.Sprintf("%s.%s", name, hex.EncodeToString(r)))
|
|
|
|
}
|
|
|
|
|
2018-08-31 18:08:18 +00:00
|
|
|
// BuildFixture will compile the fixture 'name' using the provided build flags.
|
2017-08-15 06:21:24 +00:00
|
|
|
func BuildFixture(name string, flags BuildFlags) Fixture {
|
2018-06-06 15:01:47 +00:00
|
|
|
if !runningWithFixtures {
|
|
|
|
panic("RunTestsWithFixtures not called")
|
|
|
|
}
|
2020-03-26 12:05:09 +00:00
|
|
|
fk := fixtureKey{name, flags}
|
|
|
|
if f, ok := fixtures[fk]; ok {
|
2015-09-29 16:40:12 +00:00
|
|
|
return f
|
|
|
|
}
|
|
|
|
|
2017-07-31 12:51:35 +00:00
|
|
|
if flags&EnableCGOOptimization == 0 {
|
2022-08-15 16:40:25 +00:00
|
|
|
if os.Getenv("CI") == "" || os.Getenv("CGO_CFLAGS") == "" {
|
|
|
|
os.Setenv("CGO_CFLAGS", "-O0 -g")
|
|
|
|
}
|
2017-07-31 12:51:35 +00:00
|
|
|
}
|
|
|
|
|
2015-09-29 16:40:12 +00:00
|
|
|
fixturesDir := FindFixturesDir()
|
2015-05-04 13:31:50 +00:00
|
|
|
|
2016-11-15 16:16:33 +00:00
|
|
|
dir := fixturesDir
|
2015-05-15 14:23:58 +00:00
|
|
|
path := filepath.Join(fixturesDir, name+".go")
|
2016-11-15 16:16:33 +00:00
|
|
|
if name[len(name)-1] == '/' {
|
|
|
|
dir = filepath.Join(dir, name)
|
|
|
|
path = ""
|
|
|
|
name = name[:len(name)-1]
|
|
|
|
}
|
2022-08-22 19:48:34 +00:00
|
|
|
tmpfile := TempFile(name)
|
2015-05-15 14:23:58 +00:00
|
|
|
|
2016-01-15 05:26:54 +00:00
|
|
|
buildFlags := []string{"build"}
|
2019-02-20 21:26:18 +00:00
|
|
|
var ver goversion.GoVersion
|
2020-03-18 16:25:32 +00:00
|
|
|
if ver, _ = goversion.Parse(runtime.Version()); runtime.GOOS == "windows" && ver.Major > 0 && !ver.AfterOrEqual(goversion.GoVersion{Major: 1, Minor: 9, Rev: -1}) {
|
2016-01-15 05:26:54 +00:00
|
|
|
// Work-around for https://github.com/golang/go/issues/13154
|
|
|
|
buildFlags = append(buildFlags, "-ldflags=-linkmode internal")
|
|
|
|
}
|
2022-04-01 17:31:23 +00:00
|
|
|
ldflagsv := []string{}
|
2017-08-15 06:21:24 +00:00
|
|
|
if flags&LinkStrip != 0 {
|
2022-04-01 17:31:23 +00:00
|
|
|
ldflagsv = append(ldflagsv, "-s")
|
2017-08-15 06:21:24 +00:00
|
|
|
}
|
2022-04-01 17:31:23 +00:00
|
|
|
if flags&LinkDisableDWARF != 0 {
|
|
|
|
ldflagsv = append(ldflagsv, "-w")
|
|
|
|
}
|
|
|
|
buildFlags = append(buildFlags, "-ldflags="+strings.Join(ldflagsv, " "))
|
2018-06-20 08:06:12 +00:00
|
|
|
gcflagsv := []string{}
|
|
|
|
if flags&EnableInlining == 0 {
|
|
|
|
gcflagsv = append(gcflagsv, "-l")
|
proc: support inlining
Go 1.10 added inlined calls to debug_info, this commit adds support
for DW_TAG_inlined_call to delve, both for stack traces (where
inlined calls will appear as normal stack frames) and to correct
the behavior of next, step and stepout.
The calls to Next and Frame of stackIterator continue to work
unchanged and only return real stack frames, after reading each line
appendInlinedCalls is called to unpacked all the inlined calls that
involve the current PC.
The fake stack frames produced by appendInlinedCalls are
distinguished from real stack frames by having the Inlined attribute
set to true. Also their Current and Call locations are treated
differently. The Call location will be changed to represent the
position inside the inlined call, while the Current location will
always reference the real stack frame. This is done because:
* next, step and stepout need to access the debug_info entry of
the real function they are stepping through
* we are already manipulating Call in different ways while Current
is just what we read from the call stack
The strategy remains mostly the same, we disassemble the function
and we set a breakpoint on each instruction corresponding to a
different file:line. The function in question will be the one
corresponding to the first real (i.e. non-inlined) stack frame.
* If the current function contains inlined calls, 'next' will not
set any breakpoints on instructions that belong to inlined calls. We
do not do this for 'step'.
* If we are inside an inlined call that makes other inlined
functions, 'next' will not set any breakpoints that belong to
inlined calls that are children of the current inlined call.
* If the current function is inlined the breakpoint on the return
address won't be set, because inlined frames don't have a return
address.
* The code we use for stepout doesn't work at all if we are inside
an inlined call, instead we call 'next' but instruct it to remove
all PCs belonging to the current inlined call.
2017-11-13 15:54:08 +00:00
|
|
|
}
|
2018-06-20 08:06:12 +00:00
|
|
|
if flags&EnableOptimization == 0 {
|
|
|
|
gcflagsv = append(gcflagsv, "-N")
|
|
|
|
}
|
2019-06-30 17:34:47 +00:00
|
|
|
var gcflags string
|
|
|
|
if flags&AllNonOptimized != 0 {
|
|
|
|
gcflags = "-gcflags=all=" + strings.Join(gcflagsv, " ")
|
|
|
|
} else {
|
|
|
|
gcflags = "-gcflags=" + strings.Join(gcflagsv, " ")
|
|
|
|
}
|
proc: support inlining
Go 1.10 added inlined calls to debug_info, this commit adds support
for DW_TAG_inlined_call to delve, both for stack traces (where
inlined calls will appear as normal stack frames) and to correct
the behavior of next, step and stepout.
The calls to Next and Frame of stackIterator continue to work
unchanged and only return real stack frames, after reading each line
appendInlinedCalls is called to unpacked all the inlined calls that
involve the current PC.
The fake stack frames produced by appendInlinedCalls are
distinguished from real stack frames by having the Inlined attribute
set to true. Also their Current and Call locations are treated
differently. The Call location will be changed to represent the
position inside the inlined call, while the Current location will
always reference the real stack frame. This is done because:
* next, step and stepout need to access the debug_info entry of
the real function they are stepping through
* we are already manipulating Call in different ways while Current
is just what we read from the call stack
The strategy remains mostly the same, we disassemble the function
and we set a breakpoint on each instruction corresponding to a
different file:line. The function in question will be the one
corresponding to the first real (i.e. non-inlined) stack frame.
* If the current function contains inlined calls, 'next' will not
set any breakpoints on instructions that belong to inlined calls. We
do not do this for 'step'.
* If we are inside an inlined call that makes other inlined
functions, 'next' will not set any breakpoints that belong to
inlined calls that are children of the current inlined call.
* If the current function is inlined the breakpoint on the return
address won't be set, because inlined frames don't have a return
address.
* The code we use for stepout doesn't work at all if we are inside
an inlined call, instead we call 'next' but instruct it to remove
all PCs belonging to the current inlined call.
2017-11-13 15:54:08 +00:00
|
|
|
buildFlags = append(buildFlags, gcflags, "-o", tmpfile)
|
2017-11-06 17:44:38 +00:00
|
|
|
if *EnableRace {
|
|
|
|
buildFlags = append(buildFlags, "-race")
|
|
|
|
}
|
2018-05-29 15:01:51 +00:00
|
|
|
if flags&BuildModePIE != 0 {
|
|
|
|
buildFlags = append(buildFlags, "-buildmode=pie")
|
2020-07-28 16:19:51 +00:00
|
|
|
} else {
|
|
|
|
buildFlags = append(buildFlags, "-buildmode=exe")
|
2018-05-29 15:01:51 +00:00
|
|
|
}
|
2019-03-20 17:32:51 +00:00
|
|
|
if flags&BuildModePlugin != 0 {
|
|
|
|
buildFlags = append(buildFlags, "-buildmode=plugin")
|
|
|
|
}
|
2021-01-29 17:23:52 +00:00
|
|
|
if flags&BuildModeExternalLinker != 0 {
|
|
|
|
buildFlags = append(buildFlags, "-ldflags=-linkmode=external")
|
|
|
|
}
|
2024-10-21 16:15:02 +00:00
|
|
|
if ver.IsOldDevel() || ver.AfterOrEqual(goversion.GoVersion{Major: 1, Minor: 11, Rev: -1}) {
|
2019-02-20 21:26:18 +00:00
|
|
|
if flags&EnableDWZCompression != 0 {
|
|
|
|
buildFlags = append(buildFlags, "-ldflags=-compressdwarf=false")
|
|
|
|
}
|
|
|
|
}
|
2016-11-15 16:16:33 +00:00
|
|
|
if path != "" {
|
|
|
|
buildFlags = append(buildFlags, name+".go")
|
|
|
|
}
|
|
|
|
|
2016-11-10 10:20:08 +00:00
|
|
|
cmd := exec.Command("go", buildFlags...)
|
2016-11-15 16:16:33 +00:00
|
|
|
cmd.Dir = dir
|
2022-08-15 16:40:25 +00:00
|
|
|
if os.Getenv("CI") != "" {
|
|
|
|
cmd.Env = os.Environ()
|
|
|
|
}
|
2016-01-15 05:26:54 +00:00
|
|
|
|
2015-05-15 14:23:58 +00:00
|
|
|
// Build the test binary
|
2017-05-31 12:19:45 +00:00
|
|
|
if out, err := cmd.CombinedOutput(); err != nil {
|
2015-05-15 14:23:58 +00:00
|
|
|
fmt.Printf("Error compiling %s: %s\n", path, err)
|
2017-05-31 12:19:45 +00:00
|
|
|
fmt.Printf("%s\n", string(out))
|
2015-05-04 13:31:50 +00:00
|
|
|
os.Exit(1)
|
|
|
|
}
|
|
|
|
|
2018-05-21 14:41:28 +00:00
|
|
|
if flags&EnableDWZCompression != 0 {
|
|
|
|
cmd := exec.Command("dwz", tmpfile)
|
|
|
|
if out, err := cmd.CombinedOutput(); err != nil {
|
2019-07-31 20:09:00 +00:00
|
|
|
if regexp.MustCompile(`dwz: Section offsets in (.*?) not monotonically increasing`).FindString(string(out)) == "" {
|
|
|
|
fmt.Printf("Error running dwz on %s: %s\n", tmpfile, err)
|
|
|
|
fmt.Printf("%s\n", string(out))
|
|
|
|
os.Exit(1)
|
|
|
|
}
|
2018-05-21 14:41:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-05-15 14:23:58 +00:00
|
|
|
source, _ := filepath.Abs(path)
|
2016-01-15 05:26:54 +00:00
|
|
|
source = filepath.ToSlash(source)
|
2019-01-04 10:03:16 +00:00
|
|
|
sympath, err := filepath.EvalSymlinks(source)
|
|
|
|
if err == nil {
|
2023-02-14 17:36:24 +00:00
|
|
|
source = strings.ReplaceAll(sympath, "\\", "/")
|
2019-01-04 10:03:16 +00:00
|
|
|
}
|
2016-01-26 21:08:05 +00:00
|
|
|
|
2019-03-20 17:32:51 +00:00
|
|
|
absdir, _ := filepath.Abs(dir)
|
|
|
|
|
|
|
|
fixture := Fixture{Name: name, Path: tmpfile, Source: source, BuildDir: absdir}
|
2017-08-15 06:21:24 +00:00
|
|
|
|
2020-03-26 12:05:09 +00:00
|
|
|
fixtures[fk] = fixture
|
|
|
|
return fixtures[fk]
|
2015-05-15 14:23:58 +00:00
|
|
|
}
|
2015-05-04 13:31:50 +00:00
|
|
|
|
2015-05-15 14:23:58 +00:00
|
|
|
// RunTestsWithFixtures will pre-compile test fixtures before running test
|
|
|
|
// methods. Test binaries are deleted before exiting.
|
2015-06-21 03:47:44 +00:00
|
|
|
func RunTestsWithFixtures(m *testing.M) int {
|
2018-06-06 15:01:47 +00:00
|
|
|
runningWithFixtures = true
|
|
|
|
defer func() {
|
|
|
|
runningWithFixtures = false
|
|
|
|
}()
|
2015-05-04 13:31:50 +00:00
|
|
|
status := m.Run()
|
|
|
|
|
|
|
|
// Remove the fixtures.
|
2020-03-26 12:05:09 +00:00
|
|
|
for _, f := range fixtures {
|
2015-05-04 13:31:50 +00:00
|
|
|
os.Remove(f.Path)
|
|
|
|
}
|
2018-05-29 15:01:51 +00:00
|
|
|
|
|
|
|
for _, p := range PathsToRemove {
|
|
|
|
fi, err := os.Stat(p)
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
if fi.IsDir() {
|
|
|
|
SafeRemoveAll(p)
|
|
|
|
} else {
|
|
|
|
os.Remove(p)
|
|
|
|
}
|
|
|
|
}
|
2015-06-21 03:47:44 +00:00
|
|
|
return status
|
2015-05-04 13:31:50 +00:00
|
|
|
}
|
2017-05-05 22:17:52 +00:00
|
|
|
|
|
|
|
var recordingAllowed = map[string]bool{}
|
|
|
|
var recordingAllowedMu sync.Mutex
|
|
|
|
|
|
|
|
// AllowRecording allows the calling test to be used with a recording of the
|
|
|
|
// fixture.
|
|
|
|
func AllowRecording(t testing.TB) {
|
|
|
|
recordingAllowedMu.Lock()
|
|
|
|
defer recordingAllowedMu.Unlock()
|
2023-04-28 13:12:52 +00:00
|
|
|
name := t.Name()
|
2017-05-05 22:17:52 +00:00
|
|
|
t.Logf("enabling recording for %s", name)
|
|
|
|
recordingAllowed[name] = true
|
|
|
|
}
|
|
|
|
|
|
|
|
// MustHaveRecordingAllowed skips this test if recording is not allowed
|
|
|
|
//
|
|
|
|
// Not all the tests can be run with a recording:
|
2022-06-17 17:08:11 +00:00
|
|
|
// - some fixtures never terminate independently (loopprog,
|
|
|
|
// testnextnethttp) and can not be recorded
|
|
|
|
// - some tests assume they can interact with the target process (for
|
|
|
|
// example TestIssue419, or anything changing the value of a variable),
|
|
|
|
// which we can't do on with a recording
|
|
|
|
// - some tests assume that the Pid returned by the process is valid, but
|
|
|
|
// it won't be at replay time
|
|
|
|
// - some tests will start the fixture but not never execute a single
|
|
|
|
// instruction, for some reason rr doesn't like this and will print an
|
|
|
|
// error if it happens
|
|
|
|
// - many tests will assume that we can return from a runtime.Breakpoint,
|
|
|
|
// with a recording this is not possible because when the fixture ran it
|
|
|
|
// wasn't attached to a debugger and in those circumstances a
|
|
|
|
// runtime.Breakpoint leads directly to a crash
|
2017-05-05 22:17:52 +00:00
|
|
|
//
|
|
|
|
// Some of the tests using runtime.Breakpoint (anything involving variable
|
|
|
|
// evaluation and TestWorkDir) have been adapted to work with a recording.
|
|
|
|
func MustHaveRecordingAllowed(t testing.TB) {
|
|
|
|
recordingAllowedMu.Lock()
|
|
|
|
defer recordingAllowedMu.Unlock()
|
2023-04-28 13:12:52 +00:00
|
|
|
name := t.Name()
|
2017-05-05 22:17:52 +00:00
|
|
|
if !recordingAllowed[name] {
|
|
|
|
t.Skipf("recording not allowed for %s", name)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// SafeRemoveAll removes dir and its contents but only as long as dir does
|
|
|
|
// not contain directories.
|
|
|
|
func SafeRemoveAll(dir string) {
|
2023-05-08 17:37:30 +00:00
|
|
|
fis, err := os.ReadDir(dir)
|
2017-05-05 22:17:52 +00:00
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
for _, fi := range fis {
|
|
|
|
if fi.IsDir() {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for _, fi := range fis {
|
|
|
|
if err := os.Remove(filepath.Join(dir, fi.Name())); err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
os.Remove(dir)
|
|
|
|
}
|
2018-07-28 19:12:07 +00:00
|
|
|
|
|
|
|
// MustSupportFunctionCalls skips this test if function calls are
|
|
|
|
// unsupported on this backend/architecture pair.
|
|
|
|
func MustSupportFunctionCalls(t *testing.T, testBackend string) {
|
|
|
|
if !goversion.VersionAfterOrEqual(runtime.Version(), 1, 11) {
|
|
|
|
t.Skip("this version of Go does not support function calls")
|
|
|
|
}
|
2018-08-03 15:17:01 +00:00
|
|
|
|
2021-10-14 18:06:14 +00:00
|
|
|
if runtime.GOOS == "darwin" && testBackend == "native" {
|
2018-08-29 18:30:37 +00:00
|
|
|
t.Skip("this backend does not support function calls")
|
2018-07-28 19:12:07 +00:00
|
|
|
}
|
2019-12-27 14:59:01 +00:00
|
|
|
|
2023-09-21 17:39:57 +00:00
|
|
|
if runtime.GOARCH == "386" {
|
2020-03-19 19:27:31 +00:00
|
|
|
t.Skip(fmt.Errorf("%s does not support FunctionCall for now", runtime.GOARCH))
|
|
|
|
}
|
2024-10-11 19:34:25 +00:00
|
|
|
if runtime.GOARCH == "riscv64" {
|
|
|
|
t.Skip(fmt.Errorf("%s does not support FunctionCall for now", runtime.GOARCH))
|
|
|
|
}
|
2022-05-03 17:46:24 +00:00
|
|
|
if runtime.GOARCH == "arm64" {
|
2022-12-05 23:21:52 +00:00
|
|
|
if !goversion.VersionAfterOrEqual(runtime.Version(), 1, 19) || runtime.GOOS == "windows" {
|
2022-05-03 17:46:24 +00:00
|
|
|
t.Skip("this version of Go does not support function calls")
|
|
|
|
}
|
|
|
|
}
|
2023-09-21 17:39:57 +00:00
|
|
|
|
|
|
|
if runtime.GOARCH == "ppc64le" {
|
|
|
|
if !goversion.VersionAfterOrEqual(runtime.Version(), 1, 22) {
|
|
|
|
t.Skip("On PPC64LE Building with Go lesser than 1.22 does not support function calls")
|
|
|
|
}
|
|
|
|
}
|
2018-07-28 19:12:07 +00:00
|
|
|
}
|
2018-10-01 08:19:06 +00:00
|
|
|
|
|
|
|
// DefaultTestBackend changes the value of testBackend to be the default
|
|
|
|
// test backend for the OS, if testBackend isn't already set.
|
|
|
|
func DefaultTestBackend(testBackend *string) {
|
|
|
|
if *testBackend != "" {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
*testBackend = os.Getenv("PROCTEST")
|
|
|
|
if *testBackend != "" {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if runtime.GOOS == "darwin" {
|
|
|
|
*testBackend = "lldb"
|
|
|
|
} else {
|
|
|
|
*testBackend = "native"
|
|
|
|
}
|
|
|
|
}
|
2019-03-20 17:32:51 +00:00
|
|
|
|
|
|
|
// WithPlugins builds the fixtures in plugins as plugins and returns them.
|
|
|
|
// The test calling WithPlugins will be skipped if the current combination
|
|
|
|
// of OS, architecture and version of GO doesn't support plugins or
|
|
|
|
// debugging plugins.
|
2019-06-30 17:34:47 +00:00
|
|
|
func WithPlugins(t *testing.T, flags BuildFlags, plugins ...string) []Fixture {
|
2019-03-20 17:32:51 +00:00
|
|
|
if !goversion.VersionAfterOrEqual(runtime.Version(), 1, 12) {
|
|
|
|
t.Skip("versions of Go before 1.12 do not include debug information in packages that import plugin (or they do but it's wrong)")
|
|
|
|
}
|
|
|
|
if runtime.GOOS != "linux" {
|
|
|
|
t.Skip("only supported on linux")
|
|
|
|
}
|
|
|
|
|
|
|
|
r := make([]Fixture, len(plugins))
|
|
|
|
for i := range plugins {
|
2019-06-30 17:34:47 +00:00
|
|
|
r[i] = BuildFixture(plugins[i], flags|BuildModePlugin)
|
2019-03-20 17:32:51 +00:00
|
|
|
}
|
|
|
|
return r
|
|
|
|
}
|
2020-04-16 17:42:22 +00:00
|
|
|
|
|
|
|
var hasCgo = func() bool {
|
|
|
|
out, err := exec.Command("go", "env", "CGO_ENABLED").CombinedOutput()
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
2021-08-04 21:12:15 +00:00
|
|
|
if strings.TrimSpace(string(out)) != "1" {
|
|
|
|
return false
|
|
|
|
}
|
2023-06-07 03:50:03 +00:00
|
|
|
_, err1 := exec.LookPath("gcc")
|
|
|
|
_, err2 := exec.LookPath("clang")
|
|
|
|
return (err1 == nil) || (err2 == nil)
|
2020-04-16 17:42:22 +00:00
|
|
|
}()
|
|
|
|
|
|
|
|
func MustHaveCgo(t *testing.T) {
|
|
|
|
if !hasCgo {
|
|
|
|
t.Skip("Cgo not enabled")
|
|
|
|
}
|
|
|
|
}
|
2021-08-24 15:21:17 +00:00
|
|
|
|
|
|
|
func RegabiSupported() bool {
|
|
|
|
// Tracks regabiSupported variable in ParseGOEXPERIMENT internal/buildcfg/exp.go
|
|
|
|
switch {
|
2021-12-22 18:26:21 +00:00
|
|
|
case goversion.VersionAfterOrEqual(runtime.Version(), 1, 18):
|
2024-10-11 19:34:25 +00:00
|
|
|
return runtime.GOARCH == "amd64" || runtime.GOARCH == "arm64" || runtime.GOARCH == "ppc64le" || runtime.GOARCH == "ppc64" || runtime.GOARCH == "riscv64"
|
2021-09-17 06:47:46 +00:00
|
|
|
case goversion.VersionAfterOrEqual(runtime.Version(), 1, 17):
|
2021-08-24 15:21:17 +00:00
|
|
|
return runtime.GOARCH == "amd64" && (runtime.GOOS == "android" || runtime.GOOS == "linux" || runtime.GOOS == "darwin" || runtime.GOOS == "windows")
|
2021-12-22 18:26:21 +00:00
|
|
|
default:
|
|
|
|
return false
|
2021-08-24 15:21:17 +00:00
|
|
|
}
|
|
|
|
}
|
2024-10-31 17:19:08 +00:00
|
|
|
|
|
|
|
func ProjectRoot() string {
|
|
|
|
wd, err := os.Getwd()
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
gopaths := strings.FieldsFunc(os.Getenv("GOPATH"), func(r rune) bool { return r == os.PathListSeparator })
|
|
|
|
for _, curpath := range gopaths {
|
|
|
|
// Detects "gopath mode" when GOPATH contains several paths ex. "d:\\dir\\gopath;f:\\dir\\gopath2"
|
|
|
|
if strings.Contains(wd, curpath) {
|
|
|
|
return filepath.Join(curpath, "src", "github.com", "go-delve", "delve")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
val, err := exec.Command("go", "list", "-mod=", "-m", "-f", "{{ .Dir }}").Output()
|
|
|
|
if err != nil {
|
|
|
|
panic(err) // the Go tool was tested to work earlier
|
|
|
|
}
|
|
|
|
return strings.TrimSuffix(string(val), "\n")
|
|
|
|
}
|
|
|
|
|
|
|
|
func GetDlvBinary(t *testing.T) string {
|
|
|
|
// In case this was set in the environment
|
|
|
|
// from getDlvBinEBPF lets clear it here, so
|
|
|
|
// we can ensure we don't get build errors
|
|
|
|
// depending on the test ordering.
|
|
|
|
t.Setenv("CGO_LDFLAGS", ldFlags)
|
|
|
|
var tags []string
|
|
|
|
if runtime.GOOS == "windows" && runtime.GOARCH == "arm64" {
|
|
|
|
tags = []string{"-tags=exp.winarm64"}
|
|
|
|
}
|
|
|
|
if runtime.GOOS == "linux" && runtime.GOARCH == "ppc64le" {
|
|
|
|
tags = []string{"-tags=exp.linuxppc64le"}
|
|
|
|
}
|
|
|
|
if runtime.GOOS == "linux" && runtime.GOARCH == "riscv64" {
|
|
|
|
tags = []string{"-tags=exp.linuxriscv64"}
|
|
|
|
}
|
|
|
|
return getDlvBinInternal(t, tags...)
|
|
|
|
}
|
|
|
|
|
|
|
|
func GetDlvBinaryEBPF(t *testing.T) string {
|
|
|
|
return getDlvBinInternal(t, "-tags", "ebpf")
|
|
|
|
}
|
|
|
|
|
|
|
|
func getDlvBinInternal(t *testing.T, goflags ...string) string {
|
|
|
|
dlvbin := filepath.Join(t.TempDir(), "dlv.exe")
|
|
|
|
args := append([]string{"build", "-o", dlvbin}, goflags...)
|
|
|
|
args = append(args, "github.com/go-delve/delve/cmd/dlv")
|
|
|
|
|
|
|
|
wd, _ := os.Getwd()
|
|
|
|
fmt.Printf("at %s %s\n", wd, goflags)
|
|
|
|
|
|
|
|
out, err := exec.Command("go", args...).CombinedOutput()
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("go build -o %v github.com/go-delve/delve/cmd/dlv: %v\n%s", dlvbin, err, string(out))
|
|
|
|
}
|
|
|
|
|
|
|
|
return dlvbin
|
|
|
|
}
|