Browse Source

Use Mono.Cecil instead of DiaSymReader to read classic PDB files.

pull/1274/merge
Siegfried Pammer 7 years ago
parent
commit
9e0c7ae9c8
  1. 4
      ICSharpCode.Decompiler.PdbProvider.Cecil/ICSharpCode.Decompiler.PdbProvider.Cecil.csproj
  2. 92
      ICSharpCode.Decompiler.PdbProvider.Cecil/MonoCecilDebugInfoProvider.cs
  3. 9
      ICSharpCode.Decompiler/DebugInfo/IDebugInfoProvider.cs
  4. 2
      ILSpy/DebugInfo/PortableDebugInfoProvider.cs
  5. 5
      ILSpy/ILSpy.csproj
  6. 3
      ILSpy/LoadedAssembly.cs

4
ICSharpCode.Decompiler.PdbProvider.Cecil/ICSharpCode.Decompiler.PdbProvider.Cecil.csproj

@ -1,7 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework> <TargetFramework>netstandard2.0</TargetFramework>
<LangVersion>7.2</LangVersion>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>

92
ICSharpCode.Decompiler.PdbProvider.Cecil/MonoCecilDebugInfoProvider.cs

@ -16,66 +16,106 @@
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO;
using System.Linq; using System.Linq;
using System.Reflection.Metadata.Ecma335; using System.Reflection.Metadata.Ecma335;
using ICSharpCode.Decompiler.DebugInfo; using ICSharpCode.Decompiler.DebugInfo;
using ICSharpCode.Decompiler.Metadata;
using ICSharpCode.Decompiler.Util; using ICSharpCode.Decompiler.Util;
using Mono.Cecil; using Mono.Cecil;
using Mono.Cecil.Pdb;
using SRM = System.Reflection.Metadata; using SRM = System.Reflection.Metadata;
namespace ICSharpCode.Decompiler.PdbProvider.Cecil namespace ICSharpCode.Decompiler.PdbProvider.Cecil
{ {
public class MonoCecilDebugInfoProvider : IDebugInfoProvider public class MonoCecilDebugInfoProvider : IDebugInfoProvider
{ {
readonly ModuleDefinition module; readonly Dictionary<SRM.MethodDefinitionHandle, (IList<SequencePoint> SequencePoints, IList<Variable> Variables)> debugInfo;
public MonoCecilDebugInfoProvider(ModuleDefinition module, string description = null) public unsafe MonoCecilDebugInfoProvider(PEFile module, string pdbFileName, string description = null)
{ {
this.module = module; if (module == null) {
this.Description = description ?? "none"; throw new ArgumentNullException(nameof(module));
}
if (!module.Reader.IsEntireImageAvailable) {
throw new ArgumentException("This provider needs access to the full image!");
}
this.Description = description ?? $"Loaded from PDB file: {pdbFileName}";
var image = module.Reader.GetEntireImage();
this.debugInfo = new Dictionary<SRM.MethodDefinitionHandle, (IList<SequencePoint> SequencePoints, IList<Variable> Variables)>();
using (UnmanagedMemoryStream stream = new UnmanagedMemoryStream(image.Pointer, image.Length))
using (var moduleDef = ModuleDefinition.ReadModule(stream)) {
moduleDef.ReadSymbols(new PdbReaderProvider().GetSymbolReader(moduleDef, pdbFileName));
foreach (var method in module.Metadata.MethodDefinitions) {
var cecilMethod = moduleDef.LookupToken(MetadataTokens.GetToken(method)) as MethodDefinition;
var debugInfo = cecilMethod?.DebugInformation;
if (debugInfo == null)
continue;
IList<SequencePoint> sequencePoints = EmptyList<SequencePoint>.Instance;
if (debugInfo.HasSequencePoints) {
sequencePoints = new List<SequencePoint>(debugInfo.SequencePoints.Count);
foreach (var point in debugInfo.SequencePoints) {
sequencePoints.Add(new SequencePoint {
Offset = point.Offset,
StartLine = point.StartLine,
StartColumn = point.StartColumn,
EndLine = point.EndLine,
EndColumn = point.EndColumn,
DocumentUrl = point.Document.Url
});
}
}
var variables = new List<Variable>();
foreach (var scope in debugInfo.GetScopes()) {
if (!scope.HasVariables)
continue;
foreach (var v in scope.Variables) {
variables.Add(new Variable(v.Index, v.Name));
}
}
this.debugInfo.Add(method, (sequencePoints, variables));
}
}
} }
public string Description { get; } public string Description { get; }
public IList<SequencePoint> GetSequencePoints(SRM.MethodDefinitionHandle handle) public IList<SequencePoint> GetSequencePoints(SRM.MethodDefinitionHandle handle)
{ {
var method = this.module.LookupToken(MetadataTokens.GetToken(handle)) as MethodDefinition; if (!debugInfo.TryGetValue(handle, out var info)) {
if (method?.DebugInformation == null || !method.DebugInformation.HasSequencePoints)
return EmptyList<SequencePoint>.Instance; return EmptyList<SequencePoint>.Instance;
return method.DebugInformation.SequencePoints.Select(point => new SequencePoint { }
Offset = point.Offset,
StartLine = point.StartLine, return info.SequencePoints;
StartColumn = point.StartColumn,
EndLine = point.EndLine,
EndColumn = point.EndColumn,
DocumentUrl = point.Document.Url
}).ToList();
} }
public IList<Variable> GetVariables(SRM.MethodDefinitionHandle handle) public IList<Variable> GetVariables(SRM.MethodDefinitionHandle handle)
{ {
var method = this.module.LookupToken(MetadataTokens.GetToken(handle)) as MethodDefinition; if (!debugInfo.TryGetValue(handle, out var info)) {
if (method?.DebugInformation == null)
return EmptyList<Variable>.Instance; return EmptyList<Variable>.Instance;
return method.DebugInformation.GetScopes() }
.SelectMany(s => s.Variables)
.Select(v => new Variable { Name = v.Name }).ToList(); return info.Variables;
} }
public bool TryGetName(SRM.MethodDefinitionHandle handle, int index, out string name) public bool TryGetName(SRM.MethodDefinitionHandle handle, int index, out string name)
{ {
var method = this.module.LookupToken(MetadataTokens.GetToken(handle)) as MethodDefinition;
name = null; name = null;
if (method?.DebugInformation == null || !method.HasBody) if (!debugInfo.TryGetValue(handle, out var info)) {
return false; return false;
var variable = method.Body.Variables.FirstOrDefault(v => v.Index == index); }
if (variable == null)
return false; var variable = info.Variables.FirstOrDefault(v => v.Index == index);
return method.DebugInformation.TryGetName(variable, out name); name = variable.Name;
return name != null;
} }
} }
} }

9
ICSharpCode.Decompiler/DebugInfo/IDebugInfoProvider.cs

@ -7,7 +7,14 @@ namespace ICSharpCode.Decompiler.DebugInfo
{ {
public struct Variable public struct Variable
{ {
public string Name { get; set; } public Variable(int index, string name)
{
Index = index;
Name = name;
}
public int Index { get; }
public string Name { get; }
} }
public interface IDebugInfoProvider public interface IDebugInfoProvider

2
ILSpy/DebugInfo/PortableDebugInfoProvider.cs

@ -75,7 +75,7 @@ namespace ICSharpCode.ILSpy.DebugInfo
var scope = metadata.GetLocalScope(h); var scope = metadata.GetLocalScope(h);
foreach (var v in scope.GetLocalVariables()) { foreach (var v in scope.GetLocalVariables()) {
var var = metadata.GetLocalVariable(v); var var = metadata.GetLocalVariable(v);
variables.Add(new Variable { Name = metadata.GetString(var.Name) }); variables.Add(new Variable(var.Index, metadata.GetString(var.Name)));
} }
} }

5
ILSpy/ILSpy.csproj

@ -50,9 +50,8 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="AvalonEdit" Version="5.0.4" /> <PackageReference Include="AvalonEdit" Version="5.0.4" />
<PackageReference Include="Microsoft.DiaSymReader.Native" Version="1.7.0" />
<PackageReference Include="Microsoft.VisualStudio.Composition" Version="15.5.23" /> <PackageReference Include="Microsoft.VisualStudio.Composition" Version="15.5.23" />
<PackageReference Include="Microsoft.DiaSymReader" Version="1.2.0" /> <PackageReference Include="Mono.Cecil" Version="0.10.0" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
@ -65,6 +64,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="..\ICSharpCode.Decompiler.PdbProvider.Cecil\MonoCecilDebugInfoProvider.cs" Link="DebugInfo\MonoCecilDebugInfoProvider.cs" />
<Compile Include="AboutPage.cs" /> <Compile Include="AboutPage.cs" />
<Compile Include="Analyzers\AnalyzerScope.cs" /> <Compile Include="Analyzers\AnalyzerScope.cs" />
<Compile Include="Analyzers\Builtin\AttributeAppliedToAnalyzer.cs" /> <Compile Include="Analyzers\Builtin\AttributeAppliedToAnalyzer.cs" />
@ -128,7 +128,6 @@
<Compile Include="CreateListDialog.xaml.cs"> <Compile Include="CreateListDialog.xaml.cs">
<DependentUpon>CreateListDialog.xaml</DependentUpon> <DependentUpon>CreateListDialog.xaml</DependentUpon>
</Compile> </Compile>
<Compile Include="DebugInfo\DiaSymNativeDebugInfoProvider.cs" />
<Compile Include="DebugInfo\PortableDebugInfoProvider.cs" /> <Compile Include="DebugInfo\PortableDebugInfoProvider.cs" />
<Compile Include="DebugSteps.xaml.cs"> <Compile Include="DebugSteps.xaml.cs">
<DependentUpon>DebugSteps.xaml</DependentUpon> <DependentUpon>DebugSteps.xaml</DependentUpon>

3
ILSpy/LoadedAssembly.cs

@ -28,6 +28,7 @@ using System.Threading.Tasks;
using ICSharpCode.Decompiler; using ICSharpCode.Decompiler;
using ICSharpCode.Decompiler.DebugInfo; using ICSharpCode.Decompiler.DebugInfo;
using ICSharpCode.Decompiler.Metadata; using ICSharpCode.Decompiler.Metadata;
using ICSharpCode.Decompiler.PdbProvider.Cecil;
using ICSharpCode.Decompiler.TypeSystem; using ICSharpCode.Decompiler.TypeSystem;
using ICSharpCode.Decompiler.TypeSystem.Implementation; using ICSharpCode.Decompiler.TypeSystem.Implementation;
using ICSharpCode.ILSpy.DebugInfo; using ICSharpCode.ILSpy.DebugInfo;
@ -187,7 +188,7 @@ namespace ICSharpCode.ILSpy
string pdbDirectory = Path.GetDirectoryName(fileName); string pdbDirectory = Path.GetDirectoryName(fileName);
pdbFileName = Path.Combine(pdbDirectory, Path.GetFileNameWithoutExtension(fileName) + ".pdb"); pdbFileName = Path.Combine(pdbDirectory, Path.GetFileNameWithoutExtension(fileName) + ".pdb");
if (File.Exists(pdbFileName)) { if (File.Exists(pdbFileName)) {
debugInfoProvider = new DiaSymNativeDebugInfoProvider(module, pdbFileName, OpenStream(pdbFileName)); debugInfoProvider = new MonoCecilDebugInfoProvider(module, pdbFileName);
return; return;
} }

Loading…
Cancel
Save