summaryrefslogtreecommitdiff
path: root/src/debug/daccess/request.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/debug/daccess/request.cpp')
-rw-r--r--src/debug/daccess/request.cpp4271
1 files changed, 4271 insertions, 0 deletions
diff --git a/src/debug/daccess/request.cpp b/src/debug/daccess/request.cpp
new file mode 100644
index 0000000000..49432f83cd
--- /dev/null
+++ b/src/debug/daccess/request.cpp
@@ -0,0 +1,4271 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+//*****************************************************************************
+// File: request.cpp
+//
+
+//
+// CorDataAccess::Request implementation.
+//
+//*****************************************************************************
+
+#include "stdafx.h"
+#include <win32threadpool.h>
+
+#include <gceewks.cpp>
+#include <handletablepriv.h>
+#include "typestring.h"
+#include <gccover.h>
+#include <virtualcallstub.h>
+#ifdef FEATURE_COMINTEROP
+#include <comcallablewrapper.h>
+#endif // FEATURE_COMINTEROP
+
+#ifndef FEATURE_PAL
+// It is unfortunate having to include this header just to get the definition of GenericModeBlock
+#include <msodw.h>
+#endif // FEATURE_PAL
+
+// To include definiton of IsThrowableThreadAbortException
+#include <exstatecommon.h>
+
+#include "rejit.h"
+
+
+// GC headers define these to EE-specific stuff that we don't want.
+#undef EnterCriticalSection
+#undef LeaveCriticalSection
+
+#define PTR_CDADDR(ptr) TO_CDADDR(PTR_TO_TADDR(ptr))
+#define HOST_CDADDR(host) TO_CDADDR(PTR_HOST_TO_TADDR(host))
+
+#define SOSDacEnter() \
+ DAC_ENTER(); \
+ HRESULT hr = S_OK; \
+ EX_TRY \
+ {
+
+#define SOSDacLeave() \
+ } \
+ EX_CATCH \
+ { \
+ if (!DacExceptionFilter(GET_EXCEPTION(), this, &hr)) \
+ { \
+ EX_RETHROW; \
+ } \
+ } \
+ EX_END_CATCH(SwallowAllExceptions) \
+ DAC_LEAVE();
+
+// Use this when you don't want to instantiate an Object * in the host.
+TADDR DACGetMethodTableFromObjectPointer(TADDR objAddr, ICorDebugDataTarget * target)
+{
+ ULONG32 returned = 0;
+ TADDR Value = NULL;
+
+ HRESULT hr = target->ReadVirtual(objAddr, (PBYTE)&Value, sizeof(TADDR), &returned);
+
+ if ((hr != S_OK) || (returned != sizeof(TADDR)))
+ {
+ return NULL;
+ }
+
+ Value = Value & ~3; // equivalent to Object::GetGCSafeMethodTable()
+ return Value;
+}
+
+// Use this when you don't want to instantiate an Object * in the host.
+PTR_SyncBlock DACGetSyncBlockFromObjectPointer(TADDR objAddr, ICorDebugDataTarget * target)
+{
+ ULONG32 returned = 0;
+ DWORD Value = NULL;
+
+ HRESULT hr = target->ReadVirtual(objAddr - sizeof(DWORD), (PBYTE)&Value, sizeof(DWORD), &returned);
+
+ if ((hr != S_OK) || (returned != sizeof(DWORD)))
+ {
+ return NULL;
+ }
+
+ if ((Value & (BIT_SBLK_IS_HASH_OR_SYNCBLKINDEX | BIT_SBLK_IS_HASHCODE)) != BIT_SBLK_IS_HASH_OR_SYNCBLKINDEX)
+ return NULL;
+ Value &= MASK_SYNCBLOCKINDEX;
+
+ PTR_SyncTableEntry ste = PTR_SyncTableEntry(dac_cast<TADDR>(g_pSyncTable) + (sizeof(SyncTableEntry) * Value));
+ return ste->m_SyncBlock;
+}
+
+BOOL DacValidateEEClass(EEClass *pEEClass)
+{
+ // Verify things are right.
+ // The EEClass method table pointer should match the method table.
+ // TODO: Microsoft, need another test for validity, this one isn't always true anymore.
+ BOOL retval = TRUE;
+ PAL_CPP_TRY
+ {
+ MethodTable *pMethodTable = pEEClass->GetMethodTable();
+ if (!pMethodTable)
+ {
+ // PREfix.
+ return FALSE;
+ }
+ if (pEEClass != pMethodTable->GetClass())
+ {
+ retval = FALSE;
+ }
+ }
+ PAL_CPP_CATCH_ALL
+ {
+ retval = FALSE; // Something is wrong
+ }
+ PAL_CPP_ENDTRY
+ return retval;
+
+}
+
+BOOL DacValidateMethodTable(MethodTable *pMT, BOOL &bIsFree)
+{
+ // Verify things are right.
+ BOOL retval = FALSE;
+ PAL_CPP_TRY
+ {
+ bIsFree = FALSE;
+ EEClass *pEEClass = pMT->GetClass();
+ if (pEEClass==NULL)
+ {
+ // Okay to have a NULL EEClass if this is a free methodtable
+ CLRDATA_ADDRESS MethTableAddr = HOST_CDADDR(pMT);
+ CLRDATA_ADDRESS FreeObjMethTableAddr = HOST_CDADDR(g_pFreeObjectMethodTable);
+ if (MethTableAddr != FreeObjMethTableAddr)
+ goto BadMethodTable;
+
+ bIsFree = TRUE;
+ }
+ else
+ {
+ // Standard fast check
+ if (!pMT->ValidateWithPossibleAV())
+ goto BadMethodTable;
+
+ // In rare cases, we've seen the standard check above pass when it shouldn't.
+ // Insert additional/ad-hoc tests below.
+
+ // Metadata token should look valid for a class
+ mdTypeDef td = pMT->GetCl();
+ if (td != mdTokenNil && TypeFromToken(td) != mdtTypeDef)
+ goto BadMethodTable;
+
+ // BaseSize should always be greater than 0 for valid objects (unless it's an interface)
+ // For strings, baseSize is not ptr-aligned
+ if (!pMT->IsInterface() && !pMT->IsString())
+ {
+ if (pMT->GetBaseSize() == 0 || !IS_ALIGNED(pMT->GetBaseSize(), sizeof(void *)))
+ goto BadMethodTable;
+ }
+ }
+
+ retval = TRUE;
+
+BadMethodTable: ;
+ }
+ PAL_CPP_CATCH_ALL
+ {
+ retval = FALSE; // Something is wrong
+ }
+ PAL_CPP_ENDTRY
+ return retval;
+
+}
+
+BOOL DacValidateMD(MethodDesc * pMD)
+{
+ if (pMD == NULL)
+ {
+ return FALSE;
+ }
+
+ // Verify things are right.
+ BOOL retval = TRUE;
+ PAL_CPP_TRY
+ {
+ MethodTable *pMethodTable = pMD->GetMethodTable();
+
+ // Standard fast check
+ if (!pMethodTable->ValidateWithPossibleAV())
+ {
+ retval = FALSE;
+ }
+
+ if (retval && (pMD->GetSlot() >= pMethodTable->GetNumVtableSlots() && !pMD->HasNonVtableSlot()))
+ {
+ retval = FALSE;
+ }
+
+ if (retval && pMD->HasTemporaryEntryPoint())
+ {
+ MethodDesc *pMDCheck = MethodDesc::GetMethodDescFromStubAddr(pMD->GetTemporaryEntryPoint(), TRUE);
+
+ if (PTR_HOST_TO_TADDR(pMD) != PTR_HOST_TO_TADDR(pMDCheck))
+ {
+ retval = FALSE;
+ }
+ }
+
+ if (retval && pMD->HasNativeCode())
+ {
+ PCODE jitCodeAddr = pMD->GetNativeCode();
+
+ MethodDesc *pMDCheck = ExecutionManager::GetCodeMethodDesc(jitCodeAddr);
+ if (pMDCheck)
+ {
+ // Check that the given MethodDesc matches the MethodDesc from
+ // the CodeHeader
+ if (PTR_HOST_TO_TADDR(pMD) != PTR_HOST_TO_TADDR(pMDCheck))
+ {
+ retval = FALSE;
+ }
+ }
+ else
+ {
+ retval = FALSE;
+ }
+ }
+ }
+ PAL_CPP_CATCH_ALL
+ {
+ retval = FALSE; // Something is wrong
+ }
+ PAL_CPP_ENDTRY
+ return retval;
+}
+
+BOOL DacValidateMD(LPCVOID pMD)
+{
+ return DacValidateMD((MethodDesc *)pMD);
+}
+
+VOID GetJITMethodInfo (EECodeInfo * pCodeInfo, JITTypes *pJITType, CLRDATA_ADDRESS *pGCInfo)
+{
+ DWORD dwType = pCodeInfo->GetJitManager()->GetCodeType();
+ if (IsMiIL(dwType))
+ {
+ *pJITType = TYPE_JIT;
+ }
+ else if (IsMiNative(dwType))
+ {
+ *pJITType = TYPE_PJIT;
+ }
+ else
+ {
+ *pJITType = TYPE_UNKNOWN;
+ }
+
+ *pGCInfo = (CLRDATA_ADDRESS)PTR_TO_TADDR(pCodeInfo->GetGCInfo());
+}
+
+
+HRESULT
+ClrDataAccess::GetWorkRequestData(CLRDATA_ADDRESS addr, struct DacpWorkRequestData *workRequestData)
+{
+ if (addr == 0 || workRequestData == NULL)
+ return E_INVALIDARG;
+
+ SOSDacEnter();
+
+ WorkRequest *pRequest = PTR_WorkRequest(TO_TADDR(addr));
+ workRequestData->Function = (TADDR)(pRequest->Function);
+ workRequestData->Context = (TADDR)(pRequest->Context);
+ workRequestData->NextWorkRequest = (TADDR)(pRequest->next);
+
+ SOSDacLeave();
+ return hr;
+}
+
+HRESULT
+ClrDataAccess::GetHillClimbingLogEntry(CLRDATA_ADDRESS addr, struct DacpHillClimbingLogEntry *entry)
+{
+ if (addr == 0 || entry == NULL)
+ return E_INVALIDARG;
+
+ SOSDacEnter();
+
+ HillClimbingLogEntry *pLogEntry = PTR_HillClimbingLogEntry(TO_TADDR(addr));
+ entry->TickCount = pLogEntry->TickCount;
+ entry->NewControlSetting = pLogEntry->NewControlSetting;
+ entry->LastHistoryCount = pLogEntry->LastHistoryCount;
+ entry->LastHistoryMean = pLogEntry->LastHistoryMean;
+ entry->Transition = pLogEntry->Transition;
+
+ SOSDacLeave();
+ return hr;
+}
+
+HRESULT
+ClrDataAccess::GetThreadpoolData(struct DacpThreadpoolData *threadpoolData)
+{
+ if (threadpoolData == NULL)
+ return E_INVALIDARG;
+
+ SOSDacEnter();
+
+ threadpoolData->cpuUtilization = ThreadpoolMgr::cpuUtilization;
+ threadpoolData->MinLimitTotalWorkerThreads = ThreadpoolMgr::MinLimitTotalWorkerThreads;
+ threadpoolData->MaxLimitTotalWorkerThreads = ThreadpoolMgr::MaxLimitTotalWorkerThreads;
+
+ //
+ // Read ThreadpoolMgr::WorkerCounter
+ //
+ TADDR pCounter = DacGetTargetAddrForHostAddr(&ThreadpoolMgr::WorkerCounter,true);
+ ThreadpoolMgr::ThreadCounter counter;
+ DacReadAll(pCounter,&counter,sizeof(ThreadpoolMgr::ThreadCounter),true);
+ ThreadpoolMgr::ThreadCounter::Counts counts = counter.counts;
+
+ threadpoolData->NumWorkingWorkerThreads = counts.NumWorking;
+ threadpoolData->NumIdleWorkerThreads = counts.NumActive - counts.NumWorking;
+ threadpoolData->NumRetiredWorkerThreads = counts.NumRetired;
+
+ threadpoolData->FirstUnmanagedWorkRequest = HOST_CDADDR(ThreadpoolMgr::WorkRequestHead);
+
+ threadpoolData->HillClimbingLog = dac_cast<TADDR>(&HillClimbingLog);
+ threadpoolData->HillClimbingLogFirstIndex = HillClimbingLogFirstIndex;
+ threadpoolData->HillClimbingLogSize = HillClimbingLogSize;
+
+
+ //
+ // Read ThreadpoolMgr::CPThreadCounter
+ //
+ pCounter = DacGetTargetAddrForHostAddr(&ThreadpoolMgr::CPThreadCounter,true);
+ DacReadAll(pCounter,&counter,sizeof(ThreadpoolMgr::ThreadCounter),true);
+ counts = counter.counts;
+
+ threadpoolData->NumCPThreads = (LONG)(counts.NumActive + counts.NumRetired);
+ threadpoolData->NumFreeCPThreads = (LONG)(counts.NumActive - counts.NumWorking);
+ threadpoolData->MaxFreeCPThreads = ThreadpoolMgr::MaxFreeCPThreads;
+ threadpoolData->NumRetiredCPThreads = (LONG)(counts.NumRetired);
+ threadpoolData->MaxLimitTotalCPThreads = ThreadpoolMgr::MaxLimitTotalCPThreads;
+ threadpoolData->CurrentLimitTotalCPThreads = (LONG)(counts.NumActive); //legacy: currently has no meaning
+ threadpoolData->MinLimitTotalCPThreads = ThreadpoolMgr::MinLimitTotalCPThreads;
+
+ TADDR pEntry = DacGetTargetAddrForHostAddr(&ThreadpoolMgr::TimerQueue,true);
+ ThreadpoolMgr::LIST_ENTRY entry;
+ DacReadAll(pEntry,&entry,sizeof(ThreadpoolMgr::LIST_ENTRY),true);
+ TADDR node = (TADDR) entry.Flink;
+ threadpoolData->NumTimers = 0;
+ while (node && node != pEntry)
+ {
+ threadpoolData->NumTimers++;
+ DacReadAll(node,&entry,sizeof(ThreadpoolMgr::LIST_ENTRY),true);
+ node = (TADDR) entry.Flink;
+ }
+
+ threadpoolData->AsyncTimerCallbackCompletionFPtr = (CLRDATA_ADDRESS) GFN_TADDR(ThreadpoolMgr__AsyncTimerCallbackCompletion);
+ SOSDacLeave();
+ return hr;
+}
+
+HRESULT ClrDataAccess::GetThreadStoreData(struct DacpThreadStoreData *threadStoreData)
+{
+ SOSDacEnter();
+
+ ThreadStore* threadStore = ThreadStore::s_pThreadStore;
+ if (!threadStore)
+ {
+ hr = E_UNEXPECTED;
+ }
+ else
+ {
+ // initialize the fields of our local structure
+ threadStoreData->threadCount = threadStore->m_ThreadCount;
+ threadStoreData->unstartedThreadCount = threadStore->m_UnstartedThreadCount;
+ threadStoreData->backgroundThreadCount = threadStore->m_BackgroundThreadCount;
+ threadStoreData->pendingThreadCount = threadStore->m_PendingThreadCount;
+ threadStoreData->deadThreadCount = threadStore->m_DeadThreadCount;
+ threadStoreData->fHostConfig = g_fHostConfig;
+
+ // identify the "important" threads
+ threadStoreData->firstThread = HOST_CDADDR(threadStore->m_ThreadList.GetHead());
+ threadStoreData->finalizerThread = HOST_CDADDR(g_pFinalizerThread);
+ threadStoreData->gcThread = HOST_CDADDR(g_pSuspensionThread);
+ }
+
+ SOSDacLeave();
+ return hr;
+}
+
+HRESULT
+ClrDataAccess::GetStressLogAddress(CLRDATA_ADDRESS *stressLog)
+{
+ if (stressLog == NULL)
+ return E_INVALIDARG;
+
+#ifdef STRESS_LOG
+ SOSDacEnter();
+ if (g_pStressLog.IsValid())
+ *stressLog = HOST_CDADDR(g_pStressLog);
+ else
+ hr = E_FAIL;
+
+ SOSDacLeave();
+ return hr;
+#else
+ return E_NOTIMPL;
+#endif // STRESS_LOG
+}
+
+HRESULT
+ClrDataAccess::GetJitManagerList(unsigned int count, struct DacpJitManagerInfo managers[], unsigned int *pNeeded)
+{
+ SOSDacEnter();
+
+ if (managers)
+ {
+ if (count >= 1)
+ {
+ EEJitManager * managerPtr = ExecutionManager::GetEEJitManager();
+
+ DacpJitManagerInfo *currentPtr = &managers[0];
+ currentPtr->managerAddr = HOST_CDADDR(managerPtr);
+ currentPtr->codeType = managerPtr->GetCodeType();
+
+ EEJitManager *eeJitManager = PTR_EEJitManager(PTR_HOST_TO_TADDR(managerPtr));
+ currentPtr->ptrHeapList = HOST_CDADDR(eeJitManager->m_pCodeHeap);
+ }
+#ifdef FEATURE_PREJIT
+ if (count >= 2)
+ {
+ NativeImageJitManager * managerPtr = ExecutionManager::GetNativeImageJitManager();
+ DacpJitManagerInfo *currentPtr = &managers[1];
+ currentPtr->managerAddr = HOST_CDADDR(managerPtr);
+ currentPtr->codeType = managerPtr->GetCodeType();
+ }
+#endif
+ }
+ else if (pNeeded)
+ {
+ *pNeeded = 1;
+#ifdef FEATURE_PREJIT
+ *pNeeded++;
+#endif
+ }
+
+ SOSDacLeave();
+ return hr;
+}
+
+HRESULT
+ClrDataAccess::GetMethodTableSlot(CLRDATA_ADDRESS mt, unsigned int slot, CLRDATA_ADDRESS *value)
+{
+ if (mt == 0 || value == NULL)
+ return E_INVALIDARG;
+
+ SOSDacEnter();
+
+ MethodTable* mTable = PTR_MethodTable(TO_TADDR(mt));
+ BOOL bIsFree = FALSE;
+ if (!DacValidateMethodTable(mTable, bIsFree))
+ {
+ hr = E_INVALIDARG;
+ }
+ else if (slot < mTable->GetNumVtableSlots())
+ {
+ // Now get the slot:
+ *value = mTable->GetRestoredSlot(slot);
+ }
+ else
+ {
+ hr = E_INVALIDARG;
+ MethodTable::IntroducedMethodIterator it(mTable);
+ for (; it.IsValid() && FAILED(hr); it.Next())
+ {
+ MethodDesc * pMD = it.GetMethodDesc();
+ if (pMD->GetSlot() == slot)
+ {
+ *value = pMD->GetMethodEntryPoint();
+ hr = S_OK;
+ }
+ }
+ }
+
+ SOSDacLeave();
+ return hr;
+}
+
+
+HRESULT
+ClrDataAccess::GetCodeHeapList(CLRDATA_ADDRESS jitManager, unsigned int count, struct DacpJitCodeHeapInfo codeHeaps[], unsigned int *pNeeded)
+{
+ if (jitManager == NULL)
+ return E_INVALIDARG;
+
+ SOSDacEnter();
+
+ EEJitManager *pJitManager = PTR_EEJitManager(TO_TADDR(jitManager));
+ HeapList *heapList = pJitManager->m_pCodeHeap;
+
+ if (codeHeaps)
+ {
+ unsigned int i = 0;
+ while ((heapList != NULL) && (i < count))
+ {
+ // What type of CodeHeap pointer do we have?
+ CodeHeap *codeHeap = heapList->pHeap;
+ TADDR ourVTablePtr = VPTR_HOST_VTABLE_TO_TADDR(*(LPVOID*)codeHeap);
+ if (ourVTablePtr == LoaderCodeHeap::VPtrTargetVTable())
+ {
+ LoaderCodeHeap *loaderCodeHeap = PTR_LoaderCodeHeap(PTR_HOST_TO_TADDR(codeHeap));
+ codeHeaps[i].codeHeapType = CODEHEAP_LOADER;
+ codeHeaps[i].LoaderHeap =
+ TO_CDADDR(PTR_HOST_MEMBER_TADDR(LoaderCodeHeap, loaderCodeHeap, m_LoaderHeap));
+ }
+ else if (ourVTablePtr == HostCodeHeap::VPtrTargetVTable())
+ {
+ HostCodeHeap *hostCodeHeap = PTR_HostCodeHeap(PTR_HOST_TO_TADDR(codeHeap));
+ codeHeaps[i].codeHeapType = CODEHEAP_HOST;
+ codeHeaps[i].HostData.baseAddr = PTR_CDADDR(hostCodeHeap->m_pBaseAddr);
+ codeHeaps[i].HostData.currentAddr = PTR_CDADDR(hostCodeHeap->m_pLastAvailableCommittedAddr);
+ }
+ else
+ {
+ codeHeaps[i].codeHeapType = CODEHEAP_UNKNOWN;
+ }
+ heapList = heapList->hpNext;
+ i++;
+ }
+
+ if (pNeeded)
+ *pNeeded = i;
+ }
+ else if (pNeeded)
+ {
+ int i = 0;
+ while (heapList != NULL)
+ {
+ heapList = heapList->hpNext;
+ i++;
+ }
+
+ *pNeeded = i;
+ }
+ else
+ {
+ hr = E_INVALIDARG;
+ }
+
+ SOSDacLeave();
+ return hr;
+}
+
+HRESULT
+ClrDataAccess::GetStackLimits(CLRDATA_ADDRESS threadPtr, CLRDATA_ADDRESS *lower,
+ CLRDATA_ADDRESS *upper, CLRDATA_ADDRESS *fp)
+{
+ if (threadPtr == 0 || (lower == NULL && upper == NULL && fp == NULL))
+ return E_INVALIDARG;
+
+ SOSDacEnter();
+
+ Thread * thread = PTR_Thread(TO_TADDR(threadPtr));
+
+ if (lower)
+ *lower = TO_CDADDR(thread->GetCachedStackBase().GetAddr());
+
+ if (upper)
+ *upper = TO_CDADDR(thread->GetCachedStackLimit().GetAddr());
+
+ if (fp)
+ *fp = PTR_HOST_MEMBER_TADDR(Thread, thread, m_pFrame);
+
+ SOSDacLeave();
+
+ return hr;
+}
+
+HRESULT
+ClrDataAccess::GetRegisterName(int regNum, unsigned int count, __out_z __inout_ecount(count) wchar_t *buffer, unsigned int *pNeeded)
+{
+ if (!buffer && !pNeeded)
+ return E_POINTER;
+
+#ifdef _TARGET_AMD64_
+ static const wchar_t *regs[] =
+ {
+ W("rax"), W("rcx"), W("rdx"), W("rbx"), W("rsp"), W("rbp"), W("rsi"), W("rdi"),
+ W("r8"), W("r9"), W("r10"), W("r11"), W("r12"), W("r13"), W("r14"), W("r15"),
+ };
+#elif defined(_TARGET_ARM_)
+ static const wchar_t *regs[] =
+ {
+ W("r0"),
+ W("r1"),
+ W("r2"),
+ W("r3"),
+ W("r4"),
+ W("r5"),
+ W("r6"),
+ W("r7"),
+ W("r8"), W("r9"), W("r10"), W("r11"), W("r12"), W("sp"), W("lr")
+ };
+#elif defined(_TARGET_ARM64_)
+ static const wchar_t *regs[] =
+ {
+ W("X0"),
+ W("X1"),
+ W("X2"),
+ W("X3"),
+ W("X4"),
+ W("X5"),
+ W("X6"),
+ W("X7"),
+ W("X8"), W("X9"), W("X10"), W("X11"), W("X12"), W("X13"), W("X14"), W("X15"), W("X16"), W("X17"),
+ W("X18"), W("X19"), W("X20"), W("X21"), W("X22"), W("X23"), W("X24"), W("X25"), W("X26"), W("X27"),
+ W("X28"), W("Fp"), W("Sp"), W("Lr")
+ };
+#elif defined(_TARGET_X86_)
+ static const wchar_t *regs[] =
+ {
+ W("eax"), W("ecx"), W("edx"), W("ebx"), W("esp"), W("ebp"), W("esi"), W("edi"),
+ };
+#endif
+
+ // Caller frame registers are encoded as "-(reg+1)".
+ bool callerFrame = regNum < 0;
+ if (callerFrame)
+ regNum = -regNum-1;
+
+ if ((unsigned int)regNum >= _countof(regs))
+ return E_UNEXPECTED;
+
+
+ const wchar_t caller[] = W("caller.");
+ unsigned int needed = (callerFrame?(unsigned int)wcslen(caller):0) + (unsigned int)wcslen(regs[regNum]) + 1;
+ if (pNeeded)
+ *pNeeded = needed;
+
+ if (buffer)
+ {
+ _snwprintf_s(buffer, count, _TRUNCATE, W("%s%s"), callerFrame ? caller : W(""), regs[regNum]);
+ if (count < needed)
+ return S_FALSE;
+ }
+
+ return S_OK;
+}
+
+HRESULT
+ClrDataAccess::GetStackReferences(DWORD osThreadID, ISOSStackRefEnum **ppEnum)
+{
+ if (ppEnum == NULL)
+ return E_POINTER;
+
+ SOSDacEnter();
+
+ DacStackReferenceWalker *walker = new (nothrow) DacStackReferenceWalker(this, osThreadID);
+
+ if (walker == NULL)
+ {
+ hr = E_OUTOFMEMORY;
+ }
+ else
+ {
+ hr = walker->Init();
+
+ if (SUCCEEDED(hr))
+ hr = walker->QueryInterface(__uuidof(ISOSStackRefEnum), (void**)ppEnum);
+
+ if (FAILED(hr))
+ {
+ delete walker;
+ *ppEnum = NULL;
+ }
+ }
+
+ SOSDacLeave();
+ return hr;
+}
+
+HRESULT
+ClrDataAccess::GetThreadFromThinlockID(UINT thinLockId, CLRDATA_ADDRESS *pThread)
+{
+ if (pThread == NULL)
+ return E_INVALIDARG;
+
+ SOSDacEnter();
+
+ Thread *thread = g_pThinLockThreadIdDispenser->IdToThread(thinLockId);
+ *pThread = PTR_HOST_TO_TADDR(thread);
+
+ SOSDacLeave();
+ return hr;
+}
+
+
+HRESULT
+ClrDataAccess::GetThreadAllocData(CLRDATA_ADDRESS addr, struct DacpAllocData *data)
+{
+ if (data == NULL)
+ return E_POINTER;
+
+ SOSDacEnter();
+
+ Thread* thread = PTR_Thread(TO_TADDR(addr));
+
+ data->allocBytes = TO_CDADDR(thread->m_alloc_context.alloc_bytes);
+ data->allocBytesLoh = TO_CDADDR(thread->m_alloc_context.alloc_bytes_loh);
+
+ SOSDacLeave();
+ return hr;
+}
+
+HRESULT
+ClrDataAccess::GetHeapAllocData(unsigned int count, struct DacpGenerationAllocData *data, unsigned int *pNeeded)
+{
+ if (data == 0 && pNeeded == NULL)
+ return E_INVALIDARG;
+
+ SOSDacEnter();
+#if defined(FEATURE_SVR_GC)
+ if (GCHeap::IsServerHeap())
+ {
+ hr = GetServerAllocData(count, data, pNeeded);
+ }
+ else
+#endif //FEATURE_SVR_GC
+ {
+ if (pNeeded)
+ *pNeeded = 1;
+
+ if (data && count >= 1)
+ {
+ for (int i=0;i<NUMBERGENERATIONS;i++)
+ {
+ data[0].allocData[i].allocBytes = (CLRDATA_ADDRESS)(ULONG_PTR) WKS::generation_table[i].allocation_context.alloc_bytes;
+ data[0].allocData[i].allocBytesLoh = (CLRDATA_ADDRESS)(ULONG_PTR) WKS::generation_table[i].allocation_context.alloc_bytes_loh;
+ }
+ }
+ }
+
+ SOSDacLeave();
+ return hr;
+}
+
+HRESULT
+ClrDataAccess::GetThreadData(CLRDATA_ADDRESS threadAddr, struct DacpThreadData *threadData)
+{
+ SOSDacEnter();
+
+ // marshal the Thread object from the target
+ Thread* thread = PTR_Thread(TO_TADDR(threadAddr));
+
+ // initialize our local copy from the marshaled target Thread instance
+ ZeroMemory (threadData, sizeof(DacpThreadData));
+ threadData->corThreadId = thread->m_ThreadId;
+ threadData->osThreadId = thread->m_OSThreadId;
+ threadData->state = thread->m_State;
+ threadData->preemptiveGCDisabled = thread->m_fPreemptiveGCDisabled;
+ threadData->allocContextPtr = TO_CDADDR(thread->m_alloc_context.alloc_ptr);
+ threadData->allocContextLimit = TO_CDADDR(thread->m_alloc_context.alloc_limit);
+
+ // @todo Microsoft: the following assignment is pointless--we're just getting the
+ // target address of the m_pFiberData field of the Thread instance. Then we're going to
+ // compute it again as the argument to ReadVirtual. Ultimately, we want the value of
+ // that field, not its address. We already have that value as part of thread (the
+ // marshaled Thread instance).This should just go away and we should simply have:
+ // threadData->fiberData = TO_CDADDR(thread->m_pFiberData );
+ // instead of the next 11 lines.
+ threadData->fiberData = (CLRDATA_ADDRESS)PTR_HOST_MEMBER_TADDR(Thread, thread, m_pFiberData);
+
+ ULONG32 returned = 0;
+ TADDR Value = NULL;
+ HRESULT hr = m_pTarget->ReadVirtual(PTR_HOST_MEMBER_TADDR(Thread, thread, m_pFiberData),
+ (PBYTE)&Value,
+ sizeof(TADDR),
+ &returned);
+
+ if ((hr == S_OK) && (returned == sizeof(TADDR)))
+ {
+ threadData->fiberData = (CLRDATA_ADDRESS) Value;
+ }
+
+ threadData->pFrame = PTR_CDADDR(thread->m_pFrame);
+ threadData->context = PTR_CDADDR(thread->m_Context);
+ threadData->domain = PTR_CDADDR(thread->m_pDomain);
+ threadData->lockCount = thread->m_dwLockCount;
+#ifndef FEATURE_PAL
+ threadData->teb = TO_CDADDR(thread->m_pTEB);
+#else
+ threadData->teb = NULL;
+#endif
+ threadData->lastThrownObjectHandle =
+ TO_CDADDR(thread->m_LastThrownObjectHandle);
+ threadData->nextThread =
+ HOST_CDADDR(ThreadStore::s_pThreadStore->m_ThreadList.GetNext(thread));
+#ifdef WIN64EXCEPTIONS
+ if (thread->m_ExceptionState.m_pCurrentTracker)
+ {
+ threadData->firstNestedException = PTR_HOST_TO_TADDR(
+ thread->m_ExceptionState.m_pCurrentTracker->m_pPrevNestedInfo);
+ }
+#else
+ threadData->firstNestedException = PTR_HOST_TO_TADDR(
+ thread->m_ExceptionState.m_currentExInfo.m_pPrevNestedInfo);
+#endif // _WIN64
+
+ SOSDacLeave();
+ return hr;
+}
+
+#ifdef FEATURE_REJIT
+void CopyReJitInfoToReJitData(ReJitInfo * pReJitInfo, DacpReJitData * pReJitData)
+{
+ pReJitData->rejitID = pReJitInfo->m_pShared->GetId();
+ pReJitData->NativeCodeAddr = pReJitInfo->m_pCode;
+
+ switch (pReJitInfo->m_pShared->GetState())
+ {
+ default:
+ _ASSERTE(!"Unknown SharedRejitInfo state. DAC should be updated to understand this new state.");
+ pReJitData->flags = DacpReJitData::kUnknown;
+ break;
+
+ case SharedReJitInfo::kStateRequested:
+ pReJitData->flags = DacpReJitData::kRequested;
+ break;
+
+ case SharedReJitInfo::kStateActive:
+ pReJitData->flags = DacpReJitData::kActive;
+ break;
+
+ case SharedReJitInfo::kStateReverted:
+ pReJitData->flags = DacpReJitData::kReverted;
+ break;
+ }
+}
+#endif // FEATURE_REJIT
+
+
+
+//---------------------------------------------------------------------------------------
+//
+// Given a method desc addr, this loads up DacpMethodDescData and multiple DacpReJitDatas
+// with data on that method
+//
+// Arguments:
+// * methodDesc - MD to look up
+// * ip - IP address of interest (e.g., from an !ip2md call). This is used to ensure
+// the rejitted version corresponding to this IP is returned. May be NULL if you
+// don't care.
+// * methodDescData - [out] DacpMethodDescData to populate
+// * cRevertedRejitVersions - Number of entries allocated in rgRevertedRejitData
+// array
+// * rgRevertedRejitData - [out] Array of DacpReJitDatas to populate with rejitted
+// rejit version data
+// * pcNeededRevertedRejitData - [out] If cRevertedRejitVersions==0, the total
+// number of available rejit versions (including the current version) is
+// returned here. Else, the number of reverted rejit data actually fetched is
+// returned here.
+//
+// Return Value:
+// HRESULT indicating success or failure.
+//
+
+HRESULT ClrDataAccess::GetMethodDescData(
+ CLRDATA_ADDRESS methodDesc,
+ CLRDATA_ADDRESS ip,
+ struct DacpMethodDescData *methodDescData,
+ ULONG cRevertedRejitVersions,
+ DacpReJitData * rgRevertedRejitData,
+ ULONG * pcNeededRevertedRejitData)
+{
+ if (methodDesc == 0)
+ return E_INVALIDARG;
+
+ if ((cRevertedRejitVersions != 0) && (rgRevertedRejitData == NULL))
+ {
+ return E_INVALIDARG;
+ }
+
+ if ((rgRevertedRejitData != NULL) && (pcNeededRevertedRejitData == NULL))
+ {
+ // If you're asking for reverted rejit data, you'd better ask for the number of
+ // elements we return
+ return E_INVALIDARG;
+ }
+
+ SOSDacEnter();
+
+ PTR_MethodDesc pMD = PTR_MethodDesc(TO_TADDR(methodDesc));
+
+ if (!DacValidateMD(pMD))
+ {
+ hr = E_INVALIDARG;
+ }
+ else
+ {
+ ZeroMemory(methodDescData,sizeof(DacpMethodDescData));
+ if (rgRevertedRejitData != NULL)
+ ZeroMemory(rgRevertedRejitData, sizeof(*rgRevertedRejitData)*cRevertedRejitVersions);
+ if (pcNeededRevertedRejitData != NULL)
+ *pcNeededRevertedRejitData = 0;
+
+ methodDescData->requestedIP = ip;
+ methodDescData->bHasNativeCode = pMD->HasNativeCode();
+ methodDescData->bIsDynamic = (pMD->IsLCGMethod()) ? TRUE : FALSE;
+ methodDescData->wSlotNumber = pMD->GetSlot();
+ if (pMD->HasNativeCode())
+ {
+ methodDescData->NativeCodeAddr = TO_CDADDR(pMD->GetNativeCode());
+#ifdef DBG_TARGET_ARM
+ methodDescData->NativeCodeAddr &= ~THUMB_CODE;
+#endif
+ }
+ else
+ {
+ methodDescData->NativeCodeAddr = (CLRDATA_ADDRESS)-1;
+ }
+ methodDescData->AddressOfNativeCodeSlot = pMD->HasNativeCodeSlot() ?
+ TO_CDADDR(pMD->GetAddrOfNativeCodeSlot()) : NULL;
+ methodDescData->MDToken = pMD->GetMemberDef();
+ methodDescData->MethodDescPtr = methodDesc;
+ methodDescData->MethodTablePtr = HOST_CDADDR(pMD->GetMethodTable());
+ methodDescData->ModulePtr = HOST_CDADDR(pMD->GetModule());
+
+#ifdef FEATURE_REJIT
+
+ // If rejit info is appropriate, get the following:
+ // * ReJitInfo for the current, active version of the method
+ // * ReJitInfo for the requested IP (for !ip2md and !u)
+ // * ReJitInfos for all reverted versions of the method (up to
+ // cRevertedRejitVersions)
+ //
+ // Minidumps will not have all this rejit info, and failure to get rejit info
+ // should not be fatal. So enclose all rejit stuff in a try.
+
+ EX_TRY
+ {
+ ReJitManager * pReJitMgr = pMD->GetReJitManager();
+
+ // Current ReJitInfo
+ ReJitInfo * pReJitInfoCurrent = pReJitMgr->FindNonRevertedReJitInfo(pMD);
+ if (pReJitInfoCurrent != NULL)
+ {
+ CopyReJitInfoToReJitData(pReJitInfoCurrent, &methodDescData->rejitDataCurrent);
+ }
+
+ // Requested ReJitInfo
+ _ASSERTE(methodDescData->rejitDataRequested.rejitID == 0);
+ if (methodDescData->requestedIP != NULL)
+ {
+ ReJitInfo * pReJitInfoRequested = pReJitMgr->FindReJitInfo(
+ pMD,
+ CLRDATA_ADDRESS_TO_TADDR(methodDescData->requestedIP),
+ NULL /* reJitId */);
+
+ if (pReJitInfoRequested != NULL)
+ {
+ CopyReJitInfoToReJitData(pReJitInfoRequested, &methodDescData->rejitDataRequested);
+ }
+ }
+
+ // Total number of jitted rejit versions
+ ULONG cJittedRejitVersions;
+ if (SUCCEEDED(pReJitMgr->GetReJITIDs(pMD, 0 /* cReJitIds */, &cJittedRejitVersions, NULL /* reJitIds */)))
+ {
+ methodDescData->cJittedRejitVersions = cJittedRejitVersions;
+ }
+
+ // Reverted ReJitInfos
+ if (rgRevertedRejitData == NULL)
+ {
+ // No reverted rejit versions will be returned, but maybe caller wants a
+ // count of all versions
+ if (pcNeededRevertedRejitData != NULL)
+ {
+ *pcNeededRevertedRejitData = methodDescData->cJittedRejitVersions;
+ }
+ }
+ else
+ {
+ // Caller wants some reverted rejit versions. Gather reverted rejit version data to return
+ ULONG cReJitIds;
+ StackSArray<ReJITID> reJitIds;
+
+ // Prepare array to populate with rejitids. "+ 1" because GetReJITIDs
+ // returns all available rejitids, including the rejitid for the one non-reverted
+ // current version.
+ ReJITID * rgReJitIds = reJitIds.OpenRawBuffer(cRevertedRejitVersions + 1);
+ if (rgReJitIds != NULL)
+ {
+ hr = pReJitMgr->GetReJITIDs(pMD, cRevertedRejitVersions + 1, &cReJitIds, rgReJitIds);
+ if (SUCCEEDED(hr))
+ {
+ // Go through rejitids. For each reverted one, populate a entry in rgRevertedRejitData
+ reJitIds.CloseRawBuffer(cReJitIds);
+ ULONG iRejitDataReverted = 0;
+ for (COUNT_T i=0;
+ (i < cReJitIds) && (iRejitDataReverted < cRevertedRejitVersions);
+ i++)
+ {
+ ReJitInfo * pRejitInfo = pReJitMgr->FindReJitInfo(
+ pMD,
+ NULL /* pCodeStart */,
+ reJitIds[i]);
+
+ if ((pRejitInfo == NULL) ||
+ (pRejitInfo->m_pShared->GetState() != SharedReJitInfo::kStateReverted))
+ {
+ continue;
+ }
+
+ CopyReJitInfoToReJitData(pRejitInfo, &rgRevertedRejitData[iRejitDataReverted]);
+ iRejitDataReverted++;
+ }
+ // pcNeededRevertedRejitData != NULL as per condition at top of function (cuz rgRevertedRejitData !=
+ // NULL).
+ *pcNeededRevertedRejitData = iRejitDataReverted;
+ }
+ }
+ }
+ }
+ EX_CATCH
+ {
+ if (pcNeededRevertedRejitData != NULL)
+ *pcNeededRevertedRejitData = 0;
+ }
+ EX_END_CATCH(SwallowAllExceptions)
+ hr = S_OK; // Failure to get rejitids is not fatal
+#endif // FEATURE_REJIT
+
+#if defined(HAVE_GCCOVER)
+ if (pMD->m_GcCover)
+ {
+ EX_TRY
+ {
+ // In certain minidumps, we won't save the gccover information.
+ // (it would be unwise to do so, it is heavy and not a customer scenario).
+ methodDescData->GCStressCodeCopy = HOST_CDADDR(pMD->m_GcCover) + offsetof(GCCoverageInfo, savedCode);
+ }
+ EX_CATCH
+ {
+ methodDescData->GCStressCodeCopy = 0;
+ }
+ EX_END_CATCH(SwallowAllExceptions)
+ }
+ else
+#endif // HAVE_GCCOVER
+
+ // Set this above Dario since you know how to tell if dynamic
+ if (methodDescData->bIsDynamic)
+ {
+ DynamicMethodDesc *pDynamicMethod = PTR_DynamicMethodDesc(TO_TADDR(methodDesc));
+ if (pDynamicMethod)
+ {
+ LCGMethodResolver *pResolver = pDynamicMethod->GetLCGMethodResolver();
+ if (pResolver)
+ {
+ OBJECTREF value = pResolver->GetManagedResolver();
+ if (value)
+ {
+ FieldDesc *pField = (&g_Mscorlib)->GetField(FIELD__DYNAMICRESOLVER__DYNAMIC_METHOD);
+ _ASSERTE(pField);
+ value = pField->GetRefValue(value);
+ if (value)
+ {
+ methodDescData->managedDynamicMethodObject = PTR_HOST_TO_TADDR(value);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ SOSDacLeave();
+ return hr;
+}
+
+HRESULT
+ClrDataAccess::GetMethodDescTransparencyData(CLRDATA_ADDRESS methodDesc, struct DacpMethodDescTransparencyData *data)
+{
+ if (methodDesc == 0 || data == NULL)
+ return E_INVALIDARG;
+
+ SOSDacEnter();
+
+ MethodDesc *pMD = PTR_MethodDesc(TO_TADDR(methodDesc));
+ if (!DacValidateMD(pMD))
+ {
+ hr = E_INVALIDARG;
+ }
+ else
+ {
+ ZeroMemory(data, sizeof(DacpMethodDescTransparencyData));
+
+ if (pMD->HasCriticalTransparentInfo())
+ {
+ data->bHasCriticalTransparentInfo = pMD->HasCriticalTransparentInfo();
+ data->bIsCritical = pMD->IsCritical();
+ data->bIsTreatAsSafe = pMD->IsTreatAsSafe();
+ }
+ }
+
+ SOSDacLeave();
+ return hr;
+}
+
+HRESULT
+ClrDataAccess::GetCodeHeaderData(CLRDATA_ADDRESS ip, struct DacpCodeHeaderData *codeHeaderData)
+{
+ if (ip == 0 || codeHeaderData == NULL)
+ return E_INVALIDARG;
+
+ SOSDacEnter();
+
+ EECodeInfo codeInfo(TO_TADDR(ip));
+
+ if (!codeInfo.IsValid())
+ {
+ // We may be able to walk stubs to find a method desc if it's not a jitted method.
+ MethodDesc *methodDescI = MethodTable::GetMethodDescForSlotAddress(TO_TADDR(ip));
+ if (methodDescI == NULL)
+ {
+ hr = E_INVALIDARG;
+ }
+ else
+ {
+ codeHeaderData->MethodDescPtr = HOST_CDADDR(methodDescI);
+ codeHeaderData->JITType = TYPE_UNKNOWN;
+ codeHeaderData->GCInfo = NULL;
+ codeHeaderData->MethodStart = NULL;
+ codeHeaderData->MethodSize = 0;
+ codeHeaderData->ColdRegionStart = NULL;
+ }
+ }
+ else
+ {
+ codeHeaderData->MethodDescPtr = HOST_CDADDR(codeInfo.GetMethodDesc());
+
+ GetJITMethodInfo(&codeInfo, &codeHeaderData->JITType, &codeHeaderData->GCInfo);
+
+ codeHeaderData->MethodStart =
+ (CLRDATA_ADDRESS) codeInfo.GetStartAddress();
+ size_t methodSize = codeInfo.GetCodeManager()->GetFunctionSize(codeInfo.GetGCInfo());
+ _ASSERTE(FitsIn<DWORD>(methodSize));
+ codeHeaderData->MethodSize = static_cast<DWORD>(methodSize);
+
+ IJitManager::MethodRegionInfo methodRegionInfo = {NULL, 0, NULL, 0};
+ codeInfo.GetMethodRegionInfo(&methodRegionInfo);
+
+ codeHeaderData->HotRegionSize = (DWORD) methodRegionInfo.hotSize;
+ codeHeaderData->ColdRegionSize = (DWORD) methodRegionInfo.coldSize;
+ codeHeaderData->ColdRegionStart = (CLRDATA_ADDRESS) methodRegionInfo.coldStartAddress;
+ }
+
+ SOSDacLeave();
+ return hr;
+}
+
+HRESULT
+ClrDataAccess::GetMethodDescPtrFromFrame(CLRDATA_ADDRESS frameAddr, CLRDATA_ADDRESS * ppMD)
+{
+ if (frameAddr == 0 || ppMD == NULL)
+ return E_INVALIDARG;
+
+ SOSDacEnter();
+
+ Frame *pFrame = PTR_Frame(TO_TADDR(frameAddr));
+ CLRDATA_ADDRESS methodDescAddr = HOST_CDADDR(pFrame->GetFunction());
+ if ((methodDescAddr == NULL) || !DacValidateMD(PTR_MethodDesc(TO_TADDR(methodDescAddr))))
+ {
+ hr = E_INVALIDARG;
+ }
+ else
+ {
+ *ppMD = methodDescAddr;
+ hr = S_OK;
+ }
+
+ SOSDacLeave();
+ return hr;
+}
+
+HRESULT
+ClrDataAccess::GetMethodDescPtrFromIP(CLRDATA_ADDRESS ip, CLRDATA_ADDRESS * ppMD)
+{
+ if (ip == 0 || ppMD == NULL)
+ return E_INVALIDARG;
+
+ SOSDacEnter();
+
+ EECodeInfo codeInfo(TO_TADDR(ip));
+
+ if (!codeInfo.IsValid())
+ {
+ hr = E_FAIL;
+ }
+ else
+ {
+ CLRDATA_ADDRESS pMD = HOST_CDADDR(codeInfo.GetMethodDesc());
+ if ((pMD == NULL) || !DacValidateMD(PTR_MethodDesc(TO_TADDR(pMD))))
+ {
+ hr = E_INVALIDARG;
+ }
+ else
+ {
+ *ppMD = pMD;
+ hr = S_OK;
+ }
+ }
+
+ SOSDacLeave();
+ return hr;
+}
+
+HRESULT
+ClrDataAccess::GetMethodDescName(CLRDATA_ADDRESS methodDesc, unsigned int count, __out_z __inout_ecount(count) wchar_t *name, unsigned int *pNeeded)
+{
+ if (methodDesc == 0)
+ return E_INVALIDARG;
+
+ SOSDacEnter();
+
+ MethodDesc* pMD = PTR_MethodDesc(TO_TADDR(methodDesc));
+ StackSString str;
+
+ PAL_CPP_TRY
+ {
+ TypeString::AppendMethodInternal(str, pMD, TypeString::FormatSignature|TypeString::FormatNamespace|TypeString::FormatFullInst);
+ }
+ PAL_CPP_CATCH_ALL
+ {
+ hr = E_FAIL;
+ if (pMD->IsDynamicMethod())
+ {
+ if (pMD->IsLCGMethod() || pMD->IsILStub())
+ {
+ // In heap dumps, trying to format the signature can fail
+ // in certain cases because StoredSigMethodDesc::m_pSig points
+ // to the IMAGE_MAPPED layout (in the PEImage::m_pLayouts array).
+ // We save only the IMAGE_LOADED layout to the heap dump. Rather
+ // than bloat the dump, we just drop the signature in these
+ // cases.
+
+ str.Clear();
+ TypeString::AppendMethodInternal(str, pMD, TypeString::FormatNamespace|TypeString::FormatFullInst);
+ hr = S_OK;
+ }
+ }
+ else
+ {
+#ifdef FEATURE_MINIMETADATA_IN_TRIAGEDUMPS
+ if (MdCacheGetEEName(TO_TADDR(methodDesc), str))
+ {
+ hr = S_OK;
+ }
+ else
+ {
+#endif // FEATURE_MINIMETADATA_IN_TRIAGEDUMPS
+ str.Clear();
+ Module* pModule = pMD->GetModule();
+ if (pModule)
+ {
+ WCHAR path[MAX_PATH];
+ COUNT_T nChars = 0;
+ if (pModule->GetPath().DacGetUnicode(NumItems(path), path, &nChars) &&
+ nChars > 0 && nChars <= NumItems(path))
+ {
+ WCHAR* pFile = path + nChars - 1;
+ while ((pFile >= path) && (*pFile != W('\\')))
+ {
+ pFile--;
+ }
+ pFile++;
+ if (*pFile)
+ {
+ str.Append(pFile);
+ str.Append(W("!Unknown"));
+ hr = S_OK;
+ }
+ }
+ }
+#ifdef FEATURE_MINIMETADATA_IN_TRIAGEDUMPS
+ }
+#endif
+ }
+ }
+ PAL_CPP_ENDTRY
+
+ if (SUCCEEDED(hr))
+ {
+
+ const wchar_t *val = str.GetUnicode();
+
+ if (pNeeded)
+ *pNeeded = str.GetCount() + 1;
+
+ if (name && count)
+ {
+ wcsncpy_s(name, count, val, _TRUNCATE);
+ name[count-1] = 0;
+ }
+ }
+
+ SOSDacLeave();
+ return hr;
+}
+
+HRESULT
+ClrDataAccess::GetDomainFromContext(CLRDATA_ADDRESS contextAddr, CLRDATA_ADDRESS *domain)
+{
+ if (contextAddr == 0 || domain == NULL)
+ return E_INVALIDARG;
+
+ SOSDacEnter();
+
+ Context* context = PTR_Context(TO_TADDR(contextAddr));
+ *domain = HOST_CDADDR(context->GetDomain());
+
+ SOSDacLeave();
+ return hr;
+}
+
+
+HRESULT
+ClrDataAccess::GetObjectStringData(CLRDATA_ADDRESS obj, unsigned int count, __out_z __inout_ecount(count) wchar_t *stringData, unsigned int *pNeeded)
+{
+ if (obj == 0)
+ return E_INVALIDARG;
+
+ if ((stringData == 0 || count <= 0) && (pNeeded == NULL))
+ return E_INVALIDARG;
+
+ SOSDacEnter();
+
+ TADDR mtTADDR = DACGetMethodTableFromObjectPointer(TO_TADDR(obj), m_pTarget);
+ MethodTable *mt = PTR_MethodTable(mtTADDR);
+
+ // Object must be a string
+ BOOL bFree = FALSE;
+ if (!DacValidateMethodTable(mt, bFree))
+ hr = E_INVALIDARG;
+ else if (HOST_CDADDR(mt) != HOST_CDADDR(g_pStringClass))
+ hr = E_INVALIDARG;
+
+ if (SUCCEEDED(hr))
+ {
+ PTR_StringObject str(TO_TADDR(obj));
+ ULONG32 needed = (ULONG32)str->GetStringLength()+1;
+
+ if (stringData && count > 0)
+ {
+ if (count > needed)
+ count = needed;
+
+ TADDR pszStr = TO_TADDR(obj)+offsetof(StringObject, m_Characters);
+ hr = m_pTarget->ReadVirtual(pszStr, (PBYTE)stringData, count*sizeof(wchar_t), &needed);
+
+ if (SUCCEEDED(hr))
+ stringData[count-1] = 0;
+ else
+ stringData[0] = 0;
+ }
+ else
+ {
+ hr = E_INVALIDARG;
+ }
+
+ if (pNeeded)
+ *pNeeded = needed;
+ }
+
+ SOSDacLeave();
+ return hr;
+}
+
+HRESULT
+ClrDataAccess::GetObjectClassName(CLRDATA_ADDRESS obj, unsigned int count, __out_z __inout_ecount(count) wchar_t *className, unsigned int *pNeeded)
+{
+ if (obj == 0)
+ return E_INVALIDARG;
+
+ SOSDacEnter();
+
+ // Don't turn the Object into a pointer, it is too costly on
+ // scans of the gc heap.
+ MethodTable *mt = NULL;
+ TADDR mtTADDR = DACGetMethodTableFromObjectPointer(CLRDATA_ADDRESS_TO_TADDR(obj), m_pTarget);
+ if (mtTADDR != NULL)
+ mt = PTR_MethodTable(mtTADDR);
+ else
+ hr = E_INVALIDARG;
+
+ BOOL bFree = FALSE;
+ if (SUCCEEDED(hr) && !DacValidateMethodTable(mt, bFree))
+ hr = E_INVALIDARG;
+
+ if (SUCCEEDED(hr))
+ {
+ // There is a case where metadata was unloaded and the AppendType call will fail.
+ // This is when an AppDomain has been unloaded but not yet collected.
+ PEFile *pPEFile = mt->GetModule()->GetFile();
+ if (pPEFile->GetNativeImage() == NULL && pPEFile->GetILimage() == NULL)
+ {
+ if (pNeeded)
+ *pNeeded = 16;
+
+ if (className)
+ wcsncpy_s(className, count, W("<Unloaded Type>"), _TRUNCATE);
+ }
+ else
+ {
+ StackSString s;
+ TypeString::AppendType(s, TypeHandle(mt), TypeString::FormatNamespace|TypeString::FormatFullInst);
+ const wchar_t *val = s.GetUnicode();
+
+ if (pNeeded)
+ *pNeeded = s.GetCount() + 1;
+
+ if (className && count)
+ {
+ wcsncpy_s(className, count, val, _TRUNCATE);
+ className[count-1] = 0;
+ }
+ }
+ }
+
+ SOSDacLeave();
+ return hr;
+}
+
+HRESULT
+ClrDataAccess::GetMethodDescFromToken(CLRDATA_ADDRESS moduleAddr, mdToken token, CLRDATA_ADDRESS *methodDesc)
+{
+ if (moduleAddr == 0 || methodDesc == NULL)
+ return E_INVALIDARG;
+
+ SOSDacEnter();
+
+ Module* pModule = PTR_Module(TO_TADDR(moduleAddr));
+ TypeHandle th;
+ switch (TypeFromToken(token))
+ {
+ case mdtFieldDef:
+ *methodDesc = HOST_CDADDR(pModule->LookupFieldDef(token));
+ break;
+ case mdtMethodDef:
+ *methodDesc = HOST_CDADDR(pModule->LookupMethodDef(token));
+ break;
+ case mdtTypeDef:
+ th = pModule->LookupTypeDef(token);
+ *methodDesc = th.AsTAddr();
+ break;
+ case mdtTypeRef:
+ th = pModule->LookupTypeRef(token);
+ *methodDesc = th.AsTAddr();
+ break;
+ default:
+ hr = E_INVALIDARG;
+ break;
+ }
+
+ SOSDacLeave();
+ return hr;
+}
+
+HRESULT
+ClrDataAccess::TraverseModuleMap(ModuleMapType mmt, CLRDATA_ADDRESS moduleAddr, MODULEMAPTRAVERSE pCallback, LPVOID token)
+{
+ if (moduleAddr == 0)
+ return E_INVALIDARG;
+
+ SOSDacEnter();
+
+ Module* pModule = PTR_Module(TO_TADDR(moduleAddr));
+
+ // We want to traverse these two tables, passing callback information
+ switch (mmt)
+ {
+ case TYPEDEFTOMETHODTABLE:
+ {
+ LookupMap<PTR_MethodTable>::Iterator typeIter(&pModule->m_TypeDefToMethodTableMap);
+ for (int i = 0; typeIter.Next(); i++)
+ {
+ if (typeIter.GetElement())
+ {
+ MethodTable* pMT = typeIter.GetElement();
+ (pCallback)(i,PTR_HOST_TO_TADDR(pMT), token);
+ }
+ }
+ }
+ break;
+ case TYPEREFTOMETHODTABLE:
+ {
+ LookupMap<PTR_TypeRef>::Iterator typeIter(&pModule->m_TypeRefToMethodTableMap);
+ for (int i = 0; typeIter.Next(); i++)
+ {
+ if (typeIter.GetElement())
+ {
+ MethodTable* pMT = TypeHandle::FromTAddr(dac_cast<TADDR>(typeIter.GetElement())).GetMethodTable();
+ (pCallback)(i,PTR_HOST_TO_TADDR(pMT), token);
+ }
+ }
+ }
+ break;
+ default:
+ hr = E_INVALIDARG;
+ }
+
+ SOSDacLeave();
+ return hr;
+}
+
+HRESULT
+ClrDataAccess::GetModule(CLRDATA_ADDRESS addr, IXCLRDataModule **mod)
+{
+ if (addr == 0 || mod == NULL)
+ return E_INVALIDARG;
+
+ SOSDacEnter();
+
+ Module* pModule = PTR_Module(TO_TADDR(addr));
+ *mod = new ClrDataModule(this, pModule);
+ SOSDacLeave();
+
+ return hr;
+}
+
+HRESULT
+ClrDataAccess::GetModuleData(CLRDATA_ADDRESS addr, struct DacpModuleData *ModuleData)
+{
+ if (addr == 0 || ModuleData == NULL)
+ return E_INVALIDARG;
+
+ SOSDacEnter();
+
+ Module* pModule = PTR_Module(TO_TADDR(addr));
+
+ ZeroMemory(ModuleData,sizeof(DacpModuleData));
+ ModuleData->Address = addr;
+ ModuleData->File = HOST_CDADDR(pModule->GetFile());
+ COUNT_T metadataSize = 0;
+ if (pModule->GetFile()->HasNativeImage())
+ {
+ ModuleData->ilBase = (CLRDATA_ADDRESS)PTR_TO_TADDR(pModule->GetFile()->GetLoadedNative()->GetBase());
+ }
+ else
+ if (!pModule->GetFile()->IsDynamic())
+ {
+ ModuleData->ilBase = (CLRDATA_ADDRESS)(ULONG_PTR) pModule->GetFile()->GetIJWBase();
+ }
+
+ ModuleData->metadataStart = (CLRDATA_ADDRESS)dac_cast<TADDR>(pModule->GetFile()->GetLoadedMetadata(&metadataSize));
+ ModuleData->metadataSize = (SIZE_T) metadataSize;
+
+ ModuleData->bIsReflection = pModule->IsReflection();
+ ModuleData->bIsPEFile = pModule->IsPEFile();
+ ModuleData->Assembly = HOST_CDADDR(pModule->GetAssembly());
+ ModuleData->dwModuleID = pModule->GetModuleID();
+ ModuleData->dwModuleIndex = pModule->GetModuleIndex().m_dwIndex;
+ ModuleData->dwTransientFlags = pModule->m_dwTransientFlags;
+
+ EX_TRY
+ {
+ //
+ // In minidump's case, these data structure is not avaiable.
+ //
+ ModuleData->TypeDefToMethodTableMap = PTR_CDADDR(pModule->m_TypeDefToMethodTableMap.pTable);
+ ModuleData->TypeRefToMethodTableMap = PTR_CDADDR(pModule->m_TypeRefToMethodTableMap.pTable);
+ ModuleData->MethodDefToDescMap = PTR_CDADDR(pModule->m_MethodDefToDescMap.pTable);
+ ModuleData->FieldDefToDescMap = PTR_CDADDR(pModule->m_FieldDefToDescMap.pTable);
+ ModuleData->MemberRefToDescMap = NULL;
+ ModuleData->FileReferencesMap = PTR_CDADDR(pModule->m_FileReferencesMap.pTable);
+ ModuleData->ManifestModuleReferencesMap = PTR_CDADDR(pModule->m_ManifestModuleReferencesMap.pTable);
+
+#ifdef FEATURE_MIXEDMODE // IJW
+ ModuleData->pThunkHeap = HOST_CDADDR(pModule->m_pThunkHeap);
+#endif // FEATURE_MIXEDMODE // IJW
+ }
+ EX_CATCH
+ {
+ }
+ EX_END_CATCH(SwallowAllExceptions)
+
+ SOSDacLeave();
+ return hr;
+}
+
+HRESULT
+ClrDataAccess::GetILForModule(CLRDATA_ADDRESS moduleAddr, DWORD rva, CLRDATA_ADDRESS *il)
+{
+ if (moduleAddr == 0 || il == NULL)
+ return E_INVALIDARG;
+
+ SOSDacEnter();
+
+ Module* pModule = PTR_Module(TO_TADDR(moduleAddr));
+ *il = (TADDR)(CLRDATA_ADDRESS)pModule->GetIL(rva);
+
+ SOSDacLeave();
+ return hr;
+}
+
+HRESULT
+ClrDataAccess::GetMethodTableData(CLRDATA_ADDRESS mt, struct DacpMethodTableData *MTData)
+{
+ if (mt == 0 || MTData == NULL)
+ return E_INVALIDARG;
+
+ SOSDacEnter();
+
+ MethodTable* pMT = PTR_MethodTable(TO_TADDR(mt));
+ BOOL bIsFree = FALSE;
+ if (!DacValidateMethodTable(pMT, bIsFree))
+ {
+ hr = E_INVALIDARG;
+ }
+ else
+ {
+ ZeroMemory(MTData,sizeof(DacpMethodTableData));
+ MTData->BaseSize = pMT->GetBaseSize();
+ if(pMT->IsString())
+ MTData->BaseSize -= sizeof(WCHAR);
+ MTData->ComponentSize = (DWORD)pMT->GetComponentSize();
+ MTData->bIsFree = bIsFree;
+ if(!bIsFree)
+ {
+ MTData->Module = HOST_CDADDR(pMT->GetModule());
+ MTData->Class = HOST_CDADDR(pMT->GetClass());
+ MTData->ParentMethodTable = HOST_CDADDR(pMT->GetParentMethodTable());;
+ MTData->wNumInterfaces = pMT->GetNumInterfaces();
+ MTData->wNumMethods = pMT->GetNumMethods();
+ MTData->wNumVtableSlots = pMT->GetNumVtableSlots();
+ MTData->wNumVirtuals = pMT->GetNumVirtuals();
+ MTData->cl = pMT->GetCl();
+ MTData->dwAttrClass = pMT->GetAttrClass();
+ MTData->bContainsPointers = pMT->ContainsPointers();
+ MTData->bIsShared = (pMT->IsDomainNeutral() ? TRUE : FALSE); // flags & enum_flag_DomainNeutral
+ MTData->bIsDynamic = pMT->IsDynamicStatics();
+ }
+ }
+
+ SOSDacLeave();
+ return hr;
+}
+
+HRESULT
+ClrDataAccess::GetMethodTableName(CLRDATA_ADDRESS mt, unsigned int count, __out_z __inout_ecount(count) wchar_t *mtName, unsigned int *pNeeded)
+{
+ if (mt == 0)
+ return E_INVALIDARG;
+
+ SOSDacEnter();
+
+ MethodTable *pMT = PTR_MethodTable(TO_TADDR(mt));
+ BOOL free = FALSE;
+
+ if (mt == HOST_CDADDR(g_pFreeObjectMethodTable))
+ {
+ if (pNeeded)
+ *pNeeded = 5;
+
+ if (mtName && count)
+ wcsncpy_s(mtName, count, W("Free"), _TRUNCATE);
+ }
+ else if (!DacValidateMethodTable(pMT, free))
+ {
+ hr = E_INVALIDARG;
+ }
+ else
+ {
+ // There is a case where metadata was unloaded and the AppendType call will fail.
+ // This is when an AppDomain has been unloaded but not yet collected.
+ PEFile *pPEFile = pMT->GetModule()->GetFile();
+ if (pPEFile->GetNativeImage() == NULL && pPEFile->GetILimage() == NULL)
+ {
+ if (pNeeded)
+ *pNeeded = 16;
+
+ if (mtName)
+ wcsncpy_s(mtName, count, W("<Unloaded Type>"), _TRUNCATE);
+ }
+ else
+ {
+ StackSString s;
+#ifdef FEATURE_MINIMETADATA_IN_TRIAGEDUMPS
+ PAL_CPP_TRY
+ {
+#endif // FEATURE_MINIMETADATA_IN_TRIAGEDUMPS
+
+ TypeString::AppendType(s, TypeHandle(pMT), TypeString::FormatNamespace|TypeString::FormatFullInst);
+
+#ifdef FEATURE_MINIMETADATA_IN_TRIAGEDUMPS
+ }
+ PAL_CPP_CATCH_ALL
+ {
+ if (!MdCacheGetEEName(dac_cast<TADDR>(pMT), s))
+ {
+ PAL_CPP_RETHROW;
+ }
+ }
+ PAL_CPP_ENDTRY
+#endif // FEATURE_MINIMETADATA_IN_TRIAGEDUMPS
+
+ if (s.IsEmpty())
+ {
+ hr = E_OUTOFMEMORY;
+ }
+ else
+ {
+ const wchar_t *val = s.GetUnicode();
+
+ if (pNeeded)
+ *pNeeded = s.GetCount() + 1;
+
+ if (mtName && count)
+ {
+ wcsncpy_s(mtName, count, val, _TRUNCATE);
+ mtName[count-1] = 0;
+ }
+ }
+ }
+ }
+
+ SOSDacLeave();
+ return hr;
+}
+
+HRESULT
+ClrDataAccess::GetFieldDescData(CLRDATA_ADDRESS addr, struct DacpFieldDescData *FieldDescData)
+{
+ if (addr == 0 || FieldDescData == NULL)
+ return E_INVALIDARG;
+
+ SOSDacEnter();
+ FieldDesc* pFieldDesc = PTR_FieldDesc(TO_TADDR(addr));
+ FieldDescData->Type = pFieldDesc->GetFieldType();
+ FieldDescData->sigType = FieldDescData->Type;
+
+ EX_TRY
+ {
+ // minidump case, we do not have the field's type's type handle!
+ // Strike should be able to form name based on the metadata token in
+ // the field desc. Find type is using look up map which is huge. We cannot
+ // drag in this data structure in minidump's case.
+ //
+ TypeHandle th = pFieldDesc->LookupFieldTypeHandle();
+ MethodTable *pMt = th.GetMethodTable();
+ if (pMt)
+ {
+ FieldDescData->MTOfType = HOST_CDADDR(th.GetMethodTable());
+ }
+ else
+ {
+ FieldDescData->MTOfType = NULL;
+ }
+ }
+ EX_CATCH
+ {
+ FieldDescData->MTOfType = NULL;
+ }
+ EX_END_CATCH(SwallowAllExceptions)
+
+ // TODO: This is not currently useful, I need to get the module of the
+ // type definition not that of the field description.
+
+ // TODO: Is there an easier way to get this information?
+ // I'm getting the typeDef of a (possibly unloaded) type.
+ MetaSig tSig(pFieldDesc);
+ tSig.NextArg();
+ SigPointer sp1 = tSig.GetArgProps();
+ CorElementType et;
+ hr = sp1.GetElemType(&et); // throw away the value, we just need to walk past.
+
+ if (SUCCEEDED(hr))
+ {
+ if (et == ELEMENT_TYPE_CLASS || et == ELEMENT_TYPE_VALUETYPE) // any other follows token?
+ {
+ hr = sp1.GetToken(&(FieldDescData->TokenOfType));
+ }
+ else
+ {
+ // There is no encoded token of field type
+ FieldDescData->TokenOfType = mdTypeDefNil;
+ if (FieldDescData->MTOfType == NULL)
+ {
+ // If there is no encoded token (that is, it is primitive type) and no MethodTable for it, remember the
+ // element_type from signature
+ //
+ FieldDescData->sigType = et;
+ }
+ }
+ }
+
+ FieldDescData->ModuleOfType = HOST_CDADDR(pFieldDesc->GetModule());
+ FieldDescData->mb = pFieldDesc->GetMemberDef();
+ FieldDescData->MTOfEnclosingClass = HOST_CDADDR(pFieldDesc->GetApproxEnclosingMethodTable());
+ FieldDescData->dwOffset = pFieldDesc->GetOffset();
+ FieldDescData->bIsThreadLocal = pFieldDesc->IsThreadStatic();
+#ifdef FEATURE_REMOTING
+ FieldDescData->bIsContextLocal = pFieldDesc->IsContextStatic();;
+#else
+ FieldDescData->bIsContextLocal = FALSE;
+#endif
+ FieldDescData->bIsStatic = pFieldDesc->IsStatic();
+ FieldDescData->NextField = HOST_CDADDR(PTR_FieldDesc(PTR_HOST_TO_TADDR(pFieldDesc) + sizeof(FieldDesc)));
+
+ SOSDacLeave();
+ return hr;
+}
+
+HRESULT
+ClrDataAccess::GetMethodTableFieldData(CLRDATA_ADDRESS mt, struct DacpMethodTableFieldData *data)
+{
+ if (mt == 0 || data == NULL)
+ return E_INVALIDARG;
+
+ SOSDacEnter();
+
+ MethodTable* pMT = PTR_MethodTable(TO_TADDR(mt));
+ BOOL bIsFree = FALSE;
+ if (!pMT || !DacValidateMethodTable(pMT, bIsFree))
+ {
+ hr = E_INVALIDARG;
+ }
+ else
+ {
+ data->wNumInstanceFields = pMT->GetNumInstanceFields();
+ data->wNumStaticFields = pMT->GetNumStaticFields();
+ data->wNumThreadStaticFields = pMT->GetNumThreadStaticFields();
+
+ data->FirstField = PTR_TO_TADDR(pMT->GetClass()->GetFieldDescList());
+
+#ifdef FEATURE_REMOTING
+ BOOL hasContextStatics = pMT->HasContextStatics();
+
+ data->wContextStaticsSize = (hasContextStatics) ? pMT->GetContextStaticsSize() : 0;
+ _ASSERTE(!hasContextStatics || FitsIn<WORD>(pMT->GetContextStaticsOffset()));
+ data->wContextStaticOffset = (hasContextStatics) ? static_cast<WORD>(pMT->GetContextStaticsOffset()) : 0;
+#else
+ data->wContextStaticsSize = 0;
+ data->wContextStaticOffset = 0;
+#endif
+ }
+
+ SOSDacLeave();
+ return hr;
+}
+
+HRESULT
+ClrDataAccess::GetMethodTableTransparencyData(CLRDATA_ADDRESS mt, struct DacpMethodTableTransparencyData *pTransparencyData)
+{
+ if (mt == 0 || pTransparencyData == NULL)
+ return E_INVALIDARG;
+
+ SOSDacEnter();
+
+ MethodTable *pMT = PTR_MethodTable(TO_TADDR(mt));
+ BOOL bIsFree = FALSE;
+ if (!DacValidateMethodTable(pMT, bIsFree))
+ {
+ hr = E_INVALIDARG;
+ }
+ else
+ {
+ ZeroMemory(pTransparencyData, sizeof(DacpMethodTableTransparencyData));
+
+ EEClass * pClass = pMT->GetClass();
+ if (pClass->HasCriticalTransparentInfo())
+ {
+ pTransparencyData->bHasCriticalTransparentInfo = pClass->HasCriticalTransparentInfo();
+ pTransparencyData->bIsCritical = pClass->IsCritical() || pClass->IsAllCritical();
+ pTransparencyData->bIsTreatAsSafe = pClass->IsTreatAsSafe();
+ }
+ }
+
+ SOSDacLeave();
+ return hr;
+}
+
+HRESULT
+ClrDataAccess::GetMethodTableForEEClass(CLRDATA_ADDRESS eeClass, CLRDATA_ADDRESS *value)
+{
+ if (eeClass == 0 || value == NULL)
+ return E_INVALIDARG;
+
+ SOSDacEnter();
+
+ EEClass * pClass = PTR_EEClass(TO_TADDR(eeClass));
+ if (!DacValidateEEClass(pClass))
+ {
+ hr = E_INVALIDARG;
+ }
+ else
+ {
+ *value = HOST_CDADDR(pClass->GetMethodTable());
+ }
+
+ SOSDacLeave();
+ return hr;
+}
+
+HRESULT
+ClrDataAccess::GetFrameName(CLRDATA_ADDRESS vtable, unsigned int count, __out_z __inout_ecount(count) wchar_t *frameName, unsigned int *pNeeded)
+{
+ if (vtable == 0)
+ return E_INVALIDARG;
+
+ SOSDacEnter();
+
+ PWSTR pszName = DacGetVtNameW(CLRDATA_ADDRESS_TO_TADDR(vtable));
+ if (pszName == NULL)
+ {
+ hr = E_INVALIDARG;
+ }
+ else
+ {
+ // Turn from bytes to wide characters
+ unsigned int len = (unsigned int)wcslen(pszName);
+
+ if (frameName)
+ {
+ wcsncpy_s(frameName, count, pszName, _TRUNCATE);
+
+ if (pNeeded)
+ {
+ if (count < len)
+ *pNeeded = count - 1;
+ else
+ *pNeeded = len;
+ }
+ }
+ else if (pNeeded)
+ {
+ *pNeeded = len + 1;
+ }
+ }
+
+ SOSDacLeave();
+ return hr;
+}
+
+HRESULT
+ClrDataAccess::GetPEFileName(CLRDATA_ADDRESS addr, unsigned int count, __out_z __inout_ecount(count) wchar_t *fileName, unsigned int *pNeeded)
+{
+ if (addr == 0 || (fileName == NULL && pNeeded == NULL) || (fileName != NULL && count == 0))
+ return E_INVALIDARG;
+
+ SOSDacEnter();
+ PEFile* pPEFile = PTR_PEFile(TO_TADDR(addr));
+
+ // Turn from bytes to wide characters
+ if (!pPEFile->GetPath().IsEmpty())
+ {
+ if (!pPEFile->GetPath().DacGetUnicode(count, fileName, pNeeded))
+ hr = E_FAIL;
+ }
+ else if (!pPEFile->IsDynamic())
+ {
+ PEAssembly *pAssembly = pPEFile->GetAssembly();
+ StackSString displayName;
+ pAssembly->GetDisplayName(displayName, 0);
+
+ if (displayName.IsEmpty())
+ {
+ if (fileName)
+ fileName[0] = 0;
+
+ if (pNeeded)
+ *pNeeded = 1;
+ }
+ else
+ {
+ unsigned int len = displayName.GetCount()+1;
+
+ if (fileName)
+ {
+ wcsncpy_s(fileName, count, displayName.GetUnicode(), _TRUNCATE);
+
+ if (count < len)
+ len = count;
+ }
+
+ if (pNeeded)
+ *pNeeded = len;
+ }
+ }
+ else
+ {
+ if (fileName && count)
+ fileName[0] = 0;
+
+ if (pNeeded)
+ *pNeeded = 1;
+ }
+
+ SOSDacLeave();
+ return hr;
+}
+
+HRESULT
+ClrDataAccess::GetPEFileBase(CLRDATA_ADDRESS addr, CLRDATA_ADDRESS *base)
+{
+ if (addr == 0 || base == NULL)
+ return E_INVALIDARG;
+
+ SOSDacEnter();
+
+ PEFile* pPEFile = PTR_PEFile(TO_TADDR(addr));
+
+ // More fields later?
+ if (pPEFile->HasNativeImage())
+ *base = TO_CDADDR(PTR_TO_TADDR(pPEFile->GetLoadedNative()->GetBase()));
+ else if (!pPEFile->IsDynamic())
+ *base = TO_CDADDR(pPEFile->GetIJWBase());
+ else
+ *base = NULL;
+
+ SOSDacLeave();
+ return hr;
+}
+
+DWORD DACGetNumComponents(TADDR addr, ICorDebugDataTarget* target)
+{
+ // For an object pointer, this attempts to read the number of
+ // array components.
+ addr+=sizeof(size_t);
+ ULONG32 returned = 0;
+ DWORD Value = NULL;
+ HRESULT hr = target->ReadVirtual(addr, (PBYTE)&Value, sizeof(DWORD), &returned);
+
+ if ((hr != S_OK) || (returned != sizeof(DWORD)))
+ {
+ return 0;
+ }
+ return Value;
+}
+
+HRESULT
+ClrDataAccess::GetObjectData(CLRDATA_ADDRESS addr, struct DacpObjectData *objectData)
+{
+ if (addr == 0 || objectData == NULL)
+ return E_INVALIDARG;
+
+ SOSDacEnter();
+
+ ZeroMemory (objectData, sizeof(DacpObjectData));
+ TADDR mtTADDR = DACGetMethodTableFromObjectPointer(CLRDATA_ADDRESS_TO_TADDR(addr),m_pTarget);
+ if (mtTADDR==NULL)
+ hr = E_INVALIDARG;
+
+ BOOL bFree = FALSE;
+ MethodTable *mt = NULL;
+ if (SUCCEEDED(hr))
+ {
+ mt = PTR_MethodTable(mtTADDR);
+ if (!DacValidateMethodTable(mt, bFree))
+ hr = E_INVALIDARG;
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ objectData->MethodTable = HOST_CDADDR(mt);
+ objectData->Size = mt->GetBaseSize();
+ if (mt->GetComponentSize())
+ {
+ objectData->Size += (DACGetNumComponents(CLRDATA_ADDRESS_TO_TADDR(addr),m_pTarget) * mt->GetComponentSize());
+ objectData->dwComponentSize = mt->GetComponentSize();
+ }
+
+ if (bFree)
+ {
+ objectData->ObjectType = OBJ_FREE;
+ }
+ else
+ {
+ if (objectData->MethodTable == HOST_CDADDR(g_pStringClass))
+ {
+ objectData->ObjectType = OBJ_STRING;
+ }
+ else if (objectData->MethodTable == HOST_CDADDR(g_pObjectClass))
+ {
+ objectData->ObjectType = OBJ_OBJECT;
+ }
+ else if (mt->IsArray())
+ {
+ objectData->ObjectType = OBJ_ARRAY;
+
+ // For now, go ahead and instantiate array classes.
+ // TODO: avoid instantiating even object Arrays in the host.
+ // NOTE: This code is carefully written to deal with MethodTable fields
+ // in the array object having the mark bit set (because we may
+ // be in mark phase when this function is called).
+ ArrayBase *pArrayObj = PTR_ArrayBase(TO_TADDR(addr));
+ objectData->ElementType = mt->GetArrayElementType();
+
+ TypeHandle thElem = mt->GetApproxArrayElementTypeHandle();
+
+ TypeHandle thCur = thElem;
+ while (thCur.IsTypeDesc())
+ thCur = thCur.AsArray()->GetArrayElementTypeHandle();
+
+ TADDR mtCurTADDR = thCur.AsTAddr();
+ if (!DacValidateMethodTable(PTR_MethodTable(mtCurTADDR), bFree))
+ {
+ hr = E_INVALIDARG;
+ }
+ else
+ {
+ objectData->ElementTypeHandle = (CLRDATA_ADDRESS)(thElem.AsTAddr());
+ objectData->dwRank = mt->GetRank();
+ objectData->dwNumComponents = pArrayObj->GetNumComponents ();
+ objectData->ArrayDataPtr = PTR_CDADDR(pArrayObj->GetDataPtr (TRUE));
+ objectData->ArrayBoundsPtr = HOST_CDADDR(pArrayObj->GetBoundsPtr());
+ objectData->ArrayLowerBoundsPtr = HOST_CDADDR(pArrayObj->GetLowerBoundsPtr());
+ }
+ }
+ else
+ {
+ objectData->ObjectType = OBJ_OTHER;
+ }
+ }
+ }
+
+#ifdef FEATURE_COMINTEROP
+ if (SUCCEEDED(hr))
+ {
+ EX_TRY_ALLOW_DATATARGET_MISSING_MEMORY
+ {
+ PTR_SyncBlock pSyncBlk = DACGetSyncBlockFromObjectPointer(CLRDATA_ADDRESS_TO_TADDR(addr), m_pTarget);
+ if (pSyncBlk != NULL)
+ {
+ // see if we have an RCW and/or CCW associated with this object
+ PTR_InteropSyncBlockInfo pInfo = pSyncBlk->GetInteropInfoNoCreate();
+ if (pInfo != NULL)
+ {
+ objectData->RCW = TO_CDADDR(pInfo->DacGetRawRCW());
+ objectData->CCW = HOST_CDADDR(pInfo->GetCCW());
+ }
+ }
+ }
+ EX_END_CATCH_ALLOW_DATATARGET_MISSING_MEMORY;
+ }
+#endif // FEATURE_COMINTEROP
+
+ SOSDacLeave();
+
+ return hr;
+}
+
+HRESULT ClrDataAccess::GetAppDomainList(unsigned int count, CLRDATA_ADDRESS values[], unsigned int *fetched)
+{
+ SOSDacEnter();
+
+ AppDomainIterator ai(FALSE);
+ unsigned int i = 0;
+ while (ai.Next() && (i < count))
+ {
+ if (values)
+ values[i] = HOST_CDADDR(ai.GetDomain());
+ i++;
+ }
+
+ if (fetched)
+ *fetched = i;
+
+ SOSDacLeave();
+ return hr;
+}
+
+HRESULT
+ClrDataAccess::GetAppDomainStoreData(struct DacpAppDomainStoreData *adsData)
+{
+ SOSDacEnter();
+
+ adsData->systemDomain = HOST_CDADDR(SystemDomain::System());
+ adsData->sharedDomain = HOST_CDADDR(SharedDomain::GetDomain());
+
+ // Get an accurate count of appdomains.
+ adsData->DomainCount = 0;
+ AppDomainIterator ai(FALSE);
+ while (ai.Next())
+ adsData->DomainCount++;
+
+ SOSDacLeave();
+ return hr;
+}
+
+HRESULT
+ClrDataAccess::GetAppDomainData(CLRDATA_ADDRESS addr, struct DacpAppDomainData *appdomainData)
+{
+ SOSDacEnter();
+
+ if (addr == 0)
+ {
+ hr = E_INVALIDARG;
+ }
+ else
+ {
+ PTR_BaseDomain pBaseDomain = PTR_BaseDomain(TO_TADDR(addr));
+
+ ZeroMemory(appdomainData, sizeof(DacpAppDomainData));
+ appdomainData->AppDomainPtr = PTR_CDADDR(pBaseDomain);
+ PTR_LoaderAllocator pLoaderAllocator = pBaseDomain->GetLoaderAllocator();
+ appdomainData->pHighFrequencyHeap = HOST_CDADDR(pLoaderAllocator->GetHighFrequencyHeap());
+ appdomainData->pLowFrequencyHeap = HOST_CDADDR(pLoaderAllocator->GetLowFrequencyHeap());
+ appdomainData->pStubHeap = HOST_CDADDR(pLoaderAllocator->GetStubHeap());
+ appdomainData->appDomainStage = STAGE_OPEN;
+
+ if (pBaseDomain->IsSharedDomain())
+ {
+ #ifdef FEATURE_LOADER_OPTIMIZATION
+ SharedDomain::SharedAssemblyIterator i;
+ while (i.Next())
+ {
+ appdomainData->AssemblyCount++;
+ }
+ #endif // FEATURE_LOADER_OPTIMIZATION
+ }
+ else if (pBaseDomain->IsAppDomain())
+ {
+ AppDomain * pAppDomain = pBaseDomain->AsAppDomain();
+ appdomainData->DomainLocalBlock = appdomainData->AppDomainPtr +
+ offsetof(AppDomain, m_sDomainLocalBlock);
+ appdomainData->pDomainLocalModules = PTR_CDADDR(pAppDomain->m_sDomainLocalBlock.m_pModuleSlots);
+
+ appdomainData->dwId = pAppDomain->GetId().m_dwId;
+ appdomainData->appDomainStage = (DacpAppDomainDataStage)pAppDomain->m_Stage.Load();
+ if (pAppDomain->IsActive())
+ {
+ // The assembly list is not valid in a closed appdomain.
+ AppDomain::AssemblyIterator i = pAppDomain->IterateAssembliesEx((AssemblyIterationFlags)(
+ kIncludeLoading | kIncludeLoaded | kIncludeExecution));
+ CollectibleAssemblyHolder<DomainAssembly *> pDomainAssembly;
+
+ while (i.Next(pDomainAssembly.This()))
+ {
+ if (pDomainAssembly->IsLoaded())
+ {
+ appdomainData->AssemblyCount++;
+ }
+ }
+
+ AppDomain::FailedAssemblyIterator j = pAppDomain->IterateFailedAssembliesEx();
+ while (j.Next())
+ {
+ appdomainData->FailedAssemblyCount++;
+ }
+ }
+
+ // MiniDumpNormal doesn't guarantee to dump the SecurityDescriptor, let it fail.
+ EX_TRY
+ {
+ appdomainData->AppSecDesc = HOST_CDADDR(pAppDomain->GetSecurityDescriptor());
+ }
+ EX_CATCH
+ {
+ HRESULT hrExc = GET_EXCEPTION()->GetHR();
+ if (hrExc != HRESULT_FROM_WIN32(ERROR_READ_FAULT)
+ && hrExc != CORDBG_E_READVIRTUAL_FAILURE)
+ {
+ EX_RETHROW;
+ }
+ }
+ EX_END_CATCH(SwallowAllExceptions)
+ }
+ }
+
+ SOSDacLeave();
+ return hr;
+}
+
+HRESULT
+ClrDataAccess::GetFailedAssemblyData(CLRDATA_ADDRESS assembly, unsigned int *pContext, HRESULT *pResult)
+{
+ if (assembly == NULL || (pContext == NULL && pResult == NULL))
+ {
+ return E_INVALIDARG;
+ }
+
+ SOSDacEnter();
+
+ FailedAssembly* pAssembly = PTR_FailedAssembly(TO_TADDR(assembly));
+ if (!pAssembly)
+ {
+ hr = E_INVALIDARG;
+ }
+ else
+ {
+#ifdef FEATURE_FUSION
+ if (pContext)
+ *pContext = pAssembly->context;
+#endif
+ if (pResult)
+ *pResult = pAssembly->error;
+ }
+
+ SOSDacLeave();
+ return hr;
+}
+
+HRESULT
+ClrDataAccess::GetFailedAssemblyLocation(CLRDATA_ADDRESS assembly, unsigned int count,
+ __out_z __inout_ecount(count) wchar_t *location, unsigned int *pNeeded)
+{
+ if (assembly == NULL || (location == NULL && pNeeded == NULL) || (location != NULL && count == 0))
+ return E_INVALIDARG;
+
+ SOSDacEnter();
+ FailedAssembly* pAssembly = PTR_FailedAssembly(TO_TADDR(assembly));
+
+ // Turn from bytes to wide characters
+ if (!pAssembly->location.IsEmpty())
+ {
+ if (!pAssembly->location.DacGetUnicode(count, location, pNeeded))
+ {
+ hr = E_FAIL;
+ }
+ }
+ else
+ {
+ if (pNeeded)
+ *pNeeded = 1;
+
+ if (location)
+ location[0] = 0;
+ }
+
+ SOSDacLeave();
+ return hr;
+}
+
+HRESULT
+ClrDataAccess::GetFailedAssemblyDisplayName(CLRDATA_ADDRESS assembly, unsigned int count, __out_z __inout_ecount(count) wchar_t *name, unsigned int *pNeeded)
+{
+ if (assembly == NULL || (name == NULL && pNeeded == NULL) || (name != NULL && count == 0))
+ return E_INVALIDARG;
+
+ SOSDacEnter();
+ FailedAssembly* pAssembly = PTR_FailedAssembly(TO_TADDR(assembly));
+
+ if (!pAssembly->displayName.IsEmpty())
+ {
+ if (!pAssembly->displayName.DacGetUnicode(count, name, pNeeded))
+ {
+ hr = E_FAIL;
+ }
+ }
+ else
+ {
+ if (pNeeded)
+ *pNeeded = 1;
+
+ if (name)
+ name[0] = 0;
+ }
+
+ SOSDacLeave();
+ return hr;
+}
+
+
+HRESULT
+ClrDataAccess::GetAssemblyList(CLRDATA_ADDRESS addr, int count, CLRDATA_ADDRESS values[], int *pNeeded)
+{
+ if (addr == NULL)
+ return E_INVALIDARG;
+
+ SOSDacEnter();
+
+ BaseDomain* pBaseDomain = PTR_BaseDomain(TO_TADDR(addr));
+
+ int n=0;
+ if (pBaseDomain->IsSharedDomain())
+ {
+#ifdef FEATURE_LOADER_OPTIMIZATION
+ SharedDomain::SharedAssemblyIterator i;
+ if (values)
+ {
+ while (i.Next() && n < count)
+ values[n++] = HOST_CDADDR(i.GetAssembly());
+ }
+ else
+ {
+ while (i.Next())
+ n++;
+ }
+
+ if (pNeeded)
+ *pNeeded = n;
+#else
+ hr = E_UNEXPECTED;
+#endif
+ }
+ else if (pBaseDomain->IsAppDomain())
+ {
+ AppDomain::AssemblyIterator i = pBaseDomain->AsAppDomain()->IterateAssembliesEx(
+ (AssemblyIterationFlags)(kIncludeLoading | kIncludeLoaded | kIncludeExecution));
+ CollectibleAssemblyHolder<DomainAssembly *> pDomainAssembly;
+
+ if (values)
+ {
+ while (i.Next(pDomainAssembly.This()) && (n < count))
+ {
+ if (pDomainAssembly->IsLoaded())
+ {
+ CollectibleAssemblyHolder<Assembly *> pAssembly = pDomainAssembly->GetAssembly();
+ // Note: DAC doesn't need to keep the assembly alive - see code:CollectibleAssemblyHolder#CAH_DAC
+ values[n++] = HOST_CDADDR(pAssembly.Extract());
+ }
+ }
+ }
+ else
+ {
+ while (i.Next(pDomainAssembly.This()))
+ if (pDomainAssembly->IsLoaded())
+ n++;
+ }
+
+ if (pNeeded)
+ *pNeeded = n;
+ }
+ else
+ {
+ // The only other type of BaseDomain is the SystemDomain, and we shouldn't be asking
+ // for the assemblies in it.
+ _ASSERTE(false);
+ hr = E_INVALIDARG;
+ }
+
+ SOSDacLeave();
+ return hr;
+}
+
+HRESULT
+ClrDataAccess::GetFailedAssemblyList(CLRDATA_ADDRESS appDomain, int count,
+ CLRDATA_ADDRESS values[], unsigned int *pNeeded)
+{
+ if ((appDomain == NULL) || (values == NULL && pNeeded == NULL))
+ {
+ return E_INVALIDARG;
+ }
+
+ SOSDacEnter();
+ AppDomain* pAppDomain = PTR_AppDomain(TO_TADDR(appDomain));
+
+ int n=0;
+ AppDomain::FailedAssemblyIterator i = pAppDomain->IterateFailedAssembliesEx();
+ while (i.Next() && n<=count)
+ {
+ if (values)
+ values[n] = HOST_CDADDR(i.GetFailedAssembly());
+
+ n++;
+ }
+
+ if (pNeeded)
+ *pNeeded = n;
+
+ SOSDacLeave();
+ return hr;
+}
+
+HRESULT
+ClrDataAccess::GetAppDomainName(CLRDATA_ADDRESS addr, unsigned int count, __out_z __inout_ecount(count) wchar_t *name, unsigned int *pNeeded)
+{
+ SOSDacEnter();
+
+ PTR_BaseDomain pBaseDomain = PTR_BaseDomain(TO_TADDR(addr));
+ if (!pBaseDomain->IsAppDomain())
+ {
+ // Shared domain and SystemDomain don't have this field.
+ if (pNeeded)
+ *pNeeded = 1;
+ if (name)
+ name[0] = 0;
+ }
+ else
+ {
+ AppDomain* pAppDomain = pBaseDomain->AsAppDomain();
+
+ if (!pAppDomain->m_friendlyName.IsEmpty())
+ {
+ if (!pAppDomain->m_friendlyName.DacGetUnicode(count, name, pNeeded))
+ {
+ hr = E_FAIL;
+ }
+ }
+ else
+ {
+ if (pNeeded)
+ *pNeeded = 1;
+ if (name)
+ name[0] = 0;
+
+ hr = S_OK;
+ }
+ }
+
+ SOSDacLeave();
+ return hr;
+}
+
+HRESULT
+ClrDataAccess::GetApplicationBase(CLRDATA_ADDRESS appDomain, int count,
+ __out_z __inout_ecount(count) wchar_t *base, unsigned int *pNeeded)
+{
+ if (appDomain == NULL || (base == NULL && pNeeded == NULL) || (base != NULL && count == 0))
+ {
+ return E_INVALIDARG;
+ }
+
+ SOSDacEnter();
+ AppDomain* pAppDomain = PTR_AppDomain(TO_TADDR(appDomain));
+
+ // Turn from bytes to wide characters
+ if ((PTR_BaseDomain(pAppDomain) == PTR_BaseDomain(SharedDomain::GetDomain())) ||
+ (PTR_BaseDomain(pAppDomain) == PTR_BaseDomain(SystemDomain::System())))
+ {
+ // Shared domain and SystemDomain don't have this field.
+ if (base)
+ base[0] = 0;
+
+ if (pNeeded)
+ *pNeeded = 1;
+ }
+
+ if (!pAppDomain->m_applicationBase.IsEmpty())
+ {
+ if (!pAppDomain->m_applicationBase.
+ DacGetUnicode(count, base, pNeeded))
+ {
+ hr = E_FAIL;
+ }
+ }
+ else
+ {
+ if (base)
+ base[0] = 0;
+
+ if (pNeeded)
+ *pNeeded = 1;
+ }
+
+ SOSDacLeave();
+ return hr;
+}
+
+HRESULT
+ClrDataAccess::GetPrivateBinPaths(CLRDATA_ADDRESS appDomain, int count,
+ __out_z __inout_ecount(count) wchar_t *paths, unsigned int *pNeeded)
+{
+ if (appDomain == NULL || (paths == NULL && pNeeded == NULL) || (paths != NULL && count == 0))
+ return E_INVALIDARG;
+
+ SOSDacEnter();
+ AppDomain* pAppDomain = PTR_AppDomain(TO_TADDR(appDomain));
+
+ // Turn from bytes to wide characters
+ if ((PTR_BaseDomain(pAppDomain) == PTR_BaseDomain(SharedDomain::GetDomain())) ||
+ (PTR_BaseDomain(pAppDomain) == PTR_BaseDomain(SystemDomain::System())))
+ {
+ // Shared domain and SystemDomain don't have this field.
+ if (pNeeded)
+ *pNeeded = 1;
+
+ if (paths)
+ paths[0] = 0;
+
+ hr = S_OK;
+ }
+
+ if (!pAppDomain->m_privateBinPaths.IsEmpty())
+ {
+ if (!pAppDomain->m_privateBinPaths.DacGetUnicode(count, paths, pNeeded))
+ {
+ hr = E_FAIL;
+ }
+ }
+ else
+ {
+ if (paths)
+ paths[0] = 0;
+
+ if (pNeeded)
+ *pNeeded = 1;
+ }
+
+ SOSDacLeave();
+ return hr;
+}
+
+HRESULT
+ClrDataAccess::GetAppDomainConfigFile(CLRDATA_ADDRESS appDomain, int count,
+ __out_z __inout_ecount(count) wchar_t *configFile, unsigned int *pNeeded)
+{
+ if (appDomain == NULL || (configFile == NULL && pNeeded == NULL) || (configFile != NULL && count == 0))
+ {
+ return E_INVALIDARG;
+ }
+
+ SOSDacEnter();
+ AppDomain* pAppDomain = PTR_AppDomain(TO_TADDR(appDomain));
+
+ // Turn from bytes to wide characters
+
+ if ((PTR_BaseDomain(pAppDomain) == PTR_BaseDomain(SharedDomain::GetDomain())) ||
+ (PTR_BaseDomain(pAppDomain) == PTR_BaseDomain(SystemDomain::System())))
+ {
+ // Shared domain and SystemDomain don't have this field.
+ if (configFile)
+ configFile[0] = 0;
+
+ if (pNeeded)
+ *pNeeded = 1;
+ }
+
+ if (!pAppDomain->m_configFile.IsEmpty())
+ {
+ if (!pAppDomain->m_configFile.DacGetUnicode(count, configFile, pNeeded))
+ {
+ hr = E_FAIL;
+ }
+ }
+ else
+ {
+ if (configFile)
+ configFile[0] = 0;
+
+ if (pNeeded)
+ *pNeeded = 1;
+ }
+
+ SOSDacLeave();
+ return hr;
+}
+
+HRESULT
+ClrDataAccess::GetAssemblyData(CLRDATA_ADDRESS cdBaseDomainPtr, CLRDATA_ADDRESS assembly, struct DacpAssemblyData *assemblyData)
+{
+ if (assembly == NULL && cdBaseDomainPtr == NULL)
+ {
+ return E_INVALIDARG;
+ }
+
+ SOSDacEnter();
+
+ Assembly* pAssembly = PTR_Assembly(TO_TADDR(assembly));
+
+ // Make sure conditionally-assigned fields like AssemblySecDesc, LoadContext, etc. are zeroed
+ ZeroMemory(assemblyData, sizeof(DacpAssemblyData));
+
+ // If the specified BaseDomain is an AppDomain, get a pointer to it
+ AppDomain * pDomain = NULL;
+ if (cdBaseDomainPtr != NULL)
+ {
+ assemblyData->BaseDomainPtr = cdBaseDomainPtr;
+ PTR_BaseDomain baseDomain = PTR_BaseDomain(TO_TADDR(cdBaseDomainPtr));
+ if( baseDomain->IsAppDomain() )
+ pDomain = baseDomain->AsAppDomain();
+ }
+
+ assemblyData->AssemblyPtr = HOST_CDADDR(pAssembly);
+ assemblyData->ClassLoader = HOST_CDADDR(pAssembly->GetLoader());
+ assemblyData->ParentDomain = HOST_CDADDR(pAssembly->GetDomain());
+ if (pDomain != NULL)
+ assemblyData->AssemblySecDesc = HOST_CDADDR(pAssembly->GetSecurityDescriptor(pDomain));
+ assemblyData->isDynamic = pAssembly->IsDynamic();
+ assemblyData->ModuleCount = 0;
+ assemblyData->isDomainNeutral = pAssembly->IsDomainNeutral();
+
+ if (pAssembly->GetManifestFile())
+ {
+#ifdef FEATURE_FUSION
+ assemblyData->LoadContext = pAssembly->GetManifestFile()->GetLoadContext();
+ assemblyData->dwLocationFlags = pAssembly->GetManifestFile()->GetLocationFlags();
+#endif
+
+ }
+
+ ModuleIterator mi = pAssembly->IterateModules();
+ while (mi.Next())
+ {
+ assemblyData->ModuleCount++;
+ }
+
+ SOSDacLeave();
+ return hr;
+}
+
+HRESULT
+ClrDataAccess::GetAssemblyName(CLRDATA_ADDRESS assembly, unsigned int count, __out_z __inout_ecount(count) wchar_t *name, unsigned int *pNeeded)
+{
+ SOSDacEnter();
+ Assembly* pAssembly = PTR_Assembly(TO_TADDR(assembly));
+
+ if (name)
+ name[0] = 0;
+
+ if (!pAssembly->GetManifestFile()->GetPath().IsEmpty())
+ {
+ if (!pAssembly->GetManifestFile()->GetPath().DacGetUnicode(count, name, pNeeded))
+ hr = E_FAIL;
+ else if (name)
+ name[count-1] = 0;
+ }
+ else if (!pAssembly->GetManifestFile()->IsDynamic())
+ {
+ StackSString displayName;
+ pAssembly->GetManifestFile()->GetDisplayName(displayName, 0);
+
+ const wchar_t *val = displayName.GetUnicode();
+
+ if (pNeeded)
+ *pNeeded = displayName.GetCount() + 1;
+
+ if (name && count)
+ {
+ wcsncpy_s(name, count, val, _TRUNCATE);
+ name[count-1] = 0;
+ }
+ }
+ else
+ {
+ hr = E_FAIL;
+ }
+
+ SOSDacLeave();
+ return hr;
+}
+
+HRESULT
+ClrDataAccess::GetAssemblyLocation(CLRDATA_ADDRESS assembly, int count, __out_z __inout_ecount(count) wchar_t *location, unsigned int *pNeeded)
+{
+ if ((assembly == NULL) || (location == NULL && pNeeded == NULL) || (location != NULL && count == 0))
+ {
+ return E_INVALIDARG;
+ }
+
+ SOSDacEnter();
+
+ Assembly* pAssembly = PTR_Assembly(TO_TADDR(assembly));
+
+ // Turn from bytes to wide characters
+ if (!pAssembly->GetManifestFile()->GetPath().IsEmpty())
+ {
+ if (!pAssembly->GetManifestFile()->GetPath().
+ DacGetUnicode(count, location, pNeeded))
+ {
+ hr = E_FAIL;
+ }
+ }
+ else
+ {
+ if (location)
+ location[0] = 0;
+
+ if (pNeeded)
+ *pNeeded = 1;
+ }
+
+ SOSDacLeave();
+ return hr;
+}
+
+HRESULT
+ClrDataAccess::GetAssemblyModuleList(CLRDATA_ADDRESS assembly, unsigned int count, CLRDATA_ADDRESS modules[], unsigned int *pNeeded)
+{
+ if (assembly == 0)
+ return E_INVALIDARG;
+
+ SOSDacEnter();
+
+ Assembly* pAssembly = PTR_Assembly(TO_TADDR(assembly));
+ ModuleIterator mi = pAssembly->IterateModules();
+ unsigned int n = 0;
+ if (modules)
+ {
+ while (mi.Next() && n < count)
+ modules[n++] = HOST_CDADDR(mi.GetModule());
+ }
+ else
+ {
+ while (mi.Next())
+ n++;
+ }
+
+ if (pNeeded)
+ *pNeeded = n;
+
+ SOSDacLeave();
+ return hr;
+}
+
+HRESULT
+ClrDataAccess::GetGCHeapDetails(CLRDATA_ADDRESS heap, struct DacpGcHeapDetails *details)
+{
+ if (heap == 0 || details == NULL)
+ return E_INVALIDARG;
+
+ SOSDacEnter();
+
+ // doesn't make sense to call this on WKS mode
+ if (!GCHeap::IsServerHeap())
+ hr = E_INVALIDARG;
+ else
+#ifdef FEATURE_SVR_GC
+ hr = ServerGCHeapDetails(heap, details);
+#else
+ hr = E_NOTIMPL;
+#endif
+
+ SOSDacLeave();
+ return hr;
+}
+
+HRESULT
+ClrDataAccess::GetGCHeapStaticData(struct DacpGcHeapDetails *detailsData)
+{
+ if (detailsData == NULL)
+ return E_INVALIDARG;
+
+ SOSDacEnter();
+
+ detailsData->lowest_address = PTR_CDADDR(g_lowest_address);
+ detailsData->highest_address = PTR_CDADDR(g_highest_address);
+ detailsData->card_table = PTR_CDADDR(g_card_table);
+
+ detailsData->heapAddr = NULL;
+
+ detailsData->alloc_allocated = PTR_CDADDR(WKS::gc_heap::alloc_allocated);
+ detailsData->ephemeral_heap_segment = PTR_CDADDR(WKS::gc_heap::ephemeral_heap_segment);
+
+#ifdef BACKGROUND_GC
+ detailsData->mark_array = PTR_CDADDR(WKS::gc_heap::mark_array);
+ detailsData->current_c_gc_state = (CLRDATA_ADDRESS)(ULONG_PTR)WKS::gc_heap::current_c_gc_state;
+ detailsData->next_sweep_obj = PTR_CDADDR(WKS::gc_heap::next_sweep_obj);
+ detailsData->saved_sweep_ephemeral_seg = PTR_CDADDR(WKS::gc_heap::saved_sweep_ephemeral_seg);
+ detailsData->saved_sweep_ephemeral_start = PTR_CDADDR(WKS::gc_heap::saved_sweep_ephemeral_start);
+ detailsData->background_saved_lowest_address = PTR_CDADDR(WKS::gc_heap::background_saved_lowest_address);
+ detailsData->background_saved_highest_address = PTR_CDADDR(WKS::gc_heap::background_saved_highest_address);
+#endif //BACKGROUND_GC
+
+ for (int i=0;i<NUMBERGENERATIONS;i++)
+ {
+ detailsData->generation_table[i].start_segment = (CLRDATA_ADDRESS)dac_cast<TADDR>(WKS::generation_table[i].start_segment);
+ detailsData->generation_table[i].allocation_start = (CLRDATA_ADDRESS)(ULONG_PTR) WKS::generation_table[i].allocation_start;
+ detailsData->generation_table[i].allocContextPtr = (CLRDATA_ADDRESS)(ULONG_PTR) WKS::generation_table[i].allocation_context.alloc_ptr;
+ detailsData->generation_table[i].allocContextLimit = (CLRDATA_ADDRESS)(ULONG_PTR) WKS::generation_table[i].allocation_context.alloc_limit;
+ }
+
+ TADDR pFillPointerArray = TO_TADDR(WKS::gc_heap::finalize_queue.GetAddr()) + offsetof(WKS::CFinalize,m_FillPointers);
+ for(int i=0;i<(NUMBERGENERATIONS+WKS::CFinalize::ExtraSegCount);i++)
+ {
+ ULONG32 returned = 0;
+ size_t pValue;
+ hr = m_pTarget->ReadVirtual(pFillPointerArray+(i*sizeof(size_t)), (PBYTE)&pValue, sizeof(size_t), &returned);
+ if (SUCCEEDED(hr))
+ {
+ if (returned == sizeof(size_t))
+ detailsData->finalization_fill_pointers[i] = (CLRDATA_ADDRESS) pValue;
+ else
+ hr = E_FAIL;
+ }
+ }
+
+ SOSDacLeave();
+ return hr;
+}
+
+HRESULT
+ClrDataAccess::GetHeapSegmentData(CLRDATA_ADDRESS seg, struct DacpHeapSegmentData *heapSegment)
+{
+ if (seg == 0 || heapSegment == NULL)
+ return E_INVALIDARG;
+
+ SOSDacEnter();
+
+ if (GCHeap::IsServerHeap())
+ {
+#if !defined(FEATURE_SVR_GC)
+ _ASSERTE(0);
+#else // !defined(FEATURE_SVR_GC)
+ hr = GetServerHeapData(seg, heapSegment);
+#endif //!defined(FEATURE_SVR_GC)
+ }
+ else
+ {
+ WKS::heap_segment *pSegment = __DPtr<WKS::heap_segment>(TO_TADDR(seg));
+ if (!pSegment)
+ {
+ hr = E_INVALIDARG;
+ }
+ else
+ {
+ heapSegment->segmentAddr = seg;
+ heapSegment->allocated = (CLRDATA_ADDRESS)(ULONG_PTR) pSegment->allocated;
+ heapSegment->committed = (CLRDATA_ADDRESS)(ULONG_PTR) pSegment->committed;
+ heapSegment->reserved = (CLRDATA_ADDRESS)(ULONG_PTR) pSegment->reserved;
+ heapSegment->used = (CLRDATA_ADDRESS)(ULONG_PTR) pSegment->used;
+ heapSegment->mem = (CLRDATA_ADDRESS)(ULONG_PTR) pSegment->mem;
+ heapSegment->next = (CLRDATA_ADDRESS)dac_cast<TADDR>(pSegment->next);
+ heapSegment->flags = pSegment->flags;
+ heapSegment->gc_heap = NULL;
+ heapSegment->background_allocated = (CLRDATA_ADDRESS)(ULONG_PTR)pSegment->background_allocated;
+ }
+ }
+
+ SOSDacLeave();
+ return hr;
+}
+
+HRESULT
+ClrDataAccess::GetGCHeapList(unsigned int count, CLRDATA_ADDRESS heaps[], unsigned int *pNeeded)
+{
+ SOSDacEnter();
+
+ // make sure we called this in appropriate circumstances (i.e., we have multiple heaps)
+ if (GCHeap::IsServerHeap())
+ {
+#if !defined(FEATURE_SVR_GC)
+ _ASSERTE(0);
+#else // !defined(FEATURE_SVR_GC)
+ int heapCount = GCHeapCount();
+ if (pNeeded)
+ *pNeeded = heapCount;
+
+ if (heaps)
+ {
+ // get the heap locations
+ if (count == heapCount)
+ hr = GetServerHeaps(heaps, m_pTarget);
+ else
+ hr = E_INVALIDARG;
+ }
+#endif // !defined(FEATURE_SVR_GC)
+ }
+ else
+ {
+ hr = E_FAIL; // doesn't make sense to call this on WKS mode
+ }
+
+ SOSDacLeave();
+ return hr;
+}
+
+HRESULT
+ClrDataAccess::GetGCHeapData(struct DacpGcHeapData *gcheapData)
+{
+ if (gcheapData == NULL)
+ return E_INVALIDARG;
+
+ SOSDacEnter();
+
+ // Now get the heap type. The first data member of the GCHeap class is the GC_HEAP_TYPE, which has
+ // three possible values:
+ // GC_HEAP_INVALID = 0,
+ // GC_HEAP_WKS = 1,
+ // GC_HEAP_SVR = 2
+
+ TADDR gcHeapLocation = g_pGCHeap.GetAddrRaw (); // get the starting address of the global GCHeap instance
+ size_t gcHeapValue = 0; // this will hold the heap type
+ ULONG32 returned = 0;
+
+ // @todo Microsoft: we should probably be capturing the HRESULT from ReadVirtual. We could
+ // provide a more informative error message. E_FAIL is a wretchedly vague thing to return.
+ hr = m_pTarget->ReadVirtual(gcHeapLocation, (PBYTE)&gcHeapValue, sizeof(gcHeapValue), &returned);
+
+ //@todo Microsoft: We have an enumerated type, we probably should use the symbolic name
+ // we have GC_HEAP_INVALID if gcHeapValue == 0, so we're done
+ if (SUCCEEDED(hr) && ((returned != sizeof(gcHeapValue)) || (gcHeapValue == 0)))
+ hr = E_FAIL;
+
+ if (SUCCEEDED(hr))
+ {
+ // Now we can get other important information about the heap
+ gcheapData->g_max_generation = GCHeap::GetMaxGeneration();
+ gcheapData->bServerMode = GCHeap::IsServerHeap();
+ gcheapData->bGcStructuresValid = CNameSpace::GetGcRuntimeStructuresValid();
+ if (GCHeap::IsServerHeap())
+ {
+#if !defined (FEATURE_SVR_GC)
+ _ASSERTE(0);
+ gcheapData->HeapCount = 1;
+#else // !defined (FEATURE_SVR_GC)
+ gcheapData->HeapCount = GCHeapCount();
+#endif // !defined (FEATURE_SVR_GC)
+ }
+ else
+ {
+ gcheapData->HeapCount = 1;
+ }
+ }
+
+ SOSDacLeave();
+ return hr;
+}
+
+HRESULT
+ClrDataAccess::GetOOMStaticData(struct DacpOomData *oomData)
+{
+ if (oomData == NULL)
+ return E_INVALIDARG;
+
+ SOSDacEnter();
+
+ memset(oomData, 0, sizeof(DacpOomData));
+
+ if (!GCHeap::IsServerHeap())
+ {
+ oom_history* pOOMInfo = &(WKS::gc_heap::oom_info);
+ oomData->reason = pOOMInfo->reason;
+ oomData->alloc_size = pOOMInfo->alloc_size;
+ oomData->available_pagefile_mb = pOOMInfo->available_pagefile_mb;
+ oomData->gc_index = pOOMInfo->gc_index;
+ oomData->fgm = pOOMInfo->fgm;
+ oomData->size = pOOMInfo->size;
+ oomData->loh_p = pOOMInfo->loh_p;
+ }
+ else
+ {
+ hr = E_FAIL;
+ }
+
+ SOSDacLeave();
+ return hr;
+}
+
+HRESULT
+ClrDataAccess::GetOOMData(CLRDATA_ADDRESS oomAddr, struct DacpOomData *data)
+{
+ if (oomAddr == 0 || data == NULL)
+ return E_INVALIDARG;
+
+ SOSDacEnter();
+ memset(data, 0, sizeof(DacpOomData));
+
+ if (!GCHeap::IsServerHeap())
+ hr = E_FAIL; // doesn't make sense to call this on WKS mode
+
+#ifdef FEATURE_SVR_GC
+ else
+ hr = ServerOomData(oomAddr, data);
+#else
+ _ASSERTE_MSG(false, "IsServerHeap returned true but FEATURE_SVR_GC not defined");
+ hr = E_NOTIMPL;
+#endif //FEATURE_SVR_GC
+
+ SOSDacLeave();
+ return hr;
+}
+
+HRESULT
+ClrDataAccess::GetHeapAnalyzeData(CLRDATA_ADDRESS addr, struct DacpGcHeapAnalyzeData *data)
+{
+ if (addr == 0 || data == NULL)
+ return E_INVALIDARG;
+
+ SOSDacEnter();
+
+ if (!GCHeap::IsServerHeap())
+ hr = E_FAIL; // doesn't make sense to call this on WKS mode
+
+#ifdef FEATURE_SVR_GC
+ else
+ hr = ServerGCHeapAnalyzeData(addr, data);
+#else
+ _ASSERTE_MSG(false, "IsServerHeap returned true but FEATURE_SVR_GC not defined");
+ hr = E_NOTIMPL;
+#endif //FEATURE_SVR_GC
+
+ SOSDacLeave();
+ return hr;
+}
+
+HRESULT
+ClrDataAccess::GetHeapAnalyzeStaticData(struct DacpGcHeapAnalyzeData *analyzeData)
+{
+ if (analyzeData == NULL)
+ return E_INVALIDARG;
+
+ SOSDacEnter();
+
+ analyzeData->internal_root_array = PTR_CDADDR(WKS::gc_heap::internal_root_array);
+ analyzeData->internal_root_array_index = (size_t) WKS::gc_heap::internal_root_array_index;
+ analyzeData->heap_analyze_success = (BOOL) WKS::gc_heap::heap_analyze_success;
+
+ SOSDacLeave();
+ return hr;
+}
+
+HRESULT
+ClrDataAccess::GetUsefulGlobals(struct DacpUsefulGlobalsData *globalsData)
+{
+ if (globalsData == NULL)
+ return E_INVALIDARG;
+
+ SOSDacEnter();
+
+ PTR_ArrayTypeDesc objArray = g_pPredefinedArrayTypes[ELEMENT_TYPE_OBJECT];
+ if (objArray)
+ globalsData->ArrayMethodTable = HOST_CDADDR(objArray->GetMethodTable());
+ else
+ globalsData->ArrayMethodTable = 0;
+
+ globalsData->StringMethodTable = HOST_CDADDR(g_pStringClass);
+ globalsData->ObjectMethodTable = HOST_CDADDR(g_pObjectClass);
+ globalsData->ExceptionMethodTable = HOST_CDADDR(g_pExceptionClass);
+ globalsData->FreeMethodTable = HOST_CDADDR(g_pFreeObjectMethodTable);
+
+ SOSDacLeave();
+ return hr;
+}
+
+
+HRESULT
+ClrDataAccess::GetNestedExceptionData(CLRDATA_ADDRESS exception, CLRDATA_ADDRESS *exceptionObject, CLRDATA_ADDRESS *nextNestedException)
+{
+ if (exception == 0 || exceptionObject == NULL || nextNestedException == NULL)
+ return E_INVALIDARG;
+
+ SOSDacEnter();
+
+#ifdef WIN64EXCEPTIONS
+ ExceptionTracker *pExData = PTR_ExceptionTracker(TO_TADDR(exception));
+#else
+ ExInfo *pExData = PTR_ExInfo(TO_TADDR(exception));
+#endif // _WIN64
+
+ if (!pExData)
+ {
+ hr = E_INVALIDARG;
+ }
+ else
+ {
+ *exceptionObject = TO_CDADDR(*PTR_TADDR(pExData->m_hThrowable));
+ *nextNestedException = PTR_HOST_TO_TADDR(pExData->m_pPrevNestedInfo);
+ }
+
+ SOSDacLeave();
+ return hr;
+}
+
+
+HRESULT
+ClrDataAccess::GetDomainLocalModuleData(CLRDATA_ADDRESS addr, struct DacpDomainLocalModuleData *pLocalModuleData)
+{
+ if (addr == 0 || pLocalModuleData == NULL)
+ return E_INVALIDARG;
+
+ SOSDacEnter();
+
+ DomainLocalModule* pLocalModule = PTR_DomainLocalModule(TO_TADDR(addr));
+
+ pLocalModuleData->pGCStaticDataStart = TO_CDADDR(PTR_TO_TADDR(pLocalModule->GetPrecomputedGCStaticsBasePointer()));
+ pLocalModuleData->pNonGCStaticDataStart = TO_CDADDR(pLocalModule->GetPrecomputedNonGCStaticsBasePointer());
+ pLocalModuleData->pDynamicClassTable = PTR_CDADDR(pLocalModule->m_pDynamicClassTable.Load());
+ pLocalModuleData->pClassData = (TADDR) (PTR_HOST_MEMBER_TADDR(DomainLocalModule, pLocalModule, m_pDataBlob));
+
+ SOSDacLeave();
+ return hr;
+}
+
+
+HRESULT
+ClrDataAccess::GetDomainLocalModuleDataFromModule(CLRDATA_ADDRESS addr, struct DacpDomainLocalModuleData *pLocalModuleData)
+{
+ if (addr == 0 || pLocalModuleData == NULL)
+ return E_INVALIDARG;
+
+ SOSDacEnter();
+
+ Module* pModule = PTR_Module(TO_TADDR(addr));
+ if( pModule->GetAssembly()->IsDomainNeutral() )
+ {
+ // The module is loaded domain-neutral, then we need to know the specific AppDomain in order to
+ // choose a DomainLocalModule instance. Rather than try and guess an AppDomain (eg. based on
+ // whatever the current debugger thread is in), we'll fail and force the debugger to explicitly use
+ // a specific AppDomain.
+ hr = E_INVALIDARG;
+ }
+ else
+ {
+ DomainLocalModule* pLocalModule = PTR_DomainLocalModule(pModule->GetDomainLocalModule(NULL));
+ if (!pLocalModule)
+ {
+ hr = E_INVALIDARG;
+ }
+ else
+ {
+ pLocalModuleData->pGCStaticDataStart = TO_CDADDR(PTR_TO_TADDR(pLocalModule->GetPrecomputedGCStaticsBasePointer()));
+ pLocalModuleData->pNonGCStaticDataStart = TO_CDADDR(pLocalModule->GetPrecomputedNonGCStaticsBasePointer());
+ pLocalModuleData->pDynamicClassTable = PTR_CDADDR(pLocalModule->m_pDynamicClassTable.Load());
+ pLocalModuleData->pClassData = (TADDR) (PTR_HOST_MEMBER_TADDR(DomainLocalModule, pLocalModule, m_pDataBlob));
+ }
+ }
+
+ SOSDacLeave();
+ return hr;
+}
+
+HRESULT
+ClrDataAccess::GetDomainLocalModuleDataFromAppDomain(CLRDATA_ADDRESS appDomainAddr, int moduleID, struct DacpDomainLocalModuleData *pLocalModuleData)
+{
+ if (appDomainAddr == 0 || moduleID < 0 || pLocalModuleData == NULL)
+ return E_INVALIDARG;
+
+ SOSDacEnter();
+
+ pLocalModuleData->appDomainAddr = appDomainAddr;
+ pLocalModuleData->ModuleID = moduleID;
+
+ AppDomain *pAppDomain = PTR_AppDomain(TO_TADDR(appDomainAddr));
+ ModuleIndex index = Module::IDToIndex(moduleID);
+ DomainLocalModule* pLocalModule = pAppDomain->GetDomainLocalBlock()->GetModuleSlot(index);
+ if (!pLocalModule)
+ {
+ hr = E_INVALIDARG;
+ }
+ else
+ {
+ pLocalModuleData->pGCStaticDataStart = TO_CDADDR(PTR_TO_TADDR(pLocalModule->GetPrecomputedGCStaticsBasePointer()));
+ pLocalModuleData->pNonGCStaticDataStart = TO_CDADDR(pLocalModule->GetPrecomputedNonGCStaticsBasePointer());
+ pLocalModuleData->pDynamicClassTable = PTR_CDADDR(pLocalModule->m_pDynamicClassTable.Load());
+ pLocalModuleData->pClassData = (TADDR) (PTR_HOST_MEMBER_TADDR(DomainLocalModule, pLocalModule, m_pDataBlob));
+ }
+
+ SOSDacLeave();
+ return hr;
+}
+
+
+
+
+HRESULT
+ClrDataAccess::GetThreadLocalModuleData(CLRDATA_ADDRESS thread, unsigned int index, struct DacpThreadLocalModuleData *pLocalModuleData)
+{
+ if (pLocalModuleData == NULL)
+ return E_INVALIDARG;
+
+ SOSDacEnter();
+
+ pLocalModuleData->threadAddr = thread;
+ pLocalModuleData->ModuleIndex = index;
+
+ PTR_Thread pThread = PTR_Thread(TO_TADDR(thread));
+ PTR_ThreadLocalBlock pLocalBlock = ThreadStatics::GetCurrentTLBIfExists(pThread, NULL);
+ if (!pLocalBlock)
+ {
+ hr = E_INVALIDARG;
+ }
+ else
+ {
+ PTR_ThreadLocalModule pLocalModule = pLocalBlock->GetTLMIfExists(ModuleIndex(index));
+ if (!pLocalModule)
+ {
+ hr = E_INVALIDARG;
+ }
+ else
+ {
+ pLocalModuleData->pGCStaticDataStart = TO_CDADDR(PTR_TO_TADDR(pLocalModule->GetPrecomputedGCStaticsBasePointer()));
+ pLocalModuleData->pNonGCStaticDataStart = TO_CDADDR(pLocalModule->GetPrecomputedNonGCStaticsBasePointer());
+ pLocalModuleData->pDynamicClassTable = PTR_CDADDR(pLocalModule->m_pDynamicClassTable);
+ pLocalModuleData->pClassData = (TADDR) (PTR_HOST_MEMBER_TADDR(ThreadLocalModule, pLocalModule, m_pDataBlob));
+ }
+ }
+
+ SOSDacLeave();
+ return hr;
+}
+
+
+HRESULT ClrDataAccess::GetHandleEnum(ISOSHandleEnum **ppHandleEnum)
+{
+ unsigned int types[] = {HNDTYPE_WEAK_SHORT, HNDTYPE_WEAK_LONG, HNDTYPE_STRONG, HNDTYPE_PINNED, HNDTYPE_VARIABLE, HNDTYPE_DEPENDENT,
+ HNDTYPE_ASYNCPINNED, HNDTYPE_SIZEDREF,
+#ifdef FEATURE_COMINTEROP
+ HNDTYPE_REFCOUNTED, HNDTYPE_WEAK_WINRT
+#endif
+ };
+
+ return GetHandleEnumForTypes(types, _countof(types), ppHandleEnum);
+}
+
+HRESULT ClrDataAccess::GetHandleEnumForTypes(unsigned int types[], unsigned int count, ISOSHandleEnum **ppHandleEnum)
+{
+ if (ppHandleEnum == 0)
+ return E_POINTER;
+
+ SOSDacEnter();
+
+ DacHandleWalker *walker = new DacHandleWalker();
+
+ HRESULT hr = walker->Init(this, types, count);
+
+ if (SUCCEEDED(hr))
+ hr = walker->QueryInterface(__uuidof(ISOSHandleEnum), (void**)ppHandleEnum);
+
+ if (FAILED(hr))
+ delete walker;
+
+ SOSDacLeave();
+ return hr;
+}
+
+HRESULT ClrDataAccess::GetHandleEnumForGC(unsigned int gen, ISOSHandleEnum **ppHandleEnum)
+{
+ if (ppHandleEnum == 0)
+ return E_POINTER;
+
+ SOSDacEnter();
+
+ unsigned int types[] = {HNDTYPE_WEAK_SHORT, HNDTYPE_WEAK_LONG, HNDTYPE_STRONG, HNDTYPE_PINNED, HNDTYPE_VARIABLE, HNDTYPE_DEPENDENT,
+ HNDTYPE_ASYNCPINNED, HNDTYPE_SIZEDREF,
+#ifdef FEATURE_COMINTEROP
+ HNDTYPE_REFCOUNTED, HNDTYPE_WEAK_WINRT
+#endif
+ };
+
+ DacHandleWalker *walker = new DacHandleWalker();
+
+ HRESULT hr = walker->Init(this, types, _countof(types), gen);
+ if (SUCCEEDED(hr))
+ hr = walker->QueryInterface(__uuidof(ISOSHandleEnum), (void**)ppHandleEnum);
+
+ if (FAILED(hr))
+ delete walker;
+
+ SOSDacLeave();
+ return hr;
+}
+
+HRESULT
+ClrDataAccess::TraverseEHInfo(CLRDATA_ADDRESS ip, DUMPEHINFO pFunc, LPVOID token)
+{
+ if (ip == 0 || pFunc == NULL)
+ return E_INVALIDARG;
+
+ SOSDacEnter();
+
+ EECodeInfo codeInfo(TO_TADDR(ip));
+ if (!codeInfo.IsValid())
+ {
+ hr = E_INVALIDARG;
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ EH_CLAUSE_ENUMERATOR EnumState;
+ EE_ILEXCEPTION_CLAUSE EHClause;
+ unsigned EHCount;
+
+ EHCount = codeInfo.GetJitManager()->InitializeEHEnumeration(codeInfo.GetMethodToken(), &EnumState);
+ for (unsigned i = 0; i < EHCount; i++)
+ {
+ codeInfo.GetJitManager()->GetNextEHClause(&EnumState, &EHClause);
+
+ DACEHInfo deh;
+ ZeroMemory(&deh,sizeof(deh));
+
+ if (IsFault(&EHClause))
+ {
+ deh.clauseType = EHFault;
+ }
+ else if (IsFinally(&EHClause))
+ {
+ deh.clauseType = EHFinally;
+ }
+ else if (IsFilterHandler(&EHClause))
+ {
+ deh.clauseType = EHFilter;
+ deh.filterOffset = EHClause.FilterOffset;
+ }
+ else if (IsTypedHandler(&EHClause))
+ {
+ deh.clauseType = EHTyped;
+ deh.isCatchAllHandler = (&EHClause.TypeHandle == (void*)(size_t)mdTypeRefNil);
+ }
+ else
+ {
+ deh.clauseType = EHUnknown;
+ }
+
+ if (HasCachedTypeHandle(&EHClause))
+ {
+ deh.mtCatch = TO_CDADDR(&EHClause.TypeHandle);
+ }
+ else if(!IsFaultOrFinally(&EHClause))
+ {
+ // the module of the token (whether a ref or def token) is the same as the module of the method containing the EH clause
+ deh.moduleAddr = HOST_CDADDR(codeInfo.GetMethodDesc()->GetModule());
+ deh.tokCatch = EHClause.ClassToken;
+ }
+
+ deh.tryStartOffset = EHClause.TryStartPC;
+ deh.tryEndOffset = EHClause.TryEndPC;
+ deh.handlerStartOffset = EHClause.HandlerStartPC;
+ deh.handlerEndOffset = EHClause.HandlerEndPC;
+ deh.isDuplicateClause = IsDuplicateClause(&EHClause);
+
+ if (!(pFunc)(i, EHCount, &deh, token))
+ {
+ // User wants to stop the enumeration
+ hr = E_ABORT;
+ break;
+ }
+ }
+ }
+
+ SOSDacLeave();
+ return hr;
+}
+
+HRESULT
+ClrDataAccess::TraverseRCWCleanupList(CLRDATA_ADDRESS cleanupListPtr, VISITRCWFORCLEANUP pFunc, LPVOID token)
+{
+#ifdef FEATURE_COMINTEROP
+ if (pFunc == 0)
+ return E_INVALIDARG;
+
+ SOSDacEnter();
+ RCWCleanupList *pList = g_pRCWCleanupList;
+
+ if (cleanupListPtr)
+ {
+ pList = PTR_RCWCleanupList(TO_TADDR(cleanupListPtr));
+ }
+
+ if (pList)
+ {
+ PTR_RCW pBucket = dac_cast<PTR_RCW>(TO_TADDR(pList->m_pFirstBucket));
+ while (pBucket != NULL)
+ {
+ PTR_RCW pRCW = pBucket;
+ Thread *pSTAThread = pRCW->GetSTAThread();
+ LPVOID pCtxCookie = pRCW->GetWrapperCtxCookie();
+ BOOL bIsFreeThreaded = pRCW->IsFreeThreaded();
+
+ while (pRCW)
+ {
+ (pFunc)(HOST_CDADDR(pRCW),(CLRDATA_ADDRESS)pCtxCookie, (CLRDATA_ADDRESS)(TADDR)pSTAThread, bIsFreeThreaded, token);
+ pRCW = pRCW->m_pNextRCW;
+ }
+ pBucket = pBucket->m_pNextCleanupBucket;
+ }
+ }
+
+ SOSDacLeave();
+ return hr;
+#else
+ return E_NOTIMPL;
+#endif // FEATURE_COMINTEROP
+}
+
+HRESULT
+ClrDataAccess::TraverseLoaderHeap(CLRDATA_ADDRESS loaderHeapAddr, VISITHEAP pFunc)
+{
+ if (loaderHeapAddr == 0 || pFunc == 0)
+ return E_INVALIDARG;
+
+ SOSDacEnter();
+
+ LoaderHeap *pLoaderHeap = PTR_LoaderHeap(TO_TADDR(loaderHeapAddr));
+ PTR_LoaderHeapBlock block = pLoaderHeap->m_pFirstBlock;
+ while (block.IsValid())
+ {
+ TADDR addr = PTR_TO_TADDR(block->pVirtualAddress);
+ size_t size = block->dwVirtualSize;
+
+ BOOL bCurrentBlock = (block == pLoaderHeap->m_pCurBlock);
+
+ pFunc(addr,size,bCurrentBlock);
+
+ block = block->pNext;
+ }
+
+ SOSDacLeave();
+ return hr;
+}
+
+HRESULT
+ClrDataAccess::TraverseVirtCallStubHeap(CLRDATA_ADDRESS pAppDomain, VCSHeapType heaptype, VISITHEAP pFunc)
+{
+ if (pAppDomain == 0)
+ return E_INVALIDARG;
+
+ SOSDacEnter();
+
+ BaseDomain* pBaseDomain = PTR_BaseDomain(TO_TADDR(pAppDomain));
+ VirtualCallStubManager *pVcsMgr = PTR_VirtualCallStubManager((TADDR)pBaseDomain->GetLoaderAllocator()->GetVirtualCallStubManager());
+ if (!pVcsMgr)
+ {
+ hr = E_POINTER;
+ }
+ else
+ {
+ LoaderHeap *pLoaderHeap = NULL;
+ switch(heaptype)
+ {
+ case IndcellHeap:
+ pLoaderHeap = pVcsMgr->indcell_heap;
+ break;
+ case LookupHeap:
+ pLoaderHeap = pVcsMgr->lookup_heap;
+ break;
+ case ResolveHeap:
+ pLoaderHeap = pVcsMgr->resolve_heap;
+ break;
+ case DispatchHeap:
+ pLoaderHeap = pVcsMgr->dispatch_heap;
+ break;
+ case CacheEntryHeap:
+ pLoaderHeap = pVcsMgr->cache_entry_heap;
+ break;
+ default:
+ hr = E_INVALIDARG;
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ PTR_LoaderHeapBlock block = pLoaderHeap->m_pFirstBlock;
+ while (block.IsValid())
+ {
+ TADDR addr = PTR_TO_TADDR(block->pVirtualAddress);
+ size_t size = block->dwVirtualSize;
+
+ BOOL bCurrentBlock = (block == pLoaderHeap->m_pCurBlock);
+ pFunc(addr, size, bCurrentBlock);
+
+ block = block->pNext;
+ }
+ }
+ }
+
+ SOSDacLeave();
+ return hr;
+}
+
+
+HRESULT
+ClrDataAccess::GetSyncBlockData(unsigned int SBNumber, struct DacpSyncBlockData *pSyncBlockData)
+{
+ if (pSyncBlockData == NULL)
+ return E_INVALIDARG;
+
+ SOSDacEnter();
+
+ ZeroMemory(pSyncBlockData,sizeof(DacpSyncBlockData));
+ pSyncBlockData->SyncBlockCount = (SyncBlockCache::s_pSyncBlockCache->m_FreeSyncTableIndex) - 1;
+ PTR_SyncTableEntry ste = PTR_SyncTableEntry(dac_cast<TADDR>(g_pSyncTable)+(sizeof(SyncTableEntry) * SBNumber));
+ pSyncBlockData->bFree = ((dac_cast<TADDR>(ste->m_Object.Load())) & 1);
+
+ if (pSyncBlockData->bFree == FALSE)
+ {
+ pSyncBlockData->Object = (CLRDATA_ADDRESS)dac_cast<TADDR>(ste->m_Object.Load());
+
+ if (ste->m_SyncBlock != NULL)
+ {
+ SyncBlock *pBlock = PTR_SyncBlock(ste->m_SyncBlock);
+ pSyncBlockData->SyncBlockPointer = HOST_CDADDR(pBlock);
+#ifdef FEATURE_COMINTEROP
+ if (pBlock->m_pInteropInfo)
+ {
+ pSyncBlockData->COMFlags |= (pBlock->m_pInteropInfo->DacGetRawRCW() != 0) ? SYNCBLOCKDATA_COMFLAGS_RCW : 0;
+ pSyncBlockData->COMFlags |= (pBlock->m_pInteropInfo->GetCCW() != NULL) ? SYNCBLOCKDATA_COMFLAGS_CCW : 0;
+#ifdef FEATURE_COMINTEROP_UNMANAGED_ACTIVATION
+ pSyncBlockData->COMFlags |= (pBlock->m_pInteropInfo->GetComClassFactory() != NULL) ? SYNCBLOCKDATA_COMFLAGS_CF : 0;
+#endif // FEATURE_COMINTEROP_UNMANAGED_ACTIVATION
+ }
+#endif // FEATURE_COMINTEROP
+
+ pSyncBlockData->MonitorHeld = pBlock->m_Monitor.m_MonitorHeld;
+ pSyncBlockData->Recursion = pBlock->m_Monitor.m_Recursion;
+ pSyncBlockData->HoldingThread = HOST_CDADDR(pBlock->m_Monitor.m_HoldingThread);
+
+ if (pBlock->GetAppDomainIndex().m_dwIndex)
+ {
+ pSyncBlockData->appDomainPtr = PTR_HOST_TO_TADDR(
+ SystemDomain::TestGetAppDomainAtIndex(pBlock->GetAppDomainIndex()));
+ }
+
+ // TODO: Microsoft, implement the wait list
+ pSyncBlockData->AdditionalThreadCount = 0;
+
+ if (pBlock->m_Link.m_pNext != NULL)
+ {
+ PTR_SLink pLink = pBlock->m_Link.m_pNext;
+ do
+ {
+ pSyncBlockData->AdditionalThreadCount++;
+ pLink = pBlock->m_Link.m_pNext;
+ }
+ while ((pLink != NULL) &&
+ (pSyncBlockData->AdditionalThreadCount < 1000));
+ }
+ }
+ }
+
+ SOSDacLeave();
+ return hr;
+}
+
+HRESULT
+ClrDataAccess::GetSyncBlockCleanupData(CLRDATA_ADDRESS syncBlock, struct DacpSyncBlockCleanupData *syncBlockCData)
+{
+ if (syncBlock == 0 || syncBlockCData == NULL)
+ return E_INVALIDARG;
+
+ SOSDacEnter();
+
+ ZeroMemory (syncBlockCData, sizeof(DacpSyncBlockCleanupData));
+ SyncBlock *pBlock = NULL;
+
+ if (syncBlock == NULL && SyncBlockCache::s_pSyncBlockCache->m_pCleanupBlockList)
+ {
+ pBlock = (SyncBlock *) PTR_SyncBlock(
+ PTR_HOST_TO_TADDR(SyncBlockCache::s_pSyncBlockCache->m_pCleanupBlockList) - offsetof(SyncBlock, m_Link));
+ }
+ else
+ {
+ pBlock = PTR_SyncBlock(TO_TADDR(syncBlock));
+ }
+
+ if (pBlock)
+ {
+ syncBlockCData->SyncBlockPointer = HOST_CDADDR(pBlock);
+ if (pBlock->m_Link.m_pNext)
+ {
+ syncBlockCData->nextSyncBlock = (CLRDATA_ADDRESS)
+ (PTR_HOST_TO_TADDR(pBlock->m_Link.m_pNext) - offsetof(SyncBlock, m_Link));
+ }
+
+#ifdef FEATURE_COMINTEROP
+ if (pBlock->m_pInteropInfo->DacGetRawRCW())
+ syncBlockCData->blockRCW = (CLRDATA_ADDRESS) pBlock->m_pInteropInfo->DacGetRawRCW();
+#ifdef FEATURE_COMINTEROP_UNMANAGED_ACTIVATION
+ if (pBlock->m_pInteropInfo->GetComClassFactory())
+ syncBlockCData->blockClassFactory = (CLRDATA_ADDRESS) (TADDR) pBlock->m_pInteropInfo->GetComClassFactory();
+#endif // FEATURE_COMINTEROP_UNMANAGED_ACTIVATION
+ if (pBlock->m_pInteropInfo->GetCCW())
+ syncBlockCData->blockCCW = (CLRDATA_ADDRESS) dac_cast<TADDR>(pBlock->m_pInteropInfo->GetCCW());
+#endif // FEATURE_COMINTEROP
+ }
+
+ SOSDacLeave();
+ return hr;
+}
+
+HRESULT
+ClrDataAccess::GetJitHelperFunctionName(CLRDATA_ADDRESS ip, unsigned int count, __out_z __inout_ecount(count) char *name, unsigned int *pNeeded)
+{
+ SOSDacEnter();
+
+ PCSTR pszHelperName = GetJitHelperName(TO_TADDR(ip));
+ if (pszHelperName == NULL)
+ {
+ hr = E_INVALIDARG;
+ }
+ else
+ {
+ unsigned int len = (unsigned int)strlen(pszHelperName) + 1;
+
+ if (pNeeded)
+ *pNeeded = len;
+
+ if (name)
+ {
+ if (count < len)
+ hr = E_FAIL;
+ else
+ strcpy_s(name, count, pszHelperName);
+ }
+ }
+
+ SOSDacLeave();
+ return hr;
+};
+
+HRESULT
+ClrDataAccess::GetJumpThunkTarget(T_CONTEXT *ctx, CLRDATA_ADDRESS *targetIP, CLRDATA_ADDRESS *targetMD)
+{
+ if (ctx == NULL || targetIP == NULL || targetMD == NULL)
+ return E_INVALIDARG;
+
+#ifdef _WIN64
+ SOSDacEnter();
+
+ if (!GetAnyThunkTarget(ctx, targetIP, targetMD))
+ hr = E_FAIL;
+
+ SOSDacLeave();
+ return hr;
+#else
+ return E_FAIL;
+#endif // _WIN64
+}
+
+
+#ifdef _PREFAST_
+#pragma warning(push)
+#pragma warning(disable:21000) // Suppress PREFast warning about overly large function
+#endif
+STDMETHODIMP
+ClrDataAccess::Request(IN ULONG32 reqCode,
+ IN ULONG32 inBufferSize,
+ IN BYTE* inBuffer,
+ IN ULONG32 outBufferSize,
+ OUT BYTE* outBuffer)
+{
+ HRESULT status;
+
+ DAC_ENTER();
+
+ EX_TRY
+ {
+ switch(reqCode)
+ {
+ case CLRDATA_REQUEST_REVISION:
+ if (inBufferSize != 0 ||
+ inBuffer ||
+ outBufferSize != sizeof(ULONG32))
+ {
+ status = E_INVALIDARG;
+ }
+ else
+ {
+ *(ULONG32*)outBuffer = 9;
+ status = S_OK;
+ }
+ break;
+
+ default:
+ status = E_INVALIDARG;
+ break;
+ }
+ }
+ EX_CATCH
+ {
+ if (!DacExceptionFilter(GET_EXCEPTION(), this, &status))
+ {
+ EX_RETHROW;
+ }
+ }
+ EX_END_CATCH(SwallowAllExceptions)
+
+ DAC_LEAVE();
+ return status;
+}
+#ifdef _PREFAST_
+#pragma warning(pop)
+#endif
+
+void
+ClrDataAccess::EnumWksGlobalMemoryRegions(CLRDataEnumMemoryFlags flags)
+{
+ SUPPORTS_DAC;
+ WKS::gc_heap::ephemeral_heap_segment.EnumMem();
+ WKS::gc_heap::alloc_allocated.EnumMem();
+ WKS::gc_heap::finalize_queue.EnumMem();
+ WKS::generation_table.EnumMem();
+ WKS::gc_heap::oom_info.EnumMem();
+
+ if (WKS::generation_table.IsValid())
+ {
+ // enumerating the generations from max (which is normally gen2) to max+1 gives you
+ // the segment list for all the normal segements plus the large heap segment (max+1)
+ // this is the convention in the GC so it is repeated here
+ for (ULONG i = GCHeap::GetMaxGeneration(); i <= GCHeap::GetMaxGeneration()+1; i++)
+ {
+ __DPtr<WKS::heap_segment> seg = dac_cast<TADDR>(WKS::generation_table[i].start_segment);
+ while (seg)
+ {
+ DacEnumMemoryRegion(dac_cast<TADDR>(seg), sizeof(WKS::heap_segment));
+
+ seg = __DPtr<WKS::heap_segment>(dac_cast<TADDR>(seg->next));
+ }
+ }
+ }
+}
+
+HRESULT
+ClrDataAccess::GetClrWatsonBuckets(CLRDATA_ADDRESS thread, void *pGenericModeBlock)
+{
+#ifdef FEATURE_PAL
+ // This API is not available under FEATURE_PAL
+ return E_FAIL;
+#else // FEATURE_PAL
+ if (thread == 0 || pGenericModeBlock == NULL)
+ return E_INVALIDARG;
+
+ SOSDacEnter();
+
+ Thread * pThread = PTR_Thread(TO_TADDR(thread));
+ hr = GetClrWatsonBucketsWorker(pThread, reinterpret_cast<GenericModeBlock *>(pGenericModeBlock));
+
+ SOSDacLeave();
+ return hr;
+#endif // FEATURE_PAL
+}
+
+#ifndef FEATURE_PAL
+
+HRESULT ClrDataAccess::GetClrWatsonBucketsWorker(Thread * pThread, GenericModeBlock * pGM)
+{
+ if ((pThread == NULL) || (pGM == NULL))
+ {
+ return E_INVALIDARG;
+ }
+
+ // By default, there are no buckets
+ PTR_VOID pBuckets = NULL;
+
+ // Get the handle to the throwble
+ OBJECTHANDLE ohThrowable = pThread->GetThrowableAsHandle();
+ if (ohThrowable != NULL)
+ {
+ // Get the object from handle and check if the throwable is preallocated or not
+ OBJECTREF oThrowable = ObjectFromHandle(ohThrowable);
+ if (oThrowable != NULL)
+ {
+ // Does the throwable have buckets?
+ if (((EXCEPTIONREF)oThrowable)->AreWatsonBucketsPresent())
+ {
+ // Get the watson buckets from the throwable for non-preallocated
+ // exceptions
+ U1ARRAYREF refWatsonBucketArray = ((EXCEPTIONREF)oThrowable)->GetWatsonBucketReference();
+ pBuckets = dac_cast<PTR_VOID>(refWatsonBucketArray->GetDataPtr());
+ }
+ else
+ {
+ // This is a preallocated exception object - check if the UE Watson bucket tracker
+ // has any bucket details
+ pBuckets = pThread->GetExceptionState()->GetUEWatsonBucketTracker()->RetrieveWatsonBuckets();
+ if (pBuckets == NULL)
+ {
+ // Since the UE watson bucket tracker does not have them, look up the current
+ // exception tracker
+ if (pThread->GetExceptionState()->GetCurrentExceptionTracker() != NULL)
+ {
+ pBuckets = pThread->GetExceptionState()->GetCurrentExceptionTracker()->GetWatsonBucketTracker()->RetrieveWatsonBuckets();
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ // Debuger.Break doesn't have a throwable, but saves Watson buckets in EHWatsonBucketTracker.
+ pBuckets = pThread->GetExceptionState()->GetUEWatsonBucketTracker()->RetrieveWatsonBuckets();
+ }
+
+ // If pBuckets is non-null, it is the address of a Watson GenericModeBlock in the target process.
+ if (pBuckets != NULL)
+ {
+ ULONG32 returned = 0;
+ HRESULT hr = m_pTarget->ReadVirtual(dac_cast<TADDR>(pBuckets), reinterpret_cast<BYTE *>(pGM), sizeof(*pGM), &returned);
+ if (FAILED(hr))
+ {
+ hr = CORDBG_E_READVIRTUAL_FAILURE;
+ }
+ if (SUCCEEDED(hr) && (returned != sizeof(*pGM)))
+ {
+ hr = HRESULT_FROM_WIN32(ERROR_PARTIAL_COPY);
+ }
+ return hr;
+ }
+ else
+ {
+ // Buckets are not available
+ return S_FALSE;
+ }
+}
+
+#endif // FEATURE_PAL
+
+HRESULT ClrDataAccess::GetTLSIndex(ULONG *pIndex)
+{
+ if (pIndex == NULL)
+ return E_INVALIDARG;
+
+ SOSDacEnter();
+ if (CExecutionEngine::GetTlsIndex() == TLS_OUT_OF_INDEXES)
+ {
+ *pIndex = 0;
+ hr = S_FALSE;
+ }
+ else
+ {
+ *pIndex = CExecutionEngine::GetTlsIndex();
+ }
+
+ SOSDacLeave();
+ return hr;
+}
+
+HRESULT ClrDataAccess::GetDacModuleHandle(HMODULE *phModule)
+{
+ if(phModule == NULL)
+ return E_INVALIDARG;
+ *phModule = GetModuleInst();
+ return S_OK;
+}
+
+HRESULT ClrDataAccess::GetRCWData(CLRDATA_ADDRESS addr, struct DacpRCWData *rcwData)
+{
+ if (addr == 0 || rcwData == NULL)
+ return E_INVALIDARG;
+
+#ifdef FEATURE_COMINTEROP
+ SOSDacEnter();
+
+ ZeroMemory (rcwData, sizeof(DacpRCWData));
+
+ PTR_RCW pRCW = dac_cast<PTR_RCW>(CLRDATA_ADDRESS_TO_TADDR(addr));
+
+ rcwData->identityPointer = TO_CDADDR(pRCW->m_pIdentity);
+ rcwData->unknownPointer = TO_CDADDR(pRCW->GetRawIUnknown_NoAddRef());
+ rcwData->vtablePtr = TO_CDADDR(pRCW->m_vtablePtr);
+ rcwData->creatorThread = TO_CDADDR(pRCW->m_pCreatorThread);
+ rcwData->ctxCookie = TO_CDADDR(pRCW->GetWrapperCtxCookie());
+ rcwData->refCount = pRCW->m_cbRefCount;
+
+ rcwData->isJupiterObject = pRCW->IsJupiterObject();
+ rcwData->supportsIInspectable = pRCW->SupportsIInspectable();
+ rcwData->isAggregated = pRCW->IsURTAggregated();
+ rcwData->isContained = pRCW->IsURTContained();
+ rcwData->jupiterObject = TO_CDADDR(pRCW->GetJupiterObject());
+ rcwData->isFreeThreaded = pRCW->IsFreeThreaded();
+ rcwData->isDisconnected = pRCW->IsDisconnected();
+
+ if (pRCW->m_SyncBlockIndex != 0)
+ {
+ PTR_SyncTableEntry ste = PTR_SyncTableEntry(dac_cast<TADDR>(g_pSyncTable) + (sizeof(SyncTableEntry) * pRCW->m_SyncBlockIndex));
+ rcwData->managedObject = PTR_CDADDR(ste->m_Object.Load());
+ }
+
+ // count the number of cached interface pointers
+ rcwData->interfaceCount = 0;
+ RCW::CachedInterfaceEntryIterator it = pRCW->IterateCachedInterfacePointers();
+ while (it.Next())
+ {
+ if (it.GetEntry()->m_pUnknown.Load() != NULL)
+ rcwData->interfaceCount++;
+ }
+
+ SOSDacLeave();
+ return hr;
+#else
+ return E_NOTIMPL;
+#endif
+}
+
+HRESULT ClrDataAccess::GetRCWInterfaces(CLRDATA_ADDRESS rcw, unsigned int count, struct DacpCOMInterfacePointerData interfaces[], unsigned int *pNeeded)
+{
+ if (rcw == 0)
+ return E_INVALIDARG;
+
+#ifdef FEATURE_COMINTEROP
+
+ SOSDacEnter();
+ PTR_RCW pRCW = dac_cast<PTR_RCW>(CLRDATA_ADDRESS_TO_TADDR(rcw));
+ if (interfaces == NULL)
+ {
+ if (pNeeded)
+ {
+ unsigned int c = 0;
+ RCW::CachedInterfaceEntryIterator it = pRCW->IterateCachedInterfacePointers();
+ while (it.Next())
+ {
+ if (it.GetEntry()->m_pUnknown.Load() != NULL)
+ c++;
+ }
+
+ *pNeeded = c;
+ }
+ else
+ {
+ hr = E_INVALIDARG;
+ }
+ }
+ else
+ {
+ ZeroMemory(interfaces, sizeof(DacpCOMInterfacePointerData) * count);
+
+ unsigned int itemIndex = 0;
+ RCW::CachedInterfaceEntryIterator it = pRCW->IterateCachedInterfacePointers();
+ while (it.Next())
+ {
+ InterfaceEntry *pEntry = it.GetEntry();
+ if (pEntry->m_pUnknown.Load() != NULL)
+ {
+ if (itemIndex >= count)
+ {
+ // the outBuffer is too small
+ hr = E_INVALIDARG;
+ break;
+ }
+ else
+ {
+ interfaces[itemIndex].interfacePtr = TO_CDADDR(pEntry->m_pUnknown.Load());
+ interfaces[itemIndex].methodTable = TO_CDADDR(pEntry->m_pMT.Load());
+ interfaces[itemIndex].comContext = TO_CDADDR(it.GetCtxCookie());
+ itemIndex++;
+ }
+ }
+ }
+
+ if (SUCCEEDED(hr) && pNeeded)
+ *pNeeded = itemIndex;
+ }
+
+ SOSDacLeave();
+ return hr;
+#else
+ return E_NOTIMPL;
+#endif
+}
+
+#ifdef FEATURE_COMINTEROP
+PTR_ComCallWrapper ClrDataAccess::DACGetCCWFromAddress(CLRDATA_ADDRESS addr)
+{
+ PTR_ComCallWrapper pCCW = NULL;
+
+ // first check whether the address is our COM IP
+ TADDR pPtr = CLRDATA_ADDRESS_TO_TADDR(addr);
+
+ ULONG32 returned = 0;
+ if (m_pTarget->ReadVirtual(pPtr, (PBYTE)&pPtr, sizeof(TADDR), &returned) == S_OK &&
+ returned == sizeof(TADDR))
+ {
+ // this should be the vtable pointer - dereference the 2nd slot
+ if (m_pTarget->ReadVirtual(pPtr + sizeof(PBYTE) * TEAR_OFF_SLOT, (PBYTE)&pPtr, sizeof(TADDR), &returned) == S_OK &&
+ returned == sizeof(TADDR))
+ {
+
+#ifdef DBG_TARGET_ARM
+ // clear the THUMB bit on pPtr before comparing with known vtable entry
+ pPtr &= ~THUMB_CODE;
+#endif
+
+ if (pPtr == GetEEFuncEntryPoint(TEAR_OFF_STANDARD))
+ {
+ // Points to ComCallWrapper
+ PTR_IUnknown pUnk(CLRDATA_ADDRESS_TO_TADDR(addr));
+ pCCW = ComCallWrapper::GetWrapperFromIP(pUnk);
+ }
+ else if (pPtr == GetEEFuncEntryPoint(TEAR_OFF_SIMPLE) || pPtr == GetEEFuncEntryPoint(TEAR_OFF_SIMPLE_INNER))
+ {
+ // Points to SimpleComCallWrapper
+ PTR_IUnknown pUnk(CLRDATA_ADDRESS_TO_TADDR(addr));
+ pCCW = SimpleComCallWrapper::GetWrapperFromIP(pUnk)->GetMainWrapper();
+ }
+ }
+ }
+
+ if (pCCW == NULL)
+ {
+ // no luck interpreting the address as a COM interface pointer - it must be a CCW address
+ pCCW = dac_cast<PTR_ComCallWrapper>(CLRDATA_ADDRESS_TO_TADDR(addr));
+ }
+
+ if (pCCW->IsLinked())
+ pCCW = ComCallWrapper::GetStartWrapper(pCCW);
+
+ return pCCW;
+}
+
+PTR_IUnknown ClrDataAccess::DACGetCOMIPFromCCW(PTR_ComCallWrapper pCCW, int vtableIndex)
+{
+ if (pCCW->m_rgpIPtr[vtableIndex] != NULL)
+ {
+ PTR_IUnknown pUnk = dac_cast<PTR_IUnknown>(dac_cast<TADDR>(pCCW) + offsetof(ComCallWrapper, m_rgpIPtr[vtableIndex]));
+
+ PTR_ComMethodTable pCMT = ComMethodTable::ComMethodTableFromIP(pUnk);
+ if (pCMT->IsLayoutComplete())
+ {
+ // return only fully laid out vtables
+ return pUnk;
+ }
+ }
+ return NULL;
+}
+#endif
+
+
+HRESULT ClrDataAccess::GetCCWData(CLRDATA_ADDRESS ccw, struct DacpCCWData *ccwData)
+{
+ if (ccw == 0 || ccwData == NULL)
+ return E_INVALIDARG;
+
+#ifdef FEATURE_COMINTEROP
+ SOSDacEnter();
+ ZeroMemory (ccwData, sizeof(DacpCCWData));
+
+ PTR_ComCallWrapper pCCW = DACGetCCWFromAddress(ccw);
+ PTR_SimpleComCallWrapper pSimpleCCW = pCCW->GetSimpleWrapper();
+
+ ccwData->outerIUnknown = TO_CDADDR(pSimpleCCW->m_pOuter);
+ ccwData->refCount = pSimpleCCW->GetRefCount();
+ ccwData->isNeutered = pSimpleCCW->IsNeutered();
+ ccwData->ccwAddress = TO_CDADDR(dac_cast<TADDR>(pCCW));
+
+ ccwData->jupiterRefCount = pSimpleCCW->GetJupiterRefCount();
+ ccwData->isPegged = pSimpleCCW->IsPegged();
+ ccwData->isGlobalPegged = RCWWalker::IsGlobalPeggingOn();
+ ccwData->hasStrongRef = pCCW->IsWrapperActive();
+ ccwData->handle = pCCW->GetObjectHandle();
+ ccwData->isExtendsCOMObject = pCCW->GetSimpleWrapper()->IsExtendsCOMObject();
+ ccwData->isAggregated = pCCW->GetSimpleWrapper()->IsAggregated();
+
+ if (pCCW->GetObjectHandle() != NULL)
+ ccwData->managedObject = PTR_CDADDR(ObjectFromHandle(pCCW->GetObjectHandle()));
+
+ // count the number of COM vtables
+ ccwData->interfaceCount = 0;
+ while (pCCW != NULL)
+ {
+ for (int i = 0; i < ComCallWrapper::NumVtablePtrs; i++)
+ {
+ if (DACGetCOMIPFromCCW(pCCW, i) != NULL)
+ ccwData->interfaceCount++;
+ }
+ pCCW = ComCallWrapper::GetNext(pCCW);
+ }
+
+ SOSDacLeave();
+ return hr;
+#else
+ return E_NOTIMPL;
+#endif
+}
+
+HRESULT ClrDataAccess::GetCCWInterfaces(CLRDATA_ADDRESS ccw, unsigned int count, struct DacpCOMInterfacePointerData interfaces[], unsigned int *pNeeded)
+{
+ if (ccw == 0)
+ return E_INVALIDARG;
+
+#ifdef FEATURE_COMINTEROP
+ SOSDacEnter();
+ PTR_ComCallWrapper pCCW = DACGetCCWFromAddress(ccw);
+
+ if (interfaces == NULL)
+ {
+ if (pNeeded)
+ {
+ unsigned int c = 0;
+ while (pCCW != NULL)
+ {
+ for (int i = 0; i < ComCallWrapper::NumVtablePtrs; i++)
+ if (DACGetCOMIPFromCCW(pCCW, i) != NULL)
+ c++;
+ pCCW = ComCallWrapper::GetNext(pCCW);
+ }
+
+ *pNeeded = c;
+ }
+ else
+ {
+ hr = E_INVALIDARG;
+ }
+ }
+ else
+ {
+ ZeroMemory(interfaces, sizeof(DacpCOMInterfacePointerData) * count);
+
+ PTR_ComCallWrapperTemplate pCCWTemplate = pCCW->GetSimpleWrapper()->GetComCallWrapperTemplate();
+ unsigned int itemIndex = 0;
+ unsigned int wrapperOffset = 0;
+ while (pCCW != NULL && SUCCEEDED(hr))
+ {
+ for (int i = 0; i < ComCallWrapper::NumVtablePtrs && SUCCEEDED(hr); i++)
+ {
+ PTR_IUnknown pUnk = DACGetCOMIPFromCCW(pCCW, i);
+ if (pUnk != NULL)
+ {
+ if (itemIndex >= count)
+ {
+ // the outBuffer is too small
+ hr = E_INVALIDARG;
+ break;
+ }
+
+ interfaces[itemIndex].interfacePtr = PTR_CDADDR(pUnk);
+
+ // if this is the first ComCallWrapper, the 0th vtable slots is special
+ if (wrapperOffset == 0 && i == ComCallWrapper::Slot_Basic)
+ {
+ // this is IDispatch/IUnknown
+ interfaces[itemIndex].methodTable = NULL;
+ }
+ else
+ {
+ // this slot represents the class interface or an interface implemented by the class
+ DWORD ifaceMapIndex = wrapperOffset + i - ComCallWrapper::Slot_FirstInterface;
+
+ PTR_ComMethodTable pCMT = ComMethodTable::ComMethodTableFromIP(pUnk);
+ interfaces[itemIndex].methodTable = PTR_CDADDR(pCMT->GetMethodTable());
+ }
+
+ itemIndex++;
+ }
+ }
+
+ pCCW = ComCallWrapper::GetNext(pCCW);
+ wrapperOffset += ComCallWrapper::NumVtablePtrs;
+ }
+
+ if (SUCCEEDED(hr) && pNeeded)
+ *pNeeded = itemIndex;
+ }
+
+ SOSDacLeave();
+ return hr;
+#else
+ return E_NOTIMPL;
+#endif
+}
+
+HRESULT ClrDataAccess::GetObjectExceptionData(CLRDATA_ADDRESS objAddr, struct DacpExceptionObjectData *data)
+{
+ if (data == NULL)
+ return E_POINTER;
+
+ SOSDacEnter();
+
+ PTR_ExceptionObject pObj = dac_cast<PTR_ExceptionObject>(TO_TADDR(objAddr));
+
+ data->Message = TO_CDADDR(dac_cast<TADDR>(pObj->GetMessage()));
+ data->InnerException = TO_CDADDR(dac_cast<TADDR>(pObj->GetInnerException()));
+ data->StackTrace = TO_CDADDR(dac_cast<TADDR>(pObj->GetStackTraceArrayObject()));
+ data->WatsonBuckets = TO_CDADDR(dac_cast<TADDR>(pObj->GetWatsonBucketReference()));
+ data->StackTraceString = TO_CDADDR(dac_cast<TADDR>(pObj->GetStackTraceString()));
+ data->RemoteStackTraceString = TO_CDADDR(dac_cast<TADDR>(pObj->GetRemoteStackTraceString()));
+ data->HResult = pObj->GetHResult();
+ data->XCode = pObj->GetXCode();
+
+ SOSDacLeave();
+
+ return hr;
+}
+
+HRESULT ClrDataAccess::IsRCWDCOMProxy(CLRDATA_ADDRESS rcwAddr, BOOL* isDCOMProxy)
+{
+ if (isDCOMProxy == nullptr)
+ {
+ return E_POINTER;
+ }
+
+ *isDCOMProxy = FALSE;
+
+#ifdef FEATURE_COMINTEROP
+ SOSDacEnter();
+
+ PTR_RCW pRCW = dac_cast<PTR_RCW>(CLRDATA_ADDRESS_TO_TADDR(rcwAddr));
+ *isDCOMProxy = pRCW->IsDCOMProxy();
+
+ SOSDacLeave();
+
+ return S_OK;
+#else
+ return E_NOTIMPL;
+#endif // FEATURE_COMINTEROP
+}