2023-06-01 20:18:53 -05:00
|
|
|
using Microsoft.Iris.Debug.Data;
|
2024-01-20 20:32:30 -06:00
|
|
|
using Microsoft.Iris.Markup;
|
2023-06-01 20:18:53 -05:00
|
|
|
using System;
|
2023-06-01 22:49:47 -05:00
|
|
|
using System.Collections.Concurrent;
|
2023-06-01 20:18:53 -05:00
|
|
|
using System.Net.Sockets;
|
|
|
|
|
using System.Runtime.Serialization;
|
|
|
|
|
|
|
|
|
|
namespace Microsoft.Iris.Debug.SystemNet;
|
|
|
|
|
|
2025-07-20 02:13:16 -05:00
|
|
|
public class NetDebuggerServer : IDebuggerServer, IRemoteDebuggerState, IDisposable
|
2023-06-01 20:18:53 -05:00
|
|
|
{
|
|
|
|
|
public static IDebuggerServer Current { get; private set; }
|
|
|
|
|
|
2023-06-01 22:49:47 -05:00
|
|
|
private readonly ConcurrentQueue<byte[]> _outQueue = new();
|
2023-06-01 20:18:53 -05:00
|
|
|
private readonly TcpListener _listener;
|
|
|
|
|
private readonly IFormatter _formatter;
|
|
|
|
|
private Socket _socket;
|
2023-06-01 20:36:32 -05:00
|
|
|
private bool _disposed = false;
|
2023-10-11 13:22:33 -05:00
|
|
|
private InterpreterCommand _uibCommand;
|
|
|
|
|
|
|
|
|
|
public event Action<IDebuggerState, object> Connected;
|
2023-06-02 00:09:51 -05:00
|
|
|
|
|
|
|
|
public Uri ConnectionUri { get; }
|
|
|
|
|
|
|
|
|
|
public InterpreterCommand DebuggerCommand
|
|
|
|
|
{
|
|
|
|
|
get => _uibCommand;
|
|
|
|
|
set
|
|
|
|
|
{
|
2024-01-20 20:32:30 -06:00
|
|
|
QueueDebuggerMessage(new(0, DebuggerMessageType.InterpreterCommand, value, _formatter));
|
2023-06-02 00:09:51 -05:00
|
|
|
_uibCommand = value;
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-06-01 20:18:53 -05:00
|
|
|
|
|
|
|
|
public NetDebuggerServer(string connectionUri) : this(new Uri(connectionUri))
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public NetDebuggerServer(Uri connectionUri)
|
|
|
|
|
{
|
|
|
|
|
ConnectionUri = connectionUri ?? DebugRemoting.DEFAULT_TCP_URI;
|
|
|
|
|
|
|
|
|
|
_listener = TcpListener.Create(connectionUri.Port);
|
|
|
|
|
_listener.Start();
|
|
|
|
|
|
|
|
|
|
_formatter = DebugRemoting.CreateBsonFormatter();
|
|
|
|
|
|
2025-10-03 21:21:35 -05:00
|
|
|
Current = this;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void Start()
|
|
|
|
|
{
|
2023-06-02 00:09:51 -05:00
|
|
|
System.Threading.Thread connectThread = new(ConnectLoop) { IsBackground = true };
|
2023-06-01 20:18:53 -05:00
|
|
|
connectThread.Start();
|
|
|
|
|
}
|
|
|
|
|
|
2024-01-20 20:32:30 -06:00
|
|
|
public MarkupLineNumberEntry[] OnLineNumberTableRequested(string uri)
|
|
|
|
|
{
|
2025-07-20 02:13:16 -05:00
|
|
|
var loadResult = (MarkupLoadResult)LoadResultCache.Read(uri);
|
2024-01-20 20:32:30 -06:00
|
|
|
var lineNumberTable = loadResult.LineNumberTable.DumpTable();
|
|
|
|
|
|
|
|
|
|
return lineNumberTable;
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-09 14:46:51 -05:00
|
|
|
public void LogInterpreterDecode(object context, InterpreterInstruction instruction)
|
2023-06-01 20:18:53 -05:00
|
|
|
{
|
2024-01-20 20:32:30 -06:00
|
|
|
QueueDebuggerMessage(new(0, DebuggerMessageType.InterpreterDecode, instruction, _formatter));
|
2023-10-09 14:46:51 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void LogInterpreterExecute(object context, InterpreterEntry entry)
|
|
|
|
|
{
|
2024-01-20 20:32:30 -06:00
|
|
|
QueueDebuggerMessage(new(0, DebuggerMessageType.InterpreterExecute, entry, _formatter));
|
2023-06-01 20:18:53 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void LogDispatcher(string message)
|
|
|
|
|
{
|
2024-01-20 20:32:30 -06:00
|
|
|
QueueDebuggerMessage(new(0, DebuggerMessageType.DispatcherStep, message, _formatter));
|
2023-06-01 20:18:53 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void Dispose()
|
|
|
|
|
{
|
2023-06-01 20:36:32 -05:00
|
|
|
if (_disposed)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
_disposed = true;
|
2023-06-01 20:18:53 -05:00
|
|
|
_listener.Stop();
|
|
|
|
|
_socket?.Dispose();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void QueueDebuggerMessage(DebuggerMessageFrame frame)
|
|
|
|
|
{
|
|
|
|
|
_outQueue.Enqueue(frame.ToBytes());
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-02 00:09:51 -05:00
|
|
|
private void MessageReceiveLoop()
|
2023-06-01 20:18:53 -05:00
|
|
|
{
|
|
|
|
|
while (_socket.Connected)
|
|
|
|
|
{
|
|
|
|
|
DebuggerMessageFrame frame;
|
2024-01-20 20:32:30 -06:00
|
|
|
while ((frame = DebugRemoting.ReceiveDebuggerMessage(_socket, _formatter)) == null)
|
2023-06-02 00:09:51 -05:00
|
|
|
if (!_socket.Connected) return;
|
2023-06-01 20:18:53 -05:00
|
|
|
|
|
|
|
|
switch (frame.Type)
|
|
|
|
|
{
|
2023-06-02 00:09:51 -05:00
|
|
|
case DebuggerMessageType.UpdateBreakpoint:
|
2024-01-20 20:32:30 -06:00
|
|
|
var breakpoint = frame.GetValue<Breakpoint>();
|
2023-06-02 00:09:51 -05:00
|
|
|
if (breakpoint.Enabled)
|
|
|
|
|
Application.DebugSettings.Breakpoints.Add(breakpoint);
|
|
|
|
|
else
|
|
|
|
|
Application.DebugSettings.Breakpoints.Remove(breakpoint);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case DebuggerMessageType.InterpreterCommand:
|
2024-01-20 20:32:30 -06:00
|
|
|
_uibCommand = frame.GetValue<InterpreterCommand>();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case DebuggerMessageType.LineNumberTable:
|
|
|
|
|
var lineNumberTable = OnLineNumberTableRequested(frame.GetValue<string>());
|
|
|
|
|
|
|
|
|
|
DebuggerMessageFrame<MarkupLineNumberEntry[]> responseFrame =
|
|
|
|
|
new(frame.TransactionId, DebuggerMessageType.LineNumberTable, lineNumberTable, _formatter);
|
|
|
|
|
|
|
|
|
|
QueueDebuggerMessage(responseFrame);
|
2023-06-02 00:09:51 -05:00
|
|
|
break;
|
|
|
|
|
|
2023-06-01 20:18:53 -05:00
|
|
|
default:
|
2025-07-20 02:13:16 -05:00
|
|
|
Trace.WriteLine(TraceCategory.MarkupDebug, "Received unknown debugger message of type '{0}'.", frame.Type);
|
2023-06-01 20:18:53 -05:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void MessageSendLoop()
|
|
|
|
|
{
|
|
|
|
|
while (_socket.Connected)
|
|
|
|
|
{
|
2023-06-01 22:49:47 -05:00
|
|
|
byte[] frameBytes;
|
|
|
|
|
while (!_outQueue.TryDequeue(out frameBytes)) ;
|
2023-06-01 20:18:53 -05:00
|
|
|
|
2023-06-02 00:09:51 -05:00
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
_socket.Send(BitConverter.GetBytes(frameBytes.Length));
|
|
|
|
|
_socket.Send(frameBytes);
|
|
|
|
|
}
|
|
|
|
|
catch (SocketException) { }
|
2023-06-01 20:18:53 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void ConnectLoop()
|
|
|
|
|
{
|
2023-06-01 20:36:32 -05:00
|
|
|
while (!_listener.Pending())
|
|
|
|
|
if (_disposed) return;
|
2023-06-01 20:18:53 -05:00
|
|
|
|
|
|
|
|
_socket = _listener.AcceptSocket();
|
2023-10-11 13:22:33 -05:00
|
|
|
Connected?.Invoke(this, _socket);
|
2023-06-01 20:18:53 -05:00
|
|
|
|
2023-06-02 00:09:51 -05:00
|
|
|
System.Threading.Thread receiveThread = new(MessageReceiveLoop) { IsBackground = true };
|
|
|
|
|
System.Threading.Thread sendThread = new(MessageSendLoop) { IsBackground = true };
|
2023-06-01 20:18:53 -05:00
|
|
|
receiveThread.Start();
|
|
|
|
|
sendThread.Start();
|
|
|
|
|
}
|
2025-07-20 02:13:16 -05:00
|
|
|
|
|
|
|
|
public void WaitForContinue()
|
|
|
|
|
{
|
|
|
|
|
while (Application.Debugger.DebuggerCommand == InterpreterCommand.Break) ;
|
|
|
|
|
}
|
2023-06-01 20:18:53 -05:00
|
|
|
}
|