/*** DEBSYM.C - symbol lookup routines for expression evaluator * * */ extern bool_t FNtsdEvalType; // enum specifying return from IsDominated typedef enum { DOM_ambiguous, DOM_keep, DOM_replace } DOM_t; // Return values from SearchClassName typedef enum { SCN_error, // error, abort search SCN_notfound, // not found SCN_found, // found SCN_rewrite // found and this pointer inserted } SCN_t; // Return values from MatchMethod typedef enum { MTH_error, // error - abort search MTH_found // found without error } MTH_t; typedef struct HSL_restart_t { search_t Name; HSYM hSym; HSYML_t state; ushort mask; } HSL_restart_t; static char *vtabptr = "#vptr#"; static HDEP hSymClass = 0; static psymclass_t pSymClass = NULL; static HDEP hVBDom = 0; static pdombase_t pVBDom = NULL; static HDEP hVBSearch = 0; static pdombase_t pVBSearch = NULL; static psearch_t pNameFirst = NULL; LOCAL pnode_t AddETConst (pnode_t, OFFSET, CV_typ_t); LOCAL pnode_t AddETExpr (pnode_t, CV_typ_t, OFFSET, OFFSET, CV_typ_t); LOCAL pnode_t AddETInit (pnode_t, CV_typ_t); LOCAL bool_t AddHSYM (psearch_t, HSYM, PHSL_HEAD, uint); LOCAL SCN_t AddVBList (psymclass_t, pdombase_t *, HDEP *); LOCAL SCN_t AddVBType (pdombase_t *, HDEP *, CV_typ_t); LOCAL ushort AmbFromList (psearch_t); LOCAL bool_t AmbToList (psearch_t); LOCAL HR_t ClAmbToList (psearch_t); LOCAL bool_t DebLoadConst (peval_t, CONSTPTR, HSYM); LOCAL SCN_t DupSymCl (psearch_t); LOCAL SCN_t FindIntro (psearch_t); LOCAL SCN_t GenQualExpr (psearch_t); LOCAL HDEP GenQualName (psearch_t, psymclass_t); LOCAL bool_t GrowTMList (void); LOCAL SCN_t IncrSymBase (void); LOCAL bool_t InitMod (psearch_t); LOCAL DOM_t IsDominated (psymclass_t, psymclass_t); LOCAL bool_t IsIntroVirt (ushort, CV_typ_t, ushort *); LOCAL bool_t LineNumber (psearch_t); LOCAL void MatchArgs (peval_t, psearch_t, CV_fldattr_t, UOFFSET, bool_t); LOCAL HR_t __fastcall MatchFunction (psearch_t); LOCAL void MoveSymCl (HDEP hSymCl); LOCAL SCN_t OverloadToAmbList (psearch_t, psymclass_t); LOCAL SCN_t MethodsToAmbList (psearch_t, psymclass_t); LOCAL bool_t ParseRegister (psearch_t); LOCAL void PurgeAmbCl (psearch_t); LOCAL SCN_t RecurseBase (psearch_t, CV_typ_t, CV_typ_t, OFFSET, OFFSET, CV_fldattr_t, bool_t); LOCAL SCN_t RemoveAmb (psearch_t); LOCAL SCN_t SearchBases (psearch_t); LOCAL SCN_t SearchBType (psearch_t); LOCAL SCN_t SearchClassName (psearch_t); LOCAL bool_t SearchQualName (psearch_t, psymclass_t, HDEP, bool_t); LOCAL SCN_t SearchRoot (psearch_t); LOCAL SCN_t SetBase (psearch_t, CV_typ_t, CV_typ_t, OFFSET, OFFSET, CV_fldattr_t, bool_t); LOCAL SCN_t SetBPValue (psearch_t); LOCAL SCN_t SetValue (psearch_t); LOCAL HR_t SymAmbToList (psearch_t); LOCAL bool_t SymToNode (psearch_t); LOCAL bool_t VBSearched (CV_typ_t); LOCAL bool_t VBaseFound (psearch_t); LOCAL CV_typ_t SkipModifiers(HMOD, CV_typ_t); LOCAL bool_t CheckDupAmb ( psearch_t ); LOCAL bool_t __fastcall InsertThis (psearch_t); LOCAL MTH_t MatchMethod (psearch_t, psymclass_t); __inline BOOL getBaseDefnFromDecl( CV_typ_t typeIn, peval_t pv, CV_typ_t* ptypeOut) { peval_t pvBase = &pSymClass->symbase[pSymClass->CurIndex].Base; Unreferenced (pv); return getDefnFromDecl (typeIn, pvBase, ptypeOut); } __inline unsigned char SkipPad( unsigned char *pb) { if (*pb >= LF_PAD0) { // there is a pad field return(*pb & 0x0f); } return(0); } OPNAME OpName[] = { {"\x004""this"}, // OP_this {"\x00b""operator->*"}, // OP_Opmember {"\x00b""operator>>="}, // OP_Orightequal {"\x00b""operator<<="}, // OP_Oleftequal {"\x00a""operator()"}, // OP_Ofunction {"\x00a""operator[]"}, // OP_Oarray {"\x00a""operator+="}, // OP_Oplusequal {"\x00a""operator-="}, // OP_Ominusequal {"\x00a""operator*="}, // OP_Otimesequal {"\x00a""operator/="}, // OP_Odivequal {"\x00a""operator%="}, // OP_Opcentequal {"\x00a""operator&="}, // OP_Oandequal {"\x00a""operator^="}, // OP_Oxorequal {"\x00a""operator|="}, // OP_Oorequal {"\x00a""operator<<"}, // OP_Oshl {"\x00a""operator>>"}, // OP_Oshr {"\x00a""operator=="}, // OP_Oequalequal {"\x00a""operator!="}, // OP_Obangequal {"\x00a""operator<="}, // OP_Olessequal {"\x00a""operator>="}, // OP_Ogreatequal {"\x00a""operator&&"}, // OP_Oandand {"\x00a""operator||"}, // OP_Ooror {"\x00a""operator++"}, // OP_Oincrement {"\x00a""operator--"}, // OP_Odecrement {"\x00a""operator->"}, // OP_Opointsto {"\x009""operator+"}, // OP_Oplus {"\x009""operator-"}, // OP_Ominus {"\x009""operator*"}, // OP_Ostar {"\x009""operator/"}, // OP_Odivide {"\x009""operator%"}, // OP_Opercent {"\x009""operator^"}, // OP_Oxor {"\x009""operator&"}, // OP_Oand {"\x009""operator|"}, // OP_Oor {"\x009""operator~"}, // OP_Otilde {"\x009""operator!"}, // OP_Obang {"\x009""operator="}, // OP_Oequal {"\x009""operator<"}, // OP_Oless {"\x009""operator>"}, // OP_Ogreater {"\x009""operator,"}, // OP_Ocomma {"\x012""operator new"}, // OP_Onew {"\x015""operator delete"} // OP_Odelete }; extern char Suffix; // Symbol searching and search initialization routines /** InitSearchBase - initialize search for base class * * InitSearchBase (bnOp, typD, typ, pName, pv) * * Entry bnOp = based pointer to OP_cast node * bn = based pointer to cast string * typD = type of derived class * typB = type of desired base class * pName = pointer to symbol search structure * pv = pointer to value node * * Exit search structure initialized for SearchSym * * Returns pointer to search symbol structure */ void InitSearchBase ( bnode_t bnOp, CV_typ_t typD, CV_typ_t typB, psearch_t pName, peval_t pv ) { // set starting context for symbol search to current context _fmemset (pName, 0, sizeof (*pName)); pName->initializer = INIT_base; pName->pv = pv; pName->typeIn = typD; pName->typeOut = typB; pName->scope = SCP_class; pName->CXTT = *pCxt; pName->bn = 0; pName->bnOp = bnOp; pName->state = SYM_bclass; pName->CurClass = typD; } /** InitSearchtDef - initialize typedef symbol search * * InitSearctDef (pName, iClass, tDef, scope, clsmask) * * Entry iClass = initial class if explicit class reference * tDef = index of typedef * scope = mask describing scope of search * clsmask = mask describing permitted class elements * * Exit search structure initialized for SearchSym * * Returns pointer to search symbol structure */ void InitSearchtDef ( psearch_t pName, peval_t pv, ushort scope ) { char NullString = 0; // set starting context for symbol search to current context _fmemset (pName, 0, sizeof (*pName)); pName->initializer = INIT_tdef; pName->sstr.lpName = &NullString; pName->sstr.cb = 0; pName->pfnCmp = TDCMP; pName->scope = scope; pName->CXTT = *pCxt; pName->pv = pv; pName->typeIn = EVAL_TYP (pv); pName->sstr.searchmask |= SSTR_symboltype | SSTR_NoHash; pName->sstr.symtype = S_UDT; pName->state = SYM_init; } /** SearchCFlag - initialize compile flags symbol search * * SearchCFlag (pName, iClass, scope, clsmask) * * Entry pName = pointer to symbol search structure * * Exit search structure initialized for SearchSym * * Returns pointer to search symbol structure */ HSYM SearchCFlag ( void ) { search_t Name; CXT CXTTOut; // set starting context for symbol search to current context _fmemset (&Name, 0, sizeof (Name)); Name.pfnCmp = CSCMP; Name.CXTT = *pCxt; Name.sstr.searchmask |= SSTR_symboltype; Name.sstr.symtype = S_COMPILE; if (InitMod (&Name) == TRUE) { SHGetCxtFromHmod (Name.hMod, &Name.CXTT); if ((Name.hSym = SHFindNameInContext (Name.hSym, &Name.CXTT, (LPSSTR)&Name, pExState->state.fCase, Name.pfnCmp, &CXTTOut)) != 0) { return (Name.hSym); } } // error in context initialization or compile flag symbol not found return (0); } /** SetAmbiant - set ambiant code or data model * * mode = SetAmbiant (flag) * * Entry flag = TRUE if ambiant data model * flag = FALSE if ambiant code model * * Exit none * * Returns ambiant model C7_... from the compile flags symbol * if the compile flags symbol is not found, C7_NEAR is returned */ CV_ptrmode_e SetAmbiant ( bool_t isdata ) { HSYM hCFlag; CFLAGPTR pCFlag; CV_ptrmode_e mode; Unreferenced( isdata ); if ((hCFlag = SearchCFlag ()) == 0) { // compile flag symbol not found, set model to near mode = (ADDR_IS_OFF32(*SHpADDRFrompCXT(pCxt))) ? CV_PTR_NEAR32 : CV_PTR_NEAR; } else { pCFlag = MHOmfLock ((HDEP)hCFlag); switch (pCFlag->flags.ambdata) { default: DASSERT (FALSE); case CV_CFL_DNEAR: // NOTENOTE Compiler is always sending us this one... // convert it to something appropriate sounding. mode = (ADDR_IS_OFF32(*SHpADDRFrompCXT(pCxt))) ? CV_PTR_NEAR32 : CV_PTR_NEAR; break; case CV_CFL_DFAR: mode = CV_PTR_FAR; break; case CV_CFL_DHUGE: mode = CV_PTR_HUGE; break; } MHOmfUnLock ((HDEP)hCFlag); } return (mode); } /** GetHSYMList - get HSYM list for context * * status = EEGetHSYMList (phSYMl, pCXT, mask, pRE, fEnableProlog) * * Entry phSYML = pointer to handle to symbol list * pCXT = pointer to context * mask = selection mask * pRE = pointer to regular expression * fEnableProlog = FALSE if function scoped symbols only after prolog * fEnableProlog = TRUE if function scoped symbols during prolog * * Exit *phMem = handle for HSYM list buffer * * Returns EENOERROR if no error * status code if error */ EESTATUS GetHSYMList ( HDEP *phSYML, PCXT pCxt, ushort mask, uchar *pRE, SHFLAG fEnableProlog ) { search_t Name = {0}; CXT CXTTOut; HSYM hSym = 0; PHSL_HEAD pHSLHead; HSYML_t state; HSL_restart_t *pRestart; bool_t fRestart; bool_t isprolog; bool_t fCaseSensitive = TRUE; if (mask & HSYMR_nocase) { mask &= ~HSYMR_nocase; fCaseSensitive = FALSE; } if (*phSYML == 0) { // allocate and initialize buffer if ((*phSYML = MHMemAllocate (HSYML_SIZE)) == 0) { return (EECATASTROPHIC); } pHSLHead = MHMemLock (*phSYML); _fmemset (pHSLHead, 0, HSYML_SIZE); pHSLHead->size = HSYML_SIZE; pHSLHead->blockcnt = 1; pHSLHead->remaining = HSYML_SIZE - sizeof ( HSL_HEAD ); pHSLHead->pHSLList = (PHSL_LIST)(((uchar *)pHSLHead) + sizeof (HSL_HEAD)); state = HSYML_lexical; Name.initializer = INIT_RE; Name.pfnCmp = FNCMP; Name.sstr.searchmask |= SSTR_RE; Name.CXTT = *pCxt; Name.hMod = pCxt->hMod; if ( pCxt->hMod ) { Name.hExe = SHHexeFromHmod ( pCxt->hMod ); } else { // not valid to call SHHexeFromHmod with an Hmod of 0, // so set Hexe explicitly Name.hExe = 0; } if ( pRE && *pRE ) { Name.sstr.pRE = pRE; } fRestart = FALSE; } else { pHSLHead = MHMemLock (*phSYML); pRestart = MHMemLock (pHSLHead->restart); Name = pRestart->Name; mask = pRestart->mask; state = pRestart->state; hSym = pRestart->hSym; pHSLHead->blockcnt = 1; pHSLHead->symbolcnt = 0; pHSLHead->remaining = HSYML_SIZE - sizeof ( HSL_HEAD ); pHSLHead->pHSLList = (PHSL_LIST)(((uchar *)pHSLHead) + sizeof (HSL_HEAD)); MHMemUnLock (pHSLHead->restart); _fmemset ((uchar *)pHSLHead + sizeof (HSL_HEAD), 0, HSYML_SIZE - sizeof (HSL_HEAD)); AddHSYM (&Name, hSym, pHSLHead, state); fRestart = TRUE; Name.hSym = hSym; } switch (state) { case HSYML_lexical: if (mask & HSYMR_lexical) { // search up the lexical scope to but not including the // function level while (SHIsCXTBlk (&Name.CXTT)) { while ((hSym = SHFindNameInContext (Name.hSym, &Name.CXTT, (LPSSTR)&Name, fCaseSensitive, FNCMP, &CXTTOut)) != 0) { if (AddHSYM (&Name, hSym, pHSLHead, HSYMR_lexical) == FALSE) { goto hsyml_exit; } Name.hSym = hSym; } // go to the parent scope SHGoToParent (&Name.CXTT, &CXTTOut); // reset current symbol Name.CXTT = CXTTOut; Name.hSym = 0; } mask &= ~HSYMR_lexical; } case HSYML_function: if (mask & HSYMR_function) { if (fRestart == FALSE) { Name.hSym = 0; Name.CXTT.hBlk = 0; } fRestart = FALSE; state = HSYML_function; if ( Name.CXTT.hMod != 0 ) { isprolog = SHIsInProlog (&Name.CXTT); } while (!SHIsCXTMod (&Name.CXTT) && Name.CXTT.hMod != 0) { while ((hSym = SHFindNameInContext (Name.hSym, &Name.CXTT, (LPSSTR)&Name, fCaseSensitive, FNCMP, &CXTTOut)) != 0) { if ((isprolog == TRUE) && (fEnableProlog == FALSE)) { // we want to reject bp_relative and register // stuff if we are in the prolog or epilog of // a function if ((Name.lastsym != S_BPREL16) && (Name.lastsym != S_BPREL32) && (Name.lastsym != S_REGISTER)) { if (AddHSYM (&Name, hSym, pHSLHead, HSYMR_function) == FALSE) { goto hsyml_exit; } } } else { if (AddHSYM (&Name, hSym, pHSLHead, HSYMR_function) == FALSE) { goto hsyml_exit; } } Name.hSym = hSym; } // go to the parent scope SHGoToParent (&Name.CXTT, &CXTTOut); // reset current symbol Name.CXTT = CXTTOut; Name.hSym = 0; } mask &= ~HSYMR_function; } case HSYML_class: if (mask & HSYMR_class) { if (fRestart == FALSE) { Name.hSym = 0; if (ClassImp != 0) { Name.CurClass = ClassImp; } } fRestart = FALSE; if ((Name.CurClass != 0)) { DASSERT (FALSE); // need to do equivalent of EEGetChild on this } mask &= ~HSYMR_class; } case HSYML_module: if (mask & HSYMR_module) { if (fRestart == FALSE) { SHGetCxtFromHmod (Name.hMod, &Name.CXTT); Name.hSym = 0; } fRestart = FALSE; Name.state = HSYML_module; while ((hSym = SHFindNameInContext (Name.hSym, &Name.CXTT, (LPSSTR)&Name, fCaseSensitive, Name.pfnCmp, &CXTTOut)) != 0) { if (AddHSYM (&Name, hSym, pHSLHead, HSYMR_module) == FALSE) { goto hsyml_exit; } Name.hSym = hSym; } mask &= ~HSYMR_module; } case HSYML_global: // search global symbol table if (mask & HSYMR_global) { if (fRestart == FALSE) { Name.hSym = 0; } fRestart = FALSE; Name.state = HSYML_global; Name.sstr.searchmask |= SSTR_NoHash; while ((hSym = SHFindNameInGlobal (Name.hSym, &Name.CXTT, (LPSSTR)&Name, fCaseSensitive, Name.pfnCmp, &CXTTOut)) != 0) { if (AddHSYM (&Name, hSym, pHSLHead, HSYMR_global) == FALSE) { goto hsyml_exit; } Name.hSym = hSym; } mask &= ~HSYMR_global; } case HSYML_exe: if (mask & HSYMR_exe) { Name.state = HSYML_exe; if (fRestart == FALSE) { Name.hModCur = SHGetNextMod (Name.hExe, Name.hMod); Name.hSym = 0; } fRestart = FALSE; Name.sstr.searchmask |= SSTR_NoHash; do { if (SHGetCxtFromHmod (Name.hModCur, &Name.CXTT)) { while ((hSym = SHFindNameInContext (Name.hSym, &Name.CXTT, (LPSSTR)&Name, fCaseSensitive, Name.pfnCmp, &CXTTOut) ) != 0) { if (AddHSYM (&Name, hSym, pHSLHead, HSYMR_exe) == FALSE) { goto hsyml_exit; } Name.hSym = hSym; } } } while (Name.hSym = 0, (Name.hModCur = SHGetNextMod (Name.hExe, Name.hModCur)) != Name.hMod); mask &= ~HSYMR_exe; } case HSYML_public: if (mask & HSYMR_public && Name.hExe) { if (fRestart == FALSE) { hSym = 0; } fRestart = FALSE; Name.state = HSYML_public; Name.sstr.searchmask |= SSTR_NoHash; while ((hSym = PHFindNameInPublics (hSym, Name.hExe, (LPSSTR)&Name, fCaseSensitive, Name.pfnCmp)) != 0) { if (AddHSYM (&Name, hSym, pHSLHead, HSYMR_public) == FALSE) { goto hsyml_exit; } Name.hSym = hSym; } mask &= ~HSYMR_public; } } pHSLHead->status.endsearch = TRUE; MHMemUnLock (*phSYML); return (EENOERROR); hsyml_exit: if (pHSLHead->restart == 0) { // allocate restart buffer if ((pHSLHead->restart = MHMemAllocate (sizeof (HSL_restart_t))) == 0) { pHSLHead->status.fatal = TRUE; MHMemUnLock (*phSYML); return (EENOMEMORY); } } pRestart = MHMemLock (pHSLHead->restart); pRestart->Name = Name; pRestart->mask = mask; pRestart->state = state; pRestart->hSym = hSym; MHMemUnLock (pHSLHead->restart); MHMemUnLock (*phSYML); return (EENOERROR); } LOCAL bool_t AddHSYM ( psearch_t pName, HSYM hSym, PHSL_HEAD pHSLHead, uint request ) { PHSL_LIST pHSLList; pHSLList = pHSLHead->pHSLList; // check usability of current block if (pHSLList->status.isused == TRUE) { // block has been used, check for same context if (_fmemcmp (&pHSLList->Cxt, &pName->CXTT, sizeof (CXT)) != 0) { // context has changed pHSLList->status.complete = TRUE; pHSLHead->pHSLList = (PHSL_LIST)((uchar *)pHSLList + sizeof ( HSL_LIST ) + pHSLList->symbolcnt * sizeof ( HSYM ) ); pHSLList = pHSLHead->pHSLList; pHSLHead->blockcnt++; } } if (pHSLList->status.hascxt == FALSE) { if (pHSLHead->remaining < (sizeof (HSL_LIST) + sizeof (HSYM))) { return (FALSE); } pHSLHead->remaining -= sizeof (HSL_LIST); pHSLList->status.hascxt = TRUE; pHSLList->Cxt = pName->CXTT; pHSLList->request = (ushort) request; } if (pHSLHead->remaining < sizeof (HSYM)) { return (FALSE); } pHSLList->status.isused = TRUE; pHSLList->hSym[pHSLList->symbolcnt++] = hSym; pHSLHead->remaining -= sizeof (HSYM); return (TRUE); } // search for the base sym of the base pointer // // Entry pName = structure describing the base pointer name // // Exit pName.eval reflects the bound base info // // Returns HR_ if base sym found HR_t SearchBasePtrBase ( psearch_t pName ) { search_t lName = *pName; plfPointer pType; SYMPTR pSym; unsigned short lrectyp; eval_t eval; peval_t lpv = &eval; ushort savefEProlog = pExState->state.fEProlog; HR_t retval = HR_notfound; pExState->state.fEProlog = TRUE; // KLUDGE to get around CXT complications eval = *pName->pv; CLEAR_EVAL_FLAGS (lpv); // an enregistered primitive EVAL_IS_REG (lpv) = EVAL_IS_REG(pName->pv); EVAL_IS_BPREL (lpv) = EVAL_IS_BPREL(pName->pv); lName.hSym = 0; // start search at beginning of CXT lName.pv = lpv; DASSERT(!CV_IS_PRIMITIVE (EVAL_TYP(lpv))); DASSERT (EVAL_MOD (lpv) != 0); EVAL_TYPDEF (lpv) = THGetTypeFromIndex (EVAL_MOD (lpv), EVAL_TYP(lpv)); DASSERT (EVAL_TYPDEF (lpv) != 0); _fmemset (&lpv->data, 0, sizeof (lpv->data)); pType = (plfPointer)(&((TYPPTR)(MHOmfLock (EVAL_TYPDEF(lpv))))->leaf); DASSERT(pType->leaf == LF_POINTER); DASSERT((pType->attr.ptrtype >= CV_PTR_BASE_VAL) && (pType->attr.ptrtype <= CV_PTR_BASE_SEGADDR)); pSym = (SYMPTR)(&((plfPointer)pType)->pbase.Sym); PTR_BSYMTYPE (pName->pv) = pSym->rectyp; emiAddr (PTR_ADDR (pName->pv)) = pCxt->addr.emi; switch (pSym->rectyp) { case S_BPREL16: lName.sstr.lpName = &((BPRELPTR16)pSym)->name[1]; lName.sstr.cb = ((BPRELPTR16)pSym)->name[0]; if (SearchSym(&lName) != HR_found) { goto ReturnNotFound;; } PopStack(); SetAddrSeg (&PTR_ADDR (pName->pv), 0); pSym = (SYMPTR)MHOmfLock(lName.hSym); if (((BPRELPTR16)pSym)->rectyp == S_BPREL16) { SetAddrOff (&PTR_ADDR (pName->pv), ((BPRELPTR16)pSym)->off); ADDR_IS_OFF32 (PTR_ADDR (pName->pv)) = FALSE; ADDR_IS_FLAT (PTR_ADDR (pName->pv)) = FALSE; ADDR_IS_LI (PTR_ADDR (pName->pv)) = FALSE; PTR_STYPE (pName->pv) = ((BPRELPTR16)pSym)->typind; } else { goto ReturnNotFound;; } pExState->state.bprel = TRUE; break; case S_LDATA16: case S_GDATA16: lName.sstr.lpName = &((DATAPTR16)pSym)->name[1]; lName.sstr.cb = ((DATAPTR16)pSym)->name[0]; lrectyp = pSym->rectyp; do { if (SearchSym(&lName) != HR_found) { goto ReturnNotFound;; } PopStack(); pSym = (SYMPTR)MHOmfLock(lName.hSym); } while (pSym->rectyp != lrectyp); pExState->state.fLData = TRUE; SetAddrSeg (&PTR_ADDR (pName->pv), ((DATAPTR16)pSym)->seg); SetAddrOff (&PTR_ADDR (pName->pv), ((DATAPTR16)pSym)->off); ADDR_IS_OFF32 (PTR_ADDR (pName->pv)) = FALSE; ADDR_IS_FLAT (PTR_ADDR (pName->pv)) = FALSE; ADDR_IS_LI (PTR_ADDR (pName->pv)) = TRUE; PTR_STYPE (pName->pv) = ((DATAPTR16)pSym)->typind; break; case S_BPREL32: lName.sstr.lpName = &((BPRELPTR32)pSym)->name[1]; lName.sstr.cb = ((BPRELPTR32)pSym)->name[0]; if (SearchSym(&lName) != HR_found) { goto ReturnNotFound;; } PopStack(); SetAddrSeg (&PTR_ADDR (pName->pv), 0); if (((BPRELPTR32)pSym)->off != 0) { SetAddrOff (&PTR_ADDR (pName->pv), ((BPRELPTR32)pSym)->off); ADDR_IS_OFF32 (PTR_ADDR (pName->pv)) = TRUE; ADDR_IS_FLAT (PTR_ADDR (pName->pv)) = TRUE; ADDR_IS_LI (PTR_ADDR (pName->pv)) = FALSE; PTR_STYPE (pName->pv) = ((BPRELPTR32)pSym)->typind; } else { goto ReturnNotFound;; } pExState->state.bprel = TRUE; break; case S_LDATA32: case S_GDATA32: case S_LTHREAD32: case S_GTHREAD32: lName.sstr.lpName = &((DATAPTR32)pSym)->name[1]; lName.sstr.cb = ((DATAPTR32)pSym)->name[0]; lrectyp = pSym->rectyp; do { if (SearchSym(&lName) != HR_found) { goto ReturnNotFound;; } PopStack(); pSym = (SYMPTR)MHOmfLock(lName.hSym); } while (pSym->rectyp != lrectyp); pExState->state.fLData = TRUE; SetAddrSeg (&PTR_ADDR (pName->pv), ((DATAPTR32)pSym)->seg); SetAddrOff (&PTR_ADDR (pName->pv), ((DATAPTR32)pSym)->off); ADDR_IS_OFF32 (PTR_ADDR (pName->pv)) = TRUE; ADDR_IS_FLAT (PTR_ADDR (pName->pv)) = TRUE; ADDR_IS_LI (PTR_ADDR (pName->pv)) = TRUE; PTR_STYPE (pName->pv) = ((DATAPTR32)pSym)->typind; break; case S_REGISTER: break; default: DASSERT(FALSE); break; } retval = HR_found; ReturnNotFound: pExState->state.fEProlog = savefEProlog; return(retval); } /** SearchSym - search for symbol * * status = SearchSym (pName) * * Entry pName = structure describing state of search * * Exit pName updated to reflect search results * pName->hSym = handle of symbol * pName->CXTT = context of symbol * * Returns HR_... enum specifying search result */ HR_t SearchSym ( psearch_t pName ) { CXT CXTTOut; HSYM hSym = 0; bool_t isprolog; SCN_t retval; char NameNew[ 256 ]; LPB NameOld = ((LPSSTR) pName)->lpName; unsigned char cbNew; unsigned char cbOld = ((LPSSTR) pName)->cb; BOOL SearchWithSuffix; // NOTE: this routine may be called recursively through MatchFunction if ((hBPatch != 0) && (pExState->ambiguous != 0) && (pExState->ambiguous == pName->bn)) { // this is a request for a symbol that was previously found to // be ambiguous. Pop the next ambiguous symbol off the list and // return it to the caller. return (AmbFromList (pName)); } // If we encounter a lone '.', handle as the CUR PC operator (for any platform). if ((pName->sstr.cb == 1 ) && *(pName->sstr.lpName) == '.') { EVAL_STATE( pName->pv ) = EV_rvalue; EVAL_TYP( pName->pv ) = T_PCHAR; EVAL_IS_PTR( pName->pv ) = TRUE; EVAL_IS_CURPC( pName->pv ) = TRUE; PushStack (pName->pv); return (HR_found); } SearchWithSuffix = ( Suffix && !(((LPSSTR)pName)->searchmask & SSTR_RE) ); if ( SearchWithSuffix ) { cbNew = cbOld+1; memcpy( NameNew, NameOld, cbOld ); NameNew[ cbOld ] = Suffix; NameNew[ cbNew ] = '\0'; } // this routine will terminate on the following conditions: // 1. A symbol is found that is not a function address // 2. A symbol is found that is a function and is not a method // and the end of the symbol table is reached // 3. A symbol is found that is a method and the end of the // inheritance tree for the class is reached. // If BindingBP is set, all function/method addresses that match // the expression are entered into the TMList pointed to by pTMList for (;;) { switch (pName->state) { case SYM_bclass: // this state is a special entry for searching for the base // class of a class when only the type of the base is known if (InitMod (pName) == FALSE) { // error in context return (HR_notfound); } pName->state = SYM_class; continue; case SYM_init: if (InitMod (pName) == FALSE) { /* * For line numbers (@linenumber) to be error */ if ((pName->scope & ~SCP_class) && (*pName->sstr.lpName == '@') && (isdigit (*(pName->sstr.lpName + 1))) ) { return HR_notfound; } // error in context so we will allow check for registers return (ParseRegister (pName)); } if ((pName->scope & ~SCP_class) && *pName->sstr.lpName == '@') { //search for @register, @linenumber, fastcall routine if (isdigit (*(pName->sstr.lpName + 1))) { return (LineNumber (pName)); } else if ((hSym = PHFindNameInPublics ((HSYM) NULL, pName->hExe, (LPSSTR)pName, pExState->state.fCase, pName->pfnCmp)) != 0) { goto found; } else if (ParseRegister (pName) == HR_found) { return (HR_found); } else { return (HR_notfound); } } else if (*pName->sstr.lpName == 0xff) { // search for handle to symbol. The handle to // symbol comes from CV when a specific symbol // is to be searched. The most common case is // when a specific variable is to be displayed // in the locals window pName->sstr.lpName++; hSym = *((HSYM UNALIGNED *)(pName->sstr.lpName)); goto found; } // start normal symbol search pName->state = SYM_lexical; case SYM_lexical: if (pName->scope & SCP_lexical) { // search up the lexical scope to the function level // but do not search the module level because of the // class search required for method functions isprolog = SHIsInProlog (&pName->CXTT); while (!SHIsCXTMod (&pName->CXTT) ) { hSym = SHFindNameInContext (pName->hSym, &pName->CXTT, (LPSSTR)pName, pExState->state.fCase, FNCMP, &CXTTOut); if ( hSym ) { if (isprolog && (pExState->state.fEProlog == FALSE)) { // we want to reject bp_relative and register // stuff if we are in the prolog or epilog of // a function // M00FLAT32 - need another check here if ((pName->lastsym != S_BPREL16) && (pName->lastsym != S_BPREL32) && (pName->lastsym != S_REGISTER)) { goto foundsave; } else { // stop the search here: we have // already found a symbol, but cannot // evaluate it. --caviar #5898 pExState->err_num = ERR_NOSTACKFRAME; return HR_error; } } else { goto foundsave; } } // go to the parent scope SHGoToParent (&pName->CXTT, &CXTTOut); // reset current symbol pName->hSym = 0; pName->CXTT = CXTTOut; } } pName->state = SYM_class; if (pName->scope & SCP_class) { if (pName->ExpClass != 0) { // search an explicit class pName->CurClass = pName->ExpClass; } else if (ClassImp != 0) { pName->CurClass = ClassImp; } } case SYM_class: if ((pName->CurClass != 0) && (pName->scope & SCP_class)) { retval = SearchClassName (pName); switch (retval) { case SCN_found: // the symbol is a member of the class. If // an explict class was not specified and // the current context is implicitly a class, // then we rewrote the tree to change the // symbol reference to this->symbol DASSERT (pName->hFound == 0); DASSERT (pName->hAmbCl == 0); if (EVAL_TYP (pName->pv) != T_NOTYPE) { if (PushStack (pName->pv) == FALSE) return (HR_error); goto nopush; } else { if (EVAL_IS_STMEMBER(pName->pv)) { pExState->err_num = ERR_STATICNOOMF; } else { pExState->err_num = ERR_BADOMF; } return (HR_error); } case SCN_rewrite: return (HR_rewrite); case SCN_error: return (HR_error); default: DASSERT (pName->hFound == 0); DASSERT (pName->hAmbCl == 0); if (pName->initializer == INIT_base) { // we were searching for the base class of // a class which was not found. return (HR_notfound); } break; } } SHGetCxtFromHmod (pName->hMod, &pName->CXTT); pName->hSym = 0; pName->state = SYM_module; case SYM_module: if (pName->scope & SCP_module) { if ((hSym = SHFindNameInContext (pName->hSym, &pName->CXTT, (LPSSTR)pName, pExState->state.fCase, pName->pfnCmp, &CXTTOut)) != 0) { goto foundsave; } } pName->state = SYM_global; pName->hSym = 0; case SYM_global: // users specified a context on a break point command // we have already searched the module specified so end the search // here // sps - 7/24/92 if (pBindBPCxt && pBindBPCxt->hMod &&(pBindBPCxt->hMod != pName->hModCur) && (pExState->ambiguous != 0) && (pExState->ambiguous == pName->bn)) { return(HR_end); } // search global symbol table if (pName->scope & SCP_global) { hSym = SHFindNameInGlobal( pName->hSym, &pName->CXTT, (LPSSTR)pName, pExState->state.fCase, pName->pfnCmp, &CXTTOut); if ( !hSym && SearchWithSuffix ) { ((LPSSTR)pName)->lpName = NameNew; ((LPSSTR)pName)->cb = cbNew; hSym = SHFindNameInGlobal( pName->hSym, &pName->CXTT, (LPSSTR)pName, pExState->state.fCase, pName->pfnCmp, &CXTTOut ); ((LPSSTR)pName)->lpName = NameOld; ((LPSSTR)pName)->cb = cbOld; } if ( hSym ) { goto foundsave; } } pName->hModCur = SHGetNextMod (pName->hExe, pName->hMod); pName->hSym = 0; pName->state = SYM_exe; case SYM_exe: if (pName->scope & SCP_global) { if (pName->hModCur == 0) { pName->hModCur = SHGetNextMod(pName->hExe, pName->hModCur); } while (pName->hModCur != pName->hMod) { if (SHGetCxtFromHmod (pName->hModCur, &pName->CXTT)) { hSym = SHFindNameInContext (pName->hSym, &pName->CXTT, (LPSSTR)pName, pExState->state.fCase, pName->pfnCmp, &CXTTOut); if ( !hSym && SearchWithSuffix ) { ((LPSSTR)pName)->lpName = NameNew; ((LPSSTR)pName)->cb = cbNew; hSym = SHFindNameInContext (pName->hSym, &pName->CXTT, (LPSSTR)pName, pExState->state.fCase, pName->pfnCmp, &CXTTOut); ((LPSSTR)pName)->lpName = NameOld; ((LPSSTR)pName)->cb = cbOld; } if ( hSym ) { goto foundsave; } } pName->hSym = 0; pName->hModCur = SHGetNextMod (pName->hExe, pName->hModCur); if (pName->hModCur == 0) { pName->hModCur = SHGetNextMod(pName->hExe, pName->hModCur); } } } // we are at the end of the normal symbol search. If the // symbol has not been found, we will search the public // symbol table. if (!BindingBP) { // if we are not binding breakpoints and we have // found a symbol in previous calls, return. Otherwise, // we will look in the publics table. Note that // finding a symbol in the publics table has a // large probability of finding one with a type of // zero which will limit it's usefulness if (pName->hSym != 0) { if (pName->possibles > 1) { pExState->err_num = ERR_AMBIGUOUS; return (HR_ambiguous); } return (HR_notfound); } } else { // we are binding breakpoints. We need to see if // one or more symbols have matched. If so, we // are done with the symbol search. If we have // not found the symbol, we search the publics table. // For breakpoints, we do not need type information, // only the address, so symbols found in the publics // table are much more useful. if ((pExState->ambiguous != 0) && (pExState->ambiguous == pName->bn)) { // we have found at least one symbol to this // point. this is indicated by SymAmbToList // setting the node of the function's symbol // into the expression state structure. By // this point all ambiguous symbols have been // added to the back patch list. If we have // not found any symbol yet, we search the // publics table. Note also that there cannot // be any ambiguity in the publics table because // the function names have to be unique in the // publics table. return HR_end; } } // search public symbol table pName->state = SYM_public; case SYM_public: // // some searches such as finding a UDT by type // do not require a symbol // if (pName->scope & SCP_global) { hSym = PHFindNameInPublics ( (HSYM)NULL, pName->hExe, (LPSSTR)pName, pExState->state.fCase, pName->pfnCmp); if ( !hSym && SearchWithSuffix ) { ((LPSSTR)pName)->lpName = NameNew; ((LPSSTR)pName)->cb = cbNew; hSym = PHFindNameInPublics ( (HSYM)NULL, pName->hExe, (LPSSTR)pName, pExState->state.fCase, pName->pfnCmp ); ((LPSSTR)pName)->lpName = NameOld; ((LPSSTR)pName)->cb = cbOld; } if (!hSym) { char rgch[256]; *rgch = '_'; strcpy(&rgch[1], NameOld); ((LPSSTR)pName)->lpName = rgch; ((LPSSTR)pName)->cb = cbOld + 1; hSym = PHFindNameInPublics ( (HSYM)NULL, pName->hExe, (LPSSTR) pName, pExState->state.fCase, pName->pfnCmp ); if ( !hSym && SearchWithSuffix ) { *rgch = '_'; strcpy(&rgch[1], NameNew); ((LPSSTR)pName)->lpName = rgch; ((LPSSTR)pName)->cb = cbNew + 1; hSym = PHFindNameInPublics ( (HSYM)NULL, pName->hExe, (LPSSTR) pName, pExState->state.fCase, pName->pfnCmp ); } // // now look for fastcall names // if (!hSym) { *rgch = '@'; strcpy(&rgch[1], NameOld); ((LPSSTR)pName)->lpName = rgch; ((LPSSTR)pName)->cb = cbOld + 1; hSym = PHFindNameInPublics ( (HSYM)NULL, pName->hExe, (LPSSTR) pName, pExState->state.fCase, pName->pfnCmp ); } ((LPSSTR)pName)->lpName = NameOld; ((LPSSTR)pName)->cb = cbOld; } if ( hSym ) { if (hSym == pName->hSym) { // We found this symbol last call! There // are no more to be found (or worth finding). return HR_notfound; } goto foundsave; } } if (EVAL_IS_REG (pName->pv)) { return (HR_notfound); // found it last time - quite looking } else if ((pName->scope & ~SCP_class) && ParseRegister (pName) == HR_found) { return (HR_found); } pExState->err_num = ERR_UNKNOWNSYMBOL; return (HR_notfound); } } foundsave: pName->CXTT = CXTTOut; found: pName->hSym = hSym; EVAL_HSYM (pName->pv) = pName->hSym; if (pName->initializer == INIT_tdef) { // the routines that search for UDTs only need the // hsym and the stack pointer may not be valid at this // point (FormatUDT for example), so return now return (HR_found); } if (SymToNode (pName) == FALSE) { return (HR_notfound); } if (PushStack (pName->pv) == FALSE) return (HR_error); nopush: if (!EVAL_IS_FCN (ST)) { // if this symbol is not a function and we have not processed // a function previously, then the search is done if (pExState->ambiguous == 0) { return (HR_found); } else if (pExState->ambiguous == pName->bn) { pExState->err_num = ERR_SYMCONFLICT; return (HR_error); } else { return (HR_found); } } else if (EVAL_IS_METHOD (ST)) { // ambiguous methods were entered into the ambiguous breakpoint // list by SetBPValue which was called in SearchClassName return (HR_found); } else if (pName->state == SYM_public) { // we will take the first function symbol found in the // publics table since the names have to be unique in the // publics table return (HR_found); } else if ((BindingBP == TRUE) && (bArgList == 0)) { // if we are binding breakpoints and there is not an // argument list, we will enter all functions found with // this name into the breakpoint ambiguity list. return (SymAmbToList (pName)); } else { // the found symbol is non-member function. continue // search to end of symbols to find the best function. // in the case of a breakpoint with argument list, there // must be an exact match on the argument types EVAL_MOD (pName->pv) = SHHMODFrompCXT (&pName->CXTT); if (pName->scope & SCP_nomatchfn) return (HR_found); return (MatchFunction (pName)); } } LOCAL bool_t InitMod ( psearch_t pName ) { if (((pName->hMod = SHHMODFrompCXT (&pName->CXTT)) == 0) || ((pName->hExe = SHHexeFromHmod (pName->hMod)) == 0)) { // error in context return (FALSE); } return (TRUE); } // Class searching and main support routines /*** SearchClassName - Search a class and bases for element by name * * flag = SearchClassName (pName) * * Entry pName = pointer to struct describing search * * Exit pName updated to reflect type * * Returns SCN_... enum describing result */ LOCAL SCN_t SearchClassName ( psearch_t pName ) { SCN_t retval; ushort max; CV_fldattr_t attr = {0}; // allocate and initialize list of dominated virtual bases if (hVBDom == 0) { if ((hVBDom = MHMemAllocate (sizeof (dombase_t) + DOMBASE_DEFAULT * sizeof (CV_typ_t))) == 0) { pExState->err_num == ERR_NOMEMORY; return (SCN_error); } pVBDom = MHMemLock (hVBDom); pVBDom->MaxIndex = DOMBASE_DEFAULT; } else { pVBDom = MHMemLock (hVBDom); } pVBDom->CurIndex = 0; // allocate and initialize list of searched virtual bases if (hVBSearch == 0) { if ((hVBSearch = MHMemAllocate (sizeof (dombase_t) + DOMBASE_DEFAULT * sizeof (CV_typ_t))) == 0) { pExState->err_num == ERR_NOMEMORY; MHMemUnLock (hVBDom); return (SCN_error); } pVBSearch = MHMemLock (hVBSearch); pVBSearch->MaxIndex = DOMBASE_DEFAULT; } else { pVBSearch = MHMemLock (hVBSearch); } pVBSearch->CurIndex = 0; // allocate and initialize structure for recursive base searches if (hSymClass == 0) { if ((hSymClass = MHMemAllocate (sizeof (symclass_t) + SYMBASE_DEFAULT * sizeof (symbase_t))) == 0) { pExState->err_num == ERR_NOMEMORY; MHMemUnLock (hVBDom); MHMemUnLock (hVBSearch); return (SCN_error); } pSymClass = MHMemLock (hSymClass); pSymClass->MaxIndex = SYMBASE_DEFAULT; } else { pSymClass = MHMemLock (hSymClass); } pSymClass->CurIndex = 0; pSymClass->hNext = 0; max = pSymClass->MaxIndex; _fmemset (pSymClass, 0, max * sizeof (symbase_t) + sizeof (symclass_t)); pSymClass->MaxIndex = max; // recurse through the inheritance tree searching for the feature if ((retval = RecurseBase (pName, pName->CurClass, 0, 0, 0, attr, FALSE)) != SCN_error) { // at this point we need to check for dominance and then clean // up the allocated memory and return the search results if (pName->possibles == 0) { // if the count was zero, the handle of found list must be zero DASSERT (pName->hFound == 0); retval = SCN_notfound; } else if (pName->cFound == 0) { if (pName->hFound == 0) { DASSERT (pSymClass->s.viable == TRUE); // the found value is in the permanent stack. This means // the feature was found in the most derived class retval = SetValue (pName); } } else if (pName->cFound == 1) { // the feature was not found in the most derived class // but no other matching feature was found. Move the feature // descriptor pointed to by pName->hFound into the permanent // feature descriptor pSymClass. An important thing to remember // here is that there can only be one feature descriptor pSymClass // when calling SetValue unless we are binding breakpoints. // If we are binding breakpoints we can have multiple feature // descriptors in pSymClass and the list pointed to by // pName->hAmbCl. If we have an argument list, these must // resolve to one feature. If we do not have an argument // list, all of the features are valid and must be added // to the breakpoint list. MoveSymCl (pName->hFound); pName->hFound = 0; pName->cFound--; DASSERT (pSymClass->s.viable == TRUE); retval = SetValue (pName); } else { // since two or more features were found, we need to cull the // feature list to remove dominated features and features which // are the same static item. Ambiguity is removed strictly on // the name of the feature. Overloaded methods are resolved later. if ((retval = RemoveAmb (pName)) == SCN_found) { retval = SetValue (pName); } } } MHMemUnLock (hVBDom); MHMemUnLock (hVBSearch); MHMemUnLock (hSymClass); DASSERT (pName->hAmbCl == 0); return (retval); } /*** RecurseBase - Search a class and its bases for element by name * * status = RecurseBase (pName, type, vbptr, vbpoff, thisadjust, attr, virtual) * * Entry pName = pointer to struct describing search * type = type index of class * vbptr = type index of virtual base pointer * vbpoff = offset of virtual base pointer from address point * thisadjust = offset of base from previous class * thisadjust = virtual base index if virtual base * attr = attribute of base class * virtual = TRUE if this is a virtual base * * Exit pName updated to reflect type * * Returns SCN_... enum describing result */ LOCAL SCN_t RecurseBase ( psearch_t pName, CV_typ_t type, CV_typ_t vbptr, OFFSET vbpoff, OFFSET thisadjust, CV_fldattr_t attr, bool_t virtual ) { SCN_t retval; // save offset of base from address point for this pointer adjustment if (SetBase (pName, type, vbptr, vbpoff, thisadjust, attr, virtual) != SCN_found) { return (SCN_error); } if (pName->initializer == INIT_base) { retval = SearchBType (pName); } else { retval = SearchRoot (pName); } switch (retval) { case SCN_found: if ((pName->clsmask & CLS_virtintro) == FALSE) { // add virtual bases to searched and dominated base lists // if we were searching for the introducing virtual function, // the fact that we found one is sufficient. if ((pSymClass->s.isvbase == TRUE) && (VBaseFound (pName) == TRUE)) { // the found feature is a previously found // virtual base class. pSymClass->s.isdupvbase = TRUE; } if ((retval = AddVBList (pSymClass, &pVBSearch, &hVBSearch)) != SCN_error) { retval = AddVBList (pSymClass, &pVBDom, &hVBDom); } } case SCN_error: return (retval); case SCN_notfound: // we did not find the element in the root of this class // so we search the inheritance tree. if (pExState->state.fSupBase == FALSE) { return (SearchBases (pName)); } else { return (SCN_notfound); } default: return (SCN_error); } } /** VBaseFound - search to see if virtual base already found * * status = VBaseFound (pName) * * Entry pName = structure describing search * pSymClass = structure describing most recent class search * * Exit pName updated to reflect search * pSymClass updated to unambiguous feature * * Returns TRUE if duplicate virtual base found * FALSE if not duplicate virtual base */ LOCAL bool_t VBaseFound ( psearch_t pName ) { psymclass_t pSymCl; HDEP hSymCl; CV_typ_t type = EVAL_TYP (&pSymClass->evalP); hSymCl = pName->hFound; while (hSymCl != 0) { pSymCl = MHMemLock (hSymCl); if (pSymCl == pSymClass) { return (FALSE); } if ((pSymCl->s.isvbase == TRUE) && (type == EVAL_TYP (&pSymCl->evalP))) { // the virtual base is already in the list MHMemUnLock( hSymCl ); return (TRUE); } DASSERT( FALSE ); MHMemUnLock( hSymCl ); hSymCl = 0; // NOTENOTE -- jimsch -- was no linking to next } return (FALSE); } /** RemoveAmb - remove ambiguity * * status = RemoveAmb (pName) * * Entry pName = structure describing search * pSymClass = structure describing most recent class search * * Exit pName updated to reflect search * pSymClass updated to unambiguous feature * * Returns SCN_found if unambiguous feature found * SCN_error otherwise */ LOCAL SCN_t RemoveAmb ( psearch_t pName ) { psymclass_t pSymCl; // we know that at this point two or more features were found // the list of features are pointed to by pName->hFound. // The permanent stack cannot contain a viable feature DASSERT (pSymClass->s.viable == FALSE); MoveSymCl (pName->hFound); pName->hFound = pSymClass->hNext; while (pName->hFound != 0) { // lock and check next list element pSymCl = MHMemLock (pName->hFound); switch (IsDominated (pSymClass, pSymCl)) { case DOM_ambiguous: // the new feature does not dominate the current best MHMemUnLock (pName->hFound); if (BindingBP == FALSE) { pExState->err_num = ERR_AMBIGUOUS; return (SCN_error); } // feature is ambiguous and we are setting breakpoints // save the feature in the ambiguous list and advance to // the next feature pSymClass->hNext = pSymCl->hNext; pSymCl->hNext = pName->hAmbCl; pName->hAmbCl = pName->hFound; MHMemUnLock (pName->hAmbCl); pName->hFound = pSymClass->hNext; break; case DOM_replace: // decrement the number of possible matches by the // count in the current best structure pName->possibles -= pSymClass->possibles; pName->cFound--; MHMemUnLock (pName->hFound); MoveSymCl (pName->hFound); pName->hFound = pSymClass->hNext; PurgeAmbCl (pName); break; case DOM_keep: // decrement the number of possible matches by the // count in the structure being discarded pName->possibles -= pSymCl->possibles; pName->cFound--; pSymClass->hNext = pSymCl->hNext; MHMemUnLock (pName->hFound); pName->hFound = pSymClass->hNext; break; } } // decrement the count of found features to account for the one we kept pName->cFound--; return (SCN_found); } /*** SearchBases - Search for an element in the bases of a class * * flag = SearchBases (pName, pvClass) * * Entry pName = pointer to struct describing search * * Exit pName updated to reflect type * * Returns enum describing search state * */ LOCAL SCN_t SearchBases ( psearch_t pName ) { ushort cnt; // count of number of elements in struct HTYPE hField; // handle to type record for struct field list char *pField; // pointer to field list uint fSkip = 0; // offset in the field list SCN_t retval = SCN_notfound; CV_typ_t newindex; CV_typ_t vbptr; OFFSET offset; OFFSET vbpoff; CV_fldattr_t attr; CV_fldattr_t vattr; peval_t pvBase = &pSymClass->symbase[pSymClass->CurIndex].Base; bool_t virtual; // Set to head of type record and search the base classes in order if ((hField = THGetTypeFromIndex (EVAL_MOD (pvBase), CLASS_FIELD (pvBase))) == 0) { // set error and stop search DASSERT (FALSE); pExState->err_num = ERR_BADOMF; return (SCN_error); } pField = (char *)(&((TYPPTR)MHOmfLock (hField))->data[0]); for (cnt = CLASS_COUNT (pvBase); cnt > 0; cnt--) { fSkip += SkipPad(((uchar *)pField) + fSkip); newindex = 0; switch (((plfEasy)(pField + fSkip))->leaf) { case LF_INDEX: // switch to next part of type record newindex = ((plfIndex)(pField + fSkip))->index; MHOmfUnLock (hField); if ((hField = THGetTypeFromIndex (EVAL_MOD (pvBase), newindex)) == 0) { DASSERT (FALSE); pExState->err_num = ERR_INTERNAL; return (SCN_error); } pField = (char *)(&((TYPPTR)MHOmfLock (hField))->data[0]); fSkip = 0; // the LF_INDEX is not part of the field count cnt++; break; case LF_BCLASS: // read type index of base class offset of base pointer // from address point attr = ((plfBClass)(pField + fSkip))->attr; newindex = ((plfBClass)(pField + fSkip))->index; fSkip += sizeof (struct lfBClass); offset = (OFFSET)RNumLeaf (pField + fSkip, &fSkip); vbptr = 0; vbpoff = 0; virtual = FALSE; goto foo; case LF_VBCLASS: // read type index of base class, type index of virtual // base pointer, offset of virtual base pointer from // address point and offset of virtual base displacement // from virtual base table vattr = ((plfVBClass)(pField + fSkip))->attr; newindex = ((plfVBClass)(pField + fSkip))->index; vbptr = ((plfVBClass)(pField + fSkip))->vbptr; virtual = TRUE; fSkip += sizeof (struct lfVBClass); vbpoff = (OFFSET)RNumLeaf (pField + fSkip, &fSkip); offset = (OFFSET)RNumLeaf (pField + fSkip, &fSkip); if ((pName->clsmask & CLS_virtintro) == FALSE) { // if we are searching for the introducing virtual method // then we want to search all bases if (VBSearched (newindex) == TRUE) { break; } retval = AddVBType (&pVBSearch, &hVBSearch, newindex); } foo: // check base class MHOmfUnLock (hField); // Advance to next base class structure if (IncrSymBase () != SCN_found) { return (SCN_error); } retval = RecurseBase (pName, newindex, vbptr, vbpoff, offset, attr, virtual); switch (retval) { case SCN_error: // if we got an error, abort the search newindex = 0; break; case SCN_found: // we have found the feature in a base class. // Dup the class search structure and continue the // search to the end of the inheritance tree if ((pName->clsmask & CLS_virtintro) == FALSE) { if ((retval = DupSymCl (pName)) != SCN_found) { // if we got an error duping, abort the search newindex = 0; } // set not found, so the unwinding of the call stack // does not reduplicate the class search structure retval = SCN_notfound; } else { // we were searching for the introducing virtual // method. Since there can be only one in the // tree above the virtual method, we can terminate // the search immediately return (retval); } break; default: break; } pSymClass->CurIndex--; MHOmfLock (hField); break; default: // we have reached the end of the base classes. // exit loop and check search results. break; } if (newindex == 0) { // all base classes must appear first in the field list. break; } } MHOmfUnLock (hField); return (retval); } bool_t getDefnFromDecl( CV_typ_t typeIn, peval_t pv, CV_typ_t* ptypeOut) { HTYPE hType; uint skip; TYPPTR pType; eval_t localEval; neval_t nv = &localEval; *nv = *pv; DASSERT (!CV_IS_PRIMITIVE (typeIn)); if ((hType = THGetTypeFromIndex (EVAL_MOD (nv), typeIn)) == 0) { pExState->err_num = ERR_BADOMF; return FALSE; } pType = (TYPPTR)MHOmfLock(hType); switch (pType->leaf) { case LF_STRUCTURE: case LF_CLASS: { plfClass pClass = (plfClass)(&pType->leaf); if (pClass->property.fwdref) { skip = offsetof (lfClass, data); RNumLeaf (((char *)(&pClass->leaf)) + skip, &skip); // forward ref - look for the definition of the UDT if ((*ptypeOut = GetUdtDefnTindex (typeIn, nv, ((char *)&(pClass->leaf)) + skip)) == T_NOTYPE) { goto failed; } } else *ptypeOut = typeIn; break; } case LF_UNION: { plfUnion pUnion = (plfUnion)(&pType->leaf); if (pUnion->property.fwdref) { skip = offsetof (lfUnion, data); RNumLeaf (((char *)(&pUnion->leaf)) + skip, &skip); // forward ref - look for the definition of the UDT if ((*ptypeOut = GetUdtDefnTindex (typeIn, nv, ((char *)&(pUnion->leaf)) + skip)) == T_NOTYPE) { goto failed; } } else *ptypeOut = typeIn; break; } case LF_ENUM: { plfEnum pEnum = (plfEnum)(&pType->leaf); if (pEnum->property.fwdref) { // forward ref - look for the definition of the UDT if ((*ptypeOut = GetUdtDefnTindex (typeIn, nv, (char *) pEnum->Name)) == T_NOTYPE) { goto failed; } } else *ptypeOut = typeIn; break; } default: *ptypeOut = typeIn; } MHOmfUnLock (hType); return TRUE; failed: MHOmfUnLock (hType); pExState->err_num = ERR_BADOMF; return FALSE; } /*** SearchBType - Search for an base by type * * flag = SearchBType (pName) * * Entry pName = pointer to struct describing search * pSymClass = pointer to base class path list structure * * Exit pName updated to reflect search * * Return enum describing search * * If the base class is found, the base class value is stored in the * the symbase[], not in pSymClass->evalP. This is to simplify the * GenQualExpr code. */ LOCAL SCN_t SearchBType ( psearch_t pName ) { ushort cnt; // count of number of elements in struct HTYPE hField; // handle to type record for struct field list char *pField; // pointer to field list uint fSkip = 0; // offset in the field list ushort anchor = 0; // offset in the field list to start of type CV_typ_t newindex; CV_typ_t vbptr; ushort retval = SCN_notfound; OFFSET offset; OFFSET vbpoff; bool_t termflag = FALSE; CV_fldattr_t attr; CV_fldattr_t vattr; peval_t pvBase = &pSymClass->symbase[pSymClass->CurIndex].Base; // set hField to the handle of the field list for the class if ((hField = THGetTypeFromIndex (EVAL_MOD (pvBase), CLASS_FIELD (pvBase))) == 0) { pExState->err_num = ERR_BADOMF; return (SCN_error); } pField = (char *)(&((TYPPTR)MHOmfLock (hField))->data[0]); // walk field list for the class for (cnt = CLASS_COUNT (pvBase); cnt > 0; cnt--) { fSkip += SkipPad(((uchar *)pField) + fSkip); switch (((plfEasy)(pField + fSkip))->leaf) { case LF_INDEX: // switch to new type record because compiler split it up newindex = ((plfIndex)(pField + fSkip))->index; MHOmfUnLock (hField); if ((hField = THGetTypeFromIndex (EVAL_MOD (pvBase), newindex)) == 0) { pExState->err_num = ERR_INTERNAL; return (SCN_error); } pField = (char *)(&((TYPPTR)MHOmfLock (hField))->data[0]); fSkip = 0; // the LF_INDEX is not part of the field count cnt++; break; case LF_BCLASS: attr = ((plfBClass)(pField + fSkip))->attr; if (!getBaseDefnFromDecl(((plfBClass)(pField + fSkip))->index, pName->pv, &newindex)) return SCN_error; // newindex = ((plfBClass)(pField + fSkip))->index; fSkip += offsetof (lfBClass, offset[0]); offset = (ushort)RNumLeaf (pField + fSkip, &fSkip); if (pName->typeOut == newindex) { // base has been found, set result values MHOmfUnLock (hField); if (IncrSymBase () != SCN_found) { return (SCN_error); } // save offset of base from address point for this // pointer adjustment if (SetBase (pName, newindex, 0, 0, offset, attr, FALSE) != SCN_found) { return (SCN_error); } pSymClass->s.viable = TRUE; pName->possibles++; return (SCN_found); } break; case LF_VBCLASS: vattr = ((plfVBClass)(pField + fSkip))->attr; if (!getBaseDefnFromDecl(((plfVBClass)(pField + fSkip))->index, pName->pv, &newindex)) return SCN_error; // newindex = ((plfVBClass)(pField + fSkip))->index; vbptr = ((plfVBClass)(pField + fSkip))->vbptr; fSkip += offsetof (lfVBClass, vbpoff[0]); vbpoff = (ushort)RNumLeaf (pField + fSkip, &fSkip); offset = (ushort)RNumLeaf (pField + fSkip, &fSkip); if (pName->typeOut == newindex) { // base has been found, set result values MHOmfUnLock (hField); if (IncrSymBase () != SCN_found) { return (SCN_error); } // save offset of base from address point for this // pointer adjustment if (SetBase (pName, newindex, vbptr, vbpoff, offset, attr, TRUE) != SCN_found) { return (SCN_error); } pSymClass->s.viable = TRUE; pName->possibles++; return (SCN_found); } break; default: termflag = TRUE; break; } if (termflag == TRUE) { break; } } MHOmfUnLock (hField); return (retval); } /*** SearchRoot - Search for an element of a class * * flag = SearchRoot (pName) * * Entry pName = pointer to struct describing search * pvBase = pointer to value describing base to be searched * * Exit pName updated to reflect search * * Return enum describing search */ LOCAL SCN_t SearchRoot ( psearch_t pName ) { ushort cnt; // count of number of elements in struct HTYPE hField; // handle to type record for struct field list char *pField; // pointer to field list HTYPE hBase; // handle to type record for base class uint fSkip = 0; // offset in the field list uint anchor; // offset in the field list to start of type uint tSkip; // temporary offset in the field list bool_t cmpflag = 1; CV_typ_t newindex; CV_typ_t vbptr; ushort retval = SCN_notfound; char *pc; ulong value; OFFSET offset; OFFSET vbpoff; CV_fldattr_t access; short count; CV_typ_t vfpType = T_NOTYPE; peval_t pvBase = &pSymClass->symbase[pSymClass->CurIndex].Base; CV_typ_t type; peval_t pvF = &pSymClass->evalP; ushort vtabind; ushort vbind; // set hField to the handle of the field list for the class if ((hField = THGetTypeFromIndex (EVAL_MOD (pvBase), CLASS_FIELD (pvBase))) == 0) { pExState->err_num = ERR_BADOMF; return (SCN_error); } pField = (char *)(&((TYPPTR)MHOmfLock ((HDEP)hField))->data[0]); // walk field list for the class #if 0 for (cnt = CLASS_COUNT (pvBase); cnt > 0; cnt--) { fSkip += SkipPad(((uchar *)pField) + fSkip); anchor = fSkip; switch (((plfEasy)(pField + fSkip))->leaf) { case LF_INDEX: // switch to new type record because compiler split it up newindex = ((plfIndex)(pField + fSkip))->index; MHOmfUnLock ((HDEP)hField); if ((hField = THGetTypeFromIndex (EVAL_MOD (pvBase), newindex)) == 0) { pExState->err_num = ERR_BADOMF; return (SCN_error); } pField = (char *)(&((TYPPTR)MHOmfLock ((HDEP)hField))->data[0]); fSkip = 0; // the LF_INDEX is not part of the field count cnt++; break; case LF_MEMBER: fSkip += offsetof (lfMember, offset[0]); offset = (short)RNumLeaf (pField + fSkip, &fSkip); access = ((plfMember)(pField + anchor))->attr; pc = pField + fSkip; fSkip += (*(pField + fSkip) + sizeof (char)); if (pName->clsmask & CLS_member) { if ((cmpflag = fnCmp ((LPSSTR) pName, NULL, pc, pExState->state.fCase)) == 0) { type = ((plfMember)(pField + anchor))->index; MHOmfUnLock ((HDEP)hField); hField = 0; EVAL_MOD (pvF) = SHHMODFrompCXT (&pName->CXTT); SetNodeType (pvF, type); EVAL_STATE (pvF) = EV_lvalue; // save the casting data for the this pointer pSymClass->offset = offset; pSymClass->access = access; pSymClass->possibles = 1; pName->possibles++; } } break; case LF_ENUMERATE: access = ((plfEnumerate)(pField + fSkip))->attr; fSkip += offsetof (lfEnumerate, value[0]); value = RNumLeaf (pField + fSkip, &fSkip); pc = pField + fSkip; fSkip += *(pField + fSkip) + sizeof (char); if (pName->clsmask & CLS_enumerate) { if ((cmpflag = fnCmp ((LPSSTR) pName, NULL, pc, pExState->state.fCase)) == 0) { pSymClass->possibles = 1; pName->possibles++; } } break; #if !defined(C_ONLY) case LF_STMEMBER: type = ((plfSTMember)(pField + anchor))->index; fSkip += offsetof (lfSTMember, Name[0]); if (pName->clsmask & CLS_member) { if ((cmpflag = fnCmp ((LPV) pName, (HVOID) NULL, pField + fSkip, pExState->state.fCase)) == 0) { pSymClass->access = ((plfSTMember)(pField + anchor))->attr; MHOmfUnLock (hField); hField = 0; EVAL_MOD (pvF) = SHHMODFrompCXT (&pName->CXTT); SetNodeType (pvF, type); EVAL_STATE (pvF) = EV_lvalue; EVAL_IS_STMEMBER (pvF) = TRUE; pSymClass->possibles = 1; pName->possibles++; } } fSkip += *(pField + fSkip) + sizeof (char); break; case LF_BCLASS: type = ((plfBClass)(pField + anchor))->index; access = ((plfBClass)(pField + anchor))->attr; fSkip += offsetof (lfBClass, offset[0]); newindex = ((plfBClass)(pField + anchor))->index; offset = (short)RNumLeaf (pField + fSkip, &fSkip); if ((pName->clsmask & CLS_bclass) != 0) { // switch to the base class type record to check the name MHOmfUnLock (hField); if ((hBase = THGetTypeFromIndex (EVAL_MOD (pvBase), newindex)) == 0) { pExState->err_num = ERR_BADOMF; return (SCN_error); } pField = (char *)(&((TYPPTR)MHOmfLock (hBase))->leaf); tSkip = offsetof (lfClass, data[0]); RNumLeaf (pField + tSkip, &tSkip); pc = pField + tSkip; cmpflag = fnCmp ((LPV) pName, (HVOID) NULL, pc, pExState->state.fCase); MHOmfUnLock (hBase); // reset to original field list if (cmpflag == 0) { // element has been found, set result values pSymClass->s.isbase = TRUE; pSymClass->s.isvbase = FALSE; pSymClass->offset += offset; EVAL_MOD (pvF) = SHHMODFrompCXT (&pName->CXTT); SetNodeType (pvF, type); EVAL_STATE (pvF) = EV_type; pSymClass->access = access; pSymClass->possibles = 1; pName->possibles++; } pField = (char *)(&((TYPPTR)MHOmfLock (hField))->data[0]); } break; case LF_VBCLASS: type = ((plfBClass)(pField + anchor))->index; access = ((plfVBClass)(pField + anchor))->attr; newindex = ((plfVBClass)(pField + anchor))->index; vbptr = ((plfVBClass)(pField + anchor))->vbptr; fSkip += offsetof (lfVBClass, vbpoff[0]); vbpoff = (short)RNumLeaf (pField + fSkip, &fSkip); vbind = (short)RNumLeaf (pField + fSkip, &fSkip); if ((pName->clsmask & CLS_bclass) != 0) { // switch to the base class type record to check the name MHOmfUnLock (hField); if ((hBase = THGetTypeFromIndex (EVAL_MOD (pvBase), newindex)) == 0) { pExState->err_num = ERR_BADOMF; return (SCN_error); } pField = (char *)(&((TYPPTR)MHOmfLock (hBase))->leaf); tSkip = offsetof (lfClass, data[0]); RNumLeaf (pField + tSkip, &tSkip); pc = pField + tSkip; cmpflag = fnCmp ((LPV) pName, (HVOID) NULL, pc, pExState->state.fCase); MHOmfUnLock (hBase); // reset to original field list if (cmpflag == 0) { // element has been found, set result values pSymClass->s.isbase = FALSE; pSymClass->s.isvbase = TRUE; pSymClass->vbind = vbind; pSymClass->vbpoff = vbpoff; pSymClass->vbptr = vbptr; EVAL_MOD (pvF) = SHHMODFrompCXT (&pName->CXTT); SetNodeType (pvF, type); EVAL_STATE (pvF) = EV_type; pSymClass->access = access; pSymClass->possibles = 1; pName->possibles++; } pField = (char *)(&((TYPPTR)MHOmfLock (hField))->data[0]); } break; case LF_IVBCLASS: fSkip += offsetof (lfVBClass, vbpoff[0]); RNumLeaf (pField + fSkip, &fSkip); RNumLeaf (pField + fSkip, &fSkip); break; case LF_FRIENDCLS: newindex = ((plfFriendCls)(pField + fSkip))->index; fSkip += sizeof (struct lfFriendCls); if ((pName->clsmask & CLS_fclass) != 0) { DASSERT (FALSE); // switch to the base class type record to check the name MHOmfUnLock (hField); if ((hBase = THGetTypeFromIndex (EVAL_MOD (pvBase), newindex)) == 0) { pExState->err_num = ERR_INTERNAL; return (SCN_error); } pField = (char *)(&((TYPPTR)MHOmfLock (hBase))->data[0]); tSkip = offsetof (lfClass, data[0]); RNumLeaf (pField + tSkip, &tSkip); pc = pField + tSkip; cmpflag = fnCmp ((LPV) pName, (HVOID) NULL, pc, pExState->state.fCase); MHOmfUnLock (hBase); // reset to original field list pField = (char *)(&((TYPPTR)MHOmfLock (hField))->data[0]); if (cmpflag == 0) { // element has been found, set result values pName->typeOut = newindex; } } break; case LF_FRIENDFCN: newindex = ((plfFriendFcn)(pField + fSkip))->index; fSkip += sizeof (struct lfFriendFcn) + ((plfFriendFcn)(pField + fSkip))->Name[0]; if ((pName->clsmask & CLS_frmethod) != 0) { DASSERT (FALSE); } break; case LF_VFUNCTAB: fSkip += sizeof (struct lfVFuncTab); // save the type of the virtual function pointer vfpType = ((plfVFuncTab)(pField + anchor))->type; pc = vfuncptr; if (pName->clsmask & CLS_vfunc) { if ((cmpflag = fnCmp ((LPV) pName, (HVOID) NULL, pc, pExState->state.fCase)) == 0) { MHOmfUnLock (hField); hField = 0; EVAL_MOD (pvF) = SHHMODFrompCXT (&pName->CXTT); SetNodeType (pvF, vfpType); EVAL_STATE (pvF) = EV_lvalue; // save the casting data for the this pointer if (pName->bnOp != 0) { pSymClass->offset = 0; pSymClass->access.access = CV_public; } pSymClass->possibles = 1; pName->possibles++; } } break; case LF_METHOD: count = ((plfMethod)(pField + fSkip))->count; cnt -= count - 1; newindex = ((plfMethod)(pField + fSkip))->mList; pc = pField + anchor + offsetof (lfMethod, Name[0]); fSkip += sizeof (struct lfMethod) + *pc; if (pName->clsmask & CLS_method) { if ((cmpflag = fnCmp ((LPV) pName, (HVOID) NULL, pc, pExState->state.fCase)) == 0) { // note that the OMF specifies that the vfuncptr will // be emitted as the first field after the bases if (pName->clsmask & CLS_virtintro) { // we are looking for the introducing virtual // method. We need to find a method with the // correct name of the correct type index that // is introducing. MHOmfUnLock (hField); if (IsIntroVirt (count, newindex, &vtabind) == FALSE) { cmpflag = 1; } else { if (FCN_VFPTYPE (pvF) == T_NOTYPE) { FCN_VFPTYPE (pvF) = vfpType; FCN_VFPTYPE (pName->pv) = vfpType; FCN_VTABIND (pvF) = vtabind; FCN_VTABIND (pName->pv) = vtabind; } cmpflag = 0; } pField = (char *)(&((TYPPTR)MHOmfLock (hField))->data[0]); } else { // save the type index of the method list, the // count of methods overloaded on this name, // the type index of the vfuncptr. Also, // increment the number of possible features by // the overload count pSymClass->possibles = count; pName->possibles += count; pSymClass->mlist = newindex; pSymClass->vfpType = vfpType; } } } break; case LF_NESTTYPE: newindex = ((plfNestType)(pField + fSkip))->index; fSkip += offsetof (lfNestType, Name[0]); pc = pField + fSkip; fSkip += *(pField + fSkip) + sizeof (char); if (pName->clsmask & CLS_ntype) { if ((cmpflag = fnCmp ((LPV) pName, (HVOID) NULL, pc, pExState->state.fCase)) == 0) { // set type of typedef symbol EVAL_STATE (pvF) = EV_type; } } break; #else Unreferenced( vbpoff ); Unreferenced( hBase ); Unreferenced( vbptr ); Unreferenced( tSkip ); Unreferenced( count ); Unreferenced( vtabind ); Unreferenced( vbind ); #endif default: pExState->err_num = ERR_BADOMF; retval = SCN_notfound; } if (cmpflag == 0) { pSymClass->s.viable = TRUE; retval = SCN_found; break; } } #endif #if 1 for (cnt = CLASS_COUNT (pvBase); cnt > 0; cnt--) { fSkip += SkipPad(((uchar *)pField) + fSkip); anchor = fSkip; switch (((plfEasy)(pField + fSkip))->leaf) { case LF_INDEX: // switch to new type record because compiler split it up newindex = ((plfIndex)(pField + fSkip))->index; MHOmfUnLock (hField); if ((hField = THGetTypeFromIndex (EVAL_MOD (pvBase), newindex)) == 0) { pExState->err_num = ERR_BADOMF; return (SCN_error); } pField = (char *)(&((TYPPTR)MHOmfLock (hField))->data); fSkip = 0; // the LF_INDEX is not part of the field count cnt++; break; case LF_MEMBER: fSkip += offsetof (lfMember, offset); offset = (UOFFSET)RNumLeaf (pField + fSkip, &fSkip); access = ((plfMember)(pField + anchor))->attr; pc = pField + fSkip; fSkip += (*(pField + fSkip) + sizeof (char)); if (pName->clsmask & CLS_member) { if ((cmpflag = fnCmp ((LPSSTR) pName, NULL, pc, pExState->state.fCase)) == 0) { type = ((plfMember)(pField + anchor))->index; MHOmfUnLock (hField); hField = 0; EVAL_MOD (pvF) = SHHMODFrompCXT (&pName->CXTT); SetNodeType (pvF, type); EVAL_STATE (pvF) = EV_lvalue; // save the casting data for the this pointer pSymClass->offset = offset; pSymClass->access = access; pSymClass->possibles = 1; pName->possibles++; } } break; case LF_ENUMERATE: access = ((plfEnumerate)(pField + fSkip))->attr; fSkip += offsetof (lfEnumerate, value); value = (ulong) RNumLeaf (pField + fSkip, &fSkip); pc = pField + fSkip; fSkip += *(pField + fSkip) + sizeof (char); if (pName->clsmask & CLS_enumerate) { if ((cmpflag = fnCmp ((LPSSTR) pName, NULL, pc, pExState->state.fCase)) == 0) { pSymClass->possibles = 1; pName->possibles++; } } break; case LF_STMEMBER: type = ((plfSTMember)(pField + anchor))->index; fSkip += offsetof (lfSTMember, Name); if (pName->clsmask & CLS_member) { if ((cmpflag = fnCmp ((LPSSTR) pName, NULL, pField + fSkip, pExState->state.fCase)) == 0) { pSymClass->access = ((plfSTMember)(pField + anchor))->attr; MHOmfUnLock (hField); hField = 0; EVAL_MOD (pvF) = SHHMODFrompCXT (&pName->CXTT); SetNodeType (pvF, type); EVAL_STATE (pvF) = EV_lvalue; EVAL_IS_STMEMBER (pvF) = TRUE; pSymClass->possibles = 1; pName->possibles++; } } fSkip += *(pField + fSkip) + sizeof (char); break; case LF_BCLASS: type = ((plfBClass)(pField + anchor))->index; access = ((plfBClass)(pField + anchor))->attr; fSkip += offsetof (lfBClass, offset); newindex = ((plfBClass)(pField + anchor))->index; offset = (UOFFSET)RNumLeaf (pField + fSkip, &fSkip); if ((pName->clsmask & CLS_bclass) != 0) { // switch to the base class type record to check the name MHOmfUnLock (hField); if ((hBase = THGetTypeFromIndex (EVAL_MOD (pvBase), newindex)) == 0) { pExState->err_num = ERR_BADOMF; return (SCN_error); } pField = (char *)(&((TYPPTR)MHOmfLock (hBase))->leaf); tSkip = offsetof (lfClass, data); RNumLeaf (pField + tSkip, &tSkip); pc = pField + tSkip; cmpflag = fnCmp ((LPSSTR) pName, NULL, pc, pExState->state.fCase); MHOmfUnLock (hBase); // reset to original field list if (cmpflag == 0) { // element has been found, set result values pSymClass->s.isbase = TRUE; pSymClass->s.isvbase = FALSE; pSymClass->offset += offset; EVAL_MOD (pvF) = SHHMODFrompCXT (&pName->CXTT); SetNodeType (pvF, type); EVAL_STATE (pvF) = EV_type; pSymClass->access = access; pSymClass->possibles = 1; pName->possibles++; } pField = (char *)(&((TYPPTR)MHOmfLock (hField))->data); } break; case LF_VBCLASS: type = ((plfBClass)(pField + anchor))->index; access = ((plfVBClass)(pField + anchor))->attr; newindex = ((plfVBClass)(pField + anchor))->index; vbptr = ((plfVBClass)(pField + anchor))->vbptr; fSkip += offsetof (lfVBClass, vbpoff); vbpoff = (UOFFSET)RNumLeaf (pField + fSkip, &fSkip); vbind = (short)RNumLeaf (pField + fSkip, &fSkip); if ((pName->clsmask & CLS_bclass) != 0) { // switch to the base class type record to check the name MHOmfUnLock (hField); if ((hBase = THGetTypeFromIndex (EVAL_MOD (pvBase), newindex)) == 0) { pExState->err_num = ERR_BADOMF; return (SCN_error); } pField = (char *)(&((TYPPTR)MHOmfLock (hBase))->leaf); tSkip = offsetof (lfClass, data); RNumLeaf (pField + tSkip, &tSkip); pc = pField + tSkip; cmpflag = fnCmp ((LPSSTR) pName, NULL, pc, pExState->state.fCase); MHOmfUnLock (hBase); // reset to original field list if (cmpflag == 0) { // element has been found, set result values pSymClass->s.isbase = FALSE; pSymClass->s.isvbase = TRUE; pSymClass->vbind = vbind; pSymClass->vbpoff = vbpoff; pSymClass->vbptr = vbptr; EVAL_MOD (pvF) = SHHMODFrompCXT (&pName->CXTT); SetNodeType (pvF, type); EVAL_STATE (pvF) = EV_type; pSymClass->access = access; pSymClass->possibles = 1; pName->possibles++; } pField = (char *)(&((TYPPTR)MHOmfLock (hField))->data); } break; case LF_IVBCLASS: fSkip += offsetof (lfVBClass, vbpoff); RNumLeaf (pField + fSkip, &fSkip); RNumLeaf (pField + fSkip, &fSkip); break; case LF_FRIENDCLS: newindex = ((plfFriendCls)(pField + fSkip))->index; fSkip += sizeof (struct lfFriendCls); if ((pName->clsmask & CLS_fclass) != 0) { DASSERT (FALSE); // switch to the base class type record to check the name MHOmfUnLock (hField); if ((hBase = THGetTypeFromIndex (EVAL_MOD (pvBase), newindex)) == 0) { pExState->err_num = ERR_INTERNAL; return (SCN_error); } pField = (char *)(&((TYPPTR)MHOmfLock (hBase))->data); tSkip = offsetof (lfClass, data); RNumLeaf (pField + tSkip, &tSkip); pc = pField + tSkip; cmpflag = fnCmp ((LPSSTR) pName, NULL, pc, pExState->state.fCase); MHOmfUnLock (hBase); // reset to original field list pField = (char *)(&((TYPPTR)MHOmfLock (hField))->data); if (cmpflag == 0) { // element has been found, set result values pName->typeOut = newindex; } } break; case LF_FRIENDFCN: newindex = ((plfFriendFcn)(pField + fSkip))->index; fSkip += sizeof (struct lfFriendFcn) + ((plfFriendFcn)(pField + fSkip))->Name[0]; if ((pName->clsmask & CLS_frmethod) != 0) { DASSERT (FALSE); } break; case LF_VFUNCTAB: fSkip += sizeof (struct lfVFuncTab); // save the type of the virtual function pointer vfpType = ((plfVFuncTab)(pField + anchor))->type; pc = vfuncptr; if (pName->clsmask & CLS_vfunc) { if ((cmpflag = fnCmp ((LPSSTR) pName, NULL, pc, pExState->state.fCase)) == 0) { MHOmfUnLock (hField); hField = 0; EVAL_MOD (pvF) = SHHMODFrompCXT (&pName->CXTT); SetNodeType (pvF, vfpType); EVAL_STATE (pvF) = EV_lvalue; // save the casting data for the this pointer if (pName->bnOp != 0) { pSymClass->offset = 0; pSymClass->access.access = CV_public; } pSymClass->possibles = 1; pName->possibles++; } } break; case LF_METHOD: count = ((plfMethod)(pField + fSkip))->count; cnt -= count - 1; newindex = ((plfMethod)(pField + fSkip))->mList; pc = pField + anchor + offsetof (lfMethod, Name); fSkip += sizeof (struct lfMethod) + *pc; if (pName->clsmask & CLS_method) { if ((cmpflag = fnCmp ((LPSSTR) pName, NULL, pc, pExState->state.fCase)) == 0) { // note that the OMF specifies that the vfuncptr will // be emitted as the first field after the bases if (pName->clsmask & CLS_virtintro) { // we are looking for the introducing virtual // method. We need to find a method with the // correct name of the correct type index that // is introducing. MHOmfUnLock (hField); if (IsIntroVirt (count, newindex, &vtabind) == FALSE) { cmpflag = 1; } else { if (FCN_VFPTYPE (pvF) == T_NOTYPE) { FCN_VFPTYPE (pvF) = vfpType; FCN_VFPTYPE (pName->pv) = vfpType; FCN_VTABIND (pvF) = vtabind; FCN_VTABIND (pName->pv) = vtabind; } cmpflag = 0; } pField = (char *)(&((TYPPTR)MHOmfLock (hField))->data); } else { // save the type index of the method list, the // count of methods overloaded on this name, // the type index of the vfuncptr. Also, // increment the number of possible features by // the overload count pSymClass->possibles = count; pName->possibles += count; pSymClass->mlist = newindex; pSymClass->vfpType = vfpType; } } } break; case LF_NESTTYPE: newindex = ((plfNestType)(pField + fSkip))->index; fSkip += offsetof (lfNestType, Name); pc = pField + fSkip; fSkip += *(pField + fSkip) + sizeof (char); if (pName->clsmask & CLS_ntype) { if ((cmpflag = fnCmp ((LPSSTR) pName, NULL, pc, pExState->state.fCase)) == 0) { // set type of typedef symbol pSymClass->possibles = 1; pName->possibles++; EVAL_STATE (pvF) = EV_type; EVAL_TYP(pvF) = newindex; } else if (pName->clsmask & CLS_enumerate) { // check if the nested type is an enum. if it is // we gotta search thru its field list for a matching // enumerate // sps - 9/14/92 HTYPE hEnum, hEnumField; // nested handle plfEnum pEnum; char *pEnumField; // field list of the enum record ushort enumCount; uint fSkip = 0; // offset in the field list uint anchor; // offset in the field list to start of type if (CV_IS_PRIMITIVE(newindex)) { break; } if ((hEnum = THGetTypeFromIndex (EVAL_MOD (pvBase), newindex)) == 0) { pExState->err_num = ERR_BADOMF; return (SCN_error); } pEnum = (plfEnum) (&((TYPPTR)MHOmfLock (hEnum))->leaf); if (pEnum->leaf == LF_ENUM) { if (pEnum->property.fwdref) { eval_t localeval = *pvBase; neval_t nv = &localeval; // forward ref - look for the definition of the UDT if ((newindex = GetUdtDefnTindex (newindex, pvBase, (char *)&(pEnum->Name[0]))) != T_NOTYPE) { if ((hEnum = THGetTypeFromIndex (EVAL_MOD (pvBase), newindex)) == 0) { pExState->err_num = ERR_BADOMF; return (SCN_error); } pEnum = (plfEnum) (&((TYPPTR)MHOmfLock (hEnum))->leaf); } else break; // No Fwd ref found... no CVInfo for nested type... proceed with search [rm] } if ((hEnumField = THGetTypeFromIndex (EVAL_MOD (pvBase), pEnum->field)) == 0) { if ( BindingBP ) { break; } else { pExState->err_num = ERR_BADOMF; return (SCN_error); } } pEnumField = (char *)(&((TYPPTR)MHOmfLock (hEnumField))->data); for (enumCount = pEnum->count; enumCount > 0; enumCount--) { fSkip += SkipPad(((uchar *)pEnumField) + fSkip); anchor = fSkip; DASSERT ((((plfEasy)(pEnumField + fSkip))->leaf) == LF_ENUMERATE); access = ((plfEnumerate)(pEnumField + fSkip))->attr; fSkip += offsetof (lfEnumerate, value); value = (ulong) RNumLeaf (pEnumField + fSkip, &fSkip); pc = pEnumField + fSkip; fSkip += *(pEnumField + fSkip) + sizeof (char); if ((cmpflag = fnCmp ((LPSSTR) pName, NULL, pc, pExState->state.fCase)) == 0) { EVAL_MOD (pvF) = SHHMODFrompCXT (&pName->CXTT); SetNodeType (pvF, pEnum->utype); EVAL_STATE (pvF) = EV_constant; EVAL_LONG (pvF) = value; // save the casting data for the this pointer pSymClass->access = access; pSymClass->possibles = 1; pName->possibles++; break; } } MHOmfUnLock (hEnumField); } MHOmfUnLock (hEnum); } } break; default: pExState->err_num = ERR_BADOMF; retval = SCN_notfound; } #ifdef NEVER // if ((cnt == 0) && ************ (pName->tTypeDef != 0)) { if ((cnt == 0) && (pName->tTypeDef != 0)) { // we found a typedef name that was not hidden by // a member or method name } #endif if (cmpflag == 0) { pSymClass->s.viable = TRUE; retval = SCN_found; break; } } #endif if (hField != 0) { MHOmfUnLock ((HDEP)hField); } return (retval); } /** SetBPValue - set the breakpoint list from a class search * * status = SetBPValue (pName) * * Entry pName = pointer to structure describing search * pSymCl = pointer to class element * * Exit pName updated to reflect found feature * this pointer inserted in bind tree if feature is part of * the class pointed to by this pointer of method * * Returns SCN_rewrite if this pointer inserted (rebind required) * SCN_found if no error * SCN_error otherwise */ LOCAL SCN_t SetBPValue ( psearch_t pName ) { peval_t pv; DASSERT ((pName->cFound == 0) && (pName->hFound == 0)); if (pSymClass->mlist != T_NOTYPE) { if ((pName->possibles == 1) || (bArgList != 0)) { switch (MatchMethod (pName, pSymClass)) { default: DASSERT (FALSE); case MTH_error: return (SCN_error); case MTH_found: break; } } else { // we have a list of functions and no argument list. // This means that we have an ambiguous breakpoint // and need to add the functions to the breakpoint // list for user disambiguation. Basically what // we are going to do is force all of the methods // into the breakpoint list and let later // binding resolve any errors. return (OverloadToAmbList (pName, pSymClass)); } } // at this point, the following values are set // pName->addr = address of method if not virtual method // pName->typeOut = type index of method // pName->hSym = handle of symbol for function pv = &pSymClass->evalP; if ((FCN_ATTR (pv).mprop == CV_MTvirtual) || (FCN_ATTR (pv).mprop == CV_MTintro)) { pExState->err_num = ERR_NOVIRTUALBP; return (SCN_error); } pv = pName->pv; *pv = pSymClass->evalP; EVAL_ACCESS (pv) = (uchar)(pSymClass->access.access); pName->typeOut = EVAL_TYP (pv); // save the offset of a class member // (caviar #1756) --gdp 9-10-92 if (pName->bnOp) { peval_t pvOp = &(pnodeOfbnode(pName->bnOp))->v[0]; EVAL_IS_MEMBER(pvOp) = TRUE; MEMBER_OFFSET(pvOp) = pName->initializer == INIT_right ? pSymClass->offset : 0; } return (SCN_found); } LOCAL SCN_t OverloadToAmbList ( psearch_t pName, psymclass_t pSymCl ) { SCN_t retval; // add the first list of methods if ((retval = MethodsToAmbList (pName, pSymCl)) != SCN_found) { return (retval); } // loop through the remaining class descriptors adding them to the list while (pName->hAmbCl != 0) { MoveSymCl (pName->hAmbCl); if ((retval = MethodsToAmbList (pName,pSymCl)) != SCN_found) { return (retval); } } if (pExState->ambiguous == 0) { // no instantiated function has been found return (SCN_notfound); } SymToNode (pName); DASSERT (EVAL_TYP (pName->pv) != T_NOTYPE); return (SCN_found); } /** MethodsToAmbList - add a list of methods to ambiguous breakpoints * * flag = MethodsToAmbList (pName, pSymCl) * * Entry pName = pointer to search descriptor * pSymCl = pointer to symbol class structure * * Exit methods added to list of ambiguous breakpoints * * Returns SCN_found if methods added * SCN_error if error during addition * */ LOCAL SCN_t MethodsToAmbList ( psearch_t pName, psymclass_t pSymCl ) { HTYPE hMethod; pmlMethod pMethod; uint skip; CV_fldattr_t attr; CV_typ_t type; ushort vtabind; HDEP hQual; peval_t pvF; ushort count = pSymCl->possibles; peval_t pvB; HMOD hMod; HDEP hTemp; psearch_t pTemp; bool_t retval; pvB = &pSymCl->symbase[pSymCl->CurIndex].Base; hMod = EVAL_MOD (pvB); // we now walk the list of methods adding each method to the list of // ambiguous breakpoints if ((hMethod = THGetTypeFromIndex (hMod, pSymCl->mlist)) == (HTYPE) NULL) { DASSERT (FALSE); return (MTH_error); } // set the number of methods overloaded on this name and the index into // the method list skip = 0; while (count-- > 0) { // lock the omf record, extract information for the current entry in // the method list and increment to field for next method pMethod = (pmlMethod)((&((TYPPTR)MHOmfLock (hMethod))->leaf) + 1); pMethod = (pmlMethod)((uchar *)pMethod + skip); attr = pMethod->attr; type = pMethod->index; skip += sizeof (mlMethod); if (pMethod->attr.mprop == CV_MTintro) { vtabind = (short)RNumLeaf (((char *)pMethod) + skip, &skip); } else { vtabind = 0; } MHOmfUnLock (hMethod); // now add the method to the list pvF = &pSymCl->evalP; EVAL_MOD (pvF) = hMod; DASSERT (type != T_NOTYPE); if (SetNodeType (pvF, type) == FALSE) { return (MTH_error); } else { FCN_ATTR (pvF) = attr; FCN_VTABIND (pvF) = vtabind; FCN_VFPTYPE (pvF) = pSymCl->vfpType; pName->best.match = type; if (((hQual = GenQualName (pName, pSymCl)) == 0) || (SearchQualName (pName, pSymCl, hQual, TRUE) == FALSE)) { if (hQual != 0) { MHMemFree (hQual); } return (SCN_error); } MHMemFree (hQual); } /* * Function must be present in the exe and the one we found must * be of the correct type (it will find others for some reason) * or else it should be ignored. We will conver all possible * function types so throwing this one away should make no * difference */ if ((FCN_NOTPRESENT (pvF) == FALSE) && (EVAL_TYP( pvF ) == type)) { if (pExState->ambiguous == 0) { // we have found the first function. We need to set all of // the return values in the pointer to the search entry pExState->ambiguous = pName->bn; // at this point, the following values are set // pName->addr = address of method if not virtual method // pName->typeOut = type index of method // pName->hSym = handle of symbol for function *pName->pv = pSymClass->evalP; EVAL_ACCESS (pName->pv) = (uchar)(pSymClass->access.access); pName->typeOut = EVAL_TYP (pName->pv); pName->hSym = EVAL_HSYM (pvF); } else { if ((hTemp = MHMemAllocate (sizeof (search_t))) == 0) { pExState->err_num = ERR_NOMEMORY; return (SCN_error); } pTemp = MHMemLock (hTemp); *pTemp = *pName; pTemp->hSym = pvF->hSym; retval = AmbToList (pTemp); MHMemUnLock (hTemp); MHMemFree (hTemp); if (retval == FALSE) { return (SCN_error); } } } } if (pExState->ambiguous == 0) { return SCN_notfound; } return (SCN_found); } /** SetValue - set the result of the class search * * status = SetValue (pName) * * Entry pName = pointer to structure describing search * pSymClass = pointer to class element * * Exit pName updated to reflect found feature * this pointer inserted in bind tree if feature is part of * the class pointed to by this pointer of method * * Returns SCN_rewrite if this pointer inserted (rebind required) * SCN_found if no error * SCN_error otherwise */ LOCAL SCN_t SetValue ( psearch_t pName ) { peval_t pv; peval_t pvOp; SCN_t retval; HDEP hQual; // When we get here, the situation is a bit complex. // If we are not binding breakpoints, the following conditions // must be true: // pName->hAmbCl = 0 (only one feature can remain after dominance) // pName->cFound = 0 // pName->hFound = 0 // pSymClass->s.viable = TRUE // If the feature is a data item (pSymClass->mlist == T_NOTYPE), then // pName->possibles = 1 // If the feature is a method, then // pName->possibles = number of overloads on name // pSymClass->mlist = type index of member list // bArgList = based pointer to argument list tree (cannot be 0) // Argument matching must result in a best match to a single method // // If we are binding breakpoints, the following conditions must be true // pName->cFound = 0 // pName->hFound = 0 // pName->possibles = total number of methods in pSymClass and // pName->hAmbCl // pName->hAmbCl > 0 if two or more features survived dominance // Each of the features in pSymClass and the pName->hAmbCl list // must be a method list (pSymClass->mlist != T_NOTYPE) // // If we do not have an argument list, then we accept all methods in // pSymClass->mlist and pName->hAmbCl.mlist. The number of methods is // pName->possibles. // // If we do have an argument list, then we accept all methods in // pSymClass->mlist and pName->hAmbCl.mlist that are exact matches // for the argument list. Implicit conversions are not considered. // The number of methods must less than 1 + number of elements in the // list pName->hAmbCl and must be less than or equal to pName->possibles. if (BindingBP == TRUE) { // call the set of routines that will process breakpoints on methods // of a class, the inheritance tree of the class and the derivation // tree of the class. If the routine returns without error, pName // describes the first function breakpoint and hTMList describes the // remainder of the list of methods that match the function and // signature if one is specified. return (SetBPValue (pName)); } // At this point, there must be only one class after dominance resolution, // the count of the found items must be zero, and the handle of the found // item list must be null. Otherwise there was a failure in dominance // resolution. DASSERT ((pName->hAmbCl == 0) && (pName->cFound == 0) && (pName->hFound == 0) && (pSymClass->s.viable == TRUE)); if (pSymClass->mlist == T_NOTYPE) { DASSERT (pName->possibles == 1); } else if (bArgList == 0) { pExState->err_num = ERR_NOARGLIST; return (SCN_error); } // if we are processing C++, then we can allow for overloaded methods // which is specified by the type index of the method list not being // zero. If this is true, then we select the best of the overloaded // methods. if (pSymClass->mlist != T_NOTYPE) { switch (MatchMethod (pName, pSymClass)) { default: DASSERT (FALSE); case MTH_error: return (SCN_error); case MTH_found: // at this point, the following values are set // pName->addr = address of method if not virtual method // pName->typeOut = type index of method // pName->hSym = handle of symbol for function pv = &pSymClass->evalP; if (FCN_ATTR (pv).mprop == CV_MTvirtual) { // search to introducing virtual method if ((retval = FindIntro (pName)) != SCN_found) { return (retval); } } break; } } // the symbol is a data member of the class (C or C++). If an // explict class was not specified and the current context is // implicitly a class (we are in the scope of the method of the class), // then we rewrite the tree to change the symbol reference to this->symbol if ((pName->initializer != INIT_base) && (pName->initializer != INIT_sym) && (pName->ExpClass == 0)) { //DASSERT (FALSE); pExState->err_num = ERR_INTERNAL; return (SCN_error); } else if ((pName->ExpClass == 0) && (ClassImp != 0) && (pName->initializer != INIT_base)) { // if the feature is a member of *this class of a method, then // we need to rewrite // feature // to // this->feature // The calling routine will need to rebind the expression InsertThis (pName); return (SCN_rewrite); } // the initializer for the search must be INIT_right or INIT_base. // by the time we get to here we know that bnOp is the based pointer to // the node that will receive the casting expression and pv points // to the feature node. pv = pName->pv; pvOp = &(pnodeOfbnode(pName->bnOp)->v[0]); switch (pName->initializer) { case INIT_right: EVAL_CBTOK(&pSymClass->evalP) = EVAL_CBTOK(pv); EVAL_ITOK(&pSymClass->evalP) = EVAL_ITOK(pv); *pv = pSymClass->evalP; EVAL_ACCESS (pv) = (uchar)(pSymClass->access.access); pName->typeOut = EVAL_TYP (pv); EVAL_IS_MEMBER (pvOp) = TRUE; MEMBER_TYPE (pvOp) = EVAL_TYP (pv); MEMBER_OFFSET (pvOp) = pSymClass->offset; MEMBER_ACCESS (pvOp) = pSymClass->access; if ((pSymClass->s.isvbase == TRUE) || (pSymClass->s.isivbase == TRUE)) { MEMBER_VBASE (pvOp) = pSymClass->s.isvbase; MEMBER_IVBASE (pvOp) = pSymClass->s.isivbase; MEMBER_VBPTR (pvOp) = pSymClass->vbptr; MEMBER_VBPOFF (pvOp) = pSymClass->vbpoff; MEMBER_VBIND (pvOp) = pSymClass->vbind; } break; case INIT_base: *pv = pSymClass->symbase[pSymClass->CurIndex].Base; EVAL_ACCESS (pv) = (uchar)(pSymClass->symbase[pSymClass-> CurIndex].attrBC.access); pName->typeOut = EVAL_TYP (pv); EVAL_IS_MEMBER (pvOp) = TRUE; EVAL_ACCESS (pvOp) = (uchar)(pSymClass->symbase[pSymClass-> CurIndex].attrBC.access); MEMBER_OFFSET (pvOp) = 0; break; default: DASSERT (FALSE); return (SCN_error); } if (EVAL_IS_STMEMBER (pv) == FALSE) { // the feature is not a static data member of the class return (GenQualExpr (pName)); } else { // the feature is a static member so we need to generate the // qualified path and search for a symbol of the correct type // so we can set the address if (((hQual = GenQualName (pName, pSymClass)) == 0) || (SearchQualName (pName, pSymClass, hQual, FALSE) == FALSE)) { if (hQual != 0) { MHMemFree (hQual); } return (SCN_error); } *pv = pSymClass->evalP; EVAL_STATE (pv) = EV_lvalue; MHMemFree (hQual); return (SCN_found); } } // Support routines /** AddETConst - add evalthisconst node * * pn = AddETConst (pnP, off, btype) * * Entry pnP = pointer to previous node * * Exit OP_evalthisconst node added to bind tree * current node linked to pnP as left child if pnP != NULL * pTree->node_next advanced * btype = type of the base class * * Returns pointer to node just allocated */ LOCAL pnode_t AddETConst ( pnode_t pnP, OFFSET off, CV_typ_t btype ) { pnode_t pn; padjust_t pa; pn = (pnode_t)(((char *)pTree) + pTree->node_next); pa = (padjust_t)(&pn->v[0]); _fmemset (pn, 0, sizeof (node_t) + sizeof (adjust_t)); NODE_OP (pn) = OP_thisconst; pa->btype = btype; pa->disp = off; if (pnP != NULL) { NODE_LCHILD (pnP) = bnodeOfpnode(pn); } pTree->node_next += sizeof (node_t) + sizeof (adjust_t); return (pn); } /** AddETInit - add evalthisinit node * * pn = AddETInit (pnP, btype) * * Entry pnP = pointer to previous node * * Exit OP_evalthisinit node added to bind tree * current node linked to pnP as left child if pnP != NULL * pTree->node_next advanced * btype = type of the base class * * Returns pointer to node just allocated */ LOCAL pnode_t AddETInit ( pnode_t pnP, CV_typ_t btype ) { pnode_t pn; padjust_t pa; pn = (pnode_t)(((char *)pTree) + pTree->node_next); pa = (padjust_t)(&pn->v[0]); _fmemset (pn, 0, sizeof (node_t) + sizeof (adjust_t)); NODE_OP (pn) = OP_thisinit; pa->btype = btype; if (pnP != NULL) { NODE_LCHILD (pnP) = bnodeOfpnode(pn); } pTree->node_next += sizeof (node_t) + sizeof (adjust_t); return (pn); } /** AddETExpr - add evalthisexpr node * * pn = AddETExpr (pnP, vbptr, vbpoff, vbind, btype) * * Entry pnP = pointer to previous node * vbptr = type index of virtual base pointer * vboff = offset of vbptr from address point * vbdisp = offset of displacement in virtual base table * btype = type of the base class * * Exit OP_evalthisconst node added to bind tree * current node linked to pnP as left child if pnP != NULL * pTree->node_next advanced * * Returns pointer to node just allocated * * The evaluation of this node will result in * * ab = (ap * vbpoff) + *(*(ap +vbpoff) + vbdisp) * where * ab = address of base class * ap = current address point */ LOCAL pnode_t AddETExpr ( pnode_t pnP, CV_typ_t vbptr, OFFSET vbpoff, OFFSET vbdisp, CV_typ_t btype ) { pnode_t pn; padjust_t pa; pn = (pnode_t)(((char *)pTree) + pTree->node_next); pa = (padjust_t)(&pn->v[0]); _fmemset (pn, 0, sizeof (node_t) + sizeof (adjust_t)); NODE_OP (pn) = OP_thisexpr; pa->btype = btype; pa->disp = vbdisp; pa->vbpoff = vbpoff; pa->vbptr = vbptr; if (pnP != NULL) { NODE_LCHILD (pnP) = bnodeOfpnode(pn); } pTree->node_next += sizeof (node_t) + sizeof (adjust_t); return (pn); } /*** AddVBList - Add virtual bases to searched or dominated list * * status = AddVBList (pSymClass, ppList, phMem) * * Entry pSymClass = pointer to base class path list structure * ppList = pointer to dominated or searched list * phMem = pointer to handle for ppList * * Exit virtual bases added to list * * Return SCN_found if all bases added to list * SCN_error if bases could not be added */ LOCAL SCN_t AddVBList ( psymclass_t pSymClass, pdombase_t *ppList, HDEP * phList ) { ushort cnt; // count of number of elements in struct HTYPE hField; // handle to type record for struct field list char *pField; // pointer to field list uint fSkip = 0; // offset in the field list uint anchor; // offset in the field list to start of type CV_typ_t newindex; ushort retval = SCN_found; bool_t termflag = FALSE; peval_t pvBase = &pSymClass->symbase[pSymClass->CurIndex].Base; ushort pad; // set hField to the handle of the field list for the class if ((hField = THGetTypeFromIndex (EVAL_MOD (pvBase), CLASS_FIELD (pvBase))) == 0) { pExState->err_num = ERR_BADOMF; return (SCN_error); } pField = (char *)(&((TYPPTR)MHOmfLock (hField))->data[0]); // walk field list for the class for (cnt = CLASS_COUNT (pvBase); cnt > 0; cnt--) { if ((pad = *(((char *)pField) + fSkip)) >= LF_PAD0) { // there is a pad field fSkip += pad & 0x0f; } anchor = fSkip; switch (((plfEasy)(pField + fSkip))->leaf) { case LF_INDEX: // switch to new type record because compiler split it up newindex = ((plfIndex)(pField + fSkip))->index; MHOmfUnLock (hField); if ((hField = THGetTypeFromIndex (EVAL_MOD (pvBase), newindex)) == 0) { pExState->err_num = ERR_INTERNAL; return (SCN_error); } pField = (char *)(&((TYPPTR)MHOmfLock (hField))->data[0]); fSkip = 0; // the LF_INDEX is not part of the field count cnt++; break; case LF_BCLASS: // skip direct base class fSkip += offsetof (lfBClass, offset[0]); RNumLeaf (pField + fSkip, &fSkip); break; case LF_VBCLASS: case LF_IVBCLASS: newindex = ((plfVBClass)(pField + fSkip))->index; if ((retval = AddVBType (ppList, phList, newindex)) == SCN_error) { termflag = TRUE; break; } fSkip += offsetof (lfVBClass, vbpoff[0]); RNumLeaf (pField + fSkip, &fSkip); RNumLeaf (pField + fSkip, &fSkip); break; default: termflag = TRUE; break; } if (termflag == TRUE) { break; } } MHOmfUnLock (hField); return (retval); } /*** AddVBType - Add virtual base to list * * status = AddVBType (ppList, phList, type) * * Entry ppList = pointer to dominated or searched list * phList = pointer to handle for ppList * type = type index * * Exit type added to list * * Return SCN_found if all bases added to list * SCN_error if bases could not be added */ LOCAL SCN_t AddVBType ( pdombase_t *ppList, HDEP *phList, CV_typ_t type ) { ushort i; bool_t add = TRUE; ushort len; pdombase_t pList = *ppList; for (i = 0; i < pList->CurIndex; i++) { if (type == pList->dom[i]) { add = FALSE; break; } } if (add == TRUE) { if (pList->CurIndex >= pList->MaxIndex) { len = sizeof (dombase_t) + (pList->MaxIndex + 10) * sizeof (CV_typ_t); MHMemUnLock (*phList); if ((*phList = MHMemReAlloc (*phList, len)) == 0) { pExState->err_num = ERR_NOMEMORY; pList = MHMemLock (*phList); return (SCN_error); } else { pList = MHMemLock (*phList); pVBDom->MaxIndex += 10; } } pList->dom[pList->CurIndex++] = type; } return (SCN_found); } /** AmbFromList - add get next ambiguous symbol from list * * status = AmbFromList (pName) * * Entry pName = pointer to list describing search * * Exit breakpoint added to list of breakpoints * pName reset to continue breakpoint search * * Returns HR_found if breakpoint added * HR_error if breakpoint could not be added to list */ LOCAL ushort AmbFromList ( psearch_t pName ) { psearch_t pBPatch; pBPatch = MHMemLock (hBPatch); *pName = *pBPatch; MHMemUnLock (hBPatch); pName->pv = &(pnodeOfbnode(pName->bn)->v[0]); EVAL_HSYM (pName->pv) = pName->hSym; if ((SymToNode (pName) == TRUE) && (PushStack (pName->pv) == TRUE)) { return (HR_found); } else { return (HR_error); } } /** AmbToList - add ambiguous symbol to list * * fSuccess = AmbToList (pName) * * Entry pName = pointer to list describing search * * Exit ambiguous symbol added to list pointed to by pTMList * pTMLbp * * Returns TRUE if symbol added * FALSE if error */ LOCAL bool_t AmbToList ( psearch_t pName ) { HDEP hBPatch; psearch_t pBPatch; if (iBPatch >= (USHORT)pTMLbp->cTMListMax) { // the back patch list has filled the TM list if (!GrowTMList ()) { pExState->err_num = ERR_NOMEMORY; return (FALSE); } } if ((hBPatch = MHMemAllocate (sizeof (search_t))) != 0) { pTMList[iBPatch++] = hBPatch; pBPatch = MHMemLock (hBPatch); *pBPatch = *pName; MHMemUnLock (hBPatch); return (TRUE); } else { pExState->err_num = ERR_NOMEMORY; return (FALSE); } } /** ClAmbToList - add class ambiguous symbol to list * * status = ClAmbToList (pName) * * Entry pName = pointer to list describing search * * Exit ambiguous symbol added to list pointed to by pTMList * pTMLbp * pName reset to continue breakpoint search * * Returns HR_... describing state */ LOCAL HR_t ClAmbToList ( psearch_t pName ) { HDEP hSearch; psearch_t pSearch; HR_t retval; HDEP hevalT; PopStack (); if (pExState->ambiguous == 0) { // this is the first breakpoint symbol found. // indicate the only node in the tree that is // allowed ambiguity and initialize list of // symbols for later back patching into duplicated // expression trees. We save the initial search packet // so that the first symbol will be set into the breakpoint // list. pExState->ambiguous = pName->bn; if ((hSearch = MHMemAllocate (sizeof (search_t))) == 0) { pExState->err_num = ERR_NOMEMORY; return (HR_error); } if ((hSearch = MHMemAllocate (sizeof (eval_t))) == 0) { MHMemFree (hSearch); pExState->err_num = ERR_NOMEMORY; return (HR_error); } pSearch = MHMemLock (hSearch); *pSearch = *pName; pSearch->pv = (peval_t)MHMemLock (hevalT); retval = SearchSym (pSearch); PushStack (pName->pv); MHMemUnLock (hSearch); MHMemFree (hSearch); MHMemUnLock (hevalT); MHMemFree (hevalT); return (retval); } else if (pExState->ambiguous != pName->bn) { // there has already been a ambiguous symbol that is // not at this node in the tree pExState->err_num = ERR_BPAMBIGUOUS; return (HR_error); } else { if (AmbToList (pName) == FALSE) { return (HR_error); } // reset search to allow more symbols pName->possibles = 0; return (SearchSym (pName)); } } /** DupSymCl - duplicate symbol class structure and link to list * * DupSymCl (pName); * * Entry pName = handle of structure describing search * *pSymClass = symbol class structure * * Exit *pSymClass = duplicated and linked to list pName->hFound * pSymClass->s.viable = FALSE * * Returns SCN_found if pSymClass duplicated * SCN_error if unable to allocate memory for duplication */ LOCAL SCN_t DupSymCl ( psearch_t pName ) { HDEP hSymCl; psymclass_t pSymCl; ushort size; size = (ushort) (sizeof (symclass_t) + (pSymClass->CurIndex + 1) * sizeof (symbase_t)); if ((hSymCl = MHMemAllocate (size)) == 0) { pExState->err_num = ERR_NOMEMORY; return (SCN_error); } pSymCl = MHMemLock (hSymCl); _fmemmove (pSymCl, pSymClass, size); pSymCl->MaxIndex = (ushort)(pSymCl->CurIndex + 1); pSymCl->hNext = pName->hFound; pName->hFound = hSymCl; pName->cFound++; pSymClass->s.viable = FALSE; MHMemUnLock (hSymCl); return (SCN_found); } /** FindIntro - find introducing virtual method * * status = FindIntro (pName) * * Entry pName = structure describing search * pSymClass = structure describing class search * * Exit pSymClass updated to reflect introducing virtual method * * Returns SCN_found if introducing virtual method found * SCN_error if introducing virtual method not found */ LOCAL SCN_t FindIntro ( psearch_t pName ) { ushort oldmask; SCN_t retval; oldmask = pName->clsmask; // limit searches to introducing virtual methods // the CLS_vfunc is set so that we pick up the vfuncptr information pName->clsmask = CLS_virtintro | CLS_vfunc | CLS_method; retval = SearchBases (pName); pName->clsmask = oldmask; return (retval); } /*** GenQualName - generate qualified method name * * handle = GenQualName (pName, pSymClass) * * Entry pSymCLass = pointer to struct describing search * * Exit qualified function name generated * * Returns 0 if name string not generated * handle if name string generated */ LOCAL HDEP GenQualName ( psearch_t pName, psymclass_t pSymCl ) { HDEP hQual; char *pQual; uint buflen = 255; uint len; uint fSkip; char *pField; // pointer to field list HTYPE hBase; // handle to type record for base class char *pc; short i; peval_t pL; if ((hQual = MHMemAllocate (buflen + 1)) == 0) { // unable to allocate memory pExState->err_num = ERR_NOMEMORY; return (0); } pQual = MHMemLock (hQual); _fmemset (pQual, 0, 256); // walk up list of search structures adding qualifiers for (i = 0; i <= pSymCl->CurIndex; i++) { if (CLASS_PROP (&pSymCl->symbase[i].Base).cnested == TRUE) { NOTTESTED (FALSE); } if ((pSymCl->symbase[i].clsmask & CLS_virtintro) != 0) { // if the search turned into a search for the introducing virtual // function, break out of this loop so that the method name is // correct break; } pL = &pSymCl->symbase[i].Base; } // copy name of last class encountered if ((hBase = THGetTypeFromIndex (EVAL_MOD (pL), EVAL_TYP (pL))) == 0) { pExState->err_num = ERR_INTERNAL; return (HDEP)(SCN_error); } pField = (char *)(&((TYPPTR)MHOmfLock ((HDEP)hBase))->leaf); switch (((plfClass)pField)->leaf) { case LF_CLASS: case LF_STRUCTURE: fSkip = offsetof (lfClass, data[0]); RNumLeaf (pField + fSkip, &fSkip); pc = pField + fSkip; break; case LF_UNION: fSkip = offsetof (lfUnion, data[0]); RNumLeaf (pField + fSkip, &fSkip); pc = pField + fSkip; break; default: DASSERT (FALSE); MHOmfUnLock ((HDEP)hBase); MHMemUnLock (hQual); return (hQual); } len = *pc++; if ((len + 2) <= buflen) { _fmemcpy (pQual, pc, len); pQual += len; *pQual++ = ':'; *pQual++ = ':'; buflen -= len + 2; } _fmemcpy (pQual, pName->sstr.lpName, pName->sstr.cb); MHOmfUnLock ((HDEP)hBase); MHMemUnLock (hQual); return (hQual); } /*** pvThisFromST - generate expression for null path to qualified name * * status = pvThisFromST (bnOp) * * Entry bnOp = node to add init expression to * * Exit qualified path expression generated * * Returns TRUE if expression generated * FALSE if no memory */ bool_t pvThisFromST ( bnode_t bnOp ) { uint len; pnode_t Parent; peval_t pvOp; int diff; if (ST == NULL) { return (FALSE); } // we need to generate an expression tree attached to the operator node // which will compute the null this pointer adjustment from ST. This // routine is used for pClass->Class::member len = sizeof (node_t) + sizeof (adjust_t); if ((diff = pTree->size - pTree->node_next - len) < 0) { if (!GrowETree ((uint) (-diff))) { pExState->err_num = ERR_NOMEMORY; return (FALSE); } if (bnCxt != 0) { // the context was pointing into the expression tree. // since the expression tree could have been reallocated, // we must recompute the context pointer pCxt = SHpCXTFrompCXF ((PCXF)&(pnodeOfbnode(bnCxt))->v[0]); } } pvOp = &pnodeOfbnode(bnOp)->v[0]; EVAL_IS_MEMBER (pvOp) = TRUE; MEMBER_THISEXPR (pvOp) = pTree->node_next; Parent = NULL; // now add the node that causes pvThis to be initialized with the // value of ST. AddETInit (Parent, EVAL_TYP (ST)); return (TRUE); } /*** GenQualExpr - generate expression for path to qualified name * * status = GenQualExpr (pName) * * Entry pName = pointer to struct describing search * pSymClass = pointer to class path structure * * Exit qualified path expression generated * * Returns SCN_found is expression generated * SCN_error if no memory */ LOCAL SCN_t GenQualExpr ( psearch_t pName ) { short i; peval_t pvOp; uint len; pnode_t Parent; int diff; peval_t pvB; CV_typ_t btype; OFFSET off; uint pvOff = 0; // we need to generate an expression tree attached to the operator node // which will compute the this pointer adjustment. The number // of nodes is potentially the number of base classes + an // initializer. // M00OPTIMIZE - if the final base is a direct or indirect virtual base // M00OPTIMIZE - of the inital class, then the entire expression can be // M00OPTIMIZE - reduced to one node + the initializer len = (pSymClass->CurIndex + 2) * (sizeof (node_t) + sizeof (adjust_t)); pvOp = &(pnodeOfbnode(pName->bnOp)->v[0]); if ((diff = pTree->size - pTree->node_next - len) < 0) { if (((char *)(pName->pv) >= (char *)pTree) && ((char *)(pName->pv) < ((char *)pTree) + pTree->size)) { pvOff = ((char *)pName->pv) - ((char *)pTree); } if (!GrowETree ((uint) (-diff))) { pExState->err_num = ERR_NOMEMORY; return (SCN_error); } if (bnCxt != 0) { // the context was pointing into the expression tree. // since the expression tree could have been reallocated, // we must recompute the context pointer pCxt = SHpCXTFrompCXF ((PCXF)&(pnodeOfbnode(bnCxt))->v[0]); } if (pvOff != 0) { pName->pv = (peval_t)(((char *)pTree) + pvOff); } pvOp = &(pnodeOfbnode(pName->bnOp)->v[0]); } // walk the path backwards generating the expression required to do // the adjustment. The backwards walk is because evaluation is depth // first. MEMBER_THISEXPR (pvOp) = pTree->node_next; Parent = NULL; for (i = pSymClass->CurIndex; i > 0; i--) { pvB = &pSymClass->symbase[i].Base; btype = EVAL_TYP (pvB); off = pSymClass->symbase[i].thisadjust; if (pSymClass->symbase[i].virtual == TRUE) { Parent = AddETExpr (Parent, pSymClass->symbase[i].vbptr, pSymClass->symbase[i].vbpoff, off, btype); } else { Parent = AddETConst (Parent, off, btype); } } // add the first real adjustment if necessary. What is really happening // here is that the the expression was of the form x.CLASS::member and // we need an adjustment from the object to the start of the base class pvB = &pSymClass->evalP; btype = EVAL_TYP (pvB); if ((EVAL_STATE (pvB) == EV_type) && EVAL_IS_CLASS (pvB)) { Parent = AddETConst (Parent, pSymClass->offset, btype); } // now add the node that causes pvThis to be initialized with the // value of ST. pvB = &pSymClass->symbase[i].Base; btype = EVAL_TYP (pvB); Parent = AddETInit (Parent, btype); return (SCN_found); } /** GetArgType - get type of argument to function * * fSuccess = GetArgType (pvF, argn, ptype); * * Entry pvF = pointer to function description * argn = argument index (0-based) * ptype = pointer to location to store type * * Exit *ptype = type of argument * *ptype = 0 if vararg * * Returns FARG_error if error * FARG_none if no arguments * FARG_vararg if varargs allowed * FARG_exact if exact list */ farg_t GetArgType ( peval_t pvF, short argn, CV_typ_t *type ) { HTYPE hList; // handle of the type list plfArgList pList = NULL; register farg_t retval; if (FCN_PCOUNT (pvF) == 0) { // there are no formals. We need to check for varargs *type = 0; if (FCN_VARARGS (pvF) == TRUE) { return (FARG_vararg); } else { return (FARG_none); } } // set hList to the handle of the type list if ((hList = THGetTypeFromIndex (EVAL_MOD (pvF), FCN_PINDEX (pvF))) == HNULL) { DASSERT (FALSE); return (FARG_error); } if (argn >= FCN_PCOUNT (pvF) - 1) { // this argument can possibly be a vararg. if (FCN_VARARGS (pvF) == TRUE) { *type = 0; retval = FARG_vararg; } else if (argn > FCN_PCOUNT (pvF)) { // varargs are not allowed and the maximum arg count is exceeded retval = FARG_error; } else { // varargs are not allowed and this is the last argument pList = (plfArgList)(&((TYPPTR)MHOmfLock ((HDEP)hList))->leaf); *type = pList->arg[argn]; retval = FARG_exact; } } else { // this is before the last argument so it cannot be a vararg // load type list and store type of argument pList = (plfArgList)(&((TYPPTR)MHOmfLock ((HDEP)hList))->leaf); *type = pList->arg[argn]; retval = FARG_exact; } if (pList != NULL) { MHOmfUnLock ((HDEP)hList); } return (retval); } /** VBSearched - check to see if virtual base hase already been searched * * flag = VBSearched (type) * * Entry type = type index of virtual base * * Exit none * * Returns TRUE if virtual base has already been searched * FALSE if virtual base has not been searched */ LOCAL bool_t VBSearched ( CV_typ_t type ) { ushort i; for (i = 0; i < pVBSearch->CurIndex; i++) { if (pVBSearch->dom[i] == type) { return (TRUE); } } return (FALSE); } /** GrowTMList - grow TML * * fSuccess = GrowTMList (void) * * Entry pTMLbp = pointer to TML * pTMList = pointer to TM list * * Exit TML grown * pTMList = pointer to locked table * * Returns TRUE if table grown * FALSE if out of memory */ LOCAL bool_t GrowTMList( void ) { register bool_t retval = FALSE; MHMemUnLock (pTMLbp->hTMList); if ((pTMLbp->hTMList = MHMemReAlloc (pTMLbp->hTMList, (pTMLbp->cTMListMax + TMLISTCNT) * sizeof (HTM))) != 0) { pTMLbp->cTMListMax += TMLISTCNT; retval = TRUE; } // lock list to maintain lock/unlock synchronization pTMList = MHMemLock (pTMLbp->hTMList); return (retval); } /** IncrSymBase - increment symbase_t index and grow if necessary * * status = IncrSymbase (); * * Entry none * * Exit *pSymClass->CurIndex incremented * pSymBase grown if necessary * * Returns SCN_found if pSymClass->CurIndex incremented * SCN_error if unable to allocate memory for duplication */ LOCAL SCN_t IncrSymBase ( void ) { uint size; if (++pSymClass->CurIndex >= pSymClass->MaxIndex) { size = sizeof (psymclass_t) + (pSymClass->CurIndex + 5) * sizeof (symbase_t); MHMemUnLock (hSymClass); if ((hSymClass = MHMemReAlloc (hSymClass, size)) == 0) { pExState->err_num = ERR_NOMEMORY; pSymClass = MHMemLock (hSymClass); pSymClass->CurIndex--; return (SCN_error); } pSymClass = MHMemLock (hSymClass); pSymClass->MaxIndex += 5; } return (SCN_found); } /** IsDominated - check to see of feature is dominated * * fStatus = IsDominated (pSymBest, pSymTest) * * Entry pName = structure describing search * pSymClass = structure describing most recent class search * * Exit pName updated to reflect search * pSymClass updated to unambiguous feature * * Returns DOM_replace if pSymBest is dominated by pSymTest * DOM_keep if pSymBest is exactly equivalent to pSymTest * DOM_ambiguous if pSymBest is equal to pSymTest * DOM_keep if pSymTest is duplicate virtual base */ LOCAL DOM_t IsDominated ( psymclass_t pSymBest, psymclass_t pSymTest ) { short i; short j; if (pSymBest->s.isdupvbase == TRUE) { return (DOM_replace); } if (pSymTest->s.isdupvbase == TRUE) { return (DOM_keep); } // check all of the base classes for a dominated virtual base for (i = 0; i <= pSymBest->CurIndex; i++) { if (pSymBest->symbase[i].virtual == TRUE) { for (j = pVBDom->CurIndex; j >= 0; j--) { if (pVBDom->dom[j] == EVAL_TYP (&pSymBest->symbase[i].Base)) { return (DOM_replace); } } } } for (i = 0; i <= pSymTest->CurIndex; i++) { if (pSymTest->symbase[i].virtual == TRUE) { for (j = pVBDom->CurIndex; j >= 0; j--) { if (pVBDom->dom[j] == EVAL_TYP (&pSymTest->symbase[i].Base)) { return (DOM_keep); } } } } // we have two paths to potentially two different features. We now check // to see if the features are identical. This is done by checking for // static data members that have identical addresses and types if (!EVAL_IS_STMEMBER (&pSymBest->evalP) || !EVAL_IS_STMEMBER (&pSymTest->evalP) || (EVAL_TYP (&pSymBest->evalP) != EVAL_TYP (&pSymTest->evalP)) || (EVAL_SYM_SEG (&pSymBest->evalP) != EVAL_SYM_SEG (&pSymTest->evalP)) || (EVAL_SYM_OFF (&pSymBest->evalP) != EVAL_SYM_OFF (&pSymTest->evalP))) { return (DOM_ambiguous); } return (DOM_keep); } /** IsIntroVirt - is this the introducing virtual method * * fSuccess = IsIntroVirt (count, mlist, pvtabindex) * * Entry count = number of methods in list * mlist = type index of method list * pvtabind = pointer to virtual function table index * * Exit *pvtabind = virtual fuction table index * * Returns TRUE if the introducing virtual method is found * FALSE otherwise */ LOCAL bool_t IsIntroVirt ( ushort count, CV_typ_t mlist, ushort *vtabind) { HTYPE hMethod; pmlMethod pMethod; plfMFunc pMFunc; uint skip; CV_fldattr_t attr; CV_typ_t type; bool_t Mmatch = 0; peval_t pvF; HMOD hMod; bool_t retval; pvF = &pSymClass->evalP; hMod = EVAL_MOD (pvF); // we now walk the list of methods looking for a method with the same // return type and argument list type if ((hMethod = THGetTypeFromIndex (hMod, mlist)) == (HTYPE) NULL) { DASSERT (FALSE); return (FALSE); } // set the number of methods overloaded on this name and the index into // the method list skip = 0; while (count-- > 0) { // lock the omf record, extract information for the current entry in // the method list and increment to field for next method pMethod = (pmlMethod)((&((TYPPTR)MHOmfLock (hMethod))->leaf) + 1 + skip); attr = pMethod->attr; type = pMethod->index; skip += sizeof (mlMethod); if (pMethod->attr.mprop == CV_MTintro) { *vtabind = (short)RNumLeaf (((char *)pMethod) + skip, &skip); } else { *vtabind = 0; } MHOmfUnLock (hMethod); if (attr.mprop == CV_MTintro) { if ((hMethod = THGetTypeFromIndex (hMod, type)) == (HTYPE) NULL) { DASSERT (FALSE); return (FALSE); } pMFunc = (plfMFunc)((&((TYPPTR)MHOmfLock (hMethod))->leaf)); retval = (pMFunc->rvtype == FCN_RETURN (pvF)) && (pMFunc->arglist == FCN_PINDEX (pvF)); MHOmfUnLock (hMethod); if (retval == TRUE) { return (TRUE); } } } return (FALSE); } LOCAL CV_typ_t SkipModifiers( HMOD mod, CV_typ_t type ) { HTYPE hType; plfModifier pType; if (!CV_IS_PRIMITIVE (type)) { hType = THGetTypeFromIndex (mod, type); pType = (plfModifier)((&((TYPPTR)MHOmfLock (hType))->leaf)); while (pType->leaf == LF_MODIFIER) { type = pType->type; if (CV_IS_PRIMITIVE (type)) { break; } MHOmfUnLock (hType); hType = THGetTypeFromIndex (mod, type); pType = (plfModifier)((&((TYPPTR)MHOmfLock (hType))->leaf)); } } MHOmfUnLock (hType); return type; } /** MatchArgs - match a method against argument list * * flag = MatchArgs (pv, pName, fattr, vtabind, fForce) * * Entry pv = pointer to function descriptor * pName = pointer to search structure * attr = attribute if method * vtabind = offset into vtable if virtual method * fForce = TRUE if match on first (only) method is forced * This is the case if bp method, no args and single * method. * BindingBP = TRUE if call is via ParseBP API entry * if BindingBP is true, then only exact matches are allowed * bArgList = based pointer to argument list * * Exit ST = resolved address of method * * Returns TRUE if a match was found or ambiguous references are allowed * FALSE if no match or ambiguity not allowed */ LOCAL void MatchArgs ( peval_t pvM, psearch_t pName, CV_fldattr_t attr, UOFFSET vtabind, bool_t fForce ) { pnode_t pnT; pargd_t pa; bool_t update; argcounters current; short argc; CV_typ_t Ftype; bool_t argmatch; eval_t evalArg; peval_t pvArg = &evalArg; HTYPE hType; plfModifier pType; // walk down the formal list specified by pvM and the actual list // specified by bArgList. Initialize the conversion counters to // zero and set the index to varargs parameter to zero argc = 0; current.exact = 0; current.implicit = 0; current.varargs = 0; argmatch = FALSE; update = FALSE; pnT = pnodeOfbnode(bArgList); (pName->overloadCount)++; if (fForce == TRUE) { argmatch = TRUE; update = TRUE; } else if (!N_EVAL_IS_FCN(pvM)) { argmatch = TRUE; current.exact = 0; } else while (TRUE) { if (NODE_OP (pnT) == OP_endofargs) { if ((argc == FCN_PCOUNT (pvM)) || ((argc >= (FCN_PCOUNT (pvM) - 1)) && (FCN_VARARGS (pvM) == TRUE))) { argmatch = TRUE; } break; } if ((argc > FCN_PCOUNT (pvM)) && (FCN_VARARGS (pvM) == FALSE)) { // this function cannot possibly be a match because the // number of actuals is greater than the number of formals // and the method does not allow varargs. break; } switch (GetArgType (pvM, argc, &Ftype)) { case FARG_error: DASSERT (FALSE); return; case FARG_none: // special case foo(void) // sps 2/20/92 if ((argc == 0) && (pa->actual == T_VOID)) { argmatch = TRUE; goto argmatchloop; } return; case FARG_vararg: // varargs are allowed unless we are binding breakpoints if (BindingBP == TRUE) { return; } break; case FARG_exact: if ((argc + 1) > FCN_PCOUNT (pvM)) { // we must exactly match the argument count and we // have more arguments return; } break; } argc++; // pa points to the argument descriptor array in the OP_arg node pa = (pargd_t)&(pnT->v[0]); if (Ftype == 0) { // all arguments from this point on are vararg current.varargs = argc; pa->current = OM_vararg; } #if 1 else { CV_typ_t Atype = pa->actual; eval_t vA, vF; peval_t pvA = &vA; peval_t pvF = &vF; if (pa->flags.istype) { // If we have a type want identical type indices // (This helps with class dumps) if (Atype == Ftype) { current.exact++; pa->current = OM_exact; pnT = pnodeOfbnode(NODE_RCHILD (pnT)); continue; } else { pExState->err_num = ERR_NONE; break; } } Ftype = SkipModifiers(EVAL_MOD(pvM), Ftype); Atype = SkipModifiers(EVAL_MOD(pvM), Atype); *pvF = *pvM; if (!SetNodeType(pvF, Ftype)) { // error (not valid type) break; } // Update Ftype (SetNodeType must have resolved potential fwd refs) Ftype = EVAL_TYP (pvF); // if we are calling a 32 bit func we must promote all const // int2's to int4's if (EVAL_SYM_IS32(pvM) && (EVAL_STATE((peval_t)(&(pnodeOfbnode(NODE_LCHILD (pnT)))->v[0])) == EV_constant) && ((Atype == T_INT2) || (Atype == T_UINT2)) ) { Atype++; } *pvA = *pvM; if (!SetNodeType(pvA, Atype)) { // error (not valid type) break; } if (EVAL_IS_PTR(pvA) && EVAL_IS_REF(pvA)) { Atype = SkipModifiers(EVAL_MOD(pvM), PTR_UTYPE(pvA)); } if (Atype == Ftype) { current.exact++; pa->current = OM_exact; pnT = pnodeOfbnode(NODE_RCHILD (pnT)); continue; } if (EVAL_IS_PTR(pvF)) { *pvA = *pvM; if (!SetNodeType(pvA, Atype)) { // error (not valid type) break; } if (!EVAL_IS_REF(pvF)) { if (!EVAL_IS_PTR(pvA)) { // do not cast a non-pointer to pointer break; } PTR_UTYPE(pvA) = SkipModifiers(EVAL_MOD(pvM), PTR_UTYPE(pvA)); PTR_UTYPE(pvF) = SkipModifiers(EVAL_MOD(pvM), PTR_UTYPE(pvF)); if (EVAL_PTRTYPE(pvA) == EVAL_PTRTYPE(pvF) && PTR_UTYPE(pvA) == PTR_UTYPE(pvF) && !EVAL_IS_BASED(pvA) && !EVAL_IS_BASED(pvF)) { // we don't match based pointers. if we want to // do this we must examine additional information // we allow mathcing a pointer with an array // however all arrays are considered far // since codeview information does not distinguish // between far or near arrays. --gdp 10/16/92 current.exact++; pa->current = OM_exact; pnT = pnodeOfbnode(NODE_RCHILD (pnT)); continue; } } else { // // special handling of a reference // CV_typ_t Utype; Utype = SkipModifiers(EVAL_MOD(pvM), PTR_UTYPE (pvF)); if (Utype == Atype) { current.exact++; pa->current = OM_exact; pnT = pnodeOfbnode(NODE_RCHILD (pnT)); continue; } else { break; } } } // see if we can cast the type of the actual to the type of // the formal if we are not binding breakpoints. If we are // binding breakpoints, only exact matches are allowed *pvArg = *pvM; SetNodeType (pvArg, pa->actual); if (EVAL_IS_BITF (pvArg)) { SetNodeType (pvArg, BITF_UTYPE (pvArg)); } if (CastNode (pvArg, Ftype, Ftype)) { pa->current = OM_implicit; current.implicit++; } else { pExState->err_num = ERR_NONE; break; } } pnT = pnodeOfbnode(NODE_RCHILD (pnT)); } argmatchloop: #endif #if 0 else if (pa->actual == Ftype) { current.exact++; pa->current = OM_exact; } else { /* * we need to check to see if we have a modifier to the * actual type * * Modifies we look for are: * * const foo * volatile foo * * pointer to foo by reference (C++ call by reference) */ if (!CV_IS_PRIMITIVE (Ftype)) { hType = THGetTypeFromIndex (EVAL_MOD (pvM), Ftype); DASSERT(hType != (HTYPE) NULL); pType = (plfModifier)((&((TYPPTR)MHOmfLock ((HDEP)hType))->leaf)); if (pType->leaf == LF_MODIFIER) { if (((pType->attr.MOD_const == TRUE) == (int) pa->flags.isconst) || ((pType->attr.MOD_volatile == TRUE) == (int) pa->flags.isvolatile) && (pType->type == Ftype)) { current.exact++; pa->current = OM_exact; MHOmfUnLock((HDEP)hType); pnT = pnodeOfbnode(NODE_RCHILD (pnT)); continue; } } else { if (pType->leaf == LF_POINTER) { lfPointer * pType2 = (lfPointer *) pType; if ((pType2->attr.ptrmode == CV_PTR_MODE_REF) && (pType2->utype == pa->actual)) { current.exact++; pa->current = OM_exact; MHOmfUnLock((HDEP)hType); pnT = pnodeOfbnode(NODE_RCHILD (pnT)); continue; } } } MHOmfUnLock( (HDEP)hType ); } if (pa->flags.istype == TRUE) { // the formal argument is a type and exact match is required break; } else { // see if we can cast the type of the actual to the type of // the formal if we are not binding breakpoints. If we are // binding breakpoints, only exact matches are allowed *pvArg = *pvM; SetNodeType (pvArg, pa->actual); if (EVAL_IS_BITF (pvArg)) { SetNodeType (pvArg, BITF_UTYPE (pvArg)); } if (CastNode (pvArg, Ftype, Ftype)) { pa->current = OM_implicit; current.implicit++; } else { pExState->err_num = ERR_NONE; break; } } } pnT = pnodeOfbnode(NODE_RCHILD (pnT)); } #endif if (argmatch == TRUE) { // check current against best match if (pName->best.match == 0) { // we have a first time match update = TRUE; pName->possibles++; } else if (fForce == FALSE) { // we have already matched on some function so we now // check to see if the current is better than the best if (current.varargs == 0) { // there are no varargs in this method therefor it is // better than any previous match with varargs if (pName->best.varargs != 0) { update = TRUE; pName->best = current; pName->possibles = 1; } else if (current.exact > pName->best.exact) { // this function has more exact matches than the // best one so far update = TRUE; pName->possibles = 1; } else if (EVAL_TYP (pvM) != pName->best.match && current.exact == pName->best.exact) { // this function is a good as the best one. // this means the call is ambiguous pName->possibles++; } } else { if (pName->best.varargs != 0) { // both the current and the best functions have // varargs if (current.varargs < pName->best.varargs) { // this function uses fewer varargs which // makes it a better one update = TRUE; pName->possibles = 1; } else if (current.varargs == pName->best.varargs) { // this function uses the same number of varargs // pick the one with more exact matches if (current.exact > pName->best.exact) { update = TRUE; pName->possibles = 1; } else if (EVAL_TYP (pvM) != pName->best.match && current.exact == pName->best.exact) { pName->possibles++; } } } } } if (update == TRUE) { if (fForce == FALSE) { // the current match is better for (pnT = pnodeOfbnode(bArgList); NODE_OP (pnT) != OP_endofargs; pnT = pnodeOfbnode(NODE_RCHILD (pnT))) { pa = (pargd_t)&(pnT->v[0]); pa->best = pa->current; } { //M00KLUDGE - hack for compiler DS != SS bug argcounters *pcurrent = ¤t; pName->best = *pcurrent; } } pName->best.match = EVAL_TYP (pvM); pName->best.attr = attr; pName->best.vtabind = vtabind; pName->best.hSym = pName->hSym; } } } /** MatchFunction - match a function against argument list * * flag = MatchFunction (pName) * * Entry pName = pointer to search status * BindingBP = TRUE if call is via ParseBP API entry * bArgList = based pointer to argument list * * Exit pv = resolved address of method * * Returns HR_... describing match result */ LOCAL HR_t __fastcall MatchFunction ( psearch_t pName ) { HR_t retval; CV_fldattr_t attr = {0}; CV_typ_t type; ADDR addr; bool_t dupfcn; if (bArgList == 0) { // if there is no argument list, assume we are assigning to a // function pointer and take the first function found. Let the // user beware. return (HR_found); } // NOTENOTE -- jimsch -- don't search publics if something was found // it is making all sorts of problems for me on MIPS pName->scope &= ~SCP_global; // save the function address and type. Then if a subsequent match has // the same address and type (i.e., comdat code), we can ignore it. addr = EVAL_SYM (ST); type = EVAL_TYP (ST); // pop the entry that SearchSym has added to the evaluation stack // the best match will be pushed back on later pName->scope |= SCP_nomatchfn; PopStack (); MatchArgs (pName->pv, pName, attr, 0, FALSE); while ((retval = SearchSym (pName)) != HR_notfound) { DASSERT (retval != HR_end); dupfcn = FALSE; if (retval == HR_found) { if ((EVAL_TYP (ST) == type) && (_fmemcmp (&addr, &EVAL_SYM (ST), sizeof (addr)) == 0)) { dupfcn = TRUE; } PopStack (); if (dupfcn == FALSE) { MatchArgs (pName->pv, pName, attr, 0, FALSE); } } else { return (retval); } } pName->scope &= ~SCP_nomatchfn; // clear the symbol not found error from the recursive symbol search pExState->err_num = ERR_NONE; if (pName->best.match == 0) { pExState->err_num = ERR_ARGLIST; return (HR_error); } else if (pName->possibles > 1) { PushStack (pName->pv); pExState->err_num = ERR_AMBIGUOUS; EVAL_IS_AMBIGUOUS (ST) = TRUE; return (HR_ambiguous); } else if (pName->overloadCount > 1 && pName->best.implicit > 0) { // // overloaded function that involves implicit casts // pExState->err_num = ERR_AMBIGUOUS; return (HR_ambiguous); } else { pName->hSym = pName->best.hSym; if ((SymToNode (pName) == FALSE) || (PushStack (pName->pv) == FALSE)) { return (HR_notfound); } else { return (HR_found); } } } /** MatchMethod - match a method against argument list * * flag = MatchMethod (pName, pSymCl) * * Entry pName = pointer to search descriptor * pSymCl = pointer tp symbol class structure * select = selection masj * BindingBP = TRUE if call is via ParseBP API entry * if BindingBP is true, then only exact matches allowed * bArgList = based pointer to argument list * * Exit pName->pv = resolved address of method * * Returns MTH_found if a match was found or ambiguous references are allowed * MTH_error if error or ambiguity not allowed * */ LOCAL MTH_t MatchMethod ( psearch_t pName, psymclass_t pSymCl ) { HTYPE hMethod; pmlMethod pMethod; uint skip; eval_t evalM; peval_t pvM = &evalM; CV_fldattr_t attr; CV_typ_t type; ushort vtabind; bool_t Mmatch = 0; HDEP hQual; peval_t pvF; ushort count = pSymCl->possibles; peval_t pvB; HMOD hMod; bool_t fForce = FALSE; pvB = &pSymClass->symbase[pSymClass->CurIndex].Base; hMod = EVAL_MOD (pvB); pName->possibles = 0; // we now walk the list of methods looking for an argument match // For now, we require an exact match except that we assume any // primitive type can be cast to any other primitive type. A cast from // pointer to derived to pointer to base is an implicit conversion if ((hMethod = THGetTypeFromIndex (hMod, pSymCl->mlist)) == (HTYPE)NULL) { DASSERT (FALSE); return (MTH_error); } // set the number of methods overloaded on this name and the index into // the method list skip = 0; // if ((BindingBP == TRUE) && (bArgList == 0)) if (bArgList == 0) { if (count == 1) { fForce = TRUE; } else { // there is not an argument list. We allow breakpoints if a single // method by that name exists. Otherwise, we require an argument // list pExState->err_num = ERR_NOARGLIST; return (MTH_error); } } while (count-- > 0) { // lock the omf record, extract information for the current entry in // the method list and increment to field for next method pMethod = (pmlMethod)((&((TYPPTR)MHOmfLock (hMethod))->leaf) + 1); pMethod = (pmlMethod)((uchar *)pMethod + skip); attr = pMethod->attr; type = pMethod->index; skip += sizeof (mlMethod); if (pMethod->attr.mprop == CV_MTintro) { vtabind = (short)RNumLeaf (((char *)pMethod) + skip, &skip); } else { vtabind = 0; } MHOmfUnLock (hMethod); // now compare the actual and formal argument lists for the function // pvM will be initialized to be a function node whose type index is // type. CLEAR_EVAL (pvM); EVAL_MOD (pvM) = hMod; if (SetNodeType (pvM, type) == FALSE) { // the type record for the method was not found DASSERT (FALSE); return (MTH_error); } MatchArgs (pvM, pName, attr, vtabind, fForce); } // since the name was found at this level, it hides all other methods // by the same name above it in the inheritance tree. Therefore we must // either have a match or an error because there is no match or two or // methods match after conversions are considered if (pName->best.match == 0) { pExState->err_num = ERR_ARGLIST; return (MTH_error); } else if (pName->possibles > 1) { pExState->err_num = ERR_AMBIGUOUS; EVAL_IS_AMBIGUOUS (pName->pv) = TRUE; return (MTH_error); } else if (pName->overloadCount > 1 && pName->best.implicit > 0) { // we have an overloaded method // in this case the EE requires exact matches only pExState->err_num = ERR_AMBIGUOUS; EVAL_IS_AMBIGUOUS (pName->pv) = TRUE; return (MTH_error); } else { // we have found a non-ambiguous match pvF = &pSymCl->evalP; EVAL_MOD (pvF) = hMod; if (SetNodeType (pvF, pName->best.match) == FALSE) { return (MTH_error); } else { pSymCl->access.access = pName->best.attr.access; FCN_ATTR (pvF) = pName->best.attr; FCN_VTABIND (pvF) = pName->best.vtabind; FCN_VFPTYPE (pvF) = pSymCl->vfpType; if (NODE_OP (pnodeOfbnode(pName->bnOp)) == OP_bscope) { // binary scoping switches off virtual function evaluation FCN_PROPERTY (pvF) = CV_MTvanilla; } if ((FCN_PROPERTY (pvF) == CV_MTvirtual) || (FCN_PROPERTY (pvF) == CV_MTintro)) { // do nothing. address will have to be found at evaluation } else { if (((hQual = GenQualName (pName, pSymClass)) == 0) || (SearchQualName (pName, pSymCl, hQual, TRUE) == FALSE)) { if (hQual != 0) { MHMemFree (hQual); } return (MTH_error); } MHMemFree (hQual); } return (MTH_found); } } } /** MoveSymCl - move symbol class structure * * MoveSymCl (hSymCl); * * Entry hSymCl = handle of symbol class structure * * Exit *pSymClass = symbol class structure * * Returns none */ LOCAL void MoveSymCl ( HDEP hSymCl ) { psymclass_t pSymCl; ushort max; pSymCl = MHMemLock (hSymCl); DASSERT (pSymClass->MaxIndex >= pSymCl->CurIndex); max = pSymClass->MaxIndex; _fmemmove (pSymClass, pSymCl, sizeof (symclass_t) + (pSymCl->CurIndex + 1) * sizeof (symbase_t)); pSymClass->MaxIndex = max; MHMemUnLock (hSymCl); MHMemFree (hSymCl); } /** PurgeAmbCl - purge ambiguous class structure list * * PurgeAmbCl (pName) * * Entry pName = pointer to symbol search structure * * Exit pname->hAmb list freed * * Returns none */ LOCAL void PurgeAmbCl ( psearch_t pName ) { psymclass_t pAmbCl; HDEP hNext; while (pName->hAmbCl != 0) { pAmbCl = MHMemLock (pName->hAmbCl); hNext = pAmbCl->hNext; MHMemUnLock (pName->hAmbCl); pName->hAmbCl = hNext; } } /*** SetBase - set base value in pSymClass->symbase array * * status = SetBase (pName, type, vbptr, vbpoff, thisadjust, attr, virtual) * * Entry pName = pointer to struct describing search * type = type index of class * vbptr = type index of virtual base pointer * vbpoff = offset of virtual base pointer from address point * thisadjust = offset of base from previous class * thisadjust = virtual base index if virtual base * attr = field attribute mask * virtual = TRUE if virtual base * * Exit new base class added to pSymClass * * Returns enum describing search state */ LOCAL SCN_t SetBase ( psearch_t pName, CV_typ_t type, CV_typ_t vbptr, OFFSET vbpoff, OFFSET thisadjust, CV_fldattr_t attr, bool_t virtual ) { peval_t pvB; // save offset of base from address point for this pointer adjustment pSymClass->symbase[pSymClass->CurIndex].thisadjust = thisadjust; pSymClass->symbase[pSymClass->CurIndex].vbptr = vbptr; pSymClass->symbase[pSymClass->CurIndex].vbpoff = vbpoff; pSymClass->symbase[pSymClass->CurIndex].attrBC = attr; pSymClass->symbase[pSymClass->CurIndex].virtual = virtual; pSymClass->symbase[pSymClass->CurIndex].clsmask = pName->clsmask; pvB = &pSymClass->symbase[pSymClass->CurIndex].Base; EVAL_MOD (pvB) = pName->hMod; if (SetNodeType (pvB, type) == FALSE) { pExState->err_num = ERR_BADOMF; return (SCN_error); } return (SCN_found); } /*** SearchQualName - Search for a qualified method name * * flag = SearchQualName (pName, pSymCl, hQual, fProc) * * Entry pName = pointer to struct describing search * pSymCl = pointer to structure describing path to symbol * hQual = handle to symbol name * fProc = TRUE if proc symbol to be searched for * fProc = FALSE if data to be searched for * * Exit pName updated to reflect search * * Return enum describing search */ LOCAL bool_t SearchQualName ( psearch_t pName, psymclass_t pSymCl, HDEP hQual, bool_t fProc ) { HDEP hTemp; psearch_t pTemp; uchar *pQual; ushort retval; if ((hTemp = MHMemAllocate (sizeof (search_t))) == 0) { pExState->err_num = ERR_NOMEMORY; return (FALSE); } pTemp = MHMemLock (hTemp); *pTemp = *pName; pTemp->CXTT = *pCxt; // set pointer to symbol name pQual = (uchar *)MHMemLock (hQual); pTemp->sstr.lpName = pQual; pTemp->sstr.cb = (uchar)_fstrlen ((char *)pQual); pTemp->state = SYM_init; if (fProc == TRUE) { pTemp->scope = SCP_module | SCP_global; pTemp->sstr.searchmask |= SSTR_proc; } else { pTemp->scope = SCP_module | SCP_global | SCP_lexical; // data members may not be overloaded, hence there is // no need for the type to qualify the name. Furthermore // there are cases where the symbol type doesn't match // the member type exactly (e.g. variable length arrays, // symbol has actual length and member has zero length) // hence this matching is suppressed for data items [rm] // pTemp->sstr.searchmask |= SSTR_data; } pTemp->initializer = INIT_qual; pTemp->typeOut = EVAL_TYP (&pSymCl->evalP); retval = SearchSym (pTemp); MHMemUnLock (hQual); if (retval != HR_found) { #ifdef NEVER /* CAVIAR #1081 */ if ((retval != HR_end) && (pTemp->FcnBP != 0)) { // if (pTemp->FcnBP != 0) { // there is another symbol with the same name but a different // type. Since this is set only when we are binding breakpoints, // let's go ahead and try it pTemp->state = SYM_init; pTemp->scope = SCP_module | SCP_global; pTemp->sstr.searchmask |= SSTR_proc; pTemp->typeOut = pTemp->FcnBP; retval = SearchSym (pTemp); } #endif if (retval != HR_found) { // the only way we can get here is if the method or data // is declared in the class but is not defined or // is a noninstianted inline method. // therefore, we return a special error code if (ST == NULL) { // this is a hack to get around the case where the expression // bp {,foo.c, foo.exe}X::f // and the first function in the module foo is a method. // SearchSym ended up calling the class search routines // because the context is implicitly a class so class is // searched even though it shouldn't be. Any fix for this // causes problems and we are too close to release to find // a valid fix. The major result of this fix is that // some breakpoints will not get reset on entry. return (FALSE); } PushStack (ST); // if this is a missing static DATA member function then // best.match won't have anything in it at all... we'll need // to pick up what we want from typeOut which will have been // set by a previous non-qualified name search... [rm] if (pName->best.match == T_NOTYPE) { SetNodeType (ST, pName->typeOut); } else { SetNodeType (ST, pName->best.match); } if (EVAL_IS_FCN(ST)) { FCN_NOTPRESENT (ST) = TRUE; } else { // indicate missing static data member EVAL_HSYM (ST) = 0; pExState->state.fNotPresent = TRUE; } // if (fProc) { // SetNodeType (ST, pName->best.match); // FCN_NOTPRESENT (ST) = TRUE; // } } } // 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 (&pSymCl->evalP); EVAL_ACCESS (ST) = (uchar)(pSymCl->access.access); pSymCl->evalP = *ST; MHMemUnLock (hTemp); MHMemFree (hTemp); return (PopStack ()); } /** SymAmbToList - add ambiguous symbol to list * * status = SymAmbToList (pName) * * Entry pName = pointer to list describing search * * Exit ambiguous symbol added to list pointed to by pTMList * pTMLbp * pName reset to continue breakpoint search * * Returns HR_... describing state */ LOCAL HR_t SymAmbToList ( psearch_t pName ) { HDEP hSearch; psearch_t pSearch; HR_t retval; HDEP hevalT; PopStack (); if (pExState->ambiguous == 0) { // this is the first breakpoint symbol found. // indicate the only node in the tree that is // allowed ambiguity and initialize list of // symbols for later back patching into duplicated // expression trees. We save the initial search packet // so that the first symbol will be set into the breakpoint // list. pNameFirst = pName; pExState->ambiguous = pName->bn; if ((hSearch = MHMemAllocate (sizeof (search_t))) == 0) { pExState->err_num = ERR_NOMEMORY; return (HR_error); } if ((hevalT = MHMemAllocate (sizeof (eval_t))) == 0) { MHMemFree (hSearch); pExState->err_num = ERR_NOMEMORY; return (HR_error); } pSearch = MHMemLock (hSearch); *pSearch = *pName; pSearch->pv = (peval_t)MHMemLock (hevalT); SHGoToParent (&pName->CXTT, &pSearch->CXTT); // clear the newly allocated pv _fmemset ( pSearch->pv, 0, sizeof (eval_t) ); retval = SearchSym (pSearch); PushStack (pName->pv); MHMemUnLock (hSearch); MHMemFree (hSearch); MHMemUnLock (hevalT); MHMemFree (hevalT); if (retval == HR_end) { retval = HR_found; } return (retval); } else if (pExState->ambiguous != pName->bn) { // there has already been a ambiguous symbol that is // not at this node in the tree pExState->err_num = ERR_BPAMBIGUOUS; return (HR_error); } else { if (CheckDupAmb (pName) == FALSE) { // the function is not already in the ambiguity list if (AmbToList (pName) == FALSE) { return (HR_error); } } // reset search to allow more symbols pName->possibles = 0; return (SearchSym (pName)); } } /** CheckDupAmb - check for duplicate ambiguity entry * * fSuccess = CheckDupAmb (pName) * * Entry pName = pointer to list describing search * * Exit none * * Returns TRUE if duplicate symbol found * FALSE if duplicate symbol not found */ LOCAL bool_t CheckDupAmb ( psearch_t pName ) { psearch_t pN; ushort i; bool_t fdup = FALSE; if ((EVAL_TYP (pNameFirst->pv) == EVAL_TYP (pName->pv)) && (_fmemcmp ((void *)&EVAL_SYM (pNameFirst->pv), (void *)&EVAL_SYM (pName->pv), sizeof (ADDR)) == 0)) { return (TRUE); } for (i = 1; i < iBPatch; i++) { pN = (psearch_t) MHMemLock (pTMList[i]); if (pN->typeOut == EVAL_TYP (pName->pv) && (_fmemcmp ((void *)&pN->addr, (void *)&EVAL_SYM (pName->pv), sizeof (ADDR)) == 0)) { fdup = TRUE; } MHMemUnLock (pTMList[i]); if (fdup == TRUE) { break; } } return (fdup); } /** SymToNode - store symbol information in evaluation node * * fSuccess = SymToNode (hName) * * Entry pName = pointer to search state * * Exit type information and address data stored in value * if the symbol is a typedef record, then the evaluation * state will be set to EV_type. Otherwise, it will be set * to EV_lvalue. * * Returns TRUE if variable was accessible * FALSE if error */ LOCAL bool_t SymToNode ( psearch_t pName ) { CV_typ_t typ; ushort evalstate; HSYM hSym; peval_t pv = pName->pv; PCXT pCXT = &pName->CXTT; SYMPTR pSym; ushort cmpThis = 1; MEMINFO mi; if ((hSym = pName->hSym) == NULL) { // this symbol is found as a class member which means it does // not have a symbol. DASSERT (pName->typeOut != T_NOTYPE); return (SetNodeType (pv, pName->typeOut)); } EVAL_STATE (pv) = EV_lvalue; EVAL_MOD (pv) = SHHMODFrompCXT (pCXT); CLEAR_EVAL_FLAGS (pv); EVAL_SYM_EMI (pv) = pCXT->addr.emi; switch((pSym = MHOmfLock ((HDEP)hSym))->rectyp) { case S_REGISTER: EVAL_IS_REG (pv) = TRUE; EVAL_REG (pv) = ((REGPTR)pSym)->reg; typ = ((REGPTR)pSym)->typind; cmpThis = strncmp ( (char *) &((REGPTR)pSym)->name[0], (char *) &OpName[0], ((REGPTR)pSym)->name[0] + 1); break; case S_CONSTANT: if (!DebLoadConst (pv, (CONSTPTR)pSym, hSym)) { MHOmfUnLock ((HDEP)hSym); return (FALSE); } EVAL_STATE (pv) = EV_constant; typ = EVAL_TYP (pv); break; case S_UDT: typ = ((UDTPTR)pSym)->typind; EVAL_STATE (pv) = EV_type; break; case S_BLOCK16: EVAL_SYM_SEG (pv) = ((BLOCKPTR16)pSym)->seg; EVAL_SYM_OFF (pv) = ((BLOCKPTR16)pSym)->off; typ = T_NOTYPE; ADDR_IS_LI (EVAL_SYM (pv)) = TRUE; NOTTESTED (FALSE); // not tested break; case S_LPROC16: case S_GPROC16: ADDR_IS_LI (EVAL_SYM (pv)) = TRUE; if ((typ = ((PROCPTR16)pSym)->typind) == T_NOTYPE) { // this is a hack to allow breakpoints on untyped symbols typ = T_PFUCHAR; EVAL_SYM_OFF (pv) = ((PROCPTR16)pSym)->off; EVAL_SYM_SEG (pv) = ((PROCPTR16)pSym)->seg; EVAL_PTR (pv) = EVAL_SYM (pv); EVAL_STATE (pv) = EV_rvalue; } else { EVAL_SYM (pv) = *SHpADDRFrompCXT (pCXT); EVAL_SYM_SEG (pv) = ((PROCPTR16)pSym)->seg; EVAL_SYM_OFF (pv) = ((PROCPTR16)pSym)->off; ADDR_IS_LI (EVAL_SYM (pv)) = TRUE; } break; case S_LABEL16: EVAL_IS_LABEL (pv) = TRUE; EVAL_SYM_OFF (pv) = ((LABELPTR16)pSym)->off; EVAL_SYM_SEG (pv) = ((LABELPTR16)pSym)->seg; ADDR_IS_LI (EVAL_SYM (pv)) = TRUE; EVAL_PTR (pv) = EVAL_SYM (pv); EVAL_STATE (pv) = EV_rvalue; typ = T_PFUCHAR; break; case S_BPREL16: EVAL_IS_BPREL (pv) = TRUE; EVAL_SYM_OFF (pv) = ((BPRELPTR16)pSym)->off; EVAL_SYM_SEG (pv) = 0; ADDR_IS_LI (EVAL_SYM (pv)) = FALSE; typ = ((BPRELPTR16)pSym)->typind; pExState->state.bprel = TRUE; cmpThis = strncmp ( (char *) &((BPRELPTR16)pSym)->name[0], (char *) &OpName[0], ((BPRELPTR16)pSym)->name[0] + 1); break; case S_LDATA16: pExState->state.fLData = TRUE; EVAL_SYM_OFF (pv) = ((DATAPTR16)pSym)->off; EVAL_SYM_SEG (pv) = ((DATAPTR16)pSym)->seg; typ = ((DATAPTR16)pSym)->typind; ADDR_IS_LI (EVAL_SYM (pv)) = TRUE; break; case S_GDATA16: pExState->state.fGData = TRUE; EVAL_SYM_OFF (pv) = ((DATAPTR16)pSym)->off; EVAL_SYM_SEG (pv) = ((DATAPTR16)pSym)->seg; typ = ((DATAPTR16)pSym)->typind; ADDR_IS_LI (EVAL_SYM (pv)) = TRUE; break; case S_PUB16: EVAL_SYM_OFF (pv) = ((DATAPTR16)pSym)->off; EVAL_SYM_SEG (pv) = ((DATAPTR16)pSym)->seg; EVAL_STATE (pv) = EV_lvalue; ADDR_IS_LI (EVAL_SYM (pv)) = TRUE; if ((typ = ((DATAPTR16)pSym)->typind) == T_NOTYPE) { // this is a hack to allow breakpoints on untyped symbols MEMINFO mi; mi.addr = EVAL_SYM(pv); SYGetMemInfo(&mi); if ((mi.dwState & MEM_COMMIT) && (mi.dwProtect & (PAGE_EXECUTE | PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY)) ) { typ = T_PFUCHAR; EVAL_STATE (pv) = EV_rvalue; } else { typ = T_UINT2; EVAL_STATE (pv) = EV_lvalue; } } EVAL_PTR (pv) = EVAL_SYM (pv); break; case S_BLOCK32: EVAL_SYM_SEG (pv) = ((BLOCKPTR32)pSym)->seg; EVAL_SYM_OFF (pv) = ((BLOCKPTR32)pSym)->off; typ = T_NOTYPE; ADDR_IS_LI (EVAL_SYM (pv)) = TRUE; ADDR_IS_FLAT (EVAL_SYM (pv)) = TRUE; ADDR_IS_OFF32( EVAL_SYM ( pv ) ) = TRUE; break; case S_LPROC32: case S_GPROC32: ADDR_IS_LI (EVAL_SYM (pv)) = TRUE; ADDR_IS_FLAT (EVAL_SYM (pv)) = TRUE; ADDR_IS_OFF32( EVAL_SYM ( pv ) ) = TRUE; if ((typ = ((PROCPTR32)pSym)->typind) == T_NOTYPE) { // this is a hack to allow breakpoints on untyped symbols typ = T_32PUCHAR; EVAL_SYM_OFF (pv) = ((PROCPTR32)pSym)->off; EVAL_SYM_SEG (pv) = ((PROCPTR32)pSym)->seg; EVAL_PTR (pv) = EVAL_SYM (pv); EVAL_STATE (pv) = EV_rvalue; } else { EVAL_SYM (pv) = *SHpADDRFrompCXT (pCXT); EVAL_SYM_SEG (pv) = ((PROCPTR32)pSym)->seg; EVAL_SYM_OFF (pv) = ((PROCPTR32)pSym)->off; } break; case S_LPROCMIPS: case S_GPROCMIPS: ADDR_IS_LI (EVAL_SYM (pv)) = TRUE; ADDR_IS_FLAT (EVAL_SYM (pv)) = TRUE; ADDR_IS_OFF32( EVAL_SYM ( pv ) ) = TRUE; if ((typ = ((PROCPTRMIPS)pSym)->typind) == T_NOTYPE) { // this is a hack to allow breakpoints on untyped symbols typ = T_32PUCHAR; EVAL_SYM_OFF (pv) = ((PROCPTRMIPS)pSym)->off; EVAL_SYM_SEG (pv) = ((PROCPTRMIPS)pSym)->seg; EVAL_PTR (pv) = EVAL_SYM (pv); EVAL_STATE (pv) = EV_rvalue; } else { EVAL_SYM (pv) = *SHpADDRFrompCXT (pCXT); EVAL_SYM_SEG (pv) = ((PROCPTRMIPS)pSym)->seg; EVAL_SYM_OFF (pv) = ((PROCPTRMIPS)pSym)->off; } break; case S_REGREL32: EVAL_IS_REGREL (pv) = TRUE; EVAL_SYM_OFF (pv) = ((LPREGREL32)pSym)->off; EVAL_SYM_SEG (pv) = 0; EVAL_REGREL (pv) = ((LPREGREL32)pSym)->reg; typ = ((LPREGREL32)pSym)->typind; ADDR_IS_LI (EVAL_SYM (pv)) = FALSE; ADDR_IS_FLAT (EVAL_SYM (pv)) = TRUE; ADDR_IS_OFF32( EVAL_SYM ( pv ) ) = TRUE; pExState->state.regrel = TRUE; cmpThis = strncmp ( (char *) &((LPREGREL32)pSym)->name[0], (char *) &OpName[0], ((LPREGREL32)pSym)->name[0] + 1); break; case S_LABEL32: EVAL_IS_LABEL (pv) = TRUE; EVAL_SYM_OFF (pv) = ((LABELPTR32)pSym)->off; EVAL_SYM_SEG (pv) = ((LABELPTR32)pSym)->seg; ADDR_IS_LI (EVAL_SYM (pv)) = TRUE; ADDR_IS_FLAT (EVAL_SYM (pv)) = TRUE; ADDR_IS_OFF32( EVAL_SYM ( pv ) ) = TRUE; EVAL_PTR (pv) = EVAL_SYM (pv); EVAL_STATE (pv) = EV_rvalue; typ = T_32PUCHAR; break; case S_BPREL32: EVAL_IS_BPREL (pv) = TRUE; EVAL_SYM_OFF (pv) = ((BPRELPTR32)pSym)->off; EVAL_SYM_SEG (pv) = 0; typ = ((BPRELPTR32)pSym)->typind; ADDR_IS_LI (EVAL_SYM (pv)) = FALSE; ADDR_IS_FLAT (EVAL_SYM (pv)) = TRUE; ADDR_IS_OFF32( EVAL_SYM ( pv ) ) = TRUE; pExState->state.bprel = TRUE; pExState->state.regrel = TRUE; cmpThis = strncmp ( (char *) &((BPRELPTR32)pSym)->name[0], (char *) &OpName[0], ((BPRELPTR32)pSym)->name[0] + 1); break; case S_LTHREAD32: // NOTENOTE - jimsch -- TLS -- global vs local difference? case S_GTHREAD32: EVAL_IS_TLSREL( pv ) = TRUE; EVAL_SYM_OFF( pv ) = ((DATAPTR32) pSym)->off; EVAL_SYM_SEG( pv ) = ((DATAPTR32) pSym)->seg; typ = ((DATAPTR32) pSym)->typind; ADDR_IS_LI( EVAL_SYM( pv )) = TRUE; ADDR_IS_FLAT( EVAL_SYM( pv )) = TRUE; ADDR_IS_OFF32( EVAL_SYM ( pv ) ) = TRUE; pExState->state.tlsrel = TRUE; break; case S_LDATA32: pExState->state.fLData = TRUE; EVAL_SYM_OFF (pv) = ((DATAPTR32)pSym)->off; EVAL_SYM_SEG (pv) = ((DATAPTR32)pSym)->seg; typ = ((DATAPTR32)pSym)->typind; ADDR_IS_LI (EVAL_SYM (pv)) = TRUE; ADDR_IS_FLAT (EVAL_SYM (pv)) = TRUE; ADDR_IS_OFF32( EVAL_SYM ( pv ) ) = TRUE; break; case S_GDATA32: pExState->state.fGData = TRUE; EVAL_SYM_OFF (pv) = ((DATAPTR32)pSym)->off; EVAL_SYM_SEG (pv) = ((DATAPTR32)pSym)->seg; typ = ((DATAPTR32)pSym)->typind; ADDR_IS_LI (EVAL_SYM (pv)) = TRUE; ADDR_IS_FLAT (EVAL_SYM (pv)) = TRUE; ADDR_IS_OFF32( EVAL_SYM ( pv ) ) = TRUE; if (FNtsdEvalType) { FNtsdEvalType = FALSE; EVAL_STATE (pv) = EV_rvalue; EVAL_PTR (pv) = EVAL_SYM (pv); typ = T_32PULONG; } break; case S_PUB32: EVAL_SYM_OFF (pv) = ((DATAPTR32)pSym)->off; EVAL_SYM_SEG (pv) = ((DATAPTR32)pSym)->seg; ADDR_IS_LI (EVAL_SYM (pv)) = TRUE; ADDR_IS_FLAT (EVAL_SYM (pv)) = TRUE; ADDR_IS_OFF32( EVAL_SYM ( pv ) ) = TRUE; EVAL_PTR (pv) = EVAL_SYM (pv); EVAL_STATE (pv) = EV_lvalue; if (((typ = ((DATAPTR32)pSym)->typind) == T_NOTYPE) || FNtsdEvalType) { if (FNtsdEvalType) { FNtsdEvalType = FALSE; evalstate = EV_rvalue; typ = T_32PULONG; } else { typ = T_UINT4; evalstate = EV_lvalue; } // // this is a hack to allow breakpoints on untyped symbols // mi.addr = EVAL_SYM(pv); SYGetMemInfo(&mi); if ((mi.dwState & MEM_COMMIT) && (mi.dwProtect & (PAGE_EXECUTE | PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY)) ) { typ = T_32PUCHAR; EVAL_STATE (pv) = EV_rvalue; } else { // // this gives windbg the "look & feel" of ntsd/kd // if the user does a "dd foo" and there are only // coff publics then the answer will be the same // as ntsd/kd // EVAL_STATE (pv) = evalstate; } } break; default: // these OMF records are no longer supported MHOmfUnLock ((HDEP)hSym); pExState->err_num = ERR_BADOMF; return (FALSE); } MHOmfUnLock ((HDEP)hSym); if (SetNodeType (pv, typ) == FALSE) { return (FALSE); } else if (ClassImp != T_NOTYPE) { if (EVAL_IS_PTR (pv) && memcmp (pName->sstr.lpName, &OpName[0] + 1, pName->sstr.cb) == 0) { PTR_THISADJUST (pv) = ClassThisAdjust; } else if (cmpThis == 0) { PTR_THISADJUST (pv) = ClassThisAdjust; } } return (TRUE); } #if defined (M68K) #define VALID68851 0x40 #define VALID68882 0x80 #define VALID68000 0x01 #define VALID68010 0x02 | VALID68000 #define VALID68020 0x04 | VALID68010 #define VALID68030 0x08 | VALID68020 | VALID68851 #define VALID68040 0x10 | VALID68030 struct hreg { char name[7]; ushort index; char valid; ushort type; } _based (_segname("_CODE")) hreg_list[] = { {"\x002""D0", CV_R68_D0, VALID68000, T_ULONG}, {"\x002""D1", CV_R68_D1, VALID68000, T_ULONG}, {"\x002""D2", CV_R68_D2, VALID68000, T_ULONG}, {"\x002""D3", CV_R68_D3, VALID68000, T_ULONG}, {"\x002""D4", CV_R68_D4, VALID68000, T_ULONG}, {"\x002""D5", CV_R68_D5, VALID68000, T_ULONG}, {"\x002""D6", CV_R68_D6, VALID68000, T_ULONG}, {"\x002""D7", CV_R68_D7, VALID68000, T_ULONG}, {"\x002""A0", CV_R68_A0, VALID68000, T_ULONG}, {"\x002""A1", CV_R68_A1, VALID68000, T_ULONG}, {"\x002""A2", CV_R68_A2, VALID68000, T_ULONG}, {"\x002""A3", CV_R68_A3, VALID68000, T_ULONG}, {"\x002""A4", CV_R68_A4, VALID68000, T_ULONG}, {"\x002""A5", CV_R68_A5, VALID68000, T_ULONG}, {"\x002""A6", CV_R68_A6, VALID68000, T_ULONG}, {"\x002""A7", CV_R68_A7, VALID68000, T_ULONG}, {"\x003""CCR", CV_R68_CCR, VALID68000, T_USHORT}, {"\x002""SR", CV_R68_SR, VALID68000, T_USHORT}, {"\x003""USP", CV_R68_USP, VALID68000, T_ULONG}, {"\x003""MSP", CV_R68_MSP, VALID68000, T_ULONG}, {"\x002""PC", CV_R68_PC, VALID68000, T_ULONG}, {"\x003""SFC", CV_R68_SFC, VALID68010, T_USHORT}, {"\x003""DFC", CV_R68_DFC, VALID68010, T_USHORT}, {"\x003""VBR", CV_R68_VBR, VALID68010, T_USHORT}, {"\x004""CACR", CV_R68_CACR, VALID68020, T_ULONG}, {"\x004""CAAR", CV_R68_CAAR, VALID68020, T_ULONG}, {"\x003""ISP", CV_R68_ISP, VALID68020, T_ULONG}, {"\x003""PSR", CV_R68_PSR, VALID68851, T_USHORT}, {"\x004""PCSR", CV_R68_PCSR, VALID68851, T_USHORT}, {"\x003""VAL", CV_R68_VAL, VALID68851, T_USHORT}, {"\x003""CRP", CV_R68_CRP, VALID68851, T_UQUAD}, {"\x003""SRP", CV_R68_SRP, VALID68851, T_UQUAD}, {"\x003""DRP", CV_R68_DRP, VALID68851, T_UQUAD}, {"\x002""TC", CV_R68_TC, VALID68851, T_ULONG}, {"\x002""AC", CV_R68_AC, VALID68851, T_USHORT}, {"\x003""SCC", CV_R68_SCC, VALID68851, T_USHORT}, {"\x003""CAL", CV_R68_CAL, VALID68851, T_USHORT}, {"\x004""BAD0", CV_R68_BAD0, VALID68851, T_USHORT}, {"\x004""BAD1", CV_R68_BAD1, VALID68851, T_USHORT}, {"\x004""BAD2", CV_R68_BAD2, VALID68851, T_USHORT}, {"\x004""BAD3", CV_R68_BAD3, VALID68851, T_USHORT}, {"\x004""BAD4", CV_R68_BAD4, VALID68851, T_USHORT}, {"\x004""BAD5", CV_R68_BAD5, VALID68851, T_USHORT}, {"\x004""BAD6", CV_R68_BAD6, VALID68851, T_USHORT}, {"\x004""BAD7", CV_R68_BAD7, VALID68851, T_USHORT}, {"\x004""BAC0", CV_R68_BAC0, VALID68851, T_USHORT}, {"\x004""BAC1", CV_R68_BAC1, VALID68851, T_USHORT}, {"\x004""BAC2", CV_R68_BAC2, VALID68851, T_USHORT}, {"\x004""BAC3", CV_R68_BAC3, VALID68851, T_USHORT}, {"\x004""BAC4", CV_R68_BAC4, VALID68851, T_USHORT}, {"\x004""BAC5", CV_R68_BAC5, VALID68851, T_USHORT}, {"\x004""BAC6", CV_R68_BAC6, VALID68851, T_USHORT}, {"\x004""BAC7", CV_R68_BAC7, VALID68851, T_USHORT}, {"\x003""TT0", CV_R68_TT0, VALID68030, T_ULONG}, {"\x003""TT1", CV_R68_TT1, VALID68030, T_ULONG}, {"\x004""FPCR", CV_R68_FPCR, VALID68882, T_ULONG}, {"\x004""FPSR", CV_R68_FPSR, VALID68882, T_ULONG}, {"\x005""FPIAR", CV_R68_FPIAR, VALID68882, T_ULONG}, {"\x003""FP0", CV_R68_FP0, VALID68882, T_REAL80}, {"\x003""FP1", CV_R68_FP1, VALID68882, T_REAL80}, {"\x003""FP2", CV_R68_FP2, VALID68882, T_REAL80}, {"\x003""FP3", CV_R68_FP3, VALID68882, T_REAL80}, {"\x003""FP4", CV_R68_FP4, VALID68882, T_REAL80}, {"\x003""FP5", CV_R68_FP5, VALID68882, T_REAL80}, {"\x003""FP6", CV_R68_FP6, VALID68882, T_REAL80}, {"\x003""FP7", CV_R68_FP7, VALID68882, T_REAL80}, }; #endif // M68K struct hreg { char name[9]; int index; ushort type; #ifdef WIN32 } hreg_list[] = { #else } _based (_segname("_CODE")) hreg_list[] = { #endif {"\x002""$p", CV_REG_PSEUDO1, T_ULONG}, {"\x003""$p1", CV_REG_PSEUDO1, T_ULONG}, {"\x003""$p2", CV_REG_PSEUDO2, T_ULONG}, {"\x003""$p3", CV_REG_PSEUDO3, T_ULONG}, {"\x003""$p4", CV_REG_PSEUDO4, T_ULONG}, {"\x002""$u", CV_REG_PSEUDO5, T_ULONG}, {"\x003""$u1", CV_REG_PSEUDO5, T_ULONG}, {"\x003""$u2", CV_REG_PSEUDO6, T_ULONG}, {"\x003""$u3", CV_REG_PSEUDO7, T_ULONG}, {"\x003""$u4", CV_REG_PSEUDO8, T_ULONG}, {"\x004""$exp", CV_REG_PSEUDO9, T_ULONG}, #ifdef TARGET_i386 {"\x002""AX", CV_REG_AX, T_USHORT}, {"\x002""BX", CV_REG_BX, T_USHORT}, {"\x002""CX", CV_REG_CX, T_USHORT}, {"\x002""DX", CV_REG_DX, T_USHORT}, {"\x002""SP", CV_REG_SP, T_USHORT}, {"\x002""BP", CV_REG_BP, T_USHORT}, {"\x002""SI", CV_REG_SI, T_USHORT}, {"\x002""DI", CV_REG_DI, T_USHORT}, {"\x002""DS", CV_REG_DS, T_USHORT}, {"\x002""ES", CV_REG_ES, T_USHORT}, {"\x002""SS", CV_REG_SS, T_USHORT}, {"\x002""CS", CV_REG_CS, T_USHORT}, {"\x002""IP", CV_REG_IP, T_USHORT}, {"\x002""FL", CV_REG_FLAGS, T_USHORT}, {"\x003""EFL", CV_REG_EFLAGS, T_ULONG}, {"\x003""EAX", CV_REG_EAX, T_ULONG}, {"\x003""EBX", CV_REG_EBX, T_ULONG}, {"\x003""ECX", CV_REG_ECX, T_ULONG}, {"\x003""EDX", CV_REG_EDX, T_ULONG}, {"\x003""ESP", CV_REG_ESP, T_ULONG}, {"\x003""EBP", CV_REG_EBP, T_ULONG}, {"\x003""ESI", CV_REG_ESI, T_ULONG}, {"\x003""EDI", CV_REG_EDI, T_ULONG}, {"\x003""EIP", CV_REG_EIP, T_ULONG}, {"\x002""FS", CV_REG_FS, T_USHORT}, {"\x002""GS", CV_REG_GS, T_USHORT}, {"\x002""AH", CV_REG_AH, T_UCHAR}, {"\x002""BH", CV_REG_BH, T_UCHAR}, {"\x002""CH", CV_REG_CH, T_UCHAR}, {"\x002""DH", CV_REG_DH, T_UCHAR}, {"\x002""AL", CV_REG_AL, T_UCHAR}, {"\x002""BL", CV_REG_BL, T_UCHAR}, {"\x002""CL", CV_REG_CL, T_UCHAR}, {"\x002""DL", CV_REG_DL, T_UCHAR}, {"\x002""st", CV_REG_ST0, T_REAL80}, {"\x003""st0", CV_REG_ST0, T_REAL80}, {"\x003""st1", CV_REG_ST1, T_REAL80}, {"\x003""st2", CV_REG_ST2, T_REAL80}, {"\x003""st3", CV_REG_ST3, T_REAL80}, {"\x003""st4", CV_REG_ST4, T_REAL80}, {"\x003""st5", CV_REG_ST5, T_REAL80}, {"\x003""st6", CV_REG_ST6, T_REAL80}, {"\x003""st7", CV_REG_ST7, T_REAL80}, {"\x003""cr0", CV_REG_CR0, T_ULONG}, {"\x003""cr1", CV_REG_CR1, T_ULONG}, {"\x003""cr2", CV_REG_CR2, T_ULONG}, {"\x003""cr3", CV_REG_CR3, T_ULONG}, {"\x003""cr4", CV_REG_CR4, T_ULONG}, {"\x003""dr0", CV_REG_DR0, T_ULONG}, {"\x003""dr1", CV_REG_DR1, T_ULONG}, {"\x003""dr2", CV_REG_DR2, T_ULONG}, {"\x003""dr3", CV_REG_DR3, T_ULONG}, {"\x003""dr4", CV_REG_DR4, T_ULONG}, {"\x003""dr5", CV_REG_DR5, T_ULONG}, {"\x003""dr6", CV_REG_DR6, T_ULONG}, {"\x003""dr7", CV_REG_DR7, T_ULONG}, #endif // TARGET_i386 #ifdef TARGET_PPC {"\004""GPR0", CV_PPC_GPR0,T_ULONG}, {"\004""GPR1", CV_PPC_GPR1, T_ULONG}, {"\004""GPR2", CV_PPC_GPR2, T_ULONG}, {"\004""GPR3", CV_PPC_GPR3, T_ULONG}, {"\004""GPR4", CV_PPC_GPR4, T_ULONG}, {"\004""GPR5", CV_PPC_GPR5, T_ULONG}, {"\004""GPR6", CV_PPC_GPR6, T_ULONG}, {"\004""GPR7", CV_PPC_GPR7, T_ULONG}, {"\004""GPR8", CV_PPC_GPR8, T_ULONG}, {"\004""GPR9", CV_PPC_GPR9, T_ULONG}, {"\005""GPR10", CV_PPC_GPR10, T_ULONG}, {"\005""GPR11", CV_PPC_GPR11, T_ULONG}, {"\005""GPR12", CV_PPC_GPR12, T_ULONG}, {"\005""GPR13", CV_PPC_GPR13, T_ULONG}, {"\005""GPR14", CV_PPC_GPR14, T_ULONG}, {"\005""GPR15", CV_PPC_GPR15, T_ULONG}, {"\005""GPR16", CV_PPC_GPR16, T_ULONG}, {"\005""GPR17", CV_PPC_GPR17, T_ULONG}, {"\005""GPR18", CV_PPC_GPR18, T_ULONG}, {"\005""GPR19", CV_PPC_GPR19, T_ULONG}, {"\005""GPR20", CV_PPC_GPR20, T_ULONG}, {"\005""GPR21", CV_PPC_GPR21, T_ULONG}, {"\005""GPR22", CV_PPC_GPR22, T_ULONG}, {"\005""GPR23", CV_PPC_GPR23, T_ULONG}, {"\005""GPR24", CV_PPC_GPR24, T_ULONG}, {"\005""GPR25", CV_PPC_GPR25, T_ULONG}, {"\005""GPR30", CV_PPC_GPR30, T_ULONG}, {"\005""GPR26", CV_PPC_GPR26, T_ULONG}, {"\005""GPR27", CV_PPC_GPR27, T_ULONG}, {"\005""GPR28", CV_PPC_GPR28, T_ULONG}, {"\005""GPR29", CV_PPC_GPR29, T_ULONG}, {"\005""GPR31", CV_PPC_GPR31, T_ULONG}, // floating point registers follow {"\004""FPR0", CV_PPC_FPR0, T_REAL64 }, {"\004""FPR1", CV_PPC_FPR1, T_REAL64 }, {"\004""FPR2", CV_PPC_FPR2, T_REAL64 }, {"\004""FPR3", CV_PPC_FPR3, T_REAL64 }, {"\004""FPR4", CV_PPC_FPR4, T_REAL64 }, {"\004""FPR5", CV_PPC_FPR5, T_REAL64 }, {"\004""FPR6", CV_PPC_FPR6, T_REAL64 }, {"\004""FPR7", CV_PPC_FPR7, T_REAL64 }, {"\004""FPR8", CV_PPC_FPR8, T_REAL64 }, {"\004""FPR9", CV_PPC_FPR9, T_REAL64 }, {"\005""FPR10", CV_PPC_FPR10, T_REAL64 }, {"\005""FPR11", CV_PPC_FPR11, T_REAL64 }, {"\005""FPR12", CV_PPC_FPR12, T_REAL64 }, {"\005""FPR13", CV_PPC_FPR13, T_REAL64 }, {"\005""FPR14", CV_PPC_FPR14, T_REAL64 }, {"\005""FPR15", CV_PPC_FPR15, T_REAL64 }, {"\005""FPR16", CV_PPC_FPR16, T_REAL64 }, {"\005""FPR17", CV_PPC_FPR17, T_REAL64 }, {"\005""FPR18", CV_PPC_FPR18, T_REAL64 }, {"\005""FPR19", CV_PPC_FPR19, T_REAL64 }, {"\005""FPR20", CV_PPC_FPR20, T_REAL64 }, {"\005""FPR21", CV_PPC_FPR21, T_REAL64 }, {"\005""FPR22", CV_PPC_FPR22, T_REAL64 }, {"\005""FPR23", CV_PPC_FPR23, T_REAL64 }, {"\005""FPR24", CV_PPC_FPR24, T_REAL64 }, {"\005""FPR25", CV_PPC_FPR25, T_REAL64 }, {"\005""FPR26", CV_PPC_FPR26, T_REAL64 }, {"\005""FPR27", CV_PPC_FPR27, T_REAL64 }, {"\005""FPR28", CV_PPC_FPR28, T_REAL64 }, {"\005""FPR29", CV_PPC_FPR29, T_REAL64 }, {"\005""FPR30", CV_PPC_FPR30, T_REAL64 }, {"\005""FPR31", CV_PPC_FPR31, T_REAL64 }, {"\005""FPSCR", CV_PPC_FPSCR, T_ULONG }, {"\002""LR", CV_PPC_LR, T_ULONG }, {"\002""CR", CV_PPC_CR, T_ULONG }, {"\003""CTR", CV_PPC_CTR, T_ULONG }, {"\003""CIA", CV_PPC_PC, T_ULONG }, {"\003""XER", CV_PPC_XER, T_ULONG }, {"\003""MSR", CV_PPC_MSR, T_ULONG } #endif //TARGET_PPC #ifdef TARGET_MIPS {"\004""ZERO", CV_M4_IntZERO, T_ULONG}, {"\002""AT", CV_M4_IntAT, T_ULONG}, {"\002""V0", CV_M4_IntV0, T_ULONG}, {"\002""V1", CV_M4_IntV1, T_ULONG}, {"\002""A0", CV_M4_IntA0, T_ULONG}, {"\002""A1", CV_M4_IntA1, T_ULONG}, {"\002""A2", CV_M4_IntA2, T_ULONG}, {"\002""A3", CV_M4_IntA3, T_ULONG}, {"\002""T0", CV_M4_IntT0, T_ULONG}, {"\002""T1", CV_M4_IntT1, T_ULONG}, {"\002""T2", CV_M4_IntT2, T_ULONG}, {"\002""T3", CV_M4_IntT3, T_ULONG}, {"\002""T4", CV_M4_IntT4, T_ULONG}, {"\002""T5", CV_M4_IntT5, T_ULONG}, {"\002""T6", CV_M4_IntT6, T_ULONG}, {"\002""T7", CV_M4_IntT7, T_ULONG}, {"\002""T8", CV_M4_IntT8, T_ULONG}, {"\002""T9", CV_M4_IntT9, T_ULONG}, {"\002""S0", CV_M4_IntS0, T_ULONG}, {"\002""S1", CV_M4_IntS1, T_ULONG}, {"\002""S2", CV_M4_IntS2, T_ULONG}, {"\002""S3", CV_M4_IntS3, T_ULONG}, {"\002""S4", CV_M4_IntS4, T_ULONG}, {"\002""S5", CV_M4_IntS5, T_ULONG}, {"\002""S6", CV_M4_IntS6, T_ULONG}, {"\002""S7", CV_M4_IntS7, T_ULONG}, {"\002""S8", CV_M4_IntS8, T_ULONG}, {"\002""K0", CV_M4_IntKT0, T_ULONG}, {"\002""K1", CV_M4_IntKT1, T_ULONG}, {"\002""GP", CV_M4_IntGP, T_ULONG}, {"\002""SP", CV_M4_IntSP, T_ULONG}, {"\002""RA", CV_M4_IntRA, T_ULONG}, {"\003""FIR", CV_M4_Fir, T_ULONG}, {"\003""PSR", CV_M4_Psr, T_ULONG}, {"\003""FSR", CV_M4_FltFsr, T_ULONG}, {"\002""HI", CV_M4_IntHI, T_ULONG}, {"\002""LO", CV_M4_IntLO, T_ULONG}, {"\003""FR0", CV_M4_FltF0, T_REAL32}, {"\003""FR1", CV_M4_FltF1, T_REAL32}, {"\003""FR2", CV_M4_FltF2, T_REAL32}, {"\003""FR3", CV_M4_FltF3, T_REAL32}, {"\003""FR4", CV_M4_FltF4, T_REAL32}, {"\003""FR5", CV_M4_FltF5, T_REAL32}, {"\003""FR6", CV_M4_FltF6, T_REAL32}, {"\003""FR7", CV_M4_FltF7, T_REAL32}, {"\003""FR8", CV_M4_FltF8, T_REAL32}, {"\003""FR9", CV_M4_FltF9, T_REAL32}, {"\004""FR10", CV_M4_FltF10, T_REAL32}, {"\004""FR11", CV_M4_FltF11, T_REAL32}, {"\004""FR12", CV_M4_FltF12, T_REAL32}, {"\004""FR13", CV_M4_FltF13, T_REAL32}, {"\004""FR14", CV_M4_FltF14, T_REAL32}, {"\004""FR15", CV_M4_FltF15, T_REAL32}, {"\004""FR16", CV_M4_FltF16, T_REAL32}, {"\004""FR17", CV_M4_FltF17, T_REAL32}, {"\004""FR18", CV_M4_FltF18, T_REAL32}, {"\004""FR19", CV_M4_FltF19, T_REAL32}, {"\004""FR20", CV_M4_FltF20, T_REAL32}, {"\004""FR21", CV_M4_FltF21, T_REAL32}, {"\004""FR22", CV_M4_FltF22, T_REAL32}, {"\004""FR23", CV_M4_FltF23, T_REAL32}, {"\004""FR24", CV_M4_FltF24, T_REAL32}, {"\004""FR25", CV_M4_FltF25, T_REAL32}, {"\004""FR26", CV_M4_FltF26, T_REAL32}, {"\004""FR27", CV_M4_FltF27, T_REAL32}, {"\004""FR28", CV_M4_FltF28, T_REAL32}, {"\004""FR29", CV_M4_FltF29, T_REAL32}, {"\004""FR30", CV_M4_FltF30, T_REAL32}, {"\004""FR31", CV_M4_FltF31, T_REAL32}, {"\003""FP0", CV_M4_FltF0 << 8 | CV_M4_FltF1, T_REAL64}, {"\003""FP2", CV_M4_FltF2 << 8 | CV_M4_FltF3, T_REAL64}, {"\003""FP4", CV_M4_FltF4 << 8 | CV_M4_FltF5, T_REAL64}, {"\003""FP6", CV_M4_FltF6 << 8 | CV_M4_FltF7, T_REAL64}, {"\003""FP8", CV_M4_FltF8 << 8 | CV_M4_FltF9, T_REAL64}, {"\004""FP10", CV_M4_FltF10 << 8 | CV_M4_FltF11, T_REAL64}, {"\004""FP12", CV_M4_FltF12 << 8 | CV_M4_FltF13, T_REAL64}, {"\004""FP14", CV_M4_FltF14 << 8 | CV_M4_FltF15, T_REAL64}, {"\004""FP16", CV_M4_FltF16 << 8 | CV_M4_FltF17, T_REAL64}, {"\004""FP18", CV_M4_FltF18 << 8 | CV_M4_FltF19, T_REAL64}, {"\004""FP20", CV_M4_FltF20 << 8 | CV_M4_FltF21, T_REAL64}, {"\004""FP22", CV_M4_FltF22 << 8 | CV_M4_FltF23, T_REAL64}, {"\004""FP24", CV_M4_FltF24 << 8 | CV_M4_FltF25, T_REAL64}, {"\004""FP26", CV_M4_FltF26 << 8 | CV_M4_FltF27, T_REAL64}, {"\004""FP28", CV_M4_FltF28 << 8 | CV_M4_FltF29, T_REAL64}, {"\004""FP30", CV_M4_FltF30 << 8 | CV_M4_FltF31, T_REAL64}, #endif // TARGET_MIPS #ifdef TARGET_ALPHA {"\002""V0", CV_ALPHA_IntV0, T_UQUAD }, {"\002""T0", CV_ALPHA_IntT0, T_UQUAD }, {"\002""T1", CV_ALPHA_IntT1, T_UQUAD }, {"\002""T2", CV_ALPHA_IntT2, T_UQUAD }, {"\002""T3", CV_ALPHA_IntT3, T_UQUAD }, {"\002""T4", CV_ALPHA_IntT4, T_UQUAD }, {"\002""T5", CV_ALPHA_IntT5, T_UQUAD }, {"\002""T6", CV_ALPHA_IntT6, T_UQUAD }, {"\002""T7", CV_ALPHA_IntT7, T_UQUAD }, {"\002""S0", CV_ALPHA_IntS0, T_UQUAD }, {"\002""S1", CV_ALPHA_IntS1, T_UQUAD }, {"\002""S2", CV_ALPHA_IntS2, T_UQUAD }, {"\002""S3", CV_ALPHA_IntS3, T_UQUAD }, {"\002""S4", CV_ALPHA_IntS4, T_UQUAD }, {"\002""S5", CV_ALPHA_IntS5, T_UQUAD }, {"\002""FP", CV_ALPHA_IntFP, T_UQUAD }, {"\002""A0", CV_ALPHA_IntA0, T_UQUAD }, {"\002""A1", CV_ALPHA_IntA1, T_UQUAD }, {"\002""A2", CV_ALPHA_IntA2, T_UQUAD }, {"\002""A3", CV_ALPHA_IntA3, T_UQUAD }, {"\002""A4", CV_ALPHA_IntA4, T_UQUAD }, {"\002""A5", CV_ALPHA_IntA5, T_UQUAD }, {"\002""T8", CV_ALPHA_IntT8, T_UQUAD }, {"\002""T9", CV_ALPHA_IntT9, T_UQUAD }, {"\003""T10", CV_ALPHA_IntT10, T_UQUAD }, {"\003""T11", CV_ALPHA_IntT11, T_UQUAD }, {"\002""RA", CV_ALPHA_IntRA, T_UQUAD }, {"\003""T12", CV_ALPHA_IntT12, T_UQUAD }, {"\002""AT", CV_ALPHA_IntAT, T_UQUAD }, {"\002""GP", CV_ALPHA_IntGP, T_UQUAD }, {"\002""SP", CV_ALPHA_IntSP, T_UQUAD }, {"\004""ZERO", CV_ALPHA_IntZERO, T_UQUAD }, {"\002""F0", CV_ALPHA_FltF0, T_REAL64 }, {"\002""F1", CV_ALPHA_FltF1, T_REAL64 }, {"\002""F2", CV_ALPHA_FltF2, T_REAL64 }, {"\002""F3", CV_ALPHA_FltF3, T_REAL64 }, {"\002""F4", CV_ALPHA_FltF4, T_REAL64 }, {"\002""F5", CV_ALPHA_FltF5, T_REAL64 }, {"\002""F6", CV_ALPHA_FltF6, T_REAL64 }, {"\002""F7", CV_ALPHA_FltF7, T_REAL64 }, {"\002""F8", CV_ALPHA_FltF8, T_REAL64 }, {"\002""F9", CV_ALPHA_FltF9, T_REAL64 }, {"\003""F10", CV_ALPHA_FltF10, T_REAL64 }, {"\003""F11", CV_ALPHA_FltF11, T_REAL64 }, {"\003""F12", CV_ALPHA_FltF12, T_REAL64 }, {"\003""F13", CV_ALPHA_FltF13, T_REAL64 }, {"\003""F14", CV_ALPHA_FltF14, T_REAL64 }, {"\003""F15", CV_ALPHA_FltF15, T_REAL64 }, {"\003""F16", CV_ALPHA_FltF16, T_REAL64 }, {"\003""F17", CV_ALPHA_FltF17, T_REAL64 }, {"\003""F18", CV_ALPHA_FltF18, T_REAL64 }, {"\003""F19", CV_ALPHA_FltF19, T_REAL64 }, {"\003""F20", CV_ALPHA_FltF20, T_REAL64 }, {"\003""F21", CV_ALPHA_FltF21, T_REAL64 }, {"\003""F22", CV_ALPHA_FltF22, T_REAL64 }, {"\003""F23", CV_ALPHA_FltF23, T_REAL64 }, {"\003""F24", CV_ALPHA_FltF24, T_REAL64 }, {"\003""F25", CV_ALPHA_FltF25, T_REAL64 }, {"\003""F26", CV_ALPHA_FltF26, T_REAL64 }, {"\003""F27", CV_ALPHA_FltF27, T_REAL64 }, {"\003""F28", CV_ALPHA_FltF28, T_REAL64 }, {"\003""F29", CV_ALPHA_FltF29, T_REAL64 }, {"\003""F30", CV_ALPHA_FltF30, T_REAL64 }, {"\003""F31", CV_ALPHA_FltF31, T_REAL64 }, {"\003""FIR", CV_ALPHA_Fir, T_UQUAD }, {"\004""FPCR", CV_ALPHA_Fpcr, T_UQUAD }, {"\003""PSR", CV_ALPHA_Psr, T_ULONG } #endif // TARGET_ALPHA }; #define REGCNT (sizeof (hreg_list)/sizeof (struct hreg)) LOCAL bool_t ParseRegister ( psearch_t pName ) { int i; peval_t pv; if (*pName->sstr.lpName == '@') { pName->sstr.lpName++; pName->sstr.cb--; } for (i = 0; i < REGCNT; i++) { if (fnCmp ((LPSSTR) pName, NULL, hreg_list[i].name, FALSE) == 0) break; } if (i >= REGCNT) { return (HR_notfound); } pv = pName->pv; EVAL_REG (pv) = hreg_list[i].index; SetNodeType (pv, hreg_list[i].type); EVAL_IS_REG (pv) = TRUE; EVAL_STATE (pv) = EV_lvalue; PushStack (pv); return (HR_found); } #if defined (M68K) /** TypeFromHreg - get the CV type of a register * * type = TypeFromHreg (hReg) * * Entry hReg = register index * * Returns the CV type of the register * (T_NOTYPE if register not found) */ ushort TypeFromHreg ( ushort hreg ) { int i; for (i = 0; i < REGCNT; i++) { if (hreg == hreg_list[i].index) { return(hreg_list[i].type); } } return(T_NOTYPE); } #endif LOCAL bool_t LineNumber ( psearch_t pName ) { uchar *pb = pName->sstr.lpName + 1; uint i; char c; ulong val = 0; //FLS fls; HSF hsf; ADDR addr; SHOFF cbLine; peval_t pv; // convert line number for (i = pName->sstr.cb - 1; i > 0; i--) { c = *pb; if (!isdigit (c)) { // Must have reached the end pExState->err_num = ERR_LINENUMBER; return (HR_error); } val *= 10; val += (c - '0'); if (val > 0xffff) { // Must have overflowed pExState->err_num = ERR_LINENUMBER; return (HR_error); } pb++; } // Make sure we have the right address. if (!ADDR_IS_LI( *SHpADDRFrompCXT( pCxt ) )) { SHUnFixupAddr( SHpADDRFrompCXT( pCxt ) ); } if ( (hsf = SLHsfFromPcxt ( pCxt ) ) && SLFLineToAddr ( hsf, (ushort) val, &addr, &cbLine, NULL ) ) { pv = pName->pv; if (ADDR_IS_FLAT( *SHpADDRFrompCXT( pCxt )) ) { SetNodeType (pv, T_32PUCHAR); } else if (ADDR_IS_OFF32( *SHpADDRFrompCXT( pCxt )) ) { SetNodeType (pv, T_32PFUCHAR); } else { SetNodeType (pv, T_PFUCHAR); } EVAL_IS_LABEL (pv) = TRUE; EVAL_STATE (pv) = EV_rvalue; EVAL_SYM (pv) = addr; EVAL_PTR (pv) = addr; PushStack (pv); return (HR_found); } else { pExState->err_num = ERR_NOCODE; return (HR_error); } pExState->err_num = ERR_BADCONTEXT; return (HR_error); } /** InsertThis - rewrite bind tree to add this-> * * fSuccess = InsertThis (pName); * * Entry pName = pointer to search structure * * Exit tree rewritten such that the node pn becomes OP_pointsto * with the left node being OP_this and the right node being * the original symbol * * Returns TRUE if tree rewritten * FALSE if error */ LOCAL bool_t __fastcall InsertThis ( psearch_t pName ) { ushort len = 2 * (sizeof (node_t) + sizeof (eval_t)); ushort Left; ushort Right; pnode_t pn; bnode_t bn = pName->bn; Left = pTree->node_next; Right = Left + sizeof (node_t) + sizeof (eval_t); if ((ushort)(pTree->size - Left) < len) { if (!GrowETree (len)) { NOTTESTED (FALSE); pExState->err_num = ERR_NOMEMORY; return (FALSE); } if (bnCxt != 0) { // the context was pointing into the expression tree. // since the expression tree could have been reallocated, // we must recompute the context pointer pCxt = SHpCXTFrompCXF ((PCXF)&(pnodeOfbnode(bnCxt))->v[0]); } } // copy symbol to right node _fmemcpy (pnodeOfbnode((bnode_t)Right), pnodeOfbnode(bn), sizeof (node_t) + sizeof (eval_t)); // insert OP_this node as left node pn = pnodeOfbnode((bnode_t)Left); _fmemset (pn, 0, sizeof (node_t) + sizeof (eval_t)); NODE_OP (pn) = OP_this; // change original node to OP_pointsto pn = pnodeOfbnode(bn); _fmemset (pn, 0, sizeof (node_t) + sizeof (eval_t)); NODE_OP (pn) = OP_pointsto; NODE_LCHILD (pn) = (bnode_t)Left; NODE_RCHILD (pn) = (bnode_t)Right; pTree->node_next += len; return (TRUE); } /* * load a constant symbol into a node. */ LOCAL bool_t DebLoadConst ( peval_t pv, CONSTPTR pSym, HSYM hSym ) { uint skip = 0; CV_typ_t type; HTYPE hType; plfEnum pEnum; type = pSym->typind; if (!CV_IS_PRIMITIVE (type)) { // we also allow constants that are enumeration values, so check // that the non-primitive type is an enumeration and set the type // to the underlying type of the enum MHOmfUnLock ((HDEP)hSym); hType = THGetTypeFromIndex (EVAL_MOD (pv), type); if (hType == 0) { DASSERT (FALSE); pSym = MHOmfLock ((HDEP)hSym); pExState->err_num = ERR_BADOMF; return (FALSE); } pEnum = (plfEnum)(&((TYPPTR)(MHOmfLock ((HDEP)hType)))->leaf); if ((pEnum->leaf != LF_ENUM) || !CV_IS_PRIMITIVE (pEnum->utype)) { DASSERT (FALSE); MHOmfUnLock ((HDEP)hType); pSym = MHOmfLock ((HDEP)hSym); pExState->err_num = ERR_BADOMF; return (FALSE); } MHOmfUnLock ((HDEP)hType); pSym = MHOmfLock ((HDEP)hSym); SetNodeType (pv, type); // SetNodeType will resolve forward ref Enums - but we need to get the // utype from the pv when this happens - sps type = ENUM_UTYPE (pv); } else { SetNodeType (pv, type); } EVAL_STATE (pv) = EV_rvalue; if ((CV_MODE (type) != CV_TM_DIRECT) || ((CV_TYPE (type) != CV_SIGNED) && (CV_TYPE (type) != CV_UNSIGNED) && (CV_TYPE (type) != CV_INT))) { DASSERT (FALSE); pExState->err_num = ERR_BADOMF; return (FALSE); } EVAL_ULONG (pv) = RNumLeaf (&pSym->value, &skip); return (TRUE); }