Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
@@ -0,0 +1,104 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using Microsoft.Diagnostics.Runtime;

namespace Microsoft.Diagnostics.DebugServices.Implementation
{
/// <summary>
/// Adapter exposing the host's <see cref="IModuleService"/> /
/// <see cref="IModuleSymbols"/> through ClrMD's
/// <see cref="IClrSymbolProvider"/> contract.
/// </summary>
[ServiceExport(Type = typeof(IClrSymbolProvider), Scope = ServiceScope.Target)]
public sealed class HostSymbolProvider : IClrSymbolProvider
{
private readonly IModuleService _moduleService;
private readonly ulong _signExtensionMask;

public HostSymbolProvider(IModuleService moduleService, IMemoryService memoryService)
{
_moduleService = moduleService ?? throw new ArgumentNullException(nameof(moduleService));
_signExtensionMask = memoryService?.SignExtensionMask() ?? ulong.MaxValue;
}

public bool TryGetSymbolName(ulong address, out string symbolName, out ulong displacement)
{
symbolName = null;
displacement = 0;

address &= _signExtensionMask;

IModule module;
try
{
module = _moduleService.GetModuleFromAddress(address);
}
catch (DiagnosticsException)
{
return false;
}
if (module is null)
{
return false;
}

IModuleSymbols symbols = module.Services.GetService<IModuleSymbols>();
if (symbols is null)
{
return false;
}

if (!symbols.TryGetSymbolName(address, out string bareName, out displacement)
|| string.IsNullOrEmpty(bareName))
{
return false;
}

// Strip any module! qualifier the lower-level service might have
// prepended — the new contract returns bare names only.
int bang = bareName.IndexOf('!');
symbolName = bang >= 0 && bang + 1 < bareName.Length ? bareName.Substring(bang + 1) : bareName;
return true;
}

public bool TryGetSymbolAddress(ulong moduleBase, string name, out ulong address)
{
address = 0;
if (string.IsNullOrEmpty(name))
{
return false;
}

moduleBase &= _signExtensionMask;

IModule scopedModule;
try
{
scopedModule = _moduleService.GetModuleFromBaseAddress(moduleBase);
}
catch (DiagnosticsException)
{
return false;
}
if (scopedModule is null)
{
return false;
}

IModuleSymbols scopedSymbols = scopedModule.Services.GetService<IModuleSymbols>();
if (scopedSymbols is null)
{
return false;
}

if (scopedSymbols.TryGetSymbolAddress(name, out ulong scopedAddr) && scopedAddr != 0)
{
address = scopedAddr;
return true;
}
return false;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -44,15 +44,7 @@ public Runtime(IServiceProvider services, int id, ClrInfo clrInfo)
_settingsService = services.GetService<ISettingsService>() ?? throw new ArgumentException("ISettingsService required");
_symbolService = services.GetService<ISymbolService>() ?? throw new ArgumentException("ISymbolService required");

RuntimeType = RuntimeType.Unknown;
if (clrInfo.Flavor == ClrFlavor.Core)
{
RuntimeType = RuntimeType.NetCore;
}
else if (clrInfo.Flavor == ClrFlavor.Desktop)
{
RuntimeType = RuntimeType.Desktop;
}
RuntimeType = GetRuntimeType(clrInfo.Flavor);
RuntimeModule = services.GetService<IModuleService>().GetModuleFromBaseAddress(clrInfo.ModuleInfo.ImageBase);

ServiceContainerFactory containerFactory = services.GetService<IServiceManager>().CreateServiceContainerFactory(ServiceScope.Runtime, services);
Expand Down Expand Up @@ -382,9 +374,18 @@ public override int GetHashCode()
"Desktop .NET Framework",
".NET Core",
".NET Core (single-file)",
"Native AOT",
"Other"
};

private static RuntimeType GetRuntimeType(ClrFlavor flavor) => flavor switch
{
ClrFlavor.Core => RuntimeType.NetCore,
ClrFlavor.Desktop => RuntimeType.Desktop,
ClrFlavor.NativeAOT => RuntimeType.NativeAOT,
_ => RuntimeType.Unknown,
};

public override string ToString()
{
StringBuilder sb = new();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,8 @@ public IEnumerable<IRuntime> EnumerateRuntimes(int startingRuntimeId, RuntimeEnu
return false;
}
return verifyDac;
}
},
SymbolProvider = _services.GetService<IClrSymbolProvider>(),
});
for (int i = 0; i < dataTarget.ClrVersions.Length; i++)
{
Expand Down
135 changes: 135 additions & 0 deletions src/SOS/SOS.Hosting/DataTargetWrapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ internal sealed unsafe class DataTargetWrapper : COMCallableIUnknown
private static readonly Guid IID_ICLRMetadataLocator = new("aa8fa804-bc05-4642-b2c5-c353ed22fc63");
private static readonly Guid IID_ICLRRuntimeLocator = new("b760bf44-9377-4597-8be7-58083bdc5146");
private static readonly Guid IID_ICLRContractLocator = new("17d5b8c6-34a9-407f-af4f-a930201d4e02");
private static readonly Guid IID_ICLRSymbolProvider = new("c4f8b7e2-9d3a-4f6c-b1e5-8a2d7c3f9b1e");

// For ClrMD's magic hand shake
private const ulong MagicCallbackConstant = 0x43;
Expand All @@ -31,6 +32,7 @@ internal sealed unsafe class DataTargetWrapper : COMCallableIUnknown
private readonly IModuleService _moduleService;
private readonly IThreadUnwindService _threadUnwindService;
private readonly IRemoteMemoryService _remoteMemoryService;
private readonly IClrSymbolProvider _symbolProvider;
private readonly ulong _ignoreAddressBitsMask;

public IntPtr IDataTarget { get; }
Expand All @@ -47,6 +49,7 @@ public DataTargetWrapper(IServiceProvider services, IRuntime runtime)
_threadUnwindService = services.GetService<IThreadUnwindService>();
_moduleService = services.GetService<IModuleService>();
_remoteMemoryService = services.GetService<IRemoteMemoryService>();
_symbolProvider = services.GetService<IClrSymbolProvider>();
_ignoreAddressBitsMask = _memoryService.SignExtensionMask();

VTableBuilder builder = AddInterface(IID_ICLRDataTarget, false);
Expand All @@ -73,6 +76,11 @@ public DataTargetWrapper(IServiceProvider services, IRuntime runtime)
builder.AddMethod(new GetContractDescriptorDelegate(GetContractDescriptor));
builder.Complete();

builder = AddInterface(IID_ICLRSymbolProvider, false);
builder.AddMethod(new TryGetSymbolNameDelegate(TryGetSymbolName));
builder.AddMethod(new TryGetSymbolAddressDelegate(TryGetSymbolAddress));
builder.Complete();

AddRef();
}

Expand Down Expand Up @@ -378,6 +386,113 @@ private int GetContractDescriptor(

#endregion

#region ICLRSymbolProvider

private int TryGetSymbolName(
IntPtr self,
ulong address,
uint cchName,
char* pName,
uint* pcchNameActual,
ulong* pDisplacement)
{
if (cchName > int.MaxValue)
{
return HResult.E_INVALIDARG;
}

address &= _ignoreAddressBitsMask;

try
{
if (_symbolProvider is null)
{
return HResult.E_NOTIMPL;
}

if (!_symbolProvider.TryGetSymbolName(address, out string symbolName, out ulong displacement)
|| string.IsNullOrEmpty(symbolName))
{
return HResult.E_FAIL;
}

if (pcchNameActual != null)
{
*pcchNameActual = (uint)symbolName.Length + 1;
}
if (pDisplacement != null)
{
*pDisplacement = displacement;
}

if (cchName == 0 || pName == null)
{
return HResult.S_OK;
}

int copy = Math.Min(symbolName.Length, (int)cchName - 1);
for (int i = 0; i < copy; i++)
{
pName[i] = symbolName[i];
}
pName[copy] = '\0';
return copy < symbolName.Length ? HResult.S_FALSE : HResult.S_OK;
}
catch
{
return HResult.E_FAIL;
}
}

private int TryGetSymbolAddress(
IntPtr self,
ulong moduleBase,
string name,
ulong* pAddress)
{
if (pAddress == null)
{
return HResult.E_INVALIDARG;
}
*pAddress = 0;

moduleBase &= _ignoreAddressBitsMask;

try
{
if (_symbolProvider is null)
{
return HResult.E_NOTIMPL;
}

if (string.IsNullOrEmpty(name))
{
return HResult.E_INVALIDARG;
}

// Bare symbol names only — '!' is reserved as the SOS module
// separator and is not produced by any of the mangling toolchains
// we target.
if (name.IndexOf('!') >= 0)
{
return HResult.E_INVALIDARG;
}

if (_symbolProvider.TryGetSymbolAddress(moduleBase, name, out ulong address) && address != 0)
{
*pAddress = address;
return HResult.S_OK;
}
return HResult.E_FAIL;
}
catch
{
return HResult.E_FAIL;
}
}

#endregion

#region ICLRDataTarget delegates

[UnmanagedFunctionPointer(CallingConvention.Winapi)]
Expand Down Expand Up @@ -522,5 +637,25 @@ private delegate int GetContractDescriptorDelegate(
[Out] out ulong address);

#endregion

#region ICLRSymbolProvider delegates

[UnmanagedFunctionPointer(CallingConvention.Winapi)]
private delegate int TryGetSymbolNameDelegate(
[In] IntPtr self,
[In] ulong address,
[In] uint cchName,
[Out] char* pName,
[Out] uint* pcchNameActual,
[Out] ulong* pDisplacement);

[UnmanagedFunctionPointer(CallingConvention.Winapi)]
private delegate int TryGetSymbolAddressDelegate(
[In] IntPtr self,
[In] ulong moduleBase,
[In][MarshalAs(UnmanagedType.LPWStr)] string name,
[Out] ulong* pAddress);

#endregion
}
}
Loading