func TestEvalAddrAndCast(t *testing.T) { withTestProcess("testvariables3", t, func(p *proc.Process, fixture protest.Fixture) { assertNoError(p.Continue(), t, "Continue() returned an error") c1addr, err := evalVariable(p, "&c1") assertNoError(err, t, "EvalExpression(&c1)") c1addrstr := api.ConvertVar(c1addr).SinglelineString() t.Logf("&c1 → %s", c1addrstr) if !strings.HasPrefix(c1addrstr, "(*main.cstruct)(0x") { t.Fatalf("Invalid value of EvalExpression(&c1) \"%s\"", c1addrstr) } aaddr, err := evalVariable(p, "&(c1.pb.a)") assertNoError(err, t, "EvalExpression(&(c1.pb.a))") aaddrstr := api.ConvertVar(aaddr).SinglelineString() t.Logf("&(c1.pb.a) → %s", aaddrstr) if !strings.HasPrefix(aaddrstr, "(*main.astruct)(0x") { t.Fatalf("invalid value of EvalExpression(&(c1.pb.a)) \"%s\"", aaddrstr) } a, err := evalVariable(p, "*"+aaddrstr) assertNoError(err, t, fmt.Sprintf("EvalExpression(*%s)", aaddrstr)) t.Logf("*%s → %s", aaddrstr, api.ConvertVar(a).SinglelineString()) assertVariable(t, a, varTest{aaddrstr, false, "struct main.astruct {A: 1, B: 2}", "", "struct main.astruct", nil}) }) }
func TestMapEvaluation(t *testing.T) { withTestProcess("testvariables3", t, func(p *proc.Process, fixture protest.Fixture) { assertNoError(p.Continue(), t, "Continue() returned an error") m1v, err := evalVariable(p, "m1") assertNoError(err, t, "EvalVariable()") m1 := api.ConvertVar(m1v) t.Logf("m1 = %v", m1.MultilineString("")) if m1.Type != "map[string]main.astruct" { t.Fatalf("Wrong type: %s", m1.Type) } if len(m1.Children)/2 != 41 { t.Fatalf("Wrong number of children: %d", len(m1.Children)/2) } found := false for i := range m1.Children { if i%2 == 0 && m1.Children[i].Value == "Malone" { found = true } } if !found { t.Fatalf("Could not find Malone") } m1sliced, err := evalVariable(p, "m1[10:]") assertNoError(err, t, "EvalVariable(m1[10:])") if len(m1sliced.Children)/2 != int(m1.Len-10) { t.Fatalf("Wrong number of children (after slicing): %d", len(m1sliced.Children)/2) } }) }
func convertVars(pv []*proc.Variable) []api.Variable { vars := make([]api.Variable, 0, len(pv)) for _, v := range pv { vars = append(vars, api.ConvertVar(v)) } return vars }
func (d *Debugger) PackageVariables(threadID int, filter string) ([]api.Variable, error) { regex, err := regexp.Compile(filter) if err != nil { return nil, fmt.Errorf("invalid filter argument: %s", err.Error()) } vars := []api.Variable{} thread, found := d.process.Threads[threadID] if !found { return nil, fmt.Errorf("couldn't find thread %d", threadID) } scope, err := thread.Scope() if err != nil { return nil, err } pv, err := scope.PackageVariables() if err != nil { return nil, err } for _, v := range pv { if regex.Match([]byte(v.Name)) { vars = append(vars, api.ConvertVar(v)) } } return vars, err }
func TestUnsafePointer(t *testing.T) { withTestProcess("testvariables3", t, func(p *proc.Process, fixture protest.Fixture) { assertNoError(p.Continue(), t, "Continue() returned an error") up1v, err := evalVariable(p, "up1") assertNoError(err, t, "EvalVariable(up1)") up1 := api.ConvertVar(up1v) if ss := up1.SinglelineString(); !strings.HasPrefix(ss, "unsafe.Pointer(") { t.Fatalf("wrong value for up1: %s", ss) } }) }
// EvalVariableInScope will attempt to evaluate the variable represented by 'symbol' // in the scope provided. func (d *Debugger) EvalVariableInScope(scope api.EvalScope, symbol string) (*api.Variable, error) { s, err := d.process.ConvertEvalScope(scope.GoroutineID, scope.Frame) if err != nil { return nil, err } v, err := s.EvalVariable(symbol) if err != nil { return nil, err } return api.ConvertVar(v), err }
func functionArguments(s *proc.EvalScope) ([]api.Variable, error) { pv, err := s.FunctionArguments() if err != nil { return nil, err } vars := make([]api.Variable, 0, len(pv)) for _, v := range pv { vars = append(vars, api.ConvertVar(v)) } return vars, nil }
func (d *Debugger) EvalVariableInThread(threadID int, symbol string) (*api.Variable, error) { thread, found := d.process.Threads[threadID] if !found { return nil, fmt.Errorf("couldn't find thread %d", threadID) } v, err := thread.EvalVariable(symbol) if err != nil { return nil, err } converted := api.ConvertVar(v) return &converted, err }
// EvalVariableInScope will attempt to evaluate the variable represented by 'symbol' // in the scope provided. func (d *Debugger) EvalVariableInScope(scope api.EvalScope, symbol string, cfg proc.LoadConfig) (*api.Variable, error) { d.processMutex.Lock() defer d.processMutex.Unlock() s, err := d.process.ConvertEvalScope(scope.GoroutineID, scope.Frame) if err != nil { return nil, err } v, err := s.EvalVariable(symbol, cfg) if err != nil { return nil, err } return api.ConvertVar(v), err }
func (d *Debugger) collectBreakpointInformation(state *api.DebuggerState) error { if state == nil || state.Breakpoint == nil { return nil } bp := state.Breakpoint bpi := &api.BreakpointInfo{} state.BreakpointInfo = bpi if bp.Goroutine { g, err := d.process.CurrentThread.GetG() if err != nil { return err } bpi.Goroutine = api.ConvertGoroutine(g) } if bp.Stacktrace > 0 { rawlocs, err := d.process.CurrentThread.Stacktrace(bp.Stacktrace) if err != nil { return err } bpi.Stacktrace, err = d.convertStacktrace(rawlocs, false) if err != nil { return err } } s, err := d.process.CurrentThread.Scope() if err != nil { return err } if len(bp.Variables) > 0 { bpi.Variables = make([]api.Variable, len(bp.Variables)) } for i := range bp.Variables { v, err := s.EvalVariable(bp.Variables[i]) if err != nil { return err } bpi.Variables[i] = api.ConvertVar(v) } vars, err := functionArguments(s) if err == nil { bpi.Arguments = vars } return nil }
func (d *Debugger) FunctionArguments(threadID int) ([]api.Variable, error) { vars := []api.Variable{} thread, found := d.process.Threads[threadID] if !found { return nil, fmt.Errorf("couldn't find thread %d", threadID) } pv, err := thread.FunctionArguments() if err != nil { return nil, err } for _, v := range pv { vars = append(vars, api.ConvertVar(v)) } return vars, err }
func (d *Debugger) LocalVariables(scope api.EvalScope) ([]api.Variable, error) { s, err := d.process.ConvertEvalScope(scope.GoroutineID, scope.Frame) if err != nil { return nil, err } pv, err := s.LocalVariables() if err != nil { return nil, err } vars := make([]api.Variable, 0, len(pv)) for _, v := range pv { vars = append(vars, api.ConvertVar(v)) } return vars, err }
func TestMultilineVariableEvaluation(t *testing.T) { testcases := []varTest{ {"a1", true, "\"foofoofoofoofoofoo\"", "", "struct string", nil}, {"a11", true, `[3]main.FooBar [ {Baz: 1, Bur: "a"}, {Baz: 2, Bur: "b"}, {Baz: 3, Bur: "c"}, ]`, "", "[3]main.FooBar", nil}, {"a12", true, `[]main.FooBar len: 2, cap: 2, [ {Baz: 4, Bur: "d"}, {Baz: 5, Bur: "e"}, ]`, "", "struct []main.FooBar", nil}, {"a13", true, `[]*main.FooBar len: 3, cap: 3, [ *{Baz: 6, Bur: "f"}, *{Baz: 7, Bur: "g"}, *{Baz: 8, Bur: "h"}, ]`, "", "struct []*main.FooBar", nil}, {"a2", true, "6", "10", "int", nil}, {"a4", true, "[2]int [1,2]", "", "[2]int", nil}, {"a5", true, "[]int len: 5, cap: 5, [1,2,3,4,5]", "", "struct []int", nil}, {"a6", true, "main.FooBar {Baz: 8, Bur: \"word\"}", "", "main.FooBar", nil}, {"a7", true, "*main.FooBar {Baz: 5, Bur: \"strum\"}", "", "*main.FooBar", nil}, {"a8", true, "main.FooBar2 {Bur: 10, Baz: \"feh\"}", "", "main.FooBar2", nil}, {"a9", true, "*main.FooBar nil", "", "*main.FooBar", nil}, {"a8", true, "main.FooBar2 {Bur: 10, Baz: \"feh\"}", "", "main.FooBar2", nil}, // reread variable after member {"i32", true, "[2]int32 [1,2]", "", "[2]int32", nil}, {"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]", "", "struct []int", nil}, {"ms", true, `main.Nest { Level: 0, Nest: *main.Nest { Level: 1, Nest: *(*main.Nest)(…`, "", "main.Nest", nil}, } withTestProcess("testvariables", t, func(p *proc.Process, fixture protest.Fixture) { err := p.Continue() assertNoError(err, t, "Continue() returned an error") for _, tc := range testcases { variable, err := evalVariable(p, tc.name) assertNoError(err, t, "EvalVariable() returned an error") if ms := api.ConvertVar(variable).MultilineString(""); !matchStringOrPrefix(ms, tc.value) { t.Fatalf("Expected %s got %s (variable %s)\n", tc.value, ms, variable.Name) } } }) }
func assertVariable(t *testing.T, variable *proc.Variable, expected varTest) { if expected.preserveName { if variable.Name != expected.name { t.Fatalf("Expected %s got %s\n", expected.name, variable.Name) } } cv := api.ConvertVar(variable) if cv.Type != expected.varType { t.Fatalf("Expected %s got %s (for variable %s)\n", expected.varType, cv.Type, expected.name) } if ss := cv.SinglelineString(); !matchStringOrPrefix(ss, expected.value) { t.Fatalf("Expected %#v got %#v (for variable %s)\n", expected.value, ss, expected.name) } }
func TestComplexSetting(t *testing.T) { withTestProcess("testvariables", t, func(p *proc.Process, fixture protest.Fixture) { err := p.Continue() assertNoError(err, t, "Continue() returned an error") h := func(setExpr, value string) { assertNoError(setVariable(p, "c128", setExpr), t, "SetVariable()") variable, err := evalVariable(p, "c128") assertNoError(err, t, "EvalVariable()") if s := api.ConvertVar(variable).SinglelineString(); s != value { t.Fatalf("Wrong value of c128: \"%s\", expected \"%s\" after setting it to \"%s\"", s, value, setExpr) } } h("3.2i", "(0 + 3.2i)") h("1.1", "(1.1 + 0i)") h("1 + 3.3i", "(1 + 3.3i)") h("complex(1.2, 3.4)", "(1.2 + 3.4i)") }) }
func TestVariableEvaluation(t *testing.T) { testcases := []varTest{ {"a1", true, "\"foofoofoofoofoofoo\"", "", "struct string", nil}, {"a11", true, "[3]main.FooBar [{Baz: 1, Bur: \"a\"},{Baz: 2, Bur: \"b\"},{Baz: 3, Bur: \"c\"}]", "", "[3]main.FooBar", nil}, {"a12", true, "[]main.FooBar len: 2, cap: 2, [{Baz: 4, Bur: \"d\"},{Baz: 5, Bur: \"e\"}]", "", "struct []main.FooBar", nil}, {"a13", true, "[]*main.FooBar len: 3, cap: 3, [*{Baz: 6, Bur: \"f\"},*{Baz: 7, Bur: \"g\"},*{Baz: 8, Bur: \"h\"}]", "", "struct []*main.FooBar", nil}, {"a2", true, "6", "10", "int", nil}, {"a3", true, "7.23", "3.1", "float64", nil}, {"a4", true, "[2]int [1,2]", "", "[2]int", nil}, {"a5", true, "[]int len: 5, cap: 5, [1,2,3,4,5]", "", "struct []int", nil}, {"a6", true, "main.FooBar {Baz: 8, Bur: \"word\"}", "", "main.FooBar", nil}, {"a7", true, "*main.FooBar {Baz: 5, Bur: \"strum\"}", "", "*main.FooBar", nil}, {"a8", true, "main.FooBar2 {Bur: 10, Baz: \"feh\"}", "", "main.FooBar2", nil}, {"a9", true, "*main.FooBar nil", "", "*main.FooBar", nil}, {"baz", true, "\"bazburzum\"", "", "struct string", nil}, {"neg", true, "-1", "-20", "int", nil}, {"f32", true, "1.2", "1.1", "float32", nil}, {"c64", true, "(1 + 2i)", "(4 + 5i)", "complex64", nil}, {"c128", true, "(2 + 3i)", "(6.3 + 7i)", "complex128", nil}, {"a6.Baz", true, "8", "20", "int", nil}, {"a7.Baz", true, "5", "25", "int", nil}, {"a8.Baz", true, "\"feh\"", "", "struct string", nil}, {"a9.Baz", true, "nil", "", "int", fmt.Errorf("a9 is nil")}, {"a9.NonExistent", true, "nil", "", "int", fmt.Errorf("a9 has no member NonExistent")}, {"a8", true, "main.FooBar2 {Bur: 10, Baz: \"feh\"}", "", "main.FooBar2", nil}, // reread variable after member {"i32", true, "[2]int32 [1,2]", "", "[2]int32", nil}, {"b1", true, "true", "false", "bool", nil}, {"b2", true, "false", "true", "bool", nil}, {"i8", true, "1", "2", "int8", nil}, {"u16", true, "65535", "0", "uint16", nil}, {"u32", true, "4294967295", "1", "uint32", nil}, {"u64", true, "18446744073709551615", "2", "uint64", nil}, {"u8", true, "255", "3", "uint8", nil}, {"up", true, "5", "4", "uintptr", nil}, {"f", true, "main.barfoo", "", "func()", nil}, {"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]", "", "struct []int", nil}, {"ms", true, "main.Nest {Level: 0, Nest: *main.Nest {Level: 1, Nest: *(*main.Nest)(…", "", "main.Nest", nil}, {"ms.Nest.Nest", true, "*main.Nest {Level: 2, Nest: *main.Nest {Level: 3, Nest: *(*main.Nest)(…", "", "*main.Nest", nil}, {"ms.Nest.Nest.Nest.Nest.Nest", true, "*main.Nest nil", "", "*main.Nest", nil}, {"ms.Nest.Nest.Nest.Nest.Nest.Nest", true, "", "", "*main.Nest", fmt.Errorf("ms.Nest.Nest.Nest.Nest.Nest is nil")}, {"main.p1", true, "10", "12", "int", nil}, {"p1", true, "10", "13", "int", nil}, {"NonExistent", true, "", "", "", fmt.Errorf("could not find symbol value for NonExistent")}, } withTestProcess("testvariables", t, func(p *proc.Process, fixture protest.Fixture) { err := p.Continue() assertNoError(err, t, "Continue() returned an error") for _, tc := range testcases { variable, err := evalVariable(p, tc.name) if tc.err == nil { assertNoError(err, t, "EvalVariable() returned an error") assertVariable(t, variable, tc) } else { if err == nil { t.Fatalf("Expected error %s, got no error: %s\n", tc.err.Error(), api.ConvertVar(variable).SinglelineString()) } if tc.err.Error() != err.Error() { t.Fatalf("Unexpected error. Expected %s got %s", tc.err.Error(), err.Error()) } } if tc.settable() { assertNoError(setVariable(p, tc.name, tc.setTo), t, "SetVariable()") variable, err = evalVariable(p, tc.name) assertNoError(err, t, "EvalVariable()") assertVariable(t, variable, tc.afterSet()) assertNoError(setVariable(p, tc.name, tc.value), t, "SetVariable()") variable, err := evalVariable(p, tc.name) assertNoError(err, t, "EvalVariable()") assertVariable(t, variable, tc) } } }) }