/****************************************************************************
**
**  Name:  symget.cpp
**
**  Description:
**     routines for getting symbols out of the symbol table.
**
**  Status:  PRELIMINARY
*****************************************************************************/

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

#ifndef _BASETBL_
#include "basetbl.h"
#endif


#ifndef _BASEWIND_
#include "basewind.h"
#endif

#ifndef _ADDR_
#include "addr.h"
#endif

#ifndef _CPU_
#include "cpu.h"
#endif

#ifndef _ENLIB_
#include "enlib.h"
#endif

#ifndef _HASHTBL_
#include "hashtbl.h"
#endif

#ifndef _HEAP_
#include "heap.h"
#endif

#ifndef _MEMPOOL_
#include "mempool.h"
#endif

#ifndef _ORDTBL_
#include "ordtbl.h"
#endif

#ifndef __STRING_H
#include <string.h>
#endif

#ifndef _SYMBLSVR_
#include "symblsvr.h"
#endif

#ifndef _SYMELF_
#include "symelf.h"
#endif

#ifndef _SYMERROR_
#include "symerror.h"
#endif

#ifndef _SYMGET_
#include "symget.h"
#endif

#ifndef _SYMMGR_
#include "symmgr.h"
#endif

#ifndef _SYMUTIL_
#include "symutil.h"
#endif

#ifndef _TYPETBL_
#include "typetbl.h"
#endif

#ifndef _CLIULIB_
#include "cliulib.h"
#endif


                       /****************************
                        *                          *
                        *     LOCAL DEFINITIONS    *
                        *                          *
                        ****************************/


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

                       /****************************
                        *                          *
                        *      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,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(symName,(S8 *) 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) {
   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);
   typePtr->sizeInMAUs = typeMAUSize; 
   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;
}

//--------------------------------------------------------------------------
// SymGetBaseType
//--------------------------------------------------------------------------
RETCODE EXPORT SymGetBaseType(BASE_INDEX baseIndex,
                              BASE_TYPE FAR *baseType) {
   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);
   *baseType = (BASE_TYPE)(base->GetBaseType());
   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, tmpOffset, listHead;
   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 = (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;
   
   // find the last element in the label list if the list has entries.
   if (!count) {
      nextOffset = NULL_SYMBOL;
   } else {
      i = count - 1;
      tmpOffset = 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,
           DESCRIPTOR     codeAddrRangeDesc) {
   
   SYM_TYPE_FUNCTION HUGE *funcPtr;
   U8                tmpArray[MAX_SYMNAME_LENGTH];
   RETCODE           err;
   
   // 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
   if (SUCCESS != (err = UtilSetAddrParams(
                   funcPtr -> symHeader.symHeader.typeIndex.baseIndex,
                   funcPtr -> symHeader.symHeader.beginAddrInfo.startAddr,
                   funcPtr -> symHeader.symHeader.endAddrInfo.endAddr,
                   codeAddrRangeDesc)))  {
       return err;
       }
   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;
}


//--------------------------------------------------------------------------
// 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);
   }*/
   *fatherName = 0L;

   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,
                           DESCRIPTOR codeAddrRangeDesc) {
   RETCODE err;
   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
   if (SUCCESS != (err = UtilSetAddrParams(labelPtr->typeIndex.baseIndex,
                                           labelPtr->beginAddrInfo.startAddr,
                                           labelPtr->endAddrInfo.endAddr,
                                           codeAddrRangeDesc)))  {
      return err;
   }
   st.GetString(labelPtr->symbolNameOffset,(LPU8)tmpArray);
   strcpy(labelName,(S8 *)tmpArray);
   return GOOD;
}

//-------------------------------------------------------------------------  
// SymGetModule
//
//    Returns module name and address
//-------------------------------------------------------------------------  
RETCODE EXPORT
SymGetModule(SYM_DESCRIPTOR inputModule,
             LPSTR          moduleName,
             DESCRIPTOR     moduleAddrRangeDesc)  {

   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.
   err = UtilSetAddrParams(
                   modPtr -> symHeader.symHeader.typeIndex.baseIndex,
                   modPtr -> symHeader.symHeader.beginAddrInfo.startAddr,
                   modPtr -> symHeader.symHeader.endAddrInfo.endAddr,
                   moduleAddrRangeDesc);
   // get symbol name   
   st.GetString(modPtr->symHeader.symHeader.symbolNameOffset,(LPU8)tmpArray);

   // remove two control characters
   strcpy(moduleName,(S8 *)&tmpArray[2]);
   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 = 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++;
   }
}

//-------------------------------------------------------------------------
// SymGetModuleAlias   -- add by Winky 2/5/98
//-------------------------------------------------------------------------  
RETCODE EXPORT SymGetModuleAlias(LPSTR inputSymbol, 
                                 LPSTR moduleAlias) {
   S8 buf[32];

   GetPrivateProfileString("ModuleAlias", inputSymbol, "", buf,
      sizeof(buf), "micepack.ini");

   strcpy(moduleAlias,(S8 *)buf);
   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;
}

//-------------------------------------------------------------------------  
// 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,
                    DESCRIPTOR     symbolAddrDesc) {

   HPU8 symPtr;

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

   (COMMON_SYMBOL_HEADER HUGE *)symPtr =
      (COMMON_SYMBOL_HEADER HUGE *)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;
      }
   }
   // fix up the address range
   return UtilSetAddrParams(
          ((COMMON_SYMBOL_HEADER HUGE *)symPtr)->typeIndex.baseIndex,
          ((COMMON_SYMBOL_HEADER HUGE *)symPtr)->beginAddrInfo.startAddr,
          ((COMMON_SYMBOL_HEADER HUGE *)symPtr)->endAddrInfo.endAddr,
                            symbolAddrDesc);
} // 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 = (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 = (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 = (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
   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 = 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 = 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,
                 DESCRIPTOR FAR *symbolName) {

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

   // make sure the symbol descriptor is ok
   if (!UtilIsValidSymDescriptor(inputSymbol)) {
      *symbolName = (DESCRIPTOR)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 = (DESCRIPTOR)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), (S8 *)&tmpArray[2]);
   } else {
      strcpy((LPSTR)(*symbolName), (S8 *)&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 = ((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 = ((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 = ((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 = ((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->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;
}

//--------------------------------------------------------------------------
// 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--);
   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-- );
   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;

   typeHeader->dirty = typeHdr->dirty; //Hera 3/11/98
   // 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 Array_Type :
         {
            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)) )) != 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))
                != GOOD) return(err);
            break;
	 }*/

	 case Typedef :
         {
            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))
                != GOOD)  return(err);
            break;
         }
         default :
            // Unknown forward reference type 
            return(ER_UNKNOWN_FWREF_TYPE);
      } // end of switch
   }
   
   // NOTE: 02/17/94 - Nghia
   // Dereference pointer
   typeHdr = (TYPE_HEADER_TYPE2 HUGE *)tt.GetHugeDataPtr(offset);
   
   // Extract the size of MAU and type name
   typeHeader->sizeInMAUs = typeHdr->sizeInMAUs;
   st.GetString(typeHdr->typeName,(U8 *) (typeHeader->typeName));

   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;
}

/******************************************************************
*
*  Update Pointer Type -- Hera 3/12/98
*
*******************************************************************/
RETCODE EXPORT SymUpdateTypePointerTypeIndex(TYPE_INDEX typeIndex,
					     TYPE_INDEX newTypeIndex){
   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));
   *typePtr = newTypeIndex;
   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;
}

//--------------------------------------------------------------------------
// SymGetTypeClass
//--------------------------------------------------------------------------
RETCODE EXPORT SymGetTypeClass(TYPE_INDEX typeIndex, LPSTR clsName,
                                     TYPE_C_STRUCT *cls,
                                     U16 *componentIndex, BOOLEAN *noMatch) {
   RETCODE err;
   TABLE_OFFSET offset, lastClsOffset = 0;
   TYPE_CLASS_HEADER HUGE *clsPtr;
   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;
      clsPtr = (TYPE_CLASS_HEADER HUGE *)tt.GetHugeDataPtr(offset +
                sizeof(TYPE_HEADER_TYPE2) + lastClsOffset);
      st.GetString(clsPtr->nameOffset, name);
      lastClsOffset += sizeof(TYPE_CLASS_HEADER);
      if( !strcmp(clsName, (S8 *) name)) {
         *noMatch = FALSE;
         break;
      }
   } while ( i-- );
   if (*noMatch == TRUE)
      return GOOD;

   strcpy(cls->name, (S8 *)name);
   cls->typeIndex = clsPtr->typeIndex;
   cls->offset = clsPtr->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;
}

//--------------------------------------------------------------------------
// SymGetTypeClassNth
//--------------------------------------------------------------------------
RETCODE EXPORT SymGetTypeClassNth(TYPE_INDEX typeIndex,
                                        U16 n,
                                        TYPE_C_STRUCT *cls) {
   RETCODE err;
   TABLE_OFFSET offset, lastClsOffset = 0;
   TYPE_CLASS_HEADER HUGE *clsPtr;
   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;
      clsPtr = (TYPE_CLASS_HEADER HUGE *)tt.GetHugeDataPtr(offset +
                sizeof(TYPE_HEADER_TYPE2) + lastClsOffset);
      lastClsOffset += sizeof(TYPE_CLASS_HEADER);
   } while ( i-- );

   
   st.GetString(clsPtr->nameOffset, name);
   strcpy(cls->name, (S8 *)name);
   cls->typeIndex = clsPtr->typeIndex;
   cls->offset = clsPtr->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;
}


//--------------------------------------------------------------------------
// 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)) )
      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:
            if (SUCCESS != (err = UtilSetAddrParams(
                                 symVar -> symHeader.typeIndex.baseIndex,
                                 symVar -> symHeader.beginAddrInfo.startAddr,
                                 symVar -> symHeader.endAddrInfo.endAddr,
                                 varAddr-> getFixedAddrDesc)))
               return err;
            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 <breakAddr> < startAddr of parent, OR
//       b) if <breakAddr> > endAddr of parent
//    4. If <breakAddr> is in block range, check for its current lifeTimeState
//       while (lifeTimeList != NULL) { 
//          if <breakAddr> > (<lifetimeOffset> + <startAddr of parent>) 
//             set the lifetimeState = the state indicated by the linked node.
//          Stop when <breakAddr> < (<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;
   OFFSET_ADDR_TYPE          breakAddr;
   U8                        tmpSymType;
   DESCRIPTOR                pcAddrDesc;
   RETCODE                   err, firstErr = GOOD;
   
   // make sure the symbol descriptor is ok
   if (!UtilIsValidSymDescriptor(inputSymbol))
      return ER_INVALID_SYM_DESCRIPTOR;

   varPtr = (SYM_TYPE_VARIABLE HUGE *)st.GetHugeDataPtr(inputSymbol);
   tmpSymType = (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(&pcAddrDesc)))
      return err;
   if (GOOD != (err = UtilGetOffsetFromAddrDesc(inputSymbol,
                                                pcAddrDesc,
                                                &breakAddr)))
      goto CLEANUP;

   // 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 breakAddr is not in parent block range - it's a DEAD variable
   if ((breakAddr < parentPtr->beginAddrInfo.startAddr) ||
       (breakAddr > 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 (breakAddr > ((parentPtr->beginAddrInfo.startAddr) +
          (lifetimePtr->lifetimeInfo.lifetimeAddr)) ) {
         *lifetimeState = lifetimePtr->lifetimeInfo.lifetimeClass;
      } else {
         break;     // assuming ascending, have gone past
      }
      currentOffset = lifetimePtr->nextLifetimeInfo;  // follow linked list
   }
CLEANUP:
   firstErr = err;
    err = AdrDestroyAddress(pcAddrDesc);
   if (GOOD == firstErr) firstErr = err;
   return firstErr;
}  // 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 = ht.GetEntryCount();
   }

   // retrieve the number of module loaded from the symbolStat[] table
   if (numModules)
      *numModules = symbolStat[SYM_MODULE];
   
   // 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);
      }
   
      if (numTypes != NULL) {
         tt.GetMaxTypeIndex(typeIndexMax);
         *numTypes = typeIndexMax;
      }
   }
   return (GOOD);
}  // end of SymGetLdrStats

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