Browse Source

#1024: Make PDB Support in ILSpy more robust.

pull/1420/head
Siegfried Pammer 7 years ago
parent
commit
d5b495329f
  1. 8
      ICSharpCode.Decompiler/DebugInfo/PortablePdbWriter.cs
  2. 7
      ILSpy/Commands/GeneratePdbContextMenuEntry.cs
  3. 55
      ILSpy/LoadedAssembly.cs

8
ICSharpCode.Decompiler/DebugInfo/PortablePdbWriter.cs

@ -6,6 +6,7 @@ using System.IO;
using System.Linq; using System.Linq;
using System.Reflection.Metadata; using System.Reflection.Metadata;
using System.Reflection.Metadata.Ecma335; using System.Reflection.Metadata.Ecma335;
using System.Reflection.PortableExecutable;
using System.Security.Cryptography; using System.Security.Cryptography;
using System.Text; using System.Text;
using ICSharpCode.Decompiler.CSharp; using ICSharpCode.Decompiler.CSharp;
@ -29,6 +30,10 @@ namespace ICSharpCode.Decompiler.DebugInfo
public static readonly Guid HashAlgorithmSHA256 = new Guid("8829d00f-11b8-4213-878b-770e8597ac16"); public static readonly Guid HashAlgorithmSHA256 = new Guid("8829d00f-11b8-4213-878b-770e8597ac16");
static readonly FileVersionInfo decompilerVersion = FileVersionInfo.GetVersionInfo(typeof(CSharpDecompiler).Assembly.Location); static readonly FileVersionInfo decompilerVersion = FileVersionInfo.GetVersionInfo(typeof(CSharpDecompiler).Assembly.Location);
public static bool HasCodeViewDebugDirectoryEntry(PEFile file)
{
return file.Reader.ReadDebugDirectory().Any(entry => entry.Type == DebugDirectoryEntryType.CodeView);
}
public static void WritePdb(PEFile file, CSharpDecompiler decompiler, DecompilerSettings settings, Stream targetStream) public static void WritePdb(PEFile file, CSharpDecompiler decompiler, DecompilerSettings settings, Stream targetStream)
{ {
@ -101,7 +106,8 @@ namespace ICSharpCode.Decompiler.DebugInfo
metadata.AddImportScope(default, default); metadata.AddImportScope(default, default);
} }
} }
var debugDir = file.Reader.ReadDebugDirectory().FirstOrDefault(dir => dir.IsPortableCodeView);
var debugDir = file.Reader.ReadDebugDirectory().FirstOrDefault(dir => dir.Type == DebugDirectoryEntryType.CodeView);
var portable = file.Reader.ReadCodeViewDebugDirectoryData(debugDir); var portable = file.Reader.ReadCodeViewDebugDirectoryData(debugDir);
var contentId = new BlobContentId(portable.Guid, debugDir.Stamp); var contentId = new BlobContentId(portable.Guid, debugDir.Stamp);
PortablePdbBuilder serializer = new PortablePdbBuilder(metadata, GetRowCounts(reader), entrypointHandle, blobs => contentId); PortablePdbBuilder serializer = new PortablePdbBuilder(metadata, GetRowCounts(reader), entrypointHandle, blobs => contentId);

7
ILSpy/Commands/GeneratePdbContextMenuEntry.cs

@ -21,6 +21,7 @@ using System.Diagnostics;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Windows;
using ICSharpCode.Decompiler; using ICSharpCode.Decompiler;
using ICSharpCode.Decompiler.CSharp; using ICSharpCode.Decompiler.CSharp;
using ICSharpCode.Decompiler.DebugInfo; using ICSharpCode.Decompiler.DebugInfo;
@ -51,6 +52,11 @@ namespace ICSharpCode.ILSpy
internal static void GeneratePdbForAssembly(LoadedAssembly assembly) internal static void GeneratePdbForAssembly(LoadedAssembly assembly)
{ {
var file = assembly.GetPEFileOrNull();
if (!PortablePdbWriter.HasCodeViewDebugDirectoryEntry(file)) {
MessageBox.Show($"Cannot create PDB file for {Path.GetFileName(assembly.FileName)}, because it does not contain a PE Debug Directory Entry of type 'CodeView'.");
return;
}
SaveFileDialog dlg = new SaveFileDialog(); SaveFileDialog dlg = new SaveFileDialog();
dlg.FileName = DecompilerTextView.CleanUpName(assembly.ShortName) + ".pdb"; dlg.FileName = DecompilerTextView.CleanUpName(assembly.ShortName) + ".pdb";
dlg.Filter = "Portable PDB|*.pdb|All files|*.*"; dlg.Filter = "Portable PDB|*.pdb|All files|*.*";
@ -62,7 +68,6 @@ namespace ICSharpCode.ILSpy
Stopwatch stopwatch = Stopwatch.StartNew(); Stopwatch stopwatch = Stopwatch.StartNew();
using (FileStream stream = new FileStream(fileName, FileMode.OpenOrCreate, FileAccess.Write)) { using (FileStream stream = new FileStream(fileName, FileMode.OpenOrCreate, FileAccess.Write)) {
try { try {
var file = assembly.GetPEFileOrNull();
var decompiler = new CSharpDecompiler(file, assembly.GetAssemblyResolver(), options.DecompilerSettings); var decompiler = new CSharpDecompiler(file, assembly.GetAssemblyResolver(), options.DecompilerSettings);
PortablePdbWriter.WritePdb(file, decompiler, options.DecompilerSettings, stream); PortablePdbWriter.WritePdb(file, decompiler, options.DecompilerSettings, stream);
} catch (OperationCanceledException) { } catch (OperationCanceledException) {

55
ILSpy/LoadedAssembly.cs

@ -22,6 +22,7 @@ using System.IO;
using System.Reflection.Metadata; using System.Reflection.Metadata;
using System.Reflection.PortableExecutable; using System.Reflection.PortableExecutable;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using ICSharpCode.Decompiler; using ICSharpCode.Decompiler;
@ -174,12 +175,12 @@ namespace ICSharpCode.ILSpy
return module; return module;
} }
private void LoadSymbols(PEFile module) void LoadSymbols(PEFile module)
{ {
try { try {
var reader = module.Reader; var reader = module.Reader;
// try to open portable pdb file/embedded pdb info: // try to open portable pdb file/embedded pdb info:
if (reader.TryOpenAssociatedPortablePdb(fileName, OpenStream, out var provider, out var pdbFileName)) { if (TryOpenPortablePdb(module, out var provider, out var pdbFileName)) {
debugInfoProvider = new PortableDebugInfoProvider(pdbFileName, provider); debugInfoProvider = new PortableDebugInfoProvider(pdbFileName, provider);
} else { } else {
// search for pdb in same directory as dll // search for pdb in same directory as dll
@ -192,20 +193,50 @@ namespace ICSharpCode.ILSpy
// TODO: use symbol cache, get symbols from microsoft // TODO: use symbol cache, get symbols from microsoft
} }
} catch (BadImageFormatException) { } catch (Exception ex) when (ex is BadImageFormatException || ex is COMException) {
// Ignore PDB load errors // Ignore PDB load errors
} }
}
Stream OpenStream(string fileName) const string LegacyPDBPrefix = "Microsoft C/C++ MSF 7.00";
{ byte[] buffer = new byte[LegacyPDBPrefix.Length];
if (!File.Exists(fileName))
return null; bool TryOpenPortablePdb(PEFile module, out MetadataReaderProvider provider, out string pdbFileName)
var memory = new MemoryStream(); {
using (var stream = File.OpenRead(fileName)) provider = null;
stream.CopyTo(memory); pdbFileName = null;
memory.Position = 0; var reader = module.Reader;
return memory; foreach (var entry in reader.ReadDebugDirectory()) {
if (entry.IsPortableCodeView) {
return reader.TryOpenAssociatedPortablePdb(fileName, OpenStream, out provider, out pdbFileName);
}
if (entry.Type == DebugDirectoryEntryType.CodeView) {
string pdbDirectory = Path.GetDirectoryName(fileName);
pdbFileName = Path.Combine(pdbDirectory, Path.GetFileNameWithoutExtension(fileName) + ".pdb");
if (File.Exists(pdbFileName)) {
Stream stream = OpenStream(pdbFileName);
if (stream.Read(buffer, 0, buffer.Length) == LegacyPDBPrefix.Length
&& System.Text.Encoding.ASCII.GetString(buffer) == LegacyPDBPrefix) {
return false;
}
stream.Position = 0;
provider = MetadataReaderProvider.FromPortablePdbStream(stream);
return true;
}
}
} }
return false;
}
Stream OpenStream(string fileName)
{
if (!File.Exists(fileName))
return null;
var memory = new MemoryStream();
using (var stream = File.OpenRead(fileName))
stream.CopyTo(memory);
memory.Position = 0;
return memory;
} }
[ThreadStatic] [ThreadStatic]

Loading…
Cancel
Save