/***    debsup.c - debapi support routines.
 *
 *      The routines in this module can only be called from debapi.c.
 */




LOCAL EESTATUS CountClassElem (peval_t, long *, uint);
LOCAL ushort   SetClassiName (peval_t, long, PEEHSTR, PEEHSTR, uint, ushort, uint);
LOCAL ushort   SetFcniParm (peval_t, long, PEEHSTR);

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 = MHMemLock (hTMLeft);
        pExRight = MHMemLock (hTMRight);
        if (EVAL_TYP(&pExLeft->result) == EVAL_TYP (&pExRight->result)) {
            retval = TRUE;
        }
        MHMemUnLock (hTMLeft);
        MHMemUnLock (hTMRight);
    }
    return (retval);
}


/**     GetHtypeFromTM - Get the HTYPE of a TM result
 *
 *      hType = GetHtypeFromTM(hTM);
 *
 *      Entry   hTM = handle of TM
 *
 *      Exit    none
 *
 *      Returns the HTYPE of the result or 0
 */

HTYPE
GetHtypeFromTM(
    HTM hTM
    )
{
    HTYPE retval = 0;
    pexstate_t  pEx;

    if ( hTM != 0 ) {
        pEx = MHMemLock (hTM);
        retval = THGetTypeFromIndex (EVAL_MOD (&pEx->result),
                                                     EVAL_TYP (&pEx->result));
        MHMemUnLock (hTM);
    }
    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
 */


EESTATUS cChildrenTM (PHTM phTM, long *pcChildren, PSHFLAG pVar)
{
    EESTATUS    retval = EENOERROR;
    eval_t      eval;
    peval_t     pv = &eval;
    long        len;

    Unreferenced( pVar );


    DASSERT (*phTM != 0);
    *pcChildren = 0;
    if (*phTM == 0) {
        return (EECATASTROPHIC);
    }
    DASSERT(pExState == NULL );
    pExState = MHMemLock (*phTM);
    if (pExState->state.bind_ok == TRUE) {
        eval = pExState->result;
#if !defined (C_ONLY)
        if (EVAL_IS_REF (pv)) {
            RemoveIndir (pv);
        }
#endif
        pExState->err_num = 0;
        if (!CV_IS_PRIMITIVE (EVAL_TYP (pv))) {
            if (EVAL_IS_CLASS (pv)) {
                retval = CountClassElem (pv, pcChildren,
                 (EVAL_STATE (pv) == EV_type)? CLS_defn: CLS_data);
            }
            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.
                // Otherwise, the number of elements is the sizeof the
                // array divided by the size of the underlying type

                len = PTR_ARRAYLEN (pv);
                SetNodeType (pv, PTR_UTYPE (pv));
                *pcChildren = len / TypeSize (pv);
            }
            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 {
        pExState->err_num = ERR_NOTEVALUATABLE;
        retval = EEGENERAL;
    }
    MHMemUnLock (*phTM);
    pExState = NULL;
    return (retval);
}





/**     cParamTM - return count of parameters for TM
 *
 *      ushort 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
 */



ushort   cParamTM (HTM hTM, ushort *pcParam, PSHFLAG pVarArg)
{
    peval_t     pv;
    ushort      retval = EECATASTROPHIC;

    DASSERT (hTM != 0);
    if (hTM != 0) {
        DASSERT (pExState == NULL);
        pExState = MHMemLock (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);
                }
                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;
        }
        MHMemUnLock (hTM);
        pExState = NULL;
    }
    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
 */


ushort DupTM (PHTM phTMIn, PHTM phTMOut)
{
    ushort      retval = EENOMEMORY;
    pexstate_t  pExOut;
    char   *pStr;
    char   *pcName;
    uint        len;

    DASSERT (pExState == NULL);
    pExState = MHMemLock (*phTMIn);
    pExStr = MHMemLock (pExState->hExStr);
    pTree = MHMemLock (pExState->hSTree);
    if ((*phTMOut = MHMemAllocate (sizeof (exstate_t))) != 0) {
        pExOut = MHMemLock (*phTMOut);
        memset (pExOut, 0, sizeof (exstate_t));
        pExOut->ambiguous = pExState->ambiguous;
        pExOut->state.parse_ok = TRUE;

        // copy expression string

        if ((pExOut->hExStr = MHMemAllocate (pExOut->ExLen = pExState->ExLen)) == 0) {
            goto failure;
        }
        pStr = MHMemLock (pExOut->hExStr);
        memcpy (pStr, pExStr, pExOut->ExLen);
        MHMemUnLock (pExOut->hExStr);

        // copy syntax tree

        if ((pExOut->hSTree = MHMemAllocate (pTree->size)) == 0) {
            goto failure;
        }
        pStr = MHMemLock (pExOut->hSTree);
        memcpy (pStr, pTree, pTree->size);
        MHMemUnLock (pExOut->hSTree);

        // copy name string

        if (pExState->hCName != 0) {
            pcName = MHMemLock (pExState->hCName);
            len = strlen (pcName) + 1;
            if ((pExOut->hCName = MHMemAllocate (len)) == 0) {
                MHMemUnLock (pExState->hCName);
                goto failure;
            }
            pStr = MHMemLock (pExOut->hCName);
            memcpy (pStr, pcName, len);
            MHMemUnLock (pExOut->hCName);
            MHMemUnLock (pExState->hCName);
        }
        MHMemUnLock (*phTMOut);
        retval = EENOERROR;
    }
succeed:
    MHMemUnLock (pExState->hExStr);
    MHMemUnLock (pExState->hSTree);
    MHMemUnLock (*phTMIn);
    pExState = NULL;
    return (retval);

failure:
    if (pExOut->hExStr != 0) {
        MHMemFree (pExOut->hExStr);
    }
    if (pExOut->hSTree != 0) {
        MHMemFree (pExOut->hSTree);
    }
    if (pExOut->hCName != 0) {
        MHMemFree (pExOut->hCName);
    }
    MHMemUnLock (*phTMOut);
    MHMemFree (*phTMOut);
    *phTMOut = 0;
    goto succeed;
}



/**     GetChildTM - get TM representing ith child of a TM
 *
 *      flag = GetChildTM (iChild)
 *
 *      Entry   iChild = child to get TM for
 *              pExStateP = address of locked parent expression state
 *              pExState = address of locked expression state
 *
 *      Exit    pExState initialized for child
 *
 *      Returns TRUE if no error
 *              FALSE if error
 */


EESTATUS GetChildTM (HTM hTM, ulong iChild, PEEHSTR phDStr, PEEHSTR phName, uint radix)
{
    eval_t      evalP;
    peval_t     pvP;
    EESTATUS    retval = EENOERROR;
    char        tempbuf[16];
    ushort      len;
    ushort      plen;
    uint        excess;
    char   *pDStr;
    char   *pName;
    char        *fmtstr;


    DASSERT (hTM != 0);
    if (hTM == 0) {
        return (EECATASTROPHIC);
    }
    DASSERT(pExState == NULL);
    pExState = MHMemLock (hTM);
    if (pExState->state.bind_ok != TRUE) {
        pExState->err_num = ERR_NOTEVALUATABLE;
        MHMemUnLock (hTM);
        pExState = NULL;
        return (EEGENERAL);
    }
    pExStrP = MHMemLock (pExState->hExStr);
    pCxt = &pExState->cxt;
    DASSERT (pExState->strIndex <= pExState->ExLen);
    plen = pExState->strIndex;
    excess = pExState->ExLen - plen;
    pvP = &evalP;
    *pvP = pExState->result;
#if !defined (C_ONLY)
    if (EVAL_IS_REF (pvP)) {
        RemoveIndir (pvP);
    }
#endif
    GettingChild = TRUE;
    if (EVAL_IS_ARRAY (pvP)) {
        // fake up name as [i]  ultoa not used here because 0 converts
        // as null string

        switch (radix) {
            case 8:
                fmtstr = "[%o]";
                break;

            case 16:
                fmtstr = "[%x]";
                break;

            default:
            case 10:
                fmtstr = "[%ld]";
                break;
        }

        len = sprintf (tempbuf, fmtstr, iChild);

        if (((*phName = MHMemAllocate (len + 1)) == 0) ||
         ((*phDStr = MHMemAllocate (plen + excess + len + 1)) == 0)) {
            goto nomemory;
        }
        pName = MHMemLock (*phName);
        pDStr = MHMemLock (*phDStr);
        strcpy (pName, tempbuf);
        memcpy (pDStr, pExStrP, plen);
        memcpy (pDStr + plen, pName, len);
        *(pDStr + plen + len) = 0;
        MHMemUnLock (*phDStr);
        MHMemUnLock (*phName);
    }
    else if (EVAL_IS_PTR (pvP)) {
        SetNodeType (pvP, PTR_UTYPE (pvP));
        if (!EVAL_IS_VTSHAPE (pvP)) {
            // set name to null

            if (((*phName = MHMemAllocate (1)) == 0) ||
              ((*phDStr = MHMemAllocate (plen + 3)) == 0)) {
                goto nomemory;
            }
            pName = MHMemLock (*phName);
            pDStr = MHMemLock (*phDStr);
            *pName = 0;
            *pDStr++ = '(';
            memcpy (pDStr, pExStrP, plen);
            pDStr += plen;
            *pDStr++ = ')';
            memcpy (pDStr, pExStrP + plen, excess);
            pDStr += excess;
            *pDStr = 0;
            MHMemUnLock (*phDStr);
            MHMemUnLock (*phName);
        }
        else {
            // fake up name as [i]  ultoa not used here because 0 converts
            // as null string

            switch (radix) {
                case 8:
                    fmtstr = "[%o]";
                    break;

                case 16:
                    fmtstr = "[%x]";
                    break;

                default:
                case 10:
                    fmtstr = "[%ld]";
                    break;
            }

            len = sprintf (tempbuf, fmtstr, iChild);

            if (((*phName = MHMemAllocate (len + 1)) == 0) ||
             ((*phDStr = MHMemAllocate (plen + len + 1)) == 0)) {
                goto nomemory;
            }
            pName = MHMemLock (*phName);
            pDStr = MHMemLock (*phDStr);
            strcpy (pName, tempbuf);
            memcpy (pDStr, pExStrP, plen);
            memcpy (pDStr + plen, pName, len);
            memcpy (pDStr + plen + len, pExStrP + plen, excess);
            *(pDStr + plen + len + excess) = 0;
            MHMemUnLock (*phDStr);
            MHMemUnLock (*phName);
        }
    }
    else 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

        if ((pExState->err_num = SetClassiName (pvP, iChild, phDStr, phName,
          ((EVAL_STATE (pvP) == EV_type)? CLS_defn: CLS_data), plen, excess)) != ERR_NONE) {
            goto general;
        }
    }
    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.

        if ((retval = SetFcniParm (pvP, iChild, phName)) == EENOERROR) {
            pName = MHMemLock (*phName);
            if ((*phDStr = MHMemAllocate ((len = strlen (pName)) + 1)) == 0) {
                MHMemUnLock (*phName);
                goto nomemory;
            }
            pDStr = MHMemLock (*phDStr);
            memcpy (pDStr, pName, len);
            *(pDStr + len) = 0;
            MHMemUnLock (*phDStr);
            MHMemUnLock (*phName);
        }
    }
    else if (EVAL_IS_LABEL (pvP)) {
        // CV should never ask for the children of a label
        DASSERT (FALSE);
        pExState->err_num = ERR_INTERNAL;
        goto general;
    }
    MHMemUnLock (pExState->hExStr);
    pExState = NULL;
    MHMemUnLock (hTM);
    GettingChild = FALSE;
    return (retval);

nomemory:
    pExState->err_num = ERR_NOMEMORY;
general:
    MHMemUnLock (pExState->hExStr);
    pExState = NULL;
    MHMemUnLock (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;
    short       len = 0;
    UOFFSET     offset = 0;
    char   *pExStr;
    peval_t     pv;
    short       retval = EECATASTROPHIC;
    short       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 = MHMemAllocate (TYPESTRMAX)) != 0)) {
        retval = EEGENERAL;
        buf = MHMemLock (*phszName);
        memset (buf, 0, TYPESTRMAX);
        DASSERT(pExState == NULL);
        pExState = MHMemLock (*phTM);
        if (pExState->state.bind_ok == TRUE) {
            pv = &pExState->result;
            if ((pExState->state.childtm == TRUE) && (pExState->state.noname == TRUE)) {
                // if there is no name
                MHMemUnLock (*phTM);
                pExState = NULL;
                MHMemUnLock (*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 = MHMemLock (pExState->hCName);
                len = (int)strlen (pExStr);
                len = min (len, buflen);
                strncpy (buf, pExStr, len);
                MHMemUnLock (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)

                switch ((pSym = MHOmfLock (EVAL_HSYM (pv)))->rectyp) {
                    case S_REGISTER:
                        len = ((REGPTR)pSym)->name[0];
                        offset = offsetof (REGSYM, name[1]);
                        break;

                    case S_CONSTANT:
                        len = ((CONSTPTR)pSym)->name[0];
                        offset = offsetof (CONSTSYM, name[1]);
                        break;

                    case 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

                        len = 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_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_PUB32:
                    case S_LTHREAD32:
                    case S_GTHREAD32:
                        len = ((DATAPTR32)pSym)->name[0];
                        offset = offsetof (DATASYM32, name[1]);
                        break;

                    case S_REGREL32:
                        len = ((LPREGREL32)pSym)->name[0];
                        offset = offsetof (REGREL32, name[1]);
                        break;

                    case S_LPROCMIPS:
                    case S_GPROCMIPS:
                        len = ((PROCPTRMIPS)pSym)->name[0];
                        offset = offsetof (PROCSYMMIPS, name[1]);
                        break;

                    default:
                        pExState->err_num = ERR_BADOMF;
                        MHMemUnLock (*phTM);
                        pExState = NULL;
                        /// BUGBUG -- Messed up return
                        return (EEGENERAL);
                }
                len = min (len, buflen);
                strncpy (buf, ((char *)pSym) + offset, len);
                MHOmfUnLock (EVAL_HSYM (pv));
                *(buf + len) = 0;
                retval = EENOERROR;
            }
        }
        else {
            /*
             * if the expression did not bind, return the expression and
             *   the error message if one is available
             *
             * Lets treat this a bit more funny.   Since the only known
             *  occurance of this is currently in locals and watch windows,
             *  check to see if there is a direct symbol refrence and
             *  correct for this case, additionally don't return an
             *  error if we can get any type of name
             */

            pExStr = MHMemLock (pExState->hExStr);

            for (len = 0; pExStr[len] != 0; len++) {
                if (pExStr[len] == (char)-1) {
                    pExStr += len+5;
                    len = -1;
                } else if ((len == 0) &&
                      ((pExStr[len] == ')') || (pExStr[len] == '.'))) {
                    pExStr++;
                    len = -1;
                }
            }

            if (*pExStr != 0) {
                len = min (buflen, len);
                strncpy (buf, pExStr, len);
                buf += len;
                buflen -= len;
                retval = EENOERROR;
            }
            MHMemUnLock (pExState->hExStr);
        }
        MHMemUnLock (*phszName);
        MHMemUnLock (*phTM);
        pExState = NULL;
    }
    return (retval);
}




/**     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;
    TI *    pTMInfo;
    eval_t      evalT;
    peval_t     pvT;
#ifdef TARGET_i386
    SHREG       reg;
#endif
    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(TI) + sizeof(val_t) )) == 0) {
        return  EENOMEMORY;
    }
    pTMInfo = MHMemLock( *phTMInfo );
    DASSERT( pTMInfo != NULL );
    memset( pTMInfo, 0, sizeof(TI) + 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->u.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->u.SegType = EEDATA;
            }

            /*
             *  in all other cases it must have been a code segment
             */

            else {
                pTMInfo->u.SegType = EECODE;
            }

        } else if ((EVAL_STATE( pvT ) == EV_rvalue) &&
                   (EVAL_IS_FCN( pvT ) ||
                    EVAL_IS_LABEL( pvT ))) {

            pTMInfo->fResponse.fSegType = TRUE;
            pTMInfo->u.SegType = EECODE;

        } else if ((EVAL_STATE( pvT ) == EV_rvalue) &&
                   (EVAL_IS_ADDR( pvT ))) {

            pTMInfo->fResponse.fSegType = TRUE;
            pTMInfo->u.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->u2.AI              = EVAL_SYM( pvT );
                pTMInfo->fResponse.Type     = EVAL_TYP( pvT );
                if (!ADDR_IS_LI(pTMInfo->u2.AI)) {
                    SHUnFixupAddr(&pTMInfo->u2.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->u2.AI              = EVAL_PTR( pvT );
                pTMInfo->fResponse.Type     = EVAL_TYP(pvT);
                if (!ADDR_IS_LI( pTMInfo->u2.AI )) {
                    SHUnFixupAddr( &pTMInfo->u2.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->u2.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->u2.AI = EVAL_SYM( pvT );
            pTMInfo->fResponse.fAddr = TRUE;
            pTMInfo->fResponse.Type = EVAL_TYP( pvT );

            if (!ADDR_IS_LI(pTMInfo->u2.AI)) {
                SHUnFixupAddr(&pTMInfo->u2.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->u2.AI = EVAL_PTR( pvT );
            pTMInfo->fResponse.Type = EVAL_TYP( pvT );

            if (!ADDR_IS_LI( pTMInfo->u2.AI )) {
                SHUnFixupAddr( &pTMInfo->u2.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;
                Evaluating = TRUE;
                if (CastNode(pvT, pReqInfo->Type, pReqInfo->Type)) {
                    switch( TypeSize( pvT ) ) {
                    case 1:
                        pTMInfo->u2.AI.addr.off = VAL_UCHAR( pvT );
                        break;

                    case 2:
                        pTMInfo->u2.AI.addr.off = VAL_USHORT( pvT );
                        break;

                    case 4:
                        pTMInfo->u2.AI.addr.off = VAL_ULONG( pvT );
                        break;

                    default:
                        eestatus = EEGENERAL;
                        break;
                    }

                    pTMInfo->fResponse.fAddr = TRUE;
                    pTMInfo->fResponse.Type = pReqInfo->Type;

#ifdef TARGET_i386
                    if (pTMInfo->u.SegType & EECODE) {
                        reg.hReg = CV_REG_CS;
                    } else {
                        reg.hReg = CV_REG_DS;
                    }

                    GetReg(&reg, pCxt);
                    pTMInfo->u2.AI.addr.seg = reg.Byte2;
#else
                    pTMInfo->u2.AI.addr.seg = 0;
#endif

                    SHUnFixupAddr( &pTMInfo->u2.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->u.fFunction = pExState->state.fFunction;

    pExStr = MHMemLock(pExState->hExStr);
    p = &pExStr[pExState->strIndex];
    if (*p == ',') {
        *p++;
    }
    if (tolower(*p) == 's') {
        pTMInfo->u.fFmtStr = TRUE;
    }
    else {
        pTMInfo->u.fFmtStr = FALSE;
    }
    MHMemUnLock( pExState->hExStr );

    MHMemUnLock( *phTMInfo );
    MHMemUnLock( *phTM );
    pExState = NULL;

    return      eestatus;
}




/**     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
 */


ushort IsExpandablePtr (peval_t pv)
{
    eval_t      evalT;
    peval_t     pvT;
    ushort      retval = EENOTEXP;

    if (EVAL_IS_PTR (pv)) {
        // this will also handle the reference cases
        if (EVAL_TYP(pv) == T_VOID     ||
            EVAL_TYP(pv) == T_PVOID    ||
            EVAL_TYP(pv) == T_PFVOID   ||
            EVAL_TYP(pv) == T_PHVOID   ||
            EVAL_TYP(pv) == T_32PVOID  ||
            EVAL_TYP(pv) == T_32PFVOID) {
            return retval;
        }
        if (CV_IS_PRIMITIVE (PTR_UTYPE (pv))) {
            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);
}




/***    CountClassElem - count number of class elements according to mask
 *
 *      count = CountClassElem (pv, search)
 *
 *      Entry   pv = pointer to node to be initialized
 *              search = mask specifying which element types to count
 *
 *      Exit    none
 *
 *      Returns count of number of class elements meeting search requirments
 */


LOCAL EESTATUS CountClassElem (peval_t pv, long *pcChildren,
  uint search)
{
    ushort          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;
    ushort          retval = EENOERROR;
    CV_typ_t        newindex;
    uchar           pad;

    // 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[0]);

    //  walk field list to the end counting elements

    for (cnt = CLASS_COUNT (pv); cnt > 0; cnt--) {
        if ((pad = *(((char *)pField) + fSkip)) >= LF_PAD0) {
            // there is a pad field
            fSkip += pad & 0x0f;
        }
        anchor = fSkip;
        switch (((plfEasy)(pField + fSkip))->leaf) {
            case LF_INDEX:
                // 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[0]);
                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[0]);
                RNumLeaf (pField + fSkip, &fSkip);
                fSkip += *(pField + fSkip) + sizeof (char);
                if (search & CLS_member) {
                    (*pcChildren)++;
                }
                break;


#if !defined(C_ONLY)
            case LF_ENUMERATE:
                // skip value name of enumerate
                fSkip += offsetof (lfEnumerate, value[0]);
                RNumLeaf (pField + fSkip, &fSkip);
                fSkip += *(pField + fSkip) + sizeof (char);
                if (search & CLS_enumerate) {
                    (*pcChildren)++;
                }
                break;

            case LF_STMEMBER:
                fSkip += offsetof (lfSTMember, Name[0]);
                fSkip += *(pField + fSkip) + sizeof (char);
                if (search & CLS_member) {
                    (*pcChildren)++;
                }
                break;

            case LF_BCLASS:
                fSkip += offsetof (lfBClass, offset[0]);
                RNumLeaf (pField + fSkip, &fSkip);
                if (search & CLS_bclass) {
                    (*pcChildren)++;
                }
                break;

            case LF_VBCLASS:
                fSkip += offsetof (lfVBClass, vbpoff[0]);
                RNumLeaf (pField + fSkip, &fSkip);
                RNumLeaf (pField + fSkip, &fSkip);
                if (search & CLS_bclass) {
                    (*pcChildren)++;
                }
                break;

            case LF_IVBCLASS:
                fSkip += offsetof (lfVBClass, vbpoff[0]);
                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_NESTTYPE:
                fSkip += sizeof (struct lfNestType) +
                                  ((plfNestType)(pField + fSkip))->Name[0];
                if (search & CLS_ntype) {
                    (*pcChildren)++;
                }
                break;
#endif

            default:
                pExState->err_num = ERR_BADOMF;
                MHOmfUnLock (hField);
                *pcChildren = 0;
                return (EEGENERAL);
        }
    }
    if (hField != 0) {
        MHOmfUnLock (hField);
    }
    return (retval);
}





/**     DereferenceTM - generate expression string from pointer to data TM
 *
 *      flag = DereferenceTM (hTMIn, phEStr)
 *
 *      Entry   phTMIn = handle to TM to dereference
 *              phEStr = pointer to handle to dereferencing expression
 *
 *      Exit    *phEStr = expression referencing pointer data
 *
 *      Returns EECATASTROPHIC if fatal error
 *              EEGENERAL if TM not dereferencable
 *              EENOERROR if expression generated
 */


EESTATUS DereferenceTM (HTM hTM, PEEHSTR phDStr)
{
    peval_t     pvTM;
    EESTATUS    retval = EECATASTROPHIC;
    pexstate_t  pTM;
    ushort      plen;
    uint        excess;

    DASSERT (hTM != 0);
    if (hTM != 0) {
        // lock TM and set pointer to result field of TM

        pTM = MHMemLock (hTM);
        pvTM = &pTM->result;
        if (EVAL_IS_ARRAY (pvTM) || (IsExpandablePtr (pvTM) != EEPOINTER)) {
            pTM->err_num = ERR_NOTEXPANDABLE;
            retval = EEGENERAL;
        }
        else {
            // allocate buffer for *(input string) and copy

            if ((*phDStr = MHMemAllocate (pTM->ExLen + 4)) != 0) {
                // if not reference generate,  expression = *(old expr)
                // if reference, expression = (old expr)

                pExStr = MHMemLock (*phDStr);
                *pExStr++ = '(';
#if !defined (C_ONLY)
                if (!EVAL_IS_REF (pvTM)) {
                    *pExStr++ = '*';
                }
#else
                *pExStr++ = '*';
#endif
                plen = pTM->strIndex;
                excess = pTM->ExLen - plen;
                pExStrP = MHMemLock (pTM->hExStr);
                memcpy (pExStr, pExStrP, plen);
                pExStr += plen;
                *pExStr++ = ')';
                memcpy (pExStr, pExStrP + plen, excess);
                pExStr += excess;
                *pExStr = 0;
                MHMemUnLock (pTM->hExStr);
                MHMemUnLock (*phDStr);
                retval = EENOERROR;
            }
        }
        MHMemUnLock (hTM);
    }
    return (retval);
}




/***    SetClassiName - Set a node to a specified element of a class
 *
 *      fFound = SetClassiName (pv, ordinal, phDStr, phName, search, plen)
 *
 *      Entry   ordinal = number of class element to initialize for
 *                        (zero based)
 *              search = mask specifying which element types to count
 *              pExStrP = address of locked pExParent->hExStr
 *              plen = length of parent string to end of parse
 *              excess = length of parent string after end of parse
 *
 *      Exit    pExState->hCName = handle of buffer containing name
 *
 *      Returns ERR_NONE if element found within structure
 *              error number if element not found within structure
 */


LOCAL ushort SetClassiName (peval_t pv, long ordinal,
  PEEHSTR phDStr, PEEHSTR phName, uint search, ushort plen, uint excess)
{
    HTYPE           hField;         // handle to type record for struct field list
    char       *pField;         // current position withing field list
    char       *pMethod;
    uint            fSkip = 0;      // current offset in the field list
    uint            anchor;
    uint            len;
    bool_t          retval = ERR_NONE;
    CV_typ_t        newindex;
    char       *pName;
    char       *pc;
    char       *pDStr;
    char            FName[255];
    char       *pFName = &FName[0];
    eval_t          evalT;
    peval_t         pvT;
    uchar           pad;
    PHDR_TYPE       pHdr;

    // set fField to the handle of the field list

    if ((hField = THGetTypeFromIndex (EVAL_MOD (pv), CLASS_FIELD (pv))) == 0) {
        DASSERT (FALSE);
        return (ERR_BADOMF);
    }
    pField = (char *)(&((TYPPTR)MHOmfLock (hField))->data[0]);

    //  walk field list to iElement-th field

    while (ordinal >= 0) {
        if ((pad = *(((char *)pField) + fSkip)) >= LF_PAD0) {
            // there is a pad field
            fSkip += pad & 0x0f;
        }
        anchor = fSkip;
        switch (((plfEasy)(pField + fSkip))->leaf) {
            case LF_INDEX:
                // move to next list in chain

                newindex = ((plfIndex)(pField + fSkip))->index;
                MHOmfUnLock (hField);
                if ((hField = THGetTypeFromIndex (EVAL_MOD (pv), newindex)) == 0) {
                    return (ERR_BADOMF);
                }
                pField = (char *)(&((TYPPTR)MHOmfLock (hField))->data[0]);
                fSkip = 0;
                break;

            case LF_MEMBER:
                // skip offset of member and name of member
                fSkip += offsetof (lfMember, offset[0]);
                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[0]);
                RNumLeaf (pField + fSkip, &fSkip);
                pc = pField + fSkip;
                fSkip += *(pField + fSkip) + sizeof (char);
                if (search & CLS_enumerate) {
                    ordinal--;
                }
                break;


#if !defined(C_ONLY)
            case LF_STMEMBER:
                fSkip += offsetof (lfSTMember, Name[0]);
                pc = pField + fSkip;
                fSkip += *(pField + fSkip) + sizeof (char);
                if (search & CLS_member) {
                    ordinal--;
                }
                break;

            case LF_BCLASS:
                fSkip += offsetof (lfBClass, offset[0]);
                RNumLeaf (pField + fSkip, &fSkip);
                if (search & CLS_bclass) {
                    ordinal--;
                }
                break;

            case LF_VBCLASS:
                fSkip += offsetof (lfVBClass, vbpoff[0]);
                RNumLeaf (pField + fSkip, &fSkip);
                RNumLeaf (pField + fSkip, &fSkip);
                if (search & CLS_bclass) {
                    ordinal--;
                }
                break;

            case LF_IVBCLASS:
                fSkip += offsetof (lfVBClass, vbpoff[0]);
                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[0]);
                fSkip += sizeof (struct lfMethod) + *pc;
                if (search & CLS_method) {
                    ordinal -= ((plfMethod)(pField + anchor))->count;
                }
                break;

            case LF_NESTTYPE:
                fSkip += offsetof (lfNestType, Name[0]);
                pc = pField + fSkip;
                fSkip += *(pField + fSkip) + sizeof (char);
                if (search & CLS_ntype) {
                    ordinal--;
                }
                break;
#endif

            default:
                MHOmfUnLock (hField);
                return (ERR_BADOMF);
        }
        if (ordinal < 0) {
            break;
        }
    }

    // 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_MEMBER:
        case LF_STMEMBER:
        case LF_VFUNCTAB:
            len = *pc;
            if (((*phName = MHMemAllocate (len + 1)) == 0) ||
              ((*phDStr = MHMemAllocate (plen + excess + len + 4)) == 0)) {
                goto nomemory;
            }
            pName = MHMemLock (*phName);
            strncpy (pName, pc + 1, len);
            *(pName + len) = 0;
            pDStr = MHMemLock (*phDStr);
            *pDStr++ = '(';
            memcpy (pDStr, pExStrP, plen);
            pDStr += plen;
            *pDStr++ = ')';
            *pDStr++ = '.';
            memcpy (pDStr, pName, len);
            pDStr += len;
            memcpy (pDStr, pExStrP + plen, excess);
            pDStr += excess;
            *pDStr = 0;
            MHMemUnLock (*phDStr);
            MHMemUnLock (*phName);
            break;
#if !defined (C_ONLY)

        case LF_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[0]);
                RNumLeaf (pField + fSkip, &fSkip);
                len = *(pField + fSkip);

                // generate (*(base *)(&expr))

                if (((*phName = MHMemAllocate (len + 1)) == 0) ||
                  ((*phDStr = MHMemAllocate (plen + len + excess + 10)) == 0)) {
                    goto nomemory;
                }
                pName = MHMemLock (*phName);
                strncpy (pName, pField + fSkip + sizeof (char), len);
                *(pName + len) = 0;
                pDStr = MHMemLock (*phDStr);
                memcpy (pDStr, "(*(", 3);
                memcpy (pDStr + 3, pField + fSkip + sizeof (char), len);
                memcpy (pDStr + 3 + len, "*)(&", 4);
                memcpy (pDStr + 7 + len, pExStrP, plen);
                memcpy (pDStr + 7 + len + plen, "))", 2);
                memcpy (pDStr + 7 + len + plen + 2, pExStrP + plen, excess);
                *(pDStr + 9 + len + plen + excess) = 0;
                MHMemUnLock (*phDStr);
                MHMemUnLock (*phName);
            }
            break;

        case LF_VBCLASS:
            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[0]);
                RNumLeaf (pField + fSkip, &fSkip);
                len = *(pField + fSkip);

                // generate (*(base *)(&expr))

                if (((*phName = MHMemAllocate (len + 1)) == 0) ||
                  ((*phDStr = MHMemAllocate (plen + len + 10)) == 0)) {
                    goto nomemory;
                }
                pName = MHMemLock (*phName);
                //*pName = 0;
                strncpy (pName, pField + fSkip + sizeof (char), len);
                *(pName + len) = 0;
                pDStr = MHMemLock (*phDStr);
                memcpy (pDStr, "(*(", 3);
                memcpy (pDStr + 3, pField + fSkip + sizeof (char), len);
                memcpy (pDStr + 3 + len, "*)(&", 4);
                memcpy (pDStr + 7 + len, pExStrP, plen);
                memcpy (pDStr + 7 + len + plen, "))", 2);
                memcpy (pDStr + 7 + len + plen + 2, pExStrP + plen, excess);
                *(pDStr + 9 + len + plen + excess) = 0;
                MHMemUnLock (*phDStr);
                MHMemUnLock (*phName);
            }
            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[0]);
                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_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) {
                pMethod = (char *)(&((TYPPTR)MHOmfLock (hField))->data[0]);
                fSkip = 0;
                while (++ordinal < 0) {
                    if (((pmlMethod)(pMethod + fSkip))->attr.mprop == CV_MTvirtual) {
                        fSkip += sizeof (mlMethod);
                        RNumLeaf (pMethod + fSkip, &fSkip);
                    }
                    else {
                        fSkip += sizeof (mlMethod);
                    }
                }
                pvT = &evalT;
                CLEAR_EVAL (pvT);
                EVAL_MOD (pvT) = SHHMODFrompCXT (pCxt);
                newindex = ((pmlMethod)(pMethod + fSkip))->index;
                MHOmfUnLock (hField);
                hField = 0;
                SetNodeType (pvT, newindex);
                if ((*phName = MHMemAllocate (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 = MHMemLock (*phName);
                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 ((*phDStr = MHMemAllocate (plen + FCNSTRMAX + 2)) == 0) {
                    MHMemUnLock (*phName);
                    goto nomemory;
                }

                pDStr = MHMemLock (*phDStr);
                memcpy (pDStr, pExStrP, plen);
                memcpy (pDStr + plen, ".", 1);
                memcpy (pDStr + 1 + plen, pc, len);
                memcpy (pDStr + 1 + plen + len, pExStrP + plen, excess);
                *(pDStr + len + plen + 1 + excess) = 0;
                MHMemUnLock (*phDStr);
                // truncate name to first (
                for (len = 0; (*pc != '(') && (*pc != 0); pc++) {
                    len++;
                }
                *pc = 0;
                MHMemUnLock (*phName);
                if ((*phName = MHMemReAlloc (*phName, len + 1)) == 0) {
                    goto nomemory;
                }
            }
            break;
#else
      Unreferenced( evalT );
    Unreferenced( pHdr );
    Unreferenced( pvT );
    Unreferenced( pMethod );
#endif

        default:
            retval = ERR_BADOMF;
            break;
    }
    if (hField != 0) {
        MHOmfUnLock (hField);
    }
    return (retval);

nomemory:
    if (hField != 0) {
        MHOmfUnLock (hField);
    }
    if (*phName != 0) {
        MHMemFree (*phName);
    }
    return (ERR_NOMEMORY);
}




/***    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.
 */


LOCAL ushort SetFcniParm (peval_t pv, long ordinal, PEEHSTR pHStr)
{
    char   *pStr;
    HSYM        hSym;
    SYMPTR      pSym;
    ushort      offset;
    ushort      len;
    bool_t      retval;

    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);
    for (;;) {
        if ((hSym = SHNextHsym (EVAL_MOD (pv), hSym)) == 0) {
            pExState->err_num = ERR_BADOMF;
            return (EEGENERAL);
        }

        // lock the symbol and check the type
        pSym = MHOmfLock (hSym);
        switch (pSym->rectyp) {
#if defined (ADDR_16) || defined (ADDR_MIXED)
            case S_BPREL16:
                if (((BPRELPTR16)pSym)->off >= 0) {
                // This is a formal argument
                    ordinal--;
                    len = ((BPRELPTR16)pSym)->name[0];
                    offset = offsetof (BPRELSYM16, name[0]) + sizeof (char);
                }
                break;
#endif

            case S_BPREL32:
                if (((BPRELPTR32)pSym)->off >= 0) {
                // This is a formal argument
                    ordinal--;
                    len = ((BPRELPTR32)pSym)->name[0];
                    offset = offsetof (BPRELSYM32, name[0]) + sizeof (char);
                }
                break;

            case S_REGREL32:
                if (((LPREGREL32)pSym)->off >= 0) {
                   // Formal parameter
                   ordinal--;
                   len = ((LPREGREL32)pSym)->name[0];
                   offset = offsetof (REGREL32, name[1]);
                }
                break;

            case S_REGISTER:
                ordinal--;
                len = ((REGPTR)pSym)->name[0];
                offset = offsetof (REGSYM, name[1]);
                break;

            case S_GTHREAD32:
            case S_LTHREAD32:
                DASSERT(FALSE);
                return( EEGENERAL );

            case S_END:
            case S_BLOCK16:
            case S_BLOCK32:
            case S_ENDARG:
                // we should never get here
                pExState->err_num = ERR_BADOMF;
                MHOmfUnLock (hSym);
                return (EEGENERAL);

            default:
                break;
        }
        if (ordinal < 0) {
            break;
        }
        MHOmfUnLock (hSym);
    }

    // if we get here, pSym points to the symbol record for the parameter

    if ((*pHStr = MHMemAllocate (len + 1)) != 0) {
        pStr = MHMemLock (*pHStr);
        strncpy (pStr, ((char *)pSym) + offset, len);
        *(pStr + len) = 0;
        MHMemUnLock (*pHStr);
        retval = EENOERROR;
    }
    else {
        MHOmfUnLock (hSym);
        retval = EEGENERAL;
    }
    MHOmfUnLock (hSym);
    return (retval);
}


bool_t
ResolveAddr(
            peval_t     pv
            )
{
    ulong       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)) {
        EVAL_SYM_OFF (pv) += pExState->frame.BP.off;
        EVAL_SYM_SEG (pv) = pExState->frame.SS;
        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.
     */

    else if (EVAL_IS_REGREL (pv)) {
        reg.hReg = EVAL_REGREL (pv);
#ifdef TARGET_PPC
        if (reg.hReg == CV_PPC_GPR1) {
            ul = pExState->frame.BP.off;
        } else
#endif
#ifdef TARGET_MIPS
        if (reg.hReg == CV_M4_IntSP) {
            ul = pExState->frame.BP.off;
        } else
#endif
#ifdef TARGET_ALPHA
        if (reg.hReg == CV_ALPHA_IntSP) {
            ul = pExState->frame.BP.off;
        } else
#endif
        if (GetReg (&reg, pCxt) == NULL) {
            DASSERT (FALSE);
        } else {
            ul = reg.Byte4;
            if (!ADDR_IS_OFF32(*SHpADDRFrompCXT(pCxt))) {
                ul &= 0xffff;
            }
        }

        EVAL_SYM_OFF (pv) += ul;
        EVAL_SYM_SEG (pv) = pExState->frame.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)) {
        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 ));
    }

    return TRUE;
}                               /* ResolveAddr() */