diff --git a/src/neo-vm/Debugger.cs b/src/neo-vm/Debugger.cs new file mode 100644 index 00000000..8518e3ef --- /dev/null +++ b/src/neo-vm/Debugger.cs @@ -0,0 +1,78 @@ +using System.Collections.Generic; + +namespace Neo.VM +{ + public class Debugger + { + private readonly ExecutionEngine engine; + private readonly Dictionary> break_points = new Dictionary>(new HashComparer()); + + public Debugger(ExecutionEngine engine) + { + this.engine = engine; + } + + public void AddBreakPoint(byte[] script_hash, uint position) + { + if (!break_points.TryGetValue(script_hash, out HashSet hashset)) + { + hashset = new HashSet(); + break_points.Add(script_hash, hashset); + } + hashset.Add(position); + } + + public void Execute() + { + engine.State &= ~VMState.BREAK; + while (!engine.State.HasFlag(VMState.HALT) && !engine.State.HasFlag(VMState.FAULT) && !engine.State.HasFlag(VMState.BREAK)) + { + engine.ExecuteNext(); + if (engine.State == VMState.NONE && engine.InvocationStack.Count > 0 && break_points.Count > 0) + { + if (break_points.TryGetValue(engine.CurrentContext.ScriptHash, out HashSet hashset) && hashset.Contains((uint)engine.CurrentContext.InstructionPointer)) + engine.State = VMState.BREAK; + } + } + } + + public bool RemoveBreakPoint(byte[] script_hash, uint position) + { + if (!break_points.TryGetValue(script_hash, out HashSet hashset)) return false; + if (!hashset.Remove(position)) return false; + if (hashset.Count == 0) break_points.Remove(script_hash); + return true; + } + + public void StepInto() + { + if (engine.State.HasFlag(VMState.HALT) || engine.State.HasFlag(VMState.FAULT)) return; + engine.ExecuteNext(); + if (engine.State == VMState.NONE) + engine.State = VMState.BREAK; + } + + public void StepOut() + { + engine.State &= ~VMState.BREAK; + int c = engine.InvocationStack.Count; + while (!engine.State.HasFlag(VMState.HALT) && !engine.State.HasFlag(VMState.FAULT) && !engine.State.HasFlag(VMState.BREAK) && engine.InvocationStack.Count >= c) + engine.ExecuteNext(); + if (engine.State == VMState.NONE) + engine.State = VMState.BREAK; + } + + public void StepOver() + { + if (engine.State.HasFlag(VMState.HALT) || engine.State.HasFlag(VMState.FAULT)) return; + engine.State &= ~VMState.BREAK; + int c = engine.InvocationStack.Count; + do + { + engine.ExecuteNext(); + } while (!engine.State.HasFlag(VMState.HALT) && !engine.State.HasFlag(VMState.FAULT) && !engine.State.HasFlag(VMState.BREAK) && engine.InvocationStack.Count > c); + if (engine.State == VMState.NONE) + engine.State = VMState.BREAK; + } + } +} diff --git a/src/neo-vm/ExecutionEngine.cs b/src/neo-vm/ExecutionEngine.cs index 940320dc..f529184a 100644 --- a/src/neo-vm/ExecutionEngine.cs +++ b/src/neo-vm/ExecutionEngine.cs @@ -57,7 +57,6 @@ public class ExecutionEngine : IDisposable private bool is_stackitem_count_strict = true; private readonly IScriptTable table; - private readonly Dictionary> break_points = new Dictionary>(new HashComparer()); public IScriptContainer ScriptContainer { get; } public ICrypto Crypto { get; } @@ -67,7 +66,7 @@ public class ExecutionEngine : IDisposable public ExecutionContext CurrentContext => InvocationStack.Peek(); public ExecutionContext CallingContext => InvocationStack.Count > 1 ? InvocationStack.Peek(1) : null; public ExecutionContext EntryContext => InvocationStack.Peek(InvocationStack.Count - 1); - public VMState State { get; protected set; } = VMState.BREAK; + public VMState State { get; internal protected set; } = VMState.BREAK; public ExecutionEngine(IScriptContainer container, ICrypto crypto, IScriptTable table = null, IInteropService service = null) { @@ -77,16 +76,6 @@ public ExecutionEngine(IScriptContainer container, ICrypto crypto, IScriptTable this.Service = service; } - public void AddBreakPoint(byte[] script_hash, uint position) - { - if (!break_points.TryGetValue(script_hash, out HashSet hashset)) - { - hashset = new HashSet(); - break_points.Add(script_hash, hashset); - } - hashset.Add(position); - } - #region Limits /// @@ -207,7 +196,7 @@ public void Execute() ExecuteNext(); } - protected void ExecuteNext() + internal protected void ExecuteNext() { if (InvocationStack.Count == 0) { @@ -225,11 +214,6 @@ protected void ExecuteNext() { State = VMState.FAULT; } - if (State == VMState.NONE && InvocationStack.Count > 0) - { - if (break_points.Count > 0 && break_points.TryGetValue(CurrentContext.ScriptHash, out HashSet hashset) && hashset.Contains((uint)CurrentContext.InstructionPointer)) - State = VMState.BREAK; - } } } @@ -1307,47 +1291,5 @@ protected virtual bool PreExecuteInstruction() { return true; } - - public bool RemoveBreakPoint(byte[] script_hash, uint position) - { - if (!break_points.TryGetValue(script_hash, out HashSet hashset)) - return false; - if (!hashset.Remove(position)) - return false; - if (hashset.Count == 0) - break_points.Remove(script_hash); - return true; - } - - public void StepInto() - { - if (State.HasFlag(VMState.HALT) || State.HasFlag(VMState.FAULT)) return; - ExecuteNext(); - if (State == VMState.NONE) - State = VMState.BREAK; - } - - public void StepOut() - { - State &= ~VMState.BREAK; - int c = InvocationStack.Count; - while (!State.HasFlag(VMState.HALT) && !State.HasFlag(VMState.FAULT) && !State.HasFlag(VMState.BREAK) && InvocationStack.Count >= c) - ExecuteNext(); - if (State == VMState.NONE) - State = VMState.BREAK; - } - - public void StepOver() - { - if (State.HasFlag(VMState.HALT) || State.HasFlag(VMState.FAULT)) return; - State &= ~VMState.BREAK; - int c = InvocationStack.Count; - do - { - ExecuteNext(); - } while (!State.HasFlag(VMState.HALT) && !State.HasFlag(VMState.FAULT) && !State.HasFlag(VMState.BREAK) && InvocationStack.Count > c); - if (State == VMState.NONE) - State = VMState.BREAK; - } } } diff --git a/tests/neo-vm.Tests/VMJsonTestBase.cs b/tests/neo-vm.Tests/VMJsonTestBase.cs index d51d826e..de3fdcf4 100644 --- a/tests/neo-vm.Tests/VMJsonTestBase.cs +++ b/tests/neo-vm.Tests/VMJsonTestBase.cs @@ -50,6 +50,7 @@ public void ExecuteTest(VMUT ut) using (var engine = new ExecutionEngine(scriptContainer, Crypto.Default, scriptTable, service)) { + Debugger debugger = new Debugger(engine); engine.LoadScript(test.Script); // Execute Steps @@ -64,10 +65,10 @@ public void ExecuteTest(VMUT ut) { switch (run) { - case VMUTActionType.Execute: engine.Execute(); break; - case VMUTActionType.StepInto: engine.StepInto(); break; - case VMUTActionType.StepOut: engine.StepOut(); break; - case VMUTActionType.StepOver: engine.StepOver(); break; + case VMUTActionType.Execute: debugger.Execute(); break; + case VMUTActionType.StepInto: debugger.StepInto(); break; + case VMUTActionType.StepOut: debugger.StepOut(); break; + case VMUTActionType.StepOver: debugger.StepOver(); break; } }