gdb: Support continue specific threads

This commit is contained in:
Coxxs 2025-06-24 15:45:18 +08:00
parent b932905053
commit 625ca3f934
3 changed files with 45 additions and 7 deletions

View file

@ -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($"<thread id=\"{thread.ThreadUid:x}\" name=\"{threadName}\" />\n");
sb.Append($"<thread id=\"{thread.ThreadUid:x}\" name=\"{threadName}\">{(DebugProcess.IsThreadPaused(thread) ? "Paused" : "Running")}</thread>\n");
}
sb.Append("</threads>");

View file

@ -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; }

View file

@ -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)