Skip to content

Commit 10c60fc

Browse files
authored
Implement unwrapping a ComWrappers CCW when dumping a stowed exception. (#36360)
1 parent 4e140f4 commit 10c60fc

File tree

7 files changed

+129
-14
lines changed

7 files changed

+129
-14
lines changed

src/coreclr/src/debug/daccess/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ include_directories(BEFORE ${VM_DIR}/${ARCH_SOURCES_DIR})
55
include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR})
66
include_directories(${CLR_DIR}/src/debug/ee)
77
include_directories(${CLR_DIR}/src/gcdump)
8+
include_directories(${CLR_DIR}/src/interop/inc)
89

910
if(CLR_CMAKE_HOST_UNIX)
1011
include_directories(${GENERATED_INCLUDE_DIR})

src/coreclr/src/debug/daccess/dacimpl.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1456,6 +1456,10 @@ class ClrDataAccess
14561456
PTR_IUnknown DACGetCOMIPFromCCW(PTR_ComCallWrapper pCCW, int vtableIndex);
14571457
#endif
14581458

1459+
#ifdef FEATURE_COMWRAPPERS
1460+
HRESULT DACTryGetComWrappersObjectFromCCW(CLRDATA_ADDRESS ccwPtr, OBJECTREF* objRef);
1461+
#endif
1462+
14591463
static LONG s_procInit;
14601464

14611465
public:

src/coreclr/src/debug/daccess/enummem.cpp

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1298,7 +1298,7 @@ HRESULT ClrDataAccess::EnumMemDumpAllThreadsStack(CLRDataEnumMemoryFlags flags)
12981298
}
12991299

13001300

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

1434+
OBJECTREF managedExceptionObject = NULL;
1435+
1436+
#ifdef FEATURE_COMINTEROP
14341437
// dump the managed exception object wrapped in CCW
14351438
// memory of the CCW object itself is dumped later by DacInstanceManager::DumpAllInstances
14361439
DacpCCWData ccwData;
14371440
GetCCWData(ccwPtr, &ccwData); // this call collects some memory implicitly
1438-
DumpManagedExcepObject(flags, OBJECTREF(TO_TADDR(ccwData.managedObject)));
1441+
managedExceptionObject = OBJECTREF(CLRDATA_ADDRESS_TO_TADDR(ccwData.managedObject));
1442+
#endif
1443+
#ifdef FEATURE_COMWRAPPERS
1444+
if (managedExceptionObject == NULL)
1445+
{
1446+
OBJECTREF wrappedObjAddress;
1447+
if (DACTryGetComWrappersObjectFromCCW(ccwPtr, &wrappedObjAddress) == S_OK)
1448+
{
1449+
managedExceptionObject = wrappedObjAddress;
1450+
}
1451+
}
1452+
#endif
1453+
DumpManagedExcepObject(flags, managedExceptionObject);
14391454

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

14511466
CATCH_ALL_EXCEPT_RETHROW_COR_E_OPERATIONCANCELLED
14521467
(
1453-
ReportMem(vTableAddress + sizeof(PBYTE)* TEAR_OFF_SLOT, sizeof(TADDR));
1468+
ReportMem(vTableAddress, sizeof(TADDR)); // Report the QI slot on the vtable for ComWrappers
1469+
ReportMem(vTableAddress + sizeof(PBYTE) * TEAR_OFF_SLOT, sizeof(TADDR)); // Report the AddRef slot on the vtable for built-in CCWs
14541470
);
14551471

14561472
return S_OK;

src/coreclr/src/debug/daccess/request.cpp

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
#include <comcallablewrapper.h>
2121
#endif // FEATURE_COMINTEROP
2222

23+
#include <interoplibabi.h>
24+
2325
#ifndef TARGET_UNIX
2426
// It is unfortunate having to include this header just to get the definition of GenericModeBlock
2527
#include <msodw.h>
@@ -4065,6 +4067,76 @@ PTR_IUnknown ClrDataAccess::DACGetCOMIPFromCCW(PTR_ComCallWrapper pCCW, int vtab
40654067
}
40664068
#endif
40674069

4070+
#ifdef FEATURE_COMWRAPPERS
4071+
HRESULT ClrDataAccess::DACTryGetComWrappersObjectFromCCW(CLRDATA_ADDRESS ccwPtr, OBJECTREF* objRef)
4072+
{
4073+
if (ccwPtr == 0 || objRef == NULL)
4074+
return E_INVALIDARG;
4075+
4076+
SOSDacEnter();
4077+
4078+
// Read CCWs QI address and compare it to the managed object wrapper's implementation.
4079+
ULONG32 bytesRead = 0;
4080+
TADDR ccw = CLRDATA_ADDRESS_TO_TADDR(ccwPtr);
4081+
TADDR vTableAddress = NULL;
4082+
IfFailGo(m_pTarget->ReadVirtual(ccw, (PBYTE)&vTableAddress, sizeof(TADDR), &bytesRead));
4083+
if (bytesRead != sizeof(TADDR)
4084+
|| vTableAddress == NULL)
4085+
{
4086+
hr = E_FAIL;
4087+
goto ErrExit;
4088+
}
4089+
4090+
TADDR qiAddress = NULL;
4091+
IfFailGo(m_pTarget->ReadVirtual(vTableAddress, (PBYTE)&qiAddress, sizeof(TADDR), &bytesRead));
4092+
if (bytesRead != sizeof(TADDR)
4093+
|| qiAddress == NULL)
4094+
{
4095+
hr = E_FAIL;
4096+
goto ErrExit;
4097+
}
4098+
4099+
4100+
#ifdef TARGET_ARM
4101+
// clear the THUMB bit on qiAddress before comparing with known vtable entry
4102+
qiAddress &= ~THUMB_CODE;
4103+
#endif
4104+
4105+
if (qiAddress != GetEEFuncEntryPoint(ManagedObjectWrapper_QueryInterface))
4106+
{
4107+
hr = E_FAIL;
4108+
goto ErrExit;
4109+
}
4110+
4111+
// Mask the "dispatch pointer" to get a double pointer to the ManagedObjectWrapper
4112+
TADDR managedObjectWrapperPtrPtr = ccw & InteropLib::ABI::DispatchThisPtrMask;
4113+
4114+
// Return ManagedObjectWrapper as an OBJECTHANDLE. (The OBJECTHANDLE is guaranteed to live at offset 0).
4115+
TADDR managedObjectWrapperPtr;
4116+
IfFailGo(m_pTarget->ReadVirtual(managedObjectWrapperPtrPtr, (PBYTE)&managedObjectWrapperPtr, sizeof(TADDR), &bytesRead));
4117+
if (bytesRead != sizeof(TADDR))
4118+
{
4119+
hr = E_FAIL;
4120+
goto ErrExit;
4121+
}
4122+
4123+
OBJECTHANDLE handle;
4124+
IfFailGo(m_pTarget->ReadVirtual(managedObjectWrapperPtr, (PBYTE)&handle, sizeof(OBJECTHANDLE), &bytesRead));
4125+
if (bytesRead != sizeof(OBJECTHANDLE))
4126+
{
4127+
hr = E_FAIL;
4128+
goto ErrExit;
4129+
}
4130+
4131+
*objRef = ObjectFromHandle(handle);
4132+
4133+
SOSDacLeave();
4134+
4135+
return S_OK;
4136+
4137+
ErrExit: return hr;
4138+
}
4139+
#endif
40684140

40694141
HRESULT ClrDataAccess::GetCCWData(CLRDATA_ADDRESS ccw, struct DacpCCWData *ccwData)
40704142
{

src/coreclr/src/inc/daccess.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -629,6 +629,9 @@ typedef struct _DacGlobals
629629
ULONG fn__Unknown_AddRefSpecial;
630630
ULONG fn__Unknown_AddRefInner;
631631
#endif
632+
#ifdef FEATURE_COMWRAPPERS
633+
ULONG fn__ManagedObjectWrapper_QueryInterface;
634+
#endif
632635

633636
// Vtable pointer values for all classes that must
634637
// be instanted using vtable pointers as the identity.

src/coreclr/src/interop/comwrappers.cpp

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
// See the LICENSE file in the project root for more information.
44

55
#include "comwrappers.hpp"
6+
#include <interoplibabi.h>
67
#include <interoplibimports.h>
78

89
#include <new> // placement new
@@ -47,8 +48,8 @@ namespace ABI
4748
};
4849
ABI_ASSERT(sizeof(ComInterfaceDispatch) == sizeof(void*));
4950

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

5455
const intptr_t AlignmentThisPtrMaxPadding = DispatchAlignmentThisPtr - sizeof(void*);
@@ -179,17 +180,20 @@ namespace ABI
179180
}
180181
}
181182

182-
namespace
183+
// ManagedObjectWrapper_QueryInterface needs to be visible outside of this compilation unit
184+
// to support the DAC. See code:ClrDataAccess::DACTryGetComWrappersObjectFromCCW for the
185+
// usage in the DAC (look for the GetEEFuncEntryPoint call).
186+
HRESULT STDMETHODCALLTYPE ManagedObjectWrapper_QueryInterface(
187+
_In_ ABI::ComInterfaceDispatch* disp,
188+
/* [in] */ REFIID riid,
189+
/* [iid_is][out] */ _COM_Outptr_ void __RPC_FAR* __RPC_FAR* ppvObject)
183190
{
184-
HRESULT STDMETHODCALLTYPE ManagedObjectWrapper_QueryInterface(
185-
_In_ ABI::ComInterfaceDispatch* disp,
186-
/* [in] */ REFIID riid,
187-
/* [iid_is][out] */ _COM_Outptr_ void __RPC_FAR* __RPC_FAR* ppvObject)
188-
{
189-
ManagedObjectWrapper* wrapper = ABI::ToManagedObjectWrapper(disp);
190-
return wrapper->QueryInterface(riid, ppvObject);
191-
}
191+
ManagedObjectWrapper* wrapper = ABI::ToManagedObjectWrapper(disp);
192+
return wrapper->QueryInterface(riid, ppvObject);
193+
}
192194

195+
namespace
196+
{
193197
ULONG STDMETHODCALLTYPE ManagedObjectWrapper_AddRef(_In_ ABI::ComInterfaceDispatch* disp)
194198
{
195199
ManagedObjectWrapper* wrapper = ABI::ToManagedObjectWrapper(disp);
@@ -310,6 +314,7 @@ void ManagedObjectWrapper::GetIUnknownImpl(
310314
*fpRelease = ManagedObjectWrapper_IUnknownImpl.Release;
311315
}
312316

317+
// The logic here should match code:ClrDataAccess::DACTryGetComWrappersObjectFromCCW in daccess/request.cpp
313318
ManagedObjectWrapper* ManagedObjectWrapper::MapFromIUnknown(_In_ IUnknown* pUnk)
314319
{
315320
_ASSERTE(pUnk != nullptr);
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
// See the LICENSE file in the project root for more information.
4+
5+
#include <stddef.h>
6+
7+
namespace InteropLib
8+
{
9+
namespace ABI
10+
{
11+
const size_t DispatchAlignmentThisPtr = 16; // Should be a power of 2.
12+
const intptr_t DispatchThisPtrMask = ~(DispatchAlignmentThisPtr - 1);
13+
}
14+
}

0 commit comments

Comments
 (0)