diff --git a/src/Ryujinx.HLE/Debugger/Debugger.cs b/src/Ryujinx.HLE/Debugger/Debugger.cs
index c94f142cd..015fbf8fb 100644
--- a/src/Ryujinx.HLE/Debugger/Debugger.cs
+++ b/src/Ryujinx.HLE/Debugger/Debugger.cs
@@ -411,13 +411,13 @@ namespace Ryujinx.HLE.Debugger
break;
}
- if (DebugProcess.GetDebugState() == DebugState.Stopped)
+ if (DebugProcess.IsThreadPaused(DebugProcess.GetThread(threadId.Value)))
{
- Reply(ToHex("Stopped"));
+ Reply(ToHex("Paused"));
}
else
{
- Reply(ToHex("Not stopped"));
+ Reply(ToHex("Running"));
}
break;
}
@@ -625,6 +625,8 @@ namespace Ryujinx.HLE.Debugger
threadActionMap[thread.ThreadUid] = new VContPendingAction(VContAction.None);
}
+ VContAction defaultAction = VContAction.None;
+
// For each inferior thread, the *leftmost* action with a matching thread-id is applied.
for (int i = rawActions.Length - 1; i >= 0; i--)
{
@@ -642,6 +644,7 @@ namespace Ryujinx.HLE.Debugger
_ => VContAction.None
};
+ // Note: We don't support signals yet.
ushort? signal = null;
if (cmd == 'C' || cmd == 'S')
{
@@ -666,12 +669,17 @@ namespace Ryujinx.HLE.Debugger
{
threadActionMap[row.Key] = new VContPendingAction(action, signal);
}
+
+ if (action == VContAction.Continue) {
+ defaultAction = action;
+ } else {
+ Logger.Warning?.Print(LogClass.GdbStub, $"Received vCont command with unsupported default action: {rawAction}");
+ }
}
}
bool hasError = false;
- // TODO: We don't support stop or continue yet, and we don't support signals.
foreach (var (threadUid, action) in threadActionMap)
{
if (action.Action == VContAction.Step)
@@ -683,10 +691,20 @@ namespace Ryujinx.HLE.Debugger
}
}
- // If all threads are set to continue, continue the process.
+ // If we receive "vCont;c", just continue the process.
+ // If we receive something like "vCont;c:2e;c:2f" (IDA Pro will send commands like this), continue these threads.
+ // For "vCont;s:2f;c", we only step thread 2f, and do not continue other threads. (Is this correct?)
if (threadActionMap.Values.All(a => a.Action == VContAction.Continue))
{
DebugProcess.DebugContinue();
+ } else if (defaultAction == VContAction.None) {
+ foreach (var (threadUid, action) in threadActionMap)
+ {
+ if (action.Action == VContAction.Continue)
+ {
+ DebugProcess.DebugContinue(DebugProcess.GetThread(threadUid));
+ }
+ }
}
if (hasError)
@@ -716,7 +734,7 @@ namespace Ryujinx.HLE.Debugger
foreach (var thread in GetThreads())
{
string threadName = System.Security.SecurityElement.Escape(thread.GetThreadName());
- sb.Append($"\n");
+ sb.Append($"{(DebugProcess.IsThreadPaused(thread) ? "Paused" : "Running")}\n");
}
sb.Append("");
diff --git a/src/Ryujinx.HLE/Debugger/IDebuggableProcess.cs b/src/Ryujinx.HLE/Debugger/IDebuggableProcess.cs
index 273a1147f..0896f25d2 100644
--- a/src/Ryujinx.HLE/Debugger/IDebuggableProcess.cs
+++ b/src/Ryujinx.HLE/Debugger/IDebuggableProcess.cs
@@ -8,9 +8,11 @@ namespace Ryujinx.HLE.Debugger
{
void DebugStop();
void DebugContinue();
+ 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; }
diff --git a/src/Ryujinx.HLE/HOS/Kernel/Process/KProcess.cs b/src/Ryujinx.HLE/HOS/Kernel/Process/KProcess.cs
index c24d5c3cc..0a57f5bc6 100644
--- a/src/Ryujinx.HLE/HOS/Kernel/Process/KProcess.cs
+++ b/src/Ryujinx.HLE/HOS/Kernel/Process/KProcess.cs
@@ -1257,12 +1257,25 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
_kernelContext.CriticalSection.Leave();
}
+ public void DebugContinue(KThread target)
+ {
+ Interlocked.Exchange(ref _parent.debugState, (int)DebugState.Running);
+
+ _kernelContext.CriticalSection.Enter();
+ lock (_parent._threadingLock)
+ {
+ target.Resume(ThreadSchedState.ThreadPauseFlag);
+ }
+ _kernelContext.CriticalSection.Leave();
+ }
+
public bool DebugStep(KThread target)
{
- if (_parent.debugState != (int)DebugState.Stopped)
+ if (!IsThreadPaused(target))
{
return false;
}
+
_kernelContext.CriticalSection.Enter();
steppingThread = target;
bool waiting = target.MutexOwner != null || target.WaitingSync || target.WaitingInArbitration;
@@ -1322,6 +1335,11 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
return (DebugState)_parent.debugState;
}
+ public bool IsThreadPaused(KThread target)
+ {
+ return (target.SchedFlags & ThreadSchedState.ThreadPauseFlag) != 0;
+ }
+
public ulong[] GetThreadUids()
{
lock (_parent._threadingLock)