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:
parent
b45a81458a
commit
39a3ba8329
13 changed files with 218 additions and 3 deletions
9
src/ARMeilleure/State/DebugState.cs
Normal file
9
src/ARMeilleure/State/DebugState.cs
Normal file
|
@ -0,0 +1,9 @@
|
|||
namespace ARMeilleure.State
|
||||
{
|
||||
enum DebugState
|
||||
{
|
||||
Running,
|
||||
Stopping,
|
||||
Stopped,
|
||||
}
|
||||
}
|
|
@ -1,5 +1,8 @@
|
|||
using ARMeilleure.Memory;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Diagnostics;
|
||||
using System.Threading;
|
||||
|
||||
namespace ARMeilleure.State
|
||||
{
|
||||
|
@ -96,6 +99,14 @@ namespace ARMeilleure.State
|
|||
private readonly ExceptionCallback _supervisorCallback;
|
||||
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(
|
||||
IJitMemoryAllocator allocator,
|
||||
ICounter counter,
|
||||
|
@ -145,6 +156,33 @@ namespace ARMeilleure.State
|
|||
_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)
|
||||
{
|
||||
_breakCallback?.Invoke(this, address, imm);
|
||||
|
|
9
src/Ryujinx.Cpu/AppleHv/DebugState.cs
Normal file
9
src/Ryujinx.Cpu/AppleHv/DebugState.cs
Normal file
|
@ -0,0 +1,9 @@
|
|||
namespace Ryujinx.Cpu.AppleHv
|
||||
{
|
||||
enum DebugState
|
||||
{
|
||||
Running,
|
||||
Stopping,
|
||||
Stopped,
|
||||
}
|
||||
}
|
|
@ -127,6 +127,15 @@ namespace Ryujinx.Cpu.AppleHv
|
|||
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/>
|
||||
public void StopRunning()
|
||||
{
|
||||
|
|
|
@ -46,5 +46,27 @@ namespace Ryujinx.Cpu.AppleHv
|
|||
{
|
||||
_v[index] = value;
|
||||
}
|
||||
|
||||
public void RequestInterrupt()
|
||||
{
|
||||
}
|
||||
|
||||
public void DebugStop()
|
||||
{
|
||||
}
|
||||
|
||||
public bool DebugStep()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public void DebugContinue()
|
||||
{
|
||||
}
|
||||
|
||||
public bool GetAndClearInterruptRequested()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,11 +2,10 @@ using ARMeilleure.State;
|
|||
using Ryujinx.Memory;
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.Versioning;
|
||||
using System.Threading;
|
||||
|
||||
namespace Ryujinx.Cpu.AppleHv
|
||||
{
|
||||
[SupportedOSPlatform("macos")]
|
||||
class HvExecutionContextVcpu : IHvExecutionContext
|
||||
{
|
||||
private static readonly MemoryBlock _setSimdFpRegFuncMem;
|
||||
|
@ -14,6 +13,14 @@ namespace Ryujinx.Cpu.AppleHv
|
|||
private static readonly SetSimdFpReg _setSimdFpReg;
|
||||
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()
|
||||
{
|
||||
// .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 int _interruptRequested;
|
||||
|
||||
public HvExecutionContextVcpu(ulong vcpu)
|
||||
{
|
||||
|
@ -181,8 +189,46 @@ namespace Ryujinx.Cpu.AppleHv
|
|||
|
||||
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;
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,5 +39,13 @@ namespace Ryujinx.Cpu.AppleHv
|
|||
SetV(i, context.GetV(i));
|
||||
}
|
||||
}
|
||||
|
||||
void RequestInterrupt();
|
||||
bool GetAndClearInterruptRequested();
|
||||
|
||||
// TODO: comments
|
||||
void DebugStop();
|
||||
bool DebugStep();
|
||||
void DebugContinue();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -108,5 +108,10 @@ namespace Ryujinx.Cpu
|
|||
/// If you only need to pause the thread temporarily, use <see cref="RequestInterrupt"/> instead.
|
||||
/// </remarks>
|
||||
void StopRunning();
|
||||
|
||||
// TODO: comments
|
||||
void DebugStop();
|
||||
bool DebugStep();
|
||||
void DebugContinue();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -109,6 +109,15 @@ namespace Ryujinx.Cpu.Jit
|
|||
_impl.RequestInterrupt();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void DebugStop() => _impl.DebugStop();
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool DebugStep() => _impl.DebugStep();
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void DebugContinue() => _impl.DebugContinue();
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void StopRunning()
|
||||
{
|
||||
|
|
12
src/Ryujinx.HLE/Debugger/IDebuggableProcess.cs
Normal file
12
src/Ryujinx.HLE/Debugger/IDebuggableProcess.cs
Normal 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; }
|
||||
}
|
||||
}
|
|
@ -473,5 +473,13 @@ namespace Ryujinx.HLE.HOS
|
|||
}
|
||||
IsPaused = pause;
|
||||
}
|
||||
|
||||
public Debugger.IDebuggableProcess DebugGetApplicationProcess()
|
||||
{
|
||||
lock (KernelContext.Processes)
|
||||
{
|
||||
return KernelContext.Processes.Values.Where(x => x.IsApplication).First();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@ using System.Threading;
|
|||
|
||||
namespace Ryujinx.HLE.HOS.Kernel.Process
|
||||
{
|
||||
class KProcess : KSynchronizationObject
|
||||
class KProcess : KSynchronizationObject, Debugger.IDebuggableProcess
|
||||
{
|
||||
public const uint KernelVersionMajor = 10;
|
||||
public const uint KernelVersionMinor = 4;
|
||||
|
@ -1175,5 +1175,32 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
|||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,6 +31,19 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
|||
{
|
||||
}
|
||||
|
||||
public void DebugStop()
|
||||
{
|
||||
}
|
||||
|
||||
public bool DebugStep()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public void DebugContinue()
|
||||
{
|
||||
}
|
||||
|
||||
public void StopRunning()
|
||||
{
|
||||
Running = false;
|
||||
|
|
Loading…
Reference in a new issue