Skip to content

Commit b519b6e

Browse files
committed
implement GetMethodTableSlot and GetMethodTableSlotEnum
1 parent e6d984a commit b519b6e

File tree

5 files changed

+404
-17
lines changed

5 files changed

+404
-17
lines changed

src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IRuntimeTypeSystem.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// The .NET Foundation licenses this file to you under the MIT license.
33

44
using System;
5+
using System.Collections.Generic;
56

67
namespace Microsoft.Diagnostics.DataContractReader.Contracts;
78

@@ -89,6 +90,8 @@ public interface IRuntimeTypeSystem : IContract
8990
TargetPointer GetParentMethodTable(TypeHandle typeHandle) => throw new NotImplementedException();
9091

9192
TargetPointer GetMethodDescForSlot(TypeHandle methodTable, ushort slot) => throw new NotImplementedException();
93+
IEnumerable<TargetPointer> GetIntroducedMethodDescs(TypeHandle methodTable) => throw new NotImplementedException();
94+
TargetCodePointer GetSlot(TypeHandle typeHandle, uint slot) => throw new NotImplementedException();
9295

9396
uint GetBaseSize(TypeHandle typeHandle) => throw new NotImplementedException();
9497
// The component size is only available for strings and arrays. It is the size of the element type of the array, or the size of an ECMA 335 character (2 bytes)
@@ -104,6 +107,7 @@ public interface IRuntimeTypeSystem : IContract
104107

105108
// Returns an ECMA-335 TypeDef table token for this type, or for its generic type definition if it is a generic instantiation
106109
uint GetTypeDefToken(TypeHandle typeHandle) => throw new NotImplementedException();
110+
ushort GetNumVtableSlots(TypeHandle typeHandle) => throw new NotImplementedException();
107111
ushort GetNumMethods(TypeHandle typeHandle) => throw new NotImplementedException();
108112
// Returns the ECMA 335 TypeDef table Flags value (a bitmask of TypeAttributes) for this type,
109113
// or for its generic type definition if it is a generic instantiation
@@ -175,6 +179,7 @@ public interface IRuntimeTypeSystem : IContract
175179
TargetPointer GetMethodDescVersioningState(MethodDescHandle methodDesc) => throw new NotImplementedException();
176180

177181
TargetCodePointer GetNativeCode(MethodDescHandle methodDesc) => throw new NotImplementedException();
182+
TargetCodePointer GetMethodEntryPointIfExists(MethodDescHandle methodDesc) => throw new NotImplementedException();
178183

179184
ushort GetSlotNumber(MethodDescHandle methodDesc) => throw new NotImplementedException();
180185

src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeTypeSystem_1.cs

Lines changed: 78 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -410,6 +410,14 @@ public uint GetTypeDefToken(TypeHandle typeHandle)
410410
MethodTable methodTable = _methodTables[typeHandle.Address];
411411
return (uint)(methodTable.Flags.GetTypeDefRid() | ((int)TableIndex.TypeDef << 24));
412412
}
413+
public ushort GetNumVtableSlots(TypeHandle typeHandle)
414+
{
415+
if (!typeHandle.IsMethodTable())
416+
return 0;
417+
MethodTable methodTable = _methodTables[typeHandle.Address];
418+
ushort numNonVirtualSlots = methodTable.IsCanonMT ? GetClassData(typeHandle).NumNonVirtualSlots : (ushort)0;
419+
return checked((ushort)(methodTable.NumVirtuals + numNonVirtualSlots));
420+
}
413421
public ushort GetNumMethods(TypeHandle typeHandle) => !typeHandle.IsMethodTable() ? (ushort)0 : GetClassData(typeHandle).NumMethods;
414422
public uint GetTypeDefTypeAttributes(TypeHandle typeHandle) => !typeHandle.IsMethodTable() ? (uint)0 : GetClassData(typeHandle).CorTypeAttr;
415423
public ushort GetNumInstanceFields(TypeHandle typeHandle) => !typeHandle.IsMethodTable() ? (ushort)0 : GetClassData(typeHandle).NumInstanceFields;
@@ -699,15 +707,6 @@ private FunctionPointerRetAndArgs(Target target, TargetPointer typePointer)
699707
}
700708
}
701709

702-
private ushort GetNumVtableSlots(TypeHandle typeHandle)
703-
{
704-
if (!typeHandle.IsMethodTable())
705-
return 0;
706-
MethodTable methodTable = _methodTables[typeHandle.Address];
707-
ushort numNonVirtualSlots = methodTable.IsCanonMT ? GetClassData(typeHandle).NumNonVirtualSlots : (ushort)0;
708-
return checked((ushort)(methodTable.NumVirtuals + numNonVirtualSlots));
709-
}
710-
711710
public MethodDescHandle GetMethodDescHandle(TargetPointer methodDescPointer)
712711
=> GetMethodDescHandle(methodDescPointer, validate: true);
713712

@@ -1086,33 +1085,78 @@ private IEnumerable<MethodDescHandle> GetIntroducedMethods(TypeHandle typeHandle
10861085
}
10871086
}
10881087

1088+
IEnumerable<TargetPointer> IRuntimeTypeSystem.GetIntroducedMethodDescs(TypeHandle typeHandle)
1089+
{
1090+
if (!typeHandle.IsMethodTable())
1091+
throw new ArgumentException($"{nameof(typeHandle)} is not a MethodTable");
1092+
1093+
TypeHandle canonMT = GetTypeHandle(GetCanonicalMethodTable(typeHandle));
1094+
foreach (MethodDescHandle mdh in GetIntroducedMethods(canonMT))
1095+
{
1096+
yield return mdh.Address;
1097+
}
1098+
}
1099+
1100+
// Uses GetMethodDescForSlotVtable if slot is less than the number of vtable slots
1101+
// otherwise looks for the slot in the introduced methods
10891102
TargetPointer IRuntimeTypeSystem.GetMethodDescForSlot(TypeHandle typeHandle, ushort slot)
1103+
{
1104+
if (!typeHandle.IsMethodTable())
1105+
throw new ArgumentException($"{nameof(typeHandle)} is not a MethodTable");
1106+
1107+
TypeHandle canonMT = GetTypeHandle(GetCanonicalMethodTable(typeHandle));
1108+
if (slot < GetNumVtableSlots(canonMT))
1109+
{
1110+
return GetMethodDescForSlotVtable(canonMT, slot);
1111+
}
1112+
else
1113+
{
1114+
foreach (MethodDescHandle mdh in GetIntroducedMethods(canonMT))
1115+
{
1116+
MethodDesc md = _methodDescs[mdh.Address];
1117+
if (md.Slot == slot)
1118+
{
1119+
return mdh.Address;
1120+
}
1121+
}
1122+
return TargetPointer.Null;
1123+
}
1124+
}
1125+
1126+
private TargetPointer GetMethodDescForSlotVtable(TypeHandle typeHandle, ushort slot)
10901127
{
10911128
// based on MethodTable::GetMethodDescForSlot_NoThrow
10921129
if (!typeHandle.IsMethodTable())
10931130
throw new ArgumentException($"{nameof(typeHandle)} is not a MethodTable");
10941131

10951132
TargetPointer cannonMTPTr = GetCanonicalMethodTable(typeHandle);
10961133
TypeHandle canonMT = GetTypeHandle(cannonMTPTr);
1134+
if (slot >= GetNumVtableSlots(canonMT))
1135+
throw new ArgumentException(nameof(slot), "Slot number is greater than the number of slots");
1136+
10971137
TargetPointer slotPtr = GetAddressOfSlot(canonMT, slot);
10981138
TargetCodePointer pCode = _target.ReadCodePointer(slotPtr);
10991139

11001140
if (pCode == TargetCodePointer.Null)
11011141
{
1102-
while (canonMT.Address != TargetPointer.Null)
1142+
TargetPointer lookupMTPtr = cannonMTPTr;
1143+
while (lookupMTPtr != TargetPointer.Null)
11031144
{
11041145
// if pCode is null, we iterate through the method descs in the MT.
1105-
foreach (MethodDescHandle mdh in GetIntroducedMethods(canonMT))
1146+
TypeHandle lookupMT = GetTypeHandle(lookupMTPtr);
1147+
foreach (MethodDescHandle mdh in GetIntroducedMethods(lookupMT))
11061148
{
11071149
MethodDesc md = _methodDescs[mdh.Address];
11081150
if (md.Slot == slot)
11091151
{
11101152
return mdh.Address;
11111153
}
11121154
}
1113-
canonMT = GetTypeHandle(GetCanonicalMethodTable(GetTypeHandle(GetParentMethodTable(canonMT))));
1155+
lookupMTPtr = GetParentMethodTable(lookupMT);
1156+
if (lookupMTPtr != TargetPointer.Null)
1157+
lookupMTPtr = GetCanonicalMethodTable(GetTypeHandle(lookupMTPtr));
11141158
}
1115-
Debug.Fail("We should never reach here, as there should always be a MethodDesc for a slot");
1159+
return TargetPointer.Null;
11161160
}
11171161

11181162
return GetMethodDescForEntrypoint(pCode);
@@ -1135,6 +1179,21 @@ private readonly TargetPointer GetMethodDescForEntrypoint(TargetCodePointer pCod
11351179
}
11361180
}
11371181

1182+
TargetCodePointer IRuntimeTypeSystem.GetSlot(TypeHandle typeHandle, uint slot)
1183+
{
1184+
// based on MethodTable::GetSlot(uint slotNumber)
1185+
if (!typeHandle.IsMethodTable())
1186+
throw new ArgumentException($"{nameof(typeHandle)} is not a MethodTable");
1187+
1188+
if (slot < GetNumVtableSlots(typeHandle))
1189+
{
1190+
TargetPointer slotPtr = GetAddressOfSlot(typeHandle, slot);
1191+
return _target.ReadCodePointer(slotPtr);
1192+
}
1193+
1194+
return TargetCodePointer.Null;
1195+
}
1196+
11381197
TargetPointer IRuntimeTypeSystem.GetAddressOfNativeCodeSlot(MethodDescHandle methodDesc)
11391198
{
11401199
MethodDesc md = _methodDescs[methodDesc.Address];
@@ -1161,6 +1220,12 @@ TargetCodePointer IRuntimeTypeSystem.GetNativeCode(MethodDescHandle methodDescHa
11611220
return GetStableEntryPoint(md);
11621221
}
11631222

1223+
TargetCodePointer IRuntimeTypeSystem.GetMethodEntryPointIfExists(MethodDescHandle methodDescHandle)
1224+
{
1225+
MethodDesc md = _methodDescs[methodDescHandle.Address];
1226+
return GetMethodEntryPointIfExists(md);
1227+
}
1228+
11641229
private TargetCodePointer GetStableEntryPoint(MethodDesc md)
11651230
{
11661231
// TODO(cdac): _ASSERTE(!IsVersionableWithVtableSlotBackpatch());

src/native/managed/cdac/mscordaccore_universal/Legacy/ConversionExtensions.cs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,21 @@ public static ClrDataAddress ToClrDataAddress(this TargetPointer address, Target
2626
}
2727
}
2828

29+
/// <summary>
30+
/// Converts a TargetCodePointer to a ClrDataAddress using sign extension if required.
31+
/// </summary>
32+
public static ClrDataAddress ToClrDataAddress(this TargetCodePointer address, Target target)
33+
{
34+
if (target.PointerSize == sizeof(ulong))
35+
{
36+
return address.Value;
37+
}
38+
else
39+
{
40+
return (ulong)(int)address.Value;
41+
}
42+
}
43+
2944
/// <summary>
3045
/// Converts a ClrDataAddress to a TargetPointer, ensuring the address is within the valid range for the target platform.
3146
/// When overrideCheck is true, this will not check the range and will allow any address. This is used on legacy endpoints which

src/native/managed/cdac/mscordaccore_universal/Legacy/ISOSDacInterface.cs

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,20 @@ internal struct DacpMethodDescData
243243

244244
}
245245

246+
[GeneratedComInterface]
247+
[Guid("286CA186-E763-4F61-9760-487D43AE4341")]
248+
internal unsafe partial interface ISOSEnum
249+
{
250+
[PreserveSig]
251+
int Skip(uint count);
252+
253+
[PreserveSig]
254+
int Reset();
255+
256+
[PreserveSig]
257+
int GetCount(uint* pCount);
258+
}
259+
246260
[GeneratedComInterface]
247261
[Guid("436f00f2-b42a-4b9f-870c-e73db66ae930")]
248262
internal unsafe partial interface ISOSDacInterface
@@ -656,12 +670,30 @@ internal unsafe partial interface ISOSDacInterface14
656670
int GetMethodTableInitializationFlags(ClrDataAddress methodTable, MethodTableInitializationFlags* initializationStatus);
657671
}
658672

673+
internal struct SOSMethodData
674+
{
675+
public ClrDataAddress MethodDesc;
676+
public ClrDataAddress Entrypoint;
677+
public ClrDataAddress DefiningMethodTable;
678+
public ClrDataAddress DefiningModule;
679+
public uint Token;
680+
public uint Slot;
681+
}
682+
683+
[GeneratedComInterface]
684+
[Guid("3c0fe725-c324-4a4f-8100-d399588a662e")]
685+
internal unsafe partial interface ISOSMethodEnum : ISOSEnum
686+
{
687+
[PreserveSig]
688+
int Next(uint count, [In, Out, MarshalUsing(CountElementName = nameof(count))] SOSMethodData[] values, uint* pNeeded);
689+
}
690+
659691
[GeneratedComInterface]
660692
[Guid("7ed81261-52a9-4a23-a358-c3313dea30a8")]
661693
internal unsafe partial interface ISOSDacInterface15
662694
{
663695
[PreserveSig]
664-
int GetMethodTableSlotEnumerator(ClrDataAddress mt, /*ISOSMethodEnum*/void** enumerator);
696+
int GetMethodTableSlotEnumerator(ClrDataAddress mt, out ISOSMethodEnum? enumerator);
665697
}
666698

667699
[GeneratedComInterface]

0 commit comments

Comments
 (0)