diff --git a/ICSharpCode.Decompiler/DebugInfo/KnownGuids.cs b/ICSharpCode.Decompiler/DebugInfo/KnownGuids.cs new file mode 100644 index 000000000..eb3c4ac9a --- /dev/null +++ b/ICSharpCode.Decompiler/DebugInfo/KnownGuids.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace ICSharpCode.Decompiler.DebugInfo +{ + public static class KnownGuids + { + public static readonly Guid CSharpLanguageGuid = new Guid("3f5162f8-07c6-11d3-9053-00c04fa302a1"); + public static readonly Guid VBLanguageGuid = new Guid("3a12d0b8-c26c-11d0-b442-00a0244a1dd2"); + public static readonly Guid FSharpLanguageGuid = new Guid("ab4f38c9-b6e6-43ba-be3b-58080b2ccce3"); + + public static readonly Guid StateMachineHoistedLocalScopes = new Guid("6DA9A61E-F8C7-4874-BE62-68BC5630DF71"); + public static readonly Guid DynamicLocalVariables = new Guid("83C563C4-B4F3-47D5-B824-BA5441477EA8"); + public static readonly Guid DefaultNamespaces = new Guid("58b2eab6-209f-4e4e-a22c-b2d0f910c782"); + public static readonly Guid EditAndContinueLocalSlotMap = new Guid("755F52A8-91C5-45BE-B4B8-209571E552BD"); + public static readonly Guid EditAndContinueLambdaAndClosureMap = new Guid("A643004C-0240-496F-A783-30D64F4979DE"); + public static readonly Guid EmbeddedSource = new Guid("0e8a571b-6926-466e-b4ad-8ab04611f5fe"); + public static readonly Guid SourceLink = new Guid("CC110556-A091-4D38-9FEC-25AB9A351A6A"); + public static readonly Guid MethodSteppingInformation = new Guid("54FD2AC5-E925-401A-9C2A-F94F171072F8"); + + public static readonly Guid HashAlgorithmSHA1 = new Guid("ff1816ec-aa5e-4d10-87f7-6f4963833460"); + public static readonly Guid HashAlgorithmSHA256 = new Guid("8829d00f-11b8-4213-878b-770e8597ac16"); + } +} diff --git a/ICSharpCode.Decompiler/DebugInfo/PortablePdbWriter.cs b/ICSharpCode.Decompiler/DebugInfo/PortablePdbWriter.cs index d898d8313..a329bcfbf 100644 --- a/ICSharpCode.Decompiler/DebugInfo/PortablePdbWriter.cs +++ b/ICSharpCode.Decompiler/DebugInfo/PortablePdbWriter.cs @@ -41,13 +41,6 @@ namespace ICSharpCode.Decompiler.DebugInfo { public class PortablePdbWriter { - static readonly Guid CSharpLanguageGuid = new Guid("3f5162f8-07c6-11d3-9053-00c04fa302a1"); - - static readonly Guid DebugInfoEmbeddedSource = new Guid("0e8a571b-6926-466e-b4ad-8ab04611f5fe"); - static readonly Guid MethodSteppingInformationBlobId = new Guid("54FD2AC5-E925-401A-9C2A-F94F171072F8"); - - static readonly Guid HashAlgorithmSHA1 = new Guid("ff1816ec-aa5e-4d10-87f7-6f4963833460"); - static readonly Guid HashAlgorithmSHA256 = new Guid("8829d00f-11b8-4213-878b-770e8597ac16"); static readonly FileVersionInfo decompilerVersion = FileVersionInfo.GetVersionInfo(typeof(CSharpDecompiler).Assembly.Location); public static bool HasCodeViewDebugDirectoryEntry(PEFile file) @@ -95,13 +88,13 @@ namespace ICSharpCode.Decompiler.DebugInfo // Create Document(Handle) var document = metadata.AddDocument(name, - hashAlgorithm: metadata.GetOrAddGuid(HashAlgorithmSHA256), + hashAlgorithm: metadata.GetOrAddGuid(KnownGuids.HashAlgorithmSHA256), hash: metadata.GetOrAddBlob(sourceCheckSum), - language: metadata.GetOrAddGuid(CSharpLanguageGuid)); + language: metadata.GetOrAddGuid(KnownGuids.CSharpLanguageGuid)); // Add embedded source to the PDB customDocumentDebugInfo.Add((document, - metadata.GetOrAddGuid(DebugInfoEmbeddedSource), + metadata.GetOrAddGuid(KnownGuids.EmbeddedSource), sourceBlob)); debugInfoGen.GenerateImportScopes(metadata, globalImportScope); @@ -121,7 +114,7 @@ namespace ICSharpCode.Decompiler.DebugInfo } if (function.IsAsync) { customMethodDebugInfo.Add((methodHandle, - metadata.GetOrAddGuid(MethodSteppingInformationBlobId), + metadata.GetOrAddGuid(KnownGuids.MethodSteppingInformation), metadata.GetOrAddBlob(function.AsyncDebugInfo.BuildBlob(methodHandle)))); } } diff --git a/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj b/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj index 6cce8ee34..ec313b5d4 100644 --- a/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj +++ b/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj @@ -63,6 +63,7 @@ + diff --git a/ICSharpCode.Decompiler/Metadata/Dom.cs b/ICSharpCode.Decompiler/Metadata/Dom.cs index 464781a0a..0425b4e5f 100644 --- a/ICSharpCode.Decompiler/Metadata/Dom.cs +++ b/ICSharpCode.Decompiler/Metadata/Dom.cs @@ -213,7 +213,7 @@ namespace ICSharpCode.Decompiler.Metadata public class GenericContext { - readonly PEFile module; + readonly MetadataReader metadata; readonly TypeDefinitionHandle declaringType; readonly MethodDefinitionHandle method; @@ -223,14 +223,27 @@ namespace ICSharpCode.Decompiler.Metadata public GenericContext(MethodDefinitionHandle method, PEFile module) { - this.module = module; + this.metadata = module.Metadata; this.method = method; this.declaringType = module.Metadata.GetMethodDefinition(method).GetDeclaringType(); } + public GenericContext(MethodDefinitionHandle method, MetadataReader metadata) + { + this.metadata = metadata; + this.method = method; + this.declaringType = metadata.GetMethodDefinition(method).GetDeclaringType(); + } + public GenericContext(TypeDefinitionHandle declaringType, PEFile module) { - this.module = module; + this.metadata = module.Metadata; + this.declaringType = declaringType; + } + + public GenericContext(TypeDefinitionHandle declaringType, MetadataReader metadata) + { + this.metadata = metadata; this.declaringType = declaringType; } @@ -239,7 +252,7 @@ namespace ICSharpCode.Decompiler.Metadata GenericParameterHandle genericParameter = GetGenericTypeParameterHandleOrNull(index); if (genericParameter.IsNil) return index.ToString(); - return module.Metadata.GetString(module.Metadata.GetGenericParameter(genericParameter).Name); + return metadata.GetString(metadata.GetGenericParameter(genericParameter).Name); } public string GetGenericMethodTypeParameterName(int index) @@ -247,13 +260,13 @@ namespace ICSharpCode.Decompiler.Metadata GenericParameterHandle genericParameter = GetGenericMethodTypeParameterHandleOrNull(index); if (genericParameter.IsNil) return index.ToString(); - return module.Metadata.GetString(module.Metadata.GetGenericParameter(genericParameter).Name); + return metadata.GetString(metadata.GetGenericParameter(genericParameter).Name); } public GenericParameterHandle GetGenericTypeParameterHandleOrNull(int index) { GenericParameterHandleCollection genericParameters; - if (declaringType.IsNil || index < 0 || index >= (genericParameters = module.Metadata.GetTypeDefinition(declaringType).GetGenericParameters()).Count) + if (declaringType.IsNil || index < 0 || index >= (genericParameters = metadata.GetTypeDefinition(declaringType).GetGenericParameters()).Count) return MetadataTokens.GenericParameterHandle(0); return genericParameters[index]; } @@ -261,7 +274,7 @@ namespace ICSharpCode.Decompiler.Metadata public GenericParameterHandle GetGenericMethodTypeParameterHandleOrNull(int index) { GenericParameterHandleCollection genericParameters; - if (method.IsNil || index < 0 || index >= (genericParameters = module.Metadata.GetMethodDefinition(method).GetGenericParameters()).Count) + if (method.IsNil || index < 0 || index >= (genericParameters = metadata.GetMethodDefinition(method).GetGenericParameters()).Count) return MetadataTokens.GenericParameterHandle(0); return genericParameters[index]; } diff --git a/ILSpy/DebugInfo/PortableDebugInfoProvider.cs b/ILSpy/DebugInfo/PortableDebugInfoProvider.cs index b811ce681..7ed280919 100644 --- a/ILSpy/DebugInfo/PortableDebugInfoProvider.cs +++ b/ILSpy/DebugInfo/PortableDebugInfoProvider.cs @@ -26,19 +26,22 @@ namespace ICSharpCode.Decompiler.PdbProvider class PortableDebugInfoProvider : IDebugInfoProvider { string pdbFileName; - MetadataReaderProvider provider; + + internal MetadataReaderProvider Provider { get; } + + internal bool IsEmbedded => pdbFileName == null; public PortableDebugInfoProvider(string pdbFileName, MetadataReaderProvider provider) { this.pdbFileName = pdbFileName; - this.provider = provider; + this.Provider = provider; } public string Description => pdbFileName == null ? "Embedded in this assembly" : $"Loaded from portable PDB: {pdbFileName}"; public IList GetSequencePoints(MethodDefinitionHandle method) { - var metadata = provider.GetMetadataReader(); + var metadata = Provider.GetMetadataReader(); var debugInfo = metadata.GetMethodDebugInformation(method); var sequencePoints = new List(); @@ -67,7 +70,7 @@ namespace ICSharpCode.Decompiler.PdbProvider public IList GetVariables(MethodDefinitionHandle method) { - var metadata = provider.GetMetadataReader(); + var metadata = Provider.GetMetadataReader(); var variables = new List(); foreach (var h in metadata.GetLocalScopes(method)) { @@ -83,7 +86,7 @@ namespace ICSharpCode.Decompiler.PdbProvider public bool TryGetName(MethodDefinitionHandle method, int index, out string name) { - var metadata = provider.GetMetadataReader(); + var metadata = Provider.GetMetadataReader(); name = null; foreach (var h in metadata.GetLocalScopes(method)) { diff --git a/ILSpy/ILSpy.csproj b/ILSpy/ILSpy.csproj index 763e624d9..93f16b639 100644 --- a/ILSpy/ILSpy.csproj +++ b/ILSpy/ILSpy.csproj @@ -169,11 +169,44 @@ MSBuild:Compile + + Code + MSBuild:Compile + + + Code + MSBuild:Compile + + + Code + MSBuild:Compile + + + Code + MSBuild:Compile + + + Code + MSBuild:Compile + + + Code + MSBuild:Compile + + + Code + MSBuild:Compile + + + Code + MSBuild:Compile + + diff --git a/ILSpy/Metadata/DebugMetadataTreeNode.cs b/ILSpy/Metadata/DebugMetadataTreeNode.cs new file mode 100644 index 000000000..03220d533 --- /dev/null +++ b/ILSpy/Metadata/DebugMetadataTreeNode.cs @@ -0,0 +1,79 @@ +// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System.Linq; +using System.Reflection.Metadata; +using ICSharpCode.Decompiler; +using ICSharpCode.Decompiler.Metadata; +using ICSharpCode.ILSpy.TreeNodes; +using ICSharpCode.ILSpy.ViewModels; + +namespace ICSharpCode.ILSpy.Metadata +{ + class DebugMetadataTreeNode : ILSpyTreeNode + { + private PEFile module; + private MetadataReader provider; + private AssemblyTreeNode assemblyTreeNode; + private bool isEmbedded; + + public DebugMetadataTreeNode(PEFile module, bool isEmbedded, MetadataReader provider, AssemblyTreeNode assemblyTreeNode) + { + this.module = module; + this.provider = provider; + this.assemblyTreeNode = assemblyTreeNode; + this.isEmbedded = isEmbedded; + this.Text = "Debug Metadata (" + (isEmbedded ? "Embedded" : "From portable PDB") + ")"; + this.LazyLoading = true; + } + + public override object Text { get; } + + public override object Icon => Images.Library; + + public override bool View(TabPageModel tabPage) + { + tabPage.Title = Text.ToString(); + tabPage.SupportsLanguageSwitching = false; + + return false; + } + + public override void Decompile(Language language, ITextOutput output, DecompilationOptions options) + { + language.WriteCommentLine(output, "Debug Metadata"); + } + + protected override void LoadChildren() + { + this.Children.Add(new DocumentTableTreeNode(this.module, this.provider, isEmbedded)); + this.Children.Add(new MethodDebugInformationTableTreeNode(this.module, this.provider, isEmbedded)); + this.Children.Add(new LocalScopeTableTreeNode(this.module, this.provider, isEmbedded)); + this.Children.Add(new LocalVariableTableTreeNode(this.module, this.provider, isEmbedded)); + this.Children.Add(new LocalConstantTableTreeNode(this.module, this.provider, isEmbedded)); + this.Children.Add(new ImportScopeTableTreeNode(this.module, this.provider, isEmbedded)); + this.Children.Add(new StateMachineMethodTableTreeNode(this.module, this.provider, isEmbedded)); + this.Children.Add(new CustomDebugInformationTableTreeNode(this.module, this.provider, isEmbedded)); + } + + public MetadataTableTreeNode FindNodeByHandleKind(HandleKind kind) + { + return this.Children.OfType().SingleOrDefault(x => x.Kind == kind); + } + } +} diff --git a/ILSpy/Metadata/DebugTables/CustomDebugInformationTableTreeNode.cs b/ILSpy/Metadata/DebugTables/CustomDebugInformationTableTreeNode.cs new file mode 100644 index 000000000..b818c3b57 --- /dev/null +++ b/ILSpy/Metadata/DebugTables/CustomDebugInformationTableTreeNode.cs @@ -0,0 +1,161 @@ +// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Reflection.Metadata; +using System.Reflection.Metadata.Ecma335; +using System.Text; +using ICSharpCode.Decompiler; +using ICSharpCode.Decompiler.DebugInfo; +using ICSharpCode.Decompiler.Disassembler; +using ICSharpCode.Decompiler.IL; +using ICSharpCode.Decompiler.Metadata; + +namespace ICSharpCode.ILSpy.Metadata +{ + internal class CustomDebugInformationTableTreeNode : DebugMetadataTableTreeNode + { + private readonly bool isEmbedded; + + public CustomDebugInformationTableTreeNode(PEFile module, MetadataReader metadata, bool isEmbedded) + : base(HandleKind.CustomDebugInformation, module, metadata) + { + this.isEmbedded = isEmbedded; + } + + public override object Text => $"37 CustomDebugInformation ({metadata.GetTableRowCount(TableIndex.CustomDebugInformation)})"; + + public override object Icon => Images.Literal; + + public override bool View(ViewModels.TabPageModel tabPage) + { + tabPage.Title = Text.ToString(); + tabPage.SupportsLanguageSwitching = false; + + var view = Helpers.PrepareDataGrid(tabPage, this); + var list = new List(); + CustomDebugInformationEntry scrollTargetEntry = default; + + foreach (var row in metadata.CustomDebugInformation) { + CustomDebugInformationEntry entry = new CustomDebugInformationEntry(module, metadata, isEmbedded, row); + if (entry.RID == scrollTarget) { + scrollTargetEntry = entry; + } + list.Add(entry); + } + + view.ItemsSource = list; + + tabPage.Content = view; + + if (scrollTargetEntry.RID > 1) { + ScrollItemIntoView(view, scrollTargetEntry); + } + + return true; + } + + struct CustomDebugInformationEntry + { + readonly int? offset; + readonly PEFile module; + readonly MetadataReader metadata; + readonly CustomDebugInformationHandle handle; + readonly CustomDebugInformation debugInfo; + + public int RID => MetadataTokens.GetRowNumber(handle); + + public object Offset => offset == null ? "n/a" : (object)offset; + + [StringFormat("X8")] + public int Parent => MetadataTokens.GetToken(debugInfo.Parent); + + public string ParentTooltip { + get { + ITextOutput output = new PlainTextOutput(); + var context = new GenericContext(default(TypeDefinitionHandle), module); + debugInfo.Parent.WriteTo(module, output, context); + return output.ToString(); + } + } + + [StringFormat("X8")] + public int Kind => MetadataTokens.GetHeapOffset(debugInfo.Kind); + + public string KindTooltip { + get { + if (debugInfo.Kind.IsNil) + return null; + var guid = metadata.GetGuid(debugInfo.Kind); + if (KnownGuids.StateMachineHoistedLocalScopes == guid) { + return "State Machine Hoisted Local Scopes (C# / VB) [" + guid + "]"; + } + if (KnownGuids.DynamicLocalVariables == guid) { + return "Dynamic Local Variables (C#) [" + guid + "]"; + } + if (KnownGuids.DefaultNamespaces == guid) { + return "Default Namespaces (VB) [" + guid + "]"; + } + if (KnownGuids.EditAndContinueLocalSlotMap == guid) { + return "Edit And Continue Local Slot Map (C# / VB) [" + guid + "]"; + } + if (KnownGuids.EditAndContinueLambdaAndClosureMap == guid) { + return "Edit And Continue Lambda And Closure Map (C# / VB) [" + guid + "]"; + } + if (KnownGuids.EmbeddedSource == guid) { + return "State Machine Hoisted Local Scopes (C# / VB) [" + guid + "]"; + } + if (KnownGuids.SourceLink == guid) { + return "Source Link (C# / VB) [" + guid + "]"; + } + if (KnownGuids.MethodSteppingInformation == guid) { + return "Method Stepping Information (C# / VB) [" + guid + "]"; + } + + return $"Unknown [" + guid + "]"; + } + } + + [StringFormat("X")] + public int Value => MetadataTokens.GetHeapOffset(debugInfo.Value); + + public string ValueTooltip { + get { + return null; + } + } + + public CustomDebugInformationEntry(PEFile module, MetadataReader metadata, bool isEmbedded, CustomDebugInformationHandle handle) + { + this.offset = isEmbedded ? null : (int?)metadata.GetTableMetadataOffset(TableIndex.CustomDebugInformation) + + metadata.GetTableRowSize(TableIndex.CustomDebugInformation) * (MetadataTokens.GetRowNumber(handle) - 1); + this.module = module; + this.metadata = metadata; + this.handle = handle; + this.debugInfo = metadata.GetCustomDebugInformation(handle); + } + } + + public override void Decompile(Language language, ITextOutput output, DecompilationOptions options) + { + language.WriteCommentLine(output, "CustomDebugInformation"); + } + } +} \ No newline at end of file diff --git a/ILSpy/Metadata/DebugTables/DocumentTableTreeNode.cs b/ILSpy/Metadata/DebugTables/DocumentTableTreeNode.cs new file mode 100644 index 000000000..6b690c7df --- /dev/null +++ b/ILSpy/Metadata/DebugTables/DocumentTableTreeNode.cs @@ -0,0 +1,149 @@ +// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Reflection.Metadata; +using System.Reflection.Metadata.Ecma335; + +using ICSharpCode.Decompiler; +using ICSharpCode.Decompiler.DebugInfo; +using ICSharpCode.Decompiler.Metadata; + +namespace ICSharpCode.ILSpy.Metadata +{ + internal class DocumentTableTreeNode : DebugMetadataTableTreeNode + { + private readonly bool isEmbedded; + + public DocumentTableTreeNode(PEFile module, MetadataReader metadata, bool isEmbedded) + : base(HandleKind.Document, module, metadata) + { + this.isEmbedded = isEmbedded; + } + + public override object Text => $"30 Document ({metadata.GetTableRowCount(TableIndex.Document)})"; + + public override object Icon => Images.Literal; + + public override bool View(ViewModels.TabPageModel tabPage) + { + tabPage.Title = Text.ToString(); + tabPage.SupportsLanguageSwitching = false; + + var view = Helpers.PrepareDataGrid(tabPage, this); + var list = new List(); + DocumentEntry scrollTargetEntry = default; + + foreach (var row in metadata.Documents) { + DocumentEntry entry = new DocumentEntry(metadata, isEmbedded, row); + if (entry.RID == scrollTarget) { + scrollTargetEntry = entry; + } + list.Add(entry); + } + + view.ItemsSource = list; + + tabPage.Content = view; + + if (scrollTargetEntry.RID > 1) { + ScrollItemIntoView(view, scrollTargetEntry); + } + + return true; + } + + struct DocumentEntry + { + readonly int? offset; + readonly MetadataReader metadata; + readonly DocumentHandle handle; + readonly Document document; + + public int RID => MetadataTokens.GetRowNumber(handle); + + public object Offset => offset == null ? "n/a" : (object)offset; + + public string Name => metadata.GetString(document.Name); + + public string NameTooltip => $"{MetadataTokens.GetHeapOffset(document.Name):X} \"{Name}\""; + + [StringFormat("X")] + public int HashAlgorithm => MetadataTokens.GetHeapOffset(document.HashAlgorithm); + + public string HashAlgorithmTooltip { + get { + if (document.HashAlgorithm.IsNil) + return null; + Guid guid = metadata.GetGuid(document.HashAlgorithm); + if (guid == KnownGuids.HashAlgorithmSHA1) + return "SHA1 [ff1816ec-aa5e-4d10-87f7-6f4963833460]"; + if (guid == KnownGuids.HashAlgorithmSHA256) + return "SHA256 [8829d00f-11b8-4213-878b-770e8597ac16]"; + return $"Unknown [" + guid + "]"; + } + } + + [StringFormat("X")] + public int Hash => MetadataTokens.GetHeapOffset(document.Hash); + + public string HashTooltip { + get { + if (document.Hash.IsNil) + return null; + System.Collections.Immutable.ImmutableArray token = metadata.GetBlobContent(document.Hash); + return token.ToHexString(token.Length); + } + } + + [StringFormat("X")] + public int Language => MetadataTokens.GetHeapOffset(document.Language); + + public string LanguageTooltip { + get { + if (document.Language.IsNil) + return null; + Guid guid = metadata.GetGuid(document.Language); + if (guid == KnownGuids.CSharpLanguageGuid) + return "Visual C# [3f5162f8-07c6-11d3-9053-00c04fa302a1]"; + if (guid == KnownGuids.VBLanguageGuid) + return "Visual Basic [3a12d0b8-c26c-11d0-b442-00a0244a1dd2]"; + if (guid == KnownGuids.FSharpLanguageGuid) + return "Visual F# [ab4f38c9-b6e6-43ba-be3b-58080b2ccce3]"; + return $"Unknown [" + guid + "]"; + } + } + + public DocumentEntry(MetadataReader metadata, bool isEmbedded, DocumentHandle handle) + { + this.offset = isEmbedded ? null : (int?)metadata.GetTableMetadataOffset(TableIndex.Document) + + metadata.GetTableRowSize(TableIndex.Document) * (MetadataTokens.GetRowNumber(handle) - 1); + this.metadata = metadata; + this.handle = handle; + this.document = metadata.GetDocument(handle); + } + } + + public override void Decompile(Language language, ITextOutput output, DecompilationOptions options) + { + language.WriteCommentLine(output, "Document"); + } + } +} \ No newline at end of file diff --git a/ILSpy/Metadata/DebugTables/ImportScopeTableTreeNode.cs b/ILSpy/Metadata/DebugTables/ImportScopeTableTreeNode.cs new file mode 100644 index 000000000..289cbabc9 --- /dev/null +++ b/ILSpy/Metadata/DebugTables/ImportScopeTableTreeNode.cs @@ -0,0 +1,109 @@ +// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Reflection.Metadata; +using System.Reflection.Metadata.Ecma335; +using System.Text; +using ICSharpCode.Decompiler; +using ICSharpCode.Decompiler.IL; +using ICSharpCode.Decompiler.Disassembler; +using ICSharpCode.Decompiler.Metadata; +using System.Linq; + +namespace ICSharpCode.ILSpy.Metadata +{ + internal class ImportScopeTableTreeNode : DebugMetadataTableTreeNode + { + private readonly bool isEmbedded; + + public ImportScopeTableTreeNode(PEFile module, MetadataReader metadata, bool isEmbedded) + : base(HandleKind.ImportScope, module, metadata) + { + this.isEmbedded = isEmbedded; + } + + public override object Text => $"35 ImportScope ({metadata.GetTableRowCount(TableIndex.ImportScope)})"; + + public override object Icon => Images.Literal; + + public override bool View(ViewModels.TabPageModel tabPage) + { + tabPage.Title = Text.ToString(); + tabPage.SupportsLanguageSwitching = false; + + var view = Helpers.PrepareDataGrid(tabPage, this); + var list = new List(); + ImportScopeEntry scrollTargetEntry = default; + + foreach (var row in metadata.ImportScopes) { + ImportScopeEntry entry = new ImportScopeEntry(module, metadata, isEmbedded, row); + if (entry.RID == scrollTarget) { + scrollTargetEntry = entry; + } + list.Add(entry); + } + + view.ItemsSource = list; + + tabPage.Content = view; + + if (scrollTargetEntry.RID > 1) { + ScrollItemIntoView(view, scrollTargetEntry); + } + + return true; + } + + struct ImportScopeEntry + { + readonly int? offset; + readonly PEFile module; + readonly MetadataReader metadata; + readonly ImportScopeHandle handle; + readonly ImportScope localScope; + + public int RID => MetadataTokens.GetRowNumber(handle); + + public object Offset => offset == null ? "n/a" : (object)offset; + + [StringFormat("X8")] + public int Parent => MetadataTokens.GetToken(localScope.Parent); + + [StringFormat("X")] + public int Imports => MetadataTokens.GetHeapOffset(localScope.ImportsBlob); + + public ImportScopeEntry(PEFile module, MetadataReader metadata, bool isEmbedded, ImportScopeHandle handle) + { + this.offset = isEmbedded ? null : (int?)metadata.GetTableMetadataOffset(TableIndex.ImportScope) + + metadata.GetTableRowSize(TableIndex.ImportScope) * (MetadataTokens.GetRowNumber(handle) - 1); + this.module = module; + this.metadata = metadata; + this.handle = handle; + this.localScope = metadata.GetImportScope(handle); + } + } + + public override void Decompile(Language language, ITextOutput output, DecompilationOptions options) + { + language.WriteCommentLine(output, "ImportScope"); + } + } +} \ No newline at end of file diff --git a/ILSpy/Metadata/DebugTables/LocalConstantTableTreeNode.cs b/ILSpy/Metadata/DebugTables/LocalConstantTableTreeNode.cs new file mode 100644 index 000000000..a0474b798 --- /dev/null +++ b/ILSpy/Metadata/DebugTables/LocalConstantTableTreeNode.cs @@ -0,0 +1,108 @@ +// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Reflection.Metadata; +using System.Reflection.Metadata.Ecma335; +using System.Text; +using ICSharpCode.Decompiler; +using ICSharpCode.Decompiler.Disassembler; +using ICSharpCode.Decompiler.Metadata; + +namespace ICSharpCode.ILSpy.Metadata +{ + internal class LocalConstantTableTreeNode : DebugMetadataTableTreeNode + { + private readonly bool isEmbedded; + + public LocalConstantTableTreeNode(PEFile module, MetadataReader metadata, bool isEmbedded) + : base(HandleKind.LocalConstant, module, metadata) + { + this.isEmbedded = isEmbedded; + } + + public override object Text => $"34 LocalConstant ({metadata.GetTableRowCount(TableIndex.LocalConstant)})"; + + public override object Icon => Images.Literal; + + public override bool View(ViewModels.TabPageModel tabPage) + { + tabPage.Title = Text.ToString(); + tabPage.SupportsLanguageSwitching = false; + + var view = Helpers.PrepareDataGrid(tabPage, this); + var list = new List(); + LocalConstantEntry scrollTargetEntry = default; + + foreach (var row in metadata.LocalConstants) { + LocalConstantEntry entry = new LocalConstantEntry(module, metadata, isEmbedded, row); + if (entry.RID == scrollTarget) { + scrollTargetEntry = entry; + } + list.Add(entry); + } + + view.ItemsSource = list; + + tabPage.Content = view; + + if (scrollTargetEntry.RID > 1) { + ScrollItemIntoView(view, scrollTargetEntry); + } + + return true; + } + + struct LocalConstantEntry + { + readonly int? offset; + readonly PEFile module; + readonly MetadataReader metadata; + readonly LocalConstantHandle handle; + readonly LocalConstant localConst; + + public int RID => MetadataTokens.GetRowNumber(handle); + + public object Offset => offset == null ? "n/a" : (object)offset; + + public string Name => metadata.GetString(localConst.Name); + + public string NameTooltip => $"{MetadataTokens.GetHeapOffset(localConst.Name):X} \"{Name}\""; + + [StringFormat("X")] + public int Signature => MetadataTokens.GetToken(localConst.Signature); + + public LocalConstantEntry(PEFile module, MetadataReader metadata, bool isEmbedded, LocalConstantHandle handle) + { + this.offset = isEmbedded ? null : (int?)metadata.GetTableMetadataOffset(TableIndex.LocalConstant) + + metadata.GetTableRowSize(TableIndex.LocalConstant) * (MetadataTokens.GetRowNumber(handle) - 1); + this.module = module; + this.metadata = metadata; + this.handle = handle; + this.localConst = metadata.GetLocalConstant(handle); + } + } + + public override void Decompile(Language language, ITextOutput output, DecompilationOptions options) + { + language.WriteCommentLine(output, "Document"); + } + } +} \ No newline at end of file diff --git a/ILSpy/Metadata/DebugTables/LocalScopeTableTreeNode.cs b/ILSpy/Metadata/DebugTables/LocalScopeTableTreeNode.cs new file mode 100644 index 000000000..e30b45245 --- /dev/null +++ b/ILSpy/Metadata/DebugTables/LocalScopeTableTreeNode.cs @@ -0,0 +1,129 @@ +// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Reflection.Metadata; +using System.Reflection.Metadata.Ecma335; +using System.Text; +using ICSharpCode.Decompiler; +using ICSharpCode.Decompiler.IL; +using ICSharpCode.Decompiler.Disassembler; +using ICSharpCode.Decompiler.Metadata; +using System.Linq; + +namespace ICSharpCode.ILSpy.Metadata +{ + internal class LocalScopeTableTreeNode : DebugMetadataTableTreeNode + { + private readonly bool isEmbedded; + + public LocalScopeTableTreeNode(PEFile module, MetadataReader metadata, bool isEmbedded) + : base(HandleKind.LocalScope, module, metadata) + { + this.isEmbedded = isEmbedded; + } + + public override object Text => $"32 LocalScope ({metadata.GetTableRowCount(TableIndex.LocalScope)})"; + + public override object Icon => Images.Literal; + + public override bool View(ViewModels.TabPageModel tabPage) + { + tabPage.Title = Text.ToString(); + tabPage.SupportsLanguageSwitching = false; + + var view = Helpers.PrepareDataGrid(tabPage, this); + var list = new List(); + LocalScopeEntry scrollTargetEntry = default; + + foreach (var row in metadata.LocalScopes) { + LocalScopeEntry entry = new LocalScopeEntry(module, metadata, isEmbedded, row); + if (entry.RID == scrollTarget) { + scrollTargetEntry = entry; + } + list.Add(entry); + } + + view.ItemsSource = list; + + tabPage.Content = view; + + if (scrollTargetEntry.RID > 1) { + ScrollItemIntoView(view, scrollTargetEntry); + } + + return true; + } + + struct LocalScopeEntry + { + readonly int? offset; + readonly PEFile module; + readonly MetadataReader metadata; + readonly LocalScopeHandle handle; + readonly LocalScope localScope; + + public int RID => MetadataTokens.GetRowNumber(handle); + + public object Offset => offset == null ? "n/a" : (object)offset; + + [StringFormat("X8")] + public int Method => MetadataTokens.GetToken(localScope.Method); + + public string MethodTooltip { + get { + ITextOutput output = new PlainTextOutput(); + ((EntityHandle)localScope.Method).WriteTo(module, output, Decompiler.Metadata.GenericContext.Empty); + return output.ToString(); + } + } + + [StringFormat("X8")] + public int ImportScope => MetadataTokens.GetToken(localScope.ImportScope); + + [StringFormat("X8")] + public int VariableList => MetadataTokens.GetToken(localScope.GetLocalVariables().FirstOrDefault()); + + [StringFormat("X8")] + public int ConstantList => MetadataTokens.GetToken(localScope.GetLocalConstants().FirstOrDefault()); + + [StringFormat("X8")] + public int StartOffset => localScope.StartOffset; + + [StringFormat("X8")] + public int Length => localScope.Length; + + public LocalScopeEntry(PEFile module, MetadataReader metadata, bool isEmbedded, LocalScopeHandle handle) + { + this.offset = isEmbedded ? null : (int?)metadata.GetTableMetadataOffset(TableIndex.LocalScope) + + metadata.GetTableRowSize(TableIndex.LocalScope) * (MetadataTokens.GetRowNumber(handle) - 1); + this.module = module; + this.metadata = metadata; + this.handle = handle; + this.localScope = metadata.GetLocalScope(handle); + } + } + + public override void Decompile(Language language, ITextOutput output, DecompilationOptions options) + { + language.WriteCommentLine(output, "LocalScope"); + } + } +} \ No newline at end of file diff --git a/ILSpy/Metadata/DebugTables/LocalVariableTableTreeNode.cs b/ILSpy/Metadata/DebugTables/LocalVariableTableTreeNode.cs new file mode 100644 index 000000000..165e1f37c --- /dev/null +++ b/ILSpy/Metadata/DebugTables/LocalVariableTableTreeNode.cs @@ -0,0 +1,110 @@ +// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System.Collections.Generic; +using System.Reflection.Metadata; +using System.Reflection.Metadata.Ecma335; +using ICSharpCode.Decompiler; +using ICSharpCode.Decompiler.Metadata; + +namespace ICSharpCode.ILSpy.Metadata +{ + internal class LocalVariableTableTreeNode : DebugMetadataTableTreeNode + { + private readonly bool isEmbedded; + + public LocalVariableTableTreeNode(PEFile module, MetadataReader metadata, bool isEmbedded) + : base(HandleKind.LocalVariable, module, metadata) + { + this.isEmbedded = isEmbedded; + } + + public override object Text => $"33 LocalVariable ({metadata.GetTableRowCount(TableIndex.LocalVariable)})"; + + public override object Icon => Images.Literal; + + public override bool View(ViewModels.TabPageModel tabPage) + { + tabPage.Title = Text.ToString(); + tabPage.SupportsLanguageSwitching = false; + + var view = Helpers.PrepareDataGrid(tabPage, this); + var list = new List(); + LocalVariableEntry scrollTargetEntry = default; + + foreach (var row in metadata.LocalVariables) { + LocalVariableEntry entry = new LocalVariableEntry(module, metadata, isEmbedded, row); + if (entry.RID == scrollTarget) { + scrollTargetEntry = entry; + } + list.Add(entry); + } + + view.ItemsSource = list; + + tabPage.Content = view; + + if (scrollTargetEntry.RID > 1) { + ScrollItemIntoView(view, scrollTargetEntry); + } + + return true; + } + + struct LocalVariableEntry + { + readonly int? offset; + readonly PEFile module; + readonly MetadataReader metadata; + readonly LocalVariableHandle handle; + readonly LocalVariable localVar; + + public int RID => MetadataTokens.GetRowNumber(handle); + + public object Offset => offset == null ? "n/a" : (object)offset; + + [StringFormat("X8")] + public LocalVariableAttributes Attributes => localVar.Attributes; + + public object AttributesTooltip => new FlagsTooltip() { + FlagGroup.CreateMultipleChoiceGroup(typeof(LocalVariableAttributes)), + }; + + public int Index => localVar.Index; + + public string Name => metadata.GetString(localVar.Name); + + public string NameTooltip => $"{MetadataTokens.GetHeapOffset(localVar.Name):X} \"{Name}\""; + + public LocalVariableEntry(PEFile module, MetadataReader metadata, bool isEmbedded, LocalVariableHandle handle) + { + this.offset = isEmbedded ? null : (int?)metadata.GetTableMetadataOffset(TableIndex.LocalVariable) + + metadata.GetTableRowSize(TableIndex.LocalVariable) * (MetadataTokens.GetRowNumber(handle) - 1); + this.module = module; + this.metadata = metadata; + this.handle = handle; + this.localVar = metadata.GetLocalVariable(handle); + } + } + + public override void Decompile(Language language, ITextOutput output, DecompilationOptions options) + { + language.WriteCommentLine(output, "Document"); + } + } +} \ No newline at end of file diff --git a/ILSpy/Metadata/DebugTables/MethodDebugInformationTableTreeNode.cs b/ILSpy/Metadata/DebugTables/MethodDebugInformationTableTreeNode.cs new file mode 100644 index 000000000..718e4cad9 --- /dev/null +++ b/ILSpy/Metadata/DebugTables/MethodDebugInformationTableTreeNode.cs @@ -0,0 +1,150 @@ +// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Reflection.Metadata; +using System.Reflection.Metadata.Ecma335; +using System.Text; +using ICSharpCode.Decompiler; +using ICSharpCode.Decompiler.Disassembler; +using ICSharpCode.Decompiler.Metadata; + +namespace ICSharpCode.ILSpy.Metadata +{ + internal class MethodDebugInformationTableTreeNode : DebugMetadataTableTreeNode + { + private readonly bool isEmbedded; + + public MethodDebugInformationTableTreeNode(PEFile module, MetadataReader metadata, bool isEmbedded) + : base(HandleKind.MethodDebugInformation, module, metadata) + { + this.isEmbedded = isEmbedded; + } + + public override object Text => $"31 MethodDebugInformation ({metadata.GetTableRowCount(TableIndex.MethodDebugInformation)})"; + + public override object Icon => Images.Literal; + + public override bool View(ViewModels.TabPageModel tabPage) + { + tabPage.Title = Text.ToString(); + tabPage.SupportsLanguageSwitching = false; + + var view = Helpers.PrepareDataGrid(tabPage, this); + var list = new List(); + MethodDebugInformationEntry scrollTargetEntry = default; + + foreach (var row in metadata.MethodDebugInformation) { + MethodDebugInformationEntry entry = new MethodDebugInformationEntry(module, metadata, isEmbedded, row); + if (entry.RID == scrollTarget) { + scrollTargetEntry = entry; + } + list.Add(entry); + } + + view.ItemsSource = list; + + tabPage.Content = view; + + if (scrollTargetEntry.RID > 1) { + ScrollItemIntoView(view, scrollTargetEntry); + } + + return true; + } + + struct MethodDebugInformationEntry + { + readonly int? offset; + readonly PEFile module; + readonly MetadataReader metadata; + readonly MethodDebugInformationHandle handle; + readonly MethodDebugInformation debugInfo; + + public int RID => MetadataTokens.GetRowNumber(handle); + + public object Offset => offset == null ? "n/a" : (object)offset; + + [StringFormat("X8")] + public int Document => MetadataTokens.GetToken(debugInfo.Document); + + public string DocumentTooltip { + get { + if (debugInfo.Document.IsNil) + return null; + var document = metadata.GetDocument(debugInfo.Document); + return $"{MetadataTokens.GetHeapOffset(document.Name):X} \"{metadata.GetString(document.Name)}\""; + } + } + + [StringFormat("X")] + public int SequencePoints => MetadataTokens.GetHeapOffset(debugInfo.SequencePointsBlob); + + public string SequencePointsTooltip { + get { + if (debugInfo.SequencePointsBlob.IsNil) + return null; + StringBuilder sb = new StringBuilder(); + foreach (var p in debugInfo.GetSequencePoints()) { + sb.AppendLine($"document='{MetadataTokens.GetToken(p.Document):X8}', offset={p.Offset}, start={p.StartLine};{p.StartColumn}, end={p.EndLine};{p.EndColumn}, hidden={p.IsHidden}"); + } + return sb.ToString().TrimEnd(); + } + } + + [StringFormat("X")] + public int LocalSignature => MetadataTokens.GetToken(debugInfo.LocalSignature); + + public string LocalSignatureTooltip { + get { + if (debugInfo.LocalSignature.IsNil) + return null; + ITextOutput output = new PlainTextOutput(); + var context = new Decompiler.Metadata.GenericContext(default(TypeDefinitionHandle), metadata); + StandaloneSignature localSignature = module.Metadata.GetStandaloneSignature(debugInfo.LocalSignature); + var signatureDecoder = new DisassemblerSignatureTypeProvider(module, output); + int index = 0; + foreach (var item in localSignature.DecodeLocalSignature(signatureDecoder, context)) { + if (index > 0) output.WriteLine(); + output.Write("[{0}] ", index); + item(ILNameSyntax.Signature); + index++; + } + return output.ToString(); + } + } + + public MethodDebugInformationEntry(PEFile module, MetadataReader metadata, bool isEmbedded, MethodDebugInformationHandle handle) + { + this.offset = isEmbedded ? null : (int?)metadata.GetTableMetadataOffset(TableIndex.MethodDebugInformation) + + metadata.GetTableRowSize(TableIndex.MethodDebugInformation) * (MetadataTokens.GetRowNumber(handle) - 1); + this.module = module; + this.metadata = metadata; + this.handle = handle; + this.debugInfo = metadata.GetMethodDebugInformation(handle); + } + } + + public override void Decompile(Language language, ITextOutput output, DecompilationOptions options) + { + language.WriteCommentLine(output, "MethodDebugInformation"); + } + } +} \ No newline at end of file diff --git a/ILSpy/Metadata/DebugTables/StateMachineMethodTableTreeNode.cs b/ILSpy/Metadata/DebugTables/StateMachineMethodTableTreeNode.cs new file mode 100644 index 000000000..1f65d29f0 --- /dev/null +++ b/ILSpy/Metadata/DebugTables/StateMachineMethodTableTreeNode.cs @@ -0,0 +1,141 @@ +// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Reflection.Metadata; +using System.Reflection.Metadata.Ecma335; +using System.Text; +using ICSharpCode.Decompiler; +using ICSharpCode.Decompiler.IL; +using ICSharpCode.Decompiler.Disassembler; +using ICSharpCode.Decompiler.Metadata; + +namespace ICSharpCode.ILSpy.Metadata +{ + internal class StateMachineMethodTableTreeNode : DebugMetadataTableTreeNode + { + readonly bool isEmbedded; + + public StateMachineMethodTableTreeNode(PEFile module, MetadataReader metadata, bool isEmbedded) + : base((HandleKind)0x36, module, metadata) + { + this.isEmbedded = isEmbedded; + } + + public override object Text => $"36 StateMachineMethod ({metadata.GetTableRowCount(TableIndex.StateMachineMethod)})"; + + public override object Icon => Images.Literal; + + public unsafe override bool View(ViewModels.TabPageModel tabPage) + { + tabPage.Title = Text.ToString(); + tabPage.SupportsLanguageSwitching = false; + + var view = Helpers.PrepareDataGrid(tabPage, this); + var list = new List(); + StateMachineMethodEntry scrollTargetEntry = default; + var length = metadata.GetTableRowCount(TableIndex.StateMachineMethod); + byte* ptr = metadata.MetadataPointer; + + for (int rid = 1; rid <= length; rid++) { + StateMachineMethodEntry entry = new StateMachineMethodEntry(module, ptr, isEmbedded, rid); + if (scrollTarget == rid) { + scrollTargetEntry = entry; + } + list.Add(entry); + } + + view.ItemsSource = list; + + tabPage.Content = view; + + if (scrollTargetEntry.RID > 1) { + ScrollItemIntoView(view, scrollTargetEntry); + } + + return true; + } + + readonly struct StateMachineMethod + { + public readonly MethodDefinitionHandle MoveNextMethod; + public readonly MethodDefinitionHandle KickoffMethod; + + public unsafe StateMachineMethod(byte* ptr, int methodDefSize) + { + MoveNextMethod = MetadataTokens.MethodDefinitionHandle(Helpers.GetValue(ptr, methodDefSize)); + KickoffMethod = MetadataTokens.MethodDefinitionHandle(Helpers.GetValue(ptr + methodDefSize, methodDefSize)); + } + } + + unsafe struct StateMachineMethodEntry + { + readonly int? offset; + readonly PEFile module; + readonly MetadataReader metadata; + readonly StateMachineMethod stateMachineMethod; + + public int RID { get; } + + public object Offset => offset == null ? "n/a" : (object)offset; + + [StringFormat("X8")] + public int MoveNextMethod => MetadataTokens.GetToken(stateMachineMethod.MoveNextMethod); + + public string MoveNextMethodTooltip { + get { + ITextOutput output = new PlainTextOutput(); + var context = new GenericContext(default(TypeDefinitionHandle), module); + ((EntityHandle)stateMachineMethod.MoveNextMethod).WriteTo(module, output, context); + return output.ToString(); + } + } + + [StringFormat("X8")] + public int KickoffMethod => MetadataTokens.GetToken(stateMachineMethod.KickoffMethod); + + public string KickoffMethodTooltip { + get { + ITextOutput output = new PlainTextOutput(); + var context = new GenericContext(default(TypeDefinitionHandle), module); + ((EntityHandle)stateMachineMethod.KickoffMethod).WriteTo(module, output, context); + return output.ToString(); + } + } + + public StateMachineMethodEntry(PEFile module, byte* ptr, bool isEmbedded, int row) + { + this.module = module; + this.metadata = module.Metadata; + this.RID = row; + int rowOffset = metadata.GetTableMetadataOffset(TableIndex.StateMachineMethod) + + metadata.GetTableRowSize(TableIndex.StateMachineMethod) * (row - 1); + this.offset = isEmbedded ? null : (int?)rowOffset; + this.stateMachineMethod = new StateMachineMethod(ptr + rowOffset, metadata.GetTableRowCount(TableIndex.MethodDef) < ushort.MaxValue ? 2 : 4); + } + + } + + public override void Decompile(Language language, ITextOutput output, DecompilationOptions options) + { + language.WriteCommentLine(output, "StateMachineMethod"); + } + } +} \ No newline at end of file diff --git a/ILSpy/Metadata/MetadataTableTreeNode.cs b/ILSpy/Metadata/MetadataTableTreeNode.cs index 1bb40f1cf..8daea15c9 100644 --- a/ILSpy/Metadata/MetadataTableTreeNode.cs +++ b/ILSpy/Metadata/MetadataTableTreeNode.cs @@ -62,4 +62,15 @@ namespace ICSharpCode.ILSpy.Metadata this.scrollTarget = default; } } + + internal abstract class DebugMetadataTableTreeNode : MetadataTableTreeNode + { + protected MetadataReader metadata; + + public DebugMetadataTableTreeNode(HandleKind kind, PEFile module, MetadataReader metadata) + : base(kind, module) + { + this.metadata = metadata; + } + } } \ No newline at end of file diff --git a/ILSpy/TreeNodes/AssemblyTreeNode.cs b/ILSpy/TreeNodes/AssemblyTreeNode.cs index 56f5633bf..33a5ad24a 100644 --- a/ILSpy/TreeNodes/AssemblyTreeNode.cs +++ b/ILSpy/TreeNodes/AssemblyTreeNode.cs @@ -143,6 +143,10 @@ namespace ICSharpCode.ILSpy.TreeNodes var assembly = (MetadataModule)typeSystem.MainModule; var metadata = module.Metadata; this.Children.Add(new Metadata.MetadataTreeNode(module, this)); + Decompiler.DebugInfo.IDebugInfoProvider debugInfo = LoadedAssembly.GetDebugInfoOrNull(); + if (debugInfo is Decompiler.PdbProvider.PortableDebugInfoProvider ppdb) { + this.Children.Add(new Metadata.DebugMetadataTreeNode(module, ppdb.IsEmbedded, ppdb.Provider.GetMetadataReader(), this)); + } this.Children.Add(new ReferenceFolderTreeNode(module, this)); if (module.Resources.Any()) this.Children.Add(new ResourceListTreeNode(module));