summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJuan Hoyos <juan.hoyos@microsoft.com>2019-06-26 10:11:56 -0700
committerGitHub <noreply@github.com>2019-06-26 10:11:56 -0700
commit394edf40a089ac3fae5415dba8235b89c7133319 (patch)
treeb345f3742355429ce2ea9d7790fe37b4ee6fe6f3
parentbe31aaea6402390d808fa41d4cd1fa9b68f4cdd0 (diff)
downloadcoreclr-394edf40a089ac3fae5415dba8235b89c7133319.tar.gz
coreclr-394edf40a089ac3fae5415dba8235b89c7133319.tar.bz2
coreclr-394edf40a089ac3fae5415dba8235b89c7133319.zip
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
-rw-r--r--src/debug/daccess/dacdbiimpl.cpp195
-rw-r--r--src/debug/daccess/dacdbiimpl.h27
-rw-r--r--src/debug/di/divalue.cpp192
-rw-r--r--src/debug/di/rspriv.h19
-rw-r--r--src/debug/inc/dacdbiinterface.h39
-rw-r--r--src/inc/cordebug.idl34
-rw-r--r--src/inc/corerror.xml6
-rw-r--r--src/pal/prebuilt/corerror/mscorurt.rc1
-rw-r--r--src/pal/prebuilt/idl/cordebug_i.cpp5
-rw-r--r--src/pal/prebuilt/inc/cordebug.h129
-rw-r--r--src/pal/prebuilt/inc/corerror.h1
-rw-r--r--src/vm/comdelegate.cpp10
-rw-r--r--src/vm/common.h1
13 files changed, 634 insertions, 25 deletions
diff --git a/src/debug/daccess/dacdbiimpl.cpp b/src/debug/daccess/dacdbiimpl.cpp
index 8d02590727..4ef3bc7b20 100644
--- a/src/debug/daccess/dacdbiimpl.cpp
+++ b/src/debug/daccess/dacdbiimpl.cpp
@@ -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;
diff --git a/src/debug/daccess/dacdbiimpl.h b/src/debug/daccess/dacdbiimpl.h
index ae88efeb33..b3ca37f127 100644
--- a/src/debug/daccess/dacdbiimpl.h
+++ b/src/debug/daccess/dacdbiimpl.h
@@ -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
diff --git a/src/debug/di/divalue.cpp b/src/debug/di/divalue.cpp
index 59cd382085..a8ef5652e7 100644
--- a/src/debug/di/divalue.cpp
+++ b/src/debug/di/divalue.cpp
@@ -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)
diff --git a/src/debug/di/rspriv.h b/src/debug/di/rspriv.h
index a6cfcf9749..6e4a93fb90 100644
--- a/src/debug/di/rspriv.h
+++ b/src/debug/di/rspriv.h
@@ -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;
};
/* ------------------------------------------------------------------------- *
diff --git a/src/debug/inc/dacdbiinterface.h b/src/debug/inc/dacdbiinterface.h
index bd532a7c3d..77cc74d678 100644
--- a/src/debug/inc/dacdbiinterface.h
+++ b/src/debug/inc/dacdbiinterface.h
@@ -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
diff --git a/src/inc/cordebug.idl b/src/inc/cordebug.idl
index ce1bf4a49e..c0dcb7670b 100644
--- a/src/inc/cordebug.idl
+++ b/src/inc/cordebug.idl
@@ -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.
diff --git a/src/inc/corerror.xml b/src/inc/corerror.xml
index d8b8f6361e..38efe0d6de 100644
--- a/src/inc/corerror.xml
+++ b/src/inc/corerror.xml
@@ -2183,6 +2183,12 @@
<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>
diff --git a/src/pal/prebuilt/corerror/mscorurt.rc b/src/pal/prebuilt/corerror/mscorurt.rc
index ee8ef677a7..ebdf18e2fb 100644
--- a/src/pal/prebuilt/corerror/mscorurt.rc
+++ b/src/pal/prebuilt/corerror/mscorurt.rc
@@ -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"
diff --git a/src/pal/prebuilt/idl/cordebug_i.cpp b/src/pal/prebuilt/idl/cordebug_i.cpp
index f7f625a805..65ed624a75 100644
--- a/src/pal/prebuilt/idl/cordebug_i.cpp
+++ b/src/pal/prebuilt/idl/cordebug_i.cpp
@@ -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);
diff --git a/src/pal/prebuilt/inc/cordebug.h b/src/pal/prebuilt/inc/cordebug.h
index a9742571a7..96dc9c0eb1 100644
--- a/src/pal/prebuilt/inc/cordebug.h
+++ b/src/pal/prebuilt/inc/cordebug.h
@@ -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__
diff --git a/src/pal/prebuilt/inc/corerror.h b/src/pal/prebuilt/inc/corerror.h
index 7bd0c10221..15dc301546 100644
--- a/src/pal/prebuilt/inc/corerror.h
+++ b/src/pal/prebuilt/inc/corerror.h
@@ -383,6 +383,7 @@
#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)
diff --git a/src/vm/comdelegate.cpp b/src/vm/comdelegate.cpp
index a7ed685c3e..7ee85b6136 100644
--- a/src/vm/comdelegate.cpp
+++ b/src/vm/comdelegate.cpp
@@ -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)
{
diff --git a/src/vm/common.h b/src/vm/common.h
index 18044b5b13..6abe996e90 100644
--- a/src/vm/common.h
+++ b/src/vm/common.h
@@ -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;