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.State;
using ARMeilleure.Translation; using ARMeilleure.Translation;
using System; using System;
using System.Threading;
using ExecutionContext = ARMeilleure.State.ExecutionContext;
namespace ARMeilleure.Instructions namespace ARMeilleure.Instructions
{ {
@ -175,7 +177,7 @@ namespace ARMeilleure.Instructions
ExecutionContext context = GetContext(); ExecutionContext context = GetContext();
if (context.DebugStopped == 1) if (Optimizations.EnableDebugging && context.Interrupted)
{ {
return false; return false;
} }

View file

@ -14,7 +14,7 @@ namespace ARMeilleure.State
internal IntPtr NativeContextPtr => _nativeContext.BasePtr; internal IntPtr NativeContextPtr => _nativeContext.BasePtr;
private bool _interrupted; internal bool Interrupted { get; private set; }
private readonly ICounter _counter; private readonly ICounter _counter;
@ -104,8 +104,8 @@ namespace ARMeilleure.State
internal int ShouldStep; internal int ShouldStep;
internal int DebugStopped; internal int DebugStopped;
// This is only valid while debugging is enabled. public ulong DebugPc; // This is only valid while debugging is enabled.
public ulong DebugPc; public Barrier StepBarrier = new Barrier(2);
public ExecutionContext( public ExecutionContext(
IJitMemoryAllocator allocator, IJitMemoryAllocator allocator,
@ -141,9 +141,9 @@ namespace ARMeilleure.State
internal void CheckInterrupt() internal void CheckInterrupt()
{ {
if (_interrupted) if (Interrupted)
{ {
_interrupted = false; Interrupted = false;
_interruptCallback?.Invoke(this); _interruptCallback?.Invoke(this);
} }
@ -153,32 +153,14 @@ namespace ARMeilleure.State
public void RequestInterrupt() public void RequestInterrupt()
{ {
_interrupted = true; Interrupted = true;
} }
public void DebugStop() public void RequestDebugStep()
{
if (Interlocked.CompareExchange(ref DebugStopped, 1, 0) == 0)
{ {
Interlocked.Exchange(ref ShouldStep, 1);
RequestInterrupt(); 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) internal void OnBreak(ulong address, int imm)
{ {

View file

@ -144,19 +144,19 @@ namespace ARMeilleure.Translation
{ {
context.DebugPc = address; context.DebugPc = address;
do do
{
context.DebugPc = ExecuteSingle(context, context.DebugPc);
while (context.DebugStopped == 1)
{ {
if (Interlocked.CompareExchange(ref context.ShouldStep, 0, 1) == 1) if (Interlocked.CompareExchange(ref context.ShouldStep, 0, 1) == 1)
{ {
context.DebugPc = Step(context, context.DebugPc); context.DebugPc = Step(context, context.DebugPc);
context.RequestInterrupt(); context.StepBarrier.SignalAndWait();
context.StepBarrier.SignalAndWait();
}
else
{
context.DebugPc = ExecuteSingle(context, context.DebugPc);
} }
context.CheckInterrupt(); context.CheckInterrupt();
} }
}
while (context.Running && context.DebugPc != 0); while (context.Running && context.DebugPc != 0);
} }
else if (Optimizations.UseUnmanagedDispatchLoop) 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 class HvExecutionContext : IExecutionContext
{ {
/// <inheritdoc/> /// <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/> /// <inheritdoc/>
public long TpidrEl0 public long TpidrEl0
@ -71,7 +82,6 @@ namespace Ryujinx.Cpu.AppleHv
private readonly IHvExecutionContext _shadowContext; private readonly IHvExecutionContext _shadowContext;
private IHvExecutionContext _impl; private IHvExecutionContext _impl;
private int _shouldStep; private int _shouldStep;
private int _debugStopped;
private readonly ExceptionCallbacks _exceptionCallbacks; private readonly ExceptionCallbacks _exceptionCallbacks;
@ -83,6 +93,7 @@ namespace Ryujinx.Cpu.AppleHv
_shadowContext = new HvExecutionContextShadow(); _shadowContext = new HvExecutionContextShadow();
_impl = _shadowContext; _impl = _shadowContext;
_exceptionCallbacks = exceptionCallbacks; _exceptionCallbacks = exceptionCallbacks;
StepBarrier = new(2);
Running = true; Running = true;
} }
@ -133,38 +144,30 @@ namespace Ryujinx.Cpu.AppleHv
} }
/// <inheritdoc/> /// <inheritdoc/>
public void DebugStop() public void RequestDebugStep()
{ {
if (Interlocked.CompareExchange(ref _debugStopped, 1, 0) == 0) Interlocked.Exchange(ref _shouldStep, 1);
{
RequestInterrupt();
}
}
/// <inheritdoc/>
public bool DebugStep()
{
if (_debugStopped != 1)
{
return false;
}
_shouldStep = 1;
return true;
}
/// <inheritdoc/>
public void DebugContinue()
{
Interlocked.CompareExchange(ref _debugStopped, 0, 1);
} }
/// <inheritdoc/> /// <inheritdoc/>
public ulong DebugPc public ulong DebugPc
{ {
get => _impl.ElrEl1; get => Pc;
set => _impl.ElrEl1 = value; 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/> /// <inheritdoc/>
public void StopRunning() public void StopRunning()
@ -183,13 +186,17 @@ namespace Ryujinx.Cpu.AppleHv
{ {
if (Interlocked.CompareExchange(ref _shouldStep, 0, 1) == 1) if (Interlocked.CompareExchange(ref _shouldStep, 0, 1) == 1)
{ {
uint currentEl = Pstate & ~(0xfffffff0); uint currentEl = Pstate & ~((uint)ExceptionLevel.PstateMask);
if (currentEl == 0b0101) if (currentEl == (uint)ExceptionLevel.EL1h)
{ {
HvApi.hv_vcpu_get_sys_reg(vcpu.Handle, HvSysReg.SPSR_EL1, out ulong spsr).ThrowOnError(); HvApi.hv_vcpu_get_sys_reg(vcpu.Handle, HvSysReg.SPSR_EL1, out ulong spsr).ThrowOnError();
spsr |= (1 << 21); spsr |= (1 << 21);
HvApi.hv_vcpu_set_sys_reg(vcpu.Handle, HvSysReg.SPSR_EL1, spsr); 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); 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})."); throw new Exception($"Unhandled exception from guest kernel with ESR 0x{hvEsr:X} ({hvEc}).");
} }
address = SynchronousException(memoryManager, ref vcpu); address = SynchronousException(memoryManager, ref vcpu);
HvApi.hv_vcpu_set_reg(vcpu.Handle, HvReg.PC, address).ThrowOnError(); 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.SPSR_EL1, spsr).ThrowOnError();
HvApi.hv_vcpu_set_sys_reg(vcpuHandle, HvSysReg.MDSCR_EL1, 0); HvApi.hv_vcpu_set_sys_reg(vcpuHandle, HvSysReg.MDSCR_EL1, 0);
ReturnToPool(vcpu); ReturnToPool(vcpu);
StepBarrier.SignalAndWait();
StepBarrier.SignalAndWait();
InterruptHandler(); InterruptHandler();
vcpu = RentFromPool(memoryManager.AddressSpace, vcpu); vcpu = RentFromPool(memoryManager.AddressSpace, vcpu);
break; break;
case ExceptionClass.BrkAarch64: case ExceptionClass.BrkAarch64:
ReturnToPool(vcpu); ReturnToPool(vcpu);
BreakHandler(elr, (ushort)esr); BreakHandler(elr, (ushort)esr);
InterruptHandler();
vcpu = RentFromPool(memoryManager.AddressSpace, vcpu); vcpu = RentFromPool(memoryManager.AddressSpace, vcpu);
break; break;
default: default:

View file

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

View file

@ -1,5 +1,6 @@
using ARMeilleure.State; using ARMeilleure.State;
using System; using System;
using System.Threading;
namespace Ryujinx.Cpu namespace Ryujinx.Cpu
{ {
@ -115,10 +116,9 @@ namespace Ryujinx.Cpu
void StopRunning(); void StopRunning();
// TODO: comments // TODO: comments
void DebugStop(); void RequestDebugStep();
bool DebugStep();
void DebugContinue();
ulong DebugPc { get; set; } ulong DebugPc { get; set; }
Barrier StepBarrier { get; }
} }
} }

View file

@ -1,5 +1,7 @@
using ARMeilleure.Memory; using ARMeilleure.Memory;
using ARMeilleure.State; using ARMeilleure.State;
using System.Threading;
using ExecutionContext = ARMeilleure.State.ExecutionContext;
namespace Ryujinx.Cpu.Jit namespace Ryujinx.Cpu.Jit
{ {
@ -117,13 +119,7 @@ namespace Ryujinx.Cpu.Jit
} }
/// <inheritdoc/> /// <inheritdoc/>
public void DebugStop() => _impl.DebugStop(); public void RequestDebugStep() => _impl.RequestDebugStep();
/// <inheritdoc/>
public bool DebugStep() => _impl.DebugStep();
/// <inheritdoc/>
public void DebugContinue() => _impl.DebugContinue();
/// <inheritdoc/> /// <inheritdoc/>
public ulong DebugPc public ulong DebugPc
@ -132,6 +128,9 @@ namespace Ryujinx.Cpu.Jit
set => _impl.DebugPc = value; set => _impl.DebugPc = value;
} }
/// <inheritdoc/>
public Barrier StepBarrier => _impl.StepBarrier;
/// <inheritdoc/> /// <inheritdoc/>
public void StopRunning() public void StopRunning()
{ {

View file

@ -53,6 +53,7 @@ namespace Ryujinx.HLE.Debugger
private IVirtualMemoryManager GetMemory() => Device.System.DebugGetApplicationProcess().CpuMemory; private IVirtualMemoryManager GetMemory() => Device.System.DebugGetApplicationProcess().CpuMemory;
private void InvalidateCacheRegion(ulong address, ulong size) => private void InvalidateCacheRegion(ulong address, ulong size) =>
Device.System.DebugGetApplicationProcess().InvalidateCacheRegion(address, size); Device.System.DebugGetApplicationProcess().InvalidateCacheRegion(address, size);
private KernelContext KernelContext => Device.System.KernelContext;
const int GdbRegisterCount = 68; 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) switch (gdbRegId)
{ {
@ -724,13 +725,32 @@ namespace Ryujinx.HLE.Debugger
public void ThreadBreak(IExecutionContext ctx, ulong address, int imm) 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}"); Logger.Notice.Print(LogClass.GdbStub, $"Break hit on thread {ctx.ThreadUid} at pc {address:x016}");
Messages.Add(new ThreadBreakMessage(ctx, address, imm)); 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(); 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 && if (currentThread.Context.Running &&
currentThread.Owner != null && currentThread.Owner != null &&
currentThread.GetUserDisableCount() != 0 && currentThread.GetUserDisableCount() != 0 &&

View file

@ -1,5 +1,6 @@
using ARMeilleure.State; using ARMeilleure.State;
using Ryujinx.Cpu; using Ryujinx.Cpu;
using System.Threading;
namespace Ryujinx.HLE.HOS.Kernel.Process namespace Ryujinx.HLE.HOS.Kernel.Process
{ {
@ -24,6 +25,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
private readonly ulong[] _x = new ulong[32]; private readonly ulong[] _x = new ulong[32];
public ulong DebugPc { get; set; } public ulong DebugPc { get; set; }
public Barrier StepBarrier { get; }
public ulong GetX(int index) => _x[index]; public ulong GetX(int index) => _x[index];
public void SetX(int index, ulong value) => _x[index] = value; public void SetX(int index, ulong value) => _x[index] = value;
@ -35,16 +37,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
{ {
} }
public void DebugStop() public void RequestDebugStep()
{
}
public bool DebugStep()
{
return false;
}
public void DebugContinue()
{ {
} }

View file

@ -1443,15 +1443,16 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
lock (_activityOperationLock) lock (_activityOperationLock)
{ {
if (_debugState != (int)DebugState.Stopped if (_debugState != (int)DebugState.Stopped
|| (_forcePauseFlags & ThreadSchedState.ThreadPauseFlag) == 0 || (_forcePauseFlags & ThreadSchedState.ThreadPauseFlag) == 0)
|| !Context.DebugStep())
{ {
return false; return false;
} }
DebugHalt.Reset(); Context.RequestDebugStep();
Resume(ThreadSchedState.ThreadPauseFlag); Resume(ThreadSchedState.ThreadPauseFlag);
DebugHalt.WaitOne(); Context.StepBarrier.SignalAndWait();
Suspend(ThreadSchedState.ThreadPauseFlag);
Context.StepBarrier.SignalAndWait();
return true; return true;
} }
@ -1467,12 +1468,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
return; return;
} }
if ((_forcePauseFlags & ThreadSchedState.ThreadPauseFlag) == 0)
{
Suspend(ThreadSchedState.ThreadPauseFlag); Suspend(ThreadSchedState.ThreadPauseFlag);
} Context.RequestInterrupt();
Context.DebugStop();
DebugHalt.WaitOne(); DebugHalt.WaitOne();
_debugState = (int)DebugState.Stopped; _debugState = (int)DebugState.Stopped;
@ -1489,8 +1486,6 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
return; return;
} }
Context.DebugContinue();
if ((_forcePauseFlags & ThreadSchedState.ThreadPauseFlag) != 0) if ((_forcePauseFlags & ThreadSchedState.ThreadPauseFlag) != 0)
{ {
Resume(ThreadSchedState.ThreadPauseFlag); Resume(ThreadSchedState.ThreadPauseFlag);