Add runtime enumeration control to runtime service and providers (#4765)
authorMike McLaughlin <mikem@microsoft.com>
Fri, 28 Jun 2024 18:38:06 +0000 (11:38 -0700)
committerGitHub <noreply@github.com>
Fri, 28 Jun 2024 18:38:06 +0000 (11:38 -0700)
Add `runtimes --all` option.

src/Microsoft.Diagnostics.DebugServices.Implementation/RuntimeProvider.cs
src/Microsoft.Diagnostics.DebugServices.Implementation/RuntimeService.cs
src/Microsoft.Diagnostics.DebugServices/IRuntimeProvider.cs
src/Microsoft.Diagnostics.DebugServices/IRuntimeService.cs
src/Microsoft.Diagnostics.DebugServices/RuntimeEnumerationFlags.cs [new file with mode: 0644]
src/Microsoft.Diagnostics.ExtensionCommands/Host/RuntimesCommand.cs
src/SOS/SOS.Package/SOS.Symbol.Package.csproj
src/sos-packaging.props

index 3ea0ab90be54efd2336a1ff59249f9c593130d35..4639a0ebcfc34719a16e8c774a38dcc39e6c9602 100644 (file)
@@ -26,15 +26,17 @@ namespace Microsoft.Diagnostics.DebugServices.Implementation
         /// Returns the list of .NET runtimes in the target
         /// </summary>
         /// <param name="startingRuntimeId">The starting runtime id for this provider</param>
-        public IEnumerable<IRuntime> EnumerateRuntimes(int startingRuntimeId)
+        /// <param name="flags">Enumeration control flags</param>
+        public IEnumerable<IRuntime> EnumerateRuntimes(int startingRuntimeId, RuntimeEnumerationFlags flags)
         {
             // The ClrInfo and DataTarget instances are disposed when Runtime instance is disposed. Runtime instances are
             // not flushed when the Target/RuntimeService is flushed; they are all disposed and the list cleared. They are
             // all re-created the next time the IRuntime or ClrRuntime instance is queried.
-            DataTarget dataTarget = new(new CustomDataTarget(_services.GetService<IDataReader>()))
+            DataTarget dataTarget = new(new CustomDataTarget(_services.GetService<IDataReader>())
             {
+                ForceCompleteRuntimeEnumeration = (flags & RuntimeEnumerationFlags.All) != 0,
                 FileLocator = null
-            };
+            });
             for (int i = 0; i < dataTarget.ClrVersions.Length; i++)
             {
                 yield return new Runtime(_services, startingRuntimeId + i, dataTarget.ClrVersions[i]);
index ef969eb2d23bf2fd2c46ba158d7a8008dda8f821..b37c5d6f335c48d58e79b2472625492589208dd4 100644 (file)
@@ -47,7 +47,8 @@ namespace Microsoft.Diagnostics.DebugServices.Implementation
         /// <summary>
         /// Returns the list of runtimes in the target
         /// </summary>
-        public IEnumerable<IRuntime> EnumerateRuntimes()
+        /// <param name="flags">Enumeration control flags</param>
+        public IEnumerable<IRuntime> EnumerateRuntimes(RuntimeEnumerationFlags flags)
         {
             if (_runtimes is null)
             {
@@ -55,7 +56,7 @@ namespace Microsoft.Diagnostics.DebugServices.Implementation
                 foreach (ServiceFactory factory in _serviceManager.EnumerateProviderFactories(typeof(IRuntimeProvider)))
                 {
                     IRuntimeProvider provider = (IRuntimeProvider)factory(_services);
-                    _runtimes.AddRange(provider.EnumerateRuntimes(_runtimes.Count));
+                    _runtimes.AddRange(provider.EnumerateRuntimes(_runtimes.Count, flags));
                 }
             }
             return _runtimes;
index a81155d02107c952dbf6a9a66245185e32b4a658..357bb63cfe8242c24b12d9e9fad12297b2691990 100644 (file)
@@ -1,6 +1,7 @@
 // Licensed to the .NET Foundation under one or more agreements.
 // The .NET Foundation licenses this file to you under the MIT license.
 
+using System;
 using System.Collections.Generic;
 
 namespace Microsoft.Diagnostics.DebugServices
@@ -14,6 +15,7 @@ namespace Microsoft.Diagnostics.DebugServices
         /// Returns the list of runtimes in the target
         /// </summary>
         /// <param name="startingRuntimeId">The starting runtime id for this provider</param>
-        IEnumerable<IRuntime> EnumerateRuntimes(int startingRuntimeId);
+        /// <param name="flags">Enumeration control flags</param>
+        IEnumerable<IRuntime> EnumerateRuntimes(int startingRuntimeId, RuntimeEnumerationFlags flags);
     }
 }
index 4f3863996e53fdef3bc69a087e44c8867dc0ea2b..3ba22b1ed775cba5b3981ebd254ee059ca58c4a3 100644 (file)
@@ -13,6 +13,7 @@ namespace Microsoft.Diagnostics.DebugServices
         /// <summary>
         /// Returns the list of runtimes in the target
         /// </summary>
-        IEnumerable<IRuntime> EnumerateRuntimes();
+        /// <param name="flags">Enumeration control flags</param>
+        IEnumerable<IRuntime> EnumerateRuntimes(RuntimeEnumerationFlags flags = RuntimeEnumerationFlags.Default);
     }
 }
diff --git a/src/Microsoft.Diagnostics.DebugServices/RuntimeEnumerationFlags.cs b/src/Microsoft.Diagnostics.DebugServices/RuntimeEnumerationFlags.cs
new file mode 100644 (file)
index 0000000..ccf0ee5
--- /dev/null
@@ -0,0 +1,24 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System;
+
+namespace Microsoft.Diagnostics.DebugServices
+{
+    /// <summary>
+    /// Enumeration control flags
+    /// </summary>
+    [Flags]
+    public enum RuntimeEnumerationFlags
+    {
+        /// <summary>
+        /// Providers can return only the runtimes they feel are important like ones involved in a crash.
+        /// </summary>
+        Default = 0x00,
+
+        /// <summary>
+        /// Force enumeration of all runtimes.  If set, all the possible runtimes in the target process are enumerated.
+        /// </summary>
+        All = 0x01,
+    }
+}
index 1d678a23aa492938de0e8bd9cbad6947ef671b63..561214e0b6462beef55ad36aed31efafb796aab4 100644 (file)
@@ -30,16 +30,28 @@ namespace Microsoft.Diagnostics.ExtensionCommands
         [Option(Name = "--netcore", Aliases = new string[] { "-netcore", "-c" }, Help = "Switches to the .NET Core or .NET 5+ runtime if exists.")]
         public bool NetCore { get; set; }
 
+        [Option(Name = "--all", Aliases = new string[] { "-a" }, Help = "Forces all runtimes to be enumerated.")]
+        public bool All { get; set; }
+
         public override void Invoke()
         {
             if (NetFx && NetCore)
             {
                 throw new DiagnosticsException("Cannot specify both -netfx and -netcore options");
             }
+            RuntimeEnumerationFlags flags = RuntimeEnumerationFlags.Default;
+
+            if (All)
+            {
+                // Force all runtimes to be enumerated. This requires a target flush.
+                flags = RuntimeEnumerationFlags.All;
+                Target.Flush();
+            }
+
             if (NetFx || NetCore)
             {
                 string name = NetFx ? "desktop .NET Framework" : ".NET Core";
-                foreach (IRuntime runtime in RuntimeService.EnumerateRuntimes())
+                foreach (IRuntime runtime in RuntimeService.EnumerateRuntimes(flags))
                 {
                     if (NetFx && runtime.RuntimeType == RuntimeType.Desktop ||
                         NetCore && runtime.RuntimeType == RuntimeType.NetCore)
@@ -59,10 +71,10 @@ namespace Microsoft.Diagnostics.ExtensionCommands
             else
             {
                 // Display the current runtime star ("*") only if there is more than one runtime and it is the current one
-                bool displayStar = RuntimeService.EnumerateRuntimes().Count() > 1;
+                bool displayStar = RuntimeService.EnumerateRuntimes(flags).Count() > 1;
                 IRuntime currentRuntime = ContextService.GetCurrentRuntime();
 
-                foreach (IRuntime runtime in RuntimeService.EnumerateRuntimes())
+                foreach (IRuntime runtime in RuntimeService.EnumerateRuntimes(flags))
                 {
                     string current = displayStar ? (runtime == currentRuntime ? "*" : " ") : "";
                     Write(current);
index 59adf253d907a11095636724b54bd4bf94ba04cc..d5c0851fc045f4c860c0d5651fa9a8460b8b04b0 100644 (file)
@@ -21,6 +21,9 @@
     <None Include="$(ArtifactsBinDir)\Windows_NT.x64.$(Configuration)\PDB\sos.pdb" Pack="true" Visible="false">
       <PackagePath>$(SOSPackagePathPrefix)/win-x64</PackagePath>
     </None>
+  </ItemGroup>
+
+  <ItemGroup Condition="'$(BuildX64Package)' != 'true'">
     <None Include="$(ArtifactsBinDir)\Windows_NT.x86.$(Configuration)\PDB\sos.pdb" Pack="true" Visible="false">
       <PackagePath>$(SOSPackagePathPrefix)/win-x86</PackagePath>
     </None>
index 7ca956b59dfe37fbd20539da6f518e4fd3ce43ef..77556c055798c044e99578c07e27b7dc380abbea 100644 (file)
@@ -10,7 +10,9 @@
   <ItemGroup>
     <SosRequiredBinaries Include="$(ArtifactsBinDir)\Windows_NT.x64.$(Configuration)\sos.dll" TargetRid="win-x64" />
     <SosRequiredBinaries Include="$(ArtifactsBinDir)\Windows_NT.x64.$(Configuration)\Microsoft.DiaSymReader.Native.amd64.dll" TargetRid="win-x64" />
+  </ItemGroup>
       
+  <ItemGroup Condition="'$(BuildX64Package)' != 'true'">
     <SosRequiredBinaries Include="$(ArtifactsBinDir)\Windows_NT.x86.$(Configuration)\sos.dll" TargetRid="win-x86" />
     <SosRequiredBinaries Include="$(ArtifactsBinDir)\Windows_NT.x86.$(Configuration)\Microsoft.DiaSymReader.Native.x86.dll" TargetRid="win-x86" />