Skip to content

Commit

Permalink
Add option to override the runtime version used for .NET FW debugging
Browse files Browse the repository at this point in the history
  • Loading branch information
ElektroKill committed Nov 28, 2023
1 parent f159533 commit ec1b135
Show file tree
Hide file tree
Showing 9 changed files with 101 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,15 @@ You should have received a copy of the GNU General Public License
*/

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using dnSpy.Contracts.Debugger;
using dnSpy.Contracts.Debugger.DotNet.CorDebug;
using dnSpy.Contracts.Debugger.StartDebugging;
using dnSpy.Contracts.Debugger.StartDebugging.Dialog;
using dnSpy.Contracts.MVVM;
using dnSpy.Debugger.DotNet.CorDebug.Properties;
using dnSpy.Debugger.DotNet.CorDebug.Utilities;

namespace dnSpy.Debugger.DotNet.CorDebug.Dialogs.DebugProgram {
Expand All @@ -34,6 +37,16 @@ sealed class DotNetFrameworkStartDebuggingOptionsPage : DotNetCommonStartDebuggi
// Shouldn't be localized
public override string DisplayName => ".NET Framework";

public ListVM<string> RuntimeVersionsVM { get; } = new ListVM<string>(CreateRuntimeVersions());

static string[] CreateRuntimeVersions() {
var list = new List<string> {
dnSpy_Debugger_DotNet_CorDebug_Resources.DbgAsm_Autodetect,
};
list.AddRange(DotNetHelpers.GetInstalledFrameworkVersions().OrderByDescending(x => x));
return list.ToArray();
}

public DotNetFrameworkStartDebuggingOptionsPage(IPickFilename pickFilename, IPickDirectory pickDirectory)
: base(pickFilename, pickDirectory) {
}
Expand Down Expand Up @@ -74,10 +87,18 @@ DotNetFrameworkStartDebuggingOptions GetDefaultOptions(string filename, string b
DotNetFrameworkStartDebuggingOptions CreateOptions(string breakKind) =>
InitializeDefault(new DotNetFrameworkStartDebuggingOptions(), breakKind);

void Initialize(DotNetFrameworkStartDebuggingOptions options) => base.Initialize(options);
void Initialize(DotNetFrameworkStartDebuggingOptions options) {
base.Initialize(options);
if (options.DebuggeeVersion is null)
RuntimeVersionsVM.SelectedIndex = 0;
else
RuntimeVersionsVM.SelectedItem = options.DebuggeeVersion;
}

public override StartDebuggingOptionsInfo GetOptions() {
var options = GetOptions(new DotNetFrameworkStartDebuggingOptions());
var options = GetOptions(new DotNetFrameworkStartDebuggingOptions {
DebuggeeVersion = RuntimeVersionsVM.SelectedIndex == 0 ? null : RuntimeVersionsVM.SelectedItem
});
var flags = StartDebuggingOptionsInfoFlags.None;
if (File.Exists(options.Filename)) {
var extension = Path.GetExtension(options.Filename);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ public DotNetFrameworkDbgEngineImpl(DbgEngineImplDependencies deps, DbgManager d
}

protected override CLRTypeDebugInfo CreateDebugInfo(CorDebugStartDebuggingOptions options) =>
new DesktopCLRTypeDebugInfo();
new DesktopCLRTypeDebugInfo(((DotNetFrameworkStartDebuggingOptions)options).DebuggeeVersion);

protected override CLRTypeAttachInfo CreateAttachInfo(CorDebugAttachToProgramOptions options) =>
new DesktopCLRTypeAttachInfo(((DotNetFrameworkAttachToProgramOptions)options).DebuggeeVersion);
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,12 @@
<data name="DbgAsm_HostArgs" xml:space="preserve">
<value>Host Ar_guments</value>
</data>
<data name="DbgAsm_RuntimeVersion" xml:space="preserve">
<value>_Runtime Version</value>
</data>
<data name="DbgAsm_Autodetect" xml:space="preserve">
<value>Autodetect</value>
</data>
<data name="DbgAsm_Timeout" xml:space="preserve">
<value>_Timeout</value>
</data>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
Expand All @@ -46,8 +47,11 @@
<TextBox Grid.Row="2" Grid.Column="1" Margin="5 5 0 0" Name="cwdTextBox" Text="{Binding WorkingDirectory, ValidatesOnDataErrors=True, ValidatesOnExceptions=True, UpdateSourceTrigger=PropertyChanged}" />
<Button Grid.Row="2" Grid.Column="2" Margin="5 5 0 0" Style="{StaticResource EllipsisButton}" Command="{Binding PickWorkingDirectoryCommand}" />

<Label Grid.Row="3" Grid.Column="0" Margin="0 5 0 0" Content="{x:Static p:dnSpy_Debugger_DotNet_CorDebug_Resources.DbgAsm_BreakAt}" Target="{Binding ElementName=breakComboBox}" />
<ComboBox Grid.Row="3" Grid.Column="1" Margin="5 5 0 0" HorizontalAlignment="Stretch" Name="breakComboBox" DisplayMemberPath="Name" ItemsSource="{Binding BreakProcessKindVM.Items}" SelectedIndex="{Binding BreakProcessKindVM.SelectedIndex}" VerticalContentAlignment="Center" />
<Label Grid.Row="3" Grid.Column="0" Margin="0 5 0 0" Content="{x:Static p:dnSpy_Debugger_DotNet_CorDebug_Resources.DbgAsm_RuntimeVersion}" Target="{Binding ElementName=runtimeVersionComboBox}" />
<ComboBox Grid.Row="3" Grid.Column="1" Margin="5 5 0 0" HorizontalAlignment="Stretch" Name="runtimeVersionComboBox" ItemsSource="{Binding RuntimeVersionsVM.Items}" SelectedIndex="{Binding RuntimeVersionsVM.SelectedIndex}" VerticalContentAlignment="Center" />

<Label Grid.Row="4" Grid.Column="0" Margin="0 5 0 0" Content="{x:Static p:dnSpy_Debugger_DotNet_CorDebug_Resources.DbgAsm_BreakAt}" Target="{Binding ElementName=breakComboBox}" />
<ComboBox Grid.Row="4" Grid.Column="1" Margin="5 5 0 0" HorizontalAlignment="Stretch" Name="breakComboBox" DisplayMemberPath="Name" ItemsSource="{Binding BreakProcessKindVM.Items}" SelectedIndex="{Binding BreakProcessKindVM.SelectedIndex}" VerticalContentAlignment="Center" />
</Grid>
</DataTemplate>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,14 @@ You should have received a copy of the GNU General Public License
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Text.RegularExpressions;
using dndbg.COM.MetaHost;
using dnlib.DotNet;
using dnlib.PE;
using dnSpy.Debugger.DotNet.CorDebug.Native;
using dnSpy.Debugger.Shared;
using Microsoft.Win32;

Expand Down Expand Up @@ -188,5 +192,32 @@ public static bool IsDotNetExecutable(string filename) {
}
return false;
}

public static string? GetLatestInstalledFrameworkVersion() =>
GetInstalledFrameworkVersions().OrderByDescending(x => x).FirstOrDefault();

public static IEnumerable<string> GetInstalledFrameworkVersions() {
var clsid = new Guid("9280188D-0E8E-4867-B30C-7FA83884E8DE");
var riid = typeof(ICLRMetaHost).GUID;
var mh = (ICLRMetaHost)NativeMethods.CLRCreateInstance(ref clsid, ref riid);

int hr = mh.EnumerateInstalledRuntimes(out var iter);
if (hr < 0)
yield break;
for (;;) {
hr = iter.Next(1, out object obj, out uint fetched);
if (hr < 0 || fetched == 0)
break;

var rtInfo = (ICLRRuntimeInfo)obj;
uint chBuffer = 0;
var sb = new StringBuilder(300);
hr = rtInfo.GetVersionString(sb, ref chBuffer);
sb.EnsureCapacity((int)chBuffer);
hr = rtInfo.GetVersionString(sb, ref chBuffer);

yield return sb.ToString();
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,8 @@ interface ICLRMetaHost {
[return: MarshalAs(UnmanagedType.Interface)]
object GetRuntime([MarshalAs(UnmanagedType.LPWStr)] [In] string pwzVersion, [In] ref Guid riid);
void GetVersionFromFile([MarshalAs(UnmanagedType.LPWStr)] [In] string pwzFilePath, [MarshalAs(UnmanagedType.LPWStr)] [Out] StringBuilder pwzBuffer, [In] [Out] ref uint pcchBuffer);
[return: MarshalAs(UnmanagedType.Interface)]
IEnumUnknown EnumerateInstalledRuntimes();
[PreserveSig]
int EnumerateInstalledRuntimes([MarshalAs(UnmanagedType.Interface)] out IEnumUnknown ppEnumerator);
[PreserveSig]
int EnumerateLoadedRuntimes([In] IntPtr hndProcess, [MarshalAs(UnmanagedType.Interface)] out IEnumUnknown ppEnumerator);
void RequestRuntimeLoadedNotification([MarshalAs(UnmanagedType.Interface)] [In] ICLRMetaHost pCallbackFunction);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,17 @@ You should have received a copy of the GNU General Public License
using System.Text;
using dndbg.COM.CorDebug;
using dndbg.COM.MetaHost;
using dnSpy.Debugger.DotNet.CorDebug.Utilities;

namespace dndbg.Engine {
static class DebuggeeVersionDetector {
public static string GetVersion(string filename) => TryGetVersion(filename) ?? RuntimeEnvironment.GetSystemVersion();
public static string GetVersion(string filename) => TryGetVersion(filename) ??
DotNetHelpers.GetLatestInstalledFrameworkVersion() ??
#if NETFRAMEWORK
RuntimeEnvironment.GetSystemVersion();
#else
"v4.0.30319";
#endif

public static string? TryGetVersion(string filename) {
try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@ namespace dnSpy.Contracts.Debugger.DotNet.CorDebug {
/// This is used to debug .NET Framework assemblies.
/// </summary>
public sealed class DotNetFrameworkStartDebuggingOptions : CorDebugStartDebuggingOptions {
/// <summary>
/// Version of an already installed CLR (eg. "v2.0.50727", or "v4.0.30319") or null to auto detect it
/// </summary>
public string? DebuggeeVersion { get; set; }

/// <summary>
/// Clones this instance
/// </summary>
Expand All @@ -40,6 +45,7 @@ public DotNetFrameworkStartDebuggingOptions CopyTo(DotNetFrameworkStartDebugging
if (other is null)
throw new ArgumentNullException(nameof(other));
base.CopyTo(other);
other.DebuggeeVersion = DebuggeeVersion;
return other;
}
}
Expand Down

0 comments on commit ec1b135

Please sign in to comment.