Skip to content

Commit

Permalink
Use metadata to find type names when appropriate
Browse files Browse the repository at this point in the history
The dac private API will return "<Unloaded Type>" for dynamic type names.  We can work around this by using metadata (when available) to produce the name.  This restores ClrMD 1.1's behavior.

Fixes dotnet/diagnostics#4108.
  • Loading branch information
leculver committed Aug 21, 2023
1 parent c31c5c0 commit f55f994
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ public override IEnumerable<ClrGenericParameter> EnumerateGenericParameters()
if (_name == null)
{
// GetTypeName returns whether the value should be cached or not.
if (!Helpers.TryGetTypeName(MethodTable, out string? name))
if (!Helpers.TryGetTypeName(this, out string? name))
return name;

// Cache the result or "string.Empty" for null.
Expand Down
38 changes: 36 additions & 2 deletions src/Microsoft.Diagnostics.Runtime/Implementation/ClrTypeHelpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,14 @@
using System.Runtime.InteropServices;
using Microsoft.Diagnostics.Runtime.DacInterface;
using Microsoft.Diagnostics.Runtime.Implementation;
using Microsoft.Diagnostics.Runtime.Utilities;

namespace Microsoft.Diagnostics.Runtime
{
internal sealed class ClrTypeHelpers : IClrTypeHelpers, IClrFieldHelpers
{
private readonly string UnloadedTypeName = "<Unloaded Type>";

private readonly uint _firstChar = (uint)IntPtr.Size + 4;
private readonly uint _stringLength = (uint)IntPtr.Size;
private readonly SOSDac _sos;
Expand Down Expand Up @@ -138,19 +141,50 @@ private ImmutableArray<ComInterfaceData> GetComInterfaces(COMInterfacePointerDat
return _typeFactory.GetOrCreateType(mt, 0);
}

public bool TryGetTypeName(ulong mt, out string? name)
public bool TryGetTypeName(ClrType type, out string? name)
{
name = _sos.GetMethodTableName(mt);
name = _sos.GetMethodTableName(type.MethodTable);
if (string.IsNullOrWhiteSpace(name))
return true;

if (name == UnloadedTypeName)
{
string? nameFromToken = GetNameFromToken(type.Module?.MetadataImport, type.MetadataToken);
if (nameFromToken is not null)
{
name = nameFromToken;
return true;
}
}

name = DACNameParser.Parse(name);
if (CacheOptions.CacheTypeNames == StringCaching.Intern)
name = string.Intern(name);

return CacheOptions.CacheTypeNames != StringCaching.None;
}

private static string? GetNameFromToken(MetadataImport? import, int token)
{
if (import is not null)
{
HResult hr = import.GetTypeDefProperties(token, out string? name, out _, out _);
if (hr && name is not null)
{
hr = import.GetNestedClassProperties(token, out int enclosingToken);
if (hr && enclosingToken != 0 && enclosingToken != token)
{
string? inner = GetNameFromToken(import, enclosingToken) ?? "<UNKNOWN>";
name += $"+{inner}";
}

return name;
}
}

return null;
}

public ulong GetLoaderAllocatorHandle(ulong mt)
{
if (_sos6 != null && _sos6.GetMethodTableCollectibleData(mt, out MethodTableCollectibleData data) && data.Collectible != 0)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ internal interface IClrTypeHelpers
ClrHeap Heap { get; }
IDataReader DataReader { get; }

bool TryGetTypeName(ulong mt, out string? name);
bool TryGetTypeName(ClrType type, out string? name);
ulong GetLoaderAllocatorHandle(ulong mt);
ulong GetAssemblyLoadContextAddress(ulong mt);

Expand Down

0 comments on commit f55f994

Please sign in to comment.