mirror of
				https://github.com/go-delve/delve.git
				synced 2025-10-31 18:57:18 +08:00 
			
		
		
		
	 59aece9c0a
			
		
	
	59aece9c0a
	
	
	
		
			
			Add go1.24 to compatibility set and test matrix. Remove go1.21 from test matrix. TestRangeOverFuncNextInlined is disabled because the improved inlining of go1.24 produces symbol names that are too complicated for us to correlate, a fix for this will require a change to the compiler that will probably be too complex to make it into 1.24.
		
			
				
	
	
		
			1792 lines
		
	
	
		
			47 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			1792 lines
		
	
	
		
			47 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")
 | |
| 	}
 | |
| 	if goversion.VersionAfterOrEqual(runtime.Version(), 1, 24) && !goversion.VersionAfterOrEqual(runtime.Version(), 1, 25) {
 | |
| 		t.Skip("broken due to inlined symbol names")
 | |
| 	}
 | |
| 
 | |
| 	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
 | |
| 		})
 | |
| 	})
 | |
| }
 |