Browse Source

Lots of improvements/fixes for the disassembler.

pull/194/merge
Daniel Grunwald 15 years ago
parent
commit
dd4d090468
  1. 97
      ICSharpCode.Decompiler/Disassembler/DisassemblerHelpers.cs
  2. 4
      ICSharpCode.Decompiler/Disassembler/ILStructure.cs
  3. 33
      ICSharpCode.Decompiler/Disassembler/MethodBodyDisassembler.cs
  4. 343
      ICSharpCode.Decompiler/Disassembler/ReflectionDisassembler.cs
  5. 4
      ILSpy/TextView/DecompilerTextView.cs

97
ICSharpCode.Decompiler/Disassembler/DisassemblerHelpers.cs

@ -17,6 +17,7 @@
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
using System; using System;
using System.Collections.Generic;
using Mono.Cecil; using Mono.Cecil;
using Mono.Cecil.Cil; using Mono.Cecil.Cil;
@ -77,8 +78,14 @@ namespace ICSharpCode.Decompiler.Disassembler
writer.WriteDefinition(CecilExtensions.OffsetToString(instruction.Offset), instruction); writer.WriteDefinition(CecilExtensions.OffsetToString(instruction.Offset), instruction);
writer.Write(": "); writer.Write(": ");
writer.WriteReference(instruction.OpCode.Name, instruction.OpCode); writer.WriteReference(instruction.OpCode.Name, instruction.OpCode);
if(null != instruction.Operand) { if (instruction.Operand != null) {
writer.Write(' '); writer.Write(' ');
if (instruction.OpCode == OpCodes.Ldtoken) {
if (instruction.Operand is MethodReference)
writer.Write("method ");
else if (instruction.Operand is FieldReference)
writer.Write("field ");
}
WriteOperand(writer, instruction.Operand); WriteOperand(writer, instruction.Operand);
} }
} }
@ -153,22 +160,62 @@ namespace ICSharpCode.Decompiler.Disassembler
return true; return true;
} }
static readonly HashSet<string> ilKeywords = BuildKeywordList(
"abstract", "algorithm", "alignment", "ansi", "any", "arglist",
"array", "as", "assembly", "assert", "at", "auto", "autochar", "beforefieldinit",
"blob", "blob_object", "bool", "brnull", "brnull.s", "brzero", "brzero.s", "bstr",
"bytearray", "byvalstr", "callmostderived", "carray", "catch", "cdecl", "cf",
"char", "cil", "class", "clsid", "const", "currency", "custom", "date", "decimal",
"default", "demand", "deny", "endmac", "enum", "error", "explicit", "extends", "extern",
"false", "famandassem", "family", "famorassem", "fastcall", "fault", "field", "filetime",
"filter", "final", "finally", "fixed", "float", "float32", "float64", "forwardref",
"fromunmanaged", "handler", "hidebysig", "hresult", "idispatch", "il", "illegal",
"implements", "implicitcom", "implicitres", "import", "in", "inheritcheck", "init",
"initonly", "instance", "int", "int16", "int32", "int64", "int8", "interface", "internalcall",
"iunknown", "lasterr", "lcid", "linkcheck", "literal", "localloc", "lpstr", "lpstruct", "lptstr",
"lpvoid", "lpwstr", "managed", "marshal", "method", "modopt", "modreq", "native", "nested",
"newslot", "noappdomain", "noinlining", "nomachine", "nomangle", "nometadata", "noncasdemand",
"noncasinheritance", "noncaslinkdemand", "noprocess", "not", "not_in_gc_heap", "notremotable",
"notserialized", "null", "nullref", "object", "objectref", "opt", "optil", "out",
"permitonly", "pinned", "pinvokeimpl", "prefix1", "prefix2", "prefix3", "prefix4", "prefix5", "prefix6",
"prefix7", "prefixref", "prejitdeny", "prejitgrant", "preservesig", "private", "privatescope", "protected",
"public", "record", "refany", "reqmin", "reqopt", "reqrefuse", "reqsecobj", "request", "retval",
"rtspecialname", "runtime", "safearray", "sealed", "sequential", "serializable", "special", "specialname",
"static", "stdcall", "storage", "stored_object", "stream", "streamed_object", "string", "struct",
"synchronized", "syschar", "sysstring", "tbstr", "thiscall", "tls", "to", "true", "typedref",
"unicode", "unmanaged", "unmanagedexp", "unsigned", "unused", "userdefined", "value", "valuetype",
"vararg", "variant", "vector", "virtual", "void", "wchar", "winapi", "with", "wrapper",
// These are not listed as keywords in spec, but ILAsm treats them as such
"property", "type", "flags", "callconv"
);
static HashSet<string> BuildKeywordList(params string[] keywords)
{
HashSet<string> s = new HashSet<string>(keywords);
foreach (var field in typeof(OpCodes).GetFields()) {
s.Add(((OpCode)field.GetValue(null)).Name);
}
return s;
}
public static string Escape(string identifier) public static string Escape(string identifier)
{ {
if (IsValidIdentifier(identifier) && identifier != "value") if (IsValidIdentifier(identifier) && !ilKeywords.Contains(identifier))
return identifier; return identifier;
else else
return "'" + identifier + "'"; return "'" + NRefactory.CSharp.OutputVisitor.ConvertString(identifier).Replace("'", "\\'") + "'";
} }
public static void WriteTo(this TypeReference type, ITextOutput writer, ILNameSyntax syntax = ILNameSyntax.Signature) public static void WriteTo(this TypeReference type, ITextOutput writer, ILNameSyntax syntax = ILNameSyntax.Signature)
{ {
ILNameSyntax syntaxForElementTypes = syntax == ILNameSyntax.SignatureNoNamedTypeParameters ? syntax : ILNameSyntax.Signature;
if (type is PinnedType) { if (type is PinnedType) {
writer.Write("pinned "); ((PinnedType)type).ElementType.WriteTo(writer, syntaxForElementTypes);
((PinnedType)type).ElementType.WriteTo(writer, syntax); writer.Write(" pinned");
} else if (type is ArrayType) { } else if (type is ArrayType) {
ArrayType at = (ArrayType)type; ArrayType at = (ArrayType)type;
at.ElementType.WriteTo(writer, syntax); at.ElementType.WriteTo(writer, syntaxForElementTypes);
writer.Write('['); writer.Write('[');
writer.Write(string.Join(", ", at.Dimensions)); writer.Write(string.Join(", ", at.Dimensions));
writer.Write(']'); writer.Write(']');
@ -181,33 +228,33 @@ namespace ICSharpCode.Decompiler.Disassembler
else else
writer.Write(Escape(type.Name)); writer.Write(Escape(type.Name));
} else if (type is ByReferenceType) { } else if (type is ByReferenceType) {
((ByReferenceType)type).ElementType.WriteTo(writer, syntax); ((ByReferenceType)type).ElementType.WriteTo(writer, syntaxForElementTypes);
writer.Write('&'); writer.Write('&');
} else if (type is PointerType) { } else if (type is PointerType) {
((PointerType)type).ElementType.WriteTo(writer, syntax); ((PointerType)type).ElementType.WriteTo(writer, syntaxForElementTypes);
writer.Write('*'); writer.Write('*');
} else if (type is GenericInstanceType) { } else if (type is GenericInstanceType) {
type.GetElementType().WriteTo(writer, syntax == ILNameSyntax.SignatureNoNamedTypeParameters ? syntax : ILNameSyntax.Signature); type.GetElementType().WriteTo(writer, syntaxForElementTypes);
writer.Write('<'); writer.Write('<');
var arguments = ((GenericInstanceType)type).GenericArguments; var arguments = ((GenericInstanceType)type).GenericArguments;
for (int i = 0; i < arguments.Count; i++) { for (int i = 0; i < arguments.Count; i++) {
if (i > 0) if (i > 0)
writer.Write(", "); writer.Write(", ");
arguments[i].WriteTo(writer, syntax == ILNameSyntax.SignatureNoNamedTypeParameters ? syntax : ILNameSyntax.Signature); arguments[i].WriteTo(writer, syntaxForElementTypes);
} }
writer.Write('>'); writer.Write('>');
} else if (type is OptionalModifierType) { } else if (type is OptionalModifierType) {
writer.Write("modopt("); ((OptionalModifierType)type).ElementType.WriteTo(writer, syntax);
writer.Write(" modopt(");
((OptionalModifierType)type).ModifierType.WriteTo(writer, ILNameSyntax.TypeName); ((OptionalModifierType)type).ModifierType.WriteTo(writer, ILNameSyntax.TypeName);
writer.Write(") "); writer.Write(") ");
((OptionalModifierType)type).ElementType.WriteTo(writer, syntax);
} else if (type is RequiredModifierType) { } else if (type is RequiredModifierType) {
writer.Write("modreq("); ((RequiredModifierType)type).ElementType.WriteTo(writer, syntax);
writer.Write(" modreq(");
((RequiredModifierType)type).ModifierType.WriteTo(writer, ILNameSyntax.TypeName); ((RequiredModifierType)type).ModifierType.WriteTo(writer, ILNameSyntax.TypeName);
writer.Write(") "); writer.Write(") ");
((RequiredModifierType)type).ElementType.WriteTo(writer, syntax);
} else { } else {
string name = PrimitiveTypeName(type); string name = PrimitiveTypeName(type.FullName);
if (syntax == ILNameSyntax.ShortTypeName) { if (syntax == ILNameSyntax.ShortTypeName) {
writer.WriteReference(Escape(type.Name), type); writer.WriteReference(Escape(type.Name), type);
} else if ((syntax == ILNameSyntax.Signature || syntax == ILNameSyntax.SignatureNoNamedTypeParameters) && name != null) { } else if ((syntax == ILNameSyntax.Signature || syntax == ILNameSyntax.SignatureNoNamedTypeParameters) && name != null) {
@ -284,11 +331,10 @@ namespace ICSharpCode.Decompiler.Disassembler
string s = operand as string; string s = operand as string;
if (s != null) { if (s != null) {
writer.Write("\"" + s.Replace("\\", "\\\\").Replace("\"", "\\\"") + "\""); writer.Write("\"" + NRefactory.CSharp.OutputVisitor.ConvertString(s) + "\"");
return; } else if (operand is char) {
} writer.Write(((int)(char)operand).ToString());
} else if (operand is float) {
if (operand is float) {
float val = (float)operand; float val = (float)operand;
if (val == 0) { if (val == 0) {
writer.Write("0.0"); writer.Write("0.0");
@ -304,7 +350,6 @@ namespace ICSharpCode.Decompiler.Disassembler
} else { } else {
writer.Write(val.ToString("R", System.Globalization.CultureInfo.InvariantCulture)); writer.Write(val.ToString("R", System.Globalization.CultureInfo.InvariantCulture));
} }
return;
} else if (operand is double) { } else if (operand is double) {
double val = (double)operand; double val = (double)operand;
if (val == 0) { if (val == 0) {
@ -321,15 +366,17 @@ namespace ICSharpCode.Decompiler.Disassembler
} else { } else {
writer.Write(val.ToString("R", System.Globalization.CultureInfo.InvariantCulture)); writer.Write(val.ToString("R", System.Globalization.CultureInfo.InvariantCulture));
} }
return; } else if (operand is bool) {
} writer.Write((bool)operand ? "true" : "false");
} else {
s = ToInvariantCultureString(operand); s = ToInvariantCultureString(operand);
writer.Write(s); writer.Write(s);
} }
}
public static string PrimitiveTypeName(this TypeReference type) public static string PrimitiveTypeName(string fullName)
{ {
switch (type.FullName) { switch (fullName) {
case "System.SByte": case "System.SByte":
return "int8"; return "int8";
case "System.Int16": case "System.Int16":

4
ICSharpCode.Decompiler/Disassembler/ILStructure.cs

@ -88,7 +88,9 @@ namespace ICSharpCode.Decompiler.Disassembler
: this(ILStructureType.Root, 0, body.CodeSize) : this(ILStructureType.Root, 0, body.CodeSize)
{ {
// Build the tree of exception structures: // Build the tree of exception structures:
foreach (ExceptionHandler eh in body.ExceptionHandlers) { for (int i = 0; i < body.ExceptionHandlers.Count; i++) {
ExceptionHandler eh = body.ExceptionHandlers[i];
if (!body.ExceptionHandlers.Take(i).Any(oldEh => oldEh.TryStart == eh.TryStart && oldEh.TryEnd == eh.TryEnd))
AddNestedStructure(new ILStructure(ILStructureType.Try, eh.TryStart.Offset, eh.TryEnd.Offset, eh)); AddNestedStructure(new ILStructure(ILStructureType.Try, eh.TryStart.Offset, eh.TryEnd.Offset, eh));
if (eh.HandlerType == ExceptionHandlerType.Filter) if (eh.HandlerType == ExceptionHandlerType.Filter)
AddNestedStructure(new ILStructure(ILStructureType.Filter, eh.FilterStart.Offset, eh.HandlerStart.Offset, eh)); AddNestedStructure(new ILStructure(ILStructureType.Filter, eh.FilterStart.Offset, eh.HandlerStart.Offset, eh));

33
ICSharpCode.Decompiler/Disassembler/MethodBodyDisassembler.cs

@ -52,9 +52,6 @@ namespace ICSharpCode.Decompiler.Disassembler
// start writing IL code // start writing IL code
MethodDefinition method = body.Method; MethodDefinition method = body.Method;
output.WriteLine("// Method begins at RVA 0x{0:x4}", method.RVA); output.WriteLine("// Method begins at RVA 0x{0:x4}", method.RVA);
if (method.HasOverrides)
foreach (var methodOverride in method.Overrides)
output.WriteLine(".override {0}::{1}", methodOverride.DeclaringType.FullName, methodOverride.Name);
output.WriteLine("// Code size {0} (0x{0:x})", body.CodeSize); output.WriteLine("// Code size {0} (0x{0:x})", body.CodeSize);
output.WriteLine(".maxstack {0}", body.MaxStackSize); output.WriteLine(".maxstack {0}", body.MaxStackSize);
if (method.DeclaringType.Module.Assembly.EntryPoint == method) if (method.DeclaringType.Module.Assembly.EntryPoint == method)
@ -84,7 +81,8 @@ namespace ICSharpCode.Decompiler.Disassembler
if (detectControlStructure && body.Instructions.Count > 0) { if (detectControlStructure && body.Instructions.Count > 0) {
Instruction inst = body.Instructions[0]; Instruction inst = body.Instructions[0];
WriteStructureBody(new ILStructure(body), ref inst, methodMapping, method.Body.CodeSize); HashSet<int> branchTargets = GetBranchTargets(body.Instructions);
WriteStructureBody(new ILStructure(body), branchTargets, ref inst, methodMapping, method.Body.CodeSize);
} else { } else {
foreach (var inst in method.Body.Instructions) { foreach (var inst in method.Body.Instructions) {
inst.WriteTo(output); inst.WriteTo(output);
@ -111,6 +109,21 @@ namespace ICSharpCode.Decompiler.Disassembler
} }
} }
HashSet<int> GetBranchTargets(IEnumerable<Instruction> instructions)
{
HashSet<int> branchTargets = new HashSet<int>();
foreach (var inst in instructions) {
Instruction target = inst.Operand as Instruction;
if (target != null)
branchTargets.Add(target.Offset);
Instruction[] targets = inst.Operand as Instruction[];
if (targets != null)
foreach (Instruction t in targets)
branchTargets.Add(t.Offset);
}
return branchTargets;
}
void WriteStructureHeader(ILStructure s) void WriteStructureHeader(ILStructure s)
{ {
switch (s.Type) { switch (s.Type) {
@ -159,8 +172,9 @@ namespace ICSharpCode.Decompiler.Disassembler
output.Indent(); output.Indent();
} }
void WriteStructureBody(ILStructure s, ref Instruction inst, MemberMapping currentMethodMapping, int codeSize) void WriteStructureBody(ILStructure s, HashSet<int> branchTargets, ref Instruction inst, MemberMapping currentMethodMapping, int codeSize)
{ {
bool isFirstInstructionInStructure = true;
bool prevInstructionWasBranch = false; bool prevInstructionWasBranch = false;
int childIndex = 0; int childIndex = 0;
while (inst != null && inst.Offset < s.EndOffset) { while (inst != null && inst.Offset < s.EndOffset) {
@ -168,14 +182,12 @@ namespace ICSharpCode.Decompiler.Disassembler
if (childIndex < s.Children.Count && s.Children[childIndex].StartOffset <= offset && offset < s.Children[childIndex].EndOffset) { if (childIndex < s.Children.Count && s.Children[childIndex].StartOffset <= offset && offset < s.Children[childIndex].EndOffset) {
ILStructure child = s.Children[childIndex++]; ILStructure child = s.Children[childIndex++];
WriteStructureHeader(child); WriteStructureHeader(child);
WriteStructureBody(child, ref inst, currentMethodMapping, codeSize); WriteStructureBody(child, branchTargets, ref inst, currentMethodMapping, codeSize);
WriteStructureFooter(child); WriteStructureFooter(child);
prevInstructionWasBranch = false;
} else { } else {
if (prevInstructionWasBranch) { if (!isFirstInstructionInStructure && (prevInstructionWasBranch || branchTargets.Contains(offset))) {
output.WriteLine(); // put empty line after branch instructions output.WriteLine(); // put an empty line after branches, and in front of branch targets
} }
inst.WriteTo(output); inst.WriteTo(output);
// add IL code mappings - used in debugger // add IL code mappings - used in debugger
@ -197,6 +209,7 @@ namespace ICSharpCode.Decompiler.Disassembler
inst = inst.Next; inst = inst.Next;
} }
isFirstInstructionInStructure = false;
} }
} }

343
ICSharpCode.Decompiler/Disassembler/ReflectionDisassembler.cs

@ -49,14 +49,16 @@ namespace ICSharpCode.Decompiler.Disassembler
{ MethodAttributes.Final, "final" }, { MethodAttributes.Final, "final" },
{ MethodAttributes.HideBySig, "hidebysig" }, { MethodAttributes.HideBySig, "hidebysig" },
{ 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.Virtual, "virtual" }, { MethodAttributes.CheckAccessOnOverride, "strict" },
{ MethodAttributes.Abstract, "abstract" }, { MethodAttributes.Abstract, "abstract" },
{ MethodAttributes.Static, "static" } { 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>() {
@ -74,7 +76,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>() {
@ -88,6 +90,8 @@ 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" },
}; };
public void DisassembleMethod(MethodDefinition method) public void DisassembleMethod(MethodDefinition method)
@ -107,6 +111,44 @@ namespace ICSharpCode.Decompiler.Disassembler
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.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();
@ -120,6 +162,9 @@ namespace ICSharpCode.Decompiler.Disassembler
//return type //return type
method.ReturnType.WriteTo(output); method.ReturnType.WriteTo(output);
output.Write(' '); output.Write(' ');
if (method.MethodReturnType.HasMarshalInfo) {
WriteMarshalInfo(method.MethodReturnType.MarshalInfo);
}
output.Write(DisassemblerHelpers.Escape(method.Name)); output.Write(DisassemblerHelpers.Escape(method.Name));
WriteTypeParameters(output, method); WriteTypeParameters(output, method);
@ -141,9 +186,15 @@ 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 || method.Parameters.Any(HasParameterAttributes)) {
OpenBlock(defaultCollapsed: isInType); OpenBlock(defaultCollapsed: isInType);
WriteAttributes(method.CustomAttributes); WriteAttributes(method.CustomAttributes);
if (method.HasOverrides) {
foreach (var methodOverride in method.Overrides) {
output.Write(".override method ");
methodOverride.WriteTo(output);
output.WriteLine();
}
}
foreach (var p in method.Parameters) { foreach (var p in method.Parameters) {
WriteParameterAttributes(p); WriteParameterAttributes(p);
} }
@ -154,12 +205,209 @@ namespace ICSharpCode.Decompiler.Disassembler
methodBodyDisassembler.Disassemble(method.Body, methodMapping); methodBodyDisassembler.Disassemble(method.Body, methodMapping);
} }
CloseBlock("end of method " + method.DeclaringType.Name + "::" + method.Name); CloseBlock("end of method " + DisassemblerHelpers.Escape(method.DeclaringType.Name) + "::" + DisassemblerHelpers.Escape(method.Name));
} else {
output.WriteLine();
} }
#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;
WriteNativeType(ami.ElementType);
output.Write("[size={0}, sizeParameterIndex={1}, sizeParameterMultiplier={2}]", ami.Size, ami.SizeParameterIndex, ami.SizeParameterMultiplier);
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 sysstring");
FixedArrayMarshalInfo fami = marshalInfo as FixedArrayMarshalInfo;
if (fami != null)
output.Write("[{0}]", ((FixedArrayMarshalInfo)marshalInfo).Size);
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;
goto default; // ???
case NativeType.Error:
output.Write("error");
break;
case NativeType.Max:
// ???
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++) {
@ -188,17 +436,39 @@ namespace ICSharpCode.Decompiler.Disassembler
{ {
if (!HasParameterAttributes(p)) if (!HasParameterAttributes(p))
return; return;
output.Write(".param [{0}]", p.Index); output.Write(".param [{0}]", p.Index + 1);
if (p.HasConstant) { if (p.HasConstant) {
output.Write(" = "); output.Write(" = ");
if (p.Constant != null) WriteConstant(p.Constant);
DisassemblerHelpers.WriteOperand(output, p.Constant);
else
output.Write("nullref");
} }
output.WriteLine(); output.WriteLine();
WriteAttributes(p.CustomAttributes); 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
@ -224,13 +494,20 @@ 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(); output.WriteLine();
if (field.HasCustomAttributes) { if (field.HasCustomAttributes) {
@ -272,7 +549,7 @@ namespace ICSharpCode.Decompiler.Disassembler
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();
} }
@ -298,16 +575,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();
} }
@ -426,14 +703,6 @@ namespace ICSharpCode.Decompiler.Disassembler
output.WriteLine(); output.WriteLine();
} }
} }
if (type.HasProperties) {
output.WriteLine("// Properties");
foreach (var prop in type.Properties) {
cancellationToken.ThrowIfCancellationRequested();
DisassembleProperty(prop);
}
output.WriteLine();
}
if (type.HasEvents) { if (type.HasEvents) {
output.WriteLine("// Events"); output.WriteLine("// Events");
foreach (var ev in type.Events) { foreach (var ev in type.Events) {
@ -443,6 +712,14 @@ namespace ICSharpCode.Decompiler.Disassembler
} }
output.WriteLine(); output.WriteLine();
} }
if (type.HasProperties) {
output.WriteLine("// Properties");
foreach (var prop in type.Properties) {
cancellationToken.ThrowIfCancellationRequested();
DisassembleProperty(prop);
}
output.WriteLine();
}
CloseBlock("end of class " + (type.DeclaringType != null ? type.Name : type.FullName)); CloseBlock("end of class " + (type.DeclaringType != null ? type.Name : type.FullName));
isInType = oldIsInType; isInType = oldIsInType;
} }
@ -460,6 +737,9 @@ 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++) {
@ -469,9 +749,6 @@ namespace ICSharpCode.Decompiler.Disassembler
} }
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) {

4
ILSpy/TextView/DecompilerTextView.cs

@ -617,12 +617,12 @@ namespace ICSharpCode.ILSpy.TextView
public void SaveFoldingsState(IEnumerable<FoldingSection> foldings) public void SaveFoldingsState(IEnumerable<FoldingSection> foldings)
{ {
ExpandedFoldings = foldings.Where(f => !f.IsFolded).Select(f => Tuple.Create(f.StartOffset, f.EndOffset)).ToList(); ExpandedFoldings = foldings.Where(f => !f.IsFolded).Select(f => Tuple.Create(f.StartOffset, f.EndOffset)).ToList();
FoldingsChecksum = foldings.Select(f => f.StartOffset * 3 - f.EndOffset).Aggregate((a, b) => a + b); FoldingsChecksum = unchecked(foldings.Select(f => f.StartOffset * 3 - f.EndOffset).Aggregate((a, b) => a + b));
} }
internal void RestoreFoldings(List<NewFolding> list) internal void RestoreFoldings(List<NewFolding> list)
{ {
var checksum = list.Select(f => f.StartOffset * 3 - f.EndOffset).Aggregate((a, b) => a + b); var checksum = unchecked(list.Select(f => f.StartOffset * 3 - f.EndOffset).Aggregate((a, b) => a + b));
if (FoldingsChecksum == checksum) if (FoldingsChecksum == checksum)
foreach (var folding in list) foreach (var folding in list)
folding.DefaultClosed = !ExpandedFoldings.Any(f => f.Item1 == folding.StartOffset && f.Item2 == folding.EndOffset); folding.DefaultClosed = !ExpandedFoldings.Any(f => f.Item1 == folding.StartOffset && f.Item2 == folding.EndOffset);

Loading…
Cancel
Save