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
35 changes: 34 additions & 1 deletion docs/design/datacontracts/Thread.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,13 @@ This contract is for reading and iterating the threads of the process.
## APIs of contract

``` csharp
[Flags]
enum ThreadContextSource
{
None = 0,
Debugger = 1,
}

record struct ThreadStoreData (
int ThreadCount,
TargetPointer FirstThread,
Expand Down Expand Up @@ -52,7 +59,8 @@ ThreadStoreCounts GetThreadCounts();
ThreadData GetThreadData(TargetPointer threadPointer);
void GetStackLimitData(TargetPointer threadPointer, out TargetPointer stackBase, out TargetPointer stackLimit, out TargetPointer frameAddress);
TargetPointer IdToThread(uint id);
TargetPointer GetThreadLocalStaticBase(TargetPointer threadPointer, int indexOffset, int indexType);
TargetPointer GetThreadLocalStaticBase(TargetPointer threadPointer, TargetPointer tlsIndexPtr);
byte[] GetContext(TargetPointer threadPointer, ThreadContextSource contextSource, uint contextFlags);
```

## Version 1
Expand Down Expand Up @@ -107,6 +115,7 @@ The contract additionally depends on these data descriptors
| `Thread` | `CurrentCustomDebuggerNotification` | Handle to the current custom debugger notification object |
| `Thread` | `LinkNext` | Pointer to get next thread |
| `Thread` | `ExceptionTracker` | Pointer to exception tracking information |
| `Thread` | `DebuggerFilterContext` | Pointer to the debugger filter context for the thread |
| `Thread` | `RuntimeThreadLocals` | Pointer to some thread-local storage |
| `Thread` | `ThreadLocalDataPtr` | Pointer to thread local data structure |
| `Thread` | `UEWatsonBucketTrackerBuckets` | Pointer to thread Watson buckets data (optional, Windows only) |
Expand Down Expand Up @@ -329,4 +338,28 @@ byte[] IThread.GetWatsonBuckets(TargetPointer threadPointer)
return span.ToArray();
}

byte[] IThread.GetContext(TargetPointer threadPointer, ThreadContextSource contextSource, uint contextFlags)
{
// Allocate a context buffer for the target platform
IPlatformAgnosticContext context = IPlatformAgnosticContext.GetContextForPlatform(target);
byte[] bytes = new byte[context.Size];

TargetPointer filterContext = TargetPointer.Null;

if (contextSource.HasFlag(ThreadContextSource.Debugger))
filterContext = target.ReadPointer(threadPointer + /* Thread::DebuggerFilterContext offset */);

if (filterContext != TargetPointer.Null)
{
// Use the filter context directly
target.ReadBuffer(filterContext, bytes);
return bytes;
}

// Fall back to the OS thread context
ulong osId = target.ReadNUInt(threadPointer + /* Thread::OSId offset */);
target.GetThreadContext(osId, contextFlags, bytes);
return bytes;
}

```
52 changes: 2 additions & 50 deletions src/coreclr/debug/daccess/dacdbiimpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5886,58 +5886,10 @@ HRESULT STDMETHODCALLTYPE DacDbiInterfaceImpl::GetContext(VMPTR_Thread vmThread,
{
// If the filter context is NULL, then we use the true context of the thread.
pContextBuffer->ContextFlags = DT_CONTEXT_ALL;
HRESULT hr = m_pTarget->GetThreadContext(pThread->GetOSThreadId(),
IfFailThrow(m_pTarget->GetThreadContext(pThread->GetOSThreadId(),
pContextBuffer->ContextFlags,
sizeof(DT_CONTEXT),
reinterpret_cast<BYTE *>(pContextBuffer));
if (hr == E_NOTIMPL)
{
// GetThreadContext is not implemented on this data target.
// That's why we have to make do with context we can obtain from Frames explicitly stored in Thread object.
// It suffices for managed debugging stackwalk.
REGDISPLAY tmpRd = {};
T_CONTEXT tmpContext = {};
FillRegDisplay(&tmpRd, &tmpContext);

// Going through thread Frames and looking for first (deepest one) one that
// that has context available for stackwalking (SP and PC)
// For example: RedirectedThreadFrame, InlinedCallFrame, DynamicHelperFrame
Frame *frame = pThread->GetFrame();

while (frame != NULL && frame != FRAME_TOP)
{
#ifdef FEATURE_INTERPRETER
if (frame->GetFrameIdentifier() == FrameIdentifier::InterpreterFrame)
{
PTR_InterpreterFrame pInterpreterFrame = dac_cast<PTR_InterpreterFrame>(frame);
pInterpreterFrame->SetContextToInterpMethodContextFrame(&tmpContext);
CopyMemory(pContextBuffer, &tmpContext, sizeof(*pContextBuffer));
return S_OK;
}
#endif // FEATURE_INTERPRETER
frame->UpdateRegDisplay(&tmpRd);
if (GetRegdisplaySP(&tmpRd) != 0 && GetControlPC(&tmpRd) != 0)
{
UpdateContextFromRegDisp(&tmpRd, &tmpContext);
CopyMemory(pContextBuffer, &tmpContext, sizeof(*pContextBuffer));
pContextBuffer->ContextFlags = DT_CONTEXT_CONTROL
#if defined(TARGET_AMD64) || defined(TARGET_ARM)
| DT_CONTEXT_INTEGER // DT_CONTEXT_INTEGER is needed to include the frame register on ARM32 and AMD64 architectures
// DT_CONTEXT_CONTROL already includes the frame register for X86 and ARM64 architectures
#endif
;
return S_OK;
}
frame = frame->Next();
}

// It looks like this thread is not running managed code.
ZeroMemory(pContextBuffer, sizeof(*pContextBuffer));
}
else
{
IfFailThrow(hr);
}
reinterpret_cast<BYTE *>(pContextBuffer)));
}
else
{
Expand Down
8 changes: 6 additions & 2 deletions src/coreclr/debug/daccess/dacdbiimplstackwalk.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -723,7 +723,6 @@ FramePointer DacDbiInterfaceImpl::GetFramePointerWorker(StackFrameIterator * pIt
}

// Return TRUE if the specified CONTEXT is the CONTEXT of the leaf frame.
// @dbgtodo filter CONTEXT - Currently we check for the filter CONTEXT first.
HRESULT STDMETHODCALLTYPE DacDbiInterfaceImpl::IsLeafFrame(VMPTR_Thread vmThread, const DT_CONTEXT * pContext, OUT BOOL * pResult)
{
DD_ENTER_MAY_THROW;
Expand All @@ -733,7 +732,12 @@ HRESULT STDMETHODCALLTYPE DacDbiInterfaceImpl::IsLeafFrame(VMPTR_Thread vmThread
{

DT_CONTEXT ctxLeaf;
IfFailThrow(GetContext(vmThread, &ctxLeaf));
Comment thread
rcj1 marked this conversation as resolved.
Thread * pThread = vmThread.GetDacPtr();
ctxLeaf.ContextFlags = DT_CONTEXT_ALL;
IfFailThrow(m_pTarget->GetThreadContext(pThread->GetOSThreadId(),
ctxLeaf.ContextFlags,
sizeof(DT_CONTEXT),
reinterpret_cast<BYTE *>(&ctxLeaf)));

// Call a platform-specific helper to compare the two contexts.
*pResult = CompareControlRegisters(pContext, &ctxLeaf);
Expand Down
4 changes: 1 addition & 3 deletions src/coreclr/debug/inc/amd64/primitives.h
Original file line number Diff line number Diff line change
Expand Up @@ -147,14 +147,12 @@ inline void CORDbgSetSP(DT_CONTEXT *context, LPVOID rsp)
#define CORDbgSetFP(context, rbp)
#define CORDbgGetFP(context) 0

// compare the RIP, RSP, and RBP
inline BOOL CompareControlRegisters(const DT_CONTEXT * pCtx1, const DT_CONTEXT * pCtx2)
{
LIMITED_METHOD_DAC_CONTRACT;

if ((pCtx1->Rip == pCtx2->Rip) &&
(pCtx1->Rsp == pCtx2->Rsp) &&
(pCtx1->Rbp == pCtx2->Rbp))
(pCtx1->Rsp == pCtx2->Rsp))
{
return TRUE;
}
Expand Down
3 changes: 0 additions & 3 deletions src/coreclr/debug/inc/arm/primitives.h
Original file line number Diff line number Diff line change
Expand Up @@ -117,13 +117,10 @@ inline LPVOID CORDbgGetFP(DT_CONTEXT* context)
return (LPVOID)(UINT_PTR)0;
}

// compare the EIP, ESP, and EBP
inline BOOL CompareControlRegisters(const DT_CONTEXT * pCtx1, const DT_CONTEXT * pCtx2)
{
LIMITED_METHOD_DAC_CONTRACT;

// @ARMTODO: Sort out frame registers

if ((pCtx1->Pc == pCtx2->Pc) &&
(pCtx1->Sp == pCtx2->Sp))
{
Expand Down
5 changes: 1 addition & 4 deletions src/coreclr/debug/inc/arm64/primitives.h
Original file line number Diff line number Diff line change
Expand Up @@ -132,11 +132,8 @@ inline BOOL CompareControlRegisters(const DT_CONTEXT * pCtx1, const DT_CONTEXT *
{
LIMITED_METHOD_DAC_CONTRACT;

// @ARMTODO: Sort out frame registers

if ((pCtx1->Pc == pCtx2->Pc) &&
(pCtx1->Sp == pCtx2->Sp) &&
(pCtx1->Fp == pCtx2->Fp))
(pCtx1->Sp == pCtx2->Sp))
{
return TRUE;
}
Expand Down
4 changes: 1 addition & 3 deletions src/coreclr/debug/inc/i386/primitives.h
Original file line number Diff line number Diff line change
Expand Up @@ -108,14 +108,12 @@ inline LPVOID CORDbgGetFP(DT_CONTEXT* context)
return (LPVOID)(UINT_PTR)context->Ebp;
}

// compare the EIP, ESP, and EBP
inline BOOL CompareControlRegisters(const DT_CONTEXT * pCtx1, const DT_CONTEXT * pCtx2)
{
LIMITED_METHOD_DAC_CONTRACT;

if ((pCtx1->Eip == pCtx2->Eip) &&
(pCtx1->Esp == pCtx2->Esp) &&
(pCtx1->Ebp == pCtx2->Ebp))
(pCtx1->Esp == pCtx2->Esp))
{
return TRUE;
}
Expand Down
5 changes: 1 addition & 4 deletions src/coreclr/debug/inc/loongarch64/primitives.h
Original file line number Diff line number Diff line change
Expand Up @@ -118,11 +118,8 @@ inline BOOL CompareControlRegisters(const DT_CONTEXT * pCtx1, const DT_CONTEXT *
{
LIMITED_METHOD_DAC_CONTRACT;

// TODO-LoongArch64: Sort out frame registers

if ((pCtx1->Pc == pCtx2->Pc) &&
(pCtx1->Sp == pCtx2->Sp) &&
(pCtx1->Fp == pCtx2->Fp))
(pCtx1->Sp == pCtx2->Sp))
{
return TRUE;
}
Expand Down
5 changes: 1 addition & 4 deletions src/coreclr/debug/inc/riscv64/primitives.h
Original file line number Diff line number Diff line change
Expand Up @@ -119,11 +119,8 @@ inline BOOL CompareControlRegisters(const DT_CONTEXT * pCtx1, const DT_CONTEXT *
{
LIMITED_METHOD_DAC_CONTRACT;

// TODO-RISCV64: Sort out frame registers

if ((pCtx1->Pc == pCtx2->Pc) &&
(pCtx1->Sp == pCtx2->Sp) &&
(pCtx1->Fp == pCtx2->Fp))
(pCtx1->Sp == pCtx2->Sp))
{
return TRUE;
}
Expand Down
3 changes: 0 additions & 3 deletions src/coreclr/vm/datadescriptor/datadescriptor.inc
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,6 @@ CDAC_TYPE_FIELD(Thread, T_POINTER, CachedStackBase, cdac_data<Thread>::CachedSta
CDAC_TYPE_FIELD(Thread, T_POINTER, CachedStackLimit, cdac_data<Thread>::CachedStackLimit)
CDAC_TYPE_FIELD(Thread, T_POINTER, ExceptionTracker, cdac_data<Thread>::ExceptionTracker)
CDAC_TYPE_FIELD(Thread, T_POINTER, DebuggerFilterContext, cdac_data<Thread>::DebuggerFilterContext)
#ifdef PROFILING_SUPPORTED
CDAC_TYPE_FIELD(Thread, T_POINTER, ProfilerFilterContext, cdac_data<Thread>::ProfilerFilterContext)
#endif // PROFILING_SUPPORTED
CDAC_TYPE_FIELD(Thread, TYPE(ObjectHandle), ExposedObject, cdac_data<Thread>::ExposedObject)
CDAC_TYPE_FIELD(Thread, TYPE(ObjectHandle), LastThrownObject, cdac_data<Thread>::LastThrownObject)
CDAC_TYPE_FIELD(Thread, T_UINT32, LastThrownObjectIsUnhandled, cdac_data<Thread>::LastThrownObjectIsUnhandled)
Expand Down
3 changes: 0 additions & 3 deletions src/coreclr/vm/threads.h
Original file line number Diff line number Diff line change
Expand Up @@ -3768,9 +3768,6 @@ struct cdac_data<Thread>
"Thread::m_ExceptionState is of type ThreadExceptionState");
static constexpr size_t ExceptionTracker = offsetof(Thread, m_ExceptionState) + offsetof(ThreadExceptionState, m_pCurrentTracker);
static constexpr size_t DebuggerFilterContext = offsetof(Thread, m_debuggerFilterContext);
#ifdef PROFILING_SUPPORTED
static constexpr size_t ProfilerFilterContext = offsetof(Thread, m_pProfilerFilterContext);
#endif // PROFILING_SUPPORTED
#ifndef TARGET_UNIX
static constexpr size_t UEWatsonBucketTrackerBuckets = offsetof(Thread, m_ExceptionState) + offsetof(ThreadExceptionState, m_UEWatsonBucketTracker)
+ offsetof(EHWatsonBucketTracker, m_WatsonUnhandledInfo.m_pUnhandledBuckets);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,13 @@

namespace Microsoft.Diagnostics.DataContractReader.Contracts;

[Flags]
public enum ThreadContextSource
{
None = 0,
Debugger = 1,
}

public record struct ThreadStoreData(
int ThreadCount,
TargetPointer FirstThread,
Expand Down Expand Up @@ -60,6 +67,7 @@ void GetStackLimitData(TargetPointer threadPointer, out TargetPointer stackBase,
TargetPointer GetThreadLocalStaticBase(TargetPointer threadPointer, TargetPointer tlsIndexPtr) => throw new NotImplementedException();
TargetPointer GetCurrentExceptionHandle(TargetPointer threadPointer) => throw new NotImplementedException();
byte[] GetWatsonBuckets(TargetPointer threadPointer) => throw new NotImplementedException();
byte[] GetContext(TargetPointer threadPointer, ThreadContextSource contextSource, uint contextFlags) => throw new NotImplementedException();
Comment thread
rcj1 marked this conversation as resolved.
}

public readonly struct Thread : IThread
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,9 @@ public enum ContextFlagsValues : uint
}

public readonly uint Size => 0x4d0;
public readonly uint DefaultContextFlags => (uint)ContextFlagsValues.CONTEXT_ALL;
public readonly uint FullContextFlags => (uint)ContextFlagsValues.CONTEXT_FULL;

public readonly uint AllContextFlags => (uint)ContextFlagsValues.CONTEXT_ALL;

public readonly int StackPointerRegister => 4;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public enum ContextFlagsValues : uint
CONTEXT_X18 = CONTEXT_ARM64 | 0x10,
CONTEXT_XSTATE = CONTEXT_ARM64 | 0x20,
CONTEXT_FULL = CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_FLOATING_POINT,
CONTEXT_ALL = CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_FLOATING_POINT | CONTEXT_DEBUG_REGISTERS | CONTEXT_X18,
CONTEXT_ALL = CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_FLOATING_POINT | CONTEXT_DEBUG_REGISTERS,

//
// This flag is set by the unwinder if it has unwound to a call
Expand All @@ -38,10 +38,9 @@ public enum ContextFlagsValues : uint

public readonly uint Size => 0x390;

public readonly uint DefaultContextFlags => (uint)(ContextFlagsValues.CONTEXT_CONTROL |
ContextFlagsValues.CONTEXT_INTEGER |
ContextFlagsValues.CONTEXT_FLOATING_POINT |
ContextFlagsValues.CONTEXT_DEBUG_REGISTERS);
public readonly uint FullContextFlags => (uint)ContextFlagsValues.CONTEXT_FULL;

public readonly uint AllContextFlags => (uint)ContextFlagsValues.CONTEXT_ALL;
Comment thread
rcj1 marked this conversation as resolved.

public readonly int StackPointerRegister => 31;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,9 @@ public enum ContextFlagsValues : uint
}

public readonly uint Size => 0x1a0;
public readonly uint DefaultContextFlags => (uint)ContextFlagsValues.CONTEXT_ALL;
public readonly uint FullContextFlags => (uint)ContextFlagsValues.CONTEXT_FULL;

public readonly uint AllContextFlags => (uint)ContextFlagsValues.CONTEXT_ALL;

public readonly int StackPointerRegister => 13;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ public sealed class ContextHolder<T> : IPlatformAgnosticContext, IEquatable<Cont
public T Context;

public uint Size => Context.Size;
public uint DefaultContextFlags => Context.DefaultContextFlags;
public uint FullContextFlags => Context.FullContextFlags;
public uint AllContextFlags => Context.AllContextFlags;

public int StackPointerRegister => Context.StackPointerRegister;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ namespace Microsoft.Diagnostics.DataContractReader.Contracts.StackWalkHelpers;
public interface IPlatformAgnosticContext
{
public abstract uint Size { get; }
public abstract uint DefaultContextFlags { get; }
public abstract uint FullContextFlags { get; }
Comment thread
rcj1 marked this conversation as resolved.
public abstract uint AllContextFlags { get; }

public int StackPointerRegister { get; }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ namespace Microsoft.Diagnostics.DataContractReader.Contracts.StackWalkHelpers;
public interface IPlatformContext
{
uint Size { get; }
uint DefaultContextFlags { get; }
uint FullContextFlags { get; }
uint AllContextFlags { get; }

int StackPointerRegister { get; }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,9 @@ public enum ContextFlagsValues : uint

public readonly uint Size => 0x320;

public readonly uint DefaultContextFlags => (uint)(ContextFlagsValues.CONTEXT_CONTROL |
ContextFlagsValues.CONTEXT_INTEGER |
ContextFlagsValues.CONTEXT_FLOATING_POINT |
ContextFlagsValues.CONTEXT_DEBUG_REGISTERS);
public readonly uint FullContextFlags => (uint)ContextFlagsValues.CONTEXT_FULL;

public readonly uint AllContextFlags => (uint)ContextFlagsValues.CONTEXT_ALL;

public readonly int StackPointerRegister => 3;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,9 @@ public enum ContextFlagsValues : uint

public readonly uint Size => 0x220;

public readonly uint DefaultContextFlags => (uint)ContextFlagsValues.CONTEXT_ALL;
public readonly uint FullContextFlags => (uint)ContextFlagsValues.CONTEXT_FULL;

public readonly uint AllContextFlags => (uint)ContextFlagsValues.CONTEXT_ALL;

public readonly int StackPointerRegister => 2;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,9 @@ public enum ContextFlagsValues : uint
}

public readonly uint Size => 0x2cc;
public readonly uint DefaultContextFlags => (uint)ContextFlagsValues.CONTEXT_ALL;
public readonly uint FullContextFlags => (uint)ContextFlagsValues.CONTEXT_FULL;

public readonly uint AllContextFlags => (uint)ContextFlagsValues.CONTEXT_ALL;

public readonly int StackPointerRegister => 4;

Expand Down
Loading
Loading