From b310187433b5f7585d1de19030d730c66bcf4793 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Srbeck=C3=BD?= Date: Thu, 24 Jan 2008 20:07:26 +0000 Subject: [PATCH] GUI debugging controls --- Decompiler.csproj | 1 + src/AstBuilder.cs | 2 +- src/AstMetodBodyBuilder.cs | 11 +-- src/ByteCode.cs | 8 +-- src/ControlFlow/Node.cs | 53 +++++++++++++++ src/ControlFlow/Nodes.cs | 28 ++------ src/MainForm.Designer.cs | 113 +++++++++++++++++++++++++++---- src/MainForm.cs | 50 +++++++++++++- src/Options.cs | 10 +++ src/Program.cs | 14 +--- src/StackExpression.cs | 6 +- src/StackExpressionCollection.cs | 1 + 12 files changed, 235 insertions(+), 62 deletions(-) create mode 100644 src/Options.cs diff --git a/Decompiler.csproj b/Decompiler.csproj index dec6cf25a..bba26f581 100644 --- a/Decompiler.csproj +++ b/Decompiler.csproj @@ -49,6 +49,7 @@ + diff --git a/src/AstBuilder.cs b/src/AstBuilder.cs index d6027e55d..a1da9ac62 100644 --- a/src/AstBuilder.cs +++ b/src/AstBuilder.cs @@ -32,7 +32,7 @@ namespace Decompiler code = code.Replace(":\r\n\t", ": "); code = code.Replace(": }", ":\r\n\t}"); code = code.Replace("\t", " "); - code = code.Replace("\"/*", "//"); + code = code.Replace("\"/*", ""); code = code.Replace("*/\";", ""); // Post processing commands diff --git a/src/AstMetodBodyBuilder.cs b/src/AstMetodBodyBuilder.cs index d46ff2278..61a488cac 100644 --- a/src/AstMetodBodyBuilder.cs +++ b/src/AstMetodBodyBuilder.cs @@ -36,6 +36,7 @@ namespace Decompiler exprCollection.Optimize(); MethodBodyGraph bodyGraph = new MethodBodyGraph(exprCollection); + bodyGraph.Optimize(); foreach(VariableDefinition varDef in methodDef.Body.Variables) { localVarTypes[varDef.Name] = varDef.VariableType; @@ -63,10 +64,10 @@ namespace Decompiler IEnumerable TransformNode(Node node) { - yield return MakeComment(node.ToString()); + yield return MakeComment("// " + node.ToString()); if (node is BasicBlock) { - yield return new Ast.LabelStatement(string.Format("BasicBlock_{0}", ((BasicBlock)node).Id)); + yield return new Ast.LabelStatement(((BasicBlock)node).Label); foreach(StackExpression expr in ((BasicBlock)node).Body) { yield return TransformExpression(expr); } @@ -86,6 +87,8 @@ namespace Decompiler } else { throw new Exception("Bad node type"); } + + yield return MakeComment(""); } Ast.Statement TransformExpression(StackExpression expr) @@ -119,7 +122,7 @@ namespace Decompiler static Ast.ExpressionStatement MakeComment(string text) { - text = "/* " + text + "*/"; + text = "/*" + text + "*/"; return new Ast.ExpressionStatement(new PrimitiveExpression(text, text)); } @@ -146,7 +149,7 @@ namespace Decompiler object operand = byteCode.Operand; Ast.TypeReference operandAsTypeRef = operand is Cecil.TypeReference ? new Ast.TypeReference(((Cecil.TypeReference)operand).FullName) : null; ByteCode operandAsByteCode = operand as ByteCode; - string operandAsByteCodeLabel = operand is ByteCode ? String.Format("IL_{0:X2}", ((ByteCode)operand).Offset) : null; + string operandAsByteCodeLabel = operand is ByteCode ? ((ByteCode)operand).Expression.BasicBlock.Label : null; Ast.Expression arg1 = args.Length >= 1 ? args[0] : null; Ast.Expression arg2 = args.Length >= 2 ? args[1] : null; Ast.Expression arg3 = args.Length >= 3 ? args[2] : null; diff --git a/src/ByteCode.cs b/src/ByteCode.cs index c73e7908a..77ac28e89 100644 --- a/src/ByteCode.cs +++ b/src/ByteCode.cs @@ -9,7 +9,7 @@ namespace Decompiler { public partial class ByteCode { - StackExpression owner; + StackExpression expression; ByteCode previous; ByteCode next; @@ -18,9 +18,9 @@ namespace Decompiler OpCode opCode; object operand; - public StackExpression Owner { - get { return owner; } - set { owner = value; } + public StackExpression Expression { + get { return expression; } + set { expression = value; } } public ByteCode Previous { diff --git a/src/ControlFlow/Node.cs b/src/ControlFlow/Node.cs index d7e2dbe1d..61a24c54e 100644 --- a/src/ControlFlow/Node.cs +++ b/src/ControlFlow/Node.cs @@ -23,12 +23,19 @@ namespace Decompiler.ControlFlow public abstract class Node { + public static int NextNodeID = 1; + + int id; Node parent; Node headChild; Set childs = new Set(); Set predecessors = new Set(); Set successors = new Set(); + public int ID { + get { return id; } + } + public Node Parent { get { return parent; } } @@ -53,6 +60,7 @@ namespace Decompiler.ControlFlow public Node(Node parent) { this.parent = parent; + this.id = NextNodeID++; } public void Optimize() @@ -60,6 +68,7 @@ namespace Decompiler.ControlFlow for(int i = 0; i < this.Childs.Count;) { Node child = childs[i]; if (child.Predecessors.Count == 1) { + if (Options.ReduceGraph-- <= 0) return; MergeChilds(child.Predecessors[0], child); i = 0; // Restart } else { @@ -146,5 +155,49 @@ namespace Decompiler.ControlFlow node.Predecessors.Clear(); node.Successors.Clear(); } + + public override string ToString() + { + System.Text.StringBuilder sb = new System.Text.StringBuilder(); + sb.Append(this.GetType().Name); + sb.Append(" "); + sb.Append(ID); + sb.Append(" "); + + if (this.Predecessors.Count > 0 || this.Successors.Count > 0) { + sb.Append("("); + if (this.Predecessors.Count > 0) { + sb.Append("Predecessors:"); + bool isFirst = true; + foreach(Node predecessor in this.Predecessors) { + if (isFirst) { + isFirst = false; + } else { + sb.Append(","); + } + sb.Append(predecessor.ID); + } + } + + if (this.Predecessors.Count > 0 && this.Successors.Count > 0) { + sb.Append(" "); + } + + if (this.Successors.Count > 0) { + sb.Append("Successors:"); + bool isFirst = true; + foreach(Node successor in this.Successors) { + if (isFirst) { + isFirst = false; + } else { + sb.Append(","); + } + sb.Append(successor.ID); + } + } + sb.Append(")"); + } + return sb.ToString(); + } } } diff --git a/src/ControlFlow/Nodes.cs b/src/ControlFlow/Nodes.cs index f4445d042..c72c92031 100644 --- a/src/ControlFlow/Nodes.cs +++ b/src/ControlFlow/Nodes.cs @@ -11,14 +11,13 @@ namespace Decompiler.ControlFlow if (exprs.Count == 0) throw new ArgumentException("Count == 0", "exprs"); BasicBlock basicBlock = null; - int basicBlockId = 1; for(int i = 0; i < exprs.Count; i++) { // Start new basic block if // - this is first expression // - last expression was branch // - this expression is branch target if (i == 0 || exprs[i - 1].BranchTarget != null || exprs[i].BranchesHere.Count > 0){ - basicBlock = new BasicBlock(this, basicBlockId++); + basicBlock = new BasicBlock(this); this.Childs.Add(basicBlock); } basicBlock.Body.Add(exprs[i]); @@ -54,11 +53,6 @@ namespace Decompiler.ControlFlow public AcyclicGraph(Node parent): base(parent){ } - - public override string ToString() - { - return "AcyclicGraph"; - } } public class Loop: Node @@ -66,34 +60,24 @@ namespace Decompiler.ControlFlow public Loop(Node parent): base(parent){ } - - public override string ToString() - { - return "Loop"; - } } public class BasicBlock: Node { - int id; List body = new List(); - public int Id { - get { return id; } + public string Label { + get { + return "BasicBlock_" + ID; + } } public List Body { get { return body; } } - public BasicBlock(Node parent, int id): base(parent) - { - this.id = id; - } - - public override string ToString() + public BasicBlock(Node parent): base(parent) { - return string.Format("BasicBlock {0}", id, body.Count); } } } diff --git a/src/MainForm.Designer.cs b/src/MainForm.Designer.cs index 70fe75762..9fd25b039 100644 --- a/src/MainForm.Designer.cs +++ b/src/MainForm.Designer.cs @@ -32,34 +32,119 @@ namespace Decompiler /// private void InitializeComponent() { - this.sourceCode = new System.Windows.Forms.TextBox(); + this.collapseCount = new System.Windows.Forms.NumericUpDown(); + this.reduceCount = new System.Windows.Forms.NumericUpDown(); + this.collapseBtn = new System.Windows.Forms.Button(); + this.reduceBtn = new System.Windows.Forms.Button(); + this.decompileBtn = new System.Windows.Forms.Button(); + this.sourceCodeBox = new System.Windows.Forms.RichTextBox(); + ((System.ComponentModel.ISupportInitialize)(this.collapseCount)).BeginInit(); + ((System.ComponentModel.ISupportInitialize)(this.reduceCount)).BeginInit(); this.SuspendLayout(); // - // sourceCode + // collapseCount // - this.sourceCode.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + this.collapseCount.Location = new System.Drawing.Point(12, 12); + this.collapseCount.Maximum = new decimal(new int[] { + 100000, + 0, + 0, + 0}); + this.collapseCount.Name = "collapseCount"; + this.collapseCount.Size = new System.Drawing.Size(120, 26); + this.collapseCount.TabIndex = 1; + this.collapseCount.Value = new decimal(new int[] { + 1000, + 0, + 0, + 0}); + this.collapseCount.ValueChanged += new System.EventHandler(this.CollapseCountValueChanged); + // + // reduceCount + // + this.reduceCount.Location = new System.Drawing.Point(308, 12); + this.reduceCount.Maximum = new decimal(new int[] { + 100000, + 0, + 0, + 0}); + this.reduceCount.Name = "reduceCount"; + this.reduceCount.Size = new System.Drawing.Size(120, 26); + this.reduceCount.TabIndex = 2; + this.reduceCount.Value = new decimal(new int[] { + 1000, + 0, + 0, + 0}); + this.reduceCount.ValueChanged += new System.EventHandler(this.ReduceCountValueChanged); + // + // collapseBtn + // + this.collapseBtn.Location = new System.Drawing.Point(138, 12); + this.collapseBtn.Name = "collapseBtn"; + this.collapseBtn.Size = new System.Drawing.Size(164, 26); + this.collapseBtn.TabIndex = 3; + this.collapseBtn.Text = "Collapse expression"; + this.collapseBtn.UseVisualStyleBackColor = true; + this.collapseBtn.Click += new System.EventHandler(this.CollapseBtnClick); + // + // reduceBtn + // + this.reduceBtn.Location = new System.Drawing.Point(434, 12); + this.reduceBtn.Name = "reduceBtn"; + this.reduceBtn.Size = new System.Drawing.Size(143, 26); + this.reduceBtn.TabIndex = 4; + this.reduceBtn.Text = "Reduce graph"; + this.reduceBtn.UseVisualStyleBackColor = true; + this.reduceBtn.Click += new System.EventHandler(this.ReduceBtnClick); + // + // decompileBtn + // + this.decompileBtn.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.decompileBtn.Font = new System.Drawing.Font("Microsoft Sans Serif", 8F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.decompileBtn.Location = new System.Drawing.Point(639, 12); + this.decompileBtn.Name = "decompileBtn"; + this.decompileBtn.Size = new System.Drawing.Size(109, 26); + this.decompileBtn.TabIndex = 5; + this.decompileBtn.Text = "Decompile"; + this.decompileBtn.UseVisualStyleBackColor = true; + this.decompileBtn.Click += new System.EventHandler(this.DecompileBtnClick); + // + // sourceCodeBox + // + this.sourceCodeBox.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); - this.sourceCode.Font = new System.Drawing.Font("Courier New", 10F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.sourceCode.Location = new System.Drawing.Point(12, 12); - this.sourceCode.Multiline = true; - this.sourceCode.Name = "sourceCode"; - this.sourceCode.ScrollBars = System.Windows.Forms.ScrollBars.Both; - this.sourceCode.Size = new System.Drawing.Size(736, 665); - this.sourceCode.TabIndex = 0; - this.sourceCode.WordWrap = false; + this.sourceCodeBox.Font = new System.Drawing.Font("Courier New", 10F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.sourceCodeBox.Location = new System.Drawing.Point(12, 45); + this.sourceCodeBox.Name = "sourceCodeBox"; + this.sourceCodeBox.Size = new System.Drawing.Size(736, 632); + this.sourceCodeBox.TabIndex = 6; + this.sourceCodeBox.Text = ""; + this.sourceCodeBox.WordWrap = false; // // MainForm // this.AutoScaleDimensions = new System.Drawing.SizeF(9F, 20F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.ClientSize = new System.Drawing.Size(760, 689); - this.Controls.Add(this.sourceCode); + this.Controls.Add(this.sourceCodeBox); + this.Controls.Add(this.decompileBtn); + this.Controls.Add(this.reduceBtn); + this.Controls.Add(this.collapseBtn); + this.Controls.Add(this.reduceCount); + this.Controls.Add(this.collapseCount); this.Name = "MainForm"; this.Text = "Decompiler"; + ((System.ComponentModel.ISupportInitialize)(this.collapseCount)).EndInit(); + ((System.ComponentModel.ISupportInitialize)(this.reduceCount)).EndInit(); this.ResumeLayout(false); - this.PerformLayout(); } - private System.Windows.Forms.TextBox sourceCode; + private System.Windows.Forms.RichTextBox sourceCodeBox; + private System.Windows.Forms.Button decompileBtn; + private System.Windows.Forms.Button reduceBtn; + private System.Windows.Forms.Button collapseBtn; + private System.Windows.Forms.NumericUpDown reduceCount; + private System.Windows.Forms.NumericUpDown collapseCount; } } diff --git a/src/MainForm.cs b/src/MainForm.cs index 18ade0766..36de821f9 100644 --- a/src/MainForm.cs +++ b/src/MainForm.cs @@ -3,6 +3,8 @@ using System.Collections.Generic; using System.Drawing; using System.Windows.Forms; +using Mono.Cecil; + namespace Decompiler { /// @@ -10,18 +12,60 @@ namespace Decompiler /// public partial class MainForm : Form { - public MainForm() + string filename; + + public MainForm(string filename) { + this.filename = filename; InitializeComponent(); } public string SourceCode { get { - return sourceCode.Text; + return sourceCodeBox.Text; } set { - sourceCode.Text = value; + sourceCodeBox.Text = value; } } + + public void Decompile() + { + ControlFlow.Node.NextNodeID = 0; + Options.CollapseExpression = (int)collapseCount.Value; + Options.ReduceGraph = (int)reduceCount.Value; + + AssemblyDefinition assembly = AssemblyFactory.GetAssembly(filename); + AstBuilder codeDomBuilder = new AstBuilder(); + codeDomBuilder.AddAssembly(assembly); + SourceCode = codeDomBuilder.GenerateCode(); + } + + void CollapseBtnClick(object sender, EventArgs e) + { + collapseCount.Value++; + Decompile(); + } + + void ReduceBtnClick(object sender, EventArgs e) + { + reduceCount.Value++; + Decompile(); + } + + void DecompileBtnClick(object sender, EventArgs e) + { + Decompile(); + } + + void CollapseCountValueChanged(object sender, EventArgs e) + { + Decompile(); + } + + void ReduceCountValueChanged(object sender, EventArgs e) + { + Decompile(); + } } } diff --git a/src/Options.cs b/src/Options.cs new file mode 100644 index 000000000..fd56768f7 --- /dev/null +++ b/src/Options.cs @@ -0,0 +1,10 @@ +using System; + +namespace Decompiler +{ + public static class Options + { + public static int CollapseExpression = 0; + public static int ReduceGraph = 0; + } +} diff --git a/src/Program.cs b/src/Program.cs index 1af494614..daa064739 100644 --- a/src/Program.cs +++ b/src/Program.cs @@ -21,21 +21,13 @@ namespace Decompiler [STAThread] private static void Main(string[] args) { - string sourceCode = Decompile(@"..\..\tests\QuickSort\bin\Release\QuickSort.exe"); + string sourceFilename = @"..\..\tests\QuickSort\bin\Release\QuickSort.exe"; Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); - MainForm mainForm = new MainForm(); - mainForm.SourceCode = sourceCode; + MainForm mainForm = new MainForm(sourceFilename); + mainForm.Decompile(); Application.Run(mainForm); } - - static string Decompile(string filename) - { - AssemblyDefinition assembly = AssemblyFactory.GetAssembly(filename); - AstBuilder codeDomBuilder = new AstBuilder(); - codeDomBuilder.AddAssembly(assembly); - return codeDomBuilder.GenerateCode(); - } } } diff --git a/src/StackExpression.cs b/src/StackExpression.cs index bbecfeaf8..2e11a4d86 100644 --- a/src/StackExpression.cs +++ b/src/StackExpression.cs @@ -63,7 +63,7 @@ namespace Decompiler get { List branchesHere = new List(); foreach(ByteCode byteCode in this.FirstByteCode.BranchesHere) { - branchesHere.Add(byteCode.Owner); + branchesHere.Add(byteCode.Expression); } return branchesHere; } @@ -74,7 +74,7 @@ namespace Decompiler if (this.lastByteCode.BranchTarget == null) { return null; } else { - return this.lastByteCode.BranchTarget.Owner; + return this.lastByteCode.BranchTarget.Expression; } } } @@ -135,7 +135,7 @@ namespace Decompiler { this.owner = owner; this.lastByteCode = lastByteCode; - this.lastByteCode.Owner = this; + this.lastByteCode.Expression = this; } public bool MustBeParenthesized { diff --git a/src/StackExpressionCollection.cs b/src/StackExpressionCollection.cs index 434c12bb5..829f0835f 100644 --- a/src/StackExpressionCollection.cs +++ b/src/StackExpressionCollection.cs @@ -27,6 +27,7 @@ namespace Decompiler !expr.IsBranchTarget && prevExpr.IsClosed) { + if (Options.CollapseExpression-- <= 0) return; this.RemoveAt(i - 1); i--; expr.LastArguments.Insert(0, prevExpr); i--;