diff --git a/src/Ryujinx.Cpu/IExecutionContext.cs b/src/Ryujinx.Cpu/IExecutionContext.cs
index df0c94278..c3ebe5aa5 100644
--- a/src/Ryujinx.Cpu/IExecutionContext.cs
+++ b/src/Ryujinx.Cpu/IExecutionContext.cs
@@ -42,6 +42,11 @@ namespace Ryujinx.Cpu
///
uint Fpsr { get; set; }
+ ///
+ /// Floating-point Status and Control Register.
+ ///
+ uint Fpscr => Fpsr | Fpcr;
+
///
/// Indicates whenever the CPU is running 64-bit (AArch64 mode) or 32-bit (AArch32 mode) code.
///
diff --git a/src/Ryujinx.HLE/Debugger/Debugger.MainThread.cs b/src/Ryujinx.HLE/Debugger/Debugger.MainThread.cs
index 2e1f40120..c4ec001bf 100644
--- a/src/Ryujinx.HLE/Debugger/Debugger.MainThread.cs
+++ b/src/Ryujinx.HLE/Debugger/Debugger.MainThread.cs
@@ -64,10 +64,10 @@ namespace Ryujinx.HLE.Debugger
Logger.Notice.Print(LogClass.GdbStub, "NACK received!");
continue;
case '\x03':
- _messages.Add(new BreakInMessage());
+ _messages.Add(StatelessMessage.BreakIn);
break;
case '$':
- string cmd = "";
+ string cmd = string.Empty;
while (true)
{
int x = _readStream.ReadByte();
@@ -85,7 +85,7 @@ namespace Ryujinx.HLE.Debugger
}
else
{
- _messages.Add(new SendNackMessage());
+ _messages.Add(StatelessMessage.SendNack);
}
break;
diff --git a/src/Ryujinx.HLE/Debugger/Debugger.MessageHandler.cs b/src/Ryujinx.HLE/Debugger/Debugger.MessageHandler.cs
new file mode 100644
index 000000000..4e2cdc237
--- /dev/null
+++ b/src/Ryujinx.HLE/Debugger/Debugger.MessageHandler.cs
@@ -0,0 +1,58 @@
+using Ryujinx.Common.Logging;
+using System;
+using System.IO;
+
+namespace Ryujinx.HLE.Debugger
+{
+ public partial class Debugger
+ {
+ private void MessageHandlerMain()
+ {
+ while (!_shuttingDown)
+ {
+ try
+ {
+ switch (_messages.Take())
+ {
+ case StatelessMessage { Type: MessageType.BreakIn }:
+ Logger.Notice.Print(LogClass.GdbStub, "Break-in requested");
+ _commands.Interrupt();
+ break;
+
+ case StatelessMessage { Type: MessageType.SendNack }:
+ _writeStream.WriteByte((byte)'-');
+ break;
+
+ case StatelessMessage { Type: MessageType.Kill }:
+ return;
+
+ case CommandMessage { Command: { } cmd }:
+ Logger.Debug?.Print(LogClass.GdbStub, $"Received Command: {cmd}");
+ _writeStream.WriteByte((byte)'+');
+ _commandProcessor.Process(cmd);
+ break;
+
+ case ThreadBreakMessage { Context: { } ctx }:
+ DebugProcess.DebugStop();
+ GThread = CThread = ctx.ThreadUid;
+ _breakHandlerEvent.Set();
+ _commandProcessor.Reply($"T05thread:{ctx.ThreadUid:x};");
+ break;
+ }
+ }
+ catch (IOException e)
+ {
+ Logger.Error?.Print(LogClass.GdbStub, "Error while processing GDB messages", e);
+ }
+ catch (NullReferenceException e)
+ {
+ Logger.Error?.Print(LogClass.GdbStub, "Error while processing GDB messages", e);
+ }
+ catch (ObjectDisposedException e)
+ {
+ Logger.Error?.Print(LogClass.GdbStub, "Error while processing GDB messages", e);
+ }
+ }
+ }
+ }
+}
diff --git a/src/Ryujinx.HLE/Debugger/Debugger.Rcmd.cs b/src/Ryujinx.HLE/Debugger/Debugger.Rcmd.cs
new file mode 100644
index 000000000..302969011
--- /dev/null
+++ b/src/Ryujinx.HLE/Debugger/Debugger.Rcmd.cs
@@ -0,0 +1,103 @@
+using Ryujinx.Common.Logging;
+using Ryujinx.HLE.HOS.Kernel.Process;
+using System;
+using System.Text;
+
+namespace Ryujinx.HLE.Debugger
+{
+ public partial class Debugger
+ {
+ public string GetStackTrace()
+ {
+ if (GThread == null)
+ return "No thread selected\n";
+
+ return Process?.Debugger?.GetGuestStackTrace(DebugProcess.GetThread(GThread.Value)) ?? "No application process found\n";
+ }
+
+ public string GetRegisters()
+ {
+ if (GThread == null)
+ return "No thread selected\n";
+
+ return Process?.Debugger?.GetCpuRegisterPrintout(DebugProcess.GetThread(GThread.Value)) ?? "No application process found\n";
+ }
+
+ public string GetMinidump()
+ {
+ var response = new StringBuilder();
+ response.AppendLine("=== Begin Minidump ===\n");
+ response.AppendLine(GetProcessInfo());
+
+ foreach (var thread in GetThreads())
+ {
+ response.AppendLine($"=== Thread {thread.ThreadUid} ===");
+ try
+ {
+ string stackTrace = Process.Debugger.GetGuestStackTrace(thread);
+ response.AppendLine(stackTrace);
+ }
+ catch (Exception e)
+ {
+ response.AppendLine($"[Error getting stack trace: {e.Message}]");
+ }
+
+ try
+ {
+ string registers = Process.Debugger.GetCpuRegisterPrintout(thread);
+ response.AppendLine(registers);
+ }
+ catch (Exception e)
+ {
+ response.AppendLine($"[Error getting registers: {e.Message}]");
+ }
+ }
+
+ response.AppendLine("=== End Minidump ===");
+
+ Logger.Info?.Print(LogClass.GdbStub, response.ToString());
+ return response.ToString();
+ }
+
+ public string GetProcessInfo()
+ {
+ try
+ {
+ if (Process is not { } kProcess)
+ return "No application process found\n";
+
+ var sb = new StringBuilder();
+
+ sb.AppendLine($"Program Id: 0x{kProcess.TitleId:x16}");
+ sb.AppendLine($"Application: {(kProcess.IsApplication ? 1 : 0)}");
+ sb.AppendLine("Layout:");
+ sb.AppendLine(
+ $" Alias: 0x{kProcess.MemoryManager.AliasRegionStart:x10} - 0x{kProcess.MemoryManager.AliasRegionEnd - 1:x10}");
+ sb.AppendLine(
+ $" Heap: 0x{kProcess.MemoryManager.HeapRegionStart:x10} - 0x{kProcess.MemoryManager.HeapRegionEnd - 1:x10}");
+ sb.AppendLine(
+ $" Aslr: 0x{kProcess.MemoryManager.AslrRegionStart:x10} - 0x{kProcess.MemoryManager.AslrRegionEnd - 1:x10}");
+ sb.AppendLine(
+ $" Stack: 0x{kProcess.MemoryManager.StackRegionStart:x10} - 0x{kProcess.MemoryManager.StackRegionEnd - 1:x10}");
+
+ sb.AppendLine("Modules:");
+ var debugger = kProcess.Debugger;
+ if (debugger != null)
+ {
+ foreach (HleProcessDebugger.Image image in debugger.GetLoadedImages())
+ {
+ ulong endAddress = image.BaseAddress + image.Size - 1;
+ sb.AppendLine($" 0x{image.BaseAddress:x10} - 0x{endAddress:x10} {image.Name}");
+ }
+ }
+
+ return sb.ToString();
+ }
+ catch (Exception e)
+ {
+ Logger.Error?.Print(LogClass.GdbStub, $"Error getting process info: {e.Message}");
+ return $"Error getting process info: {e.Message}\n";
+ }
+ }
+ }
+}
diff --git a/src/Ryujinx.HLE/Debugger/Debugger.cs b/src/Ryujinx.HLE/Debugger/Debugger.cs
index e8eef26a3..6a5da60ee 100644
--- a/src/Ryujinx.HLE/Debugger/Debugger.cs
+++ b/src/Ryujinx.HLE/Debugger/Debugger.cs
@@ -57,172 +57,24 @@ namespace Ryujinx.HLE.Debugger
internal KProcess Process => Device.System?.DebugGetApplicationProcess();
internal IDebuggableProcess DebugProcess => Device.System?.DebugGetApplicationProcessDebugInterface();
- internal KThread[] GetThreads() =>
- DebugProcess.GetThreadUids().Select(x => DebugProcess.GetThread(x)).ToArray();
+ internal KThread[] GetThreads() => DebugProcess.ThreadUids.Select(DebugProcess.GetThread).ToArray();
internal bool IsProcess32Bit => DebugProcess.GetThread(GThread.Value).Context.IsAarch32;
-
- private void MessageHandlerMain()
- {
- while (!_shuttingDown)
- {
- IMessage msg = _messages.Take();
- try
- {
- switch (msg)
- {
- case BreakInMessage:
- Logger.Notice.Print(LogClass.GdbStub, "Break-in requested");
- _commandProcessor.Commands.Interrupt();
- break;
-
- case SendNackMessage:
- _writeStream.WriteByte((byte)'-');
- break;
-
- case CommandMessage { Command: var cmd }:
- Logger.Debug?.Print(LogClass.GdbStub, $"Received Command: {cmd}");
- _writeStream.WriteByte((byte)'+');
- _commandProcessor.Process(cmd);
- break;
-
- case ThreadBreakMessage { Context: var ctx }:
- DebugProcess.DebugStop();
- GThread = CThread = ctx.ThreadUid;
- _breakHandlerEvent.Set();
- _commandProcessor.Reply($"T05thread:{ctx.ThreadUid:x};");
- break;
-
- case KillMessage:
- return;
- }
- }
- catch (IOException e)
- {
- Logger.Error?.Print(LogClass.GdbStub, "Error while processing GDB messages", e);
- }
- catch (NullReferenceException e)
- {
- Logger.Error?.Print(LogClass.GdbStub, "Error while processing GDB messages", e);
- }
- catch (ObjectDisposedException e)
- {
- Logger.Error?.Print(LogClass.GdbStub, "Error while processing GDB messages", e);
- }
- }
- }
-
- internal bool WriteRegister(IExecutionContext ctx, int gdbRegId, StringStream ss) =>
+
+ internal bool WriteRegister(IExecutionContext ctx, int registerId, StringStream ss) =>
IsProcess32Bit
- ? ctx.WriteRegister32(gdbRegId, ss)
- : ctx.WriteRegister64(gdbRegId, ss);
+ ? ctx.WriteRegister32(registerId, ss)
+ : ctx.WriteRegister64(registerId, ss);
- internal string ReadRegister(IExecutionContext ctx, int gdbRegId) =>
+ internal string ReadRegister(IExecutionContext ctx, int registerId) =>
IsProcess32Bit
- ? ctx.ReadRegister32(gdbRegId)
- : ctx.ReadRegister64(gdbRegId);
-
- public string GetStackTrace()
- {
- if (GThread == null)
- return "No thread selected\n";
-
- return Process?.Debugger?.GetGuestStackTrace(DebugProcess.GetThread(GThread.Value)) ?? "No application process found\n";
- }
-
- public string GetRegisters()
- {
- if (GThread == null)
- return "No thread selected\n";
-
- return Process?.Debugger?.GetCpuRegisterPrintout(DebugProcess.GetThread(GThread.Value)) ?? "No application process found\n";
- }
-
- public string GetMinidump()
- {
- var response = new StringBuilder();
- response.AppendLine("=== Begin Minidump ===\n");
- response.AppendLine(GetProcessInfo());
-
- foreach (var thread in GetThreads())
- {
- response.AppendLine($"=== Thread {thread.ThreadUid} ===");
- try
- {
- string stackTrace = Process.Debugger.GetGuestStackTrace(thread);
- response.AppendLine(stackTrace);
- }
- catch (Exception e)
- {
- response.AppendLine($"[Error getting stack trace: {e.Message}]");
- }
-
- try
- {
- string registers = Process.Debugger.GetCpuRegisterPrintout(thread);
- response.AppendLine(registers);
- }
- catch (Exception e)
- {
- response.AppendLine($"[Error getting registers: {e.Message}]");
- }
- }
-
- response.AppendLine("=== End Minidump ===");
-
- Logger.Info?.Print(LogClass.GdbStub, response.ToString());
- return response.ToString();
- }
-
- public string GetProcessInfo()
- {
- try
- {
- if (Process == null)
- return "No application process found\n";
-
- KProcess kProcess = Process;
-
- var sb = new StringBuilder();
-
- sb.AppendLine($"Program Id: 0x{kProcess.TitleId:x16}");
- sb.AppendLine($"Application: {(kProcess.IsApplication ? 1 : 0)}");
- sb.AppendLine("Layout:");
- sb.AppendLine(
- $" Alias: 0x{kProcess.MemoryManager.AliasRegionStart:x10} - 0x{kProcess.MemoryManager.AliasRegionEnd - 1:x10}");
- sb.AppendLine(
- $" Heap: 0x{kProcess.MemoryManager.HeapRegionStart:x10} - 0x{kProcess.MemoryManager.HeapRegionEnd - 1:x10}");
- sb.AppendLine(
- $" Aslr: 0x{kProcess.MemoryManager.AslrRegionStart:x10} - 0x{kProcess.MemoryManager.AslrRegionEnd - 1:x10}");
- sb.AppendLine(
- $" Stack: 0x{kProcess.MemoryManager.StackRegionStart:x10} - 0x{kProcess.MemoryManager.StackRegionEnd - 1:x10}");
-
- sb.AppendLine("Modules:");
- var debugger = kProcess.Debugger;
- if (debugger != null)
- {
- var images = debugger.GetLoadedImages();
- for (int i = 0; i < images.Count; i++)
- {
- var image = images[i];
- ulong endAddress = image.BaseAddress + image.Size - 1;
- string name = image.Name;
- sb.AppendLine($" 0x{image.BaseAddress:x10} - 0x{endAddress:x10} {name}");
- }
- }
-
- return sb.ToString();
- }
- catch (Exception e)
- {
- Logger.Error?.Print(LogClass.GdbStub, $"Error getting process info: {e.Message}");
- return $"Error getting process info: {e.Message}\n";
- }
- }
+ ? ctx.ReadRegister32(registerId)
+ : ctx.ReadRegister64(registerId);
public void Dispose()
{
Dispose(true);
+ GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
@@ -237,7 +89,7 @@ namespace Ryujinx.HLE.Debugger
_readStream?.Close();
_writeStream?.Close();
_debuggerThread.Join();
- _messages.Add(new KillMessage());
+ _messages.Add(StatelessMessage.Kill);
_messageHandlerThread.Join();
_messages.Dispose();
_breakHandlerEvent.Dispose();
diff --git a/src/Ryujinx.HLE/Debugger/Gdb/CommandProcessor.cs b/src/Ryujinx.HLE/Debugger/Gdb/CommandProcessor.cs
index 997b635e4..a07dafd1c 100644
--- a/src/Ryujinx.HLE/Debugger/Gdb/CommandProcessor.cs
+++ b/src/Ryujinx.HLE/Debugger/Gdb/CommandProcessor.cs
@@ -53,7 +53,7 @@ namespace Ryujinx.HLE.Debugger.Gdb
switch (ss.ReadChar())
{
case '!':
- if (!ss.IsEmpty())
+ if (!ss.IsEmpty)
{
goto unknownCommand;
}
@@ -62,7 +62,7 @@ namespace Ryujinx.HLE.Debugger.Gdb
ReplyOK();
break;
case '?':
- if (!ss.IsEmpty())
+ if (!ss.IsEmpty)
{
goto unknownCommand;
}
@@ -70,10 +70,10 @@ namespace Ryujinx.HLE.Debugger.Gdb
Commands.Query();
break;
case 'c':
- Commands.Continue(ss.IsEmpty() ? null : ss.ReadRemainingAsHex());
+ Commands.Continue(ss.IsEmpty ? null : ss.ReadRemainingAsHex());
break;
case 'D':
- if (!ss.IsEmpty())
+ if (!ss.IsEmpty)
{
goto unknownCommand;
}
@@ -81,7 +81,7 @@ namespace Ryujinx.HLE.Debugger.Gdb
Commands.Detach();
break;
case 'g':
- if (!ss.IsEmpty())
+ if (!ss.IsEmpty)
{
goto unknownCommand;
}
@@ -172,7 +172,7 @@ namespace Ryujinx.HLE.Debugger.Gdb
if (ss.ConsumeRemaining("fThreadInfo"))
{
Reply(
- $"m{Debugger.DebugProcess.GetThreadUids().Select(x => $"{x:x}").JoinToString(",")}");
+ $"m{Debugger.DebugProcess.ThreadUids.Select(x => $"{x:x}").JoinToString(",")}");
break;
}
@@ -225,7 +225,7 @@ namespace Ryujinx.HLE.Debugger.Gdb
if (len >= (ulong)data.Length - offset)
{
- Reply("l" + Helpers.ToBinaryFormat(data.Substring((int)offset)));
+ Reply("l" + Helpers.ToBinaryFormat(data[(int)offset..]));
}
else
{
@@ -274,7 +274,7 @@ namespace Ryujinx.HLE.Debugger.Gdb
case 'Q':
goto unknownCommand;
case 's':
- Commands.Step(ss.IsEmpty() ? null : ss.ReadRemainingAsHex());
+ Commands.Step(ss.IsEmpty ? null : ss.ReadRemainingAsHex());
break;
case 'T':
{
diff --git a/src/Ryujinx.HLE/Debugger/Gdb/Commands.cs b/src/Ryujinx.HLE/Debugger/Gdb/Commands.cs
index 6468e1452..9093440eb 100644
--- a/src/Ryujinx.HLE/Debugger/Gdb/Commands.cs
+++ b/src/Ryujinx.HLE/Debugger/Gdb/Commands.cs
@@ -53,7 +53,7 @@ namespace Ryujinx.HLE.Debugger.Gdb
{
// GDB is performing initial contact. Stop everything.
Debugger.DebugProcess.DebugStop();
- Debugger.GThread = Debugger.CThread = Debugger.DebugProcess.GetThreadUids().First();
+ Debugger.GThread = Debugger.CThread = Debugger.DebugProcess.ThreadUids.First();
Processor.Reply($"T05thread:{Debugger.CThread:x};");
}
@@ -63,7 +63,7 @@ namespace Ryujinx.HLE.Debugger.Gdb
Debugger.DebugProcess.DebugStop();
if (Debugger.GThread == null || Debugger.GetThreads().All(x => x.ThreadUid != Debugger.GThread.Value))
{
- Debugger.GThread = Debugger.CThread = Debugger.DebugProcess.GetThreadUids().First();
+ Debugger.GThread = Debugger.CThread = Debugger.DebugProcess.ThreadUids.First();
}
Processor.Reply($"T02thread:{Debugger.GThread:x};");
@@ -151,7 +151,7 @@ namespace Ryujinx.HLE.Debugger.Gdb
}
}
- Processor.Reply(ss.IsEmpty());
+ Processor.Reply(ss.IsEmpty);
}
internal void SetThread(char op, ulong? threadId)
@@ -251,7 +251,7 @@ namespace Ryujinx.HLE.Debugger.Gdb
IExecutionContext ctx = Debugger.DebugProcess.GetThread(Debugger.GThread.Value).Context;
- Processor.Reply(Debugger.WriteRegister(ctx, gdbRegId, ss) && ss.IsEmpty());
+ Processor.Reply(Debugger.WriteRegister(ctx, gdbRegId, ss) && ss.IsEmpty);
}
internal void Step(ulong? newPc)
diff --git a/src/Ryujinx.HLE/Debugger/Gdb/Registers.cs b/src/Ryujinx.HLE/Debugger/Gdb/Registers.cs
index ebd89459f..31203b62b 100644
--- a/src/Ryujinx.HLE/Debugger/Gdb/Registers.cs
+++ b/src/Ryujinx.HLE/Debugger/Gdb/Registers.cs
@@ -13,65 +13,56 @@ namespace Ryujinx.HLE.Debugger.Gdb
*/
private const uint FpcrMask = 0xfc1fffff;
- public static string ReadRegister64(this IExecutionContext state, int gdbRegId)
- {
- switch (gdbRegId)
+ public static string ReadRegister64(this IExecutionContext state, int registerId) =>
+ registerId switch
{
- case >= 0 and <= 31:
- return Helpers.ToHex(BitConverter.GetBytes(state.GetX(gdbRegId)));
- case 32:
- return Helpers.ToHex(BitConverter.GetBytes(state.DebugPc));
- case 33:
- return Helpers.ToHex(BitConverter.GetBytes(state.Pstate));
- case >= 34 and <= 65:
- return Helpers.ToHex(state.GetV(gdbRegId - 34).ToArray());
- case 66:
- return Helpers.ToHex(BitConverter.GetBytes((uint)state.Fpsr));
- case 67:
- return Helpers.ToHex(BitConverter.GetBytes((uint)state.Fpcr));
- default:
- return null;
- }
- }
+ >= 0 and <= 31 => Helpers.ToHex(BitConverter.GetBytes(state.GetX(registerId))),
+ 32 => Helpers.ToHex(BitConverter.GetBytes(state.DebugPc)),
+ 33 => Helpers.ToHex(BitConverter.GetBytes(state.Pstate)),
+ >= 34 and <= 65 => Helpers.ToHex(state.GetV(registerId - 34).ToArray()),
+ 66 => Helpers.ToHex(BitConverter.GetBytes((uint)state.Fpsr)),
+ 67 => Helpers.ToHex(BitConverter.GetBytes((uint)state.Fpcr)),
+ _ => null
+ };
- public static bool WriteRegister64(this IExecutionContext state, int gdbRegId, StringStream ss)
+ public static bool WriteRegister64(this IExecutionContext state, int registerId, StringStream ss)
{
- switch (gdbRegId)
+ switch (registerId)
{
case >= 0 and <= 31:
{
- ulong value = ss.ReadLengthAsLEHex(16);
- state.SetX(gdbRegId, value);
+ ulong value = ss.ReadLengthAsLittleEndianHex(16);
+ state.SetX(registerId, value);
return true;
}
case 32:
{
- ulong value = ss.ReadLengthAsLEHex(16);
+ ulong value = ss.ReadLengthAsLittleEndianHex(16);
state.DebugPc = value;
return true;
}
case 33:
{
- ulong value = ss.ReadLengthAsLEHex(8);
+ ulong value = ss.ReadLengthAsLittleEndianHex(8);
state.Pstate = (uint)value;
return true;
}
case >= 34 and <= 65:
{
- ulong value0 = ss.ReadLengthAsLEHex(16);
- ulong value1 = ss.ReadLengthAsLEHex(16);
- state.SetV(gdbRegId - 34, new V128(value0, value1));
+ ulong value0 = ss.ReadLengthAsLittleEndianHex(16);
+ ulong value1 = ss.ReadLengthAsLittleEndianHex(16);
+ state.SetV(registerId - 34, new V128(value0, value1));
return true;
}
case 66:
{
- ulong value = ss.ReadLengthAsLEHex(8);
+ ulong value = ss.ReadLengthAsLittleEndianHex(8);
state.Fpsr = (uint)value;
return true;
}
case 67:
{
- ulong value = ss.ReadLengthAsLEHex(8);
+ ulong value = ss.ReadLengthAsLittleEndianHex(8);
state.Fpcr = (uint)value;
return true;
}
@@ -80,65 +71,64 @@ namespace Ryujinx.HLE.Debugger.Gdb
}
}
- public static string ReadRegister32(this IExecutionContext state, int gdbRegId)
+ public static string ReadRegister32(this IExecutionContext state, int registerId)
{
- switch (gdbRegId)
+ switch (registerId)
{
case >= 0 and <= 14:
- return Helpers.ToHex(BitConverter.GetBytes((uint)state.GetX(gdbRegId)));
+ return Helpers.ToHex(BitConverter.GetBytes((uint)state.GetX(registerId)));
case 15:
return Helpers.ToHex(BitConverter.GetBytes((uint)state.DebugPc));
case 16:
- return Helpers.ToHex(BitConverter.GetBytes((uint)state.Pstate));
+ return Helpers.ToHex(BitConverter.GetBytes(state.Pstate));
case >= 17 and <= 32:
- return Helpers.ToHex(state.GetV(gdbRegId - 17).ToArray());
+ return Helpers.ToHex(state.GetV(registerId - 17).ToArray());
case >= 33 and <= 64:
- int reg = (gdbRegId - 33);
+ int reg = (registerId - 33);
int n = reg / 2;
int shift = reg % 2;
ulong value = state.GetV(n).Extract(shift);
return Helpers.ToHex(BitConverter.GetBytes(value));
case 65:
- uint fpscr = (uint)state.Fpsr | (uint)state.Fpcr;
- return Helpers.ToHex(BitConverter.GetBytes(fpscr));
+ return Helpers.ToHex(BitConverter.GetBytes(state.Fpscr));
default:
return null;
}
}
- public static bool WriteRegister32(this IExecutionContext state, int gdbRegId, StringStream ss)
+ public static bool WriteRegister32(this IExecutionContext state, int registerId, StringStream ss)
{
- switch (gdbRegId)
+ switch (registerId)
{
case >= 0 and <= 14:
{
- ulong value = ss.ReadLengthAsLEHex(8);
- state.SetX(gdbRegId, value);
+ ulong value = ss.ReadLengthAsLittleEndianHex(8);
+ state.SetX(registerId, value);
return true;
}
case 15:
{
- ulong value = ss.ReadLengthAsLEHex(8);
+ ulong value = ss.ReadLengthAsLittleEndianHex(8);
state.DebugPc = value;
return true;
}
case 16:
{
- ulong value = ss.ReadLengthAsLEHex(8);
+ ulong value = ss.ReadLengthAsLittleEndianHex(8);
state.Pstate = (uint)value;
return true;
}
case >= 17 and <= 32:
{
- ulong value0 = ss.ReadLengthAsLEHex(16);
- ulong value1 = ss.ReadLengthAsLEHex(16);
- state.SetV(gdbRegId - 17, new V128(value0, value1));
+ ulong value0 = ss.ReadLengthAsLittleEndianHex(16);
+ ulong value1 = ss.ReadLengthAsLittleEndianHex(16);
+ state.SetV(registerId - 17, new V128(value0, value1));
return true;
}
case >= 33 and <= 64:
{
- ulong value = ss.ReadLengthAsLEHex(16);
- int regId = (gdbRegId - 33);
+ ulong value = ss.ReadLengthAsLittleEndianHex(16);
+ int regId = (registerId - 33);
int regNum = regId / 2;
int shift = regId % 2;
V128 reg = state.GetV(regNum);
@@ -147,7 +137,7 @@ namespace Ryujinx.HLE.Debugger.Gdb
}
case 65:
{
- ulong value = ss.ReadLengthAsLEHex(8);
+ ulong value = ss.ReadLengthAsLittleEndianHex(8);
state.Fpsr = (uint)value & FpcrMask;
state.Fpcr = (uint)value & ~FpcrMask;
return true;
diff --git a/src/Ryujinx.HLE/Debugger/IDebuggableProcess.cs b/src/Ryujinx.HLE/Debugger/IDebuggableProcess.cs
index 0896f25d2..a632cea33 100644
--- a/src/Ryujinx.HLE/Debugger/IDebuggableProcess.cs
+++ b/src/Ryujinx.HLE/Debugger/IDebuggableProcess.cs
@@ -11,11 +11,11 @@ namespace Ryujinx.HLE.Debugger
void DebugContinue(KThread thread);
bool DebugStep(KThread thread);
KThread GetThread(ulong threadUid);
- DebugState GetDebugState();
bool IsThreadPaused(KThread thread);
- ulong[] GetThreadUids();
public void DebugInterruptHandler(IExecutionContext ctx);
IVirtualMemoryManager CpuMemory { get; }
+ ulong[] ThreadUids { get; }
+ DebugState DebugState { get; }
void InvalidateCacheRegion(ulong address, ulong size);
}
}
diff --git a/src/Ryujinx.HLE/Debugger/IMessage.cs b/src/Ryujinx.HLE/Debugger/IMessage.cs
new file mode 100644
index 000000000..9877bcd5e
--- /dev/null
+++ b/src/Ryujinx.HLE/Debugger/IMessage.cs
@@ -0,0 +1,47 @@
+using Ryujinx.Cpu;
+
+namespace Ryujinx.HLE.Debugger
+{
+ ///
+ /// Marker interface for debugger messages.
+ ///
+ interface IMessage;
+
+ public enum MessageType
+ {
+ Kill,
+ BreakIn,
+ SendNack
+ }
+
+ record struct StatelessMessage(MessageType Type) : IMessage
+ {
+ public static StatelessMessage Kill => new(MessageType.Kill);
+ public static StatelessMessage BreakIn => new(MessageType.BreakIn);
+ public static StatelessMessage SendNack => new(MessageType.SendNack);
+ }
+
+ struct CommandMessage : IMessage
+ {
+ public readonly string Command;
+
+ public CommandMessage(string cmd)
+ {
+ Command = cmd;
+ }
+ }
+
+ public class ThreadBreakMessage : IMessage
+ {
+ public IExecutionContext Context { get; }
+ public ulong Address { get; }
+ public int Opcode { get; }
+
+ public ThreadBreakMessage(IExecutionContext context, ulong address, int opcode)
+ {
+ Context = context;
+ Address = address;
+ Opcode = opcode;
+ }
+ }
+}
diff --git a/src/Ryujinx.HLE/Debugger/Message/BreakInMessage.cs b/src/Ryujinx.HLE/Debugger/Message/BreakInMessage.cs
deleted file mode 100644
index 81d8784ae..000000000
--- a/src/Ryujinx.HLE/Debugger/Message/BreakInMessage.cs
+++ /dev/null
@@ -1,6 +0,0 @@
-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
deleted file mode 100644
index ad265d432..000000000
--- a/src/Ryujinx.HLE/Debugger/Message/CommandMessage.cs
+++ /dev/null
@@ -1,12 +0,0 @@
-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
deleted file mode 100644
index 4b03183c5..000000000
--- a/src/Ryujinx.HLE/Debugger/Message/IMessage.cs
+++ /dev/null
@@ -1,6 +0,0 @@
-namespace Ryujinx.HLE.Debugger
-{
- interface IMessage
- {
- }
-}
diff --git a/src/Ryujinx.HLE/Debugger/Message/KillMessage.cs b/src/Ryujinx.HLE/Debugger/Message/KillMessage.cs
deleted file mode 100644
index 43ae0f21e..000000000
--- a/src/Ryujinx.HLE/Debugger/Message/KillMessage.cs
+++ /dev/null
@@ -1,6 +0,0 @@
-namespace Ryujinx.HLE.Debugger
-{
- struct KillMessage : IMessage
- {
- }
-}
diff --git a/src/Ryujinx.HLE/Debugger/Message/SendNackMessage.cs b/src/Ryujinx.HLE/Debugger/Message/SendNackMessage.cs
deleted file mode 100644
index ce804c46e..000000000
--- a/src/Ryujinx.HLE/Debugger/Message/SendNackMessage.cs
+++ /dev/null
@@ -1,6 +0,0 @@
-namespace Ryujinx.HLE.Debugger
-{
- struct SendNackMessage : IMessage
- {
- }
-}
diff --git a/src/Ryujinx.HLE/Debugger/Message/ThreadBreakMessage.cs b/src/Ryujinx.HLE/Debugger/Message/ThreadBreakMessage.cs
deleted file mode 100644
index 027096eeb..000000000
--- a/src/Ryujinx.HLE/Debugger/Message/ThreadBreakMessage.cs
+++ /dev/null
@@ -1,18 +0,0 @@
-using IExecutionContext = Ryujinx.Cpu.IExecutionContext;
-
-namespace Ryujinx.HLE.Debugger
-{
- public class ThreadBreakMessage : IMessage
- {
- public IExecutionContext Context { get; }
- public ulong Address { get; }
- public int Opcode { get; }
-
- public ThreadBreakMessage(IExecutionContext context, ulong address, int opcode)
- {
- Context = context;
- Address = address;
- Opcode = opcode;
- }
- }
-}
diff --git a/src/Ryujinx.HLE/Debugger/StringStream.cs b/src/Ryujinx.HLE/Debugger/StringStream.cs
index bc422f51f..9e5a48704 100644
--- a/src/Ryujinx.HLE/Debugger/StringStream.cs
+++ b/src/Ryujinx.HLE/Debugger/StringStream.cs
@@ -5,63 +5,56 @@ namespace Ryujinx.HLE.Debugger
{
internal class StringStream
{
- private readonly string Data;
- private int Position;
+ private readonly string _data;
+ private int _position;
public StringStream(string s)
{
- Data = s;
+ _data = s;
}
+
+ public bool IsEmpty => _position >= _data.Length;
- public char ReadChar()
- {
- return Data[Position++];
- }
+ public char ReadChar() => _data[_position++];
public string ReadUntil(char needle)
{
- int needlePos = Data.IndexOf(needle, Position);
+ int needlePos = _data.IndexOf(needle, _position);
if (needlePos == -1)
{
- needlePos = Data.Length;
+ needlePos = _data.Length;
}
- string result = Data.Substring(Position, needlePos - Position);
- Position = needlePos + 1;
+ 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;
+ string result = _data.Substring(_position, len);
+ _position += len;
return result;
}
public string ReadRemaining()
{
- string result = Data.Substring(Position);
- Position = Data.Length;
+ string result = _data[_position..];
+ _position = _data.Length;
return result;
}
- public ulong ReadRemainingAsHex()
- {
- return ulong.Parse(ReadRemaining(), NumberStyles.HexNumber);
- }
+ public ulong ReadRemainingAsHex()
+ => ulong.Parse(ReadRemaining(), NumberStyles.HexNumber);
- public ulong ReadUntilAsHex(char needle)
- {
- return ulong.Parse(ReadUntil(needle), NumberStyles.HexNumber);
- }
+ public ulong ReadUntilAsHex(char needle)
+ => ulong.Parse(ReadUntil(needle), NumberStyles.HexNumber);
- public ulong ReadLengthAsHex(int len)
- {
- return ulong.Parse(ReadLength(len), NumberStyles.HexNumber);
- }
+ public ulong ReadLengthAsHex(int len)
+ => ulong.Parse(ReadLength(len), NumberStyles.HexNumber);
- public ulong ReadLengthAsLEHex(int len)
+ public ulong ReadLengthAsLittleEndianHex(int len)
{
Debug.Assert(len % 2 == 0);
@@ -83,9 +76,9 @@ namespace Ryujinx.HLE.Debugger
public bool ConsumePrefix(string prefix)
{
- if (Data.Substring(Position).StartsWith(prefix))
+ if (_data[_position..].StartsWith(prefix))
{
- Position += prefix.Length;
+ _position += prefix.Length;
return true;
}
return false;
@@ -93,17 +86,12 @@ namespace Ryujinx.HLE.Debugger
public bool ConsumeRemaining(string match)
{
- if (Data.Substring(Position) == match)
+ if (_data[_position..] == match)
{
- Position += match.Length;
+ _position += match.Length;
return true;
}
return false;
}
-
- public bool IsEmpty()
- {
- return Position >= Data.Length;
- }
}
}
diff --git a/src/Ryujinx.HLE/HOS/Kernel/Process/KProcess.cs b/src/Ryujinx.HLE/HOS/Kernel/Process/KProcess.cs
index eb75fb9a1..20c8b116c 100644
--- a/src/Ryujinx.HLE/HOS/Kernel/Process/KProcess.cs
+++ b/src/Ryujinx.HLE/HOS/Kernel/Process/KProcess.cs
@@ -1338,22 +1338,24 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
return true;
}
- public DebugState GetDebugState()
- {
- return (DebugState)_parent.debugState;
- }
+ public DebugState DebugState => (DebugState)_parent.debugState;
public bool IsThreadPaused(KThread target)
{
return (target.SchedFlags & ThreadSchedState.ThreadPauseFlag) != 0;
}
- public ulong[] GetThreadUids()
+ public ulong[] ThreadUids
{
- lock (_parent._threadingLock)
+ get
{
- var threads = _parent._threads.Where(x => !x.TerminationRequested).ToArray();
- return threads.Select(x => x.ThreadUid).ToArray();
+ lock (_parent._threadingLock)
+ {
+ return _parent._threads
+ .Where(x => !x.TerminationRequested)
+ .Select(x => x.ThreadUid)
+ .ToArray();
+ }
}
}
@@ -1361,8 +1363,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
{
lock (_parent._threadingLock)
{
- var threads = _parent._threads.Where(x => !x.TerminationRequested).ToArray();
- return threads.FirstOrDefault(x => x.ThreadUid == threadUid);
+ return _parent._threads.Where(x => !x.TerminationRequested)
+ .FirstOrDefault(x => x.ThreadUid == threadUid);
}
}
@@ -1379,7 +1381,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
_parent.InterruptHandler(ctx);
}
- public IVirtualMemoryManager CpuMemory { get { return _parent.CpuMemory; } }
+ public IVirtualMemoryManager CpuMemory => _parent.CpuMemory;
public void InvalidateCacheRegion(ulong address, ulong size)
{
diff --git a/src/Ryujinx.HLE/HOS/Kernel/Threading/KScheduler.cs b/src/Ryujinx.HLE/HOS/Kernel/Threading/KScheduler.cs
index 54440ab5f..fa81ef983 100644
--- a/src/Ryujinx.HLE/HOS/Kernel/Threading/KScheduler.cs
+++ b/src/Ryujinx.HLE/HOS/Kernel/Threading/KScheduler.cs
@@ -293,7 +293,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
KThread currentThread = KernelStatic.GetCurrentThread();
KThread selectedThread = _state.SelectedThread;
- if (!currentThread.IsThreadNamed && currentThread.GetThreadName() != "")
+ if (!currentThread.IsThreadNamed && string.IsNullOrEmpty(currentThread.GetThreadName()))
{
currentThread.HostThread.Name = $"<{currentThread.GetThreadName()}>";
currentThread.IsThreadNamed = true;