File: Contracts\StackWalk\FrameHandling\FrameIterator.cs
Web Access
Project: src\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 Microsoft.Diagnostics.DataContractReader.Data;

namespace Microsoft.Diagnostics.DataContractReader.Contracts.StackWalkHelpers;

/// <summary>
/// Walks the linked list of capital-F <see cref="Data.Frame"/> structures pushed on a
/// managed thread (Thread::m_pFrame chain), maintaining a single current-frame cursor.
/// This class only owns iteration state; per-frame inspection and operations live in
/// <see cref="FrameHelpers"/>. Convenience methods on this class forward to
/// <see cref="FrameHelpers"/> for the current frame.
/// </summary>
internal sealed class FrameIterator
{
    private readonly Target target;
    private readonly TargetPointer terminator;
    private readonly FrameHelpers frameHelpers;
    private TargetPointer currentFramePointer;

    internal Data.Frame CurrentFrame => target.ProcessedData.GetOrAdd<Data.Frame>(currentFramePointer);

    public TargetPointer CurrentFrameAddress => currentFramePointer;

    public FrameIterator(Target target, ThreadData threadData)
    {
        this.target = target;
        terminator = new TargetPointer(target.PointerSize == 8 ? ulong.MaxValue : uint.MaxValue);
        frameHelpers = new FrameHelpers(target);
        currentFramePointer = threadData.Frame;
    }

    public bool IsValid()
    {
        return currentFramePointer != terminator;
    }

    public bool Next()
    {
        if (currentFramePointer == terminator)
            return false;

        currentFramePointer = CurrentFrame.Next;
        return currentFramePointer != terminator;
    }

    /// <summary>
    /// Returns the <see cref="FrameType"/> of the current frame.
    /// </summary>
    public FrameType GetCurrentFrameType()
        => frameHelpers.GetFrameType(CurrentFrame.Identifier);

    /// <summary>
    /// Returns the return address of the current frame, matching native Frame::GetReturnAddress().
    /// </summary>
    public TargetPointer GetCurrentReturnAddress()
        => frameHelpers.GetReturnAddress(CurrentFrame);

    /// <summary>
    /// Updates <paramref name="context"/> based on the current frame's type.
    /// </summary>
    public void UpdateContextFromCurrentFrame(IPlatformAgnosticContext context)
        => frameHelpers.UpdateContextFromFrame(CurrentFrame, context);
}