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
4 changes: 2 additions & 2 deletions docs/design/datacontracts/DacStreams.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,8 @@ Following the EENameStream header, there are CountOfNames entries. Each entry be
``` csharp
string StringFromEEAddress(TargetPointer address)
{
TargetPointer miniMetaDataBuffAddress = _target.Read<uint>(_target.ReadGlobalPointer(Constants.Globals.MiniMetaDataBuffAddress));
uint miniMetaDataBuffMaxSize = _target.Read<uint>(_target.ReadGlobalPointer(Constants.Globals.MiniMetaDataBuffMaxSize));
TargetPointer miniMetaDataBuffAddress = _target.Read<uint>(_target.ReadGlobalPointer("MiniMetaDataBuffAddress"));
uint miniMetaDataBuffMaxSize = _target.Read<uint>(_target.ReadGlobalPointer("MiniMetaDataBuffMaxSize"));

// Parse MiniMetadataStream according the the format described above to produce a dictionary from pointer to string from the EENameStream.
// Then lookup in the dictionary, to produce a result if it was present in the table.
Expand Down
6 changes: 3 additions & 3 deletions docs/design/datacontracts/Loader.md
Original file line number Diff line number Diff line change
Expand Up @@ -284,14 +284,14 @@ IEnumerable<ModuleHandle> GetModuleHandles(TargetPointer appDomain, AssemblyIter

TargetPointer GetRootAssembly()
{
TargetPointer appDomainPointer = target.ReadGlobalPointer(Constants.Globals.AppDomain);
TargetPointer appDomainPointer = target.ReadGlobalPointer("AppDomain");
AppDomain appDomain = // read AppDomain object starting at appDomainPointer
return appDomain.RootAssembly;
}

string ILoader.GetAppDomainFriendlyName()
{
TargetPointer appDomainPointer = target.ReadGlobalPointer(Constants.Globals.AppDomain);
TargetPointer appDomainPointer = target.ReadGlobalPointer("AppDomain");
TargetPointer appDomain = target.ReadPointer(appDomainPointer)
TargetPointer pathStart = appDomain + /* AppDomain::FriendlyName offset */;
char[] name = // Read<char> from target starting at pathStart until null terminator
Expand Down Expand Up @@ -490,7 +490,7 @@ bool IsAssemblyLoaded(ModuleHandle handle)

TargetPointer GetGlobalLoaderAllocator()
{
TargetPointer systemDomainPointer = target.ReadGlobalPointer(Constants.Globals.SystemDomain);
TargetPointer systemDomainPointer = target.ReadGlobalPointer("SystemDomain");
TargetPointer systemDomain = target.ReadPointer(systemDomainPointer);
return target.ReadPointer(systemDomain + /* SystemDomain::GlobalLoaderAllocator offset */);
}
Expand Down
39 changes: 38 additions & 1 deletion docs/design/datacontracts/RuntimeTypeSystem.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ partial interface IRuntimeTypeSystem : IContract
public TargetPointer GetGCThreadStaticsBasePointer(TypeHandle typeHandle, TargetPointer threadPtr);
public TargetPointer GetNonGCThreadStaticsBasePointer(TypeHandle typeHandle, TargetPointer threadPtr);
public TargetPointer GetFieldDescList(TypeHandle typeHandle);
public TargetPointer GetGCStaticsBasePointer(TypeHandle typeHandle);
public TargetPointer GetNonGCStaticsBasePointer(TypeHandle typeHandle);
public virtual ReadOnlySpan<TypeHandle> GetInstantiation(TypeHandle typeHandle);
public virtual bool IsGenericTypeDefinition(TypeHandle typeHandle);

Expand Down Expand Up @@ -337,6 +339,7 @@ The contract depends on the following globals
| Global name | Meaning |
| --- | --- |
| `FreeObjectMethodTablePointer` | A pointer to the address of a `MethodTable` used by the GC to indicate reclaimed memory
| `StaticsPointerMask` | For masking out a bit of DynamicStaticsInfo pointer fields

The contract additionally depends on these data descriptors

Expand All @@ -351,6 +354,10 @@ The contract additionally depends on these data descriptors
| `MethodTable` | `NumInterfaces` | Number of interfaces of `MethodTable` |
| `MethodTable` | `NumVirtuals` | Number of virtual methods in `MethodTable` |
| `MethodTable` | `PerInstInfo` | Either the array element type, or pointer to generic information for `MethodTable` |
| `MethodTable` | `AuxiliaryData` | Pointer to the AuxiliaryData of a method table |
| `DynamicStaticsInfo` | `NonGCStatics` | Pointer to non-GC statics |
| `DynamicStaticsInfo` | `GCStatics` | Pointer to the GC statics |
| `DynamicStaticsInfo` | `Size` | Size of the data |
| `ThreadStaticsInfo` | `GCTlsIndex` | Pointer to GC thread local storage index |
| `ThreadStaticsInfo` | `NonGCTlsIndex` | Pointer to non-GC thread local storage index |
| `EEClass` | `InternalCorElementType` | An InternalCorElementType uses the enum values of a CorElementType to indicate some of the information about the type of the type which uses the EEClass In particular, all reference types are CorElementType.Class, Enums are the element type of their underlying type and ValueTypes which can exactly be represented as an element type are represented as such, all other values types are represented as CorElementType.ValueType. |
Expand Down Expand Up @@ -472,6 +479,36 @@ Contracts used:

public TargetPointer GetFieldDescList(TypeHandle typeHandle) => !typeHandle.IsMethodTable() ? TargetPointer.Null : GetClassData(typeHandle).FieldDescList;

public TargetPointer GetGCStaticsBasePointer(TypeHandle typeHandle)
{
if (!typeHandle.IsMethodTable())
return TargetPointer.Null;

MethodTable methodTable = _methodTables[typeHandle.Address];
if (!methodTable.Flags.IsDynamicStatics)
return TargetPointer.Null;
TargetPointer dynamicStaticsInfoSize = target.GetTypeInfo(DataType.DynamicStaticsInfo).Size!.Value;
TargetPointer mask = target.ReadGlobalPointer("StaticsPointerMask");

TargetPointer dynamicStaticsInfo = methodTable.AuxiliaryData - dynamicStaticsInfoSize;
return (target.ReadPointer(dynamicStaticsInfo + /* DynamicStaticsInfo::GCStatics offset */) & (ulong)mask);
}

public TargetPointer GetNonGCStaticsBasePointer(TypeHandle typeHandle)
{
if (!typeHandle.IsMethodTable())
return TargetPointer.Null;

MethodTable methodTable = _methodTables[typeHandle.Address];
if (!methodTable.Flags.IsDynamicStatics)
return TargetPointer.Null;
TargetPointer dynamicStaticsInfoSize = target.GetTypeInfo(DataType.DynamicStaticsInfo).Size!.Value;
TargetPointer mask = target.ReadGlobalPointer("StaticsPointerMask");

TargetPointer dynamicStaticsInfo = methodTable.AuxiliaryData - dynamicStaticsInfoSize;
return (target.ReadPointer(dynamicStaticsInfo + /* DynamicStaticsInfo::NonGCStatics offset */) & (ulong)mask);
}

public TargetPointer GetGCThreadStaticsBasePointer(TypeHandle typeHandle, TargetPointer threadPtr)
{
if (!typeHandle.IsMethodTable())
Expand Down Expand Up @@ -918,7 +955,7 @@ And the various apis are implemented with the following algorithms

ushort FlagsAndTokenRange = // Read FlagsAndTokenRange field from MethodDescChunk contract using address methodDescChunk

int tokenRemainderBitCount = _target.ReadGlobal<byte>(Constants.Globals.MethodDescTokenRemainderBitCount);
int tokenRemainderBitCount = _target.ReadGlobal<byte>("MethodDescTokenRemainderBitCount");
int tokenRangeBitCount = 24 - tokenRemainderBitCount;
uint allRidBitsSet = 0xFFFFFF;
uint tokenRemainderMask = allRidBitsSet >> tokenRangeBitCount;
Expand Down
10 changes: 5 additions & 5 deletions docs/design/datacontracts/StressLog.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ StressLogData GetStressLogData()
return default;
}

StressLog stressLog = new StressLog(Target, Target.ReadGlobalPointer(Constants.Globals.StressLog));
StressLog stressLog = new StressLog(Target, Target.ReadGlobalPointer("StressLog"));
return new StressLogData(
stressLog.LoggedFacilities,
stressLog.Level,
Expand Down Expand Up @@ -210,9 +210,9 @@ bool IsPointerInStressLog(StressLogData stressLog, TargetPointer pointer)
// This method is a helper for the various specific versions.
protected TargetPointer GetFormatPointer(ulong formatOffset)
{
if (Target.ReadGlobal<byte>(Constants.Globals.StressLogHasModuleTable) == 0)
if (Target.ReadGlobal<byte>("StressLogHasModuleTable") == 0)
{
StressLog stressLog = new(Target, target.ReadGlobalPointer(Constants.Globals.StressLog));
StressLog stressLog = new(Target, target.ReadGlobalPointer("StressLog"));
return new TargetPointer(stressLog.ModuleOffset + formatOffset);
}

Expand All @@ -227,7 +227,7 @@ protected TargetPointer GetFormatPointer(ulong formatOffset)
moduleTable = stressLog.Modules ?? throw new InvalidOperationException("StressLogModuleTable is not set and StressLog does not contain a ModuleTable offset, but StressLogHasModuleTable is set to 1.");
}
uint moduleEntrySize = target.GetTypeInfo(DataType.StressLogModuleDesc).Size!.Value;
uint maxModules = target.ReadGlobal<uint>(Constants.Globals.StressLogMaxModules);
uint maxModules = target.ReadGlobal<uint>("StressLogMaxModules");
for (uint i = 0; i < maxModules; ++i)
{
StressLogModuleDesc module = new(Target, moduleTable.Value + i * moduleEntrySize);
Expand Down Expand Up @@ -322,7 +322,7 @@ The format offset refers to the cummulative offset into a module referred to in
```csharp
StressMsgData GetStressMsgData(StressMsg msg)
{
StressLog stressLog = new(Target, target.ReadGlobalPointer(Constants.Globals.StressLog));
StressLog stressLog = new(Target, target.ReadGlobalPointer("StressLog"));
uint pointerSize = Target.GetTypeInfo(DataType.pointer).Size!.Value;

ulong payload1 = target.Read<ulong>(msg.Header);
Expand Down
7 changes: 7 additions & 0 deletions src/coreclr/vm/datadescriptor/datadescriptor.inc
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,12 @@ CDAC_TYPE_FIELD(MethodTable, /*pointer*/, PerInstInfo, cdac_data<MethodTable>::P
CDAC_TYPE_FIELD(MethodTable, /*pointer*/, AuxiliaryData, cdac_data<MethodTable>::AuxiliaryData)
CDAC_TYPE_END(MethodTable)

CDAC_TYPE_BEGIN(DynamicStaticsInfo)
CDAC_TYPE_SIZE(sizeof(DynamicStaticsInfo))
CDAC_TYPE_FIELD(DynamicStaticsInfo, /*uint32*/, GCStatics, offsetof(DynamicStaticsInfo, m_pGCStatics))
CDAC_TYPE_FIELD(DynamicStaticsInfo, /*uint32*/, NonGCStatics, offsetof(DynamicStaticsInfo, m_pNonGCStatics))
CDAC_TYPE_END(DynamicStaticsInfo)

CDAC_TYPE_BEGIN(MethodTableAuxiliaryData)
CDAC_TYPE_INDETERMINATE(MethodTableAuxiliaryData)
CDAC_TYPE_FIELD(MethodTableAuxiliaryData, /*pointer*/, LoaderModule, offsetof(MethodTableAuxiliaryData, m_pLoaderModule))
Expand Down Expand Up @@ -935,6 +941,7 @@ CDAC_GLOBAL(ObjectHeaderSize, uint64, OBJHEADER_SIZE)
CDAC_GLOBAL(SyncBlockValueToObjectOffset, uint16, OBJHEADER_SIZE - cdac_data<ObjHeader>::SyncBlockValue)
CDAC_GLOBAL(StubCodeBlockLast, uint8, STUB_CODE_BLOCK_LAST)
CDAC_GLOBAL(DefaultADID, uint32, DefaultADID)
CDAC_GLOBAL(StaticsPointerMask, uintptr_t, DynamicStaticsInfo::STATICSPOINTERMASK)
CDAC_GLOBAL(PtrArrayOffsetToDataArray, uintptr_t, offsetof(PtrArray, m_Array))
CDAC_GLOBAL(NumberOfTlsOffsetsNotUsedInNoncollectibleArray, uint8, NUMBER_OF_TLSOFFSETS_NOT_USED_IN_NONCOLLECTIBLE_ARRAY)
CDAC_GLOBAL(MaxClrNotificationArgs, uint32, MAX_CLR_NOTIFICATION_ARGS)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,8 @@ 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();
TargetPointer GetGCStaticsBasePointer(TypeHandle typeHandle) => throw new NotImplementedException();
TargetPointer GetNonGCStaticsBasePointer(TypeHandle typeHandle) => throw new NotImplementedException();
TargetPointer GetGCThreadStaticsBasePointer(TypeHandle typeHandle, TargetPointer threadPtr) => throw new NotImplementedException();
TargetPointer GetNonGCThreadStaticsBasePointer(TypeHandle typeHandle, TargetPointer threadPtr) => throw new NotImplementedException();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ public enum DataType
CGrowableSymbolStream,
ProbeExtensionResult,
MethodTable,
DynamicStaticsInfo,
EEClass,
ArrayClass,
MethodTableAuxiliaryData,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ public static class Globals
public const string ExecutionManagerCodeRangeMapAddress = nameof(ExecutionManagerCodeRangeMapAddress);
public const string StubCodeBlockLast = nameof(StubCodeBlockLast);
public const string DefaultADID = nameof(DefaultADID);
public const string StaticsPointerMask = nameof(StaticsPointerMask);
public const string PtrArrayOffsetToDataArray = nameof(PtrArrayOffsetToDataArray);
public const string NumberOfTlsOffsetsNotUsedInNoncollectibleArray = nameof(NumberOfTlsOffsetsNotUsedInNoncollectibleArray);
public const string MaxClrNotificationArgs = nameof(MaxClrNotificationArgs);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -410,6 +410,18 @@ 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;
private TargetPointer GetDynamicStaticsInfo(TypeHandle typeHandle)
{
if (!typeHandle.IsMethodTable())
return default;

MethodTable methodTable = _methodTables[typeHandle.Address];
if (!methodTable.Flags.IsDynamicStatics)
return default;
TargetPointer dynamicStaticsInfoSize = _target.GetTypeInfo(DataType.DynamicStaticsInfo).Size!.Value;
TargetPointer dynamicStaticsInfoAddr = methodTable.AuxiliaryData - dynamicStaticsInfoSize;
return dynamicStaticsInfoAddr;
}

private Data.ThreadStaticsInfo GetThreadStaticsInfo(TypeHandle typeHandle)
{
Expand Down Expand Up @@ -438,6 +450,24 @@ public TargetPointer GetNonGCThreadStaticsBasePointer(TypeHandle typeHandle, Tar
return threadContract.GetThreadLocalStaticBase(threadPtr, tlsIndexPtr);
}

public TargetPointer GetGCStaticsBasePointer(TypeHandle typeHandle)
{
TargetPointer dynamicStaticsInfoAddr = GetDynamicStaticsInfo(typeHandle);
if (dynamicStaticsInfoAddr == TargetPointer.Null)
return TargetPointer.Null;
Data.DynamicStaticsInfo dynamicStaticsInfo = _target.ProcessedData.GetOrAdd<Data.DynamicStaticsInfo>(dynamicStaticsInfoAddr);
return dynamicStaticsInfo.GCStatics;
}

public TargetPointer GetNonGCStaticsBasePointer(TypeHandle typeHandle)
{
TargetPointer dynamicStaticsInfoAddr = GetDynamicStaticsInfo(typeHandle);
if (dynamicStaticsInfoAddr == TargetPointer.Null)
return TargetPointer.Null;
Data.DynamicStaticsInfo dynamicStaticsInfo = _target.ProcessedData.GetOrAdd<Data.DynamicStaticsInfo>(dynamicStaticsInfoAddr);
return dynamicStaticsInfo.NonGCStatics;
}

public ReadOnlySpan<TypeHandle> GetInstantiation(TypeHandle typeHandle)
{
if (!typeHandle.IsMethodTable())
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;

namespace Microsoft.Diagnostics.DataContractReader.Data;

internal sealed class DynamicStaticsInfo : IData<DynamicStaticsInfo>
{
static DynamicStaticsInfo IData<DynamicStaticsInfo>.Create(Target target, TargetPointer address) => new DynamicStaticsInfo(target, address);
public DynamicStaticsInfo(Target target, TargetPointer address)
{
Target.TypeInfo type = target.GetTypeInfo(DataType.DynamicStaticsInfo);
TargetPointer mask = target.ReadGlobalPointer(Constants.Globals.StaticsPointerMask);
GCStatics = target.ReadPointer(address + (ulong)type.Fields[nameof(GCStatics)].Offset) & mask;
NonGCStatics = target.ReadPointer(address + (ulong)type.Fields[nameof(NonGCStatics)].Offset) & mask;
}
public TargetPointer GCStatics { get; init; }
public TargetPointer NonGCStatics { get; init; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -2407,7 +2407,46 @@ int ISOSDacInterface13.LockedFlush()

#region ISOSDacInterface14
int ISOSDacInterface14.GetStaticBaseAddress(ClrDataAddress methodTable, ClrDataAddress* nonGCStaticsAddress, ClrDataAddress* GCStaticsAddress)
=> _legacyImpl14 is not null ? _legacyImpl14.GetStaticBaseAddress(methodTable, nonGCStaticsAddress, GCStaticsAddress) : HResults.E_NOTIMPL;
{
int hr = HResults.S_OK;
if (nonGCStaticsAddress == null && GCStaticsAddress == null)
hr = HResults.E_POINTER;
else if (methodTable == 0)
hr = HResults.E_INVALIDARG;
else
{
try
{
Contracts.IRuntimeTypeSystem rtsContract = _target.Contracts.RuntimeTypeSystem;
Contracts.TypeHandle typeHandle = rtsContract.GetTypeHandle(methodTable.ToTargetPointer(_target));
if (GCStaticsAddress != null)
*GCStaticsAddress = rtsContract.GetGCStaticsBasePointer(typeHandle).ToClrDataAddress(_target);
if (nonGCStaticsAddress != null)
*nonGCStaticsAddress = rtsContract.GetNonGCStaticsBasePointer(typeHandle).ToClrDataAddress(_target);
}
catch (System.Exception ex)
{
hr = ex.HResult;
}
}
#if DEBUG
if (_legacyImpl14 is not null)
{
ClrDataAddress nonGCStaticsAddressLocal;
ClrDataAddress GCStaticsAddressLocal;
int hrLocal = _legacyImpl14.GetStaticBaseAddress(methodTable, &nonGCStaticsAddressLocal, &GCStaticsAddressLocal);
Debug.Assert(hrLocal == hr, $"cDAC: {hr:x}, DAC: {hrLocal:x}");
if (hr == HResults.S_OK)
{
if (GCStaticsAddress != null)
Debug.Assert(*GCStaticsAddress == GCStaticsAddressLocal);
if (nonGCStaticsAddress != null)
Debug.Assert(*nonGCStaticsAddress == nonGCStaticsAddressLocal);
}
}
#endif
return hr;
}
int ISOSDacInterface14.GetThreadStaticBaseAddress(ClrDataAddress methodTable, ClrDataAddress thread, ClrDataAddress* nonGCStaticsAddress, ClrDataAddress* GCStaticsAddress)
{
int hr = HResults.S_OK;
Expand Down
Loading