
The step command is changed such that when the function being currently called is a coroutine switch function it will move to the associated coroutine. Functions that switch coroutines are currently the next, stop and yield closures produced by the iter.Pull function.
1789 lines
46 KiB
Go
1789 lines
46 KiB
Go
package proc_test
|
|
|
|
import (
|
|
"fmt"
|
|
"go/constant"
|
|
"path/filepath"
|
|
"runtime"
|
|
"strconv"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/go-delve/delve/pkg/goversion"
|
|
"github.com/go-delve/delve/pkg/proc"
|
|
protest "github.com/go-delve/delve/pkg/proc/test"
|
|
"github.com/go-delve/delve/service/api"
|
|
)
|
|
|
|
type nextTest struct {
|
|
begin, end int
|
|
}
|
|
|
|
type contFunc int
|
|
|
|
const (
|
|
contContinue contFunc = iota
|
|
contNext
|
|
contStep
|
|
contStepout
|
|
contReverseNext
|
|
contReverseStep
|
|
contReverseStepout
|
|
contContinueToBreakpoint
|
|
contNothing
|
|
)
|
|
|
|
type seqTest struct {
|
|
cf contFunc
|
|
pos interface{}
|
|
}
|
|
|
|
func testseq(program string, contFunc contFunc, testcases []nextTest, initialLocation string, t *testing.T) {
|
|
seqTestcases := make([]seqTest, len(testcases)+1)
|
|
seqTestcases[0] = seqTest{contContinue, testcases[0].begin}
|
|
for i := range testcases {
|
|
if i > 0 {
|
|
if testcases[i-1].end != testcases[i].begin {
|
|
panic(fmt.Errorf("begin/end mismatch at index %d", i))
|
|
}
|
|
}
|
|
seqTestcases[i+1] = seqTest{contFunc, testcases[i].end}
|
|
}
|
|
testseq2(t, program, initialLocation, seqTestcases)
|
|
}
|
|
|
|
const traceTestseq2 = true
|
|
|
|
func testseq2(t *testing.T, program string, initialLocation string, testcases []seqTest) {
|
|
testseq2Args(".", []string{}, 0, t, program, initialLocation, testcases)
|
|
}
|
|
|
|
func testseq2Args(wd string, args []string, buildFlags protest.BuildFlags, t *testing.T, program string, initialLocation string, testcases []seqTest) {
|
|
protest.AllowRecording(t)
|
|
t.Helper()
|
|
withTestProcessArgs(program, t, wd, args, buildFlags, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
|
|
checkBreakpointClear := true
|
|
var bp *proc.Breakpoint
|
|
if initialLocation != "" {
|
|
bp = setFunctionBreakpoint(p, t, initialLocation)
|
|
} else if testcases[0].cf == contContinue {
|
|
bp = setFileBreakpoint(p, t, fixture.Source, testcases[0].pos.(int))
|
|
} else if testcases[0].cf == contNothing {
|
|
// Do nothing
|
|
checkBreakpointClear = false
|
|
} else {
|
|
panic("testseq2 can not set initial breakpoint")
|
|
}
|
|
if traceTestseq2 {
|
|
t.Logf("initial breakpoint %v", bp)
|
|
}
|
|
|
|
testseq2intl(t, fixture, grp, p, bp, testcases)
|
|
|
|
if countBreakpoints(p) != 0 && checkBreakpointClear {
|
|
t.Fatal("Not all breakpoints were cleaned up", len(p.Breakpoints().M))
|
|
}
|
|
})
|
|
}
|
|
|
|
func testseq2intl(t *testing.T, fixture protest.Fixture, grp *proc.TargetGroup, p *proc.Target, bp *proc.Breakpoint, testcases []seqTest) {
|
|
f, ln := currentLineNumber(p, t)
|
|
for i, tc := range testcases {
|
|
switch tc.cf {
|
|
case contNext:
|
|
if traceTestseq2 {
|
|
t.Log("next")
|
|
}
|
|
assertNoError(grp.Next(), t, "Next() returned an error")
|
|
case contStep:
|
|
if traceTestseq2 {
|
|
t.Log("step")
|
|
}
|
|
assertNoError(grp.Step(), t, "Step() returned an error")
|
|
case contStepout:
|
|
if traceTestseq2 {
|
|
t.Log("stepout")
|
|
}
|
|
assertNoError(grp.StepOut(), t, "StepOut() returned an error")
|
|
case contContinue:
|
|
if traceTestseq2 {
|
|
t.Log("continue")
|
|
}
|
|
assertNoError(grp.Continue(), t, "Continue() returned an error")
|
|
if i == 0 {
|
|
if traceTestseq2 {
|
|
t.Log("clearing initial breakpoint")
|
|
}
|
|
err := p.ClearBreakpoint(bp.Addr)
|
|
assertNoError(err, t, "ClearBreakpoint() returned an error")
|
|
}
|
|
case contReverseNext:
|
|
if traceTestseq2 {
|
|
t.Log("reverse-next")
|
|
}
|
|
assertNoError(grp.ChangeDirection(proc.Backward), t, "direction switch")
|
|
assertNoError(grp.Next(), t, "reverse Next() returned an error")
|
|
assertNoError(grp.ChangeDirection(proc.Forward), t, "direction switch")
|
|
case contReverseStep:
|
|
if traceTestseq2 {
|
|
t.Log("reverse-step")
|
|
}
|
|
assertNoError(grp.ChangeDirection(proc.Backward), t, "direction switch")
|
|
assertNoError(grp.Step(), t, "reverse Step() returned an error")
|
|
assertNoError(grp.ChangeDirection(proc.Forward), t, "direction switch")
|
|
case contReverseStepout:
|
|
if traceTestseq2 {
|
|
t.Log("reverse-stepout")
|
|
}
|
|
assertNoError(grp.ChangeDirection(proc.Backward), t, "direction switch")
|
|
assertNoError(grp.StepOut(), t, "reverse StepOut() returned an error")
|
|
assertNoError(grp.ChangeDirection(proc.Forward), t, "direction switch")
|
|
case contContinueToBreakpoint:
|
|
bp := setFileBreakpoint(p, t, fixture.Source, tc.pos.(int))
|
|
if traceTestseq2 {
|
|
t.Log("continue")
|
|
}
|
|
assertNoError(grp.Continue(), t, "Continue() returned an error")
|
|
err := p.ClearBreakpoint(bp.Addr)
|
|
assertNoError(err, t, "ClearBreakpoint() returned an error")
|
|
case contNothing:
|
|
// do nothing
|
|
}
|
|
|
|
if err := p.CurrentThread().Breakpoint().CondError; err != nil {
|
|
t.Logf("breakpoint condition error: %v", err)
|
|
}
|
|
|
|
f, ln = currentLineNumber(p, t)
|
|
regs, _ := p.CurrentThread().Registers()
|
|
pc := regs.PC()
|
|
_, _, fn := p.BinInfo().PCToLine(pc)
|
|
|
|
if traceTestseq2 {
|
|
fnname := "?"
|
|
if fn != nil {
|
|
fnname = fn.Name
|
|
}
|
|
t.Logf("at %#x (%s) %s:%d", pc, fnname, f, ln)
|
|
}
|
|
switch pos := tc.pos.(type) {
|
|
case int:
|
|
if pos >= 0 && ln != pos {
|
|
t.Fatalf("Program did not continue to correct next location expected %d was %s:%d (%#x) (testcase %d)", pos, filepath.Base(f), ln, pc, i)
|
|
}
|
|
case string:
|
|
v := strings.Split(pos, ":")
|
|
tgtln, _ := strconv.Atoi(v[1])
|
|
if !strings.HasSuffix(f, v[0]) || (ln != tgtln) {
|
|
t.Fatalf("Program did not continue to correct next location, expected %s was %s:%d (%#x) (testcase %d)", pos, filepath.Base(f), ln, pc, i)
|
|
}
|
|
case func(*proc.Target):
|
|
pos(p)
|
|
case func(*proc.TargetGroup, *proc.Target):
|
|
pos(grp, p)
|
|
default:
|
|
panic(fmt.Errorf("unexpected type %T", pos))
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestNextGeneral(t *testing.T) {
|
|
var testcases []nextTest
|
|
|
|
ver, _ := goversion.Parse(runtime.Version())
|
|
|
|
if ver.Major < 0 || ver.AfterOrEqual(goversion.GoVersion{Major: 1, Minor: 7, Rev: -1}) {
|
|
testcases = []nextTest{
|
|
{17, 19},
|
|
{19, 20},
|
|
{20, 23},
|
|
{23, 24},
|
|
{24, 26},
|
|
{26, 31},
|
|
{31, 23},
|
|
{23, 24},
|
|
{24, 26},
|
|
{26, 31},
|
|
{31, 23},
|
|
{23, 24},
|
|
{24, 26},
|
|
{26, 27},
|
|
{27, 28},
|
|
{28, 34},
|
|
}
|
|
} else {
|
|
testcases = []nextTest{
|
|
{17, 19},
|
|
{19, 20},
|
|
{20, 23},
|
|
{23, 24},
|
|
{24, 26},
|
|
{26, 31},
|
|
{31, 23},
|
|
{23, 24},
|
|
{24, 26},
|
|
{26, 31},
|
|
{31, 23},
|
|
{23, 24},
|
|
{24, 26},
|
|
{26, 27},
|
|
{27, 34},
|
|
}
|
|
}
|
|
|
|
testseq("testnextprog", contNext, testcases, "main.testnext", t)
|
|
}
|
|
|
|
func TestNextFunctionReturn(t *testing.T) {
|
|
testcases := []nextTest{
|
|
{13, 14},
|
|
{14, 15},
|
|
{15, 35},
|
|
}
|
|
protest.AllowRecording(t)
|
|
testseq("testnextprog", contNext, testcases, "main.helloworld", t)
|
|
}
|
|
|
|
func TestNextFunctionReturnDefer(t *testing.T) {
|
|
var testcases []nextTest
|
|
|
|
ver, _ := goversion.Parse(runtime.Version())
|
|
|
|
if ver.Major < 0 || ver.AfterOrEqual(goversion.GoVersion{Major: 1, Minor: 9, Rev: -1}) {
|
|
testcases = []nextTest{
|
|
{5, 6},
|
|
{6, 9},
|
|
{9, 10},
|
|
}
|
|
} else {
|
|
testcases = []nextTest{
|
|
{5, 8},
|
|
{8, 9},
|
|
{9, 10},
|
|
}
|
|
}
|
|
protest.AllowRecording(t)
|
|
testseq("testnextdefer", contNext, testcases, "main.main", t)
|
|
}
|
|
|
|
func TestNextDeferReturnAndDirectCall(t *testing.T) {
|
|
// Next should not step into a deferred function if it is called
|
|
// directly, only if it is called through a panic or a deferreturn.
|
|
// Here we test the case where the function is called by a deferreturn
|
|
testseq("defercall", contNext, []nextTest{
|
|
{9, 10},
|
|
{10, 11},
|
|
{11, 12},
|
|
{12, 13},
|
|
{13, 28}}, "main.callAndDeferReturn", t)
|
|
}
|
|
|
|
func TestNextPanicAndDirectCall(t *testing.T) {
|
|
// Next should not step into a deferred function if it is called
|
|
// directly, only if it is called through a panic or a deferreturn.
|
|
// Here we test the case where the function is called by a panic
|
|
testseq("defercall", contNext, []nextTest{
|
|
{15, 16},
|
|
{16, 17},
|
|
{17, 18},
|
|
{18, 6}}, "main.callAndPanic2", t)
|
|
}
|
|
|
|
func TestStepCall(t *testing.T) {
|
|
testseq("testnextprog", contStep, []nextTest{
|
|
{34, 13},
|
|
{13, 14}}, "", t)
|
|
}
|
|
|
|
func TestStepCallPtr(t *testing.T) {
|
|
// Tests that Step works correctly when calling functions with a
|
|
// function pointer.
|
|
if goversion.VersionAfterOrEqual(runtime.Version(), 1, 11) && !protest.RegabiSupported() {
|
|
testseq("teststepprog", contStep, []nextTest{
|
|
{9, 10},
|
|
{10, 6},
|
|
{6, 7},
|
|
{7, 11}}, "", t)
|
|
} else {
|
|
if runtime.GOOS == "linux" && runtime.GOARCH == "ppc64le" && buildMode == "pie" {
|
|
testseq("teststepprog", contStep, []nextTest{
|
|
{9, 10},
|
|
{10, 5},
|
|
{5, 6},
|
|
{6, 7},
|
|
{7, 10},
|
|
{10, 11}}, "", t)
|
|
} else {
|
|
testseq("teststepprog", contStep, []nextTest{
|
|
{9, 10},
|
|
{10, 5},
|
|
{5, 6},
|
|
{6, 7},
|
|
{7, 11}}, "", t)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestStepReturnAndPanic(t *testing.T) {
|
|
// Tests that Step works correctly when returning from functions
|
|
// and when a deferred function is called when panic'ing.
|
|
testseq("defercall", contStep, []nextTest{
|
|
{17, 6},
|
|
{6, 7},
|
|
{7, 18},
|
|
{18, 6},
|
|
{6, 7}}, "", t)
|
|
}
|
|
|
|
func TestStepDeferReturn(t *testing.T) {
|
|
// Tests that Step works correctly when a deferred function is
|
|
// called during a return.
|
|
testseq("defercall", contStep, []nextTest{
|
|
{11, 6},
|
|
{6, 7},
|
|
{7, 12},
|
|
{12, 13},
|
|
{13, 6},
|
|
{6, 7},
|
|
{7, 13},
|
|
{13, 28}}, "", t)
|
|
}
|
|
|
|
func TestStepIgnorePrivateRuntime(t *testing.T) {
|
|
// Tests that Step will ignore calls to private runtime functions
|
|
// (such as runtime.convT2E in this case)
|
|
switch {
|
|
case goversion.VersionAfterOrEqual(runtime.Version(), 1, 17) && protest.RegabiSupported():
|
|
testseq("teststepprog", contStep, []nextTest{
|
|
{21, 13},
|
|
{13, 14},
|
|
{14, 15},
|
|
{15, 17},
|
|
{17, 22}}, "", t)
|
|
case goversion.VersionAfterOrEqual(runtime.Version(), 1, 17):
|
|
testseq("teststepprog", contStep, []nextTest{
|
|
{21, 14},
|
|
{14, 15},
|
|
{15, 17},
|
|
{17, 22}}, "", t)
|
|
case goversion.VersionAfterOrEqual(runtime.Version(), 1, 11):
|
|
testseq("teststepprog", contStep, []nextTest{
|
|
{21, 14},
|
|
{14, 15},
|
|
{15, 22}}, "", t)
|
|
default:
|
|
panic("too old")
|
|
}
|
|
}
|
|
|
|
func TestInlineStep(t *testing.T) {
|
|
skipOn(t, "broken", "ppc64le")
|
|
if ver, _ := goversion.Parse(runtime.Version()); ver.Major >= 0 && !ver.AfterOrEqual(goversion.GoVersion{Major: 1, Minor: 10, Rev: -1}) {
|
|
// Versions of go before 1.10 do not have DWARF information for inlined calls
|
|
t.Skip("inlining not supported")
|
|
}
|
|
testseq2Args(".", []string{}, protest.EnableInlining, t, "testinline", "", []seqTest{
|
|
{contContinue, 18},
|
|
{contStep, 6},
|
|
{contStep, 7},
|
|
{contStep, 24},
|
|
{contStep, 25},
|
|
{contStep, 7},
|
|
{contStep, 18},
|
|
{contStep, 19},
|
|
})
|
|
}
|
|
|
|
func TestInlineNext(t *testing.T) {
|
|
if ver, _ := goversion.Parse(runtime.Version()); ver.Major >= 0 && !ver.AfterOrEqual(goversion.GoVersion{Major: 1, Minor: 10, Rev: -1}) {
|
|
// Versions of go before 1.10 do not have DWARF information for inlined calls
|
|
t.Skip("inlining not supported")
|
|
}
|
|
testseq2Args(".", []string{}, protest.EnableInlining, t, "testinline", "", []seqTest{
|
|
{contContinue, 18},
|
|
{contStep, 6},
|
|
{contNext, 7},
|
|
{contNext, 18},
|
|
{contNext, 19},
|
|
})
|
|
}
|
|
|
|
func TestInlineStepOver(t *testing.T) {
|
|
if ver, _ := goversion.Parse(runtime.Version()); ver.Major >= 0 && !ver.AfterOrEqual(goversion.GoVersion{Major: 1, Minor: 10, Rev: -1}) {
|
|
// Versions of go before 1.10 do not have DWARF information for inlined calls
|
|
t.Skip("inlining not supported")
|
|
}
|
|
testseq2Args(".", []string{}, protest.EnableInlining, t, "testinline", "", []seqTest{
|
|
{contContinue, 18},
|
|
{contNext, 19},
|
|
{contNext, 20},
|
|
})
|
|
}
|
|
|
|
func TestInlineStepOut(t *testing.T) {
|
|
if ver, _ := goversion.Parse(runtime.Version()); ver.Major >= 0 && !ver.AfterOrEqual(goversion.GoVersion{Major: 1, Minor: 10, Rev: -1}) {
|
|
// Versions of go before 1.10 do not have DWARF information for inlined calls
|
|
t.Skip("inlining not supported")
|
|
}
|
|
testseq2Args(".", []string{}, protest.EnableInlining, t, "testinline", "", []seqTest{
|
|
{contContinue, 18},
|
|
{contStep, 6},
|
|
{contStepout, 18},
|
|
})
|
|
}
|
|
|
|
func TestBackwardNextGeneral(t *testing.T) {
|
|
if testBackend != "rr" {
|
|
t.Skip("Reverse stepping test needs rr")
|
|
}
|
|
testseq2(t, "testnextprog", "main.helloworld", []seqTest{
|
|
{contContinue, 13},
|
|
{contNext, 14},
|
|
{contReverseNext, 13},
|
|
{contReverseNext, 34},
|
|
{contReverseNext, 28},
|
|
{contReverseNext, 27},
|
|
{contReverseNext, 26},
|
|
{contReverseNext, 24},
|
|
{contReverseNext, 23},
|
|
{contReverseNext, 31},
|
|
{contReverseNext, 26},
|
|
{contReverseNext, 24},
|
|
{contReverseNext, 23},
|
|
{contReverseNext, 31},
|
|
{contReverseNext, 26},
|
|
{contReverseNext, 24},
|
|
{contReverseNext, 23},
|
|
{contReverseNext, 20},
|
|
{contReverseNext, 19},
|
|
{contReverseNext, 17},
|
|
{contReverseNext, 39},
|
|
{contReverseNext, 38},
|
|
{contReverseNext, 37},
|
|
})
|
|
}
|
|
|
|
func TestBackwardStepOutGeneral(t *testing.T) {
|
|
if testBackend != "rr" {
|
|
t.Skip("Reverse stepping test needs rr")
|
|
}
|
|
testseq2(t, "testnextprog", "main.helloworld", []seqTest{
|
|
{contContinue, 13},
|
|
{contNext, 14},
|
|
{contReverseStepout, 34},
|
|
{contReverseStepout, 39},
|
|
})
|
|
}
|
|
|
|
func TestBackwardStepGeneral(t *testing.T) {
|
|
if testBackend != "rr" {
|
|
t.Skip("Reverse stepping test needs rr")
|
|
}
|
|
testseq2(t, "testnextprog", "main.helloworld", []seqTest{
|
|
{contContinue, 13},
|
|
{contNext, 14},
|
|
{contReverseStep, 13},
|
|
{contReverseStep, 34},
|
|
{contReverseStep, 28},
|
|
{contReverseNext, 27}, // skip fmt.Printf
|
|
{contReverseStep, 26},
|
|
{contReverseStep, 24},
|
|
{contReverseStep, 23},
|
|
{contReverseStep, 11},
|
|
{contReverseNext, 10}, // skip time.Sleep
|
|
{contReverseStep, 9},
|
|
|
|
{contReverseStep, 31},
|
|
{contReverseStep, 26},
|
|
{contReverseStep, 24},
|
|
{contReverseStep, 23},
|
|
{contReverseStep, 11},
|
|
{contReverseNext, 10}, // skip time.Sleep
|
|
{contReverseStep, 9},
|
|
|
|
{contReverseStep, 31},
|
|
{contReverseStep, 26},
|
|
{contReverseStep, 24},
|
|
{contReverseStep, 23},
|
|
{contReverseStep, 20},
|
|
{contReverseStep, 19},
|
|
{contReverseStep, 17},
|
|
{contReverseStep, 39},
|
|
{contReverseStep, 38},
|
|
{contReverseStep, 37},
|
|
})
|
|
}
|
|
|
|
func TestBackwardNextDeferPanic(t *testing.T) {
|
|
if testBackend != "rr" {
|
|
t.Skip("Reverse stepping test needs rr")
|
|
}
|
|
if goversion.VersionAfterOrEqual(runtime.Version(), 1, 18) {
|
|
testseq2(t, "defercall", "", []seqTest{
|
|
{contContinue, 12},
|
|
{contReverseNext, 11},
|
|
{contReverseNext, 10},
|
|
{contReverseNext, 9},
|
|
{contReverseNext, 27},
|
|
|
|
{contContinueToBreakpoint, 12}, // skip first call to sampleFunction
|
|
{contContinueToBreakpoint, 6}, // go to call to sampleFunction through deferreturn
|
|
{contReverseNext, -1}, // runtime.deferreturn, maybe we should try to skip this
|
|
{contReverseStepout, 13},
|
|
{contReverseNext, 12},
|
|
{contReverseNext, 11},
|
|
{contReverseNext, 10},
|
|
{contReverseNext, 9},
|
|
{contReverseNext, 27},
|
|
|
|
{contContinueToBreakpoint, 18}, // go to panic call
|
|
{contNext, 6}, // panic so the deferred call happens
|
|
{contReverseNext, 18},
|
|
{contReverseNext, 17},
|
|
{contReverseNext, 16},
|
|
{contReverseNext, 15},
|
|
{contReverseNext, 23},
|
|
{contReverseNext, 22},
|
|
{contReverseNext, 21},
|
|
{contReverseNext, 28},
|
|
})
|
|
} else {
|
|
testseq2(t, "defercall", "", []seqTest{
|
|
{contContinue, 12},
|
|
{contReverseNext, 11},
|
|
{contReverseNext, 10},
|
|
{contReverseNext, 9},
|
|
{contReverseNext, 27},
|
|
|
|
{contContinueToBreakpoint, 12}, // skip first call to sampleFunction
|
|
{contContinueToBreakpoint, 6}, // go to call to sampleFunction through deferreturn
|
|
{contReverseNext, 13},
|
|
{contReverseNext, 12},
|
|
{contReverseNext, 11},
|
|
{contReverseNext, 10},
|
|
{contReverseNext, 9},
|
|
{contReverseNext, 27},
|
|
|
|
{contContinueToBreakpoint, 18}, // go to panic call
|
|
{contNext, 6}, // panic so the deferred call happens
|
|
{contReverseNext, 18},
|
|
{contReverseNext, 17},
|
|
{contReverseNext, 16},
|
|
{contReverseNext, 15},
|
|
{contReverseNext, 23},
|
|
{contReverseNext, 22},
|
|
{contReverseNext, 21},
|
|
{contReverseNext, 28},
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestStepIntoWrapperForEmbeddedPointer(t *testing.T) {
|
|
skipOn(t, "N/A", "linux", "386", "pie") // skipping wrappers doesn't work on linux/386/PIE due to the use of get_pc_thunk
|
|
// Under some circumstances (when using an interface to call a method on an
|
|
// embedded field, see _fixtures/ifaceembcall.go) the compiler will
|
|
// autogenerate a wrapper function that uses a tail call (i.e. it ends in
|
|
// an unconditional jump instruction to a different function).
|
|
// Delve should be able to step into this tail call.
|
|
testseq2(t, "ifaceembcall", "", []seqTest{
|
|
{contContinue, 28}, // main.main, the line calling iface.PtrReceiver()
|
|
{contStep, 18}, // main.(*A).PtrReceiver
|
|
{contStep, 19},
|
|
{contStepout, 28},
|
|
{contContinueToBreakpoint, 29}, // main.main, the line calling iface.NonPtrReceiver()
|
|
{contStep, 22}, // main.(A).NonPtrReceiver
|
|
{contStep, 23},
|
|
{contStepout, 29}})
|
|
|
|
// same test but with next instead of stepout
|
|
if goversion.VersionAfterOrEqual(runtime.Version(), 1, 14) && runtime.GOARCH != "386" && !goversion.VersionAfterOrEqualRev(runtime.Version(), 1, 15, 4) {
|
|
// Line numbers generated for versions 1.14 through 1.15.3 on any system except linux/386
|
|
testseq2(t, "ifaceembcall", "", []seqTest{
|
|
{contContinue, 28}, // main.main, the line calling iface.PtrReceiver()
|
|
{contStep, 18}, // main.(*A).PtrReceiver
|
|
{contNext, 19},
|
|
{contNext, 19},
|
|
{contNext, 28},
|
|
{contContinueToBreakpoint, 29}, // main.main, the line calling iface.NonPtrReceiver()
|
|
{contStep, 22},
|
|
{contNext, 23},
|
|
{contNext, 23},
|
|
{contNext, 29},
|
|
})
|
|
} else {
|
|
testseq2(t, "ifaceembcall", "", []seqTest{
|
|
{contContinue, 28}, // main.main, the line calling iface.PtrReceiver()
|
|
{contStep, 18}, // main.(*A).PtrReceiver
|
|
{contNext, 19},
|
|
{contNext, 28},
|
|
{contContinueToBreakpoint, 29}, // main.main, the line calling iface.NonPtrReceiver()
|
|
{contStep, 22},
|
|
{contNext, 23},
|
|
{contNext, 29},
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestNextGenericMethodThroughInterface(t *testing.T) {
|
|
// Tests that autogenerated wrappers for generic methods called through an
|
|
// interface are skipped.
|
|
|
|
varcheck := func(p *proc.Target) {
|
|
yvar := evalVariable(p, t, "y")
|
|
yval, _ := constant.Int64Val(yvar.Value)
|
|
if yval != 2 {
|
|
t.Errorf("expected 2 got %#v", yvar.Value)
|
|
}
|
|
}
|
|
|
|
if runtime.GOOS == "linux" && runtime.GOARCH == "386" {
|
|
testseq2(t, "genericintoiface", "main.callf", []seqTest{
|
|
{contContinue, 17},
|
|
{contStep, 18},
|
|
{contStep, 10},
|
|
{contNothing, varcheck},
|
|
{contNext, 11},
|
|
{contNext, 19},
|
|
})
|
|
} else {
|
|
testseq2(t, "genericintoiface", "main.callf", []seqTest{
|
|
{contContinue, 17},
|
|
{contStep, 18},
|
|
{contStep, 9},
|
|
{contNext, 10},
|
|
{contNothing, varcheck},
|
|
{contNext, 11},
|
|
{contNext, 19},
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestRangeOverFuncNext(t *testing.T) {
|
|
if !goversion.VersionAfterOrEqual(runtime.Version(), 1, 23) {
|
|
t.Skip("N/A")
|
|
}
|
|
|
|
var bp *proc.Breakpoint
|
|
|
|
funcBreak := func(t *testing.T, fnname string) seqTest {
|
|
return seqTest{
|
|
contNothing,
|
|
func(p *proc.Target) {
|
|
bp = setFunctionBreakpoint(p, t, fnname)
|
|
}}
|
|
}
|
|
|
|
clearBreak := func(t *testing.T) seqTest {
|
|
return seqTest{
|
|
contNothing,
|
|
func(p *proc.Target) {
|
|
assertNoError(p.ClearBreakpoint(bp.Addr), t, "ClearBreakpoint")
|
|
}}
|
|
}
|
|
|
|
notAtEntryPoint := func(t *testing.T) seqTest {
|
|
return seqTest{contNothing, func(p *proc.Target) {
|
|
pc := currentPC(p, t)
|
|
fn := p.BinInfo().PCToFunc(pc)
|
|
if pc == fn.Entry {
|
|
t.Fatalf("current PC is entry point")
|
|
}
|
|
}}
|
|
}
|
|
|
|
nx := func(n int) seqTest {
|
|
return seqTest{contNext, n}
|
|
}
|
|
|
|
assertLocals := func(t *testing.T, varnames ...string) seqTest {
|
|
return seqTest{
|
|
contNothing,
|
|
func(p *proc.Target) {
|
|
scope, err := proc.GoroutineScope(p, p.CurrentThread())
|
|
assertNoError(err, t, "GoroutineScope")
|
|
vars, err := scope.Locals(0, "")
|
|
assertNoError(err, t, "Locals")
|
|
|
|
gotnames := make([]string, len(vars))
|
|
for i := range vars {
|
|
gotnames[i] = vars[i].Name
|
|
}
|
|
|
|
ok := true
|
|
if len(vars) != len(varnames) {
|
|
ok = false
|
|
} else {
|
|
for i := range vars {
|
|
if vars[i].Name != varnames[i] {
|
|
ok = false
|
|
break
|
|
}
|
|
}
|
|
}
|
|
if !ok {
|
|
t.Errorf("Wrong variable names, expected %q, got %q", varnames, gotnames)
|
|
}
|
|
},
|
|
}
|
|
}
|
|
|
|
assertEval := func(t *testing.T, exprvals ...string) seqTest {
|
|
return seqTest{
|
|
contNothing,
|
|
func(p *proc.Target) {
|
|
scope, err := proc.GoroutineScope(p, p.CurrentThread())
|
|
assertNoError(err, t, "GoroutineScope")
|
|
for i := 0; i < len(exprvals); i += 2 {
|
|
expr, tgt := exprvals[i], exprvals[i+1]
|
|
v, err := scope.EvalExpression(expr, normalLoadConfig)
|
|
if err != nil {
|
|
t.Errorf("Could not evaluate %q: %v", expr, err)
|
|
} else {
|
|
out := api.ConvertVar(v).SinglelineString()
|
|
if out != tgt {
|
|
t.Errorf("Wrong value for %q, got %q expected %q", expr, out, tgt)
|
|
}
|
|
}
|
|
}
|
|
},
|
|
}
|
|
}
|
|
|
|
assertFunc := func(t *testing.T, fname string) seqTest {
|
|
return seqTest{
|
|
contNothing,
|
|
func(p *proc.Target) {
|
|
pc := currentPC(p, t)
|
|
fn := p.BinInfo().PCToFunc(pc)
|
|
if fn.Name != fname {
|
|
t.Errorf("Wrong function name, expected %s got %s", fname, fn.Name)
|
|
}
|
|
},
|
|
}
|
|
}
|
|
|
|
withTestProcessArgs("rangeoverfunc", t, ".", []string{}, 0, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
|
|
t.Run("TestTrickyIterAll1", func(t *testing.T) {
|
|
testseq2intl(t, fixture, grp, p, nil, []seqTest{
|
|
funcBreak(t, "main.TestTrickyIterAll"),
|
|
{contContinue, 24}, // TestTrickyIterAll
|
|
nx(25),
|
|
nx(26),
|
|
nx(27), // for _, x := range ...
|
|
assertLocals(t, "trickItAll", "i"),
|
|
assertEval(t, "i", "0"),
|
|
nx(28), // i += x
|
|
assertLocals(t, "trickItAll", "i", "x"),
|
|
assertEval(t,
|
|
"i", "0",
|
|
"x", "30"),
|
|
nx(29), // if i >= 36 {
|
|
nx(32),
|
|
nx(27), // for _, x := range ...
|
|
notAtEntryPoint(t),
|
|
nx(28), // i += x
|
|
assertEval(t,
|
|
"i", "30",
|
|
"x", "7"),
|
|
nx(29), // if i >= 36 {
|
|
nx(30), // break
|
|
nx(32),
|
|
nx(34), // fmt.Println
|
|
})
|
|
})
|
|
|
|
t.Run("TestTrickyIterAll2", func(t *testing.T) {
|
|
testseq2intl(t, fixture, grp, p, nil, []seqTest{
|
|
funcBreak(t, "main.TestTrickyIterAll2"),
|
|
{contContinue, 37}, // TestTrickyIterAll2
|
|
nx(38),
|
|
nx(39),
|
|
nx(40), // for _, x := range...
|
|
nx(41),
|
|
nx(42),
|
|
nx(40),
|
|
notAtEntryPoint(t),
|
|
nx(41),
|
|
nx(42),
|
|
nx(42), // different function from the one above...
|
|
nx(43),
|
|
})
|
|
})
|
|
|
|
t.Run("TestBreak1", func(t *testing.T) {
|
|
testseq2intl(t, fixture, grp, p, nil, []seqTest{
|
|
funcBreak(t, "main.TestBreak1"),
|
|
{contContinue, 46}, // TestBreak1
|
|
nx(47),
|
|
nx(48), // for _, x := range... (x == -1)
|
|
nx(49), // if x == -4
|
|
assertLocals(t, "result", "x"),
|
|
assertEval(t,
|
|
"result", "[]int len: 0, cap: 0, nil",
|
|
"x", "-1"),
|
|
|
|
nx(52), // for _, y := range... (y == 1)
|
|
nx(53), // if y == 3
|
|
assertLocals(t, "result", "x", "y"),
|
|
assertEval(t,
|
|
"result", "[]int len: 0, cap: 0, nil",
|
|
"x", "-1",
|
|
"y", "1"),
|
|
nx(56), // result = append(result, y)
|
|
nx(57),
|
|
nx(52), // for _, y := range... (y == 2)
|
|
notAtEntryPoint(t),
|
|
nx(53), // if y == 3
|
|
assertEval(t,
|
|
"x", "-1",
|
|
"y", "2"),
|
|
nx(56), // result = append(result, y)
|
|
nx(57),
|
|
nx(52), // for _, y := range... (y == 3)
|
|
nx(53), // if y == 3
|
|
assertEval(t,
|
|
"x", "-1",
|
|
"y", "3"),
|
|
nx(54), // break
|
|
nx(57),
|
|
nx(58), // result = append(result, x)
|
|
nx(59),
|
|
|
|
nx(48), // for _, x := range... (x == -2)
|
|
notAtEntryPoint(t),
|
|
nx(49), // if x == -4
|
|
assertEval(t,
|
|
"result", "[]int len: 3, cap: 4, [1,2,-1]",
|
|
"x", "-2"),
|
|
nx(52), // for _, y := range... (y == 1)
|
|
nx(53), // if y == 3
|
|
nx(56), // result = append(result, y)
|
|
nx(57),
|
|
nx(52), // for _, y := range... (y == 2)
|
|
notAtEntryPoint(t),
|
|
nx(53), // if y == 3
|
|
nx(56), // result = append(result, y)
|
|
nx(57),
|
|
nx(52), // for _, y := range... (y == 3)
|
|
nx(53), // if y == 3
|
|
nx(54), // break
|
|
nx(57),
|
|
nx(58), // result = append(result, x)
|
|
nx(59),
|
|
|
|
nx(48), // for _, x := range... (x == -4)
|
|
assertEval(t,
|
|
"result", "[]int len: 6, cap: 8, [1,2,-1,1,2,-2]",
|
|
"x", "-4"),
|
|
nx(49), // if x == -4
|
|
nx(50), // break
|
|
nx(59),
|
|
nx(60),
|
|
nx(61),
|
|
})
|
|
})
|
|
|
|
t.Run("TestBreak2", func(t *testing.T) {
|
|
testseq2intl(t, fixture, grp, p, nil, []seqTest{
|
|
funcBreak(t, "main.TestBreak2"),
|
|
|
|
{contContinue, 63}, // TestBreak2
|
|
nx(64),
|
|
nx(65),
|
|
|
|
nx(66), // for _, x := range (x == -1)
|
|
nx(67), // for _, y := range (y == 1)
|
|
nx(68), // if y == 3
|
|
nx(71), // if x == -4
|
|
nx(74), // result = append(result, y)
|
|
nx(75),
|
|
|
|
nx(67), // for _, y := range (y == 2)
|
|
nx(68), // if y == 3
|
|
nx(71), // if x == -4
|
|
nx(74), // result = append(result, y)
|
|
nx(75),
|
|
|
|
nx(67), // for _, y := range (y == 3)
|
|
nx(68), // if y == 3
|
|
nx(69), // break
|
|
nx(75),
|
|
nx(76), // result = append(result, x)
|
|
nx(77),
|
|
|
|
nx(66), // for _, x := range (x == -2)
|
|
nx(67), // for _, y := range (y == 1)
|
|
nx(68), // if y == 3
|
|
nx(71), // if x == -4
|
|
nx(74), // result = append(result, y)
|
|
nx(75),
|
|
|
|
nx(67), // for _, y := range (y == 2)
|
|
nx(68), // if y == 3
|
|
nx(71), // if x == -4
|
|
nx(74), // result = append(result, y)
|
|
nx(75),
|
|
|
|
nx(67), // for _, y := range (y == 3)
|
|
nx(68), // if y == 3
|
|
nx(69), // break
|
|
nx(75),
|
|
nx(76), // result = append(result, x)
|
|
nx(77),
|
|
|
|
nx(66), // for _, x := range (x == -4)
|
|
nx(67), // for _, y := range (y == 1)
|
|
nx(68), // if y == 3
|
|
nx(71), // if x == -4
|
|
nx(72), // break outer
|
|
nx(75),
|
|
nx(77),
|
|
nx(78),
|
|
nx(79),
|
|
})
|
|
})
|
|
|
|
t.Run("TestMultiCont0", func(t *testing.T) {
|
|
testseq2intl(t, fixture, grp, p, nil, []seqTest{
|
|
funcBreak(t, "main.TestMultiCont0"),
|
|
{contContinue, 81},
|
|
nx(82),
|
|
nx(84),
|
|
nx(85), // for _, w := range (w == 1000)
|
|
nx(86), // result = append(result, w)
|
|
assertEval(t,
|
|
"w", "1000",
|
|
"result", "[]int len: 0, cap: 10, []"),
|
|
nx(87), // if w == 2000
|
|
assertLocals(t, "result", "w"),
|
|
assertEval(t, "result", "[]int len: 1, cap: 10, [1000]"),
|
|
nx(90), // for _, x := range (x == 100)
|
|
nx(91), // for _, y := range (y == 10)
|
|
nx(92), // result = append(result, y)
|
|
assertLocals(t, "result", "w", "x", "y"),
|
|
assertEval(t,
|
|
"w", "1000",
|
|
"x", "100",
|
|
"y", "10"),
|
|
|
|
nx(93), // for _, z := range (z == 1)
|
|
nx(94), // if z&1 == 1
|
|
assertLocals(t, "result", "w", "x", "y", "z"),
|
|
assertEval(t,
|
|
"w", "1000",
|
|
"x", "100",
|
|
"y", "10",
|
|
"z", "1"),
|
|
nx(95), // continue
|
|
|
|
nx(93), // for _, z := range (z == 2)
|
|
nx(94), // if z&1 == 1
|
|
assertEval(t, "z", "2"),
|
|
nx(97), // result = append(result, z)
|
|
nx(98), // if z >= 4 {
|
|
nx(101),
|
|
|
|
nx(93), // for _, z := range (z == 3)
|
|
nx(94), // if z&1 == 1
|
|
assertEval(t, "z", "3"),
|
|
nx(95), // continue
|
|
|
|
nx(93), // for _, z := range (z == 4)
|
|
nx(94), // if z&1 == 1
|
|
assertEval(t, "z", "4"),
|
|
nx(97), // result = append(result, z)
|
|
assertEval(t, "result", "[]int len: 3, cap: 10, [1000,10,2]"),
|
|
nx(98), // if z >= 4 {
|
|
nx(99), // continue W
|
|
nx(101),
|
|
nx(103),
|
|
nx(105),
|
|
|
|
nx(85), // for _, w := range (w == 2000)
|
|
nx(86), // result = append(result, w)
|
|
nx(87), // if w == 2000
|
|
assertEval(t,
|
|
"w", "2000",
|
|
"result", "[]int len: 5, cap: 10, [1000,10,2,4,2000]"),
|
|
nx(88), // break
|
|
nx(106),
|
|
nx(107), // fmt.Println
|
|
})
|
|
})
|
|
|
|
t.Run("TestPanickyIterator1", func(t *testing.T) {
|
|
testseq2intl(t, fixture, grp, p, nil, []seqTest{
|
|
funcBreak(t, "main.TestPanickyIterator1"),
|
|
{contContinue, 110},
|
|
nx(111),
|
|
nx(112),
|
|
nx(116), // for _, z := range (z == 1)
|
|
nx(117), // result = append(result, z)
|
|
nx(118), // if z == 4
|
|
nx(121),
|
|
|
|
nx(116), // for _, z := range (z == 2)
|
|
nx(117), // result = append(result, z)
|
|
nx(118), // if z == 4
|
|
nx(121),
|
|
|
|
nx(116), // for _, z := range (z == 3)
|
|
nx(117), // result = append(result, z)
|
|
nx(118), // if z == 4
|
|
nx(121),
|
|
|
|
nx(116), // for _, z := range (z == 4)
|
|
nx(117), // result = append(result, z)
|
|
nx(118), // if z == 4
|
|
nx(119), // break
|
|
|
|
nx(112), // defer func()
|
|
nx(113), // r := recover()
|
|
nx(114), // fmt.Println
|
|
})
|
|
})
|
|
|
|
t.Run("TestPanickyIterator2", func(t *testing.T) {
|
|
testseq2intl(t, fixture, grp, p, nil, []seqTest{
|
|
funcBreak(t, "main.TestPanickyIterator2"),
|
|
{contContinue, 125},
|
|
nx(126),
|
|
nx(127),
|
|
nx(131), // for _, x := range (x == 100)
|
|
nx(132),
|
|
nx(133),
|
|
nx(135), // for _, y := range (y == 10)
|
|
nx(136), // result = append(result, y)
|
|
nx(139), // for k, z := range (k == 0, z == 1)
|
|
nx(140), // result = append(result, z)
|
|
nx(141), // if k == 1
|
|
nx(144),
|
|
|
|
nx(139), // for k, z := range (k == 1, z == 2)
|
|
nx(140), // result = append(result, z)
|
|
nx(141), // if k == 1
|
|
nx(142), // break Y
|
|
nx(135),
|
|
nx(145),
|
|
nx(127), // defer func()
|
|
nx(128), // r := recover()
|
|
nx(129), // fmt.Println
|
|
})
|
|
})
|
|
|
|
t.Run("TestPanickyIteratorWithNewDefer", func(t *testing.T) {
|
|
testseq2intl(t, fixture, grp, p, nil, []seqTest{
|
|
funcBreak(t, "main.TestPanickyIteratorWithNewDefer"),
|
|
{contContinue, 149},
|
|
nx(150),
|
|
nx(151),
|
|
nx(155), // for _, x := range (x == 100)
|
|
nx(156),
|
|
nx(157),
|
|
nx(159), // for _, y := range (y == 10)
|
|
nx(160),
|
|
nx(163), // result = append(result, y)
|
|
nx(166), // for k, z := range (k == 0, z == 1)
|
|
nx(167), // result = append(result, z)
|
|
nx(168), // if k == 1
|
|
nx(171),
|
|
|
|
nx(166), // for k, z := range (k == 0, z == 1)
|
|
nx(167), // result = append(result, z)
|
|
nx(168), // if k == 1
|
|
nx(169), // break Y
|
|
nx(159),
|
|
nx(172),
|
|
nx(160), // defer func()
|
|
nx(161), // fmt.Println
|
|
})
|
|
})
|
|
|
|
t.Run("TestLongReturn", func(t *testing.T) {
|
|
testseq2intl(t, fixture, grp, p, nil, []seqTest{
|
|
funcBreak(t, "main.TestLongReturn"),
|
|
{contContinue, 181},
|
|
nx(182), // for _, x := range (x == 1)
|
|
nx(183), // for _, y := range (y == 10)
|
|
nx(184), // if y == 10
|
|
nx(185), // return
|
|
nx(187),
|
|
nx(189),
|
|
nx(178), // into TestLongReturnWrapper, fmt.Println
|
|
})
|
|
})
|
|
|
|
t.Run("TestGotoA1", func(t *testing.T) {
|
|
testseq2intl(t, fixture, grp, p, nil, []seqTest{
|
|
funcBreak(t, "main.TestGotoA1"),
|
|
{contContinue, 192},
|
|
nx(193),
|
|
nx(194), // for _, x := range (x == -1)
|
|
nx(195), // result = append(result, x)
|
|
nx(196), // if x == -4
|
|
nx(199), // for _, y := range (y == 1)
|
|
nx(200), // if y == 3
|
|
nx(203), // result = append(result, y)
|
|
nx(204),
|
|
|
|
nx(199), // for _, y := range (y == 2)
|
|
nx(200), // if y == 3
|
|
nx(203), // result = append(result, y)
|
|
nx(204),
|
|
|
|
nx(199), // for _, y := range (y == 3)
|
|
nx(200), // if y == 3
|
|
nx(201), // goto A
|
|
nx(204),
|
|
nx(206), // result = append(result, x)
|
|
nx(207),
|
|
|
|
nx(194), // for _, x := range (x == -4)
|
|
nx(195), // result = append(result, x)
|
|
nx(196), // if x == -4
|
|
nx(197), // break
|
|
nx(207),
|
|
nx(208), // fmt.Println
|
|
})
|
|
})
|
|
|
|
t.Run("TestGotoB1", func(t *testing.T) {
|
|
testseq2intl(t, fixture, grp, p, nil, []seqTest{
|
|
funcBreak(t, "main.TestGotoB1"),
|
|
{contContinue, 211},
|
|
nx(212),
|
|
nx(213), // for _, x := range (x == -1)
|
|
nx(214), // result = append(result, x)
|
|
nx(215), // if x == -4
|
|
nx(218), // for _, y := range (y == 1)
|
|
nx(219), // if y == 3
|
|
nx(222), // result = append(result, y)
|
|
nx(223),
|
|
|
|
nx(218), // for _, y := range (y == 2)
|
|
nx(219), // if y == 3
|
|
nx(222), // result = append(result, y)
|
|
nx(223),
|
|
|
|
nx(218), // for _, y := range (y == 3)
|
|
nx(219), // if y == 3
|
|
nx(220), // goto B
|
|
nx(223),
|
|
nx(225),
|
|
nx(227), // result = append(result, 999)
|
|
nx(228), // fmt.Println
|
|
})
|
|
})
|
|
|
|
t.Run("TestRecur", func(t *testing.T) {
|
|
testseq2intl(t, fixture, grp, p, nil, []seqTest{
|
|
funcBreak(t, "main.TestRecur"),
|
|
{contContinue, 231},
|
|
clearBreak(t),
|
|
nx(232), // result := []int{}
|
|
assertEval(t, "n", "3"),
|
|
nx(233), // if n > 0 {
|
|
nx(234), // TestRecur
|
|
|
|
nx(236), // for _, x := range (x == 10)
|
|
assertFunc(t, "main.TestRecur"),
|
|
nx(237), // result = ...
|
|
assertEval(t, "n", "3"),
|
|
assertFunc(t, "main.TestRecur-range1"),
|
|
assertEval(t, "x", "10", "n", "3"),
|
|
nx(238), // if n == 3
|
|
nx(239), // TestRecur(0)
|
|
nx(241),
|
|
|
|
nx(236), // for _, x := range (x == 20)
|
|
nx(237), // result = ...
|
|
assertEval(t, "x", "20", "n", "3"),
|
|
})
|
|
})
|
|
})
|
|
}
|
|
|
|
func TestRangeOverFuncStepOut(t *testing.T) {
|
|
if !goversion.VersionAfterOrEqual(runtime.Version(), 1, 23) {
|
|
t.Skip("N/A")
|
|
}
|
|
|
|
testseq2(t, "rangeoverfunc", "", []seqTest{
|
|
{contContinue, 97},
|
|
{contStepout, 251},
|
|
})
|
|
}
|
|
|
|
func TestRangeOverFuncNextInlined(t *testing.T) {
|
|
if !goversion.VersionAfterOrEqual(runtime.Version(), 1, 23) {
|
|
t.Skip("N/A")
|
|
}
|
|
|
|
var bp *proc.Breakpoint
|
|
|
|
funcBreak := func(t *testing.T, fnname string) seqTest {
|
|
return seqTest{
|
|
contNothing,
|
|
func(p *proc.Target) {
|
|
bp = setFunctionBreakpoint(p, t, fnname)
|
|
}}
|
|
}
|
|
|
|
clearBreak := func(t *testing.T) seqTest {
|
|
return seqTest{
|
|
contNothing,
|
|
func(p *proc.Target) {
|
|
assertNoError(p.ClearBreakpoint(bp.Addr), t, "ClearBreakpoint")
|
|
}}
|
|
}
|
|
|
|
nx := func(n int) seqTest {
|
|
return seqTest{contNext, n}
|
|
}
|
|
|
|
assertLocals := func(t *testing.T, varnames ...string) seqTest {
|
|
return seqTest{
|
|
contNothing,
|
|
func(p *proc.Target) {
|
|
scope, err := proc.GoroutineScope(p, p.CurrentThread())
|
|
assertNoError(err, t, "GoroutineScope")
|
|
vars, err := scope.Locals(0, "")
|
|
assertNoError(err, t, "Locals")
|
|
|
|
gotnames := make([]string, len(vars))
|
|
for i := range vars {
|
|
gotnames[i] = vars[i].Name
|
|
}
|
|
|
|
ok := true
|
|
if len(vars) != len(varnames) {
|
|
ok = false
|
|
} else {
|
|
for i := range vars {
|
|
if vars[i].Name != varnames[i] {
|
|
ok = false
|
|
break
|
|
}
|
|
}
|
|
}
|
|
if !ok {
|
|
t.Errorf("Wrong variable names, expected %q, got %q", varnames, gotnames)
|
|
}
|
|
},
|
|
}
|
|
}
|
|
|
|
assertEval := func(t *testing.T, exprvals ...string) seqTest {
|
|
return seqTest{
|
|
contNothing,
|
|
func(p *proc.Target) {
|
|
scope, err := proc.GoroutineScope(p, p.CurrentThread())
|
|
assertNoError(err, t, "GoroutineScope")
|
|
for i := 0; i < len(exprvals); i += 2 {
|
|
expr, tgt := exprvals[i], exprvals[i+1]
|
|
v, err := scope.EvalExpression(expr, normalLoadConfig)
|
|
if err != nil {
|
|
t.Errorf("Could not evaluate %q: %v", expr, err)
|
|
} else {
|
|
out := api.ConvertVar(v).SinglelineString()
|
|
if out != tgt {
|
|
t.Errorf("Wrong value for %q, got %q expected %q", expr, out, tgt)
|
|
}
|
|
}
|
|
}
|
|
},
|
|
}
|
|
}
|
|
|
|
assertFunc := func(t *testing.T, fname string) seqTest {
|
|
return seqTest{
|
|
contNothing,
|
|
func(p *proc.Target) {
|
|
pc := currentPC(p, t)
|
|
fn := p.BinInfo().PCToFunc(pc)
|
|
if fn.Name != fname {
|
|
t.Errorf("Wrong function name, expected %s got %s", fname, fn.Name)
|
|
}
|
|
},
|
|
}
|
|
}
|
|
|
|
withTestProcessArgs("rangeoverfunc", t, ".", []string{}, protest.EnableInlining, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
|
|
t.Run("TestTrickyIterAll1", func(t *testing.T) {
|
|
testseq2intl(t, fixture, grp, p, nil, []seqTest{
|
|
funcBreak(t, "main.TestTrickyIterAll"),
|
|
{contContinue, 24}, // TestTrickyIterAll
|
|
nx(25),
|
|
nx(26),
|
|
nx(27), // for _, x := range ...
|
|
assertLocals(t, "trickItAll", "i"),
|
|
assertEval(t, "i", "0"),
|
|
nx(28), // i += x
|
|
assertLocals(t, "trickItAll", "i", "x"),
|
|
assertEval(t,
|
|
"i", "0",
|
|
"x", "30"),
|
|
nx(29), // if i >= 36 {
|
|
nx(32),
|
|
nx(27), // for _, x := range ...
|
|
nx(28), // i += x
|
|
assertEval(t,
|
|
"i", "30",
|
|
"x", "7"),
|
|
nx(29), // if i >= 36 {
|
|
nx(30), // break
|
|
nx(27),
|
|
nx(32),
|
|
nx(34), // fmt.Println
|
|
})
|
|
})
|
|
|
|
t.Run("TestTrickyIterAll2", func(t *testing.T) {
|
|
testseq2intl(t, fixture, grp, p, nil, []seqTest{
|
|
funcBreak(t, "main.TestTrickyIterAll2"),
|
|
{contContinue, 37}, // TestTrickyIterAll2
|
|
nx(38),
|
|
nx(39),
|
|
nx(40), // for _, x := range...
|
|
nx(41),
|
|
nx(42),
|
|
nx(40),
|
|
nx(41),
|
|
nx(42),
|
|
nx(40),
|
|
nx(42),
|
|
nx(43),
|
|
})
|
|
})
|
|
|
|
t.Run("TestBreak1", func(t *testing.T) {
|
|
testseq2intl(t, fixture, grp, p, nil, []seqTest{
|
|
funcBreak(t, "main.TestBreak1"),
|
|
{contContinue, 46}, // TestBreak1
|
|
nx(47),
|
|
nx(48), // for _, x := range... (x == -1)
|
|
nx(49), // if x == -4
|
|
assertLocals(t, "result", "x"),
|
|
assertEval(t,
|
|
"result", "[]int len: 0, cap: 0, nil",
|
|
"x", "-1"),
|
|
|
|
nx(52), // for _, y := range... (y == 1)
|
|
nx(53), // if y == 3
|
|
assertLocals(t, "result", "x", "y"),
|
|
assertEval(t,
|
|
"result", "[]int len: 0, cap: 0, nil",
|
|
"x", "-1",
|
|
"y", "1"),
|
|
nx(56), // result = append(result, y)
|
|
nx(57),
|
|
nx(52), // for _, y := range... (y == 2)
|
|
nx(53), // if y == 3
|
|
assertEval(t,
|
|
"x", "-1",
|
|
"y", "2"),
|
|
nx(56), // result = append(result, y)
|
|
nx(57),
|
|
nx(52), // for _, y := range... (y == 3)
|
|
nx(53), // if y == 3
|
|
assertEval(t,
|
|
"x", "-1",
|
|
"y", "3"),
|
|
nx(54), // break
|
|
nx(52),
|
|
nx(57),
|
|
nx(58), // result = append(result, x)
|
|
nx(59),
|
|
|
|
nx(48), // for _, x := range... (x == -2)
|
|
nx(49), // if x == -4
|
|
assertEval(t,
|
|
"result", "[]int len: 3, cap: 4, [1,2,-1]",
|
|
"x", "-2"),
|
|
nx(52), // for _, y := range... (y == 1)
|
|
nx(53), // if y == 3
|
|
nx(56), // result = append(result, y)
|
|
nx(57),
|
|
nx(52), // for _, y := range... (y == 2)
|
|
nx(53), // if y == 3
|
|
nx(56), // result = append(result, y)
|
|
nx(57),
|
|
nx(52), // for _, y := range... (y == 3)
|
|
nx(53), // if y == 3
|
|
nx(54), // break
|
|
nx(52),
|
|
nx(57),
|
|
nx(58), // result = append(result, x)
|
|
nx(59),
|
|
|
|
nx(48), // for _, x := range... (x == -4)
|
|
assertEval(t,
|
|
"result", "[]int len: 6, cap: 8, [1,2,-1,1,2,-2]",
|
|
"x", "-4"),
|
|
nx(49), // if x == -4
|
|
nx(50), // break
|
|
nx(48),
|
|
nx(59),
|
|
nx(60),
|
|
nx(61),
|
|
})
|
|
})
|
|
|
|
t.Run("TestBreak2", func(t *testing.T) {
|
|
testseq2intl(t, fixture, grp, p, nil, []seqTest{
|
|
funcBreak(t, "main.TestBreak2"),
|
|
|
|
{contContinue, 63}, // TestBreak2
|
|
nx(64),
|
|
nx(65),
|
|
|
|
nx(66), // for _, x := range (x == -1)
|
|
nx(67), // for _, y := range (y == 1)
|
|
nx(68), // if y == 3
|
|
nx(71), // if x == -4
|
|
nx(74), // result = append(result, y)
|
|
nx(75),
|
|
|
|
nx(67), // for _, y := range (y == 2)
|
|
nx(68), // if y == 3
|
|
nx(71), // if x == -4
|
|
nx(74), // result = append(result, y)
|
|
nx(75),
|
|
|
|
nx(67), // for _, y := range (y == 3)
|
|
nx(68), // if y == 3
|
|
nx(69), // break
|
|
nx(67),
|
|
nx(75),
|
|
nx(76), // result = append(result, x)
|
|
nx(77),
|
|
|
|
nx(66), // for _, x := range (x == -2)
|
|
nx(67), // for _, y := range (y == 1)
|
|
nx(68), // if y == 3
|
|
nx(71), // if x == -4
|
|
nx(74), // result = append(result, y)
|
|
nx(75),
|
|
|
|
nx(67), // for _, y := range (y == 2)
|
|
nx(68), // if y == 3
|
|
nx(71), // if x == -4
|
|
nx(74), // result = append(result, y)
|
|
nx(75),
|
|
|
|
nx(67), // for _, y := range (y == 3)
|
|
nx(68), // if y == 3
|
|
nx(69), // break
|
|
nx(67),
|
|
nx(75),
|
|
nx(76), // result = append(result, x)
|
|
nx(77),
|
|
|
|
nx(66), // for _, x := range (x == -4)
|
|
nx(67), // for _, y := range (y == 1)
|
|
nx(68), // if y == 3
|
|
nx(71), // if x == -4
|
|
nx(72), // break outer
|
|
nx(67),
|
|
nx(75),
|
|
nx(66),
|
|
nx(77),
|
|
nx(78),
|
|
nx(79),
|
|
})
|
|
})
|
|
|
|
t.Run("TestMultiCont0", func(t *testing.T) {
|
|
testseq2intl(t, fixture, grp, p, nil, []seqTest{
|
|
funcBreak(t, "main.TestMultiCont0"),
|
|
{contContinue, 81},
|
|
nx(82),
|
|
nx(84),
|
|
nx(85), // for _, w := range (w == 1000)
|
|
nx(86), // result = append(result, w)
|
|
assertEval(t,
|
|
"w", "1000",
|
|
"result", "[]int len: 0, cap: 10, []"),
|
|
nx(87), // if w == 2000
|
|
assertLocals(t, "result", "w"),
|
|
assertEval(t, "result", "[]int len: 1, cap: 10, [1000]"),
|
|
nx(90), // for _, x := range (x == 100)
|
|
nx(91), // for _, y := range (y == 10)
|
|
nx(92), // result = append(result, y)
|
|
assertLocals(t, "result", "w", "x", "y"),
|
|
assertEval(t,
|
|
"w", "1000",
|
|
"x", "100",
|
|
"y", "10"),
|
|
|
|
nx(93), // for _, z := range (z == 1)
|
|
nx(94), // if z&1 == 1
|
|
assertLocals(t, "result", "w", "x", "y", "z"),
|
|
assertEval(t,
|
|
"w", "1000",
|
|
"x", "100",
|
|
"y", "10",
|
|
"z", "1"),
|
|
nx(95), // continue
|
|
|
|
nx(93), // for _, z := range (z == 2)
|
|
nx(94), // if z&1 == 1
|
|
assertEval(t, "z", "2"),
|
|
nx(97), // result = append(result, z)
|
|
nx(98), // if z >= 4 {
|
|
nx(101),
|
|
|
|
nx(93), // for _, z := range (z == 3)
|
|
nx(94), // if z&1 == 1
|
|
assertEval(t, "z", "3"),
|
|
nx(95), // continue
|
|
|
|
nx(93), // for _, z := range (z == 4)
|
|
nx(94), // if z&1 == 1
|
|
assertEval(t, "z", "4"),
|
|
nx(97), // result = append(result, z)
|
|
assertEval(t, "result", "[]int len: 3, cap: 10, [1000,10,2]"),
|
|
nx(98), // if z >= 4 {
|
|
nx(99), // continue W
|
|
nx(93),
|
|
nx(101),
|
|
nx(91),
|
|
nx(103),
|
|
nx(90),
|
|
nx(105),
|
|
|
|
nx(85), // for _, w := range (w == 2000)
|
|
nx(86), // result = append(result, w)
|
|
nx(87), // if w == 2000
|
|
assertEval(t,
|
|
"w", "2000",
|
|
"result", "[]int len: 5, cap: 10, [1000,10,2,4,2000]"),
|
|
nx(88), // break
|
|
nx(85),
|
|
nx(106),
|
|
nx(107), // fmt.Println
|
|
})
|
|
})
|
|
|
|
t.Run("TestPanickyIterator1", func(t *testing.T) {
|
|
testseq2intl(t, fixture, grp, p, nil, []seqTest{
|
|
funcBreak(t, "main.TestPanickyIterator1"),
|
|
{contContinue, 110},
|
|
nx(111),
|
|
nx(112),
|
|
nx(116), // for _, z := range (z == 1)
|
|
nx(117), // result = append(result, z)
|
|
nx(118), // if z == 4
|
|
nx(121),
|
|
|
|
nx(116), // for _, z := range (z == 2)
|
|
nx(117), // result = append(result, z)
|
|
nx(118), // if z == 4
|
|
nx(121),
|
|
|
|
nx(116), // for _, z := range (z == 3)
|
|
nx(117), // result = append(result, z)
|
|
nx(118), // if z == 4
|
|
nx(121),
|
|
|
|
nx(116), // for _, z := range (z == 4)
|
|
nx(117), // result = append(result, z)
|
|
nx(118), // if z == 4
|
|
nx(119), // break
|
|
|
|
nx(112), // defer func()
|
|
nx(113), // r := recover()
|
|
nx(114), // fmt.Println
|
|
})
|
|
})
|
|
|
|
t.Run("TestPanickyIterator2", func(t *testing.T) {
|
|
testseq2intl(t, fixture, grp, p, nil, []seqTest{
|
|
funcBreak(t, "main.TestPanickyIterator2"),
|
|
{contContinue, 125},
|
|
nx(126),
|
|
nx(127),
|
|
nx(131), // for _, x := range (x == 100)
|
|
nx(132),
|
|
nx(133),
|
|
nx(135), // for _, y := range (y == 10)
|
|
nx(136), // result = append(result, y)
|
|
nx(139), // for k, z := range (k == 0, z == 1)
|
|
nx(140), // result = append(result, z)
|
|
nx(141), // if k == 1
|
|
nx(144),
|
|
|
|
nx(139), // for k, z := range (k == 1, z == 2)
|
|
nx(140), // result = append(result, z)
|
|
nx(141), // if k == 1
|
|
nx(142), // break Y
|
|
nx(135),
|
|
nx(145),
|
|
nx(127), // defer func()
|
|
nx(128), // r := recover()
|
|
nx(129), // fmt.Println
|
|
})
|
|
})
|
|
|
|
t.Run("TestPanickyIteratorWithNewDefer", func(t *testing.T) {
|
|
testseq2intl(t, fixture, grp, p, nil, []seqTest{
|
|
funcBreak(t, "main.TestPanickyIteratorWithNewDefer"),
|
|
{contContinue, 149},
|
|
nx(150),
|
|
nx(151),
|
|
nx(155), // for _, x := range (x == 100)
|
|
nx(156),
|
|
nx(157),
|
|
nx(159), // for _, y := range (y == 10)
|
|
nx(160),
|
|
nx(163), // result = append(result, y)
|
|
nx(166), // for k, z := range (k == 0, z == 1)
|
|
nx(167), // result = append(result, z)
|
|
nx(168), // if k == 1
|
|
nx(171),
|
|
|
|
nx(166), // for k, z := range (k == 0, z == 1)
|
|
nx(167), // result = append(result, z)
|
|
nx(168), // if k == 1
|
|
nx(169), // break Y
|
|
nx(159),
|
|
nx(172),
|
|
nx(160), // defer func()
|
|
nx(161), // fmt.Println
|
|
})
|
|
})
|
|
|
|
t.Run("TestLongReturn", func(t *testing.T) {
|
|
testseq2intl(t, fixture, grp, p, nil, []seqTest{
|
|
funcBreak(t, "main.TestLongReturn"),
|
|
{contContinue, 181},
|
|
nx(182), // for _, x := range (x == 1)
|
|
nx(183), // for _, y := range (y == 10)
|
|
nx(184), // if y == 10
|
|
nx(185), // return
|
|
nx(183),
|
|
nx(187),
|
|
nx(182),
|
|
nx(189),
|
|
nx(178), // into TestLongReturnWrapper, fmt.Println
|
|
})
|
|
})
|
|
|
|
t.Run("TestGotoA1", func(t *testing.T) {
|
|
testseq2intl(t, fixture, grp, p, nil, []seqTest{
|
|
funcBreak(t, "main.TestGotoA1"),
|
|
{contContinue, 192},
|
|
nx(193),
|
|
nx(194), // for _, x := range (x == -1)
|
|
nx(195), // result = append(result, x)
|
|
nx(196), // if x == -4
|
|
nx(199), // for _, y := range (y == 1)
|
|
nx(200), // if y == 3
|
|
nx(203), // result = append(result, y)
|
|
nx(204),
|
|
|
|
nx(199), // for _, y := range (y == 2)
|
|
nx(200), // if y == 3
|
|
nx(203), // result = append(result, y)
|
|
nx(204),
|
|
|
|
nx(199), // for _, y := range (y == 3)
|
|
nx(200), // if y == 3
|
|
nx(201), // goto A
|
|
nx(199),
|
|
nx(204),
|
|
nx(206), // result = append(result, x)
|
|
nx(207),
|
|
|
|
nx(194), // for _, x := range (x == -4)
|
|
nx(195), // result = append(result, x)
|
|
nx(196), // if x == -4
|
|
nx(197), // break
|
|
nx(194),
|
|
nx(207),
|
|
nx(208), // fmt.Println
|
|
})
|
|
})
|
|
|
|
t.Run("TestGotoB1", func(t *testing.T) {
|
|
testseq2intl(t, fixture, grp, p, nil, []seqTest{
|
|
funcBreak(t, "main.TestGotoB1"),
|
|
{contContinue, 211},
|
|
nx(212),
|
|
nx(213), // for _, x := range (x == -1)
|
|
nx(214), // result = append(result, x)
|
|
nx(215), // if x == -4
|
|
nx(218), // for _, y := range (y == 1)
|
|
nx(219), // if y == 3
|
|
nx(222), // result = append(result, y)
|
|
nx(223),
|
|
|
|
nx(218), // for _, y := range (y == 2)
|
|
nx(219), // if y == 3
|
|
nx(222), // result = append(result, y)
|
|
nx(223),
|
|
|
|
nx(218), // for _, y := range (y == 3)
|
|
nx(219), // if y == 3
|
|
nx(220), // goto B
|
|
nx(218),
|
|
nx(223),
|
|
nx(213),
|
|
nx(225),
|
|
nx(227), // result = append(result, 999)
|
|
nx(228), // fmt.Println
|
|
})
|
|
})
|
|
|
|
t.Run("TestRecur", func(t *testing.T) {
|
|
testseq2intl(t, fixture, grp, p, nil, []seqTest{
|
|
funcBreak(t, "main.TestRecur"),
|
|
{contContinue, 231},
|
|
clearBreak(t),
|
|
nx(232), // result := []int{}
|
|
assertEval(t, "n", "3"),
|
|
nx(233), // if n > 0 {
|
|
nx(234), // TestRecur
|
|
|
|
nx(236), // for _, x := range (x == 10)
|
|
assertFunc(t, "main.TestRecur"),
|
|
assertEval(t, "n", "3"),
|
|
nx(237), // result = ...
|
|
assertFunc(t, "main.TestRecur-range1"),
|
|
assertEval(t, "x", "10", "n", "3"),
|
|
nx(238), // if n == 3
|
|
nx(239), // TestRecur(0)
|
|
nx(241),
|
|
|
|
nx(236), // for _, x := range (x == 20)
|
|
nx(237), // result = ...
|
|
assertEval(t, "x", "20", "n", "3"),
|
|
})
|
|
})
|
|
})
|
|
}
|
|
|
|
func TestStepIntoCoroutine(t *testing.T) {
|
|
if !goversion.VersionAfterOrEqual(runtime.Version(), 1, 23) {
|
|
t.Skip("N/A")
|
|
}
|
|
skipOn(t, "not working due to optimizations", "386")
|
|
withTestProcessArgs("backwardsiter", t, ".", []string{}, 0, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
|
|
testseq2intl(t, fixture, grp, p, nil, []seqTest{
|
|
{contContinueToBreakpoint, 20}, // fmt.Println(next()) -- first call
|
|
{contStep, 9}, // func(yield)
|
|
{contNext, 10}, // for...
|
|
{contNext, 11}, // if !yield
|
|
{contStep, 20}, // fmt.Println(next()) -- first call (returning from next)
|
|
{contNext, 21}, // fmt.Println(next()) -- second call
|
|
{contStep, 11}, // if !yield
|
|
{contNext, 10}, // for...
|
|
{contNext, 11}, // if !yield
|
|
{contStep, 21}, // fmt.Println(next()) -- second call (returning from next)
|
|
{contNext, 22}, // fmt.Println(next()) -- third call
|
|
{contNext, 23}, // stop()
|
|
{contStep, 11}, // if !yield
|
|
})
|
|
})
|
|
}
|