Abstract all the runtime specific info and class.
authorMike McLaughlin <mikem@microsoft.com>
Tue, 31 Dec 2019 02:18:23 +0000 (18:18 -0800)
committerMike McLaughlin <mikem@microsoft.com>
Sun, 5 Jan 2020 07:20:16 +0000 (23:20 -0800)
Add IRuntime/Runtime classes.

The code to get the runtime module address/size info, DAC/DBI file path, create/get the
SOS DAC process instance and to create/get the ICorDebug process instance to the Runtime
class implementation. It was moved mostly intack with some type and function name changes.

Added -desktop and -netcore options to the !sosstatus command to switch between runtimes.

Eventually SOSHosting will provide the IRuntime instance when hosted under dotnet-dump.

Fix unloading/reloading SOS (under windbg) issue: https://github.com/dotnet/diagnostics/issues/386

Flush process specific global state when process terminates issue: https://github.com/dotnet/diagnostics/issues/479

22 files changed:
src/SOS/SOS.Hosting/SOSHost.cs
src/SOS/Strike/CMakeLists.txt
src/SOS/Strike/EventCallbacks.cpp
src/SOS/Strike/ExpressionNode.cpp
src/SOS/Strike/ExpressionNode.h
src/SOS/Strike/Strike.vcxproj
src/SOS/Strike/Strike.vcxproj.filters
src/SOS/Strike/WatchCmd.cpp
src/SOS/Strike/cordebugdatatarget.h [new file with mode: 0644]
src/SOS/Strike/cordebuglibraryprovider.h [new file with mode: 0644]
src/SOS/Strike/disasm.h
src/SOS/Strike/exts.h
src/SOS/Strike/hostcoreclr.cpp
src/SOS/Strike/hostcoreclr.h
src/SOS/Strike/runtime.cpp [new file with mode: 0644]
src/SOS/Strike/runtime.h [new file with mode: 0644]
src/SOS/Strike/sosdocs.txt
src/SOS/Strike/sosdocsunix.txt
src/SOS/Strike/strike.cpp
src/SOS/Strike/util.cpp
src/SOS/Strike/util.h
src/Tools/dotnet-dump/Analyzer.cs

index f30e710e27792048e7f55b35c112d5d44282f3f4..115bdeb2363fe6102a468fbe637bc22a95aa9f86 100644 (file)
@@ -38,6 +38,7 @@ namespace SOS
             [In, MarshalAs(UnmanagedType.Struct)] ref SOSNetCoreCallbacks callbacks,
             int callbacksSize,
             [In, MarshalAs(UnmanagedType.LPStr)] string tempDirectory,
+            bool isDesktop,
             [In, MarshalAs(UnmanagedType.LPStr)] string dacFilePath,
             [In, MarshalAs(UnmanagedType.LPStr)] string dbiFilePath,
             bool symbolStoreEnabled);
@@ -224,9 +225,10 @@ namespace SOS
         /// Loads and initializes the SOS module.
         /// </summary>
         /// <param name="tempDirectory">Temporary directory created to download DAC module</param>
+        /// <param name="isDesktop">if true, desktop runtime, else .NET Core runtime</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)
+        public void InitializeSOSHost(string tempDirectory, bool isDesktop, string dacFilePath, string dbiFilePath)
         {
             if (_sosLibrary == IntPtr.Zero)
             {
@@ -268,6 +270,7 @@ namespace SOS
                     ref s_callbacks,
                     Marshal.SizeOf<SOSNetCoreCallbacks>(),
                     tempDirectory,
+                    isDesktop,
                     dacFilePath,
                     dbiFilePath,
                     SymbolReader.IsSymbolStoreEnabled());
index ae4ff471f3d8d864eb66a0a78210e3295652fd6c..207ec5a9933745e232d346270e2db202640f5380 100644 (file)
@@ -69,6 +69,7 @@ if(WIN32)
     gcroot.cpp
     hostcoreclr.cpp
     metadata.cpp
+    runtime.cpp
     sigparser.cpp
     sildasm.cpp
     sos.cpp
@@ -125,6 +126,7 @@ else(WIN32)
     gcroot.cpp
     hostcoreclr.cpp
     metadata.cpp
+    runtime.cpp
     sigparser.cpp
     sildasm.cpp
     stressLogDump.cpp
index 947d913becc9450d2394d9468be913042b819e93..bdef2f9e65eeca4be931fe7db7f91e601ed949c4 100644 (file)
@@ -105,7 +105,8 @@ HRESULT __stdcall EventCallbacks::Exception(PEXCEPTION_RECORD64 Exception, ULONG
 
 HRESULT __stdcall EventCallbacks::ExitProcess(ULONG ExitCode)
 {
-    UninitCorDebugInterface();
+    Runtime::CleanupRuntimes();
+    CleanupTempDirectory();
     return DEBUG_STATUS_NO_CHANGE;
 }
 
index b61dcad48788c880d69f01eafa4fe755b5319f66..45a2f5c191005ce353d80e040a22cb2bb6b9e59d 100644 (file)
@@ -4,11 +4,12 @@
 
 #include "ExpressionNode.h"
 
-
 #ifndef IfFailRet
 #define IfFailRet(EXPR) do { Status = (EXPR); if(FAILED(Status)) { return (Status); } } while (0)
 #endif
 
+ICorDebugProcess* ExpressionNode::s_pCorDebugProcess = nullptr;
+
 // Returns the complete expression being evaluated to get the value for this node
 // The returned pointer is a string interior to this object - once you release
 // all references to this object the string is invalid.
@@ -45,8 +46,15 @@ WCHAR* ExpressionNode::GetErrorMessage() { return pErrorMessage; }
 // Factory function for creating the expression node at the root of a tree
 HRESULT ExpressionNode::CreateExpressionNode(__in_z WCHAR* pExpression, ExpressionNode** ppExpressionNode)
 {
+    _ASSERTE(g_pRuntime != nullptr);
     *ppExpressionNode = NULL;
-    HRESULT Status = CreateExpressionNodeHelper(pExpression,
+
+    HRESULT Status = g_pRuntime->GetCorDebugInterface(&s_pCorDebugProcess);
+    if (FAILED(Status)) 
+    {
+        return Status;
+    }
+    Status = CreateExpressionNodeHelper(pExpression,
         pExpression,
         0,
         NULL,
@@ -1760,7 +1768,8 @@ HRESULT ExpressionNode::EnumerateFrames(FrameEnumCallback pCallback, VOID* pUser
     ULONG ulThreadID = 0;
     g_ExtSystem->GetCurrentThreadSystemId(&ulThreadID);
 
-    IfFailRet(g_pCorDebugProcess->GetThread(ulThreadID, &pThread));
+    _ASSERTE(s_pCorDebugProcess != nullptr);
+    IfFailRet(s_pCorDebugProcess->GetThread(ulThreadID, &pThread));
     IfFailRet(pThread->QueryInterface(IID_ICorDebugThread3, (LPVOID *) &pThread3));
     IfFailRet(pThread3->CreateStackWalk(&pStackWalk));
 
@@ -1980,7 +1989,8 @@ HRESULT ExpressionNode::FindTypeByName(__in_z const WCHAR* pTypeName, ICorDebugT
 {
     HRESULT Status = S_OK;
     ToRelease<ICorDebugAppDomainEnum> pAppDomainEnum;
-    IfFailRet(g_pCorDebugProcess->EnumerateAppDomains(&pAppDomainEnum));
+    _ASSERTE(s_pCorDebugProcess != nullptr);
+    IfFailRet(s_pCorDebugProcess->EnumerateAppDomains(&pAppDomainEnum));
     DWORD count;
     IfFailRet(pAppDomainEnum->GetCount(&count));
     for(DWORD i = 0; i < count; i++)
index 48cc036729c2f33915971fb3cc0744a626495c45..b845c8a334a82003806b9440425715305999747c 100644 (file)
@@ -88,6 +88,8 @@ public:
     VOID DFSVisit(ExpressionNodeVisitorCallback pFunc, VOID* pUserData, int depth=0);
 
 private:
+    static ICorDebugProcess* s_pCorDebugProcess;
+
     // for nodes that evaluate to a type, this is that type
     // for nodes that evaluate to a debuggee value, this is the type of that
     // value or one of its base types. It represents the type the value should
index 9f5e15cb109c4acfed55b91cb90125f0dd731ffe..510008f66cb19f1c92364828866470c26fbb8cd0 100644 (file)
     <ClCompile Include="gchist.cpp" />
     <ClCompile Include="gcroot.cpp" />
     <ClCompile Include="metadata.cpp" />
+    <ClCompile Include="runtime.cpp" />
     <ClCompile Include="sildasm.cpp" />
     <ClCompile Include="sos.cpp" />
     <ClCompile Include="stressLogDump.cpp" />
     <ClCompile Include="disasmARM64.cpp" />
   </ItemGroup>
   <ItemGroup>
+    <ClInclude Include="cordebugdatatarget.h" />
+    <ClInclude Include="cordebuglibraryprovider.h" />
     <ClInclude Include="data.h" />
     <ClInclude Include="datatarget.h" />
     <ClInclude Include="disasm.h" />
     <ClInclude Include="inc\wdbgexts.h" />
     <ClInclude Include="ntinfo.h" />
     <ClInclude Include="platformspecific.h" />
+    <ClInclude Include="runtime.h" />
     <ClInclude Include="sos.h" />
     <ClInclude Include="sos_md.h" />
     <ClInclude Include="sos_stacktrace.h" />
index cd5bb759b5ff622f3f62f881f440c30d3d3c1aa1..1f4f91078e44b4b860bdc322cb33a215f48250ca 100644 (file)
@@ -21,6 +21,7 @@
     <ClCompile Include="disasmX86.cpp" />
     <ClCompile Include="disasmARM64.cpp" />
     <ClCompile Include="hostcoreclr.cpp" />
+    <ClCompile Include="runtime.cpp" />
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="data.h" />
@@ -57,6 +58,9 @@
       <Filter>inc</Filter>
     </ClInclude>
     <ClInclude Include="hostcoreclr.h" />
+    <ClInclude Include="runtime.h" />
+    <ClInclude Include="cordebugdatatarget.h" />
+    <ClInclude Include="cordebuglibraryprovider.h" />
   </ItemGroup>
   <ItemGroup>
     <ResourceCompile Include="Native.rc" />
index 443f1dd6ef66e4c3056b13adfb074348800d7967..ca548eea2544105792a9ebd49df861d76c9b40cd 100644 (file)
@@ -95,7 +95,6 @@ HRESULT WatchCmd::Print(int expansionIndex, __in_z WCHAR* expansionPath, __in_z
     INIT_API_EE();
     INIT_API_DAC();
     EnableDMLHolder dmlHolder(TRUE);
-    IfFailRet(InitCorDebugInterface());
 
     PersistList* pFilterList = NULL;
     if(pFilterName != NULL)
@@ -208,7 +207,6 @@ HRESULT WatchCmd::SaveList(__in_z WCHAR* pSaveName)
     HRESULT Status = S_OK;
     INIT_API_EE();
     INIT_API_DAC();
-    IfFailRet(InitCorDebugInterface());
 
     RemoveList(pSaveName);
     PersistList* pList = new PersistList();
diff --git a/src/SOS/Strike/cordebugdatatarget.h b/src/SOS/Strike/cordebugdatatarget.h
new file mode 100644 (file)
index 0000000..fe5bece
--- /dev/null
@@ -0,0 +1,251 @@
+// 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.
+
+#ifndef __cordebugdatatarget_h__
+#define __cordebugdatatarget_h__
+
+/**********************************************************************\
+* Data target for the debugged process. Provided to OpenVirtualProcess 
+* in order to get an ICorDebugProcess back.
+\**********************************************************************/
+class CorDebugDataTarget : public ICorDebugMutableDataTarget, public ICorDebugMetaDataLocator, public ICorDebugDataTarget4
+{
+public:
+    CorDebugDataTarget() : m_ref(0)
+    {
+    }
+
+    virtual ~CorDebugDataTarget() {}
+
+    virtual HRESULT STDMETHODCALLTYPE QueryInterface(
+        REFIID InterfaceId,
+        PVOID* pInterface)
+    {
+        if (InterfaceId == IID_IUnknown)
+        {
+            *pInterface = static_cast<IUnknown *>(static_cast<ICorDebugDataTarget *>(this));
+        }
+        else if (InterfaceId == IID_ICorDebugDataTarget)
+        {
+            *pInterface = static_cast<ICorDebugDataTarget *>(this);
+        }
+        else if (InterfaceId == IID_ICorDebugMutableDataTarget)
+        {
+            *pInterface = static_cast<ICorDebugMutableDataTarget *>(this);
+        }
+        else if (InterfaceId == IID_ICorDebugMetaDataLocator)
+        {
+            *pInterface = static_cast<ICorDebugMetaDataLocator *>(this);
+        }
+        else if (InterfaceId == IID_ICorDebugDataTarget4)
+        {
+            *pInterface = static_cast<ICorDebugDataTarget4 *>(this);
+        }
+        else
+        {
+            *pInterface = NULL;
+            return E_NOINTERFACE;
+        }
+
+        AddRef();
+        return S_OK;
+    }
+    
+    virtual ULONG STDMETHODCALLTYPE AddRef()
+    {
+        return InterlockedIncrement(&m_ref);    
+    }
+
+    virtual ULONG STDMETHODCALLTYPE Release()
+    {
+        LONG ref = InterlockedDecrement(&m_ref);
+        if (ref == 0)
+        {
+            delete this;
+        }
+        return ref;
+    }
+
+    //
+    // ICorDebugDataTarget.
+    //
+
+    virtual HRESULT STDMETHODCALLTYPE GetPlatform(CorDebugPlatform * pPlatform)
+    {
+        ULONG platformKind = g_targetMachine->GetPlatform();
+#ifdef FEATURE_PAL        
+        if(platformKind == IMAGE_FILE_MACHINE_I386)
+            *pPlatform = CORDB_PLATFORM_POSIX_X86;
+        else if(platformKind == IMAGE_FILE_MACHINE_AMD64)
+            *pPlatform = CORDB_PLATFORM_POSIX_AMD64;
+        else if(platformKind == IMAGE_FILE_MACHINE_ARMNT)
+            *pPlatform = CORDB_PLATFORM_POSIX_ARM;
+        else
+            return E_FAIL;
+#else
+        if(platformKind == IMAGE_FILE_MACHINE_I386)
+            *pPlatform = CORDB_PLATFORM_WINDOWS_X86;
+        else if(platformKind == IMAGE_FILE_MACHINE_AMD64)
+            *pPlatform = CORDB_PLATFORM_WINDOWS_AMD64;
+        else if(platformKind == IMAGE_FILE_MACHINE_ARMNT)
+            *pPlatform = CORDB_PLATFORM_WINDOWS_ARM;
+        else if(platformKind == IMAGE_FILE_MACHINE_ARM64)
+            *pPlatform = CORDB_PLATFORM_WINDOWS_ARM64;
+        else
+            return E_FAIL;        
+#endif        
+    
+        return S_OK;
+    }
+
+    virtual HRESULT STDMETHODCALLTYPE ReadVirtual( 
+        CORDB_ADDRESS address,
+        BYTE * pBuffer,
+        ULONG32 request,
+        ULONG32 * pcbRead)
+    {
+        if (g_ExtData == NULL)
+        {
+            return E_UNEXPECTED;
+        }
+#ifdef FEATURE_PAL
+        if (g_sos != nullptr)
+        {
+            // LLDB synthesizes memory (returns 0's) for missing pages (in this case the missing metadata  pages) 
+            // in core dumps. This functions creates a list of the metadata regions and caches the metadata if 
+            // available from the local or downloaded assembly. If the read would be in the metadata of a loaded 
+            // assembly, the metadata from the this cache will be returned.
+            HRESULT hr = GetMetadataMemory(address, request, pBuffer);
+            if (SUCCEEDED(hr)) {
+                if (pcbRead != nullptr) {
+                    *pcbRead = request;
+                }
+                return hr;
+            }
+        }
+#endif
+        HRESULT hr = g_ExtData->ReadVirtual(address, pBuffer, request, (PULONG) pcbRead);
+        if (FAILED(hr)) 
+        {
+            ExtDbgOut("CorDebugDataTarget::ReadVirtual FAILED %08x address %p size %08x\n", hr, address, request);
+        }
+        return hr;
+    }
+
+    virtual HRESULT STDMETHODCALLTYPE GetThreadContext(
+        DWORD dwThreadOSID,
+        ULONG32 contextFlags,
+        ULONG32 contextSize,
+        BYTE * context)
+    {
+#ifdef FEATURE_PAL
+        if (g_ExtServices == NULL)
+        {
+            return E_UNEXPECTED;
+        }
+        return g_ExtServices->GetThreadContextById(dwThreadOSID, contextFlags, contextSize, context);
+#else
+        ULONG ulThreadIDOrig;
+        ULONG ulThreadIDRequested;
+        HRESULT hr;
+
+        hr = g_ExtSystem->GetCurrentThreadId(&ulThreadIDOrig);
+        if (FAILED(hr))
+        {
+            return hr;
+        }
+
+        hr = g_ExtSystem->GetThreadIdBySystemId(dwThreadOSID, &ulThreadIDRequested);
+        if (FAILED(hr))
+        {
+            return hr;
+        }
+
+        hr = g_ExtSystem->SetCurrentThreadId(ulThreadIDRequested);
+        if (FAILED(hr))
+        {
+            return hr;
+        }
+
+        // Prepare context structure
+        ZeroMemory(context, contextSize);
+        ((CONTEXT*) context)->ContextFlags = contextFlags;
+
+        // Ok, do it!
+        hr = g_ExtAdvanced->GetThreadContext((LPVOID) context, contextSize);
+
+        // This is cleanup; failure here doesn't mean GetThreadContext should fail
+        // (that's determined by hr).
+        g_ExtSystem->SetCurrentThreadId(ulThreadIDOrig);
+
+        return hr;
+#endif // FEATURE_PAL
+    }
+
+    //
+    // ICorDebugMutableDataTarget.
+    //
+
+    virtual HRESULT STDMETHODCALLTYPE WriteVirtual(CORDB_ADDRESS address,
+                                                   const BYTE * pBuffer,
+                                                   ULONG32 bytesRequested)
+    {
+        if (g_ExtData == NULL)
+        {
+            return E_UNEXPECTED;
+        }
+        return g_ExtData->WriteVirtual(address, (PVOID)pBuffer, bytesRequested, NULL);
+    }
+
+    virtual HRESULT STDMETHODCALLTYPE SetThreadContext(DWORD dwThreadID,
+                                                       ULONG32 contextSize,
+                                                       const BYTE * pContext)
+    {
+        return E_NOTIMPL;
+    }
+
+    virtual HRESULT STDMETHODCALLTYPE ContinueStatusChanged(DWORD dwThreadId,
+                                                            CORDB_CONTINUE_STATUS continueStatus)
+    {
+        return E_NOTIMPL;
+    }
+
+    //
+    // ICorDebugMetaDataLocator.
+    //
+
+    virtual HRESULT STDMETHODCALLTYPE GetMetaData(
+        /* [in] */ LPCWSTR wszImagePath,
+        /* [in] */ DWORD dwImageTimeStamp,
+        /* [in] */ DWORD dwImageSize,
+        /* [in] */ ULONG32 cchPathBuffer,
+        /* [annotation][out] */ 
+        _Out_ ULONG32 *pcchPathBuffer,
+        /* [annotation][length_is][size_is][out] */ 
+        _Out_writes_to_(cchPathBuffer, *pcchPathBuffer) WCHAR wszPathBuffer[])
+    {
+        return E_NOTIMPL;
+    }
+
+    //
+    // ICorDebugDataTarget4
+    //
+    virtual HRESULT STDMETHODCALLTYPE VirtualUnwind(DWORD threadId, ULONG32 contextSize, PBYTE context)
+    {
+#ifdef FEATURE_PAL
+        if (g_ExtServices == NULL)
+        {
+            return E_UNEXPECTED;
+        }
+        return g_ExtServices->VirtualUnwind(threadId, contextSize, context);
+#else 
+        return E_NOTIMPL;
+#endif
+    }
+
+protected:
+    LONG m_ref;
+};
+
+#endif // __cordebugdatatarget_h__
diff --git a/src/SOS/Strike/cordebuglibraryprovider.h b/src/SOS/Strike/cordebuglibraryprovider.h
new file mode 100644 (file)
index 0000000..f5eac41
--- /dev/null
@@ -0,0 +1,170 @@
+// 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.
+
+#ifndef __cordebuglibraryprovider_h__
+#define __cordebuglibraryprovider_h__
+
+#ifndef FEATURE_PAL
+extern HMODULE LoadLibraryAndCheck(PCWSTR filename, DWORD timestamp, DWORD filesize);
+#endif
+
+/**********************************************************************\
+ * Provides a way for the public CLR debugging interface to find the 
+ * appropriate mscordbi.dll, DAC, etc.
+\**********************************************************************/
+class CorDebugLibraryProvider : public ICLRDebuggingLibraryProvider, ICLRDebuggingLibraryProvider2
+{
+public:
+    CorDebugLibraryProvider(Runtime* pRuntime) :
+        m_ref(0),
+        m_pRuntime(pRuntime)
+    {
+    }
+
+    virtual ~CorDebugLibraryProvider() {}
+
+    virtual HRESULT STDMETHODCALLTYPE QueryInterface(
+        REFIID InterfaceId,
+        PVOID* pInterface)
+    {
+        if (InterfaceId == IID_IUnknown)
+        {
+            *pInterface = static_cast<IUnknown *>(static_cast<ICLRDebuggingLibraryProvider*>(this));
+        }
+#ifndef FEATURE_PAL
+        else if (InterfaceId == IID_ICLRDebuggingLibraryProvider)
+        {
+            *pInterface = static_cast<ICLRDebuggingLibraryProvider *>(this);
+        }
+#endif
+        else if (InterfaceId == IID_ICLRDebuggingLibraryProvider2)
+        {
+            *pInterface = static_cast<ICLRDebuggingLibraryProvider2 *>(this);
+        }
+        else
+        {
+            *pInterface = NULL;
+            return E_NOINTERFACE;
+        }
+
+        AddRef();
+        return S_OK;
+    }
+    
+    virtual ULONG STDMETHODCALLTYPE AddRef()
+    {
+        return InterlockedIncrement(&m_ref);    
+    }
+
+    virtual ULONG STDMETHODCALLTYPE Release()
+    {
+        LONG ref = InterlockedDecrement(&m_ref);
+        if (ref == 0)
+        {
+            delete this;
+        }
+        return ref;
+    }
+
+    HRESULT ProvideLibraryInternal(
+        const WCHAR* pwszFileName,
+        DWORD dwTimestamp,
+        DWORD dwSizeOfImage,
+        HMODULE* phModule,
+        LPWSTR* ppResolvedModulePath)
+    {
+        const char* filePath = nullptr;
+
+        if (_wcsncmp(pwszFileName, m_pRuntime->GetDacDllNameW(), _wcslen(m_pRuntime->GetDacDllNameW())) == 0)
+        {
+            filePath = m_pRuntime->GetDacFilePath();
+        }
+        else if (_wcsncmp(pwszFileName, NET_DBI_DLL_NAME_W, _wcslen(NET_DBI_DLL_NAME_W)) == 0)
+        {
+            filePath = m_pRuntime->GetDbiFilePath();
+        }
+
+        ArrayHolder<WCHAR> modulePath = new WCHAR[MAX_LONGPATH + 1];
+        if (filePath != nullptr)
+        {
+            int length = MultiByteToWideChar(CP_ACP, 0, filePath, -1, modulePath, MAX_LONGPATH);
+            if (0 >= length)
+            {
+                ExtErr("MultiByteToWideChar(filePath) failed. Last error = 0x%x\n", GetLastError());
+                return HRESULT_FROM_WIN32(GetLastError());
+            }
+        }
+        else
+        {
+            LPCSTR runtimeDirectory = m_pRuntime->GetRuntimeDirectory();
+            if (runtimeDirectory == nullptr)
+            {
+                ExtErr("Runtime not loaded\n");
+                return E_FAIL;
+            }
+            int length = MultiByteToWideChar(CP_ACP, 0, runtimeDirectory, -1, modulePath, MAX_LONGPATH);
+            if (0 >= length)
+            {
+                ExtErr("MultiByteToWideChar(runtimeDirectory) failed. Last error = 0x%x\n", GetLastError());
+                return HRESULT_FROM_WIN32(GetLastError());
+            }
+            wcscat_s(modulePath, MAX_LONGPATH, pwszFileName);
+        }
+
+        ExtOut("Loaded %S\n", modulePath.GetPtr());
+
+#ifndef FEATURE_PAL
+        if (phModule != NULL)
+        {
+            *phModule = LoadLibraryAndCheck(modulePath.GetPtr(), dwTimestamp, dwSizeOfImage);
+        }
+#endif
+        if (ppResolvedModulePath != NULL)
+        {
+            *ppResolvedModulePath = modulePath.Detach();
+        }
+        return S_OK;
+    }
+
+    // Called by the shim to locate and load dac and dbi
+    // Parameters:
+    //    pwszFileName - the name of the file to load
+    //    dwTimestamp - the expected timestamp of the file
+    //    dwSizeOfImage - the expected SizeOfImage (a PE header data value)
+    //    phModule - a handle to loaded module
+    //
+    // Return Value
+    //    S_OK if the file was loaded, or any error if not
+    virtual HRESULT STDMETHODCALLTYPE ProvideLibrary(
+        const WCHAR * pwszFileName,
+        DWORD dwTimestamp,
+        DWORD dwSizeOfImage,
+        HMODULE* phModule)
+    {
+        if ((phModule == NULL) || (pwszFileName == NULL))
+        {
+            return E_INVALIDARG;
+        }
+        return ProvideLibraryInternal(pwszFileName, dwTimestamp, dwSizeOfImage, phModule, NULL);
+    }
+
+    virtual HRESULT STDMETHODCALLTYPE ProvideLibrary2(
+        const WCHAR* pwszFileName,
+        DWORD dwTimestamp,
+        DWORD dwSizeOfImage,
+        LPWSTR* ppResolvedModulePath)
+    {
+        if ((pwszFileName == NULL) || (ppResolvedModulePath == NULL))
+        {
+            return E_INVALIDARG;
+        }
+        return ProvideLibraryInternal(pwszFileName, dwTimestamp, dwSizeOfImage, NULL, ppResolvedModulePath);
+    }
+
+protected:
+    LONG m_ref;
+    Runtime* m_pRuntime;
+};
+
+#endif // __cordebuglibraryprovider_h__
index cec59b5a68b5160757b5fed9214a32d6fac34b33..1eb3920cb027184e457d02e35f56191b8fd98e76 100644 (file)
@@ -90,8 +90,6 @@ void DumpStackWorker (DumpStackFlag &DSFlag);
 
 void UnassemblyUnmanaged (DWORD_PTR IP, BOOL bSuppressLines);
 
-HRESULT CheckEEDll ();
-
 BOOL GetCalleeSite (DWORD_PTR IP, DWORD_PTR &IPCallee);
 
 void DisasmAndClean (DWORD_PTR &IP, __out_ecount_opt(length) char *line, ULONG length);
index e15e88776d427aa6b96ce4553c0f608e6936e470..cefec80d91333cdea1c217cadcb9fb4360d698ec 100644 (file)
@@ -79,6 +79,7 @@ typedef struct _TADDR_SEGINFO
 } TADDR_SEGINFO;
 
 #include "util.h"
+#include "runtime.h"
 
 #ifdef __cplusplus
 extern "C" {
@@ -175,7 +176,6 @@ inline BOOL IsInterrupt()
         ExtOut("Command canceled at the user's request.\n");
         ControlC = TRUE;
     }
-
     return ControlC;
 }
 
@@ -196,7 +196,11 @@ public:
 
 inline void EENotLoadedMessage(HRESULT Status)
 {
-    ExtOut("Failed to find runtime module (%s), 0x%08x\n", GetRuntimeDllName(), Status);
+#ifdef FEATURE_PAL
+    ExtOut("Failed to find runtime module (%s), 0x%08x\n", NETCORE_RUNTIME_DLL_NAME_A, Status);
+#else
+    ExtOut("Failed to find runtime module (%s or %s), 0x%08x\n", NETCORE_RUNTIME_DLL_NAME_A, DESKTOP_RUNTIME_DLL_NAME_A, Status);
+#endif
     ExtOut("Extension commands need it in order to have something to do.\n");
 }
 
@@ -204,7 +208,7 @@ inline void DACMessage(HRESULT Status)
 {
     ExtOut("Failed to load data access module, 0x%08x\n", Status);
 #ifndef FEATURE_PAL
-    ExtOut("Verify that 1) you have a recent build of the debugger (6.2.14 or newer)\n");
+    ExtOut("Verify that 1) you have a recent build of the debugger (10.0.18317.1001 or newer)\n");
     ExtOut("            2) the file %s that matches your version of %s is\n", GetDacDllName(), GetRuntimeDllName());
     ExtOut("                in the version directory or on the symbol path\n");
     ExtOut("            3) or, if you are debugging a dump file, verify that the file \n");
@@ -251,7 +255,7 @@ HRESULT CheckEEDll();
     if ((Status = ArchQuery()) != S_OK) return Status;
 
 #define INIT_API_EE()                                           \
-    if ((Status = CheckEEDll()) != S_OK)                        \
+    if ((Status = CheckEEDll()) != S_OK)           \
     {                                                           \
         EENotLoadedMessage(Status);                             \
         return Status;                                          \
@@ -285,13 +289,8 @@ HRESULT CheckEEDll();
 // and functions they call should test g_bDacBroken before calling any DAC enabled
 // feature.
 #define INIT_API_NO_RET_ON_FAILURE()                            \
-    INIT_API_NOEE()                                             \
-    if ((Status = CheckEEDll()) != S_OK)                        \
-    {                                                           \
-        ExtOut("Failed to find runtime module (%s), 0x%08x\n", GetRuntimeDllName(), Status); \
-        ExtOut("Some functionality may be impaired\n");         \
-    }                                                           \
-    else if ((Status = LoadClrDebugDll()) != S_OK)              \
+    INIT_API_NODAC()                                             \
+    if ((Status = LoadClrDebugDll()) != S_OK)              \
     {                                                           \
         ExtOut("Failed to load data access module (%s), 0x%08x\n", GetDacDllName(), Status); \
         ExtOut("Some functionality may be impaired\n");         \
index e362a1b843d7dfd49b00f137108244174000a54a..62e4dc194480103f947d451edcb9223478c5f5b2 100644 (file)
@@ -9,6 +9,7 @@
 // ==--==
 #include "sos.h"
 #include "disasm.h"
+#include "runtime.h"
 #include <dbghelp.h>
 
 #include "corhdr.h"
 #endif
 
 static bool g_hostingInitialized = false;
-static bool g_symbolStoreInitialized = false;
+bool g_symbolStoreInitialized = false;
 LPCSTR g_hostRuntimeDirectory = nullptr;
-LPCSTR g_dacFilePath = nullptr;
-LPCSTR g_dbiFilePath = nullptr;
 LPCSTR g_tmpPath = nullptr;
 SOSNetCoreCallbacks g_SOSNetCoreCallbacks;
 #ifndef FEATURE_PAL
@@ -226,78 +225,6 @@ static bool GetEntrypointExecutableAbsolutePath(std::string& entrypointExecutabl
 
 #endif // FEATURE_PAL
 
-/**********************************************************************\
- * Returns the runtime module/runtime directory of the target.
-\**********************************************************************/
-HRESULT GetRuntimeDirectory(std::string& runtimeDirectory)
-{
-#ifdef FEATURE_PAL
-    LPCSTR directory = g_ExtServices->GetCoreClrDirectory();
-    if (directory == NULL)
-    {
-        ExtErr("Error: Runtime module (%s) not loaded yet\n", GetRuntimeDllName());
-        return E_FAIL;
-    }
-    if (!GetAbsolutePath(directory, runtimeDirectory))
-    {
-        ExtDbgOut("Error: Runtime directory %s doesn't exist\n", directory);
-        return E_FAIL;
-    }
-#else
-    ULONG index;
-    HRESULT Status = GetRuntimeModuleInfo(&index, NULL);
-    if (FAILED(Status))
-    {
-        ExtErr("Error: Runtime module (%s) not loaded yet\n", GetRuntimeDllName());
-        return Status;
-    }
-    ArrayHolder<char> szModuleName = new char[MAX_LONGPATH + 1];
-    Status = g_ExtSymbols->GetModuleNames(index, 0, szModuleName, MAX_LONGPATH, NULL, NULL, 0, NULL, NULL, 0, NULL);
-    if (FAILED(Status))
-    {
-        ExtErr("Error: Failed to get runtime module name\n");
-        return Status;
-    }
-    if (GetFileAttributesA(szModuleName) == INVALID_FILE_ATTRIBUTES)
-    {
-        Status = HRESULT_FROM_WIN32(GetLastError());
-        ExtDbgOut("Error: Runtime module %s doesn't exist %08x\n", szModuleName, Status);
-        return Status;
-    }
-    runtimeDirectory = szModuleName;
-
-    // Parse off the module name to get just the path
-    size_t lastSlash = runtimeDirectory.rfind(DIRECTORY_SEPARATOR_CHAR_A);
-    if (lastSlash == std::string::npos)
-    {
-        ExtDbgOut("Error: Runtime module %s has no directory separator\n", szModuleName);
-        return E_FAIL;
-    }
-    runtimeDirectory.assign(runtimeDirectory, 0, lastSlash);
-#endif
-    return S_OK;
-}
-
-/**********************************************************************\
- * Returns the runtime module/runtime directory of the target.
-\**********************************************************************/
-HRESULT GetRuntimeDirectory(LPWSTR modulePath, int modulePathSize)
-{
-    std::string runtimeDirectory;
-    HRESULT hr = GetRuntimeDirectory(runtimeDirectory);
-    if (FAILED(hr))
-    {
-        return hr;
-    }
-    int length = MultiByteToWideChar(CP_ACP, 0, runtimeDirectory.c_str(), -1, modulePath, modulePathSize);
-    if (0 >= length)
-    {
-        ExtErr("MultiByteToWideChar(runtimeDirectory) failed. Last error = 0x%x\n", GetLastError());
-        return HRESULT_FROM_WIN32(GetLastError());
-    }
-    return S_OK;
-}
-
 //
 // Searches the runtime directory for a .NET Core runtime version
 //
@@ -408,17 +335,22 @@ static HRESULT GetHostRuntime(std::string& coreClrPath, std::string& hostRuntime
                     // Find highest 3.1.x version
                     if (!FindDotNetVersion(3, 1, hostRuntimeDirectory))
                     {
+                        HRESULT hr = CheckEEDll();
+                        if (FAILED(hr)) {
+                            return hr;
+                        }
                         // Don't use the desktop runtime to host
-                        if (g_isDesktopRuntime)
+                        if (g_pRuntime->IsDesktop())
                         {
                             return E_FAIL;
                         }
                         // If an installed runtime can not be found, use the target coreclr version
-                        HRESULT hr = GetRuntimeDirectory(hostRuntimeDirectory);
-                        if (FAILED(hr))
+                        LPCSTR runtimeDirectory = g_pRuntime->GetRuntimeDirectory();
+                        if (runtimeDirectory == nullptr)
                         {
-                            return hr;
+                            return E_FAIL;
                         }
+                        hostRuntimeDirectory = runtimeDirectory;
                     }
                 }
             }
@@ -494,96 +426,10 @@ void CleanupTempDirectory()
     }
 }
 
-/**********************************************************************\
- * Returns the DAC module path to the rest of SOS.
-\**********************************************************************/
-LPCSTR GetDacFilePath()
-{
-    // If the DAC path hasn't been set by the symbol download support, use the one in the runtime directory.
-    if (g_dacFilePath == nullptr)
-    {
-        std::string dacModulePath;
-        HRESULT hr = GetRuntimeDirectory(dacModulePath);
-        if (SUCCEEDED(hr))
-        {
-            dacModulePath.append(DIRECTORY_SEPARATOR_STR_A);
-            dacModulePath.append(GetDacDllName());
-#ifdef FEATURE_PAL
-            // If DAC file exists in the runtime directory
-            if (access(dacModulePath.c_str(), F_OK) == 0)
-#endif
-            {
-#if defined(__linux__)
-                // We are creating a symlink to the DAC in a temp directory
-                // where libcoreclrtraceptprovider.so doesn't exist so it 
-                // doesn't get loaded by the DAC causing a LTTng-UST exception.
-                //
-                // Issue #https://github.com/dotnet/coreclr/issues/20205
-                LPCSTR tmpPath = GetTempDirectory();
-                if (tmpPath != nullptr) 
-                {
-                    std::string dacSymLink(tmpPath);
-                    dacSymLink.append(NETCORE_DAC_DLL_NAME_A);
-
-                    int error = symlink(dacModulePath.c_str(), dacSymLink.c_str());
-                    if (error == 0)
-                    {
-                        dacModulePath.assign(dacSymLink);
-                    }
-                    else
-                    {
-                        ExtErr("symlink(%s, %s) FAILED %s\n", dacModulePath.c_str(), dacSymLink.c_str(), strerror(errno));
-                    }
-                }
-#endif
-                g_dacFilePath = _strdup(dacModulePath.c_str());
-            }
-        }
-
-        if (g_dacFilePath == nullptr)
-        {
-            // Attempt to only load the DAC/DBI modules
-            LoadNativeSymbols(true);
-        }
-    }
-    return g_dacFilePath;
-}
-
-/**********************************************************************\
- * Returns the DBI module path to the rest of SOS.
-\**********************************************************************/
-LPCSTR GetDbiFilePath()
-{
-    if (g_dbiFilePath == nullptr)
-    {
-        std::string dbiModulePath;
-        HRESULT hr = GetRuntimeDirectory(dbiModulePath);
-        if (SUCCEEDED(hr))
-        {
-            dbiModulePath.append(DIRECTORY_SEPARATOR_STR_A);
-            dbiModulePath.append(NET_DBI_DLL_NAME_A);
-#ifdef FEATURE_PAL
-            // If DBI file exists in the runtime directory
-            if (access(dbiModulePath.c_str(), F_OK) == 0)
-#endif
-            {
-                g_dbiFilePath = _strdup(dbiModulePath.c_str());
-            }
-        }
-
-        if (g_dbiFilePath == nullptr)
-        {
-            // Attempt to only load the DAC/DBI modules
-            LoadNativeSymbols(true);
-        }
-    }
-    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)
+extern "C" HRESULT SOSInitializeByHost(SOSNetCoreCallbacks* callbacks, int callbacksSize, LPCSTR tempDirectory, bool isDesktop, LPCSTR dacFilePath, LPCSTR dbiFilePath, bool symbolStoreEnabled)
 {
     if (memcpy_s(&g_SOSNetCoreCallbacks, sizeof(g_SOSNetCoreCallbacks), callbacks, callbacksSize) != 0)
     {
@@ -593,14 +439,7 @@ extern "C" HRESULT SOSInitializeByHost(SOSNetCoreCallbacks* callbacks, int callb
     {
         g_tmpPath = _strdup(tempDirectory);
     }
-    if (dacFilePath != nullptr)
-    {
-        g_dacFilePath = _strdup(dacFilePath);
-    }
-    if (dbiFilePath != nullptr)
-    {
-        g_dbiFilePath = _strdup(dbiFilePath);
-    }
+    Runtime::SetDacDbiPath(isDesktop, dacFilePath, dbiFilePath);
 #ifndef FEATURE_PAL
     // When SOS is hosted on dotnet-dump, the ExtensionApis are not set so 
     // the expression evaluation function needs to be supplied.
@@ -756,7 +595,7 @@ HRESULT InitializeHosting()
 // Pass to managed helper code to read in-memory PEs/PDBs.
 // Returns the number of bytes read.
 //
-static int ReadMemoryForSymbols(ULONG64 address, uint8_t *buffer, int cb)
+int ReadMemoryForSymbols(ULONG64 address, uint8_t *buffer, int cb)
 {
     ULONG read;
     if (SafeReadMemory(TO_TADDR(address), (PVOID)buffer, cb, &read))
@@ -857,32 +696,23 @@ void InitializeSymbolStoreFromSymPath()
 }
 #endif // FEATURE_PAL
 
+#ifdef FEATURE_PAL
+
 //
 // Symbol downloader callback
 //
 static void SymbolFileCallback(void* param, const char* moduleFileName, const char* symbolFilePath)
 {
-    if (strcmp(moduleFileName, GetRuntimeDllName()) == 0) {
+    if (strcmp(moduleFileName, NETCORE_RUNTIME_DLL_NAME_A) == 0) {
         return;
     }
-    if (strcmp(moduleFileName, GetDacDllName()) == 0) {
-        if (g_dacFilePath == nullptr) {
-            g_dacFilePath = _strdup(symbolFilePath);
-        }
+    if (strcmp(moduleFileName, NETCORE_DAC_DLL_NAME_A) == 0) {
         return;
     }
     if (strcmp(moduleFileName, NET_DBI_DLL_NAME_A) == 0) {
-        if (g_dbiFilePath == nullptr) {
-            g_dbiFilePath = _strdup(symbolFilePath);
-        }
         return;
     }
-#ifdef FEATURE_PAL
-    if (g_ExtServices2 != nullptr) 
-    {
-        g_ExtServices2->AddModuleSymbol(param, symbolFilePath);
-    }
-#endif
+    g_ExtServices2->AddModuleSymbol(param, symbolFilePath);
 }
 
 //
@@ -903,40 +733,14 @@ static void LoadNativeSymbolsCallback(void* param, const char* moduleFilePath, U
 HRESULT LoadNativeSymbols(bool runtimeOnly)
 {
     HRESULT hr = S_OK;
-#ifdef FEATURE_PAL
     if (g_symbolStoreInitialized)
     {
-        hr = g_ExtServices2 ? g_ExtServices2->LoadNativeSymbols(runtimeOnly, LoadNativeSymbolsCallback) : E_NOINTERFACE;
+        hr = g_ExtServices2->LoadNativeSymbols(runtimeOnly, LoadNativeSymbolsCallback);
     }
-#else
-    if (runtimeOnly)
-    {
-        ULONG index;
-        ULONG64 moduleAddress;
-        HRESULT hr = GetRuntimeModuleInfo(&index, &moduleAddress);
-        if (SUCCEEDED(hr))
-        {
-            ArrayHolder<char> moduleFilePath = new char[MAX_LONGPATH + 1];
-            hr = g_ExtSymbols->GetModuleNames(index, 0, moduleFilePath, MAX_LONGPATH, NULL, NULL, 0, NULL, NULL, 0, NULL);
-            if (SUCCEEDED(hr))
-            {
-                DEBUG_MODULE_PARAMETERS moduleParams;
-                hr = g_ExtSymbols->GetModuleParameters(1, &moduleAddress, 0, &moduleParams);
-                if (SUCCEEDED(hr))
-                {
-                    hr = InitializeSymbolStore();
-                    if (SUCCEEDED(hr) && g_symbolStoreInitialized)
-                    {
-                        LoadNativeSymbolsCallback(nullptr, moduleFilePath, moduleAddress, moduleParams.Size);
-                    }
-                }
-            }
-        }
-    }
-#endif
     return hr;
 }
 
+#endif
 
 /**********************************************************************\
  * Displays the symbol server and cache status.
index f4848c6d2740392e0713eaf58edcdc7030758608..e1bc8d7f4f6d959dcbf7c9c8f1f6cd53cdc27c14 100644 (file)
@@ -70,15 +70,14 @@ static const char *MetadataHelperClassName = "SOS.MetadataHelper";
 
 extern HMODULE g_hInstance;
 extern LPCSTR g_hostRuntimeDirectory;
-extern LPCSTR g_dacFilePath;
-extern LPCSTR g_dbiFilePath;
 extern LPCSTR g_tmpPath;
 extern SOSNetCoreCallbacks g_SOSNetCoreCallbacks;
 
-extern HRESULT GetRuntimeDirectory(std::string& runtimeDirectory);
-extern HRESULT GetRuntimeDirectory(LPWSTR modulePath, int modulePathSize);
-extern LPCSTR GetDacFilePath();
-extern LPCSTR GetDbiFilePath();
+#ifdef FEATURE_PAL
+extern bool GetAbsolutePath(const char* path, std::string& absolutePath);
+extern HRESULT LoadNativeSymbols(bool runtimeOnly = false);
+#endif
+
 extern LPCSTR GetTempDirectory();
 extern void CleanupTempDirectory();
 extern BOOL IsHostingInitialized();
@@ -98,7 +97,6 @@ extern HRESULT InitializeSymbolStore(
 extern void InitializeSymbolStoreFromSymPath();
 #endif
 
-extern HRESULT LoadNativeSymbols(bool runtimeOnly = false);
 extern void DisplaySymbolStore();
 extern void DisableSymbolStore();
 
diff --git a/src/SOS/Strike/runtime.cpp b/src/SOS/Strike/runtime.cpp
new file mode 100644 (file)
index 0000000..cafe21b
--- /dev/null
@@ -0,0 +1,599 @@
+// 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.
+
+#include "strike.h"
+#include "util.h"
+#include <string>
+#include <corhdr.h>
+#include <cor.h>
+#include <clrdata.h>
+#include <dbghelp.h>
+#include <cordebug.h>
+#include <xcordebug.h>
+#include <mscoree.h>
+#include <psapi.h>
+#include <clrinternal.h>
+#include <metahost.h>
+#include <debugshim.h>
+#include "runtime.h"
+#include "datatarget.h"
+#include "cordebugdatatarget.h"
+#include "cordebuglibraryprovider.h"
+
+#ifdef FEATURE_PAL
+#include <sys/stat.h>
+#include <dlfcn.h>
+#include <unistd.h>
+#endif // !FEATURE_PAL
+
+Runtime* Runtime::s_netcore = nullptr;
+#ifndef FEATURE_PAL
+Runtime* Runtime::s_desktop = nullptr;
+#endif
+
+// Used to initialize the runtime instance with values from the host when under dotnet-dump
+bool Runtime::s_isDesktop = false;
+LPCSTR Runtime::s_dacFilePath = nullptr;
+LPCSTR Runtime::s_dbiFilePath = nullptr;
+
+// Current runtime instance
+IRuntime* g_pRuntime = nullptr;
+
+/**********************************************************************\
+ * Creates a desktop or .NET Core instance of the runtime class
+\**********************************************************************/
+HRESULT Runtime::CreateInstance(bool isDesktop, Runtime **ppRuntime)
+{
+    PCSTR runtimeModuleName = isDesktop ? DESKTOP_RUNTIME_MODULE_NAME_A : NETCORE_RUNTIME_MODULE_NAME_A;
+    ULONG moduleIndex = 0;
+    ULONG64 moduleAddress = 0;
+    ULONG64 moduleSize = 0;
+    HRESULT hr = S_OK;
+
+    if (*ppRuntime == nullptr)
+    {
+        hr = g_ExtSymbols->GetModuleByModuleName(runtimeModuleName, 0, &moduleIndex, &moduleAddress);
+        if (SUCCEEDED(hr))
+        {
+#ifdef FEATURE_PAL
+            hr = g_ExtServices2->GetModuleInfo(moduleIndex, nullptr, &moduleSize);
+#else
+            _ASSERTE(moduleAddress != 0);
+            DEBUG_MODULE_PARAMETERS params;
+            hr = g_ExtSymbols->GetModuleParameters(1, &moduleAddress, 0, &params);
+            if (SUCCEEDED(hr))
+            {
+                moduleSize = params.Size;
+
+                if (params.SymbolType == SymDeferred)
+                {
+                    std::string reloadCommand;
+                    reloadCommand.append("/f ");
+                    reloadCommand.append(runtimeModuleName);
+                    reloadCommand.append(".dll");
+                    g_ExtSymbols->Reload(reloadCommand.c_str());
+                    g_ExtSymbols->GetModuleParameters(1, &moduleAddress, 0, &params);
+
+                    if (params.SymbolType != SymPdb && params.SymbolType != SymDia)
+                    {
+                        ExtOut("PDB symbol for %s not loaded\n", runtimeModuleName);
+                    }
+                }
+            }
+#endif
+        }
+        if (SUCCEEDED(hr))
+        {
+            *ppRuntime = new Runtime(isDesktop, moduleIndex, moduleAddress, moduleSize);
+            OnUnloadTask::Register(CleanupRuntimes);
+        }
+    }
+    return hr;
+}
+
+/**********************************************************************\
+ * Creates an instance of the runtime class. First it attempts to create
+ * the .NET Core instance and if that fails, it will try to create the
+ * desktop CLR instance.  If both runtimes exists in the process or dump
+ * this runtime only creates the .NET Core version and leaves creating
+ * the desktop instance on demand in SwitchRuntime.
+\**********************************************************************/
+HRESULT Runtime::CreateInstance()
+{
+    HRESULT hr = S_OK;
+    if (g_pRuntime == nullptr)
+    {
+        hr = CreateInstance(false, &s_netcore);
+#ifdef FEATURE_PAL
+        g_pRuntime = s_netcore;
+#else
+        if (FAILED(hr))
+        {
+            hr = CreateInstance(true, &s_desktop);
+        }
+        g_pRuntime = s_netcore != nullptr ? s_netcore : s_desktop;
+#endif
+    }
+    return hr;
+}
+
+/**********************************************************************\
+ * Switches between the .NET Core and desktop runtimes (if both 
+ * loaded). Creates the desktop CLR runtime instance on demand.
+\**********************************************************************/
+#ifndef FEATURE_PAL
+bool Runtime::SwitchRuntime(bool desktop)
+{
+    if (desktop) {
+        CreateInstance(true, &s_desktop);
+    }
+    IRuntime* runtime = desktop ? s_desktop : s_netcore;
+    if (runtime == nullptr) {
+        return false;
+    }
+    g_pRuntime = runtime;
+    return true;
+}
+#endif
+
+/**********************************************************************\
+ * Cleans up the runtime instances
+\**********************************************************************/
+void Runtime::CleanupRuntimes()
+{
+    if (s_netcore != nullptr)
+    {
+        delete s_netcore;
+        s_netcore = nullptr;
+    }
+#ifndef FEATURE_PAL
+    if (s_desktop != nullptr)
+    {
+        delete s_desktop;
+        s_desktop = nullptr;
+    }
+#endif
+    g_pRuntime = nullptr;
+}
+
+/**********************************************************************\
+ * Destroys the runtime instance
+\**********************************************************************/
+Runtime::~Runtime()
+{
+    if (m_runtimeDirectory != nullptr)
+    {
+        free((void*)m_runtimeDirectory);
+        m_runtimeDirectory = nullptr;
+    }
+    if (m_dacFilePath != nullptr)
+    {
+        free((void*)m_dacFilePath);
+        m_dacFilePath = nullptr;
+    }
+    if (m_dbiFilePath != nullptr)
+    {
+        free((void*)m_dbiFilePath);
+        m_dbiFilePath = nullptr;
+    }
+    if (m_pCorDebugProcess != NULL)
+    {
+        m_pCorDebugProcess->Detach();
+        m_pCorDebugProcess->Release();
+        m_pCorDebugProcess = nullptr;
+    }
+    if (m_clrDataProcess != nullptr)
+    {
+        m_clrDataProcess->Release();
+        m_clrDataProcess = nullptr;
+    }
+}
+
+/**********************************************************************\
+ * Flushes DAC caches
+\**********************************************************************/
+void Runtime::Flush()
+{
+    if (s_netcore != nullptr && s_netcore->m_clrDataProcess != nullptr)
+    {
+        s_netcore->m_clrDataProcess->Flush();
+    }
+#ifndef FEATURE_PAL
+    if (s_desktop != nullptr && s_desktop->m_clrDataProcess != nullptr)
+    {
+        s_desktop->m_clrDataProcess->Flush();
+    }
+#endif
+}
+
+/**********************************************************************\
+ * Returns the runtime directory of the target
+\**********************************************************************/
+HRESULT Runtime::GetRuntimeDirectory(std::string& runtimeDirectory)
+{
+#ifdef FEATURE_PAL
+    LPCSTR directory = g_ExtServices->GetCoreClrDirectory();
+    if (directory == NULL)
+    {
+        ExtErr("Error: Runtime module (%s) not loaded yet\n", GetRuntimeDllName());
+        return E_FAIL;
+    }
+    if (!GetAbsolutePath(directory, runtimeDirectory))
+    {
+        ExtDbgOut("Error: Runtime directory %s doesn't exist\n", directory);
+        return E_FAIL;
+    }
+#else
+    ArrayHolder<char> szModuleName = new char[MAX_LONGPATH + 1];
+    HRESULT hr = g_ExtSymbols->GetModuleNames(m_index, 0, szModuleName, MAX_LONGPATH, NULL, NULL, 0, NULL, NULL, 0, NULL);
+    if (FAILED(hr))
+    {
+        ExtErr("Error: Failed to get runtime module name\n");
+        return hr;
+    }
+    if (GetFileAttributesA(szModuleName) == INVALID_FILE_ATTRIBUTES)
+    {
+        hr = HRESULT_FROM_WIN32(GetLastError());
+        ExtDbgOut("Error: Runtime module %s doesn't exist %08x\n", szModuleName, hr);
+        return hr;
+    }
+    runtimeDirectory = szModuleName;
+
+    // Parse off the module name to get just the path
+    size_t lastSlash = runtimeDirectory.rfind(DIRECTORY_SEPARATOR_CHAR_A);
+    if (lastSlash == std::string::npos)
+    {
+        ExtDbgOut("Error: Runtime module %s has no directory separator\n", szModuleName);
+        return E_FAIL;
+    }
+    runtimeDirectory.assign(runtimeDirectory, 0, lastSlash);
+#endif
+    return S_OK;
+}
+
+/**********************************************************************\
+ * Returns the runtime directory of the target
+\**********************************************************************/
+LPCSTR Runtime::GetRuntimeDirectory()
+{
+    if (m_runtimeDirectory == nullptr)
+    {
+        std::string runtimeDirectory;
+        if (SUCCEEDED(GetRuntimeDirectory(runtimeDirectory)))
+        {
+            m_runtimeDirectory = _strdup(runtimeDirectory.c_str());
+        }
+    }
+    return m_runtimeDirectory;
+}
+
+/**********************************************************************\
+ * Returns the DAC module path to the rest of SOS.
+\**********************************************************************/
+LPCSTR Runtime::GetDacFilePath()
+{
+    // If the DAC path hasn't been set by the symbol download support, use the one in the runtime directory.
+    if (m_dacFilePath == nullptr)
+    {
+        LPCSTR directory = GetRuntimeDirectory();
+        if (directory != nullptr)
+        {
+            std::string dacModulePath(directory);
+            dacModulePath.append(DIRECTORY_SEPARATOR_STR_A);
+            dacModulePath.append(GetDacDllName());
+#ifdef FEATURE_PAL
+            // If DAC file exists in the runtime directory
+            if (access(dacModulePath.c_str(), F_OK) == 0)
+#endif
+            {
+#if defined(__linux__)
+                // We are creating a symlink to the DAC in a temp directory
+                // where libcoreclrtraceptprovider.so doesn't exist so it 
+                // doesn't get loaded by the DAC causing a LTTng-UST exception.
+                //
+                // Issue #https://github.com/dotnet/coreclr/issues/20205
+                LPCSTR tmpPath = GetTempDirectory();
+                if (tmpPath != nullptr) 
+                {
+                    std::string dacSymLink(tmpPath);
+                    dacSymLink.append(NETCORE_DAC_DLL_NAME_A);
+
+                    int error = symlink(dacModulePath.c_str(), dacSymLink.c_str());
+                    if (error == 0)
+                    {
+                        dacModulePath.assign(dacSymLink);
+                    }
+                    else
+                    {
+                        ExtErr("symlink(%s, %s) FAILED %s\n", dacModulePath.c_str(), dacSymLink.c_str(), strerror(errno));
+                    }
+                }
+#endif
+                m_dacFilePath = _strdup(dacModulePath.c_str());
+            }
+        }
+
+        if (m_dacFilePath == nullptr)
+        {
+            // Attempt to only load the DAC/DBI modules
+            LoadRuntimeModules();
+        }
+    }
+    return m_dacFilePath;
+}
+
+/**********************************************************************\
+ * Returns the DBI module path to the rest of SOS
+\**********************************************************************/
+LPCSTR Runtime::GetDbiFilePath()
+{
+    if (m_dbiFilePath == nullptr)
+    {
+        LPCSTR directory = GetRuntimeDirectory();
+        if (directory != nullptr)
+        {
+            std::string dbiModulePath(directory);
+            dbiModulePath.append(DIRECTORY_SEPARATOR_STR_A);
+            dbiModulePath.append(NET_DBI_DLL_NAME_A);
+#ifdef FEATURE_PAL
+            // If DBI file exists in the runtime directory
+            if (access(dbiModulePath.c_str(), F_OK) == 0)
+#endif
+            {
+                m_dbiFilePath = _strdup(dbiModulePath.c_str());
+            }
+        }
+
+        if (m_dbiFilePath == nullptr)
+        {
+            // Attempt to only load the DAC/DBI modules
+            LoadRuntimeModules();
+        }
+    }
+    return m_dbiFilePath;
+}
+
+/**********************************************************************\
+ * Creates an instance of the DAC clr data process
+\**********************************************************************/
+HRESULT Runtime::GetClrDataProcess(IXCLRDataProcess** ppClrDataProcess)
+{
+    if (m_clrDataProcess == nullptr)
+    {
+        *ppClrDataProcess = nullptr;
+
+        LPCSTR dacFilePath = GetDacFilePath();
+        if (dacFilePath == nullptr)
+        {
+            return CORDBG_E_NO_IMAGE_AVAILABLE;
+        }
+        HMODULE hdac = LoadLibraryA(dacFilePath);
+        if (hdac == NULL)
+        {
+            return CORDBG_E_MISSING_DEBUGGER_EXPORTS;
+        }
+        PFN_CLRDataCreateInstance pfnCLRDataCreateInstance = (PFN_CLRDataCreateInstance)GetProcAddress(hdac, "CLRDataCreateInstance");
+        if (pfnCLRDataCreateInstance == nullptr)
+        {
+            FreeLibrary(hdac);
+            return CORDBG_E_MISSING_DEBUGGER_EXPORTS;
+        }
+        ICLRDataTarget *target = new DataTarget();
+        HRESULT hr = pfnCLRDataCreateInstance(__uuidof(IXCLRDataProcess), target, (void**)&m_clrDataProcess);
+        if (FAILED(hr))
+        {
+            m_clrDataProcess = nullptr;
+            return hr;
+        }
+        ULONG32 flags = 0;
+        m_clrDataProcess->GetOtherNotificationFlags(&flags);
+        flags |= (CLRDATA_NOTIFY_ON_MODULE_LOAD | CLRDATA_NOTIFY_ON_MODULE_UNLOAD | CLRDATA_NOTIFY_ON_EXCEPTION);
+        m_clrDataProcess->SetOtherNotificationFlags(flags);
+    }
+    *ppClrDataProcess = m_clrDataProcess;
+    return S_OK;
+}
+
+/**********************************************************************\
+ * Loads and initializes the public ICorDebug interfaces. This should be 
+ * called at least once per debugger stop state to ensure that the 
+ * interface is available and that it doesn't hold stale data. Calling
+ * it more than once isn't an error, but does have perf overhead from 
+ * needlessly flushing memory caches.
+\**********************************************************************/
+HRESULT Runtime::GetCorDebugInterface(ICorDebugProcess** ppCorDebugProcess)
+{
+    HMODULE hModule = NULL;
+    HRESULT hr;
+    ToRelease<ICLRDebugging> pClrDebugging;
+
+    // We may already have an ICorDebug instance we can use
+    if (m_pCorDebugProcess != nullptr)
+    {
+        // ICorDebugProcess4 is currently considered a private experimental interface on ICorDebug, it might go away so
+        // we need to be sure to handle its absence gracefully
+        ToRelease<ICorDebugProcess4> pProcess4 = NULL;
+        if (SUCCEEDED(m_pCorDebugProcess->QueryInterface(__uuidof(ICorDebugProcess4), (void**)&pProcess4)))
+        {
+            // FLUSH_ALL is more expensive than PROCESS_RUNNING, but this allows us to be safe even if things
+            // like IDNA are in use where we might be looking at non-sequential snapshots of process state
+            if (SUCCEEDED(pProcess4->ProcessStateChanged(FLUSH_ALL)))
+            {
+                // We already have an ICorDebug instance loaded and flushed, nothing more to do
+                *ppCorDebugProcess = m_pCorDebugProcess;
+                return S_OK;
+            }
+        }
+
+        // This is a very heavy handed way of reseting
+        m_pCorDebugProcess->Detach();
+        m_pCorDebugProcess->Release();
+        m_pCorDebugProcess = nullptr;
+    }
+
+    // SOS now has a statically linked version of the loader code that is normally found in mscoree/mscoreei.dll
+    // Its not much code and takes a big step towards 0 install dependencies
+    // Need to pick the appropriate SKU of CLR to detect
+#if defined(FEATURE_CORESYSTEM)
+    GUID skuId = CLR_ID_ONECORE_CLR;
+#else
+    GUID skuId = CLR_ID_CORECLR;
+#endif
+#ifndef FEATURE_PAL
+    if (IsDesktop())
+    {
+        skuId = CLR_ID_V4_DESKTOP;
+    }
+#endif
+    CLRDebuggingImpl* pDebuggingImpl = new CLRDebuggingImpl(skuId);
+    hr = pDebuggingImpl->QueryInterface(IID_ICLRDebugging, (LPVOID *)&pClrDebugging);
+    if (FAILED(hr))
+    {
+        delete pDebuggingImpl;
+        return hr;
+    }
+
+    ToRelease<ICorDebugMutableDataTarget> pCorDebugDataTarget = new CorDebugDataTarget;
+    pCorDebugDataTarget->AddRef();
+
+    ToRelease<ICLRDebuggingLibraryProvider> pCorDebugLibraryProvider = new CorDebugLibraryProvider(this);
+    pCorDebugLibraryProvider->AddRef();
+
+    CLR_DEBUGGING_VERSION clrDebuggingVersionRequested = {0};
+    clrDebuggingVersionRequested.wMajor = 4;
+
+    CLR_DEBUGGING_VERSION clrDebuggingVersionActual = {0};
+
+    CLR_DEBUGGING_PROCESS_FLAGS clrDebuggingFlags = (CLR_DEBUGGING_PROCESS_FLAGS)0;
+
+    ToRelease<IUnknown> pUnkProcess;
+    hr = pClrDebugging->OpenVirtualProcess(
+        GetModuleAddress(),
+        pCorDebugDataTarget,
+        pCorDebugLibraryProvider,
+        &clrDebuggingVersionRequested,
+        IID_ICorDebugProcess,
+        &pUnkProcess,
+        &clrDebuggingVersionActual,
+        &clrDebuggingFlags);
+
+    if (FAILED(hr)) {
+        return hr;
+    }
+    hr = pUnkProcess->QueryInterface(IID_ICorDebugProcess, (PVOID*)&m_pCorDebugProcess);
+    if (FAILED(hr)) {
+        return hr;
+    }
+    *ppCorDebugProcess = m_pCorDebugProcess;
+    return hr;
+}
+
+/**********************************************************************\
+ * Displays the runtime internal status
+\**********************************************************************/
+void Runtime::DisplayStatus()
+{
+    ExtOut("%s runtime at %p (%08x)\n", m_isDesktop ? "Desktop" : ".NET Core", m_address, m_size);
+    if (m_runtimeDirectory != nullptr) {
+        ExtOut("Runtime directory: %s\n", m_runtimeDirectory);
+    }
+    if (m_dacFilePath != nullptr) {
+        ExtOut("DAC file path: %s\n", m_dacFilePath);
+    }
+    if (m_dbiFilePath != nullptr) {
+        ExtOut("DBI file path: %s\n", m_dbiFilePath);
+    }
+}
+
+extern bool g_symbolStoreInitialized;
+extern HRESULT InitializeSymbolStore();
+extern int ReadMemoryForSymbols(ULONG64 address, uint8_t* buffer, int cb);
+
+/**********************************************************************\
+ * Attempt to download the runtime modules (runtime, DAC and DBI)
+\**********************************************************************/
+void Runtime::LoadRuntimeModules()
+{
+    ArrayHolder<char> moduleFilePath = new char[MAX_LONGPATH + 1];
+    HRESULT hr = g_ExtSymbols->GetModuleNames(m_index, 0, moduleFilePath, MAX_LONGPATH, NULL, NULL, 0, NULL, NULL, 0, NULL);
+    if (SUCCEEDED(hr))
+    {
+        hr = InitializeSymbolStore();
+        if (SUCCEEDED(hr) && g_symbolStoreInitialized)
+        {
+            _ASSERTE(g_SOSNetCoreCallbacks.LoadNativeSymbolsDelegate != nullptr);
+            g_SOSNetCoreCallbacks.LoadNativeSymbolsDelegate(SymbolFileCallback, this, moduleFilePath, m_address, (int)m_size, ReadMemoryForSymbols);
+        }
+    }
+}
+
+/**********************************************************************\
+ * Called by LoadRuntimeModules to set the DAC and DBI file paths
+\**********************************************************************/
+void Runtime::SymbolFileCallback(const char* moduleFileName, const char* symbolFilePath)
+{
+    if (strcmp(moduleFileName, GetRuntimeDllName()) == 0) {
+        return;
+    }
+    if (strcmp(moduleFileName, GetDacDllName()) == 0) {
+        SetDacFilePath(symbolFilePath);
+        return;
+    }
+    if (strcmp(moduleFileName, NET_DBI_DLL_NAME_A) == 0) {
+        SetDbiFilePath(symbolFilePath);
+        return;
+    }
+}
+
+#ifndef FEATURE_PAL
+
+/**********************************************************************\
+ * Internal function to load and check the version of the module
+\**********************************************************************/
+HMODULE LoadLibraryAndCheck(
+    PCWSTR filename,
+    DWORD timestamp,
+    DWORD filesize)
+{
+    HMODULE hModule = LoadLibraryExW(
+        filename,
+        NULL,                               //  __reserved
+        LOAD_WITH_ALTERED_SEARCH_PATH);     // Ensure we check the dir in wszFullPath first
+
+    if (hModule == NULL)
+    {
+        ExtOut("Unable to load '%S'. hr = 0x%x.\n", filename, HRESULT_FROM_WIN32(GetLastError()));
+        return NULL;
+    }
+    
+    // Did we load the right one?
+    MODULEINFO modInfo = {0};
+    if (!GetModuleInformation(
+        GetCurrentProcess(),
+        hModule,
+        &modInfo,
+        sizeof(modInfo)))
+    {
+        ExtOut("Failed to read module information for '%S'. hr = 0x%x.\n", filename, HRESULT_FROM_WIN32(GetLastError()));
+        FreeLibrary(hModule);
+        return NULL;
+    }
+
+    IMAGE_DOS_HEADER * pDOSHeader = (IMAGE_DOS_HEADER *) modInfo.lpBaseOfDll;
+    IMAGE_NT_HEADERS * pNTHeaders = (IMAGE_NT_HEADERS *) (((LPBYTE) modInfo.lpBaseOfDll) + pDOSHeader->e_lfanew);
+    DWORD dwSizeActual = pNTHeaders->OptionalHeader.SizeOfImage;
+    DWORD dwTimeStampActual = pNTHeaders->FileHeader.TimeDateStamp;
+    if ((dwSizeActual != filesize) || (dwTimeStampActual != timestamp))
+    {
+        ExtOut("Found '%S', but it does not match the CLR being debugged.\n", filename);
+        ExtOut("Size: Expected '0x%x', Actual '0x%x'\n", filesize, dwSizeActual);
+        ExtOut("Time stamp: Expected '0x%x', Actual '0x%x'\n", timestamp, dwTimeStampActual);
+        FreeLibrary(hModule);
+        return NULL;
+    }
+
+    return hModule;
+}
+
+#endif // FEATURE_PAL
diff --git a/src/SOS/Strike/runtime.h b/src/SOS/Strike/runtime.h
new file mode 100644 (file)
index 0000000..eef4893
--- /dev/null
@@ -0,0 +1,257 @@
+// 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.
+
+#ifndef __runtime_h__
+#define __runtime_h__
+
+#ifdef FEATURE_PAL
+
+#define NETCORE_RUNTIME_MODULE_NAME_W   MAKEDLLNAME_W(W("coreclr"))
+#define NETCORE_RUNTIME_MODULE_NAME_A   MAKEDLLNAME_A("coreclr")
+#define NETCORE_RUNTIME_DLL_NAME_W      NETCORE_RUNTIME_MODULE_NAME_W
+#define NETCORE_RUNTIME_DLL_NAME_A      NETCORE_RUNTIME_MODULE_NAME_A
+
+#define NETCORE_DAC_MODULE_NAME_W       MAKEDLLNAME_W(W("mscordaccore"))
+#define NETCORE_DAC_MODULE_NAME_A       MAKEDLLNAME_A("mscordaccore")
+#define NETCORE_DAC_DLL_NAME_W          NETCORE_DAC_MODULE_NAME_W
+#define NETCORE_DAC_DLL_NAME_A          NETCORE_DAC_MODULE_NAME_A
+
+#define NET_DBI_MODULE_NAME_W           MAKEDLLNAME_W(W("mscordbi"))
+#define NET_DBI_MODULE_NAME_A           MAKEDLLNAME_A("mscordbi")
+#define NET_DBI_DLL_NAME_W              NET_DBI_MODULE_NAME_W       
+#define NET_DBI_DLL_NAME_A              NET_DBI_MODULE_NAME_A       
+
+#else
+
+#define NETCORE_RUNTIME_MODULE_NAME_W   W("coreclr")
+#define NETCORE_RUNTIME_MODULE_NAME_A   "coreclr"
+#define NETCORE_RUNTIME_DLL_NAME_W      MAKEDLLNAME_W(NETCORE_RUNTIME_MODULE_NAME_W)
+#define NETCORE_RUNTIME_DLL_NAME_A      MAKEDLLNAME_A(NETCORE_RUNTIME_MODULE_NAME_A)
+
+#define NETCORE_DAC_MODULE_NAME_W       W("mscordaccore")
+#define NETCORE_DAC_MODULE_NAME_A       "mscordaccore"
+#define NETCORE_DAC_DLL_NAME_W          MAKEDLLNAME_W(NETCORE_DAC_MODULE_NAME_W)
+#define NETCORE_DAC_DLL_NAME_A          MAKEDLLNAME_A(NETCORE_DAC_MODULE_NAME_A)
+
+#define NET_DBI_MODULE_NAME_W           W("mscordbi")
+#define NET_DBI_MODULE_NAME_A           "mscordbi"
+#define NET_DBI_DLL_NAME_W              MAKEDLLNAME_W(W("mscordbi"))
+#define NET_DBI_DLL_NAME_A              MAKEDLLNAME_A("mscordbi")
+
+#endif // FEATURE_PAL
+
+#define DESKTOP_RUNTIME_MODULE_NAME_W   W("clr")
+#define DESKTOP_RUNTIME_MODULE_NAME_A   "clr"
+#define DESKTOP_RUNTIME_DLL_NAME_W      MAKEDLLNAME_W(DESKTOP_RUNTIME_MODULE_NAME_W)
+#define DESKTOP_RUNTIME_DLL_NAME_A      MAKEDLLNAME_A(DESKTOP_RUNTIME_MODULE_NAME_A)
+
+#define DESKTOP_DAC_MODULE_NAME_W       W("mscordacwks")
+#define DESKTOP_DAC_MODULE_NAME_A       "mscordacwks"
+#define DESKTOP_DAC_DLL_NAME_W          MAKEDLLNAME_W(W("mscordacwks"))
+#define DESKTOP_DAC_DLL_NAME_A          MAKEDLLNAME_A("mscordacwks")
+
+/**********************************************************************\
+ * Runtime interface
+\**********************************************************************/
+class IRuntime
+{
+public:
+    // Returns true if desktop CLR; false if .NET Core
+    virtual bool IsDesktop() const = 0;
+
+    // Returns the runtime module index
+    virtual ULONG GetModuleIndex() const = 0;
+
+    // Returns the runtime module base address
+    virtual ULONG64 GetModuleAddress() const = 0;
+
+    // Returns the runtime module size
+    virtual ULONG64 GetModuleSize() const = 0;
+
+    // Returns the directory of the runtime file
+    virtual LPCSTR GetRuntimeDirectory() = 0;
+
+    // Returns the DAC module path to the rest of SOS
+    virtual LPCSTR GetDacFilePath() = 0;
+
+    // Returns the DBI module path to the rest of SOS
+    virtual LPCSTR GetDbiFilePath() = 0;
+
+    // Returns the DAC data process instance
+    virtual HRESULT GetClrDataProcess(IXCLRDataProcess** ppClrDataProcess) = 0;
+
+    // Initializes and returns the DBI debugging interface instance
+    virtual HRESULT GetCorDebugInterface(ICorDebugProcess** ppCorDebugProcess) = 0;
+
+    // Displays the runtime internal status
+    virtual void DisplayStatus() = 0;
+};
+
+extern IRuntime* g_pRuntime;
+
+/**********************************************************************\
+ * Local Runtime interface implementation
+\**********************************************************************/
+class Runtime : public IRuntime
+{
+private:
+    bool m_isDesktop;
+    ULONG m_index;
+    ULONG64 m_address;
+    ULONG64 m_size;
+    LPCSTR m_runtimeDirectory;
+    LPCSTR m_dacFilePath;
+    LPCSTR m_dbiFilePath;
+    IXCLRDataProcess* m_clrDataProcess;
+    ICorDebugProcess* m_pCorDebugProcess;
+
+    static Runtime* s_netcore;
+#ifndef FEATURE_PAL
+    static Runtime* s_desktop;
+#endif
+    static bool s_isDesktop;
+    static LPCSTR s_dacFilePath;
+    static LPCSTR s_dbiFilePath;
+
+    Runtime(bool isDesktop, ULONG index, ULONG64 address, ULONG64 size) : 
+        m_isDesktop(isDesktop),
+        m_index(index),
+        m_address(address),
+        m_size(size),
+        m_runtimeDirectory(nullptr),
+        m_dacFilePath(nullptr),
+        m_dbiFilePath(nullptr),
+        m_clrDataProcess(nullptr),
+        m_pCorDebugProcess(nullptr)
+    {
+        _ASSERTE(index != -1);
+        _ASSERTE(address != 0);
+        _ASSERTE(size != 0);
+        if (isDesktop == s_isDesktop) {
+            SetDacFilePath(s_dacFilePath);
+            SetDbiFilePath(s_dbiFilePath);
+        }
+    }
+
+    virtual Runtime::~Runtime();
+
+    static HRESULT CreateInstance(bool isDesktop, Runtime** ppRuntime);
+
+    HRESULT GetRuntimeDirectory(std::string& runtimeDirectory);
+
+    void LoadRuntimeModules();
+
+    void SymbolFileCallback(const char* moduleFileName, const char* symbolFilePath);
+
+    static void SymbolFileCallback(void* param, const char* moduleFileName, const char* symbolFilePath)
+    {
+        ((Runtime*)param)->SymbolFileCallback(moduleFileName, symbolFilePath);
+    }
+
+    void SetDacFilePath(LPCSTR dacFilePath)
+    { 
+        if (m_dacFilePath == nullptr && dacFilePath != nullptr) {
+            m_dacFilePath = _strdup(dacFilePath);
+        }
+    }
+
+    void SetDbiFilePath(LPCSTR dbiFilePath) 
+    { 
+        if (m_dbiFilePath == nullptr && dbiFilePath != nullptr) {
+            m_dbiFilePath = _strdup(dbiFilePath);
+        }
+    }
+
+public:
+    static HRESULT CreateInstance();
+
+    static void CleanupRuntimes();
+
+#ifndef FEATURE_PAL
+    static bool SwitchRuntime(bool desktop);
+#endif
+
+    static void SetDacDbiPath(bool isDesktop, LPCSTR dacFilePath, LPCSTR dbiFilePath)
+    {
+        s_isDesktop = isDesktop;
+        if (dacFilePath != nullptr) {
+            s_dacFilePath = _strdup(dacFilePath);
+        }
+        if (dbiFilePath != nullptr) {
+            s_dbiFilePath = _strdup(dbiFilePath);
+        }
+    }
+
+    static void Flush();
+
+    virtual bool IsDesktop() const { return m_isDesktop; }
+
+    virtual ULONG GetModuleIndex() const { return m_index; }
+
+    virtual ULONG64 GetModuleAddress() const { return m_address; }
+
+    virtual ULONG64 GetModuleSize() const { return m_size; }
+
+    LPCSTR GetRuntimeDirectory();
+
+    LPCSTR GetDacFilePath();
+
+    LPCSTR GetDbiFilePath();
+
+    HRESULT GetClrDataProcess(IXCLRDataProcess** ppClrDataProcess);
+
+    HRESULT GetCorDebugInterface(ICorDebugProcess** ppCorDebugProcess);
+
+    void DisplayStatus();
+
+    // Returns the runtime module DLL name (clr.dll, coreclr.dll, libcoreclr.so, libcoreclr.dylib)
+    inline const char* GetRuntimeDllName() const
+    {
+        return IsDesktop() ? DESKTOP_RUNTIME_DLL_NAME_A : NETCORE_RUNTIME_DLL_NAME_A;
+    }
+
+    // Returns the DAC module name (mscordacwks.dll, mscordaccore.dll, libmscordaccore.so, libmscordaccore.dylib) 
+    inline const char* GetDacDllName() const
+    {
+        return IsDesktop() ? DESKTOP_DAC_DLL_NAME_A : NETCORE_DAC_DLL_NAME_A;
+    }
+
+    // Returns the DAC module name (mscordacwks, mscordaccore, libmscordaccore.so, libmscordaccore.dylib) 
+    inline const WCHAR* GetDacModuleNameW() const
+    {
+        return IsDesktop() ? DESKTOP_DAC_MODULE_NAME_W : NETCORE_DAC_MODULE_NAME_W;
+    }
+
+    // Returns the DAC module name (mscordacwks.dll, mscordaccore.dll, libmscordaccore.so, libmscordaccore.dylib) 
+    inline const WCHAR* GetDacDllNameW() const
+    {
+        return IsDesktop() ? DESKTOP_DAC_DLL_NAME_W : NETCORE_DAC_DLL_NAME_W;
+    }
+};
+
+// Returns the runtime module name (clr, coreclr, libcoreclr.so, libcoreclr.dylib).
+inline const char* GetRuntimeModuleName()
+{
+    return g_pRuntime->IsDesktop() ? DESKTOP_RUNTIME_MODULE_NAME_A : NETCORE_RUNTIME_MODULE_NAME_A;
+}
+
+// Returns the runtime module DLL name (clr.dll, coreclr.dll, libcoreclr.so, libcoreclr.dylib)
+inline const char* GetRuntimeDllName()
+{
+    return g_pRuntime->IsDesktop() ? DESKTOP_RUNTIME_DLL_NAME_A : NETCORE_RUNTIME_DLL_NAME_A;
+}
+
+// Returns the DAC module name (mscordacwks, mscordaccore, libmscordaccore.so, libmscordaccore.dylib) 
+inline const char* GetDacModuleName()
+{
+    return g_pRuntime->IsDesktop() ? DESKTOP_DAC_MODULE_NAME_A : NETCORE_DAC_MODULE_NAME_A;
+}
+
+// Returns the DAC module name (mscordacwks.dll, mscordaccore.dll, libmscordaccore.so, libmscordaccore.dylib) 
+inline const char* GetDacDllName()
+{
+    return g_pRuntime->IsDesktop() ? DESKTOP_DAC_DLL_NAME_A : NETCORE_DAC_DLL_NAME_A;
+}
+
+#endif // __runtime_h__
index 655b39094e9f61c36fc1e95b9e2f179a16c0c5a8..fcd4cfad04f6cb8389c651d09ecc57dbe918be34 100644 (file)
@@ -64,7 +64,8 @@ HistInit                           SetHostRuntime (sethostruntime)
 HistRoot                           SetSymbolServer (setsymbolserver)
 HistObj                            FAQ
 HistObjFind                        SOSFlush
-HistClear                          Help (soshelp)
+HistClear                          SOSStatus (sosstatus)
+                                   Help (soshelp)
 \\
 
 COMMAND: faq.
@@ -2609,7 +2610,7 @@ You can use the "dotnet --info" in a command shell to find the path of an instal
 \\
 
 COMMAND: setsymbolserver.
-SetSymbolServer [-ms] [-mi] [-disable] [-log] [-cache <cache-path>] [-directory <search-directory>] [<symbol-server-URL>]
+!SetSymbolServer [-ms] [-mi] [-disable] [-log] [-cache <cache-path>] [-directory <search-directory>] [<symbol-server-URL>]
 
 -ms - Use the public Microsoft symbol server.
 -mi - Use the internal symweb symbol server.
@@ -2625,3 +2626,22 @@ symbol server support is automatically enabled.
 To disable downloading or clear the current SOS symbol settings allowing new symbol paths to be set:
 
     0:000> !setsymbolserver -disable
+\\
+
+COMMAND: sosstatus.
+!SOSStatus [-desktop] [-netcore] [-reset]
+
+-desktop - switch to the desktop runtime if loaded.
+-netcore - switch to the .NET Core runtime if loaded.
+-reset          - reset all the cached internal SOS state.
+
+Display internal SOS status, reset the internal cached state, or change between desktop or 
+netcore runtimes when both are loaded in the process or dump.
+
+0:000> !sosstatus
+Target platform: 8664 Context size 04d0
+.NET Core runtime at 00007FFEE7230000 (005c2000)
+DAC file path: C:\Users\mikem\AppData\Local\Temp\SymbolCache\mscordaccore.dll/5d0707425c2000/mscordaccore.dll
+DBI file path: C:\Users\mikem\AppData\Local\Temp\SymbolCache\mscordbi.dll/5d0707425c2000/mscordbi.dll
+Cache: C:\Users\mikem\AppData\Local\Temp\SymbolCache
+Server: http://msdl.microsoft.com/download/symbols/
\ No newline at end of file
index 3aa6df27b72a186837f5c7a1ca7b96cf9928f769..e2200387d4d3f9584abdcaad381f1091981d8784 100644 (file)
@@ -56,8 +56,9 @@ Examining the GC history           Other
 HistInit (histinit)                SetHostRuntime (sethostruntime)
 HistRoot (histroot)                SetSymbolServer (setsymbolserver, loadsymbols)
 HistObj  (histobj)                 FAQ
-HistObjFind (histobjfind)          SOSFlush
-HistClear (histclear)              Help (soshelp)
+HistObjFind (histobjfind)          SOSFlush (sosflush)
+HistClear (histclear)              SOSStatus (sosstatus)
+                                   Help (soshelp)
 \\
 
 COMMAND: faq.
@@ -1954,3 +1955,11 @@ stack frames).
 
     (lldb) loadsymbols
     (lldb) bt
+\\
+
+COMMAND: sosstatus.
+SOSStatus [-reset]
+
+-reset - reset all the cached internal SOS state.
+
+Display internal SOS status or reset the internal cached state.
index acd6d3d6363966227cf79c9cbc18250c765fd405..27814e649ac57656320b3919df0aaef403c57962 100644 (file)
@@ -1405,8 +1405,10 @@ DECLARE_API(DumpMT)
                 if (MethodDescData.Request(g_sos, TO_CDADDR(methodDesc)) == S_OK)
                 {
                     // Is it an fcall?
-                    if ((TO_TADDR(MethodDescData.NativeCodeAddr) >=  TO_TADDR(g_moduleInfo[MSCORWKS].baseAddr)) &&
-                        ((TO_TADDR(MethodDescData.NativeCodeAddr) <  TO_TADDR(g_moduleInfo[MSCORWKS].baseAddr + g_moduleInfo[MSCORWKS].size))))
+                    ULONG64 baseAddress = g_pRuntime->GetModuleAddress();
+                    ULONG64 size = g_pRuntime->GetModuleSize();
+                    if ((TO_TADDR(MethodDescData.NativeCodeAddr) >=  TO_TADDR(baseAddress)) &&
+                        ((TO_TADDR(MethodDescData.NativeCodeAddr) <  TO_TADDR(baseAddress + size))))
                     {
                         pszJitType = "FCALL";
                     }
@@ -7578,7 +7580,6 @@ public:
         }
         return m_count;
     }
-
             
     /*
      * New code was generated or discarded for a method.:
@@ -7586,9 +7587,11 @@ public:
     STDMETHODIMP OnCodeGenerated(IXCLRDataMethodInstance* method)
     {
 #ifndef FEATURE_PAL
+        _ASSERTE(g_pRuntime != nullptr);
+
         // This is only needed for desktop runtime because OnCodeGenerated2
         // isn't supported by the desktop DAC.
-        if (g_isDesktopRuntime)
+        if (g_pRuntime->IsDesktop())
         {
             // Some method has been generated, make a breakpoint and remove it.
             ULONG32 len = mdNameLen;
@@ -9831,8 +9834,10 @@ DECLARE_API(DumpLog)
 
     MINIDUMP_NOT_SUPPORTED();    
 
+    _ASSERTE(g_pRuntime != nullptr);
+
     // Not supported on desktop runtime
-    if (g_isDesktopRuntime)
+    if (g_pRuntime->IsDesktop())
     {
         ExtErr("DumpLog not supported on desktop runtime\n");
         return E_FAIL;
@@ -9915,12 +9920,6 @@ DECLARE_API (DumpGCLog)
     INIT_API_NODAC();
     MINIDUMP_NOT_SUPPORTED();    
     
-    if (GetEEFlavor() == UNKNOWNEE) 
-    {
-        ExtOut("CLR not loaded\n");
-        return Status;
-    }
-
     const char* fileName = "GCLog.txt";
 
     while (isspace (*args))
@@ -10021,12 +10020,6 @@ DECLARE_API (DumpGCConfigLog)
 #ifdef GC_CONFIG_DRIVEN    
     MINIDUMP_NOT_SUPPORTED();    
 
-    if (GetEEFlavor() == UNKNOWNEE) 
-    {
-        ExtOut("CLR not loaded\n");
-        return Status;
-    }
-
     const char* fileName = "GCConfigLog.txt";
 
     while (isspace (*args))
@@ -10317,11 +10310,6 @@ DECLARE_API(EEVersion)
 {
     INIT_API();
 
-    EEFLAVOR eef = GetEEFlavor();
-    if (eef == UNKNOWNEE) {
-        ExtOut("CLR not loaded\n");
-        return Status;
-    }
     static const int fileVersionBufferSize = 1024;
     ArrayHolder<char> fileVersionBuffer = new char[fileVersionBufferSize];
     VS_FIXEDFILEINFO version;
@@ -10347,7 +10335,7 @@ DECLARE_API(EEVersion)
             }
             else
             {
-                BOOL fRet = IsRetailBuild((size_t)g_moduleInfo[eef].baseAddr);
+                BOOL fRet = IsRetailBuild((size_t)g_pRuntime->GetModuleAddress());
                 if (fRet)
                     ExtOut(" retail");
                 else
@@ -10407,27 +10395,55 @@ DECLARE_API(EEVersion)
 \**********************************************************************/
 DECLARE_API(SOSStatus)
 {
-    INIT_API_NOEE();
+    INIT_API_EXT();
 
+    BOOL bDesktop = FALSE;
+    BOOL bNetCore = FALSE;
+    BOOL bReset = FALSE;
+    CMDOption option[] = 
+    {   // name, vptr, type, hasValue
+#ifndef FEATURE_PAL
+        {"-desktop", &bDesktop, COBOOL, FALSE},
+        {"-netcore", &bNetCore, COBOOL, FALSE},
+#endif
+        {"-reset", &bReset, COBOOL, FALSE},
+    };
+    if (!GetCMDOption(args, option, _countof(option), NULL, 0, NULL))
+    {
+        return Status;
+    }    
+#ifndef FEATURE_PAL
+    if (bNetCore || bDesktop)
+    {
+        PCSTR name = bDesktop ? "desktop CLR" : ".NET Core";;
+        if (!Runtime::SwitchRuntime(bDesktop))
+        {
+            ExtErr("The %s runtime is not loaded\n", name);
+            return E_FAIL;
+        }
+        ExtOut("Switched to %s runtime successfully\n", name);
+        return S_OK;
+    }
+#endif
+    if (bReset)
+    {
+        Runtime::CleanupRuntimes();
+        CleanupTempDirectory();
+        ExtOut("SOS state reset\n");
+        return S_OK;
+    }
     if (g_targetMachine != nullptr) {
         ExtOut("Target platform: %04x Context size %04x\n", g_targetMachine->GetPlatform(), g_targetMachine->GetContextSize());
     }
+    if (g_pRuntime != nullptr) {
+        g_pRuntime->DisplayStatus();
+    }
     if (g_tmpPath != nullptr) {
         ExtOut("Temp path: %s\n", g_tmpPath);
     }
-    if (g_dacFilePath != nullptr) {
-        ExtOut("DAC file path: %s\n", g_dacFilePath);
-    }
-    if (g_dbiFilePath != nullptr) {
-        ExtOut("DBI file path: %s\n", g_dbiFilePath);
-    }
     if (g_hostRuntimeDirectory != nullptr) {
         ExtOut("Host runtime path: %s\n", g_hostRuntimeDirectory);
     }
-    std::string runtimeDirectory;
-    if (SUCCEEDED(GetRuntimeDirectory(runtimeDirectory))) {
-        ExtOut("Runtime path: %s\n", runtimeDirectory.c_str());
-    }
     DisplaySymbolStore();
 
     return Status;
@@ -11683,10 +11699,8 @@ DECLARE_API(GCHandles)
 #ifndef FEATURE_PAL
 DECLARE_API(TraceToCode)
 {
-    INIT_API_NOEE();
-
-    static ULONG64 g_clrBaseAddr = 0;
-
+    INIT_API_NODAC();
+    _ASSERTE(g_pRuntime != nullptr);
 
     while(true)
     {
@@ -11703,13 +11717,10 @@ DECLARE_API(TraceToCode)
         ULONG64 base = 0;
         CLRDATA_ADDRESS cdaStart = TO_CDADDR(Offset);
         DacpMethodDescData MethodDescData;
-        if(g_ExtSymbols->GetModuleByOffset(Offset, 0, NULL, &base) == S_OK)
+        if (g_ExtSymbols->GetModuleByOffset(Offset, 0, NULL, &base) == S_OK)
         {
-            if(g_clrBaseAddr == 0)
-            {
-                GetRuntimeModuleInfo(NULL, &g_clrBaseAddr);
-            }
-            if(g_clrBaseAddr == base)
+            ULONG64 clrBaseAddr = g_pRuntime->GetModuleAddress();
+            if(clrBaseAddr == base)
             {
                 ExtOut("Compiled code in CLR\n");
                 codeType = 4;
@@ -11774,14 +11785,14 @@ DECLARE_API(TraceToCode)
 
 // This is an experimental and undocumented API that sets a debugger pseudo-register based
 // on the type of code at the given IP. It can be used in scripts to keep stepping until certain
-// kinds of code have been reached. Presumbably its slower than !TraceToCode but at least it
+// kinds of code have been reached. Presumably its slower than !TraceToCode but at least it
 // cancels much better
 #ifndef FEATURE_PAL
 DECLARE_API(GetCodeTypeFlags)
 {
     INIT_API();   
+    _ASSERTE(g_pRuntime != nullptr);
     
-
     char buffer[100+mdNameLen];
     size_t ip;
     StringHolder PReg;
@@ -11822,7 +11833,7 @@ DECLARE_API(GetCodeTypeFlags)
     CLRDATA_ADDRESS cdaStart = TO_CDADDR(ip);
     DWORD codeType = 0;
     CLRDATA_ADDRESS addr;
-    if(g_sos->GetMethodDescPtrFromIP(cdaStart, &addr) == S_OK)
+    if (g_sos->GetMethodDescPtrFromIP(cdaStart, &addr) == S_OK)
     {
         WCHAR wszNameBuffer[1024]; // should be large enough
 
@@ -11841,8 +11852,8 @@ DECLARE_API(GetCodeTypeFlags)
     }
     else if(g_ExtSymbols->GetModuleByOffset (ip, 0, NULL, &base) == S_OK)
     {
-        ULONG64 clrBaseAddr = 0;
-        if(SUCCEEDED(GetRuntimeModuleInfo(NULL, &clrBaseAddr)) && base==clrBaseAddr)
+        ULONG64 clrBaseAddr = g_pRuntime->GetModuleAddress();
+        if (base == clrBaseAddr)
         {
             ExtOut("Compiled code in CLR");
             codeType = 4;
@@ -13175,7 +13186,8 @@ public:
     {
         HRESULT Status;
 
-        IfFailRet(InitCorDebugInterface());
+        ICorDebugProcess* pCorDebugProcess;
+        IfFailRet(g_pRuntime->GetCorDebugInterface(&pCorDebugProcess));
 
         ExtOut("\n\n\nDumping managed stack and managed variables using ICorDebug.\n");
         ExtOut("=============================================================================\n");
@@ -13186,7 +13198,7 @@ public:
         ULONG ulThreadID = 0;
         g_ExtSystem->GetCurrentThreadSystemId(&ulThreadID);
 
-        IfFailRet(g_pCorDebugProcess->GetThread(ulThreadID, &pThread));
+        IfFailRet(pCorDebugProcess->GetThread(ulThreadID, &pThread));
         IfFailRet(pThread->QueryInterface(IID_ICorDebugThread3, (LPVOID *) &pThread3));
         IfFailRet(pThread3->CreateStackWalk(&pStackWalk));
 
@@ -13346,10 +13358,6 @@ public:
         }
         ExtOut("=============================================================================\n");
 
-#ifdef FEATURE_PAL
-        // Temporary until we get a process exit notification plumbed from lldb
-        UninitCorDebugInterface();
-#endif
         return S_OK;
     }
 };
@@ -14265,17 +14273,17 @@ DECLARE_API( VMMap )
 
 #endif // FEATURE_PAL
 
-DECLARE_API( SOSFlush )
+DECLARE_API(SOSFlush)
 {
-    INIT_API();
+    INIT_API_EXT();
 
-    g_clrData->Flush();
+    Runtime::Flush();
 #ifdef FEATURE_PAL
     FlushMetadataRegions();
 #endif
     
     return Status;
-}   // DECLARE_API( SOSFlush )
+}
 
 #ifndef FEATURE_PAL
 
@@ -15465,7 +15473,7 @@ DECLARE_API(VerifyStackTrace)
 // This is an internal-only Apollo extension to de-optimize the code
 DECLARE_API(SuppressJitOptimization)
 {
-    INIT_API_NOEE();    
+    INIT_API_NODAC();    
     MINIDUMP_NOT_SUPPORTED();    
 
     StringHolder onOff;
@@ -15503,12 +15511,12 @@ DECLARE_API(SuppressJitOptimization)
     else if(nArg == 1 && (_stricmp(onOff.data, "Off") == 0))
     {
         // if CLR is already loaded, try to change the flags now
-        if(CheckEEDll() == S_OK)
+        if (CheckEEDll() == S_OK)
         {
             SetNGENCompilerFlags(CORDEBUG_JIT_DEFAULT);
         }
 
-        if(g_fAllowJitOptimization)
+        if (g_fAllowJitOptimization)
             ExtOut("JIT optimization is already permitted\n");
         else
         {
@@ -15531,13 +15539,14 @@ HRESULT SetNGENCompilerFlags(DWORD flags)
     HRESULT hr;
 
     ToRelease<ICorDebugProcess2> proc2;
-    if(FAILED(hr = InitCorDebugInterface()))
+    ICorDebugProcess* pCorDebugProcess;
+    if (FAILED(hr = g_pRuntime->GetCorDebugInterface(&pCorDebugProcess)))
     {
         ExtOut("SOS: warning, prejitted code optimizations could not be changed. Failed to load ICorDebug HR = 0x%x\n", hr);
     }
-    else if(FAILED(g_pCorDebugProcess->QueryInterface(__uuidof(ICorDebugProcess2), (void**) &proc2)))
+    else if (FAILED(pCorDebugProcess->QueryInterface(__uuidof(ICorDebugProcess2), (void**) &proc2)))
     {
-        if(flags != CORDEBUG_JIT_DEFAULT)
+        if (flags != CORDEBUG_JIT_DEFAULT)
         {
             ExtOut("SOS: warning, prejitted code optimizations could not be changed. This CLR version doesn't support the functionality\n");
         }
@@ -15546,7 +15555,7 @@ HRESULT SetNGENCompilerFlags(DWORD flags)
             hr = S_OK;
         }
     }
-    else if(FAILED(hr = proc2->SetDesiredNGENCompilerFlags(flags)))
+    else if (FAILED(hr = proc2->SetDesiredNGENCompilerFlags(flags)))
     {
         // Versions of CLR that don't have SetDesiredNGENCompilerFlags DAC-ized will return E_FAIL.
         // This was first supported in the clr_triton branch around 4/1/12, Apollo release
@@ -15562,9 +15571,9 @@ HRESULT SetNGENCompilerFlags(DWORD flags)
                 hr = S_OK;
             }
         }
-        else if(hr == CORDBG_E_NGEN_NOT_SUPPORTED)
+        else if (hr == CORDBG_E_NGEN_NOT_SUPPORTED)
         {
-            if(flags != CORDEBUG_JIT_DEFAULT)
+            if (flags != CORDEBUG_JIT_DEFAULT)
             {
                 ExtOut("SOS: warning, prejitted code optimizations could not be changed. This CLR version doesn't support NGEN\n");
             }
@@ -15573,14 +15582,14 @@ HRESULT SetNGENCompilerFlags(DWORD flags)
                 hr = S_OK;
             }
         }
-        else if(hr == CORDBG_E_MUST_BE_IN_CREATE_PROCESS)
+        else if (hr == CORDBG_E_MUST_BE_IN_CREATE_PROCESS)
         {
             DWORD currentFlags = 0;
-            if(FAILED(hr = proc2->GetDesiredNGENCompilerFlags(&currentFlags)))
+            if (FAILED(hr = proc2->GetDesiredNGENCompilerFlags(&currentFlags)))
             {
                 ExtOut("SOS: warning, prejitted code optimizations could not be changed. GetDesiredNGENCompilerFlags failed hr=0x%x\n", hr);
             }
-            else if(currentFlags != flags)
+            else if (currentFlags != flags)
             {
                 ExtOut("SOS: warning, prejitted code optimizations could not be changed at this time. This setting is fixed once CLR starts\n");
             }
@@ -15927,8 +15936,8 @@ DECLARE_API(SetSymbolServer)
         {"-timeout", &timeoutInMinutes, COSIZE_T, TRUE},
         {"-ms", &msdl, COBOOL, FALSE},
         {"-log", &logging, COBOOL, FALSE},
-        {"-loadsymbols", &loadNative, COBOOL, FALSE},
 #ifdef FEATURE_PAL
+        {"-loadsymbols", &loadNative, COBOOL, FALSE},
         {"-sympath", &windowsSymbolPath.data, COSTRING, TRUE},
 #else
         {"-mi", &symweb, COBOOL, FALSE},
@@ -15997,10 +16006,12 @@ DECLARE_API(SetSymbolServer)
             ExtOut("Symbol download logging enabled\n");
         }
     }
+#ifdef FEATURE_PAL
     else if (loadNative)
     {
         Status = LoadNativeSymbols();
     }
+#endif
     else
     {
         DisplaySymbolStore();
index 9b9332ab4608cbd67716ec829aa53771cb38db3e..4bde52925deb7ec176c06d1ec087db8247715989 100644 (file)
@@ -26,6 +26,7 @@
 #include <tchar.h>
 #include "debugshim.h"
 #include "datatarget.h"
+#include "runtime.h"
 #include "gcinfo.h"
 
 #ifndef STRESS_LOG
@@ -63,8 +64,6 @@ const char * const CorElementTypeNamespace[ELEMENT_TYPE_MAX]=
 
 IXCLRDataProcess *g_clrData = NULL;
 ISOSDacInterface *g_sos = NULL;
-IXCLRDataProcess *g_clrDataProcess = NULL;
-ICorDebugProcess *g_pCorDebugProcess = NULL;
 
 #ifndef IfFailRet
 #define IfFailRet(EXPR) do { Status = (EXPR); if(FAILED(Status)) { return (Status); } } while (0)
@@ -97,6 +96,7 @@ void __cdecl operator delete[](void* pObj) throw()
 \**********************************************************************/
 DWORD_PTR GetValueFromExpression(___in __in_z const char *const instr)
 {
+    _ASSERTE(g_pRuntime != nullptr);
     std::string symbol;
     symbol.append(GetRuntimeModuleName());
     symbol.append("!");
@@ -156,86 +156,14 @@ DWORD_PTR GetValueFromExpression(___in __in_z const char *const instr)
 
 #endif // FEATURE_PAL
 
-ModuleInfo g_moduleInfo[MSCOREND] = {{0, 0, DEBUG_ANY_ID, FALSE}, {0, 0, DEBUG_ANY_ID, FALSE}, {0, 0, DEBUG_ANY_ID, FALSE}};
-
 void ReportOOM()
 {
     ExtOut("SOS Error: Out of memory\n");
 }
 
-// This is set as a side-effect of CheckEEDll()/GetRuntimeModuleInfo().
-bool g_isDesktopRuntime = false;
-
-HRESULT GetRuntimeModuleInfo(PULONG moduleIndex, PULONG64 moduleBase)
-{
-    g_isDesktopRuntime = false;
-    HRESULT hr = g_ExtSymbols->GetModuleByModuleName(NETCORE_RUNTIME_MODULE_NAME_A, 0, moduleIndex, moduleBase);
-#ifndef FEATURE_PAL
-    if (FAILED(hr)) {
-        hr = g_ExtSymbols->GetModuleByModuleName(DESKTOP_RUNTIME_MODULE_NAME_A, 0, moduleIndex, moduleBase);
-        g_isDesktopRuntime = SUCCEEDED(hr);
-    }
-#endif
-    return hr;
-}
-
 HRESULT CheckEEDll()
 {
-    HRESULT hr = S_OK;
-
-    // Do we have runtime module info?
-    if (g_moduleInfo[MSCORWKS].baseAddr == 0)
-    {
-        hr = GetRuntimeModuleInfo(&g_moduleInfo[MSCORWKS].index, &g_moduleInfo[MSCORWKS].baseAddr);
-#ifdef FEATURE_PAL
-        if (SUCCEEDED(hr))
-        {
-            if (g_ExtServices2 != nullptr)
-            {
-                g_ExtServices2->GetModuleInfo(g_moduleInfo[MSCORWKS].index, nullptr, &g_moduleInfo[MSCORWKS].size);
-            }
-        }
-#else
-        if (g_moduleInfo[MSCORWKS].baseAddr != 0 && g_moduleInfo[MSCORWKS].hasPdb == FALSE)
-        {
-            DEBUG_MODULE_PARAMETERS params;
-            if (SUCCEEDED(g_ExtSymbols->GetModuleParameters(1, &g_moduleInfo[MSCORWKS].baseAddr, 0, &params)))
-            {
-                if (params.SymbolType == SymDeferred)
-                {
-                    std::string reloadCommand;
-                    reloadCommand.append("/f ");
-                    reloadCommand.append(GetRuntimeDllName());
-                    g_ExtSymbols->Reload(reloadCommand.c_str());
-                    g_ExtSymbols->GetModuleParameters(1, &g_moduleInfo[MSCORWKS].baseAddr, 0, &params);
-                }
-                if (params.SymbolType == SymPdb || params.SymbolType == SymDia)
-                {
-                    g_moduleInfo[MSCORWKS].hasPdb = TRUE;
-                }
-                g_moduleInfo[MSCORWKS].size = params.Size;
-            }
-        }
-        if (g_moduleInfo[MSCORWKS].baseAddr != 0 && g_moduleInfo[MSCORWKS].hasPdb == FALSE) 
-        {
-            ExtOut("PDB symbol for %s not loaded\n", GetRuntimeDllName());
-        }
-#endif // FEATURE_PAL
-    }
-    return hr;
-}
-
-EEFLAVOR GetEEFlavor()
-{
-#ifdef FEATURE_PAL
-    return MSCORWKS;
-#else // FEATUER_PAL
-    EEFLAVOR flavor = UNKNOWNEE;    
-    if (SUCCEEDED(GetRuntimeModuleInfo(NULL, NULL))) {
-        flavor = MSCORWKS;
-    }
-    return flavor;
-#endif // FEATURE_PAL else
+    return Runtime::CreateInstance();
 }
 
 BOOL IsDumpFile()
@@ -3280,6 +3208,7 @@ CLRDATA_ADDRESS GetCurrentManagedThread ()
 
 void ReloadSymbolWithLineInfo()
 {
+    _ASSERTE(g_pRuntime != nullptr);
 #ifndef FEATURE_PAL
     static BOOL bLoadSymbol = FALSE;
     if (!bLoadSymbol)
@@ -3293,14 +3222,10 @@ void ReloadSymbolWithLineInfo()
             {
                 g_ExtSymbols->Reload("/f" MSCOREE_SHIM_A);
             }
-            EEFLAVOR flavor = GetEEFlavor();
-            if (flavor == MSCORWKS)
-            {
-                std::string reloadCommand;
-                reloadCommand.append("/f ");
-                reloadCommand.append(GetRuntimeDllName());
-                g_ExtSymbols->Reload(reloadCommand.c_str());
-            }
+            std::string reloadCommand;
+            reloadCommand.append("/f ");
+            reloadCommand.append(GetRuntimeDllName());
+            g_ExtSymbols->Reload(reloadCommand.c_str());
         }
         
         // reload mscoree.pdb and clrjit.pdb to get line info
@@ -3365,9 +3290,7 @@ BOOL GetEEVersion(VS_FIXEDFILEINFO* pFileInfo, char* fileVersionBuffer, int file
 {
     _ASSERTE(pFileInfo);
     _ASSERTE(g_ExtSymbols2 != nullptr);
-
-    ModuleInfo moduleInfo = g_moduleInfo[GetEEFlavor()];
-    _ASSERTE(moduleInfo.index != DEBUG_ANY_ID);
+    _ASSERTE(g_pRuntime != nullptr);
 
 #ifdef FEATURE_PAL
     // Load the symbols for runtime. On Linux we are looking for the "sccsid" 
@@ -3375,7 +3298,7 @@ BOOL GetEEVersion(VS_FIXEDFILEINFO* pFileInfo, char* fileVersionBuffer, int file
     LoadNativeSymbols(true);
 #endif
 
-    HRESULT hr = g_ExtSymbols2->GetModuleVersionInformation(moduleInfo.index, 0, "\\", pFileInfo, sizeof(VS_FIXEDFILEINFO), NULL);
+    HRESULT hr = g_ExtSymbols2->GetModuleVersionInformation(g_pRuntime->GetModuleIndex(), 0, "\\", pFileInfo, sizeof(VS_FIXEDFILEINFO), NULL);
 
     // Attempt to get the the FileVersion string that contains version and the "built by" and commit id info
     if (fileVersionBuffer != nullptr)
@@ -3385,7 +3308,7 @@ BOOL GetEEVersion(VS_FIXEDFILEINFO* pFileInfo, char* fileVersionBuffer, int file
         }
         // We can assume the English/CP_UNICODE lang/code page for the runtime modules
         g_ExtSymbols2->GetModuleVersionInformation(
-            moduleInfo.index, 0, "\\StringFileInfo\\040904B0\\FileVersion", fileVersionBuffer, fileVersionBufferSizeInBytes, NULL);
+            g_pRuntime->GetModuleIndex(), 0, "\\StringFileInfo\\040904B0\\FileVersion", fileVersionBuffer, fileVersionBufferSizeInBytes, NULL);
     }
 
     return SUCCEEDED(hr);
@@ -3959,47 +3882,6 @@ void ResetGlobals(void)
     Output::ResetIndent();
 }
 
-static HRESULT GetClrDataProcess()
-{
-    HRESULT hr = S_OK;
-
-    if (g_clrDataProcess == NULL)
-    {
-        LPCSTR dacFilePath = GetDacFilePath();
-        if (dacFilePath == nullptr)
-        {
-            return E_FAIL;
-        }
-        HMODULE hdac = LoadLibraryA(dacFilePath);
-        if (hdac == NULL)
-        {
-            return CORDBG_E_MISSING_DEBUGGER_EXPORTS;
-        }
-        PFN_CLRDataCreateInstance pfnCLRDataCreateInstance = (PFN_CLRDataCreateInstance)GetProcAddress(hdac, "CLRDataCreateInstance");
-        if (pfnCLRDataCreateInstance == NULL)
-        {
-            FreeLibrary(hdac);
-            return CORDBG_E_MISSING_DEBUGGER_EXPORTS;
-        }
-        ICLRDataTarget *target = new DataTarget();
-        hr = pfnCLRDataCreateInstance(__uuidof(IXCLRDataProcess), target, (void**)&g_clrDataProcess);
-        if (FAILED(hr))
-        {
-            g_clrDataProcess = NULL;
-            return hr;
-        }
-        ULONG32 flags = 0;
-        g_clrDataProcess->GetOtherNotificationFlags(&flags);
-        flags |= (CLRDATA_NOTIFY_ON_MODULE_LOAD | CLRDATA_NOTIFY_ON_MODULE_UNLOAD | CLRDATA_NOTIFY_ON_EXCEPTION);
-        g_clrDataProcess->SetOtherNotificationFlags(flags);
-    }
-    g_clrData = g_clrDataProcess;
-    g_clrData->AddRef();
-    g_clrData->Flush();
-
-    return S_OK;
-}
-
 //---------------------------------------------------------------------------------------
 //
 // Loads private DAC interface, and points g_clrData to it.
@@ -4009,8 +3891,9 @@ static HRESULT GetClrDataProcess()
 //
 HRESULT LoadClrDebugDll(void)
 {
-    HRESULT hr = GetClrDataProcess();
-    if (FAILED(hr)) 
+    _ASSERTE(g_pRuntime != nullptr);
+    HRESULT hr = g_pRuntime->GetClrDataProcess(&g_clrData);
+    if (FAILED(hr))
     {
 #ifdef FEATURE_PAL
         return hr;
@@ -4030,621 +3913,20 @@ HRESULT LoadClrDebugDll(void)
         g_clrData->Flush();
 #endif
     }
-    hr = g_clrData->QueryInterface(__uuidof(ISOSDacInterface), (void**)&g_sos);
-    if (FAILED(hr))
-    {
-        g_sos = NULL;
-        return hr;
-    }
-    return S_OK;
-}
-
-#ifndef FEATURE_PAL
-
-HMODULE
-LoadLibraryAndCheck(
-    PCWSTR filename,
-    DWORD timestamp,
-    DWORD filesize)
-{
-    HMODULE hModule = LoadLibraryExW(
-        filename,
-        NULL,                               //  __reserved
-        LOAD_WITH_ALTERED_SEARCH_PATH);     // Ensure we check the dir in wszFullPath first
-
-    if (hModule == NULL)
-    {
-        ExtOut("Unable to load '%S'. hr = 0x%x.\n", filename, HRESULT_FROM_WIN32(GetLastError()));
-        return NULL;
-    }
-    
-    // Did we load the right one?
-    MODULEINFO modInfo = {0};
-    if (!GetModuleInformation(
-        GetCurrentProcess(),
-        hModule,
-        &modInfo,
-        sizeof(modInfo)))
-    {
-        ExtOut("Failed to read module information for '%S'. hr = 0x%x.\n", filename, HRESULT_FROM_WIN32(GetLastError()));
-        FreeLibrary(hModule);
-        return NULL;
-    }
-
-    IMAGE_DOS_HEADER * pDOSHeader = (IMAGE_DOS_HEADER *) modInfo.lpBaseOfDll;
-    IMAGE_NT_HEADERS * pNTHeaders = (IMAGE_NT_HEADERS *) (((LPBYTE) modInfo.lpBaseOfDll) + pDOSHeader->e_lfanew);
-    DWORD dwSizeActual = pNTHeaders->OptionalHeader.SizeOfImage;
-    DWORD dwTimeStampActual = pNTHeaders->FileHeader.TimeDateStamp;
-    if ((dwSizeActual != filesize) || (dwTimeStampActual != timestamp))
-    {
-        ExtOut("Found '%S', but it does not match the CLR being debugged.\n", filename);
-        ExtOut("Size: Expected '0x%x', Actual '0x%x'\n", filesize, dwSizeActual);
-        ExtOut("Time stamp: Expected '0x%x', Actual '0x%x'\n", timestamp, dwTimeStampActual);
-        FreeLibrary(hModule);
-        return NULL;
-    }
-
-    return hModule;
-}
-
-#endif // FEATURE_PAL
-
-//---------------------------------------------------------------------------------------
-// Provides a way for the public CLR debugging interface to find the appropriate mscordbi.dll, DAC, etc.
-class SOSLibraryProvider : public ICLRDebuggingLibraryProvider, ICLRDebuggingLibraryProvider2
-{
-public:
-    SOSLibraryProvider() : m_ref(0)
-    {
-    }
-
-    virtual ~SOSLibraryProvider() {}
-
-    virtual HRESULT STDMETHODCALLTYPE QueryInterface(
-        REFIID InterfaceId,
-        PVOID* pInterface)
-    {
-        if (InterfaceId == IID_IUnknown)
-        {
-            *pInterface = static_cast<IUnknown *>(static_cast<ICLRDebuggingLibraryProvider*>(this));
-        }
-#ifndef FEATURE_PAL
-        else if (InterfaceId == IID_ICLRDebuggingLibraryProvider)
-        {
-            *pInterface = static_cast<ICLRDebuggingLibraryProvider *>(this);
-        }
-#endif
-        else if (InterfaceId == IID_ICLRDebuggingLibraryProvider2)
-        {
-            *pInterface = static_cast<ICLRDebuggingLibraryProvider2 *>(this);
-        }
-        else
-        {
-            *pInterface = NULL;
-            return E_NOINTERFACE;
-        }
-
-        AddRef();
-        return S_OK;
-    }
-    
-    virtual ULONG STDMETHODCALLTYPE AddRef()
-    {
-        return InterlockedIncrement(&m_ref);    
-    }
-
-    virtual ULONG STDMETHODCALLTYPE Release()
-    {
-        LONG ref = InterlockedDecrement(&m_ref);
-        if (ref == 0)
-        {
-            delete this;
-        }
-        return ref;
-    }
-
-    HRESULT ProvideLibraryInternal(
-        const WCHAR* pwszFileName,
-        DWORD dwTimestamp,
-        DWORD dwSizeOfImage,
-        HMODULE* phModule,
-        LPWSTR* ppResolvedModulePath)
-    {
-        const char* filePath = nullptr;
-
-        if (_wcsncmp(pwszFileName, GetDacDllNameW(), _wcslen(GetDacDllNameW())) == 0)
-        {
-            filePath = GetDacFilePath();
-        }
-        else if (_wcsncmp(pwszFileName, NET_DBI_DLL_NAME_W, _wcslen(NET_DBI_DLL_NAME_W)) == 0)
-        {
-            filePath = GetDbiFilePath();
-        }
-
-        ArrayHolder<WCHAR> modulePath = new WCHAR[MAX_LONGPATH + 1];
-        if (filePath != nullptr)
-        {
-            int length = MultiByteToWideChar(CP_ACP, 0, filePath, -1, modulePath, MAX_LONGPATH);
-            if (0 >= length)
-            {
-                ExtErr("MultiByteToWideChar(filePath) failed. Last error = 0x%x\n", GetLastError());
-                return HRESULT_FROM_WIN32(GetLastError());
-            }
-        }
-        else
-        {
-            HRESULT hr = GetRuntimeDirectory(modulePath, MAX_LONGPATH);
-            if (FAILED(hr))
-            {
-                return hr;
-            }
-            wcscat_s(modulePath, MAX_LONGPATH, pwszFileName);
-        }
-
-        ExtOut("Loaded %S\n", modulePath.GetPtr());
-
-#ifndef FEATURE_PAL
-        if (phModule != NULL)
-        {
-            *phModule = LoadLibraryAndCheck(modulePath.GetPtr(), dwTimestamp, dwSizeOfImage);
-        }
-#endif
-        if (ppResolvedModulePath != NULL)
-        {
-            *ppResolvedModulePath = modulePath.Detach();
-        }
-        return S_OK;
-    }
-
-    // Called by the shim to locate and load dac and dbi
-    // Parameters:
-    //    pwszFileName - the name of the file to load
-    //    dwTimestamp - the expected timestamp of the file
-    //    dwSizeOfImage - the expected SizeOfImage (a PE header data value)
-    //    phModule - a handle to loaded module
-    //
-    // Return Value
-    //    S_OK if the file was loaded, or any error if not
-    virtual HRESULT STDMETHODCALLTYPE ProvideLibrary(
-        const WCHAR * pwszFileName,
-        DWORD dwTimestamp,
-        DWORD dwSizeOfImage,
-        HMODULE* phModule)
-    {
-        if ((phModule == NULL) || (pwszFileName == NULL))
-        {
-            return E_INVALIDARG;
-        }
-        return ProvideLibraryInternal(pwszFileName, dwTimestamp, dwSizeOfImage, phModule, NULL);
-    }
-
-    virtual HRESULT STDMETHODCALLTYPE ProvideLibrary2(
-        const WCHAR* pwszFileName,
-        DWORD dwTimestamp,
-        DWORD dwSizeOfImage,
-        LPWSTR* ppResolvedModulePath)
-    {
-        if ((pwszFileName == NULL) || (ppResolvedModulePath == NULL))
-        {
-            return E_INVALIDARG;
-        }
-        return ProvideLibraryInternal(pwszFileName, dwTimestamp, dwSizeOfImage, NULL, ppResolvedModulePath);
-    }
-
-protected:
-    LONG m_ref;
-};
-
-//---------------------------------------------------------------------------------------
-// Data target for the debugged process.   Provided to OpenVirtualProcess in order to
-// get an ICorDebugProcess back
-// 
-class SOSDataTarget : public ICorDebugMutableDataTarget, public ICorDebugMetaDataLocator, public ICorDebugDataTarget4
-{
-public:
-    SOSDataTarget() : m_ref(0)
-    {
-    }
-
-    virtual ~SOSDataTarget() {}
-
-    virtual HRESULT STDMETHODCALLTYPE QueryInterface(
-        REFIID InterfaceId,
-        PVOID* pInterface)
-    {
-        if (InterfaceId == IID_IUnknown)
-        {
-            *pInterface = static_cast<IUnknown *>(static_cast<ICorDebugDataTarget *>(this));
-        }
-        else if (InterfaceId == IID_ICorDebugDataTarget)
-        {
-            *pInterface = static_cast<ICorDebugDataTarget *>(this);
-        }
-        else if (InterfaceId == IID_ICorDebugMutableDataTarget)
-        {
-            *pInterface = static_cast<ICorDebugMutableDataTarget *>(this);
-        }
-        else if (InterfaceId == IID_ICorDebugMetaDataLocator)
-        {
-            *pInterface = static_cast<ICorDebugMetaDataLocator *>(this);
-        }
-        else if (InterfaceId == IID_ICorDebugDataTarget4)
-        {
-            *pInterface = static_cast<ICorDebugDataTarget4 *>(this);
-        }
-        else
-        {
-            *pInterface = NULL;
-            return E_NOINTERFACE;
-        }
-
-        AddRef();
-        return S_OK;
-    }
-    
-    virtual ULONG STDMETHODCALLTYPE AddRef()
-    {
-        return InterlockedIncrement(&m_ref);    
-    }
-
-    virtual ULONG STDMETHODCALLTYPE Release()
-    {
-        LONG ref = InterlockedDecrement(&m_ref);
-        if (ref == 0)
-        {
-            delete this;
-        }
-        return ref;
-    }
-
-    //
-    // ICorDebugDataTarget.
-    //
-
-    virtual HRESULT STDMETHODCALLTYPE GetPlatform(CorDebugPlatform * pPlatform)
-    {
-        ULONG platformKind = g_targetMachine->GetPlatform();
-#ifdef FEATURE_PAL        
-        if(platformKind == IMAGE_FILE_MACHINE_I386)
-            *pPlatform = CORDB_PLATFORM_POSIX_X86;
-        else if(platformKind == IMAGE_FILE_MACHINE_AMD64)
-            *pPlatform = CORDB_PLATFORM_POSIX_AMD64;
-        else if(platformKind == IMAGE_FILE_MACHINE_ARMNT)
-            *pPlatform = CORDB_PLATFORM_POSIX_ARM;
-        else
-            return E_FAIL;
-#else
-        if(platformKind == IMAGE_FILE_MACHINE_I386)
-            *pPlatform = CORDB_PLATFORM_WINDOWS_X86;
-        else if(platformKind == IMAGE_FILE_MACHINE_AMD64)
-            *pPlatform = CORDB_PLATFORM_WINDOWS_AMD64;
-        else if(platformKind == IMAGE_FILE_MACHINE_ARMNT)
-            *pPlatform = CORDB_PLATFORM_WINDOWS_ARM;
-        else if(platformKind == IMAGE_FILE_MACHINE_ARM64)
-            *pPlatform = CORDB_PLATFORM_WINDOWS_ARM64;
-        else
-            return E_FAIL;        
-#endif        
-    
-        return S_OK;
-    }
-
-    virtual HRESULT STDMETHODCALLTYPE ReadVirtual( 
-        CORDB_ADDRESS address,
-        BYTE * pBuffer,
-        ULONG32 request,
-        ULONG32 * pcbRead)
-    {
-        if (g_ExtData == NULL)
-        {
-            return E_UNEXPECTED;
-        }
-#ifdef FEATURE_PAL
-        if (g_sos != nullptr)
-        {
-            // LLDB synthesizes memory (returns 0's) for missing pages (in this case the missing metadata  pages) 
-            // in core dumps. This functions creates a list of the metadata regions and caches the metadata if 
-            // available from the local or downloaded assembly. If the read would be in the metadata of a loaded 
-            // assembly, the metadata from the this cache will be returned.
-            HRESULT hr = GetMetadataMemory(address, request, pBuffer);
-            if (SUCCEEDED(hr)) {
-                if (pcbRead != nullptr) {
-                    *pcbRead = request;
-                }
-                return hr;
-            }
-        }
-#endif
-        HRESULT hr = g_ExtData->ReadVirtual(address, pBuffer, request, (PULONG) pcbRead);
-        if (FAILED(hr)) 
-        {
-            ExtDbgOut("SOSDataTarget::ReadVirtual FAILED %08x address %p size %08x\n", hr, address, request);
-        }
-        return hr;
-    }
-
-    virtual HRESULT STDMETHODCALLTYPE GetThreadContext(
-        DWORD dwThreadOSID,
-        ULONG32 contextFlags,
-        ULONG32 contextSize,
-        BYTE * context)
-    {
-#ifdef FEATURE_PAL
-        if (g_ExtServices == NULL)
-        {
-            return E_UNEXPECTED;
-        }
-        return g_ExtServices->GetThreadContextById(dwThreadOSID, contextFlags, contextSize, context);
-#else
-        ULONG ulThreadIDOrig;
-        ULONG ulThreadIDRequested;
-        HRESULT hr;
-
-        hr = g_ExtSystem->GetCurrentThreadId(&ulThreadIDOrig);
-        if (FAILED(hr))
-        {
-            return hr;
-        }
-
-        hr = g_ExtSystem->GetThreadIdBySystemId(dwThreadOSID, &ulThreadIDRequested);
-        if (FAILED(hr))
-        {
-            return hr;
-        }
-
-        hr = g_ExtSystem->SetCurrentThreadId(ulThreadIDRequested);
-        if (FAILED(hr))
-        {
-            return hr;
-        }
-
-        // Prepare context structure
-        ZeroMemory(context, contextSize);
-        ((CONTEXT*) context)->ContextFlags = contextFlags;
-
-        // Ok, do it!
-        hr = g_ExtAdvanced->GetThreadContext((LPVOID) context, contextSize);
-
-        // This is cleanup; failure here doesn't mean GetThreadContext should fail
-        // (that's determined by hr).
-        g_ExtSystem->SetCurrentThreadId(ulThreadIDOrig);
-
-        return hr;
-#endif // FEATURE_PAL
-    }
-
-    //
-    // ICorDebugMutableDataTarget.
-    //
-
-    virtual HRESULT STDMETHODCALLTYPE WriteVirtual(CORDB_ADDRESS address,
-                                                   const BYTE * pBuffer,
-                                                   ULONG32 bytesRequested)
-    {
-        if (g_ExtData == NULL)
-        {
-            return E_UNEXPECTED;
-        }
-        return g_ExtData->WriteVirtual(address, (PVOID)pBuffer, bytesRequested, NULL);
-    }
-
-    virtual HRESULT STDMETHODCALLTYPE SetThreadContext(DWORD dwThreadID,
-                                                       ULONG32 contextSize,
-                                                       const BYTE * pContext)
-    {
-        return E_NOTIMPL;
-    }
-
-    virtual HRESULT STDMETHODCALLTYPE ContinueStatusChanged(DWORD dwThreadId,
-                                                            CORDB_CONTINUE_STATUS continueStatus)
-    {
-        return E_NOTIMPL;
-    }
-
-    //
-    // ICorDebugMetaDataLocator.
-    //
-
-    virtual HRESULT STDMETHODCALLTYPE GetMetaData(
-        /* [in] */ LPCWSTR wszImagePath,
-        /* [in] */ DWORD dwImageTimeStamp,
-        /* [in] */ DWORD dwImageSize,
-        /* [in] */ ULONG32 cchPathBuffer,
-        /* [annotation][out] */ 
-        _Out_ ULONG32 *pcchPathBuffer,
-        /* [annotation][length_is][size_is][out] */ 
-        _Out_writes_to_(cchPathBuffer, *pcchPathBuffer) WCHAR wszPathBuffer[])
-    {
-        return E_NOTIMPL;
-    }
-
-    //
-    // ICorDebugDataTarget4
-    //
-    virtual HRESULT STDMETHODCALLTYPE VirtualUnwind(DWORD threadId, ULONG32 contextSize, PBYTE context)
-    {
-#ifdef FEATURE_PAL
-        if (g_ExtServices == NULL)
-        {
-            return E_UNEXPECTED;
-        }
-        return g_ExtServices->VirtualUnwind(threadId, contextSize, context);
-#else 
-        return E_NOTIMPL;
-#endif
-    }
-
-protected:
-    LONG m_ref;
-};
-
-HRESULT InitCorDebugInterfaceFromModule(ULONG64 ulBase, ICLRDebugging * pClrDebugging)
-{
-    HRESULT hr;
-
-    ToRelease<ICorDebugMutableDataTarget> pSOSDataTarget = new SOSDataTarget;
-    pSOSDataTarget->AddRef();
-
-    ToRelease<ICLRDebuggingLibraryProvider> pSOSLibraryProvider = new SOSLibraryProvider;
-    pSOSLibraryProvider->AddRef();
-
-    CLR_DEBUGGING_VERSION clrDebuggingVersionRequested = {0};
-    clrDebuggingVersionRequested.wMajor = 4;
-
-    CLR_DEBUGGING_VERSION clrDebuggingVersionActual = {0};
-
-    CLR_DEBUGGING_PROCESS_FLAGS clrDebuggingFlags = (CLR_DEBUGGING_PROCESS_FLAGS)0;
-
-    ToRelease<IUnknown> pUnkProcess;
-
-    hr = pClrDebugging->OpenVirtualProcess(
-        ulBase,
-        pSOSDataTarget,
-        pSOSLibraryProvider,
-        &clrDebuggingVersionRequested,
-        IID_ICorDebugProcess,
-        &pUnkProcess,
-        &clrDebuggingVersionActual,
-        &clrDebuggingFlags);
-    if (FAILED(hr))
+    else
     {
-        return hr;
+        g_clrData->AddRef();
+        g_clrData->Flush();
     }
-
-    ICorDebugProcess * pCorDebugProcess = NULL;
-    hr = pUnkProcess->QueryInterface(IID_ICorDebugProcess, (PVOID*) &pCorDebugProcess);
+    hr = g_clrData->QueryInterface(__uuidof(ISOSDacInterface), (void**)&g_sos);
     if (FAILED(hr))
     {
+        g_sos = NULL;
         return hr;
     }
-
-    // Transfer memory ownership of refcount to global
-    g_pCorDebugProcess = pCorDebugProcess;
     return S_OK;
 }
 
-//---------------------------------------------------------------------------------------
-//
-// Unloads public ICorDebug interfaces, and clears g_pCorDebugProcess
-// This is only needed once after CLR unloads, not after every InitCorDebugInterface call
-//
-VOID UninitCorDebugInterface()
-{
-    if(g_pCorDebugProcess != NULL)
-    {
-        g_pCorDebugProcess->Detach();
-        g_pCorDebugProcess->Release();
-        g_pCorDebugProcess = NULL;
-    }
-}
-
-//---------------------------------------------------------------------------------------
-//
-// Loads public ICorDebug interfaces, and points g_pCorDebugProcess to them
-// This should be called at least once per windbg stop state to ensure that
-// the interface is available and that it doesn't hold stale data. Calling it
-// more than once isn't an error, but does have perf overhead from needlessly
-// flushing memory caches.
-//
-// Return Value:
-//      HRESULT indicating success or failure
-//
-
-HRESULT InitCorDebugInterface()
-{
-    HMODULE hModule = NULL;
-    HRESULT hr;
-    ToRelease<ICLRDebugging> pClrDebugging;
-
-    // we may already have an ICorDebug instance we can use
-    if(g_pCorDebugProcess != NULL)
-    {
-        // ICorDebugProcess4 is currently considered a private experimental interface on ICorDebug, it might go away so
-        // we need to be sure to handle its absence gracefully
-        ToRelease<ICorDebugProcess4> pProcess4 = NULL;
-        if(SUCCEEDED(g_pCorDebugProcess->QueryInterface(__uuidof(ICorDebugProcess4), (void**)&pProcess4)))
-        {
-            // FLUSH_ALL is more expensive than PROCESS_RUNNING, but this allows us to be safe even if things
-            // like IDNA are in use where we might be looking at non-sequential snapshots of process state
-            if(SUCCEEDED(pProcess4->ProcessStateChanged(FLUSH_ALL)))
-            {
-                // we already have an ICorDebug instance loaded and flushed, nothing more to do
-                return S_OK;
-            }
-        }
-
-        // this is a very heavy handed way of reseting
-        UninitCorDebugInterface();
-    }
-
-    // SOS now has a statically linked version of the loader code that is normally found in mscoree/mscoreei.dll
-    // Its not much code and takes a big step towards 0 install dependencies
-    // Need to pick the appropriate SKU of CLR to detect
-#if defined(FEATURE_CORESYSTEM)
-    GUID skuId = CLR_ID_ONECORE_CLR;
-#else
-    GUID skuId = CLR_ID_CORECLR;
-#endif
-#ifndef FEATURE_PAL
-    if (g_isDesktopRuntime)
-    {
-        skuId = CLR_ID_V4_DESKTOP;
-    }
-#endif
-    CLRDebuggingImpl* pDebuggingImpl = new CLRDebuggingImpl(skuId);
-    hr = pDebuggingImpl->QueryInterface(IID_ICLRDebugging, (LPVOID *)&pClrDebugging);
-    if (FAILED(hr))
-    {
-        delete pDebuggingImpl;
-        return hr;
-    }
-
-#ifndef FEATURE_PAL
-    ULONG cLoadedModules;
-    ULONG cUnloadedModules;
-    hr = g_ExtSymbols->GetNumberModules(&cLoadedModules, &cUnloadedModules);
-    if (FAILED(hr))
-    {
-        return hr;
-    }
-
-    ULONG64 ulBase;
-    for (ULONG i = 0; i < cLoadedModules; i++)
-    {
-        hr = g_ExtSymbols->GetModuleByIndex(i, &ulBase);
-        if (FAILED(hr))
-        {
-            return hr;
-        }
-
-        // Dunno if this is a CLR module or not (or even if it's the particular one the
-        // user cares about during inproc SxS scenarios).  For now, just try to use it
-        // to grab an ICorDebugProcess.  If it works, great.  Else, continue the loop
-        // until we find the first one that works.
-        hr = InitCorDebugInterfaceFromModule(ulBase, pClrDebugging);
-        if (SUCCEEDED(hr))
-        {
-            return hr;
-        }
-
-        // On failure, just iterate to the next module and try again...
-    }
-
-    // Still here?  Didn't find the right module.
-    // TODO: Anything useful to return or log here?
-    return E_FAIL;
-#else
-    ULONG64 ulBase;
-    hr = GetRuntimeModuleInfo(NULL, &ulBase);
-    if (SUCCEEDED(hr))
-    {
-        hr = InitCorDebugInterfaceFromModule(ulBase, pClrDebugging);
-    }
-    return hr;
-#endif // FEATURE_PAL
-}
-
-
 typedef enum
 {
     GC_HEAP_INVALID = 0,
index febfdda0899d1753b382e4f0e7bcd67eba52b92a..92666b8a154e6f45329a432486a9ea29983a12a4 100644 (file)
@@ -202,9 +202,6 @@ extern ISOSDacInterface *g_sos;
 
 #include "dacprivate.h"
 
-interface ICorDebugProcess;
-extern ICorDebugProcess * g_pCorDebugProcess;
-
 // This class is templated for easy modification.  We may need to update the CachedString
 // or related classes to use WCHAR instead of char in the future.
 template <class T, int count, int size>
@@ -1539,99 +1536,6 @@ private:
     T* m_ptr;    
 };
 
-// SOS's runtime, dac and dbi module name defines. *MODULE* is just the 
-// module name on Windows, *DLL* has the .dll extension. On Linux/MacOS, 
-// *MODULE* and *DLL* are the same.
-
-#ifdef FEATURE_PAL
-
-#define NETCORE_RUNTIME_MODULE_NAME_W   MAKEDLLNAME_W(W("coreclr"))
-#define NETCORE_RUNTIME_MODULE_NAME_A   MAKEDLLNAME_A("coreclr")
-#define NETCORE_RUNTIME_DLL_NAME_W      NETCORE_RUNTIME_MODULE_NAME_W
-#define NETCORE_RUNTIME_DLL_NAME_A      NETCORE_RUNTIME_MODULE_NAME_A
-
-#define NETCORE_DAC_MODULE_NAME_W       MAKEDLLNAME_W(W("mscordaccore"))
-#define NETCORE_DAC_MODULE_NAME_A       MAKEDLLNAME_A("mscordaccore")
-#define NETCORE_DAC_DLL_NAME_W          NETCORE_DAC_MODULE_NAME_W
-#define NETCORE_DAC_DLL_NAME_A          NETCORE_DAC_MODULE_NAME_A
-
-#define NET_DBI_MODULE_NAME_W           MAKEDLLNAME_W(W("mscordbi"))
-#define NET_DBI_MODULE_NAME_A           MAKEDLLNAME_A("mscordbi")
-#define NET_DBI_DLL_NAME_W              NET_DBI_MODULE_NAME_W       
-#define NET_DBI_DLL_NAME_A              NET_DBI_MODULE_NAME_A       
-
-#else
-
-#define NETCORE_RUNTIME_MODULE_NAME_W   W("coreclr")
-#define NETCORE_RUNTIME_MODULE_NAME_A   "coreclr"
-#define NETCORE_RUNTIME_DLL_NAME_W      MAKEDLLNAME_W(NETCORE_RUNTIME_MODULE_NAME_W)
-#define NETCORE_RUNTIME_DLL_NAME_A      MAKEDLLNAME_A(NETCORE_RUNTIME_MODULE_NAME_A)
-
-#define NETCORE_DAC_MODULE_NAME_W       W("mscordaccore")
-#define NETCORE_DAC_MODULE_NAME_A       "mscordaccore"
-#define NETCORE_DAC_DLL_NAME_W          MAKEDLLNAME_W(NETCORE_DAC_MODULE_NAME_W)
-#define NETCORE_DAC_DLL_NAME_A          MAKEDLLNAME_A(NETCORE_DAC_MODULE_NAME_A)
-
-#define NET_DBI_MODULE_NAME_W           W("mscordbi")
-#define NET_DBI_MODULE_NAME_A           "mscordbi"
-#define NET_DBI_DLL_NAME_W              MAKEDLLNAME_W(W("mscordbi"))
-#define NET_DBI_DLL_NAME_A              MAKEDLLNAME_A("mscordbi")
-
-#endif // FEATURE_PAL
-
-#define DESKTOP_RUNTIME_MODULE_NAME_W   W("clr")
-#define DESKTOP_RUNTIME_MODULE_NAME_A   "clr"
-#define DESKTOP_RUNTIME_DLL_NAME_W      MAKEDLLNAME_W(DESKTOP_RUNTIME_MODULE_NAME_W)
-#define DESKTOP_RUNTIME_DLL_NAME_A      MAKEDLLNAME_A(DESKTOP_RUNTIME_MODULE_NAME_A)
-
-#define DESKTOP_DAC_MODULE_NAME_W       W("mscordacwks")
-#define DESKTOP_DAC_MODULE_NAME_A       "mscordacwks"
-#define DESKTOP_DAC_DLL_NAME_W          MAKEDLLNAME_W(W("mscordacwks"))
-#define DESKTOP_DAC_DLL_NAME_A          MAKEDLLNAME_A("mscordacwks")
-
-// This is set as a side-effect of CheckEEDll()/GetRuntimeModuleInfo().
-extern bool g_isDesktopRuntime;
-
-inline const char* GetRuntimeModuleName()
-{
-    return g_isDesktopRuntime ? DESKTOP_RUNTIME_MODULE_NAME_A : NETCORE_RUNTIME_MODULE_NAME_A;
-}
-
-inline const char* GetRuntimeDllName()
-{
-    return g_isDesktopRuntime ? DESKTOP_RUNTIME_DLL_NAME_A : NETCORE_RUNTIME_DLL_NAME_A;
-}
-
-inline const char* GetDacModuleName()
-{
-    return g_isDesktopRuntime ? DESKTOP_DAC_MODULE_NAME_A : NETCORE_DAC_MODULE_NAME_A;
-}
-
-inline const char* GetDacDllName()
-{
-    return g_isDesktopRuntime ? DESKTOP_DAC_DLL_NAME_A : NETCORE_DAC_DLL_NAME_A;
-}
-
-inline const WCHAR* GetDacModuleNameW()
-{
-    return g_isDesktopRuntime ? DESKTOP_DAC_MODULE_NAME_W : NETCORE_DAC_MODULE_NAME_W;
-}
-
-inline const WCHAR* GetDacDllNameW()
-{
-    return g_isDesktopRuntime ? DESKTOP_DAC_DLL_NAME_W : NETCORE_DAC_DLL_NAME_W;
-}
-
-struct ModuleInfo
-{
-    ULONG64 baseAddr;
-    ULONG64 size;
-    ULONG index;
-    BOOL hasPdb;
-};
-
-extern ModuleInfo g_moduleInfo[];
-
 BOOL InitializeHeapData();
 BOOL IsServerBuild ();
 UINT GetMaxGeneration();
@@ -1645,10 +1549,6 @@ void DecodeIL(IMetaDataImport *pImport, BYTE *buffer, ULONG bufSize);
 void DecodeDynamicIL(BYTE *data, ULONG Size, DacpObjectData& tokenArray);
 ULONG DisplayILOperation(const UINT indentCount, BYTE* pBuffer, ULONG position, std::function<void(DWORD)>& func);
 
-HRESULT GetRuntimeModuleInfo(PULONG moduleIndex, PULONG64 moduleBase);
-EEFLAVOR GetEEFlavor ();
-HRESULT InitCorDebugInterface();
-VOID UninitCorDebugInterface();
 BOOL GetEEVersion(VS_FIXEDFILEINFO* pFileInfo, char* fileVersionBuffer, int fileVersionBufferSizeInBytes);
 bool IsRuntimeVersion(DWORD major);
 bool IsRuntimeVersion(VS_FIXEDFILEINFO& fileInfo, DWORD major);
index 77c33c341411f0e10abb764a0a410f9722f6e489..b48a75810256efc89dd8c8de7ec903703484f95e 100644 (file)
@@ -26,6 +26,7 @@ namespace Microsoft.Diagnostics.Tools.Dump
         private readonly ServiceProvider _serviceProvider;
         private readonly ConsoleProvider _consoleProvider;
         private readonly CommandProcessor _commandProcessor;
+        private bool _isDesktop;
         private string _dacFilePath;
 
         /// <summary>
@@ -142,7 +143,7 @@ namespace Microsoft.Diagnostics.Tools.Dump
 
             _serviceProvider.AddServiceFactory(typeof(SOSHost), () => {
                 var sosHost = new SOSHost(_serviceProvider);
-                sosHost.InitializeSOSHost(SymbolReader.TempDirectory, _dacFilePath, dbiFilePath: null);
+                sosHost.InitializeSOSHost(SymbolReader.TempDirectory, _isDesktop, _dacFilePath, dbiFilePath: null);
                 return sosHost;
             });
         }
@@ -152,11 +153,33 @@ namespace Microsoft.Diagnostics.Tools.Dump
         /// </summary>
         private ClrRuntime CreateRuntime(DataTarget target)
         {
-            ClrRuntime runtime;
-            if (target.ClrVersions.Count != 1) {
-                throw new InvalidOperationException("More or less than 1 CLR version is present");
+            ClrInfo clrInfo = null;
+
+            // First check if there is a .NET Core runtime loaded
+            foreach (ClrInfo clr in target.ClrVersions)
+            {
+                if (clr.Flavor == ClrFlavor.Core)
+                {
+                    clrInfo = clr;
+                    break;
+                }
             }
-            ClrInfo clrInfo = target.ClrVersions[0];
+            // If no .NET Core runtime, then check for desktop runtime
+            if (clrInfo == null)
+            {
+                foreach (ClrInfo clr in target.ClrVersions)
+                {
+                    if (clr.Flavor == ClrFlavor.Desktop)
+                    {
+                        clrInfo = clr;
+                        break;
+                    }
+                }
+            }
+            if (clrInfo == null) {
+                throw new InvalidOperationException("No CLR runtime is present");
+            }
+            ClrRuntime runtime;
             string dacFilePath = GetDacFile(clrInfo);
             try
             {
@@ -219,6 +242,7 @@ namespace Microsoft.Diagnostics.Tools.Dump
                 {
                     throw new FileNotFoundException("Could not find matching DAC for this runtime: {0}", clrInfo.ModuleInfo.FileName);
                 }
+                _isDesktop = clrInfo.Flavor == ClrFlavor.Desktop;
             }
             return _dacFilePath;
         }