Skip to content

Commit

Permalink
Implement unwrapping a ComWrappers CCW when dumping a stowed exceptio…
Browse files Browse the repository at this point in the history
…n. (#36360)
  • Loading branch information
jkoritzinsky committed May 14, 2020
1 parent 4e140f4 commit 10c60fc
Show file tree
Hide file tree
Showing 7 changed files with 129 additions and 14 deletions.
1 change: 1 addition & 0 deletions src/coreclr/src/debug/daccess/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ include_directories(BEFORE ${VM_DIR}/${ARCH_SOURCES_DIR})
include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR})
include_directories(${CLR_DIR}/src/debug/ee)
include_directories(${CLR_DIR}/src/gcdump)
include_directories(${CLR_DIR}/src/interop/inc)

if(CLR_CMAKE_HOST_UNIX)
include_directories(${GENERATED_INCLUDE_DIR})
Expand Down
4 changes: 4 additions & 0 deletions src/coreclr/src/debug/daccess/dacimpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -1456,6 +1456,10 @@ class ClrDataAccess
PTR_IUnknown DACGetCOMIPFromCCW(PTR_ComCallWrapper pCCW, int vtableIndex);
#endif

#ifdef FEATURE_COMWRAPPERS
HRESULT DACTryGetComWrappersObjectFromCCW(CLRDATA_ADDRESS ccwPtr, OBJECTREF* objRef);
#endif

static LONG s_procInit;

public:
Expand Down
22 changes: 19 additions & 3 deletions src/coreclr/src/debug/daccess/enummem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1298,7 +1298,7 @@ HRESULT ClrDataAccess::EnumMemDumpAllThreadsStack(CLRDataEnumMemoryFlags flags)
}


#ifdef FEATURE_COMINTEROP
#if defined(FEATURE_COMINTEROP) || defined(FEATURE_COMWRAPPERS)
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
// WinRT stowed exception holds the (CCW)pointer to a managed exception object.
Expand Down Expand Up @@ -1431,11 +1431,26 @@ HRESULT ClrDataAccess::DumpStowedExceptionObject(CLRDataEnumMemoryFlags flags, C
if (ccwPtr == NULL)
return S_OK;

OBJECTREF managedExceptionObject = NULL;

#ifdef FEATURE_COMINTEROP
// dump the managed exception object wrapped in CCW
// memory of the CCW object itself is dumped later by DacInstanceManager::DumpAllInstances
DacpCCWData ccwData;
GetCCWData(ccwPtr, &ccwData); // this call collects some memory implicitly
DumpManagedExcepObject(flags, OBJECTREF(TO_TADDR(ccwData.managedObject)));
managedExceptionObject = OBJECTREF(CLRDATA_ADDRESS_TO_TADDR(ccwData.managedObject));
#endif
#ifdef FEATURE_COMWRAPPERS
if (managedExceptionObject == NULL)
{
OBJECTREF wrappedObjAddress;
if (DACTryGetComWrappersObjectFromCCW(ccwPtr, &wrappedObjAddress) == S_OK)
{
managedExceptionObject = wrappedObjAddress;
}
}
#endif
DumpManagedExcepObject(flags, managedExceptionObject);

// dump memory of the 2nd slot in the CCW's vtable
// this is used in DACGetCCWFromAddress to identify if the passed in pointer is a valid CCW.
Expand All @@ -1450,7 +1465,8 @@ HRESULT ClrDataAccess::DumpStowedExceptionObject(CLRDataEnumMemoryFlags flags, C

CATCH_ALL_EXCEPT_RETHROW_COR_E_OPERATIONCANCELLED
(
ReportMem(vTableAddress + sizeof(PBYTE)* TEAR_OFF_SLOT, sizeof(TADDR));
ReportMem(vTableAddress, sizeof(TADDR)); // Report the QI slot on the vtable for ComWrappers
ReportMem(vTableAddress + sizeof(PBYTE) * TEAR_OFF_SLOT, sizeof(TADDR)); // Report the AddRef slot on the vtable for built-in CCWs
);

return S_OK;
Expand Down
72 changes: 72 additions & 0 deletions src/coreclr/src/debug/daccess/request.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
#include <comcallablewrapper.h>
#endif // FEATURE_COMINTEROP

#include <interoplibabi.h>

#ifndef TARGET_UNIX
// It is unfortunate having to include this header just to get the definition of GenericModeBlock
#include <msodw.h>
Expand Down Expand Up @@ -4065,6 +4067,76 @@ PTR_IUnknown ClrDataAccess::DACGetCOMIPFromCCW(PTR_ComCallWrapper pCCW, int vtab
}
#endif

#ifdef FEATURE_COMWRAPPERS
HRESULT ClrDataAccess::DACTryGetComWrappersObjectFromCCW(CLRDATA_ADDRESS ccwPtr, OBJECTREF* objRef)
{
if (ccwPtr == 0 || objRef == NULL)
return E_INVALIDARG;

SOSDacEnter();

// Read CCWs QI address and compare it to the managed object wrapper's implementation.
ULONG32 bytesRead = 0;
TADDR ccw = CLRDATA_ADDRESS_TO_TADDR(ccwPtr);
TADDR vTableAddress = NULL;
IfFailGo(m_pTarget->ReadVirtual(ccw, (PBYTE)&vTableAddress, sizeof(TADDR), &bytesRead));
if (bytesRead != sizeof(TADDR)
|| vTableAddress == NULL)
{
hr = E_FAIL;
goto ErrExit;
}

TADDR qiAddress = NULL;
IfFailGo(m_pTarget->ReadVirtual(vTableAddress, (PBYTE)&qiAddress, sizeof(TADDR), &bytesRead));
if (bytesRead != sizeof(TADDR)
|| qiAddress == NULL)
{
hr = E_FAIL;
goto ErrExit;
}


#ifdef TARGET_ARM
// clear the THUMB bit on qiAddress before comparing with known vtable entry
qiAddress &= ~THUMB_CODE;
#endif

if (qiAddress != GetEEFuncEntryPoint(ManagedObjectWrapper_QueryInterface))
{
hr = E_FAIL;
goto ErrExit;
}

// Mask the "dispatch pointer" to get a double pointer to the ManagedObjectWrapper
TADDR managedObjectWrapperPtrPtr = ccw & InteropLib::ABI::DispatchThisPtrMask;

// Return ManagedObjectWrapper as an OBJECTHANDLE. (The OBJECTHANDLE is guaranteed to live at offset 0).
TADDR managedObjectWrapperPtr;
IfFailGo(m_pTarget->ReadVirtual(managedObjectWrapperPtrPtr, (PBYTE)&managedObjectWrapperPtr, sizeof(TADDR), &bytesRead));
if (bytesRead != sizeof(TADDR))
{
hr = E_FAIL;
goto ErrExit;
}

OBJECTHANDLE handle;
IfFailGo(m_pTarget->ReadVirtual(managedObjectWrapperPtr, (PBYTE)&handle, sizeof(OBJECTHANDLE), &bytesRead));
if (bytesRead != sizeof(OBJECTHANDLE))
{
hr = E_FAIL;
goto ErrExit;
}

*objRef = ObjectFromHandle(handle);

SOSDacLeave();

return S_OK;

ErrExit: return hr;
}
#endif

HRESULT ClrDataAccess::GetCCWData(CLRDATA_ADDRESS ccw, struct DacpCCWData *ccwData)
{
Expand Down
3 changes: 3 additions & 0 deletions src/coreclr/src/inc/daccess.h
Original file line number Diff line number Diff line change
Expand Up @@ -629,6 +629,9 @@ typedef struct _DacGlobals
ULONG fn__Unknown_AddRefSpecial;
ULONG fn__Unknown_AddRefInner;
#endif
#ifdef FEATURE_COMWRAPPERS
ULONG fn__ManagedObjectWrapper_QueryInterface;
#endif

// Vtable pointer values for all classes that must
// be instanted using vtable pointers as the identity.
Expand Down
27 changes: 16 additions & 11 deletions src/coreclr/src/interop/comwrappers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
// See the LICENSE file in the project root for more information.

#include "comwrappers.hpp"
#include <interoplibabi.h>
#include <interoplibimports.h>

#include <new> // placement new
Expand Down Expand Up @@ -47,8 +48,8 @@ namespace ABI
};
ABI_ASSERT(sizeof(ComInterfaceDispatch) == sizeof(void*));

const size_t DispatchAlignmentThisPtr = 16; // Should be a power of 2.
const intptr_t DispatchThisPtrMask = ~(DispatchAlignmentThisPtr - 1);
using InteropLib::ABI::DispatchAlignmentThisPtr;
using InteropLib::ABI::DispatchThisPtrMask;
ABI_ASSERT(sizeof(void*) < DispatchAlignmentThisPtr);

const intptr_t AlignmentThisPtrMaxPadding = DispatchAlignmentThisPtr - sizeof(void*);
Expand Down Expand Up @@ -179,17 +180,20 @@ namespace ABI
}
}

namespace
// ManagedObjectWrapper_QueryInterface needs to be visible outside of this compilation unit
// to support the DAC. See code:ClrDataAccess::DACTryGetComWrappersObjectFromCCW for the
// usage in the DAC (look for the GetEEFuncEntryPoint call).
HRESULT STDMETHODCALLTYPE ManagedObjectWrapper_QueryInterface(
_In_ ABI::ComInterfaceDispatch* disp,
/* [in] */ REFIID riid,
/* [iid_is][out] */ _COM_Outptr_ void __RPC_FAR* __RPC_FAR* ppvObject)
{
HRESULT STDMETHODCALLTYPE ManagedObjectWrapper_QueryInterface(
_In_ ABI::ComInterfaceDispatch* disp,
/* [in] */ REFIID riid,
/* [iid_is][out] */ _COM_Outptr_ void __RPC_FAR* __RPC_FAR* ppvObject)
{
ManagedObjectWrapper* wrapper = ABI::ToManagedObjectWrapper(disp);
return wrapper->QueryInterface(riid, ppvObject);
}
ManagedObjectWrapper* wrapper = ABI::ToManagedObjectWrapper(disp);
return wrapper->QueryInterface(riid, ppvObject);
}

namespace
{
ULONG STDMETHODCALLTYPE ManagedObjectWrapper_AddRef(_In_ ABI::ComInterfaceDispatch* disp)
{
ManagedObjectWrapper* wrapper = ABI::ToManagedObjectWrapper(disp);
Expand Down Expand Up @@ -310,6 +314,7 @@ void ManagedObjectWrapper::GetIUnknownImpl(
*fpRelease = ManagedObjectWrapper_IUnknownImpl.Release;
}

// The logic here should match code:ClrDataAccess::DACTryGetComWrappersObjectFromCCW in daccess/request.cpp
ManagedObjectWrapper* ManagedObjectWrapper::MapFromIUnknown(_In_ IUnknown* pUnk)
{
_ASSERTE(pUnk != nullptr);
Expand Down
14 changes: 14 additions & 0 deletions src/coreclr/src/interop/inc/interoplibabi.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

#include <stddef.h>

namespace InteropLib
{
namespace ABI
{
const size_t DispatchAlignmentThisPtr = 16; // Should be a power of 2.
const intptr_t DispatchThisPtrMask = ~(DispatchAlignmentThisPtr - 1);
}
}

0 comments on commit 10c60fc

Please sign in to comment.