/*** debsup.c - debapi support routines. * The routines in this module can only be called from debapi.c. */ #include "debexpr.h" #include "debsym.h" #define WINDBG_POINTERS_MACROS_ONLY #include "sundown.h" #undef WINDBG_POINTERS_MACROS_ONLY EESTATUS CountClassElem (HTM, peval_t, long *, ulong ); EESTATUS GetClassiChild (HTM, long, uint, PHTM, ulong *, SHFLAG); ulong SetFcniParm (peval_t, long, PEEHSTR); bool_t QChildFcnBind (HTM, peval_t, peval_t, EEHSTR); bool_t UndecorateScope(char *, char far *, uint); op_t StartNodeOp (HTM); void LShiftCxtString (EEHSTR); BOOL fNotPresent (HTM); EESTATUS BindStMember (HTM, const char *, PHTM, ulong *, SHFLAG); static char *pExStrP; /** AreTypesEqual - are TM types equal * flag = AreTypesEqual (hTMLeft, hTMRight); * Entry hTMLeft = handle of left TM * hTMRight = handle of right TM * Exit none * Returns TRUE if TMs have identical types */ bool_t AreTypesEqual ( HTM hTMLeft, HTM hTMRight ) { bool_t retval = FALSE; pexstate_t pExLeft; pexstate_t pExRight; if ((hTMLeft != 0) && (hTMRight != 0)) { pExLeft = (pexstate_t) MemLock (hTMLeft); pExRight = (pexstate_t) MemLock (hTMRight); #if CC_LAZYTYPES if (THAreTypesEqual( EVAL_MOD(&pExLeft->result), EVAL_TYP(&pExLeft->result), EVAL_TYP(&pExRight->result) ) ) #else if (EVAL_TYP(&pExLeft->result) == EVAL_TYP (&pExRight->result)) #endif { retval = TRUE; } MemUnLock (hTMLeft); MemUnLock (hTMRight); } return (retval); } /** cChildrenTM - return number of children for the TM * flag = cChildrenTM (phTM, pcChildren, pVar) * Entry phTM = pointer to handle of TM * pcChildren = pointer to location to store count * Exit *pcChildren = number of children for TM * Returns EENOERROR if no error * non-zero if error */ ulong cChildrenTM ( PHTM phTM, long *pcChildren, PSHFLAG pVar ) { ulong retval = EENOERROR; eval_t eval; peval_t pv = &eval; long len; DASSERT (*phTM != 0); *pVar = FALSE; *pcChildren = 0; if (*phTM == 0) { return (EECATASTROPHIC); } pExState = (pexstate_t) MemLock (*phTM); pCxt = &pExState->cxt; // The kernel may call EEcChildrenTM several times for the // same TM. Since the cost of EEcChildrenTM is pretty high now // due to the potential bindings of static members, it pays // to cache the number of children in the TM. if (pExState->state.cChildren_ok) { *pcChildren = pExState->cChildren; } else if (pExState->state.bind_ok == TRUE) { eval = pExState->result; if (EVAL_IS_REF (pv)) { RemoveIndir (pv); } pExState->err_num = 0; if (!CV_IS_PRIMITIVE (EVAL_TYP (pv))) { if (EVAL_IS_CLASS (pv)) { retval = CountClassElem (*phTM, pv, pcChildren, (ulong ) ((EVAL_STATE (pv) == EV_type)? CLS_defn: CLS_data)); } else if (EVAL_IS_ARRAY (pv) && (PTR_ARRAYLEN (pv) != 0)) { // Otherwise, the number of elements is the sizeof the // array divided by the size of the underlying type len = PTR_ARRAYLEN (pv); if(!SetNodeType (pv, PTR_UTYPE (pv))){ MemUnLock (*phTM); pExState->err_num = ERR_NOTEXPANDABLE; return (EEGENERAL); } *pcChildren = len / TypeSize (pv); } else if (EVAL_IS_ARRAY (pv) && (PTR_ARRAYLEN (pv) == 0)) { // if an array is undimensioned in the source then we // do not guess how many elements it really has. *pcChildren = 0; *pVar = TRUE; } else if (EVAL_IS_PTR (pv)) { SetNodeType (pv, PTR_UTYPE (pv)); if (EVAL_IS_VTSHAPE (pv)) { *pcChildren = VTSHAPE_COUNT (pv); } else { *pcChildren = 1; } } else { pExState->err_num = ERR_INTERNAL; retval = EEGENERAL; } } else if (EVAL_IS_PTR (pv)) { *pcChildren = 1; } pExState->cChildren = *pcChildren; pExState->state.cChildren_ok = TRUE; } else { pExState->err_num = ERR_NOTEVALUATABLE; retval = EEGENERAL; } MemUnLock (*phTM); return (retval); } /** cSynthChildTM - return number of synthesized children for the TM * flag = cSynthChildTM (phTM, pcChildren) * Entry phTM = pointer to handle of TM * pcChildren = pointer to location to store count * Exit *pcChildren = number of children for TM * Returns EENOERROR if no error * non-zero if error */ ulong cSynthChildTM( PHTM phTM, long * pcChildren ) { ulong retval = EENOERROR; *pcChildren = 0; DASSERT(*phTM != 0); if ( *phTM == 0 ) { return EECATASTROPHIC; } pExState = (pexstate_t) MemLock ( *phTM ); if ( pExState->state.bind_ok == TRUE) { if (pExState->hDClassName) { *pcChildren = 1; } } else { pExState->err_num = ERR_INTERNAL; retval = EEGENERAL; } MemUnLock(*phTM); return retval; } /** cParamTM - return count of parameters for TM * ulong cParamTM (phTM, pcParam, pVarArg) * Entry hTM = handle to TM * pcParam = pointer return count * pVarArg = pointer to vararg flags * Exit *pcParam = count of number of parameters * *pVarArgs = TRUE if function has varargs * Returns EECATASTROPHIC if fatal error * EENOERROR if no error */ ulong cParamTM ( HTM hTM, ulong *pcParam, PSHFLAG pVarArg ) { peval_t pv; ulong retval = EECATASTROPHIC; DASSERT (hTM != 0); if (hTM != 0) { pExState = (pexstate_t) MemLock (hTM); if (pExState->state.bind_ok == TRUE) { pv = &pExState->result; if (EVAL_IS_FCN (pv)) { if ((*pVarArg = FCN_VARARGS (pv)) == TRUE) { if ((*pcParam = FCN_PCOUNT (pv)) > 0) { (*pcParam)--; } } else { *pcParam = FCN_PCOUNT (pv); } if (EVAL_IS_METHOD (pv) && (FCN_THIS(pv) != T_NOTYPE)) { // add one for the this (*pcParam)++; } retval = EENOERROR; } else if (EVAL_IS_LABEL (pv)) { *pcParam = 0; retval = EENOERROR; } else { pExState->err_num = ERR_NOTFCN; retval = EEGENERAL; } } else { pExState->err_num = ERR_NOTEVALUATABLE; retval = EEGENERAL; } MemUnLock (hTM); } return (retval); } /** DupTM - duplicate TM * flag = DupTM (phTMIn, phTMOut) * Entry phTMIn = pointer to handle for input TM * phTMOut = pointer to handle for output TM * Exit TM and buffers duplicated * Returns EENOERROR if TM duplicated * EENOMEMORY if unable to allocate memory */ ulong DupTM ( PHTM phTMIn, PHTM phTMOut ) { ulong retval = EENOMEMORY; pexstate_t pExOut; char *pStr; char *pcName; char *pErrStr; uint len; pExState = (pexstate_t) MemLock (*phTMIn); pExStr = (char *) MemLock (pExState->hExStr); pTree = (pstree_t) MemLock (pExState->hSTree); if ((*phTMOut = MemAllocate (sizeof (exstate_t))) != 0) { pExOut = (pexstate_t) MemLock (*phTMOut); memset (pExOut, 0, sizeof (exstate_t)); pExOut->ambiguous = pExState->ambiguous; pExOut->state.parse_ok = TRUE; pExOut->state.fCase = pExState->state.fCase; // copy expression string if ((pExOut->hExStr = MemAllocate (pExOut->ExLen = pExState->ExLen)) == 0) { goto failure; } pStr = (char *) MemLock (pExOut->hExStr); memcpy (pStr, pExStr, pExOut->ExLen); MemUnLock (pExOut->hExStr); // copy syntax tree if ((pExOut->hSTree = MHMemAllocate (pTree->size)) == 0) { goto failure; } pStr = (char *) MemLock (pExOut->hSTree); memcpy (pStr, pTree, pTree->size); MemUnLock (pExOut->hSTree); // copy name string if (pExState->hCName != 0) { pcName = (char *) MemLock (pExState->hCName); len = _tcslen (pcName) + 1; if ((pExOut->hCName = MHMemAllocate (len)) == 0) { MemUnLock (pExState->hCName); goto failure; } pStr = (char *) MemLock (pExOut->hCName); memcpy (pStr, pcName, len); MemUnLock (pExOut->hCName); MemUnLock (pExState->hCName); } // copy saved expression string if (pExState->hExStrSav) { char * pExStrSav; if ((pExOut->hExStrSav = MemAllocate ((pExOut->ExLenSav = pExState->ExLenSav) + 1)) == 0) { goto failure; } pStr = (char *) MemLock (pExOut->hExStrSav); pExStrSav = (char *) MemLock (pExState->hExStrSav); memcpy (pStr, pExStrSav, pExOut->ExLenSav + 1); MemUnLock (pExState->hExStrSav); MemUnLock (pExOut->hExStrSav); pExOut->strIndexSav = pExState->strIndexSav; } // copy derived class name string if (pExState->hDClassName != 0) { pcName = (char *) MemLock (pExState->hDClassName); len = _tcslen (pcName) + 1; if ((pExOut->hDClassName = MHMemAllocate (len)) == 0) { MemUnLock (pExState->hDClassName); goto failure; } pStr = (char *) MemLock (pExOut->hDClassName); memcpy (pStr, pcName, len); MemUnLock (pExOut->hDClassName); MemUnLock (pExState->hDClassName); } // copy error string if (pExState->hErrStr != 0) { pErrStr = (char *) MemLock (pExState->hErrStr); len = _tcslen (pErrStr) + 1; if ((pExOut->hErrStr = MHMemAllocate (len)) == 0) { MemUnLock (pExState->hErrStr); goto failure; } pStr = (char *) MemLock (pExOut->hErrStr); memcpy (pStr, pErrStr, len); MemUnLock (pExOut->hErrStr); MemUnLock (pExState->hErrStr); } MemUnLock (*phTMOut); retval = EENOERROR; } succeed: MemUnLock (pExState->hExStr); MemUnLock (pExState->hSTree); MemUnLock (*phTMIn); return (retval); failure: if (pExOut->hExStr != 0) { MemFree (pExOut->hExStr); } if (pExOut->hSTree != 0) { MemFree (pExOut->hSTree); } if (pExOut->hCName != 0) { MemFree (pExOut->hCName); } if (pExOut->hExStrSav != 0) { MemFree (pExOut->hExStrSav); } if (pExOut->hDClassName != 0) { MemFree (pExOut->hDClassName); } if (pExOut->hErrStr != 0) { MemFree (pExOut->hErrStr); } MemUnLock (*phTMOut); MemFree (*phTMOut); *phTMOut = 0; goto succeed; } /** GetChildTM - get TM representing ith child * status = GetChildTM (hTMIn, iChild, phTMOut, pEnd, eeRadix, fCase) * Entry hTMIn = handle of parent TM * iChild = child to get TM for * phTMOut = pointer to handle for returned child * pEnd = pointer to int to receive index of char that ended parse * eeRadix = display radix (override current if != NULL ) * fCase = case sensitivity (TRUE is case sensitive) * Exit *phTMOut = handle of child TM if allocated * *pEnd = index of character that terminated parse * Returns EENOERROR if no error * non-zero if error: in that case the error code is in * *phTMOut if *phTMOut!=0, otherwise in hTMIn. */ EESTATUS GetChildTM ( HTM hTMIn, long iChild, PHTM phTMOut, ulong *pEnd, EERADIX eeRadix, SHFLAG fCase ) { eval_t evalP; peval_t pvP; EESTATUS retval = EENOERROR; char tempbuf[16]; ulong len; ulong plen; uint excess; pexstate_t pTM; pexstate_t pTMOut; EEHSTR hDStr = 0; EEHSTR hName = 0; char *pDStr; char *pName; char *format = "[%ld]"; SE_t seTemplate; DASSERT (hTMIn != 0); if (hTMIn == 0) { return (EECATASTROPHIC); } pExState = pTM = (pexstate_t) MemLock (hTMIn); if (pTM->state.bind_ok != TRUE) { pExState->err_num = ERR_NOTEVALUATABLE; MemUnLock (hTMIn); return (EEGENERAL); } pvP = &evalP; *pvP = pTM->result; pCxt = &pTM->cxt; if (EVAL_IS_REF (pvP)) { RemoveIndir (pvP); } GettingChild = TRUE; if (EVAL_IS_CLASS (pvP)) { // the type of the parent node is a class. We need to search for // the data members if an object is pointed to or the entire definition // if the class type is pointed to retval = GetClassiChild (hTMIn, iChild, (EVAL_STATE (pvP) == EV_type)? CLS_defn: CLS_data, phTMOut, pEnd, fCase); } else { pExStrP = (char *) MemLock (pTM->hExStr); DASSERT (pTM->strIndex <= pTM->ExLen); plen = pTM->strIndex; excess = pTM->ExLen - plen; switch( eeRadix ? eeRadix : pTM->radix ) { case 16: format = "[0x%lx]"; break; case 8: format = "[0%lo]"; break; } if (EVAL_IS_ARRAY (pvP)) { // fake up name as [i] ultoa not used here because 0 converts // as null string seTemplate = SE_array; len = sprintf (tempbuf, format, iChild); if (((hName = MemAllocate (len + 1)) == 0) || ((hDStr = MemAllocate (plen + excess + len + 1)) == 0)) { goto nomemory; } pName = (char *) MemLock (hName); pDStr = (char *) MemLock (hDStr); _tcscpy (pName, tempbuf); memcpy (pDStr, pExStrP, plen); memcpy (pDStr + plen, pName, len); memcpy (pDStr + plen + len, pExStrP + plen, excess); *(pDStr + plen + len + excess) = 0; MemUnLock (hDStr); MemUnLock (hName); } else if (EVAL_IS_PTR (pvP)) { SetNodeType (pvP, PTR_UTYPE (pvP)); if (!EVAL_IS_VTSHAPE (pvP)) { seTemplate = SE_ptr; // set name to null if (((hName = MemAllocate (1)) == 0) || ((hDStr = MemAllocate (plen + excess + 3)) == 0)) { goto nomemory; } pName = (char *) MemLock (hName); pDStr = (char *) MemLock (hDStr); *pName = 0; *pDStr++ = '('; memcpy (pDStr, pExStrP, plen); pDStr += plen; *pDStr++ = ')'; memcpy (pDStr, pExStrP + plen, excess); pDStr += excess; *pDStr = 0; MemUnLock (hDStr); MemUnLock (hName); } else { // fake up name as [i] ultoa not used here because 0 converts // as null string seTemplate = SE_array; len = sprintf (tempbuf, format, iChild); if (((hName = MemAllocate (len + 1)) == 0) || ((hDStr = MemAllocate (plen + excess + len + 1)) == 0)) { goto nomemory; } pName = (char *) MemLock (hName); pDStr = (char *) MemLock (hDStr); _tcscpy (pName, tempbuf); memcpy (pDStr, pExStrP, plen); memcpy (pDStr + plen, pName, len); memcpy (pDStr + plen + len, pExStrP + plen, excess); *(pDStr + plen + len + excess) = 0; MemUnLock (hDStr); MemUnLock (hName); } } else if (EVAL_IS_FCN (pvP)) { // the type of the parent node is a function. We walk down the // formal argument list and return a TM that references the ith // actual argument. We return an error if the ith actual is a vararg. seTemplate = SE_totallynew; if ((retval = SetFcniParm (pvP, iChild, &hName)) == EENOERROR) { pName = (char *) MemLock (hName); if ((hDStr = MemAllocate ((len = _tcslen (pName)) + 1)) == 0) { MemUnLock (hName); goto nomemory; } pDStr = (char *) MemLock (hDStr); memcpy (pDStr, pName, len); *(pDStr + len) = 0; MemUnLock (hDStr); MemUnLock (hName); } } else { pTM->err_num = ERR_NOTEXPANDABLE; goto general; } if ( OP_context == StartNodeOp (hTMIn)) { // if the parent expression contains a global context // shift the context string to the very left of // the child expression (so that this becomes a // global context of the child expression too) LShiftCxtString ( hDStr ); } retval = ParseBind (hDStr, hTMIn, phTMOut, pEnd, BIND_fSupOvlOps, fCase); hDStr = 0; //ParseBind has freed hDStr MemUnLock (pTM->hExStr); if (retval != EENOERROR) { goto general; } pTMOut = (pexstate_t) MemLock (*phTMOut); pTMOut->state.childtm = TRUE; if ((pTMOut->hCName = hName) == 0) { pTMOut->state.noname = TRUE; } if ((pTMOut->seTemplate = seTemplate) != SE_totallynew) { LinkWithParentTM (*phTMOut, hTMIn); } MemUnLock (*phTMOut); } MemUnLock (hTMIn); GettingChild = FALSE; return (retval); nomemory: pTM->err_num = ERR_NOMEMORY; general: if (hName) MemFree (hName); if (hDStr) MemFree (hDStr); MemUnLock (pTM->hExStr); MemUnLock (hTMIn); GettingChild = FALSE; return (EEGENERAL); } /** GetParmTM - get TM representing ith parameter of a TM * status = GetParmTM (hTM, iChild, phDStr, phName) * Entry hTM = handle of parent TM * iChild = child to get TM for * phDStr = pointer to the expression to be generated * phName = pointer to the child name to be generated * pExState = address of locked expression state * Exit *phDStr = expression string of child TM * *phName = name of child TM * Returns EESTATUS */ EESTATUS GetParmTM ( HTM hTM, ulong iChild, PEEHSTR phDStr, PEEHSTR phName ) { eval_t evalP; peval_t pvP; bool_t retval = EENOERROR; ulong len; ulong plen; uint excess; pexstate_t pTM; char *pDStr; char *pName; DASSERT (hTM != 0); if (hTM == 0) { return (EECATASTROPHIC); } pExState = pTM = (pexstate_t) MemLock (hTM); if (pTM->state.bind_ok != TRUE) { pTM->err_num = ERR_NOTEVALUATABLE; MemUnLock (hTM); return (EEGENERAL); } pExStrP = (char *) MemLock (pTM->hExStr); pCxt = &pTM->cxt; DASSERT (pTM->strIndex <= pTM->ExLen); plen = pTM->strIndex; excess = pTM->ExLen - plen; pvP = &evalP; *pvP = pTM->result; if (EVAL_IS_REF (pvP)) { RemoveIndir (pvP); } GettingChild = TRUE; DASSERT (EVAL_IS_FCN (pvP)); if (EVAL_IS_FCN (pvP)) { // the type of the parent node is a function. We walk down the // formal argument list and return a TM that references the ith // actual argument. We return an error if the ith actual is a vararg. if ((retval = SetFcniParm (pvP, iChild, phName)) == EENOERROR) { pName = (char *) MemLock (*phName); if ((*phDStr = MemAllocate ((len = _tcslen (pName)) + 1)) == 0) { MemUnLock (*phName); goto nomemory; } pDStr = (char *) MemLock (*phDStr); memcpy (pDStr, pName, len); *(pDStr + len) = 0; MemUnLock (*phDStr); MemUnLock (*phName); } } else { pTM->err_num = ERR_NOTEXPANDABLE; goto general; } MemUnLock (pTM->hExStr); MemUnLock (hTM); GettingChild = FALSE; return (retval); nomemory: pTM->err_num = ERR_NOMEMORY; general: MemUnLock (pTM->hExStr); MemUnLock (hTM); GettingChild = FALSE; return (EEGENERAL); } /** GetSymName - get name of symbol from node * fSuccess = GetSymName (buf, buflen) * Entry buf = pointer to buffer for name * buflen = length of buffer * Exit *buf = symbol name * Returns TRUE if no error retreiving name * FALSE if error * Note if pExState->hChildName is not zero, then the name in in * the buffer pointed to by hChildName */ EESTATUS GetSymName ( PHTM phTM, PEEHSTR phszName ) { SYMPTR pSym; int len = 0; UOFFSET offset = 0; char *pExStr; peval_t pv; int retval = EECATASTROPHIC; int buflen = TYPESTRMAX - 1; char *buf; HSYM hProc = 0; ADDR addr; // M00SYMBOL - we now need to allow for a symbol name to be imbedded // M00SYMBOL - in a type. Particularly for scoped types and enums. DASSERT (*phTM != 0); if ((*phTM != 0) && ((*phszName = MemAllocate (TYPESTRMAX)) != 0)) { retval = EEGENERAL; buf = (char *) MemLock (*phszName); memset (buf, 0, TYPESTRMAX); pExState = (pexstate_t) MemLock (*phTM); if (pExState->state.bind_ok == TRUE) { pv = &pExState->result; if ((pExState->state.childtm == TRUE) && (pExState->state.noname == TRUE)) { // if there is no name MemUnLock (*phTM); MemUnLock (*phszName); return (EENOERROR); } else if (pExState->hCName != 0) { // M00SYMBOL - for scoped types and symbols, we may be able to // M00SYMBOL - hCName to hold the imbedded symbol name pExStr = (char *) MemLock (pExState->hCName); len = (int)_tcslen (pExStr); len = min (len, buflen); _tcsncpy (buf, pExStr, len); MemUnLock (pExState->hCName); retval = EENOERROR; } else if (EVAL_HSYM (pv) == 0) { if ((EVAL_IS_PTR (pv) == TRUE) && (EVAL_STATE (pv) == EV_rvalue)) { addr = EVAL_PTR (pv); } else { addr = EVAL_SYM (pv); } if (!ADDR_IS_LI (addr)) { SHUnFixupAddr (&addr); } if (SHGetNearestHsym (&addr, EVAL_MOD (pv), EECODE, &hProc) == 0) { EVAL_HSYM (pv) = hProc; } } else { // if (EVAL_HSYM (pv) != 0) if (((pSym = (SYMPTR) MHOmfLock (EVAL_HSYM (pv)))->rectyp) == S_UDT) { // for a UDT, we do not return a name so that a // display of the type will display the type name // only once *buf = 0; MHOmfUnLock(EVAL_HSYM(pv)); } else { MHOmfUnLock(EVAL_HSYM(pv)); if (GetNameFromHSYM(buf, EVAL_HSYM(pv))) { retval = EENOERROR; } else { // symbol name was not found // we have either an internal error // or a bad omf pExState->err_num = ERR_INTERNAL; MemUnLock (*phTM); MemUnLock (*phszName); return EEGENERAL; } } } } else { // if the expression did not bind, return the expression and // the error message if one is available pExStr = (char *) MemLock (pExState->hExStr); len = (int)_tcslen (pExStr); len = min (buflen, len); _tcsncpy (buf, pExStr, len); buf += len; buflen -= len; MemUnLock (pExState->hExStr); } MemUnLock (*phszName); MemUnLock (*phTM); } return (retval); } /** GetNameFromHSYM - get symbol name from handle to symbol * BOOL GetNameFromHSYM (lpsz, hSym) * Entry lpsz = pointer to buffer to receive the name string * The buffer should be at least NAMESTRMAX bytes long * hSym = handle to symbol, the name of which is requested * Exit * On success the null terminated name is copied to lpsz * Return value * TRUE if name was found * FALSE if name was not found */ BOOL GetNameFromHSYM( char *lpsz, HSYM hSym ) { SYMPTR pSym; ulong len = 0; UOFFSET offset = 0; uint skip; DASSERT (lpsz != 0); DASSERT (hSym != 0); switch ((pSym = (SYMPTR) MHOmfLock (hSym))->rectyp) { case S_REGISTER: len = ((REGPTR)pSym)->name[0]; offset = offsetof (REGSYM, name[1]); break; case S_CONSTANT: // Dolphin #9323: // Do not use "offsetof(CONSTSYM, name)" // The symbol name is preceded by a numeric leaf // ("value") which may have a variable length and the // compile time offset may be bogus. skip = offsetof (CONSTSYM, value); RNumLeaf ((char *)pSym + skip, &skip); len = * ((char *)pSym + skip); offset = skip + 1; break; case S_UDT: len = ((UDTPTR)pSym)->name[0]; offset = offsetof (UDTSYM, name[1]); break; case S_BLOCK16: len = ((BLOCKPTR16)pSym)->name[0]; offset = offsetof (BLOCKSYM16, name[1]); break; case S_LPROC16: case S_GPROC16: len = ((PROCPTR16)pSym)->name[0]; offset = offsetof (PROCSYM16, name[1]); break; case S_LABEL16: len = ((LABELPTR16)pSym)->name[0]; offset = offsetof (LABELSYM16, name[1]); break; case S_BPREL16: len = ((BPRELPTR16)pSym)->name[0]; offset = offsetof (BPRELSYM16, name[1]); break; case S_LDATA16: case S_GDATA16: case S_PUB16: len = ((DATAPTR16)pSym)->name[0]; offset = offsetof (DATASYM16, name[1]); break; case S_BLOCK32: len = ((BLOCKPTR32)pSym)->name[0]; offset = offsetof (BLOCKSYM32, name[1]); break; case S_LPROC32: case S_GPROC32: len = ((PROCPTR32)pSym)->name[0]; offset = offsetof (PROCSYM32, name[1]); break; case S_LPROCMIPS: case S_GPROCMIPS: len = ((PROCPTRMIPS)pSym)->name[0]; offset = offsetof (PROCSYMMIPS, name[1]); break; case S_REGREL32: len = ((LPREGREL32)pSym)->name[0]; offset = offsetof (REGREL32, name[1]); break; case S_LABEL32: len = ((LABELPTR32)pSym)->name[0]; offset = offsetof (LABELSYM32, name[1]); break; case S_BPREL32: len = ((BPRELPTR32)pSym)->name[0]; offset = offsetof (BPRELSYM32, name[1]); break; case S_LDATA32: case S_GDATA32: case S_LTHREAD32: case S_GTHREAD32: case S_PUB32: len = ((DATAPTR32)pSym)->name[0]; offset = offsetof (DATASYM32, name[1]); break; case S_REGIA64: len = ((REGPTRIA64)pSym)->name[0]; offset = offsetof (REGSYMIA64, name[1]); break; case S_REGRELIA64: len = ((LPREGRELIA64)pSym)->name[0]; offset = offsetof (REGRELIA64, name[1]); break; case S_LPROCIA64: case S_GPROCIA64: len = ((PROCPTRIA64)pSym)->name[0]; offset = offsetof (PROCSYMIA64, name[1]); break; default: MHOmfUnLock (hSym); return FALSE; } len = min (len, NAMESTRMAX-1); _tcsncpy (lpsz, ((char *)pSym) + offset, len); MHOmfUnLock (hSym); *(lpsz + len) = 0; return TRUE; } #if 0 /** InfoFromTM - return information about TM * EESTATUS InfoFromTM (phTM, pReqInfo, phTMInfo); * Entry phTM = pointer to the handle for the expression state structure * reqInfo = info request structure * phTMInfo = pointer to handle for request info data structure * Exit *phTMInfo = handle of info structure * Returns EECATASTROPHIC if fatal error * 0 if no error */ EESTATUS InfoFromTM ( PHTM phTM, PRI pReqInfo, PHTI phTMInfo ) { PTI pTMInfo; eval_t evalT; peval_t pvT; ulong retval = EEGENERAL; DASSERT (*phTM != 0); if (*phTM == 0) { return (EECATASTROPHIC); } if ((*phTMInfo = MemAllocate (sizeof (TMI) + sizeof (val_t))) == 0) { return (EENOMEMORY); } pTMInfo = (PTI) MemLock (*phTMInfo); memset (pTMInfo, 0, sizeof (TMI)); pExState = (pexstate_t)MemLock (*phTM); if (pExState->state.bind_ok != TRUE) { // we must have at least bound the expression MemUnLock (*phTMInfo); MemUnLock (*phTM); return (EEGENERAL); } pvT = &evalT; *pvT = pExState->result; // if the node is an lvalue, store address and set response flags if (EVAL_STATE (pvT) == EV_lvalue) { // set segment information pTMInfo->fResponse.fSegType = TRUE; if (EVAL_TYP (pvT) == 0) { // the type of zero can only come from the publics table // this means we don't know anything about the symbol. pTMInfo->SegType = EEDATA | EECODE; } else if (EVAL_IS_DPTR (pvT) == TRUE) { pTMInfo->SegType = EEDATA; } else { pTMInfo->SegType = EECODE; } if (EVAL_IS_REG (pvT)) { pTMInfo->hReg = EVAL_REG (pvT); pTMInfo->fAddrInReg = TRUE; pTMInfo->fResponse.fLvalue = TRUE; } else if (EVAL_IS_BPREL (pvT) && (pExState->state.eval_ok == TRUE)) { pTMInfo->fBPRel = TRUE; if (pExState->state.eval_ok == TRUE) { ADDR addr; // Address of BP relative lvalue can only be returned after eval pTMInfo->AI = EVAL_SYM (pvT); SYGetAddr(pExState->hframe, &addr, adrBase); pTMInfo->AI.addr.off += GetAddrOff(addr); pTMInfo->AI.addr.seg = GetAddrSeg(addr); // fixup to a logical address SHUnFixupAddr (&pTMInfo->AI); pTMInfo->fResponse.fAddr = TRUE; pTMInfo->fResponse.fLvalue = TRUE; } } else if ((TargetMachine == mptmips) || (TargetMachine == mptdaxp)) { if (EVAL_IS_REGREL (pvT) && (pExState->state.eval_ok == TRUE)) { if (!ResolveAddr(pvT)) { DASSERT(FALSE); } if (((TargetMachine == mptmips) && (EVAL_REGREL(pvT) != CV_M4_IntGP)) || ((TargetMachine == mptdaxp) && (EVAL_REGREL(pvT) != CV_ALPHA_IntGP))) { pTMInfo->fBPRel = TRUE; } pTMInfo->fResponse.fAddr = TRUE; pTMInfo->fResponse.fLvalue = TRUE; pTMInfo->AI = EVAL_SYM (pvT); } } else { pTMInfo->fResponse.fAddr = TRUE; pTMInfo->fResponse.fLvalue = TRUE; pTMInfo->AI = EVAL_SYM (pvT); } if ((pExState->state.eval_ok == TRUE) && LoadSymVal (pvT)) { EVAL_STATE (pvT) = EV_rvalue; } } // if the node is an rvalue containing the address of a function, store // the function address and set the response flags if ((EVAL_STATE (pvT) == EV_rvalue) && (EVAL_IS_FCN (pvT) || EVAL_IS_LABEL (pvT))) { pTMInfo->fResponse.fAddr = TRUE; pTMInfo->fResponse.fLvalue = FALSE; pTMInfo->AI = EVAL_SYM (pvT); if ( ! ADDR_IS_LI (pTMInfo->AI)) { SHUnFixupAddr (&pTMInfo->AI); } pTMInfo->SegType = EECODE; pTMInfo->fResponse.fValue = FALSE; pTMInfo->fResponse.Type = EVAL_TYP (pvT); } #if 0 // { // [cuda#3155 4/20/93 mikemo] // This code causes pointers to be automatically dereferenced. This was // by design: it was considered more useful under CodeView that, for // example, "dw pch" would dump at the memory pointed to by "pch" rather // than at the address of "pch" itself. However, this unfortunately led // to inconsistency between "dw pch" and "dw i"; the latter would dump at // the address of "i". People who didn't realize this were never really // sure what their "dw" command was going to do. // This also caused lots of confusion for breakpoints: if you said "break // when expr changes", it would stop when the value of "i" changed, // but if you said "break when expr changes", it would stop when // the value *pointed to* by "pch" changed. This was an even bigger // problem for types like HWND, which looks to the user basically like a // scalar, but looks to the debugger like a pointer, so the debugger would // try to deref it. // So we've decided to do away with the automatic dereference. else if ((EVAL_STATE (pvT) == EV_rvalue) && (EVAL_IS_ADDR (pvT))) { Evaluating = TRUE; if (EVAL_IS_BASED (pvT)) { NormalizeBase (pvT); } Evaluating = FALSE; pTMInfo->fResponse.fAddr = TRUE; pTMInfo->fResponse.fLvalue = FALSE; pTMInfo->AI = EVAL_PTR (pvT); pTMInfo->SegType = EECODE | EEDATA; if ( ! ADDR_IS_LI (pTMInfo->AI)) { SHUnFixupAddr (&pTMInfo->AI); } pTMInfo->fResponse.fValue = FALSE; pTMInfo->fResponse.Type = EVAL_TYP (pvT); } #endif // } 0 else if ((EVAL_STATE (pvT) == EV_rvalue) || (EVAL_STATE (pvT) == EV_constant)) { // Make sure pointers are unfixed up if (EVAL_IS_ADDR(pvT) && ADDR_IS_LI(EVAL_PTR(pvT))) { SHFixupAddr(&EVAL_PTR(pvT)); } // if the node is an rvalue or a constant, store value and set response if ((EVAL_STATE (pvT) == EV_constant) || (pExState->state.eval_ok == TRUE)) { if (CV_IS_PRIMITIVE (pReqInfo->Type)) { if (pReqInfo->Type == 0) pReqInfo->Type = EVAL_TYP (pvT); Evaluating = TRUE; if (CastNode (pvT, pReqInfo->Type, pReqInfo->Type)) { memcpy (&pTMInfo->Value, &pvT->val, sizeof (pvT->val)); pTMInfo->fResponse.Type = EVAL_TYP (pvT); pTMInfo->fResponse.fValue = TRUE; } Evaluating = FALSE; } } } // set flag if bind tree contains function call pTMInfo->fFunction = pExState->state.fFunction; // set flag if we are a synthesized child TM. if ( pReqInfo->fSynthChild ) { if ( pExState->seTemplate == SE_downcast ) { DASSERT(pExState->state.childtm == TRUE); pTMInfo->fSynthChild = TRUE; } else pTMInfo->fSynthChild = FALSE; pTMInfo->fResponse.fSynthChild = TRUE; } if ( pReqInfo->fLabel ) { if ( EVAL_IS_LABEL(pvT) ) pTMInfo->fLabel = TRUE; else pTMInfo->fLabel = FALSE; pTMInfo->fResponse.fLabel = TRUE; } // set size of field in bytes unless bits are requested // for a bitfield, the bitfield size is returned if bits are // requested. Otherwise, the size of the underlying type is returned if (EVAL_IS_BITF (pvT)) { if (pReqInfo->fSzBits == TRUE) { pTMInfo->cbValue = BITF_LEN (pvT); pTMInfo->fResponse.fSzBits = TRUE; } else { EVAL_TYP (pvT) = BITF_UTYPE (pvT); pTMInfo->cbValue = TypeSize (pvT); pTMInfo->fResponse.fSzBytes = TRUE; } } else if (EVAL_TYP (pvT) != 0) { pTMInfo->cbValue = TypeSize (pvT); if (pReqInfo->fSzBits == TRUE) { pTMInfo->cbValue *= 8; pTMInfo->fResponse.fSzBits = TRUE; } else { pTMInfo->fResponse.fSzBytes = TRUE; } } retval = EENOERROR; MemUnLock (*phTMInfo); MemUnLock (*phTM); return (retval); } #else // 0 /** InfoFromTM - return information about TM * EESTATUS InfoFromTM (phTM, pReqInfo, phTMInfo); * Entry phTM = pointer to the handle for the expression state structure * reqInfo = info request structure * phTMInfo = pointer to handle for request info data structure * Exit *phTMInfo = handle of info structure * Returns EECATASTROPHIC if fatal error * 0 if no error * The return information is based on the input request structure: * fSegType - Requests the segment type the TM resides in. * returned in TI.fCode * fAddr - Return result as an address * fValue - Return value of TM * fLvalue - Return address of TM if lValue. This and * fValue are mutually exclusive * fSzBits - Return size of value in bits * fSzBytes - Return size of value in bytes. This and * fSzBits are mutually exclusive. * Type - If not T_NOTYPE then cast value to this type. * fValue must be set. */ EESTATUS InfoFromTM ( PHTM phTM, PRI pReqInfo, PHTI phTMInfo ) { EESTATUS eestatus = EEGENERAL; PTI pTMInfo; eval_t evalT; peval_t pvT; SHREG reg; char *p; *phTMInfo = 0; /* * Verify that there is a TM to play with */ DASSERT( *phTM != 0 ); if (*phTM == 0) { return EECATASTROPHIC; } /* * Check for consistancy on the requested information */ if (((pReqInfo->fValue) && (pReqInfo->fLvalue)) || ((pReqInfo->fSzBits) && (pReqInfo->fSzBytes)) || ((pReqInfo->Type != T_NOTYPE) && (!pReqInfo->fValue))) { return EEGENERAL; } /* * Allocate and lock down the TI which is used to return the answers */ if (( *phTMInfo = MHMemAllocate( sizeof(TMI) + sizeof(val_t) )) == 0) { return EENOMEMORY; } pTMInfo = MHMemLock( *phTMInfo ); DASSERT( pTMInfo != NULL ); memset( pTMInfo, 0, sizeof(TMI) + sizeof(val_t) ); /* * Lock down the TM passed in */ //DASSERT(pExState == NULL); pExState = (pexstate_t) MHMemLock( *phTM ); if ( pExState->state.bind_ok != TRUE ) { /* * If the expression has not been bound, then we can't actually * answer any of the questions being asked. */ MHMemUnLock( *phTMInfo ); MHMemUnLock( *phTM ); pExState = NULL; return EEGENERAL; } pvT = &evalT; *pvT = pExState->result; eestatus = EENOERROR; /* * If the user asked about the segment type for the expression, * get it. */ if (pReqInfo->fSegType || pReqInfo->fAddr) { if (EVAL_STATE( pvT ) == EV_lvalue) { pTMInfo->fResponse.fSegType = TRUE; /* * Check for type of 0. If so then this must be a public * as all compiler symbols have some type information */ if (EVAL_TYP( pvT ) == 0) { pTMInfo->SegType = EEDATA | EECODE; } /* * If item is of type pointer to data then must be in * data segment */ else if (EVAL_IS_DPTR( pvT ) == TRUE) { pTMInfo->SegType = EEDATA; } /* * in all other cases it must have been a code segment */ else { pTMInfo->SegType = EECODE; } } else if ((EVAL_STATE( pvT ) == EV_rvalue) && (EVAL_IS_FCN( pvT ) || EVAL_IS_LABEL( pvT ))) { pTMInfo->fResponse.fSegType = TRUE; pTMInfo->SegType = EECODE; } else if ((EVAL_STATE( pvT ) == EV_rvalue) && (EVAL_IS_ADDR( pvT ))) { pTMInfo->fResponse.fSegType = TRUE; pTMInfo->SegType = EECODE | EEDATA; } else if ((EVAL_STATE( pvT ) == EV_rvalue) || (EVAL_STATE( pvT ) == EV_constant)) { ; } } /* * If the user asked for the value then get it */ if (pReqInfo->fValue) { if ((pExState->state.eval_ok == TRUE) && LoadSymVal(pvT)) { EVAL_STATE (pvT) = EV_rvalue; } if ((EVAL_STATE(pvT) == EV_rvalue) && (EVAL_IS_FCN(pvT) || EVAL_IS_LABEL(pvT))) { if ( pReqInfo->Type == T_NOTYPE ) { pTMInfo->fResponse.fValue = TRUE; pTMInfo->fResponse.fAddr = TRUE; pTMInfo->fResponse.fLvalue = FALSE; pTMInfo->AI = EVAL_SYM( pvT ); pTMInfo->fResponse.Type = EVAL_TYP( pvT ); if (!ADDR_IS_LI(pTMInfo->AI)) { SHUnFixupAddr(&pTMInfo->AI); } } else { Evaluating = TRUE; if (CastNode( pvT, pReqInfo->Type, pReqInfo->Type )) { memcpy( pTMInfo->Value, &pvT->val, sizeof( pvT->val )); pTMInfo->fResponse.fValue = TRUE; pTMInfo->fResponse.Type = EVAL_TYP( pvT ); } Evaluating = FALSE; } } else if ((EVAL_STATE( pvT ) == EV_rvalue) && (EVAL_IS_ADDR( pvT ))) { if (EVAL_IS_BASED( pvT )) { Evaluating = TRUE; NormalizeBase( pvT ); Evaluating = FALSE; } if ( pReqInfo->Type == T_NOTYPE ) { pTMInfo->fResponse.fValue = TRUE; pTMInfo->fResponse.fAddr = TRUE; pTMInfo->fResponse.fLvalue = FALSE; pTMInfo->AI = EVAL_PTR( pvT ); pTMInfo->fResponse.Type = EVAL_TYP(pvT); if (!ADDR_IS_LI( pTMInfo->AI )) { SHUnFixupAddr( &pTMInfo->AI ); } } else { Evaluating = TRUE; if (CastNode( pvT, pReqInfo->Type, pReqInfo->Type )) { memcpy( pTMInfo->Value, &pvT->val, sizeof( pvT->val )); pTMInfo->fResponse.fValue = TRUE; pTMInfo->fResponse.Type = EVAL_TYP( pvT ); } Evaluating = FALSE; } } else if ((EVAL_STATE( pvT ) == EV_rvalue) || (EVAL_STATE( pvT ) == EV_constant)) { if ((EVAL_STATE( pvT ) == EV_constant ) || (pExState->state.eval_ok == TRUE)) { if (CV_IS_PRIMITIVE( pReqInfo->Type )) { if (pReqInfo->Type == 0) { pReqInfo->Type = EVAL_TYP( pvT ); } Evaluating = TRUE; if (CastNode( pvT, pReqInfo->Type, pReqInfo->Type )) { memcpy( pTMInfo->Value, &pvT->val, sizeof( pvT->val )); pTMInfo->fResponse.fValue = TRUE; pTMInfo->fResponse.Type = EVAL_TYP( pvT ); } Evaluating = FALSE; } } } } /* * If the user asked for the lvalue as an address */ if (pReqInfo->fAddr && pReqInfo->fLvalue) { pTMInfo->AI = pvT->addr; //eestatus = EEGENERAL; } /* * If the user asked for the value as an address */ if (pReqInfo->fAddr && !pReqInfo->fLvalue) { if ((EVAL_STATE(pvT) == EV_lvalue) && (pExState->state.eval_ok == TRUE) && LoadSymVal(pvT)) { EVAL_STATE (pvT) = EV_rvalue; } if ((EVAL_STATE(pvT) == EV_rvalue) && (EVAL_IS_FCN(pvT) || EVAL_IS_LABEL(pvT))) { pTMInfo->AI = EVAL_SYM( pvT ); pTMInfo->fResponse.fAddr = TRUE; pTMInfo->fResponse.Type = EVAL_TYP( pvT ); if (!ADDR_IS_LI(pTMInfo->AI)) { SHUnFixupAddr(&pTMInfo->AI); } eestatus = EENOERROR; } else if ((EVAL_STATE(pvT) == EV_rvalue) && (EVAL_IS_ADDR( pvT ))) { if (EVAL_IS_BASED( pvT )) { Evaluating = TRUE; NormalizeBase( pvT ); Evaluating = FALSE; } pTMInfo->fResponse.fAddr = TRUE; pTMInfo->AI = EVAL_PTR( pvT ); pTMInfo->fResponse.Type = EVAL_TYP( pvT ); if (!ADDR_IS_LI( pTMInfo->AI )) { SHUnFixupAddr( &pTMInfo->AI ); } } else if ((EVAL_STATE( pvT ) == EV_rvalue) || (EVAL_STATE( pvT ) == EV_constant)) { if ((EVAL_STATE( pvT ) == EV_constant) || (pExState->state.eval_ok == TRUE)) { //pReqInfo->Type = T_ULONG; v-vadimp - why change the type of preqInfo?i386 Evaluating = TRUE; if (CastNode(pvT, pReqInfo->Type, pReqInfo->Type)) { switch( TypeSize( pvT ) ) { case 1: pTMInfo->AI.addr.off = VAL_UCHAR( pvT ); break; case 2: pTMInfo->AI.addr.off = VAL_USHORT( pvT ); break; case 4: pTMInfo->AI.addr.off = SE32To64( VAL_ULONG( pvT ) ); break; case 8: pTMInfo->AI.addr.off = VAL_UQUAD( pvT ); if ( !Is64PtrSE(pTMInfo->AI.addr.off) ) { pTMInfo->AI.addr.off = SE32To64(pTMInfo->AI.addr.off); } break; default: eestatus = EEGENERAL; break; } pTMInfo->fResponse.fAddr = TRUE; pTMInfo->fResponse.Type = pReqInfo->Type; if (TargetMachine == mptix86) { if (pTMInfo->SegType & EECODE) { reg.hReg = CV_REG_CS; } else { reg.hReg = CV_REG_DS; } GetReg(®, pCxt, pExState->hframe); pTMInfo->AI.addr.seg = reg.Byte2; } else { pTMInfo->AI.addr.seg = 0; } SHUnFixupAddr( &pTMInfo->AI); } else { eestatus = EEGENERAL; } Evaluating = FALSE; } else { eestatus = EEGENERAL; } } else { eestatus = EEGENERAL; } } /* * Set the size fields if requested */ if (pReqInfo->fSzBits) { if (EVAL_IS_BITF( pvT )) { pTMInfo->cbValue = BITF_LEN( pvT ); pTMInfo->fResponse.fSzBits = TRUE; } else { if (EVAL_TYP( pvT ) != 0) { pTMInfo->cbValue = 8 * TypeSize( pvT ); pTMInfo->fResponse.fSzBits = TRUE; } } } if (pReqInfo->fSzBytes) { if (EVAL_IS_BITF( pvT )) { EVAL_TYP( pvT ) = BITF_UTYPE( pvT ); } if (EVAL_TYP( pvT ) != 0) { pTMInfo->cbValue = TypeSize( pvT ); pTMInfo->fResponse.fSzBytes = TRUE; } } /* * Set random flags */ pTMInfo->fFunction = pExState->state.fFunction; pExStr = MHMemLock(pExState->hExStr); p = &pExStr[pExState->strIndex]; if (*p == ',') { p++; pTMInfo->fFmtStr = TRUE; } else { pTMInfo->fFmtStr = FALSE; } MHMemUnLock( pExState->hExStr ); MHMemUnLock( *phTMInfo ); MHMemUnLock( *phTM ); pExState = NULL; return eestatus; } #endif /** IsExpandablePtr - check for pointer to displayable data * fSuccess = IsExpandablePtr (pn) * Entry pn = pointer to node for variable * Exit none * Returns EEPOINTER if node is a pointer to primitive data or, * class/struct/union * EEAGGREGATE if node is an array with a non-zero size or is * a pointer to a virtual function shape table * EENOTEXP otherwise */ ulong IsExpandablePtr ( peval_t pv ) { eval_t evalT; peval_t pvT; ulong retval = EENOTEXP; if (EVAL_IS_PTR (pv)) { // this will also handle the reference cases CV_typ_t typ = PTR_UTYPE(pv); if (CV_IS_PRIMITIVE (typ)) { // void pointers are not expandable. if (CV_TYPE(typ) == CV_SPECIAL && CV_SUBT(typ) == CV_SP_VOID) { retval = EENOTEXP; } else { retval = EEPOINTER; } } else { pvT = &evalT; CLEAR_EVAL (pvT); EVAL_MOD (pvT) = EVAL_MOD (pv); SetNodeType (pvT, PTR_UTYPE (pv)); if (EVAL_IS_CLASS (pvT) || EVAL_IS_PTR (pvT)) { retval = EEPOINTER; } else if (EVAL_IS_VTSHAPE (pvT) || (EVAL_IS_ARRAY (pvT) && (PTR_ARRAYLEN (pv) != 0))) { retval = EEAGGREGATE; } } } return (retval); } /** GetDerivClassName - Get name of derived class * Entry pv = pointer to eval node * bDistinct = if TRUE will only return the value if dynamic class is * different from the static class of the eval node. * buf = buffer to hold derived class name * lenMax = buffer size (max allowable string length, * including terminating '\0') * Exit if eval node corresponds to a pointer to a base * class that points to an object of a derived class * and the base class has a vtable, then we use the * vtable name in the publics section to find out * the actual type of the underlying object. In that * case the derived class name is copied to buf. * Returns TRUE on success (derived class name found & copied) * FALSE otherwise */ bool_t GetDerivClassName( peval_t pv, BOOL bDistinct, char *buf, uint lenMax ) { ADDR addr; ADDR addrNew; CXT cxt; HSYM hSym; SYMPTR pSym; ulong offset; uint len; const int DPREFIXLEN = 4; HTYPE hType; plfEasy pType; uint lenBClass; uint skip = 1; eval_t eval; peval_t pEval = &eval; char *lszExe; char *lsz; if (EVAL_STATE(pv) == EV_type || !EVAL_IS_PTR(pv)) { return FALSE; } *pEval = *pv; if (SetNodeType(pEval, PTR_UTYPE(pv)) == FALSE || !EVAL_IS_CLASS(pEval) || CLASS_VTSHAPE(pEval) == 0 ) { return FALSE; } // the class object has a vfptr. // By convention the pointer to the vtable is // the first field of the object. We assume that this is // a 32bit pointer and we try to find its value. memset(&cxt, 0, sizeof(CXT)); memset(&addrNew, 0, sizeof(addrNew)); // reinitialize temporary eval node and compute ptr value *pEval = *pv; if (LoadSymVal(pEval) == FALSE) { return FALSE; } // compute the actual address of vfptr pointer addr = EVAL_PTR (pEval); if (ADDR_IS_LI (addr)) { SHFixupAddr (&addr); } if (EVAL_IS_PTR (pEval) && (EVAL_IS_NPTR (pEval) || EVAL_IS_NPTR32 (pEval))) { addr.addr.seg = GetSegmentRegister(pExState->hframe, REG_DS); } // now get the contents of addr in order to // find where vfptr points to. Assume a 32bit vfptr // if addr is a 32bit address // currently we don't handle the 16-bit case if (!ADDR_IS_OFF32(addr) || sizeof(UOFFSET) != GetDebuggeeBytes(addr, sizeof(UOFFSET), &addrNew.addr.off, (TargetMachine == mptia64)? T_UQUAD : T_ULONG) ) { return FALSE; } // Sign extend this before SHUnFixupAddr is called if (TargetMachine != mptia64) { addrNew.addr.off = SE32To64( *(DWORD*)(&addrNew.addr.off) ); } if (!SHUnFixupAddr(&addrNew)) { return FALSE; } // create context string if (lszExe = SHGetExeName ((HIND) emiAddr(addrNew))) { char drive[_MAX_DRIVE]; char dir[_MAX_DIR]; char fname[_MAX_FNAME]; char ext[_MAX_EXT]; uint lenName; uint lenExt; // discard the full path-- keep only the filename.and extension _tsplitpath(lszExe, drive, dir, fname, ext); lenName = _tcslen(fname); lenExt = _tcslen(ext); if (lenName + lenExt + 4 >= lenMax) { return FALSE; } lenMax -= (lenName + lenExt + 4); memcpy(buf, "{,,", 3); buf += 3; memcpy(buf, fname, lenName); buf += lenName; memcpy(buf, ext, lenExt); buf += lenExt; *buf++ = '}'; } // Based on the address of the vtable, try to find the // corresponding vtable symbol in the publics section if (PHGetNearestHsym (&addrNew, (HIND) emiAddr(addrNew), &hSym) == 0) { pSym = (SYMPTR) MHOmfLock (hSym); switch (pSym->rectyp) { case S_PUB16: len = ((PUBPTR16)pSym)->name[0]; offset = offsetof (PUBSYM16, name) + sizeof (char); break; case S_PUB32: len = ((PUBPTR32)pSym)->name[0]; offset = offsetof (PUBSYM32, name) + sizeof (char); break; case S_GDATA32: len = ((DATAPTR32)pSym)->name[0]; offset = offsetof (DATASYM32, name) + sizeof (char); break; default: MHOmfUnLock(hSym); return FALSE; } // now we have the public symbol for the vtable // of the object // the decorated name is ??_7foo@class1@class2...@@type // where foo is the derived class name // we should convert this string to class2::class1::foo lsz = (char *)pSym + offset; if (_tcsncmp(lsz, "??_7", 4) || UndecorateScope(lsz + 4, buf, lenMax) == FALSE) { return FALSE; } MHOmfUnLock(hSym); // compute undecorated name length len = _tcslen(buf); // now check if this name is the same as the // class name of pEval if ((hType = THGetTypeFromIndex (EVAL_MOD (pEval), PTR_UTYPE (pEval))) == 0) { return FALSE; } retry: pType = (plfEasy)(&((TYPPTR)(MHOmfLock (hType)))->leaf); switch (pType->leaf) { case LF_MODIFIER: if ((hType = THGetTypeFromIndex (EVAL_MOD (pEval), ((plfModifier)pType)->type)) == 0) { return FALSE; } goto retry; case LF_STRUCTURE: case LF_CLASS: skip = offsetof (lfClass, data); RNumLeaf (((char *)(&pType->leaf)) + skip, &skip); lenBClass = *(((char *)&(pType->leaf)) + skip); if (!bDistinct || lenBClass != len || _tcsncmp (buf, ((char *)pType) + skip + 1, len) != 0) { // the name found using the vfptr is different from // the original class name; apparently buf contains // the derived class name MHOmfUnLock (hType); return TRUE; } MHOmfUnLock (hType); } } return FALSE; } /** GetVirtFuncName - Given an expression which evaluates to a virtual function, * figure out the name of the actual function that will get called. * Entry pv = Pointer to eval node. * buf = buffer to write the string into. * lenmax = amount of memory available in the buffer. * Exit - If the eval node corresponds to a bound virtual function expression, * and we can figure out the actual class of the object returns the * function name of the bound function. * NOTE: This function is currently not general enough. It expects the passed in * TM to correspond to a bound virtual function. Since it has not been tested * in more general scenarios, I have added a test to only do this is the * TM already has an ERR_NOVIRTUALBP. If you want to use it in a more general * context you might need to revisit the code and make sure the general * case works as well. */ bool_t GetVirtFuncName( PHTM phTM, PCXF pCxf, CHAR *buf, uint lenmax ) { bnode_t bnRoot, bnL, bnR ; BOOL retVal = TRUE; if (phTM == NULL) return FALSE; pExState = (pexstate_t) MemLock(*phTM); // If the expression is not bound correctly, we could have attempted to bind it // as a bp and failed because it was a bound virtual function. if (pExState->state.bind_ok != TRUE && pExState->err_num != ERR_NOVIRTUALBP) { MemUnLock(*phTM); return FALSE; } pTree = (pstree_t) MemLock(pExState->hETree); if (pTree == NULL) { MemUnLock(*phTM); return FALSE; } bnRoot = (bnode_t)pTree->start_node; if ( bnRoot == NULL || (bnL = NODE_LCHILD(bnRoot)) == NULL || (bnR = NODE_RCHILD(bnRoot)) == NULL ) { MemUnLock(pExState->hETree); MemUnLock(*phTM); } // get derived class needs a frame pointer because // it needs to figure out the address where the // ptr lies and load it in order to determine the // real class of the object. pExState->hframe = SHhFrameFrompCXF(pCxf); if (GetDerivClassName(&(bnL->v[0]), FALSE, buf, lenmax)) { uint len = _tcslen(buf); peval_t pvRight = &bnR->v[0]; if ( len + 2 < lenmax) { _tcscat(buf, "::"); len += 2; } else { retVal = FALSE; } // Get the member function part of the name of the right node. if (retVal && len + EVAL_CBTOK(pvRight) < lenmax) { char * psz = (char *) MemLock(pExState->hExStr); _tcsncat(buf, &psz[EVAL_ITOK(pvRight)], EVAL_CBTOK(pvRight)); MemUnLock(pExState->hExStr); } } else { retVal = FALSE; } MemUnLock(pExState->hETree); MemUnLock(*phTM); return retVal; } /** UndecorateScope - Undecorate scope info * Entry lsz = pointer to decorated string * "Nest0@Nest1@...@NestTop@@type_info" * buf = buffer to receive undecorated scope * lenMax = buffer size (max allowable string length, * including terminating '\0') * Exit buf contains a string of the form * "NestTop:: ... ::Nest1::Nest0" * terminated by a NULL character * Returns TRUE if scope string succesfully transformed * FALSE otherwise */ bool_t UndecorateScope( char *lsz, char far *buf, uint lenMax ) { char *lszStart; char *lszEnd; uint len; lszStart = lsz; if ((lszEnd = _tcsstr(lsz, "@@")) == 0) { return FALSE; } // every '@' character will be replaced with "::" // check if there is enough space in the destination buffer for (len = 0; lsz < lszEnd; lsz++) if (*lsz == '@') len += 2; else len++; if (len >= lenMax) { return FALSE; } // traverse the string backwards and every time a scope item // is found copy it to buf lsz = lszEnd - 1; while (lsz >= lszStart) { for (len = 0; lsz >= lszStart && *lsz != '@'; lsz--) { len++; } // scope item starts at lsz+1 memcpy (buf, lsz+1, len); buf += len; if (*lsz == '@') { memcpy (buf, "::", 2); buf += 2; lsz--; } } *buf = '\0'; return TRUE; } /*** CountClassElem - count number of class elements according to mask * error = CountClassElem (hTMIn, pv, pcChildren, search) * Entry hTMIn = handle of parent TM * pv = pointer to node containing class data * pcChildren = pointer to long to receive number of elements * search = mask specifying which element types to count * Exit *pcChildren = * count of number of class elements meeting search requirments * Returns EESTATUS */ EESTATUS CountClassElem ( HTM hTMIn, peval_t pv, long *pcChildren, ulong search ) { ulong cnt; // total number of elements in class HTYPE hField; // type record handle for class field list char *pField; // current position within field list uint fSkip = 0; // current offset in the field list uint anchor; ulong retval = EENOERROR; CV_typ_t newindex; char *pc; if (pExState->hDClassName) { // in this case we can add an extra child of the // form (DerivedClass *)pBaseClass, so that the // user can see the actual underlying object of // a class pointer (*pcChildren)++; } // set the handle of the field list if ((hField = THGetTypeFromIndex (EVAL_MOD (pv), CLASS_FIELD (pv))) == 0) { DASSERT (FALSE); return (0); } pField = (char *)(&((TYPPTR)MHOmfLock (hField))->data); // walk field list to the end counting elements for (cnt = CLASS_COUNT (pv); cnt > 0; cnt--) { fSkip += SkipPad(((uchar *)pField) + fSkip); anchor = fSkip; switch (((plfEasy)(pField + fSkip))->leaf) { case LF_INDEX: // move to next list in chain newindex = ((plfIndex)(pField + fSkip))->index; MHOmfUnLock (hField); if ((hField = THGetTypeFromIndex (EVAL_MOD (pv), newindex)) == 0) { DASSERT (FALSE); return (0); } pField = (char *)(&((TYPPTR)MHOmfLock (hField))->data); fSkip = 0; // the LF_INDEX is not part of the field count cnt++; break; case LF_MEMBER: // skip offset of member and name of member fSkip += offsetof (lfMember, offset); RNumLeaf (pField + fSkip, &fSkip); fSkip += *(pField + fSkip) + sizeof (char); if (search & CLS_member) { (*pcChildren)++; } break; case LF_ENUMERATE: // skip value name of enumerate fSkip += offsetof (lfEnumerate, value); RNumLeaf (pField + fSkip, &fSkip); fSkip += *(pField + fSkip) + sizeof (char); if (search & CLS_enumerate) { (*pcChildren)++; } break; case LF_STMEMBER: fSkip += offsetof (lfSTMember, Name); pc = pField + fSkip; fSkip += *(pField + fSkip) + sizeof (char); if (search & CLS_member) { HTM hTMOut; ulong end; SHFLAG fCase = pExState->state.fCase; // Count only static members that are present // try to bind static data member and see if it is present retval = BindStMember(hTMIn, pc, &hTMOut, &end, fCase); if (retval == EENOERROR && fNotPresent (hTMOut)) { // Just ignore this member and go on with // traversing the field list } else { (*pcChildren)++; } // clean up if (hTMOut) EEFreeTM (&hTMOut); } break; case LF_BCLASS: fSkip += offsetof (lfBClass, offset); RNumLeaf (pField + fSkip, &fSkip); if (search & CLS_bclass) { (*pcChildren)++; } break; case LF_VBCLASS: fSkip += offsetof (lfVBClass, vbpoff); RNumLeaf (pField + fSkip, &fSkip); RNumLeaf (pField + fSkip, &fSkip); if (search & CLS_bclass) { (*pcChildren)++; } break; case LF_IVBCLASS: fSkip += offsetof (lfVBClass, vbpoff); RNumLeaf (pField + fSkip, &fSkip); RNumLeaf (pField + fSkip, &fSkip); break; case LF_FRIENDCLS: fSkip += sizeof (lfFriendCls); if (search & CLS_fclass) { (*pcChildren)++; } break; case LF_FRIENDFCN: fSkip += sizeof (struct lfFriendFcn) + ((plfFriendFcn)(pField + fSkip))->Name[0]; if (search & CLS_frmethod) { (*pcChildren)++; } break; case LF_VFUNCTAB: fSkip += sizeof (lfVFuncTab); if (search & CLS_vfunc) { (*pcChildren)++; } break; case LF_METHOD: fSkip += sizeof (struct lfMethod) + ((plfMethod)(pField + fSkip))->Name[0]; cnt -= ((plfMethod)(pField + anchor))->count - 1; if (search & CLS_method) { *pcChildren += ((plfMethod)(pField + anchor))->count; } break; case LF_ONEMETHOD: fSkip += uSkipLfOneMethod((plfOneMethod)(pField + fSkip)); if (search & CLS_method) (*pcChildren)++; break; case LF_NESTTYPE: fSkip += sizeof (struct lfNestType) + ((plfNestType)(pField + fSkip))->Name[0]; if (search & CLS_ntype) { (*pcChildren)++; } break; default: pExState->err_num = ERR_BADOMF; MHOmfUnLock (hField); *pcChildren = 0; return (EEGENERAL); } } if (hField != 0) { MHOmfUnLock (hField); } return (retval); } const long celemIncr = 4; // Helper function which adds the next index to the structure. EESTATUS AddToIndexArray( PHBCIA pHBCIA, long * pCount, long index ) { PHINDEX_ARRAY pHIA = (PHINDEX_ARRAY) MemLock(*pHBCIA); if ( pHIA == NULL) return EEGENERAL; if ( pHIA->count == (ulong)*pCount ) { *pCount += celemIncr; MemUnLock(*pHBCIA); if ( (*pHBCIA = MemReAlloc(*pHBCIA, sizeof(HINDEX_ARRAY) + *pCount * sizeof(long))) == 0) { return EENOMEMORY; } else { pHIA = (PHINDEX_ARRAY) MemLock(*pHBCIA); } } DASSERT(pHIA->count < (ulong)*pCount); pHIA->rgIndex[pHIA->count] = index; pHIA->count++; MemUnLock(*pHBCIA); return EENOERROR; } /** GetMemberIA - Return indexes to the members satisfying the search criterion. * Entry hTM = handle to TM * search - the type of members whose indices are to be included. * Exit A handle to an index array structure. */ EESTATUS GetMemberIA( PHTM phTM, PHBCIA pHBCIA, ulong search ) { ulong retval = EENOERROR; eval_t eval; peval_t pv = &eval; long celem = celemIncr; PHINDEX_ARRAY phIA = NULL; DASSERT(*phTM != 0); *pHBCIA = NULL; if (*phTM == 0) { return (EECATASTROPHIC); } pExState = (pexstate_t) MemLock(*phTM); if (pExState->state.bind_ok != TRUE) { MemUnLock(*phTM); return EEGENERAL; } eval = pExState->result; if (EVAL_IS_REF (pv)) { RemoveIndir (pv); } if ( ((*pHBCIA) = MemAllocate(sizeof(HINDEX_ARRAY) + celem * sizeof(long))) == NULL) { MemUnLock(*phTM); return EENOMEMORY; } phIA = (PHINDEX_ARRAY) MemLock(*pHBCIA); phIA->count = 0; MemUnLock(*pHBCIA); if (!CV_IS_PRIMITIVE(EVAL_TYP(pv)) && EVAL_IS_CLASS (pv)) { long curIndex = (pExState->hDClassName)? 1 : 0; HTYPE hField; char *pField; uint fSkip = 0; uint anchor; ulong cnt; CV_typ_t newindex; char * pc; uint fFoundNonBaseClass = FALSE; // set the handle of the field list if ((hField = THGetTypeFromIndex (EVAL_MOD (pv), CLASS_FIELD (pv))) == 0) { DASSERT (FALSE); return (0); } pField = (char *)(&((TYPPTR)MHOmfLock (hField))->data); // walk field list to the end counting elements for (cnt = CLASS_COUNT (pv); cnt > 0 && retval == EENOERROR; cnt--, curIndex++) { // The CVInfo guarantees that the base classes will be the first elements // of the member list. The only case we call this function for is to get // the base class list currently. To optimize for this case we keep track of // if we found a non-base class member. If that is the case and the caller // has only asked us for base classes we do the quick exit. if (fFoundNonBaseClass && search == CLS_bclass ) break; fSkip += SkipPad(((uchar *)pField) + fSkip); anchor = fSkip; switch (((plfEasy)(pField + fSkip))->leaf) { case LF_INDEX: // move to next list in chain newindex = ((plfIndex)(pField + fSkip))->index; MHOmfUnLock (hField); if ((hField = THGetTypeFromIndex (EVAL_MOD (pv), newindex)) == 0) { DASSERT (FALSE); return (0); } pField = (char *)(&((TYPPTR)MHOmfLock (hField))->data); fSkip = 0; // the LF_INDEX is not part of the field count cnt++; curIndex--; break; case LF_MEMBER: // skip offset of member and name of member fSkip += offsetof (lfMember, offset); RNumLeaf (pField + fSkip, &fSkip); fSkip += *(pField + fSkip) + sizeof (char); if (search & CLS_member) { retval = AddToIndexArray(pHBCIA, &celem, curIndex); } fFoundNonBaseClass = TRUE; break; case LF_ENUMERATE: // skip value name of enumerate fSkip += offsetof (lfEnumerate, value); RNumLeaf (pField + fSkip, &fSkip); fSkip += *(pField + fSkip) + sizeof (char); if (search & CLS_enumerate) { retval = AddToIndexArray(pHBCIA, &celem, curIndex); } fFoundNonBaseClass = TRUE; break; case LF_STMEMBER: fSkip += offsetof (lfSTMember, Name); pc = pField + fSkip; fSkip += *(pField + fSkip) + sizeof (char); if (search & CLS_member) { HTM hTMOut; ulong end; SHFLAG fCase = pExState->state.fCase; // Count only static members that are present // try to bind static data member and see if it is present retval = BindStMember(*phTM, pc, &hTMOut, &end, fCase); if (retval == EENOERROR && fNotPresent (hTMOut)) { // Just ignore this member and go on with // traversing the field list } else if (retval == EENOERROR) { retval = AddToIndexArray(pHBCIA, &celem, curIndex); } // clean up if (hTMOut) EEFreeTM (&hTMOut); } fFoundNonBaseClass = TRUE; break; case LF_BCLASS: fSkip += offsetof (lfBClass, offset); RNumLeaf (pField + fSkip, &fSkip); if (search & CLS_bclass) { retval = AddToIndexArray(pHBCIA, &celem, curIndex); } break; case LF_VBCLASS: fSkip += offsetof (lfVBClass, vbpoff); RNumLeaf (pField + fSkip, &fSkip); RNumLeaf (pField + fSkip, &fSkip); if (search & CLS_bclass) { retval = AddToIndexArray(pHBCIA, &celem, curIndex); } break; case LF_IVBCLASS: fSkip += offsetof (lfVBClass, vbpoff); RNumLeaf (pField + fSkip, &fSkip); RNumLeaf (pField + fSkip, &fSkip); break; case LF_FRIENDCLS: fSkip += sizeof (lfFriendCls); if (search & CLS_fclass) { retval = AddToIndexArray(pHBCIA, &celem, curIndex); } fFoundNonBaseClass = TRUE; break; case LF_FRIENDFCN: fSkip += sizeof (struct lfFriendFcn) + ((plfFriendFcn)(pField + fSkip))->Name[0]; if (search & CLS_frmethod) { retval = AddToIndexArray(pHBCIA, &celem, curIndex); } fFoundNonBaseClass = TRUE; break; case LF_VFUNCTAB: fSkip += sizeof (lfVFuncTab); if (search & CLS_vfunc) { retval = AddToIndexArray(pHBCIA, &celem, curIndex); } break; case LF_METHOD: fSkip += sizeof (struct lfMethod) + ((plfMethod)(pField + fSkip))->Name[0]; cnt -= ((plfMethod)(pField + anchor))->count - 1; if (search & CLS_method) { int count = ((plfMethod)(pField + anchor))->count; while ( count-- ) { if ((retval = AddToIndexArray(pHBCIA, &celem, curIndex++)) != EENOERROR) break; } curIndex--; } fFoundNonBaseClass = TRUE; break; case LF_ONEMETHOD: fSkip += uSkipLfOneMethod((plfOneMethod)(pField + fSkip)); if (search & CLS_method) retval = AddToIndexArray(pHBCIA, &celem, curIndex); fFoundNonBaseClass = TRUE; break; case LF_NESTTYPE: fSkip += sizeof (struct lfNestType) + ((plfNestType)(pField + fSkip))->Name[0]; if (search & CLS_ntype) { retval = AddToIndexArray(pHBCIA, &celem, curIndex); } fFoundNonBaseClass = TRUE; break; default: pExState->err_num = ERR_BADOMF; MHOmfUnLock (hField); MemUnLock(*phTM); return (EEGENERAL); } } if (hField != 0) { MHOmfUnLock (hField); } } MemUnLock(*phTM); return (retval); } /** fNotPresent - Check if TM contains non-present static data * flag = fNotPresent (hTM) * Entry hTM = handle to TM * Exit none * Returns TRUE if TM conatains non-present static data * FALSE otherwise */ BOOL fNotPresent ( HTM hTM ) { pexstate_t pTM; BOOL retval = FALSE; DASSERT (hTM); pTM = (pexstate_t) MemLock (hTM); if (pTM->state.bind_ok && pTM->state.fNotPresent) retval = TRUE; MemUnLock (hTM); return retval; } /** DereferenceTM - generate expression string from pointer to data TM * flag = DereferenceTM (hTMIn, phEStr, phDClassName) * Entry phTMIn = handle to TM to dereference * phEStr = pointer to handle to dereferencing expression * phDClassName = pointer to handle to derived class name * in case the TM points to an enclosed base clas object * Exit *phEStr = expression referencing pointer data * *phDClassName = enclosing object (derived) class name * Returns EECATASTROPHIC if fatal error * EEGENERAL if TM not dereferencable * EENOERROR if expression generated */ EESTATUS DereferenceTM ( HTM hTM, PEEHSTR phDStr, PEEHSTR phDClassName ) { peval_t pvTM; EESTATUS retval = EECATASTROPHIC; ulong plen; uint excess; BOOL fIsCSymbol = TRUE, fIsReference = FALSE; BOOL fIsRefToPtr = FALSE; BOOL fIsWrapped = FALSE, fShouldWrap; char *szEx; DASSERT (hTM != 0); if (hTM != 0) { // lock TM and set pointer to result field of TM pExState = (pexstate_t) MemLock (hTM); pvTM = &pExState->result; if (EVAL_IS_ARRAY (pvTM) || (IsExpandablePtr (pvTM) != EEPOINTER)) { pExState->err_num = ERR_NOTEXPANDABLE; retval = EEGENERAL; } else { // allocate buffer for *(input string) and copy if ((*phDStr = MemAllocate (pExState->ExLen + 4)) != 0) { // if not reference and not a C symbol then // generate: expression = *(old_expr) // if not reference and is a C symbol then // generate: expression = *old_expr // if reference, expression = (old_expr) // if reference to a ptr, expression = *old_expr pExStr = (char *) MemLock (*phDStr); plen = pExState->strIndex; excess = pExState->ExLen - plen; pExStrP = (char *) MemLock (pExState->hExStr); // Determine if the symbol is a pure C symbol // Check 1st character fIsCSymbol = _istcsymf((_TUCHAR)*pExStrP); // Check the rest of the characters for(szEx = _tcsinc (pExStrP); fIsCSymbol && szEx < &pExStrP[plen]; szEx = _tcsinc (szEx)) { fIsCSymbol = _istcsym((_TUCHAR)*szEx); } if (EVAL_IS_REF (pvTM)) { eval_t EvalTmp; peval_t pv = &EvalTmp; fIsReference = TRUE; *pv = *pvTM; RemoveIndir (pv); if (EVAL_IS_PTR (pv)) { // Dolphin 8336 // If we have a reference to a pointer we // should dereference the underlying pointer DASSERT (!EVAL_IS_REF (pv)); fIsRefToPtr = TRUE; } } if (!fIsReference || fIsRefToPtr) { *pExStr++ = '*'; } if(pExStrP[0] == '(' && pExStrP[plen-1] == ')') { fIsWrapped = TRUE; } fShouldWrap = !fIsCSymbol && !fIsReference && !fIsWrapped; // If it is not a pure CSymbol then throw in // in an extra pair of parens if(fShouldWrap) { *pExStr++ = '('; } memcpy (pExStr, pExStrP, plen); pExStr += plen; if(fShouldWrap) { *pExStr++ = ')'; } memcpy (pExStr, pExStrP + plen, excess); pExStr += excess; *pExStr = 0; MemUnLock (pExState->hExStr); MemUnLock (*phDStr); if ( OP_context == StartNodeOp (hTM)) { // if the parent expression contains a global context // shift the context string to the very left of // the child expression (so that this becomes a // global context of the child expression too) LShiftCxtString ( *phDStr ); } // the code below implements a feature that allows // automatic casting of a pointer, as follows: // Assume: class B: a base class of class D // D d; // an object of class D // B pB = &d; // In certain cases we can automatically detect // that the object pointed by pB is actually a // D object, and generate an extra child when // expanding pB, that has the form // (D *)pB // If Class B contains a vtable, auto detection // is performed as follows: we find the vtable // address (by convention the vfptr is the first // record in the class object),then we find a name // in the publics that corresponds to this address // By undecorating the vtable name, we can get // the actual class name of the object pointed to // by pB. We store this name in TM->hDClassName; // EEcChildrenTM and EEGetChildTM use hDClassName // in order to generate the additional child. // In order for auto detection to occur, TMIn // must have been evaluated. /* Block */ { char *pName; int len; char buf[TYPESTRMAX]; if (fAutoClassCast && !fIsReference && pExState->state.eval_ok && GetDerivClassName(pvTM, TRUE, buf, sizeof (buf))) { if (*phDClassName) { MemFree(*phDClassName); *phDClassName = 0; } len = _tcslen(buf); if ((*phDClassName = MemAllocate (len + 1)) == 0) { MemUnLock(hTM); return EENOMEMORY; } pName = (char *) MemLock(*phDClassName); _tcscpy(pName, buf); MemUnLock(*phDClassName); } } /* end of Block */ retval = EENOERROR; } } MemUnLock (hTM); } return (retval); } /*** GetClassiChild - Get ith child of a class * status = GetClassiChild (hTMIn, ordinal, search, phTMOut, pEnd, fCase) * Entry hTMIN = handle to the parent TM * ordinal = number of class element to initialize for * (zero based) * search = mask specifying which element types to count * phTMOut = pointer to handle for the child TM * pEnd = pointer to int to receive index of char that ended parse * (M00API: consider removing pEnd from EEGetChildTM API) * fCase = case sensitivity (TRUE is case sensitive) * Exit *phTMOut contains the child TM that was created * Returns EESTATUS */ EESTATUS GetClassiChild ( HTM hTMIn, long ordinal, uint search, PHTM phTMOut, ulong *pEnd, SHFLAG fCase ) { HTYPE hField; // handle to type record for struct field list char *pField; // current position withing field list uint fSkip = 0; // current offset in the field list uint anchor; uint len; bool_t retval = ERR_NONE; bool_t fBound = FALSE; CV_typ_t newindex; char *pName; char *pc; char *pDStr; char FName[255]; char *pFName = FName; EEHSTR hDStr = 0; EEHSTR hName = 0; ulong plen; ulong excess; peval_t pv; eval_t evalP; pexstate_t pTMIn; pexstate_t pTMOut; char *pStrP; SE_t seTemplate; long tmpOrdinal; GCC_state_t *pLast; eval_t evalT; peval_t pvT; PHDR_TYPE pHdr; pTMIn = (pexstate_t) MemLock (hTMIn); if (pTMIn->state.bind_ok != TRUE) { pExState->err_num = ERR_NOTEVALUATABLE; MemUnLock (hTMIn); return (EEGENERAL); } pCxt = &pTMIn->cxt; pStrP = (char *) MemLock (pTMIn->hExStr); plen = pTMIn->strIndex; excess = pTMIn->ExLen - plen; pv = &evalP; *pv = pTMIn->result; if (EVAL_IS_REF (pv)) { RemoveIndir (pv); } // set fField to the handle of the field list if (pTMIn->hDClassName) { ordinal--; if (ordinal < 0) { ulong lenTypeStr; ulong lenCxtStr; ulong lenDStr; ulong lenDflCxt; char *pDClassName; char *pTypeStr; extern char * szDflCxtMarker; // CXT string denoting default CXT // pDClassName contains a string "{,,}" // pStrP is either "{}*" or "*" // Generate string for downcast node: // {,,}*( *){} or // {,,}*( *){} // respectively pDClassName = (char *) MemLock (pTMIn->hDClassName); len = _tcslen(pDClassName); // skip the context operator that exists in hDClassName pTypeStr = _tcschr(pDClassName, '}'); DASSERT (pTypeStr); pTypeStr++; lenCxtStr = (ulong)(pTypeStr - pDClassName); lenTypeStr = len - lenCxtStr; lenDflCxt = _tcslen (szDflCxtMarker); DASSERT ( *pStrP == '*' || *pStrP == '{' ); // The dereferencing '*' found in the parent string // will be skipped; use plen - 1 instead of plen lenDStr = (plen - 1) + len + excess + 4 + 1; if (*pStrP != '{') { // There is no explicit context in the parent expression // Leave space for a default context operator lenDStr += lenDflCxt; } // allocation for hName includes space for enclosing brackets if (((hName = MemAllocate (lenTypeStr + 3)) == 0) || (hDStr = MemAllocate (lenDStr)) == 0) { MemUnLock(pTMIn->hDClassName); goto nomemory; } pDStr = (char *) MemLock (hDStr); memcpy (pDStr, pDClassName, lenCxtStr); pDStr += lenCxtStr; memcpy (pDStr, "*(", 2); pDStr += 2; memcpy (pDStr, pTypeStr, lenTypeStr); pDStr += lenTypeStr; memcpy (pDStr, "*)", 2); pDStr += 2; if (*pStrP == '{') { char * pch; // pStrP should be in the form {...}*parent_expr // split pStrP into context and parent_expr pch = _tcschr (pStrP, '*'); DASSERT (pch); // add explicit context if different from the // one inserted at the beginning if (_tcsncmp (pStrP, pDClassName, lenCxtStr)) { memcpy (pDStr, pStrP, (size_t)(pch - pStrP)); pDStr += pch - pStrP; } plen -= (ulong)(pch - pStrP + 1); pStrP = pch + 1; } else { // insert default context operator memcpy (pDStr, szDflCxtMarker, lenDflCxt); pDStr += lenDflCxt; // skip dereferencing '*' in parent expression DASSERT (*pStrP == '*'); pStrP ++; plen --; } memcpy (pDStr, pStrP, plen); pDStr += plen; memcpy (pDStr, pStrP + plen, excess); pDStr += excess; *pDStr = 0; MemUnLock (hDStr); // use the derived class name as the child name // enclose it in brackets to indicate that this // is not an ordinary base class // also suppress the context operator pName = (char *) MemLock(hName); *pName = '['; memcpy(pName+1, pTypeStr, lenTypeStr); *(pName + lenTypeStr + 1) = ']'; *(pName + lenTypeStr + 2) = '\0'; MemUnLock (pTMIn->hDClassName); MemUnLock(hName); retval = ParseBind (hDStr, hTMIn, phTMOut, pEnd, BIND_fSupOvlOps, fCase); hDStr = 0; //ParseBind has freed hDStr if (retval != EENOERROR) { goto general; } pTMOut = (pexstate_t) MemLock (*phTMOut); pTMOut->state.childtm = TRUE; pTMOut->hCName = hName; pTMOut->seTemplate = SE_downcast; // link with parent's parent: // parent expr. is a deref'ed ptr // parent's parent is the actual ptr // being reused when downcasting DASSERT (pTMIn->hParentTM); LinkWithParentTM (*phTMOut, pTMIn->hParentTM); MemUnLock (*phTMOut); MemUnLock (pTMIn->hExStr); MemUnLock (hTMIn); // do not free hName,since it is being used by the TM return (retval); } } tmpOrdinal = ordinal; pLast = &pExState->searchState; if (hTMIn == pLast->hTMIn && ordinal > pLast->ordinal) { ordinal -= (pLast->ordinal + 1); hField = pLast->hField; fSkip = pLast->fSkip; } else { if ((hField = THGetTypeFromIndex (EVAL_MOD (pv), CLASS_FIELD (pv))) == 0) { DASSERT (FALSE); pTMIn->err_num = ERR_BADOMF; MemUnLock (pTMIn->hExStr); MemUnLock (hTMIn); return EEGENERAL; } } pField = (char *)(&((TYPPTR)MHOmfLock (hField))->data); // walk field list to iElement-th field while (ordinal >= 0) { fSkip += SkipPad(((uchar *)pField) + fSkip); anchor = fSkip; switch (((plfEasy)(pField + fSkip))->leaf) { case LF_INDEX: // move to next list in chain newindex = ((plfIndex)(pField + fSkip))->index; MHOmfUnLock (hField); if ((hField = THGetTypeFromIndex (EVAL_MOD (pv), newindex)) == 0) { pTMIn->err_num = ERR_BADOMF; MemUnLock (pTMIn->hExStr); MemUnLock (hTMIn); return EEGENERAL; } pField = (char *)(&((TYPPTR)MHOmfLock (hField))->data); fSkip = 0; break; case LF_MEMBER: // skip offset of member and name of member fSkip += offsetof (lfMember, offset); RNumLeaf (pField + fSkip, &fSkip); pc = pField + fSkip; fSkip += *(pField + fSkip) + sizeof (char); if (search & CLS_member) { ordinal--; } break; case LF_ENUMERATE: // skip value name of enumerate fSkip += offsetof (lfEnumerate, value); RNumLeaf (pField + fSkip, &fSkip); pc = pField + fSkip; fSkip += *(pField + fSkip) + sizeof (char); if (search & CLS_enumerate) { ordinal--; } break; case LF_STMEMBER: fSkip += offsetof (lfSTMember, Name); pc = pField + fSkip; fSkip += *(pField + fSkip) + sizeof (char); if (search & CLS_member) { // try to bind static data member and see if it is present retval = BindStMember(hTMIn, pc, phTMOut, pEnd, fCase); if (retval == EENOERROR && fNotPresent (*phTMOut)) { // Non-present static data member // Just ignore this member and go on with // traversing the field list EEFreeTM (phTMOut); } else { ordinal--; if (ordinal < 0) { // this is the member we are looking for fBound = TRUE; // do not attempt to rebind later } else if (*phTMOut) { EEFreeTM (phTMOut); // clean up } } } break; case LF_BCLASS: fSkip += offsetof (lfBClass, offset); RNumLeaf (pField + fSkip, &fSkip); if (search & CLS_bclass) { ordinal--; } break; case LF_VBCLASS: fSkip += offsetof (lfVBClass, vbpoff); RNumLeaf (pField + fSkip, &fSkip); RNumLeaf (pField + fSkip, &fSkip); if (search & CLS_bclass) { ordinal--; } break; case LF_IVBCLASS: fSkip += offsetof (lfVBClass, vbpoff); RNumLeaf (pField + fSkip, &fSkip); RNumLeaf (pField + fSkip, &fSkip); break; case LF_FRIENDCLS: fSkip += sizeof (struct lfFriendCls); if (search & CLS_fclass) { ordinal--; } break; case LF_FRIENDFCN: fSkip += sizeof (struct lfFriendFcn) + ((plfFriendFcn)(pField + fSkip))->Name[0]; if (search & CLS_frmethod) { ordinal--; } break; case LF_VFUNCTAB: fSkip += sizeof (struct lfVFuncTab); pc = vfuncptr; if (search & CLS_vfunc) { ordinal--; } break; case LF_METHOD: pc = pField + anchor + offsetof (lfMethod, Name); fSkip += sizeof (struct lfMethod) + *pc; if (search & CLS_method) { ordinal -= ((plfMethod)(pField + anchor))->count; } break; case LF_ONEMETHOD: pc = pbNameInLfOneMethod((plfOneMethod)(pField + anchor)); fSkip += uSkipLfOneMethod((plfOneMethod)(pField + anchor)); if (search & CLS_method) ordinal--; break; case LF_NESTTYPE: fSkip += offsetof (lfNestType, Name); pc = pField + fSkip; fSkip += *(pField + fSkip) + sizeof (char); if (search & CLS_ntype) { ordinal--; } break; default: MHOmfUnLock (hField); pTMIn->err_num = ERR_BADOMF; MemUnLock (pTMIn->hExStr); MemUnLock (hTMIn); return EEGENERAL; } if (ordinal < 0) { break; } } if (((plfEasy)(pField + anchor))->leaf != LF_METHOD || ordinal == -1) { // Update cached information; Methods need special // attention since the method list has to be searched // based on the value of ordinal. We update the cache // only if this is the last method in the method-list // (i.e., ordinal == -1) pLast->hTMIn = hTMIn; pLast->ordinal = tmpOrdinal; pLast->hField = hField; pLast->fSkip = fSkip; } // we have found the ith element of the class. Now create the // name and the expression to reference the name switch (((plfEasy)(pField + anchor))->leaf) { case LF_STMEMBER: seTemplate = SE_member; // get member name len = *pc; if ((hName = MemAllocate (len + 1)) == 0) goto nomemory; pName = (char *) MemLock (hName); _tcsncpy (pName, pc + 1, len); *(pName + len) = 0; MemUnLock (hName); // the rest should have already been handled by BindStMember break; case LF_MEMBER: case LF_VFUNCTAB: case LF_NESTTYPE: seTemplate = SE_member; len = *pc; if (((hName = MemAllocate (len + 1)) == 0) || ((hDStr = MemAllocate (plen + excess + len + 4)) == 0)) { goto nomemory; } pName = (char *) MemLock (hName); _tcsncpy (pName, pc + 1, len); *(pName + len) = 0; pDStr = (char *) MemLock (hDStr); *pDStr++ = '('; memcpy (pDStr, pStrP, plen); pDStr += plen; *pDStr++ = ')'; *pDStr++ = '.'; memcpy (pDStr, pName, len); pDStr += len; memcpy (pDStr, pStrP + plen, excess); pDStr += excess; *pDStr = 0; MemUnLock (hDStr); MemUnLock (hName); break; case LF_BCLASS: seTemplate = SE_bclass; newindex = ((plfBClass)(pField + anchor))->index; MHOmfUnLock (hField); if ((hField = THGetTypeFromIndex (EVAL_MOD (pv), newindex)) != 0) { // find the name of the base class from the referenced class pField = (char *)(&((TYPPTR)MHOmfLock (hField))->leaf); fSkip = offsetof (lfClass, data); RNumLeaf (pField + fSkip, &fSkip); len = *(pField + fSkip); // generate (*(base *)(&expr)) if (((hName = MemAllocate (len + 1)) == 0) || ((hDStr = MemAllocate (plen + len + excess + 10)) == 0)) { goto nomemory; } pName = (char *) MemLock (hName); _tcsncpy (pName, pField + fSkip + sizeof (char), len); *(pName + len) = 0; pDStr = (char *) MemLock (hDStr); memcpy (pDStr, "(*(", 3); memcpy (pDStr + 3, pField + fSkip + sizeof (char), len); memcpy (pDStr + 3 + len, "*)(&", 4); memcpy (pDStr + 7 + len, pStrP, plen); memcpy (pDStr + 7 + len + plen, "))", 2); memcpy (pDStr + 7 + len + plen + 2, pStrP + plen, excess); *(pDStr + 9 + len + plen + excess) = 0; MemUnLock (hDStr); MemUnLock (hName); } break; case LF_VBCLASS: seTemplate = SE_bclass; newindex = ((plfVBClass)(pField + anchor))->index; MHOmfUnLock (hField); if ((hField = THGetTypeFromIndex (EVAL_MOD (pv), newindex)) != 0) { // find the name of the base class from the referenced class pField = (char *)(&((TYPPTR)MHOmfLock (hField))->leaf); fSkip = offsetof (lfClass, data); RNumLeaf (pField + fSkip, &fSkip); len = *(pField + fSkip); // generate (*(base *)(&expr)) if (((hName = MemAllocate (len + 1)) == 0) || ((hDStr = MemAllocate (plen + len + excess + 10)) == 0)) { goto nomemory; } pName = (char *) MemLock (hName); //*pName = 0; _tcsncpy (pName, pField + fSkip + sizeof (char), len); *(pName + len) = 0; pDStr = (char *) MemLock (hDStr); memcpy (pDStr, "(*(", 3); memcpy (pDStr + 3, pField + fSkip + sizeof (char), len); memcpy (pDStr + 3 + len, "*)(&", 4); memcpy (pDStr + 7 + len, pStrP, plen); memcpy (pDStr + 7 + len + plen, "))", 2); memcpy (pDStr + 7 + len + plen + 2, pStrP + plen, excess); *(pDStr + 9 + len + plen + excess) = 0; MemUnLock (hDStr); MemUnLock (hName); } break; case LF_FRIENDCLS: // look at referenced type record to get name of class // M00KLUDGE - figure out what to do here - not bindable newindex = ((plfFriendCls)(pField + anchor))->index; MHOmfUnLock (hField); if ((hField = THGetTypeFromIndex (EVAL_MOD (pv), newindex)) != 0) { pField = (char *)(&((TYPPTR)MHOmfLock (hField))->leaf); fSkip = offsetof (lfClass, data); RNumLeaf (pField + fSkip, &fSkip); len = *(pField + fSkip); } break; case LF_FRIENDFCN: // look at referenced type record to get name of function // M00KLUDGE - figure out what to do here - not bindable newindex = ((plfFriendFcn)(pField + anchor))->index; pc = (char *)(((plfFriendFcn)(pField + anchor))->Name[0]); break; case LF_ONEMETHOD: seTemplate = SE_method; // copy function name to temporary buffer len = *pc; memcpy (FName, pc + 1, len); FName[len] = 0; newindex = ((plfOneMethod)(pField + anchor))->index; pvT = &evalT; CLEAR_EVAL (pvT); // EVAL_MOD (pvT) = SHHMODFrompCXT (pCxt); // Need to use EVAL_MOD(pv) instead, as the // parent epxression may contain an explicit context EVAL_MOD (pvT) = EVAL_MOD (pv); FCN_ATTR(pvT) = ((plfOneMethod)(pField + anchor))->attr; goto finishMethod; case LF_METHOD: seTemplate = SE_method; // copy function name to temporary buffer len = *pc; memcpy (FName, pc + 1, len); FName[len] = 0; newindex = ((plfMethod)(pField + anchor))->mList; MHOmfUnLock (hField); // index down method list to find correct method if ((hField = THGetTypeFromIndex (EVAL_MOD (pv), newindex)) != 0) { char *pMethod; pMethod = (char *)(&((TYPPTR)MHOmfLock (hField))->data); fSkip = 0; while (++ordinal < 0) { fSkip += sizeof (mlMethod); if (fIntroducingVirtual(((pmlMethod)(pMethod + fSkip))->attr.mprop)) { fSkip += sizeof(long); } } pvT = &evalT; CLEAR_EVAL (pvT); // EVAL_MOD (pvT) = SHHMODFrompCXT (pCxt); // Need to use EVAL_MOD(pv) instead, as the // parent epxression may contain an explicit context EVAL_MOD (pvT) = EVAL_MOD (pv); newindex = ((pmlMethod)(pMethod + fSkip))->index; MHOmfUnLock (hField); hField = 0; FCN_ATTR(pvT) = ((pmlMethod)(pMethod + fSkip))->attr; finishMethod: SetNodeType (pvT, newindex); EVAL_ACCESS(pvT) = (uchar) FCN_ACCESS(pvT); if ((hName = MemAllocate (FCNSTRMAX + sizeof (HDR_TYPE))) == 0) { goto nomemory; } // FormatType places a structure at the beginning of the buffer // containing offsets into the type string. We need to skip this // structure pName = (char *) MemLock (hName); pHdr = (PHDR_TYPE)pName; memset (pName, 0, FCNSTRMAX + sizeof (HDR_TYPE)); pName = pName + sizeof (HDR_TYPE); pc = pName; len = FCNSTRMAX - 1; FormatType (pvT, &pName, &len, &pFName, 0L, pHdr); len = FCNSTRMAX - len; // ignore buffer header from FormatType memmove ((char *)pHdr, pc, len); pc = (char *)pHdr; if ((hDStr = MemAllocate (plen + FCNSTRMAX + excess + 2)) == 0) { MemUnLock (hName); goto nomemory; } pDStr = (char *) MemLock (hDStr); memcpy (pDStr, pStrP, plen); memcpy (pDStr + plen, ".", 1); memcpy (pDStr + 1 + plen, pc, len); memcpy (pDStr + 1 + plen + len, pStrP + plen, excess); *(pDStr + len + plen + 1 + excess) = 0; MemUnLock (hDStr); // truncate name to first ( for (len = 0; (*pc != '(') && (*pc != 0); pc++) { len++; } *pc = 0; MemUnLock (hName); if ((hName = MHMemReAlloc (hName, len + 1)) == 0) { goto nomemory; } if (EVAL_STATE(&pTMIn->result) == EV_type) { fBound = TRUE; // do not call ParseBind seTemplate = SE_totallynew; pDStr = (char *) MemLock(hDStr); *phTMOut = 0; // Ignore return value // What we really care for is the creation of a TM (void) Parse (pDStr, pTMIn->radix, fCase, FALSE, phTMOut, pEnd); if (*phTMOut == 0) { MemUnLock(hDStr); goto general; } pTMOut = (pexstate_t) MemLock (*phTMOut); pTMOut->cxt = pTMIn->cxt; pTMOut->hframe = pTMIn->hframe; MemUnLock(*phTMOut); MemUnLock(hDStr); MemFree(hDStr); hDStr = 0; if (QChildFcnBind (*phTMOut, pv, pvT, hName) == FALSE){ retval = EEGENERAL; goto general; } else { retval = EENOERROR; } } } break; default: pTMIn->err_num = ERR_BADOMF; retval = EEGENERAL; break; } if (!fBound) { if (hDStr == 0) { pTMIn->err_num = ERR_NOTEVALUATABLE; retval = EEGENERAL; } else { if ( OP_context == StartNodeOp (hTMIn)) { // if the parent expression contains a global context // shift the context string to the very left of // the child expression (so that this becomes a // global context of the child expression too) LShiftCxtString ( hDStr ); } retval = ParseBind (hDStr, hTMIn, phTMOut, pEnd, BIND_fSupOvlOps, fCase); hDStr = 0; //ParseBind has freed hDStr } } if (hField != 0) { MHOmfUnLock (hField); } if (retval != EENOERROR) { goto general; } pTMOut = (pexstate_t) MemLock (*phTMOut); pTMOut->state.childtm = TRUE; if ((pTMOut->hCName = hName) == 0) { pTMOut->state.noname = TRUE; } if ((pTMOut->seTemplate = seTemplate) != SE_totallynew) { LinkWithParentTM (*phTMOut, hTMIn); } MemUnLock (*phTMOut); MemUnLock (pTMIn->hExStr); MemUnLock (hTMIn); // do not free hName,since it is being used by the TM return (retval); nomemory: pTMIn->err_num = ERR_NOMEMORY; general: if (hDStr) MemFree (hDStr); if (hField != 0) { MHOmfUnLock (hField); } if (hName != 0) { MemFree (hName); } MemUnLock (pTMIn->hExStr); MemUnLock (hTMIn); return (EEGENERAL); } /*** BindStMember - Bind Static Member * Workhorse for handling static members in GetClassiChild * and CountClassElem * error = BindStMember (hTMIn, lstName, phTMOut, pEnd, fCase) * Entry hTMIn = handle to parent (class) TM * lstName = lenth prefixed name string * phTMOut = pointer to handle to receive bound child TM * pEnd = pointer to int to receive index of char that ended parse * fCase = case sensitivity (TRUE is case sensitive) * pExState points to the parent TM and is preserved * Exit *phTMOut = handle to parsed and bound TM * corresponding to static data member * Returns EESTATUS */ EESTATUS BindStMember ( HTM hTMIn, const char *lstName, PHTM phTMOut, ulong *pEnd, SHFLAG fCase ) { EEHSTR hDStr = 0; pexstate_t pExStateSav = pExState; PCXT pCxtSav = pCxt; uint len; ulong plen; ulong excess; char *pDStr; char *pStrP; EESTATUS retval; DASSERT (lstName); // get parent string pStrP = (char *) MemLock (pExState->hExStr); plen = pExState->strIndex; excess = pExState->ExLen - plen; len = *lstName; if ((hDStr = MemAllocate (plen + excess + len + 4)) == 0) { pExState->err_num = ERR_NOMEMORY; return EEGENERAL; } pDStr = (char *) MemLock (hDStr); *pDStr++ = '('; memcpy (pDStr, pStrP, plen); pDStr += plen; *pDStr++ = ')'; *pDStr++ = '.'; memcpy (pDStr, lstName+1, len); pDStr += len; memcpy (pDStr, pStrP + plen, excess); pDStr += excess; *pDStr = 0; MemUnLock (hDStr); MemUnLock (pExState->hExStr); if ( OP_context == StartNodeOp (hTMIn)) { // if the parent expression contains a global context // shift the context string to the very left of // the child expression (so that this becomes a // global context of the child expression too) LShiftCxtString ( hDStr ); } retval = ParseBind (hDStr, hTMIn, phTMOut, pEnd, BIND_fSupOvlOps, fCase); pExState = pExStateSav; pCxt = pCxtSav; return retval; } /*** QChildFcnBind - Quick bind of a child TM that represents a function * success = QChildFcnBind (hTMOut, pvP, pv, hName) * Entry hTMOut = handle to the child TM * pvP = evaluation node of the parent TM (a class) * pv = evaluation node of the child (a function) * hName = handle to (non-qualified) function name * Exit *phTMOut updated * Returns TRUE on success, FALSE otherwise */ bool_t QChildFcnBind ( HTM hTMOut, peval_t pvP, peval_t pv, EEHSTR hName ) { HTYPE hClass; HDEP hQual; char *pQual; char *pName; uint lenCl; uint lenSav; peval_t pvR; pexstate_t pTMOut; char *pField; uint fSkip = 0; char *pc; search_t Temp; psearch_t pTemp = &Temp; HR_t search; pTMOut = (pexstate_t) MemLock(hTMOut); pvR = &pTMOut->result; memcpy(pvR, pv, sizeof (eval_t)); EVAL_STATE(pvR) = EV_type; if ((hClass = THGetTypeFromIndex (EVAL_MOD (pvP), EVAL_TYP (pvP))) != 0) { pField = (char *)(&((TYPPTR)MHOmfLock (hClass))->leaf); switch (((plfClass)pField)->leaf) { case LF_CLASS: case LF_STRUCTURE: fSkip = offsetof (lfClass, data); RNumLeaf (pField + fSkip, &fSkip); pc = pField + fSkip; break; case LF_UNION: fSkip = offsetof (lfUnion, data); RNumLeaf (pField + fSkip, &fSkip); pc = pField + fSkip; break; default: MHOmfUnLock (hClass); MemUnLock(hTMOut); return FALSE; } lenCl = *pc++; pName = (char *) MemLock (hName); lenSav = _tcslen(pName); if ((hQual = MemAllocate(lenCl+2+lenSav+1)) == 0) { MemUnLock(hTMOut); return FALSE; } // form qualified name pQual = (char *) MemLock(hQual); memcpy (pQual, pc, lenCl); *(pQual+lenCl) = ':'; *(pQual+lenCl+1) = ':'; memcpy (pQual+lenCl+2, pName, lenSav+1); memset (pTemp, 0, sizeof (*pTemp)); MemUnLock(hName); pTemp->pfnCmp = (PFNCMP) FNCMP; pTemp->pv = pv; pTemp->CXTT = *pCxt; pTemp->sstr.lpName = (uchar *) pQual; pTemp->sstr.cb = (uchar)_tcslen ((char *)pQual); pTemp->state = SYM_init; pTemp->scope = SCP_module | SCP_global; pTemp->sstr.searchmask |= SSTR_proc; pTemp->initializer = INIT_qual; pTemp->typeOut = EVAL_TYP (pv); search = SearchSym (pTemp); MemUnLock (hQual); MemFree (hQual); if (search != HR_found) { FCN_NOTPRESENT (pvR) = TRUE; } else { // pop off the stack entry that a successful search found. Move the // static data member flag first so that it will not be lost. EVAL_IS_STMEMBER (ST) = EVAL_IS_STMEMBER (pvR); //*pvR = *(ST); PopStack (); } pTMOut->state.bind_ok = TRUE; MHOmfUnLock (hClass); } MemUnLock(hTMOut); return TRUE; } /*** SetFcniParm - Set a node to a specified parameter of a function * fFound = SetFcniParm (pv, ordinal, pHStr) * Entry pv = pointer to node to be initialized * ordinal = number of struct element to initialize for * (zero based) * pHStr = pointer to handle for parameter name * Exit pv initialized if no error * *pHStr = handle for name * Returns EENOERROR if parameter found * EEGENERAL if parameter not found * This routine is essentially a kludge. We are depending upon the * the compiler to output the formals in order of declaration before * any of the hidden parameters or local variables. We also are * depending upon the presence of an S_END record to break us out of * the search loop. */ static HSYM lastFunc = 0; static HSYM lastParm = 0; static long lastOrdinal = 0; ulong SetFcniParm ( peval_t pv, long ordinal, PEEHSTR pHStr ) { char *pStr; HSYM hSym; SYMPTR pSym; ulong offset; ulong len; bool_t retval; long tmpOrdinal; bool_t checkThis = FALSE; if ((ordinal > FCN_PCOUNT (pv)) || ((ordinal == (FCN_PCOUNT (pv) - 1)) && (FCN_VARARGS (pv) == TRUE))) { // attempting to reference a vararg or too many parameters pExState->err_num = ERR_FCNERROR; return (EEGENERAL); } hSym = EVAL_HSYM (pv); //try to start up where we where last time instead of swimming thru // the entire list again // sps - 11/25/92 tmpOrdinal = ordinal; if ((hSym == lastFunc) && (ordinal > lastOrdinal)) { ordinal -= (lastOrdinal + 1); //zero based step function hSym = lastParm; } else { lastFunc = hSym; checkThis = TRUE; } lastOrdinal = tmpOrdinal; for (;;) { if ((hSym = SHNextHsym (EVAL_MOD (pv), hSym)) == 0) { goto ErrReturn; } // lock the symbol and check the type pSym = (SYMPTR) MHOmfLock (hSym); switch (pSym->rectyp) { case S_BPREL16: if (((BPRELPTR16)pSym)->off >= 0) { // This is a formal argument ordinal--; len = ((BPRELPTR16)pSym)->name[0]; offset = offsetof (BPRELSYM16, name) + sizeof (char); } break; case S_BPREL32: if (((BPRELPTR32)pSym)->off >= 0) { // This is a formal argument len = ((BPRELPTR32)pSym)->name[0]; offset = offsetof (BPRELSYM32, name) + sizeof (char); if ((len == 12) && (_tcsncmp((_TXCHAR *) ((BPRELPTR32)pSym)->name+1, "__$ReturnUdt", len) == 0)) { break; } ordinal--; } break; case S_REGREL32: if (((LPREGREL32)pSym)->off >= 0) { // Formal parameter len = ((LPREGREL32)pSym)->name[0]; offset = offsetof (REGREL32, name[1]); // Dolphin 7908 // Intel's 'this' has negative offset but Mips // has offset 0 so special case if (checkThis && EVAL_IS_METHOD(pv) && (len == (ulong)OpName[0].str[0]) && (_tcsncmp((_TXCHAR *) ((LPREGREL32)pSym)->name+1, OpName[0].str+1, len) == 0)) { checkThis = FALSE; break; } checkThis = FALSE; if ((len == 12) && (_tcsncmp((_TXCHAR *) ((LPREGREL32)pSym)->name+1, "__$ReturnUdt", len) == 0)) { break; } ordinal--; } break; case S_REGISTER: // ALPHA parameters are homed when compiled with debugging // but this pointer may be kept in a register if (FCN_CALL (pv) == FCN_ALPHA) { break; } #if 0 // this can be a formal argument for fastcall if (FCN_CALL (pv) == FCN_FAST) { ordinal--; len = ((REGPTR)pSym)->name[0]; offset = offsetof (BPRELSYM16, name) + sizeof (char); } else { MHOmfUnLock (hSym); goto ErrReturn; } #endif ordinal--; len = ((REGPTR)pSym)->name[0]; offset = offsetof (REGSYM, name) + sizeof (char); break; case S_END: case S_BLOCK16: case S_BLOCK32: case S_ENDARG: // we should never get here MHOmfUnLock (hSym); goto ErrReturn; default: break; } if (ordinal < 0) { break; } MHOmfUnLock (hSym); } // if we get here, pSym points to the symbol record for the parameter if ((*pHStr = MemAllocate (len + 1)) != 0) { pStr = (char *) MemLock (*pHStr); _tcsncpy (pStr, ((char *)pSym) + offset, len); *(pStr + len) = 0; MemUnLock (*pHStr); retval = EENOERROR; } else { MHOmfUnLock (hSym); goto ErrReturn; } lastParm = hSym; MHOmfUnLock (hSym); return (retval); ErrReturn: lastFunc = lastParm = 0; lastOrdinal = 0; pExState->err_num = ERR_BADOMF; return (EEGENERAL); } bool_t ResolveAddr( peval_t pv ) { UOFFSET ul; ADDR addr; SHREG reg; /* * Fixup BP Relative addresses. The BP register always comes in * as part of the frame. * This form is currently only used by x86 systems. */ if (EVAL_IS_BPREL (pv)) { SYGetAddr(pExState->hframe, &addr, adrBase); EVAL_SYM_OFF (pv) += GetAddrOff(addr); EVAL_SYM_SEG (pv) = GetAddrSeg(addr); EVAL_SYM_EMI (pv) = NULL; EVAL_IS_BPREL (pv) = FALSE; ADDR_IS_LI (EVAL_SYM (pv)) = FALSE; SHUnFixupAddr (&EVAL_SYM (pv)); } /* * Fixup register relative addresses. This form is currently used * by all non-x86 systems. * We need to see if we are relative to the "Frame register" for the * machine. If so then we need to pick the address up from the * frame packet rather than going out and getting the register * directly. This has implications for getting variables up a stack. * This code is from windbg's EE. It used to reference pCxt but that will * fault when called from EEInfoFromTM so I've changed it to reference * pExState->cxt instead. [Dolphin 13042] */ // We get to simplify this code somewhat. Since we now have a magic // cookie corresponding to a specific frame, we can now go directly to // GetRegistr for all register relative variables. We automatically // get the register corresponding to the frame we want. else if (EVAL_IS_REGREL (pv)) { reg.hReg = EVAL_REGREL (pv); if ((TargetMachine == mptmips) && (reg.hReg == CV_M4_IntSP || reg.hReg == CV_M4_IntS8)) { ADDR addrBP; SYGetAddr(pExState->hframe, &addrBP, adrBase); if (reg.hReg == CV_M4_IntS8) { // See if we're Top of Stack reg.hReg = CV_M4_IntSP; if (GetReg(®, &pExState->cxt, NULL) == NULL) { DASSERT (FALSE); } else { ul = reg.Byte4; if (ul == addrBP.addr.off) { reg.hReg = CV_M4_IntS8; // Yes, then use S8 if (GetReg(®, &pExState->cxt, NULL) == NULL) { DASSERT(FALSE); } else { ul = reg.Byte4; } } else { ul = addrBP.addr.off; } } } else { ul = addrBP.addr.off; } if (pExState->cxt.hProc) { SYMPTR pSym = (SYMPTR) MHOmfLock(pExState->cxt.hProc); if ((pSym->rectyp == S_LPROCMIPS) || (pSym->rectyp == S_GPROCMIPS)) { if (((PROCPTRMIPS)pSym)->pParent) { // nested? HSYM hSLink32 = SHFindSLink32(&pExState->cxt); CXT cxtChild; ADDR addr = {0}; if (hSLink32) { SLINK32* pSLink32 = (SLINK32*) MHOmfLock(hSLink32); reg.hReg = pSLink32->reg; if (reg.hReg != CV_M4_IntSP && reg.hReg != CV_M4_IntS8) { if (GetReg(®, &pExState->cxt, NULL) == NULL) { DASSERT (FALSE); } else { ul = reg.Byte4; } } if (pSLink32->off != 0) { addr.addr.off = ul + pSLink32->off; ADDR_IS_OFF32(addr) = TRUE; ADDR_IS_FLAT(addr) = TRUE; GetDebuggeeBytes(addr, sizeof(UOFF32), &ul, T_ULONG); } cxtChild = pExState->cxt; cxtChild.hBlk = 0; for (;;) { CXT cxtParent; HSYM parent = SHGoToParent(&cxtChild, &cxtParent); if (parent) { SYMPTR pParent = MHOmfLock(parent); switch (pParent->rectyp) { case S_BLOCK16: case S_BLOCK32: cxtChild = cxtParent; continue; case S_GPROCMIPS: case S_LPROCMIPS: if (((PROCPTRMIPS)pParent)->pParent) { addr.addr.off = ul - 4; cxtChild = cxtParent; ADDR_IS_OFF32(addr) = TRUE; ADDR_IS_FLAT(addr) = TRUE; GetDebuggeeBytes(addr, sizeof(UOFF32), &ul, T_ULONG); break; } // Fall through default: pParent = 0; break; } MHOmfUnLock(parent); if (!pParent) { break; } } } #pragma message("Stack will always grow down, right?") ul -= pSLink32->framesize; MHOmfUnLock(hSLink32); } } } MHOmfUnLock(pExState->cxt.hProc); } } else if ((TargetMachine == mptdaxp) && (reg.hReg == CV_ALPHA_IntSP || reg.hReg == CV_ALPHA_IntFP)) { ADDR addrBP; SYGetAddr(pExState->hframe, &addrBP, adrBase); if (reg.hReg == CV_ALPHA_IntFP) { // See if we're Top of Stack reg.hReg = CV_ALPHA_IntSP; if (GetReg(®, &pExState->cxt, NULL) == NULL) { DASSERT (FALSE); } else { ul = reg.Byte8i; if (ul == addrBP.addr.off) { reg.hReg = CV_ALPHA_IntFP; // Yes, then use FP if (GetReg(®, &pExState->cxt, NULL) == NULL) { DASSERT(FALSE); } else { ul = reg.Byte8i; } } else { ul = addrBP.addr.off; } } } else { ul = addrBP.addr.off; } if (pExState->cxt.hProc) { SYMPTR pSym = (SYMPTR) MHOmfLock(pExState->cxt.hProc); if ((pSym->rectyp == S_LPROC32) || (pSym->rectyp == S_GPROC32)) { if (((PROCPTR32)pSym)->pParent) { // nested? HSYM hSLink32 = SHFindSLink32(&pExState->cxt); CXT cxtChild; ADDR addr = {0}; if (hSLink32) { SLINK32* pSLink32 = (SLINK32*) MHOmfLock(hSLink32); reg.hReg = pSLink32->reg; if (reg.hReg != CV_ALPHA_IntSP && reg.hReg != CV_ALPHA_IntFP) { if (GetReg(®, &pExState->cxt, NULL) == NULL) { DASSERT (FALSE); } else { ul = reg.Byte8i; } } if (pSLink32->off != 0) { addr.addr.off = ul + pSLink32->off; ADDR_IS_OFF32(addr) = TRUE; ADDR_IS_FLAT(addr) = TRUE; GetDebuggeeBytes(addr, sizeof(UOFF32), &ul, T_ULONG); } cxtChild = pExState->cxt; cxtChild.hBlk = 0; for (;;) { CXT cxtParent; HSYM parent = SHGoToParent(&cxtChild, &cxtParent); if (parent) { SYMPTR pParent = MHOmfLock(parent); switch (pParent->rectyp) { case S_BLOCK16: case S_BLOCK32: cxtChild = cxtParent; continue; default: pParent = 0; break; } MHOmfUnLock(parent); if (!pParent) { break; } } } #pragma message("Stack will always grow down, right?") ul -= pSLink32->framesize; MHOmfUnLock(hSLink32); } } } MHOmfUnLock(pExState->cxt.hProc); } } else if ((TargetMachine == mptia64) && (reg.hReg == CV_IA64_IntSp)) { ADDR addrBP; SYGetAddr(pExState->hframe, &addrBP, adrBase); ul = addrBP.addr.off; if (pExState->cxt.hProc) { SYMPTR pSym = (SYMPTR) MHOmfLock(pExState->cxt.hProc); if ((pSym->rectyp == S_LPROCIA64) || (pSym->rectyp == S_GPROCIA64)) { if (((PROCPTRMIPS)pSym)->pParent) { // nested? HSYM hSLink32 = SHFindSLink32(&pExState->cxt); CXT cxtChild; ADDR addr = {0}; if (hSLink32) { SLINK32* pSLink32 = (SLINK32*) MHOmfLock(hSLink32); reg.hReg = pSLink32->reg; if (reg.hReg != CV_IA64_IntSp) { if (GetReg(®, &pExState->cxt, NULL) == NULL) { DASSERT (FALSE); } else { ul = reg.Byte4; } } if (pSLink32->off != 0) { addr.addr.off = ul + pSLink32->off; ADDR_IS_OFF32(addr) = TRUE; ADDR_IS_FLAT(addr) = TRUE; GetDebuggeeBytes(addr, sizeof(UOFF32), &ul, T_ULONG); } cxtChild = pExState->cxt; cxtChild.hBlk = 0; for (;;) { CXT cxtParent; HSYM parent = SHGoToParent(&cxtChild, &cxtParent); if (parent) { SYMPTR pParent = MHOmfLock(parent); switch (pParent->rectyp) { case S_BLOCK16: case S_BLOCK32: cxtChild = cxtParent; continue; case S_GPROCIA64: case S_LPROCIA64: //v-vadimp 64-bit? if (((PROCPTRIA64)pParent)->pParent) { addr.addr.off = ul - 4; cxtChild = cxtParent; ADDR_IS_OFF32(addr) = TRUE; ADDR_IS_FLAT(addr) = TRUE; GetDebuggeeBytes(addr, sizeof(UOFF32), &ul, T_ULONG); break; } // Fall through default: pParent = 0; break; } MHOmfUnLock(parent); if (!pParent) { break; } } } #pragma message("Stack will always grow down, right?") ul -= pSLink32->framesize; MHOmfUnLock(hSLink32); } } } MHOmfUnLock(pExState->cxt.hProc); } } else if (GetReg (®, &pExState->cxt, NULL) == NULL) { DASSERT (FALSE); } else { ul = reg.Byte4; if (!ADDR_IS_OFF32(*SHpADDRFrompCXT(&pExState->cxt))) { ul &= 0xffff; } } EVAL_SYM_OFF (pv) += ul; EVAL_SYM_SEG (pv) = GetSegmentRegister(pExState->hframe, REG_SS); EVAL_IS_REGREL (pv) = FALSE; ADDR_IS_LI (EVAL_SYM (pv)) = FALSE; emiAddr (EVAL_SYM (pv)) = 0; SHUnFixupAddr (&EVAL_SYM (pv)); } /* * Fixup Thread local storage relative addresses. This form is * currently used by all platforms. */ else if (EVAL_IS_TLSREL (pv)) { DASSERT(FALSE); // This EE treats THREAD32 like DATA32 and expects // DM to "do the right thing" EVAL_IS_TLSREL( pv ) = FALSE; /* * Query the EM for the TLS base on this (current) thread */ memset(&addr, 0, sizeof(ADDR)); emiAddr( addr ) = emiAddr( EVAL_SYM( pv )); // SYGetAddr(&addr, adrTlsBase); EVAL_SYM_OFF( pv ) += GetAddrOff(addr); EVAL_SYM_SEG( pv ) = GetAddrSeg(addr); ADDR_IS_LI (EVAL_SYM( pv )) = ADDR_IS_LI (addr); emiAddr(EVAL_SYM( pv )) = 0; SHUnFixupAddr( &EVAL_SYM( pv )); } else if (EVAL_IS_REGRELIA64(pv)) { DASSERT(!"v-vadimp may need code for isregrelia64"); } else if (EVAL_IS_REGIA64(pv)) { DASSERT(!"v-vadimp may need code for isregia64"); } return TRUE; } /* ResolveAddr() */ /*** StartNodeOp - Get Start Node operator of a TM * OP = StartNodeOp (hTM) * Entry hTM = handle to TM * Exit None * Returns OP_... operator found in root node of TM */ op_t StartNodeOp ( HTM hTM ) { pexstate_t pTM; pstree_t pTreeSav; op_t retval; DASSERT (hTM); pTreeSav = pTree; pTM = (pexstate_t) MemLock(hTM); DASSERT (pTM->hSTree); pTree = (pstree_t) MemLock(pTM->hSTree); retval = NODE_OP((bnode_t) (pTree->start_node)); pTree = pTreeSav; MemUnLock (pTM->hSTree); MemUnLock (hTM); return retval; } /*** LShiftCxtString - Left Shift Context String * void LShiftCxtString( hStr ) * Entry hStr = handle to expression string * Exit Modifies expression string by shifting the * first context string it encounters (i.e., a * string enclosed in "{}") to the very left of * the expression. * Returns void */ void LShiftCxtString ( EEHSTR hStr ) { LSZ szExpr; HDEP hBuf; char *pBuf; char *pStart; char *pEnd; ulong len; ulong lenCxt; DASSERT (hStr); szExpr = (LSZ) MemLock (hStr); pStart = _tcschr (szExpr, '{'); pEnd = _tcschr (szExpr, '}'); if (pStart) { DASSERT (pEnd); // length of the expression at the left of the context len = (ulong)(pStart - szExpr); // length of the context string lenCxt = (ulong)(pEnd - pStart + 1); if ((hBuf = MemAllocate ( len + 1 )) != 0) { pBuf = (char *) MemLock (hBuf); // save leftmost part of the expression to temp. buffer // Then shift context to the left and copy saved part memcpy (pBuf, szExpr, len); memmove (szExpr, pStart, lenCxt); memcpy (szExpr + lenCxt, pBuf, len); MemUnLock (hBuf); MemFree (hBuf); } else { char ch; // shift context in place for (; pStart > szExpr; pStart--) { ch = * (pStart - 1); memmove (pStart - 1, pStart, lenCxt); * (pStart + lenCxt - 1) = ch; } } } MemUnLock ((HDEP) szExpr); } /*** GetParentSubtree - Get parent subtree * bnParent = GetParentSubtree(bnRoot, seTemplate) * Entry bnRoot = based pointer to root of child eval tree * seTemplate = SE_t template used for generating child expr. * Exit none * Returns based pointer to subtree that corresponds to parent expr. */ bnode_t GetParentSubtree ( bnode_t bnRoot, SE_t seTemplate ) { bnode_t bn = bnRoot; // skip optional initial context if (NODE_OP (bn) == OP_context) bn = NODE_LCHILD (bn); switch (seTemplate) { case SE_ptr: // parent expression is identical with child expression break; case SE_deref: // Dolphin #8336: // DereferenceTM may generate two kinds of expressions // "*(parent_expression)" or // "(parent_expression)" for references only // In that case we shouldn't be checking for OP_fetch if (NODE_OP (bn) == OP_fetch) bn = NODE_LCHILD (bn); break; case SE_array: DASSERT ( NODE_OP (bn) == OP_lbrack ); if (NODE_OP (bn) != OP_lbrack) break; bn = NODE_LCHILD (bn); break; case SE_member: DASSERT ( NODE_OP (bn) == OP_dot ); if (NODE_OP (bn) != OP_dot) break; bn = NODE_LCHILD (bn); break; case SE_bclass: DASSERT (NODE_OP (bn) == OP_fetch); if (NODE_OP (bn) != OP_fetch) break; bn = NODE_LCHILD (bn); DASSERT (NODE_OP (bn) == OP_cast); if (NODE_OP (bn) != OP_cast) break; bn = NODE_RCHILD (bn); DASSERT (NODE_OP (bn) == OP_addrof); if (NODE_OP (bn) != OP_addrof) break; bn = NODE_LCHILD (bn); break; case SE_downcast: DASSERT (NODE_OP (bn) == OP_fetch); if (NODE_OP (bn) != OP_fetch) break; bn = NODE_LCHILD (bn); DASSERT (NODE_OP (bn) == OP_cast); if (NODE_OP (bn) != OP_cast) break; bn = NODE_RCHILD (bn); // skip optional context if (NODE_OP (bn) == OP_context) bn = NODE_LCHILD (bn); break; case SE_derefmember: // member obtained after dereferencing parent expr. // (*()). DASSERT ( NODE_OP (bn) == OP_dot ); if (NODE_OP (bn) != OP_dot) break; bn = NODE_LCHILD (bn); if (NODE_OP (bn) == OP_fetch) bn = NODE_LCHILD (bn); break; case SE_downcastmember: // member obtained after downcasting parent expr: // {,,}(*(*){*}()). DASSERT ( NODE_OP (bn) == OP_dot ); if (NODE_OP (bn) != OP_dot) break; bn = NODE_LCHILD (bn); DASSERT (NODE_OP (bn) == OP_fetch); if (NODE_OP (bn) != OP_fetch) break; bn = NODE_LCHILD (bn); DASSERT (NODE_OP (bn) == OP_cast); if (NODE_OP (bn) != OP_cast) break; bn = NODE_RCHILD (bn); // skip optional context if (NODE_OP (bn) == OP_context) bn = NODE_LCHILD (bn); break; default: bn = 0; break; } return bn; } /*** LinkWithParentTM - Create a link between a child and parent TM * void LinkWithParentTM (hTM, hParentTM) * Entry hTM = handle to child TM * hParentTM = handle to parent TM * Exit Links the child TM with the parent TM * Returns void */ void LinkWithParentTM( HTM hTM, HTM hParentTM ) { pexstate_t pTM; pexstate_t pParentTM; DASSERT ( hTM ); DASSERT ( hParentTM ); pTM = (pexstate_t) MemLock (hTM); pParentTM = (pexstate_t) MemLock (hParentTM); pTM->hParentTM = hParentTM; (pParentTM -> nRefCount) ++; MemUnLock (hTM); MemUnLock (hParentTM); } /*** GetDerivedTM - Get TM derived from parent TM using an expansion rule * status = GetDerivedTM (hTMIn, lszRule, phTMOut) * Entry hTMIN = handle to the parent TM * lsz = string containing expansion rule * in the form: member_name * or: member_name,format_specifier * phTMOut = pointer to handle for the child TM * Exit *phTMOut contains the handle of the child TM that was created * The derived expression is one of the following: * a) if hTMIn is a ptr that needs no downcasting: * (*()). * b) if hTMIn is a ptr that can be downcast: * {,,}(*(*){*}()). * c) if hTMIn is a class: * (). * Returns EESTATUS */ EESTATUS GetDerivedTM ( HTM hTMIn, LSZ lszRule, HTM *phTMOut ) { uint lenP; uint len; uint lenName; uint lenCXT; uint lenD; uint cchExtra; char *pch; EEHSTR hName; EEHSTR hDStr; LSZ pName; LSZ pDStr; LSZ lsz; ulong end; bool_t fCase; EESTATUS retval; SE_t seTemplate; bool_t fDeref = FALSE; bool_t fDownCast = FALSE; bool_t fSimpleIdent = TRUE; uint index = 0; DASSERT (hTMIn); pExState = (pexstate_t) MemLock (hTMIn); // set flag if parent expression needs to be dereferenced fDeref = EVAL_IS_PTR (&pExState->result) && !EVAL_IS_REF (&pExState->result); lenP = pExState->strIndex; //ignore parent's format string len = _tcslen (lszRule); // find the length of the name string contained in sz // (sz may contain a format string after the name string // delimited with a comma) lenName = ((pch = _tcschr (lszRule, _T(','))) != NULL) ? (uint)(pch - lszRule) : len; // check if the autoexpand name part is a simple identifier. // No MBCS considertions these should be valid C identifiers. for (index = 0; index < lenName; index++ ) { char ch = lszRule[index]; if (!isalnum(ch) && ch != '_') { fSimpleIdent = FALSE; break; } } // the derived expression will be: // (*()). or // {,,}(*(*){*}()). // (). // depending on whether the parent expression needs // to be dereferenced or downcast // The corresponding new strings contain 6 and 3 extra // characters respectively cchExtra = fDeref ? 6 : 3; if (pExState->hDClassName) { lsz = (char *) MemLock (pExState->hDClassName); lenD = _tcslen(lsz); MemUnLock (pExState->hDClassName); if (fDeref) cchExtra += lenD + 6; } if ((hName = MemAllocate ( lenName + 1 )) == NULL || (hDStr = MemAllocate ( lenP + len + cchExtra + 1)) == NULL ) { pExState->err_num = ERR_NOMEMORY; if (hName) MemFree (hName); MemUnLock (hTMIn); return EEGENERAL; } pName = (char *) MemLock (hName); memcpy (pName, lszRule, lenName); *(pName + lenName) = 0; MemUnLock (hName); pDStr = (char *) MemLock (hDStr); pExStr = (char *) MemLock (pExState->hExStr); if (fDeref) { if (pExState->hDClassName == NULL) { // (*()). seTemplate = SE_derefmember; memcpy (pDStr, "(*(", 3); memcpy (pDStr + 3, pExStr, lenP); memcpy (pDStr + 3 + lenP, ")).", 3); memcpy (pDStr + 6 + lenP, lszRule, len); * (pDStr + 6 + lenP + len) = 0; } else { fDownCast = TRUE; // {,,}(*(*)()). lsz = (char *) MemLock (pExState->hDClassName); if ((pch = _tcschr (lsz, '}')) != NULL) pch ++; else pch = lsz; lenCXT = (uint)(pch - lsz); seTemplate = SE_downcastmember; pch = pDStr; memcpy (pch, lsz, lenCXT); pch += lenCXT; memcpy (pch, "(*(", 3); pch += 3; memcpy (pch, lsz + lenCXT, lenD - lenCXT); pch += lenD - lenCXT; memcpy (pch, "*){*}(", 6); pch += 6; memcpy (pch, pExStr, lenP); pch += lenP; memcpy (pch, ")).", 3); pch += 3; memcpy (pch, lszRule, len); pch += len; *pch = 0; MemUnLock (pExState->hDClassName); } } else { // (). seTemplate = SE_member ; * pDStr = '('; memcpy (pDStr + 1, pExStr, lenP); memcpy (pDStr + 1 + lenP, ").", 2); memcpy (pDStr + 3 + lenP, lszRule, len); * (pDStr + 3 + lenP + len) = 0; } MemUnLock (pExState->hExStr); MemUnLock (hDStr); // if we have a complex auto-expand rule such as a.b->c don't set the template type. // The relation between the in-coming TM and the resulting TM in this case cannot be expressed // as a single operation. if (!fSimpleIdent) { seTemplate = SE_totallynew ; } if ( !fDownCast && OP_context == StartNodeOp (hTMIn)) { // if the parent expression contains a global context // shift the context string to the very left of // the child expression (so that this becomes a // global context of the child expression too) LShiftCxtString ( hDStr ); } fCase = pExState->state.fCase; MemUnLock (hTMIn); retval = ParseBind (hDStr, hTMIn, phTMOut, &end, BIND_fSupOvlOps, fCase); if (EENOERROR == retval) { pExState = (pexstate_t) MemLock (*phTMOut); pExState->state.childtm = TRUE; pExState->state.autoexpand = TRUE; pExState->hCName = hName; if ((pExState->seTemplate = seTemplate) != SE_totallynew) { // don't increment parent TM's ref count // since this TM has the same lifetime with its parent pExState->hParentTM = hTMIn; } MemUnLock (*phTMOut); } else { MemFree (hName); if (*phTMOut) EEFreeTM (phTMOut); } return retval; } uint uSkipLfOneMethod( plfOneMethod plf ) { uint uVbase = fIntroducingVirtual(plf->attr.mprop) ? sizeof(long) : 0; return sizeof (struct lfOneMethod) + 1 + uVbase + ((char *)(plf->vbaseoff))[uVbase]; } char * pbNameInLfOneMethod( plfOneMethod plf ) { return (char *)plf + offsetof(lfOneMethod, vbaseoff) + (fIntroducingVirtual(plf->attr.mprop) ? sizeof(long) : 0); } SEGMENT GetSegmentRegister(HFRAME hframe, int iWhich) { SHREG spReg; if (TargetMachine != mptix86) { return 0; } spReg.hReg = iWhich; GetReg(&spReg, NULL, hframe); return spReg.Byte2; }