[cdac] Add GetArrayData to Object contract, partially implement ISOSDacInterface::GetObjectData#105534
Conversation
|
Tagging subscribers to this area: @tommcdon |
| private static readonly Target.TypeInfo MethodTableTypeInfo = new() | ||
| { | ||
| Fields = { | ||
| { nameof(Data.MethodTable.MTFlags), new() { Offset = 4, Type = DataType.uint32}}, | ||
| { nameof(Data.MethodTable.BaseSize), new() { Offset = 8, Type = DataType.uint32}}, | ||
| { nameof(Data.MethodTable.MTFlags2), new() { Offset = 12, Type = DataType.uint32}}, | ||
| { nameof(Data.MethodTable.EEClassOrCanonMT), new () { Offset = 16, Type = DataType.nuint}}, | ||
| { nameof(Data.MethodTable.Module), new () { Offset = 24, Type = DataType.pointer}}, | ||
| { nameof(Data.MethodTable.ParentMethodTable), new () { Offset = 40, Type = DataType.pointer}}, | ||
| { nameof(Data.MethodTable.NumInterfaces), new () { Offset = 48, Type = DataType.uint16}}, | ||
| { nameof(Data.MethodTable.NumVirtuals), new () { Offset = 50, Type = DataType.uint16}}, | ||
| { nameof(Data.MethodTable.PerInstInfo), new () { Offset = 56, Type = DataType.pointer}}, | ||
| } | ||
| }; | ||
|
|
||
| private static readonly Target.TypeInfo EEClassTypeInfo = new Target.TypeInfo() | ||
| { | ||
| Fields = { | ||
| { nameof (Data.EEClass.MethodTable), new () { Offset = 8, Type = DataType.pointer}}, | ||
| { nameof (Data.EEClass.CorTypeAttr), new () { Offset = 16, Type = DataType.uint32}}, | ||
| { nameof (Data.EEClass.NumMethods), new () { Offset = 20, Type = DataType.uint16}}, | ||
| { nameof (Data.EEClass.InternalCorElementType), new () { Offset = 22, Type = DataType.uint8}}, | ||
| { nameof (Data.EEClass.NumNonVirtualSlots), new () { Offset = 24, Type = DataType.uint16}}, | ||
| } | ||
| }; |
There was a problem hiding this comment.
These were copied out of MethodTableTests
| }, | ||
| }; | ||
|
|
||
| public static class RuntimeTypeSystem |
There was a problem hiding this comment.
With the exception of AddGlobalPointers and AddArrayClass, these were copied out of MethodTableTests
| private static MockMemorySpace.Builder AddStringMethodTablePointer(TargetTestHelpers targetTestHelpers, MockMemorySpace.Builder builder) | ||
| { | ||
| MockMemorySpace.HeapFragment fragment = new() { Name = "Address of String Method Table", Address = TestStringMethodTableGlobalAddress, Data = new byte[targetTestHelpers.PointerSize] }; | ||
| targetTestHelpers.WritePointer(fragment.Data, TestStringMethodTableAddress); | ||
| return builder.AddHeapFragments([ | ||
| fragment, | ||
| new () { Name = "String Method Table", Address = TestStringMethodTableAddress, Data = new byte[targetTestHelpers.PointerSize] } | ||
| ]); | ||
| } | ||
|
|
||
| internal static MockMemorySpace.Builder AddObject(TargetTestHelpers targetTestHelpers, MockMemorySpace.Builder builder, TargetPointer address, TargetPointer methodTable) | ||
| { | ||
| MockMemorySpace.HeapFragment fragment = new() { Name = $"Object : MT = '{methodTable}'", Address = address, Data = new byte[targetTestHelpers.SizeOfTypeInfo(ObjectTypeInfo)] }; | ||
| Span<byte> dest = fragment.Data; | ||
| targetTestHelpers.WritePointer(dest.Slice(ObjectTypeInfo.Fields["m_pMethTab"].Offset), methodTable); | ||
| return builder.AddHeapFragment(fragment); | ||
| } | ||
|
|
||
| internal static MockMemorySpace.Builder AddStringObject(TargetTestHelpers targetTestHelpers, MockMemorySpace.Builder builder, TargetPointer address, string value) | ||
| { | ||
| int size = targetTestHelpers.SizeOfTypeInfo(ObjectTypeInfo) + targetTestHelpers.SizeOfTypeInfo(StringTypeInfo) + value.Length * sizeof(char); | ||
| MockMemorySpace.HeapFragment fragment = new() { Name = $"String = '{value}'", Address = address, Data = new byte[size] }; | ||
| Span<byte> dest = fragment.Data; | ||
| targetTestHelpers.WritePointer(dest.Slice(ObjectTypeInfo.Fields["m_pMethTab"].Offset), TestStringMethodTableAddress); | ||
| targetTestHelpers.Write(dest.Slice(StringTypeInfo.Fields["m_StringLength"].Offset), (uint)value.Length); | ||
| MemoryMarshal.Cast<char, byte>(value).CopyTo(dest.Slice(StringTypeInfo.Fields["m_FirstChar"].Offset)); | ||
| return builder.AddHeapFragment(fragment); | ||
| } |
There was a problem hiding this comment.
These were copied out of ObjectTests
| { | ||
| static constexpr size_t m_NumComponents = offsetof(ArrayBase, m_NumComponents); | ||
|
|
||
| static constexpr INT32* s_arrayBoundsZero = &ArrayBase::s_arrayBoundsZero; |
There was a problem hiding this comment.
I put this in here to expose the static without just making it public, but it is a bit weird to be under cdac_offsets. Do we want to rename offsets to something more general about cdac info? Or we could add something like a separate template<typename T> struct cdac_globals.
There was a problem hiding this comment.
I think we should rename it. in #104999 Jeremy is adding some cdac_offsets<Foo>::NestedStructSize constants because Foo has a private NestedStruct.
We could just name it cdac<T> or data_contract<T>
There was a problem hiding this comment.
Will rename to cdac<T> in a follow-up.
| // For an object pointer, this attempts to read the number of components. | ||
| // This expects that the first member after the MethodTable pointer (from Object) | ||
| // is a 32-bit integer representing the number of components. | ||
| // This holds for ArrayBase and StringObject - see coreclr/vm/object.h |
There was a problem hiding this comment.
Is there better / more explicit comments or doc that I could point to here?
Arraydata descriptorGetArrayDatatoObjectcontractRuntimeTypeSystemcontractISOSDacInterface::GetObjectDataexcept for handling CCW/RCWsContributes to #99302
Ran SOS unit tests from the dotnet/diagnostics repo using a private build to replace the two latest runtimes (not the one that matches the sdk) used in the tests.