
/***************************************************************************
**
**    $Header:   D:/EP196/SRC/LOG/SYMSVR/SYMBASE.CPP   1.0   15 Aug 1997 14:04:16   ZJRD  $
**
**    $Log:   D:/EP196/SRC/LOG/SYMSVR/SYMBASE.CPP  $
** 
**    Rev 1.0   15 Aug 1997 14:04:16   ZJRD
** Initial revision.
** 
****************************************************************************/

/****************************************************************************
**
**  Name:  SYMBASE.cpp
**
**  Description:
**     This module contains routines for accessing BASE symbols.
**
**  Status:  PRELIMINARY
**
**  $Log$
** 
**  $Header:   D:/EP196/SRC/LOG/SYMSVR/SYMBASE.CPP   1.0   15 Aug 1997 14:04:16   ZJRD  $
**
**  Copyright (C) 1995 Microtek International.  All rights reserved.
**
*****************************************************************************/

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

#include "stdafx.h"                      
#include <string.h>
#include "symbase.h"
#include "symwind.h"
#include "symbyadr.h"
#include "sympool.h"
#include "symindex.h"
#include "symblsvr.h"
#include "symutil.h"
                       /****************************
                        *                          *
                        *     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
//     Creates an instance of a ByAddressTable and puts it in st
//     Fills in the passed parameters into the BaseSymbol and initializes
//        all other BaseSymbol vars.
//     
//  Parameters:
//    input:
//       baseName: a pointer to the name of this base
//       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(LPSTR baseName,
							  BASE_INDEX inputBaseIndex,
                       BASE_ADDRESS baseAddr,
							  BASE_TYPE baseTypeParam,
                       RETCODE& retErr) {

   ByAddressTable bat;
   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
   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;

   // put the base name into the symbol table memory pool
   if ((retErr = st.PutString(baseName, baseNameOffset)) != GOOD) return;

   // put the instance of the by-address sorted table into the symbol
   // table memory pool
   if ((retErr = st.PutBytes((U8 *)&bat, sizeof(ByAddressTable),
                             byAddressTableOffset)) != GOOD )
      return;

   // 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((U8)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);
}  // GetBaseOffsetByName

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