github.com/undoio/delve@v1.9.0/pkg/proc/variables_test.go (about)

     1  package proc_test
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"go/constant"
     7  	"io/ioutil"
     8  	"runtime"
     9  	"sort"
    10  	"strings"
    11  	"testing"
    12  
    13  	"github.com/undoio/delve/pkg/goversion"
    14  	"github.com/undoio/delve/pkg/proc"
    15  	"github.com/undoio/delve/service/api"
    16  
    17  	protest "github.com/undoio/delve/pkg/proc/test"
    18  )
    19  
    20  var pnormalLoadConfig = proc.LoadConfig{
    21  	FollowPointers:     true,
    22  	MaxVariableRecurse: 1,
    23  	MaxStringLen:       64,
    24  	MaxArrayValues:     64,
    25  	MaxStructFields:    -1,
    26  }
    27  
    28  var pshortLoadConfig = proc.LoadConfig{
    29  	MaxStringLen:    64,
    30  	MaxStructFields: 3,
    31  }
    32  
    33  type varTest struct {
    34  	name         string
    35  	preserveName bool
    36  	value        string
    37  	alternate    string
    38  	varType      string
    39  	err          error
    40  }
    41  
    42  func matchStringOrPrefix(output, target string) bool {
    43  	if strings.HasSuffix(target, "…") {
    44  		prefix := target[:len(target)-len("…")]
    45  		b := strings.HasPrefix(output, prefix)
    46  		return b
    47  	} else {
    48  		return output == target
    49  	}
    50  }
    51  
    52  func assertVariable(t *testing.T, variable *proc.Variable, expected varTest) {
    53  	if expected.preserveName {
    54  		if variable.Name != expected.name {
    55  			t.Fatalf("Expected %s got %s\n", expected.name, variable.Name)
    56  		}
    57  	}
    58  
    59  	cv := api.ConvertVar(variable)
    60  
    61  	if cv.Type != expected.varType {
    62  		t.Fatalf("Expected %s got %s (for variable %s)\n", expected.varType, cv.Type, expected.name)
    63  	}
    64  
    65  	if ss := cv.SinglelineString(); !matchStringOrPrefix(ss, expected.value) {
    66  		t.Fatalf("Expected %#v got %#v (for variable %s)\n", expected.value, ss, expected.name)
    67  	}
    68  }
    69  
    70  func evalScope(p *proc.Target) (*proc.EvalScope, error) {
    71  	if testBackend != "rr" && testBackend != "undo" {
    72  		return proc.GoroutineScope(p, p.CurrentThread())
    73  	}
    74  	frame, err := findFirstNonRuntimeFrame(p)
    75  	if err != nil {
    76  		return nil, err
    77  	}
    78  	return proc.FrameToScope(p, p.Memory(), nil, frame), nil
    79  }
    80  
    81  func evalVariableWithCfg(p *proc.Target, symbol string, cfg proc.LoadConfig) (*proc.Variable, error) {
    82  	scope, err := evalScope(p)
    83  	if err != nil {
    84  		return nil, err
    85  	}
    86  
    87  	return scope.EvalExpression(symbol, cfg)
    88  }
    89  
    90  func (tc *varTest) alternateVarTest() varTest {
    91  	r := *tc
    92  	r.value = r.alternate
    93  	return r
    94  }
    95  
    96  func TestVariableEvaluation2(t *testing.T) {
    97  	testcases := []varTest{
    98  		{"a1", true, "\"foofoofoofoofoofoo\"", "", "string", nil},
    99  		{"a11", true, "[3]main.FooBar [{Baz: 1, Bur: \"a\"},{Baz: 2, Bur: \"b\"},{Baz: 3, Bur: \"c\"}]", "", "[3]main.FooBar", nil},
   100  		{"a12", true, "[]main.FooBar len: 2, cap: 2, [{Baz: 4, Bur: \"d\"},{Baz: 5, Bur: \"e\"}]", "", "[]main.FooBar", nil},
   101  		{"a13", true, "[]*main.FooBar len: 3, cap: 3, [*{Baz: 6, Bur: \"f\"},*{Baz: 7, Bur: \"g\"},*{Baz: 8, Bur: \"h\"}]", "", "[]*main.FooBar", nil},
   102  		{"a2", true, "6", "10", "int", nil},
   103  		{"a3", true, "7.23", "3.1", "float64", nil},
   104  		{"a4", true, "[2]int [1,2]", "", "[2]int", nil},
   105  		{"a5", true, "[]int len: 5, cap: 5, [1,2,3,4,5]", "", "[]int", nil},
   106  		{"a6", true, "main.FooBar {Baz: 8, Bur: \"word\"}", "", "main.FooBar", nil},
   107  		{"a7", true, "*main.FooBar {Baz: 5, Bur: \"strum\"}", "", "*main.FooBar", nil},
   108  		{"a8", true, "main.FooBar2 {Bur: 10, Baz: \"feh\"}", "", "main.FooBar2", nil},
   109  		{"a9", true, "*main.FooBar nil", "", "*main.FooBar", nil},
   110  		{"baz", true, "\"bazburzum\"", "", "string", nil},
   111  		{"neg", true, "-1", "-20", "int", nil},
   112  		{"f32", true, "1.2", "1.1", "float32", nil},
   113  		{"c64", true, "(1 + 2i)", "(4 + 5i)", "complex64", nil},
   114  		{"c128", true, "(2 + 3i)", "(6.3 + 7i)", "complex128", nil},
   115  		{"a6.Baz", true, "8", "20", "int", nil},
   116  		{"a7.Baz", true, "5", "25", "int", nil},
   117  		{"a8.Baz", true, "\"feh\"", "", "string", nil},
   118  		{"a9.Baz", true, "nil", "", "int", fmt.Errorf("a9 is nil")},
   119  		{"a9.NonExistent", true, "nil", "", "int", fmt.Errorf("a9 has no member NonExistent")},
   120  		{"a8", true, "main.FooBar2 {Bur: 10, Baz: \"feh\"}", "", "main.FooBar2", nil}, // reread variable after member
   121  		{"i32", true, "[2]int32 [1,2]", "", "[2]int32", nil},
   122  		{"b1", true, "true", "false", "bool", nil},
   123  		{"b2", true, "false", "true", "bool", nil},
   124  		{"i8", true, "1", "2", "int8", nil},
   125  		{"u16", true, "65535", "0", "uint16", nil},
   126  		{"u32", true, "4294967295", "1", "uint32", nil},
   127  		{"u64", true, "18446744073709551615", "2", "uint64", nil},
   128  		{"u8", true, "255", "3", "uint8", nil},
   129  		{"up", true, "5", "4", "uintptr", nil},
   130  		{"f", true, "main.barfoo", "", "func()", nil},
   131  		{"ba", true, "[]int len: 200, cap: 200, [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,...+136 more]", "", "[]int", nil},
   132  		{"ms", true, "main.Nest {Level: 0, Nest: *main.Nest {Level: 1, Nest: *(*main.Nest)(…", "", "main.Nest", nil},
   133  		{"ms.Nest.Nest", true, "*main.Nest {Level: 2, Nest: *main.Nest {Level: 3, Nest: *(*main.Nest)(…", "", "*main.Nest", nil},
   134  		{"ms.Nest.Nest.Nest.Nest.Nest", true, "*main.Nest nil", "", "*main.Nest", nil},
   135  		{"ms.Nest.Nest.Nest.Nest.Nest.Nest", true, "", "", "*main.Nest", fmt.Errorf("ms.Nest.Nest.Nest.Nest.Nest is nil")},
   136  		{"main.p1", true, "10", "12", "int", nil},
   137  		{"p1", true, "10", "13", "int", nil},
   138  		{"NonExistent", true, "", "", "", fmt.Errorf("could not find symbol value for NonExistent")},
   139  	}
   140  
   141  	protest.AllowRecording(t)
   142  	withTestProcess("testvariables", t, func(p *proc.Target, fixture protest.Fixture) {
   143  		err := p.Continue()
   144  		assertNoError(err, t, "Continue() returned an error")
   145  
   146  		for _, tc := range testcases {
   147  			variable, err := evalVariableWithCfg(p, tc.name, pnormalLoadConfig)
   148  			if tc.err == nil {
   149  				assertNoError(err, t, "EvalVariable() returned an error")
   150  				assertVariable(t, variable, tc)
   151  			} else {
   152  				if err == nil {
   153  					t.Fatalf("Expected error %s, got no error: %s\n", tc.err.Error(), api.ConvertVar(variable).SinglelineString())
   154  				}
   155  				if tc.err.Error() != err.Error() {
   156  					t.Fatalf("Unexpected error. Expected %s got %s", tc.err.Error(), err.Error())
   157  				}
   158  			}
   159  
   160  			if tc.alternate != "" && testBackend != "rr" && testBackend != "undo" {
   161  				assertNoError(setVariable(p, tc.name, tc.alternate), t, "SetVariable()")
   162  				variable, err = evalVariableWithCfg(p, tc.name, pnormalLoadConfig)
   163  				assertNoError(err, t, "EvalVariable()")
   164  				assertVariable(t, variable, tc.alternateVarTest())
   165  
   166  				assertNoError(setVariable(p, tc.name, tc.value), t, "SetVariable()")
   167  				variable, err := evalVariableWithCfg(p, tc.name, pnormalLoadConfig)
   168  				assertNoError(err, t, "EvalVariable()")
   169  				assertVariable(t, variable, tc)
   170  			}
   171  		}
   172  	})
   173  }
   174  
   175  func TestSetVariable(t *testing.T) {
   176  	var testcases = []struct {
   177  		name     string
   178  		typ      string // type of <name>
   179  		startVal string // original value of <name>
   180  		expr     string
   181  		finalVal string // new value of <name> after executing <name> = <expr>
   182  	}{
   183  		{"b.ptr", "*main.A", "*main.A {val: 1337}", "nil", "*main.A nil"},
   184  		{"m2", "map[int]*main.astruct", "map[int]*main.astruct [1: *{A: 10, B: 11}, ]", "nil", "map[int]*main.astruct nil"},
   185  		{"fn1", "main.functype", "main.afunc", "nil", "nil"},
   186  		{"ch1", "chan int", "chan int 4/11", "nil", "chan int nil"},
   187  		{"s2", "[]main.astruct", "[]main.astruct len: 8, cap: 8, [{A: 1, B: 2},{A: 3, B: 4},{A: 5, B: 6},{A: 7, B: 8},{A: 9, B: 10},{A: 11, B: 12},{A: 13, B: 14},{A: 15, B: 16}]", "nil", "[]main.astruct len: 0, cap: 0, nil"},
   188  		{"err1", "error", "error(*main.astruct) *{A: 1, B: 2}", "nil", "error nil"},
   189  		{"s1[0]", "string", `"one"`, `""`, `""`},
   190  		{"as1", "main.astruct", "main.astruct {A: 1, B: 1}", `m1["Malone"]`, "main.astruct {A: 2, B: 3}"},
   191  
   192  		{"iface1", "interface {}", "interface {}(*main.astruct) *{A: 1, B: 2}", "nil", "interface {} nil"},
   193  		{"iface1", "interface {}", "interface {} nil", "iface2", "interface {}(string) \"test\""},
   194  		{"iface1", "interface {}", "interface {}(string) \"test\"", "parr", "interface {}(*[4]int) *[0,1,2,3]"},
   195  
   196  		{"s3", "[]int", `[]int len: 0, cap: 6, []`, "s4[2:5]", "[]int len: 3, cap: 3, [3,4,5]"},
   197  		{"s3", "[]int", "[]int len: 3, cap: 3, [3,4,5]", "arr1[:]", "[]int len: 4, cap: 4, [0,1,2,3]"},
   198  	}
   199  
   200  	withTestProcess("testvariables2", t, func(p *proc.Target, fixture protest.Fixture) {
   201  		assertNoError(p.Continue(), t, "Continue()")
   202  
   203  		for _, tc := range testcases {
   204  			if tc.name == "iface1" && tc.expr == "parr" {
   205  				if !goversion.VersionAfterOrEqual(runtime.Version(), 1, 11) {
   206  					// conversion pointer -> eface not supported prior to Go 1.11
   207  					continue
   208  				}
   209  			}
   210  			variable, err := evalVariableWithCfg(p, tc.name, pnormalLoadConfig)
   211  			assertNoError(err, t, "EvalVariable()")
   212  			assertVariable(t, variable, varTest{tc.name, true, tc.startVal, "", tc.typ, nil})
   213  
   214  			assertNoError(setVariable(p, tc.name, tc.expr), t, "SetVariable()")
   215  
   216  			variable, err = evalVariableWithCfg(p, tc.name, pnormalLoadConfig)
   217  			assertNoError(err, t, "EvalVariable()")
   218  			assertVariable(t, variable, varTest{tc.name, true, tc.finalVal, "", tc.typ, nil})
   219  		}
   220  	})
   221  }
   222  
   223  func TestVariableEvaluationShort(t *testing.T) {
   224  	testcases := []varTest{
   225  		{"a1", true, "\"foofoofoofoofoofoo\"", "", "string", nil},
   226  		{"a11", true, "[3]main.FooBar [...]", "", "[3]main.FooBar", nil},
   227  		{"a12", true, "[]main.FooBar len: 2, cap: 2, [...]", "", "[]main.FooBar", nil},
   228  		{"a13", true, "[]*main.FooBar len: 3, cap: 3, [...]", "", "[]*main.FooBar", nil},
   229  		{"a2", true, "6", "", "int", nil},
   230  		{"a3", true, "7.23", "", "float64", nil},
   231  		{"a4", true, "[2]int [...]", "", "[2]int", nil},
   232  		{"a5", true, "[]int len: 5, cap: 5, [...]", "", "[]int", nil},
   233  		{"a6", true, "main.FooBar {Baz: 8, Bur: \"word\"}", "", "main.FooBar", nil},
   234  		{"a7", true, "(*main.FooBar)(0x…", "", "*main.FooBar", nil},
   235  		{"a8", true, "main.FooBar2 {Bur: 10, Baz: \"feh\"}", "", "main.FooBar2", nil},
   236  		{"a9", true, "*main.FooBar nil", "", "*main.FooBar", nil},
   237  		{"baz", true, "\"bazburzum\"", "", "string", nil},
   238  		{"neg", true, "-1", "", "int", nil},
   239  		{"f32", true, "1.2", "", "float32", nil},
   240  		{"c64", true, "(1 + 2i)", "", "complex64", nil},
   241  		{"c128", true, "(2 + 3i)", "", "complex128", nil},
   242  		{"a6.Baz", true, "8", "", "int", nil},
   243  		{"a7.Baz", true, "5", "", "int", nil},
   244  		{"a8.Baz", true, "\"feh\"", "", "string", nil},
   245  		{"a9.Baz", true, "nil", "", "int", fmt.Errorf("a9 is nil")},
   246  		{"a9.NonExistent", true, "nil", "", "int", fmt.Errorf("a9 has no member NonExistent")},
   247  		{"a8", true, "main.FooBar2 {Bur: 10, Baz: \"feh\"}", "", "main.FooBar2", nil}, // reread variable after member
   248  		{"i32", true, "[2]int32 [...]", "", "[2]int32", nil},
   249  		{"b1", true, "true", "false", "bool", nil},
   250  		{"b2", true, "false", "true", "bool", nil},
   251  		{"i8", true, "1", "2", "int8", nil},
   252  		{"u16", true, "65535", "0", "uint16", nil},
   253  		{"u32", true, "4294967295", "1", "uint32", nil},
   254  		{"u64", true, "18446744073709551615", "2", "uint64", nil},
   255  		{"u8", true, "255", "3", "uint8", nil},
   256  		{"up", true, "5", "4", "uintptr", nil},
   257  		{"f", true, "main.barfoo", "", "func()", nil},
   258  		{"ba", true, "[]int len: 200, cap: 200, [...]", "", "[]int", nil},
   259  		{"ms", true, "main.Nest {Level: 0, Nest: (*main.Nest)(0x…", "", "main.Nest", nil},
   260  		{"ms.Nest.Nest", true, "(*main.Nest)(0x…", "", "*main.Nest", nil},
   261  		{"ms.Nest.Nest.Nest.Nest.Nest", true, "*main.Nest nil", "", "*main.Nest", nil},
   262  		{"ms.Nest.Nest.Nest.Nest.Nest.Nest", true, "", "", "*main.Nest", fmt.Errorf("ms.Nest.Nest.Nest.Nest.Nest is nil")},
   263  		{"main.p1", true, "10", "", "int", nil},
   264  		{"p1", true, "10", "", "int", nil},
   265  		{"NonExistent", true, "", "", "", fmt.Errorf("could not find symbol value for NonExistent")},
   266  	}
   267  
   268  	protest.AllowRecording(t)
   269  	withTestProcess("testvariables", t, func(p *proc.Target, fixture protest.Fixture) {
   270  		err := p.Continue()
   271  		assertNoError(err, t, "Continue() returned an error")
   272  
   273  		for _, tc := range testcases {
   274  			variable, err := evalVariableWithCfg(p, tc.name, pshortLoadConfig)
   275  			if tc.err == nil {
   276  				assertNoError(err, t, "EvalVariable() returned an error")
   277  				assertVariable(t, variable, tc)
   278  			} else {
   279  				if err == nil {
   280  					t.Fatalf("Expected error %s, got no error: %s\n", tc.err.Error(), api.ConvertVar(variable).SinglelineString())
   281  				}
   282  				if tc.err.Error() != err.Error() {
   283  					t.Fatalf("Unexpected error. Expected %s got %s", tc.err.Error(), err.Error())
   284  				}
   285  			}
   286  		}
   287  	})
   288  }
   289  
   290  func TestMultilineVariableEvaluation(t *testing.T) {
   291  	testcases := []varTest{
   292  		{"a1", true, "\"foofoofoofoofoofoo\"", "", "string", nil},
   293  		{"a11", true, `[3]main.FooBar [
   294  	{Baz: 1, Bur: "a"},
   295  	{Baz: 2, Bur: "b"},
   296  	{Baz: 3, Bur: "c"},
   297  ]`, "", "[3]main.FooBar", nil},
   298  		{"a12", true, `[]main.FooBar len: 2, cap: 2, [
   299  	{Baz: 4, Bur: "d"},
   300  	{Baz: 5, Bur: "e"},
   301  ]`, "", "[]main.FooBar", nil},
   302  		{"a13", true, `[]*main.FooBar len: 3, cap: 3, [
   303  	*{Baz: 6, Bur: "f"},
   304  	*{Baz: 7, Bur: "g"},
   305  	*{Baz: 8, Bur: "h"},
   306  ]`, "", "[]*main.FooBar", nil},
   307  		{"a2", true, "6", "10", "int", nil},
   308  		{"a4", true, "[2]int [1,2]", "", "[2]int", nil},
   309  		{"a5", true, "[]int len: 5, cap: 5, [1,2,3,4,5]", "", "[]int", nil},
   310  		{"a6", true, "main.FooBar {Baz: 8, Bur: \"word\"}", "", "main.FooBar", nil},
   311  		{"a7", true, "*main.FooBar {Baz: 5, Bur: \"strum\"}", "", "*main.FooBar", nil},
   312  		{"a8", true, "main.FooBar2 {Bur: 10, Baz: \"feh\"}", "", "main.FooBar2", nil},
   313  		{"a9", true, "*main.FooBar nil", "", "*main.FooBar", nil},
   314  		{"a8", true, "main.FooBar2 {Bur: 10, Baz: \"feh\"}", "", "main.FooBar2", nil}, // reread variable after member
   315  		{"i32", true, "[2]int32 [1,2]", "", "[2]int32", nil},
   316  		{"ba", true, "[]int len: 200, cap: 200, [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,...+136 more]", "", "[]int", nil},
   317  		{"ms", true, `main.Nest {
   318  	Level: 0,
   319  	Nest: *main.Nest {
   320  		Level: 1,
   321  		Nest: *(*main.Nest)(…`, "", "main.Nest", nil},
   322  	}
   323  
   324  	protest.AllowRecording(t)
   325  	withTestProcess("testvariables", t, func(p *proc.Target, fixture protest.Fixture) {
   326  		err := p.Continue()
   327  		assertNoError(err, t, "Continue() returned an error")
   328  
   329  		for _, tc := range testcases {
   330  			variable, err := evalVariableWithCfg(p, tc.name, pnormalLoadConfig)
   331  			assertNoError(err, t, "EvalVariable() returned an error")
   332  			if ms := api.ConvertVar(variable).MultilineString("", ""); !matchStringOrPrefix(ms, tc.value) {
   333  				t.Fatalf("Expected %s got %s (variable %s)\n", tc.value, ms, variable.Name)
   334  			}
   335  		}
   336  	})
   337  }
   338  
   339  type varArray []*proc.Variable
   340  
   341  // Len is part of sort.Interface.
   342  func (s varArray) Len() int {
   343  	return len(s)
   344  }
   345  
   346  // Swap is part of sort.Interface.
   347  func (s varArray) Swap(i, j int) {
   348  	s[i], s[j] = s[j], s[i]
   349  }
   350  
   351  // Less is part of sort.Interface. It is implemented by calling the "by" closure in the sorter.
   352  func (s varArray) Less(i, j int) bool {
   353  	return s[i].Name < s[j].Name
   354  }
   355  
   356  func TestLocalVariables(t *testing.T) {
   357  	testcases := []struct {
   358  		fn     func(*proc.EvalScope, proc.LoadConfig) ([]*proc.Variable, error)
   359  		output []varTest
   360  	}{
   361  		{(*proc.EvalScope).LocalVariables,
   362  			[]varTest{
   363  				{"a1", true, "\"foofoofoofoofoofoo\"", "", "string", nil},
   364  				{"a10", true, "\"ofo\"", "", "string", nil},
   365  				{"a11", true, "[3]main.FooBar [{Baz: 1, Bur: \"a\"},{Baz: 2, Bur: \"b\"},{Baz: 3, Bur: \"c\"}]", "", "[3]main.FooBar", nil},
   366  				{"a12", true, "[]main.FooBar len: 2, cap: 2, [{Baz: 4, Bur: \"d\"},{Baz: 5, Bur: \"e\"}]", "", "[]main.FooBar", nil},
   367  				{"a13", true, "[]*main.FooBar len: 3, cap: 3, [*{Baz: 6, Bur: \"f\"},*{Baz: 7, Bur: \"g\"},*{Baz: 8, Bur: \"h\"}]", "", "[]*main.FooBar", nil},
   368  				{"a2", true, "6", "", "int", nil},
   369  				{"a3", true, "7.23", "", "float64", nil},
   370  				{"a4", true, "[2]int [1,2]", "", "[2]int", nil},
   371  				{"a5", true, "[]int len: 5, cap: 5, [1,2,3,4,5]", "", "[]int", nil},
   372  				{"a6", true, "main.FooBar {Baz: 8, Bur: \"word\"}", "", "main.FooBar", nil},
   373  				{"a7", true, "*main.FooBar {Baz: 5, Bur: \"strum\"}", "", "*main.FooBar", nil},
   374  				{"a8", true, "main.FooBar2 {Bur: 10, Baz: \"feh\"}", "", "main.FooBar2", nil},
   375  				{"a9", true, "*main.FooBar nil", "", "*main.FooBar", nil},
   376  				{"b1", true, "true", "", "bool", nil},
   377  				{"b2", true, "false", "", "bool", nil},
   378  				{"ba", true, "[]int len: 200, cap: 200, [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,...+136 more]", "", "[]int", nil},
   379  				{"c128", true, "(2 + 3i)", "", "complex128", nil},
   380  				{"c64", true, "(1 + 2i)", "", "complex64", nil},
   381  				{"f", true, "main.barfoo", "", "func()", nil},
   382  				{"f32", true, "1.2", "", "float32", nil},
   383  				{"i32", true, "[2]int32 [1,2]", "", "[2]int32", nil},
   384  				{"i8", true, "1", "", "int8", nil},
   385  				{"mp", true, "map[int]interface {} [1: 42, 2: 43, ]", "", "map[int]interface {}", nil},
   386  				{"ms", true, "main.Nest {Level: 0, Nest: *main.Nest {Level: 1, Nest: *(*main.Nest)…", "", "main.Nest", nil},
   387  				{"neg", true, "-1", "", "int", nil},
   388  				{"ni", true, "[]interface {} len: 1, cap: 1, [[]interface {} len: 1, cap: 1, [*(*interface {})…", "", "[]interface {}", nil},
   389  				{"u16", true, "65535", "", "uint16", nil},
   390  				{"u32", true, "4294967295", "", "uint32", nil},
   391  				{"u64", true, "18446744073709551615", "", "uint64", nil},
   392  				{"u8", true, "255", "", "uint8", nil},
   393  				{"up", true, "5", "", "uintptr", nil}}},
   394  		{(*proc.EvalScope).FunctionArguments,
   395  			[]varTest{
   396  				{"bar", true, "main.FooBar {Baz: 10, Bur: \"lorem\"}", "", "main.FooBar", nil},
   397  				{"baz", true, "\"bazburzum\"", "", "string", nil}}},
   398  	}
   399  
   400  	protest.AllowRecording(t)
   401  	withTestProcess("testvariables", t, func(p *proc.Target, fixture protest.Fixture) {
   402  		err := p.Continue()
   403  		assertNoError(err, t, "Continue() returned an error")
   404  
   405  		for _, tc := range testcases {
   406  			var scope *proc.EvalScope
   407  			var err error
   408  
   409  			if testBackend == "rr" || testBackend == "undo" {
   410  				var frame proc.Stackframe
   411  				frame, err = findFirstNonRuntimeFrame(p)
   412  				if err == nil {
   413  					scope = proc.FrameToScope(p, p.Memory(), nil, frame)
   414  				}
   415  			} else {
   416  				scope, err = proc.GoroutineScope(p, p.CurrentThread())
   417  			}
   418  
   419  			assertNoError(err, t, "scope")
   420  			vars, err := tc.fn(scope, pnormalLoadConfig)
   421  			assertNoError(err, t, "LocalVariables() returned an error")
   422  
   423  			sort.Sort(varArray(vars))
   424  
   425  			if len(tc.output) != len(vars) {
   426  				t.Fatalf("Invalid variable count. Expected %d got %d.", len(tc.output), len(vars))
   427  			}
   428  
   429  			for i, variable := range vars {
   430  				assertVariable(t, variable, tc.output[i])
   431  			}
   432  		}
   433  	})
   434  }
   435  
   436  func TestEmbeddedStruct(t *testing.T) {
   437  	protest.AllowRecording(t)
   438  	withTestProcess("testvariables2", t, func(p *proc.Target, fixture protest.Fixture) {
   439  		testcases := []varTest{
   440  			{"b.val", true, "-314", "-314", "int", nil},
   441  			{"b.A.val", true, "-314", "-314", "int", nil},
   442  			{"b.a.val", true, "42", "42", "int", nil},
   443  			{"b.ptr.val", true, "1337", "1337", "int", nil},
   444  			{"b.C.s", true, "\"hello\"", "\"hello\"", "string", nil},
   445  			{"b.s", true, "\"hello\"", "\"hello\"", "string", nil},
   446  			{"b2", true, "main.B {A: main.A {val: 42}, C: *main.C nil, a: main.A {val: 47}, ptr: *main.A nil}", "main.B {A: (*main.A)(0x…", "main.B", nil},
   447  
   448  			// Issue 2316: field promotion is breadth first and embedded interfaces never get promoted
   449  			{"w2.W1.T.F", true, `"T-inside-W1"`, `"T-inside-W1"`, "string", nil},
   450  			{"w2.W1.F", true, `"T-inside-W1"`, `"T-inside-W1"`, "string", nil},
   451  			{"w2.T.F", true, `"T-inside-W2"`, `"T-inside-W2"`, "string", nil},
   452  			{"w2.F", true, `"T-inside-W2"`, `"T-inside-W2"`, "string", nil},
   453  			{"w3.I.T.F", false, `"T-inside-W1"`, `"T-inside-W1"`, "string", nil},
   454  			{"w3.I.F", false, `"T-inside-W1"`, `"T-inside-W1"`, "string", nil},
   455  			{"w3.T.F", true, `"T-inside-W3"`, `"T-inside-W3"`, "string", nil},
   456  			{"w3.F", true, `"T-inside-W3"`, `"T-inside-W3"`, "string", nil},
   457  			{"w4.I.T.F", false, `"T-inside-W1"`, `"T-inside-W1"`, "string", nil},
   458  			{"w4.I.F", false, `"T-inside-W1"`, `"T-inside-W1"`, "string", nil},
   459  			{"w4.F", false, ``, ``, "", errors.New("w4 has no member F")},
   460  			{"w5.F", false, ``, ``, "", errors.New("w5 has no member F")},
   461  		}
   462  		assertNoError(p.Continue(), t, "Continue()")
   463  
   464  		ver, _ := goversion.Parse(runtime.Version())
   465  		if ver.Major >= 0 && !ver.AfterOrEqual(goversion.GoVersion{Major: 1, Minor: 9, Rev: -1}) {
   466  			// on go < 1.9 embedded fields had different names
   467  			for i := range testcases {
   468  				if testcases[i].name == "b2" {
   469  					testcases[i].value = "main.B {main.A: main.A {val: 42}, *main.C: *main.C nil, a: main.A {val: 47}, ptr: *main.A nil}"
   470  					testcases[i].alternate = "main.B {main.A: (*main.A)(0x…"
   471  				}
   472  			}
   473  		}
   474  
   475  		for _, tc := range testcases {
   476  			variable, err := evalVariableWithCfg(p, tc.name, pnormalLoadConfig)
   477  			if tc.err == nil {
   478  				assertNoError(err, t, fmt.Sprintf("EvalVariable(%s) returned an error", tc.name))
   479  				assertVariable(t, variable, tc)
   480  				variable, err = evalVariableWithCfg(p, tc.name, pshortLoadConfig)
   481  				assertNoError(err, t, fmt.Sprintf("EvalVariable(%s, pshortLoadConfig) returned an error", tc.name))
   482  				assertVariable(t, variable, tc.alternateVarTest())
   483  			} else {
   484  				if tc.err.Error() != err.Error() {
   485  					t.Fatalf("Unexpected error. Expected %s got %s", tc.err.Error(), err.Error())
   486  				}
   487  			}
   488  		}
   489  	})
   490  }
   491  
   492  func TestComplexSetting(t *testing.T) {
   493  	withTestProcess("testvariables", t, func(p *proc.Target, fixture protest.Fixture) {
   494  		err := p.Continue()
   495  		assertNoError(err, t, "Continue() returned an error")
   496  
   497  		h := func(setExpr, value string) {
   498  			assertNoError(setVariable(p, "c128", setExpr), t, "SetVariable()")
   499  			variable, err := evalVariableWithCfg(p, "c128", pnormalLoadConfig)
   500  			assertNoError(err, t, "EvalVariable()")
   501  			if s := api.ConvertVar(variable).SinglelineString(); s != value {
   502  				t.Fatalf("Wrong value of c128: \"%s\", expected \"%s\" after setting it to \"%s\"", s, value, setExpr)
   503  			}
   504  		}
   505  
   506  		h("3.2i", "(0 + 3.2i)")
   507  		h("1.1", "(1.1 + 0i)")
   508  		h("1 + 3.3i", "(1 + 3.3i)")
   509  		h("complex(1.2, 3.4)", "(1.2 + 3.4i)")
   510  	})
   511  }
   512  
   513  func TestEvalExpression(t *testing.T) {
   514  	testcases := []varTest{
   515  		// slice/array/string subscript
   516  		{"s1[0]", false, "\"one\"", "\"one\"", "string", nil},
   517  		{"s1[1]", false, "\"two\"", "\"two\"", "string", nil},
   518  		{"s1[2]", false, "\"three\"", "\"three\"", "string", nil},
   519  		{"s1[3]", false, "\"four\"", "\"four\"", "string", nil},
   520  		{"s1[4]", false, "\"five\"", "\"five\"", "string", nil},
   521  		{"s1[5]", false, "", "", "string", fmt.Errorf("index out of bounds")},
   522  		{"a1[0]", false, "\"one\"", "\"one\"", "string", nil},
   523  		{"a1[1]", false, "\"two\"", "\"two\"", "string", nil},
   524  		{"a1[2]", false, "\"three\"", "\"three\"", "string", nil},
   525  		{"a1[3]", false, "\"four\"", "\"four\"", "string", nil},
   526  		{"a1[4]", false, "\"five\"", "\"five\"", "string", nil},
   527  		{"a1[5]", false, "", "", "string", fmt.Errorf("index out of bounds")},
   528  		{"str1[0]", false, "48", "48", "byte", nil},
   529  		{"str1[1]", false, "49", "49", "byte", nil},
   530  		{"str1[2]", false, "50", "50", "byte", nil},
   531  		{"str1[10]", false, "48", "48", "byte", nil},
   532  		{"str1[11]", false, "", "", "byte", fmt.Errorf("index out of bounds")},
   533  
   534  		// slice/array/string reslicing
   535  		{"a1[2:4]", false, "[]string len: 2, cap: 2, [\"three\",\"four\"]", "[]string len: 2, cap: 2, [...]", "[]string", nil},
   536  		{"s1[2:4]", false, "[]string len: 2, cap: 2, [\"three\",\"four\"]", "[]string len: 2, cap: 2, [...]", "[]string", nil},
   537  		{"str1[2:4]", false, "\"23\"", "\"23\"", "string", nil},
   538  		{"str1[0:11]", false, "\"01234567890\"", "\"01234567890\"", "string", nil},
   539  		{"str1[:3]", false, "\"012\"", "\"012\"", "string", nil},
   540  		{"str1[3:]", false, "\"34567890\"", "\"34567890\"", "string", nil},
   541  		{"str1[0:12]", false, "", "", "string", fmt.Errorf("index out of bounds")},
   542  		{"str1[5:3]", false, "", "", "string", fmt.Errorf("index out of bounds")},
   543  		{"str1[11:]", false, "\"\"", "\"\"", "string", nil},
   544  
   545  		// NaN and Inf floats
   546  		{"pinf", false, "+Inf", "+Inf", "float64", nil},
   547  		{"ninf", false, "-Inf", "-Inf", "float64", nil},
   548  		{"nan", false, "NaN", "NaN", "float64", nil},
   549  
   550  		// pointers
   551  		{"*p2", false, "5", "5", "int", nil},
   552  		{"p2", true, "*5", "(*int)(0x…", "*int", nil},
   553  		{"p3", true, "*int nil", "*int nil", "*int", nil},
   554  		{"*p3", false, "", "", "int", fmt.Errorf("nil pointer dereference")},
   555  
   556  		// channels
   557  		{"ch1", true, "chan int 4/11", "chan int 4/11", "chan int", nil},
   558  		{"chnil", true, "chan int nil", "chan int nil", "chan int", nil},
   559  		{"ch1+1", false, "", "", "", fmt.Errorf("can not convert 1 constant to chan int")},
   560  
   561  		// maps
   562  		{"m1[\"Malone\"]", false, "main.astruct {A: 2, B: 3}", "main.astruct {A: 2, B: 3}", "main.astruct", nil},
   563  		{"m2[1].B", false, "11", "11", "int", nil},
   564  		{"m2[c1.sa[2].B-4].A", false, "10", "10", "int", nil},
   565  		{"m2[*p1].B", false, "11", "11", "int", nil},
   566  		{"m3[as1]", false, "42", "42", "int", nil},
   567  		{"mnil[\"Malone\"]", false, "", "", "", fmt.Errorf("key not found")},
   568  		{"m1[80:]", false, "", "", "", fmt.Errorf("map index out of bounds")},
   569  
   570  		// interfaces
   571  		{"err1", true, "error(*main.astruct) *{A: 1, B: 2}", "error(*main.astruct) 0x…", "error", nil},
   572  		{"err2", true, "error(*main.bstruct) *{a: main.astruct {A: 1, B: 2}}", "error(*main.bstruct) 0x…", "error", nil},
   573  		{"errnil", true, "error nil", "error nil", "error", nil},
   574  		{"iface1", true, "interface {}(*main.astruct) *{A: 1, B: 2}", "interface {}(*main.astruct) 0x…", "interface {}", nil},
   575  		{"iface1.A", false, "1", "1", "int", nil},
   576  		{"iface1.B", false, "2", "2", "int", nil},
   577  		{"iface2", true, "interface {}(string) \"test\"", "interface {}(string) \"test\"", "interface {}", nil},
   578  		{"iface3", true, "interface {}(map[string]go/constant.Value) []", "interface {}(map[string]go/constant.Value) []", "interface {}", nil},
   579  		{"iface4", true, "interface {}([]go/constant.Value) [4]", "interface {}([]go/constant.Value) [...]", "interface {}", nil},
   580  		{"ifacenil", true, "interface {} nil", "interface {} nil", "interface {}", nil},
   581  		{"err1 == err2", false, "false", "false", "", nil},
   582  		{"err1 == iface1", false, "", "", "", fmt.Errorf("mismatched types \"error\" and \"interface {}\"")},
   583  		{"errnil == nil", false, "true", "true", "", nil},
   584  		{"errtypednil == nil", false, "false", "false", "", nil},
   585  		{"nil == errnil", false, "true", "true", "", nil},
   586  		{"err1.(*main.astruct)", false, "*main.astruct {A: 1, B: 2}", "(*main.astruct)(0x…", "*main.astruct", nil},
   587  		{"err1.(*main.bstruct)", false, "", "", "", fmt.Errorf("interface conversion: error is *main.astruct, not *main.bstruct")},
   588  		{"errnil.(*main.astruct)", false, "", "", "", fmt.Errorf("interface conversion: error is nil, not *main.astruct")},
   589  		{"const1", true, "go/constant.Value(go/constant.int64Val) 3", "go/constant.Value(go/constant.int64Val) 3", "go/constant.Value", nil},
   590  
   591  		// combined expressions
   592  		{"c1.pb.a.A", true, "1", "1", "int", nil},
   593  		{"c1.sa[1].B", false, "3", "3", "int", nil},
   594  		{"s2[5].B", false, "12", "12", "int", nil},
   595  		{"s2[c1.sa[2].B].A", false, "11", "11", "int", nil},
   596  		{"s2[*p2].B", false, "12", "12", "int", nil},
   597  
   598  		// constants
   599  		{"1.1", false, "1.1", "1.1", "", nil},
   600  		{"10", false, "10", "10", "", nil},
   601  		{"1 + 2i", false, "(1 + 2i)", "(1 + 2i)", "", nil},
   602  		{"true", false, "true", "true", "", nil},
   603  		{"\"test\"", false, "\"test\"", "\"test\"", "", nil},
   604  
   605  		// binary operators
   606  		{"i2 + i3", false, "5", "5", "int", nil},
   607  		{"i2 - i3", false, "-1", "-1", "int", nil},
   608  		{"i3 - i2", false, "1", "1", "int", nil},
   609  		{"i2 * i3", false, "6", "6", "int", nil},
   610  		{"i2/i3", false, "0", "0", "int", nil},
   611  		{"f1/2.0", false, "1.5", "1.5", "float64", nil},
   612  		{"i2 << 2", false, "8", "8", "int", nil},
   613  
   614  		// unary operators
   615  		{"-i2", false, "-2", "-2", "int", nil},
   616  		{"+i2", false, "2", "2", "int", nil},
   617  		{"^i2", false, "-3", "-3", "int", nil},
   618  
   619  		// comparison operators
   620  		{"i2 == i3", false, "false", "false", "", nil},
   621  		{"i2 == 2", false, "true", "true", "", nil},
   622  		{"i2 == 2", false, "true", "true", "", nil},
   623  		{"i2 == 3", false, "false", "false", "", nil},
   624  		{"i2 != i3", false, "true", "true", "", nil},
   625  		{"i2 < i3", false, "true", "true", "", nil},
   626  		{"i2 <= i3", false, "true", "true", "", nil},
   627  		{"i2 > i3", false, "false", "false", "", nil},
   628  		{"i2 >= i3", false, "false", "false", "", nil},
   629  		{"i2 >= 2", false, "true", "true", "", nil},
   630  		{"str1 == \"01234567890\"", false, "true", "true", "", nil},
   631  		{"str1 < \"01234567890\"", false, "false", "false", "", nil},
   632  		{"str1 < \"11234567890\"", false, "true", "true", "", nil},
   633  		{"str1 > \"00234567890\"", false, "true", "true", "", nil},
   634  		{"str1 == str1", false, "true", "true", "", nil},
   635  		{"c1.pb.a == *(c1.sa[0])", false, "true", "true", "", nil},
   636  		{"c1.pb.a != *(c1.sa[0])", false, "false", "false", "", nil},
   637  		{"c1.pb.a == *(c1.sa[1])", false, "false", "false", "", nil},
   638  		{"c1.pb.a != *(c1.sa[1])", false, "true", "true", "", nil},
   639  		{`longstr == "not this"`, false, "false", "false", "", nil},
   640  
   641  		// builtins
   642  		{"cap(parr)", false, "4", "4", "", nil},
   643  		{"len(parr)", false, "4", "4", "", nil},
   644  		{"cap(p1)", false, "", "", "", fmt.Errorf("invalid argument p1 (type *int) for cap")},
   645  		{"len(p1)", false, "", "", "", fmt.Errorf("invalid argument p1 (type *int) for len")},
   646  		{"cap(a1)", false, "5", "5", "", nil},
   647  		{"len(a1)", false, "5", "5", "", nil},
   648  		{"cap(s3)", false, "6", "6", "", nil},
   649  		{"len(s3)", false, "0", "0", "", nil},
   650  		{"cap(nilslice)", false, "0", "0", "", nil},
   651  		{"len(nilslice)", false, "0", "0", "", nil},
   652  		{"cap(ch1)", false, "11", "11", "", nil},
   653  		{"len(ch1)", false, "4", "4", "", nil},
   654  		{"cap(chnil)", false, "0", "0", "", nil},
   655  		{"len(chnil)", false, "0", "0", "", nil},
   656  		{"len(m1)", false, "66", "66", "", nil},
   657  		{"len(mnil)", false, "0", "0", "", nil},
   658  		{"imag(cpx1)", false, "2", "2", "", nil},
   659  		{"real(cpx1)", false, "1", "1", "", nil},
   660  		{"imag(3i)", false, "3", "3", "", nil},
   661  		{"real(4)", false, "4", "4", "", nil},
   662  
   663  		// nil
   664  		{"nil", false, "nil", "nil", "", nil},
   665  		{"nil+1", false, "", "", "", fmt.Errorf("operator + can not be applied to \"nil\"")},
   666  		{"fn1", false, "main.afunc", "main.afunc", "main.functype", nil},
   667  		{"fn2", false, "nil", "nil", "main.functype", nil},
   668  		{"nilslice", false, "[]int len: 0, cap: 0, nil", "[]int len: 0, cap: 0, nil", "[]int", nil},
   669  		{"fn1 == fn2", false, "", "", "", fmt.Errorf("can not compare func variables")},
   670  		{"fn1 == nil", false, "false", "false", "", nil},
   671  		{"fn1 != nil", false, "true", "true", "", nil},
   672  		{"fn2 == nil", false, "true", "true", "", nil},
   673  		{"fn2 != nil", false, "false", "false", "", nil},
   674  		{"c1.sa == nil", false, "false", "false", "", nil},
   675  		{"c1.sa != nil", false, "true", "true", "", nil},
   676  		{"c1.sa[0] == nil", false, "false", "false", "", nil},
   677  		{"c1.sa[0] != nil", false, "true", "true", "", nil},
   678  		{"nilslice == nil", false, "true", "true", "", nil},
   679  		{"nil == nilslice", false, "true", "true", "", nil},
   680  		{"nilslice != nil", false, "false", "false", "", nil},
   681  		{"nilptr == nil", false, "true", "true", "", nil},
   682  		{"nilptr != nil", false, "false", "false", "", nil},
   683  		{"p1 == nil", false, "false", "false", "", nil},
   684  		{"p1 != nil", false, "true", "true", "", nil},
   685  		{"ch1 == nil", false, "false", "false", "", nil},
   686  		{"chnil == nil", false, "true", "true", "", nil},
   687  		{"ch1 == chnil", false, "", "", "", fmt.Errorf("can not compare chan variables")},
   688  		{"m1 == nil", false, "false", "false", "", nil},
   689  		{"mnil == m1", false, "", "", "", fmt.Errorf("can not compare map variables")},
   690  		{"mnil == nil", false, "true", "true", "", nil},
   691  		{"nil == 2", false, "", "", "", fmt.Errorf("can not compare int to nil")},
   692  		{"2 == nil", false, "", "", "", fmt.Errorf("can not compare int to nil")},
   693  
   694  		// errors
   695  		{"&3", false, "", "", "", fmt.Errorf("can not take address of \"3\"")},
   696  		{"*3", false, "", "", "", fmt.Errorf("expression \"3\" (int) can not be dereferenced")},
   697  		{"&(i2 + i3)", false, "", "", "", fmt.Errorf("can not take address of \"(i2 + i3)\"")},
   698  		{"i2 + p1", false, "", "", "", fmt.Errorf("mismatched types \"int\" and \"*int\"")},
   699  		{"i2 + f1", false, "", "", "", fmt.Errorf("mismatched types \"int\" and \"float64\"")},
   700  		{"i2 << f1", false, "", "", "", fmt.Errorf("shift count type float64, must be unsigned integer")},
   701  		{"i2 << -1", false, "", "", "", fmt.Errorf("shift count must not be negative")},
   702  		{"*(i2 + i3)", false, "", "", "", fmt.Errorf("expression \"(i2 + i3)\" (int) can not be dereferenced")},
   703  		{"i2.member", false, "", "", "", fmt.Errorf("i2 (type int) is not a struct")},
   704  		{"fmt.Println(\"hello\")", false, "", "", "", fmt.Errorf("function calls not allowed without using 'call'")},
   705  		{"*nil", false, "", "", "", fmt.Errorf("nil can not be dereferenced")},
   706  		{"!nil", false, "", "", "", fmt.Errorf("operator ! can not be applied to \"nil\"")},
   707  		{"&nil", false, "", "", "", fmt.Errorf("can not take address of \"nil\"")},
   708  		{"nil[0]", false, "", "", "", fmt.Errorf("expression \"nil\" (nil) does not support indexing")},
   709  		{"nil[2:10]", false, "", "", "", fmt.Errorf("can not slice \"nil\" (type nil)")},
   710  		{"nil.member", false, "", "", "", fmt.Errorf("nil (type nil) is not a struct")},
   711  		{"(map[string]main.astruct)(0x4000)", false, "", "", "", fmt.Errorf("can not convert \"0x4000\" to map[string]main.astruct")},
   712  
   713  		// typecasts
   714  		{"uint(i2)", false, "2", "2", "uint", nil},
   715  		{"int8(i2)", false, "2", "2", "int8", nil},
   716  		{"int(f1)", false, "3", "3", "int", nil},
   717  		{"complex128(f1)", false, "(3 + 0i)", "(3 + 0i)", "complex128", nil},
   718  		{"uint8(i4)", false, "32", "32", "uint8", nil},
   719  		{"uint8(i5)", false, "253", "253", "uint8", nil},
   720  		{"int8(i5)", false, "-3", "-3", "int8", nil},
   721  		{"int8(i6)", false, "12", "12", "int8", nil},
   722  		{"string(byteslice[0])", false, `"t"`, `"t"`, "string", nil},
   723  		{"string(runeslice[0])", false, `"t"`, `"t"`, "string", nil},
   724  
   725  		// misc
   726  		{"i1", true, "1", "1", "int", nil},
   727  		{"mainMenu", true, `main.Menu len: 3, cap: 3, [{Name: "home", Route: "/", Active: 1},{Name: "About", Route: "/about", Active: 1},{Name: "Login", Route: "/login", Active: 1}]`, `main.Menu len: 3, cap: 3, [...]`, "main.Menu", nil},
   728  		{"mainMenu[0]", false, `main.Item {Name: "home", Route: "/", Active: 1}`, `main.Item {Name: "home", Route: "/", Active: 1}`, "main.Item", nil},
   729  		{"sd", false, "main.D {u1: 0, u2: 0, u3: 0, u4: 0, u5: 0, u6: 0}", "main.D {u1: 0, u2: 0, u3: 0,...+3 more}", "main.D", nil},
   730  
   731  		{"ifacearr", false, "[]error len: 2, cap: 2, [*main.astruct {A: 0, B: 0},nil]", "[]error len: 2, cap: 2, [...]", "[]error", nil},
   732  		{"efacearr", false, `[]interface {} len: 3, cap: 3, [*main.astruct {A: 0, B: 0},"test",nil]`, "[]interface {} len: 3, cap: 3, [...]", "[]interface {}", nil},
   733  
   734  		{"zsslice", false, `[]struct {} len: 3, cap: 3, [{},{},{}]`, `[]struct {} len: 3, cap: 3, [...]`, "[]struct {}", nil},
   735  		{"zsvmap", false, `map[string]struct {} ["testkey": {}, ]`, `map[string]struct {} [...]`, "map[string]struct {}", nil},
   736  		{"tm", false, "main.truncatedMap {v: []map[string]main.astruct len: 1, cap: 1, [[...]]}", "main.truncatedMap {v: []map[string]main.astruct len: 1, cap: 1, [...]}", "main.truncatedMap", nil},
   737  
   738  		{"emptyslice", false, `[]string len: 0, cap: 0, []`, `[]string len: 0, cap: 0, []`, "[]string", nil},
   739  		{"emptymap", false, `map[string]string []`, `map[string]string []`, "map[string]string", nil},
   740  		{"mnil", false, `map[string]main.astruct nil`, `map[string]main.astruct nil`, "map[string]main.astruct", nil},
   741  
   742  		// conversions between string/[]byte/[]rune (issue #548)
   743  		{"runeslice", true, `[]int32 len: 4, cap: 4, [116,232,115,116]`, `[]int32 len: 4, cap: 4, [...]`, "[]int32", nil},
   744  		{"byteslice", true, `[]uint8 len: 5, cap: 5, [116,195,168,115,116]`, `[]uint8 len: 5, cap: 5, [...]`, "[]uint8", nil},
   745  		{"[]byte(str1)", false, `[]uint8 len: 11, cap: 11, [48,49,50,51,52,53,54,55,56,57,48]`, `[]uint8 len: 11, cap: 11, [48,49,50,51,52,53,54,55,56,57,48]`, "[]uint8", nil},
   746  		{"[]uint8(str1)", false, `[]uint8 len: 11, cap: 11, [48,49,50,51,52,53,54,55,56,57,48]`, `[]uint8 len: 11, cap: 11, [48,49,50,51,52,53,54,55,56,57,48]`, "[]uint8", nil},
   747  		{"[]rune(str1)", false, `[]int32 len: 11, cap: 11, [48,49,50,51,52,53,54,55,56,57,48]`, `[]int32 len: 11, cap: 11, [48,49,50,51,52,53,54,55,56,57,48]`, "[]int32", nil},
   748  		{"[]int32(str1)", false, `[]int32 len: 11, cap: 11, [48,49,50,51,52,53,54,55,56,57,48]`, `[]int32 len: 11, cap: 11, [48,49,50,51,52,53,54,55,56,57,48]`, "[]int32", nil},
   749  		{"string(byteslice)", false, `"tèst"`, `""`, "string", nil},
   750  		{"[]int32(string(byteslice))", false, `[]int32 len: 4, cap: 4, [116,232,115,116]`, `[]int32 len: 0, cap: 0, nil`, "[]int32", nil},
   751  		{"string(runeslice)", false, `"tèst"`, `""`, "string", nil},
   752  		{"[]byte(string(runeslice))", false, `[]uint8 len: 5, cap: 5, [116,195,168,115,116]`, `[]uint8 len: 0, cap: 0, nil`, "[]uint8", nil},
   753  		{"*(*[5]byte)(uintptr(&byteslice[0]))", false, `[5]uint8 [116,195,168,115,116]`, `[5]uint8 [...]`, "[5]uint8", nil},
   754  		{"string(bytearray)", false, `"tèst"`, `""`, "string", nil},
   755  		{"string(runearray)", false, `"tèst"`, `""`, "string", nil},
   756  		{"string(str1)", false, `"01234567890"`, `"01234567890"`, "string", nil},
   757  
   758  		// access to channel field members
   759  		{"ch1.qcount", false, "4", "4", "uint", nil},
   760  		{"ch1.dataqsiz", false, "11", "11", "uint", nil},
   761  		{"ch1.buf", false, `*[11]int [1,4,3,2,0,0,0,0,0,0,0]`, `(*[11]int)(…`, "*[11]int", nil},
   762  		{"ch1.buf[0]", false, "1", "1", "int", nil},
   763  
   764  		// shortcircuited logical operators
   765  		{"nilstruct != nil && nilstruct.A == 1", false, "false", "false", "", nil},
   766  		{"nilstruct == nil || nilstruct.A == 1", false, "true", "true", "", nil},
   767  
   768  		{"afunc", true, `main.afunc`, `main.afunc`, `func()`, nil},
   769  		{"main.afunc2", true, `main.afunc2`, `main.afunc2`, `func()`, nil},
   770  
   771  		{"s2[0].Error", false, "main.(*astruct).Error", "main.(*astruct).Error", "func() string", nil},
   772  		{"s2[0].NonPointerRecieverMethod", false, "main.astruct.NonPointerRecieverMethod", "main.astruct.NonPointerRecieverMethod", "func()", nil},
   773  		{"as2.Error", false, "main.(*astruct).Error", "main.(*astruct).Error", "func() string", nil},
   774  		{"as2.NonPointerRecieverMethod", false, "main.astruct.NonPointerRecieverMethod", "main.astruct.NonPointerRecieverMethod", "func()", nil},
   775  
   776  		{`iface2map.(data)`, false, "…", "…", "map[string]interface {}", nil},
   777  
   778  		{"issue1578", false, "main.Block {cache: *main.Cache nil}", "main.Block {cache: *main.Cache nil}", "main.Block", nil},
   779  		{"ni8 << 2", false, "-20", "-20", "int8", nil},
   780  		{"ni8 << 8", false, "0", "0", "int8", nil},
   781  		{"ni8 >> 1", false, "-3", "-3", "int8", nil},
   782  		{"bytearray[0] * bytearray[0]", false, "144", "144", "uint8", nil},
   783  
   784  		// function call / typecast errors
   785  		{"unknownthing(1, 2)", false, "", "", "", errors.New("function calls not allowed without using 'call'")},
   786  		{"(unknownthing)(1, 2)", false, "", "", "", errors.New("function calls not allowed without using 'call'")},
   787  		{"afunc(2)", false, "", "", "", errors.New("function calls not allowed without using 'call'")},
   788  		{"(afunc)(2)", false, "", "", "", errors.New("function calls not allowed without using 'call'")},
   789  		{"(*afunc)(2)", false, "", "", "", errors.New("could not evaluate function or type (*afunc): expression \"afunc\" (func()) can not be dereferenced")},
   790  		{"unknownthing(2)", false, "", "", "", errors.New("could not evaluate function or type unknownthing: could not find symbol value for unknownthing")},
   791  		{"(*unknownthing)(2)", false, "", "", "", errors.New("could not evaluate function or type (*unknownthing): could not find symbol value for unknownthing")},
   792  		{"(*strings.Split)(2)", false, "", "", "", errors.New("could not evaluate function or type (*strings.Split): could not find symbol value for strings")},
   793  
   794  		// pretty printing special types
   795  		{"tim1", false, `time.Time(1977-05-25T18:00:00Z)…`, `time.Time(1977-05-25T18:00:00Z)…`, "time.Time", nil},
   796  		{"tim2", false, `time.Time(2022-06-07T02:03:04-06:00)…`, `time.Time(2022-06-07T02:03:04-06:00)…`, "time.Time", nil},
   797  
   798  		// issue #3034 - map access with long string key
   799  		{`m6["very long string 0123456789a0123456789b0123456789c0123456789d0123456789e0123456789f0123456789g012345678h90123456789i0123456789j0123456789"]`, false, `123`, `123`, "int", nil},
   800  	}
   801  
   802  	ver, _ := goversion.Parse(runtime.Version())
   803  	if ver.Major >= 0 && !ver.AfterOrEqual(goversion.GoVersion{Major: 1, Minor: 7, Rev: -1}) {
   804  		for i := range testcases {
   805  			if testcases[i].name == "iface3" {
   806  				testcases[i].value = "interface {}(*map[string]go/constant.Value) *[]"
   807  				testcases[i].alternate = "interface {}(*map[string]go/constant.Value) 0x…"
   808  			}
   809  		}
   810  	}
   811  
   812  	protest.AllowRecording(t)
   813  	withTestProcess("testvariables2", t, func(p *proc.Target, fixture protest.Fixture) {
   814  		assertNoError(p.Continue(), t, "Continue() returned an error")
   815  		for _, tc := range testcases {
   816  			variable, err := evalVariableWithCfg(p, tc.name, pnormalLoadConfig)
   817  			if err != nil && err.Error() == "evaluating methods not supported on this version of Go" {
   818  				// this type of eval is unsupported with the current version of Go.
   819  				continue
   820  			}
   821  			if tc.err == nil {
   822  				assertNoError(err, t, fmt.Sprintf("EvalExpression(%s) returned an error", tc.name))
   823  				assertVariable(t, variable, tc)
   824  				variable, err := evalVariableWithCfg(p, tc.name, pshortLoadConfig)
   825  				assertNoError(err, t, fmt.Sprintf("EvalExpression(%s, pshortLoadConfig) returned an error", tc.name))
   826  				assertVariable(t, variable, tc.alternateVarTest())
   827  			} else {
   828  				if err == nil {
   829  					t.Fatalf("Expected error %s, got no error (%s)", tc.err.Error(), tc.name)
   830  				}
   831  				if tc.err.Error() != err.Error() {
   832  					t.Fatalf("Unexpected error. Expected %s got %s", tc.err.Error(), err.Error())
   833  				}
   834  			}
   835  		}
   836  	})
   837  }
   838  
   839  func TestEvalAddrAndCast(t *testing.T) {
   840  	protest.AllowRecording(t)
   841  	withTestProcess("testvariables2", t, func(p *proc.Target, fixture protest.Fixture) {
   842  		assertNoError(p.Continue(), t, "Continue() returned an error")
   843  		c1addr, err := evalVariableWithCfg(p, "&c1", pnormalLoadConfig)
   844  		assertNoError(err, t, "EvalExpression(&c1)")
   845  		c1addrstr := api.ConvertVar(c1addr).SinglelineString()
   846  		t.Logf("&c1 → %s", c1addrstr)
   847  		if !strings.HasPrefix(c1addrstr, "(*main.cstruct)(0x") {
   848  			t.Fatalf("Invalid value of EvalExpression(&c1) \"%s\"", c1addrstr)
   849  		}
   850  
   851  		aaddr, err := evalVariableWithCfg(p, "&(c1.pb.a)", pnormalLoadConfig)
   852  		assertNoError(err, t, "EvalExpression(&(c1.pb.a))")
   853  		aaddrstr := api.ConvertVar(aaddr).SinglelineString()
   854  		t.Logf("&(c1.pb.a) → %s", aaddrstr)
   855  		if !strings.HasPrefix(aaddrstr, "(*main.astruct)(0x") {
   856  			t.Fatalf("invalid value of EvalExpression(&(c1.pb.a)) \"%s\"", aaddrstr)
   857  		}
   858  
   859  		a, err := evalVariableWithCfg(p, "*"+aaddrstr, pnormalLoadConfig)
   860  		assertNoError(err, t, fmt.Sprintf("EvalExpression(*%s)", aaddrstr))
   861  		t.Logf("*%s → %s", aaddrstr, api.ConvertVar(a).SinglelineString())
   862  		assertVariable(t, a, varTest{aaddrstr, false, "main.astruct {A: 1, B: 2}", "", "main.astruct", nil})
   863  	})
   864  }
   865  
   866  func TestMapEvaluation(t *testing.T) {
   867  	protest.AllowRecording(t)
   868  	withTestProcess("testvariables2", t, func(p *proc.Target, fixture protest.Fixture) {
   869  		assertNoError(p.Continue(), t, "Continue() returned an error")
   870  		m1v, err := evalVariableWithCfg(p, "m1", pnormalLoadConfig)
   871  		assertNoError(err, t, "EvalVariable()")
   872  		m1 := api.ConvertVar(m1v)
   873  		t.Logf("m1 = %v", m1.MultilineString("", ""))
   874  
   875  		if m1.Type != "map[string]main.astruct" {
   876  			t.Fatalf("Wrong type: %s", m1.Type)
   877  		}
   878  
   879  		if len(m1.Children)/2 != 64 {
   880  			t.Fatalf("Wrong number of children: %d", len(m1.Children)/2)
   881  		}
   882  
   883  		m1sliced, err := evalVariableWithCfg(p, "m1[64:]", pnormalLoadConfig)
   884  		assertNoError(err, t, "EvalVariable(m1[64:])")
   885  		if len(m1sliced.Children)/2 != int(m1.Len-64) {
   886  			t.Fatalf("Wrong number of children (after slicing): %d", len(m1sliced.Children)/2)
   887  		}
   888  
   889  		countMalone := func(m *api.Variable) int {
   890  			found := 0
   891  			for i := range m.Children {
   892  				if i%2 == 0 && m.Children[i].Value == "Malone" {
   893  					found++
   894  				}
   895  			}
   896  			return found
   897  		}
   898  
   899  		found := countMalone(m1)
   900  		found += countMalone(api.ConvertVar(m1sliced))
   901  
   902  		if found != 1 {
   903  			t.Fatalf("Could not find Malone exactly 1 time: found %d", found)
   904  		}
   905  	})
   906  }
   907  
   908  func TestUnsafePointer(t *testing.T) {
   909  	protest.AllowRecording(t)
   910  	withTestProcess("testvariables2", t, func(p *proc.Target, fixture protest.Fixture) {
   911  		assertNoError(p.Continue(), t, "Continue() returned an error")
   912  		up1v, err := evalVariableWithCfg(p, "up1", pnormalLoadConfig)
   913  		assertNoError(err, t, "EvalVariable(up1)")
   914  		up1 := api.ConvertVar(up1v)
   915  		if ss := up1.SinglelineString(); !strings.HasPrefix(ss, "unsafe.Pointer(") {
   916  			t.Fatalf("wrong value for up1: %s", ss)
   917  		}
   918  	})
   919  }
   920  
   921  type issue426TestCase struct {
   922  	name string
   923  	typ  string
   924  }
   925  
   926  func TestIssue426(t *testing.T) {
   927  	// type casts using quoted type names
   928  	testcases := []issue426TestCase{
   929  		{"iface1", `interface {}`},
   930  		{"mapanonstruct1", `map[string]struct {}`},
   931  		{"anonstruct1", `struct { val go/constant.Value }`},
   932  		{"anonfunc", `func(struct { i int }, interface {}, struct { val go/constant.Value })`},
   933  		{"anonstruct2", `struct { i int; j int }`},
   934  		{"anoniface1", `interface { OtherFunction(int, int); SomeFunction(struct { val go/constant.Value }) }`},
   935  	}
   936  
   937  	ver, _ := goversion.Parse(runtime.Version())
   938  	if ver.Major < 0 || ver.AfterOrEqual(goversion.GoVersion{Major: 1, Minor: 8, Rev: -1}) {
   939  		testcases[2].typ = `struct { main.val go/constant.Value }`
   940  		testcases[3].typ = `func(struct { main.i int }, interface {}, struct { main.val go/constant.Value })`
   941  		testcases[4].typ = `struct { main.i int; main.j int }`
   942  		testcases[5].typ = `interface { OtherFunction(int, int); SomeFunction(struct { main.val go/constant.Value }) }`
   943  	}
   944  
   945  	// Serialization of type expressions (go/ast.Expr) containing anonymous structs or interfaces
   946  	// differs from the serialization used by the linker to produce DWARF type information
   947  	protest.AllowRecording(t)
   948  	withTestProcess("testvariables2", t, func(p *proc.Target, fixture protest.Fixture) {
   949  		assertNoError(p.Continue(), t, "Continue() returned an error")
   950  		for _, testcase := range testcases {
   951  			v, err := evalVariableWithCfg(p, testcase.name, pnormalLoadConfig)
   952  			assertNoError(err, t, fmt.Sprintf("EvalVariable(%s)", testcase.name))
   953  			t.Logf("%s → %s", testcase.name, v.RealType.String())
   954  			expr := fmt.Sprintf("(*%q)(%d)", testcase.typ, v.Addr)
   955  			_, err = evalVariableWithCfg(p, expr, pnormalLoadConfig)
   956  			assertNoError(err, t, fmt.Sprintf("EvalVariable(%s)", expr))
   957  		}
   958  	})
   959  }
   960  
   961  func testPackageRenamesHelper(t *testing.T, p *proc.Target, testcases []varTest) {
   962  	for _, tc := range testcases {
   963  		variable, err := evalVariableWithCfg(p, tc.name, pnormalLoadConfig)
   964  		if tc.err == nil {
   965  			assertNoError(err, t, fmt.Sprintf("EvalExpression(%s) returned an error", tc.name))
   966  			assertVariable(t, variable, tc)
   967  		} else {
   968  			if err == nil {
   969  				t.Fatalf("Expected error %s, got no error (%s)", tc.err.Error(), tc.name)
   970  			}
   971  			if tc.err.Error() != err.Error() {
   972  				t.Fatalf("Unexpected error. Expected %s got %s", tc.err.Error(), err.Error())
   973  			}
   974  		}
   975  	}
   976  }
   977  
   978  func TestPackageRenames(t *testing.T) {
   979  	// Tests that the concrete type of an interface variable is resolved
   980  	// correctly in a few edge cases, in particular:
   981  	// - in the presence of renamed imports
   982  	// - when two packages with the same name are imported
   983  	// - when a package has a canonical name that's different from its
   984  	// path (for example the last element of the path contains a '.' or a
   985  	// '-' or because the package name is different)
   986  	// all of those edge cases are tested within composite types
   987  	testcases := []varTest{
   988  		// Renamed imports
   989  		{"badexpr", true, `interface {}(*go/ast.BadExpr) *{From: 1, To: 2}`, "", "interface {}", nil},
   990  		{"req", true, `interface {}(*net/http.Request) *{Method: "amethod", …`, "", "interface {}", nil},
   991  
   992  		// Package name that doesn't match import path
   993  		{"iface3", true, `interface {}(*github.com/undoio/delve/_fixtures/internal/dir0/renamedpackage.SomeType) *{A: true}`, "", "interface {}", nil},
   994  
   995  		// Interfaces to anonymous types
   996  		{"dir0someType", true, "interface {}(*github.com/undoio/delve/_fixtures/internal/dir0/pkg.SomeType) *{X: 3}", "", "interface {}", nil},
   997  		{"dir1someType", true, "interface {}(github.com/undoio/delve/_fixtures/internal/dir1/pkg.SomeType) {X: 1, Y: 2}", "", "interface {}", nil},
   998  		{"amap3", true, "interface {}(map[github.com/undoio/delve/_fixtures/internal/dir0/pkg.SomeType]github.com/undoio/delve/_fixtures/internal/dir1/pkg.SomeType) [{X: 4}: {X: 5, Y: 6}, ]", "", "interface {}", nil},
   999  		{"anarray", true, `interface {}([2]github.com/undoio/delve/_fixtures/internal/dir0/pkg.SomeType) [{X: 1},{X: 2}]`, "", "interface {}", nil},
  1000  		{"achan", true, `interface {}(chan github.com/undoio/delve/_fixtures/internal/dir0/pkg.SomeType) chan github.com/undoio/delve/_fixtures/internal/dir0/pkg.SomeType 0/0`, "", "interface {}", nil},
  1001  		{"aslice", true, `interface {}([]github.com/undoio/delve/_fixtures/internal/dir0/pkg.SomeType) [{X: 3},{X: 4}]`, "", "interface {}", nil},
  1002  		{"afunc", true, `interface {}(func(github.com/undoio/delve/_fixtures/internal/dir0/pkg.SomeType, github.com/undoio/delve/_fixtures/internal/dir1/pkg.SomeType)) main.main.func1`, "", "interface {}", nil},
  1003  		{"astruct", true, `interface {}(*struct { A github.com/undoio/delve/_fixtures/internal/dir1/pkg.SomeType; B github.com/undoio/delve/_fixtures/internal/dir0/pkg.SomeType }) *{A: github.com/undoio/delve/_fixtures/internal/dir1/pkg.SomeType {X: 1, Y: 2}, B: github.com/undoio/delve/_fixtures/internal/dir0/pkg.SomeType {X: 3}}`, "", "interface {}", nil},
  1004  		{"iface2iface", true, `interface {}(*interface { AMethod(int) int; AnotherMethod(int) int }) **github.com/undoio/delve/_fixtures/internal/dir0/pkg.SomeType {X: 4}`, "", "interface {}", nil},
  1005  
  1006  		{`"dir0/pkg".A`, false, "0", "", "int", nil},
  1007  		{`"dir1/pkg".A`, false, "1", "", "int", nil},
  1008  	}
  1009  
  1010  	testcases_i386 := []varTest{
  1011  		{"amap", true, "interface {}(map[go/ast.BadExpr]net/http.Request) [{From: 2, To: 3}: {Method: \"othermethod\", …", "", "interface {}", nil},
  1012  		{"amap2", true, "interface {}(*map[go/ast.BadExpr]net/http.Request) *[{From: 2, To: 3}: {Method: \"othermethod\", …", "", "interface {}", nil},
  1013  	}
  1014  
  1015  	testcases_64bit := []varTest{
  1016  		{"amap", true, "interface {}(map[go/ast.BadExpr]net/http.Request) [{From: 2, To: 3}: *{Method: \"othermethod\", …", "", "interface {}", nil},
  1017  		{"amap2", true, "interface {}(*map[go/ast.BadExpr]net/http.Request) *[{From: 2, To: 3}: *{Method: \"othermethod\", …", "", "interface {}", nil},
  1018  	}
  1019  
  1020  	testcases1_8 := []varTest{
  1021  		// before 1.9 embedded struct fields have fieldname == type
  1022  		{"astruct2", true, `interface {}(*struct { github.com/undoio/delve/_fixtures/internal/dir1/pkg.SomeType; X int }) *{github.com/undoio/delve/_fixtures/internal/dir1/pkg.SomeType: github.com/undoio/delve/_fixtures/internal/dir1/pkg.SomeType {X: 1, Y: 2}, X: 10}`, "", "interface {}", nil},
  1023  	}
  1024  
  1025  	testcases1_9 := []varTest{
  1026  		{"astruct2", true, `interface {}(*struct { github.com/undoio/delve/_fixtures/internal/dir1/pkg.SomeType; X int }) *{SomeType: github.com/undoio/delve/_fixtures/internal/dir1/pkg.SomeType {X: 1, Y: 2}, X: 10}`, "", "interface {}", nil},
  1027  	}
  1028  
  1029  	testcases1_13 := []varTest{
  1030  		// needs DW_AT_go_package_name attribute added to Go1.13
  1031  		{`dirio.A`, false, `"something"`, "", "string", nil},
  1032  	}
  1033  
  1034  	if !goversion.VersionAfterOrEqual(runtime.Version(), 1, 7) {
  1035  		return
  1036  	}
  1037  
  1038  	protest.AllowRecording(t)
  1039  	withTestProcess("pkgrenames", t, func(p *proc.Target, fixture protest.Fixture) {
  1040  		assertNoError(p.Continue(), t, "Continue() returned an error")
  1041  		testPackageRenamesHelper(t, p, testcases)
  1042  
  1043  		if goversion.VersionAfterOrEqual(runtime.Version(), 1, 9) {
  1044  			testPackageRenamesHelper(t, p, testcases1_9)
  1045  		} else {
  1046  			testPackageRenamesHelper(t, p, testcases1_8)
  1047  		}
  1048  
  1049  		if goversion.VersionAfterOrEqual(runtime.Version(), 1, 13) {
  1050  			testPackageRenamesHelper(t, p, testcases1_13)
  1051  		}
  1052  
  1053  		if runtime.GOARCH == "386" {
  1054  			testPackageRenamesHelper(t, p, testcases_i386)
  1055  		} else {
  1056  			testPackageRenamesHelper(t, p, testcases_64bit)
  1057  		}
  1058  	})
  1059  }
  1060  
  1061  func TestConstants(t *testing.T) {
  1062  	testcases := []varTest{
  1063  		{"a", true, "constTwo (2)", "", "main.ConstType", nil},
  1064  		{"b", true, "constThree (3)", "", "main.ConstType", nil},
  1065  		{"c", true, "bitZero|bitOne (3)", "", "main.BitFieldType", nil},
  1066  		{"d", true, "33", "", "main.BitFieldType", nil},
  1067  		{"e", true, "10", "", "main.ConstType", nil},
  1068  		{"f", true, "0", "", "main.BitFieldType", nil},
  1069  		{"bitZero", true, "1", "", "main.BitFieldType", nil},
  1070  		{"bitOne", true, "2", "", "main.BitFieldType", nil},
  1071  		{"constTwo", true, "2", "", "main.ConstType", nil},
  1072  		{"pkg.SomeConst", false, "2", "", "int", nil},
  1073  	}
  1074  	ver, _ := goversion.Parse(runtime.Version())
  1075  	if ver.Major > 0 && !ver.AfterOrEqual(goversion.GoVersion{Major: 1, Minor: 10, Rev: -1}) {
  1076  		// Not supported on 1.9 or earlier
  1077  		t.Skip("constants added in go 1.10")
  1078  	}
  1079  	protest.AllowRecording(t)
  1080  	withTestProcess("consts", t, func(p *proc.Target, fixture protest.Fixture) {
  1081  		assertNoError(p.Continue(), t, "Continue")
  1082  		for _, testcase := range testcases {
  1083  			variable, err := evalVariableWithCfg(p, testcase.name, pnormalLoadConfig)
  1084  			assertNoError(err, t, fmt.Sprintf("EvalVariable(%s)", testcase.name))
  1085  			assertVariable(t, variable, testcase)
  1086  		}
  1087  	})
  1088  }
  1089  
  1090  func TestIssue1075(t *testing.T) {
  1091  	protest.AllowRecording(t)
  1092  	withTestProcess("clientdo", t, func(p *proc.Target, fixture protest.Fixture) {
  1093  		setFunctionBreakpoint(p, t, "net/http.(*Client).Do")
  1094  		assertNoError(p.Continue(), t, "Continue()")
  1095  		for i := 0; i < 10; i++ {
  1096  			scope, err := proc.GoroutineScope(p, p.CurrentThread())
  1097  			assertNoError(err, t, fmt.Sprintf("GoroutineScope (%d)", i))
  1098  			vars, err := scope.LocalVariables(pnormalLoadConfig)
  1099  			assertNoError(err, t, fmt.Sprintf("LocalVariables (%d)", i))
  1100  			for _, v := range vars {
  1101  				api.ConvertVar(v).SinglelineString()
  1102  			}
  1103  		}
  1104  	})
  1105  }
  1106  
  1107  type testCaseCallFunction struct {
  1108  	expr string   // call expression to evaluate
  1109  	outs []string // list of return parameters in this format: <param name>:<param type>:<param value>
  1110  	err  error    // if not nil should return an error
  1111  }
  1112  
  1113  func TestCallFunction(t *testing.T) {
  1114  	protest.MustSupportFunctionCalls(t, testBackend)
  1115  	protest.AllowRecording(t)
  1116  
  1117  	var testcases = []testCaseCallFunction{
  1118  		// Basic function call injection tests
  1119  
  1120  		{"call1(one, two)", []string{":int:3"}, nil},
  1121  		{"call1(one+two, 4)", []string{":int:7"}, nil},
  1122  		{"callpanic()", []string{`~panic:interface {}:interface {}(string) "callpanic panicked"`}, nil},
  1123  		{`stringsJoin(nil, "")`, []string{`:string:""`}, nil},
  1124  		{`stringsJoin(stringslice, comma)`, []string{`:string:"one,two,three"`}, nil},
  1125  		{`stringsJoin(s1, comma)`, nil, errors.New(`error evaluating "s1" as argument v in function main.stringsJoin: could not find symbol value for s1`)},
  1126  		{`stringsJoin(intslice, comma)`, nil, errors.New("can not convert value of type []int to []string")},
  1127  		{`noreturncall(2)`, nil, nil},
  1128  
  1129  		// Expression tests
  1130  		{`square(2) + 1`, []string{":int:5"}, nil},
  1131  		{`intcallpanic(1) + 1`, []string{":int:2"}, nil},
  1132  		{`intcallpanic(0) + 1`, []string{`~panic:interface {}:interface {}(string) "panic requested"`}, nil},
  1133  		{`onetwothree(5)[1] + 2`, []string{":int:9"}, nil},
  1134  
  1135  		// Call types tests (methods, function pointers, etc.)
  1136  		// The following set of calls was constructed using https://docs.google.com/document/d/1bMwCey-gmqZVTpRax-ESeVuZGmjwbocYs1iHplK-cjo/pub as a reference
  1137  
  1138  		{`a.VRcvr(1)`, []string{`:string:"1 + 3 = 4"`}, nil}, // direct call of a method with value receiver / on a value
  1139  
  1140  		{`a.PRcvr(2)`, []string{`:string:"2 - 3 = -1"`}, nil},  // direct call of a method with pointer receiver / on a value
  1141  		{`pa.VRcvr(3)`, []string{`:string:"3 + 6 = 9"`}, nil},  // direct call of a method with value receiver / on a pointer
  1142  		{`pa.PRcvr(4)`, []string{`:string:"4 - 6 = -2"`}, nil}, // direct call of a method with pointer receiver / on a pointer
  1143  
  1144  		{`vable_pa.VRcvr(6)`, []string{`:string:"6 + 6 = 12"`}, nil}, // indirect call of method on interface / containing value with value method
  1145  		{`pable_pa.PRcvr(7)`, []string{`:string:"7 - 6 = 1"`}, nil},  // indirect call of method on interface / containing pointer with value method
  1146  		{`vable_a.VRcvr(5)`, []string{`:string:"5 + 3 = 8"`}, nil},   // indirect call of method on interface / containing pointer with pointer method
  1147  
  1148  		{`pa.nonexistent()`, nil, errors.New("pa has no member nonexistent")},
  1149  		{`a.nonexistent()`, nil, errors.New("a has no member nonexistent")},
  1150  		{`vable_pa.nonexistent()`, nil, errors.New("vable_pa has no member nonexistent")},
  1151  		{`vable_a.nonexistent()`, nil, errors.New("vable_a has no member nonexistent")},
  1152  		{`pable_pa.nonexistent()`, nil, errors.New("pable_pa has no member nonexistent")},
  1153  
  1154  		{`fn2glob(10, 20)`, []string{":int:30"}, nil},               // indirect call of func value / set to top-level func
  1155  		{`fn2clos(11)`, []string{`:string:"1 + 6 + 11 = 18"`}, nil}, // indirect call of func value / set to func literal
  1156  		// UNDO [#30]: {`fn2clos(12)`, []string{`:string:"2 + 6 + 12 = 20"`}, nil},
  1157  		{`fn2valmeth(13)`, []string{`:string:"13 + 6 = 19"`}, nil}, // indirect call of func value / set to value method
  1158  		{`fn2ptrmeth(14)`, []string{`:string:"14 - 6 = 8"`}, nil},  // indirect call of func value / set to pointer method
  1159  
  1160  		{"fn2nil()", nil, errors.New("nil pointer dereference")},
  1161  
  1162  		{"ga.PRcvr(2)", []string{`:string:"2 - 0 = 2"`}, nil},
  1163  
  1164  		{"x.CallMe()", nil, nil},
  1165  		{"x2.CallMe(5)", []string{":int:25"}, nil},
  1166  
  1167  		{"\"delve\".CallMe()", nil, errors.New("\"delve\" (type string) is not a struct")},
  1168  
  1169  		// Nested function calls tests
  1170  
  1171  		{`onetwothree(intcallpanic(2))`, []string{`:[]int:[]int len: 3, cap: 3, [3,4,5]`}, nil},
  1172  		{`onetwothree(intcallpanic(0))`, []string{`~panic:interface {}:interface {}(string) "panic requested"`}, nil},
  1173  		{`onetwothree(intcallpanic(2)+1)`, []string{`:[]int:[]int len: 3, cap: 3, [4,5,6]`}, nil},
  1174  		{`onetwothree(intcallpanic("not a number"))`, nil, errors.New("error evaluating \"intcallpanic(\\\"not a number\\\")\" as argument n in function main.onetwothree: can not convert \"not a number\" constant to int")},
  1175  
  1176  		// Variable setting tests
  1177  		// UNDO [#30]: {`pa2 = getAStructPtr(8); pa2`, []string{`pa2:*main.astruct:*main.astruct {X: 8}`}, nil},
  1178  
  1179  		// Escape tests
  1180  
  1181  		{"escapeArg(&a2)", nil, errors.New("cannot use &a2 as argument pa2 in function main.escapeArg: stack object passed to escaping pointer: pa2")},
  1182  
  1183  		// Issue 1577
  1184  		{"1+2", []string{`::3`}, nil},
  1185  		{`"de"+"mo"`, []string{`::"demo"`}, nil},
  1186  	}
  1187  
  1188  	var testcases112 = []testCaseCallFunction{
  1189  		// string allocation requires trusted argument order, which we don't have in Go 1.11
  1190  		{`stringsJoin(stringslice, ",")`, []string{`:string:"one,two,three"`}, nil},
  1191  		// UNDO [#30]: {`str = "a new string"; str`, []string{`str:string:"a new string"`}, nil},
  1192  
  1193  		// support calling optimized functions
  1194  		{`strings.Join(nil, "")`, []string{`:string:""`}, nil},
  1195  		{`strings.Join(stringslice, comma)`, []string{`:string:"one,two,three"`}, nil},
  1196  		{`strings.Join(intslice, comma)`, nil, errors.New("can not convert value of type []int to []string")},
  1197  		{`strings.Join(stringslice, ",")`, []string{`:string:"one,two,three"`}, nil},
  1198  		{`strings.LastIndexByte(stringslice[1], 'w')`, []string{":int:1"}, nil},
  1199  		{`strings.LastIndexByte(stringslice[1], 'o')`, []string{":int:2"}, nil},
  1200  		{`d.Base.Method()`, []string{`:int:4`}, nil},
  1201  		{`d.Method()`, []string{`:int:4`}, nil},
  1202  	}
  1203  
  1204  	var testcases113 = []testCaseCallFunction{
  1205  		{`curriedAdd(2)(3)`, []string{`:int:5`}, nil},
  1206  
  1207  		// Method calls on a value returned by a function
  1208  
  1209  		{`getAStruct(3).VRcvr(1)`, []string{`:string:"1 + 3 = 4"`}, nil}, // direct call of a method with value receiver / on a value
  1210  
  1211  		{`getAStruct(3).PRcvr(2)`, nil, errors.New("cannot use getAStruct(3).PRcvr as argument pa in function main.(*astruct).PRcvr: stack object passed to escaping pointer: pa")}, // direct call of a method with pointer receiver / on a value
  1212  		{`getAStructPtr(6).VRcvr(3)`, []string{`:string:"3 + 6 = 9"`}, nil},  // direct call of a method with value receiver / on a pointer
  1213  		{`getAStructPtr(6).PRcvr(4)`, []string{`:string:"4 - 6 = -2"`}, nil}, // direct call of a method with pointer receiver / on a pointer
  1214  
  1215  		{`getVRcvrableFromAStruct(3).VRcvr(6)`, []string{`:string:"6 + 3 = 9"`}, nil},     // indirect call of method on interface / containing value with value method
  1216  		{`getPRcvrableFromAStructPtr(6).PRcvr(7)`, []string{`:string:"7 - 6 = 1"`}, nil},  // indirect call of method on interface / containing pointer with value method
  1217  		{`getVRcvrableFromAStructPtr(6).VRcvr(5)`, []string{`:string:"5 + 6 = 11"`}, nil}, // indirect call of method on interface / containing pointer with pointer method
  1218  	}
  1219  
  1220  	var testcasesBefore114After112 = []testCaseCallFunction{
  1221  		{`strings.Join(s1, comma)`, nil, errors.New(`error evaluating "s1" as argument a in function strings.Join: could not find symbol value for s1`)},
  1222  	}
  1223  
  1224  	var testcases114 = []testCaseCallFunction{
  1225  		{`strings.Join(s1, comma)`, nil, errors.New(`error evaluating "s1" as argument elems in function strings.Join: could not find symbol value for s1`)},
  1226  	}
  1227  
  1228  	var testcases117 = []testCaseCallFunction{
  1229  		{`regabistacktest("one", "two", "three", "four", "five", 4)`, []string{`:string:"onetwo"`, `:string:"twothree"`, `:string:"threefour"`, `:string:"fourfive"`, `:string:"fiveone"`, ":uint8:8"}, nil},
  1230  		{`regabistacktest2(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)`, []string{":int:3", ":int:5", ":int:7", ":int:9", ":int:11", ":int:13", ":int:15", ":int:17", ":int:19", ":int:11"}, nil},
  1231  		{`issue2698.String()`, []string{`:string:"1 2 3 4"`}, nil},
  1232  		{`regabistacktest3(rast3, 5)`, []string{`:[10]string:[10]string ["onetwo","twothree","threefour","fourfive","fivesix","sixseven","sevenheight","heightnine","nineten","tenone"]`, ":uint8:15"}, nil},
  1233  		{`floatsum(1, 2)`, []string{":float64:3"}, nil},
  1234  	}
  1235  
  1236  	withTestProcessArgs("fncall", t, ".", nil, protest.AllNonOptimized, func(p *proc.Target, fixture protest.Fixture) {
  1237  		testCallFunctionSetBreakpoint(t, p, fixture)
  1238  
  1239  		assertNoError(p.Continue(), t, "Continue()")
  1240  		for _, tc := range testcases {
  1241  			testCallFunction(t, p, tc)
  1242  		}
  1243  
  1244  		if goversion.VersionAfterOrEqual(runtime.Version(), 1, 12) {
  1245  			for _, tc := range testcases112 {
  1246  				testCallFunction(t, p, tc)
  1247  			}
  1248  			if !goversion.VersionAfterOrEqual(runtime.Version(), 1, 14) {
  1249  				for _, tc := range testcasesBefore114After112 {
  1250  					testCallFunction(t, p, tc)
  1251  				}
  1252  			}
  1253  		}
  1254  
  1255  		if goversion.VersionAfterOrEqual(runtime.Version(), 1, 13) {
  1256  			for _, tc := range testcases113 {
  1257  				testCallFunction(t, p, tc)
  1258  			}
  1259  		}
  1260  
  1261  		if goversion.VersionAfterOrEqual(runtime.Version(), 1, 14) {
  1262  			for _, tc := range testcases114 {
  1263  				testCallFunction(t, p, tc)
  1264  			}
  1265  		}
  1266  
  1267  		if goversion.VersionAfterOrEqual(runtime.Version(), 1, 17) {
  1268  			for _, tc := range testcases117 {
  1269  				testCallFunction(t, p, tc)
  1270  			}
  1271  		}
  1272  
  1273  		// LEAVE THIS AS THE LAST ITEM, IT BREAKS THE TARGET PROCESS!!!
  1274  		testCallFunction(t, p, testCaseCallFunction{"-unsafe escapeArg(&a2)", nil, nil})
  1275  	})
  1276  }
  1277  
  1278  func testCallFunctionSetBreakpoint(t *testing.T, p *proc.Target, fixture protest.Fixture) {
  1279  	buf, err := ioutil.ReadFile(fixture.Source)
  1280  	assertNoError(err, t, "ReadFile")
  1281  	for i, line := range strings.Split(string(buf), "\n") {
  1282  		if strings.Contains(line, "// breakpoint here") {
  1283  			setFileBreakpoint(p, t, fixture.Source, i+1)
  1284  			return
  1285  		}
  1286  	}
  1287  }
  1288  
  1289  func testCallFunction(t *testing.T, p *proc.Target, tc testCaseCallFunction) {
  1290  	const unsafePrefix = "-unsafe "
  1291  
  1292  	var callExpr, varExpr string
  1293  
  1294  	if semicolon := strings.Index(tc.expr, ";"); semicolon >= 0 {
  1295  		callExpr = tc.expr[:semicolon]
  1296  		varExpr = tc.expr[semicolon+1:]
  1297  	} else {
  1298  		callExpr = tc.expr
  1299  	}
  1300  
  1301  	checkEscape := true
  1302  	if strings.HasPrefix(callExpr, unsafePrefix) {
  1303  		callExpr = callExpr[len(unsafePrefix):]
  1304  		checkEscape = false
  1305  	}
  1306  	t.Logf("call %q", tc.expr)
  1307  	err := proc.EvalExpressionWithCalls(p, p.SelectedGoroutine(), callExpr, pnormalLoadConfig, checkEscape)
  1308  	if tc.err != nil {
  1309  		t.Logf("\terr = %v\n", err)
  1310  		if err == nil {
  1311  			t.Fatalf("call %q: expected error %q, got no error", tc.expr, tc.err.Error())
  1312  		}
  1313  		if tc.err.Error() != err.Error() {
  1314  			t.Fatalf("call %q: expected error %q, got %q", tc.expr, tc.err.Error(), err.Error())
  1315  		}
  1316  		return
  1317  	}
  1318  
  1319  	if err != nil {
  1320  		t.Fatalf("call %q: error %q", tc.expr, err.Error())
  1321  	}
  1322  
  1323  	retvalsVar := p.CurrentThread().Common().ReturnValues(pnormalLoadConfig)
  1324  	retvals := make([]*api.Variable, len(retvalsVar))
  1325  
  1326  	for i := range retvals {
  1327  		retvals[i] = api.ConvertVar(retvalsVar[i])
  1328  	}
  1329  
  1330  	if varExpr != "" {
  1331  		scope, err := proc.GoroutineScope(p, p.CurrentThread())
  1332  		assertNoError(err, t, "GoroutineScope")
  1333  		v, err := scope.EvalExpression(varExpr, pnormalLoadConfig)
  1334  		assertNoError(err, t, fmt.Sprintf("EvalExpression(%s)", varExpr))
  1335  		retvals = append(retvals, api.ConvertVar(v))
  1336  	}
  1337  
  1338  	for i := range retvals {
  1339  		t.Logf("\t%s = %s", retvals[i].Name, retvals[i].SinglelineString())
  1340  	}
  1341  
  1342  	if len(retvals) != len(tc.outs) {
  1343  		t.Fatalf("call %q: wrong number of return parameters (%#v)", tc.expr, retvals)
  1344  	}
  1345  
  1346  	for i := range retvals {
  1347  		outfields := strings.SplitN(tc.outs[i], ":", 3)
  1348  		tgtName, tgtType, tgtValue := outfields[0], outfields[1], outfields[2]
  1349  
  1350  		if tgtName != "" && tgtName != retvals[i].Name {
  1351  			t.Fatalf("call %q output parameter %d: expected name %q, got %q", tc.expr, i, tgtName, retvals[i].Name)
  1352  		}
  1353  
  1354  		if retvals[i].Type != tgtType {
  1355  			t.Fatalf("call %q, output parameter %d: expected type %q, got %q", tc.expr, i, tgtType, retvals[i].Type)
  1356  		}
  1357  		if cvs := retvals[i].SinglelineString(); cvs != tgtValue {
  1358  			t.Fatalf("call %q, output parameter %d: expected value %q, got %q", tc.expr, i, tgtValue, cvs)
  1359  		}
  1360  	}
  1361  }
  1362  
  1363  func TestIssue1531(t *testing.T) {
  1364  	// Go 1.12 introduced a change to the map representation where empty cells can be marked with 1 instead of just 0.
  1365  	protest.AllowRecording(t)
  1366  	withTestProcess("issue1531", t, func(p *proc.Target, fixture protest.Fixture) {
  1367  		assertNoError(p.Continue(), t, "Continue()")
  1368  
  1369  		hasKeys := func(mv *proc.Variable, keys ...string) {
  1370  			n := 0
  1371  			for i := 0; i < len(mv.Children); i += 2 {
  1372  				cv := &mv.Children[i]
  1373  				s := constant.StringVal(cv.Value)
  1374  				found := false
  1375  				for j := range keys {
  1376  					if keys[j] == s {
  1377  						found = true
  1378  						break
  1379  					}
  1380  				}
  1381  				if !found {
  1382  					t.Errorf("key %q not allowed", s)
  1383  					return
  1384  				}
  1385  				n++
  1386  			}
  1387  			if n != len(keys) {
  1388  				t.Fatalf("wrong number of keys found")
  1389  			}
  1390  		}
  1391  
  1392  		mv, err := evalVariableWithCfg(p, "m", pnormalLoadConfig)
  1393  		assertNoError(err, t, "EvalVariable(m)")
  1394  		cmv := api.ConvertVar(mv)
  1395  		t.Logf("m = %s", cmv.SinglelineString())
  1396  		hasKeys(mv, "s", "r", "v")
  1397  
  1398  		mmv, err := evalVariableWithCfg(p, "mm", pnormalLoadConfig)
  1399  		assertNoError(err, t, "EvalVariable(mm)")
  1400  		cmmv := api.ConvertVar(mmv)
  1401  		t.Logf("mm = %s", cmmv.SinglelineString())
  1402  		hasKeys(mmv, "r", "t", "v")
  1403  	})
  1404  }
  1405  
  1406  func currentLocation(p *proc.Target, t *testing.T) (pc uint64, f string, ln int, fn *proc.Function) {
  1407  	regs, err := p.CurrentThread().Registers()
  1408  	if err != nil {
  1409  		t.Fatalf("Registers error: %v", err)
  1410  	}
  1411  	f, l, fn := p.BinInfo().PCToLine(regs.PC())
  1412  	t.Logf("at %#x %s:%d %v", regs.PC(), f, l, fn)
  1413  	return regs.PC(), f, l, fn
  1414  }
  1415  
  1416  func assertCurrentLocationFunction(p *proc.Target, t *testing.T, fnname string) {
  1417  	_, _, _, fn := currentLocation(p, t)
  1418  	if fn == nil {
  1419  		t.Fatalf("Not in a function")
  1420  	}
  1421  	if fn.Name != fnname {
  1422  		t.Fatalf("Wrong function %s %s", fn.Name, fnname)
  1423  	}
  1424  }
  1425  
  1426  func TestPluginVariables(t *testing.T) {
  1427  	pluginFixtures := protest.WithPlugins(t, protest.AllNonOptimized, "plugin1/", "plugin2/")
  1428  
  1429  	withTestProcessArgs("plugintest2", t, ".", []string{pluginFixtures[0].Path, pluginFixtures[1].Path}, protest.AllNonOptimized, func(p *proc.Target, fixture protest.Fixture) {
  1430  		setFileBreakpoint(p, t, fixture.Source, 41)
  1431  		assertNoError(p.Continue(), t, "Continue 1")
  1432  
  1433  		bp := setFunctionBreakpoint(p, t, "github.com/undoio/delve/_fixtures/plugin2.TypesTest")
  1434  		t.Logf("bp.Addr = %#x", bp.Addr)
  1435  		setFunctionBreakpoint(p, t, "github.com/undoio/delve/_fixtures/plugin2.aIsNotNil")
  1436  
  1437  		for _, image := range p.BinInfo().Images {
  1438  			t.Logf("%#x %s\n", image.StaticBase, image.Path)
  1439  		}
  1440  
  1441  		assertNoError(p.Continue(), t, "Continue 2")
  1442  
  1443  		// test that PackageVariables returns variables from the executable and plugins
  1444  		scope, err := evalScope(p)
  1445  		assertNoError(err, t, "evalScope")
  1446  		allvars, err := scope.PackageVariables(pnormalLoadConfig)
  1447  		assertNoError(err, t, "PackageVariables")
  1448  		var plugin2AFound, mainExeGlobalFound bool
  1449  		for _, v := range allvars {
  1450  			switch v.Name {
  1451  			case "github.com/undoio/delve/_fixtures/plugin2.A":
  1452  				plugin2AFound = true
  1453  			case "main.ExeGlobal":
  1454  				mainExeGlobalFound = true
  1455  			}
  1456  		}
  1457  		if !plugin2AFound {
  1458  			t.Fatalf("variable plugin2.A not found in the output of PackageVariables")
  1459  		}
  1460  		if !mainExeGlobalFound {
  1461  			t.Fatalf("variable main.ExeGlobal not found in the output of PackageVariables")
  1462  		}
  1463  
  1464  		// read interface variable, inside plugin code, with a concrete type defined in the executable
  1465  		vs, err := evalVariableWithCfg(p, "s", pnormalLoadConfig)
  1466  		assertNoError(err, t, "Eval(s)")
  1467  		assertVariable(t, vs, varTest{"s", true, `github.com/undoio/delve/_fixtures/internal/pluginsupport.Something(*main.asomething) *{n: 2}`, ``, `github.com/undoio/delve/_fixtures/internal/pluginsupport.Something`, nil})
  1468  
  1469  		// test that the concrete type -> interface{} conversion works across plugins (mostly tests proc.dwarfToRuntimeType)
  1470  		assertNoError(setVariable(p, "plugin2.A", "main.ExeGlobal"), t, "setVariable(plugin2.A = main.ExeGlobal)")
  1471  		assertNoError(p.Continue(), t, "Continue 3")
  1472  		assertCurrentLocationFunction(p, t, "github.com/undoio/delve/_fixtures/plugin2.aIsNotNil")
  1473  		vstr, err := evalVariableWithCfg(p, "str", pnormalLoadConfig)
  1474  		assertNoError(err, t, "Eval(str)")
  1475  		assertVariable(t, vstr, varTest{"str", true, `"success"`, ``, `string`, nil})
  1476  
  1477  		assertNoError(p.StepOut(), t, "StepOut")
  1478  		assertNoError(p.StepOut(), t, "StepOut")
  1479  		assertNoError(p.Next(), t, "Next")
  1480  
  1481  		// read interface variable, inside executable code, with a concrete type defined in a plugin
  1482  		vb, err := evalVariableWithCfg(p, "b", pnormalLoadConfig)
  1483  		assertNoError(err, t, "Eval(b)")
  1484  		assertVariable(t, vb, varTest{"b", true, `github.com/undoio/delve/_fixtures/internal/pluginsupport.SomethingElse(*github.com/undoio/delve/_fixtures/plugin2.asomethingelse) *{x: 1, y: 4}`, ``, `github.com/undoio/delve/_fixtures/internal/pluginsupport.SomethingElse`, nil})
  1485  	})
  1486  }
  1487  
  1488  func TestCgoEval(t *testing.T) {
  1489  	protest.MustHaveCgo(t)
  1490  
  1491  	testcases := []varTest{
  1492  		{"s", true, `"a string"`, `"a string"`, "*char", nil},
  1493  		{"longstring", true, `"averylongstring0123456789a0123456789b0123456789c0123456789d01234...+1 more"`, `"averylongstring0123456789a0123456789b0123456789c0123456789d01234...+1 more"`, "*const char", nil},
  1494  		{"longstring[64:]", false, `"56789e0123456789f0123456789g0123456789h0123456789"`, `"56789e0123456789f0123456789g0123456789h0123456789"`, "*const char", nil},
  1495  		{"s[3]", false, "116", "116", "char", nil},
  1496  		{"v", true, "*0", "(*int)(…", "*int", nil},
  1497  		{"v[1]", false, "1", "1", "int", nil},
  1498  		{"v[90]", false, "90", "90", "int", nil},
  1499  		{"v[:5]", false, "[]int len: 5, cap: 5, [0,1,2,3,4]", "[]int len: 5, cap: 5, [...]", "[]int", nil},
  1500  		{"v_align_check", true, "*align_check {a: 0, b: 0}", "(*struct align_check)(…", "*struct align_check", nil},
  1501  		{"v_align_check[1]", false, "align_check {a: 1, b: 1}", "align_check {a: 1, b: 1}", "align_check", nil},
  1502  		{"v_align_check[90]", false, "align_check {a: 90, b: 90}", "align_check {a: 90, b: 90}", "align_check", nil},
  1503  	}
  1504  
  1505  	if runtime.GOOS == "darwin" && runtime.GOARCH == "arm64" {
  1506  		t.Skip("cgo doesn't work on darwin/arm64")
  1507  	}
  1508  
  1509  	protest.AllowRecording(t)
  1510  	withTestProcess("testvariablescgo/", t, func(p *proc.Target, fixture protest.Fixture) {
  1511  		assertNoError(p.Continue(), t, "Continue() returned an error")
  1512  		for _, tc := range testcases {
  1513  			variable, err := evalVariableWithCfg(p, tc.name, pnormalLoadConfig)
  1514  			if err != nil && err.Error() == "evaluating methods not supported on this version of Go" {
  1515  				// this type of eval is unsupported with the current version of Go.
  1516  				continue
  1517  			}
  1518  			if tc.err == nil {
  1519  				assertNoError(err, t, fmt.Sprintf("EvalExpression(%s) returned an error", tc.name))
  1520  				assertVariable(t, variable, tc)
  1521  				variable, err := evalVariableWithCfg(p, tc.name, pshortLoadConfig)
  1522  				assertNoError(err, t, fmt.Sprintf("EvalExpression(%s, pshortLoadConfig) returned an error", tc.name))
  1523  				assertVariable(t, variable, tc.alternateVarTest())
  1524  			} else {
  1525  				if err == nil {
  1526  					t.Fatalf("Expected error %s, got no error (%s)", tc.err.Error(), tc.name)
  1527  				}
  1528  				if tc.err.Error() != err.Error() {
  1529  					t.Fatalf("Unexpected error. Expected %s got %s", tc.err.Error(), err.Error())
  1530  				}
  1531  			}
  1532  		}
  1533  	})
  1534  }
  1535  
  1536  func TestEvalExpressionGenerics(t *testing.T) {
  1537  	if !goversion.VersionAfterOrEqual(runtime.Version(), 1, 18) {
  1538  		t.Skip("generics not supported")
  1539  	}
  1540  
  1541  	testcases := [][]varTest{
  1542  		// testfn[int, float32]
  1543  		[]varTest{
  1544  			{"arg1", true, "3", "", "int", nil},
  1545  			{"arg2", true, "2.1", "", "float32", nil},
  1546  			{"m", true, "map[float32]int [2.1: 3, ]", "", "map[float32]int", nil},
  1547  		},
  1548  
  1549  		// testfn[*astruct, astruct]
  1550  		[]varTest{
  1551  			{"arg1", true, "*main.astruct {x: 0, y: 1}", "", "*main.astruct", nil},
  1552  			{"arg2", true, "main.astruct {x: 2, y: 3}", "", "main.astruct", nil},
  1553  			{"m", true, "map[main.astruct]*main.astruct [{x: 2, y: 3}: *{x: 0, y: 1}, ]", "", "map[main.astruct]*main.astruct", nil},
  1554  		},
  1555  	}
  1556  
  1557  	withTestProcess("testvariables_generic", t, func(p *proc.Target, fixture protest.Fixture) {
  1558  		for i, tcs := range testcases {
  1559  			assertNoError(p.Continue(), t, fmt.Sprintf("Continue() returned an error (%d)", i))
  1560  			for _, tc := range tcs {
  1561  				variable, err := evalVariableWithCfg(p, tc.name, pnormalLoadConfig)
  1562  				if tc.err == nil {
  1563  					assertNoError(err, t, fmt.Sprintf("EvalExpression(%s) returned an error", tc.name))
  1564  					assertVariable(t, variable, tc)
  1565  				} else {
  1566  					if err == nil {
  1567  						t.Fatalf("Expected error %s, got no error (%s)", tc.err.Error(), tc.name)
  1568  					}
  1569  					if tc.err.Error() != err.Error() {
  1570  						t.Fatalf("Unexpected error. Expected %s got %s", tc.err.Error(), err.Error())
  1571  					}
  1572  				}
  1573  			}
  1574  		}
  1575  	})
  1576  }