1// Licensed to the .NET Foundation under one or more agreements.
2// The .NET Foundation licenses this file to you under the MIT license.
3// See the LICENSE file in the project root for more information.
4//*****************************************************************************
5// File: request.cpp
6//
7
8//
9// CorDataAccess::Request implementation.
10//
11//*****************************************************************************
12
13#include "stdafx.h"
14#include <win32threadpool.h>
15
16#include "typestring.h"
17#include <gccover.h>
18#include <virtualcallstub.h>
19#ifdef FEATURE_COMINTEROP
20#include <comcallablewrapper.h>
21#endif // FEATURE_COMINTEROP
22
23#ifndef FEATURE_PAL
24// It is unfortunate having to include this header just to get the definition of GenericModeBlock
25#include <msodw.h>
26#endif // FEATURE_PAL
27
28// To include definiton of IsThrowableThreadAbortException
29#include <exstatecommon.h>
30
31#include "rejit.h"
32#include "request_common.h"
33
34// GC headers define these to EE-specific stuff that we don't want.
35#undef EnterCriticalSection
36#undef LeaveCriticalSection
37
38#define PTR_CDADDR(ptr) TO_CDADDR(PTR_TO_TADDR(ptr))
39#define HOST_CDADDR(host) TO_CDADDR(PTR_HOST_TO_TADDR(host))
40
41#define SOSDacEnter() \
42 DAC_ENTER(); \
43 HRESULT hr = S_OK; \
44 EX_TRY \
45 {
46
47#define SOSDacLeave() \
48 } \
49 EX_CATCH \
50 { \
51 if (!DacExceptionFilter(GET_EXCEPTION(), this, &hr)) \
52 { \
53 EX_RETHROW; \
54 } \
55 } \
56 EX_END_CATCH(SwallowAllExceptions) \
57 DAC_LEAVE();
58
59// Use this when you don't want to instantiate an Object * in the host.
60TADDR DACGetMethodTableFromObjectPointer(TADDR objAddr, ICorDebugDataTarget * target)
61{
62 ULONG32 returned = 0;
63 TADDR Value = NULL;
64
65 HRESULT hr = target->ReadVirtual(objAddr, (PBYTE)&Value, sizeof(TADDR), &returned);
66
67 if ((hr != S_OK) || (returned != sizeof(TADDR)))
68 {
69 return NULL;
70 }
71
72 Value = Value & ~3; // equivalent to Object::GetGCSafeMethodTable()
73 return Value;
74}
75
76// Use this when you don't want to instantiate an Object * in the host.
77PTR_SyncBlock DACGetSyncBlockFromObjectPointer(TADDR objAddr, ICorDebugDataTarget * target)
78{
79 ULONG32 returned = 0;
80 DWORD Value = NULL;
81
82 HRESULT hr = target->ReadVirtual(objAddr - sizeof(DWORD), (PBYTE)&Value, sizeof(DWORD), &returned);
83
84 if ((hr != S_OK) || (returned != sizeof(DWORD)))
85 {
86 return NULL;
87 }
88
89 if ((Value & (BIT_SBLK_IS_HASH_OR_SYNCBLKINDEX | BIT_SBLK_IS_HASHCODE)) != BIT_SBLK_IS_HASH_OR_SYNCBLKINDEX)
90 return NULL;
91 Value &= MASK_SYNCBLOCKINDEX;
92
93 PTR_SyncTableEntry ste = PTR_SyncTableEntry(dac_cast<TADDR>(g_pSyncTable) + (sizeof(SyncTableEntry) * Value));
94 return ste->m_SyncBlock;
95}
96
97BOOL DacValidateEEClass(EEClass *pEEClass)
98{
99 // Verify things are right.
100 // The EEClass method table pointer should match the method table.
101 // TODO: Microsoft, need another test for validity, this one isn't always true anymore.
102 BOOL retval = TRUE;
103 EX_TRY
104 {
105 MethodTable *pMethodTable = pEEClass->GetMethodTable();
106 if (!pMethodTable)
107 {
108 // PREfix.
109 retval = FALSE;
110 }
111 else if (pEEClass != pMethodTable->GetClass())
112 {
113 retval = FALSE;
114 }
115 }
116 EX_CATCH
117 {
118 retval = FALSE; // Something is wrong
119 }
120 EX_END_CATCH(SwallowAllExceptions)
121 return retval;
122
123}
124
125BOOL DacValidateMethodTable(MethodTable *pMT, BOOL &bIsFree)
126{
127 // Verify things are right.
128 BOOL retval = FALSE;
129 EX_TRY
130 {
131 bIsFree = FALSE;
132 EEClass *pEEClass = pMT->GetClass();
133 if (pEEClass==NULL)
134 {
135 // Okay to have a NULL EEClass if this is a free methodtable
136 CLRDATA_ADDRESS MethTableAddr = HOST_CDADDR(pMT);
137 CLRDATA_ADDRESS FreeObjMethTableAddr = HOST_CDADDR(g_pFreeObjectMethodTable);
138 if (MethTableAddr != FreeObjMethTableAddr)
139 goto BadMethodTable;
140
141 bIsFree = TRUE;
142 }
143 else
144 {
145 // Standard fast check
146 if (!pMT->ValidateWithPossibleAV())
147 goto BadMethodTable;
148
149 // In rare cases, we've seen the standard check above pass when it shouldn't.
150 // Insert additional/ad-hoc tests below.
151
152 // Metadata token should look valid for a class
153 mdTypeDef td = pMT->GetCl();
154 if (td != mdTokenNil && TypeFromToken(td) != mdtTypeDef)
155 goto BadMethodTable;
156
157 // BaseSize should always be greater than 0 for valid objects (unless it's an interface)
158 // For strings, baseSize is not ptr-aligned
159 if (!pMT->IsInterface() && !pMT->IsString())
160 {
161 if (pMT->GetBaseSize() == 0 || !IS_ALIGNED(pMT->GetBaseSize(), sizeof(void *)))
162 goto BadMethodTable;
163 }
164 }
165
166 retval = TRUE;
167
168BadMethodTable: ;
169 }
170 EX_CATCH
171 {
172 retval = FALSE; // Something is wrong
173 }
174 EX_END_CATCH(SwallowAllExceptions)
175 return retval;
176
177}
178
179BOOL DacValidateMD(MethodDesc * pMD)
180{
181 if (pMD == NULL)
182 {
183 return FALSE;
184 }
185
186 // Verify things are right.
187 BOOL retval = TRUE;
188 EX_TRY
189 {
190 MethodTable *pMethodTable = pMD->GetMethodTable();
191
192 // Standard fast check
193 if (!pMethodTable->ValidateWithPossibleAV())
194 {
195 retval = FALSE;
196 }
197
198 if (retval && (pMD->GetSlot() >= pMethodTable->GetNumVtableSlots() && !pMD->HasNonVtableSlot()))
199 {
200 retval = FALSE;
201 }
202
203 if (retval && pMD->HasTemporaryEntryPoint())
204 {
205 MethodDesc *pMDCheck = MethodDesc::GetMethodDescFromStubAddr(pMD->GetTemporaryEntryPoint(), TRUE);
206
207 if (PTR_HOST_TO_TADDR(pMD) != PTR_HOST_TO_TADDR(pMDCheck))
208 {
209 retval = FALSE;
210 }
211 }
212
213 if (retval && pMD->HasNativeCode())
214 {
215 PCODE jitCodeAddr = pMD->GetNativeCode();
216
217 MethodDesc *pMDCheck = ExecutionManager::GetCodeMethodDesc(jitCodeAddr);
218 if (pMDCheck)
219 {
220 // Check that the given MethodDesc matches the MethodDesc from
221 // the CodeHeader
222 if (PTR_HOST_TO_TADDR(pMD) != PTR_HOST_TO_TADDR(pMDCheck))
223 {
224 retval = FALSE;
225 }
226 }
227 else
228 {
229 retval = FALSE;
230 }
231 }
232 }
233 EX_CATCH
234 {
235 retval = FALSE; // Something is wrong
236 }
237 EX_END_CATCH(SwallowAllExceptions)
238 return retval;
239}
240
241BOOL DacValidateMD(LPCVOID pMD)
242{
243 return DacValidateMD((MethodDesc *)pMD);
244}
245
246VOID GetJITMethodInfo (EECodeInfo * pCodeInfo, JITTypes *pJITType, CLRDATA_ADDRESS *pGCInfo)
247{
248 DWORD dwType = pCodeInfo->GetJitManager()->GetCodeType();
249 if (IsMiIL(dwType))
250 {
251 *pJITType = TYPE_JIT;
252 }
253 else if (IsMiNative(dwType))
254 {
255 *pJITType = TYPE_PJIT;
256 }
257 else
258 {
259 *pJITType = TYPE_UNKNOWN;
260 }
261
262 *pGCInfo = (CLRDATA_ADDRESS)PTR_TO_TADDR(pCodeInfo->GetGCInfo());
263}
264
265HRESULT
266ClrDataAccess::GetWorkRequestData(CLRDATA_ADDRESS addr, struct DacpWorkRequestData *workRequestData)
267{
268 if (addr == 0 || workRequestData == NULL)
269 return E_INVALIDARG;
270
271 SOSDacEnter();
272
273 WorkRequest *pRequest = PTR_WorkRequest(TO_TADDR(addr));
274 workRequestData->Function = (TADDR)(pRequest->Function);
275 workRequestData->Context = (TADDR)(pRequest->Context);
276 workRequestData->NextWorkRequest = (TADDR)(pRequest->next);
277
278 SOSDacLeave();
279 return hr;
280}
281
282HRESULT
283ClrDataAccess::GetHillClimbingLogEntry(CLRDATA_ADDRESS addr, struct DacpHillClimbingLogEntry *entry)
284{
285 if (addr == 0 || entry == NULL)
286 return E_INVALIDARG;
287
288 SOSDacEnter();
289
290 HillClimbingLogEntry *pLogEntry = PTR_HillClimbingLogEntry(TO_TADDR(addr));
291 entry->TickCount = pLogEntry->TickCount;
292 entry->NewControlSetting = pLogEntry->NewControlSetting;
293 entry->LastHistoryCount = pLogEntry->LastHistoryCount;
294 entry->LastHistoryMean = pLogEntry->LastHistoryMean;
295 entry->Transition = pLogEntry->Transition;
296
297 SOSDacLeave();
298 return hr;
299}
300
301HRESULT
302ClrDataAccess::GetThreadpoolData(struct DacpThreadpoolData *threadpoolData)
303{
304 if (threadpoolData == NULL)
305 return E_INVALIDARG;
306
307 SOSDacEnter();
308
309 threadpoolData->cpuUtilization = ThreadpoolMgr::cpuUtilization;
310 threadpoolData->MinLimitTotalWorkerThreads = ThreadpoolMgr::MinLimitTotalWorkerThreads;
311 threadpoolData->MaxLimitTotalWorkerThreads = ThreadpoolMgr::MaxLimitTotalWorkerThreads;
312
313 //
314 // Read ThreadpoolMgr::WorkerCounter
315 //
316 TADDR pCounter = DacGetTargetAddrForHostAddr(&ThreadpoolMgr::WorkerCounter,true);
317 ThreadpoolMgr::ThreadCounter counter;
318 DacReadAll(pCounter,&counter,sizeof(ThreadpoolMgr::ThreadCounter),true);
319 ThreadpoolMgr::ThreadCounter::Counts counts = counter.counts;
320
321 threadpoolData->NumWorkingWorkerThreads = counts.NumWorking;
322 threadpoolData->NumIdleWorkerThreads = counts.NumActive - counts.NumWorking;
323 threadpoolData->NumRetiredWorkerThreads = counts.NumRetired;
324
325 threadpoolData->FirstUnmanagedWorkRequest = HOST_CDADDR(ThreadpoolMgr::WorkRequestHead);
326
327 threadpoolData->HillClimbingLog = dac_cast<TADDR>(&HillClimbingLog);
328 threadpoolData->HillClimbingLogFirstIndex = HillClimbingLogFirstIndex;
329 threadpoolData->HillClimbingLogSize = HillClimbingLogSize;
330
331
332 //
333 // Read ThreadpoolMgr::CPThreadCounter
334 //
335 pCounter = DacGetTargetAddrForHostAddr(&ThreadpoolMgr::CPThreadCounter,true);
336 DacReadAll(pCounter,&counter,sizeof(ThreadpoolMgr::ThreadCounter),true);
337 counts = counter.counts;
338
339 threadpoolData->NumCPThreads = (LONG)(counts.NumActive + counts.NumRetired);
340 threadpoolData->NumFreeCPThreads = (LONG)(counts.NumActive - counts.NumWorking);
341 threadpoolData->MaxFreeCPThreads = ThreadpoolMgr::MaxFreeCPThreads;
342 threadpoolData->NumRetiredCPThreads = (LONG)(counts.NumRetired);
343 threadpoolData->MaxLimitTotalCPThreads = ThreadpoolMgr::MaxLimitTotalCPThreads;
344 threadpoolData->CurrentLimitTotalCPThreads = (LONG)(counts.NumActive); //legacy: currently has no meaning
345 threadpoolData->MinLimitTotalCPThreads = ThreadpoolMgr::MinLimitTotalCPThreads;
346
347 TADDR pEntry = DacGetTargetAddrForHostAddr(&ThreadpoolMgr::TimerQueue,true);
348 ThreadpoolMgr::LIST_ENTRY entry;
349 DacReadAll(pEntry,&entry,sizeof(ThreadpoolMgr::LIST_ENTRY),true);
350 TADDR node = (TADDR) entry.Flink;
351 threadpoolData->NumTimers = 0;
352 while (node && node != pEntry)
353 {
354 threadpoolData->NumTimers++;
355 DacReadAll(node,&entry,sizeof(ThreadpoolMgr::LIST_ENTRY),true);
356 node = (TADDR) entry.Flink;
357 }
358
359 threadpoolData->AsyncTimerCallbackCompletionFPtr = (CLRDATA_ADDRESS) GFN_TADDR(ThreadpoolMgr__AsyncTimerCallbackCompletion);
360 SOSDacLeave();
361 return hr;
362}
363
364HRESULT ClrDataAccess::GetThreadStoreData(struct DacpThreadStoreData *threadStoreData)
365{
366 SOSDacEnter();
367
368 ThreadStore* threadStore = ThreadStore::s_pThreadStore;
369 if (!threadStore)
370 {
371 hr = E_UNEXPECTED;
372 }
373 else
374 {
375 // initialize the fields of our local structure
376 threadStoreData->threadCount = threadStore->m_ThreadCount;
377 threadStoreData->unstartedThreadCount = threadStore->m_UnstartedThreadCount;
378 threadStoreData->backgroundThreadCount = threadStore->m_BackgroundThreadCount;
379 threadStoreData->pendingThreadCount = threadStore->m_PendingThreadCount;
380 threadStoreData->deadThreadCount = threadStore->m_DeadThreadCount;
381 threadStoreData->fHostConfig = g_fHostConfig;
382
383 // identify the "important" threads
384 threadStoreData->firstThread = HOST_CDADDR(threadStore->m_ThreadList.GetHead());
385 threadStoreData->finalizerThread = HOST_CDADDR(g_pFinalizerThread);
386 threadStoreData->gcThread = HOST_CDADDR(g_pSuspensionThread);
387 }
388
389 SOSDacLeave();
390 return hr;
391}
392
393HRESULT
394ClrDataAccess::GetStressLogAddress(CLRDATA_ADDRESS *stressLog)
395{
396 if (stressLog == NULL)
397 return E_INVALIDARG;
398
399#ifdef STRESS_LOG
400 SOSDacEnter();
401 if (g_pStressLog.IsValid())
402 *stressLog = HOST_CDADDR(g_pStressLog);
403 else
404 hr = E_FAIL;
405
406 SOSDacLeave();
407 return hr;
408#else
409 return E_NOTIMPL;
410#endif // STRESS_LOG
411}
412
413HRESULT
414ClrDataAccess::GetJitManagerList(unsigned int count, struct DacpJitManagerInfo managers[], unsigned int *pNeeded)
415{
416 SOSDacEnter();
417
418 if (managers)
419 {
420 if (count >= 1)
421 {
422 EEJitManager * managerPtr = ExecutionManager::GetEEJitManager();
423
424 DacpJitManagerInfo *currentPtr = &managers[0];
425 currentPtr->managerAddr = HOST_CDADDR(managerPtr);
426 currentPtr->codeType = managerPtr->GetCodeType();
427
428 EEJitManager *eeJitManager = PTR_EEJitManager(PTR_HOST_TO_TADDR(managerPtr));
429 currentPtr->ptrHeapList = HOST_CDADDR(eeJitManager->m_pCodeHeap);
430 }
431#ifdef FEATURE_PREJIT
432 if (count >= 2)
433 {
434 NativeImageJitManager * managerPtr = ExecutionManager::GetNativeImageJitManager();
435 DacpJitManagerInfo *currentPtr = &managers[1];
436 currentPtr->managerAddr = HOST_CDADDR(managerPtr);
437 currentPtr->codeType = managerPtr->GetCodeType();
438 }
439#endif
440 }
441 else if (pNeeded)
442 {
443 *pNeeded = 1;
444#ifdef FEATURE_PREJIT
445 (*pNeeded)++;
446#endif
447 }
448
449 SOSDacLeave();
450 return hr;
451}
452
453HRESULT
454ClrDataAccess::GetMethodTableSlot(CLRDATA_ADDRESS mt, unsigned int slot, CLRDATA_ADDRESS *value)
455{
456 if (mt == 0 || value == NULL)
457 return E_INVALIDARG;
458
459 SOSDacEnter();
460
461 MethodTable* mTable = PTR_MethodTable(TO_TADDR(mt));
462 BOOL bIsFree = FALSE;
463 if (!DacValidateMethodTable(mTable, bIsFree))
464 {
465 hr = E_INVALIDARG;
466 }
467 else if (slot < mTable->GetNumVtableSlots())
468 {
469 // Now get the slot:
470 *value = mTable->GetRestoredSlot(slot);
471 }
472 else
473 {
474 hr = E_INVALIDARG;
475 MethodTable::IntroducedMethodIterator it(mTable);
476 for (; it.IsValid() && FAILED(hr); it.Next())
477 {
478 MethodDesc * pMD = it.GetMethodDesc();
479 if (pMD->GetSlot() == slot)
480 {
481 *value = pMD->GetMethodEntryPoint();
482 hr = S_OK;
483 }
484 }
485 }
486
487 SOSDacLeave();
488 return hr;
489}
490
491
492HRESULT
493ClrDataAccess::GetCodeHeapList(CLRDATA_ADDRESS jitManager, unsigned int count, struct DacpJitCodeHeapInfo codeHeaps[], unsigned int *pNeeded)
494{
495 if (jitManager == NULL)
496 return E_INVALIDARG;
497
498 SOSDacEnter();
499
500 EEJitManager *pJitManager = PTR_EEJitManager(TO_TADDR(jitManager));
501 HeapList *heapList = pJitManager->m_pCodeHeap;
502
503 if (codeHeaps)
504 {
505 unsigned int i = 0;
506 while ((heapList != NULL) && (i < count))
507 {
508 // What type of CodeHeap pointer do we have?
509 CodeHeap *codeHeap = heapList->pHeap;
510 TADDR ourVTablePtr = VPTR_HOST_VTABLE_TO_TADDR(*(LPVOID*)codeHeap);
511 if (ourVTablePtr == LoaderCodeHeap::VPtrTargetVTable())
512 {
513 LoaderCodeHeap *loaderCodeHeap = PTR_LoaderCodeHeap(PTR_HOST_TO_TADDR(codeHeap));
514 codeHeaps[i].codeHeapType = CODEHEAP_LOADER;
515 codeHeaps[i].LoaderHeap =
516 TO_CDADDR(PTR_HOST_MEMBER_TADDR(LoaderCodeHeap, loaderCodeHeap, m_LoaderHeap));
517 }
518 else if (ourVTablePtr == HostCodeHeap::VPtrTargetVTable())
519 {
520 HostCodeHeap *hostCodeHeap = PTR_HostCodeHeap(PTR_HOST_TO_TADDR(codeHeap));
521 codeHeaps[i].codeHeapType = CODEHEAP_HOST;
522 codeHeaps[i].HostData.baseAddr = PTR_CDADDR(hostCodeHeap->m_pBaseAddr);
523 codeHeaps[i].HostData.currentAddr = PTR_CDADDR(hostCodeHeap->m_pLastAvailableCommittedAddr);
524 }
525 else
526 {
527 codeHeaps[i].codeHeapType = CODEHEAP_UNKNOWN;
528 }
529 heapList = heapList->hpNext;
530 i++;
531 }
532
533 if (pNeeded)
534 *pNeeded = i;
535 }
536 else if (pNeeded)
537 {
538 int i = 0;
539 while (heapList != NULL)
540 {
541 heapList = heapList->hpNext;
542 i++;
543 }
544
545 *pNeeded = i;
546 }
547 else
548 {
549 hr = E_INVALIDARG;
550 }
551
552 SOSDacLeave();
553 return hr;
554}
555
556HRESULT
557ClrDataAccess::GetStackLimits(CLRDATA_ADDRESS threadPtr, CLRDATA_ADDRESS *lower,
558 CLRDATA_ADDRESS *upper, CLRDATA_ADDRESS *fp)
559{
560 if (threadPtr == 0 || (lower == NULL && upper == NULL && fp == NULL))
561 return E_INVALIDARG;
562
563 SOSDacEnter();
564
565 Thread * thread = PTR_Thread(TO_TADDR(threadPtr));
566
567 if (lower)
568 *lower = TO_CDADDR(thread->GetCachedStackBase().GetAddr());
569
570 if (upper)
571 *upper = TO_CDADDR(thread->GetCachedStackLimit().GetAddr());
572
573 if (fp)
574 *fp = PTR_HOST_MEMBER_TADDR(Thread, thread, m_pFrame);
575
576 SOSDacLeave();
577
578 return hr;
579}
580
581HRESULT
582ClrDataAccess::GetRegisterName(int regNum, unsigned int count, __out_z __inout_ecount(count) wchar_t *buffer, unsigned int *pNeeded)
583{
584 if (!buffer && !pNeeded)
585 return E_POINTER;
586
587#ifdef _TARGET_AMD64_
588 static const wchar_t *regs[] =
589 {
590 W("rax"), W("rcx"), W("rdx"), W("rbx"), W("rsp"), W("rbp"), W("rsi"), W("rdi"),
591 W("r8"), W("r9"), W("r10"), W("r11"), W("r12"), W("r13"), W("r14"), W("r15"),
592 };
593#elif defined(_TARGET_ARM_)
594 static const wchar_t *regs[] =
595 {
596 W("r0"),
597 W("r1"),
598 W("r2"),
599 W("r3"),
600 W("r4"),
601 W("r5"),
602 W("r6"),
603 W("r7"),
604 W("r8"), W("r9"), W("r10"), W("r11"), W("r12"), W("sp"), W("lr")
605 };
606#elif defined(_TARGET_ARM64_)
607 static const wchar_t *regs[] =
608 {
609 W("X0"),
610 W("X1"),
611 W("X2"),
612 W("X3"),
613 W("X4"),
614 W("X5"),
615 W("X6"),
616 W("X7"),
617 W("X8"), W("X9"), W("X10"), W("X11"), W("X12"), W("X13"), W("X14"), W("X15"), W("X16"), W("X17"),
618 W("X18"), W("X19"), W("X20"), W("X21"), W("X22"), W("X23"), W("X24"), W("X25"), W("X26"), W("X27"),
619 W("X28"), W("Fp"), W("Sp"), W("Lr")
620 };
621#elif defined(_TARGET_X86_)
622 static const wchar_t *regs[] =
623 {
624 W("eax"), W("ecx"), W("edx"), W("ebx"), W("esp"), W("ebp"), W("esi"), W("edi"),
625 };
626#endif
627
628 // Caller frame registers are encoded as "-(reg+1)".
629 bool callerFrame = regNum < 0;
630 if (callerFrame)
631 regNum = -regNum-1;
632
633 if ((unsigned int)regNum >= _countof(regs))
634 return E_UNEXPECTED;
635
636
637 const wchar_t caller[] = W("caller.");
638 unsigned int needed = (callerFrame?(unsigned int)wcslen(caller):0) + (unsigned int)wcslen(regs[regNum]) + 1;
639 if (pNeeded)
640 *pNeeded = needed;
641
642 if (buffer)
643 {
644 _snwprintf_s(buffer, count, _TRUNCATE, W("%s%s"), callerFrame ? caller : W(""), regs[regNum]);
645 if (count < needed)
646 return S_FALSE;
647 }
648
649 return S_OK;
650}
651
652HRESULT
653ClrDataAccess::GetStackReferences(DWORD osThreadID, ISOSStackRefEnum **ppEnum)
654{
655 if (ppEnum == NULL)
656 return E_POINTER;
657
658 SOSDacEnter();
659
660 DacStackReferenceWalker *walker = new (nothrow) DacStackReferenceWalker(this, osThreadID);
661
662 if (walker == NULL)
663 {
664 hr = E_OUTOFMEMORY;
665 }
666 else
667 {
668 hr = walker->Init();
669
670 if (SUCCEEDED(hr))
671 hr = walker->QueryInterface(__uuidof(ISOSStackRefEnum), (void**)ppEnum);
672
673 if (FAILED(hr))
674 {
675 delete walker;
676 *ppEnum = NULL;
677 }
678 }
679
680 SOSDacLeave();
681 return hr;
682}
683
684HRESULT
685ClrDataAccess::GetThreadFromThinlockID(UINT thinLockId, CLRDATA_ADDRESS *pThread)
686{
687 if (pThread == NULL)
688 return E_INVALIDARG;
689
690 SOSDacEnter();
691
692 Thread *thread = g_pThinLockThreadIdDispenser->IdToThread(thinLockId);
693 *pThread = PTR_HOST_TO_TADDR(thread);
694
695 SOSDacLeave();
696 return hr;
697}
698
699
700HRESULT
701ClrDataAccess::GetThreadAllocData(CLRDATA_ADDRESS addr, struct DacpAllocData *data)
702{
703 if (data == NULL)
704 return E_POINTER;
705
706 SOSDacEnter();
707
708 Thread* thread = PTR_Thread(TO_TADDR(addr));
709
710 data->allocBytes = TO_CDADDR(thread->m_alloc_context.alloc_bytes);
711 data->allocBytesLoh = TO_CDADDR(thread->m_alloc_context.alloc_bytes_loh);
712
713 SOSDacLeave();
714 return hr;
715}
716
717HRESULT
718ClrDataAccess::GetHeapAllocData(unsigned int count, struct DacpGenerationAllocData *data, unsigned int *pNeeded)
719{
720 if (data == 0 && pNeeded == NULL)
721 return E_INVALIDARG;
722
723 SOSDacEnter();
724#if defined(FEATURE_SVR_GC)
725 if (GCHeapUtilities::IsServerHeap())
726 {
727 hr = GetServerAllocData(count, data, pNeeded);
728 }
729 else
730#endif //FEATURE_SVR_GC
731 {
732 if (pNeeded)
733 *pNeeded = 1;
734
735 if (data && count >= 1)
736 {
737 DPTR(dac_generation) table = g_gcDacGlobals->generation_table;
738 for (unsigned int i=0; i < *g_gcDacGlobals->max_gen + 2; i++)
739 {
740 dac_generation entry = *GenerationTableIndex(table, i);
741 data[0].allocData[i].allocBytes = (CLRDATA_ADDRESS)(ULONG_PTR) entry.allocation_context.alloc_bytes;
742 data[0].allocData[i].allocBytesLoh = (CLRDATA_ADDRESS)(ULONG_PTR) entry.allocation_context.alloc_bytes_loh;
743 }
744 }
745 }
746
747 SOSDacLeave();
748 return hr;
749}
750
751HRESULT
752ClrDataAccess::GetThreadData(CLRDATA_ADDRESS threadAddr, struct DacpThreadData *threadData)
753{
754 SOSDacEnter();
755
756 // marshal the Thread object from the target
757 Thread* thread = PTR_Thread(TO_TADDR(threadAddr));
758
759 // initialize our local copy from the marshaled target Thread instance
760 ZeroMemory (threadData, sizeof(DacpThreadData));
761 threadData->corThreadId = thread->m_ThreadId;
762 threadData->osThreadId = thread->m_OSThreadId;
763 threadData->state = thread->m_State;
764 threadData->preemptiveGCDisabled = thread->m_fPreemptiveGCDisabled;
765 threadData->allocContextPtr = TO_CDADDR(thread->m_alloc_context.alloc_ptr);
766 threadData->allocContextLimit = TO_CDADDR(thread->m_alloc_context.alloc_limit);
767
768 threadData->fiberData = NULL;
769
770 threadData->pFrame = PTR_CDADDR(thread->m_pFrame);
771 threadData->context = PTR_CDADDR(thread->m_pDomain);
772 threadData->domain = PTR_CDADDR(thread->m_pDomain);
773 threadData->lockCount = thread->m_dwLockCount;
774#ifndef FEATURE_PAL
775 threadData->teb = TO_CDADDR(thread->m_pTEB);
776#else
777 threadData->teb = NULL;
778#endif
779 threadData->lastThrownObjectHandle =
780 TO_CDADDR(thread->m_LastThrownObjectHandle);
781 threadData->nextThread =
782 HOST_CDADDR(ThreadStore::s_pThreadStore->m_ThreadList.GetNext(thread));
783#ifdef WIN64EXCEPTIONS
784 if (thread->m_ExceptionState.m_pCurrentTracker)
785 {
786 threadData->firstNestedException = PTR_HOST_TO_TADDR(
787 thread->m_ExceptionState.m_pCurrentTracker->m_pPrevNestedInfo);
788 }
789#else
790 threadData->firstNestedException = PTR_HOST_TO_TADDR(
791 thread->m_ExceptionState.m_currentExInfo.m_pPrevNestedInfo);
792#endif // _WIN64
793
794 SOSDacLeave();
795 return hr;
796}
797
798#ifdef FEATURE_REJIT
799void CopyNativeCodeVersionToReJitData(NativeCodeVersion nativeCodeVersion, NativeCodeVersion activeCodeVersion, DacpReJitData * pReJitData)
800{
801 pReJitData->rejitID = nativeCodeVersion.GetILCodeVersion().GetVersionId();
802 pReJitData->NativeCodeAddr = nativeCodeVersion.GetNativeCode();
803
804 if (nativeCodeVersion != activeCodeVersion)
805 {
806 pReJitData->flags = DacpReJitData::kReverted;
807 }
808 else
809 {
810 switch (nativeCodeVersion.GetILCodeVersion().GetRejitState())
811 {
812 default:
813 _ASSERTE(!"Unknown SharedRejitInfo state. DAC should be updated to understand this new state.");
814 pReJitData->flags = DacpReJitData::kUnknown;
815 break;
816
817 case ILCodeVersion::kStateRequested:
818 pReJitData->flags = DacpReJitData::kRequested;
819 break;
820
821 case ILCodeVersion::kStateActive:
822 pReJitData->flags = DacpReJitData::kActive;
823 break;
824 }
825 }
826}
827#endif // FEATURE_REJIT
828
829//---------------------------------------------------------------------------------------
830//
831// Given a method desc addr, this loads up DacpMethodDescData and multiple DacpReJitDatas
832// with data on that method
833//
834// Arguments:
835// * methodDesc - MD to look up
836// * ip - IP address of interest (e.g., from an !ip2md call). This is used to ensure
837// the rejitted version corresponding to this IP is returned. May be NULL if you
838// don't care.
839// * methodDescData - [out] DacpMethodDescData to populate
840// * cRevertedRejitVersions - Number of entries allocated in rgRevertedRejitData
841// array
842// * rgRevertedRejitData - [out] Array of DacpReJitDatas to populate with rejitted
843// rejit version data
844// * pcNeededRevertedRejitData - [out] If cRevertedRejitVersions==0, the total
845// number of available rejit versions (including the current version) is
846// returned here. Else, the number of reverted rejit data actually fetched is
847// returned here.
848//
849// Return Value:
850// HRESULT indicating success or failure.
851//
852
853HRESULT ClrDataAccess::GetMethodDescData(
854 CLRDATA_ADDRESS methodDesc,
855 CLRDATA_ADDRESS ip,
856 struct DacpMethodDescData *methodDescData,
857 ULONG cRevertedRejitVersions,
858 DacpReJitData * rgRevertedRejitData,
859 ULONG * pcNeededRevertedRejitData)
860{
861 if (methodDesc == 0)
862 return E_INVALIDARG;
863
864 if ((cRevertedRejitVersions != 0) && (rgRevertedRejitData == NULL))
865 {
866 return E_INVALIDARG;
867 }
868
869 if ((rgRevertedRejitData != NULL) && (pcNeededRevertedRejitData == NULL))
870 {
871 // If you're asking for reverted rejit data, you'd better ask for the number of
872 // elements we return
873 return E_INVALIDARG;
874 }
875
876 SOSDacEnter();
877
878 PTR_MethodDesc pMD = PTR_MethodDesc(TO_TADDR(methodDesc));
879
880 if (!DacValidateMD(pMD))
881 {
882 hr = E_INVALIDARG;
883 }
884 else
885 {
886 ZeroMemory(methodDescData, sizeof(DacpMethodDescData));
887 if (rgRevertedRejitData != NULL)
888 ZeroMemory(rgRevertedRejitData, sizeof(*rgRevertedRejitData) * cRevertedRejitVersions);
889 if (pcNeededRevertedRejitData != NULL)
890 *pcNeededRevertedRejitData = 0;
891
892 methodDescData->requestedIP = ip;
893 methodDescData->bHasNativeCode = pMD->HasNativeCode();
894 methodDescData->bIsDynamic = (pMD->IsLCGMethod()) ? TRUE : FALSE;
895 methodDescData->wSlotNumber = pMD->GetSlot();
896 if (pMD->HasNativeCode())
897 {
898 methodDescData->NativeCodeAddr = TO_CDADDR(pMD->GetNativeCode());
899#ifdef DBG_TARGET_ARM
900 methodDescData->NativeCodeAddr &= ~THUMB_CODE;
901#endif
902 }
903 else
904 {
905 methodDescData->NativeCodeAddr = (CLRDATA_ADDRESS)-1;
906 }
907 methodDescData->AddressOfNativeCodeSlot = pMD->HasNativeCodeSlot() ? TO_CDADDR(pMD->GetAddrOfNativeCodeSlot()) : NULL;
908 methodDescData->MDToken = pMD->GetMemberDef();
909 methodDescData->MethodDescPtr = methodDesc;
910 methodDescData->MethodTablePtr = HOST_CDADDR(pMD->GetMethodTable());
911 methodDescData->ModulePtr = HOST_CDADDR(pMD->GetModule());
912
913#ifdef FEATURE_REJIT
914
915 // If rejit info is appropriate, get the following:
916 // * ReJitInfo for the current, active version of the method
917 // * ReJitInfo for the requested IP (for !ip2md and !u)
918 // * ReJitInfos for all reverted versions of the method (up to
919 // cRevertedRejitVersions)
920 //
921 // Minidumps will not have all this rejit info, and failure to get rejit info
922 // should not be fatal. So enclose all rejit stuff in a try.
923
924 EX_TRY
925 {
926 CodeVersionManager *pCodeVersionManager = pMD->GetCodeVersionManager();
927
928 // Current ReJitInfo
929 ILCodeVersion activeILCodeVersion = pCodeVersionManager->GetActiveILCodeVersion(pMD);
930 NativeCodeVersion activeChild = activeILCodeVersion.GetActiveNativeCodeVersion(pMD);
931 CopyNativeCodeVersionToReJitData(activeChild, activeChild, &methodDescData->rejitDataCurrent);
932
933 if (!activeChild.IsNull())
934 {
935 // This was already set previously, but MethodDesc::GetNativeCode is potentially not aware of
936 // a new native code version, so this is more accurate.
937 methodDescData->NativeCodeAddr = activeChild.GetNativeCode();
938 }
939
940 // Requested ReJitInfo
941 _ASSERTE(methodDescData->rejitDataRequested.rejitID == 0);
942 if (methodDescData->requestedIP != NULL)
943 {
944 NativeCodeVersion nativeCodeVersionRequested = pCodeVersionManager->GetNativeCodeVersion(
945 pMD,
946 CLRDATA_ADDRESS_TO_TADDR(methodDescData->requestedIP));
947
948 if (!nativeCodeVersionRequested.IsNull())
949 {
950 CopyNativeCodeVersionToReJitData(nativeCodeVersionRequested, activeChild, &methodDescData->rejitDataRequested);
951 }
952 }
953
954 // Total number of jitted rejit versions
955 ULONG cJittedRejitVersions;
956 if (SUCCEEDED(ReJitManager::GetReJITIDs(pMD, 0 /* cReJitIds */, &cJittedRejitVersions, NULL /* reJitIds */)))
957 {
958 methodDescData->cJittedRejitVersions = cJittedRejitVersions;
959 }
960
961 // Reverted ReJitInfos
962 if (rgRevertedRejitData == NULL)
963 {
964 // No reverted rejit versions will be returned, but maybe caller wants a
965 // count of all versions
966 if (pcNeededRevertedRejitData != NULL)
967 {
968 *pcNeededRevertedRejitData = methodDescData->cJittedRejitVersions;
969 }
970 }
971 else
972 {
973 // Caller wants some reverted rejit versions. Gather reverted rejit version data to return
974 ULONG cReJitIds;
975 StackSArray<ReJITID> reJitIds;
976
977 // Prepare array to populate with rejitids. "+ 1" because GetReJITIDs
978 // returns all available rejitids, including the rejitid for the one non-reverted
979 // current version.
980 ReJITID *rgReJitIds = reJitIds.OpenRawBuffer(cRevertedRejitVersions + 1);
981 if (rgReJitIds != NULL)
982 {
983 hr = ReJitManager::GetReJITIDs(pMD, cRevertedRejitVersions + 1, &cReJitIds, rgReJitIds);
984 if (SUCCEEDED(hr))
985 {
986 // Go through rejitids. For each reverted one, populate a entry in rgRevertedRejitData
987 reJitIds.CloseRawBuffer(cReJitIds);
988 ULONG iRejitDataReverted = 0;
989 ILCodeVersion activeVersion = pCodeVersionManager->GetActiveILCodeVersion(pMD);
990 for (COUNT_T i = 0;
991 (i < cReJitIds) && (iRejitDataReverted < cRevertedRejitVersions);
992 i++)
993 {
994 ILCodeVersion ilCodeVersion = pCodeVersionManager->GetILCodeVersion(pMD, reJitIds[i]);
995
996 if ((ilCodeVersion.IsNull()) ||
997 (ilCodeVersion == activeVersion))
998 {
999 continue;
1000 }
1001
1002 NativeCodeVersion activeRejitChild = ilCodeVersion.GetActiveNativeCodeVersion(pMD);
1003 CopyNativeCodeVersionToReJitData(activeRejitChild, activeChild, &rgRevertedRejitData[iRejitDataReverted]);
1004 iRejitDataReverted++;
1005 }
1006 // pcNeededRevertedRejitData != NULL as per condition at top of function (cuz rgRevertedRejitData !=
1007 // NULL).
1008 *pcNeededRevertedRejitData = iRejitDataReverted;
1009 }
1010 }
1011 }
1012 }
1013 EX_CATCH
1014 {
1015 if (pcNeededRevertedRejitData != NULL)
1016 *pcNeededRevertedRejitData = 0;
1017 }
1018 EX_END_CATCH(SwallowAllExceptions)
1019 hr = S_OK; // Failure to get rejitids is not fatal
1020#endif // FEATURE_REJIT
1021
1022#if defined(HAVE_GCCOVER)
1023 if (pMD->m_GcCover)
1024 {
1025 EX_TRY
1026 {
1027 // In certain minidumps, we won't save the gccover information.
1028 // (it would be unwise to do so, it is heavy and not a customer scenario).
1029 methodDescData->GCStressCodeCopy = HOST_CDADDR(pMD->m_GcCover) + offsetof(GCCoverageInfo, savedCode);
1030 }
1031 EX_CATCH
1032 {
1033 methodDescData->GCStressCodeCopy = 0;
1034 }
1035 EX_END_CATCH(SwallowAllExceptions)
1036 }
1037 else
1038#endif // HAVE_GCCOVER
1039
1040 // Set this above Dario since you know how to tell if dynamic
1041 if (methodDescData->bIsDynamic)
1042 {
1043 DynamicMethodDesc *pDynamicMethod = PTR_DynamicMethodDesc(TO_TADDR(methodDesc));
1044 if (pDynamicMethod)
1045 {
1046 LCGMethodResolver *pResolver = pDynamicMethod->GetLCGMethodResolver();
1047 if (pResolver)
1048 {
1049 OBJECTREF value = pResolver->GetManagedResolver();
1050 if (value)
1051 {
1052 FieldDesc *pField = (&g_Mscorlib)->GetField(FIELD__DYNAMICRESOLVER__DYNAMIC_METHOD);
1053 _ASSERTE(pField);
1054 value = pField->GetRefValue(value);
1055 if (value)
1056 {
1057 methodDescData->managedDynamicMethodObject = PTR_HOST_TO_TADDR(value);
1058 }
1059 }
1060 }
1061 }
1062 }
1063 }
1064
1065 SOSDacLeave();
1066 return hr;
1067}
1068
1069HRESULT ClrDataAccess::GetTieredVersions(
1070 CLRDATA_ADDRESS methodDesc,
1071 int rejitId,
1072 struct DacpTieredVersionData *nativeCodeAddrs,
1073 int cNativeCodeAddrs,
1074 int *pcNativeCodeAddrs)
1075{
1076 if (methodDesc == 0 || cNativeCodeAddrs == 0 || pcNativeCodeAddrs == NULL)
1077 {
1078 return E_INVALIDARG;
1079 }
1080
1081 *pcNativeCodeAddrs = 0;
1082
1083 SOSDacEnter();
1084
1085#ifdef FEATURE_REJIT
1086 PTR_MethodDesc pMD = PTR_MethodDesc(TO_TADDR(methodDesc));
1087
1088 // If rejit info is appropriate, get the following:
1089 // * ReJitInfo for the current, active version of the method
1090 // * ReJitInfo for the requested IP (for !ip2md and !u)
1091 // * ReJitInfos for all reverted versions of the method (up to
1092 // cRevertedRejitVersions)
1093 //
1094 // Minidumps will not have all this rejit info, and failure to get rejit info
1095 // should not be fatal. So enclose all rejit stuff in a try.
1096
1097 EX_TRY
1098 {
1099 CodeVersionManager *pCodeVersionManager = pMD->GetCodeVersionManager();
1100
1101 // Total number of jitted rejit versions
1102 ULONG cJittedRejitVersions;
1103 if (!SUCCEEDED(ReJitManager::GetReJITIDs(pMD, 0 /* cReJitIds */, &cJittedRejitVersions, NULL /* reJitIds */)))
1104 {
1105 goto cleanup;
1106 }
1107
1108 if ((ULONG)rejitId >= cJittedRejitVersions)
1109 {
1110 hr = E_INVALIDARG;
1111 goto cleanup;
1112 }
1113
1114 ULONG cReJitIds;
1115 StackSArray<ReJITID> reJitIds;
1116
1117 // Prepare array to populate with rejitids.
1118 ReJITID *rgReJitIds = reJitIds.OpenRawBuffer(cJittedRejitVersions);
1119 if (rgReJitIds != NULL)
1120 {
1121 hr = ReJitManager::GetReJITIDs(pMD, cJittedRejitVersions, &cReJitIds, rgReJitIds);
1122 if (SUCCEEDED(hr))
1123 {
1124 reJitIds.CloseRawBuffer(cReJitIds);
1125
1126 ILCodeVersion ilCodeVersion = pCodeVersionManager->GetILCodeVersion(pMD, reJitIds[rejitId]);
1127
1128 if (ilCodeVersion.IsNull())
1129 {
1130 hr = S_FALSE;
1131 goto cleanup;
1132 }
1133
1134 NativeCodeVersionCollection nativeCodeVersions = ilCodeVersion.GetNativeCodeVersions(pMD);
1135 int count = 0;
1136 for (NativeCodeVersionIterator iter = nativeCodeVersions.Begin(); iter != nativeCodeVersions.End(); iter++)
1137 {
1138 nativeCodeAddrs[count].NativeCodeAddr = (*iter).GetNativeCode();
1139 PTR_NativeCodeVersionNode pNode = (*iter).AsNode();
1140 nativeCodeAddrs[count].NativeCodeVersionNodePtr = TO_CDADDR(PTR_TO_TADDR(pNode));
1141
1142 if (pMD->IsEligibleForTieredCompilation())
1143 {
1144 switch ((*iter).GetOptimizationTier())
1145 {
1146 default:
1147 nativeCodeAddrs[count].TieredInfo = DacpTieredVersionData::TIERED_UNKNOWN;
1148 break;
1149 case NativeCodeVersion::OptimizationTier0:
1150 nativeCodeAddrs[count].TieredInfo = DacpTieredVersionData::TIERED_0;
1151 break;
1152 case NativeCodeVersion::OptimizationTier1:
1153 nativeCodeAddrs[count].TieredInfo = DacpTieredVersionData::TIERED_1;
1154 break;
1155 }
1156 }
1157 else
1158 {
1159 nativeCodeAddrs[count].TieredInfo = DacpTieredVersionData::NON_TIERED;
1160 }
1161
1162 ++count;
1163
1164 if (count >= cNativeCodeAddrs)
1165 {
1166 hr = S_FALSE;
1167 break;
1168 }
1169 }
1170
1171 *pcNativeCodeAddrs = count;
1172 }
1173 }
1174 }
1175 EX_CATCH
1176 {
1177 hr = E_FAIL;
1178 }
1179 EX_END_CATCH(SwallowAllExceptions)
1180
1181cleanup:
1182 ;
1183#endif // FEATURE_REJIT
1184
1185 SOSDacLeave();
1186 return hr;
1187}
1188
1189HRESULT
1190ClrDataAccess::GetMethodDescTransparencyData(CLRDATA_ADDRESS methodDesc, struct DacpMethodDescTransparencyData *data)
1191{
1192 if (methodDesc == 0 || data == NULL)
1193 return E_INVALIDARG;
1194
1195 SOSDacEnter();
1196
1197 MethodDesc *pMD = PTR_MethodDesc(TO_TADDR(methodDesc));
1198 if (!DacValidateMD(pMD))
1199 {
1200 hr = E_INVALIDARG;
1201 }
1202 else
1203 {
1204 ZeroMemory(data, sizeof(DacpMethodDescTransparencyData));
1205 }
1206
1207 SOSDacLeave();
1208 return hr;
1209}
1210
1211HRESULT
1212ClrDataAccess::GetCodeHeaderData(CLRDATA_ADDRESS ip, struct DacpCodeHeaderData *codeHeaderData)
1213{
1214 if (ip == 0 || codeHeaderData == NULL)
1215 return E_INVALIDARG;
1216
1217 SOSDacEnter();
1218
1219 EECodeInfo codeInfo(TO_TADDR(ip));
1220
1221 if (!codeInfo.IsValid())
1222 {
1223 // We may be able to walk stubs to find a method desc if it's not a jitted method.
1224 MethodDesc *methodDescI = MethodTable::GetMethodDescForSlotAddress(TO_TADDR(ip));
1225 if (methodDescI == NULL)
1226 {
1227 hr = E_INVALIDARG;
1228 }
1229 else
1230 {
1231 codeHeaderData->MethodDescPtr = HOST_CDADDR(methodDescI);
1232 codeHeaderData->JITType = TYPE_UNKNOWN;
1233 codeHeaderData->GCInfo = NULL;
1234 codeHeaderData->MethodStart = NULL;
1235 codeHeaderData->MethodSize = 0;
1236 codeHeaderData->ColdRegionStart = NULL;
1237 }
1238 }
1239 else
1240 {
1241 codeHeaderData->MethodDescPtr = HOST_CDADDR(codeInfo.GetMethodDesc());
1242
1243 GetJITMethodInfo(&codeInfo, &codeHeaderData->JITType, &codeHeaderData->GCInfo);
1244
1245 codeHeaderData->MethodStart =
1246 (CLRDATA_ADDRESS) codeInfo.GetStartAddress();
1247 size_t methodSize = codeInfo.GetCodeManager()->GetFunctionSize(codeInfo.GetGCInfoToken());
1248 _ASSERTE(FitsIn<DWORD>(methodSize));
1249 codeHeaderData->MethodSize = static_cast<DWORD>(methodSize);
1250
1251 IJitManager::MethodRegionInfo methodRegionInfo = {NULL, 0, NULL, 0};
1252 codeInfo.GetMethodRegionInfo(&methodRegionInfo);
1253
1254 codeHeaderData->HotRegionSize = (DWORD) methodRegionInfo.hotSize;
1255 codeHeaderData->ColdRegionSize = (DWORD) methodRegionInfo.coldSize;
1256 codeHeaderData->ColdRegionStart = (CLRDATA_ADDRESS) methodRegionInfo.coldStartAddress;
1257 }
1258
1259 SOSDacLeave();
1260 return hr;
1261}
1262
1263HRESULT
1264ClrDataAccess::GetMethodDescPtrFromFrame(CLRDATA_ADDRESS frameAddr, CLRDATA_ADDRESS * ppMD)
1265{
1266 if (frameAddr == 0 || ppMD == NULL)
1267 return E_INVALIDARG;
1268
1269 SOSDacEnter();
1270
1271 Frame *pFrame = PTR_Frame(TO_TADDR(frameAddr));
1272 CLRDATA_ADDRESS methodDescAddr = HOST_CDADDR(pFrame->GetFunction());
1273 if ((methodDescAddr == NULL) || !DacValidateMD(PTR_MethodDesc(TO_TADDR(methodDescAddr))))
1274 {
1275 hr = E_INVALIDARG;
1276 }
1277 else
1278 {
1279 *ppMD = methodDescAddr;
1280 hr = S_OK;
1281 }
1282
1283 SOSDacLeave();
1284 return hr;
1285}
1286
1287HRESULT
1288ClrDataAccess::GetMethodDescPtrFromIP(CLRDATA_ADDRESS ip, CLRDATA_ADDRESS * ppMD)
1289{
1290 if (ip == 0 || ppMD == NULL)
1291 return E_INVALIDARG;
1292
1293 SOSDacEnter();
1294
1295 EECodeInfo codeInfo(TO_TADDR(ip));
1296
1297 if (!codeInfo.IsValid())
1298 {
1299 hr = E_FAIL;
1300 }
1301 else
1302 {
1303 CLRDATA_ADDRESS pMD = HOST_CDADDR(codeInfo.GetMethodDesc());
1304 if ((pMD == NULL) || !DacValidateMD(PTR_MethodDesc(TO_TADDR(pMD))))
1305 {
1306 hr = E_INVALIDARG;
1307 }
1308 else
1309 {
1310 *ppMD = pMD;
1311 hr = S_OK;
1312 }
1313 }
1314
1315 SOSDacLeave();
1316 return hr;
1317}
1318
1319HRESULT
1320ClrDataAccess::GetMethodDescName(CLRDATA_ADDRESS methodDesc, unsigned int count, __out_z __inout_ecount(count) wchar_t *name, unsigned int *pNeeded)
1321{
1322 if (methodDesc == 0)
1323 return E_INVALIDARG;
1324
1325 SOSDacEnter();
1326
1327 MethodDesc* pMD = PTR_MethodDesc(TO_TADDR(methodDesc));
1328 StackSString str;
1329
1330 EX_TRY
1331 {
1332 TypeString::AppendMethodInternal(str, pMD, TypeString::FormatSignature|TypeString::FormatNamespace|TypeString::FormatFullInst);
1333 }
1334 EX_CATCH
1335 {
1336 hr = E_FAIL;
1337 if (pMD->IsDynamicMethod())
1338 {
1339 if (pMD->IsLCGMethod() || pMD->IsILStub())
1340 {
1341 // In heap dumps, trying to format the signature can fail
1342 // in certain cases because StoredSigMethodDesc::m_pSig points
1343 // to the IMAGE_MAPPED layout (in the PEImage::m_pLayouts array).
1344 // We save only the IMAGE_LOADED layout to the heap dump. Rather
1345 // than bloat the dump, we just drop the signature in these
1346 // cases.
1347
1348 str.Clear();
1349 TypeString::AppendMethodInternal(str, pMD, TypeString::FormatNamespace|TypeString::FormatFullInst);
1350 hr = S_OK;
1351 }
1352 }
1353 else
1354 {
1355#ifdef FEATURE_MINIMETADATA_IN_TRIAGEDUMPS
1356 if (MdCacheGetEEName(TO_TADDR(methodDesc), str))
1357 {
1358 hr = S_OK;
1359 }
1360 else
1361 {
1362#endif // FEATURE_MINIMETADATA_IN_TRIAGEDUMPS
1363 str.Clear();
1364 Module* pModule = pMD->GetModule();
1365 if (pModule)
1366 {
1367 WCHAR path[MAX_LONGPATH];
1368 COUNT_T nChars = 0;
1369 if (pModule->GetPath().DacGetUnicode(NumItems(path), path, &nChars) &&
1370 nChars > 0 && nChars <= NumItems(path))
1371 {
1372 WCHAR* pFile = path + nChars - 1;
1373 while ((pFile >= path) && (*pFile != W('\\')))
1374 {
1375 pFile--;
1376 }
1377 pFile++;
1378 if (*pFile)
1379 {
1380 str.Append(pFile);
1381 str.Append(W("!Unknown"));
1382 hr = S_OK;
1383 }
1384 }
1385 }
1386#ifdef FEATURE_MINIMETADATA_IN_TRIAGEDUMPS
1387 }
1388#endif
1389 }
1390 }
1391 EX_END_CATCH(SwallowAllExceptions)
1392
1393 if (SUCCEEDED(hr))
1394 {
1395
1396 const wchar_t *val = str.GetUnicode();
1397
1398 if (pNeeded)
1399 *pNeeded = str.GetCount() + 1;
1400
1401 if (name && count)
1402 {
1403 wcsncpy_s(name, count, val, _TRUNCATE);
1404 name[count-1] = 0;
1405 }
1406 }
1407
1408 SOSDacLeave();
1409 return hr;
1410}
1411
1412HRESULT
1413ClrDataAccess::GetDomainFromContext(CLRDATA_ADDRESS contextAddr, CLRDATA_ADDRESS *domain)
1414{
1415 if (contextAddr == 0 || domain == NULL)
1416 return E_INVALIDARG;
1417
1418 SOSDacEnter();
1419
1420 *domain = contextAddr; // Context is same as the AppDomain in CoreCLR
1421
1422 SOSDacLeave();
1423 return hr;
1424}
1425
1426
1427HRESULT
1428ClrDataAccess::GetObjectStringData(CLRDATA_ADDRESS obj, unsigned int count, __out_z __inout_ecount(count) wchar_t *stringData, unsigned int *pNeeded)
1429{
1430 if (obj == 0)
1431 return E_INVALIDARG;
1432
1433 if ((stringData == 0 || count <= 0) && (pNeeded == NULL))
1434 return E_INVALIDARG;
1435
1436 SOSDacEnter();
1437
1438 TADDR mtTADDR = DACGetMethodTableFromObjectPointer(TO_TADDR(obj), m_pTarget);
1439 MethodTable *mt = PTR_MethodTable(mtTADDR);
1440
1441 // Object must be a string
1442 BOOL bFree = FALSE;
1443 if (!DacValidateMethodTable(mt, bFree))
1444 hr = E_INVALIDARG;
1445 else if (HOST_CDADDR(mt) != HOST_CDADDR(g_pStringClass))
1446 hr = E_INVALIDARG;
1447
1448 if (SUCCEEDED(hr))
1449 {
1450 PTR_StringObject str(TO_TADDR(obj));
1451 ULONG32 needed = (ULONG32)str->GetStringLength() + 1;
1452
1453 if (stringData && count > 0)
1454 {
1455 if (count > needed)
1456 count = needed;
1457
1458 TADDR pszStr = TO_TADDR(obj)+offsetof(StringObject, m_FirstChar);
1459 hr = m_pTarget->ReadVirtual(pszStr, (PBYTE)stringData, count * sizeof(wchar_t), &needed);
1460
1461 if (SUCCEEDED(hr))
1462 stringData[count - 1] = W('\0');
1463 else
1464 stringData[0] = W('\0');
1465 }
1466 else
1467 {
1468 hr = E_INVALIDARG;
1469 }
1470
1471 if (pNeeded)
1472 *pNeeded = needed;
1473 }
1474
1475 SOSDacLeave();
1476 return hr;
1477}
1478
1479HRESULT
1480ClrDataAccess::GetObjectClassName(CLRDATA_ADDRESS obj, unsigned int count, __out_z __inout_ecount(count) wchar_t *className, unsigned int *pNeeded)
1481{
1482 if (obj == 0)
1483 return E_INVALIDARG;
1484
1485 SOSDacEnter();
1486
1487 // Don't turn the Object into a pointer, it is too costly on
1488 // scans of the gc heap.
1489 MethodTable *mt = NULL;
1490 TADDR mtTADDR = DACGetMethodTableFromObjectPointer(CLRDATA_ADDRESS_TO_TADDR(obj), m_pTarget);
1491 if (mtTADDR != NULL)
1492 mt = PTR_MethodTable(mtTADDR);
1493 else
1494 hr = E_INVALIDARG;
1495
1496 BOOL bFree = FALSE;
1497 if (SUCCEEDED(hr) && !DacValidateMethodTable(mt, bFree))
1498 hr = E_INVALIDARG;
1499
1500 if (SUCCEEDED(hr))
1501 {
1502 // There is a case where metadata was unloaded and the AppendType call will fail.
1503 // This is when an AppDomain has been unloaded but not yet collected.
1504 PEFile *pPEFile = mt->GetModule()->GetFile();
1505 if (pPEFile->GetNativeImage() == NULL && pPEFile->GetILimage() == NULL)
1506 {
1507 if (pNeeded)
1508 *pNeeded = 16;
1509
1510 if (className)
1511 wcsncpy_s(className, count, W("<Unloaded Type>"), _TRUNCATE);
1512 }
1513 else
1514 {
1515 StackSString s;
1516 TypeString::AppendType(s, TypeHandle(mt), TypeString::FormatNamespace|TypeString::FormatFullInst);
1517 const wchar_t *val = s.GetUnicode();
1518
1519 if (pNeeded)
1520 *pNeeded = s.GetCount() + 1;
1521
1522 if (className && count)
1523 {
1524 wcsncpy_s(className, count, val, _TRUNCATE);
1525 className[count-1] = 0;
1526 }
1527 }
1528 }
1529
1530 SOSDacLeave();
1531 return hr;
1532}
1533
1534HRESULT
1535ClrDataAccess::GetMethodDescFromToken(CLRDATA_ADDRESS moduleAddr, mdToken token, CLRDATA_ADDRESS *methodDesc)
1536{
1537 if (moduleAddr == 0 || methodDesc == NULL)
1538 return E_INVALIDARG;
1539
1540 SOSDacEnter();
1541
1542 Module* pModule = PTR_Module(TO_TADDR(moduleAddr));
1543 TypeHandle th;
1544 switch (TypeFromToken(token))
1545 {
1546 case mdtFieldDef:
1547 *methodDesc = HOST_CDADDR(pModule->LookupFieldDef(token));
1548 break;
1549 case mdtMethodDef:
1550 *methodDesc = HOST_CDADDR(pModule->LookupMethodDef(token));
1551 break;
1552 case mdtTypeDef:
1553 th = pModule->LookupTypeDef(token);
1554 *methodDesc = th.AsTAddr();
1555 break;
1556 case mdtTypeRef:
1557 th = pModule->LookupTypeRef(token);
1558 *methodDesc = th.AsTAddr();
1559 break;
1560 default:
1561 hr = E_INVALIDARG;
1562 break;
1563 }
1564
1565 SOSDacLeave();
1566 return hr;
1567}
1568
1569HRESULT
1570ClrDataAccess::TraverseModuleMap(ModuleMapType mmt, CLRDATA_ADDRESS moduleAddr, MODULEMAPTRAVERSE pCallback, LPVOID token)
1571{
1572 if (moduleAddr == 0)
1573 return E_INVALIDARG;
1574
1575 SOSDacEnter();
1576
1577 Module* pModule = PTR_Module(TO_TADDR(moduleAddr));
1578
1579 // We want to traverse these two tables, passing callback information
1580 switch (mmt)
1581 {
1582 case TYPEDEFTOMETHODTABLE:
1583 {
1584 LookupMap<PTR_MethodTable>::Iterator typeIter(&pModule->m_TypeDefToMethodTableMap);
1585 for (int i = 0; typeIter.Next(); i++)
1586 {
1587 if (typeIter.GetElement())
1588 {
1589 MethodTable* pMT = typeIter.GetElement();
1590 (pCallback)(i,PTR_HOST_TO_TADDR(pMT), token);
1591 }
1592 }
1593 }
1594 break;
1595 case TYPEREFTOMETHODTABLE:
1596 {
1597 LookupMap<PTR_TypeRef>::Iterator typeIter(&pModule->m_TypeRefToMethodTableMap);
1598 for (int i = 0; typeIter.Next(); i++)
1599 {
1600 if (typeIter.GetElement())
1601 {
1602 MethodTable* pMT = TypeHandle::FromTAddr(dac_cast<TADDR>(typeIter.GetElement())).GetMethodTable();
1603 (pCallback)(i,PTR_HOST_TO_TADDR(pMT), token);
1604 }
1605 }
1606 }
1607 break;
1608 default:
1609 hr = E_INVALIDARG;
1610 }
1611
1612 SOSDacLeave();
1613 return hr;
1614}
1615
1616HRESULT
1617ClrDataAccess::GetModule(CLRDATA_ADDRESS addr, IXCLRDataModule **mod)
1618{
1619 if (addr == 0 || mod == NULL)
1620 return E_INVALIDARG;
1621
1622 SOSDacEnter();
1623
1624 Module* pModule = PTR_Module(TO_TADDR(addr));
1625 *mod = new ClrDataModule(this, pModule);
1626 SOSDacLeave();
1627
1628 return hr;
1629}
1630
1631HRESULT
1632ClrDataAccess::GetModuleData(CLRDATA_ADDRESS addr, struct DacpModuleData *ModuleData)
1633{
1634 if (addr == 0 || ModuleData == NULL)
1635 return E_INVALIDARG;
1636
1637 SOSDacEnter();
1638
1639 Module* pModule = PTR_Module(TO_TADDR(addr));
1640
1641 ZeroMemory(ModuleData,sizeof(DacpModuleData));
1642 ModuleData->Address = addr;
1643 ModuleData->File = HOST_CDADDR(pModule->GetFile());
1644 COUNT_T metadataSize = 0;
1645 if (pModule->GetFile()->HasNativeImage())
1646 {
1647 ModuleData->ilBase = (CLRDATA_ADDRESS)PTR_TO_TADDR(pModule->GetFile()->GetLoadedNative()->GetBase());
1648 }
1649 else
1650 if (!pModule->GetFile()->IsDynamic())
1651 {
1652 ModuleData->ilBase = (CLRDATA_ADDRESS)(ULONG_PTR) pModule->GetFile()->GetIJWBase();
1653 }
1654
1655 ModuleData->metadataStart = (CLRDATA_ADDRESS)dac_cast<TADDR>(pModule->GetFile()->GetLoadedMetadata(&metadataSize));
1656 ModuleData->metadataSize = (SIZE_T) metadataSize;
1657
1658 ModuleData->bIsReflection = pModule->IsReflection();
1659 ModuleData->bIsPEFile = pModule->IsPEFile();
1660 ModuleData->Assembly = HOST_CDADDR(pModule->GetAssembly());
1661 ModuleData->dwModuleID = pModule->GetModuleID();
1662 ModuleData->dwModuleIndex = pModule->GetModuleIndex().m_dwIndex;
1663 ModuleData->dwTransientFlags = pModule->m_dwTransientFlags;
1664
1665 EX_TRY
1666 {
1667 //
1668 // In minidump's case, these data structure is not avaiable.
1669 //
1670 ModuleData->TypeDefToMethodTableMap = PTR_CDADDR(pModule->m_TypeDefToMethodTableMap.pTable);
1671 ModuleData->TypeRefToMethodTableMap = PTR_CDADDR(pModule->m_TypeRefToMethodTableMap.pTable);
1672 ModuleData->MethodDefToDescMap = PTR_CDADDR(pModule->m_MethodDefToDescMap.pTable);
1673 ModuleData->FieldDefToDescMap = PTR_CDADDR(pModule->m_FieldDefToDescMap.pTable);
1674 ModuleData->MemberRefToDescMap = NULL;
1675 ModuleData->FileReferencesMap = PTR_CDADDR(pModule->m_FileReferencesMap.pTable);
1676 ModuleData->ManifestModuleReferencesMap = PTR_CDADDR(pModule->m_ManifestModuleReferencesMap.pTable);
1677
1678 }
1679 EX_CATCH
1680 {
1681 }
1682 EX_END_CATCH(SwallowAllExceptions)
1683
1684 SOSDacLeave();
1685 return hr;
1686}
1687
1688HRESULT
1689ClrDataAccess::GetILForModule(CLRDATA_ADDRESS moduleAddr, DWORD rva, CLRDATA_ADDRESS *il)
1690{
1691 if (moduleAddr == 0 || il == NULL)
1692 return E_INVALIDARG;
1693
1694 SOSDacEnter();
1695
1696 Module* pModule = PTR_Module(TO_TADDR(moduleAddr));
1697 *il = (TADDR)(CLRDATA_ADDRESS)pModule->GetIL(rva);
1698
1699 SOSDacLeave();
1700 return hr;
1701}
1702
1703HRESULT
1704ClrDataAccess::GetMethodTableData(CLRDATA_ADDRESS mt, struct DacpMethodTableData *MTData)
1705{
1706 if (mt == 0 || MTData == NULL)
1707 return E_INVALIDARG;
1708
1709 SOSDacEnter();
1710
1711 MethodTable* pMT = PTR_MethodTable(TO_TADDR(mt));
1712 BOOL bIsFree = FALSE;
1713 if (!DacValidateMethodTable(pMT, bIsFree))
1714 {
1715 hr = E_INVALIDARG;
1716 }
1717 else
1718 {
1719 ZeroMemory(MTData,sizeof(DacpMethodTableData));
1720 MTData->BaseSize = pMT->GetBaseSize();
1721 if(pMT->IsString())
1722 MTData->BaseSize -= sizeof(WCHAR);
1723 MTData->ComponentSize = (DWORD)pMT->GetComponentSize();
1724 MTData->bIsFree = bIsFree;
1725 if(!bIsFree)
1726 {
1727 MTData->Module = HOST_CDADDR(pMT->GetModule());
1728 MTData->Class = HOST_CDADDR(pMT->GetClass());
1729 MTData->ParentMethodTable = HOST_CDADDR(pMT->GetParentMethodTable());;
1730 MTData->wNumInterfaces = pMT->GetNumInterfaces();
1731 MTData->wNumMethods = pMT->GetNumMethods();
1732 MTData->wNumVtableSlots = pMT->GetNumVtableSlots();
1733 MTData->wNumVirtuals = pMT->GetNumVirtuals();
1734 MTData->cl = pMT->GetCl();
1735 MTData->dwAttrClass = pMT->GetAttrClass();
1736 MTData->bContainsPointers = pMT->ContainsPointers();
1737 MTData->bIsShared = FALSE;
1738 MTData->bIsDynamic = pMT->IsDynamicStatics();
1739 }
1740 }
1741
1742 SOSDacLeave();
1743 return hr;
1744}
1745
1746HRESULT
1747ClrDataAccess::GetMethodTableName(CLRDATA_ADDRESS mt, unsigned int count, __out_z __inout_ecount(count) wchar_t *mtName, unsigned int *pNeeded)
1748{
1749 if (mt == 0)
1750 return E_INVALIDARG;
1751
1752 SOSDacEnter();
1753
1754 MethodTable *pMT = PTR_MethodTable(TO_TADDR(mt));
1755 BOOL free = FALSE;
1756
1757 if (mt == HOST_CDADDR(g_pFreeObjectMethodTable))
1758 {
1759 if (pNeeded)
1760 *pNeeded = 5;
1761
1762 if (mtName && count)
1763 wcsncpy_s(mtName, count, W("Free"), _TRUNCATE);
1764 }
1765 else if (!DacValidateMethodTable(pMT, free))
1766 {
1767 hr = E_INVALIDARG;
1768 }
1769 else
1770 {
1771 // There is a case where metadata was unloaded and the AppendType call will fail.
1772 // This is when an AppDomain has been unloaded but not yet collected.
1773 PEFile *pPEFile = pMT->GetModule()->GetFile();
1774 if (pPEFile->GetNativeImage() == NULL && pPEFile->GetILimage() == NULL)
1775 {
1776 if (pNeeded)
1777 *pNeeded = 16;
1778
1779 if (mtName)
1780 wcsncpy_s(mtName, count, W("<Unloaded Type>"), _TRUNCATE);
1781 }
1782 else
1783 {
1784 StackSString s;
1785#ifdef FEATURE_MINIMETADATA_IN_TRIAGEDUMPS
1786 EX_TRY
1787 {
1788#endif // FEATURE_MINIMETADATA_IN_TRIAGEDUMPS
1789
1790 TypeString::AppendType(s, TypeHandle(pMT), TypeString::FormatNamespace|TypeString::FormatFullInst);
1791
1792#ifdef FEATURE_MINIMETADATA_IN_TRIAGEDUMPS
1793 }
1794 EX_CATCH
1795 {
1796 if (!MdCacheGetEEName(dac_cast<TADDR>(pMT), s))
1797 {
1798 EX_RETHROW;
1799 }
1800 }
1801 EX_END_CATCH(SwallowAllExceptions)
1802#endif // FEATURE_MINIMETADATA_IN_TRIAGEDUMPS
1803
1804 if (s.IsEmpty())
1805 {
1806 hr = E_OUTOFMEMORY;
1807 }
1808 else
1809 {
1810 const wchar_t *val = s.GetUnicode();
1811
1812 if (pNeeded)
1813 *pNeeded = s.GetCount() + 1;
1814
1815 if (mtName && count)
1816 {
1817 wcsncpy_s(mtName, count, val, _TRUNCATE);
1818 mtName[count-1] = 0;
1819 }
1820 }
1821 }
1822 }
1823
1824 SOSDacLeave();
1825 return hr;
1826}
1827
1828HRESULT
1829ClrDataAccess::GetFieldDescData(CLRDATA_ADDRESS addr, struct DacpFieldDescData *FieldDescData)
1830{
1831 if (addr == 0 || FieldDescData == NULL)
1832 return E_INVALIDARG;
1833
1834 SOSDacEnter();
1835 FieldDesc* pFieldDesc = PTR_FieldDesc(TO_TADDR(addr));
1836 FieldDescData->Type = pFieldDesc->GetFieldType();
1837 FieldDescData->sigType = FieldDescData->Type;
1838
1839 EX_TRY
1840 {
1841 // minidump case, we do not have the field's type's type handle!
1842 // Strike should be able to form name based on the metadata token in
1843 // the field desc. Find type is using look up map which is huge. We cannot
1844 // drag in this data structure in minidump's case.
1845 //
1846 TypeHandle th = pFieldDesc->LookupFieldTypeHandle();
1847 MethodTable *pMt = th.GetMethodTable();
1848 if (pMt)
1849 {
1850 FieldDescData->MTOfType = HOST_CDADDR(th.GetMethodTable());
1851 }
1852 else
1853 {
1854 FieldDescData->MTOfType = NULL;
1855 }
1856 }
1857 EX_CATCH
1858 {
1859 FieldDescData->MTOfType = NULL;
1860 }
1861 EX_END_CATCH(SwallowAllExceptions)
1862
1863 // TODO: This is not currently useful, I need to get the module of the
1864 // type definition not that of the field description.
1865
1866 // TODO: Is there an easier way to get this information?
1867 // I'm getting the typeDef of a (possibly unloaded) type.
1868 MetaSig tSig(pFieldDesc);
1869 tSig.NextArg();
1870 SigPointer sp1 = tSig.GetArgProps();
1871 CorElementType et;
1872 hr = sp1.GetElemType(&et); // throw away the value, we just need to walk past.
1873
1874 if (SUCCEEDED(hr))
1875 {
1876 if (et == ELEMENT_TYPE_CLASS || et == ELEMENT_TYPE_VALUETYPE) // any other follows token?
1877 {
1878 hr = sp1.GetToken(&(FieldDescData->TokenOfType));
1879 }
1880 else
1881 {
1882 // There is no encoded token of field type
1883 FieldDescData->TokenOfType = mdTypeDefNil;
1884 if (FieldDescData->MTOfType == NULL)
1885 {
1886 // If there is no encoded token (that is, it is primitive type) and no MethodTable for it, remember the
1887 // element_type from signature
1888 //
1889 FieldDescData->sigType = et;
1890 }
1891 }
1892 }
1893
1894 FieldDescData->ModuleOfType = HOST_CDADDR(pFieldDesc->GetModule());
1895 FieldDescData->mb = pFieldDesc->GetMemberDef();
1896 FieldDescData->MTOfEnclosingClass = HOST_CDADDR(pFieldDesc->GetApproxEnclosingMethodTable());
1897 FieldDescData->dwOffset = pFieldDesc->GetOffset();
1898 FieldDescData->bIsThreadLocal = pFieldDesc->IsThreadStatic();
1899 FieldDescData->bIsContextLocal = FALSE;
1900 FieldDescData->bIsStatic = pFieldDesc->IsStatic();
1901 FieldDescData->NextField = HOST_CDADDR(PTR_FieldDesc(PTR_HOST_TO_TADDR(pFieldDesc) + sizeof(FieldDesc)));
1902
1903 SOSDacLeave();
1904 return hr;
1905}
1906
1907HRESULT
1908ClrDataAccess::GetMethodTableFieldData(CLRDATA_ADDRESS mt, struct DacpMethodTableFieldData *data)
1909{
1910 if (mt == 0 || data == NULL)
1911 return E_INVALIDARG;
1912
1913 SOSDacEnter();
1914
1915 MethodTable* pMT = PTR_MethodTable(TO_TADDR(mt));
1916 BOOL bIsFree = FALSE;
1917 if (!pMT || !DacValidateMethodTable(pMT, bIsFree))
1918 {
1919 hr = E_INVALIDARG;
1920 }
1921 else
1922 {
1923 data->wNumInstanceFields = pMT->GetNumInstanceFields();
1924 data->wNumStaticFields = pMT->GetNumStaticFields();
1925 data->wNumThreadStaticFields = pMT->GetNumThreadStaticFields();
1926
1927 data->FirstField = PTR_TO_TADDR(pMT->GetClass()->GetFieldDescList());
1928
1929 data->wContextStaticsSize = 0;
1930 data->wContextStaticOffset = 0;
1931 }
1932
1933 SOSDacLeave();
1934 return hr;
1935}
1936
1937HRESULT
1938ClrDataAccess::GetMethodTableCollectibleData(CLRDATA_ADDRESS mt, struct DacpMethodTableCollectibleData *data)
1939{
1940 if (mt == 0 || data == NULL)
1941 return E_INVALIDARG;
1942
1943 SOSDacEnter();
1944
1945 MethodTable* pMT = PTR_MethodTable(TO_TADDR(mt));
1946 BOOL bIsFree = FALSE;
1947 if (!pMT || !DacValidateMethodTable(pMT, bIsFree))
1948 {
1949 hr = E_INVALIDARG;
1950 }
1951 else
1952 {
1953 data->bCollectible = pMT->Collectible();
1954 if (data->bCollectible)
1955 {
1956 data->LoaderAllocatorObjectHandle = pMT->GetLoaderAllocatorObjectHandle();
1957 }
1958 }
1959
1960 SOSDacLeave();
1961 return hr;
1962}
1963
1964HRESULT
1965ClrDataAccess::GetMethodTableTransparencyData(CLRDATA_ADDRESS mt, struct DacpMethodTableTransparencyData *pTransparencyData)
1966{
1967 if (mt == 0 || pTransparencyData == NULL)
1968 return E_INVALIDARG;
1969
1970 SOSDacEnter();
1971
1972 MethodTable *pMT = PTR_MethodTable(TO_TADDR(mt));
1973 BOOL bIsFree = FALSE;
1974 if (!DacValidateMethodTable(pMT, bIsFree))
1975 {
1976 hr = E_INVALIDARG;
1977 }
1978 else
1979 {
1980 ZeroMemory(pTransparencyData, sizeof(DacpMethodTableTransparencyData));
1981 }
1982
1983 SOSDacLeave();
1984 return hr;
1985}
1986
1987HRESULT
1988ClrDataAccess::GetMethodTableForEEClass(CLRDATA_ADDRESS eeClass, CLRDATA_ADDRESS *value)
1989{
1990 if (eeClass == 0 || value == NULL)
1991 return E_INVALIDARG;
1992
1993 SOSDacEnter();
1994
1995 EEClass * pClass = PTR_EEClass(TO_TADDR(eeClass));
1996 if (!DacValidateEEClass(pClass))
1997 {
1998 hr = E_INVALIDARG;
1999 }
2000 else
2001 {
2002 *value = HOST_CDADDR(pClass->GetMethodTable());
2003 }
2004
2005 SOSDacLeave();
2006 return hr;
2007}
2008
2009HRESULT
2010ClrDataAccess::GetFrameName(CLRDATA_ADDRESS vtable, unsigned int count, __out_z __inout_ecount(count) wchar_t *frameName, unsigned int *pNeeded)
2011{
2012 if (vtable == 0)
2013 return E_INVALIDARG;
2014
2015 SOSDacEnter();
2016
2017 PWSTR pszName = DacGetVtNameW(CLRDATA_ADDRESS_TO_TADDR(vtable));
2018 if (pszName == NULL)
2019 {
2020 hr = E_INVALIDARG;
2021 }
2022 else
2023 {
2024 // Turn from bytes to wide characters
2025 unsigned int len = (unsigned int)wcslen(pszName);
2026
2027 if (frameName)
2028 {
2029 wcsncpy_s(frameName, count, pszName, _TRUNCATE);
2030
2031 if (pNeeded)
2032 {
2033 if (count < len)
2034 *pNeeded = count - 1;
2035 else
2036 *pNeeded = len;
2037 }
2038 }
2039 else if (pNeeded)
2040 {
2041 *pNeeded = len + 1;
2042 }
2043 }
2044
2045 SOSDacLeave();
2046 return hr;
2047}
2048
2049HRESULT
2050ClrDataAccess::GetPEFileName(CLRDATA_ADDRESS addr, unsigned int count, __out_z __inout_ecount(count) wchar_t *fileName, unsigned int *pNeeded)
2051{
2052 if (addr == 0 || (fileName == NULL && pNeeded == NULL) || (fileName != NULL && count == 0))
2053 return E_INVALIDARG;
2054
2055 SOSDacEnter();
2056 PEFile* pPEFile = PTR_PEFile(TO_TADDR(addr));
2057
2058 // Turn from bytes to wide characters
2059 if (!pPEFile->GetPath().IsEmpty())
2060 {
2061 if (!pPEFile->GetPath().DacGetUnicode(count, fileName, pNeeded))
2062 hr = E_FAIL;
2063 }
2064 else if (!pPEFile->IsDynamic())
2065 {
2066 PEAssembly *pAssembly = pPEFile->GetAssembly();
2067 StackSString displayName;
2068 pAssembly->GetDisplayName(displayName, 0);
2069
2070 if (displayName.IsEmpty())
2071 {
2072 if (fileName)
2073 fileName[0] = 0;
2074
2075 if (pNeeded)
2076 *pNeeded = 1;
2077 }
2078 else
2079 {
2080 unsigned int len = displayName.GetCount()+1;
2081
2082 if (fileName)
2083 {
2084 wcsncpy_s(fileName, count, displayName.GetUnicode(), _TRUNCATE);
2085
2086 if (count < len)
2087 len = count;
2088 }
2089
2090 if (pNeeded)
2091 *pNeeded = len;
2092 }
2093 }
2094 else
2095 {
2096 if (fileName && count)
2097 fileName[0] = 0;
2098
2099 if (pNeeded)
2100 *pNeeded = 1;
2101 }
2102
2103 SOSDacLeave();
2104 return hr;
2105}
2106
2107HRESULT
2108ClrDataAccess::GetPEFileBase(CLRDATA_ADDRESS addr, CLRDATA_ADDRESS *base)
2109{
2110 if (addr == 0 || base == NULL)
2111 return E_INVALIDARG;
2112
2113 SOSDacEnter();
2114
2115 PEFile* pPEFile = PTR_PEFile(TO_TADDR(addr));
2116
2117 // More fields later?
2118 if (pPEFile->HasNativeImage())
2119 *base = TO_CDADDR(PTR_TO_TADDR(pPEFile->GetLoadedNative()->GetBase()));
2120 else if (!pPEFile->IsDynamic())
2121 *base = TO_CDADDR(pPEFile->GetIJWBase());
2122 else
2123 *base = NULL;
2124
2125 SOSDacLeave();
2126 return hr;
2127}
2128
2129DWORD DACGetNumComponents(TADDR addr, ICorDebugDataTarget* target)
2130{
2131 // For an object pointer, this attempts to read the number of
2132 // array components.
2133 addr+=sizeof(size_t);
2134 ULONG32 returned = 0;
2135 DWORD Value = NULL;
2136 HRESULT hr = target->ReadVirtual(addr, (PBYTE)&Value, sizeof(DWORD), &returned);
2137
2138 if ((hr != S_OK) || (returned != sizeof(DWORD)))
2139 {
2140 return 0;
2141 }
2142 return Value;
2143}
2144
2145HRESULT
2146ClrDataAccess::GetObjectData(CLRDATA_ADDRESS addr, struct DacpObjectData *objectData)
2147{
2148 if (addr == 0 || objectData == NULL)
2149 return E_INVALIDARG;
2150
2151 SOSDacEnter();
2152
2153 ZeroMemory (objectData, sizeof(DacpObjectData));
2154 TADDR mtTADDR = DACGetMethodTableFromObjectPointer(CLRDATA_ADDRESS_TO_TADDR(addr),m_pTarget);
2155 if (mtTADDR==NULL)
2156 hr = E_INVALIDARG;
2157
2158 BOOL bFree = FALSE;
2159 MethodTable *mt = NULL;
2160 if (SUCCEEDED(hr))
2161 {
2162 mt = PTR_MethodTable(mtTADDR);
2163 if (!DacValidateMethodTable(mt, bFree))
2164 hr = E_INVALIDARG;
2165 }
2166
2167 if (SUCCEEDED(hr))
2168 {
2169 objectData->MethodTable = HOST_CDADDR(mt);
2170 objectData->Size = mt->GetBaseSize();
2171 if (mt->GetComponentSize())
2172 {
2173 objectData->Size += (DACGetNumComponents(CLRDATA_ADDRESS_TO_TADDR(addr),m_pTarget) * mt->GetComponentSize());
2174 objectData->dwComponentSize = mt->GetComponentSize();
2175 }
2176
2177 if (bFree)
2178 {
2179 objectData->ObjectType = OBJ_FREE;
2180 }
2181 else
2182 {
2183 if (objectData->MethodTable == HOST_CDADDR(g_pStringClass))
2184 {
2185 objectData->ObjectType = OBJ_STRING;
2186 }
2187 else if (objectData->MethodTable == HOST_CDADDR(g_pObjectClass))
2188 {
2189 objectData->ObjectType = OBJ_OBJECT;
2190 }
2191 else if (mt->IsArray())
2192 {
2193 objectData->ObjectType = OBJ_ARRAY;
2194
2195 // For now, go ahead and instantiate array classes.
2196 // TODO: avoid instantiating even object Arrays in the host.
2197 // NOTE: This code is carefully written to deal with MethodTable fields
2198 // in the array object having the mark bit set (because we may
2199 // be in mark phase when this function is called).
2200 ArrayBase *pArrayObj = PTR_ArrayBase(TO_TADDR(addr));
2201 objectData->ElementType = mt->GetArrayElementType();
2202
2203 TypeHandle thElem = mt->GetApproxArrayElementTypeHandle();
2204
2205 TypeHandle thCur = thElem;
2206 while (thCur.IsTypeDesc())
2207 thCur = thCur.AsArray()->GetArrayElementTypeHandle();
2208
2209 TADDR mtCurTADDR = thCur.AsTAddr();
2210 if (!DacValidateMethodTable(PTR_MethodTable(mtCurTADDR), bFree))
2211 {
2212 hr = E_INVALIDARG;
2213 }
2214 else
2215 {
2216 objectData->ElementTypeHandle = (CLRDATA_ADDRESS)(thElem.AsTAddr());
2217 objectData->dwRank = mt->GetRank();
2218 objectData->dwNumComponents = pArrayObj->GetNumComponents ();
2219 objectData->ArrayDataPtr = PTR_CDADDR(pArrayObj->GetDataPtr (TRUE));
2220 objectData->ArrayBoundsPtr = HOST_CDADDR(pArrayObj->GetBoundsPtr());
2221 objectData->ArrayLowerBoundsPtr = HOST_CDADDR(pArrayObj->GetLowerBoundsPtr());
2222 }
2223 }
2224 else
2225 {
2226 objectData->ObjectType = OBJ_OTHER;
2227 }
2228 }
2229 }
2230
2231#ifdef FEATURE_COMINTEROP
2232 if (SUCCEEDED(hr))
2233 {
2234 EX_TRY_ALLOW_DATATARGET_MISSING_MEMORY
2235 {
2236 PTR_SyncBlock pSyncBlk = DACGetSyncBlockFromObjectPointer(CLRDATA_ADDRESS_TO_TADDR(addr), m_pTarget);
2237 if (pSyncBlk != NULL)
2238 {
2239 // see if we have an RCW and/or CCW associated with this object
2240 PTR_InteropSyncBlockInfo pInfo = pSyncBlk->GetInteropInfoNoCreate();
2241 if (pInfo != NULL)
2242 {
2243 objectData->RCW = TO_CDADDR(pInfo->DacGetRawRCW());
2244 objectData->CCW = HOST_CDADDR(pInfo->GetCCW());
2245 }
2246 }
2247 }
2248 EX_END_CATCH_ALLOW_DATATARGET_MISSING_MEMORY;
2249 }
2250#endif // FEATURE_COMINTEROP
2251
2252 SOSDacLeave();
2253
2254 return hr;
2255}
2256
2257HRESULT ClrDataAccess::GetAppDomainList(unsigned int count, CLRDATA_ADDRESS values[], unsigned int *fetched)
2258{
2259 SOSDacEnter();
2260
2261 AppDomainIterator ai(FALSE);
2262 unsigned int i = 0;
2263 while (ai.Next() && (i < count))
2264 {
2265 if (values)
2266 values[i] = HOST_CDADDR(ai.GetDomain());
2267 i++;
2268 }
2269
2270 if (fetched)
2271 *fetched = i;
2272
2273 SOSDacLeave();
2274 return hr;
2275}
2276
2277HRESULT
2278ClrDataAccess::GetAppDomainStoreData(struct DacpAppDomainStoreData *adsData)
2279{
2280 SOSDacEnter();
2281
2282 adsData->systemDomain = HOST_CDADDR(SystemDomain::System());
2283 adsData->sharedDomain = NULL;
2284
2285 // Get an accurate count of appdomains.
2286 adsData->DomainCount = 0;
2287 AppDomainIterator ai(FALSE);
2288 while (ai.Next())
2289 adsData->DomainCount++;
2290
2291 SOSDacLeave();
2292 return hr;
2293}
2294
2295HRESULT
2296ClrDataAccess::GetAppDomainData(CLRDATA_ADDRESS addr, struct DacpAppDomainData *appdomainData)
2297{
2298 SOSDacEnter();
2299
2300 if (addr == 0)
2301 {
2302 hr = E_INVALIDARG;
2303 }
2304 else
2305 {
2306 PTR_BaseDomain pBaseDomain = PTR_BaseDomain(TO_TADDR(addr));
2307
2308 ZeroMemory(appdomainData, sizeof(DacpAppDomainData));
2309 appdomainData->AppDomainPtr = PTR_CDADDR(pBaseDomain);
2310 PTR_LoaderAllocator pLoaderAllocator = pBaseDomain->GetLoaderAllocator();
2311 appdomainData->pHighFrequencyHeap = HOST_CDADDR(pLoaderAllocator->GetHighFrequencyHeap());
2312 appdomainData->pLowFrequencyHeap = HOST_CDADDR(pLoaderAllocator->GetLowFrequencyHeap());
2313 appdomainData->pStubHeap = HOST_CDADDR(pLoaderAllocator->GetStubHeap());
2314 appdomainData->appDomainStage = STAGE_OPEN;
2315
2316 if (pBaseDomain->IsAppDomain())
2317 {
2318 AppDomain * pAppDomain = pBaseDomain->AsAppDomain();
2319 appdomainData->DomainLocalBlock = appdomainData->AppDomainPtr +
2320 offsetof(AppDomain, m_sDomainLocalBlock);
2321 appdomainData->pDomainLocalModules = PTR_CDADDR(pAppDomain->m_sDomainLocalBlock.m_pModuleSlots);
2322
2323 appdomainData->dwId = pAppDomain->GetId().m_dwId;
2324 appdomainData->appDomainStage = (DacpAppDomainDataStage)pAppDomain->m_Stage.Load();
2325 if (pAppDomain->IsActive())
2326 {
2327 // The assembly list is not valid in a closed appdomain.
2328 AppDomain::AssemblyIterator i = pAppDomain->IterateAssembliesEx((AssemblyIterationFlags)(
2329 kIncludeLoading | kIncludeLoaded | kIncludeExecution));
2330 CollectibleAssemblyHolder<DomainAssembly *> pDomainAssembly;
2331
2332 while (i.Next(pDomainAssembly.This()))
2333 {
2334 if (pDomainAssembly->IsLoaded())
2335 {
2336 appdomainData->AssemblyCount++;
2337 }
2338 }
2339
2340 AppDomain::FailedAssemblyIterator j = pAppDomain->IterateFailedAssembliesEx();
2341 while (j.Next())
2342 {
2343 appdomainData->FailedAssemblyCount++;
2344 }
2345 }
2346 }
2347 }
2348
2349 SOSDacLeave();
2350 return hr;
2351}
2352
2353HRESULT
2354ClrDataAccess::GetFailedAssemblyData(CLRDATA_ADDRESS assembly, unsigned int *pContext, HRESULT *pResult)
2355{
2356 if (assembly == NULL || (pContext == NULL && pResult == NULL))
2357 {
2358 return E_INVALIDARG;
2359 }
2360
2361 SOSDacEnter();
2362
2363 FailedAssembly* pAssembly = PTR_FailedAssembly(TO_TADDR(assembly));
2364 if (!pAssembly)
2365 {
2366 hr = E_INVALIDARG;
2367 }
2368 else
2369 {
2370 if (pResult)
2371 *pResult = pAssembly->error;
2372 }
2373
2374 SOSDacLeave();
2375 return hr;
2376}
2377
2378HRESULT
2379ClrDataAccess::GetFailedAssemblyLocation(CLRDATA_ADDRESS assembly, unsigned int count,
2380 __out_z __inout_ecount(count) wchar_t *location, unsigned int *pNeeded)
2381{
2382 if (assembly == NULL || (location == NULL && pNeeded == NULL) || (location != NULL && count == 0))
2383 return E_INVALIDARG;
2384
2385 SOSDacEnter();
2386 FailedAssembly* pAssembly = PTR_FailedAssembly(TO_TADDR(assembly));
2387
2388 // Turn from bytes to wide characters
2389 if (!pAssembly->location.IsEmpty())
2390 {
2391 if (!pAssembly->location.DacGetUnicode(count, location, pNeeded))
2392 {
2393 hr = E_FAIL;
2394 }
2395 }
2396 else
2397 {
2398 if (pNeeded)
2399 *pNeeded = 1;
2400
2401 if (location)
2402 location[0] = 0;
2403 }
2404
2405 SOSDacLeave();
2406 return hr;
2407}
2408
2409HRESULT
2410ClrDataAccess::GetFailedAssemblyDisplayName(CLRDATA_ADDRESS assembly, unsigned int count, __out_z __inout_ecount(count) wchar_t *name, unsigned int *pNeeded)
2411{
2412 if (assembly == NULL || (name == NULL && pNeeded == NULL) || (name != NULL && count == 0))
2413 return E_INVALIDARG;
2414
2415 SOSDacEnter();
2416 FailedAssembly* pAssembly = PTR_FailedAssembly(TO_TADDR(assembly));
2417
2418 if (!pAssembly->displayName.IsEmpty())
2419 {
2420 if (!pAssembly->displayName.DacGetUnicode(count, name, pNeeded))
2421 {
2422 hr = E_FAIL;
2423 }
2424 }
2425 else
2426 {
2427 if (pNeeded)
2428 *pNeeded = 1;
2429
2430 if (name)
2431 name[0] = 0;
2432 }
2433
2434 SOSDacLeave();
2435 return hr;
2436}
2437
2438
2439HRESULT
2440ClrDataAccess::GetAssemblyList(CLRDATA_ADDRESS addr, int count, CLRDATA_ADDRESS values[], int *pNeeded)
2441{
2442 if (addr == NULL)
2443 return E_INVALIDARG;
2444
2445 SOSDacEnter();
2446
2447 BaseDomain* pBaseDomain = PTR_BaseDomain(TO_TADDR(addr));
2448
2449 int n=0;
2450 if (pBaseDomain->IsAppDomain())
2451 {
2452 AppDomain::AssemblyIterator i = pBaseDomain->AsAppDomain()->IterateAssembliesEx(
2453 (AssemblyIterationFlags)(kIncludeLoading | kIncludeLoaded | kIncludeExecution));
2454 CollectibleAssemblyHolder<DomainAssembly *> pDomainAssembly;
2455
2456 if (values)
2457 {
2458 while (i.Next(pDomainAssembly.This()) && (n < count))
2459 {
2460 if (pDomainAssembly->IsLoaded())
2461 {
2462 CollectibleAssemblyHolder<Assembly *> pAssembly = pDomainAssembly->GetAssembly();
2463 // Note: DAC doesn't need to keep the assembly alive - see code:CollectibleAssemblyHolder#CAH_DAC
2464 values[n++] = HOST_CDADDR(pAssembly.Extract());
2465 }
2466 }
2467 }
2468 else
2469 {
2470 while (i.Next(pDomainAssembly.This()))
2471 if (pDomainAssembly->IsLoaded())
2472 n++;
2473 }
2474
2475 if (pNeeded)
2476 *pNeeded = n;
2477 }
2478 else
2479 {
2480 // The only other type of BaseDomain is the SystemDomain, and we shouldn't be asking
2481 // for the assemblies in it.
2482 _ASSERTE(false);
2483 hr = E_INVALIDARG;
2484 }
2485
2486 SOSDacLeave();
2487 return hr;
2488}
2489
2490HRESULT
2491ClrDataAccess::GetFailedAssemblyList(CLRDATA_ADDRESS appDomain, int count,
2492 CLRDATA_ADDRESS values[], unsigned int *pNeeded)
2493{
2494 if ((appDomain == NULL) || (values == NULL && pNeeded == NULL))
2495 {
2496 return E_INVALIDARG;
2497 }
2498
2499 SOSDacEnter();
2500 AppDomain* pAppDomain = PTR_AppDomain(TO_TADDR(appDomain));
2501
2502 int n=0;
2503 AppDomain::FailedAssemblyIterator i = pAppDomain->IterateFailedAssembliesEx();
2504 while (i.Next() && n<=count)
2505 {
2506 if (values)
2507 values[n] = HOST_CDADDR(i.GetFailedAssembly());
2508
2509 n++;
2510 }
2511
2512 if (pNeeded)
2513 *pNeeded = n;
2514
2515 SOSDacLeave();
2516 return hr;
2517}
2518
2519HRESULT
2520ClrDataAccess::GetAppDomainName(CLRDATA_ADDRESS addr, unsigned int count, __out_z __inout_ecount(count) wchar_t *name, unsigned int *pNeeded)
2521{
2522 SOSDacEnter();
2523
2524 PTR_BaseDomain pBaseDomain = PTR_BaseDomain(TO_TADDR(addr));
2525 if (!pBaseDomain->IsAppDomain())
2526 {
2527 // Shared domain and SystemDomain don't have this field.
2528 if (pNeeded)
2529 *pNeeded = 1;
2530 if (name)
2531 name[0] = 0;
2532 }
2533 else
2534 {
2535 AppDomain* pAppDomain = pBaseDomain->AsAppDomain();
2536
2537 if (!pAppDomain->m_friendlyName.IsEmpty())
2538 {
2539 if (!pAppDomain->m_friendlyName.DacGetUnicode(count, name, pNeeded))
2540 {
2541 hr = E_FAIL;
2542 }
2543 }
2544 else
2545 {
2546 if (pNeeded)
2547 *pNeeded = 1;
2548 if (name)
2549 name[0] = 0;
2550
2551 hr = S_OK;
2552 }
2553 }
2554
2555 SOSDacLeave();
2556 return hr;
2557}
2558
2559HRESULT
2560ClrDataAccess::GetApplicationBase(CLRDATA_ADDRESS appDomain, int count,
2561 __out_z __inout_ecount(count) wchar_t *base, unsigned int *pNeeded)
2562{
2563 // Method is not supported on CoreCLR
2564
2565 return E_FAIL;
2566}
2567
2568HRESULT
2569ClrDataAccess::GetPrivateBinPaths(CLRDATA_ADDRESS appDomain, int count,
2570 __out_z __inout_ecount(count) wchar_t *paths, unsigned int *pNeeded)
2571{
2572 // Method is not supported on CoreCLR
2573
2574 return E_FAIL;
2575}
2576
2577HRESULT
2578ClrDataAccess::GetAppDomainConfigFile(CLRDATA_ADDRESS appDomain, int count,
2579 __out_z __inout_ecount(count) wchar_t *configFile, unsigned int *pNeeded)
2580{
2581 // Method is not supported on CoreCLR
2582
2583 return E_FAIL;
2584}
2585
2586HRESULT
2587ClrDataAccess::GetAssemblyData(CLRDATA_ADDRESS cdBaseDomainPtr, CLRDATA_ADDRESS assembly, struct DacpAssemblyData *assemblyData)
2588{
2589 if (assembly == NULL && cdBaseDomainPtr == NULL)
2590 {
2591 return E_INVALIDARG;
2592 }
2593
2594 SOSDacEnter();
2595
2596 Assembly* pAssembly = PTR_Assembly(TO_TADDR(assembly));
2597
2598 // Make sure conditionally-assigned fields like AssemblySecDesc, LoadContext, etc. are zeroed
2599 ZeroMemory(assemblyData, sizeof(DacpAssemblyData));
2600
2601 // If the specified BaseDomain is an AppDomain, get a pointer to it
2602 AppDomain * pDomain = NULL;
2603 if (cdBaseDomainPtr != NULL)
2604 {
2605 assemblyData->BaseDomainPtr = cdBaseDomainPtr;
2606 PTR_BaseDomain baseDomain = PTR_BaseDomain(TO_TADDR(cdBaseDomainPtr));
2607 if( baseDomain->IsAppDomain() )
2608 pDomain = baseDomain->AsAppDomain();
2609 }
2610
2611 assemblyData->AssemblyPtr = HOST_CDADDR(pAssembly);
2612 assemblyData->ClassLoader = HOST_CDADDR(pAssembly->GetLoader());
2613 assemblyData->ParentDomain = HOST_CDADDR(pAssembly->GetDomain());
2614 assemblyData->isDynamic = pAssembly->IsDynamic();
2615 assemblyData->ModuleCount = 0;
2616 assemblyData->isDomainNeutral = FALSE;
2617
2618 pAssembly->GetManifestFile();
2619
2620 ModuleIterator mi = pAssembly->IterateModules();
2621 while (mi.Next())
2622 {
2623 assemblyData->ModuleCount++;
2624 }
2625
2626 SOSDacLeave();
2627 return hr;
2628}
2629
2630HRESULT
2631ClrDataAccess::GetAssemblyName(CLRDATA_ADDRESS assembly, unsigned int count, __out_z __inout_ecount(count) wchar_t *name, unsigned int *pNeeded)
2632{
2633 SOSDacEnter();
2634 Assembly* pAssembly = PTR_Assembly(TO_TADDR(assembly));
2635
2636 if (name)
2637 name[0] = 0;
2638
2639 if (!pAssembly->GetManifestFile()->GetPath().IsEmpty())
2640 {
2641 if (!pAssembly->GetManifestFile()->GetPath().DacGetUnicode(count, name, pNeeded))
2642 hr = E_FAIL;
2643 else if (name)
2644 name[count-1] = 0;
2645 }
2646 else if (!pAssembly->GetManifestFile()->IsDynamic())
2647 {
2648 StackSString displayName;
2649 pAssembly->GetManifestFile()->GetDisplayName(displayName, 0);
2650
2651 const wchar_t *val = displayName.GetUnicode();
2652
2653 if (pNeeded)
2654 *pNeeded = displayName.GetCount() + 1;
2655
2656 if (name && count)
2657 {
2658 wcsncpy_s(name, count, val, _TRUNCATE);
2659 name[count-1] = 0;
2660 }
2661 }
2662 else
2663 {
2664 hr = E_FAIL;
2665 }
2666
2667 SOSDacLeave();
2668 return hr;
2669}
2670
2671HRESULT
2672ClrDataAccess::GetAssemblyLocation(CLRDATA_ADDRESS assembly, int count, __out_z __inout_ecount(count) wchar_t *location, unsigned int *pNeeded)
2673{
2674 if ((assembly == NULL) || (location == NULL && pNeeded == NULL) || (location != NULL && count == 0))
2675 {
2676 return E_INVALIDARG;
2677 }
2678
2679 SOSDacEnter();
2680
2681 Assembly* pAssembly = PTR_Assembly(TO_TADDR(assembly));
2682
2683 // Turn from bytes to wide characters
2684 if (!pAssembly->GetManifestFile()->GetPath().IsEmpty())
2685 {
2686 if (!pAssembly->GetManifestFile()->GetPath().
2687 DacGetUnicode(count, location, pNeeded))
2688 {
2689 hr = E_FAIL;
2690 }
2691 }
2692 else
2693 {
2694 if (location)
2695 location[0] = 0;
2696
2697 if (pNeeded)
2698 *pNeeded = 1;
2699 }
2700
2701 SOSDacLeave();
2702 return hr;
2703}
2704
2705HRESULT
2706ClrDataAccess::GetAssemblyModuleList(CLRDATA_ADDRESS assembly, unsigned int count, CLRDATA_ADDRESS modules[], unsigned int *pNeeded)
2707{
2708 if (assembly == 0)
2709 return E_INVALIDARG;
2710
2711 SOSDacEnter();
2712
2713 Assembly* pAssembly = PTR_Assembly(TO_TADDR(assembly));
2714 ModuleIterator mi = pAssembly->IterateModules();
2715 unsigned int n = 0;
2716 if (modules)
2717 {
2718 while (mi.Next() && n < count)
2719 modules[n++] = HOST_CDADDR(mi.GetModule());
2720 }
2721 else
2722 {
2723 while (mi.Next())
2724 n++;
2725 }
2726
2727 if (pNeeded)
2728 *pNeeded = n;
2729
2730 SOSDacLeave();
2731 return hr;
2732}
2733
2734HRESULT
2735ClrDataAccess::GetGCHeapDetails(CLRDATA_ADDRESS heap, struct DacpGcHeapDetails *details)
2736{
2737 if (heap == 0 || details == NULL)
2738 return E_INVALIDARG;
2739
2740 SOSDacEnter();
2741
2742 // doesn't make sense to call this on WKS mode
2743 if (!GCHeapUtilities::IsServerHeap())
2744 hr = E_INVALIDARG;
2745 else
2746#ifdef FEATURE_SVR_GC
2747 hr = ServerGCHeapDetails(heap, details);
2748#else
2749 hr = E_NOTIMPL;
2750#endif
2751
2752 SOSDacLeave();
2753 return hr;
2754}
2755
2756HRESULT
2757ClrDataAccess::GetGCHeapStaticData(struct DacpGcHeapDetails *detailsData)
2758{
2759 if (detailsData == NULL)
2760 return E_INVALIDARG;
2761
2762 SOSDacEnter();
2763
2764 detailsData->lowest_address = PTR_CDADDR(g_lowest_address);
2765 detailsData->highest_address = PTR_CDADDR(g_highest_address);
2766 detailsData->card_table = PTR_CDADDR(g_card_table);
2767 detailsData->heapAddr = NULL;
2768 detailsData->alloc_allocated = (CLRDATA_ADDRESS)*g_gcDacGlobals->alloc_allocated;
2769 detailsData->ephemeral_heap_segment = (CLRDATA_ADDRESS)*g_gcDacGlobals->ephemeral_heap_segment;
2770 detailsData->mark_array = (CLRDATA_ADDRESS)*g_gcDacGlobals->mark_array;
2771 detailsData->current_c_gc_state = (CLRDATA_ADDRESS)*g_gcDacGlobals->current_c_gc_state;
2772 detailsData->next_sweep_obj = (CLRDATA_ADDRESS)*g_gcDacGlobals->next_sweep_obj;
2773 detailsData->saved_sweep_ephemeral_seg = (CLRDATA_ADDRESS)*g_gcDacGlobals->saved_sweep_ephemeral_seg;
2774 detailsData->saved_sweep_ephemeral_start = (CLRDATA_ADDRESS)*g_gcDacGlobals->saved_sweep_ephemeral_start;
2775 detailsData->background_saved_lowest_address = (CLRDATA_ADDRESS)*g_gcDacGlobals->background_saved_lowest_address;
2776 detailsData->background_saved_highest_address = (CLRDATA_ADDRESS)*g_gcDacGlobals->background_saved_highest_address;
2777
2778 for (unsigned int i=0; i < *g_gcDacGlobals->max_gen + 2; i++)
2779 {
2780 DPTR(dac_generation) generation = GenerationTableIndex(g_gcDacGlobals->generation_table, i);
2781 detailsData->generation_table[i].start_segment = (CLRDATA_ADDRESS) dac_cast<TADDR>(generation->start_segment);
2782
2783 detailsData->generation_table[i].allocation_start = (CLRDATA_ADDRESS) generation->allocation_start;
2784
2785 DPTR(gc_alloc_context) alloc_context = dac_cast<TADDR>(generation) + offsetof(dac_generation, allocation_context);
2786 detailsData->generation_table[i].allocContextPtr = (CLRDATA_ADDRESS)alloc_context->alloc_ptr;
2787 detailsData->generation_table[i].allocContextLimit = (CLRDATA_ADDRESS)alloc_context->alloc_limit;
2788 }
2789
2790 if (g_gcDacGlobals->finalize_queue.IsValid())
2791 {
2792 DPTR(dac_finalize_queue) fq = Dereference(g_gcDacGlobals->finalize_queue);
2793 DPTR(uint8_t*) fillPointersTable = dac_cast<TADDR>(fq) + offsetof(dac_finalize_queue, m_FillPointers);
2794 for (unsigned int i = 0; i<(*g_gcDacGlobals->max_gen + 2 + dac_finalize_queue::ExtraSegCount); i++)
2795 {
2796 detailsData->finalization_fill_pointers[i] = (CLRDATA_ADDRESS)*TableIndex(fillPointersTable, i, sizeof(uint8_t*));
2797 }
2798 }
2799
2800 SOSDacLeave();
2801 return hr;
2802}
2803
2804HRESULT
2805ClrDataAccess::GetHeapSegmentData(CLRDATA_ADDRESS seg, struct DacpHeapSegmentData *heapSegment)
2806{
2807 if (seg == 0 || heapSegment == NULL)
2808 return E_INVALIDARG;
2809
2810 SOSDacEnter();
2811
2812 if (GCHeapUtilities::IsServerHeap())
2813 {
2814#if !defined(FEATURE_SVR_GC)
2815 _ASSERTE(0);
2816#else // !defined(FEATURE_SVR_GC)
2817 hr = GetServerHeapData(seg, heapSegment);
2818#endif //!defined(FEATURE_SVR_GC)
2819 }
2820 else
2821 {
2822 dac_heap_segment *pSegment = __DPtr<dac_heap_segment>(TO_TADDR(seg));
2823 if (!pSegment)
2824 {
2825 hr = E_INVALIDARG;
2826 }
2827 else
2828 {
2829 heapSegment->segmentAddr = seg;
2830 heapSegment->allocated = (CLRDATA_ADDRESS)(ULONG_PTR) pSegment->allocated;
2831 heapSegment->committed = (CLRDATA_ADDRESS)(ULONG_PTR) pSegment->committed;
2832 heapSegment->reserved = (CLRDATA_ADDRESS)(ULONG_PTR) pSegment->reserved;
2833 heapSegment->used = (CLRDATA_ADDRESS)(ULONG_PTR) pSegment->used;
2834 heapSegment->mem = (CLRDATA_ADDRESS)(ULONG_PTR) pSegment->mem;
2835 heapSegment->next = (CLRDATA_ADDRESS)dac_cast<TADDR>(pSegment->next);
2836 heapSegment->flags = pSegment->flags;
2837 heapSegment->gc_heap = NULL;
2838 heapSegment->background_allocated = (CLRDATA_ADDRESS)(ULONG_PTR)pSegment->background_allocated;
2839 }
2840 }
2841
2842 SOSDacLeave();
2843 return hr;
2844}
2845
2846HRESULT
2847ClrDataAccess::GetGCHeapList(unsigned int count, CLRDATA_ADDRESS heaps[], unsigned int *pNeeded)
2848{
2849 SOSDacEnter();
2850
2851 // make sure we called this in appropriate circumstances (i.e., we have multiple heaps)
2852 if (GCHeapUtilities::IsServerHeap())
2853 {
2854#if !defined(FEATURE_SVR_GC)
2855 _ASSERTE(0);
2856#else // !defined(FEATURE_SVR_GC)
2857 int heapCount = GCHeapCount();
2858 if (pNeeded)
2859 *pNeeded = heapCount;
2860
2861 if (heaps)
2862 {
2863 // get the heap locations
2864 if (count == heapCount)
2865 hr = GetServerHeaps(heaps, m_pTarget);
2866 else
2867 hr = E_INVALIDARG;
2868 }
2869#endif // !defined(FEATURE_SVR_GC)
2870 }
2871 else
2872 {
2873 hr = E_FAIL; // doesn't make sense to call this on WKS mode
2874 }
2875
2876 SOSDacLeave();
2877 return hr;
2878}
2879
2880HRESULT
2881ClrDataAccess::GetGCHeapData(struct DacpGcHeapData *gcheapData)
2882{
2883 if (gcheapData == NULL)
2884 return E_INVALIDARG;
2885
2886 SOSDacEnter();
2887
2888 // we need to check and see if g_heap_type
2889 // is GC_HEAP_INVALID, in which case we fail.
2890 ULONG32 gcHeapValue = g_heap_type;
2891
2892 // GC_HEAP_TYPE has three possible values:
2893 // GC_HEAP_INVALID = 0,
2894 // GC_HEAP_WKS = 1,
2895 // GC_HEAP_SVR = 2
2896 // If we get something other than that, we probably read the wrong location.
2897 _ASSERTE(gcHeapValue >= GC_HEAP_INVALID && gcHeapValue <= GC_HEAP_SVR);
2898
2899 // we have GC_HEAP_INVALID if gcHeapValue == 0, so we're done - we haven't
2900 // initialized the heap yet.
2901 if (gcHeapValue == GC_HEAP_INVALID)
2902 {
2903 hr = E_FAIL;
2904 goto cleanup;
2905 }
2906
2907 // Now we can get other important information about the heap
2908 // We can use GCHeapUtilities::IsServerHeap here because we have already validated
2909 // that the heap is in a valid state. We couldn't use it above, because IsServerHeap
2910 // asserts if the heap type is GC_HEAP_INVALID.
2911 gcheapData->g_max_generation = *g_gcDacGlobals->max_gen;
2912 gcheapData->bServerMode = GCHeapUtilities::IsServerHeap();
2913 gcheapData->bGcStructuresValid = *g_gcDacGlobals->gc_structures_invalid_cnt == 0;
2914
2915 if (GCHeapUtilities::IsServerHeap())
2916 {
2917#if !defined (FEATURE_SVR_GC)
2918 _ASSERTE(0);
2919 gcheapData->HeapCount = 1;
2920#else // !defined (FEATURE_SVR_GC)
2921 gcheapData->HeapCount = GCHeapCount();
2922#endif // !defined (FEATURE_SVR_GC)
2923 }
2924 else
2925 {
2926 gcheapData->HeapCount = 1;
2927 }
2928
2929cleanup:
2930 ;
2931
2932 SOSDacLeave();
2933 return hr;
2934}
2935
2936HRESULT
2937ClrDataAccess::GetOOMStaticData(struct DacpOomData *oomData)
2938{
2939 if (oomData == NULL)
2940 return E_INVALIDARG;
2941
2942 SOSDacEnter();
2943
2944 memset(oomData, 0, sizeof(DacpOomData));
2945
2946 if (!GCHeapUtilities::IsServerHeap())
2947 {
2948 oom_history* pOOMInfo = g_gcDacGlobals->oom_info;
2949 oomData->reason = pOOMInfo->reason;
2950 oomData->alloc_size = pOOMInfo->alloc_size;
2951 oomData->available_pagefile_mb = pOOMInfo->available_pagefile_mb;
2952 oomData->gc_index = pOOMInfo->gc_index;
2953 oomData->fgm = pOOMInfo->fgm;
2954 oomData->size = pOOMInfo->size;
2955 oomData->loh_p = pOOMInfo->loh_p;
2956 }
2957 else
2958 {
2959 hr = E_FAIL;
2960 }
2961
2962 SOSDacLeave();
2963 return hr;
2964}
2965
2966HRESULT
2967ClrDataAccess::GetOOMData(CLRDATA_ADDRESS oomAddr, struct DacpOomData *data)
2968{
2969 if (oomAddr == 0 || data == NULL)
2970 return E_INVALIDARG;
2971
2972 SOSDacEnter();
2973 memset(data, 0, sizeof(DacpOomData));
2974
2975 if (!GCHeapUtilities::IsServerHeap())
2976 hr = E_FAIL; // doesn't make sense to call this on WKS mode
2977
2978#ifdef FEATURE_SVR_GC
2979 else
2980 hr = ServerOomData(oomAddr, data);
2981#else
2982 _ASSERTE_MSG(false, "IsServerHeap returned true but FEATURE_SVR_GC not defined");
2983 hr = E_NOTIMPL;
2984#endif //FEATURE_SVR_GC
2985
2986 SOSDacLeave();
2987 return hr;
2988}
2989
2990HRESULT
2991ClrDataAccess::GetGCGlobalMechanisms(size_t* globalMechanisms)
2992{
2993#ifdef GC_CONFIG_DRIVEN
2994 if (globalMechanisms == NULL)
2995 return E_INVALIDARG;
2996
2997 SOSDacEnter();
2998 memset(globalMechanisms, 0, (sizeof(size_t) * MAX_GLOBAL_GC_MECHANISMS_COUNT));
2999
3000 for (int i = 0; i < MAX_GLOBAL_GC_MECHANISMS_COUNT; i++)
3001 {
3002 globalMechanisms[i] = g_gcDacGlobals->gc_global_mechanisms[i];
3003 }
3004
3005 SOSDacLeave();
3006 return hr;
3007#else
3008 return E_NOTIMPL;
3009#endif //GC_CONFIG_DRIVEN
3010}
3011
3012HRESULT
3013ClrDataAccess::GetGCInterestingInfoStaticData(struct DacpGCInterestingInfoData *data)
3014{
3015#ifdef GC_CONFIG_DRIVEN
3016 if (data == NULL)
3017 return E_INVALIDARG;
3018
3019 static_assert_no_msg(DAC_NUMBERGENERATIONS == NUMBERGENERATIONS);
3020 static_assert_no_msg(DAC_NUM_GC_DATA_POINTS == NUM_GC_DATA_POINTS);
3021 static_assert_no_msg(DAC_MAX_COMPACT_REASONS_COUNT == MAX_COMPACT_REASONS_COUNT);
3022 static_assert_no_msg(DAC_MAX_EXPAND_MECHANISMS_COUNT == MAX_EXPAND_MECHANISMS_COUNT);
3023 static_assert_no_msg(DAC_MAX_GC_MECHANISM_BITS_COUNT == MAX_GC_MECHANISM_BITS_COUNT);
3024
3025 SOSDacEnter();
3026 memset(data, 0, sizeof(DacpGCInterestingInfoData));
3027
3028 if (g_heap_type != GC_HEAP_SVR)
3029 {
3030 for (int i = 0; i < NUM_GC_DATA_POINTS; i++)
3031 data->interestingDataPoints[i] = g_gcDacGlobals->interesting_data_per_heap[i];
3032 for (int i = 0; i < MAX_COMPACT_REASONS_COUNT; i++)
3033 data->compactReasons[i] = g_gcDacGlobals->compact_reasons_per_heap[i];
3034 for (int i = 0; i < MAX_EXPAND_MECHANISMS_COUNT; i++)
3035 data->expandMechanisms[i] = g_gcDacGlobals->expand_mechanisms_per_heap[i];
3036 for (int i = 0; i < MAX_GC_MECHANISM_BITS_COUNT; i++)
3037 data->bitMechanisms[i] = g_gcDacGlobals->interesting_mechanism_bits_per_heap[i];
3038 }
3039 else
3040 {
3041 hr = E_FAIL;
3042 }
3043
3044 SOSDacLeave();
3045 return hr;
3046#else
3047 return E_NOTIMPL;
3048#endif //GC_CONFIG_DRIVEN
3049}
3050
3051HRESULT
3052ClrDataAccess::GetGCInterestingInfoData(CLRDATA_ADDRESS interestingInfoAddr, struct DacpGCInterestingInfoData *data)
3053{
3054#ifdef GC_CONFIG_DRIVEN
3055 if (interestingInfoAddr == 0 || data == NULL)
3056 return E_INVALIDARG;
3057
3058 SOSDacEnter();
3059 memset(data, 0, sizeof(DacpGCInterestingInfoData));
3060
3061 if (!GCHeapUtilities::IsServerHeap())
3062 hr = E_FAIL; // doesn't make sense to call this on WKS mode
3063
3064#ifdef FEATURE_SVR_GC
3065 else
3066 hr = ServerGCInterestingInfoData(interestingInfoAddr, data);
3067#else
3068 _ASSERTE_MSG(false, "IsServerHeap returned true but FEATURE_SVR_GC not defined");
3069 hr = E_NOTIMPL;
3070#endif //FEATURE_SVR_GC
3071
3072 SOSDacLeave();
3073 return hr;
3074#else
3075 return E_NOTIMPL;
3076#endif //GC_CONFIG_DRIVEN
3077}
3078
3079HRESULT
3080ClrDataAccess::GetHeapAnalyzeData(CLRDATA_ADDRESS addr, struct DacpGcHeapAnalyzeData *data)
3081{
3082 if (addr == 0 || data == NULL)
3083 return E_INVALIDARG;
3084
3085 SOSDacEnter();
3086
3087 if (!GCHeapUtilities::IsServerHeap())
3088 hr = E_FAIL; // doesn't make sense to call this on WKS mode
3089
3090#ifdef FEATURE_SVR_GC
3091 else
3092 hr = ServerGCHeapAnalyzeData(addr, data);
3093#else
3094 _ASSERTE_MSG(false, "IsServerHeap returned true but FEATURE_SVR_GC not defined");
3095 hr = E_NOTIMPL;
3096#endif //FEATURE_SVR_GC
3097
3098 SOSDacLeave();
3099 return hr;
3100}
3101
3102HRESULT
3103ClrDataAccess::GetHeapAnalyzeStaticData(struct DacpGcHeapAnalyzeData *analyzeData)
3104{
3105 if (analyzeData == NULL)
3106 return E_INVALIDARG;
3107
3108 SOSDacEnter();
3109
3110 analyzeData->internal_root_array = dac_cast<TADDR>(g_gcDacGlobals->internal_root_array);
3111 analyzeData->internal_root_array_index = *g_gcDacGlobals->internal_root_array_index;
3112 analyzeData->heap_analyze_success = *g_gcDacGlobals->heap_analyze_success;
3113
3114 SOSDacLeave();
3115 return hr;
3116}
3117
3118HRESULT
3119ClrDataAccess::GetUsefulGlobals(struct DacpUsefulGlobalsData *globalsData)
3120{
3121 if (globalsData == NULL)
3122 return E_INVALIDARG;
3123
3124 SOSDacEnter();
3125
3126 PTR_ArrayTypeDesc objArray = g_pPredefinedArrayTypes[ELEMENT_TYPE_OBJECT];
3127 if (objArray)
3128 globalsData->ArrayMethodTable = HOST_CDADDR(objArray->GetMethodTable());
3129 else
3130 globalsData->ArrayMethodTable = 0;
3131
3132 globalsData->StringMethodTable = HOST_CDADDR(g_pStringClass);
3133 globalsData->ObjectMethodTable = HOST_CDADDR(g_pObjectClass);
3134 globalsData->ExceptionMethodTable = HOST_CDADDR(g_pExceptionClass);
3135 globalsData->FreeMethodTable = HOST_CDADDR(g_pFreeObjectMethodTable);
3136
3137 SOSDacLeave();
3138 return hr;
3139}
3140
3141
3142HRESULT
3143ClrDataAccess::GetNestedExceptionData(CLRDATA_ADDRESS exception, CLRDATA_ADDRESS *exceptionObject, CLRDATA_ADDRESS *nextNestedException)
3144{
3145 if (exception == 0 || exceptionObject == NULL || nextNestedException == NULL)
3146 return E_INVALIDARG;
3147
3148 SOSDacEnter();
3149
3150#ifdef WIN64EXCEPTIONS
3151 ExceptionTracker *pExData = PTR_ExceptionTracker(TO_TADDR(exception));
3152#else
3153 ExInfo *pExData = PTR_ExInfo(TO_TADDR(exception));
3154#endif // _WIN64
3155
3156 if (!pExData)
3157 {
3158 hr = E_INVALIDARG;
3159 }
3160 else
3161 {
3162 *exceptionObject = TO_CDADDR(*PTR_TADDR(pExData->m_hThrowable));
3163 *nextNestedException = PTR_HOST_TO_TADDR(pExData->m_pPrevNestedInfo);
3164 }
3165
3166 SOSDacLeave();
3167 return hr;
3168}
3169
3170
3171HRESULT
3172ClrDataAccess::GetDomainLocalModuleData(CLRDATA_ADDRESS addr, struct DacpDomainLocalModuleData *pLocalModuleData)
3173{
3174 if (addr == 0 || pLocalModuleData == NULL)
3175 return E_INVALIDARG;
3176
3177 SOSDacEnter();
3178
3179 DomainLocalModule* pLocalModule = PTR_DomainLocalModule(TO_TADDR(addr));
3180
3181 pLocalModuleData->pGCStaticDataStart = TO_CDADDR(PTR_TO_TADDR(pLocalModule->GetPrecomputedGCStaticsBasePointer()));
3182 pLocalModuleData->pNonGCStaticDataStart = TO_CDADDR(pLocalModule->GetPrecomputedNonGCStaticsBasePointer());
3183 pLocalModuleData->pDynamicClassTable = PTR_CDADDR(pLocalModule->m_pDynamicClassTable.Load());
3184 pLocalModuleData->pClassData = (TADDR) (PTR_HOST_MEMBER_TADDR(DomainLocalModule, pLocalModule, m_pDataBlob));
3185
3186 SOSDacLeave();
3187 return hr;
3188}
3189
3190
3191HRESULT
3192ClrDataAccess::GetDomainLocalModuleDataFromModule(CLRDATA_ADDRESS addr, struct DacpDomainLocalModuleData *pLocalModuleData)
3193{
3194 if (addr == 0 || pLocalModuleData == NULL)
3195 return E_INVALIDARG;
3196
3197 SOSDacEnter();
3198
3199 Module* pModule = PTR_Module(TO_TADDR(addr));
3200 DomainLocalModule* pLocalModule = PTR_DomainLocalModule(pModule->GetDomainLocalModule(NULL));
3201 if (!pLocalModule)
3202 {
3203 hr = E_INVALIDARG;
3204 }
3205 else
3206 {
3207 pLocalModuleData->pGCStaticDataStart = TO_CDADDR(PTR_TO_TADDR(pLocalModule->GetPrecomputedGCStaticsBasePointer()));
3208 pLocalModuleData->pNonGCStaticDataStart = TO_CDADDR(pLocalModule->GetPrecomputedNonGCStaticsBasePointer());
3209 pLocalModuleData->pDynamicClassTable = PTR_CDADDR(pLocalModule->m_pDynamicClassTable.Load());
3210 pLocalModuleData->pClassData = (TADDR) (PTR_HOST_MEMBER_TADDR(DomainLocalModule, pLocalModule, m_pDataBlob));
3211 }
3212
3213 SOSDacLeave();
3214 return hr;
3215}
3216
3217HRESULT
3218ClrDataAccess::GetDomainLocalModuleDataFromAppDomain(CLRDATA_ADDRESS appDomainAddr, int moduleID, struct DacpDomainLocalModuleData *pLocalModuleData)
3219{
3220 if (appDomainAddr == 0 || moduleID < 0 || pLocalModuleData == NULL)
3221 return E_INVALIDARG;
3222
3223 SOSDacEnter();
3224
3225 pLocalModuleData->appDomainAddr = appDomainAddr;
3226 pLocalModuleData->ModuleID = moduleID;
3227
3228 AppDomain *pAppDomain = PTR_AppDomain(TO_TADDR(appDomainAddr));
3229 ModuleIndex index = Module::IDToIndex(moduleID);
3230 DomainLocalModule* pLocalModule = pAppDomain->GetDomainLocalBlock()->GetModuleSlot(index);
3231 if (!pLocalModule)
3232 {
3233 hr = E_INVALIDARG;
3234 }
3235 else
3236 {
3237 pLocalModuleData->pGCStaticDataStart = TO_CDADDR(PTR_TO_TADDR(pLocalModule->GetPrecomputedGCStaticsBasePointer()));
3238 pLocalModuleData->pNonGCStaticDataStart = TO_CDADDR(pLocalModule->GetPrecomputedNonGCStaticsBasePointer());
3239 pLocalModuleData->pDynamicClassTable = PTR_CDADDR(pLocalModule->m_pDynamicClassTable.Load());
3240 pLocalModuleData->pClassData = (TADDR) (PTR_HOST_MEMBER_TADDR(DomainLocalModule, pLocalModule, m_pDataBlob));
3241 }
3242
3243 SOSDacLeave();
3244 return hr;
3245}
3246
3247
3248
3249
3250HRESULT
3251ClrDataAccess::GetThreadLocalModuleData(CLRDATA_ADDRESS thread, unsigned int index, struct DacpThreadLocalModuleData *pLocalModuleData)
3252{
3253 if (pLocalModuleData == NULL)
3254 return E_INVALIDARG;
3255
3256 SOSDacEnter();
3257
3258 pLocalModuleData->threadAddr = thread;
3259 pLocalModuleData->ModuleIndex = index;
3260
3261 PTR_Thread pThread = PTR_Thread(TO_TADDR(thread));
3262 PTR_ThreadLocalBlock pLocalBlock = ThreadStatics::GetCurrentTLB(pThread);
3263 PTR_ThreadLocalModule pLocalModule = pLocalBlock->GetTLMIfExists(ModuleIndex(index));
3264 if (!pLocalModule)
3265 {
3266 hr = E_INVALIDARG;
3267 }
3268 else
3269 {
3270 pLocalModuleData->pGCStaticDataStart = TO_CDADDR(PTR_TO_TADDR(pLocalModule->GetPrecomputedGCStaticsBasePointer()));
3271 pLocalModuleData->pNonGCStaticDataStart = TO_CDADDR(pLocalModule->GetPrecomputedNonGCStaticsBasePointer());
3272 pLocalModuleData->pDynamicClassTable = PTR_CDADDR(pLocalModule->m_pDynamicClassTable);
3273 pLocalModuleData->pClassData = (TADDR) (PTR_HOST_MEMBER_TADDR(ThreadLocalModule, pLocalModule, m_pDataBlob));
3274 }
3275
3276 SOSDacLeave();
3277 return hr;
3278}
3279
3280
3281HRESULT ClrDataAccess::GetHandleEnum(ISOSHandleEnum **ppHandleEnum)
3282{
3283 unsigned int types[] = {HNDTYPE_WEAK_SHORT, HNDTYPE_WEAK_LONG, HNDTYPE_STRONG, HNDTYPE_PINNED, HNDTYPE_VARIABLE, HNDTYPE_DEPENDENT,
3284 HNDTYPE_ASYNCPINNED, HNDTYPE_SIZEDREF,
3285#ifdef FEATURE_COMINTEROP
3286 HNDTYPE_REFCOUNTED, HNDTYPE_WEAK_WINRT
3287#endif
3288 };
3289
3290 return GetHandleEnumForTypes(types, _countof(types), ppHandleEnum);
3291}
3292
3293HRESULT ClrDataAccess::GetHandleEnumForTypes(unsigned int types[], unsigned int count, ISOSHandleEnum **ppHandleEnum)
3294{
3295 if (ppHandleEnum == 0)
3296 return E_POINTER;
3297
3298 SOSDacEnter();
3299
3300 DacHandleWalker *walker = new DacHandleWalker();
3301
3302 HRESULT hr = walker->Init(this, types, count);
3303
3304 if (SUCCEEDED(hr))
3305 hr = walker->QueryInterface(__uuidof(ISOSHandleEnum), (void**)ppHandleEnum);
3306
3307 if (FAILED(hr))
3308 delete walker;
3309
3310 SOSDacLeave();
3311 return hr;
3312}
3313
3314HRESULT ClrDataAccess::GetHandleEnumForGC(unsigned int gen, ISOSHandleEnum **ppHandleEnum)
3315{
3316 if (ppHandleEnum == 0)
3317 return E_POINTER;
3318
3319 SOSDacEnter();
3320
3321 unsigned int types[] = {HNDTYPE_WEAK_SHORT, HNDTYPE_WEAK_LONG, HNDTYPE_STRONG, HNDTYPE_PINNED, HNDTYPE_VARIABLE, HNDTYPE_DEPENDENT,
3322 HNDTYPE_ASYNCPINNED, HNDTYPE_SIZEDREF,
3323#ifdef FEATURE_COMINTEROP
3324 HNDTYPE_REFCOUNTED, HNDTYPE_WEAK_WINRT
3325#endif
3326 };
3327
3328 DacHandleWalker *walker = new DacHandleWalker();
3329
3330 HRESULT hr = walker->Init(this, types, _countof(types), gen);
3331 if (SUCCEEDED(hr))
3332 hr = walker->QueryInterface(__uuidof(ISOSHandleEnum), (void**)ppHandleEnum);
3333
3334 if (FAILED(hr))
3335 delete walker;
3336
3337 SOSDacLeave();
3338 return hr;
3339}
3340
3341HRESULT
3342ClrDataAccess::TraverseEHInfo(CLRDATA_ADDRESS ip, DUMPEHINFO pFunc, LPVOID token)
3343{
3344 if (ip == 0 || pFunc == NULL)
3345 return E_INVALIDARG;
3346
3347 SOSDacEnter();
3348
3349 EECodeInfo codeInfo(TO_TADDR(ip));
3350 if (!codeInfo.IsValid())
3351 {
3352 hr = E_INVALIDARG;
3353 }
3354
3355 if (SUCCEEDED(hr))
3356 {
3357 EH_CLAUSE_ENUMERATOR EnumState;
3358 EE_ILEXCEPTION_CLAUSE EHClause;
3359 unsigned EHCount;
3360
3361 EHCount = codeInfo.GetJitManager()->InitializeEHEnumeration(codeInfo.GetMethodToken(), &EnumState);
3362 for (unsigned i = 0; i < EHCount; i++)
3363 {
3364 codeInfo.GetJitManager()->GetNextEHClause(&EnumState, &EHClause);
3365
3366 DACEHInfo deh;
3367 ZeroMemory(&deh,sizeof(deh));
3368
3369 if (IsFault(&EHClause))
3370 {
3371 deh.clauseType = EHFault;
3372 }
3373 else if (IsFinally(&EHClause))
3374 {
3375 deh.clauseType = EHFinally;
3376 }
3377 else if (IsFilterHandler(&EHClause))
3378 {
3379 deh.clauseType = EHFilter;
3380 deh.filterOffset = EHClause.FilterOffset;
3381 }
3382 else if (IsTypedHandler(&EHClause))
3383 {
3384 deh.clauseType = EHTyped;
3385 deh.isCatchAllHandler = (&EHClause.TypeHandle == (void*)(size_t)mdTypeRefNil);
3386 }
3387 else
3388 {
3389 deh.clauseType = EHUnknown;
3390 }
3391
3392 if (HasCachedTypeHandle(&EHClause))
3393 {
3394 deh.mtCatch = TO_CDADDR(&EHClause.TypeHandle);
3395 }
3396 else if(!IsFaultOrFinally(&EHClause))
3397 {
3398 // the module of the token (whether a ref or def token) is the same as the module of the method containing the EH clause
3399 deh.moduleAddr = HOST_CDADDR(codeInfo.GetMethodDesc()->GetModule());
3400 deh.tokCatch = EHClause.ClassToken;
3401 }
3402
3403 deh.tryStartOffset = EHClause.TryStartPC;
3404 deh.tryEndOffset = EHClause.TryEndPC;
3405 deh.handlerStartOffset = EHClause.HandlerStartPC;
3406 deh.handlerEndOffset = EHClause.HandlerEndPC;
3407 deh.isDuplicateClause = IsDuplicateClause(&EHClause);
3408
3409 if (!(pFunc)(i, EHCount, &deh, token))
3410 {
3411 // User wants to stop the enumeration
3412 hr = E_ABORT;
3413 break;
3414 }
3415 }
3416 }
3417
3418 SOSDacLeave();
3419 return hr;
3420}
3421
3422HRESULT
3423ClrDataAccess::TraverseRCWCleanupList(CLRDATA_ADDRESS cleanupListPtr, VISITRCWFORCLEANUP pFunc, LPVOID token)
3424{
3425#ifdef FEATURE_COMINTEROP
3426 if (pFunc == 0)
3427 return E_INVALIDARG;
3428
3429 SOSDacEnter();
3430 RCWCleanupList *pList = g_pRCWCleanupList;
3431
3432 if (cleanupListPtr)
3433 {
3434 pList = PTR_RCWCleanupList(TO_TADDR(cleanupListPtr));
3435 }
3436
3437 if (pList)
3438 {
3439 PTR_RCW pBucket = dac_cast<PTR_RCW>(TO_TADDR(pList->m_pFirstBucket));
3440 while (pBucket != NULL)
3441 {
3442 PTR_RCW pRCW = pBucket;
3443 Thread *pSTAThread = pRCW->GetSTAThread();
3444 LPVOID pCtxCookie = pRCW->GetWrapperCtxCookie();
3445 BOOL bIsFreeThreaded = pRCW->IsFreeThreaded();
3446
3447 while (pRCW)
3448 {
3449 (pFunc)(HOST_CDADDR(pRCW),(CLRDATA_ADDRESS)pCtxCookie, (CLRDATA_ADDRESS)(TADDR)pSTAThread, bIsFreeThreaded, token);
3450 pRCW = pRCW->m_pNextRCW;
3451 }
3452 pBucket = pBucket->m_pNextCleanupBucket;
3453 }
3454 }
3455
3456 SOSDacLeave();
3457 return hr;
3458#else
3459 return E_NOTIMPL;
3460#endif // FEATURE_COMINTEROP
3461}
3462
3463HRESULT
3464ClrDataAccess::TraverseLoaderHeap(CLRDATA_ADDRESS loaderHeapAddr, VISITHEAP pFunc)
3465{
3466 if (loaderHeapAddr == 0 || pFunc == 0)
3467 return E_INVALIDARG;
3468
3469 SOSDacEnter();
3470
3471 LoaderHeap *pLoaderHeap = PTR_LoaderHeap(TO_TADDR(loaderHeapAddr));
3472 PTR_LoaderHeapBlock block = pLoaderHeap->m_pFirstBlock;
3473 while (block.IsValid())
3474 {
3475 TADDR addr = PTR_TO_TADDR(block->pVirtualAddress);
3476 size_t size = block->dwVirtualSize;
3477
3478 BOOL bCurrentBlock = (block == pLoaderHeap->m_pCurBlock);
3479
3480 pFunc(addr,size,bCurrentBlock);
3481
3482 block = block->pNext;
3483 }
3484
3485 SOSDacLeave();
3486 return hr;
3487}
3488
3489HRESULT
3490ClrDataAccess::TraverseVirtCallStubHeap(CLRDATA_ADDRESS pAppDomain, VCSHeapType heaptype, VISITHEAP pFunc)
3491{
3492 if (pAppDomain == 0)
3493 return E_INVALIDARG;
3494
3495 SOSDacEnter();
3496
3497 BaseDomain* pBaseDomain = PTR_BaseDomain(TO_TADDR(pAppDomain));
3498 VirtualCallStubManager *pVcsMgr = PTR_VirtualCallStubManager((TADDR)pBaseDomain->GetLoaderAllocator()->GetVirtualCallStubManager());
3499 if (!pVcsMgr)
3500 {
3501 hr = E_POINTER;
3502 }
3503 else
3504 {
3505 LoaderHeap *pLoaderHeap = NULL;
3506 switch(heaptype)
3507 {
3508 case IndcellHeap:
3509 pLoaderHeap = pVcsMgr->indcell_heap;
3510 break;
3511 case LookupHeap:
3512 pLoaderHeap = pVcsMgr->lookup_heap;
3513 break;
3514 case ResolveHeap:
3515 pLoaderHeap = pVcsMgr->resolve_heap;
3516 break;
3517 case DispatchHeap:
3518 pLoaderHeap = pVcsMgr->dispatch_heap;
3519 break;
3520 case CacheEntryHeap:
3521 pLoaderHeap = pVcsMgr->cache_entry_heap;
3522 break;
3523 default:
3524 hr = E_INVALIDARG;
3525 }
3526
3527 if (SUCCEEDED(hr))
3528 {
3529 PTR_LoaderHeapBlock block = pLoaderHeap->m_pFirstBlock;
3530 while (block.IsValid())
3531 {
3532 TADDR addr = PTR_TO_TADDR(block->pVirtualAddress);
3533 size_t size = block->dwVirtualSize;
3534
3535 BOOL bCurrentBlock = (block == pLoaderHeap->m_pCurBlock);
3536 pFunc(addr, size, bCurrentBlock);
3537
3538 block = block->pNext;
3539 }
3540 }
3541 }
3542
3543 SOSDacLeave();
3544 return hr;
3545}
3546
3547
3548HRESULT
3549ClrDataAccess::GetSyncBlockData(unsigned int SBNumber, struct DacpSyncBlockData *pSyncBlockData)
3550{
3551 if (pSyncBlockData == NULL)
3552 return E_INVALIDARG;
3553
3554 SOSDacEnter();
3555
3556 ZeroMemory(pSyncBlockData,sizeof(DacpSyncBlockData));
3557 pSyncBlockData->SyncBlockCount = (SyncBlockCache::s_pSyncBlockCache->m_FreeSyncTableIndex) - 1;
3558 PTR_SyncTableEntry ste = PTR_SyncTableEntry(dac_cast<TADDR>(g_pSyncTable)+(sizeof(SyncTableEntry) * SBNumber));
3559 pSyncBlockData->bFree = ((dac_cast<TADDR>(ste->m_Object.Load())) & 1);
3560
3561 if (pSyncBlockData->bFree == FALSE)
3562 {
3563 pSyncBlockData->Object = (CLRDATA_ADDRESS)dac_cast<TADDR>(ste->m_Object.Load());
3564
3565 if (ste->m_SyncBlock != NULL)
3566 {
3567 SyncBlock *pBlock = PTR_SyncBlock(ste->m_SyncBlock);
3568 pSyncBlockData->SyncBlockPointer = HOST_CDADDR(pBlock);
3569#ifdef FEATURE_COMINTEROP
3570 if (pBlock->m_pInteropInfo)
3571 {
3572 pSyncBlockData->COMFlags |= (pBlock->m_pInteropInfo->DacGetRawRCW() != 0) ? SYNCBLOCKDATA_COMFLAGS_RCW : 0;
3573 pSyncBlockData->COMFlags |= (pBlock->m_pInteropInfo->GetCCW() != NULL) ? SYNCBLOCKDATA_COMFLAGS_CCW : 0;
3574#ifdef FEATURE_COMINTEROP_UNMANAGED_ACTIVATION
3575 pSyncBlockData->COMFlags |= (pBlock->m_pInteropInfo->GetComClassFactory() != NULL) ? SYNCBLOCKDATA_COMFLAGS_CF : 0;
3576#endif // FEATURE_COMINTEROP_UNMANAGED_ACTIVATION
3577 }
3578#endif // FEATURE_COMINTEROP
3579
3580 pSyncBlockData->MonitorHeld = pBlock->m_Monitor.GetMonitorHeldStateVolatile();
3581 pSyncBlockData->Recursion = pBlock->m_Monitor.GetRecursionLevel();
3582 pSyncBlockData->HoldingThread = HOST_CDADDR(pBlock->m_Monitor.GetHoldingThread());
3583
3584 if (pBlock->GetAppDomainIndex().m_dwIndex)
3585 {
3586 pSyncBlockData->appDomainPtr = PTR_HOST_TO_TADDR(
3587 SystemDomain::TestGetAppDomainAtIndex(pBlock->GetAppDomainIndex()));
3588 }
3589
3590 // TODO: Microsoft, implement the wait list
3591 pSyncBlockData->AdditionalThreadCount = 0;
3592
3593 if (pBlock->m_Link.m_pNext != NULL)
3594 {
3595 PTR_SLink pLink = pBlock->m_Link.m_pNext;
3596 do
3597 {
3598 pSyncBlockData->AdditionalThreadCount++;
3599 pLink = pBlock->m_Link.m_pNext;
3600 }
3601 while ((pLink != NULL) &&
3602 (pSyncBlockData->AdditionalThreadCount < 1000));
3603 }
3604 }
3605 }
3606
3607 SOSDacLeave();
3608 return hr;
3609}
3610
3611HRESULT
3612ClrDataAccess::GetSyncBlockCleanupData(CLRDATA_ADDRESS syncBlock, struct DacpSyncBlockCleanupData *syncBlockCData)
3613{
3614 if (syncBlock == 0 || syncBlockCData == NULL)
3615 return E_INVALIDARG;
3616
3617 SOSDacEnter();
3618
3619 ZeroMemory (syncBlockCData, sizeof(DacpSyncBlockCleanupData));
3620 SyncBlock *pBlock = NULL;
3621
3622 if (syncBlock == NULL && SyncBlockCache::s_pSyncBlockCache->m_pCleanupBlockList)
3623 {
3624 pBlock = (SyncBlock *) PTR_SyncBlock(
3625 PTR_HOST_TO_TADDR(SyncBlockCache::s_pSyncBlockCache->m_pCleanupBlockList) - offsetof(SyncBlock, m_Link));
3626 }
3627 else
3628 {
3629 pBlock = PTR_SyncBlock(TO_TADDR(syncBlock));
3630 }
3631
3632 if (pBlock)
3633 {
3634 syncBlockCData->SyncBlockPointer = HOST_CDADDR(pBlock);
3635 if (pBlock->m_Link.m_pNext)
3636 {
3637 syncBlockCData->nextSyncBlock = (CLRDATA_ADDRESS)
3638 (PTR_HOST_TO_TADDR(pBlock->m_Link.m_pNext) - offsetof(SyncBlock, m_Link));
3639 }
3640
3641#ifdef FEATURE_COMINTEROP
3642 if (pBlock->m_pInteropInfo->DacGetRawRCW())
3643 syncBlockCData->blockRCW = (CLRDATA_ADDRESS) pBlock->m_pInteropInfo->DacGetRawRCW();
3644#ifdef FEATURE_COMINTEROP_UNMANAGED_ACTIVATION
3645 if (pBlock->m_pInteropInfo->GetComClassFactory())
3646 syncBlockCData->blockClassFactory = (CLRDATA_ADDRESS) (TADDR) pBlock->m_pInteropInfo->GetComClassFactory();
3647#endif // FEATURE_COMINTEROP_UNMANAGED_ACTIVATION
3648 if (pBlock->m_pInteropInfo->GetCCW())
3649 syncBlockCData->blockCCW = (CLRDATA_ADDRESS) dac_cast<TADDR>(pBlock->m_pInteropInfo->GetCCW());
3650#endif // FEATURE_COMINTEROP
3651 }
3652
3653 SOSDacLeave();
3654 return hr;
3655}
3656
3657HRESULT
3658ClrDataAccess::GetJitHelperFunctionName(CLRDATA_ADDRESS ip, unsigned int count, __out_z __inout_ecount(count) char *name, unsigned int *pNeeded)
3659{
3660 SOSDacEnter();
3661
3662 PCSTR pszHelperName = GetJitHelperName(TO_TADDR(ip));
3663 if (pszHelperName == NULL)
3664 {
3665 hr = E_INVALIDARG;
3666 }
3667 else
3668 {
3669 unsigned int len = (unsigned int)strlen(pszHelperName) + 1;
3670
3671 if (pNeeded)
3672 *pNeeded = len;
3673
3674 if (name)
3675 {
3676 if (count < len)
3677 hr = E_FAIL;
3678 else
3679 strcpy_s(name, count, pszHelperName);
3680 }
3681 }
3682
3683 SOSDacLeave();
3684 return hr;
3685};
3686
3687HRESULT
3688ClrDataAccess::GetJumpThunkTarget(T_CONTEXT *ctx, CLRDATA_ADDRESS *targetIP, CLRDATA_ADDRESS *targetMD)
3689{
3690 if (ctx == NULL || targetIP == NULL || targetMD == NULL)
3691 return E_INVALIDARG;
3692
3693#ifdef _TARGET_AMD64_
3694 SOSDacEnter();
3695
3696 if (!GetAnyThunkTarget(ctx, targetIP, targetMD))
3697 hr = E_FAIL;
3698
3699 SOSDacLeave();
3700 return hr;
3701#else
3702 return E_FAIL;
3703#endif // _WIN64
3704}
3705
3706
3707#ifdef _PREFAST_
3708#pragma warning(push)
3709#pragma warning(disable:21000) // Suppress PREFast warning about overly large function
3710#endif
3711STDMETHODIMP
3712ClrDataAccess::Request(IN ULONG32 reqCode,
3713 IN ULONG32 inBufferSize,
3714 IN BYTE* inBuffer,
3715 IN ULONG32 outBufferSize,
3716 OUT BYTE* outBuffer)
3717{
3718 HRESULT status;
3719
3720 DAC_ENTER();
3721
3722 EX_TRY
3723 {
3724 switch(reqCode)
3725 {
3726 case CLRDATA_REQUEST_REVISION:
3727 if (inBufferSize != 0 ||
3728 inBuffer ||
3729 outBufferSize != sizeof(ULONG32))
3730 {
3731 status = E_INVALIDARG;
3732 }
3733 else
3734 {
3735 *(ULONG32*)outBuffer = 9;
3736 status = S_OK;
3737 }
3738 break;
3739
3740 default:
3741 status = E_INVALIDARG;
3742 break;
3743 }
3744 }
3745 EX_CATCH
3746 {
3747 if (!DacExceptionFilter(GET_EXCEPTION(), this, &status))
3748 {
3749 EX_RETHROW;
3750 }
3751 }
3752 EX_END_CATCH(SwallowAllExceptions)
3753
3754 DAC_LEAVE();
3755 return status;
3756}
3757#ifdef _PREFAST_
3758#pragma warning(pop)
3759#endif
3760
3761void
3762ClrDataAccess::EnumWksGlobalMemoryRegions(CLRDataEnumMemoryFlags flags)
3763{
3764 SUPPORTS_DAC;
3765
3766#ifdef FEATURE_SVR_GC
3767 // If server GC, skip enumeration
3768 if (g_gcDacGlobals->g_heaps != nullptr)
3769 return;
3770#endif
3771
3772 Dereference(g_gcDacGlobals->ephemeral_heap_segment).EnumMem();
3773 g_gcDacGlobals->alloc_allocated.EnumMem();
3774 g_gcDacGlobals->gc_structures_invalid_cnt.EnumMem();
3775 Dereference(g_gcDacGlobals->finalize_queue).EnumMem();
3776
3777 // Enumerate the entire generation table, which has variable size
3778 size_t gen_table_size = g_gcDacGlobals->generation_size * (*g_gcDacGlobals->max_gen + 2);
3779 DacEnumMemoryRegion(dac_cast<TADDR>(g_gcDacGlobals->generation_table), gen_table_size);
3780
3781 if (g_gcDacGlobals->generation_table.IsValid())
3782 {
3783 // enumerating the generations from max (which is normally gen2) to max+1 gives you
3784 // the segment list for all the normal segements plus the large heap segment (max+1)
3785 // this is the convention in the GC so it is repeated here
3786 for (ULONG i = *g_gcDacGlobals->max_gen; i <= *g_gcDacGlobals->max_gen +1; i++)
3787 {
3788 dac_generation *gen = GenerationTableIndex(g_gcDacGlobals->generation_table, i);
3789 __DPtr<dac_heap_segment> seg = dac_cast<TADDR>(gen->start_segment);
3790 while (seg)
3791 {
3792 DacEnumMemoryRegion(dac_cast<TADDR>(seg), sizeof(dac_heap_segment));
3793 seg = seg->next;
3794 }
3795 }
3796 }
3797}
3798
3799HRESULT
3800ClrDataAccess::GetClrWatsonBuckets(CLRDATA_ADDRESS thread, void *pGenericModeBlock)
3801{
3802#ifdef FEATURE_PAL
3803 // This API is not available under FEATURE_PAL
3804 return E_FAIL;
3805#else // FEATURE_PAL
3806 if (thread == 0 || pGenericModeBlock == NULL)
3807 return E_INVALIDARG;
3808
3809 SOSDacEnter();
3810
3811 Thread * pThread = PTR_Thread(TO_TADDR(thread));
3812 hr = GetClrWatsonBucketsWorker(pThread, reinterpret_cast<GenericModeBlock *>(pGenericModeBlock));
3813
3814 SOSDacLeave();
3815 return hr;
3816#endif // FEATURE_PAL
3817}
3818
3819#ifndef FEATURE_PAL
3820
3821HRESULT ClrDataAccess::GetClrWatsonBucketsWorker(Thread * pThread, GenericModeBlock * pGM)
3822{
3823 if ((pThread == NULL) || (pGM == NULL))
3824 {
3825 return E_INVALIDARG;
3826 }
3827
3828 // By default, there are no buckets
3829 PTR_VOID pBuckets = NULL;
3830
3831 // Get the handle to the throwble
3832 OBJECTHANDLE ohThrowable = pThread->GetThrowableAsHandle();
3833 if (ohThrowable != NULL)
3834 {
3835 // Get the object from handle and check if the throwable is preallocated or not
3836 OBJECTREF oThrowable = ObjectFromHandle(ohThrowable);
3837 if (oThrowable != NULL)
3838 {
3839 // Does the throwable have buckets?
3840 if (((EXCEPTIONREF)oThrowable)->AreWatsonBucketsPresent())
3841 {
3842 // Get the watson buckets from the throwable for non-preallocated
3843 // exceptions
3844 U1ARRAYREF refWatsonBucketArray = ((EXCEPTIONREF)oThrowable)->GetWatsonBucketReference();
3845 pBuckets = dac_cast<PTR_VOID>(refWatsonBucketArray->GetDataPtr());
3846 }
3847 else
3848 {
3849 // This is a preallocated exception object - check if the UE Watson bucket tracker
3850 // has any bucket details
3851 pBuckets = pThread->GetExceptionState()->GetUEWatsonBucketTracker()->RetrieveWatsonBuckets();
3852 if (pBuckets == NULL)
3853 {
3854 // Since the UE watson bucket tracker does not have them, look up the current
3855 // exception tracker
3856 if (pThread->GetExceptionState()->GetCurrentExceptionTracker() != NULL)
3857 {
3858 pBuckets = pThread->GetExceptionState()->GetCurrentExceptionTracker()->GetWatsonBucketTracker()->RetrieveWatsonBuckets();
3859 }
3860 }
3861 }
3862 }
3863 }
3864 else
3865 {
3866 // Debuger.Break doesn't have a throwable, but saves Watson buckets in EHWatsonBucketTracker.
3867 pBuckets = pThread->GetExceptionState()->GetUEWatsonBucketTracker()->RetrieveWatsonBuckets();
3868 }
3869
3870 // If pBuckets is non-null, it is the address of a Watson GenericModeBlock in the target process.
3871 if (pBuckets != NULL)
3872 {
3873 ULONG32 returned = 0;
3874 HRESULT hr = m_pTarget->ReadVirtual(dac_cast<TADDR>(pBuckets), reinterpret_cast<BYTE *>(pGM), sizeof(*pGM), &returned);
3875 if (FAILED(hr))
3876 {
3877 hr = CORDBG_E_READVIRTUAL_FAILURE;
3878 }
3879 if (SUCCEEDED(hr) && (returned != sizeof(*pGM)))
3880 {
3881 hr = HRESULT_FROM_WIN32(ERROR_PARTIAL_COPY);
3882 }
3883 return hr;
3884 }
3885 else
3886 {
3887 // Buckets are not available
3888 return S_FALSE;
3889 }
3890}
3891
3892#endif // FEATURE_PAL
3893
3894HRESULT ClrDataAccess::GetTLSIndex(ULONG *pIndex)
3895{
3896 if (pIndex == NULL)
3897 return E_INVALIDARG;
3898
3899 SOSDacEnter();
3900 if (g_TlsIndex == TLS_OUT_OF_INDEXES)
3901 {
3902 *pIndex = 0;
3903 hr = S_FALSE;
3904 }
3905 else
3906 {
3907 *pIndex = g_TlsIndex;
3908 }
3909
3910 SOSDacLeave();
3911 return hr;
3912}
3913
3914HRESULT ClrDataAccess::GetDacModuleHandle(HMODULE *phModule)
3915{
3916 if(phModule == NULL)
3917 return E_INVALIDARG;
3918 *phModule = GetModuleInst();
3919 return S_OK;
3920}
3921
3922HRESULT ClrDataAccess::GetRCWData(CLRDATA_ADDRESS addr, struct DacpRCWData *rcwData)
3923{
3924 if (addr == 0 || rcwData == NULL)
3925 return E_INVALIDARG;
3926
3927#ifdef FEATURE_COMINTEROP
3928 SOSDacEnter();
3929
3930 ZeroMemory (rcwData, sizeof(DacpRCWData));
3931
3932 PTR_RCW pRCW = dac_cast<PTR_RCW>(CLRDATA_ADDRESS_TO_TADDR(addr));
3933
3934 rcwData->identityPointer = TO_CDADDR(pRCW->m_pIdentity);
3935 rcwData->unknownPointer = TO_CDADDR(pRCW->GetRawIUnknown_NoAddRef());
3936 rcwData->vtablePtr = TO_CDADDR(pRCW->m_vtablePtr);
3937 rcwData->creatorThread = TO_CDADDR(pRCW->m_pCreatorThread);
3938 rcwData->ctxCookie = TO_CDADDR(pRCW->GetWrapperCtxCookie());
3939 rcwData->refCount = pRCW->m_cbRefCount;
3940
3941 rcwData->isJupiterObject = pRCW->IsJupiterObject();
3942 rcwData->supportsIInspectable = pRCW->SupportsIInspectable();
3943 rcwData->isAggregated = pRCW->IsURTAggregated();
3944 rcwData->isContained = pRCW->IsURTContained();
3945 rcwData->jupiterObject = TO_CDADDR(pRCW->GetJupiterObject());
3946 rcwData->isFreeThreaded = pRCW->IsFreeThreaded();
3947 rcwData->isDisconnected = pRCW->IsDisconnected();
3948
3949 if (pRCW->m_SyncBlockIndex != 0)
3950 {
3951 PTR_SyncTableEntry ste = PTR_SyncTableEntry(dac_cast<TADDR>(g_pSyncTable) + (sizeof(SyncTableEntry) * pRCW->m_SyncBlockIndex));
3952 rcwData->managedObject = PTR_CDADDR(ste->m_Object.Load());
3953 }
3954
3955 // count the number of cached interface pointers
3956 rcwData->interfaceCount = 0;
3957 RCW::CachedInterfaceEntryIterator it = pRCW->IterateCachedInterfacePointers();
3958 while (it.Next())
3959 {
3960 if (it.GetEntry()->m_pUnknown.Load() != NULL)
3961 rcwData->interfaceCount++;
3962 }
3963
3964 SOSDacLeave();
3965 return hr;
3966#else
3967 return E_NOTIMPL;
3968#endif
3969}
3970
3971HRESULT ClrDataAccess::GetRCWInterfaces(CLRDATA_ADDRESS rcw, unsigned int count, struct DacpCOMInterfacePointerData interfaces[], unsigned int *pNeeded)
3972{
3973 if (rcw == 0)
3974 return E_INVALIDARG;
3975
3976#ifdef FEATURE_COMINTEROP
3977
3978 SOSDacEnter();
3979 PTR_RCW pRCW = dac_cast<PTR_RCW>(CLRDATA_ADDRESS_TO_TADDR(rcw));
3980 if (interfaces == NULL)
3981 {
3982 if (pNeeded)
3983 {
3984 unsigned int c = 0;
3985 RCW::CachedInterfaceEntryIterator it = pRCW->IterateCachedInterfacePointers();
3986 while (it.Next())
3987 {
3988 if (it.GetEntry()->m_pUnknown.Load() != NULL)
3989 c++;
3990 }
3991
3992 *pNeeded = c;
3993 }
3994 else
3995 {
3996 hr = E_INVALIDARG;
3997 }
3998 }
3999 else
4000 {
4001 ZeroMemory(interfaces, sizeof(DacpCOMInterfacePointerData) * count);
4002
4003 unsigned int itemIndex = 0;
4004 RCW::CachedInterfaceEntryIterator it = pRCW->IterateCachedInterfacePointers();
4005 while (it.Next())
4006 {
4007 InterfaceEntry *pEntry = it.GetEntry();
4008 if (pEntry->m_pUnknown.Load() != NULL)
4009 {
4010 if (itemIndex >= count)
4011 {
4012 // the outBuffer is too small
4013 hr = E_INVALIDARG;
4014 break;
4015 }
4016 else
4017 {
4018 interfaces[itemIndex].interfacePtr = TO_CDADDR(pEntry->m_pUnknown.Load());
4019 interfaces[itemIndex].methodTable = TO_CDADDR(pEntry->m_pMT.Load());
4020 interfaces[itemIndex].comContext = TO_CDADDR(it.GetCtxCookie());
4021 itemIndex++;
4022 }
4023 }
4024 }
4025
4026 if (SUCCEEDED(hr) && pNeeded)
4027 *pNeeded = itemIndex;
4028 }
4029
4030 SOSDacLeave();
4031 return hr;
4032#else
4033 return E_NOTIMPL;
4034#endif
4035}
4036
4037#ifdef FEATURE_COMINTEROP
4038PTR_ComCallWrapper ClrDataAccess::DACGetCCWFromAddress(CLRDATA_ADDRESS addr)
4039{
4040 PTR_ComCallWrapper pCCW = NULL;
4041
4042 // first check whether the address is our COM IP
4043 TADDR pPtr = CLRDATA_ADDRESS_TO_TADDR(addr);
4044
4045 ULONG32 returned = 0;
4046 if (m_pTarget->ReadVirtual(pPtr, (PBYTE)&pPtr, sizeof(TADDR), &returned) == S_OK &&
4047 returned == sizeof(TADDR))
4048 {
4049 // this should be the vtable pointer - dereference the 2nd slot
4050 if (m_pTarget->ReadVirtual(pPtr + sizeof(PBYTE) * TEAR_OFF_SLOT, (PBYTE)&pPtr, sizeof(TADDR), &returned) == S_OK &&
4051 returned == sizeof(TADDR))
4052 {
4053
4054#ifdef DBG_TARGET_ARM
4055 // clear the THUMB bit on pPtr before comparing with known vtable entry
4056 pPtr &= ~THUMB_CODE;
4057#endif
4058
4059 if (pPtr == GetEEFuncEntryPoint(TEAR_OFF_STANDARD))
4060 {
4061 // Points to ComCallWrapper
4062 PTR_IUnknown pUnk(CLRDATA_ADDRESS_TO_TADDR(addr));
4063 pCCW = ComCallWrapper::GetWrapperFromIP(pUnk);
4064 }
4065 else if (pPtr == GetEEFuncEntryPoint(TEAR_OFF_SIMPLE) || pPtr == GetEEFuncEntryPoint(TEAR_OFF_SIMPLE_INNER))
4066 {
4067 // Points to SimpleComCallWrapper
4068 PTR_IUnknown pUnk(CLRDATA_ADDRESS_TO_TADDR(addr));
4069 pCCW = SimpleComCallWrapper::GetWrapperFromIP(pUnk)->GetMainWrapper();
4070 }
4071 }
4072 }
4073
4074 if (pCCW == NULL)
4075 {
4076 // no luck interpreting the address as a COM interface pointer - it must be a CCW address
4077 pCCW = dac_cast<PTR_ComCallWrapper>(CLRDATA_ADDRESS_TO_TADDR(addr));
4078 }
4079
4080 if (pCCW->IsLinked())
4081 pCCW = ComCallWrapper::GetStartWrapper(pCCW);
4082
4083 return pCCW;
4084}
4085
4086PTR_IUnknown ClrDataAccess::DACGetCOMIPFromCCW(PTR_ComCallWrapper pCCW, int vtableIndex)
4087{
4088 if (pCCW->m_rgpIPtr[vtableIndex] != NULL)
4089 {
4090 PTR_IUnknown pUnk = dac_cast<PTR_IUnknown>(dac_cast<TADDR>(pCCW) + offsetof(ComCallWrapper, m_rgpIPtr[vtableIndex]));
4091
4092 PTR_ComMethodTable pCMT = ComMethodTable::ComMethodTableFromIP(pUnk);
4093 if (pCMT->IsLayoutComplete())
4094 {
4095 // return only fully laid out vtables
4096 return pUnk;
4097 }
4098 }
4099 return NULL;
4100}
4101#endif
4102
4103
4104HRESULT ClrDataAccess::GetCCWData(CLRDATA_ADDRESS ccw, struct DacpCCWData *ccwData)
4105{
4106 if (ccw == 0 || ccwData == NULL)
4107 return E_INVALIDARG;
4108
4109#ifdef FEATURE_COMINTEROP
4110 SOSDacEnter();
4111 ZeroMemory (ccwData, sizeof(DacpCCWData));
4112
4113 PTR_ComCallWrapper pCCW = DACGetCCWFromAddress(ccw);
4114 PTR_SimpleComCallWrapper pSimpleCCW = pCCW->GetSimpleWrapper();
4115
4116 ccwData->outerIUnknown = TO_CDADDR(pSimpleCCW->m_pOuter);
4117 ccwData->refCount = pSimpleCCW->GetRefCount();
4118 ccwData->isNeutered = pSimpleCCW->IsNeutered();
4119 ccwData->ccwAddress = TO_CDADDR(dac_cast<TADDR>(pCCW));
4120
4121 ccwData->jupiterRefCount = pSimpleCCW->GetJupiterRefCount();
4122 ccwData->isPegged = pSimpleCCW->IsPegged();
4123 ccwData->isGlobalPegged = RCWWalker::IsGlobalPeggingOn();
4124 ccwData->hasStrongRef = pCCW->IsWrapperActive();
4125 ccwData->handle = pCCW->GetObjectHandle();
4126 ccwData->isExtendsCOMObject = pCCW->GetSimpleWrapper()->IsExtendsCOMObject();
4127 ccwData->isAggregated = pCCW->GetSimpleWrapper()->IsAggregated();
4128
4129 if (pCCW->GetObjectHandle() != NULL)
4130 ccwData->managedObject = PTR_CDADDR(ObjectFromHandle(pCCW->GetObjectHandle()));
4131
4132 // count the number of COM vtables
4133 ccwData->interfaceCount = 0;
4134 while (pCCW != NULL)
4135 {
4136 for (int i = 0; i < ComCallWrapper::NumVtablePtrs; i++)
4137 {
4138 if (DACGetCOMIPFromCCW(pCCW, i) != NULL)
4139 ccwData->interfaceCount++;
4140 }
4141 pCCW = ComCallWrapper::GetNext(pCCW);
4142 }
4143
4144 SOSDacLeave();
4145 return hr;
4146#else
4147 return E_NOTIMPL;
4148#endif
4149}
4150
4151HRESULT ClrDataAccess::GetCCWInterfaces(CLRDATA_ADDRESS ccw, unsigned int count, struct DacpCOMInterfacePointerData interfaces[], unsigned int *pNeeded)
4152{
4153 if (ccw == 0)
4154 return E_INVALIDARG;
4155
4156#ifdef FEATURE_COMINTEROP
4157 SOSDacEnter();
4158 PTR_ComCallWrapper pCCW = DACGetCCWFromAddress(ccw);
4159
4160 if (interfaces == NULL)
4161 {
4162 if (pNeeded)
4163 {
4164 unsigned int c = 0;
4165 while (pCCW != NULL)
4166 {
4167 for (int i = 0; i < ComCallWrapper::NumVtablePtrs; i++)
4168 if (DACGetCOMIPFromCCW(pCCW, i) != NULL)
4169 c++;
4170 pCCW = ComCallWrapper::GetNext(pCCW);
4171 }
4172
4173 *pNeeded = c;
4174 }
4175 else
4176 {
4177 hr = E_INVALIDARG;
4178 }
4179 }
4180 else
4181 {
4182 ZeroMemory(interfaces, sizeof(DacpCOMInterfacePointerData) * count);
4183
4184 PTR_ComCallWrapperTemplate pCCWTemplate = pCCW->GetSimpleWrapper()->GetComCallWrapperTemplate();
4185 unsigned int itemIndex = 0;
4186 unsigned int wrapperOffset = 0;
4187 while (pCCW != NULL && SUCCEEDED(hr))
4188 {
4189 for (int i = 0; i < ComCallWrapper::NumVtablePtrs && SUCCEEDED(hr); i++)
4190 {
4191 PTR_IUnknown pUnk = DACGetCOMIPFromCCW(pCCW, i);
4192 if (pUnk != NULL)
4193 {
4194 if (itemIndex >= count)
4195 {
4196 // the outBuffer is too small
4197 hr = E_INVALIDARG;
4198 break;
4199 }
4200
4201 interfaces[itemIndex].interfacePtr = PTR_CDADDR(pUnk);
4202
4203 // if this is the first ComCallWrapper, the 0th vtable slots is special
4204 if (wrapperOffset == 0 && i == ComCallWrapper::Slot_Basic)
4205 {
4206 // this is IDispatch/IUnknown
4207 interfaces[itemIndex].methodTable = NULL;
4208 }
4209 else
4210 {
4211 // this slot represents the class interface or an interface implemented by the class
4212 DWORD ifaceMapIndex = wrapperOffset + i - ComCallWrapper::Slot_FirstInterface;
4213
4214 PTR_ComMethodTable pCMT = ComMethodTable::ComMethodTableFromIP(pUnk);
4215 interfaces[itemIndex].methodTable = PTR_CDADDR(pCMT->GetMethodTable());
4216 }
4217
4218 itemIndex++;
4219 }
4220 }
4221
4222 pCCW = ComCallWrapper::GetNext(pCCW);
4223 wrapperOffset += ComCallWrapper::NumVtablePtrs;
4224 }
4225
4226 if (SUCCEEDED(hr) && pNeeded)
4227 *pNeeded = itemIndex;
4228 }
4229
4230 SOSDacLeave();
4231 return hr;
4232#else
4233 return E_NOTIMPL;
4234#endif
4235}
4236
4237HRESULT ClrDataAccess::GetObjectExceptionData(CLRDATA_ADDRESS objAddr, struct DacpExceptionObjectData *data)
4238{
4239 if (data == NULL)
4240 return E_POINTER;
4241
4242 SOSDacEnter();
4243
4244 PTR_ExceptionObject pObj = dac_cast<PTR_ExceptionObject>(TO_TADDR(objAddr));
4245
4246 data->Message = TO_CDADDR(dac_cast<TADDR>(pObj->GetMessage()));
4247 data->InnerException = TO_CDADDR(dac_cast<TADDR>(pObj->GetInnerException()));
4248 data->StackTrace = TO_CDADDR(dac_cast<TADDR>(pObj->GetStackTraceArrayObject()));
4249 data->WatsonBuckets = TO_CDADDR(dac_cast<TADDR>(pObj->GetWatsonBucketReference()));
4250 data->StackTraceString = TO_CDADDR(dac_cast<TADDR>(pObj->GetStackTraceString()));
4251 data->RemoteStackTraceString = TO_CDADDR(dac_cast<TADDR>(pObj->GetRemoteStackTraceString()));
4252 data->HResult = pObj->GetHResult();
4253 data->XCode = pObj->GetXCode();
4254
4255 SOSDacLeave();
4256
4257 return hr;
4258}
4259
4260HRESULT ClrDataAccess::IsRCWDCOMProxy(CLRDATA_ADDRESS rcwAddr, BOOL* isDCOMProxy)
4261{
4262 if (isDCOMProxy == nullptr)
4263 {
4264 return E_POINTER;
4265 }
4266
4267 *isDCOMProxy = FALSE;
4268
4269#ifdef FEATURE_COMINTEROP
4270 SOSDacEnter();
4271
4272 PTR_RCW pRCW = dac_cast<PTR_RCW>(CLRDATA_ADDRESS_TO_TADDR(rcwAddr));
4273 *isDCOMProxy = pRCW->IsDCOMProxy();
4274
4275 SOSDacLeave();
4276
4277 return S_OK;
4278#else
4279 return E_NOTIMPL;
4280#endif // FEATURE_COMINTEROP
4281}
4282
4283HRESULT ClrDataAccess::GetClrNotification(CLRDATA_ADDRESS arguments[], int count, int *pNeeded)
4284{
4285 SOSDacEnter();
4286
4287 *pNeeded = MAX_CLR_NOTIFICATION_ARGS;
4288
4289 if (g_clrNotificationArguments[0] == NULL)
4290 {
4291 hr = E_FAIL;
4292 }
4293 else
4294 {
4295 for (int i = 0; i < count && i < MAX_CLR_NOTIFICATION_ARGS; i++)
4296 {
4297 arguments[i] = g_clrNotificationArguments[i];
4298 }
4299 }
4300
4301 SOSDacLeave();
4302
4303 return hr;;
4304}
4305