From cee98fee30a0491527ec4097fcabb9013e4908e4 Mon Sep 17 00:00:00 2001 From: rcj1 Date: Thu, 31 Jul 2025 15:35:01 -0700 Subject: [PATCH 1/3] adding IsTrackedType and GetTaggedMemory cDAC APIs --- docs/design/datacontracts/Object.md | 27 ++++++ .../design/datacontracts/RuntimeTypeSystem.md | 3 + .../debug/runtimeinfo/datadescriptor.inc | 3 + src/coreclr/vm/syncblk.h | 3 + .../tests/SignedCms/SignedCmsTests.cs | 3 +- .../Contracts/IObject.cs | 1 + .../Contracts/IRuntimeTypeSystem.cs | 2 +- .../Contracts/Object_1.cs | 6 ++ .../Contracts/RuntimeTypeSystem_1.cs | 1 + .../Data/InteropSyncBlockInfo.cs | 4 + .../MethodTableFlags_1.cs | 3 +- .../Legacy/SOSDacImpl.cs | 86 ++++++++++++++++++- 12 files changed, 136 insertions(+), 6 deletions(-) diff --git a/docs/design/datacontracts/Object.md b/docs/design/datacontracts/Object.md index 18747df027df3c..ed81b041a8b657 100644 --- a/docs/design/datacontracts/Object.md +++ b/docs/design/datacontracts/Object.md @@ -16,6 +16,9 @@ TargetPointer GetArrayData(TargetPointer address, out uint count, out TargetPoin // Get built-in COM data for the object if available. Returns false, if address does not represent a COM object using built-in COM bool GetBuiltInComData(TargetPointer address, out TargetPointer rcw, out TargetPointer ccw); + +// Get the object's tagged memory (if it exists). +public TargetPointer? TaggedMemory(TargetPointer address); ``` ## Version 1 @@ -26,6 +29,7 @@ Data descriptors used: | `Array` | `m_NumComponents` | Number of items in the array | | `InteropSyncBlockInfo` | `RCW` | Pointer to the RCW for the object (if it exists) | | `InteropSyncBlockInfo` | `CCW` | Pointer to the CCW for the object (if it exists) | +| `InteropSyncBlockInfo` | `TaggedMemory` | Pointer to the tagged memory for the object (if it exists) | | `Object` | `m_pMethTab` | Method table for the object | | `String` | `m_FirstChar` | First character of the string - `m_StringLength` can be used to read the full string (encoded in UTF-16) | | `String` | `m_StringLength` | Length of the string in characters (encoded in UTF-16) | @@ -125,4 +129,27 @@ bool GetBuiltInComData(TargetPointer address, out TargetPointer rcw, out TargetP ccw = target.ReadPointer(interopInfo + /* InteropSyncBlockInfo::CCW offset */); return rcw != TargetPointer.Null && ccw != TargetPointer.Null; } + +TargetPointer? TaggedMemory(TargetPointer address) +{ + uint syncBlockValue = target.Read(address - _target.ReadGlobal("SyncBlockValueToObjectOffset")); + + // Check if the sync block value represents a sync block index + if ((syncBlockValue & (uint)(SyncBlockValue.Bits.IsHashCodeOrSyncBlockIndex | SyncBlockValue.Bits.IsHashCode)) != (uint)SyncBlockValue.Bits.IsHashCodeOrSyncBlockIndex) + return null; + + // Get the offset into the sync table entries + uint index = syncBlockValue & SyncBlockValue.SyncBlockIndexMask; + ulong offsetInSyncTableEntries = index * /* SyncTableEntry size */; + + TargetPointer syncBlock = target.ReadPointer(_syncTableEntries + offsetInSyncTableEntries + /* SyncTableEntry::SyncBlock offset */); + if (syncBlock == TargetPointer.Null) + return null; + + TargetPointer interopInfo = target.ReadPointer(syncBlock + /* SyncTableEntry::InteropInfo offset */); + if (interopInfo == TargetPointer.Null) + return null; + + return target.ReadPointer(interopInfo + /* InteropSyncBlockInfo::TaggedMemory offset */); +} ``` diff --git a/docs/design/datacontracts/RuntimeTypeSystem.md b/docs/design/datacontracts/RuntimeTypeSystem.md index 77980940d829ee..172fd5dc2375de 100644 --- a/docs/design/datacontracts/RuntimeTypeSystem.md +++ b/docs/design/datacontracts/RuntimeTypeSystem.md @@ -63,6 +63,7 @@ partial interface IRuntimeTypeSystem : IContract public ushort GetNumStaticFields(TypeHandle typeHandle); public ushort GetNumThreadStaticFields(TypeHandle typeHandle); public TargetPointer GetFieldDescList(TypeHandle typeHandle); + public bool IsTrackedReferenceWithFinalizer(TypeHandle typeHandle); public virtual ReadOnlySpan GetInstantiation(TypeHandle typeHandle); public virtual bool IsGenericTypeDefinition(TypeHandle typeHandle); @@ -459,6 +460,8 @@ The contract additionally depends on these data descriptors public ushort GetNumThreadStaticFields(TypeHandle typeHandle) => !typeHandle.IsMethodTable() ? (ushort)0 : GetClassData(typeHandle).NumThreadStaticFields; public TargetPointer GetFieldDescList(TypeHandle typeHandle) => !typeHandle.IsMethodTable() ? TargetPointer.Null : GetClassData(typeHandle).FieldDescList; + public bool IsTrackedReferenceWithFinalizer(TypeHandle typeHandle) => !typeHandle.IsMethodTable() ? false : _methodTables[typeHandle.Address].Flags.GetFlag(MethodTableFlags_1.WFLAGS_HIGH.IsTrackedReferenceWithFinalizer) != 0; + public ReadOnlySpan GetInstantiation(TypeHandle TypeHandle) { diff --git a/src/coreclr/debug/runtimeinfo/datadescriptor.inc b/src/coreclr/debug/runtimeinfo/datadescriptor.inc index f28496e5c9b7d3..6077373bcda7fe 100644 --- a/src/coreclr/debug/runtimeinfo/datadescriptor.inc +++ b/src/coreclr/debug/runtimeinfo/datadescriptor.inc @@ -201,6 +201,9 @@ CDAC_TYPE_INDETERMINATE(InteropSyncBlockInfo) CDAC_TYPE_FIELD(InteropSyncBlockInfo, /*pointer*/, CCW, cdac_data::CCW) CDAC_TYPE_FIELD(InteropSyncBlockInfo, /*pointer*/, RCW, cdac_data::RCW) #endif // FEATURE_COMINTEROP +#ifdef FEATURE_OBJCMARSHAL +CDAC_TYPE_FIELD(InteropSyncBlockInfo, /*pointer*/, TaggedMemory, cdac_data::TaggedMemory) +#endif // FEATURE_OBJCMARSHAL CDAC_TYPE_END(InteropSyncBlockInfo) CDAC_TYPE_BEGIN(SyncBlock) diff --git a/src/coreclr/vm/syncblk.h b/src/coreclr/vm/syncblk.h index efd0c7c5437e78..cd18826a50de3e 100644 --- a/src/coreclr/vm/syncblk.h +++ b/src/coreclr/vm/syncblk.h @@ -832,6 +832,9 @@ struct cdac_data #ifdef FEATURE_COMINTEROP static constexpr size_t CCW = offsetof(InteropSyncBlockInfo, m_pCCW); static constexpr size_t RCW = offsetof(InteropSyncBlockInfo, m_pRCW); +#endif +#ifdef FEATURE_OBJCMARSHAL + static constexpr size_t TaggedMemory = offsetof(InteropSyncBlockInfo, m_taggedMemory); #endif // FEATURE_COMINTEROP }; diff --git a/src/libraries/System.Security.Cryptography.Pkcs/tests/SignedCms/SignedCmsTests.cs b/src/libraries/System.Security.Cryptography.Pkcs/tests/SignedCms/SignedCmsTests.cs index b1d0d480c05b12..d2f8396eb7f7a4 100644 --- a/src/libraries/System.Security.Cryptography.Pkcs/tests/SignedCms/SignedCmsTests.cs +++ b/src/libraries/System.Security.Cryptography.Pkcs/tests/SignedCms/SignedCmsTests.cs @@ -1848,8 +1848,7 @@ public static void ComputeSignature_SlhDsa_DefaultDigest() useSigner => { using (X509Certificate2 cert = Certificates.SlhDsaSha2_128s_Ietf.GetCertificate()) - using (SlhDsa key = SlhDsa.ImportSlhDsaSecretKey(SlhDsaAlgorithm.SlhDsaSha2_128s, SlhDsaTestData.IetfSlhDsaSha2_128sPrivateKeyValue)) - { + using (SlhDsa key = SlhDsa.ImportSlhDsaPrivateKey(SlhDsaAlgorithm.SlhDsaSha2_128s, SlhDsaTestData.IetfSlhDsaSha2_128sPrivateKeyValue)) { useSigner(new CmsSigner(SubjectIdentifierType.SubjectKeyIdentifier, cert, key)); } }); diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IObject.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IObject.cs index 7566ddacc1e488..8aa748a7e8cf29 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IObject.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IObject.cs @@ -12,6 +12,7 @@ public interface IObject : IContract string GetStringValue(TargetPointer address) => throw new NotImplementedException(); TargetPointer GetArrayData(TargetPointer address, out uint count, out TargetPointer boundsStart, out TargetPointer lowerBounds) => throw new NotImplementedException(); bool GetBuiltInComData(TargetPointer address, out TargetPointer rcw, out TargetPointer ccw) => throw new NotImplementedException(); + TargetPointer? TaggedMemory(TargetPointer address) => throw new NotImplementedException(); } public readonly struct Object : IObject diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IRuntimeTypeSystem.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IRuntimeTypeSystem.cs index 0fb29e318c1d42..7ddf48d3c008dd 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IRuntimeTypeSystem.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IRuntimeTypeSystem.cs @@ -110,7 +110,7 @@ public interface IRuntimeTypeSystem : IContract ushort GetNumStaticFields(TypeHandle typeHandle) => throw new NotImplementedException(); ushort GetNumThreadStaticFields(TypeHandle typeHandle) => throw new NotImplementedException(); TargetPointer GetFieldDescList(TypeHandle typeHandle) => throw new NotImplementedException(); - + bool IsTrackedReferenceWithFinalizer(TypeHandle typeHandle) => throw new NotImplementedException(); ReadOnlySpan GetInstantiation(TypeHandle typeHandle) => throw new NotImplementedException(); bool IsGenericTypeDefinition(TypeHandle typeHandle) => throw new NotImplementedException(); diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Object_1.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Object_1.cs index d35b683f028fb1..ccb3023a73d540 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Object_1.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Object_1.cs @@ -115,6 +115,12 @@ public bool GetBuiltInComData(TargetPointer address, out TargetPointer rcw, out return rcw != TargetPointer.Null || ccw != TargetPointer.Null; } + public TargetPointer? TaggedMemory(TargetPointer address) + { + Data.SyncBlock? syncBlock = GetSyncBlock(address); + return syncBlock?.InteropInfo?.TaggedMemory; + } + private Data.SyncBlock? GetSyncBlock(TargetPointer address) { uint syncBlockValue = _target.Read(address - _target.ReadGlobal(Constants.Globals.SyncBlockValueToObjectOffset)); diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeTypeSystem_1.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeTypeSystem_1.cs index 7386d59628fcbd..d5eff239504aec 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeTypeSystem_1.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeTypeSystem_1.cs @@ -393,6 +393,7 @@ public uint GetTypeDefToken(TypeHandle typeHandle) public ushort GetNumStaticFields(TypeHandle typeHandle) => !typeHandle.IsMethodTable() ? (ushort)0 : GetClassData(typeHandle).NumStaticFields; public ushort GetNumThreadStaticFields(TypeHandle typeHandle) => !typeHandle.IsMethodTable() ? (ushort)0 : GetClassData(typeHandle).NumThreadStaticFields; public TargetPointer GetFieldDescList(TypeHandle typeHandle) => !typeHandle.IsMethodTable() ? TargetPointer.Null : GetClassData(typeHandle).FieldDescList; + public bool IsTrackedReferenceWithFinalizer(TypeHandle typeHandle) => !typeHandle.IsMethodTable() ? false : _methodTables[typeHandle.Address].Flags.GetFlag(MethodTableFlags_1.WFLAGS_HIGH.IsTrackedReferenceWithFinalizer) != 0; public ReadOnlySpan GetInstantiation(TypeHandle typeHandle) diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/InteropSyncBlockInfo.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/InteropSyncBlockInfo.cs index cffa804296de30..0520095cd12351 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/InteropSyncBlockInfo.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/InteropSyncBlockInfo.cs @@ -18,8 +18,12 @@ public InteropSyncBlockInfo(Target target, TargetPointer address) CCW = type.Fields.TryGetValue(nameof(CCW), out Target.FieldInfo ccwField) ? target.ReadPointer(address + (ulong)ccwField.Offset) : TargetPointer.Null; + TaggedMemory = type.Fields.TryGetValue(nameof(TaggedMemory), out Target.FieldInfo taggedMemoryField) + ? target.ReadPointer(address + (ulong)taggedMemoryField.Offset) + : TargetPointer.Null; } public TargetPointer RCW { get; init; } public TargetPointer CCW { get; init; } + public TargetPointer TaggedMemory { get; init; } } diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/RuntimeTypeSystemHelpers/MethodTableFlags_1.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/RuntimeTypeSystemHelpers/MethodTableFlags_1.cs index 0998d5c22c5d7b..063a3e55738a96 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/RuntimeTypeSystemHelpers/MethodTableFlags_1.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/RuntimeTypeSystemHelpers/MethodTableFlags_1.cs @@ -46,7 +46,8 @@ internal enum WFLAGS_HIGH : uint Category_Interface = 0x000C0000, ContainsGCPointers = 0x01000000, HasComponentSize = 0x80000000, // This is set if lower 16 bits is used for the component size, - // otherwise the lower bits are used for WFLAGS_LOW + // otherwise the lower bits are used for WFLAGS_LOW + IsTrackedReferenceWithFinalizer = 0x04000000 } [Flags] diff --git a/src/native/managed/cdac/mscordaccore_universal/Legacy/SOSDacImpl.cs b/src/native/managed/cdac/mscordaccore_universal/Legacy/SOSDacImpl.cs index 39506ca13fd373..01c47c35edf407 100644 --- a/src/native/managed/cdac/mscordaccore_universal/Legacy/SOSDacImpl.cs +++ b/src/native/managed/cdac/mscordaccore_universal/Legacy/SOSDacImpl.cs @@ -2350,9 +2350,91 @@ int ISOSDacInterface10.GetComWrappersRCWData(ClrDataAddress rcw, ClrDataAddress* #region ISOSDacInterface11 int ISOSDacInterface11.IsTrackedType(ClrDataAddress objAddr, Interop.BOOL* isTrackedType, Interop.BOOL* hasTaggedMemory) - => _legacyImpl11 is not null ? _legacyImpl11.IsTrackedType(objAddr, isTrackedType, hasTaggedMemory) : HResults.E_NOTIMPL; + { + int hr = HResults.S_OK; + if (objAddr == 0 || isTrackedType == null || hasTaggedMemory == null) + hr = HResults.E_INVALIDARG; + + try + { + Contracts.IObject objectContract = _target.Contracts.Object; + Contracts.IRuntimeTypeSystem rtsContract = _target.Contracts.RuntimeTypeSystem; + TargetPointer objPtr = objAddr.ToTargetPointer(_target); + TargetPointer mt = objectContract.GetMethodTableAddress(objPtr); + if (mt == TargetPointer.Null) + hr = HResults.E_INVALIDARG; + else + { + TypeHandle mtHandle = rtsContract.GetTypeHandle(mt); + *isTrackedType = rtsContract.IsTrackedReferenceWithFinalizer(mtHandle) ? Interop.BOOL.TRUE : Interop.BOOL.FALSE; + hr = (*isTrackedType == Interop.BOOL.TRUE) ? HResults.S_OK : HResults.S_FALSE; + TargetPointer? taggedMemory = objectContract.TaggedMemory(objPtr); + *hasTaggedMemory = (taggedMemory != null && taggedMemory != TargetPointer.Null) ? Interop.BOOL.TRUE : Interop.BOOL.FALSE; + } + } + catch (System.Exception ex) + { + hr = ex.HResult; + } +#if DEBUG + if (_legacyImpl11 is not null) + { + Interop.BOOL isTrackedTypeLocal; + Interop.BOOL hasTaggedMemoryLocal; + int hrLocal = _legacyImpl11.IsTrackedType(objAddr, &isTrackedTypeLocal, &hasTaggedMemoryLocal); + Debug.Assert(hrLocal == hr, $"cDAC: {hr:x}, DAC: {hrLocal:x}"); + if (hr == HResults.S_OK || hr == HResults.S_FALSE) + { + Debug.Assert(*isTrackedType == isTrackedTypeLocal); + Debug.Assert(*hasTaggedMemory == hasTaggedMemoryLocal); + } + } +#endif + return hr; + } int ISOSDacInterface11.GetTaggedMemory(ClrDataAddress objAddr, ClrDataAddress* taggedMemory, nuint* taggedMemorySizeInBytes) - => _legacyImpl11 is not null ? _legacyImpl11.GetTaggedMemory(objAddr, taggedMemory, taggedMemorySizeInBytes) : HResults.E_NOTIMPL; + { + int hr = HResults.S_OK; + if (objAddr == 0 || taggedMemory == null || taggedMemorySizeInBytes == null) + hr = HResults.E_INVALIDARG; + + *taggedMemory = 0; + *taggedMemorySizeInBytes = 0; + try + { + Contracts.IObject objectContract = _target.Contracts.Object; + TargetPointer objPtr = objAddr.ToTargetPointer(_target); + TargetPointer? taggedMemoryPtr = objectContract.TaggedMemory(objPtr); + if (taggedMemoryPtr != null) + { + *taggedMemory = taggedMemoryPtr.Value.ToClrDataAddress(_target); + *taggedMemorySizeInBytes = 2 * (nuint)_target.PointerSize; + } + else + { + hr = HResults.S_FALSE; + } + } + catch (System.Exception ex) + { + hr = ex.HResult; + } +#if DEBUG + if (_legacyImpl11 is not null) + { + ClrDataAddress taggedMemoryLocal; + nuint taggedMemorySizeInBytesLocal; + int hrLocal = _legacyImpl11.GetTaggedMemory(objAddr, &taggedMemoryLocal, &taggedMemorySizeInBytesLocal); + Debug.Assert(hrLocal == hr, $"cDAC: {hr:x}, DAC: {hrLocal:x}"); + if (hr == HResults.S_OK || hr == HResults.S_FALSE) + { + Debug.Assert(*taggedMemory == taggedMemoryLocal); + Debug.Assert(*taggedMemorySizeInBytes == taggedMemorySizeInBytesLocal); + } + } +#endif + return hr; + } #endregion ISOSDacInterface11 #region ISOSDacInterface12 From 58b3230c392d6e70e5f120165bb5f934d499e615 Mon Sep 17 00:00:00 2001 From: rcj1 Date: Thu, 31 Jul 2025 16:22:52 -0700 Subject: [PATCH 2/3] if else --- .../Legacy/SOSDacImpl.cs | 72 ++++++++++--------- 1 file changed, 38 insertions(+), 34 deletions(-) diff --git a/src/native/managed/cdac/mscordaccore_universal/Legacy/SOSDacImpl.cs b/src/native/managed/cdac/mscordaccore_universal/Legacy/SOSDacImpl.cs index 01c47c35edf407..084a51d868a087 100644 --- a/src/native/managed/cdac/mscordaccore_universal/Legacy/SOSDacImpl.cs +++ b/src/native/managed/cdac/mscordaccore_universal/Legacy/SOSDacImpl.cs @@ -2354,27 +2354,29 @@ int ISOSDacInterface11.IsTrackedType(ClrDataAddress objAddr, Interop.BOOL* isTra int hr = HResults.S_OK; if (objAddr == 0 || isTrackedType == null || hasTaggedMemory == null) hr = HResults.E_INVALIDARG; - - try + else { - Contracts.IObject objectContract = _target.Contracts.Object; - Contracts.IRuntimeTypeSystem rtsContract = _target.Contracts.RuntimeTypeSystem; - TargetPointer objPtr = objAddr.ToTargetPointer(_target); - TargetPointer mt = objectContract.GetMethodTableAddress(objPtr); - if (mt == TargetPointer.Null) - hr = HResults.E_INVALIDARG; - else + try { - TypeHandle mtHandle = rtsContract.GetTypeHandle(mt); - *isTrackedType = rtsContract.IsTrackedReferenceWithFinalizer(mtHandle) ? Interop.BOOL.TRUE : Interop.BOOL.FALSE; - hr = (*isTrackedType == Interop.BOOL.TRUE) ? HResults.S_OK : HResults.S_FALSE; - TargetPointer? taggedMemory = objectContract.TaggedMemory(objPtr); - *hasTaggedMemory = (taggedMemory != null && taggedMemory != TargetPointer.Null) ? Interop.BOOL.TRUE : Interop.BOOL.FALSE; + Contracts.IObject objectContract = _target.Contracts.Object; + Contracts.IRuntimeTypeSystem rtsContract = _target.Contracts.RuntimeTypeSystem; + TargetPointer objPtr = objAddr.ToTargetPointer(_target); + TargetPointer mt = objectContract.GetMethodTableAddress(objPtr); + if (mt == TargetPointer.Null) + hr = HResults.E_INVALIDARG; + else + { + TypeHandle mtHandle = rtsContract.GetTypeHandle(mt); + *isTrackedType = rtsContract.IsTrackedReferenceWithFinalizer(mtHandle) ? Interop.BOOL.TRUE : Interop.BOOL.FALSE; + hr = (*isTrackedType == Interop.BOOL.TRUE) ? HResults.S_OK : HResults.S_FALSE; + TargetPointer? taggedMemory = objectContract.TaggedMemory(objPtr); + *hasTaggedMemory = (taggedMemory != null && taggedMemory != TargetPointer.Null) ? Interop.BOOL.TRUE : Interop.BOOL.FALSE; + } + } + catch (System.Exception ex) + { + hr = ex.HResult; } - } - catch (System.Exception ex) - { - hr = ex.HResult; } #if DEBUG if (_legacyImpl11 is not null) @@ -2397,28 +2399,30 @@ int ISOSDacInterface11.GetTaggedMemory(ClrDataAddress objAddr, ClrDataAddress* t int hr = HResults.S_OK; if (objAddr == 0 || taggedMemory == null || taggedMemorySizeInBytes == null) hr = HResults.E_INVALIDARG; - - *taggedMemory = 0; - *taggedMemorySizeInBytes = 0; - try + else { - Contracts.IObject objectContract = _target.Contracts.Object; - TargetPointer objPtr = objAddr.ToTargetPointer(_target); - TargetPointer? taggedMemoryPtr = objectContract.TaggedMemory(objPtr); - if (taggedMemoryPtr != null) + *taggedMemory = 0; + *taggedMemorySizeInBytes = 0; + try { - *taggedMemory = taggedMemoryPtr.Value.ToClrDataAddress(_target); - *taggedMemorySizeInBytes = 2 * (nuint)_target.PointerSize; + Contracts.IObject objectContract = _target.Contracts.Object; + TargetPointer objPtr = objAddr.ToTargetPointer(_target); + TargetPointer? taggedMemoryPtr = objectContract.TaggedMemory(objPtr); + if (taggedMemoryPtr != null) + { + *taggedMemory = taggedMemoryPtr.Value.ToClrDataAddress(_target); + *taggedMemorySizeInBytes = 2 * (nuint)_target.PointerSize; + } + else + { + hr = HResults.S_FALSE; + } } - else + catch (System.Exception ex) { - hr = HResults.S_FALSE; + hr = ex.HResult; } } - catch (System.Exception ex) - { - hr = ex.HResult; - } #if DEBUG if (_legacyImpl11 is not null) { From d3a447d73a0f67558a7acbd234f46c26eb3326b0 Mon Sep 17 00:00:00 2001 From: rcj1 Date: Fri, 1 Aug 2025 13:14:39 -0700 Subject: [PATCH 3/3] restructuring --- docs/design/datacontracts/Object.md | 26 ++++++++++++------- .../Contracts/IObject.cs | 3 ++- .../Contracts/Object_1.cs | 11 ++++++-- .../MethodTableFlags_1.cs | 2 +- .../Legacy/SOSDacImpl.cs | 18 ++++++++----- 5 files changed, 40 insertions(+), 20 deletions(-) diff --git a/docs/design/datacontracts/Object.md b/docs/design/datacontracts/Object.md index ed81b041a8b657..87b8b96981e83a 100644 --- a/docs/design/datacontracts/Object.md +++ b/docs/design/datacontracts/Object.md @@ -18,7 +18,10 @@ TargetPointer GetArrayData(TargetPointer address, out uint count, out TargetPoin bool GetBuiltInComData(TargetPointer address, out TargetPointer rcw, out TargetPointer ccw); // Get the object's tagged memory (if it exists). -public TargetPointer? TaggedMemory(TargetPointer address); +TargetPointer TaggedMemory(TargetPointer address); + +// Get the tagged memory size (if applicable). +nuint GetTaggedMemorySize(); ``` ## Version 1 @@ -97,17 +100,17 @@ TargetPointer GetArrayData(TargetPointer address, out uint count, out TargetPoin { // Single-dimensional, zero-based - doesn't have bounds boundsStart = address + /* Array::m_NumComponents offset */; - lowerBounds = _target.ReadGlobalPointer("ArrayBoundsZero"); + lowerBounds = target.ReadGlobalPointer("ArrayBoundsZero"); } // Sync block is before `this` pointer, so substract the object header size - ulong dataOffset = typeSystemContract.GetBaseSize(typeHandle) - _target.ReadGlobal("ObjectHeaderSize"); + ulong dataOffset = typeSystemContract.GetBaseSize(typeHandle) - target.ReadGlobal("ObjectHeaderSize"); return address + dataOffset; } bool GetBuiltInComData(TargetPointer address, out TargetPointer rcw, out TargetPointer ccw); { - uint syncBlockValue = target.Read(address - _target.ReadGlobal("SyncBlockValueToObjectOffset")); + uint syncBlockValue = target.Read(address - target.ReadGlobal("SyncBlockValueToObjectOffset")); // Check if the sync block value represents a sync block index if ((syncBlockValue & (uint)(SyncBlockValue.Bits.IsHashCodeOrSyncBlockIndex | SyncBlockValue.Bits.IsHashCode)) != (uint)SyncBlockValue.Bits.IsHashCodeOrSyncBlockIndex) @@ -130,13 +133,13 @@ bool GetBuiltInComData(TargetPointer address, out TargetPointer rcw, out TargetP return rcw != TargetPointer.Null && ccw != TargetPointer.Null; } -TargetPointer? TaggedMemory(TargetPointer address) +TargetPointer TaggedMemory(TargetPointer address) { - uint syncBlockValue = target.Read(address - _target.ReadGlobal("SyncBlockValueToObjectOffset")); + uint syncBlockValue = target.Read(address - target.ReadGlobal("SyncBlockValueToObjectOffset")); // Check if the sync block value represents a sync block index if ((syncBlockValue & (uint)(SyncBlockValue.Bits.IsHashCodeOrSyncBlockIndex | SyncBlockValue.Bits.IsHashCode)) != (uint)SyncBlockValue.Bits.IsHashCodeOrSyncBlockIndex) - return null; + return TargetPointer.Null; // Get the offset into the sync table entries uint index = syncBlockValue & SyncBlockValue.SyncBlockIndexMask; @@ -144,12 +147,17 @@ TargetPointer? TaggedMemory(TargetPointer address) TargetPointer syncBlock = target.ReadPointer(_syncTableEntries + offsetInSyncTableEntries + /* SyncTableEntry::SyncBlock offset */); if (syncBlock == TargetPointer.Null) - return null; + return TargetPointer.Null; TargetPointer interopInfo = target.ReadPointer(syncBlock + /* SyncTableEntry::InteropInfo offset */); if (interopInfo == TargetPointer.Null) - return null; + return TargetPointer.Null; return target.ReadPointer(interopInfo + /* InteropSyncBlockInfo::TaggedMemory offset */); } + +nuint GetTaggedMemorySize() +{ + return 2 * (nuint)target.PointerSize; +} ``` diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IObject.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IObject.cs index 8aa748a7e8cf29..64f31cdd906240 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IObject.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IObject.cs @@ -12,7 +12,8 @@ public interface IObject : IContract string GetStringValue(TargetPointer address) => throw new NotImplementedException(); TargetPointer GetArrayData(TargetPointer address, out uint count, out TargetPointer boundsStart, out TargetPointer lowerBounds) => throw new NotImplementedException(); bool GetBuiltInComData(TargetPointer address, out TargetPointer rcw, out TargetPointer ccw) => throw new NotImplementedException(); - TargetPointer? TaggedMemory(TargetPointer address) => throw new NotImplementedException(); + TargetPointer TaggedMemory(TargetPointer address) => throw new NotImplementedException(); + nuint GetTaggedMemorySize() => throw new NotImplementedException(); } public readonly struct Object : IObject diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Object_1.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Object_1.cs index ccb3023a73d540..4f87b0ac4801b2 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Object_1.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Object_1.cs @@ -14,6 +14,7 @@ namespace Microsoft.Diagnostics.DataContractReader.Contracts; private readonly byte _objectToMethodTableUnmask; private readonly TargetPointer _stringMethodTable; private readonly TargetPointer _syncTableEntries; + private readonly nuint _taggedMemorySize; private static class SyncBlockValue { @@ -37,6 +38,7 @@ internal Object_1(Target target, ulong methodTableOffset, byte objectToMethodTab _stringMethodTable = stringMethodTable; _objectToMethodTableUnmask = objectToMethodTableUnmask; _syncTableEntries = syncTableEntries; + _taggedMemorySize = 2 * (nuint)target.PointerSize; } public TargetPointer GetMethodTableAddress(TargetPointer address) @@ -115,10 +117,15 @@ public bool GetBuiltInComData(TargetPointer address, out TargetPointer rcw, out return rcw != TargetPointer.Null || ccw != TargetPointer.Null; } - public TargetPointer? TaggedMemory(TargetPointer address) + public TargetPointer TaggedMemory(TargetPointer address) { Data.SyncBlock? syncBlock = GetSyncBlock(address); - return syncBlock?.InteropInfo?.TaggedMemory; + return syncBlock?.InteropInfo?.TaggedMemory ?? TargetPointer.Null; + } + + public nuint GetTaggedMemorySize() + { + return _taggedMemorySize; } private Data.SyncBlock? GetSyncBlock(TargetPointer address) diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/RuntimeTypeSystemHelpers/MethodTableFlags_1.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/RuntimeTypeSystemHelpers/MethodTableFlags_1.cs index 063a3e55738a96..53e3da505819c4 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/RuntimeTypeSystemHelpers/MethodTableFlags_1.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/RuntimeTypeSystemHelpers/MethodTableFlags_1.cs @@ -45,9 +45,9 @@ internal enum WFLAGS_HIGH : uint Category_TruePrimitive = 0x00070000, Category_Interface = 0x000C0000, ContainsGCPointers = 0x01000000, + IsTrackedReferenceWithFinalizer = 0x04000000, HasComponentSize = 0x80000000, // This is set if lower 16 bits is used for the component size, // otherwise the lower bits are used for WFLAGS_LOW - IsTrackedReferenceWithFinalizer = 0x04000000 } [Flags] diff --git a/src/native/managed/cdac/mscordaccore_universal/Legacy/SOSDacImpl.cs b/src/native/managed/cdac/mscordaccore_universal/Legacy/SOSDacImpl.cs index 084a51d868a087..449f545e47a697 100644 --- a/src/native/managed/cdac/mscordaccore_universal/Legacy/SOSDacImpl.cs +++ b/src/native/managed/cdac/mscordaccore_universal/Legacy/SOSDacImpl.cs @@ -2358,6 +2358,8 @@ int ISOSDacInterface11.IsTrackedType(ClrDataAddress objAddr, Interop.BOOL* isTra { try { + *isTrackedType = Interop.BOOL.FALSE; + *hasTaggedMemory = Interop.BOOL.FALSE; Contracts.IObject objectContract = _target.Contracts.Object; Contracts.IRuntimeTypeSystem rtsContract = _target.Contracts.RuntimeTypeSystem; TargetPointer objPtr = objAddr.ToTargetPointer(_target); @@ -2367,10 +2369,12 @@ int ISOSDacInterface11.IsTrackedType(ClrDataAddress objAddr, Interop.BOOL* isTra else { TypeHandle mtHandle = rtsContract.GetTypeHandle(mt); - *isTrackedType = rtsContract.IsTrackedReferenceWithFinalizer(mtHandle) ? Interop.BOOL.TRUE : Interop.BOOL.FALSE; + if (rtsContract.IsTrackedReferenceWithFinalizer(mtHandle)) + *isTrackedType = Interop.BOOL.TRUE; hr = (*isTrackedType == Interop.BOOL.TRUE) ? HResults.S_OK : HResults.S_FALSE; - TargetPointer? taggedMemory = objectContract.TaggedMemory(objPtr); - *hasTaggedMemory = (taggedMemory != null && taggedMemory != TargetPointer.Null) ? Interop.BOOL.TRUE : Interop.BOOL.FALSE; + TargetPointer taggedMemory = objectContract.TaggedMemory(objPtr); + if (taggedMemory != TargetPointer.Null) + *hasTaggedMemory = Interop.BOOL.TRUE; } } catch (System.Exception ex) @@ -2407,11 +2411,11 @@ int ISOSDacInterface11.GetTaggedMemory(ClrDataAddress objAddr, ClrDataAddress* t { Contracts.IObject objectContract = _target.Contracts.Object; TargetPointer objPtr = objAddr.ToTargetPointer(_target); - TargetPointer? taggedMemoryPtr = objectContract.TaggedMemory(objPtr); - if (taggedMemoryPtr != null) + TargetPointer taggedMemoryPtr = objectContract.TaggedMemory(objPtr); + if (taggedMemoryPtr != TargetPointer.Null) { - *taggedMemory = taggedMemoryPtr.Value.ToClrDataAddress(_target); - *taggedMemorySizeInBytes = 2 * (nuint)_target.PointerSize; + *taggedMemory = taggedMemoryPtr.ToClrDataAddress(_target); + *taggedMemorySizeInBytes = objectContract.GetTaggedMemorySize(); } else {