Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/design/datacontracts/DebugInfo.md
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,7 @@ public readonly struct DebugVarInfo
public uint VarNumber { get; init; }
public DebugVarLocKind Kind { get; init; }
public bool IsByRef { get; init; }
public bool IsFloatingPoint { get; init; }
public uint Register { get; init; }
public uint Register2 { get; init; }
public uint BaseRegister { get; init; }
Expand Down
78 changes: 51 additions & 27 deletions docs/design/datacontracts/RuntimeTypeSystem.md
Original file line number Diff line number Diff line change
Expand Up @@ -232,9 +232,6 @@ partial interface IRuntimeTypeSystem : IContract
// A no metadata method is also a StoredSigMethodDesc
public virtual bool IsNoMetadataMethod(MethodDescHandle methodDesc, out string methodName);

// A StoredSigMethodDesc is a MethodDesc for which the signature isn't found in metadata.
public virtual bool IsStoredSigMethodDesc(MethodDescHandle methodDesc, out ReadOnlySpan<byte> signature);

// Return true for a MethodDesc that describes a method represented by the System.Reflection.Emit.DynamicMethod class
// A DynamicMethod is also a StoredSigMethodDesc, and a NoMetadataMethod
public virtual bool IsDynamicMethod(MethodDescHandle methodDesc);
Expand All @@ -257,6 +254,9 @@ partial interface IRuntimeTypeSystem : IContract
// Corresponds to native MethodDesc::IsAsyncMethod().
public virtual bool IsAsyncMethod(MethodDescHandle methodDesc);

// Return true and the raw signature bytes for a MethodDesc, or false if no signature could be resolved.
public virtual bool TryGetMethodSignature(MethodDescHandle methodDesc, out ReadOnlySpan<byte> signature);

// Return true if a MethodDesc is in a collectible module
public virtual bool IsCollectibleMethod(MethodDescHandle methodDesc);

Expand Down Expand Up @@ -1332,6 +1332,10 @@ We depend on the following data descriptors:
| `StoredSigMethodDesc` | `cSig` | Count of bytes in the metadata signature |
| `StoredSigMethodDesc` | `ExtendedFlags` | Flags field for the `StoredSigMethodDesc` |
| `DynamicMethodDesc` | `MethodName` | Pointer to Null-terminated UTF8 string describing the Method desc |
| `AsyncMethodData` | `Flags` | Async method flags |
| `AsyncMethodData` | `Signature` | The async variant's signature (see `Signature`) |
| `Signature` | `SignaturePointer` | Pointer to the raw signature blob |
| `Signature` | `SignatureLength` | Count of bytes in the raw signature blob |
| `GCCoverageInfo` | `SavedCode` | Pointer to the GCCover saved code copy, if supported |

The following data descriptor types are used only for their sizes when computing the total size of a `MethodDesc` instance.
Expand Down Expand Up @@ -1595,6 +1599,50 @@ And the various apis are implemented with the following algorithms
return 0x06000000 | tokenRange | tokenRemainder;
}

public bool TryGetMethodSignature(MethodDescHandle methodDescHandle, out ReadOnlySpan<byte> signature)
{
MethodDesc methodDesc = _methodDescs[methodDescHandle.Address];

// Dynamic, EEImpl and Array methods store their signature directly on the MethodDesc.
MethodClassification classification = (MethodClassification)(methodDesc.Flags & MethodDescFlags.ClassificationMask);
if (classification is MethodClassification.Dynamic or MethodClassification.EEImpl or MethodClassification.Array)
{
signature = // StoredSigMethodDesc.Signature blob for methodDesc
return true;
}

// Async variant methods carry their signature in the AsyncMethodData.
if (HasFlag(methodDesc, MethodDescFlags.HasAsyncMethodData))
{
AsyncMethodData asyncData = // Read AsyncMethodData for methodDesc
if (((AsyncMethodFlags)asyncData.Flags).HasFlag(AsyncMethodFlags.IsAsyncVariant))
{
signature = // Read asyncData.Signature.SignatureLength bytes from asyncData.Signature.SignaturePointer
return true;
}
}

// Otherwise resolve the signature from ECMA metadata using the MethodDef token.
uint token = GetMethodToken(methodDescHandle);
if (EcmaMetadataUtils.GetRowId(token) == 0)
{
signature = default;
return false;
}

MetadataReader? mdReader = // Get metadata reader for the method's module, or null if unavailable
if (mdReader is null)
{
signature = default;
return false;
}

MethodDefinitionHandle methodDefHandle = MetadataTokens.MethodDefinitionHandle((int)EcmaMetadataUtils.GetRowId(token));
MethodDefinition methodDef = mdReader.GetMethodDefinition(methodDefHandle);
signature = mdReader.GetBlobBytes(methodDef.Signature);
return true;
}

public uint GetMethodDescSize(MethodDescHandle methodDescHandle)
{
MethodDesc methodDesc = _methodDescs[methodDescHandle.Address];
Expand Down Expand Up @@ -1667,30 +1715,6 @@ And the various apis are implemented with the following algorithms
return true;
}

public bool IsStoredSigMethodDesc(MethodDescHandle methodDescHandle, out ReadOnlySpan<byte> signature)
{
MethodDesc methodDesc = _methodDescs[methodDescHandle.Address];

switch (methodDesc.Classification)
{
case MethodDescClassification.Dynamic:
case MethodDescClassification.EEImpl:
case MethodDescClassification.Array:
break; // These have stored sigs

default:
signature = default;
return false;
}

TargetPointer Sig = // Read Sig field from StoredSigMethodDesc contract using address methodDescHandle.Address
uint cSig = // Read cSig field from StoredSigMethodDesc contract using address methodDescHandle.Address

TargetPointer methodNamePointer = // Read S field from DynamicMethodDesc contract using address methodDescHandle.Address
signature = // Read buffer from target memory starting at address Sig, with cSig bytes in it.
return true;
}

public bool IsDynamicMethod(MethodDescHandle methodDescHandle)
{
MethodDesc methodDesc = _methodDescs[methodDescHandle.Address];
Expand Down
9 changes: 5 additions & 4 deletions docs/design/datacontracts/Signature.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,9 @@ Data descriptors used:
| Data Descriptor Name | Field | Meaning |
| --- | --- | --- |
| `VASigCookie` | `SizeOfArgs` | Total size in bytes of the pushed argument list. Used on x86 to locate the args base. |
| `VASigCookie` | `SignaturePointer` | Target address of the raw vararg signature blob. |
| `VASigCookie` | `SignatureLength` | Length in bytes of the raw vararg signature blob. |
| `VASigCookie` | `Signature` | The raw vararg signature (see `Signature`). |
| `Signature` | `SignaturePointer` | Target address of the raw signature blob. |
| `Signature` | `SignatureLength` | Length in bytes of the raw signature blob. |

Global variables used:
| Global Name | Type | Purpose |
Expand Down Expand Up @@ -104,7 +105,7 @@ void ISignature.GetVarArgSignature(TargetPointer vaSigCookieAddr, out TargetPoin
TargetPointer vaSigCookie = _target.ReadPointer(vaSigCookieAddr);
VASigCookie cookie = _target.ProcessedData.GetOrAdd<VASigCookie>(vaSigCookie);

signatureAddress = cookie.SignaturePointer;
signatureLength = cookie.SignatureLength;
signatureAddress = cookie.Signature.SignaturePointer;
signatureLength = cookie.Signature.SignatureLength;
}
```
155 changes: 47 additions & 108 deletions src/coreclr/debug/daccess/dacdbiimpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -756,8 +756,14 @@ HRESULT STDMETHODCALLTYPE DacDbiInterfaceImpl::SetCompilerFlags(VMPTR_Assembly v
// sequence points and var info
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

// Initialize the native/IL sequence points and native var info for a function.
HRESULT STDMETHODCALLTYPE DacDbiInterfaceImpl::GetNativeCodeSequencePointsAndVarInfo(VMPTR_MethodDesc vmMethodDesc, CORDB_ADDRESS startAddress, BOOL fCodeAvailable, OUT NativeVarData * pNativeVarData, OUT SequencePoints * pSequencePoints)
// Allocator to pass to the debug-info-stores...
static BYTE* InfoStoreNew(void * pData, size_t cBytes)
{
return new (nothrow) BYTE[cBytes];
}

// Get the native/IL sequence points and native var info for a function via callbacks.
HRESULT STDMETHODCALLTYPE DacDbiInterfaceImpl::GetNativeCodeSequencePointsAndVarInfo(VMPTR_MethodDesc vmMethodDesc, CORDB_ADDRESS startAddress, BOOL fCodeAvailable, OUT ULONG32 * pFixedArgCount, FP_NATIVEVARINFO_CALLBACK fpVarInfoCallback, FP_SEQUENCEPOINT_CALLBACK fpSeqPointCallback, CALLBACK_DATA pUserData)
{
DD_ENTER_MAY_THROW;

Expand All @@ -771,11 +777,46 @@ HRESULT STDMETHODCALLTYPE DacDbiInterfaceImpl::GetNativeCodeSequencePointsAndVar

_ASSERTE(fCodeAvailable != 0);

// get information about the locations of arguments and local variables
GetNativeVarData(pMD, startAddress, GetArgCount(pMD), pNativeVarData);
// Return the fixed argument count
if (pFixedArgCount != NULL)
{
*pFixedArgCount = (ULONG32)GetArgCount(pMD);
}

DebugInfoRequest request;
request.InitFromStartingAddr(pMD, CORDB_ADDRESS_TO_TADDR(startAddress));

// Retrieve sequence points and native variable info in a single request
NewArrayHolder<ICorDebugInfo::OffsetMapping> mapCopy(NULL);
NewArrayHolder<ICorDebugInfo::NativeVarInfo> nativeVars(NULL);
ULONG32 seqEntryCount = 0;
ULONG32 varEntryCount = 0;

BOOL success = DebugInfoManager::GetBoundariesAndVars(request,
InfoStoreNew, NULL,
BoundsType::Uninstrumented,
&seqEntryCount, &mapCopy,
&varEntryCount, &nativeVars);
if (!success)
ThrowHR(E_FAIL);

Comment thread
rcj1 marked this conversation as resolved.
// Invoke the native variable info callback for each entry
if (fpVarInfoCallback != NULL)
{
for (ULONG32 i = 0; i < varEntryCount; i++)
{
fpVarInfoCallback(&nativeVars[i], pUserData);
}
}

// get the sequence points
GetSequencePoints(pMD, startAddress, pSequencePoints);
// Invoke the sequence point callback for each entry
if (fpSeqPointCallback != NULL)
{
for (ULONG32 i = 0; i < seqEntryCount; i++)
{
fpSeqPointCallback(&mapCopy[i], pUserData);
}
}

}
EX_CATCH_HRESULT(hr);
Expand Down Expand Up @@ -829,108 +870,6 @@ SIZE_T DacDbiInterfaceImpl::GetArgCount(MethodDesc * pMD)
return NumArguments;
} //GetArgCount

// Allocator to pass to the debug-info-stores...
BYTE* InfoStoreNew(void * pData, size_t cBytes)
{
return new BYTE[cBytes];
}

//-----------------------------------------------------------------------------
// Get locations and code offsets for local variables and arguments in a function
// This information is used to find the location of a value at a given IP.
// Arguments:
// input:
// pMethodDesc pointer to the method desc for the function
// startAddr starting address of the function--used to differentiate
// EnC versions
// fixedArgCount number of fixed arguments to the function
// output:
// pVarInfo data structure containing a list of variable and
// argument locations by range of IP offsets
// Note: this function may throw
//-----------------------------------------------------------------------------
void DacDbiInterfaceImpl::GetNativeVarData(MethodDesc * pMethodDesc,
CORDB_ADDRESS startAddr,
SIZE_T fixedArgCount,
NativeVarData * pVarInfo)
{
// make sure we haven't done this already
if (pVarInfo->IsInitialized())
{
return;
}

NewArrayHolder<ICorDebugInfo::NativeVarInfo> nativeVars(NULL);

DebugInfoRequest request;
request.InitFromStartingAddr(pMethodDesc, CORDB_ADDRESS_TO_TADDR(startAddr));

ULONG32 entryCount;

BOOL success = DebugInfoManager::GetBoundariesAndVars(request,
InfoStoreNew, NULL, // allocator
BoundsType::Instrumented,
NULL, NULL,
&entryCount, &nativeVars);

if (!success)
ThrowHR(E_FAIL);

// set key fields of pVarInfo
pVarInfo->InitVarDataList(nativeVars, (int)fixedArgCount, (int)entryCount);
} // GetNativeVarData




//-----------------------------------------------------------------------------
// Get the native/IL sequence points for a function
// Arguments:
// input:
// pMethodDesc pointer to the method desc for the function
// startAddr starting address of the function--used to differentiate
// output:
// pNativeMap data structure containing a list of sequence points
// Note: this function may throw
//-----------------------------------------------------------------------------
void DacDbiInterfaceImpl::GetSequencePoints(MethodDesc * pMethodDesc,
CORDB_ADDRESS startAddr,
SequencePoints * pSeqPoints)
{

// make sure we haven't done this already
if (pSeqPoints->IsInitialized())
{
return;
}

// Use the DebugInfoStore to get IL->Native maps.
// It doesn't matter whether we're jitted, ngenned etc.
DebugInfoRequest request;
request.InitFromStartingAddr(pMethodDesc, CORDB_ADDRESS_TO_TADDR(startAddr));


// Bounds info.
NewArrayHolder<ICorDebugInfo::OffsetMapping> mapCopy(NULL);

ULONG32 entryCount;
BOOL success = DebugInfoManager::GetBoundariesAndVars(request,
InfoStoreNew,
NULL, // allocator
BoundsType::Uninstrumented,
&entryCount, &mapCopy,
NULL, NULL);
if (!success)
ThrowHR(E_FAIL);

pSeqPoints->InitSequencePoints(entryCount);

// mapCopy and pSeqPoints have elements of different types. Thus, we
// need to copy the individual members from the elements of mapCopy to the
// elements of pSeqPoints. Once we're done, we can release mapCopy
pSeqPoints->CopyAndSortSequencePoints(mapCopy);

} // GetSequencePoints

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Function Data
Expand Down
13 changes: 1 addition & 12 deletions src/coreclr/debug/daccess/dacdbiimpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ class DacDbiInterfaceImpl :


// Initialize the native/IL sequence points and native var info for a function.
HRESULT STDMETHODCALLTYPE GetNativeCodeSequencePointsAndVarInfo(VMPTR_MethodDesc vmMethodDesc, CORDB_ADDRESS startAddress, BOOL fCodeAvailable, OUT NativeVarData * pNativeVarData, OUT SequencePoints * pSequencePoints);
HRESULT STDMETHODCALLTYPE GetNativeCodeSequencePointsAndVarInfo(VMPTR_MethodDesc vmMethodDesc, CORDB_ADDRESS startAddress, BOOL fCodeAvailable, OUT ULONG32 * pFixedArgCount, FP_NATIVEVARINFO_CALLBACK fpVarInfoCallback, FP_SEQUENCEPOINT_CALLBACK fpSeqPointCallback, CALLBACK_DATA pUserData);

HRESULT STDMETHODCALLTYPE IsThreadSuspendedOrHijacked(VMPTR_Thread vmThread, OUT BOOL * pResult);

Expand Down Expand Up @@ -159,17 +159,6 @@ class DacDbiInterfaceImpl :
// Get the number of fixed arguments to a function, i.e., the explicit args and the "this" pointer.
SIZE_T GetArgCount(MethodDesc * pMD);

// Get locations and code offsets for local variables and arguments in a function
void GetNativeVarData(MethodDesc * pMethodDesc,
CORDB_ADDRESS startAddr,
SIZE_T fixedArgCount,
NativeVarData * pVarInfo);

// Get the native/IL sequence points for a function
void GetSequencePoints(MethodDesc * pMethodDesc,
CORDB_ADDRESS startAddr,
SequencePoints * pNativeMap);

public:
//----------------------------------------------------------------------------------
// class MapSortILMap: A template class that will sort an array of DebuggerILToNativeMap.
Expand Down
41 changes: 36 additions & 5 deletions src/coreclr/debug/di/module.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4771,11 +4771,42 @@ void CordbNativeCode::LoadNativeInfo()
if (m_fCodeAvailable)
{
RSLockHolder lockHolder(pProcess->GetProcessLock());
IfFailThrow(pProcess->GetDAC()->GetNativeCodeSequencePointsAndVarInfo(GetVMNativeCodeMethodDescToken(),
GetAddress(),
m_fCodeAvailable,
&m_nativeVarData,
&m_sequencePoints));

struct CallbackData
{
CallbackAccumulator<ICorDebugInfo::NativeVarInfo> varInfos;
CallbackAccumulator<ICorDebugInfo::OffsetMapping> seqPoints;
};

CallbackData data;

ULONG32 fixedArgCount = 0;
IfFailThrow(pProcess->GetDAC()->GetNativeCodeSequencePointsAndVarInfo(
GetVMNativeCodeMethodDescToken(),
GetAddress(),
m_fCodeAvailable,
&fixedArgCount,
[](ICorDebugInfo::NativeVarInfo *pVarInfo, void *pUserData)
{
static_cast<CallbackData *>(pUserData)->varInfos.Push(*pVarInfo);
},
[](ICorDebugInfo::OffsetMapping *pMapping, void *pUserData)
{
static_cast<CallbackData *>(pUserData)->seqPoints.Push(*pMapping);
},
&data));
IfFailThrow(data.varInfos.hrError);
IfFailThrow(data.seqPoints.hrError);

// Initialize native var data from collected entries
m_nativeVarData.InitVarDataList(data.varInfos.items.Ptr(), (int)fixedArgCount, (int)data.varInfos.items.Size());

// Initialize sequence points from collected entries
m_sequencePoints.InitSequencePoints((ULONG32)data.seqPoints.items.Size());
if (data.seqPoints.items.Size() > 0)
{
m_sequencePoints.CopyAndSortSequencePoints(data.seqPoints.items.Ptr());
}
}

} // CordbNativeCode::LoadNativeInfo
Loading
Loading