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 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);
|
||||||
|
|
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;
|
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()
|
||||||
{
|
{
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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()
|
||||||
{
|
{
|
||||||
|
|
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;
|
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
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Reference in a new issue