diff --git a/src/coreclr/CMakeLists.txt b/src/coreclr/CMakeLists.txt index 6e9519affb16d1..b1433e14def45b 100644 --- a/src/coreclr/CMakeLists.txt +++ b/src/coreclr/CMakeLists.txt @@ -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) diff --git a/src/coreclr/clrdatadescriptors.cmake b/src/coreclr/clrdatadescriptors.cmake new file mode 100644 index 00000000000000..21f7b1600e830b --- /dev/null +++ b/src/coreclr/clrdatadescriptors.cmake @@ -0,0 +1,82 @@ +# cDAC contract descriptor + +function(generate_data_descriptors) + set(options EXPORT_VISIBLE) + set(oneValueArgs LIBRARY_NAME CONTRACT_FILE CONTRACT_NAME INTERFACE_TARGET) + set(multiValueArgs "") + 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-shared") + set(GENERATED_CDAC_DESCRIPTOR_DIR "${CMAKE_CURRENT_BINARY_DIR}/cdac-${LIBRARY}") + + # configure contract export name + set(POINTER_DATA_NAME ${DATA_DESCRIPTORS_CONTRACT_NAME}PointerData) + set(CONTRACT_NAME ${DATA_DESCRIPTORS_CONTRACT_NAME}) + if (DATA_DESCRIPTORS_EXPORT_VISIBLE) + set(EXPORT_CONTRACT 1) + else() + set(EXPORT_CONTRACT 0) + endif() + 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() + + # inherit definitions, include directories, and dependencies from the INTERFACE target + target_link_libraries(${INTERMEDIARY_LIBRARY} PRIVATE ${DATA_DESCRIPTORS_INTERFACE_TARGET}) + + 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}" $ + DEPENDS ${INTERMEDIARY_LIBRARY} ${DATA_DESCRIPTORS_DEPENDENCIES} $ "${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 + # ${CONTRACT_NAME} 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}) + + target_include_directories(${LIBRARY} PRIVATE ${GENERATED_CDAC_DESCRIPTOR_DIR}) + + # inherit definitions, include directories, and dependencies from the INTERFACE target + target_link_libraries(${LIBRARY} PRIVATE ${DATA_DESCRIPTORS_INTERFACE_TARGET}) + endif() +endfunction(generate_data_descriptors) diff --git a/src/coreclr/debug/datadescriptor-shared/README.md b/src/coreclr/debug/datadescriptor-shared/README.md new file mode 100644 index 00000000000000..b0bb9e8e3dc1d3 --- /dev/null +++ b/src/coreclr/debug/datadescriptor-shared/README.md @@ -0,0 +1,99 @@ +# Datadescriptor Implementation Infrastructure + +This folder contains infrastructure to create data descriptors as defined in the [data_descriptor.md](../../../../docs/design/datacontracts/data_descriptor.md). Data descriptors enable diagnostic tooling (debuggers, profilers, etc.) to understand the internal layout and structure of .NET runtime objects without requiring intimate knowledge of implementation details. + +## CMake Integration and Build System + +### Function Parameters + +The `generate_data_descriptors` function defined in `clrdatadescriptors.cmake` takes the following arguments: + +* **`LIBRARY_NAME`** (Required) - Sets the name of the target object being created +* **`CONTRACT_FILE`** (Required) - Path to the contract JSON file defining supported contracts +* **`CONTRACT_NAME`** (Required) - Name of the `ContractDescriptor` export symbol +* **`INTERFACE_TARGET`** (Required) - Interface target providing dependencies, include directories, and definitions +* **`EXPORT_VISIBLE`** (Optional) - Controls if the `CONTRACT_NAME` will be exported from the DLL + +### Two-Phase Build Process + +The build system uses a two-phase approach: + +**Phase 1: Intermediary Library** +- Compiles `datadescriptor.cpp` with your `datadescriptor.h` and `datadescriptor.inc` +- Creates object files that the `cdac-build-tool` can analyze +- Extracts type layout information and generates string pools + +**Phase 2: Contract Descriptor Generation** +- Runs `cdac-build-tool` to process the intermediary object files +- Generates the final contract descriptor C source file +- Compiles this into the final library that gets linked into the runtime + + +## Macro Reference + +### Structure Definition Macros + +**`CDAC_BASELINE("identifier")`** +- Specifies the baseline data contract version +- Use `"empty"` for new descriptors +- Must appear before any other content + +**`CDAC_TYPES_BEGIN()` / `CDAC_TYPES_END()`** +- Delimits the type definitions section +- Must contain all `CDAC_TYPE_*` macros + +**`CDAC_TYPE_BEGIN(typeName)`** +- Starts a new type definition +- `typeName` must be globally unique within the descriptor + +**`CDAC_TYPE_SIZE(sizeInBytes)`** +- Specifies the type has a determinate size +- Usually `sizeof(YourNativeType)` + +**`CDAC_TYPE_INDETERMINATE(typeName)`** +- Specifies the type has indeterminate size +- Alternative to `CDAC_TYPE_SIZE` + +**`CDAC_TYPE_FIELD(typeName, fieldType, fieldName, offset)`** +- Defines a field within the type +- `fieldType`: primitive type or another defined type +- `fieldName`: diagnostic-friendly name (use managed names for managed types) +- `offset`: byte offset, usually `offsetof()` or `cdac_data::FieldName` + +**`CDAC_TYPE_END(typeName)`** +- Closes the type definition +- `typeName` must match the corresponding `CDAC_TYPE_BEGIN` + +### Global Value Macros + +**`CDAC_GLOBALS_BEGIN()` / `CDAC_GLOBALS_END()`** +- Delimits the global values section + +**`CDAC_GLOBAL(globalName, typeName, value)`** +- Defines a global literal value +- `value` must be a compile-time constant +- `typeName` can be a primitive type or defined type + +**`CDAC_GLOBAL_POINTER(globalName, address)`** +- Defines a global pointer value +- `address` must be a compile-time constant pointer or `uintptr_t` + +**`CDAC_GLOBAL_STRING(globalName, stringValue)`** +- Defines a global string value +- `stringValue` must be a compile-time string literal + + +## Current Implementation + +For reference, see the current implementation in: +- **`src/coreclr/vm/datadescriptor/`** - Complete real-world implementation + - `datadescriptor.h` - Headers and includes + - `datadescriptor.inc` - Full type definitions for runtime objects + - `contracts.jsonc` - Contract definitions + - `CMakeLists.txt` - Build integration + +## Related Documentation + +- **[Data Contracts Design](../../../../docs/design/datacontracts/datacontracts_design.md)** - Overall design and motivation +- **[Contract Descriptor](../../../../docs/design/datacontracts/contract-descriptor.md)** - Binary format specification +- **[Data Descriptor](../../../../docs/design/datacontracts/data_descriptor.md)** - Logical format specification diff --git a/src/coreclr/debug/runtimeinfo/contract-descriptor.c.in b/src/coreclr/debug/datadescriptor-shared/contract-descriptor.c.in similarity index 66% rename from src/coreclr/debug/runtimeinfo/contract-descriptor.c.in rename to src/coreclr/debug/datadescriptor-shared/contract-descriptor.c.in index c1f0edd7a66f9c..a728afc10dcb33 100644 --- a/src/coreclr/debug/runtimeinfo/contract-descriptor.c.in +++ b/src/coreclr/debug/datadescriptor-shared/contract-descriptor.c.in @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. #include +#include "contractconfiguration.h" #ifdef _MSC_VER #define DLLEXPORT __declspec(dllexport) @@ -9,7 +10,7 @@ #define DLLEXPORT __attribute__((visibility("default"))) #endif -struct DotNetRuntimeContractDescriptor +struct ContractDescriptor { uint64_t magic; uint32_t flags; @@ -20,15 +21,18 @@ struct DotNetRuntimeContractDescriptor const uintptr_t *pointer_data; }; -extern const uintptr_t contractDescriptorPointerData[]; +// POINTER_DATA_NAME and CONTRACT_NAME are macros provided by +// contractconfiguration.h which is configured by CMake +extern const uintptr_t POINTER_DATA_NAME[]; -DLLEXPORT struct DotNetRuntimeContractDescriptor DotNetRuntimeContractDescriptor; - -DLLEXPORT struct DotNetRuntimeContractDescriptor DotNetRuntimeContractDescriptor = { +#if EXPORT_CONTRACT +DLLEXPORT +#endif // EXPORT_CONTRACT +struct ContractDescriptor CONTRACT_NAME = { .magic = 0x0043414443434e44ull, // "DNCCDAC\0" .flags = %%platformFlags%%, .descriptor_size = %%jsonDescriptorSize%%, .descriptor = "%%jsonDescriptor%%", .pointer_data_count = %%pointerDataCount%%, - .pointer_data = &contractDescriptorPointerData[0], + .pointer_data = &POINTER_DATA_NAME[0], }; diff --git a/src/coreclr/debug/datadescriptor-shared/contractconfiguration.h.in b/src/coreclr/debug/datadescriptor-shared/contractconfiguration.h.in new file mode 100644 index 00000000000000..e38f320a8de5ac --- /dev/null +++ b/src/coreclr/debug/datadescriptor-shared/contractconfiguration.h.in @@ -0,0 +1,6 @@ +#pragma once + +#define POINTER_DATA_NAME @POINTER_DATA_NAME@ +#define CONTRACT_NAME @CONTRACT_NAME@ + +#define EXPORT_CONTRACT @EXPORT_CONTRACT@ diff --git a/src/coreclr/debug/runtimeinfo/contractdescriptorstub.c b/src/coreclr/debug/datadescriptor-shared/contractdescriptorstub.c similarity index 66% rename from src/coreclr/debug/runtimeinfo/contractdescriptorstub.c rename to src/coreclr/debug/datadescriptor-shared/contractdescriptorstub.c index 59421a6692d2a7..6bcabd2c829618 100644 --- a/src/coreclr/debug/runtimeinfo/contractdescriptorstub.c +++ b/src/coreclr/debug/datadescriptor-shared/contractdescriptorstub.c @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. #include +#include "contractconfiguration.h" #ifdef _MSC_VER #define DLLEXPORT __declspec(dllexport) @@ -9,7 +10,7 @@ #define DLLEXPORT __attribute__((visibility("default"))) #endif -struct DotNetRuntimeContractDescriptor +struct ContractDescriptor { uint64_t magic; uint32_t flags; @@ -20,20 +21,22 @@ struct DotNetRuntimeContractDescriptor const uintptr_t *pointer_data; }; -extern const uintptr_t contractDescriptorPointerData[]; +// POINTER_DATA_NAME and CONTRACT_NAME are macros provided by +// contractconfiguration.h which is configured by CMake +extern const uintptr_t POINTER_DATA_NAME[]; // just the placeholder pointer -const uintptr_t contractDescriptorPointerData[] = { (uintptr_t)0 }; +const uintptr_t POINTER_DATA_NAME[] = { (uintptr_t)0 }; -DLLEXPORT struct DotNetRuntimeContractDescriptor DotNetRuntimeContractDescriptor; +DLLEXPORT struct ContractDescriptor CONTRACT_NAME; #define STUB_DESCRIPTOR "{\"version\":0,\"baseline\":\"empty\",\"contracts\":{},\"types\":{},\"globals\":{}}" -DLLEXPORT struct DotNetRuntimeContractDescriptor DotNetRuntimeContractDescriptor = { +DLLEXPORT struct ContractDescriptor 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_DATA_NAME[0], }; diff --git a/src/coreclr/debug/runtimeinfo/contractpointerdata.cpp b/src/coreclr/debug/datadescriptor-shared/contractpointerdata.cpp similarity index 54% rename from src/coreclr/debug/runtimeinfo/contractpointerdata.cpp rename to src/coreclr/debug/datadescriptor-shared/contractpointerdata.cpp index 1848b1fb69d898..9e1c9929aa41df 100644 --- a/src/coreclr/debug/runtimeinfo/contractpointerdata.cpp +++ b/src/coreclr/debug/datadescriptor-shared/contractpointerdata.cpp @@ -1,24 +1,18 @@ // 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 -#include - -#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_DATA_NAME[]; -const uintptr_t contractDescriptorPointerData[] = { +const uintptr_t POINTER_DATA_NAME[] = { (uintptr_t)0, // placeholder #define CDAC_GLOBAL_POINTER(name,value) (uintptr_t)(value), -#include "datadescriptor.inc" +#define CDAC_GLOBAL_SUB_DESCRIPTOR(name,value) (uintptr_t)(value), +#include "wrappeddatadescriptor.inc" }; - } diff --git a/src/coreclr/debug/runtimeinfo/datadescriptor.cpp b/src/coreclr/debug/datadescriptor-shared/datadescriptor.cpp similarity index 94% rename from src/coreclr/debug/runtimeinfo/datadescriptor.cpp rename to src/coreclr/debug/datadescriptor-shared/datadescriptor.cpp index 0efae1ad25089f..0e3332539df9ec 100644 --- a/src/coreclr/debug/runtimeinfo/datadescriptor.cpp +++ b/src/coreclr/debug/datadescriptor-shared/datadescriptor.cpp @@ -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 -#include - -#include "static_assert.h" - -#include -#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 @@ -89,7 +70,7 @@ struct CDacStringPoolSizes #define CDAC_GLOBAL_POINTER(name,value) DECL_LEN(MAKE_GLOBALLEN_NAME(name), sizeof(#name)) #define CDAC_GLOBAL(name,tyname,value) DECL_LEN(MAKE_GLOBALLEN_NAME(name), sizeof(#name)) \ DECL_LEN(MAKE_GLOBALTYPELEN_NAME(name), sizeof(#tyname)) -#include "datadescriptor.inc" +#include "wrappeddatadescriptor.inc" char cdac_string_pool_trailing_nil; #undef DECL_LEN }; @@ -107,7 +88,7 @@ enum CDacBlobTypesCount = #define CDAC_TYPES_BEGIN() 0 #define CDAC_TYPE_BEGIN(name) + 1 -#include "datadescriptor.inc" +#include "wrappeddatadescriptor.inc" }; // count the field pool size. @@ -118,7 +99,7 @@ enum #define CDAC_TYPES_BEGIN() 1 #define CDAC_TYPE_FIELD(tyname,membertyname,membername,offset) + 1 #define CDAC_TYPE_END(name) + 1 -#include "datadescriptor.inc" +#include "wrappeddatadescriptor.inc" }; // count the literal globals @@ -127,7 +108,7 @@ enum CDacBlobGlobalLiteralsCount = #define CDAC_GLOBALS_BEGIN() 0 #define CDAC_GLOBAL(name,tyname,value) + 1 -#include "datadescriptor.inc" +#include "wrappeddatadescriptor.inc" }; // count the aux vector globals @@ -136,7 +117,7 @@ enum CDacBlobGlobalPointersCount = #define CDAC_GLOBALS_BEGIN() 0 #define CDAC_GLOBAL_POINTER(name,value) + 1 -#include "datadescriptor.inc" +#include "wrappeddatadescriptor.inc" }; // count the global strings @@ -145,7 +126,7 @@ enum CDacBlobGlobalStringsCount = #define CDAC_GLOBALS_BEGIN() 0 #define CDAC_GLOBAL_STRING(name,value) + 1 -#include "datadescriptor.inc" +#include "wrappeddatadescriptor.inc" }; @@ -175,7 +156,7 @@ struct CDacFieldsPoolSizes #define CDAC_TYPE_FIELD(tyname,membertyname,membername,offset) DECL_LEN(CONCAT4(cdac_fields_pool_member__, tyname, __, membername)) #define CDAC_TYPE_END(name) DECL_LEN(CONCAT4(cdac_fields_pool_member__, tyname, _, endmarker)) \ } MAKE_TYPEFIELDS_TYNAME(name); -#include "datadescriptor.inc" +#include "wrappeddatadescriptor.inc" #undef DECL_LEN }; @@ -197,7 +178,7 @@ struct CDacGlobalPointerIndex #define DECL_LEN(membername) char membername; #define CDAC_GLOBALS_BEGIN() DECL_LEN(cdac_global_pointer_index_start_placeholder__) #define CDAC_GLOBAL_POINTER(name,value) DECL_LEN(CONCAT(cdac_global_pointer_index__, name)) -#include "datadescriptor.inc" +#include "wrappeddatadescriptor.inc" #undef DECL_LEN }; @@ -295,7 +276,7 @@ struct MagicAndBlob BlobDataDescriptor = { #define CDAC_TYPE_INDETERMINATE(name) /*.Size = */ 0, #define CDAC_TYPE_SIZE(size) /* .Size = */ size, #define CDAC_TYPE_END(name) }, -#include "datadescriptor.inc" +#include "wrappeddatadescriptor.inc" }, /* .FieldsPool = */ { @@ -306,22 +287,22 @@ struct MagicAndBlob BlobDataDescriptor = { /* .FieldOffset = */ offset, \ }, #define CDAC_TYPE_END(name) { 0, }, -#include "datadescriptor.inc" +#include "wrappeddatadescriptor.inc" }, /* .GlobalLiteralValues = */ { #define CDAC_GLOBAL(name,tyname,value) { /*.Name = */ GET_GLOBAL_NAME(name), /* .TypeName = */ GET_GLOBALTYPE_NAME(name), /* .Value = */ value }, -#include "datadescriptor.inc" +#include "wrappeddatadescriptor.inc" }, /* .GlobalPointerValues = */ { #define CDAC_GLOBAL_POINTER(name,value) { /* .Name = */ GET_GLOBAL_NAME(name), /* .PointerDataIndex = */ GET_GLOBAL_POINTER_INDEX(name) }, -#include "datadescriptor.inc" +#include "wrappeddatadescriptor.inc" }, /* .GlobalStringValues = */ { #define CDAC_GLOBAL_STRING(name,value) { /* .Name = */ GET_GLOBAL_NAME(name), /* .Value = */ GET_GLOBALSTRING_VALUE(name) }, -#include "datadescriptor.inc" +#include "wrappeddatadescriptor.inc" }, /* .NamesPool = */ ("\0" // starts with a nul @@ -331,7 +312,7 @@ struct MagicAndBlob BlobDataDescriptor = { #define CDAC_GLOBAL_STRING(name,value) #name "\0" STRINGIFY(value) "\0" #define CDAC_GLOBAL_POINTER(name,value) #name "\0" #define CDAC_GLOBAL(name,tyname,value) #name "\0" #tyname "\0" -#include "datadescriptor.inc" +#include "wrappeddatadescriptor.inc" ), /* .EndMagic = */ { 0x01, 0x02, 0x03, 0x04 }, diff --git a/src/coreclr/debug/datadescriptor-shared/wrappeddatadescriptor.inc b/src/coreclr/debug/datadescriptor-shared/wrappeddatadescriptor.inc new file mode 100644 index 00000000000000..7500ac93388803 --- /dev/null +++ b/src/coreclr/debug/datadescriptor-shared/wrappeddatadescriptor.inc @@ -0,0 +1,61 @@ +// 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. +// Wraps datadescriptor.inc to define and undefine macros used in the file. + +#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 + +#include "datadescriptor.inc" + +#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 diff --git a/src/coreclr/debug/runtimeinfo/CMakeLists.txt b/src/coreclr/debug/runtimeinfo/CMakeLists.txt index 1d0abd332c6011..a31d4b6f9812c3 100644 --- a/src/coreclr/debug/runtimeinfo/CMakeLists.txt +++ b/src/coreclr/debug/runtimeinfo/CMakeLists.txt @@ -38,67 +38,3 @@ endif() # publish runtimeinfo lib install_clr(TARGETS runtimeinfo DESTINATIONS lib COMPONENT runtime) - - -# cDAC contract 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 - - 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}" $ - DEPENDS cdac_data_descriptor cee_wks_core $ "${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() diff --git a/src/coreclr/vm/CMakeLists.txt b/src/coreclr/vm/CMakeLists.txt index 07a5a36ab39e80..37f1a76d4f73a3 100644 --- a/src/coreclr/vm/CMakeLists.txt +++ b/src/coreclr/vm/CMakeLists.txt @@ -1013,3 +1013,5 @@ add_subdirectory(wks) if(FEATURE_PERFTRACING) add_subdirectory(eventing) endif(FEATURE_PERFTRACING) + +add_subdirectory(datadescriptor) diff --git a/src/coreclr/debug/runtimeinfo/.editorconfig b/src/coreclr/vm/datadescriptor/.editorconfig similarity index 100% rename from src/coreclr/debug/runtimeinfo/.editorconfig rename to src/coreclr/vm/datadescriptor/.editorconfig diff --git a/src/coreclr/vm/datadescriptor/CMakeLists.txt b/src/coreclr/vm/datadescriptor/CMakeLists.txt new file mode 100644 index 00000000000000..3114d94b23d3b7 --- /dev/null +++ b/src/coreclr/vm/datadescriptor/CMakeLists.txt @@ -0,0 +1,18 @@ +# cDAC contract 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) + +add_library(runtime_descriptor_interface INTERFACE) +target_include_directories(runtime_descriptor_interface INTERFACE + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_BINARY_DIR}) +add_dependencies(runtime_descriptor_interface cee_wks_core) +generate_data_descriptors( + LIBRARY_NAME cdac_contract_descriptor + CONTRACT_FILE "${CMAKE_CURRENT_SOURCE_DIR}/contracts.jsonc" + CONTRACT_NAME "DotNetRuntimeContractDescriptor" + INTERFACE_TARGET runtime_descriptor_interface + EXPORT_VISIBLE) diff --git a/src/coreclr/debug/runtimeinfo/configure.h.in b/src/coreclr/vm/datadescriptor/configure.h.in similarity index 100% rename from src/coreclr/debug/runtimeinfo/configure.h.in rename to src/coreclr/vm/datadescriptor/configure.h.in diff --git a/src/coreclr/debug/runtimeinfo/contracts.jsonc b/src/coreclr/vm/datadescriptor/contracts.jsonc similarity index 100% rename from src/coreclr/debug/runtimeinfo/contracts.jsonc rename to src/coreclr/vm/datadescriptor/contracts.jsonc diff --git a/src/coreclr/vm/datadescriptor/datadescriptor.h b/src/coreclr/vm/datadescriptor/datadescriptor.h new file mode 100644 index 00000000000000..84adff2a49b4d3 --- /dev/null +++ b/src/coreclr/vm/datadescriptor/datadescriptor.h @@ -0,0 +1,24 @@ +// 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 +#include + +#include "static_assert.h" + +#include +#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 diff --git a/src/coreclr/debug/runtimeinfo/datadescriptor.inc b/src/coreclr/vm/datadescriptor/datadescriptor.inc similarity index 92% rename from src/coreclr/debug/runtimeinfo/datadescriptor.inc rename to src/coreclr/vm/datadescriptor/datadescriptor.inc index 250ac0f4f9a95b..167c581cf9e2d3 100644 --- a/src/coreclr/debug/runtimeinfo/datadescriptor.inc +++ b/src/coreclr/vm/datadescriptor/datadescriptor.inc @@ -2,108 +2,10 @@ // 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() -// ... ... -// CDAC_TYPES_END() -// CDAC_GLOBALS_BEGIN() -// ... ... -// CDAC_GLOBALS_END() -// -// In 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 and provides a specialization of cdac_data with a public constexpr -// size_t member that holds the offset: -// -// class MyClass { -// private: -// void* m_myField; -// friend template cdac_data; -// }; -// template<> struct cdac_data { -// 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::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 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() @@ -1018,17 +920,3 @@ CDAC_GLOBAL_POINTER(ExecutionManagerCodeRangeMapAddress, cdac_data