mirror of
https://git.ryujinx.app/ryubing/ryujinx.git
synced 2025-07-30 11:57:11 +02:00
Add GDB Stub
Author: merry, svc64
This commit is contained in:
parent
0cc94fdf37
commit
890165707a
53 changed files with 2428 additions and 21 deletions
|
@ -338,6 +338,9 @@ namespace Ryujinx.Headless
|
|||
false,
|
||||
string.Empty,
|
||||
string.Empty,
|
||||
options.EnableGdbStub,
|
||||
options.GdbStubPort,
|
||||
options.DebuggerSuspendOnStart,
|
||||
options.CustomVSyncInterval
|
||||
)
|
||||
.Configure(
|
||||
|
|
|
@ -423,6 +423,17 @@ namespace Ryujinx.Headless
|
|||
[Option("skip-user-profiles-manager", Required = false, Default = false, HelpText = "Enable skips the Profiles Manager popup during gameplay. Select the desired profile before starting the game")]
|
||||
public bool SkipUserProfilesManager { get; set; }
|
||||
|
||||
// Debug
|
||||
|
||||
[Option("enable-gdb-stub", Required = false, Default = false, HelpText = "Enables the GDB stub so that a developer can attach a debugger to the emulated process.")]
|
||||
public bool EnableGdbStub { get; set; }
|
||||
|
||||
[Option("gdb-stub-port", Required = false, Default = 55555, HelpText = "Specifies which TCP port the GDB stub listens on.")]
|
||||
public ushort GdbStubPort { get; set; }
|
||||
|
||||
[Option("suspend-on-start", Required = false, Default = false, HelpText = "Suspend execution when starting an application.")]
|
||||
public bool DebuggerSuspendOnStart { get; set; }
|
||||
|
||||
// Values
|
||||
|
||||
[Value(0, MetaName = "input", HelpText = "Input to load.", Required = true)]
|
||||
|
|
|
@ -218,6 +218,10 @@ namespace Ryujinx.Ava.Systems
|
|||
ConfigurationState.Instance.Multiplayer.LdnServer.Event += UpdateLdnServerState;
|
||||
ConfigurationState.Instance.Multiplayer.DisableP2p.Event += UpdateDisableP2pState;
|
||||
|
||||
ConfigurationState.Instance.Debug.EnableGdbStub.Event += UpdateEnableGdbStubState;
|
||||
ConfigurationState.Instance.Debug.GdbStubPort.Event += UpdateGdbStubPortState;
|
||||
ConfigurationState.Instance.Debug.DebuggerSuspendOnStart.Event += UpdateDebuggerSuspendOnStartState;
|
||||
|
||||
_gpuCancellationTokenSource = new CancellationTokenSource();
|
||||
_gpuDoneEvent = new ManualResetEvent(false);
|
||||
}
|
||||
|
@ -564,6 +568,21 @@ namespace Ryujinx.Ava.Systems
|
|||
Device.Configuration.MultiplayerDisableP2p = e.NewValue;
|
||||
}
|
||||
|
||||
private void UpdateEnableGdbStubState(object sender, ReactiveEventArgs<bool> e)
|
||||
{
|
||||
Device.Configuration.EnableGdbStub = e.NewValue;
|
||||
}
|
||||
|
||||
private void UpdateGdbStubPortState(object sender, ReactiveEventArgs<ushort> e)
|
||||
{
|
||||
Device.Configuration.GdbStubPort = e.NewValue;
|
||||
}
|
||||
|
||||
private void UpdateDebuggerSuspendOnStartState(object sender, ReactiveEventArgs<bool> e)
|
||||
{
|
||||
Device.Configuration.DebuggerSuspendOnStart = e.NewValue;
|
||||
}
|
||||
|
||||
public void Stop()
|
||||
{
|
||||
_isActive = false;
|
||||
|
|
|
@ -464,6 +464,21 @@ namespace Ryujinx.Ava.Systems.Configuration
|
|||
/// </summary>
|
||||
public bool UseHypervisor { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Enables or disables the GDB stub
|
||||
/// </summary>
|
||||
public bool EnableGdbStub { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Which TCP port should the GDB stub listen on
|
||||
/// </summary>
|
||||
public ushort GdbStubPort { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Suspend execution when starting an application
|
||||
/// </summary>
|
||||
public bool DebuggerSuspendOnStart { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Show toggles for dirty hacks in the UI.
|
||||
/// </summary>
|
||||
|
|
|
@ -156,6 +156,10 @@ namespace Ryujinx.Ava.Systems.Configuration
|
|||
Multiplayer.LdnPassphrase.Value = cff.MultiplayerLdnPassphrase;
|
||||
Multiplayer.LdnServer.Value = cff.LdnServer;
|
||||
|
||||
Debug.EnableGdbStub.Value = cff.EnableGdbStub;
|
||||
Debug.GdbStubPort.Value = cff.GdbStubPort;
|
||||
Debug.DebuggerSuspendOnStart.Value = cff.DebuggerSuspendOnStart;
|
||||
|
||||
{
|
||||
Hacks.ShowDirtyHacks.Value = shouldLoadFromFile ? cff.ShowDirtyHacks : Hacks.ShowDirtyHacks.Value; // Get from global config only
|
||||
|
||||
|
|
|
@ -703,6 +703,37 @@ namespace Ryujinx.Ava.Systems.Configuration
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Debug configuration section
|
||||
/// </summary>
|
||||
public class DebugSection
|
||||
{
|
||||
/// <summary>
|
||||
/// Enables or disables the GDB stub
|
||||
/// </summary>
|
||||
public ReactiveObject<bool> EnableGdbStub { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Which TCP port should the GDB stub listen on
|
||||
/// </summary>
|
||||
public ReactiveObject<ushort> GdbStubPort { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Suspend execution when starting an application
|
||||
/// </summary>
|
||||
public ReactiveObject<bool> DebuggerSuspendOnStart { get; private set; }
|
||||
|
||||
public DebugSection()
|
||||
{
|
||||
EnableGdbStub = new ReactiveObject<bool>();
|
||||
EnableGdbStub.LogChangesToValue(nameof(EnableGdbStub));
|
||||
GdbStubPort = new ReactiveObject<ushort>();
|
||||
GdbStubPort.LogChangesToValue(nameof(GdbStubPort));
|
||||
DebuggerSuspendOnStart = new ReactiveObject<bool>();
|
||||
DebuggerSuspendOnStart.LogChangesToValue(nameof(DebuggerSuspendOnStart));
|
||||
}
|
||||
}
|
||||
|
||||
public class HacksSection
|
||||
{
|
||||
/// <summary>
|
||||
|
@ -801,6 +832,11 @@ namespace Ryujinx.Ava.Systems.Configuration
|
|||
/// </summary>
|
||||
public MultiplayerSection Multiplayer { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The Debug
|
||||
/// </summary>
|
||||
public DebugSection Debug { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The Dirty Hacks section
|
||||
/// </summary>
|
||||
|
@ -854,6 +890,7 @@ namespace Ryujinx.Ava.Systems.Configuration
|
|||
Graphics = new GraphicsSection();
|
||||
Hid = new HidSection();
|
||||
Multiplayer = new MultiplayerSection();
|
||||
Debug = new DebugSection();
|
||||
Hacks = new HacksSection();
|
||||
UpdateCheckerType = new ReactiveObject<UpdaterType>();
|
||||
FocusLostActionType = new ReactiveObject<FocusLostType>();
|
||||
|
@ -893,6 +930,9 @@ namespace Ryujinx.Ava.Systems.Configuration
|
|||
Multiplayer.DisableP2p,
|
||||
Multiplayer.LdnPassphrase,
|
||||
Multiplayer.GetLdnServer(),
|
||||
Debug.EnableGdbStub,
|
||||
Debug.GdbStubPort,
|
||||
Debug.DebuggerSuspendOnStart,
|
||||
Graphics.CustomVSyncInterval,
|
||||
Hacks.ShowDirtyHacks ? Hacks.EnabledHacks : null);
|
||||
}
|
||||
|
|
|
@ -147,6 +147,9 @@ namespace Ryujinx.Ava.Systems.Configuration
|
|||
MultiplayerDisableP2p = Multiplayer.DisableP2p,
|
||||
MultiplayerLdnPassphrase = Multiplayer.LdnPassphrase,
|
||||
LdnServer = Multiplayer.LdnServer,
|
||||
EnableGdbStub = Debug.EnableGdbStub,
|
||||
GdbStubPort = Debug.GdbStubPort,
|
||||
DebuggerSuspendOnStart = Debug.DebuggerSuspendOnStart,
|
||||
ShowDirtyHacks = Hacks.ShowDirtyHacks,
|
||||
DirtyHacks = Hacks.EnabledHacks.Select(it => it.Pack()).ToArray(),
|
||||
};
|
||||
|
@ -324,6 +327,9 @@ namespace Ryujinx.Ava.Systems.Configuration
|
|||
},
|
||||
}
|
||||
];
|
||||
Debug.EnableGdbStub.Value = false;
|
||||
Debug.GdbStubPort.Value = 55555;
|
||||
Debug.DebuggerSuspendOnStart.Value = false;
|
||||
}
|
||||
|
||||
private static GraphicsBackend DefaultGraphicsBackend()
|
||||
|
|
|
@ -71,6 +71,10 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||
private string _ldnPassphrase;
|
||||
[ObservableProperty] private string _ldnServer;
|
||||
|
||||
private bool _enableGDBStub;
|
||||
private ushort _gdbStubPort;
|
||||
private bool _debuggerSuspendOnStart;
|
||||
|
||||
public SettingsHacksViewModel DirtyHacks { get; }
|
||||
|
||||
private readonly bool _isGameRunning;
|
||||
|
@ -387,6 +391,36 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||
|
||||
public bool IsInvalidLdnPassphraseVisible { get; set; }
|
||||
|
||||
public bool EnableGdbStub
|
||||
{
|
||||
get => _enableGDBStub;
|
||||
set
|
||||
{
|
||||
_enableGDBStub = value;
|
||||
ConfigurationState.Instance.Debug.EnableGdbStub.Value = _enableGDBStub;
|
||||
}
|
||||
}
|
||||
|
||||
public ushort GDBStubPort
|
||||
{
|
||||
get => _gdbStubPort;
|
||||
set
|
||||
{
|
||||
_gdbStubPort = value;
|
||||
ConfigurationState.Instance.Debug.GdbStubPort.Value = _gdbStubPort;
|
||||
}
|
||||
}
|
||||
|
||||
public bool DebuggerSuspendOnStart
|
||||
{
|
||||
get => _debuggerSuspendOnStart;
|
||||
set
|
||||
{
|
||||
_debuggerSuspendOnStart = value;
|
||||
ConfigurationState.Instance.Debug.DebuggerSuspendOnStart.Value = _debuggerSuspendOnStart;
|
||||
}
|
||||
}
|
||||
|
||||
public SettingsViewModel(VirtualFileSystem virtualFileSystem, ContentManager contentManager) : this()
|
||||
{
|
||||
_virtualFileSystem = virtualFileSystem;
|
||||
|
@ -680,10 +714,16 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||
FsGlobalAccessLogMode = config.System.FsGlobalAccessLogMode;
|
||||
OpenglDebugLevel = (int)config.Logger.GraphicsDebugLevel.Value;
|
||||
|
||||
// Multiplayer
|
||||
MultiplayerModeIndex = (int)config.Multiplayer.Mode.Value;
|
||||
DisableP2P = config.Multiplayer.DisableP2p;
|
||||
LdnPassphrase = config.Multiplayer.LdnPassphrase;
|
||||
LdnServer = config.Multiplayer.LdnServer;
|
||||
|
||||
// Debug
|
||||
EnableGdbStub = config.Debug.EnableGdbStub.Value;
|
||||
GDBStubPort = config.Debug.GdbStubPort.Value;
|
||||
DebuggerSuspendOnStart = config.Debug.DebuggerSuspendOnStart.Value;
|
||||
}
|
||||
|
||||
public void SaveSettings(bool global = false)
|
||||
|
@ -800,12 +840,18 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||
config.System.FsGlobalAccessLogMode.Value = FsGlobalAccessLogMode;
|
||||
config.Logger.GraphicsDebugLevel.Value = (GraphicsDebugLevel)OpenglDebugLevel;
|
||||
|
||||
// Multiplayer
|
||||
config.Multiplayer.LanInterfaceId.Value = _networkInterfaces[NetworkInterfaceList[NetworkInterfaceIndex]];
|
||||
config.Multiplayer.Mode.Value = (MultiplayerMode)MultiplayerModeIndex;
|
||||
config.Multiplayer.DisableP2p.Value = DisableP2P;
|
||||
config.Multiplayer.LdnPassphrase.Value = LdnPassphrase;
|
||||
config.Multiplayer.LdnServer.Value = LdnServer;
|
||||
|
||||
// Debug
|
||||
config.Debug.EnableGdbStub.Value = EnableGdbStub;
|
||||
config.Debug.GdbStubPort.Value = GDBStubPort;
|
||||
config.Debug.DebuggerSuspendOnStart.Value = DebuggerSuspendOnStart;
|
||||
|
||||
// Dirty Hacks
|
||||
config.Hacks.Xc2MenuSoftlockFix.Value = DirtyHacks.Xc2MenuSoftlockFix;
|
||||
config.Hacks.DisableNifmIsAnyInternetRequestAccepted.Value =
|
||||
|
|
64
src/Ryujinx/UI/Views/Settings/SettingsDebugView.axaml
Normal file
64
src/Ryujinx/UI/Views/Settings/SettingsDebugView.axaml
Normal file
|
@ -0,0 +1,64 @@
|
|||
<UserControl
|
||||
x:Class="Ryujinx.Ava.UI.Views.Settings.SettingsDebugView"
|
||||
xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:ext="clr-namespace:Ryujinx.Ava.Common.Markup"
|
||||
xmlns:helper="clr-namespace:Ryujinx.Common.Helper;assembly=Ryujinx.Common"
|
||||
xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
|
||||
xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels"
|
||||
mc:Ignorable="d"
|
||||
x:DataType="viewModels:SettingsViewModel">
|
||||
<Design.DataContext>
|
||||
<viewModels:SettingsViewModel />
|
||||
</Design.DataContext>
|
||||
<ScrollViewer
|
||||
Name="DebugPage"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
HorizontalScrollBarVisibility="Disabled"
|
||||
VerticalScrollBarVisibility="Auto">
|
||||
<Border Classes="settings">
|
||||
<StackPanel
|
||||
Margin="10"
|
||||
HorizontalAlignment="Stretch"
|
||||
Orientation="Vertical"
|
||||
Spacing="10">
|
||||
<TextBlock Classes="h1" Text="{ext:Locale SettingsTabDebugTitle}" />
|
||||
<StackPanel
|
||||
Margin="10,0,0,0"
|
||||
HorizontalAlignment="Stretch"
|
||||
Orientation="Vertical">
|
||||
<CheckBox IsChecked="{Binding EnableGdbStub}">
|
||||
<TextBlock Text="{ext:Locale EnableGDBStub}"
|
||||
ToolTip.Tip="{ext:Locale GDBStubToggleTooltip}" />
|
||||
</CheckBox>
|
||||
</StackPanel>
|
||||
<StackPanel
|
||||
Orientation="Horizontal">
|
||||
<TextBlock VerticalAlignment="Center"
|
||||
Text="{ext:Locale GDBStubPort}"
|
||||
Width="250" />
|
||||
<ui:NumberBox Value="{Binding GDBStubPort}"
|
||||
Width="350"
|
||||
SmallChange="1"
|
||||
LargeChange="10"
|
||||
SimpleNumberFormat="F0"
|
||||
SpinButtonPlacementMode="Inline"
|
||||
Minimum="1024"
|
||||
Maximum="65535" />
|
||||
</StackPanel>
|
||||
<StackPanel
|
||||
Margin="10,0,0,0"
|
||||
HorizontalAlignment="Stretch"
|
||||
Orientation="Vertical">
|
||||
<CheckBox IsChecked="{Binding DebuggerSuspendOnStart}">
|
||||
<TextBlock Text="{ext:Locale DebuggerSuspendOnStart}"
|
||||
ToolTip.Tip="{ext:Locale DebuggerSuspendOnStartTooltip}" />
|
||||
</CheckBox>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</ScrollViewer>
|
||||
</UserControl>
|
13
src/Ryujinx/UI/Views/Settings/SettingsDebugView.axaml.cs
Normal file
13
src/Ryujinx/UI/Views/Settings/SettingsDebugView.axaml.cs
Normal file
|
@ -0,0 +1,13 @@
|
|||
using Avalonia.Controls;
|
||||
|
||||
namespace Ryujinx.Ava.UI.Views.Settings
|
||||
{
|
||||
public partial class SettingsDebugView : UserControl
|
||||
{
|
||||
public SettingsDebugView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -46,6 +46,7 @@
|
|||
<settings:SettingsAudioView Name="AudioPage" />
|
||||
<settings:SettingsNetworkView Name="NetworkPage" />
|
||||
<settings:SettingsLoggingView Name="LoggingPage" />
|
||||
<settings:SettingsDebugView Name="DebugPage" />
|
||||
<settings:SettingsHacksView Name="HacksPage" />
|
||||
</Grid>
|
||||
<ui:NavigationView
|
||||
|
@ -100,6 +101,10 @@
|
|||
Content="{ext:Locale SettingsTabLogging}"
|
||||
Tag="LoggingPage"
|
||||
IconSource="Document" />
|
||||
<ui:NavigationViewItem
|
||||
Content="{ext:Locale SettingsTabDebug}"
|
||||
Tag="DebugPage"
|
||||
IconSource="Star" />
|
||||
<ui:NavigationViewItem
|
||||
IsVisible="{Binding ShowDirtyHacks}"
|
||||
Content="Dirty Hacks"
|
||||
|
|
|
@ -98,6 +98,9 @@ namespace Ryujinx.Ava.UI.Windows
|
|||
case "LoggingPage":
|
||||
NavPanel.Content = LoggingPage;
|
||||
break;
|
||||
case "DebugPage":
|
||||
NavPanel.Content = DebugPage;
|
||||
break;
|
||||
case nameof(HacksPage):
|
||||
HacksPage.DataContext = ViewModel;
|
||||
NavPanel.Content = HacksPage;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue