dotnet-installer/src/Microsoft.Extensions.Testing.Abstractions/PortablePdbReader.cs

87 lines
2.7 KiB
C#

// Copyright (c) .NET Foundation and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Reflection.Metadata;
using System.Runtime.InteropServices;
namespace Microsoft.Extensions.Testing.Abstractions
{
public class PortablePdbReader : IPdbReader
{
private MetadataReader _reader;
private GCHandle _gcHandle;
public PortablePdbReader(Stream pdbStream)
{
pdbStream.Position = 0;
var buffer = new byte[pdbStream.Length];
pdbStream.Read(buffer, 0, buffer.Length);
_gcHandle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
unsafe
{
var address = _gcHandle.AddrOfPinnedObject();
_reader = new MetadataReader((byte*)address.ToPointer(), buffer.Length);
}
}
public SourceInformation GetSourceInformation(MethodInfo methodInfo)
{
if (methodInfo == null)
{
return null;
}
var handle = methodInfo.GetMethodDebugInformationHandle();
return GetSourceInformation(handle);
}
private SourceInformation GetSourceInformation(MethodDebugInformationHandle handle)
{
SourceInformation sourceInformation = null;
try
{
var methodDebugDefinition = _reader.GetMethodDebugInformation(handle);
var fileName = GetMethodFileName(methodDebugDefinition);
var lineNumber = GetMethodStartLineNumber(methodDebugDefinition);
sourceInformation = new SourceInformation(fileName, lineNumber);
}
catch (BadImageFormatException)
{
}
return sourceInformation;
}
private static int GetMethodStartLineNumber(MethodDebugInformation methodDebugDefinition)
{
var sequencePoint =
methodDebugDefinition.GetSequencePoints().OrderBy(s => s.StartLine).FirstOrDefault();
var lineNumber = sequencePoint.StartLine;
return lineNumber;
}
private string GetMethodFileName(MethodDebugInformation methodDebugDefinition)
{
var fileName = string.Empty;
if (!methodDebugDefinition.Document.IsNil)
{
var document = _reader.GetDocument(methodDebugDefinition.Document);
fileName = _reader.GetString(document.Name);
}
return fileName;
}
public void Dispose()
{
_gcHandle.Free();
}
}
}