MetadataVisualizer.cs 58 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803
  1. // Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
  2. #if nope
  3. using System;
  4. using System.Collections.Generic;
  5. using System.Collections.Immutable;
  6. using System.Diagnostics;
  7. using System.Globalization;
  8. using System.IO;
  9. using System.Linq;
  10. using System.Reflection.Metadata;
  11. //using System.Reflection.Metadata.Decoding;
  12. using System.Reflection.Metadata.Ecma335;
  13. using System.Text;
  14. namespace Roslyn.Test.MetadataUtilities
  15. {
  16. [Flags]
  17. public enum MetadataVisualizerOptions
  18. {
  19. None = 0,
  20. ShortenBlobs = 1,
  21. }
  22. public sealed class MetadataVisualizer
  23. {
  24. private enum BlobKind
  25. {
  26. None,
  27. Key,
  28. FileHash,
  29. MethodSignature,
  30. FieldSignature,
  31. MemberRefSignature,
  32. StandAloneSignature,
  33. TypeSpec,
  34. MethodSpec,
  35. ConstantValue,
  36. Marshalling,
  37. PermissionSet,
  38. CustomAttribute,
  39. DocumentName,
  40. DocumentHash,
  41. SequencePoints,
  42. Imports,
  43. ImportAlias,
  44. ImportNamespace,
  45. LocalConstantSignature,
  46. CustomDebugInformation,
  47. Count
  48. }
  49. private readonly TextWriter _writer;
  50. private readonly IReadOnlyList<MetadataReader> _readers;
  51. private readonly MetadataAggregator _aggregator;
  52. private readonly MetadataVisualizerOptions _options;
  53. // enc map for each delta reader
  54. private readonly ImmutableArray<ImmutableArray<EntityHandle>> _encMaps;
  55. private MetadataReader _reader;
  56. private readonly List<string[]> _pendingRows = new List<string[]>();
  57. private readonly Dictionary<BlobHandle, BlobKind> _blobKinds = new Dictionary<BlobHandle, BlobKind>();
  58. private MetadataVisualizer(TextWriter writer, IReadOnlyList<MetadataReader> readers, MetadataVisualizerOptions options = MetadataVisualizerOptions.None)
  59. {
  60. _writer = writer;
  61. _readers = readers;
  62. _options = options;
  63. if (readers.Count > 1)
  64. {
  65. var deltaReaders = new List<MetadataReader>(readers.Skip(1));
  66. _aggregator = new MetadataAggregator(readers[0], deltaReaders);
  67. _encMaps = ImmutableArray.CreateRange(deltaReaders.Select(reader => ImmutableArray.CreateRange(reader.GetEditAndContinueMapEntries())));
  68. }
  69. }
  70. public MetadataVisualizer(MetadataReader reader, TextWriter writer, MetadataVisualizerOptions options = MetadataVisualizerOptions.None)
  71. : this(writer, new[] { reader }, options)
  72. {
  73. _reader = reader;
  74. }
  75. public MetadataVisualizer(IReadOnlyList<MetadataReader> readers, TextWriter writer, MetadataVisualizerOptions options = MetadataVisualizerOptions.None)
  76. : this(writer, readers, options)
  77. {
  78. }
  79. public void VisualizeAllGenerations()
  80. {
  81. for (int i = 0; i < _readers.Count; i++)
  82. {
  83. _writer.WriteLine(">>>");
  84. _writer.WriteLine($">>> Generation {i}:");
  85. _writer.WriteLine(">>>");
  86. _writer.WriteLine();
  87. Visualize(i);
  88. }
  89. }
  90. public void Visualize(int generation = -1)
  91. {
  92. _reader = (generation >= 0) ? _readers[generation] : _readers[_readers.Count - 1];
  93. WriteModule();
  94. WriteTypeRef();
  95. WriteTypeDef();
  96. WriteField();
  97. WriteMethod();
  98. WriteParam();
  99. WriteMemberRef();
  100. WriteConstant();
  101. WriteCustomAttribute();
  102. WriteDeclSecurity();
  103. WriteStandAloneSig();
  104. WriteEvent();
  105. WriteProperty();
  106. WriteMethodImpl();
  107. WriteModuleRef();
  108. WriteTypeSpec();
  109. WriteEnCLog();
  110. WriteEnCMap();
  111. WriteAssembly();
  112. WriteAssemblyRef();
  113. WriteFile();
  114. WriteExportedType();
  115. WriteManifestResource();
  116. WriteGenericParam();
  117. WriteMethodSpec();
  118. WriteGenericParamConstraint();
  119. // debug tables:
  120. WriteDocument();
  121. WriteMethodBody();
  122. WriteLocalScope();
  123. WriteLocalVariable();
  124. WriteLocalConstant();
  125. WriteLocalImport();
  126. WriteCustomDebugInformation();
  127. // heaps:
  128. WriteUserStrings();
  129. WriteStrings();
  130. WriteBlobs();
  131. WriteGuids();
  132. }
  133. private bool IsDelta
  134. {
  135. get
  136. {
  137. return _reader.GetTableRowCount(TableIndex.EncLog) > 0;
  138. }
  139. }
  140. private void WriteTableName(TableIndex index)
  141. {
  142. WriteRows(MakeTableName(index));
  143. }
  144. private string MakeTableName(TableIndex index)
  145. {
  146. return $"{index} (index: 0x{(byte)index:X2}, size: {_reader.GetTableRowCount(index) * _reader.GetTableRowSize(index)}): ";
  147. }
  148. private void AddHeader(params string[] header)
  149. {
  150. Debug.Assert(_pendingRows.Count == 0);
  151. _pendingRows.Add(header);
  152. }
  153. private void AddRow(params string[] fields)
  154. {
  155. Debug.Assert(_pendingRows.Count > 0 && _pendingRows.Last().Length == fields.Length);
  156. _pendingRows.Add(fields);
  157. }
  158. private void WriteRows(string title)
  159. {
  160. Debug.Assert(_pendingRows.Count > 0);
  161. if (_pendingRows.Count == 1)
  162. {
  163. _pendingRows.Clear();
  164. return;
  165. }
  166. _writer.Write(title);
  167. _writer.WriteLine();
  168. string columnSeparator = " ";
  169. int rowNumberWidth = _pendingRows.Count.ToString("x").Length;
  170. int[] columnWidths = new int[_pendingRows.First().Length];
  171. foreach (var row in _pendingRows)
  172. {
  173. for (int c = 0; c < row.Length; c++)
  174. {
  175. columnWidths[c] = Math.Max(columnWidths[c], row[c].Length + columnSeparator.Length);
  176. }
  177. }
  178. int tableWidth = columnWidths.Sum() + columnWidths.Length;
  179. string horizontalSeparator = new string('=', tableWidth);
  180. for (int r = 0; r < _pendingRows.Count; r++)
  181. {
  182. var row = _pendingRows[r];
  183. // header
  184. if (r == 0)
  185. {
  186. _writer.WriteLine(horizontalSeparator);
  187. _writer.Write(new string(' ', rowNumberWidth + 2));
  188. }
  189. else
  190. {
  191. string rowNumber = r.ToString("x");
  192. _writer.Write(new string(' ', rowNumberWidth - rowNumber.Length));
  193. _writer.Write(rowNumber);
  194. _writer.Write(": ");
  195. }
  196. for (int c = 0; c < row.Length; c++)
  197. {
  198. var field = row[c];
  199. _writer.Write(field);
  200. _writer.Write(new string(' ', columnWidths[c] - field.Length));
  201. }
  202. _writer.WriteLine();
  203. // header
  204. if (r == 0)
  205. {
  206. _writer.WriteLine(horizontalSeparator);
  207. }
  208. }
  209. _writer.WriteLine();
  210. _pendingRows.Clear();
  211. }
  212. private EntityHandle GetAggregateHandle(EntityHandle generationHandle, int generation)
  213. {
  214. var encMap = _encMaps[generation - 1];
  215. int start, count;
  216. if (!TryGetHandleRange(encMap, generationHandle.Kind, out start, out count))
  217. {
  218. throw new BadImageFormatException(string.Format("EncMap is missing record for {0:8X}.", MetadataTokens.GetToken(generationHandle)));
  219. }
  220. return encMap[start + MetadataTokens.GetRowNumber(generationHandle) - 1];
  221. }
  222. private static bool TryGetHandleRange(ImmutableArray<EntityHandle> handles, HandleKind handleType, out int start, out int count)
  223. {
  224. TableIndex tableIndex;
  225. MetadataTokens.TryGetTableIndex(handleType, out tableIndex);
  226. int mapIndex = handles.BinarySearch(MetadataTokens.Handle(tableIndex, 0), TokenTypeComparer.Instance);
  227. if (mapIndex < 0)
  228. {
  229. start = 0;
  230. count = 0;
  231. return false;
  232. }
  233. int s = mapIndex;
  234. while (s >= 0 && handles[s].Kind == handleType)
  235. {
  236. s--;
  237. }
  238. int e = mapIndex;
  239. while (e < handles.Length && handles[e].Kind == handleType)
  240. {
  241. e++;
  242. }
  243. start = s + 1;
  244. count = e - start;
  245. return true;
  246. }
  247. private MethodDefinition GetMethod(MethodDefinitionHandle handle)
  248. {
  249. return Get(handle, (reader, h) => reader.GetMethodDefinition((MethodDefinitionHandle)h));
  250. }
  251. private BlobHandle GetLocalSignature(StandaloneSignatureHandle handle)
  252. {
  253. return Get(handle, (reader, h) => reader.GetStandaloneSignature((StandaloneSignatureHandle)h).Signature);
  254. }
  255. private TEntity Get<TEntity>(Handle handle, Func<MetadataReader, Handle, TEntity> getter)
  256. {
  257. if (_aggregator != null)
  258. {
  259. int generation;
  260. var generationHandle = _aggregator.GetGenerationHandle(handle, out generation);
  261. return getter(_readers[generation], generationHandle);
  262. }
  263. else
  264. {
  265. return getter(_reader, handle);
  266. }
  267. }
  268. private string Literal(StringHandle handle)
  269. {
  270. return Literal(handle, BlobKind.None, (r, h) => "'" + StringUtilities.EscapeNonPrintableCharacters(r.GetString((StringHandle)h)) + "'");
  271. }
  272. private string Literal(NamespaceDefinitionHandle handle)
  273. {
  274. return Literal(handle, BlobKind.None, (r, h) => "'" + StringUtilities.EscapeNonPrintableCharacters(r.GetString((NamespaceDefinitionHandle)h)) + "'");
  275. }
  276. private string Literal(GuidHandle handle)
  277. {
  278. return Literal(handle, BlobKind.None, (r, h) => "{" + r.GetGuid((GuidHandle)h) + "}");
  279. }
  280. private static Guid CSharpGuid = new Guid("3f5162f8-07c6-11d3-9053-00c04fa302a1");
  281. private static Guid VisualBasicGuid = new Guid("3a12d0b8-c26c-11d0-b442-00a0244a1dd2");
  282. private static Guid FSharpGuid = new Guid("ab4f38c9-b6e6-43ba-be3b-58080b2ccce3");
  283. private static Guid Sha1Guid = new Guid("ff1816ec-aa5e-4d10-87f7-6f4963833460");
  284. private static Guid Sha256Guid = new Guid("8829d00f-11b8-4213-878b-770e8597ac16");
  285. private string GetLanguage(Guid guid)
  286. {
  287. if (guid == CSharpGuid) return "C#";
  288. if (guid == VisualBasicGuid) return "Visual Basic";
  289. if (guid == FSharpGuid) return "F#";
  290. return "{" + guid + "}";
  291. }
  292. private string GetHashAlgorithm(Guid guid)
  293. {
  294. if (guid == Sha1Guid) return "SHA-1";
  295. if (guid == Sha256Guid) return "SHA-256";
  296. return "{" + guid + "}";
  297. }
  298. private string Language(GuidHandle handle)
  299. {
  300. return Literal(handle, BlobKind.None, (r, h) => GetLanguage(r.GetGuid((GuidHandle)h)));
  301. }
  302. private string HashAlgorithm(GuidHandle handle)
  303. {
  304. return Literal(handle, BlobKind.None, (r, h) => GetHashAlgorithm(r.GetGuid((GuidHandle)h)));
  305. }
  306. /*
  307. private string Literal(DocumentNameBlobHandle handle)
  308. {
  309. return Literal((BlobHandle)handle, BlobKind.DocumentName, (r, h) => "'" + r.GetString((DocumentNameBlobHandle)(BlobHandle)h) + "'");
  310. }
  311. */
  312. private string LiteralUtf8Blob(BlobHandle handle, BlobKind kind)
  313. {
  314. return Literal(handle, kind, (r, h) =>
  315. {
  316. var bytes = r.GetBlobBytes((BlobHandle)h);
  317. return "'" + Encoding.UTF8.GetString(bytes, 0, bytes.Length) + "'";
  318. });
  319. }
  320. private string Literal(BlobHandle handle, BlobKind kind)
  321. {
  322. return Literal(handle, kind, (r, h) => BitConverter.ToString(r.GetBlobBytes((BlobHandle)h)));
  323. }
  324. private string Literal(Handle handle, BlobKind kind, Func<MetadataReader, Handle, string> getValue)
  325. {
  326. if (handle.IsNil)
  327. {
  328. return "nil";
  329. }
  330. if (kind != BlobKind.None)
  331. {
  332. _blobKinds[(BlobHandle)handle] = kind;
  333. }
  334. if (_aggregator != null)
  335. {
  336. int generation;
  337. Handle generationHandle = _aggregator.GetGenerationHandle(handle, out generation);
  338. var generationReader = _readers[generation];
  339. string value = GetValueChecked(getValue, generationReader, generationHandle);
  340. int offset = generationReader.GetHeapOffset(handle);
  341. int generationOffset = generationReader.GetHeapOffset(generationHandle);
  342. if (offset == generationOffset)
  343. {
  344. return $"{value} (#{offset:x})";
  345. }
  346. else
  347. {
  348. return $"{value} (#{offset:x}/{generationOffset:x})";
  349. }
  350. }
  351. if (IsDelta)
  352. {
  353. // we can't resolve the literal without aggregate reader
  354. return string.Format("#{0:x}", _reader.GetHeapOffset(handle));
  355. }
  356. // virtual heap handles don't have offset:
  357. int heapOffset = MetadataTokens.GetHeapOffset(handle);
  358. return $"{GetValueChecked(getValue, _reader, handle):x}" + (heapOffset >= 0 ? $" (#{heapOffset:x})" : "");
  359. }
  360. private string GetValueChecked(Func<MetadataReader, Handle, string> getValue, MetadataReader reader, Handle handle)
  361. {
  362. try
  363. {
  364. return getValue(reader, handle);
  365. }
  366. catch (BadImageFormatException)
  367. {
  368. return "<bad metadata>";
  369. }
  370. }
  371. private string Hex(ushort value)
  372. {
  373. return "0x" + value.ToString("X4");
  374. }
  375. private string Hex(int value)
  376. {
  377. return "0x" + value.ToString("X8");
  378. }
  379. public string Token(Func<Handle> handleFunc, bool displayTable = true)
  380. {
  381. Handle handle;
  382. try
  383. {
  384. handle = handleFunc();
  385. }
  386. catch (BadImageFormatException)
  387. {
  388. return "<bad metadata>";
  389. }
  390. if (handle.IsNil)
  391. {
  392. return "nil";
  393. }
  394. TableIndex table;
  395. if (displayTable && MetadataTokens.TryGetTableIndex(handle.Kind, out table))
  396. {
  397. return string.Format("0x{0:x8} ({1})", _reader.GetToken(handle), table);
  398. }
  399. else
  400. {
  401. return string.Format("0x{0:x8}", _reader.GetToken(handle));
  402. }
  403. }
  404. private static string EnumValue<T>(object value) where T : IEquatable<T>
  405. {
  406. T integralValue = (T)value;
  407. if (integralValue.Equals(default(T)))
  408. {
  409. return "0";
  410. }
  411. return string.Format("0x{0:x8} ({1})", integralValue, value);
  412. }
  413. // TODO (tomat): handle collections should implement IReadOnlyCollection<Handle>
  414. private string TokenRange<THandle>(IReadOnlyCollection<THandle> handles, Func<THandle, EntityHandle> conversion)
  415. {
  416. var genericHandles = handles.Select(conversion);
  417. if (handles.Count < 0)
  418. {
  419. return "<bad token range>";
  420. }
  421. return (handles.Count == 0) ? "nil" : Token(() => genericHandles.First(), displayTable: false) + "-" + Token(() => genericHandles.Last(), displayTable: false);
  422. }
  423. public string TokenList(IReadOnlyCollection<EntityHandle> handles, bool displayTable = false)
  424. {
  425. if (handles.Count == 0)
  426. {
  427. return "nil";
  428. }
  429. return string.Join(", ", handles.Select(h => Token(() => h, displayTable)));
  430. }
  431. private string FormatAwaits(BlobHandle handle)
  432. {
  433. var sb = new StringBuilder();
  434. var blobReader = _reader.GetBlobReader(handle);
  435. while (blobReader.RemainingBytes > 0)
  436. {
  437. if (blobReader.Offset > 0)
  438. {
  439. sb.Append(", ");
  440. }
  441. int value;
  442. sb.Append("(");
  443. sb.Append(blobReader.TryReadCompressedInteger(out value) ? value.ToString() : "?");
  444. sb.Append(", ");
  445. sb.Append(blobReader.TryReadCompressedInteger(out value) ? value.ToString() : "?");
  446. sb.Append(", ");
  447. sb.Append(blobReader.TryReadCompressedInteger(out value) ? Token(() => MetadataTokens.MethodDefinitionHandle(value)) : "?");
  448. sb.Append(')');
  449. }
  450. return sb.ToString();
  451. }
  452. private string FormatImports(BlobHandle handle)
  453. {
  454. if (handle.IsNil)
  455. {
  456. return "nil";
  457. }
  458. var sb = new StringBuilder();
  459. var importsReader = _reader.GetImportsReader(handle);
  460. while (importsReader.MoveNext())
  461. {
  462. if (sb.Length > 0)
  463. {
  464. sb.Append(", ");
  465. }
  466. var import = importsReader.Current;
  467. switch (import.Kind)
  468. {
  469. case ImportDefinitionKind.ImportNamespace:
  470. sb.AppendFormat("{0}", LiteralUtf8Blob(import.TargetNamespace, BlobKind.ImportNamespace));
  471. break;
  472. case ImportDefinitionKind.ImportAssemblyNamespace:
  473. sb.AppendFormat("{0}::{1}",
  474. Token(() => import.TargetAssembly),
  475. LiteralUtf8Blob(import.TargetNamespace, BlobKind.ImportNamespace));
  476. break;
  477. case ImportDefinitionKind.ImportType:
  478. sb.AppendFormat("{0}::{1}",
  479. Token(() => import.TargetAssembly),
  480. Token(() => import.TargetType));
  481. break;
  482. case ImportDefinitionKind.ImportXmlNamespace:
  483. sb.AppendFormat("<{0} = {1}>",
  484. LiteralUtf8Blob(import.Alias, BlobKind.ImportAlias),
  485. LiteralUtf8Blob(import.TargetNamespace, BlobKind.ImportNamespace));
  486. break;
  487. case ImportDefinitionKind.ImportAssemblyReferenceAlias:
  488. sb.AppendFormat("Extern Alias {0}",
  489. LiteralUtf8Blob(import.Alias, BlobKind.ImportAlias));
  490. break;
  491. case ImportDefinitionKind.AliasAssemblyReference:
  492. sb.AppendFormat("{0} = {1}",
  493. LiteralUtf8Blob(import.Alias, BlobKind.ImportAlias),
  494. Token(() => import.TargetAssembly));
  495. break;
  496. case ImportDefinitionKind.AliasNamespace:
  497. sb.AppendFormat("{0} = {1}",
  498. LiteralUtf8Blob(import.Alias, BlobKind.ImportAlias),
  499. LiteralUtf8Blob(import.TargetNamespace, BlobKind.ImportNamespace));
  500. break;
  501. case ImportDefinitionKind.AliasAssemblyNamespace:
  502. sb.AppendFormat("{0} = {1}::{2}",
  503. LiteralUtf8Blob(import.Alias, BlobKind.ImportAlias),
  504. Token(() => import.TargetAssembly),
  505. LiteralUtf8Blob(import.TargetNamespace, BlobKind.ImportNamespace));
  506. break;
  507. case ImportDefinitionKind.AliasType:
  508. sb.AppendFormat("{0} = {1}",
  509. LiteralUtf8Blob(import.Alias, BlobKind.ImportAlias),
  510. Token(() => import.TargetType));
  511. break;
  512. }
  513. }
  514. return sb.ToString();
  515. }
  516. /*
  517. private string SequencePoint(SequencePoint sequencePoint)
  518. {
  519. string range = sequencePoint.IsHidden ? "<hidden>" : $"({sequencePoint.StartLine}, {sequencePoint.StartColumn}) - ({sequencePoint.EndLine}, {sequencePoint.EndColumn})";
  520. return $"IL_{sequencePoint.Offset:X4}: " + range;
  521. }
  522. */
  523. public void VisualizeHeaders()
  524. {
  525. _reader = _readers[0];
  526. _writer.WriteLine("MetadataVersion: {0}", _reader.MetadataVersion);
  527. if (_reader.DebugMetadataHeader != null)
  528. {
  529. if (!_reader.DebugMetadataHeader.EntryPoint.IsNil)
  530. {
  531. _writer.WriteLine("EntryPoint: {0}", Token(() => _reader.DebugMetadataHeader.EntryPoint));
  532. }
  533. }
  534. _writer.WriteLine();
  535. }
  536. private void WriteModule()
  537. {
  538. if (_reader.DebugMetadataHeader != null)
  539. {
  540. return;
  541. }
  542. var def = _reader.GetModuleDefinition();
  543. AddHeader(
  544. "Gen",
  545. "Name",
  546. "Mvid",
  547. "EncId",
  548. "EncBaseId"
  549. );
  550. AddRow(
  551. def.Generation.ToString(),
  552. Literal(def.Name),
  553. Literal(def.Mvid),
  554. Literal(def.GenerationId),
  555. Literal(def.BaseGenerationId));
  556. WriteRows("Module (0x00):");
  557. }
  558. private void WriteTypeRef()
  559. {
  560. AddHeader(
  561. "Scope",
  562. "Name",
  563. "Namespace"
  564. );
  565. foreach (var handle in _reader.TypeReferences)
  566. {
  567. var entry = _reader.GetTypeReference(handle);
  568. AddRow(
  569. Token(() => entry.ResolutionScope),
  570. Literal(entry.Name),
  571. Literal(entry.Namespace)
  572. );
  573. }
  574. WriteRows("TypeRef (0x01):");
  575. }
  576. private void WriteTypeDef()
  577. {
  578. AddHeader(
  579. "Name",
  580. "Namespace",
  581. "EnclosingType",
  582. "BaseType",
  583. "Interfaces",
  584. "Fields",
  585. "Methods",
  586. "Attributes",
  587. "ClassSize",
  588. "PackingSize"
  589. );
  590. foreach (var handle in _reader.TypeDefinitions)
  591. {
  592. var entry = _reader.GetTypeDefinition(handle);
  593. var layout = entry.GetLayout();
  594. // TODO: Visualize InterfaceImplementations
  595. var implementedInterfaces = entry.GetInterfaceImplementations().Select(h => _reader.GetInterfaceImplementation(h).Interface).ToArray();
  596. AddRow(
  597. Literal(entry.Name),
  598. Literal(entry.Namespace),
  599. Token(() => entry.GetDeclaringType()),
  600. Token(() => entry.BaseType),
  601. TokenList(implementedInterfaces),
  602. TokenRange(entry.GetFields(), h => h),
  603. TokenRange(entry.GetMethods(), h => h),
  604. EnumValue<int>(entry.Attributes),
  605. !layout.IsDefault ? layout.Size.ToString() : "n/a",
  606. !layout.IsDefault ? layout.PackingSize.ToString() : "n/a"
  607. );
  608. }
  609. WriteRows("TypeDef (0x02):");
  610. }
  611. private void WriteField()
  612. {
  613. AddHeader(
  614. "Name",
  615. "Signature",
  616. "Attributes",
  617. "Marshalling",
  618. "Offset",
  619. "RVA"
  620. );
  621. foreach (var handle in _reader.FieldDefinitions)
  622. {
  623. var entry = _reader.GetFieldDefinition(handle);
  624. int offset = entry.GetOffset();
  625. AddRow(
  626. Literal(entry.Name),
  627. Literal(entry.Signature, BlobKind.FieldSignature),
  628. EnumValue<int>(entry.Attributes),
  629. Literal(entry.GetMarshallingDescriptor(), BlobKind.Marshalling),
  630. offset >= 0 ? offset.ToString() : "n/a",
  631. entry.GetRelativeVirtualAddress().ToString()
  632. );
  633. }
  634. WriteRows("Field (0x04):");
  635. }
  636. private void WriteMethod()
  637. {
  638. AddHeader(
  639. "Name",
  640. "Signature",
  641. "RVA",
  642. "Parameters",
  643. "GenericParameters",
  644. "ImplAttributes",
  645. "Attributes",
  646. "ImportAttributes",
  647. "ImportName",
  648. "ImportModule"
  649. );
  650. foreach (var handle in _reader.MethodDefinitions)
  651. {
  652. var entry = _reader.GetMethodDefinition(handle);
  653. var import = entry.GetImport();
  654. AddRow(
  655. Literal(entry.Name),
  656. Literal(entry.Signature, BlobKind.MethodSignature),
  657. Hex(entry.RelativeVirtualAddress),
  658. TokenRange(entry.GetParameters(), h => h),
  659. TokenRange(entry.GetGenericParameters(), h => h),
  660. EnumValue<int>(entry.Attributes), // TODO: we need better visualizer than the default enum
  661. EnumValue<int>(entry.ImplAttributes),
  662. EnumValue<short>(import.Attributes),
  663. Literal(import.Name),
  664. Token(() => import.Module)
  665. );
  666. }
  667. WriteRows("Method (0x06, 0x1C):");
  668. }
  669. private void WriteParam()
  670. {
  671. AddHeader(
  672. "Name",
  673. "Seq#",
  674. "Attributes",
  675. "Marshalling"
  676. );
  677. for (int i = 1, count = _reader.GetTableRowCount(TableIndex.Param); i <= count; i++)
  678. {
  679. var entry = _reader.GetParameter(MetadataTokens.ParameterHandle(i));
  680. AddRow(
  681. Literal(entry.Name),
  682. entry.SequenceNumber.ToString(),
  683. EnumValue<int>(entry.Attributes),
  684. Literal(entry.GetMarshallingDescriptor(), BlobKind.Marshalling)
  685. );
  686. }
  687. WriteRows("Param (0x08):");
  688. }
  689. private void WriteMemberRef()
  690. {
  691. AddHeader(
  692. "Parent",
  693. "Name",
  694. "Signature"
  695. );
  696. foreach (var handle in _reader.MemberReferences)
  697. {
  698. var entry = _reader.GetMemberReference(handle);
  699. AddRow(
  700. Token(() => entry.Parent),
  701. Literal(entry.Name),
  702. Literal(entry.Signature, BlobKind.MemberRefSignature)
  703. );
  704. }
  705. WriteRows("MemberRef (0x0a):");
  706. }
  707. private void WriteConstant()
  708. {
  709. AddHeader(
  710. "Parent",
  711. "Type",
  712. "Value"
  713. );
  714. for (int i = 1, count = _reader.GetTableRowCount(TableIndex.Constant); i <= count; i++)
  715. {
  716. var entry = _reader.GetConstant(MetadataTokens.ConstantHandle(i));
  717. AddRow(
  718. Token(() => entry.Parent),
  719. EnumValue<byte>(entry.TypeCode),
  720. Literal(entry.Value, BlobKind.ConstantValue)
  721. );
  722. }
  723. WriteRows("Constant (0x0b):");
  724. }
  725. private void WriteCustomAttribute()
  726. {
  727. AddHeader(
  728. "Parent",
  729. "Constructor",
  730. "Value"
  731. );
  732. foreach (var handle in _reader.CustomAttributes)
  733. {
  734. var entry = _reader.GetCustomAttribute(handle);
  735. AddRow(
  736. Token(() => entry.Parent),
  737. Token(() => entry.Constructor),
  738. Literal(entry.Value, BlobKind.CustomAttribute)
  739. );
  740. }
  741. WriteRows("CustomAttribute (0x0c):");
  742. }
  743. private void WriteDeclSecurity()
  744. {
  745. AddHeader(
  746. "Parent",
  747. "PermissionSet",
  748. "Action"
  749. );
  750. foreach (var handle in _reader.DeclarativeSecurityAttributes)
  751. {
  752. var entry = _reader.GetDeclarativeSecurityAttribute(handle);
  753. AddRow(
  754. Token(() => entry.Parent),
  755. Literal(entry.PermissionSet, BlobKind.PermissionSet),
  756. EnumValue<short>(entry.Action)
  757. );
  758. }
  759. WriteRows("DeclSecurity (0x0e):");
  760. }
  761. private void WriteStandAloneSig()
  762. {
  763. AddHeader("Signature");
  764. for (int i = 1, count = _reader.GetTableRowCount(TableIndex.StandAloneSig); i <= count; i++)
  765. {
  766. var value = _reader.GetStandaloneSignature(MetadataTokens.StandaloneSignatureHandle(i)).Signature;
  767. AddRow(Literal(value, BlobKind.StandAloneSignature));
  768. }
  769. WriteRows("StandAloneSig (0x11):");
  770. }
  771. private void WriteEvent()
  772. {
  773. AddHeader(
  774. "Name",
  775. "Add",
  776. "Remove",
  777. "Fire",
  778. "Attributes"
  779. );
  780. foreach (var handle in _reader.EventDefinitions)
  781. {
  782. var entry = _reader.GetEventDefinition(handle);
  783. var accessors = entry.GetAccessors();
  784. AddRow(
  785. Literal(entry.Name),
  786. Token(() => accessors.Adder),
  787. Token(() => accessors.Remover),
  788. Token(() => accessors.Raiser),
  789. EnumValue<int>(entry.Attributes)
  790. );
  791. }
  792. WriteRows("Event (0x12, 0x14, 0x18):");
  793. }
  794. private void WriteProperty()
  795. {
  796. AddHeader(
  797. "Name",
  798. "Get",
  799. "Set",
  800. "Attributes"
  801. );
  802. foreach (var handle in _reader.PropertyDefinitions)
  803. {
  804. var entry = _reader.GetPropertyDefinition(handle);
  805. var accessors = entry.GetAccessors();
  806. AddRow(
  807. Literal(entry.Name),
  808. Token(() => accessors.Getter),
  809. Token(() => accessors.Setter),
  810. EnumValue<int>(entry.Attributes)
  811. );
  812. }
  813. WriteRows("Property (0x15, 0x17, 0x18):");
  814. }
  815. private void WriteMethodImpl()
  816. {
  817. AddHeader(
  818. "Type",
  819. "Body",
  820. "Declaration"
  821. );
  822. for (int i = 1, count = _reader.GetTableRowCount(TableIndex.MethodImpl); i <= count; i++)
  823. {
  824. var entry = _reader.GetMethodImplementation(MetadataTokens.MethodImplementationHandle(i));
  825. AddRow(
  826. Token(() => entry.Type),
  827. Token(() => entry.MethodBody),
  828. Token(() => entry.MethodDeclaration)
  829. );
  830. }
  831. WriteRows("MethodImpl (0x19):");
  832. }
  833. private void WriteModuleRef()
  834. {
  835. AddHeader("Name");
  836. for (int i = 1, count = _reader.GetTableRowCount(TableIndex.ModuleRef); i <= count; i++)
  837. {
  838. var value = _reader.GetModuleReference(MetadataTokens.ModuleReferenceHandle(i)).Name;
  839. AddRow(Literal(value));
  840. }
  841. WriteRows("ModuleRef (0x1a):");
  842. }
  843. private void WriteTypeSpec()
  844. {
  845. AddHeader("Name");
  846. for (int i = 1, count = _reader.GetTableRowCount(TableIndex.TypeSpec); i <= count; i++)
  847. {
  848. var value = _reader.GetTypeSpecification(MetadataTokens.TypeSpecificationHandle(i)).Signature;
  849. AddRow(Literal(value, BlobKind.TypeSpec));
  850. }
  851. WriteRows("TypeSpec (0x1b):");
  852. }
  853. private void WriteEnCLog()
  854. {
  855. AddHeader(
  856. "Entity",
  857. "Operation");
  858. foreach (var entry in _reader.GetEditAndContinueLogEntries())
  859. {
  860. AddRow(
  861. Token(() => entry.Handle),
  862. EnumValue<int>(entry.Operation));
  863. }
  864. WriteRows("EnC Log (0x1e):");
  865. }
  866. private void WriteEnCMap()
  867. {
  868. if (_aggregator != null)
  869. {
  870. AddHeader("Entity", "Gen", "Row", "Edit");
  871. }
  872. else
  873. {
  874. AddHeader("Entity");
  875. }
  876. foreach (var entry in _reader.GetEditAndContinueMapEntries())
  877. {
  878. if (_aggregator != null)
  879. {
  880. int generation;
  881. EntityHandle primary = (EntityHandle)_aggregator.GetGenerationHandle(entry, out generation);
  882. bool isUpdate = _readers[generation] != _reader;
  883. var primaryModule = _readers[generation].GetModuleDefinition();
  884. AddRow(
  885. Token(() => entry),
  886. primaryModule.Generation.ToString(),
  887. "0x" + MetadataTokens.GetRowNumber(primary).ToString("x6"),
  888. isUpdate ? "update" : "add");
  889. }
  890. else
  891. {
  892. AddRow(Token(() => entry));
  893. }
  894. }
  895. WriteRows("EnC Map (0x1f):");
  896. }
  897. private void WriteAssembly()
  898. {
  899. if (!_reader.IsAssembly)
  900. {
  901. return;
  902. }
  903. AddHeader(
  904. "Name",
  905. "Version",
  906. "Culture",
  907. "PublicKey",
  908. "Flags",
  909. "HashAlgorithm"
  910. );
  911. var entry = _reader.GetAssemblyDefinition();
  912. AddRow(
  913. Literal(entry.Name),
  914. entry.Version.Major + "." + entry.Version.Minor + "." + entry.Version.Revision + "." + entry.Version.Build,
  915. Literal(entry.Culture),
  916. Literal(entry.PublicKey, BlobKind.Key),
  917. EnumValue<int>(entry.Flags),
  918. EnumValue<int>(entry.HashAlgorithm)
  919. );
  920. WriteRows("Assembly (0x20):");
  921. }
  922. private void WriteAssemblyRef()
  923. {
  924. AddHeader(
  925. "Name",
  926. "Version",
  927. "Culture",
  928. "PublicKeyOrToken",
  929. "Flags"
  930. );
  931. foreach (var handle in _reader.AssemblyReferences)
  932. {
  933. var entry = _reader.GetAssemblyReference(handle);
  934. AddRow(
  935. Literal(entry.Name),
  936. entry.Version.Major + "." + entry.Version.Minor + "." + entry.Version.Revision + "." + entry.Version.Build,
  937. Literal(entry.Culture),
  938. Literal(entry.PublicKeyOrToken, BlobKind.Key),
  939. EnumValue<int>(entry.Flags)
  940. );
  941. }
  942. WriteRows("AssemblyRef (0x23):");
  943. }
  944. private void WriteFile()
  945. {
  946. AddHeader(
  947. "Name",
  948. "Metadata",
  949. "HashValue"
  950. );
  951. foreach (var handle in _reader.AssemblyFiles)
  952. {
  953. var entry = _reader.GetAssemblyFile(handle);
  954. AddRow(
  955. Literal(entry.Name),
  956. entry.ContainsMetadata ? "Yes" : "No",
  957. Literal(entry.HashValue, BlobKind.FileHash)
  958. );
  959. }
  960. WriteRows("File (0x26):");
  961. }
  962. private void WriteExportedType()
  963. {
  964. AddHeader(
  965. "Name",
  966. "Namespace",
  967. "Attributes",
  968. "Implementation",
  969. "TypeDefinitionId"
  970. );
  971. foreach (var handle in _reader.ExportedTypes)
  972. {
  973. var entry = _reader.GetExportedType(handle);
  974. AddRow(
  975. Literal(entry.Name),
  976. Literal(entry.Namespace),
  977. entry.Attributes.ToString(),
  978. Token(() => entry.Implementation),
  979. Hex(entry.GetTypeDefinitionId())
  980. );
  981. }
  982. WriteRows("ExportedType (0x27):");
  983. }
  984. private void WriteManifestResource()
  985. {
  986. AddHeader(
  987. "Name",
  988. "Attributes",
  989. "Offset",
  990. "Implementation"
  991. );
  992. foreach (var handle in _reader.ManifestResources)
  993. {
  994. var entry = _reader.GetManifestResource(handle);
  995. AddRow(
  996. Literal(entry.Name),
  997. entry.Attributes.ToString(),
  998. entry.Offset.ToString(),
  999. Token(() => entry.Implementation)
  1000. );
  1001. }
  1002. WriteRows("ManifestResource (0x28):");
  1003. }
  1004. private void WriteGenericParam()
  1005. {
  1006. AddHeader(
  1007. "Name",
  1008. "Seq#",
  1009. "Attributes",
  1010. "Parent",
  1011. "TypeConstraints"
  1012. );
  1013. for (int i = 1, count = _reader.GetTableRowCount(TableIndex.GenericParam); i <= count; i++)
  1014. {
  1015. var entry = _reader.GetGenericParameter(MetadataTokens.GenericParameterHandle(i));
  1016. AddRow(
  1017. Literal(entry.Name),
  1018. entry.Index.ToString(),
  1019. EnumValue<int>(entry.Attributes),
  1020. Token(() => entry.Parent),
  1021. TokenRange(entry.GetConstraints(), h => h)
  1022. );
  1023. }
  1024. WriteRows("GenericParam (0x2a):");
  1025. }
  1026. private void WriteMethodSpec()
  1027. {
  1028. AddHeader(
  1029. "Method",
  1030. "Signature"
  1031. );
  1032. for (int i = 1, count = _reader.GetTableRowCount(TableIndex.MethodSpec); i <= count; i++)
  1033. {
  1034. var entry = _reader.GetMethodSpecification(MetadataTokens.MethodSpecificationHandle(i));
  1035. AddRow(
  1036. Token(() => entry.Method),
  1037. Literal(entry.Signature, BlobKind.MethodSpec)
  1038. );
  1039. }
  1040. WriteRows("MethodSpec (0x2b):");
  1041. }
  1042. private void WriteGenericParamConstraint()
  1043. {
  1044. AddHeader(
  1045. "Parent",
  1046. "Type"
  1047. );
  1048. for (int i = 1, count = _reader.GetTableRowCount(TableIndex.GenericParamConstraint); i <= count; i++)
  1049. {
  1050. var entry = _reader.GetGenericParameterConstraint(MetadataTokens.GenericParameterConstraintHandle(i));
  1051. AddRow(
  1052. Token(() => entry.Parameter),
  1053. Token(() => entry.Type)
  1054. );
  1055. }
  1056. WriteRows("GenericParamConstraint (0x2c):");
  1057. }
  1058. private void WriteUserStrings()
  1059. {
  1060. int size = _reader.GetHeapSize(HeapIndex.UserString);
  1061. if (size == 0)
  1062. {
  1063. return;
  1064. }
  1065. // TODO: the heap is aligned, don't display the trailing empty strings
  1066. _writer.WriteLine($"#US (size = {size}):");
  1067. var handle = MetadataTokens.UserStringHandle(0);
  1068. do
  1069. {
  1070. string value = StringUtilities.EscapeNonPrintableCharacters(_reader.GetUserString(handle));
  1071. _writer.WriteLine($" {_reader.GetHeapOffset(handle):x}: '{value}'");
  1072. handle = _reader.GetNextHandle(handle);
  1073. }
  1074. while (!handle.IsNil);
  1075. _writer.WriteLine();
  1076. }
  1077. private void WriteStrings()
  1078. {
  1079. int size = _reader.GetHeapSize(HeapIndex.String);
  1080. if (size == 0)
  1081. {
  1082. return;
  1083. }
  1084. _writer.WriteLine($"#String (size = {size}):");
  1085. var handle = MetadataTokens.StringHandle(0);
  1086. do
  1087. {
  1088. string value = StringUtilities.EscapeNonPrintableCharacters(_reader.GetString(handle));
  1089. _writer.WriteLine($" {_reader.GetHeapOffset(handle):x}: '{value}'");
  1090. handle = _reader.GetNextHandle(handle);
  1091. }
  1092. while (!handle.IsNil);
  1093. _writer.WriteLine();
  1094. }
  1095. private void WriteBlobs()
  1096. {
  1097. int size = _reader.GetHeapSize(HeapIndex.Blob);
  1098. if (size == 0)
  1099. {
  1100. return;
  1101. }
  1102. int[] sizePerKind = new int[(int)BlobKind.Count];
  1103. _writer.WriteLine($"#Blob (size = {size}):");
  1104. var handle = MetadataTokens.BlobHandle(0);
  1105. do
  1106. {
  1107. byte[] value = _reader.GetBlobBytes(handle);
  1108. BlobKind kind;
  1109. string kindString;
  1110. if (_blobKinds.TryGetValue(handle, out kind))
  1111. {
  1112. kindString = " (" + kind + ")";
  1113. // ignoring the compressed blob size:
  1114. sizePerKind[(int)kind] += value.Length;
  1115. }
  1116. else
  1117. {
  1118. kindString = "";
  1119. }
  1120. int displayLength = (_options & MetadataVisualizerOptions.ShortenBlobs) != 0 ? Math.Min(4, value.Length) : value.Length;
  1121. string valueString = BitConverter.ToString(value, 0, displayLength) + (displayLength < value.Length ? "-..." : null);
  1122. _writer.WriteLine($" {_reader.GetHeapOffset(handle):x}{kindString}: {valueString}");
  1123. handle = _reader.GetNextHandle(handle);
  1124. }
  1125. while (!handle.IsNil);
  1126. _writer.WriteLine();
  1127. _writer.WriteLine("Sizes:");
  1128. for (int i = 0; i < sizePerKind.Length; i++)
  1129. {
  1130. if (sizePerKind[i] > 0)
  1131. {
  1132. _writer.WriteLine($" {(BlobKind)i}: {(decimal)sizePerKind[i]} bytes");
  1133. }
  1134. }
  1135. // don't calculate statistics for EnC delta, it's not interesting
  1136. if (_aggregator == null)
  1137. {
  1138. _writer.WriteLine();
  1139. _writer.WriteLine("CustomAttribute sizes by constructor:");
  1140. try
  1141. {
  1142. foreach (var grouping in from caHandle in _reader.CustomAttributes
  1143. let ca = _reader.GetCustomAttribute(caHandle)
  1144. group ca.Constructor by ca.Value into values // blob -> { ctor1, ctor2, ... }
  1145. group values.Key by values.First() into g // ctor1 -> { blob1, ... }
  1146. select new { Ctor = g.Key, Size = g.Sum(ca => _reader.GetBlobReader(ca).Length) } into ctorAndSize
  1147. orderby ctorAndSize.Size descending
  1148. select ctorAndSize)
  1149. {
  1150. string typeStr = null;
  1151. switch (grouping.Ctor.Kind)
  1152. {
  1153. case HandleKind.MemberReference:
  1154. var memberRef = _reader.GetMemberReference((MemberReferenceHandle)grouping.Ctor);
  1155. switch (memberRef.Parent.Kind)
  1156. {
  1157. case HandleKind.TypeReference:
  1158. var typeRef = _reader.GetTypeReference((TypeReferenceHandle)memberRef.Parent);
  1159. typeStr = typeRef.Namespace.IsNil ? _reader.GetString(typeRef.Name) : _reader.GetString(typeRef.Namespace) + "." + _reader.GetString(typeRef.Name);
  1160. break;
  1161. case HandleKind.TypeDefinition:
  1162. var typeDef = _reader.GetTypeDefinition((TypeDefinitionHandle)memberRef.Parent);
  1163. typeStr = typeDef.Namespace.IsNil ? _reader.GetString(typeDef.Name) : _reader.GetString(typeDef.Namespace) + "." + _reader.GetString(typeDef.Name);
  1164. break;
  1165. case HandleKind.MethodDefinition:
  1166. case HandleKind.ModuleReference:
  1167. case HandleKind.TypeSpecification:
  1168. break;
  1169. }
  1170. break;
  1171. case HandleKind.MethodDefinition:
  1172. // TODO
  1173. break;
  1174. }
  1175. // grouping.Key
  1176. _writer.WriteLine($" {typeStr ?? Token(() => grouping.Ctor)}: {grouping.Size} bytes");
  1177. }
  1178. }
  1179. catch (BadImageFormatException)
  1180. {
  1181. _writer.WriteLine("<bad metadata>");
  1182. }
  1183. _writer.WriteLine();
  1184. }
  1185. }
  1186. private void WriteGuids()
  1187. {
  1188. int size = _reader.GetHeapSize(HeapIndex.Guid);
  1189. if (size == 0)
  1190. {
  1191. return;
  1192. }
  1193. _writer.WriteLine(string.Format("#Guid (size = {0}):", size));
  1194. int i = 1;
  1195. while (i <= size / 16)
  1196. {
  1197. string value = _reader.GetGuid(MetadataTokens.GuidHandle(i)).ToString();
  1198. _writer.WriteLine(" {0:x}: {{{1}}}", i, value);
  1199. i++;
  1200. }
  1201. _writer.WriteLine();
  1202. }
  1203. private void WriteDocument()
  1204. {
  1205. AddHeader(
  1206. "Name",
  1207. "Language",
  1208. "HashAlgorithm",
  1209. "Hash"
  1210. );
  1211. foreach (var handle in _reader.Documents)
  1212. {
  1213. var entry = _reader.GetDocument(handle);
  1214. AddRow(
  1215. Literal(entry.Name),
  1216. Language(entry.Language),
  1217. HashAlgorithm(entry.HashAlgorithm),
  1218. Literal(entry.Hash, BlobKind.DocumentHash)
  1219. );
  1220. }
  1221. WriteTableName(TableIndex.Document);
  1222. }
  1223. private void WriteMethodBody()
  1224. {
  1225. if (_reader.MethodBodies.Count == 0)
  1226. {
  1227. return;
  1228. }
  1229. _writer.WriteLine(MakeTableName(TableIndex.MethodBody));
  1230. _writer.WriteLine(new string('=', 50));
  1231. foreach (var handle in _reader.MethodBodies)
  1232. {
  1233. if (handle.IsNil)
  1234. {
  1235. continue;
  1236. }
  1237. var entry = _reader.GetMethodBody(handle);
  1238. _writer.WriteLine($"{MetadataTokens.GetRowNumber(handle)}: #{_reader.GetHeapOffset(entry.SequencePoints)}");
  1239. if (entry.SequencePoints.IsNil)
  1240. {
  1241. continue;
  1242. }
  1243. _blobKinds[entry.SequencePoints] = BlobKind.SequencePoints;
  1244. _writer.WriteLine("{");
  1245. bool addLineBreak = false;
  1246. var kickoffMethod = entry.GetStateMachineKickoffMethod();
  1247. if (!kickoffMethod.IsNil)
  1248. {
  1249. _writer.WriteLine($" Kickoff Method: {Token(() => kickoffMethod)}");
  1250. addLineBreak = true;
  1251. }
  1252. if (!entry.LocalSignature.IsNil)
  1253. {
  1254. _writer.WriteLine($" Locals: {Token(() => entry.LocalSignature)}");
  1255. addLineBreak = true;
  1256. }
  1257. if (addLineBreak)
  1258. {
  1259. _writer.WriteLine();
  1260. }
  1261. try
  1262. {
  1263. var spReader = _reader.GetSequencePointsReader(entry.SequencePoints);
  1264. while (spReader.MoveNext())
  1265. {
  1266. _writer.Write(" ");
  1267. _writer.WriteLine(SequencePoint(spReader.Current));
  1268. }
  1269. }
  1270. catch (BadImageFormatException)
  1271. {
  1272. _writer.WriteLine("<bad metadata>");
  1273. }
  1274. _writer.WriteLine("}");
  1275. }
  1276. _writer.WriteLine();
  1277. }
  1278. private void WriteLocalScope()
  1279. {
  1280. AddHeader(
  1281. "Method",
  1282. "ImportScope",
  1283. "Variables",
  1284. "Constants",
  1285. "StartOffset",
  1286. "Length"
  1287. );
  1288. foreach (var handle in _reader.LocalScopes)
  1289. {
  1290. var entry = _reader.GetLocalScope(handle);
  1291. AddRow(
  1292. Token(() => entry.Method),
  1293. Token(() => entry.ImportScope),
  1294. TokenRange(entry.GetLocalVariables(), h => h),
  1295. TokenRange(entry.GetLocalConstants(), h => h),
  1296. entry.StartOffset.ToString("X4"),
  1297. entry.Length.ToString()
  1298. );
  1299. }
  1300. WriteTableName(TableIndex.LocalScope);
  1301. }
  1302. private void WriteLocalVariable()
  1303. {
  1304. AddHeader(
  1305. "Name",
  1306. "Index",
  1307. "Attributes"
  1308. );
  1309. foreach (var handle in _reader.LocalVariables)
  1310. {
  1311. var entry = _reader.GetLocalVariable(handle);
  1312. AddRow(
  1313. Literal(entry.Name),
  1314. entry.Index.ToString(),
  1315. entry.Attributes.ToString()
  1316. );
  1317. }
  1318. WriteTableName(TableIndex.LocalVariable);
  1319. }
  1320. private void WriteLocalConstant()
  1321. {
  1322. AddHeader(
  1323. "Name",
  1324. "Signature"
  1325. );
  1326. foreach (var handle in _reader.LocalConstants)
  1327. {
  1328. var entry = _reader.GetLocalConstant(handle);
  1329. AddRow(
  1330. Literal(entry.Name),
  1331. Literal(entry.Signature, BlobKind.LocalConstantSignature, (r, h) => FormatLocalConstant(r, (BlobHandle)h))
  1332. );
  1333. }
  1334. WriteTableName(TableIndex.LocalConstant);
  1335. }
  1336. /*
  1337. private SignatureTypeCode ReadConstantTypeCode(ref BlobReader sigReader, List<CustomModifier<Handle>> modifiers)
  1338. {
  1339. while (true)
  1340. {
  1341. var s = sigReader.ReadSignatureTypeCode();
  1342. if (s == SignatureTypeCode.OptionalModifier || s == SignatureTypeCode.RequiredModifier)
  1343. {
  1344. var type = sigReader.ReadTypeHandle();
  1345. modifiers.Add(new CustomModifier<Handle>(type, isRequired: s == SignatureTypeCode.RequiredModifier));
  1346. }
  1347. else
  1348. {
  1349. return s;
  1350. }
  1351. }
  1352. }
  1353. private string FormatLocalConstant(MetadataReader reader, BlobHandle signature)
  1354. {
  1355. var sigReader = reader.GetBlobReader(signature);
  1356. var modifiers = new List<CustomModifier<Handle>>();
  1357. SignatureTypeCode typeCode = ReadConstantTypeCode(ref sigReader, modifiers);
  1358. Handle typeHandle = default(Handle);
  1359. object value;
  1360. if (IsPrimitiveType(typeCode))
  1361. {
  1362. if (typeCode == SignatureTypeCode.String)
  1363. {
  1364. if (sigReader.RemainingBytes == 1)
  1365. {
  1366. value = (sigReader.ReadByte() == 0xff) ? "null" : "<bad metadata>";
  1367. }
  1368. else if (sigReader.RemainingBytes % 2 != 0)
  1369. {
  1370. value = "<bad metadata>";
  1371. }
  1372. else
  1373. {
  1374. value = "'" + sigReader.ReadUTF16(sigReader.RemainingBytes) + "'";
  1375. }
  1376. }
  1377. else
  1378. {
  1379. value = string.Format(CultureInfo.InvariantCulture, "{0}", sigReader.ReadConstant((ConstantTypeCode)typeCode));
  1380. }
  1381. if (sigReader.RemainingBytes > 0)
  1382. {
  1383. typeHandle = sigReader.ReadTypeHandle();
  1384. }
  1385. }
  1386. else if (typeCode == SignatureTypeCode.TypeHandle)
  1387. {
  1388. typeHandle = sigReader.ReadTypeHandle();
  1389. value = (sigReader.RemainingBytes > 0) ? BitConverter.ToString(sigReader.ReadBytes(sigReader.RemainingBytes)) : "default";
  1390. }
  1391. else
  1392. {
  1393. value = (typeCode == SignatureTypeCode.Object) ? "null" : $"<bad type code: {typeCode}>";
  1394. }
  1395. return string.Format("{0} [{1}{2}]",
  1396. value,
  1397. FormatCustomModifiers(modifiers),
  1398. typeHandle.IsNil ? typeCode.ToString() : Token(() => typeHandle));
  1399. }
  1400. private string FormatCustomModifiers(IEnumerable<CustomModifier<Handle>> modifiers)
  1401. {
  1402. return string.Join(" ", modifiers.Select(m => (m.IsRequired ? "modreq" : "modopt") + "(" + Token(() => m.Type) + ")"));
  1403. }
  1404. */
  1405. private static bool IsPrimitiveType(SignatureTypeCode typeCode)
  1406. {
  1407. switch (typeCode)
  1408. {
  1409. case SignatureTypeCode.Boolean:
  1410. case SignatureTypeCode.Char:
  1411. case SignatureTypeCode.SByte:
  1412. case SignatureTypeCode.Byte:
  1413. case SignatureTypeCode.Int16:
  1414. case SignatureTypeCode.UInt16:
  1415. case SignatureTypeCode.Int32:
  1416. case SignatureTypeCode.UInt32:
  1417. case SignatureTypeCode.Int64:
  1418. case SignatureTypeCode.UInt64:
  1419. case SignatureTypeCode.Single:
  1420. case SignatureTypeCode.Double:
  1421. case SignatureTypeCode.String:
  1422. return true;
  1423. default:
  1424. return false;
  1425. }
  1426. }
  1427. private void WriteLocalImport()
  1428. {
  1429. AddHeader(
  1430. "Parent",
  1431. "Imports"
  1432. );
  1433. foreach (var handle in _reader.ImportScopes)
  1434. {
  1435. var entry = _reader.GetImportScope(handle);
  1436. _blobKinds[entry.Imports] = BlobKind.Imports;
  1437. AddRow(
  1438. Token(() => entry.Parent),
  1439. FormatImports(entry.Imports)
  1440. );
  1441. }
  1442. WriteTableName(TableIndex.ImportScope);
  1443. }
  1444. private void WriteCustomDebugInformation()
  1445. {
  1446. AddHeader(
  1447. "Parent",
  1448. "Value"
  1449. );
  1450. foreach (var handle in _reader.CustomDebugInformation)
  1451. {
  1452. var entry = _reader.GetCustomDebugInformation(handle);
  1453. AddRow(
  1454. Token(() => entry.Parent),
  1455. Literal(entry.Value, BlobKind.CustomDebugInformation)
  1456. );
  1457. }
  1458. WriteTableName(TableIndex.CustomDebugInformation);
  1459. }
  1460. public void VisualizeMethodBody(MethodBodyBlock body, MethodDefinitionHandle generationHandle, int generation)
  1461. {
  1462. VisualizeMethodBody(body, (MethodDefinitionHandle)GetAggregateHandle(generationHandle, generation));
  1463. }
  1464. public void VisualizeMethodBody(MethodBodyBlock body, MethodDefinitionHandle methodHandle, bool emitHeader = true)
  1465. {
  1466. StringBuilder builder = new StringBuilder();
  1467. // TODO: Inspect EncLog to find a containing type and display qualified name.
  1468. var method = GetMethod(methodHandle);
  1469. if (emitHeader)
  1470. {
  1471. builder.AppendFormat("Method {0} (0x{1:X8})", Literal(method.Name), MetadataTokens.GetToken(methodHandle));
  1472. builder.AppendLine();
  1473. }
  1474. // TODO: decode signature
  1475. if (!body.LocalSignature.IsNil)
  1476. {
  1477. var localSignature = GetLocalSignature(body.LocalSignature);
  1478. builder.AppendFormat(" Locals: {0}", Literal(localSignature, BlobKind.StandAloneSignature));
  1479. builder.AppendLine();
  1480. }
  1481. ILVisualizerAsTokens.Instance.DumpMethod(
  1482. builder,
  1483. body.MaxStack,
  1484. body.GetILContent(),
  1485. ImmutableArray.Create<ILVisualizer.LocalInfo>(), // TODO
  1486. ImmutableArray.Create<ILVisualizer.HandlerSpan>()); // TOOD: ILVisualizer.GetHandlerSpans(body.ExceptionRegions)
  1487. builder.AppendLine();
  1488. _writer.Write(builder.ToString());
  1489. }
  1490. public void WriteLine(string line)
  1491. {
  1492. _writer.WriteLine(line);
  1493. }
  1494. private sealed class TokenTypeComparer : IComparer<EntityHandle>
  1495. {
  1496. public static readonly TokenTypeComparer Instance = new TokenTypeComparer();
  1497. public int Compare(EntityHandle x, EntityHandle y)
  1498. {
  1499. return x.Kind.CompareTo(y.Kind);
  1500. }
  1501. }
  1502. }
  1503. }
  1504. #endif