diff --git a/ILSpy/Metadata/DebugDirectory/CodeViewTreeNode.cs b/ILSpy/Metadata/DebugDirectory/CodeViewTreeNode.cs new file mode 100644 index 000000000..5fdf81a90 --- /dev/null +++ b/ILSpy/Metadata/DebugDirectory/CodeViewTreeNode.cs @@ -0,0 +1,75 @@ +// 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. + +#nullable enable + +using System.Reflection.PortableExecutable; + +using ICSharpCode.Decompiler; +using ICSharpCode.Decompiler.Metadata; +using ICSharpCode.ILSpy.TreeNodes; +using ICSharpCode.ILSpy.ViewModels; + +namespace ICSharpCode.ILSpy.Metadata +{ + sealed class CodeViewTreeNode : ILSpyTreeNode + { + readonly CodeViewDebugDirectoryData entry; + public CodeViewTreeNode(CodeViewDebugDirectoryData entry) + { + this.entry = entry; + } + + override public object Text => nameof(DebugDirectoryEntryType.CodeView); + + public override object ToolTip => "Associated PDB file description."; + + public override object Icon => Images.Literal; + + public override bool View(TabPageModel tabPage) + { + tabPage.Title = Text.ToString(); + tabPage.SupportsLanguageSwitching = false; + + var dataGrid = Helpers.PrepareDataGrid(tabPage, this); + + dataGrid.ItemsSource = new[] { entry }; + + tabPage.Content = dataGrid; + + return true; + } + + sealed class PdbChecksumDebugDirectoryDataEntry + { + readonly CodeViewDebugDirectoryData entry; + public PdbChecksumDebugDirectoryDataEntry(CodeViewDebugDirectoryData entry) + { + this.entry = entry; + } + } + + public override void Decompile(Language language, ITextOutput output, DecompilationOptions options) + { + language.WriteCommentLine(output, Text.ToString()); + language.WriteCommentLine(output, $"GUID: {entry.Guid}"); + language.WriteCommentLine(output, $"Age: {entry.Age}"); + language.WriteCommentLine(output, $"Path: {entry.Path}"); + } + } +} diff --git a/ILSpy/Metadata/DebugDirectory/DebugDirectoryEntryTreeNode.cs b/ILSpy/Metadata/DebugDirectory/DebugDirectoryEntryTreeNode.cs new file mode 100644 index 000000000..995cc8a17 --- /dev/null +++ b/ILSpy/Metadata/DebugDirectory/DebugDirectoryEntryTreeNode.cs @@ -0,0 +1,62 @@ +// 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. + +#nullable enable + +using System.Reflection.PortableExecutable; + +using ICSharpCode.Decompiler; +using ICSharpCode.Decompiler.Metadata; +using ICSharpCode.ILSpy.TreeNodes; +using ICSharpCode.ILSpy.ViewModels; + +namespace ICSharpCode.ILSpy.Metadata +{ + sealed class DebugDirectoryEntryTreeNode : ILSpyTreeNode + { + readonly PEFile module; + readonly PEReader reader; + readonly DebugDirectoryEntry entry; + public DebugDirectoryEntryTreeNode(PEFile module, DebugDirectoryEntry entry) + { + this.module = module; + this.reader = module.Reader; + this.entry = entry; + } + + override public object Text => $"{entry.Type}"; + + public override object Icon => Images.Literal; + + public override void Decompile(Language language, ITextOutput output, DecompilationOptions options) + { + language.WriteCommentLine(output, Text.ToString()); + if (entry.DataSize > 0) + { + language.WriteCommentLine(output, $"Raw Data ({entry.DataSize}):"); + int dataOffset = module.Reader.IsLoadedImage ? entry.DataRelativeVirtualAddress : entry.DataPointer; + var data = module.Reader.GetEntireImage().GetContent(dataOffset, entry.DataSize); + language.WriteCommentLine(output, data.ToHexString(data.Length)); + } + else + { + language.WriteCommentLine(output, $"(no data)"); + } + } + } +} diff --git a/ILSpy/Metadata/DebugDirectory/PdbChecksumTreeNode.cs b/ILSpy/Metadata/DebugDirectory/PdbChecksumTreeNode.cs new file mode 100644 index 000000000..13444518d --- /dev/null +++ b/ILSpy/Metadata/DebugDirectory/PdbChecksumTreeNode.cs @@ -0,0 +1,83 @@ +// 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. + +#nullable enable + +using System.Reflection.PortableExecutable; + +using ICSharpCode.Decompiler; +using ICSharpCode.Decompiler.Metadata; +using ICSharpCode.ILSpy.TreeNodes; +using ICSharpCode.ILSpy.ViewModels; + +namespace ICSharpCode.ILSpy.Metadata +{ + sealed class PdbChecksumTreeNode : ILSpyTreeNode + { + readonly PdbChecksumDebugDirectoryData entry; + public PdbChecksumTreeNode(PdbChecksumDebugDirectoryData entry) + { + this.entry = entry; + } + + override public object Text => nameof(DebugDirectoryEntryType.PdbChecksum); + + public override object ToolTip + => "The entry stores a crypto hash of the content of the symbol file the PE/COFF\n" + + "file was built with. The hash can be used to validate that a given PDB file was\n" + + "built with the PE/COFF file and not altered in any way. More than one entry can\n" + + "be present if multiple PDBs were produced during the build of the PE/COFF file\n" + + "(for example, private and public symbols)."; + + public override object Icon => Images.Literal; + + public override bool View(TabPageModel tabPage) + { + tabPage.Title = Text.ToString(); + tabPage.SupportsLanguageSwitching = false; + + var dataGrid = Helpers.PrepareDataGrid(tabPage, this); + + dataGrid.ItemsSource = new[] { new PdbChecksumDebugDirectoryDataEntry(entry) }; + + tabPage.Content = dataGrid; + + return true; + } + + sealed class PdbChecksumDebugDirectoryDataEntry + { + readonly PdbChecksumDebugDirectoryData entry; + public PdbChecksumDebugDirectoryDataEntry(PdbChecksumDebugDirectoryData entry) + { + this.entry = entry; + } + + public string AlgorithmName => entry.AlgorithmName; + + public string Checksum => entry.Checksum.ToHexString(entry.Checksum.Length); + } + + public override void Decompile(Language language, ITextOutput output, DecompilationOptions options) + { + language.WriteCommentLine(output, Text.ToString()); + language.WriteCommentLine(output, $"AlgorithmName: {entry.AlgorithmName}"); + language.WriteCommentLine(output, $"Checksum: {entry.Checksum.ToHexString(entry.Checksum.Length)}"); + } + } +} diff --git a/ILSpy/Metadata/DebugDirectoryTreeNode.cs b/ILSpy/Metadata/DebugDirectoryTreeNode.cs index 9db16a628..78e3704c1 100644 --- a/ILSpy/Metadata/DebugDirectoryTreeNode.cs +++ b/ILSpy/Metadata/DebugDirectoryTreeNode.cs @@ -16,6 +16,8 @@ // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. +#nullable enable + using System; using System.Collections.Generic; using System.Reflection.PortableExecutable; @@ -36,6 +38,7 @@ namespace ICSharpCode.ILSpy.Metadata public DebugDirectoryTreeNode(PEFile module) { this.module = module; + this.LazyLoading = true; } public override object Text => "Debug Directory"; @@ -51,7 +54,10 @@ namespace ICSharpCode.ILSpy.Metadata var entries = new List(); foreach (var entry in module.Reader.ReadDebugDirectory()) { - entries.Add(new DebugDirectoryEntryView(entry)); + int dataOffset = module.Reader.IsLoadedImage ? entry.DataRelativeVirtualAddress : entry.DataPointer; + var data = module.Reader.GetEntireImage().GetContent(dataOffset, entry.DataSize); + + entries.Add(new DebugDirectoryEntryView(entry, data.ToHexString(data.Length))); } dataGrid.ItemsSource = entries.ToArray(); @@ -60,6 +66,37 @@ namespace ICSharpCode.ILSpy.Metadata return true; } + protected override void LoadChildren() + { + foreach (var entry in module.Reader.ReadDebugDirectory()) + { + switch (entry.Type) + { + case DebugDirectoryEntryType.CodeView: + var codeViewData = module.Reader.ReadCodeViewDebugDirectoryData(entry); + this.Children.Add(new CodeViewTreeNode(codeViewData)); + break; + + case DebugDirectoryEntryType.EmbeddedPortablePdb: + var embeddedPortablePdbReader = module.Reader.ReadEmbeddedPortablePdbDebugDirectoryData(entry).GetMetadataReader(); + this.Children.Add(new DebugMetadataTreeNode(module, isEmbedded: true, provider: embeddedPortablePdbReader)); + break; + + case DebugDirectoryEntryType.PdbChecksum: + var pdbChecksumData = module.Reader.ReadPdbChecksumDebugDirectoryData(entry); + this.Children.Add(new PdbChecksumTreeNode(pdbChecksumData)); + break; + + case DebugDirectoryEntryType.Unknown: + case DebugDirectoryEntryType.Coff: + case DebugDirectoryEntryType.Reproducible: + default: + this.Children.Add(new DebugDirectoryEntryTreeNode(module, entry)); + break; + } + } + } + public override void Decompile(Language language, ITextOutput output, DecompilationOptions options) { language.WriteCommentLine(output, "Data Directories"); @@ -67,7 +104,6 @@ namespace ICSharpCode.ILSpy.Metadata class DebugDirectoryEntryView { - public int Characteristics { get; set; } public uint Timestamp { get; set; } public ushort MajorVersion { get; set; } public ushort MinorVersion { get; set; } @@ -75,10 +111,11 @@ namespace ICSharpCode.ILSpy.Metadata public int SizeOfRawData { get; set; } public int AddressOfRawData { get; set; } public int PointerToRawData { get; set; } + public string RawData { get; set; } - public DebugDirectoryEntryView(DebugDirectoryEntry entry) + public DebugDirectoryEntryView(DebugDirectoryEntry entry, string data) { - this.Characteristics = 0; + this.RawData = data; this.Timestamp = entry.Stamp; this.MajorVersion = entry.MajorVersion; this.MinorVersion = entry.MinorVersion; diff --git a/ILSpy/Metadata/DebugMetadataTreeNode.cs b/ILSpy/Metadata/DebugMetadataTreeNode.cs index c0edc0d02..cd140aa57 100644 --- a/ILSpy/Metadata/DebugMetadataTreeNode.cs +++ b/ILSpy/Metadata/DebugMetadataTreeNode.cs @@ -32,14 +32,12 @@ namespace ICSharpCode.ILSpy.Metadata { private PEFile module; private MetadataReader provider; - private AssemblyTreeNode assemblyTreeNode; private bool isEmbedded; - public DebugMetadataTreeNode(PEFile module, bool isEmbedded, MetadataReader provider, AssemblyTreeNode assemblyTreeNode) + public DebugMetadataTreeNode(PEFile module, bool isEmbedded, MetadataReader provider) { this.module = module; this.provider = provider; - this.assemblyTreeNode = assemblyTreeNode; this.isEmbedded = isEmbedded; this.Text = "Debug Metadata (" + (isEmbedded ? "Embedded" : "From portable PDB") + ")"; this.LazyLoading = true; diff --git a/ILSpy/TreeNodes/AssemblyTreeNode.cs b/ILSpy/TreeNodes/AssemblyTreeNode.cs index 38be04a72..19b6b633a 100644 --- a/ILSpy/TreeNodes/AssemblyTreeNode.cs +++ b/ILSpy/TreeNodes/AssemblyTreeNode.cs @@ -210,7 +210,7 @@ namespace ICSharpCode.ILSpy.TreeNodes if (debugInfo is PortableDebugInfoProvider ppdb && ppdb.GetMetadataReader() is System.Reflection.Metadata.MetadataReader reader) { - this.Children.Add(new Metadata.DebugMetadataTreeNode(module, ppdb.IsEmbedded, reader, this)); + this.Children.Add(new Metadata.DebugMetadataTreeNode(module, ppdb.IsEmbedded, reader)); } this.Children.Add(new ReferenceFolderTreeNode(module, this)); if (module.Resources.Any())