Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/ikdasm.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeroen Frijters <jeroen@frijters.net>2013-02-25 14:27:25 +0400
committerJeroen Frijters <jeroen@frijters.net>2013-02-25 14:27:25 +0400
commit9b7577d079431bc017de44cb6b58949de1c52282 (patch)
tree542195f11cf00a5d98c58f1039a4782e8b9bdcd2
Initial commit.
-rw-r--r--.gitattributes22
-rw-r--r--.gitignore163
-rw-r--r--ByteReader.cs194
-rw-r--r--CABlob.cs597
-rw-r--r--Disassembler.cs2979
-rw-r--r--ExportedMethods.cs167
-rw-r--r--IKVM.Reflection.dllbin0 -> 442368 bytes
-rw-r--r--IL.cs1040
-rw-r--r--Keywords.cs240
-rw-r--r--LineWriter.cs100
-rw-r--r--Program.cs149
-rw-r--r--Util.cs53
-rw-r--r--VTableFixups.cs163
-rw-r--r--ikdasm.csproj78
-rw-r--r--ikdasm.sln20
15 files changed, 5965 insertions, 0 deletions
diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000..412eeda
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,22 @@
+# Auto detect text files and perform LF normalization
+* text=auto
+
+# Custom for Visual Studio
+*.cs diff=csharp
+*.sln merge=union
+*.csproj merge=union
+*.vbproj merge=union
+*.fsproj merge=union
+*.dbproj merge=union
+
+# Standard to msysgit
+*.doc diff=astextplain
+*.DOC diff=astextplain
+*.docx diff=astextplain
+*.DOCX diff=astextplain
+*.dot diff=astextplain
+*.DOT diff=astextplain
+*.pdf diff=astextplain
+*.PDF diff=astextplain
+*.rtf diff=astextplain
+*.RTF diff=astextplain
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..5ebd21a
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,163 @@
+#################
+## Eclipse
+#################
+
+*.pydevproject
+.project
+.metadata
+bin/
+tmp/
+*.tmp
+*.bak
+*.swp
+*~.nib
+local.properties
+.classpath
+.settings/
+.loadpath
+
+# External tool builders
+.externalToolBuilders/
+
+# Locally stored "Eclipse launch configurations"
+*.launch
+
+# CDT-specific
+.cproject
+
+# PDT-specific
+.buildpath
+
+
+#################
+## Visual Studio
+#################
+
+## Ignore Visual Studio temporary files, build results, and
+## files generated by popular Visual Studio add-ons.
+
+# User-specific files
+*.suo
+*.user
+*.sln.docstates
+
+# Build results
+[Dd]ebug/
+[Rr]elease/
+*_i.c
+*_p.c
+*.ilk
+*.meta
+*.obj
+*.pch
+*.pdb
+*.pgc
+*.pgd
+*.rsp
+*.sbr
+*.tlb
+*.tli
+*.tlh
+*.tmp
+*.vspscc
+.builds
+*.dotCover
+
+## TODO: If you have NuGet Package Restore enabled, uncomment this
+#packages/
+
+# Visual C++ cache files
+ipch/
+*.aps
+*.ncb
+*.opensdf
+*.sdf
+
+# Visual Studio profiler
+*.psess
+*.vsp
+
+# ReSharper is a .NET coding add-in
+_ReSharper*
+
+# Installshield output folder
+[Ee]xpress
+
+# DocProject is a documentation generator add-in
+DocProject/buildhelp/
+DocProject/Help/*.HxT
+DocProject/Help/*.HxC
+DocProject/Help/*.hhc
+DocProject/Help/*.hhk
+DocProject/Help/*.hhp
+DocProject/Help/Html2
+DocProject/Help/html
+
+# Click-Once directory
+publish
+
+# Others
+[Bb]in
+[Oo]bj
+sql
+TestResults
+*.Cache
+ClientBin
+stylecop.*
+~$*
+*.dbmdl
+Generated_Code #added for RIA/Silverlight projects
+
+# Backup & report files from converting an old project file to a newer
+# Visual Studio version. Backup files are not needed, because we have git ;-)
+_UpgradeReport_Files/
+Backup*/
+UpgradeLog*.XML
+
+
+
+############
+## Windows
+############
+
+# Windows image file caches
+Thumbs.db
+
+# Folder config file
+Desktop.ini
+
+
+#############
+## Python
+#############
+
+*.py[co]
+
+# Packages
+*.egg
+*.egg-info
+dist
+build
+eggs
+parts
+bin
+var
+sdist
+develop-eggs
+.installed.cfg
+
+# Installer logs
+pip-log.txt
+
+# Unit test / coverage reports
+.coverage
+.tox
+
+#Translations
+*.mo
+
+#Mr Developer
+.mr.developer.cfg
+
+# Mac crap
+.DS_Store
diff --git a/ByteReader.cs b/ByteReader.cs
new file mode 100644
index 0000000..7e3c6f5
--- /dev/null
+++ b/ByteReader.cs
@@ -0,0 +1,194 @@
+/*
+ Copyright (C) 2009 Jeroen Frijters
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ Jeroen Frijters
+ jeroen@frijters.net
+
+*/
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace IKVM.Reflection.Reader
+{
+ sealed class ByteReader
+ {
+ private byte[] buffer;
+ private int pos;
+ private int end;
+
+ internal ByteReader(byte[] buffer, int offset, int length)
+ {
+ this.buffer = buffer;
+ this.pos = offset;
+ this.end = pos + length;
+ }
+
+ internal static ByteReader FromBlob(byte[] blobHeap, int blob)
+ {
+ ByteReader br = new ByteReader(blobHeap, blob, 4);
+ int length = br.ReadCompressedInt();
+ br.end = br.pos + length;
+ return br;
+ }
+
+ internal int Length
+ {
+ get { return end - pos; }
+ }
+
+ internal byte PeekByte()
+ {
+ if (pos == end)
+ throw new BadImageFormatException();
+ return buffer[pos];
+ }
+
+ internal byte ReadByte()
+ {
+ if (pos == end)
+ throw new BadImageFormatException();
+ return buffer[pos++];
+ }
+
+ internal byte[] ReadBytes(int count)
+ {
+ if (count < 0)
+ throw new BadImageFormatException();
+ if (end - pos < count)
+ throw new BadImageFormatException();
+ byte[] buf = new byte[count];
+ Buffer.BlockCopy(buffer, pos, buf, 0, count);
+ pos += count;
+ return buf;
+ }
+
+ internal int ReadCompressedInt()
+ {
+ byte b1 = ReadByte();
+ if (b1 <= 0x7F)
+ {
+ return b1;
+ }
+ else if ((b1 & 0xC0) == 0x80)
+ {
+ byte b2 = ReadByte();
+ return ((b1 & 0x3F) << 8) | b2;
+ }
+ else
+ {
+ byte b2 = ReadByte();
+ byte b3 = ReadByte();
+ byte b4 = ReadByte();
+ return ((b1 & 0x3F) << 24) + (b2 << 16) + (b3 << 8) + b4;
+ }
+ }
+
+ internal string ReadString()
+ {
+ if (PeekByte() == 0xFF)
+ {
+ pos++;
+ return null;
+ }
+ int length = ReadCompressedInt();
+ string str = Encoding.UTF8.GetString(buffer, pos, length);
+ pos += length;
+ return str;
+ }
+
+ internal char ReadChar()
+ {
+ return (char)ReadInt16();
+ }
+
+ internal sbyte ReadSByte()
+ {
+ return (sbyte)ReadByte();
+ }
+
+ internal short ReadInt16()
+ {
+ if (end - pos < 2)
+ throw new BadImageFormatException();
+ byte b1 = buffer[pos++];
+ byte b2 = buffer[pos++];
+ return (short)(b1 | (b2 << 8));
+ }
+
+ internal ushort ReadUInt16()
+ {
+ return (ushort)ReadInt16();
+ }
+
+ internal int ReadInt32()
+ {
+ if (end - pos < 4)
+ throw new BadImageFormatException();
+ byte b1 = buffer[pos++];
+ byte b2 = buffer[pos++];
+ byte b3 = buffer[pos++];
+ byte b4 = buffer[pos++];
+ return (int)(b1 | (b2 << 8) | (b3 << 16) | (b4 << 24));
+ }
+
+ internal uint ReadUInt32()
+ {
+ return (uint)ReadInt32();
+ }
+
+ internal long ReadInt64()
+ {
+ ulong lo = ReadUInt32();
+ ulong hi = ReadUInt32();
+ return (long)(lo | (hi << 32));
+ }
+
+ internal ulong ReadUInt64()
+ {
+ return (ulong)ReadInt64();
+ }
+
+ internal float ReadSingle()
+ {
+ return SingleConverter.Int32BitsToSingle(ReadInt32());
+ }
+
+ internal double ReadDouble()
+ {
+ return BitConverter.Int64BitsToDouble(ReadInt64());
+ }
+
+ internal ByteReader Slice(int length)
+ {
+ if (end - pos < length)
+ throw new BadImageFormatException();
+ ByteReader br = new ByteReader(buffer, pos, length);
+ pos += length;
+ return br;
+ }
+
+ // NOTE this method only works if the original offset was aligned and for alignments that are a power of 2
+ internal void Align(int alignment)
+ {
+ alignment--;
+ pos = (pos + alignment) & ~alignment;
+ }
+ }
+}
diff --git a/CABlob.cs b/CABlob.cs
new file mode 100644
index 0000000..0e728fd
--- /dev/null
+++ b/CABlob.cs
@@ -0,0 +1,597 @@
+/*
+ Copyright (C) 2012 Jeroen Frijters
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ Jeroen Frijters
+ jeroen@frijters.net
+
+*/
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using IKVM.Reflection;
+using IKVM.Reflection.Reader;
+using Type = IKVM.Reflection.Type;
+
+namespace Ildasm
+{
+ partial class Disassembler
+ {
+ bool DecodeDeclSecurity(StringBuilder sb, IList<CustomAttributeData> list, int level)
+ {
+ try
+ {
+ sb.Append(" = {");
+ bool first = true;
+ foreach (var sec in list)
+ {
+ if (!first)
+ {
+ sb.Append(',');
+ sb.AppendLine();
+ sb.Append(' ', level + 14);
+ }
+ first = false;
+ string typeName = sec.Constructor.DeclaringType.AssemblyQualifiedName;
+ if (typeName.EndsWith(", mscorlib", StringComparison.Ordinal))
+ {
+ typeName = typeName.Substring(0, typeName.Length - 10);
+ }
+ AppendTypeName(sb, sec.Constructor.DeclaringType, typeName, compat != CompatLevel.None);
+ sb.Append(" = {");
+ byte[] blob = sec.__GetBlob();
+ // LAMESPEC the count of named arguments is a compressed integer (instead of UInt16 as NumNamed in custom attributes)
+ var br = new ByteReader(blob, 0, blob.Length);
+ int count = br.ReadCompressedInt();
+ ReadNamedArguments(sb, br, count, 0, compat != CompatLevel.None && count > 1);
+ sb.Append('}');
+ }
+ sb.Append('}');
+ return true;
+ }
+ catch (IKVM.Reflection.BadImageFormatException)
+ {
+ return false;
+ }
+ }
+
+ void AppendTypeName(StringBuilder sb, Type type)
+ {
+ if (type.IsNested)
+ {
+ AppendTypeName(sb, type.DeclaringType);
+ sb.Append('/');
+ }
+ AppendTypeNameNoOuter(sb, type);
+ }
+
+ void AppendTypeNameNoOuter(StringBuilder sb, Type type)
+ {
+ if (type.__Namespace != null)
+ {
+ sb.Append(QuoteIdentifier(type.__Namespace));
+ sb.Append('.');
+ }
+ sb.Append(QuoteIdentifier(type.__Name));
+ }
+
+ void AppendTypeName(StringBuilder sb, Type type, string typeName, bool noself = false, bool securityCompatHack = false)
+ {
+ if (type.Assembly == assembly && !noself && (!type.IsGenericType || type.IsGenericTypeDefinition) && !type.HasElementType)
+ {
+ AppendTypeName(sb, type);
+ }
+ else if (typerefs.Contains(type))
+ {
+ sb.Append('[').Append(QuoteIdentifier(referencedAssemblies[type.Assembly])).Append(']');
+ AppendTypeName(sb, type);
+ }
+ else
+ {
+ if (securityCompatHack)
+ {
+ throw new IKVM.Reflection.BadImageFormatException();
+ }
+ sb.Append("class ").Append(QuoteIdentifier(typeName, true));
+ }
+ }
+
+ bool DecodeCABlob(StringBuilder sb, ConstructorInfo constructor, byte[] blob, int level)
+ {
+ try
+ {
+ // CustomAttribute
+ var br = new ByteReader(blob, 2, blob.Length - 4);
+ ReadConstructorArguments(sb, br, constructor, level);
+ br = new ByteReader(blob, blob.Length - (br.Length + 2), br.Length + 2);
+ int named = br.ReadUInt16();
+ if (constructor.GetParameters().Length != 0 && named != 0)
+ {
+ AppendNewLine(sb, level);
+ }
+ ReadNamedArguments(sb, br, named, level, false);
+ return true;
+ }
+ catch (IKVM.Reflection.BadImageFormatException) { }
+ catch (ArgumentOutOfRangeException) { }
+ return false;
+ }
+
+ void AppendNewLine(StringBuilder sb, int level)
+ {
+ sb.AppendLine();
+ if (level < 0)
+ {
+ sb.Append(" //");
+ sb.Append(' ', -level - 4);
+ }
+ else
+ {
+ sb.Append(' ', level);
+ }
+ }
+
+ void ReadConstructorArguments(StringBuilder sb, ByteReader br, ConstructorInfo constructor, int level)
+ {
+ bool first = true;
+ foreach (var parameter in constructor.GetParameters())
+ {
+ if (!first)
+ {
+ AppendNewLine(sb, level);
+ }
+ first = false;
+ ReadFixedArg(sb, br, parameter.ParameterType);
+ }
+ }
+
+ void ReadNamedArguments(StringBuilder sb, ByteReader br, int named, int level, bool securityCompatHack)
+ {
+ for (int i = 0; i < named; i++)
+ {
+ if (i != 0)
+ {
+ AppendNewLine(sb, level);
+ }
+ byte fieldOrProperty = br.ReadByte();
+ switch (fieldOrProperty)
+ {
+ case 0x53:
+ sb.Append("field ");
+ break;
+ case 0x54:
+ sb.Append("property ");
+ break;
+ default:
+ throw new IKVM.Reflection.BadImageFormatException();
+ }
+ string typeName;
+ Type fieldOrPropertyType = ReadFieldOrPropType(sb, br, out typeName);
+ AppendCATypeName(sb, fieldOrPropertyType, typeName, securityCompatHack);
+ sb.Append(' ').Append(QuoteIdentifier(br.ReadString(), true)).Append(" = ");
+ ReadFixedArg(sb, br, fieldOrPropertyType);
+ }
+ }
+
+ void ReadFixedArg(StringBuilder sb, ByteReader br, Type type, bool arrayElement = false)
+ {
+ if (type.IsArray)
+ {
+ int length = br.ReadInt32();
+ if (length == -1 && compat == CompatLevel.None)
+ {
+ sb.Append("nullref");
+ }
+ else if (length == 0 && compat != CompatLevel.None)
+ {
+ throw new IKVM.Reflection.BadImageFormatException();
+ }
+ else
+ {
+ Type elementType = type.GetElementType();
+ AppendCATypeName(sb, elementType, null);
+ sb.AppendFormat("[{0}](", length);
+ for (int i = 0; i < length; i++)
+ {
+ if (i != 0)
+ {
+ sb.Append(' ');
+ }
+ if (elementType == typeofSystemObject)
+ {
+ string typeName;
+ ReadFixedArg(sb, br, ReadFieldOrPropType(sb, br, out typeName), false);
+ }
+ else
+ {
+ ReadFixedArg(sb, br, elementType, true);
+ }
+ }
+ sb.Append(')');
+ }
+ }
+ else if (type.FullName == "System.Type" && type.Assembly.GetName().Name == "mscorlib")
+ {
+ if (!arrayElement)
+ {
+ AppendCATypeName(sb, type, null);
+ sb.Append('(');
+ }
+ string typeName;
+ var type1 = ReadType(br, out typeName);
+ if (type1 == null)
+ {
+ if (typeName == null)
+ {
+ sb.Append("nullref");
+ }
+ else
+ {
+ sb.Append("class ").Append(QuoteIdentifier(typeName, true));
+ }
+ }
+ else
+ {
+ AppendTypeName(sb, type1, typeName, compat != CompatLevel.None && IsNestedTypeWithNamespace(type1));
+ }
+ if (!arrayElement)
+ {
+ sb.Append(')');
+ }
+ }
+ else if (type.Assembly == mscorlib)
+ {
+ if (!arrayElement)
+ {
+ AppendCATypeName(sb, type, null);
+ sb.Append('(');
+ }
+ if (type == typeofSystemBoolean)
+ {
+ sb.Append(br.ReadByte() == 0 ? "false" : "true");
+ }
+ else if (type == typeofSystemByte)
+ {
+ sb.Append(br.ReadByte());
+ }
+ else if (type == typeofSystemSByte)
+ {
+ sb.Append(br.ReadSByte());
+ }
+ else if (type == typeofSystemChar)
+ {
+ sb.AppendFormat("0x{0:X4}", (int)br.ReadChar());
+ }
+ else if (type == typeofSystemInt16)
+ {
+ sb.Append(br.ReadInt16());
+ }
+ else if (type == typeofSystemUInt16)
+ {
+ sb.Append(br.ReadUInt16());
+ }
+ else if (type == typeofSystemInt32)
+ {
+ sb.Append(br.ReadInt32());
+ }
+ else if (type == typeofSystemUInt32)
+ {
+ sb.Append(br.ReadInt32());
+ }
+ else if (type == typeofSystemInt64)
+ {
+ sb.Append(br.ReadInt64());
+ }
+ else if (type == typeofSystemUInt64)
+ {
+ sb.Append(br.ReadInt64());
+ }
+ else if (type == typeofSystemSingle)
+ {
+ sb.Append(ToString(br.ReadSingle(), true));
+ }
+ else if (type == typeofSystemDouble)
+ {
+ sb.Append(ToString(br.ReadDouble(), true));
+ }
+ else if (type == typeofSystemString)
+ {
+ var str = br.ReadString();
+ if (str == null)
+ {
+ sb.Append("nullref");
+ }
+ else
+ {
+ if (compat != CompatLevel.None)
+ {
+ int pos = str.IndexOf((char)0);
+ if (pos != -1)
+ {
+ str = str.Substring(0, pos);
+ }
+ }
+ sb.Append(QuoteIdentifier(str, true));
+ }
+ }
+ else if (type == typeofSystemObject)
+ {
+ string typeName;
+ ReadFixedArg(sb, br, ReadFieldOrPropType(sb, br, out typeName));
+ }
+ else
+ {
+ throw new NotImplementedException(type.FullName);
+ }
+ if (!arrayElement)
+ {
+ sb.Append(')');
+ }
+ }
+ else if (type.__IsMissing || (compat != CompatLevel.None && typerefs.Contains(type)))
+ {
+ // ildasm actually tries to load the assembly, but we can't do that, so we cheat by having
+ // a list of 'known' enum types
+ if (type.Assembly.GetName().Name == "mscorlib")
+ {
+ switch (type.FullName)
+ {
+ case "System.AttributeTargets":
+ case "System.Runtime.ConstrainedExecution.Consistency":
+ case "System.Runtime.ConstrainedExecution.Cer":
+ case "System.Security.Permissions.SecurityAction":
+ case "System.Security.Permissions.SecurityPermissionFlag":
+ case "System.Runtime.Versioning.ResourceScope":
+ case "System.Runtime.InteropServices.CallingConvention":
+ case "System.Runtime.InteropServices.CharSet":
+ ReadFixedArg(sb, br, typeofSystemInt32);
+ return;
+ case "System.Security.SecurityRuleSet":
+ if (compat != CompatLevel.V20)
+ {
+ ReadFixedArg(sb, br, typeofSystemByte);
+ return;
+ }
+ break;
+ case "System.Diagnostics.Tracing.EventLevel":
+ case "System.Diagnostics.Tracing.EventTask":
+ case "System.Diagnostics.Tracing.EventOpcode":
+ if (compat != CompatLevel.V20 && compat != CompatLevel.V40)
+ {
+ ReadFixedArg(sb, br, typeofSystemInt32);
+ return;
+ }
+ break;
+ case "System.Type":
+ sb.Append("type(");
+ string typeName;
+ AppendTypeName(sb, ReadType(br, out typeName), typeName);
+ sb.Append(")");
+ return;
+ }
+ }
+ switch (br.Length)
+ {
+ case 1:
+ if (compat != CompatLevel.None)
+ {
+ // ildasm uses bool (???) as the underlying type in this case
+ sb.AppendFormat("bool({0})", br.ReadByte() == 0 ? "false" : "true");
+ }
+ else
+ {
+ // just guess that the enum has int8 as the underlying type
+ sb.AppendFormat("int8({0})", br.ReadSByte());
+ }
+ break;
+ case 2:
+ // just guess that the enum has int16 as the underlying type
+ sb.AppendFormat("int16({0})", br.ReadInt16());
+ break;
+ case 4:
+ // just guess that the enum has int32 as the underlying type
+ sb.AppendFormat("int32({0})", br.ReadInt32());
+ break;
+ case 8:
+ // just guess that the enum has int64 as the underlying type
+ sb.AppendFormat("int64({0})", br.ReadInt64());
+ break;
+ default:
+ throw new IKVM.Reflection.BadImageFormatException();
+ }
+ }
+ else if (type.IsEnum)
+ {
+ ReadFixedArg(sb, br, type.GetEnumUnderlyingType(), arrayElement);
+ }
+ else
+ {
+ throw new NotImplementedException(type.FullName);
+ }
+ }
+
+ static bool IsNestedTypeWithNamespace(Type type)
+ {
+ if (!type.IsNested)
+ {
+ return false;
+ }
+ if (type.IsConstructedGenericType)
+ {
+ type = type.GetGenericTypeDefinition();
+ }
+ return type.__Namespace != null;
+ }
+
+ void AppendCATypeName(StringBuilder sb, Type type, string typeName, bool securityCompatHack = false)
+ {
+ if (type.IsArray)
+ {
+ AppendCATypeName(sb, type.GetElementType(), null);
+ sb.Append("[]");
+ }
+ else if (type == typeofSystemBoolean)
+ {
+ sb.Append("bool");
+ }
+ else if (type == typeofSystemSByte)
+ {
+ sb.Append("int8");
+ }
+ else if (type == typeofSystemByte)
+ {
+ sb.Append("uint8");
+ }
+ else if (type == typeofSystemChar)
+ {
+ sb.Append("char");
+ }
+ else if (type == typeofSystemInt16)
+ {
+ sb.Append("int16");
+ }
+ else if (type == typeofSystemUInt16)
+ {
+ sb.Append("uint16");
+ }
+ else if (type == typeofSystemInt32)
+ {
+ sb.Append("int32");
+ }
+ else if (type == typeofSystemUInt32)
+ {
+ sb.Append("uint32");
+ }
+ else if (type == typeofSystemInt64)
+ {
+ sb.Append("int64");
+ }
+ else if (type == typeofSystemUInt64)
+ {
+ sb.Append("uint64");
+ }
+ else if (type == typeofSystemSingle)
+ {
+ sb.Append("float32");
+ }
+ else if (type == typeofSystemDouble)
+ {
+ sb.Append("float64");
+ }
+ else if (type == typeofSystemString)
+ {
+ sb.Append("string");
+ }
+ else if (type == typeofSystemObject)
+ {
+ sb.Append("object");
+ }
+ else if (type.FullName == "System.Type" && type.Assembly.GetName().Name == "mscorlib")
+ {
+ sb.Append("type");
+ }
+ else
+ {
+ sb.Append("enum ");
+ AppendTypeName(sb, type, typeName, false, securityCompatHack);
+ }
+ }
+
+ Type ReadFieldOrPropType(StringBuilder sb, ByteReader br, out string typeName)
+ {
+ const byte ELEMENT_TYPE_BOOLEAN = 0x02;
+ const byte ELEMENT_TYPE_CHAR = 0x03;
+ const byte ELEMENT_TYPE_I1 = 0x04;
+ const byte ELEMENT_TYPE_U1 = 0x05;
+ const byte ELEMENT_TYPE_I2 = 0x06;
+ const byte ELEMENT_TYPE_U2 = 0x07;
+ const byte ELEMENT_TYPE_I4 = 0x08;
+ const byte ELEMENT_TYPE_U4 = 0x09;
+ const byte ELEMENT_TYPE_I8 = 0x0a;
+ const byte ELEMENT_TYPE_U8 = 0x0b;
+ const byte ELEMENT_TYPE_R4 = 0x0c;
+ const byte ELEMENT_TYPE_R8 = 0x0d;
+ const byte ELEMENT_TYPE_STRING = 0x0e;
+ const byte ELEMENT_TYPE_SZARRAY = 0x1d;
+
+ typeName = null;
+
+ switch (br.ReadByte())
+ {
+ case ELEMENT_TYPE_BOOLEAN:
+ return typeofSystemBoolean;
+ case ELEMENT_TYPE_CHAR:
+ return typeofSystemChar;
+ case ELEMENT_TYPE_I1:
+ return typeofSystemSByte;
+ case ELEMENT_TYPE_U1:
+ return typeofSystemByte;
+ case ELEMENT_TYPE_I2:
+ return typeofSystemInt16;
+ case ELEMENT_TYPE_U2:
+ return typeofSystemUInt16;
+ case ELEMENT_TYPE_I4:
+ return typeofSystemInt32;
+ case ELEMENT_TYPE_U4:
+ return typeofSystemUInt32;
+ case ELEMENT_TYPE_I8:
+ return typeofSystemInt64;
+ case ELEMENT_TYPE_U8:
+ return typeofSystemUInt64;
+ case ELEMENT_TYPE_R4:
+ return typeofSystemSingle;
+ case ELEMENT_TYPE_R8:
+ return typeofSystemDouble;
+ case ELEMENT_TYPE_STRING:
+ return typeofSystemString;
+ case ELEMENT_TYPE_SZARRAY:
+ return ReadFieldOrPropType(sb, br, out typeName).MakeArrayType();
+ case 0x55:
+ return ReadType(br, out typeName);
+ case 0x50:
+ return typeofSystemType;
+ case 0x51:
+ return typeofSystemObject;
+ default:
+ throw new IKVM.Reflection.BadImageFormatException();
+ }
+ }
+
+ Type ReadType(ByteReader br, out string typeName)
+ {
+ typeName = br.ReadString();
+ if (typeName == null)
+ {
+ return null;
+ }
+ if (typeName.Length > 0 && typeName[typeName.Length - 1] == 0)
+ {
+ // there are broken compilers that emit an extra NUL character after the type name
+ typeName = typeName.Substring(0, typeName.Length - 1);
+ }
+ var type = universe.ResolveType(assembly, typeName);
+ if (type != null && type.Assembly == mscorlib)
+ {
+ // we don't want that!
+ type = universe.ResolveType(assembly, type.FullName + ", mscorlib, Version=0.0.0.0");
+ }
+ return type;
+ }
+ }
+}
diff --git a/Disassembler.cs b/Disassembler.cs
new file mode 100644
index 0000000..6cf9a21
--- /dev/null
+++ b/Disassembler.cs
@@ -0,0 +1,2979 @@
+/*
+ Copyright (C) 2013 Jeroen Frijters
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ Jeroen Frijters
+ jeroen@frijters.net
+
+*/
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using IKVM.Reflection;
+using Type = IKVM.Reflection.Type;
+
+namespace Ildasm
+{
+ enum CompatLevel
+ {
+ None,
+ V20,
+ V40,
+ V45,
+ }
+
+ sealed partial class Disassembler
+ {
+ const int IMAGE_SCN_CNT_CODE = 0x00000020;
+ const int IMAGE_SCN_CNT_INITIALIZED_DATA = 0x00000040;
+ const int IMAGE_SCN_CNT_UNINITIALIZED_DATA = 0x00000080;
+ const int IMAGE_SCN_MEM_READ = 0x40000000;
+ const int IMAGE_SCN_MEM_WRITE = unchecked((int)0x80000000);
+ const int COMIMAGE_FLAGS_ILONLY = 0x00000001;
+ const int COMIMAGE_FLAGS_32BITREQUIRED = 0x00000002;
+ const int COMIMAGE_FLAGS_IL_LIBRARY = 0x00000004;
+ const int COMIMAGE_FLAGS_STRONGNAMESIGNED = 0x00000008;
+ const int COMIMAGE_FLAGS_NATIVE_ENTRYPOINT = 0x00000010;
+ const int COMIMAGE_FLAGS_32BITPREFERRED = 0x00020000;
+ readonly Universe universe = new Universe(UniverseOptions.EnableFunctionPointers | UniverseOptions.ResolveMissingMembers | UniverseOptions.DisablePseudoCustomAttributeRetrieval);
+ readonly Assembly mscorlib;
+ readonly Type typeofSystemBoolean;
+ readonly Type typeofSystemSByte;
+ readonly Type typeofSystemByte;
+ readonly Type typeofSystemChar;
+ readonly Type typeofSystemInt16;
+ readonly Type typeofSystemUInt16;
+ readonly Type typeofSystemInt32;
+ readonly Type typeofSystemUInt32;
+ readonly Type typeofSystemInt64;
+ readonly Type typeofSystemUInt64;
+ readonly Type typeofSystemSingle;
+ readonly Type typeofSystemDouble;
+ readonly Type typeofSystemVoid;
+ readonly Type typeofSystemIntPtr;
+ readonly Type typeofSystemUIntPtr;
+ readonly Type typeofSystemTypedReference;
+ readonly Type typeofSystemObject;
+ readonly Type typeofSystemString;
+ readonly Type typeofSystemType;
+ readonly Assembly assembly;
+ readonly Module module;
+ readonly Dictionary<Assembly, string> referencedAssemblies = new Dictionary<Assembly, string>();
+ readonly Assembly[] resolvedAssemblies;
+ readonly HashSet<Type> typerefs;
+ readonly List<FieldInfo> dataFields = new List<FieldInfo>();
+ readonly Dictionary<int, List<ExportedMethod>> exportedMethods;
+ readonly string[] methodNames;
+ readonly string[] fieldNames;
+ readonly CompatLevel compat;
+ readonly string outputFile;
+ readonly bool diffMode;
+
+ internal Disassembler(string inputFile, string outputFile, CompatLevel compat, bool diffMode)
+ {
+ this.outputFile = outputFile;
+ this.compat = compat;
+ this.diffMode = diffMode;
+ universe.AssemblyResolve += new IKVM.Reflection.ResolveEventHandler(universe_AssemblyResolve);
+ mscorlib = universe.Import(typeof(object)).Assembly;
+ typeofSystemBoolean = universe.Import(typeof(bool));
+ typeofSystemSByte = universe.Import(typeof(sbyte));
+ typeofSystemByte = universe.Import(typeof(byte));
+ typeofSystemChar = universe.Import(typeof(char));
+ typeofSystemInt16 = universe.Import(typeof(short));
+ typeofSystemUInt16 = universe.Import(typeof(ushort));
+ typeofSystemInt32 = universe.Import(typeof(int));
+ typeofSystemUInt32 = universe.Import(typeof(uint));
+ typeofSystemInt64 = universe.Import(typeof(long));
+ typeofSystemUInt64 = universe.Import(typeof(ulong));
+ typeofSystemSingle = universe.Import(typeof(float));
+ typeofSystemDouble = universe.Import(typeof(double));
+ typeofSystemVoid = universe.Import(typeof(void));
+ typeofSystemIntPtr = universe.Import(typeof(IntPtr));
+ typeofSystemUIntPtr = universe.Import(typeof(UIntPtr));
+ typeofSystemTypedReference = universe.Import(typeof(TypedReference));
+ typeofSystemObject = universe.Import(typeof(object));
+ typeofSystemString = universe.Import(typeof(string));
+ typeofSystemType = universe.Import(typeof(System.Type));
+ // HACK we specify a bogus location to prevent IKVM.Reflection from loading external modules
+ // TODO IKVM.Reflection really should have a way to avoid it trying to load external modules (e.g. a UniverseOption to always use the ModuleResolve event)
+ var raw = universe.OpenRawModule(System.IO.File.OpenRead(inputFile), System.IO.Path.GetTempPath() + "/Dummy");
+ if (raw.IsManifestModule)
+ {
+ assembly = universe.LoadAssembly(raw);
+ module = assembly.ManifestModule;
+ }
+ else
+ {
+ var ab = universe.DefineDynamicAssembly(new AssemblyName("<ModuleContainer>"), IKVM.Reflection.Emit.AssemblyBuilderAccess.ReflectionOnly);
+ assembly = ab;
+ module = ab.__AddModule(raw);
+ }
+ exportedMethods = GetExportedMethods(module);
+
+ var names = new HashSet<string>();
+ AssemblyName[] assemblyRefs = module.__GetReferencedAssemblies();
+ resolvedAssemblies = new Assembly[assemblyRefs.Length];
+ for (int i = 0; i < resolvedAssemblies.Length; i++)
+ {
+ string name = assemblyRefs[i].Name;
+ while (names.Contains(name))
+ {
+ name = name + "_" + i;
+ }
+ names.Add(name);
+ resolvedAssemblies[i] = universe.CreateMissingAssembly(assemblyRefs[i].FullName);
+ referencedAssemblies.Add(resolvedAssemblies[i], name);
+ }
+ module.__ResolveReferencedAssemblies(resolvedAssemblies);
+ typerefs = new HashSet<Type>(module.__GetReferencedTypes());
+ methodNames = GetMethodNames();
+ fieldNames = GetFieldNames();
+ }
+
+ Assembly universe_AssemblyResolve(object sender, IKVM.Reflection.ResolveEventArgs args)
+ {
+ if (resolvedAssemblies != null)
+ {
+ foreach (var asm in resolvedAssemblies)
+ {
+ AssemblyComparisonResult result;
+ if (universe.CompareAssemblyIdentity(args.Name, false, asm.FullName, false, out result))
+ {
+ return asm;
+ }
+ }
+ }
+ return universe.CreateMissingAssembly(args.Name);
+ }
+
+ internal void Save(System.IO.TextWriter writer)
+ {
+ LineWriter lw = new LineWriter(writer);
+ WriteCopyrightHeader(lw);
+ WriteVTableFixupComment(lw);
+ if (!(assembly is IKVM.Reflection.Emit.AssemblyBuilder))
+ {
+ WriteMscorlibDirective(lw);
+ }
+ WriteModuleManifest(lw);
+ if (!(assembly is IKVM.Reflection.Emit.AssemblyBuilder))
+ {
+ WriteAssemblyManifest(lw);
+ }
+ WriteExportedTypes(lw);
+ if (!(assembly is IKVM.Reflection.Emit.AssemblyBuilder))
+ {
+ WriteModules(lw);
+ WriteResources(lw);
+ }
+ WriteModuleHeader(lw);
+ WriteVTableFixups(lw);
+ WriteGlobalFields(lw);
+ WriteGlobalMethods(lw);
+ WriteTypes(lw);
+ WriteUnhandledCustomAttributes(lw);
+ WriteData(lw);
+ lw.WriteLine("// *********** DISASSEMBLY COMPLETE ***********************");
+ WriteNativeResources(lw);
+ }
+
+ string[] GetMethodNames()
+ {
+ var methods = new HashSet<MethodBase>(new MethodSignatureComparer());
+ var names = new List<string>();
+ try
+ {
+ for (int i = 0x06000001; i <= 0x06FFFFFF; i++)
+ {
+ string name;
+ var method = module.ResolveMethod(i);
+ if (methods.Contains(method))
+ {
+ name = String.Format("$MD${0:X}", i - 0x06000000);
+ }
+ else
+ {
+ name = method.Name;
+ methods.Add(method);
+ }
+ if ((method.Attributes & MethodAttributes.MemberAccessMask) == MethodAttributes.PrivateScope)
+ {
+ names.Add(String.Format("{0}$PST{1:X8}", name, method.MetadataToken));
+ }
+ else
+ {
+ names.Add(name);
+ }
+ }
+ }
+ catch (ArgumentOutOfRangeException) { }
+ return names.ToArray();
+ }
+
+ sealed class MethodSignatureComparer : IEqualityComparer<MethodBase>
+ {
+ public bool Equals(MethodBase x, MethodBase y)
+ {
+ return x.DeclaringType == y.DeclaringType
+ && x.Name == y.Name
+ && x.CallingConvention == y.CallingConvention
+ && Equals(GetReturnParameter(x), GetReturnParameter(y))
+ && Equals(x.GetParameters(), y.GetParameters())
+ && x.IsGenericMethodDefinition == y.IsGenericMethodDefinition
+ && (!x.IsGenericMethodDefinition || x.GetGenericArguments().Length == y.GetGenericArguments().Length)
+ ;
+ }
+
+ static bool Equals(ParameterInfo p1, ParameterInfo p2)
+ {
+ return p1.ParameterType == p2.ParameterType
+ && p1.__GetCustomModifiers().Equals(p2.__GetCustomModifiers());
+ }
+
+ static bool Equals(ParameterInfo[] p1, ParameterInfo[] p2)
+ {
+ if (p1.Length != p2.Length)
+ {
+ return false;
+ }
+ for (int i = 0; i < p1.Length; i++)
+ {
+ if (!Equals(p1[i], p2[i]))
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ static ParameterInfo GetReturnParameter(MethodBase mb)
+ {
+ ConstructorInfo ci = mb as ConstructorInfo;
+ return ci != null ? ci.__ReturnParameter : ((MethodInfo)mb).ReturnParameter;
+ }
+
+ public int GetHashCode(MethodBase mb)
+ {
+ Type decl = mb.DeclaringType;
+ return mb.Name.GetHashCode() ^ (decl == null ? 0 : decl.GetHashCode());
+ }
+ }
+
+ string[] GetFieldNames()
+ {
+ var fields = new HashSet<FieldInfo>(new FieldSignatureComparer());
+ var names = new List<string>();
+ try
+ {
+ for (int i = 0x04000001; i <= 0x04FFFFFF; i++)
+ {
+ string name;
+ var field = module.ResolveField(i);
+ if (fields.Contains(field))
+ {
+ name = String.Format("$FD${0:X}", i - 0x04000000);
+ }
+ else
+ {
+ name = field.Name;
+ fields.Add(field);
+ }
+ if ((field.Attributes & FieldAttributes.FieldAccessMask) == FieldAttributes.PrivateScope)
+ {
+ names.Add(String.Format("{0}$PST{1:X8}", name, field.MetadataToken));
+ }
+ else
+ {
+ names.Add(name);
+ }
+ }
+ }
+ catch (ArgumentOutOfRangeException) { }
+ return names.ToArray();
+ }
+
+ sealed class FieldSignatureComparer : IEqualityComparer<FieldInfo>
+ {
+ public bool Equals(FieldInfo x, FieldInfo y)
+ {
+ return x.DeclaringType == y.DeclaringType
+ && x.Name == y.Name
+ && x.FieldType == y.FieldType
+ && x.__GetCustomModifiers().Equals(y.__GetCustomModifiers());
+ }
+
+ public int GetHashCode(FieldInfo field)
+ {
+ Type decl = field.DeclaringType;
+ return field.Name.GetHashCode() ^ (decl == null ? 0 : decl.GetHashCode());
+ }
+ }
+
+ void WriteExportedTypes(LineWriter lw)
+ {
+ Type[] exported = module.__GetExportedTypes();
+ for (int i = 0; i < exported.Length; i++)
+ {
+ lw.Write(".class extern ");
+ if (!exported[i].IsNested)
+ {
+ lw.Write("forwarder ");
+ }
+ WriteTypeNameNoOuter(lw, exported[i]);
+ lw.WriteLine();
+ lw.WriteLine("{");
+ if (exported[i].IsNested)
+ {
+ lw.Write(" .class extern ");
+ WriteTypeName(lw, exported[i].DeclaringType);
+ lw.WriteLine();
+ }
+ else
+ {
+ lw.WriteLine(" .assembly extern {0}", QuoteIdentifier(referencedAssemblies[exported[i].Assembly]));
+ }
+ if (exported[i].MetadataToken != 0)
+ {
+ lw.WriteLine(" .class 0x{0:X8}", exported[i].MetadataToken);
+ }
+ lw.WriteLine("}");
+ }
+ }
+
+ void WriteGlobalMethods(LineWriter lw)
+ {
+ MethodInfo[] methods = module.GetMethods(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static);
+ ConstructorInfo cctor = module.__ModuleInitializer;
+ if (methods.Length != 0 || cctor != null)
+ {
+ lw.WriteLine();
+ lw.WriteLine("// ================== GLOBAL METHODS =========================");
+ lw.WriteLine();
+ foreach (var method in methods)
+ {
+ if (cctor != null && method.MetadataToken > cctor.MetadataToken)
+ {
+ WriteMethod(lw, cctor);
+ cctor = null;
+ }
+ WriteMethod(lw, method);
+ }
+ if (cctor != null)
+ {
+ WriteMethod(lw, cctor);
+ }
+ lw.WriteLine();
+ lw.WriteLine("// =============================================================");
+ lw.WriteLine();
+ }
+ }
+
+ void WriteUnhandledCustomAttributes(LineWriter lw)
+ {
+ foreach (var ca in module.__EnumerateCustomAttributeTable())
+ {
+ int parent = ca.__Parent;
+ switch (parent >> 24)
+ {
+ case 0x00: // Module
+ case 0x02: // TypeDef
+ case 0x04: // Field
+ case 0x06: // MethodDef
+ case 0x08: // Param
+ case 0x14: // Event
+ case 0x17: // Property
+ case 0x20: // Assembly
+ case 0x2a: // GenericParam
+ break;
+ case 0x01: // TypeRef
+ lw.Write(".custom (");
+ int level = lw.Column - 1;
+ WriteTypeDefOrRef(lw, module.ResolveType(parent));
+ lw.Write(") ");
+ WriteCustomAttributeImpl(lw, ca, false, level);
+ break;
+ default:
+ if (compat == CompatLevel.V20 || compat == CompatLevel.V40 || (parent >> 24) != 0x09)
+ {
+ lw.Write(".custom (UNKNOWN_OWNER) ");
+ WriteCustomAttributeImpl(lw, ca, false, lw.Column - 16);
+ }
+ break;
+ }
+ }
+ }
+
+ void WriteGlobalFields(LineWriter lw)
+ {
+ FieldInfo[] fields = module.GetFields(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static);
+ if (fields.Length != 0)
+ {
+ lw.WriteLine();
+ lw.WriteLine();
+ lw.WriteLine("// ================== GLOBAL FIELDS ==========================");
+ lw.WriteLine();
+ foreach (var field in fields)
+ {
+ WriteField(lw, field);
+ }
+ lw.WriteLine();
+ lw.WriteLine("// =============================================================");
+ }
+ lw.WriteLine();
+ }
+
+ void WriteModules(LineWriter lw)
+ {
+ foreach (var module in assembly.GetModules(true))
+ {
+ if (module != this.module)
+ {
+ lw.WriteLine(module.IsResource() ? ".file nometadata {0}" : ".file {0}", QuoteIdentifier(module.Name));
+ byte[] hash = module.__ModuleHash;
+ if (hash != null)
+ {
+ lw.Write(" .hash = (");
+ WriteBytes(lw, hash, false);
+ lw.WriteLine();
+ }
+ }
+ }
+ }
+
+ void WriteMscorlibDirective(LineWriter lw)
+ {
+ Type obj = assembly.GetType("System.Object");
+ if (obj != null && !obj.__IsMissing && obj.BaseType == null && obj.IsClass)
+ {
+ lw.WriteLine();
+ lw.WriteLine(".mscorlib ");
+ lw.WriteLine();
+ }
+ }
+
+ int GetPointerSize()
+ {
+ PortableExecutableKinds peKind;
+ ImageFileMachine machine;
+ module.GetPEKind(out peKind, out machine);
+ if ((peKind & PortableExecutableKinds.PE32Plus) != 0)
+ {
+ return 8;
+ }
+ else
+ {
+ return 4;
+ }
+ }
+
+ int GetTypeSize(Type type)
+ {
+ int packingSize;
+ int typeSize;
+ if (!type.__IsMissing && type.IsEnum)
+ {
+ type = type.GetEnumUnderlyingType();
+ }
+ if (type.__IsFunctionPointer || type.IsPointer || type == typeofSystemIntPtr || type == typeofSystemUIntPtr)
+ {
+ typeSize = GetPointerSize();
+ }
+ else if (!type.__GetLayout(out packingSize, out typeSize))
+ {
+ if (type == typeofSystemSByte
+ || type == typeofSystemByte
+ || type == typeofSystemBoolean)
+ {
+ typeSize = 1;
+ }
+ else if (type == typeofSystemInt16
+ || type == typeofSystemUInt16
+ || type == typeofSystemChar)
+ {
+ typeSize = 2;
+ }
+ else if (type == typeofSystemInt32
+ || type == typeofSystemUInt32
+ || type == typeofSystemSingle)
+ {
+ typeSize = 4;
+ }
+ else if (type == typeofSystemInt64
+ || type == typeofSystemUInt64
+ || type == typeofSystemDouble)
+ {
+ typeSize = 8;
+ }
+ }
+ return typeSize;
+ }
+
+ struct DataPointer : IComparable<DataPointer>
+ {
+ internal readonly int RVA;
+ internal readonly int Size;
+
+ internal DataPointer(int rva, int size)
+ {
+ this.RVA = rva;
+ this.Size = size;
+ }
+
+ public int CompareTo(DataPointer other)
+ {
+ return RVA.CompareTo(other.RVA);
+ }
+ }
+
+ void WriteData(LineWriter lw)
+ {
+ List<DataPointer> ptrs = new List<DataPointer>();
+ foreach (VTableFixups fixup in GetVTableFixups())
+ {
+ ptrs.Add(new DataPointer(fixup.RVA, fixup.Count * ((fixup.Type & COR_VTABLE_32BIT) != 0 ? 4 : 8)));
+ }
+ foreach (FieldInfo field in dataFields)
+ {
+ ptrs.Add(new DataPointer(field.__FieldRVA, GetTypeSize(field.FieldType)));
+ }
+ ptrs.Sort();
+ for (int i = 0; i < ptrs.Count - 1; i++)
+ {
+ if (ptrs[i].RVA == ptrs[i + 1].RVA)
+ {
+ ptrs.RemoveAt(i + 1);
+ i--;
+ }
+ }
+ for (int i = 0; i < ptrs.Count; i++)
+ {
+ int rva = ptrs[i].RVA;
+ string name;
+ int characteristics;
+ int virtualAddress;
+ int virtualSize;
+ int pointerToRawData;
+ int sizeOfRawData;
+ if (!module.__GetSectionInfo(rva, out name, out characteristics, out virtualAddress, out virtualSize, out pointerToRawData, out sizeOfRawData))
+ {
+ continue;
+ }
+ int alignment = 0;
+ int size = ptrs[i].Size;
+ if (rva + size >= virtualAddress + virtualSize)
+ {
+ size = virtualAddress + virtualSize - rva;
+ }
+ else if (i == ptrs.Count - 1)
+ {
+ // we're at the last pointer
+ }
+ else if (rva + size >= ptrs[i + 1].RVA)
+ {
+ size = ptrs[i + 1].RVA - rva;
+ }
+ else if (rva + size < virtualAddress + sizeOfRawData)
+ {
+ int next = ptrs[i + 1].RVA;
+ int align = (next & (~next + 1)) - 1;
+ alignment = ((rva + size + align) & ~align) - (rva + size);
+ }
+ WriteData(lw, name, rva, size, rva >= virtualAddress + sizeOfRawData);
+ if (alignment != 0)
+ {
+ WriteData(lw, name, rva + size, alignment, true);
+ }
+ }
+ }
+
+ void WriteData(LineWriter lw, string section, int rva, int size, bool uninitialized)
+ {
+ lw.Write(".data ");
+ switch (section)
+ {
+ case ".text":
+ lw.Write("cil I_");
+ break;
+ case ".tls":
+ lw.Write("tls T_");
+ break;
+ default:
+ lw.Write("D_");
+ break;
+ }
+ if (diffMode)
+ {
+ lw.Write("xxxxxxxx = ");
+ }
+ else
+ {
+ lw.Write("{0:X8} = ", rva);
+ }
+ if (uninitialized)
+ {
+ lw.WriteLine("int8[{0}]", size);
+ }
+ else
+ {
+ lw.WriteLine("bytearray (");
+ lw.GoToColumn(17);
+ byte[] buf = new byte[size];
+ module.__ReadDataFromRVA(rva, buf, 0, buf.Length);
+ WriteBytes(lw, buf, true);
+ lw.WriteLine();
+ }
+ }
+
+ void WriteNativeResources(LineWriter lw)
+ {
+ int rva;
+ int length;
+ module.__GetDataDirectoryEntry(2, out rva, out length);
+ if (rva != 0 && outputFile != null && !diffMode)
+ {
+ lw.WriteLine("// WARNING: Created Win32 resource file {0}", System.IO.Path.ChangeExtension(outputFile, "res"));
+ }
+ }
+
+ void WriteCopyrightHeader(LineWriter lw)
+ {
+ if (compat == CompatLevel.V20)
+ {
+ lw.WriteLine();
+ lw.WriteLine("// Microsoft (R) .NET Framework IL Disassembler. Version 2.0.50727.42");
+ lw.WriteLine("// Copyright (c) Microsoft Corporation. All rights reserved.");
+ lw.WriteLine();
+ lw.WriteLine();
+ }
+ else if (compat == CompatLevel.V40)
+ {
+ lw.WriteLine();
+ lw.WriteLine("// Microsoft (R) .NET Framework IL Disassembler. Version 4.0.30319.1");
+ lw.WriteLine("// Copyright (c) Microsoft Corporation. All rights reserved.");
+ lw.WriteLine();
+ lw.WriteLine();
+ }
+ else if (compat == CompatLevel.V45)
+ {
+ lw.WriteLine();
+ lw.WriteLine("// Microsoft (R) .NET Framework IL Disassembler. Version 4.0.30319.17929");
+ lw.WriteLine("// Copyright (c) Microsoft Corporation. All rights reserved.");
+ lw.WriteLine();
+ lw.WriteLine();
+ }
+ }
+
+ void WriteTypes(LineWriter lw)
+ {
+ Type[] types = module.GetTypes();
+ if (types.Length != 0)
+ {
+ lw.WriteLine();
+ lw.WriteLine("// =============== CLASS MEMBERS DECLARATION ===================");
+ lw.WriteLine();
+ foreach (var type in types)
+ {
+ if (!type.IsNested)
+ {
+ WriteType(lw, type);
+ }
+ }
+ lw.WriteLine();
+ lw.WriteLine("// =============================================================");
+ lw.WriteLine();
+ }
+ }
+
+ void WriteType(LineWriter lw, IKVM.Reflection.Type type)
+ {
+ int level = lw.Column;
+ lw.Write(".class ");
+ if (type.IsInterface)
+ {
+ lw.Write("interface ");
+ }
+ if (type.IsPublic)
+ {
+ lw.Write("public ");
+ }
+ else if (!type.IsNested)
+ {
+ lw.Write("private ");
+ }
+ if (type.IsAbstract)
+ {
+ lw.Write("abstract ");
+ }
+ switch (type.StructLayoutAttribute.Value)
+ {
+ case System.Runtime.InteropServices.LayoutKind.Auto:
+ lw.Write("auto ");
+ break;
+ case System.Runtime.InteropServices.LayoutKind.Sequential:
+ lw.Write("sequential ");
+ break;
+ case System.Runtime.InteropServices.LayoutKind.Explicit:
+ lw.Write("explicit ");
+ break;
+ }
+ switch (type.Attributes & TypeAttributes.StringFormatMask)
+ {
+ case TypeAttributes.AnsiClass:
+ lw.Write("ansi ");
+ break;
+ case TypeAttributes.UnicodeClass:
+ lw.Write("unicode ");
+ break;
+ case TypeAttributes.AutoClass:
+ lw.Write("autochar ");
+ break;
+ }
+ if ((type.Attributes & TypeAttributes.Import) != 0)
+ {
+ lw.Write("import ");
+ }
+ if ((type.Attributes & TypeAttributes.Serializable) != 0)
+ {
+ lw.Write("serializable ");
+ }
+ if ((type.Attributes & TypeAttributes.WindowsRuntime) != 0 && (compat == CompatLevel.None || compat >= CompatLevel.V45))
+ {
+ lw.Write("windowsruntime ");
+ }
+ if (type.IsSealed)
+ {
+ lw.Write("sealed ");
+ }
+ switch (type.Attributes & TypeAttributes.VisibilityMask)
+ {
+ case TypeAttributes.NestedPublic:
+ lw.Write("nested public ");
+ break;
+ case TypeAttributes.NestedPrivate:
+ lw.Write("nested private ");
+ break;
+ case TypeAttributes.NestedAssembly:
+ lw.Write("nested assembly ");
+ break;
+ case TypeAttributes.NestedFamily:
+ lw.Write("nested family ");
+ break;
+ case TypeAttributes.NestedFamORAssem:
+ lw.Write("nested famorassem ");
+ break;
+ }
+ if ((type.Attributes & TypeAttributes.BeforeFieldInit) != 0)
+ {
+ lw.Write("beforefieldinit ");
+ }
+ if ((type.Attributes & TypeAttributes.SpecialName) != 0)
+ {
+ lw.Write("specialname ");
+ }
+ WriteTypeNameNoOuter(lw, type);
+ if (type.IsGenericTypeDefinition)
+ {
+ WriteGenericParameterDef(lw, type.GetGenericArguments(), true);
+ }
+ lw.WriteLine();
+ lw.GoToColumn(level);
+ if (type.BaseType != null)
+ {
+ lw.Write(" extends ");
+ if (type.BaseType.__IsMissing || !type.BaseType.IsGenericType)
+ {
+ WriteTypeDefOrRef(lw, type.BaseType);
+ }
+ else
+ {
+ WriteSignatureType(lw, type.BaseType, TypeLocation.General);
+ }
+ lw.WriteLine();
+ lw.GoToColumn(level);
+ }
+ Type[] interfaces = type.__GetDeclaredInterfaces();
+ if (interfaces.Length != 0)
+ {
+ lw.Write(" implements ");
+ bool first = true;
+ foreach (var iface in interfaces)
+ {
+ if (!first)
+ {
+ lw.WriteLine(",");
+ lw.GoToColumn(level + 18);
+ }
+ first = false;
+ if (iface.__IsMissing || !iface.IsGenericType)
+ {
+ WriteTypeDefOrRef(lw, iface);
+ }
+ else
+ {
+ WriteSignatureType(lw, iface, TypeLocation.General);
+ }
+ }
+ lw.WriteLine();
+ lw.GoToColumn(level);
+ }
+ lw.WriteLine("{");
+ int packingSize;
+ int typeSize;
+ if (type.__GetLayout(out packingSize, out typeSize))
+ {
+ lw.GoToColumn(level + 2);
+ lw.WriteLine(".pack {0}", packingSize);
+ lw.GoToColumn(level + 2);
+ lw.WriteLine(".size {0}", typeSize);
+ }
+ WriteCustomAttributes(lw, level + 2, type.__GetCustomAttributes(null, false));
+ WriteDeclarativeSecurity(lw, level + 2, CustomAttributeData.__GetDeclarativeSecurity(type), type.MetadataToken);
+ WriteGenericParameterCustomAttributes(lw, level + 2, type.GetGenericArguments());
+ if (compat == CompatLevel.None || compat >= CompatLevel.V45)
+ {
+ foreach (var iface in type.__GetDeclaredInterfaces())
+ {
+ var cas = CustomAttributeData.__GetCustomAttributes(type, iface, null, false);
+ if (cas.Count != 0)
+ {
+ lw.GoToColumn(level + 2);
+ lw.Write(".interfaceimpl type ");
+ WriteTypeDefOrRef(lw, iface);
+ lw.WriteLine();
+ WriteCustomAttributes(lw, level + 2, cas);
+ }
+ }
+ }
+ foreach (var nested in type.__GetDeclaredTypes())
+ {
+ lw.GoToColumn(level + 2);
+ WriteType(lw, nested);
+ }
+ IEnumerable<FieldInfo> fields = type.__GetDeclaredFields();
+ if (diffMode)
+ {
+ fields = fields.OrderBy(x => x.Name);
+ }
+ foreach (var field in fields)
+ {
+ lw.GoToColumn(level + 2);
+ WriteField(lw, field);
+ }
+ foreach (var method in type.__GetDeclaredMethods())
+ {
+ lw.GoToColumn(level + 2);
+ WriteMethod(lw, method);
+ }
+ foreach (var evt in type.__GetDeclaredEvents())
+ {
+ lw.GoToColumn(level + 2);
+ WriteEvent(lw, evt);
+ }
+ foreach (var prop in type.__GetDeclaredProperties())
+ {
+ lw.GoToColumn(level + 2);
+ WriteProperty(lw, prop);
+ }
+ lw.GoToColumn(level);
+ lw.Write("} // end of class ");
+ WriteTypeNameNoOuter(lw, type);
+ lw.WriteLine();
+ lw.WriteLine();
+ }
+
+ void WriteGenericParameterCustomAttributes(LineWriter lw, int level, Type[] args)
+ {
+ foreach (var typeParam in args)
+ {
+ IList<CustomAttributeData> cas = CustomAttributeData.__GetCustomAttributes(typeParam, null, false);
+ if (cas.Count != 0)
+ {
+ lw.GoToColumn(level);
+ lw.WriteLine(".param type {0} ", QuoteIdentifier(typeParam.Name));
+ WriteCustomAttributes(lw, level, cas);
+ }
+ }
+ }
+
+ void WriteGenericParameterDef(LineWriter lw, Type[] parameters, bool wrap)
+ {
+ lw.Write("<");
+ int level = lw.Column;
+ string sep = "";
+ for (int i = 0; i < parameters.Length; i++)
+ {
+ Type par = parameters[i];
+ lw.Write(sep);
+ if (wrap && i != 0 && i % 4 == 0)
+ {
+ lw.WriteLine();
+ lw.GoToColumn(level);
+ }
+ if ((par.GenericParameterAttributes & GenericParameterAttributes.Contravariant) != 0)
+ {
+ lw.Write("- ");
+ }
+ if ((par.GenericParameterAttributes & GenericParameterAttributes.Covariant) != 0)
+ {
+ lw.Write("+ ");
+ }
+ if ((par.GenericParameterAttributes & GenericParameterAttributes.ReferenceTypeConstraint) != 0)
+ {
+ lw.Write("class ");
+ }
+ if ((par.GenericParameterAttributes & GenericParameterAttributes.NotNullableValueTypeConstraint) != 0)
+ {
+ lw.Write("valuetype ");
+ }
+ if ((par.GenericParameterAttributes & GenericParameterAttributes.DefaultConstructorConstraint) != 0)
+ {
+ lw.Write(".ctor ");
+ }
+ string sep2 = "(";
+ foreach (var constraint in par.GetGenericParameterConstraints())
+ {
+ lw.Write(sep2);
+ sep2 = ", ";
+ if (constraint.__IsMissing || !constraint.IsGenericType)
+ {
+ WriteTypeDefOrRef(lw, constraint);
+ }
+ else
+ {
+ WriteSignatureType(lw, constraint);
+ }
+ }
+ if (sep2 != "(")
+ {
+ lw.Write(") ");
+ }
+ lw.Write("{0}", QuoteIdentifier(par.Name));
+ sep = ",";
+ }
+ lw.Write(">");
+ }
+
+ void WriteEvent(LineWriter lw, EventInfo evt)
+ {
+ int level = lw.Column;
+ lw.Write(".event ");
+ if (evt.IsSpecialName)
+ {
+ lw.Write("specialname ");
+ }
+ if (!evt.EventHandlerType.__IsMissing && evt.EventHandlerType.IsGenericType && !evt.EventHandlerType.IsGenericTypeDefinition)
+ {
+ WriteSignatureType(lw, evt.EventHandlerType, TypeLocation.General);
+ }
+ else
+ {
+ WriteTypeDefOrRef(lw, evt.EventHandlerType);
+ }
+ lw.WriteLine(" {0}", QuoteIdentifier(evt.Name));
+ lw.GoToColumn(level);
+ lw.WriteLine("{");
+ WriteCustomAttributes(lw, level + 2, evt.__GetCustomAttributes(null, false));
+ IEnumerable<MethodInfo> accessors = evt.__GetMethods();
+ if (diffMode)
+ {
+ accessors = accessors.OrderBy(x => x.Name);
+ }
+ foreach (var acc in accessors)
+ {
+ lw.GoToColumn(level + 2);
+ if (acc == evt.GetAddMethod(true))
+ {
+ lw.Write(".addon ");
+ }
+ else if (acc == evt.GetRemoveMethod(true))
+ {
+ lw.Write(".removeon ");
+ }
+ else if (acc == evt.GetRaiseMethod(true))
+ {
+ lw.Write(".fire ");
+ }
+ else
+ {
+ lw.Write(".other ");
+ }
+ WriteCallingConvention(lw, acc.CallingConvention);
+ WriteSignatureType(lw, acc.ReturnType);
+ lw.Write(" ");
+ WriteTypeDefOrRef(lw, acc.DeclaringType);
+ lw.Write("::{0}(", QuoteIdentifier(GetMethodName(acc)));
+ WriteParameters(lw, acc.GetParameters());
+ lw.WriteLine(")");
+ }
+ lw.GoToColumn(level);
+ lw.WriteLine("}} // end of event {0}::{1}", QuoteIdentifier(evt.DeclaringType.__Name), QuoteIdentifier(evt.Name));
+ }
+
+ void WriteProperty(LineWriter lw, PropertyInfo prop)
+ {
+ int level = lw.Column;
+ lw.Write(".property ");
+ if ((prop.Attributes & PropertyAttributes.SpecialName) != 0)
+ {
+ lw.Write("specialname ");
+ }
+ if ((prop.Attributes & PropertyAttributes.RTSpecialName) != 0)
+ {
+ lw.Write("rtspecialname ");
+ }
+ if (lw.Column > 40)
+ {
+ lw.WriteLine();
+ lw.GoToColumn(level + 8);
+ }
+ WriteCallingConvention(lw, prop.__CallingConvention);
+ WriteSignatureType(lw, prop.PropertyType);
+ if (lw.Column > 40)
+ {
+ lw.WriteLine();
+ lw.GoToColumn(level + 7);
+ }
+ lw.Write(" {0}(", QuoteIdentifier(prop.Name));
+ WriteParameters(lw, prop.GetIndexParameters());
+ lw.WriteLine(")");
+ lw.GoToColumn(level);
+ lw.WriteLine("{");
+ WriteCustomAttributes(lw, level + 2, prop.__GetCustomAttributes(null, false));
+ IEnumerable<MethodInfo> accessors = prop.GetAccessors(true);
+ if (diffMode)
+ {
+ accessors = accessors.OrderBy(x => x.Name);
+ }
+ foreach (var acc in accessors)
+ {
+ lw.GoToColumn(level + 2);
+ if (acc == prop.GetGetMethod(true))
+ {
+ lw.Write(".get ");
+ }
+ else if (acc == prop.GetSetMethod(true))
+ {
+ lw.Write(".set ");
+ }
+ else
+ {
+ lw.Write(".other ");
+ }
+ WriteCallingConvention(lw, acc.CallingConvention);
+ WriteSignatureType(lw, acc.ReturnType);
+ WriteCustomModifiers(lw, acc.ReturnParameter.__GetCustomModifiers());
+ lw.Write(" ");
+ WriteTypeDefOrRef(lw, acc.DeclaringType);
+ lw.Write("::{0}(", QuoteIdentifier(GetMethodName(acc)));
+ WriteParameters(lw, acc.GetParameters());
+ lw.WriteLine(")");
+ }
+ lw.GoToColumn(level);
+ lw.WriteLine("}} // end of property {0}::{1}", QuoteIdentifier(prop.DeclaringType.Name), QuoteIdentifier(prop.Name));
+ }
+
+ void WriteParameters(LineWriter lw, ParameterInfo[] parameters)
+ {
+ int level = lw.Column;
+ bool first = true;
+ foreach (var parameter in parameters)
+ {
+ if (!first)
+ {
+ lw.WriteLine(",");
+ lw.GoToColumn(level);
+ }
+ first = false;
+ WriteSignatureType(lw, parameter.ParameterType);
+ WriteCustomModifiers(lw, parameter.__GetCustomModifiers());
+ }
+ }
+
+ void WriteMethod(LineWriter lw, MethodBase method)
+ {
+ int level0 = lw.Column;
+ lw.Write(".method ");
+ int level1 = lw.Column;
+ switch (method.Attributes & MethodAttributes.MemberAccessMask)
+ {
+ case MethodAttributes.Public:
+ lw.Write("public ");
+ break;
+ case MethodAttributes.Private:
+ lw.Write("private ");
+ break;
+ case MethodAttributes.Assembly:
+ lw.Write("assembly ");
+ break;
+ case MethodAttributes.Family:
+ lw.Write("family ");
+ break;
+ case MethodAttributes.FamORAssem:
+ lw.Write("famorassem ");
+ break;
+ case MethodAttributes.PrivateScope:
+ lw.Write("privatescope ");
+ break;
+ }
+ if ((method.Attributes & MethodAttributes.HideBySig) != 0)
+ {
+ lw.Write("hidebysig ");
+ }
+ if ((method.Attributes & MethodAttributes.NewSlot) != 0)
+ {
+ lw.Write("newslot ");
+ }
+ if ((method.Attributes & MethodAttributes.SpecialName) != 0)
+ {
+ lw.Write("specialname ");
+ }
+ if ((method.Attributes & MethodAttributes.RTSpecialName) != 0)
+ {
+ lw.Write("rtspecialname ");
+ }
+ if ((method.Attributes & MethodAttributes.Abstract) != 0)
+ {
+ lw.Write("abstract ");
+ }
+ if ((method.Attributes & MethodAttributes.CheckAccessOnOverride) != 0)
+ {
+ lw.Write("strict ");
+ }
+ if ((method.Attributes & MethodAttributes.Virtual) != 0)
+ {
+ lw.Write("virtual ");
+ }
+ if ((method.Attributes & MethodAttributes.Final) != 0)
+ {
+ lw.Write("final ");
+ }
+ if ((method.Attributes & MethodAttributes.Static) != 0)
+ {
+ lw.Write("static ");
+ }
+ if ((method.Attributes & MethodAttributes.RequireSecObject) != 0)
+ {
+ lw.Write("reqsecobj ");
+ }
+ if ((method.Attributes & MethodAttributes.PinvokeImpl) != 0)
+ {
+ WritePInvokeImpl(lw, method);
+ }
+ if (lw.Column > 40)
+ {
+ lw.WriteLine();
+ lw.GoToColumn(level1);
+ }
+ WriteCallingConvention(lw, method.CallingConvention);
+ ParameterInfo returnParameter = method is ConstructorInfo ? ((ConstructorInfo)method).__ReturnParameter : ((MethodInfo)method).ReturnParameter;
+ WriteInOutOpt(lw, returnParameter);
+ WriteSignatureType(lw, returnParameter.ParameterType);
+ WriteCustomModifiers(lw, returnParameter.__GetCustomModifiers());
+ lw.Write(" ");
+ if ((returnParameter.Attributes & ParameterAttributes.HasFieldMarshal) != 0)
+ {
+ var sb = new StringBuilder();
+ FieldMarshal marshal;
+ WriteMarshalAs(sb, level1 - 1, returnParameter.__TryGetFieldMarshal(out marshal), marshal, false);
+ bool wrap = lw.Column + sb.Length > 40;
+ if (wrap)
+ {
+ lw.WriteLine();
+ lw.GoToColumn(level1 - 1);
+ }
+ lw.Write("{0}", sb);
+ if (wrap)
+ {
+ lw.WriteLine();
+ lw.GoToColumn(level1 - 1);
+ }
+ }
+ if (lw.Column > 40)
+ {
+ lw.WriteLine();
+ lw.GoToColumn(level1 - 1);
+ }
+ lw.Write(" {0}", QuoteIdentifier(GetMethodName(method)));
+ if (method.IsGenericMethodDefinition)
+ {
+ WriteGenericParameterDef(lw, method.GetGenericArguments(), false);
+ }
+ lw.Write("(");
+ int level2 = lw.Column;
+ bool first = true;
+ foreach (var parameter in method.GetParameters())
+ {
+ if (!first)
+ {
+ lw.WriteLine(",");
+ lw.GoToColumn(level2);
+ }
+ first = false;
+ WriteInOutOpt(lw, parameter);
+ WriteSignatureType(lw, parameter.ParameterType, TypeLocation.Parameter);
+ WriteCustomModifiers(lw, parameter.__GetCustomModifiers());
+ lw.Write(" ");
+ if ((parameter.Attributes & ParameterAttributes.HasFieldMarshal) != 0)
+ {
+ FieldMarshal marshal;
+ WriteMarshalAs(lw, level2, parameter.__TryGetFieldMarshal(out marshal), marshal, true);
+ }
+ if (parameter.Name == null)
+ {
+ lw.Write("A_{0}", parameter.Position + (method.IsStatic ? 0 : 1));
+ }
+ else
+ {
+ lw.Write("{0}", QuoteIdentifier(parameter.Name));
+ }
+ }
+ lw.Write(")");
+ MethodImplAttributes implflags = method.GetMethodImplementationFlags();
+ switch (implflags & MethodImplAttributes.CodeTypeMask)
+ {
+ case MethodImplAttributes.IL:
+ lw.Write(" cil");
+ break;
+ case MethodImplAttributes.Native:
+ lw.Write(" native");
+ break;
+ case MethodImplAttributes.OPTIL:
+ lw.Write(" optil");
+ break;
+ case MethodImplAttributes.Runtime:
+ lw.Write(" runtime");
+ break;
+ }
+ if ((implflags & MethodImplAttributes.ManagedMask) == MethodImplAttributes.Managed)
+ {
+ lw.Write(" managed");
+ }
+ else
+ {
+ lw.Write(" unmanaged");
+ }
+ if ((implflags & MethodImplAttributes.Synchronized) != 0)
+ {
+ lw.Write(" synchronized");
+ }
+ if ((implflags & MethodImplAttributes.NoInlining) != 0)
+ {
+ lw.Write(" noinlining");
+ }
+ if ((implflags & MethodImplAttributes.PreserveSig) != 0)
+ {
+ lw.Write(" preservesig");
+ }
+ if ((implflags & MethodImplAttributes.InternalCall) != 0)
+ {
+ lw.Write(" internalcall");
+ }
+ if ((implflags & MethodImplAttributes.ForwardRef) != 0)
+ {
+ lw.Write(" forwardref");
+ }
+ if ((implflags & MethodImplAttributes.NoOptimization) != 0 && compat != CompatLevel.V20)
+ {
+ lw.Write(" nooptimization");
+ }
+ if ((implflags & MethodImplAttributes.AggressiveInlining) != 0 && compat != CompatLevel.V20 && compat != CompatLevel.V40)
+ {
+ lw.Write(" aggressiveinlining");
+ }
+ lw.WriteLine();
+ lw.GoToColumn(level0);
+ lw.WriteLine("{");
+ if (method.MetadataToken == module.__EntryPointToken)
+ {
+ lw.GoToColumn(level0 + 2);
+ lw.WriteLine(".entrypoint");
+ }
+ WriteCustomAttributes(lw, level0 + 2, method.__GetCustomAttributes(null, false));
+ WriteGenericParameterCustomAttributes(lw, level0 + 2, method.GetGenericArguments());
+ WriteParam(lw, level0 + 2, method is ConstructorInfo ? ((ConstructorInfo)method).__ReturnParameter : ((MethodInfo)method).ReturnParameter);
+ foreach (var parameter in method.GetParameters())
+ {
+ WriteParam(lw, level0 + 2, parameter);
+ }
+ WriteDeclarativeSecurity(lw, level0 + 2, CustomAttributeData.__GetDeclarativeSecurity(method), method.MetadataToken);
+ List<KeyValuePair<int, int>> vtentries;
+ if (vtentryMap.TryGetValue(method, out vtentries))
+ {
+ foreach (var vtentry in vtentries)
+ {
+ lw.GoToColumn(level0 + 2);
+ lw.WriteLine(".vtentry {0} : {1}", vtentry.Key, vtentry.Value);
+ }
+ }
+ List<ExportedMethod> exports;
+ if (exportedMethods.TryGetValue(method.MetadataToken, out exports))
+ {
+ foreach (var export in exports)
+ {
+ lw.GoToColumn(level0 + 2);
+ lw.WriteLine(".export [{0}] as {1}", export.ordinal, QuoteIdentifier(export.name));
+ }
+ }
+ if (method.DeclaringType != null && method is MethodInfo)
+ {
+ foreach (var impl in ((MethodInfo)method).__GetMethodImpls())
+ {
+ lw.GoToColumn(level0 + 2);
+ lw.Write(".override ");
+ if (!impl.DeclaringType.__IsMissing && impl.DeclaringType.IsGenericType)
+ {
+ lw.Write(" method ");
+ WriteInlineMethod(lw, impl, Type.EmptyTypes, null, (MethodInfo)method);
+ lw.WriteLine();
+ }
+ else
+ {
+ WriteTypeDefOrRef(lw, impl.DeclaringType);
+ lw.Write("::");
+ lw.WriteLine("{0}", QuoteIdentifier(GetMethodName(impl)));
+ }
+ }
+ }
+ MethodBody body = method.GetMethodBody();
+ if (body != null)
+ {
+ lw.GoToColumn(level0 + 2);
+ WriteIL(lw, method, body, method.DeclaringType == null ? null : method.DeclaringType.GetGenericArguments(), method.GetGenericArguments());
+ }
+ else if ((implflags & MethodImplAttributes.CodeTypeMask) == MethodImplAttributes.Native)
+ {
+ lw.GoToColumn(level0 + 2);
+ lw.WriteLine("// Embedded native code");
+ lw.GoToColumn(level0 + 2);
+ lw.WriteLine("// Disassembly of native methods is not supported.");
+ lw.GoToColumn(level0 + 2);
+ lw.WriteLine("// Managed TargetRVA = 0x{0:X8}", method.__MethodRVA);
+ }
+ lw.GoToColumn(level0);
+ if ((method.Attributes & MethodAttributes.PinvokeImpl) != 0 && (implflags & MethodImplAttributes.CodeTypeMask) != MethodImplAttributes.Native)
+ {
+ lw.WriteLine("}");
+ }
+ else
+ {
+ string methodName = GetMethodName(method);
+ if ((method.Attributes & MethodAttributes.MemberAccessMask) == MethodAttributes.PrivateScope)
+ {
+ methodName = methodName.Substring(0, methodName.Length - 12);
+ }
+ if (method.DeclaringType == null)
+ {
+ lw.WriteLine("}} // end of global method {0}", QuoteIdentifier(methodName));
+ }
+ else
+ {
+ lw.WriteLine("}} // end of method {0}::{1}", QuoteIdentifier(method.DeclaringType.__Name), QuoteIdentifier(methodName));
+ }
+ lw.WriteLine();
+ }
+ }
+
+ string GetMethodName(MethodBase method)
+ {
+ if (method.Module == module && (method.DeclaringType == null || !method.DeclaringType.IsArray))
+ {
+ return methodNames[method.__GetMethodOnTypeDefinition().MetadataToken - 0x06000001];
+ }
+ else
+ {
+ return method.Name;
+ }
+ }
+
+ static void WriteInOutOpt(LineWriter lw, ParameterInfo parameter)
+ {
+ if (parameter.IsIn || parameter.IsOut || parameter.IsOptional)
+ {
+ if (parameter.IsIn)
+ {
+ lw.Write("[in]");
+ }
+ if (parameter.IsOut)
+ {
+ lw.Write("[out]");
+ }
+ if (parameter.IsOptional)
+ {
+ lw.Write("[opt]");
+ }
+ lw.Write(" ");
+ }
+ }
+
+ void WriteParam(LineWriter lw, int level, ParameterInfo parameter)
+ {
+ IList<CustomAttributeData> ca = parameter.__GetCustomAttributes(null, false);
+ if (ca.Count != 0 || (parameter.Attributes & ParameterAttributes.HasDefault) != 0)
+ {
+ lw.GoToColumn(level);
+ lw.Write(".param [{0}]", parameter.Position + 1);
+ if ((parameter.Attributes & ParameterAttributes.HasDefault) != 0)
+ {
+ lw.Write(" = ");
+ WriteConstant(lw, parameter.RawDefaultValue, level);
+ }
+ lw.WriteLine();
+ WriteCustomAttributes(lw, level, ca);
+ }
+ }
+
+ static string EscapePInvoke(string str)
+ {
+ return str
+ .Replace("\\", "\\\\")
+ .Replace("?", "\\?")
+ .Replace("\n", "\\n")
+ .Replace("\r", "\\r")
+ .Replace("\t", "\\t")
+ .Replace("\b", "\\b")
+ .Replace("\f", "\\f")
+ .Replace("\v", "\\v")
+ .Replace("\a", "\\a")
+ .Replace("\"", "\\\"")
+ ;
+ }
+
+ void WritePInvokeImpl(LineWriter lw, MethodBase method)
+ {
+ lw.Write("pinvokeimpl(");
+ MethodInfo mi = method as MethodInfo;
+ ImplMapFlags flags;
+ string importName;
+ string importScope;
+ if (mi != null && mi.__TryGetImplMap(out flags, out importName, out importScope))
+ {
+ if (importScope != null)
+ {
+ lw.Write("\"{0}\"", EscapePInvoke(importScope));
+ }
+ if (importName != null && importName != method.Name)
+ {
+ lw.Write(" as \"{0}\"", EscapePInvoke(importName));
+ }
+ if ((flags & ImplMapFlags.NoMangle) != 0)
+ {
+ lw.Write(" nomangle");
+ }
+ switch (flags & ImplMapFlags.CharSetMask)
+ {
+ case ImplMapFlags.CharSetAnsi:
+ lw.Write(" ansi");
+ break;
+ case ImplMapFlags.CharSetAuto:
+ lw.Write(" autochar");
+ break;
+ case ImplMapFlags.CharSetUnicode:
+ lw.Write(" unicode");
+ break;
+ }
+ if ((flags & ImplMapFlags.SupportsLastError) != 0)
+ {
+ lw.Write(" lasterr");
+ }
+ switch (flags & ImplMapFlags.CallConvMask)
+ {
+ case ImplMapFlags.CallConvWinapi:
+ lw.Write(" winapi");
+ break;
+ case ImplMapFlags.CallConvStdcall:
+ lw.Write(" stdcall");
+ break;
+ case ImplMapFlags.CallConvCdecl:
+ lw.Write(" cdecl");
+ break;
+ case ImplMapFlags.CallConvThiscall:
+ lw.Write(" thiscall");
+ break;
+ }
+ switch (flags & (ImplMapFlags.BestFitOff | ImplMapFlags.BestFitOn))
+ {
+ case ImplMapFlags.BestFitOn:
+ lw.Write(" bestfit:on");
+ break;
+ case ImplMapFlags.BestFitOff:
+ lw.Write(" bestfit:off");
+ break;
+ }
+ switch (flags & (ImplMapFlags.CharMapErrorOff | ImplMapFlags.CharMapErrorOn))
+ {
+ case ImplMapFlags.CharMapErrorOn:
+ lw.Write(" charmaperror:on");
+ break;
+ case ImplMapFlags.CharMapErrorOff:
+ lw.Write(" charmaperror:off");
+ break;
+ }
+ lw.Write(") ");
+ }
+ else
+ {
+ lw.Write("/* No map */) ");
+ }
+ }
+
+ void WriteMarshalAs(LineWriter lw, int level, bool hasFieldMarshalRecord, FieldMarshal marshal, bool wrap)
+ {
+ var sb = new StringBuilder();
+ WriteMarshalAs(sb, level, hasFieldMarshalRecord, marshal, wrap);
+ lw.Write(sb.ToString());
+ }
+
+ void WriteMarshalAs(StringBuilder sb, int level, bool hasFieldMarshalRecord, FieldMarshal marshal, bool wrap)
+ {
+ if (!hasFieldMarshalRecord)
+ {
+ if (compat == CompatLevel.None)
+ {
+ sb.Append(" /*HasFieldMarshal*/ ");
+ }
+ return;
+ }
+ sb.Append(" marshal(");
+ short? sizeParamIndex = marshal.SizeParamIndex;
+ if (marshal.ArraySubType != null && marshal.UnmanagedType != System.Runtime.InteropServices.UnmanagedType.ByValArray)
+ {
+ sb.Append(UnmanagedTypeToString(marshal.ArraySubType.Value));
+ switch (marshal.ArraySubType.Value)
+ {
+ case System.Runtime.InteropServices.UnmanagedType.IUnknown:
+ case System.Runtime.InteropServices.UnmanagedType.Interface:
+ if (marshal.SizeParamIndex == null)
+ {
+ sb.Append(" ");
+ }
+ else
+ {
+ sb.AppendFormat("(iidparam = {0}) ", marshal.SizeParamIndex.Value);
+ sizeParamIndex = null;
+ }
+ break;
+ }
+ }
+ if (marshal.SafeArraySubType != null && marshal.UnmanagedType == System.Runtime.InteropServices.UnmanagedType.SafeArray)
+ {
+ sb.Append(VarEnumToString(marshal.SafeArraySubType.Value));
+ }
+ else if (marshal.UnmanagedType == System.Runtime.InteropServices.UnmanagedType.LPArray
+ && (marshal.SizeConst != null || sizeParamIndex != null))
+ {
+ // don't write [] it's implied by the following sizeConst or sizeParamIndex
+ }
+ else
+ {
+ sb.Append(UnmanagedTypeToString(marshal.UnmanagedType));
+ if (marshal.IidParameterIndex == null
+ && (marshal.UnmanagedType == System.Runtime.InteropServices.UnmanagedType.Interface
+ || marshal.UnmanagedType == System.Runtime.InteropServices.UnmanagedType.IUnknown))
+ {
+ sb.Append(" ");
+ }
+ }
+ if (marshal.SizeConst != null)
+ {
+ if (marshal.UnmanagedType != System.Runtime.InteropServices.UnmanagedType.LPArray)
+ {
+ sb.Append(" ");
+ }
+ if (sizeParamIndex != null || (compat != CompatLevel.None && !IsFixed(marshal.UnmanagedType)))
+ {
+ sb.AppendFormat("[{0} + {1}]", marshal.SizeConst.Value, sizeParamIndex.GetValueOrDefault());
+ }
+ else
+ {
+ sb.AppendFormat("[{0}]", marshal.SizeConst.Value);
+ }
+ }
+ else if (sizeParamIndex != null)
+ {
+ sb.AppendFormat("[ + {0}]", sizeParamIndex.Value);
+ }
+ if (marshal.SafeArrayUserDefinedSubType != null)
+ {
+ sb.AppendFormat(", \"{0}\"", marshal.SafeArrayUserDefinedSubType);
+ }
+ if (marshal.IidParameterIndex != null)
+ {
+ sb.AppendFormat("(iidparam = {0}) ", marshal.IidParameterIndex.Value);
+ }
+ if (marshal.MarshalType != null || marshal.MarshalCookie != null)
+ {
+ sb.AppendFormat("(\"{0}\",", marshal.MarshalType);
+ if (wrap)
+ {
+ sb.AppendLine();
+ sb.Append(' ', level);
+ }
+ sb.AppendFormat("\"{0}\")", marshal.MarshalCookie);
+ }
+ if (marshal.ArraySubType != null && marshal.UnmanagedType == System.Runtime.InteropServices.UnmanagedType.ByValArray)
+ {
+ sb.Append(UnmanagedTypeToString(marshal.ArraySubType.Value));
+ }
+ sb.Append(") ");
+ }
+
+ static string VarEnumToString(System.Runtime.InteropServices.VarEnum value)
+ {
+ switch (value)
+ {
+ case System.Runtime.InteropServices.VarEnum.VT_VARIANT:
+ return " safearray variant";
+ case System.Runtime.InteropServices.VarEnum.VT_I1:
+ return " safearray int8";
+ case System.Runtime.InteropServices.VarEnum.VT_I2:
+ return " safearray int16";
+ case System.Runtime.InteropServices.VarEnum.VT_I4:
+ return " safearray int32";
+ case System.Runtime.InteropServices.VarEnum.VT_I8:
+ return " safearray int64";
+ case System.Runtime.InteropServices.VarEnum.VT_UI1:
+ return " safearray unsigned int8";
+ case System.Runtime.InteropServices.VarEnum.VT_UI2:
+ return " safearray unsigned int16";
+ case System.Runtime.InteropServices.VarEnum.VT_UI4:
+ return " safearray unsigned int32";
+ case System.Runtime.InteropServices.VarEnum.VT_UI8:
+ return " safearray unsigned int64";
+ case System.Runtime.InteropServices.VarEnum.VT_R4:
+ return " safearray float32";
+ case System.Runtime.InteropServices.VarEnum.VT_R8:
+ return " safearray float64";
+ case System.Runtime.InteropServices.VarEnum.VT_BSTR:
+ return " safearray bstr";
+ case System.Runtime.InteropServices.VarEnum.VT_BOOL:
+ return " safearray bool";
+ case System.Runtime.InteropServices.VarEnum.VT_UNKNOWN:
+ return " safearray iunknown";
+ case System.Runtime.InteropServices.VarEnum.VT_RECORD:
+ return " safearray record";
+ case System.Runtime.InteropServices.VarEnum.VT_DISPATCH:
+ return " safearray idispatch";
+ case System.Runtime.InteropServices.VarEnum.VT_EMPTY:
+ return " safearray";
+ default:
+ Console.WriteLine(value);
+ return "";
+ }
+ }
+
+ static bool IsFixed(System.Runtime.InteropServices.UnmanagedType unmanagedType)
+ {
+ switch (unmanagedType)
+ {
+ case System.Runtime.InteropServices.UnmanagedType.ByValArray:
+ case System.Runtime.InteropServices.UnmanagedType.ByValTStr:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ string UnmanagedTypeToString(System.Runtime.InteropServices.UnmanagedType unmanagedType)
+ {
+ switch (unmanagedType)
+ {
+ case System.Runtime.InteropServices.UnmanagedType.Bool:
+ return " bool";
+ case System.Runtime.InteropServices.UnmanagedType.SysInt:
+ return " int";
+ case System.Runtime.InteropServices.UnmanagedType.SysUInt:
+ return " uint";
+ case System.Runtime.InteropServices.UnmanagedType.I1:
+ return " int8";
+ case System.Runtime.InteropServices.UnmanagedType.I2:
+ return " int16";
+ case System.Runtime.InteropServices.UnmanagedType.I4:
+ return " int32";
+ case System.Runtime.InteropServices.UnmanagedType.I8:
+ return " int64";
+ case System.Runtime.InteropServices.UnmanagedType.U1:
+ return " unsigned int8";
+ case System.Runtime.InteropServices.UnmanagedType.U2:
+ return " unsigned int16";
+ case System.Runtime.InteropServices.UnmanagedType.U4:
+ return " unsigned int32";
+ case System.Runtime.InteropServices.UnmanagedType.U8:
+ return " unsigned int64";
+ case System.Runtime.InteropServices.UnmanagedType.R4:
+ return " float32";
+ case System.Runtime.InteropServices.UnmanagedType.R8:
+ return " float64";
+ case System.Runtime.InteropServices.UnmanagedType.BStr:
+ return " bstr";
+ case System.Runtime.InteropServices.UnmanagedType.LPWStr:
+ return " lpwstr";
+ case System.Runtime.InteropServices.UnmanagedType.SafeArray:
+ return " safearray";
+ case System.Runtime.InteropServices.UnmanagedType.ByValArray:
+ return " fixed array";
+ case System.Runtime.InteropServices.UnmanagedType.ByValTStr:
+ return " fixed sysstring";
+ case System.Runtime.InteropServices.UnmanagedType.IUnknown:
+ return " iunknown";
+ case System.Runtime.InteropServices.UnmanagedType.Interface:
+ return " interface";
+ case System.Runtime.InteropServices.UnmanagedType.CustomMarshaler:
+ return " custom ";
+ case System.Runtime.InteropServices.UnmanagedType.LPArray:
+ return "[]";
+ case System.Runtime.InteropServices.UnmanagedType.AsAny:
+ return " as any";
+ case System.Runtime.InteropServices.UnmanagedType.LPStruct:
+ return " lpstruct";
+ case System.Runtime.InteropServices.UnmanagedType.IDispatch:
+ return " idispatch ";
+ case System.Runtime.InteropServices.UnmanagedType.Struct:
+ return " struct";
+ case System.Runtime.InteropServices.UnmanagedType.FunctionPtr:
+ return " method";
+ case System.Runtime.InteropServices.UnmanagedType.LPStr:
+ return " lpstr";
+ case System.Runtime.InteropServices.UnmanagedType.Error:
+ return " error";
+ case System.Runtime.InteropServices.UnmanagedType.LPTStr:
+ return " lptstr";
+ case System.Runtime.InteropServices.UnmanagedType.VBByRefStr:
+ return " byvalstr";
+ case System.Runtime.InteropServices.UnmanagedType.Currency:
+ return " currency";
+ case System.Runtime.InteropServices.UnmanagedType.VariantBool:
+ return " variant bool";
+ case (System.Runtime.InteropServices.UnmanagedType)80:
+ return ""; // Microsoft.SqlServer.DTSRuntimeWrap.dll (9.0.242.0) has this bogus value
+ case (System.Runtime.InteropServices.UnmanagedType)46:
+ return compat == CompatLevel.None ? " iinspectable" : compat == CompatLevel.V45 ? "{ 2E }" : "";
+ case (System.Runtime.InteropServices.UnmanagedType)47:
+ return compat == CompatLevel.None ? " hstring" : compat == CompatLevel.V45 ? "{ 2F }" : "";
+ default:
+ Console.WriteLine("unsupported unmanagedType in marshal blob: {0}", unmanagedType);
+ return "";
+ }
+ }
+
+ string QuoteIdentifier(string str, bool quote = false)
+ {
+ if (diffMode)
+ {
+ if (str.StartsWith("$$method0x", StringComparison.Ordinal))
+ {
+ return "'$$method0x...'";
+ }
+ else if (str.Length == 68 && str.StartsWith("<PrivateImplementationDetails>{", StringComparison.Ordinal) && str.EndsWith("}", StringComparison.Ordinal))
+ {
+ return "'<PrivateImplementationDetails>{nnnnnnnn-nnnn-nnnn-nnnn-nnnnnnnnnnnn}'";
+ }
+ for (int pos, cur = 0; (pos = str.IndexOf("?A0x", cur)) != -1; cur = pos + 4)
+ {
+ str = str.Substring(0, pos + 4) + "________" + str.Substring(pos + 12);
+ }
+ }
+ quote |= str.Length > 0 && "0123456789".IndexOf(str[0]) != -1;
+ for (int i = str.IndexOf('.'); i != -1 && i < str.Length - 1; i = str.IndexOf('.', i + 1))
+ {
+ if ("0123456789".IndexOf(str[i + 1]) != -1)
+ {
+ quote = true;
+ break;
+ }
+ }
+ foreach (char c in str)
+ {
+ if (c <= 32 || c >= 127)
+ {
+ quote = true;
+ break;
+ }
+ }
+ Escape(ref str, ref quote, "\\", "\\\\");
+ Escape(ref str, ref quote, "'", "\\'");
+ Escape(ref str, ref quote, "\"", "\\\"");
+ Escape(ref str, ref quote, "\t", "\\t");
+ Escape(ref str, ref quote, "\r", "\\r");
+ Escape(ref str, ref quote, "\n", "\\n");
+ Escape(ref str, ref quote, "\a", "\\a");
+ Escape(ref str, ref quote, "\b", "\\b");
+ Escape(ref str, ref quote, "\u0000", "\\u0000");
+ if (compat == CompatLevel.V20 || compat == CompatLevel.V40)
+ {
+ StringBuilder sb = null;
+ for (int i = 0; i < str.Length; i++)
+ {
+ if (str[i] >= 128)
+ {
+ if (sb == null)
+ {
+ sb = new StringBuilder(str);
+ }
+ sb[i] = '\uFFFD';
+ }
+ }
+ if (sb != null)
+ {
+ str = sb.ToString();
+ }
+ }
+ if (keywords.Contains(str))
+ {
+ return "'" + str + "'";
+ }
+ else if (quote
+ || str.IndexOf('<') != -1
+ || str.IndexOf('>') != -1
+ || str.StartsWith("?")
+ || (str.StartsWith(".") && str != ".ctor" && str != ".cctor")
+ || str.Contains(".?")
+ || str.Contains("..")
+ || str.IndexOf('{') != -1
+ || str.IndexOf('}') != -1
+ || str.IndexOf('[') != -1
+ || str.IndexOf(']') != -1
+ || str.IndexOf('!') != -1
+ || str.IndexOf('/') != -1
+ || str.IndexOf('=') != -1
+ || str.IndexOf('+') != -1
+ || str.IndexOf(':') != -1
+ || str.IndexOf('|') != -1
+ || str.IndexOf('~') != -1
+ || str.IndexOf('^') != -1
+ || str.IndexOf('-') != -1)
+ {
+ return "'" + str + "'";
+ }
+ else
+ {
+ return str;
+ }
+ }
+
+ static void Escape(ref string str, ref bool quote, string ch, string esc)
+ {
+ if (str.IndexOf(ch) != -1)
+ {
+ quote = true;
+ str = str.Replace(ch, esc);
+ }
+ }
+
+ void WriteField(LineWriter lw, FieldInfo field)
+ {
+ int level = lw.Column;
+ lw.Write(".field ");
+ int offset;
+ if (field.__TryGetFieldOffset(out offset))
+ {
+ lw.Write("[{0}] ", offset);
+ }
+ switch (field.Attributes & FieldAttributes.FieldAccessMask)
+ {
+ case FieldAttributes.Public:
+ lw.Write("public ");
+ break;
+ case FieldAttributes.Private:
+ lw.Write("private ");
+ break;
+ }
+ if ((field.Attributes & FieldAttributes.Static) != 0)
+ {
+ lw.Write("static ");
+ }
+ switch (field.Attributes & FieldAttributes.FieldAccessMask)
+ {
+ case FieldAttributes.Family:
+ lw.Write("family ");
+ break;
+ case FieldAttributes.Assembly:
+ lw.Write("assembly ");
+ break;
+ case FieldAttributes.FamORAssem:
+ lw.Write("famorassem ");
+ break;
+ case FieldAttributes.PrivateScope:
+ lw.Write("privatescope ");
+ break;
+ }
+ if ((field.Attributes & FieldAttributes.InitOnly) != 0)
+ {
+ lw.Write("initonly ");
+ }
+ if ((field.Attributes & FieldAttributes.Literal) != 0)
+ {
+ lw.Write("literal ");
+ }
+ if ((field.Attributes & FieldAttributes.SpecialName) != 0)
+ {
+ lw.Write("specialname ");
+ }
+ if ((field.Attributes & FieldAttributes.RTSpecialName) != 0)
+ {
+ lw.Write("rtspecialname ");
+ }
+ if ((field.Attributes & FieldAttributes.NotSerialized) != 0)
+ {
+ lw.Write("notserialized ");
+ }
+ if ((field.Attributes & FieldAttributes.HasFieldMarshal) != 0)
+ {
+ FieldMarshal marshal;
+ WriteMarshalAs(lw, level, field.__TryGetFieldMarshal(out marshal), marshal, false);
+ }
+ WriteSignatureType(lw, field.FieldType);
+ WriteCustomModifiers(lw, field.__GetCustomModifiers());
+ lw.Write(" {0}", QuoteIdentifier(GetFieldName(field)));
+ if ((field.Attributes & FieldAttributes.HasDefault) != 0)
+ {
+ lw.Write(" = ");
+ WriteConstant(lw, field.GetRawConstantValue(), level);
+ }
+ if ((field.Attributes & FieldAttributes.HasFieldRVA) != 0)
+ {
+ dataFields.Add(field);
+ string name;
+ int characteristics;
+ if (module.__GetSectionInfo(field.__FieldRVA, out name, out characteristics))
+ {
+ switch (name)
+ {
+ case ".text":
+ lw.Write(" at I_");
+ break;
+ case ".tls":
+ lw.Write(" at T_");
+ break;
+ default:
+ lw.Write(" at D_");
+ break;
+ }
+ if (diffMode)
+ {
+ lw.Write("xxxxxxxx");
+ }
+ else
+ {
+ lw.Write("{0:X8}", field.__FieldRVA);
+ }
+ }
+ else
+ {
+ lw.Write(" at 0x{0:X8} /* WARNING: rogue pointer! (size 0x{1:X8}) */", field.__FieldRVA, GetTypeSize(field.FieldType));
+ }
+ }
+ lw.WriteLine();
+ WriteCustomAttributes(lw, level, field.__GetCustomAttributes(null, false));
+ }
+
+ string GetFieldName(FieldInfo field)
+ {
+ if (field.Module == module)
+ {
+ return fieldNames[field.__GetFieldOnTypeDefinition().MetadataToken - 0x04000001];
+ }
+ else
+ {
+ return field.Name;
+ }
+ }
+
+ void WriteCustomModifiers(LineWriter lw, CustomModifiers mods)
+ {
+ foreach (var mod in mods.Reverse())
+ {
+ lw.Write(" {0}(", mod.IsRequired ? "modreq" : "modopt");
+ WriteTypeDefOrRef(lw, mod.Type);
+ lw.Write(")");
+ }
+ }
+
+ void WriteModuleManifest(LineWriter lw)
+ {
+ lw.WriteLine("// Metadata version: {0}", module.__ImageRuntimeVersion);
+ foreach (var refmodule in module.__GetReferencedModules())
+ {
+ if (!String.IsNullOrEmpty(refmodule))
+ {
+ lw.WriteLine(".module extern {0}", QuoteIdentifier(refmodule));
+ }
+ }
+ AssemblyName[] referencedAssemblies = module.__GetReferencedAssemblies();
+ for (int i = 0; i < referencedAssemblies.Length; i++)
+ {
+ AssemblyName asm = referencedAssemblies[i];
+ lw.Write(".assembly extern {0}{1}",
+ asm.ContentType == AssemblyContentType.WindowsRuntime && (compat == CompatLevel.None || compat >= CompatLevel.V45) ? "windowsruntime " : "",
+ QuoteIdentifier(asm.Name));
+ if (asm.Name != this.referencedAssemblies[resolvedAssemblies[i]])
+ {
+ lw.Write(" as {0}", QuoteIdentifier(this.referencedAssemblies[resolvedAssemblies[i]]));
+ }
+ lw.WriteLine();
+ lw.WriteLine("{");
+ byte[] token = asm.GetPublicKeyToken();
+ if (token != null && token.Length != 0)
+ {
+ lw.Write(" .publickeytoken = (");
+ WriteBytes(lw, token, false);
+ lw.WriteLine();
+ }
+ if (asm.__Hash != null)
+ {
+ lw.Write(" .hash = (");
+ WriteBytes(lw, asm.__Hash, false);
+ lw.WriteLine();
+ }
+ lw.WriteLine(" .ver {0}:{1}:{2}:{3}", asm.Version.Major, asm.Version.Minor, asm.Version.Build, asm.Version.Revision);
+ lw.WriteLine("}");
+ }
+ }
+
+ void WriteAssemblyManifest(LineWriter lw)
+ {
+ lw.WriteLine(".assembly {0}{1}{2}",
+ ((int)assembly.__AssemblyFlags & 16) != 0 ? "cil " : "",
+ ((int)assembly.__AssemblyFlags & 512) != 0 && (compat == CompatLevel.None || compat >= CompatLevel.V45) ? "windowsruntime " : "",
+ QuoteIdentifier(assembly.GetName().Name));
+ lw.WriteLine("{");
+ IEnumerable<CustomAttributeData> cas = assembly.__GetCustomAttributes(null, false);
+ if (diffMode)
+ {
+ cas = cas.OrderBy(x => x.Constructor.DeclaringType.FullName);
+ }
+ foreach (var ca in cas)
+ {
+ if (ca.Constructor.DeclaringType.FullName == "System.Diagnostics.DebuggableAttribute"
+ && ca.Constructor.DeclaringType.Assembly.GetName().Name == "mscorlib")
+ {
+ lw.WriteLine();
+ lw.WriteLine(" // --- The following custom attribute is added automatically, do not uncomment -------");
+ lw.Write(" // .custom ");
+ WriteCustomAttributeImpl(lw, ca, true, lw.Column);
+ lw.WriteLine();
+ }
+ else
+ {
+ lw.Write(" ");
+ WriteCustomAttribute(lw, ca);
+ }
+ }
+ WriteDeclarativeSecurity(lw, 2, CustomAttributeData.__GetDeclarativeSecurity(assembly), 0x20000001);
+ byte[] publicKey = assembly.GetName().GetPublicKey();
+ if (publicKey != null && publicKey.Length != 0)
+ {
+ lw.Write(" .publickey = (");
+ WriteBytes(lw, publicKey, false);
+ lw.WriteLine();
+ }
+ if (assembly.GetName().HashAlgorithm != 0)
+ {
+ lw.WriteLine(" .hash algorithm 0x{0:X8}", (int)assembly.GetName().HashAlgorithm);
+ }
+ lw.WriteLine(" .ver {0}:{1}:{2}:{3}", assembly.GetName().Version.Major, assembly.GetName().Version.Minor, assembly.GetName().Version.Build, assembly.GetName().Version.Revision);
+ if (assembly.GetName().CultureInfo != null)
+ {
+ string culture = assembly.GetName().CultureInfo.Name;
+ if (culture != "")
+ {
+ lw.Write(" .locale = (");
+ byte[] buf = new byte[culture.Length * 2 + 2];
+ for (int i = 0; i < culture.Length; i++)
+ {
+ buf[i * 2 + 0] = (byte)(culture[i] >> 0);
+ buf[i * 2 + 1] = (byte)(culture[i] >> 8);
+ }
+ WriteBytes(lw, buf, false);
+ lw.WriteLine();
+ }
+ }
+ lw.WriteLine("}");
+ }
+
+ void WriteDeclarativeSecurity(LineWriter lw, int level, IList<CustomAttributeData> list, int metadataToken)
+ {
+ var action = (System.Security.Permissions.SecurityAction)(- 1);
+ var curr = new List<CustomAttributeData>();
+ foreach (var sec in list)
+ {
+ if (action == (System.Security.Permissions.SecurityAction)sec.ConstructorArguments[0].Value)
+ {
+ curr.Add(sec);
+ }
+ else
+ {
+ WritePermissionSet(lw, level, action, curr, metadataToken);
+ curr.Clear();
+ curr.Add(sec);
+ action = (System.Security.Permissions.SecurityAction)sec.ConstructorArguments[0].Value;
+ }
+ }
+ WritePermissionSet(lw, level, action, curr, metadataToken);
+ }
+
+ void WritePermissionSet(LineWriter lw, int level, System.Security.Permissions.SecurityAction action, List<CustomAttributeData> list, int metadataToken)
+ {
+ if (list.Count != 0)
+ {
+ lw.GoToColumn(level);
+ lw.Write(".permissionset ");
+ switch (action)
+ {
+ case System.Security.Permissions.SecurityAction.Assert:
+ lw.Write("assert");
+ break;
+ case System.Security.Permissions.SecurityAction.RequestMinimum:
+ lw.Write("reqmin");
+ break;
+ case System.Security.Permissions.SecurityAction.RequestRefuse:
+ lw.Write("reqrefuse");
+ break;
+ case System.Security.Permissions.SecurityAction.RequestOptional:
+ lw.Write("reqopt");
+ break;
+ case System.Security.Permissions.SecurityAction.Demand:
+ lw.Write("demand");
+ break;
+ case System.Security.Permissions.SecurityAction.LinkDemand:
+ lw.Write("linkcheck");
+ break;
+ case System.Security.Permissions.SecurityAction.InheritanceDemand:
+ lw.Write("inheritcheck");
+ break;
+ }
+ lw.WriteLine();
+ lw.GoToColumn(level);
+ var sb = new StringBuilder();
+ if (list.Count == 1)
+ {
+ try
+ {
+ var args = list[0].NamedArguments;
+ if (args.Count == 1 && args[0].MemberInfo.Name == "XML")
+ {
+ if (compat >= CompatLevel.V45)
+ {
+ // starting with 4.5 ildasm no longer supports the 1.1 format
+ lw.Write(" bytearray (");
+ WriteBytes(lw, Encoding.Unicode.GetBytes((string)args[0].TypedValue.Value), false);
+ lw.WriteLine();
+ return;
+ }
+ lw.Write(" ");
+ WriteInlineString(lw, (string)args[0].TypedValue.Value, level);
+ lw.WriteLine();
+ return;
+ }
+ }
+ catch (IKVM.Reflection.MissingMemberException) { }
+ }
+ if (DecodeDeclSecurity(sb, list, level))
+ {
+ lw.WriteLine("{0}", sb);
+ }
+ else
+ {
+ var mem = new System.IO.MemoryStream();
+ mem.WriteByte((byte)'.');
+ WriteCompressedInt(mem, list.Count);
+ foreach (var sec in list)
+ {
+ Write(mem, sec.Constructor.DeclaringType.AssemblyQualifiedName.Replace(", PublicKeyToken=null", ""));
+ byte[] buf = sec.__GetBlob();
+ WriteCompressedInt(mem, buf.Length);
+ mem.Write(buf, 0, buf.Length);
+ }
+ byte[] blob = mem.ToArray();
+ if ((compat == CompatLevel.V20 || compat == CompatLevel.V40) && (blob.Length & 1) == 1)
+ {
+ // ildasm bug http://connect.microsoft.com/VisualStudio/feedback/details/652653/
+ Array.Resize(ref blob, blob.Length - 1);
+ }
+ lw.Write(" bytearray (");
+ WriteBytes(lw, blob, false);
+ lw.WriteLine();
+ }
+ }
+ }
+
+ void Write(System.IO.MemoryStream mem, string str)
+ {
+ if (str == null)
+ {
+ mem.WriteByte((byte)0xFF);
+ }
+ else
+ {
+ byte[] buf = Encoding.UTF8.GetBytes(str);
+ WriteCompressedInt(mem, buf.Length);
+ mem.Write(buf, 0, buf.Length);
+ }
+ }
+
+ void WriteCompressedInt(System.IO.MemoryStream mem, int value)
+ {
+ if (value <= 0x7F)
+ {
+ mem.WriteByte((byte)value);
+ }
+ else if (value <= 0x3FFF)
+ {
+ mem.WriteByte((byte)(0x80 | (value >> 8)));
+ mem.WriteByte((byte)value);
+ }
+ else
+ {
+ mem.WriteByte((byte)(0xC0 | (value >> 24)));
+ mem.WriteByte((byte)(value >> 16));
+ mem.WriteByte((byte)(value >> 8));
+ mem.WriteByte((byte)value);
+ }
+ }
+
+ void WriteDeclarativeSecurity(LineWriter lw, int level, CustomAttributeData sec)
+ {
+ if (!typerefs.Contains(sec.Constructor.DeclaringType))
+ {
+ lw.Write("class '{0}'", sec.Constructor.DeclaringType.AssemblyQualifiedName.Replace(", PublicKeyToken=null", ""));
+ }
+ else
+ {
+ WriteTypeDefOrRef(lw, sec.Constructor.DeclaringType);
+ }
+ lw.Write(" = {");
+ bool first = true;
+ foreach (var arg in sec.NamedArguments)
+ {
+ if (!first)
+ {
+ lw.WriteLine();
+ }
+ first = false;
+ lw.Write(arg.MemberInfo is PropertyInfo ? "property " : "field ");
+ if (!arg.TypedValue.ArgumentType.__IsMissing && arg.TypedValue.ArgumentType.IsEnum)
+ {
+ lw.Write("enum ");
+ WriteTypeDefOrRef(lw, arg.TypedValue.ArgumentType);
+ }
+ else
+ {
+ WriteSignatureType(lw, arg.TypedValue.ArgumentType);
+ }
+ lw.Write(" {0} = ", QuoteIdentifier(arg.MemberInfo.Name, true));
+ WriteAttributeValue(lw, arg.TypedValue.Value);
+ }
+ lw.Write("}");
+ }
+
+ void WriteAttributeValue(LineWriter lw, object obj)
+ {
+ if (obj is byte)
+ {
+ lw.Write("uint8({0})", obj);
+ }
+ else if (obj is sbyte)
+ {
+ lw.Write("int8({0})", obj);
+ }
+ else if (obj is bool)
+ {
+ lw.Write("bool({0})", ((bool)obj) ? "true" : "false");
+ }
+ else if (obj is char)
+ {
+ lw.Write("char(0x{0:X4})", (int)(char)obj);
+ }
+ else if (obj is short)
+ {
+ lw.Write("int16({0})", obj);
+ }
+ else if (obj is ushort)
+ {
+ lw.Write("uint16({0})", obj);
+ }
+ else if (obj is int)
+ {
+ lw.Write("int32({0})", obj);
+ }
+ else if (obj is uint)
+ {
+ lw.Write("uint32({0})", obj);
+ }
+ else if (obj is long)
+ {
+ lw.Write("int64({0})", obj);
+ }
+ else if (obj is ulong)
+ {
+ lw.Write("uint64({0})", obj);
+ }
+ else if (obj is float)
+ {
+ lw.Write("float32(");
+ WriteShortInlineR(lw, (float)obj, true);
+ lw.Write(")");
+ }
+ else if (obj is double)
+ {
+ lw.Write("float64(");
+ WriteInlineR(lw, (double)obj, true);
+ lw.Write(")");
+ }
+ else if (obj is string)
+ {
+ lw.Write("string({0})", QuoteIdentifier((string)obj, true));
+ }
+ else if (obj == null)
+ {
+ lw.Write("nullref");
+ }
+ }
+
+ void WriteConstant(LineWriter lw, object obj, int level)
+ {
+ if (obj is byte)
+ {
+ lw.Write("uint8(0x{0:X2})", obj);
+ }
+ else if (obj is sbyte)
+ {
+ lw.Write("int8(0x{0:X2})", obj);
+ }
+ else if (obj is bool)
+ {
+ lw.Write("bool({0})", ((bool)obj) ? "true" : "false");
+ }
+ else if (obj is char)
+ {
+ lw.Write("char(0x{0:X4})", (int)(char)obj);
+ }
+ else if (obj is short)
+ {
+ lw.Write("int16(0x{0:X4})", obj);
+ }
+ else if (obj is ushort)
+ {
+ lw.Write("uint16(0x{0:X4})", obj);
+ }
+ else if (obj is int)
+ {
+ lw.Write("int32(0x{0:X8})", obj);
+ }
+ else if (obj is uint)
+ {
+ lw.Write("uint32(0x{0:X8})", obj);
+ }
+ else if (obj is long)
+ {
+ lw.Write("int64(0x{0:X})", obj);
+ }
+ else if (obj is ulong)
+ {
+ lw.Write("uint64(0x{0:X})", obj);
+ }
+ else if (obj is float)
+ {
+ lw.Write("float32(");
+ WriteShortInlineR(lw, (float)obj, true);
+ lw.Write(")");
+ }
+ else if (obj is double)
+ {
+ double v = (double)obj;
+ lw.Write("float64(");
+ WriteInlineR(lw, v, true);
+ lw.Write(")");
+ if (Double.IsNegativeInfinity(v))
+ {
+ lw.Write(" // -1.#INF");
+ }
+ else if (Double.IsPositiveInfinity(v))
+ {
+ lw.Write(" // 1.#INF");
+ }
+ else if (Double.IsNaN(v))
+ {
+ if (BitConverter.DoubleToInt64Bits(v) == 0x7FF8000000000000L)
+ {
+ lw.Write(" // 1.#QNAN");
+ }
+ else
+ {
+ lw.Write(" // -1.#IND");
+ }
+ }
+ }
+ else if (obj is string)
+ {
+ WriteInlineString(lw, (string)obj, level);
+ }
+ else if (obj == null)
+ {
+ lw.Write("nullref");
+ }
+ }
+
+ void WriteResources(LineWriter lw)
+ {
+ foreach (var resourceName in assembly.GetManifestResourceNames())
+ {
+ ManifestResourceInfo mres = assembly.GetManifestResourceInfo(resourceName);
+ string access;
+ switch (mres.__ResourceAttributes)
+ {
+ case ResourceAttributes.Public:
+ access = "public ";
+ break;
+ case ResourceAttributes.Private:
+ access = "private ";
+ break;
+ default:
+ access = "";
+ break;
+ }
+ lw.WriteLine(".mresource {0}{1}", access, QuoteIdentifier(resourceName));
+ lw.WriteLine("{");
+ if (mres.FileName != null)
+ {
+ lw.WriteLine(" .file {0} at 0x{1:x8}", QuoteIdentifier(mres.FileName), mres.__Offset);
+ }
+ else if (mres.ReferencedAssembly != null)
+ {
+ lw.WriteLine(" .assembly extern {0}", QuoteIdentifier(referencedAssemblies[mres.ReferencedAssembly]));
+ }
+ else
+ {
+ lw.WriteLine(" // Offset: 0x{0:X8} Length: 0x{1:X8}", mres.__Offset, assembly.GetManifestResourceStream(resourceName).Length);
+ lw.WriteLine(" // WARNING: managed resource file {0} created", QuoteIdentifier(resourceName));
+ }
+ lw.WriteLine("}");
+ }
+ }
+
+ void WriteModuleHeader(LineWriter lw)
+ {
+ lw.WriteLine(".module {0}", QuoteIdentifier(module.ScopeName));
+ if (!diffMode)
+ {
+ lw.WriteLine("// MVID: {0}", module.ModuleVersionId.ToString("B").ToUpperInvariant());
+ }
+ WriteCustomAttributes(lw, 0, module.__GetCustomAttributes(null, false));
+ if (compat == CompatLevel.V20 || GetPointerSize() == 4)
+ {
+ lw.WriteLine(".imagebase 0x{0:x8}", module.__ImageBase);
+ }
+ else
+ {
+ lw.WriteLine(".imagebase 0x{0:x16}", module.__ImageBase);
+ }
+ lw.WriteLine(".file alignment 0x{0:x8}", module.__FileAlignment);
+ if (GetPointerSize() == 4)
+ {
+ lw.WriteLine(".stackreserve 0x{0:x8}", module.__StackReserve);
+ }
+ else
+ {
+ lw.WriteLine(".stackreserve 0x{0:x16}", module.__StackReserve);
+ }
+ lw.WriteLine(".subsystem 0x{0:x4} // {1}", module.__Subsystem, SubsystemToString(module.__Subsystem));
+ int corflags = GetCorFlags();
+ lw.WriteLine(".corflags 0x{0:x8}{1}", corflags, CorFlagsToString(corflags));
+ }
+
+ static string CorFlagsToString(int flags)
+ {
+ StringBuilder sb = new StringBuilder();
+ if (flags != 0)
+ {
+ sb.Append(" // ");
+ }
+ if ((flags & COMIMAGE_FLAGS_ILONLY) != 0)
+ {
+ sb.Append(" ILONLY");
+ }
+ if ((flags & COMIMAGE_FLAGS_IL_LIBRARY) != 0)
+ {
+ sb.Append(" IL_LIBRARY");
+ }
+ if ((flags & COMIMAGE_FLAGS_32BITREQUIRED) != 0)
+ {
+ sb.Append(" 32BITREQUIRED");
+ }
+ return sb.ToString();
+ }
+
+ int GetCorFlags()
+ {
+ int rva;
+ int length;
+ module.__GetDataDirectoryEntry(14, out rva, out length);
+ var buf = new byte[4];
+ module.__ReadDataFromRVA(rva + 16, buf, 0, 4);
+ return BitConverter.ToInt32(buf, 0);
+ }
+
+ static string SubsystemToString(int subsystem)
+ {
+ switch (subsystem)
+ {
+ case 2:
+ return "WINDOWS_GUI";
+ case 3:
+ return "WINDOWS_CUI";
+ default:
+ throw new NotImplementedException();
+ }
+ }
+
+ void WriteCustomAttributes(LineWriter lw, int level, IEnumerable<CustomAttributeData> cas)
+ {
+ if (diffMode)
+ {
+ cas = cas.OrderBy(ca => ca.Constructor.DeclaringType.FullName);
+ }
+ foreach (var ca in cas)
+ {
+ lw.GoToColumn(level);
+ WriteCustomAttribute(lw, ca);
+ }
+ }
+
+ void WriteCustomAttribute(LineWriter lw, CustomAttributeData ca)
+ {
+ lw.Write(".custom ");
+ WriteCustomAttributeImpl(lw, ca, false, lw.Column);
+ }
+
+ void WriteCustomAttributeImpl(LineWriter lw, CustomAttributeData ca, bool comment, int level0)
+ {
+ lw.Write("instance void ");
+ WriteTypeDefOrRef(lw, ca.Constructor.DeclaringType);
+ lw.Write("::.ctor(");
+ int level = lw.Column;
+ bool first = true;
+ foreach (var parameter in ca.Constructor.GetParameters())
+ {
+ if (!first)
+ {
+ lw.WriteLine(",");
+ if (comment)
+ {
+ lw.Write(" //");
+ }
+ lw.GoToColumn(level);
+ }
+ first = false;
+ WriteSignatureType(lw, parameter.ParameterType);
+ WriteCustomModifiers(lw, parameter.__GetCustomModifiers());
+ }
+ byte[] blob = ca.__GetBlob();
+ if (blob.Length == 0)
+ {
+ lw.WriteLine(")");
+ }
+ else
+ {
+ var wrap = lw.Column >= 80;
+ var sb = new StringBuilder();
+ if (DecodeCABlob(sb, ca.Constructor, blob, wrap ? (level0 + 4) * (comment ? -1 : 1) : lw.Column + 5))
+ {
+ lw.Write(")");
+ if (wrap)
+ {
+ lw.WriteLine();
+ if (comment)
+ {
+ lw.Write(" //");
+ }
+ lw.GoToColumn(level0);
+ }
+ lw.Write(" = {{{0}", sb);
+ lw.WriteLine("}");
+ }
+ else
+ {
+ lw.Write(") = ( ");
+ WriteBytes(lw, blob, false);
+ lw.WriteLine();
+ }
+ }
+ }
+
+ void WriteModuleOrAssemblyRef(LineWriter lw, Module mod)
+ {
+ if (mod.Assembly != assembly)
+ {
+ lw.Write("[{0}]", QuoteIdentifier(referencedAssemblies[mod.Assembly]));
+ }
+ else if (mod != this.module)
+ {
+ lw.Write("[.module {0}]", QuoteIdentifier(mod.Name));
+ }
+ }
+
+ void WriteSignatureType(LineWriter lw, Type type)
+ {
+ WriteSignatureType(lw, type, TypeLocation.General);
+ }
+
+ enum TypeLocation
+ {
+ General,
+ MemberRef,
+ MemberRefNoWrap,
+ DeclaringType,
+ MethodGenericParameter,
+ Local,
+ Parameter,
+ GenericMethodImpl,
+ }
+
+ void WriteSignatureType(LineWriter lw, Type type, TypeLocation loc)
+ {
+ WriteSignatureType(lw, type, loc, false);
+ }
+
+ void WriteSignatureType(LineWriter lw, Type type, TypeLocation loc, bool skipGenArgs)
+ {
+ if (type.__IsVector)
+ {
+ WriteSignatureType(lw, type.GetElementType(), loc);
+ WriteCustomModifiers(lw, type.__GetCustomModifiers());
+ lw.Write("[]");
+ }
+ else if (type.IsArray)
+ {
+ WriteSignatureType(lw, type.GetElementType(), loc);
+ WriteCustomModifiers(lw, type.__GetCustomModifiers());
+ lw.Write("[");
+ string sep = "";
+ int[] lower = type.__GetArrayLowerBounds();
+ foreach (var lb in lower)
+ {
+ lw.Write(sep);
+ sep = ",";
+ lw.Write("{0}...", lb);
+ }
+ for (int i = lower.Length + 1, rank = type.GetArrayRank(); i < rank; i++)
+ {
+ lw.Write(",");
+ }
+ lw.Write("]");
+ }
+ else if (type.IsByRef)
+ {
+ WriteSignatureType(lw, type.GetElementType(), loc);
+ WriteCustomModifiers(lw, type.__GetCustomModifiers());
+ lw.Write("&");
+ }
+ else if (type.IsPointer)
+ {
+ WriteSignatureType(lw, type.GetElementType(), loc);
+ WriteCustomModifiers(lw, type.__GetCustomModifiers());
+ lw.Write("*");
+ }
+ else if (type.__IsFunctionPointer)
+ {
+ WriteStandAloneMethodSig(lw, type.__MethodSignature, true, loc == TypeLocation.Local || loc == TypeLocation.Parameter || loc == TypeLocation.MemberRef);
+ }
+ else if (!type.__IsMissing && type.IsGenericType && !type.IsGenericTypeDefinition)
+ {
+ WriteSignatureType(lw, type.GetGenericTypeDefinition(), loc, true);
+ lw.Write("<");
+ string sep = "";
+ Type[] args = type.GetGenericArguments();
+ CustomModifiers[] mods = type.__GetGenericArgumentsCustomModifiers();
+ for (int i = 0; i < args.Length; i++)
+ {
+ lw.Write(sep);
+ WriteSignatureType(lw, args[i], loc);
+ WriteCustomModifiers(lw, mods[i]);
+ sep = ",";
+ }
+ lw.Write(">");
+ }
+ else if (type.IsGenericParameter)
+ {
+ if (type.DeclaringMethod != null)
+ {
+ lw.Write("!!{0}",
+ loc == TypeLocation.MemberRef || loc == TypeLocation.MemberRefNoWrap || loc == TypeLocation.DeclaringType || loc == TypeLocation.MethodGenericParameter || type.Name == null
+ ? (object)type.GenericParameterPosition
+ : QuoteIdentifier(type.Name));
+ }
+ else
+ {
+ lw.Write("!{0}",
+ loc == TypeLocation.MemberRef || loc == TypeLocation.MemberRefNoWrap || loc == TypeLocation.GenericMethodImpl || type.Name == null
+ ? (object)type.GenericParameterPosition
+ : QuoteIdentifier(type.Name));
+ }
+ }
+ else if (type == typeofSystemBoolean)
+ {
+ lw.Write("bool");
+ }
+ else if (type == typeofSystemSByte)
+ {
+ lw.Write("int8");
+ }
+ else if (type == typeofSystemByte)
+ {
+ lw.Write("uint8");
+ }
+ else if (type == typeofSystemChar)
+ {
+ lw.Write("char");
+ }
+ else if (type == typeofSystemInt16)
+ {
+ lw.Write("int16");
+ }
+ else if (type == typeofSystemUInt16)
+ {
+ lw.Write("uint16");
+ }
+ else if (type == typeofSystemInt32)
+ {
+ lw.Write("int32");
+ }
+ else if (type == typeofSystemUInt32)
+ {
+ lw.Write("uint32");
+ }
+ else if (type == typeofSystemInt64)
+ {
+ lw.Write("int64");
+ }
+ else if (type == typeofSystemUInt64)
+ {
+ lw.Write("uint64");
+ }
+ else if (type == typeofSystemSingle)
+ {
+ lw.Write("float32");
+ }
+ else if (type == typeofSystemDouble)
+ {
+ lw.Write("float64");
+ }
+ else if (type == typeofSystemString)
+ {
+ lw.Write("string");
+ }
+ else if (type == typeofSystemObject)
+ {
+ lw.Write("object");
+ }
+ else if (type == typeofSystemVoid)
+ {
+ lw.Write("void");
+ }
+ else if (type == typeofSystemIntPtr)
+ {
+ lw.Write("native int");
+ }
+ else if (type == typeofSystemUIntPtr)
+ {
+ lw.Write("native uint");
+ }
+ else if (type == typeofSystemTypedReference)
+ {
+ lw.Write("typedref");
+ }
+ else
+ {
+ lw.Write(type.IsValueType ? "valuetype " : "class ");
+ WriteModuleOrAssemblyRef(lw, type.Module);
+ WriteTypeName(lw, type);
+ if (!skipGenArgs && !type.__IsMissing && type.IsGenericTypeDefinition)
+ {
+ lw.Write("<");
+ string sep = "";
+ Type[] args = type.GetGenericArguments();
+ CustomModifiers[] mods = type.__GetGenericArgumentsCustomModifiers();
+ for (int i = 0; i < args.Length; i++)
+ {
+ lw.Write(sep);
+ WriteSignatureType(lw, args[i], loc);
+ WriteCustomModifiers(lw, mods[i]);
+ sep = ",";
+ }
+ lw.Write(">");
+ }
+ }
+ }
+
+ void WriteStandAloneMethodSig(LineWriter lw, __StandAloneMethodSig sig, bool type, bool wrap)
+ {
+ int level = lw.Column;
+ if (type)
+ {
+ lw.Write("method ");
+ }
+ if (sig.IsUnmanaged)
+ {
+ lw.Write("unmanaged ");
+ switch (sig.UnmanagedCallingConvention)
+ {
+ case System.Runtime.InteropServices.CallingConvention.Cdecl:
+ lw.Write("cdecl ");
+ break;
+ case System.Runtime.InteropServices.CallingConvention.StdCall:
+ lw.Write("stdcall ");
+ break;
+ case System.Runtime.InteropServices.CallingConvention.ThisCall:
+ lw.Write("thiscall ");
+ break;
+ }
+ }
+ else
+ {
+ WriteCallingConvention(lw, sig.CallingConvention);
+ }
+ WriteSignatureType(lw, sig.ReturnType);
+ WriteCustomModifiers(lw, sig.GetReturnTypeCustomModifiers());
+ lw.Write(type ? " *(" : "(");
+ Type[] parameters = sig.ParameterTypes;
+ for (int i = 0; i < parameters.Length; i++)
+ {
+ if (i != 0)
+ {
+ if (wrap)
+ {
+ lw.WriteLine(",");
+ lw.GoToColumn(level);
+ }
+ else
+ {
+ lw.Write(",");
+ }
+ }
+ WriteSignatureType(lw, parameters[i]);
+ WriteCustomModifiers(lw, sig.GetParameterCustomModifiers(i));
+ }
+ lw.Write(")");
+ }
+
+ private void WriteCallingConvention(LineWriter lw, CallingConventions callingConvention)
+ {
+ if ((callingConvention & CallingConventions.HasThis) != 0)
+ {
+ lw.Write("instance ");
+ }
+ if ((callingConvention & CallingConventions.VarArgs) != 0)
+ {
+ lw.Write("vararg ");
+ }
+ }
+
+ void WriteTypeName(LineWriter lw, Type type)
+ {
+ if (type.IsNested)
+ {
+ WriteTypeName(lw, type.DeclaringType);
+ lw.Write("/");
+ }
+ WriteTypeNameNoOuter(lw, type);
+ }
+
+ void WriteTypeNameNoOuter(LineWriter lw, Type type)
+ {
+ if (type.__Namespace != null)
+ {
+ lw.Write("{0}.", QuoteIdentifier(type.__Namespace));
+ }
+ lw.Write("{0}", QuoteIdentifier(type.__Name));
+ }
+
+ void WriteTypeDefOrRef(LineWriter lw, Type type)
+ {
+ if (type.IsGenericParameter)
+ {
+ lw.Write(type.DeclaringMethod == null ? "!" : "!!");
+ lw.Write("{0}", QuoteIdentifier(type.Name));
+ }
+ else if (type.IsArray)
+ {
+ WriteSignatureType(lw, type, TypeLocation.General);
+ }
+ else
+ {
+ WriteModuleOrAssemblyRef(lw, type.Module);
+ WriteTypeName(lw, type);
+ }
+ }
+
+ static void WriteBytes(LineWriter lw, byte[] buf, bool data)
+ {
+ bool hasText = false;
+ int column = lw.Column;
+ for (int i = 0; i < buf.Length; i++)
+ {
+ if (i != 0)
+ {
+ if (i % 16 == 0)
+ {
+ if (hasText)
+ {
+ hasText = false;
+ lw.Write(data ? " // " : " // ");
+ for (int j = i - 16; j < i; j++)
+ {
+ lw.Write("{0}", IsText(buf[j]) ? (char)buf[j] : '.');
+ }
+ }
+ else if (!data)
+ {
+ lw.Write(" ");
+ }
+ lw.WriteLine();
+ lw.GoToColumn(column);
+ }
+ else
+ {
+ lw.Write(" ");
+ }
+ }
+ lw.Write("{0:X2}", buf[i]);
+ hasText |= IsText(buf[i]);
+ }
+ if (!data)
+ {
+ lw.Write(" ");
+ }
+ lw.Write(") ");
+ if (hasText)
+ {
+ lw.GoToColumn(column + 16 * 3 + (data ? 1 : 2));
+ lw.Write("// ");
+ for (int j = (buf.Length + 15 & ~15) - 16; j < buf.Length; j++)
+ {
+ lw.Write("{0}", IsText(buf[j]) ? (char)buf[j] : '.');
+ }
+ }
+ }
+
+ static bool IsText(byte b)
+ {
+ return b >= 32 && b < 127;
+ }
+ }
+}
diff --git a/ExportedMethods.cs b/ExportedMethods.cs
new file mode 100644
index 0000000..2e8eafd
--- /dev/null
+++ b/ExportedMethods.cs
@@ -0,0 +1,167 @@
+/*
+ Copyright (C) 2012 Jeroen Frijters
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ Jeroen Frijters
+ jeroen@frijters.net
+
+*/
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.IO;
+using IKVM.Reflection;
+
+namespace Ildasm
+{
+ partial class Disassembler
+ {
+ struct ExportDirectoryTable
+ {
+ internal uint Flags;
+ internal uint DateTimeStamp;
+ internal ushort MajorVersion;
+ internal ushort MinorVersion;
+ internal uint NameRVA;
+ internal uint OrdinalBase;
+ internal uint AddressTableEntries;
+ internal uint NumberOfNamePointers;
+ internal uint ExportAddressTableRVA;
+ internal uint NamePointerRVA;
+ internal uint OrdinalTableRVA;
+
+ internal void Read(BinaryReader br)
+ {
+ Flags = br.ReadUInt32();
+ DateTimeStamp = br.ReadUInt32();
+ MajorVersion = br.ReadUInt16();
+ MinorVersion = br.ReadUInt16();
+ NameRVA = br.ReadUInt32();
+ OrdinalBase = br.ReadUInt32();
+ AddressTableEntries = br.ReadUInt32();
+ NumberOfNamePointers = br.ReadUInt32();
+ ExportAddressTableRVA = br.ReadUInt32();
+ NamePointerRVA = br.ReadUInt32();
+ OrdinalTableRVA = br.ReadUInt32();
+ }
+ }
+
+ struct ExportedMethod
+ {
+ internal int ordinal;
+ internal string name;
+ }
+
+ static Dictionary<int, List<ExportedMethod>> GetExportedMethods(Module module)
+ {
+ int rva;
+ int length;
+ module.__GetDataDirectoryEntry(0, out rva, out length);
+
+ if (rva == 0 || length < 40)
+ {
+ return new Dictionary<int, List<ExportedMethod>>();
+ }
+
+ ExportDirectoryTable edt = new ExportDirectoryTable();
+ byte[] buf = new byte[512];
+ module.__ReadDataFromRVA(rva, buf, 0, 40);
+ edt.Read(new BinaryReader(new MemoryStream(buf)));
+
+ var methods = new Dictionary<int, List<ExportedMethod>>();
+ for (int i = 0; i < edt.NumberOfNamePointers; i++)
+ {
+ module.__ReadDataFromRVA((int)edt.OrdinalTableRVA + i * 2, buf, 0, 2);
+ int ordinal = BitConverter.ToInt16(buf, 0) + (int)edt.OrdinalBase;
+ string name = null;
+ if (edt.NamePointerRVA != 0)
+ {
+ module.__ReadDataFromRVA((int)edt.NamePointerRVA + i * 4, buf, 0, 4);
+ module.__ReadDataFromRVA(BitConverter.ToInt32(buf, 0), buf, 0, buf.Length);
+ int len = 0;
+ while (buf[len] != 0) len++;
+ name = Encoding.ASCII.GetString(buf, 0, len);
+ }
+ int token = GetTokenFromExportOrdinal(module, edt, ordinal);
+ if (token == -1)
+ {
+ continue;
+ }
+ List<ExportedMethod> list;
+ if (!methods.TryGetValue(token, out list))
+ {
+ list = new List<ExportedMethod>();
+ methods.Add(token, list);
+ }
+ ExportedMethod method;
+ method.name = name;
+ method.ordinal = ordinal;
+ list.Add(method);
+ }
+ return methods;
+ }
+
+ static int GetTokenFromExportOrdinal(Module module, ExportDirectoryTable edt, int ordinal)
+ {
+ PortableExecutableKinds peKind;
+ ImageFileMachine machine;
+ module.GetPEKind(out peKind, out machine);
+ byte[] buf = new byte[16];
+ module.__ReadDataFromRVA((int)edt.ExportAddressTableRVA + (int)(ordinal - edt.OrdinalBase) * 4, buf, 0, 4);
+ int exportRVA = BitConverter.ToInt32(buf, 0);
+ if (machine == ImageFileMachine.ARM)
+ {
+ // mask out the instruction set selection flag
+ exportRVA &= ~1;
+ }
+ module.__ReadDataFromRVA(exportRVA, buf, 0, 16);
+ int offset;
+ if (machine == ImageFileMachine.I386 && buf[0] == 0xFF && buf[1] == 0x25)
+ {
+ // for x86 the code here is:
+ // FF 25 00 40 40 00 jmp dword ptr ds:[00404000h]
+ offset = 2;
+ }
+ else if (machine == ImageFileMachine.AMD64 && buf[0] == 0x48 && buf[1] == 0xA1)
+ {
+ // for x64 the code here is:
+ // 48 A1 00 40 40 00 00 00 00 00 mov rax,qword ptr [0000000000404000h]
+ // FF E0 jmp rax
+ offset = 2;
+ }
+ else if (machine == ImageFileMachine.ARM && buf[0] == 0xDF && buf[1] == 0xF8 && buf[2] == 0x08 && buf[3] == 0xC0)
+ {
+ // for arm the code here is:
+ // F8DF C008 ldr r12,0040145C
+ // F8DC C000 ldr r12,[r12]
+ // 4760 bx r12
+ // DEFE __debugbreak
+ // here is the RVA
+ offset = 12;
+ }
+ else
+ {
+ return -1;
+ }
+ int vtableRVA = BitConverter.ToInt32(buf, offset) - (int)module.__ImageBase;
+ module.__ReadDataFromRVA(vtableRVA, buf, 0, 4);
+ return BitConverter.ToInt32(buf, 0);
+ }
+ }
+}
diff --git a/IKVM.Reflection.dll b/IKVM.Reflection.dll
new file mode 100644
index 0000000..d79cd45
--- /dev/null
+++ b/IKVM.Reflection.dll
Binary files differ
diff --git a/IL.cs b/IL.cs
new file mode 100644
index 0000000..1abd52d
--- /dev/null
+++ b/IL.cs
@@ -0,0 +1,1040 @@
+/*
+ Copyright (C) 2012 Jeroen Frijters
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ Jeroen Frijters
+ jeroen@frijters.net
+
+*/
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using IKVM.Reflection;
+using IKVM.Reflection.Emit;
+using Type = IKVM.Reflection.Type;
+using System.Diagnostics;
+
+namespace Ildasm
+{
+ sealed partial class Disassembler : IComparer<ExceptionHandlingClause>
+ {
+ static readonly OpCode[] opcodes = GetOpCodes();
+
+ static OpCode[] GetOpCodes()
+ {
+ OpCode[] opcodes = new OpCode[768];
+ foreach (System.Reflection.FieldInfo field in typeof(OpCodes).GetFields())
+ {
+ OpCode opc = (OpCode)field.GetValue(null);
+ opcodes[opc.Value + 512] = opc;
+ }
+ return opcodes;
+ }
+
+ void WriteIL(LineWriter lw, MethodBase mb, MethodBody body, Type[] genericTypeArguments, Type[] genericMethodArguments)
+ {
+ ParameterInfo[] parameters = mb.GetParameters();
+ int level = lw.Column;
+ byte[] code = body.GetILAsByteArray();
+ lw.GoToColumn(level);
+ lw.WriteLine("// Code size {0} (0x{0:x})", code.Length);
+ lw.GoToColumn(level);
+ lw.WriteLine(".maxstack {0}", body.MaxStackSize);
+
+ IList<LocalVariableInfo> locals = body.LocalVariables;
+ if (locals.Count != 0)
+ {
+ lw.GoToColumn(level);
+ lw.Write(".locals ");
+ if (body.InitLocals)
+ {
+ lw.Write("init ");
+ }
+ lw.Write("(");
+ bool first = true;
+ foreach (var local in locals)
+ {
+ if (!first)
+ {
+ lw.WriteLine(",");
+ lw.GoToColumn(level + 9);
+ }
+ first = false;
+ WriteSignatureType(lw, local.LocalType, TypeLocation.Local);
+ if (local.IsPinned)
+ {
+ lw.Write(" pinned");
+ }
+ WriteCustomModifiers(lw, local.__GetCustomModifiers());
+ lw.Write(" V_{0}", local.LocalIndex);
+ }
+ lw.WriteLine(")");
+ }
+
+ var exceptions = new List<ExceptionHandlingClause>();
+ var exceptions2 = new List<ExceptionHandlingClause>();
+ SortExceptions(body.ExceptionHandlingClauses, exceptions, exceptions2);
+
+ Stack<ExceptionHandlingClause> activeExceptions = new Stack<ExceptionHandlingClause>();
+ ExceptionHandlingClause currentException = null;
+ bool extraNewLine = false;
+ int nextFlatException = 0;
+ int nextException = 0;
+ bool handler = false;
+ int pos = 0;
+ while (pos < code.Length)
+ {
+ if (extraNewLine)
+ {
+ lw.WriteLine();
+ extraNewLine = false;
+ }
+ if (currentException != null)
+ {
+ if (currentException.HandlerOffset == pos)
+ {
+ switch (currentException.Flags)
+ {
+ case ExceptionHandlingClauseOptions.Clause:
+ lw.GoToColumn(level - 2);
+ if (currentException.TryOffset + currentException.TryLength == pos)
+ {
+ lw.WriteLine("} // end .try");
+ }
+ else
+ {
+ lw.WriteLine("} // end handler");
+ }
+ lw.GoToColumn(level - 2);
+ lw.Write("catch ");
+ if (currentException.CatchType.__IsMissing || !currentException.CatchType.IsGenericType)
+ {
+ WriteTypeDefOrRef(lw, currentException.CatchType);
+ }
+ else
+ {
+ WriteSignatureType(lw, currentException.CatchType);
+ }
+ lw.WriteLine(" ");
+ lw.GoToColumn(level - 2);
+ lw.WriteLine("{");
+ handler = true;
+ break;
+ case ExceptionHandlingClauseOptions.Finally:
+ lw.GoToColumn(level - 2);
+ lw.WriteLine("} // end .try");
+ lw.GoToColumn(level - 2);
+ lw.WriteLine("finally");
+ lw.GoToColumn(level - 2);
+ lw.WriteLine("{");
+ break;
+ case ExceptionHandlingClauseOptions.Fault:
+ lw.GoToColumn(level - 2);
+ lw.WriteLine("} // end .try");
+ lw.GoToColumn(level - 2);
+ lw.WriteLine("fault");
+ lw.GoToColumn(level - 2);
+ lw.WriteLine("{");
+ break;
+ case ExceptionHandlingClauseOptions.Filter:
+ lw.GoToColumn(level - 2);
+ lw.WriteLine("} // end filter");
+ lw.GoToColumn(level - 2);
+ lw.WriteLine("{ // handler");
+ handler = true;
+ break;
+ default:
+ throw new IKVM.Reflection.BadImageFormatException();
+ }
+ }
+ else if (currentException.FilterOffset == pos && pos != 0)
+ {
+ lw.GoToColumn(level - 2);
+ if (handler)
+ {
+ lw.WriteLine("} // end handler");
+ }
+ else
+ {
+ lw.WriteLine("} // end .try");
+ }
+ lw.GoToColumn(level - 2);
+ lw.WriteLine("filter");
+ lw.GoToColumn(level - 2);
+ lw.WriteLine("{");
+ }
+ }
+ while (nextException < exceptions.Count
+ && exceptions[nextException].TryOffset == pos)
+ {
+ activeExceptions.Push(currentException);
+ ExceptionHandlingClause prevException = currentException;
+ currentException = exceptions[nextException++];
+ if (prevException != null && currentException.TryOffset == prevException.TryOffset && currentException.TryLength == prevException.TryLength)
+ {
+ // another handler for the same block
+ continue;
+ }
+ handler = false;
+ lw.GoToColumn(level);
+ lw.WriteLine(".try");
+ lw.GoToColumn(level);
+ lw.WriteLine("{");
+ level += 2;
+ }
+ lw.GoToColumn(level);
+ int currPos = pos;
+ lw.Write("IL_{0:x4}: ", pos);
+ int level1 = lw.Column;
+ short opcodeValue = code[pos++];
+ if (opcodeValue == 0xFE)
+ {
+ opcodeValue = (short)(0xFE00 + code[pos++]);
+ }
+ OpCode opcode = opcodes[opcodeValue + 512];
+ lw.Write("{0}", opcode.Name);
+ switch (opcode.OperandType)
+ {
+ case OperandType.InlineNone:
+ break;
+ case OperandType.InlineBrTarget:
+ lw.GoToColumn(level1 + 11);
+ lw.Write("IL_{0:x4}", ReadInt32(code, ref pos) + pos);
+ break;
+ case OperandType.ShortInlineBrTarget:
+ lw.GoToColumn(level1 + 11);
+ lw.Write("IL_{0:x4}", (sbyte)code[pos++] + pos);
+ break;
+ case OperandType.InlineMethod:
+ {
+ lw.GoToColumn(level1 + 11);
+ int token = ReadInt32(code, ref pos);
+ MethodBase methodOrConstructor = ResolveMethod(token, genericTypeArguments, genericMethodArguments);
+ if ((methodOrConstructor.CallingConvention & CallingConventions.Any) == CallingConventions.VarArgs)
+ {
+ CustomModifiers[] customModifiers;
+ Type[] optionalParameterTypes = ResolveOptionalParameterTypes(token, genericTypeArguments, genericMethodArguments, out customModifiers);
+ WriteInlineMethod(lw, methodOrConstructor, optionalParameterTypes, customModifiers);
+ }
+ else
+ {
+ WriteInlineMethod(lw, methodOrConstructor, Type.EmptyTypes, null);
+ }
+ }
+ break;
+ case OperandType.InlineField:
+ lw.GoToColumn(level1 + 11);
+ WriteInlineField(lw, ResolveField(ReadInt32(code, ref pos), genericTypeArguments, genericMethodArguments));
+ break;
+ case OperandType.InlineI:
+ lw.GoToColumn(level1 + 11);
+ WriteInlineI(lw, ReadInt32(code, ref pos));
+ break;
+ case OperandType.InlineI8:
+ lw.GoToColumn(level1 + 11);
+ WriteInlineI8(lw, ReadInt64(code, ref pos));
+ break;
+ case OperandType.ShortInlineI:
+ lw.GoToColumn(level1 + 11);
+ lw.Write("{0}", (sbyte)code[pos++]);
+ break;
+ case OperandType.InlineR:
+ lw.GoToColumn(level1 + 11);
+ WriteInlineR(lw, ReadDouble(code, ref pos), false);
+ break;
+ case OperandType.ShortInlineR:
+ lw.GoToColumn(level1 + 11);
+ WriteShortInlineR(lw, ReadSingle(code, ref pos), false);
+ break;
+ case OperandType.InlineType:
+ if (opcode == OpCodes.Constrained)
+ {
+ // "constrained." is too long to fit in the opcode column
+ lw.Write(" ");
+ }
+ else
+ {
+ lw.GoToColumn(level1 + 11);
+ }
+ WriteInlineType(lw, ReadInt32(code, ref pos), genericTypeArguments, genericMethodArguments);
+ break;
+ case OperandType.InlineTok:
+ {
+ int token = ReadInt32(code, ref pos);
+ switch (token >> 24)
+ {
+ case 0x01:
+ case 0x02:
+ lw.GoToColumn(level1 + 11);
+ WriteTypeDefOrRef(lw, ResolveType(token, genericTypeArguments, genericMethodArguments));
+ break;
+ case 0x1B:
+ {
+ Type type = ResolveType(token, genericTypeArguments, genericMethodArguments);
+ if (type.IsGenericTypeDefinition)
+ {
+ // HACK because typeof(Foo<>).MakeGenericType(typeof(Foo<>).GetGenericArguments()) == typeof(Foo<>)
+ // we need to inflate the builder here
+ type = type.MakeGenericType(type.GetGenericArguments());
+ }
+ lw.GoToColumn(level1 + 11);
+ WriteSignatureType(lw, type);
+ break;
+ }
+ case 0x04:
+ case 0x06:
+ case 0x0A:
+ case 0x2B:
+ {
+ MemberInfo member = ResolveMember(token, genericTypeArguments, genericMethodArguments);
+ if (member is FieldInfo)
+ {
+ lw.GoToColumn(level1 + 11);
+ lw.Write("field ");
+ WriteInlineField(lw, (FieldInfo)member);
+ }
+ else
+ {
+ var mb1 = (MethodBase)member;
+ lw.GoToColumn(level1 + 11);
+ if (mb1.__IsMissing || !mb1.IsGenericMethod || compat != CompatLevel.V20)
+ {
+ lw.Write("method ");
+ }
+ WriteInlineMethod(lw, mb1, Type.EmptyTypes, null);
+ }
+ break;
+ }
+ default:
+ throw new NotImplementedException("token type = " + (token >> 24));
+ }
+ }
+ break;
+ case OperandType.InlineVar:
+ lw.GoToColumn(level1 + 11);
+ WriteInlineVar(lw, mb, opcode, parameters, ReadInt16(code, ref pos));
+ break;
+ case OperandType.ShortInlineVar:
+ lw.GoToColumn(level1 + 11);
+ WriteInlineVar(lw, mb, opcode, parameters, code[pos++]);
+ break;
+ case OperandType.InlineString:
+ lw.GoToColumn(level1 + 11);
+ WriteInlineString(lw, module.ResolveString(ReadInt32(code, ref pos)), level);
+ break;
+ case OperandType.InlineSwitch:
+ {
+ lw.GoToColumn(level1 + 11);
+ lw.WriteLine("( ");
+ int count = ReadInt32(code, ref pos);
+ int offset = pos + 4 * count;
+ for (int i = 0; i < count - 1; i++)
+ {
+ lw.GoToColumn(level + 22);
+ lw.WriteLine("IL_{0:x4},", offset + ReadInt32(code, ref pos));
+ }
+ lw.GoToColumn(level + 22);
+ lw.Write("IL_{0:x4})", offset + ReadInt32(code, ref pos));
+ }
+ break;
+ case OperandType.InlineSig:
+ lw.GoToColumn(level1 + 11);
+ WriteStandAloneMethodSig(lw, module.__ResolveStandAloneMethodSig(ReadInt32(code, ref pos), genericTypeArguments, genericMethodArguments), false, false);
+ break;
+ default:
+ throw new InvalidOperationException();
+ }
+ lw.WriteLine();
+
+ if (opcode == OpCodes.Leave || opcode == OpCodes.Leave_S)
+ {
+ if (pos < code.Length)
+ {
+ lw.WriteLine();
+ }
+ }
+ else if (opcode != OpCodes.Switch && opcode != OpCodes.Rethrow && opcode != OpCodes.Endfilter && opcode != OpCodes.Endfinally)
+ {
+ switch (opcode.FlowControl)
+ {
+ case FlowControl.Branch:
+ case FlowControl.Cond_Branch:
+ case FlowControl.Throw:
+ case FlowControl.Return:
+ extraNewLine = true;
+ break;
+ }
+ }
+ if (nextFlatException < exceptions2.Count && exceptions2[nextFlatException].HandlerOffset + exceptions2[nextFlatException].HandlerLength == currPos)
+ {
+ if (extraNewLine && pos < code.Length)
+ {
+ extraNewLine = false;
+ lw.WriteLine();
+ }
+ lw.GoToColumn(level);
+ if (exceptions2[nextFlatException].FilterOffset == 0)
+ {
+ lw.Write(".try IL_{0:x4} to IL_{1:x4} catch ", exceptions2[nextFlatException].TryOffset, exceptions2[nextFlatException].TryOffset + exceptions2[nextFlatException].TryLength);
+ if (exceptions2[nextFlatException].CatchType.__IsMissing || !exceptions2[nextFlatException].CatchType.IsGenericType)
+ {
+ WriteTypeDefOrRef(lw, exceptions2[nextFlatException].CatchType);
+ }
+ else
+ {
+ WriteSignatureType(lw, exceptions2[nextFlatException].CatchType);
+ }
+ lw.WriteLine(" handler IL_{0:x4} to IL_{1:x4}", exceptions2[nextFlatException].HandlerOffset, exceptions2[nextFlatException].HandlerOffset + exceptions2[nextFlatException].HandlerLength);
+ }
+ else
+ {
+ lw.WriteLine(".try IL_{0:x4} to IL_{1:x4} filter IL_{2:x4} handler IL_{3:x4} to IL_{4:x4}",
+ exceptions2[nextFlatException].TryOffset, exceptions2[nextFlatException].TryOffset + exceptions2[nextFlatException].TryLength,
+ exceptions2[nextFlatException].FilterOffset,
+ exceptions2[nextFlatException].HandlerOffset, exceptions2[nextFlatException].HandlerOffset + exceptions2[nextFlatException].HandlerLength);
+ }
+ nextFlatException++;
+ }
+
+ while (currentException != null && currentException.HandlerOffset + currentException.HandlerLength == pos)
+ {
+ ExceptionHandlingClause prevException = currentException;
+ currentException = activeExceptions.Pop();
+ if (currentException == null || currentException.TryOffset != prevException.TryOffset || currentException.TryLength != prevException.TryLength)
+ {
+ if (extraNewLine && pos < code.Length)
+ {
+ extraNewLine = false;
+ lw.WriteLine();
+ }
+ level -= 2;
+ lw.GoToColumn(level);
+ lw.WriteLine("} // end handler");
+ handler = false;
+ }
+ else
+ {
+ handler = true;
+ }
+ }
+ }
+ }
+
+ void WriteInlineVar(LineWriter lw, MethodBase mb, OpCode opcode, ParameterInfo[] parameters, int index)
+ {
+ if (opcode == OpCodes.Ldarg_S
+ || opcode == OpCodes.Starg_S
+ || opcode == OpCodes.Ldarga_S
+ || opcode == OpCodes.Ldarg
+ || opcode == OpCodes.Starg
+ || opcode == OpCodes.Ldarga)
+ {
+ ParameterInfo param = mb.IsStatic ? parameters[index] : index == 0 ? null : parameters[index - 1];
+ if (param == null)
+ {
+ // this
+ lw.Write("0");
+ }
+ else if (param.Name == null)
+ {
+ lw.Write("A_{0}", index);
+ }
+ else
+ {
+ lw.Write("{0}", QuoteIdentifier(param.Name));
+ }
+ }
+ else
+ {
+ lw.Write("V_{0}", index);
+ }
+ }
+
+ static int FloatToInt32Bits(float v)
+ {
+ return IKVM.Reflection.Reader.SingleConverter.SingleToInt32Bits(v);
+ }
+
+ string ToString(float value, bool field)
+ {
+ if (value == 0 && !field)
+ {
+ return FloatToInt32Bits(value) < 0
+ ? "-0.0"
+ : "0.0";
+ }
+ else if (compat != CompatLevel.None)
+ {
+ byte[] buf = new byte[50];
+ _gcvt(value, 8, buf);
+ string str = Encoding.ASCII.GetString(buf, 0, Array.IndexOf(buf, (byte)0));
+ float v2;
+ if (Single.TryParse(str, out v2) && FloatToInt32Bits(value) == FloatToInt32Bits(v2))
+ {
+ return str;
+ }
+ else
+ {
+ if (field)
+ {
+ return String.Format("0x{0:X}", FloatToInt32Bits(value));
+ }
+ else
+ {
+ byte[] buf2 = BitConverter.GetBytes(value);
+ return String.Format("({0:X2} {1:X2} {2:X2} {3:X2})", buf2[0], buf2[1], buf2[2], buf2[3]);
+ }
+ }
+ }
+ else if (Single.IsInfinity(value) || Single.IsNaN(value))
+ {
+ if (field)
+ {
+ return String.Format("0x{0:X}", FloatToInt32Bits(value));
+ }
+ else
+ {
+ byte[] buf = BitConverter.GetBytes(value);
+ return String.Format("({0:X2} {1:X2} {2:X2} {3:X2})", buf[0], buf[1], buf[2], buf[3]);
+ }
+ }
+ else
+ {
+ return String.Format("{0:R}", value);
+ }
+ }
+
+ void WriteShortInlineR(LineWriter lw, float value, bool field)
+ {
+ lw.Write(ToString(value, field));
+ }
+
+ [System.Runtime.InteropServices.DllImport("msvcrt.dll", CallingConvention = System.Runtime.InteropServices.CallingConvention.Cdecl)]
+ static extern IntPtr _gcvt(double value, int digits, byte[] buffer);
+
+ string ToString(double value, bool field)
+ {
+ if (value == 0 && !field)
+ {
+ return BitConverter.DoubleToInt64Bits(value) < 0
+ ? "-0.0"
+ : "0.0";
+ }
+ else if (compat != CompatLevel.None)
+ {
+ byte[] buf = new byte[50];
+ _gcvt(value, 17, buf);
+ string str = Encoding.ASCII.GetString(buf, 0, Array.IndexOf(buf, (byte)0));
+ double v2;
+ if (Double.TryParse(str, out v2) && BitConverter.DoubleToInt64Bits(value) == BitConverter.DoubleToInt64Bits(v2))
+ {
+ return str;
+ }
+ else
+ {
+ if (field)
+ {
+ return String.Format("0x{0:X}", BitConverter.DoubleToInt64Bits(value));
+ }
+ else
+ {
+ byte[] buf2 = BitConverter.GetBytes(value);
+ return String.Format("({0:X2} {1:X2} {2:X2} {3:X2} {4:X2} {5:X2} {6:X2} {7:X2})", buf2[0], buf2[1], buf2[2], buf2[3], buf2[4], buf2[5], buf2[6], buf2[7]);
+ }
+ }
+ }
+ else if (Double.IsInfinity(value) || Double.IsNaN(value))
+ {
+ if (field)
+ {
+ return String.Format("0x{0:X}", BitConverter.DoubleToInt64Bits(value));
+ }
+ else
+ {
+ byte[] buf = BitConverter.GetBytes(value);
+ return String.Format("({0:X2} {1:X2} {2:X2} {3:X2} {4:X2} {5:X2} {6:X2} {7:X2})", buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]);
+ }
+ }
+ else
+ {
+ return String.Format("{0:R}", value.ToString("R"));
+ }
+ }
+
+ void WriteInlineR(LineWriter lw, double value, bool field)
+ {
+ lw.Write(ToString(value, field));
+ }
+
+ void WriteInlineString(LineWriter lw, string str, int level)
+ {
+ int initial = 44 - lw.Column + level;
+ int pos = 44;
+ StringBuilder sb = new StringBuilder(str.Length + 10);
+ int backslashes = 0;
+ for (int i = 0; i < str.Length; i++)
+ {
+ char c = str[i];
+ if (i < str.Length - 2 && ((pos == 94 && pos - initial != backslashes) || pos > 94))
+ {
+ if (pos - initial == backslashes)
+ {
+ sb.Append('\\', backslashes * 2);
+ backslashes = 0;
+ }
+ pos = initial + backslashes;
+ sb.Append("\"\r\n");
+ sb.Append(' ', level);
+ sb.Append("+ \"");
+ }
+ if (c == '\\')
+ {
+ backslashes++;
+ }
+ else if (backslashes != 0)
+ {
+ sb.Append('\\', backslashes * 2);
+ backslashes = 0;
+ }
+ if (c < 32)
+ {
+ switch (c)
+ {
+ case '\r':
+ sb.Append("\\r");
+ break;
+ case '\n':
+ sb.Append("\\n");
+ break;
+ case '\t':
+ sb.Append("\\t");
+ break;
+ default:
+ lw.Write("bytearray (");
+ WriteBytes(lw, GetBytes(str), false);
+ return;
+ }
+ }
+ else if (c > 126)
+ {
+ lw.Write("bytearray (");
+ WriteBytes(lw, GetBytes(str), false);
+ return;
+ }
+ else
+ {
+ switch (c)
+ {
+ case '"':
+ sb.Append("\\\"");
+ break;
+ case '?':
+ sb.Append("\\?");
+ break;
+ case '\\':
+ break;
+ default:
+ sb.Append(c);
+ break;
+ }
+ }
+ pos++;
+ }
+ sb.Append('\\', backslashes * 2);
+ lw.Write("\"{0}\"", sb);
+ }
+
+ static byte[] GetBytes(string str)
+ {
+ byte[] buf = new byte[str.Length * 2];
+ for (int i = 0; i < str.Length; i++)
+ {
+ char ch = str[i];
+ buf[i * 2 + 0] = (byte)(ch >> 0);
+ buf[i * 2 + 1] = (byte)(ch >> 8);
+ }
+ return buf;
+ }
+
+ void WriteInlineI(LineWriter lw, int value)
+ {
+ if (value >= 128 || value < 128)
+ {
+ lw.Write("0x{0:x}", value);
+ }
+ else
+ {
+ lw.Write("{0}", value);
+ }
+ }
+
+ void WriteInlineI8(LineWriter lw, long value)
+ {
+ if (value >= 128 || value < 128)
+ {
+ lw.Write("0x{0:x}", value);
+ }
+ else
+ {
+ lw.Write("{0}", value);
+ }
+ }
+
+ static bool IsArrayOfGenericParameter(Type type)
+ {
+ if (type != null && type.IsArray)
+ {
+ while (type.IsArray)
+ {
+ type = type.GetElementType();
+ }
+ return !type.__IsMissing && type.IsGenericParameter;
+ }
+ return false;
+ }
+
+ void WriteInlineMethod(LineWriter lw, MethodBase mb, Type[] optionalParameterTypes, CustomModifiers[] customModifiers, MethodInfo methodimpl = null)
+ {
+ WriteCallingConvention(lw, mb.CallingConvention);
+ if (mb is ConstructorInfo)
+ {
+ lw.Write("void ");
+ }
+ else
+ {
+ WriteSignatureType(lw, ((MethodInfo)mb.__GetMethodOnTypeDefinition()).ReturnType, IsArrayOfGenericParameter(mb.DeclaringType) ? TypeLocation.General : TypeLocation.MemberRefNoWrap);
+ WriteCustomModifiers(lw, ((MethodInfo)mb).ReturnParameter.__GetCustomModifiers());
+ lw.Write(" ");
+ }
+ bool generic;
+ if (mb.DeclaringType == null)
+ {
+ generic = false;
+ lw.Write("{0}", QuoteIdentifier(GetMethodName(mb)));
+ }
+ else
+ {
+ if (mb.DeclaringType.__IsMissing || !mb.DeclaringType.IsGenericType)
+ {
+ generic = false;
+ WriteTypeDefOrRef(lw, mb.DeclaringType);
+ }
+ else
+ {
+ generic = true;
+ WriteSignatureType(lw, mb.DeclaringType, mb.IsGenericMethod ? TypeLocation.DeclaringType : TypeLocation.General);
+ }
+ lw.Write("::{0}", QuoteIdentifier(GetMethodName(mb)));
+ }
+ if (mb.IsGenericMethod)
+ {
+ if (methodimpl != null)
+ {
+ lw.Write("<[{0}]>", mb.GetGenericArguments().Length);
+ }
+ else
+ {
+ lw.Write("<");
+ string sep = "";
+ foreach (var par in mb.GetGenericArguments())
+ {
+ lw.Write(sep);
+ sep = ",";
+ WriteSignatureType(lw, par, generic ? TypeLocation.MemberRefNoWrap : TypeLocation.MethodGenericParameter);
+ }
+ lw.Write(">");
+ }
+ }
+ if (mb.IsGenericMethodDefinition && methodimpl != null)
+ {
+ mb = ((MethodInfo)mb).MakeGenericMethod(methodimpl.GetGenericArguments());
+ }
+ else
+ {
+ mb = mb.__GetMethodOnTypeDefinition();
+ }
+ lw.Write("(");
+ TypeLocation loc = (methodimpl != null && mb.IsGenericMethod)
+ ? TypeLocation.GenericMethodImpl
+ : IsArrayOfGenericParameter(mb.DeclaringType) ? TypeLocation.General : TypeLocation.MemberRefNoWrap;
+ int level = lw.Column;
+ if (compat != CompatLevel.None && loc == TypeLocation.GenericMethodImpl)
+ {
+ // ildasm doesn't take the length of the arity ("<[1]>") into account
+ level -= 5 + (int)Math.Log10(mb.GetGenericArguments().Length);
+ }
+ bool first = true;
+ bool noLineWrapCompat = false;
+ foreach (var parameter in mb.GetParameters())
+ {
+ if (!first)
+ {
+ if (noLineWrapCompat)
+ {
+ lw.Write(",");
+ }
+ else
+ {
+ if (loc == TypeLocation.MemberRefNoWrap)
+ {
+ loc = TypeLocation.MemberRef;
+ }
+ lw.WriteLine(",");
+ lw.GoToColumn(level);
+ }
+ }
+ first = false;
+ lw.ClearWrappedFlag();
+ WriteSignatureType(lw, parameter.ParameterType, loc);
+ noLineWrapCompat |= lw.Wrapped;
+ WriteCustomModifiers(lw, parameter.__GetCustomModifiers());
+ }
+ if (optionalParameterTypes.Length != 0)
+ {
+ if (!first)
+ {
+ lw.WriteLine(",");
+ lw.GoToColumn(level);
+ }
+ first = false;
+ lw.Write("...");
+ for (int i = 0; i < optionalParameterTypes.Length; i++)
+ {
+ if (!first)
+ {
+ lw.WriteLine(",");
+ lw.GoToColumn(level);
+ }
+ first = false;
+ WriteSignatureType(lw, optionalParameterTypes[i], TypeLocation.MemberRef);
+ WriteCustomModifiers(lw, customModifiers[i]);
+ }
+ }
+ lw.Write(")");
+ }
+
+ void WriteInlineType(LineWriter lw, int metadataToken, Type[] genericTypeArguments, Type[] genericMethodArguments)
+ {
+ CustomModifiers mods = new CustomModifiers();
+ if (metadataToken >> 24 == 0x1B)
+ {
+ mods = module.__ResolveTypeSpecCustomModifiers(metadataToken, genericTypeArguments, genericMethodArguments);
+ }
+ if (!mods.IsEmpty)
+ {
+ lw.Write("class ");
+ }
+ Type type = ResolveType(metadataToken, genericTypeArguments, genericMethodArguments);
+ if (type.HasElementType)
+ {
+ WriteSignatureType(lw, type);
+ }
+ else if (!type.__IsMissing && type.IsGenericType)
+ {
+ WriteSignatureType(lw, type, TypeLocation.General);
+ }
+ else
+ {
+ WriteTypeDefOrRef(lw, type);
+ }
+ if (!mods.IsEmpty)
+ {
+ WriteCustomModifiers(lw, mods);
+ }
+ }
+
+ void WriteInlineField(LineWriter lw, FieldInfo field)
+ {
+ WriteSignatureType(lw, field.__GetFieldOnTypeDefinition().FieldType, TypeLocation.MemberRefNoWrap);
+ WriteCustomModifiers(lw, field.__GetCustomModifiers());
+ lw.Write(" ");
+ if (field.DeclaringType == null)
+ {
+ lw.Write("{0}", QuoteIdentifier(GetFieldName(field)));
+ }
+ else
+ {
+ if (field.DeclaringType.__IsMissing || !field.DeclaringType.IsGenericType)
+ {
+ WriteTypeDefOrRef(lw, field.DeclaringType);
+ }
+ else
+ {
+ WriteSignatureType(lw, field.DeclaringType, TypeLocation.General);
+ }
+ lw.Write("::{0}", QuoteIdentifier(GetFieldName(field)));
+ }
+ }
+
+ Type[] ResolveOptionalParameterTypes(int token, Type[] genericTypeArguments, Type[] genericMethodArguments, out CustomModifiers[] customModifiers)
+ {
+ return module.__ResolveOptionalParameterTypes(token, genericTypeArguments, genericMethodArguments, out customModifiers);
+ }
+
+ void SortExceptions(IList<ExceptionHandlingClause> all, List<ExceptionHandlingClause> nested, List<ExceptionHandlingClause> flat)
+ {
+ var exceptions = new List<ExceptionHandlingClause>(all);
+ exceptions.Sort(this);
+ int first = 0;
+ for (int i = 1; i <= exceptions.Count; i++)
+ {
+ if (i < exceptions.Count
+ && exceptions[first].TryOffset == exceptions[i].TryOffset
+ && exceptions[first].TryLength == exceptions[i].TryLength
+ && (compat != CompatLevel.V20 || exceptions[i].FilterOffset == 0))
+ {
+ // part of a multiple handler block
+ }
+ else
+ {
+ if (compat == CompatLevel.V20)
+ {
+ for (int j = first; j < i; j++)
+ {
+ if (exceptions[j].FilterOffset != 0
+ || (i < exceptions.Count
+ && exceptions[j].TryOffset == exceptions[i].TryOffset
+ && exceptions[j].TryLength == exceptions[i].TryLength
+ && exceptions[j].HandlerOffset + exceptions[j].HandlerLength > exceptions[i].FilterOffset))
+ {
+ flat.Add(exceptions[j]);
+ }
+ else
+ {
+ nested.Add(exceptions[j]);
+ }
+ }
+ }
+ else
+ {
+ for (int j = first; j < i; j++)
+ {
+ nested.Add(exceptions[j]);
+ }
+ int end = exceptions[first].TryOffset + exceptions[first].TryLength;
+ for (int j = i - 1; j >= first; j--)
+ {
+ Debug.Assert(exceptions[j].TryOffset == exceptions[first].TryOffset && exceptions[j].TryLength == exceptions[first].TryLength);
+ if (exceptions[j].FilterOffset == end)
+ {
+ end += exceptions[j].HandlerOffset - exceptions[j].FilterOffset;
+ }
+ if (exceptions[j].HandlerOffset != end)
+ {
+ throw new NotImplementedException();
+ }
+ end += exceptions[j].HandlerLength;
+ }
+ }
+ first = i;
+ }
+ }
+ flat.Sort(FlatExceptionComparer);
+ }
+
+ static int FlatExceptionComparer(ExceptionHandlingClause x, ExceptionHandlingClause y)
+ {
+ return (x.HandlerOffset + x.HandlerLength).CompareTo(y.HandlerOffset + y.HandlerLength);
+ }
+
+ Type ResolveType(int token, Type[] genericTypeArguments, Type[] genericMethodArguments)
+ {
+ return module.ResolveType(token, genericTypeArguments, genericMethodArguments);
+ }
+
+ FieldInfo ResolveField(int token, Type[] genericTypeArguments, Type[] genericMethodArguments)
+ {
+ return module.ResolveField(token, genericTypeArguments, genericMethodArguments);
+ }
+
+ MethodBase ResolveMethod(int token, Type[] genericTypeArguments, Type[] genericMethodArguments)
+ {
+ return module.ResolveMethod(token, genericTypeArguments, genericMethodArguments);
+ }
+
+ MemberInfo ResolveMember(int token, Type[] genericTypeArguments, Type[] genericMethodArguments)
+ {
+ return module.ResolveMember(token, genericTypeArguments, genericMethodArguments);
+ }
+
+ short ReadInt16(byte[] code, ref int pos)
+ {
+ short s = BitConverter.ToInt16(code, pos);
+ pos += 2;
+ return s;
+ }
+
+ int ReadInt32(byte[] code, ref int pos)
+ {
+ int i = BitConverter.ToInt32(code, pos);
+ pos += 4;
+ return i;
+ }
+
+ long ReadInt64(byte[] code, ref int pos)
+ {
+ long l = BitConverter.ToInt64(code, pos);
+ pos += 8;
+ return l;
+ }
+
+ float ReadSingle(byte[] code, ref int pos)
+ {
+ float f = BitConverter.ToSingle(code, pos);
+ pos += 4;
+ return f;
+ }
+
+ double ReadDouble(byte[] code, ref int pos)
+ {
+ double d = BitConverter.ToDouble(code, pos);
+ pos += 8;
+ return d;
+ }
+
+ int IComparer<ExceptionHandlingClause>.Compare(ExceptionHandlingClause x, ExceptionHandlingClause y)
+ {
+ if (x.TryOffset < y.TryOffset)
+ {
+ return -1;
+ }
+ if (x.TryOffset > y.TryOffset)
+ {
+ return 1;
+ }
+ if (x.TryLength > y.TryLength)
+ {
+ return -1;
+ }
+ if (x.TryLength < y.TryLength)
+ {
+ return 1;
+ }
+ if (x.HandlerOffset > y.HandlerOffset)
+ {
+ return -1;
+ }
+ if (x.HandlerOffset < y.HandlerOffset)
+ {
+ return 1;
+ }
+ return 0;
+ }
+ }
+}
diff --git a/Keywords.cs b/Keywords.cs
new file mode 100644
index 0000000..e77b28f
--- /dev/null
+++ b/Keywords.cs
@@ -0,0 +1,240 @@
+/*
+ Copyright (C) 2012 Jeroen Frijters
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ Jeroen Frijters
+ jeroen@frijters.net
+
+*/
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Ildasm
+{
+ partial class Disassembler
+ {
+ static readonly HashSet<string> keywords = new HashSet<string>
+ {
+ "abstract",
+ "add",
+ "algorithm",
+ "alignment",
+ "and",
+ "ansi",
+ "any",
+ "arglist",
+ "array",
+ "as",
+ "assembly",
+ "assert",
+ "at",
+ "auto",
+ "autochar",
+ "beq",
+ "bge",
+ "bgt",
+ "ble",
+ "blt",
+ "blob",
+ "bool",
+ "box",
+ "br",
+ "break",
+ "brfalse",
+ "brtrue",
+ "bstr",
+ "bytearray",
+ "call",
+ "callconv",
+ "calli",
+ "callvirt",
+ "carray",
+ "catch",
+ "castclass",
+ "cdecl",
+ "ceq",
+ "cf",
+ "cgt",
+ "char",
+ "ckfinite",
+ "clt",
+ "class",
+ "clsid",
+ "cpblk",
+ "cpobj",
+ "currency",
+ "custom",
+ "date",
+ "decimal",
+ "default",
+ "demand",
+ "deny",
+ "div",
+ "dup",
+ "endfilter",
+ "endfinally",
+ "enum",
+ "error",
+ "explicit",
+ "extends",
+ "extern",
+ "false",
+ "family",
+ "fastcall",
+ "fault",
+ "field",
+ "filetime",
+ "filter",
+ "final",
+ "finally",
+ "fixed",
+ "flags",
+ "float",
+ "float32",
+ "float64",
+ "forwarder",
+ "handler",
+ "hresult",
+ "il",
+ "in",
+ "int",
+ "illegal",
+ "implements",
+ "import",
+ "init",
+ "initblk",
+ "initobj",
+ "instance",
+ "int8",
+ "int16",
+ "int32",
+ "int64",
+ "interface",
+ "isinst",
+ "iunknown",
+ "jmp",
+ "lasterr",
+ "ldarg",
+ "ldarga",
+ "ldelem",
+ "ldelema",
+ "ldfld",
+ "ldflda",
+ "ldftn",
+ "ldlen",
+ "ldloc",
+ "ldloca",
+ "ldnull",
+ "ldobj",
+ "ldsfld",
+ "ldsflda",
+ "ldstr",
+ "ldtoken",
+ "leave",
+ "legacy",
+ "library",
+ "literal",
+ "localloc",
+ "lpstr",
+ "lpvoid",
+ "lpwstr",
+ "managed",
+ "marshal",
+ "method",
+ "mkrefany",
+ "modopt",
+ "modreq",
+ "mul",
+ "native",
+ "neg",
+ "nested",
+ "newarr",
+ "newobj",
+ "nomangle",
+ "nop",
+ "not",
+ "object",
+ "off",
+ "on",
+ "opt",
+ "or",
+ "out",
+ "pinned",
+ "pop",
+ "prefix1",
+ "prefix2",
+ "property",
+ "record",
+ "refanytype",
+ "refanyval",
+ "rem",
+ "ret",
+ "retargetable",
+ "rethrow",
+ "request",
+ "runtime",
+ "sealed",
+ "serializable",
+ "sizeof",
+ "shl",
+ "shr",
+ "starg",
+ "stdcall",
+ "stelem",
+ "stfld",
+ "stloc",
+ "stobj",
+ "storage",
+ "stored_object",
+ "stream",
+ "strict",
+ "string",
+ "struct",
+ "stsfld",
+ "sub",
+ "synchronized",
+ "thiscall",
+ "tls",
+ "to",
+ "true",
+ "type",
+ "uint",
+ "uint8",
+ "uint16",
+ "uint32",
+ "uint64",
+ "unbox",
+ "unicode",
+ "unmanaged",
+ "unsigned",
+ "unused",
+ "value",
+ "variant",
+ "vector",
+ "virtual",
+ "void",
+ "wchar",
+ "winapi",
+ "with",
+ "x86",
+ "xor",
+ };
+ }
+}
diff --git a/LineWriter.cs b/LineWriter.cs
new file mode 100644
index 0000000..4acf925
--- /dev/null
+++ b/LineWriter.cs
@@ -0,0 +1,100 @@
+/*
+ Copyright (C) 2012 Jeroen Frijters
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ Jeroen Frijters
+ jeroen@frijters.net
+
+*/
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.IO;
+
+namespace Ildasm
+{
+ sealed class LineWriter
+ {
+ readonly TextWriter writer;
+ int column;
+ bool wrapped;
+
+ internal LineWriter(TextWriter writer)
+ {
+ this.writer = writer;
+ }
+
+ internal int Column
+ {
+ get { return column; }
+ }
+
+ internal bool Wrapped
+ {
+ get { return wrapped; }
+ }
+
+ internal void ClearWrappedFlag()
+ {
+ wrapped = false;
+ }
+
+ internal void Write(string str, params object[] args)
+ {
+ Write(String.Format(str, args));
+ }
+
+ internal void Write(string str)
+ {
+ writer.Write(str);
+ column += str.Length;
+ }
+
+ internal void WriteLine(string str)
+ {
+ writer.WriteLine(str);
+ column = 0;
+ wrapped = true;
+ }
+
+ internal void WriteLine(string str, params object[] args)
+ {
+ writer.WriteLine(str, args);
+ column = 0;
+ wrapped = true;
+ }
+
+ internal void WriteLine()
+ {
+ writer.WriteLine();
+ column = 0;
+ wrapped = true;
+ }
+
+ internal void GoToColumn(int column)
+ {
+ Write(new String(' ', column - this.column));
+ }
+
+ internal void Flush()
+ {
+ writer.Flush();
+ }
+ }
+}
diff --git a/Program.cs b/Program.cs
new file mode 100644
index 0000000..528fdfb
--- /dev/null
+++ b/Program.cs
@@ -0,0 +1,149 @@
+/*
+ Copyright (C) 2012 Jeroen Frijters
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ Jeroen Frijters
+ jeroen@frijters.net
+
+*/
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.IO;
+
+namespace Ildasm
+{
+ class Program
+ {
+ static void Main(string[] args)
+ {
+ string outputFile = null;
+ string inputFile = null;
+ var compatLevel = CompatLevel.None;
+ var diffMode = false;
+ foreach (var arg in args)
+ {
+ if (arg.StartsWith("-", StringComparison.Ordinal) || arg.StartsWith("/", StringComparison.Ordinal))
+ {
+ string value;
+ if (TryMatchOption(arg, "out", out value))
+ {
+ outputFile = value;
+ }
+ else if (TryMatchOption(arg, "compat", out value))
+ {
+ switch (value)
+ {
+ case "2.0":
+ compatLevel = CompatLevel.V20;
+ break;
+ case "4.0":
+ compatLevel = CompatLevel.V40;
+ break;
+ case "4.5":
+ compatLevel = CompatLevel.V45;
+ break;
+ default:
+ PrintUsage();
+ return;
+ }
+ }
+ else if (String.Compare(arg, 1, "diffmode", 0, 8, StringComparison.OrdinalIgnoreCase) == 0)
+ {
+ diffMode = true;
+ }
+ else
+ {
+ PrintUsage();
+ return;
+ }
+ }
+ else
+ {
+ if (inputFile != null)
+ {
+ PrintUsage();
+ return;
+ }
+ else
+ {
+ inputFile = arg;
+ }
+ }
+ }
+ if (inputFile == null)
+ {
+ PrintUsage();
+ return;
+ }
+ var disassembler = new Disassembler(inputFile, outputFile, compatLevel, diffMode);
+ if (outputFile != null)
+ {
+ Encoding enc;
+ switch (compatLevel)
+ {
+ case CompatLevel.None:
+ enc = Encoding.UTF8;
+ break;
+ case CompatLevel.V20:
+ case CompatLevel.V40:
+ // instantiate new UTF8Encoding to avoid the preamble that Encoding.UTF8 has
+ // (note that the only non-ASCII character that we're encoding is the \uFFFD placeholder for non-ASCII characters)
+ enc = new UTF8Encoding();
+ break;
+ default:
+ enc = Console.OutputEncoding;
+ break;
+ }
+ using (StreamWriter sw = new StreamWriter(outputFile, false, enc))
+ {
+ disassembler.Save(sw);
+ }
+ }
+ else
+ {
+ disassembler.Save(Console.Out);
+ }
+ }
+
+ static bool TryMatchOption(string arg, string key, out string value)
+ {
+ if (arg.Length > key.Length + 2 && (arg[key.Length + 1] == ':' || arg[key.Length + 1] == '=') && String.Compare(arg, 1, key, 0, key.Length, true) == 0)
+ {
+ value = arg.Substring(key.Length + 2);
+ return true;
+ }
+ value = null;
+ return false;
+ }
+
+ static void PrintUsage()
+ {
+ Console.WriteLine("IKDASM - IL disassembler example for IKVM.Reflection");
+ Console.WriteLine("Copyright (C) 2012-2013 Jeroen Frijters");
+ Console.WriteLine();
+ Console.WriteLine("Usage: ikdasm [options] <file_name> [options]");
+ Console.WriteLine();
+ Console.WriteLine("Options:");
+ Console.WriteLine(" /OUT=<file name> Direct output to file rather than to stdout.");
+ Console.WriteLine(" /COMPAT=<version> Match ildasm behavior. (<version> = 2.0 | 4.0 | 4.5)");
+ Console.WriteLine(" /DIFFMODE Remove superficial differences to allow assembly comparisons");
+ }
+ }
+}
diff --git a/Util.cs b/Util.cs
new file mode 100644
index 0000000..6cef603
--- /dev/null
+++ b/Util.cs
@@ -0,0 +1,53 @@
+/*
+ Copyright (C) 2012 Jeroen Frijters
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ Jeroen Frijters
+ jeroen@frijters.net
+
+*/
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace IKVM.Reflection.Reader
+{
+ [System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Explicit)]
+ struct SingleConverter
+ {
+ [System.Runtime.InteropServices.FieldOffset(0)]
+ private int i;
+ [System.Runtime.InteropServices.FieldOffset(0)]
+ private float f;
+
+ internal static int SingleToInt32Bits(float v)
+ {
+ SingleConverter c = new SingleConverter();
+ c.f = v;
+ return c.i;
+ }
+
+ internal static float Int32BitsToSingle(int v)
+ {
+ SingleConverter c = new SingleConverter();
+ c.i = v;
+ return c.f;
+ }
+ }
+}
diff --git a/VTableFixups.cs b/VTableFixups.cs
new file mode 100644
index 0000000..6526d23
--- /dev/null
+++ b/VTableFixups.cs
@@ -0,0 +1,163 @@
+/*
+ Copyright (C) 2012 Jeroen Frijters
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ Jeroen Frijters
+ jeroen@frijters.net
+
+*/
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using IKVM.Reflection;
+
+namespace Ildasm
+{
+ partial class Disassembler
+ {
+ const ushort COR_VTABLE_32BIT = 0x01;
+ const ushort COR_VTABLE_64BIT = 0x02;
+ const ushort COR_VTABLE_FROM_UNMANAGED = 0x04;
+ const ushort COR_VTABLE_FROM_UNMANAGED_RETAIN_APPDOMAIN = 0x08;
+ Dictionary<MethodBase, List<KeyValuePair<int, int>>> vtentryMap = new Dictionary<MethodBase, List<KeyValuePair<int, int>>>();
+
+ void WriteVTableFixupComment(LineWriter lw)
+ {
+ int ptrsize = GetPointerSize();
+ VTableFixups[] fixups = GetVTableFixups();
+ if (fixups.Length != 0)
+ {
+ lw.WriteLine("// VTableFixup Directory:");
+ for (int i = 0; i < fixups.Length; i++)
+ {
+ lw.WriteLine("// IMAGE_COR_VTABLEFIXUP[{0}]:", i);
+ lw.WriteLine("// RVA: 0x{0:x8}", fixups[i].RVA);
+ lw.WriteLine("// Count: 0x{0:x4}", fixups[i].Count);
+ lw.WriteLine("// Type: 0x{0:x4}", fixups[i].Type);
+ var methods = GetVTableMethods(fixups[i]);
+ for (int j = 0; j < methods.Length; j++)
+ {
+ var method = methods[j];
+ List<KeyValuePair<int,int>> list;
+ if (!vtentryMap.TryGetValue(method, out list))
+ {
+ list = new List<KeyValuePair<int, int>>();
+ vtentryMap.Add(method, list);
+ }
+ list.Add(new KeyValuePair<int,int>(i + 1, j + 1));
+ if (ptrsize == 4)
+ {
+ lw.WriteLine("// [0x{0:x4}] (0x{1:x8})", j, method.MetadataToken);
+ }
+ else
+ {
+ lw.WriteLine("// [0x{0:x4}] (0x {1:x})", j, method.MetadataToken);
+ }
+ }
+ }
+ lw.WriteLine();
+ }
+ lw.WriteLine();
+ }
+
+ void WriteVTableFixups(LineWriter lw)
+ {
+ int ptrsize = GetPointerSize();
+ VTableFixups[] fixups = GetVTableFixups();
+ if (fixups.Length != 0)
+ {
+ for (int i = 0; i < fixups.Length; i++)
+ {
+ lw.Write(".vtfixup [{0}] {1}{2} at D_{3:X8} //",
+ fixups[i].Count,
+ (fixups[i].Type & COR_VTABLE_32BIT) != 0 ? "int32" : "int64",
+ (fixups[i].Type & COR_VTABLE_FROM_UNMANAGED_RETAIN_APPDOMAIN) != 0
+ ? " retainappdomain"
+ : (fixups[i].Type & COR_VTABLE_FROM_UNMANAGED) != 0
+ ? " fromunmanaged"
+ : "",
+ fixups[i].RVA);
+ foreach (var method in GetVTableMethods(fixups[i]))
+ {
+ if (ptrsize == 4)
+ {
+ lw.Write(" {0:X8}", method.MetadataToken);
+ }
+ else
+ {
+ lw.Write(" {0:X16}", method.MetadataToken);
+ }
+ }
+ lw.WriteLine();
+ }
+ }
+ }
+
+ struct VTableFixups
+ {
+ internal int RVA;
+ internal short Count;
+ internal short Type;
+ }
+
+ VTableFixups[] GetVTableFixups()
+ {
+ int rva;
+ int length;
+ module.__GetDataDirectoryEntry(14, out rva, out length);
+ byte[] buf = new byte[8];
+ module.__ReadDataFromRVA(rva + 48, buf, 0, 8);
+ rva = BitConverter.ToInt32(buf, 0);
+ if (rva == 0)
+ {
+ return new VTableFixups[0];
+ }
+ VTableFixups[] entries = new VTableFixups[BitConverter.ToInt32(buf, 4) / 8];
+ for (int i = 0; i < entries.Length; i++)
+ {
+ module.__ReadDataFromRVA(rva + i * 8, buf, 0, 8);
+ entries[i].RVA = BitConverter.ToInt32(buf, 0);
+ entries[i].Count = BitConverter.ToInt16(buf, 4);
+ entries[i].Type = BitConverter.ToInt16(buf, 6);
+ }
+ return entries;
+ }
+
+ MethodBase[] GetVTableMethods(VTableFixups fixups)
+ {
+ var methods = new MethodBase[fixups.Count];
+ byte[] buf = new byte[8];
+ int fixuprva = fixups.RVA;
+ for (int i = 0; i < fixups.Count; i++)
+ {
+ module.__ReadDataFromRVA(fixuprva, buf, 0, 4);
+ methods[i] = module.ResolveMethod(BitConverter.ToInt32(buf, 0));
+ if ((fixups.Type & COR_VTABLE_32BIT) != 0)
+ {
+ fixuprva += 4;
+ }
+ if ((fixups.Type & COR_VTABLE_64BIT) != 0)
+ {
+ fixuprva += 8;
+ }
+ }
+ return methods;
+ }
+ }
+}
diff --git a/ikdasm.csproj b/ikdasm.csproj
new file mode 100644
index 0000000..4d558e2
--- /dev/null
+++ b/ikdasm.csproj
@@ -0,0 +1,78 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">x86</Platform>
+ <ProductVersion>8.0.30703</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{6C6F65C4-81B6-46CC-A4BE-A0C6F9ED7EE6}</ProjectGuid>
+ <OutputType>Exe</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>Ikdasm</RootNamespace>
+ <AssemblyName>ikdasm</AssemblyName>
+ <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
+ <FileAlignment>512</FileAlignment>
+ <SccProjectName>
+ </SccProjectName>
+ <SccLocalPath>
+ </SccLocalPath>
+ <SccAuxPath>
+ </SccAuxPath>
+ <SccProvider>
+ </SccProvider>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
+ <PlatformTarget>x86</PlatformTarget>
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>bin\Debug\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
+ <PlatformTarget>x86</PlatformTarget>
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\Release\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="IKVM.Reflection, Version=7.3.4804.0, Culture=neutral, processorArchitecture=MSIL">
+ <SpecificVersion>False</SpecificVersion>
+ <HintPath>.\IKVM.Reflection.dll</HintPath>
+ </Reference>
+ <Reference Include="System" />
+ <Reference Include="System.Core" />
+ <Reference Include="System.Xml.Linq" />
+ <Reference Include="System.Data.DataSetExtensions" />
+ <Reference Include="System.Data" />
+ <Reference Include="System.Xml" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="ByteReader.cs" />
+ <Compile Include="CABlob.cs" />
+ <Compile Include="Disassembler.cs" />
+ <Compile Include="ExportedMethods.cs" />
+ <Compile Include="IL.cs" />
+ <Compile Include="Keywords.cs" />
+ <Compile Include="LineWriter.cs" />
+ <Compile Include="Program.cs" />
+ <Compile Include="Util.cs" />
+ <Compile Include="VTableFixups.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <Folder Include="Properties\" />
+ </ItemGroup>
+ <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+ <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+ Other similar extension points exist, see Microsoft.Common.targets.
+ <Target Name="BeforeBuild">
+ </Target>
+ <Target Name="AfterBuild">
+ </Target>
+ -->
+</Project> \ No newline at end of file
diff --git a/ikdasm.sln b/ikdasm.sln
new file mode 100644
index 0000000..caf1ef8
--- /dev/null
+++ b/ikdasm.sln
@@ -0,0 +1,20 @@
+
+Microsoft Visual Studio Solution File, Format Version 11.00
+# Visual Studio 2010
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ikdasm", "ikdasm.csproj", "{6C6F65C4-81B6-46CC-A4BE-A0C6F9ED7EE6}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|x86 = Debug|x86
+ Release|x86 = Release|x86
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {6C6F65C4-81B6-46CC-A4BE-A0C6F9ED7EE6}.Debug|x86.ActiveCfg = Debug|x86
+ {6C6F65C4-81B6-46CC-A4BE-A0C6F9ED7EE6}.Debug|x86.Build.0 = Debug|x86
+ {6C6F65C4-81B6-46CC-A4BE-A0C6F9ED7EE6}.Release|x86.ActiveCfg = Release|x86
+ {6C6F65C4-81B6-46CC-A4BE-A0C6F9ED7EE6}.Release|x86.Build.0 = Release|x86
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal