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
6/*
7 *
8 * COM+99 EE to Debugger Interface Implementation
9 *
10 */
11
12#include "common.h"
13#include "dbginterface.h"
14#include "eedbginterfaceimpl.h"
15#include "virtualcallstub.h"
16#include "contractimpl.h"
17
18#ifdef DEBUGGING_SUPPORTED
19
20#ifndef DACCESS_COMPILE
21
22//
23// Cleanup any global data used by this interface.
24//
25void EEDbgInterfaceImpl::Terminate(void)
26{
27 CONTRACTL
28 {
29 SO_INTOLERANT;
30 NOTHROW;
31 GC_NOTRIGGER;
32 }
33 CONTRACTL_END;
34
35 if (g_pEEDbgInterfaceImpl)
36 {
37 delete g_pEEDbgInterfaceImpl;
38 g_pEEDbgInterfaceImpl = NULL;
39 }
40}
41
42#endif // #ifndef DACCESS_COMPILE
43
44Thread* EEDbgInterfaceImpl::GetThread(void)
45{
46 LIMITED_METHOD_CONTRACT;
47// Since this may be called from a Debugger Interop Hijack, the EEThread may be bogus.
48// Thus we can't use contracts. If we do fix that, then the contract below would be nice...
49#if 0
50 CONTRACT(Thread *)
51 {
52 NOTHROW;
53 GC_NOTRIGGER;
54 POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
55 }
56 CONTRACT_END;
57#endif
58
59 return ::GetThread();
60}
61
62#ifndef DACCESS_COMPILE
63
64StackWalkAction EEDbgInterfaceImpl::StackWalkFramesEx(Thread* pThread,
65 PREGDISPLAY pRD,
66 PSTACKWALKFRAMESCALLBACK pCallback,
67 VOID* pData,
68 unsigned int flags)
69{
70 CONTRACTL
71 {
72 DISABLED(NOTHROW); // FIX THIS when StackWalkFramesEx gets fixed.
73 DISABLED(GC_TRIGGERS); // We cannot predict if pCallback will trigger or not.
74 // Disabled is not a bug in this case.
75 PRECONDITION(CheckPointer(pThread));
76 }
77 CONTRACTL_END;
78
79 return pThread->StackWalkFramesEx(pRD, pCallback, pData, flags);
80}
81
82Frame *EEDbgInterfaceImpl::GetFrame(CrawlFrame *pCF)
83{
84 CONTRACT(Frame *)
85 {
86 SO_NOT_MAINLINE;
87 NOTHROW;
88 GC_NOTRIGGER;
89 PRECONDITION(CheckPointer(pCF));
90 POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
91 }
92 CONTRACT_END;
93
94 RETURN pCF->GetFrame();
95}
96
97bool EEDbgInterfaceImpl::InitRegDisplay(Thread* pThread,
98 const PREGDISPLAY pRD,
99 const PCONTEXT pctx,
100 bool validContext)
101{
102 CONTRACTL
103 {
104 SO_NOT_MAINLINE;
105 NOTHROW;
106 GC_NOTRIGGER;
107 PRECONDITION(CheckPointer(pThread));
108 PRECONDITION(CheckPointer(pRD));
109 if (validContext)
110 {
111 PRECONDITION(CheckPointer(pctx));
112 }
113 }
114 CONTRACTL_END;
115
116 return pThread->InitRegDisplay(pRD, pctx, validContext);
117}
118
119BOOL EEDbgInterfaceImpl::IsStringObject(Object* o)
120{
121 CONTRACTL
122 {
123 SO_NOT_MAINLINE;
124 THROWS;
125 GC_NOTRIGGER;
126 PRECONDITION(CheckPointer(o));
127 }
128 CONTRACTL_END;
129
130 return o->GetMethodTable() == g_pStringClass;
131}
132
133BOOL EEDbgInterfaceImpl::IsTypedReference(MethodTable* pMT)
134{
135 CONTRACTL
136 {
137 SO_NOT_MAINLINE;
138 THROWS;
139 GC_NOTRIGGER;
140 PRECONDITION(CheckPointer(pMT));
141 }
142 CONTRACTL_END;
143
144 return pMT == g_TypedReferenceMT;
145}
146
147WCHAR* EEDbgInterfaceImpl::StringObjectGetBuffer(StringObject* so)
148{
149 CONTRACTL
150 {
151 SO_NOT_MAINLINE;
152 NOTHROW;
153 GC_NOTRIGGER;
154 PRECONDITION(CheckPointer(so));
155 }
156 CONTRACTL_END;
157
158 return so->GetBuffer();
159}
160
161DWORD EEDbgInterfaceImpl::StringObjectGetStringLength(StringObject* so)
162{
163 CONTRACTL
164 {
165 SO_NOT_MAINLINE;
166 NOTHROW;
167 GC_NOTRIGGER;
168 PRECONDITION(CheckPointer(so));
169 }
170 CONTRACTL_END;
171
172 return so->GetStringLength();
173}
174
175void* EEDbgInterfaceImpl::GetObjectFromHandle(OBJECTHANDLE handle)
176{
177 CONTRACTL
178 {
179 SO_NOT_MAINLINE;
180 NOTHROW;
181 GC_NOTRIGGER;
182 }
183 CONTRACTL_END;
184
185 void *v;
186
187 *((OBJECTREF *)&v) = *(OBJECTREF *)handle;
188
189 return v;
190}
191
192OBJECTHANDLE EEDbgInterfaceImpl::GetHandleFromObject(void *obj,
193 bool fStrongNewRef,
194 AppDomain *pAppDomain)
195{
196 CONTRACTL
197 {
198 SO_NOT_MAINLINE;
199 THROWS; // From CreateHandle
200 GC_NOTRIGGER;
201 PRECONDITION(CheckPointer(pAppDomain));
202 }
203 CONTRACTL_END;
204
205 OBJECTHANDLE oh;
206
207 if (fStrongNewRef)
208 {
209 oh = pAppDomain->CreateStrongHandle(ObjectToOBJECTREF((Object *)obj));
210
211 LOG((LF_CORDB, LL_INFO1000, "EEI::GHFO: Given objectref 0x%x,"
212 "created strong handle 0x%x!\n", obj, oh));
213 }
214 else
215 {
216 oh = pAppDomain->CreateLongWeakHandle( ObjectToOBJECTREF((Object *)obj));
217
218 LOG((LF_CORDB, LL_INFO1000, "EEI::GHFO: Given objectref 0x%x,"
219 "created long weak handle 0x%x!\n", obj, oh));
220 }
221
222 return oh;
223}
224
225void EEDbgInterfaceImpl::DbgDestroyHandle(OBJECTHANDLE oh,
226 bool fStrongNewRef)
227{
228 CONTRACTL
229 {
230 SO_NOT_MAINLINE;
231 NOTHROW;
232 GC_NOTRIGGER;
233 }
234 CONTRACTL_END;
235
236 LOG((LF_CORDB, LL_INFO1000, "EEI::GHFO: Destroyed given handle 0x%x,"
237 "fStrong: 0x%x!\n", oh, fStrongNewRef));
238
239 if (fStrongNewRef)
240 {
241 DestroyStrongHandle(oh);
242 }
243 else
244 {
245 DestroyLongWeakHandle(oh);
246 }
247}
248
249
250OBJECTHANDLE EEDbgInterfaceImpl::GetThreadException(Thread *pThread)
251{
252 CONTRACTL
253 {
254 NOTHROW;
255 GC_NOTRIGGER;
256 PRECONDITION(CheckPointer(pThread));
257 }
258 CONTRACTL_END;
259
260 OBJECTHANDLE oh = pThread->GetThrowableAsHandle();
261
262 if (oh != NULL)
263 {
264 return oh;
265 }
266
267 // Return the last thrown object if there's no current throwable.
268 // This logic is similar to UpdateCurrentThrowable().
269 return pThread->m_LastThrownObjectHandle;
270}
271
272bool EEDbgInterfaceImpl::IsThreadExceptionNull(Thread *pThread)
273{
274 CONTRACTL
275 {
276 SO_TOLERANT;
277 NOTHROW;
278 GC_NOTRIGGER;
279 PRECONDITION(CheckPointer(pThread));
280 }
281 CONTRACTL_END;
282
283 //
284 // We're assuming that the handle on the
285 // thread is a strong handle and we're goona check it for
286 // NULL. We're also assuming something about the
287 // implementation of the handle here, too.
288 //
289 OBJECTHANDLE h = pThread->GetThrowableAsHandle();
290 if (h == NULL)
291 {
292 return true;
293 }
294
295 void *pThrowable = *((void**)h);
296
297 return (pThrowable == NULL);
298}
299
300void EEDbgInterfaceImpl::ClearThreadException(Thread *pThread)
301{
302 //
303 // If one day there is a continuable exception, then this will have to be
304 // implemented properly.
305 //
306 //
307 LIMITED_METHOD_CONTRACT;
308}
309
310bool EEDbgInterfaceImpl::StartSuspendForDebug(AppDomain *pAppDomain,
311 BOOL fHoldingThreadStoreLock)
312{
313 CONTRACTL
314 {
315 SO_NOT_MAINLINE;
316 NOTHROW;
317 GC_NOTRIGGER;
318 }
319 CONTRACTL_END;
320
321 LOG((LF_CORDB,LL_INFO1000, "EEDbgII:SSFD: start suspend on AD:0x%x\n",
322 pAppDomain));
323
324 bool result = Thread::SysStartSuspendForDebug(pAppDomain);
325
326 return result;
327}
328
329bool EEDbgInterfaceImpl::SweepThreadsForDebug(bool forceSync)
330{
331 CONTRACTL
332 {
333 SO_NOT_MAINLINE;
334 NOTHROW;
335 DISABLED(GC_TRIGGERS); // Called by unmanaged threads.
336 }
337 CONTRACTL_END;
338
339 return Thread::SysSweepThreadsForDebug(forceSync);
340}
341
342void EEDbgInterfaceImpl::ResumeFromDebug(AppDomain *pAppDomain)
343{
344 CONTRACTL
345 {
346 SO_NOT_MAINLINE;
347 NOTHROW;
348 GC_NOTRIGGER;
349 }
350 CONTRACTL_END;
351
352 Thread::SysResumeFromDebug(pAppDomain);
353}
354
355void EEDbgInterfaceImpl::MarkThreadForDebugSuspend(Thread* pRuntimeThread)
356{
357 CONTRACTL
358 {
359 SO_NOT_MAINLINE;
360 NOTHROW;
361 GC_NOTRIGGER;
362 PRECONDITION(CheckPointer(pRuntimeThread));
363 }
364 CONTRACTL_END;
365
366 pRuntimeThread->MarkForDebugSuspend();
367}
368
369void EEDbgInterfaceImpl::MarkThreadForDebugStepping(Thread* pRuntimeThread,
370 bool onOff)
371{
372 CONTRACTL
373 {
374 SO_NOT_MAINLINE;
375 NOTHROW;
376 GC_NOTRIGGER;
377 PRECONDITION(CheckPointer(pRuntimeThread));
378 }
379 CONTRACTL_END;
380
381 pRuntimeThread->MarkDebuggerIsStepping(onOff);
382}
383
384void EEDbgInterfaceImpl::SetThreadFilterContext(Thread *thread,
385 CONTEXT *context)
386{
387 CONTRACTL
388 {
389 SO_NOT_MAINLINE;
390 NOTHROW;
391 GC_NOTRIGGER;
392 PRECONDITION(CheckPointer(thread));
393 }
394 CONTRACTL_END;
395
396 thread->SetFilterContext(context);
397}
398
399CONTEXT *EEDbgInterfaceImpl::GetThreadFilterContext(Thread *thread)
400{
401 CONTRACT(CONTEXT *)
402 {
403 NOTHROW;
404 GC_NOTRIGGER;
405 PRECONDITION(CheckPointer(thread));
406 POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
407 }
408 CONTRACT_END;
409
410 RETURN thread->GetFilterContext();
411}
412
413#ifdef FEATURE_INTEROP_DEBUGGING
414
415VOID * EEDbgInterfaceImpl::GetThreadDebuggerWord()
416{
417 return UnsafeTlsGetValue(g_debuggerWordTLSIndex);
418}
419
420void EEDbgInterfaceImpl::SetThreadDebuggerWord(VOID *dw)
421{
422 UnsafeTlsSetValue(g_debuggerWordTLSIndex, dw);
423}
424
425#endif
426
427BOOL EEDbgInterfaceImpl::IsManagedNativeCode(const BYTE *address)
428{
429 WRAPPER_NO_CONTRACT;
430 return ExecutionManager::IsManagedCode((PCODE)address);
431}
432
433PCODE EEDbgInterfaceImpl::GetNativeCodeStartAddress(PCODE address)
434{
435 WRAPPER_NO_CONTRACT;
436 _ASSERTE(address != NULL);
437
438 return ExecutionManager::GetCodeStartAddress(address);
439}
440
441MethodDesc *EEDbgInterfaceImpl::GetNativeCodeMethodDesc(const PCODE address)
442{
443 CONTRACT(MethodDesc *)
444 {
445 NOTHROW;
446 GC_NOTRIGGER;
447 PRECONDITION(address != NULL);
448 POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
449 }
450 CONTRACT_END;
451
452 RETURN ExecutionManager::GetCodeMethodDesc(address);
453}
454
455#ifndef USE_GC_INFO_DECODER
456// IsInPrologOrEpilog doesn't seem to be used for code that uses GC_INFO_DECODER
457BOOL EEDbgInterfaceImpl::IsInPrologOrEpilog(const BYTE *address,
458 size_t* prologSize)
459{
460 CONTRACTL
461 {
462 SO_NOT_MAINLINE;
463 NOTHROW;
464 GC_NOTRIGGER;
465 }
466 CONTRACTL_END;
467
468 *prologSize = 0;
469
470 EECodeInfo codeInfo((PCODE)address);
471
472 if (codeInfo.IsValid())
473 {
474 GCInfoToken gcInfoToken = codeInfo.GetGCInfoToken();
475
476 if (codeInfo.GetCodeManager()->IsInPrologOrEpilog(codeInfo.GetRelOffset(), gcInfoToken, prologSize))
477 {
478 return TRUE;
479 }
480 }
481
482 return FALSE;
483}
484#endif // USE_GC_INFO_DECODER
485
486//
487// Given a collection of native offsets of a certain function, determine if each falls
488// within an exception filter or handler.
489//
490void EEDbgInterfaceImpl::DetermineIfOffsetsInFilterOrHandler(const BYTE *functionAddress,
491 DebugOffsetToHandlerInfo *pOffsetToHandlerInfo,
492 unsigned offsetToHandlerInfoLength)
493{
494 CONTRACTL
495 {
496 SO_NOT_MAINLINE;
497 NOTHROW;
498 GC_NOTRIGGER;
499 }
500 CONTRACTL_END;
501
502 EECodeInfo codeInfo((PCODE)functionAddress);
503
504 if (!codeInfo.IsValid())
505 {
506 return;
507 }
508
509 // Loop through all the exception handling clause information for the method
510 EH_CLAUSE_ENUMERATOR pEnumState;
511 unsigned EHCount = codeInfo.GetJitManager()->InitializeEHEnumeration(codeInfo.GetMethodToken(), &pEnumState);
512 if (EHCount == 0)
513 {
514 return;
515 }
516
517 for (ULONG i=0; i < EHCount; i++)
518 {
519 EE_ILEXCEPTION_CLAUSE EHClause;
520 codeInfo.GetJitManager()->GetNextEHClause(&pEnumState, &EHClause);
521
522 // Check each EH clause against each offset of interest.
523 // Note that this could be time consuming for very long methods ( O(n^2) ).
524 // We could make this linear if we could guarentee that the two lists are sorted.
525 for (ULONG j=0; j < offsetToHandlerInfoLength; j++)
526 {
527 SIZE_T offs = pOffsetToHandlerInfo[j].offset;
528
529 // those with -1 indicate slots to skip
530 if (offs == (SIZE_T) -1)
531 {
532 continue;
533 }
534 // For a filter, the handler comes directly after it so check from start of filter
535 // to end of handler
536 if (IsFilterHandler(&EHClause))
537 {
538 if (offs >= EHClause.FilterOffset && offs < EHClause.HandlerEndPC)
539 {
540 pOffsetToHandlerInfo[j].isInFilterOrHandler = TRUE;
541 }
542 }
543 // For anything else, only care about handler range
544 else if (offs >= EHClause.HandlerStartPC && offs < EHClause.HandlerEndPC)
545 {
546 pOffsetToHandlerInfo[j].isInFilterOrHandler = TRUE;
547 }
548 }
549 }
550}
551#endif // #ifndef DACCESS_COMPILE
552
553void EEDbgInterfaceImpl::GetMethodRegionInfo(const PCODE pStart,
554 PCODE * pCold,
555 size_t *hotSize,
556 size_t *coldSize)
557{
558 CONTRACTL
559 {
560 SO_INTOLERANT;
561 NOTHROW;
562 GC_NOTRIGGER;
563 PRECONDITION(CheckPointer(pCold));
564 PRECONDITION(CheckPointer(hotSize));
565 PRECONDITION(CheckPointer(coldSize));
566 SUPPORTS_DAC;
567 }
568 CONTRACTL_END;
569
570 IJitManager::MethodRegionInfo methodRegionInfo = {NULL, 0, NULL, 0};
571
572 EECodeInfo codeInfo(pStart);
573
574 if (codeInfo.IsValid() != NULL)
575 {
576 codeInfo.GetMethodRegionInfo(&methodRegionInfo);
577 }
578
579 *pCold = methodRegionInfo.coldStartAddress;
580 *hotSize = methodRegionInfo.hotSize;
581 *coldSize = methodRegionInfo.coldSize;
582}
583
584#if defined(WIN64EXCEPTIONS)
585DWORD EEDbgInterfaceImpl::GetFuncletStartOffsets(const BYTE *pStart, DWORD* pStartOffsets, DWORD dwLength)
586{
587 CONTRACTL
588 {
589 NOTHROW;
590 GC_NOTRIGGER;
591 PRECONDITION(CheckPointer(pStart));
592 }
593 CONTRACTL_END;
594
595 EECodeInfo codeInfo((PCODE)pStart);
596 _ASSERTE(codeInfo.IsValid());
597
598 return codeInfo.GetJitManager()->GetFuncletStartOffsets(codeInfo.GetMethodToken(), pStartOffsets, dwLength);
599}
600
601StackFrame EEDbgInterfaceImpl::FindParentStackFrame(CrawlFrame* pCF)
602{
603 CONTRACTL
604 {
605 NOTHROW;
606 GC_NOTRIGGER;
607 PRECONDITION(CheckPointer(pCF));
608 }
609 CONTRACTL_END;
610
611#if defined(DACCESS_COMPILE)
612 DacNotImpl();
613 return StackFrame();
614
615#else // !DACCESS_COMPILE
616 return ExceptionTracker::FindParentStackFrameForStackWalk(pCF);
617
618#endif // !DACCESS_COMPILE
619}
620#endif // WIN64EXCEPTIONS
621
622#ifndef DACCESS_COMPILE
623size_t EEDbgInterfaceImpl::GetFunctionSize(MethodDesc *pFD)
624{
625 CONTRACTL
626 {
627 NOTHROW;
628 GC_NOTRIGGER;
629 PRECONDITION(CheckPointer(pFD));
630 }
631 CONTRACTL_END;
632
633 PCODE methodStart = pFD->GetNativeCode();
634
635 if (methodStart == NULL)
636 return 0;
637
638 EECodeInfo codeInfo(methodStart);
639 GCInfoToken gcInfoToken = codeInfo.GetGCInfoToken();
640 return codeInfo.GetCodeManager()->GetFunctionSize(gcInfoToken);
641}
642#endif //!DACCESS_COMPILE
643
644PCODE EEDbgInterfaceImpl::GetFunctionAddress(MethodDesc *pFD)
645{
646 CONTRACTL
647 {
648 NOTHROW;
649 GC_NOTRIGGER;
650 PRECONDITION(CheckPointer(pFD));
651 SUPPORTS_DAC;
652 }
653 CONTRACTL_END;
654
655 return pFD->GetNativeCode();
656}
657
658#ifndef DACCESS_COMPILE
659
660void EEDbgInterfaceImpl::DisablePreemptiveGC(void)
661{
662 CONTRACTL
663 {
664 SO_INTOLERANT;
665 NOTHROW;
666 DISABLED(GC_TRIGGERS); // Disabled because disabled in RareDisablePreemptiveGC()
667 }
668 CONTRACTL_END;
669
670 ::GetThread()->DisablePreemptiveGC();
671}
672
673void EEDbgInterfaceImpl::EnablePreemptiveGC(void)
674{
675 CONTRACTL
676 {
677 SO_INTOLERANT;
678 NOTHROW;
679 DISABLED(GC_TRIGGERS); // Disabled because disabled in RareEnablePreemptiveGC()
680 }
681 CONTRACTL_END;
682
683 ::GetThread()->EnablePreemptiveGC();
684}
685
686bool EEDbgInterfaceImpl::IsPreemptiveGCDisabled(void)
687{
688 CONTRACTL
689 {
690 SO_TOLERANT;
691 NOTHROW;
692 GC_NOTRIGGER;
693 }
694 CONTRACTL_END;
695
696 return ::GetThread()->PreemptiveGCDisabled() != 0;
697}
698
699DWORD EEDbgInterfaceImpl::MethodDescIsStatic(MethodDesc *pFD)
700{
701 CONTRACTL
702 {
703 NOTHROW;
704 GC_NOTRIGGER;
705 PRECONDITION(CheckPointer(pFD));
706 }
707 CONTRACTL_END;
708
709 return pFD->IsStatic();
710}
711
712#endif // #ifndef DACCESS_COMPILE
713
714Module *EEDbgInterfaceImpl::MethodDescGetModule(MethodDesc *pFD)
715{
716 CONTRACT(Module *)
717 {
718 NOTHROW;
719 GC_NOTRIGGER;
720 PRECONDITION(CheckPointer(pFD));
721 POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
722 }
723 CONTRACT_END;
724
725 RETURN pFD->GetModule();
726}
727
728#ifndef DACCESS_COMPILE
729
730COR_ILMETHOD* EEDbgInterfaceImpl::MethodDescGetILHeader(MethodDesc *pFD)
731{
732 CONTRACT(COR_ILMETHOD *)
733 {
734 THROWS;
735 GC_NOTRIGGER;
736 PRECONDITION(CheckPointer(pFD));
737 POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
738 }
739 CONTRACT_END;
740
741 if (pFD->IsIL())
742 {
743 RETURN pFD->GetILHeader();
744 }
745
746 RETURN NULL;
747}
748
749ULONG EEDbgInterfaceImpl::MethodDescGetRVA(MethodDesc *pFD)
750{
751 CONTRACTL
752 {
753 SO_NOT_MAINLINE;
754 NOTHROW;
755 GC_NOTRIGGER;
756 PRECONDITION(CheckPointer(pFD));
757 }
758 CONTRACTL_END;
759
760 return pFD->GetRVA();
761}
762
763MethodDesc *EEDbgInterfaceImpl::FindLoadedMethodRefOrDef(Module* pModule,
764 mdToken memberRef)
765{
766 CONTRACT(MethodDesc *)
767 {
768 NOTHROW;
769 GC_NOTRIGGER;
770 PRECONDITION(CheckPointer(pModule));
771 POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
772 }
773 CONTRACT_END;
774
775 // Must have a MemberRef or a MethodDef
776 mdToken tkType = TypeFromToken(memberRef);
777 _ASSERTE((tkType == mdtMemberRef) || (tkType == mdtMethodDef));
778
779 if (tkType == mdtMemberRef)
780 {
781 RETURN pModule->LookupMemberRefAsMethod(memberRef);
782 }
783
784 RETURN pModule->LookupMethodDef(memberRef);
785}
786
787MethodDesc *EEDbgInterfaceImpl::LoadMethodDef(Module* pModule,
788 mdMethodDef methodDef,
789 DWORD numGenericArgs,
790 TypeHandle *pGenericArgs,
791 TypeHandle *pOwnerType)
792{
793 CONTRACT(MethodDesc *)
794 {
795 THROWS;
796 GC_TRIGGERS;
797 PRECONDITION(CheckPointer(pModule));
798 POSTCONDITION(CheckPointer(RETVAL));
799 }
800 CONTRACT_END;
801
802 _ASSERTE(TypeFromToken(methodDef) == mdtMethodDef);
803
804 // The generic class and method args are sent as one array
805 // by the debugger. We now split this into two by finding out how
806 // many generic args are for the class and how many for the
807 // method. The actual final checks are done in MemberLoader::GetMethodDescFromMethodDef.
808
809 DWORD numGenericClassArgs = 0;
810 TypeHandle *pGenericClassArgs = NULL;
811 DWORD nGenericMethodArgs = 0;
812 TypeHandle *pGenericMethodArgs = NULL;
813 mdTypeDef typeDef = 0;
814
815 TypeHandle thOwner;
816
817 BOOL forceRemotable = FALSE;
818 if (numGenericArgs != 0)
819 {
820 HRESULT hr = pModule->GetMDImport()->GetParentToken(methodDef, &typeDef);
821 if (FAILED(hr))
822 COMPlusThrowHR(E_INVALIDARG);
823
824 TypeHandle thClass = LoadClass(pModule, typeDef);
825 _ASSERTE(!thClass.IsNull());
826
827 numGenericClassArgs = thClass.GetNumGenericArgs();
828 if (numGenericArgs < numGenericClassArgs)
829 {
830 COMPlusThrowHR(COR_E_TARGETPARAMCOUNT);
831 }
832 pGenericClassArgs = (numGenericClassArgs > 0) ? pGenericArgs : NULL;
833 nGenericMethodArgs = (numGenericArgs >= numGenericClassArgs) ? (numGenericArgs - numGenericClassArgs) : 0;
834 pGenericMethodArgs = (nGenericMethodArgs > 0) ? (pGenericArgs + numGenericClassArgs) : NULL;
835
836#ifdef FEATURE_COMINTEROP
837 if (numGenericClassArgs > 0)
838 {
839 thOwner = ClassLoader::LoadGenericInstantiationThrowing(pModule, typeDef, Instantiation(pGenericClassArgs, numGenericClassArgs));
840 // for classes supporting generic interop force remotable method descs
841 forceRemotable = thOwner.GetMethodTable()->SupportsGenericInterop(TypeHandle::Interop_ManagedToNative);
842 }
843#endif // FEATURE_COMINTEROP
844 }
845
846 MethodDesc *pRes = MemberLoader::GetMethodDescFromMethodDef(pModule,
847 methodDef,
848 Instantiation(pGenericClassArgs, numGenericClassArgs),
849 Instantiation(pGenericMethodArgs, nGenericMethodArgs),
850 forceRemotable);
851
852 // The ownerType is extra information that augments the specification of an interface MD.
853 // It is only needed if generics code sharing is supported, because otherwise MDs are
854 // fully self-describing.
855 if (pOwnerType != NULL)
856 {
857 if (numGenericClassArgs != 0)
858 {
859 if (thOwner.IsNull())
860 *pOwnerType = ClassLoader::LoadGenericInstantiationThrowing(pModule, typeDef, Instantiation(pGenericClassArgs, numGenericClassArgs));
861 else
862 *pOwnerType = thOwner;
863 }
864 else
865 {
866 *pOwnerType = TypeHandle(pRes->GetMethodTable());
867 }
868 }
869 RETURN (pRes);
870
871}
872
873
874TypeHandle EEDbgInterfaceImpl::FindLoadedClass(Module *pModule,
875 mdTypeDef classToken)
876{
877 CONTRACT(TypeHandle)
878 {
879 NOTHROW;
880 GC_NOTRIGGER;
881 PRECONDITION(CheckPointer(pModule));
882 }
883 CONTRACT_END;
884
885 RETURN ClassLoader::LookupTypeDefOrRefInModule(pModule, classToken);
886
887}
888
889TypeHandle EEDbgInterfaceImpl::FindLoadedInstantiation(Module *pModule,
890 mdTypeDef typeDef,
891 DWORD ntypars,
892 TypeHandle *inst)
893{
894 // Lookup operations run the class loader in non-load mode.
895 ENABLE_FORBID_GC_LOADER_USE_IN_THIS_SCOPE();
896
897
898 // scan violation: asserts that this can be suppressed since there is currently
899 // work on dac-izing all this code and as a result the issue will become moot.
900 CONTRACT_VIOLATION(FaultViolation);
901
902 return ClassLoader::LoadGenericInstantiationThrowing(pModule, typeDef, Instantiation(inst, ntypars),
903 ClassLoader::DontLoadTypes);
904}
905
906TypeHandle EEDbgInterfaceImpl::FindLoadedFnptrType(TypeHandle *inst,
907 DWORD ntypars)
908{
909 // Lookup operations run the class loader in non-load mode.
910 ENABLE_FORBID_GC_LOADER_USE_IN_THIS_SCOPE();
911
912 //<TODO> : CALLCONV? </TODO>
913 return ClassLoader::LoadFnptrTypeThrowing(0, ntypars, inst,
914 // <TODO> should this be FailIfNotLoaded? - NO - although we may
915 // want to debug unrestored VCs, we can't do it because the debug API
916 // is not set up to handle them </TODO>
917 // == FailIfNotLoadedOrNotRestored
918 ClassLoader::DontLoadTypes);
919}
920
921TypeHandle EEDbgInterfaceImpl::FindLoadedPointerOrByrefType(CorElementType et,
922 TypeHandle elemtype)
923{
924 // Lookup operations run the class loader in non-load mode.
925 ENABLE_FORBID_GC_LOADER_USE_IN_THIS_SCOPE();
926
927 return ClassLoader::LoadPointerOrByrefTypeThrowing(et, elemtype,
928 // <TODO> should this be FailIfNotLoaded? - NO - although we may
929 // want to debug unrestored VCs, we can't do it because the debug API
930 // is not set up to handle them </TODO>
931 // == FailIfNotLoadedOrNotRestored
932 ClassLoader::DontLoadTypes);
933}
934
935TypeHandle EEDbgInterfaceImpl::FindLoadedArrayType(CorElementType et,
936 TypeHandle elemtype,
937 unsigned rank)
938{
939 // Lookup operations run the class loader in non-load mode.
940 ENABLE_FORBID_GC_LOADER_USE_IN_THIS_SCOPE();
941
942 if (elemtype.IsNull())
943 return TypeHandle();
944 else
945 return ClassLoader::LoadArrayTypeThrowing(elemtype, et, rank,
946 // <TODO> should this be FailIfNotLoaded? - NO - although we may
947 // want to debug unrestored VCs, we can't do it because the debug API
948 // is not set up to handle them </TODO>
949 // == FailIfNotLoadedOrNotRestored
950 ClassLoader::DontLoadTypes );
951}
952
953
954TypeHandle EEDbgInterfaceImpl::FindLoadedElementType(CorElementType et)
955{
956 // Lookup operations run the class loader in non-load mode.
957 ENABLE_FORBID_GC_LOADER_USE_IN_THIS_SCOPE();
958
959 MethodTable *m = MscorlibBinder::GetElementType(et);
960
961 return TypeHandle(m);
962}
963
964TypeHandle EEDbgInterfaceImpl::LoadClass(Module *pModule,
965 mdTypeDef classToken)
966{
967 CONTRACT(TypeHandle)
968 {
969 THROWS;
970 GC_TRIGGERS;
971 PRECONDITION(CheckPointer(pModule));
972 }
973 CONTRACT_END;
974
975 RETURN ClassLoader::LoadTypeDefOrRefThrowing(pModule, classToken,
976 ClassLoader::ThrowIfNotFound,
977 ClassLoader::PermitUninstDefOrRef);
978
979}
980
981TypeHandle EEDbgInterfaceImpl::LoadInstantiation(Module *pModule,
982 mdTypeDef typeDef,
983 DWORD ntypars,
984 TypeHandle *inst)
985{
986 CONTRACT(TypeHandle)
987 {
988 THROWS;
989 GC_TRIGGERS;
990 PRECONDITION(CheckPointer(pModule));
991 }
992 CONTRACT_END;
993
994 RETURN ClassLoader::LoadGenericInstantiationThrowing(pModule, typeDef, Instantiation(inst, ntypars));
995}
996
997TypeHandle EEDbgInterfaceImpl::LoadArrayType(CorElementType et,
998 TypeHandle elemtype,
999 unsigned rank)
1000{
1001 CONTRACT(TypeHandle)
1002 {
1003 THROWS;
1004 GC_TRIGGERS;
1005 }
1006 CONTRACT_END;
1007
1008 if (elemtype.IsNull())
1009 RETURN TypeHandle();
1010 else
1011 RETURN ClassLoader::LoadArrayTypeThrowing(elemtype, et, rank);
1012}
1013
1014TypeHandle EEDbgInterfaceImpl::LoadPointerOrByrefType(CorElementType et,
1015 TypeHandle elemtype)
1016{
1017 CONTRACTL
1018 {
1019 SO_NOT_MAINLINE;
1020 THROWS;
1021 GC_TRIGGERS;
1022 }
1023 CONTRACTL_END;
1024
1025 return ClassLoader::LoadPointerOrByrefTypeThrowing(et, elemtype);
1026}
1027
1028TypeHandle EEDbgInterfaceImpl::LoadFnptrType(TypeHandle *inst,
1029 DWORD ntypars)
1030{
1031 CONTRACTL
1032 {
1033 SO_NOT_MAINLINE;
1034 THROWS;
1035 GC_TRIGGERS;
1036 }
1037 CONTRACTL_END;
1038
1039 /* @TODO : CALLCONV? */
1040 return ClassLoader::LoadFnptrTypeThrowing(0, ntypars, inst);
1041}
1042
1043TypeHandle EEDbgInterfaceImpl::LoadElementType(CorElementType et)
1044{
1045 CONTRACTL
1046 {
1047 SO_NOT_MAINLINE;
1048 THROWS;
1049 GC_TRIGGERS;
1050 }
1051 CONTRACTL_END;
1052
1053 MethodTable *m = MscorlibBinder::GetElementType(et);
1054
1055 if (m == NULL)
1056 {
1057 return TypeHandle();
1058 }
1059
1060 return TypeHandle(m);
1061}
1062
1063
1064HRESULT EEDbgInterfaceImpl::GetMethodImplProps(Module *pModule,
1065 mdToken tk,
1066 DWORD *pRVA,
1067 DWORD *pImplFlags)
1068{
1069 CONTRACTL
1070 {
1071 SO_NOT_MAINLINE;
1072 NOTHROW;
1073 GC_NOTRIGGER;
1074 PRECONDITION(CheckPointer(pModule));
1075 }
1076 CONTRACTL_END;
1077
1078 return pModule->GetMDImport()->GetMethodImplProps(tk, pRVA, pImplFlags);
1079}
1080
1081HRESULT EEDbgInterfaceImpl::GetParentToken(Module *pModule,
1082 mdToken tk,
1083 mdToken *pParentToken)
1084{
1085 CONTRACTL
1086 {
1087 SO_NOT_MAINLINE;
1088 NOTHROW;
1089 GC_NOTRIGGER;
1090 PRECONDITION(CheckPointer(pModule));
1091 }
1092 CONTRACTL_END;
1093
1094 return pModule->GetMDImport()->GetParentToken(tk, pParentToken);
1095}
1096
1097void EEDbgInterfaceImpl::MarkDebuggerAttached(void)
1098{
1099 CONTRACTL
1100 {
1101 SO_NOT_MAINLINE;
1102 NOTHROW;
1103 GC_NOTRIGGER;
1104 }
1105 CONTRACTL_END;
1106
1107 g_CORDebuggerControlFlags |= DBCF_ATTACHED;
1108 g_CORDebuggerControlFlags &= ~DBCF_PENDING_ATTACH;
1109}
1110
1111void EEDbgInterfaceImpl::MarkDebuggerUnattached(void)
1112{
1113 CONTRACTL
1114 {
1115 SO_NOT_MAINLINE;
1116 NOTHROW;
1117 GC_NOTRIGGER;
1118 }
1119 CONTRACTL_END;
1120
1121 g_CORDebuggerControlFlags &= ~DBCF_ATTACHED;
1122}
1123
1124
1125#ifdef EnC_SUPPORTED
1126
1127// Apply an EnC edit to the specified module
1128HRESULT EEDbgInterfaceImpl::EnCApplyChanges(EditAndContinueModule *pModule,
1129 DWORD cbMetadata,
1130 BYTE *pMetadata,
1131 DWORD cbIL,
1132 BYTE *pIL)
1133{
1134 LOG((LF_ENC, LL_INFO100, "EncApplyChanges\n"));
1135 CONTRACTL
1136 {
1137 SO_NOT_MAINLINE;
1138 DISABLED(THROWS);
1139 DISABLED(GC_TRIGGERS);
1140 PRECONDITION(CheckPointer(pModule));
1141 }
1142 CONTRACTL_END;
1143
1144 return pModule->ApplyEditAndContinue(cbMetadata, pMetadata, cbIL, pIL);
1145}
1146
1147// Remap execution to the latest version of an edited method
1148// This function should never return.
1149void EEDbgInterfaceImpl::ResumeInUpdatedFunction(EditAndContinueModule *pModule,
1150 MethodDesc *pFD,
1151 void *debuggerFuncHandle,
1152 SIZE_T resumeIP,
1153 CONTEXT *pContext)
1154{
1155 CONTRACTL
1156 {
1157 SO_NOT_MAINLINE;
1158 DISABLED(THROWS);
1159 DISABLED(GC_TRIGGERS);
1160 PRECONDITION(CheckPointer(pModule));
1161 }
1162 CONTRACTL_END;
1163
1164 pModule->ResumeInUpdatedFunction(pFD,
1165 debuggerFuncHandle,
1166 resumeIP,
1167 pContext);
1168}
1169
1170#endif // EnC_SUPPORTED
1171
1172bool EEDbgInterfaceImpl::CrawlFrameIsGcSafe(CrawlFrame *pCF)
1173{
1174 CONTRACTL
1175 {
1176 SO_NOT_MAINLINE;
1177 SO_NOT_MAINLINE;
1178 NOTHROW;
1179 GC_NOTRIGGER;
1180 PRECONDITION(CheckPointer(pCF));
1181 }
1182 CONTRACTL_END;
1183
1184 return pCF->IsGcSafe();
1185}
1186
1187bool EEDbgInterfaceImpl::IsStub(const BYTE *ip)
1188{
1189 CONTRACTL
1190 {
1191 SO_NOT_MAINLINE;
1192 NOTHROW;
1193 GC_NOTRIGGER;
1194 }
1195 CONTRACTL_END;
1196
1197 // IsStub will catch any exceptions and return false.
1198 return StubManager::IsStub((PCODE) ip) != FALSE;
1199}
1200
1201#endif // #ifndef DACCESS_COMPILE
1202
1203// static
1204bool EEDbgInterfaceImpl::DetectHandleILStubs(Thread *thread)
1205{
1206 CONTRACTL
1207 {
1208 NOTHROW;
1209 GC_NOTRIGGER;
1210 }
1211 CONTRACTL_END;
1212
1213 return thread->DetectHandleILStubsForDebugger();
1214}
1215
1216bool EEDbgInterfaceImpl::TraceStub(const BYTE *ip,
1217 TraceDestination *trace)
1218{
1219#ifndef DACCESS_COMPILE
1220 CONTRACTL
1221 {
1222 SO_NOT_MAINLINE;
1223 NOTHROW;
1224 GC_NOTRIGGER;
1225 }
1226 CONTRACTL_END;
1227
1228 return StubManager::TraceStub((PCODE) ip, trace) != FALSE;
1229#else
1230 DacNotImpl();
1231 return false;
1232#endif // #ifndef DACCESS_COMPILE
1233}
1234
1235#ifndef DACCESS_COMPILE
1236
1237bool EEDbgInterfaceImpl::FollowTrace(TraceDestination *trace)
1238{
1239 CONTRACTL
1240 {
1241 SO_NOT_MAINLINE;
1242 NOTHROW;
1243 GC_NOTRIGGER;
1244 }
1245 CONTRACTL_END;
1246
1247 return StubManager::FollowTrace(trace) != FALSE;
1248}
1249
1250bool EEDbgInterfaceImpl::TraceFrame(Thread *thread,
1251 Frame *frame,
1252 BOOL fromPatch,
1253 TraceDestination *trace,
1254 REGDISPLAY *regs)
1255{
1256 CONTRACTL
1257 {
1258 SO_NOT_MAINLINE;
1259 THROWS;
1260 DISABLED(GC_TRIGGERS); // This is not a bug - the debugger can call this on an un-managed thread.
1261 PRECONDITION(CheckPointer(frame));
1262 }
1263 CONTRACTL_END;
1264
1265 bool fResult = frame->TraceFrame(thread, fromPatch, trace, regs) != FALSE;
1266
1267#ifdef _DEBUG
1268 StubManager::DbgWriteLog("Doing TraceFrame on frame=0x%p (fromPatch=%d), yeilds:\n", frame, fromPatch);
1269 if (fResult)
1270 {
1271 SUPPRESS_ALLOCATION_ASSERTS_IN_THIS_SCOPE;
1272 FAULT_NOT_FATAL();
1273 SString buffer;
1274 StubManager::DbgWriteLog(" td=%S\n", trace->DbgToString(buffer));
1275 }
1276 else
1277 {
1278 StubManager::DbgWriteLog(" false (this frame does not expect to call managed code).\n");
1279 }
1280#endif
1281 return fResult;
1282}
1283
1284bool EEDbgInterfaceImpl::TraceManager(Thread *thread,
1285 StubManager *stubManager,
1286 TraceDestination *trace,
1287 CONTEXT *context,
1288 BYTE **pRetAddr)
1289{
1290 CONTRACTL
1291 {
1292 SO_NOT_MAINLINE;
1293 NOTHROW;
1294 GC_TRIGGERS;
1295 PRECONDITION(CheckPointer(stubManager));
1296 }
1297 CONTRACTL_END;
1298
1299 bool fResult = false;
1300
1301 EX_TRY
1302 {
1303 fResult = stubManager->TraceManager(thread, trace, context, pRetAddr) != FALSE;
1304 }
1305 EX_CATCH
1306 {
1307 // We never expect TraceManager() to fail and throw an exception,
1308 // so we should never hit this assertion.
1309 _ASSERTE(!"Fail to trace a stub through TraceManager()");
1310 fResult = false;
1311 }
1312 EX_END_CATCH(SwallowAllExceptions);
1313
1314#ifdef _DEBUG
1315 StubManager::DbgWriteLog("Doing TraceManager on %s (0x%p) for IP=0x%p, yields:\n", stubManager->DbgGetName(), stubManager, GetIP(context));
1316 if (fResult)
1317 {
1318 // Should never be on helper thread
1319 FAULT_NOT_FATAL();
1320 SString buffer;
1321 StubManager::DbgWriteLog(" td=%S\n", trace->DbgToString(buffer));
1322 }
1323 else
1324 {
1325 StubManager::DbgWriteLog(" false (this stub does not expect to call managed code).\n");
1326 }
1327#endif
1328 return fResult;
1329}
1330
1331void EEDbgInterfaceImpl::EnableTraceCall(Thread *thread)
1332{
1333 CONTRACTL
1334 {
1335 SO_NOT_MAINLINE;
1336 NOTHROW;
1337 GC_NOTRIGGER;
1338 PRECONDITION(CheckPointer(thread));
1339 }
1340 CONTRACTL_END;
1341
1342 thread->IncrementTraceCallCount();
1343}
1344
1345void EEDbgInterfaceImpl::DisableTraceCall(Thread *thread)
1346{
1347 CONTRACTL
1348 {
1349 SO_NOT_MAINLINE;
1350 NOTHROW;
1351 GC_NOTRIGGER;
1352 PRECONDITION(CheckPointer(thread));
1353 }
1354 CONTRACTL_END;
1355
1356 thread->DecrementTraceCallCount();
1357}
1358
1359EXTERN_C UINT32 _tls_index;
1360
1361void EEDbgInterfaceImpl::GetRuntimeOffsets(SIZE_T *pTLSIndex,
1362 SIZE_T *pTLSIsSpecialIndex,
1363 SIZE_T *pTLSCantStopIndex,
1364 SIZE_T *pEEThreadStateOffset,
1365 SIZE_T *pEEThreadStateNCOffset,
1366 SIZE_T *pEEThreadPGCDisabledOffset,
1367 DWORD *pEEThreadPGCDisabledValue,
1368 SIZE_T *pEEThreadFrameOffset,
1369 SIZE_T *pEEThreadMaxNeededSize,
1370 DWORD *pEEThreadSteppingStateMask,
1371 DWORD *pEEMaxFrameValue,
1372 SIZE_T *pEEThreadDebuggerFilterContextOffset,
1373 SIZE_T *pEEThreadCantStopOffset,
1374 SIZE_T *pEEFrameNextOffset,
1375 DWORD *pEEIsManagedExceptionStateMask)
1376{
1377 CONTRACTL
1378 {
1379 SO_INTOLERANT;
1380 NOTHROW;
1381 GC_NOTRIGGER;
1382 PRECONDITION(CheckPointer(pTLSIndex));
1383 PRECONDITION(CheckPointer(pTLSIsSpecialIndex));
1384 PRECONDITION(CheckPointer(pEEThreadStateOffset));
1385 PRECONDITION(CheckPointer(pEEThreadStateNCOffset));
1386 PRECONDITION(CheckPointer(pEEThreadPGCDisabledOffset));
1387 PRECONDITION(CheckPointer(pEEThreadPGCDisabledValue));
1388 PRECONDITION(CheckPointer(pEEThreadFrameOffset));
1389 PRECONDITION(CheckPointer(pEEThreadMaxNeededSize));
1390 PRECONDITION(CheckPointer(pEEThreadSteppingStateMask));
1391 PRECONDITION(CheckPointer(pEEMaxFrameValue));
1392 PRECONDITION(CheckPointer(pEEThreadDebuggerFilterContextOffset));
1393 PRECONDITION(CheckPointer(pEEThreadCantStopOffset));
1394 PRECONDITION(CheckPointer(pEEFrameNextOffset));
1395 PRECONDITION(CheckPointer(pEEIsManagedExceptionStateMask));
1396 }
1397 CONTRACTL_END;
1398
1399 *pTLSIndex = g_TlsIndex;
1400 *pTLSIsSpecialIndex = TlsIdx_ThreadType;
1401 *pTLSCantStopIndex = TlsIdx_CantStopCount;
1402 *pEEThreadStateOffset = Thread::GetOffsetOfState();
1403 *pEEThreadStateNCOffset = Thread::GetOffsetOfStateNC();
1404 *pEEThreadPGCDisabledOffset = Thread::GetOffsetOfGCFlag();
1405 *pEEThreadPGCDisabledValue = 1; // A little obvious, but just in case...
1406 *pEEThreadFrameOffset = Thread::GetOffsetOfCurrentFrame();
1407 *pEEThreadMaxNeededSize = sizeof(Thread);
1408 *pEEThreadDebuggerFilterContextOffset = Thread::GetOffsetOfDebuggerFilterContext();
1409 *pEEThreadCantStopOffset = Thread::GetOffsetOfCantStop();
1410 *pEEThreadSteppingStateMask = Thread::TSNC_DebuggerIsStepping;
1411 *pEEMaxFrameValue = (DWORD)(size_t)FRAME_TOP; // <TODO> should this be size_t for 64bit?</TODO>
1412 *pEEFrameNextOffset = Frame::GetOffsetOfNextLink();
1413 *pEEIsManagedExceptionStateMask = Thread::TSNC_DebuggerIsManagedException;
1414}
1415
1416void EEDbgInterfaceImpl::DebuggerModifyingLogSwitch (int iNewLevel,
1417 const WCHAR *pLogSwitchName)
1418{
1419 CONTRACTL
1420 {
1421 SO_NOT_MAINLINE;
1422 THROWS;
1423 GC_NOTRIGGER;
1424 }
1425 CONTRACTL_END;
1426}
1427
1428
1429HRESULT EEDbgInterfaceImpl::SetIPFromSrcToDst(Thread *pThread,
1430 SLOT addrStart,
1431 DWORD offFrom,
1432 DWORD offTo,
1433 bool fCanSetIPOnly,
1434 PREGDISPLAY pReg,
1435 PCONTEXT pCtx,
1436 void *pDji,
1437 EHRangeTree *pEHRT)
1438{
1439 CONTRACTL
1440 {
1441 SO_NOT_MAINLINE;
1442 THROWS;
1443 GC_TRIGGERS;
1444 }
1445 CONTRACTL_END;
1446
1447 return ::SetIPFromSrcToDst(pThread,
1448 addrStart,
1449 offFrom,
1450 offTo,
1451 fCanSetIPOnly,
1452 pReg,
1453 pCtx,
1454 pDji,
1455 pEHRT);
1456
1457}
1458
1459void EEDbgInterfaceImpl::SetDebugState(Thread *pThread,
1460 CorDebugThreadState state)
1461{
1462 CONTRACTL
1463 {
1464 SO_NOT_MAINLINE;
1465 NOTHROW;
1466 GC_NOTRIGGER;
1467 PRECONDITION(CheckPointer(pThread));
1468 }
1469 CONTRACTL_END;
1470
1471 _ASSERTE(state == THREAD_SUSPEND || state == THREAD_RUN);
1472
1473 LOG((LF_CORDB,LL_INFO10000,"EEDbg:Setting thread 0x%x (ID:0x%x) to 0x%x\n", pThread, pThread->GetThreadId(), state));
1474
1475 if (state == THREAD_SUSPEND)
1476 {
1477 pThread->SetThreadStateNC(Thread::TSNC_DebuggerUserSuspend);
1478 }
1479 else
1480 {
1481 pThread->ResetThreadStateNC(Thread::TSNC_DebuggerUserSuspend);
1482 }
1483}
1484
1485void EEDbgInterfaceImpl::SetAllDebugState(Thread *et,
1486 CorDebugThreadState state)
1487{
1488 CONTRACTL
1489 {
1490 SO_NOT_MAINLINE;
1491 NOTHROW;
1492 GC_NOTRIGGER;
1493 }
1494 CONTRACTL_END;
1495
1496 Thread *pThread = NULL;
1497
1498 while ((pThread = ThreadStore::GetThreadList(pThread)) != NULL)
1499 {
1500 if (pThread != et)
1501 {
1502 SetDebugState(pThread, state);
1503 }
1504 }
1505}
1506
1507// This is pretty much copied from VM\COMSynchronizable's
1508// INT32 __stdcall ThreadNative::GetThreadState, so propogate changes
1509// to both functions
1510// This just gets the user state from the EE's perspective (hence "partial").
1511CorDebugUserState EEDbgInterfaceImpl::GetPartialUserState(Thread *pThread)
1512{
1513 CONTRACTL
1514 {
1515 SO_NOT_MAINLINE;
1516 NOTHROW;
1517 GC_NOTRIGGER;
1518 PRECONDITION(CheckPointer(pThread));
1519 }
1520 CONTRACTL_END;
1521
1522 Thread::ThreadState ts = pThread->GetSnapshotState();
1523 unsigned ret = 0;
1524
1525 if (ts & Thread::TS_Background)
1526 {
1527 ret |= (unsigned)USER_BACKGROUND;
1528 }
1529
1530 if (ts & Thread::TS_Unstarted)
1531 {
1532 ret |= (unsigned)USER_UNSTARTED;
1533 }
1534
1535 // Don't report a StopRequested if the thread has actually stopped.
1536 if (ts & Thread::TS_Dead)
1537 {
1538 ret |= (unsigned)USER_STOPPED;
1539 }
1540
1541 if (ts & Thread::TS_Interruptible)
1542 {
1543 ret |= (unsigned)USER_WAIT_SLEEP_JOIN;
1544 }
1545
1546 // CoreCLR does not support user-requested thread suspension
1547 _ASSERTE(!(ts & Thread::TS_UserSuspendPending));
1548
1549 LOG((LF_CORDB,LL_INFO1000, "EEDbgII::GUS: thread 0x%x (id:0x%x)"
1550 " userThreadState is 0x%x\n", pThread, pThread->GetThreadId(), ret));
1551
1552 return (CorDebugUserState)ret;
1553}
1554
1555#endif // #ifndef DACCESS_COMPILE
1556
1557#ifdef DACCESS_COMPILE
1558
1559void
1560EEDbgInterfaceImpl::EnumMemoryRegions(CLRDataEnumMemoryFlags flags)
1561{
1562 DAC_ENUM_VTHIS();
1563}
1564
1565#endif
1566
1567unsigned EEDbgInterfaceImpl::GetSizeForCorElementType(CorElementType etyp)
1568{
1569 WRAPPER_NO_CONTRACT;
1570
1571 return (::GetSizeForCorElementType(etyp));
1572}
1573
1574
1575#ifndef DACCESS_COMPILE
1576/*
1577 * ObjIsInstanceOf
1578 *
1579 * This method supplies the internal VM implementation of this method to the
1580 * debugger left-side.
1581 *
1582 */
1583BOOL EEDbgInterfaceImpl::ObjIsInstanceOf(Object *pElement, TypeHandle toTypeHnd)
1584{
1585 WRAPPER_NO_CONTRACT;
1586
1587 return (::ObjIsInstanceOf(pElement, toTypeHnd));
1588}
1589#endif
1590
1591/*
1592 * ClearAllDebugInterfaceReferences
1593 *
1594 * This method is called by the debugging part of the runtime to notify
1595 * that the debugger resources are no longer valid and any internal references
1596 * to it must be null'ed out.
1597 *
1598 * Parameters:
1599 * None.
1600 *
1601 * Returns:
1602 * None.
1603 *
1604 */
1605void EEDbgInterfaceImpl::ClearAllDebugInterfaceReferences()
1606{
1607 LIMITED_METHOD_CONTRACT;
1608}
1609
1610#ifndef DACCESS_COMPILE
1611#ifdef _DEBUG
1612/*
1613 * ObjectRefFlush
1614 *
1615 * Flushes all debug tracking information for object referencing.
1616 *
1617 * Parameters:
1618 * pThread - The target thread to flush object references of.
1619 *
1620 * Returns:
1621 * None.
1622 *
1623 */
1624void EEDbgInterfaceImpl::ObjectRefFlush(Thread *pThread)
1625{
1626 WRAPPER_NO_CONTRACT;
1627
1628 Thread::ObjectRefFlush(pThread);
1629}
1630#endif
1631#endif
1632
1633#ifndef DACCESS_COMPILE
1634
1635BOOL AdjustContextForWriteBarrier(EXCEPTION_RECORD *pExceptionRecord, CONTEXT *pContext);
1636BOOL EEDbgInterfaceImpl::AdjustContextForWriteBarrierForDebugger(CONTEXT* context)
1637{
1638 WRAPPER_NO_CONTRACT;
1639 return AdjustContextForWriteBarrier(nullptr, context);
1640}
1641#endif
1642
1643#endif // DEBUGGING_SUPPORTED
1644