From dd4d090468edf4e2e1c0df27534fc12a9aa9db58 Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Sat, 21 May 2011 17:41:51 +0200 Subject: [PATCH] Lots of improvements/fixes for the disassembler. --- .../Disassembler/DisassemblerHelpers.cs | 99 +++-- .../Disassembler/ILStructure.cs | 6 +- .../Disassembler/MethodBodyDisassembler.cs | 33 +- .../Disassembler/ReflectionDisassembler.cs | 365 +++++++++++++++--- ILSpy/TextView/DecompilerTextView.cs | 4 +- 5 files changed, 423 insertions(+), 84 deletions(-) diff --git a/ICSharpCode.Decompiler/Disassembler/DisassemblerHelpers.cs b/ICSharpCode.Decompiler/Disassembler/DisassemblerHelpers.cs index 672cf252c..555eae487 100644 --- a/ICSharpCode.Decompiler/Disassembler/DisassemblerHelpers.cs +++ b/ICSharpCode.Decompiler/Disassembler/DisassemblerHelpers.cs @@ -17,6 +17,7 @@ // DEALINGS IN THE SOFTWARE. using System; +using System.Collections.Generic; using Mono.Cecil; using Mono.Cecil.Cil; @@ -77,8 +78,14 @@ namespace ICSharpCode.Decompiler.Disassembler writer.WriteDefinition(CecilExtensions.OffsetToString(instruction.Offset), instruction); writer.Write(": "); writer.WriteReference(instruction.OpCode.Name, instruction.OpCode); - if(null != instruction.Operand) { + if (instruction.Operand != null) { 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); } } @@ -153,22 +160,62 @@ namespace ICSharpCode.Decompiler.Disassembler return true; } + static readonly HashSet 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 BuildKeywordList(params string[] keywords) + { + HashSet s = new HashSet(keywords); + foreach (var field in typeof(OpCodes).GetFields()) { + s.Add(((OpCode)field.GetValue(null)).Name); + } + return s; + } + public static string Escape(string identifier) { - if (IsValidIdentifier(identifier) && identifier != "value") + if (IsValidIdentifier(identifier) && !ilKeywords.Contains(identifier)) return identifier; else - return "'" + identifier + "'"; + return "'" + NRefactory.CSharp.OutputVisitor.ConvertString(identifier).Replace("'", "\\'") + "'"; } 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) { - writer.Write("pinned "); - ((PinnedType)type).ElementType.WriteTo(writer, syntax); + ((PinnedType)type).ElementType.WriteTo(writer, syntaxForElementTypes); + writer.Write(" pinned"); } else if (type is ArrayType) { ArrayType at = (ArrayType)type; - at.ElementType.WriteTo(writer, syntax); + at.ElementType.WriteTo(writer, syntaxForElementTypes); writer.Write('['); writer.Write(string.Join(", ", at.Dimensions)); writer.Write(']'); @@ -181,33 +228,33 @@ namespace ICSharpCode.Decompiler.Disassembler else writer.Write(Escape(type.Name)); } else if (type is ByReferenceType) { - ((ByReferenceType)type).ElementType.WriteTo(writer, syntax); + ((ByReferenceType)type).ElementType.WriteTo(writer, syntaxForElementTypes); writer.Write('&'); } else if (type is PointerType) { - ((PointerType)type).ElementType.WriteTo(writer, syntax); + ((PointerType)type).ElementType.WriteTo(writer, syntaxForElementTypes); writer.Write('*'); } else if (type is GenericInstanceType) { - type.GetElementType().WriteTo(writer, syntax == ILNameSyntax.SignatureNoNamedTypeParameters ? syntax : ILNameSyntax.Signature); + type.GetElementType().WriteTo(writer, syntaxForElementTypes); writer.Write('<'); var arguments = ((GenericInstanceType)type).GenericArguments; for (int i = 0; i < arguments.Count; i++) { if (i > 0) writer.Write(", "); - arguments[i].WriteTo(writer, syntax == ILNameSyntax.SignatureNoNamedTypeParameters ? syntax : ILNameSyntax.Signature); + arguments[i].WriteTo(writer, syntaxForElementTypes); } writer.Write('>'); } else if (type is OptionalModifierType) { - writer.Write("modopt("); + ((OptionalModifierType)type).ElementType.WriteTo(writer, syntax); + writer.Write(" modopt("); ((OptionalModifierType)type).ModifierType.WriteTo(writer, ILNameSyntax.TypeName); writer.Write(") "); - ((OptionalModifierType)type).ElementType.WriteTo(writer, syntax); } else if (type is RequiredModifierType) { - writer.Write("modreq("); + ((RequiredModifierType)type).ElementType.WriteTo(writer, syntax); + writer.Write(" modreq("); ((RequiredModifierType)type).ModifierType.WriteTo(writer, ILNameSyntax.TypeName); writer.Write(") "); - ((RequiredModifierType)type).ElementType.WriteTo(writer, syntax); } else { - string name = PrimitiveTypeName(type); + string name = PrimitiveTypeName(type.FullName); if (syntax == ILNameSyntax.ShortTypeName) { writer.WriteReference(Escape(type.Name), type); } else if ((syntax == ILNameSyntax.Signature || syntax == ILNameSyntax.SignatureNoNamedTypeParameters) && name != null) { @@ -284,11 +331,10 @@ namespace ICSharpCode.Decompiler.Disassembler string s = operand as string; if (s != null) { - writer.Write("\"" + s.Replace("\\", "\\\\").Replace("\"", "\\\"") + "\""); - return; - } - - if (operand is float) { + writer.Write("\"" + NRefactory.CSharp.OutputVisitor.ConvertString(s) + "\""); + } else if (operand is char) { + writer.Write(((int)(char)operand).ToString()); + } else if (operand is float) { float val = (float)operand; if (val == 0) { writer.Write("0.0"); @@ -304,7 +350,6 @@ namespace ICSharpCode.Decompiler.Disassembler } else { writer.Write(val.ToString("R", System.Globalization.CultureInfo.InvariantCulture)); } - return; } else if (operand is double) { double val = (double)operand; if (val == 0) { @@ -321,15 +366,17 @@ namespace ICSharpCode.Decompiler.Disassembler } else { 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); + writer.Write(s); } - s = ToInvariantCultureString(operand); - writer.Write(s); } - public static string PrimitiveTypeName(this TypeReference type) + public static string PrimitiveTypeName(string fullName) { - switch (type.FullName) { + switch (fullName) { case "System.SByte": return "int8"; case "System.Int16": diff --git a/ICSharpCode.Decompiler/Disassembler/ILStructure.cs b/ICSharpCode.Decompiler/Disassembler/ILStructure.cs index 5fc29a9bd..4c681e3c1 100644 --- a/ICSharpCode.Decompiler/Disassembler/ILStructure.cs +++ b/ICSharpCode.Decompiler/Disassembler/ILStructure.cs @@ -88,8 +88,10 @@ namespace ICSharpCode.Decompiler.Disassembler : this(ILStructureType.Root, 0, body.CodeSize) { // Build the tree of exception structures: - foreach (ExceptionHandler eh in body.ExceptionHandlers) { - AddNestedStructure(new ILStructure(ILStructureType.Try, eh.TryStart.Offset, eh.TryEnd.Offset, eh)); + 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)); if (eh.HandlerType == ExceptionHandlerType.Filter) AddNestedStructure(new ILStructure(ILStructureType.Filter, eh.FilterStart.Offset, eh.HandlerStart.Offset, eh)); AddNestedStructure(new ILStructure(ILStructureType.Handler, eh.HandlerStart.Offset, eh.HandlerEnd == null ? body.CodeSize : eh.HandlerEnd.Offset, eh)); diff --git a/ICSharpCode.Decompiler/Disassembler/MethodBodyDisassembler.cs b/ICSharpCode.Decompiler/Disassembler/MethodBodyDisassembler.cs index c446516b1..2fcde2335 100644 --- a/ICSharpCode.Decompiler/Disassembler/MethodBodyDisassembler.cs +++ b/ICSharpCode.Decompiler/Disassembler/MethodBodyDisassembler.cs @@ -52,9 +52,6 @@ namespace ICSharpCode.Decompiler.Disassembler // start writing IL code MethodDefinition method = body.Method; 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(".maxstack {0}", body.MaxStackSize); if (method.DeclaringType.Module.Assembly.EntryPoint == method) @@ -84,7 +81,8 @@ namespace ICSharpCode.Decompiler.Disassembler if (detectControlStructure && body.Instructions.Count > 0) { Instruction inst = body.Instructions[0]; - WriteStructureBody(new ILStructure(body), ref inst, methodMapping, method.Body.CodeSize); + HashSet branchTargets = GetBranchTargets(body.Instructions); + WriteStructureBody(new ILStructure(body), branchTargets, ref inst, methodMapping, method.Body.CodeSize); } else { foreach (var inst in method.Body.Instructions) { inst.WriteTo(output); @@ -111,6 +109,21 @@ namespace ICSharpCode.Decompiler.Disassembler } } + HashSet GetBranchTargets(IEnumerable instructions) + { + HashSet branchTargets = new HashSet(); + 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) { switch (s.Type) { @@ -159,8 +172,9 @@ namespace ICSharpCode.Decompiler.Disassembler output.Indent(); } - void WriteStructureBody(ILStructure s, ref Instruction inst, MemberMapping currentMethodMapping, int codeSize) + void WriteStructureBody(ILStructure s, HashSet branchTargets, ref Instruction inst, MemberMapping currentMethodMapping, int codeSize) { + bool isFirstInstructionInStructure = true; bool prevInstructionWasBranch = false; int childIndex = 0; 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) { ILStructure child = s.Children[childIndex++]; WriteStructureHeader(child); - WriteStructureBody(child, ref inst, currentMethodMapping, codeSize); + WriteStructureBody(child, branchTargets, ref inst, currentMethodMapping, codeSize); WriteStructureFooter(child); - prevInstructionWasBranch = false; } else { - if (prevInstructionWasBranch) { - output.WriteLine(); // put empty line after branch instructions + if (!isFirstInstructionInStructure && (prevInstructionWasBranch || branchTargets.Contains(offset))) { + output.WriteLine(); // put an empty line after branches, and in front of branch targets } - inst.WriteTo(output); // add IL code mappings - used in debugger @@ -197,6 +209,7 @@ namespace ICSharpCode.Decompiler.Disassembler inst = inst.Next; } + isFirstInstructionInStructure = false; } } diff --git a/ICSharpCode.Decompiler/Disassembler/ReflectionDisassembler.cs b/ICSharpCode.Decompiler/Disassembler/ReflectionDisassembler.cs index 3a1b48f6a..956848a3e 100644 --- a/ICSharpCode.Decompiler/Disassembler/ReflectionDisassembler.cs +++ b/ICSharpCode.Decompiler/Disassembler/ReflectionDisassembler.cs @@ -49,14 +49,16 @@ namespace ICSharpCode.Decompiler.Disassembler { MethodAttributes.Final, "final" }, { MethodAttributes.HideBySig, "hidebysig" }, { MethodAttributes.SpecialName, "specialname" }, - { MethodAttributes.PInvokeImpl, "pinvokeimpl" }, + { MethodAttributes.PInvokeImpl, null }, // handled separately { MethodAttributes.UnmanagedExport, "export" }, { MethodAttributes.RTSpecialName, "rtspecialname" }, - { MethodAttributes.RequireSecObject, "requiresecobj" }, + { MethodAttributes.RequireSecObject, "reqsecobj" }, { MethodAttributes.NewSlot, "newslot" }, - { MethodAttributes.Virtual, "virtual" }, + { MethodAttributes.CheckAccessOnOverride, "strict" }, { MethodAttributes.Abstract, "abstract" }, - { MethodAttributes.Static, "static" } + { MethodAttributes.Virtual, "virtual" }, + { MethodAttributes.Static, "static" }, + { MethodAttributes.HasSecurity, null }, // ?? also invisible in ILDasm }; EnumNameCollection methodVisibility = new EnumNameCollection() { @@ -74,7 +76,7 @@ namespace ICSharpCode.Decompiler.Disassembler { MethodCallingConvention.ThisCall, "unmanaged thiscall" }, { MethodCallingConvention.FastCall, "unmanaged fastcall" }, { MethodCallingConvention.VarArg, "vararg" }, - { MethodCallingConvention.Generic, "generic" }, + { MethodCallingConvention.Generic, null }, }; EnumNameCollection methodCodeType = new EnumNameCollection() { @@ -88,6 +90,8 @@ namespace ICSharpCode.Decompiler.Disassembler { MethodImplAttributes.Synchronized, "synchronized" }, { MethodImplAttributes.NoInlining, "noinlining" }, { MethodImplAttributes.NoOptimization, "nooptimization" }, + { MethodImplAttributes.PreserveSig, "preservesig" }, + { MethodImplAttributes.InternalCall, "internalcall" }, }; public void DisassembleMethod(MethodDefinition method) @@ -107,6 +111,44 @@ namespace ICSharpCode.Decompiler.Disassembler WriteEnum(method.Attributes & MethodAttributes.MemberAccessMask, methodVisibility); 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.Indent(); @@ -120,6 +162,9 @@ namespace ICSharpCode.Decompiler.Disassembler //return type method.ReturnType.WriteTo(output); output.Write(' '); + if (method.MethodReturnType.HasMarshalInfo) { + WriteMarshalInfo(method.MethodReturnType.MarshalInfo); + } output.Write(DisassemblerHelpers.Escape(method.Name)); WriteTypeParameters(output, method); @@ -141,25 +186,228 @@ namespace ICSharpCode.Decompiler.Disassembler WriteFlags(method.ImplAttributes & ~(MethodImplAttributes.CodeTypeMask | MethodImplAttributes.ManagedMask), methodImpl); output.Unindent(); - if (method.HasBody || method.HasCustomAttributes || method.Parameters.Any(HasParameterAttributes)) { - OpenBlock(defaultCollapsed: isInType); - WriteAttributes(method.CustomAttributes); - foreach (var p in method.Parameters) { - WriteParameterAttributes(p); - } - - if (method.HasBody) { - // create IL code mappings - used in debugger - MemberMapping methodMapping = method.CreateCodeMapping(this.CodeMappings); - methodBodyDisassembler.Disassemble(method.Body, methodMapping); + OpenBlock(defaultCollapsed: isInType); + WriteAttributes(method.CustomAttributes); + if (method.HasOverrides) { + foreach (var methodOverride in method.Overrides) { + output.Write(".override method "); + methodOverride.WriteTo(output); + output.WriteLine(); } - - CloseBlock("end of method " + method.DeclaringType.Name + "::" + method.Name); - } else { - output.WriteLine(); } + foreach (var p in method.Parameters) { + WriteParameterAttributes(p); + } + + 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 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 parameters) { for (int i = 0; i < parameters.Count; i++) { @@ -188,17 +436,39 @@ namespace ICSharpCode.Decompiler.Disassembler { if (!HasParameterAttributes(p)) return; - output.Write(".param [{0}]", p.Index); + output.Write(".param [{0}]", p.Index + 1); if (p.HasConstant) { output.Write(" = "); - if (p.Constant != null) - DisassemblerHelpers.WriteOperand(output, p.Constant); - else - output.Write("nullref"); + 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 #region Disassemble Field @@ -224,13 +494,20 @@ namespace ICSharpCode.Decompiler.Disassembler { output.WriteDefinition(".field ", field); 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); output.Write(' '); output.Write(DisassemblerHelpers.Escape(field.Name)); + if ((field.Attributes & FieldAttributes.HasFieldRVA) == FieldAttributes.HasFieldRVA) { + output.Write(" at I_{0:x8}", field.RVA); + } if (field.HasConstant) { output.Write(" = "); - DisassemblerHelpers.WriteOperand(output, field.Constant); + WriteConstant(field.Constant); } output.WriteLine(); if (field.HasCustomAttributes) { @@ -272,7 +549,7 @@ namespace ICSharpCode.Decompiler.Disassembler WriteNestedMethod(".get", property.GetMethod); WriteNestedMethod(".set", property.SetMethod); foreach (var method in property.OtherMethods) { - WriteNestedMethod(".method", method); + WriteNestedMethod(".other", method); } CloseBlock(); } @@ -298,16 +575,16 @@ namespace ICSharpCode.Decompiler.Disassembler { output.WriteDefinition(".event ", ev); WriteFlags(ev.Attributes, eventAttributes); - ev.EventType.WriteTo(output); + ev.EventType.WriteTo(output, ILNameSyntax.TypeName); output.Write(' '); output.Write(DisassemblerHelpers.Escape(ev.Name)); OpenBlock(false); WriteAttributes(ev.CustomAttributes); - WriteNestedMethod(".add", ev.AddMethod); - WriteNestedMethod(".remove", ev.RemoveMethod); - WriteNestedMethod(".invoke", ev.InvokeMethod); + WriteNestedMethod(".addon", ev.AddMethod); + WriteNestedMethod(".removeon", ev.RemoveMethod); + WriteNestedMethod(".fire", ev.InvokeMethod); foreach (var method in ev.OtherMethods) { - WriteNestedMethod(".method", method); + WriteNestedMethod(".other", method); } CloseBlock(); } @@ -426,14 +703,6 @@ namespace ICSharpCode.Decompiler.Disassembler output.WriteLine(); } } - if (type.HasProperties) { - output.WriteLine("// Properties"); - foreach (var prop in type.Properties) { - cancellationToken.ThrowIfCancellationRequested(); - DisassembleProperty(prop); - } - output.WriteLine(); - } if (type.HasEvents) { output.WriteLine("// Events"); foreach (var ev in type.Events) { @@ -443,6 +712,14 @@ namespace ICSharpCode.Decompiler.Disassembler } 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)); isInType = oldIsInType; } @@ -460,6 +737,9 @@ namespace ICSharpCode.Decompiler.Disassembler } else if (gp.HasNotNullableValueTypeConstraint) { output.Write("valuetype "); } + if (gp.HasDefaultConstructorConstraint) { + output.Write(".ctor "); + } if (gp.HasConstraints) { output.Write('('); for (int j = 0; j < gp.Constraints.Count; j++) { @@ -469,9 +749,6 @@ namespace ICSharpCode.Decompiler.Disassembler } output.Write(") "); } - if (gp.HasDefaultConstructorConstraint) { - output.Write(".ctor "); - } if (gp.IsContravariant) { output.Write('-'); } else if (gp.IsCovariant) { diff --git a/ILSpy/TextView/DecompilerTextView.cs b/ILSpy/TextView/DecompilerTextView.cs index b312abf8a..024994462 100644 --- a/ILSpy/TextView/DecompilerTextView.cs +++ b/ILSpy/TextView/DecompilerTextView.cs @@ -617,12 +617,12 @@ namespace ICSharpCode.ILSpy.TextView public void SaveFoldingsState(IEnumerable foldings) { 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 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) foreach (var folding in list) folding.DefaultClosed = !ExpandedFoldings.Any(f => f.Item1 == folding.StartOffset && f.Item2 == folding.EndOffset);