/****************************************************************************
**
**  Name:  symget.cpp
**
**  Description:
**     routines for getting symbols out of the symbol table.
**
**  Status:  PRELIMINARY
**
**  $Log:   S:/tbird/mt2_186/symbol/symget.cpv  $
** 
**    Rev 1.3   12 Feb 1998 13:44:50   Judy
** 
**    Rev 1.2   22 Jul 1997 10:10:52   Judy
** 
**    Rev 1.1   26 Feb 1997 11:43:26   Judy
** 
**    Rev 1.1   14 Jan 1997 15:31:48   Judy
** No change.
** 
**    Rev 1.0   14 Jun 1996 16:42:18   Judy
** Initial revision.
** 
**    Rev 1.66   14 Jun 1995 11:32:42   nghia
** Fixed PPR10505 - GPF caused by MRI bogus Union type.
** Added check for memberCount > 0 for SymGetTypeHeader().
** 
**    Rev 1.65   06 Jun 1995 15:58:40   marilyn
** Fixed bug in SymGetStructUnion where memberIndex was returning -1 to n-1
** instead of 0 to N.  Found as a result of fixing ppr 10472.
** 
**    Rev 1.64   02 Jun 1995 10:18:40   nghia
** Fixed PPR 10418 - SymGetFuncType() always assumed that input symbol is
** of type TY_FUNC_xxxx, which is not true for assembly function.
** Added check for valid function type before allow extracting type information.
** 
**    Rev 1.63   09 May 1995 10:20:52   nghia
** Added symbol pointers validation and return ER_INVALID_SYM_DECRIPTOR if
** pointer is a NULL pointer.  This will prevent any GPF to occur.
** 
**    Rev 1.62   10 Mar 1995 17:44:12   nghia
** Fixed bug in SymGetTypeHeader() to calculated the sizeInMAU for Union
** type as the collecting the largest sizeMAU of its members.  Do not
** update the member offset - All member offsets are at 0.
** 
**    Rev 1.61   10 Mar 1995 14:52:52   nghia
** Fixed PPR 10083 - Cannot get public variables.
** 
**    Rev 1.60   12 Oct 1994 12:31:44   nghia
** Fixed PPR 9801.  - SymGetEndList() return bad value when the list has just
** one element. (Test file: /Britol/Boot/Sys333.omf).
** 
**    Rev 1.59   19 Sep 1994 18:40:24   brucea
** Fixed auto-decrement of memberCount in function SymGetTypeHeader
** Cleaned up columns, readability
** 
**    Rev 1.58   06 Sep 1994 16:09:38   nghia
** SymGetTypeHeader calculated member offsets, except the last member.
** Revised highBound array type = total sizeInMAU/ member sizeInMAU - 1.
** 
**    Rev 1.57   01 Sep 1994 18:03:40   nghia
** Added revision 1.55 - Bruce dropped off
** Revised SymGetTypeHeader to recalculate structure/union member offset.
** 
**    Rev 1.56   30 Aug 1994 13:19:48   brucea
** Modified SymGetVar to set the output address to type ADDR_USE_DS when the
** pointers are TY_SMALL_PTR or TY_LARGE_PTR
**
**    Rev 1.55   22 Aug 1994 16:10:58   nghia
** Fixed bug in SymUpdateTypeInfo().  
** 
**    Rev 1.54   17 Aug 1994 13:31:24   nghia
** Revised SymGetTypeHeader() to resolve OMF types that are not completely
** defined at load-time.  TY_C_ARRAY -> recalculate highBound.
** TY_TYPE -> recalculate sizeMAUs and update type name if not defined.
** Fixed bug in SymGetLdrStat() - return the number of symbols from the
** ordinals table, return the number of type loaded.
** 
**    Rev 1.53   11 Aug 1994 11:12:44   nghia
** Revised SymGetTypeHeaderType() to update type name for base type.
** Revised SymGetLdrStat() to use the ordinal table count as the number of 
** symbol loaded.
** 
**    Rev 1.52   19 May 1994 10:12:08   nghia
** Replace the old loader header with the new one.
** Integrated Loader Launcher.
** 
**    Rev 1.51   28 Mar 1994 10:49:58   nghia
** Added SymGetAllModules() to provide bulk-data access.
** 
**    Rev 1.50   25 Feb 1994 12:54:52   nghia
** Added symbolStat[] - to count the symbol types.
** Revised the interface to the loader to use the symbolStat[], instead of
** traverse the symbol table everytime to get the count.
** 
**    Rev 1.49   16 Nov 1993 10:25:16   nghia
** Fixed bug : Next lifeTimeState assigned when <breakAddr> > (blockAddr + life
** TimeOffset). - Also, revised the algorithm comments to reflect the actual
** implementation.
** 
**    Rev 1.48   30 Sep 1993 15:01:14   nghia
** Fixed bug in SymGetVarLifeInfo() 
** 1. Living register start out LIVE.
** 2. LifeTime information is local offset of the containing block.
** 
**    Rev 1.47   24 Sep 1993 10:27:38   nghia
** Support forward reference type.
** Added UpdateTypeInfo() routine to update type info.
** SymGetTypeHeader() do all the work to resolve any forward reference type of
** TYPEDEF, ARRAY, BITFIELD types.  Other types will be reported as an error.
** 
**    Rev 1.46   31 Aug 1993 10:11:08   ron
** 0 -> 0L (something Paul caught in code review)
** 
**    Rev 1.45   30 Aug 1993 10:51:16   ron
** added SymGetLdrStats to exported functions.
** 
**    Rev 1.44   05 Jul 1993 08:21:06   doug
** Use general syntax error.
** 
**    Rev 1.43   15 Jun 1993 11:34:00   mindy
** Have to change interface to SymGetVarLifetimeInfo since I needed to make
** it public to allow variable server to update just the lifetime information
** of register'd variables. Also needed to fix the LIVE/DEAD determination
** depending on if it's a living vs locked register.
** 
**    Rev 1.42   06 Jan 1993 17:38:22   brucea
** Changed: header (document) for SymGetSymbolFromContext
** Removed: setting of *symType in SymGetSymbolFromContext since it is an input
**    parameter
** 
**    Rev 1.41   04 Jan 1993 15:49:52   brucea
** Fixed: SymGetSymbolFromContext was not setting *symType when inputSymbol
**    was valid and before being used in switch statement
** Changed: removed ; for cosmetic reasons
** 
**    Rev 1.40   16 Dec 1992 07:05:00   brucea
** Fixed .symType access that didn't have 0xF mask in 
**    SymGetSymbolFromContext
** 
**    Rev 1.39   08 Dec 1992 07:04:00   brucea
** Cosmetic changes
** Fixed: bug in SymGetVarLifetimeInfo; it wasn't indexing to correct
**    data structure.
** 
**    Rev 1.38   03 Dec 1992 07:37:52   brucea
** Fixed bug: SymGetSymbolChild was returning error when no child existed
**    when it shouldn't have
** 
**    Rev 1.37   29 Aug 1992 22:04:16   brucea
** Added: SymGetParentModule, SymGetSymbolBasicType
** 
**    Rev 1.36   13 Aug 1992 10:57:02   brucea
** Changed: wsprint to sprintf
** Removed compile warnings
** 
**    Rev 1.35   06 Aug 1992 15:25:30   brucea
** Cleanup
** 
**    Rev 1.34   06 Aug 1992 10:16:24   brucea
** Changed access to .typeIndex.symType to use &0xF
** 
**    Rev 1.33   19 Jul 1992 22:01:46   brucea
** Modified: SymGetSymbolAddress to check for AUTO or BASED var and return error
**    if symbol is that type since they don't have a static address
** 
**    Rev 1.32   10 Jul 1992 20:00:10   brucea
** Fixed: HUGE pointers for local vars
** 
**    Rev 1.31   10 Jul 1992 19:22:48   brucea
** Added: HUGE to all casts of GetHugeDataPtr
** Fixed: SearchUpperFuncs to initialize the return offsetFound value
** Modified: SymGetSymbolFromContext to support no input descriptor, check
**       for no input symbol at beginning, 
** 
**    Rev 1.30   15 Jun 1992 09:27:30   brucea
** Changed: second parameter cast in GetString to LPU8
** Fixed up: compiler warnings for return params
** Changed: enumValue to U32 in SymGetTypeEnumName, SymGetTypeEnumValue
** 
**    Rev 1.29   30 Apr 1992 18:43:36   brucea
** Fixed: do while changed to while do to fix search for end of list in
**    SymGetEndList
** 
**    Rev 1.28   01 Apr 1992 23:41:06   brucea
** Added: #ifndef _HEAP_
** Implemented: SymGetSymbolAddress, SymGetSymbolName
** Fixed: compiler warnings
** 
**    Rev 1.27   12 Mar 1992 22:40:30   brucea
** Added: function name headers
** Fixed: SymGetModule to remove 2 control chars from front of name
** 
**    Rev 1.26   27 Feb 1992 22:43:36   brucea
** Fixed: in SymGetFuncVarHeadList, was calling SymGetSymbolHeadList with
**        SYM_FUNCTION when it should have been SYM_LOCAL_VAR
** 
**    Rev 1.25   04 Feb 1992 16:16:48   brucea
** In SymGetFuncByName, fixed bug to return GOOD instead of TRUE in last
**    statement
** SymGetVar, removed some local variables related to register lifetime;
**    removed code which indexed to lifetime info before calling
**    SymGetVarLifetimeInfo because the sub-indexing was already being done
**    in called function.
** 
**    Rev 1.24   13 Jan 1992 17:23:48   john
** Added code to make sure symbol descriptors passed in are valid.
** Added code to get variable lifetime information.
** 
**    Rev 1.23   08 Jan 1992 11:29:40   john
** Added new function SymGetLabel
** 
**    Rev 1.22   03 Jan 1992 09:21:10   john
** Fixed symgetsymbolchild.
** 
**    Rev 1.21   20 Dec 1991 16:52:16   john
** Fixed loop counter in SymGetTypeXXX calls
** 
**    Rev 1.20   18 Dec 1991 14:34:00   john
** GET_VAR_ADDR_UNION as implemented caused the address descriptor
** that was passed in to be overwritten.  The union was redesigned
** to prevent this.  The code has been changed to reflect the new
** struct.
** 
**    Rev 1.19   18 Dec 1991 11:18:30   john
** Fixed error in SymGetVar.  Living registers are supported
** 
**    Rev 1.18   13 Dec 1991 19:08:10   brucea
** Added SymGetFuncVarHeadList
** 
**    Rev 1.17   13 Dec 1991 14:07:42   brucea
** Added call to UtilIsValidDescriptor
** SymGetSymbolFromContext: fixed bug to return symbol type
** 
**    Rev 1.16   11 Dec 1991 16:46:06   brucea
** Removed GetAddrFromDesc (put it into symutil.cpp)
** 
**    Rev 1.15   09 Dec 1991 12:15:58   john
** Fixed type for the base index table
** 
**    Rev 1.14   04 Dec 1991 11:14:16   brucea
** In SymGetSymbolHeadList, added test for SYM_ROOT
** 
**    Rev 1.13   03 Dec 1991 16:59:34   john
** fixed a bug in SearchUpperFuncs
** 
**    Rev 1.12   02 Dec 1991 18:01:52   john
** Added call to support on demand loading
** 
**    Rev 1.11   02 Dec 1991 14:39:10   john
** Accidentally killed SymGetModuleReference during a merge.
** 
**    Rev 1.10   02 Dec 1991 13:02:24   john
** Merged branches 1.9.1 and 1.9.2
** 
**    Rev 1.9.2.1   02 Dec 1991 09:42:28   brucea
** Changes following:
** 
** Added include for symutil.h
** Added GetAddrFromDesc
** changes to SymGetFunc
** Removed SymGetCompAddr
** changed begin and endInfo to beginAddrInfo, etc.
** Removed functions that will not be implemented, including Const routines
** Added SymGetModule
** changed SymGetModuleName to SymGetModuleDesc
** removed SymGetSymbolByName, SymGetSymbolStruct, GetType calls
** modified parameters to SymGetVar and fixed up code to handle reg types;
**   this included changing structures and added data to end of stored
**   data structure for locked registers
**
**    Rev 1.9.1.3   27 Nov 1991 13:01:06   john
** Created a function to get a descriptor of the last entry in the
** label/var/const/misc linked lists.
** 
**    Rev 1.9.1.2   25 Nov 1991 14:07:34   john
** Created function call "SymGetModuleListHead".
** 
**    Rev 1.9.1.1   21 Nov 1991 15:26:32   john
** Added code for:
**    SymGetTypeStructUnionNth, SymGetTypeTypeIndex, SymGetTypeBitfield,
**    SymGetFuncType, SymGetFuncParamNth.
** Changed SymGetVar to pass back more info.  This was done to reduce
** the number of calls required to get variable info.
** 
** 
**    Rev 1.9   20 Nov 1991 10:09:14   john
** Fixed compile errors
** 
**    Rev 1.8   20 Nov 1991 09:19:26   john
** Added a call to get the largest type index used.  This is used
** for on demand loading.
** Changed GetSymbolFromContext to only use the base variable name
** when looking things up.
** Made changes to SymGetVar to return the symbols function/module
** descriptors.
** 
**    Rev 1.7   15 Nov 1991 14:03:38   john
** - COMMON_SYMBOL_HEADER changed.  Variables using this structure
**   were updated to match.
** - Made changes to SymGetSymbolFromContext to allow for complex
**   types.
** - Added code to SymGetTypeCArray.
** - Added code to SymGetTypeEnumName.
** - Added code to SymGetTypeEnumValue.
** - Added code to SymGetTypeHeader.
** - Added code to SymGetTypeMemberCount.
** - Added code to SymGetTypePointerTypeIndex.
** 
**    Rev 1.6   12 Nov 1991 13:53:02   brucea
** Created SymGetModuleName
** Removed SymGetLinenumAddr, SymGetLinenumAddrNext
** 
**    Rev 1.5   07 Nov 1991 13:52:08   john
** Stubbed out many SymGet routines
** 
**    Rev 1.4   06 Nov 1991 13:30:04   john
** Removed compile time warnings w/max warning level enabled
** 
**    Rev 1.3   06 Nov 1991 11:03:50   john
** Fixed the algorithm for GetFromContext.
** Fixed the algorithm for SearchUpperFuncs.
** 
**    Rev 1.2   01 Nov 1991 17:30:28   john
** Fixed logical errors.
** 
**    Rev 1.1   31 Oct 1991 17:03:06   john
** Changed prototype on SymGetCompAddr so that it isn't exportable.
** Added SymGetFuncByName.
** Fixed bug in SymGetVar.  Strings can't be directly copied out of the
** symbol table because they aren't null terminated.
** 
**    Rev 1.0   17 Oct 1991 10:15:24   john
** Initial revision.
**
**  $Header:   S:/tbird/mt2_186/symbol/symget.cpv   1.3   12 Feb 1998 13:44:50   Judy  $
**
**  Copyright (C) 1991 Microtek International.  All rights reserved.
**
*****************************************************************************/

                       /****************************
                        *                          *
                        *       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 _LOADER_
#include "loader.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

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

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

                       /****************************
                        *                          *
                        *      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;
   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);
      if (!constPtr) return ER_INVALID_SYM_DESCRIPTOR;
      st.GetString(constPtr->symbolNameOffset,name);
      if ((CaseFlag && !strcmp(symName,(S8 *) name)) ||
          (!CaseFlag && !stricmp(symName,(S8 *) name))) {
         *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) return ER_INVALID_SYM_DESCRIPTOR;
   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);
      if (!symPtr) return ER_INVALID_SYM_DESCRIPTOR;
      sibPtr = (COMMON_BLOCK_HEADER HUGE *) 
                            st.GetHugeDataPtr(symPtr->child);
      if (!sibPtr) return ER_INVALID_SYM_DESCRIPTOR;
      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 ((CaseFlag && !strcmp(symName, (S8 *)name)) ||
                (!CaseFlag && !stricmp(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;
               tmpSymbol = siblingSymbol; //Hera 6/23/97
            } 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);
   if (!base) return ER_INVALID_SYM_DESCRIPTOR;
   *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);
   if (!symPtr) return ER_INVALID_SYM_DESCRIPTOR;
   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;

   // 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,
           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) return ER_INVALID_SYM_DESCRIPTOR;
   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) return ER_INVALID_SYM_DESCRIPTOR;
   
   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
   //Hera 6/4/97
   //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 || symType == SYM_BLOCK) //Hera 6/4/97
      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);
   if (!symPtr) return ER_INVALID_SYM_DESCRIPTOR;
   st.GetString(symPtr->symbolNameOffset,name);
   if ((CaseFlag && !strcmp(funcName,(S8 *) name)) ||
       (!CaseFlag && !stricmp(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);
         if (!symPtr) return ER_INVALID_SYM_DESCRIPTOR;
         st.GetString(symPtr->symbolNameOffset,name);
         symOffset = sibOffset;
      }
      if ((CaseFlag && !strcmp((S8 *)name,funcName)) ||
          (!CaseFlag && !stricmp((S8 *)name,funcName)))
         break;
   } while (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) return ER_INVALID_SYM_DESCRIPTOR;
   
   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 (!funcHdr) return ER_INVALID_SYM_DESCRIPTOR;      
   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) return ER_INVALID_SYM_DESCRIPTOR;
   
   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));
   if (!funcHdr) return ER_INVALID_SYM_DESCRIPTOR;
   // 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;
   TYPE_HEADER_TYPE2 HUGE *typeHdr;

   // Initialize returned parameters with 0 and NULL
   *attribute = *pushMask = 0L;
   *argCount = *frameType = *level = 0;
   *fatherName = NULL;
   
   // 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) return ER_INVALID_SYM_DESCRIPTOR;   
   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;
   
   // 06/01/95 - Nghia
   // Check to make sure that <funcPtr->typeIndex> is either type
   // TY_FUNC_NODEP or TY_FUNC_DEP, or else will get the bad information.
   // See PPR 10418 - PC @ function #start which is type TY_VOID
   // When lookup symbol type information, bad thing happens.
   typeHdr = (TYPE_HEADER_TYPE2 HUGE *)tt.GetHugeDataPtr(offset);
   if (!typeHdr) return ER_INVALID_SYM_DESCRIPTOR;
   
   // Access return type information only if it is actually a function type
   if ((typeHdr->t.complexType != TY_FUNC_NODEP) &&
       (typeHdr->t.complexType != TY_FUNC_DEP)) {
      // The return type is the function type itself, which always is TY_VOID
      // fill in the return type header 
      return SymGetTypeHeader(funcPtr->typeIndex, returnType);
   }
   
   funcHdr = (FUNC_TYPE_HEADER HUGE *)tt.GetHugeDataPtr(offset + 
             sizeof(TYPE_HEADER_TYPE2));
   if (!funcHdr) return ER_INVALID_SYM_DESCRIPTOR;   
   *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) {
      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) return ER_INVALID_SYM_DESCRIPTOR;
   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);
   if (!labelPtr) return ER_INVALID_SYM_DESCRIPTOR;
   
   // 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_MODULE 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_MODULE HUGE *)st.GetHugeDataPtr(inputModule);
   if (!modPtr) return ER_INVALID_SYM_DESCRIPTOR;
   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);
      if (!modPtr) return ER_INVALID_SYM_DESCRIPTOR;
      // compare path name to module stored path name
      st.GetString(modPtr -> srcFilenameOffset, pathNameArray);
      if (!lstrcmp(pathName, (LPSTR)pathNameArray))  {
         return SUCCESS;
      }
      entry++;
   }
}

//-------------------------------------------------------------------------  
// 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) return ER_INVALID_SYM_DESCRIPTOR;
   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) return ER_INVALID_SYM_DESCRIPTOR;
   if (((modPtr->symHeader.symHeader.typeIndex.symType) & 0xF) != SYM_MODULE)
      return ER_SYMBOL_NOT_A_MODULE;
   *timestamp = modPtr->timestamp;
   return GOOD;
}

//--------------------------------------------------------------------------
// SymGetModuleExtraInfo
//--------------------------------------------------------------------------
RETCODE EXPORT SymGetModuleExtraInfo(SYM_DESCRIPTOR moduleDescriptor,
                                     U32 *auxFileOffset,
                                     LANGUAGE_TYPE *langType) {
   SYM_TYPE_MODULE HUGE *modPtr;

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

   modPtr = (SYM_TYPE_MODULE HUGE *) st.GetHugeDataPtr(moduleDescriptor);
   if (!modPtr) return ER_INVALID_SYM_DESCRIPTOR;
   if (((modPtr->symHeader.symHeader.typeIndex.symType) & 0xF) != SYM_MODULE)
      return ER_SYMBOL_NOT_A_MODULE;

   *auxFileOffset = modPtr->auxFileOffset;
   *langType      = modPtr->langType;
   return GOOD;
}  // end of SymGetModuleExtraInfo


//-------------------------------------------------------------------------  
// 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 (!symPtr) return ER_INVALID_SYM_DESCRIPTOR;

   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);
   if (!blockPtr) return ER_INVALID_SYM_DESCRIPTOR;

   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;
   LPSTR         ptrVar; /* <Winky 9/1/97> */

   // 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);
      if (!headPtr) return ER_INVALID_SYM_DESCRIPTOR;
      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;
         } else { /* added by <Winky 9/1/97> */
            ptrVar = (LPSTR)symName;
            if (strncmp(symName,"_",1) == 0) {
               ptrVar++;
               SearchUpperFuncs(inputSymbol, ptrVar, & offsetFound);
               if (offsetFound) {
                  *symType = SYM_FUNCTION;
                  break;
               }
            }
         }        /* eof by <Winky 9/1/97> */

         // 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 ((CaseFlag && !strcmp(symName,(S8 *) name)) ||
             (!CaseFlag && !stricmp(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);
   if (!ptr) return ER_INVALID_SYM_DESCRIPTOR;

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

//Hera 5/27/97
RETCODE EXPORT
SymGetSegInfo(SYM_DESCRIPTOR inputSymbol, SEG_INFO *segInfo) {
   COMMON_SYMBOL_HEADER HUGE *symPtr;
   
   if (!UtilIsValidSymDescriptor(inputSymbol)) 
      return ER_INVALID_SYM_DESCRIPTOR;
   symPtr = (COMMON_SYMBOL_HEADER HUGE *)st.GetHugeDataPtr(inputSymbol);
   if (!symPtr) return ER_INVALID_SYM_DESCRIPTOR;
   memcpy(segInfo, symPtr, sizeof(SEG_INFO));
   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);
   if (!symPtr) return ER_INVALID_SYM_DESCRIPTOR;

   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);
   if (!ptr) return ER_INVALID_SYM_DESCRIPTOR;
   *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);
      if (!ptr) return ER_INVALID_SYM_DESCRIPTOR;
      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);
   if (!ptr) return ER_INVALID_SYM_DESCRIPTOR;

   *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);
   if (!ptr) return ER_INVALID_SYM_DESCRIPTOR;
   
   // 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);
   if (!ptr) return ER_INVALID_SYM_DESCRIPTOR;
   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));
   if (!bitPtr) return ER_INVALID_SYM_DESCRIPTOR;
   // 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));
   if (!arrayPtr) return ER_INVALID_SYM_DESCRIPTOR;
   // 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);
      if (!enumPtr) return ER_INVALID_SYM_DESCRIPTOR;
      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);
      if (!enumPtr) return ER_INVALID_SYM_DESCRIPTOR;
      st.GetString(enumPtr->enumName, name);
      lastEnumOffset += sizeof(ENUM_TYPE_STRUCT);
      if ((CaseFlag && !strcmp(enumName,(S8 *) name)) ||
          (!CaseFlag && !stricmp(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);
   if (!typeHdr) return ER_INVALID_SYM_DESCRIPTOR;   
 
   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));
            if (!arrayPtr) return ER_INVALID_SYM_DESCRIPTOR;            
            // 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_BITFIELD :
         {
            TYPE_BITFIELD_STRUCT HUGE *bitPtr; // Pointer to bitfield info
            bitPtr = (TYPE_BITFIELD_STRUCT HUGE *)tt.GetHugeDataPtr(offset + 
                                                  sizeof(TYPE_HEADER_TYPE2));
            if (!bitPtr) return ER_INVALID_SYM_DESCRIPTOR;
            // 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 :
         {
            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;
            // 06/14/95 - Nghia
            // Fixed PPR 10505 - GPF when load MRI bogus union type
            // Do not try to access member type if <memberCount> is 0
            if (!memberCount) break;
            do {
               //get the i'th struct entry;
               structPtr = (TYPE_STRUCT_HEADER HUGE *)tt.GetHugeDataPtr(offset
                  + sizeof(TYPE_HEADER_TYPE2) + lastStructOffset);
               if (!structPtr) return ER_INVALID_SYM_DESCRIPTOR;
               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 += baseTypeHeader.sizeInMAUs;
               }   
            } while (--memberCount);

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

         case TY_UNION  :
         {
            TABLE_OFFSET lastStructOffset = 0L;
            TYPE_STRUCT_HEADER HUGE *structPtr;
            U16 memberCount, largestMAU = 0;
            // get the number of members in this struct/union type
            if ((err = SymGetTypeMemberCount(typeIndex,&memberCount)) != GOOD) 
               return err;

            // 06/14/95 - Nghia
            // Do not try to access member type if <memberCount> is 0
            if (!memberCount) break;
            
            do {
               //get the i'th struct entry;
               structPtr = (TYPE_STRUCT_HEADER HUGE *)tt.GetHugeDataPtr(offset
                  + sizeof(TYPE_HEADER_TYPE2) + lastStructOffset);
               if (!structPtr) return ER_INVALID_SYM_DESCRIPTOR;
               lastStructOffset += sizeof(TYPE_STRUCT_HEADER);
               // All union member offset is at 0.
               structPtr->offset = 0L;
               // get the member baseType information
               if ((err = SymGetTypeHeader((TYPE_INDEX)structPtr->typeIndex,
                                          &baseTypeHeader)) != GOOD)
                  return(err);
               // Get the largest sizeInMAU as the sizeInMAU for the union
               largestMAU = ((baseTypeHeader.sizeInMAUs > largestMAU) ?
                            baseTypeHeader.sizeInMAUs : largestMAU);
                  
            } while ((--memberCount) > 0);

            // Now update the defined union type
            typeHdr->sizeInMAUs = largestMAU;
            typeHdr->sizeCalculated = TRUE;
            break;
         }
	 case TY_FUNC_NODEP: //Hera 6/4/97
	    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);   
   if (!typeHdr) return ER_INVALID_SYM_DESCRIPTOR;

   // 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);
   if (!typeHdr) return ER_INVALID_SYM_DESCRIPTOR;   
   *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;
}

//--------------------------------------------------------------------------
// 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);
      if (!structPtr) return ER_INVALID_SYM_DESCRIPTOR;
      st.GetString(structPtr->nameOffset, name);
      lastStructOffset += sizeof(TYPE_STRUCT_HEADER);
      if ((CaseFlag && !strcmp(structName,(S8 *) name)) ||
          (!CaseFlag && !stricmp(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
   // 06/05/95 Marilyn: since rev. 1.21 we have started at memberCount so
   // fix componentIndex calculation.
   *componentIndex = memberCount - i;
   
   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;
}


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

   // 02/27/95 - Nghia
   // Added SYM_PUBLIC_VAR to list of supported variable types.
   if (!((((symVar->symHeader.typeIndex.symType) & 0xF) == SYM_GLOBAL_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:
            if (SUCCESS != (err = UtilSetAddrParams(
                                 symVar -> symHeader.typeIndex.baseIndex,
                                 symVar -> symHeader.beginAddrInfo.startAddr,
                                 symVar -> symHeader.endAddrInfo.endAddr,
                                 varAddr-> getFixedAddrDesc)))
               return err;
            // if var is small or large pointer, change ADDR_SEGSEL_TYPE
            // to ADDR_USE_DS.  This should not affect a Moto addr descriptor

            TYPE_HEADER_TYPE typeHeader;
            ADDR_SEGSEL_TYPE type;
            U16              segSelect;
            U8               typeName[MAX_SYMNAME_LENGTH] = "";
            
            typeHeader.typeName = (LPSTR)typeName;
            if (GOOD != (err = SymGetTypeHeader(symVar->typeIndex,
                                                &typeHeader)))
               return err;
            if (typeHeader.typeChoice == COMPLEX_TYPE_CLASS) {
               if ((typeHeader.t.complexType == TY_SMALL_PTR) ||
                   (typeHeader.t.complexType == TY_LARGE_PTR)) {
                  // set ADDR_USE_DS type value, the hard way
                  if (GOOD != (err =
                      AdrGetAddrSegmentSelector(varAddr->getFixedAddrDesc,
                                                &type,
                                                &segSelect)))
                     return err;
                  if (GOOD != (err =
                      AdrSetAddrSegmentSelector(varAddr->getFixedAddrDesc,
                                                ADDR_USE_DS,
                                                &segSelect)))
                     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;
   U16                       segment;//Hera 6/4/97

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

   varPtr = (SYM_TYPE_VARIABLE HUGE *)st.GetHugeDataPtr(inputSymbol);
   if (!varPtr) return ER_INVALID_SYM_DESCRIPTOR;

   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,
						&segment,
                                                &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 = ot.GetOrdinalCount();
   }

   // retrieve the number of module loaded from the symbolStat[] table
   if (numModules)
      *numModules = 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 ***********************************/
