summaryrefslogtreecommitdiff
path: root/src/vm/eedbginterfaceimpl.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/vm/eedbginterfaceimpl.cpp')
-rw-r--r--src/vm/eedbginterfaceimpl.cpp1683
1 files changed, 1683 insertions, 0 deletions
diff --git a/src/vm/eedbginterfaceimpl.cpp b/src/vm/eedbginterfaceimpl.cpp
new file mode 100644
index 0000000000..93decc9b0d
--- /dev/null
+++ b/src/vm/eedbginterfaceimpl.cpp
@@ -0,0 +1,1683 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+
+/*
+ *
+ * COM+99 EE to Debugger Interface Implementation
+ *
+ */
+
+#include "common.h"
+#include "dbginterface.h"
+#include "eedbginterfaceimpl.h"
+#include "virtualcallstub.h"
+#include "contractimpl.h"
+
+#ifdef DEBUGGING_SUPPORTED
+
+#ifndef DACCESS_COMPILE
+
+//
+// Cleanup any global data used by this interface.
+//
+void EEDbgInterfaceImpl::Terminate(void)
+{
+ CONTRACTL
+ {
+ SO_INTOLERANT;
+ NOTHROW;
+ GC_NOTRIGGER;
+ }
+ CONTRACTL_END;
+
+ if (g_pEEDbgInterfaceImpl)
+ {
+ delete g_pEEDbgInterfaceImpl;
+ g_pEEDbgInterfaceImpl = NULL;
+ }
+}
+
+#endif // #ifndef DACCESS_COMPILE
+
+Thread* EEDbgInterfaceImpl::GetThread(void)
+{
+ LIMITED_METHOD_CONTRACT;
+// Since this may be called from a Debugger Interop Hijack, the EEThread may be bogus.
+// Thus we can't use contracts. If we do fix that, then the contract below would be nice...
+#if 0
+ CONTRACT(Thread *)
+ {
+ NOTHROW;
+ GC_NOTRIGGER;
+ POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
+ }
+ CONTRACT_END;
+#endif
+
+ return ::GetThread();
+}
+
+#ifndef DACCESS_COMPILE
+
+void EEDbgInterfaceImpl::SetEEThreadPtr(VOID* newPtr)
+{
+ // Since this may be called from a Debugger Interop Hijack, the EEThread may be bogus.
+ // Thus we can't use contracts. If we do fix that, then the contract below would be nice...
+#if 0
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_NOTRIGGER;
+
+ PRECONDITION(GetThread() == NULL); // shouldn't have an EE thread.
+ }
+ CONTRACTL_END;
+#endif
+ // This should only be called by interop-debugging when we don't have an EE thread
+ // object.
+
+ // Normally the LS & RS can communicate a pointer value using the EE thread's
+ // m_debuggerWord field. If we have no EE thread, then we can use the
+ // TLS slot that the EE thread would have been in.
+
+ SetThread((Thread*)newPtr);
+}
+
+StackWalkAction EEDbgInterfaceImpl::StackWalkFramesEx(Thread* pThread,
+ PREGDISPLAY pRD,
+ PSTACKWALKFRAMESCALLBACK pCallback,
+ VOID* pData,
+ unsigned int flags)
+{
+ CONTRACTL
+ {
+ DISABLED(NOTHROW); // FIX THIS when StackWalkFramesEx gets fixed.
+ DISABLED(GC_TRIGGERS); // We cannot predict if pCallback will trigger or not.
+ // Disabled is not a bug in this case.
+ PRECONDITION(CheckPointer(pThread));
+ }
+ CONTRACTL_END;
+
+ return pThread->StackWalkFramesEx(pRD, pCallback, pData, flags);
+}
+
+Frame *EEDbgInterfaceImpl::GetFrame(CrawlFrame *pCF)
+{
+ CONTRACT(Frame *)
+ {
+ SO_NOT_MAINLINE;
+ NOTHROW;
+ GC_NOTRIGGER;
+ PRECONDITION(CheckPointer(pCF));
+ POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
+ }
+ CONTRACT_END;
+
+ RETURN pCF->GetFrame();
+}
+
+bool EEDbgInterfaceImpl::InitRegDisplay(Thread* pThread,
+ const PREGDISPLAY pRD,
+ const PCONTEXT pctx,
+ bool validContext)
+{
+ CONTRACTL
+ {
+ SO_NOT_MAINLINE;
+ NOTHROW;
+ GC_NOTRIGGER;
+ PRECONDITION(CheckPointer(pThread));
+ PRECONDITION(CheckPointer(pRD));
+ if (validContext)
+ {
+ PRECONDITION(CheckPointer(pctx));
+ }
+ }
+ CONTRACTL_END;
+
+ return pThread->InitRegDisplay(pRD, pctx, validContext);
+}
+
+BOOL EEDbgInterfaceImpl::IsStringObject(Object* o)
+{
+ CONTRACTL
+ {
+ SO_NOT_MAINLINE;
+ THROWS;
+ GC_NOTRIGGER;
+ PRECONDITION(CheckPointer(o));
+ }
+ CONTRACTL_END;
+
+ return o->GetMethodTable() == g_pStringClass;
+}
+
+BOOL EEDbgInterfaceImpl::IsTypedReference(MethodTable* pMT)
+{
+ CONTRACTL
+ {
+ SO_NOT_MAINLINE;
+ THROWS;
+ GC_NOTRIGGER;
+ PRECONDITION(CheckPointer(pMT));
+ }
+ CONTRACTL_END;
+
+ return pMT == g_TypedReferenceMT;
+}
+
+WCHAR* EEDbgInterfaceImpl::StringObjectGetBuffer(StringObject* so)
+{
+ CONTRACTL
+ {
+ SO_NOT_MAINLINE;
+ NOTHROW;
+ GC_NOTRIGGER;
+ PRECONDITION(CheckPointer(so));
+ }
+ CONTRACTL_END;
+
+ return so->GetBuffer();
+}
+
+DWORD EEDbgInterfaceImpl::StringObjectGetStringLength(StringObject* so)
+{
+ CONTRACTL
+ {
+ SO_NOT_MAINLINE;
+ NOTHROW;
+ GC_NOTRIGGER;
+ PRECONDITION(CheckPointer(so));
+ }
+ CONTRACTL_END;
+
+ return so->GetStringLength();
+}
+
+void* EEDbgInterfaceImpl::GetObjectFromHandle(OBJECTHANDLE handle)
+{
+ CONTRACTL
+ {
+ SO_NOT_MAINLINE;
+ NOTHROW;
+ GC_NOTRIGGER;
+ }
+ CONTRACTL_END;
+
+ void *v;
+
+ *((OBJECTREF *)&v) = *(OBJECTREF *)handle;
+
+ return v;
+}
+
+OBJECTHANDLE EEDbgInterfaceImpl::GetHandleFromObject(void *obj,
+ bool fStrongNewRef,
+ AppDomain *pAppDomain)
+{
+ CONTRACTL
+ {
+ SO_NOT_MAINLINE;
+ THROWS; // From CreateHandle
+ GC_NOTRIGGER;
+ PRECONDITION(CheckPointer(pAppDomain));
+ }
+ CONTRACTL_END;
+
+ OBJECTHANDLE oh;
+
+ if (fStrongNewRef)
+ {
+ oh = pAppDomain->CreateStrongHandle(ObjectToOBJECTREF((Object *)obj));
+
+ LOG((LF_CORDB, LL_INFO1000, "EEI::GHFO: Given objectref 0x%x,"
+ "created strong handle 0x%x!\n", obj, oh));
+ }
+ else
+ {
+ oh = pAppDomain->CreateLongWeakHandle( ObjectToOBJECTREF((Object *)obj));
+
+ LOG((LF_CORDB, LL_INFO1000, "EEI::GHFO: Given objectref 0x%x,"
+ "created long weak handle 0x%x!\n", obj, oh));
+ }
+
+ return oh;
+}
+
+void EEDbgInterfaceImpl::DbgDestroyHandle(OBJECTHANDLE oh,
+ bool fStrongNewRef)
+{
+ CONTRACTL
+ {
+ SO_NOT_MAINLINE;
+ NOTHROW;
+ GC_NOTRIGGER;
+ }
+ CONTRACTL_END;
+
+ LOG((LF_CORDB, LL_INFO1000, "EEI::GHFO: Destroyed given handle 0x%x,"
+ "fStrong: 0x%x!\n", oh, fStrongNewRef));
+
+ if (fStrongNewRef)
+ {
+ DestroyStrongHandle(oh);
+ }
+ else
+ {
+ DestroyLongWeakHandle(oh);
+ }
+}
+
+
+OBJECTHANDLE EEDbgInterfaceImpl::GetThreadException(Thread *pThread)
+{
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_NOTRIGGER;
+ PRECONDITION(CheckPointer(pThread));
+ }
+ CONTRACTL_END;
+
+ OBJECTHANDLE oh = pThread->GetThrowableAsHandle();
+
+ if (oh != NULL)
+ {
+ return oh;
+ }
+
+ // Return the last thrown object if there's no current throwable.
+ // This logic is similar to UpdateCurrentThrowable().
+ return pThread->m_LastThrownObjectHandle;
+}
+
+bool EEDbgInterfaceImpl::IsThreadExceptionNull(Thread *pThread)
+{
+ CONTRACTL
+ {
+ SO_TOLERANT;
+ NOTHROW;
+ GC_NOTRIGGER;
+ PRECONDITION(CheckPointer(pThread));
+ }
+ CONTRACTL_END;
+
+ //
+ // We're assuming that the handle on the
+ // thread is a strong handle and we're goona check it for
+ // NULL. We're also assuming something about the
+ // implementation of the handle here, too.
+ //
+ OBJECTHANDLE h = pThread->GetThrowableAsHandle();
+ if (h == NULL)
+ {
+ return true;
+ }
+
+ void *pThrowable = *((void**)h);
+
+ return (pThrowable == NULL);
+}
+
+void EEDbgInterfaceImpl::ClearThreadException(Thread *pThread)
+{
+ //
+ // If one day there is a continuable exception, then this will have to be
+ // implemented properly.
+ //
+ //
+ LIMITED_METHOD_CONTRACT;
+}
+
+bool EEDbgInterfaceImpl::StartSuspendForDebug(AppDomain *pAppDomain,
+ BOOL fHoldingThreadStoreLock)
+{
+ CONTRACTL
+ {
+ SO_NOT_MAINLINE;
+ NOTHROW;
+ GC_NOTRIGGER;
+ }
+ CONTRACTL_END;
+
+ LOG((LF_CORDB,LL_INFO1000, "EEDbgII:SSFD: start suspend on AD:0x%x\n",
+ pAppDomain));
+
+ bool result = Thread::SysStartSuspendForDebug(pAppDomain);
+
+ return result;
+}
+
+bool EEDbgInterfaceImpl::SweepThreadsForDebug(bool forceSync)
+{
+ CONTRACTL
+ {
+ SO_NOT_MAINLINE;
+ NOTHROW;
+ DISABLED(GC_TRIGGERS); // Called by unmanaged threads.
+ }
+ CONTRACTL_END;
+
+ return Thread::SysSweepThreadsForDebug(forceSync);
+}
+
+void EEDbgInterfaceImpl::ResumeFromDebug(AppDomain *pAppDomain)
+{
+ CONTRACTL
+ {
+ SO_NOT_MAINLINE;
+ NOTHROW;
+ GC_NOTRIGGER;
+ }
+ CONTRACTL_END;
+
+ Thread::SysResumeFromDebug(pAppDomain);
+}
+
+void EEDbgInterfaceImpl::MarkThreadForDebugSuspend(Thread* pRuntimeThread)
+{
+ CONTRACTL
+ {
+ SO_NOT_MAINLINE;
+ NOTHROW;
+ GC_NOTRIGGER;
+ PRECONDITION(CheckPointer(pRuntimeThread));
+ }
+ CONTRACTL_END;
+
+ pRuntimeThread->MarkForDebugSuspend();
+}
+
+void EEDbgInterfaceImpl::MarkThreadForDebugStepping(Thread* pRuntimeThread,
+ bool onOff)
+{
+ CONTRACTL
+ {
+ SO_NOT_MAINLINE;
+ NOTHROW;
+ GC_NOTRIGGER;
+ PRECONDITION(CheckPointer(pRuntimeThread));
+ }
+ CONTRACTL_END;
+
+ pRuntimeThread->MarkDebuggerIsStepping(onOff);
+}
+
+void EEDbgInterfaceImpl::SetThreadFilterContext(Thread *thread,
+ CONTEXT *context)
+{
+ CONTRACTL
+ {
+ SO_NOT_MAINLINE;
+ NOTHROW;
+ GC_NOTRIGGER;
+ PRECONDITION(CheckPointer(thread));
+ }
+ CONTRACTL_END;
+
+ thread->SetFilterContext(context);
+}
+
+CONTEXT *EEDbgInterfaceImpl::GetThreadFilterContext(Thread *thread)
+{
+ CONTRACT(CONTEXT *)
+ {
+ NOTHROW;
+ GC_NOTRIGGER;
+ PRECONDITION(CheckPointer(thread));
+ POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
+ }
+ CONTRACT_END;
+
+ RETURN thread->GetFilterContext();
+}
+
+VOID * EEDbgInterfaceImpl::GetThreadDebuggerWord(Thread *thread)
+{
+ CONTRACTL
+ {
+ SO_NOT_MAINLINE;
+ NOTHROW;
+ GC_NOTRIGGER;
+ PRECONDITION(CheckPointer(thread));
+ }
+ CONTRACTL_END;
+
+ return thread->m_debuggerWord;
+}
+
+void EEDbgInterfaceImpl::SetThreadDebuggerWord(Thread *thread,
+ VOID *dw)
+{
+ CONTRACTL
+ {
+ SO_NOT_MAINLINE;
+ NOTHROW;
+ GC_NOTRIGGER;
+ PRECONDITION(CheckPointer(thread));
+ }
+ CONTRACTL_END;
+
+ thread->m_debuggerWord = dw;
+}
+
+BOOL EEDbgInterfaceImpl::IsManagedNativeCode(const BYTE *address)
+{
+ WRAPPER_NO_CONTRACT;
+ return ExecutionManager::IsManagedCode((PCODE)address);
+}
+
+MethodDesc *EEDbgInterfaceImpl::GetNativeCodeMethodDesc(const PCODE address)
+{
+ CONTRACT(MethodDesc *)
+ {
+ NOTHROW;
+ GC_NOTRIGGER;
+ PRECONDITION(address != NULL);
+ POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
+ }
+ CONTRACT_END;
+
+ RETURN ExecutionManager::GetCodeMethodDesc(address);
+}
+
+// IsInPrologOrEpilog doesn't seem to be used for code that uses GC_INFO_DECODER
+BOOL EEDbgInterfaceImpl::IsInPrologOrEpilog(const BYTE *address,
+ size_t* prologSize)
+{
+ CONTRACTL
+ {
+ SO_NOT_MAINLINE;
+ NOTHROW;
+ GC_NOTRIGGER;
+ }
+ CONTRACTL_END;
+
+ *prologSize = 0;
+
+ EECodeInfo codeInfo((PCODE)address);
+
+ if (codeInfo.IsValid())
+ {
+ LPVOID methodInfo = codeInfo.GetGCInfo();
+
+ if (codeInfo.GetCodeManager()->IsInPrologOrEpilog(codeInfo.GetRelOffset(), methodInfo, prologSize))
+ {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+//
+// Given a collection of native offsets of a certain function, determine if each falls
+// within an exception filter or handler.
+//
+void EEDbgInterfaceImpl::DetermineIfOffsetsInFilterOrHandler(const BYTE *functionAddress,
+ DebugOffsetToHandlerInfo *pOffsetToHandlerInfo,
+ unsigned offsetToHandlerInfoLength)
+{
+ CONTRACTL
+ {
+ SO_NOT_MAINLINE;
+ NOTHROW;
+ GC_NOTRIGGER;
+ }
+ CONTRACTL_END;
+
+ EECodeInfo codeInfo((PCODE)functionAddress);
+
+ if (!codeInfo.IsValid())
+ {
+ return;
+ }
+
+ // Loop through all the exception handling clause information for the method
+ EH_CLAUSE_ENUMERATOR pEnumState;
+ unsigned EHCount = codeInfo.GetJitManager()->InitializeEHEnumeration(codeInfo.GetMethodToken(), &pEnumState);
+ if (EHCount == 0)
+ {
+ return;
+ }
+
+ for (ULONG i=0; i < EHCount; i++)
+ {
+ EE_ILEXCEPTION_CLAUSE EHClause;
+ codeInfo.GetJitManager()->GetNextEHClause(&pEnumState, &EHClause);
+
+ // Check each EH clause against each offset of interest.
+ // Note that this could be time consuming for very long methods ( O(n^2) ).
+ // We could make this linear if we could guarentee that the two lists are sorted.
+ for (ULONG j=0; j < offsetToHandlerInfoLength; j++)
+ {
+ SIZE_T offs = pOffsetToHandlerInfo[j].offset;
+
+ // those with -1 indicate slots to skip
+ if (offs == (SIZE_T) -1)
+ {
+ continue;
+ }
+ // For a filter, the handler comes directly after it so check from start of filter
+ // to end of handler
+ if (IsFilterHandler(&EHClause))
+ {
+ if (offs >= EHClause.FilterOffset && offs < EHClause.HandlerEndPC)
+ {
+ pOffsetToHandlerInfo[j].isInFilterOrHandler = TRUE;
+ }
+ }
+ // For anything else, only care about handler range
+ else if (offs >= EHClause.HandlerStartPC && offs < EHClause.HandlerEndPC)
+ {
+ pOffsetToHandlerInfo[j].isInFilterOrHandler = TRUE;
+ }
+ }
+ }
+}
+#endif // #ifndef DACCESS_COMPILE
+
+void EEDbgInterfaceImpl::GetMethodRegionInfo(const PCODE pStart,
+ PCODE * pCold,
+ size_t *hotSize,
+ size_t *coldSize)
+{
+ CONTRACTL
+ {
+ SO_INTOLERANT;
+ NOTHROW;
+ GC_NOTRIGGER;
+ PRECONDITION(CheckPointer(pCold));
+ PRECONDITION(CheckPointer(hotSize));
+ PRECONDITION(CheckPointer(coldSize));
+ SUPPORTS_DAC;
+ }
+ CONTRACTL_END;
+
+ IJitManager::MethodRegionInfo methodRegionInfo = {NULL, 0, NULL, 0};
+
+ EECodeInfo codeInfo(pStart);
+
+ if (codeInfo.IsValid() != NULL)
+ {
+ codeInfo.GetMethodRegionInfo(&methodRegionInfo);
+ }
+
+ *pCold = methodRegionInfo.coldStartAddress;
+ *hotSize = methodRegionInfo.hotSize;
+ *coldSize = methodRegionInfo.coldSize;
+}
+
+#if defined(WIN64EXCEPTIONS)
+DWORD EEDbgInterfaceImpl::GetFuncletStartOffsets(const BYTE *pStart, DWORD* pStartOffsets, DWORD dwLength)
+{
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_NOTRIGGER;
+ PRECONDITION(CheckPointer(pStart));
+ }
+ CONTRACTL_END;
+
+ EECodeInfo codeInfo((PCODE)pStart);
+ _ASSERTE(codeInfo.IsValid());
+
+ return codeInfo.GetJitManager()->GetFuncletStartOffsets(codeInfo.GetMethodToken(), pStartOffsets, dwLength);
+}
+
+StackFrame EEDbgInterfaceImpl::FindParentStackFrame(CrawlFrame* pCF)
+{
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_NOTRIGGER;
+ PRECONDITION(CheckPointer(pCF));
+ }
+ CONTRACTL_END;
+
+#if defined(DACCESS_COMPILE)
+ DacNotImpl();
+ return StackFrame();
+
+#else // !DACCESS_COMPILE
+ return ExceptionTracker::FindParentStackFrameForStackWalk(pCF);
+
+#endif // !DACCESS_COMPILE
+}
+#endif // WIN64EXCEPTIONS
+
+#ifndef DACCESS_COMPILE
+size_t EEDbgInterfaceImpl::GetFunctionSize(MethodDesc *pFD)
+{
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_NOTRIGGER;
+ PRECONDITION(CheckPointer(pFD));
+ }
+ CONTRACTL_END;
+
+ PCODE methodStart = pFD->GetNativeCode();
+
+ if (methodStart == NULL)
+ return 0;
+
+ EECodeInfo codeInfo(methodStart);
+ GCInfoToken gcInfoToken = codeInfo.GetGCInfoToken();
+ return codeInfo.GetCodeManager()->GetFunctionSize(gcInfoToken);
+}
+#endif //!DACCESS_COMPILE
+
+const PCODE EEDbgInterfaceImpl::GetFunctionAddress(MethodDesc *pFD)
+{
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_NOTRIGGER;
+ PRECONDITION(CheckPointer(pFD));
+ SUPPORTS_DAC;
+ }
+ CONTRACTL_END;
+
+ return pFD->GetNativeCode();
+}
+
+#ifndef DACCESS_COMPILE
+
+void EEDbgInterfaceImpl::DisablePreemptiveGC(void)
+{
+ CONTRACTL
+ {
+ SO_INTOLERANT;
+ NOTHROW;
+ DISABLED(GC_TRIGGERS); // Disabled because disabled in RareDisablePreemptiveGC()
+ }
+ CONTRACTL_END;
+
+ ::GetThread()->DisablePreemptiveGC();
+}
+
+void EEDbgInterfaceImpl::EnablePreemptiveGC(void)
+{
+ CONTRACTL
+ {
+ SO_INTOLERANT;
+ NOTHROW;
+ DISABLED(GC_TRIGGERS); // Disabled because disabled in RareEnablePreemptiveGC()
+ }
+ CONTRACTL_END;
+
+ ::GetThread()->EnablePreemptiveGC();
+}
+
+bool EEDbgInterfaceImpl::IsPreemptiveGCDisabled(void)
+{
+ CONTRACTL
+ {
+ SO_TOLERANT;
+ NOTHROW;
+ GC_NOTRIGGER;
+ }
+ CONTRACTL_END;
+
+ return ::GetThread()->PreemptiveGCDisabled() != 0;
+}
+
+DWORD EEDbgInterfaceImpl::MethodDescIsStatic(MethodDesc *pFD)
+{
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_NOTRIGGER;
+ PRECONDITION(CheckPointer(pFD));
+ }
+ CONTRACTL_END;
+
+ return pFD->IsStatic();
+}
+
+#endif // #ifndef DACCESS_COMPILE
+
+Module *EEDbgInterfaceImpl::MethodDescGetModule(MethodDesc *pFD)
+{
+ CONTRACT(Module *)
+ {
+ NOTHROW;
+ GC_NOTRIGGER;
+ PRECONDITION(CheckPointer(pFD));
+ POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
+ }
+ CONTRACT_END;
+
+ RETURN pFD->GetModule();
+}
+
+#ifndef DACCESS_COMPILE
+
+COR_ILMETHOD* EEDbgInterfaceImpl::MethodDescGetILHeader(MethodDesc *pFD)
+{
+ CONTRACT(COR_ILMETHOD *)
+ {
+ THROWS;
+ GC_NOTRIGGER;
+ PRECONDITION(CheckPointer(pFD));
+ POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
+ }
+ CONTRACT_END;
+
+ if (pFD->IsIL())
+ {
+ RETURN pFD->GetILHeader();
+ }
+
+ RETURN NULL;
+}
+
+ULONG EEDbgInterfaceImpl::MethodDescGetRVA(MethodDesc *pFD)
+{
+ CONTRACTL
+ {
+ SO_NOT_MAINLINE;
+ NOTHROW;
+ GC_NOTRIGGER;
+ PRECONDITION(CheckPointer(pFD));
+ }
+ CONTRACTL_END;
+
+ return pFD->GetRVA();
+}
+
+MethodDesc *EEDbgInterfaceImpl::FindLoadedMethodRefOrDef(Module* pModule,
+ mdToken memberRef)
+{
+ CONTRACT(MethodDesc *)
+ {
+ NOTHROW;
+ GC_NOTRIGGER;
+ PRECONDITION(CheckPointer(pModule));
+ POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
+ }
+ CONTRACT_END;
+
+ // Must have a MemberRef or a MethodDef
+ mdToken tkType = TypeFromToken(memberRef);
+ _ASSERTE((tkType == mdtMemberRef) || (tkType == mdtMethodDef));
+
+ if (tkType == mdtMemberRef)
+ {
+ RETURN pModule->LookupMemberRefAsMethod(memberRef);
+ }
+
+ RETURN pModule->LookupMethodDef(memberRef);
+}
+
+MethodDesc *EEDbgInterfaceImpl::LoadMethodDef(Module* pModule,
+ mdMethodDef methodDef,
+ DWORD numGenericArgs,
+ TypeHandle *pGenericArgs,
+ TypeHandle *pOwnerType)
+{
+ CONTRACT(MethodDesc *)
+ {
+ THROWS;
+ GC_TRIGGERS;
+ PRECONDITION(CheckPointer(pModule));
+ POSTCONDITION(CheckPointer(RETVAL));
+ }
+ CONTRACT_END;
+
+ _ASSERTE(TypeFromToken(methodDef) == mdtMethodDef);
+
+ // The generic class and method args are sent as one array
+ // by the debugger. We now split this into two by finding out how
+ // many generic args are for the class and how many for the
+ // method. The actual final checks are done in MemberLoader::GetMethodDescFromMethodDef.
+
+ DWORD numGenericClassArgs = 0;
+ TypeHandle *pGenericClassArgs = NULL;
+ DWORD nGenericMethodArgs = 0;
+ TypeHandle *pGenericMethodArgs = NULL;
+ mdTypeDef typeDef = 0;
+
+ TypeHandle thOwner;
+
+ BOOL forceRemotable = FALSE;
+ if (numGenericArgs != 0)
+ {
+ HRESULT hr = pModule->GetMDImport()->GetParentToken(methodDef, &typeDef);
+ if (FAILED(hr))
+ COMPlusThrowHR(E_INVALIDARG);
+
+ TypeHandle thClass = LoadClass(pModule, typeDef);
+ _ASSERTE(!thClass.IsNull());
+
+ numGenericClassArgs = thClass.GetNumGenericArgs();
+ if (numGenericArgs < numGenericClassArgs)
+ {
+ COMPlusThrowHR(COR_E_TARGETPARAMCOUNT);
+ }
+ pGenericClassArgs = (numGenericClassArgs > 0) ? pGenericArgs : NULL;
+ nGenericMethodArgs = (numGenericArgs >= numGenericClassArgs) ? (numGenericArgs - numGenericClassArgs) : 0;
+ pGenericMethodArgs = (nGenericMethodArgs > 0) ? (pGenericArgs + numGenericClassArgs) : NULL;
+
+#ifdef FEATURE_COMINTEROP
+ if (numGenericClassArgs > 0)
+ {
+ thOwner = ClassLoader::LoadGenericInstantiationThrowing(pModule, typeDef, Instantiation(pGenericClassArgs, numGenericClassArgs));
+ // for classes supporting generic interop force remotable method descs
+ forceRemotable = thOwner.GetMethodTable()->SupportsGenericInterop(TypeHandle::Interop_ManagedToNative);
+ }
+#endif // FEATURE_COMINTEROP
+ }
+
+ MethodDesc *pRes = MemberLoader::GetMethodDescFromMethodDef(pModule,
+ methodDef,
+ Instantiation(pGenericClassArgs, numGenericClassArgs),
+ Instantiation(pGenericMethodArgs, nGenericMethodArgs),
+ forceRemotable);
+
+ // The ownerType is extra information that augments the specification of an interface MD.
+ // It is only needed if generics code sharing is supported, because otherwise MDs are
+ // fully self-describing.
+ if (pOwnerType != NULL)
+ {
+ if (numGenericClassArgs != 0)
+ {
+ if (thOwner.IsNull())
+ *pOwnerType = ClassLoader::LoadGenericInstantiationThrowing(pModule, typeDef, Instantiation(pGenericClassArgs, numGenericClassArgs));
+ else
+ *pOwnerType = thOwner;
+ }
+ else
+ {
+ *pOwnerType = TypeHandle(pRes->GetMethodTable());
+ }
+ }
+ RETURN (pRes);
+
+}
+
+
+TypeHandle EEDbgInterfaceImpl::FindLoadedClass(Module *pModule,
+ mdTypeDef classToken)
+{
+ CONTRACT(TypeHandle)
+ {
+ NOTHROW;
+ GC_NOTRIGGER;
+ PRECONDITION(CheckPointer(pModule));
+ }
+ CONTRACT_END;
+
+ RETURN ClassLoader::LookupTypeDefOrRefInModule(pModule, classToken);
+
+}
+
+TypeHandle EEDbgInterfaceImpl::FindLoadedInstantiation(Module *pModule,
+ mdTypeDef typeDef,
+ DWORD ntypars,
+ TypeHandle *inst)
+{
+ // Lookup operations run the class loader in non-load mode.
+ ENABLE_FORBID_GC_LOADER_USE_IN_THIS_SCOPE();
+
+
+ // scan violation: asserts that this can be suppressed since there is currently
+ // work on dac-izing all this code and as a result the issue will become moot.
+ CONTRACT_VIOLATION(FaultViolation);
+
+ return ClassLoader::LoadGenericInstantiationThrowing(pModule, typeDef, Instantiation(inst, ntypars),
+ ClassLoader::DontLoadTypes);
+}
+
+TypeHandle EEDbgInterfaceImpl::FindLoadedFnptrType(TypeHandle *inst,
+ DWORD ntypars)
+{
+ // Lookup operations run the class loader in non-load mode.
+ ENABLE_FORBID_GC_LOADER_USE_IN_THIS_SCOPE();
+
+ //<TODO> : CALLCONV? </TODO>
+ return ClassLoader::LoadFnptrTypeThrowing(0, ntypars, inst,
+ // <TODO> should this be FailIfNotLoaded? - NO - although we may
+ // want to debug unrestored VCs, we can't do it because the debug API
+ // is not set up to handle them </TODO>
+ // == FailIfNotLoadedOrNotRestored
+ ClassLoader::DontLoadTypes);
+}
+
+TypeHandle EEDbgInterfaceImpl::FindLoadedPointerOrByrefType(CorElementType et,
+ TypeHandle elemtype)
+{
+ // Lookup operations run the class loader in non-load mode.
+ ENABLE_FORBID_GC_LOADER_USE_IN_THIS_SCOPE();
+
+ return ClassLoader::LoadPointerOrByrefTypeThrowing(et, elemtype,
+ // <TODO> should this be FailIfNotLoaded? - NO - although we may
+ // want to debug unrestored VCs, we can't do it because the debug API
+ // is not set up to handle them </TODO>
+ // == FailIfNotLoadedOrNotRestored
+ ClassLoader::DontLoadTypes);
+}
+
+TypeHandle EEDbgInterfaceImpl::FindLoadedArrayType(CorElementType et,
+ TypeHandle elemtype,
+ unsigned rank)
+{
+ // Lookup operations run the class loader in non-load mode.
+ ENABLE_FORBID_GC_LOADER_USE_IN_THIS_SCOPE();
+
+ if (elemtype.IsNull())
+ return TypeHandle();
+ else
+ return ClassLoader::LoadArrayTypeThrowing(elemtype, et, rank,
+ // <TODO> should this be FailIfNotLoaded? - NO - although we may
+ // want to debug unrestored VCs, we can't do it because the debug API
+ // is not set up to handle them </TODO>
+ // == FailIfNotLoadedOrNotRestored
+ ClassLoader::DontLoadTypes );
+}
+
+
+TypeHandle EEDbgInterfaceImpl::FindLoadedElementType(CorElementType et)
+{
+ // Lookup operations run the class loader in non-load mode.
+ ENABLE_FORBID_GC_LOADER_USE_IN_THIS_SCOPE();
+
+ MethodTable *m = MscorlibBinder::GetElementType(et);
+
+ return TypeHandle(m);
+}
+
+TypeHandle EEDbgInterfaceImpl::LoadClass(Module *pModule,
+ mdTypeDef classToken)
+{
+ CONTRACT(TypeHandle)
+ {
+ THROWS;
+ GC_TRIGGERS;
+ PRECONDITION(CheckPointer(pModule));
+ }
+ CONTRACT_END;
+
+ RETURN ClassLoader::LoadTypeDefOrRefThrowing(pModule, classToken,
+ ClassLoader::ThrowIfNotFound,
+ ClassLoader::PermitUninstDefOrRef);
+
+}
+
+TypeHandle EEDbgInterfaceImpl::LoadInstantiation(Module *pModule,
+ mdTypeDef typeDef,
+ DWORD ntypars,
+ TypeHandle *inst)
+{
+ CONTRACT(TypeHandle)
+ {
+ THROWS;
+ GC_TRIGGERS;
+ PRECONDITION(CheckPointer(pModule));
+ }
+ CONTRACT_END;
+
+ RETURN ClassLoader::LoadGenericInstantiationThrowing(pModule, typeDef, Instantiation(inst, ntypars));
+}
+
+TypeHandle EEDbgInterfaceImpl::LoadArrayType(CorElementType et,
+ TypeHandle elemtype,
+ unsigned rank)
+{
+ CONTRACT(TypeHandle)
+ {
+ THROWS;
+ GC_TRIGGERS;
+ }
+ CONTRACT_END;
+
+ if (elemtype.IsNull())
+ RETURN TypeHandle();
+ else
+ RETURN ClassLoader::LoadArrayTypeThrowing(elemtype, et, rank);
+}
+
+TypeHandle EEDbgInterfaceImpl::LoadPointerOrByrefType(CorElementType et,
+ TypeHandle elemtype)
+{
+ CONTRACTL
+ {
+ SO_NOT_MAINLINE;
+ THROWS;
+ GC_TRIGGERS;
+ }
+ CONTRACTL_END;
+
+ return ClassLoader::LoadPointerOrByrefTypeThrowing(et, elemtype);
+}
+
+TypeHandle EEDbgInterfaceImpl::LoadFnptrType(TypeHandle *inst,
+ DWORD ntypars)
+{
+ CONTRACTL
+ {
+ SO_NOT_MAINLINE;
+ THROWS;
+ GC_TRIGGERS;
+ }
+ CONTRACTL_END;
+
+ /* @TODO : CALLCONV? */
+ return ClassLoader::LoadFnptrTypeThrowing(0, ntypars, inst);
+}
+
+TypeHandle EEDbgInterfaceImpl::LoadElementType(CorElementType et)
+{
+ CONTRACTL
+ {
+ SO_NOT_MAINLINE;
+ THROWS;
+ GC_TRIGGERS;
+ }
+ CONTRACTL_END;
+
+ MethodTable *m = MscorlibBinder::GetElementType(et);
+
+ if (m == NULL)
+ {
+ return TypeHandle();
+ }
+
+ return TypeHandle(m);
+}
+
+
+HRESULT EEDbgInterfaceImpl::GetMethodImplProps(Module *pModule,
+ mdToken tk,
+ DWORD *pRVA,
+ DWORD *pImplFlags)
+{
+ CONTRACTL
+ {
+ SO_NOT_MAINLINE;
+ NOTHROW;
+ GC_NOTRIGGER;
+ PRECONDITION(CheckPointer(pModule));
+ }
+ CONTRACTL_END;
+
+ return pModule->GetMDImport()->GetMethodImplProps(tk, pRVA, pImplFlags);
+}
+
+HRESULT EEDbgInterfaceImpl::GetParentToken(Module *pModule,
+ mdToken tk,
+ mdToken *pParentToken)
+{
+ CONTRACTL
+ {
+ SO_NOT_MAINLINE;
+ NOTHROW;
+ GC_NOTRIGGER;
+ PRECONDITION(CheckPointer(pModule));
+ }
+ CONTRACTL_END;
+
+ return pModule->GetMDImport()->GetParentToken(tk, pParentToken);
+}
+
+void EEDbgInterfaceImpl::MarkDebuggerAttached(void)
+{
+ CONTRACTL
+ {
+ SO_NOT_MAINLINE;
+ NOTHROW;
+ GC_NOTRIGGER;
+ }
+ CONTRACTL_END;
+
+ g_CORDebuggerControlFlags |= DBCF_ATTACHED;
+ g_CORDebuggerControlFlags &= ~DBCF_PENDING_ATTACH;
+}
+
+void EEDbgInterfaceImpl::MarkDebuggerUnattached(void)
+{
+ CONTRACTL
+ {
+ SO_NOT_MAINLINE;
+ NOTHROW;
+ GC_NOTRIGGER;
+ }
+ CONTRACTL_END;
+
+ g_CORDebuggerControlFlags &= ~DBCF_ATTACHED;
+}
+
+
+#ifdef EnC_SUPPORTED
+
+// Apply an EnC edit to the specified module
+HRESULT EEDbgInterfaceImpl::EnCApplyChanges(EditAndContinueModule *pModule,
+ DWORD cbMetadata,
+ BYTE *pMetadata,
+ DWORD cbIL,
+ BYTE *pIL)
+{
+ LOG((LF_ENC, LL_INFO100, "EncApplyChanges\n"));
+ CONTRACTL
+ {
+ SO_NOT_MAINLINE;
+ DISABLED(THROWS);
+ DISABLED(GC_TRIGGERS);
+ PRECONDITION(CheckPointer(pModule));
+ }
+ CONTRACTL_END;
+
+ return pModule->ApplyEditAndContinue(cbMetadata, pMetadata, cbIL, pIL);
+}
+
+// Remap execution to the latest version of an edited method
+// This function should never return.
+void EEDbgInterfaceImpl::ResumeInUpdatedFunction(EditAndContinueModule *pModule,
+ MethodDesc *pFD,
+ void *debuggerFuncHandle,
+ SIZE_T resumeIP,
+ CONTEXT *pContext)
+{
+ CONTRACTL
+ {
+ SO_NOT_MAINLINE;
+ DISABLED(THROWS);
+ DISABLED(GC_TRIGGERS);
+ PRECONDITION(CheckPointer(pModule));
+ }
+ CONTRACTL_END;
+
+ pModule->ResumeInUpdatedFunction(pFD,
+ debuggerFuncHandle,
+ resumeIP,
+ pContext);
+}
+
+#endif // EnC_SUPPORTED
+
+bool EEDbgInterfaceImpl::CrawlFrameIsGcSafe(CrawlFrame *pCF)
+{
+ CONTRACTL
+ {
+ SO_NOT_MAINLINE;
+ SO_NOT_MAINLINE;
+ NOTHROW;
+ GC_NOTRIGGER;
+ PRECONDITION(CheckPointer(pCF));
+ }
+ CONTRACTL_END;
+
+ return pCF->IsGcSafe();
+}
+
+bool EEDbgInterfaceImpl::IsStub(const BYTE *ip)
+{
+ CONTRACTL
+ {
+ SO_NOT_MAINLINE;
+ NOTHROW;
+ GC_NOTRIGGER;
+ }
+ CONTRACTL_END;
+
+ // IsStub will catch any exceptions and return false.
+ return StubManager::IsStub((PCODE) ip) != FALSE;
+}
+
+#endif // #ifndef DACCESS_COMPILE
+
+// static
+bool EEDbgInterfaceImpl::DetectHandleILStubs(Thread *thread)
+{
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_NOTRIGGER;
+ }
+ CONTRACTL_END;
+
+ return thread->DetectHandleILStubsForDebugger();
+}
+
+bool EEDbgInterfaceImpl::TraceStub(const BYTE *ip,
+ TraceDestination *trace)
+{
+#ifndef DACCESS_COMPILE
+ CONTRACTL
+ {
+ SO_NOT_MAINLINE;
+ NOTHROW;
+ GC_NOTRIGGER;
+ }
+ CONTRACTL_END;
+
+ return StubManager::TraceStub((PCODE) ip, trace) != FALSE;
+#else
+ DacNotImpl();
+ return false;
+#endif // #ifndef DACCESS_COMPILE
+}
+
+#ifndef DACCESS_COMPILE
+
+bool EEDbgInterfaceImpl::FollowTrace(TraceDestination *trace)
+{
+ CONTRACTL
+ {
+ SO_NOT_MAINLINE;
+ NOTHROW;
+ GC_NOTRIGGER;
+ }
+ CONTRACTL_END;
+
+ return StubManager::FollowTrace(trace) != FALSE;
+}
+
+bool EEDbgInterfaceImpl::TraceFrame(Thread *thread,
+ Frame *frame,
+ BOOL fromPatch,
+ TraceDestination *trace,
+ REGDISPLAY *regs)
+{
+ CONTRACTL
+ {
+ SO_NOT_MAINLINE;
+ THROWS;
+ DISABLED(GC_TRIGGERS); // This is not a bug - the debugger can call this on an un-managed thread.
+ PRECONDITION(CheckPointer(frame));
+ }
+ CONTRACTL_END;
+
+ bool fResult = frame->TraceFrame(thread, fromPatch, trace, regs) != FALSE;
+
+#ifdef _DEBUG
+ StubManager::DbgWriteLog("Doing TraceFrame on frame=0x%p (fromPatch=%d), yeilds:\n", frame, fromPatch);
+ if (fResult)
+ {
+ SUPPRESS_ALLOCATION_ASSERTS_IN_THIS_SCOPE;
+ FAULT_NOT_FATAL();
+ SString buffer;
+ StubManager::DbgWriteLog(" td=%S\n", trace->DbgToString(buffer));
+ }
+ else
+ {
+ StubManager::DbgWriteLog(" false (this frame does not expect to call managed code).\n");
+ }
+#endif
+ return fResult;
+}
+
+bool EEDbgInterfaceImpl::TraceManager(Thread *thread,
+ StubManager *stubManager,
+ TraceDestination *trace,
+ CONTEXT *context,
+ BYTE **pRetAddr)
+{
+ CONTRACTL
+ {
+ SO_NOT_MAINLINE;
+ NOTHROW;
+ GC_TRIGGERS;
+ PRECONDITION(CheckPointer(stubManager));
+ }
+ CONTRACTL_END;
+
+ bool fResult = false;
+
+ EX_TRY
+ {
+ fResult = stubManager->TraceManager(thread, trace, context, pRetAddr) != FALSE;
+ }
+ EX_CATCH
+ {
+ // We never expect TraceManager() to fail and throw an exception,
+ // so we should never hit this assertion.
+ _ASSERTE(!"Fail to trace a stub through TraceManager()");
+ fResult = false;
+ }
+ EX_END_CATCH(SwallowAllExceptions);
+
+#ifdef _DEBUG
+ StubManager::DbgWriteLog("Doing TraceManager on %s (0x%p) for IP=0x%p, yields:\n", stubManager->DbgGetName(), stubManager, GetIP(context));
+ if (fResult)
+ {
+ // Should never be on helper thread
+ FAULT_NOT_FATAL();
+ SString buffer;
+ StubManager::DbgWriteLog(" td=%S\n", trace->DbgToString(buffer));
+ }
+ else
+ {
+ StubManager::DbgWriteLog(" false (this stub does not expect to call managed code).\n");
+ }
+#endif
+ return fResult;
+}
+
+void EEDbgInterfaceImpl::EnableTraceCall(Thread *thread)
+{
+ CONTRACTL
+ {
+ SO_NOT_MAINLINE;
+ NOTHROW;
+ GC_NOTRIGGER;
+ PRECONDITION(CheckPointer(thread));
+ }
+ CONTRACTL_END;
+
+ thread->IncrementTraceCallCount();
+}
+
+void EEDbgInterfaceImpl::DisableTraceCall(Thread *thread)
+{
+ CONTRACTL
+ {
+ SO_NOT_MAINLINE;
+ NOTHROW;
+ GC_NOTRIGGER;
+ PRECONDITION(CheckPointer(thread));
+ }
+ CONTRACTL_END;
+
+ thread->DecrementTraceCallCount();
+}
+
+#ifdef FEATURE_IMPLICIT_TLS
+EXTERN_C UINT32 _tls_index;
+#endif
+
+void EEDbgInterfaceImpl::GetRuntimeOffsets(SIZE_T *pTLSIndex,
+ SIZE_T *pTLSIsSpecialIndex,
+ SIZE_T *pTLSCantStopIndex,
+ SIZE_T* pTLSIndexOfPredefs,
+ SIZE_T *pEEThreadStateOffset,
+ SIZE_T *pEEThreadStateNCOffset,
+ SIZE_T *pEEThreadPGCDisabledOffset,
+ DWORD *pEEThreadPGCDisabledValue,
+ SIZE_T *pEEThreadDebuggerWordOffset,
+ SIZE_T *pEEThreadFrameOffset,
+ SIZE_T *pEEThreadMaxNeededSize,
+ DWORD *pEEThreadSteppingStateMask,
+ DWORD *pEEMaxFrameValue,
+ SIZE_T *pEEThreadDebuggerFilterContextOffset,
+ SIZE_T *pEEThreadCantStopOffset,
+ SIZE_T *pEEFrameNextOffset,
+ DWORD *pEEIsManagedExceptionStateMask)
+{
+ CONTRACTL
+ {
+ SO_INTOLERANT;
+ NOTHROW;
+ GC_NOTRIGGER;
+ PRECONDITION(CheckPointer(pTLSIndex));
+ PRECONDITION(CheckPointer(pTLSIsSpecialIndex));
+ PRECONDITION(CheckPointer(pEEThreadStateOffset));
+ PRECONDITION(CheckPointer(pTLSIndexOfPredefs));
+ PRECONDITION(CheckPointer(pEEThreadStateNCOffset));
+ PRECONDITION(CheckPointer(pEEThreadPGCDisabledOffset));
+ PRECONDITION(CheckPointer(pEEThreadPGCDisabledValue));
+ PRECONDITION(CheckPointer(pEEThreadDebuggerWordOffset));
+ PRECONDITION(CheckPointer(pEEThreadFrameOffset));
+ PRECONDITION(CheckPointer(pEEThreadMaxNeededSize));
+ PRECONDITION(CheckPointer(pEEThreadSteppingStateMask));
+ PRECONDITION(CheckPointer(pEEMaxFrameValue));
+ PRECONDITION(CheckPointer(pEEThreadDebuggerFilterContextOffset));
+ PRECONDITION(CheckPointer(pEEThreadCantStopOffset));
+ PRECONDITION(CheckPointer(pEEFrameNextOffset));
+ PRECONDITION(CheckPointer(pEEIsManagedExceptionStateMask));
+ }
+ CONTRACTL_END;
+
+#ifdef FEATURE_IMPLICIT_TLS
+ *pTLSIndex = _tls_index;
+#else
+ *pTLSIndex = GetThreadTLSIndex();
+#endif
+ *pTLSIsSpecialIndex = TlsIdx_ThreadType;
+ *pTLSCantStopIndex = TlsIdx_CantStopCount;
+ *pTLSIndexOfPredefs = CExecutionEngine::TlsIndex;
+ *pEEThreadStateOffset = Thread::GetOffsetOfState();
+ *pEEThreadStateNCOffset = Thread::GetOffsetOfStateNC();
+ *pEEThreadPGCDisabledOffset = Thread::GetOffsetOfGCFlag();
+ *pEEThreadPGCDisabledValue = 1; // A little obvious, but just in case...
+ *pEEThreadDebuggerWordOffset = Thread::GetOffsetOfDebuggerWord();
+ *pEEThreadFrameOffset = Thread::GetOffsetOfCurrentFrame();
+ *pEEThreadMaxNeededSize = sizeof(Thread);
+ *pEEThreadDebuggerFilterContextOffset = Thread::GetOffsetOfDebuggerFilterContext();
+ *pEEThreadCantStopOffset = Thread::GetOffsetOfCantStop();
+ *pEEThreadSteppingStateMask = Thread::TSNC_DebuggerIsStepping;
+ *pEEMaxFrameValue = (DWORD)(size_t)FRAME_TOP; // <TODO> should this be size_t for 64bit?</TODO>
+ *pEEFrameNextOffset = Frame::GetOffsetOfNextLink();
+ *pEEIsManagedExceptionStateMask = Thread::TSNC_DebuggerIsManagedException;
+}
+
+void EEDbgInterfaceImpl::DebuggerModifyingLogSwitch (int iNewLevel,
+ const WCHAR *pLogSwitchName)
+{
+ CONTRACTL
+ {
+ SO_NOT_MAINLINE;
+ THROWS;
+ GC_NOTRIGGER;
+ }
+ CONTRACTL_END;
+
+ Log::DebuggerModifyingLogSwitch (iNewLevel, pLogSwitchName);
+}
+
+
+HRESULT EEDbgInterfaceImpl::SetIPFromSrcToDst(Thread *pThread,
+ SLOT addrStart,
+ DWORD offFrom,
+ DWORD offTo,
+ bool fCanSetIPOnly,
+ PREGDISPLAY pReg,
+ PCONTEXT pCtx,
+ void *pDji,
+ EHRangeTree *pEHRT)
+{
+ CONTRACTL
+ {
+ SO_NOT_MAINLINE;
+ THROWS;
+ GC_TRIGGERS;
+ }
+ CONTRACTL_END;
+
+ return ::SetIPFromSrcToDst(pThread,
+ addrStart,
+ offFrom,
+ offTo,
+ fCanSetIPOnly,
+ pReg,
+ pCtx,
+ pDji,
+ pEHRT);
+
+}
+
+void EEDbgInterfaceImpl::SetDebugState(Thread *pThread,
+ CorDebugThreadState state)
+{
+ CONTRACTL
+ {
+ SO_NOT_MAINLINE;
+ NOTHROW;
+ GC_NOTRIGGER;
+ PRECONDITION(CheckPointer(pThread));
+ }
+ CONTRACTL_END;
+
+ _ASSERTE(state == THREAD_SUSPEND || state == THREAD_RUN);
+
+ LOG((LF_CORDB,LL_INFO10000,"EEDbg:Setting thread 0x%x (ID:0x%x) to 0x%x\n", pThread, pThread->GetThreadId(), state));
+
+ if (state == THREAD_SUSPEND)
+ {
+ pThread->SetThreadStateNC(Thread::TSNC_DebuggerUserSuspend);
+ }
+ else
+ {
+ pThread->ResetThreadStateNC(Thread::TSNC_DebuggerUserSuspend);
+ }
+}
+
+void EEDbgInterfaceImpl::SetAllDebugState(Thread *et,
+ CorDebugThreadState state)
+{
+ CONTRACTL
+ {
+ SO_NOT_MAINLINE;
+ NOTHROW;
+ GC_NOTRIGGER;
+ }
+ CONTRACTL_END;
+
+ Thread *pThread = NULL;
+
+ while ((pThread = ThreadStore::GetThreadList(pThread)) != NULL)
+ {
+ if (pThread != et)
+ {
+ SetDebugState(pThread, state);
+ }
+ }
+}
+
+// This is pretty much copied from VM\COMSynchronizable's
+// INT32 __stdcall ThreadNative::GetThreadState, so propogate changes
+// to both functions
+// This just gets the user state from the EE's perspective (hence "partial").
+CorDebugUserState EEDbgInterfaceImpl::GetPartialUserState(Thread *pThread)
+{
+ CONTRACTL
+ {
+ SO_NOT_MAINLINE;
+ NOTHROW;
+ GC_NOTRIGGER;
+ PRECONDITION(CheckPointer(pThread));
+ }
+ CONTRACTL_END;
+
+ Thread::ThreadState ts = pThread->GetSnapshotState();
+ unsigned ret = 0;
+
+ if (ts & Thread::TS_Background)
+ {
+ ret |= (unsigned)USER_BACKGROUND;
+ }
+
+ if (ts & Thread::TS_Unstarted)
+ {
+ ret |= (unsigned)USER_UNSTARTED;
+ }
+
+ // Don't report a StopRequested if the thread has actually stopped.
+ if (ts & Thread::TS_Dead)
+ {
+ ret |= (unsigned)USER_STOPPED;
+ }
+
+ if (ts & Thread::TS_Interruptible)
+ {
+ ret |= (unsigned)USER_WAIT_SLEEP_JOIN;
+ }
+
+ // Don't report a SuspendRequested if the thread has actually Suspended.
+ if ( ((ts & Thread::TS_UserSuspendPending) && (ts & Thread::TS_SyncSuspended)))
+ {
+ ret |= (unsigned)USER_SUSPENDED;
+ }
+ else if (ts & Thread::TS_UserSuspendPending)
+ {
+ ret |= (unsigned)USER_SUSPEND_REQUESTED;
+ }
+
+ LOG((LF_CORDB,LL_INFO1000, "EEDbgII::GUS: thread 0x%x (id:0x%x)"
+ " userThreadState is 0x%x\n", pThread, pThread->GetThreadId(), ret));
+
+ return (CorDebugUserState)ret;
+}
+
+#endif // #ifndef DACCESS_COMPILE
+
+#ifdef DACCESS_COMPILE
+
+void
+EEDbgInterfaceImpl::EnumMemoryRegions(CLRDataEnumMemoryFlags flags)
+{
+ DAC_ENUM_VTHIS();
+}
+
+#endif
+
+unsigned EEDbgInterfaceImpl::GetSizeForCorElementType(CorElementType etyp)
+{
+ WRAPPER_NO_CONTRACT;
+
+ return (::GetSizeForCorElementType(etyp));
+}
+
+
+#ifndef DACCESS_COMPILE
+/*
+ * ObjIsInstanceOf
+ *
+ * This method supplies the internal VM implementation of this method to the
+ * debugger left-side.
+ *
+ */
+BOOL EEDbgInterfaceImpl::ObjIsInstanceOf(Object *pElement, TypeHandle toTypeHnd)
+{
+ WRAPPER_NO_CONTRACT;
+
+ return (::ObjIsInstanceOf(pElement, toTypeHnd));
+}
+#endif
+
+/*
+ * ClearAllDebugInterfaceReferences
+ *
+ * This method is called by the debugging part of the runtime to notify
+ * that the debugger resources are no longer valid and any internal references
+ * to it must be null'ed out.
+ *
+ * Parameters:
+ * None.
+ *
+ * Returns:
+ * None.
+ *
+ */
+void EEDbgInterfaceImpl::ClearAllDebugInterfaceReferences()
+{
+ LIMITED_METHOD_CONTRACT;
+}
+
+#ifndef DACCESS_COMPILE
+#ifdef _DEBUG
+/*
+ * ObjectRefFlush
+ *
+ * Flushes all debug tracking information for object referencing.
+ *
+ * Parameters:
+ * pThread - The target thread to flush object references of.
+ *
+ * Returns:
+ * None.
+ *
+ */
+void EEDbgInterfaceImpl::ObjectRefFlush(Thread *pThread)
+{
+ WRAPPER_NO_CONTRACT;
+
+ Thread::ObjectRefFlush(pThread);
+}
+#endif
+#endif
+
+#endif // DEBUGGING_SUPPORTED