File: Contracts\Debugger_1.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.

namespace Microsoft.Diagnostics.DataContractReader.Contracts;

internal readonly struct Debugger_1 : IDebugger
{
    private enum DebuggerControlFlag_1 : uint
    {
        PendingAttach = 0x0100,
        Attached = 0x0200,
    }

    private readonly Target _target;

    internal Debugger_1(Target target)
    {
        _target = target;
    }

    private bool TryGetDebuggerAddress(out TargetPointer debuggerAddress)
    {
        debuggerAddress = TargetPointer.Null;

        TargetPointer debuggerPtrPtr = _target.ReadGlobalPointer(Constants.Globals.Debugger);
        if (debuggerPtrPtr == TargetPointer.Null)
            return false;

        debuggerAddress = _target.ReadPointer(debuggerPtrPtr);
        return debuggerAddress != TargetPointer.Null;
    }

    bool IDebugger.TryGetDebuggerData(out DebuggerData data)
    {
        data = default;
        if (!TryGetDebuggerAddress(out TargetPointer debuggerAddress))
            return false;

        Data.Debugger debugger = _target.ProcessedData.GetOrAdd<Data.Debugger>(debuggerAddress);
        data = new DebuggerData(debugger.LeftSideInitialized != 0, debugger.Defines, debugger.MDStructuresVersion);
        return true;
    }

    int IDebugger.GetAttachStateFlags()
    {
        TargetPointer addr = _target.ReadGlobalPointer(Constants.Globals.CLRJitAttachState);
        return (int)_target.Read<uint>(addr.Value);
    }

    void IDebugger.MarkDebuggerAttachPending()
    {
        TargetPointer addr = _target.ReadGlobalPointer(Constants.Globals.CORDebuggerControlFlags);
        uint currentFlags = _target.Read<uint>(addr.Value);
        _target.Write<uint>(addr.Value, currentFlags | (uint)DebuggerControlFlag_1.PendingAttach);
    }

    void IDebugger.MarkDebuggerAttached(bool fAttached)
    {
        TargetPointer addr = _target.ReadGlobalPointer(Constants.Globals.CORDebuggerControlFlags);
        uint currentFlags = _target.Read<uint>(addr.Value);
        if (fAttached)
        {
            _target.Write<uint>(addr.Value, currentFlags | (uint)DebuggerControlFlag_1.Attached);
        }
        else
        {
            _target.Write<uint>(addr.Value, currentFlags & ~((uint)DebuggerControlFlag_1.Attached | (uint)DebuggerControlFlag_1.PendingAttach));
        }
    }

    bool IDebugger.MetadataUpdatesApplied()
    {
        if (_target.TryReadGlobalPointer(Constants.Globals.MetadataUpdatesApplied, out TargetPointer? addr))
        {
            return _target.Read<byte>(addr.Value.Value) != 0;
        }
        return false;
    }

    void IDebugger.RequestSyncAtEvent()
    {
        if (!TryGetDebuggerAddress(out TargetPointer debuggerAddress))
            return;

        Data.Debugger debugger = _target.ProcessedData.GetOrAdd<Data.Debugger>(debuggerAddress);
        debugger.SetField(_target, nameof(Data.Debugger.RSRequestedSync), 1);
    }

    void IDebugger.SetSendExceptionsOutsideOfJMC(bool sendExceptionsOutsideOfJMC)
    {
        if (!TryGetDebuggerAddress(out TargetPointer debuggerAddress))
            return;

        Data.Debugger debugger = _target.ProcessedData.GetOrAdd<Data.Debugger>(debuggerAddress);
        debugger.SetField(_target, nameof(Data.Debugger.SendExceptionsOutsideOfJMC), sendExceptionsOutsideOfJMC ? 1 : 0);
    }

    TargetPointer IDebugger.GetDebuggerControlBlockAddress()
    {
        if (!TryGetDebuggerAddress(out TargetPointer debuggerAddress))
            return TargetPointer.Null;

        Data.Debugger debugger = _target.ProcessedData.GetOrAdd<Data.Debugger>(debuggerAddress);
        TargetPointer rcThread = debugger.RCThread;
        if (rcThread == TargetPointer.Null)
            return TargetPointer.Null;

        Data.DebuggerRCThread debuggerRcThread = _target.ProcessedData.GetOrAdd<Data.DebuggerRCThread>(rcThread);
        return debuggerRcThread.DCB;
    }

    void IDebugger.EnableGCNotificationEvents(bool fEnable)
    {
        if (!TryGetDebuggerAddress(out TargetPointer debuggerAddress))
            return;

        Data.Debugger debugger = _target.ProcessedData.GetOrAdd<Data.Debugger>(debuggerAddress);
        debugger.SetField(_target, nameof(Data.Debugger.GCNotificationEventsEnabled), fEnable ? 1 : 0);
    }
}