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

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

@ -16,66 +16,106 @@ @@ -16,66 +16,106 @@
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection.Metadata.Ecma335;
using ICSharpCode.Decompiler.DebugInfo;
using ICSharpCode.Decompiler.Metadata;
using ICSharpCode.Decompiler.Util;
using Mono.Cecil;
using Mono.Cecil.Pdb;
using SRM = System.Reflection.Metadata;
namespace ICSharpCode.Decompiler.PdbProvider.Cecil
{
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;
this.Description = description ?? "none";
if (module == null) {
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 IList<SequencePoint> GetSequencePoints(SRM.MethodDefinitionHandle handle)
{
var method = this.module.LookupToken(MetadataTokens.GetToken(handle)) as MethodDefinition;
if (method?.DebugInformation == null || !method.DebugInformation.HasSequencePoints)
if (!debugInfo.TryGetValue(handle, out var info)) {
return EmptyList<SequencePoint>.Instance;
return method.DebugInformation.SequencePoints.Select(point => new SequencePoint {
Offset = point.Offset,
StartLine = point.StartLine,
StartColumn = point.StartColumn,
EndLine = point.EndLine,
EndColumn = point.EndColumn,
DocumentUrl = point.Document.Url
}).ToList();
}
return info.SequencePoints;
}
public IList<Variable> GetVariables(SRM.MethodDefinitionHandle handle)
{
var method = this.module.LookupToken(MetadataTokens.GetToken(handle)) as MethodDefinition;
if (method?.DebugInformation == null)
if (!debugInfo.TryGetValue(handle, out var info)) {
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)
{
var method = this.module.LookupToken(MetadataTokens.GetToken(handle)) as MethodDefinition;
name = null;
if (method?.DebugInformation == null || !method.HasBody)
if (!debugInfo.TryGetValue(handle, out var info)) {
return false;
var variable = method.Body.Variables.FirstOrDefault(v => v.Index == index);
if (variable == null)
return false;
return method.DebugInformation.TryGetName(variable, out name);
}
var variable = info.Variables.FirstOrDefault(v => v.Index == index);
name = variable.Name;
return name != null;
}
}
}

9
ICSharpCode.Decompiler/DebugInfo/IDebugInfoProvider.cs

@ -7,7 +7,14 @@ namespace ICSharpCode.Decompiler.DebugInfo @@ -7,7 +7,14 @@ namespace ICSharpCode.Decompiler.DebugInfo
{
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

2
ILSpy/DebugInfo/PortableDebugInfoProvider.cs

@ -75,7 +75,7 @@ namespace ICSharpCode.ILSpy.DebugInfo @@ -75,7 +75,7 @@ namespace ICSharpCode.ILSpy.DebugInfo
var scope = metadata.GetLocalScope(h);
foreach (var v in scope.GetLocalVariables()) {
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 @@ @@ -50,9 +50,8 @@
<ItemGroup>
<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.DiaSymReader" Version="1.2.0" />
<PackageReference Include="Mono.Cecil" Version="0.10.0" />
</ItemGroup>
<ItemGroup>
@ -65,6 +64,7 @@ @@ -65,6 +64,7 @@
</ItemGroup>
<ItemGroup>
<Compile Include="..\ICSharpCode.Decompiler.PdbProvider.Cecil\MonoCecilDebugInfoProvider.cs" Link="DebugInfo\MonoCecilDebugInfoProvider.cs" />
<Compile Include="AboutPage.cs" />
<Compile Include="Analyzers\AnalyzerScope.cs" />
<Compile Include="Analyzers\Builtin\AttributeAppliedToAnalyzer.cs" />
@ -128,7 +128,6 @@ @@ -128,7 +128,6 @@
<Compile Include="CreateListDialog.xaml.cs">
<DependentUpon>CreateListDialog.xaml</DependentUpon>
</Compile>
<Compile Include="DebugInfo\DiaSymNativeDebugInfoProvider.cs" />
<Compile Include="DebugInfo\PortableDebugInfoProvider.cs" />
<Compile Include="DebugSteps.xaml.cs">
<DependentUpon>DebugSteps.xaml</DependentUpon>

3
ILSpy/LoadedAssembly.cs

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

Loading…
Cancel
Save