Skip to content

Commit a38d0b6

Browse files
committed
implement reverse execution
send CapabilitiesEvent after target launch to correctly signal StepBack support introduce IDebugReversibleEngineProgram160 to properly handle execution direction like VS implement DAP step granularity
1 parent 4c21dbd commit a38d0b6

File tree

7 files changed

+184
-74
lines changed

7 files changed

+184
-74
lines changed

src/MICore/CommandFactories/MICommandFactory.cs

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,8 @@
55
using System.Collections.Generic;
66
using System.Diagnostics;
77
using System.Threading.Tasks;
8-
using System.IO;
98
using System.Text;
10-
using System.Collections.ObjectModel;
119
using System.Linq;
12-
using System.Globalization;
1310
using Microsoft.VisualStudio.Debugger.Interop;
1411

1512
namespace MICore
@@ -216,33 +213,43 @@ public async Task<ValueListValue> StackListVariables(PrintValues printValues, in
216213

217214
#region Program Execution
218215

219-
public async Task ExecStep(int threadId, ResultClass resultClass = ResultClass.running)
216+
public async Task ExecStep(int threadId, bool forward = true, ResultClass resultClass = ResultClass.running)
220217
{
221218
string command = "-exec-step";
219+
if (!forward)
220+
command += " --reverse";
222221
await ThreadFrameCmdAsync(command, resultClass, threadId, 0);
223222
}
224223

225-
public async Task ExecNext(int threadId, ResultClass resultClass = ResultClass.running)
224+
public async Task ExecNext(int threadId, bool forward = true, ResultClass resultClass = ResultClass.running)
226225
{
227226
string command = "-exec-next";
227+
if (!forward)
228+
command += " --reverse";
228229
await ThreadFrameCmdAsync(command, resultClass, threadId, 0);
229230
}
230231

231-
public async Task ExecFinish(int threadId, ResultClass resultClass = ResultClass.running)
232+
public async Task ExecFinish(int threadId, bool forward = true, ResultClass resultClass = ResultClass.running)
232233
{
233234
string command = "-exec-finish";
235+
if (!forward)
236+
command += " --reverse";
234237
await ThreadFrameCmdAsync(command, resultClass, threadId, 0);
235238
}
236239

237-
public async Task ExecStepInstruction(int threadId, ResultClass resultClass = ResultClass.running)
240+
public async Task ExecStepInstruction(int threadId, bool forward = true, ResultClass resultClass = ResultClass.running)
238241
{
239242
string command = "-exec-step-instruction";
243+
if (!forward)
244+
command += " --reverse";
240245
await ThreadFrameCmdAsync(command, resultClass, threadId, 0);
241246
}
242247

243-
public async Task ExecNextInstruction(int threadId, ResultClass resultClass = ResultClass.running)
248+
public async Task ExecNextInstruction(int threadId, bool forward = true, ResultClass resultClass = ResultClass.running)
244249
{
245250
string command = "-exec-next-instruction";
251+
if (!forward)
252+
command += " --reverse";
246253
await ThreadFrameCmdAsync(command, resultClass, threadId, 0);
247254
}
248255

@@ -258,9 +265,11 @@ public virtual async Task ExecRun()
258265
/// <summary>
259266
/// Continues running the target process
260267
/// </summary>
261-
public async Task ExecContinue()
268+
public async Task ExecContinue(bool forward = true)
262269
{
263270
string command = "-exec-continue";
271+
if (!forward)
272+
command += " --reverse";
264273
await _debugger.CmdAsync(command, ResultClass.running);
265274
}
266275

@@ -661,6 +670,12 @@ public virtual bool CanDetach()
661670
return true;
662671
}
663672

673+
public virtual async Task<string[]> GetTargetFeatures()
674+
{
675+
Results results = await _debugger.CmdAsync("-list-target-features", ResultClass.done);
676+
return results.Find<ValueListValue>("features").AsStrings;
677+
}
678+
664679
abstract public Task<List<ulong>> StartAddressesForLine(string file, uint line);
665680

666681
/// <summary>

src/MIDebugEngine/AD7.Impl/AD7Engine.cs

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@
33

44
using System;
55
using System.Collections.Generic;
6-
using System.Text;
7-
using System.Runtime.ExceptionServices;
86
using Microsoft.VisualStudio.Debugger.Interop;
97
using Microsoft.VisualStudio.Debugger.Interop.UnixPortSupplier;
108
using System.Diagnostics;
@@ -35,7 +33,7 @@ namespace Microsoft.MIDebugEngine
3533

3634
[System.Runtime.InteropServices.ComVisible(true)]
3735
[System.Runtime.InteropServices.Guid("0fc2f352-2fc1-4f80-8736-51cd1ab28f16")]
38-
sealed public class AD7Engine : IDebugEngine2, IDebugEngineLaunch2, IDebugEngine3, IDebugProgram3, IDebugEngineProgram2, IDebugMemoryBytes2, IDebugEngine110, IDebugProgramDAP, IDisposable
36+
sealed public class AD7Engine : IDebugEngine2, IDebugEngineLaunch2, IDebugEngine3, IDebugProgram3, IDebugEngineProgram2, IDebugReversibleEngineProgram160, IDebugMemoryBytes2, IDebugEngine110, IDebugProgramDAP, IDisposable
3937
{
4038
// used to send events to the debugger. Some examples of these events are thread create, exception thrown, module load.
4139
private EngineCallback _engineCallback;
@@ -176,6 +174,7 @@ internal bool ProgramCreateEventSent
176174
get;
177175
private set;
178176
}
177+
public ExecuteDirection ExecutionDirection { get; private set; }
179178

180179
public string GetAddressDescription(ulong ip)
181180
{
@@ -800,11 +799,11 @@ public int Continue(IDebugThread2 pThread)
800799
{
801800
if (_pollThread.IsPollThread())
802801
{
803-
_debuggedProcess.Continue(thread?.GetDebuggedThread());
802+
_debuggedProcess.Continue(thread?.GetDebuggedThread(), ExecutionDirection);
804803
}
805804
else
806805
{
807-
_pollThread.RunOperation(() => _debuggedProcess.Continue(thread?.GetDebuggedThread()));
806+
_pollThread.RunOperation(() => _debuggedProcess.Continue(thread?.GetDebuggedThread(), ExecutionDirection));
808807
}
809808
}
810809
catch (InvalidCoreDumpOperationException)
@@ -995,7 +994,7 @@ public int Step(IDebugThread2 pThread, enum_STEPKIND kind, enum_STEPUNIT unit)
995994
return Constants.E_FAIL;
996995
}
997996

998-
_debuggedProcess.WorkerThread.RunOperation(() => _debuggedProcess.Step(thread.GetDebuggedThread().Id, kind, unit));
997+
_debuggedProcess.WorkerThread.RunOperation(() => _debuggedProcess.Step(thread.GetDebuggedThread().Id, kind, unit, ExecutionDirection));
999998
}
1000999
catch (InvalidCoreDumpOperationException)
10011000
{
@@ -1083,6 +1082,19 @@ public int WatchForThreadStep(IDebugProgram2 pOriginatingProgram, uint dwTid, in
10831082

10841083
#endregion
10851084

1085+
#region IDebugEngineProgram2 Members
1086+
int IDebugReversibleEngineProgram160.CanReverse()
1087+
{
1088+
return DebuggedProcess.TargetFeatures.Contains("reverse") ? Constants.S_OK : Constants.S_FALSE;
1089+
}
1090+
1091+
int IDebugReversibleEngineProgram160.SetExecuteDirection(ExecuteDirection ExecuteDirection)
1092+
{
1093+
ExecutionDirection = ExecuteDirection;
1094+
return Constants.S_OK;
1095+
}
1096+
#endregion
1097+
10861098
#region IDebugMemoryBytes2 Members
10871099

10881100
public int GetSize(out ulong pqwSize)

src/MIDebugEngine/Engine.Impl/DebuggedProcess.cs

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
using System.Globalization;
1212
using System.IO;
1313
using System.Linq;
14-
using System.Reflection;
1514
using System.Text;
1615
using System.Threading;
1716
using System.Threading.Tasks;
@@ -31,6 +30,7 @@ internal class DebuggedProcess : MICore.Debugger
3130
public Disassembly Disassembly { get; private set; }
3231
public ExceptionManager ExceptionManager { get; private set; }
3332
public CygwinFilePathMapper CygwinFilePathMapper { get; private set; }
33+
public string[] TargetFeatures { get; private set; }
3434

3535
private List<DebuggedModule> _moduleList;
3636
private ISampleEngineCallback _callback;
@@ -618,6 +618,8 @@ public async Task Initialize(HostWaitLoop waitLoop, CancellationToken token)
618618
}
619619
}
620620
}
621+
// now the exe is loaded and we can check target features
622+
TargetFeatures = await MICommandFactory.GetTargetFeatures();
621623

622624
success = true;
623625
}
@@ -1597,10 +1599,16 @@ protected override void ScheduleResultProcessing(Action func)
15971599
_worker.PostOperation(() => { func(); });
15981600
}
15991601

1600-
public async Task Execute(DebuggedThread thread)
1602+
public async Task Execute(DebuggedThread thread, ExecuteDirection executionDirection = ExecuteDirection.ExecuteDirection_Forward)
16011603
{
16021604
await ExceptionManager.EnsureSettingsUpdated();
16031605

1606+
if (executionDirection == ExecuteDirection.ExecuteDirection_Reverse)
1607+
{
1608+
await MICommandFactory.ExecContinue(false);
1609+
return;
1610+
}
1611+
16041612
// Should clear stepping state
16051613
if (_worker.IsPollThread())
16061614
{
@@ -1612,30 +1620,32 @@ public async Task Execute(DebuggedThread thread)
16121620
}
16131621
}
16141622

1615-
public Task Continue(DebuggedThread thread)
1623+
public Task Continue(DebuggedThread thread, ExecuteDirection executionDirection = ExecuteDirection.ExecuteDirection_Forward)
16161624
{
16171625
// Called after Stopping event
1618-
return Execute(thread);
1626+
return Execute(thread, executionDirection);
16191627
}
16201628

1621-
public async Task Step(int threadId, enum_STEPKIND kind, enum_STEPUNIT unit)
1629+
public async Task Step(int threadId, enum_STEPKIND kind, enum_STEPUNIT unit, ExecuteDirection direction = ExecuteDirection.ExecuteDirection_Forward)
16221630
{
16231631
this.VerifyNotDebuggingCoreDump();
16241632

16251633
await ExceptionManager.EnsureSettingsUpdated();
16261634

1635+
// STEP_BACKWARDS is deprecated, use direction
1636+
bool isForwardStep = direction == ExecuteDirection.ExecuteDirection_Forward;
16271637
if ((unit == enum_STEPUNIT.STEP_LINE) || (unit == enum_STEPUNIT.STEP_STATEMENT))
16281638
{
16291639
switch (kind)
16301640
{
16311641
case enum_STEPKIND.STEP_INTO:
1632-
await MICommandFactory.ExecStep(threadId);
1642+
await MICommandFactory.ExecStep(threadId, isForwardStep);
16331643
break;
16341644
case enum_STEPKIND.STEP_OVER:
1635-
await MICommandFactory.ExecNext(threadId);
1645+
await MICommandFactory.ExecNext(threadId, isForwardStep);
16361646
break;
16371647
case enum_STEPKIND.STEP_OUT:
1638-
await MICommandFactory.ExecFinish(threadId);
1648+
await MICommandFactory.ExecFinish(threadId, isForwardStep);
16391649
break;
16401650
default:
16411651
throw new NotImplementedException();
@@ -1646,13 +1656,13 @@ public async Task Step(int threadId, enum_STEPKIND kind, enum_STEPUNIT unit)
16461656
switch (kind)
16471657
{
16481658
case enum_STEPKIND.STEP_INTO:
1649-
await MICommandFactory.ExecStepInstruction(threadId);
1659+
await MICommandFactory.ExecStepInstruction(threadId, isForwardStep);
16501660
break;
16511661
case enum_STEPKIND.STEP_OVER:
1652-
await MICommandFactory.ExecNextInstruction(threadId);
1662+
await MICommandFactory.ExecNextInstruction(threadId, isForwardStep);
16531663
break;
16541664
case enum_STEPKIND.STEP_OUT:
1655-
await MICommandFactory.ExecFinish(threadId);
1665+
await MICommandFactory.ExecFinish(threadId, isForwardStep);
16561666
break;
16571667
default:
16581668
throw new NotImplementedException();

src/MIDebugEngine/MIDebugEngine.csproj

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,9 @@
9090
<Reference Include="Microsoft.VisualStudio.Debugger.Interop.15.0">
9191
<HintPath>$(NuGetPackagesDirectory)/Microsoft.VisualStudio.Debugger.Interop.15.0.15.8.28010/lib/net20/Microsoft.VisualStudio.Debugger.Interop.15.0.dll</HintPath>
9292
</Reference>
93+
<Reference Include="Microsoft.VisualStudio.Debugger.Interop.16.0">
94+
<HintPath>$(NuGetPackagesDirectory)/Microsoft.VisualStudio.Debugger.Interop.16.0.16.7.30328.139/lib/net20/Microsoft.VisualStudio.Debugger.Interop.16.0.dll</HintPath>
95+
</Reference>
9396
</ItemGroup>
9497
<ItemGroup>
9598
<Compile Include="AD7.Definitions\AD7Guids.cs" />

0 commit comments

Comments
 (0)