[cDAC] Implement GetNativeCodeSequencePointsAndVarInfo for cDAC#129267
[cDAC] Implement GetNativeCodeSequencePointsAndVarInfo for cDAC#129267barosiak wants to merge 1 commit into
Conversation
|
Tagging subscribers to this area: @steveisok, @tommcdon, @dotnet/dotnet-diag |
There was a problem hiding this comment.
Pull request overview
This PR updates the DAC↔DBI contract for GetNativeCodeSequencePointsAndVarInfo to use a callback-based enumeration model (instead of DBI-allocated output buffers), and wires up the managed cDAC (DacDbiImpl) implementation plus supporting interop structs and unit tests.
Changes:
- Replaces out-pointer buffer parameters with callback delegates for native var info and sequence points (IDL + native headers + native implementation + DBI consumer).
- Adds managed interop representations for native debug-info types and implements the cDAC-side method that enumerates var info and sequence points via callbacks.
- Adds unit tests for var location kind mapping and SourceTypes flag conversion.
Reviewed changes
Copilot reviewed 10 out of 10 changed files in this pull request and generated 8 comments.
Show a summary per file
| File | Description |
|---|---|
| src/native/managed/cdac/tests/UnitTests/DacDbiImplTests.cs | Adds unit tests for VarLoc kind/field mapping and SourceTypes flag conversion. |
| src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/IDacDbiInterface.cs | Adds managed interop structs/enums and updates method signature to callback-based pattern. |
| src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/DacDbiImpl.NativeCodeInfo.cs | Adds conversion helpers, fixed-arg counting helper, and DEBUG legacy validation. |
| src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/DacDbiImpl.cs | Implements callback-based GetNativeCodeSequencePointsAndVarInfo using cDAC contracts. |
| src/coreclr/inc/dacdbi.idl | Updates the COM IDL to define callback typedefs and the new method signature. |
| src/coreclr/inc/cordebuginfo.h | Documents that specific debug-info types are mirrored in managed code. |
| src/coreclr/debug/inc/dacdbiinterface.h | Updates the native interface signature and adds callback typedefs. |
| src/coreclr/debug/di/module.cpp | Updates CordbNativeCode::LoadNativeInfo to collect entries via callbacks and initialize its internal containers. |
| src/coreclr/debug/daccess/dacdbiimpl.h | Updates the native DAC implementation signature to the new callback-based shape. |
| src/coreclr/debug/daccess/dacdbiimpl.cpp | Rewrites the DAC implementation to enumerate var info / sequence points and invoke callbacks. |
| [StructLayout(LayoutKind.Sequential)] | ||
| public struct NativeVarInfo | ||
| { | ||
| public uint startOffset; | ||
| public uint endOffset; | ||
| public uint varNumber; | ||
| public VarLoc loc; | ||
| } |
| [StructLayout(LayoutKind.Explicit)] | ||
| public struct VarLoc | ||
| { | ||
| [FieldOffset(0)] | ||
| public VarLocType vlType; | ||
|
|
||
| // vlReg | ||
| [FieldOffset(4)] | ||
| public uint vlrReg; |
| internal static NativeVarInfo ConvertToNativeVarInfo(DebugVarInfo varInfo) | ||
| { | ||
| NativeVarInfo nvi = default; | ||
| nvi.startOffset = varInfo.StartOffset; | ||
| nvi.endOffset = varInfo.EndOffset; | ||
| nvi.varNumber = varInfo.VarNumber; | ||
| nvi.loc = ConvertToVarLoc(varInfo); | ||
| return nvi; |
| Debug.Assert(c.startOffset == d.startOffset, | ||
| $"VarInfo[{i}] startOffset mismatch - cDAC: {c.startOffset}, DAC: {d.startOffset}"); | ||
| Debug.Assert(c.endOffset == d.endOffset, | ||
| $"VarInfo[{i}] endOffset mismatch - cDAC: {c.endOffset}, DAC: {d.endOffset}"); | ||
| Debug.Assert(c.varNumber == d.varNumber, | ||
| $"VarInfo[{i}] varNumber mismatch - cDAC: {c.varNumber}, DAC: {d.varNumber}"); | ||
| Debug.Assert(c.loc.vlType == d.loc.vlType, | ||
| $"VarInfo[{i}] vlType mismatch - cDAC: {c.loc.vlType}, DAC: {d.loc.vlType}"); |
| int hr = HResults.S_OK; | ||
| try | ||
| { | ||
| Debug.Assert(vmMethodDesc != 0, $"vmMethodDesc is null"); | ||
| Debug.Assert(fCodeAvailable != 0, $"fCodeAvailable is false"); | ||
|
|
| IRuntimeTypeSystem rts = _target.Contracts.RuntimeTypeSystem; | ||
| MethodDescHandle mdh = rts.GetMethodDescHandle(new TargetPointer(vmMethodDesc)); | ||
| uint token = rts.GetMethodToken(mdh); | ||
| TargetPointer mtAddr = rts.GetMethodTable(mdh); | ||
| TypeHandle typeHandle = rts.GetTypeHandle(mtAddr); | ||
| TargetPointer modulePtr = rts.GetModule(typeHandle); | ||
| ILoader loader = _target.Contracts.Loader; | ||
| Contracts.ModuleHandle moduleHandle = loader.GetModuleHandleFromModulePtr(modulePtr); | ||
| IEcmaMetadata ecmaMetadata = _target.Contracts.EcmaMetadata; | ||
| MetadataReader? mdReader = ecmaMetadata.GetMetadata(moduleHandle); | ||
| if (mdReader is null) | ||
| throw Marshal.GetExceptionForHR(HResults.E_FAIL)!; | ||
|
|
||
| MethodDefinitionHandle methodDefHandle = MetadataTokens.MethodDefinitionHandle((int)token); | ||
| MethodDefinition methodDef = mdReader.GetMethodDefinition(methodDefHandle); | ||
| BlobReader blobReader = mdReader.GetBlobReader(methodDef.Signature); | ||
| SignatureHeader sigHeader = blobReader.ReadSignatureHeader(); | ||
| if (sigHeader.IsGeneric) | ||
| blobReader.ReadCompressedInteger(); // skip generic arity | ||
| uint paramCount = (uint)blobReader.ReadCompressedInteger(); | ||
|
|
||
| return paramCount + (sigHeader.IsInstance ? 1u : 0u); |
| ULONG32 newCapacity = (capacity == 0) ? 32 : capacity * 2; | ||
| T *pNew = new T[newCapacity]; | ||
| if (count > 0) | ||
| memcpy(pNew, pArray.GetValue(), count * sizeof(T)); | ||
| pArray = pNew; | ||
| capacity = newCapacity; | ||
| } |
| public void ConvertToVarLoc_MapsVarLocTypeCorrectly(DebugVarLocKind kind, bool isByRef, VarLocType expected) | ||
| { | ||
| var varInfo = new DebugVarInfo { Kind = kind, IsByRef = isByRef }; | ||
| VarLoc result = DacDbiImpl.ConvertToVarLoc(varInfo); | ||
| Assert.Equal(expected, result.vlType); | ||
| } |
| MethodDefinitionHandle methodDefHandle = MetadataTokens.MethodDefinitionHandle((int)token); | ||
| MethodDefinition methodDef = mdReader.GetMethodDefinition(methodDefHandle); | ||
| BlobReader blobReader = mdReader.GetBlobReader(methodDef.Signature); | ||
| SignatureHeader sigHeader = blobReader.ReadSignatureHeader(); |
There was a problem hiding this comment.
We already have
| } // CordbNativeCode::LookupOrCreateFromJITData | ||
|
|
||
| // Doubles the array capacity when full, then appends the item. | ||
| template<typename T> |
There was a problem hiding this comment.
We already have
runtime/src/coreclr/debug/di/rstype.cpp
Line 1376 in 3b91ef7
Summary
Implement
GetNativeCodeSequencePointsAndVarInfoin the cDACDacDbiImpl. The interface is changed from output-pointer parameters (NativeVarData*,SequencePoints*) to a callback pattern (FP_NATIVEVARINFO_CALLBACK,FP_SEQUENCEPOINT_CALLBACK), since the managed cDAC cannot use the nativeforDbiallocator.Changes
dacdbi.idl/dacdbiinterface.h/dacdbiimpl.h- Add callback typedefs, update method signaturedacdbiimpl.cpp- Rewrite method to use callbacks, removeGetNativeVarData/GetSequencePointshelpersmodule.cpp- RewriteLoadNativeInfowith callback struct andGrowAndAppendtemplate helperIDacDbiInterface.cs- AddVarLocType,VarLoc,NativeVarInfo,DbiOffsetMappingstructs and update method signatureDacDbiImpl.cs- ImplementGetNativeCodeSequencePointsAndVarInfoDacDbiImpl.NativeCodeInfo.cs- conversion helpers and DEBUG validationDacDbiImplTests.cs- unit tests for VarLoc type mapping, field-level conversion, and SourceTypes flag conversion