Debugger refactor
This commit is contained in:
parent
81c399ec3e
commit
65d7a16a87
12 changed files with 115 additions and 114 deletions
|
@ -2,6 +2,8 @@ using ARMeilleure.Memory;
|
|||
using ARMeilleure.State;
|
||||
using ARMeilleure.Translation;
|
||||
using System;
|
||||
using System.Threading;
|
||||
using ExecutionContext = ARMeilleure.State.ExecutionContext;
|
||||
|
||||
namespace ARMeilleure.Instructions
|
||||
{
|
||||
|
@ -175,7 +177,7 @@ namespace ARMeilleure.Instructions
|
|||
|
||||
ExecutionContext context = GetContext();
|
||||
|
||||
if (context.DebugStopped == 1)
|
||||
if (Optimizations.EnableDebugging && context.Interrupted)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@ namespace ARMeilleure.State
|
|||
|
||||
internal IntPtr NativeContextPtr => _nativeContext.BasePtr;
|
||||
|
||||
private bool _interrupted;
|
||||
internal bool Interrupted { get; private set; }
|
||||
|
||||
private readonly ICounter _counter;
|
||||
|
||||
|
@ -104,8 +104,8 @@ namespace ARMeilleure.State
|
|||
internal int ShouldStep;
|
||||
internal int DebugStopped;
|
||||
|
||||
// This is only valid while debugging is enabled.
|
||||
public ulong DebugPc;
|
||||
public ulong DebugPc; // This is only valid while debugging is enabled.
|
||||
public Barrier StepBarrier = new Barrier(2);
|
||||
|
||||
public ExecutionContext(
|
||||
IJitMemoryAllocator allocator,
|
||||
|
@ -141,9 +141,9 @@ namespace ARMeilleure.State
|
|||
|
||||
internal void CheckInterrupt()
|
||||
{
|
||||
if (_interrupted)
|
||||
if (Interrupted)
|
||||
{
|
||||
_interrupted = false;
|
||||
Interrupted = false;
|
||||
|
||||
_interruptCallback?.Invoke(this);
|
||||
}
|
||||
|
@ -153,32 +153,14 @@ namespace ARMeilleure.State
|
|||
|
||||
public void RequestInterrupt()
|
||||
{
|
||||
_interrupted = true;
|
||||
Interrupted = true;
|
||||
}
|
||||
|
||||
public void DebugStop()
|
||||
{
|
||||
if (Interlocked.CompareExchange(ref DebugStopped, 1, 0) == 0)
|
||||
public void RequestDebugStep()
|
||||
{
|
||||
Interlocked.Exchange(ref ShouldStep, 1);
|
||||
RequestInterrupt();
|
||||
}
|
||||
}
|
||||
|
||||
public bool DebugStep()
|
||||
{
|
||||
if (DebugStopped != 1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
ShouldStep = 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
public void DebugContinue()
|
||||
{
|
||||
Interlocked.CompareExchange(ref DebugStopped, 0, 1);
|
||||
}
|
||||
|
||||
internal void OnBreak(ulong address, int imm)
|
||||
{
|
||||
|
|
|
@ -144,19 +144,19 @@ namespace ARMeilleure.Translation
|
|||
{
|
||||
context.DebugPc = address;
|
||||
do
|
||||
{
|
||||
context.DebugPc = ExecuteSingle(context, context.DebugPc);
|
||||
|
||||
while (context.DebugStopped == 1)
|
||||
{
|
||||
if (Interlocked.CompareExchange(ref context.ShouldStep, 0, 1) == 1)
|
||||
{
|
||||
context.DebugPc = Step(context, context.DebugPc);
|
||||
context.RequestInterrupt();
|
||||
context.StepBarrier.SignalAndWait();
|
||||
context.StepBarrier.SignalAndWait();
|
||||
}
|
||||
else
|
||||
{
|
||||
context.DebugPc = ExecuteSingle(context, context.DebugPc);
|
||||
}
|
||||
context.CheckInterrupt();
|
||||
}
|
||||
}
|
||||
while (context.Running && context.DebugPc != 0);
|
||||
}
|
||||
else if (Optimizations.UseUnmanagedDispatchLoop)
|
||||
|
|
10
src/Ryujinx.Cpu/AppleHv/Arm/ExceptionLevel.cs
Normal file
10
src/Ryujinx.Cpu/AppleHv/Arm/ExceptionLevel.cs
Normal file
|
@ -0,0 +1,10 @@
|
|||
namespace Ryujinx.Cpu.AppleHv.Arm
|
||||
{
|
||||
enum ExceptionLevel: uint
|
||||
{
|
||||
PstateMask = 0xfffffff0,
|
||||
EL1h = 0b0101,
|
||||
El1t = 0b0100,
|
||||
EL0 = 0b0000,
|
||||
}
|
||||
}
|
|
@ -11,7 +11,18 @@ namespace Ryujinx.Cpu.AppleHv
|
|||
class HvExecutionContext : IExecutionContext
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public ulong Pc => _impl.ElrEl1;
|
||||
public ulong Pc
|
||||
{
|
||||
get
|
||||
{
|
||||
uint currentEl = Pstate & ~((uint)ExceptionLevel.PstateMask);
|
||||
if (currentEl == (uint)ExceptionLevel.EL1h)
|
||||
{
|
||||
return _impl.ElrEl1;
|
||||
}
|
||||
return _impl.Pc;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public long TpidrEl0
|
||||
|
@ -71,7 +82,6 @@ namespace Ryujinx.Cpu.AppleHv
|
|||
private readonly IHvExecutionContext _shadowContext;
|
||||
private IHvExecutionContext _impl;
|
||||
private int _shouldStep;
|
||||
private int _debugStopped;
|
||||
|
||||
private readonly ExceptionCallbacks _exceptionCallbacks;
|
||||
|
||||
|
@ -83,6 +93,7 @@ namespace Ryujinx.Cpu.AppleHv
|
|||
_shadowContext = new HvExecutionContextShadow();
|
||||
_impl = _shadowContext;
|
||||
_exceptionCallbacks = exceptionCallbacks;
|
||||
StepBarrier = new(2);
|
||||
Running = true;
|
||||
}
|
||||
|
||||
|
@ -133,38 +144,30 @@ namespace Ryujinx.Cpu.AppleHv
|
|||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void DebugStop()
|
||||
public void RequestDebugStep()
|
||||
{
|
||||
if (Interlocked.CompareExchange(ref _debugStopped, 1, 0) == 0)
|
||||
{
|
||||
RequestInterrupt();
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool DebugStep()
|
||||
{
|
||||
if (_debugStopped != 1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
_shouldStep = 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void DebugContinue()
|
||||
{
|
||||
Interlocked.CompareExchange(ref _debugStopped, 0, 1);
|
||||
Interlocked.Exchange(ref _shouldStep, 1);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ulong DebugPc
|
||||
{
|
||||
get => _impl.ElrEl1;
|
||||
set => _impl.ElrEl1 = value;
|
||||
get => Pc;
|
||||
set
|
||||
{
|
||||
uint currentEl = Pstate & ~((uint)ExceptionLevel.PstateMask);
|
||||
if (currentEl == (uint)ExceptionLevel.EL1h)
|
||||
{
|
||||
_impl.ElrEl1 = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
_impl.Pc = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Barrier StepBarrier { get; private set; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void StopRunning()
|
||||
|
@ -183,13 +186,17 @@ namespace Ryujinx.Cpu.AppleHv
|
|||
{
|
||||
if (Interlocked.CompareExchange(ref _shouldStep, 0, 1) == 1)
|
||||
{
|
||||
uint currentEl = Pstate & ~(0xfffffff0);
|
||||
if (currentEl == 0b0101)
|
||||
uint currentEl = Pstate & ~((uint)ExceptionLevel.PstateMask);
|
||||
if (currentEl == (uint)ExceptionLevel.EL1h)
|
||||
{
|
||||
HvApi.hv_vcpu_get_sys_reg(vcpu.Handle, HvSysReg.SPSR_EL1, out ulong spsr).ThrowOnError();
|
||||
spsr |= (1 << 21);
|
||||
HvApi.hv_vcpu_set_sys_reg(vcpu.Handle, HvSysReg.SPSR_EL1, spsr);
|
||||
}
|
||||
else
|
||||
{
|
||||
Pstate |= (1 << 21);
|
||||
}
|
||||
HvApi.hv_vcpu_set_sys_reg(vcpu.Handle, HvSysReg.MDSCR_EL1, 1);
|
||||
}
|
||||
|
||||
|
@ -206,7 +213,6 @@ namespace Ryujinx.Cpu.AppleHv
|
|||
{
|
||||
throw new Exception($"Unhandled exception from guest kernel with ESR 0x{hvEsr:X} ({hvEc}).");
|
||||
}
|
||||
|
||||
address = SynchronousException(memoryManager, ref vcpu);
|
||||
HvApi.hv_vcpu_set_reg(vcpu.Handle, HvReg.PC, address).ThrowOnError();
|
||||
}
|
||||
|
@ -266,13 +272,14 @@ namespace Ryujinx.Cpu.AppleHv
|
|||
HvApi.hv_vcpu_set_sys_reg(vcpuHandle, HvSysReg.SPSR_EL1, spsr).ThrowOnError();
|
||||
HvApi.hv_vcpu_set_sys_reg(vcpuHandle, HvSysReg.MDSCR_EL1, 0);
|
||||
ReturnToPool(vcpu);
|
||||
StepBarrier.SignalAndWait();
|
||||
StepBarrier.SignalAndWait();
|
||||
InterruptHandler();
|
||||
vcpu = RentFromPool(memoryManager.AddressSpace, vcpu);
|
||||
break;
|
||||
case ExceptionClass.BrkAarch64:
|
||||
ReturnToPool(vcpu);
|
||||
BreakHandler(elr, (ushort)esr);
|
||||
InterruptHandler();
|
||||
vcpu = RentFromPool(memoryManager.AddressSpace, vcpu);
|
||||
break;
|
||||
default:
|
||||
|
|
|
@ -138,6 +138,7 @@ namespace Ryujinx.Cpu.AppleHv
|
|||
|
||||
private readonly ulong _vcpu;
|
||||
private int _interruptRequested;
|
||||
private int _breakRequested;
|
||||
|
||||
public HvExecutionContextVcpu(ulong vcpu)
|
||||
{
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
using ARMeilleure.State;
|
||||
using System;
|
||||
using System.Threading;
|
||||
|
||||
namespace Ryujinx.Cpu
|
||||
{
|
||||
|
@ -115,10 +116,9 @@ namespace Ryujinx.Cpu
|
|||
void StopRunning();
|
||||
|
||||
// TODO: comments
|
||||
void DebugStop();
|
||||
bool DebugStep();
|
||||
void DebugContinue();
|
||||
void RequestDebugStep();
|
||||
|
||||
ulong DebugPc { get; set; }
|
||||
Barrier StepBarrier { get; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
using ARMeilleure.Memory;
|
||||
using ARMeilleure.State;
|
||||
using System.Threading;
|
||||
using ExecutionContext = ARMeilleure.State.ExecutionContext;
|
||||
|
||||
namespace Ryujinx.Cpu.Jit
|
||||
{
|
||||
|
@ -117,13 +119,7 @@ namespace Ryujinx.Cpu.Jit
|
|||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void DebugStop() => _impl.DebugStop();
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool DebugStep() => _impl.DebugStep();
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void DebugContinue() => _impl.DebugContinue();
|
||||
public void RequestDebugStep() => _impl.RequestDebugStep();
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ulong DebugPc
|
||||
|
@ -132,6 +128,9 @@ namespace Ryujinx.Cpu.Jit
|
|||
set => _impl.DebugPc = value;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Barrier StepBarrier => _impl.StepBarrier;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void StopRunning()
|
||||
{
|
||||
|
|
|
@ -53,6 +53,7 @@ namespace Ryujinx.HLE.Debugger
|
|||
private IVirtualMemoryManager GetMemory() => Device.System.DebugGetApplicationProcess().CpuMemory;
|
||||
private void InvalidateCacheRegion(ulong address, ulong size) =>
|
||||
Device.System.DebugGetApplicationProcess().InvalidateCacheRegion(address, size);
|
||||
private KernelContext KernelContext => Device.System.KernelContext;
|
||||
|
||||
const int GdbRegisterCount = 68;
|
||||
|
||||
|
@ -77,7 +78,7 @@ namespace Ryujinx.HLE.Debugger
|
|||
}
|
||||
}
|
||||
|
||||
private string GdbReadRegister(Ryujinx.Cpu.IExecutionContext state, int gdbRegId)
|
||||
private string GdbReadRegister(IExecutionContext state, int gdbRegId)
|
||||
{
|
||||
switch (gdbRegId)
|
||||
{
|
||||
|
@ -724,13 +725,32 @@ namespace Ryujinx.HLE.Debugger
|
|||
|
||||
public void ThreadBreak(IExecutionContext ctx, ulong address, int imm)
|
||||
{
|
||||
KThread thread = GetThread(ctx.ThreadUid);
|
||||
|
||||
thread.DebugStop();
|
||||
|
||||
Logger.Notice.Print(LogClass.GdbStub, $"Break hit on thread {ctx.ThreadUid} at pc {address:x016}");
|
||||
|
||||
Messages.Add(new ThreadBreakMessage(ctx, address, imm));
|
||||
|
||||
KThread currentThread = GetThread(ctx.ThreadUid);
|
||||
|
||||
if (currentThread.Context.Running &&
|
||||
currentThread.Owner != null &&
|
||||
currentThread.GetUserDisableCount() != 0 &&
|
||||
currentThread.Owner.PinnedThreads[currentThread.CurrentCore] == null)
|
||||
{
|
||||
KernelContext.CriticalSection.Enter();
|
||||
|
||||
currentThread.Owner.PinThread(currentThread);
|
||||
|
||||
currentThread.SetUserInterruptFlag();
|
||||
|
||||
KernelContext.CriticalSection.Leave();
|
||||
}
|
||||
|
||||
if (currentThread.IsSchedulable)
|
||||
{
|
||||
KernelContext.Schedulers[currentThread.CurrentCore].Schedule();
|
||||
}
|
||||
|
||||
currentThread.HandlePostSyscall();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -749,14 +749,6 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
|||
{
|
||||
KThread currentThread = KernelStatic.GetCurrentThread();
|
||||
|
||||
if (currentThread.GetDebugState() != DebugState.Running)
|
||||
{
|
||||
KernelContext.CriticalSection.Enter();
|
||||
currentThread.Suspend(ThreadSchedState.ThreadPauseFlag);
|
||||
currentThread.DebugHalt.Set();
|
||||
KernelContext.CriticalSection.Leave();
|
||||
}
|
||||
|
||||
if (currentThread.Context.Running &&
|
||||
currentThread.Owner != null &&
|
||||
currentThread.GetUserDisableCount() != 0 &&
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
using ARMeilleure.State;
|
||||
using Ryujinx.Cpu;
|
||||
using System.Threading;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Kernel.Process
|
||||
{
|
||||
|
@ -24,6 +25,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
|||
private readonly ulong[] _x = new ulong[32];
|
||||
|
||||
public ulong DebugPc { get; set; }
|
||||
public Barrier StepBarrier { get; }
|
||||
|
||||
public ulong GetX(int index) => _x[index];
|
||||
public void SetX(int index, ulong value) => _x[index] = value;
|
||||
|
@ -35,16 +37,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
|||
{
|
||||
}
|
||||
|
||||
public void DebugStop()
|
||||
{
|
||||
}
|
||||
|
||||
public bool DebugStep()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public void DebugContinue()
|
||||
public void RequestDebugStep()
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -1443,15 +1443,16 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
|||
lock (_activityOperationLock)
|
||||
{
|
||||
if (_debugState != (int)DebugState.Stopped
|
||||
|| (_forcePauseFlags & ThreadSchedState.ThreadPauseFlag) == 0
|
||||
|| !Context.DebugStep())
|
||||
|| (_forcePauseFlags & ThreadSchedState.ThreadPauseFlag) == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
DebugHalt.Reset();
|
||||
Context.RequestDebugStep();
|
||||
Resume(ThreadSchedState.ThreadPauseFlag);
|
||||
DebugHalt.WaitOne();
|
||||
Context.StepBarrier.SignalAndWait();
|
||||
Suspend(ThreadSchedState.ThreadPauseFlag);
|
||||
Context.StepBarrier.SignalAndWait();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -1467,12 +1468,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
|||
return;
|
||||
}
|
||||
|
||||
if ((_forcePauseFlags & ThreadSchedState.ThreadPauseFlag) == 0)
|
||||
{
|
||||
Suspend(ThreadSchedState.ThreadPauseFlag);
|
||||
}
|
||||
|
||||
Context.DebugStop();
|
||||
Context.RequestInterrupt();
|
||||
DebugHalt.WaitOne();
|
||||
|
||||
_debugState = (int)DebugState.Stopped;
|
||||
|
@ -1489,8 +1486,6 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
|||
return;
|
||||
}
|
||||
|
||||
Context.DebugContinue();
|
||||
|
||||
if ((_forcePauseFlags & ThreadSchedState.ThreadPauseFlag) != 0)
|
||||
{
|
||||
Resume(ThreadSchedState.ThreadPauseFlag);
|
||||
|
|
Loading…
Reference in a new issue