Delegate inspection API in the DBI (#25362)
authorJuan Hoyos <juan.hoyos@microsoft.com>
Wed, 26 Jun 2019 17:11:56 +0000 (10:11 -0700)
committerGitHub <noreply@github.com>
Wed, 26 Jun 2019 17:11:56 +0000 (10:11 -0700)
* Add ICorDebugDelegateObjectValue interfaces
* Expose appropriate HR (CORDBG_E_UNSUPPORTED_DELEGATE)
* Partially DACize DelegateObject
* Add DacDbi method for delegate inspection

13 files changed:
src/debug/daccess/dacdbiimpl.cpp
src/debug/daccess/dacdbiimpl.h
src/debug/di/divalue.cpp
src/debug/di/rspriv.h
src/debug/inc/dacdbiinterface.h
src/inc/cordebug.idl
src/inc/corerror.xml
src/pal/prebuilt/corerror/mscorurt.rc
src/pal/prebuilt/idl/cordebug_i.cpp
src/pal/prebuilt/inc/cordebug.h
src/pal/prebuilt/inc/corerror.h
src/vm/comdelegate.cpp
src/vm/common.h

index 8d02590..4ef3bc7 100644 (file)
@@ -3406,6 +3406,201 @@ BOOL DacDbiInterfaceImpl::IsExceptionObject(MethodTable* pMT)
     return FALSE;
 }
 
+HRESULT DacDbiInterfaceImpl::GetMethodDescPtrFromIpEx(TADDR funcIp, VMPTR_MethodDesc* ppMD)
+{
+    DD_ENTER_MAY_THROW;
+
+    // The fast path is check if the code is jitted and the code manager has it available.
+    CLRDATA_ADDRESS mdAddr;
+    HRESULT hr = g_dacImpl->GetMethodDescPtrFromIP(TO_CDADDR(funcIp), &mdAddr);
+    if (S_OK == hr)
+    {
+        ppMD->SetDacTargetPtr(CLRDATA_ADDRESS_TO_TADDR(mdAddr));
+        return hr;
+    }
+
+    // Otherwise try to see if a method desc is available for the method that isn't jitted by walking the code stubs.
+    MethodDesc* pMD = MethodTable::GetMethodDescForSlotAddress(PINSTRToPCODE(funcIp));
+
+    if (pMD == NULL)
+        return E_INVALIDARG;
+
+    ppMD->SetDacTargetPtr(PTR_HOST_TO_TADDR(pMD));
+    return S_OK;
+}
+
+BOOL DacDbiInterfaceImpl::IsDelegate(VMPTR_Object vmObject)
+{
+    DD_ENTER_MAY_THROW;
+
+    if (vmObject.IsNull())
+        return FALSE;
+
+    Object *pObj = vmObject.GetDacPtr();
+    return pObj->GetGCSafeMethodTable()->IsDelegate();
+}
+
+
+//-----------------------------------------------------------------------------
+// DacDbi API: GetDelegateType
+// Given a delegate pointer, compute the type of delegate according to the data held in it.
+//-----------------------------------------------------------------------------
+HRESULT DacDbiInterfaceImpl::GetDelegateType(VMPTR_Object delegateObject, DelegateType *delegateType)
+{
+    DD_ENTER_MAY_THROW;
+
+    _ASSERTE(!delegateObject.IsNull());
+    _ASSERTE(delegateType != NULL);
+
+#ifdef _DEBUG
+    // ensure we have a Delegate object
+    IsDelegate(delegateObject);
+#endif
+
+    // Ideally, we would share the implementation of this method with the runtime, or get the same information
+    // we are getting from here from other EE methods. Nonetheless, currently the implementation is sharded across
+    // several pieces of logic so this replicates the logic mostly due to time constraints. The Mainly from:
+    // - System.Private.CoreLib!System.Delegate.GetMethodImpl and System.Private.CoreLib!System.MulticastDelegate.GetMethodImpl
+    // - System.Private.CoreLib!System.Delegate.GetTarget and System.Private.CoreLib!System.MulticastDelegate.GetTarget
+    // - coreclr!COMDelegate::GetMethodDesc and coreclr!COMDelegate::FindMethodHandle
+    // - coreclr!COMDelegate::DelegateConstruct and the delegate type table in 
+    // - DELEGATE KINDS TABLE in comdelegate.cpp
+
+    *delegateType = DelegateType::kUnknownDelegateType;
+    PTR_DelegateObject pDelObj = dac_cast<PTR_DelegateObject>(delegateObject.GetDacPtr());
+    INT_PTR invocationCount = pDelObj->GetInvocationCount();
+
+    if (invocationCount == -1)
+    {
+        // We could get a native code for this case from _methodPtr, but not a methodDef as we'll need.
+        // We can also get the shuffling thunk. However, this doesn't have a token and there's
+        // no easy way to expose through the DBI now.
+        *delegateType = kUnmanagedFunctionDelegate;
+        return S_OK;
+    }
+
+    PTR_Object pInvocationList = OBJECTREFToObject(pDelObj->GetInvocationList());
+
+    if (invocationCount == NULL)
+    {
+        if (pInvocationList == NULL)
+        {
+            // If this delegate points to a static function or this is a open virtual delegate, this should be non-null
+            // Special case: This might fail in a VSD delegate (instance open virtual)...
+            // TODO: There is the special signatures cases missing.
+            TADDR targetMethodPtr = PCODEToPINSTR(pDelObj->GetMethodPtrAux());
+            if (targetMethodPtr == NULL)
+            {
+                // Static extension methods, other closed static delegates, and instance delegates fall into this category.
+                *delegateType = kClosedDelegate;
+            }
+            else {
+                *delegateType = kOpenDelegate;
+            }
+
+            return S_OK;
+        }
+    }
+    else
+    {
+        if (pInvocationList != NULL)
+        {
+            PTR_MethodTable invocationListMT = pInvocationList->GetGCSafeMethodTable();
+
+            if (invocationListMT->IsArray())
+                *delegateType = kTrueMulticastDelegate;
+
+            if (invocationListMT->IsDelegate())
+                *delegateType = kSecureDelegate;
+
+            // Cases missing: Loader allocator, or dynamic resolver.
+            return S_OK;
+        }
+
+        // According to the table in comdelegates.cpp, there shouldn't be a case where .
+        // Multicast falls outside of the table, so not
+    }
+
+    _ASSERT(FALSE);
+    *delegateType = kUnknownDelegateType;
+    return CORDBG_E_UNSUPPORTED_DELEGATE;
+}
+
+HRESULT DacDbiInterfaceImpl::GetDelegateFunctionData(
+    DelegateType delegateType,
+    VMPTR_Object delegateObject,
+    OUT VMPTR_DomainFile *ppFunctionDomainFile,
+    OUT mdMethodDef *pMethodDef)
+{
+    DD_ENTER_MAY_THROW;
+
+#ifdef _DEBUG
+    // ensure we have a Delegate object
+    IsDelegate(delegateObject);
+#endif
+
+    HRESULT hr = S_OK;
+    PTR_DelegateObject pDelObj = dac_cast<PTR_DelegateObject>(delegateObject.GetDacPtr());
+    TADDR targetMethodPtr = NULL;
+    VMPTR_MethodDesc pMD;
+
+    switch (delegateType)
+    {
+    case kClosedDelegate:
+        targetMethodPtr = PCODEToPINSTR(pDelObj->GetMethodPtr());
+        break;
+    case kOpenDelegate:
+        targetMethodPtr = PCODEToPINSTR(pDelObj->GetMethodPtrAux());
+        break;
+    default:
+        return E_FAIL;
+    }
+
+    hr = GetMethodDescPtrFromIpEx(targetMethodPtr, &pMD);
+    if (hr != S_OK)
+        return hr;
+
+    ppFunctionDomainFile->SetDacTargetPtr(dac_cast<TADDR>(pMD.GetDacPtr()->GetModule()->GetDomainFile()));
+    *pMethodDef = pMD.GetDacPtr()->GetMemberDef();
+
+    return hr;
+}
+
+HRESULT DacDbiInterfaceImpl::GetDelegateTargetObject(
+    DelegateType delegateType,
+    VMPTR_Object delegateObject,
+    OUT VMPTR_Object *ppTargetObj,
+    OUT VMPTR_AppDomain *ppTargetAppDomain)
+{
+    DD_ENTER_MAY_THROW;
+
+#ifdef _DEBUG
+    // ensure we have a Delegate object
+    IsDelegate(delegateObject);
+#endif
+
+    HRESULT hr = S_OK;
+    PTR_DelegateObject pDelObj = dac_cast<PTR_DelegateObject>(delegateObject.GetDacPtr());
+
+    switch (delegateType)
+    {
+        case kClosedDelegate:
+        {
+            PTR_Object pRemoteTargetObj = OBJECTREFToObject(pDelObj->GetTarget());
+            ppTargetObj->SetDacTargetPtr(pRemoteTargetObj.GetAddr());
+            ppTargetAppDomain->SetDacTargetPtr(dac_cast<TADDR>(pRemoteTargetObj->GetGCSafeMethodTable()->GetDomain()->AsAppDomain()));
+            break;
+        }
+
+        default:
+            ppTargetObj->SetDacTargetPtr(NULL);
+            ppTargetAppDomain->SetDacTargetPtr(dac_cast<TADDR>(pDelObj->GetGCSafeMethodTable()->GetDomain()->AsAppDomain()));
+            break;
+    }
+
+    return hr;
+}
+
 void DacDbiInterfaceImpl::GetStackFramesFromException(VMPTR_Object vmObject, DacDbiArrayList<DacExceptionCallStackData>& dacStackFrames)
 {
     DD_ENTER_MAY_THROW;
index ae88efe..b3ca37f 100644 (file)
@@ -349,6 +349,22 @@ public:
     // Returns true if the argument is a runtime callable wrapper
     BOOL IsRcw(VMPTR_Object vmObject);
 
+    BOOL IsDelegate(VMPTR_Object vmObject);
+
+    HRESULT GetDelegateType(VMPTR_Object delegateObject, DelegateType *delegateType);
+
+    HRESULT GetDelegateFunctionData(
+        DelegateType delegateType,
+        VMPTR_Object delegateObject,
+        OUT VMPTR_DomainFile *ppFunctionDomainFile,
+        OUT mdMethodDef *pMethodDef);
+
+    HRESULT GetDelegateTargetObject(
+        DelegateType delegateType,
+        VMPTR_Object delegateObject,
+        OUT VMPTR_Object *ppTargetObj,
+        OUT VMPTR_AppDomain *ppTargetAppDomain);
+
     // retrieves the list of COM interfaces implemented by vmObject, as it is known at
     // the time of the call (the list may change as new interface types become available
     // in the runtime)
@@ -382,6 +398,17 @@ public:
                         OUT DacDbiArrayList<DebuggerIPCE_ExpandedTypeData> * pTypes);
 
 private:
+    // Given a pointer to a managed function, obtain the method desc for it.
+    // Equivalent to GetMethodDescPtrFromIp, except if the method isn't jitted
+    // it will look for it in code stubs.
+    // Returns:
+    //   S_OK on success.
+    //   If it's a jitted method, error codes equivalent to GetMethodDescPtrFromIp
+    //   E_INVALIDARG if a non-jitted metod can't be located in the stubs.
+    HRESULT GetMethodDescPtrFromIpEx(
+        TADDR funcIp,
+        OUT VMPTR_MethodDesc *ppMD);
+
     BOOL IsExceptionObject(MethodTable* pMT);
 
     // Get the approximate and exact type handles for a type
index 59cd382..a8ef565 100644 (file)
@@ -23,7 +23,6 @@ void localCopy(void * dest, MemoryRange source)
 
     memcpy(dest, source.StartAddress(), source.Size());
 }
-
 // for an inheritance graph of the ICDValue types, // See file:./ICorDebugValueTypes.vsd for a diagram of the types.  
 
 /* ------------------------------------------------------------------------- *
@@ -271,6 +270,15 @@ void CordbValue::CreateVCObjOrRefValue(CordbAppDomain *               pAppdomain
 //   vmObj - the remote object to get an ICDValue for
 ICorDebugValue* CordbValue::CreateHeapValue(CordbAppDomain* pAppDomain, VMPTR_Object vmObj)
 {
+    // Create a temporary reference and dereference it to construct the heap value we want.
+    RSSmartPtr<CordbReferenceValue> pRefValue(CordbValue::CreateHeapReferenceValue(pAppDomain, vmObj));
+    ICorDebugValue* pExtValue;
+    IfFailThrow(pRefValue->Dereference(&pExtValue));
+    return pExtValue;
+}
+
+CordbReferenceValue* CordbValue::CreateHeapReferenceValue(CordbAppDomain* pAppDomain, VMPTR_Object vmObj)
+{
     IDacDbiInterface* pDac = pAppDomain->GetProcess()->GetDAC();
 
     TargetBuffer objBuffer = pDac->GetObjectContents(vmObj);
@@ -286,11 +294,8 @@ ICorDebugValue* CordbValue::CreateHeapValue(CordbAppDomain* pAppDomain, VMPTR_Ob
                                            VMPTR_OBJECTHANDLE::NullPtr(),
                                            NULL,
                                            &pRefValue));
-    
-    // Dereference our temporary reference value to construct the heap value we want
-    ICorDebugValue* pExtValue;
-    IfFailThrow(pRefValue->Dereference(&pExtValue));
-    return pExtValue;
+
+    return pRefValue;
 }
 
 // Gets the size om bytes of a value from its type. If the value is complex, we assume it is represented as 
@@ -1730,7 +1735,7 @@ CordbObjectValue::CordbObjectValue(CordbAppDomain *          pAppdomain,
       m_info(*pObjectData),
       m_pObjectCopy(NULL), m_objectLocalVars(NULL), m_stringBuffer(NULL),
       m_valueHome(pAppdomain->GetProcess(), remoteValue), 
-      m_fIsExceptionObject(FALSE), m_fIsRcw(FALSE)
+      m_fIsExceptionObject(FALSE), m_fIsRcw(FALSE), m_fIsDelegate(FALSE)
 {
     _ASSERTE(pAppdomain != NULL);
 
@@ -1754,6 +1759,15 @@ CordbObjectValue::CordbObjectValue(CordbAppDomain *          pAppdomain,
 
     if (hr == S_OK)
         m_fIsRcw = TRUE;
+
+    hr = S_FALSE;
+    ALLOW_DATATARGET_MISSING_MEMORY
+    (
+        hr = IsDelegate();
+    );
+
+    if (hr == S_OK)
+        m_fIsDelegate = TRUE;
 } // CordbObjectValue::CordbObjectValue
 
 // destructor
@@ -1827,6 +1841,10 @@ HRESULT CordbObjectValue::QueryInterface(REFIID id, void **pInterface)
     {
         *pInterface = static_cast<ICorDebugComObjectValue*>(this);
     }
+    else if (id == IID_ICorDebugDelegateObjectValue && m_fIsDelegate)
+    {
+        *pInterface = static_cast<ICorDebugDelegateObjectValue*>(this);
+    }
     else if (id == IID_IUnknown)
     {
         *pInterface = static_cast<IUnknown*>(static_cast<ICorDebugObjectValue*>(this));
@@ -2517,6 +2535,166 @@ HRESULT CordbObjectValue::IsRcw()
     return hr;
 }
 
+HRESULT CordbObjectValue::IsDelegate()
+{
+    HRESULT hr = S_OK;
+
+    if (m_info.objTypeData.elementType != ELEMENT_TYPE_CLASS)
+    {
+        hr = S_FALSE;
+    }
+    else
+    {
+        CORDB_ADDRESS objAddr = m_valueHome.GetAddress();
+
+        if (objAddr == NULL)
+        {
+            // object is a literal
+            hr = S_FALSE;
+        }
+        else
+        {
+            IDacDbiInterface *pDAC = GetProcess()->GetDAC();
+
+            VMPTR_Object vmObj = pDAC->GetObject(objAddr);
+            BOOL fIsDelegate = pDAC->IsDelegate(vmObj);
+
+            if (!fIsDelegate)
+                hr = S_FALSE;
+        }
+    }
+
+    return hr;
+}
+
+HRESULT IsSupportedDelegateHelper(IDacDbiInterface::DelegateType delType)
+{
+    switch (delType)
+    {
+    case IDacDbiInterface::DelegateType::kClosedDelegate:
+    case IDacDbiInterface::DelegateType::kOpenDelegate:
+        return S_OK;
+    default:
+        return CORDBG_E_UNSUPPORTED_DELEGATE;
+    }
+}
+
+HRESULT CordbObjectValue::GetTargetHelper(ICorDebugReferenceValue **ppTarget)
+{
+    IDacDbiInterface::DelegateType delType;
+    VMPTR_Object pDelegateObj;
+    VMPTR_Object pDelegateTargetObj;
+    VMPTR_AppDomain pAppDomainOfTarget;
+
+    CORDB_ADDRESS delegateAddr = m_valueHome.GetAddress();
+
+    IDacDbiInterface *pDAC = GetProcess()->GetDAC();
+    pDelegateObj = pDAC->GetObject(delegateAddr);
+
+    HRESULT hr = pDAC->GetDelegateType(pDelegateObj, &delType);
+    if (hr != S_OK)
+        return hr;
+
+    hr = IsSupportedDelegateHelper(delType);
+    if (hr != S_OK)
+        return hr;
+
+    hr = pDAC->GetDelegateTargetObject(delType, pDelegateObj, &pDelegateTargetObj, &pAppDomainOfTarget);
+    if (hr != S_OK || pDelegateTargetObj.IsNull())
+    {
+        *ppTarget = NULL;
+        return hr;
+    }
+
+    RSLockHolder lockHolder(GetProcess()->GetProcessLock());
+    RSSmartPtr<CordbAppDomain> pCordbAppDomForTarget(GetProcess()->LookupOrCreateAppDomain(pAppDomainOfTarget));
+    RSSmartPtr<CordbReferenceValue> targetObjRefVal(CordbValue::CreateHeapReferenceValue(pCordbAppDomForTarget, pDelegateTargetObj));
+    *ppTarget = static_cast<ICorDebugReferenceValue*>(targetObjRefVal.GetValue());
+    targetObjRefVal->ExternalAddRef();
+
+    return S_OK;
+}
+
+HRESULT CordbObjectValue::GetFunctionHelper(ICorDebugFunction **ppFunction)
+{
+    IDacDbiInterface::DelegateType delType;
+    VMPTR_Object pDelegateObj;
+
+    *ppFunction = NULL;
+    CORDB_ADDRESS delegateAddr = m_valueHome.GetAddress();
+
+    IDacDbiInterface *pDAC = GetProcess()->GetDAC();
+    pDelegateObj = pDAC->GetObject(delegateAddr);
+
+    HRESULT hr = pDAC->GetDelegateType(pDelegateObj, &delType);
+    if (hr != S_OK)
+        return hr;
+
+    hr = IsSupportedDelegateHelper(delType);
+    if (hr != S_OK)
+        return hr;
+
+    mdMethodDef functionMethodDef = 0;
+    VMPTR_DomainFile functionDomainFile;
+    NativeCodeFunctionData nativeCodeForDelFunc;
+
+    hr = pDAC->GetDelegateFunctionData(delType, pDelegateObj, &functionDomainFile, &functionMethodDef);
+    if (hr != S_OK)
+        return hr;
+
+    // TODO: How to ensure results are sanitized?
+    // Also, this is expensive. Do we really care that much about this?
+    pDAC->GetNativeCodeInfo(functionDomainFile, functionMethodDef, &nativeCodeForDelFunc);
+
+    RSSmartPtr<CordbModule> funcModule(GetProcess()->LookupOrCreateModule(functionDomainFile));
+    RSSmartPtr<CordbFunction> func;
+    {
+        RSLockHolder lockHolder(GetProcess()->GetProcessLock());
+        func.Assign(funcModule->LookupOrCreateFunction(functionMethodDef, nativeCodeForDelFunc.encVersion));
+    }
+
+    *ppFunction = static_cast<ICorDebugFunction*> (func.GetValue());
+    func->ExternalAddRef();
+
+    return S_OK;
+}
+
+HRESULT CordbObjectValue::GetTarget(ICorDebugReferenceValue **ppObject)
+{
+    PUBLIC_API_ENTRY(this);
+    FAIL_IF_NEUTERED(this);
+    VALIDATE_POINTER_TO_OBJECT(ppObject, ICorDebugReferenceValue **);
+    ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
+    _ASSERTE(m_fIsDelegate);
+
+    HRESULT hr = S_OK;
+
+    EX_TRY
+    {
+        hr = GetTargetHelper(ppObject);
+    }
+    EX_CATCH_HRESULT(hr);
+    return hr;
+}
+
+HRESULT CordbObjectValue::GetFunction(ICorDebugFunction **ppFunction)
+{
+    PUBLIC_API_ENTRY(this);
+    FAIL_IF_NEUTERED(this);
+    VALIDATE_POINTER_TO_OBJECT(ppFunction, ICorDebugFunction **);
+    ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
+    _ASSERTE(m_fIsDelegate);
+
+    HRESULT hr = S_OK;
+
+    EX_TRY
+    {
+        hr = GetFunctionHelper(ppFunction);
+    }
+    EX_CATCH_HRESULT(hr)
+    return hr;
+}
+
 HRESULT CordbObjectValue::GetCachedInterfaceTypes(
                         BOOL bIInspectableOnly, 
                         ICorDebugTypeEnum * * ppInterfacesEnum)
index a6cfcf9..6e4a93f 100644 (file)
@@ -101,6 +101,7 @@ class CordbRCEventThread;
 class CordbRegisterSet;
 class CordbNativeFrame;
 class CordbObjectValue;
+class CordbReferenceValue;
 class CordbEnCErrorInfo;
 class CordbEnCErrorInfoEnum;
 class Instantiation;
@@ -8755,6 +8756,9 @@ public:
     static ICorDebugValue* CreateHeapValue(CordbAppDomain* pAppDomain,
                                            VMPTR_Object vmObj);
 
+    // Creates a proper CordbReferenceValue instance based on the given remote heap object
+    static CordbReferenceValue* CreateHeapReferenceValue(CordbAppDomain* pAppDomain,
+                                                         VMPTR_Object vmObj);
 
     // Returns a pointer to the ValueHome field of this instance of CordbValue if one exists or NULL
     // otherwise. Therefore, this also tells us indirectly whether this instance of CordbValue is also an
@@ -9159,7 +9163,8 @@ class CordbObjectValue : public CordbValue,
                          public ICorDebugHeapValue2,
                          public ICorDebugHeapValue3,
                          public ICorDebugExceptionObjectValue,
-                         public ICorDebugComObjectValue
+                         public ICorDebugComObjectValue,
+                         public ICorDebugDelegateObjectValue
 {
 public:
     
@@ -9287,6 +9292,12 @@ public:
                         CORDB_ADDRESS * ptrs);
 
     //-----------------------------------------------------------
+    // ICorDebugComObjectValue
+    //-----------------------------------------------------------
+    COM_METHOD GetTarget(ICorDebugReferenceValue** ppObject);
+    COM_METHOD GetFunction(ICorDebugFunction** ppFunction);
+
+    //-----------------------------------------------------------
     // Non-COM methods
     //-----------------------------------------------------------
 
@@ -9324,6 +9335,12 @@ private:
     HRESULT IsRcw();
 
     BOOL                     m_fIsRcw;
+
+    HRESULT IsDelegate();
+    HRESULT GetFunctionHelper(ICorDebugFunction **ppFunction);
+    HRESULT GetTargetHelper(ICorDebugReferenceValue **ppTarget);
+
+    BOOL                     m_fIsDelegate;
 };
 
 /* ------------------------------------------------------------------------- *
index bd532a7..77cc74d 100644 (file)
@@ -2710,6 +2710,45 @@ public:
     virtual
         HRESULT EnableGCNotificationEvents(BOOL fEnable) = 0;
 
+
+    typedef enum
+    {
+        kClosedDelegate,
+        kOpenDelegate,
+        kOpenInstanceVSD,
+        kClosedStaticWithScpecialSig,
+        kTrueMulticastDelegate,
+        kSecureDelegate,
+        kUnmanagedFunctionDelegate,
+        kUnknownDelegateType
+    } DelegateType;
+
+    // Returns true if the object is a type deriving from System.MulticastDelegate
+    //
+    // Arguments:
+    //    vmObject - pointer to runtime object to query for.
+    //
+    virtual
+    BOOL IsDelegate(VMPTR_Object vmObject) = 0;
+
+    // Returns the delegate type
+    virtual
+    HRESULT GetDelegateType(VMPTR_Object delegateObject, DelegateType *delegateType) = 0;
+
+    virtual
+    HRESULT GetDelegateFunctionData(
+        DelegateType delegateType,
+        VMPTR_Object delegateObject,
+        OUT VMPTR_DomainFile *ppFunctionDomainFile,
+        OUT mdMethodDef *pMethodDef) = 0;
+
+    virtual
+    HRESULT GetDelegateTargetObject(
+        DelegateType delegateType,
+        VMPTR_Object delegateObject,
+        OUT VMPTR_Object *ppTargetObj,
+        OUT VMPTR_AppDomain *ppTargetAppDomain) = 0;
+
     // The following tag tells the DD-marshalling tool to stop scanning.
     // END_MARSHAL
     
index ce1bf4a..c0dcb76 100644 (file)
@@ -6491,6 +6491,40 @@ interface ICorDebugObjectValue2 : IUnknown
                                     [out] ICorDebugType **ppType);
 };
 
+[
+    object,
+    local,
+    uuid(3AF70CC7-6047-47F6-A5C5-090A1A622638),
+    pointer_default(unique)
+]
+interface ICorDebugDelegateObjectValue : IUnknown
+{
+    /*
+     * GetTarget retrieves the object on which the delegate calls the function.
+     * Returns:
+     *  - S_OK:
+     *      - The ICorDebugReferenceValue object targeted by the function.
+     *      - NULL if the delegate function is a static function or an open delegate
+     *  - HRESULT CORDBG_E_UNSUPPORTED_DELEGATE for curently unsupported delegates.
+     *      In this case, the value of ppObject should not be used. Some of these
+     *      include: Secure wrappers, Open Virual delegates.
+     */
+    HRESULT GetTarget([out] ICorDebugReferenceValue **ppObject);
+
+    /*
+     * GetFunction returns the function that gets run by the delegate.
+    *  - S_OK:
+     *      - The ICorDebugFunction function for the function the delegate would invoke.
+     *      - There are a few cases where the ICorDebugFunction can be different from what's expected,
+     *        such as generic methods, which won't contain the instantiation. 
+     *  - HRESULT CORDBG_E_UNSUPPORTED_DELEGATE for curently unsupported delegates.
+     *      In this case, the value of ppObject should not be used. Some of these
+     *      include: Secure wrappers, Open Virual delegates.
+     */
+    HRESULT GetFunction([out] ICorDebugFunction **ppFunction);
+}
+
+
 /*
  * ICorDebugBoxValue is a subclass of ICorDebugValue which
  * represents a boxed value class object.
index d8b8f63..38efe0d 100644 (file)
   <Comment>Couldn't find a native image.</Comment>
 </HRESULT>
 
+<HRESULT NumericValue="0x80131c68">
+  <SymbolicName>CORDBG_E_UNSUPPORTED_DELEGATE</SymbolicName>
+  <Message>"The delegate contains a delegate currently not supported by the API."</Message>
+  <Comment>The delegate contains a delegate currently not supported by the API.</Comment>
+</HRESULT>
+
 <HRESULT NumericValue="0x80131d02">
        <SymbolicName>PEFMT_E_64BIT</SymbolicName>
        <Message>"File is PE32+."</Message>
index ee8ef67..ebdf18e 100644 (file)
@@ -312,6 +312,7 @@ BEGIN
        MSG_FOR_URT_HR(CORDBG_E_MISSING_DEBUGGER_EXPORTS) "The debuggee memory space does not have the expected debugging export table."
        MSG_FOR_URT_HR(CORDBG_E_DATA_TARGET_ERROR) "Failure when calling a data target method."
        MSG_FOR_URT_HR(CORDBG_E_NO_IMAGE_AVAILABLE) "Couldn't find a native image."
+       MSG_FOR_URT_HR(CORDBG_E_UNSUPPORTED_DELEGATE) "The delegate contains a delegate currently not supported by the API."
        MSG_FOR_URT_HR(PEFMT_E_64BIT) "File is PE32+."
        MSG_FOR_URT_HR(PEFMT_E_32BIT) "File is PE32"
        MSG_FOR_URT_HR(NGEN_E_SYS_ASM_NI_MISSING) "NGen cannot proceed because Mscorlib.dll does not have a native image"
index f7f625a..65ed624 100644 (file)
@@ -8,7 +8,7 @@
  /* File created by MIDL compiler version 8.01.0622 */
 /* at Mon Jan 18 19:14:07 2038
  */
-/* Compiler settings for D:/dotnet/coreclr/src/inc/cordebug.idl:
+/* Compiler settings for E:/repos/coreclr2/src/inc/cordebug.idl:
     Oicf, W1, Zp8, env=Win32 (32b run), target_arch=X86 8.01.0622 
     protocol : dce , ms_ext, c_ext, robust
     error checks: allocation ref bounds_check enum stub_data 
@@ -364,6 +364,9 @@ MIDL_DEFINE_GUID(IID, IID_ICorDebugObjectValue,0x18AD3D6E,0xB7D2,0x11d2,0xBD,0x0
 MIDL_DEFINE_GUID(IID, IID_ICorDebugObjectValue2,0x49E4A320,0x4A9B,0x4eca,0xB1,0x05,0x22,0x9F,0xB7,0xD5,0x00,0x9F);
 
 
+MIDL_DEFINE_GUID(IID, IID_ICorDebugDelegateObjectValue,0x3AF70CC7,0x6047,0x47F6,0xA5,0xC5,0x09,0x0A,0x1A,0x62,0x26,0x38);
+
+
 MIDL_DEFINE_GUID(IID, IID_ICorDebugBoxValue,0xCC7BCAFC,0x8A68,0x11d2,0x98,0x3C,0x00,0x00,0xF8,0x08,0x34,0x2D);
 
 
index a974257..96dc9c0 100644 (file)
@@ -6,7 +6,7 @@
  /* File created by MIDL compiler version 8.01.0622 */
 /* at Mon Jan 18 19:14:07 2038
  */
-/* Compiler settings for F:/Dev/coreclr/src/inc/cordebug.idl:
+/* Compiler settings for E:/repos/coreclr2/src/inc/cordebug.idl:
     Oicf, W1, Zp8, env=Win32 (32b run), target_arch=X86 8.01.0622 
     protocol : dce , ms_ext, c_ext, robust
     error checks: allocation ref bounds_check enum stub_data 
@@ -738,6 +738,13 @@ typedef interface ICorDebugObjectValue2 ICorDebugObjectValue2;
 #endif         /* __ICorDebugObjectValue2_FWD_DEFINED__ */
 
 
+#ifndef __ICorDebugDelegateObjectValue_FWD_DEFINED__
+#define __ICorDebugDelegateObjectValue_FWD_DEFINED__
+typedef interface ICorDebugDelegateObjectValue ICorDebugDelegateObjectValue;
+
+#endif         /* __ICorDebugDelegateObjectValue_FWD_DEFINED__ */
+
+
 #ifndef __ICorDebugBoxValue_FWD_DEFINED__
 #define __ICorDebugBoxValue_FWD_DEFINED__
 typedef interface ICorDebugBoxValue ICorDebugBoxValue;
@@ -14686,6 +14693,96 @@ EXTERN_C const IID IID_ICorDebugObjectValue2;
 #endif         /* __ICorDebugObjectValue2_INTERFACE_DEFINED__ */
 
 
+#ifndef __ICorDebugDelegateObjectValue_INTERFACE_DEFINED__
+#define __ICorDebugDelegateObjectValue_INTERFACE_DEFINED__
+
+/* interface ICorDebugDelegateObjectValue */
+/* [unique][uuid][local][object] */
+
+
+EXTERN_C const IID IID_ICorDebugDelegateObjectValue;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+    MIDL_INTERFACE("3AF70CC7-6047-47F6-A5C5-090A1A622638")
+    ICorDebugDelegateObjectValue : public IUnknown
+    {
+    public:
+        virtual HRESULT STDMETHODCALLTYPE GetTarget(
+            /* [out] */ ICorDebugReferenceValue **ppObject) = 0;
+
+        virtual HRESULT STDMETHODCALLTYPE GetFunction(
+            /* [out] */ ICorDebugFunction **ppFunction) = 0;
+
+    };
+
+
+#else  /* C style interface */
+
+    typedef struct ICorDebugDelegateObjectValueVtbl
+    {
+        BEGIN_INTERFACE
+
+        HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+            ICorDebugDelegateObjectValue * This,
+            /* [in] */ REFIID riid,
+            /* [annotation][iid_is][out] */
+            _COM_Outptr_  void **ppvObject);
+
+        ULONG ( STDMETHODCALLTYPE *AddRef )(
+            ICorDebugDelegateObjectValue * This);
+
+        ULONG ( STDMETHODCALLTYPE *Release )(
+            ICorDebugDelegateObjectValue * This);
+
+        HRESULT ( STDMETHODCALLTYPE *GetTarget )(
+            ICorDebugDelegateObjectValue * This,
+            /* [out] */ ICorDebugReferenceValue **ppObject);
+
+        HRESULT ( STDMETHODCALLTYPE *GetFunction )(
+            ICorDebugDelegateObjectValue * This,
+            /* [out] */ ICorDebugFunction **ppFunction);
+
+        END_INTERFACE
+    } ICorDebugDelegateObjectValueVtbl;
+
+    interface ICorDebugDelegateObjectValue
+    {
+        CONST_VTBL struct ICorDebugDelegateObjectValueVtbl *lpVtbl;
+    };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorDebugDelegateObjectValue_QueryInterface(This,riid,ppvObject)       \
+    ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorDebugDelegateObjectValue_AddRef(This)      \
+    ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorDebugDelegateObjectValue_Release(This)     \
+    ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorDebugDelegateObjectValue_GetTarget(This,ppObject)  \
+    ( (This)->lpVtbl -> GetTarget(This,ppObject) )
+
+#define ICorDebugDelegateObjectValue_GetFunction(This,ppFunction)      \
+    ( (This)->lpVtbl -> GetFunction(This,ppFunction) )
+
+#endif /* COBJMACROS */
+
+
+#endif         /* C style interface */
+
+
+
+
+#endif         /* __ICorDebugDelegateObjectValue_INTERFACE_DEFINED__ */
+
+
 #ifndef __ICorDebugBoxValue_INTERFACE_DEFINED__
 #define __ICorDebugBoxValue_INTERFACE_DEFINED__
 
@@ -14810,15 +14907,15 @@ EXTERN_C const IID IID_ICorDebugBoxValue;
 #endif         /* __ICorDebugBoxValue_INTERFACE_DEFINED__ */
 
 
-/* interface __MIDL_itf_cordebug_0000_0099 */
+/* interface __MIDL_itf_cordebug_0000_0100 */
 /* [local] */ 
 
 #pragma warning(push)
 #pragma warning(disable:28718) 
 
 
-extern RPC_IF_HANDLE __MIDL_itf_cordebug_0000_0099_v0_0_c_ifspec;
-extern RPC_IF_HANDLE __MIDL_itf_cordebug_0000_0099_v0_0_s_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_cordebug_0000_0100_v0_0_c_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_cordebug_0000_0100_v0_0_s_ifspec;
 
 #ifndef __ICorDebugStringValue_INTERFACE_DEFINED__
 #define __ICorDebugStringValue_INTERFACE_DEFINED__
@@ -14958,14 +15055,14 @@ EXTERN_C const IID IID_ICorDebugStringValue;
 #endif         /* __ICorDebugStringValue_INTERFACE_DEFINED__ */
 
 
-/* interface __MIDL_itf_cordebug_0000_0100 */
+/* interface __MIDL_itf_cordebug_0000_0101 */
 /* [local] */ 
 
 #pragma warning(pop)
 
 
-extern RPC_IF_HANDLE __MIDL_itf_cordebug_0000_0100_v0_0_c_ifspec;
-extern RPC_IF_HANDLE __MIDL_itf_cordebug_0000_0100_v0_0_s_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_cordebug_0000_0101_v0_0_c_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_cordebug_0000_0101_v0_0_s_ifspec;
 
 #ifndef __ICorDebugArrayValue_INTERFACE_DEFINED__
 #define __ICorDebugArrayValue_INTERFACE_DEFINED__
@@ -17740,15 +17837,15 @@ EXTERN_C const IID IID_ICorDebugBlockingObjectEnum;
 #endif         /* __ICorDebugBlockingObjectEnum_INTERFACE_DEFINED__ */
 
 
-/* interface __MIDL_itf_cordebug_0000_0124 */
+/* interface __MIDL_itf_cordebug_0000_0125 */
 /* [local] */ 
 
 #pragma warning(push)
 #pragma warning(disable:28718)
 
 
-extern RPC_IF_HANDLE __MIDL_itf_cordebug_0000_0124_v0_0_c_ifspec;
-extern RPC_IF_HANDLE __MIDL_itf_cordebug_0000_0124_v0_0_s_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_cordebug_0000_0125_v0_0_c_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_cordebug_0000_0125_v0_0_s_ifspec;
 
 #ifndef __ICorDebugMDA_INTERFACE_DEFINED__
 #define __ICorDebugMDA_INTERFACE_DEFINED__
@@ -17888,7 +17985,7 @@ EXTERN_C const IID IID_ICorDebugMDA;
 #endif         /* __ICorDebugMDA_INTERFACE_DEFINED__ */
 
 
-/* interface __MIDL_itf_cordebug_0000_0125 */
+/* interface __MIDL_itf_cordebug_0000_0126 */
 /* [local] */ 
 
 #pragma warning(pop)
@@ -17896,8 +17993,8 @@ EXTERN_C const IID IID_ICorDebugMDA;
 #pragma warning(disable:28718) 
 
 
-extern RPC_IF_HANDLE __MIDL_itf_cordebug_0000_0125_v0_0_c_ifspec;
-extern RPC_IF_HANDLE __MIDL_itf_cordebug_0000_0125_v0_0_s_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_cordebug_0000_0126_v0_0_c_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_cordebug_0000_0126_v0_0_s_ifspec;
 
 #ifndef __ICorDebugEditAndContinueErrorInfo_INTERFACE_DEFINED__
 #define __ICorDebugEditAndContinueErrorInfo_INTERFACE_DEFINED__
@@ -18013,14 +18110,14 @@ EXTERN_C const IID IID_ICorDebugEditAndContinueErrorInfo;
 #endif         /* __ICorDebugEditAndContinueErrorInfo_INTERFACE_DEFINED__ */
 
 
-/* interface __MIDL_itf_cordebug_0000_0126 */
+/* interface __MIDL_itf_cordebug_0000_0127 */
 /* [local] */ 
 
 #pragma warning(pop)
 
 
-extern RPC_IF_HANDLE __MIDL_itf_cordebug_0000_0126_v0_0_c_ifspec;
-extern RPC_IF_HANDLE __MIDL_itf_cordebug_0000_0126_v0_0_s_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_cordebug_0000_0127_v0_0_c_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_cordebug_0000_0127_v0_0_s_ifspec;
 
 #ifndef __ICorDebugEditAndContinueSnapshot_INTERFACE_DEFINED__
 #define __ICorDebugEditAndContinueSnapshot_INTERFACE_DEFINED__
index 7bd0c10..15dc301 100644 (file)
 #define CORDBG_E_MISSING_DEBUGGER_EXPORTS EMAKEHR(0x1c4f)
 #define CORDBG_E_DATA_TARGET_ERROR EMAKEHR(0x1c61)
 #define CORDBG_E_NO_IMAGE_AVAILABLE EMAKEHR(0x1c64)
+#define CORDBG_E_UNSUPPORTED_DELEGATE EMAKEHR(0x1c68)
 #define PEFMT_E_64BIT EMAKEHR(0x1d02)
 #define PEFMT_E_32BIT EMAKEHR(0x1d0b)
 #define NGEN_E_SYS_ASM_NI_MISSING EMAKEHR(0x1f06)
index a7ed685..7ee85b6 100644 (file)
@@ -1617,6 +1617,9 @@ extern "C" void * _ReturnAddress(void);
 FCIMPL3(void, COMDelegate::DelegateConstruct, Object* refThisUNSAFE, Object* targetUNSAFE, PCODE method)
 {
     FCALL_CONTRACT;
+    // If you modify this logic, please update DacDbiInterfaceImpl::GetDelegateType, DacDbiInterfaceImpl::GetDelegateType,
+    // DacDbiInterfaceImpl::GetDelegateFunctionData, and DacDbiInterfaceImpl::GetDelegateTargetObject.
+
 
     struct _gc
     {
@@ -1785,6 +1788,9 @@ MethodDesc *COMDelegate::GetMethodDesc(OBJECTREF orDelegate)
     }
     CONTRACTL_END;
 
+    // If you modify this logic, please update DacDbiInterfaceImpl::GetDelegateType, DacDbiInterfaceImpl::GetDelegateType,
+    // DacDbiInterfaceImpl::GetDelegateFunctionData, and DacDbiInterfaceImpl::GetDelegateTargetObject.
+
     MethodDesc *pMethodHandle = NULL;
 
     DELEGATEREF thisDel = (DELEGATEREF) orDelegate;
@@ -3060,6 +3066,10 @@ MethodDesc* COMDelegate::GetDelegateCtor(TypeHandle delegateType, MethodDesc *pT
     //
     // Another is to pass a gchandle to the delegate ctor. This is fastest, but only works if we can predict the gc handle at this time. 
     //  We will use this for the non secure variants
+    //
+    // If you modify this logic, please update DacDbiInterfaceImpl::GetDelegateType, DacDbiInterfaceImpl::GetDelegateType,
+    // DacDbiInterfaceImpl::GetDelegateFunctionData, and DacDbiInterfaceImpl::GetDelegateTargetObject.
+
 
     if (invokeArgCount == methodArgCount) 
     {
index 18044b5..6abe996 100644 (file)
@@ -153,6 +153,7 @@ typedef DPTR(class NDirectMethodDesc)   PTR_NDirectMethodDesc;
 typedef VPTR(class Thread)              PTR_Thread;
 typedef DPTR(class Object)              PTR_Object;
 typedef DPTR(PTR_Object)                PTR_PTR_Object;
+typedef DPTR(class DelegateObject)      PTR_DelegateObject;
 typedef DPTR(class ObjHeader)           PTR_ObjHeader;
 typedef DPTR(class Precode)             PTR_Precode;
 typedef VPTR(class ReflectionModule)    PTR_ReflectionModule;