mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
6674 lines
224 KiB
6674 lines
224 KiB
/*** 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);
|
|
}
|