PageRenderTime 104ms CodeModel.GetById 20ms app.highlight 68ms RepoModel.GetById 1ms app.codeStats 1ms

/ICSharpCode.Decompiler/Disassembler/ReflectionDisassembler.cs

http://github.com/icsharpcode/ILSpy
C# | 1771 lines | 1587 code | 143 blank | 41 comment | 249 complexity | 36ead26240de5c48ee3c5dcabe42aa9d MD5 | raw file
   1// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team
   2// 
   3// Permission is hereby granted, free of charge, to any person obtaining a copy of this
   4// software and associated documentation files (the "Software"), to deal in the Software
   5// without restriction, including without limitation the rights to use, copy, modify, merge,
   6// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
   7// to whom the Software is furnished to do so, subject to the following conditions:
   8// 
   9// The above copyright notice and this permission notice shall be included in all copies or
  10// substantial portions of the Software.
  11// 
  12// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
  13// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
  14// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
  15// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
  16// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  17// DEALINGS IN THE SOFTWARE.
  18
  19using System;
  20using System.Collections.Generic;
  21using System.Collections.Immutable;
  22using System.Linq;
  23using System.Reflection;
  24using System.Reflection.Metadata;
  25using System.Reflection.Metadata.Ecma335;
  26using System.Threading;
  27
  28using ICSharpCode.Decompiler.Metadata;
  29using ICSharpCode.Decompiler.IL;
  30using ICSharpCode.Decompiler.DebugInfo;
  31
  32namespace ICSharpCode.Decompiler.Disassembler
  33{
  34	/// <summary>
  35	/// Disassembles type and member definitions.
  36	/// </summary>
  37	public sealed class ReflectionDisassembler
  38	{
  39		readonly ITextOutput output;
  40		CancellationToken cancellationToken;
  41		bool isInType;   // whether we are currently disassembling a whole type (-> defaultCollapsed for foldings)
  42		MethodBodyDisassembler methodBodyDisassembler;
  43
  44		public bool DetectControlStructure {
  45			get => methodBodyDisassembler.DetectControlStructure;
  46			set => methodBodyDisassembler.DetectControlStructure = value;
  47		}
  48
  49		public bool ShowSequencePoints {
  50			get => methodBodyDisassembler.ShowSequencePoints;
  51			set => methodBodyDisassembler.ShowSequencePoints = value;
  52		}
  53
  54		public bool ShowMetadataTokens {
  55			get => methodBodyDisassembler.ShowMetadataTokens;
  56			set => methodBodyDisassembler.ShowMetadataTokens = value;
  57		}
  58
  59		public bool ShowMetadataTokensInBase10 {
  60			get => methodBodyDisassembler.ShowMetadataTokensInBase10;
  61			set => methodBodyDisassembler.ShowMetadataTokensInBase10 = value;
  62		}
  63
  64		public IDebugInfoProvider DebugInfo {
  65			get => methodBodyDisassembler.DebugInfo;
  66			set => methodBodyDisassembler.DebugInfo = value;
  67		}
  68
  69		public bool ExpandMemberDefinitions { get; set; } = false;
  70
  71		public IAssemblyResolver AssemblyResolver { get; set; }
  72
  73		public ReflectionDisassembler(ITextOutput output, CancellationToken cancellationToken)
  74			: this(output, new MethodBodyDisassembler(output, cancellationToken), cancellationToken)
  75		{
  76		}
  77
  78		public ReflectionDisassembler(ITextOutput output, MethodBodyDisassembler methodBodyDisassembler, CancellationToken cancellationToken)
  79		{
  80			if (output == null)
  81				throw new ArgumentNullException(nameof(output));
  82			this.output = output;
  83			this.cancellationToken = cancellationToken;
  84			this.methodBodyDisassembler = methodBodyDisassembler;
  85		}
  86
  87		#region Disassemble Method
  88		EnumNameCollection<MethodAttributes> methodAttributeFlags = new EnumNameCollection<MethodAttributes>() {
  89			{ MethodAttributes.Final, "final" },
  90			{ MethodAttributes.HideBySig, "hidebysig" },
  91			{ MethodAttributes.SpecialName, "specialname" },
  92			{ MethodAttributes.PinvokeImpl, null },	// handled separately
  93			{ MethodAttributes.UnmanagedExport, "export" },
  94			{ MethodAttributes.RTSpecialName, "rtspecialname" },
  95			{ MethodAttributes.RequireSecObject, "reqsecobj" },
  96			{ MethodAttributes.NewSlot, "newslot" },
  97			{ MethodAttributes.CheckAccessOnOverride, "strict" },
  98			{ MethodAttributes.Abstract, "abstract" },
  99			{ MethodAttributes.Virtual, "virtual" },
 100			{ MethodAttributes.Static, "static" },
 101			{ MethodAttributes.HasSecurity, null },	// ?? also invisible in ILDasm
 102		};
 103
 104		EnumNameCollection<MethodAttributes> methodVisibility = new EnumNameCollection<MethodAttributes>() {
 105			{ MethodAttributes.Private, "private" },
 106			{ MethodAttributes.FamANDAssem, "famandassem" },
 107			{ MethodAttributes.Assembly, "assembly" },
 108			{ MethodAttributes.Family, "family" },
 109			{ MethodAttributes.FamORAssem, "famorassem" },
 110			{ MethodAttributes.Public, "public" },
 111		};
 112
 113		EnumNameCollection<SignatureCallingConvention> callingConvention = new EnumNameCollection<SignatureCallingConvention>() {
 114			{ SignatureCallingConvention.CDecl, "unmanaged cdecl" },
 115			{ SignatureCallingConvention.StdCall, "unmanaged stdcall" },
 116			{ SignatureCallingConvention.ThisCall, "unmanaged thiscall" },
 117			{ SignatureCallingConvention.FastCall, "unmanaged fastcall" },
 118			{ SignatureCallingConvention.VarArgs, "vararg" },
 119			{ SignatureCallingConvention.Default, null },
 120		};
 121
 122		EnumNameCollection<MethodImplAttributes> methodCodeType = new EnumNameCollection<MethodImplAttributes>() {
 123			{ MethodImplAttributes.IL, "cil" },
 124			{ MethodImplAttributes.Native, "native" },
 125			{ MethodImplAttributes.OPTIL, "optil" },
 126			{ MethodImplAttributes.Runtime, "runtime" },
 127		};
 128
 129		EnumNameCollection<MethodImplAttributes> methodImpl = new EnumNameCollection<MethodImplAttributes>() {
 130			{ MethodImplAttributes.Synchronized, "synchronized" },
 131			{ MethodImplAttributes.NoInlining, "noinlining" },
 132			{ MethodImplAttributes.NoOptimization, "nooptimization" },
 133			{ MethodImplAttributes.PreserveSig, "preservesig" },
 134			{ MethodImplAttributes.InternalCall, "internalcall" },
 135			{ MethodImplAttributes.ForwardRef, "forwardref" },
 136			{ MethodImplAttributes.AggressiveInlining, "aggressiveinlining" },
 137		};
 138
 139		public void DisassembleMethod(PEFile module, MethodDefinitionHandle handle)
 140		{
 141			var genericContext = new GenericContext(handle, module);
 142			// write method header
 143			output.WriteReference(module, handle, ".method", isDefinition: true);
 144			output.Write(" ");
 145			DisassembleMethodHeaderInternal(module, handle, genericContext);
 146			DisassembleMethodBlock(module, handle, genericContext);
 147		}
 148
 149		public void DisassembleMethodHeader(PEFile module, MethodDefinitionHandle handle)
 150		{
 151			var genericContext = new GenericContext(handle, module);
 152			// write method header
 153			output.WriteReference(module, handle, ".method", isDefinition: true);
 154			output.Write(" ");
 155			DisassembleMethodHeaderInternal(module, handle, genericContext);
 156		}
 157
 158		void DisassembleMethodHeaderInternal(PEFile module, MethodDefinitionHandle handle, GenericContext genericContext)
 159		{
 160			var metadata = module.Metadata;
 161
 162			WriteMetadataToken(output, module, handle, MetadataTokens.GetToken(handle),
 163				spaceAfter: true, spaceBefore: false, ShowMetadataTokens, ShowMetadataTokensInBase10);
 164			var methodDefinition = metadata.GetMethodDefinition(handle);
 165			//    .method public hidebysig  specialname
 166			//               instance default class [mscorlib]System.IO.TextWriter get_BaseWriter ()  cil managed
 167			//
 168			//emit flags
 169			WriteEnum(methodDefinition.Attributes & MethodAttributes.MemberAccessMask, methodVisibility);
 170			WriteFlags(methodDefinition.Attributes & ~MethodAttributes.MemberAccessMask, methodAttributeFlags);
 171			bool isCompilerControlled = (methodDefinition.Attributes & MethodAttributes.MemberAccessMask) == MethodAttributes.PrivateScope;
 172			if (isCompilerControlled)
 173				output.Write("privatescope ");
 174
 175			if ((methodDefinition.Attributes & MethodAttributes.PinvokeImpl) == MethodAttributes.PinvokeImpl) {
 176				output.Write("pinvokeimpl");
 177				var info = methodDefinition.GetImport();
 178				if (!info.Module.IsNil) {
 179					var moduleRef = metadata.GetModuleReference(info.Module);
 180					output.Write("(\"" + DisassemblerHelpers.EscapeString(metadata.GetString(moduleRef.Name)) + "\"");
 181
 182					if (!info.Name.IsNil && metadata.GetString(info.Name) != metadata.GetString(methodDefinition.Name))
 183						output.Write(" as \"" + DisassemblerHelpers.EscapeString(metadata.GetString(info.Name)) + "\"");
 184
 185					if ((info.Attributes & MethodImportAttributes.ExactSpelling) == MethodImportAttributes.ExactSpelling)
 186						output.Write(" nomangle");
 187
 188					switch (info.Attributes & MethodImportAttributes.CharSetMask) {
 189						case MethodImportAttributes.CharSetAnsi:
 190							output.Write(" ansi");
 191							break;
 192						case MethodImportAttributes.CharSetAuto:
 193							output.Write(" autochar");
 194							break;
 195						case MethodImportAttributes.CharSetUnicode:
 196							output.Write(" unicode");
 197							break;
 198					}
 199
 200					if ((info.Attributes & MethodImportAttributes.SetLastError) == MethodImportAttributes.SetLastError)
 201						output.Write(" lasterr");
 202
 203					switch (info.Attributes & MethodImportAttributes.CallingConventionMask) {
 204						case MethodImportAttributes.CallingConventionCDecl:
 205							output.Write(" cdecl");
 206							break;
 207						case MethodImportAttributes.CallingConventionFastCall:
 208							output.Write(" fastcall");
 209							break;
 210						case MethodImportAttributes.CallingConventionStdCall:
 211							output.Write(" stdcall");
 212							break;
 213						case MethodImportAttributes.CallingConventionThisCall:
 214							output.Write(" thiscall");
 215							break;
 216						case MethodImportAttributes.CallingConventionWinApi:
 217							output.Write(" winapi");
 218							break;
 219					}
 220
 221					output.Write(')');
 222				}
 223				output.Write(' ');
 224			}
 225
 226			output.WriteLine();
 227			output.Indent();
 228			var declaringType = methodDefinition.GetDeclaringType();
 229			MethodSignature<Action<ILNameSyntax>>? signature;
 230			try {
 231				var signatureProvider = new DisassemblerSignatureTypeProvider(module, output);
 232				signature = methodDefinition.DecodeSignature(signatureProvider, genericContext);
 233				if (signature.Value.Header.HasExplicitThis) {
 234					output.Write("instance explicit ");
 235				} else if (signature.Value.Header.IsInstance) {
 236					output.Write("instance ");
 237				}
 238
 239				//call convention
 240				WriteEnum(signature.Value.Header.CallingConvention, callingConvention);
 241
 242				//return type
 243				signature.Value.ReturnType(ILNameSyntax.Signature);
 244			} catch (BadImageFormatException) {
 245				signature = null;
 246				output.Write("<bad signature>");
 247			}
 248			output.Write(' ');
 249
 250			var parameters = methodDefinition.GetParameters();
 251			if (parameters.Count > 0) {
 252				var firstParam = metadata.GetParameter(parameters.First());
 253				if (firstParam.SequenceNumber == 0) {
 254					var marshallingDesc = firstParam.GetMarshallingDescriptor();
 255					if (!marshallingDesc.IsNil) {
 256						WriteMarshalInfo(metadata.GetBlobReader(marshallingDesc));
 257					}
 258				}
 259			}
 260
 261			if (isCompilerControlled) {
 262				output.Write(DisassemblerHelpers.Escape(metadata.GetString(methodDefinition.Name) + "$PST" + MetadataTokens.GetToken(handle).ToString("X8")));
 263			} else {
 264				output.Write(DisassemblerHelpers.Escape(metadata.GetString(methodDefinition.Name)));
 265			}
 266
 267			WriteTypeParameters(output, module, genericContext, methodDefinition.GetGenericParameters());
 268
 269			//( params )
 270			output.Write(" (");
 271			if (signature?.ParameterTypes.Length > 0) {
 272				output.WriteLine();
 273				output.Indent();
 274				WriteParameters(metadata, parameters, signature.Value);
 275				output.Unindent();
 276			}
 277			output.Write(") ");
 278			//cil managed
 279			WriteEnum(methodDefinition.ImplAttributes & MethodImplAttributes.CodeTypeMask, methodCodeType);
 280			if ((methodDefinition.ImplAttributes & MethodImplAttributes.ManagedMask) == MethodImplAttributes.Managed)
 281				output.Write("managed ");
 282			else
 283				output.Write("unmanaged ");
 284			WriteFlags(methodDefinition.ImplAttributes & ~(MethodImplAttributes.CodeTypeMask | MethodImplAttributes.ManagedMask), methodImpl);
 285
 286			output.Unindent();
 287		}
 288
 289		internal static void WriteMetadataToken(ITextOutput output, PEFile module, Handle? handle, int metadataToken, bool spaceAfter, bool spaceBefore, bool showMetadataTokens, bool base10)
 290		{
 291			if (showMetadataTokens || handle == null) {
 292				if (spaceBefore) {
 293					output.Write(' ');
 294				}
 295				output.Write("/* ");
 296				if (base10) {
 297					output.WriteReference(module, handle.GetValueOrDefault(), metadataToken.ToString(), "metadata");
 298				} else {
 299					output.WriteReference(module, handle.GetValueOrDefault(), metadataToken.ToString("X8"), "metadata");
 300				}
 301				output.Write(" */");
 302				if (spaceAfter) {
 303					output.Write(' ');
 304				}
 305			}
 306		}
 307
 308		void DisassembleMethodBlock(PEFile module, MethodDefinitionHandle handle, GenericContext genericContext)
 309		{
 310			var metadata = module.Metadata;
 311			var methodDefinition = metadata.GetMethodDefinition(handle);
 312
 313			OpenBlock(defaultCollapsed: isInType);
 314			WriteAttributes(module, methodDefinition.GetCustomAttributes());
 315			foreach (var h in handle.GetMethodImplementations(metadata)) {
 316				var impl = metadata.GetMethodImplementation(h);
 317				output.Write(".override method ");
 318				impl.MethodDeclaration.WriteTo(module, output, genericContext);
 319				output.WriteLine();
 320			}
 321
 322			foreach (var p in methodDefinition.GetGenericParameters()) {
 323				WriteGenericParameterAttributes(module, genericContext, p);
 324			}
 325			foreach (var p in methodDefinition.GetParameters()) {
 326				WriteParameterAttributes(module, p);
 327			}
 328			WriteSecurityDeclarations(module, methodDefinition.GetDeclarativeSecurityAttributes());
 329
 330			if (methodDefinition.HasBody()) {
 331				methodBodyDisassembler.Disassemble(module, handle);
 332			}
 333			var declaringType = metadata.GetTypeDefinition(methodDefinition.GetDeclaringType());
 334			CloseBlock("end of method " + DisassemblerHelpers.Escape(metadata.GetString(declaringType.Name)) + "::" + DisassemblerHelpers.Escape(metadata.GetString(methodDefinition.Name)));
 335		}
 336
 337		#region Write Security Declarations
 338		void WriteSecurityDeclarations(PEFile module, DeclarativeSecurityAttributeHandleCollection secDeclProvider)
 339		{
 340			if (secDeclProvider.Count == 0)
 341				return;
 342			foreach (var h in secDeclProvider) {
 343				output.Write(".permissionset ");
 344				var secdecl = module.Metadata.GetDeclarativeSecurityAttribute(h);
 345				switch ((ushort)secdecl.Action) {
 346					case 1: // DeclarativeSecurityAction.Request
 347						output.Write("request");
 348						break;
 349					case 2: // DeclarativeSecurityAction.Demand
 350						output.Write("demand");
 351						break;
 352					case 3: // DeclarativeSecurityAction.Assert
 353						output.Write("assert");
 354						break;
 355					case 4: // DeclarativeSecurityAction.Deny
 356						output.Write("deny");
 357						break;
 358					case 5: // DeclarativeSecurityAction.PermitOnly
 359						output.Write("permitonly");
 360						break;
 361					case 6: // DeclarativeSecurityAction.LinkDemand
 362						output.Write("linkcheck");
 363						break;
 364					case 7: // DeclarativeSecurityAction.InheritDemand
 365						output.Write("inheritcheck");
 366						break;
 367					case 8: // DeclarativeSecurityAction.RequestMinimum
 368						output.Write("reqmin");
 369						break;
 370					case 9: // DeclarativeSecurityAction.RequestOptional
 371						output.Write("reqopt");
 372						break;
 373					case 10: // DeclarativeSecurityAction.RequestRefuse
 374						output.Write("reqrefuse");
 375						break;
 376					case 11: // DeclarativeSecurityAction.PreJitGrant
 377						output.Write("prejitgrant");
 378						break;
 379					case 12: // DeclarativeSecurityAction.PreJitDeny
 380						output.Write("prejitdeny");
 381						break;
 382					case 13: // DeclarativeSecurityAction.NonCasDemand
 383						output.Write("noncasdemand");
 384						break;
 385					case 14: // DeclarativeSecurityAction.NonCasLinkDemand
 386						output.Write("noncaslinkdemand");
 387						break;
 388					case 15: // DeclarativeSecurityAction.NonCasInheritance
 389						output.Write("noncasinheritance");
 390						break;
 391					default:
 392						output.Write(secdecl.Action.ToString());
 393						break;
 394				}
 395				var blob = module.Metadata.GetBlobReader(secdecl.PermissionSet);
 396				if (AssemblyResolver == null) {
 397					output.Write(" = ");
 398					WriteBlob(blob);
 399					output.WriteLine();
 400				} else if ((char)blob.ReadByte() != '.') {
 401					blob.Reset();
 402					output.WriteLine();
 403					output.Indent();
 404					output.Write("bytearray");
 405					WriteBlob(blob);
 406					output.WriteLine();
 407					output.Unindent();
 408				} else {
 409					var outputWithRollback = new TextOutputWithRollback(output);
 410					try {
 411						TryDecodeSecurityDeclaration(outputWithRollback, blob, module);
 412						outputWithRollback.Commit();
 413					} catch (Exception ex) when (ex is BadImageFormatException || ex is EnumUnderlyingTypeResolveException) {
 414						blob.Reset();
 415						output.Write(" = ");
 416						WriteBlob(blob);
 417						output.WriteLine();
 418					}
 419				}
 420			}
 421		}
 422
 423		class SecurityDeclarationDecoder : ICustomAttributeTypeProvider<(PrimitiveTypeCode, string)>
 424		{
 425			readonly ITextOutput output;
 426			readonly IAssemblyResolver resolver;
 427			readonly PEFile module;
 428
 429			public SecurityDeclarationDecoder(ITextOutput output, IAssemblyResolver resolver, PEFile module)
 430			{
 431				this.output = output;
 432				this.resolver = resolver;
 433				this.module = module;
 434			}
 435
 436			public (PrimitiveTypeCode, string) GetPrimitiveType(PrimitiveTypeCode typeCode)
 437			{
 438				return (typeCode, null);
 439			}
 440
 441			public (PrimitiveTypeCode, string) GetSystemType()
 442			{
 443				return (0, "type");
 444			}
 445
 446			public (PrimitiveTypeCode, string) GetSZArrayType((PrimitiveTypeCode, string) elementType)
 447			{
 448				return (elementType.Item1, (elementType.Item2 ?? PrimitiveTypeCodeToString(elementType.Item1)) + "[]");
 449			}
 450
 451			public (PrimitiveTypeCode, string) GetTypeFromDefinition(MetadataReader reader, TypeDefinitionHandle handle, byte rawTypeKind)
 452			{
 453				throw new NotImplementedException();
 454			}
 455
 456			public (PrimitiveTypeCode, string) GetTypeFromReference(MetadataReader reader, TypeReferenceHandle handle, byte rawTypeKind)
 457			{
 458				throw new NotImplementedException();
 459			}
 460
 461			public (PrimitiveTypeCode, string) GetTypeFromSerializedName(string name)
 462			{
 463				if (resolver == null)
 464					throw new EnumUnderlyingTypeResolveException();
 465				var (containingModule, typeDefHandle) = ResolveType(name, module);
 466				if (typeDefHandle.IsNil)
 467					throw new EnumUnderlyingTypeResolveException();
 468				if (typeDefHandle.IsEnum(containingModule.Metadata, out var typeCode))
 469					return (typeCode, "enum " + name);
 470				return (0, name);
 471			}
 472
 473			public PrimitiveTypeCode GetUnderlyingEnumType((PrimitiveTypeCode, string) type)
 474			{
 475				return type.Item1;
 476			}
 477
 478			public bool IsSystemType((PrimitiveTypeCode, string) type)
 479			{
 480				return "type" == type.Item2;
 481			}
 482
 483			(PEFile, TypeDefinitionHandle) ResolveType(string typeName, PEFile module)
 484			{
 485				string[] nameParts = typeName.Split(new[] { ", " }, 2, StringSplitOptions.None);
 486				string[] typeNameParts = nameParts[0].Split('.');
 487				PEFile containingModule = null;
 488				TypeDefinitionHandle typeDefHandle = default;
 489				// if we deal with an assembly-qualified name, resolve the assembly
 490				if (nameParts.Length == 2)
 491					containingModule = resolver.Resolve(AssemblyNameReference.Parse(nameParts[1]));
 492				if (containingModule != null) {
 493					// try to find the type in the assembly
 494					typeDefHandle = FindType(containingModule, typeNameParts);
 495				} else {
 496					// just fully-qualified name, try current assembly
 497					typeDefHandle = FindType(module, typeNameParts);
 498					containingModule = module;
 499					if (typeDefHandle.IsNil && TryResolveMscorlib(out var mscorlib)) {
 500						// otherwise try mscorlib
 501						typeDefHandle = FindType(mscorlib, typeNameParts);
 502						containingModule = mscorlib;
 503					}
 504				}
 505
 506				return (containingModule, typeDefHandle);
 507
 508				TypeDefinitionHandle FindType(PEFile currentModule, string[] name)
 509				{
 510					var metadata = currentModule.Metadata;
 511					var currentNamespace = metadata.GetNamespaceDefinitionRoot();
 512					ImmutableArray<TypeDefinitionHandle> typeDefinitions = default;
 513
 514					for (int i = 0; i < name.Length; i++) {
 515						string identifier = name[i];
 516						if (!typeDefinitions.IsDefault) {
 517							restart:
 518							foreach (var type in typeDefinitions) {
 519								var typeDef = metadata.GetTypeDefinition(type);
 520								var currentTypeName = metadata.GetString(typeDef.Name);
 521								if (identifier == currentTypeName) {
 522									if (i + 1 == name.Length)
 523										return type;
 524									typeDefinitions = typeDef.GetNestedTypes();
 525									goto restart;
 526								}
 527							}
 528						} else {
 529							var next = currentNamespace.NamespaceDefinitions.FirstOrDefault(ns => metadata.StringComparer.Equals(metadata.GetNamespaceDefinition(ns).Name, identifier));
 530							if (!next.IsNil) {
 531								currentNamespace = metadata.GetNamespaceDefinition(next);
 532							} else {
 533								typeDefinitions = currentNamespace.TypeDefinitions;
 534								i--;
 535							}
 536						}
 537					}
 538					return default;
 539				}
 540			}
 541
 542			PrimitiveTypeCode ResolveEnumUnderlyingType(string typeName, PEFile module)
 543			{
 544				if (typeName.StartsWith("enum ", StringComparison.Ordinal))
 545					typeName = typeName.Substring(5);
 546				var (containingModule, typeDefHandle) = ResolveType(typeName, module);
 547
 548				if (typeDefHandle.IsNil || !typeDefHandle.IsEnum(containingModule.Metadata, out var typeCode))
 549					throw new EnumUnderlyingTypeResolveException();
 550				return typeCode;
 551			}
 552
 553			PEFile mscorlib;
 554
 555			bool TryResolveMscorlib(out PEFile mscorlib)
 556			{
 557				mscorlib = null;
 558				if (this.mscorlib != null) {
 559					mscorlib = this.mscorlib;
 560					return true;
 561				}
 562				if (resolver == null) {
 563					return false;
 564				}
 565				this.mscorlib = mscorlib = resolver.Resolve(AssemblyNameReference.Parse("mscorlib"));
 566				return this.mscorlib != null;
 567			}
 568		}
 569
 570		void TryDecodeSecurityDeclaration(TextOutputWithRollback output, BlobReader blob, PEFile module)
 571		{
 572			output.WriteLine(" = {");
 573			output.Indent();
 574
 575			string currentAssemblyName = null;
 576			string currentFullAssemblyName = null;
 577			if (module.Metadata.IsAssembly) {
 578				currentAssemblyName = module.Metadata.GetString(module.Metadata.GetAssemblyDefinition().Name);
 579				currentFullAssemblyName = module.Metadata.GetFullAssemblyName();
 580			}
 581			int count = blob.ReadCompressedInteger();			
 582			for (int i = 0; i < count; i++) {
 583				var fullTypeName = blob.ReadSerializedString();
 584				string[] nameParts = fullTypeName.Split(new[] { ", " }, StringSplitOptions.None);
 585				if (nameParts.Length < 2 || nameParts[1] == currentAssemblyName) {
 586					output.Write("class ");
 587					output.Write(DisassemblerHelpers.Escape(fullTypeName));
 588				} else {
 589					output.Write('[');
 590					output.Write(nameParts[1]);
 591					output.Write(']');
 592					output.Write(nameParts[0]);
 593				}
 594				output.Write(" = {");
 595				blob.ReadCompressedInteger(); // ?
 596											  // The specification seems to be incorrect here, so I'm using the logic from Cecil instead.
 597				int argCount = blob.ReadCompressedInteger();
 598
 599				var decoder = new CustomAttributeDecoder<(PrimitiveTypeCode Code, string Name)>(new SecurityDeclarationDecoder(output, AssemblyResolver, module), module.Metadata, provideBoxingTypeInfo: true);
 600				var arguments = decoder.DecodeNamedArguments(ref blob, argCount);
 601
 602				if (argCount > 0) {
 603					output.WriteLine();
 604					output.Indent();
 605				}
 606
 607				foreach (var argument in arguments) {
 608					switch (argument.Kind) {
 609						case CustomAttributeNamedArgumentKind.Field:
 610							output.Write("field ");
 611							break;
 612						case CustomAttributeNamedArgumentKind.Property:
 613							output.Write("property ");
 614							break;
 615					}
 616
 617					output.Write(argument.Type.Name ?? PrimitiveTypeCodeToString(argument.Type.Code));
 618					output.Write(" " + argument.Name + " = ");
 619
 620					WriteValue(output, argument.Type, argument.Value);
 621					output.WriteLine();
 622				}
 623
 624				if (argCount > 0) {
 625					output.Unindent();
 626				}
 627
 628				output.Write('}');
 629
 630				if (i + 1 < count)
 631					output.Write(',');
 632				output.WriteLine();
 633			}
 634			
 635			output.Unindent();
 636			output.WriteLine("}");
 637		}
 638
 639		void WriteValue(ITextOutput output, (PrimitiveTypeCode Code, string Name) type, object value)
 640		{
 641			if (value is CustomAttributeTypedArgument<(PrimitiveTypeCode, string)> boxedValue) {
 642				output.Write("object(");
 643				WriteValue(output, boxedValue.Type, boxedValue.Value);
 644				output.Write(")");
 645			} else if (value is ImmutableArray<CustomAttributeTypedArgument<(PrimitiveTypeCode, string)>> arrayValue) {
 646				string elementType = type.Name != null && !type.Name.StartsWith("enum ", StringComparison.Ordinal)
 647									? type.Name.Remove(type.Name.Length - 2) : PrimitiveTypeCodeToString(type.Code);
 648
 649				output.Write(elementType);
 650				output.Write("[");
 651				output.Write(arrayValue.Length.ToString());
 652				output.Write("](");
 653				bool first = true;
 654				foreach (var item in arrayValue) {
 655					if (!first) output.Write(" ");
 656					if (item.Value is CustomAttributeTypedArgument<(PrimitiveTypeCode, string)> boxedItem) {
 657						WriteValue(output, boxedItem.Type, boxedItem.Value);
 658					} else {
 659						WriteSimpleValue(output, item.Value, elementType);
 660					}
 661					first = false;
 662				}
 663				output.Write(")");
 664			} else {
 665				string typeName = type.Name != null && !type.Name.StartsWith("enum ", StringComparison.Ordinal)
 666					? type.Name : PrimitiveTypeCodeToString(type.Code);
 667
 668				output.Write(typeName);
 669				output.Write("(");
 670				WriteSimpleValue(output, value, typeName);
 671				output.Write(")");
 672			}
 673		}
 674
 675		private static void WriteSimpleValue(ITextOutput output, object value, string typeName)
 676		{
 677			switch (typeName) {
 678				case "string":
 679					output.Write("'" + DisassemblerHelpers.EscapeString(value.ToString()).Replace("'", "\'") + "'");
 680					break;
 681				case "type":
 682					var info = ((PrimitiveTypeCode Code, string Name))value;
 683					if (info.Name.StartsWith("enum ", StringComparison.Ordinal)) {
 684						output.Write(info.Name.Substring(5));
 685					} else {
 686						output.Write(info.Name);
 687					}
 688					break;
 689				default:
 690					DisassemblerHelpers.WriteOperand(output, value);
 691					break;
 692			}
 693		}
 694
 695		static string PrimitiveTypeCodeToString(PrimitiveTypeCode typeCode)
 696		{
 697			switch (typeCode) {
 698				case PrimitiveTypeCode.Boolean:
 699					return "bool";
 700				case PrimitiveTypeCode.Byte:
 701					return "uint8";
 702				case PrimitiveTypeCode.SByte:
 703					return "int8";
 704				case PrimitiveTypeCode.Char:
 705					return "char";
 706				case PrimitiveTypeCode.Int16:
 707					return "int16";
 708				case PrimitiveTypeCode.UInt16:
 709					return "uint16";
 710				case PrimitiveTypeCode.Int32:
 711					return "int32";
 712				case PrimitiveTypeCode.UInt32:
 713					return "uint32";
 714				case PrimitiveTypeCode.Int64:
 715					return "int64";
 716				case PrimitiveTypeCode.UInt64:
 717					return "uint64";
 718				case PrimitiveTypeCode.Single:
 719					return "float32";
 720				case PrimitiveTypeCode.Double:
 721					return "float64";
 722				case PrimitiveTypeCode.String:
 723					return "string";
 724				case PrimitiveTypeCode.Object:
 725					return "object";
 726				default:
 727					return "unknown";
 728			}
 729		}
 730
 731		#endregion
 732
 733		#region WriteMarshalInfo
 734		void WriteMarshalInfo(BlobReader marshalInfo)
 735		{
 736			output.Write("marshal(");
 737			WriteNativeType(ref marshalInfo);
 738			output.Write(") ");
 739		}
 740
 741		void WriteNativeType(ref BlobReader blob)
 742		{
 743			byte type;
 744			switch (type = blob.ReadByte()) {
 745				case 0x66: // None
 746				case 0x50: // Max
 747					break;
 748				case 0x02: // NATIVE_TYPE_BOOLEAN 
 749					output.Write("bool");
 750					break;
 751				case 0x03: // NATIVE_TYPE_I1
 752					output.Write("int8");
 753					break;
 754				case 0x04: // NATIVE_TYPE_U1
 755					output.Write("unsigned int8");
 756					break;
 757				case 0x05: // NATIVE_TYPE_I2
 758					output.Write("int16");
 759					break;
 760				case 0x06: // NATIVE_TYPE_U2
 761					output.Write("unsigned int16");
 762					break;
 763				case 0x07: // NATIVE_TYPE_I4
 764					output.Write("int32");
 765					break;
 766				case 0x08: // NATIVE_TYPE_U4
 767					output.Write("unsigned int32");
 768					break;
 769				case 0x09: // NATIVE_TYPE_I8
 770					output.Write("int64");
 771					break;
 772				case 0x0a: // NATIVE_TYPE_U8
 773					output.Write("unsigned int64");
 774					break;
 775				case 0x0b: // NATIVE_TYPE_R4
 776					output.Write("float32");
 777					break;
 778				case 0x0c: // NATIVE_TYPE_R8
 779					output.Write("float64");
 780					break;
 781				case 0x14: // NATIVE_TYPE_LPSTR
 782					output.Write("lpstr");
 783					break;
 784				case 0x1f: // NATIVE_TYPE_INT
 785					output.Write("int");
 786					break;
 787				case 0x20: // NATIVE_TYPE_UINT
 788					output.Write("unsigned int");
 789					break;
 790				case 0x26: // NATIVE_TYPE_FUNC
 791					output.Write("Func");
 792					break;
 793				case 0x2a: // NATIVE_TYPE_ARRAY
 794					if (blob.RemainingBytes > 0)
 795						WriteNativeType(ref blob);
 796					output.Write('[');
 797					int sizeParameterIndex = blob.TryReadCompressedInteger(out int value) ? value : -1;
 798					int size = blob.TryReadCompressedInteger(out value) ? value : -1;
 799					int sizeParameterMultiplier = blob.TryReadCompressedInteger(out value) ? value : -1;
 800					if (size >= 0) {
 801						output.Write(size.ToString());
 802					}
 803					if (sizeParameterIndex >= 0 && sizeParameterMultiplier != 0) {
 804						output.Write(" + ");
 805						output.Write(sizeParameterIndex.ToString());
 806					}
 807					output.Write(']');
 808					break;
 809				case 0x0f: // Currency
 810					output.Write("currency");
 811					break;
 812				case 0x13: // BStr
 813					output.Write("bstr");
 814					break;
 815				case 0x15: // LPWStr
 816					output.Write("lpwstr");
 817					break;
 818				case 0x16: // LPTStr
 819					output.Write("lptstr");
 820					break;
 821				case 0x17: // FixedSysString
 822					output.Write("fixed sysstring[{0}]", blob.ReadCompressedInteger());
 823					break;
 824				case 0x19: // IUnknown
 825					output.Write("iunknown");
 826					break;
 827				case 0x1a: // IDispatch
 828					output.Write("idispatch");
 829					break;
 830				case 0x1b: // Struct
 831					output.Write("struct");
 832					break;
 833				case 0x1c: // IntF
 834					output.Write("interface");
 835					break;
 836				case 0x1d: // SafeArray
 837					output.Write("safearray ");
 838					if (blob.RemainingBytes > 0) {
 839						byte elementType = blob.ReadByte();
 840						switch (elementType) {
 841							case 0: // None
 842								break;
 843							case 2: // I2
 844								output.Write("int16");
 845								break;
 846							case 3: // I4
 847								output.Write("int32");
 848								break;
 849							case 4: // R4
 850								output.Write("float32");
 851								break;
 852							case 5: // R8
 853								output.Write("float64");
 854								break;
 855							case 6: // Currency
 856								output.Write("currency");
 857								break;
 858							case 7: // Date
 859								output.Write("date");
 860								break;
 861							case 8: // BStr
 862								output.Write("bstr");
 863								break;
 864							case 9: // Dispatch
 865								output.Write("idispatch");
 866								break;
 867							case 10: // Error
 868								output.Write("error");
 869								break;
 870							case 11: // Bool
 871								output.Write("bool");
 872								break;
 873							case 12: // Variant
 874								output.Write("variant");
 875								break;
 876							case 13: // Unknown
 877								output.Write("iunknown");
 878								break;
 879							case 14: // Decimal
 880								output.Write("decimal");
 881								break;
 882							case 16: // I1
 883								output.Write("int8");
 884								break;
 885							case 17: // UI1
 886								output.Write("unsigned int8");
 887								break;
 888							case 18: // UI2
 889								output.Write("unsigned int16");
 890								break;
 891							case 19: // UI4
 892								output.Write("unsigned int32");
 893								break;
 894							case 22: // Int
 895								output.Write("int");
 896								break;
 897							case 23: // UInt
 898								output.Write("unsigned int");
 899								break;
 900							default:
 901								output.Write(elementType.ToString());
 902								break;
 903						}
 904					}
 905					break;
 906				case 0x1e: // FixedArray
 907					output.Write("fixed array");
 908					output.Write("[{0}]", blob.TryReadCompressedInteger(out value) ? value : 0);
 909					if (blob.RemainingBytes > 0) {
 910						output.Write(' ');
 911						WriteNativeType(ref blob);
 912					}
 913					break;
 914				case 0x22: // ByValStr
 915					output.Write("byvalstr");
 916					break;
 917				case 0x23: // ANSIBStr
 918					output.Write("ansi bstr");
 919					break;
 920				case 0x24: // TBStr
 921					output.Write("tbstr");
 922					break;
 923				case 0x25: // VariantBool
 924					output.Write("variant bool");
 925					break;
 926				case 0x28: // ASAny
 927					output.Write("as any");
 928					break;
 929				case 0x2b: // LPStruct
 930					output.Write("lpstruct");
 931					break;
 932				case 0x2c: // CustomMarshaler
 933					string guidValue = blob.ReadSerializedString();
 934					string unmanagedType = blob.ReadSerializedString();
 935					string managedType = blob.ReadSerializedString();
 936					string cookie = blob.ReadSerializedString();
 937
 938					var guid = !string.IsNullOrEmpty(guidValue) ? new Guid(guidValue) : Guid.Empty;
 939
 940					output.Write("custom(\"{0}\", \"{1}\"",
 941								 DisassemblerHelpers.EscapeString(managedType),
 942								 DisassemblerHelpers.EscapeString(cookie));
 943					if (guid != Guid.Empty || !string.IsNullOrEmpty(unmanagedType)) {
 944						output.Write(", \"{0}\", \"{1}\"", guid.ToString(), DisassemblerHelpers.EscapeString(unmanagedType));
 945					}
 946					output.Write(')');
 947					break;
 948				case 0x2d: // Error
 949					output.Write("error");
 950					break;
 951				default:
 952					output.Write(type.ToString());
 953					break;
 954			}
 955		}
 956		#endregion
 957
 958		void WriteParameters(MetadataReader metadata, IEnumerable<ParameterHandle> parameters, MethodSignature<Action<ILNameSyntax>> signature)
 959		{
 960			int i = 0;
 961			int offset = signature.Header.IsInstance ? 1 : 0;
 962
 963			foreach (var h in parameters) {
 964				var p = metadata.GetParameter(h);
 965				// skip return type parameter handle
 966				if (p.SequenceNumber == 0) continue;
 967
 968				// fill gaps in parameter list
 969				while (i < p.SequenceNumber - 1) {
 970					if (i > 0) {
 971						output.Write(',');
 972						output.WriteLine();
 973					}
 974					signature.ParameterTypes[i](ILNameSyntax.Signature);
 975					output.Write(' ');
 976					output.WriteLocalReference("''", "param_" + (i + offset), isDefinition: true);
 977					i++;
 978				}
 979
 980				// separator
 981				if (i > 0) {
 982					output.Write(',');
 983					output.WriteLine();
 984				}
 985
 986				// print parameter
 987				if ((p.Attributes & ParameterAttributes.In) == ParameterAttributes.In)
 988					output.Write("[in] ");
 989				if ((p.Attributes & ParameterAttributes.Out) == ParameterAttributes.Out)
 990					output.Write("[out] ");
 991				if ((p.Attributes & ParameterAttributes.Optional) == ParameterAttributes.Optional)
 992					output.Write("[opt] ");
 993				signature.ParameterTypes[i](ILNameSyntax.Signature);
 994				output.Write(' ');
 995				var md = p.GetMarshallingDescriptor();
 996				if (!md.IsNil) {
 997					WriteMarshalInfo(metadata.GetBlobReader(md));
 998				}
 999				output.WriteLocalReference(DisassemblerHelpers.Escape(metadata.GetString(p.Name)), "param_" + (i + offset), isDefinition: true);
1000				i++;
1001			}
1002
1003			// add remaining parameter types as unnamed parameters
1004			while (i < signature.RequiredParameterCount) {
1005				if (i > 0) {
1006					output.Write(',');
1007					output.WriteLine();
1008				}
1009				signature.ParameterTypes[i](ILNameSyntax.Signature);
1010				output.Write(' ');
1011				output.WriteLocalReference("''", "param_" + (i + offset), isDefinition: true);
1012				i++;
1013			}
1014
1015			output.WriteLine();
1016		}
1017
1018		void WriteGenericParameterAttributes(PEFile module, GenericContext context, GenericParameterHandle handle)
1019		{
1020			var metadata = module.Metadata;
1021			var p = metadata.GetGenericParameter(handle);
1022			if (p.GetCustomAttributes().Count > 0) {
1023				output.Write(".param type {0}", metadata.GetString(p.Name));
1024				output.WriteLine();
1025				output.Indent();
1026				WriteAttributes(module, p.GetCustomAttributes());
1027				output.Unindent();
1028			}
1029			foreach (var constraintHandle in p.GetConstraints()) {
1030				var constraint = metadata.GetGenericParameterConstraint(constraintHandle);
1031				if (constraint.GetCustomAttributes().Count > 0) {
1032					output.Write(".param constraint {0}, ", metadata.GetString(p.Name));
1033					constraint.Type.WriteTo(module, output, context, ILNameSyntax.TypeName);
1034					output.WriteLine();
1035					output.Indent();
1036					WriteAttributes(module, constraint.GetCustomAttributes());
1037					output.Unindent();
1038				}
1039			}
1040		}
1041
1042		void WriteParameterAttributes(PEFile module, ParameterHandle handle)
1043		{
1044			var metadata = module.Metadata;
1045			var p = metadata.GetParameter(handle);
1046			if (p.GetDefaultValue().IsNil && p.GetCustomAttributes().Count == 0)
1047				return;
1048			output.Write(".param [{0}]", p.SequenceNumber);
1049			if (!p.GetDefaultValue().IsNil) {
1050				output.Write(" = ");
1051				WriteConstant(metadata, metadata.GetConstant(p.GetDefaultValue()));
1052			}
1053			output.WriteLine();
1054			output.Indent();
1055			WriteAttributes(module, p.GetCustomAttributes());
1056			output.Unindent();
1057		}
1058
1059		void WriteConstant(MetadataReader metadata, Constant constant)
1060		{
1061			switch (constant.TypeCode) {
1062				case ConstantTypeCode.NullReference:
1063					output.Write("nullref");
1064					break;
1065				default:
1066					var blob = metadata.GetBlobReader(constant.Value);
1067					object value;
1068					try {
1069						value = blob.ReadConstant(constant.TypeCode);
1070					} catch (ArgumentOutOfRangeException) {
1071						output.Write($"/* Constant with invalid typecode: {constant.TypeCode} */");
1072						return;
1073					}
1074					if (value is string) {
1075						DisassemblerHelpers.WriteOperand(output, value);
1076					} else {
1077						string typeName = DisassemblerHelpers.PrimitiveTypeName(value.GetType().FullName);
1078						output.Write(typeName);
1079						output.Write('(');
1080						float? cf = value as float?;
1081						double? cd = value as double?;
1082						if (cf.HasValue && (float.IsNaN(cf.Value) || float.IsInfinity(cf.Value))) {
1083							output.Write("0x{0:x8}", BitConverter.ToInt32(BitConverter.GetBytes(cf.Value), 0));
1084						} else if (cd.HasValue && (double.IsNaN(cd.Value) || double.IsInfinity(cd.Value))) {
1085							output.Write("0x{0:x16}", BitConverter.DoubleToInt64Bits(cd.Value));
1086						} else {
1087							DisassemblerHelpers.WriteOperand(output, value);
1088						}
1089						output.Write(')');
1090					}
1091					break;
1092			}
1093		}
1094		#endregion
1095
1096		#region Disassemble Field
1097		EnumNameCollection<FieldAttributes> fieldVisibility = new EnumNameCollection<FieldAttributes>() {
1098			{ FieldAttributes.Private, "private" },
1099			{ FieldAttributes.FamANDAssem, "famandassem" },
1100			{ FieldAttributes.Assembly, "assembly" },
1101			{ FieldAttributes.Family, "family" },
1102			{ FieldAttributes.FamORAssem, "famorassem" },
1103			{ FieldAttributes.Public, "public" },
1104		};
1105
1106		EnumNameCollection<FieldAttributes> fieldAttributes = new EnumNameCollection<FieldAttributes>() {
1107			{ FieldAttributes.Static, "static" },
1108			{ FieldAttributes.Literal, "literal" },
1109			{ FieldAttributes.InitOnly, "initonly" },
1110			{ FieldAttributes.SpecialName, "specialname" },
1111			{ FieldAttributes.RTSpecialName, "rtspecialname" },
1112			{ FieldAttributes.NotSerialized, "notserialized" },
1113		};
1114
1115		public void DisassembleField(PEFile module, FieldDefinitionHandle field)
1116		{
1117			var metadata = module.Metadata;
1118			var fieldDefinition = metadata.GetFieldDefinition(field);
1119			output.WriteReference(module, field, ".field ", isDefinition: true);
1120			int offset = fieldDefinition.GetOffset();
1121			if (offset > -1) {
1122				output.Write("[" + offset + "] ");
1123			}
1124			WriteEnum(fieldDefinition.Attributes & FieldAttributes.FieldAccessMask, fieldVisibility);
1125			const FieldAttributes hasXAttributes = FieldAttributes.HasDefault | FieldAttributes.HasFieldMarshal | FieldAttributes.HasFieldRVA;
1126			WriteFlags(fieldDefinition.Attributes & ~(FieldAttributes.FieldAccessMask | hasXAttributes), fieldAttributes);
1127
1128			var signature = fieldDefinition.DecodeSignature(new DisassemblerSignatureTypeProvider(module, output), new GenericContext(fieldDefinition.GetDeclaringType(), module));
1129
1130			var marshallingDescriptor = fieldDefinition.GetMarshallingDescriptor();
1131			if (!marshallingDescriptor.IsNil) {
1132				WriteMarshalInfo(metadata.GetBlobReader(marshallingDescriptor));
1133			}
1134
1135			signature(ILNameSyntax.Signature);
1136			output.Write(' ');
1137			var fieldName = metadata.GetString(fieldDefinition.Name);
1138			output.Write(DisassemblerHelpers.Escape(fieldName));
1139			char sectionPrefix = 'D';
1140			if (fieldDefinition.HasFlag(FieldAttributes.HasFieldRVA)) {
1141				int rva = fieldDefinition.GetRelativeVirtualAddress();
1142				sectionPrefix = GetRVASectionPrefix(module.Reader.PEHeaders, rva);
1143				output.Write(" at {1}_{0:X8}", rva, sectionPrefix);
1144			}
1145
1146			var defaultValue = fieldDefinition.GetDefaultValue();
1147			if (!defaultValue.IsNil) {
1148				output.Write(" = ");
1149				WriteConstant(metadata, metadata.GetConstant(defaultValue));
1150			}
1151			output.WriteLine();
1152			var attributes = fieldDefinition.GetCustomAttributes();
1153			if (attributes.Count > 0) {
1154				output.MarkFoldStart();
1155				WriteAttributes(module, fieldDefinition.GetCustomAttributes());
1156				output.MarkFoldEnd();
1157			}
1158			if (fieldDefinition.HasFlag(FieldAttributes.HasFieldRVA)) {
1159				// Field data as specified in II.16.3.1 of ECMA-335 6th edition
1160				int rva = fieldDefinition.GetRelativeVirtualAddress();
1161				int sectionIndex = module.Reader.PEHeaders.GetContainingSectionIndex(rva);
1162				if (sectionIndex < 0) {
1163					output.WriteLine($"// RVA {rva:X8} invalid (not in any section)");
1164				} else {
1165					BlobReader initVal;
1166					try {
1167						initVal = fieldDefinition.GetInitialValue(module.Reader, null);
1168					} catch (BadImageFormatException ex) {
1169						initVal = default;
1170						output.WriteLine("// .data {2}_{0:X8} = {1}", fieldDefinition.GetRelativeVirtualAddress(), ex.Message, sectionPrefix);
1171					}
1172					if (initVal.Length > 0) {
1173						var sectionHeader = module.Reader.PEHeaders.SectionHeaders[sectionIndex];
1174						output.Write(".data ");
1175						if (sectionHeader.Name == ".text") {
1176							output.Write("cil ");
1177						} else if (sectionHeader.Name == ".tls") {
1178							output.Write("tls ");
1179						} else if (sectionHeader.Name != ".data") {
1180							output.Write($"/* {sectionHeader.Name} */ ");
1181						}
1182						output.Write($"{sectionPrefix}_{rva:X8} = bytearray ");
1183						WriteBlob(initVal);
1184						output.WriteLine();
1185					}
1186				}
1187			}
1188		}
1189
1190		char GetRVASectionPrefix(System.Reflection.PortableExecutable.PEHeaders headers, int rva)
1191		{
1192			int sectionIndex = headers.GetContainingSectionIndex(rva);
1193			if (sectionIndex < 0)
1194				return 'D';
1195			var sectionHeader = headers.SectionHeaders[sectionIndex];
1196			switch (sectionHeader.Name) {
1197				case ".tls":
1198					return 'T';
1199				case ".text":
1200					return 'I';
1201				default:
1202					return 'D';
1203			}
1204		}
1205		#endregion
1206
1207		#region Disassemble Property
1208		EnumNameCollection<PropertyAttributes> propertyAttributes = new EnumNameCollection<PropertyAttributes>() {
1209			{ PropertyAttributes.SpecialName, "specialname" },
1210			{ PropertyAttributes.RTSpecialName, "rtspecialname" },
1211			{ PropertyAttributes.HasDefault, "hasdefault" },
1212		};
1213
1214		public void DisassembleProperty(PEFile module, PropertyDefinitionHandle property)
1215		{
1216			var metadata = module.Metadata;
1217			var propertyDefinition = metadata.GetPropertyDefinition(property);
1218			output.WriteReference(module, property, ".property", isDefinition: true);
1219			output.Write(" ");
1220			WriteFlags(propertyDefinition.Attributes, propertyAttributes);
1221			var accessors = propertyDefinition.GetAccessors();
1222			var declaringType = metadata.GetMethodDefinition(accessors.GetAny()).GetDeclaringType();
1223			var signature = propertyDefinition.DecodeSignature(new DisassemblerSignatureTypeProvider(module, output), new GenericContext(declaringType, module));
1224
1225			if (signature.Header.IsInstance)
1226				output.Write("instance ");
1227			signature.ReturnType(ILNameSyntax.Signature);
1228			output.Write(' ');
1229			output.Write(DisassemblerHelpers.Escape(metadata.GetString(propertyDefinition.Name)));
1230
1231			output.Write('(');
1232			if (signature.ParameterTypes.Length > 0) {
1233				var parameters = metadata.GetMethodDefinition(accessors.GetAny()).GetParameters();
1234				int parametersCount = accessors.Getter.IsNil ? parameters.Count - 1 : parameters.Count;
1235
1236				output.WriteLine();
1237				output.Indent();
1238				WriteParameters(metadata, parameters.Take(parametersCount), signature);
1239				output.Unindent();
1240			}
1241			output.Write(')');
1242
1243			OpenBlock(false);
1244			WriteAttributes(module, propertyDefinition.GetCustomAttributes());
1245			WriteNestedMethod(".get", module, accessors.Getter);
1246			WriteNestedMethod(".set", module, accessors.Setter);
1247			foreach (var method in accessors.Others) {
1248				WriteNestedMethod(".other", module, method);
1249			}
1250			CloseBlock();
1251		}
1252
1253		void WriteNestedMethod(string keyword, PEFile module, MethodDefinitionHandle method)
1254		{
1255			if (method.IsNil)
1256				return;
1257
1258			output.Write(keyword);
1259			output.Write(' ');
1260			((EntityHandle)method).WriteTo(module, output, GenericContext.Empty);
1261			output.WriteLine();
1262		}
1263		#endregion
1264
1265		#region Disassemble Event
1266		EnumNameCollection<EventAttributes> eventAttributes = new EnumNameCollection<EventAttributes>() {
1267			{ EventAttributes.SpecialName, "specialname" },
1268			{ EventAttributes.RTSpecialName, "rtspecialname" },
1269		};
1270
1271		public void DisassembleEvent(PEFile module, EventDefinitionHandle handle)
1272		{
1273			var eventDefinition = module.Metadata.GetEventDefinition(handle);
1274			var accessors = eventDefinition.GetAccessors();
1275			TypeDefinitionHandle declaringType;
1276			if (!accessors.Adder.IsNil) {
1277				declaringType = module.Metadata.GetMethodDefinition(accessors.Adder).GetDeclaringType();
1278			} else if (!accessors.Remover.IsNil) {
1279				declaringType = module.Metadata.GetMethodDefinition(accessors.Remover).GetDeclaringType();
1280			} else {
1281				declaringType = module.Metadata.GetMethodDefinition(accessors.Raiser).GetDeclaringType();
1282			}
1283			output.WriteReference(module, handle, ".event", isDefinition: true);
1284			output.Write(" ");
1285			WriteFlags(eventDefinition.Attributes, eventAttributes);
1286			var provider = new DisassemblerSignatureTypeProvider(module, output);
1287			Action<ILNameSyntax> signature;
1288			switch (eventDefinition.Type.Kind) {
1289				case HandleKind.TypeDefinition:
1290					signature = provider.GetTypeFromDefinition(module.Metadata, (TypeDefinitionHandle)eventDefinition.Type, 0);
1291					break;
1292				case HandleKind.TypeReference:
1293					signature = provider.GetTypeFromReference(module.Metadata, (TypeReferenceHandle)eventDefinition.Type, 0);
1294					break;
1295				case HandleKind.TypeSpecification:
1296					signature = provider.GetTypeFromSpecification(module.Metadata, new GenericContext(declaringType, module),
1297						(TypeSpecificationHandle)eventDefinition.Type, 0);
1298					break;
1299				default:
1300					throw new BadImageFormatException("Expected a TypeDef, TypeRef or TypeSpec handle!");
1301			}
1302			signature(ILNameSyntax.TypeName);
1303			output.Write(' ');
1304			output.Write(DisassemblerHelpers.Escape(module.Metadata.GetString(eventDefinition.Name)));
1305			OpenBlock(false);
1306			WriteAttributes(module, eventDefinition.GetCustomAttributes());
1307			WriteNestedMethod(".addon", module, accessors.Adder);
1308			WriteNestedMethod(".removeon", module, accessors.Remover);
1309			WriteNestedMethod(".fire", module, accessors.Raiser);
1310			foreach (var method in accessors.Others) {
1311				WriteNestedMethod(".other", module, method);
1312			}
1313			CloseBlock();
1314		}
1315		#endregion
1316
1317		#region Disassemble Type
1318		EnumNameCollection<TypeAttributes> typeVisibility = new EnumNameCollection<TypeAttributes>() {
1319			{ TypeAttributes.Public, "public" },
1320			{ TypeAttributes.NotPublic, "private" },
1321			{ TypeAttributes.NestedPublic, "nested public" },
1322			{ TypeAttributes.NestedPrivate, "nested private" },
1323			{ TypeAttributes.NestedAssembly, "nested assembly" },
1324			{ TypeAttributes.NestedFamily, "nested family" },
1325			{ TypeAttributes.NestedFamANDAssem, "nested famandassem" },
1326			{ TypeAttributes.NestedFamORAssem, "nested famorassem" },
1327		};
1328
1329		EnumNameCollection<TypeAttributes> typeLayout = new EnumNameCollection<TypeAttributes>() {
1330			{ TypeAttributes.AutoLayout, "auto" },
1331			{ TypeAttributes.SequentialLayout, "sequential" },
1332			{ TypeAttributes.ExplicitLayout, "explicit" },
1333		};
1334
1335		EnumNameCollection<TypeAttributes> typeStringFormat = new EnumNameCollection<TypeAttributes>() {
1336			{ TypeAttributes.AutoClass, "auto" },
1337			{ TypeAttributes.AnsiClass, "ansi" },
1338			{ TypeAttributes.UnicodeClass, "unicode" },
1339		};
1340
1341		EnumNameCollection<TypeAttributes> typeAttributes = new EnumNameCollection<TypeAttributes>() {
1342			{ TypeAttributes.Abstract, "abstract" },
1343			{ TypeAttributes.Sealed, "sealed" },
1344			{ TypeAttributes.SpecialName, "specialname" },
1345			{ TypeAttributes.Import, "import" },
1346			{ TypeAttributes.Serializable, "serializable" },
1347			{ TypeAttributes.WindowsRuntime, "windowsruntime" },
1348			{ TypeAttributes.BeforeFieldInit, "beforefieldinit" },
1349			{ TypeAttributes.HasSecurity, null },
1350		};
1351
1352		public void DisassembleType(PEFile module, TypeDefinitionHandle type)
1353		{
1354			var typeDefinition = module.Metadata.GetTypeDefinition(type);
1355			output.WriteReference(module, type, ".class", isDefinition: true);
1356			output.Write(" ");
1357			if ((typeDefinition.Attributes & TypeAttributes.ClassSemanticsMask) == TypeAttributes.Interface)
1358				output.Write("interface ");
1359			WriteEnum(typeDefinition.Attributes & TypeAttributes.VisibilityMask, typeVisibility);
1360			WriteEnum(typeDefinition.Attributes & TypeAttributes.LayoutMask, typeLayout);
1361			WriteEnum(typeDefinition.Attributes & TypeAttributes.StringFormatMask, typeStringFormat);
1362			const TypeAttributes masks = TypeAttributes.ClassSemanticsMask | TypeAttributes.VisibilityMask | TypeAttributes.LayoutMask | TypeAttributes.StringFormatMask;
1363			WriteFlags(typeDefinition.Attributes & ~masks, typeAttributes);
1364
1365			output.Write(typeDefinition.GetDeclaringType().IsNil ? typeDefinition.GetFullTypeName(module.Metadata).ToILNameString() : DisassemblerHelpers.Escape(module.Metadata.GetString(typeDefinition.Name)));
1366			GenericContext genericContext = new GenericContext(type, module);
1367			WriteTypeParameters(output, module, genericContext, typeDefinition.GetGenericParameters());
1368			output.MarkFoldStart(defaultCollapsed: !ExpandMemberDefinitions && isInType);
1369			output.WriteLine();
1370
1371			EntityHandle baseType = typeDefinition.GetBaseTypeOrNil();
1372			if (!baseType.IsNil) {
1373				output.Indent();
1374				output.Write("extends ");
1375				baseType.WriteTo(module, output, genericContext, ILNameSyntax.TypeName);
1376				output.WriteLine();
1377				output.Unindent();
1378			}
1379
1380			var interfaces = typeDefinition.GetInterfaceImplementations();
1381			if (interfaces.Count > 0) {
1382				output.Indent();
1383				bool first = true;
1384				foreach (var i in interfaces) {
1385					if (!first)
1386						output.WriteLine(",");
1387					if (first)
1388						output.Write("implements ");
1389					else
1390						output.Write("           ");
1391					first = false;
1392					var iface = module.Metadata.GetInterfaceImplementation(i);
1393					WriteAttributes(module, iface.GetCustomAttributes());
1394					iface.Interface.WriteTo(module, output, genericContext, ILNameSyntax.TypeName);
1395				}
1396				output.WriteLine();
1397				output.Unindent();
1398			}
1399
1400			output.WriteLine("{");
1401			output.Indent();
1402			bool oldIsInType = isInType;
1403			isInType = true;
1404			WriteAttributes(module, typeDefinition.GetCustomAttributes());
1405			WriteSecurityDeclarations(module, typeDefinition.GetDeclarativeSecurityAttributes());
1406			foreach (var tp in typeDefinition.GetGenericParameters()) {
1407				WriteGenericParameterAttributes(module, genericContext, tp);
1408			}
1409			var layout = typeDefinition.GetLayout();
1410			if (!layout.IsDefault) {
1411				output.WriteLine(".pack {0}", layout.PackingSize);
1412				output.WriteLine(".size {0}", layout.Size);
1413				output.WriteLine();
1414			}
1415			var nestedTypes = typeDefinition.GetNestedTypes();
1416			if (!nestedTypes.IsEmpty) {
1417				output.WriteLine("// Nested Types");
1418				foreach (var nestedType in nestedTypes) {
1419					cancellationToken.ThrowIfCancellationRequested();
1420					DisassembleType(module, nestedType);
1421					output.WriteLine();
1422				}
1423				output.WriteLine();
1424			}
1425			var fields = typeDefinition.GetFields();
1426			if (fields.Any()) {
1427				output.WriteLine("// Fields");
1428				foreach (var field in fields) {
1429					cancellationToken.ThrowIfCancellationRequested();
1430					DisassembleField(module, field);
1431				}
1432				output.WriteLine();
1433			}
1434			var methods = typeDefinition.GetMethods();
1435			if (methods.Any()) {
1436				output.WriteLine("// Methods");
1437				foreach (var m in methods) {
1438					cancellationToken.ThrowIfCancellationRequested();
1439					DisassembleMethod(module, m);
1440					output.WriteLine();
1441				}
1442			}
1443			var events = typeDefinition.GetEvents();
1444			if (events.Any()) {
1445				output.WriteLine("// Events");
1446				foreach (var ev in events) {
1447					cancellationToken.ThrowIfCancellationRequested();
1448					DisassembleEvent(module, ev);
1449					output.WriteLine();
1450				}
1451				output.WriteLine();
1452			}
1453			var properties = typeDefinition.GetProperties();
1454			if (properties.Any()) {
1455				output.WriteLine("// Properties");
1456				foreach (var prop in properties) {
1457					cancellationToken.ThrowIfCancellationRequested();
1458					DisassembleProperty(module, prop);
1459				}
1460				output.WriteLine();
1461			}
1462			CloseBlock("end of class " + (!typeDefinition.GetDeclaringType().IsNil ? module.Metadata.GetString(typeDefinition.Name) : typeDefinition.GetFullTypeName(module.Metadata).ToString()));
1463			isInType = oldIsInType;
1464		}
1465
1466		void WriteTypeParameters(ITextOutput output, PEFile module, GenericContext context, GenericParameterHandleCollection p)
1467		{
1468			if (p.Count > 0) {
1469				output.Write('<');
1470				var metadata = module.Metadata;
1471				for (int i = 0; i < p.Count; i++) {
1472					if (i > 0)
1473						output.Write(", ");
1474					var gp = metadata.GetGenericParameter(p[i]);
1475					if ((gp.Attributes & GenericParameterAttributes.ReferenceTypeConstraint) == GenericParameterAttributes.ReferenceTypeConstraint) {
1476						output.Write("class ");
1477					} else if ((gp.Attributes & GenericParameterAttributes.NotNullableValueTypeConstraint) == GenericParameterAttributes.NotNullableValueTypeConstraint) {
1478						output.Write("valuetype ");
1479					}
1480					if ((gp.Attributes & GenericParameterAttributes.DefaultConstructorConstraint) == GenericParameterAttributes.DefaultConstructorConstraint) {
1481						output.Write(".ctor ");
1482					}
1483					var constraints = gp.GetConstraints();
1484					if (constraints.Count > 0) {
1485						output.Write('(');
1486						for (int j = 0; j < constraints.Count; j++) {
1487							if (j > 0)
1488								output.Write(", ");
1489							var constraint = metadata.GetGenericParameterConstraint(constraints[j]);
1490							constraint.Type.WriteTo(module, output, context, ILNameSyntax.TypeName);
1491						}
1492						output.Write(") ");
1493					}
1494					if ((gp.Attributes & GenericParameterAttributes.Contravariant) == GenericParameterAttributes.Contravariant) {
1495						output.Write('-');
1496					} else if ((gp.Attributes & GenericParameterAttributes.Covariant) == GenericParameterAttributes.Covariant) {
1497						output.Write('+');
1498					}
1499					output.Write(DisassemblerHelpers.Escape(metadata.GetString(gp.Name)));
1500				}
1501				output.Write('>');
1502			}
1503		}
1504		#endregion
1505
1506		#region Helper methods
1507		void WriteAttributes(PEFile module, CustomAttributeHandleCollection attributes)
1508		{
1509			var metadata = module.Metadata;
1510			foreach (CustomAttributeHandle a in attributes) {
1511				output.Write(".custom ");
1512				var attr = metadata.GetCustomAttribute(a);
1513				attr.Constructor.WriteTo(module, output, GenericContext.Empty);
1514				if (!attr.Value.IsNil) {
1515					output.Write(" = ");
1516					WriteBlob(attr.Value, metadata);
1517				}
1518				output.WriteLine();
1519			}
1520		}
1521
1522		void WriteBlob(BlobHandle blob, MetadataReader metadata)
1523		{
1524			var reader = metadata.GetBlobReader(blob);
1525			WriteBlob(reader);
1526		}
1527
1528		void WriteBlob(BlobReader reader)
1529		{
1530			output.Write("(");
1531			output.Indent();
1532
1533			for (int i = 0; i < reader.Length; i++) {
1534				if (i % 16 == 0 && i < reader.Length - 1) {
1535					output.WriteLine();
1536				} else {
1537					output.Write(' ');
1538				}
1539				output.Write(reader.ReadByte().ToString("x2"));
1540			}
1541
1542			output.WriteLine();
1543			output.Unindent();
1544			output.Write(")");
1545		}
1546
1547		void OpenBlock(bool defaultCollapsed)
1548		{
1549			output.MarkFoldStart(defaultCollapsed: !ExpandMemberDefinitions && defaultCollapsed);
1550			output.WriteLine();
1551			output.WriteLine("{");
1552			output.Indent();
1553		}
1554
1555		void CloseBlock(string comment = null)
1556		{
1557			output.Unindent();
1558			output.Write("}");
1559			if (comment != null)
1560				output.Write(" // " + comment);
1561			output.MarkFoldEnd();
1562			output.WriteLine();
1563		}
1564
1565		void WriteFlags<T>(T flags, EnumNameCollection<T> flagNames) where T : struct
1566		{
1567			long val = Convert.ToInt64(flags);
1568			long tested = 0;
1569			foreach (var pair in flagNames) {
1570				tested |= pair.Key;
1571				if ((val & pair.Key) != 0 && pair.Value != null) {
1572					output.Write(pair.Value);
1573					output.Write(' ');
1574				}
1575			}
1576			if ((val & ~tested) != 0)
1577				output.Write("flag({0:x4}) ", val & ~tested);
1578		}
1579
1580		void WriteEnum<T>(T enumValue, EnumNameCollection<T> enumNames) where T : struct
1581		{
1582			long val = Convert.ToInt64(enumValue);
1583			foreach (var pair in enumNames) {
1584				if (pair.Key == val) {
1585					if (pair.Value != null) {
1586						output.Write(pair.Value);
1587						output.Write(' ');
1588					}
1589					return;
1590				}
1591			}
1592			if (val != 0) {
1593				output.Write("flag({0:x4})", val);
1594				output.Write(' ');
1595			}
1596
1597		}
1598
1599		sealed class EnumNameCollection<T> : IEnumerable<KeyValuePair<long, string>> where T : struct
1600		{
1601			List<KeyValuePair<long, string>> names = new List<KeyValuePair<long, string>>();
1602
1603			public void Add(T flag, string name)
1604			{
1605				this.names.Add(new KeyValuePair<long, string>(Convert.ToInt64(flag), name));
1606			}
1607
1608			public IEnumerator<KeyValuePair<long, string>> GetEnumerator()
1609			{
1610				return names.GetEnumerator();
1611			}
1612
1613			System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
1614			{
1615				return names.GetEnumerator();
1616			}
1617		}
1618		#endregion
1619
1620		public void DisassembleNamespace(string nameSpace, PEFile module, IEnumerable<TypeDefinitionHandle> types)
1621		{
1622			if (!string.IsNullOrEmpty(nameSpace)) {
1623				output.Write(".namespace " + DisassemblerHelpers.Escape(nameSpace));
1624				OpenBlock(false);
1625			}
1626			bool oldIsInType = isInType;
1627			isInType = true;
1628			foreach (var td in types) {
1629				cancellationToken.ThrowIfCancellationRequested();
1630				DisassembleType(module, td);
1631				output.WriteLine();
1632			}
1633			if (!string.IsNullOrEmpty(nameSpace)) {
1634				CloseBlock();
1635				isInType = oldIsInType;
1636			}
1637		}
1638
1639		public void WriteAssemblyHeader(PEFile module)
1640		{
1641			var metadata = module.Metadata;
1642			if (!metadata.IsAssembly) return;
1643			output.Write(".assembly ");
1644			var asm = metadata.GetAssemblyDefinition();
1645			if ((asm.Flags & AssemblyFlags.WindowsRuntime) == AssemblyFlags.WindowsRuntime)
1646				output.Write("windowsruntime ");
1647			output.Write(DisassemblerHelpers.Escape(metadata.GetString(asm.Name)));
1648			OpenBlock(false);
1649			WriteAttributes(module, asm.GetCustomAttributes());
1650			WriteSecurityDeclarations(module, asm.GetDeclarativeSecurityAttributes());
1651			if (!asm.PublicKey.IsNil) {
1652				output.Write(".publickey = ");
1653				WriteBlob(asm.PublicKey, metadata);
1654				output.WriteLine();
1655			}
1656			if (asm.HashAlgorithm != AssemblyHashAlgorithm.None) {
1657				output.Write(".hash algorithm 0x{0:x8}", (int)asm.HashAlgorithm);
1658				if (asm.HashAlgorithm == AssemblyHashAlgorithm.Sha1)
1659					output.Write(" // SHA1");
1660				output.WriteLine();
1661			}
1662			Version v = asm.Version;
1663			if (v != null) {
1664				output.WriteLine(".ver {0}:{1}:{2}:{3}", v.Major, v.Minor, v.Build, v.Revision);
1665			}
1666			CloseBlock();
1667		}
1668
1669		public void WriteAssemblyReferences(MetadataReader metadata)
1670		{
1671			foreach (var m in metadata.GetModuleReferences()) {
1672				var mref = metadata.GetModuleReference(m);
1673				output.WriteLine(".module extern {0}", DisassemblerHelpers.Escape(metadata.GetString(mref.Name)));
1674			}
1675			foreach (var a in metadata.AssemblyReferences) {
1676				var aref = metadata.GetAssemblyReference(a);
1677				output.Write(".assembly extern ");
1678				if ((aref.Flags & AssemblyFlags.WindowsRuntime) == AssemblyFlags.WindowsRuntime)
1679					output.Write("windowsruntime ");
1680				output.Write(DisassemblerHelpers.Escape(metadata.GetString(aref.Name)));
1681				OpenBlock(false);
1682				if (!aref.PublicKeyOrToken.IsNil) {
1683					output.Write(".publickeytoken = ");
1684					WriteBlob(aref.PublicKeyOrToken, metadata);
1685					output.WriteLine();
1686				}
1687				if (aref.Version != null) {
1688					output.WriteLine(".ver {0}:{1}:{2}:{3}", aref.Version.Major, aref.Version.Minor, aref.Version.Build, aref.Version.Revision);
1689				}
1690				CloseBlock();
1691			}
1692		}
1693
1694		public void WriteModuleHeader(PEFile module, bool skipMVID = false)
1695		{
1696			var metadata = module.Metadata;
1697
1698			void WriteExportedType(ExportedType exportedType)
1699			{
1700				if (!exportedType.Namespace.IsNil) {
1701					output.Write(DisassemblerHelpers.Escape(metadata.GetString(exportedType.Namespace)));
1702					output.Write('.');
1703				}
1704				output.Write(DisassemblerHelpers.Escape(metadata.GetString(exportedType.Name)));
1705			}
1706
1707			foreach (var et in metadata.ExportedTypes) {
1708				var exportedType = metadata.GetExportedType(et);
1709				output.Write(".class extern ");
1710				if (exportedType.IsForwarder)
1711					output.Write("forwarder ");
1712				WriteExportedType(exportedType);
1713				OpenBlock(false);
1714				switch (exportedType.Implementation.Kind) {
1715					case HandleKind.AssemblyFile:
1716						var file = metadata.GetAssemblyFile((AssemblyFileHandle)exportedType.Implementation);
1717						output.WriteLine(".file {0}", metadata.GetString(file.Name));
1718						int typeDefId = exportedType.GetTypeDefinitionId();
1719						if (typeDefId != 0)
1720							output.WriteLine(".class 0x{0:x8}", typeDefId);
1721						break;
1722					case HandleKind.ExportedType:
1723						output.Write(".class extern ");
1724						var declaringType = metadata.GetExportedType((ExportedTypeHandle)exportedType.Implementation);
1725						while (true) {
1726							WriteExportedType(declaringType);
1727							if (declaringType.Implementation.Kind == HandleKind.ExportedType) {
1728								declaringType = metadata.GetExportedType((ExportedTypeHandle)declaringType.Implementation);
1729							} else {
1730								break;
1731							}
1732						}
1733						output.WriteLine();
1734						break;
1735					case HandleKind.AssemblyReference:
1736						output.Write(".assembly extern ");
1737						var reference = metadata.GetAssemblyReference((AssemblyReferenceHandle)exportedType.Implementation);
1738						output.Write(DisassemblerHelpers.Escape(metadata.GetString(reference.Name)));
1739						output.WriteLine();
1740						break;
1741					default:
1742						throw new BadImageFormatException("Implementation must either be an index into the File, ExportedType or AssemblyRef table.");
1743				}
1744				CloseBlock();
1745			}
1746			var moduleDefinition = metadata.GetModuleDefinition();
1747
1748			output.WriteLine(".module {0}", metadata.GetString(moduleDefinition.Name));
1749			if (!skipMVID) {
1750				output.WriteLine("// MVID: {0}", metadata.GetGuid(moduleDefinition.Mvid).ToString("B").ToUpperInvariant());
1751			}
1752
1753			var headers = module.Reader.PEHeaders;
1754			output.WriteLine(".imagebase 0x{0:x8}", headers.PEHeader.ImageBase);
1755			output.WriteLine(".file alignment 0x{0:x8}", headers.PEHeader.FileAlignment);
1756			output.WriteLine(".stackreserve 0x{0:x8}", headers.PEHeader.SizeOfStackReserve);
1757			output.WriteLine(".subsystem 0x{0:x} // {1}", headers.PEHeader.Subsystem, headers.PEHeader.Subsystem.ToString());
1758			output.WriteLine(".corflags 0x{0:x} // {1}", headers.CorHeader.Flags, headers.CorHeader.Flags.ToString());
1759
1760			WriteAttributes(module, metadata.GetCustomAttributes(EntityHandle.ModuleDefinition));
1761		}
1762
1763		public void WriteModuleContents(PEFile module)
1764		{
1765			foreach (var handle in module.Metadata.GetTopLevelTypeDefinitions()) {
1766				DisassembleType(module, handle);
1767				output.WriteLine();
1768			}
1769		}
1770	}
1771}