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
[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);
/// 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)
{
ref s_callbacks,
Marshal.SizeOf<SOSNetCoreCallbacks>(),
tempDirectory,
+ isDesktop,
dacFilePath,
dbiFilePath,
SymbolReader.IsSymbolStoreEnabled());
gcroot.cpp
hostcoreclr.cpp
metadata.cpp
+ runtime.cpp
sigparser.cpp
sildasm.cpp
sos.cpp
gcroot.cpp
hostcoreclr.cpp
metadata.cpp
+ runtime.cpp
sigparser.cpp
sildasm.cpp
stressLogDump.cpp
HRESULT __stdcall EventCallbacks::ExitProcess(ULONG ExitCode)
{
- UninitCorDebugInterface();
+ Runtime::CleanupRuntimes();
+ CleanupTempDirectory();
return DEBUG_STATUS_NO_CHANGE;
}
#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.
// 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,
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));
{
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++)
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
<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" />
<ClCompile Include="disasmX86.cpp" />
<ClCompile Include="disasmARM64.cpp" />
<ClCompile Include="hostcoreclr.cpp" />
+ <ClCompile Include="runtime.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="data.h" />
<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" />
INIT_API_EE();
INIT_API_DAC();
EnableDMLHolder dmlHolder(TRUE);
- IfFailRet(InitCorDebugInterface());
PersistList* pFilterList = NULL;
if(pFilterName != NULL)
HRESULT Status = S_OK;
INIT_API_EE();
INIT_API_DAC();
- IfFailRet(InitCorDebugInterface());
RemoveList(pSaveName);
PersistList* pList = new PersistList();
--- /dev/null
+// 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__
--- /dev/null
+// 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__
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);
} TADDR_SEGINFO;
#include "util.h"
+#include "runtime.h"
#ifdef __cplusplus
extern "C" {
ExtOut("Command canceled at the user's request.\n");
ControlC = TRUE;
}
-
return ControlC;
}
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");
}
{
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");
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; \
// 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"); \
// ==--==
#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
#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
//
// 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;
}
}
}
}
}
-/**********************************************************************\
- * 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)
{
{
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.
// 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))
}
#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);
}
//
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.
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();
extern void InitializeSymbolStoreFromSymPath();
#endif
-extern HRESULT LoadNativeSymbols(bool runtimeOnly = false);
extern void DisplaySymbolStore();
extern void DisableSymbolStore();
--- /dev/null
+// 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, ¶ms);
+ 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, ¶ms);
+
+ 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
--- /dev/null
+// 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__
HistRoot SetSymbolServer (setsymbolserver)
HistObj FAQ
HistObjFind SOSFlush
-HistClear Help (soshelp)
+HistClear SOSStatus (sosstatus)
+ Help (soshelp)
\\
COMMAND: faq.
\\
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.
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
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.
(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.
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";
}
}
return m_count;
}
-
/*
* New code was generated or discarded for a method.:
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;
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;
INIT_API_NODAC();
MINIDUMP_NOT_SUPPORTED();
- if (GetEEFlavor() == UNKNOWNEE)
- {
- ExtOut("CLR not loaded\n");
- return Status;
- }
-
const char* fileName = "GCLog.txt";
while (isspace (*args))
#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))
{
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;
}
else
{
- BOOL fRet = IsRetailBuild((size_t)g_moduleInfo[eef].baseAddr);
+ BOOL fRet = IsRetailBuild((size_t)g_pRuntime->GetModuleAddress());
if (fRet)
ExtOut(" retail");
else
\**********************************************************************/
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;
#ifndef FEATURE_PAL
DECLARE_API(TraceToCode)
{
- INIT_API_NOEE();
-
- static ULONG64 g_clrBaseAddr = 0;
-
+ INIT_API_NODAC();
+ _ASSERTE(g_pRuntime != nullptr);
while(true)
{
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;
// 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;
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
}
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;
{
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");
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));
}
ExtOut("=============================================================================\n");
-#ifdef FEATURE_PAL
- // Temporary until we get a process exit notification plumbed from lldb
- UninitCorDebugInterface();
-#endif
return S_OK;
}
};
#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
// 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;
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
{
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");
}
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
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");
}
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(¤tFlags)))
+ if (FAILED(hr = proc2->GetDesiredNGENCompilerFlags(¤tFlags)))
{
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");
}
{"-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},
ExtOut("Symbol download logging enabled\n");
}
}
+#ifdef FEATURE_PAL
else if (loadNative)
{
Status = LoadNativeSymbols();
}
+#endif
else
{
DisplaySymbolStore();
#include <tchar.h>
#include "debugshim.h"
#include "datatarget.h"
+#include "runtime.h"
#include "gcinfo.h"
#ifndef STRESS_LOG
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)
\**********************************************************************/
DWORD_PTR GetValueFromExpression(___in __in_z const char *const instr)
{
+ _ASSERTE(g_pRuntime != nullptr);
std::string symbol;
symbol.append(GetRuntimeModuleName());
symbol.append("!");
#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, ¶ms)))
- {
- 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, ¶ms);
- }
- 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()
void ReloadSymbolWithLineInfo()
{
+ _ASSERTE(g_pRuntime != nullptr);
#ifndef FEATURE_PAL
static BOOL bLoadSymbol = FALSE;
if (!bLoadSymbol)
{
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
{
_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"
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)
}
// 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);
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.
//
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;
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,
#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>
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();
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);
private readonly ServiceProvider _serviceProvider;
private readonly ConsoleProvider _consoleProvider;
private readonly CommandProcessor _commandProcessor;
+ private bool _isDesktop;
private string _dacFilePath;
/// <summary>
_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;
});
}
/// </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
{
{
throw new FileNotFoundException("Could not find matching DAC for this runtime: {0}", clrInfo.ModuleInfo.FileName);
}
+ _isDesktop = clrInfo.Flavor == ClrFlavor.Desktop;
}
return _dacFilePath;
}