/****************************************************************************
**
**  Name:  basetbl.cpp
**
**  Description:
**     This module contains routines for accessing BASE symbols.
**
**  Status:  TESTED
**
**  $Log:   S:/tbird/mt2_186/symbol/basetbl.cpv  $
** 
**    Rev 1.1   26 Feb 1997 11:42:22   Judy
** 
**    Rev 1.1   14 Jan 1997 15:30:28   Judy
** No change.
** 
**    Rev 1.0   14 Jun 1996 16:41:52   Judy
** Initial revision.
** 
**    Rev 1.24   20 Jan 1995 09:59:28   nghia
** Fixed PPR 10012 for PV 2.4
** Added EVENT_SYMBOL_BASE_CHANGED to SymUpdateSymbolBases().
** 
**    Rev 1.23   05 Jan 1995 16:27:34   nghia
** Fixed GPF bug - GE reports : o:/customer/386real/ge/em3_tcp.sys
** Revised BaseSymbol constructor to avoid allocate memory for self data member
** while the object construction is not done.  Moved baseNameOffset and
** byAddressTableOffset initialization to the SymAddBaseCreate_xxx() callers.
** 
**    Rev 1.22   10 Oct 1994 17:38:28   nghia
** Revised SynFindBaseIndexFromSeg/Selector to return the base type.
** 
**    Rev 1.21   26 Sep 1994 10:19:34   nghia
** Revised symbol base access routine to return gdtSel and segmentOrLdtSel.
** Revised update symbol bases routine to set address correctly.  Also continue
** to update base when an error occurred.
** 
**    Rev 1.20   22 Sep 1994 14:49:08   nghia
** Revised update symbol bases routine to continue to update other bases when
** an error occurred in updating a base.
** 
**    Rev 1.19   20 Sep 1994 10:16:02   marilyn
** Fixed bug in updateSymbolBases where gdt and ldt were switched.
** 
**    Rev 1.18   22 Aug 1994 18:31:54   brucea
** Changed error message in SymUpdateSymbolBases
** Added: SymTranslateLinearToVirtual export function
** 
**    Rev 1.17   04 Aug 1994 18:23:32   brucea
** Removed reporting of ER_SYM_NO_SELECTORS_FOUND error.  The caller and use
** the baseCount of 0 to put up its own message.
** 
**    Rev 1.16   03 Aug 1994 11:47:58   brucea
** Cosmetic changes
** 
**    Rev 1.15   25 Jul 1994 12:29:38   brucea
** Changed error message for basename not found
** Added function SymUpdateSymbolBases()
** 
**    Rev 1.14   14 Jul 1994 01:45:42   brucea
** Added: SymFindBaseIndexFromSegment and Selector
**        template for SymUpdateSymbolBases
** 
**    Rev 1.13   25 Jul 1992 16:30:36   brucea
** Added: init of baseCount to 0L in ::ObliterateTable; fixes bug where
**    base count kept getting larger with each new symbol load
** 
**    Rev 1.12   10 Jul 1992 18:50:50   brucea
** Changed: return structure in BaseSymbol constructor
** Added: incrementing baseCount to keep track of number of base indices 
** 
**    Rev 1.11   20 Apr 1992 08:41:48   brucea
** 
**    Rev 1.10   20 Apr 1992 07:58:18   brucea
** Changed: initialization of cached PRIVATE variables now done in
**    BasetblResetCacheVars which is now called from RemoveAllByAdrTables.
**    The initialization at the point of declaration was removed.
** Changed: private variable err to globalErr
** Fixes: PPR5473
** 
**    Rev 1.9   01 Apr 1992 23:39:40   brucea
** Fixed: compiler warnings
** 
**    Rev 1.8   11 Dec 1991 16:31:04   john
** Added function to get base offsets given a base name
**
**    Rev 1.7   06 Dec 1991 17:09:34   john
** Moved the "inline code" from the header here since the code was too
** involved to be left inline.
** Added routine to remove the dynamically allocated by-address tables.
**
**    Rev 1.6   29 Nov 1991 19:56:22   brucea
** changed NULL to NULL_SYMBOL
**
**    Rev 1.5   15 Oct 1991 13:37:46   john
** Changed the name of the return code "err" to "retErr" so that it did
** not override the global "err".
**
**    Rev 1.4   14 Oct 1991 14:02:50   brucea
** Put check for NULL for previousBaseOffset which handles the initial condition
** for updating the nextBaseOffset
** 
**    Rev 1.3   14 Oct 1991 13:57:14   john
** The global variable err was overriden by the passed parameter.  I renamed
** the passed parameter to remove the name conflict.
** 
**    Rev 1.2   14 Oct 1991 11:46:40   brucea
** No change.
** 
**    Rev 1.1   11 Oct 1991 15:17:00   brucea
** Changed BaseSymbol to a class and added access methods
** 
**    Rev 1.0   03 Oct 1991 11:42:56   john
** Initial revision.
**
**  $Header:   S:/tbird/mt2_186/symbol/basetbl.cpv   1.1   26 Feb 1997 11:42:22   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 _ENLIB_
#include "enlib.h"
#endif

#ifndef _EVENTS_
#include "events.h"
#endif

#ifndef _BYADRTBL_
#include "byadrtbl.h"
#endif

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

#ifndef _INDEXTBL_
#include "indextbl.h"
#endif

#ifndef __STRING_H
#include "string.h"
#endif

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

                       /****************************
                        *                          *
                        *     GLOBAL DEFINITIONS   *
                        *                          *
                        ****************************/

BaseIndexTable bit;   // Create Base Index Table object

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

#define ALL_ONES 0xFFFF

PRIVATE RETCODE globalErr;    // "global" error holder

// The purpose of these cached vars is to speed up access to the base instance
// and the by-address table instance, since many symbols are added to the same
// by-address table.  The code checks that the requested base is the same as
// the cached one.  If true, the offsets are used to access the information or
// add to the tables.
// NOTE: the actual HPU8 physical address to the tables cannot be cached
// because the table can move around.

// Set to non-legal values so they will be updated upon first use
// Must be re-initialized during the removal of symbols
PRIVATE BASE_INDEX   cachedBaseIndex;
PRIVATE TABLE_OFFSET cachedByAddressOffset;
PRIVATE TABLE_OFFSET cachedBaseOffset;

// USED FOR TABLE CREATION AND FOR ADDING A BASE
PRIVATE TABLE_OFFSET previousBaseOffset;
PRIVATE TABLE_OFFSET currentBaseOffset;

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

extern MemPool st;

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


//--------------------------------------------------------------------------
// UpdateCacheVars
//
// Description:
//    Internal routine to update cached variables for base and by-address
//    table access
//--------------------------------------------------------------------------
RETCODE PRIVATE UpdateCacheVars(BASE_INDEX baseIndex);

                       /**************
                        *            *
                        *    CODE    *
                        *            *
                        **************/

//--------------------------------------------------------------------------
//  BaseSymbol::BaseSymbol  (Parameterized CONSTRUCTOR)
//
//  Description:
//     Creates an instance of a BaseSymbol and puts it in st
//     Fills in the passed parameters into the BaseSymbol and initializes
//     all other BaseSymbol vars.
//                             01/05/95 - Nghia
//     When constructing a BaseSymbol object from the st table; the 
//     st table can be extended and reallocate to a different memory block.
//     Therefore, inside the constructor, no memory allocation from st can be
//     allowed
//
//  Parameters:
//    input:
//       baseIndex: the index into the base index table
//       baseAddress: the base address
//       baseTypeParam: type of base; code, data, both, unknown
//
//    output:
//       retErr: pass-by-reference error code, returning error code
//               from "new" constructor
//
//--------------------------------------------------------------------------
BaseSymbol::BaseSymbol(BASE_INDEX inputBaseIndex,
                       BASE_ADDRESS baseAddr,
							  BASE_TYPE baseTypeParam,
                       RETCODE& retErr) {
   BaseSymbol *previousBasePtr;

   // operator "new" writes to the global variable <globalErr>; check it
   // before going on
   if (globalErr != GOOD) {
      retErr = globalErr;
      return;
   }
 
   // fill in all known parameters and nullify those not yet known
   baseNameOffset = 0L;
   byAddressTableOffset = 0L;
   baseAddress = baseAddr;
   addressMin = 0xFFFFFFFFL;
   addressMax = 0L;
   baseType = (U8)baseTypeParam;
   addrTableDirty = FALSE;
   nextBaseOffset = NULL_SYMBOL;

   // initialize new entries for Intel segment/selectors or for
   // Motorola state
   segOrLDTsel = 0;
   GDTsel = 0;
   segAddrSpace = (U8)SEG_SPACE_USER;
   symMode = SYM_NONE;

   // update the previous base's nextBaseOffset to point to this one, but
   // only if it is not the first one created
   // update previousBaseOffset
   if (previousBaseOffset != NULL_SYMBOL)  {
      previousBasePtr =
         (BaseSymbol *)st.GetHugeDataPtr(previousBaseOffset);
      previousBasePtr->nextBaseOffset = currentBaseOffset;
   }
   previousBaseOffset = currentBaseOffset;

   // save the input index into the base itself for later lookup
   baseIndex = inputBaseIndex;
   // put the index value of the newly created base into "bit" - the 
   // base index table.
   retErr = bit.BaseAddIndex(baseIndex, currentBaseOffset);
   return;  
}  // end of BaseSymbol::BaseSymbol


//--------------------------------------------------------------------------
// BaseSymbol::operator new
//
// Purpose: allocates memory for a new BaseSymbol
//
// Input parameter:
//    size: amount of space to allocate
//
// Global Output parameter:
//    globalErr: RETCODE from memory allocation, or
//               trying to alloc more than max # of bases allowed
//
// Return parameter: (huge?) pointer to allocated memory
//--------------------------------------------------------------------------
VOID *BaseSymbol::operator new(size_t size)  {

   TABLE_OFFSET stOffset;

   // check for attempting to go one beyond max number of bases
   if (bit.BaseGetBaseCount() > MAX_BASE_INDEX_SIZE) {
      globalErr = ER_SYM_MAX_SEGCOUNT_REACHED;
      return NULL;
   }
   globalErr = st.AllocBytes(size, stOffset);
   if (globalErr == GOOD)  {
      // save offset context for linking bases together
      currentBaseOffset = stOffset;

      return (VOID *)st.GetHugeDataPtr(currentBaseOffset);
      }
   else
      return GOOD;
   }  // end of BaseSymbol::operator new

//---------------------------------------------------------------------------
//  Member functions for BaseIndexTable
//---------------------------------------------------------------------------

//---------------------------------------------------------------------------
//  BaseAddIndex
//---------------------------------------------------------------------------
RETCODE BaseIndexTable::BaseAddIndex(TABLE_INDEX index, 
                                     TABLE_OFFSET itemOffset) {
   RETCODE retCode;

   retCode = AddIndex(index, itemOffset);
   if (retCode == GOOD) {
      if (rootBaseSymbolOffset == NULL_SYMBOL)  {
         rootBaseSymbolOffset = itemOffset;
      }
   }
   // increment base count
   baseCount++;

   return retCode;
} // end of BaseAddIndex

//---------------------------------------------------------------------------
//  ObliterateTable
//---------------------------------------------------------------------------
VOID BaseIndexTable::ObliterateTable(VOID) {
   RemoveAllByAdrTables();
   IndexTable::ObliterateTable();
   rootBaseSymbolOffset = NULL_SYMBOL;
   baseCount = 0L;
} 

                       /****************************
                        *                          *
                        *    NON-CLASS FUNCTIONS   *
                        *                          *
                        ****************************/

//--------------------------------------------------------------------------
//  AddAddrToByAddrTable
//
//  Description:
//    Adds a symbol offset to the by-address sorted table maintained by 
//    the base symbol.  It also updates the base min and max address vars
//     
//  Parameters:
//    input:
//       baseIndex: the index into the base index table
//       symAddr: the offset to the symbol being added
//       minAddr, maxAddr: values to update min and max base address vars
//    output:
//       none:
//
//  Private vars:
//    cachedBaseIndex, cachedBaseOffset, cachedByAddressOffset, err
//
//  Errors:
//    reports error if baseIndex is not in the table
//
//--------------------------------------------------------------------------
RETCODE
AddAddrToByAddrTable(BASE_INDEX baseIndex, TABLE_OFFSET symOffset,
                     U32 minAddr, U32 maxAddr)  {
   
   ByAddressTable *byAddressTablePtr;
   BaseSymbol     *baseSymbolPtr;
   RETCODE        err;

   // check to see if last baseIndex is same as present baseIndex
   if (cachedBaseIndex != baseIndex)  {
      if ((err = UpdateCacheVars(baseIndex)) != GOOD) return err;
      }

   // the by-address table itself is GlobalAlloc'ed; must get pointer to table
   byAddressTablePtr =
      (ByAddressTable *)st.GetHugeDataPtr(cachedByAddressOffset);

   // put the new symbol offset (which contains its address) into the
   // by-address sorted table
   byAddressTablePtr->PutU32(symOffset);

   baseSymbolPtr = (BaseSymbol *)st.GetHugeDataPtr(cachedBaseOffset);

   // mark the by-address table unsorted
   baseSymbolPtr -> SetAddrTableDirty(TRUE);

   // update min and max address vars
   baseSymbolPtr -> UpdateAddrVars(minAddr, maxAddr);
   
   return(GOOD);
}  // end of AddAddrToByAddrTable


//--------------------------------------------------------------------------
//  BaseSetAddr
//
//  Description:
//    Modifies the base address of <baseIndex>
//     
//  Parameters:
//    input:
//       baseIndex: the index into the base index table
//       baseAddress: the base address
//    output:
//       none:
//--------------------------------------------------------------------------
RETCODE BaseSetAddr(BASE_INDEX baseIndex, BASE_ADDRESS baseAddr) {
   
   BaseSymbol *basePtr;
   RETCODE    err;

   // check to see if last baseIndex is same as present baseIndex
   if (cachedBaseIndex != baseIndex)  {
      if ((err = UpdateCacheVars(baseIndex)) != GOOD) return err;
      }

   // get pointer to BaseSymbol and fill in base address
   basePtr = (BaseSymbol *)st.GetHugeDataPtr(cachedBaseOffset);
   basePtr->SetBaseAddr(baseAddr);
   return(GOOD);
}  // end of BaseSetAddr


//--------------------------------------------------------------------------
//  GetBaseOffsetByName
//
//  Description:
//    Gets a base index by its base name.
//     
//  Parameters:
//    input:
//       baseName: the name of the base.
//
//    output:
//       baseIndex: the index of the base found. 
//    error:
//       if the base is not found.
//--------------------------------------------------------------------------
RETCODE GetBaseOffsetByName(LPSTR baseName, TABLE_OFFSET &baseOffset) {

   BaseSymbol   *basePtr;
   TABLE_OFFSET baseNameOffset;
   TABLE_OFFSET tmpBaseOffset;
   U8           name[MAX_SYMNAME_LENGTH];

   tmpBaseOffset = bit.GetRootBaseSymbolOffset();

   while (tmpBaseOffset) {
      // get the name of the base ;
      basePtr = (BaseSymbol *) st.GetHugeDataPtr(tmpBaseOffset);
      baseNameOffset = basePtr->GetBaseNameOffset();
      st.GetString(baseNameOffset, name);

      // check to see if the names match;
      if (!strcmp(baseName, (S8 *)name)) {
         // the names match;
         baseOffset = tmpBaseOffset;
         return(GOOD);
      }
      tmpBaseOffset = basePtr->GetNextBaseOffset();
   }
   return(ER_BASENAME_NOT_FOUND);
}


//--------------------------------------------------------------------------
//  SymFindBaseIndexFromSegment
//
//  Description:
//    Gets a base index by its segment or selector value
//     
//  Parameters:
//    input:
//       segment: segment
//       segAddrSpace: which Intel space is being searched - USER or SMM
//
//    output:
//       baseIndex: the index of the base found. 
//    error:
//       if the base is not found.
//--------------------------------------------------------------------------
RETCODE EXPORT
SymFindBaseIndexFromSegment(U16 segment,
                            SEG_ADDR_SPACE segAddrSpace,
                            BASE_INDEX FAR *baseIndex,
                            BASE_TYPE FAR *baseType) {

   TABLE_OFFSET tmpBaseOffset;
   BaseSymbol   *basePtr;

   tmpBaseOffset = bit.GetRootBaseSymbolOffset();

   while (tmpBaseOffset) {
      basePtr = (BaseSymbol *) st.GetHugeDataPtr(tmpBaseOffset);
      if ((segment == basePtr->GetSegOrLDTsel()) &&
          (segAddrSpace == (SEG_ADDR_SPACE)(basePtr->GetSegAddrSpace()))) {
         // the segments and space match
         *baseIndex = basePtr->GetBaseIndex();
         *baseType = basePtr->GetBaseType();
         return(GOOD);
      }
      tmpBaseOffset = basePtr->GetNextBaseOffset();
   }
   return(ER_SYMBOL_NOT_FOUND);
}  // end of SymFindBaseIndexFromSegment


//--------------------------------------------------------------------------
// SymFindBaseIndexFromSelector
//
// Purpose:
//    Find the baseIndex matching the gdt and optional ldt selectors
//
// Input parameters:
//    gdtSelector: previously loaded offset to GDT
//    ldtSelector: previously loaded offset to LDT
//
// Output parameters:
//    baseIndex: index holding the requested selectors
//    baseType:  type of the requested selectors.
//
// Error: Reports error if matching selectors not found
//
//--------------------------------------------------------------------------  
RETCODE EXPORT
SymFindBaseIndexFromSelector(U16 gdtSelector,
                             U16 ldtSelector,
                             BASE_INDEX FAR *baseIndex,
                             BASE_TYPE FAR *baseType) {

   TABLE_OFFSET tmpBaseOffset;
   BaseSymbol   *basePtr;

   tmpBaseOffset = bit.GetRootBaseSymbolOffset();

   while (tmpBaseOffset) {
      basePtr = (BaseSymbol *) st.GetHugeDataPtr(tmpBaseOffset);
      if ((gdtSelector == basePtr->GetGDTsel()) &&
          (ldtSelector == basePtr->GetSegOrLDTsel())) {
         // the selectors match
         *baseIndex = basePtr->GetBaseIndex();
         *baseType = basePtr->GetBaseType();
         return(GOOD);
      }
      tmpBaseOffset = basePtr->GetNextBaseOffset();
   }
   return(ER_SYMBOL_NOT_FOUND);

} // end of SymFindBaseIndexFromSelector


//--------------------------------------------------------------------------
// SymUpdateSymbolBase
//
// Purpose:
//    Update each symbol base when the base is a protected mode selector.
//    The update calls the address server which goes out to target
//    memory GDT/LDT tables and retrieves the base address of selector.
//
// Input parameters:  None
//
// Output parameters:
//    basecount: number of protected mode bases found and updated during
//               scan
//
// Error: Report error if no bases present; return any error from addr server
//
//--------------------------------------------------------------------------  
RETCODE EXPORT
SymUpdateSymbolBases(U16 *baseCount) {

   RETCODE      err, firstErr;
   TABLE_OFFSET tmpBaseOffset;
   BaseSymbol   *basePtr;
   DESCRIPTOR   symAddrDesc = 0L;
   U16          gdtSel;
   U16          segOrldtSel;
   U32          base;
   
   *baseCount = 0;

   tmpBaseOffset = bit.GetRootBaseSymbolOffset();
   if (!tmpBaseOffset)
      return ER_SYMBOL_NOT_A_MODULE;  // report no selectors

   if (GOOD != (err = AdrCreateAddress(&symAddrDesc)))
      return err;
   
   while (tmpBaseOffset) {
      basePtr = (BaseSymbol *) st.GetHugeDataPtr(tmpBaseOffset);
      if (SYM_PROTECTED == basePtr->GetSymMode()) {  // protected mode base
         // set the segsel type and enter the selector and ldt value
         // In protected mode the GetGDTsel returns GDT selector
         // and GetSegOrLDTsel returns LDT selector.  
         // protected mode address format is gdt:ldt:offset
         gdtSel = basePtr->GetGDTsel();
         segOrldtSel = basePtr->GetSegOrLDTsel();
         // now get the base of the GDT/LDT selectors from main memory
         // tables
         if ((GOOD != (err = AdrSetLdtSelector(symAddrDesc, gdtSel))) ||
             (GOOD != (err = AdrSetAddrSegmentSelector(symAddrDesc,
                                                      ADDR_USE_VALUE,
                                                      &segOrldtSel))) ||
            (GOOD != (err = AdrGetSegmentSelectorBase(symAddrDesc, &base)))) {
            ErrDisplayError(err, CHECK_MODE);
         } else {
            // set the base
            basePtr->SetBaseAddr((BASE_ADDRESS)base);
            *baseCount++;
         }
      }
      tmpBaseOffset = basePtr->GetNextBaseOffset();
   }  // end of while

CLEANUP:
   firstErr = err;
   if (0L != symAddrDesc) {
      err = AdrDestroyAddress(symAddrDesc);
      if (GOOD == firstErr)
         firstErr = err;
   }
   // Notify interest parties 
   err = EnlEventNotify(EVENT_SYMBOL_BASE_CHANGED);    
   return (firstErr != GOOD) ? firstErr : err;
}  // end of SymUpdateSymbolBases

//--------------------------------------------------------------------------
// SymTranslateLinearToVirtual
//
// Purpose:
//    Translates an input linear address into a segment or selector/offset
//      address.  The comparison to symbol table base must match the
//      address space as well as the range of addresses for that base.
//
// Input parameters:
//    linearAddrIn: address descriptor of linear address to convert
//
// Output parameters:
//    virtualAddrOut: address descriptor filled in as a virtual address
//
// Errors: error reported when:
//    There is no match of the input address to the base and ranges
//      stored in the loaded symbol table.
//    Input address is not type LINEAR
//    There are no bases loaded.
//
//    NOTE: do not compare on the error code, since the same is used for
//          all error conditions
//--------------------------------------------------------------------------  
RETCODE EXPORT
SymTranslateLinearToVirtual(DESCRIPTOR linearAddrIn,
                            DESCRIPTOR virtualAddrOut)  {

   RETCODE      err;
   TABLE_OFFSET tmpBaseOffset;
   BaseSymbol   *basePtr;
   U32          requestedAddr, searchOffsetAddr;
   ADDR_MODE    addrMode;
   ADDR_TYPE    type;
   ADDR_SPACE   addrSpace;
   
   tmpBaseOffset = bit.GetRootBaseSymbolOffset();
   if (!tmpBaseOffset)
      return ER_SYMBOL_NOT_A_MODULE;  // report no selectors

   if (GOOD != (err = AdrGetAddrType(linearAddrIn, &type)))
      return err;
   if (type != ADDR_LINEAR)
      return ER_SYMBOL_NOT_A_MODULE;
   // extract space from input descriptor
   if (GOOD != (err = AdrGetAddrSpace(linearAddrIn, &addrSpace)))
      return err;
   
   while (tmpBaseOffset) {
      basePtr = (BaseSymbol *) st.GetHugeDataPtr(tmpBaseOffset);
      if (SYM_NONE == basePtr->GetSymMode())
         return ER_SYMBOL_NOT_A_MODULE;
      // get linear requested addr
      if (GOOD != (err = AdrGetAddrOffset(linearAddrIn, &requestedAddr)))
         return err;
      
      // if input offset >= base, subtract base from offset else fail
      if (requestedAddr >= (basePtr->GetBaseAddress())) {
         searchOffsetAddr = requestedAddr - (basePtr->GetBaseAddress());
         if (((basePtr->CompareAddrVars(searchOffsetAddr))) &&
             (addrSpace == (basePtr->GetSegAddrSpace()))) {
            // linear address inside base object; create segment/offset
            // version of linear address
            
            // set address type
            if (GOOD != (err = AdrSetAddrType(virtualAddrOut, ADDR_VIRTUAL)))
               return err;

            if ((basePtr->GetSymMode()) == SYM_REAL) {
               addrMode = MODE_REAL;
            } else {
               addrMode = MODE_PROT32;
            }
            if (GOOD != (err = AdrSetAddrMode(virtualAddrOut, addrMode)))
               return err;

            // set seg/sel
            U16 gdtSel, segOrLdtSel;
            BASE_TYPE baseType;
            ADDR_SEGSEL_TYPE addrType;
            
            gdtSel = basePtr->GetGDTsel();
            baseType = basePtr->GetBaseType();
            switch (baseType) {
               BASE_CODE:
                  addrType = ADDR_USE_CS;
                  break;
                  
               BASE_DATA:
                  addrType = ADDR_USE_DS;
                  break;
                  
               BASE_CODE_DATA:
               BASE_UNKNOWN:
               default:
                  addrType = ADDR_USE_VALUE;
            }
            // set address descriptor ldt selector (gdt) - gdt:ldt:offset
            if (GOOD != (err =
                AdrSetLdtSelector(virtualAddrOut, gdtSel)))                                  
               return err;
            // set address descriptor segment selector (ldt) - gdt:ldt:offset
            segOrLdtSel = basePtr->GetSegOrLDTsel();
            if (GOOD != (err =
                AdrSetAddrSegmentSelector(virtualAddrOut,
                                          addrType,
                                          &segOrLdtSel)))
               return err;

            // set offset
            if (GOOD != (err =
                AdrSetAddrOffset(virtualAddrOut, searchOffsetAddr)))
               return err;

            // set address space
            if (GOOD != (err =
                AdrSetAddrSpace(virtualAddrOut, addrSpace)))
               return err;

         return GOOD;  // found match and filled in virtual addr
         }
      }  // end of if (requestedAddr...
      tmpBaseOffset = basePtr->GetNextBaseOffset();
   }  // end of while
return ER_SYMBOL_NOT_A_MODULE;  // no match found, return err

}  // end of SymTranslateLinearToVirtual


//--------------------------------------------------------------------------
//  UpdateCacheVars
//
//  Description:
//    Updates the cached variables containing the base index context
//
//  Parameters:
//    input:
//       baseIndex: the index into the base index table
//    output:
//       The cached vars are PRIVATE to this module
//
//  Errors:
//    returns error from GetOffset that can indicate index not in table
//    or an out-of-bounds index
//--------------------------------------------------------------------------
RETCODE UpdateCacheVars(BASE_INDEX baseIndex) {

   BaseSymbol   *baseSymbolPtr;
   TABLE_OFFSET tmpBaseOffset;
   RETCODE      err;

   // get new by-address table offset or generate error if not a valid index
   if((err = bit.GetOffset(baseIndex, tmpBaseOffset)) != GOOD)
      return(err);
   cachedBaseOffset = tmpBaseOffset;   // only update cached var if no error
   cachedBaseIndex = baseIndex;
   baseSymbolPtr = (BaseSymbol *)st.GetHugeDataPtr(cachedBaseOffset);

   // get the offset of the address table instance from base instance
   // (the address table instance is also in st)
   cachedByAddressOffset =
      baseSymbolPtr->GetByAddressTableOffset();
   return GOOD;
   }

//--------------------------------------------------------------------------
//  RemoveAllByAdrTables
//
//  Description:
//    Sequentially removes all the by address tables
//
//  Parameters:
//    input: none
//    output: none
//--------------------------------------------------------------------------
VOID RemoveAllByAdrTables(VOID) {
   TABLE_OFFSET  tableOffset, byAddrTableOffset;
   BaseSymbol    *basePtr;    // ptr to Base object ;
   ByAddressTable *byAddrTablePtr;  // ptr to ByAddressTable object ;

   tableOffset = bit.GetRootBaseSymbolOffset();
   while (tableOffset != NULL_SYMBOL) {
      // get a pointer to the by address sorted table ;
      basePtr = (BaseSymbol *)st.GetHugeDataPtr(tableOffset);
      byAddrTableOffset = basePtr -> GetByAddressTableOffset();
      byAddrTablePtr = (ByAddressTable *)st.GetHugeDataPtr(byAddrTableOffset);
      
      // delete the by address table object ;
      byAddrTablePtr->ObliterateTable();
      
      // get link to next base object ;
      tableOffset = basePtr -> GetNextBaseOffset();
   }  // end of while ;
   BasetblResetCacheVars();
   return;
}

//--------------------------------------------------------------------------
//  BasetblResetCacheVars
//
//  Description:
//    Re-initialize all cached vars after removal of symbols
//
//  Parameters:
//    input: none
//    output: none
//--------------------------------------------------------------------------
VOID BasetblResetCacheVars(VOID) {

   cachedBaseIndex = ALL_ONES;
   cachedByAddressOffset = NULL_SYMBOL;
   cachedBaseOffset = NULL_SYMBOL;

   // USED FOR TABLE CREATION AND FOR ADDING A BASE
   previousBaseOffset = NULL_SYMBOL;
   currentBaseOffset  = NULL_SYMBOL;

} // end of BasetblResetCacheVars
/******************************** E O F ***********************************/
