Merge pull request #50 from jkotas/PDB

Add back PDB symbols for CppCodeGen
This commit is contained in:
Jan Kotas 2015-10-12 08:53:12 -07:00
Родитель 61c7146f87 6016a69ee5
Коммит c1586e674f
8 изменённых файлов: 350 добавлений и 53 удалений

Просмотреть файл

@ -20,11 +20,12 @@ namespace ILToNative
public struct CompilationOptions
{
public bool IsCppCodeGen;
public bool NoLineNumbers;
}
public partial class Compilation
{
readonly TypeSystemContext _typeSystemContext;
readonly CompilerTypeSystemContext _typeSystemContext;
readonly CompilationOptions _options;
Dictionary<TypeDesc, RegisteredType> _registeredTypes = new Dictionary<TypeDesc, RegisteredType>();
@ -36,7 +37,7 @@ namespace ILToNative
ILToNative.CppCodeGen.CppWriter _cppWriter = null;
public Compilation(TypeSystemContext typeSystemContext, CompilationOptions options)
public Compilation(CompilerTypeSystemContext typeSystemContext, CompilationOptions options)
{
_typeSystemContext = typeSystemContext;
_options = options;
@ -44,7 +45,7 @@ namespace ILToNative
_nameMangler = new NameMangler(this);
}
public TypeSystemContext TypeSystemContext
public CompilerTypeSystemContext TypeSystemContext
{
get
{
@ -90,6 +91,14 @@ namespace ILToNative
}
}
internal CompilationOptions Options
{
get
{
return _options;
}
}
internal IEnumerable<RegisteredType> RegisteredTypes
{
get

Просмотреть файл

@ -3,13 +3,16 @@
using System;
using System.IO;
using System.Linq;
using System.Diagnostics;
using System.Collections.Generic;
using System.Reflection.Metadata;
using System.Reflection.Metadata.Ecma335;
using System.Reflection.PortableExecutable;
using Internal.TypeSystem;
using Internal.TypeSystem.Ecma;
using Internal.IL;
namespace ILToNative
{
@ -55,8 +58,7 @@ namespace ILToNative
class ModuleData
{
public string Path;
// public ISymbolReader SymbolReader;
public Microsoft.DiaSymReader.ISymUnmanagedReader PdbReader;
}
Dictionary<EcmaModule, ModuleData> _moduleData = new Dictionary<EcmaModule, ModuleData>();
@ -130,10 +132,75 @@ namespace ILToNative
_modules.Add(simpleName, module);
ModuleData moduleData = new ModuleData() { Path = filePath };
ModuleData moduleData = new ModuleData() {
Path = filePath
};
InitializeSymbolReader(moduleData);
_moduleData.Add(module, moduleData);
return module;
}
//
// Symbols
//
PdbSymbolProvider _pdbSymbolProvider;
private void InitializeSymbolReader(ModuleData moduleData)
{
if (_pdbSymbolProvider == null)
_pdbSymbolProvider = new PdbSymbolProvider();
moduleData.PdbReader = _pdbSymbolProvider.GetSymbolReaderForFile(moduleData.Path);
}
public IEnumerable<ILSequencePoint> GetSequencePointsForMethod(MethodDesc method)
{
EcmaMethod ecmaMethod = method.GetTypicalMethodDefinition() as EcmaMethod;
if (ecmaMethod == null)
return null;
ModuleData moduleData = _moduleData[ecmaMethod.Module];
if (moduleData.PdbReader == null)
return null;
return _pdbSymbolProvider.GetSequencePointsForMethod(moduleData.PdbReader, MetadataTokens.GetToken(ecmaMethod.Handle));
}
public IEnumerable<LocalVariable> GetLocalVariableNamesForMethod(MethodDesc method)
{
EcmaMethod ecmaMethod = method.GetTypicalMethodDefinition() as EcmaMethod;
if (ecmaMethod == null)
return null;
ModuleData moduleData = _moduleData[ecmaMethod.Module];
if (moduleData.PdbReader == null)
return null;
return _pdbSymbolProvider.GetLocalVariableNamesForMethod(moduleData.PdbReader, MetadataTokens.GetToken(ecmaMethod.Handle));
}
public IEnumerable<string> GetParameterNamesForMethod(MethodDesc method)
{
EcmaMethod ecmaMethod = method.GetTypicalMethodDefinition() as EcmaMethod;
if (ecmaMethod == null)
yield break;
ParameterHandleCollection parameters = ecmaMethod.MetadataReader.GetMethodDefinition(ecmaMethod.Handle).GetParameters();
if (!ecmaMethod.Signature.IsStatic)
{
yield return "_this";
}
foreach (var parameterHandle in parameters)
{
Parameter p = ecmaMethod.MetadataReader.GetParameter(parameterHandle);
yield return ecmaMethod.MetadataReader.GetString(p.Name);
}
}
}
}

Просмотреть файл

@ -0,0 +1,228 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.InteropServices;
using Internal.IL;
using Microsoft.DiaSymReader;
namespace ILToNative
{
// For now, open PDB files using legacy desktop SymBinder
class PdbSymbolProvider
{
[Guid("809c652e-7396-11d2-9771-00a0c9b4d50c")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[ComVisible(true)]
private interface IMetaDataDispenser
{
// We need to be able to call OpenScope, which is the 2nd vtable slot.
// Thus we need this one placeholder here to occupy the first slot..
void DefineScope_Placeholder();
[PreserveSig]
int OpenScope([In, MarshalAs(UnmanagedType.LPWStr)] String szScope, [In] Int32 dwOpenFlags, [In] ref Guid riid, [Out, MarshalAs(UnmanagedType.IUnknown)] out Object punk);
// Don't need any other methods.
}
// Since we're just blindly passing this interface through managed code to the Symbinder, we don't care about actually
// importing the specific methods.
// This needs to be public so that we can call Marshal.GetComInterfaceForObject() on it to get the
// underlying metadata pointer.
[Guid("7DAC8207-D3AE-4c75-9B67-92801A497D44")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[ComVisible(true)]
public interface IMetadataImport
{
// Just need a single placeholder method so that it doesn't complain about an empty interface.
void Placeholder();
}
[DllImport("clr.dll")]
private static extern int MetaDataGetDispenser([In] ref Guid rclsid,
[In] ref Guid riid,
[Out, MarshalAs(UnmanagedType.Interface)] out Object ppv);
[DllImport("ole32.dll")]
static extern int CoCreateInstance(ref Guid rclsid, IntPtr pUnkOuter,
Int32 dwClsContext,
ref Guid riid,
[MarshalAs(UnmanagedType.Interface)] out object ppv);
void ThrowExceptionForHR(int hr)
{
Marshal.ThrowExceptionForHR(hr, new IntPtr(-1));
}
IMetaDataDispenser _metadataDispenser;
ISymUnmanagedBinder _symBinder;
public PdbSymbolProvider()
{
try
{
// Create a COM Metadata dispenser
Guid dispenserClassID = new Guid(0xe5cb7a31, 0x7512, 0x11d2, 0x89, 0xce, 0x00, 0x80, 0xc7, 0x92, 0xe5, 0xd8); // CLSID_CorMetaDataDispenser
Guid dispenserIID = new Guid(0x809c652e, 0x7396, 0x11d2, 0x97, 0x71, 0x00, 0xa0, 0xc9, 0xb4, 0xd5, 0x0c); // IID_IMetaDataDispenser
object objDispenser;
if (MetaDataGetDispenser(ref dispenserClassID, ref dispenserIID, out objDispenser) < 0)
return;
_metadataDispenser = (IMetaDataDispenser)objDispenser;
Guid symBinderClassID = new Guid(0x0A29FF9E, 0x7F9C, 0x4437, 0x8B, 0x11, 0xF4, 0x24, 0x49, 0x1E, 0x39, 0x31); // CLSID_CorSymBinder
Guid symBinderIID = new Guid(0xAA544d42, 0x28CB, 0x11d3, 0xbd, 0x22, 0x00, 0x00, 0xf8, 0x08, 0x49, 0xbd); // IID_ISymUnmanagedBinder
object objBinder;
if (CoCreateInstance(ref symBinderClassID,
IntPtr.Zero, // pUnkOuter
1, // CLSCTX_INPROC_SERVER
ref symBinderIID,
out objBinder) < 0)
return;
_symBinder = (ISymUnmanagedBinder)objBinder;
}
catch
{
}
}
public ISymUnmanagedReader GetSymbolReaderForFile(string metadataFileName)
{
if (!File.Exists(Path.ChangeExtension(metadataFileName, ".pdb")))
return null;
if (_metadataDispenser == null || _symBinder == null)
return null;
try
{
Guid importerIID = new Guid(0x7dac8207, 0xd3ae, 0x4c75, 0x9b, 0x67, 0x92, 0x80, 0x1a, 0x49, 0x7d, 0x44); // IID_IMetaDataImport
// Open an metadata importer on the given filename. We'll end up passing this importer straight
// through to the Binder.
object objImporter;
if (_metadataDispenser.OpenScope(metadataFileName, 0x00000010 /* read only */, ref importerIID, out objImporter) < 0)
return null;
ISymUnmanagedReader reader;
if (_symBinder.GetReaderForFile(objImporter, metadataFileName, "", out reader) < 0)
return null;
return reader;
}
catch
{
return null;
}
}
Dictionary<ISymUnmanagedDocument, string> _urlCache = new Dictionary<ISymUnmanagedDocument, string>();
private string GetUrl(ISymUnmanagedDocument doc)
{
string url;
if (_urlCache.TryGetValue(doc, out url))
return url;
int urlLength;
ThrowExceptionForHR(doc.GetUrl(0, out urlLength, null));
char[] urlBuffer = new char[urlLength];
ThrowExceptionForHR(doc.GetUrl(urlLength, out urlLength, urlBuffer));
url = new string(urlBuffer, 0, urlLength);
_urlCache.Add(doc, url);
return url;
}
public IEnumerable<ILSequencePoint> GetSequencePointsForMethod(ISymUnmanagedReader reader, int methodToken)
{
ISymUnmanagedMethod symbolMethod;
if (reader.GetMethod(methodToken, out symbolMethod) < 0)
yield break;
int count;
ThrowExceptionForHR(symbolMethod.GetSequencePointCount(out count));
ISymUnmanagedDocument[] docs = new ISymUnmanagedDocument[count];
int[] lineNumbers = new int[count];
int[] ilOffsets = new int[count];
ThrowExceptionForHR(symbolMethod.GetSequencePoints(count, out count, ilOffsets, docs, lineNumbers, null, null, null));
for (int i = 0; i < count; i++)
{
if (lineNumbers[i] == 0xFEEFEE)
continue;
yield return new ILSequencePoint() { Document = GetUrl(docs[i]), LineNumber = lineNumbers[i], Offset = ilOffsets[i] };
}
}
//
// Gather the local details in a scope and then recurse to child scopes
//
private void ProbeScopeForLocals(List<LocalVariable> variables, ISymUnmanagedScope scope)
{
int localCount;
ThrowExceptionForHR(scope.GetLocalCount(out localCount));
ISymUnmanagedVariable[] locals = new ISymUnmanagedVariable[localCount];
ThrowExceptionForHR(scope.GetLocals(localCount, out localCount, locals));
for (int i = 0; i < localCount; i++)
{
var local = locals[i];
int slot;
ThrowExceptionForHR(local.GetAddressField1(out slot));
int nameLength;
ThrowExceptionForHR(local.GetName(0, out nameLength, null));
char[] nameBuffer = new char[nameLength];
ThrowExceptionForHR(local.GetName(nameLength, out nameLength, nameBuffer));
int attributes;
ThrowExceptionForHR(local.GetAttributes(out attributes));
variables.Add(new LocalVariable() { Slot = slot, Name = new String(nameBuffer, 0, nameLength), CompilerGenerated = (attributes & 0x1) != 0 });
}
int childrenCount;
ThrowExceptionForHR(scope.GetChildren(0, out childrenCount, null));
ISymUnmanagedScope[] children = new ISymUnmanagedScope[childrenCount];
ThrowExceptionForHR(scope.GetChildren(childrenCount, out childrenCount, children));
for (int i = 0; i < childrenCount; i++)
{
ProbeScopeForLocals(variables, children[i]);
}
}
//
// Recursively scan the scopes for a method stored in a PDB and gather the local slots
// and names for all of them. This assumes a CSC-like compiler that doesn't re-use
// local slots in the same method across scopes.
//
public IEnumerable<LocalVariable> GetLocalVariableNamesForMethod(ISymUnmanagedReader reader, int methodToken)
{
ISymUnmanagedMethod symbolMethod;
if (reader.GetMethod(methodToken, out symbolMethod) < 0)
return null;
ISymUnmanagedScope rootScope;
ThrowExceptionForHR(symbolMethod.GetRootScope(out rootScope));
var variables = new List<LocalVariable>();
ProbeScopeForLocals(variables, rootScope);
return variables;
}
}
}

Просмотреть файл

@ -118,24 +118,19 @@ namespace ILToNative.CppCodeGen
argCount++;
List<string> parameterNames = null;
#if TODO // PDBs
if (ParameterNamesCallback != null)
IEnumerable<string> parameters = _compilation.TypeSystemContext.GetParameterNamesForMethod(method);
if (parameters != null)
{
IEnumerable<string> parameters = ParameterNamesCallback(method);
if (parameters != null)
parameterNames = new List<string>(parameters);
if (parameterNames.Count != 0)
{
parameterNames = new List<string>(parameters);
if (parameterNames.Count != 0)
{
System.Diagnostics.Debug.Assert(parameterNames.Count == argCount);
}
else
{
parameterNames = null;
}
System.Diagnostics.Debug.Assert(parameterNames.Count == argCount);
}
else
{
parameterNames = null;
}
}
#endif
for (int i = 0; i < argCount; i++)
{
@ -194,24 +189,19 @@ namespace ILToNative.CppCodeGen
argCount++;
List<string> parameterNames = null;
#if TODO // PDBs
if (ParameterNamesCallback != null)
IEnumerable<string> parameters = _compilation.TypeSystemContext.GetParameterNamesForMethod(method);
if (parameters != null)
{
IEnumerable<string> parameters = ParameterNamesCallback(method);
if (parameters != null)
parameterNames = new List<string>(parameters);
if (parameterNames.Count != 0)
{
parameterNames = new List<string>(parameters);
if (parameterNames.Count != 0)
{
System.Diagnostics.Debug.Assert(parameterNames.Count == argCount);
}
else
{
parameterNames = null;
}
System.Diagnostics.Debug.Assert(parameterNames.Count == argCount);
}
else
{
parameterNames = null;
}
}
#endif
for (int i = 0; i < argCount; i++)
{
@ -367,28 +357,22 @@ namespace ILToNative.CppCodeGen
var ilImporter = new ILImporter(_compilation, this, method, methodIL);
#if TODO // PDBS
if (SequencePointsCallback != null)
CompilerTypeSystemContext typeSystemContext = _compilation.TypeSystemContext;
if (!_compilation.Options.NoLineNumbers)
{
IEnumerable<ILSequencePoint> sequencePoints = SequencePointsCallback(method);
IEnumerable<ILSequencePoint> sequencePoints = typeSystemContext.GetSequencePointsForMethod(method);
if (sequencePoints != null)
ilImporter.SetSequencePoints(sequencePoints);
}
if (LocalVariablesCallback != null)
{
IEnumerable<LocalVariable> localVariables = LocalVariablesCallback(method);
if (localVariables != null)
ilImporter.SetLocalVariables(localVariables);
}
IEnumerable<LocalVariable> localVariables = typeSystemContext.GetLocalVariableNamesForMethod(method);
if (localVariables != null)
ilImporter.SetLocalVariables(localVariables);
if (ParameterNamesCallback != null)
{
IEnumerable<string> parameters = ParameterNamesCallback(method);
if (parameters != null)
ilImporter.SetParameterNames(parameters);
}
#endif
IEnumerable<string> parameters = typeSystemContext.GetParameterNamesForMethod(method);
if (parameters != null)
ilImporter.SetParameterNames(parameters);
string methodCode;
try

Просмотреть файл

@ -33,6 +33,7 @@
<Compile Include="Compiler\MethodCode.cs" />
<Compile Include="Compiler\MethodExtensions.cs" />
<Compile Include="Compiler\NameMangler.cs" />
<Compile Include="Compiler\PdbSymbolProvider.cs" />
<Compile Include="Compiler\ReadyToRunHelper.cs" />
<Compile Include="Compiler\RegisteredField.cs" />
<Compile Include="Compiler\RegisteredMethod.cs" />

Просмотреть файл

@ -16,9 +16,12 @@
"System.Reflection.Extensions": "4.0.0",
"System.AppContext": "4.0.0",
"System.Collections.Immutable": "1.1.37",
"System.Reflection.Metadata": "1.0.22"
"System.Reflection.Metadata": "1.0.22",
"Microsoft.DiaSymReader": "1.0.6"
},
"frameworks": {
"dotnet": {}
"dotnet": {
"imports": "portable-net452"
}
}
}

Просмотреть файл

@ -17,7 +17,8 @@
"System.Console": "4.0.0-beta-*",
"System.AppContext": "4.0.0",
"System.Collections.Immutable": "1.1.37",
"System.Reflection.Metadata": "1.0.22"
"System.Reflection.Metadata": "1.0.22",
"Microsoft.DiaSymReader": "1.0.6"
},
"frameworks": {
"net46": {}

Просмотреть файл

@ -73,6 +73,10 @@ namespace ILToNative
_options.IsCppCodeGen = true;
break;
case "nolinenumbers":
_options.NoLineNumbers = true;
break;
default:
throw new CommandLineException("Unrecognized option: " + parser.GetCurrentOption());
}