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));