Skip to content

Commit

Permalink
Port ComWrappers 5.0 diagnostic changes back to master and add stowed…
Browse files Browse the repository at this point in the history
… exception array to minidumps (#43164)
  • Loading branch information
davmason authored Oct 8, 2020
1 parent 5104f58 commit 789845f
Show file tree
Hide file tree
Showing 9 changed files with 960 additions and 919 deletions.
33 changes: 33 additions & 0 deletions src/coreclr/src/debug/daccess/dacimpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -1482,6 +1482,7 @@ class ClrDataAccess
#endif

#ifdef FEATURE_COMWRAPPERS
BOOL DACGetComWrappersCCWVTableQIAddress(CLRDATA_ADDRESS ccwPtr, TADDR *vTableAddress, TADDR *qiAddress);
BOOL DACIsComWrappersCCW(CLRDATA_ADDRESS ccwPtr);
TADDR DACGetManagedObjectWrapperFromCCW(CLRDATA_ADDRESS ccwPtr);
HRESULT DACTryGetComWrappersObjectFromCCW(CLRDATA_ADDRESS ccwPtr, OBJECTREF* objRef);
Expand Down Expand Up @@ -4036,4 +4037,36 @@ extern unsigned __int64 g_nFindStackTotalTime;

#endif // #if defined(DAC_MEASURE_PERF)

#ifdef FEATURE_COMWRAPPERS

// Public contract for ExternalObjectContext, keep in sync with definition in
// interoplibinterface.cpp
struct ExternalObjectContextDACnterface
{
PTR_VOID identity;
INT_PTR _padding1;
DWORD SyncBlockIndex;
INT64 _padding3;
};

typedef DPTR(ExternalObjectContextDACnterface) PTR_ExternalObjectContext;

// Public contract for ManagedObjectWrapper, keep in sync with definition in
// comwrappers.hpp
struct ManagedObjectWrapperDACInterface
{
PTR_VOID managedObject;
INT32 _padding1;
INT32 _padding2;
INT_PTR _padding3;
INT_PTR _padding4;
INT_PTR _padding6;
LONGLONG _refCount;
INT32 _padding7;
};

typedef DPTR(ManagedObjectWrapperDACInterface) PTR_ManagedObjectWrapper;

#endif // FEATURE_COMWRAPPERS

#endif // #ifndef __DACIMPL_H__
32 changes: 30 additions & 2 deletions src/coreclr/src/debug/daccess/enummem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@
#include "binder.h"
#include "win32threadpool.h"

#ifdef FEATURE_COMWRAPPERS
#include <interoplibinterface.h>
#include <interoplibabi.h>
#endif // FEATURE_COMWRAPPERS

extern HRESULT GetDacTableAddress(ICorDebugDataTarget* dataTarget, ULONG64 baseAddress, PULONG64 dacTableAddress);

#if defined(DAC_MEASURE_PERF)
Expand Down Expand Up @@ -1056,10 +1061,10 @@ HRESULT ClrDataAccess::EnumMemDumpAllThreadsStack(CLRDataEnumMemoryFlags flags)
{
SUPPORTS_DAC;

#ifdef FEATURE_COMINTEROP
#if defined(FEATURE_COMINTEROP) || defined(FEATURE_COMWRAPPERS)
// Dump the exception object stored in the WinRT stowed exception
EnumMemStowedException(flags);
#endif
#endif // defined(FEATURE_COMINTEROP) || defined(FEATURE_COMWRAPPERS)

HRESULT status = S_OK;
TSIZE_T cbMemoryReported = m_cbMemoryReported;
Expand Down Expand Up @@ -1377,6 +1382,10 @@ HRESULT ClrDataAccess::EnumMemStowedException(CLRDataEnumMemoryFlags flags)
return S_OK;
}

// Make sure we include the whole stowed exception array so we can debug a stowed exception
// in a minidump
ReportMem(remoteStowedExceptionArray, stowedExceptionCount * sizeof(TADDR));

for (ULONG i = 0; i < stowedExceptionCount; ++i)
{
// Read the i-th stowed exception
Expand All @@ -1389,6 +1398,8 @@ HRESULT ClrDataAccess::EnumMemStowedException(CLRDataEnumMemoryFlags flags)
continue;
}

ReportMem(remoteStowedException, sizeof(STOWED_EXCEPTION_INFORMATION_HEADER));

// check if this is a v2 stowed exception
STOWED_EXCEPTION_INFORMATION_V2 stowedException = { 0 };
if (FAILED(m_pTarget->ReadVirtual(TO_CDADDR(remoteStowedException),
Expand All @@ -1399,6 +1410,8 @@ HRESULT ClrDataAccess::EnumMemStowedException(CLRDataEnumMemoryFlags flags)
continue;
}

ReportMem(remoteStowedException, sizeof(STOWED_EXCEPTION_INFORMATION_V2));

// Read the full v2 stowed exception and get the CCW pointer out of it
if (FAILED(m_pTarget->ReadVirtual(TO_CDADDR(remoteStowedException),
(PBYTE)&stowedException, sizeof(STOWED_EXCEPTION_INFORMATION_V2), &bytesRead))
Expand Down Expand Up @@ -1429,6 +1442,21 @@ HRESULT ClrDataAccess::DumpStowedExceptionObject(CLRDataEnumMemoryFlags flags, C
if (DACTryGetComWrappersObjectFromCCW(ccwPtr, &wrappedObjAddress) == S_OK)
{
managedExceptionObject = wrappedObjAddress;
// Now report the CCW itself
ReportMem(TO_TADDR(ccwPtr), sizeof(TADDR));
TADDR managedObjectWrapperPtrPtr = ccwPtr & InteropLib::ABI::DispatchThisPtrMask;
ReportMem(managedObjectWrapperPtrPtr, sizeof(TADDR));

// Plus its QI and VTable that we query to determine if it is a ComWrappers CCW
TADDR vTableAddress = NULL;
TADDR qiAddress = NULL;
DACGetComWrappersCCWVTableQIAddress(ccwPtr, &vTableAddress, &qiAddress);
ReportMem(vTableAddress, sizeof(TADDR));
ReportMem(qiAddress, sizeof(TADDR));

// And the MOW it points to
TADDR mow = DACGetManagedObjectWrapperFromCCW(ccwPtr);
ReportMem(mow, sizeof(ManagedObjectWrapperDACInterface));
}
#endif
#ifdef FEATURE_COMINTEROP
Expand Down
129 changes: 68 additions & 61 deletions src/coreclr/src/debug/daccess/request.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,36 +23,6 @@
#ifdef FEATURE_COMWRAPPERS
#include <interoplibinterface.h>
#include <interoplibabi.h>

// Public contract for ExternalObjectContext, keep in sync with definition in
// interoplibinterface.cpp
struct ExternalObjectContextDACnterface
{
INT_PTR sentinel;
PTR_VOID identity;
INT_PTR _padding1;
DWORD _padding2;
INT64 _padding3;
};

typedef DPTR(ExternalObjectContextDACnterface) PTR_ExternalObjectContext;

// Public contract for ManagedObjectWrapper, keep in sync with definition in
// comwrappers.hpp
struct ManagedObjectWrapperDACInterface
{
PTR_VOID managedObject;
INT32 _padding1;
INT32 _padding2;
INT_PTR _padding3;
INT_PTR _padding4;
INT_PTR _padding6;
LONGLONG _refCount;
INT32 _padding7;
};

typedef DPTR(ManagedObjectWrapperDACInterface) PTR_ManagedObjectWrapper;

#endif // FEATURE_COMWRAPPERS

#ifndef TARGET_UNIX
Expand Down Expand Up @@ -4105,22 +4075,23 @@ PTR_IUnknown ClrDataAccess::DACGetCOMIPFromCCW(PTR_ComCallWrapper pCCW, int vtab
#endif

#ifdef FEATURE_COMWRAPPERS
BOOL ClrDataAccess::DACIsComWrappersCCW(CLRDATA_ADDRESS ccwPtr)
BOOL ClrDataAccess::DACGetComWrappersCCWVTableQIAddress(CLRDATA_ADDRESS ccwPtr, TADDR *vTableAddress, TADDR *qiAddress)
{
// Read CCWs QI address and compare it to the managed object wrapper's implementation.
_ASSERTE(vTableAddress != NULL && qiAddress != NULL);

HRESULT hr = S_OK;
ULONG32 bytesRead = 0;
TADDR ccw = CLRDATA_ADDRESS_TO_TADDR(ccwPtr);
TADDR vTableAddress = NULL;
if (FAILED(m_pTarget->ReadVirtual(ccw, (PBYTE)&vTableAddress, sizeof(TADDR), &bytesRead))
*vTableAddress = NULL;
if (FAILED(m_pTarget->ReadVirtual(ccw, (PBYTE)vTableAddress, sizeof(TADDR), &bytesRead))
|| bytesRead != sizeof(TADDR)
|| vTableAddress == NULL)
{
return FALSE;
}

TADDR qiAddress = NULL;
if (FAILED(m_pTarget->ReadVirtual(vTableAddress, (PBYTE)&qiAddress, sizeof(TADDR), &bytesRead))
*qiAddress = NULL;
if (FAILED(m_pTarget->ReadVirtual(*vTableAddress, (PBYTE)qiAddress, sizeof(TADDR), &bytesRead))
|| bytesRead != sizeof(TADDR)
|| qiAddress == NULL)
{
Expand All @@ -4130,15 +4101,22 @@ BOOL ClrDataAccess::DACIsComWrappersCCW(CLRDATA_ADDRESS ccwPtr)

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

if (qiAddress != GetEEFuncEntryPoint(ManagedObjectWrapper_QueryInterface))
return TRUE;
}

BOOL ClrDataAccess::DACIsComWrappersCCW(CLRDATA_ADDRESS ccwPtr)
{
TADDR vTableAddress = NULL;
TADDR qiAddress = NULL;
if (!DACGetComWrappersCCWVTableQIAddress(ccwPtr, &vTableAddress, &qiAddress))
{
return FALSE;
}

return TRUE;
return qiAddress == GetEEFuncEntryPoint(ManagedObjectWrapper_QueryInterface);
}

TADDR ClrDataAccess::DACGetManagedObjectWrapperFromCCW(CLRDATA_ADDRESS ccwPtr)
Expand Down Expand Up @@ -4174,8 +4152,6 @@ HRESULT ClrDataAccess::DACTryGetComWrappersObjectFromCCW(CLRDATA_ADDRESS ccwPtr,
}

TADDR ccw = CLRDATA_ADDRESS_TO_TADDR(ccwPtr);
// 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 = DACGetManagedObjectWrapperFromCCW(ccwPtr);
Expand Down Expand Up @@ -4819,14 +4795,6 @@ HRESULT ClrDataAccess::GetObjectComWrappersData(CLRDATA_ADDRESS objAddr, CLRDATA
}

SOSDacEnter();
auto ComWrapperCallback = [](void *mocw, void *additionalData)
{
CQuickArrayList<CLRDATA_ADDRESS> *comWrappers = (CQuickArrayList<CLRDATA_ADDRESS>*)additionalData;

comWrappers->Push(TO_CDADDR(mocw));

};

if (pNeeded != NULL)
{
*pNeeded = 0;
Expand All @@ -4845,11 +4813,24 @@ HRESULT ClrDataAccess::GetObjectComWrappersData(CLRDATA_ADDRESS objAddr, CLRDATA
{
if (rcw != NULL)
{
*rcw = PTR_CDADDR(pInfo->m_externalComObjectContext);
*rcw = TO_TADDR(pInfo->m_externalComObjectContext);
}

DPTR(NewHolder<ManagedObjectComWrapperByIdMap>) mapHolder(PTR_TO_MEMBER_TADDR(InteropSyncBlockInfo, pInfo, m_managedObjectComWrapperMap));
DPTR(ManagedObjectComWrapperByIdMap *)ppMap(PTR_TO_MEMBER_TADDR(NewHolder<ManagedObjectComWrapperByIdMap>, mapHolder, m_value));
DPTR(ManagedObjectComWrapperByIdMap) pMap(TO_TADDR(*ppMap));

CQuickArrayList<CLRDATA_ADDRESS> comWrappers;
pInfo->IterateComWrappers(ComWrapperCallback, (void *)&comWrappers);
if (pMap != NULL)
{
ManagedObjectComWrapperByIdMap::Iterator iter = pMap->Begin();
while (iter != pMap->End())
{
comWrappers.Push(TO_CDADDR(iter->Value()));
++iter;

}
}

if (pNeeded != NULL)
{
Expand Down Expand Up @@ -4963,16 +4944,48 @@ HRESULT ClrDataAccess::IsComWrappersRCW(CLRDATA_ADDRESS rcw, BOOL *isComWrappers
}

SOSDacEnter();

PTR_ExternalObjectContext pEOC(TO_TADDR(rcw));

if (isComWrappersRCW != NULL)
{
*isComWrappersRCW = pEOC->sentinel == ExternalObjectContextSentinelValue;
PTR_ExternalObjectContext pRCW(TO_TADDR(rcw));
BOOL stillValid = TRUE;
if(pRCW->SyncBlockIndex >= SyncBlockCache::s_pSyncBlockCache->m_SyncTableSize)
{
stillValid = FALSE;
}

PTR_SyncBlock pSyncBlk = NULL;
if (stillValid)
{
PTR_SyncTableEntry ste = PTR_SyncTableEntry(dac_cast<TADDR>(g_pSyncTable) + (sizeof(SyncTableEntry) * pRCW->SyncBlockIndex));
pSyncBlk = ste->m_SyncBlock;
if(pSyncBlk == NULL)
{
stillValid = FALSE;
}
}

PTR_InteropSyncBlockInfo pInfo = NULL;
if (stillValid)
{
pInfo = pSyncBlk->GetInteropInfoNoCreate();
if(pInfo == NULL)
{
stillValid = FALSE;
}
}

if (stillValid)
{
stillValid = TO_TADDR(pInfo->m_externalComObjectContext) == PTR_HOST_TO_TADDR(pRCW);
}

*isComWrappersRCW = stillValid;
hr = *isComWrappersRCW ? S_OK : S_FALSE;
}

SOSDacLeave();
return hr;
return hr;
#else // FEATURE_COMWRAPPERS
return E_NOTIMPL;
#endif // FEATURE_COMWRAPPERS
Expand All @@ -4989,12 +5002,6 @@ HRESULT ClrDataAccess::GetComWrappersRCWData(CLRDATA_ADDRESS rcw, CLRDATA_ADDRES
SOSDacEnter();

PTR_ExternalObjectContext pEOC(TO_TADDR(rcw));
if (pEOC->sentinel != ExternalObjectContextSentinelValue)
{
// Not a ComWrappers RCW
hr = E_INVALIDARG;
}

if (identity != NULL)
{
*identity = PTR_CDADDR(pEOC->identity);
Expand Down
4 changes: 4 additions & 0 deletions src/coreclr/src/inc/holder.h
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,8 @@ struct AutoExpVisibleValue
template <typename TYPE>
class HolderBase
{
friend class ClrDataAccess;

protected:
TYPE m_value;

Expand Down Expand Up @@ -227,6 +229,7 @@ template
>
class BaseHolder : protected BASE
{
friend class ClrDataAccess;
protected:
BOOL m_acquired; // Have we acquired the resource?

Expand Down Expand Up @@ -695,6 +698,7 @@ FORCEINLINE void SafeArrayDoNothing(SAFEARRAY* p)
template <typename TYPE, void (*ACQUIREF)(TYPE), void (*RELEASEF)(TYPE)>
class FunctionBase : protected HolderBase<TYPE>
{
friend class ClrDataAccess;
protected:

FORCEINLINE FunctionBase(TYPE value)
Expand Down
3 changes: 1 addition & 2 deletions src/coreclr/src/interop/comwrappers.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -117,10 +117,9 @@ class ManagedObjectWrapper
/* [iid_is][out] */ _COM_Outptr_ void __RPC_FAR * __RPC_FAR * ppvObject);
ULONG AddRef(void);
ULONG Release(void);

};

// These Sentinel and Identity are used by the DAC, any changes to the layout must be updated on the DAC side (request.cpp)
// The Target and _refCount fields are used by the DAC, any changes to the layout must be updated on the DAC side (request.cpp)
static constexpr size_t DACTargetOffset = 0;
static_assert(offsetof(ManagedObjectWrapper, Target) == DACTargetOffset, "Keep in sync with DAC interfaces");
static constexpr size_t DACRefCountOffset = (4 * sizeof(intptr_t)) + (2 * sizeof(int32_t));
Expand Down
Loading

0 comments on commit 789845f

Please sign in to comment.