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. 39
      ILSpy/LoadedAssembly.cs

8
ICSharpCode.Decompiler/DebugInfo/PortablePdbWriter.cs

@ -6,6 +6,7 @@ using System.IO; @@ -6,6 +6,7 @@ using System.IO;
using System.Linq;
using System.Reflection.Metadata;
using System.Reflection.Metadata.Ecma335;
using System.Reflection.PortableExecutable;
using System.Security.Cryptography;
using System.Text;
using ICSharpCode.Decompiler.CSharp;
@ -29,6 +30,10 @@ namespace ICSharpCode.Decompiler.DebugInfo @@ -29,6 +30,10 @@ namespace ICSharpCode.Decompiler.DebugInfo
public 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)
{
return file.Reader.ReadDebugDirectory().Any(entry => entry.Type == DebugDirectoryEntryType.CodeView);
}
public static void WritePdb(PEFile file, CSharpDecompiler decompiler, DecompilerSettings settings, Stream targetStream)
{
@ -101,7 +106,8 @@ namespace ICSharpCode.Decompiler.DebugInfo @@ -101,7 +106,8 @@ namespace ICSharpCode.Decompiler.DebugInfo
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 contentId = new BlobContentId(portable.Guid, debugDir.Stamp);
PortablePdbBuilder serializer = new PortablePdbBuilder(metadata, GetRowCounts(reader), entrypointHandle, blobs => contentId);

7
ILSpy/Commands/GeneratePdbContextMenuEntry.cs

@ -21,6 +21,7 @@ using System.Diagnostics; @@ -21,6 +21,7 @@ using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;
using ICSharpCode.Decompiler;
using ICSharpCode.Decompiler.CSharp;
using ICSharpCode.Decompiler.DebugInfo;
@ -51,6 +52,11 @@ namespace ICSharpCode.ILSpy @@ -51,6 +52,11 @@ namespace ICSharpCode.ILSpy
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();
dlg.FileName = DecompilerTextView.CleanUpName(assembly.ShortName) + ".pdb";
dlg.Filter = "Portable PDB|*.pdb|All files|*.*";
@ -62,7 +68,6 @@ namespace ICSharpCode.ILSpy @@ -62,7 +68,6 @@ namespace ICSharpCode.ILSpy
Stopwatch stopwatch = Stopwatch.StartNew();
using (FileStream stream = new FileStream(fileName, FileMode.OpenOrCreate, FileAccess.Write)) {
try {
var file = assembly.GetPEFileOrNull();
var decompiler = new CSharpDecompiler(file, assembly.GetAssemblyResolver(), options.DecompilerSettings);
PortablePdbWriter.WritePdb(file, decompiler, options.DecompilerSettings, stream);
} catch (OperationCanceledException) {

39
ILSpy/LoadedAssembly.cs

@ -22,6 +22,7 @@ using System.IO; @@ -22,6 +22,7 @@ using System.IO;
using System.Reflection.Metadata;
using System.Reflection.PortableExecutable;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
using ICSharpCode.Decompiler;
@ -174,12 +175,12 @@ namespace ICSharpCode.ILSpy @@ -174,12 +175,12 @@ namespace ICSharpCode.ILSpy
return module;
}
private void LoadSymbols(PEFile module)
void LoadSymbols(PEFile module)
{
try {
var reader = module.Reader;
// 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);
} else {
// search for pdb in same directory as dll
@ -192,9 +193,40 @@ namespace ICSharpCode.ILSpy @@ -192,9 +193,40 @@ namespace ICSharpCode.ILSpy
// TODO: use symbol cache, get symbols from microsoft
}
} catch (BadImageFormatException) {
} catch (Exception ex) when (ex is BadImageFormatException || ex is COMException) {
// Ignore PDB load errors
}
}
const string LegacyPDBPrefix = "Microsoft C/C++ MSF 7.00";
byte[] buffer = new byte[LegacyPDBPrefix.Length];
bool TryOpenPortablePdb(PEFile module, out MetadataReaderProvider provider, out string pdbFileName)
{
provider = null;
pdbFileName = null;
var reader = module.Reader;
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)
{
@ -206,7 +238,6 @@ namespace ICSharpCode.ILSpy @@ -206,7 +238,6 @@ namespace ICSharpCode.ILSpy
memory.Position = 0;
return memory;
}
}
[ThreadStatic]
static int assemblyLoadDisableCount;

Loading…
Cancel
Save