Skip to content
Open
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
52 changes: 52 additions & 0 deletions docs/design/datacontracts/RuntimeTypeSystem.md
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,11 @@ partial interface IRuntimeTypeSystem : IContract
// Corresponds to native MethodDesc::IsAsyncMethod().
public virtual bool IsAsyncMethod(MethodDescHandle methodDesc);

// Gets the raw signature bytes for a MethodDesc by checking the stored signature,
// then the async variant signature, then ECMA metadata. Returns false if no

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.

The implementation details of where you look for these are not part of the contract, please remove from this comment block

// 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 @@ -1286,6 +1291,9 @@ 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` | `Sig` | Pointer to the async variant's signature blob |
| `AsyncMethodData` | `cSig` | Count of bytes in the async variant's 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 @@ -1549,6 +1557,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.cSig bytes from asyncData.Sig
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
155 changes: 47 additions & 108 deletions src/coreclr/debug/daccess/dacdbiimpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -783,8 +783,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 @@ -798,11 +804,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);

// 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 @@ -856,108 +897,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 @@ -105,7 +105,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 @@ -162,17 +162,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
19 changes: 12 additions & 7 deletions src/coreclr/debug/inc/dacdbiinterface.h
Original file line number Diff line number Diff line change
Expand Up @@ -1031,22 +1031,27 @@ IDacDbiInterface : public IUnknown
// for a function.
// Arguments:
// input:
// vmMethodDesc MethodDesc of the function
// startAddr starting address of the function--this serves to
// differentiate various EnC versions of the function
// vmMethodDesc MethodDesc of the function
// startAddr starting address of the function--this serves to
// differentiate various EnC versions of the function
// fCodeAvailable
// fpVarInfoCallback callback invoked once per native variable info entry
// fpSeqPointCallback callback invoked once per sequence point entry
// pUserData user data passed to the callbacks
// output:
// pNativeVarData space for the native code offset information for locals
// pSequencePoints space for the IL/native sequence points
// pFixedArgCount number of fixed arguments (explicit args + this)
// Return value:
// S_OK on success; otherwise, an appropriate failure HRESULT.
// Assumptions:
// vmMethodDesc, pNativeVarInfo and pSequencePoints are non-NULL
// vmMethodDesc is non-NULL

// Notes:
//-----------------------------------------------------------------------------

virtual HRESULT STDMETHODCALLTYPE GetNativeCodeSequencePointsAndVarInfo(VMPTR_MethodDesc vmMethodDesc, CORDB_ADDRESS startAddress, BOOL fCodeAvailable, OUT NativeVarData * pNativeVarData, OUT SequencePoints * pSequencePoints) = 0;
typedef void (*FP_NATIVEVARINFO_CALLBACK)(ICorDebugInfo::NativeVarInfo *pVarInfo, CALLBACK_DATA pUserData);
typedef void (*FP_SEQUENCEPOINT_CALLBACK)(ICorDebugInfo::OffsetMapping *pMapping, CALLBACK_DATA pUserData);

virtual 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) = 0;

//
// Get the filter CONTEXT on the LS. Once we move entirely over to the new managed pipeline
Expand Down
Loading
Loading