|
@@ -1,1803 +0,0 @@
|
|
|
-// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
|
|
|
-
|
|
|
|
|
-#if nope
|
|
|
|
|
-
|
|
|
|
|
-using System;
|
|
|
|
|
-using System.Collections.Generic;
|
|
|
|
|
-using System.Collections.Immutable;
|
|
|
|
|
-using System.Diagnostics;
|
|
|
|
|
-using System.Globalization;
|
|
|
|
|
-using System.IO;
|
|
|
|
|
-using System.Linq;
|
|
|
|
|
-using System.Reflection.Metadata;
|
|
|
|
|
-//using System.Reflection.Metadata.Decoding;
|
|
|
|
|
-using System.Reflection.Metadata.Ecma335;
|
|
|
|
|
-using System.Text;
|
|
|
|
|
-
|
|
|
|
|
-namespace Roslyn.Test.MetadataUtilities
|
|
|
|
|
-{
|
|
|
|
|
- [Flags]
|
|
|
|
|
- public enum MetadataVisualizerOptions
|
|
|
|
|
- {
|
|
|
|
|
- None = 0,
|
|
|
|
|
- ShortenBlobs = 1,
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- public sealed class MetadataVisualizer
|
|
|
|
|
- {
|
|
|
|
|
- private enum BlobKind
|
|
|
|
|
- {
|
|
|
|
|
- None,
|
|
|
|
|
- Key,
|
|
|
|
|
- FileHash,
|
|
|
|
|
-
|
|
|
|
|
- MethodSignature,
|
|
|
|
|
- FieldSignature,
|
|
|
|
|
- MemberRefSignature,
|
|
|
|
|
- StandAloneSignature,
|
|
|
|
|
-
|
|
|
|
|
- TypeSpec,
|
|
|
|
|
- MethodSpec,
|
|
|
|
|
-
|
|
|
|
|
- ConstantValue,
|
|
|
|
|
- Marshalling,
|
|
|
|
|
- PermissionSet,
|
|
|
|
|
- CustomAttribute,
|
|
|
|
|
-
|
|
|
|
|
- DocumentName,
|
|
|
|
|
- DocumentHash,
|
|
|
|
|
- SequencePoints,
|
|
|
|
|
- Imports,
|
|
|
|
|
- ImportAlias,
|
|
|
|
|
- ImportNamespace,
|
|
|
|
|
- LocalConstantSignature,
|
|
|
|
|
- CustomDebugInformation,
|
|
|
|
|
-
|
|
|
|
|
- Count
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- private readonly TextWriter _writer;
|
|
|
|
|
- private readonly IReadOnlyList<MetadataReader> _readers;
|
|
|
|
|
- private readonly MetadataAggregator _aggregator;
|
|
|
|
|
- private readonly MetadataVisualizerOptions _options;
|
|
|
|
|
-
|
|
|
|
|
- // enc map for each delta reader
|
|
|
|
|
- private readonly ImmutableArray<ImmutableArray<EntityHandle>> _encMaps;
|
|
|
|
|
-
|
|
|
|
|
- private MetadataReader _reader;
|
|
|
|
|
- private readonly List<string[]> _pendingRows = new List<string[]>();
|
|
|
|
|
- private readonly Dictionary<BlobHandle, BlobKind> _blobKinds = new Dictionary<BlobHandle, BlobKind>();
|
|
|
|
|
-
|
|
|
|
|
- private MetadataVisualizer(TextWriter writer, IReadOnlyList<MetadataReader> readers, MetadataVisualizerOptions options = MetadataVisualizerOptions.None)
|
|
|
|
|
- {
|
|
|
|
|
- _writer = writer;
|
|
|
|
|
- _readers = readers;
|
|
|
|
|
- _options = options;
|
|
|
|
|
-
|
|
|
|
|
- if (readers.Count > 1)
|
|
|
|
|
- {
|
|
|
|
|
- var deltaReaders = new List<MetadataReader>(readers.Skip(1));
|
|
|
|
|
- _aggregator = new MetadataAggregator(readers[0], deltaReaders);
|
|
|
|
|
-
|
|
|
|
|
- _encMaps = ImmutableArray.CreateRange(deltaReaders.Select(reader => ImmutableArray.CreateRange(reader.GetEditAndContinueMapEntries())));
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- public MetadataVisualizer(MetadataReader reader, TextWriter writer, MetadataVisualizerOptions options = MetadataVisualizerOptions.None)
|
|
|
|
|
- : this(writer, new[] { reader }, options)
|
|
|
|
|
- {
|
|
|
|
|
- _reader = reader;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- public MetadataVisualizer(IReadOnlyList<MetadataReader> readers, TextWriter writer, MetadataVisualizerOptions options = MetadataVisualizerOptions.None)
|
|
|
|
|
- : this(writer, readers, options)
|
|
|
|
|
- {
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- public void VisualizeAllGenerations()
|
|
|
|
|
- {
|
|
|
|
|
- for (int i = 0; i < _readers.Count; i++)
|
|
|
|
|
- {
|
|
|
|
|
- _writer.WriteLine(">>>");
|
|
|
|
|
- _writer.WriteLine($">>> Generation {i}:");
|
|
|
|
|
- _writer.WriteLine(">>>");
|
|
|
|
|
- _writer.WriteLine();
|
|
|
|
|
-
|
|
|
|
|
- Visualize(i);
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- public void Visualize(int generation = -1)
|
|
|
|
|
- {
|
|
|
|
|
- _reader = (generation >= 0) ? _readers[generation] : _readers[_readers.Count - 1];
|
|
|
|
|
-
|
|
|
|
|
- WriteModule();
|
|
|
|
|
- WriteTypeRef();
|
|
|
|
|
- WriteTypeDef();
|
|
|
|
|
- WriteField();
|
|
|
|
|
- WriteMethod();
|
|
|
|
|
- WriteParam();
|
|
|
|
|
- WriteMemberRef();
|
|
|
|
|
- WriteConstant();
|
|
|
|
|
- WriteCustomAttribute();
|
|
|
|
|
- WriteDeclSecurity();
|
|
|
|
|
- WriteStandAloneSig();
|
|
|
|
|
- WriteEvent();
|
|
|
|
|
- WriteProperty();
|
|
|
|
|
- WriteMethodImpl();
|
|
|
|
|
- WriteModuleRef();
|
|
|
|
|
- WriteTypeSpec();
|
|
|
|
|
- WriteEnCLog();
|
|
|
|
|
- WriteEnCMap();
|
|
|
|
|
- WriteAssembly();
|
|
|
|
|
- WriteAssemblyRef();
|
|
|
|
|
- WriteFile();
|
|
|
|
|
- WriteExportedType();
|
|
|
|
|
- WriteManifestResource();
|
|
|
|
|
- WriteGenericParam();
|
|
|
|
|
- WriteMethodSpec();
|
|
|
|
|
- WriteGenericParamConstraint();
|
|
|
|
|
-
|
|
|
|
|
- // debug tables:
|
|
|
|
|
- WriteDocument();
|
|
|
|
|
- WriteMethodBody();
|
|
|
|
|
- WriteLocalScope();
|
|
|
|
|
- WriteLocalVariable();
|
|
|
|
|
- WriteLocalConstant();
|
|
|
|
|
- WriteLocalImport();
|
|
|
|
|
- WriteCustomDebugInformation();
|
|
|
|
|
-
|
|
|
|
|
- // heaps:
|
|
|
|
|
- WriteUserStrings();
|
|
|
|
|
- WriteStrings();
|
|
|
|
|
- WriteBlobs();
|
|
|
|
|
- WriteGuids();
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- private bool IsDelta
|
|
|
|
|
- {
|
|
|
|
|
- get
|
|
|
|
|
- {
|
|
|
|
|
- return _reader.GetTableRowCount(TableIndex.EncLog) > 0;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- private void WriteTableName(TableIndex index)
|
|
|
|
|
- {
|
|
|
|
|
- WriteRows(MakeTableName(index));
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- private string MakeTableName(TableIndex index)
|
|
|
|
|
- {
|
|
|
|
|
- return $"{index} (index: 0x{(byte)index:X2}, size: {_reader.GetTableRowCount(index) * _reader.GetTableRowSize(index)}): ";
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- private void AddHeader(params string[] header)
|
|
|
|
|
- {
|
|
|
|
|
- Debug.Assert(_pendingRows.Count == 0);
|
|
|
|
|
- _pendingRows.Add(header);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- private void AddRow(params string[] fields)
|
|
|
|
|
- {
|
|
|
|
|
- Debug.Assert(_pendingRows.Count > 0 && _pendingRows.Last().Length == fields.Length);
|
|
|
|
|
- _pendingRows.Add(fields);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- private void WriteRows(string title)
|
|
|
|
|
- {
|
|
|
|
|
- Debug.Assert(_pendingRows.Count > 0);
|
|
|
|
|
-
|
|
|
|
|
- if (_pendingRows.Count == 1)
|
|
|
|
|
- {
|
|
|
|
|
- _pendingRows.Clear();
|
|
|
|
|
- return;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- _writer.Write(title);
|
|
|
|
|
- _writer.WriteLine();
|
|
|
|
|
-
|
|
|
|
|
- string columnSeparator = " ";
|
|
|
|
|
- int rowNumberWidth = _pendingRows.Count.ToString("x").Length;
|
|
|
|
|
-
|
|
|
|
|
- int[] columnWidths = new int[_pendingRows.First().Length];
|
|
|
|
|
- foreach (var row in _pendingRows)
|
|
|
|
|
- {
|
|
|
|
|
- for (int c = 0; c < row.Length; c++)
|
|
|
|
|
- {
|
|
|
|
|
- columnWidths[c] = Math.Max(columnWidths[c], row[c].Length + columnSeparator.Length);
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- int tableWidth = columnWidths.Sum() + columnWidths.Length;
|
|
|
|
|
- string horizontalSeparator = new string('=', tableWidth);
|
|
|
|
|
-
|
|
|
|
|
- for (int r = 0; r < _pendingRows.Count; r++)
|
|
|
|
|
- {
|
|
|
|
|
- var row = _pendingRows[r];
|
|
|
|
|
-
|
|
|
|
|
- // header
|
|
|
|
|
- if (r == 0)
|
|
|
|
|
- {
|
|
|
|
|
- _writer.WriteLine(horizontalSeparator);
|
|
|
|
|
- _writer.Write(new string(' ', rowNumberWidth + 2));
|
|
|
|
|
- }
|
|
|
|
|
- else
|
|
|
|
|
- {
|
|
|
|
|
- string rowNumber = r.ToString("x");
|
|
|
|
|
- _writer.Write(new string(' ', rowNumberWidth - rowNumber.Length));
|
|
|
|
|
- _writer.Write(rowNumber);
|
|
|
|
|
- _writer.Write(": ");
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- for (int c = 0; c < row.Length; c++)
|
|
|
|
|
- {
|
|
|
|
|
- var field = row[c];
|
|
|
|
|
-
|
|
|
|
|
- _writer.Write(field);
|
|
|
|
|
- _writer.Write(new string(' ', columnWidths[c] - field.Length));
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- _writer.WriteLine();
|
|
|
|
|
-
|
|
|
|
|
- // header
|
|
|
|
|
- if (r == 0)
|
|
|
|
|
- {
|
|
|
|
|
- _writer.WriteLine(horizontalSeparator);
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- _writer.WriteLine();
|
|
|
|
|
- _pendingRows.Clear();
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- private EntityHandle GetAggregateHandle(EntityHandle generationHandle, int generation)
|
|
|
|
|
- {
|
|
|
|
|
- var encMap = _encMaps[generation - 1];
|
|
|
|
|
-
|
|
|
|
|
- int start, count;
|
|
|
|
|
- if (!TryGetHandleRange(encMap, generationHandle.Kind, out start, out count))
|
|
|
|
|
- {
|
|
|
|
|
- throw new BadImageFormatException(string.Format("EncMap is missing record for {0:8X}.", MetadataTokens.GetToken(generationHandle)));
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- return encMap[start + MetadataTokens.GetRowNumber(generationHandle) - 1];
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- private static bool TryGetHandleRange(ImmutableArray<EntityHandle> handles, HandleKind handleType, out int start, out int count)
|
|
|
|
|
- {
|
|
|
|
|
- TableIndex tableIndex;
|
|
|
|
|
- MetadataTokens.TryGetTableIndex(handleType, out tableIndex);
|
|
|
|
|
-
|
|
|
|
|
- int mapIndex = handles.BinarySearch(MetadataTokens.Handle(tableIndex, 0), TokenTypeComparer.Instance);
|
|
|
|
|
- if (mapIndex < 0)
|
|
|
|
|
- {
|
|
|
|
|
- start = 0;
|
|
|
|
|
- count = 0;
|
|
|
|
|
- return false;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- int s = mapIndex;
|
|
|
|
|
- while (s >= 0 && handles[s].Kind == handleType)
|
|
|
|
|
- {
|
|
|
|
|
- s--;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- int e = mapIndex;
|
|
|
|
|
- while (e < handles.Length && handles[e].Kind == handleType)
|
|
|
|
|
- {
|
|
|
|
|
- e++;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- start = s + 1;
|
|
|
|
|
- count = e - start;
|
|
|
|
|
- return true;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- private MethodDefinition GetMethod(MethodDefinitionHandle handle)
|
|
|
|
|
- {
|
|
|
|
|
- return Get(handle, (reader, h) => reader.GetMethodDefinition((MethodDefinitionHandle)h));
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- private BlobHandle GetLocalSignature(StandaloneSignatureHandle handle)
|
|
|
|
|
- {
|
|
|
|
|
- return Get(handle, (reader, h) => reader.GetStandaloneSignature((StandaloneSignatureHandle)h).Signature);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- private TEntity Get<TEntity>(Handle handle, Func<MetadataReader, Handle, TEntity> getter)
|
|
|
|
|
- {
|
|
|
|
|
- if (_aggregator != null)
|
|
|
|
|
- {
|
|
|
|
|
- int generation;
|
|
|
|
|
- var generationHandle = _aggregator.GetGenerationHandle(handle, out generation);
|
|
|
|
|
- return getter(_readers[generation], generationHandle);
|
|
|
|
|
- }
|
|
|
|
|
- else
|
|
|
|
|
- {
|
|
|
|
|
- return getter(_reader, handle);
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- private string Literal(StringHandle handle)
|
|
|
|
|
- {
|
|
|
|
|
- return Literal(handle, BlobKind.None, (r, h) => "'" + StringUtilities.EscapeNonPrintableCharacters(r.GetString((StringHandle)h)) + "'");
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- private string Literal(NamespaceDefinitionHandle handle)
|
|
|
|
|
- {
|
|
|
|
|
- return Literal(handle, BlobKind.None, (r, h) => "'" + StringUtilities.EscapeNonPrintableCharacters(r.GetString((NamespaceDefinitionHandle)h)) + "'");
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- private string Literal(GuidHandle handle)
|
|
|
|
|
- {
|
|
|
|
|
- return Literal(handle, BlobKind.None, (r, h) => "{" + r.GetGuid((GuidHandle)h) + "}");
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- private static Guid CSharpGuid = new Guid("3f5162f8-07c6-11d3-9053-00c04fa302a1");
|
|
|
|
|
- private static Guid VisualBasicGuid = new Guid("3a12d0b8-c26c-11d0-b442-00a0244a1dd2");
|
|
|
|
|
- private static Guid FSharpGuid = new Guid("ab4f38c9-b6e6-43ba-be3b-58080b2ccce3");
|
|
|
|
|
- private static Guid Sha1Guid = new Guid("ff1816ec-aa5e-4d10-87f7-6f4963833460");
|
|
|
|
|
- private static Guid Sha256Guid = new Guid("8829d00f-11b8-4213-878b-770e8597ac16");
|
|
|
|
|
-
|
|
|
|
|
- private string GetLanguage(Guid guid)
|
|
|
|
|
- {
|
|
|
|
|
- if (guid == CSharpGuid) return "C#";
|
|
|
|
|
- if (guid == VisualBasicGuid) return "Visual Basic";
|
|
|
|
|
- if (guid == FSharpGuid) return "F#";
|
|
|
|
|
-
|
|
|
|
|
- return "{" + guid + "}";
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- private string GetHashAlgorithm(Guid guid)
|
|
|
|
|
- {
|
|
|
|
|
- if (guid == Sha1Guid) return "SHA-1";
|
|
|
|
|
- if (guid == Sha256Guid) return "SHA-256";
|
|
|
|
|
-
|
|
|
|
|
- return "{" + guid + "}";
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- private string Language(GuidHandle handle)
|
|
|
|
|
- {
|
|
|
|
|
- return Literal(handle, BlobKind.None, (r, h) => GetLanguage(r.GetGuid((GuidHandle)h)));
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- private string HashAlgorithm(GuidHandle handle)
|
|
|
|
|
- {
|
|
|
|
|
- return Literal(handle, BlobKind.None, (r, h) => GetHashAlgorithm(r.GetGuid((GuidHandle)h)));
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
-/*
|
|
|
|
|
- private string Literal(DocumentNameBlobHandle handle)
|
|
|
|
|
- {
|
|
|
|
|
- return Literal((BlobHandle)handle, BlobKind.DocumentName, (r, h) => "'" + r.GetString((DocumentNameBlobHandle)(BlobHandle)h) + "'");
|
|
|
|
|
- }
|
|
|
|
|
-*/
|
|
|
|
|
- private string LiteralUtf8Blob(BlobHandle handle, BlobKind kind)
|
|
|
|
|
- {
|
|
|
|
|
- return Literal(handle, kind, (r, h) =>
|
|
|
|
|
- {
|
|
|
|
|
- var bytes = r.GetBlobBytes((BlobHandle)h);
|
|
|
|
|
- return "'" + Encoding.UTF8.GetString(bytes, 0, bytes.Length) + "'";
|
|
|
|
|
- });
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- private string Literal(BlobHandle handle, BlobKind kind)
|
|
|
|
|
- {
|
|
|
|
|
- return Literal(handle, kind, (r, h) => BitConverter.ToString(r.GetBlobBytes((BlobHandle)h)));
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- private string Literal(Handle handle, BlobKind kind, Func<MetadataReader, Handle, string> getValue)
|
|
|
|
|
- {
|
|
|
|
|
- if (handle.IsNil)
|
|
|
|
|
- {
|
|
|
|
|
- return "nil";
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- if (kind != BlobKind.None)
|
|
|
|
|
- {
|
|
|
|
|
- _blobKinds[(BlobHandle)handle] = kind;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- if (_aggregator != null)
|
|
|
|
|
- {
|
|
|
|
|
- int generation;
|
|
|
|
|
- Handle generationHandle = _aggregator.GetGenerationHandle(handle, out generation);
|
|
|
|
|
-
|
|
|
|
|
- var generationReader = _readers[generation];
|
|
|
|
|
- string value = GetValueChecked(getValue, generationReader, generationHandle);
|
|
|
|
|
- int offset = generationReader.GetHeapOffset(handle);
|
|
|
|
|
- int generationOffset = generationReader.GetHeapOffset(generationHandle);
|
|
|
|
|
-
|
|
|
|
|
- if (offset == generationOffset)
|
|
|
|
|
- {
|
|
|
|
|
- return $"{value} (#{offset:x})";
|
|
|
|
|
- }
|
|
|
|
|
- else
|
|
|
|
|
- {
|
|
|
|
|
- return $"{value} (#{offset:x}/{generationOffset:x})";
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- if (IsDelta)
|
|
|
|
|
- {
|
|
|
|
|
- // we can't resolve the literal without aggregate reader
|
|
|
|
|
- return string.Format("#{0:x}", _reader.GetHeapOffset(handle));
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // virtual heap handles don't have offset:
|
|
|
|
|
- int heapOffset = MetadataTokens.GetHeapOffset(handle);
|
|
|
|
|
- return $"{GetValueChecked(getValue, _reader, handle):x}" + (heapOffset >= 0 ? $" (#{heapOffset:x})" : "");
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- private string GetValueChecked(Func<MetadataReader, Handle, string> getValue, MetadataReader reader, Handle handle)
|
|
|
|
|
- {
|
|
|
|
|
- try
|
|
|
|
|
- {
|
|
|
|
|
- return getValue(reader, handle);
|
|
|
|
|
- }
|
|
|
|
|
- catch (BadImageFormatException)
|
|
|
|
|
- {
|
|
|
|
|
- return "<bad metadata>";
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- private string Hex(ushort value)
|
|
|
|
|
- {
|
|
|
|
|
- return "0x" + value.ToString("X4");
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- private string Hex(int value)
|
|
|
|
|
- {
|
|
|
|
|
- return "0x" + value.ToString("X8");
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- public string Token(Func<Handle> handleFunc, bool displayTable = true)
|
|
|
|
|
- {
|
|
|
|
|
- Handle handle;
|
|
|
|
|
-
|
|
|
|
|
- try
|
|
|
|
|
- {
|
|
|
|
|
- handle = handleFunc();
|
|
|
|
|
- }
|
|
|
|
|
- catch (BadImageFormatException)
|
|
|
|
|
- {
|
|
|
|
|
- return "<bad metadata>";
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- if (handle.IsNil)
|
|
|
|
|
- {
|
|
|
|
|
- return "nil";
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- TableIndex table;
|
|
|
|
|
- if (displayTable && MetadataTokens.TryGetTableIndex(handle.Kind, out table))
|
|
|
|
|
- {
|
|
|
|
|
- return string.Format("0x{0:x8} ({1})", _reader.GetToken(handle), table);
|
|
|
|
|
- }
|
|
|
|
|
- else
|
|
|
|
|
- {
|
|
|
|
|
- return string.Format("0x{0:x8}", _reader.GetToken(handle));
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- private static string EnumValue<T>(object value) where T : IEquatable<T>
|
|
|
|
|
- {
|
|
|
|
|
- T integralValue = (T)value;
|
|
|
|
|
- if (integralValue.Equals(default(T)))
|
|
|
|
|
- {
|
|
|
|
|
- return "0";
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- return string.Format("0x{0:x8} ({1})", integralValue, value);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // TODO (tomat): handle collections should implement IReadOnlyCollection<Handle>
|
|
|
|
|
- private string TokenRange<THandle>(IReadOnlyCollection<THandle> handles, Func<THandle, EntityHandle> conversion)
|
|
|
|
|
- {
|
|
|
|
|
- var genericHandles = handles.Select(conversion);
|
|
|
|
|
-
|
|
|
|
|
- if (handles.Count < 0)
|
|
|
|
|
- {
|
|
|
|
|
- return "<bad token range>";
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- return (handles.Count == 0) ? "nil" : Token(() => genericHandles.First(), displayTable: false) + "-" + Token(() => genericHandles.Last(), displayTable: false);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- public string TokenList(IReadOnlyCollection<EntityHandle> handles, bool displayTable = false)
|
|
|
|
|
- {
|
|
|
|
|
- if (handles.Count == 0)
|
|
|
|
|
- {
|
|
|
|
|
- return "nil";
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- return string.Join(", ", handles.Select(h => Token(() => h, displayTable)));
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- private string FormatAwaits(BlobHandle handle)
|
|
|
|
|
- {
|
|
|
|
|
- var sb = new StringBuilder();
|
|
|
|
|
- var blobReader = _reader.GetBlobReader(handle);
|
|
|
|
|
-
|
|
|
|
|
- while (blobReader.RemainingBytes > 0)
|
|
|
|
|
- {
|
|
|
|
|
- if (blobReader.Offset > 0)
|
|
|
|
|
- {
|
|
|
|
|
- sb.Append(", ");
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- int value;
|
|
|
|
|
- sb.Append("(");
|
|
|
|
|
- sb.Append(blobReader.TryReadCompressedInteger(out value) ? value.ToString() : "?");
|
|
|
|
|
- sb.Append(", ");
|
|
|
|
|
- sb.Append(blobReader.TryReadCompressedInteger(out value) ? value.ToString() : "?");
|
|
|
|
|
- sb.Append(", ");
|
|
|
|
|
- sb.Append(blobReader.TryReadCompressedInteger(out value) ? Token(() => MetadataTokens.MethodDefinitionHandle(value)) : "?");
|
|
|
|
|
- sb.Append(')');
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- return sb.ToString();
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- private string FormatImports(BlobHandle handle)
|
|
|
|
|
- {
|
|
|
|
|
- if (handle.IsNil)
|
|
|
|
|
- {
|
|
|
|
|
- return "nil";
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- var sb = new StringBuilder();
|
|
|
|
|
-
|
|
|
|
|
- var importsReader = _reader.GetImportsReader(handle);
|
|
|
|
|
- while (importsReader.MoveNext())
|
|
|
|
|
- {
|
|
|
|
|
- if (sb.Length > 0)
|
|
|
|
|
- {
|
|
|
|
|
- sb.Append(", ");
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- var import = importsReader.Current;
|
|
|
|
|
- switch (import.Kind)
|
|
|
|
|
- {
|
|
|
|
|
- case ImportDefinitionKind.ImportNamespace:
|
|
|
|
|
- sb.AppendFormat("{0}", LiteralUtf8Blob(import.TargetNamespace, BlobKind.ImportNamespace));
|
|
|
|
|
- break;
|
|
|
|
|
-
|
|
|
|
|
- case ImportDefinitionKind.ImportAssemblyNamespace:
|
|
|
|
|
- sb.AppendFormat("{0}::{1}",
|
|
|
|
|
- Token(() => import.TargetAssembly),
|
|
|
|
|
- LiteralUtf8Blob(import.TargetNamespace, BlobKind.ImportNamespace));
|
|
|
|
|
- break;
|
|
|
|
|
-
|
|
|
|
|
- case ImportDefinitionKind.ImportType:
|
|
|
|
|
- sb.AppendFormat("{0}::{1}",
|
|
|
|
|
- Token(() => import.TargetAssembly),
|
|
|
|
|
- Token(() => import.TargetType));
|
|
|
|
|
- break;
|
|
|
|
|
-
|
|
|
|
|
- case ImportDefinitionKind.ImportXmlNamespace:
|
|
|
|
|
- sb.AppendFormat("<{0} = {1}>",
|
|
|
|
|
- LiteralUtf8Blob(import.Alias, BlobKind.ImportAlias),
|
|
|
|
|
- LiteralUtf8Blob(import.TargetNamespace, BlobKind.ImportNamespace));
|
|
|
|
|
- break;
|
|
|
|
|
-
|
|
|
|
|
- case ImportDefinitionKind.ImportAssemblyReferenceAlias:
|
|
|
|
|
- sb.AppendFormat("Extern Alias {0}",
|
|
|
|
|
- LiteralUtf8Blob(import.Alias, BlobKind.ImportAlias));
|
|
|
|
|
- break;
|
|
|
|
|
-
|
|
|
|
|
- case ImportDefinitionKind.AliasAssemblyReference:
|
|
|
|
|
- sb.AppendFormat("{0} = {1}",
|
|
|
|
|
- LiteralUtf8Blob(import.Alias, BlobKind.ImportAlias),
|
|
|
|
|
- Token(() => import.TargetAssembly));
|
|
|
|
|
- break;
|
|
|
|
|
-
|
|
|
|
|
- case ImportDefinitionKind.AliasNamespace:
|
|
|
|
|
- sb.AppendFormat("{0} = {1}",
|
|
|
|
|
- LiteralUtf8Blob(import.Alias, BlobKind.ImportAlias),
|
|
|
|
|
- LiteralUtf8Blob(import.TargetNamespace, BlobKind.ImportNamespace));
|
|
|
|
|
- break;
|
|
|
|
|
-
|
|
|
|
|
- case ImportDefinitionKind.AliasAssemblyNamespace:
|
|
|
|
|
- sb.AppendFormat("{0} = {1}::{2}",
|
|
|
|
|
- LiteralUtf8Blob(import.Alias, BlobKind.ImportAlias),
|
|
|
|
|
- Token(() => import.TargetAssembly),
|
|
|
|
|
- LiteralUtf8Blob(import.TargetNamespace, BlobKind.ImportNamespace));
|
|
|
|
|
- break;
|
|
|
|
|
-
|
|
|
|
|
- case ImportDefinitionKind.AliasType:
|
|
|
|
|
- sb.AppendFormat("{0} = {1}",
|
|
|
|
|
- LiteralUtf8Blob(import.Alias, BlobKind.ImportAlias),
|
|
|
|
|
- Token(() => import.TargetType));
|
|
|
|
|
- break;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- return sb.ToString();
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
-/*
|
|
|
|
|
- private string SequencePoint(SequencePoint sequencePoint)
|
|
|
|
|
- {
|
|
|
|
|
- string range = sequencePoint.IsHidden ? "<hidden>" : $"({sequencePoint.StartLine}, {sequencePoint.StartColumn}) - ({sequencePoint.EndLine}, {sequencePoint.EndColumn})";
|
|
|
|
|
- return $"IL_{sequencePoint.Offset:X4}: " + range;
|
|
|
|
|
- }
|
|
|
|
|
-*/
|
|
|
|
|
- public void VisualizeHeaders()
|
|
|
|
|
- {
|
|
|
|
|
- _reader = _readers[0];
|
|
|
|
|
-
|
|
|
|
|
- _writer.WriteLine("MetadataVersion: {0}", _reader.MetadataVersion);
|
|
|
|
|
-
|
|
|
|
|
- if (_reader.DebugMetadataHeader != null)
|
|
|
|
|
- {
|
|
|
|
|
- if (!_reader.DebugMetadataHeader.EntryPoint.IsNil)
|
|
|
|
|
- {
|
|
|
|
|
- _writer.WriteLine("EntryPoint: {0}", Token(() => _reader.DebugMetadataHeader.EntryPoint));
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- _writer.WriteLine();
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- private void WriteModule()
|
|
|
|
|
- {
|
|
|
|
|
- if (_reader.DebugMetadataHeader != null)
|
|
|
|
|
- {
|
|
|
|
|
- return;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- var def = _reader.GetModuleDefinition();
|
|
|
|
|
-
|
|
|
|
|
- AddHeader(
|
|
|
|
|
- "Gen",
|
|
|
|
|
- "Name",
|
|
|
|
|
- "Mvid",
|
|
|
|
|
- "EncId",
|
|
|
|
|
- "EncBaseId"
|
|
|
|
|
- );
|
|
|
|
|
-
|
|
|
|
|
- AddRow(
|
|
|
|
|
- def.Generation.ToString(),
|
|
|
|
|
- Literal(def.Name),
|
|
|
|
|
- Literal(def.Mvid),
|
|
|
|
|
- Literal(def.GenerationId),
|
|
|
|
|
- Literal(def.BaseGenerationId));
|
|
|
|
|
-
|
|
|
|
|
- WriteRows("Module (0x00):");
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- private void WriteTypeRef()
|
|
|
|
|
- {
|
|
|
|
|
- AddHeader(
|
|
|
|
|
- "Scope",
|
|
|
|
|
- "Name",
|
|
|
|
|
- "Namespace"
|
|
|
|
|
- );
|
|
|
|
|
-
|
|
|
|
|
- foreach (var handle in _reader.TypeReferences)
|
|
|
|
|
- {
|
|
|
|
|
- var entry = _reader.GetTypeReference(handle);
|
|
|
|
|
-
|
|
|
|
|
- AddRow(
|
|
|
|
|
- Token(() => entry.ResolutionScope),
|
|
|
|
|
- Literal(entry.Name),
|
|
|
|
|
- Literal(entry.Namespace)
|
|
|
|
|
- );
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- WriteRows("TypeRef (0x01):");
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- private void WriteTypeDef()
|
|
|
|
|
- {
|
|
|
|
|
- AddHeader(
|
|
|
|
|
- "Name",
|
|
|
|
|
- "Namespace",
|
|
|
|
|
- "EnclosingType",
|
|
|
|
|
- "BaseType",
|
|
|
|
|
- "Interfaces",
|
|
|
|
|
- "Fields",
|
|
|
|
|
- "Methods",
|
|
|
|
|
- "Attributes",
|
|
|
|
|
- "ClassSize",
|
|
|
|
|
- "PackingSize"
|
|
|
|
|
- );
|
|
|
|
|
-
|
|
|
|
|
- foreach (var handle in _reader.TypeDefinitions)
|
|
|
|
|
- {
|
|
|
|
|
- var entry = _reader.GetTypeDefinition(handle);
|
|
|
|
|
-
|
|
|
|
|
- var layout = entry.GetLayout();
|
|
|
|
|
-
|
|
|
|
|
- // TODO: Visualize InterfaceImplementations
|
|
|
|
|
- var implementedInterfaces = entry.GetInterfaceImplementations().Select(h => _reader.GetInterfaceImplementation(h).Interface).ToArray();
|
|
|
|
|
-
|
|
|
|
|
- AddRow(
|
|
|
|
|
- Literal(entry.Name),
|
|
|
|
|
- Literal(entry.Namespace),
|
|
|
|
|
- Token(() => entry.GetDeclaringType()),
|
|
|
|
|
- Token(() => entry.BaseType),
|
|
|
|
|
- TokenList(implementedInterfaces),
|
|
|
|
|
- TokenRange(entry.GetFields(), h => h),
|
|
|
|
|
- TokenRange(entry.GetMethods(), h => h),
|
|
|
|
|
- EnumValue<int>(entry.Attributes),
|
|
|
|
|
- !layout.IsDefault ? layout.Size.ToString() : "n/a",
|
|
|
|
|
- !layout.IsDefault ? layout.PackingSize.ToString() : "n/a"
|
|
|
|
|
- );
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- WriteRows("TypeDef (0x02):");
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- private void WriteField()
|
|
|
|
|
- {
|
|
|
|
|
- AddHeader(
|
|
|
|
|
- "Name",
|
|
|
|
|
- "Signature",
|
|
|
|
|
- "Attributes",
|
|
|
|
|
- "Marshalling",
|
|
|
|
|
- "Offset",
|
|
|
|
|
- "RVA"
|
|
|
|
|
- );
|
|
|
|
|
-
|
|
|
|
|
- foreach (var handle in _reader.FieldDefinitions)
|
|
|
|
|
- {
|
|
|
|
|
- var entry = _reader.GetFieldDefinition(handle);
|
|
|
|
|
-
|
|
|
|
|
- int offset = entry.GetOffset();
|
|
|
|
|
-
|
|
|
|
|
- AddRow(
|
|
|
|
|
- Literal(entry.Name),
|
|
|
|
|
- Literal(entry.Signature, BlobKind.FieldSignature),
|
|
|
|
|
- EnumValue<int>(entry.Attributes),
|
|
|
|
|
- Literal(entry.GetMarshallingDescriptor(), BlobKind.Marshalling),
|
|
|
|
|
- offset >= 0 ? offset.ToString() : "n/a",
|
|
|
|
|
- entry.GetRelativeVirtualAddress().ToString()
|
|
|
|
|
- );
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- WriteRows("Field (0x04):");
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- private void WriteMethod()
|
|
|
|
|
- {
|
|
|
|
|
- AddHeader(
|
|
|
|
|
- "Name",
|
|
|
|
|
- "Signature",
|
|
|
|
|
- "RVA",
|
|
|
|
|
- "Parameters",
|
|
|
|
|
- "GenericParameters",
|
|
|
|
|
- "ImplAttributes",
|
|
|
|
|
- "Attributes",
|
|
|
|
|
- "ImportAttributes",
|
|
|
|
|
- "ImportName",
|
|
|
|
|
- "ImportModule"
|
|
|
|
|
- );
|
|
|
|
|
-
|
|
|
|
|
- foreach (var handle in _reader.MethodDefinitions)
|
|
|
|
|
- {
|
|
|
|
|
- var entry = _reader.GetMethodDefinition(handle);
|
|
|
|
|
- var import = entry.GetImport();
|
|
|
|
|
-
|
|
|
|
|
- AddRow(
|
|
|
|
|
- Literal(entry.Name),
|
|
|
|
|
- Literal(entry.Signature, BlobKind.MethodSignature),
|
|
|
|
|
- Hex(entry.RelativeVirtualAddress),
|
|
|
|
|
- TokenRange(entry.GetParameters(), h => h),
|
|
|
|
|
- TokenRange(entry.GetGenericParameters(), h => h),
|
|
|
|
|
- EnumValue<int>(entry.Attributes), // TODO: we need better visualizer than the default enum
|
|
|
|
|
- EnumValue<int>(entry.ImplAttributes),
|
|
|
|
|
- EnumValue<short>(import.Attributes),
|
|
|
|
|
- Literal(import.Name),
|
|
|
|
|
- Token(() => import.Module)
|
|
|
|
|
- );
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- WriteRows("Method (0x06, 0x1C):");
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- private void WriteParam()
|
|
|
|
|
- {
|
|
|
|
|
- AddHeader(
|
|
|
|
|
- "Name",
|
|
|
|
|
- "Seq#",
|
|
|
|
|
- "Attributes",
|
|
|
|
|
- "Marshalling"
|
|
|
|
|
- );
|
|
|
|
|
-
|
|
|
|
|
- for (int i = 1, count = _reader.GetTableRowCount(TableIndex.Param); i <= count; i++)
|
|
|
|
|
- {
|
|
|
|
|
- var entry = _reader.GetParameter(MetadataTokens.ParameterHandle(i));
|
|
|
|
|
-
|
|
|
|
|
- AddRow(
|
|
|
|
|
- Literal(entry.Name),
|
|
|
|
|
- entry.SequenceNumber.ToString(),
|
|
|
|
|
- EnumValue<int>(entry.Attributes),
|
|
|
|
|
- Literal(entry.GetMarshallingDescriptor(), BlobKind.Marshalling)
|
|
|
|
|
- );
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- WriteRows("Param (0x08):");
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- private void WriteMemberRef()
|
|
|
|
|
- {
|
|
|
|
|
- AddHeader(
|
|
|
|
|
- "Parent",
|
|
|
|
|
- "Name",
|
|
|
|
|
- "Signature"
|
|
|
|
|
- );
|
|
|
|
|
-
|
|
|
|
|
- foreach (var handle in _reader.MemberReferences)
|
|
|
|
|
- {
|
|
|
|
|
- var entry = _reader.GetMemberReference(handle);
|
|
|
|
|
-
|
|
|
|
|
- AddRow(
|
|
|
|
|
- Token(() => entry.Parent),
|
|
|
|
|
- Literal(entry.Name),
|
|
|
|
|
- Literal(entry.Signature, BlobKind.MemberRefSignature)
|
|
|
|
|
- );
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- WriteRows("MemberRef (0x0a):");
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- private void WriteConstant()
|
|
|
|
|
- {
|
|
|
|
|
- AddHeader(
|
|
|
|
|
- "Parent",
|
|
|
|
|
- "Type",
|
|
|
|
|
- "Value"
|
|
|
|
|
- );
|
|
|
|
|
-
|
|
|
|
|
- for (int i = 1, count = _reader.GetTableRowCount(TableIndex.Constant); i <= count; i++)
|
|
|
|
|
- {
|
|
|
|
|
- var entry = _reader.GetConstant(MetadataTokens.ConstantHandle(i));
|
|
|
|
|
-
|
|
|
|
|
- AddRow(
|
|
|
|
|
- Token(() => entry.Parent),
|
|
|
|
|
- EnumValue<byte>(entry.TypeCode),
|
|
|
|
|
- Literal(entry.Value, BlobKind.ConstantValue)
|
|
|
|
|
- );
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- WriteRows("Constant (0x0b):");
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- private void WriteCustomAttribute()
|
|
|
|
|
- {
|
|
|
|
|
- AddHeader(
|
|
|
|
|
- "Parent",
|
|
|
|
|
- "Constructor",
|
|
|
|
|
- "Value"
|
|
|
|
|
- );
|
|
|
|
|
-
|
|
|
|
|
- foreach (var handle in _reader.CustomAttributes)
|
|
|
|
|
- {
|
|
|
|
|
- var entry = _reader.GetCustomAttribute(handle);
|
|
|
|
|
-
|
|
|
|
|
- AddRow(
|
|
|
|
|
- Token(() => entry.Parent),
|
|
|
|
|
- Token(() => entry.Constructor),
|
|
|
|
|
- Literal(entry.Value, BlobKind.CustomAttribute)
|
|
|
|
|
- );
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- WriteRows("CustomAttribute (0x0c):");
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- private void WriteDeclSecurity()
|
|
|
|
|
- {
|
|
|
|
|
- AddHeader(
|
|
|
|
|
- "Parent",
|
|
|
|
|
- "PermissionSet",
|
|
|
|
|
- "Action"
|
|
|
|
|
- );
|
|
|
|
|
-
|
|
|
|
|
- foreach (var handle in _reader.DeclarativeSecurityAttributes)
|
|
|
|
|
- {
|
|
|
|
|
- var entry = _reader.GetDeclarativeSecurityAttribute(handle);
|
|
|
|
|
-
|
|
|
|
|
- AddRow(
|
|
|
|
|
- Token(() => entry.Parent),
|
|
|
|
|
- Literal(entry.PermissionSet, BlobKind.PermissionSet),
|
|
|
|
|
- EnumValue<short>(entry.Action)
|
|
|
|
|
- );
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- WriteRows("DeclSecurity (0x0e):");
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- private void WriteStandAloneSig()
|
|
|
|
|
- {
|
|
|
|
|
- AddHeader("Signature");
|
|
|
|
|
-
|
|
|
|
|
- for (int i = 1, count = _reader.GetTableRowCount(TableIndex.StandAloneSig); i <= count; i++)
|
|
|
|
|
- {
|
|
|
|
|
- var value = _reader.GetStandaloneSignature(MetadataTokens.StandaloneSignatureHandle(i)).Signature;
|
|
|
|
|
-
|
|
|
|
|
- AddRow(Literal(value, BlobKind.StandAloneSignature));
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- WriteRows("StandAloneSig (0x11):");
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- private void WriteEvent()
|
|
|
|
|
- {
|
|
|
|
|
- AddHeader(
|
|
|
|
|
- "Name",
|
|
|
|
|
- "Add",
|
|
|
|
|
- "Remove",
|
|
|
|
|
- "Fire",
|
|
|
|
|
- "Attributes"
|
|
|
|
|
- );
|
|
|
|
|
-
|
|
|
|
|
- foreach (var handle in _reader.EventDefinitions)
|
|
|
|
|
- {
|
|
|
|
|
- var entry = _reader.GetEventDefinition(handle);
|
|
|
|
|
- var accessors = entry.GetAccessors();
|
|
|
|
|
-
|
|
|
|
|
- AddRow(
|
|
|
|
|
- Literal(entry.Name),
|
|
|
|
|
- Token(() => accessors.Adder),
|
|
|
|
|
- Token(() => accessors.Remover),
|
|
|
|
|
- Token(() => accessors.Raiser),
|
|
|
|
|
- EnumValue<int>(entry.Attributes)
|
|
|
|
|
- );
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- WriteRows("Event (0x12, 0x14, 0x18):");
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- private void WriteProperty()
|
|
|
|
|
- {
|
|
|
|
|
- AddHeader(
|
|
|
|
|
- "Name",
|
|
|
|
|
- "Get",
|
|
|
|
|
- "Set",
|
|
|
|
|
- "Attributes"
|
|
|
|
|
- );
|
|
|
|
|
-
|
|
|
|
|
- foreach (var handle in _reader.PropertyDefinitions)
|
|
|
|
|
- {
|
|
|
|
|
- var entry = _reader.GetPropertyDefinition(handle);
|
|
|
|
|
- var accessors = entry.GetAccessors();
|
|
|
|
|
-
|
|
|
|
|
- AddRow(
|
|
|
|
|
- Literal(entry.Name),
|
|
|
|
|
- Token(() => accessors.Getter),
|
|
|
|
|
- Token(() => accessors.Setter),
|
|
|
|
|
- EnumValue<int>(entry.Attributes)
|
|
|
|
|
- );
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- WriteRows("Property (0x15, 0x17, 0x18):");
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- private void WriteMethodImpl()
|
|
|
|
|
- {
|
|
|
|
|
- AddHeader(
|
|
|
|
|
- "Type",
|
|
|
|
|
- "Body",
|
|
|
|
|
- "Declaration"
|
|
|
|
|
- );
|
|
|
|
|
-
|
|
|
|
|
- for (int i = 1, count = _reader.GetTableRowCount(TableIndex.MethodImpl); i <= count; i++)
|
|
|
|
|
- {
|
|
|
|
|
- var entry = _reader.GetMethodImplementation(MetadataTokens.MethodImplementationHandle(i));
|
|
|
|
|
-
|
|
|
|
|
- AddRow(
|
|
|
|
|
- Token(() => entry.Type),
|
|
|
|
|
- Token(() => entry.MethodBody),
|
|
|
|
|
- Token(() => entry.MethodDeclaration)
|
|
|
|
|
- );
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- WriteRows("MethodImpl (0x19):");
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- private void WriteModuleRef()
|
|
|
|
|
- {
|
|
|
|
|
- AddHeader("Name");
|
|
|
|
|
-
|
|
|
|
|
- for (int i = 1, count = _reader.GetTableRowCount(TableIndex.ModuleRef); i <= count; i++)
|
|
|
|
|
- {
|
|
|
|
|
- var value = _reader.GetModuleReference(MetadataTokens.ModuleReferenceHandle(i)).Name;
|
|
|
|
|
- AddRow(Literal(value));
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- WriteRows("ModuleRef (0x1a):");
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- private void WriteTypeSpec()
|
|
|
|
|
- {
|
|
|
|
|
- AddHeader("Name");
|
|
|
|
|
-
|
|
|
|
|
- for (int i = 1, count = _reader.GetTableRowCount(TableIndex.TypeSpec); i <= count; i++)
|
|
|
|
|
- {
|
|
|
|
|
- var value = _reader.GetTypeSpecification(MetadataTokens.TypeSpecificationHandle(i)).Signature;
|
|
|
|
|
- AddRow(Literal(value, BlobKind.TypeSpec));
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- WriteRows("TypeSpec (0x1b):");
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- private void WriteEnCLog()
|
|
|
|
|
- {
|
|
|
|
|
- AddHeader(
|
|
|
|
|
- "Entity",
|
|
|
|
|
- "Operation");
|
|
|
|
|
-
|
|
|
|
|
- foreach (var entry in _reader.GetEditAndContinueLogEntries())
|
|
|
|
|
- {
|
|
|
|
|
- AddRow(
|
|
|
|
|
- Token(() => entry.Handle),
|
|
|
|
|
- EnumValue<int>(entry.Operation));
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- WriteRows("EnC Log (0x1e):");
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- private void WriteEnCMap()
|
|
|
|
|
- {
|
|
|
|
|
- if (_aggregator != null)
|
|
|
|
|
- {
|
|
|
|
|
- AddHeader("Entity", "Gen", "Row", "Edit");
|
|
|
|
|
- }
|
|
|
|
|
- else
|
|
|
|
|
- {
|
|
|
|
|
- AddHeader("Entity");
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
- foreach (var entry in _reader.GetEditAndContinueMapEntries())
|
|
|
|
|
- {
|
|
|
|
|
- if (_aggregator != null)
|
|
|
|
|
- {
|
|
|
|
|
- int generation;
|
|
|
|
|
- EntityHandle primary = (EntityHandle)_aggregator.GetGenerationHandle(entry, out generation);
|
|
|
|
|
- bool isUpdate = _readers[generation] != _reader;
|
|
|
|
|
-
|
|
|
|
|
- var primaryModule = _readers[generation].GetModuleDefinition();
|
|
|
|
|
-
|
|
|
|
|
- AddRow(
|
|
|
|
|
- Token(() => entry),
|
|
|
|
|
- primaryModule.Generation.ToString(),
|
|
|
|
|
- "0x" + MetadataTokens.GetRowNumber(primary).ToString("x6"),
|
|
|
|
|
- isUpdate ? "update" : "add");
|
|
|
|
|
- }
|
|
|
|
|
- else
|
|
|
|
|
- {
|
|
|
|
|
- AddRow(Token(() => entry));
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- WriteRows("EnC Map (0x1f):");
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- private void WriteAssembly()
|
|
|
|
|
- {
|
|
|
|
|
- if (!_reader.IsAssembly)
|
|
|
|
|
- {
|
|
|
|
|
- return;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- AddHeader(
|
|
|
|
|
- "Name",
|
|
|
|
|
- "Version",
|
|
|
|
|
- "Culture",
|
|
|
|
|
- "PublicKey",
|
|
|
|
|
- "Flags",
|
|
|
|
|
- "HashAlgorithm"
|
|
|
|
|
- );
|
|
|
|
|
-
|
|
|
|
|
- var entry = _reader.GetAssemblyDefinition();
|
|
|
|
|
-
|
|
|
|
|
- AddRow(
|
|
|
|
|
- Literal(entry.Name),
|
|
|
|
|
- entry.Version.Major + "." + entry.Version.Minor + "." + entry.Version.Revision + "." + entry.Version.Build,
|
|
|
|
|
- Literal(entry.Culture),
|
|
|
|
|
- Literal(entry.PublicKey, BlobKind.Key),
|
|
|
|
|
- EnumValue<int>(entry.Flags),
|
|
|
|
|
- EnumValue<int>(entry.HashAlgorithm)
|
|
|
|
|
- );
|
|
|
|
|
-
|
|
|
|
|
- WriteRows("Assembly (0x20):");
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- private void WriteAssemblyRef()
|
|
|
|
|
- {
|
|
|
|
|
- AddHeader(
|
|
|
|
|
- "Name",
|
|
|
|
|
- "Version",
|
|
|
|
|
- "Culture",
|
|
|
|
|
- "PublicKeyOrToken",
|
|
|
|
|
- "Flags"
|
|
|
|
|
- );
|
|
|
|
|
-
|
|
|
|
|
- foreach (var handle in _reader.AssemblyReferences)
|
|
|
|
|
- {
|
|
|
|
|
- var entry = _reader.GetAssemblyReference(handle);
|
|
|
|
|
-
|
|
|
|
|
- AddRow(
|
|
|
|
|
- Literal(entry.Name),
|
|
|
|
|
- entry.Version.Major + "." + entry.Version.Minor + "." + entry.Version.Revision + "." + entry.Version.Build,
|
|
|
|
|
- Literal(entry.Culture),
|
|
|
|
|
- Literal(entry.PublicKeyOrToken, BlobKind.Key),
|
|
|
|
|
- EnumValue<int>(entry.Flags)
|
|
|
|
|
- );
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- WriteRows("AssemblyRef (0x23):");
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- private void WriteFile()
|
|
|
|
|
- {
|
|
|
|
|
- AddHeader(
|
|
|
|
|
- "Name",
|
|
|
|
|
- "Metadata",
|
|
|
|
|
- "HashValue"
|
|
|
|
|
- );
|
|
|
|
|
-
|
|
|
|
|
- foreach (var handle in _reader.AssemblyFiles)
|
|
|
|
|
- {
|
|
|
|
|
- var entry = _reader.GetAssemblyFile(handle);
|
|
|
|
|
-
|
|
|
|
|
- AddRow(
|
|
|
|
|
- Literal(entry.Name),
|
|
|
|
|
- entry.ContainsMetadata ? "Yes" : "No",
|
|
|
|
|
- Literal(entry.HashValue, BlobKind.FileHash)
|
|
|
|
|
- );
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- WriteRows("File (0x26):");
|
|
|
|
|
- }
|
|
|
|
|
- private void WriteExportedType()
|
|
|
|
|
- {
|
|
|
|
|
- AddHeader(
|
|
|
|
|
- "Name",
|
|
|
|
|
- "Namespace",
|
|
|
|
|
- "Attributes",
|
|
|
|
|
- "Implementation",
|
|
|
|
|
- "TypeDefinitionId"
|
|
|
|
|
- );
|
|
|
|
|
-
|
|
|
|
|
- foreach (var handle in _reader.ExportedTypes)
|
|
|
|
|
- {
|
|
|
|
|
- var entry = _reader.GetExportedType(handle);
|
|
|
|
|
- AddRow(
|
|
|
|
|
- Literal(entry.Name),
|
|
|
|
|
- Literal(entry.Namespace),
|
|
|
|
|
- entry.Attributes.ToString(),
|
|
|
|
|
- Token(() => entry.Implementation),
|
|
|
|
|
- Hex(entry.GetTypeDefinitionId())
|
|
|
|
|
- );
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- WriteRows("ExportedType (0x27):");
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- private void WriteManifestResource()
|
|
|
|
|
- {
|
|
|
|
|
- AddHeader(
|
|
|
|
|
- "Name",
|
|
|
|
|
- "Attributes",
|
|
|
|
|
- "Offset",
|
|
|
|
|
- "Implementation"
|
|
|
|
|
- );
|
|
|
|
|
-
|
|
|
|
|
- foreach (var handle in _reader.ManifestResources)
|
|
|
|
|
- {
|
|
|
|
|
- var entry = _reader.GetManifestResource(handle);
|
|
|
|
|
-
|
|
|
|
|
- AddRow(
|
|
|
|
|
- Literal(entry.Name),
|
|
|
|
|
- entry.Attributes.ToString(),
|
|
|
|
|
- entry.Offset.ToString(),
|
|
|
|
|
- Token(() => entry.Implementation)
|
|
|
|
|
- );
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- WriteRows("ManifestResource (0x28):");
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- private void WriteGenericParam()
|
|
|
|
|
- {
|
|
|
|
|
- AddHeader(
|
|
|
|
|
- "Name",
|
|
|
|
|
- "Seq#",
|
|
|
|
|
- "Attributes",
|
|
|
|
|
- "Parent",
|
|
|
|
|
- "TypeConstraints"
|
|
|
|
|
- );
|
|
|
|
|
-
|
|
|
|
|
- for (int i = 1, count = _reader.GetTableRowCount(TableIndex.GenericParam); i <= count; i++)
|
|
|
|
|
- {
|
|
|
|
|
- var entry = _reader.GetGenericParameter(MetadataTokens.GenericParameterHandle(i));
|
|
|
|
|
-
|
|
|
|
|
- AddRow(
|
|
|
|
|
- Literal(entry.Name),
|
|
|
|
|
- entry.Index.ToString(),
|
|
|
|
|
- EnumValue<int>(entry.Attributes),
|
|
|
|
|
- Token(() => entry.Parent),
|
|
|
|
|
- TokenRange(entry.GetConstraints(), h => h)
|
|
|
|
|
- );
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- WriteRows("GenericParam (0x2a):");
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- private void WriteMethodSpec()
|
|
|
|
|
- {
|
|
|
|
|
- AddHeader(
|
|
|
|
|
- "Method",
|
|
|
|
|
- "Signature"
|
|
|
|
|
- );
|
|
|
|
|
-
|
|
|
|
|
- for (int i = 1, count = _reader.GetTableRowCount(TableIndex.MethodSpec); i <= count; i++)
|
|
|
|
|
- {
|
|
|
|
|
- var entry = _reader.GetMethodSpecification(MetadataTokens.MethodSpecificationHandle(i));
|
|
|
|
|
-
|
|
|
|
|
- AddRow(
|
|
|
|
|
- Token(() => entry.Method),
|
|
|
|
|
- Literal(entry.Signature, BlobKind.MethodSpec)
|
|
|
|
|
- );
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- WriteRows("MethodSpec (0x2b):");
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- private void WriteGenericParamConstraint()
|
|
|
|
|
- {
|
|
|
|
|
- AddHeader(
|
|
|
|
|
- "Parent",
|
|
|
|
|
- "Type"
|
|
|
|
|
- );
|
|
|
|
|
-
|
|
|
|
|
- for (int i = 1, count = _reader.GetTableRowCount(TableIndex.GenericParamConstraint); i <= count; i++)
|
|
|
|
|
- {
|
|
|
|
|
- var entry = _reader.GetGenericParameterConstraint(MetadataTokens.GenericParameterConstraintHandle(i));
|
|
|
|
|
-
|
|
|
|
|
- AddRow(
|
|
|
|
|
- Token(() => entry.Parameter),
|
|
|
|
|
- Token(() => entry.Type)
|
|
|
|
|
- );
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- WriteRows("GenericParamConstraint (0x2c):");
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- private void WriteUserStrings()
|
|
|
|
|
- {
|
|
|
|
|
- int size = _reader.GetHeapSize(HeapIndex.UserString);
|
|
|
|
|
- if (size == 0)
|
|
|
|
|
- {
|
|
|
|
|
- return;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // TODO: the heap is aligned, don't display the trailing empty strings
|
|
|
|
|
- _writer.WriteLine($"#US (size = {size}):");
|
|
|
|
|
- var handle = MetadataTokens.UserStringHandle(0);
|
|
|
|
|
- do
|
|
|
|
|
- {
|
|
|
|
|
- string value = StringUtilities.EscapeNonPrintableCharacters(_reader.GetUserString(handle));
|
|
|
|
|
- _writer.WriteLine($" {_reader.GetHeapOffset(handle):x}: '{value}'");
|
|
|
|
|
- handle = _reader.GetNextHandle(handle);
|
|
|
|
|
- }
|
|
|
|
|
- while (!handle.IsNil);
|
|
|
|
|
-
|
|
|
|
|
- _writer.WriteLine();
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- private void WriteStrings()
|
|
|
|
|
- {
|
|
|
|
|
- int size = _reader.GetHeapSize(HeapIndex.String);
|
|
|
|
|
- if (size == 0)
|
|
|
|
|
- {
|
|
|
|
|
- return;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- _writer.WriteLine($"#String (size = {size}):");
|
|
|
|
|
- var handle = MetadataTokens.StringHandle(0);
|
|
|
|
|
- do
|
|
|
|
|
- {
|
|
|
|
|
- string value = StringUtilities.EscapeNonPrintableCharacters(_reader.GetString(handle));
|
|
|
|
|
- _writer.WriteLine($" {_reader.GetHeapOffset(handle):x}: '{value}'");
|
|
|
|
|
- handle = _reader.GetNextHandle(handle);
|
|
|
|
|
- }
|
|
|
|
|
- while (!handle.IsNil);
|
|
|
|
|
-
|
|
|
|
|
- _writer.WriteLine();
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- private void WriteBlobs()
|
|
|
|
|
- {
|
|
|
|
|
- int size = _reader.GetHeapSize(HeapIndex.Blob);
|
|
|
|
|
- if (size == 0)
|
|
|
|
|
- {
|
|
|
|
|
- return;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- int[] sizePerKind = new int[(int)BlobKind.Count];
|
|
|
|
|
-
|
|
|
|
|
- _writer.WriteLine($"#Blob (size = {size}):");
|
|
|
|
|
- var handle = MetadataTokens.BlobHandle(0);
|
|
|
|
|
- do
|
|
|
|
|
- {
|
|
|
|
|
- byte[] value = _reader.GetBlobBytes(handle);
|
|
|
|
|
-
|
|
|
|
|
- BlobKind kind;
|
|
|
|
|
- string kindString;
|
|
|
|
|
- if (_blobKinds.TryGetValue(handle, out kind))
|
|
|
|
|
- {
|
|
|
|
|
- kindString = " (" + kind + ")";
|
|
|
|
|
-
|
|
|
|
|
- // ignoring the compressed blob size:
|
|
|
|
|
- sizePerKind[(int)kind] += value.Length;
|
|
|
|
|
- }
|
|
|
|
|
- else
|
|
|
|
|
- {
|
|
|
|
|
- kindString = "";
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- int displayLength = (_options & MetadataVisualizerOptions.ShortenBlobs) != 0 ? Math.Min(4, value.Length) : value.Length;
|
|
|
|
|
- string valueString = BitConverter.ToString(value, 0, displayLength) + (displayLength < value.Length ? "-..." : null);
|
|
|
|
|
-
|
|
|
|
|
- _writer.WriteLine($" {_reader.GetHeapOffset(handle):x}{kindString}: {valueString}");
|
|
|
|
|
- handle = _reader.GetNextHandle(handle);
|
|
|
|
|
- }
|
|
|
|
|
- while (!handle.IsNil);
|
|
|
|
|
-
|
|
|
|
|
- _writer.WriteLine();
|
|
|
|
|
- _writer.WriteLine("Sizes:");
|
|
|
|
|
-
|
|
|
|
|
- for (int i = 0; i < sizePerKind.Length; i++)
|
|
|
|
|
- {
|
|
|
|
|
- if (sizePerKind[i] > 0)
|
|
|
|
|
- {
|
|
|
|
|
- _writer.WriteLine($" {(BlobKind)i}: {(decimal)sizePerKind[i]} bytes");
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // don't calculate statistics for EnC delta, it's not interesting
|
|
|
|
|
- if (_aggregator == null)
|
|
|
|
|
- {
|
|
|
|
|
- _writer.WriteLine();
|
|
|
|
|
- _writer.WriteLine("CustomAttribute sizes by constructor:");
|
|
|
|
|
- try
|
|
|
|
|
- {
|
|
|
|
|
- foreach (var grouping in from caHandle in _reader.CustomAttributes
|
|
|
|
|
- let ca = _reader.GetCustomAttribute(caHandle)
|
|
|
|
|
- group ca.Constructor by ca.Value into values // blob -> { ctor1, ctor2, ... }
|
|
|
|
|
- group values.Key by values.First() into g // ctor1 -> { blob1, ... }
|
|
|
|
|
- select new { Ctor = g.Key, Size = g.Sum(ca => _reader.GetBlobReader(ca).Length) } into ctorAndSize
|
|
|
|
|
- orderby ctorAndSize.Size descending
|
|
|
|
|
- select ctorAndSize)
|
|
|
|
|
- {
|
|
|
|
|
- string typeStr = null;
|
|
|
|
|
- switch (grouping.Ctor.Kind)
|
|
|
|
|
- {
|
|
|
|
|
- case HandleKind.MemberReference:
|
|
|
|
|
- var memberRef = _reader.GetMemberReference((MemberReferenceHandle)grouping.Ctor);
|
|
|
|
|
-
|
|
|
|
|
- switch (memberRef.Parent.Kind)
|
|
|
|
|
- {
|
|
|
|
|
- case HandleKind.TypeReference:
|
|
|
|
|
- var typeRef = _reader.GetTypeReference((TypeReferenceHandle)memberRef.Parent);
|
|
|
|
|
- typeStr = typeRef.Namespace.IsNil ? _reader.GetString(typeRef.Name) : _reader.GetString(typeRef.Namespace) + "." + _reader.GetString(typeRef.Name);
|
|
|
|
|
- break;
|
|
|
|
|
-
|
|
|
|
|
- case HandleKind.TypeDefinition:
|
|
|
|
|
- var typeDef = _reader.GetTypeDefinition((TypeDefinitionHandle)memberRef.Parent);
|
|
|
|
|
- typeStr = typeDef.Namespace.IsNil ? _reader.GetString(typeDef.Name) : _reader.GetString(typeDef.Namespace) + "." + _reader.GetString(typeDef.Name);
|
|
|
|
|
- break;
|
|
|
|
|
-
|
|
|
|
|
- case HandleKind.MethodDefinition:
|
|
|
|
|
- case HandleKind.ModuleReference:
|
|
|
|
|
- case HandleKind.TypeSpecification:
|
|
|
|
|
- break;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- break;
|
|
|
|
|
-
|
|
|
|
|
- case HandleKind.MethodDefinition:
|
|
|
|
|
- // TODO
|
|
|
|
|
- break;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
- // grouping.Key
|
|
|
|
|
- _writer.WriteLine($" {typeStr ?? Token(() => grouping.Ctor)}: {grouping.Size} bytes");
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- catch (BadImageFormatException)
|
|
|
|
|
- {
|
|
|
|
|
- _writer.WriteLine("<bad metadata>");
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- _writer.WriteLine();
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- private void WriteGuids()
|
|
|
|
|
- {
|
|
|
|
|
- int size = _reader.GetHeapSize(HeapIndex.Guid);
|
|
|
|
|
- if (size == 0)
|
|
|
|
|
- {
|
|
|
|
|
- return;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- _writer.WriteLine(string.Format("#Guid (size = {0}):", size));
|
|
|
|
|
- int i = 1;
|
|
|
|
|
- while (i <= size / 16)
|
|
|
|
|
- {
|
|
|
|
|
- string value = _reader.GetGuid(MetadataTokens.GuidHandle(i)).ToString();
|
|
|
|
|
- _writer.WriteLine(" {0:x}: {{{1}}}", i, value);
|
|
|
|
|
- i++;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- _writer.WriteLine();
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- private void WriteDocument()
|
|
|
|
|
- {
|
|
|
|
|
- AddHeader(
|
|
|
|
|
- "Name",
|
|
|
|
|
- "Language",
|
|
|
|
|
- "HashAlgorithm",
|
|
|
|
|
- "Hash"
|
|
|
|
|
- );
|
|
|
|
|
-
|
|
|
|
|
- foreach (var handle in _reader.Documents)
|
|
|
|
|
- {
|
|
|
|
|
- var entry = _reader.GetDocument(handle);
|
|
|
|
|
-
|
|
|
|
|
- AddRow(
|
|
|
|
|
- Literal(entry.Name),
|
|
|
|
|
- Language(entry.Language),
|
|
|
|
|
- HashAlgorithm(entry.HashAlgorithm),
|
|
|
|
|
- Literal(entry.Hash, BlobKind.DocumentHash)
|
|
|
|
|
- );
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- WriteTableName(TableIndex.Document);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- private void WriteMethodBody()
|
|
|
|
|
- {
|
|
|
|
|
- if (_reader.MethodBodies.Count == 0)
|
|
|
|
|
- {
|
|
|
|
|
- return;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- _writer.WriteLine(MakeTableName(TableIndex.MethodBody));
|
|
|
|
|
- _writer.WriteLine(new string('=', 50));
|
|
|
|
|
-
|
|
|
|
|
- foreach (var handle in _reader.MethodBodies)
|
|
|
|
|
- {
|
|
|
|
|
- if (handle.IsNil)
|
|
|
|
|
- {
|
|
|
|
|
- continue;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- var entry = _reader.GetMethodBody(handle);
|
|
|
|
|
-
|
|
|
|
|
- _writer.WriteLine($"{MetadataTokens.GetRowNumber(handle)}: #{_reader.GetHeapOffset(entry.SequencePoints)}");
|
|
|
|
|
-
|
|
|
|
|
- if (entry.SequencePoints.IsNil)
|
|
|
|
|
- {
|
|
|
|
|
- continue;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- _blobKinds[entry.SequencePoints] = BlobKind.SequencePoints;
|
|
|
|
|
-
|
|
|
|
|
- _writer.WriteLine("{");
|
|
|
|
|
-
|
|
|
|
|
- bool addLineBreak = false;
|
|
|
|
|
-
|
|
|
|
|
- var kickoffMethod = entry.GetStateMachineKickoffMethod();
|
|
|
|
|
- if (!kickoffMethod.IsNil)
|
|
|
|
|
- {
|
|
|
|
|
- _writer.WriteLine($" Kickoff Method: {Token(() => kickoffMethod)}");
|
|
|
|
|
- addLineBreak = true;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- if (!entry.LocalSignature.IsNil)
|
|
|
|
|
- {
|
|
|
|
|
- _writer.WriteLine($" Locals: {Token(() => entry.LocalSignature)}");
|
|
|
|
|
- addLineBreak = true;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- if (addLineBreak)
|
|
|
|
|
- {
|
|
|
|
|
- _writer.WriteLine();
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- try
|
|
|
|
|
- {
|
|
|
|
|
- var spReader = _reader.GetSequencePointsReader(entry.SequencePoints);
|
|
|
|
|
- while (spReader.MoveNext())
|
|
|
|
|
- {
|
|
|
|
|
- _writer.Write(" ");
|
|
|
|
|
- _writer.WriteLine(SequencePoint(spReader.Current));
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- catch (BadImageFormatException)
|
|
|
|
|
- {
|
|
|
|
|
- _writer.WriteLine("<bad metadata>");
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- _writer.WriteLine("}");
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- _writer.WriteLine();
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- private void WriteLocalScope()
|
|
|
|
|
- {
|
|
|
|
|
- AddHeader(
|
|
|
|
|
- "Method",
|
|
|
|
|
- "ImportScope",
|
|
|
|
|
- "Variables",
|
|
|
|
|
- "Constants",
|
|
|
|
|
- "StartOffset",
|
|
|
|
|
- "Length"
|
|
|
|
|
- );
|
|
|
|
|
-
|
|
|
|
|
- foreach (var handle in _reader.LocalScopes)
|
|
|
|
|
- {
|
|
|
|
|
- var entry = _reader.GetLocalScope(handle);
|
|
|
|
|
-
|
|
|
|
|
- AddRow(
|
|
|
|
|
- Token(() => entry.Method),
|
|
|
|
|
- Token(() => entry.ImportScope),
|
|
|
|
|
- TokenRange(entry.GetLocalVariables(), h => h),
|
|
|
|
|
- TokenRange(entry.GetLocalConstants(), h => h),
|
|
|
|
|
- entry.StartOffset.ToString("X4"),
|
|
|
|
|
- entry.Length.ToString()
|
|
|
|
|
- );
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- WriteTableName(TableIndex.LocalScope);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- private void WriteLocalVariable()
|
|
|
|
|
- {
|
|
|
|
|
- AddHeader(
|
|
|
|
|
- "Name",
|
|
|
|
|
- "Index",
|
|
|
|
|
- "Attributes"
|
|
|
|
|
- );
|
|
|
|
|
-
|
|
|
|
|
- foreach (var handle in _reader.LocalVariables)
|
|
|
|
|
- {
|
|
|
|
|
- var entry = _reader.GetLocalVariable(handle);
|
|
|
|
|
-
|
|
|
|
|
- AddRow(
|
|
|
|
|
- Literal(entry.Name),
|
|
|
|
|
- entry.Index.ToString(),
|
|
|
|
|
- entry.Attributes.ToString()
|
|
|
|
|
- );
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- WriteTableName(TableIndex.LocalVariable);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- private void WriteLocalConstant()
|
|
|
|
|
- {
|
|
|
|
|
- AddHeader(
|
|
|
|
|
- "Name",
|
|
|
|
|
- "Signature"
|
|
|
|
|
- );
|
|
|
|
|
-
|
|
|
|
|
- foreach (var handle in _reader.LocalConstants)
|
|
|
|
|
- {
|
|
|
|
|
- var entry = _reader.GetLocalConstant(handle);
|
|
|
|
|
-
|
|
|
|
|
- AddRow(
|
|
|
|
|
- Literal(entry.Name),
|
|
|
|
|
- Literal(entry.Signature, BlobKind.LocalConstantSignature, (r, h) => FormatLocalConstant(r, (BlobHandle)h))
|
|
|
|
|
- );
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- WriteTableName(TableIndex.LocalConstant);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
-/*
|
|
|
|
|
- private SignatureTypeCode ReadConstantTypeCode(ref BlobReader sigReader, List<CustomModifier<Handle>> modifiers)
|
|
|
|
|
- {
|
|
|
|
|
- while (true)
|
|
|
|
|
- {
|
|
|
|
|
- var s = sigReader.ReadSignatureTypeCode();
|
|
|
|
|
- if (s == SignatureTypeCode.OptionalModifier || s == SignatureTypeCode.RequiredModifier)
|
|
|
|
|
- {
|
|
|
|
|
- var type = sigReader.ReadTypeHandle();
|
|
|
|
|
- modifiers.Add(new CustomModifier<Handle>(type, isRequired: s == SignatureTypeCode.RequiredModifier));
|
|
|
|
|
- }
|
|
|
|
|
- else
|
|
|
|
|
- {
|
|
|
|
|
- return s;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- private string FormatLocalConstant(MetadataReader reader, BlobHandle signature)
|
|
|
|
|
- {
|
|
|
|
|
- var sigReader = reader.GetBlobReader(signature);
|
|
|
|
|
-
|
|
|
|
|
- var modifiers = new List<CustomModifier<Handle>>();
|
|
|
|
|
-
|
|
|
|
|
- SignatureTypeCode typeCode = ReadConstantTypeCode(ref sigReader, modifiers);
|
|
|
|
|
-
|
|
|
|
|
- Handle typeHandle = default(Handle);
|
|
|
|
|
- object value;
|
|
|
|
|
- if (IsPrimitiveType(typeCode))
|
|
|
|
|
- {
|
|
|
|
|
- if (typeCode == SignatureTypeCode.String)
|
|
|
|
|
- {
|
|
|
|
|
- if (sigReader.RemainingBytes == 1)
|
|
|
|
|
- {
|
|
|
|
|
- value = (sigReader.ReadByte() == 0xff) ? "null" : "<bad metadata>";
|
|
|
|
|
- }
|
|
|
|
|
- else if (sigReader.RemainingBytes % 2 != 0)
|
|
|
|
|
- {
|
|
|
|
|
- value = "<bad metadata>";
|
|
|
|
|
- }
|
|
|
|
|
- else
|
|
|
|
|
- {
|
|
|
|
|
- value = "'" + sigReader.ReadUTF16(sigReader.RemainingBytes) + "'";
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- else
|
|
|
|
|
- {
|
|
|
|
|
- value = string.Format(CultureInfo.InvariantCulture, "{0}", sigReader.ReadConstant((ConstantTypeCode)typeCode));
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- if (sigReader.RemainingBytes > 0)
|
|
|
|
|
- {
|
|
|
|
|
- typeHandle = sigReader.ReadTypeHandle();
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- else if (typeCode == SignatureTypeCode.TypeHandle)
|
|
|
|
|
- {
|
|
|
|
|
- typeHandle = sigReader.ReadTypeHandle();
|
|
|
|
|
- value = (sigReader.RemainingBytes > 0) ? BitConverter.ToString(sigReader.ReadBytes(sigReader.RemainingBytes)) : "default";
|
|
|
|
|
- }
|
|
|
|
|
- else
|
|
|
|
|
- {
|
|
|
|
|
- value = (typeCode == SignatureTypeCode.Object) ? "null" : $"<bad type code: {typeCode}>";
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- return string.Format("{0} [{1}{2}]",
|
|
|
|
|
- value,
|
|
|
|
|
- FormatCustomModifiers(modifiers),
|
|
|
|
|
- typeHandle.IsNil ? typeCode.ToString() : Token(() => typeHandle));
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- private string FormatCustomModifiers(IEnumerable<CustomModifier<Handle>> modifiers)
|
|
|
|
|
- {
|
|
|
|
|
- return string.Join(" ", modifiers.Select(m => (m.IsRequired ? "modreq" : "modopt") + "(" + Token(() => m.Type) + ")"));
|
|
|
|
|
- }
|
|
|
|
|
-*/
|
|
|
|
|
- private static bool IsPrimitiveType(SignatureTypeCode typeCode)
|
|
|
|
|
- {
|
|
|
|
|
- switch (typeCode)
|
|
|
|
|
- {
|
|
|
|
|
- case SignatureTypeCode.Boolean:
|
|
|
|
|
- case SignatureTypeCode.Char:
|
|
|
|
|
- case SignatureTypeCode.SByte:
|
|
|
|
|
- case SignatureTypeCode.Byte:
|
|
|
|
|
- case SignatureTypeCode.Int16:
|
|
|
|
|
- case SignatureTypeCode.UInt16:
|
|
|
|
|
- case SignatureTypeCode.Int32:
|
|
|
|
|
- case SignatureTypeCode.UInt32:
|
|
|
|
|
- case SignatureTypeCode.Int64:
|
|
|
|
|
- case SignatureTypeCode.UInt64:
|
|
|
|
|
- case SignatureTypeCode.Single:
|
|
|
|
|
- case SignatureTypeCode.Double:
|
|
|
|
|
- case SignatureTypeCode.String:
|
|
|
|
|
- return true;
|
|
|
|
|
-
|
|
|
|
|
- default:
|
|
|
|
|
- return false;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- private void WriteLocalImport()
|
|
|
|
|
- {
|
|
|
|
|
- AddHeader(
|
|
|
|
|
- "Parent",
|
|
|
|
|
- "Imports"
|
|
|
|
|
- );
|
|
|
|
|
-
|
|
|
|
|
- foreach (var handle in _reader.ImportScopes)
|
|
|
|
|
- {
|
|
|
|
|
- var entry = _reader.GetImportScope(handle);
|
|
|
|
|
-
|
|
|
|
|
- _blobKinds[entry.Imports] = BlobKind.Imports;
|
|
|
|
|
-
|
|
|
|
|
- AddRow(
|
|
|
|
|
- Token(() => entry.Parent),
|
|
|
|
|
- FormatImports(entry.Imports)
|
|
|
|
|
- );
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- WriteTableName(TableIndex.ImportScope);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- private void WriteCustomDebugInformation()
|
|
|
|
|
- {
|
|
|
|
|
- AddHeader(
|
|
|
|
|
- "Parent",
|
|
|
|
|
- "Value"
|
|
|
|
|
- );
|
|
|
|
|
-
|
|
|
|
|
- foreach (var handle in _reader.CustomDebugInformation)
|
|
|
|
|
- {
|
|
|
|
|
- var entry = _reader.GetCustomDebugInformation(handle);
|
|
|
|
|
-
|
|
|
|
|
- AddRow(
|
|
|
|
|
- Token(() => entry.Parent),
|
|
|
|
|
- Literal(entry.Value, BlobKind.CustomDebugInformation)
|
|
|
|
|
- );
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- WriteTableName(TableIndex.CustomDebugInformation);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- public void VisualizeMethodBody(MethodBodyBlock body, MethodDefinitionHandle generationHandle, int generation)
|
|
|
|
|
- {
|
|
|
|
|
- VisualizeMethodBody(body, (MethodDefinitionHandle)GetAggregateHandle(generationHandle, generation));
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- public void VisualizeMethodBody(MethodBodyBlock body, MethodDefinitionHandle methodHandle, bool emitHeader = true)
|
|
|
|
|
- {
|
|
|
|
|
- StringBuilder builder = new StringBuilder();
|
|
|
|
|
-
|
|
|
|
|
- // TODO: Inspect EncLog to find a containing type and display qualified name.
|
|
|
|
|
- var method = GetMethod(methodHandle);
|
|
|
|
|
- if (emitHeader)
|
|
|
|
|
- {
|
|
|
|
|
- builder.AppendFormat("Method {0} (0x{1:X8})", Literal(method.Name), MetadataTokens.GetToken(methodHandle));
|
|
|
|
|
- builder.AppendLine();
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // TODO: decode signature
|
|
|
|
|
- if (!body.LocalSignature.IsNil)
|
|
|
|
|
- {
|
|
|
|
|
- var localSignature = GetLocalSignature(body.LocalSignature);
|
|
|
|
|
- builder.AppendFormat(" Locals: {0}", Literal(localSignature, BlobKind.StandAloneSignature));
|
|
|
|
|
- builder.AppendLine();
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- ILVisualizerAsTokens.Instance.DumpMethod(
|
|
|
|
|
- builder,
|
|
|
|
|
- body.MaxStack,
|
|
|
|
|
- body.GetILContent(),
|
|
|
|
|
- ImmutableArray.Create<ILVisualizer.LocalInfo>(), // TODO
|
|
|
|
|
- ImmutableArray.Create<ILVisualizer.HandlerSpan>()); // TOOD: ILVisualizer.GetHandlerSpans(body.ExceptionRegions)
|
|
|
|
|
-
|
|
|
|
|
- builder.AppendLine();
|
|
|
|
|
-
|
|
|
|
|
- _writer.Write(builder.ToString());
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- public void WriteLine(string line)
|
|
|
|
|
- {
|
|
|
|
|
- _writer.WriteLine(line);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- private sealed class TokenTypeComparer : IComparer<EntityHandle>
|
|
|
|
|
- {
|
|
|
|
|
- public static readonly TokenTypeComparer Instance = new TokenTypeComparer();
|
|
|
|
|
-
|
|
|
|
|
- public int Compare(EntityHandle x, EntityHandle y)
|
|
|
|
|
- {
|
|
|
|
|
- return x.Kind.CompareTo(y.Kind);
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-#endif
|
|
|