This commit is contained in:
Max Charlamb 2025-07-30 16:14:43 +02:00 committed by GitHub
commit 189e822511
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
23 changed files with 428 additions and 159 deletions

View File

@ -178,6 +178,12 @@ endif(CLR_CMAKE_HOST_WIN32)
#----------------------------------
include(clrdefinitions.cmake)
#--------------------------------
# Data descriptors mechanics
# - all clr specific data descriptor helpers should be included in this file
#----------------------------------
include(clrdatadescriptors.cmake)
if(FEATURE_STANDALONE_GC)
add_definitions(-DFEATURE_STANDALONE_GC)
endif(FEATURE_STANDALONE_GC)

View File

@ -0,0 +1,86 @@
# cDAC contract descriptor
function(generate_data_descriptors)
set(options "")
set(oneValueArgs LIBRARY_NAME CONTRACT_FILE HEADER_FILE INLINE_FILE POINTER_DATA_NAME CONTRACT_NAME)
set(multiValueArgs INCLUDE_DIRS DEPENDENCIES)
cmake_parse_arguments(DATA_DESCRIPTORS "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGV})
# INTERMEDIARY_LIBRARY is used as part of the build and not linked into the final product.
set(INTERMEDIARY_LIBRARY ${DATA_DESCRIPTORS_LIBRARY_NAME}_temp)
set(LIBRARY ${DATA_DESCRIPTORS_LIBRARY_NAME})
set(DATA_DESCRIPTOR_SHARED_SOURCE_DIR "${CMAKE_CURRENT_FUNCTION_LIST_DIR}/debug/datadescriptor")
set(GENERATED_CDAC_DESCRIPTOR_DIR "${CMAKE_CURRENT_BINARY_DIR}/cdac-${LIBRARY}")
# configure contract export name
set(POINTER_DATA_NAME ${DATA_DESCRIPTORS_POINTER_DATA_NAME})
set(CONTRACT_NAME ${DATA_DESCRIPTORS_CONTRACT_NAME})
configure_file("${DATA_DESCRIPTOR_SHARED_SOURCE_DIR}/contractconfiguration.h.in" "${GENERATED_CDAC_DESCRIPTOR_DIR}/contractconfiguration.h")
if (NOT CDAC_BUILD_TOOL_BINARY_PATH)
# if CDAC_BUILD_TOOL_BINARY_PATH is unspecified (for example for a build without a .NET SDK or msbuild),
# link a stub contract descriptor into the runtime
add_library_clr(${LIBRARY} OBJECT "${DATA_DESCRIPTOR_SHARED_SOURCE_DIR}/contractdescriptorstub.c")
target_include_directories(${LIBRARY} PRIVATE ${GENERATED_CDAC_DESCRIPTOR_DIR})
message(STATUS "Using a stub cDAC contract descriptor")
else()
# generate a contract descriptor using cdac-build-tool from a data descriptor and contract json file
if(NOT EXISTS "${CDAC_BUILD_TOOL_BINARY_PATH}")
message(FATAL_ERROR "${CDAC_BUILD_TOOL_BINARY_PATH} does not exist")
endif()
add_library(${INTERMEDIARY_LIBRARY} OBJECT "${DATA_DESCRIPTOR_SHARED_SOURCE_DIR}/datadescriptor.cpp")
if(CLR_CMAKE_TARGET_WIN32)
# turn off whole program optimization:
# 1. it creates object files that cdac-build-tool can't read
# 2. we never link INTERMEDIARY_LIBRARY into the final product - it's only job is to be scraped
set_target_properties(${INTERMEDIARY_LIBRARY} PROPERTIES
INTERPROCEDURAL_OPTIMIZATION_RELEASE OFF
INTERPROCEDURAL_OPTIMIZATION_RELWITHDEBINFO OFF)
endif()
# don't build the data descriptor before dependencies
if(DEFINED DATA_DESCRIPTORS_DEPENDENCIES)
add_dependencies(${INTERMEDIARY_LIBRARY} ${DATA_DESCRIPTORS_DEPENDENCIES})
endif()
if(DEFINED DATA_DESCRIPTORS_INCLUDE_DIRS)
target_include_directories(${INTERMEDIARY_LIBRARY} BEFORE PRIVATE ${DATA_DESCRIPTORS_INCLUDE_DIRS})
endif()
set(CONTRACT_BASELINE_DIR "${CLR_REPO_ROOT_DIR}/docs/design/datacontracts/data")
set(CONTRACT_DESCRIPTOR_INPUT "${DATA_DESCRIPTOR_SHARED_SOURCE_DIR}/contract-descriptor.c.in")
set(CONTRACT_DESCRIPTOR_OUTPUT "${GENERATED_CDAC_DESCRIPTOR_DIR}/contract-descriptor.c")
set(CONTRACT_FILE "${DATA_DESCRIPTORS_CONTRACT_FILE}")
# generate the contract descriptor by running cdac-build-tool
# n.b. this just uses `dotnet` from the PATH. InitializeDotNetCli adds the appropriate directory
add_custom_command(
OUTPUT "${CONTRACT_DESCRIPTOR_OUTPUT}"
VERBATIM
COMMAND ${CLR_DOTNET_HOST_PATH} ${CDAC_BUILD_TOOL_BINARY_PATH} compose -i "${CONTRACT_DESCRIPTOR_INPUT}" -o "${CONTRACT_DESCRIPTOR_OUTPUT}" -b "${CONTRACT_BASELINE_DIR}" -c "${CONTRACT_FILE}" $<TARGET_OBJECTS:${INTERMEDIARY_LIBRARY}>
DEPENDS ${INTERMEDIARY_LIBRARY} ${DATA_DESCRIPTORS_DEPENDENCIES} $<TARGET_OBJECTS:${INTERMEDIARY_LIBRARY}> "${CONTRACT_FILE}" "${CONTRACT_DESCRIPTOR_INPUT}"
USES_TERMINAL
)
# It is important that LIBRARY is an object library;
# if it was static, linking it into the final dll would not export
# DotNetRuntimeContractDescriptor since it is not referenced anywhere.
add_library_clr(${LIBRARY} OBJECT
"${CONTRACT_DESCRIPTOR_OUTPUT}"
"${DATA_DESCRIPTOR_SHARED_SOURCE_DIR}/contractpointerdata.cpp"
)
add_dependencies(${LIBRARY} ${INTERMEDIARY_LIBRARY})
if(DEFINED DATA_DESCRIPTORS_DEPENDENCIES)
add_dependencies(${LIBRARY} ${DATA_DESCRIPTORS_DEPENDENCIES})
endif()
target_include_directories(${LIBRARY} PRIVATE ${GENERATED_CDAC_DESCRIPTOR_DIR})
if(DEFINED DATA_DESCRIPTORS_INCLUDE_DIRS)
target_include_directories(${LIBRARY} BEFORE PRIVATE ${DATA_DESCRIPTORS_INCLUDE_DIRS})
endif()
endif()
endfunction(generate_data_descriptors)

View File

@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
#include <stdint.h>
#include "contractconfiguration.h"
#ifdef _MSC_VER
#define DLLEXPORT __declspec(dllexport)
@ -20,15 +21,15 @@ struct DotNetRuntimeContractDescriptor
const uintptr_t *pointer_data;
};
extern const uintptr_t contractDescriptorPointerData[];
extern const uintptr_t POINTER_NAME[];
DLLEXPORT struct DotNetRuntimeContractDescriptor DotNetRuntimeContractDescriptor;
DLLEXPORT struct DotNetRuntimeContractDescriptor CONTRACT_NAME;
DLLEXPORT struct DotNetRuntimeContractDescriptor DotNetRuntimeContractDescriptor = {
DLLEXPORT struct DotNetRuntimeContractDescriptor CONTRACT_NAME = {
.magic = 0x0043414443434e44ull, // "DNCCDAC\0"
.flags = %%platformFlags%%,
.descriptor_size = %%jsonDescriptorSize%%,
.descriptor = "%%jsonDescriptor%%",
.pointer_data_count = %%pointerDataCount%%,
.pointer_data = &contractDescriptorPointerData[0],
.pointer_data = &POINTER_NAME[0],
};

View File

@ -0,0 +1,4 @@
#pragma once
#define POINTER_NAME @POINTER_DATA_NAME@
#define CONTRACT_NAME @CONTRACT_NAME@

View File

@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
#include <stdint.h>
#include "contractconfiguration.h"
#ifdef _MSC_VER
#define DLLEXPORT __declspec(dllexport)
@ -20,20 +21,20 @@ struct DotNetRuntimeContractDescriptor
const uintptr_t *pointer_data;
};
extern const uintptr_t contractDescriptorPointerData[];
extern const uintptr_t POINTER_NAME[];
// just the placeholder pointer
const uintptr_t contractDescriptorPointerData[] = { (uintptr_t)0 };
const uintptr_t POINTER_NAME[] = { (uintptr_t)0 };
DLLEXPORT struct DotNetRuntimeContractDescriptor DotNetRuntimeContractDescriptor;
DLLEXPORT struct DotNetRuntimeContractDescriptor CONTRACT_NAME;
#define STUB_DESCRIPTOR "{\"version\":0,\"baseline\":\"empty\",\"contracts\":{},\"types\":{},\"globals\":{}}"
DLLEXPORT struct DotNetRuntimeContractDescriptor DotNetRuntimeContractDescriptor = {
DLLEXPORT struct DotNetRuntimeContractDescriptor CONTRACT_NAME = {
.magic = 0x0043414443434e44ull, // "DNCCDAC\0"
.flags = 0x1u & (sizeof(void*) == 4 ? 0x02u : 0x00u),
.descriptor_size = sizeof(STUB_DESCRIPTOR),
.descriptor = STUB_DESCRIPTOR,
.pointer_data_count = 1,
.pointer_data = &contractDescriptorPointerData[0],
.pointer_data = &POINTER_NAME[0],
};

View File

@ -1,21 +1,15 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
#include "common.h"
#include <stddef.h>
#include <stdint.h>
#include "cdacplatformmetadata.hpp"
#include "threads.h"
#include "vars.hpp"
#include "datadescriptor.h"
#include "contractconfiguration.h"
extern "C"
{
// without an extern declaration, clang does not emit this global into the object file
extern const uintptr_t contractDescriptorPointerData[];
extern const uintptr_t POINTER_NAME[];
const uintptr_t contractDescriptorPointerData[] = {
const uintptr_t POINTER_NAME[] = {
(uintptr_t)0, // placeholder
#define CDAC_GLOBAL_POINTER(name,value) (uintptr_t)(value),
#include "datadescriptor.inc"

View File

@ -1,26 +1,7 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
#include "common.h"
#include <stdint.h>
#include <stddef.h>
#include "static_assert.h"
#include <sospriv.h>
#include "cdacplatformmetadata.hpp"
#include "methodtable.h"
#include "threads.h"
#include "exinfo.h"
#include "configure.h"
#include "../debug/ee/debugger.h"
#ifdef HAVE_GCCOVER
#include "gccover.h"
#endif // HAVE_GCCOVER
#include "datadescriptor.h"
// begin blob definition
@ -261,7 +242,7 @@ static_assert_no_msg(sizeof(void*) == 4 || sizeof(void*) == 8);
// C-style designated initializers are a C++20 feature. Have to use plain old aggregate initialization instead.
DLLEXPORT
// DLLEXPORT
struct MagicAndBlob BlobDataDescriptor = {
/*.magic = */ 0x00424F4C42434144ull,// "DACBLOB",
/*.Blob =*/ {

View File

@ -1,10 +1,9 @@
set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(RUNTIMEINFO_SOURCES
runtimeinfo.cpp
)
add_library_clr(runtimeinfo STATIC ${RUNTIMEINFO_SOURCES})
target_include_directories(runtimeinfo PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR})
function(generate_module_index Target ModuleIndexFile)
# Win32 may be false when cross compiling
@ -40,65 +39,26 @@ endif()
install_clr(TARGETS runtimeinfo DESTINATIONS lib COMPONENT runtime)
# cDAC contract descriptor
# main vm data descriptor
if(CDAC_BUILD_TOOL_BINARY_PATH AND "${CLR_DOTNET_RID}" STREQUAL "")
message(FATAL_ERROR "CLR_DOTNET_RID is not set. Please ensure it is being set to the portable RID of the target platform by runtime.proj.")
endif()
configure_file(configure.h.in ${CMAKE_CURRENT_BINARY_DIR}/configure.h)
if (NOT CDAC_BUILD_TOOL_BINARY_PATH)
# if CDAC_BUILD_TOOL_BINARY_PATH is unspecified (for example for a build without a .NET SDK or msbuild),
# link a stub contract descriptor into the runtime
add_library_clr(cdac_contract_descriptor OBJECT contractdescriptorstub.c)
message(STATUS "Using a stub cDAC contract descriptor")
else()
# generate a contract descriptor using cdac-build-tool from a data descriptor and contract json file
generate_data_descriptors(
LIBRARY_NAME cdac_contract_descriptor
CONTRACT_FILE "${CMAKE_CURRENT_SOURCE_DIR}/contracts.jsonc"
POINTER_DATA_NAME "contractDescriptorPointerData"
CONTRACT_NAME "DotNetRuntimeContractDescriptor"
INCLUDE_DIRS "${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_CURRENT_BINARY_DIR}" "${VM_DIR}" "${VM_DIR}/${ARCH_SOURCES_DIR}" "${CLR_DIR}/interop/inc"
DEPENDENCIES cee_wks_core)
add_library(cdac_data_descriptor OBJECT datadescriptor.cpp)
# don't build the data descriptor before the VM (and any of its dependencies' generated headers)
add_dependencies(cdac_data_descriptor cee_wks_core)
if(CLR_CMAKE_TARGET_WIN32)
# turn off whole program optimization:
# 1. it creates object files that cdac-build-tool can't read
# 2. we never link cdac_data_descriptor into the final product - it's only job is to be scraped
set_target_properties(cdac_data_descriptor PROPERTIES
INTERPROCEDURAL_OPTIMIZATION_RELEASE OFF
INTERPROCEDURAL_OPTIMIZATION_RELWITHDEBINFO OFF)
endif()
target_include_directories(cdac_data_descriptor BEFORE PRIVATE ${VM_DIR})
target_include_directories(cdac_data_descriptor BEFORE PRIVATE ${VM_DIR}/${ARCH_SOURCES_DIR})
target_include_directories(cdac_data_descriptor PRIVATE ${CLR_DIR}/interop/inc)
set(GENERATED_CDAC_DESCRIPTOR_DIR "${CMAKE_CURRENT_BINARY_DIR}/cdac")
set(CONTRACT_DESCRIPTOR_OUTPUT "${GENERATED_CDAC_DESCRIPTOR_DIR}/contract-descriptor.c")
if(NOT EXISTS "${CDAC_BUILD_TOOL_BINARY_PATH}")
message(FATAL_ERROR "${CDAC_BUILD_TOOL_BINARY_PATH} does not exist")
endif()
set(CONTRACT_DESCRIPTOR_INPUT "${CMAKE_CURRENT_SOURCE_DIR}/contract-descriptor.c.in")
set(CONTRACT_BASELINE_DIR "${CLR_REPO_ROOT_DIR}/docs/design/datacontracts/data")
set(CONTRACT_FILE "${CMAKE_CURRENT_SOURCE_DIR}/contracts.jsonc")
# generate the contract descriptor by running cdac-build-tool
# n.b. this just uses `dotnet` from the PATH. InitializeDotNetCli adds the apropropriate directory
add_custom_command(
OUTPUT "${CONTRACT_DESCRIPTOR_OUTPUT}"
VERBATIM
COMMAND ${CLR_DOTNET_HOST_PATH} ${CDAC_BUILD_TOOL_BINARY_PATH} compose -i "${CONTRACT_DESCRIPTOR_INPUT}" -o "${CONTRACT_DESCRIPTOR_OUTPUT}" -b "${CONTRACT_BASELINE_DIR}" -c "${CONTRACT_FILE}" $<TARGET_OBJECTS:cdac_data_descriptor>
DEPENDS cdac_data_descriptor cee_wks_core $<TARGET_OBJECTS:cdac_data_descriptor> "${CONTRACT_FILE}" "${CONTRACT_DESCRIPTOR_INPUT}"
USES_TERMINAL
)
# It is important that cdac_contract_descriptor is an object library;
# if it was static, linking it into the final dll would not export
# DotNetRuntimeContractDescriptor since it is not referenced anywhere.
add_library_clr(cdac_contract_descriptor OBJECT
"${CONTRACT_DESCRIPTOR_OUTPUT}"
contractpointerdata.cpp
)
target_include_directories(cdac_contract_descriptor BEFORE PRIVATE ${VM_DIR})
target_include_directories(cdac_contract_descriptor BEFORE PRIVATE ${VM_DIR}/${ARCH_SOURCES_DIR})
target_include_directories(cdac_contract_descriptor PRIVATE ${CLR_DIR}/interop/inc)
add_dependencies(cdac_contract_descriptor cdac_data_descriptor cee_wks_core)
endif()
set(GC_DESCRIPTOR_DIR "${CLR_DIR}/gc/gcdatadescriptors")
generate_data_descriptors(
LIBRARY_NAME in_process_gc_contract_descriptor
CONTRACT_FILE "${GC_DESCRIPTOR_DIR}/contracts.jsonc"
POINTER_DATA_NAME "GContractPointerData"
CONTRACT_NAME "GCContractDescriptor"
INCLUDE_DIRS "${GC_DESCRIPTOR_DIR}" "${CLR_DIR}/gc"
DEPENDENCIES cee_wks_core)

View File

@ -0,0 +1,26 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
#include "common.h"
#include <stdint.h>
#include <stddef.h>
#include "static_assert.h"
#include <sospriv.h>
#include "cdacplatformmetadata.hpp"
#include "methodtable.h"
#include "threads.h"
#include "vars.hpp"
#include "exinfo.h"
#include "configure.h"
#include "../debug/ee/debugger.h"
#ifdef HAVE_GCCOVER
#include "gccover.h"
#endif // HAVE_GCCOVER
#include "gcheaputilities.h"

View File

@ -1010,9 +1010,11 @@ CDAC_GLOBAL(StressLogEnabled, uint8, 0)
CDAC_GLOBAL_POINTER(ExecutionManagerCodeRangeMapAddress, cdac_data<ExecutionManager>::CodeRangeMapAddress)
CDAC_GLOBAL_POINTER(PlatformMetadata, &::g_cdacPlatformMetadata)
CDAC_GLOBAL_POINTER(ProfilerControlBlock, &::g_profControlBlock)
CDAC_GLOBAL_POINTER(GCDescriptor, &::g_gcDescriptors)
CDAC_GLOBALS_END()
#undef CDAC_BASELINE
#undef CDAC_BASELINEF
#undef CDAC_TYPES_BEGIN
#undef CDAC_TYPE_BEGIN
#undef CDAC_TYPE_INDETERMINATE

View File

@ -73,6 +73,7 @@ if (NOT CLR_CMAKE_HOST_ARCH_WASM)
set(LIB_CORDBEE cordbee_wks)
set(LIB_INTEROP interop)
set(LIB_CDAC_CONTRACT_DESCRIPTOR cdac_contract_descriptor)
set(LIB_CDAC_IN_PROC_GC_CONTRACT_DESCRIPTOR in_process_gc_contract_descriptor)
endif(NOT CLR_CMAKE_HOST_ARCH_WASM)
if (CLR_CMAKE_HOST_UNIX AND NOT CLR_CMAKE_TARGET_ARCH_WASM)
@ -104,6 +105,7 @@ set(CORECLR_LIBRARIES
coreclrminipal
gc_pal
${LIB_CDAC_CONTRACT_DESCRIPTOR}
${LIB_CDAC_IN_PROC_GC_CONTRACT_DESCRIPTOR}
)
if(CLR_CMAKE_TARGET_ARCH_AMD64)

View File

@ -104,11 +104,15 @@ list(APPEND GC_SOURCES ${GC_HEADERS})
convert_to_absolute_path(GC_SOURCES ${GC_SOURCES})
if(FEATURE_STANDALONE_GC)
add_subdirectory(gcdatadescriptors)
# clrgcexp is build with standalone+regions
if (CLR_CMAKE_TARGET_ARCH_ARM64 OR CLR_CMAKE_TARGET_ARCH_AMD64)
add_library_clr(clrgcexp SHARED ${GC_SOURCES})
add_dependencies(clrgcexp eventing_headers)
target_link_libraries(clrgcexp PRIVATE ${GC_LINK_LIBRARIES})
target_link_libraries(clrgcexp PRIVATE gc_contract_descriptor)
target_compile_definitions(clrgcexp PRIVATE -DUSE_REGIONS)
install_clr(TARGETS clrgcexp DESTINATIONS . COMPONENT runtime)
endif (CLR_CMAKE_TARGET_ARCH_ARM64 OR CLR_CMAKE_TARGET_ARCH_AMD64)
@ -117,6 +121,7 @@ if(FEATURE_STANDALONE_GC)
add_library_clr(clrgc SHARED ${GC_SOURCES})
add_dependencies(clrgc eventing_headers)
target_link_libraries(clrgc PRIVATE ${GC_LINK_LIBRARIES})
target_link_libraries(clrgc PRIVATE gc_contract_descriptor)
install_clr(TARGETS clrgc DESTINATIONS . COMPONENT runtime)
add_definitions(-DBUILD_AS_STANDALONE)

View File

@ -0,0 +1,2 @@
[contracts.jsonc]
indent_size = 2

View File

@ -0,0 +1,7 @@
# cDAC contract descriptor
generate_data_descriptors(
LIBRARY_NAME gc_contract_descriptor
CONTRACT_FILE "${CMAKE_CURRENT_SOURCE_DIR}/contracts.jsonc"
INCLUDE_DIRS "${CMAKE_CURRENT_SOURCE_DIR}" "${CLR_DIR}/pal/inc" "${CLR_DIR}/inc" "${CLR_DIR}/gc"
POINTER_DATA_NAME "GCContractPointerData"
CONTRACT_NAME "GCContractDescriptor")

View File

@ -0,0 +1,13 @@
//algorithmic contracts for coreclr
// The format of this file is: JSON with comments
// {
// "CONTRACT NAME": VERSION,
// ...
// }
// CONTRACT NAME is an arbitrary string, VERSION is an integer
//
// cdac-build-tool can take multiple "-c contract_file" arguments
// so to conditionally include contracts, put additional contracts in a separate file
{
"GC": 1
}

View File

@ -0,0 +1,7 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
#include <stdint.h>
#include <stddef.h>
#include "static_assert.h"

View File

@ -0,0 +1,137 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
//
// No include guards. This file is included multiple times.
// The format is:
// CDAC_BASELINE("string") baseline data contract that the runtime should follow. "empty" is reasonable
// CDAC_TYPES_BEGIN()
// ... <types> ...
// CDAC_TYPES_END()
// CDAC_GLOBALS_BEGIN()
// ... <globals> ...
// CDAC_GLOBALS_END()
//
// In <types> the format is:
// CDAC_TYPE_BEGIN(cdacTypeIdentifier) // defined a new data descriptor named cdacIdentifier
//
// CDAC_TYPE_SIZE(k) -or- CDAC_TYPE_INDETERMINATE(cdacTypeIdentifier) specifies that the type has
// size k (bytes - usually sizeof(SomeNativeType)) or specify that the type's size is not provided
// It is important that CDAC_TYPE_SIZE or CDAC_TYPE_INDETERMINATE immediately follows
// CDAC_TYPE_BEGIN
//
// CDAC_TYPE_FIELD(cdacTypeIdentifier, cdacFieldTypeIdentifier, cdacFieldName, k) specifies the
// field of "cdacTypeIdentifier" that has name cdacFieldName and has the type
// "cdacFieldtypeIdentifier" located at offset k in the type layout. k is usually
// offsetof(SomeClass, m_FieldName) if the field is public
//
// if the field is private, the convention is that SomeClass declares a friend struct
// cdac_data<T> and provides a specialization of cdac_data<T> with a public constexpr
// size_t member that holds the offset:
//
// class MyClass {
// private:
// void* m_myField;
// friend template<typename T> cdac_data<T>;
// };
// template<> struct cdac_data<MyClass> {
// static constexpr size_t MyField = offsetof(MyClass, m_myField);
// };
//
// then the field layout can be specified as
// CDAC_TYPE_FIELD(MyClassLayout, pointer, MyField, cdac_data<MyClass>::MyField)
// There can be zero or more CDAC_TYPE_FIELD entries per type layout
// For types mapping to managed objects, use exact managed type field names in the descriptor, as
// field names often can't change due to binary serialization or implicit diagnostic contracts
//
// CDAC_TYPE_END(cdacTypeIdentifier) specifies the end of the type layout for cdacTypeIdentifier
//
// In <globals> the format is:
//
// CDAC_GLOBAL(cdacGlobalName, cdacTypeIdentifier, value)
// or
// CDAC_GLOBAL_POINTER(cdacGlobalName, cdacTypeIdentifier, address)
//
// Zero or more globals can be defined
//
// if a global is given with CDAC_GLOBAL(), `value` should be a constexpr uint64_t (or convertible
// to uint64_t) for example, it can be a literal constant or a preprocessor definition
//
// if a global is a CDAC_GLOBAL_POINTER(), address should be a constexpr pointer or a constexpr
// uintptr_t
//
//
//
// This file is compiled using the target architecture. Preprocessor defines for the target
// platform will be available. It is ok to use `#ifdef`.
#ifndef CDAC_BASELINE
#define CDAC_BASELINE(identifier)
#endif
#ifndef CDAC_TYPES_BEGIN
#define CDAC_TYPES_BEGIN()
#endif
#ifndef CDAC_TYPE_BEGIN
#define CDAC_TYPE_BEGIN(tyname)
#endif
#ifndef CDAC_TYPE_SIZE
#define CDAC_TYPE_SIZE(k)
#endif
#ifndef CDAC_TYPE_INDETERMINATE
#define CDAC_TYPE_INDETERMINATE(tyname)
#endif
#ifndef CDAC_TYPE_FIELD
#define CDAC_TYPE_FIELD(tyname,fieldtyname,fieldname,off)
#endif
#ifndef CDAC_TYPE_END
#define CDAC_TYPE_END(tyname)
#endif
#ifndef CDAC_TYPES_END
#define CDAC_TYPES_END()
#endif
#ifndef CDAC_GLOBALS_BEGIN
#define CDAC_GLOBALS_BEGIN()
#endif
#ifndef CDAC_GLOBAL
#define CDAC_GLOBAL(globalname,tyname,val)
#endif
#ifndef CDAC_GLOBAL_POINTER
#define CDAC_GLOBAL_POINTER(globalname,addr)
#endif
#ifndef CDAC_GLOBAL_STRING
#define CDAC_GLOBAL_STRING(globalname,stringval)
#endif
#ifndef CDAC_GLOBALS_END
#define CDAC_GLOBALS_END()
#endif
CDAC_BASELINE("empty")
CDAC_TYPES_BEGIN()
CDAC_TYPE_BEGIN(DummyType)
CDAC_TYPE_SIZE(10)
CDAC_TYPE_FIELD(DummyType, /*uint32*/, DummyField, 0)
CDAC_TYPE_END(DummyType)
CDAC_TYPES_END()
CDAC_GLOBALS_BEGIN()
CDAC_GLOBAL(TestGlobal, uint32, 3)
CDAC_GLOBAL_STRING(TestGlobalString, "Hello, World!")
CDAC_GLOBAL_POINTER(TestGlobalPointer, (void*)0x12345678)
CDAC_GLOBALS_END()
#undef CDAC_BASELINE
#undef CDAC_TYPES_BEGIN
#undef CDAC_TYPE_BEGIN
#undef CDAC_TYPE_INDETERMINATE
#undef CDAC_TYPE_SIZE
#undef CDAC_TYPE_FIELD
#undef CDAC_TYPE_END
#undef CDAC_TYPES_END
#undef CDAC_GLOBALS_BEGIN
#undef CDAC_GLOBAL
#undef CDAC_GLOBAL_POINTER
#undef CDAC_GLOBAL_STRING
#undef CDAC_GLOBALS_END

View File

@ -142,3 +142,22 @@ GC_Initialize(
*gcHeap = heap;
return S_OK;
}
extern "C"
{
struct DotNetRuntimeContractDescriptor;
extern DotNetRuntimeContractDescriptor GCContractDescriptor;
}
GC_EXPORT
HRESULT LOCALGC_CALLCONV
GC_GetDescriptors(
/* Out */ TADDR* gcDescriptors
)
{
assert(gcDescriptors != nullptr);
*gcDescriptors = (TADDR)&GCContractDescriptor;
return S_OK;
}

View File

@ -1,70 +1,70 @@
project(clrgcsample)
# project(clrgcsample)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
# set(CMAKE_INCLUDE_CURRENT_DIR ON)
include_directories(..)
include_directories(../env)
# include_directories(..)
# include_directories(../env)
set(SOURCES
GCSample.cpp
gcenv.ee.cpp
../gceventstatus.cpp
../gcconfig.cpp
../gccommon.cpp
../gceewks.cpp
../gchandletable.cpp
../gcscan.cpp
../gcwks.cpp
../gcload.cpp
../handletable.cpp
../handletablecache.cpp
../handletablecore.cpp
../handletablescan.cpp
../objecthandle.cpp
../softwarewritewatch.cpp
)
# set(SOURCES
# GCSample.cpp
# gcenv.ee.cpp
# ../gceventstatus.cpp
# ../gcconfig.cpp
# ../gccommon.cpp
# ../gceewks.cpp
# ../gchandletable.cpp
# ../gcscan.cpp
# ../gcwks.cpp
# ../gcload.cpp
# ../handletable.cpp
# ../handletablecache.cpp
# ../handletablecore.cpp
# ../handletablescan.cpp
# ../objecthandle.cpp
# ../softwarewritewatch.cpp
# )
if (CLR_CMAKE_TARGET_ARCH_AMD64 AND CLR_CMAKE_TARGET_WIN32)
set ( SOURCES
${SOURCES}
../vxsort/isa_detection.cpp
../vxsort/do_vxsort_avx2.cpp
../vxsort/do_vxsort_avx512.cpp
../vxsort/machine_traits.avx2.cpp
../vxsort/smallsort/bitonic_sort.AVX2.int64_t.generated.cpp
../vxsort/smallsort/bitonic_sort.AVX2.int32_t.generated.cpp
../vxsort/smallsort/bitonic_sort.AVX512.int64_t.generated.cpp
../vxsort/smallsort/bitonic_sort.AVX512.int32_t.generated.cpp
../vxsort/smallsort/avx2_load_mask_tables.cpp
)
endif (CLR_CMAKE_TARGET_ARCH_AMD64 AND CLR_CMAKE_TARGET_WIN32)
# if (CLR_CMAKE_TARGET_ARCH_AMD64 AND CLR_CMAKE_TARGET_WIN32)
# set ( SOURCES
# ${SOURCES}
# ../vxsort/isa_detection.cpp
# ../vxsort/do_vxsort_avx2.cpp
# ../vxsort/do_vxsort_avx512.cpp
# ../vxsort/machine_traits.avx2.cpp
# ../vxsort/smallsort/bitonic_sort.AVX2.int64_t.generated.cpp
# ../vxsort/smallsort/bitonic_sort.AVX2.int32_t.generated.cpp
# ../vxsort/smallsort/bitonic_sort.AVX512.int64_t.generated.cpp
# ../vxsort/smallsort/bitonic_sort.AVX512.int32_t.generated.cpp
# ../vxsort/smallsort/avx2_load_mask_tables.cpp
# )
# endif (CLR_CMAKE_TARGET_ARCH_AMD64 AND CLR_CMAKE_TARGET_WIN32)
if(CLR_CMAKE_TARGET_WIN32)
set (GC_LINK_LIBRARIES
${STATIC_MT_CRT_LIB}
${STATIC_MT_VCRT_LIB}
kernel32.lib
advapi32.lib
minipal
)
endif(CLR_CMAKE_TARGET_WIN32)
# if(CLR_CMAKE_TARGET_WIN32)
# set (GC_LINK_LIBRARIES
# ${STATIC_MT_CRT_LIB}
# ${STATIC_MT_VCRT_LIB}
# kernel32.lib
# advapi32.lib
# minipal
# )
# endif(CLR_CMAKE_TARGET_WIN32)
add_definitions(-DVERIFY_HEAP)
# add_definitions(-DVERIFY_HEAP)
if(CLR_CMAKE_TARGET_WIN32)
list(APPEND SOURCES
../windows/gcenv.windows.cpp)
add_definitions(-DUNICODE)
add_compile_definitions(NOMINMAX)
else()
list(APPEND SOURCES
../gcenv.unix.cpp)
endif()
# if(CLR_CMAKE_TARGET_WIN32)
# list(APPEND SOURCES
# ../windows/gcenv.windows.cpp)
# add_definitions(-DUNICODE)
# add_compile_definitions(NOMINMAX)
# else()
# list(APPEND SOURCES
# ../gcenv.unix.cpp)
# endif()
add_executable_clr(gcsample
${SOURCES}
)
# add_executable_clr(gcsample
# ${SOURCES}
# )
if(CLR_CMAKE_TARGET_WIN32)
target_link_libraries(gcsample PRIVATE ${GC_LINK_LIBRARIES})
endif()
# if(CLR_CMAKE_TARGET_WIN32)
# target_link_libraries(gcsample PRIVATE ${GC_LINK_LIBRARIES})
# endif()

View File

@ -34,6 +34,8 @@ GPTR_IMPL(IGCHeap, g_pGCHeap);
GcDacVars g_gc_dac_vars;
GPTR_IMPL(GcDacVars, g_gcDacGlobals);
void* g_gcDescriptors = nullptr;
#ifdef FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP
uint8_t* g_write_watch_table = nullptr;
@ -77,6 +79,7 @@ extern "C" HRESULT LOCALGC_CALLCONV GC_Initialize(
/* Out */ IGCHandleManager** gcHandleManager,
/* Out */ GcDacVars* gcDacVars
);
extern "C" HRESULT LOCALGC_CALLCONV GC_GetDescriptors(/* Out */ TADDR* gcDescriptors);
#ifndef DACCESS_COMPILE
@ -343,6 +346,7 @@ HRESULT InitializeDefaultGC()
IGCHeap* heap;
IGCHandleManager* manager;
GC_GetDescriptors((TADDR*)&g_gcDescriptors);
HRESULT initResult = GC_Initialize(nullptr, &heap, &manager, &g_gc_dac_vars);
if (initResult == S_OK)
{

View File

@ -186,6 +186,10 @@ extern GcDacVars g_gc_dac_vars;
typedef DPTR(GcDacVars) PTR_GcDacVars;
GPTR_DECL(GcDacVars, g_gcDacGlobals);
// Global pointer to the cDAC GC descriptors. This is used to provide
// the cDAC with a method of obtaining the currently in use GC's descriptors.
extern void* g_gcDescriptors;
// GCHeapUtilities provides a number of static methods
// that operate on the global heap instance. It can't be
// instantiated.

View File

@ -67,6 +67,8 @@ public static class Constants
public const string OperatingSystem = nameof(OperatingSystem);
public const string GCInfoVersion = nameof(GCInfoVersion);
public const string GCDescriptor = nameof(GCDescriptor);
}
public static class FieldNames
{

View File

@ -1137,6 +1137,12 @@ internal sealed unsafe partial class SOSDacImpl
=> _legacyImpl is not null ? _legacyImpl.GetMethodDescPtrFromFrame(frameAddr, ppMD) : HResults.E_NOTIMPL;
int ISOSDacInterface.GetMethodDescPtrFromIP(ClrDataAddress ip, ClrDataAddress* ppMD)
{
if (ip < 100)
{
TargetPointer gcDescriptor = _target.ReadPointer(_target.ReadGlobalPointer(Constants.Globals.GCDescriptor));
Debug.WriteLine($"GCDescriptor: {gcDescriptor.Value:X}");
}
if (ip == 0 || ppMD == null)
return HResults.E_INVALIDARG;