From 394edf40a089ac3fae5415dba8235b89c7133319 Mon Sep 17 00:00:00 2001 From: Juan Hoyos Date: Wed, 26 Jun 2019 10:11:56 -0700 Subject: [PATCH] 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 --- src/debug/daccess/dacdbiimpl.cpp | 195 ++++++++++++++++++++++++++++++++++ src/debug/daccess/dacdbiimpl.h | 27 +++++ src/debug/di/divalue.cpp | 192 +++++++++++++++++++++++++++++++-- src/debug/di/rspriv.h | 19 +++- src/debug/inc/dacdbiinterface.h | 39 +++++++ src/inc/cordebug.idl | 34 ++++++ src/inc/corerror.xml | 6 ++ src/pal/prebuilt/corerror/mscorurt.rc | 1 + src/pal/prebuilt/idl/cordebug_i.cpp | 5 +- src/pal/prebuilt/inc/cordebug.h | 129 +++++++++++++++++++--- src/pal/prebuilt/inc/corerror.h | 1 + src/vm/comdelegate.cpp | 10 ++ src/vm/common.h | 1 + 13 files changed, 634 insertions(+), 25 deletions(-) diff --git a/src/debug/daccess/dacdbiimpl.cpp b/src/debug/daccess/dacdbiimpl.cpp index 8d02590..4ef3bc7 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(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(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(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(delegateObject.GetDacPtr()); + + switch (delegateType) + { + case kClosedDelegate: + { + PTR_Object pRemoteTargetObj = OBJECTREFToObject(pDelObj->GetTarget()); + ppTargetObj->SetDacTargetPtr(pRemoteTargetObj.GetAddr()); + ppTargetAppDomain->SetDacTargetPtr(dac_cast(pRemoteTargetObj->GetGCSafeMethodTable()->GetDomain()->AsAppDomain())); + break; + } + + default: + ppTargetObj->SetDacTargetPtr(NULL); + ppTargetAppDomain->SetDacTargetPtr(dac_cast(pDelObj->GetGCSafeMethodTable()->GetDomain()->AsAppDomain())); + break; + } + + return hr; +} + void DacDbiInterfaceImpl::GetStackFramesFromException(VMPTR_Object vmObject, DacDbiArrayList& dacStackFrames) { DD_ENTER_MAY_THROW; diff --git a/src/debug/daccess/dacdbiimpl.h b/src/debug/daccess/dacdbiimpl.h index ae88efe..b3ca37f 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 * 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 59cd382..a8ef565 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 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(this); } + else if (id == IID_ICorDebugDelegateObjectValue && m_fIsDelegate) + { + *pInterface = static_cast(this); + } else if (id == IID_IUnknown) { *pInterface = static_cast(static_cast(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 pCordbAppDomForTarget(GetProcess()->LookupOrCreateAppDomain(pAppDomainOfTarget)); + RSSmartPtr targetObjRefVal(CordbValue::CreateHeapReferenceValue(pCordbAppDomForTarget, pDelegateTargetObj)); + *ppTarget = static_cast(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 funcModule(GetProcess()->LookupOrCreateModule(functionDomainFile)); + RSSmartPtr func; + { + RSLockHolder lockHolder(GetProcess()->GetProcessLock()); + func.Assign(funcModule->LookupOrCreateFunction(functionMethodDef, nativeCodeForDelFunc.encVersion)); + } + + *ppFunction = static_cast (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 a6cfcf9..6e4a93f 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 bd532a7..77cc74d 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 ce1bf4a..c0dcb76 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 d8b8f63..38efe0d 100644 --- a/src/inc/corerror.xml +++ b/src/inc/corerror.xml @@ -2183,6 +2183,12 @@ Couldn't find a native image. + + CORDBG_E_UNSUPPORTED_DELEGATE + "The delegate contains a delegate currently not supported by the API." + The delegate contains a delegate currently not supported by the API. + + PEFMT_E_64BIT "File is PE32+." diff --git a/src/pal/prebuilt/corerror/mscorurt.rc b/src/pal/prebuilt/corerror/mscorurt.rc index ee8ef67..ebdf18e 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 f7f625a..65ed624 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 a974257..96dc9c0 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 7bd0c10..15dc301 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 a7ed685..7ee85b6 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 18044b5..6abe996 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; -- 2.7.4