| File: Contracts\StackWalk\FrameHandling\BaseFrameHandler.cs | Web Access |
| Project: src\runtime\src\native\managed\cdac\Microsoft.Diagnostics.DataContractReader.Contracts\Microsoft.Diagnostics.DataContractReader.Contracts.csproj (Microsoft.Diagnostics.DataContractReader.Contracts) |
// 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.Collections.Generic; using Microsoft.Diagnostics.DataContractReader.Data; namespace Microsoft.Diagnostics.DataContractReader.Contracts.StackWalkHelpers; /// <summary> /// Abstract base class providing platform agnostic functionality for handling frames. /// </summary> internal abstract class BaseFrameHandler(Target target, IPlatformAgnosticContext context) { protected readonly Target _target = target; protected readonly FrameHelpers _frameHelpers = new FrameHelpers(target); private readonly IPlatformAgnosticContext _context = context; public virtual void HandleInlinedCallFrame(InlinedCallFrame inlinedCallFrame) { // if the caller return address is 0, then the call is not active // and we should not update the context if (inlinedCallFrame.CallerReturnAddress == 0) { return; } _context.InstructionPointer = inlinedCallFrame.CallerReturnAddress; _context.StackPointer = inlinedCallFrame.CallSiteSP; _context.FramePointer = inlinedCallFrame.CalleeSavedFP; } public virtual void HandleSoftwareExceptionFrame(SoftwareExceptionFrame softwareExceptionFrame) { IPlatformAgnosticContext otherContextHolder = IPlatformAgnosticContext.GetContextForPlatform(_target); otherContextHolder.ReadFromAddress(_target, softwareExceptionFrame.TargetContext); UpdateCalleeSavedRegistersFromOtherContext(otherContextHolder); _context.InstructionPointer = otherContextHolder.InstructionPointer; _context.StackPointer = otherContextHolder.StackPointer; } public virtual void HandleTransitionFrame(FramedMethodFrame framedMethodFrame) { Data.TransitionBlock transitionBlock = _target.ProcessedData.GetOrAdd<Data.TransitionBlock>(framedMethodFrame.TransitionBlockPtr); if (_target.GetTypeInfo(DataType.TransitionBlock).Size is not uint transitionBlockSize) { throw new InvalidOperationException("TransitionBlock size is not set"); } _context.InstructionPointer = transitionBlock.ReturnAddress; _context.StackPointer = framedMethodFrame.TransitionBlockPtr + transitionBlockSize; Data.CalleeSavedRegisters calleeSavedRegisters = _target.ProcessedData.GetOrAdd<Data.CalleeSavedRegisters>(transitionBlock.CalleeSavedRegisters); UpdateFromRegisterDict(calleeSavedRegisters.Registers); } public virtual void HandleFuncEvalFrame(FuncEvalFrame funcEvalFrame) { Data.DebuggerEval debuggerEval = _target.ProcessedData.GetOrAdd<Data.DebuggerEval>(funcEvalFrame.DebuggerEvalPtr); // No context to update if the eval doesn't use a hijack (exception or interpreter path). if (!debuggerEval.EvalUsesHijack) { return; } _context.ReadFromAddress(_target, debuggerEval.TargetContext); } public virtual void HandleResumableFrame(ResumableFrame frame) { _context.ReadFromAddress(_target, frame.TargetContextPtr); } public virtual void HandleFaultingExceptionFrame(FaultingExceptionFrame frame) { _context.ReadFromAddress(_target, frame.TargetContext); } public virtual void HandleTailCallFrame(TailCallFrame tailCallFrame) { throw new InvalidOperationException("TailCallFrame handling is not implemented on the target platform."); } protected void UpdateFromRegisterDict(IReadOnlyDictionary<string, TargetNUInt> registers) { foreach ((string name, TargetNUInt value) in registers) { if (!_context.TrySetRegister(name, value)) { throw new InvalidOperationException($"Unexpected register {name} found when trying to update context"); } } } protected void UpdateCalleeSavedRegistersFromOtherContext(IPlatformAgnosticContext otherContext) { foreach (string name in _target.GetTypeInfo(DataType.CalleeSavedRegisters).Fields.Keys) { if (!otherContext.TryReadRegister(name, out TargetNUInt value)) { throw new InvalidOperationException($"Unexpected register {name} in callee saved registers"); } if (!_context.TrySetRegister(name, value)) { throw new InvalidOperationException($"Unexpected register {name} in callee saved registers"); } } } protected Data.Frame? GetNextFrame(TargetPointer currentFrameAddress) { Data.Frame current = _target.ProcessedData.GetOrAdd<Data.Frame>(currentFrameAddress); if (current.Next == TargetPointer.Null) return null; ulong terminator = _target.PointerSize == 8 ? ulong.MaxValue : uint.MaxValue; if (current.Next.Value == terminator) return null; return _target.ProcessedData.GetOrAdd<Data.Frame>(current.Next); } }