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
17 changes: 14 additions & 3 deletions docs/design/datacontracts/Thread.md
Original file line number Diff line number Diff line change
Expand Up @@ -403,10 +403,21 @@ byte[] IThread.GetContext(TargetPointer threadPointer, ThreadContextSource conte
return bytes;
}

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

// Derive a context from the explicit Frame chain stored in the Thread (sufficient for managed
// debugging stack walks). Walk the Frame chain and pick the first
// frame that yields a usable context:
// * If it is an InterpreterFrame, fill the context from the top
// InterpMethodContextFrame.
// * Otherwise, update the context from the frame and accept it when both
// StackPointer and InstructionPointer are non-zero. Mark the resulting
// context flags as full so callers know SP/PC/FP are valid.
// If no frame supplies a usable context (thread is not running managed code),
// return a zeroed context.
}

```
Original file line number Diff line number Diff line change
Expand Up @@ -326,11 +326,48 @@ byte[] IThread.GetContext(TargetPointer threadPointer, ThreadContextSource conte
return bytes;
}

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

// Fall back to deriving a context from the explicit Frame chain stored in the Thread object.
return GetContextFromFrames(threadPointer);
Comment thread
rcj1 marked this conversation as resolved.
Comment thread
rcj1 marked this conversation as resolved.
}

private byte[] GetContextFromFrames(TargetPointer threadPointer)
{
IPlatformAgnosticContext context = IPlatformAgnosticContext.GetContextForPlatform(_target);

ThreadData threadData = ((IThread)this).GetThreadData(threadPointer);
FrameIterator iterator = new FrameIterator(_target, threadData);
while (iterator.IsValid())
{
// For InterpreterFrame, fill the context from the top InterpMethodContextFrame
// (matches native InterpreterFrame::SetContextToInterpMethodContextFrame).
if (iterator.GetCurrentFrameType() == FrameType.InterpreterFrame)
{
context.Clear();
iterator.UpdateContextFromCurrentFrame(context);
return context.GetBytes();
}

// For other frames, look for the first (deepest) frame that yields a context
// with both SP and PC set (e.g. RedirectedThreadFrame, InlinedCallFrame,
// DynamicHelperFrame).
context.Clear();
iterator.UpdateContextFromCurrentFrame(context);
if (context.StackPointer.Value != 0 && context.InstructionPointer.Value != 0)
{
context.RawContextFlags = context.FullContextFlags;
return context.GetBytes();
}

iterator.Next();
Comment thread
rcj1 marked this conversation as resolved.
}

return bytes;
// The thread is not running managed code: return a zeroed context.
context.Clear();
return context.GetBytes();
}
}
Loading