Debugger refactor

This commit is contained in:
svc64 2023-10-06 15:33:35 +03:00
parent 81c399ec3e
commit 65d7a16a87
12 changed files with 115 additions and 114 deletions

View file

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

View file

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

View file

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

View file

@ -0,0 +1,10 @@
namespace Ryujinx.Cpu.AppleHv.Arm
{
enum ExceptionLevel: uint
{
PstateMask = 0xfffffff0,
EL1h = 0b0101,
El1t = 0b0100,
EL0 = 0b0000,
}
}

View file

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

View file

@ -138,6 +138,7 @@ namespace Ryujinx.Cpu.AppleHv
private readonly ulong _vcpu;
private int _interruptRequested;
private int _breakRequested;
public HvExecutionContextVcpu(ulong vcpu)
{

View file

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

View file

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

View file

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

View file

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

View file

@ -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()
{
}

View file

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