diff --git a/src/Ryujinx.HLE/Debugger/Debugger.MessageHandler.cs b/src/Ryujinx.HLE/Debugger/Debugger.MessageHandler.cs index 5ed8ba528..a871f04cc 100644 --- a/src/Ryujinx.HLE/Debugger/Debugger.MessageHandler.cs +++ b/src/Ryujinx.HLE/Debugger/Debugger.MessageHandler.cs @@ -34,7 +34,7 @@ namespace Ryujinx.HLE.Debugger case ThreadBreakMessage { Context: { } ctx }: DebugProcess.DebugStop(); - GThread = CThread = ctx.ThreadUid; + GThreadId = CThreadId = ctx.ThreadUid; _breakHandlerEvent.Set(); _commands.Processor.Reply($"T05thread:{ctx.ThreadUid:x};"); break; diff --git a/src/Ryujinx.HLE/Debugger/Debugger.Rcmd.cs b/src/Ryujinx.HLE/Debugger/Debugger.Rcmd.cs index 88dc999ab..0dacec651 100644 --- a/src/Ryujinx.HLE/Debugger/Debugger.Rcmd.cs +++ b/src/Ryujinx.HLE/Debugger/Debugger.Rcmd.cs @@ -45,18 +45,18 @@ namespace Ryujinx.HLE.Debugger public string GetStackTrace() { - if (GThread == null) + if (GThreadId == null) return "No thread selected\n"; - return Process?.Debugger?.GetGuestStackTrace(DebugProcess.GetThread(GThread.Value)) ?? "No application process found\n"; + return Process?.Debugger?.GetGuestStackTrace(DebugProcess.GetThread(GThreadId.Value)) ?? "No application process found\n"; } public string GetRegisters() { - if (GThread == null) + if (GThreadId == null) return "No thread selected\n"; - return Process?.Debugger?.GetCpuRegisterPrintout(DebugProcess.GetThread(GThread.Value)) ?? "No application process found\n"; + return Process?.Debugger?.GetCpuRegisterPrintout(DebugProcess.GetThread(GThreadId.Value)) ?? "No application process found\n"; } public string GetMinidump() @@ -65,9 +65,9 @@ namespace Ryujinx.HLE.Debugger return "No application process found\n"; if (kProcess.Debugger is not { } debugger) - return $"Error getting minidump: debugger is null\n"; + return "Error getting minidump: debugger is null\n"; - var response = debugger.GetMinidump(); + string response = debugger.GetMinidump(); Logger.Info?.Print(LogClass.GdbStub, response); return response; @@ -80,10 +80,8 @@ namespace Ryujinx.HLE.Debugger if (Process is not { } kProcess) return "No application process found\n"; - if (kProcess.Debugger is not { } debugger) - return $"Error getting process info: debugger is null\n"; - - return debugger.GetProcessInfoPrintout(); + return kProcess.Debugger?.GetProcessInfoPrintout() + ?? "Error getting process info: debugger is null\n"; } catch (Exception e) { diff --git a/src/Ryujinx.HLE/Debugger/Debugger.cs b/src/Ryujinx.HLE/Debugger/Debugger.cs index cab9c8eb6..5ffb71ca8 100644 --- a/src/Ryujinx.HLE/Debugger/Debugger.cs +++ b/src/Ryujinx.HLE/Debugger/Debugger.cs @@ -1,9 +1,11 @@ +using Gommon; using Ryujinx.Common.Logging; using Ryujinx.HLE.Debugger.Gdb; using Ryujinx.HLE.HOS.Kernel.Process; using Ryujinx.HLE.HOS.Kernel.Threading; using System; using System.Collections.Concurrent; +using System.Diagnostics; using System.Linq; using System.Net.Sockets; using System.Threading; @@ -32,8 +34,12 @@ namespace Ryujinx.HLE.Debugger private bool _shuttingDown; private readonly ManualResetEventSlim _breakHandlerEvent = new(false); - internal ulong? CThread; - internal ulong? GThread; + internal ulong? CThreadId; + internal ulong? GThreadId; + + internal KThread CThread => CThreadId?.Into(DebugProcess.GetThread); + + internal KThread GThread => GThreadId?.Into(DebugProcess.GetThread); public readonly BreakpointManager BreakpointManager; @@ -56,7 +62,7 @@ namespace Ryujinx.HLE.Debugger internal KThread[] GetThreads() => DebugProcess.ThreadUids.Select(DebugProcess.GetThread).ToArray(); - internal bool IsProcess32Bit => DebugProcess.GetThread(GThread ?? DebugProcess.ThreadUids.First()).Context.IsAarch32; + internal bool IsProcess32Bit => DebugProcess.GetThread(GThreadId ?? DebugProcess.ThreadUids.First()).Context.IsAarch32; internal bool WriteRegister(IExecutionContext ctx, int registerId, StringStream ss) => IsProcess32Bit diff --git a/src/Ryujinx.HLE/Debugger/Gdb/CommandProcessor.cs b/src/Ryujinx.HLE/Debugger/Gdb/CommandProcessor.cs index 84f4dd7e6..457b61beb 100644 --- a/src/Ryujinx.HLE/Debugger/Gdb/CommandProcessor.cs +++ b/src/Ryujinx.HLE/Debugger/Gdb/CommandProcessor.cs @@ -181,7 +181,7 @@ namespace Ryujinx.HLE.Debugger.Gdb if (ss.ConsumeRemaining("fThreadInfo")) { Reply( - $"m{Debugger.DebugProcess.ThreadUids.Select(x => $"{x:x}").JoinToString(",")}"); + $"m{DebugProcess.ThreadUids.Select(x => $"{x:x}").JoinToString(",")}"); break; } diff --git a/src/Ryujinx.HLE/Debugger/Gdb/Commands.cs b/src/Ryujinx.HLE/Debugger/Gdb/Commands.cs index be64bf3f1..d26905106 100644 --- a/src/Ryujinx.HLE/Debugger/Gdb/Commands.cs +++ b/src/Ryujinx.HLE/Debugger/Gdb/Commands.cs @@ -15,7 +15,7 @@ namespace Ryujinx.HLE.Debugger.Gdb private GdbCommandProcessor _processor; - public GdbCommandProcessor Processor + public GdbCommandProcessor Processor => _processor ??= new GdbCommandProcessor(this); internal readonly TcpListener ListenerSocket; @@ -37,33 +37,33 @@ namespace Ryujinx.HLE.Debugger.Gdb { // GDB is performing initial contact. Stop everything. Debugger.DebugProcess.DebugStop(); - Debugger.GThread = Debugger.CThread = Debugger.DebugProcess.ThreadUids.First(); - Processor.Reply($"T05thread:{Debugger.CThread:x};"); + Debugger.GThreadId = Debugger.CThreadId = Debugger.DebugProcess.ThreadUids.First(); + Processor.Reply($"T05thread:{Debugger.CThreadId:x};"); } internal void Interrupt() { // GDB is requesting an interrupt. Stop everything. Debugger.DebugProcess.DebugStop(); - if (Debugger.GThread == null || Debugger.GetThreads().All(x => x.ThreadUid != Debugger.GThread.Value)) + if (Debugger.GThreadId == null || Debugger.GetThreads().All(x => x.ThreadUid != Debugger.GThreadId.Value)) { - Debugger.GThread = Debugger.CThread = Debugger.DebugProcess.ThreadUids.First(); + Debugger.GThreadId = Debugger.CThreadId = Debugger.DebugProcess.ThreadUids.First(); } - Processor.Reply($"T02thread:{Debugger.GThread:x};"); + Processor.Reply($"T02thread:{Debugger.GThreadId:x};"); } internal void Continue(ulong? newPc) { if (newPc.HasValue) { - if (Debugger.CThread == null) + if (Debugger.CThreadId == null) { Processor.ReplyError(); return; } - Debugger.DebugProcess.GetThread(Debugger.CThread.Value).Context.DebugPc = newPc.Value; + Debugger.CThread.Context.DebugPc = newPc.Value; } Debugger.DebugProcess.DebugContinue(); @@ -78,13 +78,13 @@ namespace Ryujinx.HLE.Debugger.Gdb internal void ReadRegisters() { - if (Debugger.GThread == null) + if (Debugger.GThreadId == null) { Processor.ReplyError(); return; } - IExecutionContext ctx = Debugger.DebugProcess.GetThread(Debugger.GThread.Value).Context; + IExecutionContext ctx = Debugger.GThread.Context; string registers = string.Empty; if (Debugger.IsProcess32Bit) { @@ -106,13 +106,13 @@ namespace Ryujinx.HLE.Debugger.Gdb internal void WriteRegisters(StringStream ss) { - if (Debugger.GThread == null) + if (Debugger.GThreadId == null) { Processor.ReplyError(); return; } - IExecutionContext ctx = Debugger.DebugProcess.GetThread(Debugger.GThread.Value).Context; + IExecutionContext ctx = Debugger.GThread.Context; if (Debugger.IsProcess32Bit) { for (int i = 0; i < GdbRegisters.Count32; i++) @@ -162,11 +162,11 @@ namespace Ryujinx.HLE.Debugger.Gdb switch (op) { case 'c': - Debugger.CThread = threadId; + Debugger.CThreadId = threadId; Processor.ReplyOK(); return; case 'g': - Debugger.GThread = threadId; + Debugger.GThreadId = threadId; Processor.ReplyOK(); return; default: @@ -214,13 +214,13 @@ namespace Ryujinx.HLE.Debugger.Gdb internal void ReadRegister(int gdbRegId) { - if (Debugger.GThread == null) + if (Debugger.GThreadId == null) { Processor.ReplyError(); return; } - IExecutionContext ctx = Debugger.DebugProcess.GetThread(Debugger.GThread.Value).Context; + IExecutionContext ctx = Debugger.GThread.Context; string result = Debugger.ReadRegister(ctx, gdbRegId); Processor.Reply(result != null, result); @@ -228,26 +228,26 @@ namespace Ryujinx.HLE.Debugger.Gdb internal void WriteRegister(int gdbRegId, StringStream ss) { - if (Debugger.GThread == null) + if (Debugger.GThreadId == null) { Processor.ReplyError(); return; } - IExecutionContext ctx = Debugger.DebugProcess.GetThread(Debugger.GThread.Value).Context; - - Processor.Reply(Debugger.WriteRegister(ctx, gdbRegId, ss) && ss.IsEmpty); + Processor.Reply( + success: Debugger.WriteRegister(Debugger.GThread.Context, gdbRegId, ss) && ss.IsEmpty + ); } internal void Step(ulong? newPc) { - if (Debugger.CThread == null) + if (Debugger.CThreadId == null) { Processor.ReplyError(); return; } - KThread thread = Debugger.DebugProcess.GetThread(Debugger.CThread.Value); + KThread thread = Debugger.CThread; if (newPc.HasValue) { @@ -260,7 +260,7 @@ namespace Ryujinx.HLE.Debugger.Gdb } else { - Debugger.GThread = Debugger.CThread = thread.ThreadUid; + Debugger.GThreadId = Debugger.CThreadId = thread.ThreadUid; Processor.Reply($"T05thread:{thread.ThreadUid:x};"); } } @@ -314,7 +314,7 @@ namespace Ryujinx.HLE.Debugger.Gdb _ => VContAction.None }; - // Note: We don't support signals yet. + // TODO: Note: We don't support signals yet. //ushort? signal = null; if (cmd is 'C' or 'S') { @@ -323,24 +323,22 @@ namespace Ryujinx.HLE.Debugger.Gdb // since that method advances the underlying string position } - ulong? threadId = null; - if (stream.ConsumePrefix(":")) - { - threadId = stream.ReadRemainingAsThreadUid(); - } + ulong? threadId = stream.ConsumePrefix(":") + ? stream.ReadRemainingAsThreadUid() + : null; if (threadId.HasValue) { if (threadActionMap.ContainsKey(threadId.Value)) { - threadActionMap[threadId.Value] = new VContPendingAction(action/*, signal*/); + threadActionMap[threadId.Value] = new VContPendingAction(action /*, signal*/); } } else { foreach (ulong thread in threadActionMap.Keys) { - threadActionMap[thread] = new VContPendingAction(action/*, signal*/); + threadActionMap[thread] = new VContPendingAction(action /*, signal*/); } if (action == VContAction.Continue) @@ -393,7 +391,7 @@ namespace Ryujinx.HLE.Debugger.Gdb { if (action.Action == VContAction.Step) { - Debugger.GThread = Debugger.CThread = threadUid; + Debugger.GThreadId = Debugger.CThreadId = threadUid; Processor.Reply($"T05thread:{threadUid:x};"); } } diff --git a/src/Ryujinx.HLE/Debugger/Gdb/Registers.cs b/src/Ryujinx.HLE/Debugger/Gdb/Registers.cs index 40a095a07..6c1d56bd0 100644 --- a/src/Ryujinx.HLE/Debugger/Gdb/Registers.cs +++ b/src/Ryujinx.HLE/Debugger/Gdb/Registers.cs @@ -8,7 +8,7 @@ namespace Ryujinx.HLE.Debugger.Gdb { public const int Count64 = 68; public const int Count32 = 66; - + /* FPCR = FPSR & ~FpcrMask All of FPCR's bits are reserved in FPCR and vice versa, @@ -16,6 +16,8 @@ namespace Ryujinx.HLE.Debugger.Gdb */ private const uint FpcrMask = 0xfc1fffff; + #region 64-bit + public static string ReadRegister64(this IExecutionContext state, int registerId) => registerId switch { @@ -74,6 +76,10 @@ namespace Ryujinx.HLE.Debugger.Gdb } } + #endregion + + #region 32-bit + public static string ReadRegister32(this IExecutionContext state, int registerId) { switch (registerId) @@ -149,5 +155,7 @@ namespace Ryujinx.HLE.Debugger.Gdb return false; } } + + #endregion } } diff --git a/src/Ryujinx.HLE/Debugger/IDebuggableProcess.cs b/src/Ryujinx.HLE/Debugger/IDebuggableProcess.cs index 6d0cf3029..ce1857809 100644 --- a/src/Ryujinx.HLE/Debugger/IDebuggableProcess.cs +++ b/src/Ryujinx.HLE/Debugger/IDebuggableProcess.cs @@ -9,7 +9,7 @@ namespace Ryujinx.HLE.Debugger IVirtualMemoryManager CpuMemory { get; } ulong[] ThreadUids { get; } DebugState DebugState { get; } - + void DebugStop(); void DebugContinue(); void DebugContinue(KThread thread); diff --git a/src/Ryujinx.HLE/Debugger/Message.cs b/src/Ryujinx.HLE/Debugger/Message.cs index c5f9e9554..8a74fcefe 100644 --- a/src/Ryujinx.HLE/Debugger/Message.cs +++ b/src/Ryujinx.HLE/Debugger/Message.cs @@ -26,11 +26,9 @@ namespace Ryujinx.HLE.Debugger public readonly string Command; public CommandMessage(string cmd) - { - Command = cmd; - } + => Command = cmd; } - + public class ThreadBreakMessage : Message.IMarker { public IExecutionContext Context { get; } diff --git a/src/Ryujinx.HLE/Debugger/RegisterInformation.cs b/src/Ryujinx.HLE/Debugger/RegisterInformation.cs index 5c6fa105c..979524573 100644 --- a/src/Ryujinx.HLE/Debugger/RegisterInformation.cs +++ b/src/Ryujinx.HLE/Debugger/RegisterInformation.cs @@ -3,7 +3,7 @@ using System.IO; namespace Ryujinx.HLE.Debugger { - class RegisterInformation + static class RegisterInformation { public static readonly Dictionary Features = new() {