vm: fix debugger and add tests

1. `Run()` must be able to continue execution after a breakpoint.
2. VM must stop right before the breakpoint, not after.
3. Initial vm state is NONE, not HALT.
This commit is contained in:
Evgenii Stratonikov 2020-08-18 11:13:09 +03:00
parent 8659fd79e5
commit a080d24cf5
3 changed files with 52 additions and 11 deletions

View file

@ -221,7 +221,7 @@ func (c *Context) Equals(s stackitem.Item) bool {
func (c *Context) atBreakPoint() bool {
for _, n := range c.breakPoints {
if n == c.ip {
if n == c.nextip {
return true
}
}

42
pkg/vm/debug_test.go Normal file
View file

@ -0,0 +1,42 @@
package vm
import (
"math/big"
"testing"
"github.com/nspcc-dev/neo-go/pkg/vm/opcode"
"github.com/stretchr/testify/require"
)
func TestVM_Debug(t *testing.T) {
prog := makeProgram(opcode.CALL, 3, opcode.RET,
opcode.PUSH2, opcode.PUSH3, opcode.ADD, opcode.RET)
t.Run("BreakPoint", func(t *testing.T) {
v := load(prog)
v.AddBreakPoint(3)
v.AddBreakPoint(5)
require.NoError(t, v.Run())
require.Equal(t, 3, v.Context().NextIP())
require.NoError(t, v.Run())
require.Equal(t, 5, v.Context().NextIP())
require.NoError(t, v.Run())
require.Equal(t, 1, v.estack.len)
require.Equal(t, big.NewInt(5), v.estack.Top().Value())
})
t.Run("StepInto", func(t *testing.T) {
v := load(prog)
require.NoError(t, v.StepInto())
require.Equal(t, 3, v.Context().NextIP())
require.NoError(t, v.StepOut())
require.Equal(t, 2, v.Context().NextIP())
require.Equal(t, 1, v.estack.len)
require.Equal(t, big.NewInt(5), v.estack.Top().Value())
})
t.Run("StepOver", func(t *testing.T) {
v := load(prog)
require.NoError(t, v.StepOver())
require.Equal(t, 2, v.Context().NextIP())
require.Equal(t, 1, v.estack.len)
require.Equal(t, big.NewInt(5), v.estack.Top().Value())
})
}

View file

@ -89,7 +89,7 @@ func New() *VM {
// NewWithTrigger returns a new VM for executions triggered by t.
func NewWithTrigger(t trigger.Type) *VM {
vm := &VM{
state: HaltState,
state: NoneState,
istack: NewStack("invocation"),
refs: newRefCounter(),
keys: make(map[string]*keys.PublicKey),
@ -358,11 +358,6 @@ func (v *VM) Run() error {
// HaltState (the default) or BreakState are safe to continue.
v.state = NoneState
for {
// check for breakpoint before executing the next instruction
ctx := v.Context()
if ctx != nil && ctx.atBreakPoint() {
v.state = BreakState
}
switch {
case v.state.HasFlag(FaultState):
// Should be caught and reported already by the v.Step(),
@ -379,6 +374,11 @@ func (v *VM) Run() error {
v.state = FaultState
return errors.New("unknown state")
}
// check for breakpoint before executing the next instruction
ctx := v.Context()
if ctx != nil && ctx.atBreakPoint() {
v.state = BreakState
}
}
}
@ -430,14 +430,15 @@ func (v *VM) StepOut() error {
var err error
if v.state == BreakState {
v.state = NoneState
} else {
v.state = BreakState
}
expSize := v.istack.len
for v.state == NoneState && v.istack.len >= expSize {
err = v.StepInto()
}
if v.state == NoneState {
v.state = BreakState
}
return err
}
@ -451,8 +452,6 @@ func (v *VM) StepOver() error {
if v.state == BreakState {
v.state = NoneState
} else {
v.state = BreakState
}
expSize := v.istack.len