Exemplo n.º 1
0
//-----------------------------------------------------------------------------
// 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);
}
Exemplo n.º 2
0
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);
}
Exemplo n.º 3
0
//-----------------------------------------------------------------------------
// 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);
}
Exemplo n.º 4
0
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);
    }
}
Exemplo n.º 5
0
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);
}