
/***************************************************************************
**
**    $Header:   D:/ECB2S/SRC/LOG/SYMGET.CPP   1.2.1.4   17 Apr 1997 16:03:40   ZJRD  $
**
**    $Log:   D:/ECB2S/SRC/LOG/SYMGET.CPP  $
** 
**    Rev 1.2.1.4   17 Apr 1997 16:03:40   ZJRD
** No change.
** 
**    Rev 1.2.1.3   16 Apr 1997 10:36:44   ZJRD
** No change.
** 
**    Rev 1.2.1.2   10 Apr 1997 15:45:36   ZJRD
** No change.
** 
**    Rev 1.2.1.1   03 Apr 1997 15:24:42   ZJRD
** No change.
** 
**    Rev 1.2.1.0   28 Mar 1997 10:28:00   ZJRD
** easy pack sld 2.09d
** 
**    Rev 1.1   19 Mar 1997 11:37:38   ZJRD
** No change.
** 
**    Rev 1.0   12 Mar 1997 14:51:28   ZJRD
** Initial revision.
** 
****************************************************************************/

/****************************************************************************
**
**  Name:  symget.cpp
**
**  Description:
**     routines for getting symbols out of the symbol table.
**
**  Status:  PRELIMINARY
**
**  $Log$
** 
**  $Header:   D:/ECB2S/SRC/LOG/SYMGET.CPP   1.2.1.4   17 Apr 1997 16:03:40   ZJRD  $
**
**  Copyright (C) 1995 Microtek International.  All rights reserved.
**
*****************************************************************************/

                       /****************************
                        *                          *
                        *       INCLUDE FILES      *
                        *                          *
                        ****************************/

#include "stdafx.h"                      
#include <string.h>
#include "symbase.h"
#include "symwind.h"
#include "symhash.h"
#include "symheap.h"
#include "sympool.h"
#include "symord.h"
#include "symblsvr.h"
#include "symerrs.h"
#include "symget.h"
#include "symmgr.h"
#include "symutil.h"
#include "symtype.h"

                       /****************************
                        *                          *
                        *     LOCAL DEFINITIONS    *
                        *                          *
                        ****************************/
// temporary buffer use by SymUpdateTypeInfo
CHAR tmpBuf[MAX_STRING_SIZE];


                       /****************************
                        *                          *
                        *    EXTERNAL VARIABLES    *
                        *                          *
                        ****************************/

extern BaseIndexTable bit;
extern HashTable ht;
extern TABLE_OFFSET rootOffset;
extern MemPool st;
extern IndexTable typit;
extern TypeTable tt;
extern OrdinalTable ot;    // ordinal table ;

//---------------------------------------------------------------------------
// Symbol Statistics
extern U32 symbolStat[];
extern TABLE_OFFSET lastModuleLoaded;

                       /****************************
                        *                          *
                        *     LOCAL PROTOTYPES     *
                        *                          *
                        ****************************/

RETCODE PRIVATE
SearchList(TABLE_OFFSET  inputSymbol,
           LPSTR         symName,
           SYM_TYPE_TYPE symType,
           TABLE_OFFSET  *offsetFound);

RETCODE PRIVATE
SearchUpperFuncs(TABLE_OFFSET inputSymbol,
                 LPSTR        symName,
                 TABLE_OFFSET *offsetFound);

RETCODE PRIVATE SymUpdateTypeInfo(TYPE_INDEX typeIndex, U32 typeMAUSize,
                                  TYPE_INDEX baseTypeIndex);

//RETCODE EXPORT SymGetModuleDescCase(LPSTR moduleName,
//                                LPSTR pathName,
//                                SYM_DESCRIPTOR *moduleOffset);
// this routine for module name incase 
                       /****************************
                        *                          *
                        *      EXECUTABLE CODE     *
                        *                          *
                        ****************************/

//--------------------------------------------------------------------------
//  SearchList
//--------------------------------------------------------------------------
RETCODE PRIVATE
SearchList(TABLE_OFFSET  inputSymbol,
           LPSTR         symName,
           SYM_TYPE_TYPE symType,
           TABLE_OFFSET  *offsetFound) {
   
   RETCODE err;
   SYM_DESCRIPTOR listHead;
   U16 count,i;
   int same;
   COMMON_SYMBOL_HEADER HUGE *constPtr;
   U8 name[MAX_SYMNAME_LENGTH];

   if ((err = SymGetSymbolHeadList(inputSymbol,symType,&listHead,&count))
      !=GOOD)
      return err;

   if (!listHead) {
      *offsetFound=0;
      return GOOD;
   }

   i = count - 1;
   do {
      constPtr = (COMMON_SYMBOL_HEADER HUGE *) st.GetHugeDataPtr(listHead);
      st.GetString(constPtr->symbolNameOffset,name);
      same = strcmp((char *)symName,(char *)name);
      // if same is zero then we have a match
      if ( same == 0 ) {
         *offsetFound = listHead;
         return GOOD;
      }
      listHead = constPtr->symSiblingOffset;
   } while ( (listHead) && (i--) );
   
   // if we get here then there isn't a match
   *offsetFound = 0;
   return GOOD;
}

//--------------------------------------------------------------------------
//  SearchUpperFuncs 
//--------------------------------------------------------------------------
RETCODE PRIVATE
SearchUpperFuncs(TABLE_OFFSET inputSymbol,
                 LPSTR        symName,
                 TABLE_OFFSET *offsetFound) {

   RETCODE err;
   TABLE_OFFSET parentSymbol, currentSymbol, siblingSymbol, tmpSymbol;
   SYM_TYPE_TYPE symType,sibType;
   COMMON_BLOCK_HEADER HUGE *symPtr;
   COMMON_BLOCK_HEADER HUGE *sibPtr;
   U8 name[MAX_SYMNAME_LENGTH];

   // set default to function not found
   *offsetFound = 0L;

   // if the symbol that is passed in is a module then there are no
   // function names to search.
   symPtr = (COMMON_BLOCK_HEADER HUGE *)st.GetHugeDataPtr(inputSymbol);
   if (((symPtr->symHeader.typeIndex.symType) & 0xF) == SYM_MODULE)
      return GOOD;
   
   currentSymbol = inputSymbol;
   do {

      // the only way to get to the head of the function/block list
      // is to move to the symbols parent and then descend to the
      // parents child symbol.
      if ((err = SymGetSymbolParent(currentSymbol, &symType, &parentSymbol))
         != GOOD)
         return err;
      symPtr = (COMMON_BLOCK_HEADER HUGE *) st.GetHugeDataPtr(parentSymbol);
      sibPtr = (COMMON_BLOCK_HEADER HUGE *) 
                            st.GetHugeDataPtr(symPtr->child);
      tmpSymbol = symPtr->child;

      // this function only matches the symbol name to function names
      if (((sibPtr->symHeader.typeIndex.symType) & 0xF) == SYM_FUNCTION) {
         // search this function name and the names of all this functions;
         // siblings
         do {
            
            st.GetString(sibPtr->symHeader.symbolNameOffset,name);

            // if the names match then this routine is done
            if ( !strcmp(symName, (S8 *)name) ) {
               *offsetFound = tmpSymbol;
               return GOOD;
            }
       
            // the names didn't match so find the next sibling FUNCTION
            // and check to see if it matches.
            do {
               if((err = SymGetSymbolSibling(tmpSymbol, &sibType, 
                  &siblingSymbol)) != GOOD)
                  return err;
            } while ( siblingSymbol && !(sibType == SYM_FUNCTION));
            
            if (siblingSymbol) {
               sibPtr = (COMMON_BLOCK_HEADER HUGE *)
                        st.GetHugeDataPtr(siblingSymbol);
               tmpSymbol = siblingSymbol;
            }
            
            // if siblingSymbol is zero there aren't any siblings
            // so exit the do loop
         } while (siblingSymbol);
      }
      // if the search above fails try again using a new "parent"
      currentSymbol = parentSymbol;
   } while (symType != SYM_MODULE);
   return GOOD;
}

//--------------------------------------------------------------------------
// SymUpdateTypeInfo
//--------------------------------------------------------------------------
RETCODE PRIVATE SymUpdateTypeInfo(TYPE_INDEX typeIndex, U32 typeMAUSize,
                                  TYPE_INDEX baseTypeIndex) {
   RETCODE err;
   TYPE_HEADER_TYPE2 HUGE *typePtr;
   TABLE_OFFSET typeOffset;

   if ((err = typit.GetOffset(typeIndex,typeOffset)) != GOOD)
      return err;
   typePtr = (TYPE_HEADER_TYPE2 HUGE *) tt.GetHugeDataPtr(typeOffset);
   
   // update the sizeInMAUs for the typeIndex if it is zero
   if (!typePtr->sizeInMAUs)
      typePtr->sizeInMAUs = typeMAUSize;

   switch (typePtr->t.complexType) {
      case TY_C_ARRAY :
      {
         TYPE_Z_STRUCT HUGE *arrayPtr; // Pointer to array info block
         arrayPtr = (TYPE_Z_STRUCT HUGE *)tt.GetHugeDataPtr(typeOffset + 
                                                  sizeof(TYPE_HEADER_TYPE2));
         if (arrayPtr->highBound)
            break; // do not need to update the highBound

         // SymGetTypeHeader to get the underlying type
         TYPE_HEADER_TYPE baseTypeHeader;
         baseTypeHeader.typeName = tmpBuf; // use the temporary buffer
         
         if ((err = SymGetTypeHeader((TYPE_INDEX)arrayPtr->typeIndex,
                                        &baseTypeHeader)) != GOOD)
            return(err);
         // NOTE: num element = Array size / element size
         if (baseTypeHeader.sizeInMAUs)
            arrayPtr->highBound = (typePtr->sizeInMAUs /
                                   baseTypeHeader.sizeInMAUs) - 1;
         break;
      }
      case TY_TYPE :
      {   
         // 08/05/94
         // Use the input type name offset for the typedef that does not
         // have a name - OMF loadfiles have these types
         if (!typePtr->typeName) {
            TYPE_HEADER_TYPE2 HUGE *baseTypeHdr = NULL;
            TABLE_OFFSET baseTypeOffset;
            // NOTE: 08/04/94 - Nghia Dereference pointer
            if ((err = typit.GetOffset(baseTypeIndex, baseTypeOffset)) != GOOD)
               return err;
            baseTypeHdr = (TYPE_HEADER_TYPE2 HUGE *)
                          tt.GetHugeDataPtr(baseTypeOffset);
            // Copy the type name offset of the base type to the target type
            typePtr->typeName = baseTypeHdr->typeName;
         }
         break;
      }
   }
   // Type is updated
   typePtr->sizeCalculated = TRUE;
   return GOOD;
}

//--------------------------------------------------------------------------
// SymCheckForNoSymbols
//
// Design:
//   Check to see if any modules loaded.  If not, check to see if
//   any symbols off the root symbol linked lists - i.e. vars, labels, const,
//   or miscellaneous
//--------------------------------------------------------------------------
RETCODE EXPORT SymCheckForNoSymbols(BOOLEAN *noSymbolsLoaded) {

   SYM_DESCRIPTOR modDesc;
   RETCODE        err;
   HPU8           ptr;

   *noSymbolsLoaded = FALSE;
   err = SymGetModuleListHead(&modDesc);
   if (ER_SYM_NO_MODULES_LOADED == err) {
      // now check for any publics chained off root node

      ptr = st.GetHugeDataPtr(rootOffset);
      if ((NULL_SYMBOL == 
            ((COMMON_BLOCK_HEADER *)ptr)->list.varListOffset) &&
          (NULL_SYMBOL == 
            ((COMMON_BLOCK_HEADER *)ptr)->list.labelListOffset) &&
          (NULL_SYMBOL ==
            ((COMMON_BLOCK_HEADER *)ptr)->list.constListOffset) &&
          (NULL_SYMBOL ==
            ((COMMON_BLOCK_HEADER *)ptr)->list.miscListOffset)) {
         *noSymbolsLoaded = TRUE;
      }
   }
   return GOOD;
}  // end of SymCheckForNoSymbols


//--------------------------------------------------------------------------
// SymGetBaseAddress
//--------------------------------------------------------------------------
RETCODE EXPORT SymGetBaseAddress(BASE_INDEX baseIndex,
                                 BASE_ADDRESS *baseAddress) {
   RETCODE err;
   TABLE_OFFSET baseOffset;
   BaseSymbol HUGE *base;
   
   // check to make sure the base exists
   if ((err = bit.GetOffset(baseIndex,baseOffset)) != GOOD)
      return err;
   
   // get a pointer to the base symbol
   base = (BaseSymbol HUGE*) st.GetHugeDataPtr(baseOffset);
   *baseAddress = base->GetBaseAddress();
   return GOOD;
}

//--------------------------------------------------------------------------
// SymGetEndList
//--------------------------------------------------------------------------
RETCODE EXPORT SymGetEndList(SYM_DESCRIPTOR inputSymbol, 
                             SYM_TYPE_TYPE symType, SYM_DESCRIPTOR *endList) {

   COMMON_SYMBOL_HEADER HUGE *symPtr;
   RETCODE      err;
   TABLE_OFFSET nextOffset = NULL_SYMBOL, tmpOffset, listHead = NULL_SYMBOL;
   U16          i, count;
   U8           tmpSymType;
   
   // make sure the symbol descriptor is ok
   if (!UtilIsValidSymDescriptor(inputSymbol))
      return ER_INVALID_SYM_DESCRIPTOR;

   // make sure the input symbol has a set of linked lists
   symPtr = (COMMON_SYMBOL_HEADER HUGE *) st.GetHugeDataPtr(inputSymbol);
   tmpSymType = (U8)((symPtr->typeIndex.symType) & 0xF);

   if (!((tmpSymType == SYM_MODULE)  ||
        (tmpSymType == SYM_FUNCTION) ||
        (tmpSymType == SYM_BLOCK)    ||
        (tmpSymType == SYM_ROOT))) {
      return ER_SYMBOL_NOT_A_MODULE;
   }
   
   if((err = SymGetSymbolHeadList(inputSymbol, symType, &listHead, &count))
      != GOOD)
      return err;

   // 10/12/94 - Nghia
   // Fixed PPR 9801 - Load Bristol Babcock /customer/386real/bristol/boot
   // /SYS333.OMF get GPF. - When SymGetEndList() with 1 element in list,
   // the nextOffset is not initialized and return the correct value if
   // count is 1.
   
   // find the last element in the label list if the list has entries.
   if (count) {
      i = count - 1;
      // if count == 1, nextOffset = listHead.
      tmpOffset = nextOffset = listHead;
      while (i--) {
         if ((err = SymGetSymbolSibling(tmpOffset, &symType, &nextOffset))
            != GOOD)
            return err;
         tmpOffset = nextOffset;
      }
   }
   // pass back the end of the list
   *endList = nextOffset;
   return GOOD;
}
                              
//--------------------------------------------------------------------------
// SymGetFunc
//--------------------------------------------------------------------------
RETCODE EXPORT
SymGetFunc(SYM_DESCRIPTOR inputSymbol,
           LPSTR          funcName,
           FUNC_CLASS     *funcClass,
           U32            *stackSize,
           ADDR_RANGE_TYPE *codeAddrRange) {
   
   SYM_TYPE_FUNCTION HUGE *funcPtr;
   U8                tmpArray[MAX_SYMNAME_LENGTH];
   
   // make sure the symbol descriptor is ok
   if (!UtilIsValidSymDescriptor(inputSymbol))
      return ER_INVALID_SYM_DESCRIPTOR;

   // find out if inputSymbol points to a function
   funcPtr=(SYM_TYPE_FUNCTION HUGE *)st.GetHugeDataPtr(inputSymbol);
   if (((funcPtr->symHeader.symHeader.typeIndex.symType) & 0xF ) !=
      SYM_FUNCTION)
      return ER_SYMBOL_NOT_A_FUNCTION;
   *funcClass=funcPtr->funcClass;
   *stackSize=funcPtr->stackSpace;

   // fix up the address range
   codeAddrRange->segType = (SEGMENTTYPE)
                  funcPtr->symHeader.symHeader.typeIndex.baseIndex;
   codeAddrRange->startAddr =
                  funcPtr->symHeader.symHeader.beginAddrInfo.startAddr;
   codeAddrRange->endAddr =
                  funcPtr->symHeader.symHeader.endAddrInfo.endAddr;

   st.GetString(funcPtr->symHeader.symHeader.symbolNameOffset,(LPU8)tmpArray);
   strcpy(funcName,(S8 *)tmpArray);
   return GOOD;
}

//--------------------------------------------------------------------------
// SymGetFuncByName
//--------------------------------------------------------------------------
RETCODE EXPORT SymGetFuncByName(SYM_DESCRIPTOR inputSymbol, LPSTR funcName, 
                                SYM_DESCRIPTOR *symDesc) {
   
   RETCODE err;
   COMMON_SYMBOL_HEADER HUGE *symPtr;
   SYM_TYPE_TYPE symType;
   SYM_DESCRIPTOR symOffset,sibOffset;
   U8 name[MAX_SYMNAME_LENGTH];

   // make sure the symbol descriptor is ok
   if (!UtilIsValidSymDescriptor(inputSymbol))
      return ER_INVALID_SYM_DESCRIPTOR;

   // get a pointer to the symbol passed in
   symPtr = (COMMON_SYMBOL_HEADER HUGE *)st.GetHugeDataPtr(inputSymbol);
   
   if (((symPtr->typeIndex.symType) & 0xF) != SYM_MODULE)
      return ER_SYMBOL_NOT_A_MODULE;
   
   // find the first function attached to this module
   // it should be the module's immediate child
   do {
      if ((err = SymGetSymbolChild(inputSymbol, &symType, &symOffset)) 
         != GOOD)
         return err;
   } while ( (symType != SYM_FUNCTION) && (NULL_SYMBOL != symOffset));
   
   // if symOffset was zero then we didn't find a function attached
   // to this module.
   if (!symOffset)
      return ER_SYMBOL_NOT_FOUND;
   
   // check to see if the the name passed in matches the first function;
   // found.
   symPtr = (COMMON_SYMBOL_HEADER HUGE *) st.GetHugeDataPtr(symOffset);
   st.GetString(symPtr->symbolNameOffset,name);
   if (!strcmp(funcName,(S8 *) name)) {
      *symDesc = symOffset;
      return GOOD;
   }

   // search all of this functions siblings for a name match
   do {
      if ((err = SymGetSymbolSibling(symOffset, &symType, &sibOffset)) 
         != GOOD)
         return err;
      if(sibOffset) {
         symPtr = (COMMON_SYMBOL_HEADER HUGE *) st.GetHugeDataPtr(sibOffset);
         st.GetString(symPtr->symbolNameOffset,name);
         symOffset = sibOffset;
      }
   } while ( (strcmp((S8 *)name,funcName)) && sibOffset);
   
   // if the sibOffset is zero we didn't find a name match
   if (!sibOffset)
      return ER_SYMBOL_NOT_FOUND;
   
   // a match was found.  
   *symDesc = sibOffset;
   return GOOD;
}
   
//--------------------------------------------------------------------------
// SymGetFuncParamNth
//--------------------------------------------------------------------------
RETCODE EXPORT SymGetFuncParamNth(SYM_DESCRIPTOR functionSymbol,
                                  U8 n, TYPE_HEADER_TYPE *typeHeader) {
   RETCODE err;
   TABLE_OFFSET offset;
   SYM_TYPE_FUNCTION HUGE *funcPtr;
   FUNC_TYPE_HEADER HUGE *funcHdr;
   TYPE_INDEX HUGE *argPtr;

   // make sure the symbol descriptor is ok
   if (!UtilIsValidSymDescriptor(functionSymbol))
      return ER_INVALID_SYM_DESCRIPTOR;

   funcPtr = (SYM_TYPE_FUNCTION HUGE *)st.GetHugeDataPtr(functionSymbol);
   
   if ((funcPtr->symHeader.symHeader.typeIndex.symType & 0xF)
       != SYM_FUNCTION) 
      return ER_SYMBOL_NOT_A_FUNCTION;
   
   // get the offset in the type table of the header requested
   if ((err = typit.GetOffset(funcPtr->typeIndex, offset)) != GOOD) 
      return err;
   
   funcHdr = (FUNC_TYPE_HEADER HUGE *)tt.GetHugeDataPtr(offset);
   
   if ( n > funcHdr->argCount)
      return ER_ARRAY_INDEX_TOO_LARGE;
   
   // point to the n'th type index
   argPtr = (TYPE_INDEX HUGE *)tt.GetHugeDataPtr( offset + 
            sizeof(TYPE_HEADER_TYPE2) + ((n-1) * sizeof(TYPE_INDEX)));

   // get the typeheader and pass it directly back to the caller
   if ((err = SymGetTypeHeader(*argPtr,typeHeader)) != GOOD)
      return err;
   
   return GOOD;
}  // end of SymGetFuncParamNth


//--------------------------------------------------------------------------
// SymGetFuncReturnTypeIndex
//--------------------------------------------------------------------------
RETCODE EXPORT
SymGetFuncReturnTypeIndex(SYM_DESCRIPTOR inputSymbol,
                          TYPE_INDEX FAR *returnType) {

   RETCODE err;
   TABLE_OFFSET           offset;
   SYM_TYPE_FUNCTION HUGE *funcPtr;
   FUNC_TYPE_HEADER  HUGE *funcHdr;

   // make sure the symbol descriptor is ok
   if (!UtilIsValidSymDescriptor(inputSymbol))
      return ER_INVALID_SYM_DESCRIPTOR;

   funcPtr = (SYM_TYPE_FUNCTION HUGE *)st.GetHugeDataPtr(inputSymbol);
   
   if (((funcPtr->symHeader.symHeader.typeIndex.symType) & 0xF) !=
      SYM_FUNCTION) 
      return ER_SYMBOL_NOT_A_FUNCTION;
   
   // get the offset in the type table of the header requested
   if ((err = typit.GetOffset(funcPtr->typeIndex, offset)) != GOOD) 
      return err;
   
   funcHdr = (FUNC_TYPE_HEADER HUGE *)tt.GetHugeDataPtr(offset + 
                                     sizeof(TYPE_HEADER_TYPE2));
   
   // fill in the return type header
   *returnType = funcHdr->returnType;

   return GOOD;
}  // end of SymGetFuncReturnTypeIndex


//--------------------------------------------------------------------------
// SymGetFuncType
//--------------------------------------------------------------------------
RETCODE EXPORT SymGetFuncType(SYM_DESCRIPTOR   inputSymbol,
                              U32              *attribute,
                              U8               *frameType,
                              U32              *pushMask,
                              TYPE_HEADER_TYPE *returnType,
                              U8               *argCount,
                              U8               *level,
                              LPSTR            fatherName) {

   RETCODE                err;
   TABLE_OFFSET           offset;
   SYM_TYPE_FUNCTION HUGE *funcPtr;
   FUNC_TYPE_HEADER  HUGE *funcHdr;

   // make sure the symbol descriptor is ok
   if (!UtilIsValidSymDescriptor(inputSymbol))
      return ER_INVALID_SYM_DESCRIPTOR;

   funcPtr = (SYM_TYPE_FUNCTION HUGE *)st.GetHugeDataPtr(inputSymbol);
   
   if (((funcPtr->symHeader.symHeader.typeIndex.symType) & 0xF) !=
      SYM_FUNCTION) 
      return ER_SYMBOL_NOT_A_FUNCTION;
   
   // get the offset in the type table of the header requested
   if ((err = typit.GetOffset(funcPtr->typeIndex, offset)) != GOOD) 
      return err;
   
   funcHdr = (FUNC_TYPE_HEADER HUGE *)tt.GetHugeDataPtr(offset + 
                                     sizeof(TYPE_HEADER_TYPE2));
   
   *attribute = funcHdr->attribute;
   *frameType = funcHdr->frameType;
   *pushMask = funcHdr->pushMask;
   *argCount = funcHdr->argCount;
   *level = funcHdr->level;
   
   // fill in the return type header
   if ((err = SymGetTypeHeader(funcHdr->returnType, returnType)) != GOOD)
      return err;

   // get and copy the father name if it exists, else return a null
   if (!funcHdr->fatherName) {
      *fatherName = 0L;
   } else {
      U8 name[MAX_SYMNAME_LENGTH];
      
      // get the name out of the symbol table;
      st.GetString(funcHdr->fatherName,name);
      // copy the name to requester
      strcpy(fatherName,(S8 *)name);
   }

   return GOOD;
}

//--------------------------------------------------------------------------
// SymGetFuncVarHeadList
//
// Purpose:
//   Gets symbol descriptor to function variable list and the number
//      of variables in the list.
//   Also does on-demand load of this function's local variables if needed
//
// Design:
//   check for valid function descriptor
//   get the variable list pointer; if NULL_SYMBOL, call on-demand load
//   get the varList pointer and list count
//--------------------------------------------------------------------------
RETCODE EXPORT
SymGetFuncVarHeadList(SYM_DESCRIPTOR funcDesc,
                      SYM_DESCRIPTOR *varList,
                      U16            *listCount)  {

   SYM_TYPE_FUNCTION HUGE *funcPtr;
   RETCODE           retCode;

   // check for valid symbol descriptor input
   if (!UtilIsValidSymDescriptor(funcDesc))
      return ER_INVALID_SYM_DESCRIPTOR;

   funcPtr = (SYM_TYPE_FUNCTION HUGE *)st.GetHugeDataPtr(funcDesc);
   if (((funcPtr->symHeader.symHeader.typeIndex.symType) & 0xF) !=
      SYM_FUNCTION)
      return ER_SYMBOL_NOT_A_FUNCTION;

   if (funcPtr->symHeader.list.varListOffset == NULL_SYMBOL)  {
      if(SUCCESS != (retCode = UtilOnDemandLoad(funcDesc)))
         return retCode;
      }

   return SymGetSymbolHeadList(funcDesc, SYM_LOCAL_VAR, varList, listCount);
}  // end of SymGetFuncVarHeadList

//-------------------------------------------------------------------------  
// SymGetLabel
//-------------------------------------------------------------------------  
RETCODE EXPORT SymGetLabel(SYM_DESCRIPTOR inputSymbol, LPSTR labelName,
                           ADDR_RANGE_TYPE *codeAddrRange) {
   COMMON_SYMBOL_HEADER HUGE *labelPtr;
   U8 tmpArray[MAX_SYMNAME_LENGTH];   
   
   // make sure the symbol descriptor is ok
   if (!UtilIsValidSymDescriptor(inputSymbol))
      return ER_INVALID_SYM_DESCRIPTOR;

   labelPtr = (COMMON_SYMBOL_HEADER HUGE *)st.GetHugeDataPtr(inputSymbol);
   // check to make sure this is a label
   if (((labelPtr->typeIndex.symType) & 0xF) != SYM_LABEL) 
      return ER_SYMBOL_NOT_A_LABEL;
   // fix up the address range
   codeAddrRange->segType = (SEGMENTTYPE)labelPtr->typeIndex.baseIndex;
   codeAddrRange->startAddr = labelPtr->beginAddrInfo.startAddr;
   codeAddrRange->endAddr =   labelPtr->endAddrInfo.endAddr;
             
   st.GetString(labelPtr->symbolNameOffset,(LPU8)tmpArray);
   strcpy(labelName,(char *)tmpArray);
   return GOOD;
}

//-------------------------------------------------------------------------  
// SymGetModule
//
//    Returns module name and address
//-------------------------------------------------------------------------  
RETCODE EXPORT
SymGetModule(SYM_DESCRIPTOR inputModule,
             LPSTR          moduleName,
             ADDR_RANGE_TYPE *moduleAddrRange) {

   SYM_TYPE_FUNCTION HUGE *modPtr;
   U8 tmpArray[MAX_SYMNAME_LENGTH];
//   RETCODE err;


   // make sure the symbol descriptor is ok
   if (!UtilIsValidSymDescriptor(inputModule))
      return ER_INVALID_SYM_DESCRIPTOR;

   // find out if inputSymbol points to a module
   modPtr=(SYM_TYPE_FUNCTION HUGE *)st.GetHugeDataPtr(inputModule);
   if (((modPtr->symHeader.symHeader.typeIndex.symType) & 0xF) != SYM_MODULE)
      return ER_SYMBOL_NOT_A_MODULE;

   // fix up the address range
   // NOTES: 09/07/93 - Nghia
   // Continue to retrieve information about the module although there might
   // be an error occurred in setting its address range.  Data modules will
   // always have invalid address range.
   moduleAddrRange->segType = (SEGMENTTYPE)
                    modPtr -> symHeader.symHeader.typeIndex.baseIndex;
   moduleAddrRange->startAddr =
                    modPtr -> symHeader.symHeader.beginAddrInfo.startAddr;
   moduleAddrRange->endAddr = modPtr -> symHeader.symHeader.endAddrInfo.endAddr;

   // get symbol name   
   st.GetString(modPtr->symHeader.symHeader.symbolNameOffset,(LPU8)tmpArray);

   // remove two control characters
   strcpy(moduleName,(S8 *)&tmpArray[2]);
   return( GOOD );
//   return(err);

}  // end of SymGetModule


//-------------------------------------------------------------------------  
// SymGetModuleDesc
//-------------------------------------------------------------------------  
RETCODE EXPORT SymGetModuleDesc(LPSTR moduleName,
                                LPSTR pathName,
                                SYM_DESCRIPTOR *moduleOffset) {
   RETCODE err;
   U8 tmpArray[MAX_SYMNAME_LENGTH], misses;
   U8 pathNameArray[MAX_PATH_LENGTH];
   U8 entry;
   U8 pathLength;
   SYM_TYPE_MODULE HUGE *modPtr;

   // look through the hash table for the module name
   // if the path name length is 0, return first match
   // if not 0 length, compare path on each try

   pathLength = (U8)lstrlen(pathName);
   entry = 1;
   while (TRUE)  {
      sprintf((LPSTR) tmpArray, (LPSTR)"%c%c%s", 0x1, entry, moduleName);
      if ((err = ht.LookupName((LPSTR) tmpArray, *moduleOffset, misses))
         != GOOD) 
         return err; 
      if (!*moduleOffset)
         return ER_SYMBOL_NOT_FOUND;

      // check path length for zero length
      if (!pathLength)
         return SUCCESS;

      // get offset to module path string
      modPtr = (SYM_TYPE_MODULE HUGE *)st.GetHugeDataPtr(*moduleOffset);

      // compare path name to module stored path name
      st.GetString(modPtr -> srcFilenameOffset, pathNameArray);
      if (!lstrcmp(pathName, (LPSTR)pathNameArray))  {
         return SUCCESS;
      }
      entry++;
   }
}

//-------------------------------------------------------------------------  
// SymGetModuleDesc
//-------------------------------------------------------------------------  
/*
RETCODE EXPORT SymGetModuleDesc(LPSTR moduleName,
                                LPSTR pathName,
                                SYM_DESCRIPTOR *moduleOffset) {
    char *temp , *temp1;
    RETCODE err;
    
    if ( GOOD==SymGetModuleDescCase(moduleName,pathName,moduleOffset) ) 
        return GOOD;
    temp = new char [ strlen(moduleName)+1 ];
    strcpy( temp , moduleName );
    temp1 = strupr(temp);
    if ( GOOD!=(err=SymGetModuleDescCase(temp1,pathName,moduleOffset))) {
        strcpy( temp , moduleName );
        temp1 = strlwr(temp);
        if ( GOOD!=(err=SymGetModuleDescCase(temp1,pathName,moduleOffset))) {
            delete temp;    
            return err;
        }
    }
    delete temp;
    return GOOD;
}
*/

//-------------------------------------------------------------------------  
// SymGetModuleDescNth
//-------------------------------------------------------------------------  
RETCODE EXPORT SymGetModuleDescNth(LPSTR moduleName, U8 entry, 
                                   SYM_DESCRIPTOR *moduleOffset) {
   RETCODE err;
   U8 tmpArray[MAX_PATH_LENGTH], misses;

   // look through the hash table for the nth module name

   sprintf((LPSTR) tmpArray, (LPSTR)"%c%c%s",0x1,entry,moduleName);
   if ((err = ht.LookupName((LPSTR) tmpArray, *moduleOffset, misses))
      != GOOD)
      return err;
   if (!*moduleOffset)
      return ER_SYMBOL_NOT_FOUND;
   return GOOD;
}

//-------------------------------------------------------------------------  
// SymGetModuleListHead
//-------------------------------------------------------------------------  
RETCODE EXPORT SymGetModuleListHead(SYM_DESCRIPTOR *moduleDescriptor) {
   RETCODE err;
   SYM_TYPE_TYPE symType;

   // the first child entry off of the root should be the head of the
   // module linked list.
   if (GOOD != (err = SymGetSymbolChild(rootOffset,
                                        &symType,
                                        moduleDescriptor)))
      return err;
   if (NULL_SYMBOL == *moduleDescriptor) {
      return ER_SYM_NO_MODULES_LOADED;
   }
   if (symType != SYM_MODULE)
      return ER_SYMBOL_NOT_A_MODULE;
   return GOOD;
}

//-------------------------------------------------------------------------  
// SymGetModuleRef
//-------------------------------------------------------------------------  
RETCODE EXPORT SymGetModuleRef(SYM_DESCRIPTOR inputSymbol, 
                               LPSTR moduleReference) {
   
   SYM_TYPE_MODULE HUGE *modPtr;
   U8 tmpArray[MAX_SYMNAME_LENGTH];
   
   // make sure the symbol descriptor is ok
   if (!UtilIsValidSymDescriptor(inputSymbol))
      return ER_INVALID_SYM_DESCRIPTOR;

   // find out if inputSymbol points to a module
   modPtr=(SYM_TYPE_MODULE HUGE *)st.GetHugeDataPtr(inputSymbol);
   if (((modPtr->symHeader.symHeader.typeIndex.symType) & 0xF) != SYM_MODULE)
      return ER_SYMBOL_NOT_A_MODULE;
   st.GetString(modPtr->srcFilenameOffset,(LPU8)tmpArray);
   strcpy(moduleReference,(S8 *)tmpArray);
   return GOOD;
}

//-------------------------------------------------------------------------  
// SymGetModuleSourceFilePosition
//-------------------------------------------------------------------------  
RETCODE EXPORT SymGetModuleSourceFilePosition(SYM_DESCRIPTOR inputSymbol,
                                              U32 *srcFileOffset) {
   
   SYM_TYPE_MODULE HUGE *modPtr;
   
   // make sure the symbol descriptor is ok
   if (!UtilIsValidSymDescriptor(inputSymbol))
      return ER_INVALID_SYM_DESCRIPTOR;

   // find out if inputSymbol points to a module
   modPtr=(SYM_TYPE_MODULE HUGE *)st.GetHugeDataPtr(inputSymbol);
   if (((modPtr->symHeader.symHeader.typeIndex.symType) & 0xF) != SYM_MODULE)
      return ER_SYMBOL_NOT_A_MODULE;
   *srcFileOffset = modPtr->srcFilePosition;

   return GOOD;
}

//-------------------------------------------------------------------------  
// SymGetModuleTimestamp
//-------------------------------------------------------------------------  
RETCODE EXPORT SymGetModuleTimestamp(SYM_DESCRIPTOR inputSymbol, 
                                     TIMESTAMP_TYPE *timestamp) {
   
   SYM_TYPE_MODULE HUGE *modPtr;

   // make sure the symbol descriptor is ok
   if (!UtilIsValidSymDescriptor(inputSymbol))
      return ER_INVALID_SYM_DESCRIPTOR;

   // find out if inputSymbol points to a module
   modPtr = (SYM_TYPE_MODULE HUGE *)st.GetHugeDataPtr(inputSymbol);
   if (((modPtr->symHeader.symHeader.typeIndex.symType) & 0xF) != SYM_MODULE)
      return ER_SYMBOL_NOT_A_MODULE;
   *timestamp = modPtr->timestamp;
   return GOOD;
}

//-------------------------------------------------------------------------  
// SymGetSymbolAddress
//-------------------------------------------------------------------------  
RETCODE EXPORT
SymGetSymbolAddress(SYM_DESCRIPTOR inputSymbol,
                    ADDR_RANGE_TYPE *symbolAddr) {

   HPU8 symPtr;

   // make sure the symbol descriptor is ok
   if (!UtilIsValidSymDescriptor(inputSymbol))
      return ER_INVALID_SYM_DESCRIPTOR;

   symPtr =(HPU8)st.GetHugeDataPtr(inputSymbol);

   if (SYM_LOCAL_VAR == 
      ((((COMMON_SYMBOL_HEADER HUGE *)symPtr)->typeIndex.symType) & 0xF)) {
      switch (((SYM_TYPE_VARIABLE HUGE *)symPtr)->storageClass) {
         case AUTO_VAR_CLASS:
         case BASED_VAR_CLASS:
            return ER_SYM_LOCAL_VAR_ADDRESS;
      }
   }
   symbolAddr->segType =
     (SEGMENTTYPE)(((COMMON_SYMBOL_HEADER HUGE *)symPtr)->typeIndex.baseIndex);
   symbolAddr->startAddr =
          ((COMMON_SYMBOL_HEADER HUGE *)symPtr)->beginAddrInfo.startAddr;
   symbolAddr->endAddr =
          ((COMMON_SYMBOL_HEADER HUGE *)symPtr)->endAddrInfo.endAddr;
   return GOOD;
} // end of SymGetSymbolAddress

//-------------------------------------------------------------------------  
// SymGetSymbolChild
//-------------------------------------------------------------------------  
RETCODE EXPORT SymGetSymbolChild(SYM_DESCRIPTOR inputSymbol, 
                                 SYM_TYPE_TYPE  *symType, 
                                 SYM_DESCRIPTOR *nextSymbol ) {
   
   COMMON_BLOCK_HEADER HUGE *blockPtr;
   U8                       tmpSymType;
   
   // make sure the symbol descriptor is ok
   if (!UtilIsValidSymDescriptor(inputSymbol))
      return ER_INVALID_SYM_DESCRIPTOR;

   // find out if inputSymbol points to a symbol that has a child
   blockPtr = (COMMON_BLOCK_HEADER HUGE *)st.GetHugeDataPtr(inputSymbol);

   tmpSymType = (U8)((blockPtr->symHeader.typeIndex.symType) & 0xF);
   if (!((tmpSymType == SYM_MODULE) 
      || (tmpSymType == SYM_ROOT)
      || (tmpSymType == SYM_FUNCTION)
      || (tmpSymType == SYM_BLOCK))) {
      return ER_SYMBOL_HAS_NO_CHILD;
   } else {
      *nextSymbol = ((COMMON_BLOCK_HEADER *)blockPtr)->child;
      if (*nextSymbol == NULL_SYMBOL)
         return GOOD;  // no child; nextSymbol is NULL_SYMBOL
      blockPtr = (COMMON_BLOCK_HEADER HUGE *)st.GetHugeDataPtr(*nextSymbol);
      *symType = (SYM_TYPE_TYPE)((blockPtr->symHeader.typeIndex.symType) & 0xF);
   }
   return GOOD;
}

//-------------------------------------------------------------------------  
// SymGetSymbolFromContext
//
// Purpose:
//    Given a descriptor into the symbol table, look up an item with the
//    name <symName> and type <symType>.  Return a descriptor to it, its
//    type, and whether it is global or not.  This routine is used to look up
//    a symbol local to an already-established context, esp. after a
//    breakpoint.
//
// Input parameters:
//    inputSymbol:
//       base level context from which to search; can be module, function,
//       or block.  If NULL_SYMBOL, the name is looked up from global hash
//       table
//    symName:
//       long pointer to the name to be looked up.
//    symType:
//       indicates the type to be looked up.  If set to SYM_UNDEFINED, then
//       also used as an output for the type found that matches the name.
//
// Output parameters:
//    symType:
//       If set to SYM_UNDEFINED on entry to the function, the search is
//       made within the variable, label, or constant linked list off the
//       input symbol.  If not found, the symbol parent is used, etc until
//       the root symbol stops the process.  symType is set as output
//       to hold the type found that matches the name.  If name not found,
//       value stays SYM_UNDEFINED.  
//    outputSymbol:
//       descriptor to symbol found; it can
//       be used in subsequent call to get detailed information.
//    isGlobal:
//       TRUE if either the symbol found is global or there is
//       a matching global symbol name; otherwise it is FALSE
//
//    This function currently makes the assumption the item being asked for
//    is not complex (ie. x.y.z).
//
//    If <inputSymbol> is a module and *symType == SYM_UNDEFINED,
//    search its lists for matching name
//
// Error:
//    reports ER_SYMBOL_NOT_FOUND if the symbol is not found.
//-------------------------------------------------------------------------  
RETCODE EXPORT
SymGetSymbolFromContext(SYM_DESCRIPTOR inputSymbol,
                        LPSTR          symName,
                        SYM_TYPE_TYPE  *symType,
                        SYM_DESCRIPTOR *outputSymbol,
                        BOOLEAN        *isGlobal) {

   COMMON_SYMBOL_HEADER HUGE *headPtr;
   RETCODE       err;
   TABLE_OFFSET  offsetFound = 0, currentOffset, tmpOffset;
   SYM_TYPE_TYPE isRootType;
   U8            name[MAX_SYMNAME_LENGTH],dummy;
   U8            tmpSymType;

   // exit if symbol name wasn't given
   if (!strlen(symName))
      return ER_CLI_SYNTAX;

   if (NULL_SYMBOL == inputSymbol)  {
      // indicates no context; make global lookup
      *symType = SYM_GLOBAL_VAR;  // fake out SW to look in hash table

   } else {  // assuming valid input symbol
      // make sure the symbol descriptor is ok
      if (!UtilIsValidSymDescriptor(inputSymbol))
         return ER_INVALID_SYM_DESCRIPTOR;

      headPtr = (COMMON_SYMBOL_HEADER HUGE *)st.GetHugeDataPtr(inputSymbol);
      tmpSymType = (U8)((headPtr->typeIndex.symType) & 0xF);
      if (!((tmpSymType == SYM_MODULE) ||
          (tmpSymType == SYM_FUNCTION) ||
          (tmpSymType == SYM_BLOCK))) {
         return ER_SYMBOL_NOT_A_FUNCTION;
      }
      // check to see if symbols have been loaded for this module.
      // if they haven't then call the loader to get them.
      if ((err = UtilOnDemandLoad(inputSymbol)) != GOOD)
         return err;
   } 
   *isGlobal = FALSE;
   switch (*symType) {
      case SYM_UNDEFINED:
         currentOffset = inputSymbol;

         // search the current scopes local symbol list.  if the
         // symbol isn't found then recursively move up in scope
         // and search all symbol lists.
         do {
            // find the base variable name
            SearchList(currentOffset,symName, SYM_LOCAL_VAR, &offsetFound);
            if (offsetFound) {
               *symType = SYM_LOCAL_VAR;
               break;
            }
            SearchList(currentOffset, symName, SYM_LABEL, &offsetFound);
            if (offsetFound) {
               *symType = SYM_LABEL;
               break;
            }
            SearchList(currentOffset, symName, SYM_CONSTANT, &offsetFound);
            if (offsetFound) {
               *symType = SYM_CONSTANT;
               break;
            }
            // move up in scope here
            if ((err = SymGetSymbolParent(currentOffset,&isRootType,
               &tmpOffset)) != GOOD) return err;
            currentOffset = tmpOffset;
         } while (isRootType != SYM_ROOT);

         // check to see if the previous "break" commands forced us to exit
         // the "while" loop because the symbol was found
         if (offsetFound)
            break;

         // check the current function name for a match and all functions
         // callable from this function inside the current module.
         // external function names will be checked later
         // do this only if there is only one name being searched for
         
         SearchUpperFuncs(inputSymbol,symName, &offsetFound);
         if (offsetFound) {
            *symType = SYM_FUNCTION;
            break;
         }

         // now check the hash table for the symbol name ; fall thru to
         // next case since code is identical

      case SYM_GLOBAL_VAR:
         // search the global hash table for the symbol
         if((err = ht.LookupName(symName, offsetFound, dummy)) != GOOD) 
            return err;
         if(offsetFound) *isGlobal = TRUE;
         break;

      case SYM_LOCAL_VAR:
         SearchList(inputSymbol,symName,SYM_LOCAL_VAR, &offsetFound);
         break;

      case SYM_FUNCTION:  

         // check the current function name for a match, this may
         // not really be necessary because of the way SearchUpperFuncs
         // works, but it'll be done anyway
         st.GetString(headPtr->symbolNameOffset,name);
         if (!strcmp((S8 *)symName,(S8 *)name)) {
            offsetFound = inputSymbol;
         }
         if (offsetFound)
            break;

         // if the current function name is not a match, check all function
         // names in the module
         SearchUpperFuncs(inputSymbol,symName, &offsetFound);
         if (offsetFound) break;

         // now check the hash table for the symbol name

         if((err = ht.LookupName(symName, offsetFound, dummy)) != GOOD) 
            return err;
         if(offsetFound) *isGlobal = TRUE;
         break;
      case SYM_BLOCK:
         // this action doesn't really make any sense in this context
         offsetFound = 0;
         return ER_SYMBOL_NOT_FOUND;

      case SYM_LABEL:  
         SearchList(inputSymbol, symName, SYM_LABEL, &offsetFound);
         break;

      case SYM_CONSTANT:  
         SearchList(inputSymbol, symName, SYM_CONSTANT, &offsetFound);
         break;

      case SYM_MISCELLANEOUS:  
         SearchList(inputSymbol, symName, SYM_MISCELLANEOUS, &offsetFound);
         break;

      default:
         offsetFound = 0;
         return ER_UNKNOWN_LIST_TYPE;
   }
   // the base name was not found in any of the lists/tables
// Changed by Gates Hua , for search one symbol prefix '_'
//   if(!offsetFound) {
//      return ER_SYMBOL_NOT_FOUND;
//   }
   if ( !offsetFound ) {
       *isGlobal = FALSE;
       char *tt;
       int i,j;
       tt = new char[ strlen(symName) + 2 ];
       if ( tt == 0 ) return (-1);
       strcpy( tt, symName );
       i = strlen( symName );
       j = i;
       for(int ii=i;ii>=1;ii--) {
          tt[ii] = tt[ii-1];
       }
       tt[0] = '_';
       tt[i+1] = '\0';
/*
       while( j ) {
          if ( tt[j-1] == '#') {
            for(int ii=i;ii>=j;ii--) {
               tt[ii] = tt[ii-1];
            }
            tt[j] = '_';
            tt[i+1] = '\0';
            break;
          }
          j--;
       }
*/
       switch (*symType) {
          case SYM_UNDEFINED:
             currentOffset = inputSymbol;

             // search the current scopes local symbol list.  if the
             // symbol isn't found then recursively move up in scope
             // and search all symbol lists.
             do {
                // find the base variable name
                SearchList(currentOffset,tt, SYM_LOCAL_VAR, &offsetFound);
                if (offsetFound) {
                   *symType = SYM_LOCAL_VAR;
                   break;
                }
                SearchList(currentOffset, tt, SYM_LABEL, &offsetFound);
                if (offsetFound) {
                   *symType = SYM_LABEL;
                   break;
                }
                SearchList(currentOffset, tt, SYM_CONSTANT, &offsetFound);
                if (offsetFound) {
                   *symType = SYM_CONSTANT;
                   break;
                }
                // move up in scope here
                if ((err = SymGetSymbolParent(currentOffset,&isRootType,
                   &tmpOffset)) != GOOD) return err;
                currentOffset = tmpOffset;
             } while (isRootType != SYM_ROOT);

             // check to see if the previous "break" commands forced us to exit
             // the "while" loop because the symbol was found
             if (offsetFound)
                break;

             // check the current function name for a match and all functions
             // callable from this function inside the current module.
             // external function names will be checked later
             // do this only if there is only one name being searched for

             SearchUpperFuncs(inputSymbol,tt, &offsetFound);
             if (offsetFound) {
                *symType = SYM_FUNCTION;
                break;
             }

             // now check the hash table for the symbol name ; fall thru to
             // next case since code is identical

          case SYM_GLOBAL_VAR:
             // search the global hash table for the symbol
             if((err = ht.LookupName(tt, offsetFound, dummy)) != GOOD)
                return err;
             if(offsetFound) *isGlobal = TRUE;
             break;

          case SYM_LOCAL_VAR:
             SearchList(inputSymbol,tt,SYM_LOCAL_VAR, &offsetFound);
             break;

          case SYM_FUNCTION:

             // check the current function name for a match, this may
             // not really be necessary because of the way SearchUpperFuncs
             // works, but it'll be done anyway
             st.GetString(headPtr->symbolNameOffset,name);
             if (!strcmp((S8 *)tt,(S8 *)name)) {
                offsetFound = inputSymbol;
             }
             if (offsetFound)
                break;

             // if the current function name is not a match, check all function
             // names in the module
             SearchUpperFuncs(inputSymbol,tt, &offsetFound);
             if (offsetFound) break;

             // now check the hash table for the symbol name

             if((err = ht.LookupName(tt, offsetFound, dummy)) != GOOD)
                return err;
             if(offsetFound) *isGlobal = TRUE;
             break;
          case SYM_BLOCK:
             // this action doesn't really make any sense in this context
             offsetFound = 0;
             return ER_SYMBOL_NOT_FOUND;

          case SYM_LABEL:
             SearchList(inputSymbol, tt, SYM_LABEL, &offsetFound);
             break;

          case SYM_CONSTANT:
             SearchList(inputSymbol, tt, SYM_CONSTANT, &offsetFound);
             break;

          case SYM_MISCELLANEOUS:
             SearchList(inputSymbol, tt, SYM_MISCELLANEOUS, &offsetFound);
             break;

          default:
             offsetFound = 0;
             return ER_UNKNOWN_LIST_TYPE;
       }
       if ( tt ) delete tt;
       if(!offsetFound) {
          return ER_SYMBOL_NOT_FOUND;
       }
   }
   
   *outputSymbol = offsetFound;
   
   // get the symbols type info and pass it back
   headPtr = (COMMON_SYMBOL_HEADER HUGE *)st.GetHugeDataPtr(offsetFound);
   *symType = (SYM_TYPE_TYPE)(headPtr->typeIndex.symType & 0xF);
   
   return GOOD;
}

//--------------------------------------------------------------------------
// SymGetSymbolHeadList
//--------------------------------------------------------------------------
RETCODE EXPORT SymGetSymbolHeadList(SYM_DESCRIPTOR inputSymbol, 
                                    SYM_TYPE_TYPE  basicSymType,
                                    SYM_DESCRIPTOR *list,
                                    U16            *listCount) {
   
   HPU8 ptr;
   PACKED_TYPE_INDEX typeIndex;
   SYM_TYPE_TYPE tmpSymType;

   // make sure the symbol descriptor is ok
   if (!UtilIsValidSymDescriptor(inputSymbol))
      return ER_INVALID_SYM_DESCRIPTOR;

   // find out if inputSymbol points to a symbol that has linked lists
   ptr=st.GetHugeDataPtr(inputSymbol);
   typeIndex = ((COMMON_BLOCK_HEADER *)ptr)->symHeader.typeIndex;
   tmpSymType = (SYM_TYPE_TYPE)(typeIndex.symType & 0xF);

   if( !((tmpSymType == SYM_ROOT) 
      || (tmpSymType == SYM_MODULE) 
      || (tmpSymType == SYM_FUNCTION)
      || (tmpSymType == SYM_BLOCK))) {

      return ER_SYMBOL_HAS_NO_LISTS;
   } else {
      // get a ptr to the beginning of the list requested
      switch(basicSymType) {
         case SYM_GLOBAL_VAR:
         case SYM_LOCAL_VAR:
            // if the offset is 0, there aren't any elements in the list
            *list = ((COMMON_BLOCK_HEADER *)ptr)->list.varListOffset;
         break;

         case SYM_LABEL:
            // if the offset is 0, there aren't any elements in the list
            *list = ((COMMON_BLOCK_HEADER *)ptr)->list.labelListOffset;
         break;

         case SYM_CONSTANT:
            // if the offset is 0, there aren't any elements in the list
            *list = ((COMMON_BLOCK_HEADER *)ptr)->list.constListOffset;
         break;

         case SYM_MISCELLANEOUS:
            // if the offset is 0, there aren't any elements in the list
            *list = ((COMMON_BLOCK_HEADER *)ptr)->list.miscListOffset;
         break;
         
         default:
            return ER_UNKNOWN_LIST_TYPE;
      }
      // if the list is empty we're done
      if (!*list) {
         *listCount = 0;
         return GOOD;
      }
      // now find out how many items are in the list
      ptr=st.GetHugeDataPtr(*list);
      *listCount=1;
      while(
         ((COMMON_BLOCK_HEADER *)ptr)->symHeader.symSiblingOffset) {
         
         (*listCount)++;
         ptr=st.GetHugeDataPtr(
            ((COMMON_BLOCK_HEADER *)ptr)->symHeader.symSiblingOffset
            );
      }
   }
   return GOOD;
}

//--------------------------------------------------------------------------
// SymGetSymbolName
//
// NOTE: works for symbols including module (special case)
//--------------------------------------------------------------------------
RETCODE EXPORT
SymGetSymbolName(SYM_DESCRIPTOR     inputSymbol,
                 LPSTR              *symbolName) {

   S8 tmpArray[MAX_SYMNAME_LENGTH];
   COMMON_SYMBOL_HEADER HUGE *symPtr;
   U16 strLen;

   // make sure the symbol descriptor is ok
   if (!UtilIsValidSymDescriptor(inputSymbol)) {
      *symbolName = TMalloc(1L);
      **symbolName = '\0';
      return ER_INVALID_SYM_DESCRIPTOR;
   }
   symPtr=(COMMON_SYMBOL_HEADER HUGE *)st.GetHugeDataPtr(inputSymbol);

   st.GetString(symPtr->symbolNameOffset,(LPU8)tmpArray);
   strLen =  (U16)strlen(tmpArray);
   if (!strLen) {
      tmpArray[0] = '\0'; // make sure something is there
   }
   *symbolName = TMalloc((U32)(strLen + 1));
   if (!(*symbolName))
      return ER_OUT_OF_MEMORY;

   if (((symPtr->typeIndex.symType) & 0xF) == SYM_MODULE) {
      // first 2 chars are control chars
      strcpy((LPSTR)*symbolName, (LPSTR)&tmpArray[2]);
   } else {
      strcpy((LPSTR)*symbolName, (LPSTR)&tmpArray[0]);
   }
   return GOOD;
} // end of SymGetSymbolName


//--------------------------------------------------------------------------
// SymGetSymbolParent
//--------------------------------------------------------------------------
RETCODE EXPORT SymGetSymbolParent(SYM_DESCRIPTOR inputSymbol, 
                                  SYM_TYPE_TYPE  *symType, 
                                  SYM_DESCRIPTOR *nextSymbol) {

   HPU8 ptr;

   // make sure the symbol descriptor is ok
   if (!UtilIsValidSymDescriptor(inputSymbol))
      return ER_INVALID_SYM_DESCRIPTOR;

   ptr=st.GetHugeDataPtr(inputSymbol);
   *nextSymbol = ((COMMON_BLOCK_HEADER *)ptr)->symHeader.symParentOffset;
   ptr = st.GetHugeDataPtr(*nextSymbol);
   *symType = (SYM_TYPE_TYPE)
              (((COMMON_SYMBOL_HEADER *)ptr)->typeIndex.symType & 0xF);
   return GOOD;
}

//--------------------------------------------------------------------------
// SymGetParentModule
//--------------------------------------------------------------------------
RETCODE SymGetParentModule(SYM_DESCRIPTOR inputSymbol, 
                           SYM_DESCRIPTOR *moduleSymbol) {

   HPU8 ptr;
   SYM_TYPE_TYPE symType;

   while (TRUE) {
      if (!UtilIsValidSymDescriptor(inputSymbol)) {
         *moduleSymbol = NULL_SYMBOL;
         return ER_INVALID_SYM_DESCRIPTOR;
      }
      *moduleSymbol = inputSymbol;
      ptr = st.GetHugeDataPtr(inputSymbol);
      symType = (SYM_TYPE_TYPE)
                (((COMMON_SYMBOL_HEADER *)ptr)->typeIndex.symType & 0xF);
      if (SYM_MODULE == symType)
         return GOOD;
      if (SYM_ROOT == symType) {
         *moduleSymbol = NULL_SYMBOL;
         return GOOD;
      }
      // go to parent
      inputSymbol = ((COMMON_BLOCK_HEADER *)ptr)->symHeader.symParentOffset;
   }
}  // end of SymGetParentModule


//--------------------------------------------------------------------------
// SymGetSymbolSibling
//--------------------------------------------------------------------------
RETCODE EXPORT SymGetSymbolSibling(SYM_DESCRIPTOR inputSymbol, 
                                   SYM_TYPE_TYPE  *symType, 
                                   SYM_DESCRIPTOR *nextSymbol ) {

   HPU8 ptr;

   // make sure the symbol descriptor is ok
   if (!UtilIsValidSymDescriptor(inputSymbol))
      return ER_INVALID_SYM_DESCRIPTOR;

   ptr=st.GetHugeDataPtr(inputSymbol);
   *nextSymbol = ((COMMON_BLOCK_HEADER *)ptr)->symHeader.symSiblingOffset;
   ptr = st.GetHugeDataPtr(*nextSymbol);
   *symType = (SYM_TYPE_TYPE)
              (((COMMON_SYMBOL_HEADER *)ptr)->typeIndex.symType & 0xF);
   return GOOD;
}  // end of SymGetSymbolSibling

//--------------------------------------------------------------------------
// SymGetAllModules
//--------------------------------------------------------------------------
RETCODE EXPORT SymGetAllModules(SYM_DESCRIPTOR  FAR *modulesList,
                                U16                 listCount,
                                U16 FAR             *numReturn) {

   HPU8 ptr;
   SYM_DESCRIPTOR headDesc, nextDesc, *tmpPtr;
   RETCODE err;

   // if the modulesList is empty we're done
   *numReturn = 0;
   if (modulesList == NULL) return GOOD;
   
   // get the module head descriptor
   if ((err = SymGetModuleListHead(&headDesc)) != GOOD)
      return err;
   
   // make sure the symbol descriptor is ok
   if (!UtilIsValidSymDescriptor(headDesc))
      return ER_INVALID_SYM_DESCRIPTOR;

   ptr=st.GetHugeDataPtr(headDesc);
   // make sure it is module type
   if (SYM_MODULE != (((COMMON_SYMBOL_HEADER *)ptr)->typeIndex.symType & 0xF))
      return ER_SYMBOL_HAS_NO_LISTS;
   *numReturn = 1;
   tmpPtr     = modulesList;
   *tmpPtr++  = headDesc;
   // get all modules until reach NULL_DESCRIPTOR or 
   while (((nextDesc =
          ((COMMON_BLOCK_HEADER *)ptr)->symHeader.symSiblingOffset)
                       != NULL_SYMBOL) && (*numReturn < listCount)) {
      *tmpPtr++ = nextDesc;              // put into list 
      ++(*numReturn);                    // count it 
      ptr = st.GetHugeDataPtr(nextDesc); // advance to next one
   }
       
   return GOOD;
}  // end of SymGetAllModules


//--------------------------------------------------------------------------
// SymGetSymbolBasicType
//--------------------------------------------------------------------------
RETCODE SymGetSymbolBasicType(SYM_DESCRIPTOR      inputSymbol, 
                              BASIC_SYM_ADDR_TYPE *basicType)  {

   HPU8 ptr;
   SYM_TYPE_TYPE symType;

   // make sure the symbol descriptor is ok
   if (!UtilIsValidSymDescriptor(inputSymbol))
      return ER_INVALID_SYM_DESCRIPTOR;
   ptr = st.GetHugeDataPtr(inputSymbol);
   symType = (SYM_TYPE_TYPE)
             (((COMMON_SYMBOL_HEADER *)ptr)->typeIndex.symType & 0xF);
   switch (symType) {
      case SYM_ROOT:
      case SYM_MODULE:
      case SYM_FUNCTION:
      case SYM_BLOCK:
      case SYM_LABEL:
      case SYM_USER_DEFINED_LABEL:
      case SYM_PUBLIC_LABEL:
         *basicType = SYM_CODE_ADDR;
         break;

      case SYM_GLOBAL_VAR:
      case SYM_LOCAL_VAR:
      case SYM_USER_DEFINED_VAR:  
      case SYM_PUBLIC_VAR:
         *basicType = SYM_DATA_ADDR;
         break;

      case SYM_PUBLIC_UNKNOWN:
      case SYM_MISCELLANEOUS:
      case SYM_CONSTANT:
      case SYM_TYPE:
      case SYM_UNDEFINED:
      default:
         *basicType = SYM_UNKNOWN_ADDR;
         break;
   }
   return GOOD;
}  // end of SymGetSymbolBasicType


//--------------------------------------------------------------------------
// SymGetTypeBitfield
//--------------------------------------------------------------------------
RETCODE EXPORT SymGetTypeBitfield(TYPE_INDEX typeIndex,
                                  TYPE_BITFIELD_STRUCT *bitfieldStruct) {
   RETCODE err;
   TABLE_OFFSET offset;
   TYPE_BITFIELD_STRUCT HUGE *bitPtr;
   
   // get the offset in the type table of the header requested
   if ((err = typit.GetOffset(typeIndex, offset)) != GOOD)
      return err;

   bitPtr = (TYPE_BITFIELD_STRUCT HUGE *)tt.GetHugeDataPtr(offset + 
                                                  sizeof(TYPE_HEADER_TYPE2));

   // Fill in the requested information
   bitfieldStruct->bitfieldSigned = bitPtr->bitfieldSigned;
   bitfieldStruct->offset         = bitPtr->offset;
   bitfieldStruct->size           = bitPtr->size;
   bitfieldStruct->baseTypeIndex  = bitPtr->baseTypeIndex;

   return GOOD;
}

//--------------------------------------------------------------------------
// SymGetTypeCArray
//--------------------------------------------------------------------------
RETCODE EXPORT SymGetTypeCArray(TYPE_INDEX typeIndex,
                                TYPE_Z_STRUCT *cArrayStruct) {
   RETCODE err;
   TABLE_OFFSET offset;
   TYPE_Z_STRUCT HUGE *arrayPtr;
   
   // get the offset in the type table of the header requested
   if ((err = typit.GetOffset(typeIndex, offset)) != GOOD)
      return err;
   
   arrayPtr = (TYPE_Z_STRUCT HUGE *)tt.GetHugeDataPtr(offset + 
                                                  sizeof(TYPE_HEADER_TYPE2));
   // Fill in the requested information
   cArrayStruct->typeIndex = arrayPtr->typeIndex;
   cArrayStruct->highBound = arrayPtr->highBound;
   
   return GOOD;
}

//--------------------------------------------------------------------------
// SymGetTypeArray51
//--------------------------------------------------------------------------
RETCODE EXPORT SymGetTypeArray51(TYPE_INDEX typeIndex,
                                 TYPE_OMF51_ARRAY_STRUCT *arrayStruct) {
   RETCODE err;
   TABLE_OFFSET offset;
   TYPE_OMF51_ARRAY_STRUCT HUGE *arrayPtr;
   
   // get the offset in the type table of the header requested
   if ((err = typit.GetOffset(typeIndex, offset)) != GOOD)
      return err;
   
   arrayPtr = (TYPE_OMF51_ARRAY_STRUCT HUGE *)tt.GetHugeDataPtr(offset +
                                                  sizeof(TYPE_HEADER_TYPE2));
   // Fill in the requested information
   arrayStruct->typeIndex = arrayPtr->typeIndex;
   arrayStruct->dim       = arrayPtr->dim;
   
   return GOOD;
}

//--------------------------------------------------------------------------
// SymGetTypeArrayDimSizeNth
//--------------------------------------------------------------------------
RETCODE EXPORT SymGetTypeArrayDimSizeNth(TYPE_INDEX typeIndex,
                                         U8 n, DIMENSION *dimSize) {
   RETCODE err;
   TABLE_OFFSET offset;
   TYPE_OMF51_ARRAY_STRUCT HUGE *arrayPtr;
   DIMENSION *ptrDimSize ;


   // get the offset in the type table of the header requested
   if ((err = typit.GetOffset(typeIndex, offset)) != GOOD)
      return err;
   
   arrayPtr = (TYPE_OMF51_ARRAY_STRUCT HUGE *)tt.GetHugeDataPtr(offset +
                                             sizeof(TYPE_HEADER_TYPE2));
   if ( n > arrayPtr->dim)
      return ER_ARRAY_INDEX_TOO_LARGE;
   
   // point to the n'th dimension size
//   ptrDimSize = (DIMENSION *)tt.GetHugeDataPtr( offset +
//              sizeof(TYPE_HEADER_TYPE2) + ((n-1) * sizeof(DIMENSION)));
   ptrDimSize = (DIMENSION *)tt.GetHugeDataPtr( offset +
              sizeof(TYPE_HEADER_TYPE2) + sizeof(TYPE_OMF51_ARRAY_STRUCT) +
              ((n-1) * sizeof(DIMENSION)));

   *dimSize = *ptrDimSize;
   return GOOD;
}  // end of SymTypeArrayDimSizeNth

//--------------------------------------------------------------------------
// SymGetTypeEnumName
//--------------------------------------------------------------------------
RETCODE EXPORT SymGetTypeEnumName(TYPE_INDEX typeIndex, U32 enumValue,
                                  LPSTR enumName, BOOLEAN *noMatch) {
   RETCODE err;
   TABLE_OFFSET offset, lastEnumOffset = 0;
   ENUM_TYPE_STRUCT HUGE *enumPtr;
   U16 memberCount, i;
   
   // get the offset in the type table of the header requested
   if ((err = typit.GetOffset(typeIndex, offset)) != GOOD)
      return err;
   
   // get the number of enums in this type
   if ((err = SymGetTypeMemberCount(typeIndex,&memberCount)) != GOOD) 
      return err;

   *noMatch = TRUE;
   i = memberCount;
   do {
      //get the i'th enum entry;
      enumPtr = (ENUM_TYPE_STRUCT HUGE *)tt.GetHugeDataPtr(offset +
                sizeof(TYPE_HEADER_TYPE2) + lastEnumOffset);
      lastEnumOffset += sizeof(ENUM_TYPE_STRUCT);
      if (enumPtr->enumValue == enumValue) {
         *noMatch = FALSE;
         break;
      }
   } while ( --i );
//   } while ( i--);
   if (*noMatch == TRUE)
      return GOOD;
   st.GetString(enumPtr->enumName,(U8 *)enumName);
   
   return GOOD;
}


//--------------------------------------------------------------------------
// SymGetTypeEnumValue
//--------------------------------------------------------------------------
RETCODE EXPORT SymGetTypeEnumValue(TYPE_INDEX typeIndex, LPSTR enumName,
                                   U32 *enumValue, BOOLEAN *noMatch) {
   RETCODE err;
   TABLE_OFFSET offset, lastEnumOffset = 0;
   ENUM_TYPE_STRUCT HUGE *enumPtr;
   U16 memberCount, i;
   U8 name[MAX_SYMNAME_LENGTH];
   
   // get the offset in the type table of the header requested
   if ((err = typit.GetOffset(typeIndex, offset)) != GOOD)
      return err;
   
   // get the number of enums in this type
   if ((err = SymGetTypeMemberCount(typeIndex,&memberCount)) != GOOD) 
      return err;
   
   *noMatch = TRUE;
   i = memberCount;
   do {
      //get the i'th enum entry;
      enumPtr = (ENUM_TYPE_STRUCT HUGE *)tt.GetHugeDataPtr(offset +
                sizeof(TYPE_HEADER_TYPE2) + lastEnumOffset);
      st.GetString(enumPtr->enumName, name);
      lastEnumOffset += sizeof(ENUM_TYPE_STRUCT);
      if( !strcmp(enumName, (S8 *) name)) {
         *noMatch = FALSE;
         break;
      }
   } while ( --i );
//   } while ( i-- );
   if (*noMatch == TRUE)
      return GOOD;
   *enumValue = enumPtr->enumValue;
   
   return GOOD;
}

//--------------------------------------------------------------------------
// SymGetTypeIndexMax
//--------------------------------------------------------------------------
RETCODE EXPORT SymGetTypeIndexMax(TYPE_INDEX *typeIndexMax) {
   return (tt.GetMaxTypeIndex(*typeIndexMax));
}


//--------------------------------------------------------------------------
// SymGetTypeHeader
//--------------------------------------------------------------------------
RETCODE EXPORT SymGetTypeHeader(TYPE_INDEX typeIndex, 
                                TYPE_HEADER_TYPE *typeHeader) {
   RETCODE err;
   TABLE_OFFSET offset;
   TYPE_HEADER_TYPE2 HUGE *typeHdr;
         
   // get the offset in the type table of the header requested
   if ((err = typit.GetOffset(typeIndex, offset)) != GOOD)
      return err;
   
   typeHdr = (TYPE_HEADER_TYPE2 HUGE *)tt.GetHugeDataPtr(offset);

   typeHeader->typeChoice = typeHdr->typeChoice;
   if (typeHdr->typeChoice == SIMPLE_TYPE_CLASS)
      typeHeader->t.simpleType = typeHdr->t.simpleType;
   else 
      typeHeader->t.complexType = typeHdr->t.complexType;

   // Check if the type requested has its sizeInMAUs calculated
   // All SIMPLE_TYPE_CLASS is precalculated, so only COMPLEX_TYPE are here
   if (!(typeHdr->sizeCalculated)) {
      TYPE_HEADER_TYPE baseTypeHeader;    // To get base type info
      // Need to have the type name buffer - USE AS SCRATCH PAD ONLY
      baseTypeHeader.typeName = (LPSTR) typeHeader->typeName;
      
      switch(typeHdr->t.complexType) {
         case TY_C_ARRAY :
         {
            TYPE_Z_STRUCT HUGE *arrayPtr; // Pointer to array info block
            arrayPtr = (TYPE_Z_STRUCT HUGE *)tt.GetHugeDataPtr(offset + 
                                                  sizeof(TYPE_HEADER_TYPE2));
            // SymGetTypeHeader to get the underlying type
            if ((err = SymGetTypeHeader((TYPE_INDEX)arrayPtr->typeIndex,
                                        &baseTypeHeader)) != GOOD)
               return(err);
            
            // Now we have the sizeInMAUs of the base type, we can calculate
            // and update the actual sizeInMAUs of the requested CArray type.
            // SymUpdateTypeInfo() will update the sizeCalculated flag
            // NOTE: Array size = element size * number of element
            if ((err = SymUpdateTypeInfo(typeIndex, (baseTypeHeader.sizeInMAUs
               * ((arrayPtr->highBound)+1)),
               arrayPtr->typeIndex)) != GOOD)
               return(err);
            break;
         }
         
         case TY_OMF51_ARRAY :
         {
            TYPE_OMF51_ARRAY_STRUCT HUGE *arrayPtr; // Pointer to array info block
            U32 memberCnt=1L;

            arrayPtr = (TYPE_OMF51_ARRAY_STRUCT HUGE *)tt.GetHugeDataPtr(offset+
                                                  sizeof(TYPE_HEADER_TYPE2));
            // SymGetTypeHeader to get the underlying type
            if ((err = SymGetTypeHeader((TYPE_INDEX)arrayPtr->typeIndex,
                                        &baseTypeHeader)) != GOOD)
               return(err);

            for (U8 dim=0; dim < arrayPtr->dim; dim++) {
//                memberCnt *= (U32)(*(DIMENSION HUGE *)tt.GetHugeDataPtr(offset+
//                          sizeof(TYPE_HEADER_TYPE2)+(dim * sizeof(DIMENSION))));
                memberCnt *= (U32) ( (*(DIMENSION HUGE*)tt.GetHugeDataPtr(offset+
                          sizeof(TYPE_HEADER_TYPE2)+sizeof(TYPE_OMF51_ARRAY_STRUCT)+
                          (dim * sizeof(DIMENSION))) )+1 );
            }
            if ((err = SymUpdateTypeInfo(typeIndex, (baseTypeHeader.sizeInMAUs
               * memberCnt), arrayPtr->typeIndex)) != GOOD)
               return(err);
            break;
         }

         case TY_BITFIELD :
         {
            TYPE_BITFIELD_STRUCT HUGE *bitPtr; // Pointer to bitfield info
            bitPtr = (TYPE_BITFIELD_STRUCT HUGE *)tt.GetHugeDataPtr(offset + 
                                                  sizeof(TYPE_HEADER_TYPE2));
            // Get the baseType information - It will eventually resolve !
            if ((err = SymGetTypeHeader((TYPE_INDEX)bitPtr->baseTypeIndex,
                                        &baseTypeHeader)) != GOOD)
               return(err);
            // Now we have the sizeInMAUs of the base type, we can update
            // the info - SymUpdateTypeInfo() will update the
            // sizeCalculated flag
            if ((err = SymUpdateTypeInfo(typeIndex,
                                         baseTypeHeader.sizeInMAUs,
                                         bitPtr->baseTypeIndex))
                != GOOD) return(err);
            break;
         }

         case TY_TYPE :  
         {
            TYPE_INDEX HUGE *baseTypeIndexPtr;  // To extract the base index
            TYPE_INDEX baseTypeIndex;
            // Get the base type index of the requested type
            // NOTES: the next field after TYPE_HEADER_TYPE2 is the type index
            baseTypeIndexPtr = (TYPE_INDEX HUGE *)
                       tt.GetHugeDataPtr(offset + sizeof(TYPE_HEADER_TYPE2));
            // Now we have the base type index
            baseTypeIndex = *baseTypeIndexPtr;

            // Call recursively to get to the final type and get it sizeInMAUs 
            if ((err = SymGetTypeHeader(baseTypeIndex, &baseTypeHeader))
                != GOOD) return(err);
            // Now update the defined type using the basetype sizeInMAUs
            if ((err = SymUpdateTypeInfo(typeIndex,
                                         baseTypeHeader.sizeInMAUs,
                                         baseTypeIndex))
                != GOOD)  return(err);
            break;
         }
         case TY_STRUCT :
         case TY_UNION  :
         {
            TABLE_OFFSET lastStructOffset = 0;
            TYPE_STRUCT_HEADER HUGE *structPtr;
            U16 memberCount, memberOffset = 0;
            // get the number of members in this struct/union type
            if ((err = SymGetTypeMemberCount(typeIndex,&memberCount)) != GOOD) 
               return err;
            do {
               //get the i'th struct entry;
               structPtr = (TYPE_STRUCT_HEADER HUGE *)tt.GetHugeDataPtr(offset
                  + sizeof(TYPE_HEADER_TYPE2) + lastStructOffset);
               lastStructOffset += sizeof(TYPE_STRUCT_HEADER);
               // update all member offset
               structPtr->offset = memberOffset;
               // get the member baseType information - skip the last one
               // memberCount == 1
               if (memberCount > 1) {
                  if ((err = SymGetTypeHeader((TYPE_INDEX)structPtr->typeIndex,
                                              &baseTypeHeader)) != GOOD)
                     return(err);
                  // increment memberOffset for the next element
                  memberOffset += (U16)baseTypeHeader.sizeInMAUs;
               }   
            } while (--memberCount);

            // Now update the defined type 
            typeHdr->sizeCalculated = TRUE;
            break;
         }

         default :
            // Unknown forward reference type 
            return(ER_UNKNOWN_FWREF_TYPE);
      } // end of switch
   }
   
   // NOTE: 02/17/94 - Nghia
   // Dereference pointer again to make sure it's good
   typeHdr = (TYPE_HEADER_TYPE2 HUGE *)tt.GetHugeDataPtr(offset);   

   // Retrieve the type information
   typeHeader->sizeInMAUs = typeHdr->sizeInMAUs;
   st.GetString(typeHdr->typeName,(U8 *) (typeHeader->typeName));
   typeHeader->sizeCalculated = TRUE;
   return GOOD;
}

//--------------------------------------------------------------------------
// SymGetTypeMemberCount
//--------------------------------------------------------------------------
RETCODE EXPORT SymGetTypeMemberCount(TYPE_INDEX typeIndex, U16 *memberCount) {
   RETCODE err;
   TABLE_OFFSET offset;
   TYPE_HEADER_TYPE2 HUGE *typeHdr;
   
   // get the offset in the type table of the header requested
   if ((err = typit.GetOffset(typeIndex, offset)) != GOOD)
      return err;
   
   typeHdr = (TYPE_HEADER_TYPE2 HUGE *)tt.GetHugeDataPtr(offset);
   
   *memberCount = typeHdr->memberCount;
   return GOOD;
}

//--------------------------------------------------------------------------
// SymGetTypePointerTypeIndex
//--------------------------------------------------------------------------
RETCODE EXPORT SymGetTypePointerTypeIndex(TYPE_INDEX typeIndex,       
                                          TYPE_INDEX *pointerTypeIndex) {
   RETCODE err;
   TABLE_OFFSET offset;
   TYPE_INDEX HUGE *typePtr;
   
   // get the offset in the type table of the header requested
   if ((err = typit.GetOffset(typeIndex, offset)) != GOOD)
      return err;
   
   typePtr = (TYPE_INDEX HUGE *)tt.GetHugeDataPtr(offset +
                                              sizeof(TYPE_HEADER_TYPE2));
   
   *pointerTypeIndex = *typePtr;
   
   return GOOD;
}

//--------------------------------------------------------------------------
// SymGetTypePointer51
//--------------------------------------------------------------------------
RETCODE EXPORT SymGetTypePointer51(TYPE_INDEX typeIndex,
                                   TYPE_OMF51_PTR_STRUCT *ptrStruct) {
   RETCODE err;
   TABLE_OFFSET offset;
   TYPE_OMF51_PTR_STRUCT HUGE *typePtr;
   
   // get the offset in the type table of the header requested
   if ((err = typit.GetOffset(typeIndex, offset)) != GOOD)
      return err;
   
   typePtr = (TYPE_OMF51_PTR_STRUCT HUGE *)tt.GetHugeDataPtr(offset +
                                           sizeof(TYPE_HEADER_TYPE2));

// Changed by Gates Hua , 07/27/95    
//   typePtr->typeIndex = ptrStruct->typeIndex;
//   typePtr->attribute = ptrStruct->attribute;
//   typePtr->ptrSpec   = ptrStruct->ptrSpec;
//   typePtr->memSpace  = ptrStruct->memSpace;
   ptrStruct->typeIndex = typePtr->typeIndex;
   ptrStruct->attribute = typePtr->attribute;
   ptrStruct->ptrSpec = typePtr->ptrSpec;
   ptrStruct->memSpace = typePtr->memSpace;
   return GOOD;
}

//--------------------------------------------------------------------------
// SymGetTypeStructUnion
//--------------------------------------------------------------------------
RETCODE EXPORT
SymGetTypeStructUnion(TYPE_INDEX       typeIndex,
                      LPSTR            structName,
                      TYPE_S_U_STRUCT *structOrUnion,
                      U16             *componentIndex,
                      BOOLEAN         *noMatch) {
   
   RETCODE err;
   TABLE_OFFSET offset, lastStructOffset = 0;
   TYPE_STRUCT_HEADER HUGE *structPtr;
   U16 memberCount, i;
   U8 name[MAX_SYMNAME_LENGTH];
   
   // get the offset in the type table of the header requested
   if ((err = typit.GetOffset(typeIndex, offset)) != GOOD)
      return err;
   
   // get the number of structs in this type
   if ((err = SymGetTypeMemberCount(typeIndex,&memberCount)) != GOOD) 
      return err;
   
   *noMatch = TRUE;
   i = memberCount;
   do {
      //get the i'th struct entry;
      structPtr = (TYPE_STRUCT_HEADER HUGE *)tt.GetHugeDataPtr(offset +
                sizeof(TYPE_HEADER_TYPE2) + lastStructOffset);
      st.GetString(structPtr->nameOffset, name);
      lastStructOffset += sizeof(TYPE_STRUCT_HEADER);
      if( !strcmp(structName, (S8 *) name)) {
         *noMatch = FALSE;
         break;
      }
   } while ( i-- );
   if (*noMatch == TRUE)
      return GOOD;

   strcpy(structOrUnion->name, (S8 *)name);
   structOrUnion->typeIndex = structPtr->typeIndex;
   structOrUnion->offset = structPtr->offset;
   // adding one to i is necessary since it starts one less than memberCount
   // and the first element begins at 0
   *componentIndex = memberCount - (i + 1);
   
   return GOOD;
}

//--------------------------------------------------------------------------
// SymGetTypeStructUnionNth
//--------------------------------------------------------------------------
RETCODE EXPORT SymGetTypeStructUnionNth(TYPE_INDEX typeIndex,
                                        U16 n,
                                        TYPE_S_U_STRUCT *structOrUnion) {
   RETCODE err;
   TABLE_OFFSET offset, lastStructOffset = 0;
   TYPE_STRUCT_HEADER HUGE *structPtr;
   U16 memberCount, i;
   U8 name[MAX_SYMNAME_LENGTH];
   
   // get the offset in the type table of the header requested
   if ((err = typit.GetOffset(typeIndex, offset)) != GOOD)
      return err;
   
   // get the number of structs in this type
   if ((err = SymGetTypeMemberCount(typeIndex,&memberCount)) != GOOD) 
      return err;
   
   if ( n >= memberCount )
      return ER_ARRAY_INDEX_TOO_LARGE;
   
   i = n;
   do {
      //get the i'th struct entry;
      structPtr = (TYPE_STRUCT_HEADER HUGE *)tt.GetHugeDataPtr(offset +
                sizeof(TYPE_HEADER_TYPE2) + lastStructOffset);
      lastStructOffset += sizeof(TYPE_STRUCT_HEADER);
   } while ( i-- );

   
   st.GetString(structPtr->nameOffset, name);
   strcpy(structOrUnion->name, (S8 *)name);
   structOrUnion->typeIndex = structPtr->typeIndex;
   structOrUnion->offset = structPtr->offset;
   
   return GOOD;
}

//--------------------------------------------------------------------------
// SymGetTypeTypeIndex
//--------------------------------------------------------------------------
/*
RETCODE EXPORT
SymGetTypeTypeIndex(TYPE_INDEX typeIndex,       
                    TYPE_INDEX *typeTypeIndex) {
   
   RETCODE err;
   TABLE_OFFSET offset;
   TYPE_INDEX HUGE *typePtr;
   
   // get the offset in the type table of the header requested
   if ((err = typit.GetOffset(typeIndex, offset)) != GOOD)
      return err;
   
   typePtr = (TYPE_INDEX HUGE *)tt.GetHugeDataPtr(offset +
                                                  sizeof(TYPE_HEADER_TYPE2));
   
   *typeTypeIndex = *typePtr;
   
   return GOOD;
}
*/
RETCODE EXPORT
SymGetTypeTypeIndex(TYPE_INDEX typeIndex,       
                    TYPE_INDEX *typeTypeIndex) {
   
   RETCODE err;
   TABLE_OFFSET offset;
//   TYPE_INDEX HUGE *typePtr;
   TYPE_TYPE HUGE *typePtr;
   
   // get the offset in the type table of the header requested
   if ((err = typit.GetOffset(typeIndex, offset)) != GOOD)
      return err;
   
//   typePtr = (TYPE_INDEX HUGE *)tt.GetHugeDataPtr(offset +
   typePtr = (TYPE_TYPE HUGE *)tt.GetHugeDataPtr(offset +
                                                  sizeof(TYPE_HEADER_TYPE2));
   
   *typeTypeIndex = typePtr->typeIndex;
   
   return GOOD;
}

RETCODE EXPORT
SymGetTypeTypeType(TYPE_INDEX typeIndex,       
                   TYPE_INDEX *typeTypeIndex,
                   SEGMENTTYPE *segType) {
   
   RETCODE err;
   TABLE_OFFSET offset;
//   TYPE_INDEX HUGE *typePtr;
   TYPE_TYPE HUGE *typePtr;
   
   // get the offset in the type table of the header requested
   if ((err = typit.GetOffset(typeIndex, offset)) != GOOD)
      return err;
   
//   typePtr = (TYPE_INDEX HUGE *)tt.GetHugeDataPtr(offset +
   typePtr = (TYPE_TYPE HUGE *)tt.GetHugeDataPtr(offset +
                                                  sizeof(TYPE_HEADER_TYPE2));
   
   *typeTypeIndex = typePtr->typeIndex;
   *segType = typePtr->segType;
   
   return GOOD;
}

//--------------------------------------------------------------------------
// SymGetVar
//--------------------------------------------------------------------------
RETCODE EXPORT
SymGetVar(SYM_DESCRIPTOR     inputSymbol,
          LPSTR              varName,
          TYPE_INDEX         *typeIndex,
          VAR_STORAGE_CLASS  *storageClass,
          VAR_REGISTER_CLASS *registerClass,
          BOOLEAN            *isConstant,
          SYM_DESCRIPTOR     *funcDescriptor,
          SYM_DESCRIPTOR     *moduleDescriptor,
          SYM_DESCRIPTOR     *parentDescriptor,
          GET_VAR_ADDR_STRUCT *varAddr) {

   RETCODE err;
   SYM_TYPE_VARIABLE HUGE *symVar;
   VAR_BASED_VAR     HUGE *basedPtr;
   AUTO_VAR_OFFSET   HUGE *autoVarPtr;
   SYM_DESCRIPTOR    parentSymbol;
   SYM_TYPE_TYPE     symType;
   TABLE_OFFSET      currentSymbol;
   VAR_LIFETIME_STATE lifetimeState;

   // make sure the symbol descriptor is ok
   if (!UtilIsValidSymDescriptor(inputSymbol))
      return ER_INVALID_SYM_DESCRIPTOR;

   // get a pointer to the symbol that we are retrieving, and make sure
   // it is a variable.
   symVar=(SYM_TYPE_VARIABLE HUGE *)st.GetHugeDataPtr(inputSymbol);
   if (!((((symVar->symHeader.typeIndex.symType) & 0xF) == SYM_GLOBAL_VAR) ||
//       (((symVar->symHeader.typeIndex.symType) & 0xF) == SYM_LOCAL_VAR)) )
       (((symVar->symHeader.typeIndex.symType) & 0xF) == SYM_LOCAL_VAR) ||
       (((symVar->symHeader.typeIndex.symType) & 0xF) == SYM_PUBLIC_VAR)) )
      return ER_NOT_A_VARIABLE;

   if ( (symVar->isValidAddr == FALSE) )
      return ER_INVALID_ADDRESS;

   if (symVar->registerClass == SHADOW_REG)
      return ER_NOT_IMPLEMENTED;
   if ((symVar->registerClass != NOT_REG) &&
      (symVar->storageClass == BASED_VAR_CLASS))
      return ER_NOT_IMPLEMENTED;
   
   // fill in the variable info
   *storageClass = symVar->storageClass;
   *registerClass = symVar->registerClass;
   *typeIndex = symVar->typeIndex;
   *isConstant = symVar->isConstant;
   
   // fill in the variable's "address" info
   if (*registerClass == NOT_REG) {
      // there is no lifetime info when the var is not a register.
      switch (*storageClass) {
         case STATIC_VAR_CLASS:   // all these classes have fixed addresses
         case UNKNOWN_VAR_CLASS:
         case GLOBAL_VAR_CLASS:
            varAddr->fixedAddr.segType = (SEGMENTTYPE)
                     symVar -> symHeader.typeIndex.baseIndex;
            varAddr->fixedAddr.startAddr =
                     symVar -> symHeader.beginAddrInfo.startAddr;
            varAddr->fixedAddr.endAddr =
                     symVar -> symHeader.endAddrInfo.endAddr;
            break;

         case AUTO_VAR_CLASS:
            varAddr->addrData.getAutoVar.autoVarOffset =
               symVar->symHeader.beginAddrInfo.autoVarOffset;
            varAddr->addrData.getAutoVar.autoVarSize =
               symVar->symHeader.endAddrInfo.varSize;
            break;

         case BASED_VAR_CLASS:
            // get a pointer to the memory just below the common header
            basedPtr = (VAR_BASED_VAR HUGE *)st.GetHugeDataPtr(inputSymbol +
               sizeof(SYM_TYPE_VARIABLE));
            varAddr->addrData.getBasedVar.basedVar.offsetVal = 
               basedPtr->offsetVal;
            varAddr->addrData.getBasedVar.basedVar.controlNum = 
               basedPtr->controlNum;
            varAddr->addrData.getBasedVar.basedVar.publicLocal = 
               basedPtr->publicLocal;
            varAddr->addrData.getBasedVar.basedVar.memorySpace = 
               basedPtr->memorySpace;
            varAddr->addrData.getBasedVar.basedVar.baseSize = 
               basedPtr->baseSize;
            break;

         default:
            return ER_STORAGE_CLASS_UNKNOWN;
      }
   } else {
      if (*registerClass == LOCKED_REG) {
         // adjust huge pointer to point to next variable after
         // SYM_TYPE_VARIABLE.
         autoVarPtr = (AUTO_VAR_OFFSET HUGE *)st.GetHugeDataPtr(inputSymbol +
            sizeof(SYM_TYPE_VARIABLE));
         varAddr->addrData.getLockedReg.autoVarOffset = *autoVarPtr;
               
         varAddr->addrData.getLockedReg.getRegIndex.regIndex =
            symVar->symHeader.beginAddrInfo.registerIndex;
         
         varAddr->addrData.getLockedReg.varSize =
            symVar->symHeader.endAddrInfo.varSize;
               
         // find out if the symbol is live or dead
         if ((err = SymGetVarLifetimeInfo(inputSymbol, &lifetimeState))
            != GOOD)
            return err;
         
         varAddr->addrData.getLockedReg.lifetimeState = lifetimeState;
               
      } else if (*registerClass == LIVING_REG) {
         // register index is in the beginning address slot,
         // size is in the end address slot,
         // frame offset is in the location just after the variable
         // header.
         varAddr->addrData.getRegisterIndex.varLivingReg =
            symVar->symHeader.beginAddrInfo.registerIndex;
               
         varAddr->addrData.getRegisterIndex.varSize =
            symVar->symHeader.endAddrInfo.varSize;
               
         // find out if the symbol is live or dead
         if ((err = SymGetVarLifetimeInfo(inputSymbol, &lifetimeState))
            != GOOD)
            return err;
         
         varAddr->addrData.getRegisterIndex.lifetimeState = lifetimeState;
               
      } else {
         // this should never happen.  See above.
         return ER_NOT_IMPLEMENTED;
      }
   }
   
   // get the function and module descriptors
   currentSymbol = inputSymbol;
   *funcDescriptor = *moduleDescriptor = *parentDescriptor = NULL_SYMBOL;
   do {
      if ((err = SymGetSymbolParent(currentSymbol, &symType, &parentSymbol))
         != GOOD)
         return err;
      if (!*parentDescriptor) *parentDescriptor = parentSymbol;
      if ((symType == SYM_FUNCTION)  && (!*funcDescriptor))
         *funcDescriptor = parentSymbol;
      if (symType == SYM_MODULE) *moduleDescriptor = parentSymbol;
      if (symType == SYM_ROOT) break;
      currentSymbol = parentSymbol;
   } while (TRUE);

   // copy the name of the variable into varName
   st.GetString(symVar->symHeader.symbolNameOffset,(U8 FAR *)varName);
   return GOOD;
}

//----------------------------------------------------------------------
//  SymGetVarLifetimeInfo
//
//  Scan rules:
//
//    1. if <firstEntry> is NULL_SYMBOL, return LIVE.
//    2. Assumption is that the lifetimeAddr's are sorted by offset.
//    3. Assumption is that a lifetime reg is only "livable", i.e. it
//       can only be LIVE within the address range of the parent block
//       or function; i.e. DEAD is returned if:
//       a) if <pcAddr> < startAddr of parent, OR
//       b) if <pcAddr> > endAddr of parent
//    4. If <pcAddr> is in block range, check for its current lifeTimeState
//       while (lifeTimeList != NULL) { 
//          if <pcAddr> > (<lifetimeOffset> + <startAddr of parent>)
//             set the lifetimeState = the state indicated by the linked node.
//          Stop when <pcAddr> < (<lifetimeOffset> + <startAddr of parent>)
//       }
//    5. The lifetimeClass (state LIVE or DEAD) is returned.
//----------------------------------------------------------------------
RETCODE EXPORT SymGetVarLifetimeInfo(SYM_DESCRIPTOR      inputSymbol,
                                     VAR_LIFETIME_STATE FAR *lifetimeState) {

   SYM_TYPE_VARIABLE HUGE    *varPtr;
   COMMON_SYMBOL_HEADER HUGE *parentPtr;
   SYM_LIFETIME_INFO HUGE    *lifetimePtr;
   SYM_LIFETIME_START_INFO HUGE *lifetimeStartPtr;
   TABLE_OFFSET              lifetimeOffset, currentOffset;
   U8                        tmpSymType;
   OFFSET_ADDR_TYPE          pcAddr;
   RETCODE                   err;
   
   // make sure the symbol descriptor is ok
   if (!UtilIsValidSymDescriptor(inputSymbol))
      return ER_INVALID_SYM_DESCRIPTOR;

   varPtr = (SYM_TYPE_VARIABLE HUGE *)st.GetHugeDataPtr(inputSymbol);
   tmpSymType = (U8)((varPtr->symHeader.typeIndex.symType) & 0xF);
   if (!((tmpSymType == SYM_GLOBAL_VAR) ||
        (tmpSymType == SYM_LOCAL_VAR)   ||
        (tmpSymType == SYM_PUBLIC_VAR)  ||
        (tmpSymType == SYM_PUBLIC_UNKNOWN))) {
      return ER_NOT_A_VARIABLE;
   }
   if (varPtr->registerClass == NOT_REG)
      return ER_NO_LIFETIME_INFO;
   
   // get the current PC then convert the break address to the
   // "symbol table format"; i.e. must subtract out base address
//   if (GOOD != (err = CpuGetPC(&pcAddr)))
//      return err;

   // check present address to see if within variable's scope; i.e.
   // whether between start and end address of parent
   currentOffset = varPtr->symHeader.symParentOffset;
   parentPtr = (COMMON_SYMBOL_HEADER HUGE *)st.GetHugeDataPtr(currentOffset);
   // If pcAddr is not in parent block range - it's a DEAD variable
   if ((pcAddr < parentPtr->beginAddrInfo.startAddr) ||
       (pcAddr > parentPtr->endAddrInfo.endAddr)) {
      *lifetimeState = DEAD;
      goto CLEANUP;
   }

   switch (varPtr->registerClass) {
      case LOCKED_REG:
         /* Locked registers are living until first DEATH record
         ** occurs telling of the DEATH of the register.
         */
         *lifetimeState = LIVE;
         lifetimeOffset = inputSymbol + sizeof(SYM_TYPE_VARIABLE) + 
            sizeof(AUTO_VAR_OFFSET);
         break;

      case LIVING_REG:
         /* ATN2 - living registers are LIVE until BIRTH record occurs
         ** indicating where register starts DEAD/ALIVE.
          */
         *lifetimeState = LIVE;
         lifetimeOffset = inputSymbol + sizeof(SYM_TYPE_VARIABLE);
         break;

      case SHADOW_REG:
         err = ER_NOT_IMPLEMENTED;
         goto CLEANUP;

      default:
         err = ER_REGISTER_CLASS_UNKNOWN;
         goto CLEANUP;
   }
   // Get pointer to first lifetime data.  If value is NULL_SYMBOL, there
   // is no lifetime data; return LIVE.
   lifetimeStartPtr = (SYM_LIFETIME_START_INFO HUGE *)
                      st.GetHugeDataPtr(lifetimeOffset);
   currentOffset = lifetimeStartPtr->firstEntry;

   // The while loop compares the execution break address with the
   // addresses in the lifetime linked list and find out if the
   // variable is alive/dead.  The last state before the current PC address
   // goes beyond the lifetime info in the list is the returned value
   while (currentOffset != NULL_SYMBOL) {
      lifetimePtr = (SYM_LIFETIME_INFO HUGE *)
                    st.GetHugeDataPtr(currentOffset);
      // NOTES: 09/27/93 - Nghia
      // lifetimeAddr is the local offset of the current block segment
      // It is not the absolute address!
      if (pcAddr > ((parentPtr->beginAddrInfo.startAddr) +
          (lifetimePtr->lifetimeInfo.lifetimeAddr.addr)) ) {
         *lifetimeState = lifetimePtr->lifetimeInfo.lifetimeClass;
      } else {
         break;     // assuming ascending, have gone past
      }
      currentOffset = lifetimePtr->nextLifetimeInfo;  // follow linked list
   }
CLEANUP:
   return err;
}  // end of SymGetVarLifetimeInfo

//--------------------------------------------------------------------------
// SymGetLdrStats
//
// Description:
//    Fill in the number of symbols loaded and the current module name,
//    the number of modules loaded so far, and the number of Types loaded,
//    in the loader status block.  This is called from the loader DLL,
//    and the information is used by the ldrprog.c dialog in the cliulib
//    DLL.
//--------------------------------------------------------------------------
RETCODE EXPORT SymGetLdrStats(LPSTR moduleName, U32 FAR *numSymbols,
   U16 FAR *numModules, U32 FAR *numTypes)
{
   static S8 mname[MAX_SYMNAME_LENGTH];
   RETCODE        err;
   LPSTR          lpstrTmp;
   U32            tmpU32;
   TYPE_INDEX     typeIndexMax;

   // retrieve the total number of symbols loaded up to now
   if (numSymbols != NULL) {
      *numSymbols = ot.GetOrdinalCount();
   }

   // retrieve the number of module loaded from the symbolStat[] table
   if (numModules)
      *numModules = (U16)symbolStat[SYM_MODULE];
   
   // retrieve the number of types
   if (numTypes) {
      tt.GetMaxTypeIndex(typeIndexMax);
      *numTypes = typeIndexMax;
   }

   // retrieve the name of the last loaded module
   if (moduleName != NULL && lastModuleLoaded) {
      if ((err = SymAddGetModuleName((SYM_DESCRIPTOR) lastModuleLoaded,
                                     (LPSTR) mname)) != GOOD) {
         return (err);
      }
      lpstrTmp = (LPSTR) mname;
      /* make sure it will fit in the status buffer (and in the dialog) */
      while ((tmpU32 = lstrlen(lpstrTmp)) + 1 >= MAX_MODULE_NAME_LEN) {
         lpstrTmp++;
      }
      if (tmpU32 > 0L) {
         lstrcpy((LPSTR)moduleName, (LPSTR)lpstrTmp);
      }   
   }
   return (GOOD);
}  // end of SymGetLdrStats

/******************************** E O F ***********************************/
