|
|
|
@ -18,8 +18,10 @@ |
|
|
|
|
|
|
|
|
|
|
|
using System; |
|
|
|
using System; |
|
|
|
using System.Collections.Generic; |
|
|
|
using System.Collections.Generic; |
|
|
|
|
|
|
|
using System.Diagnostics; |
|
|
|
|
|
|
|
using System.Linq; |
|
|
|
|
|
|
|
using System.Text; |
|
|
|
using System.Threading; |
|
|
|
using System.Threading; |
|
|
|
|
|
|
|
|
|
|
|
using Mono.Cecil; |
|
|
|
using Mono.Cecil; |
|
|
|
using Mono.Collections.Generic; |
|
|
|
using Mono.Collections.Generic; |
|
|
|
|
|
|
|
|
|
|
|
@ -32,7 +34,6 @@ namespace ICSharpCode.Decompiler.Disassembler |
|
|
|
{ |
|
|
|
{ |
|
|
|
ITextOutput output; |
|
|
|
ITextOutput output; |
|
|
|
CancellationToken cancellationToken; |
|
|
|
CancellationToken cancellationToken; |
|
|
|
bool detectControlStructure; |
|
|
|
|
|
|
|
bool isInType; // whether we are currently disassembling a whole type (-> defaultCollapsed for foldings)
|
|
|
|
bool isInType; // whether we are currently disassembling a whole type (-> defaultCollapsed for foldings)
|
|
|
|
MethodBodyDisassembler methodBodyDisassembler; |
|
|
|
MethodBodyDisassembler methodBodyDisassembler; |
|
|
|
|
|
|
|
|
|
|
|
@ -42,23 +43,24 @@ namespace ICSharpCode.Decompiler.Disassembler |
|
|
|
throw new ArgumentNullException("output"); |
|
|
|
throw new ArgumentNullException("output"); |
|
|
|
this.output = output; |
|
|
|
this.output = output; |
|
|
|
this.cancellationToken = cancellationToken; |
|
|
|
this.cancellationToken = cancellationToken; |
|
|
|
this.detectControlStructure = detectControlStructure; |
|
|
|
|
|
|
|
this.methodBodyDisassembler = new MethodBodyDisassembler(output, detectControlStructure, cancellationToken); |
|
|
|
this.methodBodyDisassembler = new MethodBodyDisassembler(output, detectControlStructure, cancellationToken); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
#region Disassemble Method
|
|
|
|
#region Disassemble Method
|
|
|
|
EnumNameCollection<MethodAttributes> methodAttributeFlags = new EnumNameCollection<MethodAttributes>() { |
|
|
|
EnumNameCollection<MethodAttributes> methodAttributeFlags = new EnumNameCollection<MethodAttributes>() { |
|
|
|
{ MethodAttributes.Static, "static" }, |
|
|
|
|
|
|
|
{ MethodAttributes.Final, "final" }, |
|
|
|
{ MethodAttributes.Final, "final" }, |
|
|
|
{ MethodAttributes.Virtual, "virtual" }, |
|
|
|
|
|
|
|
{ MethodAttributes.HideBySig, "hidebysig" }, |
|
|
|
{ MethodAttributes.HideBySig, "hidebysig" }, |
|
|
|
{ MethodAttributes.Abstract, "abstract" }, |
|
|
|
|
|
|
|
{ MethodAttributes.SpecialName, "specialname" }, |
|
|
|
{ MethodAttributes.SpecialName, "specialname" }, |
|
|
|
{ MethodAttributes.PInvokeImpl, "pinvokeimpl" }, |
|
|
|
{ MethodAttributes.PInvokeImpl, null }, // handled separately
|
|
|
|
{ MethodAttributes.UnmanagedExport, "export" }, |
|
|
|
{ MethodAttributes.UnmanagedExport, "export" }, |
|
|
|
{ MethodAttributes.RTSpecialName, "rtspecialname" }, |
|
|
|
{ MethodAttributes.RTSpecialName, "rtspecialname" }, |
|
|
|
{ MethodAttributes.RequireSecObject, "requiresecobj" }, |
|
|
|
{ MethodAttributes.RequireSecObject, "reqsecobj" }, |
|
|
|
{ MethodAttributes.NewSlot, "newslot" } |
|
|
|
{ MethodAttributes.NewSlot, "newslot" }, |
|
|
|
|
|
|
|
{ MethodAttributes.CheckAccessOnOverride, "strict" }, |
|
|
|
|
|
|
|
{ MethodAttributes.Abstract, "abstract" }, |
|
|
|
|
|
|
|
{ MethodAttributes.Virtual, "virtual" }, |
|
|
|
|
|
|
|
{ MethodAttributes.Static, "static" }, |
|
|
|
|
|
|
|
{ MethodAttributes.HasSecurity, null }, // ?? also invisible in ILDasm
|
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
EnumNameCollection<MethodAttributes> methodVisibility = new EnumNameCollection<MethodAttributes>() { |
|
|
|
EnumNameCollection<MethodAttributes> methodVisibility = new EnumNameCollection<MethodAttributes>() { |
|
|
|
@ -76,7 +78,7 @@ namespace ICSharpCode.Decompiler.Disassembler |
|
|
|
{ MethodCallingConvention.ThisCall, "unmanaged thiscall" }, |
|
|
|
{ MethodCallingConvention.ThisCall, "unmanaged thiscall" }, |
|
|
|
{ MethodCallingConvention.FastCall, "unmanaged fastcall" }, |
|
|
|
{ MethodCallingConvention.FastCall, "unmanaged fastcall" }, |
|
|
|
{ MethodCallingConvention.VarArg, "vararg" }, |
|
|
|
{ MethodCallingConvention.VarArg, "vararg" }, |
|
|
|
{ MethodCallingConvention.Generic, "generic" }, |
|
|
|
{ MethodCallingConvention.Generic, null }, |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
EnumNameCollection<MethodImplAttributes> methodCodeType = new EnumNameCollection<MethodImplAttributes>() { |
|
|
|
EnumNameCollection<MethodImplAttributes> methodCodeType = new EnumNameCollection<MethodImplAttributes>() { |
|
|
|
@ -90,6 +92,9 @@ namespace ICSharpCode.Decompiler.Disassembler |
|
|
|
{ MethodImplAttributes.Synchronized, "synchronized" }, |
|
|
|
{ MethodImplAttributes.Synchronized, "synchronized" }, |
|
|
|
{ MethodImplAttributes.NoInlining, "noinlining" }, |
|
|
|
{ MethodImplAttributes.NoInlining, "noinlining" }, |
|
|
|
{ MethodImplAttributes.NoOptimization, "nooptimization" }, |
|
|
|
{ MethodImplAttributes.NoOptimization, "nooptimization" }, |
|
|
|
|
|
|
|
{ MethodImplAttributes.PreserveSig, "preservesig" }, |
|
|
|
|
|
|
|
{ MethodImplAttributes.InternalCall, "internalcall" }, |
|
|
|
|
|
|
|
{ MethodImplAttributes.ForwardRef, "forwardref" }, |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
public void DisassembleMethod(MethodDefinition method) |
|
|
|
public void DisassembleMethod(MethodDefinition method) |
|
|
|
@ -108,12 +113,53 @@ namespace ICSharpCode.Decompiler.Disassembler |
|
|
|
//emit flags
|
|
|
|
//emit flags
|
|
|
|
WriteEnum(method.Attributes & MethodAttributes.MemberAccessMask, methodVisibility); |
|
|
|
WriteEnum(method.Attributes & MethodAttributes.MemberAccessMask, methodVisibility); |
|
|
|
WriteFlags(method.Attributes & ~MethodAttributes.MemberAccessMask, methodAttributeFlags); |
|
|
|
WriteFlags(method.Attributes & ~MethodAttributes.MemberAccessMask, methodAttributeFlags); |
|
|
|
|
|
|
|
if(method.IsCompilerControlled) output.Write("privatescope "); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if ((method.Attributes & MethodAttributes.PInvokeImpl) == MethodAttributes.PInvokeImpl) { |
|
|
|
|
|
|
|
output.Write("pinvokeimpl"); |
|
|
|
|
|
|
|
if (method.HasPInvokeInfo) { |
|
|
|
|
|
|
|
PInvokeInfo info = method.PInvokeInfo; |
|
|
|
|
|
|
|
output.Write("(\"" + NRefactory.CSharp.OutputVisitor.ConvertString(info.Module.Name) + "\""); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!string.IsNullOrEmpty(info.EntryPoint) && info.EntryPoint != method.Name) |
|
|
|
|
|
|
|
output.Write(" as \"" + NRefactory.CSharp.OutputVisitor.ConvertString(info.EntryPoint) + "\""); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (info.IsNoMangle) |
|
|
|
|
|
|
|
output.Write(" nomangle"); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (info.IsCharSetAnsi) |
|
|
|
|
|
|
|
output.Write(" ansi"); |
|
|
|
|
|
|
|
else if (info.IsCharSetAuto) |
|
|
|
|
|
|
|
output.Write(" autochar"); |
|
|
|
|
|
|
|
else if (info.IsCharSetUnicode) |
|
|
|
|
|
|
|
output.Write(" unicode"); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (info.SupportsLastError) |
|
|
|
|
|
|
|
output.Write(" lasterr"); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (info.IsCallConvCdecl) |
|
|
|
|
|
|
|
output.Write(" cdecl"); |
|
|
|
|
|
|
|
else if (info.IsCallConvFastcall) |
|
|
|
|
|
|
|
output.Write(" fastcall"); |
|
|
|
|
|
|
|
else if (info.IsCallConvStdCall) |
|
|
|
|
|
|
|
output.Write(" stdcall"); |
|
|
|
|
|
|
|
else if (info.IsCallConvThiscall) |
|
|
|
|
|
|
|
output.Write(" thiscall"); |
|
|
|
|
|
|
|
else if (info.IsCallConvWinapi) |
|
|
|
|
|
|
|
output.Write(" winapi"); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
output.Write(')'); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
output.Write(' '); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
output.WriteLine(); |
|
|
|
output.WriteLine(); |
|
|
|
output.Indent(); |
|
|
|
output.Indent(); |
|
|
|
|
|
|
|
if (method.ExplicitThis) { |
|
|
|
if (method.HasThis) |
|
|
|
output.Write("instance explicit "); |
|
|
|
|
|
|
|
} else if (method.HasThis) { |
|
|
|
output.Write("instance "); |
|
|
|
output.Write("instance "); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
//call convention
|
|
|
|
//call convention
|
|
|
|
WriteEnum(method.CallingConvention & (MethodCallingConvention)0x1f, callingConvention); |
|
|
|
WriteEnum(method.CallingConvention & (MethodCallingConvention)0x1f, callingConvention); |
|
|
|
@ -122,7 +168,16 @@ namespace ICSharpCode.Decompiler.Disassembler |
|
|
|
//return type
|
|
|
|
//return type
|
|
|
|
method.ReturnType.WriteTo(output); |
|
|
|
method.ReturnType.WriteTo(output); |
|
|
|
output.Write(' '); |
|
|
|
output.Write(' '); |
|
|
|
output.Write(DisassemblerHelpers.Escape(method.Name)); |
|
|
|
if (method.MethodReturnType.HasMarshalInfo) { |
|
|
|
|
|
|
|
WriteMarshalInfo(method.MethodReturnType.MarshalInfo); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (method.IsCompilerControlled) { |
|
|
|
|
|
|
|
output.Write(DisassemblerHelpers.Escape(method.Name + "$PST" + method.MetadataToken.ToInt32().ToString("X8"))); |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
output.Write(DisassemblerHelpers.Escape(method.Name)); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
WriteTypeParameters(output, method); |
|
|
|
WriteTypeParameters(output, method); |
|
|
|
|
|
|
|
|
|
|
|
//( params )
|
|
|
|
//( params )
|
|
|
|
@ -143,34 +198,454 @@ namespace ICSharpCode.Decompiler.Disassembler |
|
|
|
WriteFlags(method.ImplAttributes & ~(MethodImplAttributes.CodeTypeMask | MethodImplAttributes.ManagedMask), methodImpl); |
|
|
|
WriteFlags(method.ImplAttributes & ~(MethodImplAttributes.CodeTypeMask | MethodImplAttributes.ManagedMask), methodImpl); |
|
|
|
|
|
|
|
|
|
|
|
output.Unindent(); |
|
|
|
output.Unindent(); |
|
|
|
if (method.HasBody || method.HasCustomAttributes) { |
|
|
|
OpenBlock(defaultCollapsed: isInType); |
|
|
|
OpenBlock(defaultCollapsed: isInType); |
|
|
|
WriteAttributes(method.CustomAttributes); |
|
|
|
WriteAttributes(method.CustomAttributes); |
|
|
|
if (method.HasOverrides) { |
|
|
|
|
|
|
|
foreach (var methodOverride in method.Overrides) { |
|
|
|
if (method.HasBody) { |
|
|
|
output.Write(".override method "); |
|
|
|
// create IL code mappings - used in debugger
|
|
|
|
methodOverride.WriteTo(output); |
|
|
|
MemberMapping methodMapping = method.CreateCodeMapping(this.CodeMappings); |
|
|
|
output.WriteLine(); |
|
|
|
methodBodyDisassembler.Disassemble(method.Body, methodMapping); |
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
foreach (var p in method.Parameters) { |
|
|
|
|
|
|
|
WriteParameterAttributes(p); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
WriteSecurityDeclarations(method); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (method.HasBody) { |
|
|
|
|
|
|
|
// create IL code mappings - used in debugger
|
|
|
|
|
|
|
|
MemberMapping methodMapping = method.CreateCodeMapping(this.CodeMappings); |
|
|
|
|
|
|
|
methodBodyDisassembler.Disassemble(method.Body, methodMapping); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
CloseBlock("end of method " + DisassemblerHelpers.Escape(method.DeclaringType.Name) + "::" + DisassemblerHelpers.Escape(method.Name)); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#region Write Security Declarations
|
|
|
|
|
|
|
|
void WriteSecurityDeclarations(ISecurityDeclarationProvider secDeclProvider) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
if (!secDeclProvider.HasSecurityDeclarations) |
|
|
|
|
|
|
|
return; |
|
|
|
|
|
|
|
foreach (var secdecl in secDeclProvider.SecurityDeclarations) { |
|
|
|
|
|
|
|
output.Write(".permissionset "); |
|
|
|
|
|
|
|
switch (secdecl.Action) { |
|
|
|
|
|
|
|
case SecurityAction.Request: |
|
|
|
|
|
|
|
output.Write("request"); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case SecurityAction.Demand: |
|
|
|
|
|
|
|
output.Write("demand"); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case SecurityAction.Assert: |
|
|
|
|
|
|
|
output.Write("assert"); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case SecurityAction.Deny: |
|
|
|
|
|
|
|
output.Write("deny"); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case SecurityAction.PermitOnly: |
|
|
|
|
|
|
|
output.Write("permitonly"); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case SecurityAction.LinkDemand: |
|
|
|
|
|
|
|
output.Write("linkcheck"); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case SecurityAction.InheritDemand: |
|
|
|
|
|
|
|
output.Write("inheritcheck"); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case SecurityAction.RequestMinimum: |
|
|
|
|
|
|
|
output.Write("reqmin"); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case SecurityAction.RequestOptional: |
|
|
|
|
|
|
|
output.Write("reqopt"); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case SecurityAction.RequestRefuse: |
|
|
|
|
|
|
|
output.Write("reqrefuse"); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case SecurityAction.PreJitGrant: |
|
|
|
|
|
|
|
output.Write("prejitgrant"); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case SecurityAction.PreJitDeny: |
|
|
|
|
|
|
|
output.Write("prejitdeny"); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case SecurityAction.NonCasDemand: |
|
|
|
|
|
|
|
output.Write("noncasdemand"); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case SecurityAction.NonCasLinkDemand: |
|
|
|
|
|
|
|
output.Write("noncaslinkdemand"); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case SecurityAction.NonCasInheritance: |
|
|
|
|
|
|
|
output.Write("noncasinheritance"); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
default: |
|
|
|
|
|
|
|
output.Write(secdecl.Action.ToString()); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
output.WriteLine(" = {"); |
|
|
|
|
|
|
|
output.Indent(); |
|
|
|
|
|
|
|
for (int i = 0; i < secdecl.SecurityAttributes.Count; i++) { |
|
|
|
|
|
|
|
SecurityAttribute sa = secdecl.SecurityAttributes[i]; |
|
|
|
|
|
|
|
if (sa.AttributeType.Scope == sa.AttributeType.Module) { |
|
|
|
|
|
|
|
output.Write("class "); |
|
|
|
|
|
|
|
output.Write(DisassemblerHelpers.Escape(GetAssemblyQualifiedName(sa.AttributeType))); |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
sa.AttributeType.WriteTo(output, ILNameSyntax.TypeName); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
output.Write(" = {"); |
|
|
|
|
|
|
|
if (sa.HasFields || sa.HasProperties) { |
|
|
|
|
|
|
|
output.WriteLine(); |
|
|
|
|
|
|
|
output.Indent(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
foreach (CustomAttributeNamedArgument na in sa.Fields) { |
|
|
|
|
|
|
|
output.Write("field "); |
|
|
|
|
|
|
|
WriteSecurityDeclarationArgument(na); |
|
|
|
|
|
|
|
output.WriteLine(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
foreach (CustomAttributeNamedArgument na in sa.Properties) { |
|
|
|
|
|
|
|
output.Write("property "); |
|
|
|
|
|
|
|
WriteSecurityDeclarationArgument(na); |
|
|
|
|
|
|
|
output.WriteLine(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
output.Unindent(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
output.Write('}'); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (i + 1< secdecl.SecurityAttributes.Count) |
|
|
|
|
|
|
|
output.Write(','); |
|
|
|
|
|
|
|
output.WriteLine(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
output.Unindent(); |
|
|
|
|
|
|
|
output.WriteLine("}"); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void WriteSecurityDeclarationArgument(CustomAttributeNamedArgument na) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
TypeReference type = na.Argument.Type; |
|
|
|
|
|
|
|
if (type.MetadataType == MetadataType.Class || type.MetadataType == MetadataType.ValueType) { |
|
|
|
|
|
|
|
output.Write("enum "); |
|
|
|
|
|
|
|
if (type.Scope != type.Module) { |
|
|
|
|
|
|
|
output.Write("class "); |
|
|
|
|
|
|
|
output.Write(DisassemblerHelpers.Escape(GetAssemblyQualifiedName(type))); |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
type.WriteTo(output, ILNameSyntax.TypeName); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
CloseBlock("End of method " + method.DeclaringType.Name + "." + method.Name); |
|
|
|
|
|
|
|
} else { |
|
|
|
} else { |
|
|
|
output.WriteLine(); |
|
|
|
type.WriteTo(output); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
output.Write(' '); |
|
|
|
|
|
|
|
output.Write(DisassemblerHelpers.Escape(na.Name)); |
|
|
|
|
|
|
|
output.Write(" = "); |
|
|
|
|
|
|
|
if (na.Argument.Value is string) { |
|
|
|
|
|
|
|
// secdecls use special syntax for strings
|
|
|
|
|
|
|
|
output.Write("string('{0}')", NRefactory.CSharp.OutputVisitor.ConvertString((string)na.Argument.Value).Replace("'", "\'")); |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
WriteConstant(na.Argument.Value); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
string GetAssemblyQualifiedName(TypeReference type) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
AssemblyNameReference anr = type.Scope as AssemblyNameReference; |
|
|
|
|
|
|
|
if (anr == null) { |
|
|
|
|
|
|
|
ModuleDefinition md = type.Scope as ModuleDefinition; |
|
|
|
|
|
|
|
if (md != null) { |
|
|
|
|
|
|
|
anr = md.Assembly.Name; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (anr != null) { |
|
|
|
|
|
|
|
return type.FullName + ", " + anr.FullName; |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
return type.FullName; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#region WriteMarshalInfo
|
|
|
|
|
|
|
|
void WriteMarshalInfo(MarshalInfo marshalInfo) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
output.Write("marshal("); |
|
|
|
|
|
|
|
WriteNativeType(marshalInfo.NativeType, marshalInfo); |
|
|
|
|
|
|
|
output.Write(") "); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void WriteNativeType(NativeType nativeType, MarshalInfo marshalInfo = null) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
switch (nativeType) { |
|
|
|
|
|
|
|
case NativeType.None: |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case NativeType.Boolean: |
|
|
|
|
|
|
|
output.Write("bool"); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case NativeType.I1: |
|
|
|
|
|
|
|
output.Write("int8"); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case NativeType.U1: |
|
|
|
|
|
|
|
output.Write("unsigned int8"); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case NativeType.I2: |
|
|
|
|
|
|
|
output.Write("int16"); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case NativeType.U2: |
|
|
|
|
|
|
|
output.Write("unsigned int16"); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case NativeType.I4: |
|
|
|
|
|
|
|
output.Write("int32"); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case NativeType.U4: |
|
|
|
|
|
|
|
output.Write("unsigned int32"); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case NativeType.I8: |
|
|
|
|
|
|
|
output.Write("int64"); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case NativeType.U8: |
|
|
|
|
|
|
|
output.Write("unsigned int64"); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case NativeType.R4: |
|
|
|
|
|
|
|
output.Write("float32"); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case NativeType.R8: |
|
|
|
|
|
|
|
output.Write("float64"); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case NativeType.LPStr: |
|
|
|
|
|
|
|
output.Write("lpstr"); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case NativeType.Int: |
|
|
|
|
|
|
|
output.Write("int"); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case NativeType.UInt: |
|
|
|
|
|
|
|
output.Write("unsigned int"); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case NativeType.Func: |
|
|
|
|
|
|
|
goto default; // ??
|
|
|
|
|
|
|
|
case NativeType.Array: |
|
|
|
|
|
|
|
ArrayMarshalInfo ami = (ArrayMarshalInfo)marshalInfo; |
|
|
|
|
|
|
|
if (ami == null) |
|
|
|
|
|
|
|
goto default; |
|
|
|
|
|
|
|
if (ami.ElementType != NativeType.Max) |
|
|
|
|
|
|
|
WriteNativeType(ami.ElementType); |
|
|
|
|
|
|
|
output.Write('['); |
|
|
|
|
|
|
|
if (ami.SizeParameterMultiplier == 0) { |
|
|
|
|
|
|
|
output.Write(ami.Size.ToString()); |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
if (ami.Size >= 0) |
|
|
|
|
|
|
|
output.Write(ami.Size.ToString()); |
|
|
|
|
|
|
|
output.Write(" + "); |
|
|
|
|
|
|
|
output.Write(ami.SizeParameterIndex.ToString()); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
output.Write(']'); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case NativeType.Currency: |
|
|
|
|
|
|
|
output.Write("currency"); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case NativeType.BStr: |
|
|
|
|
|
|
|
output.Write("bstr"); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case NativeType.LPWStr: |
|
|
|
|
|
|
|
output.Write("lpwstr"); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case NativeType.LPTStr: |
|
|
|
|
|
|
|
output.Write("lptstr"); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case NativeType.FixedSysString: |
|
|
|
|
|
|
|
output.Write("fixed sysstring[{0}]", ((FixedSysStringMarshalInfo)marshalInfo).Size); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case NativeType.IUnknown: |
|
|
|
|
|
|
|
output.Write("iunknown"); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case NativeType.IDispatch: |
|
|
|
|
|
|
|
output.Write("idispatch"); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case NativeType.Struct: |
|
|
|
|
|
|
|
output.Write("struct"); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case NativeType.IntF: |
|
|
|
|
|
|
|
output.Write("interface"); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case NativeType.SafeArray: |
|
|
|
|
|
|
|
output.Write("safearray "); |
|
|
|
|
|
|
|
SafeArrayMarshalInfo sami = marshalInfo as SafeArrayMarshalInfo; |
|
|
|
|
|
|
|
if (sami != null) { |
|
|
|
|
|
|
|
switch (sami.ElementType) { |
|
|
|
|
|
|
|
case VariantType.None: |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case VariantType.I2: |
|
|
|
|
|
|
|
output.Write("int16"); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case VariantType.I4: |
|
|
|
|
|
|
|
output.Write("int32"); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case VariantType.R4: |
|
|
|
|
|
|
|
output.Write("float32"); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case VariantType.R8: |
|
|
|
|
|
|
|
output.Write("float64"); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case VariantType.CY: |
|
|
|
|
|
|
|
output.Write("currency"); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case VariantType.Date: |
|
|
|
|
|
|
|
output.Write("date"); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case VariantType.BStr: |
|
|
|
|
|
|
|
output.Write("bstr"); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case VariantType.Dispatch: |
|
|
|
|
|
|
|
output.Write("idispatch"); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case VariantType.Error: |
|
|
|
|
|
|
|
output.Write("error"); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case VariantType.Bool: |
|
|
|
|
|
|
|
output.Write("bool"); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case VariantType.Variant: |
|
|
|
|
|
|
|
output.Write("variant"); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case VariantType.Unknown: |
|
|
|
|
|
|
|
output.Write("iunknown"); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case VariantType.Decimal: |
|
|
|
|
|
|
|
output.Write("decimal"); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case VariantType.I1: |
|
|
|
|
|
|
|
output.Write("int8"); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case VariantType.UI1: |
|
|
|
|
|
|
|
output.Write("unsigned int8"); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case VariantType.UI2: |
|
|
|
|
|
|
|
output.Write("unsigned int16"); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case VariantType.UI4: |
|
|
|
|
|
|
|
output.Write("unsigned int32"); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case VariantType.Int: |
|
|
|
|
|
|
|
output.Write("int"); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case VariantType.UInt: |
|
|
|
|
|
|
|
output.Write("unsigned int"); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
default: |
|
|
|
|
|
|
|
output.Write(sami.ElementType.ToString()); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case NativeType.FixedArray: |
|
|
|
|
|
|
|
output.Write("fixed array"); |
|
|
|
|
|
|
|
FixedArrayMarshalInfo fami = marshalInfo as FixedArrayMarshalInfo; |
|
|
|
|
|
|
|
if (fami != null) { |
|
|
|
|
|
|
|
output.Write("[{0}]", fami.Size); |
|
|
|
|
|
|
|
if (fami.ElementType != NativeType.None) { |
|
|
|
|
|
|
|
output.Write(' '); |
|
|
|
|
|
|
|
WriteNativeType(fami.ElementType); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case NativeType.ByValStr: |
|
|
|
|
|
|
|
output.Write("byvalstr"); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case NativeType.ANSIBStr: |
|
|
|
|
|
|
|
output.Write("ansi bstr"); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case NativeType.TBStr: |
|
|
|
|
|
|
|
output.Write("tbstr"); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case NativeType.VariantBool: |
|
|
|
|
|
|
|
output.Write("variant bool"); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case NativeType.ASAny: |
|
|
|
|
|
|
|
output.Write("as any"); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case NativeType.LPStruct: |
|
|
|
|
|
|
|
output.Write("lpstruct"); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case NativeType.CustomMarshaler: |
|
|
|
|
|
|
|
CustomMarshalInfo cmi = marshalInfo as CustomMarshalInfo; |
|
|
|
|
|
|
|
if (cmi == null) |
|
|
|
|
|
|
|
goto default; |
|
|
|
|
|
|
|
output.Write("custom(\"{0}\", \"{1}\"", |
|
|
|
|
|
|
|
NRefactory.CSharp.OutputVisitor.ConvertString(cmi.ManagedType.FullName), |
|
|
|
|
|
|
|
NRefactory.CSharp.OutputVisitor.ConvertString(cmi.Cookie)); |
|
|
|
|
|
|
|
if (cmi.Guid != Guid.Empty || !string.IsNullOrEmpty(cmi.UnmanagedType)) { |
|
|
|
|
|
|
|
output.Write(", \"{0}\", \"{1}\"", cmi.Guid.ToString(), NRefactory.CSharp.OutputVisitor.ConvertString(cmi.UnmanagedType)); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
output.Write(')'); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case NativeType.Error: |
|
|
|
|
|
|
|
output.Write("error"); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
default: |
|
|
|
|
|
|
|
output.Write(nativeType.ToString()); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
void WriteParameters(Collection<ParameterDefinition> parameters) |
|
|
|
void WriteParameters(Collection<ParameterDefinition> parameters) |
|
|
|
{ |
|
|
|
{ |
|
|
|
for (int i = 0; i < parameters.Count; i++) { |
|
|
|
for (int i = 0; i < parameters.Count; i++) { |
|
|
|
var p = parameters[i]; |
|
|
|
var p = parameters[i]; |
|
|
|
|
|
|
|
if (p.IsIn) |
|
|
|
|
|
|
|
output.Write("[in] "); |
|
|
|
|
|
|
|
if (p.IsOut) |
|
|
|
|
|
|
|
output.Write("[out] "); |
|
|
|
|
|
|
|
if (p.IsOptional) |
|
|
|
|
|
|
|
output.Write("[opt] "); |
|
|
|
p.ParameterType.WriteTo(output); |
|
|
|
p.ParameterType.WriteTo(output); |
|
|
|
output.Write(' '); |
|
|
|
output.Write(' '); |
|
|
|
|
|
|
|
if (p.HasMarshalInfo) { |
|
|
|
|
|
|
|
WriteMarshalInfo(p.MarshalInfo); |
|
|
|
|
|
|
|
} |
|
|
|
output.WriteDefinition(DisassemblerHelpers.Escape(p.Name), p); |
|
|
|
output.WriteDefinition(DisassemblerHelpers.Escape(p.Name), p); |
|
|
|
if (i < parameters.Count - 1) |
|
|
|
if (i < parameters.Count - 1) |
|
|
|
output.Write(','); |
|
|
|
output.Write(','); |
|
|
|
output.WriteLine(); |
|
|
|
output.WriteLine(); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool HasParameterAttributes(ParameterDefinition p) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
return p.HasConstant || p.HasCustomAttributes; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void WriteParameterAttributes(ParameterDefinition p) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
if (!HasParameterAttributes(p)) |
|
|
|
|
|
|
|
return; |
|
|
|
|
|
|
|
output.Write(".param [{0}]", p.Index + 1); |
|
|
|
|
|
|
|
if (p.HasConstant) { |
|
|
|
|
|
|
|
output.Write(" = "); |
|
|
|
|
|
|
|
WriteConstant(p.Constant); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
output.WriteLine(); |
|
|
|
|
|
|
|
WriteAttributes(p.CustomAttributes); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void WriteConstant(object constant) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
if (constant == null) { |
|
|
|
|
|
|
|
output.Write("nullref"); |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
string typeName = DisassemblerHelpers.PrimitiveTypeName(constant.GetType().FullName); |
|
|
|
|
|
|
|
if (typeName != null && typeName != "string") { |
|
|
|
|
|
|
|
output.Write(typeName); |
|
|
|
|
|
|
|
output.Write('('); |
|
|
|
|
|
|
|
float? cf = constant as float?; |
|
|
|
|
|
|
|
double? cd = constant as double?; |
|
|
|
|
|
|
|
if (cf.HasValue && (float.IsNaN(cf.Value) || float.IsInfinity(cf.Value))) { |
|
|
|
|
|
|
|
output.Write("0x{0:x8}", BitConverter.ToInt32(BitConverter.GetBytes(cf.Value), 0)); |
|
|
|
|
|
|
|
} else if (cd.HasValue && (double.IsNaN(cd.Value) || double.IsInfinity(cd.Value))) { |
|
|
|
|
|
|
|
output.Write("0x{0:x16}", BitConverter.DoubleToInt64Bits(cd.Value)); |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
DisassemblerHelpers.WriteOperand(output, constant); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
output.Write(')'); |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
DisassemblerHelpers.WriteOperand(output, constant); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
#region Disassemble Field
|
|
|
|
#region Disassemble Field
|
|
|
|
@ -196,20 +671,26 @@ namespace ICSharpCode.Decompiler.Disassembler |
|
|
|
{ |
|
|
|
{ |
|
|
|
output.WriteDefinition(".field ", field); |
|
|
|
output.WriteDefinition(".field ", field); |
|
|
|
WriteEnum(field.Attributes & FieldAttributes.FieldAccessMask, fieldVisibility); |
|
|
|
WriteEnum(field.Attributes & FieldAttributes.FieldAccessMask, fieldVisibility); |
|
|
|
WriteFlags(field.Attributes & ~(FieldAttributes.FieldAccessMask | FieldAttributes.HasDefault), fieldAttributes); |
|
|
|
const FieldAttributes hasXAttributes = FieldAttributes.HasDefault | FieldAttributes.HasFieldMarshal | FieldAttributes.HasFieldRVA; |
|
|
|
|
|
|
|
WriteFlags(field.Attributes & ~(FieldAttributes.FieldAccessMask | hasXAttributes), fieldAttributes); |
|
|
|
|
|
|
|
if (field.HasMarshalInfo) { |
|
|
|
|
|
|
|
WriteMarshalInfo(field.MarshalInfo); |
|
|
|
|
|
|
|
} |
|
|
|
field.FieldType.WriteTo(output); |
|
|
|
field.FieldType.WriteTo(output); |
|
|
|
output.Write(' '); |
|
|
|
output.Write(' '); |
|
|
|
output.Write(DisassemblerHelpers.Escape(field.Name)); |
|
|
|
output.Write(DisassemblerHelpers.Escape(field.Name)); |
|
|
|
|
|
|
|
if ((field.Attributes & FieldAttributes.HasFieldRVA) == FieldAttributes.HasFieldRVA) { |
|
|
|
|
|
|
|
output.Write(" at I_{0:x8}", field.RVA); |
|
|
|
|
|
|
|
} |
|
|
|
if (field.HasConstant) { |
|
|
|
if (field.HasConstant) { |
|
|
|
output.Write(" = "); |
|
|
|
output.Write(" = "); |
|
|
|
DisassemblerHelpers.WriteOperand(output, field.Constant); |
|
|
|
WriteConstant(field.Constant); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
output.WriteLine(); |
|
|
|
if (field.HasCustomAttributes) { |
|
|
|
if (field.HasCustomAttributes) { |
|
|
|
OpenBlock(false); |
|
|
|
output.MarkFoldStart(); |
|
|
|
WriteAttributes(field.CustomAttributes); |
|
|
|
WriteAttributes(field.CustomAttributes); |
|
|
|
CloseBlock(); |
|
|
|
output.MarkFoldEnd(); |
|
|
|
} else { |
|
|
|
|
|
|
|
output.WriteLine(); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
@ -225,15 +706,27 @@ namespace ICSharpCode.Decompiler.Disassembler |
|
|
|
{ |
|
|
|
{ |
|
|
|
output.WriteDefinition(".property ", property); |
|
|
|
output.WriteDefinition(".property ", property); |
|
|
|
WriteFlags(property.Attributes, propertyAttributes); |
|
|
|
WriteFlags(property.Attributes, propertyAttributes); |
|
|
|
|
|
|
|
if (property.HasThis) |
|
|
|
|
|
|
|
output.Write("instance "); |
|
|
|
property.PropertyType.WriteTo(output); |
|
|
|
property.PropertyType.WriteTo(output); |
|
|
|
output.Write(' '); |
|
|
|
output.Write(' '); |
|
|
|
output.Write(DisassemblerHelpers.Escape(property.Name)); |
|
|
|
output.Write(DisassemblerHelpers.Escape(property.Name)); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
output.Write("("); |
|
|
|
|
|
|
|
if (property.HasParameters) { |
|
|
|
|
|
|
|
output.WriteLine(); |
|
|
|
|
|
|
|
output.Indent(); |
|
|
|
|
|
|
|
WriteParameters(property.Parameters); |
|
|
|
|
|
|
|
output.Unindent(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
output.Write(")"); |
|
|
|
|
|
|
|
|
|
|
|
OpenBlock(false); |
|
|
|
OpenBlock(false); |
|
|
|
WriteAttributes(property.CustomAttributes); |
|
|
|
WriteAttributes(property.CustomAttributes); |
|
|
|
WriteNestedMethod(".get", property.GetMethod); |
|
|
|
WriteNestedMethod(".get", property.GetMethod); |
|
|
|
WriteNestedMethod(".set", property.SetMethod); |
|
|
|
WriteNestedMethod(".set", property.SetMethod); |
|
|
|
foreach (var method in property.OtherMethods) { |
|
|
|
foreach (var method in property.OtherMethods) { |
|
|
|
WriteNestedMethod(".method", method); |
|
|
|
WriteNestedMethod(".other", method); |
|
|
|
} |
|
|
|
} |
|
|
|
CloseBlock(); |
|
|
|
CloseBlock(); |
|
|
|
} |
|
|
|
} |
|
|
|
@ -242,16 +735,10 @@ namespace ICSharpCode.Decompiler.Disassembler |
|
|
|
{ |
|
|
|
{ |
|
|
|
if (method == null) |
|
|
|
if (method == null) |
|
|
|
return; |
|
|
|
return; |
|
|
|
if (detectControlStructure) { |
|
|
|
output.Write(keyword); |
|
|
|
output.WriteDefinition(keyword, method); |
|
|
|
output.Write(' '); |
|
|
|
output.Write(' '); |
|
|
|
method.WriteTo(output); |
|
|
|
DisassembleMethodInternal(method); |
|
|
|
output.WriteLine(); |
|
|
|
} else { |
|
|
|
|
|
|
|
output.Write(keyword); |
|
|
|
|
|
|
|
output.Write(' '); |
|
|
|
|
|
|
|
method.WriteTo(output); |
|
|
|
|
|
|
|
output.WriteLine(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
@ -265,16 +752,16 @@ namespace ICSharpCode.Decompiler.Disassembler |
|
|
|
{ |
|
|
|
{ |
|
|
|
output.WriteDefinition(".event ", ev); |
|
|
|
output.WriteDefinition(".event ", ev); |
|
|
|
WriteFlags(ev.Attributes, eventAttributes); |
|
|
|
WriteFlags(ev.Attributes, eventAttributes); |
|
|
|
ev.EventType.WriteTo(output); |
|
|
|
ev.EventType.WriteTo(output, ILNameSyntax.TypeName); |
|
|
|
output.Write(' '); |
|
|
|
output.Write(' '); |
|
|
|
output.Write(DisassemblerHelpers.Escape(ev.Name)); |
|
|
|
output.Write(DisassemblerHelpers.Escape(ev.Name)); |
|
|
|
OpenBlock(false); |
|
|
|
OpenBlock(false); |
|
|
|
WriteAttributes(ev.CustomAttributes); |
|
|
|
WriteAttributes(ev.CustomAttributes); |
|
|
|
WriteNestedMethod(".add", ev.AddMethod); |
|
|
|
WriteNestedMethod(".addon", ev.AddMethod); |
|
|
|
WriteNestedMethod(".remove", ev.RemoveMethod); |
|
|
|
WriteNestedMethod(".removeon", ev.RemoveMethod); |
|
|
|
WriteNestedMethod(".invoke", ev.InvokeMethod); |
|
|
|
WriteNestedMethod(".fire", ev.InvokeMethod); |
|
|
|
foreach (var method in ev.OtherMethods) { |
|
|
|
foreach (var method in ev.OtherMethods) { |
|
|
|
WriteNestedMethod(".method", method); |
|
|
|
WriteNestedMethod(".other", method); |
|
|
|
} |
|
|
|
} |
|
|
|
CloseBlock(); |
|
|
|
CloseBlock(); |
|
|
|
} |
|
|
|
} |
|
|
|
@ -331,7 +818,7 @@ namespace ICSharpCode.Decompiler.Disassembler |
|
|
|
const TypeAttributes masks = TypeAttributes.ClassSemanticMask | TypeAttributes.VisibilityMask | TypeAttributes.LayoutMask | TypeAttributes.StringFormatMask; |
|
|
|
const TypeAttributes masks = TypeAttributes.ClassSemanticMask | TypeAttributes.VisibilityMask | TypeAttributes.LayoutMask | TypeAttributes.StringFormatMask; |
|
|
|
WriteFlags(type.Attributes & ~masks, typeAttributes); |
|
|
|
WriteFlags(type.Attributes & ~masks, typeAttributes); |
|
|
|
|
|
|
|
|
|
|
|
output.Write(DisassemblerHelpers.Escape(type.Name)); |
|
|
|
output.Write(DisassemblerHelpers.Escape(type.DeclaringType != null ? type.Name : type.FullName)); |
|
|
|
WriteTypeParameters(output, type); |
|
|
|
WriteTypeParameters(output, type); |
|
|
|
output.MarkFoldStart(defaultCollapsed: isInType); |
|
|
|
output.MarkFoldStart(defaultCollapsed: isInType); |
|
|
|
output.WriteLine(); |
|
|
|
output.WriteLine(); |
|
|
|
@ -339,7 +826,7 @@ namespace ICSharpCode.Decompiler.Disassembler |
|
|
|
if (type.BaseType != null) { |
|
|
|
if (type.BaseType != null) { |
|
|
|
output.Indent(); |
|
|
|
output.Indent(); |
|
|
|
output.Write("extends "); |
|
|
|
output.Write("extends "); |
|
|
|
type.BaseType.WriteTo(output, true); |
|
|
|
type.BaseType.WriteTo(output, ILNameSyntax.TypeName); |
|
|
|
output.WriteLine(); |
|
|
|
output.WriteLine(); |
|
|
|
output.Unindent(); |
|
|
|
output.Unindent(); |
|
|
|
} |
|
|
|
} |
|
|
|
@ -352,9 +839,7 @@ namespace ICSharpCode.Decompiler.Disassembler |
|
|
|
output.Write("implements "); |
|
|
|
output.Write("implements "); |
|
|
|
else |
|
|
|
else |
|
|
|
output.Write(" "); |
|
|
|
output.Write(" "); |
|
|
|
if (type.Interfaces[index].Namespace != null) |
|
|
|
type.Interfaces[index].WriteTo(output, ILNameSyntax.TypeName); |
|
|
|
output.Write("{0}.", type.Interfaces[index].Namespace); |
|
|
|
|
|
|
|
output.Write(type.Interfaces[index].Name); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
output.WriteLine(); |
|
|
|
output.WriteLine(); |
|
|
|
output.Unindent(); |
|
|
|
output.Unindent(); |
|
|
|
@ -365,6 +850,7 @@ namespace ICSharpCode.Decompiler.Disassembler |
|
|
|
bool oldIsInType = isInType; |
|
|
|
bool oldIsInType = isInType; |
|
|
|
isInType = true; |
|
|
|
isInType = true; |
|
|
|
WriteAttributes(type.CustomAttributes); |
|
|
|
WriteAttributes(type.CustomAttributes); |
|
|
|
|
|
|
|
WriteSecurityDeclarations(type); |
|
|
|
if (type.HasLayoutInfo) { |
|
|
|
if (type.HasLayoutInfo) { |
|
|
|
output.WriteLine(".pack {0}", type.PackingSize); |
|
|
|
output.WriteLine(".pack {0}", type.PackingSize); |
|
|
|
output.WriteLine(".size {0}", type.ClassSize); |
|
|
|
output.WriteLine(".size {0}", type.ClassSize); |
|
|
|
@ -387,13 +873,13 @@ namespace ICSharpCode.Decompiler.Disassembler |
|
|
|
} |
|
|
|
} |
|
|
|
output.WriteLine(); |
|
|
|
output.WriteLine(); |
|
|
|
} |
|
|
|
} |
|
|
|
if (type.HasProperties) { |
|
|
|
if (type.HasMethods) { |
|
|
|
output.WriteLine("// Properties"); |
|
|
|
output.WriteLine("// Methods"); |
|
|
|
foreach (var prop in type.Properties) { |
|
|
|
foreach (var m in type.Methods) { |
|
|
|
cancellationToken.ThrowIfCancellationRequested(); |
|
|
|
cancellationToken.ThrowIfCancellationRequested(); |
|
|
|
DisassembleProperty(prop); |
|
|
|
DisassembleMethod(m); |
|
|
|
|
|
|
|
output.WriteLine(); |
|
|
|
} |
|
|
|
} |
|
|
|
output.WriteLine(); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
if (type.HasEvents) { |
|
|
|
if (type.HasEvents) { |
|
|
|
output.WriteLine("// Events"); |
|
|
|
output.WriteLine("// Events"); |
|
|
|
@ -404,18 +890,15 @@ namespace ICSharpCode.Decompiler.Disassembler |
|
|
|
} |
|
|
|
} |
|
|
|
output.WriteLine(); |
|
|
|
output.WriteLine(); |
|
|
|
} |
|
|
|
} |
|
|
|
if (type.HasMethods) { |
|
|
|
if (type.HasProperties) { |
|
|
|
output.WriteLine("// Methods"); |
|
|
|
output.WriteLine("// Properties"); |
|
|
|
var accessorMethods = type.GetAccessorMethods(); |
|
|
|
foreach (var prop in type.Properties) { |
|
|
|
foreach (var m in type.Methods) { |
|
|
|
|
|
|
|
cancellationToken.ThrowIfCancellationRequested(); |
|
|
|
cancellationToken.ThrowIfCancellationRequested(); |
|
|
|
if (!(detectControlStructure && accessorMethods.Contains(m))) { |
|
|
|
DisassembleProperty(prop); |
|
|
|
DisassembleMethod(m); |
|
|
|
|
|
|
|
output.WriteLine(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
output.WriteLine(); |
|
|
|
} |
|
|
|
} |
|
|
|
CloseBlock("End of class " + type.FullName); |
|
|
|
CloseBlock("end of class " + (type.DeclaringType != null ? type.Name : type.FullName)); |
|
|
|
isInType = oldIsInType; |
|
|
|
isInType = oldIsInType; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@ -432,18 +915,18 @@ namespace ICSharpCode.Decompiler.Disassembler |
|
|
|
} else if (gp.HasNotNullableValueTypeConstraint) { |
|
|
|
} else if (gp.HasNotNullableValueTypeConstraint) { |
|
|
|
output.Write("valuetype "); |
|
|
|
output.Write("valuetype "); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (gp.HasDefaultConstructorConstraint) { |
|
|
|
|
|
|
|
output.Write(".ctor "); |
|
|
|
|
|
|
|
} |
|
|
|
if (gp.HasConstraints) { |
|
|
|
if (gp.HasConstraints) { |
|
|
|
output.Write('('); |
|
|
|
output.Write('('); |
|
|
|
for (int j = 0; j < gp.Constraints.Count; j++) { |
|
|
|
for (int j = 0; j < gp.Constraints.Count; j++) { |
|
|
|
if (j > 0) |
|
|
|
if (j > 0) |
|
|
|
output.Write(", "); |
|
|
|
output.Write(", "); |
|
|
|
gp.Constraints[j].WriteTo(output, true); |
|
|
|
gp.Constraints[j].WriteTo(output, ILNameSyntax.TypeName); |
|
|
|
} |
|
|
|
} |
|
|
|
output.Write(") "); |
|
|
|
output.Write(") "); |
|
|
|
} |
|
|
|
} |
|
|
|
if (gp.HasDefaultConstructorConstraint) { |
|
|
|
|
|
|
|
output.Write(".ctor "); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (gp.IsContravariant) { |
|
|
|
if (gp.IsContravariant) { |
|
|
|
output.Write('-'); |
|
|
|
output.Write('-'); |
|
|
|
} else if (gp.IsCovariant) { |
|
|
|
} else if (gp.IsCovariant) { |
|
|
|
@ -586,9 +1069,12 @@ namespace ICSharpCode.Decompiler.Disassembler |
|
|
|
{ |
|
|
|
{ |
|
|
|
output.Write(".assembly " + DisassemblerHelpers.Escape(asm.Name.Name)); |
|
|
|
output.Write(".assembly " + DisassemblerHelpers.Escape(asm.Name.Name)); |
|
|
|
OpenBlock(false); |
|
|
|
OpenBlock(false); |
|
|
|
Version v = asm.Name.Version; |
|
|
|
WriteAttributes(asm.CustomAttributes); |
|
|
|
if (v != null) { |
|
|
|
WriteSecurityDeclarations(asm); |
|
|
|
output.WriteLine(".ver {0}:{1}:{2}:{3}", v.Major, v.Minor, v.Build, v.Revision); |
|
|
|
if (asm.Name.PublicKey != null && asm.Name.PublicKey.Length > 0) { |
|
|
|
|
|
|
|
output.Write(".publickey = "); |
|
|
|
|
|
|
|
WriteBlob(asm.Name.PublicKey); |
|
|
|
|
|
|
|
output.WriteLine(); |
|
|
|
} |
|
|
|
} |
|
|
|
if (asm.Name.HashAlgorithm != AssemblyHashAlgorithm.None) { |
|
|
|
if (asm.Name.HashAlgorithm != AssemblyHashAlgorithm.None) { |
|
|
|
output.Write(".hash algorithm 0x{0:x8}", (int)asm.Name.HashAlgorithm); |
|
|
|
output.Write(".hash algorithm 0x{0:x8}", (int)asm.Name.HashAlgorithm); |
|
|
|
@ -596,15 +1082,66 @@ namespace ICSharpCode.Decompiler.Disassembler |
|
|
|
output.Write(" // SHA1"); |
|
|
|
output.Write(" // SHA1"); |
|
|
|
output.WriteLine(); |
|
|
|
output.WriteLine(); |
|
|
|
} |
|
|
|
} |
|
|
|
if (asm.Name.PublicKey != null && asm.Name.PublicKey.Length > 0) { |
|
|
|
Version v = asm.Name.Version; |
|
|
|
output.Write(".publickey = "); |
|
|
|
if (v != null) { |
|
|
|
WriteBlob(asm.Name.PublicKey); |
|
|
|
output.WriteLine(".ver {0}:{1}:{2}:{3}", v.Major, v.Minor, v.Build, v.Revision); |
|
|
|
output.WriteLine(); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
WriteAttributes(asm.CustomAttributes); |
|
|
|
|
|
|
|
CloseBlock(); |
|
|
|
CloseBlock(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public void WriteAssemblyReferences(ModuleDefinition module) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
foreach (var mref in module.ModuleReferences) { |
|
|
|
|
|
|
|
output.WriteLine(".module extern {0}", DisassemblerHelpers.Escape(mref.Name)); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
foreach (var aref in module.AssemblyReferences) { |
|
|
|
|
|
|
|
output.Write(".assembly extern {0}", DisassemblerHelpers.Escape(aref.Name)); |
|
|
|
|
|
|
|
OpenBlock(false); |
|
|
|
|
|
|
|
if (aref.PublicKeyToken != null) { |
|
|
|
|
|
|
|
output.Write(".publickeytoken = "); |
|
|
|
|
|
|
|
WriteBlob(aref.PublicKeyToken); |
|
|
|
|
|
|
|
output.WriteLine(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (aref.Version != null) { |
|
|
|
|
|
|
|
output.WriteLine(".ver {0}:{1}:{2}:{3}", aref.Version.Major, aref.Version.Minor, aref.Version.Build, aref.Version.Revision); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
CloseBlock(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public void WriteModuleHeader(ModuleDefinition module) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
if (module.HasExportedTypes) { |
|
|
|
|
|
|
|
foreach (ExportedType exportedType in module.ExportedTypes) { |
|
|
|
|
|
|
|
output.Write(".class extern "); |
|
|
|
|
|
|
|
if (exportedType.IsForwarder) |
|
|
|
|
|
|
|
output.Write("forwarder "); |
|
|
|
|
|
|
|
output.Write(exportedType.DeclaringType != null ? exportedType.Name : exportedType.FullName); |
|
|
|
|
|
|
|
OpenBlock(false); |
|
|
|
|
|
|
|
if (exportedType.DeclaringType != null) |
|
|
|
|
|
|
|
output.WriteLine(".class extern {0}", DisassemblerHelpers.Escape(exportedType.DeclaringType.FullName)); |
|
|
|
|
|
|
|
else |
|
|
|
|
|
|
|
output.WriteLine(".assembly extern {0}", DisassemblerHelpers.Escape(exportedType.Scope.Name)); |
|
|
|
|
|
|
|
CloseBlock(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
output.WriteLine(".module {0}", module.Name); |
|
|
|
|
|
|
|
output.WriteLine("// MVID: {0}", module.Mvid.ToString("B").ToUpperInvariant()); |
|
|
|
|
|
|
|
// TODO: imagebase, file alignment, stackreserve, subsystem
|
|
|
|
|
|
|
|
output.WriteLine(".corflags 0x{0:x} // {1}", module.Attributes, module.Attributes.ToString()); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
WriteAttributes(module.CustomAttributes); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public void WriteModuleContents(ModuleDefinition module) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
foreach (TypeDefinition td in module.Types) { |
|
|
|
|
|
|
|
DisassembleType(td); |
|
|
|
|
|
|
|
output.WriteLine(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/// <inheritdoc/>
|
|
|
|
/// <inheritdoc/>
|
|
|
|
public Tuple<string, List<MemberMapping>> CodeMappings { |
|
|
|
public Tuple<string, List<MemberMapping>> CodeMappings { |
|
|
|
get; |
|
|
|
get; |
|
|
|
|