mirror of https://github.com/icsharpcode/ILSpy.git
5 changed files with 476 additions and 123 deletions
@ -0,0 +1,169 @@
@@ -0,0 +1,169 @@
|
||||
// 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:
|
||||
// 4
|
||||
// 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 System.Linq; |
||||
using System.Threading; |
||||
|
||||
using ICSharpCode.Decompiler.FlowAnalysis; |
||||
using Mono.Cecil; |
||||
using Mono.Cecil.Cil; |
||||
|
||||
namespace ICSharpCode.ILSpy.Disassembler |
||||
{ |
||||
/// <summary>
|
||||
/// Disassembles a method body.
|
||||
/// </summary>
|
||||
public class MethodBodyDisassembler |
||||
{ |
||||
readonly ITextOutput output; |
||||
readonly bool detectControlStructure; |
||||
readonly CancellationToken cancellationToken; |
||||
|
||||
public MethodBodyDisassembler(ITextOutput output, bool detectControlStructure, CancellationToken cancellationToken) |
||||
{ |
||||
if (output == null) |
||||
throw new ArgumentNullException("output"); |
||||
this.output = output; |
||||
this.detectControlStructure = detectControlStructure; |
||||
this.cancellationToken = cancellationToken; |
||||
} |
||||
|
||||
public void Disassemble(MethodBody body) |
||||
{ |
||||
MethodDefinition method = body.Method; |
||||
output.WriteCommentLine("// Method begins at RVA 0x{0:x4}", method.RVA); |
||||
output.WriteCommentLine("// Code size {0} (0x{0:x})", body.CodeSize); |
||||
output.WriteLine(".maxstack {0}", body.MaxStackSize); |
||||
if (method.DeclaringType.Module.Assembly.EntryPoint == method) |
||||
output.WriteLine (".entrypoint"); |
||||
|
||||
if (method.Body.HasVariables) { |
||||
output.Write(".locals "); |
||||
if (method.Body.InitLocals) |
||||
output.Write("init "); |
||||
output.WriteLine("("); |
||||
output.Indent(); |
||||
foreach (var v in method.Body.Variables) { |
||||
output.WriteDefinition("[" + v.Index + "] ", v); |
||||
v.VariableType.WriteTo(output); |
||||
output.Write(' '); |
||||
output.Write(DisassemblerHelpers.Escape(v.Name)); |
||||
output.WriteLine(); |
||||
} |
||||
output.Unindent(); |
||||
output.WriteLine(")"); |
||||
} |
||||
output.WriteLine(); |
||||
|
||||
if (detectControlStructure) { |
||||
var cfg = ControlFlowGraphBuilder.Build(method.Body); |
||||
cfg.ComputeDominance(cancellationToken); |
||||
cfg.ComputeDominanceFrontier(); |
||||
var s = ControlStructureDetector.DetectStructure(cfg, method.Body.ExceptionHandlers, cancellationToken); |
||||
WriteStructure(s); |
||||
} else { |
||||
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(); |
||||
} |
||||
} |
||||
} |
||||
|
||||
void WriteStructure(ControlStructure s) |
||||
{ |
||||
if (s.Type != ControlStructureType.Root) { |
||||
switch (s.Type) { |
||||
case ControlStructureType.Loop: |
||||
output.Write("// loop start"); |
||||
if (s.EntryPoint.Start != null) { |
||||
output.Write(" (head: "); |
||||
DisassemblerHelpers.WriteOffsetReference(output, s.EntryPoint.Start); |
||||
output.Write(')'); |
||||
} |
||||
output.WriteLine(); |
||||
break; |
||||
case ControlStructureType.Try: |
||||
output.WriteLine(".try {"); |
||||
break; |
||||
case ControlStructureType.Handler: |
||||
switch (s.ExceptionHandler.HandlerType) { |
||||
case Mono.Cecil.Cil.ExceptionHandlerType.Catch: |
||||
case Mono.Cecil.Cil.ExceptionHandlerType.Filter: |
||||
output.Write("catch"); |
||||
if (s.ExceptionHandler.CatchType != null) { |
||||
output.Write(' '); |
||||
s.ExceptionHandler.CatchType.WriteTo(output); |
||||
} |
||||
output.WriteLine(" {"); |
||||
break; |
||||
case Mono.Cecil.Cil.ExceptionHandlerType.Finally: |
||||
output.WriteLine("finally {"); |
||||
break; |
||||
case Mono.Cecil.Cil.ExceptionHandlerType.Fault: |
||||
output.WriteLine("fault {"); |
||||
break; |
||||
default: |
||||
throw new NotSupportedException(); |
||||
} |
||||
break; |
||||
case ControlStructureType.Filter: |
||||
output.WriteLine("filter {"); |
||||
break; |
||||
default: |
||||
throw new NotSupportedException(); |
||||
} |
||||
output.Indent(); |
||||
} |
||||
foreach (var node in s.Nodes.Concat(s.Children.Select(c => c.EntryPoint)).OrderBy(n => n.BlockIndex)) { |
||||
if (s.Nodes.Contains(node)) { |
||||
foreach (var inst in node.Instructions) { |
||||
inst.WriteTo(output); |
||||
output.WriteLine(); |
||||
} |
||||
} else { |
||||
WriteStructure(s.Children.Single(c => c.EntryPoint == node)); |
||||
} |
||||
} |
||||
if (s.Type != ControlStructureType.Root) { |
||||
output.Unindent(); |
||||
switch (s.Type) { |
||||
case ControlStructureType.Loop: |
||||
output.WriteCommentLine("// end loop"); |
||||
break; |
||||
case ControlStructureType.Try: |
||||
output.WriteLine("} // end .try"); |
||||
break; |
||||
case ControlStructureType.Handler: |
||||
output.WriteLine("} // end handler"); |
||||
break; |
||||
case ControlStructureType.Filter: |
||||
output.WriteLine("} // end filter"); |
||||
break; |
||||
default: |
||||
throw new NotSupportedException(); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,240 @@
@@ -0,0 +1,240 @@
|
||||
// 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 System.Collections.Generic; |
||||
using System.Threading; |
||||
|
||||
using Mono.Cecil; |
||||
using Mono.Collections.Generic; |
||||
|
||||
namespace ICSharpCode.ILSpy.Disassembler |
||||
{ |
||||
/// <summary>
|
||||
/// Disassembles type and member definitions.
|
||||
/// </summary>
|
||||
public class ReflectionDisassembler |
||||
{ |
||||
ITextOutput output; |
||||
CancellationToken cancellationToken; |
||||
MethodBodyDisassembler methodBodyDisassembler; |
||||
|
||||
public ReflectionDisassembler(ITextOutput output, bool detectControlStructure, CancellationToken cancellationToken) |
||||
{ |
||||
if (output == null) |
||||
throw new ArgumentNullException("output"); |
||||
this.output = output; |
||||
this.cancellationToken = cancellationToken; |
||||
this.methodBodyDisassembler = new MethodBodyDisassembler(output, detectControlStructure, cancellationToken); |
||||
} |
||||
|
||||
EnumNameCollection<MethodAttributes> methodAttributeFlags = new EnumNameCollection<MethodAttributes>() { |
||||
{ MethodAttributes.Static, "static" }, |
||||
{ MethodAttributes.Final, "final" }, |
||||
{ MethodAttributes.Virtual, "virtual" }, |
||||
{ MethodAttributes.HideBySig, "hidebysig" }, |
||||
{ MethodAttributes.Abstract, "abstract" }, |
||||
{ MethodAttributes.SpecialName, "specialname" }, |
||||
{ MethodAttributes.PInvokeImpl, "pinvokeimpl" }, |
||||
{ MethodAttributes.UnmanagedExport, "export" }, |
||||
{ MethodAttributes.RTSpecialName, "rtspecialname" }, |
||||
{ MethodAttributes.RequireSecObject, "requiresecobj" }, |
||||
{ MethodAttributes.NewSlot, "newslot" } |
||||
}; |
||||
|
||||
EnumNameCollection<MethodAttributes> methodVisibility = new EnumNameCollection<MethodAttributes>() { |
||||
{ MethodAttributes.Private, "private" }, |
||||
{ MethodAttributes.FamANDAssem, "famandassem" }, |
||||
{ MethodAttributes.Assembly, "assembly" }, |
||||
{ MethodAttributes.Family, "family" }, |
||||
{ MethodAttributes.FamORAssem, "famorassem" }, |
||||
{ MethodAttributes.Public, "public" }, |
||||
}; |
||||
|
||||
EnumNameCollection<MethodCallingConvention> callingConvention = new EnumNameCollection<MethodCallingConvention>() { |
||||
{ MethodCallingConvention.C, "unmanaged cdecl" }, |
||||
{ MethodCallingConvention.StdCall, "unmanaged stdcall" }, |
||||
{ MethodCallingConvention.ThisCall, "unmanaged thiscall" }, |
||||
{ MethodCallingConvention.FastCall, "unmanaged fastcall" }, |
||||
{ MethodCallingConvention.VarArg, "vararg" }, |
||||
{ MethodCallingConvention.Generic, "generic" }, |
||||
}; |
||||
|
||||
EnumNameCollection<MethodImplAttributes> methodCodeType = new EnumNameCollection<MethodImplAttributes>() { |
||||
{ MethodImplAttributes.IL, "cil" }, |
||||
{ MethodImplAttributes.Native, "native" }, |
||||
{ MethodImplAttributes.OPTIL, "optil" }, |
||||
{ MethodImplAttributes.Runtime, "runtime" }, |
||||
}; |
||||
|
||||
EnumNameCollection<MethodImplAttributes> methodImpl = new EnumNameCollection<MethodImplAttributes>() { |
||||
{ MethodImplAttributes.Synchronized, "synchronized" }, |
||||
}; |
||||
|
||||
public void DisassembleMethod(MethodDefinition method) |
||||
{ |
||||
// .method public hidebysig specialname
|
||||
// instance default class [mscorlib]System.IO.TextWriter get_BaseWriter () cil managed
|
||||
//
|
||||
|
||||
// write method header
|
||||
output.WriteDefinition(".method ", method); |
||||
|
||||
//emit flags
|
||||
WriteEnum(method.Attributes & MethodAttributes.MemberAccessMask, methodVisibility); |
||||
WriteFlags(method.Attributes & ~MethodAttributes.MemberAccessMask, methodAttributeFlags); |
||||
|
||||
output.WriteLine(); |
||||
output.Indent(); |
||||
|
||||
if (method.HasThis) |
||||
output.Write("instance "); |
||||
|
||||
//call convention
|
||||
WriteEnum(method.CallingConvention & (MethodCallingConvention)0x1f, callingConvention); |
||||
|
||||
|
||||
//return type
|
||||
method.ReturnType.WriteTo(output, false, true); |
||||
output.Write(' '); |
||||
output.Write(DisassemblerHelpers.Escape(method.Name)); |
||||
|
||||
//( params )
|
||||
output.Write(" ("); |
||||
if (method.HasParameters) { |
||||
output.WriteLine(); |
||||
output.Indent(); |
||||
WriteParameters(method.Parameters); |
||||
output.Unindent(); |
||||
} |
||||
output.Write(") "); |
||||
//cil managed
|
||||
WriteEnum(method.ImplAttributes & MethodImplAttributes.CodeTypeMask, methodCodeType); |
||||
if ((method.ImplAttributes & MethodImplAttributes.ManagedMask) == MethodImplAttributes.Managed) |
||||
output.Write("managed "); |
||||
else |
||||
output.Write("unmanaged "); |
||||
WriteFlags(method.ImplAttributes & ~(MethodImplAttributes.CodeTypeMask | MethodImplAttributes.ManagedMask), methodImpl); |
||||
|
||||
output.WriteLine(); |
||||
output.Unindent(); |
||||
OpenBlock(); |
||||
WriteAttributes(method.CustomAttributes); |
||||
|
||||
if (method.HasBody) |
||||
methodBodyDisassembler.Disassemble(method.Body); |
||||
|
||||
CloseBlock(); |
||||
} |
||||
|
||||
void WriteParameters(Collection<ParameterDefinition> parameters) |
||||
{ |
||||
for (int i = 0; i < parameters.Count; i++) { |
||||
var p = parameters[i]; |
||||
p.ParameterType.WriteTo(output); |
||||
output.Write(' '); |
||||
output.WriteDefinition(DisassemblerHelpers.Escape(p.Name), p); |
||||
if (i < parameters.Count - 1) |
||||
output.Write(','); |
||||
output.WriteLine(); |
||||
} |
||||
} |
||||
|
||||
void WriteAttributes(Collection<CustomAttribute> attributes) |
||||
{ |
||||
foreach (CustomAttribute a in attributes) { |
||||
output.Write(".custom"); |
||||
a.Constructor.WriteTo(output); |
||||
byte[] blob = a.GetBlob(); |
||||
if (blob != null) { |
||||
output.Write(" = "); |
||||
WriteBlob(blob); |
||||
} |
||||
output.WriteLine(); |
||||
} |
||||
} |
||||
|
||||
void WriteBlob(byte[] blob) |
||||
{ |
||||
output.Write("("); |
||||
output.Indent(); |
||||
|
||||
for (int i = 0; i < blob.Length; i++) { |
||||
if (i % 16 == 0 && i < blob.Length - 1) { |
||||
output.WriteLine(); |
||||
} else { |
||||
output.Write(' '); |
||||
} |
||||
output.Write(blob[i].ToString("x2")); |
||||
} |
||||
|
||||
output.WriteLine(); |
||||
output.Unindent(); |
||||
output.Write(")"); |
||||
} |
||||
|
||||
void OpenBlock() |
||||
{ |
||||
output.WriteLine("{"); |
||||
output.Indent(); |
||||
} |
||||
|
||||
void CloseBlock() |
||||
{ |
||||
output.Unindent(); |
||||
output.WriteLine("}"); |
||||
} |
||||
|
||||
void WriteFlags<T>(T flags, EnumNameCollection<T> flagNames) where T : struct |
||||
{ |
||||
long val = Convert.ToInt64(flags); |
||||
long tested = 0; |
||||
foreach (var pair in flagNames) { |
||||
tested |= pair.Key; |
||||
if ((val & pair.Key) != 0) { |
||||
output.Write(pair.Value); |
||||
output.Write(' '); |
||||
} |
||||
} |
||||
if ((val & ~tested) != 0) |
||||
output.Write("flag({0}) ", val & ~tested); |
||||
} |
||||
|
||||
void WriteEnum<T>(T enumValue, EnumNameCollection<T> enumNames) where T : struct |
||||
{ |
||||
long val = Convert.ToInt64(enumValue); |
||||
foreach (var pair in enumNames) { |
||||
if (pair.Key == val) { |
||||
output.Write(pair.Value); |
||||
output.Write(' '); |
||||
return; |
||||
} |
||||
} |
||||
if (val != 0) { |
||||
output.Write("flag({0})", val); |
||||
output.Write(' '); |
||||
} |
||||
|
||||
} |
||||
|
||||
sealed class EnumNameCollection<T> : IEnumerable<KeyValuePair<long, string>> where T : struct |
||||
{ |
||||
List<KeyValuePair<long, string>> names = new List<KeyValuePair<long, string>>(); |
||||
|
||||
public void Add(T flag, string name) |
||||
{ |
||||
this.names.Add(new KeyValuePair<long, string>(Convert.ToInt64(flag), name)); |
||||
} |
||||
|
||||
public IEnumerator<KeyValuePair<long, string>> GetEnumerator() |
||||
{ |
||||
return names.GetEnumerator(); |
||||
} |
||||
|
||||
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() |
||||
{ |
||||
return names.GetEnumerator(); |
||||
} |
||||
} |
||||
} |
||||
} |
Loading…
Reference in new issue