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.
2142 lines
58 KiB
2142 lines
58 KiB
/*** debutil.c - Expression evaluator utility routines
|
|
*
|
|
*/
|
|
|
|
|
|
LOCAL void CheckFcnArgs (neval_t, HTYPE *, CV_call_e);
|
|
bool_t GrowStack (uint);
|
|
LOCAL void SetDPtr (neval_t, HTYPE *);
|
|
|
|
char size_special[8] = { 0, 2, 2, 0, 8, 0, 0, 0};
|
|
char size_special2[8] = { 0, 0, 0, 0, 0, 0, 0, 0};
|
|
char size_integral[8] = { 1, 2, 4, 8, 0, 0, 0, 0};
|
|
char size_real[8] = { 4, 8, 10, 16, 3, 0, 0, 0};
|
|
char size_ptr[8] = { 0, 2, 4, 4, 4, 6, 0, 0};
|
|
char size_int[8] = { 1, 2, 2, 2, 4, 4, 8, 8};
|
|
|
|
|
|
/** PushStack - push bind data onto stack
|
|
*
|
|
* fSuccess = PushStack (pv);
|
|
*
|
|
* Entry pv = pointer to evaluation entry
|
|
*
|
|
* Exit pv->vflags pushed onto evaluation stack
|
|
*
|
|
* Returns TRUE if entry pushed
|
|
* FALSE if error in push
|
|
*/
|
|
|
|
bool_t PushStack (peval_t pv)
|
|
{
|
|
uint len;
|
|
pelem_t pEL;
|
|
pelem_t pELP;
|
|
|
|
DASSERT ((ST == NULL) || (((char *) ST > (char *) pEStack) &&
|
|
((char *)ST < (char *)pEStack + (uint)StackOffset)));
|
|
DASSERT ((STP == NULL) ||
|
|
(((char *) STP > (char *) pEStack) && (STP < ST)));
|
|
len = sizeof (elem_t) +
|
|
max (EVAL_VALLEN (pv), sizeof (val_t)) - sizeof (val_t);
|
|
|
|
if (((uint)StackLen - (uint)StackOffset) < len) {
|
|
if (!GrowStack (len)) {
|
|
pExState->err_num = ERR_NOMEMORY;
|
|
return (FALSE);
|
|
}
|
|
}
|
|
if (ST == NULL) {
|
|
// first element onto stack and set based pointer to previous element
|
|
// to 0xffff which indicates null
|
|
|
|
pEL = (pelem_t)pEStack;
|
|
pELP = NULL;
|
|
pEL->pe = UINT_MAX;
|
|
}
|
|
else {
|
|
pEL = (pelem_t)((uchar *)pEStack + (uint)StackOffset);
|
|
pELP = (pelem_t)((char *)ST - (offsetof (elem_t, se) -
|
|
offsetof (elem_t, pe)));
|
|
pEL->pe = belemOfpelem(pELP);
|
|
}
|
|
StackOffset = (uint)StackOffset + len;
|
|
StackMax = max ((uint)StackMax, (uint)StackOffset);
|
|
if (pELP == NULL) {
|
|
STP = NULL;
|
|
}
|
|
else {
|
|
STP = (peval_t)&pELP->se;
|
|
}
|
|
ST = (peval_t)&pEL->se;
|
|
*ST = *pv;
|
|
DASSERT ((ST == NULL) || ((ST > (peval_t) pEStack) &&
|
|
((char *)ST < (char *)pEStack + (uint)StackOffset)));
|
|
DASSERT ((STP == NULL) ||
|
|
(((char *) STP > (char *)pEStack) && (STP < ST)));
|
|
return (TRUE);
|
|
}
|
|
|
|
|
|
|
|
|
|
/** PopStack - pop bind data from stack
|
|
*
|
|
* fSuccess = PopStack (void);
|
|
*
|
|
* Entry none
|
|
*
|
|
* Exit stack popped by one
|
|
*
|
|
* Returns TRUE if stack popped
|
|
* FALSE if error in pop
|
|
*/
|
|
|
|
|
|
bool_t PopStack ()
|
|
{
|
|
pelem_t pEL;
|
|
uint bELP;
|
|
|
|
DASSERT (ST != NULL);
|
|
DASSERT ((ST == NULL) || ((ST > (peval_t) pEStack) &&
|
|
((char *)ST < (char *)pEStack + (uint)StackOffset)));
|
|
DASSERT ((STP == NULL) ||
|
|
(((char *) STP > (char *) pEStack) && (STP < ST)));
|
|
if (ST == NULL) {
|
|
pExState->err_num = ERR_INTERNAL;
|
|
return (FALSE);
|
|
}
|
|
else {
|
|
// determine the beginning of the current stack element and
|
|
// reset the stack offset to the beginning of the top stack element
|
|
|
|
if (STP != NULL) {
|
|
DASSERT (((char *) STP > (char *) pEStack) && (STP < ST));
|
|
}
|
|
pEL = (pelem_t)((char *)ST - offsetof (elem_t, se));
|
|
|
|
// set the based pointer to the previous stack element
|
|
|
|
bELP = (uint)pEL->pe;
|
|
if (bELP == UINT_MAX) {
|
|
// we are popping off the only stack element
|
|
|
|
StackOffset = 0;
|
|
STP = NULL;
|
|
ST = NULL;
|
|
}
|
|
else if (bELP == 0) {
|
|
// we are popping to the last stack element
|
|
|
|
StackOffset = (char *)pEL - (char *)pEStack;
|
|
STP = NULL;
|
|
ST = (peval_t)&((pelem_t)pEStack)->se;
|
|
}
|
|
else {
|
|
StackOffset = (char *)pEL - (char *)pEStack;
|
|
ST = STP;
|
|
pEL = (pelem_t)((char *)ST - offsetof (elem_t, se));
|
|
bELP = (uint)pEL->pe;
|
|
STP = (peval_t)&((pelemOfbelem(bELP))->se);
|
|
}
|
|
DASSERT ((ST == NULL) || ((ST > (peval_t) pEStack) &&
|
|
((char *)ST < (char *)pEStack + (uint)StackOffset)));
|
|
DASSERT ((STP == NULL) || ((STP > (peval_t) pEStack) && (STP < ST)));
|
|
return (TRUE);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
/** CkPointStack - checkpoint stack position
|
|
*
|
|
* CkPointStack (void);
|
|
*
|
|
* Entry none
|
|
*
|
|
* Exit stack position saved in StackCkPoint
|
|
*
|
|
* Returns nothing
|
|
*/
|
|
|
|
|
|
void CkPointStack (void)
|
|
{
|
|
StackCkPoint = StackOffset;
|
|
}
|
|
|
|
|
|
|
|
|
|
/** ResetStack - reset stack to checkpoint position
|
|
*
|
|
* fSuccess = CkPointStack (void);
|
|
*
|
|
* Entry StackCkPoint = checkpointed position
|
|
*
|
|
* Exit stack position reset
|
|
*
|
|
* Returns TRUE if successfully reset
|
|
* FALSE if error
|
|
*/
|
|
|
|
|
|
bool_t ResetStack (void)
|
|
{
|
|
while (StackOffset > StackCkPoint) {
|
|
if (PopStack () == FALSE) {
|
|
return (FALSE);
|
|
}
|
|
}
|
|
if (StackOffset != StackCkPoint) {
|
|
return (FALSE);
|
|
}
|
|
return (TRUE);
|
|
}
|
|
|
|
|
|
|
|
|
|
/** GrowStack - grow evaluation stack and reset pointers
|
|
*
|
|
* fSuccess = GrowStack (len);
|
|
*
|
|
* Entry len = minimum increase size
|
|
*
|
|
* Exit stack grown
|
|
*
|
|
* Returns TRUE if stack grown
|
|
* FALSE if error
|
|
*/
|
|
|
|
|
|
bool_t GrowStack (uint len)
|
|
{
|
|
uint bST = UINT_MAX;
|
|
uint bSTP = UINT_MAX;
|
|
HDEP hNS; // handle of new evaluation stack
|
|
pelem_t pNS; // address of new evaluation stack
|
|
uint size;
|
|
|
|
// convert current stack pointers to based form
|
|
|
|
if (ST != NULL) {
|
|
bST = (uchar *)ST - (uchar *)pEStack - offsetof (elem_t, se);
|
|
}
|
|
if (STP != NULL) {
|
|
bSTP = (uchar *)STP - (uchar *)pEStack - offsetof (elem_t, se);
|
|
}
|
|
|
|
// allocate new evaluation stack and copy old to new
|
|
|
|
size = max ((uint)StackLen + 5 * sizeof (elem_t), (uint)StackLen + len);
|
|
if ((hNS = MHMemAllocate (size)) == 0) {
|
|
// if no memory
|
|
pExState->err_num = ERR_NOMEMORY;
|
|
return (FALSE);
|
|
}
|
|
else {
|
|
pNS = MHMemLock (hNS);
|
|
memcpy (pNS, pEStack, (char *)pelemOfbelem(StackOffset) -
|
|
(char *)pEStack);
|
|
|
|
// if old stack was not the standard fixed buffer, release it
|
|
|
|
MHMemUnLock (hEStack);
|
|
MHMemFree (hEStack);
|
|
hEStack = hNS;
|
|
pEStack = pNS;
|
|
if (bST != UINT_MAX) {
|
|
ST = (peval_t)&((pelem_t)(((char *)pEStack) + bST))->se;
|
|
}
|
|
if (bSTP != UINT_MAX) {
|
|
STP = (peval_t)&((pelem_t)(((char *)pEStack) + bSTP))->se;
|
|
}
|
|
StackLen = size;
|
|
return (TRUE);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* RNumLeaf - read numeric leaf
|
|
*
|
|
* value = RNumLeaf (
|
|
* Read numeric leaf and return value and size of leaf
|
|
*/
|
|
|
|
|
|
ulong RNumLeaf (void *pleaf, uint *skip)
|
|
{
|
|
ushort val;
|
|
|
|
if ((val = ((plfEasy)pleaf)->leaf) < LF_NUMERIC) {
|
|
// No leaf can have an index less than LF_NUMERIC (0x8000) so word is value
|
|
*skip += 2;
|
|
return (val);
|
|
}
|
|
|
|
switch (val) {
|
|
case LF_CHAR:
|
|
*skip += 3;
|
|
return (((plfChar)pleaf)->val);
|
|
|
|
case LF_USHORT:
|
|
*skip += 4;
|
|
return (((plfUShort)pleaf)->val);
|
|
|
|
case LF_SHORT:
|
|
*skip += 4;
|
|
return (((plfShort)pleaf)->val);
|
|
|
|
case LF_LONG:
|
|
case LF_ULONG:
|
|
*skip += 6;
|
|
return (((plfULong)pleaf)->val);
|
|
|
|
default:
|
|
DASSERT (FALSE);
|
|
return (0L);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
SHFLAG
|
|
fnCmp (
|
|
LPSSTR lpsstr,
|
|
LPV lpv,
|
|
LPSTR stName,
|
|
SHFLAG fCase
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Compares the name described by the hInfo packet with a length
|
|
prefixed name
|
|
|
|
Arguments:
|
|
|
|
lpsstr - sstr packet with match string or pattern (from user)
|
|
lpv - pointer to acutal symbol record
|
|
stName - length prefixed string (from symbol record)
|
|
fCase - case sensitivity flag
|
|
|
|
Return Value:
|
|
|
|
0 if matched, non-0 if not
|
|
|
|
--*/
|
|
{
|
|
psearch_t pName = (psearch_t) lpsstr;
|
|
SYMPTR pSym = (SYMPTR) lpv;
|
|
|
|
DASSERT (pName != NULL);
|
|
|
|
if ((stName == NULL) || (stName[0] == 0)) {
|
|
return (1);
|
|
}
|
|
|
|
if (pName->sstr.searchmask & SSTR_RE) {
|
|
|
|
pName->lastsym = pSym->rectyp;
|
|
|
|
if (pName->sstr.pRE == NULL) {
|
|
// return match if no regular expression specified
|
|
return (0);
|
|
} else {
|
|
|
|
// this is regular expression search
|
|
char buffer [256];
|
|
char * lpBuffer = buffer;
|
|
|
|
// stName is a length prefixed string. convert to a
|
|
// null terminated string
|
|
strncpy ( lpBuffer, stName+1, (unsigned char)stName[0] );
|
|
lpBuffer [ (unsigned char)stName[0] ] = '\0';
|
|
|
|
// do the compare using lpBuffer
|
|
return SHCompareRE ( lpBuffer, (char *)pName->sstr.pRE, fCase);
|
|
}
|
|
}
|
|
|
|
// strings do not compare if lengths are different
|
|
|
|
if (pName->sstr.cb == (uchar)(*stName++)) {
|
|
// Lengths are the same
|
|
if (pSym != NULL) {
|
|
// save type of last symbol checked
|
|
pName->lastsym = pSym->rectyp;
|
|
}
|
|
if (pName->sstr.searchmask & SSTR_proc) {
|
|
int cmpflag;
|
|
CV_typ_t type;
|
|
|
|
if (fCase == TRUE) {
|
|
cmpflag = strncmp ((char *)pName->sstr.lpName, stName, pName->sstr.cb);
|
|
} else {
|
|
cmpflag = _strnicmp ((char *)pName->sstr.lpName, stName, pName->sstr.cb);
|
|
}
|
|
if (cmpflag != 0) {
|
|
// we did not have a name match
|
|
return (cmpflag);
|
|
}
|
|
|
|
// we are checking only procs with the correct type
|
|
// If this flag is set, then the initializer set the desired
|
|
// proc index into pName->typeOut
|
|
|
|
switch (pSym->rectyp) {
|
|
case S_LPROC16:
|
|
case S_GPROC16:
|
|
type = ((PROCPTR16)pSym)->typind;
|
|
break;
|
|
|
|
case S_LPROC32:
|
|
case S_GPROC32:
|
|
type = ((PROCPTR32)pSym)->typind;
|
|
break;
|
|
|
|
case S_LPROCMIPS:
|
|
case S_GPROCMIPS:
|
|
type = ((PROCPTRMIPS)pSym)->typind;
|
|
break;
|
|
}
|
|
if (BindingBP == TRUE) {
|
|
if (type == pName->typeOut) {
|
|
// we have an exact match on name and type
|
|
return (0);
|
|
}
|
|
if (pName->FcnBP == 0) {
|
|
// save alternate type so we can search again
|
|
pName->FcnBP = type;
|
|
}
|
|
} else if (type == pName->typeOut) {
|
|
// we have an exact match on name and type
|
|
return (0);
|
|
}
|
|
return (1);
|
|
|
|
} else if (pName->sstr.searchmask & SSTR_data) {
|
|
// we are checking only global data with the correct type
|
|
// If this flag is set, then the initializer set the desired
|
|
// proc index into pName->typeOut
|
|
|
|
switch (pSym->rectyp) {
|
|
|
|
case S_GDATA16:
|
|
if (((DATAPTR16)pSym)->typind != pName->typeOut) {
|
|
return (1);
|
|
}
|
|
break;
|
|
|
|
case S_GDATA32:
|
|
if (((DATAPTR32)pSym)->typind != pName->typeOut) {
|
|
return (1);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
if (fCase == TRUE) {
|
|
return (strncmp ((char *)pName->sstr.lpName, stName, pName->sstr.cb));
|
|
} else {
|
|
return (_strnicmp ((char *)pName->sstr.lpName, stName, pName->sstr.cb));
|
|
}
|
|
}
|
|
|
|
#ifdef TARGET_i386
|
|
//
|
|
// Due to the strange naming conventions and strange assumptions about
|
|
// the lack of intellegence on the part of some people. It has been
|
|
// deemed desirable that we do special matching for standard call
|
|
// functions. Specifically that we ignore the @## on the end of the
|
|
// public label when doing compares. Potentially stupid but maybe
|
|
// necessary
|
|
//
|
|
// DEFINITLY NECESSARY!
|
|
//
|
|
|
|
//
|
|
// To do this the following conditions must be met:
|
|
//
|
|
// 1. Must be checking againist either a 16-bit public or a
|
|
// 32-bit public.
|
|
//
|
|
// 2. Must be no '@' character in the users string
|
|
//
|
|
// 3. Must be an '@' character in the symbol handlers string
|
|
//
|
|
// -------------------------------------------------------------
|
|
// Wesley Witt (wesw) 2-June-1994
|
|
// -------------------------------------------------------------
|
|
//
|
|
// The rules also accomodate fastcall names. A fastcall name
|
|
// has an @ as the first character. If the user's string has
|
|
// an @ as the first character and the symbol handler's string
|
|
// has an @ as the first character then the pointers are
|
|
// advanced and the above rule set applies as it has.
|
|
//
|
|
if (pSym != NULL &&
|
|
((pSym->rectyp == S_PUB16) || (pSym->rectyp == S_PUB32))) {
|
|
int idx = 0;
|
|
char *pch;
|
|
if (stName[0] == '@' && pName->sstr.lpName[0] == '@') {
|
|
idx = 1;
|
|
}
|
|
pch = strchr(&stName[idx], '@');
|
|
if ((pch != NULL) && (strchr(&pName->sstr.lpName[idx], '@') == NULL)) {
|
|
if ((pch-stName-idx) == pName->sstr.cb-idx) {
|
|
if (fCase == TRUE) {
|
|
return strncmp(&pName->sstr.lpName[idx], &stName[idx], pch-stName-idx);
|
|
} else {
|
|
return _strnicmp(&pName->sstr.lpName[idx], &stName[idx], pch-stName-idx);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif /* TARGET_i386 */
|
|
return (1);
|
|
} /* fnCmp() */
|
|
|
|
|
|
|
|
|
|
/** tdCmp - typedef compare routine.
|
|
*
|
|
* Compares the type described by the hInfo packet with a typedef symbol
|
|
*
|
|
* fFlag = tdCmp (psearch_t pName, SYMPTR pSym, char *stName, int fCase);
|
|
*
|
|
* Entry pName = pointer to psearch_t packet describing name
|
|
* pSym = pointer to symbol structure (NULL if internal call)
|
|
* stName = pointer to a length preceeded name
|
|
* fCase = ignored
|
|
*
|
|
* Exit none
|
|
*
|
|
* Returns 0 if typedef symbol of proper type found
|
|
*/
|
|
|
|
|
|
SHFLAG
|
|
tdCmp (
|
|
LPSSTR lpsstr,
|
|
LPV lpv,
|
|
char *stName,
|
|
SHFLAG fCase
|
|
)
|
|
{
|
|
psearch_t pName = (psearch_t) lpsstr;
|
|
SYMPTR pSym = (SYMPTR) lpv;
|
|
|
|
Unreferenced( stName );
|
|
Unreferenced( fCase );
|
|
|
|
DASSERT (pName != NULL);
|
|
DASSERT (pSym != NULL);
|
|
|
|
// strings do not compare if lengths are different
|
|
|
|
if ((pSym->rectyp == S_UDT) && (((UDTPTR)pSym)->typind == pName->typeIn)) {
|
|
pName->lastsym = pSym->rectyp;
|
|
return (0);
|
|
}
|
|
return (1);
|
|
}
|
|
|
|
|
|
|
|
|
|
/** csCmp - compile symbol compare routine.
|
|
*
|
|
* Compares the type described by the hInfo packet with a compile symbol
|
|
*
|
|
* fFlag = csCmp (psearch_t pName, SYMPTR pSym, char *stName, int fCase);
|
|
*
|
|
* Entry pName = pointer to psearch_t packet describing name
|
|
* pSym = pointer to symbol structure (NULL if internal call)
|
|
* stName = pointer to a length preceeded name
|
|
* fCase = ignored
|
|
*
|
|
* Exit none
|
|
*
|
|
* Returns 0 if compile symbol found
|
|
*/
|
|
|
|
|
|
SHFLAG
|
|
csCmp (
|
|
LPSSTR lpsstr,
|
|
LPV lpv,
|
|
char *stName,
|
|
SHFLAG fCase
|
|
)
|
|
{
|
|
psearch_t pName = (psearch_t) lpsstr;
|
|
SYMPTR pSym = (SYMPTR) lpv;
|
|
|
|
Unreferenced( stName );
|
|
Unreferenced( fCase );
|
|
|
|
DASSERT (pName != NULL);
|
|
DASSERT (pSym != NULL);
|
|
|
|
// strings do not compare if lengths are different
|
|
|
|
if (pSym->rectyp == S_COMPILE) {
|
|
pName->lastsym = pSym->rectyp;
|
|
return (0);
|
|
}
|
|
return (1);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*** InsertNode - Insert node in parse tree
|
|
*
|
|
* error = InsertNode (ptok)
|
|
*
|
|
* Entry pExState = address of expression state structure
|
|
* pExState->hSTree locked
|
|
*
|
|
* Exit pExState->hSTree locked
|
|
* pTree = address of locked syntax tree
|
|
*
|
|
* Returns TRUE if successful
|
|
* FALSE if unsuccessful
|
|
*
|
|
*/
|
|
|
|
|
|
bool_t InsertNode ()
|
|
{
|
|
return (FALSE);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/** RemoveIndir - Remove a level of indirection from a node
|
|
*
|
|
* RemoveIndir (pv)
|
|
*
|
|
* Entry pv = pointer to value
|
|
*
|
|
* Exit
|
|
*
|
|
* Returns none
|
|
*
|
|
* DESCRIPTION
|
|
* Strips a level of indirection from a node's type; thus (char **)
|
|
* becomes (char *), and (char *) becomes (char).
|
|
*/
|
|
|
|
|
|
void RemoveIndir (peval_t pv)
|
|
{
|
|
CV_typ_t typ;
|
|
|
|
// Initialization, error checking. Find the base type of the
|
|
// pointer type.
|
|
|
|
DASSERT (EVAL_IS_PTR (pv));
|
|
|
|
// Since we are removing a level of indirection on the pointer, the
|
|
// value can no longer be in a register so we clear the flag indicating
|
|
// the value is in a register
|
|
|
|
EVAL_IS_REG (pv) = FALSE;
|
|
|
|
// Set the type of the node to the underlying type
|
|
|
|
if (CV_IS_PRIMITIVE (EVAL_TYP (pv))) {
|
|
switch (EVAL_TYP (pv)) {
|
|
case T_NCVPTR:
|
|
typ = PTR_UTYPE (pv);
|
|
break;
|
|
|
|
case T_FCVPTR:
|
|
case T_HCVPTR:
|
|
EVAL_SYM_SEG (pv) = EVAL_PTR_SEG (pv);
|
|
typ = PTR_UTYPE (pv);
|
|
break;
|
|
|
|
default:
|
|
typ = CV_NEWMODE (EVAL_TYP (pv), CV_TM_DIRECT);
|
|
break;
|
|
}
|
|
}
|
|
else if (EVAL_IS_ARRAY (pv)) {
|
|
typ = PTR_UTYPE (pv);
|
|
}
|
|
else if (EVAL_IS_PTR (pv)) {
|
|
typ = PTR_UTYPE (pv);
|
|
if (EVAL_PTRTYPE (pv) != CV_PTR_NEAR) {
|
|
EVAL_SYM_SEG (pv) = EVAL_PTR_SEG (pv);
|
|
}
|
|
}
|
|
else {
|
|
DASSERT (FALSE);
|
|
return;
|
|
}
|
|
SetNodeType (pv, typ);
|
|
}
|
|
|
|
|
|
__inline HTYPE
|
|
GetHTypeFromTindex (
|
|
neval_t nv,
|
|
CV_typ_t type
|
|
)
|
|
{
|
|
N_EVAL_TYPDEF (nv) = THGetTypeFromIndex (N_EVAL_MOD (nv), type);
|
|
// DASSERT (N_EVAL_TYPDEF (nv) != 0);
|
|
return (N_EVAL_TYPDEF (nv));
|
|
}
|
|
|
|
|
|
|
|
/*** SetNodeType - set node flags for a type index
|
|
*
|
|
* fSuccess = SetNodeType (pv, type)
|
|
*
|
|
* Entry pv = pointer to value
|
|
* type = type index
|
|
*
|
|
* Exit EVAL_TYPDEF (pv) = handle to typedef record if not primitive
|
|
* pv->flags set for type
|
|
* pv->data set for type
|
|
*
|
|
* Returns TRUE if type flags set
|
|
* FALSE if not (invalid type)
|
|
*/
|
|
|
|
eval_t evalN;
|
|
neval_t nv = &evalN;
|
|
|
|
bool_t SetNodeType (peval_t pv, CV_typ_t type)
|
|
{
|
|
plfEasy pType;
|
|
uint skip;
|
|
bool_t retflag = TRUE;
|
|
HTYPE hType;
|
|
CV_typ_t oldType;
|
|
CV_call_e call;
|
|
CV_modifier_t cvol;
|
|
CV_ptrmode_e mode;
|
|
SYMPTR pSym;
|
|
static uchar cvptr[5] = {CV_PTR_NEAR, CV_PTR_FAR, CV_PTR_HUGE, CV_PTR_NEAR32, CV_PTR_FAR32};
|
|
search_t Name;
|
|
psearch_t pName = &Name;
|
|
eval_t eval, savedeval;
|
|
peval_t lpv = &eval;
|
|
peval_t lpsaved = &savedeval;
|
|
ushort iregSav;
|
|
bool_t hibyteSav;
|
|
|
|
// save static data on stack because of possible
|
|
// recursion while calling SearchSym
|
|
|
|
*lpsaved = *nv;
|
|
|
|
// copy the node to near memory to save code space
|
|
|
|
*nv = *pv;
|
|
N_CLEAR_EVAL_FLAGS (nv);
|
|
if (EVAL_IS_REG (pv)) {
|
|
// an enregistered primitive
|
|
N_EVAL_IS_REG (nv) = TRUE;
|
|
// save register information before clearing data
|
|
iregSav = EVAL_REG(pv);
|
|
hibyteSav = EVAL_IS_HIBYTE (pv);
|
|
}
|
|
else if (EVAL_IS_BPREL (pv)) {
|
|
N_EVAL_IS_BPREL (nv) = TRUE;
|
|
}
|
|
else if (EVAL_IS_LABEL (pv)) { // CUDA #4067: must preserve islabel bit
|
|
N_EVAL_IS_LABEL (nv) = TRUE;
|
|
}
|
|
else if (EVAL_IS_REGREL (pv)) {
|
|
N_EVAL_IS_REGREL (nv) = TRUE;
|
|
}
|
|
else if (EVAL_IS_TLSREL( pv )) {
|
|
N_EVAL_IS_TLSREL (nv) = TRUE;
|
|
}
|
|
|
|
modifier:
|
|
|
|
oldType = N_EVAL_TYP (nv);
|
|
N_EVAL_TYP (nv) = type;
|
|
if (!CV_IS_PRIMITIVE (type)) {
|
|
DASSERT (N_EVAL_MOD (nv) != 0);
|
|
if ((hType = GetHTypeFromTindex (nv, type)) == 0) {
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
// from this point, it is assumed that a value of FALSE is zero and
|
|
// the memset of the node set all bit values to FALSE
|
|
|
|
if (CV_IS_INTERNAL_PTR (type)) {
|
|
// we are creating a special pointer to class type
|
|
|
|
if (oldType == T_NOTYPE) {
|
|
DASSERT (FALSE);
|
|
return (FALSE);
|
|
}
|
|
N_EVAL_IS_ADDR (nv) = TRUE;
|
|
N_EVAL_IS_PTR (nv) = TRUE;
|
|
N_EVAL_IS_DPTR (nv) = TRUE;
|
|
// N_EVAL_IS_CONST (nv) = FALSE;
|
|
// N_EVAL_IS_VOLATILE (nv) = FALSE;
|
|
// N_EVAL_IS_REF (nv) = FALSE;
|
|
N_PTR_UTYPE (nv) = oldType;
|
|
|
|
// The following code assumes that the ordering of the
|
|
// pointer modes is the same as the ordering of the CV created
|
|
// pointer types
|
|
|
|
N_EVAL_PTRTYPE (nv) = cvptr[CV_MODE (type) - CV_TM_NPTR];
|
|
}
|
|
else if (CV_IS_PRIMITIVE (type)) {
|
|
|
|
// If the type is primitive then it must reference data
|
|
|
|
N_EVAL_IS_DATA (nv) = TRUE;
|
|
N_EVAL_IS_DPTR (nv) = TRUE;
|
|
|
|
if (CV_TYP_IS_PTR (type)) {
|
|
|
|
// can't cast from 32 bit ptr to a 16 or vice versa
|
|
|
|
if ( EVAL_IS_PTR (pv) ) {
|
|
if (EVAL_PTRTYPE(pv) == CV_PTR_NEAR32 ||
|
|
EVAL_PTRTYPE(pv) == CV_PTR_FAR32) {
|
|
if (CV_MODE (type) < CV_TM_NPTR32) {
|
|
return (FALSE);
|
|
}
|
|
}
|
|
else {
|
|
if (CV_MODE (type) >= CV_TM_NPTR32) {
|
|
return (FALSE);
|
|
}
|
|
}
|
|
}
|
|
else if (EVAL_IS_REG (nv) ) {
|
|
|
|
// At this point, the data union believes that this is a REG
|
|
// This code converts it to be a pointer
|
|
|
|
eval_t nvCopy;
|
|
nvCopy = *nv;
|
|
|
|
//
|
|
// Clear out the register fields
|
|
//
|
|
N_EVAL_REG (nv) = 0;
|
|
|
|
//
|
|
// Set up the pointer fields
|
|
//
|
|
|
|
N_PTR_REG_IREG (nv) = N_EVAL_REG (&nvCopy);
|
|
N_PTR_REG_HIBYTE (nv) = EVAL_IS_HIBYTE (&nvCopy);
|
|
}
|
|
N_EVAL_IS_PTR (nv) = TRUE;
|
|
N_EVAL_IS_ADDR (nv) = TRUE;
|
|
|
|
// The following code assumes that the ordering of the
|
|
// pointer modes is the same as the ordering of the CV created
|
|
// pointer types
|
|
|
|
N_EVAL_PTRTYPE (nv) = cvptr[CV_MODE (type) - CV_TM_NPTR];
|
|
N_PTR_UTYPE (nv) = CV_NEWMODE(type, CV_TM_DIRECT);
|
|
}
|
|
}
|
|
else {
|
|
memset (&nv->data, 0, sizeof (nv->data));
|
|
pType = (plfEasy)(&((TYPPTR)(MHOmfLock (hType)))->leaf);
|
|
switch (pType->leaf) {
|
|
case LF_NULL:
|
|
break;
|
|
|
|
case LF_CLASS:
|
|
case LF_STRUCTURE:
|
|
if (((plfClass)pType)->property.fwdref) {
|
|
skip = offsetof (lfClass, data);
|
|
RNumLeaf (((char *)(&pType->leaf)) + skip, &skip);
|
|
// forward ref - look for the definition of the UDT
|
|
if ((type = GetUdtDefnTindex (type, nv, ((char *)&(pType->leaf)) + skip)) == T_NOTYPE) {
|
|
retflag = FALSE;
|
|
break;
|
|
}
|
|
MHOmfUnLock (hType);
|
|
if ((hType = GetHTypeFromTindex (nv, type)) == 0) {
|
|
retflag = FALSE;
|
|
break;
|
|
}
|
|
pType = (plfEasy)(&((TYPPTR)(MHOmfLock (hType)))->leaf);
|
|
N_EVAL_TYP (nv) = type;
|
|
}
|
|
if (((plfClass)pType)->property.fwdref) {
|
|
retflag = FALSE;
|
|
break;
|
|
}
|
|
N_EVAL_IS_DATA (nv) = TRUE;
|
|
N_EVAL_IS_CLASS (nv) = TRUE;
|
|
N_CLASS_COUNT (nv) = ((plfClass)pType)->count;
|
|
N_CLASS_FIELD (nv) = ((plfClass)pType)->field;
|
|
N_CLASS_DERIVE (nv) = ((plfClass)pType)->derived;
|
|
N_CLASS_VTSHAPE (nv) = ((plfClass)pType)->vshape;
|
|
N_CLASS_PROP (nv) = ((plfClass)pType)->property;
|
|
skip = offsetof (lfClass, data[0]);
|
|
N_CLASS_LEN (nv) = (ushort)RNumLeaf (((char *)(&pType->leaf)) + skip, &skip);
|
|
break;
|
|
|
|
case LF_UNION:
|
|
if (((plfUnion)pType)->property.fwdref) {
|
|
skip = offsetof (lfUnion, data);
|
|
RNumLeaf (((char *)(&pType->leaf)) + skip, &skip);
|
|
// forward ref - look for the definition of the UDT
|
|
if ((type = GetUdtDefnTindex (type, nv, ((char *)&(pType->leaf)) + skip)) == T_NOTYPE) {
|
|
retflag = FALSE;
|
|
break;
|
|
}
|
|
MHOmfUnLock (hType);
|
|
if ((hType = GetHTypeFromTindex (nv, type)) == 0) {
|
|
retflag = FALSE;
|
|
break;
|
|
}
|
|
pType = (plfEasy)(&((TYPPTR)(MHOmfLock (hType)))->leaf);
|
|
N_EVAL_TYP (nv) = type;
|
|
}
|
|
if (((plfUnion)pType)->property.fwdref) {
|
|
retflag = FALSE;
|
|
break;
|
|
}
|
|
N_EVAL_IS_DATA (nv) = TRUE;
|
|
N_EVAL_IS_CLASS (nv) = TRUE;
|
|
N_CLASS_COUNT (nv) = ((plfUnion)pType)->count;
|
|
N_CLASS_FIELD (nv) = ((plfUnion)pType)->field;
|
|
N_CLASS_PROP (nv) = ((plfClass)pType)->property;
|
|
skip = offsetof (lfUnion, data[0]);
|
|
N_CLASS_LEN (nv) = (ushort)RNumLeaf (((char *)(&pType->leaf)) + skip, &skip);
|
|
break;
|
|
|
|
case LF_ENUM:
|
|
if (((plfEnum)pType)->property.fwdref) {
|
|
// forward ref - look for the definition of the UDT
|
|
if ((type = GetUdtDefnTindex (type, nv, (char *)&(((plfEnum)pType)->Name[0]))) == T_NOTYPE) {
|
|
retflag = FALSE;
|
|
break;
|
|
}
|
|
MHOmfUnLock (hType);
|
|
if ((hType = GetHTypeFromTindex (nv, type)) == 0) {
|
|
retflag = FALSE;
|
|
break;
|
|
}
|
|
pType = (plfEasy)(&((TYPPTR)(MHOmfLock (hType)))->leaf);
|
|
N_EVAL_TYP (nv) = type;
|
|
}
|
|
if (((plfEnum)pType)->property.fwdref) {
|
|
retflag = FALSE;
|
|
break;
|
|
}
|
|
N_EVAL_IS_ENUM (nv) = TRUE;
|
|
N_ENUM_COUNT (nv) = ((plfEnum)pType)->count;
|
|
N_ENUM_FIELD (nv) = ((plfEnum)pType)->field;
|
|
N_ENUM_UTYPE (nv) = ((plfEnum)pType)->utype;
|
|
N_ENUM_PROP (nv) = ((plfClass)pType)->property;
|
|
break;
|
|
|
|
|
|
case LF_BITFIELD:
|
|
N_EVAL_IS_DATA (nv) = TRUE;
|
|
N_EVAL_IS_BITF (nv) = TRUE;
|
|
skip = 1;
|
|
|
|
// read number of bits in field
|
|
|
|
N_BITF_LEN (nv) = ((plfBitfield)pType)->length;
|
|
N_BITF_POS (nv) = ((plfBitfield)pType)->position;
|
|
N_BITF_UTYPE (nv) = ((plfBitfield)pType)->type;
|
|
skip = sizeof (lfBitfield);
|
|
break;
|
|
|
|
|
|
case LF_POINTER:
|
|
if (EVAL_IS_REG (pv)) {
|
|
// an en-registered pointer
|
|
N_PTR_REG_IREG (nv) = EVAL_REG (pv);
|
|
N_PTR_REG_HIBYTE (nv) = EVAL_IS_HIBYTE (pv);
|
|
}
|
|
N_EVAL_IS_ADDR (nv) = TRUE;
|
|
N_EVAL_IS_PTR (nv) = TRUE;
|
|
N_EVAL_IS_CONST (nv) = ((plfPointer)pType)->attr.isconst;
|
|
N_EVAL_IS_VOLATILE (nv) = ((plfPointer)pType)->attr.isvolatile;
|
|
mode = ((plfPointer)pType)->attr.ptrmode;
|
|
N_PTR_UTYPE (nv) = ((plfPointer)&(pType->leaf))->utype;
|
|
if (!CV_IS_PRIMITIVE (N_PTR_UTYPE (nv))) {
|
|
// Avoid leaving unresolved forward references in the
|
|
// evaluation node, in order to work around context-related
|
|
// problems. Resolving a fwd ref requires a symbol search
|
|
// and the appropriate context may be unavailable at a later
|
|
// time.
|
|
CV_typ_t newindex;
|
|
if (getDefnFromDecl(N_PTR_UTYPE (nv), nv, &newindex)) {
|
|
N_PTR_UTYPE (nv) = newindex;
|
|
}
|
|
}
|
|
switch (N_EVAL_PTRTYPE (nv) = ((plfPointer)pType)->attr.ptrmode) {
|
|
case CV_PTR_MODE_PTR:
|
|
break;
|
|
|
|
case CV_PTR_MODE_REF:
|
|
N_EVAL_IS_REF (nv) = TRUE;
|
|
break;
|
|
|
|
case CV_PTR_MODE_PMEM:
|
|
N_EVAL_IS_PMEMBER (nv) = TRUE;
|
|
N_PTR_PMCLASS (nv) = ((plfPointer)pType)->pbase.pm.pmclass;
|
|
N_PTR_PMENUM (nv) = ((plfPointer)pType)->pbase.pm.pmenum;
|
|
break;
|
|
|
|
case CV_PTR_MODE_PMFUNC:
|
|
N_EVAL_IS_PMETHOD (nv) = TRUE;
|
|
N_PTR_PMCLASS (nv) = ((plfPointer)pType)->pbase.pm.pmclass;
|
|
N_PTR_PMENUM (nv) = ((plfPointer)pType)->pbase.pm.pmenum;
|
|
break;
|
|
|
|
default:
|
|
pExState->err_num = ERR_BADOMF;
|
|
retflag = FALSE;
|
|
break;
|
|
}
|
|
switch (N_EVAL_PTRTYPE (nv) = ((plfPointer)pType)->attr.ptrtype) {
|
|
case CV_PTR_NEAR32:
|
|
case CV_PTR_FAR32:
|
|
// can't cast from 32 bit ptr to a 16 or vice versa
|
|
if (EVAL_IS_PTR (pv) &&
|
|
(EVAL_PTRTYPE(pv) != CV_PTR_NEAR32) &&
|
|
(EVAL_PTRTYPE(pv) != CV_PTR_FAR32)
|
|
) {
|
|
retflag = FALSE;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
if (EVAL_IS_PTR (pv) &&
|
|
((EVAL_PTRTYPE(pv) == CV_PTR_NEAR32) ||
|
|
(EVAL_PTRTYPE(pv) == CV_PTR_FAR32))
|
|
) {
|
|
retflag = FALSE;
|
|
break;
|
|
}
|
|
|
|
switch (N_EVAL_PTRTYPE (nv)) {
|
|
case CV_PTR_BASE_SEG:
|
|
// based on a segment. Use the segment value from the leaf
|
|
N_PTR_BSEG (nv) = ((plfPointer)pType)->pbase.bseg;
|
|
break;
|
|
|
|
case CV_PTR_BASE_VAL:
|
|
case CV_PTR_BASE_SEGVAL:
|
|
case CV_PTR_BASE_ADDR:
|
|
case CV_PTR_BASE_SEGADDR:
|
|
// We need to do an extra symbol search to find
|
|
// the symbol on which the pointer is based.
|
|
// The copy of the symbol record in the type
|
|
// section is not good. We need to do the
|
|
// extra search even if the base is bp-relative
|
|
// The compiler no longer sets the correct offset
|
|
// in copy of the symbol record found in the type
|
|
// section.
|
|
|
|
memset (pName, 0, sizeof (*pName));
|
|
|
|
// initialize search_t struct
|
|
// M00KLUDGE: We use the context stored
|
|
// in the TM during the bind phase. This
|
|
// does not work properly If the actual
|
|
// base is shadowed by a local variable
|
|
|
|
pName->pfnCmp = (PFNCMP) FNCMP;
|
|
pName->pv = (peval_t) nv;
|
|
pName->scope = SCP_lexical | SCP_module | SCP_global;
|
|
pName->clsmask = 0;
|
|
pName->CXTT = *pCxt;
|
|
pName->bn = 0;
|
|
pName->bnOp = 0;
|
|
pName->state = SYM_init;
|
|
|
|
pSym = (SYMPTR)(&((plfPointer)pType)->pbase.Sym);
|
|
N_PTR_BSYMTYPE (nv) = pSym->rectyp;
|
|
emiAddr (N_PTR_ADDR (nv)) = pCxt->addr.emi;
|
|
|
|
if (SearchBasePtrBase(pName) != HR_found) {
|
|
pExState->err_num = ERR_NOTEVALUATABLE;
|
|
return FALSE;
|
|
}
|
|
|
|
case CV_PTR_BASE_TYPE:
|
|
N_PTR_BTYPE (nv) = ((plfPointer)pType)->pbase.btype.index;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
SetDPtr (nv, &hType);
|
|
break;
|
|
|
|
case LF_ARRAY:
|
|
// The CodeView information doesn't tell us whether arrays
|
|
// are near or far, so we always make them far.
|
|
|
|
if (EVAL_IS_REG (pv)) {
|
|
// an en-registered pointer
|
|
N_PTR_REG_IREG (nv) = EVAL_REG (pv);
|
|
N_PTR_REG_HIBYTE (nv) = EVAL_IS_HIBYTE (pv);
|
|
}
|
|
N_EVAL_IS_DATA (nv) = TRUE;
|
|
N_EVAL_IS_ADDR (nv) = TRUE;
|
|
N_EVAL_IS_PTR (nv) = TRUE;
|
|
N_EVAL_IS_ARRAY (nv) = TRUE;
|
|
N_EVAL_PTRTYPE (nv) = ADDR_IS_OFF32(*SHpADDRFrompCXT(pCxt)) ? CV_PTR_NEAR32 : CV_PTR_FAR;
|
|
N_PTR_UTYPE (nv) = ((plfArray)pType)->elemtype;
|
|
if (!CV_IS_PRIMITIVE (N_PTR_UTYPE (nv))) {
|
|
// Avoid leaving unresolved forward references in the
|
|
// evaluation node, in order to work around context-related
|
|
// problems. Resolving a fwd ref requires a symbol search
|
|
// and the appropriate context may be unavailable at a later
|
|
// time.
|
|
CV_typ_t newindex;
|
|
if (getDefnFromDecl(N_PTR_UTYPE (nv), nv, &newindex)) {
|
|
N_PTR_UTYPE (nv) = newindex;
|
|
}
|
|
}
|
|
skip = offsetof (lfArray, data[0]);
|
|
N_PTR_ARRAYLEN (nv) = RNumLeaf (((char *)(&pType->leaf)) + skip, &skip);
|
|
break;
|
|
|
|
case LF_PROCEDURE:
|
|
N_EVAL_IS_ADDR (nv) = TRUE;
|
|
N_EVAL_IS_FCN (nv) = TRUE;
|
|
N_FCN_RETURN (nv) = ((plfProc)pType)->rvtype;
|
|
if (N_FCN_RETURN (nv) == 0) {
|
|
N_FCN_RETURN (nv) = T_VOID;
|
|
}
|
|
call = ((plfProc)pType)->calltype;
|
|
N_FCN_PCOUNT (nv) = ((plfProc)pType)->parmcount;
|
|
N_FCN_PINDEX (nv) = ((plfProc)pType)->arglist;
|
|
skip = sizeof (lfProc);
|
|
CheckFcnArgs (nv, &hType, call);
|
|
break;
|
|
|
|
case LF_MFUNCTION:
|
|
N_EVAL_IS_ADDR (nv) = TRUE;
|
|
N_EVAL_IS_FCN (nv) = TRUE;
|
|
N_EVAL_IS_METHOD (nv) = TRUE;
|
|
N_FCN_CLASS (nv) = ((plfMFunc)pType)->classtype;
|
|
N_FCN_THIS (nv) = ((plfMFunc)pType)->thistype;
|
|
N_FCN_RETURN (nv) = ((plfMFunc)pType)->rvtype;
|
|
if (N_FCN_RETURN (nv) == 0) {
|
|
N_FCN_RETURN (nv) = T_VOID;
|
|
}
|
|
call = ((plfMFunc)pType)->calltype;
|
|
N_FCN_PCOUNT (nv) = ((plfMFunc)pType)->parmcount;
|
|
N_FCN_PINDEX (nv) = ((plfMFunc)pType)->arglist;
|
|
N_FCN_THISADJUST (nv) = ((plfMFunc)pType)->thisadjust;
|
|
skip = sizeof (lfMFunc);
|
|
CheckFcnArgs (nv, &hType, call);
|
|
break;
|
|
|
|
case LF_MODIFIER:
|
|
cvol = ((plfModifier)pType)->attr;
|
|
type = ((plfModifier)pType)->type;
|
|
MHOmfUnLock (hType);
|
|
hType = 0;
|
|
if (cvol.MOD_const == TRUE) {
|
|
N_EVAL_IS_CONST (nv) = TRUE;
|
|
}
|
|
else if (cvol.MOD_volatile == TRUE){
|
|
N_EVAL_IS_VOLATILE (nv) = TRUE;
|
|
}
|
|
goto modifier;
|
|
|
|
case LF_VTSHAPE:
|
|
N_EVAL_IS_VTSHAPE (nv) = TRUE;
|
|
N_VTSHAPE_COUNT (nv) = ((plfVTShape)pType)->count;
|
|
break;
|
|
|
|
case LF_LABEL:
|
|
N_EVAL_IS_LABEL (nv) = TRUE;
|
|
break;
|
|
|
|
default:
|
|
pExState->err_num = ERR_BADOMF;
|
|
retflag = FALSE;
|
|
break;
|
|
}
|
|
if (hType != 0) {
|
|
MHOmfUnLock (hType);
|
|
}
|
|
}
|
|
|
|
if (EVAL_IS_REG (nv) && EVAL_IS_PTR (nv)) {
|
|
// an enregistered pointer
|
|
// restore register information
|
|
N_PTR_REG_IREG (nv) = iregSav;
|
|
N_PTR_REG_HIBYTE (nv) = hibyteSav;
|
|
}
|
|
|
|
*pv = *nv;
|
|
*nv = *lpsaved;
|
|
return (retflag);
|
|
}
|
|
|
|
|
|
|
|
|
|
/** CheckFcnArgs - check for function arguments
|
|
*
|
|
* CheckVarArgs (nv, phType, call, pcParam);
|
|
*
|
|
* Entry nv = near pointer to value node
|
|
* phType = pointer to type handle
|
|
* call = calling convention
|
|
* pcParam = pointer to paramater count
|
|
*
|
|
* Exit N_FCN_VARARGS (nv) = TRUE if varargs
|
|
*
|
|
* Returns none
|
|
*/
|
|
|
|
|
|
LOCAL void
|
|
CheckFcnArgs (
|
|
neval_t nv,
|
|
HTYPE *phType,
|
|
CV_call_e call
|
|
)
|
|
{
|
|
plfArgList pType;
|
|
ushort skip = 0;
|
|
|
|
switch(call) {
|
|
|
|
case CV_CALL_NEAR_C:
|
|
|
|
//near C call - caller pops stack
|
|
N_FCN_CALL (nv) = FCN_C;
|
|
// N_FCN_FARCALL (nv) = FALSE;
|
|
N_FCN_CALLERPOP (nv) = TRUE;
|
|
break;
|
|
|
|
case CV_CALL_FAR_C:
|
|
// far C call - caller pops stack
|
|
N_FCN_CALL (nv) = FCN_C;
|
|
N_FCN_FARCALL (nv) = TRUE;
|
|
N_FCN_CALLERPOP (nv) = TRUE;
|
|
break;
|
|
|
|
case CV_CALL_NEAR_PASCAL:
|
|
// near pascal call - callee pops stack
|
|
N_FCN_CALL (nv) = FCN_PASCAL;
|
|
// N_FCN_FARCALL (nv) = FALSE;
|
|
// N_FCN_CALLERPOP (nv) = FALSE;
|
|
break;
|
|
|
|
case CV_CALL_FAR_PASCAL:
|
|
// far pascal call - callee pops stack
|
|
N_FCN_CALL (nv) = FCN_PASCAL;
|
|
N_FCN_FARCALL (nv) = TRUE;
|
|
// N_FCN_CALLERPOP (nv) = FALSE;
|
|
break;
|
|
|
|
case CV_CALL_NEAR_FAST:
|
|
// near fast call - callee pops stack
|
|
N_FCN_CALL (nv) = FCN_FAST;
|
|
// N_FCN_FARCALL (nv) = FALSE;
|
|
// N_FCN_CALLERPOP (nv) = FALSE;
|
|
break;
|
|
|
|
case CV_CALL_FAR_FAST:
|
|
// far fast call - callee pops stack
|
|
N_FCN_CALL (nv) = FCN_FAST;
|
|
N_FCN_FARCALL (nv) = TRUE;
|
|
// N_FCN_CALLERPOP (nv) = FALSE;
|
|
break;
|
|
|
|
case CV_CALL_NEAR_STD:
|
|
// near standard call - callee pops stack
|
|
N_FCN_CALL (nv) = FCN_STD;
|
|
// N_FCN_FARCALL (nv) = FALSE;
|
|
// N_FCN_CALLERPOP (nv) = FALSE;
|
|
break;
|
|
|
|
case CV_CALL_FAR_STD:
|
|
// far fast call - callee pops stack
|
|
N_FCN_CALL (nv) = FCN_STD;
|
|
N_FCN_FARCALL (nv) = TRUE;
|
|
// N_FCN_CALLERPOP (nv) = FALSE;
|
|
break;
|
|
|
|
case CV_CALL_PPCCALL:
|
|
N_FCN_CALL (nv) = FCN_PPC;
|
|
break;
|
|
|
|
case CV_CALL_MIPSCALL:
|
|
N_FCN_CALL (nv) = FCN_MIPS;
|
|
break;
|
|
|
|
case CV_CALL_ALPHACALL:
|
|
N_FCN_CALL (nv) = FCN_ALPHA;
|
|
break;
|
|
|
|
case CV_CALL_THISCALL:
|
|
N_FCN_CALL (nv) = FCN_THIS;
|
|
break;
|
|
|
|
case CV_CALL_GENERIC:
|
|
#ifdef ALPHA
|
|
//
|
|
// MBH -bugbug
|
|
// This is here because CV_CALL_ALPHACALL has changed values in
|
|
// cvinfo.h, but no in the front end yet.
|
|
//
|
|
CheckFcnArgs (nv, phType, CV_CALL_ALPHACALL);
|
|
return;
|
|
#endif
|
|
//
|
|
// otherwise, deliberately fall through
|
|
//
|
|
|
|
default:
|
|
// unknown function
|
|
DASSERT (FALSE);
|
|
N_FCN_CALL (nv) = 0;
|
|
// N_FCN_FARCALL (nv) = FALSE;
|
|
// N_FCN_CALLERPOP (nv) = FALSE;
|
|
break;
|
|
|
|
}
|
|
|
|
//M00KLUDGE - this check is to avoid a cvpack problem to be fixed
|
|
if (N_FCN_PINDEX (nv) == 0) {
|
|
return;
|
|
}
|
|
|
|
if ((N_FCN_CALL (nv) != FCN_C) &&
|
|
(N_FCN_CALL (nv) != FCN_PPC) &&
|
|
(N_FCN_CALL (nv) != FCN_MIPS) &&
|
|
(N_FCN_CALL (nv) != FCN_ALPHA) &&
|
|
(FCN_PINDEX (nv) == T_VOID)) {
|
|
return;
|
|
}
|
|
|
|
MHOmfUnLock (*phType);
|
|
*phType = THGetTypeFromIndex (EVAL_MOD (nv), N_FCN_PINDEX (nv));
|
|
DASSERT (*phType != 0);
|
|
if (*phType == 0) {
|
|
return;
|
|
}
|
|
pType = (plfArgList)(&((TYPPTR)(MHOmfLock (*phType)))->leaf);
|
|
|
|
if (FCN_PCOUNT (nv) == 0) {
|
|
// there are no arguments. We need to check for old C
|
|
// style varargs and voidarg function calls. These are
|
|
// indicated by an argument count of zero and an
|
|
// argument type list which is a LF_EASY list.
|
|
|
|
if ((pType->count == 0) || (pType->arg[0] == T_NOTYPE)) {
|
|
// This is either void or no args. We cannot
|
|
// tell the difference so we set the varargs flag
|
|
N_FCN_VARARGS (nv) = TRUE;
|
|
}
|
|
}
|
|
else {
|
|
// There are formal parameters. Skip down the list to the last
|
|
// parameter and check for varargs
|
|
|
|
if (pType->arg[pType->count - 1] == T_NOTYPE) {
|
|
// the last argument has a type of zero which is the specification
|
|
// of varargs. Set the type to 0 to indicate vararg
|
|
N_FCN_VARARGS (nv) = TRUE;
|
|
}
|
|
else if (pType->arg[pType->count - 1] == LF_DEFARG) {
|
|
N_FCN_DEFARGS (nv) = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
/** SetDPtr - set data pointer flag
|
|
*
|
|
* SetDPtr (nv, phType)
|
|
*
|
|
* Entry nv = near pointer to value node
|
|
* phType = pointer to type handle
|
|
*
|
|
* Exit EVAL_IS_DPTR (nv) = TRUE if pointer to data
|
|
*
|
|
* Returns none
|
|
*/
|
|
|
|
|
|
LOCAL void SetDPtr (neval_t nv, HTYPE *phType)
|
|
{
|
|
if (!CV_IS_PRIMITIVE (N_PTR_UTYPE (nv))) {
|
|
MHOmfUnLock (*phType);
|
|
*phType = THGetTypeFromIndex (EVAL_MOD (nv), N_PTR_UTYPE (nv));
|
|
DASSERT(*phType != (HTYPE) NULL);
|
|
if (((plfEasy)(&((TYPPTR)(MHOmfLock (*phType)))->leaf))->leaf != LF_PROCEDURE) {
|
|
N_EVAL_IS_DPTR (nv) = TRUE;
|
|
}
|
|
}
|
|
else {
|
|
N_EVAL_IS_DPTR (nv) = TRUE;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
/*** LoadVal - Load the value of a node
|
|
*
|
|
* fSuccess = LoadVal (pv)
|
|
*
|
|
* Entry pv = pointer to value
|
|
*
|
|
* Exit EVAL_VAL (pv) = value
|
|
* EVAL_STATE (pv) = EV_rvalue
|
|
*
|
|
* Returns TRUE if value loaded
|
|
* FALSE if not (complex symbol type such as structure).
|
|
*
|
|
*/
|
|
|
|
|
|
bool_t LoadVal (peval_t pv)
|
|
{
|
|
DASSERT (EVAL_STATE (pv) == EV_lvalue);
|
|
|
|
if (LoadSymVal (pv)) {
|
|
EVAL_STATE (pv) = EV_rvalue;
|
|
return (TRUE);
|
|
}
|
|
return (FALSE);
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
* TypeSize
|
|
*
|
|
* Returns size in bytes of value on expression stack
|
|
*/
|
|
|
|
|
|
long TypeSize (peval_t pv)
|
|
{
|
|
if (CV_IS_PRIMITIVE (EVAL_TYP (pv))) {
|
|
// primitive type
|
|
return (TypeSizePrim (EVAL_TYP (pv)));
|
|
}
|
|
else {
|
|
// complex type
|
|
return (TypeDefSize (pv));
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* TypeDefSize
|
|
*
|
|
* Returns size in bytes of a non-primitive type.
|
|
*/
|
|
|
|
long TypeDefSize (peval_t pv)
|
|
{
|
|
long retval;
|
|
|
|
if (EVAL_IS_ARRAY (pv)) {
|
|
retval = PTR_ARRAYLEN (pv);
|
|
}
|
|
else if (EVAL_IS_PTR (pv)) {
|
|
switch (EVAL_PTRTYPE (pv)) {
|
|
case CV_PTR_FAR:
|
|
case CV_PTR_HUGE:
|
|
retval = 4;
|
|
break;
|
|
|
|
case CV_PTR_NEAR32:
|
|
retval = 4;
|
|
break;
|
|
|
|
case CV_PTR_FAR32:
|
|
retval = 6;
|
|
break;
|
|
|
|
default:
|
|
retval = 2;
|
|
}
|
|
}
|
|
else if (EVAL_IS_CLASS (pv)) {
|
|
retval = CLASS_LEN (pv);
|
|
}
|
|
else if (EVAL_IS_FCN (pv)) {
|
|
if (pv->data.fcn.flags.farcall == TRUE) {
|
|
retval = 4;
|
|
}
|
|
else {
|
|
retval = sizeof (UOFFSET);
|
|
}
|
|
}
|
|
else if (EVAL_IS_BITF (pv)) {
|
|
switch (BITF_UTYPE (pv)) {
|
|
case T_SHORT:
|
|
case T_USHORT:
|
|
retval = 2;
|
|
break;
|
|
|
|
case T_LONG:
|
|
case T_ULONG:
|
|
retval = 4;
|
|
break;
|
|
|
|
default:
|
|
pExState->err_num = ERR_BADOMF;
|
|
retval = 0;
|
|
break;
|
|
}
|
|
}
|
|
else {
|
|
retval = 0;
|
|
}
|
|
return (retval);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** TypeSizePrim - return size of primitive type
|
|
*
|
|
* len = TypeSizePrim (type)
|
|
*
|
|
* Entry type = primitive type index
|
|
*
|
|
* Exit none
|
|
*
|
|
* Returns size in byte of primitive type
|
|
*/
|
|
|
|
|
|
int TypeSizePrim (CV_typ_t itype)
|
|
{
|
|
if (itype == T_NOTYPE) {
|
|
/*
|
|
* we need to have a assert here but we cannot because a
|
|
* pointer to function can (will) have a null argumtent list
|
|
* which makes it look like a varargs which means all bets are off
|
|
*/
|
|
if (ADDR_IS_OFF32(*SHpADDRFrompCXT(pCxt))) {
|
|
return (sizeof (ULONG));
|
|
} else {
|
|
return sizeof(USHORT);
|
|
}
|
|
}
|
|
else if (CV_MODE (itype) != CV_TM_DIRECT) {
|
|
return (size_ptr [CV_MODE (itype)]);
|
|
}
|
|
else switch (CV_TYPE (itype)) {
|
|
case CV_SPECIAL:
|
|
return (size_special [CV_SUBT (itype)]);
|
|
|
|
case CV_SPECIAL2:
|
|
return (size_special2 [CV_SUBT (itype)]);
|
|
|
|
case CV_INT:
|
|
return (size_int [CV_SUBT (itype)]);
|
|
|
|
case CV_SIGNED:
|
|
case CV_UNSIGNED:
|
|
case CV_BOOLEAN:
|
|
return (size_integral [CV_SUBT (itype)]);
|
|
|
|
case CV_REAL:
|
|
return (size_real [CV_SUBT (itype)]);
|
|
|
|
case CV_COMPLEX:
|
|
default:
|
|
DASSERT (FALSE);
|
|
return (0);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** UpdateMem - update memory or register for assignment operation
|
|
*
|
|
* fSuccess = UpdateMem (pv);
|
|
*
|
|
* Entry pv = pointer to node containg update data
|
|
*
|
|
* Exit is_assign = TRUE to indicate memory changed
|
|
*
|
|
* Returns TRUE if memory updated without error
|
|
* FALSE if error during memory update
|
|
*/
|
|
|
|
|
|
bool_t UpdateMem (peval_t pv)
|
|
{
|
|
SHREG reg;
|
|
ushort cbVal;
|
|
ushort dummy[2];
|
|
ADDR addr;
|
|
|
|
is_assign = TRUE; /* Indicate assignment operation */
|
|
if (!EVAL_IS_REG (pv)) {
|
|
// destination is not a register
|
|
ResolveAddr( pv );
|
|
|
|
cbVal = (ushort)TypeSize (pv);
|
|
addr = EVAL_SYM (pv);
|
|
if (ADDR_IS_LI (addr)) {
|
|
SHFixupAddr (&addr);
|
|
}
|
|
if (EVAL_IS_PTR (pv) && (EVAL_IS_FPTR (pv) || EVAL_IS_HPTR (pv))) {
|
|
dummy[0] = (OFF16) EVAL_PTR_OFF (pv);
|
|
dummy[1] = EVAL_PTR_SEG (pv);
|
|
return (PutDebuggeeBytes (addr, cbVal, (char *)dummy, EVAL_TYP(pv)) == (UINT)cbVal);
|
|
}
|
|
else {
|
|
return (PutDebuggeeBytes (addr, cbVal, (char *)&EVAL_VAL (pv), EVAL_TYP(pv)) == (UINT)cbVal);
|
|
}
|
|
}
|
|
|
|
//
|
|
// It is in a register
|
|
//
|
|
|
|
reg.hReg = EVAL_REG (pv);
|
|
if (EVAL_IS_PTR(pv)) {
|
|
reg.hReg = PTR_REG_IREG(pv);
|
|
}
|
|
|
|
//
|
|
// Get the old register value; we copy in the number of bits
|
|
// for the current data type; allows multiple vars in one
|
|
// register should a compiler ever so desire.
|
|
//
|
|
|
|
if (GetReg (®, pCxt) == NULL) {
|
|
pExState->err_num = ERR_REGNOTAVAIL;
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Transfer the bytes from the eval_t to the register
|
|
//
|
|
|
|
|
|
if (CV_IS_PRIMITIVE ( EVAL_TYP (pv) ) ) {
|
|
|
|
//
|
|
// notenote: this is dependent on byte ordering.
|
|
// Won't work on a big-endian machine.
|
|
//
|
|
|
|
#if defined(TARGET_ALPHA) || defined(TARGET_PPC)
|
|
if ( EVAL_TYP(pv) == T_REAL32 ) {
|
|
//
|
|
// Can't do a memory copy here because the
|
|
// register subsystem assumes that the reg value
|
|
// is a double (the type of Byte8).
|
|
//
|
|
|
|
float f1;
|
|
double d1;
|
|
|
|
f1 = EVAL_FLOAT(pv);
|
|
d1 = f1;
|
|
*((ULONGLONG UNALIGNED *)®.Byte8) = *((PULONGLONG)&d1);
|
|
} else
|
|
#endif
|
|
{
|
|
cbVal = TypeSizePrim(EVAL_TYP (pv));
|
|
|
|
memcpy(®.Byte1, &EVAL_CHAR (pv), cbVal);
|
|
}
|
|
|
|
} else if (EVAL_IS_PTR (pv) ) {
|
|
|
|
//
|
|
// Handle pointers to UserDefinedTypes
|
|
// notenote - this isn't right for WOW,
|
|
// where pointers can be different lengths.
|
|
//
|
|
|
|
memcpy(®.Byte1, &EVAL_CHAR (pv), sizeof (long));
|
|
|
|
} else {
|
|
|
|
//
|
|
// Non-primitive types in registers not
|
|
// supported in first release
|
|
//
|
|
|
|
EVAL_LONG (pv) = 0;
|
|
DASSERT(FALSE);
|
|
}
|
|
|
|
if (SetReg (®, NULL) == NULL) {
|
|
pExState->err_num = ERR_REGNOTAVAIL;
|
|
return (FALSE);
|
|
}
|
|
|
|
if ((reg.hReg == CV_REG_CS) || (reg.hReg == CV_REG_IP)) {
|
|
// M00KLUDGE what do I do here?????
|
|
//fEnvirGbl.fAll &= mdUserPc; /* clear the user pc mask */
|
|
//UpdateUserEnvir (mUserPc); /* restore the user pc */
|
|
}
|
|
return (TRUE);
|
|
}
|
|
|
|
|
|
|
|
#if defined (M68K)
|
|
/** FlipBytes - reverse byte order (toggle big/little endian)
|
|
*
|
|
* FlipBytes (pval, type)
|
|
*
|
|
* Entry pval = pointer to byte stream to be reversed
|
|
* type = CV type index (Must be primitive, presently)
|
|
*
|
|
* Exit byte stream reversed
|
|
*
|
|
* Returns nothing
|
|
*/
|
|
void FlipBytes (uchar *pval, CV_typ_t type)
|
|
{
|
|
int cbSize;
|
|
uchar *pb, bT;
|
|
|
|
DASSERT(CV_IS_PRIMITIVE(type));
|
|
|
|
if (!CV_TYP_IS_REAL(type)) {
|
|
cbSize = TypeSizePrim(type);
|
|
pb = pval;
|
|
|
|
while (cbSize > 1) {
|
|
cbSize--;
|
|
|
|
bT = *pb;
|
|
*pb = *(pb+cbSize);
|
|
*(pb+cbSize) = bT;
|
|
|
|
pb++;
|
|
cbSize--;
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/** GetDebuggeeBytes
|
|
** PutDebuggeeBytes
|
|
** GetReg
|
|
** SetReg
|
|
*
|
|
* These routines are a layer for the DH...
|
|
* routines. For big-endian targets, (i.e. if
|
|
* M68K is defined,) they call the byte-flipping
|
|
* routine as neccesary. Parameters and returns
|
|
* are the same as the DH... routines, except
|
|
* DH___DebuggeeBytes, which take one extra parameter,
|
|
* the CV type of the data.
|
|
*
|
|
* This layer only exists for big-endian-target builds.
|
|
* (Presently, if M68K is defined.)
|
|
*/
|
|
UINT GetDebuggeeBytes (ADDR addr, UINT cb, void *pv, CV_typ_t type)
|
|
{
|
|
UINT retval;
|
|
|
|
retval = (*pCVF->pDHGetDebuggeeBytes)(addr, cb, pv);
|
|
FlipBytes((uchar *)pv, type);
|
|
|
|
return(retval);
|
|
}
|
|
|
|
UINT PutDebuggeeBytes (ADDR addr, UINT cb, void *pv, CV_typ_t type)
|
|
{
|
|
UINT retval;
|
|
|
|
FlipBytes((uchar *)pv, type);
|
|
retval = (*pCVF->pDHPutDebuggeeBytes)(addr, cb, pv);
|
|
FlipBytes((uchar *)pv, type);
|
|
|
|
return(retval);
|
|
}
|
|
|
|
PSHREG GetReg (PSHREG pshreg, PCXT pcxt)
|
|
{
|
|
PSHREG retval;
|
|
|
|
retval = (*pCVF->pDHGetReg)(pshreg, pcxt);
|
|
FlipBytes(&retval->Byte1, TypeFromHreg(retval->hReg));
|
|
|
|
return(retval);
|
|
}
|
|
|
|
PSHREG SetReg (PSHREG pshreg, PCXT pcxt)
|
|
{
|
|
PSHREG retval;
|
|
|
|
FlipBytes(&pshreg->Byte1, TypeFromHreg(pshreg->hReg));
|
|
retval = (*pCVF->pDHSetReg)(pshreg, pcxt);
|
|
FlipBytes(&retval->Byte1, TypeFromHreg(retval->hReg));
|
|
|
|
return(retval);
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
LOCAL __inline CV_prop_t
|
|
GetProperty(
|
|
CV_typ_t type,
|
|
neval_t nv)
|
|
{
|
|
HTYPE hType;
|
|
plfEasy pType;
|
|
CV_prop_t retval = {0};
|
|
|
|
if ((hType = GetHTypeFromTindex (nv, type)) == 0) {
|
|
DASSERT(FALSE);
|
|
return retval;
|
|
}
|
|
pType = (plfEasy)(&((TYPPTR)(MHOmfLock (hType)))->leaf);
|
|
|
|
switch (pType->leaf) {
|
|
case LF_CLASS:
|
|
case LF_STRUCTURE:
|
|
retval = ((plfClass)pType)->property;
|
|
break;
|
|
|
|
case LF_UNION:
|
|
retval = ((plfUnion)pType)->property;
|
|
break;
|
|
|
|
case LF_ENUM:
|
|
retval = ((plfEnum)pType)->property;
|
|
break;
|
|
|
|
default:
|
|
DASSERT(FALSE);
|
|
}
|
|
|
|
MHOmfUnLock(hType);
|
|
return retval;
|
|
}
|
|
|
|
CV_typ_t
|
|
GetUdtDefnTindex (
|
|
CV_typ_t TypeIn,
|
|
neval_t nv,
|
|
char *lpStr)
|
|
{
|
|
static BOOL fIn = FALSE;
|
|
search_t Name;
|
|
eval_t localEval = *nv;
|
|
CV_typ_t tiResult = T_NOTYPE;
|
|
CV_prop_t propIn, propSeek;
|
|
|
|
// recursion check
|
|
if (fIn)
|
|
return FALSE;
|
|
fIn = TRUE; // set recursion guard
|
|
|
|
EVAL_TYP (&localEval) = 0;
|
|
EVAL_ITOK (&localEval) = 0;
|
|
EVAL_CBTOK (&localEval) = 0;
|
|
|
|
memset (&Name, 0, sizeof (search_t));
|
|
Name.initializer = INIT_sym;
|
|
Name.pfnCmp = (PFNCMP) FNCMP;
|
|
Name.pv = &localEval;
|
|
// Look in all scopes except class scope: if we are in a member
|
|
// fn of the current class, this will lead to infinite recursion
|
|
// as we look for class X in the scope of class X in the ...
|
|
Name.scope = SCP_all & ~SCP_class;
|
|
Name.clsmask = CLS_enumerate | CLS_ntype;
|
|
Name.CXTT = *pCxt;
|
|
Name.bn = 0;
|
|
Name.bnOp = 0;
|
|
Name.sstr.lpName = (uchar *) lpStr + 1;
|
|
Name.sstr.cb = *lpStr;
|
|
Name.state = SYM_init;
|
|
|
|
// modify search to look only for UDTs
|
|
|
|
Name.sstr.searchmask = SSTR_symboltype;
|
|
Name.sstr.symtype = S_UDT;
|
|
|
|
propIn = GetProperty(TypeIn, nv);
|
|
|
|
while (SearchSym (&Name) == HR_found) {
|
|
PopStack ();
|
|
if (EVAL_STATE (&localEval) == EV_type) {
|
|
propSeek = GetProperty(EVAL_TYP(&localEval), &localEval);
|
|
if ((propIn.isnested == propSeek.isnested) &&
|
|
(propIn.scoped == propSeek.scoped)) {
|
|
tiResult = EVAL_TYP (&localEval);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
fIn = FALSE; // clear recursion guard
|
|
return tiResult;
|
|
}
|
|
|
|
/** GetHSYMCodeFromHSYM - Get HSYM encoded form from HSYM value
|
|
*
|
|
* lsz = GetHSYMFromHSYMCode (hSym)
|
|
*
|
|
* Entry hSm = hSym to be encoded
|
|
*
|
|
* Exit none
|
|
*
|
|
* Returns pointer to static buffer containing a string
|
|
* representation of hSym. The encoding is merely
|
|
* a conversion to a string that expresses the
|
|
* hSym value in hex notation.
|
|
*
|
|
*/
|
|
|
|
char *
|
|
GetHSYMCodeFromHSYM(
|
|
HSYM hSym)
|
|
{
|
|
static char buf[HSYM_CODE_LEN + 1];
|
|
sprintf(buf, "%08.08lx\0", (ulong)hSym);
|
|
return (char *)buf;
|
|
}
|
|
|
|
/** GetHSYMFromHSYMCode - Get HSYM from encoded HSYM string
|
|
*
|
|
* hSym = GetHSYMFromHSYMCode (lsz)
|
|
*
|
|
* Entry lsz = pointer to encoded HSYM string
|
|
*
|
|
* Exit none
|
|
*
|
|
* Returns hSym value
|
|
*/
|
|
|
|
HSYM
|
|
GetHSYMFromHSYMCode(
|
|
char *lsz)
|
|
{
|
|
unsigned long ul = 0;
|
|
char ch;
|
|
int digit;
|
|
int i;
|
|
for (i=0; i < HSYM_CODE_LEN; i++) {
|
|
DASSERT (isdigit (*lsz));
|
|
ch = *lsz++;
|
|
if (isdigit (ch))
|
|
digit = ch - '0';
|
|
else
|
|
digit = toupper(ch) - 'A' + 10;
|
|
ul <<= 4;
|
|
ul += digit;
|
|
}
|
|
return (HSYM) ul;
|
|
}
|
|
|
|
/** fCanSubtractPtrs - Check if ptrs can be subtracted
|
|
*
|
|
* flag = fCanSubtractPtrs (pvleft, pvright)
|
|
*
|
|
* Entry pvleft, pvRight = pointers to corresponding
|
|
* evaluation nodes.
|
|
*
|
|
* Exit none
|
|
*
|
|
* Returns TRUE if ptr subtraction is allowed for the
|
|
* corresponding pointer types.
|
|
*/
|
|
|
|
bool_t
|
|
fCanSubtractPtrs (
|
|
peval_t pvleft,
|
|
peval_t pvright)
|
|
{
|
|
bool_t retval = FALSE;
|
|
eval_t evalL;
|
|
eval_t evalR;
|
|
peval_t pvL = &evalL;
|
|
peval_t pvR = &evalR;
|
|
|
|
DASSERT (EVAL_IS_PTR (pvleft) && EVAL_IS_PTR (pvright));
|
|
DASSERT (!EVAL_IS_REF (pvleft) && !EVAL_IS_REF (pvright));
|
|
|
|
if (EVAL_TYP (pvleft) == EVAL_TYP (pvright)) {
|
|
retval = TRUE;
|
|
}
|
|
else if ( EVAL_PTRTYPE (pvleft) == EVAL_PTRTYPE (pvright) ) {
|
|
*pvL = *pvleft;
|
|
*pvR = *pvright;
|
|
|
|
// check the underlying types
|
|
// RemoveIndir will resolve fwd. references and
|
|
// skip modifier nodes.
|
|
RemoveIndir (pvL);
|
|
RemoveIndir (pvR);
|
|
|
|
retval = ( EVAL_TYP (pvL) == EVAL_TYP (pvR) );
|
|
}
|
|
|
|
return retval;
|
|
}
|
|
|
|
#if MEMDBG
|
|
|
|
#define MAX_MEM_ENTRIES 20000
|
|
|
|
typedef struct MEMORYINFO {
|
|
UINT addr;
|
|
UINT addr2;
|
|
UINT size;
|
|
UINT line;
|
|
CHAR tag[16];
|
|
CHAR file[16];
|
|
} MEMORYINFO, *LPMEMORYINFO;
|
|
|
|
LPMEMORYINFO mi;
|
|
UINT cmi;
|
|
|
|
|
|
VOID
|
|
LogMemoryInfo(
|
|
char *tag,
|
|
UINT addr,
|
|
UINT addr2,
|
|
UINT size,
|
|
char *file,
|
|
UINT line
|
|
)
|
|
{
|
|
CHAR buf[128];
|
|
CHAR fname[_MAX_FNAME];
|
|
CHAR ext[_MAX_EXT];
|
|
|
|
|
|
if (mi == NULL) {
|
|
mi = (LPMEMORYINFO)VirtualAlloc(
|
|
NULL,
|
|
sizeof(MEMORYINFO) * MAX_MEM_ENTRIES,
|
|
MEM_COMMIT,
|
|
PAGE_READWRITE );
|
|
if (mi == NULL) {
|
|
ExitProcess( 1 );
|
|
}
|
|
}
|
|
buf[0] = 0;
|
|
_splitpath( file, NULL, NULL, fname, ext );
|
|
sprintf( mi[cmi].file, "%s%s", fname, ext );
|
|
strcpy( mi[cmi].tag, tag );
|
|
mi[cmi].addr = addr;
|
|
mi[cmi].addr2 = addr2;
|
|
mi[cmi].size = size;
|
|
mi[cmi].line = line;
|
|
cmi++;
|
|
if (cmi == MAX_MEM_ENTRIES) {
|
|
cmi = 0;
|
|
}
|
|
}
|
|
|
|
|
|
HDEP
|
|
DbgMemAlloc(
|
|
UINT size,
|
|
char *file,
|
|
UINT line
|
|
)
|
|
{
|
|
HDEP hdep = (HDEP)(*pCVF->pMHMemAllocate)( size );
|
|
LogMemoryInfo( "alloc", (UINT)hdep, 0, size, file, line );
|
|
return hdep;
|
|
}
|
|
|
|
|
|
HDEP
|
|
DbgMemReAlloc(
|
|
HDEP hmem,
|
|
UINT size,
|
|
char *file,
|
|
UINT line
|
|
)
|
|
{
|
|
HDEP hdep = (HDEP)(*pCVF->pMHMemReAlloc)( hmem, size );
|
|
LogMemoryInfo( "realloc", (UINT)hmem, (UINT)hdep, size, file, line );
|
|
return hdep;
|
|
}
|
|
|
|
|
|
VOID
|
|
DbgMemFree(
|
|
HDEP hmem,
|
|
char *file,
|
|
UINT line
|
|
)
|
|
{
|
|
LogMemoryInfo( "free", (UINT)hmem, 0, 0, file, line );
|
|
(*pCVF->pMHMemFree)( hmem );
|
|
}
|
|
|
|
LPVOID
|
|
DbgMemLock(
|
|
HDEP hmem,
|
|
char *file,
|
|
UINT line
|
|
)
|
|
{
|
|
LPVOID lpv = (*pCVF->pMHMemLock)( hmem );
|
|
// LogMemoryInfo( "lock", (UINT)hmem, (UINT)lpv, 0, file, line );
|
|
return lpv;
|
|
}
|
|
|
|
VOID
|
|
DbgMemUnLock(
|
|
HDEP hmem,
|
|
char *file,
|
|
UINT line
|
|
)
|
|
{
|
|
// LogMemoryInfo( "unlock", (UINT)hmem, 0, 0, file, line );
|
|
(*pCVF->pMHMemUnLock)( hmem );
|
|
}
|
|
#endif
|