/*** DEBEVAL.C - Expression evaluator main routines */ #include "debexpr.h" #define WINDBG_POINTERS_MACROS_ONLY #include "sundown.h" #undef WINDBG_POINTERS_MACROS_ONLY // Return values from Logical (). #define DL_DEBERR 1 // Error occurred, DebErr is set #define DL_SUCCESS 2 // Evaluation successful #define DL_CONTINUE 3 // Inconclusive, continue evaluation // Actions to be taken by EvalUtil(). #define EU_LOAD 0x0001 // Load node values #define EU_TYPE 0x0002 // Do implicit type coercion uint Logical (op_t, bool_t); bool_t FASTCALL CalcThisExpr (CV_typ_t, UOFFSET, UOFFSET, CV_typ_t); bool_t DerefVBPtr (CV_typ_t); bool_t FASTCALL Eval (bnode_t); bool_t FASTCALL EvalAddrOf (bnode_t); bool_t FASTCALL EvalArray (bnode_t); bool_t FASTCALL EvalAssign (bnode_t); bool_t FASTCALL EvalBang (bnode_t); bool_t FASTCALL EvalBasePtr (bnode_t); bool_t FASTCALL EvalBinary (bnode_t); bool_t FASTCALL EvalBScope (bnode_t); bool_t FASTCALL EvalByteOps (bnode_t); bool_t FASTCALL EvalCast (bnode_t); bool_t FASTCALL EvalContext (bnode_t); bool_t FASTCALL EvalDMember (bnode_t); bool_t FASTCALL EvalDot (bnode_t); bool_t FASTCALL EvalError (register bnode_t); bool_t FASTCALL EvalFetch (bnode_t); bool_t FASTCALL EvalFunction (bnode_t); bool_t FASTCALL EvalLChild (bnode_t); bool_t FASTCALL EvalLogical (bnode_t); bool_t FASTCALL EvalRChild (bnode_t); bool_t FASTCALL EvalParent (bnode_t); bool_t FASTCALL EvalPlusMinus (bnode_t); bool_t FASTCALL EvalPMember (bnode_t); bool_t FASTCALL EvalPostIncDec (bnode_t); bool_t FASTCALL EvalPreIncDec (bnode_t); bool_t FASTCALL EvalPointsTo (bnode_t); bool_t FASTCALL EvalPushNode (bnode_t); bool_t FASTCALL EvalRelat (bnode_t); bool_t FASTCALL EvalRetVal (bnode_t); bool_t FASTCALL EvalSegOp (bnode_t); bool_t FASTCALL EvalThisInit (bnode_t); bool_t FASTCALL EvalThisConst (bnode_t); bool_t FASTCALL EvalThisExpr (bnode_t); bool_t FASTCALL EvalUnary (bnode_t); bool_t FASTCALL EvalUScope (bnode_t); bool_t FASTCALL EVArith (op_t); bool_t FASTCALL Assign (op_t); bool_t FASTCALL EvalUtil (op_t, peval_t, peval_t, ulong ); bool_t FASTCALL FetchOp (peval_t pv); bool_t FASTCALL InitConst (long); bool_t FASTCALL IsStringLiteral (peval_t); bool_t FASTCALL EVPlusMinus (op_t); INLINE bool_t EVPrePost (op_t); bool_t FASTCALL Relational (op_t); bool_t FASTCALL SBitField (void); bool_t FASTCALL StructEval (bnode_t); bool_t FASTCALL StructElem (bnode_t); bool_t ThisOffset (peval_t); bool_t FASTCALL EVUnary (op_t); bool_t PushArgs (pnode_t, SHREG *, UOFFSET*); bool_t PushOffset (UOFFSET, SHREG *, UOFFSET *, ulong ); bool_t PushString (peval_t, SHREG *, CV_typ_t, BOOL Is32); bool_t PushRef (peval_t, SHREG *, CV_typ_t, BOOL Is32); bool_t PushUserValue (peval_t, pargd_t, SHREG *, UOFFSET *); bool_t StoreC (peval_t); bool_t StoreP (void); bool_t StoreF (void); bool_t Store32 (peval_t); bool_t StoreMips (peval_t); bool_t StoreAlpha (peval_t); bool_t StorePPC (peval_t); bool_t StoreIa64 (peval_t); INLINE bool_t VFuncAddress (peval_t, ulong ); INLINE bool_t VFuncAddress2 (peval_t, peval_t); INLINE ULONG MakeLong (USHORT, USHORT); INLINE USHORT LoWord (ULONG); INLINE USHORT HiWord (ULONG); INLINE BOOL getFuncAddrNoThunks (peval_t pv); eval_t ThisAddress; const peval_t pvThis = &ThisAddress; // Bind dispatch table bool_t (NEAR FASTCALL *SEGBASED(_segname("_CODE"))pEval[]) (bnode_t) = { #define OPCNT(name, val) #define OPCDAT(opc) #define OPDAT(op, opfprec, opgprec, opclass, opbind, opeval) opeval, #include "debops.h" #undef OPDAT #undef OPCDAT #undef OPCNT }; bool_t FASTCALL EvalError (register bnode_t bn) { Unreferenced(bn); pExState->err_num = ERR_INTERNAL; return (FALSE); } bool_t FASTCALL Eval (bnode_t bn) { return ((*pEval[NODE_OP((pnode_t)bn)])(bn)); } bool_t FASTCALL EvalLChild (bnode_t bn) { register bnode_t bnL = NODE_LCHILD (bn); return ((*pEval[NODE_OP(bnL)])(bnL)); } bool_t FASTCALL EvalRChild (bnode_t bn) { register bnode_t bnR = NODE_RCHILD (bn); return ((*pEval[NODE_OP(bnR)])(bnR)); } // os independent long double (10 byte reals) support // check for 32-bit compiler and existence of long doubles. #if (_MSC_VER >= 800) && defined(_M_IX86) && (_M_IX86 >= 300) #pragma message("WARNING:floating point code not portable to non-x86 CPU's") FLOAT10 __inline Float10FromLong ( long lSrc ) { FLOAT10 f10Ret; __asm { fild lSrc fstp tbyte ptr f10Ret; fwait } return f10Ret; } FLOAT10 __inline Float10Negate ( FLOAT10 flt10 ) { double dNeg1 = -1.0; FLOAT10 f10Ret; __asm { fld tbyte ptr flt10 fmul qword ptr dNeg1 fstp tbyte ptr f10Ret fwait } return f10Ret; } FLOAT10 __inline Float10OpPlus ( FLOAT10 f1, FLOAT10 f2 ) { FLOAT10 f10Ret; __asm { fld tbyte ptr f1 fld tbyte ptr f2 faddp st(1), st(0) fstp tbyte ptr f10Ret fwait } return f10Ret; } FLOAT10 __inline Float10OpMinus ( FLOAT10 f1, FLOAT10 f2 ) { FLOAT10 f10Ret; __asm { fld tbyte ptr f1 fld tbyte ptr f2 fsubp st(1), st(0) fstp tbyte ptr f10Ret fwait } return f10Ret; } FLOAT10 __inline Float10OpMul ( FLOAT10 f1, FLOAT10 f2 ) { FLOAT10 f10Ret; __asm { fld tbyte ptr f1 fld tbyte ptr f2 fmulp st(1), st(0) fstp tbyte ptr f10Ret fwait } return f10Ret; } FLOAT10 __inline Float10OpDiv ( FLOAT10 f1, FLOAT10 f2 ) { FLOAT10 f10Ret; __asm { fld tbyte ptr f1 fld tbyte ptr f2 fdivp st(1), st(0) fstp tbyte ptr f10Ret fwait } return f10Ret; } FLOAT10 __inline Float10Zero () { FLOAT10 f10Ret; __asm { fldz fstp tbyte ptr f10Ret fwait } return f10Ret; } #pragma warning(disable:4035) int __inline Float10Equal ( FLOAT10 f1, FLOAT10 f2 ) { __asm { fld tbyte ptr f1 fld tbyte ptr f2 fcompp fnstsw ax fwait sahf mov eax, 0 // can't use xor or sub eax,eax because of flags!!! sete al } // note: leaves result in eax! } int __inline Float10LessThan ( FLOAT10 f1, FLOAT10 f2 ) { __asm { fld tbyte ptr f1 fld tbyte ptr f2 fcompp fnstsw ax fwait sahf mov eax, 0 // can't use xor or sub eax,eax because of flags!!! seta al } // note: leaves result in eax! } #pragma warning(default:4035) #else // float10 is really a long double in this case FLOAT10 __inline Float10FromLong ( long lSrc ) { FLOAT10 f10; DASSERT(FALSE); return f10; //return (FLOAT10) lSrc; } FLOAT10 __inline Float10Negate ( FLOAT10 flt10 ) { DASSERT(FALSE); return flt10; //return -flt10; } FLOAT10 __inline Float10OpPlus ( FLOAT10 f1, FLOAT10 f2 ) { DASSERT(FALSE); return f1; //return f1 + f2; } FLOAT10 __inline Float10OpMinus ( FLOAT10 f1, FLOAT10 f2 ) { DASSERT(FALSE); return f1; //return f1 - f2; } FLOAT10 __inline Float10OpMul ( FLOAT10 f1, FLOAT10 f2 ) { DASSERT(FALSE); return f1; //return f1 * f2; } FLOAT10 __inline Float10OpDiv ( FLOAT10 f1, FLOAT10 f2 ) { DASSERT(FALSE); return f1; //return f1 / f2; } FLOAT10 __inline Float10Zero () { static FLOAT10 f10zero; DASSERT(FALSE); return f10zero; //return 0.0; } int __inline Float10Equal ( FLOAT10 f1, FLOAT10 f2 ) { DASSERT(FALSE); return 0; //return f1 == f2; } int __inline Float10LessThan ( FLOAT10 f1, FLOAT10 f2 ) { DASSERT(FALSE); return 0; //return f1 < f2; } #endif /*** DoEval - Evaluate parse tree * SYNOPSIS * error = DoEval () * ENTRY * none * RETURNS * True if tree evaluated without error. * DESCRIPTION * The parser will call this routine to evaluate the parse tree * NOTES */ bool_t DoEval (PHTM phTM, HFRAME hFrame, EEDSP style) { ulong retval = EEGENERAL; bool_t evalstate; pexstate_t pParentTM; bool_t fIncrementalEval = FALSE; // lock the expression state structure, save the formatting style // and frame DASSERT (*phTM != 0); if (*phTM == 0) { return (EECATASTROPHIC); } pExState = (pexstate_t) MemLock (*phTM); if (pExState->hParentTM) { pParentTM = (pexstate_t) MemLock (pExState->hParentTM); if (pParentTM->state.bind_ok && pExState->cxt.hBlk == pParentTM->cxt.hBlk && pExState->cxt.hProc == pParentTM->cxt.hProc && pExState->cxt.hMod == pParentTM->cxt.hMod ) { // The parent TM has been bound in // the same scope as the child TM if (pParentTM->state.eval_ok && pParentTM->timeStamp >= GetTickCounter()) { // parent TM contains an up-to-date value, // that can be used for incremental evaluation fIncrementalEval = TRUE; } else if (pParentTM->err_num == 0){ // err_num check is just a heuristic: // attempt to reevaluate parent TM (even // if it has never been evaluated before) // but prevent continuous reevaluations of // ancestor TMs that can't be evaluated // anyway pexstate_t pExStateSav; EESTATUS error; pExStateSav = pExState; error = DoEval (&pExStateSav->hParentTM, hFrame, style); pExState = pExStateSav; if (EENOERROR == error) { fIncrementalEval = TRUE; } } } MemUnLock (pExState->hParentTM); } pExState->style = style; pExState->hframe = hFrame; pCxt = &pExState->cxt; pExState->err_num = ERR_NOTEVALUATABLE; //DASSERT (pExState->state.parse_ok == TRUE); //DASSERT (pExState->state.bind_ok == TRUE); //DASSERT (pExState->hSTree != 0); if ((pExState->state.parse_ok == TRUE) && (pExState->state.bind_ok == TRUE) && pExState->hETree) { pTree = (pstree_t) MemLock (pExState->hETree); // DASSERT (hEStack != 0); // Codeview may reevaluate with a new EE without rebinding // In that case the hEStack of the new EE may be null // caviar #3804 --gdp 9/29/92 if (hEStack == 0) { if ((hEStack = MHMemAllocate (ESTACK_DEFAULT * sizeof (elem_t))) == 0) { return (EECATASTROPHIC); } StackLen = (belem_t)(ESTACK_DEFAULT * sizeof (elem_t)); } pEStack = (pelem_t) MemLock (hEStack); StackMax = 0; StackCkPoint = 0; StackOffset = 0; pExState->err_num = 0; ST = NULL; STP = NULL; pExStr = (char *) MemLock (pExState->hExStr); // zero out type of ThisAddress so that users can check to see if // ThisAddress has been correctly initialized bnCxt = 0; EVAL_TYP (pvThis) = 0; Evaluating = TRUE; { SHREG spReg; bnode_t bnParent = 0; bnode_t bnRoot; op_t opSav; bnRoot = (bnode_t)pTree->start_node; if (fIncrementalEval && (bnParent = GetParentSubtree(bnRoot, pExState->seTemplate)) != 0) { opSav = NODE_OP (bnParent); NODE_OP (bnParent) = OP_parent; } // do the evaluation -- any function args/temporaries will // stay on the users stack for the whole eval [rm] evalstate = Eval (bnRoot); if (fIncrementalEval && bnParent) { // restore evaluation tree to its original form NODE_OP (bnParent) = opSav; } } Evaluating = FALSE; bnCxt = 0; MemUnLock (pExState->hExStr); // If the input consisted of a single identifier (i.e., no // operators involved), then the resulting value may still // be an identifier. Look it up in the symbols. if (evalstate == TRUE) { uint access = pExState->result.flags.bits.access; if (EVAL_STATE (&pExState->result) == EV_type) { EVAL_STATE (ST) = EV_type; } pExState->result = *ST; // restore the access flags from the bind phase --gdp pExState->result.flags.bits.access = access; pExState->state.eval_ok = TRUE; pExState->state.fAEreeval = TRUE; // set eval timestamp pExState->timeStamp = GetTickCounter(); pExState->evalThisSav = *pvThis; retval = EENOERROR; } else { retval = EECATASTROPHIC; // EEGENERAL; } MemUnLock (hEStack); MemUnLock (pExState->hETree); } MemUnLock (*phTM); return (retval); } bool_t FASTCALL EvalPushNode (bnode_t bn) { #if 1 // kentf bool_t Ok; Ok = PushStack (&bn->v[0]); if ( Ok && EVAL_IS_CURPC( ST ) ) { // Get current PC #pragma message("Need investigation on SYSGetAddr(&(EVAL_PTR(ST)),adrPC)") SYGetAddr(pExState->hframe, &(EVAL_PTR(ST)), adrPC); EVAL_IS_ADDR( ST ) = TRUE; EVAL_IS_BPREL( ST ) = FALSE; EVAL_IS_REGREL( ST ) = FALSE; EVAL_IS_TLSREL( ST ) = FALSE; // correctly set the type based on the size of the PC if (MODE_IS_FLAT(EVAL_PTR_MODE(ST))) { EVAL_TYP(ST) = T_32PCHAR; } else { EVAL_TYP(ST) = T_PCHAR; } } return Ok; #else // kentf bool_t Ok; ADDR addr; Ok = PushStack (&bn->v[0]); if ( Ok && EVAL_IS_CURPC( ST ) ) { // Get current PC // The original code is commented out. // The replacement code may not work. // Once the ide tree is running, BryanT // will investigate. // SYGetAddr( &(EVAL_PTR( ST )), adrPC); memset(&addr, 0, sizeof(ADDR)); emiAddr(addr) = emiAddr(EVAL_SYM(ST)); #pragma message("Need investigation on SYSGetAddr(&(EVAL_PTR(ST)),adrPC)") EVAL_SYM_OFF(ST) += GetAddrOff(addr); EVAL_SYM_SEG(ST) = GetAddrSeg(addr); EVAL_IS_ADDR( ST ) = TRUE; EVAL_IS_BPREL( ST ) = FALSE; EVAL_IS_REGREL( ST ) = FALSE; EVAL_IS_TLSREL( ST ) = FALSE; } return Ok; #endif // kentf } /** EvalParent - evaluate parent subexpression * fSuccess = EvalParent (bn) * Entry bn = based pointer to node * Returns TRUE if no error during evaluation * FALSE if error during evaluation * DESCRIPTION * Evaluates a parent subexpression that is embedded * in a child expression by accessing the evaluated * result of the parent TM. The parent TM must have * been evaluated before this function gets control. */ bool_t FASTCALL EvalParent (bnode_t bn) { pexstate_t pTM; bool_t retval; if (!pExState->hParentTM) { DASSERT (FALSE); return FALSE; } pTM = (pexstate_t) MemLock (pExState->hParentTM); DASSERT (pTM->state.eval_ok); *pvThis = pTM->evalThisSav; retval = PushStack (&pTM->result); MemUnLock (pExState->hParentTM); return retval; } /** EvalUnary - perform a unary arithmetic operation * fSuccess = EvalUnary (bn) * Entry bn = based pointer to node * Returns TRUE if no error during evaluation * FALSE if error during evaluation * DESCRIPTION * Evaluates the result of an arithmetic operation. The unary operators * dealt with here are: * ~ - + * Pointer arithmetic is NOT handled; all operands must be of * arithmetic type. */ bool_t FASTCALL EvalUnary (bnode_t bn) { if (EvalLChild (bn)) { return (EVUnary (NODE_OP (bn))); } return (FALSE); } /*** EvalBasePtr - Perform a based pointer access (:>) * fSuccess = EvalBasePtr (bnRight) * Entry bnRight = based pointer to right operand node * Exit * Returns TRUE if successful * FALSE if error */ bool_t FASTCALL EvalBasePtr (bnode_t bn) { return (EvalSegOp (bn)); } /** EvalBinary - evaluate a binary arithmetic operation * fSuccess = EvalBinary (bn) * Entry bn = based pointer to node * Returns TRUE if no error during evaluation * FALSE if error during evaluation */ bool_t FASTCALL EvalBinary (bnode_t bn) { if (EvalLChild (bn) && EvalRChild (bn)) { return (EVArith (NODE_OP (bn))); } return (FALSE); } /*** EvalPlusMinus - Evaluate binary plus or minus * fSuccess = EvalPlusMinus (bn) * Entry bn = based pointer to tree node * Exit ST = STP +- ST * Returns TRUE if Eval successful * FALSE if Eval error */ bool_t FASTCALL EvalPlusMinus (bnode_t bn) { if (EvalLChild (bn) && EvalRChild (bn)) { return (EVPlusMinus (NODE_OP (bn))); } return (FALSE); } /*** EvalDot - Perform the dot ('.') operation * fSuccess = EvalDot (bn) * Entry bn = based pointer to tree node * Exit NODE_STYPE (bn) = type of stack top * Returns TRUE if Eval successful * FALSE if Eval error * Exit pExState->err_num = error ordinal if Eval error */ bool_t FASTCALL EvalDot (bnode_t bn) { if (!EvalLChild (bn)) { return (FALSE); } if (EVAL_STATE (ST) == EV_rvalue && !EVAL_IS_REF (ST)) { return (StructElem (bn)); } else { return (StructEval (bn)); } } /** EvalLogical - Handle '&&' and '||' operators * wStatus = EvalLogical (bn) * Entry op = Operand (OP_andand or OP_oror) * REval = FALSE if right hand not evaluated * ST = left hand value * REval = TRUE if right hand evaluated * STP = left hand value * ST = right hand value * Returns wStatus = evaluation status * (REval = TRUE) * DL_DEBERR Evaluation failed, DebErr is set * DL_SUCCESS Evaluation succeeded, result in ST * (REVAL == FALSE) * DL_DEBERR Evaluation failed, * DL_SUCCESS Evaluation succeeded, result in ST * DL_CONTINUE Evaluation inconclusive, must evaluate right node * DESCRIPTION * If (REval = TRUE), checks that both operands (STP and ST) are of scalar * type and evaluates the result (0 or 1). * If (REval == FALSE), checks that the left operand (ST) is of scalar * type and determines whether evaluation of the right operand is * necessary. */ bool_t FASTCALL EvalLogical (bnode_t bn) { uint wStatus; if (!EvalLChild (bn)) { return (FALSE); } wStatus = Logical (NODE_OP (bn), FALSE); if (wStatus == DL_DEBERR) { return(FALSE); } else if (wStatus == DL_SUCCESS) { // Do not evaluate rhs return (TRUE); } //DASSERT (wStatus == DL_CONTINUE); if (!EvalRChild (bn)) { return (FALSE); } return (Logical (NODE_OP (bn), TRUE) == DL_SUCCESS); } /** Logical - Handle '&&' and '||' operators * wStatus = Logical (op, REval) * Entry op = Operand (OP_andand or OP_oror) * REval = FALSE if right hand not evaluated * ST = left hand value * REval = TRUE if right hand evaluated * STP = left hand value * ST = right hand value * Returns wStatus = evaluation status * (REval = TRUE) * DL_DEBERR Evaluation failed, DebErr is set * DL_SUCCESS Evaluation succeeded, result in ST * (REVAL == FALSE) * DL_DEBERR Evaluation failed, * DL_SUCCESS Evaluation succeeded, result in ST * DL_CONTINUE Evaluation inconclusive, must evaluate right node * DESCRIPTION * If (REval = TRUE), checks that both operands (STP and ST) are of scalar * type and evaluates the result (0 or 1). * If (REval == FALSE), checks that the left operand (ST) is of scalar * type and determines whether evaluation of the right operand is * necessary. */ uint Logical (op_t op, bool_t REval) { int result; bool_t fIsZeroL; bool_t fIsZeroR; // Evaluate the result. We push a constant node with value of // zero so we can compare against it (i.e., expr1 && expr2 is // equivalent to (expr1 != 0) && (expr2 != 0)). // Evaluate whether the left node is zero. if (REval == FALSE) { if (!PushStack (ST) || !InitConst (0)) { pExState->err_num = ERR_NOMEMORY; return (FALSE); } if (!Relational (OP_eqeq)) return (DL_DEBERR); //DASSERT (EVAL_TYP (ST) == T_SHORT); fIsZeroL = (EVAL_SHORT (ST) == 1); // remove left hand comparison PopStack (); result = (op == OP_oror); EVAL_STATE (ST) = EV_rvalue; if (pExState->state.f32bit) { EVAL_LONG (ST) = (long) result; SetNodeType (ST, T_INT4); } else { EVAL_SHORT (ST) = (short) result; SetNodeType (ST, T_INT2); } if ( ((op == OP_andand) && (!fIsZeroL)) || ((op == OP_oror) && (fIsZeroL)) ) { return(DL_CONTINUE); } else { return (DL_SUCCESS); } } else { if (!PushStack (ST) || !InitConst (0)) { pExState->err_num = ERR_NOMEMORY; return (FALSE); } if (!Relational (OP_eqeq)) return (DL_DEBERR); //DASSERT (EVAL_TYP(ST) == T_SHORT); fIsZeroR = (EVAL_SHORT (ST) == 1); PopStack (); fIsZeroL = (EVAL_SHORT (STP) == 1); // Finally, determine whether or not we have a result, and if so, // what the result is: if ( ((op == OP_andand) && ((!fIsZeroL) && (!fIsZeroR))) || ((op == OP_oror) && ((!fIsZeroL) || (!fIsZeroR))) ) result = 1; else result = 0; } EVAL_STATE (STP) = EV_rvalue; if (pExState->state.f32bit) { EVAL_LONG (STP) = (long) result; SetNodeType (STP, T_INT4); } else { EVAL_SHORT (STP) = (short) result; SetNodeType (STP, T_INT2); } PopStack (); return (DL_SUCCESS); } /*** EvalContext - evaluate the context operator * fSuccess = EvalContext (bn) * Exit ST = address node * pExState->err_num = error number if error * Returns TRUE if successful * FALSE if error * The stack top value (ST) is set to the address of the * stack top operand */ bool_t FASTCALL EvalContext (bnode_t bn) { PCXT oldCxt; bool_t error; bnode_t oldbnCxt; HFRAME hframeOld; // Set the new context for evaluation of the remainder of this // part of the tree oldCxt = pCxt; oldbnCxt = bnCxt; pCxt = SHpCXTFrompCXF ((PCXF)&bn->v[0]); hframeOld = pExState->hframe; pExState->hframe = SHhFrameFrompCXF ((PCXF)&bn->v[0]); #if 1 // JLS // Why would we ever have a valid "frame" at bind time, the frame // is a strange handle passed in at Eval time. The best one can do // is to either get a new Frame now, or use the normal frame if (pExState->hframe == NULL) { pExState->hframe = hframeOld; } #else // JLS if ((pExState->hframe.BP.seg == 0) && (pExState->hframe.BP.off == 0)) { // we did not have a valid frame at bind time pExState->hframe = hframeOld; } #endif // JLS error = EvalLChild (bn); if (error == TRUE) { // if there was not an error and if the result of the // expression is bp relative, then we must load the value // before returning to the original context if ((EVAL_STATE (ST) == EV_lvalue) && (EVAL_IS_BPREL (ST) || EVAL_IS_REGREL(ST) || EVAL_IS_TLSREL(ST)) && // if the new context is the same as the old context, we can // still treat bp relatives as l-values. It should be sufficient // to compare only hProc and hMod (since the explicit context // cannot contain a block !(SHHMODFrompCXT(pCxt) == SHHMODFrompCXT(oldCxt) && SHHPROCFrompCXT(pCxt) == SHHPROCFrompCXT(oldCxt)) ) { if (EVAL_IS_REF (ST)) { if (!EvalUtil (OP_fetch, ST, NULL, EU_LOAD)) { // unable to load value pExState->err_num = ERR_NOTEVALUATABLE; pExState->hframe = hframeOld; return (FALSE); } EVAL_IS_REF (ST) = FALSE; EVAL_STATE (ST) = EV_lvalue; EVAL_SYM_OFF (ST) = EVAL_PTR_OFF (ST); EVAL_SYM_SEG (ST) = EVAL_PTR_SEG (ST); SetNodeType (ST, PTR_UTYPE (ST)); } if (EVAL_IS_ENUM (ST)) { SetNodeType (ST, ENUM_UTYPE (ST)); } if (!EvalUtil (OP_fetch, ST, NULL, EU_LOAD)) { // unable to load value pExState->err_num = ERR_NOTEVALUATABLE; pExState->hframe = hframeOld; return (FALSE); } #if defined(TARGMAC68K) EVAL_STATE (ST) = EV_lvalue; #endif } } pExState->hframe = hframeOld; if ((bnCxt = oldbnCxt) != 0) { // the old context was pointing into the expression tree. // since the expression tree could have been reallocated, // we must recompute the context pointer pCxt = SHpCXTFrompCXF ((PCXF)&((pnode_t)bnCxt)->v[0]); } else { // the context pointer is pointing into the expression state structure pCxt = oldCxt; } return (error); } /*** EvalAddrOf - Perform the address-of ('&') operation * fSuccess = EvalAddrOf (bn) * Entry * Exit ST = address node * pExState->err_num = error number if error * Returns TRUE if successful * FALSE if error * The stack top value (ST) is set to the address of the * stack top operand */ bool_t FASTCALL EvalAddrOf (bnode_t bn) { CV_typ_t type; if (!EvalLChild (bn)) { return (FALSE); } if (EVAL_STATE (ST) != EV_lvalue) { pExState->err_num = ERR_NOTEVALUATABLE; return (FALSE); } // The operand must be an lvalue and cannot be a register variable DASSERT (!(EVAL_IS_REG (ST))); DASSERT (NODE_STYPE (bn) != 0); if (EVAL_IS_REF(ST)) { // just clear the ref flag in order to convert // ST to a pointer to the object EVAL_IS_REF(ST) = FALSE; return TRUE; } if ((type = NODE_STYPE (bn)) == 0) { // unable to find proper pointer type return (FALSE); } else { EVAL_STATE (ST) = EV_rvalue; if (EVAL_IS_BPREL (ST)) { ResolveAddr(ST); } if (EVAL_IS_REGREL(ST)) { ResolveAddr(ST); } EVAL_PTR (ST) = EVAL_SYM (ST); if (ADDR_IS_LI (EVAL_PTR (ST))) { SHFixupAddr (&EVAL_PTR (ST)); } return (SetNodeType (ST, type)); } } /*** EvalFetch - Perform the fetch ('*') operation * fSuccess = EvalFetch (bn) * Entry ST = pointer to address value * Exit ST = dereferenced value * pExState->err_num = error number if error * Returns TRUE if successful * FALSE if error * The resultant node is set to the contents of the location * pointed to by the operand node. */ bool_t FASTCALL EvalFetch (bnode_t bn) { if (EvalLChild (bn)) { return (FetchOp (ST)); } return (FALSE); } /*** EvalThisInit - initialize this calculation * fSuccess = EvalThisInit (bn) * Entry bn = based pointer to node * Exit TempThis = stack top * Returns TRUE if successful * FALSE if error */ bool_t FASTCALL EvalThisInit (bnode_t bn) { Unreferenced(bn); *pvThis = *ST; if (EVAL_IS_CLASS (pvThis)) { #if 1 ResolveAddr(pvThis); #else if (EVAL_IS_BPREL (pvThis)) { EVAL_SYM_OFF (pvThis) += pExState->frame.BP.off; EVAL_SYM_SEG (pvThis) = pExState->frame.SS; //M00FLAT32 EVAL_IS_BPREL (pvThis) = FALSE; ADDR_IS_LI (EVAL_SYM (pvThis)) = FALSE; } #endif return (TRUE); } else if (EVAL_IS_PTR (pvThis)) { if (EVAL_STATE (pvThis) == EV_lvalue) { FetchOp (pvThis); } else { EVAL_SYM (pvThis) = EVAL_PTR (pvThis); EVAL_STATE (pvThis) = EV_lvalue; // Remove a level of indirection from the resultant type. RemoveIndir (pvThis); EVAL_IS_REF (pvThis) = FALSE; return (TRUE); } } // we should not initialize the this address unless the stack top // is a class or a pointer to class pExState->err_num = ERR_INTERNAL; return (FALSE); } /*** EvalThisConst - Adjust this temp by constant * fSuccess = EvalThisConst (bn) * Entry bn = based pointer to node containing constant * Exit EVAL_SYM_OFF (TempThis) adjusted by constant * Returns TRUE if successful * FALSE if error */ bool_t FASTCALL EvalThisConst (bnode_t bn) { if (EvalLChild (bn) == TRUE) { EVAL_SYM_OFF (pvThis) += ((padjust_t)(&bn->v[0]))->disp; return (SetNodeType (pvThis, ((padjust_t)(&bn->v[0]))->btype)); } return (FALSE); } /*** EvalThisExpr - Adjust this temp by expression * fSuccess = EvalThisExpr (bn) * Entry bn = based pointer to node containing expression * Exit EVAL_SYM_OFF (TempThis) adjusted by expression * newaddr = oldaddr + *(*(oldaddr + vbptroff) + vbindex) * Returns TRUE if successful * FALSE if error * The evaluation of this node will result in * pvThis = (pvThis + vbpoff) + *(*(pvThis +vbpoff) + vbdisp) * where * pvThis = address of base class * ap = current address point */ bool_t FASTCALL EvalThisExpr (bnode_t bn) { padjust_t pa = (padjust_t)(&bn->v[0]); // we set the node types of the pointer to char * to prevent the // EVPlusMinus () code from attempting an array indexing operation if (EvalLChild (bn) == TRUE) { return (CalcThisExpr (pa->vbptr, pa->vbpoff, pa->disp, pa->btype)); } return (FALSE); } /*** CalcThisExpr - Adjust this temp by expression * fSuccess = CalcThisExpr (vbptr, vbpoff, disp, btype) * Entry vbptr = type index of virtual base pointer * vbpoff = offset of vbptr from this pointer * disp = index of virtual base displacement from *vbptr * btype = type index of base class * Exit EVAL_SYM_OFF (TempThis) adjusted by expression * newaddr = oldaddr + *(*(oldaddr + vbptroff) + vbindex) * Returns TRUE if successful * FALSE if error * The evaluation of this node will result in * pvThis = (pvThis + vbpoff) + *(*(pvThis + vbpoff) + vbdisp) * where * pvThis = address of base class */ bool_t FASTCALL CalcThisExpr (CV_typ_t vbptr, UOFFSET vbpoff, UOFFSET disp, CV_typ_t btype) { // we set the node types of the pointer to char * or a 32 flat // char * to prevent the // EVPlusMinus () code from attempting an array indexing operation if (PushStack (pvThis) == TRUE) { EVAL_PTR (ST) = EVAL_SYM (ST); EVAL_STATE (ST) = EV_rvalue; if ((SetNodeType (ST, (CV_typ_t) (pExState->state.f32bit ? T_32PCHAR : T_PFCHAR)) == TRUE) && // BUGBUG must support 64 bit constants (InitConst ((UOFF32)vbpoff) == TRUE) && (EVPlusMinus (OP_plus) == TRUE) && (PushStack (ST) == TRUE) && (DerefVBPtr (vbptr)) && // BUGBUG must support 64 bit constants (InitConst ((UOFF32)disp) == TRUE) && (EVPlusMinus (OP_plus) == TRUE) && (EVAL_IS_ARRAY (ST) = FALSE, EVAL_STATE (ST) = EV_lvalue, EVAL_SYM (ST) = EVAL_PTR (ST), FetchOp (ST) == TRUE) && (EVAL_STATE (ST) = EV_rvalue, EVAL_PTR (ST) = EVAL_SYM (ST), EVPlusMinus (OP_plus) == TRUE) ) { SetNodeType (ST, btype); EVAL_STATE (ST) = EV_lvalue; EVAL_SYM (ST) = EVAL_PTR (ST); *pvThis = *ST; return (PopStack ()); } } return (FALSE); } /** DerefVBPtr - dereference virtual base pointer * flag = DerefVBPtr (type) * Entry type = type index of virtual base pointer * ST = address of virtual base pointer as T_PFCHAR or T_32PCHAR * Exit ST = virtual base pointer * Returns TRUE if no error * FALSE if error */ bool_t DerefVBPtr (CV_typ_t type) { // The operand cannot be a register variable DASSERT (!(EVAL_IS_REG (ST))); DASSERT (type != 0); DASSERT (EVAL_IS_BPREL (ST) == FALSE); if (type != 0) { if (SetNodeType (ST, type) == TRUE) { EVAL_STATE (ST) = EV_lvalue; EVAL_SYM (ST) = EVAL_PTR (ST); if (!EvalUtil (OP_fetch, ST, NULL, EU_LOAD | EU_TYPE)) { return (FALSE); } // The resultant node is basically identical to the child except // that its EVAL_SYM field is equal to the actual contents of // the pointer: if (EVAL_IS_BASED (ST)) { if (!NormalizeBase (ST)) { return(FALSE); } } // Remove a level of indirection from the resultant type. RemoveIndir (ST); EVAL_IS_REF (ST) = FALSE; return (TRUE); } } return (FALSE); } /*** EvalAssign - Perform an assignment operation * fSuccess = EvalAssign (bn) * Entry bn = based pointer to assignment node * Exit * pExState->err_num = error number if error * Returns TRUE if successful * FALSE if error */ bool_t FASTCALL EvalAssign (bnode_t bn) { if (!EvalLChild (bn) || !EvalRChild (bn)) { return (FALSE); } return (Assign (NODE_OP (bn))); } /*** Assign - Perform an assignment operation * fSuccess = Assign (op) * Entry op = assignment operator * Exit * pExState->err_num = error number if error * Returns TRUE if successful * FALSE if error */ bool_t FASTCALL Assign (op_t op) { extern CV_typ_t eqop[]; op_t nop; // Left operand must have evaluated to an lvalue if (EVAL_STATE (STP) != EV_lvalue) { pExState->err_num = ERR_NEEDLVALUE; return (FALSE); } if (EVAL_IS_REF (ST)) { if (FetchOp (ST) == FALSE) { return (FALSE); } } if (EVAL_IS_REF (STP)) { if (FetchOp (STP) == FALSE) { return (FALSE); } } if (EVAL_IS_ENUM (ST)) { SetNodeType (ST, ENUM_UTYPE (ST)); } if (EVAL_IS_ENUM (STP)) { SetNodeType (STP, ENUM_UTYPE (STP)); } if (op == OP_eq) { // for simple assignment, load both nodes if (!EvalUtil (OP_eq, ST, NULL, EU_LOAD)) { return (FALSE); } if (EVAL_IS_BASED (ST) && !((EVAL_TYP (STP) == T_SHORT) || (EVAL_TYP (STP) == T_USHORT) || (EVAL_TYP (STP) == T_INT2) || (EVAL_TYP (STP) == T_UINT2))) { // if the value to be stored is a based pointer and the type // of the destination is not an int, then normalize the pointer. // A based pointer can be stored into an int without normalization. if (!NormalizeBase (ST)) { return (FALSE); } } if (EVAL_IS_BASED (STP)) { // if the location to be stored into is a based pointer and the // value to be stored is a pointer or is a long value not equal // to zero, then the value is denormalized if (EVAL_IS_PTR (ST) || (((EVAL_TYP (ST) == T_LONG) || (EVAL_TYP(ST) == T_ULONG)) && (EVAL_ULONG (ST) != 0L)) || (((EVAL_TYP (ST) == T_INT4) || (EVAL_TYP(ST) == T_UINT4)) && (EVAL_ULONG (ST) != 0L))) { //M00KLUDGE - this should go through CastNode if (!DeNormalizePtr (ST, STP)) { return (FALSE); } } } } else { // map assignment operator to arithmetic operator // push address onto top of stack and load the value and // perform operation if (!PushStack (STP) || !PushStack (STP)) { pExState->err_num = ERR_NOMEMORY; return (FALSE); } switch (nop = (op_t) eqop[op - OP_multeq]) { case OP_plus: case OP_minus: EVPlusMinus (nop); break; default: EVArith (nop); } // The top of the stack now contains the value of the memory location // modified by the value. Move the value to the right operand of the // assignment operand. // M00KLUDGE - this will not work with variable sized stack entries *STP = *ST; PopStack (); } // store result if (EVAL_IS_BITF (STP)) { // store bitfield return (SBitField ()); } #ifdef NEVER // this may cause problems in assignment operators. else if (EVAL_IS_ADDR (STP)) { // the left value is an address. If the right value is not an address // convert it to a long before moving to the left value. // M00KLUDGE - this assumes equivalence between far pointers and longs if (!EVAL_IS_ADDR (ST)) { CastNode (ST, T_LONG, T_LONG); } EVAL_VAL (STP) = EVAL_VAL (ST); } #endif else if (EVAL_IS_PTR (STP)) { // dolphin #2109: use a non-NULL hmod before casting // EVAL_MOD(ST) is 0 if ST represents a register if (EVAL_MOD(ST) == 0) { EVAL_MOD(ST) = EVAL_MOD(STP); } CastNode (ST, EVAL_TYP (STP), PTR_UTYPE (STP)); if (ADDR_IS_LI (EVAL_PTR (ST)) == TRUE) { SHFixupAddr (&EVAL_PTR (ST)); } EVAL_VAL (STP) = EVAL_VAL (ST); } else { if (EVAL_MOD(ST) == 0) { EVAL_MOD(ST) = EVAL_MOD(STP); } CastNode (ST, EVAL_TYP (STP), EVAL_TYP (STP)); EVAL_VAL (STP) = EVAL_VAL (ST); } PopStack (); EVAL_STATE (ST) = EV_rvalue; return (UpdateMem (ST)); } /** FetchOp - fetch pointer value * fSuccess = FetchOp (pv) * Entry ST = pointer node * Exit EVAL_SYM (ST) = pointer value * Returns TRUE if pointer value fetched without error * FALSE if error */ bool_t FASTCALL FetchOp (peval_t pv) { // load the value and perform implicit type conversions. if (!EvalUtil (OP_fetch, pv, NULL, EU_LOAD | EU_TYPE)) { return (FALSE); } // The resultant node is basically identical to the child except // that its EVAL_SYM field is equal to the actual contents of // the pointer: if (EVAL_IS_BASED (pv)) { if (!NormalizeBase (pv)) { return(FALSE); } } EVAL_SYM (pv) = EVAL_PTR (pv); EVAL_SYM_OFF (ST) -= PTR_THISADJUST (ST); PTR_THISADJUST (ST) = 0; EVAL_STATE (pv) = EV_lvalue; // Remove a level of indirection from the resultant type. RemoveIndir (pv); EVAL_IS_REF (pv) = FALSE; return (TRUE); } /** InitConst - initialize constand on evaluation stack * fSuccess = InitConst (const) * Entry const = constant value * Exit value field of ST = constant eval node * Returns TRUE if node added without error * FALSE if error */ bool_t FASTCALL InitConst (long off) { eval_t evalT; peval_t pvT; pvT = &evalT; CLEAR_EVAL (pvT); EVAL_STATE (pvT) = EV_constant; SetNodeType (pvT, T_LONG); EVAL_LONG (pvT) = off; return (PushStack (pvT)); } /** SBitField - store value into bitfield * fSuccess = SBitField () * Entry STP = result bitfield * ST = value * Exit value field of STP = new field value * Returns TRUE if field inserted without error * FALSE if error */ bool_t FASTCALL SBitField () { ulong cBits; // Number of bits in field ulong pos; // Bit position of field ulong mask; // Bit mask UQUAD mask_q; // 64 bit version ulong mask_l; // 32 bit version uchar mask_c; // 8 bit version CV_typ_t uType; bool_t retval; // get information on the bit field. Shift counts are limited to 5 bits // to emulate the hardware pos = BITF_POS (STP) & 0x1f; cBits = BITF_LEN (STP); uType = BITF_UTYPE (STP); if (!CV_IS_PRIMITIVE(uType)) { // find out the true type, we can have LF_ENUM as underlying types. HTYPE htype = THGetTypeFromIndex(EVAL_MOD(STP), uType); if (htype != 0) { // check to see if it is an LF_ENUM. If so, we set uType // to be the underlying type of the enum instead. TYPPTR ptype = (TYPPTR) MHOmfLock(htype); if (ptype && ptype->leaf == LF_ENUM) { lfEnum * plf = (lfEnum*) &ptype->leaf; uType = plf->utype; } MHOmfUnLock(htype); } } // check if the underlying type is sufficiently large // and use a larger type if necessary DASSERT (CV_IS_PRIMITIVE(uType)); if ((long) (cBits + pos) > (TypeSizePrim(uType) << 3)) { switch (uType) { case T_CHAR: case T_RCHAR: case T_INT1: uType = T_INT2; break; case T_UCHAR: case T_UINT1: uType = T_UINT2; break; case T_SHORT: case T_INT2: uType = T_INT4; break; case T_USHORT: case T_UINT2: uType = T_UINT4; break; case T_LONG: uType = T_QUAD; break; case T_ULONG: uType = T_UQUAD; break; case T_INT4: uType = T_INT8; break; case T_UINT4: uType = T_UINT8; break; default: DASSERT (FALSE); pExState->err_num = ERR_BADOMF; return (FALSE); } } PushStack (STP); SetNodeType (ST, uType); EVAL_STATE (ST) = EV_lvalue; if (!LoadSymVal (ST)) { return (FALSE); } CastNode (STP, uType, uType); switch (uType) { case T_CHAR: case T_RCHAR: case T_UCHAR: case T_INT1: case T_UINT1: mask_c = (uchar) ((1 << cBits) - 1); EVAL_UCHAR (STP) = (uchar) (EVAL_UCHAR (STP) & mask_c); EVAL_UCHAR (ST) = (uchar) ((EVAL_UCHAR (ST) & ~(mask_c << pos)) | (EVAL_UCHAR (STP) << pos)); break; case T_SHORT: case T_USHORT: case T_INT2: case T_UINT2: mask = ((1 << cBits) - 1); EVAL_USHORT (STP) = (ushort) (EVAL_USHORT (STP) & mask); EVAL_USHORT (ST) = (ushort) ((EVAL_USHORT (ST) & ~(mask << pos)) | (EVAL_USHORT (STP) << pos)); break; case T_LONG: case T_ULONG: case T_INT4: case T_UINT4: mask_l = ((1L << cBits) - 1); EVAL_ULONG (STP) = (ulong) (EVAL_ULONG (STP) & mask_l); EVAL_ULONG (ST) = (EVAL_ULONG (ST) & ~(mask_l << pos)) | (EVAL_ULONG (STP) << pos); break; case T_QUAD: case T_UQUAD: case T_INT8: case T_UINT8: mask_q = (((UQUAD)1 << cBits) - 1); EVAL_UQUAD (STP) = (UQUAD) (EVAL_UQUAD (STP) & mask_q); EVAL_UQUAD (ST) = (EVAL_UQUAD (ST) & ~(mask_q << pos)) | (EVAL_UQUAD (STP) << pos); break; default: DASSERT (FALSE); return (FALSE); } retval = UpdateMem (ST); PopStack (); // signed extend if signed type switch (uType) { case T_CHAR: case T_RCHAR: case T_INT1: EVAL_CHAR (ST) <<= (8 - cBits); EVAL_CHAR (ST) >>= (8 - cBits); break; case T_SHORT: case T_INT2: EVAL_SHORT (ST) <<= (16 - cBits); EVAL_SHORT (ST) >>= (16 - cBits); break; case T_LONG: case T_INT4: EVAL_LONG (ST) <<= (32 - cBits); EVAL_LONG (ST) >>= (32 - cBits); break; case T_QUAD: case T_INT8: EVAL_QUAD (ST) <<= (64 - cBits); EVAL_QUAD (ST) >>= (64 - cBits); break; } *STP = *ST; PopStack (); return (retval); } /*** EVPlusMinus - Perform an addition or subtraction operation * fSuccess = EVPlusMinus (op) * Entry op = OP_plus or OP_minus * Exit STP = STP op ST and stack popped * pExState->err_num = error number if error * Returns TRUE if successful * FALSE if error * DESCRIPTION * Special handling is required when one or both operands are * pointers. Otherwise, the arguments are passed on to EVArith(). */ bool_t FASTCALL EVPlusMinus (op_t op) { ulong cbBase; eval_t evalT; peval_t pvT; if (EVAL_IS_REF (ST)) { if (FetchOp (ST) == FALSE) { return (FALSE); } } if (EVAL_IS_REF (STP)) { if (FetchOp (STP) == FALSE) { return (FALSE); } } if (EVAL_IS_ENUM (ST)) { SetNodeType (ST, ENUM_UTYPE (ST)); } if (EVAL_IS_ENUM (STP)) { SetNodeType (STP, ENUM_UTYPE (STP)); } // Check to see if either operand is a pointer. // If so, the operation is special. Otherwise, // hand it to EVArith (). if (!EVAL_IS_PTR (STP) && !EVAL_IS_PTR (ST)) { return (EVArith (op)); } // Load values and perform implicit type coercion if required. if (!EvalUtil (op, STP, ST, EU_LOAD)) { return (FALSE); } // Perform the evaluation. There are two cases: // I) ptr + int, int + ptr, ptr - int // II) ptr - ptr // Do some common setup first. pvT = &evalT; if ((op == OP_plus) || !(EVAL_IS_PTR (ST))) { // Case (I). ptr + int, int + ptr, ptr - int if (!EVAL_IS_PTR (STP)) { // Switch so int is on right *pvT = *STP; *STP = *ST; *ST = *pvT; } // if pointer node is BP relative, compute actual address *pvT = *STP; RemoveIndir (pvT); cbBase = TypeSize (pvT); #if 0 if (EVAL_IS_BPREL (STP)) { EVAL_SYM_OFF (STP) += pExState->frame.BP.off; EVAL_SYM_SEG (STP) = pExState->frame.SS; //M00FLAT32 EVAL_IS_BPREL (STP) = FALSE; ADDR_IS_LI (EVAL_SYM (ST)) = FALSE; SHUnFixupAddr (&EVAL_SYM (ST)); } #else ResolveAddr(STP); #endif // The resultant node has the same type as the pointer: EVAL_STATE (STP) = EV_rvalue; // Cast the increment node to an unsigned long. CastNode (ST, T_ULONG, T_ULONG); // Assign the proper value to the resultant node. if (op == OP_plus) { EVAL_PTR_OFF (STP) += (UOFFSET)(EVAL_ULONG (ST) * cbBase); } else { EVAL_PTR_OFF (STP) -= (UOFFSET)(EVAL_ULONG (ST) * cbBase); } } else { // Case (II): ptr - ptr. The result is of type ptrdiff_t and // is equal to the distance between the two pointers (in the // address space) divided by the size of the items pointed to: *pvT = *STP; RemoveIndir (pvT); cbBase = TypeSize (pvT); DASSERT (EVAL_IS_PTR (ST)); if (!EVAL_IS_PTR (STP) || !fCanSubtractPtrs (ST, STP) || // Dolphin #5530: fail gracefully if cbBase is 0. In that // case the underlying type is special (e.g., void) and // pointer subtraction is not allowed. cbBase == 0) { pExState->err_num = ERR_OPERANDTYPES; return (FALSE); } EVAL_STATE (STP) = EV_rvalue; // we know we are working with pointers so we do not // have to check EVAL_IS_PTR (pv) if (EVAL_IS_BASED (STP)) { NormalizeBase (STP); } if (EVAL_IS_BASED (ST)) { NormalizeBase (ST); } if (EVAL_IS_NPTR (STP) || EVAL_IS_FPTR (STP)) { SetNodeType (STP, T_SHORT); EVAL_SHORT (STP) = (short) (EVAL_PTR_OFF (STP) - EVAL_PTR_OFF (ST)); EVAL_SHORT (STP) /= (ushort) cbBase; } else if (EVAL_IS_NPTR32 (STP) || EVAL_IS_FPTR32 (STP)) { SetNodeType (STP, T_ULONG); EVAL_ULONG (STP) = (UOFF32) (EVAL_PTR_OFF (STP) - EVAL_PTR_OFF (ST)); EVAL_ULONG (STP) /= cbBase; } else if (EVAL_IS_PTR64 (STP)) { //v-vadimp - needs review SetNodeType (STP, T_UQUAD); EVAL_UQUAD(STP) = (UOFF64) (EVAL_PTR_OFF (STP) - EVAL_PTR_OFF (ST)); EVAL_UQUAD (STP) /= cbBase; } else { SetNodeType (STP, T_LONG); // M00KLUDGE This will not work in 32 bit mode // BUGBUG this does not do 64 bit pointers correctly EVAL_LONG (STP) = (UOFF32) (((((ushort)EVAL_PTR_SEG (STP)) << 16) + EVAL_PTR_OFF (STP)) - ((((ushort)EVAL_PTR_SEG (ST)) << 16) + EVAL_PTR_OFF (ST))); EVAL_LONG (STP) /= cbBase; } } return(PopStack ()); } /** EvalRelat - Perform relational and equality operations * fSuccess = EvalRelat (bn) * Entry bn = based pointer to node * Returns TRUE if no evaluation error * FALSE if evaluation error * Description * If both operands are arithmetic, passes them on to EVArith(). * Otherwise (one or both operands pointers), does the evaluation * here. */ bool_t FASTCALL EvalRelat (bnode_t bn) { if (!EvalLChild (bn) || !EvalRChild (bn)) { return (FALSE); } return (Relational (NODE_OP (bn))); } /** Relational - Perform relational and equality operations * fSuccess = Relational (op) * Entry op = OP_lt, OP_lteq, OP_gt, OP_gteq, OP_eqeq, or OP_bangeq * Returns TRUE if no evaluation error * FALSE if evaluation error * Description * If both operands are arithmetic, passes them on to EVArith(). * Otherwise (one or both operands pointers), does the evaluation * here. */ bool_t FASTCALL Relational (op_t op) { int result; ushort segL; ushort segR; UOFFSET offL; UOFFSET offR; if (EVAL_IS_REF (ST)) { if (FetchOp (ST) == FALSE) { return (FALSE); } } if (EVAL_IS_REF (STP)) { if (FetchOp (STP) == FALSE) { return (FALSE); } } if (EVAL_IS_ENUM (ST)) { SetNodeType (ST, ENUM_UTYPE (ST)); } if (EVAL_IS_ENUM (STP)) { SetNodeType (STP, ENUM_UTYPE (STP)); } // Check to see if either operand is a pointer. // If so, the operation is special. Otherwise, // hand it to EVArith (). if (!EVAL_IS_PTR (STP) || !EVAL_IS_PTR (ST)) { return (EVArith (op)); } if (EvalUtil (op, ST, STP, EU_LOAD | EU_TYPE) == FALSE) { return (FALSE); } // Both nodes should now be typed as either near or far // pointers. DASSERT (EVAL_IS_PTR (STP) && EVAL_IS_PTR (ST)); // For the relational operators ('<', '<=', '>', '>='), // only offsets are compared. For the equality operators ('==', '!='), // both segments and offsets are compared. if (ADDR_IS_LI (EVAL_PTR (STP))) { SHFixupAddr (&EVAL_PTR (STP)); } if (ADDR_IS_LI (EVAL_PTR (ST))) { SHFixupAddr (&EVAL_PTR (ST)); } segL = (ushort)EVAL_PTR_SEG (STP); segR = (ushort)EVAL_PTR_SEG (ST); offL = EVAL_PTR_OFF (STP); offR = EVAL_PTR_OFF (ST); switch (op) { case OP_lt: result = (offL < offR); break; case OP_lteq: result = (offL <= offR); break; case OP_gt: result = (offL > offR); break; case OP_gteq: result = (offL >= offR); break; case OP_eqeq: if (0 == offL && 0 == offR && EVAL_PTRTYPE(ST) == CV_PTR_NEAR && EVAL_PTRTYPE(STP) == CV_PTR_NEAR) { result = 1; } else { result = ((segL == segR) && (offL == offR)); } break; case OP_bangeq: if (0 == offL && 0 == offR && EVAL_PTRTYPE(ST) == CV_PTR_NEAR && EVAL_PTRTYPE(STP) == CV_PTR_NEAR) { result = 0; } else { result = ((segL != segR) || (offL != offR)); } break; default: //DASSERT (FALSE); pExState->err_num = ERR_INTERNAL; return (FALSE); } EVAL_STATE (STP) = EV_rvalue; if (pExState->state.f32bit) { EVAL_LONG (STP) = (long) result; SetNodeType (STP, T_INT4); } else { EVAL_SHORT (STP) = (short) result; SetNodeType (STP, T_INT2); } return (PopStack ()); } /** EvalRetVal - Evaluate Return Value of current function * fSuccess = EvalRetVal (bn) * Entry bn = based pointer to node * Returns TRUE if no evaluation error * FALSE if evaluation error * Description * Evaluates return value of current function */ bool_t FASTCALL EvalRetVal (bnode_t bn) { peval_t pv = &bn->v[0]; if (!PushStack (pv)) return FALSE; if (EVAL_IS_CLASS (ST)) { SHREG reg = {0}; // this case needs special handling, since // eax contains a pointer to the return value switch (TargetMachine) { case mptmips: reg.hReg = CV_M4_IntV0; break; case mptdaxp: reg.hReg = CV_ALPHA_IntV0; break; case mptm68k: DASSERT(FALSE); break; case mptix86: reg.hReg = CV_REG_EAX; break; case mptia64: reg.hReg = CV_IA64_IntV0; break; case mptmppc: case mptntppc: reg.hReg = CV_PPC_GPR3; break; default: DASSERT(FALSE); } if (GetReg (®, pCxt, NULL) == NULL) { pExState->err_num = ERR_REGNOTAVAIL; return (FALSE); } EVAL_SYM_OFF (ST) = reg.Byte4; ADDRLIN32( EVAL_SYM(ST) ); } #if defined (TARGMAC68K) else if (FCN_CALL (ST) == FCN_PASCAL) { SHREG reg = {0}; reg.hReg = CV_R68_A7; if (GetReg (®, pCxt, NULL) == NULL) { pExState->err_num = ERR_REGNOTAVAIL; return (FALSE); } EVAL_SYM_OFF (ST) = reg.Byte4; ADDRLIN32( EVAL_SYM(ST) ); } #endif return TRUE; } /*** EvalUScope - Do unary :: scoping * fSuccess = EvalUScope (bn); * Entry pvRes = based pointer to unary scoping node * Exit pvRes = evaluated left node of pvRes * Returns TRUE if evaluation successful * FALSE if error */ bool_t FASTCALL EvalUScope (bnode_t bn) { register bool_t retval; CXT cxt; // save current context packet and set current context to module scope cxt = *pCxt; SHGetCxtFromHmod (SHHMODFrompCXT (pCxt), pCxt); retval = EvalLChild (bn); *pCxt = cxt; return (retval); } /*** DoBScope - Do binary :: scoping * fSuccess = DoBScope (pn); * Entry pvRes = pointer to binary scoping node * Returns TRUE if evaluation successful * FALSE if error */ bool_t FASTCALL EvalBScope (bnode_t bn) { peval_t pv; pv = &NODE_LCHILD (bn)->v[0]; if (CLASS_NAMESPACE (pv)) { return EvalPushNode (bn); } if (CLASS_GLOBALTYPE (pv)) { // the left member of the scope operator was a type not in class // scope. We presumably have an empty stack so we need to fake // up a stack entry //if (ST == NULL) // Dolphin 5503: We GP-faulted while binding an expression like // Foo::m_array[Foo::m_staticCount], because we needed to fake // up a stack entry even if ST was not NULL. // Now we always push a faked entry unless there is a preceding // bnOp (".", "->", etc); in that case a class stack entry has // already been pushed onto the stack. if (! CLASS_FOLLOWSBNOP (pv)) PushStack (pv); } return (StructEval (bn)); } /*** EvalPreIncDec - Do ++expr or --expr * fSuccess = EvalPreIncDec (bnode_t bn); * Entry bn = based pointer to node * Exit ST decremented or incremented * pExState->err_num = error number if error * Returns TRUE if successful * FALSE if error */ bool_t FASTCALL EvalPreIncDec (bnode_t bn) { op_t nop = OP_plus; if (!EvalLChild (bn)) { return(FALSE); } if (NODE_OP (bn) == OP_predec) { nop = OP_minus; } // push the entry on the stack and then perform incmrement/decrement PushStack (ST); // load left node and store as return value if (EvalUtil (nop, ST, NULL, EU_LOAD)) { // do the post-increment or post-decrement operation and store if (EVPrePost (nop)) { if (Assign (OP_eq)) { return (TRUE); } } } return (FALSE); } /*** EvalPostIncDec - Do expr++ or expr-- * fSuccess = EvalPostIncDec (op); * Entry bn = based pointer to node * Exit ST decremented or incremented * pExState->err_num = error number if error * Returns TRUE if successful * FALSE if error */ bool_t FASTCALL EvalPostIncDec (bnode_t bn) { eval_t evalT; peval_t pvT = &evalT; op_t nop = OP_plus; if (!EvalLChild (bn)) { return(FALSE); } if (NODE_OP (bn) == OP_postdec) { nop = OP_minus; } // push the entry on the stack and then perform incmrement/decrement PushStack (ST); // load left node and store as return value if (EvalUtil (nop, ST, NULL, EU_LOAD)) { *pvT = *ST; // do the post-increment or post-decrement operation and store if (EVPrePost (nop)) { if (Assign (OP_eq)) { *ST = *pvT; return (TRUE); } } } return (FALSE); } /** EVPrePost - perform the increment operation * fSuccess = EVPrePost (op); * Entry op = operation to perform (OP_plus or OP_minus) * Exit increment/decrement performed and result stored in memory * DebErr set if error * Returns TRUE if no error * FALSE if error */ INLINE bool_t EVPrePost (op_t op) { if (InitConst (1) == TRUE) { return (EVPlusMinus (op)); } return (FALSE); } /*** EvalBang - Perform logical negation operation * fSuccess = EvalBang (bn) * Entry bn = based pointer to node * Exit ST = pointer to negated value * pExState->err_num = error number if error * Returns TRUE if successful * FALSE if error * DESCRIPTION * Checks for a pointer operand; if found, handles it here, otherwise * passes it on to EVUnary (). */ bool_t FASTCALL EvalBang (bnode_t bn) { int result; ushort seg; UOFFSET off; if (!EvalLChild (bn)) { return (FALSE); } // load the value and perform implicit type conversion. if (!EvalUtil (OP_bang, ST, NULL, EU_LOAD)) { return (FALSE); } if (EVAL_IS_REF (ST)) { if (FetchOp (ST) == FALSE) { return (FALSE); } } // If the operand is not of pointer type, just pass it on to EVUnary if (!(EVAL_IS_PTR (ST))) return (EVUnary (OP_bang)); // The result is 1 if the pointer is a null pointer and 0 otherwise // Note that for a near pointer, we compare the offset against // 0, while for a far pointer we compare both segment and offset. seg = (ushort)EVAL_PTR_SEG (ST); off = EVAL_PTR_OFF (ST); if (EVAL_IS_NPTR (ST) || EVAL_IS_NPTR32 (ST)) { result = (off == 0); } else { result = ((seg == 0) && (off == 0)); } CLEAR_EVAL (ST); EVAL_STATE (ST) = EV_rvalue; if (pExState->state.f32bit) { EVAL_LONG (ST) = (long) result; return (SetNodeType (ST, T_INT4)); } else { EVAL_SHORT (ST) = (short) result; return (SetNodeType (ST, T_INT2)); } } /*** EvalDMember - Perform a dot member access ('.*') * fSuccess = EvalDMember (bn) * Entry bn = based pointer to node * Exit ST = value of member * pExState->err_num = error number if error * Returns TRUE if successful * FALSE if error */ bool_t FASTCALL EvalDMember (bnode_t bn) { Unreferenced(bn); pExState->err_num = ERR_OPNOTSUPP; return (FALSE); //M00KLUDGE - not implemented #ifdef NEVER // Resolve identifiers, if any, but do NOT resolve the right-child // identifier. For example, 'foo' could be both a local (or global) // variable and the name of a structure element. if (!ResolveIdent (ST)) return (FALSE); if (NODE_OP (pnRight) != OP_ident) { pExState->err_num = ERR_SYNTAX; return (FALSE); } // Attempt to find the structure or class element. if (EVAL_IS_STRUCT (ST)) { if (!SetStructRef (pnRight)) { pExState->err_num = ERR_NOTELEMENT; return (FALSE); } } else if (EVAL_IS_CLASS (ST)) { if (!SetClassRef (pnRight)) { pExState->err_num = ERR_NOTELEMENT; return (FALSE); } } else { pExState->err_num = ERR_NEEDSTRUCT; return (FALSE); } return (TRUE); #endif } /*** EvalPMember - Perform a pointer to member access ('->*') * SYNOPSIS * fSuccess = EvalPMember (bn) * ENTRY * pvRes Pointer to node in which result is to be stored * pvLeft Pointer to left operand node * pvRight Pointer to right operand node * RETURNS * TRUE if successful, FALSE if not and sets DebErr * DESCRIPTION * NOTES */ bool_t FASTCALL EvalPMember (bnode_t bn) { Unreferenced(bn); // Check to make sure the left operand is a struct/union pointer. // To do this, remove a level of indirection from the node's type // and see if it's a struct or union. pExState->err_num = ERR_OPNOTSUPP; return (FALSE); } /*** EvalPointsTo - Perform a structure access ('->') * fSuccess = EvalPointsTo (bn) * Entry bRight = based pointer to node * Exit ST = value node for member * Returns TRUE if successful * FALSE if error */ bool_t FASTCALL EvalPointsTo (bnode_t bn) { if (!EvalLChild (bn)) { return (FALSE); } if (!FetchOp (ST)) { return (FALSE); } // The result is simple -- (*ST).pnRight. The call to StructEval () // will set the error code if it fails. if (EVAL_STATE (ST) == EV_rvalue) { return (StructElem (bn)); } else { return (StructEval (bn)); } } /*** EvalArray - Perform an array access ('[]') * fSuccess = EvalArray (bn) * Entry bn = based pointer to array node * Returns TRUE if successful * FALSE if error * Obtains the contents of an array member. This is done by * calling EVPlusMinus() and DoFetch(). */ bool_t FASTCALL EvalArray (bnode_t bn) { ulong index; eval_t evalT; peval_t pvT; if (EvalLChild (bn) && EvalRChild (bn)) { if (EVAL_IS_ARRAY (STP) || EVAL_IS_ARRAY (ST)) { // above check is for array[3] or 3[array] if (EvalUtil (OP_lbrack, STP, ST, EU_LOAD) && EVPlusMinus (OP_plus)) { return (FetchOp (ST)); } } else if (EVAL_IS_PTR (STP)) { // this code is a hack to allow the locals and quick watch windows // display the virtual function table. The GetChildTM generates // an expression of the form a.__vfuncptr[n]. This means that the // evaluation of a.__vfuncptr on the left sets STP to a pointer // node and ThisAddress to the adjusted this pointer. Note that // it turns out that symbol address of STP and ThisAddress are // the same pvT = &evalT; *pvT = *STP; SetNodeType (pvT, PTR_UTYPE (pvT)); if (EVAL_IS_VTSHAPE (pvT) && (EVAL_STATE (ST) == EV_constant) && ((index = EVAL_USHORT (ST)) < VTSHAPE_COUNT (pvT))) { PopStack (); DASSERT ((EVAL_SYM_OFF (pvThis) == EVAL_SYM_OFF (ST)) && (EVAL_SYM_SEG (pvThis) == EVAL_SYM_SEG (ST))); return (VFuncAddress (ST, index)); } else { if (EvalUtil (OP_lbrack, STP, ST, EU_LOAD) && EVPlusMinus (OP_plus)) { return (FetchOp (ST)); } } } } return (FALSE); } /*** EvalCast - Perform a type cast operation * fSuccess = EvalCast (bn) * Entry bn = based pointer to cast node * Exit * Returns TRUE if successful * FALSE if error */ bool_t FASTCALL EvalCast (bnode_t bn) { peval_t pv; peval_t pvL; if (!EvalRChild (bn) || !EvalUtil (OP_cast, ST, NULL, EU_LOAD)) { return (FALSE); } DASSERT (!EVAL_IS_CLASS (ST)); // Cast the node to the desired type. if the cast node is a member node, // then the stack top is cast by changing the pointer value by the amount // in the value and then setting the type of the stack top to the type // of the left node pv = (peval_t)&bn->v[0]; pvL = &(NODE_LCHILD (bn))->v[0]; if (EVAL_MOD (pvL) != 0) { EVAL_MOD (ST) = EVAL_MOD (pvL); } if (EVAL_IS_MEMBER (pv) == TRUE) { // a cast of pointer to derived to pointer to base is not done // for a null value if (EVAL_PTR_OFF (ST) != 0) { if (Eval ((bnode_t)MEMBER_THISEXPR (pv)) == FALSE) { return (FALSE); } *ST = *pvThis; EVAL_STATE (ST) = EV_rvalue; EVAL_PTR (ST) = EVAL_SYM (pvThis); } return (SetNodeType (ST, EVAL_TYP (pvL))); } else { if (EVAL_IS_PTR (pvL)) { return (CastNode (ST, EVAL_TYP (pvL), PTR_UTYPE (pvL))); } else { return (CastNode (ST, EVAL_TYP (pvL), EVAL_TYP (pvL))); } } } /*** EvalByteOps - Handle 'by', 'wo' and 'dw' operators * fSuccess = EvalByteOps (bn) * Entry bn = based pointer to node * Exit ST = pointer to value * Returns TRUE if successful * FALSE if error * DESCRIPTION * Evaluates the contents of the address operand as a byte * ('by'), word ('wo') or dword ('dw'): * Operand Result * ------- ------ * *(uchar *) *
*(uchar *)
* *(uchar *)&variable * Where (uchar *) is replaced by (uint *) for the 'wo' operator, * or by (ulong *) for the 'dw' operator. */ bool_t FASTCALL EvalByteOps (bnode_t bn) { CV_typ_t type; register op_t op; if (!EvalLChild (bn)) { return (FALSE); } // If the operand is an lvalue and it is a register, // load the value of the register; otherwise, use the // address of the variable. // If the operand is not an lvalue, use its value as is. if (EVAL_STATE (ST) == EV_lvalue) { if (EVAL_IS_REG (ST)) { if (!LoadVal (ST)) { pExState->err_num = ERR_INTERNAL; return (FALSE); } else { type = T_USHORT; } } else { if ((type = NODE_STYPE (bn)) == 0) { // unable to find proper pointer type return (FALSE); } EVAL_STATE (ST) = EV_rvalue; #if 0 if (EVAL_IS_BPREL (ST)) { EVAL_SYM_OFF (ST) += pExState->frame.BP.off; EVAL_SYM_SEG (ST) = pExState->frame.SS; EVAL_IS_BPREL (ST) = FALSE; ADDR_IS_LI (EVAL_SYM (ST)) = FALSE; SHUnFixupAddr (&EVAL_SYM (ST)); } #else ResolveAddr(ST); #endif EVAL_PTR (ST) = EVAL_SYM (ST); SetNodeType (ST, type); } } // Now cast the node to (char far *), (int far *) or // (long far *). If the type is char, uchar, short // or ushort, we want to first cast to (char *) so // that we properly DS-extend (casting (int)8 to (char // far *) will give the result 0:8). type = EVAL_TYP (ST); //DASSERT(IS_PRIMITIVE (typ)); if (CV_TYP_IS_REAL (type)) { pExState->err_num = ERR_OPERANDTYPES; return (FALSE); } if ((op = NODE_OP (bn)) == OP_by) { type = pExState->state.f32bit ? T_32PFUCHAR : T_PFUCHAR; } else if (op == OP_wo) { type = pExState->state.f32bit ? T_32PFUSHORT : T_PFUSHORT; } else if (op == OP_dw) { type = pExState->state.f32bit ? T_32PFULONG : T_PFULONG; } if (CastNode (ST, type, type) == FALSE) { return (FALSE); } return (FetchOp (ST)); } /*** EvalSegOp - Handle ':' segmentation operator * fSuccess = EvalSegOp (bn) * Entry bn = based pointer to node * Exit EVAL_SYM (ST) = seg (STP): offset (ST) * Returns TRUE if successful * FALSE if error * DESCRIPTION * Both operands must have integral values (but cannot * be long or ulong). The result of op1:op2 is a (char * far *) with segment equal to op1 and offset equal to * op2. * NOTES */ bool_t FASTCALL EvalSegOp (bnode_t bn) { bool_t fLin32 = FALSE; if (!EvalLChild (bn) || !EvalRChild (bn)) { return(FALSE); } // check to make sure that neither operand is of type long or ulong. switch ( EVAL_TYP ( STP ) ) { case T_INT4: case T_UINT4: if ( VAL_ULONG( STP ) <= 0xffff ) { // [cuda #3035 8th Apr 93 sanjays] // An expression 0x0:0x0001 has its left operand typed INT by // the EEParser and rightly so because it doesn't know the context // We have to allow type int for the segment portion but make // sure the value is less than 0xffff. // We just look at the unsigned value so we will not accept negative // numbers either. break; } // else { fallthrough} case T_LONG: case T_ULONG: case T_QUAD: case T_UQUAD: case T_INT8: case T_UINT8: pExState->err_num = ERR_OPERANDTYPES; return (FALSE); default: break; } // set linear mode switch ( EVAL_TYP ( ST ) ) { case T_LONG: case T_ULONG: case T_INT4: case T_UINT4: fLin32 = TRUE; default: break; } // Load values and perform implicit type coercion if required. if (!EvalUtil (OP_segop, STP, ST, EU_LOAD | EU_TYPE)) return(FALSE); //DASSERT ((EVAL_TYP (STP) == T_SHORT) || (EVAL_TYP (STP) == T_USHORT)); //DASSERT ((EVAL_TYP (ST) == T_SHORT) || (EVAL_TYP (ST) == T_USHORT)); EVAL_STATE (STP) = EV_rvalue; EVAL_PTR_SEG (STP) = EVAL_USHORT (STP); EVAL_PTR_OFF (STP) = fLin32 ? EVAL_ULONG (ST) : EVAL_USHORT (ST); //REVIEW -billjoy - do we need to set fFlat? ADDR_IS_OFF32 ( EVAL_PTR (STP) ) = pExState->state.f32bit ? 1 : 0; SetNodeType (STP, (CV_typ_t) (pExState->state.f32bit ? T_32PFCHAR : T_PFCHAR)); return (PopStack ()); } /** EVUnary - Evaluate the result of a unary arithmetic operation * fSuccess = EVUnary (op) * Entry op = Operator (OP_...) * Returns TRUE if no error during evaluation * FALSE if error during evaluation * DESCRIPTION * Evaluates the result of an arithmetic operation. The unary operators * dealt with here are: * ! ~ - + * Pointer arithmetic is NOT handled; all operands must be of * arithmetic type. */ bool_t FASTCALL EVUnary (op_t op) { bool_t fIsFloat = FALSE; bool_t fIsDouble = FALSE; bool_t fIsLDouble = FALSE; bool_t fIsSigned; bool_t fResInt; int iRes; QUAD lRes, lL; UQUAD ulRes, ulL; FLOAT10 ldRes, ldL; double dRes, dL; float fRes, fL; CV_typ_t typRes; if (EVAL_IS_REF (ST)) { if (FetchOp (ST) == FALSE) { return (FALSE); } } // Load the values and perform implicit type conversion. if (!EvalUtil (op, ST, NULL, EU_LOAD | EU_TYPE)) return (FALSE); // The resultant type is the same as the type of the left-hand // side (assume for now we don't have the special int-result case). typRes = EVAL_TYP (ST); if (CV_TYP_IS_REAL (typRes) == TRUE) { fIsFloat = (CV_SUBT (typRes) == CV_RC_REAL32); fIsDouble = (CV_SUBT (typRes) == CV_RC_REAL64); fIsLDouble = (CV_SUBT (typRes) == CV_RC_REAL80); } fIsSigned = CV_TYP_IS_SIGNED (typRes); fResInt = FALSE; // Common code. Since we're going to do most of our arithmetic // in either long, ulong or double, we do the casts and get the // value of the operands here rather than repeating this code // in each arm of the switch statement. // Note: We now cast to (U)QUAD instead of (u)long, in order // to support __int64 bit operations if (fIsFloat) { fL = EVAL_FLOAT (ST); } else if (fIsDouble) { dL = EVAL_DOUBLE (ST); } else if (fIsLDouble) { ldL = EVAL_LDOUBLE (ST); } else if (fIsSigned) { CastNode (ST, T_QUAD, T_QUAD); lL = EVAL_QUAD (ST); } else { // unsigned CastNode (ST, T_UQUAD, T_UQUAD); ulL = EVAL_UQUAD (ST); } // Finally, do the actual arithmetic operation. switch (op) { case OP_bang: // Operand is of arithmetic type; result is always int. fResInt = TRUE; if (fIsFloat) { iRes = !fL; } else if (fIsDouble) { iRes = !dL; } else if (fIsLDouble) { iRes = !LongFromFloat10 ( ldL ); } else if (fIsSigned) { iRes = !lL; } else { iRes = !ulL; } break; case OP_tilde: // operand must be integral. //DASSERT (!fIsReal); if (fIsSigned) { lRes = ~lL; } else { ulRes = ~ulL; } break; case OP_negate: if (fIsFloat) { fRes = -fL; } else if (fIsDouble) { dRes = -dL; } else if (fIsLDouble) { ldRes = Float10Negate ( ldL ); } else if (fIsSigned) { lRes = -lL; } else { ulRes = -(QUAD)ulL; } break; case OP_uplus: if (fIsFloat) { fRes = fL; } else if (fIsDouble) { dRes = dL; } else if (fIsLDouble) { ldRes = ldL; } else if (fIsSigned) { lRes = lL; } else { ulRes = ulL; } break; default: DASSERT (FALSE); pExState->err_num = ERR_INTERNAL; return (FALSE); } // Now set up the resultant node and coerce back to the correct // type: EVAL_STATE (ST) = EV_rvalue; if (fResInt) { if (pExState->state.f32bit) { EVAL_LONG (ST) = (long) iRes; SetNodeType (ST, T_INT4); } else { EVAL_SHORT (ST) = (short) iRes; SetNodeType (ST, T_INT2); } } else { if (fIsFloat) { EVAL_FLOAT (ST) = fRes; SetNodeType (ST, T_REAL32); } else if (fIsDouble) { EVAL_DOUBLE (ST) = dRes; SetNodeType (ST, T_REAL64); } else if (fIsLDouble) { EVAL_LDOUBLE (ST) = ldRes; SetNodeType (ST, T_REAL80); } else if (fIsSigned) { EVAL_QUAD (ST) = lRes; SetNodeType (ST, T_QUAD); } else { EVAL_UQUAD (ST) = ulRes; SetNodeType (ST, T_UQUAD); } CastNode (ST, typRes, typRes); } return(TRUE); } /** EVArith - Evaluate the result of an arithmetic operation * fSuccess = EVArith (op) * Entry op = Operator (OP_...) * Returns TRUE if no error during evaluation * FALSE if error during evaluation * DESCRIPTION * Evaluates the result of an arithmetic operation. The operators * dealt with here are: * * / % * + - * == != * < <= > >= * << >> * & ^ | * Pointer arithmetic is NOT handled; all operands must be of * arithmetic type. */ bool_t FASTCALL EVArith (op_t op) { bool_t fIsFloat = FALSE; bool_t fIsDouble = FALSE; bool_t fIsLDouble = FALSE; bool_t fIsSigned; bool_t fResInt; bool_t lNearNullPtr = FALSE; bool_t rNearNullPtr = FALSE; int iRes; QUAD lRes, lL, lR; UQUAD ulRes, ulL, ulR; float fRes, fL, fR; double dRes, dL, dR; FLOAT10 ldRes, ldL, ldR; CV_typ_t typRes; if (EVAL_IS_REF (STP)) { if (FetchOp (STP) == FALSE) { return (FALSE); } } if (EVAL_IS_REF (ST)) { if (FetchOp (ST) == FALSE) { return (FALSE); } } if (EVAL_IS_ENUM (ST)) { SetNodeType (ST, ENUM_UTYPE (ST)); } if (EVAL_IS_ENUM (STP)) { SetNodeType (STP, ENUM_UTYPE (STP)); } // A NULL near pointer should compare equal to 0, although // its offset may be non-0 --gdp 9/22/92 if (EVAL_IS_PTR(ST) && EVAL_PTRTYPE(ST) == CV_PTR_NEAR && EVAL_PTR_OFF(ST) == 0) { rNearNullPtr = TRUE; } if (EVAL_IS_PTR(STP) && EVAL_PTRTYPE(STP) == CV_PTR_NEAR && EVAL_PTR_OFF(STP) == 0) { lNearNullPtr = TRUE; } // Resolve identifiers and check the node types. If the nodes // pass validation, they should not be pointers (only arithmetic // operands are handled by this routine). // Load the values and perform implicit type conversion. if (!EvalUtil (op, STP, ST, EU_LOAD | EU_TYPE)) return (FALSE); // The resultant type is the same as the type of the left-hand // side (assume for now we don't have the special int-result case). typRes = EVAL_TYP (STP); if (CV_TYP_IS_REAL (typRes) == TRUE) { fIsFloat = (CV_SUBT (typRes) == CV_RC_REAL32); fIsDouble = (CV_SUBT (typRes) == CV_RC_REAL64); fIsLDouble = (CV_SUBT (typRes) == CV_RC_REAL80); } fIsSigned = CV_TYP_IS_SIGNED (typRes); fResInt = FALSE; // Common code. Since we're going to do most of our arithmetic // in either long, ulong or double, we do the casts and get the // value of the operands here rather than repeating this code // in each arm of the switch statement. if (fIsLDouble) { CastNode (STP, T_REAL80, T_REAL80); ldL = EVAL_LDOUBLE (STP); CastNode (ST, T_REAL80, T_REAL80); ldR = EVAL_LDOUBLE (ST); } else if (fIsDouble) { CastNode (STP, T_REAL64, T_REAL64); dL = EVAL_DOUBLE (STP); CastNode (ST, T_REAL64, T_REAL64); dR = EVAL_DOUBLE (ST); } else if (fIsFloat) { CastNode (STP, T_REAL32, T_REAL32); fL = EVAL_FLOAT (STP); CastNode (ST, T_REAL32, T_REAL32); fR = EVAL_FLOAT (ST); } else if (fIsSigned) { CastNode (STP, T_QUAD, T_QUAD); lL = EVAL_QUAD (STP); CastNode (ST, T_QUAD, T_QUAD); lR = EVAL_QUAD (ST); } else { CastNode (STP, T_UQUAD, T_UQUAD); ulL = EVAL_UQUAD (STP); CastNode (ST, T_UQUAD, T_UQUAD); ulR = EVAL_UQUAD (ST); } // Finally, do the actual arithmetic operation. switch (op) { case OP_eqeq: case OP_bangeq: case OP_lt: case OP_gt: case OP_lteq: case OP_gteq: { // This is kind of a strange way to do things, but it should // be pretty obvious what's going on, and it saves code. int fEq; int fLt; fResInt = TRUE; if (fIsLDouble) { fEq = Float10Equal (ldL, ldR); fLt = Float10LessThan (ldL, ldR); } else if (fIsDouble) { fEq = (dL == dR); fLt = (dL < dR); } else if (fIsFloat) { fEq = (fL == fR); fLt = (fL < fR); } else if (fIsSigned) { fEq = (lL == lR); fLt = (lL < lR); } else { fEq = lNearNullPtr && (ulR == 0) || rNearNullPtr && (ulL == 0) || (ulL == ulR); fLt = (ulL < ulR); } switch (op) { case OP_eqeq: iRes = fEq; break; case OP_bangeq: iRes = !fEq; break; case OP_lt: iRes = fLt; break; case OP_gt: iRes = !fLt && !fEq; break; case OP_lteq: iRes = fLt || fEq; break; case OP_gteq: iRes = !fLt || fEq; break; } } break; case OP_plus: if (fIsLDouble) { ldRes = Float10OpPlus (ldL, ldR); } else if (fIsDouble) { dRes = dL + dR; } else if (fIsFloat) { fRes = fL + fR; } else if (fIsSigned) { lRes = lL + lR; } else { ulRes = ulL + ulR; } break; case OP_minus: if (fIsLDouble) { ldRes = Float10OpMinus (ldL, ldR); } else if (fIsDouble) { dRes = dL - dR; } else if (fIsFloat) { fRes = fL - fR; } else if (fIsSigned) { lRes = lL - lR; } else { ulRes = ulL - ulR; } break; case OP_mult: if (fIsLDouble) { ldRes = Float10OpMul (ldL, ldR); } else if (fIsDouble) { dRes = dL * dR; } else if (fIsFloat) { fRes = fL * fR; } else if (fIsSigned) { lRes = lL * lR; } else { ulRes = ulL * ulR; } break; case OP_div: // This looks big, but I can't figure out how to do it // with ||'s. Besides, Hans claims it will tail merge // on the error conditions anyway. if (fIsLDouble) { if (Float10Equal (ldR, Float10Zero())) { pExState->err_num = ERR_DIVIDEBYZERO; return (FALSE); } ldRes = Float10OpDiv ( ldL, ldR ); } else if (fIsDouble) { if (dR == (double)0.0) { pExState->err_num = ERR_DIVIDEBYZERO; return (FALSE); } dRes = dL / dR; } else if (fIsFloat) { if (fR == (float)0.0) { pExState->err_num = ERR_DIVIDEBYZERO; return (FALSE); } fRes = fL / fR; } else if (fIsSigned) { if (lR == (long)0) { pExState->err_num = ERR_DIVIDEBYZERO; return (FALSE); } lRes = lL / lR; } else { if (ulR == (unsigned long)0) { pExState->err_num = ERR_DIVIDEBYZERO; return (FALSE); } ulRes = ulL / ulR; } break; case OP_mod: // Both operands must be integral. //DASSERT(!fIsReal); if (fIsSigned) { if (lR == (long)0) { pExState->err_num = ERR_DIVIDEBYZERO; return (FALSE); } lRes = lL % lR; } else { if (ulR == (unsigned long)0) { pExState->err_num = ERR_DIVIDEBYZERO; return (FALSE); } ulRes = ulL % ulR; } break; case OP_shl: // Both operands must be integral. //DASSERT(!fIsReal); if (fIsSigned) { lRes = lL << lR; } else { ulRes = ulL << ulR; } break; case OP_shr: // Both operands must be integral. //DASSERT(!fIsReal); if (fIsSigned) { lRes = lL >> lR; } else { ulRes = ulL >> ulR; } break; case OP_and: // Both operands must have integral type. //DASSERT(!fIsReal); if (fIsSigned) { lRes = lL & lR; } else { ulRes = ulL & ulR; } break; case OP_or: // Both operands must have integral type. //DASSERT(!fIsReal); if (fIsSigned) { lRes = lL | lR; } else { ulRes = ulL | ulR; } break; case OP_xor: // Both operands must have integral type. //DASSERT(!fIsReal); if (fIsSigned) { lRes = lL ^ lR; } else { ulRes = ulL ^ ulR; } break; default: pExState->err_num = ERR_INTERNAL; //DASSERT(FALSE); return (FALSE); } // Now set up the resultant node and coerce back to the correct // type: EVAL_STATE (STP) = EV_rvalue; if (fResInt) { if (pExState->state.f32bit) { EVAL_LONG (STP) = (long) iRes; SetNodeType (STP, T_INT4); } else { EVAL_SHORT (STP) = (short) iRes; SetNodeType (STP, T_INT2); } } else { if (fIsLDouble) { EVAL_LDOUBLE (STP) = ldRes; SetNodeType (STP, T_REAL80); } else if (fIsDouble) { EVAL_DOUBLE (STP) = dRes; SetNodeType (STP, T_REAL64); } else if (fIsFloat) { EVAL_FLOAT (STP) = fRes; SetNodeType (STP, T_REAL32); } else { if (fIsSigned) { EVAL_QUAD (STP) = lRes; SetNodeType (STP, T_QUAD); } else { EVAL_UQUAD (STP) = ulRes; SetNodeType (STP, T_UQUAD); } CastNode (STP, typRes, typRes); } } return (PopStack ()); } /*** EvalUtil - Set up nodes for evaluation * fSuccess = EvalUtil (op, pvLeft, pvRight, wFlags) * Entry pvLeft = pointer to left operand node * pvRight = pointer to right operand node, or NULL * wFlags = EU_... * Exit pvLeft and pvRight loaded and/or typed as requested * Returns TRUE if successful * FALSE if error */ bool_t FASTCALL EvalUtil (op_t op, peval_t pvLeft, peval_t pvRight, ulong wFlags) { // Load the value of the node(s). if (wFlags & EU_LOAD) { switch (EVAL_STATE (pvLeft)) { case EV_lvalue: if (!LoadVal (pvLeft)) { pExState->err_num = ERR_NOTEVALUATABLE; return (FALSE); } break; case EV_rvalue: case EV_constant: break; case EV_type: if (EVAL_IS_STMEMBER (pvLeft)) { if (!LoadVal (pvLeft)) { pExState->err_num = ERR_NOTEVALUATABLE; return (FALSE); } else { break; } } default: pExState->err_num = ERR_SYNTAX; return (FALSE); } if (pvRight != NULL) { switch (EVAL_STATE (pvRight)) { case EV_lvalue: if (!LoadVal (pvRight)) { pExState->err_num = ERR_NOTEVALUATABLE; return (FALSE); } break; case EV_rvalue: case EV_constant: break; case EV_type: if (EVAL_IS_STMEMBER (pvRight)) { if (!LoadVal (pvRight)) { pExState->err_num = ERR_NOTEVALUATABLE; return (FALSE); } else { break; } } default: pExState->err_num = ERR_SYNTAX; return (FALSE); } } } // Perform implicit type coercion. if (wFlags & EU_TYPE) { TypeNodes (op, pvLeft, pvRight); } return (TRUE); } /** EvalPrototype - evaluate a function prototype as for a breakpoint. * fSuccess = EvalPrototype (pn) * Entry bn = based pointer to OP_fcn * Exit ST = result of function call * pExState->err_num = error number if error * Returns TRUE if successful * FALSE if error */ bool_t EvalPrototype (bnode_t bn) { bnode_t bnRight = NODE_RCHILD (bn); eval_t evalF; peval_t pvF = &evalF; // NOTE: evaluation of prototypes/bp addrs DOES NOT MODIFY. // is_assign = TRUE ; if (!EvalLChild (bn)) { return FALSE; } if (EVAL_IS_PTR (ST)) { FetchOp (ST); } *pvF = *ST; PopStack (); if (EVAL_IS_METHOD (pvF)) { if (EVAL_IS_BPREL (pvThis)) { ResolveAddr(pvThis); } if (EVAL_IS_REGREL(pvThis)) { SHREG reg; // The problem with this code is that if we are evaluating a // prototype or EEBPADDRESS we may not even be running -- or may // not be in context whatsoever. Thus, any registers we may // get will be meaningless. Lets hope this does not happen. DASSERT (FALSE); return FALSE; EVAL_IS_REGREL(pvThis) = FALSE; reg.hReg = EVAL_REGREL (pvThis); if (GetReg(®, pCxt, NULL) == NULL) { DASSERT (FALSE); return FALSE; } EVAL_SYM_OFF (pvThis) += reg.Byte4; EVAL_SYM_SEG (pvThis) = GetSegmentRegister(pExState->hframe, REG_SS); ADDR_IS_LI (EVAL_SYM (pvF)) = FALSE; SHUnFixupAddr ((LPADDR)&EVAL_SYM (pvF)); } } // The stack is empty here, we need to push address back on or // else we will fault. PushStack (pvF); return TRUE; } /** EvalFunction - Perform an function call * fSuccess = EvalFunction (pn) * Entry bn = based pointer to OP_fcn * Exit ST = result of function call * pExState->err_num = error number if error * Returns TRUE if successful * FALSE if error */ bool_t FASTCALL EvalFunction (bnode_t bn) { bnode_t bnRight = NODE_RCHILD (bn); bnode_t bnT; eval_t evalRet; peval_t pvRet; eval_t evalF; peval_t pvF; bnode_t bnA; peval_t pvA; SHREG spReg; bool_t retval = FALSE; HDEP hReg = 0; UOFFSET maxSP = 0; CV_typ_t typArg; pargd_t pa; ADDR fcnAddr; bool_t fEvalProto = FALSE; HDEP hFunc; ADDR addr; // check if we are dealing with a actual call or a function proto // we can check this by just checking the first argument in the // bArgList, because Function has already checked that they are // either all types or all expressions // sps - 2/24/92 if ((bnRight != NULL) && (NODE_OP ((pnode_t)bnRight) != OP_endofargs)) { pnode_t pnT = (pnode_t)bnRight; pargd_t pa = (pargd_t)&(pnT->v[0]); fEvalProto = (pa->flags.istype); } // Function prototypes and evaluation for the purpose of setting a BP // go through EvalPrototype. if (pExState->style == EEBPADDRESS || fEvalProto) { return EvalPrototype (bn); } // EvalFunction can possibly update global variables etc... is_assign = TRUE; if (!EvalLChild (bn)) { // CUDA #3949 : can't goto EvalFunctionExit here because hReg is not // initialized yet [rm] // goto EvalFunctionExit; return FALSE; } if (EVAL_IS_PTR (ST)) { FetchOp (ST); } // the stack top is the function address node. We save this information // and pop the function node. We then push the argument left to right // using the SP relative offset from the bind that is stored in the address // field of the OP_arg node. // The evaluation of the left node also processed the this pointer // adjustment. ThisAddress contains the value of the this pointer pvF = &evalF; *pvF = *ST; PopStack (); // Do not allow function evaluation on the Mac. if (TargetMachine == mptmppc) { return FALSE; } // the left child must resolve to a function address and BP must not // be zero and the overlay containing the function must be loaded SYGetAddr(pExState->hframe, &addr, adrBase); if (GetAddrOff(addr) == 0) { pExState->err_num = ERR_FCNCALL; return FALSE; } if (DHSetupExecute(&hFunc)) { pExState->err_num = ERR_NOMEMORY; return FALSE; } switch (TargetMachine) { case mptmips: spReg.hReg = CV_M4_IntSP; break; case mptdaxp: spReg.hReg = CV_ALPHA_IntSP; break; case mptm68k: DASSERT(FALSE); break; case mptix86: spReg.hReg = CV_REG_ESP; break; case mptia64: spReg.hReg = CV_IA64_IntSp; break; case mptmppc: case mptntppc: DASSERT (FALSE); break; default: DASSERT (FALSE); } GetReg (&spReg, pCxt, NULL); // Evaluate argument nodes until end of arguments reached and count arguments for (bnT = bnRight; NODE_OP (bnT) != OP_endofargs; bnT = NODE_RCHILD (bnT)) { if (NODE_OP (bnT) != OP_arg) { pExState->err_num = ERR_INTERNAL; goto EvalFunctionExit; } bnA = NODE_LCHILD (bnT); pvA = &bnA->v[0]; pa = (pargd_t)&bnT->v[0]; typArg = pa->type; if (Eval (bnA) == FALSE) { goto EvalFunctionExit; } GetReg (&spReg, pCxt, NULL); // Canonicalize reference actual parameters. if (EVAL_IS_REF (ST)) { if (!FetchOp (ST)) { goto EvalFunctionExit; } EVAL_IS_REF (ST) = FALSE; } if (EVAL_STATE (ST) == EV_constant && pa->flags.ref == FALSE && IsStringLiteral(ST)) { if (PushString (ST, &spReg, typArg, EVAL_SYM_IS32(pvF)) == FALSE) { goto EvalFunctionExit; } SetReg (&spReg, pCxt, NULL); } else { // if the OP_arg node contains a nonzero type (not vararg), // cast the stack top to the specified value if (pa->flags.ref == TRUE) { // for a reference argument, the following happens // if the actual is a constant, cast and push onto // the stack and pass the address. If the actual // is a variable of the correct type, pass the address. // If the actual is a variable of the wrong type, load // and attempt to cast to the correct type, push the // value onto the stack and pass the address. If the // actual is a complex type, pass the address. If the // formal is a base class of the actual, cast the // address and pass that. if (EVAL_STATE (ST) == EV_constant) { // push the casted constant onto the stack if (!CastNode (ST, pa->utype, pa->utype)) { goto EvalFunctionExit; } PushRef (ST, &spReg, pa->type, EVAL_SYM_IS32(pvF)); SetReg (&spReg, pCxt, NULL); } else if (EVAL_STATE (ST) == EV_lvalue && (EVAL_IS_CLASS (ST) || EVAL_TYP (ST) == pa->utype)) { // we either have a class or a simple variable that // has an address (lvalue) and matches the formal // argument type exactly. // the address of the class or a base class must // be pushed This is done by changing the type of // the node to a far constructed cv pointer. The // following cast will set the node to the correct type. SetNodeType (ST, (CV_typ_t) (EVAL_SYM_IS32(pvF) ? T_32NCVPTR : T_FCVPTR)); if (!CastNode (ST, pa->type, pa->type)) { goto EvalFunctionExit; } if (!EvalUtil (OP_function, ST, NULL, EU_LOAD)) { goto EvalFunctionExit; } EVAL_PTR (ST) = EVAL_SYM (ST); } else { // process a "simple" variable if (!EvalUtil (OP_function, ST, NULL, EU_LOAD)) { goto EvalFunctionExit; } // if the variable is not of the correct type, // load and cast the value to the correct type, // push the value onto the stack and pass that // address to the function if (EVAL_TYP (ST) != pa->type) { if (!CastNode (ST, pa->utype, pa->utype)) { goto EvalFunctionExit; } } PushRef (ST, &spReg, pa->type, EVAL_SYM_IS32(pvF)); SetReg (&spReg, pCxt, NULL); } } else { // an actual that is not a reference cannot be a class. Load the value // and cast it to the proper type. if (EVAL_IS_CLASS (ST)) { pExState->err_num = ERR_CANTCONVERT; goto EvalFunctionExit; } if (EVAL_IS_ENUM (ST)) { // typArg may be a fwd ref to an enum type // Try to resolve it before proceeding or else // CastNode may fail. [Dolphin #3659] eval_t localEval; peval_t pvT = &localEval; *pvT = *ST; if (SetNodeType (pvT, typArg)) { typArg = EVAL_TYP (pvT); } } if (!EvalUtil (OP_function, ST, NULL, EU_LOAD) || !CastNode (ST, typArg, typArg)) { goto EvalFunctionExit; } } } } // evaluate left hand side of tree to get function address // set type of this pointer if method pvRet = &evalRet; if (EVAL_IS_METHOD (pvF)) { if (EVAL_IS_BPREL (pvThis)) { ResolveAddr(pvThis); } if (EVAL_IS_REGREL(pvThis)) { SHREG reg; EVAL_IS_REGREL(pvThis) = FALSE; reg.hReg = EVAL_REGREL (pvThis); if (GetReg(®, pCxt, pExState->hframe) == NULL) { DASSERT(FALSE); retval = FALSE; goto EvalFunctionExit; } EVAL_SYM_OFF (pvThis) += reg.Byte4; EVAL_SYM_SEG (pvThis) = GetSegmentRegister(pExState->hframe, REG_SS); ADDR_IS_LI (EVAL_SYM (pvF)) = FALSE; SHUnFixupAddr ((LPADDR)&EVAL_SYM (pvF)); } // Do not call with a NULL this pointer. if (!EVAL_IS_STMETHOD (pvThis) && EVAL_SYM_OFF (pvThis) == 0) { retval = FALSE; goto EvalFunctionExit; } } DASSERT (TargetMachine != mptmppc); // set type of return node *pvRet = *pvF; SetNodeType (pvRet, FCN_RETURN (pvRet)); EVAL_VALLEN (pvRet) = (ulong )TypeSize (pvRet); EVAL_STATE (pvRet) = EV_rvalue; // for some return types, certain calling conventions requires a hidden // argument pointing to space allocated on the user's stack large // enough to hold the return value. if (EVAL_SYM_IS32(pvF)) { // in the 32 bit world all calling conventions returning a struct/class // the callee allocates the tmp and passes the address in a hidden // parm if (EVAL_IS_CLASS (pvRet)) { spReg.Byte4 -= (EVAL_VALLEN (pvRet) + 3) & ~3; if (TargetMachine == mptix86) { // if fastcall pass the address of return tmp in ECX if (FCN_CALL(pvF) == FCN_FAST) { SHREG reg; reg.hReg = CV_REG_ECX; reg.Byte4 = spReg.Byte4; SetReg (®, pCxt, NULL); } else { ADDR_IS_LI (EVAL_SYM (pvRet)) = FALSE; EVAL_STATE (pvRet) = EV_lvalue; EVAL_SYM_OFF (pvRet) = spReg.Byte4; EVAL_ULONG (pvRet) = spReg.Byte4; EVAL_SYM_SEG (pvRet) = GetSegmentRegister(pExState->hframe, REG_SS); } } } } else { switch (FCN_CALL (pvF)) { case FCN_C: // The C and the C++ compiler use different calling // conventions for functions that return structures > 4 bytes // Until the compiler provides sufficient information // to distinguish between these two, the EE will not // support such function calls. if (!EVAL_IS_REF (pvRet) && ((!CV_IS_PRIMITIVE (EVAL_TYP (pvRet)) && ((EVAL_VALLEN (pvRet) > 4) && (CV_TYPE (EVAL_TYP (pvRet)) != CV_REAL))))) { pExState->err_num = ERR_CALLSEQ; goto EvalFunctionExit; } break; case FCN_PASCAL: // If the return value is larger than 4 bytes, then allocate // space on the stack and set the return node // to point to this address if (!EVAL_IS_REF (pvRet) && ((!CV_IS_PRIMITIVE (EVAL_TYP (pvRet)) || (CV_TYPE (EVAL_TYP (pvRet)) == CV_REAL) || (EVAL_VALLEN (pvRet) > 4)))) { ADDR_IS_LI (EVAL_SYM (pvRet)) = FALSE; EVAL_STATE (pvRet) = EV_lvalue; spReg.Byte4 -= (ushort) ((EVAL_VALLEN (pvRet) + 1) & ~1); EVAL_SYM_OFF (pvRet) = spReg.Byte2; EVAL_USHORT (pvRet) = spReg.Byte2; EVAL_SYM_SEG (pvRet) = GetSegmentRegister(pExState->hframe, REG_SS);; } break; case FCN_FAST: // If the return value is not real and is larger than 4 bytes, // then allocate space on the stack and set the return node // to point to this address. For fastcall, real values are // returned on the numeric coprocessor stack if (!EVAL_IS_REF (pvRet) && ((!CV_IS_PRIMITIVE (EVAL_TYP (pvRet)) && ((EVAL_VALLEN (pvRet) > 4) && (CV_TYPE (EVAL_TYP (pvRet)) != CV_REAL))))) { ADDR_IS_LI (EVAL_SYM (pvRet)) = FALSE; EVAL_STATE (pvRet) = EV_lvalue; spReg.Byte4 -= (ushort) ((EVAL_VALLEN (pvRet) + 1) & ~1); EVAL_SYM_OFF (pvRet) = spReg.Byte2; EVAL_USHORT (pvRet) = spReg.Byte2; EVAL_SYM_SEG (pvRet) = GetSegmentRegister(pExState->hframe, REG_SS);; } break; default: DASSERT (FALSE); pExState->err_num = ERR_INTERNAL; goto EvalFunctionExit; } } // push arguments for the function if (PushArgs ((pnode_t)bnRight, &spReg, &maxSP) == FALSE) { goto EvalFunctionExit; } if (EVAL_STATE (pvRet) == EV_lvalue) { if (!PushOffset (EVAL_SYM_OFF (pvRet), &spReg, &maxSP, (EVAL_SYM_IS32 (pvF) ? sizeof (CV_uoff32_t) : sizeof (CV_uoff16_t)))) { goto EvalFunctionExit; } } if (EVAL_IS_METHOD (pvF)) { SetNodeType (pvThis, FCN_THIS (pvF)); if (ADDR_IS_LI (EVAL_SYM(pvThis))) { SHFixupAddr (&EVAL_SYM(pvThis)); } DASSERT (!EVAL_IS_FPTR32(pvThis)); //unsupported if (EVAL_IS_NPTR32 (pvThis)) { SHREG argReg; DASSERT (EVAL_SYM_IS32(pvF)); if (FCN_CALL(pvF) == FCN_MIPS) { argReg.hReg = CV_M4_IntA0; // BUGBUG must support 64 bit offsets argReg.Byte4 = (UOFF32)EVAL_SYM_OFF(pvThis); SetReg(&argReg, pCxt, NULL); } else if (FCN_CALL(pvF) == FCN_ALPHA) { argReg.hReg = CV_ALPHA_IntA0; // BUGBUG must support 64 bit offsets argReg.Byte4 = (UOFF32)EVAL_SYM_OFF(pvThis); SetReg(&argReg, pCxt, NULL); } else if (FCN_CALL(pvF) == FCN_PPC) { argReg.hReg = CV_PPC_GPR3; // BUGBUG must support 64 bit offsets argReg.Byte4 = (UOFF32)EVAL_SYM_OFF(pvThis); SetReg(&argReg, pCxt, NULL); } else if (FCN_CALL(pvF) == FCN_IA64) { argReg.hReg = CV_IA64_IntR32; // BUGBUG must support 64 bit offsets argReg.Byte4 = (UOFF32)EVAL_SYM_OFF(pvThis); // v-vadimp - theoretically EM should take care of updating the stacked registers correctly // and no extra functionality is needed here SetReg(&argReg, pCxt, NULL); } else // for _thiscall pass the this pointer in ECX if (FCN_CALL(pvF) == FCN_THISCALL) { argReg.hReg = CV_REG_ECX; // BUGBUG must support 64 bit offsets argReg.Byte4 = (UOFF32)EVAL_SYM_OFF (pvThis); SetReg (&argReg, pCxt, NULL); } else if (!PushOffset (EVAL_SYM_OFF (pvThis), &spReg, &maxSP, sizeof (CV_uoff32_t))) { goto EvalFunctionExit; } } else { if (!EVAL_IS_NPTR (pvThis)) { if (!PushOffset (EVAL_SYM_SEG (pvThis), &spReg, &maxSP, sizeof (ushort))) { goto EvalFunctionExit; } } if (!PushOffset (EVAL_SYM_OFF (pvThis), &spReg, &maxSP, sizeof (CV_uoff16_t))) { goto EvalFunctionExit; } } } // Call the user's procedure spReg.Byte4 -= (ushort) maxSP; SetReg (&spReg, pCxt, NULL); if (!getFuncAddrNoThunks(pvF)) { goto EvalFunctionExit; } fcnAddr = EVAL_SYM(pvF); // make sure that the execution model is Native, if it is not // then return ERR_CALLSEQ. { WORD wModel; SYMPTR pSym; UOFFSET obMax = 0xFFFFFFFF; if (SHModelFromAddr(&fcnAddr, &wModel, (uchar *)&pSym, &obMax )) { if ( wModel != CEXM_MDL_native ) { // not native calling sequence, return error pExState->err_num = ERR_CALLSEQ; goto EvalFunctionExit; } } } if (ADDR_IS_LI (fcnAddr)) { SHFixupAddr (&fcnAddr); } if (DHStartExecute (hFunc, &fcnAddr, TRUE, EVAL_IS_FFCN (pvF) ? SHFar : SHNear ) ) { pExState->err_num = ERR_FCNCALLERR; goto EvalFunctionExit; } // Procedure succeeded, set return information and set flag to force // update is_assign = TRUE; PushStack (pvRet); if (EVAL_TYP (pvRet) != T_VOID) { if (EVAL_SYM_IS32 (pvF)) { switch (FCN_CALL(pvF)) { case FCN_C: case FCN_THISCALL: case FCN_STD: case FCN_FAST: retval = Store32 (pvF); break; case FCN_IA64: retval = StoreIa64(pvF); break; case FCN_MIPS: retval = StoreMips(pvF); break; case FCN_ALPHA: retval = StoreAlpha(pvF); break; case FCN_PPC: retval = StorePPC(pvF); break; default: goto EvalFunctionExit; } // CUDA #4020 : mark pointers as 32 bit or else badness... if (retval && EVAL_IS_PTR(ST)) { ADDRLIN32(EVAL_PTR(ST)); } } else { switch (FCN_CALL (pvF)) { case FCN_C: retval = StoreC (pvF); break; case FCN_PASCAL: retval = StoreP (); break; case FCN_FAST: retval = StoreF (); break; default: goto EvalFunctionExit; } } } else { retval = TRUE; } if (retval == TRUE) { // According to C++ "a function call is an lvalue only // if the result type is a reference". In that case // the result node is converted to the lvalue of the // referenced object. By doing so, it is possible to // evaluate child expressions (such as base classes), // that need to get the address of the referenced object . if (EVAL_IS_REF (ST)) { EVAL_SYM (ST) = EVAL_PTR (ST); RemoveIndir (ST); EVAL_STATE (ST) = EV_lvalue; } else { EVAL_STATE (ST) = EV_rvalue; } } EvalFunctionExit: if (DHCleanUpExecute(hFunc)) { retval = FALSE; } return retval; } /** PushArgs - push arguments * fSuccess = PushArgs (pnArg, pspReg, pmaxSP); * Entry pnArg = pointer to argument nodes * pspReg = pointer to register structure for SP value * pmaxSP = pointer to location to store maximum SP relative offset * Exit arguments pushed onto stack * Returns TRUE if parameters pushed without error * FALSE if error during push */ bool_t PushArgs ( pnode_t pnArg, SHREG *pspReg, UOFFSET *pmaxSP ) { SHREG argReg; // The arguments have been evaluated left to right which means that the // rightmost argument is at ST. We need to recurse down the right side // of the argument tree to find the OP_arg node that corresponds to the // stack top. if (NODE_OP (pnArg) == OP_endofargs) { return (TRUE); } if (!PushArgs ((pnode_t)NODE_RCHILD (pnArg), pspReg, pmaxSP)) { return (FALSE); } else { if (((pargd_t)&(pnArg->v[0]))->flags.isreg == TRUE) { argReg.hReg = ((pargd_t)&(pnArg->v[0]))->reg; switch (TargetMachine) { case mptmips: switch (argReg.hReg) { case CV_M4_IntA0: case CV_M4_IntA1: case CV_M4_IntA2: case CV_M4_IntA3: argReg.Byte4 = EVAL_ULONG( ST ); *pmaxSP = max( *pmaxSP, ((pargd_t)&pnArg->v[0])->SPoff ); break; case CV_M4_FltF12: case CV_M4_FltF14: memcpy(&argReg.Byte4, &EVAL_FLOAT( ST ), sizeof(float)); *pmaxSP = max( *pmaxSP, ((pargd_t)&pnArg->v[0])->SPoff ); break; case (CV_M4_IntA1<<8)|CV_M4_IntA0: case (CV_M4_IntA3<<8)|CV_M4_IntA2: case (CV_M4_FltF13<<8)|CV_M4_FltF12: case (CV_M4_FltF15<<8)|CV_M4_FltF14: memcpy(&argReg.Byte1, &EVAL_DOUBLE( ST ), sizeof(double)); *pmaxSP = __max( *pmaxSP, ((pargd_t)&pnArg->v[0])->SPoff ); break; default: DASSERT(FALSE); break; } break; case mptdaxp: switch (argReg.hReg) { case CV_ALPHA_IntA0: case CV_ALPHA_IntA1: case CV_ALPHA_IntA2: case CV_ALPHA_IntA3: case CV_ALPHA_IntA4: case CV_ALPHA_IntA5: *((QUAD *) &argReg.Byte4) = EVAL_QUAD( ST ); *pmaxSP = __max( *pmaxSP, ((pargd_t)&pnArg->v[0])->SPoff ); break; case CV_ALPHA_FltF16: case CV_ALPHA_FltF17: case CV_ALPHA_FltF18: case CV_ALPHA_FltF19: case CV_ALPHA_FltF20: case CV_ALPHA_FltF21: memcpy(&argReg.Byte1, &EVAL_DOUBLE ( ST ), sizeof(double)); *pmaxSP = __max( *pmaxSP, ((pargd_t)&pnArg->v[0])->SPoff ); break; default: DASSERT(FALSE); break; } break; case mptix86: switch (argReg.hReg & 0xff) { case CV_REG_AL: case CV_REG_CL: case CV_REG_DL: case CV_REG_BL: case CV_REG_AH: case CV_REG_CH: case CV_REG_DH: argReg.Byte1 = EVAL_UCHAR (ST); break; case CV_REG_EAX: case CV_REG_ECX: case CV_REG_EDX: case CV_REG_EBX: case CV_REG_ESP: case CV_REG_EBP: case CV_REG_ESI: case CV_REG_EDI: case CV_REG_CR0: case CV_REG_CR1: case CV_REG_CR2: case CV_REG_CR3: case CV_REG_CR4: case CV_REG_DR0: case CV_REG_DR1: case CV_REG_DR2: case CV_REG_DR3: case CV_REG_DR4: case CV_REG_DR5: case CV_REG_DR6: case CV_REG_DR7: argReg.Byte4 = EVAL_ULONG (ST); break; case CV_REG_ST0: case CV_REG_ST1: case CV_REG_ST2: case CV_REG_ST3: case CV_REG_ST4: case CV_REG_ST5: case CV_REG_ST6: case CV_REG_ST7: argReg.Byte10 = EVAL_LDOUBLE (ST); break; default: argReg.Byte2 = EVAL_USHORT (ST); break; } if ((argReg.hReg >> 8) != CV_REG_NONE) { switch (argReg.hReg >> 8) { case CV_REG_DX: case CV_REG_ES: argReg.Byte2High = *(((ushort *)&(EVAL_ULONG (ST))) + 1); break; } } break; case mptia64: switch (argReg.hReg) { case CV_IA64_IntR32: case CV_IA64_IntR33: case CV_IA64_IntR34: case CV_IA64_IntR35: case CV_IA64_IntR36: case CV_IA64_IntR37: case CV_IA64_IntR38: case CV_IA64_IntR39: *((QUAD *) &argReg.Byte4) = EVAL_QUAD( ST ); *pmaxSP = __max( *pmaxSP, ((pargd_t)&pnArg->v[0])->SPoff ); break; case CV_IA64_FltT2: case CV_IA64_FltT3: case CV_IA64_FltT4: case CV_IA64_FltT5: case CV_IA64_FltT6: case CV_IA64_FltT7: case CV_IA64_FltT8: case CV_IA64_FltT9: memcpy(&argReg.Byte1, &EVAL_DOUBLE ( ST ), sizeof(double)); *pmaxSP = __max( *pmaxSP, ((pargd_t)&pnArg->v[0])->SPoff ); break; default: DASSERT(FALSE); break; } break; case mptm68k: case mptmppc: case mptntppc: default: DASSERT(FALSE); } SetReg (&argReg, pCxt, NULL); } else if (!PushUserValue (ST, (pargd_t)&pnArg->v[0], pspReg, pmaxSP)) { pExState->err_num = ERR_PTRACE; return (FALSE); } } PopStack (); return (TRUE); } /** PushRef - push referenced value onto stack * fSuccess = PushRef (pv, spReg, reftype, Is32); * Entry pv = value * spReg = pointer to sp register structure * reftype = type of the reference * Exit string pushed onto user stack * SP register structure updated to reflect size of string * Returns TRUE if return value stored without error * FALSE if error during store */ bool_t PushRef (peval_t pv, SHREG *spReg, CV_typ_t reftype, BOOL Is32) { uint cbVal; bool_t retval = TRUE; uint fudgePad = Is32 ? 3 : 1; CV_typ_t lvalueCastType = Is32 ? T_32NCVPTR : T_FCVPTR; Unreferenced( reftype ); switch (EVAL_STATE (pv)) { case EV_lvalue: // for an lvalue, change the node to a reference to the lvalue EVAL_PTR (pv) = EVAL_SYM (pv); CastNode (pv, lvalueCastType, lvalueCastType); break; case EV_rvalue: case EV_constant: cbVal = ((uint)TypeSize (pv) + fudgePad ) & ~fudgePad; // decrement stack pointer to allocate room for string spReg->Byte4 -= (ushort) cbVal; // get current SS value and set symbol address to SS:SP EVAL_SYM_SEG (pv) = GetSegmentRegister(pExState->hframe, REG_SS); //M00FLAT32 EVAL_SYM_OFF (pv) = spReg->Byte4; EVAL_STATE (pv) = EV_lvalue; ADDR_IS_LI (EVAL_SYM (pv)) = FALSE; retval = (PutDebuggeeBytes (EVAL_SYM (pv), cbVal, EVAL_PVAL (pv), EVAL_TYP(pv)) == cbVal); EVAL_PTR (pv) = EVAL_SYM (pv); if (retval == FALSE) { pExState->err_num = ERR_PTRACE; } break; default: DASSERT (FALSE); retval = FALSE; break; } return (retval); } /** IsStringLiteral - check if an evaluation node represents a string literal * flag = IsStringLiteral (pv); * Entry pv = pointer to evaluation node * Exit none * Returns TRUE if pv represents a string literal ("..." or L"...") * FALSE otherwise */ bool_t FASTCALL IsStringLiteral (peval_t pv) { char *pb; CV_typ_t typ = EVAL_TYP (pv); if (CV_MODE(typ) != CV_TM_DIRECT && ((typ = CV_NEWMODE(typ, CV_TM_DIRECT)) == T_RCHAR || typ == T_WCHAR)) { pb = pExStr + EVAL_ITOK (pv); if (*pb == 'L') { pb++; } if (*pb == '"') { return TRUE; } } return FALSE; } /** PushString - push constant string onto stack * fSuccess = PushString (pv, spReg, typArg, Is32); * Entry pv = value describing string * spReg = pointer to sp register structure * typArg = type of resultant pointer node * is32 = is function 32 bit? * Exit string pushed onto user stack * SP register structure updated to reflect size of string * Returns TRUE if return value stored without error * FALSE if error during store */ bool_t PushString (peval_t pv, SHREG *spReg, CV_typ_t typArg, BOOL Is32) { char *pb; char *pbEnd; uint cbVal; bool_t errcnt = 0; bool_t fWide; ulong zero = 0; ulong FillCnt; ushort ch; OFF32 spSave; uint fudgePad = Is32 ? 3 : 1; static int weirdMap[4] = {4, 3, 2, 5}; // compute location and length of string note that pointer points to // initial " or L" of string and the length includes the initial ' or // L" and the ending ". The byte count must be rounded to even parity // because of restrictions on the stack. If the string is a wide // character string, then the C runtime must be called to translate the // string. pb = pExStr + EVAL_ITOK (pv); pbEnd = pb + EVAL_CBTOK (pv) - 1; if ((fWide = (*pb == 'L')) == TRUE) { // skip wide character leader and compute number of bytes for stack // we add two bytes for forcing a zero termination pb++; cbVal = 2 * (EVAL_CBTOK (pv) - 3); FillCnt = Is32 ? weirdMap[cbVal & ~3] : 2; } else { cbVal = EVAL_CBTOK (pv) - 2; FillCnt = 1 + (~cbVal & fudgePad); } DASSERT (((cbVal + FillCnt) & fudgePad) == 0); DASSERT (*pb == '"'); pb++; // decrement stack pointer to allocate room for string. We know that // the string actually pushed can be no longer than cbVal + FillCnt. // It can be shorter because of escaped characters such as \n and \001 spReg->Byte4 -= (ushort) (cbVal + FillCnt); spSave = spReg->Byte4; SetNodeType (pv, typArg); // get current SS value and set symbol address to SS:SP EVAL_SYM_SEG (pv) = GetSegmentRegister(pExState->hframe, REG_SS);; EVAL_SYM_OFF (pv) = spReg->Byte4; EVAL_SYM_IS32 (pv) = (BYTE) Is32; ADDR_IS_LI (EVAL_SYM (pv)) = FALSE; EVAL_STATE (pv) = EV_lvalue; if (fWide == FALSE) { // move characters one at a time onto the user's stack, converting // while moving. while (pb < pbEnd) { if ((ch = *pb++) == '\\') { ulong cbChar; GetEscapedChar (&pb, &cbChar, &ch); } if (PutDebuggeeBytes (EVAL_SYM (pv), sizeof (char), &ch, T_RCHAR) != sizeof (char)) { errcnt++; } EVAL_SYM_OFF (pv) += sizeof (char); } } else { // M00BUG - this is a fake routine until the runtime routines are // M00BUG - available to do the correct translation. We will also // M00BUG - need to get the locale state from the user's space for // M00BUG - for the translation while (pb < pbEnd) { ch = *pb++; // move wide characters onto the user's stack if (PutDebuggeeBytes (EVAL_SYM (pv), 2, &ch, T_WCHAR) != 2) { errcnt++; } EVAL_SYM_OFF (pv) += 2 * sizeof (char); } } if (PutDebuggeeBytes (EVAL_SYM (pv), FillCnt, &zero, (CV_typ_t)(fWide ? T_WCHAR : T_RCHAR)) != FillCnt) { errcnt++; } EVAL_SYM_OFF (pv) = spSave; EVAL_PTR (pv) = EVAL_SYM (pv); if (errcnt != 0) { pExState->err_num = ERR_PTRACE; return (FALSE); } return (TRUE); } /** StoreC - store return value for 16 bit C call * fSuccess = StoreC (pvF); * Entry pvF = pointer to function descriptor * Exit return value stored in ST * Returns TRUE if return value stored without error * FALSE if error during store */ bool_t StoreC (peval_t pvF) { SHREG argReg; ulong len; Unreferenced( pvF ); if (EVAL_IS_PTR (ST)) { argReg.hReg = ((CV_REG_DX << 8) | CV_REG_AX); GetReg (&argReg, pCxt, NULL); EVAL_PTR_OFF (ST) = argReg.Byte2; EVAL_USHORT (ST) = argReg.Byte2; if (EVAL_VALLEN (ST) > 2) { EVAL_PTR_SEG (ST) = argReg.Byte2High; } if (EVAL_IS_NPTR (ST) || EVAL_IS_NPTR32 (ST)) { // for near pointer, pointer DS:AX EVAL_PTR_SEG (ST) = GetSegmentRegister(pExState->hframe, REG_DS); //M00FLAT32 } } else if (EVAL_TYP (ST) == T_REAL80) { // return value is long double, read value from the coprocessor // stack and cast to proper size argReg.hReg = CV_REG_ST0; GetReg (&argReg, pCxt, NULL); EVAL_LDOUBLE (ST) = argReg.Byte10; if (EVAL_TYP (ST) == T_REAL64 ) { EVAL_DOUBLE (ST) = DoubleFromFloat10 (EVAL_LDOUBLE (ST)); } else if (EVAL_TYP (ST) == T_REAL32) { EVAL_FLOAT (ST) = FloatFromFloat10 (EVAL_LDOUBLE (ST)); } } else if (CV_TYPE (EVAL_TYP (ST)) == CV_REAL) { // read real return value from the value pointed to by either // DS:AX (near) or DX:AX (far) argReg.hReg = CV_REG_AX; GetReg (&argReg, pCxt, NULL); EVAL_SYM_OFF (ST) = argReg.Byte2; argReg.hReg = CV_REG_DS; GetReg (&argReg, pCxt, NULL); EVAL_SYM_SEG (ST) = argReg.Byte2; ADDR_IS_LI (EVAL_SYM (ST)) = FALSE; if (GetDebuggeeBytes (EVAL_SYM (ST), EVAL_VALLEN (ST), (char *)&EVAL_DOUBLE (ST), EVAL_TYP(ST)) != EVAL_VALLEN (ST)) { pExState->err_num = ERR_PTRACE; return (FALSE); } if (EVAL_TYP (ST) == T_REAL32) { CastNode (ST, T_REAL64, T_REAL64); } } else if ((EVAL_TYP (ST) == T_CHAR) || (EVAL_TYP (ST) == T_RCHAR)) { argReg.hReg = CV_REG_AL; GetReg (&argReg, pCxt, NULL); EVAL_SHORT (ST) = argReg.Byte1; } else if (EVAL_TYP (ST) == T_UCHAR) { argReg.hReg = CV_REG_AL; GetReg (&argReg, pCxt, NULL); EVAL_USHORT (ST) = argReg.Byte1; } else { len = EVAL_VALLEN (ST); argReg.hReg = ((CV_REG_DX << 8) | CV_REG_AX); GetReg (&argReg, pCxt, NULL); if (CV_IS_PRIMITIVE (EVAL_TYP (ST)) || (EVAL_IS_CLASS (ST) && (len < 4) && (len != 3))) { EVAL_USHORT (ST) = argReg.Byte2; if (len > 2) { *(((ushort *)&(EVAL_ULONG (ST))) + 1) = argReg.Byte2High; } } else { // treat (DS)DX:AX as the pointer to the return value EVAL_SYM_OFF (ST) = argReg.Byte2; argReg.hReg = CV_REG_DS; GetReg (&argReg, pCxt, NULL); EVAL_SYM_SEG (ST) = argReg.Byte2; ADDR_IS_LI (EVAL_SYM (ST)) = FALSE; if (GetDebuggeeBytes (EVAL_SYM (ST), EVAL_VALLEN (ST), (char *)&EVAL_VAL (ST), EVAL_TYP(ST)) != EVAL_VALLEN (ST)) { pExState->err_num = ERR_PTRACE; return (FALSE); } } } return (TRUE); } /** StoreF - store return value for 16 bit fast call * fSuccess = StoreF (); * Entry ST pointer to eval describing return value * Exit return value stored * Returns TRUE if return value stored without error * FALSE if error during store */ bool_t StoreF (void) { SHREG argReg; if (EVAL_IS_PTR (ST)) { argReg.hReg = ((CV_REG_DX << 8) | CV_REG_AX); GetReg (&argReg, pCxt, NULL); EVAL_PTR_OFF (ST) = argReg.Byte2; if (EVAL_VALLEN (ST) > 2) { EVAL_PTR_SEG (ST) = argReg.Byte2High; } if (EVAL_IS_NPTR (ST) || EVAL_IS_NPTR32 (ST)) { // for near pointer, pointer DS:AX EVAL_PTR_SEG (ST) = GetSegmentRegister(pExState->hframe, REG_DS); //M00FLAT32 } } else if (CV_IS_PRIMITIVE (EVAL_TYP(ST)) && (CV_TYPE (EVAL_TYP (ST)) == CV_REAL)) { // return value is real, read value from the coprocessor // stack and cast to proper size argReg.hReg = CV_REG_ST0; GetReg (&argReg, pCxt, NULL); EVAL_LDOUBLE (ST) = argReg.Byte10; if (EVAL_TYP (ST) == T_REAL64) { EVAL_DOUBLE (ST) = DoubleFromFloat10 (EVAL_LDOUBLE (ST)); } else if (EVAL_TYP (ST) == T_REAL32) { EVAL_FLOAT (ST) = FloatFromFloat10 (EVAL_LDOUBLE (ST)); } } else if ((EVAL_TYP (ST) == T_CHAR) || (EVAL_TYP (ST) == T_RCHAR)) { argReg.hReg = CV_REG_AL; GetReg (&argReg, pCxt, NULL); EVAL_SHORT (ST) = argReg.Byte1; } else if (EVAL_TYP (ST) == T_UCHAR) { argReg.hReg = CV_REG_AL; GetReg (&argReg, pCxt, NULL); EVAL_USHORT (ST) = argReg.Byte1; } else { argReg.hReg = ((CV_REG_DX << 8) | CV_REG_AX); GetReg (&argReg, pCxt, NULL); EVAL_USHORT (ST) = argReg.Byte2; if (EVAL_VALLEN (ST) > 2) { *(((ushort *)&(EVAL_ULONG (ST))) + 1) = argReg.Byte2High; } } return (TRUE); } /** StoreP - store return value for pascal call * fSuccess = StoreP (); * Entry ST = pointer to node describing return value * Exit return value stored * Returns TRUE if return value stored without error * FALSE if error during store */ bool_t StoreP () { SHREG argReg; if (EVAL_IS_PTR (ST)) { argReg.hReg = ((CV_REG_DX << 8) | CV_REG_AX); GetReg (&argReg, pCxt, NULL); EVAL_PTR_OFF (ST) = argReg.Byte2; if (EVAL_VALLEN (ST) > 2) { EVAL_PTR_SEG (ST) = argReg.Byte2High; } if (EVAL_IS_NPTR (ST) || EVAL_IS_NPTR32 (ST)) { // for near pointer, pointer DS:AX EVAL_PTR_SEG (ST) = GetSegmentRegister(pExState->hframe, REG_DS); //M00FLAT32 } } else if (CV_TYPE (EVAL_TYP (ST)) == CV_REAL) { // read real return value from the value pointed to by either // DS:AX (near) or DX:AX (far) if (EVAL_IS_NFCN (ST)) { // for near return, pointer to return variable is DS:AX argReg.hReg = (CV_REG_DS << 8) | CV_REG_AX; } else { // for far return, pointer to return variable is DX:AX argReg.hReg = ((CV_REG_DX << 8) | CV_REG_AX); } GetReg (&argReg, pCxt, NULL); // M00FLAT32 EVAL_SYM_SEG (ST) = argReg.Byte2High; EVAL_SYM_OFF (ST) = argReg.Byte2; ADDR_IS_LI (EVAL_SYM (ST)) = FALSE; if (GetDebuggeeBytes (EVAL_SYM (ST), EVAL_VALLEN (ST), (char *)&EVAL_DOUBLE (ST), EVAL_TYP(ST)) != EVAL_VALLEN (ST)) { pExState->err_num = ERR_PTRACE; return (FALSE); } if (EVAL_TYP (ST) == T_REAL32) { CastNode (ST, T_REAL64, T_REAL64); } } else if ((EVAL_TYP (ST) == T_CHAR) || (EVAL_TYP (ST) == T_RCHAR)) { argReg.hReg = CV_REG_AL; GetReg (&argReg, pCxt, NULL); EVAL_SHORT (ST) = argReg.Byte1; } else if (EVAL_TYP (ST) == T_UCHAR) { argReg.hReg = CV_REG_AL; GetReg (&argReg, pCxt, NULL); EVAL_USHORT (ST) = argReg.Byte1; } else { argReg.hReg = ((CV_REG_DX << 8) | CV_REG_AX); GetReg (&argReg, pCxt, NULL); EVAL_USHORT (ST) = argReg.Byte2; if (EVAL_VALLEN (ST) > 2) { *(((ushort *)&(EVAL_ULONG (ST))) + 1) = argReg.Byte2High; } if (EVAL_IS_PTR (ST) && (EVAL_IS_NPTR (ST) || EVAL_IS_NPTR32(ST))) { // for near pointer, pointer DS:AX EVAL_PTR_SEG (ST) = GetSegmentRegister(pExState->hframe, REG_DS); //M00FLAT32 } } return (TRUE); } /** Store32 - store return value for 32 bit call * fSuccess = Store32 (pvF); * Entry pvF = pointer to function descriptor * Exit return value stored in ST * Returns TRUE if return value stored without error * FALSE if error during store */ bool_t Store32 (peval_t pvF) { SHREG argReg; Unreferenced( pvF ); if (CV_IS_PRIMITIVE (EVAL_TYP (ST)) && CV_TYP_IS_REAL (EVAL_TYP (ST))) { // return value is real, read value from the coprocessor // stack and cast to proper size argReg.hReg = CV_REG_ST0; GetReg (&argReg, pCxt, NULL); switch (EVAL_TYP (ST)) { case T_REAL32: EVAL_FLOAT (ST) = FloatFromFloat10 (argReg.Byte10); return (TRUE); case T_REAL48: case T_REAL64: EVAL_DOUBLE (ST) = DoubleFromFloat10 (argReg.Byte10); return (TRUE); case T_REAL80: EVAL_LDOUBLE (ST) = argReg.Byte10; return (TRUE); default: pExState->err_num = ERR_INTERNAL; return (FALSE); } } if (EVAL_IS_CLASS (ST)) { // treat EAX as the pointer to the return value argReg.hReg = CV_REG_EAX; GetReg (&argReg, pCxt, NULL); EVAL_SYM_OFF (ST) = argReg.Byte4; EVAL_SYM_SEG (ST) = GetSegmentRegister(pExState->hframe, REG_DS); ADDR_IS_LI (EVAL_SYM (ST)) = FALSE; if (GetDebuggeeBytes (EVAL_SYM (ST), EVAL_VALLEN (ST), (char *)&EVAL_VAL (ST), EVAL_TYP(ST)) != EVAL_VALLEN (ST)) { pExState->err_num = ERR_PTRACE; return (FALSE); } return (TRUE); } if (EVAL_IS_PTR (ST)) { argReg.hReg = CV_REG_EAX; GetReg (&argReg, pCxt, NULL); EVAL_PTR_OFF (ST) = argReg.Byte4; EVAL_PTR_SEG (ST) = GetSegmentRegister(pExState->hframe, REG_DS); ADDR_IS_LI (EVAL_PTR (ST)) = FALSE; return (TRUE); } switch (EVAL_VALLEN (ST)) { case 1: argReg.hReg = CV_REG_AL; GetReg (&argReg, pCxt, NULL); EVAL_CHAR (ST) = argReg.Byte1; break; case 2: argReg.hReg = CV_REG_AX; GetReg (&argReg, pCxt, NULL); EVAL_SHORT (ST) = argReg.Byte2; break; case 4: argReg.hReg = CV_REG_EAX; GetReg (&argReg, pCxt, NULL); EVAL_LONG (ST) = argReg.Byte4; break; case 8: argReg.hReg = CV_REG_EDX; GetReg (&argReg, pCxt, NULL); EVAL_UQUAD (ST) = (UQUAD) argReg.Byte4 << 32; argReg.hReg = CV_REG_EAX; GetReg (&argReg, pCxt, NULL); EVAL_UQUAD (ST) |= argReg.Byte4; break; default: pExState->err_num = ERR_INTERNAL; return (FALSE); } return (TRUE); } /** StoreMips - store return value for Mips call * fSuccess = StoreMips (pvF); * Entry pvF = pointer to function descriptor * Exit return value stored in ST * Returns TRUE if return value stored without error * FALSE if error during store */ bool_t PASCAL StoreMips ( peval_t pvF) { SHREG argReg; ulong len; Unreferenced( pvF ); DASSERT( EVAL_TYP(ST) != T_REAL80 ); // Floating point values are returned in f0 (Real) or f0:f1 (float) if ((EVAL_TYP (ST) == T_REAL32) || (EVAL_TYP (ST) == T_REAL64) ) { argReg.hReg = (CV_M4_FltF1 << 8) | CV_M4_FltF0; GetReg ( &argReg, pCxt, NULL ); if (EVAL_TYP (ST) == T_REAL32) { EVAL_FLOAT(ST) = *((float *) &argReg.Byte4); } else { EVAL_DOUBLE(ST) = *((double *) &argReg.Byte4); } } else if ((EVAL_TYP (ST) == T_CHAR) || (EVAL_TYP (ST) == T_RCHAR)) { argReg.hReg = CV_M4_IntV0; GetReg( &argReg, pCxt, NULL ); EVAL_SHORT( ST ) = argReg.Byte1; } else if (EVAL_TYP (ST) == T_UCHAR) { argReg.hReg = CV_M4_IntV0; GetReg( &argReg, pCxt, NULL ); EVAL_USHORT( ST ) = argReg.Byte1; } else if (EVAL_IS_PTR (ST)) { DASSERT( EVAL_IS_NPTR32(ST) ); argReg.hReg = CV_M4_IntV0; GetReg( &argReg, pCxt, NULL ); EVAL_PTR_OFF (ST) = argReg.Byte4; EVAL_ULONG (ST) = argReg.Byte4; EVAL_PTR_SEG (ST) = 0; ADDR_IS_FLAT( EVAL_PTR (ST)) = TRUE; ADDR_IS_OFF32( EVAL_PTR (ST)) = TRUE; ADDR_IS_REAL( EVAL_PTR( ST)) = FALSE; ADDR_IS_LI( EVAL_PTR (ST)) = FALSE; } else { len = EVAL_VALLEN(ST); argReg.hReg = CV_M4_IntV0; if (len == 8 && CV_IS_PRIMITIVE (EVAL_TYP (ST))) { argReg.hReg = (CV_M4_IntV1<<8) | CV_M4_IntV0; } GetReg( &argReg, pCxt, NULL ); // Check for primitive lengths if (CV_IS_PRIMITIVE (EVAL_TYP (ST)) || (EVAL_IS_CLASS (ST) && (len < 4) && (len != 3))) { if (len <= 2) { EVAL_USHORT(ST) = argReg.Byte2; } else if (len < 8) { EVAL_ULONG (ST) = argReg.Byte4; } else { EVAL_UQUAD (ST) = (argReg.Byte4High << 32i64) | argReg.Byte4; } } else { EVAL_SYM_OFF (ST) = argReg.Byte4; EVAL_SYM_SEG (ST) = 0; ADDR_IS_FLAT( EVAL_SYM (ST)) = TRUE; ADDR_IS_OFF32( EVAL_SYM (ST)) = TRUE; ADDR_IS_LI( EVAL_SYM (ST)) = FALSE; if (GetDebuggeeBytes(EVAL_SYM(ST), EVAL_VALLEN(ST), (char *)&EVAL_VAL(ST), EVAL_TYP(ST)) != (UINT)EVAL_VALLEN(ST)) { pExState->err_num = ERR_PTRACE; return FALSE; } } } return (TRUE); } /** StoreAlpha - store return value for Alpha call * fSuccess = StoreAlpha (pvF); * Entry pvF = pointer to function descriptor * Exit return value stored in ST * Returns TRUE if return value stored without error * FALSE if error during store */ bool_t PASCAL StoreAlpha ( peval_t pvF ) { SHREG argReg; ulong len; Unreferenced( pvF ); DASSERT( EVAL_TYP(ST) != T_REAL80 ); if (CV_TYP_IS_REAL (EVAL_TYP (ST) ) ) { union { float f; double d; unsigned long l[2]; } u; // Floating point values are returned in F0; argReg.hReg = CV_ALPHA_FltF0; GetReg( &argReg, pCxt, NULL); // The SHREG is unaligned; this compiler can only do aligned // loads and stores of floating points. u.l[0] = argReg.Byte4; u.l[1] = argReg.Byte4High; if (EVAL_TYP (ST) == T_REAL64) { EVAL_DOUBLE(ST) = u.d; return (TRUE); } if (EVAL_TYP (ST) == T_REAL32) { // This does the conversion from double to Single u.f = (float) u.d; EVAL_FLOAT(ST) = u.f; return (TRUE); } } // All other values are returned in IntV0 (r0) argReg.hReg = CV_ALPHA_IntV0; GetReg( &argReg, pCxt, NULL); switch (EVAL_TYP (ST) ) { case T_CHAR: case T_RCHAR: EVAL_SHORT(ST) = argReg.Byte1; return (TRUE); break; case T_UCHAR: EVAL_USHORT(ST) = argReg.Byte1; return (TRUE); break; } if (EVAL_IS_PTR (ST)) { DASSERT( EVAL_IS_NPTR32(ST) ); EVAL_PTR_OFF (ST) = argReg.Byte4; EVAL_ULONG (ST) = argReg.Byte4; EVAL_PTR_SEG (ST) = 0; ADDR_IS_FLAT( EVAL_PTR (ST)) = TRUE; ADDR_IS_OFF32( EVAL_PTR (ST)) = TRUE; // ADDR_IS_REAL( EVAL_PTR( ST)) = FALSE; ADDR_IS_LI( EVAL_PTR (ST)) = FALSE; } else { len = EVAL_VALLEN(ST); // Check for primitive lengths #pragma message ("Add __int64 return values for ALPHA") if (CV_IS_PRIMITIVE (EVAL_TYP (ST)) || (EVAL_IS_CLASS (ST) && (len <= 4) && (len != 3))) { if (len <= 2) { EVAL_USHORT(ST) = argReg.Byte2; } else { EVAL_ULONG (ST) = argReg.Byte4; } } else { EVAL_SYM_OFF (ST) = argReg.Byte4; EVAL_SYM_SEG (ST) = 0; // ADDR_IS_FLAT( EVAL_SYM (ST)) = TRUE; // ADDR_IS_OFF32( EVAL_SYM (ST)) = TRUE; ADDR_IS_LI( EVAL_SYM (ST)) = FALSE; if (GetDebuggeeBytes(EVAL_SYM(ST), EVAL_VALLEN(ST), (char *)&EVAL_VAL(ST), EVAL_TYP(ST)) != (UINT)EVAL_VALLEN(ST)) { pExState->err_num = ERR_PTRACE; return FALSE; } } } return (TRUE); } /** StorePPC - store return value for PPC call * fSuccess = StorePPC (pvF); * Entry pvF = pointer to function descriptor * Exit return value stored in ST * Returns TRUE if return value stored without error * FALSE if error during store */ bool_t PASCAL StorePPC ( peval_t pvF ) { SHREG argReg; ulong len; Unreferenced( pvF ); DASSERT( EVAL_TYP(ST) != T_REAL80 ); /* * Floating point values are returned in FPR1 */ if ((EVAL_TYP (ST) == T_REAL32) || (EVAL_TYP (ST) == T_REAL64) ) { argReg.hReg = (CV_PPC_FPR1); GetReg( &argReg, pCxt, NULL); if (EVAL_TYP (ST) == T_REAL32) { EVAL_FLOAT(ST) = (float) argReg.Byte8; } else { EVAL_DOUBLE(ST) = *((double *) &argReg.Byte4); } } else if ((EVAL_TYP (ST) == T_CHAR) || (EVAL_TYP (ST) == T_RCHAR)) { argReg.hReg = CV_PPC_GPR3; GetReg( &argReg, pCxt, NULL); EVAL_SHORT( ST ) = argReg.Byte1; } else if (EVAL_TYP (ST) == T_UCHAR) { argReg.hReg = CV_PPC_GPR3; GetReg( &argReg, pCxt, NULL); EVAL_USHORT( ST ) = argReg.Byte1; } else if (EVAL_IS_PTR (ST)) { DASSERT( EVAL_IS_NPTR32(ST) ); argReg.hReg = CV_PPC_GPR3; GetReg( &argReg, pCxt, NULL); EVAL_PTR_OFF (ST) = argReg.Byte4; EVAL_ULONG (ST) = argReg.Byte4; EVAL_PTR_SEG (ST) = 0; ADDR_IS_FLAT( EVAL_PTR (ST)) = TRUE; ADDR_IS_OFF32( EVAL_PTR (ST)) = TRUE; ADDR_IS_REAL( EVAL_PTR( ST)) = FALSE; ADDR_IS_LI( EVAL_PTR (ST)) = FALSE; } else { len = EVAL_VALLEN(ST); argReg.hReg = CV_PPC_GPR3; GetReg( &argReg, pCxt, NULL); /* * Check for primitive lengths */ if (CV_IS_PRIMITIVE (EVAL_TYP (ST)) || (EVAL_IS_CLASS (ST) && (len < 4) && (len != 3))) { if (len <= 2) { EVAL_USHORT(ST) = argReg.Byte2; } else { EVAL_ULONG (ST) = argReg.Byte4; } } else { EVAL_SYM_OFF (ST) = argReg.Byte4; EVAL_SYM_SEG (ST) = 0; ADDR_IS_FLAT( EVAL_SYM (ST)) = TRUE; ADDR_IS_OFF32( EVAL_SYM (ST)) = TRUE; ADDR_IS_LI( EVAL_SYM (ST)) = FALSE; if (GetDebuggeeBytes(EVAL_SYM(ST), EVAL_VALLEN(ST), (char *)&EVAL_VAL(ST), EVAL_TYP(ST)) != (UINT)EVAL_VALLEN(ST)) { pExState->err_num = ERR_PTRACE; return FALSE; } } } return (TRUE); } /* StorePPC() */ /** StoreIa64 - store return value for IA64 call * fSuccess = StoreIA64 (pvF); * Entry pvF = pointer to function descriptor * Exit return value stored in ST * Returns TRUE if return value stored without error * FALSE if error during store */ LOCAL bool_t NEAR PASCAL StoreIa64 ( peval_t pvF) { SHREG argReg; ulong len; Unreferenced( pvF ); DASSERT( EVAL_TYP(ST) != T_REAL80 ); if (CV_TYP_IS_REAL ( EVAL_TYP (ST) ) ) { union { float f; double d; unsigned long l[2]; } u; // EM Floating point values are returned in f2 argReg.hReg = CV_IA64_FltS0; GetReg ( &argReg, pCxt , NULL); // The SHREG is unaligned; this compiler can only do aligned // loads and stores of floating points. u.l[0] = argReg.Byte4; u.l[1] = argReg.Byte4High; if (EVAL_TYP (ST) == T_REAL64) { EVAL_DOUBLE(ST) = u.d; return (TRUE); } if (EVAL_TYP (ST) == T_REAL32) { // This does the conversion from double to single u.f = (float)u.d; EVAL_FLOAT (ST) = u.f; return (TRUE); } } // All other values are returned in IntV0 (r0) argReg.hReg = CV_IA64_IntV0; GetReg( &argReg, pCxt, NULL); switch( EVAL_TYP(ST) ) { case T_CHAR: case T_RCHAR: EVAL_SHORT( ST ) = argReg.Byte1; return (TRUE); break; case T_UCHAR: EVAL_USHORT( ST ) = argReg.Byte1; return (TRUE); break; } if (EVAL_IS_PTR (ST)) { DASSERT( EVAL_IS_NPTR32(ST) ); EVAL_PTR_OFF (ST) = argReg.Byte4; EVAL_ULONG (ST) = argReg.Byte4; EVAL_PTR_SEG (ST) = 0; ADDR_IS_OFF32 ( EVAL_PTR (ST)) = TRUE; ADDR_IS_FLAT ( EVAL_PTR (ST)) = TRUE; ADDR_IS_LI( EVAL_PTR (ST)) = FALSE; } else { len = EVAL_VALLEN(ST); // Check for primitive lengths #pragma message ("Add __int64 return value's for IA64") if (CV_IS_PRIMITIVE (EVAL_TYP (ST)) || (EVAL_IS_CLASS (ST) && (len <= 4) && (len != 3))) { if (len <= 2) { EVAL_USHORT(ST) = argReg.Byte2; } else { EVAL_ULONG (ST) = argReg.Byte4; } } else { EVAL_SYM_OFF (ST) = argReg.Byte4; EVAL_SYM_SEG (ST) = 0; ADDR_IS_LI (EVAL_SYM (ST)) = FALSE; if (GetDebuggeeBytes(EVAL_SYM(ST), EVAL_VALLEN(ST), (char *)&EVAL_VAL(ST), EVAL_TYP(ST)) != (UINT)EVAL_VALLEN(ST)) { pExState->err_num = ERR_PTRACE; return FALSE; } } } return (TRUE); } /** PushUserValue - push value onto user stack * fSuccess = PushUserValue (pv, pa, pspReg, pmaxSP) * Entry pv = pointer to value * pa = pointer to argument data describing stack offset * spReg = pointer to register packet for stack pointer * pmaxSP = pointer to location to store maximum SP relative offset * Exit value pushed onto user stack * Returns TRUE if value pushed * FALSE if error in push */ bool_t PushUserValue (peval_t pv, pargd_t pa, SHREG *pspReg, UOFFSET *pmaxSP) { ADDR addrStk = {0}; uint offsize; *pmaxSP = max (*pmaxSP, pa->SPoff); addrStk = EVAL_SYM (pv); addrStk.addr.seg = GetSegmentRegister(pExState->hframe, REG_SS);; addrStk.addr.off = pspReg->Byte4 - pa->SPoff; ADDR_IS_LI (addrStk) = FALSE; if (EVAL_IS_PTR (pv)) { // since pointers are stored strangely, we have to put them // in two pieces. First we store the offset (16 or 32 bits) if (ADDR_IS_LI (EVAL_PTR (pv))) { SHFixupAddr (&EVAL_PTR (pv)); } offsize = modeAddr (EVAL_PTR (pv)).fOff32 ? sizeof (CV_uoff32_t) : sizeof (CV_uoff16_t); if (PutDebuggeeBytes (addrStk, offsize, &EVAL_PTR_OFF (pv), (CV_typ_t)(modeAddr(EVAL_PTR (pv)).fOff32 ? T_ULONG : T_USHORT)) == offsize) { if (EVAL_IS_NPTR (pv) || EVAL_IS_NPTR32 (pv)) { return (TRUE); } else { addrStk.addr.off += offsize; if (PutDebuggeeBytes (addrStk, sizeof (_segment), (char *)&EVAL_PTR_SEG (pv), T_SEGMENT) == sizeof (_segment)) { return (TRUE); } } } } else { if (PutDebuggeeBytes (addrStk, pa->vallen, (char *)&EVAL_VAL (pv), EVAL_TYP(pv)) == pa->vallen) { return (TRUE); } } pExState->err_num = ERR_PTRACE; return (FALSE); } /** PushOffset - push address value for pascal and fastcall * fSuccess = PushOffset (offset, pspReg, pmaxSP, size); * Entry offset = offset from user's SP of return value * pspReg = pointer to register structure for SP * pmaxSP = pointer to location to store maximum SP relative offset * size = size in bytes of value to be pushed * Exit * Returns TRUE if offset pushed * FALSE if error * Note Can be used to push segment also */ bool_t PushOffset (UOFFSET offset, SHREG *pspReg, UOFFSET *pmaxSP, ulong size) { ADDR addrStk = {0}; Unreferenced( size ); *pmaxSP += size; addrStk.addr.seg = GetSegmentRegister(pExState->hframe, REG_SS);; addrStk.addr.off = pspReg->Byte4 - *pmaxSP; //expect a warning for 16 bit if (PutDebuggeeBytes (addrStk, size, (char *)&offset, T_USHORT) == size) { return (TRUE); } else { pExState->err_num = ERR_PTRACE; return (FALSE); } } /*** StructElem - Extract a structure element from stack * fSuccess = StructElem (bn) * Entry bn = based pointer to operator node * ST = address of struct (initial this address) * Exit ST = value node for member * Returns TRUE if successful * FALSE if error */ bool_t FASTCALL StructElem (bnode_t bnOp) { peval_t pvOp; peval_t pvR; bnode_t bnR; char *pS; pvOp = &bnOp->v[0]; bnR = NODE_RCHILD (bnOp); pvR = &bnR->v[0]; if (EVAL_IS_MEMBER (pvOp) == FALSE) { pExState->err_num = ERR_NEEDLVALUE; return (FALSE); } if (EVAL_IS_METHOD (pvR)) { // this is to prevent cascaded function calls // like ?foo().bar() Currently we do not // handle this case --caviar #5425 pExState->err_num = ERR_NOTEVALUATABLE; return (FALSE); } SetNodeType (ST, EVAL_TYP (pvR)); EVAL_VALLEN (ST) = (ulong )TypeSize (ST); pS = (char *)&EVAL_VAL (ST); pS += MEMBER_OFFSET (pvOp); memmove (&EVAL_VAL (ST), pS, EVAL_VALLEN (ST)); return (TRUE); } /*** StructEval - Perform a structure access (., ->, ::, .*, ->*) * fSuccess = StructEval (bn) * Entry bn = based pointer to operator node * ST = address of struct (initial this address) * Exit ST = value node for member * Returns TRUE if successful * FALSE if error */ bool_t FASTCALL StructEval (bnode_t bn) { peval_t pv; peval_t pvR; bnode_t bnR; CV_typ_t typ; bool_t retval; eval_t evalT; peval_t pvT; if (EVAL_IS_REF (ST)) { if (!FetchOp (ST)) { return (FALSE); } EVAL_IS_REF (ST) = FALSE; } // point to the eval_t field of the operator node. This field will // contain the data needed to adjust the this pointer (*ST). For // any structure reference (., ->, ::, .*, ->*), the stack top is // the initial value of the this pointer pv = &bn->v[0]; if ((EVAL_IS_MEMBER (pv) == FALSE) || MEMBER_THISEXPR (pv) == 0) { *pvThis = *ST; } else if (Eval ((bnode_t)MEMBER_THISEXPR (pv)) == FALSE) { return (FALSE); } if ((MEMBER_VBASE (pv) == TRUE) || (MEMBER_IVBASE (pv) == TRUE)) { if (CalcThisExpr (MEMBER_VBPTR (pv), MEMBER_VBPOFF (pv), MEMBER_VBIND (pv), MEMBER_TYPE (pv)) == FALSE) { return (FALSE); } } *ST = *pvThis; if (!OP_IS_IDENT (NODE_OP (NODE_RCHILD (bn)))) { if ((retval = EvalRChild (bn)) == FALSE) { return (FALSE); } } else { bnR = NODE_RCHILD (bn); pvR = &bnR->v[0]; if (EVAL_IS_STMEMBER (pvR) && EVAL_HSYM(pvR) == 0) { // missing static data member pExState->err_num = ERR_STMEMBERNP; return FALSE; } if (EVAL_IS_STMEMBER (pvR) || // if we are looking at a nested enumerate // sps 9/15/92 (EVAL_STATE(pvR) == EV_constant)) { *ST = *pvR; return (TRUE); } else if (EVAL_IS_METHOD (pvR)) { if (FCN_NOTPRESENT(pvR)) { // can't get the address of a function // unless it is present pExState->err_num = ERR_METHODNP; return FALSE; } if ((FCN_PROPERTY (pvR) == CV_MTvirtual) || (FCN_PROPERTY (pvR) == CV_MTintro)) { pvT = &evalT; if (VFuncAddress2 (pvT, pvR) == FALSE) { // we may get here if the object // does not have a valid vfptr // (e.g., if it is not initialized) pExState->err_num = ERR_NOTEVALUATABLE; return (FALSE); } else { *ST = *pvR; EVAL_SYM (ST) = EVAL_PTR (pvT); // dolphin #2223: set EVAL_PTR(ST) // so that FormatNode can display // the function address EVAL_PTR (ST) = EVAL_PTR (pvT); } } else { *ST = *pvR; } return (TRUE); } else { EVAL_SYM_OFF (ST) += MEMBER_OFFSET (pv); typ = EVAL_TYP (pvR); return (SetNodeType (ST, typ)); } } return(TRUE); } /** VFuncAddress - compute virtual function address * fSuccess = VFuncAddress (pv, index) * Entry pv = pointer to pointer node to adjust * index = vtshape table index * pvThis = initial this pointer * Exit pv = adjusted pointer * Returns TRUE if adjustment made * FALSE if error */ INLINE bool_t VFuncAddress (peval_t pv, ulong index) { eval_t evalT; peval_t pvT; plfVTShape pShape; uint desc; ulong i; ulong shape; DTI dti; bool_t fOff32; ADDR addr = {0}; fOff32 = TRUE; pvT = &evalT; *pvT = *pv; SetNodeType (pvT, PTR_UTYPE (pvT)); EVAL_STATE (pvT) = EV_lvalue; if (!EVAL_IS_VTSHAPE (pvT)) { // the only way we should get array referencing on a pointer // is if the pointer is a vfuncptr. DASSERT (FALSE); return (FALSE); } if (!EvalUtil (OP_fetch, pv, NULL, EU_LOAD)) { return (FALSE); } CLEAR_EVAL_FLAGS (pv); #if 0 // We read in the vtable ptr just as a normal 4 byte quantity. // Copy over the offset and create a unfixedup address. ADDRLIN32(addr); // addr has been zero initialized so other fields are just the way // we want them. SE_SetAddrOff(&addr, EVAL_ULONG(pv)); #else addr = EVAL_PTR(pv); #endif SHUnFixupAddr(&addr); EVAL_SYM (pv) = addr; EVAL_STATE (pv) = EV_lvalue; EVAL_IS_ADDR (pv) = TRUE; EVAL_IS_PTR (pv) = TRUE; // now walk down the descriptor list, incrementing the pointer // address by the size of the entry described by the shape table pShape = (plfVTShape)(&((TYPPTR)MHOmfLock (EVAL_TYPDEF (pvT)))->leaf); for (i = 0; i < index; i++) { shape = pShape->desc[i >> 1]; desc = (shape >> ((~i & 1) * 4)) & 0x0f; switch (desc) { case CV_VTS_near: EVAL_SYM_OFF (pv) += sizeof (CV_uoff16_t); break; case CV_VTS_far: EVAL_SYM_OFF (pv) += sizeof (CV_uoff16_t) + sizeof (_segment); break; case CV_VTS_outer: // address point displacement EVAL_SYM_OFF (pv) += sizeof (CV_uoff32_t); break; case CV_VTS_meta: // far pointer to a metaclass descriptor #pragma message ("CAUTION - FLAT 32 specific") EVAL_SYM_OFF (pv) += sizeof (CV_uoff32_t); break; case CV_VTS_near32: EVAL_SYM_OFF (pv) += sizeof (CV_uoff32_t); break; case CV_VTS_far32: EVAL_SYM_OFF (pv) += sizeof (CV_uoff32_t) + sizeof (_segment); break; default: DASSERT (FALSE); MHOmfUnLock (EVAL_TYPDEF (pvT)); return (FALSE); } } shape = pShape->desc[i >> 1]; desc = (shape >> ((~i & 1) * 4)) & 0x0f; MHOmfUnLock (EVAL_TYPDEF (pvT)); switch (desc) { case CV_VTS_near: EVAL_PTRTYPE (pv) = CV_PTR_NEAR; break; case CV_VTS_far: EVAL_PTRTYPE (pv) = CV_PTR_FAR; break; case CV_VTS_outer: // address point displacement EVAL_PTRTYPE (pv) = CV_PTR_NEAR32; break; case CV_VTS_meta: // far pointer to a metaclass descriptor EVAL_PTRTYPE (pv) = CV_PTR_NEAR32; break; case CV_VTS_near32: EVAL_PTRTYPE (pv) = CV_PTR_NEAR32; break; case CV_VTS_far32: EVAL_PTRTYPE (pv) = CV_PTR_FAR32; break; default: return (FALSE); } if (EvalUtil (OP_fetch, pv, NULL, EU_LOAD)) { CLEAR_EVAL_FLAGS (pv); EVAL_IS_ADDR (pv) = TRUE; EVAL_IS_FCN (pv) = TRUE; return (TRUE); } return (FALSE); } /** VFuncAddress2 - compute virtual function address given the function * offset in the vtable * fSuccess = VFuncAddress (pv, pvFunc) * Entry pv = pointer to pointer node to hold the function address * pvFunc = evaluation node of virtual function * pvThis = initial this pointer * Exit pv value is the address of the vfunction * Returns TRUE if adjustment made * FALSE if error */ INLINE bool_t VFuncAddress2 (peval_t pv, peval_t pvFunc) { ADDR addr = {0}; *pv = *pvThis; if (!SetNodeType (pv, FCN_VFPTYPE (pvFunc)) || !EvalUtil (OP_fetch, pv, NULL, EU_LOAD)) { return (FALSE); } CLEAR_EVAL_FLAGS (pv); // We read in the vtable ptr just as a normal 4 byte quantity. // We need to use that to compose the actual address. ADDRLIN32(addr); // We have a physical address. SE_SetAddrOff(&addr, EVAL_ULONG(pv)); SHUnFixupAddr(&addr); EVAL_SYM (pv) = addr; EVAL_STATE (pv) = EV_lvalue; EVAL_IS_ADDR (pv) = TRUE; EVAL_IS_PTR (pv) = TRUE; // adjust offset in the vtable, // set size of function pointer, and load pointer value EVAL_SYM_OFF (pv) += FCN_VTABIND(pvFunc); if (FCN_FARCALL(pvFunc)) { EVAL_PTRTYPE (pv) = CV_PTR_FAR; } else { EVAL_PTRTYPE (pv) = pExState->state.f32bit ? CV_PTR_NEAR32 : CV_PTR_NEAR; } if (EvalUtil (OP_fetch, pv, NULL, EU_LOAD)) { CLEAR_EVAL_FLAGS (pv); EVAL_IS_ADDR (pv) = TRUE; EVAL_IS_FCN (pv) = TRUE; return (TRUE); } return (FALSE); } INLINE ULONG MakeLong (USHORT lo, USHORT hi) { return (ULONG)hi << 16 | lo; } INLINE USHORT LoWord (ULONG l) { return (USHORT) (l & 0xffffL); } INLINE USHORT HiWord (ULONG l) { return (USHORT) (l >> 16 & 0xffffL); } INLINE BOOL getFuncAddrNoThunks (peval_t pv) { ulong saveState = EVAL_STATE(pv); // look real address of a function - that is we will attempt to recognize thunks // and skip them to get to the real address of the functions - the address of the // function will be return in the EVAL_SYM of the incoming pv //BUGBUG: I think this should be if (TargetMachine == mptx86) #if (_MSC_VER >= 800) && defined(_M_IX86) && (_M_IX86 >= 300) eval_t evalTmp; peval_t pvTmp = &evalTmp; // fetch the contents of the purported address of the function, if we find a // unconditional jump, we may assume that we are looking at a thunk. keep // looking until we no longer see a jump while (TRUE) { *pvTmp = *pv; EVAL_STATE(pvTmp) = EV_lvalue; // fetch opcode byte if (!SetNodeType (pvTmp, T_UCHAR) || !EvalUtil (OP_fetch, pvTmp, NULL, EU_LOAD)) { return (FALSE); } #define JMP32 ((char) 0xe9) if (EVAL_CHAR(pvTmp) == JMP32) { SHREG regCS; // fetch next four bytes of jump as relative offset EVAL_SYM_OFF(pvTmp)++; EVAL_STATE(pvTmp) = EV_lvalue; if (!SetNodeType (pvTmp, T_ULONG) || !EvalUtil (OP_fetch, pvTmp, NULL, EU_LOAD)) { return (FALSE); } SHFixupAddr(&EVAL_SYM(pvTmp)); EVAL_SYM_OFF(pv) = EVAL_SYM_OFF(pvTmp) + EVAL_ULONG(pvTmp) + 4; regCS.hReg = CV_REG_CS; GetReg (®CS, pCxt, NULL); EVAL_SYM_SEG (pv) = regCS.Byte2; ADDR_IS_FLAT(EVAL_SYM(pv)) = TRUE; ADDR_IS_OFF32(EVAL_SYM(pv)) = TRUE; ADDR_IS_LI(EVAL_SYM(pv)) = FALSE; SHUnFixupAddr(&EVAL_SYM(pv)); EVAL_STATE(pv) = EV_lvalue; } else { EVAL_STATE(pv) = saveState; return TRUE; } } #else return TRUE; #endif }