See merge request ryubing/ryujinx!71
This commit is contained in:
Coxxs
2025-08-04 20:45:15 -05:00
committed by LotP
parent 324f18aa5f
commit d22756f1bd
58 changed files with 3394 additions and 25 deletions

View File

@@ -0,0 +1,203 @@
using Ryujinx.Common;
using Ryujinx.Common.Logging;
using Ryujinx.HLE.HOS.Kernel.Threading;
using Ryujinx.Memory;
using System.Collections.Concurrent;
using System.Linq;
namespace Ryujinx.HLE.Debugger
{
internal class Breakpoint
{
public byte[] OriginalData { get; }
public bool IsStep { get; }
public Breakpoint(byte[] originalData, bool isStep)
{
OriginalData = originalData;
IsStep = isStep;
}
}
/// <summary>
/// Manages software breakpoints for the debugger.
/// </summary>
public class BreakpointManager
{
private readonly Debugger _debugger;
private readonly ConcurrentDictionary<ulong, Breakpoint> _breakpoints = new();
private static readonly byte[] _aarch64BreakInstruction = { 0x00, 0x00, 0x20, 0xD4 }; // BRK #0
private static readonly byte[] _aarch32BreakInstruction = { 0xFE, 0xDE, 0xFF, 0xE7 }; // TRAP
private static readonly byte[] _aarch32ThumbBreakInstruction = { 0x80, 0xB6 };
public BreakpointManager(Debugger debugger)
{
_debugger = debugger;
}
/// <summary>
/// Sets a software breakpoint at a specified address.
/// </summary>
/// <param name="address">The memory address to set the breakpoint at.</param>
/// <param name="length">The length of the instruction to replace.</param>
/// <param name="isStep">Indicates if this is a single-step breakpoint.</param>
/// <returns>True if the breakpoint was set successfully; otherwise, false.</returns>
public bool SetBreakPoint(ulong address, ulong length, bool isStep = false)
{
if (_breakpoints.ContainsKey(address))
{
return false;
}
byte[] breakInstruction = GetBreakInstruction(length);
if (breakInstruction == null)
{
Logger.Error?.Print(LogClass.GdbStub, $"Unsupported instruction length for breakpoint: {length}");
return false;
}
var originalInstruction = new byte[length];
if (!ReadMemory(address, originalInstruction))
{
Logger.Error?.Print(LogClass.GdbStub, $"Failed to read memory at 0x{address:X16} to set breakpoint.");
return false;
}
if (!WriteMemory(address, breakInstruction))
{
Logger.Error?.Print(LogClass.GdbStub, $"Failed to write breakpoint at 0x{address:X16}.");
return false;
}
var breakpoint = new Breakpoint(originalInstruction, isStep);
if (_breakpoints.TryAdd(address, breakpoint))
{
Logger.Debug?.Print(LogClass.GdbStub, $"Breakpoint set at 0x{address:X16}");
return true;
}
Logger.Error?.Print(LogClass.GdbStub, $"Failed to add breakpoint at 0x{address:X16}.");
return false;
}
/// <summary>
/// Clears a software breakpoint at a specified address.
/// </summary>
/// <param name="address">The memory address of the breakpoint to clear.</param>
/// <param name="length">The length of the instruction (unused).</param>
/// <returns>True if the breakpoint was cleared successfully; otherwise, false.</returns>
public bool ClearBreakPoint(ulong address, ulong length)
{
if (_breakpoints.TryGetValue(address, out Breakpoint breakpoint))
{
if (!WriteMemory(address, breakpoint.OriginalData))
{
Logger.Error?.Print(LogClass.GdbStub, $"Failed to restore original instruction at 0x{address:X16} to clear breakpoint.");
return false;
}
_breakpoints.TryRemove(address, out _);
Logger.Debug?.Print(LogClass.GdbStub, $"Breakpoint cleared at 0x{address:X16}");
return true;
}
Logger.Warning?.Print(LogClass.GdbStub, $"No breakpoint found at address 0x{address:X16}");
return false;
}
/// <summary>
/// Clears all currently set software breakpoints.
/// </summary>
public void ClearAll()
{
foreach (var bp in _breakpoints)
{
if (!WriteMemory(bp.Key, bp.Value.OriginalData))
{
Logger.Error?.Print(LogClass.GdbStub, $"Failed to restore original instruction at 0x{bp.Key:X16} while clearing all breakpoints.");
}
}
_breakpoints.Clear();
Logger.Debug?.Print(LogClass.GdbStub, "All breakpoints cleared.");
}
/// <summary>
/// Clears all currently set single-step software breakpoints.
/// </summary>
public void ClearAllStepBreakpoints()
{
var stepBreakpoints = _breakpoints.Where(p => p.Value.IsStep).ToList();
if (stepBreakpoints.Count == 0)
{
return;
}
foreach (var bp in stepBreakpoints)
{
if (_breakpoints.TryRemove(bp.Key, out Breakpoint removedBreakpoint))
{
WriteMemory(bp.Key, removedBreakpoint.OriginalData);
}
}
Logger.Debug?.Print(LogClass.GdbStub, "All step breakpoints cleared.");
}
private byte[] GetBreakInstruction(ulong length)
{
if (_debugger.IsProcessAarch32)
{
if (length == 2)
{
return _aarch32ThumbBreakInstruction;
}
if (length == 4)
{
return _aarch32BreakInstruction;
}
}
else
{
if (length == 4)
{
return _aarch64BreakInstruction;
}
}
return null;
}
private bool ReadMemory(ulong address, byte[] data)
{
try
{
_debugger.DebugProcess.CpuMemory.Read(address, data);
return true;
}
catch (InvalidMemoryRegionException)
{
return false;
}
}
private bool WriteMemory(ulong address, byte[] data)
{
try
{
_debugger.DebugProcess.CpuMemory.Write(address, data);
_debugger.DebugProcess.InvalidateCacheRegion(address, (ulong)data.Length);
return true;
}
catch (InvalidMemoryRegionException)
{
return false;
}
}
}
}

View File

@@ -0,0 +1,9 @@
namespace Ryujinx.HLE.Debugger
{
public enum DebugState
{
Running,
Stopping,
Stopped,
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,15 @@
namespace Ryujinx.HLE.Debugger
{
enum GdbSignal
{
Zero = 0,
Int = 2,
Quit = 3,
Trap = 5,
Abort = 6,
Alarm = 14,
IO = 23,
XCPU = 24,
Unknown = 143
}
}

View File

@@ -0,0 +1,93 @@
<?xml version="1.0"?>
<!-- Copyright (C) 2009-2022 Free Software Foundation, Inc.
Contributed by ARM Ltd.
Copying and distribution of this file, with or without modification,
are permitted in any medium without royalty provided the copyright
notice and this notice are preserved. -->
<!DOCTYPE feature SYSTEM "gdb-target.dtd">
<feature name="org.gnu.gdb.aarch64.core">
<reg name="x0" bitsize="64"/>
<reg name="x1" bitsize="64"/>
<reg name="x2" bitsize="64"/>
<reg name="x3" bitsize="64"/>
<reg name="x4" bitsize="64"/>
<reg name="x5" bitsize="64"/>
<reg name="x6" bitsize="64"/>
<reg name="x7" bitsize="64"/>
<reg name="x8" bitsize="64"/>
<reg name="x9" bitsize="64"/>
<reg name="x10" bitsize="64"/>
<reg name="x11" bitsize="64"/>
<reg name="x12" bitsize="64"/>
<reg name="x13" bitsize="64"/>
<reg name="x14" bitsize="64"/>
<reg name="x15" bitsize="64"/>
<reg name="x16" bitsize="64"/>
<reg name="x17" bitsize="64"/>
<reg name="x18" bitsize="64"/>
<reg name="x19" bitsize="64"/>
<reg name="x20" bitsize="64"/>
<reg name="x21" bitsize="64"/>
<reg name="x22" bitsize="64"/>
<reg name="x23" bitsize="64"/>
<reg name="x24" bitsize="64"/>
<reg name="x25" bitsize="64"/>
<reg name="x26" bitsize="64"/>
<reg name="x27" bitsize="64"/>
<reg name="x28" bitsize="64"/>
<reg name="x29" bitsize="64"/>
<reg name="x30" bitsize="64"/>
<reg name="sp" bitsize="64" type="data_ptr"/>
<reg name="pc" bitsize="64" type="code_ptr"/>
<flags id="cpsr_flags" size="4">
<!-- Stack Pointer. -->
<field name="SP" start="0" end="0"/>
<!-- Exception Level. -->
<field name="EL" start="2" end="3"/>
<!-- Execution state. -->
<field name="nRW" start="4" end="4"/>
<!-- FIQ interrupt mask. -->
<field name="F" start="6" end="6"/>
<!-- IRQ interrupt mask. -->
<field name="I" start="7" end="7"/>
<!-- SError interrupt mask. -->
<field name="A" start="8" end="8"/>
<!-- Debug exception mask. -->
<field name="D" start="9" end="9"/>
<!-- ARMv8.5-A: Branch Target Identification BTYPE. -->
<field name="BTYPE" start="10" end="11"/>
<!-- ARMv8.0-A: Speculative Store Bypass. -->
<field name="SSBS" start="12" end="12"/>
<!-- Illegal Execution state. -->
<field name="IL" start="20" end="20"/>
<!-- Software Step. -->
<field name="SS" start="21" end="21"/>
<!-- ARMv8.1-A: Privileged Access Never. -->
<field name="PAN" start="22" end="22"/>
<!-- ARMv8.2-A: User Access Override. -->
<field name="UAO" start="23" end="23"/>
<!-- ARMv8.4-A: Data Independent Timing. -->
<field name="DIT" start="24" end="24"/>
<!-- ARMv8.5-A: Tag Check Override. -->
<field name="TCO" start="25" end="25"/>
<!-- Overflow Condition flag. -->
<field name="V" start="28" end="28"/>
<!-- Carry Condition flag. -->
<field name="C" start="29" end="29"/>
<!-- Zero Condition flag. -->
<field name="Z" start="30" end="30"/>
<!-- Negative Condition flag. -->
<field name="N" start="31" end="31"/>
</flags>
<reg name="cpsr" bitsize="32" type="cpsr_flags"/>
</feature>

View File

@@ -0,0 +1,159 @@
<?xml version="1.0"?>
<!-- Copyright (C) 2009-2022 Free Software Foundation, Inc.
Contributed by ARM Ltd.
Copying and distribution of this file, with or without modification,
are permitted in any medium without royalty provided the copyright
notice and this notice are preserved. -->
<!DOCTYPE feature SYSTEM "gdb-target.dtd">
<feature name="org.gnu.gdb.aarch64.fpu">
<vector id="v2d" type="ieee_double" count="2"/>
<vector id="v2u" type="uint64" count="2"/>
<vector id="v2i" type="int64" count="2"/>
<vector id="v4f" type="ieee_single" count="4"/>
<vector id="v4u" type="uint32" count="4"/>
<vector id="v4i" type="int32" count="4"/>
<vector id="v8f" type="ieee_half" count="8"/>
<vector id="v8u" type="uint16" count="8"/>
<vector id="v8i" type="int16" count="8"/>
<vector id="v8bf16" type="bfloat16" count="8"/>
<vector id="v16u" type="uint8" count="16"/>
<vector id="v16i" type="int8" count="16"/>
<vector id="v1u" type="uint128" count="1"/>
<vector id="v1i" type="int128" count="1"/>
<union id="vnd">
<field name="f" type="v2d"/>
<field name="u" type="v2u"/>
<field name="s" type="v2i"/>
</union>
<union id="vns">
<field name="f" type="v4f"/>
<field name="u" type="v4u"/>
<field name="s" type="v4i"/>
</union>
<union id="vnh">
<field name="bf" type="v8bf16"/>
<field name="f" type="v8f"/>
<field name="u" type="v8u"/>
<field name="s" type="v8i"/>
</union>
<union id="vnb">
<field name="u" type="v16u"/>
<field name="s" type="v16i"/>
</union>
<union id="vnq">
<field name="u" type="v1u"/>
<field name="s" type="v1i"/>
</union>
<union id="aarch64v">
<field name="d" type="vnd"/>
<field name="s" type="vns"/>
<field name="h" type="vnh"/>
<field name="b" type="vnb"/>
<field name="q" type="vnq"/>
</union>
<reg name="v0" bitsize="128" type="aarch64v" regnum="34"/>
<reg name="v1" bitsize="128" type="aarch64v" />
<reg name="v2" bitsize="128" type="aarch64v" />
<reg name="v3" bitsize="128" type="aarch64v" />
<reg name="v4" bitsize="128" type="aarch64v" />
<reg name="v5" bitsize="128" type="aarch64v" />
<reg name="v6" bitsize="128" type="aarch64v" />
<reg name="v7" bitsize="128" type="aarch64v" />
<reg name="v8" bitsize="128" type="aarch64v" />
<reg name="v9" bitsize="128" type="aarch64v" />
<reg name="v10" bitsize="128" type="aarch64v"/>
<reg name="v11" bitsize="128" type="aarch64v"/>
<reg name="v12" bitsize="128" type="aarch64v"/>
<reg name="v13" bitsize="128" type="aarch64v"/>
<reg name="v14" bitsize="128" type="aarch64v"/>
<reg name="v15" bitsize="128" type="aarch64v"/>
<reg name="v16" bitsize="128" type="aarch64v"/>
<reg name="v17" bitsize="128" type="aarch64v"/>
<reg name="v18" bitsize="128" type="aarch64v"/>
<reg name="v19" bitsize="128" type="aarch64v"/>
<reg name="v20" bitsize="128" type="aarch64v"/>
<reg name="v21" bitsize="128" type="aarch64v"/>
<reg name="v22" bitsize="128" type="aarch64v"/>
<reg name="v23" bitsize="128" type="aarch64v"/>
<reg name="v24" bitsize="128" type="aarch64v"/>
<reg name="v25" bitsize="128" type="aarch64v"/>
<reg name="v26" bitsize="128" type="aarch64v"/>
<reg name="v27" bitsize="128" type="aarch64v"/>
<reg name="v28" bitsize="128" type="aarch64v"/>
<reg name="v29" bitsize="128" type="aarch64v"/>
<reg name="v30" bitsize="128" type="aarch64v"/>
<reg name="v31" bitsize="128" type="aarch64v"/>
<flags id="fpsr_flags" size="4">
<!-- Invalid Operation cumulative floating-point exception bit. -->
<field name="IOC" start="0" end="0"/>
<!-- Divide by Zero cumulative floating-point exception bit. -->
<field name="DZC" start="1" end="1"/>
<!-- Overflow cumulative floating-point exception bit. -->
<field name="OFC" start="2" end="2"/>
<!-- Underflow cumulative floating-point exception bit. -->
<field name="UFC" start="3" end="3"/>
<!-- Inexact cumulative floating-point exception bit.. -->
<field name="IXC" start="4" end="4"/>
<!-- Input Denormal cumulative floating-point exception bit. -->
<field name="IDC" start="7" end="7"/>
<!-- Cumulative saturation bit, Advanced SIMD only. -->
<field name="QC" start="27" end="27"/>
<!-- When AArch32 is supported at any Exception level and AArch32
floating-point is implemented: Overflow condition flag for AArch32
floating-point comparison operations. -->
<field name="V" start="28" end="28"/>
<!-- When AArch32 is supported at any Exception level and AArch32
floating-point is implemented:
Carry condition flag for AArch32 floating-point comparison operations.
-->
<field name="C" start="29" end="29"/>
<!-- When AArch32 is supported at any Exception level and AArch32
floating-point is implemented:
Zero condition flag for AArch32 floating-point comparison operations.
-->
<field name="Z" start="30" end="30"/>
<!-- When AArch32 is supported at any Exception level and AArch32
floating-point is implemented:
Negative condition flag for AArch32 floating-point comparison
operations. -->
<field name="N" start="31" end="31"/>
</flags>
<reg name="fpsr" bitsize="32" type="fpsr_flags"/>
<flags id="fpcr_flags" size="4">
<!-- Flush Inputs to Zero (part of Armv8.7). -->
<field name="FIZ" start="0" end="0"/>
<!-- Alternate Handling (part of Armv8.7). -->
<field name="AH" start="1" end="1"/>
<!-- Controls how the output elements other than the lowest element of the
vector are determined for Advanced SIMD scalar instructions (part of
Armv8.7). -->
<field name="NEP" start="2" end="2"/>
<!-- Invalid Operation floating-point exception trap enable. -->
<field name="IOE" start="8" end="8"/>
<!-- Divide by Zero floating-point exception trap enable. -->
<field name="DZE" start="9" end="9"/>
<!-- Overflow floating-point exception trap enable. -->
<field name="OFE" start="10" end="10"/>
<!-- Underflow floating-point exception trap enable. -->
<field name="UFE" start="11" end="11"/>
<!-- Inexact floating-point exception trap enable. -->
<field name="IXE" start="12" end="12"/>
<!-- Input Denormal floating-point exception trap enable. -->
<field name="IDE" start="15" end="15"/>
<!-- Flush-to-zero mode control bit on half-precision data-processing
instructions. -->
<field name="FZ16" start="19" end="19"/>
<!-- Rounding Mode control field. -->
<field name="RMode" start="22" end="23"/>
<!-- Flush-to-zero mode control bit. -->
<field name="FZ" start="24" end="24"/>
<!-- Default NaN mode control bit. -->
<field name="DN" start="25" end="25"/>
<!-- Alternative half-precision control bit. -->
<field name="AHP" start="26" end="26"/>
</flags>
<reg name="fpcr" bitsize="32" type="fpcr_flags"/>
</feature>

View File

@@ -0,0 +1,27 @@
<?xml version="1.0"?>
<!-- Copyright (C) 2008 Free Software Foundation, Inc.
Copying and distribution of this file, with or without modification,
are permitted in any medium without royalty provided the copyright
notice and this notice are preserved. -->
<!DOCTYPE feature SYSTEM "gdb-target.dtd">
<feature name="org.gnu.gdb.arm.core">
<reg name="r0" bitsize="32"/>
<reg name="r1" bitsize="32"/>
<reg name="r2" bitsize="32"/>
<reg name="r3" bitsize="32"/>
<reg name="r4" bitsize="32"/>
<reg name="r5" bitsize="32"/>
<reg name="r6" bitsize="32"/>
<reg name="r7" bitsize="32"/>
<reg name="r8" bitsize="32"/>
<reg name="r9" bitsize="32"/>
<reg name="r10" bitsize="32"/>
<reg name="r11" bitsize="32"/>
<reg name="r12" bitsize="32"/>
<reg name="sp" bitsize="32" type="data_ptr"/>
<reg name="lr" bitsize="32"/>
<reg name="pc" bitsize="32" type="code_ptr"/>
<reg name="cpsr" bitsize="32" />
</feature>

View File

@@ -0,0 +1,86 @@
<?xml version="1.0"?>
<!-- Copyright (C) 2008 Free Software Foundation, Inc.
Copying and distribution of this file, with or without modification,
are permitted in any medium without royalty provided the copyright
notice and this notice are preserved. -->
<!DOCTYPE feature SYSTEM "gdb-target.dtd">
<feature name="org.gnu.gdb.arm.vfp">
<vector id="neon_uint8x8" type="uint8" count="8"/>
<vector id="neon_uint16x4" type="uint16" count="4"/>
<vector id="neon_uint32x2" type="uint32" count="2"/>
<vector id="neon_float32x2" type="ieee_single" count="2"/>
<union id="neon_d">
<field name="u8" type="neon_uint8x8"/>
<field name="u16" type="neon_uint16x4"/>
<field name="u32" type="neon_uint32x2"/>
<field name="u64" type="uint64"/>
<field name="f32" type="neon_float32x2"/>
<field name="f64" type="ieee_double"/>
</union>
<vector id="neon_uint8x16" type="uint8" count="16"/>
<vector id="neon_uint16x8" type="uint16" count="8"/>
<vector id="neon_uint32x4" type="uint32" count="4"/>
<vector id="neon_uint64x2" type="uint64" count="2"/>
<vector id="neon_float32x4" type="ieee_single" count="4"/>
<vector id="neon_float64x2" type="ieee_double" count="2"/>
<union id="neon_q">
<field name="u8" type="neon_uint8x16"/>
<field name="u16" type="neon_uint16x8"/>
<field name="u32" type="neon_uint32x4"/>
<field name="u64" type="neon_uint64x2"/>
<field name="f32" type="neon_float32x4"/>
<field name="f64" type="neon_float64x2"/>
</union>
<reg name="d0" bitsize="64" type="neon_d"/>
<reg name="d1" bitsize="64" type="neon_d"/>
<reg name="d2" bitsize="64" type="neon_d"/>
<reg name="d3" bitsize="64" type="neon_d"/>
<reg name="d4" bitsize="64" type="neon_d"/>
<reg name="d5" bitsize="64" type="neon_d"/>
<reg name="d6" bitsize="64" type="neon_d"/>
<reg name="d7" bitsize="64" type="neon_d"/>
<reg name="d8" bitsize="64" type="neon_d"/>
<reg name="d9" bitsize="64" type="neon_d"/>
<reg name="d10" bitsize="64" type="neon_d"/>
<reg name="d11" bitsize="64" type="neon_d"/>
<reg name="d12" bitsize="64" type="neon_d"/>
<reg name="d13" bitsize="64" type="neon_d"/>
<reg name="d14" bitsize="64" type="neon_d"/>
<reg name="d15" bitsize="64" type="neon_d"/>
<reg name="d16" bitsize="64" type="neon_d"/>
<reg name="d17" bitsize="64" type="neon_d"/>
<reg name="d18" bitsize="64" type="neon_d"/>
<reg name="d19" bitsize="64" type="neon_d"/>
<reg name="d20" bitsize="64" type="neon_d"/>
<reg name="d21" bitsize="64" type="neon_d"/>
<reg name="d22" bitsize="64" type="neon_d"/>
<reg name="d23" bitsize="64" type="neon_d"/>
<reg name="d24" bitsize="64" type="neon_d"/>
<reg name="d25" bitsize="64" type="neon_d"/>
<reg name="d26" bitsize="64" type="neon_d"/>
<reg name="d27" bitsize="64" type="neon_d"/>
<reg name="d28" bitsize="64" type="neon_d"/>
<reg name="d29" bitsize="64" type="neon_d"/>
<reg name="d30" bitsize="64" type="neon_d"/>
<reg name="d31" bitsize="64" type="neon_d"/>
<reg name="q0" bitsize="128" type="neon_q"/>
<reg name="q1" bitsize="128" type="neon_q"/>
<reg name="q2" bitsize="128" type="neon_q"/>
<reg name="q3" bitsize="128" type="neon_q"/>
<reg name="q4" bitsize="128" type="neon_q"/>
<reg name="q5" bitsize="128" type="neon_q"/>
<reg name="q6" bitsize="128" type="neon_q"/>
<reg name="q7" bitsize="128" type="neon_q"/>
<reg name="q8" bitsize="128" type="neon_q"/>
<reg name="q9" bitsize="128" type="neon_q"/>
<reg name="q10" bitsize="128" type="neon_q"/>
<reg name="q11" bitsize="128" type="neon_q"/>
<reg name="q12" bitsize="128" type="neon_q"/>
<reg name="q13" bitsize="128" type="neon_q"/>
<reg name="q14" bitsize="128" type="neon_q"/>
<reg name="q15" bitsize="128" type="neon_q"/>
<reg name="fpscr" bitsize="32" type="int" group="float"/>
</feature>

View File

@@ -0,0 +1,14 @@
<?xml version="1.0"?>
<!-- Copyright (C) 2009-2013 Free Software Foundation, Inc.
Contributed by ARM Ltd.
Copying and distribution of this file, with or without modification,
are permitted in any medium without royalty provided the copyright
notice and this notice are preserved. -->
<!DOCTYPE target SYSTEM "gdb-target.dtd">
<target>
<architecture>arm</architecture>
<xi:include href="arm-core.xml"/>
<xi:include href="arm-neon.xml"/>
</target>

View File

@@ -0,0 +1,14 @@
<?xml version="1.0"?>
<!-- Copyright (C) 2009-2013 Free Software Foundation, Inc.
Contributed by ARM Ltd.
Copying and distribution of this file, with or without modification,
are permitted in any medium without royalty provided the copyright
notice and this notice are preserved. -->
<!DOCTYPE target SYSTEM "gdb-target.dtd">
<target>
<architecture>aarch64</architecture>
<xi:include href="aarch64-core.xml"/>
<xi:include href="aarch64-fpu.xml"/>
</target>

View File

@@ -0,0 +1,21 @@
using Ryujinx.Cpu;
using Ryujinx.HLE.HOS.Kernel.Threading;
using Ryujinx.Memory;
namespace Ryujinx.HLE.Debugger
{
internal interface IDebuggableProcess
{
void DebugStop();
void DebugContinue();
void DebugContinue(KThread thread);
bool DebugStep(KThread thread);
KThread GetThread(ulong threadUid);
DebugState GetDebugState();
bool IsThreadPaused(KThread thread);
ulong[] GetThreadUids();
public void DebugInterruptHandler(IExecutionContext ctx);
IVirtualMemoryManager CpuMemory { get; }
void InvalidateCacheRegion(ulong address, ulong size);
}
}

View File

@@ -0,0 +1,6 @@
namespace Ryujinx.HLE.Debugger
{
struct BreakInMessage : IMessage
{
}
}

View File

@@ -0,0 +1,12 @@
namespace Ryujinx.HLE.Debugger
{
struct CommandMessage : IMessage
{
public string Command;
public CommandMessage(string cmd)
{
Command = cmd;
}
}
}

View File

@@ -0,0 +1,6 @@
namespace Ryujinx.HLE.Debugger
{
interface IMessage
{
}
}

View File

@@ -0,0 +1,6 @@
namespace Ryujinx.HLE.Debugger
{
struct KillMessage : IMessage
{
}
}

View File

@@ -0,0 +1,6 @@
namespace Ryujinx.HLE.Debugger
{
struct SendNackMessage : IMessage
{
}
}

View File

@@ -0,0 +1,18 @@
using IExecutionContext = Ryujinx.Cpu.IExecutionContext;
namespace Ryujinx.HLE.Debugger
{
public class ThreadBreakMessage : IMessage
{
public IExecutionContext Context { get; }
public ulong Address { get; }
public int Opcode { get; }
public ThreadBreakMessage(IExecutionContext context, ulong address, int opcode)
{
Context = context;
Address = address;
Opcode = opcode;
}
}
}

View File

@@ -0,0 +1,28 @@
using System.Collections.Generic;
using System.IO;
namespace Ryujinx.HLE.Debugger
{
class RegisterInformation
{
public static readonly Dictionary<string, string> Features = new()
{
{ "target64.xml", GetEmbeddedResourceContent("target64.xml") },
{ "target32.xml", GetEmbeddedResourceContent("target32.xml") },
{ "aarch64-core.xml", GetEmbeddedResourceContent("aarch64-core.xml") },
{ "aarch64-fpu.xml", GetEmbeddedResourceContent("aarch64-fpu.xml") },
{ "arm-core.xml", GetEmbeddedResourceContent("arm-core.xml") },
{ "arm-neon.xml", GetEmbeddedResourceContent("arm-neon.xml") },
};
private static string GetEmbeddedResourceContent(string resourceName)
{
Stream stream = System.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceStream("Ryujinx.HLE.Debugger.GdbXml." + resourceName);
StreamReader reader = new StreamReader(stream);
string result = reader.ReadToEnd();
reader.Dispose();
stream.Dispose();
return result;
}
}
}

View File

@@ -0,0 +1,109 @@
using System.Diagnostics;
using System.Globalization;
namespace Ryujinx.HLE.Debugger
{
class StringStream
{
private readonly string Data;
private int Position;
public StringStream(string s)
{
Data = s;
}
public char ReadChar()
{
return Data[Position++];
}
public string ReadUntil(char needle)
{
int needlePos = Data.IndexOf(needle, Position);
if (needlePos == -1)
{
needlePos = Data.Length;
}
string result = Data.Substring(Position, needlePos - Position);
Position = needlePos + 1;
return result;
}
public string ReadLength(int len)
{
string result = Data.Substring(Position, len);
Position += len;
return result;
}
public string ReadRemaining()
{
string result = Data.Substring(Position);
Position = Data.Length;
return result;
}
public ulong ReadRemainingAsHex()
{
return ulong.Parse(ReadRemaining(), NumberStyles.HexNumber);
}
public ulong ReadUntilAsHex(char needle)
{
return ulong.Parse(ReadUntil(needle), NumberStyles.HexNumber);
}
public ulong ReadLengthAsHex(int len)
{
return ulong.Parse(ReadLength(len), NumberStyles.HexNumber);
}
public ulong ReadLengthAsLEHex(int len)
{
Debug.Assert(len % 2 == 0);
ulong result = 0;
int pos = 0;
while (pos < len)
{
result += ReadLengthAsHex(2) << (4 * pos);
pos += 2;
}
return result;
}
public ulong? ReadRemainingAsThreadUid()
{
string s = ReadRemaining();
return s == "-1" ? null : ulong.Parse(s, NumberStyles.HexNumber);
}
public bool ConsumePrefix(string prefix)
{
if (Data.Substring(Position).StartsWith(prefix))
{
Position += prefix.Length;
return true;
}
return false;
}
public bool ConsumeRemaining(string match)
{
if (Data.Substring(Position) == match)
{
Position += match.Length;
return true;
}
return false;
}
public bool IsEmpty()
{
return Position >= Data.Length;
}
}
}