Skip to content

[cDAC] Adds DAC like entrypoint with new COM interface #113899

New issue

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

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

Already on GitHub? Sign in to your account

Merged
merged 34 commits into from
Apr 10, 2025

Conversation

max-charlamb
Copy link
Contributor

@max-charlamb max-charlamb commented Mar 25, 2025

Resolves #112583

New Entrypoint

Will be invoked by SOS as in dotnet/diagnostics#5373

The DAC uses a shim layer to convert the host's ICLRDataTarget into a ICorDebugDataTarget using defines based on the target platform. Previously, the cDAC was only invoked through the DAC and used the ICorDebugDataTarget API.
Now that we depend directly on ICLRDataTarget, it is not possible to get the target's OS configuration. Therefore, I have included a new contract IRuntimeInfo which encapsulates information about the target runtime.

Currently the contract has two methods:

RuntimeInfoArchitecture GetTargetArchitecture();
RuntimeInfoOperatingSystem GetTargetOperatingSystem();

If we decide to store the build id/information in the contract, this would be a logical place to include it.

// Same export name and signature as existing DAC entrypoint
[UnmanagedCallersOnly(EntryPoint = "CLRDataCreateInstance")]
private static unsafe int CLRDataCreateInstance(Guid* pIID, IntPtr /*ICLRDataTarget*/ pLegacyTarget, void** iface);

// Additional entrypoint to allow passing in callback
[UnmanagedCallersOnly(EntryPoint = "CLRDataCreateInstanceWithFallback")]
private static unsafe int CLRDataCreateInstanceWithFallback(Guid* pIID, IntPtr /*ICLRDataTarget*/ pLegacyTarget, IntPtr pLegacyImpl, void** iface);

Data Contract Global Strings

To support passing global strings (for the RuntimeInfo contract), I have modified the data descriptor spec. Previously globals were of the form

[ VALUE | [int], "type name" ]
or
VALUE | [int]

Where the VALUE may be a JSON numeric constant integer or a string containing a signed or unsigned decimal or hex (with prefix 0x or 0X) integer constant.

I have modified VALUE to be less constrained: VALUE may be either a number or a string. JSON numeric constants are always parsed as numbers. JSON strings are always parsed as strings and may additionally parse as a hex (with prefix 0x or 0X) or decimal number.

To fit the new spec, the cDAC data contract implementation was modified in three main:

  • The datadescriptor.h and datadescriptor.cpp in the runtime.
    • Added mechanism CDAC_GLOBAL_STRING(name, value) to pass global strings which are a mapping of a string (name) to string (value). Both strings exist in the existing string pool.
  • The cdac-build-tool which takes the obj file and converts it to a JSON human readable contract.
    • Modified to parse global strings from the obj and properly convert to JSON.
  • The parser inside of cdacreader which reads the JSON into a Target.
    • Modified to parse global strings and allow fetching existing stringy number globals as strings.

With this change existing stringy numbers can be parsed as either a number or a string.

Example:

{
  "globals": {
    "stringValue" : "Hello world",
    "stringyInt" : "1234",
    "stringyHex" : "0x1234",
    "int" : 1234
  }
}
target.ReadGlobalString("stringValue"); // "Hello world"
target.ReadGlobal<ulong>("stringValue"); // Exception!! cannot be parsed as a number

target.ReadGlobalString("stringyInt"); // "1234"
target.ReadGlobal<ulong>("stringyInt"); // 1234

target.ReadGlobalString("stringyHex"); // "0x1234"
target.ReadGlobal<ulong>("stringyHex"); // 4660 (0x1234)

target.ReadGlobalString("int"); // Exception!! no string representation for JSON Numbers
target.ReadGlobal<ulong>("int"); // 1234

Testing

Tested with SOS CDACCompatible tests locally.

@max-charlamb
Copy link
Contributor Author

/azp run runtime-diagnostics

Copy link

Azure Pipelines successfully started running 1 pipeline(s).

Copy link
Contributor

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR removes the dependency on the outdated GetPlatform callback and introduces a new COM interface along with a RuntimeInfo contract to obtain OS/Arch information for DAC functionality. Key changes include:

  • Eliminating GetTargetPlatform callbacks and related Platform property implementations.
  • Adding new COM interfaces (ICLRDataTarget and ICLRContractLocator) and an entrypoint (CLRDataCreateInstance) to support the new data contract.
  • Introducing the RuntimeInfo contract and related factory/configuration changes to fetch target runtime architecture and operating system.

Reviewed Changes

Copilot reviewed 13 out of 17 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
src/tools/StressLogAnalyzer/src/Program.cs Removed GetTargetPlatform callback as the platform info is now provided via the new contract.
src/native/managed/cdacreader/tests/TestPlaceholderTarget.cs Removed the Platform property and added a TryReadGlobal implementation for globals.
src/native/managed/cdacreader/src/Legacy/ICLRData.cs Added new COM interface definitions for ICLRDataTarget and ICLRContractLocator.
src/native/managed/cdacreader/src/Entrypoints.cs Removed getPlatform delegate and introduced CLRDataCreateInstance with updates to error messaging.
src/native/managed/cdacreader/Microsoft.Diagnostics.DataContractReader/ContractDescriptorTarget.cs Removed getTargetPlatform dependency from target creation and reader initialization.
src/native/managed/cdacreader/Microsoft.Diagnostics.DataContractReader/CachingContractRegistry.cs Added a new contract factory mapping for IRuntimeInfo.
src/native/managed/cdacreader/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/Context/IPlatformAgnosticContext.cs Updated platform context retrieval to use the new RuntimeInfo contract.
src/native/managed/cdacreader/Microsoft.Diagnostics.DataContractReader.Abstractions/Target.cs Removed the CorDebugPlatform enum and its Platform property from the target abstraction.
src/native/managed/cdacreader/Microsoft.Diagnostics.DataContractReader.Abstractions/ContractRegistry.cs Added RuntimeInfo access to the contract registry.
docs/design/datacontracts/RuntimeInfo.md Introduced documentation for the new RuntimeInfo contract.
Files not reviewed (4)
  • src/coreclr/debug/daccess/cdac.cpp: Language not supported
  • src/coreclr/debug/runtimeinfo/contracts.jsonc: Language not supported
  • src/coreclr/debug/runtimeinfo/datadescriptor.h: Language not supported
  • src/native/managed/cdacreader/inc/cdac_reader.h: Language not supported

@max-charlamb max-charlamb requested a review from Copilot March 28, 2025 17:38
Copy link
Contributor

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR adds a DAC-like entrypoint with a new COM interface and introduces a new contract (IRuntimeInfo) to encapsulate target runtime information, replacing the previous reliance on the Platform property. Key changes include:

  • Removal of the deprecated GetTargetPlatform callback and the Platform property.
  • Addition of new COM interfaces (ICLRDataTarget and ICLRContractLocator) and corresponding entrypoint (CLRDataCreateInstance).
  • Introduction and integration of the IRuntimeInfo contract and factory, including updates in contract consumption and context determination.

Reviewed Changes

Copilot reviewed 13 out of 17 changed files in this pull request and generated no comments.

Show a summary per file
File Description
src/tools/StressLogAnalyzer/src/Program.cs Removed the obsolete GetTargetPlatform callback to align with the new IRuntimeInfo approach.
src/native/managed/cdacreader/tests/TestPlaceholderTarget.cs Removed the Platform property and added a new TryReadGlobal method for retrieving globals.
src/native/managed/cdacreader/src/Legacy/ICLRData.cs Introduced new COM interface definitions (ICLRDataTarget and ICLRContractLocator).
src/native/managed/cdacreader/src/Entrypoints.cs Updated the entrypoint initialization by removing getPlatform and using the new COM interfaces.
src/native/managed/cdacreader/Microsoft.Diagnostics.DataContractReader/ContractDescriptorTarget.cs Removed getTargetPlatform from the reader and Platform property, reflecting the migration to IRuntimeInfo.
src/native/managed/cdacreader/Microsoft.Diagnostics.DataContractReader/CachingContractRegistry.cs Added a new factory entry for IRuntimeInfo.
src/native/managed/cdacreader/Microsoft.Diagnostics.DataContractReader.Contracts/* Added new contract definitions and factories for RuntimeInfo.
src/native/managed/cdacreader/Microsoft.Diagnostics.DataContractReader.Abstractions/* Removed Platform from Target and added an abstract RuntimeInfo property.
docs/design/datacontracts/RuntimeInfo.md Documented the new RuntimeInfo contract and its APIs.
Files not reviewed (4)
  • src/coreclr/debug/daccess/cdac.cpp: Language not supported
  • src/coreclr/debug/runtimeinfo/contracts.jsonc: Language not supported
  • src/coreclr/debug/runtimeinfo/datadescriptor.h: Language not supported
  • src/native/managed/cdacreader/inc/cdac_reader.h: Language not supported
Comments suppressed due to low confidence (3)

src/native/managed/cdacreader/tests/TestPlaceholderTarget.cs:95

  • Please ensure that the new TryReadGlobal method is adequately covered by unit tests, including cases when the specified global is missing.
public override bool TryReadGlobal<T>(string name, [NotNullWhen(true)] out T? value)

src/native/managed/cdacreader/Microsoft.Diagnostics.DataContractReader.Abstractions/Target.cs:18

  • The Platform property has been removed; ensure that all consumers now reference IRuntimeInfo and its methods for retrieving target OS and architecture.
public abstract CorDebugPlatform Platform { get; }

src/native/managed/cdacreader/src/Entrypoints.cs:16

  • Since the getPlatform callback has been removed to support the new IRuntimeInfo contract, please update any related documentation or error messages to reflect this change.
-        delegate* unmanaged<int*, void*, int> getPlatform,

#error TARGET_{ARCH} define is not recognized by the cDAC. Update this switch and the enum values in IRuntimeInfo.cs
#endif

CDAC_GLOBAL_STRING(RID, RID_STRING)
Copy link
Member

Choose a reason for hiding this comment

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

I have looked at what the contract json looks like. OperatingSystem and Architecture looks good, but the RID is not getting substituted correctly:

"OperatingSystem":["windows","string"],"Architecture":["x64","string"],"RID":["RID_STRING","string"]},

(If it is too hard to pass the RID through, I would be ok with leaving it out for now.)

Copy link
Contributor Author

@max-charlamb max-charlamb Apr 9, 2025

Choose a reason for hiding this comment

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

This shouldn't be an issue to resolve. To stringify the macro expansion (ex: win-x64) instead of the macro name (RID_STRING), a second layer of macro is required to expand before stringifying. For more details see: https://gcc.gnu.org/onlinedocs/gcc-4.8.5/cpp/Stringification.html

I added the second layer but missed actually invoking it instead of calling the stringification operator directly.

// used to stringify the result of a macros expansion
#define STRINGIFY(x) #x

Edit: fixed

@max-charlamb max-charlamb merged commit 7618121 into dotnet:main Apr 10, 2025
148 of 151 checks passed
@github-actions github-actions bot locked and limited conversation to collaborators May 11, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Create cDAC entrypoint same as DAC CLRDataCreateInstance
7 participants