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