//----------------------------------------------------------------------------- // Creates the canary thread and signaling events. //----------------------------------------------------------------------------- void HelperCanary::Init() { // You can only run the init code once. The debugger attempts to lazy-init // the canary at several points but if the canary is already inited then // we just eagerly return. See issue 841005 for more details. if(m_initialized) { return; } else { m_initialized = true; } m_hPingEvent = WszCreateEvent(NULL, (BOOL) kAutoResetEvent, FALSE, NULL); if (m_hPingEvent == NULL) { STRESS_LOG1(LF_CORDB, LL_ALWAYS, "Canary failed to create ping event. gle=%d\n", GetLastError()); // in the past if we failed to start the thread we just assumed it was unsafe // so I am preserving that behavior. However I am going to assert that this // doesn't really happen _ASSERTE(!"Canary failed to create ping event"); return; } m_hWaitEvent = WszCreateEvent(NULL, (BOOL) kManualResetEvent, FALSE, NULL); if (m_hWaitEvent == NULL) { STRESS_LOG1(LF_CORDB, LL_ALWAYS, "Canary failed to create wait event. gle=%d\n", GetLastError()); // in the past if we failed to start the thread we just assumed it was unsafe // so I am preserving that behavior. However I am going to assert that this // doesn't really happen _ASSERTE(!"Canary failed to create wait event"); return; } // Spin up the canary. This will call dllmain, but that's ok because it just // degenerates to our timeout case. const DWORD flags = CREATE_SUSPENDED; m_hCanaryThread = CreateThread(NULL, 0, HelperCanary::ThreadProc, this, flags, &m_CanaryThreadId); // in the past if we failed to start the thread we just assumed it was unsafe // so I am preserving that behavior. However I am going to assert that this // doesn't really happen if(m_hCanaryThread == NULL) { _ASSERTE(!"CreateThread() failed to create Canary thread"); return; } // Capture the Canary thread's TID so that the RS can mark it as a can't-stop region. // This is essential so that the RS doesn't view it as some external thread to be suspended when we hit // debug events. _ASSERTE(g_pRCThread != NULL); g_pRCThread->GetDCB()->m_CanaryThreadId = m_CanaryThreadId; ResumeThread(m_hCanaryThread); }
void StackFrameIterator::InternalInitForEH(Thread * pThreadToWalk, PAL_LIMITED_CONTEXT * pCtx) { STRESS_LOG0(LF_STACKWALK, LL_INFO10000, "----Init---- [ EH ]\n"); StackFrameIterator::InternalInit(pThreadToWalk, pCtx, ApplyReturnAddressAdjustment); STRESS_LOG1(LF_STACKWALK, LL_INFO10000, " %p\n", m_ControlPC); }
//----------------------------------------------------------------------------- // Try and take locks. //----------------------------------------------------------------------------- void HelperCanary::TakeLocks() { _ASSERTE(::GetThread() == NULL); // Canary Thread should always be outside the runtime. _ASSERTE(m_CanaryThreadId == GetCurrentThreadId()); // Call new, which will take whatever standard heap locks there are. // We don't care about what memory we get; we just want to take the heap lock(s). DWORD * p = new (nothrow) DWORD(); delete p; STRESS_LOG1(LF_CORDB, LL_ALWAYS, "canary stage:%d\n", 1); }
void GCScan::GcScanHandles (promote_func* fn, int condemned, int max_gen, ScanContext* sc) { STRESS_LOG1(LF_GC|LF_GCROOTS, LL_INFO10, "GcScanHandles (Promotion Phase = %d)\n", sc->promotion); if (sc->promotion) { Ref_TracePinningRoots(condemned, max_gen, sc, fn); Ref_TraceNormalRoots(condemned, max_gen, sc, fn); } else { Ref_UpdatePointers(condemned, max_gen, sc, fn); Ref_UpdatePinnedPointers(condemned, max_gen, sc, fn); Ref_ScanDependentHandlesForRelocation(condemned, max_gen, sc, fn); } }
void StackFrameIterator::InternalInit(Thread * pThreadToWalk, PTR_PInvokeTransitionFrame pFrame) { m_pThread = pThreadToWalk; m_pInstance = GetRuntimeInstance(); m_pCodeManager = NULL; m_pHijackedReturnValue = NULL; m_HijackedReturnValueKind = GCRK_Unknown; m_pConservativeStackRangeLowerBound = NULL; m_pConservativeStackRangeUpperBound = NULL; m_dwFlags = CollapseFunclets | RemapHardwareFaultsToSafePoint; // options for GC stack walk m_pNextExInfo = pThreadToWalk->GetCurExInfo(); if (pFrame == TOP_OF_STACK_MARKER) { m_ControlPC = 0; return; } memset(&m_RegDisplay, 0, sizeof(m_RegDisplay)); // We need to walk the ExInfo chain in parallel with the stackwalk so that we know when we cross over // exception throw points. So we must find our initial point in the ExInfo chain here so that we can // properly walk it in parallel. ResetNextExInfoForSP((UIntNative)dac_cast<TADDR>(pFrame)); m_RegDisplay.SetIP((PCODE)pFrame->m_RIP); m_RegDisplay.SetAddrOfIP((PTR_PCODE)PTR_HOST_MEMBER(PInvokeTransitionFrame, pFrame, m_RIP)); PTR_UIntNative pPreservedRegsCursor = (PTR_UIntNative)PTR_HOST_MEMBER(PInvokeTransitionFrame, pFrame, m_PreservedRegs); #ifdef TARGET_ARM m_RegDisplay.pLR = (PTR_UIntNative)PTR_HOST_MEMBER(PInvokeTransitionFrame, pFrame, m_RIP); m_RegDisplay.pR11 = (PTR_UIntNative)PTR_HOST_MEMBER(PInvokeTransitionFrame, pFrame, m_ChainPointer); if (pFrame->m_dwFlags & PTFF_SAVE_R4) { m_RegDisplay.pR4 = pPreservedRegsCursor++; } if (pFrame->m_dwFlags & PTFF_SAVE_R5) { m_RegDisplay.pR5 = pPreservedRegsCursor++; } if (pFrame->m_dwFlags & PTFF_SAVE_R6) { m_RegDisplay.pR6 = pPreservedRegsCursor++; } ASSERT(!(pFrame->m_dwFlags & PTFF_SAVE_R7)); // R7 should never contain a GC ref because we require // a frame pointer for methods with pinvokes if (pFrame->m_dwFlags & PTFF_SAVE_R8) { m_RegDisplay.pR8 = pPreservedRegsCursor++; } if (pFrame->m_dwFlags & PTFF_SAVE_R9) { m_RegDisplay.pR9 = pPreservedRegsCursor++; } if (pFrame->m_dwFlags & PTFF_SAVE_R10) { m_RegDisplay.pR10 = pPreservedRegsCursor++; } if (pFrame->m_dwFlags & PTFF_SAVE_SP) { m_RegDisplay.SP = *pPreservedRegsCursor++; } m_RegDisplay.pR7 = (PTR_UIntNative) PTR_HOST_MEMBER(PInvokeTransitionFrame, pFrame, m_FramePointer); if (pFrame->m_dwFlags & PTFF_SAVE_R0) { m_RegDisplay.pR0 = pPreservedRegsCursor++; } if (pFrame->m_dwFlags & PTFF_SAVE_R1) { m_RegDisplay.pR1 = pPreservedRegsCursor++; } if (pFrame->m_dwFlags & PTFF_SAVE_R2) { m_RegDisplay.pR2 = pPreservedRegsCursor++; } if (pFrame->m_dwFlags & PTFF_SAVE_R3) { m_RegDisplay.pR3 = pPreservedRegsCursor++; } if (pFrame->m_dwFlags & PTFF_SAVE_LR) { m_RegDisplay.pLR = pPreservedRegsCursor++; } if (pFrame->m_dwFlags & PTFF_R0_IS_GCREF) { m_pHijackedReturnValue = (PTR_RtuObjectRef) m_RegDisplay.pR0; m_HijackedReturnValueKind = GCRK_Object; } if (pFrame->m_dwFlags & PTFF_R0_IS_BYREF) { m_pHijackedReturnValue = (PTR_RtuObjectRef) m_RegDisplay.pR0; m_HijackedReturnValueKind = GCRK_Byref; } m_ControlPC = dac_cast<PTR_VOID>(*(m_RegDisplay.pIP)); #else // TARGET_ARM if (pFrame->m_dwFlags & PTFF_SAVE_RBX) { m_RegDisplay.pRbx = pPreservedRegsCursor++; } if (pFrame->m_dwFlags & PTFF_SAVE_RSI) { m_RegDisplay.pRsi = pPreservedRegsCursor++; } if (pFrame->m_dwFlags & PTFF_SAVE_RDI) { m_RegDisplay.pRdi = pPreservedRegsCursor++; } ASSERT(!(pFrame->m_dwFlags & PTFF_SAVE_RBP)); // RBP should never contain a GC ref because we require // a frame pointer for methods with pinvokes #ifdef TARGET_AMD64 if (pFrame->m_dwFlags & PTFF_SAVE_R12) { m_RegDisplay.pR12 = pPreservedRegsCursor++; } if (pFrame->m_dwFlags & PTFF_SAVE_R13) { m_RegDisplay.pR13 = pPreservedRegsCursor++; } if (pFrame->m_dwFlags & PTFF_SAVE_R14) { m_RegDisplay.pR14 = pPreservedRegsCursor++; } if (pFrame->m_dwFlags & PTFF_SAVE_R15) { m_RegDisplay.pR15 = pPreservedRegsCursor++; } #endif // TARGET_AMD64 m_RegDisplay.pRbp = (PTR_UIntNative) PTR_HOST_MEMBER(PInvokeTransitionFrame, pFrame, m_FramePointer); if (pFrame->m_dwFlags & PTFF_SAVE_RSP) { m_RegDisplay.SP = *pPreservedRegsCursor++; } if (pFrame->m_dwFlags & PTFF_SAVE_RAX) { m_RegDisplay.pRax = pPreservedRegsCursor++; } if (pFrame->m_dwFlags & PTFF_SAVE_RCX) { m_RegDisplay.pRcx = pPreservedRegsCursor++; } if (pFrame->m_dwFlags & PTFF_SAVE_RDX) { m_RegDisplay.pRdx = pPreservedRegsCursor++; } #ifdef TARGET_AMD64 if (pFrame->m_dwFlags & PTFF_SAVE_R8 ) { m_RegDisplay.pR8 = pPreservedRegsCursor++; } if (pFrame->m_dwFlags & PTFF_SAVE_R9 ) { m_RegDisplay.pR9 = pPreservedRegsCursor++; } if (pFrame->m_dwFlags & PTFF_SAVE_R10) { m_RegDisplay.pR10 = pPreservedRegsCursor++; } if (pFrame->m_dwFlags & PTFF_SAVE_R11) { m_RegDisplay.pR11 = pPreservedRegsCursor++; } #endif // TARGET_AMD64 if (pFrame->m_dwFlags & PTFF_RAX_IS_GCREF) { m_pHijackedReturnValue = (PTR_RtuObjectRef) m_RegDisplay.pRax; m_HijackedReturnValueKind = GCRK_Object; } if (pFrame->m_dwFlags & PTFF_RAX_IS_BYREF) { m_pHijackedReturnValue = (PTR_RtuObjectRef) m_RegDisplay.pRax; m_HijackedReturnValueKind = GCRK_Byref; } m_ControlPC = dac_cast<PTR_VOID>(*(m_RegDisplay.pIP)); #endif // TARGET_ARM // @TODO: currently, we always save all registers -- how do we handle the onese we don't save once we // start only saving those that weren't already saved? // If our control PC indicates that we're in one of the thunks we use to make managed callouts from the // runtime we need to adjust the frame state to that of the managed method that previously called into the // runtime (i.e. skip the intervening unmanaged frames). HandleManagedCalloutThunk(); STRESS_LOG1(LF_STACKWALK, LL_INFO10000, " %p\n", m_ControlPC); }