[NativeAOT] Add cDAC data descriptor infrastructure - #127024

Closed
max-charlamb wants to merge 1 commit into
mainfrom
dev/max-charlamb/nativeaot-datadescriptor
Closed

[NativeAOT] Add cDAC data descriptor infrastructure#127024
max-charlamb wants to merge 1 commit into
mainfrom
dev/max-charlamb/nativeaot-datadescriptor

Conversation

@max-charlamb

Copy link
Copy Markdown
Member

Note

This PR was created with assistance from GitHub Copilot.

Summary

Adds the native cDAC data descriptor infrastructure for NativeAOT, enabling diagnostic tools (cDAC reader, SOS) to inspect NativeAOT runtime state through the same contract-based mechanism used by CoreCLR.

This is the first PR in a stacked pair. The second PR (#126972 replacement) adds the managed type sub-descriptor on top.

Changes

Native data descriptor (datadescriptor.inc)

  • Thread/ThreadStore: Thread state, OS ID, exception tracker, stack bounds, alloc context, transition frame
  • EEAllocContext/GCAllocContext: Allocation pointer, limit, bytes allocated
  • MethodTable (EEType): Flags, base size, related type, vtable slots, interfaces, hash code — with flag constants exposed via cdac_data<> friend pattern
  • ExInfo: Exception linked list traversal
  • RuntimeInstance: ThreadStore pointer
  • Globals: Runtime instance, free object MethodTable, GC bounds, thread state flags, object unmask
  • Contracts: Thread (1001), Exception (1), RuntimeTypeSystem (1001)
  • Sub-descriptors: GC (workstation + server)

Build integration

  • CMake integration using shared clrdatadescriptors.cmake infrastructure
  • Separate GC descriptor targets for workstation and server GC
  • Symbol export via --export-dynamic-symbol in Microsoft.NETCore.Native.targets

Add the native cDAC data descriptor for NativeAOT, enabling diagnostic
tools (cDAC reader, SOS) to inspect NativeAOT runtime state through the
same contract-based mechanism used by CoreCLR.
Includes:
- datadescriptor.inc with Thread, ThreadStore, MethodTable, ExInfo,
EEAllocContext, GCAllocContext, RuntimeInstance types and globals
- CMake integration using shared clrdatadescriptors.cmake infrastructure
- GC sub-descriptor for workstation and server GC
- Contract declarations: Thread (1001), Exception (1), RuntimeTypeSystem (1001)
- Symbol export via --export-dynamic-symbol in build targets
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings April 16, 2026 20:49
@max-charlamb
max-charlamb deleted the dev/max-charlamb/nativeaot-datadescriptor branch April 16, 2026 20:53

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Adds NativeAOT-side cDAC data descriptor generation so diagnostic tools can inspect NativeAOT runtime state via the shared contract-descriptor mechanism (similar to CoreCLR), including build integration and symbol export.

Changes:

  • Introduces a NativeAOT datadescriptor.inc describing key runtime types/globals and supported contracts (plus GC sub-descriptor hook).
  • Adds cdac_data<T> friend-based offset exposure for NativeAOT runtime types (e.g., MethodTable, ThreadStore, RuntimeInstance).
  • Integrates descriptor generation into NativeAOT CMake builds and exports the DotNetRuntimeContractDescriptor symbol from ILC output.

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 4 comments.

Show a summary per file
FileDescription
src/coreclr/nativeaot/Runtime/threadstore.hExposes ThreadStore offsets for descriptor generation via cdac_data<ThreadStore>.
src/coreclr/nativeaot/Runtime/inc/MethodTable.hExposes MethodTable field offsets + flag constants via cdac_data<MethodTable>.
src/coreclr/nativeaot/Runtime/datadescriptor/datadescriptor.incNew NativeAOT data descriptor defining types/globals/contracts and GC sub-descriptor pointer.
src/coreclr/nativeaot/Runtime/datadescriptor/datadescriptor.hNew include aggregator to support offsetof() use in datadescriptor.inc.
src/coreclr/nativeaot/Runtime/datadescriptor/CMakeLists.txtAdds CMake targets that generate contract descriptors and GC descriptors.
src/coreclr/nativeaot/Runtime/RuntimeInstance.hExposes RuntimeInstance offsets via cdac_data<RuntimeInstance>.
src/coreclr/nativeaot/Runtime/Full/CMakeLists.txtLinks the generated descriptor object libraries into Runtime.*GC.
src/coreclr/nativeaot/Runtime/CMakeLists.txtAdds the new datadescriptor/ subdirectory to the NativeAOT runtime build.
src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.targetsExports DotNetRuntimeContractDescriptor from produced binaries when debugger support is enabled.

CDAC_TYPE_FIELD(Thread, T_POINTER, ExceptionTracker, offsetof(RuntimeThreadLocals, m_pExInfoStackHead))
CDAC_TYPE_FIELD(Thread, T_POINTER, CachedStackBase, offsetof(RuntimeThreadLocals, m_pStackHigh))
CDAC_TYPE_FIELD(Thread, T_POINTER, CachedStackLimit, offsetof(RuntimeThreadLocals, m_pStackLow))
CDAC_TYPE_FIELD(Thread, TYPE(RuntimeThreadLocals), RuntimeThreadLocals, offsetof(RuntimeThreadLocals, m_eeAllocContext))

CopilotAIApr 16, 2026

Copy link

Choose a reason for hiding this comment

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

Thread.RuntimeThreadLocals is declared as TYPE(RuntimeThreadLocals) but the offset used is offsetof(RuntimeThreadLocals, m_eeAllocContext), which points into the middle of the RuntimeThreadLocals layout (the alloc context) rather than to the start of the RuntimeThreadLocals subobject. Since Thread is class Thread : private RuntimeThreadLocals, the runtime locals base is at offset 0; this field should be a pointer to that base (typically T_POINTER with offset 0, similar to CoreCLR), otherwise tools will interpret the wrong address as a RuntimeThreadLocals instance.

Suggested change
CDAC_TYPE_FIELD(Thread, TYPE(RuntimeThreadLocals), RuntimeThreadLocals, offsetof(RuntimeThreadLocals, m_eeAllocContext))
CDAC_TYPE_FIELD(Thread, T_POINTER, RuntimeThreadLocals, 0)

Copilot uses AI. Check for mistakes.
Comment on lines +73 to +76
template<> struct cdac_data<ThreadStore>
{
static constexpr size_t FirstThreadLink = offsetof(ThreadStore, m_ThreadList);
};

CopilotAIApr 16, 2026

Copy link

Choose a reason for hiding this comment

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

cdac_data<ThreadStore>::FirstThreadLink is set to offsetof(ThreadStore, m_ThreadList), but m_ThreadList is an SList<Thread> object whose head pointer is the private SList::m_pHead. Using the address of the SList object as though it were the head link relies on m_pHead being at offset 0 (and on empty-base layout), which is a fragile ABI contract for diagnostics. Consider exposing the offset of m_ThreadList.m_pHead explicitly (e.g., by adding a cdac_data<SList<...>>/friend hook or an explicit Thread* head field) so the descriptor doesn't depend on SList layout details.

Copilot uses AI. Check for mistakes.
Comment on lines +15 to +23
add_library(nativeaot_descriptor_interface INTERFACE)
target_include_directories(nativeaot_descriptor_interface INTERFACE
${CMAKE_CURRENT_SOURCE_DIR})
add_dependencies(nativeaot_descriptor_interface Runtime.WorkstationGC)
generate_data_descriptors(
LIBRARY_NAME nativeaot_cdac_contract_descriptor
CONTRACT_NAME "DotNetRuntimeContractDescriptor"
INTERFACE_TARGET nativeaot_descriptor_interface
EXPORT_VISIBLE)

CopilotAIApr 16, 2026

Copy link

Choose a reason for hiding this comment

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

add_dependencies(... Runtime.WorkstationGC) is added in this subdirectory before Runtime.WorkstationGC is defined (it’s created in Runtime/Full/CMakeLists.txt, which is added after this subdir). This will fail CMake configure, and it also risks creating a circular dependency since Runtime.WorkstationGC links against the generated descriptor libraries. Drop these explicit dependencies (linking the descriptor targets into Runtime.*GC is sufficient), or move dependency wiring to a scope where Runtime.WorkstationGC already exists.

Copilot uses AI. Check for mistakes.
${GC_DESCRIPTOR_DIR}
${GC_DIR})
add_dependencies(nativeaot_gc_svr_descriptor_interface Runtime.WorkstationGC)
target_compile_definitions(nativeaot_gc_svr_descriptor_interface INTERFACE -DSERVER_GC)

CopilotAIApr 16, 2026

Copy link

Choose a reason for hiding this comment

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

target_compile_definitions(... INTERFACE -DSERVER_GC) passes a definition string that already includes -D. CMake will add -D itself, producing an invalid define on some generators (e.g., -D-DSERVER_GC). Use SERVER_GC (without the -D prefix).

Suggested change
target_compile_definitions(nativeaot_gc_svr_descriptor_interface INTERFACE -DSERVER_GC)
target_compile_definitions(nativeaot_gc_svr_descriptor_interface INTERFACE SERVER_GC)

Copilot uses AI. Check for mistakes.
@github-actionsgithub-actionsBot locked and limited conversation to collaborators May 17, 2026
Sign up for freeto 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.

2 participants

@max-charlamb
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

[NativeAOT] Add cDAC data descriptor infrastructure - #127024

Closed
max-charlamb wants to merge 1 commit into
mainfrom
dev/max-charlamb/nativeaot-datadescriptor
Closed

[NativeAOT] Add cDAC data descriptor infrastructure#127024
max-charlamb wants to merge 1 commit into
mainfrom
dev/max-charlamb/nativeaot-datadescriptor

Conversation

@max-charlamb

Copy link
Copy Markdown
Member

Note

This PR was created with assistance from GitHub Copilot.

Summary

Adds the native cDAC data descriptor infrastructure for NativeAOT, enabling diagnostic tools (cDAC reader, SOS) to inspect NativeAOT runtime state through the same contract-based mechanism used by CoreCLR.

This is the first PR in a stacked pair. The second PR (#126972 replacement) adds the managed type sub-descriptor on top.

Changes

Native data descriptor (datadescriptor.inc)

  • Thread/ThreadStore: Thread state, OS ID, exception tracker, stack bounds, alloc context, transition frame
  • EEAllocContext/GCAllocContext: Allocation pointer, limit, bytes allocated
  • MethodTable (EEType): Flags, base size, related type, vtable slots, interfaces, hash code — with flag constants exposed via cdac_data<> friend pattern
  • ExInfo: Exception linked list traversal
  • RuntimeInstance: ThreadStore pointer
  • Globals: Runtime instance, free object MethodTable, GC bounds, thread state flags, object unmask
  • Contracts: Thread (1001), Exception (1), RuntimeTypeSystem (1001)
  • Sub-descriptors: GC (workstation + server)

Build integration

  • CMake integration using shared clrdatadescriptors.cmake infrastructure
  • Separate GC descriptor targets for workstation and server GC
  • Symbol export via --export-dynamic-symbol in Microsoft.NETCore.Native.targets

Add the native cDAC data descriptor for NativeAOT, enabling diagnostic
tools (cDAC reader, SOS) to inspect NativeAOT runtime state through the
same contract-based mechanism used by CoreCLR.
Includes:
- datadescriptor.inc with Thread, ThreadStore, MethodTable, ExInfo,
EEAllocContext, GCAllocContext, RuntimeInstance types and globals
- CMake integration using shared clrdatadescriptors.cmake infrastructure
- GC sub-descriptor for workstation and server GC
- Contract declarations: Thread (1001), Exception (1), RuntimeTypeSystem (1001)
- Symbol export via --export-dynamic-symbol in build targets
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings April 16, 2026 20:49
@max-charlamb
max-charlamb deleted the dev/max-charlamb/nativeaot-datadescriptor branch April 16, 2026 20:53

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Adds NativeAOT-side cDAC data descriptor generation so diagnostic tools can inspect NativeAOT runtime state via the shared contract-descriptor mechanism (similar to CoreCLR), including build integration and symbol export.

Changes:

  • Introduces a NativeAOT datadescriptor.inc describing key runtime types/globals and supported contracts (plus GC sub-descriptor hook).
  • Adds cdac_data<T> friend-based offset exposure for NativeAOT runtime types (e.g., MethodTable, ThreadStore, RuntimeInstance).
  • Integrates descriptor generation into NativeAOT CMake builds and exports the DotNetRuntimeContractDescriptor symbol from ILC output.

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 4 comments.

Show a summary per file
FileDescription
src/coreclr/nativeaot/Runtime/threadstore.hExposes ThreadStore offsets for descriptor generation via cdac_data<ThreadStore>.
src/coreclr/nativeaot/Runtime/inc/MethodTable.hExposes MethodTable field offsets + flag constants via cdac_data<MethodTable>.
src/coreclr/nativeaot/Runtime/datadescriptor/datadescriptor.incNew NativeAOT data descriptor defining types/globals/contracts and GC sub-descriptor pointer.
src/coreclr/nativeaot/Runtime/datadescriptor/datadescriptor.hNew include aggregator to support offsetof() use in datadescriptor.inc.
src/coreclr/nativeaot/Runtime/datadescriptor/CMakeLists.txtAdds CMake targets that generate contract descriptors and GC descriptors.
src/coreclr/nativeaot/Runtime/RuntimeInstance.hExposes RuntimeInstance offsets via cdac_data<RuntimeInstance>.
src/coreclr/nativeaot/Runtime/Full/CMakeLists.txtLinks the generated descriptor object libraries into Runtime.*GC.
src/coreclr/nativeaot/Runtime/CMakeLists.txtAdds the new datadescriptor/ subdirectory to the NativeAOT runtime build.
src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.targetsExports DotNetRuntimeContractDescriptor from produced binaries when debugger support is enabled.

CDAC_TYPE_FIELD(Thread, T_POINTER, ExceptionTracker, offsetof(RuntimeThreadLocals, m_pExInfoStackHead))
CDAC_TYPE_FIELD(Thread, T_POINTER, CachedStackBase, offsetof(RuntimeThreadLocals, m_pStackHigh))
CDAC_TYPE_FIELD(Thread, T_POINTER, CachedStackLimit, offsetof(RuntimeThreadLocals, m_pStackLow))
CDAC_TYPE_FIELD(Thread, TYPE(RuntimeThreadLocals), RuntimeThreadLocals, offsetof(RuntimeThreadLocals, m_eeAllocContext))

CopilotAIApr 16, 2026

Copy link

Choose a reason for hiding this comment

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

Thread.RuntimeThreadLocals is declared as TYPE(RuntimeThreadLocals) but the offset used is offsetof(RuntimeThreadLocals, m_eeAllocContext), which points into the middle of the RuntimeThreadLocals layout (the alloc context) rather than to the start of the RuntimeThreadLocals subobject. Since Thread is class Thread : private RuntimeThreadLocals, the runtime locals base is at offset 0; this field should be a pointer to that base (typically T_POINTER with offset 0, similar to CoreCLR), otherwise tools will interpret the wrong address as a RuntimeThreadLocals instance.

Suggested change
CDAC_TYPE_FIELD(Thread, TYPE(RuntimeThreadLocals), RuntimeThreadLocals, offsetof(RuntimeThreadLocals, m_eeAllocContext))
CDAC_TYPE_FIELD(Thread, T_POINTER, RuntimeThreadLocals, 0)

Copilot uses AI. Check for mistakes.
Comment on lines +73 to +76
template<> struct cdac_data<ThreadStore>
{
static constexpr size_t FirstThreadLink = offsetof(ThreadStore, m_ThreadList);
};

CopilotAIApr 16, 2026

Copy link

Choose a reason for hiding this comment

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

cdac_data<ThreadStore>::FirstThreadLink is set to offsetof(ThreadStore, m_ThreadList), but m_ThreadList is an SList<Thread> object whose head pointer is the private SList::m_pHead. Using the address of the SList object as though it were the head link relies on m_pHead being at offset 0 (and on empty-base layout), which is a fragile ABI contract for diagnostics. Consider exposing the offset of m_ThreadList.m_pHead explicitly (e.g., by adding a cdac_data<SList<...>>/friend hook or an explicit Thread* head field) so the descriptor doesn't depend on SList layout details.

Copilot uses AI. Check for mistakes.
Comment on lines +15 to +23
add_library(nativeaot_descriptor_interface INTERFACE)
target_include_directories(nativeaot_descriptor_interface INTERFACE
${CMAKE_CURRENT_SOURCE_DIR})
add_dependencies(nativeaot_descriptor_interface Runtime.WorkstationGC)
generate_data_descriptors(
LIBRARY_NAME nativeaot_cdac_contract_descriptor
CONTRACT_NAME "DotNetRuntimeContractDescriptor"
INTERFACE_TARGET nativeaot_descriptor_interface
EXPORT_VISIBLE)

CopilotAIApr 16, 2026

Copy link

Choose a reason for hiding this comment

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

add_dependencies(... Runtime.WorkstationGC) is added in this subdirectory before Runtime.WorkstationGC is defined (it’s created in Runtime/Full/CMakeLists.txt, which is added after this subdir). This will fail CMake configure, and it also risks creating a circular dependency since Runtime.WorkstationGC links against the generated descriptor libraries. Drop these explicit dependencies (linking the descriptor targets into Runtime.*GC is sufficient), or move dependency wiring to a scope where Runtime.WorkstationGC already exists.

Copilot uses AI. Check for mistakes.
${GC_DESCRIPTOR_DIR}
${GC_DIR})
add_dependencies(nativeaot_gc_svr_descriptor_interface Runtime.WorkstationGC)
target_compile_definitions(nativeaot_gc_svr_descriptor_interface INTERFACE -DSERVER_GC)

CopilotAIApr 16, 2026

Copy link

Choose a reason for hiding this comment

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

target_compile_definitions(... INTERFACE -DSERVER_GC) passes a definition string that already includes -D. CMake will add -D itself, producing an invalid define on some generators (e.g., -D-DSERVER_GC). Use SERVER_GC (without the -D prefix).

Suggested change
target_compile_definitions(nativeaot_gc_svr_descriptor_interface INTERFACE -DSERVER_GC)
target_compile_definitions(nativeaot_gc_svr_descriptor_interface INTERFACE SERVER_GC)

Copilot uses AI. Check for mistakes.
@github-actionsgithub-actionsBot locked and limited conversation to collaborators May 17, 2026
Sign up for freeto 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.

2 participants

@max-charlamb
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

[NativeAOT] Add cDAC data descriptor infrastructure - #127024

Closed
max-charlamb wants to merge 1 commit into
mainfrom
dev/max-charlamb/nativeaot-datadescriptor
Closed

[NativeAOT] Add cDAC data descriptor infrastructure#127024
max-charlamb wants to merge 1 commit into
mainfrom
dev/max-charlamb/nativeaot-datadescriptor

Conversation

@max-charlamb

Copy link
Copy Markdown
Member

Note

This PR was created with assistance from GitHub Copilot.

Summary

Adds the native cDAC data descriptor infrastructure for NativeAOT, enabling diagnostic tools (cDAC reader, SOS) to inspect NativeAOT runtime state through the same contract-based mechanism used by CoreCLR.

This is the first PR in a stacked pair. The second PR (#126972 replacement) adds the managed type sub-descriptor on top.

Changes

Native data descriptor (datadescriptor.inc)

  • Thread/ThreadStore: Thread state, OS ID, exception tracker, stack bounds, alloc context, transition frame
  • EEAllocContext/GCAllocContext: Allocation pointer, limit, bytes allocated
  • MethodTable (EEType): Flags, base size, related type, vtable slots, interfaces, hash code — with flag constants exposed via cdac_data<> friend pattern
  • ExInfo: Exception linked list traversal
  • RuntimeInstance: ThreadStore pointer
  • Globals: Runtime instance, free object MethodTable, GC bounds, thread state flags, object unmask
  • Contracts: Thread (1001), Exception (1), RuntimeTypeSystem (1001)
  • Sub-descriptors: GC (workstation + server)

Build integration

  • CMake integration using shared clrdatadescriptors.cmake infrastructure
  • Separate GC descriptor targets for workstation and server GC
  • Symbol export via --export-dynamic-symbol in Microsoft.NETCore.Native.targets

Add the native cDAC data descriptor for NativeAOT, enabling diagnostic
tools (cDAC reader, SOS) to inspect NativeAOT runtime state through the
same contract-based mechanism used by CoreCLR.
Includes:
- datadescriptor.inc with Thread, ThreadStore, MethodTable, ExInfo,
EEAllocContext, GCAllocContext, RuntimeInstance types and globals
- CMake integration using shared clrdatadescriptors.cmake infrastructure
- GC sub-descriptor for workstation and server GC
- Contract declarations: Thread (1001), Exception (1), RuntimeTypeSystem (1001)
- Symbol export via --export-dynamic-symbol in build targets
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings April 16, 2026 20:49
@max-charlamb
max-charlamb deleted the dev/max-charlamb/nativeaot-datadescriptor branch April 16, 2026 20:53

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Adds NativeAOT-side cDAC data descriptor generation so diagnostic tools can inspect NativeAOT runtime state via the shared contract-descriptor mechanism (similar to CoreCLR), including build integration and symbol export.

Changes:

  • Introduces a NativeAOT datadescriptor.inc describing key runtime types/globals and supported contracts (plus GC sub-descriptor hook).
  • Adds cdac_data<T> friend-based offset exposure for NativeAOT runtime types (e.g., MethodTable, ThreadStore, RuntimeInstance).
  • Integrates descriptor generation into NativeAOT CMake builds and exports the DotNetRuntimeContractDescriptor symbol from ILC output.

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 4 comments.

Show a summary per file
FileDescription
src/coreclr/nativeaot/Runtime/threadstore.hExposes ThreadStore offsets for descriptor generation via cdac_data<ThreadStore>.
src/coreclr/nativeaot/Runtime/inc/MethodTable.hExposes MethodTable field offsets + flag constants via cdac_data<MethodTable>.
src/coreclr/nativeaot/Runtime/datadescriptor/datadescriptor.incNew NativeAOT data descriptor defining types/globals/contracts and GC sub-descriptor pointer.
src/coreclr/nativeaot/Runtime/datadescriptor/datadescriptor.hNew include aggregator to support offsetof() use in datadescriptor.inc.
src/coreclr/nativeaot/Runtime/datadescriptor/CMakeLists.txtAdds CMake targets that generate contract descriptors and GC descriptors.
src/coreclr/nativeaot/Runtime/RuntimeInstance.hExposes RuntimeInstance offsets via cdac_data<RuntimeInstance>.
src/coreclr/nativeaot/Runtime/Full/CMakeLists.txtLinks the generated descriptor object libraries into Runtime.*GC.
src/coreclr/nativeaot/Runtime/CMakeLists.txtAdds the new datadescriptor/ subdirectory to the NativeAOT runtime build.
src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.targetsExports DotNetRuntimeContractDescriptor from produced binaries when debugger support is enabled.

CDAC_TYPE_FIELD(Thread, T_POINTER, ExceptionTracker, offsetof(RuntimeThreadLocals, m_pExInfoStackHead))
CDAC_TYPE_FIELD(Thread, T_POINTER, CachedStackBase, offsetof(RuntimeThreadLocals, m_pStackHigh))
CDAC_TYPE_FIELD(Thread, T_POINTER, CachedStackLimit, offsetof(RuntimeThreadLocals, m_pStackLow))
CDAC_TYPE_FIELD(Thread, TYPE(RuntimeThreadLocals), RuntimeThreadLocals, offsetof(RuntimeThreadLocals, m_eeAllocContext))

CopilotAIApr 16, 2026

Copy link

Choose a reason for hiding this comment

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

Thread.RuntimeThreadLocals is declared as TYPE(RuntimeThreadLocals) but the offset used is offsetof(RuntimeThreadLocals, m_eeAllocContext), which points into the middle of the RuntimeThreadLocals layout (the alloc context) rather than to the start of the RuntimeThreadLocals subobject. Since Thread is class Thread : private RuntimeThreadLocals, the runtime locals base is at offset 0; this field should be a pointer to that base (typically T_POINTER with offset 0, similar to CoreCLR), otherwise tools will interpret the wrong address as a RuntimeThreadLocals instance.

Suggested change
CDAC_TYPE_FIELD(Thread, TYPE(RuntimeThreadLocals), RuntimeThreadLocals, offsetof(RuntimeThreadLocals, m_eeAllocContext))
CDAC_TYPE_FIELD(Thread, T_POINTER, RuntimeThreadLocals, 0)

Copilot uses AI. Check for mistakes.
Comment on lines +73 to +76
template<> struct cdac_data<ThreadStore>
{
static constexpr size_t FirstThreadLink = offsetof(ThreadStore, m_ThreadList);
};

CopilotAIApr 16, 2026

Copy link

Choose a reason for hiding this comment

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

cdac_data<ThreadStore>::FirstThreadLink is set to offsetof(ThreadStore, m_ThreadList), but m_ThreadList is an SList<Thread> object whose head pointer is the private SList::m_pHead. Using the address of the SList object as though it were the head link relies on m_pHead being at offset 0 (and on empty-base layout), which is a fragile ABI contract for diagnostics. Consider exposing the offset of m_ThreadList.m_pHead explicitly (e.g., by adding a cdac_data<SList<...>>/friend hook or an explicit Thread* head field) so the descriptor doesn't depend on SList layout details.

Copilot uses AI. Check for mistakes.
Comment on lines +15 to +23
add_library(nativeaot_descriptor_interface INTERFACE)
target_include_directories(nativeaot_descriptor_interface INTERFACE
${CMAKE_CURRENT_SOURCE_DIR})
add_dependencies(nativeaot_descriptor_interface Runtime.WorkstationGC)
generate_data_descriptors(
LIBRARY_NAME nativeaot_cdac_contract_descriptor
CONTRACT_NAME "DotNetRuntimeContractDescriptor"
INTERFACE_TARGET nativeaot_descriptor_interface
EXPORT_VISIBLE)

CopilotAIApr 16, 2026

Copy link

Choose a reason for hiding this comment

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

add_dependencies(... Runtime.WorkstationGC) is added in this subdirectory before Runtime.WorkstationGC is defined (it’s created in Runtime/Full/CMakeLists.txt, which is added after this subdir). This will fail CMake configure, and it also risks creating a circular dependency since Runtime.WorkstationGC links against the generated descriptor libraries. Drop these explicit dependencies (linking the descriptor targets into Runtime.*GC is sufficient), or move dependency wiring to a scope where Runtime.WorkstationGC already exists.

Copilot uses AI. Check for mistakes.
${GC_DESCRIPTOR_DIR}
${GC_DIR})
add_dependencies(nativeaot_gc_svr_descriptor_interface Runtime.WorkstationGC)
target_compile_definitions(nativeaot_gc_svr_descriptor_interface INTERFACE -DSERVER_GC)

CopilotAIApr 16, 2026

Copy link

Choose a reason for hiding this comment

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

target_compile_definitions(... INTERFACE -DSERVER_GC) passes a definition string that already includes -D. CMake will add -D itself, producing an invalid define on some generators (e.g., -D-DSERVER_GC). Use SERVER_GC (without the -D prefix).

Suggested change
target_compile_definitions(nativeaot_gc_svr_descriptor_interface INTERFACE -DSERVER_GC)
target_compile_definitions(nativeaot_gc_svr_descriptor_interface INTERFACE SERVER_GC)

Copilot uses AI. Check for mistakes.
@github-actionsgithub-actionsBot locked and limited conversation to collaborators May 17, 2026
Sign up for freeto 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.

2 participants

@max-charlamb
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

[NativeAOT] Add cDAC data descriptor infrastructure - #127024

Closed
max-charlamb wants to merge 1 commit into
mainfrom
dev/max-charlamb/nativeaot-datadescriptor
Closed

[NativeAOT] Add cDAC data descriptor infrastructure#127024
max-charlamb wants to merge 1 commit into
mainfrom
dev/max-charlamb/nativeaot-datadescriptor

Conversation

@max-charlamb

Copy link
Copy Markdown
Member

Note

This PR was created with assistance from GitHub Copilot.

Summary

Adds the native cDAC data descriptor infrastructure for NativeAOT, enabling diagnostic tools (cDAC reader, SOS) to inspect NativeAOT runtime state through the same contract-based mechanism used by CoreCLR.

This is the first PR in a stacked pair. The second PR (#126972 replacement) adds the managed type sub-descriptor on top.

Changes

Native data descriptor (datadescriptor.inc)

  • Thread/ThreadStore: Thread state, OS ID, exception tracker, stack bounds, alloc context, transition frame
  • EEAllocContext/GCAllocContext: Allocation pointer, limit, bytes allocated
  • MethodTable (EEType): Flags, base size, related type, vtable slots, interfaces, hash code — with flag constants exposed via cdac_data<> friend pattern
  • ExInfo: Exception linked list traversal
  • RuntimeInstance: ThreadStore pointer
  • Globals: Runtime instance, free object MethodTable, GC bounds, thread state flags, object unmask
  • Contracts: Thread (1001), Exception (1), RuntimeTypeSystem (1001)
  • Sub-descriptors: GC (workstation + server)

Build integration

  • CMake integration using shared clrdatadescriptors.cmake infrastructure
  • Separate GC descriptor targets for workstation and server GC
  • Symbol export via --export-dynamic-symbol in Microsoft.NETCore.Native.targets

Add the native cDAC data descriptor for NativeAOT, enabling diagnostic
tools (cDAC reader, SOS) to inspect NativeAOT runtime state through the
same contract-based mechanism used by CoreCLR.
Includes:
- datadescriptor.inc with Thread, ThreadStore, MethodTable, ExInfo,
EEAllocContext, GCAllocContext, RuntimeInstance types and globals
- CMake integration using shared clrdatadescriptors.cmake infrastructure
- GC sub-descriptor for workstation and server GC
- Contract declarations: Thread (1001), Exception (1), RuntimeTypeSystem (1001)
- Symbol export via --export-dynamic-symbol in build targets
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings April 16, 2026 20:49
@max-charlamb
max-charlamb deleted the dev/max-charlamb/nativeaot-datadescriptor branch April 16, 2026 20:53

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Adds NativeAOT-side cDAC data descriptor generation so diagnostic tools can inspect NativeAOT runtime state via the shared contract-descriptor mechanism (similar to CoreCLR), including build integration and symbol export.

Changes:

  • Introduces a NativeAOT datadescriptor.inc describing key runtime types/globals and supported contracts (plus GC sub-descriptor hook).
  • Adds cdac_data<T> friend-based offset exposure for NativeAOT runtime types (e.g., MethodTable, ThreadStore, RuntimeInstance).
  • Integrates descriptor generation into NativeAOT CMake builds and exports the DotNetRuntimeContractDescriptor symbol from ILC output.

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 4 comments.

Show a summary per file
FileDescription
src/coreclr/nativeaot/Runtime/threadstore.hExposes ThreadStore offsets for descriptor generation via cdac_data<ThreadStore>.
src/coreclr/nativeaot/Runtime/inc/MethodTable.hExposes MethodTable field offsets + flag constants via cdac_data<MethodTable>.
src/coreclr/nativeaot/Runtime/datadescriptor/datadescriptor.incNew NativeAOT data descriptor defining types/globals/contracts and GC sub-descriptor pointer.
src/coreclr/nativeaot/Runtime/datadescriptor/datadescriptor.hNew include aggregator to support offsetof() use in datadescriptor.inc.
src/coreclr/nativeaot/Runtime/datadescriptor/CMakeLists.txtAdds CMake targets that generate contract descriptors and GC descriptors.
src/coreclr/nativeaot/Runtime/RuntimeInstance.hExposes RuntimeInstance offsets via cdac_data<RuntimeInstance>.
src/coreclr/nativeaot/Runtime/Full/CMakeLists.txtLinks the generated descriptor object libraries into Runtime.*GC.
src/coreclr/nativeaot/Runtime/CMakeLists.txtAdds the new datadescriptor/ subdirectory to the NativeAOT runtime build.
src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.targetsExports DotNetRuntimeContractDescriptor from produced binaries when debugger support is enabled.

CDAC_TYPE_FIELD(Thread, T_POINTER, ExceptionTracker, offsetof(RuntimeThreadLocals, m_pExInfoStackHead))
CDAC_TYPE_FIELD(Thread, T_POINTER, CachedStackBase, offsetof(RuntimeThreadLocals, m_pStackHigh))
CDAC_TYPE_FIELD(Thread, T_POINTER, CachedStackLimit, offsetof(RuntimeThreadLocals, m_pStackLow))
CDAC_TYPE_FIELD(Thread, TYPE(RuntimeThreadLocals), RuntimeThreadLocals, offsetof(RuntimeThreadLocals, m_eeAllocContext))

CopilotAIApr 16, 2026

Copy link

Choose a reason for hiding this comment

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

Thread.RuntimeThreadLocals is declared as TYPE(RuntimeThreadLocals) but the offset used is offsetof(RuntimeThreadLocals, m_eeAllocContext), which points into the middle of the RuntimeThreadLocals layout (the alloc context) rather than to the start of the RuntimeThreadLocals subobject. Since Thread is class Thread : private RuntimeThreadLocals, the runtime locals base is at offset 0; this field should be a pointer to that base (typically T_POINTER with offset 0, similar to CoreCLR), otherwise tools will interpret the wrong address as a RuntimeThreadLocals instance.

Suggested change
CDAC_TYPE_FIELD(Thread, TYPE(RuntimeThreadLocals), RuntimeThreadLocals, offsetof(RuntimeThreadLocals, m_eeAllocContext))
CDAC_TYPE_FIELD(Thread, T_POINTER, RuntimeThreadLocals, 0)

Copilot uses AI. Check for mistakes.
Comment on lines +73 to +76
template<> struct cdac_data<ThreadStore>
{
static constexpr size_t FirstThreadLink = offsetof(ThreadStore, m_ThreadList);
};

CopilotAIApr 16, 2026

Copy link

Choose a reason for hiding this comment

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

cdac_data<ThreadStore>::FirstThreadLink is set to offsetof(ThreadStore, m_ThreadList), but m_ThreadList is an SList<Thread> object whose head pointer is the private SList::m_pHead. Using the address of the SList object as though it were the head link relies on m_pHead being at offset 0 (and on empty-base layout), which is a fragile ABI contract for diagnostics. Consider exposing the offset of m_ThreadList.m_pHead explicitly (e.g., by adding a cdac_data<SList<...>>/friend hook or an explicit Thread* head field) so the descriptor doesn't depend on SList layout details.

Copilot uses AI. Check for mistakes.
Comment on lines +15 to +23
add_library(nativeaot_descriptor_interface INTERFACE)
target_include_directories(nativeaot_descriptor_interface INTERFACE
${CMAKE_CURRENT_SOURCE_DIR})
add_dependencies(nativeaot_descriptor_interface Runtime.WorkstationGC)
generate_data_descriptors(
LIBRARY_NAME nativeaot_cdac_contract_descriptor
CONTRACT_NAME "DotNetRuntimeContractDescriptor"
INTERFACE_TARGET nativeaot_descriptor_interface
EXPORT_VISIBLE)

CopilotAIApr 16, 2026

Copy link

Choose a reason for hiding this comment

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

add_dependencies(... Runtime.WorkstationGC) is added in this subdirectory before Runtime.WorkstationGC is defined (it’s created in Runtime/Full/CMakeLists.txt, which is added after this subdir). This will fail CMake configure, and it also risks creating a circular dependency since Runtime.WorkstationGC links against the generated descriptor libraries. Drop these explicit dependencies (linking the descriptor targets into Runtime.*GC is sufficient), or move dependency wiring to a scope where Runtime.WorkstationGC already exists.

Copilot uses AI. Check for mistakes.
${GC_DESCRIPTOR_DIR}
${GC_DIR})
add_dependencies(nativeaot_gc_svr_descriptor_interface Runtime.WorkstationGC)
target_compile_definitions(nativeaot_gc_svr_descriptor_interface INTERFACE -DSERVER_GC)

CopilotAIApr 16, 2026

Copy link

Choose a reason for hiding this comment

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

target_compile_definitions(... INTERFACE -DSERVER_GC) passes a definition string that already includes -D. CMake will add -D itself, producing an invalid define on some generators (e.g., -D-DSERVER_GC). Use SERVER_GC (without the -D prefix).

Suggested change
target_compile_definitions(nativeaot_gc_svr_descriptor_interface INTERFACE -DSERVER_GC)
target_compile_definitions(nativeaot_gc_svr_descriptor_interface INTERFACE SERVER_GC)

Copilot uses AI. Check for mistakes.
@github-actionsgithub-actionsBot locked and limited conversation to collaborators May 17, 2026
Sign up for freeto 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.

2 participants

@max-charlamb
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

[NativeAOT] Add cDAC data descriptor infrastructure - #127024

Closed
max-charlamb wants to merge 1 commit into
mainfrom
dev/max-charlamb/nativeaot-datadescriptor
Closed

[NativeAOT] Add cDAC data descriptor infrastructure#127024
max-charlamb wants to merge 1 commit into
mainfrom
dev/max-charlamb/nativeaot-datadescriptor

Conversation

@max-charlamb

Copy link
Copy Markdown
Member

Note

This PR was created with assistance from GitHub Copilot.

Summary

Adds the native cDAC data descriptor infrastructure for NativeAOT, enabling diagnostic tools (cDAC reader, SOS) to inspect NativeAOT runtime state through the same contract-based mechanism used by CoreCLR.

This is the first PR in a stacked pair. The second PR (#126972 replacement) adds the managed type sub-descriptor on top.

Changes

Native data descriptor (datadescriptor.inc)

  • Thread/ThreadStore: Thread state, OS ID, exception tracker, stack bounds, alloc context, transition frame
  • EEAllocContext/GCAllocContext: Allocation pointer, limit, bytes allocated
  • MethodTable (EEType): Flags, base size, related type, vtable slots, interfaces, hash code — with flag constants exposed via cdac_data<> friend pattern
  • ExInfo: Exception linked list traversal
  • RuntimeInstance: ThreadStore pointer
  • Globals: Runtime instance, free object MethodTable, GC bounds, thread state flags, object unmask
  • Contracts: Thread (1001), Exception (1), RuntimeTypeSystem (1001)
  • Sub-descriptors: GC (workstation + server)

Build integration

  • CMake integration using shared clrdatadescriptors.cmake infrastructure
  • Separate GC descriptor targets for workstation and server GC
  • Symbol export via --export-dynamic-symbol in Microsoft.NETCore.Native.targets

Add the native cDAC data descriptor for NativeAOT, enabling diagnostic
tools (cDAC reader, SOS) to inspect NativeAOT runtime state through the
same contract-based mechanism used by CoreCLR.
Includes:
- datadescriptor.inc with Thread, ThreadStore, MethodTable, ExInfo,
EEAllocContext, GCAllocContext, RuntimeInstance types and globals
- CMake integration using shared clrdatadescriptors.cmake infrastructure
- GC sub-descriptor for workstation and server GC
- Contract declarations: Thread (1001), Exception (1), RuntimeTypeSystem (1001)
- Symbol export via --export-dynamic-symbol in build targets
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings April 16, 2026 20:49
@max-charlamb
max-charlamb deleted the dev/max-charlamb/nativeaot-datadescriptor branch April 16, 2026 20:53

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Adds NativeAOT-side cDAC data descriptor generation so diagnostic tools can inspect NativeAOT runtime state via the shared contract-descriptor mechanism (similar to CoreCLR), including build integration and symbol export.

Changes:

  • Introduces a NativeAOT datadescriptor.inc describing key runtime types/globals and supported contracts (plus GC sub-descriptor hook).
  • Adds cdac_data<T> friend-based offset exposure for NativeAOT runtime types (e.g., MethodTable, ThreadStore, RuntimeInstance).
  • Integrates descriptor generation into NativeAOT CMake builds and exports the DotNetRuntimeContractDescriptor symbol from ILC output.

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 4 comments.

Show a summary per file
FileDescription
src/coreclr/nativeaot/Runtime/threadstore.hExposes ThreadStore offsets for descriptor generation via cdac_data<ThreadStore>.
src/coreclr/nativeaot/Runtime/inc/MethodTable.hExposes MethodTable field offsets + flag constants via cdac_data<MethodTable>.
src/coreclr/nativeaot/Runtime/datadescriptor/datadescriptor.incNew NativeAOT data descriptor defining types/globals/contracts and GC sub-descriptor pointer.
src/coreclr/nativeaot/Runtime/datadescriptor/datadescriptor.hNew include aggregator to support offsetof() use in datadescriptor.inc.
src/coreclr/nativeaot/Runtime/datadescriptor/CMakeLists.txtAdds CMake targets that generate contract descriptors and GC descriptors.
src/coreclr/nativeaot/Runtime/RuntimeInstance.hExposes RuntimeInstance offsets via cdac_data<RuntimeInstance>.
src/coreclr/nativeaot/Runtime/Full/CMakeLists.txtLinks the generated descriptor object libraries into Runtime.*GC.
src/coreclr/nativeaot/Runtime/CMakeLists.txtAdds the new datadescriptor/ subdirectory to the NativeAOT runtime build.
src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.targetsExports DotNetRuntimeContractDescriptor from produced binaries when debugger support is enabled.

CDAC_TYPE_FIELD(Thread, T_POINTER, ExceptionTracker, offsetof(RuntimeThreadLocals, m_pExInfoStackHead))
CDAC_TYPE_FIELD(Thread, T_POINTER, CachedStackBase, offsetof(RuntimeThreadLocals, m_pStackHigh))
CDAC_TYPE_FIELD(Thread, T_POINTER, CachedStackLimit, offsetof(RuntimeThreadLocals, m_pStackLow))
CDAC_TYPE_FIELD(Thread, TYPE(RuntimeThreadLocals), RuntimeThreadLocals, offsetof(RuntimeThreadLocals, m_eeAllocContext))

CopilotAIApr 16, 2026

Copy link

Choose a reason for hiding this comment

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

Thread.RuntimeThreadLocals is declared as TYPE(RuntimeThreadLocals) but the offset used is offsetof(RuntimeThreadLocals, m_eeAllocContext), which points into the middle of the RuntimeThreadLocals layout (the alloc context) rather than to the start of the RuntimeThreadLocals subobject. Since Thread is class Thread : private RuntimeThreadLocals, the runtime locals base is at offset 0; this field should be a pointer to that base (typically T_POINTER with offset 0, similar to CoreCLR), otherwise tools will interpret the wrong address as a RuntimeThreadLocals instance.

Suggested change
CDAC_TYPE_FIELD(Thread, TYPE(RuntimeThreadLocals), RuntimeThreadLocals, offsetof(RuntimeThreadLocals, m_eeAllocContext))
CDAC_TYPE_FIELD(Thread, T_POINTER, RuntimeThreadLocals, 0)

Copilot uses AI. Check for mistakes.
Comment on lines +73 to +76
template<> struct cdac_data<ThreadStore>
{
static constexpr size_t FirstThreadLink = offsetof(ThreadStore, m_ThreadList);
};

CopilotAIApr 16, 2026

Copy link

Choose a reason for hiding this comment

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

cdac_data<ThreadStore>::FirstThreadLink is set to offsetof(ThreadStore, m_ThreadList), but m_ThreadList is an SList<Thread> object whose head pointer is the private SList::m_pHead. Using the address of the SList object as though it were the head link relies on m_pHead being at offset 0 (and on empty-base layout), which is a fragile ABI contract for diagnostics. Consider exposing the offset of m_ThreadList.m_pHead explicitly (e.g., by adding a cdac_data<SList<...>>/friend hook or an explicit Thread* head field) so the descriptor doesn't depend on SList layout details.

Copilot uses AI. Check for mistakes.
Comment on lines +15 to +23
add_library(nativeaot_descriptor_interface INTERFACE)
target_include_directories(nativeaot_descriptor_interface INTERFACE
${CMAKE_CURRENT_SOURCE_DIR})
add_dependencies(nativeaot_descriptor_interface Runtime.WorkstationGC)
generate_data_descriptors(
LIBRARY_NAME nativeaot_cdac_contract_descriptor
CONTRACT_NAME "DotNetRuntimeContractDescriptor"
INTERFACE_TARGET nativeaot_descriptor_interface
EXPORT_VISIBLE)

CopilotAIApr 16, 2026

Copy link

Choose a reason for hiding this comment

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

add_dependencies(... Runtime.WorkstationGC) is added in this subdirectory before Runtime.WorkstationGC is defined (it’s created in Runtime/Full/CMakeLists.txt, which is added after this subdir). This will fail CMake configure, and it also risks creating a circular dependency since Runtime.WorkstationGC links against the generated descriptor libraries. Drop these explicit dependencies (linking the descriptor targets into Runtime.*GC is sufficient), or move dependency wiring to a scope where Runtime.WorkstationGC already exists.

Copilot uses AI. Check for mistakes.
${GC_DESCRIPTOR_DIR}
${GC_DIR})
add_dependencies(nativeaot_gc_svr_descriptor_interface Runtime.WorkstationGC)
target_compile_definitions(nativeaot_gc_svr_descriptor_interface INTERFACE -DSERVER_GC)

CopilotAIApr 16, 2026

Copy link

Choose a reason for hiding this comment

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

target_compile_definitions(... INTERFACE -DSERVER_GC) passes a definition string that already includes -D. CMake will add -D itself, producing an invalid define on some generators (e.g., -D-DSERVER_GC). Use SERVER_GC (without the -D prefix).

Suggested change
target_compile_definitions(nativeaot_gc_svr_descriptor_interface INTERFACE -DSERVER_GC)
target_compile_definitions(nativeaot_gc_svr_descriptor_interface INTERFACE SERVER_GC)

Copilot uses AI. Check for mistakes.
@github-actionsgithub-actionsBot locked and limited conversation to collaborators May 17, 2026
Sign up for freeto 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.

2 participants

@max-charlamb
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

[NativeAOT] Add cDAC data descriptor infrastructure - #127024

Closed
max-charlamb wants to merge 1 commit into
mainfrom
dev/max-charlamb/nativeaot-datadescriptor
Closed

[NativeAOT] Add cDAC data descriptor infrastructure#127024
max-charlamb wants to merge 1 commit into
mainfrom
dev/max-charlamb/nativeaot-datadescriptor

Conversation

@max-charlamb

Copy link
Copy Markdown
Member

Note

This PR was created with assistance from GitHub Copilot.

Summary

Adds the native cDAC data descriptor infrastructure for NativeAOT, enabling diagnostic tools (cDAC reader, SOS) to inspect NativeAOT runtime state through the same contract-based mechanism used by CoreCLR.

This is the first PR in a stacked pair. The second PR (#126972 replacement) adds the managed type sub-descriptor on top.

Changes

Native data descriptor (datadescriptor.inc)

  • Thread/ThreadStore: Thread state, OS ID, exception tracker, stack bounds, alloc context, transition frame
  • EEAllocContext/GCAllocContext: Allocation pointer, limit, bytes allocated
  • MethodTable (EEType): Flags, base size, related type, vtable slots, interfaces, hash code — with flag constants exposed via cdac_data<> friend pattern
  • ExInfo: Exception linked list traversal
  • RuntimeInstance: ThreadStore pointer
  • Globals: Runtime instance, free object MethodTable, GC bounds, thread state flags, object unmask
  • Contracts: Thread (1001), Exception (1), RuntimeTypeSystem (1001)
  • Sub-descriptors: GC (workstation + server)

Build integration

  • CMake integration using shared clrdatadescriptors.cmake infrastructure
  • Separate GC descriptor targets for workstation and server GC
  • Symbol export via --export-dynamic-symbol in Microsoft.NETCore.Native.targets

Add the native cDAC data descriptor for NativeAOT, enabling diagnostic
tools (cDAC reader, SOS) to inspect NativeAOT runtime state through the
same contract-based mechanism used by CoreCLR.
Includes:
- datadescriptor.inc with Thread, ThreadStore, MethodTable, ExInfo,
EEAllocContext, GCAllocContext, RuntimeInstance types and globals
- CMake integration using shared clrdatadescriptors.cmake infrastructure
- GC sub-descriptor for workstation and server GC
- Contract declarations: Thread (1001), Exception (1), RuntimeTypeSystem (1001)
- Symbol export via --export-dynamic-symbol in build targets
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings April 16, 2026 20:49
@max-charlamb
max-charlamb deleted the dev/max-charlamb/nativeaot-datadescriptor branch April 16, 2026 20:53

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Adds NativeAOT-side cDAC data descriptor generation so diagnostic tools can inspect NativeAOT runtime state via the shared contract-descriptor mechanism (similar to CoreCLR), including build integration and symbol export.

Changes:

  • Introduces a NativeAOT datadescriptor.inc describing key runtime types/globals and supported contracts (plus GC sub-descriptor hook).
  • Adds cdac_data<T> friend-based offset exposure for NativeAOT runtime types (e.g., MethodTable, ThreadStore, RuntimeInstance).
  • Integrates descriptor generation into NativeAOT CMake builds and exports the DotNetRuntimeContractDescriptor symbol from ILC output.

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 4 comments.

Show a summary per file
FileDescription
src/coreclr/nativeaot/Runtime/threadstore.hExposes ThreadStore offsets for descriptor generation via cdac_data<ThreadStore>.
src/coreclr/nativeaot/Runtime/inc/MethodTable.hExposes MethodTable field offsets + flag constants via cdac_data<MethodTable>.
src/coreclr/nativeaot/Runtime/datadescriptor/datadescriptor.incNew NativeAOT data descriptor defining types/globals/contracts and GC sub-descriptor pointer.
src/coreclr/nativeaot/Runtime/datadescriptor/datadescriptor.hNew include aggregator to support offsetof() use in datadescriptor.inc.
src/coreclr/nativeaot/Runtime/datadescriptor/CMakeLists.txtAdds CMake targets that generate contract descriptors and GC descriptors.
src/coreclr/nativeaot/Runtime/RuntimeInstance.hExposes RuntimeInstance offsets via cdac_data<RuntimeInstance>.
src/coreclr/nativeaot/Runtime/Full/CMakeLists.txtLinks the generated descriptor object libraries into Runtime.*GC.
src/coreclr/nativeaot/Runtime/CMakeLists.txtAdds the new datadescriptor/ subdirectory to the NativeAOT runtime build.
src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.targetsExports DotNetRuntimeContractDescriptor from produced binaries when debugger support is enabled.

CDAC_TYPE_FIELD(Thread, T_POINTER, ExceptionTracker, offsetof(RuntimeThreadLocals, m_pExInfoStackHead))
CDAC_TYPE_FIELD(Thread, T_POINTER, CachedStackBase, offsetof(RuntimeThreadLocals, m_pStackHigh))
CDAC_TYPE_FIELD(Thread, T_POINTER, CachedStackLimit, offsetof(RuntimeThreadLocals, m_pStackLow))
CDAC_TYPE_FIELD(Thread, TYPE(RuntimeThreadLocals), RuntimeThreadLocals, offsetof(RuntimeThreadLocals, m_eeAllocContext))

CopilotAIApr 16, 2026

Copy link

Choose a reason for hiding this comment

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

Thread.RuntimeThreadLocals is declared as TYPE(RuntimeThreadLocals) but the offset used is offsetof(RuntimeThreadLocals, m_eeAllocContext), which points into the middle of the RuntimeThreadLocals layout (the alloc context) rather than to the start of the RuntimeThreadLocals subobject. Since Thread is class Thread : private RuntimeThreadLocals, the runtime locals base is at offset 0; this field should be a pointer to that base (typically T_POINTER with offset 0, similar to CoreCLR), otherwise tools will interpret the wrong address as a RuntimeThreadLocals instance.

Suggested change
CDAC_TYPE_FIELD(Thread, TYPE(RuntimeThreadLocals), RuntimeThreadLocals, offsetof(RuntimeThreadLocals, m_eeAllocContext))
CDAC_TYPE_FIELD(Thread, T_POINTER, RuntimeThreadLocals, 0)

Copilot uses AI. Check for mistakes.
Comment on lines +73 to +76
template<> struct cdac_data<ThreadStore>
{
static constexpr size_t FirstThreadLink = offsetof(ThreadStore, m_ThreadList);
};

CopilotAIApr 16, 2026

Copy link

Choose a reason for hiding this comment

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

cdac_data<ThreadStore>::FirstThreadLink is set to offsetof(ThreadStore, m_ThreadList), but m_ThreadList is an SList<Thread> object whose head pointer is the private SList::m_pHead. Using the address of the SList object as though it were the head link relies on m_pHead being at offset 0 (and on empty-base layout), which is a fragile ABI contract for diagnostics. Consider exposing the offset of m_ThreadList.m_pHead explicitly (e.g., by adding a cdac_data<SList<...>>/friend hook or an explicit Thread* head field) so the descriptor doesn't depend on SList layout details.

Copilot uses AI. Check for mistakes.
Comment on lines +15 to +23
add_library(nativeaot_descriptor_interface INTERFACE)
target_include_directories(nativeaot_descriptor_interface INTERFACE
${CMAKE_CURRENT_SOURCE_DIR})
add_dependencies(nativeaot_descriptor_interface Runtime.WorkstationGC)
generate_data_descriptors(
LIBRARY_NAME nativeaot_cdac_contract_descriptor
CONTRACT_NAME "DotNetRuntimeContractDescriptor"
INTERFACE_TARGET nativeaot_descriptor_interface
EXPORT_VISIBLE)

CopilotAIApr 16, 2026

Copy link

Choose a reason for hiding this comment

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

add_dependencies(... Runtime.WorkstationGC) is added in this subdirectory before Runtime.WorkstationGC is defined (it’s created in Runtime/Full/CMakeLists.txt, which is added after this subdir). This will fail CMake configure, and it also risks creating a circular dependency since Runtime.WorkstationGC links against the generated descriptor libraries. Drop these explicit dependencies (linking the descriptor targets into Runtime.*GC is sufficient), or move dependency wiring to a scope where Runtime.WorkstationGC already exists.

Copilot uses AI. Check for mistakes.
${GC_DESCRIPTOR_DIR}
${GC_DIR})
add_dependencies(nativeaot_gc_svr_descriptor_interface Runtime.WorkstationGC)
target_compile_definitions(nativeaot_gc_svr_descriptor_interface INTERFACE -DSERVER_GC)

CopilotAIApr 16, 2026

Copy link

Choose a reason for hiding this comment

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

target_compile_definitions(... INTERFACE -DSERVER_GC) passes a definition string that already includes -D. CMake will add -D itself, producing an invalid define on some generators (e.g., -D-DSERVER_GC). Use SERVER_GC (without the -D prefix).

Suggested change
target_compile_definitions(nativeaot_gc_svr_descriptor_interface INTERFACE -DSERVER_GC)
target_compile_definitions(nativeaot_gc_svr_descriptor_interface INTERFACE SERVER_GC)

Copilot uses AI. Check for mistakes.
@github-actionsgithub-actionsBot locked and limited conversation to collaborators May 17, 2026
Sign up for freeto 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.

2 participants

@max-charlamb
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

[NativeAOT] Add cDAC data descriptor infrastructure - #127024

Closed
max-charlamb wants to merge 1 commit into
mainfrom
dev/max-charlamb/nativeaot-datadescriptor
Closed

[NativeAOT] Add cDAC data descriptor infrastructure#127024
max-charlamb wants to merge 1 commit into
mainfrom
dev/max-charlamb/nativeaot-datadescriptor

Conversation

@max-charlamb

Copy link
Copy Markdown
Member

Note

This PR was created with assistance from GitHub Copilot.

Summary

Adds the native cDAC data descriptor infrastructure for NativeAOT, enabling diagnostic tools (cDAC reader, SOS) to inspect NativeAOT runtime state through the same contract-based mechanism used by CoreCLR.

This is the first PR in a stacked pair. The second PR (#126972 replacement) adds the managed type sub-descriptor on top.

Changes

Native data descriptor (datadescriptor.inc)

  • Thread/ThreadStore: Thread state, OS ID, exception tracker, stack bounds, alloc context, transition frame
  • EEAllocContext/GCAllocContext: Allocation pointer, limit, bytes allocated
  • MethodTable (EEType): Flags, base size, related type, vtable slots, interfaces, hash code — with flag constants exposed via cdac_data<> friend pattern
  • ExInfo: Exception linked list traversal
  • RuntimeInstance: ThreadStore pointer
  • Globals: Runtime instance, free object MethodTable, GC bounds, thread state flags, object unmask
  • Contracts: Thread (1001), Exception (1), RuntimeTypeSystem (1001)
  • Sub-descriptors: GC (workstation + server)

Build integration

  • CMake integration using shared clrdatadescriptors.cmake infrastructure
  • Separate GC descriptor targets for workstation and server GC
  • Symbol export via --export-dynamic-symbol in Microsoft.NETCore.Native.targets

Add the native cDAC data descriptor for NativeAOT, enabling diagnostic
tools (cDAC reader, SOS) to inspect NativeAOT runtime state through the
same contract-based mechanism used by CoreCLR.
Includes:
- datadescriptor.inc with Thread, ThreadStore, MethodTable, ExInfo,
EEAllocContext, GCAllocContext, RuntimeInstance types and globals
- CMake integration using shared clrdatadescriptors.cmake infrastructure
- GC sub-descriptor for workstation and server GC
- Contract declarations: Thread (1001), Exception (1), RuntimeTypeSystem (1001)
- Symbol export via --export-dynamic-symbol in build targets
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings April 16, 2026 20:49
@max-charlamb
max-charlamb deleted the dev/max-charlamb/nativeaot-datadescriptor branch April 16, 2026 20:53

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Adds NativeAOT-side cDAC data descriptor generation so diagnostic tools can inspect NativeAOT runtime state via the shared contract-descriptor mechanism (similar to CoreCLR), including build integration and symbol export.

Changes:

  • Introduces a NativeAOT datadescriptor.inc describing key runtime types/globals and supported contracts (plus GC sub-descriptor hook).
  • Adds cdac_data<T> friend-based offset exposure for NativeAOT runtime types (e.g., MethodTable, ThreadStore, RuntimeInstance).
  • Integrates descriptor generation into NativeAOT CMake builds and exports the DotNetRuntimeContractDescriptor symbol from ILC output.

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 4 comments.

Show a summary per file
FileDescription
src/coreclr/nativeaot/Runtime/threadstore.hExposes ThreadStore offsets for descriptor generation via cdac_data<ThreadStore>.
src/coreclr/nativeaot/Runtime/inc/MethodTable.hExposes MethodTable field offsets + flag constants via cdac_data<MethodTable>.
src/coreclr/nativeaot/Runtime/datadescriptor/datadescriptor.incNew NativeAOT data descriptor defining types/globals/contracts and GC sub-descriptor pointer.
src/coreclr/nativeaot/Runtime/datadescriptor/datadescriptor.hNew include aggregator to support offsetof() use in datadescriptor.inc.
src/coreclr/nativeaot/Runtime/datadescriptor/CMakeLists.txtAdds CMake targets that generate contract descriptors and GC descriptors.
src/coreclr/nativeaot/Runtime/RuntimeInstance.hExposes RuntimeInstance offsets via cdac_data<RuntimeInstance>.
src/coreclr/nativeaot/Runtime/Full/CMakeLists.txtLinks the generated descriptor object libraries into Runtime.*GC.
src/coreclr/nativeaot/Runtime/CMakeLists.txtAdds the new datadescriptor/ subdirectory to the NativeAOT runtime build.
src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.targetsExports DotNetRuntimeContractDescriptor from produced binaries when debugger support is enabled.

CDAC_TYPE_FIELD(Thread, T_POINTER, ExceptionTracker, offsetof(RuntimeThreadLocals, m_pExInfoStackHead))
CDAC_TYPE_FIELD(Thread, T_POINTER, CachedStackBase, offsetof(RuntimeThreadLocals, m_pStackHigh))
CDAC_TYPE_FIELD(Thread, T_POINTER, CachedStackLimit, offsetof(RuntimeThreadLocals, m_pStackLow))
CDAC_TYPE_FIELD(Thread, TYPE(RuntimeThreadLocals), RuntimeThreadLocals, offsetof(RuntimeThreadLocals, m_eeAllocContext))

CopilotAIApr 16, 2026

Copy link

Choose a reason for hiding this comment

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

Thread.RuntimeThreadLocals is declared as TYPE(RuntimeThreadLocals) but the offset used is offsetof(RuntimeThreadLocals, m_eeAllocContext), which points into the middle of the RuntimeThreadLocals layout (the alloc context) rather than to the start of the RuntimeThreadLocals subobject. Since Thread is class Thread : private RuntimeThreadLocals, the runtime locals base is at offset 0; this field should be a pointer to that base (typically T_POINTER with offset 0, similar to CoreCLR), otherwise tools will interpret the wrong address as a RuntimeThreadLocals instance.

Suggested change
CDAC_TYPE_FIELD(Thread, TYPE(RuntimeThreadLocals), RuntimeThreadLocals, offsetof(RuntimeThreadLocals, m_eeAllocContext))
CDAC_TYPE_FIELD(Thread, T_POINTER, RuntimeThreadLocals, 0)

Copilot uses AI. Check for mistakes.
Comment on lines +73 to +76
template<> struct cdac_data<ThreadStore>
{
static constexpr size_t FirstThreadLink = offsetof(ThreadStore, m_ThreadList);
};

CopilotAIApr 16, 2026

Copy link

Choose a reason for hiding this comment

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

cdac_data<ThreadStore>::FirstThreadLink is set to offsetof(ThreadStore, m_ThreadList), but m_ThreadList is an SList<Thread> object whose head pointer is the private SList::m_pHead. Using the address of the SList object as though it were the head link relies on m_pHead being at offset 0 (and on empty-base layout), which is a fragile ABI contract for diagnostics. Consider exposing the offset of m_ThreadList.m_pHead explicitly (e.g., by adding a cdac_data<SList<...>>/friend hook or an explicit Thread* head field) so the descriptor doesn't depend on SList layout details.

Copilot uses AI. Check for mistakes.
Comment on lines +15 to +23
add_library(nativeaot_descriptor_interface INTERFACE)
target_include_directories(nativeaot_descriptor_interface INTERFACE
${CMAKE_CURRENT_SOURCE_DIR})
add_dependencies(nativeaot_descriptor_interface Runtime.WorkstationGC)
generate_data_descriptors(
LIBRARY_NAME nativeaot_cdac_contract_descriptor
CONTRACT_NAME "DotNetRuntimeContractDescriptor"
INTERFACE_TARGET nativeaot_descriptor_interface
EXPORT_VISIBLE)

CopilotAIApr 16, 2026

Copy link

Choose a reason for hiding this comment

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

add_dependencies(... Runtime.WorkstationGC) is added in this subdirectory before Runtime.WorkstationGC is defined (it’s created in Runtime/Full/CMakeLists.txt, which is added after this subdir). This will fail CMake configure, and it also risks creating a circular dependency since Runtime.WorkstationGC links against the generated descriptor libraries. Drop these explicit dependencies (linking the descriptor targets into Runtime.*GC is sufficient), or move dependency wiring to a scope where Runtime.WorkstationGC already exists.

Copilot uses AI. Check for mistakes.
${GC_DESCRIPTOR_DIR}
${GC_DIR})
add_dependencies(nativeaot_gc_svr_descriptor_interface Runtime.WorkstationGC)
target_compile_definitions(nativeaot_gc_svr_descriptor_interface INTERFACE -DSERVER_GC)

CopilotAIApr 16, 2026

Copy link

Choose a reason for hiding this comment

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

target_compile_definitions(... INTERFACE -DSERVER_GC) passes a definition string that already includes -D. CMake will add -D itself, producing an invalid define on some generators (e.g., -D-DSERVER_GC). Use SERVER_GC (without the -D prefix).

Suggested change
target_compile_definitions(nativeaot_gc_svr_descriptor_interface INTERFACE -DSERVER_GC)
target_compile_definitions(nativeaot_gc_svr_descriptor_interface INTERFACE SERVER_GC)

Copilot uses AI. Check for mistakes.
@github-actionsgithub-actionsBot locked and limited conversation to collaborators May 17, 2026
Sign up for freeto 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.

2 participants

@max-charlamb
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

[NativeAOT] Add cDAC data descriptor infrastructure - #127024

Closed
max-charlamb wants to merge 1 commit into
mainfrom
dev/max-charlamb/nativeaot-datadescriptor
Closed

[NativeAOT] Add cDAC data descriptor infrastructure#127024
max-charlamb wants to merge 1 commit into
mainfrom
dev/max-charlamb/nativeaot-datadescriptor

Conversation

@max-charlamb

Copy link
Copy Markdown
Member

Note

This PR was created with assistance from GitHub Copilot.

Summary

Adds the native cDAC data descriptor infrastructure for NativeAOT, enabling diagnostic tools (cDAC reader, SOS) to inspect NativeAOT runtime state through the same contract-based mechanism used by CoreCLR.

This is the first PR in a stacked pair. The second PR (#126972 replacement) adds the managed type sub-descriptor on top.

Changes

Native data descriptor (datadescriptor.inc)

  • Thread/ThreadStore: Thread state, OS ID, exception tracker, stack bounds, alloc context, transition frame
  • EEAllocContext/GCAllocContext: Allocation pointer, limit, bytes allocated
  • MethodTable (EEType): Flags, base size, related type, vtable slots, interfaces, hash code — with flag constants exposed via cdac_data<> friend pattern
  • ExInfo: Exception linked list traversal
  • RuntimeInstance: ThreadStore pointer
  • Globals: Runtime instance, free object MethodTable, GC bounds, thread state flags, object unmask
  • Contracts: Thread (1001), Exception (1), RuntimeTypeSystem (1001)
  • Sub-descriptors: GC (workstation + server)

Build integration

  • CMake integration using shared clrdatadescriptors.cmake infrastructure
  • Separate GC descriptor targets for workstation and server GC
  • Symbol export via --export-dynamic-symbol in Microsoft.NETCore.Native.targets

Add the native cDAC data descriptor for NativeAOT, enabling diagnostic
tools (cDAC reader, SOS) to inspect NativeAOT runtime state through the
same contract-based mechanism used by CoreCLR.
Includes:
- datadescriptor.inc with Thread, ThreadStore, MethodTable, ExInfo,
EEAllocContext, GCAllocContext, RuntimeInstance types and globals
- CMake integration using shared clrdatadescriptors.cmake infrastructure
- GC sub-descriptor for workstation and server GC
- Contract declarations: Thread (1001), Exception (1), RuntimeTypeSystem (1001)
- Symbol export via --export-dynamic-symbol in build targets
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings April 16, 2026 20:49
@max-charlamb
max-charlamb deleted the dev/max-charlamb/nativeaot-datadescriptor branch April 16, 2026 20:53

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Adds NativeAOT-side cDAC data descriptor generation so diagnostic tools can inspect NativeAOT runtime state via the shared contract-descriptor mechanism (similar to CoreCLR), including build integration and symbol export.

Changes:

  • Introduces a NativeAOT datadescriptor.inc describing key runtime types/globals and supported contracts (plus GC sub-descriptor hook).
  • Adds cdac_data<T> friend-based offset exposure for NativeAOT runtime types (e.g., MethodTable, ThreadStore, RuntimeInstance).
  • Integrates descriptor generation into NativeAOT CMake builds and exports the DotNetRuntimeContractDescriptor symbol from ILC output.

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 4 comments.

Show a summary per file
FileDescription
src/coreclr/nativeaot/Runtime/threadstore.hExposes ThreadStore offsets for descriptor generation via cdac_data<ThreadStore>.
src/coreclr/nativeaot/Runtime/inc/MethodTable.hExposes MethodTable field offsets + flag constants via cdac_data<MethodTable>.
src/coreclr/nativeaot/Runtime/datadescriptor/datadescriptor.incNew NativeAOT data descriptor defining types/globals/contracts and GC sub-descriptor pointer.
src/coreclr/nativeaot/Runtime/datadescriptor/datadescriptor.hNew include aggregator to support offsetof() use in datadescriptor.inc.
src/coreclr/nativeaot/Runtime/datadescriptor/CMakeLists.txtAdds CMake targets that generate contract descriptors and GC descriptors.
src/coreclr/nativeaot/Runtime/RuntimeInstance.hExposes RuntimeInstance offsets via cdac_data<RuntimeInstance>.
src/coreclr/nativeaot/Runtime/Full/CMakeLists.txtLinks the generated descriptor object libraries into Runtime.*GC.
src/coreclr/nativeaot/Runtime/CMakeLists.txtAdds the new datadescriptor/ subdirectory to the NativeAOT runtime build.
src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.targetsExports DotNetRuntimeContractDescriptor from produced binaries when debugger support is enabled.

CDAC_TYPE_FIELD(Thread, T_POINTER, ExceptionTracker, offsetof(RuntimeThreadLocals, m_pExInfoStackHead))
CDAC_TYPE_FIELD(Thread, T_POINTER, CachedStackBase, offsetof(RuntimeThreadLocals, m_pStackHigh))
CDAC_TYPE_FIELD(Thread, T_POINTER, CachedStackLimit, offsetof(RuntimeThreadLocals, m_pStackLow))
CDAC_TYPE_FIELD(Thread, TYPE(RuntimeThreadLocals), RuntimeThreadLocals, offsetof(RuntimeThreadLocals, m_eeAllocContext))

CopilotAIApr 16, 2026

Copy link

Choose a reason for hiding this comment

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

Thread.RuntimeThreadLocals is declared as TYPE(RuntimeThreadLocals) but the offset used is offsetof(RuntimeThreadLocals, m_eeAllocContext), which points into the middle of the RuntimeThreadLocals layout (the alloc context) rather than to the start of the RuntimeThreadLocals subobject. Since Thread is class Thread : private RuntimeThreadLocals, the runtime locals base is at offset 0; this field should be a pointer to that base (typically T_POINTER with offset 0, similar to CoreCLR), otherwise tools will interpret the wrong address as a RuntimeThreadLocals instance.

Suggested change
CDAC_TYPE_FIELD(Thread, TYPE(RuntimeThreadLocals), RuntimeThreadLocals, offsetof(RuntimeThreadLocals, m_eeAllocContext))
CDAC_TYPE_FIELD(Thread, T_POINTER, RuntimeThreadLocals, 0)

Copilot uses AI. Check for mistakes.
Comment on lines +73 to +76
template<> struct cdac_data<ThreadStore>
{
static constexpr size_t FirstThreadLink = offsetof(ThreadStore, m_ThreadList);
};

CopilotAIApr 16, 2026

Copy link

Choose a reason for hiding this comment

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

cdac_data<ThreadStore>::FirstThreadLink is set to offsetof(ThreadStore, m_ThreadList), but m_ThreadList is an SList<Thread> object whose head pointer is the private SList::m_pHead. Using the address of the SList object as though it were the head link relies on m_pHead being at offset 0 (and on empty-base layout), which is a fragile ABI contract for diagnostics. Consider exposing the offset of m_ThreadList.m_pHead explicitly (e.g., by adding a cdac_data<SList<...>>/friend hook or an explicit Thread* head field) so the descriptor doesn't depend on SList layout details.

Copilot uses AI. Check for mistakes.
Comment on lines +15 to +23
add_library(nativeaot_descriptor_interface INTERFACE)
target_include_directories(nativeaot_descriptor_interface INTERFACE
${CMAKE_CURRENT_SOURCE_DIR})
add_dependencies(nativeaot_descriptor_interface Runtime.WorkstationGC)
generate_data_descriptors(
LIBRARY_NAME nativeaot_cdac_contract_descriptor
CONTRACT_NAME "DotNetRuntimeContractDescriptor"
INTERFACE_TARGET nativeaot_descriptor_interface
EXPORT_VISIBLE)

CopilotAIApr 16, 2026

Copy link

Choose a reason for hiding this comment

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

add_dependencies(... Runtime.WorkstationGC) is added in this subdirectory before Runtime.WorkstationGC is defined (it’s created in Runtime/Full/CMakeLists.txt, which is added after this subdir). This will fail CMake configure, and it also risks creating a circular dependency since Runtime.WorkstationGC links against the generated descriptor libraries. Drop these explicit dependencies (linking the descriptor targets into Runtime.*GC is sufficient), or move dependency wiring to a scope where Runtime.WorkstationGC already exists.

Copilot uses AI. Check for mistakes.
${GC_DESCRIPTOR_DIR}
${GC_DIR})
add_dependencies(nativeaot_gc_svr_descriptor_interface Runtime.WorkstationGC)
target_compile_definitions(nativeaot_gc_svr_descriptor_interface INTERFACE -DSERVER_GC)

CopilotAIApr 16, 2026

Copy link

Choose a reason for hiding this comment

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

target_compile_definitions(... INTERFACE -DSERVER_GC) passes a definition string that already includes -D. CMake will add -D itself, producing an invalid define on some generators (e.g., -D-DSERVER_GC). Use SERVER_GC (without the -D prefix).

Suggested change
target_compile_definitions(nativeaot_gc_svr_descriptor_interface INTERFACE -DSERVER_GC)
target_compile_definitions(nativeaot_gc_svr_descriptor_interface INTERFACE SERVER_GC)

Copilot uses AI. Check for mistakes.
@github-actionsgithub-actionsBot locked and limited conversation to collaborators May 17, 2026
Sign up for freeto 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.

2 participants

@max-charlamb