diff --git a/src/MICore/CommandFactories/MICommandFactory.cs b/src/MICore/CommandFactories/MICommandFactory.cs index c73d5c088..99fad5d43 100644 --- a/src/MICore/CommandFactories/MICommandFactory.cs +++ b/src/MICore/CommandFactories/MICommandFactory.cs @@ -5,11 +5,8 @@ using System.Collections.Generic; using System.Diagnostics; using System.Threading.Tasks; -using System.IO; using System.Text; -using System.Collections.ObjectModel; using System.Linq; -using System.Globalization; using Microsoft.VisualStudio.Debugger.Interop; namespace MICore @@ -216,33 +213,43 @@ public async Task StackListVariables(PrintValues printValues, in #region Program Execution - public async Task ExecStep(int threadId, ResultClass resultClass = ResultClass.running) + public async Task ExecStep(int threadId, bool forward = true, ResultClass resultClass = ResultClass.running) { string command = "-exec-step"; + if (!forward) + command += " --reverse"; await ThreadFrameCmdAsync(command, resultClass, threadId, 0); } - public async Task ExecNext(int threadId, ResultClass resultClass = ResultClass.running) + public async Task ExecNext(int threadId, bool forward = true, ResultClass resultClass = ResultClass.running) { string command = "-exec-next"; + if (!forward) + command += " --reverse"; await ThreadFrameCmdAsync(command, resultClass, threadId, 0); } - public async Task ExecFinish(int threadId, ResultClass resultClass = ResultClass.running) + public async Task ExecFinish(int threadId, bool forward = true, ResultClass resultClass = ResultClass.running) { string command = "-exec-finish"; + if (!forward) + command += " --reverse"; await ThreadFrameCmdAsync(command, resultClass, threadId, 0); } - public async Task ExecStepInstruction(int threadId, ResultClass resultClass = ResultClass.running) + public async Task ExecStepInstruction(int threadId, bool forward = true, ResultClass resultClass = ResultClass.running) { string command = "-exec-step-instruction"; + if (!forward) + command += " --reverse"; await ThreadFrameCmdAsync(command, resultClass, threadId, 0); } - public async Task ExecNextInstruction(int threadId, ResultClass resultClass = ResultClass.running) + public async Task ExecNextInstruction(int threadId, bool forward = true, ResultClass resultClass = ResultClass.running) { string command = "-exec-next-instruction"; + if (!forward) + command += " --reverse"; await ThreadFrameCmdAsync(command, resultClass, threadId, 0); } @@ -258,9 +265,11 @@ public virtual async Task ExecRun() /// /// Continues running the target process /// - public async Task ExecContinue() + public async Task ExecContinue(bool forward = true) { string command = "-exec-continue"; + if (!forward) + command += " --reverse"; await _debugger.CmdAsync(command, ResultClass.running); } @@ -661,6 +670,8 @@ public virtual bool CanDetach() return true; } + abstract public Task GetTargetFeatures(); + abstract public Task> StartAddressesForLine(string file, uint line); /// diff --git a/src/MICore/CommandFactories/clrdbg.cs b/src/MICore/CommandFactories/clrdbg.cs index 05523bf6e..e29cc2c98 100644 --- a/src/MICore/CommandFactories/clrdbg.cs +++ b/src/MICore/CommandFactories/clrdbg.cs @@ -5,8 +5,6 @@ using System.Collections.Generic; using System.Diagnostics; using System.Threading.Tasks; -using System.IO; -using System.Text; using System.Collections.ObjectModel; using System.Linq; using System.Globalization; @@ -14,7 +12,7 @@ namespace MICore { - internal class ClrdbgMICommandFactory : MICommandFactory + internal sealed class ClrdbgMICommandFactory : MICommandFactory { private readonly static Guid s_exceptionCategory_CLR = new Guid("449EC4CC-30D2-4032-9256-EE18EB41B62B"); private readonly static Guid s_exceptionCategory_MDA = new Guid("6ECE07A9-0EDE-45C4-8296-818D8FC401D4"); @@ -89,6 +87,11 @@ public override Task> StartAddressesForLine(string file, uint line) return Task.FromResult>(null); } + public override Task GetTargetFeatures() + { + throw new NotImplementedException(); + } + public override Task EnableTargetAsyncOption() { // clrdbg is always in target-async mode diff --git a/src/MICore/CommandFactories/gdb.cs b/src/MICore/CommandFactories/gdb.cs index 3382fbfe0..ae7f867cf 100644 --- a/src/MICore/CommandFactories/gdb.cs +++ b/src/MICore/CommandFactories/gdb.cs @@ -3,17 +3,13 @@ using System; using System.Collections.Generic; -using System.Diagnostics; using System.Threading.Tasks; using System.IO; -using System.Text; -using System.Collections.ObjectModel; -using System.Linq; using System.Globalization; namespace MICore { - internal class GdbMICommandFactory : MICommandFactory + internal sealed class GdbMICommandFactory : MICommandFactory { private int _currentThreadId = 0; private uint _currentFrameLevel = 0; @@ -183,6 +179,12 @@ public override async Task> StartAddressesForLine(string file, uint return addresses; } + public override async Task GetTargetFeatures() + { + Results results = await _debugger.CmdAsync("-list-target-features", ResultClass.done); + return results.Find("features").AsStrings; + } + public override Task EnableTargetAsyncOption() { // Linux attach TODO: GDB will fail this command when attaching. This is worked around diff --git a/src/MICore/CommandFactories/lldb.cs b/src/MICore/CommandFactories/lldb.cs index e571841ca..feac018c4 100644 --- a/src/MICore/CommandFactories/lldb.cs +++ b/src/MICore/CommandFactories/lldb.cs @@ -3,18 +3,15 @@ using System; using System.Collections.Generic; -using System.Diagnostics; using System.Threading.Tasks; using System.IO; using System.Text; -using System.Collections.ObjectModel; -using System.Linq; using System.Globalization; using Microsoft.VisualStudio.Debugger.Interop; namespace MICore { - internal class LlldbMICommandFactory : MICommandFactory + internal sealed class LlldbMICommandFactory : MICommandFactory { public override string Name { @@ -119,6 +116,11 @@ public override Task EnableTargetAsyncOption() return Task.FromResult((object)null); } + public override Task GetTargetFeatures() + { + throw new NotImplementedException(); + } + public override string GetTargetArchitectureCommand() { return "platform status"; diff --git a/src/MIDebugEngine/AD7.Impl/AD7Engine.cs b/src/MIDebugEngine/AD7.Impl/AD7Engine.cs index f3f404244..e266aa2ba 100755 --- a/src/MIDebugEngine/AD7.Impl/AD7Engine.cs +++ b/src/MIDebugEngine/AD7.Impl/AD7Engine.cs @@ -3,8 +3,6 @@ using System; using System.Collections.Generic; -using System.Text; -using System.Runtime.ExceptionServices; using Microsoft.VisualStudio.Debugger.Interop; using Microsoft.VisualStudio.Debugger.Interop.UnixPortSupplier; using System.Diagnostics; @@ -35,7 +33,7 @@ namespace Microsoft.MIDebugEngine [System.Runtime.InteropServices.ComVisible(true)] [System.Runtime.InteropServices.Guid("0fc2f352-2fc1-4f80-8736-51cd1ab28f16")] - sealed public class AD7Engine : IDebugEngine2, IDebugEngineLaunch2, IDebugEngine3, IDebugProgram3, IDebugEngineProgram2, IDebugMemoryBytes2, IDebugEngine110, IDebugProgramDAP, IDebugMemoryBytesDAP, IDisposable + sealed public class AD7Engine : IDebugEngine2, IDebugEngineLaunch2, IDebugEngine3, IDebugProgram3, IDebugEngineProgram2, IDebugReversibleEngineProgram160, IDebugMemoryBytes2, IDebugEngine110, IDebugProgramDAP, IDebugMemoryBytesDAP, IDisposable { // used to send events to the debugger. Some examples of these events are thread create, exception thrown, module load. private EngineCallback _engineCallback; @@ -176,6 +174,7 @@ internal bool ProgramCreateEventSent get; private set; } + public ExecuteDirection ExecutionDirection { get; private set; } public string GetAddressDescription(ulong ip) { @@ -800,11 +799,11 @@ public int Continue(IDebugThread2 pThread) { if (_pollThread.IsPollThread()) { - _debuggedProcess.Continue(thread?.GetDebuggedThread()); + _debuggedProcess.Continue(thread?.GetDebuggedThread(), ExecutionDirection); } else { - _pollThread.RunOperation(() => _debuggedProcess.Continue(thread?.GetDebuggedThread())); + _pollThread.RunOperation(() => _debuggedProcess.Continue(thread?.GetDebuggedThread(), ExecutionDirection)); } } catch (InvalidCoreDumpOperationException) @@ -995,7 +994,7 @@ public int Step(IDebugThread2 pThread, enum_STEPKIND kind, enum_STEPUNIT unit) return Constants.E_FAIL; } - _debuggedProcess.WorkerThread.RunOperation(() => _debuggedProcess.Step(thread.GetDebuggedThread().Id, kind, unit)); + _debuggedProcess.WorkerThread.RunOperation(() => _debuggedProcess.Step(thread.GetDebuggedThread().Id, kind, unit, ExecutionDirection)); } catch (InvalidCoreDumpOperationException) { @@ -1083,6 +1082,19 @@ public int WatchForThreadStep(IDebugProgram2 pOriginatingProgram, uint dwTid, in #endregion + #region IDebugEngineProgram2 Members + int IDebugReversibleEngineProgram160.CanReverse() + { + return DebuggedProcess.TargetFeatures.Contains("reverse") ? Constants.S_OK : Constants.S_FALSE; + } + + int IDebugReversibleEngineProgram160.SetExecuteDirection(ExecuteDirection ExecuteDirection) + { + ExecutionDirection = ExecuteDirection; + return Constants.S_OK; + } + #endregion + #region IDebugMemoryBytes2 Members public int GetSize(out ulong pqwSize) diff --git a/src/MIDebugEngine/Engine.Impl/DebuggedProcess.cs b/src/MIDebugEngine/Engine.Impl/DebuggedProcess.cs index b0db63117..b3e39d58d 100755 --- a/src/MIDebugEngine/Engine.Impl/DebuggedProcess.cs +++ b/src/MIDebugEngine/Engine.Impl/DebuggedProcess.cs @@ -11,7 +11,6 @@ using System.Globalization; using System.IO; using System.Linq; -using System.Reflection; using System.Text; using System.Threading; using System.Threading.Tasks; @@ -31,6 +30,7 @@ internal class DebuggedProcess : MICore.Debugger public Disassembly Disassembly { get; private set; } public ExceptionManager ExceptionManager { get; private set; } public CygwinFilePathMapper CygwinFilePathMapper { get; private set; } + public string[] TargetFeatures { get; private set; } private List _moduleList; private ISampleEngineCallback _callback; @@ -618,6 +618,8 @@ public async Task Initialize(HostWaitLoop waitLoop, CancellationToken token) } } } + // now the exe is loaded and we can check target features + TargetFeatures = await MICommandFactory.GetTargetFeatures(); success = true; } @@ -1597,10 +1599,16 @@ protected override void ScheduleResultProcessing(Action func) _worker.PostOperation(() => { func(); }); } - public async Task Execute(DebuggedThread thread) + public async Task Execute(DebuggedThread thread, ExecuteDirection executionDirection = ExecuteDirection.ExecuteDirection_Forward) { await ExceptionManager.EnsureSettingsUpdated(); + if (executionDirection == ExecuteDirection.ExecuteDirection_Reverse) + { + await MICommandFactory.ExecContinue(false); + return; + } + // Should clear stepping state if (_worker.IsPollThread()) { @@ -1612,30 +1620,32 @@ public async Task Execute(DebuggedThread thread) } } - public Task Continue(DebuggedThread thread) + public Task Continue(DebuggedThread thread, ExecuteDirection executionDirection = ExecuteDirection.ExecuteDirection_Forward) { // Called after Stopping event - return Execute(thread); + return Execute(thread, executionDirection); } - public async Task Step(int threadId, enum_STEPKIND kind, enum_STEPUNIT unit) + public async Task Step(int threadId, enum_STEPKIND kind, enum_STEPUNIT unit, ExecuteDirection direction = ExecuteDirection.ExecuteDirection_Forward) { this.VerifyNotDebuggingCoreDump(); await ExceptionManager.EnsureSettingsUpdated(); + // STEP_BACKWARDS is deprecated, use direction + bool isForwardStep = direction == ExecuteDirection.ExecuteDirection_Forward; if ((unit == enum_STEPUNIT.STEP_LINE) || (unit == enum_STEPUNIT.STEP_STATEMENT)) { switch (kind) { case enum_STEPKIND.STEP_INTO: - await MICommandFactory.ExecStep(threadId); + await MICommandFactory.ExecStep(threadId, isForwardStep); break; case enum_STEPKIND.STEP_OVER: - await MICommandFactory.ExecNext(threadId); + await MICommandFactory.ExecNext(threadId, isForwardStep); break; case enum_STEPKIND.STEP_OUT: - await MICommandFactory.ExecFinish(threadId); + await MICommandFactory.ExecFinish(threadId, isForwardStep); break; default: throw new NotImplementedException(); @@ -1646,13 +1656,13 @@ public async Task Step(int threadId, enum_STEPKIND kind, enum_STEPUNIT unit) switch (kind) { case enum_STEPKIND.STEP_INTO: - await MICommandFactory.ExecStepInstruction(threadId); + await MICommandFactory.ExecStepInstruction(threadId, isForwardStep); break; case enum_STEPKIND.STEP_OVER: - await MICommandFactory.ExecNextInstruction(threadId); + await MICommandFactory.ExecNextInstruction(threadId, isForwardStep); break; case enum_STEPKIND.STEP_OUT: - await MICommandFactory.ExecFinish(threadId); + await MICommandFactory.ExecFinish(threadId, isForwardStep); break; default: throw new NotImplementedException(); diff --git a/src/MIDebugEngine/MIDebugEngine.csproj b/src/MIDebugEngine/MIDebugEngine.csproj index 08f4034ea..0748e60a1 100755 --- a/src/MIDebugEngine/MIDebugEngine.csproj +++ b/src/MIDebugEngine/MIDebugEngine.csproj @@ -90,6 +90,9 @@ $(NuGetPackagesDirectory)/Microsoft.VisualStudio.Debugger.Interop.15.0.15.8.28010/lib/net20/Microsoft.VisualStudio.Debugger.Interop.15.0.dll + + $(NuGetPackagesDirectory)/Microsoft.VisualStudio.Debugger.Interop.16.0.16.7.30328.139/lib/net20/Microsoft.VisualStudio.Debugger.Interop.16.0.dll + diff --git a/src/MakePIAPortable/MakePIAPortable.csproj b/src/MakePIAPortable/MakePIAPortable.csproj index f6ee28b87..00b8da502 100644 --- a/src/MakePIAPortable/MakePIAPortable.csproj +++ b/src/MakePIAPortable/MakePIAPortable.csproj @@ -57,6 +57,9 @@ $(NuGetPackagesDirectory)/Microsoft.VisualStudio.Debugger.Interop.15.0.15.8.28010/lib/net20/Microsoft.VisualStudio.Debugger.Interop.15.0.dll + + $(NuGetPackagesDirectory)/Microsoft.VisualStudio.Debugger.Interop.16.0.16.7.30328.139/lib/net20/Microsoft.VisualStudio.Debugger.Interop.16.0.dll + @@ -85,6 +88,7 @@ + diff --git a/src/MakePIAPortable/MakePortableLegacyPIAs.cmd b/src/MakePIAPortable/MakePortableLegacyPIAs.cmd index 059c25b44..90c6473cb 100644 --- a/src/MakePIAPortable/MakePortableLegacyPIAs.cmd +++ b/src/MakePIAPortable/MakePortableLegacyPIAs.cmd @@ -28,6 +28,7 @@ set pias=%pias% Microsoft.VisualStudio.Debugger.Interop.10.0.dll set pias=%pias% Microsoft.VisualStudio.Debugger.Interop.11.0.dll set pias=%pias% Microsoft.VisualStudio.Debugger.Interop.12.0.dll set pias=%pias% Microsoft.VisualStudio.Debugger.Interop.15.0.dll +set pias=%pias% Microsoft.VisualStudio.Debugger.Interop.16.0.dll set PIAERROR= for %%i in (%pias%) do call :ProcessPIA %%i diff --git a/src/OpenDebugAD7/AD7DebugSession.cs b/src/OpenDebugAD7/AD7DebugSession.cs index 1053dc39b..ada869100 100644 --- a/src/OpenDebugAD7/AD7DebugSession.cs +++ b/src/OpenDebugAD7/AD7DebugSession.cs @@ -26,6 +26,18 @@ namespace OpenDebugAD7 { + // not in the DAP dll yet + internal sealed class CapabilitiesEvent : DebugEvent + { + internal CapabilitiesEvent() + : base("capabilities") + { + } + + [JsonProperty("capabilities")] + internal InitializeResponse Capabilities; + } + internal class AD7DebugSession : DebugAdapterBase, IDebugPortNotify2, IDebugEventCallback2 { // This is a general purpose lock. Don't hold it across long operations. @@ -521,7 +533,7 @@ private void SetAllExceptions(enum_EXCEPTION_STATE state) } } - private void StepInternal(int threadId, enum_STEPKIND stepKind, SteppingGranularity granularity, string errorMessage) + private void StepInternal(int threadId, enum_STEPKIND stepKind, SteppingGranularity granularity, ExecuteDirection stepDirection, string errorMessage) { // If we are already running ignore additional step requests if (!m_isStopped) @@ -555,6 +567,7 @@ private void StepInternal(int threadId, enum_STEPKIND stepKind, SteppingGranular } try { + ((IDebugReversibleEngineProgram160)m_engine).SetExecuteDirection(stepDirection); builder.CheckHR(m_program.Step(thread, stepKind, stepUnit)); } catch (AD7Exception) @@ -780,6 +793,14 @@ protected override void HandleLaunchRequestAsync(IRequestResponder responder) + private void ContinueInternal(int threadId, ExecuteDirection direction) { - int threadId = responder.Arguments.ThreadId; - // Sometimes we can get a threadId of 0. Make sure we don't look it up in this case, otherwise we will crash. IDebugThread2 thread = null; lock (m_threads) @@ -1140,13 +1167,9 @@ protected override void HandleContinueRequestAsync(IRequestResponder responder) + { + try + { + ContinueInternal(responder.Arguments.ThreadId, ExecuteDirection.ExecuteDirection_Forward); + responder.SetResponse(new ContinueResponse()); + } + catch (AD7Exception e) + { + responder.SetError(new ProtocolException(e.Message)); + } + + } + + protected override void HandleReverseContinueRequestAsync(IRequestResponder responder) + { + try + { + ContinueInternal(responder.Arguments.ThreadId, ExecuteDirection.ExecuteDirection_Reverse); + responder.SetResponse(new ContinueResponse()); + } + catch (AD7Exception e) + { + responder.SetError(new ProtocolException(e.Message)); + } + } + protected override void HandleStepInRequestAsync(IRequestResponder responder) { try { var granularity = responder.Arguments.Granularity.GetValueOrDefault(); - StepInternal(responder.Arguments.ThreadId, enum_STEPKIND.STEP_INTO, granularity, AD7Resources.Error_Scenario_Step_In); + StepInternal(responder.Arguments.ThreadId, enum_STEPKIND.STEP_INTO, granularity, ExecuteDirection.ExecuteDirection_Forward, AD7Resources.Error_Scenario_Step_In); responder.SetResponse(new StepInResponse()); } catch (AD7Exception e) @@ -1179,7 +1229,7 @@ protected override void HandleNextRequestAsync(IRequestResponder try { var granularity = responder.Arguments.Granularity.GetValueOrDefault(); - StepInternal(responder.Arguments.ThreadId, enum_STEPKIND.STEP_OVER, granularity, AD7Resources.Error_Scenario_Step_Next); + StepInternal(responder.Arguments.ThreadId, enum_STEPKIND.STEP_OVER, granularity, ExecuteDirection.ExecuteDirection_Forward, AD7Resources.Error_Scenario_Step_Next); responder.SetResponse(new NextResponse()); } catch (AD7Exception e) @@ -1193,7 +1243,7 @@ protected override void HandleStepOutRequestAsync(IRequestResponder$(NuGetPackagesDirectory)/Microsoft.VisualStudio.Debugger.Interop.15.0.15.8.28010/lib/net20/Microsoft.VisualStudio.Debugger.Interop.15.0.dll true + + $(NuGetPackagesDirectory)/Microsoft.VisualStudio.Debugger.Interop.16.0.16.7.30328.139/lib/net20/Microsoft.VisualStudio.Debugger.Interop.16.0.dll + true + $(NuGetPackagesDirectory)/Microsoft.VisualStudio.Shared.VsCodeDebugProtocol.16.7.40526.2/lib/net45/Microsoft.VisualStudio.Shared.VSCodeDebugProtocol.dll @@ -181,6 +185,7 @@ + diff --git a/src/OpenDebugAD7/packages.config b/src/OpenDebugAD7/packages.config index eabba745f..5b0e94dbd 100644 --- a/src/OpenDebugAD7/packages.config +++ b/src/OpenDebugAD7/packages.config @@ -2,7 +2,8 @@ - + +`