Files
2026-08-27 10:56:38 -06:00

227 lines
7.2 KiB
C#

using System;
using System.IO;
using System.Reflection;
using System.Runtime.InteropServices;
namespace Microsoft.DiaSymReader;
internal static class SymUnmanagedFactory
{
private delegate void NativeFactory(ref Guid id, [MarshalAs(UnmanagedType.IUnknown)] out object instance);
private const string AlternateLoadPathEnvironmentVariableName = "MICROSOFT_DIASYMREADER_NATIVE_ALT_LOAD_PATH";
private const string LegacyDiaSymReaderModuleName = "diasymreader.dll";
private const string DiaSymReaderModuleName32 = "Microsoft.DiaSymReader.Native.x86.dll";
private const string DiaSymReaderModuleNameAmd64 = "Microsoft.DiaSymReader.Native.amd64.dll";
private const string DiaSymReaderModuleNameArm64 = "Microsoft.DiaSymReader.Native.arm64.dll";
private const string CreateSymReaderFactoryName = "CreateSymReader";
private const string CreateSymWriterFactoryName = "CreateSymWriter";
private const string SymWriterClsid = "0AE2DEB0-F901-478b-BB9F-881EE8066788";
private const string SymReaderClsid = "0A3976C5-4529-4ef8-B0B0-42EED37082CD";
private static Type s_lazySymReaderComType;
private static Type s_lazySymWriterComType;
private static readonly Lazy<Func<string, string>> s_lazyGetEnvironmentVariable = new Lazy<Func<string, string>>(delegate
{
try
{
foreach (MethodInfo declaredMethod in typeof(Environment).GetTypeInfo().GetDeclaredMethods("GetEnvironmentVariable"))
{
ParameterInfo[] parameters = declaredMethod.GetParameters();
if (parameters.Length == 1 && parameters[0].ParameterType == typeof(string))
{
return (Func<string, string>)declaredMethod.CreateDelegate(typeof(Func<string, string>));
}
}
}
catch
{
}
return (Func<string, string>)null;
});
internal static string DiaSymReaderModuleName => RuntimeInformation.ProcessArchitecture switch
{
Architecture.X86 => "Microsoft.DiaSymReader.Native.x86.dll",
Architecture.X64 => "Microsoft.DiaSymReader.Native.amd64.dll",
Architecture.Arm64 => "Microsoft.DiaSymReader.Native.arm64.dll",
_ => throw new NotSupportedException(),
};
[DllImport("Microsoft.DiaSymReader.Native.x86.dll", EntryPoint = "CreateSymReader")]
[DefaultDllImportSearchPaths(DllImportSearchPath.SafeDirectories | DllImportSearchPath.AssemblyDirectory)]
private static extern void CreateSymReader32(ref Guid id, [MarshalAs(UnmanagedType.IUnknown)] out object symReader);
[DllImport("Microsoft.DiaSymReader.Native.amd64.dll", EntryPoint = "CreateSymReader")]
[DefaultDllImportSearchPaths(DllImportSearchPath.SafeDirectories | DllImportSearchPath.AssemblyDirectory)]
private static extern void CreateSymReaderAmd64(ref Guid id, [MarshalAs(UnmanagedType.IUnknown)] out object symReader);
[DllImport("Microsoft.DiaSymReader.Native.arm64.dll", EntryPoint = "CreateSymReader")]
[DefaultDllImportSearchPaths(DllImportSearchPath.SafeDirectories | DllImportSearchPath.AssemblyDirectory)]
private static extern void CreateSymReaderArm64(ref Guid id, [MarshalAs(UnmanagedType.IUnknown)] out object symReader);
[DllImport("Microsoft.DiaSymReader.Native.x86.dll", EntryPoint = "CreateSymWriter")]
[DefaultDllImportSearchPaths(DllImportSearchPath.SafeDirectories | DllImportSearchPath.AssemblyDirectory)]
private static extern void CreateSymWriter32(ref Guid id, [MarshalAs(UnmanagedType.IUnknown)] out object symWriter);
[DllImport("Microsoft.DiaSymReader.Native.amd64.dll", EntryPoint = "CreateSymWriter")]
[DefaultDllImportSearchPaths(DllImportSearchPath.SafeDirectories | DllImportSearchPath.AssemblyDirectory)]
private static extern void CreateSymWriterAmd64(ref Guid id, [MarshalAs(UnmanagedType.IUnknown)] out object symWriter);
[DllImport("Microsoft.DiaSymReader.Native.arm64.dll", EntryPoint = "CreateSymWriter")]
[DefaultDllImportSearchPaths(DllImportSearchPath.SafeDirectories | DllImportSearchPath.AssemblyDirectory)]
private static extern void CreateSymWriterArm64(ref Guid id, [MarshalAs(UnmanagedType.IUnknown)] out object symWriter);
[DllImport("kernel32")]
private static extern IntPtr LoadLibrary(string path);
[DllImport("kernel32")]
private static extern bool FreeLibrary(IntPtr hModule);
[DllImport("kernel32")]
private static extern IntPtr GetProcAddress(IntPtr hModule, string procedureName);
internal static string GetEnvironmentVariable(string name)
{
try
{
return s_lazyGetEnvironmentVariable.Value?.Invoke(name);
}
catch
{
return null;
}
}
private static object TryLoadFromAlternativePath(Guid clsid, string factoryName)
{
string environmentVariable = GetEnvironmentVariable("MICROSOFT_DIASYMREADER_NATIVE_ALT_LOAD_PATH");
if (string.IsNullOrEmpty(environmentVariable))
{
return null;
}
IntPtr intPtr = LoadLibrary(Path.Combine(environmentVariable, DiaSymReaderModuleName));
if (intPtr == IntPtr.Zero)
{
Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
}
object instance = null;
try
{
IntPtr procAddress = GetProcAddress(intPtr, factoryName);
if (procAddress == IntPtr.Zero)
{
Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
}
Marshal.GetDelegateForFunctionPointer<NativeFactory>(procAddress)(ref clsid, out instance);
}
finally
{
if (instance == null && !FreeLibrary(intPtr))
{
Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
}
}
return instance;
}
private static Type GetComTypeType(ref Type lazyType, Guid clsid)
{
if (lazyType == null)
{
lazyType = Marshal.GetTypeFromCLSID(clsid);
}
return lazyType;
}
internal static object CreateObject(bool createReader, bool useAlternativeLoadPath, bool useComRegistry, out string moduleName, out Exception loadException)
{
object symReader = null;
loadException = null;
moduleName = null;
Guid id = new Guid(createReader ? "0A3976C5-4529-4ef8-B0B0-42EED37082CD" : "0AE2DEB0-F901-478b-BB9F-881EE8066788");
try
{
try
{
switch (RuntimeInformation.ProcessArchitecture)
{
case Architecture.X86:
if (createReader)
{
CreateSymReader32(ref id, out symReader);
}
else
{
CreateSymWriter32(ref id, out symReader);
}
break;
case Architecture.X64:
if (createReader)
{
CreateSymReaderAmd64(ref id, out symReader);
}
else
{
CreateSymWriterAmd64(ref id, out symReader);
}
break;
case Architecture.Arm64:
if (createReader)
{
CreateSymReaderArm64(ref id, out symReader);
}
else
{
CreateSymWriterArm64(ref id, out symReader);
}
break;
default:
throw new NotSupportedException();
}
}
catch (DllNotFoundException ex) when (useAlternativeLoadPath)
{
symReader = TryLoadFromAlternativePath(id, createReader ? "CreateSymReader" : "CreateSymWriter");
if (symReader == null)
{
loadException = ex;
}
}
}
catch (Exception ex2)
{
loadException = ex2;
symReader = null;
}
if (symReader != null)
{
moduleName = DiaSymReaderModuleName;
}
else if (useComRegistry)
{
try
{
symReader = Activator.CreateInstance(createReader ? GetComTypeType(ref s_lazySymReaderComType, id) : GetComTypeType(ref s_lazySymWriterComType, id));
moduleName = "diasymreader.dll";
}
catch (Exception ex3)
{
loadException = ex3;
symReader = null;
}
}
return symReader;
}
}