Browse Source

Added very simple disassembler.

pull/1/head
Daniel Grunwald 14 years ago
parent
commit
f2a70aac5a
  1. 261
      ILSpy/Disassembler/CecilExtensions.cs
  2. 43
      ILSpy/Disassembler/ILLanguage.cs
  3. 5
      ILSpy/ExtensionMethods.cs
  4. 3
      ILSpy/ILSpy.csproj
  5. 7
      ILSpy/Language.cs
  6. 3
      ILSpy/MainWindow.xaml
  7. 10
      ILSpy/MainWindow.xaml.cs

261
ILSpy/Disassembler/CecilExtensions.cs

@ -0,0 +1,261 @@ @@ -0,0 +1,261 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under MIT X11 license (for details please see \doc\license.txt)
using System;
using Mono.Cecil;
using Mono.Cecil.Cil;
namespace ICSharpCode.ILSpy.Disassembler
{
static class CecilExtensions
{
#region Debug output(ToString helpers)
public static string OffsetToString(int offset)
{
return string.Format("IL_{0:x4}", offset);
}
public static void WriteTo(this ExceptionHandler exceptionHandler, ITextOutput writer)
{
writer.Write("Try IL_{0:x4}-IL_{1:x4} ", exceptionHandler.TryStart.Offset, exceptionHandler.TryEnd.Offset);
writer.Write(exceptionHandler.HandlerType.ToString());
if (exceptionHandler.FilterStart != null) {
writer.Write(" IL_{0:x4}-IL_{1:x4} handler ", exceptionHandler.FilterStart.Offset, exceptionHandler.FilterEnd.Offset);
}
writer.Write(" IL_{0:x4}-IL_{1:x4} ", exceptionHandler.HandlerStart.Offset, exceptionHandler.HandlerEnd.Offset);
}
public static void WriteTo(this Instruction instruction, ITextOutput writer)
{
writer.Write(OffsetToString(instruction.Offset));
writer.Write(": ");
writer.Write(instruction.OpCode.Name);
if(null != instruction.Operand) {
writer.Write(' ');
WriteOperand(writer, instruction.Operand);
}
}
public static void WriteOperand(ITextOutput writer, object operand)
{
if(null == operand) throw new ArgumentNullException("operand");
Instruction targetInstruction = operand as Instruction;
if(null != targetInstruction) {
writer.Write(OffsetToString(targetInstruction.Offset));
return;
}
Instruction [] targetInstructions = operand as Instruction [];
if(null != targetInstructions) {
WriteLabelList(writer, targetInstructions);
return;
}
VariableReference variableRef = operand as VariableReference;
if(null != variableRef) {
writer.Write(variableRef.Index.ToString());
return;
}
MethodReference methodRef = operand as MethodReference;
if(null != methodRef) {
WriteMethodReference(writer, methodRef);
return;
}
string s = operand as string;
if(null != s) {
writer.Write("\"" + s + "\"");
return;
}
s = ToInvariantCultureString(operand);
writer.Write(s);
}
static void WriteLabelList(ITextOutput writer, Instruction[] instructions)
{
writer.Write("(");
for(int i = 0; i < instructions.Length; i++) {
if(i != 0) writer.Write(", ");
writer.Write(OffsetToString(instructions [i].Offset));
}
writer.Write(")");
}
static string ToInvariantCultureString(object value)
{
IConvertible convertible = value as IConvertible;
return(null != convertible)
? convertible.ToString(System.Globalization.CultureInfo.InvariantCulture)
: value.ToString();
}
static void WriteMethodReference(ITextOutput writer, MethodReference method)
{
writer.Write(FormatTypeReference(method.ReturnType));
writer.Write(' ');
writer.Write(FormatTypeReference(method.DeclaringType));
writer.Write("::");
writer.Write(method.Name);
writer.Write("(");
var parameters = method.Parameters;
for(int i=0; i < parameters.Count; ++i) {
if(i > 0) writer.Write(", ");
writer.Write(FormatTypeReference(parameters [i].ParameterType));
}
writer.Write(")");
}
static string FormatTypeReference(TypeReference type)
{
string typeName = type.FullName;
switch(typeName) {
case "System.Void": return "void";
case "System.String": return "string";
case "System.Int32": return "int32";
case "System.Long": return "int64";
case "System.Boolean": return "bool";
case "System.Single": return "float32";
case "System.Double": return "float64";
}
return typeName;
}
#endregion
#region GetPushDelta / GetPopDelta
public static int GetPushDelta(this Instruction instruction)
{
OpCode code = instruction.OpCode;
switch (code.StackBehaviourPush) {
case StackBehaviour.Push0:
return 0;
case StackBehaviour.Push1:
case StackBehaviour.Pushi:
case StackBehaviour.Pushi8:
case StackBehaviour.Pushr4:
case StackBehaviour.Pushr8:
case StackBehaviour.Pushref:
return 1;
case StackBehaviour.Push1_push1:
return 2;
case StackBehaviour.Varpush:
if (code.FlowControl != FlowControl.Call)
break;
IMethodSignature method = (IMethodSignature) instruction.Operand;
return IsVoid (method.ReturnType) ? 0 : 1;
}
throw new NotSupportedException ();
}
public static int GetPopDelta(this Instruction instruction, MethodDefinition current, int currentStackSize)
{
OpCode code = instruction.OpCode;
switch (code.StackBehaviourPop) {
case StackBehaviour.Pop0:
return 0;
case StackBehaviour.Popi:
case StackBehaviour.Popref:
case StackBehaviour.Pop1:
return 1;
case StackBehaviour.Pop1_pop1:
case StackBehaviour.Popi_pop1:
case StackBehaviour.Popi_popi:
case StackBehaviour.Popi_popi8:
case StackBehaviour.Popi_popr4:
case StackBehaviour.Popi_popr8:
case StackBehaviour.Popref_pop1:
case StackBehaviour.Popref_popi:
return 2;
case StackBehaviour.Popi_popi_popi:
case StackBehaviour.Popref_popi_popi:
case StackBehaviour.Popref_popi_popi8:
case StackBehaviour.Popref_popi_popr4:
case StackBehaviour.Popref_popi_popr8:
case StackBehaviour.Popref_popi_popref:
return 3;
case StackBehaviour.PopAll:
return currentStackSize;
case StackBehaviour.Varpop:
if (code == OpCodes.Ret)
return IsVoid (current.ReturnType) ? 0 : 1;
if (code.FlowControl != FlowControl.Call)
break;
IMethodSignature method = (IMethodSignature) instruction.Operand;
int count = method.HasParameters ? method.Parameters.Count : 0;
if (method.HasThis && code != OpCodes.Newobj)
++count;
return count;
}
throw new NotSupportedException ();
}
public static bool IsVoid(this TypeReference type)
{
return type.FullName == "System.Void" && !(type is TypeSpecification);
}
public static bool IsValueTypeOrVoid(this TypeReference type)
{
while (type is OptionalModifierType || type is RequiredModifierType)
type = ((TypeSpecification)type).ElementType;
if (type is ArrayType)
return false;
return type.IsValueType || type.IsVoid();
}
#endregion
public static string ShortTypeName(this TypeReference type)
{
switch (type.FullName) {
case "System.Int16":
return "short";
case "System.Int32":
return "int";
case "System.Int64":
return "long";
case "System.UInt16":
return "ushort";
case "System.UInt32":
return "uint";
case "System.UInt64":
return "ulong";
case "System.Single":
return "float";
case "System.Double":
return "double";
case "System.Void":
return "void";
case "System.Boolean":
return "bool";
case "System.String":
return "string";
case "System.Char":
return "char";
case "System.Object":
return "object";
default:
string name = type.Name;
int pos = name.LastIndexOf('`');
if (pos >= 0)
return name.Substring(0, pos);
else
return name;
}
}
}
}

43
ILSpy/Disassembler/ILLanguage.cs

@ -0,0 +1,43 @@ @@ -0,0 +1,43 @@
// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using Mono.Cecil;
namespace ICSharpCode.ILSpy.Disassembler
{
public class ILLanguage : Language
{
public override string Name {
get { return "IL"; }
}
public override void Decompile(MethodDefinition method, ITextOutput output)
{
foreach (var inst in method.Body.Instructions) {
inst.WriteTo(output);
output.WriteLine();
}
output.WriteLine();
foreach (var eh in method.Body.ExceptionHandlers) {
eh.WriteTo(output);
output.WriteLine();
}
}
}
}

5
ILSpy/ExtensionMethods.cs

@ -34,6 +34,11 @@ namespace ICSharpCode.ILSpy @@ -34,6 +34,11 @@ namespace ICSharpCode.ILSpy
list.Add(item);
}
public static void Write(this ITextOutput output, string format, params object[] args)
{
output.Write(string.Format(format, args));
}
/// <summary>
/// Sets the value of a dependency property on <paramref name="targetObject"/> using a markup extension.
/// </summary>

3
ILSpy/ILSpy.csproj

@ -75,6 +75,8 @@ @@ -75,6 +75,8 @@
<Compile Include="BaseTypesTreeNode.cs" />
<Compile Include="CueBannerService.cs" />
<Compile Include="Decompiler\CSharpLanguage.cs" />
<Compile Include="Disassembler\CecilExtensions.cs" />
<Compile Include="Disassembler\ILLanguage.cs" />
<Compile Include="EventTreeNode.cs" />
<Compile Include="ExtensionMethods.cs" />
<Compile Include="FieldTreeNode.cs" />
@ -143,6 +145,7 @@ @@ -143,6 +145,7 @@
<Folder Include="Images" />
<Folder Include="Mono.Cecil.Rocks" />
<Folder Include="Decompiler" />
<Folder Include="Disassembler" />
<Folder Include="themes" />
</ItemGroup>
<ItemGroup>

7
ILSpy/Language.cs

@ -26,7 +26,7 @@ namespace ICSharpCode.ILSpy @@ -26,7 +26,7 @@ namespace ICSharpCode.ILSpy
/// </summary>
public abstract class Language
{
public static readonly Language Current = new Decompiler.CSharpLanguage();
public static Language Current = new Decompiler.CSharpLanguage();
public abstract string Name { get; }
@ -58,5 +58,10 @@ namespace ICSharpCode.ILSpy @@ -58,5 +58,10 @@ namespace ICSharpCode.ILSpy
{
return t.Name;
}
public override string ToString()
{
return Name;
}
}
}

3
ILSpy/MainWindow.xaml

@ -67,6 +67,8 @@ @@ -67,6 +67,8 @@
Height="16"
Source="Images/Open.png" />
</Button>
<Separator />
<ComboBox Name="languageComboBox" DisplayMemberPath="Name" Width="50" SelectionChanged="LanguageComboBox_SelectionChanged" />
</ToolBar>
<!-- Main grid separating left pane (treeView) from main pane (textEditor) -->
<Grid>
@ -90,6 +92,7 @@ @@ -90,6 +92,7 @@
<!-- Tree View of assemblies and classes -->
<tv:SharpTreeView
Name="treeView"
SelectionChanged="TreeView_SelectionChanged"
ShowRoot="False"
AllowDropOrder="True"
AllowDrop="True" />

10
ILSpy/MainWindow.xaml.cs

@ -57,6 +57,10 @@ namespace ICSharpCode.ILSpy @@ -57,6 +57,10 @@ namespace ICSharpCode.ILSpy
this.DataContext = filterSettings;
InitializeComponent();
languageComboBox.Items.Add(new Decompiler.CSharpLanguage());
languageComboBox.Items.Add(new Disassembler.ILLanguage());
languageComboBox.SelectedItem = languageComboBox.Items[0];
textEditor.Text = "Welcome to ILSpy!";
AssemblyListTreeNode assemblyListTreeNode = new AssemblyListTreeNode(assemblyList);
assemblyListTreeNode.FilterSettings = filterSettings.Clone();
@ -147,5 +151,11 @@ namespace ICSharpCode.ILSpy @@ -147,5 +151,11 @@ namespace ICSharpCode.ILSpy
textEditor.Text = ex.ToString();
}
}
void LanguageComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
ILSpy.Language.Current = (ILSpy.Language)languageComboBox.SelectedItem;
TreeView_SelectionChanged(null, null);
}
}
}
Loading…
Cancel
Save