Beispiel #1
0
// Find the code manager containing the given address, which might be a return address from a managed function. The
// address may be to another managed function, or it may be to an unmanaged function, or it may be to a GC
// hijack. The address may also refer to an EEType if we've been called from RhpGetClasslibFunction. If it is
// a GC hijack, we will recognize that and use the real return address.
static ICodeManager * FindCodeManagerRespectingReturnAddressHijacks(void * address)
{
    RuntimeInstance * pRI = GetRuntimeInstance();

    // Try looking up the code manager assuming the address is for code first. This is expected to be most common.
    ICodeManager * pCodeManager = pRI->FindCodeManagerByAddress(address);
    if (pCodeManager != NULL)
        return pCodeManager;

    // @TODO: CORERT: Do we need to make this work for CoreRT?
    // Less common, we will look for the address in any of the sections of the module.  This is slower, but is 
    // necessary for EEType pointers and jump stubs.
    Module * pModule = pRI->FindModuleByAddress(address);
    if (pModule != NULL)
        return pModule;

    // Corner-case: The thread might be hijacked -- @TODO: this is a bit brittle because there is no validation that
    // the hijacked return address from the thread is actually related to place where the caller got the hijack 
    // target.
    Thread * pCurThread = ThreadStore::GetCurrentThread();
    if (pCurThread->IsHijacked() && Thread::IsHijackTarget(address))
    {
        ICodeManager * pCodeManagerForHijack = pRI->FindCodeManagerByAddress(pCurThread->GetHijackedReturnAddress());
        ASSERT_MSG(pCodeManagerForHijack != NULL, "expected to find the module for a hijacked return address");
        return pCodeManagerForHijack;
    }

    return NULL;
}
Beispiel #2
0
// this generic type or method is not a duplicate - enter it into the hash table
bool GenericUnificationHashtable::EnterDesc(GenericUnificationDesc *pDesc, UIntTarget *pIndirCells)
{
    if (m_tableSize < m_entryCount)
    {
        if (!GrowTable(m_entryCount))
            return false;
    }

    m_entryCount++;
    
    UInt32 hashCode = pDesc->m_hashCode & m_hashMask;

    Entry *pEntry = new (nothrow) Entry(m_table[hashCode], pDesc, pIndirCells);
    if (pEntry == nullptr)
        return false;
    m_table[hashCode] = pEntry;

    if (pDesc->m_flags & GUF_GC_STATICS)
    {
        UInt32 indirCellIndex = pDesc->GetIndirCellIndex(GUF_GC_STATICS);
        UInt8 *pGcStaticData = (UInt8 *)pIndirCells[indirCellIndex];
        StaticGcDesc *pGcStaticsDesc = (StaticGcDesc *)pIndirCells[indirCellIndex + 1];
        if (!GetRuntimeInstance()->AddDynamicGcStatics(pGcStaticData, pGcStaticsDesc))
            return false;
    }

    if (pDesc->m_flags & GUF_THREAD_STATICS)
    {
        UInt32 indirCellIndex = pDesc->GetIndirCellIndex(GUF_THREAD_STATICS);
        UInt32 tlsIndex = *(UInt32 *)pIndirCells[indirCellIndex];
        UInt32 tlsOffset = (UInt32)pIndirCells[indirCellIndex + 1];
        StaticGcDesc *pGcStaticsDesc = (StaticGcDesc *)pIndirCells[indirCellIndex + 2];
        if (!GetRuntimeInstance()->AddDynamicThreadStaticGcData(tlsIndex, tlsOffset, pGcStaticsDesc))
            return false;
    }

    return true;
}
Beispiel #3
0
// Find the code manager containing the given address, which might be a return address from a managed function. The
// address may be to another managed function, or it may be to an unmanaged function. The address may also refer to 
// an EEType.
static ICodeManager * FindCodeManagerForClasslibFunction(void * address)
{
    RuntimeInstance * pRI = GetRuntimeInstance();

    // Try looking up the code manager assuming the address is for code first. This is expected to be most common.
    ICodeManager * pCodeManager = pRI->FindCodeManagerByAddress(address);
    if (pCodeManager != NULL)
        return pCodeManager;

    // @TODO: CORERT: Do we need to make this work for CoreRT?
    // Less common, we will look for the address in any of the sections of the module.  This is slower, but is 
    // necessary for EEType pointers and jump stubs.
    Module * pModule = pRI->FindModuleByAddress(address);
    if (pModule != NULL)
        return pModule;

    ASSERT_MSG(!Thread::IsHijackTarget(address), "not expected to be called with hijacked return address");

    return NULL;
}
Beispiel #4
0
// Find the module containing the given address, which is a return address from a managed function. The
// address may be to another managed function, or it may be to an unmanaged function, or it may be to a GC
// hijack. The address may also refer to an EEType if we've been called from RhpGetClasslibFunction. If it is
// a GC hijack, we will recgonize that and use the real return address, updating the address passed in.
static Module * FindModuleRespectingReturnAddressHijacks(void ** pAddress)
{
    RuntimeInstance * pRI = GetRuntimeInstance();

    // Try looking up the module assuming the address is for code first. Fall back to a read-only data looukp
    // if that fails. If we have data indicating that the data case is more common then we can reverse the
    // order of checks. Finally check read/write data: generic EETypes live there since they need to be fixed
    // up at runtime to support unification.
    Module * pModule = pRI->FindModuleByCodeAddress(*pAddress);
    if (pModule == NULL)
    {
        pModule = pRI->FindModuleByReadOnlyDataAddress(*pAddress);

        if (pModule == NULL)
            pModule = pRI->FindModuleByDataAddress(*pAddress);

        if (pModule == NULL)
        {
            // Hmmm... we didn't find a managed module for the given PC. We have a return address in unmanaged
            // code, but it could be because the thread is hijacked for GC suspension. If it is then we should
            // get the real return address and try again.
            Thread * pCurThread = ThreadStore::GetCurrentThread();
        
            if (!pCurThread->IsHijacked())
            {
                // The PC isn't in a managed module, and there is no hijack in place, so we have no EH info.
                return NULL;
            }

            // Update the PC passed in to reflect the correct return address.
            *pAddress = pCurThread->GetHijackedReturnAddress();

            pModule = pRI->FindModuleByCodeAddress(*pAddress);
        }
    }

    return pModule;
}
Beispiel #5
0
//---------------------------------------------------------------------------------------
//
// Sends a raw managed debug event to the debugger.
//
// Arguments:
//      pPayload - managed debug event data
//
//
// Notes:
//    The entire process will get frozen by the debugger once we send.  The debugger
//    needs to resume the process. It may detach as well.
//    See CordbProcess::DecodeEvent in mscordbi for decoding this event. These methods must stay in sync.
//
//---------------------------------------------------------------------------------------
void DebugEventSource::SendRawEvent(DebugEventPayload* pPayload)
{
#ifdef _MSC_VER
    // We get to send an array of void* as data with the notification.
    // The debugger can then use ReadProcessMemory to read through this array.
    UInt64 rgData [] = {
        (UInt64) CLRDBG_EXCEPTION_DATA_CHECKSUM, 
        (UInt64) GetRuntimeInstance()->GetPalInstance(), 
        (UInt64) pPayload
    };

    //
    // Physically send the event via an OS Exception. We're using exceptions as a notification
    // mechanism on top of the OS native debugging pipeline.
    //
    __try
    {
        const UInt32 dwFlags = 0; // continuable (eg, Debugger can continue GH)
        // RaiseException treats arguments as pointer sized values, but we encoded 3 QWORDS.
        // On 32 bit platforms we have 6 elements, on 64 bit platforms we have 3 elements
        RaiseException(CLRDBG_NOTIFICATION_EXCEPTION_CODE, dwFlags, 3*sizeof(UInt64)/sizeof(UInt32*), (UInt32*)rgData);

        // If debugger continues "GH" (DBG_CONTINUE), then we land here. 
        // This is the expected path for a well-behaved ICorDebug debugger.
    }
    __except(1)
    {
        // We can get here if:
        // An ICorDebug aware debugger enabled the debug events AND
        // a) the debugger detached during the event OR
        // b) the debugger continues "GN" (DBG_EXCEPTION_NOT_HANDLED) - this would be considered a badly written debugger
        //
        // there is no great harm in reaching here but it is a needless perf-cost
    }
#endif // _MSC_VER
}
ThreadStore * GetThreadStore()
{
    return GetRuntimeInstance()->GetThreadStore();
}
Beispiel #7
0
void EnumAllStaticGCRefs(EnumGcRefCallbackFunc * fn, EnumGcRefScanContext * sc)
{
    GetRuntimeInstance()->EnumAllStaticGCRefs(fn, sc);
}
Beispiel #8
0
void EnumAllStaticGCRefs(EnumGcRefCallbackFunc * fn, EnumGcRefScanContext * sc)
{
    GetRuntimeInstance()->EnumAllStaticGCRefs(reinterpret_cast<void*>(fn), sc);
}
void StackFrameIterator::InternalInit(Thread * pThreadToWalk, PTR_PAL_LIMITED_CONTEXT pCtx, UInt32 dwFlags)
{
    ASSERT((dwFlags & MethodStateCalculated) == 0);

    m_pThread = pThreadToWalk;
    m_pInstance = GetRuntimeInstance(); 
    m_ControlPC = 0;
    m_pCodeManager = NULL;
    m_pHijackedReturnValue = NULL;
    m_HijackedReturnValueKind = GCRK_Unknown;
    m_pConservativeStackRangeLowerBound = NULL;
    m_pConservativeStackRangeUpperBound = NULL;
    m_dwFlags = dwFlags;
    m_pNextExInfo = pThreadToWalk->GetCurExInfo();

    // 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(pCtx->GetSp());

    PTR_VOID ControlPC = dac_cast<PTR_VOID>(pCtx->GetIp());
    if (dwFlags & ApplyReturnAddressAdjustment)
        ControlPC = AdjustReturnAddressBackward(ControlPC);

    // 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(ControlPC, pCtx->GetFp());

    // This codepath is used by the hijack stackwalk and we can get arbitrary ControlPCs from there.  If this
    // context has a non-managed control PC, then we're done.
    if (!m_pInstance->FindCodeManagerByAddress(ControlPC))
        return;

    //
    // control state
    //
    m_ControlPC       = ControlPC;
    m_RegDisplay.SP   = pCtx->GetSp();
    m_RegDisplay.IP   = pCtx->GetIp();
    m_RegDisplay.pIP  = PTR_TO_MEMBER(PAL_LIMITED_CONTEXT, pCtx, IP);

#ifdef TARGET_ARM
    //
    // preserved regs
    //
    m_RegDisplay.pR4  = PTR_TO_MEMBER(PAL_LIMITED_CONTEXT, pCtx, R4);
    m_RegDisplay.pR5  = PTR_TO_MEMBER(PAL_LIMITED_CONTEXT, pCtx, R5);
    m_RegDisplay.pR6  = PTR_TO_MEMBER(PAL_LIMITED_CONTEXT, pCtx, R6);
    m_RegDisplay.pR7  = PTR_TO_MEMBER(PAL_LIMITED_CONTEXT, pCtx, R7);
    m_RegDisplay.pR8  = PTR_TO_MEMBER(PAL_LIMITED_CONTEXT, pCtx, R8);
    m_RegDisplay.pR9  = PTR_TO_MEMBER(PAL_LIMITED_CONTEXT, pCtx, R9);
    m_RegDisplay.pR10 = PTR_TO_MEMBER(PAL_LIMITED_CONTEXT, pCtx, R10);
    m_RegDisplay.pR11 = PTR_TO_MEMBER(PAL_LIMITED_CONTEXT, pCtx, R11);
    m_RegDisplay.pLR  = PTR_TO_MEMBER(PAL_LIMITED_CONTEXT, pCtx, LR);

    //
    // preserved vfp regs
    //
    for (Int32 i = 0; i < 16 - 8; i++)
    {
        m_RegDisplay.D[i] = pCtx->D[i];
    }
    //
    // scratch regs
    //
    m_RegDisplay.pR0  = PTR_TO_MEMBER(PAL_LIMITED_CONTEXT, pCtx, R0);
#else // TARGET_ARM
    //
    // preserved regs
    //
    m_RegDisplay.pRbp = PTR_TO_MEMBER(PAL_LIMITED_CONTEXT, pCtx, Rbp);
    m_RegDisplay.pRsi = PTR_TO_MEMBER(PAL_LIMITED_CONTEXT, pCtx, Rsi);
    m_RegDisplay.pRdi = PTR_TO_MEMBER(PAL_LIMITED_CONTEXT, pCtx, Rdi);
    m_RegDisplay.pRbx = PTR_TO_MEMBER(PAL_LIMITED_CONTEXT, pCtx, Rbx);
#ifdef TARGET_AMD64
    m_RegDisplay.pR12 = PTR_TO_MEMBER(PAL_LIMITED_CONTEXT, pCtx, R12);
    m_RegDisplay.pR13 = PTR_TO_MEMBER(PAL_LIMITED_CONTEXT, pCtx, R13);
    m_RegDisplay.pR14 = PTR_TO_MEMBER(PAL_LIMITED_CONTEXT, pCtx, R14);
    m_RegDisplay.pR15 = PTR_TO_MEMBER(PAL_LIMITED_CONTEXT, pCtx, R15);
    //
    // preserved xmm regs
    //
    memcpy(m_RegDisplay.Xmm, &pCtx->Xmm6, sizeof(m_RegDisplay.Xmm));
#endif // TARGET_AMD64

    //
    // scratch regs
    //
    m_RegDisplay.pRax = PTR_TO_MEMBER(PAL_LIMITED_CONTEXT, pCtx, Rax);
    m_RegDisplay.pRcx = NULL;
    m_RegDisplay.pRdx = NULL;
#ifdef TARGET_AMD64
    m_RegDisplay.pR8  = NULL;
    m_RegDisplay.pR9  = NULL;
    m_RegDisplay.pR10 = NULL;
    m_RegDisplay.pR11 = NULL;
#endif // TARGET_AMD64
#endif // TARGET_ARM
}
Beispiel #10
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);
}