This commit is contained in:
Rachel 2025-07-30 13:25:28 +02:00 committed by GitHub
commit a9344a7712
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 95 additions and 5 deletions

View File

@ -46,6 +46,7 @@ record struct ThreadData (
ThreadStoreData GetThreadStoreData();
ThreadStoreCounts GetThreadCounts();
ThreadData GetThreadData(TargetPointer threadPointer);
TargetPointer IdToThread(uint id);
```
## Version 1
@ -58,6 +59,7 @@ This contract depends on the following descriptors:
| `RuntimeThreadLocals` |
| `Thread` |
| `ThreadStore` |
| `IdDispenser` |
| Global name |
| --- |
@ -66,7 +68,7 @@ This contract depends on the following descriptors:
| `FeatureEHFunclets` |
| `FinalizerThread` |
| `GCThread` |
| `ThinLockThreadIdDispenser` |
``` csharp
ThreadStoreData GetThreadStoreData()
{
@ -93,11 +95,11 @@ DacThreadStoreCounts GetThreadCounts()
ThreadData GetThreadData(TargetPointer address)
{
var runtimeThread = new Thread(Target, threadPointer);
var runtimeThread = new Thread(target, threadPointer);
// Exception tracker is a pointer when EH funclets are enabled
TargetPointer exceptionTrackerAddr = _target.ReadGlobal<byte>("FeatureEHFunclets") != 0
? _target.ReadPointer(address + /* Thread::ExceptionTracker offset */)
TargetPointer exceptionTrackerAddr = target.ReadGlobal<byte>("FeatureEHFunclets") != 0
? target.ReadPointer(address + /* Thread::ExceptionTracker offset */)
: address + /* Thread::ExceptionTracker offset */;
TargetPointer firstNestedException = exceptionTrackerAddr != TargetPointer.Null
? target.ReadPointer(exceptionTrackerAddr + /* ExceptionInfo::PreviousNestedInfo offset*/)
@ -127,4 +129,15 @@ ThreadData GetThreadData(TargetPointer address)
NextThread: target.ReadPointer(address + /* Thread::LinkNext offset */) - threadLinkOffset;
);
}
TargetPointer IThread.IdToThread(uint id)
{
TargetPointer idDispenserPointer = target.ReadGlobalPointer(Constants.Globals.ThinlockThreadIdDispenser);
TargetPointer idDispenser = target.ReadPointer(idDispenserPointer)
uint HighestId = target.ReadPointer(idDispenser + /* IdDispenser::HighestId offset */);
TargetPointer threadPtr = TargetPointer.Null;
if (id < HighestId)
threadPtr = target.ReadPointer(idDispenser + /* IdDispenser::IdToThread offset */);
return threadPtr;
}
```

View File

@ -140,6 +140,12 @@ CDAC_TYPE_INDETERMINATE(RuntimeThreadLocals)
CDAC_TYPE_FIELD(RuntimeThreadLocals, /*EEAllocContext*/, AllocContext, offsetof(RuntimeThreadLocals, alloc_context))
CDAC_TYPE_END(RuntimeThreadLocals)
CDAC_TYPE_BEGIN(IdDispenser)
CDAC_TYPE_INDETERMINATE(IdDispenser)
CDAC_TYPE_FIELD(IdDispenser, /*pointer*/, IdToThread, cdac_data<IdDispenser>::IdToThread)
CDAC_TYPE_FIELD(IdDispenser, /*uint32*/, HighestId, cdac_data<IdDispenser>::HighestId)
CDAC_TYPE_END(IdDispenser)
CDAC_TYPE_BEGIN(EEAllocContext)
CDAC_TYPE_INDETERMINATE(EEAllocContext)
CDAC_TYPE_FIELD(EEAllocContext, /*GCAllocContext*/, GCAllocationContext, offsetof(ee_alloc_context, m_GCAllocContext))
@ -992,6 +998,7 @@ CDAC_GLOBAL_POINTER(MiniMetaDataBuffAddress, &::g_MiniMetaDataBuffAddress)
CDAC_GLOBAL_POINTER(MiniMetaDataBuffMaxSize, &::g_MiniMetaDataBuffMaxSize)
CDAC_GLOBAL_POINTER(DacNotificationFlags, &::g_dacNotificationFlags)
CDAC_GLOBAL_POINTER(OffsetOfCurrentThreadInfo, &::g_offsetOfCurrentThreadInfo)
CDAC_GLOBAL_POINTER(ThinlockThreadIdDispenser, &::g_pThinLockThreadIdDispenser)
#ifdef TARGET_WINDOWS
CDAC_GLOBAL_POINTER(TlsIndexBase, &::_tls_index)
#endif // TARGET_WINDOWS

View File

@ -4390,7 +4390,17 @@ public:
_ASSERTE(result == NULL || (dac_cast<size_t>(result) & 0x3) == 0 || ((Thread*)result)->GetThreadId() == id);
return result;
}
friend struct ::cdac_data<IdDispenser>;
};
template<>
struct cdac_data<IdDispenser>
{
static constexpr size_t IdToThread = offsetof(IdDispenser, m_idToThread);
static constexpr size_t HighestId = offsetof(IdDispenser, m_highestId);
};
typedef DPTR(IdDispenser) PTR_IdDispenser;

View File

@ -48,6 +48,7 @@ public interface IThread : IContract
ThreadStoreData GetThreadStoreData() => throw new NotImplementedException();
ThreadStoreCounts GetThreadCounts() => throw new NotImplementedException();
ThreadData GetThreadData(TargetPointer thread) => throw new NotImplementedException();
TargetPointer IdToThread(uint id) => throw new NotImplementedException();
}
public readonly struct Thread : IThread

View File

@ -28,6 +28,7 @@ public enum DataType
Exception,
ExceptionInfo,
RuntimeThreadLocals,
IdDispenser,
Module,
ModuleLookupMap,
AppDomain,

View File

@ -30,6 +30,7 @@ public static class Constants
public const string DacNotificationFlags = nameof(DacNotificationFlags);
public const string OffsetOfCurrentThreadInfo = nameof(OffsetOfCurrentThreadInfo);
public const string TlsIndexBase = nameof(TlsIndexBase);
public const string ThinlockThreadIdDispenser = nameof(ThinlockThreadIdDispenser);
public const string StressLogEnabled = nameof(StressLogEnabled);
public const string StressLogHasModuleTable = nameof(StressLogHasModuleTable);

View File

@ -68,6 +68,17 @@ internal readonly struct Thread_1 : IThread
GetThreadFromLink(thread.LinkNext));
}
TargetPointer IThread.IdToThread(uint id)
{
TargetPointer idDispenserPtr = _target.ReadGlobalPointer(Constants.Globals.ThinlockThreadIdDispenser);
TargetPointer idDispenser = _target.ReadPointer(idDispenserPtr);
Data.IdDispenser idDispenserObj = _target.ProcessedData.GetOrAdd<Data.IdDispenser>(idDispenser);
TargetPointer threadPtr = TargetPointer.Null;
if (id < idDispenserObj.HighestId)
threadPtr = _target.ReadPointer(idDispenserObj.IdToThread + (ulong)(id * _target.PointerSize));
return threadPtr;
}
private TargetPointer GetThreadFromLink(TargetPointer threadLink)
{
if (threadLink == TargetPointer.Null)

View File

@ -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 IdDispenser : IData<IdDispenser>
{
static IdDispenser IData<IdDispenser>.Create(Target target, TargetPointer address) => new IdDispenser(target, address);
public IdDispenser(Target target, TargetPointer address)
{
Target.TypeInfo type = target.GetTypeInfo(DataType.IdDispenser);
IdToThread = target.ReadPointer(address + (ulong)type.Fields[nameof(IdToThread)].Offset);
HighestId = target.Read<uint>(address + (ulong)type.Fields[nameof(HighestId)].Offset);
}
public TargetPointer IdToThread { get; init; }
public uint HighestId { get; init; }
}

View File

@ -1920,7 +1920,33 @@ internal sealed unsafe partial class SOSDacImpl
return hr;
}
int ISOSDacInterface.GetThreadFromThinlockID(uint thinLockId, ClrDataAddress* pThread)
=> _legacyImpl is not null ? _legacyImpl.GetThreadFromThinlockID(thinLockId, pThread) : HResults.E_NOTIMPL;
{
int hr = HResults.S_OK;
if (pThread == null)
hr = HResults.E_INVALIDARG;
try
{
TargetPointer threadPtr = _target.Contracts.Thread.IdToThread(thinLockId);
*pThread = threadPtr.ToClrDataAddress(_target);
}
catch (System.Exception ex)
{
hr = ex.HResult;
}
#if DEBUG
if (_legacyImpl is not null)
{
ClrDataAddress pThreadLocal;
int hrLocal = _legacyImpl.GetThreadFromThinlockID(thinLockId, &pThreadLocal);
Debug.Assert(hrLocal == hr, $"cDAC: {hr:x}, DAC: {hrLocal:x}");
if (hr == HResults.S_OK)
{
Debug.Assert(*pThread == pThreadLocal);
}
}
#endif
return hr;
}
int ISOSDacInterface.GetThreadLocalModuleData(ClrDataAddress thread, uint index, void* data)
{
// CoreCLR does not use thread local modules anymore