Skip to content

Commit

Permalink
[cdac] Implement IXCLRDataProcess::GetTaskByOSThreadID (dotnet#109230)
Browse files Browse the repository at this point in the history
- Add `ClrDataTask` to cDAC as its implementation of `IXCLRDataTask`
  - Currently delegates everything to legacy implementation
- Implement `IXCLRDataProcess::GetTaskByOSThreadID`
  - Uses `Thread` contract to find the address of the thread corresponding to the specified OS thread ID.
  - Gets the result from the legacy DAC and passes it to the cDAC `ClrDataTask`
- Add tests for `Thread` contract
  • Loading branch information
elinor-fung authored Oct 28, 2024
1 parent 87fea60 commit ef906f1
Show file tree
Hide file tree
Showing 9 changed files with 481 additions and 22 deletions.
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.Contracts;

internal sealed class ThreadFactory : IContractFactory<IThread>
{
IThread IContractFactory<IThread>.CreateContract(Target target, int version)
{
TargetPointer threadStorePointer = target.ReadGlobalPointer(Constants.Globals.ThreadStore);
TargetPointer threadStore = target.ReadPointer(threadStorePointer);
return version switch
{
1 => new Thread_1(target, threadStore),
_ => default(Thread),
};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,6 @@

namespace Microsoft.Diagnostics.DataContractReader.Contracts;

internal sealed class ThreadFactory : IContractFactory<IThread>
{
IThread IContractFactory<IThread>.CreateContract(Target target, int version)
{
TargetPointer threadStorePointer = target.ReadGlobalPointer(Constants.Globals.ThreadStore);
TargetPointer threadStore = target.ReadPointer(threadStorePointer);
return version switch
{
1 => new Thread_1(target, threadStore),
_ => default(Thread),
};
}
}

internal readonly struct Thread_1 : IThread
{
private readonly Target _target;
Expand Down
55 changes: 55 additions & 0 deletions src/native/managed/cdacreader/src/Legacy/ClrDataTask.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Runtime.InteropServices.Marshalling;

namespace Microsoft.Diagnostics.DataContractReader.Legacy;

[GeneratedComClass]
internal sealed unsafe partial class ClrDataTask : IXCLRDataTask
{
private readonly TargetPointer _address;
private readonly Target _target;
private readonly IXCLRDataTask? _legacyImpl;

public ClrDataTask(TargetPointer address, Target target, IXCLRDataTask? legacyImpl)
{
_address = address;
_target = target;
_legacyImpl = legacyImpl;
}

public int GetProcess(/*IXCLRDataProcess*/ void** process)
=> _legacyImpl is not null ? _legacyImpl.GetProcess(process) : HResults.E_NOTIMPL;
public int GetCurrentAppDomain(/*IXCLRDataAppDomain*/ void** appDomain)
=> _legacyImpl is not null ? _legacyImpl.GetCurrentAppDomain(appDomain) : HResults.E_NOTIMPL;
public int GetUniqueID(ulong* id)
=> _legacyImpl is not null ? _legacyImpl.GetUniqueID(id) : HResults.E_NOTIMPL;
public int GetFlags(uint* flags)
=> _legacyImpl is not null ? _legacyImpl.GetFlags(flags) : HResults.E_NOTIMPL;
public int IsSameObject(IXCLRDataTask* task)
=> _legacyImpl is not null ? _legacyImpl.IsSameObject(task) : HResults.E_NOTIMPL;
public int GetManagedObject(/*IXCLRDataValue*/ void** value)
=> _legacyImpl is not null ? _legacyImpl.GetManagedObject(value) : HResults.E_NOTIMPL;
public int GetDesiredExecutionState(uint* state)
=> _legacyImpl is not null ? _legacyImpl.GetDesiredExecutionState(state) : HResults.E_NOTIMPL;
public int SetDesiredExecutionState(uint state)
=> _legacyImpl is not null ? _legacyImpl.SetDesiredExecutionState(state) : HResults.E_NOTIMPL;
public int CreateStackWalk(uint flags, /*IXCLRDataStackWalk*/ void** stackWalk)
=> _legacyImpl is not null ? _legacyImpl.CreateStackWalk(flags, stackWalk) : HResults.E_NOTIMPL;
public int GetOSThreadID(uint* id)
=> _legacyImpl is not null ? _legacyImpl.GetOSThreadID(id) : HResults.E_NOTIMPL;
public int GetContext(uint contextFlags, uint contextBufSize, uint* contextSize, byte* contextBuffer)
=> _legacyImpl is not null ? _legacyImpl.GetContext(contextFlags, contextBufSize, contextSize, contextBuffer) : HResults.E_NOTIMPL;
public int SetContext(uint contextSize, byte* context)
=> _legacyImpl is not null ? _legacyImpl.SetContext(contextSize, context) : HResults.E_NOTIMPL;
public int GetCurrentExceptionState(/*IXCLRDataExceptionState*/ void** exception)
=> _legacyImpl is not null ? _legacyImpl.GetCurrentExceptionState(exception) : HResults.E_NOTIMPL;
public int Request(uint reqCode, uint inBufferSize, byte* inBuffer, uint outBufferSize, byte* outBuffer)
=> _legacyImpl is not null ? _legacyImpl.Request(reqCode, inBufferSize, inBuffer, outBufferSize, outBuffer) : HResults.E_NOTIMPL;
public int GetName(uint bufLen, uint* nameLen, char* nameBuffer)
=> _legacyImpl is not null ? _legacyImpl.GetName(bufLen, nameLen, nameBuffer) : HResults.E_NOTIMPL;
public int GetLastExceptionState(/*IXCLRDataExceptionState*/ void** exception)
=> _legacyImpl is not null ? _legacyImpl.GetLastExceptionState(exception) : HResults.E_NOTIMPL;
}
55 changes: 54 additions & 1 deletion src/native/managed/cdacreader/src/Legacy/IXCLRData.cs
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ internal unsafe partial interface IXCLRDataProcess
int EndEnumTasks(ulong handle);

[PreserveSig]
int GetTaskByOSThreadID(uint osThreadID, /*IXCLRDataTask*/ void** task);
int GetTaskByOSThreadID(uint osThreadID, out IXCLRDataTask? task);
[PreserveSig]
int GetTaskByUniqueID(ulong taskID, /*IXCLRDataTask*/ void** task);

Expand Down Expand Up @@ -309,3 +309,56 @@ internal unsafe partial interface IXCLRDataProcess2 : IXCLRDataProcess
[PreserveSig]
int SetGcNotification(GcEvtArgs gcEvtArgs);
}

[GeneratedComInterface]
[Guid("A5B0BEEA-EC62-4618-8012-A24FFC23934C")]
internal unsafe partial interface IXCLRDataTask
{
[PreserveSig]
int GetProcess(/*IXCLRDataProcess*/ void** process);

[PreserveSig]
int GetCurrentAppDomain(/*IXCLRDataAppDomain*/ void** appDomain);

[PreserveSig]
int GetUniqueID(ulong* id);

[PreserveSig]
int GetFlags(uint* flags);

[PreserveSig]
int IsSameObject(IXCLRDataTask* task);

[PreserveSig]
int GetManagedObject(/*IXCLRDataValue*/ void** value);

[PreserveSig]
int GetDesiredExecutionState(uint* state);

[PreserveSig]
int SetDesiredExecutionState(uint state);

[PreserveSig]
int CreateStackWalk(uint flags, /*IXCLRDataStackWalk*/ void** stackWalk);

[PreserveSig]
int GetOSThreadID(uint* id);

[PreserveSig]
int GetContext(uint contextFlags, uint contextBufSize, uint* contextSize, byte* contextBuffer);

[PreserveSig]
int SetContext(uint contextSize, byte* context);

[PreserveSig]
int GetCurrentExceptionState(/*IXCLRDataExceptionState*/ void** exception);

[PreserveSig]
int Request(uint reqCode, uint inBufferSize, byte* inBuffer, uint outBufferSize, byte* outBuffer);

[PreserveSig]
int GetName(uint bufLen, uint* nameLen, char* nameBuffer);

[PreserveSig]
int GetLastExceptionState(/*IXCLRDataExceptionState*/ void** exception);
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,40 @@ int IXCLRDataProcess.EnumTask(ulong* handle, /*IXCLRDataTask*/ void** task)
int IXCLRDataProcess.EndEnumTasks(ulong handle)
=> _legacyProcess is not null ? _legacyProcess.EndEnumTasks(handle) : HResults.E_NOTIMPL;

int IXCLRDataProcess.GetTaskByOSThreadID(uint osThreadID, /*IXCLRDataTask*/ void** task)
=> _legacyProcess is not null ? _legacyProcess.GetTaskByOSThreadID(osThreadID, task) : HResults.E_NOTIMPL;
int IXCLRDataProcess.GetTaskByOSThreadID(uint osThreadID, out IXCLRDataTask? task)
{
task = default;

// Find the thread correspending to the OS thread ID
Contracts.IThread contract = _target.Contracts.Thread;
TargetPointer thread = contract.GetThreadStoreData().FirstThread;
TargetPointer matchingThread = TargetPointer.Null;
while (thread != TargetPointer.Null)
{
Contracts.ThreadData threadData = contract.GetThreadData(thread);
if (threadData.OSId.Value == osThreadID)
{
matchingThread = thread;
break;
}

thread = threadData.NextThread;
}

if (matchingThread == TargetPointer.Null)
return HResults.E_INVALIDARG;

IXCLRDataTask? legacyTask = null;
if (_legacyProcess is not null)
{
int hr = _legacyProcess.GetTaskByOSThreadID(osThreadID, out legacyTask);
if (hr < 0)
return hr;
}

task = new ClrDataTask(matchingThread, _target, legacyTask);
return HResults.S_OK;
}

int IXCLRDataProcess.GetTaskByUniqueID(ulong taskID, /*IXCLRDataTask*/ void** task)
=> _legacyProcess is not null ? _legacyProcess.GetTaskByUniqueID(taskID, task) : HResults.E_NOTIMPL;
Expand Down
8 changes: 4 additions & 4 deletions src/native/managed/cdacreader/tests/LoaderTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ public void GetPath(MockTarget.Architecture arch)

// Add the modules
MockLoader loader = new(builder);
TargetPointer moduleAddr = loader.AddModule(helpers, path: expected);
TargetPointer moduleAddrEmptyPath = loader.AddModule(helpers);
TargetPointer moduleAddr = loader.AddModule(path: expected);
TargetPointer moduleAddrEmptyPath = loader.AddModule();

bool success = builder.TryCreateTarget(out ContractDescriptorTarget? target);
Assert.True(success);
Expand Down Expand Up @@ -62,8 +62,8 @@ public void GetFileName(MockTarget.Architecture arch)

// Add the modules
MockLoader loader = new(builder);
TargetPointer moduleAddr = loader.AddModule(helpers, fileName: expected);
TargetPointer moduleAddrEmptyName = loader.AddModule(helpers);
TargetPointer moduleAddr = loader.AddModule(fileName: expected);
TargetPointer moduleAddrEmptyName = loader.AddModule();

bool success = builder.TryCreateTarget(out ContractDescriptorTarget? target);
Assert.True(success);
Expand Down
Loading

0 comments on commit ef906f1

Please sign in to comment.