Cosmos/source/Cosmos.Debug.Symbols/DebugSymbolReader.cs
2017-03-19 09:29:46 -05:00

353 lines
13 KiB
C#

using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Reflection.Metadata;
using System.Reflection.Metadata.Ecma335;
using System.Reflection.PortableExecutable;
namespace Cosmos.Debug.Symbols
{
internal static class MetadataHelper
{
private static readonly Dictionary<string, MetadataReaderProvider> mMetadataCache;
static MetadataHelper()
{
mMetadataCache = new Dictionary<string, MetadataReaderProvider>();
}
public static MetadataReader TryGetReader(string aAssemblyPath)
{
MetadataReaderProvider provider;
if (mMetadataCache.TryGetValue(aAssemblyPath, out provider))
{
return provider.GetMetadataReader();
}
provider = TryOpenReaderFromAssemblyFile(aAssemblyPath);
if (provider == null)
{
return null;
}
mMetadataCache.Add(aAssemblyPath, provider);
// The reader has already been open, so this doesn't throw:
return provider.GetMetadataReader();
}
public static Type GetTypeFromReference(MetadataReader reader, Module aModule, TypeReferenceHandle handle, byte rawTypeKind)
{
int xToken = MetadataTokens.GetToken(handle);
return aModule.ResolveType(xToken, null, null);
}
private static PEReader TryGetPEReader(string aAssemblyPath)
{
var peStream = TryOpenFile(aAssemblyPath);
if (peStream != null)
{
return new PEReader(peStream);
}
return null;
}
private static MetadataReaderProvider TryOpenReaderFromAssemblyFile(string aAssemblyPath)
{
using (var peReader = TryGetPEReader(aAssemblyPath))
{
if (peReader == null)
{
return null;
}
string pdbPath;
MetadataReaderProvider provider;
if (peReader.TryOpenAssociatedPortablePdb(aAssemblyPath, TryOpenFile, out provider, out pdbPath))
{
return provider;
}
}
return null;
}
private static Stream TryOpenFile(string aPath)
{
if (!File.Exists(aPath))
{
return null;
}
try
{
return File.OpenRead(aPath);
}
catch
{
return null;
}
}
}
public class DebugSymbolReader
{
private static string mCurrentFile;
private static DebugSymbolReader mCurrentDebugSymbolReader;
private readonly PEReader mPEReader;
private readonly MetadataReader mMetadataReader;
private DebugSymbolReader(string aFilePath)
{
mPEReader = new PEReader(File.OpenRead(aFilePath), PEStreamOptions.PrefetchEntireImage);
mMetadataReader = mPEReader.GetMetadataReader();
}
internal static DebugSymbolReader GetReader(string aFilePath)
{
if (File.Exists(aFilePath))
{
if (mCurrentDebugSymbolReader != null && mCurrentFile == aFilePath)
{
return mCurrentDebugSymbolReader;
}
mCurrentDebugSymbolReader = new DebugSymbolReader(aFilePath);
if (mCurrentDebugSymbolReader.mPEReader.HasMetadata)
{
mCurrentFile = aFilePath;
return mCurrentDebugSymbolReader;
}
}
return null;
}
public static DebugInfo.SequencePoint[] GetSequencePoints(string aAssemblyPath, int aMetadataToken)
{
var xSequencePoints = new List<DebugInfo.SequencePoint>();
try
{
var xReader = MetadataHelper.TryGetReader(aAssemblyPath);
if (xReader == null)
{
return xSequencePoints.ToArray();
}
var xMethodDebugInfoHandle = MetadataTokens.MethodDebugInformationHandle(aMetadataToken);
if (!xMethodDebugInfoHandle.IsNil)
{
var xDebugInfo = xReader.GetMethodDebugInformation(xMethodDebugInfoHandle);
var xDebugInfoSequencePoints = xDebugInfo.GetSequencePoints();
foreach (var xSequencePoint in xDebugInfoSequencePoints)
{
string xDocumentName = string.Empty;
if (!xSequencePoint.Document.IsNil)
{
var xDocument = xReader.GetDocument(xSequencePoint.Document);
if (!xDocument.Name.IsNil)
{
xDocumentName = xReader.GetString(xDocument.Name);
}
}
xSequencePoints.Add(new DebugInfo.SequencePoint
{
Document = xDocumentName,
ColStart = xSequencePoint.StartColumn,
ColEnd = xSequencePoint.EndColumn,
LineStart = xSequencePoint.StartLine,
LineEnd = xSequencePoint.EndLine,
Offset = xSequencePoint.Offset
});
}
}
}
catch(Exception ex)
{
}
return xSequencePoints.ToArray();
}
public static MethodBodyBlock GetMethodBodyBlock(Module aModule, int aMetadataToken)
{
var xMethodDefHandle = MetadataTokens.MethodDefinitionHandle(aMetadataToken);
if (!xMethodDefHandle.IsNil)
{
string xLocation = aModule.Assembly.Location;
var xReader = GetReader(xLocation);
var xMethodDefinition = xReader.mMetadataReader.GetMethodDefinition(xMethodDefHandle);
if (xMethodDefinition.RelativeVirtualAddress > 0)
{
int xRelativeVirtualAddress = xMethodDefinition.RelativeVirtualAddress;
return xReader.mPEReader.GetMethodBody(xRelativeVirtualAddress);
}
}
return null;
}
public static IList<Type> GetLocalVariableInfos(MethodBase aMethodBase)
{
var xLocalVariables = new List<Type>();
string xLocation = aMethodBase.Module.Assembly.Location;
var xGenericMethodParameters = new Type[0];
var xGenericTypeParameters = new Type[0];
if (aMethodBase.IsGenericMethod)
{
xGenericMethodParameters = aMethodBase.GetGenericArguments();
}
if (aMethodBase.DeclaringType.GetTypeInfo().IsGenericType)
{
xGenericTypeParameters = aMethodBase.DeclaringType.GetTypeInfo().GetGenericArguments();
}
// TODO: Read from pdb.
//var xReader = MetadataHelper.TryGetReader(xLocation);
//if (xReader != null)
//{
// xLocalVariables = ResolveLocalsFromPdb(xReader, aMethodBase, xGenericTypeParameters, xGenericMethodParameters).ToList();
//}
//else
//{
var xReader = GetReader(xLocation).mMetadataReader;
xLocalVariables = ResolveLocalsFromSignature(xReader, aMethodBase, xGenericTypeParameters, xGenericMethodParameters).ToList();
//}
//var xLocals = aMethodBase.GetMethodBody().LocalVariables;
//foreach (var xLocal in xLocals)
//{
// xLocalVariables.Add(xLocal.LocalType);
//}
return xLocalVariables;
}
private static IList<Type> ResolveLocalsFromPdb(MetadataReader aReader, MethodBase aMethodBase, Type[] aGenericTypeParameters, Type[] aGenericMethodParameters)
{
var xLocalVariables = new List<Type>();
// TODO
return xLocalVariables;
}
private static IList<Type> ResolveLocalsFromSignature(MetadataReader aReader, MethodBase aMethodBase, Type[] aGenericTypeParameters, Type[] aGenericMethodParameters)
{
var xLocalVariables = new List<Type>();
var xMethodBody = GetMethodBodyBlock(aMethodBase.Module, aMethodBase.MetadataToken);
if (xMethodBody != null && !xMethodBody.LocalSignature.IsNil)
{
var xSig = aReader.GetStandaloneSignature(xMethodBody.LocalSignature);
var xLocals = xSig.DecodeLocalSignature(new LocalTypeProvider(aMethodBase.Module), new LocalTypeGenericContext(aGenericTypeParameters.ToImmutableArray(), aGenericMethodParameters.ToImmutableArray()));
foreach (var xLocal in xLocals)
{
xLocalVariables.Add(xLocal);
}
}
return xLocalVariables;
}
public static Type GetCatchType(Module aModule, ExceptionRegion aRegion)
{
string xLocation = aModule.Assembly.Location;
var xReader = MetadataHelper.TryGetReader(xLocation);
switch (aRegion.CatchType.Kind)
{
case HandleKind.TypeReference:
return MetadataHelper.GetTypeFromReference(xReader, aModule, (TypeReferenceHandle) aRegion.CatchType, 0);
break;
case HandleKind.TypeDefinition:
break;
case HandleKind.FieldDefinition:
break;
case HandleKind.MethodDefinition:
break;
case HandleKind.Parameter:
break;
case HandleKind.InterfaceImplementation:
break;
case HandleKind.MemberReference:
break;
case HandleKind.Constant:
break;
case HandleKind.CustomAttribute:
break;
case HandleKind.DeclarativeSecurityAttribute:
break;
case HandleKind.StandaloneSignature:
break;
case HandleKind.EventDefinition:
break;
case HandleKind.PropertyDefinition:
break;
case HandleKind.MethodImplementation:
break;
case HandleKind.ModuleReference:
break;
case HandleKind.TypeSpecification:
break;
case HandleKind.AssemblyDefinition:
break;
case HandleKind.AssemblyFile:
break;
case HandleKind.AssemblyReference:
break;
case HandleKind.ExportedType:
break;
case HandleKind.GenericParameter:
break;
case HandleKind.MethodSpecification:
break;
case HandleKind.GenericParameterConstraint:
break;
case HandleKind.MethodDebugInformation:
break;
case HandleKind.CustomDebugInformation:
break;
default:
throw new ArgumentOutOfRangeException();
}
throw new NotImplementedException();
}
public static bool TryGetStaticFieldValue(Module aModule, int aMetadataToken, ref byte[] aBuffer)
{
var xAssemblyPath = aModule.Assembly.Location;
var xMetadataReader = GetReader(xAssemblyPath).mMetadataReader;
var xPEReader = GetReader(xAssemblyPath).mPEReader;
var xHandle = (FieldDefinitionHandle)MetadataTokens.Handle(aMetadataToken);
if (!xHandle.IsNil)
{
var xFieldDefinition = xMetadataReader.GetFieldDefinition(xHandle);
var xRVA = xFieldDefinition.GetRelativeVirtualAddress();
if (xFieldDefinition.Attributes.HasFlag(FieldAttributes.HasFieldRVA))
{
var xBytes = xPEReader.GetSectionData(xRVA).GetContent();
for (int i = 0; i < aBuffer.Length; i++)
{
aBuffer[i] = xBytes[i];
}
}
}
return false;
}
}
}