vm: add stepInto,stepOver,stepOut

Original C# vm debugger behavior
This commit is contained in:
Vsevolod Brekelov 2019-10-14 18:37:11 +03:00
parent aab2f9a837
commit 591d5eafbe
2 changed files with 124 additions and 0 deletions

View file

@ -128,6 +128,30 @@ Example:
> step 10`,
Func: handleStep,
},
{
Name: "stepinto",
Help: "Stepinto instruction to take in the debugger",
LongHelp: `Usage: stepInto
example:
> stepinto`,
Func: handleStepInto,
},
{
Name: "stepout",
Help: "Stepout instruction to take in the debugger",
LongHelp: `Usage: stepOut
example:
> stepout`,
Func: handleStepOut,
},
{
Name: "stepover",
Help: "Stepover instruction to take in the debugger",
LongHelp: `Usage: stepOver
example:
> stepover`,
Func: handleStepOver,
},
{
Name: "ops",
Help: "Dump opcodes of the current loaded program",
@ -297,6 +321,34 @@ func handleStep(c *ishell.Context) {
changePrompt(c, v)
}
func handleStepInto(c *ishell.Context) {
handleStepType(c, "into")
}
func handleStepOut(c *ishell.Context) {
handleStepType(c, "out")
}
func handleStepOver(c *ishell.Context) {
handleStepType(c, "over")
}
func handleStepType(c *ishell.Context, stepType string) {
if !checkVMIsReady(c) {
return
}
v := getVMFromContext(c)
switch stepType {
case "into":
v.StepInto()
case "out":
v.StepOut()
case "over":
v.StepOver()
}
changePrompt(c, v)
}
func handleOps(c *ishell.Context) {
if !checkVMIsReady(c) {
return

View file

@ -289,12 +289,84 @@ func (v *VM) Step() {
v.execute(ctx, op, param)
}
// StepInto behaves the same as “step over” in case if the line does not contain a function it otherwise
// the debugger will enter the called function and continue line-by-line debugging there.
func (v *VM) StepInto() {
ctx := v.Context()
if ctx == nil {
v.state |= haltState
}
if v.HasStopped() {
return
}
if ctx != nil && ctx.prog != nil {
op, param, err := ctx.Next()
if err != nil {
log.Printf("error encountered at instruction %d (%s)", ctx.ip, op)
log.Println(err)
v.state = faultState
}
v.execute(ctx, op, param)
i, op := ctx.CurrInstr()
fmt.Printf("at breakpoint %d (%s)\n", i, op.String())
}
cctx := v.Context()
if cctx != nil && cctx.atBreakPoint() {
v.state = breakState
}
}
// StepOut takes the debugger to the line where the current function was called.
func (v *VM) StepOut() {
if v.state == breakState {
v.state = noneState
} else {
v.state = breakState
}
expSize := v.istack.len
for v.state.HasFlag(noneState) && v.istack.len >= expSize {
v.StepInto()
}
}
// StepOver takes the debugger to the line that will step over a given line.
// If the line contains a function the function will be executed and the result returned without debugging each line.
func (v *VM) StepOver() {
if v.HasStopped() {
return
}
if v.state == breakState {
v.state = noneState
} else {
v.state = breakState
}
expSize := v.istack.len
for {
v.StepInto()
if !(v.state.HasFlag(noneState) && v.istack.len > expSize) {
break
}
}
}
// HasFailed returns whether VM is in the failed state now. Usually used to
// check status after Run.
func (v *VM) HasFailed() bool {
return v.state.HasFlag(faultState)
}
// HasStopped returns whether VM is in Halt or Failed state.
func (v *VM) HasStopped() bool {
return v.state.HasFlag(haltState) || v.state.HasFlag(faultState)
}
// SetCheckedHash sets checked hash for CHECKSIG and CHECKMULTISIG instructions.
func (v *VM) SetCheckedHash(h []byte) {
v.checkhash = make([]byte, len(h))