[cDAC] Implement MarkDebuggerAttach* DacDbi APIs#126794
[cDAC] Implement MarkDebuggerAttach* DacDbi APIs#126794
Conversation
…DacDbi Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/3f4fdba8-737a-48ee-b4de-df5fc4139ae0 Co-authored-by: rcj1 <77995559+rcj1@users.noreply.github.com> Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/3f4fdba8-737a-48ee-b4de-df5fc4139ae0
There was a problem hiding this comment.
Pull request overview
This PR extends the cDAC Debugger contract and the legacy DacDbiImpl surface to support MarkDebuggerAttachPending / MarkDebuggerAttached by writing the appropriate bits into g_CORDebuggerControlFlags, and adds unit test coverage plus documentation updates.
Changes:
- Added
IDebugger.MarkDebuggerAttachPending()andIDebugger.MarkDebuggerAttached(bool)APIs and implemented them inDebugger_1via target-memory writes. - Updated
DacDbiImplto call the cDAC contract implementations (with DEBUG-only legacy cross-validation). - Exposed
g_CORDebuggerControlFlagsvia the CoreCLR data descriptor and added tests/docs for the new flag semantics.
Reviewed changes
Copilot reviewed 8 out of 8 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| src/native/managed/cdac/tests/DebuggerTests.cs | Adds test target plumbing + new unit tests validating control-flag writes. |
| src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/DacDbiImpl.cs | Implements the two DBI methods by calling the cDAC Debugger contract and translating errors to HRESULTs. |
| src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Debugger_1.cs | Adds the flag enum and implements the two new attach APIs by updating CORDebuggerControlFlags. |
| src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Constants.cs | Introduces the new Globals.CORDebuggerControlFlags name constant. |
| src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IDebugger.cs | Extends the contract interface with the two new methods. |
| src/coreclr/vm/datadescriptor/datadescriptor.inc | Exposes g_CORDebuggerControlFlags and adjusts Debugger global gating. |
| src/coreclr/inc/cordbpriv.h | Adds cDAC dependency annotations to DBCF_PENDING_ATTACH / DBCF_ATTACHED. |
| docs/design/datacontracts/Debugger.md | Documents the new APIs, global dependency, and flag behavior. |
|
Tagging subscribers to this area: @steveisok, @tommcdon, @dotnet/dotnet-diag |
This comment has been minimized.
This comment has been minimized.
|
Test helpers tbd in #126595 |
| bool IDebugger.TryGetDebuggerData(out DebuggerData data) | ||
| { | ||
| data = default; | ||
| TargetPointer debuggerPtrPtr = _target.ReadGlobalPointer(Constants.Globals.Debugger); | ||
| if (debuggerPtrPtr == TargetPointer.Null) | ||
| return false; | ||
|
|
||
| TargetPointer debuggerPtr = _target.ReadPointer(debuggerPtrPtr); | ||
| if (debuggerPtr == TargetPointer.Null) | ||
| return false; | ||
|
|
||
| Data.Debugger debugger = _target.ProcessedData.GetOrAdd<Data.Debugger>(debuggerPtr); | ||
| if (debugger.LeftSideInitialized == 0) | ||
| return false; | ||
|
|
||
| data = new DebuggerData(debugger.Defines, debugger.MDStructuresVersion); | ||
| data = new DebuggerData(debugger.LeftSideInitialized != 0, debugger.Defines, debugger.MDStructuresVersion); | ||
| return true; |
There was a problem hiding this comment.
Was there a reason to change the semantics here? If the left side is not initialized, I don't think the data is valid. Can't we use the result of getting the debugger data as a proxy for LeftSideInitialized
There was a problem hiding this comment.
There's a brief window of time where some of the components have been initialized but the left side has not yet been marked as initialized.
runtime/src/coreclr/debug/ee/debugger.cpp
Line 1973 in 1f1f5fd
if (g_pDebugger != NULL) which is a lot of places. In the case where we use this method as a g_pDebugger == NULL check, and don't end up using the data, this means we only have to check exactly what we want - whether g_pDebugger is NULL.
| | --- | --- | --- | | ||
| | `Debugger` | TargetPointer | Address of the pointer to the Debugger instance (`&g_pDebugger`) | | ||
| | `CLRJitAttachState` | TargetPointer | Pointer to the CLR JIT attach state flags | | ||
| | `CORDebuggerControlFlags` | TargetPointer | Pointer to `g_CORDebuggerControlFlags` | |
There was a problem hiding this comment.
Both CLRJitAttachState and CORDebuggerControlFlags have a bunch bits related to attach that look redundant. Is there opportunity to clean this up?
There was a problem hiding this comment.
Well, CLRJitAttachState is inspected here: https://dev.azure.com/devdiv/DevDiv/_git/DebuggerShared?path=/jit/CoreCLRInspector.cpp&version=GBmain&_a=contents&line=11&lineStyle=plain&lineEnd=12&lineStartColumn=1&lineEndColumn=1. Do we need this? @noahfalk @thaystg
There was a problem hiding this comment.
To the best of my knowledge VS still uses this to determine whether to attach a managed or native debugger to the debuggee when launched as a JIT debugger. We could confirm with them that nothing has changed, but most likely yes, we still need this unless we re-negotiate the contract with VS. It would be interesting to see how VS handles JIT attach for a single-file binary. I wouldn't be surprised if the export is missing or VS doesn't recognize it when exported from a different binary name and the result may be that Debugger.Launch() and other VS JIT attach scenarios don't auto-detect managed debugging for single-file apps.
Technically it looks like we could do whatever we wanted with the other bits of CLRJitAttachState so we could merge the globals together as long as the PE export name is "CLRJitAttachState" and the two current CLRJitAttachState bits remain fixed.
My preference would be to leave the two globals separate for clarity, but remove all the dead flags from the CORDebuggerControlFlags field.
There was a problem hiding this comment.
debugging for single-file apps.
The export is there - exported as ordinal:
runtime/src/native/corehost/apphost/static/singlefilehost.def
Lines 10 to 11 in 5da2b01
My preference would be to leave the two globals separate for clarity, but remove all the dead flags from the CORDebuggerControlFlags field.
sounds reasonable
| @@ -22,6 +24,7 @@ The contract depends on the following globals | |||
| | --- | --- | --- | | |||
| | `Debugger` | TargetPointer | Address of the pointer to the Debugger instance (`&g_pDebugger`) | | |||
| | `CLRJitAttachState` | TargetPointer | Pointer to the CLR JIT attach state flags | | |||
There was a problem hiding this comment.
This can use a less misleading name. JIT does not mean Just-In-Time compiler in this name.
There was a problem hiding this comment.
do you have a suggestion of what else to call it? "JIT attach" and "JIT debugging" is standard terminology for this kind of thing used in the runtime code, our public documentation, and in public discussion unrelated to .NET
Would 'DebuggerJITAttachState' help?
There was a problem hiding this comment.
I have not realized that CLRJitAttachState is part of the undocumented public surface. I guess it makes hard to change.
"JIT attach" and "JIT debugging" is standard terminology
Nit: It has multiple names. Windows docs call it "automatic debugging" that is a lot more self-describing.
There was a problem hiding this comment.
I guess it makes hard to change.
I expect only the name in the PE export table matters for existing contract. What we call it in the source or in the cDAC descriptor could be adjusted.
This comment has been minimized.
This comment has been minimized.
Co-authored-by: Jan Kotas <jkotas@microsoft.com>
🤖 Copilot Code Review — PR #126794Note This review was generated by Copilot (Claude Opus 4.6) with additional analysis from Claude Sonnet 4.5. Holistic AssessmentMotivation: This PR implements debugger attach flag methods ( Approach: The change systematically threads Summary: Detailed Findings
|
MarkDebuggerAttachPendingandMarkDebuggerAttachedin cDACDacDbiImplby adding correspondingDebugger_1contract APIs and wiring them to target-memory writes of debugger control flags.