Windows2000/private/windbg64/debugger/ee/debsup.c
2020-09-30 17:12:32 +02:00

4771 lines
148 KiB
C

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