Hosting SOS under ClrMd for ELF dumps.
authorMike McLaughlin <mikem@microsoft.com>
Sun, 17 Feb 2019 20:12:13 +0000 (12:12 -0800)
committerMike McLaughlin <mikem@microsoft.com>
Fri, 22 Feb 2019 23:04:33 +0000 (15:04 -0800)
18 files changed:
diagnostics.sln
eng/Build-Native.cmd
eng/build-native.sh
src/SOS/SOS.Hosting/Amd64Context.cs [new file with mode: 0644]
src/SOS/SOS.Hosting/AssemblyResolver.cs [new file with mode: 0644]
src/SOS/SOS.Hosting/ISOSHostContext.cs [new file with mode: 0644]
src/SOS/SOS.Hosting/LLDBServicesWrapper.cs [new file with mode: 0644]
src/SOS/SOS.Hosting/SOS.Hosting.csproj [new file with mode: 0644]
src/SOS/SOS.Hosting/SOSHost.cs [new file with mode: 0644]
src/SOS/SOS.NETCore/SymbolReader.cs
src/SOS/SOS.NETCore/Tracer.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 [new file with mode: 0644]

index a4f7cac454cfc222798ede524470aa2494585ae8..fa4e6d875b414147d1df5015d5f99e1a2d66e847 100644 (file)
@@ -597,6 +597,46 @@ Global
                {41351955-16D5-48D7-AF4C-AF25F5FB2E78}.RelWithDebInfo|x64.Build.0 = Release|Any CPU
                {41351955-16D5-48D7-AF4C-AF25F5FB2E78}.RelWithDebInfo|x86.ActiveCfg = Release|Any CPU
                {41351955-16D5-48D7-AF4C-AF25F5FB2E78}.RelWithDebInfo|x86.Build.0 = Release|Any CPU
+               {ED27F39F-DF5C-4E22-87E0-EC5B5873B503}.Checked|Any CPU.ActiveCfg = Debug|Any CPU
+               {ED27F39F-DF5C-4E22-87E0-EC5B5873B503}.Checked|Any CPU.Build.0 = Debug|Any CPU
+               {ED27F39F-DF5C-4E22-87E0-EC5B5873B503}.Checked|ARM.ActiveCfg = Debug|Any CPU
+               {ED27F39F-DF5C-4E22-87E0-EC5B5873B503}.Checked|ARM.Build.0 = Debug|Any CPU
+               {ED27F39F-DF5C-4E22-87E0-EC5B5873B503}.Checked|ARM64.ActiveCfg = Debug|Any CPU
+               {ED27F39F-DF5C-4E22-87E0-EC5B5873B503}.Checked|ARM64.Build.0 = Debug|Any CPU
+               {ED27F39F-DF5C-4E22-87E0-EC5B5873B503}.Checked|x64.ActiveCfg = Debug|Any CPU
+               {ED27F39F-DF5C-4E22-87E0-EC5B5873B503}.Checked|x64.Build.0 = Debug|Any CPU
+               {ED27F39F-DF5C-4E22-87E0-EC5B5873B503}.Checked|x86.ActiveCfg = Debug|Any CPU
+               {ED27F39F-DF5C-4E22-87E0-EC5B5873B503}.Checked|x86.Build.0 = Debug|Any CPU
+               {ED27F39F-DF5C-4E22-87E0-EC5B5873B503}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+               {ED27F39F-DF5C-4E22-87E0-EC5B5873B503}.Debug|Any CPU.Build.0 = Debug|Any CPU
+               {ED27F39F-DF5C-4E22-87E0-EC5B5873B503}.Debug|ARM.ActiveCfg = Debug|Any CPU
+               {ED27F39F-DF5C-4E22-87E0-EC5B5873B503}.Debug|ARM.Build.0 = Debug|Any CPU
+               {ED27F39F-DF5C-4E22-87E0-EC5B5873B503}.Debug|ARM64.ActiveCfg = Debug|Any CPU
+               {ED27F39F-DF5C-4E22-87E0-EC5B5873B503}.Debug|ARM64.Build.0 = Debug|Any CPU
+               {ED27F39F-DF5C-4E22-87E0-EC5B5873B503}.Debug|x64.ActiveCfg = Debug|Any CPU
+               {ED27F39F-DF5C-4E22-87E0-EC5B5873B503}.Debug|x64.Build.0 = Debug|Any CPU
+               {ED27F39F-DF5C-4E22-87E0-EC5B5873B503}.Debug|x86.ActiveCfg = Debug|Any CPU
+               {ED27F39F-DF5C-4E22-87E0-EC5B5873B503}.Debug|x86.Build.0 = Debug|Any CPU
+               {ED27F39F-DF5C-4E22-87E0-EC5B5873B503}.Release|Any CPU.ActiveCfg = Release|Any CPU
+               {ED27F39F-DF5C-4E22-87E0-EC5B5873B503}.Release|Any CPU.Build.0 = Release|Any CPU
+               {ED27F39F-DF5C-4E22-87E0-EC5B5873B503}.Release|ARM.ActiveCfg = Release|Any CPU
+               {ED27F39F-DF5C-4E22-87E0-EC5B5873B503}.Release|ARM.Build.0 = Release|Any CPU
+               {ED27F39F-DF5C-4E22-87E0-EC5B5873B503}.Release|ARM64.ActiveCfg = Release|Any CPU
+               {ED27F39F-DF5C-4E22-87E0-EC5B5873B503}.Release|ARM64.Build.0 = Release|Any CPU
+               {ED27F39F-DF5C-4E22-87E0-EC5B5873B503}.Release|x64.ActiveCfg = Release|Any CPU
+               {ED27F39F-DF5C-4E22-87E0-EC5B5873B503}.Release|x64.Build.0 = Release|Any CPU
+               {ED27F39F-DF5C-4E22-87E0-EC5B5873B503}.Release|x86.ActiveCfg = Release|Any CPU
+               {ED27F39F-DF5C-4E22-87E0-EC5B5873B503}.Release|x86.Build.0 = Release|Any CPU
+               {ED27F39F-DF5C-4E22-87E0-EC5B5873B503}.RelWithDebInfo|Any CPU.ActiveCfg = Release|Any CPU
+               {ED27F39F-DF5C-4E22-87E0-EC5B5873B503}.RelWithDebInfo|Any CPU.Build.0 = Release|Any CPU
+               {ED27F39F-DF5C-4E22-87E0-EC5B5873B503}.RelWithDebInfo|ARM.ActiveCfg = Release|Any CPU
+               {ED27F39F-DF5C-4E22-87E0-EC5B5873B503}.RelWithDebInfo|ARM.Build.0 = Release|Any CPU
+               {ED27F39F-DF5C-4E22-87E0-EC5B5873B503}.RelWithDebInfo|ARM64.ActiveCfg = Release|Any CPU
+               {ED27F39F-DF5C-4E22-87E0-EC5B5873B503}.RelWithDebInfo|ARM64.Build.0 = Release|Any CPU
+               {ED27F39F-DF5C-4E22-87E0-EC5B5873B503}.RelWithDebInfo|x64.ActiveCfg = Release|Any CPU
+               {ED27F39F-DF5C-4E22-87E0-EC5B5873B503}.RelWithDebInfo|x64.Build.0 = Release|Any CPU
+               {ED27F39F-DF5C-4E22-87E0-EC5B5873B503}.RelWithDebInfo|x86.ActiveCfg = Release|Any CPU
+               {ED27F39F-DF5C-4E22-87E0-EC5B5873B503}.RelWithDebInfo|x86.Build.0 = Release|Any CPU
                {90CF2633-58F0-44EE-943B-D70207455F20}.Checked|Any CPU.ActiveCfg = Debug|Any CPU
                {90CF2633-58F0-44EE-943B-D70207455F20}.Checked|Any CPU.Build.0 = Debug|Any CPU
                {90CF2633-58F0-44EE-943B-D70207455F20}.Checked|ARM.ActiveCfg = Debug|Any CPU
@@ -659,6 +699,7 @@ Global
                {20EBC3C4-917C-402D-B778-9A6E3742BF5A} = {41638A4C-0DAF-47ED-A774-ECBBAC0315D7}
                {1F012743-941B-4915-8C55-02097894CF3F} = {41638A4C-0DAF-47ED-A774-ECBBAC0315D7}
                {41351955-16D5-48D7-AF4C-AF25F5FB2E78} = {B62728C8-1267-4043-B46F-5537BBAEC692}
+               {ED27F39F-DF5C-4E22-87E0-EC5B5873B503} = {41638A4C-0DAF-47ED-A774-ECBBAC0315D7}
                {90CF2633-58F0-44EE-943B-D70207455F20} = {19FAB78C-3351-4911-8F0C-8C6056401740}
        EndGlobalSection
        GlobalSection(ExtensibilityGlobals) = postSolution
index a810a095ba93b1bb90c6b7e7401e40274ce2ed0d..e847566b0160e9770bbc43305c8d89011f7c81b2 100644 (file)
@@ -331,6 +331,13 @@ if /i "%__DoCrossArchBuild%"=="1" (
     endlocal
 )
 
+REM Copy the native SOS binaries to where these tools expect for testing
+
+set "__dotnet_sos=%__RootBinDir%\bin\dotnet-sos\%__BuildType%\netcoreapp2.1\publish\win-%__BuildArch%"
+set "__dotnet_dump=%__RootBinDir%\bin\dotnet-dump\%__BuildType%\netcoreapp2.1\publish\win-%__BuildArch%"
+xcopy /y /q /i /s %__BinDir% %__dotnet_sos%
+xcopy /y /q /i /s %__BinDir% %__dotnet_dump%
+
 REM =========================================================================================
 REM ===
 REM === All builds complete!
index deb6c858c6120e9e3f83004069fdfc0589294d8a..473915a19a3c6d2fba6c1ab8d66482de4436169b 100755 (executable)
@@ -469,6 +469,14 @@ if [ $__Build == true ]; then
     fi
 
     build_native "$__BuildArch" "$__IntermediatesDir" "$__ExtraCmakeArgs"
+
+    # Copy the native SOS binaries to where these tools expect for testing
+    __dotnet_sos=$__RootBinDir/bin/dotnet-sos/$__BuildType/netcoreapp2.1/publish/$__DistroRid
+    __dotnet_dump=$__RootBinDir/bin/dotnet-dump/$__BuildType/netcoreapp2.1/publish/$__DistroRid
+    mkdir -p "$__dotnet_sos"
+    mkdir -p "$__dotnet_dump"
+    cp "$__BinDir"/* "$__dotnet_sos"
+    cp "$__BinDir"/* "$__dotnet_dump"
 fi
 
 # Run SOS/lldbplugin tests
diff --git a/src/SOS/SOS.Hosting/Amd64Context.cs b/src/SOS/SOS.Hosting/Amd64Context.cs
new file mode 100644 (file)
index 0000000..c7030aa
--- /dev/null
@@ -0,0 +1,114 @@
+// 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.
+
+using System.Runtime.InteropServices;
+
+namespace SOS
+{
+    [StructLayout(LayoutKind.Explicit)]
+    internal struct AMD64Context
+    {
+        [FieldOffset(0x0)]
+        public ulong P1Home;
+        [FieldOffset(0x8)]
+        public ulong P2Home;
+        [FieldOffset(0x10)]
+        public ulong P3Home;
+        [FieldOffset(0x18)]
+        public ulong P4Home;
+        [FieldOffset(0x20)]
+        public ulong P5Home;
+        [FieldOffset(0x28)]
+        public ulong P6Home;
+
+        [FieldOffset(0x30)]
+        public int ContextFlags;
+
+        [FieldOffset(0x34)]
+        public int MxCsr;
+
+        [FieldOffset(0x38)]
+        public short SegCs;
+        [FieldOffset(0x3a)]
+        public short SegDs;
+        [FieldOffset(0x3c)]
+        public short SegEs;
+        [FieldOffset(0x3e)]
+        public short SegFs;
+        [FieldOffset(0x40)]
+        public short SegGs;
+        [FieldOffset(0x42)]
+        public short SegSs;
+        [FieldOffset(0x44)]
+        public int EFlags;
+
+        [FieldOffset(0x48)]
+        public ulong Dr0;
+        [FieldOffset(0x50)]
+        public ulong Dr1;
+        [FieldOffset(0x58)]
+        public ulong Dr2;
+        [FieldOffset(0x60)]
+        public ulong Dr3;
+        [FieldOffset(0x68)]
+        public ulong Dr6;
+        [FieldOffset(0x70)]
+        public ulong Dr7;
+
+        [FieldOffset(0x78)]
+        public ulong Rax;
+        [FieldOffset(0x80)]
+        public ulong Rcx;
+        [FieldOffset(0x88)]
+        public ulong Rdx;
+        [FieldOffset(0x90)]
+        public ulong Rbx;
+        [FieldOffset(0x98)]
+        public ulong Rsp;
+        [FieldOffset(0xa0)]
+        public ulong Rbp;
+        [FieldOffset(0xa8)]
+        public ulong Rsi;
+        [FieldOffset(0xb0)]
+        public ulong Rdi;
+        [FieldOffset(0xb8)]
+        public ulong R8;
+        [FieldOffset(0xc0)]
+        public ulong R9;
+        [FieldOffset(0xc8)]
+        public ulong R10;
+        [FieldOffset(0xd0)]
+        public ulong R11;
+        [FieldOffset(0xd8)]
+        public ulong R12;
+        [FieldOffset(0xe0)]
+        public ulong R13;
+        [FieldOffset(0xe8)]
+        public ulong R14;
+        [FieldOffset(0xf0)]
+        public ulong R15;
+
+        [FieldOffset(0xf8)]
+        public ulong Rip;
+
+        //[FieldOffset(0x100)]
+        //public XmmSaveArea FltSave;
+
+        //[FieldOffset(0x300)]
+        //public VectorRegisterArea VectorRegisters;
+
+        [FieldOffset(0x4a8)]
+        public ulong DebugControl;
+        [FieldOffset(0x4b0)]
+        public ulong LastBranchToRip;
+        [FieldOffset(0x4b8)]
+        public ulong LastBranchFromRip;
+        [FieldOffset(0x4c0)]
+        public ulong LastExceptionToRip;
+        [FieldOffset(0x4c8)]
+        public ulong LastExceptionFromRip;
+
+        public static int Size => Marshal.SizeOf(typeof(AMD64Context));
+    }
+}
\ No newline at end of file
diff --git a/src/SOS/SOS.Hosting/AssemblyResolver.cs b/src/SOS/SOS.Hosting/AssemblyResolver.cs
new file mode 100644 (file)
index 0000000..a6734c7
--- /dev/null
@@ -0,0 +1,102 @@
+// 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.
+
+using System;
+using System.Diagnostics;
+using System.IO;
+using System.Reflection;
+
+namespace SOS
+{
+    /// <summary>
+    /// Used to enable app-local assembly unification.
+    /// </summary>
+    internal static class AssemblyResolver
+    {
+        static AssemblyResolver()
+        {
+            AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;
+        }
+
+        /// <summary>
+        /// Call to enable the assembly resolver for the current AppDomain.
+        /// </summary>
+        public static void Enable()
+        {
+            // intentionally empty.  This is just meant to ensure the static constructor
+            // has run.
+        }
+
+        private static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
+        {
+            // apply any existing policy
+            AssemblyName referenceName = new AssemblyName(AppDomain.CurrentDomain.ApplyPolicy(args.Name));
+
+            string fileName = referenceName.Name + ".dll";
+            string assemblyPath = null;
+            string probingPath = null;
+            Assembly assm = null;
+
+            // look next to requesting assembly
+            assemblyPath = args.RequestingAssembly?.Location;
+            if (!String.IsNullOrEmpty(assemblyPath))
+            {
+                probingPath = Path.Combine(Path.GetDirectoryName(assemblyPath), fileName);
+                Debug.WriteLine($"Considering {probingPath} based on RequestingAssembly");
+                if (Probe(probingPath, referenceName.Version, out assm))
+                {
+                    return assm;
+                }
+            }
+
+            // look next to the executing assembly
+            assemblyPath = Assembly.GetExecutingAssembly().Location;
+            if (!String.IsNullOrEmpty(assemblyPath))
+            {
+                probingPath = Path.Combine(Path.GetDirectoryName(assemblyPath), fileName);
+
+                Debug.WriteLine($"Considering {probingPath} based on ExecutingAssembly");
+                if (Probe(probingPath, referenceName.Version, out assm))
+                {
+                    return assm;
+                }
+            }
+
+            // look in AppDomain base directory
+            probingPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, fileName);
+            Debug.WriteLine($"Considering {probingPath} based on BaseDirectory");
+            if (Probe(probingPath, referenceName.Version, out assm))
+            {
+                return assm;
+            }
+
+            return null;
+        }
+
+        /// <summary>
+        /// Considers a path to load for satisfying an assembly ref and loads it
+        /// if the file exists and version is sufficient.
+        /// </summary>
+        /// <param name="filePath">Path to consider for load</param>
+        /// <param name="minimumVersion">Minimum version to consider</param>
+        /// <param name="assembly">loaded assembly</param>
+        /// <returns>true if assembly was loaded</returns>
+        private static bool Probe(string filePath, Version minimumVersion, out Assembly assembly)
+        {
+            if (File.Exists(filePath))
+            {
+                AssemblyName name = AssemblyName.GetAssemblyName(filePath);
+
+                if (name.Version >= minimumVersion)
+                {
+                    assembly = Assembly.LoadFile(filePath);
+                    return true;
+                }
+            }
+
+            assembly = null;
+            return false;
+        }
+    }
+}
diff --git a/src/SOS/SOS.Hosting/ISOSHostContext.cs b/src/SOS/SOS.Hosting/ISOSHostContext.cs
new file mode 100644 (file)
index 0000000..3157a30
--- /dev/null
@@ -0,0 +1,30 @@
+// 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.
+
+using System.Threading;
+
+namespace SOS
+{
+    /// <summary>
+    /// Context/services provided to the SOS host.
+    /// </summary>
+    public interface ISOSHostContext
+    {
+        /// <summary>
+        /// Display text on the console
+        /// </summary>
+        /// <param name="text">message</param>
+        void Write(string text);
+
+        /// <summary>
+        /// Get/set the current native thread id
+        /// </summary>
+        int CurrentThreadId { get; set; }
+
+        /// <summary>
+        /// Cancellation token for current operation
+        /// </summary>
+        CancellationToken CancellationToken { get; }
+    }
+}
\ No newline at end of file
diff --git a/src/SOS/SOS.Hosting/LLDBServicesWrapper.cs b/src/SOS/SOS.Hosting/LLDBServicesWrapper.cs
new file mode 100644 (file)
index 0000000..74670f5
--- /dev/null
@@ -0,0 +1,1065 @@
+// 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.
+
+using Microsoft.Diagnostics.Runtime;
+using Microsoft.Diagnostics.Runtime.Interop;
+using Microsoft.Diagnostics.Runtime.Utilities;
+using System;
+using System.Diagnostics;
+using System.Globalization;
+using System.IO;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Text;
+
+namespace SOS
+{
+    internal unsafe class LLDBServicesWrapper : COMCallableIUnknown
+    {
+        private static readonly Guid IID_ILLDBServices = new Guid("2E6C569A-9E14-4DA4-9DFC-CDB73A532566");
+        private static readonly Guid IID_ILLDBServices2 = new Guid("012F32F0-33BA-4E8E-BC01-037D382D8A5E");
+        private static readonly Guid IID_SOSHostServices = new Guid("D13608FB-AD14-4B49-990A-80284F934C41");
+
+        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);
+
+        #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;
+        }
+
+        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,
+        };
+
+        static readonly string s_coreclrModuleName = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? "coreclr" : "libcoreclr.so";
+
+        readonly SOSHost _sosHost;
+        readonly IDataReader _dataReader;
+        readonly ISOSHostContext _context;
+
+        /// <summary>
+        /// Create an instance of the service wrapper SOS uses.
+        /// </summary>
+        /// <param name="dataReader">clrmd data reader instance</param>
+        /// <param name="context">sos hosting context</param>
+        public LLDBServicesWrapper(SOSHost host, IDataReader dataReader, ISOSHostContext context)
+        {
+            _sosHost = host;
+            _dataReader = dataReader;
+            _context = context;
+
+            VTableBuilder builder = AddInterface(IID_ILLDBServices, validate: false);
+
+            builder.AddMethod(new GetCoreClrDirectoryDelegate(GetCoreClrDirectory));
+            builder.AddMethod(new GetExpressionDelegate(GetExpression));
+            builder.AddMethod(new VirtualUnwindDelegate(VirtualUnwind));
+            builder.AddMethod(new SetExceptionCallbackDelegate(SetExceptionCallback));
+            builder.AddMethod(new ClearExceptionCallbackDelegate(ClearExceptionCallback));
+
+            builder.AddMethod(new GetInterruptDelegate(GetInterrupt));
+            builder.AddMethod(new OutputVaListDelegate(OutputVaList));
+            builder.AddMethod(new GetDebuggerTypeDelegate(GetDebuggerType));
+            builder.AddMethod(new GetPageSizeDelegate(GetPageSize));
+            builder.AddMethod(new GetExecutingProcessorTypeDelegate(GetExecutingProcessorType));
+            builder.AddMethod(new ExecuteDelegate(Execute));
+            builder.AddMethod(new GetLastEventInformationDelegate(GetLastEventInformation));
+            builder.AddMethod(new DisassembleDelegate(Disassemble));
+
+            builder.AddMethod(new GetContextStackTraceDelegate(GetContextStackTrace));
+            builder.AddMethod(new ReadVirtualDelegate(ReadVirtual));
+            builder.AddMethod(new WriteVirtualDelegate(WriteVirtual));
+
+            builder.AddMethod(new GetSymbolOptionsDelegate(GetSymbolOptions));
+            builder.AddMethod(new GetNameByOffsetDelegate(GetNameByOffset));
+            builder.AddMethod(new GetNumberModulesDelegate(GetNumberModules));
+            builder.AddMethod(new GetModuleByIndexDelegate(GetModuleByIndex));
+            builder.AddMethod(new GetModuleByModuleNameDelegate(GetModuleByModuleName));
+            builder.AddMethod(new GetModuleByOffsetDelegate(GetModuleByOffset));
+            builder.AddMethod(new GetModuleNamesDelegate(GetModuleNames));
+            builder.AddMethod(new GetLineByOffsetDelegate(GetLineByOffset));
+            builder.AddMethod(new GetSourceFileLineOffsetsDelegate(GetSourceFileLineOffsets));
+            builder.AddMethod(new FindSourceFileDelegate(FindSourceFile));
+
+            builder.AddMethod(new GetCurrentProcessIdDelegate(GetCurrentProcessId));
+            builder.AddMethod(new GetCurrentThreadIdDelegate(GetCurrentThreadId));
+            builder.AddMethod(new SetCurrentThreadIdDelegate(SetCurrentThreadId));
+            builder.AddMethod(new GetCurrentThreadSystemIdDelegate(GetCurrentThreadSystemId));
+            builder.AddMethod(new GetThreadIdBySystemIdDelegate(GetThreadIdBySystemId));
+            builder.AddMethod(new GetThreadContextByIdDelegate(GetThreadContextById));
+
+            builder.AddMethod(new GetValueByNameDelegate(GetValueByName));
+            builder.AddMethod(new GetInstructionOffsetDelegate(GetInstructionOffset));
+            builder.AddMethod(new GetStackOffsetDelegate(GetStackOffset));
+            builder.AddMethod(new GetFrameOffsetDelegate(GetFrameOffset));
+
+            ILLDBServices = builder.Complete();
+
+            builder = AddInterface(IID_ILLDBServices2, validate: false);
+            builder.AddMethod(new LoadNativeSymbolsDelegate2(LoadNativeSymbols2));
+            builder.AddMethod(new AddModuleSymbolDelegate(AddModuleSymbol));
+            builder.Complete();
+
+            builder = AddInterface(IID_SOSHostServices, validate: false);
+            builder.AddMethod(new GetSOSNETCoreCallbacksDelegate(GetSOSNETCoreCallbacks));
+            builder.Complete();
+
+            AddRef();
+        }
+
+        #region ILLDBServices
+
+        string GetCoreClrDirectory(
+            IntPtr self)
+        {
+            foreach (ModuleInfo module in _dataReader.EnumerateModules())
+            {
+                if (string.Equals(Path.GetFileName(module.FileName), s_coreclrModuleName))
+                {
+                    return Path.GetDirectoryName(module.FileName) + Path.DirectorySeparatorChar;
+                }
+            }
+            return null;
+        }
+
+        ulong GetExpression(
+            IntPtr self,
+            string text)
+        {
+            if (ulong.TryParse(text.Replace("0x", ""), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out ulong result)) {
+                return result;
+            }
+            return 0;
+        }
+
+        int VirtualUnwind(
+            IntPtr self,
+            uint threadId,
+            uint contextSize,
+            byte[] context)
+        {
+            return E_NOTIMPL;
+        }
+
+        int SetExceptionCallback(
+            IntPtr self,
+            PFN_EXCEPTION_CALLBACK callback)
+        {
+            return S_OK;
+        }
+
+        int ClearExceptionCallback(
+            IntPtr self)
+        {
+            return S_OK;
+        }
+
+        int GetInterrupt(
+            IntPtr self)
+        {
+            return _context.CancellationToken.IsCancellationRequested ? S_OK : E_FAIL;
+        }
+
+        int OutputVaList(
+            IntPtr self,
+            DEBUG_OUTPUT mask,
+            string format,
+            IntPtr va_list)
+        {
+            try
+            {
+                _context.Write(format);
+            }
+            catch (OperationCanceledException)
+            {
+                // ctrl-c interrupted the command
+            }
+            return S_OK;
+        }
+
+        int GetDebuggerType(
+            IntPtr self,
+            out DEBUG_CLASS debugClass,
+            out DEBUG_CLASS_QUALIFIER qualifier)
+        {
+            debugClass = DEBUG_CLASS.USER_WINDOWS;
+            qualifier = DEBUG_CLASS_QUALIFIER.USER_WINDOWS_DUMP;
+            return S_OK;
+        }
+
+        int GetPageSize(
+            IntPtr self,
+            out uint size)
+        {
+            size = 4096;
+            return S_OK;
+        }
+
+        int GetExecutingProcessorType(
+            IntPtr self,
+            out IMAGE_FILE_MACHINE type)
+        {
+            switch (_dataReader.GetArchitecture())
+            {
+                case Microsoft.Diagnostics.Runtime.Architecture.Amd64:
+                    type = IMAGE_FILE_MACHINE.AMD64;
+                    break;
+                case Microsoft.Diagnostics.Runtime.Architecture.X86:
+                    type = IMAGE_FILE_MACHINE.I386;
+                    break;
+                case Microsoft.Diagnostics.Runtime.Architecture.Arm:
+                    type = IMAGE_FILE_MACHINE.ARM;
+                    break;
+                default:
+                    type = IMAGE_FILE_MACHINE.UNKNOWN;
+                    break;
+            }
+            return S_OK;
+        }
+
+        int Execute(
+            IntPtr self,
+            DEBUG_OUTCTL outputControl,
+            string command,
+            DEBUG_EXECUTE flags)
+        {
+            return E_NOTIMPL;
+        }
+
+        int GetLastEventInformation(
+            IntPtr self,
+            out uint type,
+            out uint processId,
+            out uint threadId,
+            IntPtr extraInformation,
+            uint extraInformationSize,
+            out uint extraInformationUsed,
+            string description,
+            uint descriptionSize,
+            out uint descriptionUsed)
+        {
+            type = 0;
+            processId = 0;
+            threadId = 0;
+            extraInformationSize = 0;
+            extraInformationUsed = 0;
+            descriptionUsed = 0;
+            return E_NOTIMPL;
+        }
+
+        int Disassemble(
+            IntPtr self,
+            ulong offset,
+            DEBUG_DISASM flags,
+            StringBuilder buffer,
+            uint bufferSize,
+            out uint disassemblySize,
+            out ulong endOffset)
+        {
+            disassemblySize = 0;
+            endOffset = 0;
+            return E_NOTIMPL;
+        }
+
+        int GetContextStackTrace(
+            IntPtr self,
+            IntPtr startContext,
+            uint startContextSize,
+            DEBUG_STACK_FRAME[] frames,
+            uint framesSize,
+            IntPtr frameContexts,
+            uint frameContextsSize,
+            uint frameContextsEntrySize,
+            IntPtr pframesFilled)
+        {
+            return E_NOTIMPL;
+        }
+
+        int ReadVirtual(
+            IntPtr self,
+            ulong address,
+            IntPtr buffer,
+            int bytesRequested,
+            IntPtr pbytesRead)
+        {
+            if (_dataReader.ReadMemory(address, buffer, bytesRequested, out int bytesRead))
+            {
+                if (pbytesRead != IntPtr.Zero)
+                {
+                    Marshal.WriteInt32(pbytesRead, bytesRead);
+                }
+                return S_OK;
+            }
+            return E_FAIL;
+        }
+
+        int WriteVirtual(
+            IntPtr self,
+            ulong address,
+            IntPtr buffer,
+            uint bytesRequested,
+            IntPtr pbytesWritten)
+        {
+            // This gets used by MemoryBarrier() calls in the dac, which really shouldn't matter what we do here.
+            if (pbytesWritten != IntPtr.Zero) {
+                Marshal.WriteInt32(pbytesWritten, (int)bytesRequested);
+            }
+            return S_OK;
+        }
+
+        int GetSymbolOptions(
+            IntPtr self,
+            out SYMOPT options)
+        {
+            options = SYMOPT.LOAD_LINES; 
+            return S_OK;
+        }
+
+        int GetNameByOffset(
+            IntPtr self,
+            ulong offset,
+            StringBuilder nameBuffer,
+            uint nameBufferSize,
+            out uint nameSize,
+            out ulong displacement)
+        {
+            nameSize = 0;
+            displacement = 0;
+            return E_NOTIMPL;
+        }
+
+        int GetNumberModules(
+            IntPtr self,
+            out uint loaded,
+            out uint unloaded)
+        {
+            loaded = (uint)_dataReader.EnumerateModules().Count();
+            unloaded = 0;
+            return S_OK;
+        }
+
+        int GetModuleByIndex(
+            IntPtr self,
+            uint index,
+            out ulong baseAddress)
+        {
+            baseAddress = 0;
+
+            try
+            {
+                ModuleInfo module = _dataReader.EnumerateModules().ElementAt((int)index);
+                if (module == null)
+                {
+                    return E_FAIL;
+                }
+                baseAddress = module.ImageBase;
+            }
+            catch (ArgumentOutOfRangeException)
+            {
+                return E_FAIL;
+            }
+
+            return S_OK;
+        }
+
+        int GetModuleByModuleName(
+            IntPtr self,
+            string name,
+            uint startIndex,
+            IntPtr pIndex,
+            out ulong baseAddress)
+        {
+            // The returned "index" is never used by SOS. Always passes startIndex = 0;
+            Debug.Assert(pIndex == IntPtr.Zero);
+            Debug.Assert(startIndex == 0);
+
+            baseAddress = 0;
+
+            foreach (ModuleInfo module in _dataReader.EnumerateModules())
+            {
+                if (string.Equals(Path.GetFileName(module.FileName), name))
+                {
+                    baseAddress = module.ImageBase;
+                    return S_OK;
+                }
+            }
+            return E_FAIL;
+        }
+
+        int GetModuleByOffset(
+            IntPtr self,
+            ulong offset,
+            uint startIndex,
+            out uint index,
+            out ulong baseAddress)
+        {
+            index = 0;
+            baseAddress = 0;
+            return E_NOTIMPL;
+        }
+
+        int GetModuleNames(
+            IntPtr self,
+            uint index,
+            ulong baseAddress,
+            StringBuilder imageNameBuffer,
+            uint imageNameBufferSize,
+            out uint imageNameSize,
+            StringBuilder moduleNameBuffer,
+            uint ModuleNameBufferSize,
+            out uint moduleNameSize,
+            StringBuilder loadedImageNameBuffer,
+            uint loadedImageNameBufferSize,
+            out uint loadedImageNameSize)
+        {
+            imageNameSize = 0;
+            moduleNameSize = 0;
+            loadedImageNameSize = 0;
+            return E_NOTIMPL;
+        }
+
+        int GetLineByOffset(
+            IntPtr self,
+            ulong offset,
+            out uint line,
+            StringBuilder fileBuffer,
+            uint fileBufferSize,
+            out uint fileSize,
+            out ulong displacement)
+        {
+            line = 0;
+            fileSize = 0;
+            displacement = 0;
+            return E_NOTIMPL;
+        }
+
+        int GetSourceFileLineOffsets(
+            IntPtr self,
+            string file,
+            ulong[] buffer,
+            uint bufferLines,
+            out uint fileLines)
+        {
+            fileLines = 0;
+            return E_NOTIMPL;
+        }
+
+        int FindSourceFile(
+            IntPtr self,
+            uint startElement,
+            string file,
+            uint flags,
+            out uint foundElement,
+            StringBuilder buffer,
+            uint bufferSize,
+            out uint foundSize)
+        {
+            foundElement = 0;
+            foundSize = 0;
+            return E_NOTIMPL;
+        }
+
+        int GetCurrentProcessId(
+            IntPtr self,
+            out uint id)
+        {
+            id = 0;
+            if (_dataReader is IDataReader2 dataReader2) {
+                id = dataReader2.ProcessId;
+            }
+            return S_OK;
+        }
+
+        int GetCurrentThreadId(
+            IntPtr self,
+            out uint id)
+        {
+            return GetThreadIdBySystemId(self, (uint)_context.CurrentThreadId, out id);
+        }
+
+        int SetCurrentThreadId(
+            IntPtr self,
+            uint id)
+        {
+            try
+            {
+                unchecked {
+                    _context.CurrentThreadId = (int)_dataReader.EnumerateAllThreads().ElementAt((int)id);
+                }
+            }
+            catch (ArgumentOutOfRangeException)
+            {
+                return E_FAIL;
+            }
+            return S_OK;
+        }
+
+        int GetCurrentThreadSystemId(
+            IntPtr self,
+            out uint sysId)
+        {
+            sysId = (uint)_context.CurrentThreadId;
+            return S_OK;
+        }
+
+        int GetThreadIdBySystemId(
+            IntPtr self,
+            uint sysId,
+            out uint id)
+        {
+            id = 0;
+            if (sysId != 0)
+            {
+                foreach (uint s in _dataReader.EnumerateAllThreads())
+                {
+                    if (s == sysId) {
+                        return S_OK;
+                    }
+                    id++;
+                }
+            }
+            return E_FAIL;
+        }
+
+        int GetThreadContextById(
+            IntPtr self,
+            uint threadId,
+            uint contextFlags,
+            uint contextSize,
+            IntPtr context)
+        {
+            if (_dataReader.GetThreadContext(threadId, contextFlags, contextSize, context)) {
+                return S_OK;
+            }
+            return E_FAIL;
+        }
+
+        int GetValueByName(
+            IntPtr self,
+            string name,
+            out ulong value)
+        {
+            return GetRegister(name, out value);
+        }
+
+        int GetInstructionOffset(
+            IntPtr self,
+            out ulong offset)
+        {
+            // TODO: Support other architectures
+            return GetRegister("rip", out offset);
+        }
+
+        int GetStackOffset(
+            IntPtr self,
+            out ulong offset)
+        {
+            // TODO: Support other architectures
+            return GetRegister("rsp", out offset);
+        }
+
+        int GetFrameOffset(
+            IntPtr self,
+            out ulong offset)
+        {
+            // TODO: Support other architectures
+            return GetRegister("rbp", out offset);
+        }
+
+        #endregion 
+
+        // TODO: Support other architectures
+        int GetRegister(string register, out ulong value)
+        {
+            value = 0;
+            int hr = GetCurrentThreadSystemId(IntPtr.Zero, out uint threadId);
+            if (hr != 0) {
+                return hr;
+            }
+            byte[] buffer = new byte[AMD64Context.Size];
+            if (!_dataReader.GetThreadContext(threadId, uint.MaxValue, (uint)AMD64Context.Size, buffer))
+            {
+                return E_FAIL;
+            }
+            fixed (byte* ptr = buffer)
+            {
+                AMD64Context* context = (AMD64Context*)ptr;
+                switch (register.ToLower())
+                {
+                    case "rax":
+                        value = context->Rax;
+                        break;
+                    case "rbx":
+                        value = context->Rbx;
+                        break;
+                    case "rcx":
+                        value = context->Rcx;
+                        break;
+                    case "rdx":
+                        value = context->Rdx;
+                        break;
+                    case "rsi":
+                        value = context->Rsi;
+                        break;
+                    case "rdi":
+                        value = context->Rdi;
+                        break;
+                    case "r8":
+                        value = context->R8;
+                        break;
+                    case "r9":
+                        value = context->R9;
+                        break;
+                    case "r10":
+                        value = context->R10;
+                        break;
+                    case "r11":
+                        value = context->R11;
+                        break;
+                    case "r12":
+                        value = context->R12;
+                        break;
+                    case "r13":
+                        value = context->R13;
+                        break;
+                    case "r14":
+                        value = context->R14;
+                        break;
+                    case "r15":
+                        value = context->R15;
+                        break;
+                    case "rip":
+                        value = context->Rip;
+                        break;
+                    case "rsp":
+                        value = context->Rsp;
+                        break;
+                    case "rbp":
+                        value = context->Rbp;
+                        break;
+                    default:
+                        return E_FAIL;
+                }
+            }
+            return S_OK;
+        }
+
+        #region ILLDBServices2
+
+        int LoadNativeSymbols2(
+            IntPtr self,
+            bool runtimeOnly,
+            ModuleLoadCallback callback)
+        {
+            foreach (ModuleInfo module in _dataReader.EnumerateModules())
+            {
+                callback(IntPtr.Zero, module.FileName, module.ImageBase, unchecked((int)module.FileSize));
+            }
+            return S_OK;
+        }
+
+        int AddModuleSymbol(
+            IntPtr self,
+            IntPtr parameter,
+            string symbolFilename)
+        {
+            return S_OK;
+        }
+
+        #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)]
+        [return: MarshalAs(UnmanagedType.LPStr)]
+        private delegate string GetCoreClrDirectoryDelegate(
+            IntPtr self);
+
+        [UnmanagedFunctionPointer(CallingConvention.StdCall)]
+        private delegate ulong GetExpressionDelegate(
+            IntPtr self,
+            [In][MarshalAs(UnmanagedType.LPStr)] string text);
+
+        [UnmanagedFunctionPointer(CallingConvention.StdCall)]
+        private delegate int VirtualUnwindDelegate(
+            IntPtr self,
+            uint threadId,
+            uint contextSize,
+            byte[] context);
+
+        [UnmanagedFunctionPointer(CallingConvention.StdCall)]
+        private delegate int PFN_EXCEPTION_CALLBACK(LLDBServicesWrapper services);
+
+        [UnmanagedFunctionPointer(CallingConvention.StdCall)]
+        private delegate int SetExceptionCallbackDelegate(
+            IntPtr self,
+            PFN_EXCEPTION_CALLBACK callback);
+
+        [UnmanagedFunctionPointer(CallingConvention.StdCall)]
+        private delegate int ClearExceptionCallbackDelegate(
+            IntPtr self);
+
+        [UnmanagedFunctionPointer(CallingConvention.StdCall)]
+        private delegate int GetInterruptDelegate(
+            IntPtr self);
+
+        [UnmanagedFunctionPointer(CallingConvention.StdCall)]
+        private delegate int OutputVaListDelegate(
+            IntPtr self,
+            DEBUG_OUTPUT mask,
+            [In, MarshalAs(UnmanagedType.LPStr)] string format,
+            IntPtr va_list);
+
+        [UnmanagedFunctionPointer(CallingConvention.StdCall)]
+        private delegate int GetDebuggerTypeDelegate(
+            IntPtr self,
+            out DEBUG_CLASS debugClass,
+            out DEBUG_CLASS_QUALIFIER qualifier);
+
+        [UnmanagedFunctionPointer(CallingConvention.StdCall)]
+        private delegate int GetPageSizeDelegate(
+            IntPtr self,
+            out uint size);
+
+        [UnmanagedFunctionPointer(CallingConvention.StdCall)]
+        private delegate int GetExecutingProcessorTypeDelegate(
+            IntPtr self,
+            out IMAGE_FILE_MACHINE type);
+
+        [UnmanagedFunctionPointer(CallingConvention.StdCall)]
+        private delegate int ExecuteDelegate(
+            IntPtr self,
+            DEBUG_OUTCTL outputControl,
+            [In, MarshalAs(UnmanagedType.LPStr)] string command,
+            DEBUG_EXECUTE flags);
+
+        [UnmanagedFunctionPointer(CallingConvention.StdCall)]
+        private delegate int GetLastEventInformationDelegate(
+            IntPtr self,
+            out uint type,
+            out uint processId,
+            out uint threadId,
+            IntPtr extraInformation,
+            uint extraInformationSize,
+            out uint extraInformationUsed,
+            [In][MarshalAs(UnmanagedType.LPStr)] string description,
+            uint descriptionSize,
+            out uint descriptionUsed);
+
+        [UnmanagedFunctionPointer(CallingConvention.StdCall)]
+        private delegate int DisassembleDelegate(
+            IntPtr self,
+            ulong offset,
+            DEBUG_DISASM flags,
+            [Out, MarshalAs(UnmanagedType.LPStr)] StringBuilder buffer,
+            uint bufferSize,
+            out uint disassemblySize,
+            out ulong endOffset);
+
+        [UnmanagedFunctionPointer(CallingConvention.StdCall)]
+        private delegate int GetContextStackTraceDelegate(
+            IntPtr self,
+            IntPtr startContext,
+            uint startContextSize,
+            [Out, MarshalAs(UnmanagedType.LPArray)] DEBUG_STACK_FRAME[] frames,
+            uint framesSize,
+            IntPtr frameContexts,
+            uint frameContextsSize,
+            uint frameContextsEntrySize,
+            IntPtr pframesFilled);
+
+        [UnmanagedFunctionPointer(CallingConvention.StdCall)]
+        private delegate int ReadVirtualDelegate(
+            IntPtr self,
+            ulong address,
+            IntPtr buffer,
+            int bytesRequested,
+            IntPtr pbytesRead);
+
+        [UnmanagedFunctionPointer(CallingConvention.StdCall)]
+        private delegate int WriteVirtualDelegate(
+            IntPtr self,
+            ulong address,
+            IntPtr buffer,
+            uint bytesRequested,
+            IntPtr pbytesWritten);
+
+        [UnmanagedFunctionPointer(CallingConvention.StdCall)]
+        private delegate int GetSymbolOptionsDelegate(
+            IntPtr self,
+            out SYMOPT options);
+
+        [UnmanagedFunctionPointer(CallingConvention.StdCall)]
+        private delegate int GetNameByOffsetDelegate(
+            IntPtr self,
+            ulong offset,
+            [Out, MarshalAs(UnmanagedType.LPStr)] StringBuilder nameBuffer,
+            uint nameBufferSize,
+            out uint nameSize,
+            out ulong displacement);
+
+        [UnmanagedFunctionPointer(CallingConvention.StdCall)]
+        private delegate int GetNumberModulesDelegate(
+            IntPtr self,
+            out uint loaded,
+            out uint unloaded);
+
+        [UnmanagedFunctionPointer(CallingConvention.StdCall)]
+        private delegate int GetModuleByIndexDelegate(
+            IntPtr self,
+            uint index,
+            out ulong baseAddress);
+
+        [UnmanagedFunctionPointer(CallingConvention.StdCall)]
+        private delegate int GetModuleByModuleNameDelegate(
+            IntPtr self,
+            [In, MarshalAs(UnmanagedType.LPStr)] string name,
+            uint startIndex,
+            IntPtr index,
+            out ulong baseAddress);
+
+        [UnmanagedFunctionPointer(CallingConvention.StdCall)]
+        private delegate int GetModuleByOffsetDelegate(
+            IntPtr self,
+            ulong offset,
+            uint startIndex,
+            out uint index,
+            out ulong baseAddress);
+
+        [UnmanagedFunctionPointer(CallingConvention.StdCall)]
+        private delegate int GetModuleNamesDelegate(
+            IntPtr self,
+            uint index,
+            ulong baseAddress,
+            [Out, MarshalAs(UnmanagedType.LPStr)] StringBuilder imageNameBuffer,
+            uint imageNameBufferSize,
+            out uint imageNameSize,
+            [Out, MarshalAs(UnmanagedType.LPStr)] StringBuilder moduleNameBuffer,
+            uint ModuleNameBufferSize,
+            out uint moduleNameSize,
+            [Out, MarshalAs(UnmanagedType.LPStr)] StringBuilder loadedImageNameBuffer,
+            uint loadedImageNameBufferSize,
+            out uint loadedImageNameSize);
+
+        [UnmanagedFunctionPointer(CallingConvention.StdCall)]
+        private delegate int GetLineByOffsetDelegate(
+            IntPtr self,
+            ulong offset,
+            out uint line,
+            [Out, MarshalAs(UnmanagedType.LPStr)] StringBuilder fileBuffer,
+            uint fileBufferSize,
+            out uint fileSize,
+            out ulong displacement);
+
+        [UnmanagedFunctionPointer(CallingConvention.StdCall)]
+        private delegate int GetSourceFileLineOffsetsDelegate(
+            IntPtr self,
+            [In, MarshalAs(UnmanagedType.LPStr)] string file,
+            [Out, MarshalAs(UnmanagedType.LPArray)] ulong[] buffer,
+            uint bufferLines,
+            out uint fileLines);
+
+        [UnmanagedFunctionPointer(CallingConvention.StdCall)]
+        private delegate int FindSourceFileDelegate(
+            IntPtr self,
+            uint startElement,
+            [In, MarshalAs(UnmanagedType.LPStr)] string file,
+            uint flags,
+            out uint foundElement,
+            [Out, MarshalAs(UnmanagedType.LPStr)] StringBuilder buffer,
+            uint bufferSize,
+            out uint foundSize);
+
+        [UnmanagedFunctionPointer(CallingConvention.StdCall)]
+        private delegate int GetCurrentProcessIdDelegate(
+            IntPtr self,
+            out uint id);
+
+        [UnmanagedFunctionPointer(CallingConvention.StdCall)]
+        private delegate int GetCurrentThreadIdDelegate(
+            IntPtr self,
+            out uint id);
+
+        [UnmanagedFunctionPointer(CallingConvention.StdCall)]
+        private delegate int SetCurrentThreadIdDelegate(
+            IntPtr self,
+            uint id);
+
+        [UnmanagedFunctionPointer(CallingConvention.StdCall)]
+        private delegate int GetCurrentThreadSystemIdDelegate(
+            IntPtr self,
+            out uint sysId);
+
+        [UnmanagedFunctionPointer(CallingConvention.StdCall)]
+        private delegate int GetThreadIdBySystemIdDelegate(
+            IntPtr self,
+            uint sysId,
+            out uint id);
+
+        [UnmanagedFunctionPointer(CallingConvention.StdCall)]
+        private delegate int GetThreadContextByIdDelegate(
+            IntPtr self,
+            uint threadId,
+            uint contextFlags,
+            uint contextSize,
+            IntPtr context);
+
+        [UnmanagedFunctionPointer(CallingConvention.StdCall)]
+        private delegate int GetValueByNameDelegate(
+            IntPtr self,
+            [In, MarshalAs(UnmanagedType.LPStr)] string name,
+            out ulong value);
+
+        [UnmanagedFunctionPointer(CallingConvention.StdCall)]
+        private delegate int GetInstructionOffsetDelegate(
+            IntPtr self,
+            out ulong offset);
+
+        [UnmanagedFunctionPointer(CallingConvention.StdCall)]
+        private delegate int GetStackOffsetDelegate(
+            IntPtr self,
+            out ulong offset);
+
+        [UnmanagedFunctionPointer(CallingConvention.StdCall)]
+        private delegate int GetFrameOffsetDelegate(
+            IntPtr self,
+            out ulong offset);
+
+        #endregion
+
+        #region ILLDBServices2 delegates
+
+        /// <summary>
+        /// The LoadNativeSymbolsDelegate2 callback
+        /// </summary>
+        public delegate void ModuleLoadCallback(
+            IntPtr parameter,
+            [MarshalAs(UnmanagedType.LPStr)] string moduleFilePath,
+            ulong moduleAddress,
+            int moduleSize);
+
+        [UnmanagedFunctionPointer(CallingConvention.StdCall)]
+        private delegate int LoadNativeSymbolsDelegate2(
+            IntPtr self,
+            bool runtimeOnly,
+            ModuleLoadCallback callback);
+
+        [UnmanagedFunctionPointer(CallingConvention.StdCall)]
+        private delegate int AddModuleSymbolDelegate(
+            IntPtr self,
+            IntPtr parameter,
+            [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
diff --git a/src/SOS/SOS.Hosting/SOS.Hosting.csproj b/src/SOS/SOS.Hosting/SOS.Hosting.csproj
new file mode 100644 (file)
index 0000000..777fb9e
--- /dev/null
@@ -0,0 +1,20 @@
+<!-- Copyright (c)  Microsoft.  All Rights Reserved.  Licensed under the Apache License, Version 2.0.  See License.txt in the project root for license information. -->
+<Project Sdk="Microsoft.NET.Sdk">
+  <PropertyGroup>
+    <TargetFramework>netstandard2.0</TargetFramework>
+    <AssemblyName>SOS.Hosting</AssemblyName>
+    <NoWarn>;1591;1701</NoWarn>
+    <Description>SOS Hosting support</Description>
+    <DebugSymbols>true</DebugSymbols>
+    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
+  </PropertyGroup>
+  
+  <ItemGroup>
+    <PackageReference Include="Microsoft.Diagnostics.Runtime" Version="$(MicrosoftDiagnosticsRuntimeVersion)" />
+  </ItemGroup>
+  
+  <ItemGroup>
+    <ProjectReference Include="..\..\Microsoft.Diagnostic.Repl\Microsoft.Diagnostic.Repl.csproj" />
+    <ProjectReference Include="..\SOS.NETCore\SOS.NETCore.csproj" />
+  </ItemGroup>
+</Project>
diff --git a/src/SOS/SOS.Hosting/SOSHost.cs b/src/SOS/SOS.Hosting/SOSHost.cs
new file mode 100644 (file)
index 0000000..9df525e
--- /dev/null
@@ -0,0 +1,99 @@
+// 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.
+
+using Microsoft.Diagnostics.Runtime;
+using System;
+using System.IO;
+using System.Reflection;
+using System.Runtime.InteropServices;
+
+namespace SOS
+{
+    /// <summary>
+    /// Helper code to hosting SOS under ClrMD
+    /// </summary>
+    public sealed class SOSHost
+    {
+        [UnmanagedFunctionPointer(CallingConvention.StdCall)]
+        delegate int SOSCommandDelegate(IntPtr ILLDBServices, [In, MarshalAs(UnmanagedType.LPStr)] string args);
+
+        readonly LLDBServicesWrapper _wrapper;
+        IntPtr _sosLibrary = IntPtr.Zero;
+
+        /// <summary>
+        /// Enable the assembly resolver to get the right SOS.NETCore version (the one
+        /// in the same directory as SOS.Hosting).
+        /// </summary>
+        static SOSHost()
+        {
+            AssemblyResolver.Enable();
+        }
+
+        /// <summary>
+        /// The native SOS binaries path. Default is OS/architecture (RID) named directory in the same directory as this assembly.
+        /// </summary>
+        public string SOSPath { get; set; }
+
+        /// <summary>
+        /// Create an instance of the hosting class
+        /// </summary>
+        public SOSHost(IDataReader dataReader, ISOSHostContext context)
+        {
+            string os = null;
+            if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) {
+                os = "win";
+            }
+            else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) {
+                os = "linux";
+            }
+            if (os == null) {
+                throw new PlatformNotSupportedException($"{RuntimeInformation.OSDescription} not supported");
+            }
+            string architecture = RuntimeInformation.OSArchitecture.ToString().ToLowerInvariant();
+            string rid = os + "-" + architecture;
+            SOSPath = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), rid);
+
+            _wrapper = new LLDBServicesWrapper(this, dataReader, context);
+        }
+
+        public void ExecuteCommand(string commandLine)
+        {
+            string command = "Help";
+            string arguments = null;
+
+            if (commandLine != null)
+            {
+                int firstSpace = commandLine.IndexOf(' ');
+                command = firstSpace == -1 ? commandLine : commandLine.Substring(0, firstSpace);
+                arguments = firstSpace == -1 ? null : commandLine.Substring(firstSpace);
+            }
+            ExecuteCommand(command, arguments);
+        }
+
+        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");
+                }
+            }
+            IntPtr commandAddress = DataTarget.PlatformFunctions.GetProcAddress(_sosLibrary, command);
+            if (commandAddress == IntPtr.Zero)
+            {
+                throw new EntryPointNotFoundException($"Can not find SOS command: {command}");
+            }
+            var commandFunc = (SOSCommandDelegate)Marshal.GetDelegateForFunctionPointer(commandAddress, typeof(SOSCommandDelegate));
+
+            int result = commandFunc(_wrapper.ILLDBServices, arguments ?? "");
+            if (result != 0)
+            {
+                throw new InvalidOperationException($"SOS command FAILED 0x{result:X8}");
+            }
+        }
+    }
+}
index 3a098e507739ac99e85317e2304385fa895faa37..1c128fc7aef4cdf1b329e80fc8098869d0058f28 100644 (file)
@@ -18,12 +18,11 @@ using System.Reflection.Metadata;
 using System.Reflection.Metadata.Ecma335;
 using System.Reflection.PortableExecutable;
 using System.Runtime.InteropServices;
-using System.Text;
 using System.Threading;
 
 namespace SOS
 {
-    internal class SymbolReader
+    public class SymbolReader
     {
         [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
         internal struct DebugInfo
@@ -145,13 +144,13 @@ namespace SOS
         /// Read memory callback
         /// </summary>
         /// <returns>number of bytes read or 0 for error</returns>
-        internal unsafe delegate int ReadMemoryDelegate(ulong address, byte* buffer, int count);
+        public unsafe delegate int ReadMemoryDelegate(ulong address, byte* buffer, int count);
 
         /// <summary>
         /// Writeline delegate for symbol store logging
         /// </summary>
         /// <param name="message"></param>
-        internal delegate void WriteLine([MarshalAs(UnmanagedType.LPStr)] string message);
+        public delegate void WriteLine([MarshalAs(UnmanagedType.LPStr)] string message);
 
         /// <summary>
         /// The LoadNativeSymbols callback
@@ -175,7 +174,7 @@ namespace SOS
         /// <param name="symbolCachePath">symbol cache directory path (optional)</param>
         /// <param name="windowsSymbolPath">windows symbol path (optional)</param>
         /// <returns></returns>
-        internal static bool InitializeSymbolStore(bool logging, bool msdl, bool symweb, string symbolServerPath, string symbolCachePath, string windowsSymbolPath)
+        public static bool InitializeSymbolStore(bool logging, bool msdl, bool symweb, string symbolServerPath, string symbolCachePath, string windowsSymbolPath)
         {
             if (s_tracer == null) {
                 s_tracer = new Tracer(enabled: logging, enabledVerbose: logging, Console.WriteLine);
@@ -203,7 +202,7 @@ namespace SOS
         /// <summary>
         /// Displays the symbol server and cache configuration
         /// </summary>
-        internal static void DisplaySymbolStore()
+        public static void DisplaySymbolStore()
         {
             if (s_tracer != null)
             {
@@ -227,7 +226,7 @@ namespace SOS
         /// <summary>
         /// This function disables any symbol downloading support.
         /// </summary>
-        internal static void DisableSymbolStore()
+        public static void DisableSymbolStore()
         {
             s_tracer = null;
             s_symbolStore = null;
@@ -331,7 +330,7 @@ namespace SOS
         /// <param name="inMemoryPdbAddress">in memory PDB address or zero</param>
         /// <param name="inMemoryPdbSize">in memory PDB size</param>
         /// <returns>Symbol reader handle or zero if error</returns>
-        internal static IntPtr LoadSymbolsForModule(string assemblyPath, bool isFileLayout, ulong loadedPeAddress, int loadedPeSize, 
+        public static IntPtr LoadSymbolsForModule(string assemblyPath, bool isFileLayout, ulong loadedPeAddress, int loadedPeSize, 
             ulong inMemoryPdbAddress, int inMemoryPdbSize, ReadMemoryDelegate readMemory)
         {
             try
@@ -363,7 +362,7 @@ namespace SOS
         /// Cleanup and dispose of symbol reader handle
         /// </summary>
         /// <param name="symbolReaderHandle">symbol reader handle returned by LoadSymbolsForModule</param>
-        internal static void Dispose(IntPtr symbolReaderHandle)
+        public static void Dispose(IntPtr symbolReaderHandle)
         {
             Debug.Assert(symbolReaderHandle != IntPtr.Zero);
             try
@@ -386,7 +385,7 @@ namespace SOS
         /// <param name="methodToken">method token return</param>
         /// <param name="ilOffset">IL offset return</param>
         /// <returns> true if information is available</returns>
-        internal static bool ResolveSequencePoint(IntPtr symbolReaderHandle, string filePath, int lineNumber, out int methodToken, out int ilOffset)
+        public static bool ResolveSequencePoint(IntPtr symbolReaderHandle, string filePath, int lineNumber, out int methodToken, out int ilOffset)
         {
             Debug.Assert(symbolReaderHandle != IntPtr.Zero);
             methodToken = 0;
@@ -429,7 +428,7 @@ namespace SOS
         /// <param name="lineNumber">source line number return</param>
         /// <param name="fileName">source file name return</param>
         /// <returns> true if information is available</returns>
-        internal static bool GetLineByILOffset(IntPtr symbolReaderHandle, int methodToken, long ilOffset, out int lineNumber, out IntPtr fileName)
+        public static bool GetLineByILOffset(IntPtr symbolReaderHandle, int methodToken, long ilOffset, out int lineNumber, out IntPtr fileName)
         {
             lineNumber = 0;
             fileName = IntPtr.Zero;
@@ -511,7 +510,7 @@ namespace SOS
         /// <param name="localIndex">local variable index</param>
         /// <param name="localVarName">local variable name return</param>
         /// <returns>true if name has been found</returns>
-        internal static bool GetLocalVariableName(IntPtr symbolReaderHandle, int methodToken, int localIndex, out IntPtr localVarName)
+        public static bool GetLocalVariableName(IntPtr symbolReaderHandle, int methodToken, int localIndex, out IntPtr localVarName)
         {
             localVarName = IntPtr.Zero;
 
@@ -946,12 +945,20 @@ namespace SOS
         /// <returns>stream or null</returns>
         private static SymbolStoreFile GetSymbolStoreFile(SymbolStoreKey key)
         {
-            // Add the default symbol cache if it hasn't already been added
-            if (!s_symbolCacheAdded) {
-                s_symbolStore = new CacheSymbolStore(s_tracer, s_symbolStore, GetDefaultSymbolCache());
-                s_symbolCacheAdded = true;
+            try
+            {
+                // Add the default symbol cache if it hasn't already been added
+                if (!s_symbolCacheAdded) {
+                    s_symbolStore = new CacheSymbolStore(s_tracer, s_symbolStore, GetDefaultSymbolCache());
+                    s_symbolCacheAdded = true;
+                }
+                return s_symbolStore.GetFile(key, CancellationToken.None).GetAwaiter().GetResult();
+            }
+            catch (Exception ex) when (ex is UnauthorizedAccessException || ex is BadImageFormatException || ex is IOException)
+            {
+                s_tracer.Error("Exception: {0}", ex.ToString());
+                return null;
             }
-            return s_symbolStore.GetFile(key, CancellationToken.None).GetAwaiter().GetResult();
         }
 
         /// <summary>
index 894598cc16544e89b94525872cb9948d141015f2..ac046d0ede4f7df08266d3be834e5cca35105223 100644 (file)
@@ -24,7 +24,9 @@ namespace SOS
 
         public void WriteLine(string message)
         {
-            m_output?.Invoke(message);
+            lock (this) {
+                m_output?.Invoke(message);
+            }
         }
 
         public void WriteLine(string format, params object[] arguments)
index ca82bf2b25e0d728eef5e7bc3b5b24b52a23e183..060b0c401944689918ce16cec7cea480d4e7f885 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 cd5bb759b5ff622f3f62f881f440c30d3d3c1aa1..1640905752885365e5fcaa57db8c8ea713c2a1c4 100644 (file)
@@ -57,6 +57,7 @@
       <Filter>inc</Filter>
     </ClInclude>
     <ClInclude Include="hostcoreclr.h" />
+    <ClInclude Include="soshostservices.h" />
   </ItemGroup>
   <ItemGroup>
     <ResourceCompile Include="Native.rc" />
index df6e99006061610e4e51c3dda6136ed78f27af2c..462134846463542b4b2693b639b0605b598104b3 100644 (file)
@@ -561,6 +561,17 @@ 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;
@@ -682,15 +693,6 @@ HRESULT InitializeHosting()
     return Status;
 }
 
-/**********************************************************************\
- * Public entry point to set the managed callbacks (unused).
-\**********************************************************************/
-extern "C" void InitializeSymbolReaderCallbacks(SOSNetCoreCallbacks sosNetCoreCallbacks)
-{
-    g_SOSNetCoreCallbacks = sosNetCoreCallbacks;
-    g_hostingInitialized = true;
-}
-
 //
 // Pass to managed helper code to read in-memory PEs/PDBs.
 // Returns the number of bytes read.
index f6b6dfa3f490897ba0afdbcaeb148dc842f8e548..88ce27abd8f23649ae3452b1b98b5fa9c402e576 100644 (file)
 #ifndef __hostcoreclr_h__
 #define __hostcoreclr_h__
 
+#include <soshostservices.h>
+
 static const char *SymbolReaderDllName = "SOS.NETCore";
 static const char *SymbolReaderClassName = "SOS.SymbolReader";
 
-typedef void (*OutputDelegate)(const char*);
-typedef  int (*ReadMemoryDelegate)(ULONG64, uint8_t*, int);
-typedef void (*SymbolFileCallbackDelegate)(void*, const char* moduleFileName, const char* symbolFileName);
-
-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*, 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*);
-
-struct SOSNetCoreCallbacks
-{
-    InitializeSymbolStoreDelegate InitializeSymbolStoreDelegate;
-    DisplaySymbolStoreDelegate DisplaySymbolStoreDelegate;
-    DisableSymbolStoreDelegate DisableSymbolStoreDelegate;
-    LoadNativeSymbolsDelegate LoadNativeSymbolsDelegate;
-    LoadSymbolsForModuleDelegate LoadSymbolsForModuleDelegate;
-    DisposeDelegate DisposeDelegate;
-    ResolveSequencePointDelegate ResolveSequencePointDelegate;
-    GetLineByILOffsetDelegate GetLineByILOffsetDelegate;
-    GetLocalVariableNameDelegate GetLocalVariableNameDelegate;
-};
-
 extern HMODULE g_hInstance;
 extern LPCSTR g_hostRuntimeDirectory;
 extern SOSNetCoreCallbacks g_SOSNetCoreCallbacks;
index dd0d3ea1c61be9f729ccf1f15011ef2ddec7871c..81964382b28e0f8395e4437673e07376e46c4d30 100644 (file)
@@ -232,6 +232,4 @@ EXPORTS
     getCodeTypeFlags=GetCodeTypeFlags
     TraceToCode
     tracetocode=TraceToCode
-#endif
-
-    InitializeSymbolReaderCallbacks
\ No newline at end of file
+#endif
\ No newline at end of file
index ddfd32808daf09376269fe8fa5e47772d2f84591..732da868ffbfdc290b7feebae21ee97a682bea80 100644 (file)
@@ -53,5 +53,3 @@ ThreadState
 Token2EE
 u
 VerifyHeap
-
-InitializeSymbolReaderCallbacks
\ No newline at end of file
diff --git a/src/SOS/Strike/soshostservices.h b/src/SOS/Strike/soshostservices.h
new file mode 100644 (file)
index 0000000..619a2e4
--- /dev/null
@@ -0,0 +1,69 @@
+// 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*);
+
+#define SOSNetCoreCallbacksVersion 1
+
+struct SOSNetCoreCallbacks
+{
+    InitializeSymbolStoreDelegate InitializeSymbolStoreDelegate;
+    DisplaySymbolStoreDelegate DisplaySymbolStoreDelegate;
+    DisableSymbolStoreDelegate DisableSymbolStoreDelegate;
+    LoadNativeSymbolsDelegate LoadNativeSymbolsDelegate;
+    LoadSymbolsForModuleDelegate LoadSymbolsForModuleDelegate;
+    DisposeDelegate DisposeDelegate;
+    ResolveSequencePointDelegate ResolveSequencePointDelegate;
+    GetLineByILOffsetDelegate GetLineByILOffsetDelegate;
+    GetLocalVariableNameDelegate GetLocalVariableNameDelegate;
+};
+
+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__