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 }