mirror of https://github.com/icsharpcode/ILSpy.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
165 lines
4.6 KiB
165 lines
4.6 KiB
// Copyright (c) 2018 Siegfried Pammer |
|
// |
|
// Permission is hereby granted, free of charge, to any person obtaining a copy of this |
|
// software and associated documentation files (the "Software"), to deal in the Software |
|
// without restriction, including without limitation the rights to use, copy, modify, merge, |
|
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons |
|
// to whom the Software is furnished to do so, subject to the following conditions: |
|
// |
|
// The above copyright notice and this permission notice shall be included in all copies or |
|
// substantial portions of the Software. |
|
// |
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, |
|
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR |
|
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE |
|
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR |
|
// 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.Diagnostics.CodeAnalysis; |
|
using System.IO; |
|
using System.Reflection.Metadata; |
|
|
|
using ICSharpCode.Decompiler.DebugInfo; |
|
using ICSharpCode.Decompiler.Util; |
|
|
|
#nullable enable |
|
|
|
namespace ICSharpCode.ILSpyX.PdbProvider |
|
{ |
|
class PortableDebugInfoProvider : IDebugInfoProvider |
|
{ |
|
string? pdbFileName; |
|
string moduleFileName; |
|
readonly MetadataReaderProvider provider; |
|
bool hasError; |
|
|
|
internal bool IsEmbedded => pdbFileName == null; |
|
|
|
public PortableDebugInfoProvider(string moduleFileName, MetadataReaderProvider provider, |
|
string? pdbFileName = null) |
|
{ |
|
this.moduleFileName = moduleFileName ?? throw new ArgumentNullException(nameof(moduleFileName)); |
|
this.provider = provider ?? throw new ArgumentNullException(nameof(provider)); |
|
this.pdbFileName = pdbFileName; |
|
} |
|
|
|
public string Description { |
|
get { |
|
if (pdbFileName == null) |
|
{ |
|
if (hasError) |
|
return "Error while loading the PDB stream embedded in this assembly"; |
|
return "Embedded in this assembly"; |
|
} |
|
else |
|
{ |
|
if (hasError) |
|
return $"Error while loading portable PDB: {pdbFileName}"; |
|
return $"Loaded from portable PDB: {pdbFileName}"; |
|
} |
|
} |
|
} |
|
|
|
internal MetadataReader? GetMetadataReader() |
|
{ |
|
try |
|
{ |
|
hasError = false; |
|
return provider.GetMetadataReader(); |
|
} |
|
catch (BadImageFormatException) |
|
{ |
|
hasError = true; |
|
return null; |
|
} |
|
catch (IOException) |
|
{ |
|
hasError = true; |
|
return null; |
|
} |
|
} |
|
|
|
public string SourceFileName => pdbFileName ?? moduleFileName; |
|
|
|
public IList<Decompiler.DebugInfo.SequencePoint> GetSequencePoints(MethodDefinitionHandle method) |
|
{ |
|
var metadata = GetMetadataReader(); |
|
if (metadata == null) |
|
return EmptyList<Decompiler.DebugInfo.SequencePoint>.Instance; |
|
var debugInfo = metadata.GetMethodDebugInformation(method); |
|
var sequencePoints = new List<Decompiler.DebugInfo.SequencePoint>(); |
|
|
|
foreach (var point in debugInfo.GetSequencePoints()) |
|
{ |
|
string documentFileName; |
|
|
|
if (!point.Document.IsNil) |
|
{ |
|
var document = metadata.GetDocument(point.Document); |
|
documentFileName = metadata.GetString(document.Name); |
|
} |
|
else |
|
{ |
|
documentFileName = ""; |
|
} |
|
|
|
sequencePoints.Add(new Decompiler.DebugInfo.SequencePoint() { |
|
Offset = point.Offset, |
|
StartLine = point.StartLine, |
|
StartColumn = point.StartColumn, |
|
EndLine = point.EndLine, |
|
EndColumn = point.EndColumn, |
|
DocumentUrl = documentFileName |
|
}); |
|
} |
|
|
|
return sequencePoints; |
|
} |
|
|
|
public IList<Variable> GetVariables(MethodDefinitionHandle method) |
|
{ |
|
var metadata = GetMetadataReader(); |
|
var variables = new List<Variable>(); |
|
if (metadata == null) |
|
return variables; |
|
|
|
foreach (var h in metadata.GetLocalScopes(method)) |
|
{ |
|
var scope = metadata.GetLocalScope(h); |
|
foreach (var v in scope.GetLocalVariables()) |
|
{ |
|
var var = metadata.GetLocalVariable(v); |
|
variables.Add(new Variable(var.Index, metadata.GetString(var.Name))); |
|
} |
|
} |
|
|
|
return variables; |
|
} |
|
|
|
public bool TryGetName(MethodDefinitionHandle method, int index, [NotNullWhen(true)] out string? name) |
|
{ |
|
var metadata = GetMetadataReader(); |
|
name = null; |
|
if (metadata == null) |
|
return false; |
|
|
|
foreach (var h in metadata.GetLocalScopes(method)) |
|
{ |
|
var scope = metadata.GetLocalScope(h); |
|
foreach (var v in scope.GetLocalVariables()) |
|
{ |
|
var var = metadata.GetLocalVariable(v); |
|
if (var.Index == index) |
|
{ |
|
name = metadata.GetString(var.Name); |
|
return true; |
|
} |
|
} |
|
} |
|
return false; |
|
} |
|
} |
|
}
|
|
|