1
0
Fork 0
mirror of https://github.com/VSadov/Satori.git synced 2025-06-09 17:44:48 +09:00

[cdac] Make DAC load and use cDAC when available (#100946)

- If `DOTNET_ENABLE_CDAC` environment variable is `1`, Look for `cdacreader` next to DAC and load it if found
- Implement `ISOSDacInterface` in cDAC - currently returns `E_NOTIMPL` for everything
- Make DAC delegate to cDAC (if available) for GetThreadStoreData and GetBreakingChangeVersion
- Initialize cDAC with function for reading from the target
This commit is contained in:
Elinor Fung 2024-04-16 21:37:28 -07:00 committed by GitHub
parent e6f1fd8297
commit e126f8ff2e
Signed by: github
GPG key ID: B5690EEEBB952194
15 changed files with 755 additions and 72 deletions

View file

@ -1,5 +1,7 @@
add_definitions(-DFEATURE_NO_HOST)
add_subdirectory(${CLR_SRC_NATIVE_DIR}/managed/cdacreader/cmake ${CLR_ARTIFACTS_OBJ_DIR}/cdacreader)
include_directories(BEFORE ${VM_DIR})
include_directories(BEFORE ${VM_DIR}/${ARCH_SOURCES_DIR})
include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR})
@ -12,6 +14,7 @@ if(CLR_CMAKE_HOST_UNIX)
endif(CLR_CMAKE_HOST_UNIX)
set(DACCESS_SOURCES
cdac.cpp
dacdbiimpl.cpp
dacdbiimpllocks.cpp
dacdbiimplstackwalk.cpp
@ -40,6 +43,7 @@ convert_to_absolute_path(DACCESS_SOURCES ${DACCESS_SOURCES})
add_library_clr(daccess ${DACCESS_SOURCES})
set_target_properties(daccess PROPERTIES DAC_COMPONENT TRUE)
target_precompile_headers(daccess PRIVATE [["stdafx.h"]])
target_link_libraries(daccess PRIVATE cdacreader_api)
add_dependencies(daccess eventing_headers)

View file

@ -0,0 +1,88 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
#include "cdac.h"
#include <sospriv.h>
#include <sstring.h>
#include "dbgutil.h"
#include <cdac_reader.h>
#define CDAC_LIB_NAME MAKEDLLNAME_W(W("cdacreader"))
namespace
{
bool TryLoadCDACLibrary(HMODULE *phCDAC)
{
// Load cdacreader from next to DAC binary
PathString path;
if (FAILED(GetClrModuleDirectory(path)))
return false;
path.Append(CDAC_LIB_NAME);
*phCDAC = CLRLoadLibrary(path.GetUnicode());
if (*phCDAC == NULL)
return false;
return true;
}
int ReadFromTargetCallback(uint64_t addr, uint8_t* dest, uint32_t count, void* context)
{
CDAC* cdac = reinterpret_cast<CDAC*>(context);
return cdac->ReadFromTarget(addr, dest, count);
}
}
CDAC CDAC::Create(uint64_t descriptorAddr, ICorDebugDataTarget* target)
{
HMODULE cdacLib;
if (!TryLoadCDACLibrary(&cdacLib))
return CDAC::Invalid();
return CDAC{cdacLib, descriptorAddr, target};
}
CDAC::CDAC(HMODULE module, uint64_t descriptorAddr, ICorDebugDataTarget* target)
: m_module(module)
, m_target{target}
{
if (m_module == NULL)
{
m_cdac_handle = NULL;
return;
}
decltype(&cdac_reader_init) init = reinterpret_cast<decltype(&cdac_reader_init)>(::GetProcAddress(m_module, "cdac_reader_init"));
decltype(&cdac_reader_get_sos_interface) getSosInterface = reinterpret_cast<decltype(&cdac_reader_get_sos_interface)>(::GetProcAddress(m_module, "cdac_reader_get_sos_interface"));
_ASSERTE(init != nullptr && getSosInterface != nullptr);
init(descriptorAddr, &ReadFromTargetCallback, this, &m_cdac_handle);
getSosInterface(m_cdac_handle, &m_sos);
}
CDAC::~CDAC()
{
if (m_cdac_handle != NULL)
{
decltype(&cdac_reader_free) free = reinterpret_cast<decltype(&cdac_reader_free)>(::GetProcAddress(m_module, "cdac_reader_free"));
_ASSERTE(free != nullptr);
free(m_cdac_handle);
}
if (m_module != NULL)
::FreeLibrary(m_module);
}
IUnknown* CDAC::SosInterface()
{
return m_sos;
}
int CDAC::ReadFromTarget(uint64_t addr, uint8_t* dest, uint32_t count)
{
HRESULT hr = ReadFromDataTarget(m_target, addr, dest, count);
if (FAILED(hr))
return hr;
return S_OK;
}

View file

@ -0,0 +1,69 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
#ifndef CDAC_H
#define CDAC_H
class CDAC final
{
public: // static
static CDAC Create(uint64_t descriptorAddr, ICorDebugDataTarget *pDataTarget);
static CDAC Invalid()
{
return CDAC{nullptr, 0, nullptr};
}
public:
CDAC(const CDAC&) = delete;
CDAC& operator=(const CDAC&) = delete;
CDAC(CDAC&& other)
: m_module{ other.m_module }
, m_cdac_handle{ other.m_cdac_handle }
, m_target{ other.m_target }
, m_sos{ other.m_sos.Extract() }
{
other.m_module = NULL;
other.m_cdac_handle = 0;
other.m_target = NULL;
other.m_sos = NULL;
}
CDAC& operator=(CDAC&& other)
{
m_module = other.m_module;
m_cdac_handle = other.m_cdac_handle;
m_target = other.m_target;
m_sos = other.m_sos.Extract();
other.m_module = NULL;
other.m_cdac_handle = 0;
other.m_target = NULL;
other.m_sos = NULL;
return *this;
}
~CDAC();
bool IsValid() const
{
return m_module != NULL && m_cdac_handle != 0;
}
// This does not AddRef the returned interface
IUnknown* SosInterface();
int ReadFromTarget(uint64_t addr, uint8_t* dest, uint32_t count);
private:
CDAC(HMODULE module, uint64_t descriptorAddr, ICorDebugDataTarget* target);
private:
HMODULE m_module;
intptr_t m_cdac_handle;
ICorDebugDataTarget* m_target;
NonVMComHolder<IUnknown> m_sos;
};
#endif // CDAC_H

View file

@ -23,6 +23,8 @@
#include "dwreport.h"
#include "primitives.h"
#include "dbgutil.h"
#include "cdac.h"
#include <clrconfignocache.h>
#ifdef USE_DAC_TABLE_RVA
#include <dactablerva.h>
@ -3034,6 +3036,7 @@ private:
//----------------------------------------------------------------------------
ClrDataAccess::ClrDataAccess(ICorDebugDataTarget * pTarget, ICLRDataTarget * pLegacyTarget/*=0*/)
: m_cdac{CDAC::Invalid()}
{
SUPPORTS_DAC_HOST_ONLY; // ctor does no marshalling - don't check with DacCop
@ -3123,7 +3126,6 @@ ClrDataAccess::ClrDataAccess(ICorDebugDataTarget * pTarget, ICLRDataTarget * pLe
// see ClrDataAccess::VerifyDlls for details.
m_fEnableDllVerificationAsserts = false;
#endif
}
ClrDataAccess::~ClrDataAccess(void)
@ -5491,6 +5493,28 @@ ClrDataAccess::Initialize(void)
IfFailRet(GetDacGlobalValues());
IfFailRet(DacGetHostVtPtrs());
CLRConfigNoCache enable = CLRConfigNoCache::Get("ENABLE_CDAC");
if (enable.IsSet())
{
DWORD val;
if (enable.TryAsInteger(10, val) && val == 1)
{
// TODO: [cdac] Get contract descriptor from exported symbol
uint64_t contractDescriptorAddr = 0;
//if (TryGetSymbol(m_pTarget, m_globalBase, "DotNetRuntimeContractDescriptor", &contractDescriptorAddr))
{
m_cdac = CDAC::Create(contractDescriptorAddr, m_pTarget);
if (m_cdac.IsValid())
{
// Get SOS interfaces from the cDAC if available.
IUnknown* unk = m_cdac.SosInterface();
(void)unk->QueryInterface(__uuidof(ISOSDacInterface), (void**)&m_cdacSos);
(void)unk->QueryInterface(__uuidof(ISOSDacInterface9), (void**)&m_cdacSos9);
}
}
}
}
//
// DAC is now setup and ready to use
//

View file

@ -794,6 +794,7 @@ class DacStreamManager;
#endif // FEATURE_MINIMETADATA_IN_TRIAGEDUMPS
#include "cdac.h"
//----------------------------------------------------------------------------
//
@ -1208,7 +1209,7 @@ public:
CLRDATA_ADDRESS *allocLimit);
// ISOSDacInterface13
virtual HRESULT STDMETHODCALLTYPE TraverseLoaderHeap(CLRDATA_ADDRESS loaderHeapAddr, LoaderHeapKind kind, VISITHEAP pCallback);
virtual HRESULT STDMETHODCALLTYPE TraverseLoaderHeap(CLRDATA_ADDRESS loaderHeapAddr, LoaderHeapKind kind, VISITHEAP pCallback);
virtual HRESULT STDMETHODCALLTYPE GetDomainLoaderAllocator(CLRDATA_ADDRESS domainAddress, CLRDATA_ADDRESS *pLoaderAllocator);
virtual HRESULT STDMETHODCALLTYPE GetLoaderAllocatorHeapNames(int count, const char **ppNames, int *pNeeded);
virtual HRESULT STDMETHODCALLTYPE GetLoaderAllocatorHeaps(CLRDATA_ADDRESS loaderAllocator, int count, CLRDATA_ADDRESS *pLoaderHeaps, LoaderHeapKind *pKinds, int *pNeeded);
@ -1221,13 +1222,15 @@ public:
virtual HRESULT STDMETHODCALLTYPE GetStaticBaseAddress(CLRDATA_ADDRESS methodTable, CLRDATA_ADDRESS *nonGCStaticsAddress, CLRDATA_ADDRESS *GCStaticsAddress);
virtual HRESULT STDMETHODCALLTYPE GetThreadStaticBaseAddress(CLRDATA_ADDRESS methodTable, CLRDATA_ADDRESS thread, CLRDATA_ADDRESS *nonGCStaticsAddress, CLRDATA_ADDRESS *GCStaticsAddress);
virtual HRESULT STDMETHODCALLTYPE GetMethodTableInitializationFlags(CLRDATA_ADDRESS methodTable, MethodTableInitializationFlags *initializationStatus);
//
// ClrDataAccess.
//
HRESULT Initialize(void);
HRESULT GetThreadStoreDataImpl(struct DacpThreadStoreData *data);
BOOL IsExceptionFromManagedCode(EXCEPTION_RECORD * pExceptionRecord);
#ifndef TARGET_UNIX
HRESULT GetWatsonBuckets(DWORD dwThreadId, GenericModeBlock * pGM);
@ -1414,6 +1417,10 @@ public:
ULONG32 m_instanceAge;
bool m_debugMode;
CDAC m_cdac;
NonVMComHolder<ISOSDacInterface> m_cdacSos;
NonVMComHolder<ISOSDacInterface9> m_cdacSos9;
#ifdef FEATURE_MINIMETADATA_IN_TRIAGEDUMPS
protected:
@ -1964,7 +1971,7 @@ public:
virtual ~DacMemoryEnumerator() {}
virtual HRESULT Init() = 0;
HRESULT STDMETHODCALLTYPE Skip(unsigned int count);
HRESULT STDMETHODCALLTYPE Reset();
HRESULT STDMETHODCALLTYPE GetCount(unsigned int *pCount);

View file

@ -38,6 +38,8 @@ typedef DPTR(InteropLib::ABI::ManagedObjectWrapperLayout) PTR_ManagedObjectWrapp
#include "rejit.h"
#include "request_common.h"
#include "cdac.h"
// GC headers define these to EE-specific stuff that we don't want.
#undef EnterCriticalSection
#undef LeaveCriticalSection
@ -299,31 +301,64 @@ HRESULT ClrDataAccess::GetThreadStoreData(struct DacpThreadStoreData *threadStor
{
SOSDacEnter();
ThreadStore* threadStore = ThreadStore::s_pThreadStore;
if (!threadStore)
if (m_cdacSos != NULL)
{
hr = E_UNEXPECTED;
// Try the cDAC first - it will return E_NOTIMPL if it doesn't support this method yet. Fall back to the DAC.
hr = m_cdacSos->GetThreadStoreData(threadStoreData);
if (FAILED(hr))
{
hr = GetThreadStoreDataImpl(threadStoreData);
}
#ifdef _DEBUG
else
{
// Assert that the data is the same as what we get from the DAC.
DacpThreadStoreData threadStoreDataLocal;
HRESULT hrLocal = GetThreadStoreDataImpl(&threadStoreDataLocal);
_ASSERTE(hr == hrLocal);
_ASSERTE(threadStoreData->threadCount == threadStoreDataLocal.threadCount);
_ASSERTE(threadStoreData->unstartedThreadCount == threadStoreDataLocal.unstartedThreadCount);
_ASSERTE(threadStoreData->backgroundThreadCount == threadStoreDataLocal.backgroundThreadCount);
_ASSERTE(threadStoreData->pendingThreadCount == threadStoreDataLocal.pendingThreadCount);
_ASSERTE(threadStoreData->deadThreadCount == threadStoreDataLocal.deadThreadCount);
_ASSERTE(threadStoreData->fHostConfig == threadStoreDataLocal.fHostConfig);
_ASSERTE(threadStoreData->firstThread == threadStoreDataLocal.firstThread);
_ASSERTE(threadStoreData->finalizerThread == threadStoreDataLocal.finalizerThread);
_ASSERTE(threadStoreData->gcThread == threadStoreDataLocal.gcThread);
}
#endif
}
else
{
// initialize the fields of our local structure
threadStoreData->threadCount = threadStore->m_ThreadCount;
threadStoreData->unstartedThreadCount = threadStore->m_UnstartedThreadCount;
threadStoreData->backgroundThreadCount = threadStore->m_BackgroundThreadCount;
threadStoreData->pendingThreadCount = threadStore->m_PendingThreadCount;
threadStoreData->deadThreadCount = threadStore->m_DeadThreadCount;
threadStoreData->fHostConfig = FALSE;
// identify the "important" threads
threadStoreData->firstThread = HOST_CDADDR(threadStore->m_ThreadList.GetHead());
threadStoreData->finalizerThread = HOST_CDADDR(g_pFinalizerThread);
threadStoreData->gcThread = HOST_CDADDR(g_pSuspensionThread);
hr = GetThreadStoreDataImpl(threadStoreData);
}
SOSDacLeave();
return hr;
}
HRESULT ClrDataAccess::GetThreadStoreDataImpl(struct DacpThreadStoreData *threadStoreData)
{
ThreadStore* threadStore = ThreadStore::s_pThreadStore;
if (!threadStore)
return E_UNEXPECTED;
// initialize the fields of our local structure
threadStoreData->threadCount = threadStore->m_ThreadCount;
threadStoreData->unstartedThreadCount = threadStore->m_UnstartedThreadCount;
threadStoreData->backgroundThreadCount = threadStore->m_BackgroundThreadCount;
threadStoreData->pendingThreadCount = threadStore->m_PendingThreadCount;
threadStoreData->deadThreadCount = threadStore->m_DeadThreadCount;
threadStoreData->fHostConfig = FALSE;
// identify the "important" threads
threadStoreData->firstThread = HOST_CDADDR(threadStore->m_ThreadList.GetHead());
threadStoreData->finalizerThread = HOST_CDADDR(g_pFinalizerThread);
threadStoreData->gcThread = HOST_CDADDR(g_pSuspensionThread);
return S_OK;
}
HRESULT
ClrDataAccess::GetStressLogAddress(CLRDATA_ADDRESS *stressLog)
{
@ -4951,7 +4986,15 @@ HRESULT ClrDataAccess::GetBreakingChangeVersion(int* pVersion)
if (pVersion == nullptr)
return E_INVALIDARG;
*pVersion = SOS_BREAKING_CHANGE_VERSION;
if (m_cdacSos9 != nullptr && SUCCEEDED(m_cdacSos9->GetBreakingChangeVersion(pVersion)))
{
_ASSERTE(*pVersion == SOS_BREAKING_CHANGE_VERSION);
}
else
{
*pVersion = SOS_BREAKING_CHANGE_VERSION;
}
return S_OK;
}
@ -5406,10 +5449,10 @@ HRESULT STDMETHODCALLTYPE ClrDataAccess::GetStaticBaseAddress(CLRDATA_ADDRESS me
{
if (!nonGCStaticsAddress && !GCStaticsAddress)
return E_POINTER;
if (!methodTable)
return E_INVALIDARG;
SOSDacEnter();
PTR_MethodTable mTable = PTR_MethodTable(TO_TADDR(methodTable));
@ -5440,13 +5483,13 @@ HRESULT STDMETHODCALLTYPE ClrDataAccess::GetThreadStaticBaseAddress(CLRDATA_ADDR
{
if (!nonGCStaticsAddress && !GCStaticsAddress)
return E_POINTER;
if (!methodTable)
return E_INVALIDARG;
if (!threadPtr)
return E_INVALIDARG;
SOSDacEnter();
PTR_MethodTable mTable = PTR_MethodTable(TO_TADDR(methodTable));

View file

@ -85,6 +85,10 @@
<!-- CoreRun is not used for testing anymore, but we still use it for benchmarking and profiling -->
<RuntimeFiles Include="$(CoreCLRArtifactsPath)\corerun*" />
<RuntimeFiles Include="$(CoreCLRArtifactsPath)\PDB\corerun*" />
<!-- Include cDAC reader library
TODO: [cdac] Remove once cdacreader is added to shipping shared framework -->
<RuntimeFiles Include="$(CoreCLRArtifactsPath)\*cdacreader*" />
<RuntimeFiles Include="$(CoreCLRArtifactsPath)\PDB\*cdacreader*" />
</ItemGroup>
<!-- If the build has native sanitizers, copy over the non-sanitized diagnostic binaries so they can be loaded by a debugger -->
<ItemGroup Condition="'$(EnableNativeSanitizers)' != ''">

View file

@ -9,8 +9,20 @@ extern "C"
{
#endif
int cdac_reader_init(intptr_t descriptor, intptr_t* handle);
// Initialize the cDAC reader
// descriptor: the address of the descriptor in the target process
// read_from_target: a callback that reads memory from the target process
// read_context: a context pointer that will be passed to read_from_target
// handle: returned opaque the handle to the reader. This should be passed to other functions in this API.
int cdac_reader_init(uint64_t descriptor, int(*read_from_target)(uint64_t, uint8_t*, uint32_t, void*), void* read_context, /*out*/ intptr_t* handle);
// Free the cDAC reader
// handle: handle to the reader
int cdac_reader_free(intptr_t handle);
// Get the SOS interface from the cDAC reader
// handle: handle to the reader
// obj: returned SOS interface that can be QI'd to ISOSDacInterface*
int cdac_reader_get_sos_interface(intptr_t handle, IUnknown** obj);
#ifdef __cplusplus

View file

@ -12,9 +12,9 @@ internal static class Entrypoints
private const string CDAC = "cdac_reader_";
[UnmanagedCallersOnly(EntryPoint = $"{CDAC}init")]
private static unsafe int Init(nint descriptor, IntPtr* handle)
private static unsafe int Init(ulong descriptor, delegate* unmanaged<ulong, byte*, uint, void*, int> readFromTarget, void* readContext, IntPtr* handle)
{
Target target = new(descriptor);
Target target = new(descriptor, readFromTarget, readContext);
GCHandle gcHandle = GCHandle.Alloc(target);
*handle = GCHandle.ToIntPtr(gcHandle);
return 0;
@ -42,7 +42,7 @@ internal static class Entrypoints
if (target == null)
return -1;
SOSDacImpl impl = new(target);
Legacy.SOSDacImpl impl = new(target);
nint ptr = cw.GetOrCreateComInterfaceForObject(impl, CreateComInterfaceFlags.None);
*obj = ptr;
return 0;

View file

@ -0,0 +1,293 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.Marshalling;
namespace Microsoft.Diagnostics.DataContractReader.Legacy;
// This file contains managed declarations for the SOS-DAC interfaces.
// See src/coreclr/inc/sospriv.idl
#pragma warning disable CS0649 // Field is never assigned to, and will always have its default value
internal struct DacpThreadStoreData
{
public int threadCount;
public int unstartedThreadCount;
public int backgroundThreadCount;
public int pendingThreadCount;
public int deadThreadCount;
public ulong firstThread;
public ulong finalizerThread;
public ulong gcThread;
public int fHostConfig; // Uses hosting flags defined above
};
internal struct DacpThreadData
{
public int corThreadId;
public int osThreadId;
public int state;
public uint preemptiveGCDisabled;
public ulong allocContextPtr;
public ulong allocContextLimit;
public ulong context;
public ulong domain;
public ulong pFrame;
public int lockCount;
public ulong firstNestedException; // Pass this pointer to DacpNestedExceptionInfo
public ulong teb;
public ulong fiberData;
public ulong lastThrownObjectHandle;
public ulong nextThread;
}
#pragma warning restore CS0649 // Field is never assigned to, and will always have its default value
[GeneratedComInterface]
[Guid("436f00f2-b42a-4b9f-870c-e73db66ae930")]
internal unsafe partial interface ISOSDacInterface
{
// All functions are explicitly PreserveSig so that we can just return E_NOTIMPL instead of throwing
// as the cDAC slowly replaces parts of the DAC.
// ThreadStore
[PreserveSig]
int GetThreadStoreData(DacpThreadStoreData* data);
// AppDomains
[PreserveSig]
int GetAppDomainStoreData(/*struct DacpAppDomainStoreData*/ void* data);
[PreserveSig]
int GetAppDomainList(uint count, [In, Out, MarshalUsing(CountElementName = nameof(count))] ulong[] values, uint* pNeeded);
[PreserveSig]
int GetAppDomainData(ulong addr, /*struct DacpAppDomainData*/ void* data);
[PreserveSig]
int GetAppDomainName(ulong addr, uint count, char* name, uint* pNeeded);
[PreserveSig]
int GetDomainFromContext(ulong context, ulong* domain);
// Assemblies
[PreserveSig]
int GetAssemblyList(ulong appDomain, int count, [In, Out, MarshalUsing(CountElementName = nameof(count))] ulong[] values, int* pNeeded);
[PreserveSig]
int GetAssemblyData(ulong baseDomainPtr, ulong assembly, /*struct DacpAssemblyData*/ void* data);
[PreserveSig]
int GetAssemblyName(ulong assembly, uint count, char* name, uint* pNeeded);
// Modules
[PreserveSig]
int GetModule(ulong addr, /*IXCLRDataModule*/ void** mod);
[PreserveSig]
int GetModuleData(ulong moduleAddr, /*struct DacpModuleData*/ void* data);
[PreserveSig]
int TraverseModuleMap(/*ModuleMapType*/ int mmt, ulong moduleAddr, /*MODULEMAPTRAVERSE*/ void* pCallback, void* token);
[PreserveSig]
int GetAssemblyModuleList(ulong assembly, uint count, [In, Out, MarshalUsing(CountElementName = nameof(count))] ulong[] modules, uint* pNeeded);
[PreserveSig]
int GetILForModule(ulong moduleAddr, int rva, ulong* il);
// Threads
[PreserveSig]
int GetThreadData(ulong thread, DacpThreadData *data);
[PreserveSig]
int GetThreadFromThinlockID(uint thinLockId, ulong* pThread);
[PreserveSig]
int GetStackLimits(ulong threadPtr, ulong* lower, ulong* upper, ulong* fp);
// MethodDescs
[PreserveSig]
int GetMethodDescData(ulong methodDesc, ulong ip, /*struct DacpMethodDescData*/ void* data, uint cRevertedRejitVersions, /*struct DacpReJitData*/ void* rgRevertedRejitData, uint* pcNeededRevertedRejitData);
[PreserveSig]
int GetMethodDescPtrFromIP(ulong ip, ulong* ppMD);
[PreserveSig]
int GetMethodDescName(ulong methodDesc, uint count, char* name, uint* pNeeded);
[PreserveSig]
int GetMethodDescPtrFromFrame(ulong frameAddr, ulong* ppMD);
[PreserveSig]
int GetMethodDescFromToken(ulong moduleAddr, /*mdToken*/ uint token, ulong* methodDesc);
[PreserveSig]
int GetMethodDescTransparencyData(ulong methodDesc, /*struct DacpMethodDescTransparencyData*/ void* data);
// JIT Data
[PreserveSig]
int GetCodeHeaderData(ulong ip, /*struct DacpCodeHeaderData*/ void* data);
[PreserveSig]
int GetJitManagerList(uint count, /*struct DacpJitManagerInfo*/ void* managers, uint* pNeeded);
[PreserveSig]
int GetJitHelperFunctionName(ulong ip, uint count, byte* name, uint* pNeeded);
[PreserveSig]
int GetJumpThunkTarget(/*T_CONTEXT*/void* ctx, ulong* targetIP, ulong* targetMD);
// ThreadPool
[PreserveSig]
int GetThreadpoolData(/*struct DacpThreadpoolData*/ void* data);
[PreserveSig]
int GetWorkRequestData(ulong addrWorkRequest, /*struct DacpWorkRequestData*/ void* data);
[PreserveSig]
int GetHillClimbingLogEntry(ulong addr, /*struct DacpHillClimbingLogEntry*/ void* data);
// Objects
[PreserveSig]
int GetObjectData(ulong objAddr, /*struct DacpObjectData*/ void* data);
[PreserveSig]
int GetObjectStringData(ulong obj, uint count, char* stringData, uint* pNeeded);
[PreserveSig]
int GetObjectClassName(ulong obj, uint count, char* className, uint* pNeeded);
// MethodTable
[PreserveSig]
int GetMethodTableName(ulong mt, uint count, char* mtName, uint* pNeeded);
[PreserveSig]
int GetMethodTableData(ulong mt, /*struct DacpMethodTableData*/ void* data);
[PreserveSig]
int GetMethodTableSlot(ulong mt, uint slot, ulong* value);
[PreserveSig]
int GetMethodTableFieldData(ulong mt, /*struct DacpMethodTableFieldData*/ void* data);
[PreserveSig]
int GetMethodTableTransparencyData(ulong mt, /*struct DacpMethodTableTransparencyData*/ void* data);
// EEClass
[PreserveSig]
int GetMethodTableForEEClass(ulong eeClass, ulong* value);
// FieldDesc
[PreserveSig]
int GetFieldDescData(ulong fieldDesc, /*struct DacpFieldDescData*/ void* data);
// Frames
[PreserveSig]
int GetFrameName(ulong vtable, uint count, char* frameName, uint* pNeeded);
// PEFiles
[PreserveSig]
int GetPEFileBase(ulong addr, ulong* peBase);
[PreserveSig]
int GetPEFileName(ulong addr, uint count, char* fileName, uint* pNeeded);
// GC
[PreserveSig]
int GetGCHeapData(/*struct DacpGcHeapData*/ void* data);
[PreserveSig]
int GetGCHeapList(uint count, [In, Out, MarshalUsing(CountElementName = nameof(count))] ulong[] heaps, uint* pNeeded); // svr only
[PreserveSig]
int GetGCHeapDetails(ulong heap, /*struct DacpGcHeapDetails */ void* details); // wks only
[PreserveSig]
int GetGCHeapStaticData(/*struct DacpGcHeapDetails */ void* data);
[PreserveSig]
int GetHeapSegmentData(ulong seg, /*struct DacpHeapSegmentData */ void* data);
[PreserveSig]
int GetOOMData(ulong oomAddr, /*struct DacpOomData */ void* data);
[PreserveSig]
int GetOOMStaticData(/*struct DacpOomData */ void* data);
[PreserveSig]
int GetHeapAnalyzeData(ulong addr, /*struct DacpGcHeapAnalyzeData */ void* data);
[PreserveSig]
int GetHeapAnalyzeStaticData(/*struct DacpGcHeapAnalyzeData */ void* data);
// DomainLocal
[PreserveSig]
int GetDomainLocalModuleData(ulong addr, /*struct DacpDomainLocalModuleData */ void* data);
[PreserveSig]
int GetDomainLocalModuleDataFromAppDomain(ulong appDomainAddr, int moduleID, /*struct DacpDomainLocalModuleData */ void* data);
[PreserveSig]
int GetDomainLocalModuleDataFromModule(ulong moduleAddr, /*struct DacpDomainLocalModuleData */ void* data);
// ThreadLocal
[PreserveSig]
int GetThreadLocalModuleData(ulong thread, uint index, /*struct DacpThreadLocalModuleData */ void* data);
// SyncBlock
[PreserveSig]
int GetSyncBlockData(uint number, /*struct DacpSyncBlockData */ void* data);
[PreserveSig]
int GetSyncBlockCleanupData(ulong addr, /*struct DacpSyncBlockCleanupData */ void* data);
// Handles
[PreserveSig]
int GetHandleEnum(/*ISOSHandleEnum*/ void** ppHandleEnum);
[PreserveSig]
int GetHandleEnumForTypes([In, MarshalUsing(CountElementName = nameof(count))] uint[] types, uint count, /*ISOSHandleEnum*/ void** ppHandleEnum);
[PreserveSig]
int GetHandleEnumForGC(uint gen, /*ISOSHandleEnum*/ void** ppHandleEnum);
// EH
[PreserveSig]
int TraverseEHInfo(ulong ip, /*DUMPEHINFO*/ void* pCallback, void* token);
[PreserveSig]
int GetNestedExceptionData(ulong exception, ulong* exceptionObject, ulong* nextNestedException);
// StressLog
[PreserveSig]
int GetStressLogAddress(ulong* stressLog);
// Heaps
[PreserveSig]
int TraverseLoaderHeap(ulong loaderHeapAddr, /*VISITHEAP*/ void* pCallback);
[PreserveSig]
int GetCodeHeapList(ulong jitManager, uint count, /*struct DacpJitCodeHeapInfo*/ void* codeHeaps, uint* pNeeded);
[PreserveSig]
int TraverseVirtCallStubHeap(ulong pAppDomain, /*VCSHeapType*/ int heaptype, /*VISITHEAP*/ void* pCallback);
// Other
[PreserveSig]
int GetUsefulGlobals(/*struct DacpUsefulGlobalsData */ void* data);
[PreserveSig]
int GetClrWatsonBuckets(ulong thread, void* pGenericModeBlock);
[PreserveSig]
int GetTLSIndex(uint* pIndex);
[PreserveSig]
int GetDacModuleHandle(/*HMODULE*/ void* phModule);
// COM
[PreserveSig]
int GetRCWData(ulong addr, /*struct DacpRCWData */ void* data);
[PreserveSig]
int GetRCWInterfaces(ulong rcw, uint count, /*struct DacpCOMInterfacePointerData*/ void* interfaces, uint* pNeeded);
[PreserveSig]
int GetCCWData(ulong ccw, /*struct DacpCCWData */ void* data);
[PreserveSig]
int GetCCWInterfaces(ulong ccw, uint count, /*struct DacpCOMInterfacePointerData*/ void* interfaces, uint* pNeeded);
[PreserveSig]
int TraverseRCWCleanupList(ulong cleanupListPtr, /*VISITRCWFORCLEANUP*/ void* pCallback, void* token);
// GC Reference Functions
/* GetStackReferences
* Enumerates all references on a given callstack.
*/
[PreserveSig]
int GetStackReferences(int osThreadID, /*ISOSStackRefEnum*/ void** ppEnum);
[PreserveSig]
int GetRegisterName(int regName, uint count, char* buffer, uint* pNeeded);
[PreserveSig]
int GetThreadAllocData(ulong thread, /*struct DacpAllocData */ void* data);
[PreserveSig]
int GetHeapAllocData(uint count, /*struct DacpGenerationAllocData */ void* data, uint* pNeeded);
// For BindingDisplay plugin
[PreserveSig]
int GetFailedAssemblyList(ulong appDomain, int count, [In, Out, MarshalUsing(CountElementName = nameof(count))] ulong[] values, uint* pNeeded);
[PreserveSig]
int GetPrivateBinPaths(ulong appDomain, int count, char* paths, uint* pNeeded);
[PreserveSig]
int GetAssemblyLocation(ulong assembly, int count, char* location, uint* pNeeded);
[PreserveSig]
int GetAppDomainConfigFile(ulong appDomain, int count, char* configFile, uint* pNeeded);
[PreserveSig]
int GetApplicationBase(ulong appDomain, int count, char* appBase, uint* pNeeded);
[PreserveSig]
int GetFailedAssemblyData(ulong assembly, uint* pContext, int* pResult);
[PreserveSig]
int GetFailedAssemblyLocation(ulong assesmbly, uint count, char* location, uint* pNeeded);
[PreserveSig]
int GetFailedAssemblyDisplayName(ulong assembly, uint count, char* name, uint* pNeeded);
};
[GeneratedComInterface]
[Guid("4eca42d8-7e7b-4c8a-a116-7bfbf6929267")]
internal partial interface ISOSDacInterface9
{
int GetBreakingChangeVersion();
}

View file

@ -0,0 +1,119 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.Marshalling;
namespace Microsoft.Diagnostics.DataContractReader.Legacy;
/// <summary>
/// Implementation of ISOSDacInterface* interfaces intended to be passed out to consumers
/// interacting with the DAC via those COM interfaces.
/// </summary>
[GeneratedComClass]
internal sealed partial class SOSDacImpl : ISOSDacInterface, ISOSDacInterface9
{
private readonly Target _target;
public SOSDacImpl(Target target)
{
_target = target;
}
public unsafe int GetAppDomainConfigFile(ulong appDomain, int count, char* configFile, uint* pNeeded) => HResults.E_NOTIMPL;
public unsafe int GetAppDomainData(ulong addr, void* data) => HResults.E_NOTIMPL;
public unsafe int GetAppDomainList(uint count, [In, MarshalUsing(CountElementName = "count"), Out] ulong[] values, uint* pNeeded) => HResults.E_NOTIMPL;
public unsafe int GetAppDomainName(ulong addr, uint count, char* name, uint* pNeeded) => HResults.E_NOTIMPL;
public unsafe int GetAppDomainStoreData(void* data) => HResults.E_NOTIMPL;
public unsafe int GetApplicationBase(ulong appDomain, int count, char* appBase, uint* pNeeded) => HResults.E_NOTIMPL;
public unsafe int GetAssemblyData(ulong baseDomainPtr, ulong assembly, void* data) => HResults.E_NOTIMPL;
public unsafe int GetAssemblyList(ulong appDomain, int count, [In, MarshalUsing(CountElementName = "count"), Out] ulong[] values, int* pNeeded) => HResults.E_NOTIMPL;
public unsafe int GetAssemblyLocation(ulong assembly, int count, char* location, uint* pNeeded) => HResults.E_NOTIMPL;
public unsafe int GetAssemblyModuleList(ulong assembly, uint count, [In, MarshalUsing(CountElementName = "count"), Out] ulong[] modules, uint* pNeeded) => HResults.E_NOTIMPL;
public unsafe int GetAssemblyName(ulong assembly, uint count, char* name, uint* pNeeded) => HResults.E_NOTIMPL;
public int GetBreakingChangeVersion()
{
// TODO: Return non-hard-coded version
return 4;
}
public unsafe int GetCCWData(ulong ccw, void* data) => HResults.E_NOTIMPL;
public unsafe int GetCCWInterfaces(ulong ccw, uint count, void* interfaces, uint* pNeeded) => HResults.E_NOTIMPL;
public unsafe int GetClrWatsonBuckets(ulong thread, void* pGenericModeBlock) => HResults.E_NOTIMPL;
public unsafe int GetCodeHeaderData(ulong ip, void* data) => HResults.E_NOTIMPL;
public unsafe int GetCodeHeapList(ulong jitManager, uint count, void* codeHeaps, uint* pNeeded) => HResults.E_NOTIMPL;
public unsafe int GetDacModuleHandle(void* phModule) => HResults.E_NOTIMPL;
public unsafe int GetDomainFromContext(ulong context, ulong* domain) => HResults.E_NOTIMPL;
public unsafe int GetDomainLocalModuleData(ulong addr, void* data) => HResults.E_NOTIMPL;
public unsafe int GetDomainLocalModuleDataFromAppDomain(ulong appDomainAddr, int moduleID, void* data) => HResults.E_NOTIMPL;
public unsafe int GetDomainLocalModuleDataFromModule(ulong moduleAddr, void* data) => HResults.E_NOTIMPL;
public unsafe int GetFailedAssemblyData(ulong assembly, uint* pContext, int* pResult) => HResults.E_NOTIMPL;
public unsafe int GetFailedAssemblyDisplayName(ulong assembly, uint count, char* name, uint* pNeeded) => HResults.E_NOTIMPL;
public unsafe int GetFailedAssemblyList(ulong appDomain, int count, [In, MarshalUsing(CountElementName = "count"), Out] ulong[] values, uint* pNeeded) => HResults.E_NOTIMPL;
public unsafe int GetFailedAssemblyLocation(ulong assesmbly, uint count, char* location, uint* pNeeded) => HResults.E_NOTIMPL;
public unsafe int GetFieldDescData(ulong fieldDesc, void* data) => HResults.E_NOTIMPL;
public unsafe int GetFrameName(ulong vtable, uint count, char* frameName, uint* pNeeded) => HResults.E_NOTIMPL;
public unsafe int GetGCHeapData(void* data) => HResults.E_NOTIMPL;
public unsafe int GetGCHeapDetails(ulong heap, void* details) => HResults.E_NOTIMPL;
public unsafe int GetGCHeapList(uint count, [In, MarshalUsing(CountElementName = "count"), Out] ulong[] heaps, uint* pNeeded) => HResults.E_NOTIMPL;
public unsafe int GetGCHeapStaticData(void* data) => HResults.E_NOTIMPL;
public unsafe int GetHandleEnum(void** ppHandleEnum) => HResults.E_NOTIMPL;
public unsafe int GetHandleEnumForGC(uint gen, void** ppHandleEnum) => HResults.E_NOTIMPL;
public unsafe int GetHandleEnumForTypes([In, MarshalUsing(CountElementName = "count")] uint[] types, uint count, void** ppHandleEnum) => HResults.E_NOTIMPL;
public unsafe int GetHeapAllocData(uint count, void* data, uint* pNeeded) => HResults.E_NOTIMPL;
public unsafe int GetHeapAnalyzeData(ulong addr, void* data) => HResults.E_NOTIMPL;
public unsafe int GetHeapAnalyzeStaticData(void* data) => HResults.E_NOTIMPL;
public unsafe int GetHeapSegmentData(ulong seg, void* data) => HResults.E_NOTIMPL;
public unsafe int GetHillClimbingLogEntry(ulong addr, void* data) => HResults.E_NOTIMPL;
public unsafe int GetILForModule(ulong moduleAddr, int rva, ulong* il) => HResults.E_NOTIMPL;
public unsafe int GetJitHelperFunctionName(ulong ip, uint count, byte* name, uint* pNeeded) => HResults.E_NOTIMPL;
public unsafe int GetJitManagerList(uint count, void* managers, uint* pNeeded) => HResults.E_NOTIMPL;
public unsafe int GetJumpThunkTarget(void* ctx, ulong* targetIP, ulong* targetMD) => HResults.E_NOTIMPL;
public unsafe int GetMethodDescData(ulong methodDesc, ulong ip, void* data, uint cRevertedRejitVersions, void* rgRevertedRejitData, uint* pcNeededRevertedRejitData) => HResults.E_NOTIMPL;
public unsafe int GetMethodDescFromToken(ulong moduleAddr, uint token, ulong* methodDesc) => HResults.E_NOTIMPL;
public unsafe int GetMethodDescName(ulong methodDesc, uint count, char* name, uint* pNeeded) => HResults.E_NOTIMPL;
public unsafe int GetMethodDescPtrFromFrame(ulong frameAddr, ulong* ppMD) => HResults.E_NOTIMPL;
public unsafe int GetMethodDescPtrFromIP(ulong ip, ulong* ppMD) => HResults.E_NOTIMPL;
public unsafe int GetMethodDescTransparencyData(ulong methodDesc, void* data) => HResults.E_NOTIMPL;
public unsafe int GetMethodTableData(ulong mt, void* data) => HResults.E_NOTIMPL;
public unsafe int GetMethodTableFieldData(ulong mt, void* data) => HResults.E_NOTIMPL;
public unsafe int GetMethodTableForEEClass(ulong eeClass, ulong* value) => HResults.E_NOTIMPL;
public unsafe int GetMethodTableName(ulong mt, uint count, char* mtName, uint* pNeeded) => HResults.E_NOTIMPL;
public unsafe int GetMethodTableSlot(ulong mt, uint slot, ulong* value) => HResults.E_NOTIMPL;
public unsafe int GetMethodTableTransparencyData(ulong mt, void* data) => HResults.E_NOTIMPL;
public unsafe int GetModule(ulong addr, void** mod) => HResults.E_NOTIMPL;
public unsafe int GetModuleData(ulong moduleAddr, void* data) => HResults.E_NOTIMPL;
public unsafe int GetNestedExceptionData(ulong exception, ulong* exceptionObject, ulong* nextNestedException) => HResults.E_NOTIMPL;
public unsafe int GetObjectClassName(ulong obj, uint count, char* className, uint* pNeeded) => HResults.E_NOTIMPL;
public unsafe int GetObjectData(ulong objAddr, void* data) => HResults.E_NOTIMPL;
public unsafe int GetObjectStringData(ulong obj, uint count, char* stringData, uint* pNeeded) => HResults.E_NOTIMPL;
public unsafe int GetOOMData(ulong oomAddr, void* data) => HResults.E_NOTIMPL;
public unsafe int GetOOMStaticData(void* data) => HResults.E_NOTIMPL;
public unsafe int GetPEFileBase(ulong addr, ulong* peBase) => HResults.E_NOTIMPL;
public unsafe int GetPEFileName(ulong addr, uint count, char* fileName, uint* pNeeded) => HResults.E_NOTIMPL;
public unsafe int GetPrivateBinPaths(ulong appDomain, int count, char* paths, uint* pNeeded) => HResults.E_NOTIMPL;
public unsafe int GetRCWData(ulong addr, void* data) => HResults.E_NOTIMPL;
public unsafe int GetRCWInterfaces(ulong rcw, uint count, void* interfaces, uint* pNeeded) => HResults.E_NOTIMPL;
public unsafe int GetRegisterName(int regName, uint count, char* buffer, uint* pNeeded) => HResults.E_NOTIMPL;
public unsafe int GetStackLimits(ulong threadPtr, ulong* lower, ulong* upper, ulong* fp) => HResults.E_NOTIMPL;
public unsafe int GetStackReferences(int osThreadID, void** ppEnum) => HResults.E_NOTIMPL;
public unsafe int GetStressLogAddress(ulong* stressLog) => HResults.E_NOTIMPL;
public unsafe int GetSyncBlockCleanupData(ulong addr, void* data) => HResults.E_NOTIMPL;
public unsafe int GetSyncBlockData(uint number, void* data) => HResults.E_NOTIMPL;
public unsafe int GetThreadAllocData(ulong thread, void* data) => HResults.E_NOTIMPL;
public unsafe int GetThreadData(ulong thread, DacpThreadData* data) => HResults.E_NOTIMPL;
public unsafe int GetThreadFromThinlockID(uint thinLockId, ulong* pThread) => HResults.E_NOTIMPL;
public unsafe int GetThreadLocalModuleData(ulong thread, uint index, void* data) => HResults.E_NOTIMPL;
public unsafe int GetThreadpoolData(void* data) => HResults.E_NOTIMPL;
public unsafe int GetThreadStoreData(DacpThreadStoreData* data) => HResults.E_NOTIMPL;
public unsafe int GetTLSIndex(uint* pIndex) => HResults.E_NOTIMPL;
public unsafe int GetUsefulGlobals(void* data) => HResults.E_NOTIMPL;
public unsafe int GetWorkRequestData(ulong addrWorkRequest, void* data) => HResults.E_NOTIMPL;
public unsafe int TraverseEHInfo(ulong ip, void* pCallback, void* token) => HResults.E_NOTIMPL;
public unsafe int TraverseLoaderHeap(ulong loaderHeapAddr, void* pCallback) => HResults.E_NOTIMPL;
public unsafe int TraverseModuleMap(int mmt, ulong moduleAddr, void* pCallback, void* token) => HResults.E_NOTIMPL;
public unsafe int TraverseRCWCleanupList(ulong cleanupListPtr, void* pCallback, void* token) => HResults.E_NOTIMPL;
public unsafe int TraverseVirtCallStubHeap(ulong pAppDomain, int heaptype, void* pCallback) => HResults.E_NOTIMPL;
}

View file

@ -1,36 +0,0 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.Marshalling;
namespace Microsoft.Diagnostics.DataContractReader;
[GeneratedComInterface]
[Guid("4eca42d8-7e7b-4c8a-a116-7bfbf6929267")]
internal partial interface ISOSDacInterface9
{
int GetBreakingChangeVersion();
}
/// <summary>
/// Implementation of ISOSDacInterface* interfaces intended to be passed out to consumers
/// interacting with the DAC via those COM interfaces.
/// </summary>
[GeneratedComClass]
internal sealed partial class SOSDacImpl : ISOSDacInterface9
{
private readonly Target _target;
public SOSDacImpl(Target target)
{
_target = target;
}
public int GetBreakingChangeVersion()
{
// TODO: Return non-hard-coded version
return 4;
}
}

View file

@ -1,11 +1,64 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System;
using System.Buffers.Binary;
namespace Microsoft.Diagnostics.DataContractReader;
internal sealed class Target
public struct TargetPointer
{
public Target(nint _)
{
}
public static TargetPointer Null = new(0);
public ulong Value;
public TargetPointer(ulong value) => Value = value;
}
internal sealed unsafe class Target
{
private readonly delegate* unmanaged<ulong, byte*, uint, void*, int> _readFromTarget;
private readonly void* _readContext;
private bool _isLittleEndian;
private int _pointerSize;
public Target(ulong _, delegate* unmanaged<ulong, byte*, uint, void*, int> readFromTarget, void* readContext)
{
_readFromTarget = readFromTarget;
_readContext = readContext;
// TODO: [cdac] Populate from descriptor
_isLittleEndian = BitConverter.IsLittleEndian;
_pointerSize = IntPtr.Size;
}
public bool TryReadPointer(ulong address, out TargetPointer pointer)
{
pointer = TargetPointer.Null;
byte* buffer = stackalloc byte[_pointerSize];
ReadOnlySpan<byte> span = new ReadOnlySpan<byte>(buffer, _pointerSize);
if (ReadFromTarget(address, buffer, (uint)_pointerSize) < 0)
return false;
if (_pointerSize == sizeof(uint))
{
pointer = new TargetPointer(
_isLittleEndian
? BinaryPrimitives.ReadUInt32LittleEndian(span)
: BinaryPrimitives.ReadUInt32BigEndian(span));
}
else if (_pointerSize == sizeof(ulong))
{
pointer = new TargetPointer(
_isLittleEndian
? BinaryPrimitives.ReadUInt64LittleEndian(span)
: BinaryPrimitives.ReadUInt64BigEndian(span));
}
return true;
}
private int ReadFromTarget(ulong address, byte* buffer, uint bytesToRead)
=> _readFromTarget(address, buffer, bytesToRead, _readContext);
}

View file

@ -1,7 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<AssemblyName Condition="'$(TargetsWindows)' != 'true'">lib$(MSBuildProjectName)</AssemblyName>
<TargetFramework>$(NetCoreAppToolCurrent)</TargetFramework>
<RootNamespace>Microsoft.Diagnostics.DataContractReader</RootNamespace>
<Nullable>enable</Nullable>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<!-- Do not produce a public package. This ships as part of the runtime -->
@ -9,6 +11,9 @@
<InvariantGlobalization>true</InvariantGlobalization>
</PropertyGroup>
<ItemGroup>
<Compile Include="$(LibrariesProjectRoot)Common\src\System\HResults.cs" Link="Common\System\HResults.cs" />
</ItemGroup>
<ItemGroup>
<InstallRuntimeComponentDestination Include="." />
<!-- TODO: [cdac] Output to sharedFramework and add PlatformManifestFileEntry for Microsoft.NETCore.App once ready to include in shipping package -->

View file

@ -1,8 +1,6 @@
<Project Sdk="Microsoft.Build.Traversal">
<PropertyGroup>
<!-- We always want to use release for publishing using NativeAOT -->
<NativeLibsPublishConfiguration>Release</NativeLibsPublishConfiguration>
<!-- we always want to make shared libs -->
<!-- we always want to make shared libs -->
<NativeLibKind Condition="'$(NativeLibKind)' == ''">shared</NativeLibKind>
<!-- When we publish, we want to ensure the SDK does the same thing as though we ran 'dotnet publish' -->
@ -39,7 +37,7 @@
<!-- properties to pass down to the subproject builds -->
<ItemGroup>
<SubprojectProps Include="Configuration" Value="$(NativeLibsPublishConfiguration)" />
<SubprojectProps Include="Configuration" Value="$(Configuration)" />
<SubprojectProps Include="RuntimeConfiguration" Value="$(RuntimeConfiguration)" />
<SubprojectProps Include="LibrariesConfiguration" Value="$(LibrariesConfiguration)" />
<SubprojectProps Include="RuntimeIdentifier" Value="$(OutputRID)" />