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. |
60 | TADDR 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. |
77 | PTR_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 | |
97 | BOOL 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 | |
125 | BOOL 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 | |
168 | BadMethodTable: ; |
169 | } |
170 | EX_CATCH |
171 | { |
172 | retval = FALSE; // Something is wrong |
173 | } |
174 | EX_END_CATCH(SwallowAllExceptions) |
175 | return retval; |
176 | |
177 | } |
178 | |
179 | BOOL 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 | |
241 | BOOL DacValidateMD(LPCVOID pMD) |
242 | { |
243 | return DacValidateMD((MethodDesc *)pMD); |
244 | } |
245 | |
246 | VOID 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 | |
265 | HRESULT |
266 | ClrDataAccess::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 | |
282 | HRESULT |
283 | ClrDataAccess::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 | |
301 | HRESULT |
302 | ClrDataAccess::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 | |
364 | HRESULT 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 | |
393 | HRESULT |
394 | ClrDataAccess::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 | |
413 | HRESULT |
414 | ClrDataAccess::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 | |
453 | HRESULT |
454 | ClrDataAccess::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 | |
492 | HRESULT |
493 | ClrDataAccess::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 | |
556 | HRESULT |
557 | ClrDataAccess::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 | |
581 | HRESULT |
582 | ClrDataAccess::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 | |
652 | HRESULT |
653 | ClrDataAccess::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 | |
684 | HRESULT |
685 | ClrDataAccess::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 | |
700 | HRESULT |
701 | ClrDataAccess::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 | |
717 | HRESULT |
718 | ClrDataAccess::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 | |
751 | HRESULT |
752 | ClrDataAccess::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 |
799 | void 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 | |
853 | HRESULT 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 | |
1069 | HRESULT 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 | |
1181 | cleanup: |
1182 | ; |
1183 | #endif // FEATURE_REJIT |
1184 | |
1185 | SOSDacLeave(); |
1186 | return hr; |
1187 | } |
1188 | |
1189 | HRESULT |
1190 | ClrDataAccess::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 | |
1211 | HRESULT |
1212 | ClrDataAccess::(CLRDATA_ADDRESS ip, struct DacpCodeHeaderData *) |
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 | |
1263 | HRESULT |
1264 | ClrDataAccess::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 | |
1287 | HRESULT |
1288 | ClrDataAccess::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 | |
1319 | HRESULT |
1320 | ClrDataAccess::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 | |
1412 | HRESULT |
1413 | ClrDataAccess::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 | |
1427 | HRESULT |
1428 | ClrDataAccess::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 | |
1479 | HRESULT |
1480 | ClrDataAccess::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 | |
1534 | HRESULT |
1535 | ClrDataAccess::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 | |
1569 | HRESULT |
1570 | ClrDataAccess::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 | |
1616 | HRESULT |
1617 | ClrDataAccess::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 | |
1631 | HRESULT |
1632 | ClrDataAccess::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 | |
1688 | HRESULT |
1689 | ClrDataAccess::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 | |
1703 | HRESULT |
1704 | ClrDataAccess::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 | |
1746 | HRESULT |
1747 | ClrDataAccess::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 | |
1828 | HRESULT |
1829 | ClrDataAccess::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 | |
1907 | HRESULT |
1908 | ClrDataAccess::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 | |
1937 | HRESULT |
1938 | ClrDataAccess::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 | |
1964 | HRESULT |
1965 | ClrDataAccess::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 | |
1987 | HRESULT |
1988 | ClrDataAccess::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 | |
2009 | HRESULT |
2010 | ClrDataAccess::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 | |
2049 | HRESULT |
2050 | ClrDataAccess::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 | |
2107 | HRESULT |
2108 | ClrDataAccess::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 | |
2129 | DWORD 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 | |
2145 | HRESULT |
2146 | ClrDataAccess::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 | |
2257 | HRESULT 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 | |
2277 | HRESULT |
2278 | ClrDataAccess::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 | |
2295 | HRESULT |
2296 | ClrDataAccess::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 | |
2353 | HRESULT |
2354 | ClrDataAccess::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 | |
2378 | HRESULT |
2379 | ClrDataAccess::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 | |
2409 | HRESULT |
2410 | ClrDataAccess::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 | |
2439 | HRESULT |
2440 | ClrDataAccess::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 | |
2490 | HRESULT |
2491 | ClrDataAccess::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 | |
2519 | HRESULT |
2520 | ClrDataAccess::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 | |
2559 | HRESULT |
2560 | ClrDataAccess::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 | |
2568 | HRESULT |
2569 | ClrDataAccess::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 | |
2577 | HRESULT |
2578 | ClrDataAccess::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 | |
2586 | HRESULT |
2587 | ClrDataAccess::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 | |
2630 | HRESULT |
2631 | ClrDataAccess::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 | |
2671 | HRESULT |
2672 | ClrDataAccess::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 | |
2705 | HRESULT |
2706 | ClrDataAccess::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 | |
2734 | HRESULT |
2735 | ClrDataAccess::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 | |
2756 | HRESULT |
2757 | ClrDataAccess::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 | |
2804 | HRESULT |
2805 | ClrDataAccess::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 | |
2846 | HRESULT |
2847 | ClrDataAccess::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 | |
2880 | HRESULT |
2881 | ClrDataAccess::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 | |
2929 | cleanup: |
2930 | ; |
2931 | |
2932 | SOSDacLeave(); |
2933 | return hr; |
2934 | } |
2935 | |
2936 | HRESULT |
2937 | ClrDataAccess::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 | |
2966 | HRESULT |
2967 | ClrDataAccess::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 | |
2990 | HRESULT |
2991 | ClrDataAccess::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 | |
3012 | HRESULT |
3013 | ClrDataAccess::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 | |
3051 | HRESULT |
3052 | ClrDataAccess::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 | |
3079 | HRESULT |
3080 | ClrDataAccess::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 | |
3102 | HRESULT |
3103 | ClrDataAccess::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 | |
3118 | HRESULT |
3119 | ClrDataAccess::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 | |
3142 | HRESULT |
3143 | ClrDataAccess::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 | |
3171 | HRESULT |
3172 | ClrDataAccess::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 | |
3191 | HRESULT |
3192 | ClrDataAccess::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 | |
3217 | HRESULT |
3218 | ClrDataAccess::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 | |
3250 | HRESULT |
3251 | ClrDataAccess::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 | |
3281 | HRESULT 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 | |
3293 | HRESULT 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 | |
3314 | HRESULT 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 | |
3341 | HRESULT |
3342 | ClrDataAccess::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 | |
3422 | HRESULT |
3423 | ClrDataAccess::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 | |
3463 | HRESULT |
3464 | ClrDataAccess::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 | |
3489 | HRESULT |
3490 | ClrDataAccess::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 | |
3548 | HRESULT |
3549 | ClrDataAccess::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 | |
3611 | HRESULT |
3612 | ClrDataAccess::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 | |
3657 | HRESULT |
3658 | ClrDataAccess::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 | |
3687 | HRESULT |
3688 | ClrDataAccess::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 |
3711 | STDMETHODIMP |
3712 | ClrDataAccess::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 | |
3761 | void |
3762 | ClrDataAccess::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 | |
3799 | HRESULT |
3800 | ClrDataAccess::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 | |
3821 | HRESULT 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 | |
3894 | HRESULT 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 | |
3914 | HRESULT ClrDataAccess::GetDacModuleHandle(HMODULE *phModule) |
3915 | { |
3916 | if(phModule == NULL) |
3917 | return E_INVALIDARG; |
3918 | *phModule = GetModuleInst(); |
3919 | return S_OK; |
3920 | } |
3921 | |
3922 | HRESULT 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 | |
3971 | HRESULT 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 |
4038 | PTR_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 | |
4086 | PTR_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 | |
4104 | HRESULT 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 | |
4151 | HRESULT 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 | |
4237 | HRESULT 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 | |
4260 | HRESULT 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 | |
4283 | HRESULT 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 | |