gitlab.com/Raven-IO/raven-delve@v1.22.4/pkg/proc/proc_test.go (about)

     1  package proc_test
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/binary"
     6  	"flag"
     7  	"fmt"
     8  	"go/ast"
     9  	"go/constant"
    10  	"go/parser"
    11  	"go/token"
    12  	"io"
    13  	"math/rand"
    14  	"net"
    15  	"net/http"
    16  	"os"
    17  	"os/exec"
    18  	"path/filepath"
    19  	"reflect"
    20  	"runtime"
    21  	"sort"
    22  	"strconv"
    23  	"strings"
    24  	"sync"
    25  	"testing"
    26  	"text/tabwriter"
    27  	"time"
    28  
    29  	"gitlab.com/Raven-IO/raven-delve/pkg/dwarf/frame"
    30  	"gitlab.com/Raven-IO/raven-delve/pkg/dwarf/op"
    31  	"gitlab.com/Raven-IO/raven-delve/pkg/goversion"
    32  	"gitlab.com/Raven-IO/raven-delve/pkg/logflags"
    33  	"gitlab.com/Raven-IO/raven-delve/pkg/proc"
    34  	"gitlab.com/Raven-IO/raven-delve/pkg/proc/core"
    35  	"gitlab.com/Raven-IO/raven-delve/pkg/proc/gdbserial"
    36  	"gitlab.com/Raven-IO/raven-delve/pkg/proc/native"
    37  	protest "gitlab.com/Raven-IO/raven-delve/pkg/proc/test"
    38  	"gitlab.com/Raven-IO/raven-delve/service/api"
    39  )
    40  
    41  var normalLoadConfig = proc.LoadConfig{true, 1, 64, 64, -1, 0}
    42  var testBackend, buildMode string
    43  
    44  func init() {
    45  	runtime.GOMAXPROCS(4)
    46  	os.Setenv("GOMAXPROCS", "4")
    47  }
    48  
    49  func TestMain(m *testing.M) {
    50  	flag.StringVar(&testBackend, "backend", "", "selects backend")
    51  	flag.StringVar(&buildMode, "test-buildmode", "", "selects build mode")
    52  	var logConf string
    53  	flag.StringVar(&logConf, "log", "", "configures logging")
    54  	flag.Parse()
    55  	protest.DefaultTestBackend(&testBackend)
    56  	if buildMode != "" && buildMode != "pie" {
    57  		fmt.Fprintf(os.Stderr, "unknown build mode %q", buildMode)
    58  		os.Exit(1)
    59  	}
    60  	logflags.Setup(logConf != "", logConf, "")
    61  	os.Exit(protest.RunTestsWithFixtures(m))
    62  }
    63  
    64  func matchSkipConditions(conditions ...string) bool {
    65  	for _, cond := range conditions {
    66  		condfound := false
    67  		for _, s := range []string{runtime.GOOS, runtime.GOARCH, testBackend, buildMode} {
    68  			if s == cond {
    69  				condfound = true
    70  				break
    71  			}
    72  		}
    73  		if !condfound {
    74  			return false
    75  		}
    76  	}
    77  	return true
    78  }
    79  
    80  func skipOn(t testing.TB, reason string, conditions ...string) {
    81  	if matchSkipConditions(conditions...) {
    82  		t.Skipf("skipped on %s: %s", strings.Join(conditions, "/"), reason)
    83  	}
    84  }
    85  
    86  func skipUnlessOn(t testing.TB, reason string, conditions ...string) {
    87  	if !matchSkipConditions(conditions...) {
    88  		t.Skipf("skipped on %s: %s", strings.Join(conditions, "/"), reason)
    89  	}
    90  }
    91  
    92  func withTestProcess(name string, t testing.TB, fn func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture)) {
    93  	withTestProcessArgs(name, t, ".", []string{}, 0, fn)
    94  }
    95  
    96  func withTestProcessArgs(name string, t testing.TB, wd string, args []string, buildFlags protest.BuildFlags, fn func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture)) {
    97  	if buildMode == "pie" {
    98  		buildFlags |= protest.BuildModePIE
    99  	}
   100  	fixture := protest.BuildFixture(name, buildFlags)
   101  	var grp *proc.TargetGroup
   102  	var err error
   103  	var tracedir string
   104  
   105  	switch testBackend {
   106  	case "native":
   107  		grp, err = native.Launch(append([]string{fixture.Path}, args...), wd, 0, []string{}, "", "", proc.OutputRedirect{}, proc.OutputRedirect{})
   108  	case "lldb":
   109  		grp, err = gdbserial.LLDBLaunch(append([]string{fixture.Path}, args...), wd, 0, []string{}, "", [3]string{})
   110  	case "rr":
   111  		protest.MustHaveRecordingAllowed(t)
   112  		t.Log("recording")
   113  		grp, tracedir, err = gdbserial.RecordAndReplay(append([]string{fixture.Path}, args...), wd, true, []string{}, "", proc.OutputRedirect{}, proc.OutputRedirect{})
   114  		t.Logf("replaying %q", tracedir)
   115  	default:
   116  		t.Fatal("unknown backend")
   117  	}
   118  	if err != nil {
   119  		t.Fatal("Launch():", err)
   120  	}
   121  
   122  	defer func() {
   123  		grp.Detach(true)
   124  	}()
   125  
   126  	fn(grp.Selected, grp, fixture)
   127  }
   128  
   129  func getRegisters(p *proc.Target, t *testing.T) proc.Registers {
   130  	regs, err := p.CurrentThread().Registers()
   131  	if err != nil {
   132  		t.Fatal("Registers():", err)
   133  	}
   134  
   135  	return regs
   136  }
   137  
   138  func dataAtAddr(thread proc.MemoryReadWriter, addr uint64) ([]byte, error) {
   139  	data := make([]byte, 1)
   140  	_, err := thread.ReadMemory(data, addr)
   141  	return data, err
   142  }
   143  
   144  func assertNoError(err error, t testing.TB, s string) {
   145  	if err != nil {
   146  		_, file, line, _ := runtime.Caller(1)
   147  		fname := filepath.Base(file)
   148  		t.Fatalf("failed assertion at %s:%d: %s - %s\n", fname, line, s, err)
   149  	}
   150  }
   151  
   152  func currentPC(p *proc.Target, t *testing.T) uint64 {
   153  	regs, err := p.CurrentThread().Registers()
   154  	if err != nil {
   155  		t.Fatal(err)
   156  	}
   157  
   158  	return regs.PC()
   159  }
   160  
   161  func currentLineNumber(p *proc.Target, t *testing.T) (string, int) {
   162  	pc := currentPC(p, t)
   163  	f, l, _ := p.BinInfo().PCToLine(pc)
   164  	return f, l
   165  }
   166  
   167  func assertLineNumber(p *proc.Target, t *testing.T, lineno int, descr string) (string, int) {
   168  	f, l := currentLineNumber(p, t)
   169  	if l != lineno {
   170  		_, callerFile, callerLine, _ := runtime.Caller(1)
   171  		t.Fatalf("%s expected line :%d got %s:%d\n\tat %s:%d", descr, lineno, f, l, callerFile, callerLine)
   172  	}
   173  	return f, l
   174  }
   175  
   176  func assertFunctionName(p *proc.Target, t *testing.T, fnname string, descr string) {
   177  	pc := currentPC(p, t)
   178  	f, l, fn := p.BinInfo().PCToLine(pc)
   179  	if fn == nil {
   180  		t.Fatalf("%s expected function %s got %s:%d", descr, fnname, f, l)
   181  	}
   182  	if fn.Name != fnname {
   183  		t.Fatalf("%s expected function %s got %s %s:%d", descr, fnname, fn.Name, f, l)
   184  	}
   185  }
   186  
   187  func TestExit(t *testing.T) {
   188  	protest.AllowRecording(t)
   189  	withTestProcess("continuetestprog", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
   190  		err := grp.Continue()
   191  		pe, ok := err.(proc.ErrProcessExited)
   192  		if !ok {
   193  			t.Fatalf("Continue() returned unexpected error type %s", err)
   194  		}
   195  		if pe.Status != 0 {
   196  			t.Errorf("Unexpected error status: %d", pe.Status)
   197  		}
   198  		if pe.Pid != p.Pid() {
   199  			t.Errorf("Unexpected process id: %d", pe.Pid)
   200  		}
   201  	})
   202  }
   203  
   204  func TestExitAfterContinue(t *testing.T) {
   205  	protest.AllowRecording(t)
   206  	withTestProcess("continuetestprog", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
   207  		setFunctionBreakpoint(p, t, "main.sayhi")
   208  		assertNoError(grp.Continue(), t, "First Continue()")
   209  		err := grp.Continue()
   210  		pe, ok := err.(proc.ErrProcessExited)
   211  		if !ok {
   212  			t.Fatalf("Continue() returned unexpected error type %s", pe)
   213  		}
   214  		if pe.Status != 0 {
   215  			t.Errorf("Unexpected error status: %d", pe.Status)
   216  		}
   217  		if pe.Pid != p.Pid() {
   218  			t.Errorf("Unexpected process id: %d", pe.Pid)
   219  		}
   220  	})
   221  }
   222  
   223  func setFunctionBreakpoint(p *proc.Target, t testing.TB, fname string) *proc.Breakpoint {
   224  	t.Helper()
   225  	addrs, err := proc.FindFunctionLocation(p, fname, 0)
   226  	if err != nil {
   227  		t.Fatalf("FindFunctionLocation(%s): %v", fname, err)
   228  	}
   229  	if len(addrs) != 1 {
   230  		t.Fatalf("setFunctionBreakpoint(%s): too many results %v", fname, addrs)
   231  	}
   232  	bp, err := p.SetBreakpoint(int(addrs[0]), addrs[0], proc.UserBreakpoint, nil)
   233  	if err != nil {
   234  		t.Fatalf("FindFunctionLocation(%s): %v", fname, err)
   235  	}
   236  	return bp
   237  }
   238  
   239  func setFunctionBreakpointAll(p *proc.Target, t testing.TB, fname string) {
   240  	t.Helper()
   241  	addrs, err := proc.FindFunctionLocation(p, fname, 0)
   242  	if err != nil {
   243  		t.Fatalf("FindFunctionLocation(%s): %v", fname, err)
   244  	}
   245  	for _, addr := range addrs {
   246  		_, err := p.SetBreakpoint(int(addr), addr, proc.UserBreakpoint, nil)
   247  		if err != nil {
   248  			t.Fatalf("FindFunctionLocation(%s): %v", fname, err)
   249  		}
   250  	}
   251  }
   252  
   253  func setFileBreakpoint(p *proc.Target, t testing.TB, path string, lineno int) *proc.Breakpoint {
   254  	_, f, l, _ := runtime.Caller(1)
   255  	f = filepath.Base(f)
   256  
   257  	addrs, err := proc.FindFileLocation(p, path, lineno)
   258  	if err != nil {
   259  		t.Fatalf("%s:%d: FindFileLocation(%s, %d): %v", f, l, path, lineno, err)
   260  	}
   261  	if len(addrs) != 1 {
   262  		t.Fatalf("%s:%d: setFileLineBreakpoint(%s, %d): too many (or not enough) results %v", f, l, path, lineno, addrs)
   263  	}
   264  	bp, err := p.SetBreakpoint(int(addrs[0]), addrs[0], proc.UserBreakpoint, nil)
   265  	if err != nil {
   266  		t.Fatalf("%s:%d: SetBreakpoint: %v", f, l, err)
   267  	}
   268  	return bp
   269  }
   270  
   271  func findFunctionLocation(p *proc.Target, t *testing.T, fnname string) uint64 {
   272  	_, f, l, _ := runtime.Caller(1)
   273  	f = filepath.Base(f)
   274  	addrs, err := proc.FindFunctionLocation(p, fnname, 0)
   275  	if err != nil {
   276  		t.Fatalf("%s:%d: FindFunctionLocation(%s): %v", f, l, fnname, err)
   277  	}
   278  	if len(addrs) != 1 {
   279  		t.Fatalf("%s:%d: FindFunctionLocation(%s): too many results %v", f, l, fnname, addrs)
   280  	}
   281  	return addrs[0]
   282  }
   283  
   284  func findFileLocation(p *proc.Target, t *testing.T, file string, lineno int) uint64 {
   285  	_, f, l, _ := runtime.Caller(1)
   286  	f = filepath.Base(f)
   287  	addrs, err := proc.FindFileLocation(p, file, lineno)
   288  	if err != nil {
   289  		t.Fatalf("%s:%d: FindFileLocation(%s, %d): %v", f, l, file, lineno, err)
   290  	}
   291  	if len(addrs) != 1 {
   292  		t.Fatalf("%s:%d: FindFileLocation(%s, %d): too many results %v", f, l, file, lineno, addrs)
   293  	}
   294  	return addrs[0]
   295  }
   296  
   297  func TestHalt(t *testing.T) {
   298  	stopChan := make(chan interface{}, 1)
   299  	withTestProcess("loopprog", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
   300  		setFunctionBreakpoint(p, t, "main.loop")
   301  		assertNoError(grp.Continue(), t, "Continue")
   302  		resumeChan := make(chan struct{}, 1)
   303  		go func() {
   304  			<-resumeChan
   305  			time.Sleep(100 * time.Millisecond)
   306  			stopChan <- grp.RequestManualStop()
   307  		}()
   308  		grp.ResumeNotify(resumeChan)
   309  		assertNoError(grp.Continue(), t, "Continue")
   310  		retVal := <-stopChan
   311  
   312  		if err, ok := retVal.(error); ok && err != nil {
   313  			t.Fatal()
   314  		}
   315  	})
   316  }
   317  
   318  func TestStepInstruction(t *testing.T) {
   319  	protest.AllowRecording(t)
   320  	withTestProcess("testprog", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
   321  		setFunctionBreakpoint(p, t, "main.helloworld")
   322  		assertNoError(grp.Continue(), t, "Continue()")
   323  
   324  		regs := getRegisters(p, t)
   325  		rip := regs.PC()
   326  
   327  		err := grp.StepInstruction(false)
   328  		assertNoError(err, t, "Step()")
   329  
   330  		regs = getRegisters(p, t)
   331  		if rip >= regs.PC() {
   332  			t.Errorf("Expected %#v to be greater than %#v", regs.PC(), rip)
   333  		}
   334  	})
   335  }
   336  
   337  func TestNextInstruction(t *testing.T) {
   338  	protest.AllowRecording(t)
   339  	withTestProcess("testprog", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
   340  		setFileBreakpoint(p, t, fixture.Source, 19)
   341  		assertNoError(grp.Continue(), t, "Continue()")
   342  
   343  		err := grp.StepInstruction(true)
   344  		assertNoError(err, t, "Step()")
   345  
   346  		assertLineNumber(p, t, 20, "next-instruction did not step over call")
   347  	})
   348  }
   349  
   350  func TestBreakpoint(t *testing.T) {
   351  	protest.AllowRecording(t)
   352  	withTestProcess("testprog", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
   353  		bp := setFunctionBreakpoint(p, t, "main.helloworld")
   354  		assertNoError(grp.Continue(), t, "Continue()")
   355  
   356  		regs, err := p.CurrentThread().Registers()
   357  		assertNoError(err, t, "Registers")
   358  		pc := regs.PC()
   359  
   360  		if bp.Logical.TotalHitCount != 1 {
   361  			t.Fatalf("Breakpoint should be hit once, got %d\n", bp.Logical.TotalHitCount)
   362  		}
   363  
   364  		if pc-1 != bp.Addr && pc != bp.Addr {
   365  			f, l, _ := p.BinInfo().PCToLine(pc)
   366  			t.Fatalf("Break not respected:\nPC:%#v %s:%d\nFN:%#v \n", pc, f, l, bp.Addr)
   367  		}
   368  	})
   369  }
   370  
   371  func TestBreakpointInSeparateGoRoutine(t *testing.T) {
   372  	protest.AllowRecording(t)
   373  	withTestProcess("testthreads", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
   374  		setFunctionBreakpoint(p, t, "main.anotherthread")
   375  
   376  		assertNoError(grp.Continue(), t, "Continue")
   377  
   378  		regs, err := p.CurrentThread().Registers()
   379  		assertNoError(err, t, "Registers")
   380  		pc := regs.PC()
   381  
   382  		f, l, _ := p.BinInfo().PCToLine(pc)
   383  		if f != "testthreads.go" && l != 8 {
   384  			t.Fatal("Program did not hit breakpoint")
   385  		}
   386  	})
   387  }
   388  
   389  func TestBreakpointWithNonExistentFunction(t *testing.T) {
   390  	withTestProcess("testprog", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
   391  		_, err := p.SetBreakpoint(0, 0, proc.UserBreakpoint, nil)
   392  		if err == nil {
   393  			t.Fatal("Should not be able to break at non existent function")
   394  		}
   395  	})
   396  }
   397  
   398  func TestClearBreakpointBreakpoint(t *testing.T) {
   399  	withTestProcess("testprog", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
   400  		bp := setFunctionBreakpoint(p, t, "main.sleepytime")
   401  
   402  		err := p.ClearBreakpoint(bp.Addr)
   403  		assertNoError(err, t, "ClearBreakpoint()")
   404  
   405  		data, err := dataAtAddr(p.Memory(), bp.Addr)
   406  		assertNoError(err, t, "dataAtAddr")
   407  
   408  		int3 := []byte{0xcc}
   409  		if bytes.Equal(data, int3) {
   410  			t.Fatalf("Breakpoint was not cleared data: %#v, int3: %#v", data, int3)
   411  		}
   412  
   413  		if countBreakpoints(p) != 0 {
   414  			t.Fatal("Breakpoint not removed internally")
   415  		}
   416  	})
   417  }
   418  
   419  type nextTest struct {
   420  	begin, end int
   421  }
   422  
   423  func countBreakpoints(p *proc.Target) int {
   424  	bpcount := 0
   425  	for _, bp := range p.Breakpoints().M {
   426  		if bp.LogicalID() >= 0 {
   427  			bpcount++
   428  		}
   429  	}
   430  	return bpcount
   431  }
   432  
   433  type contFunc int
   434  
   435  const (
   436  	contContinue contFunc = iota
   437  	contNext
   438  	contStep
   439  	contStepout
   440  	contReverseNext
   441  	contReverseStep
   442  	contReverseStepout
   443  	contContinueToBreakpoint
   444  	contNothing
   445  )
   446  
   447  type seqTest struct {
   448  	cf  contFunc
   449  	pos interface{}
   450  }
   451  
   452  func testseq(program string, contFunc contFunc, testcases []nextTest, initialLocation string, t *testing.T) {
   453  	seqTestcases := make([]seqTest, len(testcases)+1)
   454  	seqTestcases[0] = seqTest{contContinue, testcases[0].begin}
   455  	for i := range testcases {
   456  		if i > 0 {
   457  			if testcases[i-1].end != testcases[i].begin {
   458  				panic(fmt.Errorf("begin/end mismatch at index %d", i))
   459  			}
   460  		}
   461  		seqTestcases[i+1] = seqTest{contFunc, testcases[i].end}
   462  	}
   463  	testseq2(t, program, initialLocation, seqTestcases)
   464  }
   465  
   466  const traceTestseq2 = true
   467  
   468  func testseq2(t *testing.T, program string, initialLocation string, testcases []seqTest) {
   469  	testseq2Args(".", []string{}, 0, t, program, initialLocation, testcases)
   470  }
   471  
   472  func testseq2Args(wd string, args []string, buildFlags protest.BuildFlags, t *testing.T, program string, initialLocation string, testcases []seqTest) {
   473  	protest.AllowRecording(t)
   474  	withTestProcessArgs(program, t, wd, args, buildFlags, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
   475  		var bp *proc.Breakpoint
   476  		if initialLocation != "" {
   477  			bp = setFunctionBreakpoint(p, t, initialLocation)
   478  		} else if testcases[0].cf == contContinue {
   479  			bp = setFileBreakpoint(p, t, fixture.Source, testcases[0].pos.(int))
   480  		} else {
   481  			panic("testseq2 can not set initial breakpoint")
   482  		}
   483  		if traceTestseq2 {
   484  			t.Logf("initial breakpoint %v", bp)
   485  		}
   486  		regs, err := p.CurrentThread().Registers()
   487  		assertNoError(err, t, "Registers")
   488  
   489  		f, ln := currentLineNumber(p, t)
   490  		for i, tc := range testcases {
   491  			switch tc.cf {
   492  			case contNext:
   493  				if traceTestseq2 {
   494  					t.Log("next")
   495  				}
   496  				assertNoError(grp.Next(), t, "Next() returned an error")
   497  			case contStep:
   498  				if traceTestseq2 {
   499  					t.Log("step")
   500  				}
   501  				assertNoError(grp.Step(), t, "Step() returned an error")
   502  			case contStepout:
   503  				if traceTestseq2 {
   504  					t.Log("stepout")
   505  				}
   506  				assertNoError(grp.StepOut(), t, "StepOut() returned an error")
   507  			case contContinue:
   508  				if traceTestseq2 {
   509  					t.Log("continue")
   510  				}
   511  				assertNoError(grp.Continue(), t, "Continue() returned an error")
   512  				if i == 0 {
   513  					if traceTestseq2 {
   514  						t.Log("clearing initial breakpoint")
   515  					}
   516  					err := p.ClearBreakpoint(bp.Addr)
   517  					assertNoError(err, t, "ClearBreakpoint() returned an error")
   518  				}
   519  			case contReverseNext:
   520  				if traceTestseq2 {
   521  					t.Log("reverse-next")
   522  				}
   523  				assertNoError(grp.ChangeDirection(proc.Backward), t, "direction switch")
   524  				assertNoError(grp.Next(), t, "reverse Next() returned an error")
   525  				assertNoError(grp.ChangeDirection(proc.Forward), t, "direction switch")
   526  			case contReverseStep:
   527  				if traceTestseq2 {
   528  					t.Log("reverse-step")
   529  				}
   530  				assertNoError(grp.ChangeDirection(proc.Backward), t, "direction switch")
   531  				assertNoError(grp.Step(), t, "reverse Step() returned an error")
   532  				assertNoError(grp.ChangeDirection(proc.Forward), t, "direction switch")
   533  			case contReverseStepout:
   534  				if traceTestseq2 {
   535  					t.Log("reverse-stepout")
   536  				}
   537  				assertNoError(grp.ChangeDirection(proc.Backward), t, "direction switch")
   538  				assertNoError(grp.StepOut(), t, "reverse StepOut() returned an error")
   539  				assertNoError(grp.ChangeDirection(proc.Forward), t, "direction switch")
   540  			case contContinueToBreakpoint:
   541  				bp := setFileBreakpoint(p, t, fixture.Source, tc.pos.(int))
   542  				if traceTestseq2 {
   543  					t.Log("continue")
   544  				}
   545  				assertNoError(grp.Continue(), t, "Continue() returned an error")
   546  				err := p.ClearBreakpoint(bp.Addr)
   547  				assertNoError(err, t, "ClearBreakpoint() returned an error")
   548  			case contNothing:
   549  				// do nothing
   550  			}
   551  
   552  			if err := p.CurrentThread().Breakpoint().CondError; err != nil {
   553  				t.Logf("breakpoint condition error: %v", err)
   554  			}
   555  
   556  			f, ln = currentLineNumber(p, t)
   557  			regs, _ = p.CurrentThread().Registers()
   558  			pc := regs.PC()
   559  
   560  			if traceTestseq2 {
   561  				t.Logf("at %#x %s:%d", pc, f, ln)
   562  				fmt.Printf("at %#x %s:%d\n", pc, f, ln)
   563  			}
   564  			switch pos := tc.pos.(type) {
   565  			case int:
   566  				if pos >= 0 && ln != pos {
   567  					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)
   568  				}
   569  			case string:
   570  				v := strings.Split(pos, ":")
   571  				tgtln, _ := strconv.Atoi(v[1])
   572  				if !strings.HasSuffix(f, v[0]) || (ln != tgtln) {
   573  					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)
   574  				}
   575  			case func(*proc.Target):
   576  				pos(p)
   577  			default:
   578  				panic(fmt.Errorf("unexpected type %T", pos))
   579  			}
   580  		}
   581  
   582  		if countBreakpoints(p) != 0 {
   583  			t.Fatal("Not all breakpoints were cleaned up", len(p.Breakpoints().M))
   584  		}
   585  	})
   586  }
   587  
   588  func TestNextGeneral(t *testing.T) {
   589  	var testcases []nextTest
   590  
   591  	ver, _ := goversion.Parse(runtime.Version())
   592  
   593  	if ver.Major < 0 || ver.AfterOrEqual(goversion.GoVersion{Major: 1, Minor: 7, Rev: -1}) {
   594  		testcases = []nextTest{
   595  			{17, 19},
   596  			{19, 20},
   597  			{20, 23},
   598  			{23, 24},
   599  			{24, 26},
   600  			{26, 31},
   601  			{31, 23},
   602  			{23, 24},
   603  			{24, 26},
   604  			{26, 31},
   605  			{31, 23},
   606  			{23, 24},
   607  			{24, 26},
   608  			{26, 27},
   609  			{27, 28},
   610  			{28, 34},
   611  		}
   612  	} else {
   613  		testcases = []nextTest{
   614  			{17, 19},
   615  			{19, 20},
   616  			{20, 23},
   617  			{23, 24},
   618  			{24, 26},
   619  			{26, 31},
   620  			{31, 23},
   621  			{23, 24},
   622  			{24, 26},
   623  			{26, 31},
   624  			{31, 23},
   625  			{23, 24},
   626  			{24, 26},
   627  			{26, 27},
   628  			{27, 34},
   629  		}
   630  	}
   631  
   632  	testseq("testnextprog", contNext, testcases, "main.testnext", t)
   633  }
   634  
   635  func TestNextConcurrent(t *testing.T) {
   636  	skipOn(t, "broken", "windows", "arm64")
   637  	testcases := []nextTest{
   638  		{8, 9},
   639  		{9, 10},
   640  		{10, 11},
   641  	}
   642  	protest.AllowRecording(t)
   643  	withTestProcess("parallel_next", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
   644  		bp := setFunctionBreakpoint(p, t, "main.sayhi")
   645  		assertNoError(grp.Continue(), t, "Continue")
   646  		f, ln := currentLineNumber(p, t)
   647  		initV := evalVariable(p, t, "n")
   648  		initVval, _ := constant.Int64Val(initV.Value)
   649  		err := p.ClearBreakpoint(bp.Addr)
   650  		assertNoError(err, t, "ClearBreakpoint()")
   651  		for _, tc := range testcases {
   652  			g, err := proc.GetG(p.CurrentThread())
   653  			assertNoError(err, t, "GetG()")
   654  			if p.SelectedGoroutine().ID != g.ID {
   655  				t.Fatalf("SelectedGoroutine not CurrentThread's goroutine: %d %d", g.ID, p.SelectedGoroutine().ID)
   656  			}
   657  			if ln != tc.begin {
   658  				t.Fatalf("Program not stopped at correct spot expected %d was %s:%d", tc.begin, filepath.Base(f), ln)
   659  			}
   660  			assertNoError(grp.Next(), t, "Next() returned an error")
   661  			f, ln = assertLineNumber(p, t, tc.end, "Program did not continue to the expected location")
   662  			v := evalVariable(p, t, "n")
   663  			vval, _ := constant.Int64Val(v.Value)
   664  			if vval != initVval {
   665  				t.Fatal("Did not end up on same goroutine")
   666  			}
   667  		}
   668  	})
   669  }
   670  
   671  func TestNextConcurrentVariant2(t *testing.T) {
   672  	skipOn(t, "broken", "windows", "arm64")
   673  	// Just like TestNextConcurrent but instead of removing the initial breakpoint we check that when it happens is for other goroutines
   674  	testcases := []nextTest{
   675  		{8, 9},
   676  		{9, 10},
   677  		{10, 11},
   678  	}
   679  	protest.AllowRecording(t)
   680  	withTestProcess("parallel_next", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
   681  		setFunctionBreakpoint(p, t, "main.sayhi")
   682  		assertNoError(grp.Continue(), t, "Continue")
   683  		f, ln := currentLineNumber(p, t)
   684  		initV := evalVariable(p, t, "n")
   685  		initVval, _ := constant.Int64Val(initV.Value)
   686  		for _, tc := range testcases {
   687  			t.Logf("test case %v", tc)
   688  			g, err := proc.GetG(p.CurrentThread())
   689  			assertNoError(err, t, "GetG()")
   690  			if p.SelectedGoroutine().ID != g.ID {
   691  				t.Fatalf("SelectedGoroutine not CurrentThread's goroutine: %d %d", g.ID, p.SelectedGoroutine().ID)
   692  			}
   693  			if ln != tc.begin {
   694  				t.Fatalf("Program not stopped at correct spot expected %d was %s:%d", tc.begin, filepath.Base(f), ln)
   695  			}
   696  			assertNoError(grp.Next(), t, "Next() returned an error")
   697  			var vval int64
   698  			for {
   699  				v := evalVariable(p, t, "n")
   700  				for _, thread := range p.ThreadList() {
   701  					proc.GetG(thread)
   702  				}
   703  				vval, _ = constant.Int64Val(v.Value)
   704  				if bpstate := p.CurrentThread().Breakpoint(); bpstate.Breakpoint == nil {
   705  					if vval != initVval {
   706  						t.Fatal("Did not end up on same goroutine")
   707  					}
   708  					break
   709  				} else {
   710  					if vval == initVval {
   711  						t.Fatal("Initial breakpoint triggered twice for the same goroutine")
   712  					}
   713  					assertNoError(grp.Continue(), t, "Continue 2")
   714  				}
   715  			}
   716  			f, ln = assertLineNumber(p, t, tc.end, "Program did not continue to the expected location")
   717  		}
   718  	})
   719  }
   720  
   721  func TestNextFunctionReturn(t *testing.T) {
   722  	testcases := []nextTest{
   723  		{13, 14},
   724  		{14, 15},
   725  		{15, 35},
   726  	}
   727  	protest.AllowRecording(t)
   728  	testseq("testnextprog", contNext, testcases, "main.helloworld", t)
   729  }
   730  
   731  func TestNextFunctionReturnDefer(t *testing.T) {
   732  	var testcases []nextTest
   733  
   734  	ver, _ := goversion.Parse(runtime.Version())
   735  
   736  	if ver.Major < 0 || ver.AfterOrEqual(goversion.GoVersion{Major: 1, Minor: 9, Rev: -1}) {
   737  		testcases = []nextTest{
   738  			{5, 6},
   739  			{6, 9},
   740  			{9, 10},
   741  		}
   742  	} else {
   743  		testcases = []nextTest{
   744  			{5, 8},
   745  			{8, 9},
   746  			{9, 10},
   747  		}
   748  	}
   749  	protest.AllowRecording(t)
   750  	testseq("testnextdefer", contNext, testcases, "main.main", t)
   751  }
   752  
   753  func TestNextNetHTTP(t *testing.T) {
   754  	testcases := []nextTest{
   755  		{11, 12},
   756  		{12, 13},
   757  	}
   758  	withTestProcess("testnextnethttp", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
   759  		go func() {
   760  			// Wait for program to start listening.
   761  			for {
   762  				conn, err := net.Dial("tcp", "127.0.0.1:9191")
   763  				if err == nil {
   764  					conn.Close()
   765  					break
   766  				}
   767  				time.Sleep(50 * time.Millisecond)
   768  			}
   769  			resp, err := http.Get("http://127.0.0.1:9191")
   770  			if err == nil {
   771  				resp.Body.Close()
   772  			}
   773  		}()
   774  		if err := grp.Continue(); err != nil {
   775  			t.Fatal(err)
   776  		}
   777  		f, ln := currentLineNumber(p, t)
   778  		for _, tc := range testcases {
   779  			if ln != tc.begin {
   780  				t.Fatalf("Program not stopped at correct spot expected %d was %s:%d", tc.begin, filepath.Base(f), ln)
   781  			}
   782  
   783  			assertNoError(grp.Next(), t, "Next() returned an error")
   784  
   785  			f, ln = assertLineNumber(p, t, tc.end, "Program did not continue to correct next location")
   786  		}
   787  	})
   788  }
   789  
   790  func TestRuntimeBreakpoint(t *testing.T) {
   791  	withTestProcess("testruntimebreakpoint", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
   792  		err := grp.Continue()
   793  		if err != nil {
   794  			t.Fatal(err)
   795  		}
   796  		regs, err := p.CurrentThread().Registers()
   797  		assertNoError(err, t, "Registers")
   798  		pc := regs.PC()
   799  		f, l, _ := p.BinInfo().PCToLine(pc)
   800  		if l != 10 {
   801  			t.Fatalf("did not respect breakpoint %s:%d", f, l)
   802  		}
   803  	})
   804  }
   805  
   806  func returnAddress(tgt *proc.Target, thread proc.Thread) (uint64, error) {
   807  	locations, err := proc.ThreadStacktrace(tgt, thread, 2)
   808  	if err != nil {
   809  		return 0, err
   810  	}
   811  	if len(locations) < 2 {
   812  		return 0, fmt.Errorf("no return address for function: %s", locations[0].Current.Fn.BaseName())
   813  	}
   814  	return locations[1].Current.PC, nil
   815  }
   816  
   817  func TestFindReturnAddress(t *testing.T) {
   818  	protest.AllowRecording(t)
   819  	withTestProcess("testnextprog", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
   820  		setFileBreakpoint(p, t, fixture.Source, 24)
   821  		err := grp.Continue()
   822  		if err != nil {
   823  			t.Fatal(err)
   824  		}
   825  		addr, err := returnAddress(p, p.CurrentThread())
   826  		if err != nil {
   827  			t.Fatal(err)
   828  		}
   829  		_, l, _ := p.BinInfo().PCToLine(addr)
   830  		if l != 40 {
   831  			t.Fatalf("return address not found correctly, expected line 40")
   832  		}
   833  	})
   834  }
   835  
   836  func TestFindReturnAddressTopOfStackFn(t *testing.T) {
   837  	skipOn(t, "broken in linux ppc64le", "linux", "ppc64le", "native")
   838  	protest.AllowRecording(t)
   839  	withTestProcess("testreturnaddress", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
   840  		fnName := "runtime.rt0_go"
   841  		setFunctionBreakpoint(p, t, fnName)
   842  		if err := grp.Continue(); err != nil {
   843  			t.Fatal(err)
   844  		}
   845  		if _, err := returnAddress(p, p.CurrentThread()); err == nil {
   846  			t.Fatal("expected error to be returned")
   847  		}
   848  	})
   849  }
   850  
   851  func TestSwitchThread(t *testing.T) {
   852  	protest.AllowRecording(t)
   853  	withTestProcess("testnextprog", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
   854  		// With invalid thread id
   855  		err := p.SwitchThread(-1)
   856  		if err == nil {
   857  			t.Fatal("Expected error for invalid thread id")
   858  		}
   859  		setFunctionBreakpoint(p, t, "main.main")
   860  		err = grp.Continue()
   861  		if err != nil {
   862  			t.Fatal(err)
   863  		}
   864  		var nt int
   865  		ct := p.CurrentThread().ThreadID()
   866  		for _, thread := range p.ThreadList() {
   867  			if thread.ThreadID() != ct {
   868  				nt = thread.ThreadID()
   869  				break
   870  			}
   871  		}
   872  		if nt == 0 {
   873  			t.Fatal("could not find thread to switch to")
   874  		}
   875  		// With valid thread id
   876  		err = p.SwitchThread(nt)
   877  		if err != nil {
   878  			t.Fatal(err)
   879  		}
   880  		if p.CurrentThread().ThreadID() != nt {
   881  			t.Fatal("Did not switch threads")
   882  		}
   883  	})
   884  }
   885  
   886  func TestCGONext(t *testing.T) {
   887  	// Test if one can do 'next' in a cgo binary
   888  	// On OSX with Go < 1.5 CGO is not supported due to: https://github.com/golang/go/issues/8973
   889  	if !goversion.VersionAfterOrEqual(runtime.Version(), 1, 5) {
   890  		skipOn(t, "upstream issue", "darwin")
   891  	}
   892  	protest.MustHaveCgo(t)
   893  
   894  	skipOn(t, "broken - see https://gitlab.com/Raven-IO/raven-delve/issues/3158", "darwin", "amd64")
   895  
   896  	protest.AllowRecording(t)
   897  	withTestProcess("cgotest", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
   898  		setFunctionBreakpoint(p, t, "main.main")
   899  		assertNoError(grp.Continue(), t, "Continue()")
   900  		assertNoError(grp.Next(), t, "Next()")
   901  	})
   902  }
   903  
   904  func TestCGOBreakpointLocation(t *testing.T) {
   905  	protest.MustHaveCgo(t)
   906  	protest.AllowRecording(t)
   907  
   908  	withTestProcess("cgotest", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
   909  		bp := setFunctionBreakpoint(p, t, "C.foo")
   910  		if !strings.Contains(bp.File, "cgotest.go") {
   911  			t.Fatalf("incorrect breakpoint location, expected cgotest.go got %s", bp.File)
   912  		}
   913  	})
   914  }
   915  
   916  type loc struct {
   917  	line int
   918  	fn   string
   919  }
   920  
   921  func (l1 *loc) match(l2 proc.Stackframe) bool {
   922  	if l1.line >= 0 {
   923  		if l1.line != l2.Call.Line {
   924  			return false
   925  		}
   926  	}
   927  	return l1.fn == l2.Call.Fn.Name
   928  }
   929  
   930  func TestStacktrace(t *testing.T) {
   931  	stacks := [][]loc{
   932  		{{4, "main.stacktraceme"}, {8, "main.func1"}, {16, "main.main"}},
   933  		{{4, "main.stacktraceme"}, {8, "main.func1"}, {12, "main.func2"}, {17, "main.main"}},
   934  	}
   935  	protest.AllowRecording(t)
   936  	withTestProcess("stacktraceprog", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
   937  		bp := setFunctionBreakpoint(p, t, "main.stacktraceme")
   938  
   939  		for i := range stacks {
   940  			assertNoError(grp.Continue(), t, "Continue()")
   941  			locations, err := proc.ThreadStacktrace(p, p.CurrentThread(), 40)
   942  			assertNoError(err, t, "Stacktrace()")
   943  
   944  			if len(locations) != len(stacks[i])+2 {
   945  				t.Fatalf("Wrong stack trace size %d %d\n", len(locations), len(stacks[i])+2)
   946  			}
   947  
   948  			t.Logf("Stacktrace %d:\n", i)
   949  			for i := range locations {
   950  				t.Logf("\t%s:%d\n", locations[i].Call.File, locations[i].Call.Line)
   951  			}
   952  
   953  			for j := range stacks[i] {
   954  				if !stacks[i][j].match(locations[j]) {
   955  					t.Fatalf("Wrong stack trace pos %d\n", j)
   956  				}
   957  			}
   958  		}
   959  
   960  		p.ClearBreakpoint(bp.Addr)
   961  		grp.Continue()
   962  	})
   963  }
   964  
   965  func TestStacktrace2(t *testing.T) {
   966  	withTestProcess("retstack", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
   967  		assertNoError(grp.Continue(), t, "Continue()")
   968  
   969  		locations, err := proc.ThreadStacktrace(p, p.CurrentThread(), 40)
   970  		assertNoError(err, t, "Stacktrace()")
   971  		if !stackMatch([]loc{{-1, "main.f"}, {16, "main.main"}}, locations, false) {
   972  			for i := range locations {
   973  				t.Logf("\t%s:%d [%s]\n", locations[i].Call.File, locations[i].Call.Line, locations[i].Call.Fn.Name)
   974  			}
   975  			t.Fatalf("Stack error at main.f()\n%v\n", locations)
   976  		}
   977  
   978  		assertNoError(grp.Continue(), t, "Continue()")
   979  		locations, err = proc.ThreadStacktrace(p, p.CurrentThread(), 40)
   980  		assertNoError(err, t, "Stacktrace()")
   981  		if !stackMatch([]loc{{-1, "main.g"}, {17, "main.main"}}, locations, false) {
   982  			for i := range locations {
   983  				t.Logf("\t%s:%d [%s]\n", locations[i].Call.File, locations[i].Call.Line, locations[i].Call.Fn.Name)
   984  			}
   985  			t.Fatalf("Stack error at main.g()\n%v\n", locations)
   986  		}
   987  	})
   988  
   989  }
   990  
   991  func stackMatch(stack []loc, locations []proc.Stackframe, skipRuntime bool) bool {
   992  	if len(stack) > len(locations) {
   993  		return false
   994  	}
   995  	i := 0
   996  	for j := range locations {
   997  		if i >= len(stack) {
   998  			break
   999  		}
  1000  		if skipRuntime {
  1001  			if locations[j].Call.Fn == nil || strings.HasPrefix(locations[j].Call.Fn.Name, "runtime.") {
  1002  				continue
  1003  			}
  1004  		}
  1005  		if !stack[i].match(locations[j]) {
  1006  			return false
  1007  		}
  1008  		i++
  1009  	}
  1010  	return i >= len(stack)
  1011  }
  1012  
  1013  func TestStacktraceGoroutine(t *testing.T) {
  1014  	mainStack := []loc{{14, "main.stacktraceme"}, {29, "main.main"}}
  1015  	if goversion.VersionAfterOrEqual(runtime.Version(), 1, 11) {
  1016  		mainStack[0].line = 15
  1017  	}
  1018  	agoroutineStacks := [][]loc{
  1019  		{{8, "main.agoroutine"}},
  1020  		{{9, "main.agoroutine"}},
  1021  		{{10, "main.agoroutine"}},
  1022  	}
  1023  
  1024  	lenient := 0
  1025  	if runtime.GOOS == "windows" {
  1026  		lenient = 1
  1027  	}
  1028  
  1029  	protest.AllowRecording(t)
  1030  	withTestProcess("goroutinestackprog", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  1031  		bp := setFunctionBreakpoint(p, t, "main.stacktraceme")
  1032  
  1033  		assertNoError(grp.Continue(), t, "Continue()")
  1034  
  1035  		gs, _, err := proc.GoroutinesInfo(p, 0, 0)
  1036  		assertNoError(err, t, "GoroutinesInfo")
  1037  
  1038  		agoroutineCount := 0
  1039  		mainCount := 0
  1040  
  1041  		for i, g := range gs {
  1042  			locations, err := proc.GoroutineStacktrace(p, g, 40, 0)
  1043  			if err != nil {
  1044  				// On windows we do not have frame information for goroutines doing system calls.
  1045  				t.Logf("Could not retrieve goroutine stack for goid=%d: %v", g.ID, err)
  1046  				continue
  1047  			}
  1048  
  1049  			if stackMatch(mainStack, locations, false) {
  1050  				mainCount++
  1051  			}
  1052  
  1053  			found := false
  1054  			for _, agoroutineStack := range agoroutineStacks {
  1055  				if stackMatch(agoroutineStack, locations, true) {
  1056  					found = true
  1057  				}
  1058  			}
  1059  
  1060  			if found {
  1061  				agoroutineCount++
  1062  			} else {
  1063  				t.Logf("Non-goroutine stack: %d (%d)", i, len(locations))
  1064  				for i := range locations {
  1065  					name := ""
  1066  					if locations[i].Call.Fn != nil {
  1067  						name = locations[i].Call.Fn.Name
  1068  					}
  1069  					t.Logf("\t%s:%d %s (%#x) %x %v\n", locations[i].Call.File, locations[i].Call.Line, name, locations[i].Current.PC, locations[i].FrameOffset(), locations[i].SystemStack)
  1070  				}
  1071  			}
  1072  		}
  1073  
  1074  		if mainCount != 1 {
  1075  			t.Fatalf("Main goroutine stack not found %d", mainCount)
  1076  		}
  1077  
  1078  		if agoroutineCount < 10-lenient {
  1079  			t.Fatalf("Goroutine stacks not found (%d)", agoroutineCount)
  1080  		}
  1081  
  1082  		p.ClearBreakpoint(bp.Addr)
  1083  		grp.Continue()
  1084  	})
  1085  }
  1086  
  1087  func TestKill(t *testing.T) {
  1088  	withTestProcess("testprog", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  1089  		if err := grp.Detach(true); err != nil {
  1090  			t.Fatal(err)
  1091  		}
  1092  		if valid, _ := p.Valid(); valid {
  1093  			t.Fatal("expected process to have exited")
  1094  		}
  1095  		if runtime.GOOS == "linux" {
  1096  			if runtime.GOARCH == "arm64" {
  1097  				// there is no any sync between signal sended(tracee handled) and open /proc/%d/. It may fail on arm64
  1098  				return
  1099  			}
  1100  			_, err := os.Open(fmt.Sprintf("/proc/%d/", p.Pid()))
  1101  			if err == nil {
  1102  				t.Fatal("process has not exited", p.Pid())
  1103  			}
  1104  		}
  1105  	})
  1106  }
  1107  
  1108  func testGSupportFunc(name string, t *testing.T, p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  1109  	bp := setFunctionBreakpoint(p, t, "main.main")
  1110  
  1111  	assertNoError(grp.Continue(), t, name+": Continue()")
  1112  
  1113  	g, err := proc.GetG(p.CurrentThread())
  1114  	assertNoError(err, t, name+": GetG()")
  1115  
  1116  	if g == nil {
  1117  		t.Fatal(name + ": g was nil")
  1118  	}
  1119  
  1120  	t.Logf(name+": g is: %v", g)
  1121  
  1122  	p.ClearBreakpoint(bp.Addr)
  1123  }
  1124  
  1125  func TestGetG(t *testing.T) {
  1126  	withTestProcess("testprog", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  1127  		testGSupportFunc("nocgo", t, p, grp, fixture)
  1128  	})
  1129  
  1130  	// On OSX with Go < 1.5 CGO is not supported due to: https://github.com/golang/go/issues/8973
  1131  	if !goversion.VersionAfterOrEqual(runtime.Version(), 1, 5) {
  1132  		skipOn(t, "upstream issue", "darwin")
  1133  	}
  1134  	protest.MustHaveCgo(t)
  1135  
  1136  	protest.AllowRecording(t)
  1137  	withTestProcess("cgotest", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  1138  		testGSupportFunc("cgo", t, p, grp, fixture)
  1139  	})
  1140  }
  1141  
  1142  func TestContinueMulti(t *testing.T) {
  1143  	protest.AllowRecording(t)
  1144  	withTestProcess("integrationprog", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  1145  		bp1 := setFunctionBreakpoint(p, t, "main.main")
  1146  		bp2 := setFunctionBreakpoint(p, t, "main.sayhi")
  1147  
  1148  		mainCount := 0
  1149  		sayhiCount := 0
  1150  		for {
  1151  			err := grp.Continue()
  1152  			if valid, _ := p.Valid(); !valid {
  1153  				break
  1154  			}
  1155  			assertNoError(err, t, "Continue()")
  1156  
  1157  			if bp := p.CurrentThread().Breakpoint(); bp.LogicalID() == bp1.LogicalID() {
  1158  				mainCount++
  1159  			}
  1160  
  1161  			if bp := p.CurrentThread().Breakpoint(); bp.LogicalID() == bp2.LogicalID() {
  1162  				sayhiCount++
  1163  			}
  1164  		}
  1165  
  1166  		if mainCount != 1 {
  1167  			t.Fatalf("Main breakpoint hit wrong number of times: %d\n", mainCount)
  1168  		}
  1169  
  1170  		if sayhiCount != 3 {
  1171  			t.Fatalf("Sayhi breakpoint hit wrong number of times: %d\n", sayhiCount)
  1172  		}
  1173  	})
  1174  }
  1175  
  1176  func TestBreakpointOnFunctionEntry(t *testing.T) {
  1177  	testseq2(t, "testprog", "main.main", []seqTest{{contContinue, 17}})
  1178  }
  1179  
  1180  func TestProcessReceivesSIGCHLD(t *testing.T) {
  1181  	protest.AllowRecording(t)
  1182  	withTestProcess("sigchldprog", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  1183  		err := grp.Continue()
  1184  		_, ok := err.(proc.ErrProcessExited)
  1185  		if !ok {
  1186  			t.Fatalf("Continue() returned unexpected error type %v", err)
  1187  		}
  1188  	})
  1189  }
  1190  
  1191  func TestIssue239(t *testing.T) {
  1192  	withTestProcess("is sue239", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  1193  		setFileBreakpoint(p, t, fixture.Source, 17)
  1194  		assertNoError(grp.Continue(), t, "Continue()")
  1195  	})
  1196  }
  1197  
  1198  func findFirstNonRuntimeFrame(p *proc.Target) (proc.Stackframe, error) {
  1199  	frames, err := proc.ThreadStacktrace(p, p.CurrentThread(), 10)
  1200  	if err != nil {
  1201  		return proc.Stackframe{}, err
  1202  	}
  1203  
  1204  	for _, frame := range frames {
  1205  		if frame.Current.Fn != nil && !strings.HasPrefix(frame.Current.Fn.Name, "runtime.") {
  1206  			return frame, nil
  1207  		}
  1208  	}
  1209  	return proc.Stackframe{}, fmt.Errorf("non-runtime frame not found")
  1210  }
  1211  
  1212  func evalVariableOrError(p *proc.Target, symbol string) (*proc.Variable, error) {
  1213  	var scope *proc.EvalScope
  1214  	var err error
  1215  
  1216  	if testBackend == "rr" {
  1217  		var frame proc.Stackframe
  1218  		frame, err = findFirstNonRuntimeFrame(p)
  1219  		if err == nil {
  1220  			scope = proc.FrameToScope(p, p.Memory(), nil, 0, frame)
  1221  		}
  1222  	} else {
  1223  		scope, err = proc.GoroutineScope(p, p.CurrentThread())
  1224  	}
  1225  
  1226  	if err != nil {
  1227  		return nil, err
  1228  	}
  1229  	return scope.EvalExpression(symbol, normalLoadConfig)
  1230  }
  1231  
  1232  func evalVariable(p *proc.Target, t testing.TB, symbol string) *proc.Variable {
  1233  	v, err := evalVariableOrError(p, symbol)
  1234  	if err != nil {
  1235  		_, file, line, _ := runtime.Caller(1)
  1236  		fname := filepath.Base(file)
  1237  		t.Fatalf("%s:%d: EvalVariable(%q): %v", fname, line, symbol, err)
  1238  	}
  1239  	return v
  1240  }
  1241  
  1242  func setVariable(p *proc.Target, symbol, value string) error {
  1243  	scope, err := proc.GoroutineScope(p, p.CurrentThread())
  1244  	if err != nil {
  1245  		return err
  1246  	}
  1247  	return scope.SetVariable(symbol, value)
  1248  }
  1249  
  1250  func TestVariableEvaluation(t *testing.T) {
  1251  	protest.AllowRecording(t)
  1252  	testcases := []struct {
  1253  		name        string
  1254  		st          reflect.Kind
  1255  		value       interface{}
  1256  		length, cap int64
  1257  		childrenlen int
  1258  	}{
  1259  		{"a1", reflect.String, "foofoofoofoofoofoo", 18, 0, 0},
  1260  		{"a11", reflect.Array, nil, 3, -1, 3},
  1261  		{"a12", reflect.Slice, nil, 2, 2, 2},
  1262  		{"a13", reflect.Slice, nil, 3, 3, 3},
  1263  		{"a2", reflect.Int, int64(6), 0, 0, 0},
  1264  		{"a3", reflect.Float64, float64(7.23), 0, 0, 0},
  1265  		{"a4", reflect.Array, nil, 2, -1, 2},
  1266  		{"a5", reflect.Slice, nil, 5, 5, 5},
  1267  		{"a6", reflect.Struct, nil, 2, 0, 2},
  1268  		{"a7", reflect.Ptr, nil, 1, 0, 1},
  1269  		{"a8", reflect.Struct, nil, 2, 0, 2},
  1270  		{"a9", reflect.Ptr, nil, 1, 0, 1},
  1271  		{"baz", reflect.String, "bazburzum", 9, 0, 0},
  1272  		{"neg", reflect.Int, int64(-1), 0, 0, 0},
  1273  		{"f32", reflect.Float32, float64(float32(1.2)), 0, 0, 0},
  1274  		{"c64", reflect.Complex64, complex128(complex64(1 + 2i)), 0, 0, 0},
  1275  		{"c128", reflect.Complex128, complex128(2 + 3i), 0, 0, 0},
  1276  		{"a6.Baz", reflect.Int, int64(8), 0, 0, 0},
  1277  		{"a7.Baz", reflect.Int, int64(5), 0, 0, 0},
  1278  		{"a8.Baz", reflect.String, "feh", 3, 0, 0},
  1279  		{"a8", reflect.Struct, nil, 2, 0, 2},
  1280  		{"i32", reflect.Array, nil, 2, -1, 2},
  1281  		{"b1", reflect.Bool, true, 0, 0, 0},
  1282  		{"b2", reflect.Bool, false, 0, 0, 0},
  1283  		{"f", reflect.Func, "main.barfoo", 0, 0, 0},
  1284  		{"ba", reflect.Slice, nil, 200, 200, 64},
  1285  	}
  1286  
  1287  	withTestProcess("testvariables", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  1288  		assertNoError(grp.Continue(), t, "Continue() returned an error")
  1289  
  1290  		for _, tc := range testcases {
  1291  			v := evalVariable(p, t, tc.name)
  1292  
  1293  			if v.Kind != tc.st {
  1294  				t.Fatalf("%s simple type: expected: %s got: %s", tc.name, tc.st, v.Kind.String())
  1295  			}
  1296  			if v.Value == nil && tc.value != nil {
  1297  				t.Fatalf("%s value: expected: %v got: %v", tc.name, tc.value, v.Value)
  1298  			} else {
  1299  				switch v.Kind {
  1300  				case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
  1301  					x, _ := constant.Int64Val(v.Value)
  1302  					if y, ok := tc.value.(int64); !ok || x != y {
  1303  						t.Fatalf("%s value: expected: %v got: %v", tc.name, tc.value, v.Value)
  1304  					}
  1305  				case reflect.Float32, reflect.Float64:
  1306  					x, _ := constant.Float64Val(v.Value)
  1307  					if y, ok := tc.value.(float64); !ok || x != y {
  1308  						t.Fatalf("%s value: expected: %v got: %v", tc.name, tc.value, v.Value)
  1309  					}
  1310  				case reflect.Complex64, reflect.Complex128:
  1311  					xr, _ := constant.Float64Val(constant.Real(v.Value))
  1312  					xi, _ := constant.Float64Val(constant.Imag(v.Value))
  1313  					if y, ok := tc.value.(complex128); !ok || complex(xr, xi) != y {
  1314  						t.Fatalf("%s value: expected: %v got: %v", tc.name, tc.value, v.Value)
  1315  					}
  1316  				case reflect.String:
  1317  					if y, ok := tc.value.(string); !ok || constant.StringVal(v.Value) != y {
  1318  						t.Fatalf("%s value: expected: %v got: %v", tc.name, tc.value, v.Value)
  1319  					}
  1320  				}
  1321  			}
  1322  			if v.Len != tc.length {
  1323  				t.Fatalf("%s len: expected: %d got: %d", tc.name, tc.length, v.Len)
  1324  			}
  1325  			if v.Cap != tc.cap {
  1326  				t.Fatalf("%s cap: expected: %d got: %d", tc.name, tc.cap, v.Cap)
  1327  			}
  1328  			if len(v.Children) != tc.childrenlen {
  1329  				t.Fatalf("%s children len: expected %d got: %d", tc.name, tc.childrenlen, len(v.Children))
  1330  			}
  1331  		}
  1332  	})
  1333  }
  1334  
  1335  func TestFrameEvaluation(t *testing.T) {
  1336  	protest.AllowRecording(t)
  1337  	lenient := false
  1338  	if runtime.GOOS == "windows" {
  1339  		lenient = true
  1340  	}
  1341  	withTestProcess("goroutinestackprog", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  1342  		setFunctionBreakpoint(p, t, "main.stacktraceme")
  1343  		assertNoError(grp.Continue(), t, "Continue()")
  1344  
  1345  		t.Logf("stopped on thread %d, goroutine: %#v", p.CurrentThread().ThreadID(), p.SelectedGoroutine())
  1346  
  1347  		// Testing evaluation on goroutines
  1348  		gs, _, err := proc.GoroutinesInfo(p, 0, 0)
  1349  		assertNoError(err, t, "GoroutinesInfo")
  1350  		found := make([]bool, 10)
  1351  		for _, g := range gs {
  1352  			frame := -1
  1353  			frames, err := proc.GoroutineStacktrace(p, g, 40, 0)
  1354  			if err != nil {
  1355  				t.Logf("could not stacktrace goroutine %d: %v\n", g.ID, err)
  1356  				continue
  1357  			}
  1358  			t.Logf("Goroutine %d %#v", g.ID, g.Thread)
  1359  			logStacktrace(t, p, frames)
  1360  			for i := range frames {
  1361  				if frames[i].Call.Fn != nil && frames[i].Call.Fn.Name == "main.agoroutine" {
  1362  					frame = i
  1363  					break
  1364  				}
  1365  			}
  1366  
  1367  			if frame < 0 {
  1368  				t.Logf("Goroutine %d: could not find correct frame", g.ID)
  1369  				continue
  1370  			}
  1371  
  1372  			scope, err := proc.ConvertEvalScope(p, g.ID, frame, 0)
  1373  			assertNoError(err, t, "ConvertEvalScope()")
  1374  			t.Logf("scope = %v", scope)
  1375  			v, err := scope.EvalExpression("i", normalLoadConfig)
  1376  			t.Logf("v = %v", v)
  1377  			if err != nil {
  1378  				t.Logf("Goroutine %d: %v\n", g.ID, err)
  1379  				continue
  1380  			}
  1381  			vval, _ := constant.Int64Val(v.Value)
  1382  			found[vval] = true
  1383  		}
  1384  
  1385  		for i := range found {
  1386  			if !found[i] {
  1387  				if lenient {
  1388  					lenient = false
  1389  				} else {
  1390  					t.Fatalf("Goroutine %d not found\n", i)
  1391  				}
  1392  			}
  1393  		}
  1394  
  1395  		// Testing evaluation on frames
  1396  		assertNoError(grp.Continue(), t, "Continue() 2")
  1397  		g, err := proc.GetG(p.CurrentThread())
  1398  		assertNoError(err, t, "GetG()")
  1399  
  1400  		frames, err := proc.GoroutineStacktrace(p, g, 40, 0)
  1401  		assertNoError(err, t, "Stacktrace()")
  1402  		t.Logf("Goroutine %d %#v", g.ID, g.Thread)
  1403  		logStacktrace(t, p, frames)
  1404  
  1405  		for i := 0; i <= 3; i++ {
  1406  			scope, err := proc.ConvertEvalScope(p, g.ID, i+1, 0)
  1407  			assertNoError(err, t, fmt.Sprintf("ConvertEvalScope() on frame %d", i+1))
  1408  			v, err := scope.EvalExpression("n", normalLoadConfig)
  1409  			assertNoError(err, t, fmt.Sprintf("EvalVariable() on frame %d", i+1))
  1410  			n, _ := constant.Int64Val(v.Value)
  1411  			t.Logf("frame %d n %d\n", i+1, n)
  1412  			if n != int64(3-i) {
  1413  				t.Fatalf("On frame %d value of n is %d (not %d)", i+1, n, 3-i)
  1414  			}
  1415  		}
  1416  	})
  1417  }
  1418  
  1419  func TestThreadFrameEvaluation(t *testing.T) {
  1420  	skipOn(t, "upstream issue - https://github.com/golang/go/issues/29322", "pie")
  1421  	deadlockBp := proc.FatalThrow
  1422  	if !goversion.VersionAfterOrEqual(runtime.Version(), 1, 11) {
  1423  		t.SkipNow()
  1424  	}
  1425  	withTestProcess("testdeadlock", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  1426  		assertNoError(grp.Continue(), t, "Continue()")
  1427  
  1428  		bp := p.CurrentThread().Breakpoint()
  1429  		if bp.Breakpoint == nil || bp.Logical.Name != deadlockBp {
  1430  			t.Fatalf("did not stop at deadlock breakpoint %v", bp)
  1431  		}
  1432  
  1433  		// There is no selected goroutine during a deadlock, so the scope will
  1434  		// be a thread scope.
  1435  		scope, err := proc.ConvertEvalScope(p, 0, 0, 0)
  1436  		assertNoError(err, t, "ConvertEvalScope() on frame 0")
  1437  		_, err = scope.EvalExpression("s", normalLoadConfig)
  1438  		assertNoError(err, t, "EvalVariable(\"s\") on frame 0")
  1439  	})
  1440  }
  1441  
  1442  func TestPointerSetting(t *testing.T) {
  1443  	withTestProcess("testvariables2", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  1444  		assertNoError(grp.Continue(), t, "Continue() returned an error")
  1445  
  1446  		pval := func(n int64) {
  1447  			variable := evalVariable(p, t, "p1")
  1448  			c0val, _ := constant.Int64Val(variable.Children[0].Value)
  1449  			if c0val != n {
  1450  				t.Fatalf("Wrong value of p1, *%d expected *%d", c0val, n)
  1451  			}
  1452  		}
  1453  
  1454  		pval(1)
  1455  
  1456  		// change p1 to point to i2
  1457  		scope, err := proc.GoroutineScope(p, p.CurrentThread())
  1458  		assertNoError(err, t, "Scope()")
  1459  		i2addr, err := scope.EvalExpression("i2", normalLoadConfig)
  1460  		assertNoError(err, t, "EvalExpression()")
  1461  		assertNoError(setVariable(p, "p1", fmt.Sprintf("(*int)(0x%x)", i2addr.Addr)), t, "SetVariable()")
  1462  		pval(2)
  1463  
  1464  		// change the value of i2 check that p1 also changes
  1465  		assertNoError(setVariable(p, "i2", "5"), t, "SetVariable()")
  1466  		pval(5)
  1467  	})
  1468  }
  1469  
  1470  func TestVariableFunctionScoping(t *testing.T) {
  1471  	withTestProcess("testvariables", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  1472  		err := grp.Continue()
  1473  		assertNoError(err, t, "Continue() returned an error")
  1474  
  1475  		evalVariable(p, t, "a1")
  1476  		evalVariable(p, t, "a2")
  1477  
  1478  		// Move scopes, a1 exists here by a2 does not
  1479  		err = grp.Continue()
  1480  		assertNoError(err, t, "Continue() returned an error")
  1481  
  1482  		evalVariable(p, t, "a1")
  1483  
  1484  		_, err = evalVariableOrError(p, "a2")
  1485  		if err == nil {
  1486  			t.Fatalf("Can eval out of scope variable a2")
  1487  		}
  1488  	})
  1489  }
  1490  
  1491  func TestRecursiveStructure(t *testing.T) {
  1492  	protest.AllowRecording(t)
  1493  	withTestProcess("testvariables2", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  1494  		assertNoError(grp.Continue(), t, "Continue()")
  1495  		v := evalVariable(p, t, "aas")
  1496  		t.Logf("v: %v\n", v)
  1497  	})
  1498  }
  1499  
  1500  func TestIssue316(t *testing.T) {
  1501  	// A pointer loop that includes one interface should not send dlv into an infinite loop
  1502  	protest.AllowRecording(t)
  1503  	withTestProcess("testvariables2", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  1504  		assertNoError(grp.Continue(), t, "Continue()")
  1505  		evalVariable(p, t, "iface5")
  1506  	})
  1507  }
  1508  
  1509  func TestIssue325(t *testing.T) {
  1510  	// nil pointer dereference when evaluating interfaces to function pointers
  1511  	protest.AllowRecording(t)
  1512  	withTestProcess("testvariables2", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  1513  		assertNoError(grp.Continue(), t, "Continue()")
  1514  		iface2fn1v := evalVariable(p, t, "iface2fn1")
  1515  		t.Logf("iface2fn1: %v\n", iface2fn1v)
  1516  
  1517  		iface2fn2v := evalVariable(p, t, "iface2fn2")
  1518  		t.Logf("iface2fn2: %v\n", iface2fn2v)
  1519  	})
  1520  }
  1521  
  1522  func TestBreakpointCounts(t *testing.T) {
  1523  	protest.AllowRecording(t)
  1524  	withTestProcess("bpcountstest", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  1525  		bp := setFileBreakpoint(p, t, fixture.Source, 12)
  1526  
  1527  		for {
  1528  			if err := grp.Continue(); err != nil {
  1529  				if _, exited := err.(proc.ErrProcessExited); exited {
  1530  					break
  1531  				}
  1532  				assertNoError(err, t, "Continue()")
  1533  			}
  1534  		}
  1535  
  1536  		t.Logf("TotalHitCount: %d", bp.Logical.TotalHitCount)
  1537  		if bp.Logical.TotalHitCount != 200 {
  1538  			t.Fatalf("Wrong TotalHitCount for the breakpoint (%d)", bp.Logical.TotalHitCount)
  1539  		}
  1540  
  1541  		if len(bp.Logical.HitCount) != 2 {
  1542  			t.Fatalf("Wrong number of goroutines for breakpoint (%d)", len(bp.Logical.HitCount))
  1543  		}
  1544  
  1545  		for _, v := range bp.Logical.HitCount {
  1546  			if v != 100 {
  1547  				t.Fatalf("Wrong HitCount for breakpoint (%v)", bp.Logical.HitCount)
  1548  			}
  1549  		}
  1550  	})
  1551  }
  1552  
  1553  func TestHardcodedBreakpointCounts(t *testing.T) {
  1554  	skipOn(t, "broken", "windows", "arm64")
  1555  	withTestProcess("hcbpcountstest", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  1556  		counts := map[int64]int{}
  1557  		for {
  1558  			if err := grp.Continue(); err != nil {
  1559  				if _, exited := err.(proc.ErrProcessExited); exited {
  1560  					break
  1561  				}
  1562  				assertNoError(err, t, "Continue()")
  1563  			}
  1564  
  1565  			for _, th := range p.ThreadList() {
  1566  				bp := th.Breakpoint().Breakpoint
  1567  				if bp == nil {
  1568  					continue
  1569  				}
  1570  				if bp.Logical.Name != proc.HardcodedBreakpoint {
  1571  					t.Fatalf("wrong breakpoint name %s", bp.Logical.Name)
  1572  				}
  1573  				g, err := proc.GetG(th)
  1574  				assertNoError(err, t, "GetG")
  1575  				counts[g.ID]++
  1576  			}
  1577  		}
  1578  
  1579  		if len(counts) != 2 {
  1580  			t.Fatalf("Wrong number of goroutines for hardcoded breakpoint (%d)", len(counts))
  1581  		}
  1582  
  1583  		for goid, count := range counts {
  1584  			if count != 100 {
  1585  				t.Fatalf("Wrong hit count for hardcoded breakpoint (%d) on goroutine %d", count, goid)
  1586  			}
  1587  		}
  1588  	})
  1589  }
  1590  
  1591  func BenchmarkArray(b *testing.B) {
  1592  	// each bencharr struct is 128 bytes, bencharr is 64 elements long
  1593  	b.SetBytes(int64(64 * 128))
  1594  	withTestProcess("testvariables2", b, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  1595  		assertNoError(grp.Continue(), b, "Continue()")
  1596  		b.ResetTimer()
  1597  		for i := 0; i < b.N; i++ {
  1598  			evalVariable(p, b, "bencharr")
  1599  		}
  1600  	})
  1601  }
  1602  
  1603  const doTestBreakpointCountsWithDetection = false
  1604  
  1605  func TestBreakpointCountsWithDetection(t *testing.T) {
  1606  	if !doTestBreakpointCountsWithDetection {
  1607  		return
  1608  	}
  1609  	m := map[int64]int64{}
  1610  	protest.AllowRecording(t)
  1611  	withTestProcess("bpcountstest", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  1612  		bp := setFileBreakpoint(p, t, fixture.Source, 12)
  1613  
  1614  		for {
  1615  			if err := grp.Continue(); err != nil {
  1616  				if _, exited := err.(proc.ErrProcessExited); exited {
  1617  					break
  1618  				}
  1619  				assertNoError(err, t, "Continue()")
  1620  			}
  1621  			for _, th := range p.ThreadList() {
  1622  				if bp := th.Breakpoint(); bp.Breakpoint == nil {
  1623  					continue
  1624  				}
  1625  				scope, err := proc.GoroutineScope(p, th)
  1626  				assertNoError(err, t, "Scope()")
  1627  				v, err := scope.EvalExpression("i", normalLoadConfig)
  1628  				assertNoError(err, t, "evalVariable")
  1629  				i, _ := constant.Int64Val(v.Value)
  1630  				v, err = scope.EvalExpression("id", normalLoadConfig)
  1631  				assertNoError(err, t, "evalVariable")
  1632  				id, _ := constant.Int64Val(v.Value)
  1633  				m[id] = i
  1634  			}
  1635  
  1636  			total := int64(0)
  1637  			for i := range m {
  1638  				total += m[i] + 1
  1639  			}
  1640  
  1641  			if uint64(total) != bp.Logical.TotalHitCount {
  1642  				t.Fatalf("Mismatched total count %d %d\n", total, bp.Logical.TotalHitCount)
  1643  			}
  1644  		}
  1645  
  1646  		t.Logf("TotalHitCount: %d", bp.Logical.TotalHitCount)
  1647  		if bp.Logical.TotalHitCount != 200 {
  1648  			t.Fatalf("Wrong TotalHitCount for the breakpoint (%d)", bp.Logical.TotalHitCount)
  1649  		}
  1650  
  1651  		if len(bp.Logical.HitCount) != 2 {
  1652  			t.Fatalf("Wrong number of goroutines for breakpoint (%d)", len(bp.Logical.HitCount))
  1653  		}
  1654  
  1655  		for _, v := range bp.Logical.HitCount {
  1656  			if v != 100 {
  1657  				t.Fatalf("Wrong HitCount for breakpoint (%v)", bp.Logical.HitCount)
  1658  			}
  1659  		}
  1660  	})
  1661  }
  1662  
  1663  func BenchmarkArrayPointer(b *testing.B) {
  1664  	// each bencharr struct is 128 bytes, benchparr is an array of 64 pointers to bencharr
  1665  	// each read will read 64 bencharr structs plus the 64 pointers of benchparr
  1666  	b.SetBytes(int64(64*128 + 64*8))
  1667  	withTestProcess("testvariables2", b, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  1668  		assertNoError(grp.Continue(), b, "Continue()")
  1669  		b.ResetTimer()
  1670  		for i := 0; i < b.N; i++ {
  1671  			evalVariable(p, b, "bencharr")
  1672  		}
  1673  	})
  1674  }
  1675  
  1676  func BenchmarkMap(b *testing.B) {
  1677  	// m1 contains 41 entries, each one has a value that's 2 int values (2* 8 bytes) and a string key
  1678  	// each string key has an average of 9 character
  1679  	// reading strings and the map structure imposes a overhead that we ignore here
  1680  	b.SetBytes(int64(41 * (2*8 + 9)))
  1681  	withTestProcess("testvariables2", b, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  1682  		assertNoError(grp.Continue(), b, "Continue()")
  1683  		b.ResetTimer()
  1684  		for i := 0; i < b.N; i++ {
  1685  			evalVariable(p, b, "m1")
  1686  		}
  1687  	})
  1688  }
  1689  
  1690  func BenchmarkGoroutinesInfo(b *testing.B) {
  1691  	withTestProcess("testvariables2", b, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  1692  		assertNoError(grp.Continue(), b, "Continue()")
  1693  		b.ResetTimer()
  1694  		for i := 0; i < b.N; i++ {
  1695  			p.ClearCaches()
  1696  			_, _, err := proc.GoroutinesInfo(p, 0, 0)
  1697  			assertNoError(err, b, "GoroutinesInfo")
  1698  		}
  1699  	})
  1700  }
  1701  
  1702  func TestIssue262(t *testing.T) {
  1703  	// Continue does not work when the current breakpoint is set on a NOP instruction
  1704  	protest.AllowRecording(t)
  1705  	withTestProcess("issue262", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  1706  		setFileBreakpoint(p, t, fixture.Source, 11)
  1707  
  1708  		assertNoError(grp.Continue(), t, "Continue()")
  1709  		err := grp.Continue()
  1710  		if err == nil {
  1711  			t.Fatalf("No error on second continue")
  1712  		}
  1713  		_, exited := err.(proc.ErrProcessExited)
  1714  		if !exited {
  1715  			t.Fatalf("Process did not exit after second continue: %v", err)
  1716  		}
  1717  	})
  1718  }
  1719  
  1720  func TestIssue305(t *testing.T) {
  1721  	// If 'next' hits a breakpoint on the goroutine it's stepping through
  1722  	// the internal breakpoints aren't cleared preventing further use of
  1723  	// 'next' command
  1724  	protest.AllowRecording(t)
  1725  	withTestProcess("issue305", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  1726  		setFileBreakpoint(p, t, fixture.Source, 5)
  1727  
  1728  		assertNoError(grp.Continue(), t, "Continue()")
  1729  
  1730  		assertNoError(grp.Next(), t, "Next() 1")
  1731  		assertNoError(grp.Next(), t, "Next() 2")
  1732  		assertNoError(grp.Next(), t, "Next() 3")
  1733  		assertNoError(grp.Next(), t, "Next() 4")
  1734  		assertNoError(grp.Next(), t, "Next() 5")
  1735  	})
  1736  }
  1737  
  1738  func TestPointerLoops(t *testing.T) {
  1739  	// Pointer loops through map entries, pointers and slices
  1740  	// Regression test for issue #341
  1741  	protest.AllowRecording(t)
  1742  	withTestProcess("testvariables2", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  1743  		assertNoError(grp.Continue(), t, "Continue()")
  1744  		for _, expr := range []string{"mapinf", "ptrinf", "sliceinf"} {
  1745  			t.Logf("requesting %s", expr)
  1746  			v := evalVariable(p, t, expr)
  1747  			t.Logf("%s: %v\n", expr, v)
  1748  		}
  1749  	})
  1750  }
  1751  
  1752  func BenchmarkLocalVariables(b *testing.B) {
  1753  	withTestProcess("testvariables", b, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  1754  		assertNoError(grp.Continue(), b, "Continue() returned an error")
  1755  		scope, err := proc.GoroutineScope(p, p.CurrentThread())
  1756  		assertNoError(err, b, "Scope()")
  1757  		b.ResetTimer()
  1758  		for i := 0; i < b.N; i++ {
  1759  			_, err := scope.LocalVariables(normalLoadConfig)
  1760  			assertNoError(err, b, "LocalVariables()")
  1761  		}
  1762  	})
  1763  }
  1764  
  1765  func TestCondBreakpoint(t *testing.T) {
  1766  	protest.AllowRecording(t)
  1767  	withTestProcess("parallel_next", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  1768  		bp := setFileBreakpoint(p, t, fixture.Source, 9)
  1769  		bp.UserBreaklet().Cond = &ast.BinaryExpr{
  1770  			Op: token.EQL,
  1771  			X:  &ast.Ident{Name: "n"},
  1772  			Y:  &ast.BasicLit{Kind: token.INT, Value: "7"},
  1773  		}
  1774  
  1775  		assertNoError(grp.Continue(), t, "Continue()")
  1776  
  1777  		nvar := evalVariable(p, t, "n")
  1778  
  1779  		n, _ := constant.Int64Val(nvar.Value)
  1780  		if n != 7 {
  1781  			t.Fatalf("Stopped on wrong goroutine %d\n", n)
  1782  		}
  1783  	})
  1784  }
  1785  
  1786  func TestCondBreakpointWithFrame(t *testing.T) {
  1787  	protest.AllowRecording(t)
  1788  	withTestProcess("condframe", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  1789  		bp := setFileBreakpoint(p, t, fixture.Source, 12)
  1790  		parsed, err := parser.ParseExpr("runtime.frame(1).i == 3")
  1791  		if err != nil {
  1792  			t.Fatalf("failed to parse expression: %v", err)
  1793  		}
  1794  		bp.UserBreaklet().Cond = parsed
  1795  
  1796  		assertNoError(grp.Continue(), t, "Continue()")
  1797  
  1798  		g := p.SelectedGoroutine()
  1799  		scope, err := proc.ConvertEvalScope(p, g.ID, 1, 0)
  1800  		if err != nil {
  1801  			t.Fatal(err)
  1802  		}
  1803  
  1804  		v, err := scope.EvalExpression("i", normalLoadConfig)
  1805  		if err != nil {
  1806  			t.Fatal(err)
  1807  		}
  1808  
  1809  		vval, _ := constant.Int64Val(v.Value)
  1810  		if vval != 3 {
  1811  			t.Fatalf("Incorrect value for frame variable: %v", vval)
  1812  		}
  1813  	})
  1814  }
  1815  
  1816  func TestCondBreakpointError(t *testing.T) {
  1817  	protest.AllowRecording(t)
  1818  	withTestProcess("parallel_next", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  1819  		bp := setFileBreakpoint(p, t, fixture.Source, 9)
  1820  		bp.UserBreaklet().Cond = &ast.BinaryExpr{
  1821  			Op: token.EQL,
  1822  			X:  &ast.Ident{Name: "nonexistentvariable"},
  1823  			Y:  &ast.BasicLit{Kind: token.INT, Value: "7"},
  1824  		}
  1825  
  1826  		err := grp.Continue()
  1827  		if err == nil {
  1828  			t.Fatalf("No error on first Continue()")
  1829  		}
  1830  
  1831  		if err.Error() != "error evaluating expression: could not find symbol value for nonexistentvariable" && err.Error() != "multiple errors evaluating conditions" {
  1832  			t.Fatalf("Unexpected error on first Continue(): %v", err)
  1833  		}
  1834  
  1835  		bp.UserBreaklet().Cond = &ast.BinaryExpr{
  1836  			Op: token.EQL,
  1837  			X:  &ast.Ident{Name: "n"},
  1838  			Y:  &ast.BasicLit{Kind: token.INT, Value: "7"},
  1839  		}
  1840  
  1841  		err = grp.Continue()
  1842  		if err != nil {
  1843  			if _, exited := err.(proc.ErrProcessExited); !exited {
  1844  				t.Fatalf("Unexpected error on second Continue(): %v", err)
  1845  			}
  1846  		} else {
  1847  			nvar := evalVariable(p, t, "n")
  1848  
  1849  			n, _ := constant.Int64Val(nvar.Value)
  1850  			if n != 7 {
  1851  				t.Fatalf("Stopped on wrong goroutine %d\n", n)
  1852  			}
  1853  		}
  1854  	})
  1855  }
  1856  
  1857  func TestHitCondBreakpointEQ(t *testing.T) {
  1858  	withTestProcess("break", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  1859  		bp := setFileBreakpoint(p, t, fixture.Source, 7)
  1860  		bp.Logical.HitCond = &struct {
  1861  			Op  token.Token
  1862  			Val int
  1863  		}{token.EQL, 3}
  1864  
  1865  		assertNoError(grp.Continue(), t, "Continue()")
  1866  		ivar := evalVariable(p, t, "i")
  1867  
  1868  		i, _ := constant.Int64Val(ivar.Value)
  1869  		if i != 3 {
  1870  			t.Fatalf("Stopped on wrong hitcount %d\n", i)
  1871  		}
  1872  
  1873  		err := grp.Continue()
  1874  		if _, exited := err.(proc.ErrProcessExited); !exited {
  1875  			t.Fatalf("Unexpected error on Continue(): %v", err)
  1876  		}
  1877  	})
  1878  }
  1879  
  1880  func TestHitCondBreakpointGEQ(t *testing.T) {
  1881  	protest.AllowRecording(t)
  1882  	withTestProcess("break", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  1883  		bp := setFileBreakpoint(p, t, fixture.Source, 7)
  1884  		bp.Logical.HitCond = &struct {
  1885  			Op  token.Token
  1886  			Val int
  1887  		}{token.GEQ, 3}
  1888  
  1889  		for it := 3; it <= 10; it++ {
  1890  			assertNoError(grp.Continue(), t, "Continue()")
  1891  			ivar := evalVariable(p, t, "i")
  1892  
  1893  			i, _ := constant.Int64Val(ivar.Value)
  1894  			if int(i) != it {
  1895  				t.Fatalf("Stopped on wrong hitcount %d\n", i)
  1896  			}
  1897  		}
  1898  
  1899  		assertNoError(grp.Continue(), t, "Continue()")
  1900  	})
  1901  }
  1902  
  1903  func TestHitCondBreakpointREM(t *testing.T) {
  1904  	protest.AllowRecording(t)
  1905  	withTestProcess("break", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  1906  		bp := setFileBreakpoint(p, t, fixture.Source, 7)
  1907  		bp.Logical.HitCond = &struct {
  1908  			Op  token.Token
  1909  			Val int
  1910  		}{token.REM, 2}
  1911  
  1912  		for it := 2; it <= 10; it += 2 {
  1913  			assertNoError(grp.Continue(), t, "Continue()")
  1914  			ivar := evalVariable(p, t, "i")
  1915  
  1916  			i, _ := constant.Int64Val(ivar.Value)
  1917  			if int(i) != it {
  1918  				t.Fatalf("Stopped on wrong hitcount %d\n", i)
  1919  			}
  1920  		}
  1921  
  1922  		err := grp.Continue()
  1923  		if _, exited := err.(proc.ErrProcessExited); !exited {
  1924  			t.Fatalf("Unexpected error on Continue(): %v", err)
  1925  		}
  1926  	})
  1927  }
  1928  
  1929  func TestIssue356(t *testing.T) {
  1930  	// slice with a typedef does not get printed correctly
  1931  	protest.AllowRecording(t)
  1932  	withTestProcess("testvariables2", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  1933  		assertNoError(grp.Continue(), t, "Continue() returned an error")
  1934  		mmvar := evalVariable(p, t, "mainMenu")
  1935  		if mmvar.Kind != reflect.Slice {
  1936  			t.Fatalf("Wrong kind for mainMenu: %v\n", mmvar.Kind)
  1937  		}
  1938  	})
  1939  }
  1940  
  1941  func TestStepIntoFunction(t *testing.T) {
  1942  	withTestProcess("teststep", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  1943  		// Continue until breakpoint
  1944  		assertNoError(grp.Continue(), t, "Continue() returned an error")
  1945  		// Step into function
  1946  		assertNoError(grp.Step(), t, "Step() returned an error")
  1947  		// We should now be inside the function.
  1948  		loc, err := p.CurrentThread().Location()
  1949  		if err != nil {
  1950  			t.Fatal(err)
  1951  		}
  1952  		if loc.Fn.Name != "main.callme" {
  1953  			t.Fatalf("expected to be within the 'callme' function, was in %s instead", loc.Fn.Name)
  1954  		}
  1955  		if !strings.Contains(loc.File, "teststep") {
  1956  			t.Fatalf("debugger stopped at incorrect location: %s:%d", loc.File, loc.Line)
  1957  		}
  1958  		if loc.Line != 8 {
  1959  			t.Fatalf("debugger stopped at incorrect line: %d", loc.Line)
  1960  		}
  1961  	})
  1962  }
  1963  
  1964  func TestIssue332_Part1(t *testing.T) {
  1965  	// Next shouldn't step inside a function call
  1966  	protest.AllowRecording(t)
  1967  	withTestProcess("issue332", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  1968  		setFileBreakpoint(p, t, fixture.Source, 8)
  1969  		assertNoError(grp.Continue(), t, "Continue()")
  1970  		assertNoError(grp.Next(), t, "first Next()")
  1971  		locations, err := proc.ThreadStacktrace(p, p.CurrentThread(), 2)
  1972  		assertNoError(err, t, "Stacktrace()")
  1973  		if locations[0].Call.Fn == nil {
  1974  			t.Fatalf("Not on a function")
  1975  		}
  1976  		if locations[0].Call.Fn.Name != "main.main" {
  1977  			t.Fatalf("Not on main.main after Next: %s (%s:%d)", locations[0].Call.Fn.Name, locations[0].Call.File, locations[0].Call.Line)
  1978  		}
  1979  		if locations[0].Call.Line != 9 {
  1980  			t.Fatalf("Not on line 9 after Next: %s (%s:%d)", locations[0].Call.Fn.Name, locations[0].Call.File, locations[0].Call.Line)
  1981  		}
  1982  	})
  1983  }
  1984  
  1985  func TestIssue332_Part2(t *testing.T) {
  1986  	// Step should skip a function's prologue
  1987  	// In some parts of the prologue, for some functions, the FDE data is incorrect
  1988  	// which leads to 'next' and 'stack' failing with error "could not find FDE for PC: <garbage>"
  1989  	// because the incorrect FDE data leads to reading the wrong stack address as the return address
  1990  	protest.AllowRecording(t)
  1991  	withTestProcess("issue332", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  1992  		setFileBreakpoint(p, t, fixture.Source, 8)
  1993  		assertNoError(grp.Continue(), t, "Continue()")
  1994  
  1995  		// step until we enter changeMe
  1996  		for {
  1997  			assertNoError(grp.Step(), t, "Step()")
  1998  			locations, err := proc.ThreadStacktrace(p, p.CurrentThread(), 2)
  1999  			assertNoError(err, t, "Stacktrace()")
  2000  			if locations[0].Call.Fn == nil {
  2001  				t.Fatalf("Not on a function")
  2002  			}
  2003  			if locations[0].Call.Fn.Name == "main.changeMe" {
  2004  				break
  2005  			}
  2006  		}
  2007  
  2008  		regs, err := p.CurrentThread().Registers()
  2009  		assertNoError(err, t, "Registers()")
  2010  		pc := regs.PC()
  2011  		pcAfterPrologue := findFunctionLocation(p, t, "main.changeMe")
  2012  		if pcAfterPrologue == p.BinInfo().LookupFunc()["main.changeMe"][0].Entry {
  2013  			t.Fatalf("main.changeMe and main.changeMe:0 are the same (%x)", pcAfterPrologue)
  2014  		}
  2015  		if pc != pcAfterPrologue {
  2016  			t.Fatalf("Step did not skip the prologue: current pc: %x, first instruction after prologue: %x", pc, pcAfterPrologue)
  2017  		}
  2018  
  2019  		assertNoError(grp.Next(), t, "first Next()")
  2020  		assertNoError(grp.Next(), t, "second Next()")
  2021  		assertNoError(grp.Next(), t, "third Next()")
  2022  		err = grp.Continue()
  2023  		if _, exited := err.(proc.ErrProcessExited); !exited {
  2024  			assertNoError(err, t, "final Continue()")
  2025  		}
  2026  	})
  2027  }
  2028  
  2029  func TestIssue414(t *testing.T) {
  2030  	skipOn(t, "broken", "linux", "386", "pie") // test occasionally hangs on linux/386/pie
  2031  	// Stepping until the program exits
  2032  	protest.AllowRecording(t)
  2033  	withTestProcess("math", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  2034  		setFileBreakpoint(p, t, fixture.Source, 9)
  2035  		assertNoError(grp.Continue(), t, "Continue()")
  2036  		for {
  2037  			pc := currentPC(p, t)
  2038  			f, ln := currentLineNumber(p, t)
  2039  			t.Logf("at %s:%d %#x\n", f, ln, pc)
  2040  			var err error
  2041  			// Stepping through the runtime is not generally safe so after we are out
  2042  			// of main.main just use Next.
  2043  			// See: https://gitlab.com/Raven-IO/raven-delve/pull/2082
  2044  			if f == fixture.Source {
  2045  				err = grp.Step()
  2046  			} else {
  2047  				err = grp.Next()
  2048  			}
  2049  			if err != nil {
  2050  				if _, exited := err.(proc.ErrProcessExited); exited {
  2051  					break
  2052  				}
  2053  			}
  2054  			assertNoError(err, t, "Step()")
  2055  		}
  2056  	})
  2057  }
  2058  
  2059  func TestPackageVariables(t *testing.T) {
  2060  	var skippedVariable = map[string]bool{
  2061  		"runtime.uint16Eface": true,
  2062  		"runtime.uint32Eface": true,
  2063  		"runtime.uint64Eface": true,
  2064  		"runtime.stringEface": true,
  2065  		"runtime.sliceEface":  true,
  2066  	}
  2067  
  2068  	protest.AllowRecording(t)
  2069  	withTestProcess("testvariables", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  2070  		err := grp.Continue()
  2071  		assertNoError(err, t, "Continue()")
  2072  		scope, err := proc.GoroutineScope(p, p.CurrentThread())
  2073  		assertNoError(err, t, "Scope()")
  2074  		vars, err := scope.PackageVariables(normalLoadConfig)
  2075  		assertNoError(err, t, "PackageVariables()")
  2076  		failed := false
  2077  		for _, v := range vars {
  2078  			if skippedVariable[v.Name] {
  2079  				continue
  2080  			}
  2081  			if v.Unreadable != nil && v.Unreadable.Error() != "no location attribute Location" {
  2082  				failed = true
  2083  				t.Logf("Unreadable variable %s: %v", v.Name, v.Unreadable)
  2084  			}
  2085  		}
  2086  		if failed {
  2087  			t.Fatalf("previous errors")
  2088  		}
  2089  	})
  2090  }
  2091  
  2092  func TestIssue149(t *testing.T) {
  2093  	ver, _ := goversion.Parse(runtime.Version())
  2094  	if ver.Major > 0 && !ver.AfterOrEqual(goversion.GoVersion{Major: 1, Minor: 7, Rev: -1}) {
  2095  		return
  2096  	}
  2097  	// setting breakpoint on break statement
  2098  	withTestProcess("break", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  2099  		findFileLocation(p, t, fixture.Source, 8)
  2100  	})
  2101  }
  2102  
  2103  func TestPanicBreakpoint(t *testing.T) {
  2104  	protest.AllowRecording(t)
  2105  	withTestProcess("panic", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  2106  		assertNoError(grp.Continue(), t, "Continue()")
  2107  		bp := p.CurrentThread().Breakpoint()
  2108  		if bp.Breakpoint == nil || bp.Logical.Name != proc.UnrecoveredPanic {
  2109  			t.Fatalf("not on unrecovered-panic breakpoint: %v", bp)
  2110  		}
  2111  	})
  2112  }
  2113  
  2114  func TestCmdLineArgs(t *testing.T) {
  2115  	expectSuccess := func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  2116  		err := grp.Continue()
  2117  		bp := p.CurrentThread().Breakpoint()
  2118  		if bp.Breakpoint != nil && bp.Logical.Name == proc.UnrecoveredPanic {
  2119  			t.Fatalf("testing args failed on unrecovered-panic breakpoint: %v", bp)
  2120  		}
  2121  		exit, exited := err.(proc.ErrProcessExited)
  2122  		if !exited {
  2123  			t.Fatalf("Process did not exit: %v", err)
  2124  		} else {
  2125  			if exit.Status != 0 {
  2126  				t.Fatalf("process exited with invalid status %d", exit.Status)
  2127  			}
  2128  		}
  2129  	}
  2130  
  2131  	expectPanic := func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  2132  		grp.Continue()
  2133  		bp := p.CurrentThread().Breakpoint()
  2134  		if bp.Breakpoint == nil || bp.Logical.Name != proc.UnrecoveredPanic {
  2135  			t.Fatalf("not on unrecovered-panic breakpoint: %v", bp)
  2136  		}
  2137  	}
  2138  
  2139  	// make sure multiple arguments (including one with spaces) are passed to the binary correctly
  2140  	withTestProcessArgs("testargs", t, ".", []string{"test"}, 0, expectSuccess)
  2141  	withTestProcessArgs("testargs", t, ".", []string{"-test"}, 0, expectPanic)
  2142  	withTestProcessArgs("testargs", t, ".", []string{"test", "pass flag"}, 0, expectSuccess)
  2143  	// check that arguments with spaces are *only* passed correctly when correctly called
  2144  	withTestProcessArgs("testargs", t, ".", []string{"test pass", "flag"}, 0, expectPanic)
  2145  	withTestProcessArgs("testargs", t, ".", []string{"test", "pass", "flag"}, 0, expectPanic)
  2146  	withTestProcessArgs("testargs", t, ".", []string{"test pass flag"}, 0, expectPanic)
  2147  	// and that invalid cases (wrong arguments or no arguments) panic
  2148  	withTestProcess("testargs", t, expectPanic)
  2149  	withTestProcessArgs("testargs", t, ".", []string{"invalid"}, 0, expectPanic)
  2150  	withTestProcessArgs("testargs", t, ".", []string{"test", "invalid"}, 0, expectPanic)
  2151  	withTestProcessArgs("testargs", t, ".", []string{"invalid", "pass flag"}, 0, expectPanic)
  2152  }
  2153  
  2154  func TestIssue462(t *testing.T) {
  2155  	skipOn(t, "broken", "windows") // Stacktrace of Goroutine 0 fails with an error
  2156  	withTestProcess("testnextnethttp", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  2157  		go func() {
  2158  			// Wait for program to start listening.
  2159  			for {
  2160  				conn, err := net.Dial("tcp", "127.0.0.1:9191")
  2161  				if err == nil {
  2162  					conn.Close()
  2163  					break
  2164  				}
  2165  				time.Sleep(50 * time.Millisecond)
  2166  			}
  2167  
  2168  			grp.RequestManualStop()
  2169  		}()
  2170  
  2171  		assertNoError(grp.Continue(), t, "Continue()")
  2172  		_, err := proc.ThreadStacktrace(p, p.CurrentThread(), 40)
  2173  		assertNoError(err, t, "Stacktrace()")
  2174  	})
  2175  }
  2176  
  2177  func TestNextParked(t *testing.T) {
  2178  	protest.AllowRecording(t)
  2179  	withTestProcess("parallel_next", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  2180  		bp := setFunctionBreakpoint(p, t, "main.sayhi")
  2181  
  2182  		// continue until a parked goroutine exists
  2183  		var parkedg *proc.G
  2184  		for parkedg == nil {
  2185  			err := grp.Continue()
  2186  			if _, exited := err.(proc.ErrProcessExited); exited {
  2187  				t.Log("could not find parked goroutine")
  2188  				return
  2189  			}
  2190  			assertNoError(err, t, "Continue()")
  2191  
  2192  			gs, _, err := proc.GoroutinesInfo(p, 0, 0)
  2193  			assertNoError(err, t, "GoroutinesInfo()")
  2194  
  2195  			// Search for a parked goroutine that we know for sure will have to be
  2196  			// resumed before the program can exit. This is a parked goroutine that:
  2197  			// 1. is executing main.sayhi
  2198  			// 2. hasn't called wg.Done yet
  2199  			for _, g := range gs {
  2200  				if g.Thread != nil {
  2201  					continue
  2202  				}
  2203  				frames, _ := proc.GoroutineStacktrace(p, g, 5, 0)
  2204  				for _, frame := range frames {
  2205  					// line 11 is the line where wg.Done is called
  2206  					if frame.Current.Fn != nil && frame.Current.Fn.Name == "main.sayhi" && frame.Current.Line < 11 {
  2207  						parkedg = g
  2208  						break
  2209  					}
  2210  				}
  2211  				if parkedg != nil {
  2212  					break
  2213  				}
  2214  			}
  2215  		}
  2216  
  2217  		assertNoError(p.SwitchGoroutine(parkedg), t, "SwitchGoroutine()")
  2218  		p.ClearBreakpoint(bp.Addr)
  2219  		assertNoError(grp.Next(), t, "Next()")
  2220  
  2221  		if p.SelectedGoroutine().ID != parkedg.ID {
  2222  			t.Fatalf("Next did not continue on the selected goroutine, expected %d got %d", parkedg.ID, p.SelectedGoroutine().ID)
  2223  		}
  2224  	})
  2225  }
  2226  
  2227  func TestStepParked(t *testing.T) {
  2228  	protest.AllowRecording(t)
  2229  	withTestProcess("parallel_next", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  2230  		bp := setFunctionBreakpoint(p, t, "main.sayhi")
  2231  
  2232  		// continue until a parked goroutine exists
  2233  		var parkedg *proc.G
  2234  	LookForParkedG:
  2235  		for {
  2236  			err := grp.Continue()
  2237  			if _, exited := err.(proc.ErrProcessExited); exited {
  2238  				t.Log("could not find parked goroutine")
  2239  				return
  2240  			}
  2241  			assertNoError(err, t, "Continue()")
  2242  
  2243  			gs, _, err := proc.GoroutinesInfo(p, 0, 0)
  2244  			assertNoError(err, t, "GoroutinesInfo()")
  2245  
  2246  			for _, g := range gs {
  2247  				if g.Thread == nil && g.CurrentLoc.Fn != nil && g.CurrentLoc.Fn.Name == "main.sayhi" {
  2248  					parkedg = g
  2249  					break LookForParkedG
  2250  				}
  2251  			}
  2252  		}
  2253  
  2254  		t.Logf("Parked g is: %v\n", parkedg)
  2255  		frames, _ := proc.GoroutineStacktrace(p, parkedg, 20, 0)
  2256  		for _, frame := range frames {
  2257  			name := ""
  2258  			if frame.Call.Fn != nil {
  2259  				name = frame.Call.Fn.Name
  2260  			}
  2261  			t.Logf("\t%s:%d in %s (%#x)", frame.Call.File, frame.Call.Line, name, frame.Current.PC)
  2262  		}
  2263  
  2264  		assertNoError(p.SwitchGoroutine(parkedg), t, "SwitchGoroutine()")
  2265  		p.ClearBreakpoint(bp.Addr)
  2266  		assertNoError(grp.Step(), t, "Step()")
  2267  
  2268  		if p.SelectedGoroutine().ID != parkedg.ID {
  2269  			t.Fatalf("Step did not continue on the selected goroutine, expected %d got %d", parkedg.ID, p.SelectedGoroutine().ID)
  2270  		}
  2271  	})
  2272  }
  2273  
  2274  func TestUnsupportedArch(t *testing.T) {
  2275  	ver, _ := goversion.Parse(runtime.Version())
  2276  	if ver.Major < 0 || !ver.AfterOrEqual(goversion.GoVersion{Major: 1, Minor: 6, Rev: -1}) || ver.AfterOrEqual(goversion.GoVersion{Major: 1, Minor: 7, Rev: -1}) {
  2277  		// cross compile (with -N?) works only on select versions of go
  2278  		return
  2279  	}
  2280  
  2281  	fixturesDir := protest.FindFixturesDir()
  2282  	infile := filepath.Join(fixturesDir, "math.go")
  2283  	outfile := filepath.Join(fixturesDir, "_math_debug_386")
  2284  
  2285  	cmd := exec.Command("go", "build", "-gcflags=-N -l", "-o", outfile, infile)
  2286  	for _, v := range os.Environ() {
  2287  		if !strings.HasPrefix(v, "GOARCH=") {
  2288  			cmd.Env = append(cmd.Env, v)
  2289  		}
  2290  	}
  2291  	cmd.Env = append(cmd.Env, "GOARCH=386")
  2292  	out, err := cmd.CombinedOutput()
  2293  	if err != nil {
  2294  		t.Fatalf("go build failed: %v: %v", err, string(out))
  2295  	}
  2296  	defer os.Remove(outfile)
  2297  
  2298  	var p *proc.TargetGroup
  2299  
  2300  	switch testBackend {
  2301  	case "native":
  2302  		p, err = native.Launch([]string{outfile}, ".", 0, []string{}, "", "", proc.OutputRedirect{}, proc.OutputRedirect{})
  2303  	case "lldb":
  2304  		p, err = gdbserial.LLDBLaunch([]string{outfile}, ".", 0, []string{}, "", [3]string{})
  2305  	default:
  2306  		t.Skip("test not valid for this backend")
  2307  	}
  2308  
  2309  	if err == nil {
  2310  		p.Detach(true)
  2311  		t.Fatal("Launch is expected to fail, but succeeded")
  2312  	}
  2313  
  2314  	if _, ok := err.(*proc.ErrUnsupportedArch); ok {
  2315  		// all good
  2316  		return
  2317  	}
  2318  
  2319  	t.Fatal(err)
  2320  }
  2321  
  2322  func TestIssue573(t *testing.T) {
  2323  	// calls to runtime.duffzero and runtime.duffcopy jump directly into the middle
  2324  	// of the function and the internal breakpoint set by StepInto may be missed.
  2325  	protest.AllowRecording(t)
  2326  	withTestProcess("issue573", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  2327  		setFunctionBreakpoint(p, t, "main.foo")
  2328  		assertNoError(grp.Continue(), t, "Continue()")
  2329  		assertNoError(grp.Step(), t, "Step() #1")
  2330  		assertNoError(grp.Step(), t, "Step() #2") // Bug exits here.
  2331  		assertNoError(grp.Step(), t, "Step() #3") // Third step ought to be possible; program ought not have exited.
  2332  	})
  2333  }
  2334  
  2335  func TestTestvariables2Prologue(t *testing.T) {
  2336  	withTestProcess("testvariables2", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  2337  		addrEntry := p.BinInfo().LookupFunc()["main.main"][0].Entry
  2338  		addrPrologue := findFunctionLocation(p, t, "main.main")
  2339  		if addrEntry == addrPrologue {
  2340  			t.Fatalf("Prologue detection failed on testvariables2.go/main.main")
  2341  		}
  2342  	})
  2343  }
  2344  
  2345  func TestNextDeferReturnAndDirectCall(t *testing.T) {
  2346  	// Next should not step into a deferred function if it is called
  2347  	// directly, only if it is called through a panic or a deferreturn.
  2348  	// Here we test the case where the function is called by a deferreturn
  2349  	testseq("defercall", contNext, []nextTest{
  2350  		{9, 10},
  2351  		{10, 11},
  2352  		{11, 12},
  2353  		{12, 13},
  2354  		{13, 28}}, "main.callAndDeferReturn", t)
  2355  }
  2356  
  2357  func TestNextPanicAndDirectCall(t *testing.T) {
  2358  	// Next should not step into a deferred function if it is called
  2359  	// directly, only if it is called through a panic or a deferreturn.
  2360  	// Here we test the case where the function is called by a panic
  2361  	testseq("defercall", contNext, []nextTest{
  2362  		{15, 16},
  2363  		{16, 17},
  2364  		{17, 18},
  2365  		{18, 6}}, "main.callAndPanic2", t)
  2366  }
  2367  
  2368  func TestStepCall(t *testing.T) {
  2369  	testseq("testnextprog", contStep, []nextTest{
  2370  		{34, 13},
  2371  		{13, 14}}, "", t)
  2372  }
  2373  
  2374  func TestStepCallPtr(t *testing.T) {
  2375  	// Tests that Step works correctly when calling functions with a
  2376  	// function pointer.
  2377  	if goversion.VersionAfterOrEqual(runtime.Version(), 1, 11) && !protest.RegabiSupported() {
  2378  		testseq("teststepprog", contStep, []nextTest{
  2379  			{9, 10},
  2380  			{10, 6},
  2381  			{6, 7},
  2382  			{7, 11}}, "", t)
  2383  	} else {
  2384  		if runtime.GOOS == "linux" && runtime.GOARCH == "ppc64le" && buildMode == "pie" {
  2385  			testseq("teststepprog", contStep, []nextTest{
  2386  				{9, 10},
  2387  				{10, 5},
  2388  				{5, 6},
  2389  				{6, 7},
  2390  				{7, 10},
  2391  				{10, 11}}, "", t)
  2392  		} else {
  2393  			testseq("teststepprog", contStep, []nextTest{
  2394  				{9, 10},
  2395  				{10, 5},
  2396  				{5, 6},
  2397  				{6, 7},
  2398  				{7, 11}}, "", t)
  2399  		}
  2400  	}
  2401  }
  2402  
  2403  func TestStepReturnAndPanic(t *testing.T) {
  2404  	// Tests that Step works correctly when returning from functions
  2405  	// and when a deferred function is called when panic'ing.
  2406  	testseq("defercall", contStep, []nextTest{
  2407  		{17, 6},
  2408  		{6, 7},
  2409  		{7, 18},
  2410  		{18, 6},
  2411  		{6, 7}}, "", t)
  2412  }
  2413  
  2414  func TestStepDeferReturn(t *testing.T) {
  2415  	// Tests that Step works correctly when a deferred function is
  2416  	// called during a return.
  2417  	testseq("defercall", contStep, []nextTest{
  2418  		{11, 6},
  2419  		{6, 7},
  2420  		{7, 12},
  2421  		{12, 13},
  2422  		{13, 6},
  2423  		{6, 7},
  2424  		{7, 13},
  2425  		{13, 28}}, "", t)
  2426  }
  2427  
  2428  func TestStepIgnorePrivateRuntime(t *testing.T) {
  2429  	// Tests that Step will ignore calls to private runtime functions
  2430  	// (such as runtime.convT2E in this case)
  2431  	switch {
  2432  	case goversion.VersionAfterOrEqual(runtime.Version(), 1, 17) && protest.RegabiSupported():
  2433  		testseq("teststepprog", contStep, []nextTest{
  2434  			{21, 13},
  2435  			{13, 14},
  2436  			{14, 15},
  2437  			{15, 17},
  2438  			{17, 22}}, "", t)
  2439  	case goversion.VersionAfterOrEqual(runtime.Version(), 1, 17):
  2440  		testseq("teststepprog", contStep, []nextTest{
  2441  			{21, 14},
  2442  			{14, 15},
  2443  			{15, 17},
  2444  			{17, 22}}, "", t)
  2445  	case goversion.VersionAfterOrEqual(runtime.Version(), 1, 11):
  2446  		testseq("teststepprog", contStep, []nextTest{
  2447  			{21, 14},
  2448  			{14, 15},
  2449  			{15, 22}}, "", t)
  2450  	default:
  2451  		panic("too old")
  2452  	}
  2453  }
  2454  
  2455  func TestIssue561(t *testing.T) {
  2456  	// Step fails to make progress when PC is at a CALL instruction
  2457  	// where a breakpoint is also set.
  2458  	protest.AllowRecording(t)
  2459  	withTestProcess("issue561", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  2460  		setFileBreakpoint(p, t, fixture.Source, 10)
  2461  		assertNoError(grp.Continue(), t, "Continue()")
  2462  		assertNoError(grp.Step(), t, "Step()")
  2463  		assertLineNumber(p, t, 5, "wrong line number after Step,")
  2464  	})
  2465  }
  2466  
  2467  func TestGoroutineLabels(t *testing.T) {
  2468  	withTestProcess("goroutineLabels", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  2469  		assertNoError(grp.Continue(), t, "Continue()")
  2470  		g, err := proc.GetG(p.CurrentThread())
  2471  		assertNoError(err, t, "GetG()")
  2472  		if len(g.Labels()) != 0 {
  2473  			t.Fatalf("No labels expected")
  2474  		}
  2475  
  2476  		assertNoError(grp.Continue(), t, "Continue()")
  2477  		g, err = proc.GetG(p.CurrentThread())
  2478  		assertNoError(err, t, "GetG()")
  2479  		labels := g.Labels()
  2480  		if v := labels["k1"]; v != "v1" {
  2481  			t.Errorf("Unexpected label value k1=%v", v)
  2482  		}
  2483  		if v := labels["k2"]; v != "v2" {
  2484  			t.Errorf("Unexpected label value k2=%v", v)
  2485  		}
  2486  	})
  2487  }
  2488  
  2489  func TestStepOut(t *testing.T) {
  2490  	testseq2(t, "testnextprog", "main.helloworld", []seqTest{{contContinue, 13}, {contStepout, 35}})
  2491  }
  2492  
  2493  func TestStepConcurrentDirect(t *testing.T) {
  2494  	skipOn(t, "broken - step concurrent", "windows", "arm64")
  2495  	protest.AllowRecording(t)
  2496  	withTestProcess("teststepconcurrent", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  2497  		bp := setFileBreakpoint(p, t, fixture.Source, 37)
  2498  
  2499  		assertNoError(grp.Continue(), t, "Continue()")
  2500  		err := p.ClearBreakpoint(bp.Addr)
  2501  		assertNoError(err, t, "ClearBreakpoint()")
  2502  
  2503  		for _, b := range p.Breakpoints().M {
  2504  			if b.Logical.Name == proc.UnrecoveredPanic {
  2505  				err := p.ClearBreakpoint(b.Addr)
  2506  				assertNoError(err, t, "ClearBreakpoint(unrecovered-panic)")
  2507  				break
  2508  			}
  2509  		}
  2510  
  2511  		gid := p.SelectedGoroutine().ID
  2512  
  2513  		seq := []int{37, 38, 13, 15, 16, 38}
  2514  
  2515  		i := 0
  2516  		count := 0
  2517  		for {
  2518  			anyerr := false
  2519  			if p.SelectedGoroutine().ID != gid {
  2520  				t.Errorf("Step switched to different goroutine %d %d\n", gid, p.SelectedGoroutine().ID)
  2521  				anyerr = true
  2522  			}
  2523  			f, ln := currentLineNumber(p, t)
  2524  			if ln != seq[i] {
  2525  				if i == 1 && ln == 40 {
  2526  					// loop exited
  2527  					break
  2528  				}
  2529  				frames, err := proc.ThreadStacktrace(p, p.CurrentThread(), 20)
  2530  				if err != nil {
  2531  					t.Errorf("Could not get stacktrace of goroutine %d\n", p.SelectedGoroutine().ID)
  2532  				} else {
  2533  					t.Logf("Goroutine %d (thread: %d):", p.SelectedGoroutine().ID, p.CurrentThread().ThreadID())
  2534  					for _, frame := range frames {
  2535  						t.Logf("\t%s:%d (%#x)", frame.Call.File, frame.Call.Line, frame.Current.PC)
  2536  					}
  2537  				}
  2538  				t.Errorf("Program did not continue at expected location (%d) %s:%d [i %d count %d]", seq[i], f, ln, i, count)
  2539  				anyerr = true
  2540  			}
  2541  			if anyerr {
  2542  				t.FailNow()
  2543  			}
  2544  			i = (i + 1) % len(seq)
  2545  			if i == 0 {
  2546  				count++
  2547  			}
  2548  			assertNoError(grp.Step(), t, "Step()")
  2549  		}
  2550  
  2551  		if count != 100 {
  2552  			t.Fatalf("Program did not loop expected number of times: %d", count)
  2553  		}
  2554  	})
  2555  }
  2556  
  2557  func TestStepConcurrentPtr(t *testing.T) {
  2558  	protest.AllowRecording(t)
  2559  	withTestProcess("teststepconcurrent", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  2560  		setFileBreakpoint(p, t, fixture.Source, 24)
  2561  
  2562  		for _, b := range p.Breakpoints().M {
  2563  			if b.Logical.Name == proc.UnrecoveredPanic {
  2564  				err := p.ClearBreakpoint(b.Addr)
  2565  				assertNoError(err, t, "ClearBreakpoint(unrecovered-panic)")
  2566  				break
  2567  			}
  2568  		}
  2569  
  2570  		kvals := map[int64]int64{}
  2571  		count := 0
  2572  		for {
  2573  			err := grp.Continue()
  2574  			_, exited := err.(proc.ErrProcessExited)
  2575  			if exited {
  2576  				break
  2577  			}
  2578  			assertNoError(err, t, "Continue()")
  2579  
  2580  			f, ln := currentLineNumber(p, t)
  2581  			if ln != 24 {
  2582  				for _, th := range p.ThreadList() {
  2583  					t.Logf("thread %d stopped on breakpoint %v", th.ThreadID(), th.Breakpoint())
  2584  				}
  2585  				curbp := p.CurrentThread().Breakpoint()
  2586  				t.Fatalf("Program did not continue at expected location (24): %s:%d %#x [%v] (gid %d count %d)", f, ln, currentPC(p, t), curbp, p.SelectedGoroutine().ID, count)
  2587  			}
  2588  
  2589  			gid := p.SelectedGoroutine().ID
  2590  
  2591  			kvar := evalVariable(p, t, "k")
  2592  			k, _ := constant.Int64Val(kvar.Value)
  2593  
  2594  			if oldk, ok := kvals[gid]; ok {
  2595  				if oldk >= k {
  2596  					t.Fatalf("Goroutine %d did not make progress?", gid)
  2597  				}
  2598  			}
  2599  			kvals[gid] = k
  2600  
  2601  			assertNoError(grp.Step(), t, "Step()")
  2602  			for p.Breakpoints().HasSteppingBreakpoints() {
  2603  				if p.SelectedGoroutine().ID == gid {
  2604  					t.Fatalf("step did not step into function call (but internal breakpoints still active?) (%d %d)", gid, p.SelectedGoroutine().ID)
  2605  				}
  2606  				assertNoError(grp.Continue(), t, "Continue()")
  2607  			}
  2608  
  2609  			if p.SelectedGoroutine().ID != gid {
  2610  				t.Fatalf("Step switched goroutines (wanted: %d got: %d)", gid, p.SelectedGoroutine().ID)
  2611  			}
  2612  
  2613  			f, ln = assertLineNumber(p, t, 13, "Step did not step into function call")
  2614  
  2615  			count++
  2616  			if count > 50 {
  2617  				// this test could potentially go on for 10000 cycles, since that's
  2618  				// too slow we cut the execution after 50 cycles
  2619  				break
  2620  			}
  2621  		}
  2622  
  2623  		if count == 0 {
  2624  			t.Fatalf("Breakpoint never hit")
  2625  		}
  2626  	})
  2627  }
  2628  
  2629  func TestStepOutBreakpoint(t *testing.T) {
  2630  	protest.AllowRecording(t)
  2631  	withTestProcess("testnextprog", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  2632  		bp := setFileBreakpoint(p, t, fixture.Source, 13)
  2633  		assertNoError(grp.Continue(), t, "Continue()")
  2634  		p.ClearBreakpoint(bp.Addr)
  2635  
  2636  		// StepOut should be interrupted by a breakpoint on the same goroutine.
  2637  		setFileBreakpoint(p, t, fixture.Source, 14)
  2638  		assertNoError(grp.StepOut(), t, "StepOut()")
  2639  		assertLineNumber(p, t, 14, "wrong line number")
  2640  		if p.Breakpoints().HasSteppingBreakpoints() {
  2641  			t.Fatal("has internal breakpoints after hitting breakpoint on same goroutine")
  2642  		}
  2643  	})
  2644  }
  2645  
  2646  func TestNextBreakpoint(t *testing.T) {
  2647  	protest.AllowRecording(t)
  2648  	withTestProcess("testnextprog", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  2649  		bp := setFileBreakpoint(p, t, fixture.Source, 34)
  2650  		assertNoError(grp.Continue(), t, "Continue()")
  2651  		p.ClearBreakpoint(bp.Addr)
  2652  
  2653  		// Next should be interrupted by a breakpoint on the same goroutine.
  2654  		setFileBreakpoint(p, t, fixture.Source, 14)
  2655  		assertNoError(grp.Next(), t, "Next()")
  2656  		assertLineNumber(p, t, 14, "wrong line number")
  2657  		if p.Breakpoints().HasSteppingBreakpoints() {
  2658  			t.Fatal("has internal breakpoints after hitting breakpoint on same goroutine")
  2659  		}
  2660  	})
  2661  }
  2662  
  2663  func TestNextBreakpointKeepsSteppingBreakpoints(t *testing.T) {
  2664  	protest.AllowRecording(t)
  2665  	withTestProcess("testnextprog", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  2666  		grp.KeepSteppingBreakpoints = proc.TracepointKeepsSteppingBreakpoints
  2667  		bp := setFileBreakpoint(p, t, fixture.Source, 34)
  2668  		assertNoError(grp.Continue(), t, "Continue()")
  2669  		p.ClearBreakpoint(bp.Addr)
  2670  
  2671  		// Next should be interrupted by a tracepoint on the same goroutine.
  2672  		bp = setFileBreakpoint(p, t, fixture.Source, 14)
  2673  		bp.Logical.Tracepoint = true
  2674  		assertNoError(grp.Next(), t, "Next()")
  2675  		assertLineNumber(p, t, 14, "wrong line number")
  2676  		if !p.Breakpoints().HasSteppingBreakpoints() {
  2677  			t.Fatal("does not have internal breakpoints after hitting tracepoint on same goroutine")
  2678  		}
  2679  
  2680  		// Continue to complete next.
  2681  		assertNoError(grp.Continue(), t, "Continue()")
  2682  		assertLineNumber(p, t, 35, "wrong line number")
  2683  		if p.Breakpoints().HasSteppingBreakpoints() {
  2684  			t.Fatal("has internal breakpoints after completing next")
  2685  		}
  2686  	})
  2687  }
  2688  
  2689  func TestStepOutDefer(t *testing.T) {
  2690  	protest.AllowRecording(t)
  2691  	withTestProcess("testnextdefer", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  2692  		bp := setFileBreakpoint(p, t, fixture.Source, 9)
  2693  		assertNoError(grp.Continue(), t, "Continue()")
  2694  		p.ClearBreakpoint(bp.Addr)
  2695  
  2696  		assertLineNumber(p, t, 9, "wrong line number")
  2697  
  2698  		assertNoError(grp.StepOut(), t, "StepOut()")
  2699  
  2700  		f, l, _ := p.BinInfo().PCToLine(currentPC(p, t))
  2701  		if f == fixture.Source || l == 6 {
  2702  			t.Fatalf("wrong location %s:%d, expected to end somewhere in runtime", f, l)
  2703  		}
  2704  	})
  2705  }
  2706  
  2707  func TestStepOutDeferReturnAndDirectCall(t *testing.T) {
  2708  	// StepOut should not step into a deferred function if it is called
  2709  	// directly, only if it is called through a panic.
  2710  	// Here we test the case where the function is called by a deferreturn
  2711  	testseq2(t, "defercall", "", []seqTest{
  2712  		{contContinue, 11},
  2713  		{contStepout, 28}})
  2714  }
  2715  
  2716  func TestStepOnCallPtrInstr(t *testing.T) {
  2717  	protest.AllowRecording(t)
  2718  	withTestProcess("teststepprog", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  2719  		setFileBreakpoint(p, t, fixture.Source, 10)
  2720  
  2721  		assertNoError(grp.Continue(), t, "Continue()")
  2722  
  2723  		found := false
  2724  
  2725  		for {
  2726  			_, ln := currentLineNumber(p, t)
  2727  			if ln != 10 {
  2728  				break
  2729  			}
  2730  			regs, err := p.CurrentThread().Registers()
  2731  			assertNoError(err, t, "Registers()")
  2732  			pc := regs.PC()
  2733  			text, err := proc.Disassemble(p.Memory(), regs, p.Breakpoints(), p.BinInfo(), pc, pc+uint64(p.BinInfo().Arch.MaxInstructionLength()))
  2734  			assertNoError(err, t, "Disassemble()")
  2735  			if text[0].IsCall() {
  2736  				found = true
  2737  				break
  2738  			}
  2739  			assertNoError(grp.StepInstruction(false), t, "StepInstruction()")
  2740  		}
  2741  
  2742  		if !found {
  2743  			t.Fatal("Could not find CALL instruction")
  2744  		}
  2745  
  2746  		assertNoError(grp.Step(), t, "Step()")
  2747  
  2748  		if goversion.VersionAfterOrEqual(runtime.Version(), 1, 11) && !protest.RegabiSupported() {
  2749  			assertLineNumber(p, t, 6, "Step continued to wrong line,")
  2750  		} else {
  2751  			assertLineNumber(p, t, 5, "Step continued to wrong line,")
  2752  		}
  2753  	})
  2754  }
  2755  
  2756  func TestIssue594(t *testing.T) {
  2757  	skipOn(t, "upstream issue", "darwin", "lldb")
  2758  	// debugserver will receive an EXC_BAD_ACCESS for this, at that point
  2759  	// there is no way to reconvert this exception into a unix signal and send
  2760  	// it to the process.
  2761  	// This is a bug in debugserver/lldb:
  2762  	//  https://bugs.llvm.org//show_bug.cgi?id=22868
  2763  
  2764  	// Exceptions that aren't caused by breakpoints should be propagated
  2765  	// back to the target.
  2766  	// In particular the target should be able to cause a nil pointer
  2767  	// dereference panic and recover from it.
  2768  	protest.AllowRecording(t)
  2769  	withTestProcess("issue594", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  2770  		assertNoError(grp.Continue(), t, "Continue()")
  2771  		var f string
  2772  		var ln int
  2773  		if testBackend == "rr" {
  2774  			frame, err := findFirstNonRuntimeFrame(p)
  2775  			assertNoError(err, t, "findFirstNonRuntimeFrame")
  2776  			f, ln = frame.Current.File, frame.Current.Line
  2777  		} else {
  2778  			f, ln = currentLineNumber(p, t)
  2779  		}
  2780  		if ln != 21 {
  2781  			t.Fatalf("Program stopped at %s:%d, expected :21", f, ln)
  2782  		}
  2783  	})
  2784  }
  2785  
  2786  func TestStepOutPanicAndDirectCall(t *testing.T) {
  2787  	// StepOut should not step into a deferred function if it is called
  2788  	// directly, only if it is called through a panic.
  2789  	// Here we test the case where the function is called by a panic
  2790  	testseq2(t, "defercall", "", []seqTest{
  2791  		{contContinue, 17},
  2792  		{contStepout, 6}})
  2793  }
  2794  
  2795  func TestWorkDir(t *testing.T) {
  2796  	wd := os.TempDir()
  2797  	// For Darwin `os.TempDir()` returns `/tmp` which is symlink to `/private/tmp`.
  2798  	if runtime.GOOS == "darwin" {
  2799  		wd = "/private/tmp"
  2800  	}
  2801  	protest.AllowRecording(t)
  2802  	withTestProcessArgs("workdir", t, wd, []string{}, 0, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  2803  		setFileBreakpoint(p, t, fixture.Source, 14)
  2804  		grp.Continue()
  2805  		v := evalVariable(p, t, "pwd")
  2806  		str := constant.StringVal(v.Value)
  2807  		if wd != str {
  2808  			t.Fatalf("Expected %s got %s\n", wd, str)
  2809  		}
  2810  	})
  2811  }
  2812  
  2813  func TestNegativeIntEvaluation(t *testing.T) {
  2814  	testcases := []struct {
  2815  		name  string
  2816  		typ   string
  2817  		value interface{}
  2818  	}{
  2819  		{"ni8", "int8", int64(-5)},
  2820  		{"ni16", "int16", int64(-5)},
  2821  		{"ni32", "int32", int64(-5)},
  2822  	}
  2823  	protest.AllowRecording(t)
  2824  	withTestProcess("testvariables2", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  2825  		assertNoError(grp.Continue(), t, "Continue()")
  2826  		for _, tc := range testcases {
  2827  			v := evalVariable(p, t, tc.name)
  2828  			if typ := v.RealType.String(); typ != tc.typ {
  2829  				t.Fatalf("Wrong type for variable %q: %q (expected: %q)", tc.name, typ, tc.typ)
  2830  			}
  2831  			if val, _ := constant.Int64Val(v.Value); val != tc.value {
  2832  				t.Fatalf("Wrong value for variable %q: %v (expected: %v)", tc.name, val, tc.value)
  2833  			}
  2834  		}
  2835  	})
  2836  }
  2837  
  2838  func TestIssue683(t *testing.T) {
  2839  	// Step panics when source file can not be found
  2840  	protest.AllowRecording(t)
  2841  	withTestProcess("issue683", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  2842  		setFunctionBreakpoint(p, t, "main.main")
  2843  		assertNoError(grp.Continue(), t, "First Continue()")
  2844  		for i := 0; i < 20; i++ {
  2845  			// eventually an error about the source file not being found will be
  2846  			// returned, the important thing is that we shouldn't panic
  2847  			err := grp.Step()
  2848  			if err != nil {
  2849  				break
  2850  			}
  2851  		}
  2852  	})
  2853  }
  2854  
  2855  func TestIssue664(t *testing.T) {
  2856  	protest.AllowRecording(t)
  2857  	withTestProcess("issue664", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  2858  		setFileBreakpoint(p, t, fixture.Source, 4)
  2859  		assertNoError(grp.Continue(), t, "Continue()")
  2860  		assertNoError(grp.Next(), t, "Next()")
  2861  		assertLineNumber(p, t, 5, "Did not continue to correct location,")
  2862  	})
  2863  }
  2864  
  2865  // Benchmarks (*Process).Continue + (*Scope).FunctionArguments
  2866  func BenchmarkTrace(b *testing.B) {
  2867  	withTestProcess("traceperf", b, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  2868  		setFunctionBreakpoint(p, b, "main.PerfCheck")
  2869  		b.ResetTimer()
  2870  		for i := 0; i < b.N; i++ {
  2871  			assertNoError(grp.Continue(), b, "Continue()")
  2872  			s, err := proc.GoroutineScope(p, p.CurrentThread())
  2873  			assertNoError(err, b, "Scope()")
  2874  			_, err = s.FunctionArguments(proc.LoadConfig{false, 0, 64, 0, 3, 0})
  2875  			assertNoError(err, b, "FunctionArguments()")
  2876  		}
  2877  		b.StopTimer()
  2878  	})
  2879  }
  2880  
  2881  func TestNextInDeferReturn(t *testing.T) {
  2882  	// runtime.deferreturn updates the G struct in a way that for one
  2883  	// instruction leaves the curg._defer field non-nil but with curg._defer.fn
  2884  	// field being nil.
  2885  	// We need to deal with this without panicking.
  2886  	protest.AllowRecording(t)
  2887  	withTestProcess("defercall", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  2888  		setFunctionBreakpoint(p, t, "runtime.deferreturn")
  2889  		assertNoError(grp.Continue(), t, "First Continue()")
  2890  
  2891  		// Set a breakpoint on the deferred function so that the following loop
  2892  		// can not step out of the runtime.deferreturn and all the way to the
  2893  		// point where the target program panics.
  2894  		setFunctionBreakpoint(p, t, "main.sampleFunction")
  2895  		for i := 0; i < 20; i++ {
  2896  			loc, err := p.CurrentThread().Location()
  2897  			assertNoError(err, t, "CurrentThread().Location()")
  2898  			t.Logf("at %#x %s:%d", loc.PC, loc.File, loc.Line)
  2899  			if loc.Fn != nil && loc.Fn.Name == "main.sampleFunction" {
  2900  				break
  2901  			}
  2902  			assertNoError(grp.Next(), t, fmt.Sprintf("Next() %d", i))
  2903  		}
  2904  	})
  2905  }
  2906  
  2907  func TestAttachDetach(t *testing.T) {
  2908  	if testBackend == "lldb" && runtime.GOOS == "linux" {
  2909  		bs, _ := os.ReadFile("/proc/sys/kernel/yama/ptrace_scope")
  2910  		if bs == nil || strings.TrimSpace(string(bs)) != "0" {
  2911  			t.Logf("can not run TestAttachDetach: %v\n", bs)
  2912  			return
  2913  		}
  2914  	}
  2915  	if testBackend == "rr" {
  2916  		return
  2917  	}
  2918  	var buildFlags protest.BuildFlags
  2919  	if buildMode == "pie" {
  2920  		buildFlags |= protest.BuildModePIE
  2921  	}
  2922  	fixture := protest.BuildFixture("testnextnethttp", buildFlags)
  2923  	cmd := exec.Command(fixture.Path)
  2924  	cmd.Stdout = os.Stdout
  2925  	cmd.Stderr = os.Stderr
  2926  	assertNoError(cmd.Start(), t, "starting fixture")
  2927  
  2928  	// wait for testnextnethttp to start listening
  2929  	t0 := time.Now()
  2930  	for {
  2931  		conn, err := net.Dial("tcp", "127.0.0.1:9191")
  2932  		if err == nil {
  2933  			conn.Close()
  2934  			break
  2935  		}
  2936  		time.Sleep(50 * time.Millisecond)
  2937  		if time.Since(t0) > 10*time.Second {
  2938  			t.Fatal("fixture did not start")
  2939  		}
  2940  	}
  2941  
  2942  	var p *proc.TargetGroup
  2943  	var err error
  2944  
  2945  	switch testBackend {
  2946  	case "native":
  2947  		p, err = native.Attach(cmd.Process.Pid, nil, []string{})
  2948  	case "lldb":
  2949  		path := ""
  2950  		if runtime.GOOS == "darwin" {
  2951  			path = fixture.Path
  2952  		}
  2953  		p, err = gdbserial.LLDBAttach(cmd.Process.Pid, path, nil, []string{})
  2954  	default:
  2955  		err = fmt.Errorf("unknown backend %q", testBackend)
  2956  	}
  2957  
  2958  	assertNoError(err, t, "Attach")
  2959  	go func() {
  2960  		time.Sleep(1 * time.Second)
  2961  		resp, err := http.Get("http://127.0.0.1:9191")
  2962  		if err == nil {
  2963  			resp.Body.Close()
  2964  		}
  2965  	}()
  2966  
  2967  	assertNoError(p.Continue(), t, "Continue")
  2968  	assertLineNumber(p.Selected, t, 11, "Did not continue to correct location,")
  2969  
  2970  	assertNoError(p.Detach(false), t, "Detach")
  2971  
  2972  	if runtime.GOOS != "darwin" {
  2973  		// Debugserver sometimes will leave a zombie process after detaching, this
  2974  		// seems to be a bug with debugserver.
  2975  		resp, err := http.Get("http://127.0.0.1:9191/nobp")
  2976  		assertNoError(err, t, "Page request after detach")
  2977  		bs, err := io.ReadAll(resp.Body)
  2978  		assertNoError(err, t, "Reading /nobp page")
  2979  		defer resp.Body.Close()
  2980  		if out := string(bs); !strings.Contains(out, "hello, world!") {
  2981  			t.Fatalf("/nobp page does not contain \"hello, world!\": %q", out)
  2982  		}
  2983  	}
  2984  
  2985  	cmd.Process.Kill()
  2986  }
  2987  
  2988  func TestVarSum(t *testing.T) {
  2989  	protest.AllowRecording(t)
  2990  	withTestProcess("testvariables2", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  2991  		assertNoError(grp.Continue(), t, "Continue()")
  2992  		sumvar := evalVariable(p, t, "s1[0] + s1[1]")
  2993  		sumvarstr := constant.StringVal(sumvar.Value)
  2994  		if sumvarstr != "onetwo" {
  2995  			t.Fatalf("s1[0] + s1[1] == %q (expected \"onetwo\")", sumvarstr)
  2996  		}
  2997  		if sumvar.Len != int64(len(sumvarstr)) {
  2998  			t.Fatalf("sumvar.Len == %d (expected %d)", sumvar.Len, len(sumvarstr))
  2999  		}
  3000  	})
  3001  }
  3002  
  3003  func TestPackageWithPathVar(t *testing.T) {
  3004  	protest.AllowRecording(t)
  3005  	withTestProcess("pkgrenames", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  3006  		assertNoError(grp.Continue(), t, "Continue()")
  3007  		evalVariable(p, t, "pkg.SomeVar")
  3008  		evalVariable(p, t, "pkg.SomeVar.X")
  3009  	})
  3010  }
  3011  
  3012  func TestEnvironment(t *testing.T) {
  3013  	protest.AllowRecording(t)
  3014  	t.Setenv("SOMEVAR", "bah")
  3015  	withTestProcess("testenv", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  3016  		assertNoError(grp.Continue(), t, "Continue()")
  3017  		v := evalVariable(p, t, "x")
  3018  		vv := constant.StringVal(v.Value)
  3019  		t.Logf("v = %q", vv)
  3020  		if vv != "bah" {
  3021  			t.Fatalf("value of v is %q (expected \"bah\")", vv)
  3022  		}
  3023  	})
  3024  }
  3025  
  3026  func getFrameOff(p *proc.Target, t *testing.T) int64 {
  3027  	frameoffvar := evalVariable(p, t, "runtime.frameoff")
  3028  	frameoff, _ := constant.Int64Val(frameoffvar.Value)
  3029  	return frameoff
  3030  }
  3031  
  3032  func TestRecursiveNext(t *testing.T) {
  3033  	protest.AllowRecording(t)
  3034  	testcases := []nextTest{
  3035  		{6, 7},
  3036  		{7, 10},
  3037  		{10, 11},
  3038  		{11, 17},
  3039  	}
  3040  	testseq("increment", contNext, testcases, "main.Increment", t)
  3041  
  3042  	withTestProcess("increment", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  3043  		bp := setFunctionBreakpoint(p, t, "main.Increment")
  3044  		assertNoError(grp.Continue(), t, "Continue")
  3045  		err := p.ClearBreakpoint(bp.Addr)
  3046  		assertNoError(err, t, "ClearBreakpoint")
  3047  		assertNoError(grp.Next(), t, "Next 1")
  3048  		assertNoError(grp.Next(), t, "Next 2")
  3049  		assertNoError(grp.Next(), t, "Next 3")
  3050  		frameoff0 := getFrameOff(p, t)
  3051  		assertNoError(grp.Step(), t, "Step")
  3052  		frameoff1 := getFrameOff(p, t)
  3053  		if frameoff0 == frameoff1 {
  3054  			t.Fatalf("did not step into function?")
  3055  		}
  3056  		assertLineNumber(p, t, 6, "program did not continue to expected location,")
  3057  		assertNoError(grp.Next(), t, "Next 4")
  3058  		assertLineNumber(p, t, 7, "program did not continue to expected location,")
  3059  		assertNoError(grp.StepOut(), t, "StepOut")
  3060  		assertLineNumber(p, t, 11, "program did not continue to expected location,")
  3061  		frameoff2 := getFrameOff(p, t)
  3062  		if frameoff0 != frameoff2 {
  3063  			t.Fatalf("frame offset mismatch %x != %x", frameoff0, frameoff2)
  3064  		}
  3065  	})
  3066  }
  3067  
  3068  // TestIssue877 ensures that the environment variables starting with DYLD_ and LD_
  3069  // are passed when executing the binary on OSX via debugserver
  3070  func TestIssue877(t *testing.T) {
  3071  	if runtime.GOOS != "darwin" && testBackend == "lldb" {
  3072  		return
  3073  	}
  3074  	const envval = "/usr/local/lib"
  3075  	t.Setenv("DYLD_LIBRARY_PATH", envval)
  3076  	withTestProcess("issue877", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  3077  		assertNoError(grp.Continue(), t, "Continue()")
  3078  		v := evalVariable(p, t, "dyldenv")
  3079  		vv := constant.StringVal(v.Value)
  3080  		t.Logf("v = %q", vv)
  3081  		if vv != envval {
  3082  			t.Fatalf("value of v is %q (expected %q)", vv, envval)
  3083  		}
  3084  	})
  3085  }
  3086  
  3087  func TestIssue893(t *testing.T) {
  3088  	// Test what happens when next is called immediately after launching the
  3089  	// executable, acceptable behaviors are: (a) no error, (b) no source at PC
  3090  	// error, (c) program runs to completion
  3091  	protest.AllowRecording(t)
  3092  	withTestProcess("increment", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  3093  		err := grp.Next()
  3094  		if err == nil {
  3095  			return
  3096  		}
  3097  		if _, ok := err.(*frame.ErrNoFDEForPC); ok {
  3098  			return
  3099  		}
  3100  		if _, ok := err.(*proc.ErrNoSourceForPC); ok {
  3101  			return
  3102  		}
  3103  		if _, ok := err.(proc.ErrProcessExited); ok {
  3104  			return
  3105  		}
  3106  		assertNoError(err, t, "Next")
  3107  	})
  3108  }
  3109  
  3110  func TestStepInstructionNoGoroutine(t *testing.T) {
  3111  	protest.AllowRecording(t)
  3112  	withTestProcess("increment", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  3113  		// Call StepInstruction immediately after launching the program, it should
  3114  		// work even though no goroutine is selected.
  3115  		assertNoError(grp.StepInstruction(false), t, "StepInstruction")
  3116  	})
  3117  }
  3118  
  3119  func TestIssue871(t *testing.T) {
  3120  	protest.AllowRecording(t)
  3121  	withTestProcess("issue871", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  3122  		assertNoError(grp.Continue(), t, "Continue")
  3123  
  3124  		var scope *proc.EvalScope
  3125  		var err error
  3126  		if testBackend == "rr" {
  3127  			var frame proc.Stackframe
  3128  			frame, err = findFirstNonRuntimeFrame(p)
  3129  			if err == nil {
  3130  				scope = proc.FrameToScope(p, p.Memory(), nil, 0, frame)
  3131  			}
  3132  		} else {
  3133  			scope, err = proc.GoroutineScope(p, p.CurrentThread())
  3134  		}
  3135  		assertNoError(err, t, "scope")
  3136  
  3137  		locals, err := scope.LocalVariables(normalLoadConfig)
  3138  		assertNoError(err, t, "LocalVariables")
  3139  
  3140  		foundA, foundB := false, false
  3141  
  3142  		for _, v := range locals {
  3143  			t.Logf("local %v", v)
  3144  			switch v.Name {
  3145  			case "a":
  3146  				foundA = true
  3147  				if v.Flags&proc.VariableEscaped == 0 {
  3148  					t.Errorf("variable a not flagged as escaped")
  3149  				}
  3150  			case "b":
  3151  				foundB = true
  3152  			}
  3153  		}
  3154  
  3155  		if !foundA {
  3156  			t.Errorf("variable a not found")
  3157  		}
  3158  
  3159  		if !foundB {
  3160  			t.Errorf("variable b not found")
  3161  		}
  3162  	})
  3163  }
  3164  
  3165  func TestShadowedFlag(t *testing.T) {
  3166  	if ver, _ := goversion.Parse(runtime.Version()); ver.Major >= 0 && !ver.AfterOrEqual(goversion.GoVersion{Major: 1, Minor: 9, Rev: -1}) {
  3167  		return
  3168  	}
  3169  	withTestProcess("testshadow", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  3170  		assertNoError(grp.Continue(), t, "Continue")
  3171  		scope, err := proc.GoroutineScope(p, p.CurrentThread())
  3172  		assertNoError(err, t, "GoroutineScope")
  3173  		locals, err := scope.LocalVariables(normalLoadConfig)
  3174  		assertNoError(err, t, "LocalVariables")
  3175  		foundShadowed := false
  3176  		foundNonShadowed := false
  3177  		for _, v := range locals {
  3178  			if v.Flags&proc.VariableShadowed != 0 {
  3179  				if v.Name != "a" {
  3180  					t.Errorf("wrong shadowed variable %s", v.Name)
  3181  				}
  3182  				foundShadowed = true
  3183  				if n, _ := constant.Int64Val(v.Value); n != 0 {
  3184  					t.Errorf("wrong value for shadowed variable a: %d", n)
  3185  				}
  3186  			} else {
  3187  				if v.Name != "a" {
  3188  					t.Errorf("wrong non-shadowed variable %s", v.Name)
  3189  				}
  3190  				foundNonShadowed = true
  3191  				if n, _ := constant.Int64Val(v.Value); n != 1 {
  3192  					t.Errorf("wrong value for non-shadowed variable a: %d", n)
  3193  				}
  3194  			}
  3195  		}
  3196  		if !foundShadowed {
  3197  			t.Error("could not find any shadowed variable")
  3198  		}
  3199  		if !foundNonShadowed {
  3200  			t.Error("could not find any non-shadowed variable")
  3201  		}
  3202  	})
  3203  }
  3204  
  3205  func TestDebugStripped(t *testing.T) {
  3206  	// Currently only implemented for Linux ELF and macOS Mach-O executables.
  3207  	// TODO(derekparker): Add support for PE.
  3208  	skipOn(t, "not working on windows", "windows")
  3209  	skipOn(t, "not working on freebsd", "freebsd")
  3210  	skipOn(t, "not working on linux/386", "linux", "386")
  3211  	skipOn(t, "not working on linux/ppc64le when -gcflags=-N -l is passed", "linux", "ppc64le")
  3212  	ver, _ := goversion.Parse(runtime.Version())
  3213  	if ver.IsDevel() {
  3214  		t.Skip("not supported")
  3215  	}
  3216  	withTestProcessArgs("testnextprog", t, "", []string{}, protest.LinkStrip, func(p *proc.Target, grp *proc.TargetGroup, f protest.Fixture) {
  3217  		setFunctionBreakpoint(p, t, "main.main")
  3218  		assertNoError(grp.Continue(), t, "Continue")
  3219  		assertCurrentLocationFunction(p, t, "main.main")
  3220  		assertLineNumber(p, t, 37, "first continue")
  3221  		assertNoError(grp.Next(), t, "Next")
  3222  		assertLineNumber(p, t, 38, "after next")
  3223  
  3224  		// Assert that commands like "args", "locals", etc... will
  3225  		// return an error instead of panic.
  3226  		s, err := proc.ThreadScope(p, p.CurrentThread())
  3227  		assertNoError(err, t, "ThreadScope")
  3228  		_, err = s.Locals(0)
  3229  		if err == nil {
  3230  			t.Error("expected an error to be returned from scope.Locals in stripped binary")
  3231  		}
  3232  	})
  3233  }
  3234  
  3235  func TestDebugStripped2(t *testing.T) {
  3236  	// TODO(derekparker): Add support for PE.
  3237  	skipOn(t, "not working on windows", "windows")
  3238  	skipOn(t, "not working on freebsd", "freebsd")
  3239  	skipOn(t, "not working on linux/386", "linux", "386")
  3240  	skipOn(t, "not working on linux/ppc64le when -gcflags=-N -l is passed", "linux", "ppc64le")
  3241  	ver, _ := goversion.Parse(runtime.Version())
  3242  	if ver.IsDevel() {
  3243  		t.Skip("not supported")
  3244  	}
  3245  	if ver.Major > 0 && ver.AfterOrEqual(goversion.GoVersion{Major: 1, Minor: 22, Rev: -1}) {
  3246  		skipOn(t, "not working on linux/arm64 with Go 1.22", "linux", "arm64")
  3247  	}
  3248  	withTestProcessArgs("inlinestripped", t, "", []string{}, protest.EnableInlining|protest.LinkStrip|protest.LinkDisableDWARF, func(p *proc.Target, grp *proc.TargetGroup, f protest.Fixture) {
  3249  		setFunctionBreakpointAll(p, t, "fmt.Println")
  3250  
  3251  		for i, line := range []int{12, 13, 14} {
  3252  			assertNoError(grp.Continue(), t, "Continue")
  3253  			assertCurrentLocationFunction(p, t, "main.main")
  3254  			assertLineNumber(p, t, line, fmt.Sprintf("continue %d", i))
  3255  		}
  3256  	})
  3257  }
  3258  
  3259  func TestIssue844(t *testing.T) {
  3260  	// Conditional breakpoints should not prevent next from working if their
  3261  	// condition isn't met.
  3262  	withTestProcess("nextcond", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  3263  		setFileBreakpoint(p, t, fixture.Source, 9)
  3264  		condbp := setFileBreakpoint(p, t, fixture.Source, 10)
  3265  		condbp.UserBreaklet().Cond = &ast.BinaryExpr{
  3266  			Op: token.EQL,
  3267  			X:  &ast.Ident{Name: "n"},
  3268  			Y:  &ast.BasicLit{Kind: token.INT, Value: "11"},
  3269  		}
  3270  		assertNoError(grp.Continue(), t, "Continue")
  3271  		assertNoError(grp.Next(), t, "Next")
  3272  		assertLineNumber(p, t, 10, "continued to wrong location,")
  3273  	})
  3274  }
  3275  
  3276  func logStacktrace(t *testing.T, p *proc.Target, frames []proc.Stackframe) {
  3277  	w := tabwriter.NewWriter(os.Stderr, 0, 0, 3, ' ', 0)
  3278  	fmt.Fprintf(w, "\n%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t\n", "Call PC", "Frame Offset", "Frame Pointer Offset", "PC", "Return", "Function", "Location", "Top Defer", "Defers")
  3279  	for j := range frames {
  3280  		name := "?"
  3281  		if frames[j].Current.Fn != nil {
  3282  			name = frames[j].Current.Fn.Name
  3283  		}
  3284  		if frames[j].Call.Fn != nil && frames[j].Current.Fn != frames[j].Call.Fn {
  3285  			name = fmt.Sprintf("%s inlined in %s", frames[j].Call.Fn.Name, frames[j].Current.Fn.Name)
  3286  		}
  3287  
  3288  		topmostdefer := ""
  3289  		if frames[j].TopmostDefer != nil {
  3290  			_, _, fn := frames[j].TopmostDefer.DeferredFunc(p)
  3291  			fnname := ""
  3292  			if fn != nil {
  3293  				fnname = fn.Name
  3294  			}
  3295  			topmostdefer = fmt.Sprintf("%#x %s", frames[j].TopmostDefer.DwrapPC, fnname)
  3296  		}
  3297  
  3298  		defers := ""
  3299  		for deferIdx, _defer := range frames[j].Defers {
  3300  			_, _, fn := _defer.DeferredFunc(p)
  3301  			fnname := ""
  3302  			if fn != nil {
  3303  				fnname = fn.Name
  3304  			}
  3305  			defers += fmt.Sprintf("%d %#x %s |", deferIdx, _defer.DwrapPC, fnname)
  3306  		}
  3307  
  3308  		frame := frames[j]
  3309  		fmt.Fprintf(w, "%#x\t%#x\t%#x\t%#x\t%#x\t%s\t%s:%d\t%s\t%s\t\n",
  3310  			frame.Call.PC, frame.FrameOffset(), frame.FramePointerOffset(), frame.Current.PC, frame.Ret,
  3311  			name, filepath.Base(frame.Call.File), frame.Call.Line, topmostdefer, defers)
  3312  
  3313  	}
  3314  	w.Flush()
  3315  }
  3316  
  3317  // stacktraceCheck checks that all the functions listed in tc appear in
  3318  // frames in the same order.
  3319  // Checks that all the functions in tc starting with "C." or with "!" are in
  3320  // a systemstack frame.
  3321  // Returns a slice m where m[i] is the index in frames of the function tc[i]
  3322  // or nil if any check fails.
  3323  func stacktraceCheck(t *testing.T, tc []string, frames []proc.Stackframe) []int {
  3324  	m := make([]int, len(tc))
  3325  	i, j := 0, 0
  3326  	for i < len(tc) {
  3327  		tcname := tc[i]
  3328  		tcsystem := strings.HasPrefix(tcname, "C.")
  3329  		if tcname[0] == '!' {
  3330  			tcsystem = true
  3331  			tcname = tcname[1:]
  3332  		}
  3333  		for j < len(frames) {
  3334  			name := "?"
  3335  			if frames[j].Current.Fn != nil {
  3336  				name = frames[j].Current.Fn.Name
  3337  			}
  3338  			if name == tcname {
  3339  				m[i] = j
  3340  				if tcsystem != frames[j].SystemStack {
  3341  					t.Logf("system stack check failed for frame %d (expected %v got %v)", j, tcsystem, frames[j].SystemStack)
  3342  					t.Logf("expected: %v\n", tc)
  3343  					return nil
  3344  				}
  3345  				break
  3346  			}
  3347  
  3348  			j++
  3349  		}
  3350  		if j >= len(frames) {
  3351  			t.Logf("couldn't find frame %d %s", i, tc)
  3352  			t.Logf("expected: %v\n", tc)
  3353  			return nil
  3354  		}
  3355  
  3356  		i++
  3357  	}
  3358  	return m
  3359  }
  3360  
  3361  func frameInFile(frame proc.Stackframe, file string) bool {
  3362  	for _, loc := range []proc.Location{frame.Current, frame.Call} {
  3363  		if !strings.HasSuffix(loc.File, file) && !strings.HasSuffix(loc.File, "/"+file) && !strings.HasSuffix(loc.File, "\\"+file) {
  3364  			return false
  3365  		}
  3366  		if loc.Line <= 0 {
  3367  			return false
  3368  		}
  3369  	}
  3370  	return true
  3371  }
  3372  
  3373  func TestCgoStacktrace(t *testing.T) {
  3374  	if runtime.GOOS == "windows" {
  3375  		ver, _ := goversion.Parse(runtime.Version())
  3376  		if ver.Major > 0 && !ver.AfterOrEqual(goversion.GoVersion{Major: 1, Minor: 9, Rev: -1}) {
  3377  			t.Skip("disabled on windows with go before version 1.9")
  3378  		}
  3379  	}
  3380  	if runtime.GOOS == "darwin" {
  3381  		ver, _ := goversion.Parse(runtime.Version())
  3382  		if ver.Major > 0 && !ver.AfterOrEqual(goversion.GoVersion{Major: 1, Minor: 8, Rev: -1}) {
  3383  			t.Skip("disabled on macOS with go before version 1.8")
  3384  		}
  3385  	}
  3386  	skipOn(t, "broken - cgo stacktraces", "386")
  3387  	skipOn(t, "broken - cgo stacktraces", "windows", "arm64")
  3388  	skipOn(t, "broken - cgo stacktraces", "linux", "ppc64le")
  3389  	if !goversion.VersionAfterOrEqual(runtime.Version(), 1, 21) {
  3390  		skipOn(t, "broken - cgo stacktraces", "windows", "arm64")
  3391  	}
  3392  	protest.MustHaveCgo(t)
  3393  
  3394  	// Tests that:
  3395  	// a) we correctly identify the goroutine while we are executing cgo code
  3396  	// b) that we can stitch together the system stack (where cgo code
  3397  	// executes) and the normal goroutine stack
  3398  
  3399  	// Each test case describes how the stack trace should appear after a
  3400  	// continue. The first function on each test case is the topmost function
  3401  	// that should be found on the stack, the actual stack trace can have more
  3402  	// frame than those listed here but all the frames listed must appear in
  3403  	// the specified order.
  3404  	testCases := [][]string{
  3405  		{"main.main"},
  3406  		{"C.helloworld_pt2", "C.helloworld", "main.main"},
  3407  		{"main.helloWorldS", "main.helloWorld", "C.helloworld_pt2", "C.helloworld", "main.main"},
  3408  		{"C.helloworld_pt4", "C.helloworld_pt3", "main.helloWorldS", "main.helloWorld", "C.helloworld_pt2", "C.helloworld", "main.main"},
  3409  		{"main.helloWorld2", "C.helloworld_pt4", "C.helloworld_pt3", "main.helloWorldS", "main.helloWorld", "C.helloworld_pt2", "C.helloworld", "main.main"}}
  3410  
  3411  	var gid int64
  3412  
  3413  	frameOffs := map[string]int64{}
  3414  	framePointerOffs := map[string]int64{}
  3415  
  3416  	withTestProcess("cgostacktest/", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  3417  		for itidx, tc := range testCases {
  3418  			t.Logf("iteration step %d", itidx)
  3419  
  3420  			assertNoError(grp.Continue(), t, fmt.Sprintf("Continue at iteration step %d", itidx))
  3421  
  3422  			g, err := proc.GetG(p.CurrentThread())
  3423  			assertNoError(err, t, fmt.Sprintf("GetG at iteration step %d", itidx))
  3424  
  3425  			if itidx == 0 {
  3426  				gid = g.ID
  3427  			} else {
  3428  				if gid != g.ID {
  3429  					t.Fatalf("wrong goroutine id at iteration step %d (expected %d got %d)", itidx, gid, g.ID)
  3430  				}
  3431  			}
  3432  
  3433  			frames, err := proc.GoroutineStacktrace(p, g, 100, 0)
  3434  			assertNoError(err, t, fmt.Sprintf("Stacktrace at iteration step %d", itidx))
  3435  
  3436  			logStacktrace(t, p, frames)
  3437  
  3438  			m := stacktraceCheck(t, tc, frames)
  3439  			mismatch := m == nil
  3440  
  3441  			for i, j := range m {
  3442  				if strings.HasPrefix(tc[i], "C.hellow") {
  3443  					if !frameInFile(frames[j], "hello.c") {
  3444  						t.Logf("position in %q is %s:%d (call %s:%d)", tc[i], frames[j].Current.File, frames[j].Current.Line, frames[j].Call.File, frames[j].Call.Line)
  3445  						mismatch = true
  3446  						break
  3447  					}
  3448  				}
  3449  				if frameOff, ok := frameOffs[tc[i]]; ok {
  3450  					if frameOff != frames[j].FrameOffset() {
  3451  						t.Logf("frame %s offset mismatch", tc[i])
  3452  					}
  3453  					if framePointerOffs[tc[i]] != frames[j].FramePointerOffset() {
  3454  						t.Logf("frame %s pointer offset mismatch, expected: %#v actual: %#v", tc[i], framePointerOffs[tc[i]], frames[j].FramePointerOffset())
  3455  					}
  3456  				} else {
  3457  					frameOffs[tc[i]] = frames[j].FrameOffset()
  3458  					framePointerOffs[tc[i]] = frames[j].FramePointerOffset()
  3459  				}
  3460  			}
  3461  
  3462  			// also check that ThreadStacktrace produces the same list of frames
  3463  			threadFrames, err := proc.ThreadStacktrace(p, p.CurrentThread(), 100)
  3464  			assertNoError(err, t, fmt.Sprintf("ThreadStacktrace at iteration step %d", itidx))
  3465  
  3466  			if len(threadFrames) != len(frames) {
  3467  				mismatch = true
  3468  			} else {
  3469  				for j := range frames {
  3470  					if frames[j].Current.File != threadFrames[j].Current.File || frames[j].Current.Line != threadFrames[j].Current.Line {
  3471  						t.Logf("stack mismatch between goroutine stacktrace and thread stacktrace")
  3472  						t.Logf("thread stacktrace:")
  3473  						logStacktrace(t, p, threadFrames)
  3474  						mismatch = true
  3475  						break
  3476  					}
  3477  				}
  3478  			}
  3479  			if mismatch {
  3480  				t.Fatal("see previous loglines")
  3481  			}
  3482  		}
  3483  	})
  3484  }
  3485  
  3486  func TestCgoSources(t *testing.T) {
  3487  	if runtime.GOOS == "windows" {
  3488  		ver, _ := goversion.Parse(runtime.Version())
  3489  		if ver.Major > 0 && !ver.AfterOrEqual(goversion.GoVersion{Major: 1, Minor: 9, Rev: -1}) {
  3490  			t.Skip("disabled on windows with go before version 1.9")
  3491  		}
  3492  	}
  3493  
  3494  	if runtime.GOARCH == "386" {
  3495  		t.Skip("cgo stacktraces not supported on i386 for now")
  3496  	}
  3497  
  3498  	protest.MustHaveCgo(t)
  3499  
  3500  	withTestProcess("cgostacktest/", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  3501  		sources := p.BinInfo().Sources
  3502  		for _, needle := range []string{"main.go", "hello.c"} {
  3503  			found := false
  3504  			for _, k := range sources {
  3505  				if strings.HasSuffix(k, needle) || strings.HasSuffix(k, "/"+needle) || strings.HasSuffix(k, "\\"+needle) {
  3506  					found = true
  3507  					break
  3508  				}
  3509  			}
  3510  			if !found {
  3511  				t.Errorf("File %s not found", needle)
  3512  			}
  3513  		}
  3514  	})
  3515  }
  3516  
  3517  func TestSystemstackStacktrace(t *testing.T) {
  3518  	skipOn(t, "broken", "ppc64le")
  3519  	// check that we can follow a stack switch initiated by runtime.systemstack()
  3520  	withTestProcess("panic", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  3521  		setFunctionBreakpoint(p, t, "runtime.startpanic_m")
  3522  		assertNoError(grp.Continue(), t, "first continue")
  3523  		assertNoError(grp.Continue(), t, "second continue")
  3524  		g, err := proc.GetG(p.CurrentThread())
  3525  		assertNoError(err, t, "GetG")
  3526  		frames, err := proc.GoroutineStacktrace(p, g, 100, 0)
  3527  		assertNoError(err, t, "stacktrace")
  3528  		logStacktrace(t, p, frames)
  3529  		m := stacktraceCheck(t, []string{"!runtime.startpanic_m", "runtime.gopanic", "main.main"}, frames)
  3530  		if m == nil {
  3531  			t.Fatal("see previous loglines")
  3532  		}
  3533  	})
  3534  }
  3535  
  3536  func TestSystemstackOnRuntimeNewstack(t *testing.T) {
  3537  	skipOn(t, "broken", "ppc64le")
  3538  	// The bug being tested here manifests as follows:
  3539  	// - set a breakpoint somewhere or interrupt the program with Ctrl-C
  3540  	// - try to look at stacktraces of other goroutines
  3541  	// If one of the other goroutines is resizing its own stack the stack
  3542  	// command won't work for it.
  3543  	withTestProcess("binarytrees", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  3544  		setFunctionBreakpoint(p, t, "main.main")
  3545  		assertNoError(grp.Continue(), t, "first continue")
  3546  
  3547  		g, err := proc.GetG(p.CurrentThread())
  3548  		assertNoError(err, t, "GetG")
  3549  		mainGoroutineID := g.ID
  3550  
  3551  		setFunctionBreakpointAll(p, t, "runtime.newstack")
  3552  		for {
  3553  			assertNoError(grp.Continue(), t, "second continue")
  3554  			g, err = proc.GetG(p.CurrentThread())
  3555  			assertNoError(err, t, "GetG")
  3556  			if g.ID == mainGoroutineID {
  3557  				break
  3558  			}
  3559  		}
  3560  		frames, err := proc.GoroutineStacktrace(p, g, 100, 0)
  3561  		assertNoError(err, t, "stacktrace")
  3562  		logStacktrace(t, p, frames)
  3563  		m := stacktraceCheck(t, []string{"!runtime.newstack", "main.main"}, frames)
  3564  		if m == nil {
  3565  			t.Fatal("see previous loglines")
  3566  		}
  3567  	})
  3568  }
  3569  
  3570  func TestIssue1034(t *testing.T) {
  3571  	skipOn(t, "broken - cgo stacktraces", "386")
  3572  	protest.MustHaveCgo(t)
  3573  
  3574  	// The external linker on macOS produces an abbrev for DW_TAG_subprogram
  3575  	// without the "has children" flag, we should support this.
  3576  	withTestProcess("cgostacktest/", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  3577  		setFunctionBreakpoint(p, t, "main.main")
  3578  		assertNoError(grp.Continue(), t, "Continue()")
  3579  		frames, err := proc.GoroutineStacktrace(p, p.SelectedGoroutine(), 10, 0)
  3580  		assertNoError(err, t, "Stacktrace")
  3581  		scope := proc.FrameToScope(p, p.Memory(), nil, 0, frames[2:]...)
  3582  		args, _ := scope.FunctionArguments(normalLoadConfig)
  3583  		assertNoError(err, t, "FunctionArguments()")
  3584  		if len(args) > 0 {
  3585  			t.Fatalf("wrong number of arguments for frame %v (%d)", frames[2], len(args))
  3586  		}
  3587  	})
  3588  }
  3589  
  3590  func TestIssue1008(t *testing.T) {
  3591  	skipOn(t, "broken - cgo stacktraces", "386")
  3592  	protest.MustHaveCgo(t)
  3593  
  3594  	// The external linker on macOS inserts "end of sequence" extended opcodes
  3595  	// in debug_line. which we should support correctly.
  3596  	withTestProcess("cgostacktest/", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  3597  		setFunctionBreakpoint(p, t, "main.main")
  3598  		assertNoError(grp.Continue(), t, "Continue()")
  3599  		loc, err := p.CurrentThread().Location()
  3600  		assertNoError(err, t, "CurrentThread().Location()")
  3601  		t.Logf("location %v\n", loc)
  3602  		if !strings.HasSuffix(loc.File, "/main.go") {
  3603  			t.Errorf("unexpected location %s:%d\n", loc.File, loc.Line)
  3604  		}
  3605  		if loc.Line > 35 {
  3606  			t.Errorf("unexpected location %s:%d (file only has 34 lines)\n", loc.File, loc.Line)
  3607  		}
  3608  	})
  3609  }
  3610  
  3611  func testDeclLineCount(t *testing.T, p *proc.Target, lineno int, tgtvars []string) {
  3612  	sort.Strings(tgtvars)
  3613  
  3614  	assertLineNumber(p, t, lineno, "Program did not continue to correct next location")
  3615  	scope, err := proc.GoroutineScope(p, p.CurrentThread())
  3616  	assertNoError(err, t, fmt.Sprintf("GoroutineScope (:%d)", lineno))
  3617  	vars, err := scope.Locals(0)
  3618  	assertNoError(err, t, fmt.Sprintf("Locals (:%d)", lineno))
  3619  	if len(vars) != len(tgtvars) {
  3620  		t.Fatalf("wrong number of variables %d (:%d)", len(vars), lineno)
  3621  	}
  3622  	outvars := make([]string, len(vars))
  3623  	for i, v := range vars {
  3624  		outvars[i] = v.Name
  3625  	}
  3626  	sort.Strings(outvars)
  3627  
  3628  	for i := range outvars {
  3629  		if tgtvars[i] != outvars[i] {
  3630  			t.Fatalf("wrong variables, got: %q expected %q\n", outvars, tgtvars)
  3631  		}
  3632  	}
  3633  }
  3634  
  3635  func TestDeclLine(t *testing.T) {
  3636  	ver, _ := goversion.Parse(runtime.Version())
  3637  	if ver.Major > 0 && !ver.AfterOrEqual(goversion.GoVersion{Major: 1, Minor: 10, Rev: -1}) {
  3638  		t.Skip("go 1.9 and prior versions do not emit DW_AT_decl_line")
  3639  	}
  3640  
  3641  	withTestProcess("decllinetest", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  3642  		setFileBreakpoint(p, t, fixture.Source, 8)
  3643  		setFileBreakpoint(p, t, fixture.Source, 9)
  3644  		setFileBreakpoint(p, t, fixture.Source, 10)
  3645  		setFileBreakpoint(p, t, fixture.Source, 11)
  3646  		b := setFunctionBreakpoint(p, t, "main.f1")
  3647  		if b.Line != 14 {
  3648  			// Line 14 is hard-coded below.
  3649  			t.Fatalf("expected \"main.f1\" breakpoint to be set on line 14, but got line: %d", b.Line)
  3650  		}
  3651  
  3652  		assertNoError(grp.Continue(), t, "Continue 1")
  3653  		if goversion.VersionAfterOrEqual(runtime.Version(), 1, 15) {
  3654  			testDeclLineCount(t, p, 8, []string{})
  3655  		} else {
  3656  			testDeclLineCount(t, p, 8, []string{"a"})
  3657  		}
  3658  
  3659  		assertNoError(grp.Continue(), t, "Continue 2")
  3660  		testDeclLineCount(t, p, 9, []string{"a"})
  3661  
  3662  		assertNoError(grp.Continue(), t, "Continue 3")
  3663  		if goversion.VersionAfterOrEqual(runtime.Version(), 1, 15) {
  3664  			testDeclLineCount(t, p, 10, []string{"a"})
  3665  		} else {
  3666  			testDeclLineCount(t, p, 10, []string{"a", "b"})
  3667  		}
  3668  
  3669  		assertNoError(grp.Continue(), t, "Continue 4")
  3670  		testDeclLineCount(t, p, 11, []string{"a", "b"})
  3671  
  3672  		assertNoError(grp.Continue(), t, "Continue 5")
  3673  		// On line 14, we expect the function's arguments to be available, even
  3674  		// though their DW_AT_decl_line declares higher line numbers. The decl_line
  3675  		// is supposed to be ignored for the visibility of arguments.
  3676  		testDeclLineCount(t, p, 14, []string{"a", "b"})
  3677  	})
  3678  }
  3679  
  3680  func TestIssue1137(t *testing.T) {
  3681  	withTestProcess("dotpackagesiface", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  3682  		assertNoError(grp.Continue(), t, "Continue()")
  3683  		v := evalVariable(p, t, "iface")
  3684  		assertNoError(v.Unreadable, t, "iface unreadable")
  3685  		v2 := evalVariable(p, t, "iface2")
  3686  		assertNoError(v2.Unreadable, t, "iface2 unreadable")
  3687  	})
  3688  }
  3689  
  3690  func TestIssue1101(t *testing.T) {
  3691  	// If a breakpoint is hit close to process death on a thread that isn't the
  3692  	// group leader the process could die while we are trying to stop it.
  3693  	//
  3694  	// This can be easily reproduced by having the goroutine that's executing
  3695  	// main.main (which will almost always run on the thread group leader) wait
  3696  	// for a second goroutine before exiting, then setting a breakpoint on the
  3697  	// second goroutine and stepping through it (see TestIssue1101 in
  3698  	// proc_test.go).
  3699  	//
  3700  	// When stepping over the return instruction of main.f the deferred
  3701  	// wg.Done() call will be executed which will cause the main goroutine to
  3702  	// resume and proceed to exit. Both the temporary breakpoint on wg.Done and
  3703  	// the temporary breakpoint on the return address of main.f will be in
  3704  	// close proximity to main.main calling os.Exit() and causing the death of
  3705  	// the thread group leader.
  3706  
  3707  	withTestProcess("issue1101", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  3708  		setFunctionBreakpoint(p, t, "main.f")
  3709  		assertNoError(grp.Continue(), t, "Continue()")
  3710  		assertNoError(grp.Next(), t, "Next() 1")
  3711  		assertNoError(grp.Next(), t, "Next() 2")
  3712  		lastCmd := "Next() 3"
  3713  		exitErr := grp.Next()
  3714  		if exitErr == nil {
  3715  			lastCmd = "final Continue()"
  3716  			exitErr = grp.Continue()
  3717  		}
  3718  		if pexit, exited := exitErr.(proc.ErrProcessExited); exited {
  3719  			if pexit.Status != 2 && testBackend != "lldb" && (runtime.GOOS != "linux" || runtime.GOARCH != "386") {
  3720  				// Looks like there's a bug with debugserver on macOS that sometimes
  3721  				// will report exit status 0 instead of the proper exit status.
  3722  				//
  3723  				// Also it seems that sometimes on linux/386 we will not receive the
  3724  				// exit status. This happens if the process exits at the same time as it
  3725  				// receives a signal.
  3726  				t.Fatalf("process exited status %d (expected 2) (last command = %s) (%#v)", pexit.Status, lastCmd, pexit)
  3727  			}
  3728  		} else {
  3729  			assertNoError(exitErr, t, lastCmd)
  3730  			t.Fatalf("process did not exit after %s", lastCmd)
  3731  		}
  3732  	})
  3733  }
  3734  
  3735  func TestIssue1145(t *testing.T) {
  3736  	withTestProcess("sleep", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  3737  		setFileBreakpoint(p, t, fixture.Source, 18)
  3738  		assertNoError(grp.Continue(), t, "Continue()")
  3739  		resumeChan := make(chan struct{}, 1)
  3740  		grp.ResumeNotify(resumeChan)
  3741  		go func() {
  3742  			<-resumeChan
  3743  			time.Sleep(100 * time.Millisecond)
  3744  			grp.RequestManualStop()
  3745  		}()
  3746  
  3747  		assertNoError(grp.Next(), t, "Next()")
  3748  		if p.Breakpoints().HasSteppingBreakpoints() {
  3749  			t.Fatal("has internal breakpoints after manual stop request")
  3750  		}
  3751  	})
  3752  }
  3753  
  3754  func TestHaltKeepsSteppingBreakpoints(t *testing.T) {
  3755  	withTestProcess("sleep", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  3756  		grp.KeepSteppingBreakpoints = proc.HaltKeepsSteppingBreakpoints
  3757  		setFileBreakpoint(p, t, fixture.Source, 18)
  3758  		assertNoError(grp.Continue(), t, "Continue()")
  3759  		resumeChan := make(chan struct{}, 1)
  3760  		grp.ResumeNotify(resumeChan)
  3761  		go func() {
  3762  			<-resumeChan
  3763  			time.Sleep(100 * time.Millisecond)
  3764  			grp.RequestManualStop()
  3765  		}()
  3766  
  3767  		assertNoError(grp.Next(), t, "Next()")
  3768  		if !p.Breakpoints().HasSteppingBreakpoints() {
  3769  			t.Fatal("does not have internal breakpoints after manual stop request")
  3770  		}
  3771  	})
  3772  }
  3773  
  3774  func TestDisassembleGlobalVars(t *testing.T) {
  3775  	skipOn(t, "broken - global variable symbolication", "arm64")   // On ARM64 symLookup can't look up variables due to how they are loaded, see issue #1778
  3776  	skipOn(t, "broken - global variable symbolication", "ppc64le") // See comment on ARM64 above.
  3777  	// On 386 linux when pie, the generated code use __x86.get_pc_thunk to ensure position-independent.
  3778  	// Locate global variable by
  3779  	//    `CALL __x86.get_pc_thunk.ax(SB) 0xb0f7f
  3780  	//     LEAL 0xc0a19(AX), AX`
  3781  	// dynamically.
  3782  	if runtime.GOARCH == "386" && runtime.GOOS == "linux" && buildMode == "pie" {
  3783  		t.Skip("On 386 linux when pie, symLookup can't look up global variables")
  3784  	}
  3785  	withTestProcess("teststepconcurrent", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  3786  		mainfn := p.BinInfo().LookupFunc()["main.main"][0]
  3787  		regs, _ := p.CurrentThread().Registers()
  3788  		text, err := proc.Disassemble(p.Memory(), regs, p.Breakpoints(), p.BinInfo(), mainfn.Entry, mainfn.End)
  3789  		assertNoError(err, t, "Disassemble")
  3790  		found := false
  3791  		for i := range text {
  3792  			if strings.Index(text[i].Text(proc.IntelFlavour, p.BinInfo()), "main.v") > 0 {
  3793  				found = true
  3794  				break
  3795  			}
  3796  		}
  3797  		if !found {
  3798  			t.Fatalf("could not find main.v reference in disassembly")
  3799  		}
  3800  	})
  3801  }
  3802  
  3803  func checkFrame(frame proc.Stackframe, fnname, file string, line int, inlined bool) error {
  3804  	if frame.Call.Fn == nil || frame.Call.Fn.Name != fnname {
  3805  		return fmt.Errorf("wrong function name: %s", fnname)
  3806  	}
  3807  	if file != "" {
  3808  		if frame.Call.File != file || frame.Call.Line != line {
  3809  			return fmt.Errorf("wrong file:line %s:%d", frame.Call.File, frame.Call.Line)
  3810  		}
  3811  	}
  3812  	if frame.Inlined != inlined {
  3813  		if inlined {
  3814  			return fmt.Errorf("not inlined")
  3815  		}
  3816  		return fmt.Errorf("inlined")
  3817  	}
  3818  	return nil
  3819  }
  3820  
  3821  func TestAllPCsForFileLines(t *testing.T) {
  3822  	if ver, _ := goversion.Parse(runtime.Version()); ver.Major >= 0 && !ver.AfterOrEqual(goversion.GoVersion{Major: 1, Minor: 10, Rev: -1}) {
  3823  		// Versions of go before 1.10 do not have DWARF information for inlined calls
  3824  		t.Skip("inlining not supported")
  3825  	}
  3826  	withTestProcessArgs("testinline", t, ".", []string{}, protest.EnableInlining, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  3827  		l2pcs := p.BinInfo().AllPCsForFileLines(fixture.Source, []int{7, 20})
  3828  		if len(l2pcs) != 2 {
  3829  			t.Fatalf("expected two map entries for %s:{%d,%d} (got %d: %v)", fixture.Source, 7, 20, len(l2pcs), l2pcs)
  3830  		}
  3831  		pcs := l2pcs[20]
  3832  		if len(pcs) < 1 {
  3833  			t.Fatalf("expected at least one location for %s:%d (got %d: %#x)", fixture.Source, 20, len(pcs), pcs)
  3834  		}
  3835  		pcs = l2pcs[7]
  3836  		if len(pcs) < 2 {
  3837  			t.Fatalf("expected at least two locations for %s:%d (got %d: %#x)", fixture.Source, 7, len(pcs), pcs)
  3838  		}
  3839  	})
  3840  }
  3841  
  3842  func TestInlinedStacktraceAndVariables(t *testing.T) {
  3843  	if ver, _ := goversion.Parse(runtime.Version()); ver.Major >= 0 && !ver.AfterOrEqual(goversion.GoVersion{Major: 1, Minor: 10, Rev: -1}) {
  3844  		// Versions of go before 1.10 do not have DWARF information for inlined calls
  3845  		t.Skip("inlining not supported")
  3846  	}
  3847  
  3848  	firstCallCheck := &scopeCheck{
  3849  		line: 7,
  3850  		ok:   false,
  3851  		varChecks: []varCheck{
  3852  			{
  3853  				name:   "a",
  3854  				typ:    "int",
  3855  				kind:   reflect.Int,
  3856  				hasVal: true,
  3857  				intVal: 3,
  3858  			},
  3859  			{
  3860  				name:   "z",
  3861  				typ:    "int",
  3862  				kind:   reflect.Int,
  3863  				hasVal: true,
  3864  				intVal: 9,
  3865  			},
  3866  		},
  3867  	}
  3868  
  3869  	secondCallCheck := &scopeCheck{
  3870  		line: 7,
  3871  		ok:   false,
  3872  		varChecks: []varCheck{
  3873  			{
  3874  				name:   "a",
  3875  				typ:    "int",
  3876  				kind:   reflect.Int,
  3877  				hasVal: true,
  3878  				intVal: 4,
  3879  			},
  3880  			{
  3881  				name:   "z",
  3882  				typ:    "int",
  3883  				kind:   reflect.Int,
  3884  				hasVal: true,
  3885  				intVal: 16,
  3886  			},
  3887  		},
  3888  	}
  3889  
  3890  	withTestProcessArgs("testinline", t, ".", []string{}, protest.EnableInlining, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  3891  		pcs, err := proc.FindFileLocation(p, fixture.Source, 7)
  3892  		assertNoError(err, t, "LineToPC")
  3893  		if len(pcs) < 2 {
  3894  			t.Fatalf("expected at least two locations for %s:%d (got %d: %#x)", fixture.Source, 7, len(pcs), pcs)
  3895  		}
  3896  		for _, pc := range pcs {
  3897  			t.Logf("setting breakpoint at %#x\n", pc)
  3898  			_, err := p.SetBreakpoint(0, pc, proc.UserBreakpoint, nil)
  3899  			assertNoError(err, t, fmt.Sprintf("SetBreakpoint(%#x)", pc))
  3900  		}
  3901  
  3902  		// first inlined call
  3903  		assertNoError(grp.Continue(), t, "Continue")
  3904  		frames, err := proc.ThreadStacktrace(p, p.CurrentThread(), 20)
  3905  		assertNoError(err, t, "ThreadStacktrace")
  3906  		t.Logf("Stacktrace:\n")
  3907  		for i := range frames {
  3908  			t.Logf("\t%s at %s:%d (%#x)\n", frames[i].Call.Fn.Name, frames[i].Call.File, frames[i].Call.Line, frames[i].Current.PC)
  3909  		}
  3910  
  3911  		if err := checkFrame(frames[0], "main.inlineThis", fixture.Source, 7, true); err != nil {
  3912  			t.Fatalf("Wrong frame 0: %v", err)
  3913  		}
  3914  		if err := checkFrame(frames[1], "main.main", fixture.Source, 18, false); err != nil {
  3915  			t.Fatalf("Wrong frame 1: %v", err)
  3916  		}
  3917  
  3918  		if avar, _ := constant.Int64Val(evalVariable(p, t, "a").Value); avar != 3 {
  3919  			t.Fatalf("value of 'a' variable is not 3 (%d)", avar)
  3920  		}
  3921  		if zvar, _ := constant.Int64Val(evalVariable(p, t, "z").Value); zvar != 9 {
  3922  			t.Fatalf("value of 'z' variable is not 9 (%d)", zvar)
  3923  		}
  3924  
  3925  		if _, ok := firstCallCheck.checkLocalsAndArgs(p, t); !ok {
  3926  			t.Fatalf("exiting for past errors")
  3927  		}
  3928  
  3929  		// second inlined call
  3930  		assertNoError(grp.Continue(), t, "Continue")
  3931  		frames, err = proc.ThreadStacktrace(p, p.CurrentThread(), 20)
  3932  		assertNoError(err, t, "ThreadStacktrace (2)")
  3933  		t.Logf("Stacktrace 2:\n")
  3934  		for i := range frames {
  3935  			t.Logf("\t%s at %s:%d (%#x)\n", frames[i].Call.Fn.Name, frames[i].Call.File, frames[i].Call.Line, frames[i].Current.PC)
  3936  		}
  3937  
  3938  		if err := checkFrame(frames[0], "main.inlineThis", fixture.Source, 7, true); err != nil {
  3939  			t.Fatalf("Wrong frame 0: %v", err)
  3940  		}
  3941  		if err := checkFrame(frames[1], "main.main", fixture.Source, 19, false); err != nil {
  3942  			t.Fatalf("Wrong frame 1: %v", err)
  3943  		}
  3944  
  3945  		if avar, _ := constant.Int64Val(evalVariable(p, t, "a").Value); avar != 4 {
  3946  			t.Fatalf("value of 'a' variable is not 3 (%d)", avar)
  3947  		}
  3948  		if zvar, _ := constant.Int64Val(evalVariable(p, t, "z").Value); zvar != 16 {
  3949  			t.Fatalf("value of 'z' variable is not 9 (%d)", zvar)
  3950  		}
  3951  		if bvar, err := evalVariableOrError(p, "b"); err == nil {
  3952  			t.Fatalf("expected error evaluating 'b', but it succeeded instead: %v", bvar)
  3953  		}
  3954  
  3955  		if _, ok := secondCallCheck.checkLocalsAndArgs(p, t); !ok {
  3956  			t.Fatalf("exiting for past errors")
  3957  		}
  3958  	})
  3959  }
  3960  
  3961  func TestInlineStep(t *testing.T) {
  3962  	skipOn(t, "broken", "ppc64le")
  3963  	if ver, _ := goversion.Parse(runtime.Version()); ver.Major >= 0 && !ver.AfterOrEqual(goversion.GoVersion{Major: 1, Minor: 10, Rev: -1}) {
  3964  		// Versions of go before 1.10 do not have DWARF information for inlined calls
  3965  		t.Skip("inlining not supported")
  3966  	}
  3967  	testseq2Args(".", []string{}, protest.EnableInlining, t, "testinline", "", []seqTest{
  3968  		{contContinue, 18},
  3969  		{contStep, 6},
  3970  		{contStep, 7},
  3971  		{contStep, 24},
  3972  		{contStep, 25},
  3973  		{contStep, 7},
  3974  		{contStep, 18},
  3975  		{contStep, 19},
  3976  	})
  3977  }
  3978  
  3979  func TestInlineNext(t *testing.T) {
  3980  	if ver, _ := goversion.Parse(runtime.Version()); ver.Major >= 0 && !ver.AfterOrEqual(goversion.GoVersion{Major: 1, Minor: 10, Rev: -1}) {
  3981  		// Versions of go before 1.10 do not have DWARF information for inlined calls
  3982  		t.Skip("inlining not supported")
  3983  	}
  3984  	testseq2Args(".", []string{}, protest.EnableInlining, t, "testinline", "", []seqTest{
  3985  		{contContinue, 18},
  3986  		{contStep, 6},
  3987  		{contNext, 7},
  3988  		{contNext, 18},
  3989  		{contNext, 19},
  3990  	})
  3991  }
  3992  
  3993  func TestInlineStepOver(t *testing.T) {
  3994  	if ver, _ := goversion.Parse(runtime.Version()); ver.Major >= 0 && !ver.AfterOrEqual(goversion.GoVersion{Major: 1, Minor: 10, Rev: -1}) {
  3995  		// Versions of go before 1.10 do not have DWARF information for inlined calls
  3996  		t.Skip("inlining not supported")
  3997  	}
  3998  	testseq2Args(".", []string{}, protest.EnableInlining, t, "testinline", "", []seqTest{
  3999  		{contContinue, 18},
  4000  		{contNext, 19},
  4001  		{contNext, 20},
  4002  	})
  4003  }
  4004  
  4005  func TestInlineStepOut(t *testing.T) {
  4006  	if ver, _ := goversion.Parse(runtime.Version()); ver.Major >= 0 && !ver.AfterOrEqual(goversion.GoVersion{Major: 1, Minor: 10, Rev: -1}) {
  4007  		// Versions of go before 1.10 do not have DWARF information for inlined calls
  4008  		t.Skip("inlining not supported")
  4009  	}
  4010  	testseq2Args(".", []string{}, protest.EnableInlining, t, "testinline", "", []seqTest{
  4011  		{contContinue, 18},
  4012  		{contStep, 6},
  4013  		{contStepout, 18},
  4014  	})
  4015  }
  4016  
  4017  func TestInlineFunctionList(t *testing.T) {
  4018  	// We should be able to list all functions, even inlined ones.
  4019  	ver, _ := goversion.Parse(runtime.Version())
  4020  	if ver.Major >= 0 && !ver.AfterOrEqual(goversion.GoVersion{Major: 1, Minor: 10, Rev: -1}) {
  4021  		// Versions of go before 1.10 do not have DWARF information for inlined calls
  4022  		t.Skip("inlining not supported")
  4023  	}
  4024  	if runtime.GOOS == "windows" && runtime.GOARCH == "arm64" {
  4025  		// TODO(qmuntal): seems to be an upstream issue, investigate.
  4026  		t.Skip("inlining not supported")
  4027  	}
  4028  	withTestProcessArgs("testinline", t, ".", []string{}, protest.EnableInlining|protest.EnableOptimization, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  4029  		var found bool
  4030  		for _, fn := range p.BinInfo().Functions {
  4031  			if strings.Contains(fn.Name, "inlineThis") {
  4032  				found = true
  4033  				break
  4034  			}
  4035  		}
  4036  		if !found {
  4037  			t.Fatal("inline function not returned")
  4038  		}
  4039  	})
  4040  }
  4041  
  4042  func TestInlineBreakpoint(t *testing.T) {
  4043  	// We should be able to set a breakpoint on the call site of an inlined function.
  4044  	if ver, _ := goversion.Parse(runtime.Version()); ver.Major >= 0 && !ver.AfterOrEqual(goversion.GoVersion{Major: 1, Minor: 10, Rev: -1}) {
  4045  		// Versions of go before 1.10 do not have DWARF information for inlined calls
  4046  		t.Skip("inlining not supported")
  4047  	}
  4048  	withTestProcessArgs("testinline", t, ".", []string{}, protest.EnableInlining|protest.EnableOptimization, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  4049  		pcs, err := proc.FindFileLocation(p, fixture.Source, 17)
  4050  		if err != nil {
  4051  			t.Fatal(err)
  4052  		}
  4053  		t.Logf("%#v\n", pcs)
  4054  		if len(pcs) != 1 {
  4055  			t.Fatalf("unable to get PC for inlined function call: %v", pcs)
  4056  		}
  4057  		fn := p.BinInfo().PCToFunc(pcs[0])
  4058  		expectedFn := "main.main"
  4059  		if fn.Name != expectedFn {
  4060  			t.Fatalf("incorrect function returned, expected %s, got %s", expectedFn, fn.Name)
  4061  		}
  4062  		_, err = p.SetBreakpoint(0, pcs[0], proc.UserBreakpoint, nil)
  4063  		if err != nil {
  4064  			t.Fatalf("unable to set breakpoint: %v", err)
  4065  		}
  4066  	})
  4067  }
  4068  
  4069  func TestDoubleInlineBreakpoint(t *testing.T) {
  4070  	// We should be able to set a breakpoint on an inlined function that
  4071  	// has been inlined within an inlined function.
  4072  	if ver, _ := goversion.Parse(runtime.Version()); ver.Major >= 0 && !ver.AfterOrEqual(goversion.GoVersion{Major: 1, Minor: 10, Rev: -1}) {
  4073  		// Versions of go before 1.10 do not have DWARF information for inlined calls
  4074  		t.Skip("inlining not supported")
  4075  	}
  4076  	withTestProcessArgs("doubleinline", t, ".", []string{}, protest.EnableInlining|protest.EnableOptimization, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  4077  		fns, err := p.BinInfo().FindFunction("main.(*Rectangle).Height")
  4078  		if err != nil {
  4079  			t.Fatal(err)
  4080  		}
  4081  		if len(fns) != 1 {
  4082  			t.Fatalf("expected one function for Height, got %d", len(fns))
  4083  		}
  4084  		if len(fns[0].InlinedCalls) != 1 {
  4085  			t.Fatalf("expected one inlined call for Height, got %d", len(fns[0].InlinedCalls))
  4086  		}
  4087  	})
  4088  }
  4089  
  4090  func TestIssue951(t *testing.T) {
  4091  	if ver, _ := goversion.Parse(runtime.Version()); ver.Major >= 0 && !ver.AfterOrEqual(goversion.GoVersion{Major: 1, Minor: 9, Rev: -1}) {
  4092  		t.Skip("scopes not implemented in <=go1.8")
  4093  	}
  4094  
  4095  	withTestProcess("issue951", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  4096  		assertNoError(grp.Continue(), t, "Continue()")
  4097  		scope, err := proc.GoroutineScope(p, p.CurrentThread())
  4098  		assertNoError(err, t, "GoroutineScope")
  4099  		args, err := scope.FunctionArguments(normalLoadConfig)
  4100  		assertNoError(err, t, "FunctionArguments")
  4101  		t.Logf("%#v", args[0])
  4102  		if args[0].Flags&proc.VariableShadowed == 0 {
  4103  			t.Error("argument is not shadowed")
  4104  		}
  4105  		vars, err := scope.LocalVariables(normalLoadConfig)
  4106  		assertNoError(err, t, "LocalVariables")
  4107  		shadowed, notShadowed := 0, 0
  4108  		for i := range vars {
  4109  			t.Logf("var %d: %#v\n", i, vars[i])
  4110  			if vars[i].Flags&proc.VariableShadowed != 0 {
  4111  				shadowed++
  4112  			} else {
  4113  				notShadowed++
  4114  			}
  4115  		}
  4116  		if shadowed != 1 || notShadowed != 1 {
  4117  			t.Errorf("Wrong number of shadowed/non-shadowed local variables: %d %d", shadowed, notShadowed)
  4118  		}
  4119  	})
  4120  }
  4121  
  4122  func TestDWZCompression(t *testing.T) {
  4123  	skipOn(t, "broken", "ppc64le")
  4124  	// If dwz is not available in the system, skip this test
  4125  	if _, err := exec.LookPath("dwz"); err != nil {
  4126  		t.Skip("dwz not installed")
  4127  	}
  4128  
  4129  	withTestProcessArgs("dwzcompression", t, ".", []string{}, protest.EnableDWZCompression, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  4130  		setFunctionBreakpoint(p, t, "C.fortytwo")
  4131  		assertNoError(grp.Continue(), t, "first Continue()")
  4132  		val := evalVariable(p, t, "stdin")
  4133  		if val.RealType == nil {
  4134  			t.Errorf("Can't find type for \"stdin\" global variable")
  4135  		}
  4136  	})
  4137  }
  4138  
  4139  func TestMapLoadConfigWithReslice(t *testing.T) {
  4140  	// Check that load configuration is respected for resliced maps.
  4141  	withTestProcess("testvariables2", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  4142  		zolotovLoadCfg := proc.LoadConfig{FollowPointers: true, MaxStructFields: -1, MaxVariableRecurse: 3, MaxStringLen: 10, MaxArrayValues: 10}
  4143  		assertNoError(grp.Continue(), t, "First Continue()")
  4144  		scope, err := proc.GoroutineScope(p, p.CurrentThread())
  4145  		assertNoError(err, t, "GoroutineScope")
  4146  		m1, err := scope.EvalExpression("m1", zolotovLoadCfg)
  4147  		assertNoError(err, t, "EvalVariable")
  4148  		t.Logf("m1 returned children %d (%d)", len(m1.Children)/2, m1.Len)
  4149  
  4150  		expr := fmt.Sprintf("(*(*%q)(%d))[10:]", m1.DwarfType.String(), m1.Addr)
  4151  		t.Logf("expr %q\n", expr)
  4152  
  4153  		m1cont, err := scope.EvalExpression(expr, zolotovLoadCfg)
  4154  		assertNoError(err, t, "EvalVariable")
  4155  
  4156  		t.Logf("m1cont returned children %d", len(m1cont.Children)/2)
  4157  
  4158  		if len(m1cont.Children) != 20 {
  4159  			t.Fatalf("wrong number of children returned %d\n", len(m1cont.Children)/2)
  4160  		}
  4161  	})
  4162  }
  4163  
  4164  func TestStepOutReturn(t *testing.T) {
  4165  	ver, _ := goversion.Parse(runtime.Version())
  4166  	if ver.Major >= 0 && !ver.AfterOrEqual(goversion.GoVersion{Major: 1, Minor: 10, Rev: -1}) {
  4167  		t.Skip("return variables aren't marked on 1.9 or earlier")
  4168  	}
  4169  	withTestProcess("stepoutret", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  4170  		setFunctionBreakpoint(p, t, "main.stepout")
  4171  		assertNoError(grp.Continue(), t, "Continue")
  4172  		assertNoError(grp.StepOut(), t, "StepOut")
  4173  		ret := p.CurrentThread().Common().ReturnValues(normalLoadConfig)
  4174  		if len(ret) != 2 {
  4175  			t.Fatalf("wrong number of return values %v", ret)
  4176  		}
  4177  
  4178  		stridx := 0
  4179  		numidx := 1
  4180  
  4181  		if !goversion.VersionAfterOrEqual(runtime.Version(), 1, 12) {
  4182  			// in 1.11 and earlier the order of return values in DWARF is
  4183  			// unspecified, in 1.11 and later it follows the order of definition
  4184  			// specified by the user
  4185  			for i := range ret {
  4186  				if ret[i].Name == "str" {
  4187  					stridx = i
  4188  					numidx = 1 - i
  4189  					break
  4190  				}
  4191  			}
  4192  		}
  4193  
  4194  		if ret[stridx].Name != "str" {
  4195  			t.Fatalf("(str) bad return value name %s", ret[stridx].Name)
  4196  		}
  4197  		if ret[stridx].Kind != reflect.String {
  4198  			t.Fatalf("(str) bad return value kind %v", ret[stridx].Kind)
  4199  		}
  4200  		if s := constant.StringVal(ret[stridx].Value); s != "return 47" {
  4201  			t.Fatalf("(str) bad return value %q", s)
  4202  		}
  4203  
  4204  		if ret[numidx].Name != "num" {
  4205  			t.Fatalf("(num) bad return value name %s", ret[numidx].Name)
  4206  		}
  4207  		if ret[numidx].Kind != reflect.Int {
  4208  			t.Fatalf("(num) bad return value kind %v", ret[numidx].Kind)
  4209  		}
  4210  		if n, _ := constant.Int64Val(ret[numidx].Value); n != 48 {
  4211  			t.Fatalf("(num) bad return value %d", n)
  4212  		}
  4213  	})
  4214  }
  4215  
  4216  func TestOptimizationCheck(t *testing.T) {
  4217  	withTestProcess("continuetestprog", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  4218  		fn := p.BinInfo().LookupFunc()["main.main"][0]
  4219  		if fn.Optimized() {
  4220  			t.Fatalf("main.main is optimized")
  4221  		}
  4222  	})
  4223  
  4224  	if goversion.VersionAfterOrEqual(runtime.Version(), 1, 10) {
  4225  		withTestProcessArgs("continuetestprog", t, ".", []string{}, protest.EnableOptimization|protest.EnableInlining, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  4226  			fn := p.BinInfo().LookupFunc()["main.main"][0]
  4227  			if !fn.Optimized() {
  4228  				t.Fatalf("main.main is not optimized")
  4229  			}
  4230  		})
  4231  	}
  4232  }
  4233  
  4234  func TestIssue1264(t *testing.T) {
  4235  	// It should be possible to set a breakpoint condition that consists only
  4236  	// of evaluating a single boolean variable.
  4237  	withTestProcess("issue1264", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  4238  		bp := setFileBreakpoint(p, t, fixture.Source, 8)
  4239  		bp.UserBreaklet().Cond = &ast.Ident{Name: "equalsTwo"}
  4240  		assertNoError(grp.Continue(), t, "Continue()")
  4241  		assertLineNumber(p, t, 8, "after continue")
  4242  	})
  4243  }
  4244  
  4245  func TestReadDefer(t *testing.T) {
  4246  	withTestProcess("deferstack", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  4247  		assertNoError(grp.Continue(), t, "Continue")
  4248  		frames, err := proc.GoroutineStacktrace(p, p.SelectedGoroutine(), 10, proc.StacktraceReadDefers)
  4249  		assertNoError(err, t, "Stacktrace")
  4250  
  4251  		logStacktrace(t, p, frames)
  4252  
  4253  		examples := []struct {
  4254  			frameIdx     int
  4255  			topmostDefer string
  4256  			defers       []string
  4257  		}{
  4258  			// main.call3 (defers nothing, topmost defer main.f2)
  4259  			{0, "main.f2", []string{}},
  4260  
  4261  			// main.call2 (defers main.f2, main.f3, topmost defer main.f2)
  4262  			{1, "main.f2", []string{"main.f2", "main.f3"}},
  4263  
  4264  			// main.call1 (defers main.f1, main.f2, topmost defer main.f1)
  4265  			{2, "main.f1", []string{"main.f1", "main.f2"}},
  4266  
  4267  			// main.main (defers nothing)
  4268  			{3, "", []string{}}}
  4269  
  4270  		defercheck := func(d *proc.Defer, deferName, tgt string, frameIdx int) {
  4271  			if d == nil {
  4272  				t.Fatalf("expected %q as %s of frame %d, got nothing", tgt, deferName, frameIdx)
  4273  			}
  4274  			if d.Unreadable != nil {
  4275  				t.Fatalf("expected %q as %s of frame %d, got unreadable defer: %v", tgt, deferName, frameIdx, d.Unreadable)
  4276  			}
  4277  			_, _, dfn := d.DeferredFunc(p)
  4278  			if dfn == nil {
  4279  				t.Fatalf("expected %q as %s of frame %d, got %#x", tgt, deferName, frameIdx, d.DwrapPC)
  4280  			}
  4281  			if dfn.Name != tgt {
  4282  				t.Fatalf("expected %q as %s of frame %d, got %q", tgt, deferName, frameIdx, dfn.Name)
  4283  			}
  4284  		}
  4285  
  4286  		for _, example := range examples {
  4287  			frame := &frames[example.frameIdx]
  4288  
  4289  			if example.topmostDefer != "" {
  4290  				defercheck(frame.TopmostDefer, "topmost defer", example.topmostDefer, example.frameIdx)
  4291  			}
  4292  
  4293  			if len(example.defers) != len(frames[example.frameIdx].Defers) {
  4294  				t.Fatalf("expected %d defers for %d, got %v", len(example.defers), example.frameIdx, frame.Defers)
  4295  			}
  4296  
  4297  			for deferIdx := range example.defers {
  4298  				defercheck(frame.Defers[deferIdx], fmt.Sprintf("defer %d", deferIdx), example.defers[deferIdx], example.frameIdx)
  4299  			}
  4300  		}
  4301  	})
  4302  }
  4303  
  4304  func TestReadDeferArgs(t *testing.T) {
  4305  	if goversion.VersionAfterOrEqual(runtime.Version(), 1, 17) {
  4306  		// When regabi is enabled in Go 1.17 and later, reading arguments of
  4307  		// deferred functions becomes significantly more complicated because of
  4308  		// the autogenerated code used to unpack the argument frame stored in
  4309  		// runtime._defer into registers.
  4310  		// We either need to know how to do the translation, implementing the ABI1
  4311  		// rules in Delve, or have some assistance from the compiler (for example
  4312  		// have the dwrap function contain entries for each of the captured
  4313  		// variables with a location describing their offset from DX).
  4314  		// Ultimately this feature is unimportant enough that we can leave it
  4315  		// disabled for now.
  4316  		t.Skip("unsupported")
  4317  	}
  4318  	var tests = []struct {
  4319  		frame, deferCall int
  4320  		a, b             int64
  4321  	}{
  4322  		{1, 1, 42, 61},
  4323  		{2, 2, 1, -1},
  4324  	}
  4325  
  4326  	withTestProcess("deferstack", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  4327  		assertNoError(grp.Continue(), t, "Continue()")
  4328  
  4329  		for _, test := range tests {
  4330  			scope, err := proc.ConvertEvalScope(p, -1, test.frame, test.deferCall)
  4331  			assertNoError(err, t, fmt.Sprintf("ConvertEvalScope(-1, %d, %d)", test.frame, test.deferCall))
  4332  
  4333  			if !goversion.VersionAfterOrEqual(runtime.Version(), 1, 17) {
  4334  				// In Go 1.17 deferred function calls can end up inside a wrapper, and
  4335  				// the scope for this evaluation needs to be the wrapper.
  4336  				if scope.Fn.Name != "main.f2" {
  4337  					t.Fatalf("expected function \"main.f2\" got %q", scope.Fn.Name)
  4338  				}
  4339  			}
  4340  
  4341  			avar, err := scope.EvalExpression("a", normalLoadConfig)
  4342  			if err != nil {
  4343  				t.Fatal(err)
  4344  			}
  4345  			bvar, err := scope.EvalExpression("b", normalLoadConfig)
  4346  			if err != nil {
  4347  				t.Fatal(err)
  4348  			}
  4349  
  4350  			a, _ := constant.Int64Val(avar.Value)
  4351  			b, _ := constant.Int64Val(bvar.Value)
  4352  
  4353  			if a != test.a {
  4354  				t.Errorf("value of argument 'a' at frame %d, deferred call %d: %d (expected %d)", test.frame, test.deferCall, a, test.a)
  4355  			}
  4356  
  4357  			if b != test.b {
  4358  				t.Errorf("value of argument 'b' at frame %d, deferred call %d: %d (expected %d)", test.frame, test.deferCall, b, test.b)
  4359  			}
  4360  		}
  4361  	})
  4362  }
  4363  
  4364  func TestIssue1374(t *testing.T) {
  4365  	// Continue did not work when stopped at a breakpoint immediately after calling CallFunction.
  4366  	skipOn(t, "broken - pie mode", "linux", "ppc64le", "native", "pie")
  4367  
  4368  	protest.MustSupportFunctionCalls(t, testBackend)
  4369  	withTestProcess("issue1374", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  4370  		setFileBreakpoint(p, t, fixture.Source, 7)
  4371  		assertNoError(grp.Continue(), t, "First Continue")
  4372  		assertLineNumber(p, t, 7, "Did not continue to correct location (first continue),")
  4373  		assertNoError(proc.EvalExpressionWithCalls(grp, p.SelectedGoroutine(), "getNum()", normalLoadConfig, true), t, "Call")
  4374  		err := grp.Continue()
  4375  		if _, isexited := err.(proc.ErrProcessExited); !isexited {
  4376  			regs, _ := p.CurrentThread().Registers()
  4377  			f, l, _ := p.BinInfo().PCToLine(regs.PC())
  4378  			t.Fatalf("expected process exited error got %v at %s:%d", err, f, l)
  4379  		}
  4380  	})
  4381  }
  4382  
  4383  func TestIssue1432(t *testing.T) {
  4384  	// Check that taking the address of a struct, casting it into a pointer to
  4385  	// the struct's type and then accessing a member field will still:
  4386  	// - perform auto-dereferencing on struct member access
  4387  	// - yield a Variable that's ultimately assignable (i.e. has an address)
  4388  	withTestProcess("issue1432", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  4389  		assertNoError(grp.Continue(), t, "Continue")
  4390  		svar := evalVariable(p, t, "s")
  4391  		t.Logf("%#x", svar.Addr)
  4392  
  4393  		scope, err := proc.GoroutineScope(p, p.CurrentThread())
  4394  		assertNoError(err, t, "GoroutineScope()")
  4395  
  4396  		err = scope.SetVariable(fmt.Sprintf("(*\"main.s\")(%#x).i", svar.Addr), "10")
  4397  		assertNoError(err, t, "SetVariable")
  4398  	})
  4399  }
  4400  
  4401  func TestGoroutinesInfoLimit(t *testing.T) {
  4402  	withTestProcess("teststepconcurrent", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  4403  		setFileBreakpoint(p, t, fixture.Source, 37)
  4404  		assertNoError(grp.Continue(), t, "Continue()")
  4405  
  4406  		gcount := 0
  4407  		nextg := 0
  4408  		const goroutinesInfoLimit = 10
  4409  		for nextg >= 0 {
  4410  			oldnextg := nextg
  4411  			var gs []*proc.G
  4412  			var err error
  4413  			gs, nextg, err = proc.GoroutinesInfo(p, nextg, goroutinesInfoLimit)
  4414  			assertNoError(err, t, fmt.Sprintf("GoroutinesInfo(%d, %d)", oldnextg, goroutinesInfoLimit))
  4415  			gcount += len(gs)
  4416  			t.Logf("got %d goroutines\n", len(gs))
  4417  		}
  4418  
  4419  		t.Logf("number of goroutines: %d\n", gcount)
  4420  
  4421  		gs, _, err := proc.GoroutinesInfo(p, 0, 0)
  4422  		assertNoError(err, t, "GoroutinesInfo(0, 0)")
  4423  		t.Logf("number of goroutines (full scan): %d\n", gcount)
  4424  		if len(gs) != gcount {
  4425  			t.Fatalf("mismatch in the number of goroutines %d %d\n", gcount, len(gs))
  4426  		}
  4427  	})
  4428  }
  4429  
  4430  func TestIssue1469(t *testing.T) {
  4431  	withTestProcess("issue1469", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  4432  		setFileBreakpoint(p, t, fixture.Source, 13)
  4433  		assertNoError(grp.Continue(), t, "Continue()")
  4434  
  4435  		gid2thread := make(map[int64][]proc.Thread)
  4436  		for _, thread := range p.ThreadList() {
  4437  			g, _ := proc.GetG(thread)
  4438  			if g == nil {
  4439  				continue
  4440  			}
  4441  			gid2thread[g.ID] = append(gid2thread[g.ID], thread)
  4442  		}
  4443  
  4444  		for gid := range gid2thread {
  4445  			if len(gid2thread[gid]) > 1 {
  4446  				t.Logf("too many threads running goroutine %d", gid)
  4447  				for _, thread := range gid2thread[gid] {
  4448  					t.Logf("\tThread %d", thread.ThreadID())
  4449  					frames, err := proc.ThreadStacktrace(p, thread, 20)
  4450  					if err != nil {
  4451  						t.Logf("\t\tcould not get stacktrace %v", err)
  4452  					}
  4453  					for _, frame := range frames {
  4454  						t.Logf("\t\t%#x at %s:%d (systemstack: %v)", frame.Call.PC, frame.Call.File, frame.Call.Line, frame.SystemStack)
  4455  					}
  4456  				}
  4457  			}
  4458  		}
  4459  	})
  4460  }
  4461  
  4462  func TestDeadlockBreakpoint(t *testing.T) {
  4463  	skipOn(t, "upstream issue - https://github.com/golang/go/issues/29322", "pie")
  4464  	deadlockBp := proc.FatalThrow
  4465  	if !goversion.VersionAfterOrEqual(runtime.Version(), 1, 11) {
  4466  		deadlockBp = proc.UnrecoveredPanic
  4467  	}
  4468  	withTestProcess("testdeadlock", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  4469  		assertNoError(grp.Continue(), t, "Continue()")
  4470  
  4471  		bp := p.CurrentThread().Breakpoint()
  4472  		if bp.Breakpoint == nil || bp.Logical.Name != deadlockBp {
  4473  			t.Fatalf("did not stop at deadlock breakpoint %v", bp)
  4474  		}
  4475  	})
  4476  }
  4477  
  4478  func findSource(source string, sources []string) bool {
  4479  	for _, s := range sources {
  4480  		if s == source {
  4481  			return true
  4482  		}
  4483  	}
  4484  	return false
  4485  }
  4486  
  4487  func TestListImages(t *testing.T) {
  4488  	protest.MustHaveCgo(t)
  4489  	pluginFixtures := protest.WithPlugins(t, protest.AllNonOptimized, "plugin1/", "plugin2/")
  4490  
  4491  	withTestProcessArgs("plugintest", t, ".", []string{pluginFixtures[0].Path, pluginFixtures[1].Path}, protest.AllNonOptimized, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  4492  		if !findSource(fixture.Source, p.BinInfo().Sources) {
  4493  			t.Fatalf("could not find %s in sources: %q\n", fixture.Source, p.BinInfo().Sources)
  4494  		}
  4495  
  4496  		assertNoError(grp.Continue(), t, "first continue")
  4497  		f, l := currentLineNumber(p, t)
  4498  		plugin1Found := false
  4499  		t.Logf("Libraries before %s:%d:", f, l)
  4500  		for _, image := range p.BinInfo().Images {
  4501  			t.Logf("\t%#x %q err:%v", image.StaticBase, image.Path, image.LoadError())
  4502  			if image.Path == pluginFixtures[0].Path {
  4503  				plugin1Found = true
  4504  			}
  4505  		}
  4506  		if !plugin1Found {
  4507  			t.Fatalf("Could not find plugin1")
  4508  		}
  4509  		if !findSource(fixture.Source, p.BinInfo().Sources) {
  4510  			// Source files for the base program must be available even after a plugin is loaded. Issue #2074.
  4511  			t.Fatalf("could not find %s in sources (after loading plugin): %q\n", fixture.Source, p.BinInfo().Sources)
  4512  		}
  4513  		assertNoError(grp.Continue(), t, "second continue")
  4514  		f, l = currentLineNumber(p, t)
  4515  		plugin1Found, plugin2Found := false, false
  4516  		t.Logf("Libraries after %s:%d:", f, l)
  4517  		for _, image := range p.BinInfo().Images {
  4518  			t.Logf("\t%#x %q err:%v", image.StaticBase, image.Path, image.LoadError())
  4519  			switch image.Path {
  4520  			case pluginFixtures[0].Path:
  4521  				plugin1Found = true
  4522  			case pluginFixtures[1].Path:
  4523  				plugin2Found = true
  4524  			}
  4525  		}
  4526  		if !plugin1Found {
  4527  			t.Fatalf("Could not find plugin1")
  4528  		}
  4529  		if !plugin2Found {
  4530  			t.Fatalf("Could not find plugin2")
  4531  		}
  4532  	})
  4533  }
  4534  
  4535  func TestAncestors(t *testing.T) {
  4536  	t.Setenv("GODEBUG", "tracebackancestors=100")
  4537  	withTestProcess("testnextprog", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  4538  		setFunctionBreakpoint(p, t, "main.testgoroutine")
  4539  		assertNoError(grp.Continue(), t, "Continue()")
  4540  		as, err := proc.Ancestors(p, p.SelectedGoroutine(), 1000)
  4541  		assertNoError(err, t, "Ancestors")
  4542  		t.Logf("ancestors: %#v\n", as)
  4543  		if len(as) != 1 {
  4544  			t.Fatalf("expected only one ancestor got %d", len(as))
  4545  		}
  4546  		mainFound := false
  4547  		for i, a := range as {
  4548  			astack, err := a.Stack(100)
  4549  			assertNoError(err, t, fmt.Sprintf("Ancestor %d stack", i))
  4550  			t.Logf("ancestor %d\n", i)
  4551  			logStacktrace(t, p, astack)
  4552  			for _, frame := range astack {
  4553  				if frame.Current.Fn != nil && frame.Current.Fn.Name == "main.main" {
  4554  					mainFound = true
  4555  				}
  4556  			}
  4557  		}
  4558  		if !mainFound {
  4559  			t.Fatal("could not find main.main function in ancestors")
  4560  		}
  4561  	})
  4562  }
  4563  
  4564  func testCallConcurrentCheckReturns(p *proc.Target, t *testing.T, gid1, gid2 int64) int {
  4565  	found := 0
  4566  	for _, thread := range p.ThreadList() {
  4567  		g, _ := proc.GetG(thread)
  4568  		if g == nil || (g.ID != gid1 && g.ID != gid2) {
  4569  			continue
  4570  		}
  4571  		retvals := thread.Common().ReturnValues(normalLoadConfig)
  4572  		if len(retvals) == 0 {
  4573  			continue
  4574  		}
  4575  		n, _ := constant.Int64Val(retvals[0].Value)
  4576  		t.Logf("injection on goroutine %d (thread %d) returned %v\n", g.ID, thread.ThreadID(), n)
  4577  		switch g.ID {
  4578  		case gid1:
  4579  			if n != 11 {
  4580  				t.Errorf("wrong return value for goroutine %d", g.ID)
  4581  			}
  4582  			found++
  4583  		case gid2:
  4584  			if n != 12 {
  4585  				t.Errorf("wrong return value for goroutine %d", g.ID)
  4586  			}
  4587  			found++
  4588  		}
  4589  	}
  4590  	return found
  4591  }
  4592  
  4593  func TestCallConcurrent(t *testing.T) {
  4594  	skipOn(t, "broken - pie mode", "linux", "ppc64le", "native", "pie")
  4595  
  4596  	protest.MustSupportFunctionCalls(t, testBackend)
  4597  	withTestProcess("teststepconcurrent", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  4598  		bp := setFileBreakpoint(p, t, fixture.Source, 24)
  4599  		assertNoError(grp.Continue(), t, "Continue()")
  4600  		//_, err := p.ClearBreakpoint(bp.Addr)
  4601  		//assertNoError(err, t, "ClearBreakpoint() returned an error")
  4602  
  4603  		gid1 := p.SelectedGoroutine().ID
  4604  		t.Logf("starting injection in %d / %d", p.SelectedGoroutine().ID, p.CurrentThread().ThreadID())
  4605  		assertNoError(proc.EvalExpressionWithCalls(grp, p.SelectedGoroutine(), "Foo(10, 1)", normalLoadConfig, false), t, "EvalExpressionWithCalls()")
  4606  
  4607  		returned := testCallConcurrentCheckReturns(p, t, gid1, -1)
  4608  
  4609  		curthread := p.CurrentThread()
  4610  		if curbp := curthread.Breakpoint(); curbp.Breakpoint == nil || curbp.LogicalID() != bp.LogicalID() || returned > 0 {
  4611  			t.Logf("skipping test, the call injection terminated before we hit a breakpoint in a different thread")
  4612  			return
  4613  		}
  4614  
  4615  		err := p.ClearBreakpoint(bp.Addr)
  4616  		assertNoError(err, t, "ClearBreakpoint() returned an error")
  4617  
  4618  		gid2 := p.SelectedGoroutine().ID
  4619  		t.Logf("starting second injection in %d / %d", p.SelectedGoroutine().ID, p.CurrentThread().ThreadID())
  4620  		assertNoError(proc.EvalExpressionWithCalls(grp, p.SelectedGoroutine(), "Foo(10, 2)", normalLoadConfig, false), t, "EvalExpressionWithCalls")
  4621  
  4622  		for {
  4623  			returned += testCallConcurrentCheckReturns(p, t, gid1, gid2)
  4624  			if returned >= 2 {
  4625  				break
  4626  			}
  4627  			t.Logf("Continuing... %d", returned)
  4628  			assertNoError(grp.Continue(), t, "Continue()")
  4629  		}
  4630  
  4631  		grp.Continue()
  4632  	})
  4633  }
  4634  
  4635  func TestPluginStepping(t *testing.T) {
  4636  	protest.MustHaveCgo(t)
  4637  	pluginFixtures := protest.WithPlugins(t, protest.AllNonOptimized, "plugin1/", "plugin2/")
  4638  
  4639  	testseq2Args(".", []string{pluginFixtures[0].Path, pluginFixtures[1].Path}, protest.AllNonOptimized, t, "plugintest2", "", []seqTest{
  4640  		{contContinue, 41},
  4641  		{contStep, "plugin1.go:9"},
  4642  		{contStep, "plugin1.go:10"},
  4643  		{contStep, "plugin1.go:11"},
  4644  		{contNext, "plugin1.go:12"},
  4645  		{contNext, "plugintest2.go:41"},
  4646  		{contNext, "plugintest2.go:42"},
  4647  		{contStep, "plugin2.go:22"},
  4648  		{contNext, "plugin2.go:23"},
  4649  		{contNext, "plugin2.go:26"},
  4650  		{contNext, "plugintest2.go:42"}})
  4651  }
  4652  
  4653  func TestIssue1601(t *testing.T) {
  4654  	protest.MustHaveCgo(t)
  4655  	// Tests that recursive types involving C qualifiers and typedefs are parsed correctly
  4656  	withTestProcess("issue1601", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  4657  		assertNoError(grp.Continue(), t, "Continue")
  4658  		evalVariable(p, t, "C.globalq")
  4659  	})
  4660  }
  4661  
  4662  func TestIssue1615(t *testing.T) {
  4663  	// A breakpoint condition that tests for string equality with a constant string shouldn't fail with 'string too long for comparison' error
  4664  
  4665  	withTestProcess("issue1615", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  4666  		bp := setFileBreakpoint(p, t, fixture.Source, 19)
  4667  		bp.UserBreaklet().Cond = &ast.BinaryExpr{
  4668  			Op: token.EQL,
  4669  			X:  &ast.Ident{Name: "s"},
  4670  			Y:  &ast.BasicLit{Kind: token.STRING, Value: `"projects/my-gcp-project-id-string/locations/us-central1/queues/my-task-queue-name"`},
  4671  		}
  4672  
  4673  		assertNoError(grp.Continue(), t, "Continue")
  4674  		assertLineNumber(p, t, 19, "")
  4675  	})
  4676  }
  4677  
  4678  func TestCgoStacktrace2(t *testing.T) {
  4679  	if !goversion.VersionAfterOrEqual(runtime.Version(), 1, 21) {
  4680  		skipOn(t, "upstream issue", "windows")
  4681  		skipOn(t, "broken", "arm64")
  4682  	}
  4683  	skipOn(t, "broken", "386")
  4684  	skipOn(t, "broken - cgo stacktraces", "darwin", "arm64")
  4685  	skipOn(t, "broken", "ppc64le")
  4686  	protest.MustHaveCgo(t)
  4687  	// If a panic happens during cgo execution the stacktrace should show the C
  4688  	// function that caused the problem.
  4689  	withTestProcess("cgosigsegvstack", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  4690  		err := grp.Continue()
  4691  		if _, exited := err.(proc.ErrProcessExited); exited {
  4692  			t.Fatal("process exited")
  4693  		}
  4694  		frames, err := proc.ThreadStacktrace(p, p.CurrentThread(), 100)
  4695  		assertNoError(err, t, "Stacktrace()")
  4696  		logStacktrace(t, p, frames)
  4697  		m := stacktraceCheck(t, []string{"C.sigsegv", "C.testfn", "main.main"}, frames)
  4698  		if m == nil {
  4699  			t.Fatal("see previous loglines")
  4700  		}
  4701  	})
  4702  }
  4703  
  4704  func TestIssue1736(t *testing.T) {
  4705  	withTestProcess("testvariables2", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  4706  		assertNoError(grp.Continue(), t, "Continue()")
  4707  		ch1BufVar := evalVariable(p, t, "*(ch1.buf)")
  4708  		q := fmt.Sprintf("*(*%q)(%d)", ch1BufVar.DwarfType.Common().Name, ch1BufVar.Addr)
  4709  		t.Logf("%s", q)
  4710  		ch1BufVar2 := evalVariable(p, t, q)
  4711  		if ch1BufVar2.Unreadable != nil {
  4712  			t.Fatal(ch1BufVar2.Unreadable)
  4713  		}
  4714  	})
  4715  }
  4716  
  4717  func TestIssue1817(t *testing.T) {
  4718  	// Setting a breakpoint on a line that doesn't have any PC addresses marked
  4719  	// is_stmt should work.
  4720  	withTestProcess("issue1817", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  4721  		setFileBreakpoint(p, t, fixture.Source, 16)
  4722  	})
  4723  }
  4724  
  4725  func TestListPackagesBuildInfo(t *testing.T) {
  4726  	withTestProcess("pkgrenames", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  4727  		pkgs := p.BinInfo().ListPackagesBuildInfo(true)
  4728  		t.Logf("returned %d", len(pkgs))
  4729  		if len(pkgs) < 10 {
  4730  			t.Errorf("very few packages returned")
  4731  		}
  4732  		for _, pkg := range pkgs {
  4733  			t.Logf("%q %q", pkg.ImportPath, pkg.DirectoryPath)
  4734  			const _fixtures = "_fixtures"
  4735  			fidx := strings.Index(pkg.ImportPath, _fixtures)
  4736  			if fidx < 0 {
  4737  				continue
  4738  			}
  4739  			if !strings.HasSuffix(strings.ReplaceAll(pkg.DirectoryPath, "\\", "/"), pkg.ImportPath[fidx:]) {
  4740  				t.Errorf("unexpected suffix: %q %q", pkg.ImportPath, pkg.DirectoryPath)
  4741  			}
  4742  		}
  4743  	})
  4744  }
  4745  
  4746  func TestIssue1795(t *testing.T) {
  4747  	// When doing midstack inlining the Go compiler sometimes (always?) emits
  4748  	// the toplevel inlined call with ranges that do not cover the inlining of
  4749  	// other nested inlined calls.
  4750  	// For example if a function A calls B which calls C and both the calls to
  4751  	// B and C are inlined the DW_AT_inlined_subroutine entry for A might have
  4752  	// ranges that do not cover the ranges of the inlined call to C.
  4753  	// This is probably a violation of the DWARF standard (it's unclear) but we
  4754  	// might as well support it as best as possible anyway.
  4755  	if !goversion.VersionAfterOrEqual(runtime.Version(), 1, 13) {
  4756  		t.Skip("Test not relevant to Go < 1.13")
  4757  	}
  4758  	skipOn(t, "broken", "ppc64le")
  4759  	withTestProcessArgs("issue1795", t, ".", []string{}, protest.EnableInlining|protest.EnableOptimization, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  4760  		assertNoError(grp.Continue(), t, "Continue()")
  4761  		assertLineNumber(p, t, 12, "wrong line number after Continue,")
  4762  		assertNoError(grp.Next(), t, "Next()")
  4763  		assertLineNumber(p, t, 13, "wrong line number after Next,")
  4764  	})
  4765  	withTestProcessArgs("issue1795", t, ".", []string{}, protest.EnableInlining|protest.EnableOptimization, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  4766  		setFunctionBreakpoint(p, t, "regexp.(*Regexp).doExecute")
  4767  		assertNoError(grp.Continue(), t, "Continue()")
  4768  		assertLineNumber(p, t, 12, "wrong line number after Continue (1),")
  4769  		assertNoError(grp.Continue(), t, "Continue()")
  4770  		frames, err := proc.ThreadStacktrace(p, p.CurrentThread(), 40)
  4771  		assertNoError(err, t, "ThreadStacktrace()")
  4772  		logStacktrace(t, p, frames)
  4773  		if err := checkFrame(frames[0], "regexp.(*Regexp).doExecute", "", 0, false); err != nil {
  4774  			t.Errorf("Wrong frame 0: %v", err)
  4775  		}
  4776  		if err := checkFrame(frames[1], "regexp.(*Regexp).doMatch", "", 0, true); err != nil {
  4777  			t.Errorf("Wrong frame 1: %v", err)
  4778  		}
  4779  		if err := checkFrame(frames[2], "regexp.(*Regexp).MatchString", "", 0, true); err != nil {
  4780  			t.Errorf("Wrong frame 2: %v", err)
  4781  		}
  4782  		if err := checkFrame(frames[3], "main.main", fixture.Source, 12, false); err != nil {
  4783  			t.Errorf("Wrong frame 3: %v", err)
  4784  		}
  4785  	})
  4786  }
  4787  
  4788  func BenchmarkConditionalBreakpoints(b *testing.B) {
  4789  	b.N = 1
  4790  	withTestProcess("issue1549", b, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  4791  		bp := setFileBreakpoint(p, b, fixture.Source, 12)
  4792  		bp.UserBreaklet().Cond = &ast.BinaryExpr{
  4793  			Op: token.EQL,
  4794  			X:  &ast.Ident{Name: "value"},
  4795  			Y:  &ast.BasicLit{Kind: token.INT, Value: "-1"},
  4796  		}
  4797  		err := grp.Continue()
  4798  		if _, exited := err.(proc.ErrProcessExited); !exited {
  4799  			b.Fatalf("Unexpected error on Continue(): %v", err)
  4800  		}
  4801  	})
  4802  }
  4803  
  4804  func TestBackwardNextGeneral(t *testing.T) {
  4805  	if testBackend != "rr" {
  4806  		t.Skip("Reverse stepping test needs rr")
  4807  	}
  4808  	testseq2(t, "testnextprog", "main.helloworld", []seqTest{
  4809  		{contContinue, 13},
  4810  		{contNext, 14},
  4811  		{contReverseNext, 13},
  4812  		{contReverseNext, 34},
  4813  		{contReverseNext, 28},
  4814  		{contReverseNext, 27},
  4815  		{contReverseNext, 26},
  4816  		{contReverseNext, 24},
  4817  		{contReverseNext, 23},
  4818  		{contReverseNext, 31},
  4819  		{contReverseNext, 26},
  4820  		{contReverseNext, 24},
  4821  		{contReverseNext, 23},
  4822  		{contReverseNext, 31},
  4823  		{contReverseNext, 26},
  4824  		{contReverseNext, 24},
  4825  		{contReverseNext, 23},
  4826  		{contReverseNext, 20},
  4827  		{contReverseNext, 19},
  4828  		{contReverseNext, 17},
  4829  		{contReverseNext, 39},
  4830  		{contReverseNext, 38},
  4831  		{contReverseNext, 37},
  4832  	})
  4833  }
  4834  
  4835  func TestBackwardStepOutGeneral(t *testing.T) {
  4836  	if testBackend != "rr" {
  4837  		t.Skip("Reverse stepping test needs rr")
  4838  	}
  4839  	testseq2(t, "testnextprog", "main.helloworld", []seqTest{
  4840  		{contContinue, 13},
  4841  		{contNext, 14},
  4842  		{contReverseStepout, 34},
  4843  		{contReverseStepout, 39},
  4844  	})
  4845  }
  4846  
  4847  func TestBackwardStepGeneral(t *testing.T) {
  4848  	if testBackend != "rr" {
  4849  		t.Skip("Reverse stepping test needs rr")
  4850  	}
  4851  	testseq2(t, "testnextprog", "main.helloworld", []seqTest{
  4852  		{contContinue, 13},
  4853  		{contNext, 14},
  4854  		{contReverseStep, 13},
  4855  		{contReverseStep, 34},
  4856  		{contReverseStep, 28},
  4857  		{contReverseNext, 27}, // skip fmt.Printf
  4858  		{contReverseStep, 26},
  4859  		{contReverseStep, 24},
  4860  		{contReverseStep, 23},
  4861  		{contReverseStep, 11},
  4862  		{contReverseNext, 10}, // skip time.Sleep
  4863  		{contReverseStep, 9},
  4864  
  4865  		{contReverseStep, 31},
  4866  		{contReverseStep, 26},
  4867  		{contReverseStep, 24},
  4868  		{contReverseStep, 23},
  4869  		{contReverseStep, 11},
  4870  		{contReverseNext, 10}, // skip time.Sleep
  4871  		{contReverseStep, 9},
  4872  
  4873  		{contReverseStep, 31},
  4874  		{contReverseStep, 26},
  4875  		{contReverseStep, 24},
  4876  		{contReverseStep, 23},
  4877  		{contReverseStep, 20},
  4878  		{contReverseStep, 19},
  4879  		{contReverseStep, 17},
  4880  		{contReverseStep, 39},
  4881  		{contReverseStep, 38},
  4882  		{contReverseStep, 37},
  4883  	})
  4884  }
  4885  
  4886  func TestBackwardNextDeferPanic(t *testing.T) {
  4887  	if testBackend != "rr" {
  4888  		t.Skip("Reverse stepping test needs rr")
  4889  	}
  4890  	if goversion.VersionAfterOrEqual(runtime.Version(), 1, 18) {
  4891  		testseq2(t, "defercall", "", []seqTest{
  4892  			{contContinue, 12},
  4893  			{contReverseNext, 11},
  4894  			{contReverseNext, 10},
  4895  			{contReverseNext, 9},
  4896  			{contReverseNext, 27},
  4897  
  4898  			{contContinueToBreakpoint, 12}, // skip first call to sampleFunction
  4899  			{contContinueToBreakpoint, 6},  // go to call to sampleFunction through deferreturn
  4900  			{contReverseNext, -1},          // runtime.deferreturn, maybe we should try to skip this
  4901  			{contReverseStepout, 13},
  4902  			{contReverseNext, 12},
  4903  			{contReverseNext, 11},
  4904  			{contReverseNext, 10},
  4905  			{contReverseNext, 9},
  4906  			{contReverseNext, 27},
  4907  
  4908  			{contContinueToBreakpoint, 18}, // go to panic call
  4909  			{contNext, 6},                  // panic so the deferred call happens
  4910  			{contReverseNext, 18},
  4911  			{contReverseNext, 17},
  4912  			{contReverseNext, 16},
  4913  			{contReverseNext, 15},
  4914  			{contReverseNext, 23},
  4915  			{contReverseNext, 22},
  4916  			{contReverseNext, 21},
  4917  			{contReverseNext, 28},
  4918  		})
  4919  	} else {
  4920  		testseq2(t, "defercall", "", []seqTest{
  4921  			{contContinue, 12},
  4922  			{contReverseNext, 11},
  4923  			{contReverseNext, 10},
  4924  			{contReverseNext, 9},
  4925  			{contReverseNext, 27},
  4926  
  4927  			{contContinueToBreakpoint, 12}, // skip first call to sampleFunction
  4928  			{contContinueToBreakpoint, 6},  // go to call to sampleFunction through deferreturn
  4929  			{contReverseNext, 13},
  4930  			{contReverseNext, 12},
  4931  			{contReverseNext, 11},
  4932  			{contReverseNext, 10},
  4933  			{contReverseNext, 9},
  4934  			{contReverseNext, 27},
  4935  
  4936  			{contContinueToBreakpoint, 18}, // go to panic call
  4937  			{contNext, 6},                  // panic so the deferred call happens
  4938  			{contReverseNext, 18},
  4939  			{contReverseNext, 17},
  4940  			{contReverseNext, 16},
  4941  			{contReverseNext, 15},
  4942  			{contReverseNext, 23},
  4943  			{contReverseNext, 22},
  4944  			{contReverseNext, 21},
  4945  			{contReverseNext, 28},
  4946  		})
  4947  	}
  4948  }
  4949  
  4950  func TestIssue1925(t *testing.T) {
  4951  	// Calling a function should not leave cached goroutine information in an
  4952  	// inconsistent state.
  4953  	// In particular the stepInstructionOut function called at the end of a
  4954  	// 'call' procedure should clean the G cache like every other function
  4955  	// altering the state of the target process.
  4956  	skipOn(t, "broken - pie mode", "linux", "ppc64le", "native", "pie")
  4957  	protest.MustSupportFunctionCalls(t, testBackend)
  4958  	withTestProcess("testvariables2", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  4959  		assertNoError(grp.Continue(), t, "Continue()")
  4960  		assertNoError(proc.EvalExpressionWithCalls(grp, p.SelectedGoroutine(), "afunc(2)", normalLoadConfig, true), t, "Call")
  4961  		t.Logf("%v\n", p.SelectedGoroutine().CurrentLoc)
  4962  		if loc := p.SelectedGoroutine().CurrentLoc; loc.File != fixture.Source {
  4963  			t.Errorf("wrong location for selected goroutine after call: %s:%d", loc.File, loc.Line)
  4964  		}
  4965  	})
  4966  }
  4967  
  4968  func TestStepIntoWrapperForEmbeddedPointer(t *testing.T) {
  4969  	skipOn(t, "N/A", "linux", "386", "pie") // skipping wrappers doesn't work on linux/386/PIE due to the use of get_pc_thunk
  4970  	// Under some circumstances (when using an interface to call a method on an
  4971  	// embedded field, see _fixtures/ifaceembcall.go) the compiler will
  4972  	// autogenerate a wrapper function that uses a tail call (i.e. it ends in
  4973  	// an unconditional jump instruction to a different function).
  4974  	// Delve should be able to step into this tail call.
  4975  	testseq2(t, "ifaceembcall", "", []seqTest{
  4976  		{contContinue, 28}, // main.main, the line calling iface.PtrReceiver()
  4977  		{contStep, 18},     // main.(*A).PtrReceiver
  4978  		{contStep, 19},
  4979  		{contStepout, 28},
  4980  		{contContinueToBreakpoint, 29}, // main.main, the line calling iface.NonPtrReceiver()
  4981  		{contStep, 22},                 // main.(A).NonPtrReceiver
  4982  		{contStep, 23},
  4983  		{contStepout, 29}})
  4984  
  4985  	// same test but with next instead of stepout
  4986  	if goversion.VersionAfterOrEqual(runtime.Version(), 1, 14) && runtime.GOARCH != "386" && !goversion.VersionAfterOrEqualRev(runtime.Version(), 1, 15, 4) {
  4987  		// Line numbers generated for versions 1.14 through 1.15.3 on any system except linux/386
  4988  		testseq2(t, "ifaceembcall", "", []seqTest{
  4989  			{contContinue, 28}, // main.main, the line calling iface.PtrReceiver()
  4990  			{contStep, 18},     // main.(*A).PtrReceiver
  4991  			{contNext, 19},
  4992  			{contNext, 19},
  4993  			{contNext, 28},
  4994  			{contContinueToBreakpoint, 29}, // main.main, the line calling iface.NonPtrReceiver()
  4995  			{contStep, 22},
  4996  			{contNext, 23},
  4997  			{contNext, 23},
  4998  			{contNext, 29}})
  4999  	} else {
  5000  		testseq2(t, "ifaceembcall", "", []seqTest{
  5001  			{contContinue, 28}, // main.main, the line calling iface.PtrReceiver()
  5002  			{contStep, 18},     // main.(*A).PtrReceiver
  5003  			{contNext, 19},
  5004  			{contNext, 28},
  5005  			{contContinueToBreakpoint, 29}, // main.main, the line calling iface.NonPtrReceiver()
  5006  			{contStep, 22},
  5007  			{contNext, 23},
  5008  			{contNext, 29}})
  5009  
  5010  	}
  5011  }
  5012  
  5013  func TestStepoutOneliner(t *testing.T) {
  5014  	// The heuristic detecting autogenerated wrappers when stepping out should
  5015  	// not skip oneliner functions.
  5016  	withTestProcess("issue2086", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  5017  		assertNoError(grp.Continue(), t, "Continue()")
  5018  		assertLineNumber(p, t, 15, "after first continue")
  5019  		assertNoError(grp.StepOut(), t, "StepOut()")
  5020  		if fn := p.BinInfo().PCToFunc(currentPC(p, t)); fn == nil || fn.Name != "main.T.m" {
  5021  			t.Fatalf("wrong function after stepout %#v", fn)
  5022  		}
  5023  		assertNoError(grp.StepOut(), t, "second StepOut()")
  5024  		if fn := p.BinInfo().PCToFunc(currentPC(p, t)); fn == nil || fn.Name != "main.main" {
  5025  			t.Fatalf("wrong fnuction after second stepout %#v", fn)
  5026  		}
  5027  	})
  5028  }
  5029  
  5030  func TestRequestManualStopWhileStopped(t *testing.T) {
  5031  	// Requesting a manual stop while stopped shouldn't cause problems (issue #2138).
  5032  	withTestProcess("issue2138", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  5033  		resumed := make(chan struct{})
  5034  		setFileBreakpoint(p, t, fixture.Source, 8)
  5035  		assertNoError(grp.Continue(), t, "Continue() 1")
  5036  		grp.ResumeNotify(resumed)
  5037  		go func() {
  5038  			<-resumed
  5039  			time.Sleep(1 * time.Second)
  5040  			grp.RequestManualStop()
  5041  		}()
  5042  		t.Logf("at time.Sleep call")
  5043  		assertNoError(grp.Continue(), t, "Continue() 2")
  5044  		t.Logf("manually stopped")
  5045  		grp.RequestManualStop()
  5046  		grp.RequestManualStop()
  5047  		grp.RequestManualStop()
  5048  
  5049  		resumed = make(chan struct{})
  5050  		grp.ResumeNotify(resumed)
  5051  		go func() {
  5052  			<-resumed
  5053  			time.Sleep(1 * time.Second)
  5054  			grp.RequestManualStop()
  5055  		}()
  5056  		t.Logf("resuming sleep")
  5057  		assertNoError(grp.Continue(), t, "Continue() 3")
  5058  		t.Logf("done")
  5059  	})
  5060  }
  5061  
  5062  func TestStepOutPreservesGoroutine(t *testing.T) {
  5063  	// Checks that StepOut preserves the currently selected goroutine.
  5064  	rand.Seed(time.Now().Unix())
  5065  	withTestProcess("issue2113", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  5066  		assertNoError(grp.Continue(), t, "Continue()")
  5067  
  5068  		logState := func() {
  5069  			g := p.SelectedGoroutine()
  5070  			var goid int64 = -42
  5071  			if g != nil {
  5072  				goid = g.ID
  5073  			}
  5074  			pc := currentPC(p, t)
  5075  			f, l, fn := p.BinInfo().PCToLine(pc)
  5076  			var fnname = "???"
  5077  			if fn != nil {
  5078  				fnname = fn.Name
  5079  			}
  5080  			t.Logf("goroutine %d at %s:%d in %s", goid, f, l, fnname)
  5081  		}
  5082  
  5083  		logState()
  5084  
  5085  		gs, _, err := proc.GoroutinesInfo(p, 0, 0)
  5086  		assertNoError(err, t, "GoroutinesInfo")
  5087  		candg := []*proc.G{}
  5088  		bestg := []*proc.G{}
  5089  		for _, g := range gs {
  5090  			t.Logf("stacktracing goroutine %d (%v)\n", g.ID, g.CurrentLoc)
  5091  			frames, err := proc.GoroutineStacktrace(p, g, 20, 0)
  5092  			assertNoError(err, t, "Stacktrace")
  5093  			for _, frame := range frames {
  5094  				if frame.Call.Fn != nil && frame.Call.Fn.Name == "main.coroutine" {
  5095  					candg = append(candg, g)
  5096  					if g.Thread != nil && frames[0].Call.Fn != nil && strings.HasPrefix(frames[0].Call.Fn.Name, "runtime.") {
  5097  						bestg = append(bestg, g)
  5098  					}
  5099  					break
  5100  				}
  5101  			}
  5102  		}
  5103  		var pickg *proc.G
  5104  		if len(bestg) > 0 {
  5105  			pickg = bestg[rand.Intn(len(bestg))]
  5106  			t.Logf("selected goroutine %d (best)\n", pickg.ID)
  5107  		} else {
  5108  			pickg = candg[rand.Intn(len(candg))]
  5109  			t.Logf("selected goroutine %d\n", pickg.ID)
  5110  
  5111  		}
  5112  		goid := pickg.ID
  5113  		assertNoError(p.SwitchGoroutine(pickg), t, "SwitchGoroutine")
  5114  
  5115  		logState()
  5116  
  5117  		err = grp.StepOut()
  5118  		if err != nil {
  5119  			_, isexited := err.(proc.ErrProcessExited)
  5120  			if !isexited {
  5121  				assertNoError(err, t, "StepOut()")
  5122  			} else {
  5123  				return
  5124  			}
  5125  		}
  5126  
  5127  		logState()
  5128  
  5129  		g2 := p.SelectedGoroutine()
  5130  		if g2 == nil {
  5131  			t.Fatalf("no selected goroutine after stepout")
  5132  		} else if g2.ID != goid {
  5133  			t.Fatalf("unexpected selected goroutine %d", g2.ID)
  5134  		}
  5135  	})
  5136  }
  5137  
  5138  func TestIssue2319(t *testing.T) {
  5139  	// Check to make sure we don't crash on startup when the target is
  5140  	// a binary with a mix of DWARF-5 C++ compilation units and
  5141  	// DWARF-4 Go compilation units.
  5142  
  5143  	// Require CGO, since we need to use the external linker for this test.
  5144  	protest.MustHaveCgo(t)
  5145  
  5146  	// The test fixture uses linux/amd64 assembly and a *.syso file
  5147  	// that is linux/amd64, so skip for other architectures.
  5148  	if runtime.GOOS != "linux" || runtime.GOARCH != "amd64" {
  5149  		t.Skipf("skipping since not linux/amd64")
  5150  	}
  5151  
  5152  	// Skip unless on 1.14 or later. The test fixture uses a *.syso
  5153  	// file, which in 1.13 is not loaded unless we're in internal
  5154  	// linking mode (we need external linking here).
  5155  	if !goversion.VersionAfterOrEqual(runtime.Version(), 1, 14) {
  5156  		t.Skip("test contains fixture that is specific to go 1.14+")
  5157  	}
  5158  
  5159  	fixture := protest.BuildFixture("issue2319/", protest.BuildModeExternalLinker)
  5160  
  5161  	// Load up the binary and make sure there are no crashes.
  5162  	bi := proc.NewBinaryInfo("linux", "amd64")
  5163  	assertNoError(bi.LoadBinaryInfo(fixture.Path, 0, nil), t, "LoadBinaryInfo")
  5164  }
  5165  
  5166  func TestDump(t *testing.T) {
  5167  	if (runtime.GOOS == "darwin" && testBackend == "native") || (runtime.GOOS == "windows" && runtime.GOARCH != "amd64") {
  5168  		t.Skip("not supported")
  5169  	}
  5170  	skipOn(t, "not implemented", "ppc64le")
  5171  
  5172  	convertRegisters := func(arch *proc.Arch, dregs op.DwarfRegisters) string {
  5173  		dregs.Reg(^uint64(0))
  5174  		buf := new(bytes.Buffer)
  5175  		for i := 0; i < dregs.CurrentSize(); i++ {
  5176  			reg := dregs.Reg(uint64(i))
  5177  			if reg == nil {
  5178  				continue
  5179  			}
  5180  			name, _, repr := arch.DwarfRegisterToString(i, reg)
  5181  			fmt.Fprintf(buf, " %s=%s", name, repr)
  5182  		}
  5183  		return buf.String()
  5184  	}
  5185  
  5186  	convertThread := func(thread proc.Thread) string {
  5187  		regs, err := thread.Registers()
  5188  		assertNoError(err, t, fmt.Sprintf("Thread registers %d", thread.ThreadID()))
  5189  		arch := thread.BinInfo().Arch
  5190  		dregs := arch.RegistersToDwarfRegisters(0, regs)
  5191  		return fmt.Sprintf("%08d %s", thread.ThreadID(), convertRegisters(arch, *dregs))
  5192  	}
  5193  
  5194  	convertThreads := func(threads []proc.Thread) []string {
  5195  		r := make([]string, len(threads))
  5196  		for i := range threads {
  5197  			r[i] = convertThread(threads[i])
  5198  		}
  5199  		sort.Strings(r)
  5200  		return r
  5201  	}
  5202  
  5203  	convertGoroutine := func(g *proc.G) string {
  5204  		threadID := 0
  5205  		if g.Thread != nil {
  5206  			threadID = g.Thread.ThreadID()
  5207  		}
  5208  		return fmt.Sprintf("%d pc=%#x sp=%#x bp=%#x lr=%#x gopc=%#x startpc=%#x systemstack=%v thread=%d", g.ID, g.PC, g.SP, g.BP, g.LR, g.GoPC, g.StartPC, g.SystemStack, threadID)
  5209  	}
  5210  
  5211  	convertFrame := func(arch *proc.Arch, frame *proc.Stackframe) string {
  5212  		return fmt.Sprintf("currentPC=%#x callPC=%#x frameOff=%#x\n", frame.Current.PC, frame.Call.PC, frame.FrameOffset())
  5213  	}
  5214  
  5215  	makeDump := func(p *proc.Target, corePath, exePath string, flags proc.DumpFlags) *proc.Target {
  5216  		fh, err := os.Create(corePath)
  5217  		assertNoError(err, t, "Create()")
  5218  		var state proc.DumpState
  5219  		p.Dump(fh, flags, &state)
  5220  		assertNoError(state.Err, t, "Dump()")
  5221  		if state.ThreadsDone != state.ThreadsTotal || state.MemDone != state.MemTotal || !state.AllDone || state.Dumping || state.Canceled {
  5222  			t.Fatalf("bad DumpState %#v", &state)
  5223  		}
  5224  		c, err := core.OpenCore(corePath, exePath, nil)
  5225  		assertNoError(err, t, "OpenCore()")
  5226  		return c.Selected
  5227  	}
  5228  
  5229  	testDump := func(p, c *proc.Target) {
  5230  		if p.Pid() != c.Pid() {
  5231  			t.Errorf("Pid mismatch %x %x", p.Pid(), c.Pid())
  5232  		}
  5233  
  5234  		threads := convertThreads(p.ThreadList())
  5235  		cthreads := convertThreads(c.ThreadList())
  5236  
  5237  		if len(threads) != len(cthreads) {
  5238  			t.Errorf("Thread number mismatch %d %d", len(threads), len(cthreads))
  5239  		}
  5240  
  5241  		for i := range threads {
  5242  			if threads[i] != cthreads[i] {
  5243  				t.Errorf("Thread mismatch\nlive:\t%s\ncore:\t%s", threads[i], cthreads[i])
  5244  			}
  5245  		}
  5246  
  5247  		gos, _, err := proc.GoroutinesInfo(p, 0, 0)
  5248  		assertNoError(err, t, "GoroutinesInfo() - live process")
  5249  		cgos, _, err := proc.GoroutinesInfo(c, 0, 0)
  5250  		assertNoError(err, t, "GoroutinesInfo() - core dump")
  5251  
  5252  		if len(gos) != len(cgos) {
  5253  			t.Errorf("Goroutine number mismatch %d %d", len(gos), len(cgos))
  5254  		}
  5255  
  5256  		var scope, cscope *proc.EvalScope
  5257  
  5258  		for i := range gos {
  5259  			if convertGoroutine(gos[i]) != convertGoroutine(cgos[i]) {
  5260  				t.Errorf("Goroutine mismatch\nlive:\t%s\ncore:\t%s", convertGoroutine(gos[i]), convertGoroutine(cgos[i]))
  5261  			}
  5262  
  5263  			frames, err := proc.GoroutineStacktrace(p, gos[i], 20, 0)
  5264  			assertNoError(err, t, fmt.Sprintf("Stacktrace for goroutine %d - live process", gos[i].ID))
  5265  			cframes, err := proc.GoroutineStacktrace(c, cgos[i], 20, 0)
  5266  			assertNoError(err, t, fmt.Sprintf("Stacktrace for goroutine %d - core dump", gos[i].ID))
  5267  
  5268  			if len(frames) != len(cframes) {
  5269  				t.Errorf("Frame number mismatch for goroutine %d: %d %d", gos[i].ID, len(frames), len(cframes))
  5270  			}
  5271  
  5272  			for j := range frames {
  5273  				if convertFrame(p.BinInfo().Arch, &frames[j]) != convertFrame(p.BinInfo().Arch, &cframes[j]) {
  5274  					t.Errorf("Frame mismatch %d.%d\nlive:\t%s\ncore:\t%s", gos[i].ID, j, convertFrame(p.BinInfo().Arch, &frames[j]), convertFrame(p.BinInfo().Arch, &cframes[j]))
  5275  				}
  5276  				if frames[j].Call.Fn != nil && frames[j].Call.Fn.Name == "main.main" {
  5277  					scope = proc.FrameToScope(p, p.Memory(), gos[i], 0, frames[j:]...)
  5278  					cscope = proc.FrameToScope(c, c.Memory(), cgos[i], 0, cframes[j:]...)
  5279  				}
  5280  			}
  5281  		}
  5282  
  5283  		vars, err := scope.LocalVariables(normalLoadConfig)
  5284  		assertNoError(err, t, "LocalVariables - live process")
  5285  		cvars, err := cscope.LocalVariables(normalLoadConfig)
  5286  		assertNoError(err, t, "LocalVariables - core dump")
  5287  
  5288  		if len(vars) != len(cvars) {
  5289  			t.Errorf("Variable number mismatch %d %d", len(vars), len(cvars))
  5290  		}
  5291  
  5292  		for i := range vars {
  5293  			varstr := vars[i].Name + "=" + api.ConvertVar(vars[i]).SinglelineString()
  5294  			cvarstr := cvars[i].Name + "=" + api.ConvertVar(cvars[i]).SinglelineString()
  5295  			if strings.Contains(varstr, "(unreadable") {
  5296  				// errors reading from unmapped memory differ between live process and core
  5297  				continue
  5298  			}
  5299  			if varstr != cvarstr {
  5300  				t.Errorf("Variable mismatch %s %s", varstr, cvarstr)
  5301  			}
  5302  		}
  5303  	}
  5304  
  5305  	withTestProcess("testvariables2", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  5306  		assertNoError(grp.Continue(), t, "Continue()")
  5307  		corePath := filepath.Join(fixture.BuildDir, "coredump")
  5308  		corePathPlatIndep := filepath.Join(fixture.BuildDir, "coredump-indep")
  5309  
  5310  		t.Logf("testing normal dump")
  5311  
  5312  		c := makeDump(p, corePath, fixture.Path, 0)
  5313  		defer os.Remove(corePath)
  5314  		testDump(p, c)
  5315  
  5316  		if runtime.GOOS == "linux" && runtime.GOARCH == "amd64" {
  5317  			// No reason to do this test on other goos/goarch because they use the
  5318  			// platform-independent format anyway.
  5319  			t.Logf("testing platform-independent dump")
  5320  			c2 := makeDump(p, corePathPlatIndep, fixture.Path, proc.DumpPlatformIndependent)
  5321  			defer os.Remove(corePathPlatIndep)
  5322  			testDump(p, c2)
  5323  		}
  5324  	})
  5325  }
  5326  
  5327  func TestCompositeMemoryWrite(t *testing.T) {
  5328  	if runtime.GOARCH != "amd64" {
  5329  		t.Skip("only valid on amd64")
  5330  	}
  5331  	skipOn(t, "not implemented", "freebsd")
  5332  	withTestProcess("fputest/", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  5333  		getregs := func() (pc, rax, xmm1 uint64) {
  5334  			regs, err := p.CurrentThread().Registers()
  5335  			assertNoError(err, t, "Registers")
  5336  			fmtregs, err := regs.Slice(true)
  5337  			assertNoError(err, t, "register slice")
  5338  
  5339  			var xmm1buf []byte
  5340  
  5341  			for _, reg := range fmtregs {
  5342  				switch strings.ToLower(reg.Name) {
  5343  				case "rax":
  5344  					rax = reg.Reg.Uint64Val
  5345  				case "xmm1":
  5346  					xmm1buf = reg.Reg.Bytes
  5347  				}
  5348  			}
  5349  
  5350  			xmm1 = binary.LittleEndian.Uint64(xmm1buf[:8])
  5351  
  5352  			return regs.PC(), rax, xmm1
  5353  		}
  5354  
  5355  		const fakeAddress = 0xbeef0000
  5356  
  5357  		getmem := func(mem proc.MemoryReader) uint64 {
  5358  			buf := make([]byte, 8)
  5359  			_, err := mem.ReadMemory(buf, fakeAddress)
  5360  			assertNoError(err, t, "ReadMemory")
  5361  			return binary.LittleEndian.Uint64(buf)
  5362  		}
  5363  
  5364  		assertNoError(grp.Continue(), t, "Continue()")
  5365  		oldPc, oldRax, oldXmm1 := getregs()
  5366  		t.Logf("PC %#x AX %#x XMM1 %#x", oldPc, oldRax, oldXmm1)
  5367  
  5368  		memRax, err := proc.NewCompositeMemory(p, []op.Piece{{Size: 0, Val: 0, Kind: op.RegPiece}}, fakeAddress)
  5369  		assertNoError(err, t, "NewCompositeMemory (rax)")
  5370  		memXmm1, err := proc.NewCompositeMemory(p, []op.Piece{{Size: 0, Val: 18, Kind: op.RegPiece}}, fakeAddress)
  5371  		assertNoError(err, t, "NewCompositeMemory (xmm1)")
  5372  
  5373  		if memRax := getmem(memRax); memRax != oldRax {
  5374  			t.Errorf("reading rax memory, expected %#x got %#x", oldRax, memRax)
  5375  		}
  5376  		if memXmm1 := getmem(memXmm1); memXmm1 != oldXmm1 {
  5377  			t.Errorf("reading xmm1 memory, expected %#x got %#x", oldXmm1, memXmm1)
  5378  		}
  5379  
  5380  		_, err = memRax.WriteMemory(0xbeef0000, []byte{0xef, 0xbe, 0x0d, 0xf0, 0xef, 0xbe, 0x0d, 0xf0})
  5381  		assertNoError(err, t, "WriteMemory (rax)")
  5382  		_, err = memXmm1.WriteMemory(0xbeef0000, []byte{0xef, 0xbe, 0x0d, 0xf0, 0xef, 0xbe, 0x0d, 0xf0})
  5383  		assertNoError(err, t, "WriteMemory (xmm1)")
  5384  
  5385  		newPc, newRax, newXmm1 := getregs()
  5386  		t.Logf("PC %#x AX %#x XMM1 %#x", newPc, newRax, newXmm1)
  5387  
  5388  		const tgt = 0xf00dbeeff00dbeef
  5389  		if newRax != tgt {
  5390  			t.Errorf("reading rax register, expected %#x, got %#x", uint64(tgt), newRax)
  5391  		}
  5392  		if newXmm1 != tgt {
  5393  			t.Errorf("reading xmm1 register, expected %#x, got %#x", uint64(tgt), newXmm1)
  5394  		}
  5395  	})
  5396  }
  5397  
  5398  func TestVariablesWithExternalLinking(t *testing.T) {
  5399  	protest.MustHaveCgo(t)
  5400  	// Tests that macOSDebugFrameBugWorkaround works.
  5401  	// See:
  5402  	//  https://github.com/golang/go/issues/25841
  5403  	//  https://gitlab.com/Raven-IO/raven-delve/issues/2346
  5404  	withTestProcessArgs("testvariables2", t, ".", []string{}, protest.BuildModeExternalLinker, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  5405  		assertNoError(grp.Continue(), t, "Continue()")
  5406  		str1Var := evalVariable(p, t, "str1")
  5407  		if str1Var.Unreadable != nil {
  5408  			t.Fatalf("variable str1 is unreadable: %v", str1Var.Unreadable)
  5409  		}
  5410  		t.Logf("%#v", str1Var)
  5411  		if constant.StringVal(str1Var.Value) != "01234567890" {
  5412  			t.Fatalf("wrong value for str1: %v", str1Var.Value)
  5413  		}
  5414  	})
  5415  }
  5416  
  5417  func TestWatchpointsBasic(t *testing.T) {
  5418  	skipOn(t, "not implemented", "freebsd")
  5419  	skipOn(t, "not implemented", "386")
  5420  	skipOn(t, "not implemented", "ppc64le")
  5421  	skipOn(t, "see https://gitlab.com/Raven-IO/raven-delve/issues/2768", "windows")
  5422  	protest.AllowRecording(t)
  5423  
  5424  	position1 := 19
  5425  	position5 := 41
  5426  
  5427  	if runtime.GOARCH == "arm64" {
  5428  		position1 = 18
  5429  		position5 = 40
  5430  	}
  5431  
  5432  	withTestProcess("databpeasy", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  5433  		setFunctionBreakpoint(p, t, "main.main")
  5434  		setFileBreakpoint(p, t, fixture.Source, 21) // Position 2 breakpoint
  5435  		setFileBreakpoint(p, t, fixture.Source, 27) // Position 4 breakpoint
  5436  		assertNoError(grp.Continue(), t, "Continue 0")
  5437  		assertLineNumber(p, t, 13, "Continue 0") // Position 0
  5438  
  5439  		scope, err := proc.GoroutineScope(p, p.CurrentThread())
  5440  		assertNoError(err, t, "GoroutineScope")
  5441  
  5442  		bp, err := p.SetWatchpoint(0, scope, "globalvar1", proc.WatchWrite, nil)
  5443  		assertNoError(err, t, "SetDataBreakpoint(write-only)")
  5444  
  5445  		assertNoError(grp.Continue(), t, "Continue 1")
  5446  		assertLineNumber(p, t, position1, "Continue 1") // Position 1
  5447  
  5448  		if curbp := p.CurrentThread().Breakpoint().Breakpoint; curbp == nil || (curbp.LogicalID() != bp.LogicalID()) {
  5449  			t.Fatal("breakpoint not set")
  5450  		}
  5451  
  5452  		assertNoError(p.ClearBreakpoint(bp.Addr), t, "ClearBreakpoint")
  5453  
  5454  		assertNoError(grp.Continue(), t, "Continue 2")
  5455  		assertLineNumber(p, t, 21, "Continue 2") // Position 2
  5456  
  5457  		_, err = p.SetWatchpoint(0, scope, "globalvar1", proc.WatchWrite|proc.WatchRead, nil)
  5458  		assertNoError(err, t, "SetDataBreakpoint(read-write)")
  5459  
  5460  		assertNoError(grp.Continue(), t, "Continue 3")
  5461  		assertLineNumber(p, t, 22, "Continue 3") // Position 3
  5462  
  5463  		p.ClearBreakpoint(bp.Addr)
  5464  
  5465  		assertNoError(grp.Continue(), t, "Continue 4")
  5466  		assertLineNumber(p, t, 27, "Continue 4") // Position 4
  5467  
  5468  		t.Logf("setting final breakpoint")
  5469  		_, err = p.SetWatchpoint(0, scope, "globalvar1", proc.WatchWrite, nil)
  5470  		assertNoError(err, t, "SetDataBreakpoint(write-only, again)")
  5471  
  5472  		assertNoError(grp.Continue(), t, "Continue 5")
  5473  		assertLineNumber(p, t, position5, "Continue 5") // Position 5
  5474  	})
  5475  }
  5476  
  5477  func TestWatchpointCounts(t *testing.T) {
  5478  	skipOn(t, "not implemented", "freebsd")
  5479  	skipOn(t, "not implemented", "386")
  5480  	skipOn(t, "see https://gitlab.com/Raven-IO/raven-delve/issues/2768", "windows")
  5481  	skipOn(t, "not implemented", "ppc64le")
  5482  	protest.AllowRecording(t)
  5483  
  5484  	withTestProcess("databpcountstest", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  5485  		setFunctionBreakpoint(p, t, "main.main")
  5486  		assertNoError(grp.Continue(), t, "Continue 0")
  5487  
  5488  		scope, err := proc.GoroutineScope(p, p.CurrentThread())
  5489  		assertNoError(err, t, "GoroutineScope")
  5490  
  5491  		bp, err := p.SetWatchpoint(0, scope, "globalvar1", proc.WatchWrite, nil)
  5492  		assertNoError(err, t, "SetWatchpoint(write-only)")
  5493  
  5494  		for {
  5495  			if err := grp.Continue(); err != nil {
  5496  				if _, exited := err.(proc.ErrProcessExited); exited {
  5497  					break
  5498  				}
  5499  				assertNoError(err, t, "Continue()")
  5500  			}
  5501  		}
  5502  
  5503  		t.Logf("TotalHitCount: %d", bp.Logical.TotalHitCount)
  5504  		if bp.Logical.TotalHitCount != 200 {
  5505  			t.Fatalf("Wrong TotalHitCount for the breakpoint (%d)", bp.Logical.TotalHitCount)
  5506  		}
  5507  
  5508  		if len(bp.Logical.HitCount) != 2 {
  5509  			t.Fatalf("Wrong number of goroutines for breakpoint (%d)", len(bp.Logical.HitCount))
  5510  		}
  5511  
  5512  		for _, v := range bp.Logical.HitCount {
  5513  			if v != 100 {
  5514  				t.Fatalf("Wrong HitCount for breakpoint (%v)", bp.Logical.HitCount)
  5515  			}
  5516  		}
  5517  	})
  5518  }
  5519  
  5520  func TestManualStopWhileStopped(t *testing.T) {
  5521  	// Checks that RequestManualStop sent to a stopped thread does not cause the target process to die.
  5522  	withTestProcess("loopprog", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  5523  		asyncCont := func(done chan struct{}) {
  5524  			defer close(done)
  5525  			err := grp.Continue()
  5526  			t.Logf("%v\n", err)
  5527  			if err != nil {
  5528  				panic(err)
  5529  			}
  5530  			for _, th := range p.ThreadList() {
  5531  				if th.Breakpoint().Breakpoint != nil {
  5532  					t.Logf("unexpected stop at breakpoint: %v", th.Breakpoint().Breakpoint)
  5533  					panic("unexpected stop at breakpoint")
  5534  				}
  5535  			}
  5536  		}
  5537  
  5538  		const (
  5539  			repeatsSlow = 3
  5540  			repeatsFast = 5
  5541  		)
  5542  
  5543  		for i := 0; i < repeatsSlow; i++ {
  5544  			t.Logf("Continue %d (slow)", i)
  5545  			done := make(chan struct{})
  5546  			go asyncCont(done)
  5547  			time.Sleep(1 * time.Second)
  5548  			grp.RequestManualStop()
  5549  			time.Sleep(1 * time.Second)
  5550  			grp.RequestManualStop()
  5551  			time.Sleep(1 * time.Second)
  5552  			<-done
  5553  		}
  5554  		for i := 0; i < repeatsFast; i++ {
  5555  			t.Logf("Continue %d (fast)", i)
  5556  			rch := make(chan struct{})
  5557  			done := make(chan struct{})
  5558  			grp.ResumeNotify(rch)
  5559  			go asyncCont(done)
  5560  			<-rch
  5561  			grp.RequestManualStop()
  5562  			grp.RequestManualStop()
  5563  			<-done
  5564  		}
  5565  	})
  5566  }
  5567  
  5568  func TestDwrapStartLocation(t *testing.T) {
  5569  	// Tests that the start location of a goroutine is unwrapped in Go 1.17 and later.
  5570  	withTestProcess("goroutinestackprog", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  5571  		setFunctionBreakpoint(p, t, "main.stacktraceme")
  5572  		assertNoError(grp.Continue(), t, "Continue()")
  5573  		gs, _, err := proc.GoroutinesInfo(p, 0, 0)
  5574  		assertNoError(err, t, "GoroutinesInfo")
  5575  		found := false
  5576  		for _, g := range gs {
  5577  			startLoc := g.StartLoc(p)
  5578  			if startLoc.Fn == nil {
  5579  				continue
  5580  			}
  5581  			t.Logf("%#v\n", startLoc.Fn.Name)
  5582  			if startLoc.Fn.Name == "main.agoroutine" {
  5583  				found = true
  5584  				break
  5585  			}
  5586  		}
  5587  		if !found {
  5588  			t.Errorf("could not find any goroutine with a start location of main.agoroutine")
  5589  		}
  5590  	})
  5591  }
  5592  
  5593  func TestWatchpointStack(t *testing.T) {
  5594  	skipOn(t, "not implemented", "freebsd")
  5595  	skipOn(t, "not implemented", "386")
  5596  	skipOn(t, "not implemented", "ppc64le")
  5597  	skipOn(t, "see https://gitlab.com/Raven-IO/raven-delve/issues/2768", "windows")
  5598  	protest.AllowRecording(t)
  5599  
  5600  	position1 := 17
  5601  
  5602  	if runtime.GOARCH == "arm64" {
  5603  		position1 = 16
  5604  	}
  5605  
  5606  	withTestProcess("databpstack", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  5607  		setFileBreakpoint(p, t, fixture.Source, 11) // Position 0 breakpoint
  5608  		clearlen := len(p.Breakpoints().M)
  5609  
  5610  		assertNoError(grp.Continue(), t, "Continue 0")
  5611  		assertLineNumber(p, t, 11, "Continue 0") // Position 0
  5612  
  5613  		scope, err := proc.GoroutineScope(p, p.CurrentThread())
  5614  		assertNoError(err, t, "GoroutineScope")
  5615  
  5616  		_, err = p.SetWatchpoint(0, scope, "w", proc.WatchWrite, nil)
  5617  		assertNoError(err, t, "SetDataBreakpoint(write-only)")
  5618  
  5619  		watchbpnum := 3
  5620  		if recorded, _ := grp.Recorded(); recorded {
  5621  			watchbpnum = 4
  5622  		}
  5623  
  5624  		if len(p.Breakpoints().M) != clearlen+watchbpnum {
  5625  			// want 1 watchpoint, 1 stack resize breakpoint, 1 out of scope sentinel (2 if recorded)
  5626  			t.Errorf("wrong number of breakpoints after setting watchpoint: %d", len(p.Breakpoints().M)-clearlen)
  5627  		}
  5628  
  5629  		var retaddr uint64
  5630  		for _, bp := range p.Breakpoints().M {
  5631  			for _, breaklet := range bp.Breaklets {
  5632  				if breaklet.Kind&proc.WatchOutOfScopeBreakpoint != 0 {
  5633  					retaddr = bp.Addr
  5634  					break
  5635  				}
  5636  			}
  5637  		}
  5638  
  5639  		// Note: for recorded processes retaddr will not always be the return
  5640  		// address, ~50% of the times it will be the address of the CALL
  5641  		// instruction preceding the return address, this does not matter for this
  5642  		// test.
  5643  
  5644  		_, err = p.SetBreakpoint(0, retaddr, proc.UserBreakpoint, nil)
  5645  		assertNoError(err, t, "SetBreakpoint")
  5646  
  5647  		if len(p.Breakpoints().M) != clearlen+watchbpnum {
  5648  			// want 1 watchpoint, 1 stack resize breakpoint, 1 out of scope sentinel (which is also a user breakpoint) (and another out of scope sentinel if recorded)
  5649  			t.Errorf("wrong number of breakpoints after setting watchpoint: %d", len(p.Breakpoints().M)-clearlen)
  5650  		}
  5651  
  5652  		assertNoError(grp.Continue(), t, "Continue 1")
  5653  		assertLineNumber(p, t, position1, "Continue 1") // Position 1
  5654  
  5655  		assertNoError(grp.Continue(), t, "Continue 2")
  5656  		t.Logf("%#v", p.CurrentThread().Breakpoint().Breakpoint)
  5657  		assertLineNumber(p, t, 24, "Continue 2") // Position 2 (watchpoint gone out of scope)
  5658  
  5659  		if len(p.Breakpoints().M) != clearlen+1 {
  5660  			// want 1 user breakpoint set at retaddr
  5661  			t.Errorf("wrong number of breakpoints after watchpoint goes out of scope: %d", len(p.Breakpoints().M)-clearlen)
  5662  		}
  5663  
  5664  		if len(p.Breakpoints().WatchOutOfScope) != 1 {
  5665  			t.Errorf("wrong number of out-of-scope watchpoints after watchpoint goes out of scope: %d", len(p.Breakpoints().WatchOutOfScope))
  5666  		}
  5667  
  5668  		err = p.ClearBreakpoint(retaddr)
  5669  		assertNoError(err, t, "ClearBreakpoint")
  5670  
  5671  		if len(p.Breakpoints().M) != clearlen {
  5672  			// want 1 user breakpoint set at retaddr
  5673  			t.Errorf("wrong number of breakpoints after removing user breakpoint: %d", len(p.Breakpoints().M)-clearlen)
  5674  		}
  5675  	})
  5676  }
  5677  
  5678  func TestWatchpointStackBackwardsOutOfScope(t *testing.T) {
  5679  	skipUnlessOn(t, "only for recorded targets", "rr")
  5680  	protest.AllowRecording(t)
  5681  
  5682  	withTestProcess("databpstack", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  5683  		setFileBreakpoint(p, t, fixture.Source, 11) // Position 0 breakpoint
  5684  		clearlen := len(p.Breakpoints().M)
  5685  
  5686  		assertNoError(grp.Continue(), t, "Continue 0")
  5687  		assertLineNumber(p, t, 11, "Continue 0") // Position 0
  5688  
  5689  		scope, err := proc.GoroutineScope(p, p.CurrentThread())
  5690  		assertNoError(err, t, "GoroutineScope")
  5691  
  5692  		_, err = p.SetWatchpoint(0, scope, "w", proc.WatchWrite, nil)
  5693  		assertNoError(err, t, "SetDataBreakpoint(write-only)")
  5694  
  5695  		assertNoError(grp.Continue(), t, "Continue 1")
  5696  		assertLineNumber(p, t, 17, "Continue 1") // Position 1
  5697  
  5698  		grp.ChangeDirection(proc.Backward)
  5699  
  5700  		assertNoError(grp.Continue(), t, "Continue 2")
  5701  		t.Logf("%#v", p.CurrentThread().Breakpoint().Breakpoint)
  5702  		assertLineNumber(p, t, 16, "Continue 2") // Position 1 again (because of inverted movement)
  5703  
  5704  		assertNoError(grp.Continue(), t, "Continue 3")
  5705  		t.Logf("%#v", p.CurrentThread().Breakpoint().Breakpoint)
  5706  		assertLineNumber(p, t, 11, "Continue 3") // Position 0 (breakpoint 1 hit)
  5707  
  5708  		assertNoError(grp.Continue(), t, "Continue 4")
  5709  		t.Logf("%#v", p.CurrentThread().Breakpoint().Breakpoint)
  5710  		assertLineNumber(p, t, 23, "Continue 4") // Position 2 (watchpoint gone out of scope)
  5711  
  5712  		if len(p.Breakpoints().M) != clearlen {
  5713  			t.Errorf("wrong number of breakpoints after watchpoint goes out of scope: %d", len(p.Breakpoints().M)-clearlen)
  5714  		}
  5715  
  5716  		if len(p.Breakpoints().WatchOutOfScope) != 1 {
  5717  			t.Errorf("wrong number of out-of-scope watchpoints after watchpoint goes out of scope: %d", len(p.Breakpoints().WatchOutOfScope))
  5718  		}
  5719  
  5720  		if len(p.Breakpoints().M) != clearlen {
  5721  			// want 1 user breakpoint set at retaddr
  5722  			t.Errorf("wrong number of breakpoints after removing user breakpoint: %d", len(p.Breakpoints().M)-clearlen)
  5723  		}
  5724  	})
  5725  }
  5726  
  5727  func TestSetOnFunctions(t *testing.T) {
  5728  	// The set command between function variables should fail with an error
  5729  	// Issue #2691
  5730  	withTestProcess("goroutinestackprog", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  5731  		setFunctionBreakpoint(p, t, "main.main")
  5732  		assertNoError(grp.Continue(), t, "Continue()")
  5733  		scope, err := proc.GoroutineScope(p, p.CurrentThread())
  5734  		assertNoError(err, t, "GoroutineScope")
  5735  		err = scope.SetVariable("main.func1", "main.func2")
  5736  		if err == nil {
  5737  			t.Fatal("expected error when assigning between function variables")
  5738  		}
  5739  	})
  5740  }
  5741  
  5742  func TestNilPtrDerefInBreakInstr(t *testing.T) {
  5743  	// Checks that having a breakpoint on the exact instruction that causes a
  5744  	// nil pointer dereference does not cause problems.
  5745  
  5746  	var asmfile string
  5747  	switch runtime.GOARCH {
  5748  	case "amd64":
  5749  		asmfile = "main_amd64.s"
  5750  	case "arm64":
  5751  		asmfile = "main_arm64.s"
  5752  	case "386":
  5753  		asmfile = "main_386.s"
  5754  	case "ppc64le":
  5755  		asmfile = "main_ppc64le.s"
  5756  	default:
  5757  		t.Fatalf("assembly file for %s not provided", runtime.GOARCH)
  5758  	}
  5759  
  5760  	withTestProcess("asmnilptr/", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  5761  		f := filepath.Join(fixture.BuildDir, asmfile)
  5762  		f = strings.Replace(f, "\\", "/", -1)
  5763  		setFileBreakpoint(p, t, f, 5)
  5764  		t.Logf("first continue")
  5765  		assertNoError(grp.Continue(), t, "Continue()")
  5766  		t.Logf("second continue")
  5767  		err := grp.Continue()
  5768  		if runtime.GOOS == "darwin" && err != nil && err.Error() == "bad access" {
  5769  			// this is also ok
  5770  			return
  5771  		}
  5772  		t.Logf("third continue")
  5773  		assertNoError(err, t, "Continue()")
  5774  		bp := p.CurrentThread().Breakpoint()
  5775  		if bp != nil {
  5776  			t.Logf("%#v\n", bp.Breakpoint)
  5777  		}
  5778  		if bp == nil || (bp.Logical.Name != proc.UnrecoveredPanic) {
  5779  			t.Fatalf("no breakpoint hit or wrong breakpoint hit: %#v", bp)
  5780  		}
  5781  	})
  5782  }
  5783  
  5784  func TestStepIntoAutogeneratedSkip(t *testing.T) {
  5785  	// Tests that autogenerated functions are skipped with the new naming
  5786  	// scheme for autogenerated functions (issue #2948).
  5787  	withTestProcess("stepintobug", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  5788  		setFileBreakpoint(p, t, fixture.Source, 9)
  5789  		assertNoError(grp.Continue(), t, "Continue()")
  5790  		assertNoError(grp.Step(), t, "Step")
  5791  		assertLineNumber(p, t, 12, "After step")
  5792  	})
  5793  }
  5794  
  5795  func TestFollowExec(t *testing.T) {
  5796  	skipOn(t, "follow exec not implemented on freebsd", "freebsd")
  5797  	skipOn(t, "follow exec not implemented on macOS", "darwin")
  5798  	withTestProcessArgs("spawn", t, ".", []string{"spawn", "3"}, 0, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  5799  		grp.LogicalBreakpoints[1] = &proc.LogicalBreakpoint{LogicalID: 1, Set: proc.SetBreakpoint{FunctionName: "main.traceme1"}, HitCount: make(map[int64]uint64)}
  5800  		grp.LogicalBreakpoints[2] = &proc.LogicalBreakpoint{LogicalID: 2, Set: proc.SetBreakpoint{FunctionName: "main.traceme2"}, HitCount: make(map[int64]uint64)}
  5801  		grp.LogicalBreakpoints[3] = &proc.LogicalBreakpoint{LogicalID: 3, Set: proc.SetBreakpoint{FunctionName: "main.traceme3"}, HitCount: make(map[int64]uint64)}
  5802  
  5803  		assertNoError(grp.EnableBreakpoint(grp.LogicalBreakpoints[1]), t, "EnableBreakpoint(main.traceme1)")
  5804  		assertNoError(grp.EnableBreakpoint(grp.LogicalBreakpoints[3]), t, "EnableBreakpoint(main.traceme3)")
  5805  
  5806  		assertNoError(grp.FollowExec(true, ""), t, "FollowExec")
  5807  
  5808  		first := true
  5809  		finished := false
  5810  		pids := map[int]int{}
  5811  		ns := map[string]int{}
  5812  
  5813  		for {
  5814  			t.Log("Continuing")
  5815  			err := grp.Continue()
  5816  			if err != nil {
  5817  				_, isexited := err.(proc.ErrProcessExited)
  5818  				if isexited {
  5819  					break
  5820  				}
  5821  				assertNoError(err, t, "Continue")
  5822  			}
  5823  
  5824  			if first {
  5825  				first = false
  5826  				if grp.Selected != p {
  5827  					t.Fatalf("first breakpoint hit was not on the parent process")
  5828  				}
  5829  				if grp.Selected.CurrentThread().Breakpoint().Breakpoint.LogicalID() != 1 {
  5830  					t.Fatalf("wrong breakpoint %#v", grp.Selected.CurrentThread().Breakpoint().Breakpoint)
  5831  				}
  5832  				loc, err := grp.Selected.CurrentThread().Location()
  5833  				assertNoError(err, t, "Location")
  5834  				if loc.Fn.Name != "main.traceme1" {
  5835  					t.Fatalf("wrong stop location %#v", loc)
  5836  				}
  5837  			} else if grp.Selected == p {
  5838  				if finished {
  5839  					t.Fatalf("breakpoint hit after the last one in the parent process")
  5840  				}
  5841  				if p.CurrentThread().Breakpoint().Breakpoint.LogicalID() != 3 {
  5842  					t.Fatalf("wrong breakpoint %#v", p.CurrentThread().Breakpoint().Breakpoint)
  5843  				}
  5844  				loc, err := p.CurrentThread().Location()
  5845  				assertNoError(err, t, "Location")
  5846  				if loc.Fn.Name != "main.traceme3" {
  5847  					t.Fatalf("wrong stop location %#v", loc)
  5848  				}
  5849  				finished = true
  5850  			} else {
  5851  				if finished {
  5852  					t.Fatalf("breakpoint hit after the last one in a child process")
  5853  				}
  5854  				it := proc.ValidTargets{Group: grp}
  5855  				for it.Next() {
  5856  					tgt := it.Target
  5857  					if !tgt.CurrentThread().Breakpoint().Active {
  5858  						continue
  5859  					}
  5860  					if tgt.CurrentThread().Breakpoint().Breakpoint.LogicalID() != 2 {
  5861  						t.Fatalf("wrong breakpoint %#v", grp.Selected.CurrentThread().Breakpoint().Breakpoint)
  5862  					}
  5863  					pids[tgt.Pid()]++
  5864  					loc, err := tgt.CurrentThread().Location()
  5865  					assertNoError(err, t, "Location")
  5866  					if loc.Fn.Name != "main.traceme2" {
  5867  						t.Fatalf("wrong stop location %#v", loc)
  5868  					}
  5869  					nvar := evalVariable(tgt, t, "n")
  5870  					if nvar.Unreadable != nil {
  5871  						t.Fatalf("unreadable variable 'n' on target %d: %v", tgt.Pid(), nvar.Unreadable)
  5872  					}
  5873  					t.Logf("variable 'n' on target %d: %#v (%v)", tgt.Pid(), nvar, nvar.Value)
  5874  					ns[constant.StringVal(nvar.Value)]++
  5875  				}
  5876  			}
  5877  		}
  5878  
  5879  		if len(ns) != 3 {
  5880  			t.Errorf("bad contents of ns: %#v", ns)
  5881  		}
  5882  		for _, v := range ns {
  5883  			if v != 1 {
  5884  				t.Errorf("bad contents of ns: %#v", ns)
  5885  			}
  5886  		}
  5887  		if ns["C0"] != 1 || ns["C1"] != 1 || ns["C2"] != 1 {
  5888  			t.Errorf("bad contents of ns: %#v", ns)
  5889  		}
  5890  
  5891  		if len(pids) != 3 {
  5892  			t.Errorf("bad contents of pids: %#v", pids)
  5893  		}
  5894  		for _, v := range pids {
  5895  			if v != 1 {
  5896  				t.Errorf("bad contents of pids: %#v", pids)
  5897  			}
  5898  		}
  5899  	})
  5900  }
  5901  
  5902  func TestEscapeCheckUnreadable(t *testing.T) {
  5903  	// A failure in escapeCheck to dereference a field should not cause
  5904  	// infinite recursion. See issue #3310.
  5905  	withTestProcessArgs("reflecttypefncall", t, ".", []string{}, protest.AllNonOptimized, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  5906  		setFileBreakpoint(p, t, fixture.Source, 9)
  5907  		assertNoError(grp.Continue(), t, "Continue")
  5908  		proc.EvalExpressionWithCalls(grp, p.SelectedGoroutine(), "value.Type()", normalLoadConfig, true)
  5909  	})
  5910  }
  5911  
  5912  func TestStepShadowConcurrentBreakpoint(t *testing.T) {
  5913  	// Checks that a StepBreakpoint can not shadow a concurrently hit user breakpoint
  5914  	withTestProcess("stepshadow", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  5915  		break2 := setFunctionBreakpoint(p, t, "main.stacktraceme2")
  5916  		breakMain := setFileBreakpoint(p, t, fixture.Source, 15)
  5917  		assertNoError(grp.Continue(), t, "Continue()")
  5918  
  5919  		stacktraceme1calls, stacktraceme2calls := 0, 0
  5920  
  5921  		for {
  5922  			t.Logf("stop (%d %d):", stacktraceme1calls, stacktraceme2calls)
  5923  			for _, th := range p.ThreadList() {
  5924  				loc, _ := th.Location()
  5925  				t.Logf("\t%s:%d\n", loc.File, loc.Line)
  5926  				bp := th.Breakpoint().Breakpoint
  5927  				if bp != nil && bp.Addr == break2.Addr {
  5928  					stacktraceme2calls++
  5929  				}
  5930  				// make stop on the breakpoint in main.main the selected goroutine so we can use step later
  5931  				if bp != nil && bp.Addr == breakMain.Addr {
  5932  					g, _ := proc.GetG(th)
  5933  					p.SwitchGoroutine(g)
  5934  				}
  5935  			}
  5936  
  5937  			file, lineno := currentLineNumber(p, t)
  5938  
  5939  			var err error
  5940  			var reason string
  5941  			switch lineno {
  5942  			default:
  5943  				t.Fatalf("unexpected stop location %s:%d", file, lineno)
  5944  			case 15: // loop in main.main
  5945  				reason = "Step()"
  5946  				err = grp.Step()
  5947  			case 28: // main.stacktraceme1
  5948  				stacktraceme1calls++
  5949  				reason = "Continue()"
  5950  				err = grp.Continue()
  5951  			case 30, 31: // main.stacktraceme2
  5952  				reason = "Continue()"
  5953  				err = grp.Continue()
  5954  			}
  5955  			if _, isexited := err.(proc.ErrProcessExited); isexited {
  5956  				break
  5957  			}
  5958  			assertNoError(err, t, reason)
  5959  		}
  5960  
  5961  		t.Logf("%d %d\n", stacktraceme1calls, stacktraceme2calls)
  5962  
  5963  		if stacktraceme1calls != 100 {
  5964  			t.Errorf("wrong number of calls to stacktraceme1 found: %d", stacktraceme1calls)
  5965  		}
  5966  		if stacktraceme2calls != 100 {
  5967  			t.Errorf("wrong number of calls to stacktraceme2 found: %d", stacktraceme2calls)
  5968  		}
  5969  	})
  5970  }
  5971  
  5972  func TestFollowExecRegexFilter(t *testing.T) {
  5973  	skipOn(t, "follow exec not implemented on freebsd", "freebsd")
  5974  	skipOn(t, "follow exec not implemented on macOS", "darwin")
  5975  	withTestProcessArgs("spawn", t, ".", []string{"spawn", "3"}, 0, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  5976  		grp.LogicalBreakpoints[1] = &proc.LogicalBreakpoint{LogicalID: 1, Set: proc.SetBreakpoint{FunctionName: "main.traceme1"}, HitCount: make(map[int64]uint64)}
  5977  		grp.LogicalBreakpoints[2] = &proc.LogicalBreakpoint{LogicalID: 2, Set: proc.SetBreakpoint{FunctionName: "main.traceme2"}, HitCount: make(map[int64]uint64)}
  5978  		grp.LogicalBreakpoints[3] = &proc.LogicalBreakpoint{LogicalID: 3, Set: proc.SetBreakpoint{FunctionName: "main.traceme3"}, HitCount: make(map[int64]uint64)}
  5979  
  5980  		assertNoError(grp.EnableBreakpoint(grp.LogicalBreakpoints[1]), t, "EnableBreakpoint(main.traceme1)")
  5981  		assertNoError(grp.EnableBreakpoint(grp.LogicalBreakpoints[3]), t, "EnableBreakpoint(main.traceme3)")
  5982  
  5983  		assertNoError(grp.FollowExec(true, "spawn.* child C1"), t, "FollowExec")
  5984  
  5985  		assertNoError(grp.Continue(), t, "Continue 1")
  5986  		assertFunctionName(grp.Selected, t, "main.traceme1", "Program did not continue to the expected location (1)")
  5987  		assertNoError(grp.Continue(), t, "Continue 2")
  5988  		assertFunctionName(grp.Selected, t, "main.traceme2", "Program did not continue to the expected location (2)")
  5989  		assertNoError(grp.Continue(), t, "Continue 3")
  5990  		assertFunctionName(grp.Selected, t, "main.traceme3", "Program did not continue to the expected location (3)")
  5991  		err := grp.Continue()
  5992  		if err != nil {
  5993  			_, isexited := err.(proc.ErrProcessExited)
  5994  			if !isexited {
  5995  				assertNoError(err, t, "Continue 4")
  5996  			}
  5997  		} else {
  5998  			t.Fatal("process did not exit after 4 continues")
  5999  		}
  6000  	})
  6001  }
  6002  
  6003  func TestReadTargetArguments(t *testing.T) {
  6004  	protest.AllowRecording(t)
  6005  	withTestProcessArgs("restartargs", t, ".", []string{"one", "two", "three"}, 0, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  6006  		t.Logf("command line: %q\n", p.CmdLine)
  6007  		if !strings.HasSuffix(p.CmdLine, " one two three") {
  6008  			t.Fatalf("wrong command line")
  6009  		}
  6010  	})
  6011  }
  6012  
  6013  func testWaitForSetup(t *testing.T, mu *sync.Mutex, started *bool) (*exec.Cmd, *proc.WaitFor) {
  6014  	var buildFlags protest.BuildFlags
  6015  	if buildMode == "pie" {
  6016  		buildFlags |= protest.BuildModePIE
  6017  	}
  6018  	fixture := protest.BuildFixture("loopprog", buildFlags)
  6019  
  6020  	cmd := exec.Command(fixture.Path)
  6021  
  6022  	go func() {
  6023  		time.Sleep(2 * time.Second)
  6024  		cmd.Stdout = os.Stdout
  6025  		cmd.Stderr = os.Stderr
  6026  		assertNoError(cmd.Start(), t, "starting fixture")
  6027  		mu.Lock()
  6028  		*started = true
  6029  		mu.Unlock()
  6030  	}()
  6031  
  6032  	waitFor := &proc.WaitFor{Name: fixture.Path, Interval: 100 * time.Millisecond, Duration: 10 * time.Second}
  6033  
  6034  	return cmd, waitFor
  6035  }
  6036  
  6037  func TestWaitFor(t *testing.T) {
  6038  	skipOn(t, "waitfor implementation is delegated to debugserver", "darwin")
  6039  	skipOn(t, "flaky", "freebsd")
  6040  
  6041  	var mu sync.Mutex
  6042  	started := false
  6043  
  6044  	cmd, waitFor := testWaitForSetup(t, &mu, &started)
  6045  
  6046  	pid, err := native.WaitFor(waitFor)
  6047  	assertNoError(err, t, "waitFor.Wait()")
  6048  	if pid != cmd.Process.Pid {
  6049  		t.Errorf("pid mismatch, expected %d got %d", pid, cmd.Process.Pid)
  6050  	}
  6051  
  6052  	cmd.Process.Kill()
  6053  	cmd.Wait()
  6054  }
  6055  
  6056  func TestWaitForAttach(t *testing.T) {
  6057  	skipOn(t, "flaky", "freebsd")
  6058  	if testBackend == "lldb" && runtime.GOOS == "linux" {
  6059  		bs, _ := os.ReadFile("/proc/sys/kernel/yama/ptrace_scope")
  6060  		if bs == nil || strings.TrimSpace(string(bs)) != "0" {
  6061  			t.Logf("can not run TestAttachDetach: %v\n", bs)
  6062  			return
  6063  		}
  6064  	}
  6065  	if testBackend == "rr" {
  6066  		return
  6067  	}
  6068  
  6069  	var mu sync.Mutex
  6070  	started := false
  6071  
  6072  	cmd, waitFor := testWaitForSetup(t, &mu, &started)
  6073  
  6074  	var p *proc.TargetGroup
  6075  	var err error
  6076  
  6077  	switch testBackend {
  6078  	case "native":
  6079  		p, err = native.Attach(0, waitFor, []string{})
  6080  	case "lldb":
  6081  		path := ""
  6082  		if runtime.GOOS == "darwin" {
  6083  			path = waitFor.Name
  6084  		}
  6085  		p, err = gdbserial.LLDBAttach(0, path, waitFor, []string{})
  6086  	default:
  6087  		err = fmt.Errorf("unknown backend %q", testBackend)
  6088  	}
  6089  
  6090  	assertNoError(err, t, "Attach")
  6091  
  6092  	mu.Lock()
  6093  	if !started {
  6094  		t.Fatalf("attach succeeded but started is false")
  6095  	}
  6096  	mu.Unlock()
  6097  
  6098  	p.Detach(true)
  6099  
  6100  	cmd.Wait()
  6101  }
  6102  
  6103  func TestNextGenericMethodThroughInterface(t *testing.T) {
  6104  	// Tests that autogenerated wrappers for generic methods called through an
  6105  	// interface are skipped.
  6106  
  6107  	varcheck := func(p *proc.Target) {
  6108  		yvar := evalVariable(p, t, "y")
  6109  		yval, _ := constant.Int64Val(yvar.Value)
  6110  		if yval != 2 {
  6111  			t.Errorf("expected 2 got %#v", yvar.Value)
  6112  		}
  6113  	}
  6114  
  6115  	if runtime.GOOS == "linux" && runtime.GOARCH == "386" {
  6116  		testseq2(t, "genericintoiface", "main.callf", []seqTest{
  6117  			{contContinue, 17},
  6118  			{contStep, 18},
  6119  			{contStep, 10},
  6120  			{contNothing, varcheck},
  6121  			{contNext, 11},
  6122  			{contNext, 19},
  6123  		})
  6124  	} else {
  6125  		testseq2(t, "genericintoiface", "main.callf", []seqTest{
  6126  			{contContinue, 17},
  6127  			{contStep, 18},
  6128  			{contStep, 9},
  6129  			{contNext, 10},
  6130  			{contNothing, varcheck},
  6131  			{contNext, 11},
  6132  			{contNext, 19},
  6133  		})
  6134  	}
  6135  }
  6136  
  6137  func TestIssue3545(t *testing.T) {
  6138  	protest.AllowRecording(t)
  6139  	withTestProcessArgs("nilptr", t, "", []string{}, protest.EnableOptimization, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  6140  		err := grp.Continue()
  6141  		if err != nil && err.Error() == "bad access" {
  6142  			grp.Continue()
  6143  		}
  6144  		locations, err := proc.ThreadStacktrace(p, p.CurrentThread(), 40)
  6145  		assertNoError(err, t, "Stacktrace()")
  6146  		var foundMain bool
  6147  		for _, loc := range locations {
  6148  			if loc.Call.Fn != nil && loc.Call.Fn.Name == "main.main" {
  6149  				if foundMain {
  6150  					t.Fatal("main.main found more than once in the stacktrace")
  6151  				}
  6152  				foundMain = true
  6153  			}
  6154  		}
  6155  		if !foundMain {
  6156  			t.Fatal("did not find main.main in stack trace")
  6157  		}
  6158  	})
  6159  }
  6160  
  6161  func TestPanicLine(t *testing.T) {
  6162  	withTestProcess("panicline", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  6163  		err := grp.Continue()
  6164  		if runtime.GOOS == "darwin" && err != nil && err.Error() == "bad access" {
  6165  			// not supported
  6166  			return
  6167  		}
  6168  		assertNoError(err, t, "Continue()")
  6169  		frames, err := proc.ThreadStacktrace(p, p.CurrentThread(), 20)
  6170  		assertNoError(err, t, "ThreadStacktrace")
  6171  		logStacktrace(t, p, frames)
  6172  
  6173  		found := false
  6174  		for _, frame := range frames {
  6175  			if strings.HasSuffix(frame.Call.File, "panicline.go") && frame.Call.Line == 7 {
  6176  				found = true
  6177  				break
  6178  			}
  6179  		}
  6180  		if !found {
  6181  			t.Fatalf("could not find panicline.go:6")
  6182  		}
  6183  	})
  6184  }
  6185  
  6186  func TestReadClosure(t *testing.T) {
  6187  	if !goversion.VersionAfterOrEqual(runtime.Version(), 1, 23) {
  6188  		t.Skip("not implemented")
  6189  	}
  6190  	withTestProcess("closurecontents", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
  6191  		avalues := []int64{0, 3, 9, 27}
  6192  		for i := 0; i < 4; i++ {
  6193  			assertNoError(grp.Continue(), t, "Continue()")
  6194  			accV := evalVariable(p, t, "acc")
  6195  			t.Log(api.ConvertVar(accV).MultilineString("", ""))
  6196  			if len(accV.Children) != 2 {
  6197  				t.Error("wrong number of children")
  6198  			} else {
  6199  				found := 0
  6200  				for j := range accV.Children {
  6201  					v := &accV.Children[j]
  6202  					switch v.Name {
  6203  					case "scale":
  6204  						found++
  6205  						if val, _ := constant.Int64Val(v.Value); val != 3 {
  6206  							t.Error("wrong value for scale")
  6207  						}
  6208  					case "a":
  6209  						found++
  6210  						if val, _ := constant.Int64Val(v.Value); val != avalues[i] {
  6211  							t.Errorf("wrong value for a: %d", val)
  6212  						}
  6213  					}
  6214  				}
  6215  				if found != 2 {
  6216  					t.Error("wrong captured variables")
  6217  				}
  6218  			}
  6219  		}
  6220  	})
  6221  }
  6222  
  6223  func TestStepIntoGoroutine(t *testing.T) {
  6224  	testseq2(t, "goroutinestackprog", "", []seqTest{
  6225  		{contContinue, 23},
  6226  		{contStep, 7},
  6227  		{contNothing, func(p *proc.Target) {
  6228  			vari := api.ConvertVar(evalVariable(p, t, "i"))
  6229  			varis := vari.SinglelineString()
  6230  			t.Logf("i = %s", varis)
  6231  			if varis != "0" {
  6232  				t.Fatalf("wrong value for variable i: %s", vari.SinglelineString())
  6233  			}
  6234  		}},
  6235  	})
  6236  }