Download and register DAC with CLRMD (#248)
authorMike McLaughlin <mikem@microsoft.com>
Wed, 8 May 2019 16:41:34 +0000 (09:41 -0700)
committerGitHub <noreply@github.com>
Wed, 8 May 2019 16:41:34 +0000 (09:41 -0700)
Issue https://github.com/dotnet/diagnostics/issues/158

Add SOSInitializeByHost SOS module entry so the SOSHost
code can pass the temp dir created, DAC module path downloaded for
clrmd and the symbol store enabled flag.

Removed ISOSHostServices and replaced initializing the SOSNetCoreCallbacks
initialization as part of the call to SOSInitializeByHost.

Added the "clrmodules" command as a test of a pure CLRMD command and
as place to add the module version requested by some customers.

Catch the DllNotFoundException exception and add "try installing libc6-dev"
to exception message and documentation to work around Microsoft stretch docker
image problems.

Issue: https://github.com/dotnet/diagnostics/issues/201

17 files changed:
documentation/dotnet-dump-instructions.md
documentation/installing-sos-instructions.md
src/SOS/SOS.Hosting/AssemblyResolver.cs
src/SOS/SOS.Hosting/LLDBServicesWrapper.cs
src/SOS/SOS.Hosting/SOSHost.cs
src/SOS/SOS.NETCore/SymbolReader.cs
src/SOS/Strike/Strike.vcxproj
src/SOS/Strike/Strike.vcxproj.filters
src/SOS/Strike/hostcoreclr.cpp
src/SOS/Strike/hostcoreclr.h
src/SOS/Strike/sos.def
src/SOS/Strike/sos_unixexports.src
src/SOS/Strike/soshostservices.h [deleted file]
src/Tools/dotnet-dump/AnalyzeContext.cs
src/Tools/dotnet-dump/Analyzer.cs
src/Tools/dotnet-dump/Commands/ClrModulesCommand.cs [new file with mode: 0644]
src/Tools/dotnet-dump/dotnet-dump.csproj

index ead87c93cfdad0d072706ccb33d70d2f86317dac..a235104acd8762087ad351e231be5abef8105f59 100644 (file)
@@ -5,7 +5,7 @@ The dotnet-dump CLI global tool is way to collect and analyze Windows and Linux
 
 ## Installing dotnet-dump
 
-The first step is to install the dotnet-dump CLI global tool. This requires the 2.1 .NET Core SDK to be installed. If you see the error message `Tool 'dotnet-dump' is already installed`, you will need to uninstall the global tool (see below). 
+The first step is to install the dotnet-dump CLI global tool. This requires at least the 2.1 or greater .NET Core SDK to be installed. If you see the error message `Tool 'dotnet-dump' is already installed`, you will need to uninstall the global tool (see below). 
 
     $ dotnet tool install -g dotnet-dump --version 1.0.3-preview5.19251.2
     You can invoke the tool using the following command: dotnet-dump
index f3198d6a33952653fb6dbfdebc27e5f6f553a07d..ff8921e1d6f1e38d6d6d4455e3a24d8cd6ae5aec 100644 (file)
@@ -1,7 +1,7 @@
 Installing SOS on Linux and MacOS
 =================================
 
-The first step is to install the dotnet-sos CLI global tool. This requires the 2.1 .NET Core SDK to be installed. If you see the error message `Tool 'dotnet-sos' is already installed`, you will need to uninstall the global tool (see below). 
+The first step is to install the dotnet-sos CLI global tool. This requires at least the 2.1 or greater .NET Core SDK to be installed. If you see the error message `Tool 'dotnet-sos' is already installed`, you will need to uninstall the global tool (see below). 
 
     $ dotnet tool install -g dotnet-sos --version 1.0.3-preview5.19251.2
     You can invoke the tool using the following command: dotnet-sos
index 8e9e07beffaa87099d45b492e6e060c3dd6960ae..7903fc8d3ce5c3c4c4845d7d1bd8fada46e4ffd1 100644 (file)
@@ -12,14 +12,20 @@ namespace SOS
     /// <summary>
     /// Used to enable app-local assembly unification.
     /// </summary>
-    internal static class AssemblyResolver
+    public static class AssemblyResolver
     {
+        private static bool s_initialized = false;
+
         /// <summary>
         /// Call to enable the assembly resolver for the current AppDomain.
         /// </summary>
         public static void Enable()
         {
-            AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;
+            if (!s_initialized)
+            {
+                s_initialized = true;
+                AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;
+            }
         }
 
         private static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
index 7704a9baa9d3b9fb1dd67c51e3a35d19e356fa3a..b1ae1c0c50ec26080c48882a9022101085cb11d5 100644 (file)
@@ -23,104 +23,6 @@ namespace SOS
 
         public IntPtr ILLDBServices { get; }
 
-        #region SOS.NETCore function delegates
-
-        private delegate bool InitializeSymbolStoreDelegate(
-            bool logging,
-            bool msdl,
-            bool symweb,
-            string symbolServerPath,
-            string symbolCachePath,
-            string windowsSymbolPath);
-
-        private delegate void DisplaySymbolStoreDelegate();
-
-        private delegate void DisableSymbolStoreDelegate();
-
-        private delegate void LoadNativeSymbolsDelegate(
-            SymbolReader.SymbolFileCallback callback,
-            IntPtr parameter,
-            string tempDirectory,
-            string moduleFilePath,
-            ulong address,
-            int size,
-            SymbolReader.ReadMemoryDelegate readMemory);
-
-        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);
-
-        #endregion
-
-        /// <summary>
-        /// Used by ISOSHostServices.GetSOSNETCoreCallbacks.
-        /// </summary>
-        [StructLayout(LayoutKind.Sequential)]
-        struct SOSNetCoreCallbacks
-        {
-            public InitializeSymbolStoreDelegate InitializeSymbolStoreDelegate;
-            public DisplaySymbolStoreDelegate DisplaySymbolStoreDelegate;
-            public DisableSymbolStoreDelegate DisableSymbolStoreDelegate;
-            public LoadNativeSymbolsDelegate LoadNativeSymbolsDelegate;
-            public LoadSymbolsForModuleDelegate LoadSymbolsForModuleDelegate;
-            public DisposeDelegate DisposeDelegate;
-            public ResolveSequencePointDelegate ResolveSequencePointDelegate;
-            public GetLineByILOffsetDelegate GetLineByILOffsetDelegate;
-            public GetLocalVariableNameDelegate GetLocalVariableNameDelegate;
-            public GetMetadataLocatorDelegate GetMetadataLocatorDelegate;
-        }
-
-        static SOSNetCoreCallbacks s_callbacks = new SOSNetCoreCallbacks {
-            InitializeSymbolStoreDelegate = SymbolReader.InitializeSymbolStore,
-            DisplaySymbolStoreDelegate = SymbolReader.DisplaySymbolStore,
-            DisableSymbolStoreDelegate = SymbolReader.DisableSymbolStore,
-            LoadNativeSymbolsDelegate = SymbolReader.LoadNativeSymbols,
-            LoadSymbolsForModuleDelegate = SymbolReader.LoadSymbolsForModule,
-            DisposeDelegate  = SymbolReader.Dispose,
-            ResolveSequencePointDelegate = SymbolReader.ResolveSequencePoint,
-            GetLineByILOffsetDelegate = SymbolReader.GetLineByILOffset,
-            GetLocalVariableNameDelegate = SymbolReader.GetLocalVariableName,
-            GetMetadataLocatorDelegate = MetadataHelper.GetMetadataLocator
-        };
-
         static readonly string s_coreclrModuleName = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? "coreclr" : "libcoreclr.so";
 
         readonly SOSHost _sosHost;
@@ -189,10 +91,6 @@ namespace SOS
             builder.AddMethod(new AddModuleSymbolDelegate(AddModuleSymbol));
             builder.Complete();
 
-            builder = AddInterface(IID_SOSHostServices, validate: false);
-            builder.AddMethod(new GetSOSNETCoreCallbacksDelegate(GetSOSNETCoreCallbacks));
-            builder.Complete();
-
             AddRef();
         }
 
@@ -762,30 +660,6 @@ namespace SOS
 
         #endregion
 
-        #region ISOSHostServices
-
-        int GetSOSNETCoreCallbacks(
-            IntPtr self,
-            int version,
-            IntPtr pCallbacks)
-        {
-            if (version < 1)
-            {
-                return E_FAIL;
-            }
-            try
-            {
-                Marshal.StructureToPtr(s_callbacks, pCallbacks, false);
-            }
-            catch (ArgumentException)
-            {
-                return E_FAIL;
-            }
-            return S_OK;
-        }
-
-        #endregion 
-
         #region ILLDBServices delegates
 
         [UnmanagedFunctionPointer(CallingConvention.StdCall)]
@@ -1069,15 +943,5 @@ namespace SOS
             [MarshalAs(UnmanagedType.LPStr)] string symbolFilename);
 
         #endregion
-
-        #region ISOSHostServices delegates
-
-        [UnmanagedFunctionPointer(CallingConvention.StdCall)]
-        private delegate int GetSOSNETCoreCallbacksDelegate(
-            IntPtr self,
-            int version,
-            IntPtr pCallbacks);
-
-        #endregion 
     }
 }
\ No newline at end of file
index 36896d6ec9f381eddc2866489065fccba6263d89..579a2f72e108cb3181437cf85ca2be34cccbab43 100644 (file)
@@ -4,6 +4,7 @@
 
 using Microsoft.Diagnostics.Runtime;
 using System;
+using System.Diagnostics;
 using System.IO;
 using System.Reflection;
 using System.Runtime.InteropServices;
@@ -16,7 +17,118 @@ namespace SOS
     public sealed class SOSHost
     {
         [UnmanagedFunctionPointer(CallingConvention.StdCall)]
-        delegate int SOSCommandDelegate(IntPtr ILLDBServices, [In, MarshalAs(UnmanagedType.LPStr)] string args);
+        private delegate int SOSCommandDelegate(
+            IntPtr ILLDBServices,
+            [In, MarshalAs(UnmanagedType.LPStr)] string args);
+
+        [UnmanagedFunctionPointer(CallingConvention.StdCall)]
+        private delegate int SOSInitializeDelegate(
+            [In, MarshalAs(UnmanagedType.Struct)] ref SOSNetCoreCallbacks callbacks,
+            int callbacksSize,
+            [In, MarshalAs(UnmanagedType.LPStr)] string tempDirectory, 
+            [In, MarshalAs(UnmanagedType.LPStr)] string dacFilePath, 
+            [In, MarshalAs(UnmanagedType.LPStr)] string dbiFilePath,
+            bool symbolStoreEnabled);
+
+        private const string SOSInitialize = "SOSInitializeByHost";
+
+        #region SOS.NETCore function delegates
+
+        private delegate bool InitializeSymbolStoreDelegate(
+            bool logging,
+            bool msdl,
+            bool symweb,
+            string symbolServerPath,
+            string symbolCachePath,
+            string windowsSymbolPath);
+
+        private delegate void DisplaySymbolStoreDelegate();
+
+        private delegate void DisableSymbolStoreDelegate();
+
+        private delegate void LoadNativeSymbolsDelegate(
+            SymbolReader.SymbolFileCallback callback,
+            IntPtr parameter,
+            string tempDirectory,
+            string moduleFilePath,
+            ulong address,
+            int size,
+            SymbolReader.ReadMemoryDelegate readMemory);
+
+        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);
+
+        #endregion
+
+        /// <summary>
+        /// Pass to SOSInitializeByHost
+        /// </summary>
+        [StructLayout(LayoutKind.Sequential)]
+        struct SOSNetCoreCallbacks
+        {
+            public InitializeSymbolStoreDelegate InitializeSymbolStoreDelegate;
+            public DisplaySymbolStoreDelegate DisplaySymbolStoreDelegate;
+            public DisableSymbolStoreDelegate DisableSymbolStoreDelegate;
+            public LoadNativeSymbolsDelegate LoadNativeSymbolsDelegate;
+            public LoadSymbolsForModuleDelegate LoadSymbolsForModuleDelegate;
+            public DisposeDelegate DisposeDelegate;
+            public ResolveSequencePointDelegate ResolveSequencePointDelegate;
+            public GetLineByILOffsetDelegate GetLineByILOffsetDelegate;
+            public GetLocalVariableNameDelegate GetLocalVariableNameDelegate;
+            public GetMetadataLocatorDelegate GetMetadataLocatorDelegate;
+        }
+
+        static SOSNetCoreCallbacks s_callbacks = new SOSNetCoreCallbacks {
+            InitializeSymbolStoreDelegate = SymbolReader.InitializeSymbolStore,
+            DisplaySymbolStoreDelegate = SymbolReader.DisplaySymbolStore,
+            DisableSymbolStoreDelegate = SymbolReader.DisableSymbolStore,
+            LoadNativeSymbolsDelegate = SymbolReader.LoadNativeSymbols,
+            LoadSymbolsForModuleDelegate = SymbolReader.LoadSymbolsForModule,
+            DisposeDelegate  = SymbolReader.Dispose,
+            ResolveSequencePointDelegate = SymbolReader.ResolveSequencePoint,
+            GetLineByILOffsetDelegate = SymbolReader.GetLineByILOffset,
+            GetLocalVariableNameDelegate = SymbolReader.GetLocalVariableName,
+            GetMetadataLocatorDelegate = MetadataHelper.GetMetadataLocator
+        };
 
         readonly LLDBServicesWrapper _wrapper;
         IntPtr _sosLibrary = IntPtr.Zero;
@@ -57,6 +169,69 @@ namespace SOS
             _wrapper = new LLDBServicesWrapper(this, dataReader, context);
         }
 
+        /// <summary>
+        /// Loads and initializes the SOS module.
+        /// </summary>
+        /// <param name="tempDirectory">Temporary directory created to download DAC module</param>
+        /// <param name="dacFilePath">The path to DAC that CLRMD loaded or downloaded or null</param>
+        /// <param name="dbiFilePath">The path to DBI (for future use) or null</param>
+        public void InitializeSOSHost(string tempDirectory, string dacFilePath, string dbiFilePath)
+        {
+            if (_sosLibrary == IntPtr.Zero)
+            {
+                string sosPath = Path.Combine(SOSPath, RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? "sos.dll" : "libsos.so");
+                try
+                {
+                    _sosLibrary = DataTarget.PlatformFunctions.LoadLibrary(sosPath);
+                }
+                catch (DllNotFoundException ex)
+                {
+                    // This is a workaround for the Microsoft SDK docker images. Can fail when LoadLibrary uses libdl.so to load the SOS module.
+                    if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
+                    {
+                        throw new DllNotFoundException("Problem loading SOS module. Try installing libc6-dev (apt-get install libc6-dev) to work around this problem.", ex);
+                    }
+                    else
+                    {
+                        throw;
+                    }
+                }
+                if (_sosLibrary == IntPtr.Zero)
+                {
+                    throw new FileNotFoundException($"SOS module {sosPath} not found");
+                }
+                IntPtr initializeAddress = DataTarget.PlatformFunctions.GetProcAddress(_sosLibrary, SOSInitialize);
+                if (initializeAddress == IntPtr.Zero)
+                {
+                    throw new EntryPointNotFoundException($"Can not find SOS module initialization function: {SOSInitialize}");
+                }
+                var initializeFunc = (SOSInitializeDelegate)Marshal.GetDelegateForFunctionPointer(initializeAddress, typeof(SOSInitializeDelegate));
+
+                // SOS depends on that the temp directory ends with "/".
+                if (!string.IsNullOrEmpty(tempDirectory) && tempDirectory[tempDirectory.Length - 1] != Path.DirectorySeparatorChar)
+                {
+                    tempDirectory = tempDirectory + Path.DirectorySeparatorChar;
+                }
+
+                int result = initializeFunc(
+                    ref s_callbacks,
+                    Marshal.SizeOf<SOSNetCoreCallbacks>(), 
+                    tempDirectory,
+                    dacFilePath,
+                    dbiFilePath,
+                    SymbolReader.IsSymbolStoreEnabled());
+
+                if (result != 0)
+                {
+                    throw new InvalidOperationException($"SOS initialization FAILED 0x{result:X8}");
+                }
+            }
+        }
+
+        /// <summary>
+        /// Execute a SOS command.
+        /// </summary>
+        /// <param name="commandLine">command name and arguments</param>
         public void ExecuteCommand(string commandLine)
         {
             string command = "Help";
@@ -71,17 +246,15 @@ namespace SOS
             ExecuteCommand(command, arguments);
         }
 
+        /// <summary>
+        /// Execute a SOS command.
+        /// </summary>
+        /// <param name="command">just the command name</param>
+        /// <param name="arguments">the command arguments and options</param>
         public void ExecuteCommand(string command, string arguments)
         {
-            if (_sosLibrary == IntPtr.Zero)
-            {
-                string sosPath = Path.Combine(SOSPath, RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? "sos.dll" : "libsos.so");
-                _sosLibrary = DataTarget.PlatformFunctions.LoadLibrary(sosPath);
-                if (_sosLibrary == IntPtr.Zero)
-                {
-                    throw new FileNotFoundException($"SOS module {sosPath} not found");
-                }
-            }
+            Debug.Assert(_sosLibrary != null);
+
             IntPtr commandAddress = DataTarget.PlatformFunctions.GetProcAddress(_sosLibrary, command);
             if (commandAddress == IntPtr.Zero)
             {
index f80a4febbaeb9bab8082fc2356d51a47495af91f..9bd04f2208c28e9102be71c95641302f375f2c3e 100644 (file)
@@ -238,6 +238,7 @@ namespace SOS
         /// </summary>
         /// <param name="callback">called back for each symbol file loaded</param>
         /// <param name="parameter">callback parameter</param>
+        /// <param name="tempDirectory">temp directory unique to this instance of SOS</param>
         /// <param name="moduleFilePath">module path</param>
         /// <param name="address">module base address</param>
         /// <param name="size">module size</param>
@@ -277,41 +278,65 @@ namespace SOS
                         // Don't download the sos binaries that come with the runtime
                         if (moduleFileName != "SOS.NETCore.dll" && !moduleFileName.StartsWith("libsos."))
                         {
-                            using (SymbolStoreFile file = GetSymbolStoreFile(key))
+                            string downloadFilePath = GetSymbolFile(key, tempDirectory);
+                            if (downloadFilePath != null)
                             {
-                                if (file != null)
-                                {
-                                    try
-                                    {
-                                        string downloadFilePath = file.FileName;
-
-                                        // If the downloaded doesn't already exists on disk in the cache, then write it to a temporary location.
-                                        if (!File.Exists(downloadFilePath))
-                                        {
-                                            downloadFilePath = Path.Combine(tempDirectory, moduleFileName);
-
-                                            using (Stream destinationStream = File.OpenWrite(downloadFilePath)) {
-                                                file.Stream.CopyTo(destinationStream);
-                                            }
-                                            s_tracer.WriteLine("Downloaded symbol file {0}", key.FullPathName);
-                                        }
-                                        s_tracer.Information("{0}: {1}", moduleFileName, downloadFilePath);
-                                        callback(parameter, moduleFileName, downloadFilePath);
-                                    }
-                                    catch (Exception ex) when (ex is UnauthorizedAccessException || ex is DirectoryNotFoundException)
-                                    {
-                                        s_tracer.Error("{0}", ex.Message);
-                                    }
-                                }
+                                s_tracer.Information("{0}: {1}", moduleFileName, downloadFilePath);
+                                callback(parameter, moduleFileName, downloadFilePath);
                             }
                         }
                     }
                 }
                 catch (Exception ex) when (ex is BadInputFormatException || ex is InvalidVirtualAddressException)
                 {
-                    s_tracer.Error("Exception: {0}/{1}: {2:X16}", moduleFilePath, address);
+                    s_tracer.Error("{0}/{1:X16}: {2}", moduleFilePath, address, ex.Message);
+                }
+            }
+        }
+
+        /// <summary>
+        /// Download a symbol from the symbol stores/server.
+        /// </summary>
+        /// <param name="key">index of the file to download</param>
+        /// <param name="tempDirectory">temp directory to put the file. This directory is only created if 
+        /// the file is NOT already in the cache and is downloaded.</param>
+        /// <returns>Path to the downloaded file either in the cache or in the temp directory</returns>
+        public static string GetSymbolFile(SymbolStoreKey key, string tempDirectory)
+        {
+            string downloadFilePath = null;
+
+            if (IsSymbolStoreEnabled())
+            {
+                using (SymbolStoreFile file = GetSymbolStoreFile(key))
+                {
+                    if (file != null)
+                    {
+                        try
+                        {
+                            downloadFilePath = file.FileName;
+
+                            // If the downloaded doesn't already exists on disk in the cache, then write it to a temporary location.
+                            if (!File.Exists(downloadFilePath))
+                            {
+                                Directory.CreateDirectory(tempDirectory);
+                                downloadFilePath = Path.Combine(tempDirectory, Path.GetFileName(key.FullPathName));
+
+                                using (Stream destinationStream = File.OpenWrite(downloadFilePath)) {
+                                    file.Stream.CopyTo(destinationStream);
+                                }
+                                s_tracer.WriteLine("Downloaded symbol file {0}", key.FullPathName);
+                            }
+                        }
+                        catch (Exception ex) when (ex is UnauthorizedAccessException || ex is DirectoryNotFoundException)
+                        {
+                            s_tracer.Error("{0}: {1}", file.FileName, ex.Message);
+                            downloadFilePath = null;
+                        }
+                    }
                 }
             }
+
+            return downloadFilePath;
         }
 
         /// <summary>
@@ -940,7 +965,7 @@ namespace SOS
         /// <summary>
         /// Returns true if symbol download has been enabled.
         /// </summary>
-        internal static bool IsSymbolStoreEnabled()
+        public static bool IsSymbolStoreEnabled()
         {
             return s_symbolStore != null;
         }
index 060b0c401944689918ce16cec7cea480d4e7f885..ca82bf2b25e0d728eef5e7bc3b5b24b52a23e183 100644 (file)
     <ClInclude Include="ntinfo.h" />
     <ClInclude Include="platformspecific.h" />
     <ClInclude Include="sos.h" />
-    <ClInclude Include="soshostservices.h" />
     <ClInclude Include="sos_md.h" />
     <ClInclude Include="sos_stacktrace.h" />
     <ClInclude Include="strike.h" />
index 1640905752885365e5fcaa57db8c8ea713c2a1c4..cd5bb759b5ff622f3f62f881f440c30d3d3c1aa1 100644 (file)
@@ -57,7 +57,6 @@
       <Filter>inc</Filter>
     </ClInclude>
     <ClInclude Include="hostcoreclr.h" />
-    <ClInclude Include="soshostservices.h" />
   </ItemGroup>
   <ItemGroup>
     <ResourceCompile Include="Native.rc" />
index d8ee2412e65e05a611f43214ccce6641645a8437..302f0e92fccdec2e29caaa4ef1314af0eb0f67b3 100644 (file)
@@ -543,6 +543,32 @@ LPCSTR GetDbiFilePath()
     return g_dbiFilePath;
 }
 
+/**********************************************************************\
+ * Called when the managed SOS Host loads/initializes SOS.
+\**********************************************************************/
+extern "C" HRESULT SOSInitializeByHost(SOSNetCoreCallbacks* callbacks, int callbacksSize, LPCSTR tempDirectory, LPCSTR dacFilePath, LPCSTR dbiFilePath, bool symbolStoreEnabled)
+{
+    if (memcpy_s(&g_SOSNetCoreCallbacks, sizeof(g_SOSNetCoreCallbacks), callbacks, callbacksSize) != 0)
+    {
+        return E_INVALIDARG;
+    }
+    if (tempDirectory != nullptr)
+    {
+        g_tmpPath = _strdup(tempDirectory);
+    }
+    if (dacFilePath != nullptr)
+    {
+        g_dacFilePath = _strdup(dacFilePath);
+    }
+    if (dbiFilePath != nullptr)
+    {
+        g_dbiFilePath = _strdup(dbiFilePath);
+    }
+    g_symbolStoreInitialized = symbolStoreEnabled;
+    g_hostingInitialized = true;
+    return S_OK;
+}
+
 /**********************************************************************\
  * Returns true if the host runtime has already been initialized.
 \**********************************************************************/
@@ -561,17 +587,6 @@ HRESULT InitializeHosting()
     {
         return S_OK;
     }
-#ifdef FEATURE_PAL
-    ToRelease<ISOSHostServices> hostServices(NULL);
-    if (SUCCEEDED(g_ExtServices->QueryInterface(__uuidof(ISOSHostServices), (void**)&hostServices)))
-    {
-        if (SUCCEEDED(hostServices->GetSOSNETCoreCallbacks(SOSNetCoreCallbacksVersion, &g_SOSNetCoreCallbacks)))
-        {
-            g_hostingInitialized = true;
-            return S_OK;
-        }
-    }
-#endif // FEATURE_PAL
     coreclr_initialize_ptr initializeCoreCLR = nullptr;
     coreclr_create_delegate_ptr createDelegate = nullptr;
     std::string hostRuntimeDirectory;
index 13c04b072cfbf1027ccf85181a238bc0e13aea6f..fbbcb205ee6c1a4dc722a3390ecaa0aa9746256e 100644 (file)
 #ifndef __hostcoreclr_h__
 #define __hostcoreclr_h__
 
-#include <soshostservices.h>
+struct SymbolModuleInfo;
+
+typedef void (*OutputDelegate)(const char*);
+typedef  int (*ReadMemoryDelegate)(ULONG64, uint8_t*, int);
+typedef void (*SymbolFileCallbackDelegate)(void*, const char* moduleFileName, const char* symbolFilePath);
+
+typedef  BOOL (*InitializeSymbolStoreDelegate)(BOOL, BOOL, BOOL, const char*, const char*, const char*);
+typedef  void (*DisplaySymbolStoreDelegate)();
+typedef  void (*DisableSymbolStoreDelegate)();
+typedef  void (*LoadNativeSymbolsDelegate)(SymbolFileCallbackDelegate, void*, const char*, const char*, ULONG64, int, ReadMemoryDelegate);
+typedef  PVOID (*LoadSymbolsForModuleDelegate)(const char*, BOOL, ULONG64, int, ULONG64, int, ReadMemoryDelegate);
+typedef  void (*DisposeDelegate)(PVOID);
+typedef  BOOL (*ResolveSequencePointDelegate)(PVOID, const char*, unsigned int, unsigned int*, unsigned int*);
+typedef  BOOL (*GetLocalVariableNameDelegate)(PVOID, int, int, BSTR*);
+typedef  BOOL (*GetLineByILOffsetDelegate)(PVOID, mdMethodDef, ULONG64, ULONG *, BSTR*);
+
+typedef  BOOL (*GetMetadataLocatorDelegate)(
+    LPCWSTR imagePath,
+    unsigned int imageTimestamp,
+    unsigned int imageSize,
+    GUID* mvid,
+    unsigned int mdRva,
+    unsigned int flags,
+    unsigned int bufferSize,
+    PVOID pMetadata,
+    unsigned int* pMetadataSize
+);
+
+struct SOSNetCoreCallbacks
+{
+    InitializeSymbolStoreDelegate InitializeSymbolStoreDelegate;
+    DisplaySymbolStoreDelegate DisplaySymbolStoreDelegate;
+    DisableSymbolStoreDelegate DisableSymbolStoreDelegate;
+    LoadNativeSymbolsDelegate LoadNativeSymbolsDelegate;
+    LoadSymbolsForModuleDelegate LoadSymbolsForModuleDelegate;
+    DisposeDelegate DisposeDelegate;
+    ResolveSequencePointDelegate ResolveSequencePointDelegate;
+    GetLineByILOffsetDelegate GetLineByILOffsetDelegate;
+    GetLocalVariableNameDelegate GetLocalVariableNameDelegate;
+    GetMetadataLocatorDelegate GetMetadataLocatorDelegate;
+};
 
 static const char *SOSManagedDllName = "SOS.NETCore";
 static const char *SymbolReaderClassName = "SOS.SymbolReader";
index 81964382b28e0f8395e4437673e07376e46c4d30..cebf92cc0ef220823a62f9fe9228f2460796a466 100644 (file)
@@ -232,4 +232,6 @@ EXPORTS
     getCodeTypeFlags=GetCodeTypeFlags
     TraceToCode
     tracetocode=TraceToCode
-#endif
\ No newline at end of file
+#endif
+
+    SOSInitializeByHost
index 732da868ffbfdc290b7feebae21ee97a682bea80..acb294055accf6bd89c3bacb833cb7c5a8d24e7c 100644 (file)
@@ -53,3 +53,5 @@ ThreadState
 Token2EE
 u
 VerifyHeap
+
+SOSInitializeByHost
\ No newline at end of file
diff --git a/src/SOS/Strike/soshostservices.h b/src/SOS/Strike/soshostservices.h
deleted file mode 100644 (file)
index d16c71c..0000000
+++ /dev/null
@@ -1,82 +0,0 @@
-// 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.
-
-//----------------------------------------------------------------------------
-//
-// LLDB debugger services for sos
-//
-//----------------------------------------------------------------------------
-
-#ifndef __SOSHOSTSERVICES_H__
-#define __SOSHOSTSERVICES_H__
-
-#include <stdarg.h>
-#include <unknwn.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-struct SymbolModuleInfo;
-
-typedef void (*OutputDelegate)(const char*);
-typedef  int (*ReadMemoryDelegate)(ULONG64, uint8_t*, int);
-typedef void (*SymbolFileCallbackDelegate)(void*, const char* moduleFileName, const char* symbolFilePath);
-
-typedef  BOOL (*InitializeSymbolStoreDelegate)(BOOL, BOOL, BOOL, const char*, const char*, const char*);
-typedef  void (*DisplaySymbolStoreDelegate)();
-typedef  void (*DisableSymbolStoreDelegate)();
-typedef  void (*LoadNativeSymbolsDelegate)(SymbolFileCallbackDelegate, void*, const char*, const char*, ULONG64, int, ReadMemoryDelegate);
-typedef  PVOID (*LoadSymbolsForModuleDelegate)(const char*, BOOL, ULONG64, int, ULONG64, int, ReadMemoryDelegate);
-typedef  void (*DisposeDelegate)(PVOID);
-typedef  BOOL (*ResolveSequencePointDelegate)(PVOID, const char*, unsigned int, unsigned int*, unsigned int*);
-typedef  BOOL (*GetLocalVariableNameDelegate)(PVOID, int, int, BSTR*);
-typedef  BOOL (*GetLineByILOffsetDelegate)(PVOID, mdMethodDef, ULONG64, ULONG *, BSTR*);
-
-typedef  BOOL (*GetMetadataLocatorDelegate)(
-    LPCWSTR imagePath,
-    unsigned int imageTimestamp,
-    unsigned int imageSize,
-    GUID* mvid,
-    unsigned int mdRva,
-    unsigned int flags,
-    unsigned int bufferSize,
-    PVOID pMetadata,
-    unsigned int* pMetadataSize
-);
-
-#define SOSNetCoreCallbacksVersion 2
-
-struct SOSNetCoreCallbacks
-{
-    InitializeSymbolStoreDelegate InitializeSymbolStoreDelegate;
-    DisplaySymbolStoreDelegate DisplaySymbolStoreDelegate;
-    DisableSymbolStoreDelegate DisableSymbolStoreDelegate;
-    LoadNativeSymbolsDelegate LoadNativeSymbolsDelegate;
-    LoadSymbolsForModuleDelegate LoadSymbolsForModuleDelegate;
-    DisposeDelegate DisposeDelegate;
-    ResolveSequencePointDelegate ResolveSequencePointDelegate;
-    GetLineByILOffsetDelegate GetLineByILOffsetDelegate;
-    GetLocalVariableNameDelegate GetLocalVariableNameDelegate;
-    GetMetadataLocatorDelegate GetMetadataLocatorDelegate;
-};
-
-MIDL_INTERFACE("D13608FB-AD14-4B49-990A-80284F934C41")
-ISOSHostServices : public IUnknown
-{
-public:
-    //----------------------------------------------------------------------------
-    // ISOSHostServices
-    //----------------------------------------------------------------------------
-
-    virtual HRESULT GetSOSNETCoreCallbacks(
-        int version,
-        SOSNetCoreCallbacks* callbacks) = 0;
-};
-
-#ifdef __cplusplus
-};
-#endif
-
-#endif // #ifndef __SOSHOSTSERVICES_H__
index d347a0e25f7de140d954181914f5866a06d2d5bc..4dba574612994d225f0ffaf9958e6eef214fc536 100644 (file)
@@ -4,9 +4,16 @@
 // 
 // --------------------------------------------------------------------
 using Microsoft.Diagnostics.Runtime;
+using Microsoft.SymbolStore;
+using Microsoft.SymbolStore.KeyGenerators;
 using SOS;
 using System;
+using System.Collections.Generic;
 using System.CommandLine;
+using System.Diagnostics;
+using System.IO;
+using System.Linq;
+using System.Runtime.InteropServices;
 using System.Threading;
 
 namespace Microsoft.Diagnostic.Tools.Dump
@@ -18,7 +25,10 @@ namespace Microsoft.Diagnostic.Tools.Dump
     {
         private readonly IConsole _console;
         private ClrRuntime _runtime;
-        private SOSHost _sosHost;
+
+        private static SOSHost s_sosHost;
+        private static string s_tempDirectory;
+        private static string s_dacFilePath;
 
         public AnalyzeContext(IConsole console, DataTarget target)
         {
@@ -43,12 +53,78 @@ namespace Microsoft.Diagnostic.Tools.Dump
                     if (Target.ClrVersions.Count != 1) {
                         throw new InvalidOperationException("More or less than 1 CLR version is present");
                     }
-                    _runtime = Target.ClrVersions[0].CreateRuntime();
+                    ClrInfo clrInfo = Target.ClrVersions[0];
+                    string dacFilePath = GetDacFile(clrInfo);
+                    try
+                    {
+                        _runtime = clrInfo.CreateRuntime(dacFilePath);
+                    }
+                    catch (DllNotFoundException ex)
+                    {
+                        // This is a workaround for the Microsoft SDK docker images. Can fail when clrmd uses libdl.so 
+                        // to create a symlink to and load the DAC module.
+                        if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
+                        {
+                            throw new DllNotFoundException("Problem initializing CLRMD. Try installing libc6-dev (apt-get install libc6-dev) to work around this problem.", ex);
+                        }
+                        else
+                        {
+                            throw;
+                        }
+                    }
                 }
                 return _runtime;
             }
         }
 
+        private string GetDacFile(ClrInfo clrInfo)
+        {
+            if (s_dacFilePath == null)
+            {
+                string dac = clrInfo.LocalMatchingDac;
+                if (dac != null && File.Exists(dac))
+                {
+                    s_dacFilePath = dac;
+                }
+                else if (SymbolReader.IsSymbolStoreEnabled())
+                {
+                    string dacFileName = Path.GetFileName(clrInfo.LocalMatchingDac);
+                    SymbolStoreKey key = null;
+
+                    if (clrInfo.ModuleInfo.BuildId != null)
+                    {
+                        IEnumerable<SymbolStoreKey> keys = ELFFileKeyGenerator.GetKeys(
+                            KeyTypeFlags.ClrKeys, clrInfo.ModuleInfo.FileName, clrInfo.ModuleInfo.BuildId, symbolFile: false, symbolFileName: null);
+
+                        key = keys.SingleOrDefault((k) => Path.GetFileName(k.FullPathName) == dacFileName);
+                    }
+                    else
+                    {
+                        // Use the coreclr.dll's id (timestamp/filesize) to download the the dac module.
+                        key = PEFileKeyGenerator.GetKey(dacFileName, clrInfo.ModuleInfo.TimeStamp, clrInfo.ModuleInfo.FileSize);
+                    }
+
+                    if (key != null)
+                    {
+                        if (s_tempDirectory == null)
+                        {
+                            int processId = Process.GetCurrentProcess().Id;
+                            s_tempDirectory = Path.Combine(Path.GetTempPath(), "analyze" + processId.ToString());
+                        }
+                        // Now download the DAC module from the symbol server
+                        s_dacFilePath = SymbolReader.GetSymbolFile(key, s_tempDirectory);
+                    }
+                }
+
+                if (s_dacFilePath == null)
+                {
+                    throw new FileNotFoundException("Could not find matching DAC for this runtime: {0}", clrInfo.ModuleInfo.FileName);
+                }
+            }
+
+            return s_dacFilePath;
+        }
+
         /// <summary>
         /// Returns the SOS host instance
         /// </summary>
@@ -56,18 +132,14 @@ namespace Microsoft.Diagnostic.Tools.Dump
         {
             get 
             {
-                if (_sosHost == null) {
-                    _sosHost = new SOSHost(Target.DataReader, this);
+                if (s_sosHost == null) {
+                    s_sosHost = new SOSHost(Target.DataReader, this);
+                    s_sosHost.InitializeSOSHost(s_tempDirectory, s_dacFilePath, dbiFilePath: null);
                 }
-                return _sosHost;
+                return s_sosHost;
             }
         }
 
-        /// <summary>
-        /// Delegate to invoke to exit repl
-        /// </summary>
-        public Action Exit { get; }
-
         /// <summary>
         /// Current OS thread Id
         /// </summary>
index 7cd64a695f4960208533583784ab6b691b2565a4..ef80f36616ad81b8c7daf6b9ff5e4dff9760d35a 100644 (file)
@@ -1,5 +1,6 @@
 using Microsoft.Diagnostic.Repl;
 using Microsoft.Diagnostics.Runtime;
+using SOS;
 using System;
 using System.CommandLine;
 using System.IO;
@@ -16,6 +17,15 @@ namespace Microsoft.Diagnostic.Tools.Dump
         private readonly ConsoleProvider _consoleProvider;
         private readonly CommandProcessor _commandProcessor;
 
+        /// <summary>
+        /// Enable the assembly resolver to get the right SOS.NETCore version (the one
+        /// in the same directory as this assembly).
+        /// </summary>
+        static Analyzer()
+        {
+            AssemblyResolver.Enable();
+        }
+
         public Analyzer()
         {
             _consoleProvider = new ConsoleProvider();
@@ -34,8 +44,7 @@ namespace Microsoft.Diagnostic.Tools.Dump
                     target = DataTarget.LoadCoreDump(dump_path.FullName);
                 }
                 else if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) {
-                    //target = DataTarget.LoadCrashDump(dump_path.FullName, CrashDumpReader.ClrMD);
-                    throw new PlatformNotSupportedException("Preview build: This is not yet implemented on Windows");
+                    target = DataTarget.LoadCrashDump(dump_path.FullName, CrashDumpReader.ClrMD);
                 }
                 else {
                     throw new PlatformNotSupportedException($"Unsupported operating system: {RuntimeInformation.OSDescription}");
@@ -53,8 +62,9 @@ namespace Microsoft.Diagnostic.Tools.Dump
                     _commandProcessor.AddService(analyzeContext);
 
                     // Automatically enable symbol server support on Linux and MacOS
-                    if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) {
-                        analyzeContext.SOSHost.ExecuteCommand("SetSymbolServer", "-ms");
+                    //if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
+                    {
+                        SymbolReader.InitializeSymbolStore(logging: false, msdl: true, symweb: false, symbolServerPath: null, symbolCachePath: null, windowsSymbolPath: null);
                     }
 
                     // Run the commands from the dotnet-dump command line
diff --git a/src/Tools/dotnet-dump/Commands/ClrModulesCommand.cs b/src/Tools/dotnet-dump/Commands/ClrModulesCommand.cs
new file mode 100644 (file)
index 0000000..50a24cf
--- /dev/null
@@ -0,0 +1,23 @@
+
+using Microsoft.Diagnostic.Repl;
+using Microsoft.Diagnostics.Runtime;
+using System.CommandLine;
+using System.Threading.Tasks;
+
+namespace Microsoft.Diagnostic.Tools.Dump
+{
+    [Command(Name = "clrmodules", Help = "Lists the managed modules in the process.")]
+    public class ClrModulesCommand : CommandBase
+    {
+        public AnalyzeContext AnalyzeContext { get; set; }
+
+        public override Task InvokeAsync()
+        {
+            foreach (ClrModule module in AnalyzeContext.Runtime.Modules)
+            {
+                WriteLine("{0:X16} {1}", module.Address, module.FileName);
+            }
+            return Task.CompletedTask;
+        }
+    }
+}
index 1eca1261bf9a6001cea0ae0cc2f99eba89f999f5..bbf450565a02ef1797b68ba964f82fe77ee5ee63 100644 (file)
 
   <ItemGroup>
     <PackageReference Include="Microsoft.Diagnostics.Runtime" Version="$(MicrosoftDiagnosticsRuntimeVersion)" />
+    <PackageReference Include="Microsoft.SymbolStore" Version="$(MicrosoftSymbolStoreVersion)" />
   </ItemGroup>
   
   <ItemGroup>
     <ProjectReference Include="$(MSBuildThisFileDirectory)..\..\Microsoft.Diagnostic.Repl\Microsoft.Diagnostic.Repl.csproj" />
-    <ProjectReference Include="$(MSBuildThisFileDirectory)..\..\SOS\SOS.Hosting\SOS.Hosting.csproj" />
     <ProjectReference Include="$(MSBuildThisFileDirectory)..\..\Microsoft.Diagnostics.Tools.RuntimeClient\Microsoft.Diagnostics.Tools.RuntimeClient.csproj" />
+    <ProjectReference Include="$(MSBuildThisFileDirectory)..\..\SOS\SOS.Hosting\SOS.Hosting.csproj" />
+    <ProjectReference Include="$(MSBuildThisFileDirectory)..\..\SOS\SOS.NETCore\SOS.NETCore.csproj" />
   </ItemGroup>
 
   <ItemGroup>