Skip to content

Commit a0c9fb8

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
1 parent 0b9ad84 commit a0c9fb8

File tree

12 files changed

+156
-52
lines changed

12 files changed

+156
-52
lines changed

src/MICore/CommandFactories/MICommandFactory.cs

Lines changed: 20 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,8 @@ public virtual bool CanDetach()
661670
return true;
662671
}
663672

673+
abstract public Task<string[]> GetTargetFeatures();
674+
664675
abstract public Task<List<ulong>> StartAddressesForLine(string file, uint line);
665676

666677
/// <summary>

src/MICore/CommandFactories/clrdbg.cs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,14 @@
55
using System.Collections.Generic;
66
using System.Diagnostics;
77
using System.Threading.Tasks;
8-
using System.IO;
9-
using System.Text;
108
using System.Collections.ObjectModel;
119
using System.Linq;
1210
using System.Globalization;
1311
using Microsoft.VisualStudio.Debugger.Interop;
1412

1513
namespace MICore
1614
{
17-
internal class ClrdbgMICommandFactory : MICommandFactory
15+
internal sealed class ClrdbgMICommandFactory : MICommandFactory
1816
{
1917
private readonly static Guid s_exceptionCategory_CLR = new Guid("449EC4CC-30D2-4032-9256-EE18EB41B62B");
2018
private readonly static Guid s_exceptionCategory_MDA = new Guid("6ECE07A9-0EDE-45C4-8296-818D8FC401D4");
@@ -89,6 +87,11 @@ public override Task<List<ulong>> StartAddressesForLine(string file, uint line)
8987
return Task.FromResult<List<ulong>>(null);
9088
}
9189

90+
public override Task<string[]> GetTargetFeatures()
91+
{
92+
throw new NotImplementedException();
93+
}
94+
9295
public override Task EnableTargetAsyncOption()
9396
{
9497
// clrdbg is always in target-async mode

src/MICore/CommandFactories/gdb.cs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,13 @@
33

44
using System;
55
using System.Collections.Generic;
6-
using System.Diagnostics;
76
using System.Threading.Tasks;
87
using System.IO;
9-
using System.Text;
10-
using System.Collections.ObjectModel;
11-
using System.Linq;
128
using System.Globalization;
139

1410
namespace MICore
1511
{
16-
internal class GdbMICommandFactory : MICommandFactory
12+
internal sealed class GdbMICommandFactory : MICommandFactory
1713
{
1814
private int _currentThreadId = 0;
1915
private uint _currentFrameLevel = 0;
@@ -183,6 +179,12 @@ public override async Task<List<ulong>> StartAddressesForLine(string file, uint
183179
return addresses;
184180
}
185181

182+
public override async Task<string[]> GetTargetFeatures()
183+
{
184+
Results results = await _debugger.CmdAsync("-list-target-features", ResultClass.done);
185+
return results.Find<ValueListValue>("features").AsStrings;
186+
}
187+
186188
public override Task EnableTargetAsyncOption()
187189
{
188190
// Linux attach TODO: GDB will fail this command when attaching. This is worked around

src/MICore/CommandFactories/lldb.cs

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

44
using System;
55
using System.Collections.Generic;
6-
using System.Diagnostics;
76
using System.Threading.Tasks;
87
using System.IO;
98
using System.Text;
10-
using System.Collections.ObjectModel;
11-
using System.Linq;
129
using System.Globalization;
1310
using Microsoft.VisualStudio.Debugger.Interop;
1411

1512
namespace MICore
1613
{
17-
internal class LlldbMICommandFactory : MICommandFactory
14+
internal sealed class LlldbMICommandFactory : MICommandFactory
1815
{
1916
public override string Name
2017
{
@@ -119,6 +116,11 @@ public override Task EnableTargetAsyncOption()
119116
return Task.FromResult((object)null);
120117
}
121118

119+
public override Task<string[]> GetTargetFeatures()
120+
{
121+
throw new NotImplementedException();
122+
}
123+
122124
public override string GetTargetArchitectureCommand()
123125
{
124126
return "platform status";

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, IDebugMemoryBytesDAP, IDisposable
36+
sealed public class AD7Engine : IDebugEngine2, IDebugEngineLaunch2, IDebugEngine3, IDebugProgram3, IDebugEngineProgram2, IDebugReversibleEngineProgram160, IDebugMemoryBytes2, IDebugEngine110, IDebugProgramDAP, IDebugMemoryBytesDAP, 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" />

src/MakePIAPortable/MakePIAPortable.csproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,9 @@
5757
<Reference Include="Microsoft.VisualStudio.Debugger.Interop.15.0">
5858
<HintPath>$(NuGetPackagesDirectory)/Microsoft.VisualStudio.Debugger.Interop.15.0.15.8.28010/lib/net20/Microsoft.VisualStudio.Debugger.Interop.15.0.dll</HintPath>
5959
</Reference>
60+
<Reference Include="Microsoft.VisualStudio.Debugger.Interop.16.0">
61+
<HintPath>$(NuGetPackagesDirectory)/Microsoft.VisualStudio.Debugger.Interop.16.0.16.7.30328.139/lib/net20/Microsoft.VisualStudio.Debugger.Interop.16.0.dll</HintPath>
62+
</Reference>
6063
</ItemGroup>
6164
<UsingTask TaskName="FindILDAsm" TaskFactory="CodeTaskFactory" AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.Core.dll">
6265
<ParameterGroup>
@@ -85,6 +88,7 @@
8588
<DropSignedFile Include="$(PIAOutput)\Microsoft.VisualStudio.Debugger.Interop.11.0.dll" />
8689
<DropSignedFile Include="$(PIAOutput)\Microsoft.VisualStudio.Debugger.Interop.12.0.dll" />
8790
<DropSignedFile Include="$(PIAOutput)\Microsoft.VisualStudio.Debugger.Interop.15.0.dll" />
91+
<DropSignedFile Include="$(PIAOutput)\Microsoft.VisualStudio.Debugger.Interop.16.0.dll" />
8892
</ItemGroup>
8993
<Target Name="CopyToVSCodeFolder" AfterTargets="DropFiles">
9094
<ItemGroup>

src/MakePIAPortable/MakePortableLegacyPIAs.cmd

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ set pias=%pias% Microsoft.VisualStudio.Debugger.Interop.10.0.dll
2828
set pias=%pias% Microsoft.VisualStudio.Debugger.Interop.11.0.dll
2929
set pias=%pias% Microsoft.VisualStudio.Debugger.Interop.12.0.dll
3030
set pias=%pias% Microsoft.VisualStudio.Debugger.Interop.15.0.dll
31+
set pias=%pias% Microsoft.VisualStudio.Debugger.Interop.16.0.dll
3132

3233
set PIAERROR=
3334
for %%i in (%pias%) do call :ProcessPIA %%i

0 commit comments

Comments
 (0)