Add desktop CLR hosting of the SOS managed code (#1688)
authorMike McLaughlin <mikem@microsoft.com>
Sat, 31 Oct 2020 17:19:53 +0000 (10:19 -0700)
committerGitHub <noreply@github.com>
Sat, 31 Oct 2020 17:19:53 +0000 (10:19 -0700)
Add desktop CLR hosting of the SOS managed code

New !sethostruntime options "-netcore" and "-desktop".

 Update documents and code review feedback

15 files changed:
documentation/sos-debugging-extension-windows.md
documentation/sos-debugging-extension.md
src/SOS/SOS.Hosting/SOSHost.cs
src/SOS/SOS.NETCore/SymbolReader.cs
src/SOS/SOS.UnitTests/ConfigFiles/Windows/Debugger.Tests.Config.txt
src/SOS/SOS.UnitTests/Scripts/DualRuntimes.script
src/SOS/Strike/CMakeLists.txt
src/SOS/Strike/Strike.vcxproj
src/SOS/Strike/Strike.vcxproj.filters
src/SOS/Strike/hostcoreclr.cpp
src/SOS/Strike/hostdesktop.cpp [new file with mode: 0644]
src/SOS/Strike/sos.def
src/SOS/Strike/sosdocs.txt
src/SOS/Strike/sosdocsunix.txt
src/SOS/Strike/strike.cpp

index bf9e38427f46385d67b45b901ff3343971f43e17..9ff741b7d6fc7d82fd3115eafb15031b97a4670b 100644 (file)
@@ -63,7 +63,9 @@ Type `!help <functionname>` for detailed info on that function.
     HistRoot                           SetSymbolServer (setsymbolserver)
     HistObj                            FAQ
     HistObjFind                        SOSFlush
-    HistClear                          Help (soshelp)
+    HistClear                          SOSStatus (sosstatus)
+                                       FAQ
+                                       Help (soshelp)
 
 ## Commands
 
@@ -120,6 +122,8 @@ Type `!help <functionname>` for detailed info on that function.
 |**RCWCleanupList** \<*RCWCleanupList address*>|Displays the list of runtime callable wrappers at the specified address that are awaiting cleanup.|
 |**SaveModule** \<*Base address*> \<*Filename*>|Writes an image, which is loaded in memory at the specified address, to the specified file.|
 |**SOSFlush**|Flushes an internal SOS cache.|
+|**SOSStatus** [**-netfx**] [**-netcore**] [**-reset**]|Display internal SOS status, reset the internal cached state, or change between the desktop .NET framework or .NET Core runtimes when both are loaded in the process or dump.<br/><br/>-netfx   - switch to the desktop .NET Framework runtime if loaded.<br/>-netcore - switch to the .NET Core runtime if loaded.<br/>-reset   - reset all the cached internal SOS state.<br/><br/>|
+|**SetHostRuntime** [**-netcore**] [**-netfx**] [\<runtime-directory\>]|This command controls the runtime that is used to host the maanged code that runs as part of SOS in the debugger (cdb/windbg). The default is the desktop .NET Framework. The "-netcore" option allows the installed .NET Core runtime be used. The "-netfx" option allows switches back to the .NET Framework runtime.<br/><br/>Normally, SOS attempts to find an installed .NET Core runtime to run its managed code automatically but this command is available if it fails. The default is to use the same runtime (libcoreclr) being debugged. Use this command if the default runtime being debugged isn't working enough to run the SOS code or if the version is less than 2.1.0.<br/><br/>If you received the following error message when running a SOS command, use this command to set the path to 2.1.0 or greater .NET Core runtime. <br/><br/>`(lldb) clrstack`<br/>`Error: Fail to initialize CoreCLR 80004005 ClrStack failed`<br/><br/>`(lldb) sethostruntime /usr/share/dotnet/shared/Microsoft.NETCore.App/2.1.6`<br/><br/>You can use the "dotnet --info" in a command shell to find the path of an installed .NET Core runtime.|
 |**StopOnException** [**-derived**] [**-create** &#124; **-create2**] \<*Exception*> \<*Pseudo-register number*>|Causes the debugger to stop when the specified exception is thrown, but to continue running when other exceptions are thrown.<br /><br /> The **-derived** option catches the specified exception and every exception that derives from the specified exception.|
 |**SyncBlk** [**-all** &#124; \<*syncblk number*>]|Displays the specified `SyncBlock` structure or all `SyncBlock` structures.  If you do not pass any arguments, the **SyncBlk** command displays the `SyncBlock` structure corresponding to objects that are owned by a thread.<br /><br /> A `SyncBlock` structure is a container for extra information that does not need to be created for every object. It can hold COM interop data, hash codes, and locking information for thread-safe operations.|
 |**ThreadPool**|Displays information about the managed thread pool, including the number of work requests in the queue, the number of completion port threads, and the number of timers.|
index 28f1b75b1b6359f1976e945e3d996a3078f8b05b..f11d512d5cac309f5623ee1e715dc80e258ff820 100644 (file)
@@ -63,9 +63,11 @@ importance. Shortcut names for popular functions are listed in parenthesis. Type
     -----------------------------      -----------------------------
     HistInit (histinit)                SetHostRuntime (sethostruntime)
     HistRoot (histroot)                SetSymbolServer (setsymbolserver, loadsymbols)
-    HistObj  (histobj)                 FAQ
-    HistObjFind (histobjfind)          SOSFlush
-    HistClear (histclear)              Help (soshelp)
+    HistObj  (histobj)                 SetClrPath (setclrpath)
+    HistObjFind (histobjfind)          SOSFlush (sosflush)
+    HistClear (histclear)              SOSStatus (sosstatus)
+                                       FAQ
+                                       Help (soshelp)
 
 ## Commands
 
@@ -110,6 +112,8 @@ importance. Shortcut names for popular functions are listed in parenthesis. Type
 |**PrintException** [**-nested**] [**-lines**] [\<*Exception object address*>]<br /><br /> -or-<br /><br /> **PE** [**-nested**] [\<*Exception object address*>]|Displays and formats fields of any object derived from the <xref:System.Exception> class at the specified address. If you do not specify an address, the **PrintException** command displays the last exception thrown on the current thread.<br /><br /> The **-nested** option displays details about nested exception objects.<br /><br /> The **-lines** option displays source information, if available.<br /><br /> You can use this command to format and view the `_stackTrace` field, which is a binary array.|
 |**SyncBlk** [**-all** &#124; \<*syncblk number*>]|Displays the specified `SyncBlock` structure or all `SyncBlock` structures.  If you do not pass any arguments, the **SyncBlk** command displays the `SyncBlock` structure corresponding to objects that are owned by a thread.<br /><br /> A `SyncBlock` structure is a container for extra information that does not need to be created for every object. It can hold COM interop data, hash codes, and locking information for thread-safe operations.|
 |**SOSFlush**|Flushes an internal SOS cache.|
+|**SOSStatus** [**-reset**]|Displays internal SOS status or reset the internal cached state.|
+|**SetHostRuntime** [\<runtime-directory\>]|This command sets the path to the .NET Core runtime to use to host the managed code that runs as part of SOS in the debugger (lldb). The runtime needs to be at least version 2.1.0 or greater. If there are spaces in directory, it needs to be single-quoted (').<br/><br/>Normally, SOS attempts to find an installed .NET Core runtime to run its managed code automatically but this command is available if it fails. The default is to use the same runtime (libcoreclr) being debugged. Use this command if the default runtime being debugged isn't working enough to run the SOS code or if the version is less than 2.1.0.<br/><br/>If you received the following error message when running a SOS command, use this command to set the path to 2.1.0 or greater .NET Core runtime. <br/><br/>`(lldb) clrstack`<br/>`Error: Fail to initialize CoreCLR 80004005 ClrStack failed`<br/><br/>`(lldb) sethostruntime /usr/share/dotnet/shared/Microsoft.NETCore.App/2.1.6`<br/><br/>You can use the "dotnet --info" in a command shell to find the path of an installed .NET Core runtime.|
 |**SetSymbolServer** [**-ms**] [**-disable**] [**-log**] [**-loadsymbols**] [**-cache** \<cache-path>] [**-directory** \<search-directory>] [**-sympath** \<windows-symbol-path>] [\<symbol-server-URL>]|Enables the symbol server downloading support.<br/><br/>The **-ms** option enables downloading from the public Microsoft symbol server.<br/><br/>The **-disable** option turns on the symbol download support.<br/><br/>The **-cache** \<cache-path> option specifies a symbol cache directory. The default is $HOME/.dotnet/symbolcache if not specified.<br/><br/>The **-directory** option add a path to search for symbols. Can be more than one.<br/><br/>The **-sympath** option adds server, cache and directory paths in the Windows symbol path format.<br/><br/>The **-log** option enables symbol download logging.<br/><br/>The **-loadsymbols** option attempts to download the native .NET Core symbols for the runtime.|
 |**Token2EE** \<*module name*> \<*token*>|Turns the specified metadata token in the specified module into a `MethodTable` structure or `MethodDesc` structure.<br /><br /> You can pass `*` for the module name parameter to find what that token maps to in every loaded managed module. You can also pass the debugger's name for a module, such as `mscorlib` or `image00400000`.|
 |**Threads** (**clrthreads**) [**-live**] [**-special**]|Displays all managed threads in the process.<br /><br /> The **Threads** command displays the debugger shorthand ID, the CLR thread ID, and the operating system thread ID.  Additionally, the **Threads** command displays a Domain column that indicates the application domain in which a thread is executing, an APT column that displays the COM apartment mode, and an Exception column that displays the last exception thrown in the thread.<br /><br /> The **-live** option displays threads associated with a live thread.<br /><br /> The **-special** option displays all special threads created by the CLR. Special threads include garbage collection threads (in concurrent and server garbage collection), debugger helper threads, finalizer threads, <xref:System.AppDomain> unload threads, and thread pool timer threads.|
index 2563dadf39ce1d77b06e930c466215d77d08fcf0..82dfe3e4dbe9f71ce753f37b70ad62c855e85713 100644 (file)
@@ -29,7 +29,7 @@ namespace SOS
 
         [UnmanagedFunctionPointer(CallingConvention.Winapi)]
         private delegate int SOSInitializeDelegate(
-            [In, MarshalAs(UnmanagedType.Struct)] ref SOSNetCoreCallbacks callbacks,
+            [In, MarshalAs(UnmanagedType.Struct)] ref SymbolReader.SOSNetCoreCallbacks callbacks,
             int callbacksSize,
             [In, MarshalAs(UnmanagedType.LPStr)] string tempDirectory,
             [In, MarshalAs(UnmanagedType.LPStr)] string runtimeModulePath,
@@ -38,138 +38,8 @@ namespace SOS
             [In, MarshalAs(UnmanagedType.LPStr)] string dbiFilePath,
             bool symbolStoreEnabled);
 
-        [UnmanagedFunctionPointer(CallingConvention.Winapi)]
-        private delegate UIntPtr GetExpressionDelegate(
-            [In, MarshalAs(UnmanagedType.LPStr)] string expression);
-
         private const string SOSInitialize = "SOSInitializeByHost";
 
-        #region SOS.NETCore function delegates
-
-        private delegate bool InitializeSymbolStoreDelegate(
-            bool logging,
-            bool msdl,
-            bool symweb,
-            string tempDirectory,
-            string symbolServerPath,
-            string authToken,
-            int timeoutInMintues,
-            string symbolCachePath,
-            string symbolDirectoryPath,
-            string windowsSymbolPath);
-
-        private delegate void DisplaySymbolStoreDelegate(
-            SymbolReader.WriteLine writeLine);
-
-        private delegate void DisableSymbolStoreDelegate();
-
-        private delegate void LoadNativeSymbolsDelegate(
-            SymbolReader.SymbolFileCallback callback,
-            IntPtr parameter,
-            SymbolReader.RuntimeConfiguration config,
-            string moduleFilePath,
-            ulong address,
-            int size,
-            SymbolReader.ReadMemoryDelegate readMemory);
-
-        private delegate void LoadNativeSymbolsFromIndexDelegate(
-            SymbolReader.SymbolFileCallback callback,
-            IntPtr parameter,
-            SymbolReader.RuntimeConfiguration config,
-            string moduleFilePath,
-            bool specialKeys,
-            int moduleIndexSize,
-            IntPtr moduleIndex);
-
-        private delegate IntPtr LoadSymbolsForModuleDelegate(
-            string assemblyPath,
-            bool isFileLayout,
-            ulong loadedPeAddress,
-            int loadedPeSize,
-            ulong inMemoryPdbAddress,
-            int inMemoryPdbSize,
-            SymbolReader.ReadMemoryDelegate readMemory);
-
-        private delegate void DisposeDelegate(IntPtr symbolReaderHandle);
-
-        private delegate bool ResolveSequencePointDelegate(
-            IntPtr symbolReaderHandle,
-            string filePath,
-            int lineNumber,
-            out int methodToken,
-            out int ilOffset);
-
-        private delegate bool GetLineByILOffsetDelegate(
-            IntPtr symbolReaderHandle,
-            int methodToken,
-            long ilOffset,
-            out int lineNumber,
-            out IntPtr fileName);
-
-        private delegate bool GetLocalVariableNameDelegate(
-            IntPtr symbolReaderHandle,
-            int methodToken,
-            int localIndex,
-            out IntPtr localVarName);
-
-        private delegate int GetMetadataLocatorDelegate(
-            [MarshalAs(UnmanagedType.LPWStr)] string imagePath,
-            uint imageTimestamp,
-            uint imageSize,
-            [MarshalAs(UnmanagedType.LPArray, SizeConst = 16)] byte[] mvid,
-            uint mdRva,
-            uint flags,
-            uint bufferSize,
-            IntPtr buffer,
-            IntPtr dataSize);
-
-        private delegate int GetICorDebugMetadataLocatorDelegate(
-            [MarshalAs(UnmanagedType.LPWStr)] string imagePath,
-            uint imageTimestamp,
-            uint imageSize,
-            uint pathBufferSize,
-            IntPtr pPathBufferSize,
-            IntPtr pPathBuffer);
-
-        #endregion
-
-        /// <summary>
-        /// Pass to SOSInitializeByHost
-        /// </summary>
-        [StructLayout(LayoutKind.Sequential)]
-        struct SOSNetCoreCallbacks
-        {
-            public InitializeSymbolStoreDelegate InitializeSymbolStoreDelegate;
-            public DisplaySymbolStoreDelegate DisplaySymbolStoreDelegate;
-            public DisableSymbolStoreDelegate DisableSymbolStoreDelegate;
-            public LoadNativeSymbolsDelegate LoadNativeSymbolsDelegate;
-            public LoadNativeSymbolsFromIndexDelegate LoadNativeSymbolsFromIndexDelegate;
-            public LoadSymbolsForModuleDelegate LoadSymbolsForModuleDelegate;
-            public DisposeDelegate DisposeDelegate;
-            public ResolveSequencePointDelegate ResolveSequencePointDelegate;
-            public GetLineByILOffsetDelegate GetLineByILOffsetDelegate;
-            public GetLocalVariableNameDelegate GetLocalVariableNameDelegate;
-            public GetMetadataLocatorDelegate GetMetadataLocatorDelegate;
-            public GetExpressionDelegate GetExpressionDelegate;
-            public GetICorDebugMetadataLocatorDelegate GetICorDebugMetadataLocatorDelegate;
-        }
-
-        static SOSNetCoreCallbacks s_callbacks = new SOSNetCoreCallbacks {
-            InitializeSymbolStoreDelegate = SymbolReader.InitializeSymbolStore,
-            DisplaySymbolStoreDelegate = SymbolReader.DisplaySymbolStore,
-            DisableSymbolStoreDelegate = SymbolReader.DisableSymbolStore,
-            LoadNativeSymbolsDelegate = SymbolReader.LoadNativeSymbols,
-            LoadNativeSymbolsFromIndexDelegate = SymbolReader.LoadNativeSymbolsFromIndex,
-            LoadSymbolsForModuleDelegate = SymbolReader.LoadSymbolsForModule,
-            DisposeDelegate = SymbolReader.Dispose,
-            ResolveSequencePointDelegate = SymbolReader.ResolveSequencePoint,
-            GetLineByILOffsetDelegate = SymbolReader.GetLineByILOffset,
-            GetLocalVariableNameDelegate = SymbolReader.GetLocalVariableName,
-            GetMetadataLocatorDelegate = MetadataHelper.GetMetadataLocator,
-            GetExpressionDelegate = SOSHost.GetExpression,
-            GetICorDebugMetadataLocatorDelegate = MetadataHelper.GetICorDebugMetadataLocator
-        };
-
         const string DesktopRuntimeModuleName = "clr";
 
         internal readonly IDataReader DataReader;
@@ -285,8 +155,8 @@ namespace SOS
                 }
 
                 int result = initializeFunc(
-                    ref s_callbacks,
-                    Marshal.SizeOf<SOSNetCoreCallbacks>(),
+                    ref SymbolReader.SymbolCallbacks,
+                    Marshal.SizeOf<SymbolReader.SOSNetCoreCallbacks>(),
                     tempDirectory,
                     AnalyzeContext.RuntimeModuleDirectory,
                     isDesktop,
index 298a52a7cbb5f0ede2de63ab130f81f1df9cf7a5..7eee4d57af179238e451cb4953be45039282ef53 100644 (file)
@@ -12,6 +12,7 @@ using Microsoft.SymbolStore.SymbolStores;
 using System;
 using System.Collections.Generic;
 using System.Diagnostics;
+using System.Globalization;
 using System.IO;
 using System.Linq;
 using System.Reflection.Metadata;
@@ -154,6 +155,9 @@ namespace SOS
         const string MsdlSymbolServer = "http://msdl.microsoft.com/download/symbols/";
         const string SymwebSymbolServer = "http://symweb.corp.microsoft.com/";
 
+        [DllImport("sos.dll")]
+        private static extern int InitializeBySymbolReader([In, MarshalAs(UnmanagedType.Struct)] ref SOSNetCoreCallbacks callbacks, int callbacksSize);
+
         /// <summary>
         /// Read memory callback
         /// </summary>
@@ -173,6 +177,137 @@ namespace SOS
         /// <param name="symbolFileName">symbol file name and path</param>
         public delegate void SymbolFileCallback(IntPtr parameter, [MarshalAs(UnmanagedType.LPStr)] string moduleFileName, [MarshalAs(UnmanagedType.LPStr)] string symbolFileName);
 
+        #region SOS.NETCore function delegates
+
+        public delegate bool InitializeSymbolStoreDelegate(
+            bool logging,
+            bool msdl,
+            bool symweb,
+            string tempDirectory,
+            string symbolServerPath,
+            string authToken,
+            int timeoutInMintues,
+            string symbolCachePath,
+            string symbolDirectoryPath,
+            string windowsSymbolPath);
+
+        public delegate void DisplaySymbolStoreDelegate(
+            SymbolReader.WriteLine writeLine);
+
+        public delegate void DisableSymbolStoreDelegate();
+
+        public delegate void LoadNativeSymbolsDelegate(
+            SymbolReader.SymbolFileCallback callback,
+            IntPtr parameter,
+            SymbolReader.RuntimeConfiguration config,
+            string moduleFilePath,
+            ulong address,
+            int size,
+            SymbolReader.ReadMemoryDelegate readMemory);
+
+        public delegate void LoadNativeSymbolsFromIndexDelegate(
+            SymbolReader.SymbolFileCallback callback,
+            IntPtr parameter,
+            SymbolReader.RuntimeConfiguration config,
+            string moduleFilePath,
+            bool specialKeys,
+            int moduleIndexSize,
+            IntPtr moduleIndex);
+
+        public delegate IntPtr LoadSymbolsForModuleDelegate(
+            string assemblyPath,
+            bool isFileLayout,
+            ulong loadedPeAddress,
+            int loadedPeSize,
+            ulong inMemoryPdbAddress,
+            int inMemoryPdbSize,
+            SymbolReader.ReadMemoryDelegate readMemory);
+
+        public delegate void DisposeDelegate(
+            IntPtr symbolReaderHandle);
+
+        public delegate bool ResolveSequencePointDelegate(
+            IntPtr symbolReaderHandle,
+            string filePath,
+            int lineNumber,
+            out int methodToken,
+            out int ilOffset);
+
+        public delegate bool GetLineByILOffsetDelegate(
+            IntPtr symbolReaderHandle,
+            int methodToken,
+            long ilOffset,
+            out int lineNumber,
+            out IntPtr fileName);
+
+        public delegate bool GetLocalVariableNameDelegate(
+            IntPtr symbolReaderHandle,
+            int methodToken,
+            int localIndex,
+            out IntPtr localVarName);
+
+        [UnmanagedFunctionPointer(CallingConvention.Winapi)]
+        public delegate UIntPtr GetExpressionDelegate(
+            [In, MarshalAs(UnmanagedType.LPStr)] string expression);
+
+        public delegate int GetMetadataLocatorDelegate(
+            [MarshalAs(UnmanagedType.LPWStr)] string imagePath,
+            uint imageTimestamp,
+            uint imageSize,
+            [MarshalAs(UnmanagedType.LPArray, SizeConst = 16)] byte[] mvid,
+            uint mdRva,
+            uint flags,
+            uint bufferSize,
+            IntPtr buffer,
+            IntPtr dataSize);
+
+        public delegate int GetICorDebugMetadataLocatorDelegate(
+            [MarshalAs(UnmanagedType.LPWStr)] string imagePath,
+            uint imageTimestamp,
+            uint imageSize,
+            uint pathBufferSize,
+            IntPtr pPathBufferSize,
+            IntPtr pPathBuffer);
+
+        #endregion
+
+        /// <summary>
+        /// Symbol service callback table
+        /// </summary>
+        [StructLayout(LayoutKind.Sequential)]
+        public struct SOSNetCoreCallbacks
+        {
+            public InitializeSymbolStoreDelegate InitializeSymbolStoreDelegate;
+            public DisplaySymbolStoreDelegate DisplaySymbolStoreDelegate;
+            public DisableSymbolStoreDelegate DisableSymbolStoreDelegate;
+            public LoadNativeSymbolsDelegate LoadNativeSymbolsDelegate;
+            public LoadNativeSymbolsFromIndexDelegate LoadNativeSymbolsFromIndexDelegate;
+            public LoadSymbolsForModuleDelegate LoadSymbolsForModuleDelegate;
+            public DisposeDelegate DisposeDelegate;
+            public ResolveSequencePointDelegate ResolveSequencePointDelegate;
+            public GetLineByILOffsetDelegate GetLineByILOffsetDelegate;
+            public GetLocalVariableNameDelegate GetLocalVariableNameDelegate;
+            public GetMetadataLocatorDelegate GetMetadataLocatorDelegate;
+            public GetExpressionDelegate GetExpressionDelegate;
+            public GetICorDebugMetadataLocatorDelegate GetICorDebugMetadataLocatorDelegate;
+        }
+
+        public static SOSNetCoreCallbacks SymbolCallbacks = new SOSNetCoreCallbacks {
+            InitializeSymbolStoreDelegate = SymbolReader.InitializeSymbolStore,
+            DisplaySymbolStoreDelegate = SymbolReader.DisplaySymbolStore,
+            DisableSymbolStoreDelegate = SymbolReader.DisableSymbolStore,
+            LoadNativeSymbolsDelegate = SymbolReader.LoadNativeSymbols,
+            LoadNativeSymbolsFromIndexDelegate = SymbolReader.LoadNativeSymbolsFromIndex,
+            LoadSymbolsForModuleDelegate = SymbolReader.LoadSymbolsForModule,
+            DisposeDelegate = SymbolReader.Dispose,
+            ResolveSequencePointDelegate = SymbolReader.ResolveSequencePoint,
+            GetLineByILOffsetDelegate = SymbolReader.GetLineByILOffset,
+            GetLocalVariableNameDelegate = SymbolReader.GetLocalVariableName,
+            GetMetadataLocatorDelegate = MetadataHelper.GetMetadataLocator,
+            GetExpressionDelegate = SymbolReader.GetExpression,
+            GetICorDebugMetadataLocatorDelegate = MetadataHelper.GetICorDebugMetadataLocator
+        };
+
         /// <summary>
         /// Temporary directory for dac/symbols
         /// </summary>
@@ -181,6 +316,16 @@ namespace SOS
         static readonly ITracer s_tracer = new Tracer();
         static SymbolStore s_symbolStore = null;
 
+        /// <summary>
+        /// Entry point from the desktop hosting code.
+        /// </summary>
+        /// <param name="argument">SOS module path</param>
+        /// <returns>0 success, !0 failure</returns>
+        public static int InitializeSymbolReader(string argument)
+        {
+            return InitializeBySymbolReader(ref SymbolCallbacks, Marshal.SizeOf<SymbolReader.SOSNetCoreCallbacks>());
+        }
+
         /// <summary>
         /// Initializes symbol loading. Adds the symbol server and/or the cache path (if not null) to the list of
         /// symbol servers. This API can be called more than once to add more servers to search.
@@ -534,6 +679,24 @@ namespace SOS
             }
         }
 
+        /// <summary>
+        /// Get expression helper for native SOS.
+        /// </summary>
+        /// <param name="expression">hex number</param>
+        /// <returns>value</returns>
+        public static UIntPtr GetExpression(
+            string expression)
+        {
+            if (expression != null)
+            {
+                if (ulong.TryParse(expression.Replace("0x", ""), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out ulong result))
+                {
+                    return new UIntPtr(result);
+                }
+            }
+            return UIntPtr.Zero;
+        }
+
         /// <summary>
         /// Returns method token and IL offset for given source line number.
         /// </summary>
index 886f7ff8f5a5b72a75893598d7ca08a576f8fd49..abf457ba734393d1a6d31a81c9cdddbaca1320ba 100644 (file)
           <BuildProjectFramework>netcoreapp2.1</BuildProjectFramework>
           <RuntimeFrameworkVersion>$(RuntimeVersion21)</RuntimeFrameworkVersion>
           <FrameworkVersion>$(AspNetCoreVersion21)</FrameworkVersion>
+          <!-- Do at least one test hosted on .NET Core. -->
+          <SOSHostRuntime>$(DotNetRoot)\shared\Microsoft.NETCore.App\$(RuntimeVersion21)</SOSHostRuntime>
         </Option>
         <!--
             SOS.WebApp3 and SOS.DualRuntimes (runs on 3.1 and latest aspnetcore)
 
       <FrameworkVersion Condition="'$(FrameworkVersion)' == ''">$(RuntimeFrameworkVersion)</FrameworkVersion>
       <RuntimeSymbolsPath>$(DotNetRoot)\shared\Microsoft.NETCore.App\$(RuntimeFrameworkVersion)</RuntimeSymbolsPath>
-      <SOSHostRuntime>$(DotNetRoot)\shared\Microsoft.NETCore.App\$(RuntimeFrameworkVersion)</SOSHostRuntime>
       <HostExe>$(DotNetRoot)\dotnet.exe</HostExe>
       <HostArgs>--fx-version $(FrameworkVersion)</HostArgs>
     </Option>
       <BuildProjectRuntime>win-$(TargetArchitecture)</BuildProjectRuntime>
       <DebugType>full</DebugType>
       <RuntimeSymbolsPath>$(DesktopFrameworkPath)</RuntimeSymbolsPath>
-      <SOSHostRuntime>$(DotNetRoot)\shared\Microsoft.NETCore.App\$(RuntimeVersion21)</SOSHostRuntime>
     </Option>
   </Options>
 
index 32368122f2d04a1913d6f5cbd36873e6a0e10a0b..a9448432d2f511d702c984aff41de8cb98185aa8 100644 (file)
@@ -75,7 +75,7 @@ IFDEF:TRIAGE_DUMP
 SOSCOMMAND:setclrpath %DESKTOP_RUNTIME_PATH%
 ENDIF:TRIAGE_DUMP
 
-SOSCOMMAND:SOSStatus -desktop
+SOSCOMMAND:SOSStatus -netfx
 VERIFY:\s*Switched to desktop CLR runtime successfully\s+
 
 # Currently not on a desktop CLR thread so using the -all option to dump it.
@@ -102,4 +102,4 @@ VERIFY:\s*Statistics:\s+
 VERIFY:\s+MT\s+Count\s+TotalSize\s+Class Name\s+
 VERIFY:\s*<HEXVAL>\s+<DECVAL>\s+<DECVAL>\s+.*
 VERIFY:\s*Total\s+<DECVAL>\s+objects\s+
-!VERIFY:.*UNKNOWN.*
\ No newline at end of file
+!VERIFY:.*UNKNOWN.*
index af1820d0cc9a0a541e0f8bcf80dda5481e4ef800..63db0173bd5163622ef73142bec3dce9e24dac18 100644 (file)
@@ -73,6 +73,7 @@ if(WIN32)
     gchist.cpp
     gcroot.cpp
     hostcoreclr.cpp
+    hostdesktop.cpp
     metadata.cpp
     runtime.cpp
     sigparser.cpp
@@ -110,6 +111,7 @@ if(WIN32)
     advapi32.lib
     psapi.lib
     ntdll.lib
+    mscoree.lib
   )
 else(WIN32)
   add_definitions(-DFEATURE_ENABLE_HARDWARE_EXCEPTIONS)
index 510008f66cb19f1c92364828866470c26fbb8cd0..ab8b69636828d0362ea4c0c17a60612efff21484 100644 (file)
     <ClCompile Include="exts.cpp" />
     <ClCompile Include="gchist.cpp" />
     <ClCompile Include="gcroot.cpp" />
+    <ClCompile Include="hostdesktop.cpp" />
     <ClCompile Include="metadata.cpp" />
     <ClCompile Include="runtime.cpp" />
     <ClCompile Include="sildasm.cpp" />
index 1f4f91078e44b4b860bdc322cb33a215f48250ca..0b1f0e7aa13e27cb8a05243c86addda8a711539f 100644 (file)
@@ -22,6 +22,7 @@
     <ClCompile Include="disasmARM64.cpp" />
     <ClCompile Include="hostcoreclr.cpp" />
     <ClCompile Include="runtime.cpp" />
+    <ClCompile Include="hostdesktop.cpp" />
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="data.h" />
index ac351a92a68c008cd3f27aed815daac421fe89de..c3f3fd0e85dfeaf412ae86c6296f910e192ada8d 100644 (file)
 #define IfFailRet(EXPR) do { Status = (EXPR); if(FAILED(Status)) { return (Status); } } while (0)
 #endif
 
+#ifdef FEATURE_PAL
+#define TPALIST_SEPARATOR_STR_A ":"
+#else
+#define TPALIST_SEPARATOR_STR_A ";"
+#endif
+
+#ifndef FEATURE_PAL
+extern HRESULT InitializeDesktopClrHost();
+extern void UninitializeDesktopClrHost();
+#endif
+
 bool g_dotnetDumpHost = false;
 static bool g_hostingInitialized = false;
 bool g_symbolStoreInitialized = false;
 LPCSTR g_hostRuntimeDirectory = nullptr;
 LPCSTR g_tmpPath = nullptr;
 SOSNetCoreCallbacks g_SOSNetCoreCallbacks;
+
 #ifndef FEATURE_PAL
+bool g_useDesktopClrHost = true;
 HMODULE g_hmoduleSymBinder = nullptr;
 ISymUnmanagedBinder3 *g_pSymBinder = nullptr;
 #endif
-
-#ifdef FEATURE_PAL
-#define TPALIST_SEPARATOR_STR_A ":"
-#else
-#define TPALIST_SEPARATOR_STR_A ";"
-#endif
-
 //
 // Build the TPA list of assemblies for the runtime hosting api.
 //
@@ -456,6 +462,24 @@ void CleanupTempDirectory()
     }
 }
 
+#ifndef FEATURE_PAL
+
+/**********************************************************************\
+ * Called when the desktop clr is initialized on Windows
+\**********************************************************************/
+extern "C" HRESULT InitializeBySymbolReader(
+    SOSNetCoreCallbacks * callbacks,
+    int callbacksSize)
+{
+    if (memcpy_s(&g_SOSNetCoreCallbacks, sizeof(g_SOSNetCoreCallbacks), callbacks, callbacksSize) != 0)
+    {
+        return E_INVALIDARG;
+    }
+    return S_OK;
+}
+
+#endif
+
 /**********************************************************************\
  * Called when the managed SOS Host loads/initializes SOS.
 \**********************************************************************/
@@ -511,13 +535,26 @@ HRESULT InitializeHosting()
     {
         return S_OK;
     }
+    HRESULT Status;
+#ifndef FEATURE_PAL
+    if (g_useDesktopClrHost)
+    {
+        Status = InitializeDesktopClrHost();
+        if (SUCCEEDED(Status))
+        {
+            OnUnloadTask::Register(UninitializeDesktopClrHost);
+            g_hostingInitialized = true;
+            return Status;
+        }
+    }
+#endif
     coreclr_initialize_ptr initializeCoreCLR = nullptr;
     coreclr_create_delegate_ptr createDelegate = nullptr;
     std::string hostRuntimeDirectory;
     std::string sosModuleDirectory;
     std::string coreClrPath;
 
-    HRESULT Status = GetHostRuntime(coreClrPath, hostRuntimeDirectory);
+    Status = GetHostRuntime(coreClrPath, hostRuntimeDirectory);
     if (FAILED(Status))
     {
         ExtDbgOut("Error: Failed to get host runtime directory\n");
diff --git a/src/SOS/Strike/hostdesktop.cpp b/src/SOS/Strike/hostdesktop.cpp
new file mode 100644 (file)
index 0000000..61e5760
--- /dev/null
@@ -0,0 +1,125 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+// Windows Header Files
+#include <windows.h>
+#include <stdio.h>
+#include <metahost.h>
+#include <objbase.h>
+#include <mscoree.h>
+#include <tchar.h>
+#include <strsafe.h>
+#include <string>
+#include <holder.h>
+#include <arrayholder.h>
+
+#define CLR_VERSION     L"v4.0.30319"
+#define ASSEMBLY_NAME   L"SOS.NETCore.dll"
+#define CLASS_NAME      L"SOS.SymbolReader"
+#define FUNCTION_NAME   L"InitializeSymbolReader"
+
+extern HMODULE g_hInstance;
+extern void ExtErr(PCSTR Format, ...);
+
+void UninitializeDesktopClrHost();
+
+ICLRRuntimeHost* g_clrHost = nullptr;
+
+/// <summary>
+/// Loads and initializes the desktop CLR to host the SOS.NetCore.dll code.
+/// </summary>
+HRESULT InitializeDesktopClrHost()
+{
+    HRESULT hr = S_OK;
+    DWORD ret = 0;
+
+    if (g_clrHost != nullptr)
+    {
+        return S_OK;
+    }
+    ArrayHolder<WCHAR> wszSOSModulePath = new WCHAR[MAX_LONGPATH + 1];
+    if (GetModuleFileNameW(g_hInstance, wszSOSModulePath, MAX_LONGPATH) == 0)
+    {
+        ExtErr("Error: Failed to get SOS module directory\n");
+        return HRESULT_FROM_WIN32(GetLastError());
+    }
+    ArrayHolder<WCHAR> wszManagedModulePath = new WCHAR[MAX_LONGPATH + 1];
+    if (wcscpy_s(wszManagedModulePath.GetPtr(), MAX_LONGPATH, wszSOSModulePath.GetPtr()) != 0)
+    {
+        ExtErr("Error: Failed to copy module name\n");
+        return E_FAIL;
+    }
+    WCHAR* lastSlash = wcsrchr(wszManagedModulePath.GetPtr(), DIRECTORY_SEPARATOR_CHAR_W);
+    if (lastSlash != nullptr)
+    {
+        *++lastSlash = L'\0';
+    }
+    if (wcscat_s(wszManagedModulePath.GetPtr(), MAX_LONGPATH, ASSEMBLY_NAME) != 0)
+    {
+        ExtErr("Error: Failed to append SOS module name\n");
+        return E_FAIL;
+    }
+    hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
+    if (FAILED(hr) && hr != RPC_E_CHANGED_MODE)
+    {
+        ExtErr("Error: CoInitializeEx failed. %08x\n", hr);
+        return hr;
+    }
+    // Loads the CLR and then initializes the managed debugger extensions.
+    ReleaseHolder<ICLRMetaHost> metaHost;
+    hr = CLRCreateInstance(CLSID_CLRMetaHost, IID_ICLRMetaHost, (PVOID*)&metaHost);
+    if (FAILED(hr) || metaHost == nullptr)
+    {
+        ExtErr("Error: CLRCreateInstance failed %08x\n", hr);
+        return hr;
+    }
+    ReleaseHolder<ICLRRuntimeInfo> runtimeInfo;
+    hr = metaHost->GetRuntime(CLR_VERSION, IID_ICLRRuntimeInfo, (PVOID*)&runtimeInfo);
+    if (FAILED(hr) || runtimeInfo == nullptr)
+    {
+        ExtErr("Error: ICLRMetaHost::GetRuntime failed %08x\n", hr);
+        return hr;
+    }
+    hr = runtimeInfo->GetInterface(CLSID_CLRRuntimeHost, IID_ICLRRuntimeHost, (PVOID*)&g_clrHost);
+    if (FAILED(hr) || g_clrHost == nullptr)
+    {
+        ExtErr("Error: ICLRRuntimeInfo::GetInterface failed %08x\n", hr);
+        return hr;
+    }
+    hr = g_clrHost->Start();
+    if (FAILED(hr)) 
+    {
+        ExtErr("Error: ICLRRuntimeHost::Start failed %08x\n", hr);
+        UninitializeDesktopClrHost();
+        return hr;
+    }
+    // Initialize the managed code
+    hr = g_clrHost->ExecuteInDefaultAppDomain(wszManagedModulePath.GetPtr(), CLASS_NAME, FUNCTION_NAME, wszSOSModulePath.GetPtr(), (DWORD *)&ret);
+    if (FAILED(hr)) 
+    {
+        ExtErr("Error: ICLRRuntimeHost::ExecuteInDefaultAppDomain failed %08x\n", hr);
+        UninitializeDesktopClrHost();
+        return hr;
+    }
+    if (ret != 0)
+    { 
+        ExtErr("Error: InitializeSymbolReader failed %08x\n", ret);
+        UninitializeDesktopClrHost();
+        return ret;
+    }
+    return S_OK;
+}
+
+/// <summary>
+/// Uninitializes and unloads the desktop CLR
+/// </summary>
+void UninitializeDesktopClrHost()
+{
+    if (g_clrHost != nullptr)
+    {
+        g_clrHost->Stop();
+        g_clrHost->Release();
+        g_clrHost = nullptr;
+    }
+}
index edf8a8ba1c7361b49520cc0fff65f4ca99178979..07ce5c3bb3e3bc229e6544c2d69eb4f8a8de1b3b 100644 (file)
@@ -242,3 +242,4 @@ EXPORTS
 #endif
 
     SOSInitializeByHost
+    InitializeBySymbolReader
index 99d49ac8b122077129cadf47693017845181640d..20c3ca5b511941443744f748217c3af7fe3a5947 100644 (file)
@@ -2621,18 +2621,25 @@ investigating lifetime issues of interop-heavy applications.
 \\
 
 COMMAND: sethostruntime.
-!SetHostRuntime <runtime-directory>
+!SetHostRuntime [-netcore] [-netfx] <runtime-directory>
 
-This command sets the path to the .NET Core runtime to use to host the managed
-code that runs as part of SOS in the debugger (cdb/windbg). The runtime needs
-to be at least version 2.0.0 or greater. If there are spaces in directory, it
-needs to be single-quoted (').
+-netcore - switch to hosting on the .NET Core runtime
+-netfx   - switch to hosting on the desktop .NET Framework runtime if loaded.
+
+This command controls the runtime that is used to host the maanged code that
+runs as part of SOS in the debugger (cdb/windbg). The default is the desktop
+.NET Framework. The "-netcore" option allows the installed .NET Core runtime
+be used. The "-netfx" option allows switches back to the .NET Framework runtime. 
+
+If a <runtime-directory> is given, the command assumes it is a path to a .NET 
+Core runtime which needs to be at least version 2.1.0 or greater. If there are 
+spaces in directory, it needs to be single-quoted (').
 
 Normally, SOS attempts to find an installed .NET Core runtime to run its
 managed code automatically but this command is available if it fails. The
 default is to use the same runtime (coreclr.dll) being debugged. Use this
 command if the default runtime being debugged isn't working enough to run
-the SOS code or if the version is less than 2.0.0.
+the SOS code or if the version is less than 2.1.0.
 
 If you received the following error message when running a SOS command, use
 this command to set the path to 2.0.0 or greater .NET Core runtime.
@@ -2668,14 +2675,14 @@ To disable downloading or clear the current SOS symbol settings allowing new sym
 \\
 
 COMMAND: sosstatus.
-!SOSStatus [-desktop] [-netcore] [-reset]
+!SOSStatus [-netfx] [-netcore] [-reset]
 
--desktop - switch to the desktop runtime if loaded.
+-netfx   - switch to the desktop .NET Framework runtime if loaded.
 -netcore - switch to the .NET Core runtime if loaded.
--reset      - reset all the cached internal SOS state.
+-reset   - reset all the cached internal SOS state.
 
-Display internal SOS status, reset the internal cached state, or change between desktop or 
-netcore runtimes when both are loaded in the process or dump.
+Display internal SOS status, reset the internal cached state, or change between the desktop .NET framework
+or .NET Core runtimes when both are loaded in the process or dump.
 
     0:000> !sosstatus
     Target platform: 8664 Context size 04d0
index 196e1c5556a392ce3e11b8790e074de93e3c7513..740189371d604a1a8d4405dd6d9daf1441d4d46a 100644 (file)
@@ -1911,17 +1911,17 @@ SetHostRuntime <runtime-directory>
 
 This command sets the path to the .NET Core runtime to use to host the managed 
 code that runs as part of SOS in the debugger (lldb). The runtime needs
-to be at least version 2.0.0 or greater. If there are spaces in directory, it
+to be at least version 2.1.0 or greater. If there are spaces in directory, it
 needs to be single-quoted (').
 
 Normally, SOS attempts to find an installed .NET Core runtime to run its
 managed code automatically but this command is available if it fails. The
 default is to use the same runtime (libcoreclr) being debugged. Use this
 command if the default runtime being debugged isn't working enough to run
-the SOS code or if the version is less than 2.0.0.
+the SOS code or if the version is less than 2.1.0.
 
 If you received the following error message when running a SOS command, use
-this command to set the path to 2.0.0 or greater .NET Core runtime.
+this command to set the path to 2.1.0 or greater .NET Core runtime.
 
     (lldb) clrstack
     Error: Fail to initialize CoreCLR 80004005
index a0f518ad0d418f2b99c9bf612a0c0e37afcb06e9..1a52758ae2db1488f110f749a6ec8dff0f5df813 100644 (file)
@@ -158,6 +158,7 @@ BOOL ControlC = FALSE;
 WCHAR g_mdName[mdNameLen];
 
 #ifndef FEATURE_PAL
+extern bool g_useDesktopClrHost;
 HMODULE g_hInstance = NULL;
 #endif // !FEATURE_PAL
 
@@ -10931,7 +10932,7 @@ DECLARE_API(SOSStatus)
     CMDOption option[] =
     {   // name, vptr, type, hasValue
 #ifndef FEATURE_PAL
-        {"-desktop", &bDesktop, COBOOL, FALSE},
+        {"-netfx", &bDesktop, COBOOL, FALSE},
         {"-netcore", &bNetCore, COBOOL, FALSE},
 #endif
         {"-reset", &bReset, COBOOL, FALSE},
@@ -10956,7 +10957,7 @@ DECLARE_API(SOSStatus)
         }
         else
         {
-            ExtErr("The '-desktop' and '-netcore' options are only supported on Windows targets\n");
+            ExtErr("The '-netfx' and '-netcore' options are only supported on Windows targets\n");
             return E_FAIL;
         }
     }
@@ -10980,6 +10981,12 @@ DECLARE_API(SOSStatus)
     if (g_tmpPath != nullptr) {
         ExtOut("Temp path: %s\n", g_tmpPath);
     }
+#ifndef FEATURE_PAL
+    if (g_useDesktopClrHost) {
+        ExtOut("Using the desktop .NET Framework to host the managed SOS code\n");
+    }
+    else 
+#endif
     if (g_hostRuntimeDirectory != nullptr) {
         ExtOut("Host runtime path: %s\n", g_hostRuntimeDirectory);
     }
@@ -16484,32 +16491,71 @@ DECLARE_API(SetHostRuntime)
 {
     INIT_API_EXT();
 
+    BOOL bDesktop = FALSE;
+    BOOL bNetCore = FALSE;
+    CMDOption option[] =
+    {   // name, vptr, type, hasValue
+#ifndef FEATURE_PAL
+        {"-netfx", &bDesktop, COBOOL, FALSE},
+        {"-netcore", &bNetCore, COBOOL, FALSE},
+#endif
+    };
     StringHolder hostRuntimeDirectory;
     CMDValue arg[] =
     {
         {&hostRuntimeDirectory.data, COSTRING},
     };
     size_t narg;
-    if (!GetCMDOption(args, nullptr, 0, arg, _countof(arg), &narg))
+    if (!GetCMDOption(args, option, _countof(option), arg, _countof(arg), &narg))
     {
         return E_FAIL;
     }
+#ifndef FEATURE_PAL
+    if (narg > 0 || bNetCore || bDesktop)
+#else
     if (narg > 0)
+#endif
     {
         if (IsHostingInitialized())
         {
-            ExtErr("Runtime hosting already initialized %s\n", g_hostRuntimeDirectory);
+            ExtErr("Runtime hosting already initialized %s\n", g_hostRuntimeDirectory != nullptr ? g_hostRuntimeDirectory : "");
             return E_FAIL;
         }
+    }
+#ifndef FEATURE_PAL
+    if (bNetCore)
+    {
+        g_useDesktopClrHost = false;
+    }
+    else if (bDesktop)
+    {
+        g_useDesktopClrHost = true;
+    }
+#endif
+    if (narg > 0)
+    {
         if (g_hostRuntimeDirectory != nullptr)
         {
             free((void*)g_hostRuntimeDirectory);
         }
         g_hostRuntimeDirectory = _strdup(hostRuntimeDirectory.data);
+#ifndef FEATURE_PAL
+        g_useDesktopClrHost = false;
+#endif
     }
-    if (g_hostRuntimeDirectory != nullptr)
+#ifndef FEATURE_PAL
+    if (g_useDesktopClrHost)
     {
-        ExtOut("Host runtime path: %s\n", g_hostRuntimeDirectory);
+        ExtOut("Using the desktop .NET Framework to host the managed SOS code\n");
+    }
+    else 
+#endif
+    {
+        ExtOut("Using the .NET Core runtime to host the managed SOS code\n");
+        if (g_hostRuntimeDirectory != nullptr) 
+        {
+            ExtOut("Host runtime path: %s\n", g_hostRuntimeDirectory);
+        }
     }
     return S_OK;
 }