Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add COMWrappers to crossgen #63969

Merged
merged 9 commits into from
Jan 22, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
binaries are up to date and which are stale. -->
<GenerateDependencyFile>false</GenerateDependencyFile>
<Configurations>Debug;Release;Checked</Configurations>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@

using System;
using System.Collections;
using System.Diagnostics;
using System.Runtime.InteropServices;

namespace Microsoft.DiaSymReader
{
internal unsafe sealed class ILCompilerComWrappers : ComWrappers
{
protected override unsafe ComInterfaceEntry* ComputeVtables(object obj, CreateComInterfaceFlags flags, out int count)
{
// passing the managed object to COM is not currently supported
throw new NotImplementedException();
}

protected override object CreateObject(IntPtr externalComObject, CreateObjectFlags flags)
{
// Assert use of the UniqueInstance flag since the returned Native Object Wrapper always
// supports IDisposable and its Dispose will always release and suppress finalization.
// If the wrapper doesn't always support IDisposable the assert can be relaxed.
Debug.Assert(flags.HasFlag(CreateObjectFlags.UniqueInstance));

// Throw an exception if the type is not supported by the implementation.
// Null can be returned as well, but an ArgumentNullException will be thrown for
// the consumer of this ComWrappers instance.
return SymNgenWriterWrapper.CreateIfSupported(externalComObject) ?? throw new NotSupportedException();
}

protected override void ReleaseObjects(IEnumerable objects) => throw new NotImplementedException();
}
}
73 changes: 70 additions & 3 deletions src/coreclr/tools/aot/ILCompiler.Diagnostics/ISymNGenWriter.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

#pragma warning disable 436 // SuppressUnmanagedCodeSecurityAttribute defined in source and mscorlib
#pragma warning disable 436 // SuppressUnmanagedCodeSecurityAttribute defined in source and mscorlib

using System;
using System.Collections.Generic;
Expand All @@ -11,9 +11,39 @@

namespace Microsoft.DiaSymReader
{
[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("D682FD12-43dE-411C-811B-BE8404CEA126"), SuppressUnmanagedCodeSecurity]
/// <summary>
/// IUnknown COM type for writing NGen PDBs
/// </summary>
/// <remarks>
/// <code>
/// [
/// object,
/// uuid(d682fd12-43de-411c-811b-be8404cea126),
/// pointer_default(unique)
/// ]
/// interface ISymNGenWriter : IUnknown
/// {
/// /*
/// * Add a new public symbol to the NGEN PDB.
/// */
/// HRESULT AddSymbol([in] BSTR pSymbol,
/// [in] USHORT iSection,
/// [in] ULONGLONG rva);
///
/// /*
/// * Adds a new section to the NGEN PDB.
/// */
/// HRESULT AddSection([in] USHORT iSection,
/// [in] USHORT flags,
/// [in] long offset,
/// [in] long cb);
/// };
/// </code>
/// </remarks>
internal interface ISymNGenWriter
{
public static readonly Guid IID = new Guid("D682FD12-43dE-411C-811B-BE8404CEA126");

// Add a new public symbol to the NGEN PDB.
void AddSymbol([MarshalAs(UnmanagedType.BStr)] string pSymbol,
ushort iSection,
Expand Down Expand Up @@ -46,9 +76,46 @@ internal enum OMF : ushort
}


[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("B029E51B-4C55-4fe2-B993-9F7BC1F10DB4"), SuppressUnmanagedCodeSecurity]
/// <summary>
/// IUnknown COM type for writing NGen PDBs
/// </summary>
/// <remarks>
/// <code>
/// [
/// object,
/// local,
/// uuid(B029E51B-4C55-4fe2-B993-9F7BC1F10DB4),
/// pointer_default(unique)
/// ]
/// interface ISymNGenWriter2 : ISymNGenWriter
/// {
/// HRESULT OpenModW([in] const wchar_t* wszModule,
/// [in] const wchar_t* wszObjFile,
/// [out] BYTE** ppmod);
///
/// HRESULT CloseMod([in] BYTE* pmod);
///
/// HRESULT ModAddSymbols([in] BYTE* pmod, [in] BYTE* pbSym, [in] long cb);
///
/// HRESULT ModAddSecContribEx(
/// [in] BYTE* pmod,
/// [in] USHORT isect,
/// [in] long off,
/// [in] long cb,
/// [in] ULONG dwCharacteristics,
/// [in] DWORD dwDataCrc,
/// [in] DWORD dwRelocCrc);
///
/// HRESULT QueryPDBNameExW(
/// [out, size_is(cchMax)] wchar_t wszPDB[],
/// [in] SIZE_T cchMax);
/// };
/// </remarks>
/// </code>
internal interface ISymNGenWriter2 : ISymNGenWriter
{
public readonly static new Guid IID = new Guid("B029E51B-4C55-4fe2-B993-9F7BC1F10DB4");

// Add a new public symbol to the NGEN PDB.
new void AddSymbol([MarshalAs(UnmanagedType.BStr)] string pSymbol,
ushort iSection,
Expand Down
6 changes: 4 additions & 2 deletions src/coreclr/tools/aot/ILCompiler.Diagnostics/PdbWriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ private static IntPtr DllImportResolver(string libraryName, Assembly assembly, D
private extern static void CreateNGenPdbWriter(
[MarshalAs(UnmanagedType.LPWStr)] string ngenImagePath,
[MarshalAs(UnmanagedType.LPWStr)] string pdbPath,
[MarshalAs(UnmanagedType.Interface)] out ISymNGenWriter2 ngenPdbWriter);
out IntPtr ngenPdbWriterPtr);

public PdbWriter(string pdbPath, PDBExtraData pdbExtraData, TargetDetails target)
{
Expand Down Expand Up @@ -217,7 +217,9 @@ private void WritePDBDataHelper(string dllPath, IEnumerable<MethodInfo> methods)
// Delete any preexisting PDB file upfront, otherwise CreateNGenPdbWriter silently opens it
File.Delete(_pdbFilePath);

CreateNGenPdbWriter(dllPath, _pdbFilePath, out _ngenWriter);
var comWrapper = new ILCompilerComWrappers();
CreateNGenPdbWriter(dllPath, _pdbFilePath, out var pdbWriterInst);
_ngenWriter = (ISymNGenWriter2)comWrapper.GetOrCreateObjectForComInstance(pdbWriterInst, CreateObjectFlags.UniqueInstance);
agocke marked this conversation as resolved.
Show resolved Hide resolved

{
// PDB file is now created. Get its path and update _pdbFilePath so the PDB file
Expand Down
145 changes: 145 additions & 0 deletions src/coreclr/tools/aot/ILCompiler.Diagnostics/SymNgenWriterWrapper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@

using System;
using System.Runtime.InteropServices;
using System.Text;

#nullable enable

namespace Microsoft.DiaSymReader
{
internal class SymNgenWriterWrapper : ISymNGenWriter2, IDisposable
{
private bool _isDisposed = false;
public IntPtr ISymNGenWriter2Inst { get; }

private SymNgenWriterWrapper(IntPtr writer2Inst)
{
ISymNGenWriter2Inst = writer2Inst;
}

public static SymNgenWriterWrapper? CreateIfSupported(IntPtr ptr)
{
var iid = ISymNGenWriter2.IID;
int hr = Marshal.QueryInterface(ptr, ref iid, out IntPtr ngenWriterInst);
if (hr != 0)
{
return null;
}

return new SymNgenWriterWrapper(ngenWriterInst);
}

~SymNgenWriterWrapper()
{
DisposeInternal();
}

public void Dispose()
{
DisposeInternal();
GC.SuppressFinalize(this);
}

private void DisposeInternal()
{
if (_isDisposed)
{
return;
}
Marshal.Release(ISymNGenWriter2Inst);
_isDisposed = true;
}

public unsafe void AddSymbol(string pSymbol, ushort iSection, ulong rva)
{
IntPtr strLocal = Marshal.StringToBSTR(pSymbol);
var inst = ISymNGenWriter2Inst;
var func = (delegate* unmanaged<IntPtr, IntPtr, ushort, ulong, int>)(*(*(void***)inst + 3 /* ISymNGenWriter2.AddSymbol slot */));
int hr = func(inst, strLocal, iSection, rva);
if (hr != 0)
{
Marshal.FreeBSTR(strLocal);
agocke marked this conversation as resolved.
Show resolved Hide resolved
Marshal.ThrowExceptionForHR(hr);
}
}

public unsafe void AddSection(ushort iSection, OMF flags, int offset, int cb)
{
var inst = ISymNGenWriter2Inst;
var func = (delegate* unmanaged<IntPtr, ushort, OMF, int, int, int>)(*(*(void***)inst + 4));
int hr = func(inst, iSection, flags, offset, cb);
if (hr != 0)
{
Marshal.ThrowExceptionForHR(hr);
}
}

public unsafe void OpenModW(string wszModule, string wszObjFile, out UIntPtr ppmod)
{
IntPtr moduleLocal = Marshal.StringToBSTR(wszModule);
IntPtr objLocal = Marshal.StringToBSTR(wszObjFile);
agocke marked this conversation as resolved.
Show resolved Hide resolved
var inst = ISymNGenWriter2Inst;
var func = (delegate* unmanaged<IntPtr, IntPtr, IntPtr, out UIntPtr, int>)(*(*(void***)inst + 5));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not required, but I'd highly recommend changing this signature to use UIntPtr* instead of out UIntPtr. Otherwise, you're still producing an IL stub.

int hr = func(inst, moduleLocal, objLocal, out ppmod);
if (hr != 0)
{
Marshal.ThrowExceptionForHR(hr);
}
}

public unsafe void CloseMod(UIntPtr pmod)
{
var inst = ISymNGenWriter2Inst;
var func = (delegate* unmanaged<IntPtr, UIntPtr, int>)(*(*(void***)inst + 6));
int hr = func(inst, pmod);
if (hr != 0)
{
Marshal.ThrowExceptionForHR(hr);
}
}

public unsafe void ModAddSymbols(UIntPtr pmod, [MarshalAs(UnmanagedType.LPArray)] byte[] pbSym, int cb)
{
fixed (byte* pbSymPtr = pbSym)
{
var pbSymLocal = (IntPtr)pbSymPtr;
var inst = ISymNGenWriter2Inst;
var func = (delegate* unmanaged<IntPtr, UIntPtr, IntPtr, int, int>)(*(*(void***)inst + 7));
int hr = func(inst, pmod, pbSymLocal, cb);
if (hr != 0)
{
Marshal.ThrowExceptionForHR(hr);
}
}
}

public unsafe void ModAddSecContribEx(UIntPtr pmod, ushort isect, int off, int cb, uint dwCharacteristics, uint dwDataCrc, uint dwRelocCrc)
{
var inst = ISymNGenWriter2Inst;
var func = (delegate* unmanaged<IntPtr, UIntPtr, ushort, int, int, uint, uint, uint, int>)(*(*(void***)inst + 8));
int hr = func(inst, pmod, isect, off, cb, dwCharacteristics, dwDataCrc, dwRelocCrc);
if (hr != 0)
{
Marshal.ThrowExceptionForHR(hr);
}
}

public unsafe void QueryPDBNameExW(StringBuilder pdb, IntPtr cchMax)
{
fixed (void* pdbPtr = pdb.ToString())
{
var pdbLocal = (IntPtr)pdbPtr;
var inst = ISymNGenWriter2Inst;
var func = (delegate* unmanaged<IntPtr, IntPtr, IntPtr, int>)(*(*(void***)inst + 9));
int hr = func(inst, pdbLocal, cchMax);
if (hr != 0)
{
Marshal.ThrowExceptionForHR(hr);
}
}
}

void ISymNGenWriter.AddSymbol(string pSymbol, ushort iSection, ulong rva) => AddSymbol(pSymbol, iSection, rva);
void ISymNGenWriter.AddSection(ushort iSection, OMF flags, int offset, int cb) => AddSection(iSection, flags, offset, cb);
}
}