Skip to content
Open
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
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 @@ -734,7 +734,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 @@ -744,7 +743,12 @@ HRESULT STDMETHODCALLTYPE DacDbiInterfaceImpl::IsLeafFrame(VMPTR_Thread vmThread
{

DT_CONTEXT ctxLeaf;
IfFailThrow(GetContext(vmThread, &ctxLeaf));
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
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,14 @@

namespace Microsoft.Diagnostics.DataContractReader.Contracts;

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

public record struct ThreadStoreData(
int ThreadCount,
TargetPointer FirstThread,
Expand Down Expand Up @@ -60,6 +68,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();
}

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 @@ -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;

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; }
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
Original file line number Diff line number Diff line change
Expand Up @@ -760,37 +760,11 @@ private bool IsManaged(TargetPointer ip, [NotNullWhen(true)] out CodeBlockHandle

private void FillContextFromThread(IPlatformAgnosticContext context, ThreadData threadData)
{
byte[] bytes = new byte[context.Size];
Span<byte> buffer = new Span<byte>(bytes);

// Match the native DacStackReferenceWalker behavior: if the thread has a
// FilterContext or ProfilerFilterContext set, use that instead of calling
// GetThreadContext. During debugger breaks, GC stress redirection, or
// profiler stack walks, these contexts hold the correct managed frame state.
Data.Thread thread = _target.ProcessedData.GetOrAdd<Data.Thread>(threadData.ThreadAddress);

TargetPointer filterContext = thread.DebuggerFilterContext;
if (filterContext == TargetPointer.Null)
filterContext = thread.ProfilerFilterContext;

if (filterContext != TargetPointer.Null)
{
_target.ReadBuffer(filterContext.Value, buffer);
context.FillFromBuffer(buffer);
return;
}

// The underlying ICLRDataTarget.GetThreadContext has some variance depending on the host.
// SOS's managed implementation sets the ContextFlags to platform specific values defined in ThreadService.cs (diagnostics repo)
// SOS's native implementation keeps the ContextFlags passed into this function.
// To match the DAC behavior, the DefaultContextFlags are what the DAC passes in in DacGetThreadContext.
// In most implementations, this will be overridden by the host, but in some cases, it may not be.
if (!_target.TryGetThreadContext(threadData.OSId.Value, context.DefaultContextFlags, buffer))
{
throw new InvalidOperationException($"GetThreadContext failed for thread {threadData.OSId.Value}");
}

context.FillFromBuffer(buffer);
byte[] bytes = _target.Contracts.Thread.GetContext(
threadData.ThreadAddress,
ThreadContextSource.Debugger | ThreadContextSource.Profiler,
context.AllContextFlags);
context.FillFromBuffer(bytes);
}

private static StackDataFrameHandle AssertCorrectHandle(IStackDataFrameHandle stackDataFrameHandle)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using Microsoft.Diagnostics.DataContractReader.Contracts.StackWalkHelpers;

namespace Microsoft.Diagnostics.DataContractReader.Contracts;

Expand Down Expand Up @@ -284,4 +285,34 @@ byte[] IThread.GetWatsonBuckets(TargetPointer threadPointer)
_target.ReadBuffer(readFrom, rval);
return rval;
}

byte[] IThread.GetContext(TargetPointer threadPointer, ThreadContextSource contextSource, uint contextFlags)
{
IPlatformAgnosticContext context = IPlatformAgnosticContext.GetContextForPlatform(_target);
byte[] bytes = new byte[context.Size];
Span<byte> buffer = new Span<byte>(bytes);

Data.Thread thread = _target.ProcessedData.GetOrAdd<Data.Thread>(threadPointer);

TargetPointer filterContext = TargetPointer.Null;

if (contextSource.HasFlag(ThreadContextSource.Debugger))
filterContext = thread.DebuggerFilterContext;

if (filterContext == TargetPointer.Null && contextSource.HasFlag(ThreadContextSource.Profiler))
filterContext = thread.ProfilerFilterContext;

if (filterContext != TargetPointer.Null)
{
_target.ReadBuffer(filterContext.Value, buffer);
return bytes;
}

if (!_target.TryGetThreadContext(thread.OSId.Value, contextFlags, buffer))
{
throw new InvalidOperationException($"GetThreadContext failed for thread {thread.OSId.Value}");
}

return bytes;
}
}
Loading
Loading