Browse Source

Lots of improvements/fixes for the disassembler.

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

99
ICSharpCode.Decompiler/Disassembler/DisassemblerHelpers.cs

@ -17,6 +17,7 @@ @@ -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 @@ -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 @@ -153,22 +160,62 @@ namespace ICSharpCode.Decompiler.Disassembler
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)
{
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 @@ -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 @@ -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 @@ -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 @@ -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":

6
ICSharpCode.Decompiler/Disassembler/ILStructure.cs

@ -88,8 +88,10 @@ namespace ICSharpCode.Decompiler.Disassembler @@ -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));

33
ICSharpCode.Decompiler/Disassembler/MethodBodyDisassembler.cs

@ -52,9 +52,6 @@ namespace ICSharpCode.Decompiler.Disassembler @@ -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 @@ -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<int> 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 @@ -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)
{
switch (s.Type) {
@ -159,8 +172,9 @@ namespace ICSharpCode.Decompiler.Disassembler @@ -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<int> 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 @@ -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 @@ -197,6 +209,7 @@ namespace ICSharpCode.Decompiler.Disassembler
inst = inst.Next;
}
isFirstInstructionInStructure = false;
}
}

365
ICSharpCode.Decompiler/Disassembler/ReflectionDisassembler.cs

@ -49,14 +49,16 @@ namespace ICSharpCode.Decompiler.Disassembler @@ -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<MethodAttributes> methodVisibility = new EnumNameCollection<MethodAttributes>() {
@ -74,7 +76,7 @@ namespace ICSharpCode.Decompiler.Disassembler @@ -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<MethodImplAttributes> methodCodeType = new EnumNameCollection<MethodImplAttributes>() {
@ -88,6 +90,8 @@ namespace ICSharpCode.Decompiler.Disassembler @@ -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 @@ -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 @@ -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 @@ -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<ParameterDefinition> parameters)
{
for (int i = 0; i < parameters.Count; i++) {
@ -188,17 +436,39 @@ namespace ICSharpCode.Decompiler.Disassembler @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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) {

4
ILSpy/TextView/DecompilerTextView.cs

@ -617,12 +617,12 @@ namespace ICSharpCode.ILSpy.TextView @@ -617,12 +617,12 @@ namespace ICSharpCode.ILSpy.TextView
public void SaveFoldingsState(IEnumerable<FoldingSection> 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<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)
foreach (var folding in list)
folding.DefaultClosed = !ExpandedFoldings.Any(f => f.Item1 == folding.StartOffset && f.Item2 == folding.EndOffset);

Loading…
Cancel
Save