Skip to content

Commit ef0d0bc

Browse files
barosiakCopilotCopilot
authored
[cDAC] Implement SetCompilerFlags for cDAC (#127244)
### Summary Implement SetCompilerFlags in cDAC DacDbiImpl using ILoader contract to set debugger assembly control flags, using a post-write EnC capability check instead of native DAC's pre-write one. ### Changes - DacDbiImpl.cs - SetCompilerFlags implementation - CorDbHResults.cs - Add CORDBG_S_NOT_ALL_BITS_SET success HRESULT - LoaderTests.cs - Add 8 test cases covering both flags set/unset, EnC-not-capable, and JIT opts toggling across architectures --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
1 parent fbb7705 commit ef0d0bc

12 files changed

Lines changed: 347 additions & 3 deletions

File tree

docs/design/datacontracts/Loader.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ enum DebuggerAssemblyControlFlags : uint
119119
DACF_NONE = 0x00,
120120
DACF_ALLOW_JIT_OPTS = 0x02,
121121
DACF_ENC_ENABLED = 0x08,
122+
DACF_IGNORE_PDBS = 0x20,
122123
DACF_CONTROL_FLAGS_MASK = 0x2E,
123124
}
124125
```

docs/design/datacontracts/ReJIT.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ Data descriptors used:
2929
| --- | --- | --- |
3030
| ProfControlBlock | GlobalEventMask | an `ICorProfiler` `COR_PRF_MONITOR` value |
3131
| ProfControlBlock | RejitOnAttachEnabled | cached value of the `ProfAPI_RejitOnAttach` configuration knob |
32+
| ProfControlBlock | MainProfilerProfInterface | pointer to the main profiler's `ICorProfilerCallback` interface, non-null means a main profiler is attached |
33+
| ProfControlBlock | NotificationProfilerCount | number of notification-only profilers currently attached |
3234
| ILCodeVersionNode | VersionId | `ILCodeVersion` ReJIT ID
3335
| ILCodeVersionNode | RejitState | a `RejitFlags` value |
3436

src/coreclr/inc/cordbpriv.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ enum DebuggerControlFlag
4949
// Flags used to control the debuggable state of modules and
5050
// assemblies.
5151
//
52-
// [cDAC] [Loader]: Contract depends on DACF_NONE, DACF_ALLOW_JIT_OPTS, DACF_ENC_ENABLED, DACF_CONTROL_FLAGS_MASK.
52+
// [cDAC] [Loader]: Contract depends on DACF_NONE, DACF_ALLOW_JIT_OPTS, DACF_ENC_ENABLED, DACF_IGNORE_PDBS, DACF_CONTROL_FLAGS_MASK.
5353
enum DebuggerAssemblyControlFlags
5454
{
5555
DACF_NONE = 0x00,

src/coreclr/vm/datadescriptor/datadescriptor.inc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -924,6 +924,8 @@ CDAC_TYPE_END(ILCodeVersionNode)
924924
CDAC_TYPE_BEGIN(ProfControlBlock)
925925
CDAC_TYPE_FIELD(ProfControlBlock, T_UINT64, GlobalEventMask, offsetof(ProfControlBlock, globalEventMask))
926926
CDAC_TYPE_FIELD(ProfControlBlock, T_BOOL, RejitOnAttachEnabled, offsetof(ProfControlBlock, fRejitOnAttachEnabled))
927+
CDAC_TYPE_FIELD(ProfControlBlock, T_POINTER, MainProfilerProfInterface, offsetof(ProfControlBlock, mainProfilerInfo) + offsetof(ProfilerInfo, pProfInterface))
928+
CDAC_TYPE_FIELD(ProfControlBlock, T_INT32, NotificationProfilerCount, offsetof(ProfControlBlock, notificationProfilerCount))
927929
CDAC_TYPE_END(ProfControlBlock)
928930
#endif // PROFILING_SUPPORTED
929931

src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/ILoader.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ public enum DebuggerAssemblyControlFlags : uint
3333
DACF_NONE = 0x00,
3434
DACF_ALLOW_JIT_OPTS = 0x02,
3535
DACF_ENC_ENABLED = 0x08,
36+
DACF_IGNORE_PDBS = 0x20,
3637
DACF_CONTROL_FLAGS_MASK = 0x2E,
3738
}
3839

src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/CorDbHResults.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,5 @@ public static class CorDbgHResults
1010
public const int CORDBG_E_READVIRTUAL_FAILURE = unchecked((int)0x80131c49);
1111
public const int ERROR_BUFFER_OVERFLOW = unchecked((int)0x8007006F); // HRESULT_FROM_WIN32(ERROR_BUFFER_OVERFLOW)
1212
public const int CORDBG_E_CLASS_NOT_LOADED = unchecked((int)0x80131303);
13+
public const int CORDBG_S_NOT_ALL_BITS_SET = unchecked((int)0x00131c13);
1314
}

src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Loader_1.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ private enum ModuleFlags_1 : uint
2323
JitOptimizationDisabled = 0x2, // Cached flag: JIT optimizations are disabled
2424
EditAndContinue = 0x8, // Edit and Continue is enabled for this module
2525
ReflectionEmit = 0x40, // Reflection.Emit was used to create this module
26+
EncCapable = 0x200, // Cached flag: module is Edit and Continue capable
2627
}
2728

2829
private const uint DebuggerInfoMask = 0x0000FC00;
@@ -389,6 +390,8 @@ private static ModuleFlags GetFlags(Data.Module module)
389390
flags |= ModuleFlags.EditAndContinue;
390391
if (runtimeFlags.HasFlag(ModuleFlags_1.ReflectionEmit))
391392
flags |= ModuleFlags.ReflectionEmit;
393+
if (runtimeFlags.HasFlag(ModuleFlags_1.EncCapable))
394+
flags |= ModuleFlags.EncCapable;
392395

393396
return flags;
394397
}

src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/ProfControlBlock.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,12 @@ public ProfControlBlock(Target target, TargetPointer address)
1313
Target.TypeInfo type = target.GetTypeInfo(DataType.ProfControlBlock);
1414
GlobalEventMask = target.ReadField<ulong>(address, type, nameof(GlobalEventMask));
1515
RejitOnAttachEnabled = target.ReadField<byte>(address, type, nameof(RejitOnAttachEnabled)) != 0;
16+
MainProfilerProfInterface = target.ReadPointerField(address, type, nameof(MainProfilerProfInterface));
17+
NotificationProfilerCount = target.ReadField<int>(address, type, nameof(NotificationProfilerCount));
1618
}
1719

1820
public ulong GlobalEventMask { get; init; }
1921
public bool RejitOnAttachEnabled { get; init; }
22+
public TargetPointer MainProfilerProfInterface { get; init; }
23+
public int NotificationProfilerCount { get; init; }
2024
}

src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/DacDbiImpl.cs

Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
using System.Runtime.InteropServices;
99
using System.Runtime.InteropServices.Marshalling;
1010
using Microsoft.Diagnostics.DataContractReader.Contracts;
11+
using DACF = Microsoft.Diagnostics.DataContractReader.Contracts.DebuggerAssemblyControlFlags;
1112

1213
namespace Microsoft.Diagnostics.DataContractReader.Legacy;
1314

@@ -37,6 +38,17 @@ private int StringHolderAssignCopy(nint stringHolder, string str)
3738
}
3839
}
3940

41+
private bool CORProfilerPresent()
42+
{
43+
if (!_target.TryReadGlobalPointer(Constants.Globals.ProfilerControlBlock, out TargetPointer? profControlBlockAddress))
44+
return false;
45+
46+
Target.TypeInfo type = _target.GetTypeInfo(DataType.ProfControlBlock);
47+
TargetPointer mainProfInterface = _target.ReadPointerField(profControlBlockAddress.Value, type, "MainProfilerProfInterface");
48+
int notificationCount = _target.ReadField<int>(profControlBlockAddress.Value, type, "NotificationProfilerCount");
49+
return mainProfInterface != TargetPointer.Null || notificationCount > 0;
50+
}
51+
4052
public DacDbiImpl(Target target, object? legacyObj)
4153
{
4254
_target = target;
@@ -315,7 +327,51 @@ public int GetCompilerFlags(ulong vmAssembly, Interop.BOOL* pfAllowJITOpts, Inte
315327
}
316328

317329
public int SetCompilerFlags(ulong vmAssembly, Interop.BOOL fAllowJitOpts, Interop.BOOL fEnableEnC)
318-
=> LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.SetCompilerFlags(vmAssembly, fAllowJitOpts, fEnableEnC) : HResults.E_NOTIMPL;
330+
{
331+
int hr = HResults.S_OK;
332+
try
333+
{
334+
Contracts.ILoader loader = _target.Contracts.Loader;
335+
Contracts.ModuleHandle handle = loader.GetModuleHandleFromAssemblyPtr(new TargetPointer(vmAssembly));
336+
337+
DACF debuggerInfoBits = loader.GetDebuggerInfoBits(handle);
338+
DACF controlFlags = debuggerInfoBits & ~(DACF.DACF_ALLOW_JIT_OPTS | DACF.DACF_ENC_ENABLED);
339+
controlFlags &= DACF.DACF_CONTROL_FLAGS_MASK;
340+
341+
if (fAllowJitOpts != Interop.BOOL.FALSE)
342+
{
343+
controlFlags |= DACF.DACF_ALLOW_JIT_OPTS;
344+
}
345+
346+
if (fEnableEnC != Interop.BOOL.FALSE)
347+
{
348+
bool fIgnorePdbs = (debuggerInfoBits & DACF.DACF_IGNORE_PDBS) != 0;
349+
bool canSetEnC = (loader.GetFlags(handle) & Contracts.ModuleFlags.EncCapable) != 0 && !CORProfilerPresent() && fIgnorePdbs;
350+
if (canSetEnC)
351+
{
352+
controlFlags |= DACF.DACF_ENC_ENABLED;
353+
}
354+
else
355+
{
356+
hr = CorDbgHResults.CORDBG_S_NOT_ALL_BITS_SET;
357+
}
358+
}
359+
360+
loader.SetDebuggerInfoBits(handle, controlFlags);
361+
}
362+
catch (System.Exception ex)
363+
{
364+
hr = ex.HResult;
365+
}
366+
#if DEBUG
367+
if (_legacy is not null)
368+
{
369+
int hrLocal = _legacy.SetCompilerFlags(vmAssembly, fAllowJitOpts, fEnableEnC);
370+
Debug.ValidateHResult(hr, hrLocal);
371+
}
372+
#endif
373+
return hr;
374+
}
319375

320376
public int EnumerateAssembliesInAppDomain(ulong vmAppDomain, nint fpCallback, nint pUserData)
321377
=> LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.EnumerateAssembliesInAppDomain(vmAppDomain, fpCallback, pUserData) : HResults.E_NOTIMPL;

0 commit comments

Comments
 (0)