diff --git a/src/Ryujinx.Cpu/AppleHv/HvExecutionContext.cs b/src/Ryujinx.Cpu/AppleHv/HvExecutionContext.cs
index 8ce358898..63b4b2edc 100644
--- a/src/Ryujinx.Cpu/AppleHv/HvExecutionContext.cs
+++ b/src/Ryujinx.Cpu/AppleHv/HvExecutionContext.cs
@@ -136,6 +136,13 @@ namespace Ryujinx.Cpu.AppleHv
///
public void DebugContinue() => _impl.DebugContinue();
+ ///
+ public ulong DebugPc
+ {
+ get => _impl.DebugPc;
+ set => _impl.DebugPc = value;
+ }
+
///
public void StopRunning()
{
diff --git a/src/Ryujinx.Cpu/AppleHv/HvExecutionContextShadow.cs b/src/Ryujinx.Cpu/AppleHv/HvExecutionContextShadow.cs
index b4e96b561..b9cc08fb2 100644
--- a/src/Ryujinx.Cpu/AppleHv/HvExecutionContextShadow.cs
+++ b/src/Ryujinx.Cpu/AppleHv/HvExecutionContextShadow.cs
@@ -21,6 +21,8 @@ namespace Ryujinx.Cpu.AppleHv
private readonly ulong[] _x;
private readonly V128[] _v;
+ public ulong DebugPc { get; set; }
+
public HvExecutionContextShadow()
{
_x = new ulong[32];
diff --git a/src/Ryujinx.Cpu/AppleHv/HvExecutionContextVcpu.cs b/src/Ryujinx.Cpu/AppleHv/HvExecutionContextVcpu.cs
index a55a2aba2..c581698b9 100644
--- a/src/Ryujinx.Cpu/AppleHv/HvExecutionContextVcpu.cs
+++ b/src/Ryujinx.Cpu/AppleHv/HvExecutionContextVcpu.cs
@@ -19,7 +19,7 @@ namespace Ryujinx.Cpu.AppleHv
internal Barrier _stepBarrier = new Barrier(2);
// This is only valid while debugging is enabled.
- public ulong DebugPc;
+ public ulong DebugPc { get; set; }
static HvExecutionContextVcpu()
{
diff --git a/src/Ryujinx.Cpu/AppleHv/IHvExecutionContext.cs b/src/Ryujinx.Cpu/AppleHv/IHvExecutionContext.cs
index b385cd78e..f12ba9dfc 100644
--- a/src/Ryujinx.Cpu/AppleHv/IHvExecutionContext.cs
+++ b/src/Ryujinx.Cpu/AppleHv/IHvExecutionContext.cs
@@ -47,5 +47,7 @@ namespace Ryujinx.Cpu.AppleHv
void DebugStop();
bool DebugStep();
void DebugContinue();
+
+ ulong DebugPc { get; set; }
}
}
diff --git a/src/Ryujinx.Cpu/IExecutionContext.cs b/src/Ryujinx.Cpu/IExecutionContext.cs
index ad07a2766..927ba120d 100644
--- a/src/Ryujinx.Cpu/IExecutionContext.cs
+++ b/src/Ryujinx.Cpu/IExecutionContext.cs
@@ -113,5 +113,7 @@ namespace Ryujinx.Cpu
void DebugStop();
bool DebugStep();
void DebugContinue();
+
+ ulong DebugPc { get; set; }
}
}
diff --git a/src/Ryujinx.Cpu/Jit/JitExecutionContext.cs b/src/Ryujinx.Cpu/Jit/JitExecutionContext.cs
index a3224c366..fda9e54cb 100644
--- a/src/Ryujinx.Cpu/Jit/JitExecutionContext.cs
+++ b/src/Ryujinx.Cpu/Jit/JitExecutionContext.cs
@@ -118,6 +118,13 @@ namespace Ryujinx.Cpu.Jit
///
public void DebugContinue() => _impl.DebugContinue();
+ ///
+ public ulong DebugPc
+ {
+ get => _impl.DebugPc;
+ set => _impl.DebugPc = value;
+ }
+
///
public void StopRunning()
{
diff --git a/src/Ryujinx.HLE/Debugger/Debugger.cs b/src/Ryujinx.HLE/Debugger/Debugger.cs
new file mode 100644
index 000000000..534938e66
--- /dev/null
+++ b/src/Ryujinx.HLE/Debugger/Debugger.cs
@@ -0,0 +1,410 @@
+using Ryujinx.Common.Logging;
+using Ryujinx.Memory;
+using System;
+using System.Collections.Concurrent;
+using System.Diagnostics;
+using System.Linq;
+using System.Net;
+using System.Net.Sockets;
+using System.Text;
+using System.Threading;
+
+namespace Ryujinx.HLE.Debugger
+{
+ public class Debugger : IDisposable
+ {
+ internal Switch Device { get; private set; }
+
+ public ushort GdbStubPort { get; private set; }
+
+ private TcpListener ListenerSocket;
+ private Socket ClientSocket = null;
+ private NetworkStream ReadStream = null;
+ private NetworkStream WriteStream = null;
+ private BlockingCollection Messages = new BlockingCollection(1);
+ private Thread SocketThread;
+ private Thread HandlerThread;
+
+ private ulong cThread;
+ private ulong gThread;
+
+ public Debugger(Switch device, ushort port)
+ {
+ Device = device;
+ GdbStubPort = port;
+
+ ARMeilleure.Optimizations.EnableDebugging = true;
+
+ SocketThread = new Thread(SocketReaderThreadMain);
+ HandlerThread = new Thread(HandlerThreadMain);
+ SocketThread.Start();
+ HandlerThread.Start();
+ }
+
+ private void HaltApplication() => Device.System.DebugGetApplicationProcess().DebugStopAllThreads();
+ private ulong[] GetThreadIds() => Device.System.DebugGetApplicationProcess().DebugGetThreadUids();
+ private Ryujinx.Cpu.IExecutionContext GetThread(ulong threadUid) => Device.System.DebugGetApplicationProcess().DebugGetThreadContext(threadUid);
+ private Ryujinx.Cpu.IExecutionContext[] GetThreads() => GetThreadIds().Select(x => GetThread(x)).ToArray();
+ private IVirtualMemoryManager GetMemory() => Device.System.DebugGetApplicationProcess().CpuMemory;
+
+ const int GdbRegisterCount = 34;
+
+ private int GdbRegisterHexSize(int gdbRegId)
+ {
+ switch (gdbRegId)
+ {
+ case >= 0 and <= 31:
+ return 16;
+ case 32:
+ return 16;
+ case 33:
+ return 8;
+ default:
+ throw new ArgumentException();
+ }
+ }
+
+ private string GdbReadRegister(Ryujinx.Cpu.IExecutionContext state, int gdbRegId)
+ {
+ switch (gdbRegId)
+ {
+ case >= 0 and <= 31:
+ return $"{state.GetX(gdbRegId):x16}";
+ case 32:
+ return $"{state.DebugPc:x16}";
+ case 33:
+ return $"{state.Pstate:x8}";
+ default:
+ throw new ArgumentException();
+ }
+ }
+
+ private void GdbWriteRegister(Ryujinx.Cpu.IExecutionContext state, int gdbRegId, ulong value)
+ {
+ switch (gdbRegId)
+ {
+ case >= 0 and <= 31:
+ state.SetX(gdbRegId, value);
+ return;
+ case 32:
+ state.DebugPc = value;
+ return;
+ case 33:
+ state.Pstate = (uint)value;
+ return;
+ default:
+ throw new ArgumentException();
+ }
+ }
+
+ private void HandlerThreadMain()
+ {
+ while (true)
+ {
+ switch (Messages.Take())
+ {
+ case AbortMessage _:
+ return;
+
+ case BreakInMessage _:
+ Logger.Notice.Print(LogClass.GdbStub, "Break-in requested");
+ // TODO
+ break;
+
+ case SendNackMessage _:
+ WriteStream.WriteByte((byte)'-');
+ break;
+
+ case CommandMessage { Command: var cmd }:
+ Logger.Debug?.Print(LogClass.GdbStub, $"Received Command: {cmd}");
+ WriteStream.WriteByte((byte)'+');
+ ProcessCommand(cmd);
+ break;
+ }
+ }
+ }
+
+ private void ProcessCommand(string cmd)
+ {
+ StringStream ss = new StringStream(cmd);
+
+ switch (ss.ReadChar())
+ {
+ case '!':
+ if (!ss.IsEmpty())
+ {
+ goto default;
+ }
+ // Enable extended mode
+ Reply("OK");
+ break;
+ case '?':
+ if (!ss.IsEmpty())
+ {
+ goto default;
+ }
+ CommandQuery();
+ break;
+ case 'c':
+ CommandContinue(ss.IsEmpty() ? null : ss.ReadRemainingAsHex());
+ break;
+ case 'D':
+ if (!ss.IsEmpty())
+ {
+ goto default;
+ }
+ CommandDetach();
+ break;
+ case 'g':
+ if (!ss.IsEmpty())
+ {
+ goto default;
+ }
+ CommandReadGeneralRegisters();
+ break;
+ case 'G':
+ CommandWriteGeneralRegisters(ss);
+ break;
+ case 'H':
+ {
+ char op = ss.ReadChar();
+ ulong threadId = ss.ReadRemainingAsHex();
+ CommandSetThread(op, threadId);
+ break;
+ }
+ case 'k':
+ Logger.Notice.Print(LogClass.GdbStub, "Kill request received");
+ Reply("");
+ break;
+ case 'm':
+ {
+ ulong addr = ss.ReadUntilAsHex(',');
+ ulong len = ss.ReadRemainingAsHex();
+ CommandReadMemory(addr, len);
+ break;
+ }
+ case 'M':
+ {
+ ulong addr = ss.ReadUntilAsHex(',');
+ ulong len = ss.ReadUntilAsHex(':');
+ CommandWriteMemory(addr, len, ss);
+ break;
+ }
+ case 'p':
+ {
+ ulong gdbRegId = ss.ReadRemainingAsHex();
+ CommandReadGeneralRegister((int)gdbRegId);
+ break;
+ }
+ case 'P':
+ {
+ ulong gdbRegId = ss.ReadUntilAsHex('=');
+ ulong value = ss.ReadRemainingAsHex();
+ CommandWriteGeneralRegister((int)gdbRegId, value);
+ break;
+ }
+ default:
+ Logger.Notice.Print(LogClass.GdbStub, $"Unknown command: {cmd}");
+ Reply("");
+ break;
+ }
+ }
+
+ void CommandQuery()
+ {
+ // GDB is performing initial contact. Stop everything.
+ HaltApplication();
+ gThread = cThread = GetThreadIds().First();
+ Reply($"T05thread:{cThread:x}");
+ }
+
+ void CommandContinue(ulong? newPc)
+ {
+ if (newPc.HasValue)
+ {
+ GetThread(cThread).DebugPc = newPc.Value;
+ }
+
+ foreach (var thread in GetThreads())
+ {
+ thread.DebugContinue();
+ }
+ }
+
+ void CommandDetach()
+ {
+ // TODO: Remove all breakpoints
+ CommandContinue(null);
+ }
+
+ void CommandReadGeneralRegisters()
+ {
+ var ctx = GetThread(gThread);
+ string registers = "";
+ for (int i = 0; i < GdbRegisterCount; i++)
+ {
+ registers += GdbReadRegister(ctx, i);
+ }
+ Reply(registers);
+ }
+
+ void CommandWriteGeneralRegisters(StringStream ss)
+ {
+ var ctx = GetThread(gThread);
+ for (int i = 0; i < GdbRegisterCount; i++)
+ {
+ GdbWriteRegister(ctx, i, ss.ReadLengthAsHex(GdbRegisterHexSize(i)));
+ }
+ Reply(ss.IsEmpty() ? "OK" : "E99");
+ }
+
+ void CommandSetThread(char op, ulong threadId)
+ {
+ switch (op)
+ {
+ case 'c':
+ cThread = threadId;
+ Reply("OK");
+ return;
+ case 'g':
+ gThread = threadId;
+ Reply("OK");
+ return;
+ default:
+ Reply("E99");
+ return;
+ }
+ }
+
+ void CommandReadMemory(ulong addr, ulong len)
+ {
+ var data = new byte[len];
+ GetMemory().Read(addr, data);
+ Reply(string.Join("", data.Select(x => $"{x:x2}")));
+ }
+
+ void CommandWriteMemory(ulong addr, ulong len, StringStream ss)
+ {
+ var data = new byte[len];
+ for (ulong i = 0; i < len; i++)
+ {
+ data[i] = (byte)ss.ReadLengthAsHex(2);
+ }
+ GetMemory().Write(addr, data);
+ }
+
+ void CommandReadGeneralRegister(int gdbRegId)
+ {
+ var ctx = GetThread(gThread);
+ Reply(GdbReadRegister(ctx, gdbRegId));
+ }
+
+ void CommandWriteGeneralRegister(int gdbRegId, ulong value)
+ {
+ var ctx = GetThread(gThread);
+ GdbWriteRegister(ctx, gdbRegId, value);
+ Reply("OK");
+ }
+
+ private void Reply(string cmd)
+ {
+ WriteStream.Write(Encoding.ASCII.GetBytes($"${cmd}#{CalculateChecksum(cmd):x2}"));
+ }
+
+ private void SocketReaderThreadMain()
+ {
+ restartListen:
+ try
+ {
+ var endpoint = new IPEndPoint(IPAddress.Any, GdbStubPort);
+ ListenerSocket = new TcpListener(endpoint);
+ ListenerSocket.Start();
+ Logger.Notice.Print(LogClass.GdbStub, $"Currently waiting on {endpoint} for GDB client");
+
+ ClientSocket = ListenerSocket.AcceptSocket();
+ ReadStream = new NetworkStream(ClientSocket, System.IO.FileAccess.Read);
+ WriteStream = new NetworkStream(ClientSocket, System.IO.FileAccess.Write);
+ Logger.Notice.Print(LogClass.GdbStub, "GDB client connected");
+
+ while (true)
+ {
+ switch (ReadStream.ReadByte())
+ {
+ case -1:
+ goto eof;
+ case '+':
+ continue;
+ case '-':
+ Logger.Notice.Print(LogClass.GdbStub, "NACK received!");
+ continue;
+ case '\x03':
+ Messages.Add(new BreakInMessage());
+ break;
+ case '$':
+ string cmd = "";
+ while (true)
+ {
+ int x = ReadStream.ReadByte();
+ if (x == -1)
+ goto eof;
+ if (x == '#')
+ break;
+ cmd += (char)x;
+ }
+
+ string checksum = $"{(char)ReadStream.ReadByte()}{(char)ReadStream.ReadByte()}";
+ // Debug.Assert(checksum == $"{CalculateChecksum(cmd):x2}");
+
+ Messages.Add(new CommandMessage(cmd));
+ break;
+ }
+ }
+
+ eof:
+ Logger.Notice.Print(LogClass.GdbStub, "GDB client lost connection");
+ goto restartListen;
+ }
+ catch (Exception)
+ {
+ Logger.Notice.Print(LogClass.GdbStub, "GDB stub socket closed");
+ return;
+ }
+ }
+
+ private byte CalculateChecksum(string cmd)
+ {
+ byte checksum = 0;
+ foreach (char x in cmd)
+ {
+ unchecked
+ {
+ checksum += (byte)x;
+ }
+ }
+ return checksum;
+ }
+
+ public void Dispose()
+ {
+ Dispose(true);
+ }
+
+ protected virtual void Dispose(bool disposing)
+ {
+ if (disposing)
+ {
+ if (HandlerThread.IsAlive)
+ {
+ Messages.Add(new AbortMessage());
+ }
+ ListenerSocket.Stop();
+ ClientSocket?.Shutdown(SocketShutdown.Both);
+ ClientSocket?.Close();
+ ReadStream?.Close();
+ WriteStream?.Close();
+ SocketThread.Join();
+ HandlerThread.Join();
+ }
+ }
+ }
+}
diff --git a/src/Ryujinx.HLE/Debugger/GdbSignal.cs b/src/Ryujinx.HLE/Debugger/GdbSignal.cs
new file mode 100644
index 000000000..687194ef3
--- /dev/null
+++ b/src/Ryujinx.HLE/Debugger/GdbSignal.cs
@@ -0,0 +1,15 @@
+namespace Ryujinx.HLE.Debugger
+{
+ enum GdbSignal
+ {
+ Zero = 0,
+ Int = 2,
+ Quit = 3,
+ Trap = 5,
+ Abort = 6,
+ Alarm = 14,
+ IO = 23,
+ XCPU = 24,
+ Unknown = 143
+ }
+}
diff --git a/src/Ryujinx.HLE/Debugger/Message/AbortMessage.cs b/src/Ryujinx.HLE/Debugger/Message/AbortMessage.cs
new file mode 100644
index 000000000..2c0d6bb79
--- /dev/null
+++ b/src/Ryujinx.HLE/Debugger/Message/AbortMessage.cs
@@ -0,0 +1,6 @@
+namespace Ryujinx.HLE.Debugger
+{
+ struct AbortMessage : IMessage
+ {
+ }
+}
diff --git a/src/Ryujinx.HLE/Debugger/Message/BreakInMessage.cs b/src/Ryujinx.HLE/Debugger/Message/BreakInMessage.cs
new file mode 100644
index 000000000..24cfb0b4a
--- /dev/null
+++ b/src/Ryujinx.HLE/Debugger/Message/BreakInMessage.cs
@@ -0,0 +1,6 @@
+namespace Ryujinx.HLE.Debugger
+{
+ struct BreakInMessage : IMessage
+ {
+ }
+}
diff --git a/src/Ryujinx.HLE/Debugger/Message/CommandMessage.cs b/src/Ryujinx.HLE/Debugger/Message/CommandMessage.cs
new file mode 100644
index 000000000..72320532f
--- /dev/null
+++ b/src/Ryujinx.HLE/Debugger/Message/CommandMessage.cs
@@ -0,0 +1,12 @@
+namespace Ryujinx.HLE.Debugger
+{
+ struct CommandMessage : IMessage
+ {
+ public string Command;
+
+ public CommandMessage(string cmd)
+ {
+ Command = cmd;
+ }
+ }
+}
diff --git a/src/Ryujinx.HLE/Debugger/Message/IMessage.cs b/src/Ryujinx.HLE/Debugger/Message/IMessage.cs
new file mode 100644
index 000000000..d530d00d3
--- /dev/null
+++ b/src/Ryujinx.HLE/Debugger/Message/IMessage.cs
@@ -0,0 +1,6 @@
+namespace Ryujinx.HLE.Debugger
+{
+ interface IMessage
+ {
+ }
+}
diff --git a/src/Ryujinx.HLE/Debugger/Message/SendNackMessage.cs b/src/Ryujinx.HLE/Debugger/Message/SendNackMessage.cs
new file mode 100644
index 000000000..f599ee91c
--- /dev/null
+++ b/src/Ryujinx.HLE/Debugger/Message/SendNackMessage.cs
@@ -0,0 +1,6 @@
+namespace Ryujinx.HLE.Debugger
+{
+ struct SendNackMessage : IMessage
+ {
+ }
+}
diff --git a/src/Ryujinx.HLE/Debugger/StringStream.cs b/src/Ryujinx.HLE/Debugger/StringStream.cs
new file mode 100644
index 000000000..b654f6f54
--- /dev/null
+++ b/src/Ryujinx.HLE/Debugger/StringStream.cs
@@ -0,0 +1,68 @@
+using System.Globalization;
+
+namespace Ryujinx.HLE.Debugger
+{
+ class StringStream
+ {
+ private readonly string Data;
+ private int Position;
+
+ public StringStream(string s)
+ {
+ Data = s;
+ }
+
+ public char ReadChar()
+ {
+ return Data[Position++];
+ }
+
+ public string ReadUntil(char needle)
+ {
+ int needlePos = Data.IndexOf(needle, Position);
+
+ if (needlePos == -1)
+ {
+ needlePos = Data.Length;
+ }
+
+ string result = Data.Substring(Position, needlePos - Position);
+ Position = needlePos + 1;
+ return result;
+ }
+
+ public string ReadLength(int len)
+ {
+ string result = Data.Substring(Position, len);
+ Position += len;
+ return result;
+ }
+
+ public string ReadRemaining()
+ {
+ string result = Data.Substring(Position);
+ Position = Data.Length;
+ return result;
+ }
+
+ public ulong ReadRemainingAsHex()
+ {
+ return ulong.Parse(ReadRemaining(), NumberStyles.HexNumber);
+ }
+
+ public ulong ReadUntilAsHex(char needle)
+ {
+ return ulong.Parse(ReadUntil(needle), NumberStyles.HexNumber);
+ }
+
+ public ulong ReadLengthAsHex(int len)
+ {
+ return ulong.Parse(ReadLength(len), NumberStyles.HexNumber);
+ }
+
+ public bool IsEmpty()
+ {
+ return Position >= Data.Length;
+ }
+ }
+}
diff --git a/src/Ryujinx.HLE/HOS/Kernel/Process/ProcessExecutionContext.cs b/src/Ryujinx.HLE/HOS/Kernel/Process/ProcessExecutionContext.cs
index 6050f88f2..f9718280e 100644
--- a/src/Ryujinx.HLE/HOS/Kernel/Process/ProcessExecutionContext.cs
+++ b/src/Ryujinx.HLE/HOS/Kernel/Process/ProcessExecutionContext.cs
@@ -21,6 +21,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
private readonly ulong[] _x = new ulong[32];
+ public ulong DebugPc { get; set; }
+
public ulong GetX(int index) => _x[index];
public void SetX(int index, ulong value) => _x[index] = value;
diff --git a/src/Ryujinx.HLE/Switch.cs b/src/Ryujinx.HLE/Switch.cs
index 9dfc69892..89bf7b975 100644
--- a/src/Ryujinx.HLE/Switch.cs
+++ b/src/Ryujinx.HLE/Switch.cs
@@ -26,6 +26,7 @@ namespace Ryujinx.HLE
public Hid Hid { get; }
public TamperMachine TamperMachine { get; }
public IHostUIHandler UIHandler { get; }
+ public Debugger.Debugger Debugger { get; }
public bool EnableDeviceVsync { get; set; } = true;
@@ -53,6 +54,7 @@ namespace Ryujinx.HLE
Statistics = new PerformanceStatistics();
Hid = new Hid(this, System.HidStorage);
Processes = new ProcessLoader(this);
+ Debugger = Configuration.EnableGdbStub ? new Debugger.Debugger(this, configuration.GdbStubPort) : null;
TamperMachine = new TamperMachine();
System.InitializeServices();
@@ -154,6 +156,7 @@ namespace Ryujinx.HLE
AudioDeviceDriver.Dispose();
FileSystem.Dispose();
Memory.Dispose();
+ Debugger.Dispose();
}
}
}
diff --git a/src/Ryujinx.Headless.SDL2/Options.cs b/src/Ryujinx.Headless.SDL2/Options.cs
index ea2063758..5891319c7 100644
--- a/src/Ryujinx.Headless.SDL2/Options.cs
+++ b/src/Ryujinx.Headless.SDL2/Options.cs
@@ -229,5 +229,13 @@ namespace Ryujinx.Headless.SDL2
[Value(0, MetaName = "input", HelpText = "Input to load.", Required = true)]
public string InputPath { get; set; }
+
+ // Debugging
+
+ [Option("enable-gdb-stub", Required = false, Default = false, HelpText = "Enable the GDB stub.")]
+ public bool EnableGdbStub { get; set; }
+
+ [Option("gdb-stub-port", Required = false, Default = 55555, HelpText = "GDB stub port.")]
+ public ushort GdbStubPort { get; set; }
}
}
diff --git a/src/Ryujinx.Headless.SDL2/Program.cs b/src/Ryujinx.Headless.SDL2/Program.cs
index 85aff6712..d6cf7d6d6 100644
--- a/src/Ryujinx.Headless.SDL2/Program.cs
+++ b/src/Ryujinx.Headless.SDL2/Program.cs
@@ -571,7 +571,9 @@ namespace Ryujinx.Headless.SDL2
options.AudioVolume,
options.UseHypervisor ?? true,
options.MultiplayerLanInterfaceId,
- Common.Configuration.Multiplayer.MultiplayerMode.Disabled);
+ Common.Configuration.Multiplayer.MultiplayerMode.Disabled,
+ options.EnableGdbStub,
+ options.GdbStubPort);
return new Switch(configuration);
}
diff --git a/src/Ryujinx/AppHost.cs b/src/Ryujinx/AppHost.cs
index 0db8ef414..65ef63926 100644
--- a/src/Ryujinx/AppHost.cs
+++ b/src/Ryujinx/AppHost.cs
@@ -872,7 +872,9 @@ namespace Ryujinx.Ava
ConfigurationState.Instance.System.AudioVolume,
ConfigurationState.Instance.System.UseHypervisor,
ConfigurationState.Instance.Multiplayer.LanInterfaceId.Value,
- ConfigurationState.Instance.Multiplayer.Mode);
+ ConfigurationState.Instance.Multiplayer.Mode,
+ ConfigurationState.Instance.Debug.EnableGdbStub.Value,
+ ConfigurationState.Instance.Debug.GdbStubPort.Value);
Device = new Switch(configuration);
}