/*----------------------------------------------------------------------------
** Name: symutil.cpp
**
** Title: symbol utilities
**
** Purpose:
**  Utility code for symbol table; any routines that are used by a number of
**     symbol functions that warrant being placed in one central module.
**
** Status: PRELIMINARY | 
**
** $Log:   S:/tbird/mt2_186/symbol/symutil.cpv  $
** 
**    Rev 1.2   22 Jul 1997 10:11:06   Judy
** 
**    Rev 1.1   26 Feb 1997 11:43:34   Judy
** 
**    Rev 1.1   14 Jan 1997 15:32:18   Judy
** No change.
** 
**    Rev 1.0   14 Jun 1996 16:42:22   Judy
** Initial revision.
** 
**    Rev 1.39   26 Sep 1994 10:36:24   nghia
** Revise Utility routine to retrieve correct base address information.
** Revise UtilSetAddrParams to set address descriptor parts with correct order
** and information.
** 
**    Rev 1.38   22 Sep 1994 14:55:02   nghia
** Fixed bug in UtilSetAddrOffset() and UtilGetSegSel() to read/write
** selector correctly for address descriptor.
** sym: segOrGdtSel:ldt - AdrSetLdtSelector():AdrSetAddrSegmentSelector.
** 
**    Rev 1.37   04 Aug 1994 18:28:34   brucea
** Removed commented code that did special check for address offset of 0
** 
**    Rev 1.36   03 Aug 1994 12:02:24   brucea
** Modified: UtilGetOffsetFromAddrDesc to allow an offset of 0 to be calculated
** Modified: UtilSetAddrParams to removed test for offset of 0 before setting
**    the end address of an address descriptor
** 
**    Rev 1.35   28 Jul 1994 13:15:40   brucea
** Fixed bug in UtilGetOffsetFromAddrDesc
** In UtilSetAddrOffset, now filling in segment for virtual addresses
** 
**    Rev 1.34   25 Jul 1994 11:17:12   brucea
** Modified: SymCalcSymbolOffset to deal with virtual and linear input types
** Added: UtilGetSegSelFromSymDesc
** Modified: UtilGetOffsetFromAddrDesc() to support linear and virtual
** Handled: addrSpace parameter addition to LdrLoadModuleByDesc
** 
**    Rev 1.32   14 Jul 1994 01:54:22   brucea
** Modified: number of address-related functions to handle Intel addresses
** 
**    Rev 1.31   20 Jun 1994 09:51:40   marilyn
** Updated interface to AdrSetAddrSegmentSelector.
** 
**    Rev 1.30   19 May 1994 10:10:50   nghia
** Removed the old 695 loader header, replace with the new Loader header.
** 
**    Rev 1.29   18 Mar 1994 10:53:44   marilyn
** Fixed bug dealing with mixing address mode and address type in a
** couple of switch statements.
** 
**    Rev 1.28   28 Feb 1994 16:25:18   marilyn
** Removed references to ADDR_LOGICAL.
** 
**    Rev 1.27   18 Jan 1994 17:08:16   nghia
** Fixed bug: General Instrument - DC2.ABS and BWM loadfile.
** When on demand loading for large file, the symbol table loose pointer value
** upon table expanding demanded.  Re-dereference the offset to get the 
** correct pointer value.
** 
**    Rev 1.26   24 Sep 1993 10:31:56   nghia
** Filter out ER_NO_LINENUMS_ADDED for UtilLoadOnDemand() to set data module
** to SYMBOLS_LOADED.
** 
**    Rev 1.25   14 Jul 1993 12:02:24   nghia
** Call LdrLoadModuleByDesc() to do ondemand loading.
** 
**    Rev 1.24   18 Dec 1992 18:13:46   brucea
** Added: SymCalcSymbolOffset
** 
**    Rev 1.23   14 Sep 1992 17:51:08   brucea
** Took out: EVENT_SYMBOL_DELETED event notify from SymRemoveSymbols
** 
**    Rev 1.22   08 Sep 1992 13:06:06   brucea
** Added: events.h include
** 
**    Rev 1.21   28 Aug 1992 10:47:30   brucea
** Fixed bug: UtilIsValidSymDescriptor now checks for valid symDesc before
**    moving on to next part of check
** 
**    Rev 1.20   10 Aug 1992 09:13:24   brucea
** Adde: & 0xF to access to typeindex.symType in UtilOnDemandLoad
** 
** 
**    Rev 1.19   06 Aug 1992 15:24:52   brucea
** Cleanup
** 
**    Rev 1.18   06 Aug 1992 10:12:22   brucea
** Changed access to .typeIndex.symType to use &0xF
** 
**    Rev 1.17   15 Jun 1992 09:30:28   brucea
** Removed: break after return (it was redundant)
** 
**    Rev 1.16   01 Apr 1992 23:38:20   brucea
** Fixed: compiler warnings
** 
**    Rev 1.15   14 Feb 1992 15:17:24   brucea
** Added: setting of modPtr->fileOffset once the on-demand symbols have been
**    loaded
** 
**    Rev 1.14   04 Feb 1992 16:12:10   brucea
** Improved and fixed UtilIsValidSymDescriptor; added check for NULL_SYMBOL,
**    changed |= to &= so FALSE is propagated for each test.
** 
**    Rev 1.13   10 Jan 1992 19:21:32   brucea
** Added #include "enlib.h" to support event notification
** 
**    Rev 1.12   10 Jan 1992 16:16:18   brucea
** Added event notification when symbols are deleted
** Changed array 256 to MAX_SYMNAME_LENGTH
** 
**    Rev 1.11   02 Jan 1992 11:59:28   john
** Added code for comparing two timestamps
** 
**    Rev 1.10   18 Dec 1991 10:39:14   john
** Renamed LdrLoad695_Module to match new name in ldrsvr.h
** 
**    Rev 1.9   16 Dec 1991 16:24:56   brucea
** Added #include "ldrsvr.h" and removed explicit prototype
** Removed last 3 parameters from LdrLoad695_Module call
** 
**    Rev 1.8   13 Dec 1991 14:13:48   brucea
** Added call to LdrLoad695_Module and other changes inside UtilOnDemandLoad
** Added UtilIsValidSymDescriptor
** 
**    Rev 1.7   12 Dec 1991 14:11:56   john
** Seperated the code to remove the tables to allow only the tables to be
** removed when the DLL is removed.
** 
**    Rev 1.6   11 Dec 1991 17:09:26   brucea
** Added UtilGetAddrFromSymDesc, UtilGetOffsetFromAddrDesc,
**    UtilGetOffsetFromAddrDesc, UtilSetAddrOffset, UtilSetEndAddrOffset
** Modified UtilOnDemandLoad with commented code to call loader for on-demand
** 
**    Rev 1.5   09 Dec 1991 14:44:14   john
** Needed prototypes for InitSymTable
** 
**    Rev 1.4   09 Dec 1991 14:40:20   john
** Added a function to remove all the symbols from the symbol table.
** 
**    Rev 1.3   05 Dec 1991 14:45:04   brucea
** Fixed end address code error in UtilSetAddrParams
** 
**    Rev 1.2   02 Dec 1991 18:04:40   john
** Added call to support on demand loading
** 
**    Rev 1.1   29 Nov 1991 20:06:40   brucea
** Added #includes for: addr.h, symbolsvr.h, symget.h
** Added function UtilSetAddrParams
** 
**    Rev 1.0   18 Nov 1991 20:26:22   brucea
** Initial revision.
** 
** $Header:   S:/tbird/mt2_186/symbol/symutil.cpv   1.2   22 Jul 1997 10:11:06   Judy  $
**
** Copyright (C) 1991 Microtek International.  All rights reserved.
**
**--------------------------------------------------------------------------*/

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

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

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

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

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

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

#ifndef _LOADER_
#include "loader.h"
#endif

#ifndef _LINENUM_
#include "linenum.h"
#endif

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

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

#ifndef _SYMADD_
#include "symadd.h"
#endif

#ifndef _SYMBLSVR_
#include "symblsvr.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

                       /****************************
                        *                          *
                        *        DEFINITIONS       *
                        *                          *
                        ****************************/

extern BaseIndexTable bit;
extern HashTable ht;
extern LinenumTable lt;
extern OrdinalTable ot;
extern MemPool st;
extern TypeTable tt;
extern IndexTable typit;

// holds filename containing symbols to load
extern U8 loadFilename[MAX_SYMNAME_LENGTH];


                       /****************************
                        *                          *
                        *     EXECUTABLE CODE      *
                        *                          *
                        ****************************/

//------------------------------------------------------------------------
//                  SYMBOL UTILITIES
//------------------------------------------------------------------------

//------------------------------------------------------------------------
// SymRemoveSymbols
//
// Purpose:
//    Removes all symbols from the symbol table.
//
// Input parameters:
//
// Output parameters:
//
//------------------------------------------------------------------------
RETCODE EXPORT SymRemoveSymbols(VOID) {

   RETCODE err;

   // remove all dynamically allocated memory ;
   if ((err = UtilDeleteTables()) != GOOD) return(err);
   
   // re-initialize all the tables ;
   if((err = InitSymTable()) != GOOD) return(err);
   if((err = tt.InitBasicTypes()) != GOOD) return(err);

   return(GOOD);
}  // end of SymRemoveSymbols


//------------------------------------------------------------------------
// SymCalcSymbolOffset
//
// Description:
//    Given a symbol descriptor and address, calculate the offset from
//    the beginning of that symbol to the input address.  If the input
//    address is less than the start of the symbol range, return a value
//    of 0.
//
// Input parameters:
//    symDesc: symbol descriptor to address to be compared
//    inputAddrDesc: address to be compared with symbol's start address
//
//    NOTE: none of the descriptors are destroyed; this is the job of
//    the caller.  Also, none of the contents of the descriptors are
//    modified.
//
// Output parameter:
//    symbolOffset: simple offset (U32) from start to requested addr
//------------------------------------------------------------------------
RETCODE EXPORT
SymCalcSymbolOffset(DESCRIPTOR symDesc,
                    DESCRIPTOR inputAddrDesc,
                    U32 FAR   *symbolOffset) {

   DESCRIPTOR   symAddrDesc = 0L;
   DESCRIPTOR   resultAddrDesc = 0L;
   ADDR_COMPARE result;
   RETCODE      err, firstErr = GOOD;
   U32          tempOffset;
   ADDR_TYPE    inputAddrType;

   *symbolOffset = 0L;   // default value
   // get address of symbol; compare input address to symbol address
   if (GOOD != (err = AdrCreateAddress(&symAddrDesc)))
      return err;
   
   if (GOOD != (err = AdrGetAddrType(inputAddrDesc, &inputAddrType)))
      goto CLEANUP;

   // set the created address type to the input address type.  The
   // SymGetSymbolAddress will fill in the symAddrDesc with either
   // linear of virtual values based on this type information
   
   if (GOOD != (err = AdrSetAddrType(symAddrDesc, inputAddrType)))
      goto CLEANUP;

   if (GOOD != (err = SymGetSymbolAddress(symDesc,
                                          symAddrDesc)))
      goto CLEANUP;
   // compare input address (inputAddrDesc) with symbol start address
   if (GOOD != (err = AdrCompareAddresses(inputAddrDesc,
                                          symAddrDesc,
                                          &result)))
      goto CLEANUP;

   if (FIRST_ADDR_GREATER == result) {
      // must subtract starting address from input address and return
      // the offset difference.
      if (GOOD != (err = AdrGetAddrOffset(symAddrDesc,
                                          &tempOffset)))
         goto CLEANUP;
      // do not want to change symbol passed in; so must duplicate
      if (GOOD != (err = AdrDuplicateAddress(inputAddrDesc,
                                             &resultAddrDesc)))
         goto CLEANUP;
      if (GOOD != (err = AdrSubtractFromAddress(resultAddrDesc,
                                                tempOffset)))
         goto CLEANUP;   // modifies resultAddrDesc

      if (GOOD !=
         (err = AdrGetAddrOffset(resultAddrDesc, symbolOffset)))
         goto CLEANUP;   // put result into symbolOffset
   }
CLEANUP:
   firstErr = err;
   if (0L != symAddrDesc) {
      err = AdrDestroyAddress(symAddrDesc);
      if (GOOD == firstErr)
         firstErr = err;
   }
   if (0L != resultAddrDesc) {
      err = AdrDestroyAddress(resultAddrDesc);
      if (GOOD == firstErr)
         firstErr = err;
   }
   return firstErr;
}  /* end of SymCalcSymbolOffset */
         

//------------------------------------------------------------------------
// UtilCmpTimestamp
//------------------------------------------------------------------------
S16 UtilCmpTimestamp(TIMESTAMP_TYPE *time1, TIMESTAMP_TYPE *time2) {

   S16 diff;
   
   if ((diff = time1->year - time2->year) != 0) return (diff);
   if ((diff = time1->month - time2->month) != 0) return (diff);
   if ((diff = time1->day - time2->day) != 0) return (diff);
   if ((diff = time1->hour - time2->hour) != 0) return (diff);
   if ((diff = time1->minute - time2->minute) != 0) return (diff);
   if ((diff = time1->second - time2->second) != 0) return (diff);

   return (0);
}

//------------------------------------------------------------------------
// UtilDeleteTables
//------------------------------------------------------------------------
RETCODE UtilDeleteTables(VOID) {

   // remove the base index table and all the by-address tables associated
   // with bit.  This call does both
   bit.ObliterateTable();
   
   // remove the storage for global name hash table;
   ht.ObliterateTable();
   
   // remove all line number info. ;
   lt.ObliterateTable();
   
   // remove info on what order symbols were loaded. ;
   ot.ObliterateTable();
   
   // remove all the memory for all type info. ;
   tt.ObliterateTable();
   
   // remove the index table for all the types just removed. ;
   typit.ObliterateTable();
   
   // remove all the memory for all symbols.  this is done last since it ;
   // holds information potentially stored in all the other tables. ;
   st.ObliterateTable();

   return(GOOD);
}

//--------------------------------------------------------------------------
//  UtilGetAddrFromSymDesc
//
//  Description:
//    Returns the base address of <symDesc>
//     
//  Parameters:
//    input:
//       symDesc: offset to a symbol
//    output:
//       baseAddr: the base address being returned
//--------------------------------------------------------------------------
RETCODE
UtilGetAddrFromSymDesc(SYM_DESCRIPTOR symDesc,
                       BASE_ADDRESS *baseAddr) {
   
   RETCODE    err;
   COMMON_SYMBOL_HEADER *symPtr;

   symPtr=(COMMON_SYMBOL_HEADER *)st.GetHugeDataPtr(symDesc);
   err = SymGetBaseAddress(symPtr -> typeIndex.baseIndex,
                               baseAddr);
   return err;
}  // end of UtilGetAddrFromSymDesc


//--------------------------------------------------------------------------
//  UtilGetSegSelFromSymDesc
//
//  Description:
//    Returns the segment/selector, ldt, and base address of <symDesc>
//     
//  Parameters:
//    input:
//       symDesc: offset to a symbol
//    output:
//       gdtSel: gdt selector
//       segmentOrLdtSel: segment (real) or ldt selector value
//--------------------------------------------------------------------------
RETCODE
UtilGetSegSelFromSymDesc(SYM_DESCRIPTOR symDesc,
                         U16 FAR *gdtSel,
                         U16 FAR *segmentOrLdtSel) {
   
   RETCODE    err;
   COMMON_SYMBOL_HEADER *symPtr;
   BASE_INDEX      baseIndex;
   BaseSymbol HUGE *basePtr;
   TABLE_OFFSET baseOffset;
   
   symPtr=(COMMON_SYMBOL_HEADER *)st.GetHugeDataPtr(symDesc);
   baseIndex = symPtr->typeIndex.baseIndex;
   
   // check to make sure the base exists, then get base pointer from
   // base index table.
   if ((err = bit.GetOffset(baseIndex,baseOffset)) != GOOD)
      return err;
   
   // get a pointer to the base symbol residing in st
   basePtr = (BaseSymbol HUGE*) st.GetHugeDataPtr(baseOffset);
   // Get base address information
   *gdtSel = basePtr->GetGDTsel();
   *segmentOrLdtSel = basePtr->GetSegOrLDTsel();

   return GOOD;
}  // end of UtilGetSegSelFromSymDesc


//------------------------------------------------------------------------
// UtilIsValidSymDescriptor
//
// Purpose:
//    Checks for validity of the passed symbol descriptor; i.e. that the
//       symbol descriptor is not outside the bounds of st
//    Checks that symbolNameOffset, symParentOffset, and symSiblingOffset
//       are also within the st bounds
//
// Input parameters:
//    symDesc: st table offset to be tested against size of table
//
// Output parameters:  returns FALSE if not valid, TRUE if valid
//------------------------------------------------------------------------
BOOLEAN UtilIsValidSymDescriptor(SYM_DESCRIPTOR symDesc) {

   BOOLEAN bool;
   COMMON_SYMBOL_HEADER *symPtr;

   if (symDesc == NULL_SYMBOL)
      return FALSE;
   bool = st.IsValidTableOffset(symDesc);
   if (bool) {
      symPtr = (COMMON_SYMBOL_HEADER *)st.GetHugeDataPtr(symDesc);
      bool &= st.IsValidTableOffset(symPtr->symbolNameOffset);
      bool &= st.IsValidTableOffset(symPtr->symParentOffset);
      bool &= st.IsValidTableOffset(symPtr->symSiblingOffset);
   }
   return bool;
} // end of UtilIsValidSymDescriptor


//------------------------------------------------------------------------
// UtilGetOffsetFromAddrDesc
//
// Purpose:
//    Convert an abstract address into an offset value for local address
//    lookup.  If type is linear, subtracts the base address from the
//    requested address and returns the result.  If virtual, simply returns
//    the abstract offset.
//
// Input parameters:
//    symbolDesc: any legitimate symbol -> must have base index and base addr
//    addrDesc: abstract requested address
//
// Output parameters:
//    offsetAddr: final offset address used for looking up a symbol
//
// Errors:
//    returns error if the abstract address is linear and the
//       requested address is larger than the base address stored for this
//       symbol
//------------------------------------------------------------------------
#pragma argsused
RETCODE
UtilGetOffsetFromAddrDesc(SYM_DESCRIPTOR   symbolDesc,
			  DESCRIPTOR       addrDesc,
			  U16              *segment, //Hera 6/4/97
                          OFFSET_ADDR_TYPE *offsetAddr)  {

   RETCODE          err;
   BASE_ADDRESS     baseAddr;
   ADDR_TYPE        addrType;

   // get address type and handle appropriately
   if (GOOD != (err = AdrGetAddrType(addrDesc, &addrType)))
      return err;
   if (GOOD != (err = AdrGetAddrOffset(addrDesc, offsetAddr)))
      return err;

   switch (addrType) {
      case ADDR_VIRTUAL:
	 if((err = AdrGetAddrSegment(addrDesc, segment)) != GOOD)
	    return err;
         return GOOD;

      case ADDR_LINEAR:
      case ADDR_PHYSICAL:
         // Must extract base address from module symbol, then subtract
         // it from the requested linear address
         if (GOOD != (err =
             UtilGetAddrFromSymDesc(symbolDesc, &baseAddr)))
            return err;
         if (baseAddr <= *offsetAddr) {
            *offsetAddr -= baseAddr;
         } else {
            return ER_SYM_BASEADDR_TOO_SMALL;
	 }
	 *segment = baseAddr >> 4; //Hera 6/4/97
         break;

      default:
         return ER_ADDR_TYPE_NOT_ACCEPTED;
      }  //end of switch
   return GOOD;
   } // end of UtilGetOffsetFromAdrDesc


//------------------------------------------------------------------------
// UtilSetAddrOffset
//
// Purpose:
//    Installs the passed-in offset address into the address descriptor.
//    Convert an offset value back into an abstract address.
//    If type is linear, adds the base address into the passed address and
//    returns the result.  If virtual, places the offset into the
//    address descriptor AND installs the segment value of the symbol
//    passed in (accesses its base to get the segment/selector and ldt).
//
// Input parameters:
//    symbolDesc: any legitimate symbol -> must have base index and base addr
//    offsetAddr: offset address value to be put into abstract address
//
// Output parameters:
//    addrDesc: abstract address to be filled in
//
// Errors:
//    returns error input address type is ADDR_PHYSICAL
//------------------------------------------------------------------------
RETCODE
UtilSetAddrOffset(SYM_DESCRIPTOR   symbolDesc,
		  U16              segment, //Hera 6/4/97
                  OFFSET_ADDR_TYPE offsetAddr,
                  DESCRIPTOR       addrDesc)  {

   RETCODE      err;
   BASE_ADDRESS baseAddr;
   ADDR_TYPE    addrType;
   U16          gdtSel;
   U16          segmentOrLdtSel;

   // get address type and handle appropriately
   if (GOOD != (err = AdrGetAddrType(addrDesc, &addrType)))
      return err;

   switch (addrType) {
      case ADDR_VIRTUAL:
         // get the seg/ldt and install
         if (GOOD != (err =                         
            UtilGetSegSelFromSymDesc(symbolDesc,
                                     &gdtSel, 
                                     &segmentOrLdtSel))) { 
            return err;
         }
         // put these two values into address descriptor
         // protected mode address format is gdt:ldt:offset         
         if ((GOOD != (err = AdrSetLdtSelector(addrDesc, gdtSel))) ||
             (GOOD != (err = AdrSetAddrSegmentSelector(addrDesc,
                                                      ADDR_USE_VALUE,
						      &segment/*Hera 6/4/97*/)))) {
            return err;
         }
         break;

      case ADDR_LINEAR:
      case ADDR_PHYSICAL:
         // address type is linear; must extract base address
         // from module symbol, then subtract it from the requested linear
         // address
         if (GOOD != (err =
             UtilGetAddrFromSymDesc(symbolDesc, &baseAddr)))
	    return err;
	 //Hera 6/4/97
	 if (baseAddr != segment)
            baseAddr = ((BASE_ADDRESS)segment << 4);
         offsetAddr += baseAddr;
         break;

      default:
         return ER_ADDR_TYPE_NOT_ACCEPTED;
      }  //end of switch

   return AdrSetAddrOffset(addrDesc, offsetAddr);
} // end of UtilSetAddrOffset


//------------------------------------------------------------------------
// UtilSetEndAddrOffset
//
// Purpose:
//    Convert an offset value back into the end abstract address.
//    If type is linear, adds the base address into the passed address and
//    returns the result.  If virtual, simply places the end offset into the
//    the abstract end address.
//    NOTE: this routine assumes that UtilSetAddrOffset has been called first
//    and has checked for selector validity.
//
// Input parameters:
//    symbolDesc: any legitimate symbol -> must have base index and base addr
//    endOffsetAddr: offset address value to be put into abstract address
//
// Output parameters:
//    addrDesc: abstract address to be filled in
//
// Errors:
//------------------------------------------------------------------------
RETCODE
UtilSetEndAddrOffset(SYM_DESCRIPTOR   symbolDesc,
		     BASE_ADDRESS     segment, //Hera 6/4/97
                     OFFSET_ADDR_TYPE endOffsetAddr,
                     DESCRIPTOR       addrDesc)  {

   RETCODE          err;
   BASE_ADDRESS     baseAddr;
   ADDR_TYPE        addrType;

   // get address type and handle appropriately
   if (GOOD != (err = AdrGetAddrType(addrDesc, &addrType)))
      return err;

   switch (addrType) {
      case ADDR_VIRTUAL:
         break;

      case ADDR_LINEAR:
      case ADDR_PHYSICAL:
         // address type is linear; must extract base address
         // from module symbol, then subtract it from the requested linear
         // address
         if (GOOD != (err =
             UtilGetAddrFromSymDesc(symbolDesc, &baseAddr)))
	    return err;
	 if (baseAddr != segment)
	    baseAddr = segment; //Hera 6/4/97
         endOffsetAddr += baseAddr;
         break;

      default:
         return ER_ADDR_TYPE_NOT_ACCEPTED;
      }  //end of switch

   return AdrSetEndAddrOffset(addrDesc, endOffsetAddr);
} // end of UtilSetEndAddrOffset


//------------------------------------------------------------------------
// UtilOnDemandLoad
//------------------------------------------------------------------------
RETCODE UtilOnDemandLoad(SYM_DESCRIPTOR inputSymbol) {

   RETCODE         err;
   COMMON_SYMBOL_HEADER *headPtr;
   SYM_TYPE_MODULE *modPtr;
   SYM_DESCRIPTOR  currentOffset, tmpOffset;
   SYM_TYPE_TYPE   symType;
   U8              modName[MAX_SYMNAME_LENGTH];
   U8              tmpSymType;
   ADDR_SPACE      addrSpace = SPACE_USER;

   headPtr = (COMMON_SYMBOL_HEADER *) st.GetHugeDataPtr(inputSymbol);
   tmpSymType = (headPtr->typeIndex.symType) & 0xF;
   if (!((tmpSymType == SYM_MODULE)  ||
         (tmpSymType == SYM_FUNCTION)||
         (tmpSymType == SYM_BLOCK))) {
      return(ER_SYMBOL_NOT_A_FUNCTION);
   }

   // find the module descriptor from the inputSymbol descriptor. ;
   // the input symbol is a func/block/module descriptor. ;
   currentOffset = inputSymbol;
   while (((headPtr->typeIndex.symType) & 0xF) != SYM_MODULE) {
      // search the symbols parent list until the module descriptor ;
      // is found.  Then check to see if the module symbols have been ;
      // loaded. ;
      if ((err = SymGetSymbolParent(currentOffset, &symType, 
         &tmpOffset)) != GOOD) return(err);
      headPtr = (COMMON_SYMBOL_HEADER *) st.GetHugeDataPtr(tmpOffset);
      currentOffset = tmpOffset;
   }
   modPtr = (SYM_TYPE_MODULE *) headPtr;
   if (modPtr->fileOffset != SYMBOLS_LOADED) {
      // Get the module name to do loading - currentOffset == symDesc
      if (GOOD != (err = SymAddGetModuleName(currentOffset,
                                                (LPSTR)modName)))
         return err;
      // Call loader to load symbols and set flag when done
      if ((err = LdrLoadModuleByDesc((LPSTR)loadFilename, (LPSTR)modName,
                                     currentOffset, addrSpace)) != GOOD) {
         // NOTES: 09/22/93 - Nghia
         // Filter out err if module does not contain line number information
         if ((err == ER_NO_LINENUMS_ADDED) ||
             (err == ER_NO_LINEBLK_IN_MODULE)) {
            // Notes: 01/18/94 - Nghia
            // Retrieve the headPtr again, in cases the table is expanded
            // which trashed the headPtr.  STRANGE PROBLEM with
            // Windows ReAlloc() function.
            headPtr = (COMMON_SYMBOL_HEADER *)
                      st.GetHugeDataPtr(currentOffset);
            if (((headPtr->typeIndex.symType) & 0xF) == SYM_MODULE) {
               modPtr = (SYM_TYPE_MODULE *) headPtr;            
               // indicate that the module does not have line information
               // so set flag to indicate that it's loaded
               modPtr->fileOffset = SYMBOLS_LOADED;
            }
         }
         // return err to avoid unwanted processing 
         // Caller need not report the filter errors  
         return err;
         
      } else {
         // Notes: 01/18/94 - Nghia
         // Retrieve the headPtr again, in cases the table is expanded
         // which trashed the headPtr.  STRANGE PROBLEM with
         // Windows ReAlloc() function.
         headPtr = (COMMON_SYMBOL_HEADER *)
                   st.GetHugeDataPtr(currentOffset);
         modPtr = (SYM_TYPE_MODULE *) headPtr;
         // Make sure that it is a module
         if (((headPtr->typeIndex.symType) & 0xF) != SYM_MODULE)
            return ER_SYMBOL_NOT_A_MODULE;
         // indicate that the rest of module symbols have been loaded
         modPtr->fileOffset = SYMBOLS_LOADED;
      }
   }
   return(GOOD);
}  // end of UtilOnDemandLoad


//------------------------------------------------------------------------
// UtilSetAddrParams
//
// Purpose:
//    Enters the address or addresses into a address object
//
// Input parameters:
//    baseIndex: symbol table base index which equates to Intel selector
//               or segment
//    offsetAddr: symbol offset address
//    offsetAddrEnd: end address of symbol: makes up the address range
//                   0 ==> no end address; any other value means there is
//    desc: descriptor for access to address object; it is equivalent to
//          a pointer
//
// Output parameters:
//    desc: modifies the address object
//          for linear:
//             address offset is base + offset
//             addressSpace?
//          for virtual, address is:
//             copy base segOrGDTsel into AdrSetAddrSegmentSelector
//             copy LDTsel into AdrSetLdtSelector
//             copy segAddrSpace into AdrSetAddrSpace
//             copy symMode into !!!!!!!!!!!!
//------------------------------------------------------------------------
RETCODE
UtilSetAddrParams(BASE_INDEX       baseIndex,
                  OFFSET_ADDR_TYPE offsetAddr,
                  OFFSET_ADDR_TYPE offsetAddrEnd,
                  DESCRIPTOR       desc)  {

   ADDR_TYPE       addrType;
   RETCODE         err; 
   BASE_ADDRESS    baseAddr;
   TABLE_OFFSET    baseOffset;
   BaseSymbol HUGE *basePtr;
   ADDR_MODE       addrMode;
   ADDR_SPACE      addrSpace;
         

   if (GOOD != (err = AdrGetAddrType(desc, &addrType)))
      return err;
   switch (addrType)  {
      case ADDR_LINEAR:
      case ADDR_PHYSICAL:
         // enter the start and end addresses
         if (GOOD != (err = SymGetBaseAddress(baseIndex, &baseAddr)))
               return err;
         if (GOOD !=
            (err = AdrSetAddrOffset(desc, baseAddr + offsetAddr)))
            return err;
         if (0L != offsetAddrEnd)  {
            if (GOOD != (err =
                AdrSetEndAddrOffset(desc, baseAddr + offsetAddrEnd)))
               return err;
            }
         break;

      case ADDR_VIRTUAL:
         //***********************************************************
         // set the segment/GDT selector, LDT selector, and SegSelType
         //***********************************************************
         // check to make sure the base exists
         if ((err = bit.GetOffset(baseIndex, baseOffset)) != GOOD)
            return err;
   
         // get a pointer to the base symbol
         basePtr = (BaseSymbol HUGE*) st.GetHugeDataPtr(baseOffset);

         if (GOOD != (err = AdrSetLdtSelector(desc,
                                              basePtr->GetGDTsel())))
             return err;
         U16 segOrLDTSel = basePtr->GetSegOrLDTsel();
         if (GOOD != (err = AdrSetAddrSegmentSelector(desc,
               ADDR_USE_VALUE, &segOrLDTSel)))
            return err;
         //******************************************
         // set the ADDR_MODE for address
         //******************************************
         if (basePtr->GetSymMode() == SYM_REAL) {
            addrMode = MODE_REAL;
         } else {
            addrMode = MODE_PROT16;
         }
         if (GOOD != (err = AdrSetAddrMode(desc, addrMode)))
             return err;
         //****************************************
         // set offset start and end address values
         //****************************************
         if (GOOD != (err = AdrSetAddrOffset(desc, offsetAddr)))
            return err;
         if (GOOD != (err = AdrSetEndAddrOffset(desc, offsetAddrEnd))) {
            return err;
         }
         //******************************************
         // set the space (USER or SMM)
         //******************************************
         if (basePtr->GetSegAddrSpace() == SEG_SPACE_USER) {
            addrSpace = SPACE_USER;
         } else {
            addrSpace = SPACE_SMM;
         }
         if (GOOD != (err = AdrSetAddrSpace(desc, addrSpace)))
             return err;
         break;

//      case ADDR_PHYSICAL:
      // cannot accept a physical address request; must be in linear
      // or virtual form.  The caller must convert these back to physical
      // after type is returned
//         return ER_ADDR_TYPE_NOT_ACCEPTED;

      } // end of switch
   return GOOD;
   }  // end of UtilSetAddrParams

//Hera 5/26/97 -- for multiple code segments
RETCODE
UtilSetAddrParams1(BASE_INDEX      baseIndex,
                   U16             segment,
                   OFFSET_ADDR_TYPE offsetAddr,
                   OFFSET_ADDR_TYPE offsetAddrEnd,
                   DESCRIPTOR       desc)  {

   ADDR_TYPE       addrType;
   RETCODE         err; 
   BASE_ADDRESS    baseAddr;
   TABLE_OFFSET    baseOffset;
   BaseSymbol HUGE *basePtr;
   ADDR_MODE       addrMode;
   ADDR_SPACE      addrSpace;
         

   if (GOOD != (err = AdrGetAddrType(desc, &addrType)))
      return err;
   switch (addrType)  {
      case ADDR_LINEAR:
      case ADDR_PHYSICAL:
         // enter the start and end addresses
         //if (GOOD != (err = SymGetBaseAddress(baseIndex, &baseAddr)))
	 //      return err;
         baseAddr = segment;
         if (GOOD !=
            (err = AdrSetAddrOffset(desc, baseAddr + offsetAddr)))
            return err;
	 if (0L != offsetAddrEnd)  {
            if (GOOD != (err =
                AdrSetEndAddrOffset(desc, baseAddr + offsetAddrEnd)))
               return err;
            }
         break;

      case ADDR_VIRTUAL:
         //***********************************************************
         // set the segment/GDT selector, LDT selector, and SegSelType
	 //***********************************************************
         // check to make sure the base exists
         if ((err = bit.GetOffset(baseIndex, baseOffset)) != GOOD)
            return err;
   
         // get a pointer to the base symbol
         basePtr = (BaseSymbol HUGE*) st.GetHugeDataPtr(baseOffset);

         if (GOOD != (err = AdrSetLdtSelector(desc,
                                              basePtr->GetGDTsel())))
	     return err;
	 //U16 segOrLDTSel = basePtr->GetSegOrLDTsel();
         U16 segOrLDTSel = segment; //Hera
         if (GOOD != (err = AdrSetAddrSegmentSelector(desc,
               ADDR_USE_VALUE, &segOrLDTSel)))
            return err;
         //******************************************
         // set the ADDR_MODE for address
         //******************************************
         if (basePtr->GetSymMode() == SYM_REAL) {
            addrMode = MODE_REAL;
         } else {
            addrMode = MODE_PROT16;
         }
         if (GOOD != (err = AdrSetAddrMode(desc, addrMode)))
             return err;
         //****************************************
         // set offset start and end address values
         //****************************************
         if (GOOD != (err = AdrSetAddrOffset(desc, offsetAddr)))
            return err;
         if (GOOD != (err = AdrSetEndAddrOffset(desc, offsetAddrEnd))) {
            return err;
         }
         //******************************************
         // set the space (USER or SMM)
         //******************************************
         if (basePtr->GetSegAddrSpace() == SEG_SPACE_USER) {
            addrSpace = SPACE_USER;
         } else {
            addrSpace = SPACE_SMM;
         }
         if (GOOD != (err = AdrSetAddrSpace(desc, addrSpace)))
             return err;
         break;

//      case ADDR_PHYSICAL:
      // cannot accept a physical address request; must be in linear
      // or virtual form.  The caller must convert these back to physical
      // after type is returned
//         return ER_ADDR_TYPE_NOT_ACCEPTED;

      } // end of switch
   return GOOD;
   }  // end of UtilSetAddrParams1
/******************************** E O F *************************************/
