From 924e7a0ec4d7c1baecd3017401fe2f89b2611b3d Mon Sep 17 00:00:00 2001 From: Siegfried Pammer Date: Sat, 14 Nov 2020 21:12:51 +0100 Subject: [PATCH] Fix "Select PDB" command when working with bundles. --- .../MonoCecilDebugInfoProvider.cs | 3 ++ .../DebugInfo/IDebugInfoProvider.cs | 1 + ILSpy/AssemblyList.cs | 3 +- ILSpy/Commands/SelectPdbContextMenuEntry.cs | 3 +- ILSpy/DebugInfo/DebugInfoUtils.cs | 18 ++++++---- ILSpy/DebugInfo/PortableDebugInfoProvider.cs | 15 +++++--- ILSpy/LoadedAssembly.cs | 35 ++++++++++++++----- ILSpy/TreeNodes/AssemblyTreeNode.cs | 2 +- 8 files changed, 57 insertions(+), 23 deletions(-) diff --git a/ICSharpCode.Decompiler.PdbProvider.Cecil/MonoCecilDebugInfoProvider.cs b/ICSharpCode.Decompiler.PdbProvider.Cecil/MonoCecilDebugInfoProvider.cs index b0d53022d..0ca165e06 100644 --- a/ICSharpCode.Decompiler.PdbProvider.Cecil/MonoCecilDebugInfoProvider.cs +++ b/ICSharpCode.Decompiler.PdbProvider.Cecil/MonoCecilDebugInfoProvider.cs @@ -50,6 +50,7 @@ namespace ICSharpCode.Decompiler.PdbProvider } this.Description = description ?? $"Loaded from PDB file: {pdbFileName}"; + this.SourceFileName = pdbFileName; var image = module.Reader.GetEntireImage(); this.debugInfo = new Dictionary SequencePoints, IList Variables)>(); @@ -97,6 +98,8 @@ namespace ICSharpCode.Decompiler.PdbProvider public string Description { get; } + public string SourceFileName { get; } + public IList GetSequencePoints(SRM.MethodDefinitionHandle handle) { if (!debugInfo.TryGetValue(handle, out var info)) diff --git a/ICSharpCode.Decompiler/DebugInfo/IDebugInfoProvider.cs b/ICSharpCode.Decompiler/DebugInfo/IDebugInfoProvider.cs index cf2221009..5c148df25 100644 --- a/ICSharpCode.Decompiler/DebugInfo/IDebugInfoProvider.cs +++ b/ICSharpCode.Decompiler/DebugInfo/IDebugInfoProvider.cs @@ -23,5 +23,6 @@ namespace ICSharpCode.Decompiler.DebugInfo IList GetSequencePoints(MethodDefinitionHandle method); IList GetVariables(MethodDefinitionHandle method); bool TryGetName(MethodDefinitionHandle method, int index, out string name); + string SourceFileName { get; } } } diff --git a/ILSpy/AssemblyList.cs b/ILSpy/AssemblyList.cs index f1e9cd9e2..35420146c 100644 --- a/ILSpy/AssemblyList.cs +++ b/ILSpy/AssemblyList.cs @@ -252,9 +252,8 @@ namespace ICSharpCode.ILSpy public LoadedAssembly ReloadAssembly(LoadedAssembly target) { var index = this.assemblies.IndexOf(target); - var newAsm = new LoadedAssembly(this, target.FileName); + var newAsm = new LoadedAssembly(this, target.FileName, pdbFileName: target.PdbFileName); newAsm.IsAutoLoaded = target.IsAutoLoaded; - newAsm.PdbFileOverride = target.PdbFileOverride; lock (assemblies) { this.assemblies.Remove(target); diff --git a/ILSpy/Commands/SelectPdbContextMenuEntry.cs b/ILSpy/Commands/SelectPdbContextMenuEntry.cs index 7f90c6566..38c5d970a 100644 --- a/ILSpy/Commands/SelectPdbContextMenuEntry.cs +++ b/ILSpy/Commands/SelectPdbContextMenuEntry.cs @@ -43,8 +43,7 @@ namespace ICSharpCode.ILSpy using (context.TreeView.LockUpdates()) { - assembly.PdbFileOverride = dlg.FileName; - assembly.AssemblyList.ReloadAssembly(assembly); + assembly.LoadDebugInfo(dlg.FileName); } MainWindow.Instance.SelectNode(MainWindow.Instance.FindNodeByPath(new[] { assembly.FileName }, true)); diff --git a/ILSpy/DebugInfo/DebugInfoUtils.cs b/ILSpy/DebugInfo/DebugInfoUtils.cs index fff7ed5c3..cd3f9b596 100644 --- a/ILSpy/DebugInfo/DebugInfoUtils.cs +++ b/ILSpy/DebugInfo/DebugInfoUtils.cs @@ -37,12 +37,15 @@ namespace ICSharpCode.Decompiler.PdbProvider // try to open portable pdb file/embedded pdb info: if (TryOpenPortablePdb(module, out var provider, out var pdbFileName)) { - return new PortableDebugInfoProvider(pdbFileName, provider); + return new PortableDebugInfoProvider(pdbFileName, provider, module.FileName); } else { // search for pdb in same directory as dll - pdbFileName = Path.Combine(Path.GetDirectoryName(module.FileName), Path.GetFileNameWithoutExtension(module.FileName) + ".pdb"); + pdbFileName = Path.Combine( + Path.GetDirectoryName(module.FileName), + Path.GetFileNameWithoutExtension(module.FileName) + ".pdb" + ); if (File.Exists(pdbFileName)) { return new MonoCecilDebugInfoProvider(module, pdbFileName); @@ -75,14 +78,15 @@ namespace ICSharpCode.Decompiler.PdbProvider { stream.Position = 0; var provider = MetadataReaderProvider.FromPortablePdbStream(stream); - return new PortableDebugInfoProvider(pdbFileName, provider); + return new PortableDebugInfoProvider(pdbFileName, provider, module.FileName); } } const string LegacyPDBPrefix = "Microsoft C/C++ MSF 7.00"; static readonly byte[] buffer = new byte[LegacyPDBPrefix.Length]; - static bool TryOpenPortablePdb(PEFile module, out MetadataReaderProvider provider, out string pdbFileName) + static bool TryOpenPortablePdb(PEFile module, + out MetadataReaderProvider provider, out string pdbFileName) { provider = null; pdbFileName = null; @@ -91,12 +95,14 @@ namespace ICSharpCode.Decompiler.PdbProvider { if (entry.IsPortableCodeView) { - return reader.TryOpenAssociatedPortablePdb(module.FileName, OpenStream, out provider, out pdbFileName); + return reader.TryOpenAssociatedPortablePdb(module.FileName, OpenStream, + out provider, out pdbFileName); } if (entry.Type == DebugDirectoryEntryType.CodeView) { string pdbDirectory = Path.GetDirectoryName(module.FileName); - pdbFileName = Path.Combine(pdbDirectory, Path.GetFileNameWithoutExtension(module.FileName) + ".pdb"); + pdbFileName = Path.Combine( + pdbDirectory, Path.GetFileNameWithoutExtension(module.FileName) + ".pdb"); if (File.Exists(pdbFileName)) { Stream stream = OpenStream(pdbFileName); diff --git a/ILSpy/DebugInfo/PortableDebugInfoProvider.cs b/ILSpy/DebugInfo/PortableDebugInfoProvider.cs index 58a1ca125..e57e81eae 100644 --- a/ILSpy/DebugInfo/PortableDebugInfoProvider.cs +++ b/ILSpy/DebugInfo/PortableDebugInfoProvider.cs @@ -27,20 +27,27 @@ namespace ICSharpCode.Decompiler.PdbProvider class PortableDebugInfoProvider : IDebugInfoProvider { string pdbFileName; + string moduleFileName; internal MetadataReaderProvider Provider { get; } internal bool IsEmbedded => pdbFileName == null; - public PortableDebugInfoProvider(string pdbFileName, MetadataReaderProvider provider) + public PortableDebugInfoProvider(string pdbFileName, MetadataReaderProvider provider, + string moduleFileName) { this.pdbFileName = pdbFileName; - this.Provider = provider; + this.moduleFileName = moduleFileName; + this.Provider = provider ?? throw new ArgumentNullException(nameof(provider)); } - public string Description => pdbFileName == null ? "Embedded in this assembly" : $"Loaded from portable PDB: {pdbFileName}"; + public string Description => pdbFileName == null + ? "Embedded in this assembly" + : $"Loaded from portable PDB: {pdbFileName}"; - public IList GetSequencePoints(MethodDefinitionHandle method) + public string SourceFileName => pdbFileName ?? moduleFileName; + + public IList GetSequencePoints(MethodDefinitionHandle method) { var metadata = Provider.GetMetadataReader(); var debugInfo = metadata.GetMethodDebugInformation(method); diff --git a/ILSpy/LoadedAssembly.cs b/ILSpy/LoadedAssembly.cs index 4fdcb2975..35296686a 100644 --- a/ILSpy/LoadedAssembly.cs +++ b/ILSpy/LoadedAssembly.cs @@ -85,10 +85,12 @@ namespace ICSharpCode.ILSpy public LoadedAssembly ParentBundle { get; } - public LoadedAssembly(AssemblyList assemblyList, string fileName, Task stream = null, IAssemblyResolver assemblyResolver = null) + public LoadedAssembly(AssemblyList assemblyList, string fileName, + Task stream = null, IAssemblyResolver assemblyResolver = null, string pdbFileName = null) { this.assemblyList = assemblyList ?? throw new ArgumentNullException(nameof(assemblyList)); this.fileName = fileName ?? throw new ArgumentNullException(nameof(fileName)); + this.PdbFileName = pdbFileName; this.providedAssemblyResolver = assemblyResolver; this.loadingTask = Task.Run(() => LoadAsync(stream)); // requires that this.fileName is set @@ -256,7 +258,10 @@ namespace ICSharpCode.ILSpy public bool IsAutoLoaded { get; set; } - public string PdbFileOverride { get; set; } + /// + /// Gets the PDB file name or null, if no PDB was found or it's embedded. + /// + public string PdbFileName { get; private set; } async Task LoadAsync(Task streamTask) { @@ -323,11 +328,21 @@ namespace ICSharpCode.ILSpy PEFile module = new PEFile(fileName, stream, streamOptions, metadataOptions: options); + debugInfoProvider = LoadDebugInfo(module); + lock (loadedAssemblies) + { + loadedAssemblies.Add(module, this); + } + return new LoadResult(module); + } + + IDebugInfoProvider LoadDebugInfo(PEFile module) + { if (DecompilerSettingsPanel.CurrentDecompilerSettings.UseDebugSymbols) { try { - debugInfoProvider = DebugInfoUtils.FromFile(module, PdbFileOverride) + return DebugInfoUtils.FromFile(module, PdbFileName) ?? DebugInfoUtils.LoadSymbols(module); } catch (IOException) @@ -341,11 +356,15 @@ namespace ICSharpCode.ILSpy // ignore any errors during symbol loading } } - lock (loadedAssemblies) - { - loadedAssemblies.Add(module, this); - } - return new LoadResult(module); + return null; + } + + public async Task LoadDebugInfo(string fileName) + { + this.PdbFileName = fileName; + var assembly = await GetPEFileAsync().ConfigureAwait(false); + debugInfoProvider = await Task.Run(() => LoadDebugInfo(assembly)); + return debugInfoProvider; } [ThreadStatic] diff --git a/ILSpy/TreeNodes/AssemblyTreeNode.cs b/ILSpy/TreeNodes/AssemblyTreeNode.cs index 1650bf20b..8dba58e8a 100644 --- a/ILSpy/TreeNodes/AssemblyTreeNode.cs +++ b/ILSpy/TreeNodes/AssemblyTreeNode.cs @@ -124,9 +124,9 @@ namespace ICSharpCode.ILSpy.TreeNodes } tooltip.Inlines.Add(new Bold(new Run("Location: "))); tooltip.Inlines.Add(new Run(LoadedAssembly.FileName)); - tooltip.Inlines.Add(new LineBreak()); if (module != null) { + tooltip.Inlines.Add(new LineBreak()); tooltip.Inlines.Add(new Bold(new Run("Architecture: "))); tooltip.Inlines.Add(new Run(Language.GetPlatformDisplayName(module))); string runtimeName = Language.GetRuntimeDisplayName(module);