예제 #1
0
파일: thread.cpp 프로젝트: ArildF/masters
//
// Callback for walking a thread's stack. Sends required frame data to the
// DI as send buffers fill up.
//
StackWalkAction DebuggerThread::TraceAndSendStackCallback(FrameInfo *pInfo, VOID* data)
{
    _RefreshStackFramesData *rsfd = (_RefreshStackFramesData*) data;
    Thread *t = rsfd->thread;
    DebuggerIPCEvent *pEvent = NULL;

    if (rsfd->iWhich == IPC_TARGET_INPROC)
    {
        pEvent = rsfd->pEvent;
    }
    else
    {
        _ASSERTE( rsfd->iWhich == IPC_TARGET_OUTOFPROC );
        pEvent = rsfd->rcThread->GetIPCEventSendBuffer(rsfd->iWhich);
    }

    // Record registers for the start of the next chain, if appropriate.
    if (rsfd->needChainRegisters)
    {
        rsfd->chainRegisters = pInfo->registers;
        rsfd->needChainRegisters = false;
    }

    // Only report frames which are chain boundaries, or are not marked internal.
    LOG((LF_CORDB, LL_INFO1000, "DT::TASSC:chainReason:0x%x internal:0x%x  "
         "md:0x%x **************************\n", pInfo->chainReason,
         pInfo->internal, pInfo->md));

    if (pInfo->chainReason == 0 && (pInfo->internal || pInfo->md == NULL))
        return SWA_CONTINUE;

#ifdef LOGGING
    if( pInfo->quickUnwind == true )
        LOG((LF_CORDB, LL_INFO10000, "DT::TASSC: rsfd => Doing quick unwind\n"));
#endif
    
    //
    // If we've filled this event, send it off to the Right Side
    // before continuing the walk.
    //
    if ((rsfd->eventSize + sizeof(DebuggerIPCE_STRData)) >= rsfd->eventMaxSize)
    {
        //
        //
        pEvent->StackTraceResultData.threadUserState = g_pEEInterface->GetUserState(t);
        
        if (rsfd->iWhich == IPC_TARGET_OUTOFPROC)            
        {
            rsfd->rcThread->SendIPCEvent(rsfd->iWhich);
        }
        else
        {
            DebuggerIPCEvent *peT;
            peT = rsfd->rcThread->GetIPCEventSendBufferContinuation(pEvent);

            if (peT == NULL)
            {
                pEvent->hr = E_OUTOFMEMORY;
                return SWA_ABORT;
            }
            
            CopyEventInfo(pEvent, peT);
            pEvent = peT;
            rsfd->pEvent = peT;
            rsfd->eventSize = 0;
        }
        //
        // Reset for the next set of frames.
        //
        pEvent->StackTraceResultData.traceCount = 0;
        rsfd->currentSTRData = &(pEvent->StackTraceResultData.traceData);
        rsfd->eventSize = (UINT_PTR)(rsfd->currentSTRData) - (UINT_PTR)(pEvent);
    }

    MethodDesc* fd = pInfo->md;
    
    if (fd != NULL && !pInfo->internal)
    {
        //
        // Send a frame
        //

        rsfd->currentSTRData->isChain = false;
        rsfd->currentSTRData->fp = pInfo->fp;
        rsfd->currentSTRData->quicklyUnwound = pInfo->quickUnwind;

        // Pass the appdomain that this thread was in when it was executing this frame to the Right Side.
        rsfd->currentSTRData->currentAppDomainToken = (void*)pInfo->currentAppDomain;

        REGDISPLAY* rd = &pInfo->registers;
        DebuggerREGDISPLAY* drd = &(rsfd->currentSTRData->rd);
        LPVOID FPAddress = GetRegdisplayFPAddress(rd);

        // Set some common elements
        drd->SP  = rd->SP;
        drd->PC   = (SIZE_T)*(rd->pPC);
        drd->FP  = (FPAddress == NULL ? 0 : *((SIZE_T *)FPAddress));

        //
        // PUSHED_REG_ADDR gives us NULL if the register still lives in the thread's context, or it gives us the address
        // of where the register was pushed for this frame.
        //
#define PUSHED_REG_ADDR(_a) (((UINT_PTR)(_a) >= (UINT_PTR)rd->pContext) && ((UINT_PTR)(_a) <= ((UINT_PTR)rd->pContext + sizeof(CONTEXT)))) ? NULL : (_a)

        // Frame pointer        
        drd->pFP = PUSHED_REG_ADDR(FPAddress);

#ifdef _X86_

        drd->pEdi = PUSHED_REG_ADDR(rd->pEdi);
        drd->Edi  = (rd->pEdi == NULL ? 0 : *(rd->pEdi));
        drd->pEsi = PUSHED_REG_ADDR(rd->pEsi);
        drd->Esi  = (rd->pEsi == NULL ? 0 : *(rd->pEsi));
        drd->pEbx = PUSHED_REG_ADDR(rd->pEbx);
        drd->Ebx  = (rd->pEbx == NULL ? 0 : *(rd->pEbx));
        drd->pEdx = PUSHED_REG_ADDR(rd->pEdx);
        drd->Edx  = (rd->pEdx == NULL ? 0 : *(rd->pEdx));
        drd->pEcx = PUSHED_REG_ADDR(rd->pEcx);
        drd->Ecx  = (rd->pEcx == NULL ? 0 : *(rd->pEcx));
        drd->pEax = PUSHED_REG_ADDR(rd->pEax);
        drd->Eax  = (rd->pEax == NULL ? 0 : *(rd->pEax));
        
        // Please leave EBP, ESP, EIP at the front so I don't have to scroll
        // left to see the most important registers.  Thanks!
        LOG( (LF_CORDB, LL_INFO1000, "DT::TASSC:Registers:"
            "Ebp = %x   Esp = %x   Eip = %x   Edi:%d   "
            "Esi = %x   Ebx = %x   Edx = %x   Ecx = %x   Eax = %x\n",
            drd->FP, drd->SP, drd->PC, drd->Edi,
            drd->Esi, drd->Ebx, drd->Edx, drd->Ecx, drd->Eax ) );
#elif defined(_PPC_) || defined (_SPARC_)
        // All that's needed for now
#else
        PORTABILITY_ASSERT("TraceAndSendStackCallback needs some munging for this platform.");
#endif
            
        DebuggerIPCE_FuncData* currentFuncData = &rsfd->currentSTRData->v.funcData;
        _ASSERTE(fd != NULL);

        GetVAInfo(&(currentFuncData->fVarArgs),
                  &(currentFuncData->rpSig),
                  &(currentFuncData->cbSig),
                  &(currentFuncData->rpFirstArg),
                  fd,
                  rd,
                  pInfo->relOffset);


        LOG((LF_CORDB, LL_INFO10000, "DT::TASSC: good frame for %s::%s\n",
             fd->m_pszDebugClassName,
             fd->m_pszDebugMethodName));

        //
        // Fill in information about the function that goes with this
        // frame.
        //
        currentFuncData->funcRVA = g_pEEInterface->MethodDescGetRVA(fd);
        _ASSERTE (t != NULL);
        
        Module *pRuntimeModule = g_pEEInterface->MethodDescGetModule(fd);
        AppDomain *pAppDomain = pInfo->currentAppDomain;
        currentFuncData->funcDebuggerModuleToken = (void*) g_pDebugger->LookupModule(pRuntimeModule, pAppDomain);
        
        if (currentFuncData->funcDebuggerModuleToken == NULL && rsfd->iWhich == IPC_TARGET_INPROC)
        {
            currentFuncData->funcDebuggerModuleToken = (void*)g_pDebugger->AddDebuggerModule(pRuntimeModule, pAppDomain);
            
            LOG((LF_CORDB, LL_INFO100, "DT::TASSC: load module Mod:%#08x AD:%#08x isDynamic:%#x runtimeMod:%#08x\n",
                 currentFuncData->funcDebuggerModuleToken, pAppDomain, pRuntimeModule->IsReflection(), pRuntimeModule));
        }                                   
        _ASSERTE(currentFuncData->funcDebuggerModuleToken != 0);
        
        currentFuncData->funcDebuggerAssemblyToken = 
            (g_pEEInterface->MethodDescGetModule(fd))->GetClassLoader()->GetAssembly();
        currentFuncData->funcMetadataToken = fd->GetMemberDef();

        currentFuncData->classMetadataToken = fd->GetClass()->GetCl();

        // Pass back the local var signature token.
        COR_ILMETHOD *CorILM = g_pEEInterface->MethodDescGetILHeader(fd);

        if (CorILM == NULL )
        {
            currentFuncData->localVarSigToken = mdSignatureNil;
            currentFuncData->ilStartAddress = NULL;
            currentFuncData->ilSize = 0;
            rsfd->currentSTRData->v.ILIP = NULL;

            currentFuncData->nativeStartAddressPtr = NULL;
            currentFuncData->nativeSize = 0;
            currentFuncData->nativenVersion = DebuggerJitInfo::DJI_VERSION_FIRST_VALID;
        }
        else
        {
            COR_ILMETHOD_DECODER ILHeader(CorILM);

            if (ILHeader.GetLocalVarSigTok() != 0)
                currentFuncData->localVarSigToken = ILHeader.GetLocalVarSigTok();
            else
                currentFuncData->localVarSigToken = mdSignatureNil; 
            //
            //
            currentFuncData->ilStartAddress = const_cast<BYTE*>(ILHeader.Code);
            currentFuncData->ilSize = ILHeader.GetCodeSize();

            currentFuncData->ilnVersion = g_pDebugger->GetVersionNumber(fd);

            LOG((LF_CORDB,LL_INFO10000,"Sending il Ver:0x%x in stack trace!\n", currentFuncData->ilnVersion));

            DebuggerJitInfo *jitInfo = g_pDebugger->GetJitInfo(fd, (const BYTE*)*pInfo->registers.pPC);

            if (jitInfo == NULL)
            {
                //EnC: Couldn't find the code;
                rsfd->currentSTRData->v.ILIP = NULL;

                // Note: always send back the size of the method. This
                // allows us to get the code, even when we haven't
                // been tracking. (Handling of the GetCode message
                // knows how to find the start address of the code, or
                // how to respond if is been pitched.)
                currentFuncData->nativeSize = g_pEEInterface->GetFunctionSize(fd);

                currentFuncData->nativeStartAddressPtr = NULL;
                currentFuncData->nativenVersion = DebuggerJitInfo::DJI_VERSION_FIRST_VALID;
                currentFuncData->CodeVersionToken = NULL;
                currentFuncData->ilToNativeMapAddr = NULL;
                currentFuncData->ilToNativeMapSize = 0;
                currentFuncData->nVersionMostRecentEnC = currentFuncData->ilnVersion;
            }
            else
            {
                LOG((LF_CORDB,LL_INFO10000,"DeTh::TASSC: Code: 0x%x Got DJI "
                     "0x%x, from 0x%x to 0x%x\n",(const BYTE*)drd->PC,jitInfo, 
                     jitInfo->m_addrOfCode, jitInfo->m_addrOfCode + 
                     jitInfo->m_sizeOfCode));
                
                DWORD whichIrrelevant;
                rsfd->currentSTRData->v.ILIP = const_cast<BYTE*>(ILHeader.Code) 
                    + jitInfo->MapNativeOffsetToIL((SIZE_T)pInfo->relOffset,
                                                   &rsfd->currentSTRData->v.mapping,
                                                   &whichIrrelevant);

                // Pass back the pointers to the sequence point map so
                // that the RIght Side can copy it out if needed.
                _ASSERTE(jitInfo->m_sequenceMapSorted);
                
                currentFuncData->ilToNativeMapAddr = jitInfo->m_sequenceMap;
                currentFuncData->ilToNativeMapSize = jitInfo->m_sequenceMapCount;
                
                if (!jitInfo->m_codePitched)
                {   // It's there & life is groovy
                    currentFuncData->nativeStartAddressPtr = &(jitInfo->m_addrOfCode);
                    currentFuncData->nativeSize = g_pEEInterface->GetFunctionSize(fd);
                    currentFuncData->nativenVersion = jitInfo->m_nVersion;
                    currentFuncData->CodeVersionToken = (void *)jitInfo;
                }
                else
                {
                    // It's been pitched
                    currentFuncData->nativeStartAddressPtr = NULL;
                    currentFuncData->nativeSize = 0;
                }
                
                LOG((LF_CORDB,LL_INFO10000,"Sending native Ver:0x%x Tok:0x%x in stack trace!\n",
                     currentFuncData->nativenVersion,currentFuncData->CodeVersionToken));
            }
        }

        currentFuncData->nativeOffset = (SIZE_T)pInfo->relOffset;

        //
        // Bump our pointers to the next space for the next frame.
        //
        pEvent->StackTraceResultData.traceCount++;
        rsfd->currentSTRData++;
        rsfd->eventSize += sizeof(DebuggerIPCE_STRData);
    }

    if (pInfo->chainReason != 0)
    {
        //
        // If we've filled this event, send it off to the Right Side
        // before continuing the walk.
        //
        if ((rsfd->eventSize + sizeof(DebuggerIPCE_STRData)) >=
            rsfd->eventMaxSize)
        {
            //
            //
            pEvent->StackTraceResultData.threadUserState = 
                g_pEEInterface->GetUserState(t);
                
            if (rsfd->iWhich == IPC_TARGET_OUTOFPROC)            
            {
                rsfd->rcThread->SendIPCEvent(rsfd->iWhich);
            }
            else
            {
                DebuggerIPCEvent *peT;
                peT = rsfd->rcThread->GetIPCEventSendBufferContinuation(pEvent);
                
                if (peT == NULL)
                {
                    pEvent->hr = E_OUTOFMEMORY;
                    return SWA_ABORT;
                }
                
                CopyEventInfo(pEvent, peT);                    
                pEvent = peT;
                rsfd->pEvent = peT;
                rsfd->eventSize = 0;
            }

            //
            // Reset for the next set of frames.
            //
            pEvent->StackTraceResultData.traceCount = 0;
            rsfd->currentSTRData = &(pEvent->StackTraceResultData.traceData);
            rsfd->eventSize = (UINT_PTR)(rsfd->currentSTRData) -
                (UINT_PTR)(pEvent);
        }

        //
        // Send a chain boundary
        //

        rsfd->currentSTRData->isChain = true;
        rsfd->currentSTRData->u.chainReason = pInfo->chainReason;
        rsfd->currentSTRData->u.managed = pInfo->managed;
        rsfd->currentSTRData->u.context = pInfo->context;
        rsfd->currentSTRData->fp = pInfo->fp;
        rsfd->currentSTRData->quicklyUnwound = pInfo->quickUnwind;

#ifdef _DEBUG
        REGDISPLAY* rd = &rsfd->chainRegisters;
#endif  // _DEBUG

#ifdef _X86_
        LOG( (LF_CORDB, LL_INFO1000, "DT::TASSC:Registers:  Edi:%d \
  Esi = %x   Ebx = %x   Edx = %x   Ecx = %x   Eax = %x   Ebp = %x\n", (rd->pEdi == NULL ? 0 : *(rd->pEdi)),
              (rd->pEsi == NULL ? 0 : *(rd->pEsi)), (rd->pEbx == NULL ? 0 : *(rd->pEbx)), 
              (rd->pEdx == NULL ? 0 : *(rd->pEdx)), (rd->pEcx == NULL ? 0 : *(rd->pEcx)), 
              (rd->pEax == NULL ? 0 : *(rd->pEax)), (rd->pEbp == NULL ? 0 : *(rd->pEbp))) );
#endif
        LOG( (LF_CORDB, LL_INFO1000, "DT::TASSC:PC:  PC:%x    SP:%x\n",
             (SIZE_T)*(rd->pPC), rd->SP));
            
        rsfd->needChainRegisters = true;

        //
        // Bump our pointers to the next space for the next frame.
        //
        pEvent->StackTraceResultData.traceCount++;
        rsfd->currentSTRData++;
        rsfd->eventSize += sizeof(DebuggerIPCE_STRData);
    }

    return SWA_CONTINUE;
}
예제 #2
0
//+----------------------------------------------------------------------------
//
//  Function:   CallDescrWithObjectArray, private
//
//  Synopsis:   Builds the stack from a object array and call the object
//
// Note this function triggers GC and assumes that pServer, pArguments, pVarRet, and ppVarOutParams are
// all already protected!!
//+----------------------------------------------------------------------------
void CallDescrWithObjectArray(OBJECTREF& pServer, 
                  ReflectMethod *pRM, 
                  const BYTE *pTarget, 
                  MetaSig* sig, 
                  VASigCookie *pCookie,
                  BOOL fIsStatic,  
                  PTRARRAYREF& pArgArray,
                  OBJECTREF *pVarRet,
                  PTRARRAYREF *ppVarOutParams) 
{
    THROWSCOMPLUSEXCEPTION();
    TRIGGERSGC();       // the debugger, profiler code triggers a GC

    LOG((LF_REMOTING, LL_INFO10,
         "CallDescrWithObjectArray IN\n"));

    ByRefInfo *pByRefs = NULL;
    INT64 retval = 0;
    UINT  nActualStackBytes = 0;
    LPBYTE pAlloc = 0;
    LPBYTE pFrameBase = 0;
    UINT32 numByRef = 0;
    DWORD attr = pRM->dwFlags;
#ifdef _DEBUG
    MethodDesc *pMD = pRM->pMethod;
#endif

    // check the calling convention

    BYTE callingconvention = sig->GetCallingConvention();
    if (!isCallConv(callingconvention, IMAGE_CEE_CS_CALLCONV_DEFAULT))
    {
        _ASSERTE(!"This calling convention is not supported.");
        COMPlusThrow(kInvalidProgramException);
    }

#ifdef DEBUGGING_SUPPORTED
    // debugger goo What does this do? can someone put a comment here?
    if (CORDebuggerTraceCall())
        g_pDebugInterface->TraceCall(pTarget);
#endif // DEBUGGING_SUPPORTED

#ifdef PROFILING_SUPPORTED
    // If we're profiling, notify the profiler that we're about to invoke the remoting target
    if (CORProfilerTrackRemoting())
        g_profControlBlock.pProfInterface->RemotingServerInvocationStarted(
            reinterpret_cast<ThreadID>(GetThread()));
#endif // PROFILING_SUPPORTED
        
    // Create a fake FramedMethodFrame on the stack.
    nActualStackBytes = sig->SizeOfActualFixedArgStack(fIsStatic);
    pAlloc = (LPBYTE)_alloca(FramedMethodFrame::GetNegSpaceSize() + sizeof(FramedMethodFrame) + nActualStackBytes);
    pFrameBase = pAlloc + FramedMethodFrame::GetNegSpaceSize();


    // cycle through the parameters and see if there are byrefs

    BYTE typ = 0;
    BOOL   fHasByRefs = FALSE;

    if (attr & RM_ATTR_BYREF_FLAG_SET)
        fHasByRefs = attr & RM_ATTR_HAS_BYREF_ARG;
    else
    {
        sig->Reset();
        while ((typ = sig->NextArg()) != ELEMENT_TYPE_END)
        {
            if (typ == ELEMENT_TYPE_BYREF)
            {
                fHasByRefs = TRUE;
                attr |= RM_ATTR_HAS_BYREF_ARG;
                break;
            }
        }
        attr |= RM_ATTR_BYREF_FLAG_SET;
        pRM->dwFlags = attr;
        sig->Reset();
    }

    int nFixedArgs = sig->NumFixedArgs();
    // if there are byrefs allocate and array for the out parameters

    if (fHasByRefs)
    {
        *ppVarOutParams = PTRARRAYREF(AllocateObjectArray(sig->NumFixedArgs(), g_pObjectClass));

        // Null out the array
        memset(&(*ppVarOutParams)->m_Array, 0, sizeof(OBJECTREF) * sig->NumFixedArgs());
    }

    ArgIterator argit(pFrameBase, sig, fIsStatic);

    // set the this pointer
    OBJECTREF *ppThis = (OBJECTREF*)argit.GetThisAddr();
    *ppThis = NULL;

    // if there is a return buffer, allocate it
    if (sig->HasRetBuffArg()) 
    {
        EEClass *pEECValue = sig->GetRetEEClass();
        _ASSERTE(pEECValue->IsValueClass());
        MethodTable * mt = pEECValue->GetMethodTable();
        *pVarRet = AllocateObject(mt);

        *(argit.GetRetBuffArgAddr()) = (*pVarRet)->UnBox();

#if defined(_PPC_) || defined(_SPARC_) // retbuf
        // the CallDescrWorker callsite for methods with return buffer is 
        //  different for RISC CPUs - we pass this information along by setting 
        //  the lowest bit in pTarget
        pTarget = (const BYTE *)((UINT_PTR)pTarget | 0x1);
#endif
    }



    // gather data about the parameters by iterating over the sig:
    UINT32 arg = 0;    
    UINT32 structSize = 0;
    int    ofs = 0;
    // REVIEW: need to use actual arg count if VarArgs are supported
    ArgInfo* pArgInfo = (ArgInfo*) _alloca(nFixedArgs*sizeof(ArgInfo));
#ifdef _DEBUG
    // We expect to write useful data over every part of this so need
    // not do this in retail!
    memset((void *)pArgInfo, 0, sizeof(ArgInfo)*nFixedArgs);
#endif
    for( ; 0 != (ofs = argit.GetNextOffset(&typ, &structSize)); arg++, pArgInfo++ )
    {


        if (typ == ELEMENT_TYPE_BYREF)
        {
            EEClass *pClass = NULL;
            CorElementType brType = sig->GetByRefType(&pClass);
            if (CorIsPrimitiveType(brType))
            {
                pArgInfo->dataSize = gElementTypeInfo[brType].m_cbSize;
            }
            else if (pClass->IsValueClass())
            {
                pArgInfo->dataSize = pClass->GetAlignedNumInstanceFieldBytes();
                numByRef ++;
            }
            else
            {

                pArgInfo->dataSize = sizeof(Object *);
                numByRef ++;
            }
            ByRefInfo *brInfo = (ByRefInfo *) _alloca(offsetof(ByRefInfo,data) + pArgInfo->dataSize);
            brInfo->argIndex = arg;
            brInfo->typ = brType;
            brInfo->pClass = pClass;
            brInfo->pNext = pByRefs;
            pByRefs = brInfo;
            pArgInfo->dataLocation = (BYTE*)brInfo->data;
            *((void**)(pFrameBase + ofs)) = (void*)pArgInfo->dataLocation;
            pArgInfo->dataClass = pClass;
            pArgInfo->dataType = brType;
            pArgInfo->byref = TRUE;
        }
        else
        {
            pArgInfo->dataLocation = pFrameBase + ofs;
            pArgInfo->dataSize = StackElemSize(structSize);
            pArgInfo->dataClass = sig->GetTypeHandle().GetClass(); // this may cause GC!
            pArgInfo->dataType = typ;
            pArgInfo->byref = FALSE;
        }  
    }

    if (!fIsStatic) {
        // If this isn't a value class, verify the objectref
#ifdef _DEBUG
        if (pMD->GetClass()->IsValueClass() == FALSE)
        {
            VALIDATEOBJECTREF(pServer);
        }
#endif //_DEBUG
        *ppThis = pServer;
     }

    // There should be no GC when we fill up the stack with parameters, as we don't protect them
    // Assignment of "*ppThis" above triggers the point where we become unprotected.
    BEGINFORBIDGC();


    // reset pArgInfo to point to the start of the block we _alloca-ed
    pArgInfo = pArgInfo-nFixedArgs;

    PBYTE             dataLocation;
    INT32             dataSize;
    EEClass          *dataClass;
    BYTE              dataType;

    OBJECTREF* pArguments = pArgArray->m_Array;
    UINT32 i, j = arg;
    for (i=0; i<j; i++)
    {
        dataSize = pArgInfo->dataSize;
        dataLocation = pArgInfo->dataLocation;
        dataClass = pArgInfo->dataClass;
        dataType = pArgInfo->dataType;

        switch (dataSize) 
        {
            case 1:
                // This "if" statement is necessary to make the assignement big-endian aware
                if (pArgInfo->byref)
                    *((INT8*)dataLocation) = *((INT8*)pArguments[i]->GetData());
                else
                    *(StackElemType*)dataLocation = (StackElemType)*((INT8*)pArguments[i]->GetData());
                break;
            case 2:
                // This "if" statement is necessary to make the assignement big-endian aware
                if (pArgInfo->byref)
                    *((INT16*)dataLocation) = *((INT16*)pArguments[i]->GetData());
                else
                    *(StackElemType*)dataLocation = (StackElemType)*((INT16*)pArguments[i]->GetData());
                break;
            case 4:
                if ((dataType == ELEMENT_TYPE_STRING)  ||
                    (dataType == ELEMENT_TYPE_OBJECT)  ||
                    (dataType == ELEMENT_TYPE_CLASS)   ||
                    (dataType == ELEMENT_TYPE_SZARRAY) ||
                    (dataType == ELEMENT_TYPE_ARRAY))
                {
                    *(OBJECTREF *)dataLocation = pArguments[i];
                }
                else
                {
                    *(StackElemType*)dataLocation = (StackElemType)*((INT32*)pArguments[i]->GetData());
                }
                break;

            case 8:
                *((INT64*)dataLocation) = *((INT64*)pArguments[i]->GetData());
                break;

            default:
            {
                memcpy(dataLocation, pArguments[i]->UnBox(), dataSize);
            }
        }

        pArgInfo++;
    }
#ifdef _DEBUG
    // Should not be using this any more
    pArgInfo = pArgInfo - nFixedArgs;
    memset((void *)pArgInfo, 0, sizeof(ArgInfo)*nFixedArgs);
#endif

    // if there were byrefs, push a protection frame

    ProtectByRefsFrame *pProtectionFrame = NULL;    
    if (pByRefs && numByRef > 0)
    {
        char *pBuffer = (char*)_alloca (sizeof (ProtectByRefsFrame));
        pProtectionFrame = new (pBuffer) ProtectByRefsFrame(GetThread(), pByRefs);
    }

    // call the correct worker function depending of if the method
    // is varargs or not

    ENDFORBIDGC();

#ifdef _PPC_
    FramedMethodFrame::Enregister(pFrameBase, sig, fIsStatic, nActualStackBytes);
#endif

    INSTALL_COMPLUS_EXCEPTION_HANDLER();

    retval = CallDescrWorker(
                pFrameBase + sizeof(FramedMethodFrame) + nActualStackBytes,
                nActualStackBytes / STACK_ELEM_SIZE,
#if defined(_X86_) || defined(_PPC_) // argregs
                (ArgumentRegisters*)(pFrameBase + FramedMethodFrame::GetOffsetOfArgumentRegisters()),
#endif
                (LPVOID)pTarget);

    UNINSTALL_COMPLUS_EXCEPTION_HANDLER();

    // set floating point return values

    getFPReturn(sig->GetFPReturnSize(), &retval);

    // need to build a object based on the return type.
    
    if (!sig->HasRetBuffArg()) 
    {
        BYTE *pRetVal = (BYTE*)&retval;

#ifdef BIGENDIAN
        switch (sig->GetReturnTypeSize())
        {
        case 1:
            pRetVal += sizeof(void*)-1;
            break;
        case 2:
            pRetVal += sizeof(void*)-2;
            break;
        default:
            // nothing to do
            break;
        }
#endif

        GetObjectFromStack(pVarRet, pRetVal, sig->GetReturnType(), sig->GetRetEEClass());
    }

    // extract the out args from the byrefs

    if (pByRefs)
    {     
        do
        {
            // Always extract the data ptr every time we enter this loop because
            // calls to GetObjectFromStack below can cause a GC.
            // Even this is not enough, because that we are passing a pointer to GC heap
            // to GetObjectFromStack .  If GC happens, nobody is protecting the passed in pointer.

            OBJECTREF pTmp = NULL;
            GetObjectFromStack(&pTmp, pByRefs->data, pByRefs->typ, pByRefs->pClass);
            (*ppVarOutParams)->SetAt(pByRefs->argIndex, pTmp);
            pByRefs = pByRefs->pNext;
        }
        while (pByRefs);
        if (pProtectionFrame) pProtectionFrame->Pop();
    }

#ifdef PROFILING_SUPPORTED
    // If we're profiling, notify the profiler that we're about to invoke the remoting target
    if (CORProfilerTrackRemoting())
        g_profControlBlock.pProfInterface->RemotingServerInvocationReturned(
            reinterpret_cast<ThreadID>(GetThread()));
#endif // PROFILING_SUPPORTED

    LOG((LF_REMOTING, LL_INFO10, "CallDescrWithObjectArray OUT\n"));
}