From b59032516eef15e65ff7cc6d01677712dc3baf6a Mon Sep 17 00:00:00 2001 From: aarzilli Date: Tue, 10 Jul 2018 12:15:11 +0200 Subject: [PATCH] proc,service,terminal: eval expressions in the scope of a deferred call Add ability to evaluate variables on the scope of a deferred call's argument frame. --- Documentation/cli/README.md | 14 +++++++-- _fixtures/deferstack.go | 6 ++-- pkg/proc/proc.go | 18 ++++++++++-- pkg/proc/proc_test.go | 47 +++++++++++++++++++++++++++++-- pkg/proc/stack.go | 39 +++++++++++++++++++++++++ pkg/terminal/command.go | 37 +++++++++++++++++++----- service/api/types.go | 5 ++-- service/debugger/debugger.go | 10 +++---- service/test/common_test.go | 2 +- service/test/integration1_test.go | 36 +++++++++++------------ service/test/integration2_test.go | 42 +++++++++++++-------------- 11 files changed, 193 insertions(+), 63 deletions(-) diff --git a/Documentation/cli/README.md b/Documentation/cli/README.md index c9e05263..c0378cb8 100644 --- a/Documentation/cli/README.md +++ b/Documentation/cli/README.md @@ -14,6 +14,7 @@ Command | Description [condition](#condition) | Set breakpoint condition. [config](#config) | Changes configuration parameters. [continue](#continue) | Run until breakpoint or program termination. +[deferred](#deferred) | Executes command in the context of a deferred call. [disassemble](#disassemble) | Disassembler. [down](#down) | Move the current frame down. [edit](#edit) | Open where you are in $DELVE_EDITOR or $EDITOR @@ -161,6 +162,14 @@ Run until breakpoint or program termination. Aliases: c +## deferred +Executes command in the context of a deferred call. + + deferred + +Executes the specified command (print, args, locals) in the context of the n-th deferred call in the current frame. + + ## disassemble Disassembler. @@ -341,10 +350,11 @@ If regex is specified only the source files matching it will be returned. ## stack Print stack trace. - [goroutine ] [frame ] stack [] [-full] [-g] [-s] [-offsets] + [goroutine ] [frame ] stack [] [-full] [-offsets] [-defer] -full every stackframe is decorated with the value of its local variables and arguments. - -offsets prints frame offset of each frame + -offsets prints frame offset of each frame. + -defer prints deferred function call stack for each frame. Aliases: bt diff --git a/_fixtures/deferstack.go b/_fixtures/deferstack.go index 851fa019..6e17c784 100644 --- a/_fixtures/deferstack.go +++ b/_fixtures/deferstack.go @@ -5,21 +5,21 @@ import "runtime" func f1() { } -func f2() { +func f2(a int8, b int32) { } func f3() { } func call1() { - defer f2() + defer f2(1, -1) defer f1() call2() } func call2() { defer f3() - defer f2() + defer f2(42, 61) call3() } diff --git a/pkg/proc/proc.go b/pkg/proc/proc.go index 49843879..d633e853 100644 --- a/pkg/proc/proc.go +++ b/pkg/proc/proc.go @@ -544,7 +544,8 @@ func FindGoroutine(dbp Process, gid int) (*G, error) { // ConvertEvalScope returns a new EvalScope in the context of the // specified goroutine ID and stack frame. -func ConvertEvalScope(dbp Process, gid, frame int) (*EvalScope, error) { +// If deferCall is > 0 the eval scope will be relative to the specified deferred call. +func ConvertEvalScope(dbp Process, gid, frame, deferCall int) (*EvalScope, error) { if _, err := dbp.Valid(); err != nil { return nil, err } @@ -564,7 +565,7 @@ func ConvertEvalScope(dbp Process, gid, frame int) (*EvalScope, error) { thread = g.Thread } - locs, err := g.Stacktrace(frame+1, false) + locs, err := g.Stacktrace(frame+1, deferCall > 0) if err != nil { return nil, err } @@ -573,6 +574,19 @@ func ConvertEvalScope(dbp Process, gid, frame int) (*EvalScope, error) { return nil, fmt.Errorf("Frame %d does not exist in goroutine %d", frame, gid) } + if deferCall > 0 { + if deferCall-1 >= len(locs[frame].Defers) { + return nil, fmt.Errorf("Frame %d only has %d deferred calls", frame, len(locs[frame].Defers)) + } + + d := locs[frame].Defers[deferCall-1] + if d.Unreadable != nil { + return nil, d.Unreadable + } + + return d.EvalScope(ct) + } + return FrameToScope(dbp.BinInfo(), thread, g, locs[frame:]...), nil } diff --git a/pkg/proc/proc_test.go b/pkg/proc/proc_test.go index f1dc01a7..12bdfdaa 100644 --- a/pkg/proc/proc_test.go +++ b/pkg/proc/proc_test.go @@ -1263,7 +1263,7 @@ func TestFrameEvaluation(t *testing.T) { continue } - scope, err := proc.ConvertEvalScope(p, g.ID, frame) + scope, err := proc.ConvertEvalScope(p, g.ID, frame, 0) assertNoError(err, t, "ConvertEvalScope()") t.Logf("scope = %v", scope) v, err := scope.EvalVariable("i", normalLoadConfig) @@ -1288,7 +1288,7 @@ func TestFrameEvaluation(t *testing.T) { assertNoError(err, t, "GetG()") for i := 0; i <= 3; i++ { - scope, err := proc.ConvertEvalScope(p, g.ID, i+1) + scope, err := proc.ConvertEvalScope(p, g.ID, i+1, 0) assertNoError(err, t, fmt.Sprintf("ConvertEvalScope() on frame %d", i+1)) v, err := scope.EvalVariable("n", normalLoadConfig) assertNoError(err, t, fmt.Sprintf("EvalVariable() on frame %d", i+1)) @@ -4041,3 +4041,46 @@ func TestNextUnknownInstr(t *testing.T) { assertNoError(proc.Next(p), t, "Next()") }) } + +func TestReadDeferArgs(t *testing.T) { + var tests = []struct { + frame, deferCall int + a, b int64 + }{ + {1, 1, 42, 61}, + {2, 2, 1, -1}, + } + + withTestProcess("deferstack", t, func(p proc.Process, fixture protest.Fixture) { + assertNoError(proc.Continue(p), t, "Continue()") + + for _, test := range tests { + scope, err := proc.ConvertEvalScope(p, -1, test.frame, test.deferCall) + assertNoError(err, t, fmt.Sprintf("ConvertEvalScope(-1, %d, %d)", test.frame, test.deferCall)) + + if scope.Fn.Name != "main.f2" { + t.Fatalf("expected function \"main.f2\" got %q", scope.Fn.Name) + } + + avar, err := scope.EvalVariable("a", normalLoadConfig) + if err != nil { + t.Fatal(err) + } + bvar, err := scope.EvalVariable("b", normalLoadConfig) + if err != nil { + t.Fatal(err) + } + + a, _ := constant.Int64Val(avar.Value) + b, _ := constant.Int64Val(bvar.Value) + + if a != test.a { + t.Errorf("value of argument 'a' at frame %d, deferred call %d: %d (expected %d)", test.frame, test.deferCall, a, test.a) + } + + if b != test.b { + t.Errorf("value of argument 'b' at frame %d, deferred call %d: %d (expected %d)", test.frame, test.deferCall, b, test.b) + } + } + }) +} diff --git a/pkg/proc/stack.go b/pkg/proc/stack.go index 07258f3f..4abcca4b 100644 --- a/pkg/proc/stack.go +++ b/pkg/proc/stack.go @@ -594,6 +594,7 @@ type Defer struct { DeferPC uint64 // PC address of instruction that added this defer SP uint64 // Value of SP register when this function was deferred (this field gets adjusted when the stack is moved to match the new stack space) link *Defer // Next deferred function + argSz int64 variable *Variable Unreadable error @@ -660,6 +661,7 @@ func (d *Defer) load() { d.DeferPC, _ = constant.Uint64Val(d.variable.fieldVariable("pc").Value) d.SP, _ = constant.Uint64Val(d.variable.fieldVariable("sp").Value) + d.argSz, _ = constant.Int64Val(d.variable.fieldVariable("siz").Value) linkvar := d.variable.fieldVariable("link").maybeDereference() if linkvar.Addr != 0 { @@ -685,3 +687,40 @@ func (d *Defer) Next() *Defer { } return d.link } + +// EvalScope returns an EvalScope relative to the argument frame of this deferred call. +// The argument frame of a deferred call is stored in memory immediately +// after the deferred header. +func (d *Defer) EvalScope(thread Thread) (*EvalScope, error) { + scope, err := GoroutineScope(thread) + if err != nil { + return nil, fmt.Errorf("could not get scope: %v", err) + } + + bi := thread.BinInfo() + scope.PC = d.DeferredPC + scope.File, scope.Line, scope.Fn = bi.PCToLine(d.DeferredPC) + + if scope.Fn == nil { + return nil, fmt.Errorf("could not find function at %#x", d.DeferredPC) + } + + // The arguments are stored immediately after the defer header struct, i.e. + // addr+sizeof(_defer). Since CFA in go is always the address of the first + // argument, that's what we use for the value of CFA. + // For SP we use CFA minus the size of one pointer because that would be + // the space occupied by pushing the return address on the stack during the + // CALL. + scope.Regs.CFA = (int64(d.variable.Addr) + d.variable.RealType.Common().ByteSize) + scope.Regs.Regs[scope.Regs.SPRegNum].Uint64Val = uint64(scope.Regs.CFA - int64(bi.Arch.PtrSize())) + + bi.dwarfReader.Seek(scope.Fn.offset) + e, err := bi.dwarfReader.Next() + if err != nil { + return nil, fmt.Errorf("could not read DWARF function entry: %v", err) + } + scope.Regs.FrameBase, _, _, _ = bi.Location(e, dwarf.AttrFrameBase, scope.PC, scope.Regs) + scope.Mem = cacheMemory(scope.Mem, uintptr(scope.Regs.CFA), int(d.argSz)) + + return scope, nil +} diff --git a/pkg/terminal/command.go b/pkg/terminal/command.go index 02a2a884..9a2cf741 100644 --- a/pkg/terminal/command.go +++ b/pkg/terminal/command.go @@ -32,6 +32,7 @@ type cmdPrefix int const ( noPrefix = cmdPrefix(0) onPrefix = cmdPrefix(1 << iota) + deferredPrefix ) type callContext struct { @@ -188,7 +189,7 @@ Called without arguments it will show information about the current goroutine. Called with a single argument it will switch to the specified goroutine. Called with more arguments it will execute a command on the specified goroutine.`}, {aliases: []string{"breakpoints", "bp"}, cmdFn: breakpoints, helpMsg: "Print out info for active breakpoints."}, - {aliases: []string{"print", "p"}, allowedPrefixes: onPrefix, cmdFn: printVar, helpMsg: `Evaluate an expression. + {aliases: []string{"print", "p"}, allowedPrefixes: onPrefix | deferredPrefix, cmdFn: printVar, helpMsg: `Evaluate an expression. [goroutine ] [frame ] print @@ -216,12 +217,12 @@ If regex is specified only the functions matching it will be returned.`}, types [] If regex is specified only the types matching it will be returned.`}, - {aliases: []string{"args"}, allowedPrefixes: onPrefix, cmdFn: args, helpMsg: `Print function arguments. + {aliases: []string{"args"}, allowedPrefixes: onPrefix | deferredPrefix, cmdFn: args, helpMsg: `Print function arguments. [goroutine ] [frame ] args [-v] [] If regex is specified only function arguments with a name matching it will be returned. If -v is specified more information about each function argument will be shown.`}, - {aliases: []string{"locals"}, allowedPrefixes: onPrefix, cmdFn: locals, helpMsg: `Print local variables. + {aliases: []string{"locals"}, allowedPrefixes: onPrefix | deferredPrefix, cmdFn: locals, helpMsg: `Print local variables. [goroutine ] [frame ] locals [-v] [] @@ -250,10 +251,11 @@ When connected to a headless instance started with the --accept-multiclient, pas Show source around current point or provided linespec.`}, {aliases: []string{"stack", "bt"}, allowedPrefixes: onPrefix, cmdFn: stackCommand, helpMsg: `Print stack trace. - [goroutine ] [frame ] stack [] [-full] [-g] [-s] [-offsets] + [goroutine ] [frame ] stack [] [-full] [-offsets] [-defer] -full every stackframe is decorated with the value of its local variables and arguments. - -offsets prints frame offset of each frame + -offsets prints frame offset of each frame. + -defer prints deferred function call stack for each frame. `}, {aliases: []string{"frame"}, cmdFn: func(t *Term, ctx callContext, arg string) error { @@ -286,6 +288,11 @@ Move the current frame up by . The second form runs the command on the given down [] Move the current frame down by . The second form runs the command on the given frame.`}, + {aliases: []string{"deferred"}, cmdFn: c.deferredCommand, helpMsg: `Executes command in the context of a deferred call. + + deferred + +Executes the specified command (print, args, locals) in the context of the n-th deferred call in the current frame.`}, {aliases: []string{"source"}, cmdFn: c.sourceCommand, helpMsg: `Executes a file containing a list of delve commands source `}, @@ -428,7 +435,7 @@ func (c *Commands) CallWithContext(cmdstr string, t *Term, ctx callContext) erro // Call takes a command to execute. func (c *Commands) Call(cmdstr string, t *Term) error { - ctx := callContext{Prefix: noPrefix, Scope: api.EvalScope{GoroutineID: -1, Frame: c.frame}} + ctx := callContext{Prefix: noPrefix, Scope: api.EvalScope{GoroutineID: -1, Frame: c.frame, DeferredCall: 0}} return c.CallWithContext(cmdstr, t, ctx) } @@ -716,6 +723,22 @@ func (c *Commands) frameCommand(t *Term, ctx callContext, argstr string, directi return nil } +func (c *Commands) deferredCommand(t *Term, ctx callContext, argstr string) error { + ctx.Prefix = deferredPrefix + + space := strings.Index(argstr, " ") + + var err error + ctx.Scope.DeferredCall, err = strconv.Atoi(argstr[:space]) + if err != nil { + return err + } + if ctx.Scope.DeferredCall <= 0 { + return errors.New("argument of deferred must be a number greater than 0 (use 'stack -defer' to see the list of deferred calls)") + } + return c.CallWithContext(argstr[space:], t, ctx) +} + func printscope(t *Term) error { state, err := t.client.GetState() if err != nil { @@ -1573,7 +1596,7 @@ func printStack(stack []api.Stackframe, ind string, offsets bool) { } for j, d := range stack[i].Defers { - deferHeader := fmt.Sprintf("%s defer %d: ", s, j) + deferHeader := fmt.Sprintf("%s defer %d: ", s, j+1) s2 := strings.Repeat(" ", len(deferHeader)) if d.Unreadable != "" { fmt.Printf("%s(unreadable defer: %s)\n", deferHeader, d.Unreadable) diff --git a/service/api/types.go b/service/api/types.go index 5c692ffb..fa21fdb4 100644 --- a/service/api/types.go +++ b/service/api/types.go @@ -324,8 +324,9 @@ type BreakpointInfo struct { // EvalScope is the scope a command should // be evaluated in. Describes the goroutine and frame number. type EvalScope struct { - GoroutineID int - Frame int + GoroutineID int + Frame int + DeferredCall int // when DeferredCall is n > 0 this eval scope is relative to the n-th deferred call in the current frame } const ( diff --git a/service/debugger/debugger.go b/service/debugger/debugger.go index 9a8920c7..0cd53654 100644 --- a/service/debugger/debugger.go +++ b/service/debugger/debugger.go @@ -825,7 +825,7 @@ func (d *Debugger) LocalVariables(scope api.EvalScope, cfg proc.LoadConfig) ([]a d.processMutex.Lock() defer d.processMutex.Unlock() - s, err := proc.ConvertEvalScope(d.target, scope.GoroutineID, scope.Frame) + s, err := proc.ConvertEvalScope(d.target, scope.GoroutineID, scope.Frame, scope.DeferredCall) if err != nil { return nil, err } @@ -841,7 +841,7 @@ func (d *Debugger) FunctionArguments(scope api.EvalScope, cfg proc.LoadConfig) ( d.processMutex.Lock() defer d.processMutex.Unlock() - s, err := proc.ConvertEvalScope(d.target, scope.GoroutineID, scope.Frame) + s, err := proc.ConvertEvalScope(d.target, scope.GoroutineID, scope.Frame, scope.DeferredCall) if err != nil { return nil, err } @@ -858,7 +858,7 @@ func (d *Debugger) EvalVariableInScope(scope api.EvalScope, symbol string, cfg p d.processMutex.Lock() defer d.processMutex.Unlock() - s, err := proc.ConvertEvalScope(d.target, scope.GoroutineID, scope.Frame) + s, err := proc.ConvertEvalScope(d.target, scope.GoroutineID, scope.Frame, scope.DeferredCall) if err != nil { return nil, err } @@ -875,7 +875,7 @@ func (d *Debugger) SetVariableInScope(scope api.EvalScope, symbol, value string) d.processMutex.Lock() defer d.processMutex.Unlock() - s, err := proc.ConvertEvalScope(d.target, scope.GoroutineID, scope.Frame) + s, err := proc.ConvertEvalScope(d.target, scope.GoroutineID, scope.Frame, scope.DeferredCall) if err != nil { return err } @@ -1009,7 +1009,7 @@ func (d *Debugger) FindLocation(scope api.EvalScope, locStr string) ([]api.Locat return nil, err } - s, _ := proc.ConvertEvalScope(d.target, scope.GoroutineID, scope.Frame) + s, _ := proc.ConvertEvalScope(d.target, scope.GoroutineID, scope.Frame, scope.DeferredCall) locs, err := loc.Find(d, s, locStr) for i := range locs { diff --git a/service/test/common_test.go b/service/test/common_test.go index 53ca36a6..0103bc3e 100644 --- a/service/test/common_test.go +++ b/service/test/common_test.go @@ -76,7 +76,7 @@ type LocationFinder interface { } func findLocationHelper(t *testing.T, c LocationFinder, loc string, shouldErr bool, count int, checkAddr uint64) []uint64 { - locs, err := c.FindLocation(api.EvalScope{-1, 0}, loc) + locs, err := c.FindLocation(api.EvalScope{-1, 0, 0}, loc) t.Logf("FindLocation(\"%s\") → %v\n", loc, locs) if shouldErr { diff --git a/service/test/integration1_test.go b/service/test/integration1_test.go index 3bef7843..185b6e8c 100644 --- a/service/test/integration1_test.go +++ b/service/test/integration1_test.go @@ -433,7 +433,7 @@ func Test1ClientServer_infoLocals(t *testing.T) { if state.Err != nil { t.Fatalf("Unexpected error: %v, state: %#v", state.Err, state) } - locals, err := c.ListLocalVariables(api.EvalScope{-1, 0}) + locals, err := c.ListLocalVariables(api.EvalScope{-1, 0, 0}) if err != nil { t.Fatalf("Unexpected error: %v", err) } @@ -461,7 +461,7 @@ func Test1ClientServer_infoArgs(t *testing.T) { if regs == "" { t.Fatal("Expected string showing registers values, got empty string") } - locals, err := c.ListFunctionArgs(api.EvalScope{-1, 0}) + locals, err := c.ListFunctionArgs(api.EvalScope{-1, 0, 0}) if err != nil { t.Fatalf("Unexpected error: %v", err) } @@ -687,7 +687,7 @@ func Test1ClientServer_EvalVariable(t *testing.T) { t.Fatalf("Continue(): %v\n", state.Err) } - var1, err := c.EvalVariable(api.EvalScope{-1, 0}, "a1") + var1, err := c.EvalVariable(api.EvalScope{-1, 0, 0}, "a1") assertNoError(err, t, "EvalVariable") t.Logf("var1: %s", var1.SinglelineString()) @@ -706,9 +706,9 @@ func Test1ClientServer_SetVariable(t *testing.T) { t.Fatalf("Continue(): %v\n", state.Err) } - assertNoError(c.SetVariable(api.EvalScope{-1, 0}, "a2", "8"), t, "SetVariable()") + assertNoError(c.SetVariable(api.EvalScope{-1, 0, 0}, "a2", "8"), t, "SetVariable()") - a2, err := c.EvalVariable(api.EvalScope{-1, 0}, "a2") + a2, err := c.EvalVariable(api.EvalScope{-1, 0, 0}, "a2") if err != nil { t.Fatalf("Could not evaluate variable: %v", err) } @@ -835,10 +835,10 @@ func Test1Issue355(t *testing.T) { assertError(err, t, "ListThreads()") _, err = c.GetThread(tid) assertError(err, t, "GetThread()") - assertError(c.SetVariable(api.EvalScope{gid, 0}, "a", "10"), t, "SetVariable()") - _, err = c.ListLocalVariables(api.EvalScope{gid, 0}) + assertError(c.SetVariable(api.EvalScope{gid, 0, 0}, "a", "10"), t, "SetVariable()") + _, err = c.ListLocalVariables(api.EvalScope{gid, 0, 0}) assertError(err, t, "ListLocalVariables()") - _, err = c.ListFunctionArgs(api.EvalScope{gid, 0}) + _, err = c.ListFunctionArgs(api.EvalScope{gid, 0, 0}) assertError(err, t, "ListFunctionArgs()") _, err = c.ListRegisters() assertError(err, t, "ListRegisters()") @@ -846,9 +846,9 @@ func Test1Issue355(t *testing.T) { assertError(err, t, "ListGoroutines()") _, err = c.Stacktrace(gid, 10, false) assertError(err, t, "Stacktrace()") - _, err = c.FindLocation(api.EvalScope{gid, 0}, "+1") + _, err = c.FindLocation(api.EvalScope{gid, 0, 0}, "+1") assertError(err, t, "FindLocation()") - _, err = c.DisassemblePC(api.EvalScope{-1, 0}, 0x40100, api.IntelFlavour) + _, err = c.DisassemblePC(api.EvalScope{-1, 0, 0}, 0x40100, api.IntelFlavour) assertError(err, t, "DisassemblePC()") }) } @@ -863,12 +863,12 @@ func Test1Disasm(t *testing.T) { state := <-ch assertNoError(state.Err, t, "Continue()") - locs, err := c.FindLocation(api.EvalScope{-1, 0}, "main.main") + locs, err := c.FindLocation(api.EvalScope{-1, 0, 0}, "main.main") assertNoError(err, t, "FindLocation()") if len(locs) != 1 { t.Fatalf("wrong number of locations for main.main: %d", len(locs)) } - d1, err := c.DisassemblePC(api.EvalScope{-1, 0}, locs[0].PC, api.IntelFlavour) + d1, err := c.DisassemblePC(api.EvalScope{-1, 0, 0}, locs[0].PC, api.IntelFlavour) assertNoError(err, t, "DisassemblePC()") if len(d1) < 2 { t.Fatalf("wrong size of disassembly: %d", len(d1)) @@ -876,7 +876,7 @@ func Test1Disasm(t *testing.T) { pcstart := d1[0].Loc.PC pcend := d1[len(d1)-1].Loc.PC + uint64(len(d1[len(d1)-1].Bytes)) - d2, err := c.DisassembleRange(api.EvalScope{-1, 0}, pcstart, pcend, api.IntelFlavour) + d2, err := c.DisassembleRange(api.EvalScope{-1, 0, 0}, pcstart, pcend, api.IntelFlavour) assertNoError(err, t, "DisassembleRange()") if len(d1) != len(d2) { @@ -885,7 +885,7 @@ func Test1Disasm(t *testing.T) { t.Fatal("mismatched length between disassemble pc and disassemble range") } - d3, err := c.DisassemblePC(api.EvalScope{-1, 0}, state.CurrentThread.PC, api.IntelFlavour) + d3, err := c.DisassemblePC(api.EvalScope{-1, 0, 0}, state.CurrentThread.PC, api.IntelFlavour) assertNoError(err, t, "DisassemblePC() - second call") if len(d1) != len(d3) { @@ -929,7 +929,7 @@ func Test1Disasm(t *testing.T) { state, err := c.StepInstruction() assertNoError(err, t, fmt.Sprintf("StepInstruction() %d", count)) - d3, err = c.DisassemblePC(api.EvalScope{-1, 0}, state.CurrentThread.PC, api.IntelFlavour) + d3, err = c.DisassemblePC(api.EvalScope{-1, 0, 0}, state.CurrentThread.PC, api.IntelFlavour) assertNoError(err, t, fmt.Sprintf("StepInstruction() %d", count)) curinstr := getCurinstr(d3) @@ -992,7 +992,7 @@ func Test1ClientServer_CondBreakpoint(t *testing.T) { state := <-c.Continue() assertNoError(state.Err, t, "Continue()") - nvar, err := c.EvalVariable(api.EvalScope{-1, 0}, "n") + nvar, err := c.EvalVariable(api.EvalScope{-1, 0, 0}, "n") assertNoError(err, t, "EvalVariable()") if nvar.SinglelineString() != "7" { @@ -1096,14 +1096,14 @@ func Test1TypesCommand(t *testing.T) { func Test1Issue406(t *testing.T) { withTestClient1("issue406", t, func(c *rpc1.RPCClient) { - locs, err := c.FindLocation(api.EvalScope{-1, 0}, "issue406.go:146") + locs, err := c.FindLocation(api.EvalScope{-1, 0, 0}, "issue406.go:146") assertNoError(err, t, "FindLocation()") _, err = c.CreateBreakpoint(&api.Breakpoint{Addr: locs[0].PC}) assertNoError(err, t, "CreateBreakpoint()") ch := c.Continue() state := <-ch assertNoError(state.Err, t, "Continue()") - v, err := c.EvalVariable(api.EvalScope{-1, 0}, "cfgtree") + v, err := c.EvalVariable(api.EvalScope{-1, 0, 0}, "cfgtree") assertNoError(err, t, "EvalVariable()") vs := v.MultilineString("") t.Logf("cfgtree formats to: %s\n", vs) diff --git a/service/test/integration2_test.go b/service/test/integration2_test.go index 86af8486..654c524e 100644 --- a/service/test/integration2_test.go +++ b/service/test/integration2_test.go @@ -484,7 +484,7 @@ func TestClientServer_infoLocals(t *testing.T) { if state.Err != nil { t.Fatalf("Unexpected error: %v, state: %#v", state.Err, state) } - locals, err := c.ListLocalVariables(api.EvalScope{-1, 0}, normalLoadConfig) + locals, err := c.ListLocalVariables(api.EvalScope{-1, 0, 0}, normalLoadConfig) if err != nil { t.Fatalf("Unexpected error: %v", err) } @@ -513,7 +513,7 @@ func TestClientServer_infoArgs(t *testing.T) { if len(regs) == 0 { t.Fatal("Expected string showing registers values, got empty string") } - locals, err := c.ListFunctionArgs(api.EvalScope{-1, 0}, normalLoadConfig) + locals, err := c.ListFunctionArgs(api.EvalScope{-1, 0, 0}, normalLoadConfig) if err != nil { t.Fatalf("Unexpected error: %v", err) } @@ -755,7 +755,7 @@ func TestClientServer_EvalVariable(t *testing.T) { t.Fatalf("Continue(): %v\n", state.Err) } - var1, err := c.EvalVariable(api.EvalScope{-1, 0}, "a1", normalLoadConfig) + var1, err := c.EvalVariable(api.EvalScope{-1, 0, 0}, "a1", normalLoadConfig) assertNoError(err, t, "EvalVariable") t.Logf("var1: %s", var1.SinglelineString()) @@ -774,9 +774,9 @@ func TestClientServer_SetVariable(t *testing.T) { t.Fatalf("Continue(): %v\n", state.Err) } - assertNoError(c.SetVariable(api.EvalScope{-1, 0}, "a2", "8"), t, "SetVariable()") + assertNoError(c.SetVariable(api.EvalScope{-1, 0, 0}, "a2", "8"), t, "SetVariable()") - a2, err := c.EvalVariable(api.EvalScope{-1, 0}, "a2", normalLoadConfig) + a2, err := c.EvalVariable(api.EvalScope{-1, 0, 0}, "a2", normalLoadConfig) if err != nil { t.Fatalf("Could not evaluate variable: %v", err) } @@ -909,10 +909,10 @@ func TestIssue355(t *testing.T) { assertError(err, t, "ListThreads()") _, err = c.GetThread(tid) assertError(err, t, "GetThread()") - assertError(c.SetVariable(api.EvalScope{gid, 0}, "a", "10"), t, "SetVariable()") - _, err = c.ListLocalVariables(api.EvalScope{gid, 0}, normalLoadConfig) + assertError(c.SetVariable(api.EvalScope{gid, 0, 0}, "a", "10"), t, "SetVariable()") + _, err = c.ListLocalVariables(api.EvalScope{gid, 0, 0}, normalLoadConfig) assertError(err, t, "ListLocalVariables()") - _, err = c.ListFunctionArgs(api.EvalScope{gid, 0}, normalLoadConfig) + _, err = c.ListFunctionArgs(api.EvalScope{gid, 0, 0}, normalLoadConfig) assertError(err, t, "ListFunctionArgs()") _, err = c.ListRegisters(0, false) assertError(err, t, "ListRegisters()") @@ -920,9 +920,9 @@ func TestIssue355(t *testing.T) { assertError(err, t, "ListGoroutines()") _, err = c.Stacktrace(gid, 10, false, &normalLoadConfig) assertError(err, t, "Stacktrace()") - _, err = c.FindLocation(api.EvalScope{gid, 0}, "+1") + _, err = c.FindLocation(api.EvalScope{gid, 0, 0}, "+1") assertError(err, t, "FindLocation()") - _, err = c.DisassemblePC(api.EvalScope{-1, 0}, 0x40100, api.IntelFlavour) + _, err = c.DisassemblePC(api.EvalScope{-1, 0, 0}, 0x40100, api.IntelFlavour) assertError(err, t, "DisassemblePC()") }) } @@ -937,12 +937,12 @@ func TestDisasm(t *testing.T) { state := <-ch assertNoError(state.Err, t, "Continue()") - locs, err := c.FindLocation(api.EvalScope{-1, 0}, "main.main") + locs, err := c.FindLocation(api.EvalScope{-1, 0, 0}, "main.main") assertNoError(err, t, "FindLocation()") if len(locs) != 1 { t.Fatalf("wrong number of locations for main.main: %d", len(locs)) } - d1, err := c.DisassemblePC(api.EvalScope{-1, 0}, locs[0].PC, api.IntelFlavour) + d1, err := c.DisassemblePC(api.EvalScope{-1, 0, 0}, locs[0].PC, api.IntelFlavour) assertNoError(err, t, "DisassemblePC()") if len(d1) < 2 { t.Fatalf("wrong size of disassembly: %d", len(d1)) @@ -950,7 +950,7 @@ func TestDisasm(t *testing.T) { pcstart := d1[0].Loc.PC pcend := d1[len(d1)-1].Loc.PC + uint64(len(d1[len(d1)-1].Bytes)) - d2, err := c.DisassembleRange(api.EvalScope{-1, 0}, pcstart, pcend, api.IntelFlavour) + d2, err := c.DisassembleRange(api.EvalScope{-1, 0, 0}, pcstart, pcend, api.IntelFlavour) assertNoError(err, t, "DisassembleRange()") if len(d1) != len(d2) { @@ -959,7 +959,7 @@ func TestDisasm(t *testing.T) { t.Fatal("mismatched length between disassemble pc and disassemble range") } - d3, err := c.DisassemblePC(api.EvalScope{-1, 0}, state.CurrentThread.PC, api.IntelFlavour) + d3, err := c.DisassemblePC(api.EvalScope{-1, 0, 0}, state.CurrentThread.PC, api.IntelFlavour) assertNoError(err, t, "DisassemblePC() - second call") if len(d1) != len(d3) { @@ -1003,7 +1003,7 @@ func TestDisasm(t *testing.T) { state, err := c.StepInstruction() assertNoError(err, t, fmt.Sprintf("StepInstruction() %d", count)) - d3, err = c.DisassemblePC(api.EvalScope{-1, 0}, state.CurrentThread.PC, api.IntelFlavour) + d3, err = c.DisassemblePC(api.EvalScope{-1, 0, 0}, state.CurrentThread.PC, api.IntelFlavour) assertNoError(err, t, fmt.Sprintf("StepInstruction() %d", count)) curinstr := getCurinstr(d3) @@ -1068,7 +1068,7 @@ func TestClientServer_CondBreakpoint(t *testing.T) { state := <-c.Continue() assertNoError(state.Err, t, "Continue()") - nvar, err := c.EvalVariable(api.EvalScope{-1, 0}, "n", normalLoadConfig) + nvar, err := c.EvalVariable(api.EvalScope{-1, 0, 0}, "n", normalLoadConfig) assertNoError(err, t, "EvalVariable()") if nvar.SinglelineString() != "7" { @@ -1174,14 +1174,14 @@ func TestTypesCommand(t *testing.T) { func TestIssue406(t *testing.T) { protest.AllowRecording(t) withTestClient2("issue406", t, func(c service.Client) { - locs, err := c.FindLocation(api.EvalScope{-1, 0}, "issue406.go:146") + locs, err := c.FindLocation(api.EvalScope{-1, 0, 0}, "issue406.go:146") assertNoError(err, t, "FindLocation()") _, err = c.CreateBreakpoint(&api.Breakpoint{Addr: locs[0].PC}) assertNoError(err, t, "CreateBreakpoint()") ch := c.Continue() state := <-ch assertNoError(state.Err, t, "Continue()") - v, err := c.EvalVariable(api.EvalScope{-1, 0}, "cfgtree", normalLoadConfig) + v, err := c.EvalVariable(api.EvalScope{-1, 0, 0}, "cfgtree", normalLoadConfig) assertNoError(err, t, "EvalVariable()") vs := v.MultilineString("") t.Logf("cfgtree formats to: %s\n", vs) @@ -1193,7 +1193,7 @@ func TestEvalExprName(t *testing.T) { state := <-c.Continue() assertNoError(state.Err, t, "Continue()") - var1, err := c.EvalVariable(api.EvalScope{-1, 0}, "i1+1", normalLoadConfig) + var1, err := c.EvalVariable(api.EvalScope{-1, 0, 0}, "i1+1", normalLoadConfig) assertNoError(err, t, "EvalVariable") const name = "i1+1" @@ -1511,7 +1511,7 @@ func TestAcceptMulticlient(t *testing.T) { } func mustHaveDebugCalls(t *testing.T, c service.Client) { - locs, err := c.FindLocation(api.EvalScope{-1, 0}, "runtime.debugCallV1") + locs, err := c.FindLocation(api.EvalScope{-1, 0, 0}, "runtime.debugCallV1") if len(locs) == 0 || err != nil { t.Skip("function calls not supported on this version of go") } @@ -1552,7 +1552,7 @@ func TestClientServerFunctionCallBadPos(t *testing.T) { protest.MustSupportFunctionCalls(t, testBackend) withTestClient2("fncall", t, func(c service.Client) { mustHaveDebugCalls(t, c) - loc, err := c.FindLocation(api.EvalScope{-1, 0}, "fmt/print.go:649") + loc, err := c.FindLocation(api.EvalScope{-1, 0, 0}, "fmt/print.go:649") assertNoError(err, t, "could not find location") _, err = c.CreateBreakpoint(&api.Breakpoint{File: loc[0].File, Line: loc[0].Line}) -- GitLab