Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.

Commit 394edf4

Browse files
authored
Delegate inspection API in the DBI (#25362)
* Add ICorDebugDelegateObjectValue interfaces * Expose appropriate HR (CORDBG_E_UNSUPPORTED_DELEGATE) * Partially DACize DelegateObject * Add DacDbi method for delegate inspection
1 parent be31aae commit 394edf4

File tree

13 files changed

+634
-25
lines changed

13 files changed

+634
-25
lines changed

src/debug/daccess/dacdbiimpl.cpp

Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3406,6 +3406,201 @@ BOOL DacDbiInterfaceImpl::IsExceptionObject(MethodTable* pMT)
34063406
return FALSE;
34073407
}
34083408

3409+
HRESULT DacDbiInterfaceImpl::GetMethodDescPtrFromIpEx(TADDR funcIp, VMPTR_MethodDesc* ppMD)
3410+
{
3411+
DD_ENTER_MAY_THROW;
3412+
3413+
// The fast path is check if the code is jitted and the code manager has it available.
3414+
CLRDATA_ADDRESS mdAddr;
3415+
HRESULT hr = g_dacImpl->GetMethodDescPtrFromIP(TO_CDADDR(funcIp), &mdAddr);
3416+
if (S_OK == hr)
3417+
{
3418+
ppMD->SetDacTargetPtr(CLRDATA_ADDRESS_TO_TADDR(mdAddr));
3419+
return hr;
3420+
}
3421+
3422+
// Otherwise try to see if a method desc is available for the method that isn't jitted by walking the code stubs.
3423+
MethodDesc* pMD = MethodTable::GetMethodDescForSlotAddress(PINSTRToPCODE(funcIp));
3424+
3425+
if (pMD == NULL)
3426+
return E_INVALIDARG;
3427+
3428+
ppMD->SetDacTargetPtr(PTR_HOST_TO_TADDR(pMD));
3429+
return S_OK;
3430+
}
3431+
3432+
BOOL DacDbiInterfaceImpl::IsDelegate(VMPTR_Object vmObject)
3433+
{
3434+
DD_ENTER_MAY_THROW;
3435+
3436+
if (vmObject.IsNull())
3437+
return FALSE;
3438+
3439+
Object *pObj = vmObject.GetDacPtr();
3440+
return pObj->GetGCSafeMethodTable()->IsDelegate();
3441+
}
3442+
3443+
3444+
//-----------------------------------------------------------------------------
3445+
// DacDbi API: GetDelegateType
3446+
// Given a delegate pointer, compute the type of delegate according to the data held in it.
3447+
//-----------------------------------------------------------------------------
3448+
HRESULT DacDbiInterfaceImpl::GetDelegateType(VMPTR_Object delegateObject, DelegateType *delegateType)
3449+
{
3450+
DD_ENTER_MAY_THROW;
3451+
3452+
_ASSERTE(!delegateObject.IsNull());
3453+
_ASSERTE(delegateType != NULL);
3454+
3455+
#ifdef _DEBUG
3456+
// ensure we have a Delegate object
3457+
IsDelegate(delegateObject);
3458+
#endif
3459+
3460+
// Ideally, we would share the implementation of this method with the runtime, or get the same information
3461+
// we are getting from here from other EE methods. Nonetheless, currently the implementation is sharded across
3462+
// several pieces of logic so this replicates the logic mostly due to time constraints. The Mainly from:
3463+
// - System.Private.CoreLib!System.Delegate.GetMethodImpl and System.Private.CoreLib!System.MulticastDelegate.GetMethodImpl
3464+
// - System.Private.CoreLib!System.Delegate.GetTarget and System.Private.CoreLib!System.MulticastDelegate.GetTarget
3465+
// - coreclr!COMDelegate::GetMethodDesc and coreclr!COMDelegate::FindMethodHandle
3466+
// - coreclr!COMDelegate::DelegateConstruct and the delegate type table in
3467+
// - DELEGATE KINDS TABLE in comdelegate.cpp
3468+
3469+
*delegateType = DelegateType::kUnknownDelegateType;
3470+
PTR_DelegateObject pDelObj = dac_cast<PTR_DelegateObject>(delegateObject.GetDacPtr());
3471+
INT_PTR invocationCount = pDelObj->GetInvocationCount();
3472+
3473+
if (invocationCount == -1)
3474+
{
3475+
// We could get a native code for this case from _methodPtr, but not a methodDef as we'll need.
3476+
// We can also get the shuffling thunk. However, this doesn't have a token and there's
3477+
// no easy way to expose through the DBI now.
3478+
*delegateType = kUnmanagedFunctionDelegate;
3479+
return S_OK;
3480+
}
3481+
3482+
PTR_Object pInvocationList = OBJECTREFToObject(pDelObj->GetInvocationList());
3483+
3484+
if (invocationCount == NULL)
3485+
{
3486+
if (pInvocationList == NULL)
3487+
{
3488+
// If this delegate points to a static function or this is a open virtual delegate, this should be non-null
3489+
// Special case: This might fail in a VSD delegate (instance open virtual)...
3490+
// TODO: There is the special signatures cases missing.
3491+
TADDR targetMethodPtr = PCODEToPINSTR(pDelObj->GetMethodPtrAux());
3492+
if (targetMethodPtr == NULL)
3493+
{
3494+
// Static extension methods, other closed static delegates, and instance delegates fall into this category.
3495+
*delegateType = kClosedDelegate;
3496+
}
3497+
else {
3498+
*delegateType = kOpenDelegate;
3499+
}
3500+
3501+
return S_OK;
3502+
}
3503+
}
3504+
else
3505+
{
3506+
if (pInvocationList != NULL)
3507+
{
3508+
PTR_MethodTable invocationListMT = pInvocationList->GetGCSafeMethodTable();
3509+
3510+
if (invocationListMT->IsArray())
3511+
*delegateType = kTrueMulticastDelegate;
3512+
3513+
if (invocationListMT->IsDelegate())
3514+
*delegateType = kSecureDelegate;
3515+
3516+
// Cases missing: Loader allocator, or dynamic resolver.
3517+
return S_OK;
3518+
}
3519+
3520+
// According to the table in comdelegates.cpp, there shouldn't be a case where .
3521+
// Multicast falls outside of the table, so not
3522+
}
3523+
3524+
_ASSERT(FALSE);
3525+
*delegateType = kUnknownDelegateType;
3526+
return CORDBG_E_UNSUPPORTED_DELEGATE;
3527+
}
3528+
3529+
HRESULT DacDbiInterfaceImpl::GetDelegateFunctionData(
3530+
DelegateType delegateType,
3531+
VMPTR_Object delegateObject,
3532+
OUT VMPTR_DomainFile *ppFunctionDomainFile,
3533+
OUT mdMethodDef *pMethodDef)
3534+
{
3535+
DD_ENTER_MAY_THROW;
3536+
3537+
#ifdef _DEBUG
3538+
// ensure we have a Delegate object
3539+
IsDelegate(delegateObject);
3540+
#endif
3541+
3542+
HRESULT hr = S_OK;
3543+
PTR_DelegateObject pDelObj = dac_cast<PTR_DelegateObject>(delegateObject.GetDacPtr());
3544+
TADDR targetMethodPtr = NULL;
3545+
VMPTR_MethodDesc pMD;
3546+
3547+
switch (delegateType)
3548+
{
3549+
case kClosedDelegate:
3550+
targetMethodPtr = PCODEToPINSTR(pDelObj->GetMethodPtr());
3551+
break;
3552+
case kOpenDelegate:
3553+
targetMethodPtr = PCODEToPINSTR(pDelObj->GetMethodPtrAux());
3554+
break;
3555+
default:
3556+
return E_FAIL;
3557+
}
3558+
3559+
hr = GetMethodDescPtrFromIpEx(targetMethodPtr, &pMD);
3560+
if (hr != S_OK)
3561+
return hr;
3562+
3563+
ppFunctionDomainFile->SetDacTargetPtr(dac_cast<TADDR>(pMD.GetDacPtr()->GetModule()->GetDomainFile()));
3564+
*pMethodDef = pMD.GetDacPtr()->GetMemberDef();
3565+
3566+
return hr;
3567+
}
3568+
3569+
HRESULT DacDbiInterfaceImpl::GetDelegateTargetObject(
3570+
DelegateType delegateType,
3571+
VMPTR_Object delegateObject,
3572+
OUT VMPTR_Object *ppTargetObj,
3573+
OUT VMPTR_AppDomain *ppTargetAppDomain)
3574+
{
3575+
DD_ENTER_MAY_THROW;
3576+
3577+
#ifdef _DEBUG
3578+
// ensure we have a Delegate object
3579+
IsDelegate(delegateObject);
3580+
#endif
3581+
3582+
HRESULT hr = S_OK;
3583+
PTR_DelegateObject pDelObj = dac_cast<PTR_DelegateObject>(delegateObject.GetDacPtr());
3584+
3585+
switch (delegateType)
3586+
{
3587+
case kClosedDelegate:
3588+
{
3589+
PTR_Object pRemoteTargetObj = OBJECTREFToObject(pDelObj->GetTarget());
3590+
ppTargetObj->SetDacTargetPtr(pRemoteTargetObj.GetAddr());
3591+
ppTargetAppDomain->SetDacTargetPtr(dac_cast<TADDR>(pRemoteTargetObj->GetGCSafeMethodTable()->GetDomain()->AsAppDomain()));
3592+
break;
3593+
}
3594+
3595+
default:
3596+
ppTargetObj->SetDacTargetPtr(NULL);
3597+
ppTargetAppDomain->SetDacTargetPtr(dac_cast<TADDR>(pDelObj->GetGCSafeMethodTable()->GetDomain()->AsAppDomain()));
3598+
break;
3599+
}
3600+
3601+
return hr;
3602+
}
3603+
34093604
void DacDbiInterfaceImpl::GetStackFramesFromException(VMPTR_Object vmObject, DacDbiArrayList<DacExceptionCallStackData>& dacStackFrames)
34103605
{
34113606
DD_ENTER_MAY_THROW;

src/debug/daccess/dacdbiimpl.h

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,22 @@ class DacDbiInterfaceImpl :
349349
// Returns true if the argument is a runtime callable wrapper
350350
BOOL IsRcw(VMPTR_Object vmObject);
351351

352+
BOOL IsDelegate(VMPTR_Object vmObject);
353+
354+
HRESULT GetDelegateType(VMPTR_Object delegateObject, DelegateType *delegateType);
355+
356+
HRESULT GetDelegateFunctionData(
357+
DelegateType delegateType,
358+
VMPTR_Object delegateObject,
359+
OUT VMPTR_DomainFile *ppFunctionDomainFile,
360+
OUT mdMethodDef *pMethodDef);
361+
362+
HRESULT GetDelegateTargetObject(
363+
DelegateType delegateType,
364+
VMPTR_Object delegateObject,
365+
OUT VMPTR_Object *ppTargetObj,
366+
OUT VMPTR_AppDomain *ppTargetAppDomain);
367+
352368
// retrieves the list of COM interfaces implemented by vmObject, as it is known at
353369
// the time of the call (the list may change as new interface types become available
354370
// in the runtime)
@@ -382,6 +398,17 @@ class DacDbiInterfaceImpl :
382398
OUT DacDbiArrayList<DebuggerIPCE_ExpandedTypeData> * pTypes);
383399

384400
private:
401+
// Given a pointer to a managed function, obtain the method desc for it.
402+
// Equivalent to GetMethodDescPtrFromIp, except if the method isn't jitted
403+
// it will look for it in code stubs.
404+
// Returns:
405+
// S_OK on success.
406+
// If it's a jitted method, error codes equivalent to GetMethodDescPtrFromIp
407+
// E_INVALIDARG if a non-jitted metod can't be located in the stubs.
408+
HRESULT GetMethodDescPtrFromIpEx(
409+
TADDR funcIp,
410+
OUT VMPTR_MethodDesc *ppMD);
411+
385412
BOOL IsExceptionObject(MethodTable* pMT);
386413

387414
// Get the approximate and exact type handles for a type

0 commit comments

Comments
 (0)