Browse Source

Added UI for debug steps

pull/728/merge
Siegfried Pammer 9 years ago
parent
commit
b2ef367c77
  1. 1
      ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj
  2. 5
      ICSharpCode.Decompiler/IL/Transforms/BlockTransform.cs
  3. 2
      ICSharpCode.Decompiler/IL/Transforms/IILTransform.cs
  4. 49
      ICSharpCode.Decompiler/IL/Transforms/Stepper.cs
  5. 17
      ILSpy/Commands/ShowDebugSteps.cs
  6. 18
      ILSpy/DebugSteps.xaml
  7. 86
      ILSpy/DebugSteps.xaml.cs
  8. 5
      ILSpy/DecompilationOptions.cs
  9. 8
      ILSpy/ILSpy.csproj
  10. 20
      ILSpy/Languages/ILAstLanguage.cs

1
ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj

@ -44,6 +44,7 @@ @@ -44,6 +44,7 @@
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|AnyCPU'">
<Prefer32Bit>false</Prefer32Bit>
<DefineConstants>TRACE;DEBUG;STEP</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|AnyCPU'">
<Prefer32Bit>false</Prefer32Bit>

5
ICSharpCode.Decompiler/IL/Transforms/BlockTransform.cs

@ -89,6 +89,8 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -89,6 +89,8 @@ namespace ICSharpCode.Decompiler.IL.Transforms
void VisitBlock(ControlFlowNode cfgNode, BlockTransformContext context)
{
Block block = (Block)cfgNode.UserData;
context.Stepper.StartGroup(block.Label, block);
// First, process the children in the dominator tree.
// The ConditionDetection transform requires dominated blocks to
// be already processed.
@ -97,13 +99,14 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -97,13 +99,14 @@ namespace ICSharpCode.Decompiler.IL.Transforms
}
context.ControlFlowNode = cfgNode;
context.Block = (Block)cfgNode.UserData;
context.Block = block;
context.Block.CheckInvariant(ILPhase.Normal);
foreach (var transform in blockTransforms) {
context.CancellationToken.ThrowIfCancellationRequested();
transform.Run(context.Block, context);
context.Block.CheckInvariant(ILPhase.Normal);
}
context.Stepper.EndGroup();
}
}
}

2
ICSharpCode.Decompiler/IL/Transforms/IILTransform.cs

@ -42,6 +42,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -42,6 +42,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
public ILTransformContext()
{
Stepper = new Stepper();
}
public ILTransformContext(ILTransformContext context)
@ -49,6 +50,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -49,6 +50,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
this.TypeSystem = context.TypeSystem;
this.Settings = context.Settings;
this.CancellationToken = context.CancellationToken;
this.Stepper = context.Stepper;
}
/// <summary>

49
ICSharpCode.Decompiler/IL/Transforms/Stepper.cs

@ -49,6 +49,29 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -49,6 +49,29 @@ namespace ICSharpCode.Decompiler.IL.Transforms
#endif
}
}
public IList<Node> Steps => steps;
public int StepLimit { get; set; } = int.MaxValue;
public class Node
{
public string Description { get; set; }
public ILInstruction Position { get; set; }
public int Step { get; set; }
public ICollection<Node> Children { get; } = new List<Node>();
}
readonly Stack<Node> groups;
readonly IList<Node> steps;
int step = 0;
public Stepper()
{
steps = new List<Node>();
groups = new Stack<Node>();
}
/// <summary>
/// Call this method immediately before performing a transform step.
@ -58,7 +81,31 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -58,7 +81,31 @@ namespace ICSharpCode.Decompiler.IL.Transforms
/// </summary>
public void Step(string description, ILInstruction near)
{
// TODO: implement stepping
StepInternal(description, near);
}
private Node StepInternal(string description, ILInstruction near)
{
if (step >= StepLimit)
throw new StepLimitReachedException();
var stepNode = new Node { Description = $"{description} ({step})", Position = near, Step = step };
var p = groups.PeekOrDefault();
if (p != null)
p.Children.Add(stepNode);
else
steps.Add(stepNode);
step++;
return stepNode;
}
public void StartGroup(string description, ILInstruction near)
{
groups.Push(StepInternal(description, near));
}
public void EndGroup()
{
groups.Pop();
}
}
}

17
ILSpy/Commands/ShowDebugSteps.cs

@ -0,0 +1,17 @@ @@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ICSharpCode.ILSpy.Commands
{
[ExportMainMenuCommand(Menu = "_View", Header = "_Show debug steps", MenuOrder = 5000)]
class ShowDebugSteps : SimpleCommand
{
public override void Execute(object parameter)
{
DebugSteps.Show();
}
}
}

18
ILSpy/DebugSteps.xaml

@ -0,0 +1,18 @@ @@ -0,0 +1,18 @@
<UserControl x:Class="ICSharpCode.ILSpy.DebugSteps"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:ICSharpCode.ILSpy"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<TreeView Name="tree" MouseDoubleClick="tree_MouseDoubleClick">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Children}">
<TextBlock Text="{Binding Description}" />
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
</Grid>
</UserControl>

86
ILSpy/DebugSteps.xaml.cs

@ -0,0 +1,86 @@ @@ -0,0 +1,86 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using ICSharpCode.Decompiler.IL.Transforms;
namespace ICSharpCode.ILSpy
{
/// <summary>
/// Interaktionslogik für DebugSteps.xaml
/// </summary>
public partial class DebugSteps : UserControl, IPane
{
ILAstLanguage language;
DebugSteps()
{
InitializeComponent();
MainWindow.Instance.SessionSettings.FilterSettings.PropertyChanged += FilterSettings_PropertyChanged;
MainWindow.Instance.SelectionChanged += SelectionChanged;
if (MainWindow.Instance.CurrentLanguage is ILAstLanguage l) {
l.StepperUpdated += ILAstStepperUpdated;
language = l;
ILAstStepperUpdated(null, null);
}
}
private void SelectionChanged(object sender, SelectionChangedEventArgs e)
{
Dispatcher.Invoke(() => tree.ItemsSource = null);
}
private void FilterSettings_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
if (e.PropertyName == "CurrentLanguage") {
if (language != null) {
language.StepperUpdated -= ILAstStepperUpdated;
}
if (MainWindow.Instance.CurrentLanguage is ILAstLanguage l) {
l.StepperUpdated += ILAstStepperUpdated;
language = l;
ILAstStepperUpdated(null, null);
}
}
}
private void ILAstStepperUpdated(object sender, EventArgs e)
{
if (language == null) return;
Dispatcher.Invoke(() => tree.ItemsSource = language.Stepper.Steps);
}
public static void Show()
{
MainWindow.Instance.ShowInTopPane("Debug Steps", new DebugSteps());
}
void IPane.Closed()
{
MainWindow.Instance.SessionSettings.FilterSettings.PropertyChanged -= FilterSettings_PropertyChanged;
MainWindow.Instance.SelectionChanged -= SelectionChanged;
if (language != null) {
language.StepperUpdated -= ILAstStepperUpdated;
}
}
private void tree_MouseDoubleClick(object sender, MouseButtonEventArgs e)
{
Stepper.Node n = (Stepper.Node)tree.SelectedItem;
var window = MainWindow.Instance;
window.TextView.DecompileAsync(window.CurrentLanguage, window.SelectedNodes, new DecompilationOptions() { StepLimit = n.Step + 1 });
}
}
}

5
ILSpy/DecompilationOptions.cs

@ -62,6 +62,11 @@ namespace ICSharpCode.ILSpy @@ -62,6 +62,11 @@ namespace ICSharpCode.ILSpy
/// </remarks>
public TextView.DecompilerTextViewState TextViewState { get; set; }
/// <summary>
/// Used internally for debugging.
/// </summary>
internal int StepLimit = int.MaxValue;
public DecompilationOptions()
{
this.DecompilerSettings = DecompilerSettingsPanel.CurrentDecompilerSettings;

8
ILSpy/ILSpy.csproj

@ -130,6 +130,7 @@ @@ -130,6 +130,7 @@
<Compile Include="Commands\ExitCommand.cs" />
<Compile Include="Commands\CommandWrapper.cs" />
<Compile Include="Commands\OpenListCommand.cs" />
<Compile Include="Commands\ShowDebugSteps.cs" />
<Compile Include="Commands\SortAssemblyListCommand.cs" />
<Compile Include="Controls\CustomDialog.cs">
<SubType>Form</SubType>
@ -147,6 +148,9 @@ @@ -147,6 +148,9 @@
<Compile Include="CreateListDialog.xaml.cs">
<DependentUpon>CreateListDialog.xaml</DependentUpon>
</Compile>
<Compile Include="DebugSteps.xaml.cs">
<DependentUpon>DebugSteps.xaml</DependentUpon>
</Compile>
<Compile Include="ILSpyTraceListener.cs" />
<Compile Include="Languages\CSharpLanguage.cs" />
<Compile Include="DecompilationOptions.cs" />
@ -333,6 +337,10 @@ @@ -333,6 +337,10 @@
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="DebugSteps.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="MainWindow.xaml" />
<Page Include="OpenFromGacDialog.xaml" />
<Page Include="OpenListDialog.xaml" />

20
ILSpy/Languages/ILAstLanguage.cs

@ -36,7 +36,14 @@ namespace ICSharpCode.ILSpy @@ -36,7 +36,14 @@ namespace ICSharpCode.ILSpy
/// </summary>
abstract class ILAstLanguage : Language
{
//ILAstOptimizationStep? abortBeforeStep;
public event EventHandler StepperUpdated;
protected virtual void OnStepperUpdated(EventArgs e = null)
{
StepperUpdated?.Invoke(this, e ?? new EventArgs());
}
public Stepper Stepper { get; set; } = new Stepper();
readonly string name;
@ -161,8 +168,17 @@ namespace ICSharpCode.ILSpy @@ -161,8 +168,17 @@ namespace ICSharpCode.ILSpy
var typeSystem = new DecompilerTypeSystem(method.Module);
ILReader reader = new ILReader(typeSystem);
ILFunction il = reader.ReadIL(method.Body, options.CancellationToken);
il.RunTransforms(transforms, new ILTransformContext { Settings = options.DecompilerSettings, TypeSystem = typeSystem });
ILTransformContext context = new ILTransformContext { Settings = options.DecompilerSettings, TypeSystem = typeSystem };
context.Stepper.StepLimit = options.StepLimit;
try {
il.RunTransforms(transforms, context);
} catch (StepLimitReachedException) {
il.WriteTo(output);
return;
}
Stepper = context.Stepper;
il.WriteTo(output);
OnStepperUpdated(new EventArgs());
}
}
}

Loading…
Cancel
Save