IDebuggableProcess: Create and expose interface to enable implementation of debugging tools

# Conflicts:
#	src/ARMeilleure/State/DebugState.cs
#	src/ARMeilleure/State/ExecutionContext.cs
TODO: Fix comments. I also tried implementing AppleHV primitives here (it's actually broken).
This commit is contained in:
merry 2022-02-08 18:57:32 +00:00 committed by svc64
parent b45a81458a
commit 39a3ba8329
13 changed files with 218 additions and 3 deletions

View file

@ -0,0 +1,9 @@
namespace ARMeilleure.State
{
enum DebugState
{
Running,
Stopping,
Stopped,
}
}

View file

@ -1,5 +1,8 @@
using ARMeilleure.Memory; using ARMeilleure.Memory;
using System; using System;
using System.Collections.Concurrent;
using System.Diagnostics;
using System.Threading;
namespace ARMeilleure.State namespace ARMeilleure.State
{ {
@ -96,6 +99,14 @@ namespace ARMeilleure.State
private readonly ExceptionCallback _supervisorCallback; private readonly ExceptionCallback _supervisorCallback;
private readonly ExceptionCallback _undefinedCallback; private readonly ExceptionCallback _undefinedCallback;
internal int _debugState = (int)DebugState.Running;
internal int _shouldStep = 0;
internal ManualResetEvent _debugHalt = new ManualResetEvent(true);
internal Barrier _stepBarrier = new Barrier(2);
// This is only valid while debugging is enabled.
public ulong DebugPc;
public ExecutionContext( public ExecutionContext(
IJitMemoryAllocator allocator, IJitMemoryAllocator allocator,
ICounter counter, ICounter counter,
@ -145,6 +156,33 @@ namespace ARMeilleure.State
_interrupted = true; _interrupted = true;
} }
public void DebugStop()
{
_debugHalt.Reset();
Interlocked.CompareExchange(ref _debugState, (int)DebugState.Stopping, (int)DebugState.Running);
}
public bool DebugStep()
{
if (_debugState != (int)DebugState.Stopped)
{
return false;
}
_shouldStep = 1;
_debugHalt.Set();
_stepBarrier.SignalAndWait();
_debugHalt.Reset();
_stepBarrier.SignalAndWait();
return true;
}
public void DebugContinue()
{
_debugHalt.Set();
}
internal void OnBreak(ulong address, int imm) internal void OnBreak(ulong address, int imm)
{ {
_breakCallback?.Invoke(this, address, imm); _breakCallback?.Invoke(this, address, imm);

View file

@ -0,0 +1,9 @@
namespace Ryujinx.Cpu.AppleHv
{
enum DebugState
{
Running,
Stopping,
Stopped,
}
}

View file

@ -127,6 +127,15 @@ namespace Ryujinx.Cpu.AppleHv
return Interlocked.Exchange(ref _interruptRequested, 0) != 0; return Interlocked.Exchange(ref _interruptRequested, 0) != 0;
} }
/// <inheritdoc/>
public void DebugStop() => _impl.DebugStop();
/// <inheritdoc/>
public bool DebugStep() => _impl.DebugStep();
/// <inheritdoc/>
public void DebugContinue() => _impl.DebugContinue();
/// <inheritdoc/> /// <inheritdoc/>
public void StopRunning() public void StopRunning()
{ {

View file

@ -46,5 +46,27 @@ namespace Ryujinx.Cpu.AppleHv
{ {
_v[index] = value; _v[index] = value;
} }
public void RequestInterrupt()
{
}
public void DebugStop()
{
}
public bool DebugStep()
{
return false;
}
public void DebugContinue()
{
}
public bool GetAndClearInterruptRequested()
{
return false;
}
} }
} }

View file

@ -2,11 +2,10 @@ using ARMeilleure.State;
using Ryujinx.Memory; using Ryujinx.Memory;
using System; using System;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Runtime.Versioning; using System.Threading;
namespace Ryujinx.Cpu.AppleHv namespace Ryujinx.Cpu.AppleHv
{ {
[SupportedOSPlatform("macos")]
class HvExecutionContextVcpu : IHvExecutionContext class HvExecutionContextVcpu : IHvExecutionContext
{ {
private static readonly MemoryBlock _setSimdFpRegFuncMem; private static readonly MemoryBlock _setSimdFpRegFuncMem;
@ -14,6 +13,14 @@ namespace Ryujinx.Cpu.AppleHv
private static readonly SetSimdFpReg _setSimdFpReg; private static readonly SetSimdFpReg _setSimdFpReg;
private static readonly IntPtr _setSimdFpRegNativePtr; private static readonly IntPtr _setSimdFpRegNativePtr;
internal int _debugState = (int)DebugState.Running;
internal int _shouldStep = 0;
internal ManualResetEvent _debugHalt = new ManualResetEvent(true);
internal Barrier _stepBarrier = new Barrier(2);
// This is only valid while debugging is enabled.
public ulong DebugPc;
static HvExecutionContextVcpu() static HvExecutionContextVcpu()
{ {
// .NET does not support passing vectors by value, so we need to pass a pointer and use a native // .NET does not support passing vectors by value, so we need to pass a pointer and use a native
@ -136,6 +143,7 @@ namespace Ryujinx.Cpu.AppleHv
} }
private readonly ulong _vcpu; private readonly ulong _vcpu;
private int _interruptRequested;
public HvExecutionContextVcpu(ulong vcpu) public HvExecutionContextVcpu(ulong vcpu)
{ {
@ -181,8 +189,46 @@ namespace Ryujinx.Cpu.AppleHv
public void RequestInterrupt() public void RequestInterrupt()
{ {
if (Interlocked.Exchange(ref _interruptRequested, 1) == 0)
{
ulong vcpu = _vcpu;
HvApi.hv_vcpus_exit(ref vcpu, 1);
}
}
public void DebugStop()
{
_debugHalt.Reset();
Interlocked.CompareExchange(ref _debugState, (int)DebugState.Stopping, (int)DebugState.Running);
ulong vcpu = _vcpu; ulong vcpu = _vcpu;
HvApi.hv_vcpus_exit(ref vcpu, 1); HvApi.hv_vcpus_exit(ref vcpu, 1);
} }
public bool DebugStep()
{
if (_debugState != (int)DebugState.Stopped)
{
return false;
}
_shouldStep = 1;
_debugHalt.Set();
_stepBarrier.SignalAndWait();
_debugHalt.Reset();
_stepBarrier.SignalAndWait();
return true;
}
public void DebugContinue()
{
_debugHalt.Set();
HvApi.hv_vcpu_run(_vcpu);
}
public bool GetAndClearInterruptRequested()
{
return Interlocked.Exchange(ref _interruptRequested, 0) != 0;
}
} }
} }

View file

@ -39,5 +39,13 @@ namespace Ryujinx.Cpu.AppleHv
SetV(i, context.GetV(i)); SetV(i, context.GetV(i));
} }
} }
void RequestInterrupt();
bool GetAndClearInterruptRequested();
// TODO: comments
void DebugStop();
bool DebugStep();
void DebugContinue();
} }
} }

View file

@ -108,5 +108,10 @@ namespace Ryujinx.Cpu
/// If you only need to pause the thread temporarily, use <see cref="RequestInterrupt"/> instead. /// If you only need to pause the thread temporarily, use <see cref="RequestInterrupt"/> instead.
/// </remarks> /// </remarks>
void StopRunning(); void StopRunning();
// TODO: comments
void DebugStop();
bool DebugStep();
void DebugContinue();
} }
} }

View file

@ -109,6 +109,15 @@ namespace Ryujinx.Cpu.Jit
_impl.RequestInterrupt(); _impl.RequestInterrupt();
} }
/// <inheritdoc/>
public void DebugStop() => _impl.DebugStop();
/// <inheritdoc/>
public bool DebugStep() => _impl.DebugStep();
/// <inheritdoc/>
public void DebugContinue() => _impl.DebugContinue();
/// <inheritdoc/> /// <inheritdoc/>
public void StopRunning() public void StopRunning()
{ {

View file

@ -0,0 +1,12 @@
using Ryujinx.Memory;
namespace Ryujinx.HLE.Debugger
{
public interface IDebuggableProcess
{
public void DebugStopAllThreads();
public ulong[] DebugGetThreadUids();
public Ryujinx.Cpu.IExecutionContext DebugGetThreadContext(ulong threadUid);
public IVirtualMemoryManager CpuMemory { get; }
}
}

View file

@ -473,5 +473,13 @@ namespace Ryujinx.HLE.HOS
} }
IsPaused = pause; IsPaused = pause;
} }
public Debugger.IDebuggableProcess DebugGetApplicationProcess()
{
lock (KernelContext.Processes)
{
return KernelContext.Processes.Values.Where(x => x.IsApplication).First();
}
}
} }
} }

View file

@ -14,7 +14,7 @@ using System.Threading;
namespace Ryujinx.HLE.HOS.Kernel.Process namespace Ryujinx.HLE.HOS.Kernel.Process
{ {
class KProcess : KSynchronizationObject class KProcess : KSynchronizationObject, Debugger.IDebuggableProcess
{ {
public const uint KernelVersionMajor = 10; public const uint KernelVersionMajor = 10;
public const uint KernelVersionMinor = 4; public const uint KernelVersionMinor = 4;
@ -1175,5 +1175,32 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
{ {
return Capabilities.IsSvcPermitted(svcId); return Capabilities.IsSvcPermitted(svcId);
} }
public void DebugStopAllThreads()
{
lock (_threadingLock)
{
foreach (KThread thread in _threads)
{
thread.Context.DebugStop();
}
}
}
public ulong[] DebugGetThreadUids()
{
lock (_threadingLock)
{
return _threads.Select(x => x.ThreadUid).ToArray();
}
}
public Ryujinx.Cpu.IExecutionContext DebugGetThreadContext(ulong threadUid)
{
lock (_threadingLock)
{
return _threads.Where(x => x.ThreadUid == threadUid).FirstOrDefault()?.Context;
}
}
} }
} }

View file

@ -31,6 +31,19 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
{ {
} }
public void DebugStop()
{
}
public bool DebugStep()
{
return false;
}
public void DebugContinue()
{
}
public void StopRunning() public void StopRunning()
{ {
Running = false; Running = false;