Skip to content

[cDAC] Add switch to load cDAC directly #5373

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,40 @@ public Version RuntimeVersion

public string GetDacFilePath()
{
_dacFilePath ??= GetLibraryPath(DebugLibraryKind.Dac);
if (_dacFilePath is not null)
{
return _dacFilePath;
}

// Optionally load the DAC through the cDAC
string str = Environment.GetEnvironmentVariable("DOTNET_SOS_LOAD_CDAC");
int.TryParse(str ?? string.Empty, out int val);

if (val == 0)
{
_dacFilePath ??= GetLibraryPath(DebugLibraryKind.Dac);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably will just add another value to DebugLibraryKind for the CDAC in CLRMD. CLRMD needs some of these changes and more to find a CDAC compatible runtime, load it and create the instance.

}
else
{
OSPlatform platform = Target.OperatingSystem;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FYI, this should use the RuntimeInformation.IsOSPlatform() because we need the OS we are loading the module on not the target OS. We can load Linux dumps on Windows with windbg or dotnet-dump.

if (platform == OSPlatform.Windows)
{
_dacFilePath ??= GetLocalPath("cdacreader.dll");
}
else if (platform == OSPlatform.Linux)
{
_dacFilePath ??= GetLocalPath("libcdacreader.so");
}
else if (platform == OSPlatform.OSX)
{
_dacFilePath ??= GetLocalPath("libcdacreader.dylib");
}
else
{
Trace.TraceError($"GetCdacFilePath: platform not supported - {platform}");
}
}

return _dacFilePath;
}

Expand Down
38 changes: 37 additions & 1 deletion src/SOS/SOS.Hosting/DataTargetWrapper.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Licensed to the .NET Foundation under one or more agreements.
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;
Expand All @@ -17,10 +17,14 @@ internal sealed unsafe class DataTargetWrapper : COMCallableIUnknown
private static readonly Guid IID_ICLRDataTarget4 = new("E799DC06-E099-4713-BDD9-906D3CC02CF2");
private static readonly Guid IID_ICLRMetadataLocator = new("aa8fa804-bc05-4642-b2c5-c353ed22fc63");
private static readonly Guid IID_ICLRRuntimeLocator = new("b760bf44-9377-4597-8be7-58083bdc5146");
private static readonly Guid IID_ICLRContractLocator = new("17d5b8c6-34a9-407f-af4f-a930201d4e02");

// For ClrMD's magic hand shake
private const ulong MagicCallbackConstant = 0x43;

// cDAC Contract Descriptor export symbol name
private const string ContractDescriptorExport = "DotNetRuntimeContractDescriptor";

private readonly IRuntime _runtime;
private readonly IContextService _contextService;
private readonly ISymbolService _symbolService;
Expand Down Expand Up @@ -67,6 +71,10 @@ public DataTargetWrapper(IServiceProvider services, IRuntime runtime)
builder.AddMethod(new GetRuntimeBaseDelegate(GetRuntimeBase));
builder.Complete();

builder = AddInterface(IID_ICLRContractLocator, false);
builder.AddMethod(new GetContractDescriptorDelegate(GetContractDescriptor));
builder.Complete();

AddRef();
}

Expand Down Expand Up @@ -350,6 +358,26 @@ private int GetRuntimeBase(

#endregion

#region ICLRContractLocator

private int GetContractDescriptor(
IntPtr self,
out ulong address)
{
address = 0;
IExportSymbols exportSymbols = _runtime.RuntimeModule.Services.GetService<IExportSymbols>();
if (exportSymbols is not null)
{
if (exportSymbols.TryGetSymbolAddress(ContractDescriptorExport, out address))
{
return HResult.S_OK;
}
}
return HResult.E_FAIL;
}

#endregion

#region ICLRDataTarget delegates

[UnmanagedFunctionPointer(CallingConvention.Winapi)]
Expand Down Expand Up @@ -485,5 +513,13 @@ private delegate int GetRuntimeBaseDelegate(
[Out] out ulong address);

#endregion

#region ICLRContractLocator delegate

[UnmanagedFunctionPointer(CallingConvention.Winapi)]
private delegate int GetContractDescriptorDelegate(
[In] IntPtr self,
[Out] out ulong address);
#endregion
}
}
16 changes: 16 additions & 0 deletions src/SOS/Strike/platform/datatarget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,12 @@ DataTarget::QueryInterface(
AddRef();
return S_OK;
}
else if (InterfaceId == IID_ICLRContractLocator)
{
*Interface = (ICLRContractLocator*)this;
AddRef();
return S_OK;
}
else
{
*Interface = NULL;
Expand Down Expand Up @@ -385,3 +391,13 @@ DataTarget::GetRuntimeBase(
*baseAddress = m_baseAddress;
return S_OK;
}

// ICLRContractLocator

HRESULT STDMETHODCALLTYPE
DataTarget::GetContractDescriptor(
/* out */ CLRDATA_ADDRESS* contractAddress)
{
// TODO: IMPLEMENT
return E_FAIL;
}
7 changes: 6 additions & 1 deletion src/SOS/Strike/platform/datatarget.h
Original file line number Diff line number Diff line change
Expand Up @@ -120,4 +120,9 @@ class DataTarget : public ICLRDataTarget2, ICorDebugDataTarget4, ICLRMetadataLoc

virtual HRESULT STDMETHODCALLTYPE GetRuntimeBase(
/* [out] */ CLRDATA_ADDRESS* baseAddress);
};

// ICLRContractLocator

virtual HRESULT STDMETHODCALLTYPE GetContractDescriptor(
/* [out] */ CLRDATA_ADDRESS* contractAddress);
};
47 changes: 46 additions & 1 deletion src/SOS/Strike/platform/runtimeimpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include <psapi.h>
#include <clrinternal.h>
#include <metahost.h>
#include <clrconfignocache.h>
#include "runtimeimpl.h"
#include "datatarget.h"
#include "cordebugdatatarget.h"
Expand Down Expand Up @@ -299,6 +300,43 @@ LPCSTR Runtime::GetDacFilePath()
return m_dacFilePath;
}

/**********************************************************************\
* Returns the cDAC module path to the rest of SOS.
\**********************************************************************/
LPCSTR Runtime::GetCdacFilePath()
{
if (m_cdacFilePath == nullptr)
{
// No debugger service instance means that SOS is hosted by dotnet-dump,
// which does runtime enumeration in CLRMD. We should never get here.
IDebuggerServices* debuggerServices = GetDebuggerServices();
if (debuggerServices == nullptr)
{
ExtDbgOut("GetCdacFilePath: GetDebuggerServices returned nullptr\n");
return nullptr;
}

// TODO: Signature verification

LPCSTR directory = GetRuntimeDirectory();
if (directory != nullptr)
{
std::string dacModulePath(directory);
dacModulePath.append(DIRECTORY_SEPARATOR_STR_A);
dacModulePath.append(GetCdacDllName());
#ifdef FEATURE_PAL
// If DAC file exists in the runtime directory
if (access(dacModulePath.c_str(), F_OK) == 0)
#endif
{
m_cdacFilePath = _strdup(dacModulePath.c_str());
}
}
}
return m_cdacFilePath;
}


/**********************************************************************\
* Returns the DBI module path to the rest of SOS
\**********************************************************************/
Expand Down Expand Up @@ -427,7 +465,14 @@ HRESULT Runtime::GetClrDataProcess(IXCLRDataProcess** ppClrDataProcess)
{
*ppClrDataProcess = nullptr;

LPCSTR dacFilePath = GetDacFilePath();
CLRConfigNoCache enable = CLRConfigNoCache::Get("SOS_LOAD_CDAC");
DWORD val = 0;
if (enable.IsSet())
{
enable.TryAsInteger(10, val);
}

LPCSTR dacFilePath = val != 0 ? GetCdacFilePath() : GetDacFilePath();
if (dacFilePath == nullptr)
{
return CORDBG_E_NO_IMAGE_AVAILABLE;
Expand Down
9 changes: 9 additions & 0 deletions src/SOS/Strike/platform/runtimeimpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,12 @@ inline const char* GetDacDllName()
return (g_pRuntime->GetRuntimeConfiguration() == IRuntime::WindowsDesktop) ? DESKTOP_DAC_DLL_NAME_A : NETCORE_DAC_DLL_NAME_A;
}

// Returns the cDAC module name
inline const char* GetCdacDllName()
{
return MAKEDLLNAME_A("cdacreader");
}

/**********************************************************************\
* Local Runtime interface implementation
\**********************************************************************/
Expand All @@ -121,6 +127,7 @@ class Runtime : public IRuntime
RuntimeInfo* m_runtimeInfo;
LPCSTR m_runtimeDirectory;
LPCSTR m_dacFilePath;
LPCSTR m_cdacFilePath;
LPCSTR m_dbiFilePath;
IXCLRDataProcess* m_clrDataProcess;
ICorDebugProcess* m_pCorDebugProcess;
Expand Down Expand Up @@ -150,6 +157,8 @@ class Runtime : public IRuntime

LPCSTR GetDacFilePath();

LPCSTR GetCdacFilePath();

LPCSTR GetDbiFilePath();

void DisplayStatus();
Expand Down
14 changes: 14 additions & 0 deletions src/shared/inc/clrdata.idl
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,20 @@ interface ICLRRuntimeLocator : IUnknown
HRESULT GetRuntimeBase([out] CLRDATA_ADDRESS* baseAddress);
};

[
object,
local,
uuid(17d5b8c6-34a9-407f-af4f-a930201d4e02),
pointer_default(unique)
]
interface ICLRContractLocator : IUnknown
{
/*
Returns the address of the runtime's contract descriptor.
*/
HRESULT GetContractDescriptor([out] CLRDATA_ADDRESS* contractAddress);
}

/*
* Interface used by the data access services layer to locate metadata
* of assemblies in a target.
Expand Down
11 changes: 7 additions & 4 deletions src/shared/pal/prebuilt/idl/clrdata_i.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@

/* File created by MIDL compiler version 8.01.0626 */
/* Compiler settings for clrdata.idl:
Oicf, W1, Zp8, env=Win64 (32b run), target_arch=AMD64 8.01.0626
Oicf, W1, Zp8, env=Win64 (32b run), target_arch=AMD64 8.01.0626
protocol : dce , ms_ext, c_ext, robust
error checks: allocation ref bounds_check enum stub_data
VC __declspec() decoration level:
error checks: allocation ref bounds_check enum stub_data
VC __declspec() decoration level:
__declspec(uuid()), __declspec(selectany), __declspec(novtable)
DECLSPEC_UUID(), MIDL_INTERFACE()
*/
Expand All @@ -22,7 +22,7 @@

#ifdef __cplusplus
extern "C"{
#endif
#endif


#include <rpc.h>
Expand Down Expand Up @@ -78,6 +78,9 @@ MIDL_DEFINE_GUID(IID, IID_ICLRDataTarget3,0xa5664f95,0x0af4,0x4a1b,0x96,0x0e,0x2
MIDL_DEFINE_GUID(IID, IID_ICLRRuntimeLocator,0xb760bf44,0x9377,0x4597,0x8b,0xe7,0x58,0x08,0x3b,0xdc,0x51,0x46);


MIDL_DEFINE_GUID(IID, IID_ICLRContractLocator,0x17d5b8c6,0x34a9,0x407f,0xaf,0x4f,0xa9,0x30,0x20,0x1d,0x4e,0x02);


MIDL_DEFINE_GUID(IID, IID_ICLRMetadataLocator,0xaa8fa804,0xbc05,0x4642,0xb2,0xc5,0xc3,0x53,0xed,0x22,0xfc,0x63);


Expand Down
Loading
Loading