/****************************************************************************
**
**  Name:  DEBUG.CPP
**
**  Description:
**      Routines for the debugging information.
**
**  Status:  CODED
**
**  $Log:   S:/tbird/mt2_186/omf86/debug.cpv  $
** 
**    Rev 1.7   02 Sep 1997 16:45:20   Judy
** To fix line number bug. (Test report id: 104, 105)
** 
**    Rev 1.6   26 Aug 1997 10:45:36   Judy
   
      Rev 1.0   26 Aug 1997 09:55:20   unknown
   Initial revision.
** 
**    Rev 1.5   22 Jul 1997 10:11:28   Judy
** 
**    Rev 1.4   19 Jun 1997 17:10:36   Judy
** No change.
** 
**    Rev 1.3   18 Jun 1997 14:53:18   Judy
** 
**    Rev 1.1   18 Apr 1997 09:29:40   Judy
** 
**    Rev 1.0   26 Feb 1997 11:40:34   Judy
** Initial revision.
** 
**    Rev 1.6   18 Oct 1996 09:15:36   hera
** We do some changes for PLM having not list file.
** 
**    Rev 1.6   18 Oct 1996 09:13:16   hera
** We do some changes for PLM which has no list file
** 
**    Rev 1.5   11 Oct 1996 16:23:02   hera
** We do not cut the prefix "_" in High C and PLM in ProcessPUBDEF
** 
**    Rev 1.4   30 Sep 1996 10:35:34   hera
** 
**    Rev 1.3   30 Sep 1996 10:28:28   hera
** 
**    Rev 1.2   26 Sep 1996 08:24:20   hera
** 
**    Rev 1.1   25 Sep 1996 10:03:30   hera
** 
**    Rev 1.0   14 Jun 1996 16:36:50   Judy
 ** Initial revision.
** 
**    Rev 1.22   19 May 1995 17:18:58   nghia
** Fixed PPR 10364 - missing LINNUM record when load ondemand off.
** Initialized <oldOffset> to 0 so that the compare condition does not
** reject valid line numbers.
** 
**    Rev 1.21   24 Apr 1995 18:08:44   nghia
** Fixed PPR 10232 - Replace symbol has invalid type with type void.
** 
**    Rev 1.20   10 Mar 1995 13:51:52   nghia
** Fixed PPR 10082 - Cannot load locals for BC40/Paradigm.  
** Revised condition to skip a BLKDEF-BLKEND to handle the extra blocks 
** generated by BC40.
** Revised function blocks processing in on-demand to handle open and close
** blocks correctly.  Added reset function address range for on-demand loading.
** 
**    Rev 1.19   14 Feb 1995 17:40:54   nghia
** Fixed PPR 10016 for PV 2.4 - Load borland's tool file /386real/allied/ast4.ab
** Discarded module blocks that had block size = 0.  Init module range to
** startOffset and 0.
**
**    Rev 1.18   24 Oct 1994 09:56:54   joyce
** Use subtraction instead of addition to filter out the unlikely to be
** correct line numbers.
**
**    Rev 1.17   21 Oct 1994 10:30:26   joyce
** Filtered out the unlikely to be correct line numbers.
**
**    Rev 1.16   11 Oct 1994 09:34:06   joyce
** 1. Use a stack to save block state, and discard the unnamed blocks if they
**    are out of their parent functions' address range.
** 2. Discard the line numbers if the address is out of the module range.
** 3. reorganize the error handling-- do not call LdrWarning() if the error code
**    is ER_LDR_ABORT, otherwise the error code might be changed to GOOD.
**
**    Rev 1.15   26 Sep 1994 13:37:46   joyce
** 1. Add checkings for TFree. If memory free error, allow user to abort the
**    load.
**
**    Rev 1.14   20 Sep 1994 11:52:28   joyce
** 1. Check for the returned error ER_PUBLIC_IGNORED while calling to add a
**    public label or var.  Ignore this error message.
**
**    Rev 1.13   14 Sep 1994 10:40:44   joyce
** Modify the error handling of CppFixUp.... functions.
**
**    Rev 1.12   07 Sep 1994 17:27:58   joyce
** 1. Modify ProcessLINNUM and ProcessBLKDEF to display module name when
**    multiple code segments are found in a module.
**
**    Rev 1.11   06 Sep 1994 09:53:30   joyce
** For the initial load with on-demand option on, Globals and Statics should be
** loaded.  Changes are made to support this.
**
**    Rev 1.10   23 Aug 1994 14:24:04   joyce
** 1. Changes in ProcessPUBDEF : remove ProcessTypes, and add list buffers
**    freeing function calls.
** 2. Change the algorithm of handling BLKDEF(ProcessBLKDEF) :
**    . No demand and On demand initial load -- Create functions.
**    . No demand and On demand module load -- Create unnamed blocks.
**    . On demand module load -- Open functions to add symbols.
**    This is because we can't open an unnamed block for on-demand load. The
**    loader has to create the block and add symbols all at once.
**
**    Rev 1.9   03 Aug 1994 13:25:10   steve
** Joyce's changes for 386 build 11
**
**    Rev 1.8   25 Jul 1994 12:41:14   steve
** Joyce's omf changes for 386 build 9
**
**    Rev 1.7   14 Jul 1994 15:23:28   steve
** More changes for 386 build 8 from Joyce
**
**    Rev 1.4   17 Jun 1994 15:15:22   joyce
** Add retcode checking for LdrWarning() so if user cancelled the load, it would
** cleanup and return.
**
**    Rev 1.3   16 Jun 1994 13:31:12   joyce
** Use LdrWarning() to replace Warning() and remove err.h from the include list.
**
**    Rev 1.2   02 Jun 1994 18:39:54   joyce
** Numerous changes to meet the code convention as the result of code review.
**
**    Rev 1.1   25 May 1994 15:59:52   joyce
** Remove the "UNSUPPORTED_DEBSYM_TYPE" warning for the externals
** (frameMethod==1).
**
**    Rev 1.0   24 May 1994 14:48:04   joyce
** Initial revision.
**
**  $Header:   S:/tbird/mt2_186/omf86/debug.cpv   1.7   02 Sep 1997 16:45:20   Judy  $
**
**  Copyright (C) 1994 Microtek International.  All rights reserved.
**
*****************************************************************************/

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

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

#ifndef __MEM_H
#include <mem.h>
#endif

#ifndef __STDLIB_H
#include <stdlib.h>
#endif

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

#ifndef _LMANGLE_
#include "lmangle.h"
#endif

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

#ifndef _HOSTERRS_
#include "hosterrs.h"
#endif

#ifndef __OMF86LDR__
#include "omf86ldr.h"
#endif

#ifndef __BASE__
#include "base.h"
#endif

#ifndef __PLM86__
#include "plm86.h"
#endif

#ifndef __TYPE__
#include "type.h"
#endif

		    /****************************
		     *                          *
		     *     LOCAL DEFINITIONS    *
		     *                          *
		     ****************************/
MODULE_BASE ModuleBase;
BLOCK_STATES BlockState[BLOCK_STATE_SIZE];
U8 BlkStateCnt = 0;
LANGUAGE_TYPE LangType=LANG_UNKNOWN;
CHAR ModName[NAME_LEN+1];
STATIC U32 ModuleOffset;
STATIC BOOLEAN FirstLineNum, HasBlocks, ModuleCreated, LineNumLoaded;
U16 Scope;
STATIC PUBLIC_SYM *PublicSymbol=NULL, *PubLinkTail=NULL;
STATIC OFFSET_ADDR_RANGE_TYPE ModuleAddrRange;
STATIC DEBUG_SYM *DbgSymbol=NULL, *DbgLinkTail;
STATIC U32 DbgSymCnt=0;
STATIC OFFSET_ADDR_RANGE_TYPE FuncRange;
Blk_Info *BlkSymbol=NULL, *BlkLinkTail=NULL;
U16 Segment = 0; //Hera
BOOLEAN AddFunc = FALSE;

		    /****************************
		     *                          *
		     *    EXTERNAL VARIABLES    *
		     *                          *
		     ****************************/
extern TIMESTAMP_TYPE LoadFileTimeStamp;
extern LADDRESS StackTop;
extern LPLDRSTATBLOCK StatBlock;
extern U32 StartRangeNotSet;
//**Hera 10/19/96**/
extern LANGUAGE_TYPE LangType;
extern HANDLE ListFile;
//**Hera**/
//**Hera 4/7/97**/
extern BOOLEAN FixedFlag;
//**Hera**/

		    /****************************
		     *                          *
		     *     LOCAL PROTOTYPES     *
		     *                          *
		     ****************************/
PRIVATE RETCODE GetSymbolEntries(HANDLE, U32, U32, BOOLEAN,
				 LADDRESS, SEG_ADDR_SPACE, U8);
PRIVATE RETCODE AddSymbol( LPSTR, U32, BASE_ADDRESS, SEG_ADDR_SPACE, U8,
			   TYPE_INDEX, U32);
PRIVATE BOOLEAN IsInModuleAddressRange(U16);
//PRIVATE BOOLEAN IsPublicSymbol(LPSTR, LADDRESS, BOOLEAN *);
PRIVATE LPSTR FixupName(LPSTR);
PRIVATE VOID UpdateModuleAddrRangeFromBLKDEF(OFFSET_ADDR_RANGE_TYPE *);
PRIVATE VOID UpdateModuleAddrRangeFromLINNUM(U16);
PRIVATE RETCODE LoadDebugSymbols(OMF86_FUNC_PARA *);
PRIVATE RETCODE FreeDebugSymbols(RETCODE);

		    /****************************
		     *                          *
		     *      EXECUTABLE CODE     *
		     *                          *
		     ****************************/
/******************************************************************************
**
**  ProcessTHEADR
**
******************************************************************************/
RETCODE ProcessTHEADR(OMF86_FUNC_PARA *funcPara) {
U8 nameLen;
RETCODE err=GOOD, err2;

   if (IsLoadSymbol(funcPara->flags)) {
      if ((err=LoadModuleEnd(funcPara)) != GOOD)
	 return(err);
      InitModuleParam();
      ModuleOffset = CurrentLocation() - sizeof(OMF86_REC_HEADER);
      if (((err=GetName(funcPara->hFile, &nameLen, ModName)) != GOOD) &&
	  (err2=LdrWarning(err, NULL, NULL, NULL)) != GOOD)
	 return(err2);
   }
   return(GOOD);
}  /* ProcessTHEADR */

/******************************************************************************
**
**  ProcessLINNUM
**
******************************************************************************/
RETCODE ProcessLINNUM(OMF86_FUNC_PARA *funcPara) {
#define LINE_ADDR_GUARD 512
RETCODE err=GOOD, err2;
LADDRESS base;
SYM_DESCRIPTOR moduleDesc;
BOOLEAN onDemand, localsLoaded;
LINENUM_ENTRY lineRec;
LINENUM_TEMP  lineTemp; //Hera 5/9/97
BASE_INDEX baseIndex;
BASE_TYPE baseType;
U16 oldOffset = 0;  // 05/19/95 - Nghia fixed bug PPR 10364
OFFSET_ADDR_RANGE_TYPE fnAddr;
OFFSET_ADDR_RANGE_TYPE tmAddr; /* <Winky 9/1/97> */
int newLine;
   //**Hera 10/19/96 If there is not List File, skip **/
   //**0xffff == HFILE_ERROR**/
   if(LangType == LANG_PLM && ListFile == 0xffff)
      return GOOD;
   //**Hera**
   // If not loadsymbol flag == FALSE, skip
   if (!IsLoadSymbol(funcPara->flags))  return(GOOD);
   localsLoaded = (funcPara->oFlag == MOPEN ||
		   !IsLoadOnDemand(funcPara->flags)) ? TRUE : FALSE;
   onDemand = IsLoadOnDemand(funcPara->flags);
   if ((err=GetBase(funcPara->hFile, &base)) != GOOD)
      return(err);
//   if (!ModuleBase.baseKnown) {
      if ((err=GetBaseIndex((BASE_ADDRESS)base.segment, funcPara->addrSpace,
			    TRUE, &baseIndex, &baseType)) != GOOD)
	 return(err);
      ModuleBase.baseKnown = TRUE;
      ModuleBase.baseIndex = baseIndex;
      ModuleBase.baseAddr = base.segment;
      ModuleBase.baseType = baseType;
//   }
//   else if (base.segment != ModuleBase.baseAddr)
//      return(LdrWarning(ER_OMF86_MULTIPLE_SEGMENT, ModName, NULL, NULL));
//   else baseIndex = ModuleBase.baseIndex;

   if (FirstLineNum) {
      if (!ModuleCreated && funcPara->oFlag == MCREATE) {
	 OFFSET_ADDR_RANGE_TYPE modRange;
	 // Set uninitialized address range for module
	 modRange.offsetStartAddr = (U16)StartRangeNotSet;
	 modRange.offsetEndAddr = 0;
         Segment = base.segment; //Hera
	 if (((err = SymAddModuleCreate(ModName, baseIndex,
		     &LoadFileTimeStamp, &modRange, ModuleOffset,
		     onDemand, 0L, &moduleDesc)) != GOOD) ||
	     ((err = SymAddModuleExtraInfo(moduleDesc,0L,LangType))!= GOOD)) {
	    /* what is typeOffset for? (here we give it 0) */
	    SkipOver(funcPara->hFile, funcPara->endLoc, THEADR);
	    FreeDebugSymbols(GOOD); //don't display err msg inside the fuction
	    InitModuleParam();
	    return(LdrWarning(ER_CANNOT_ADD_MOD, ModName, NULL, NULL));
	 }
	 AddFunc = TRUE; //Hera 5/26/97
	 ModuleCreated = TRUE;
	 funcPara->moduleDesc = moduleDesc;
      }
      else moduleDesc = funcPara->moduleDesc;
      if (localsLoaded) {
	 if ((err = SymAddLinenumStart(moduleDesc)) != GOOD) {
	    err2 = LdrWarning(err, NULL, NULL, NULL);
	    SymAddModuleClose(TRUE);
	    AddFunc = FALSE;         
	    return(err2);
	 }
	 if (!LineNumLoaded) LineNumLoaded = TRUE;
      }
   }
   newLine = 1;
   while (CurrentLocation() < funcPara->endLoc) {
      if ((err=OMFGetBytes(funcPara->hFile, (U8 *)&lineTemp, sizeof(lineTemp)))
	   != GOOD)
	 return(err);
      // 05/19/95 - Nghia
      // Fixed PPR 10364 - missed LINNUM record because the <oldOffset>
      // is not reset to 0 for each module.
      if (FirstLineNum) {
	 oldOffset =  lineTemp.offset;
	 FirstLineNum = FALSE;	 
      }
      // Skip any line that is not in range and out of order
      if ((Segment == base.segment && !IsInModuleAddressRange(lineTemp.offset))
           ||((oldOffset > lineTemp.offset) &&
	   (oldOffset - lineTemp.offset > LINE_ADDR_GUARD))) {
	 continue;
      }
      //Hera 5/9/97
      lineRec.lineNum = lineTemp.lineNum;
      lineRec.offset = lineTemp.offset;
      lineRec.segment = base.segment;
      if (LineNumLoaded && ((err=LoadLinenum(&lineRec, &oldOffset)) != GOOD)){
	 if ((err2=LdrWarning(err, NULL, NULL, NULL)) != GOOD)
	    return(err2);
      }
      //Hera 5/26/97
      if (newLine){
	 fnAddr.offsetStartAddr = lineTemp.offset;
	 newLine = 0;
      }
      else 
         fnAddr.offsetEndAddr = lineTemp.offset;
      //Hera   
      if (Segment == base.segment)
	 UpdateModuleAddrRangeFromLINNUM(lineRec.offset);
   }
   if (AddFunc){
      PUBLIC_SYM *pubPtr;
      LPSTR funcName;
      pubPtr = PublicSymbol;

      while (pubPtr != NULL){
         if (pubPtr->addr.segment == base.segment &&
	    pubPtr->addr.offset == fnAddr.offsetStartAddr) {
	    funcName = pubPtr->symName;
	    pubPtr->isLoaded = TRUE;
	    break;
         }else
	    pubPtr = pubPtr->next;
      }
      if (pubPtr == NULL)
         return(err); //Hera 6/23/97
         //funcName = "";
      /* Added by <Winky 9/1/97> */
      tmAddr.offsetStartAddr = fnAddr.offsetStartAddr;
      pubPtr = pubPtr->next;
      while ((pubPtr != NULL) && (pubPtr->addr.segment == base.segment)) {
         if ((pubPtr->addr.offset >= fnAddr.offsetStartAddr) &&
             (pubPtr->addr.offset <= fnAddr.offsetEndAddr)) {
            tmAddr.offsetEndAddr = pubPtr->addr.offset;
            err=SymAddFuncCreate(funcName, baseIndex, base.segment,
                                 FUNC_GLOBAL, 0, &tmAddr, 0x01);
            SymAddFuncClose();
            funcName = pubPtr->symName;
            pubPtr->isLoaded = TRUE;
            tmAddr.offsetStartAddr = pubPtr->addr.offset;
         }
         pubPtr = pubPtr->next;
      }
      tmAddr.offsetEndAddr = fnAddr.offsetEndAddr;
      err=SymAddFuncCreate(funcName, baseIndex, base.segment, FUNC_GLOBAL,
      	                   0, //stackSize=0;
                           &tmAddr, 0x01);
      /* eof by <Winky 9/1/97> */
      SymAddFuncClose();
   }
   return(err);
}  /* ProcessLINNUM */

/******************************************************************************
**
**  ProcessPUBDEF
**
******************************************************************************/
RETCODE ProcessPUBDEF(OMF86_FUNC_PARA *funcPara) {
RETCODE err;
LADDRESS address;
CHAR symName[NAME_LEN+1];
LPSTR publicName = "";
U16  offset;
TYPE_INDEX typeIdx;
PUBLIC_SYM *tmpPtr=NULL;
U8 nameLen;
PUBLIC_SYM *pubPtr;
BOOLEAN isfound;

   if (!IsLoadSymbol(funcPara->flags) || funcPara->oFlag != MCREATE)
      return(GOOD);
   if (!PublicSymbol) {
      /* Free type list buffers after finishing type processings */
      FreeListBuffer(INDEX_LIST);
      FreeListBuffer(NAME_LIST);
      FreeListBuffer(VALUE_LIST);
      if ((PublicSymbol=(PUBLIC_SYM *)TMalloc(sizeof(PUBLIC_SYM))) == NULL)
	 return(ER_NO_MEMORY);
      memset(PublicSymbol, NULL, sizeof(PUBLIC_SYM));
      tmpPtr = PubLinkTail = PublicSymbol;
   }
   if ((err=GetBase(funcPara->hFile, &address)) != GOOD)
      return(err);
   while (CurrentLocation() < funcPara->endLoc) {
      if ((err=GetName(funcPara->hFile, &nameLen, symName)) != GOOD)
	 return(err);

      //**Hera 10/11/96**/
      //**If FixedFlag(set in plm86.cpp) is FALSE, **/
      //**we do not cut prefix "_"**/
      if (symName != NULL && FixedFlag)
	  publicName = FixupName((LPSTR)symName);
      else if(symName != NULL)
          publicName = (LPSTR)symName;
      //**Hera**/
       
      if ((err=OMFGetBytes(funcPara->hFile, (U8 *)&offset, sizeof(offset)))
	  != GOOD) return(err);
      address.offset = offset;
      if ((err=GetTypeIndex(funcPara->hFile, &typeIdx)) != GOOD) {
	 // 04/21/95 - Nghia
	 // For Public name definition symbols, if the typeIndex is not
	 // valid, use the default type BI_VOID
	 if (err != ER_TYPE_IDXS_DONT_MATCH) return(err);
	  // Use default type BI_VOID
	 typeIdx = BI_VOID;
      }
      //Hera 4/10/97
      isfound = FALSE;
      pubPtr=PublicSymbol;
      while(pubPtr) {
	 if (pubPtr->symName != NULL && (!strcmp(pubPtr->symName,publicName))) {
	    if(pubPtr->typeIndex == 0x101) //void
	       pubPtr->typeIndex = typeIdx;
	    isfound = TRUE;
            break;
	 }
         pubPtr = pubPtr->next;
      }
      if(!isfound) {      
         if (!tmpPtr) {
	    if ((tmpPtr=(PUBLIC_SYM *)TMalloc(sizeof(PUBLIC_SYM))) == NULL)
	       return(ER_NO_MEMORY);
	    memset(tmpPtr, NULL, sizeof(PUBLIC_SYM));
	    if (!PubLinkTail)
	       return(ER_PUBLIC_IGNORED);
	    PubLinkTail->next = tmpPtr;
         }
         if ((tmpPtr->symName=(CHAR *)TMalloc(lstrlen(publicName)+1)) == NULL)
	    return(ER_NO_MEMORY);
         lstrcpy(tmpPtr->symName, publicName);
         memcpy(&(tmpPtr->addr), &address, sizeof(address));
         tmpPtr->typeIndex = typeIdx;
         tmpPtr->next = NULL;
         PubLinkTail = tmpPtr;
	 tmpPtr = NULL;
      }
      //Hera
   }
   return(GOOD);
}  /* ProcessPUBDEF */

/******************************************************************************
**
**  ProcessLOCSYM
**
******************************************************************************/
RETCODE ProcessLOCSYM(OMF86_FUNC_PARA *funcPara) {
LADDRESS base;
RETCODE err;

   if (!IsLoadSymbol(funcPara->flags))
      return(GOOD);
   if (funcPara->oFlag == MCREATE) { /* Initial Load */
      if (IsLoadOnDemand(funcPara->flags) && Scope)
	 return(GOOD);
   }
   else if (!Scope) return(GOOD); /* On-demand, globals are already loaded */

   if ((err=GetBase(funcPara->hFile, &base)) != GOOD) return(err);
   return(GetSymbolEntries(funcPara->hFile, funcPara->endLoc,
			   funcPara->flags, funcPara->oFlag,
			   base, funcPara->addrSpace, STATICSYM));
}  /* ProcessLOCSYM */


/******************************************************************************
**
**  ProcessDEBSYM
**
******************************************************************************/
RETCODE ProcessDEBSYM(OMF86_FUNC_PARA *funcPara) {
LADDRESS baseAddr;
FRAME_INFO frameInfo;
RETCODE err;
U16 blkIndex;
U8 symClass;

   if (!IsLoadSymbol(funcPara->flags))
      return(GOOD);
   if (funcPara->oFlag == MCREATE) { /* Initial Load */
      if (IsLoadOnDemand(funcPara->flags) && Scope)
	 return(GOOD);
   }
   else if (!Scope) return(GOOD); /* On-demand, globals are already loaded */

   if ((err=OMFGetBytes(funcPara->hFile, (U8 *)&frameInfo,
       sizeof(frameInfo))) != GOOD)
      return(err);
   switch(((U8)frameInfo.frameMethod)&3) {
      case 0:
	 GetBase(funcPara->hFile, &baseAddr);
	 symClass = STATICSYM;
	 break;
      case 1: // external symbol
	 return(GOOD);
      case 2:
	 GetIndex(funcPara->hFile, &blkIndex);
	 memcpy(&baseAddr, &StackTop, sizeof(baseAddr));
	 symClass = LOCALSYM | AUTOMATICSYM;
	 break;
      default:
	 return(ER_REC_NOT_HANDLED);
   }
   return(GetSymbolEntries(funcPara->hFile, funcPara->endLoc,
			   funcPara->flags, funcPara->oFlag,
			   baseAddr, funcPara->addrSpace, symClass));
}  /* ProcessDEBSYM */

/******************************************************************************
**
**  ProcessBLKDEF
**
**  Initial Load :                      Module Load : (On-demand)
**    Not_on_demand --
**       Functions      :  Create            Functions      :  Open
**       Unnamed blocks :  Create            Unnamed blocks :  Create
**    On_demand --
**       Functions      :  Create
**       Unnamed blocks :  Skip over the block
**
******************************************************************************/
RETCODE ProcessBLKDEF(OMF86_FUNC_PARA *funcPara) {
LADDRESS base;
CHAR blkName[NAME_LEN+1];
CHAR *pName;
BLOCK_INFO blkInfo;
PROC_INFO procInfo;
RETCODE err=GOOD, err2;
U8 nameLen;
BASE_INDEX baseIndex;
FUNC_CLASS funcClass;
U16 retAddrOffset=0;
TYPE_INDEX typeIdx;
OFFSET_ADDR_RANGE_TYPE fnAddr;
//BOOLEAN isLoaded; //Hera 4/3/97
BASE_TYPE baseType;
Blk_Info *blkTemp;

   if (!IsLoadSymbol(funcPara->flags))
      return(GOOD);

   BlockState[BlkStateCnt++] = BLOCK_START;
   if ((err=GetBase(funcPara->hFile, &base)) != GOOD)
      goto BLKDEF_END;
   if ((err=GetName(funcPara->hFile, &nameLen, blkName)) != GOOD)
      goto BLKDEF_END;

   /*  Read in the rest of BLKDEF */
   if ((err=OMFGetBytes(funcPara->hFile, (U8 *)&blkInfo,
			sizeof(blkInfo))) != GOOD)
      goto BLKDEF_END;
   if ((err=OMFGetBytes(funcPara->hFile, (U8 *)&procInfo,
	sizeof(procInfo))) != GOOD)
      goto BLKDEF_END;
   if ((procInfo.procBit) && ((err=OMFGetBytes(funcPara->hFile,
			(U8 *)&retAddrOffset, sizeof(retAddrOffset))) != GOOD))
      goto BLKDEF_END;

   // 01/06/94 - Nghia
   // - Discard blocks that does not have a blkSize when there is no
   // function scope opened.
   // - Discard the unnamed blocks defined before an opened functions scope.
   // 03/21/96 - Joyce
   // - Discard the blocks defined before an opened functions scope.
   if (!Scope && (!blkInfo.blkSize || (!procInfo.procBit) ||
	((funcPara->oFlag == MCREATE) && (blkName[0] == '\0'))) ) {
      BlockState[--BlkStateCnt] = BLOCK_DISCARD;
      BlkStateCnt++;
      return(GOOD);
   }
//   if (!ModuleBase.baseKnown) {
      if ((err=GetBaseIndex((BASE_ADDRESS)base.segment, funcPara->addrSpace,
                             TRUE, &baseIndex, &baseType)) != GOOD)
	 goto BLKDEF_END;
      ModuleBase.baseKnown = TRUE;
      ModuleBase.baseAddr = base.segment;
      ModuleBase.baseIndex = baseIndex;
      ModuleBase.baseType = baseType;
//   }
//   else if (base.segment != ModuleBase.baseAddr) {
//      err = LdrWarning(ER_OMF86_MULTIPLE_SEGMENT, ModName, NULL, NULL);
//      goto BLKDEF_END;
//   }
//   else baseIndex = ModuleBase.baseIndex;

   // Demangle block name if needed
   if (!nameLen || !IsDeMangle(funcPara->flags) ||
      ((err = LdrCppFixupFunction((LPSTR)blkName, (LPSTR *)&pName,
				  (funcPara->oFlag == MCREATE))) != GOOD)) {
      pName = blkName; // use the original block name
   }

   if ((funcPara->oFlag == MCREATE) && !ModuleCreated) {
      SYM_DESCRIPTOR moduleDesc;
      OFFSET_ADDR_RANGE_TYPE modRange;
      // Set uninitialized address range for module
      modRange.offsetStartAddr = (U16)StartRangeNotSet;
      modRange.offsetEndAddr = 0;
      Segment = base.segment; //Hera
      if (((err = SymAddModuleCreate(ModName, baseIndex,
		  &LoadFileTimeStamp, &modRange, ModuleOffset,
		  IsLoadOnDemand(funcPara->flags), 0L,
		  &moduleDesc)) != GOOD) ||
	  ((err = SymAddModuleExtraInfo(moduleDesc, 0L, LangType))!= GOOD)) {
	 /* what is typeOffset for? (here we give it 0) */
	 SkipOver(funcPara->hFile, funcPara->endLoc, THEADR);
	 FreeDebugSymbols(GOOD);  //don't display err msg inside the fuction
	 InitModuleParam();
	 return(LdrWarning(ER_CANNOT_ADD_MOD, ModName, NULL, NULL));
      }
      ModuleCreated = TRUE;
      funcPara->moduleDesc = moduleDesc;
   }
   // Open function for ondemand loading  
   else if ((funcPara->oFlag == MOPEN) && (*pName != '\0')) {
      if ((err = SymAddFuncOpen(pName)) != GOOD) {
	 /* try mangled name */
	 pName = blkName;
	 if ((err = SymAddFuncOpen(pName)) != GOOD) {
	    if ((err = LdrWarning(ER_FN_NOT_FOUND, (LPSTR)pName,
				  NULL, NULL)) != GOOD)
	       return(err);
	    return(SkipOver(funcPara->hFile, funcPara->endLoc, BLKDEF));
	 }
      }
      // Save the function address range for local block checking
      FuncRange.offsetStartAddr = blkInfo.blkOffset;
      FuncRange.offsetEndAddr   = blkInfo.blkOffset + blkInfo.blkSize - 1L;
      Scope++;
      // Need to update module address range because
      // processTHEADER() reset the module Range.
      if (Segment == base.segment)
         UpdateModuleAddrRangeFromBLKDEF(&FuncRange);
      return GOOD;
   }
   /***
    *** For initial load and ondemand=ON, do not load unnamed blocks and
    ***  wait till module load to create the blocks
    ***/
   if ((*pName == '\0') && (funcPara->oFlag == MCREATE) &&
       IsLoadOnDemand(funcPara->flags)) {
      err = GOOD;
      goto BLKDEF_END;
   }
   /***
    *** Create functions for initial load and create unnamed blocks for
    *** ondemand load.
    ***/
   fnAddr.offsetStartAddr = blkInfo.blkOffset;
   fnAddr.offsetEndAddr   = blkInfo.blkOffset + blkInfo.blkSize - 1L;
   if (*pName != '\0') { // function
      FuncRange.offsetStartAddr = fnAddr.offsetStartAddr;
      FuncRange.offsetEndAddr   = fnAddr.offsetEndAddr;
   }
   else if ((fnAddr.offsetStartAddr < FuncRange.offsetStartAddr) ||
	    (fnAddr.offsetEndAddr > FuncRange.offsetEndAddr)) {
      /***
       ***  Discard the block and its associated local symbols if the
       ***  block range is outside its parent function.
       ***/
      err = GOOD;
      goto BLKDEF_END;
   }
   if ((nameLen > 0) && ((err=GetTypeIndex(funcPara->hFile,
					   &typeIdx)) != GOOD))
      goto BLKDEF_END;
   base.offset = blkInfo.blkOffset;
   //Hera 4/3/97
   blkTemp = (Blk_Info*)TMalloc(sizeof(Blk_Info));
   //pBlkName = FixupName((LPSTR)blkName);
   lstrcpy(blkTemp->blkName, pName);
   blkTemp->base.offset = base.offset;
   blkTemp->base.segment= base.segment;
   blkTemp->next = NULL;
   if (BlkSymbol == NULL) {
      BlkSymbol = blkTemp;
      BlkLinkTail = BlkSymbol;
   }
   else
   {
      BlkLinkTail->next = blkTemp;
      BlkLinkTail = blkTemp;
   } //Hera
   funcClass = (!Scope /*&& IsPublicSymbol(pName, base, &isLoaded) Hera 4/3/97*/ ) ?
	       FUNC_GLOBAL : FUNC_LOCAL;
   if (((err=SymAddFuncCreate(pName, baseIndex, base.segment, funcClass, //Hera 5/9/97
			      0, //stackSize=0;
			      &fnAddr, typeIdx)) != GOOD) &&
       (err2=LdrWarning(ER_CANNOT_ADD_FUNC, (LPSTR)pName, NULL, NULL))!= GOOD)
      return(err2);
   if (err != GOOD) {
      err = GOOD; /* error message is displayed */
      goto BLKDEF_END;
   }
   if (*pName)
      StatBlock->numFunctions++;
   if (Segment == base.segment)
      UpdateModuleAddrRangeFromBLKDEF(&fnAddr);
   if (!HasBlocks) HasBlocks = TRUE;
   Scope++;
   return(GOOD);
BLKDEF_END:
   SkipOver(funcPara->hFile, funcPara->endLoc, BLKDEF);
   return(err);
}  /* ProcessBLKDEF */

/******************************************************************************
**
**  ProcessBLKEND
**
******************************************************************************/
RETCODE ProcessBLKEND(OMF86_FUNC_PARA *funcPara) {
BLOCK_STATES state;

   if (!IsLoadSymbol(funcPara->flags)) return(GOOD);
   if (BlkStateCnt < 1)
      return(ER_BAD_FILE);
   state = BlockState[--BlkStateCnt];
   BlockState[BlkStateCnt] = BLOCK_END;
   if (state == BLOCK_DISCARD)
      return(GOOD);
   Scope--;
   return(SymAddFuncClose());
}  /* ProcessBLKEND */

/******************************************************************************
**
**  InitModuleParam
**
******************************************************************************/
VOID InitModuleParam(VOID) {
   HasBlocks = LineNumLoaded = ModuleCreated = FALSE;
   DbgSymbol = NULL;
   DbgSymCnt = 0L;
   FirstLineNum = TRUE;
   ModuleAddrRange.offsetStartAddr = StartRangeNotSet;
   ModuleAddrRange.offsetEndAddr = Scope = 0;
   BlkStateCnt = 0;
   LangType = LANG_UNKNOWN;
   memset(BlockState, BLOCK_END, BLOCK_STATE_SIZE);
   memset(&ModuleBase, NULL, sizeof(ModuleBase));
   memset(&FuncRange, NULL, sizeof(FuncRange));
   LdrCppClearFunctionTable();
}  /* InitModuleParam */

/******************************************************************************
**
**  GetSymbolEntries
**
******************************************************************************/
PRIVATE RETCODE GetSymbolEntries(HANDLE hFile, U32 endLoc, U32 flags,
				 BOOLEAN oFlag, LADDRESS baseAddr,
				 SEG_ADDR_SPACE addrSpace, U8 symClass) {
CHAR symName[NAME_LEN+1];
U16  offset;
TYPE_INDEX typeIndex;
S32  symOffset;
RETCODE err, err2;
U8 nameLen;
DEBUG_SYM *tmpPtr=NULL;

   while (CurrentLocation() < endLoc) {
      if ((err=GetName(hFile, &nameLen, symName)) != GOOD)
	 return(err);
      if ((err=OMFGetBytes(hFile, (U8 *)&offset, sizeof(offset))) != GOOD)
	 return(err);
      if ((err=GetTypeIndex(hFile, &typeIndex)) != GOOD) {
	 // 04/21/95 - Nghia
	 // If the typeIndex is not valid, replace with type BI_VOID
	 // warn user about replacing symbol type
	 // See PPR 10232 for more information.
	 if (err != ER_TYPE_IDXS_DONT_MATCH) return(err);
	 if (!symName) sprintf((LPSTR)symName, "(id=0x%lX)", typeIndex);
    /*   if ((err = LdrWarning(ER_SYM_INVALID_TYPE_ID, (LPSTR)symName,
			       NULL, NULL)) != GOOD)
	    return(err); */
	 typeIndex = BI_VOID;
      }
      
      // get symbol offset
      symOffset = (symClass & AUTOMATICSYM) ? (S32) ((S16)offset) :
		  (U32) offset;
      
      if (oFlag == MCREATE && !ModuleCreated) {
	 if (!DbgSymbol) {
	    if ((DbgSymbol=(DEBUG_SYM *)TMalloc(sizeof(DEBUG_SYM))) == NULL)
	       return(ER_NO_MEMORY);
	    memset(DbgSymbol, NULL, sizeof(DEBUG_SYM));
	    tmpPtr = DbgLinkTail = DbgSymbol;
	 }
	 if (!tmpPtr) {
	    if ((tmpPtr=(DEBUG_SYM *)TMalloc(sizeof(DEBUG_SYM))) == NULL)
	       return(FreeDebugSymbols(ER_NO_MEMORY));
	    memset(tmpPtr, NULL, sizeof(DEBUG_SYM));
	    DbgLinkTail->next = tmpPtr;
	 }
	 if ((tmpPtr->symName=(CHAR *)TMalloc(lstrlen((LPSTR)symName)+1))
	     == NULL)
	    return(FreeDebugSymbols(ER_NO_MEMORY));
	 lstrcpy(tmpPtr->symName, symName);
	 tmpPtr->segment = baseAddr.segment;
	 tmpPtr->offset  = (U32)symOffset;
	 tmpPtr->typeIndex = typeIndex;
	 tmpPtr->symClass = symClass;
	 tmpPtr->next = NULL;
	 DbgLinkTail = tmpPtr;
	 tmpPtr = NULL;
	 DbgSymCnt++;
	 continue; // next symbol
      }
      
      // load symbol directly
      if (((err=AddSymbol(symName, symOffset,
			  (BASE_ADDRESS)baseAddr.segment,
			  addrSpace, symClass, typeIndex, flags))
	   != GOOD) &&
	  (err2=LdrWarning(err, NULL, NULL, NULL)) != GOOD) {
	 return(err2);
      }
   } // while
   
   return(GOOD);
}  /* GetSymbolEntries */

/******************************************************************************
**
**  AddSymbol
**
******************************************************************************/
PRIVATE RETCODE AddSymbol( LPSTR name, U32 symOffset, BASE_ADDRESS segAddr,
			   SEG_ADDR_SPACE addrSpace, U8 symClass,
			   TYPE_INDEX typeIndex, U32 flags) {
RETCODE err;
BASE_INDEX baseIndex=0;
VAR_STORAGE_CLASS varClass;
LPSTR symName;
SYM_DESCRIPTOR symP;
BOOLEAN isLoaded=FALSE;
BASE_TYPE baseType;

//** Hera 09/17/96**/
TYPE_HEADER_TYPE  typeHeader;
CHAR typeName[MAX_STRING_SIZE] = "";
//** Hera**/

   if (!(symClass & AUTOMATICSYM)) {
      if ((err = GetBaseIndex(segAddr, addrSpace, FALSE, &baseIndex, &baseType))
	       == ERR_BAD_BASE) // base not in SEGDEF's, do not build this symbol
	 return(GOOD);
      else if (err != GOOD)
	 return(err);
   }
   symName = name;

   //** Hera 09/17/96**/
   typeHeader.typeName = typeName;
   SymGetTypeHeader(typeIndex,&typeHeader);
   
   if ((symClass & PUBLICSYM) &&
       (typeHeader.t.complexType == TY_FUNC_NODEP || typeHeader.t.complexType == TY_FUNC_DEP))
   //**Hera**/
   {
      if (IsDeMangle(flags))
	 LdrCppFixupGlobal(name, &symName);
      
      if (baseType == BASE_CODE) {
	 // Add public label
	 err = SymAddLabelPublic(symName, baseIndex,
	       (OFFSET_ADDR_TYPE) symOffset);
	 return (err == ER_PUBLIC_IGNORED) ? GOOD : err;
      } else {
	 // Add public variable
	 while (((err = SymAddVarPublic(symName, baseIndex, typeIndex,
		  (OFFSET_ADDR_TYPE)symOffset)) == ER_INDEX_NOT_IN_TABLE)
		&& (typeIndex != BI_VOID)) {
	    // warn user about replacing symbol type
	    if (!symName) sprintf((LPSTR)symName, "(id=0x%lX)", typeIndex);
      /*    if ((err = LdrWarning(ER_SYM_INVALID_TYPE_ID, (LPSTR)symName,
				  NULL, NULL)) != GOOD)
	       return(err); */
	    typeIndex = BI_VOID;
	 } // while
	 
	 // ignore duplicate labels and those which are not in
	 // code segment
	 return (((err == ER_PUBLIC_IGNORED) || (err == ER_NOT_A_VARIABLE)) ?
		   GOOD : err);
      }
   }
   if ((symClass & STATICSYM) && !Scope) {
      LADDRESS address;

      address.segment = (U16)segAddr;
      address.offset  = (U16)symOffset;
      if (IsPublicSymbol(name, address, &isLoaded))
	 symClass |= GLOBALSYM;
      if (isLoaded) return(GOOD);
   }

   //**Hera 09/12/96 -- for microsoft assembly**/
   if ((symClass & STATICSYM) && baseType == BASE_CODE &&
       (typeHeader.t.complexType == TY_FUNC_NODEP || typeHeader.t.complexType == TY_FUNC_DEP))
   {
   //**Hera**/
      return(SymAddLabel(symName,
			 baseIndex,
			 (OFFSET_ADDR_TYPE) symOffset));
   }
   if (symClass & GLOBALSYM)
      varClass = GLOBAL_VAR_CLASS;
   else if (symClass & STATICSYM)
      varClass = STATIC_VAR_CLASS;
   else if (symClass & AUTOMATICSYM)
      varClass = AUTO_VAR_CLASS;

   // 04/21/95 - Nghia
   // Replace typeIndex with BI_VOID if symbol has invalid type
   // Warn the user about replacing symbol type.
   while (((err = SymAddVar(symName,
			   baseIndex,
			   typeIndex,
			   varClass,
			   NOT_REG,
			   (ADD_VAR_ADDR_UNION *)&symOffset,
			   FALSE, /* not constant */
			   TRUE,  /* address is valid */
			   &symP)) == ER_INDEX_NOT_IN_TABLE) &&
	  (typeIndex != BI_VOID)) {
      // warn user about replacing symbol type
      if (!symName) sprintf((LPSTR)symName, "(id=0x%lX)", typeIndex);
      /*if ((err = LdrWarning(ER_SYM_INVALID_TYPE_ID, (LPSTR)symName,
			    NULL, NULL)) != GOOD)
	 return(err);*/
      typeIndex = BI_VOID;
   }
   
   return(err);
}  /* AddSymbol */

/******************************************************************************
**
**  FreePublics
**
******************************************************************************/
RETCODE FreePublics(RETCODE err) {
PUBLIC_SYM *tmpPtr, *tmpPtrNext;
RETCODE err1;

   tmpPtr = PublicSymbol;
   while (tmpPtr != NULL) {
      if ((tmpPtr->symName) && (TFree((LPSTR)tmpPtr->symName) != GOOD)) {
	 if ((err1 = LdrWarning(ER_BAD_FREE, NULL, NULL, NULL)) != GOOD)
	    return(err1);
      }
      tmpPtrNext = tmpPtr->next;
      if (TFree((LPSTR)tmpPtr) != GOOD) {
	 if ((err1 = LdrWarning(ER_BAD_FREE, NULL, NULL, NULL)) != GOOD)
	    return(err1);
      }
      tmpPtr = tmpPtrNext;
   }
   PubLinkTail = PublicSymbol = NULL;
   return(err);
} /* FreePublics */

/******************************************************************************
**
**  FreeDebugSymbols
**
******************************************************************************/
PRIVATE RETCODE FreeDebugSymbols(RETCODE err) {
DEBUG_SYM *tmpPtr, *tmpPtrNext;
RETCODE err1=GOOD;
LOOP_VAR i=0;

   if ((err != GOOD) && (err != ER_LDR_ABORT)) {
      err1 = LdrWarning(err, NULL, NULL, NULL);
      err = (err1 == GOOD) ? err : err1;
   }
   tmpPtr = DbgSymbol;
   while (tmpPtr != NULL && i++ < DbgSymCnt) {
      if ((tmpPtr->symName) && (TFree((LPSTR)tmpPtr->symName) != GOOD)) {
	 if ((err1 = LdrWarning(ER_BAD_FREE, NULL, NULL, NULL)) != GOOD)
	    return(err1);
      }
      tmpPtrNext = tmpPtr->next;
      if (TFree((LPSTR)tmpPtr) != GOOD) {
	 if ((err1 = LdrWarning(ER_BAD_FREE, NULL, NULL, NULL)) != GOOD)
	    return(err1);
      }
      tmpPtr = tmpPtrNext;
   }
   DbgLinkTail = DbgSymbol = NULL;
   return(err);
} /* FreeDebugSymbols */

/******************************************************************************
**
**  LoadPublics
**
******************************************************************************/
RETCODE LoadPublics(OMF86_FUNC_PARA *funcPara) {
PUBLIC_SYM *tmpPtr;
RETCODE err2=GOOD, err;

  tmpPtr = PublicSymbol;
  Scope=0;
  while (tmpPtr != NULL) {
     if (!tmpPtr->isLoaded &&
	 ((err=AddSymbol(tmpPtr->symName, (U32)tmpPtr->addr.offset,
			 (BASE_ADDRESS)tmpPtr->addr.segment,
			 funcPara->addrSpace,
			 STATICSYM | PUBLICSYM, tmpPtr->typeIndex,
			 funcPara->flags)) != GOOD) &&
         (err2=LdrWarning(err, NULL, NULL, NULL)) != GOOD);

     //   goto LOAD_PUBLICS_END; <Judy 7/31/97>
     // next symbol in the list
     tmpPtr = tmpPtr->next;
  }
LOAD_PUBLICS_END:
  return(FreePublics(err2));
} /* LoadPublics */

/******************************************************************************
**
**  LoadDebugSymbols
**
******************************************************************************/
PRIVATE RETCODE LoadDebugSymbols(OMF86_FUNC_PARA *funcPara) {
DEBUG_SYM *tmpPtr;
RETCODE err2=GOOD, err;
LOOP_VAR i=0;

   tmpPtr = DbgSymbol;
   while (tmpPtr != NULL && i++ < DbgSymCnt) {
      if (((err=AddSymbol(tmpPtr->symName, (U32)tmpPtr->offset,
			  (BASE_ADDRESS)tmpPtr->segment, funcPara->addrSpace,
			  tmpPtr->symClass, tmpPtr->typeIndex,
			  funcPara->flags)) != GOOD) &&
	  (err2=LdrWarning(err, NULL, NULL, NULL)) != GOOD)
	 goto LOAD_DEBUG_SYMBOLS_END;
      tmpPtr = tmpPtr->next;
   }
LOAD_DEBUG_SYMBOLS_END:
   return(FreeDebugSymbols(err2));
}   /* LoadDebugSymbols */

/******************************************************************************
**
**  IsPublicSymbol
**
******************************************************************************/
BOOLEAN IsPublicSymbol(LPSTR inputSymName, LADDRESS inputAddr,
			       BOOLEAN *isLoaded) {
PUBLIC_SYM *tmpPtr;

  *isLoaded = FALSE;
  tmpPtr = PublicSymbol;
  while (tmpPtr != NULL) {
     if (tmpPtr->symName != NULL) {
	if (!lstrcmp(inputSymName, (LPSTR)tmpPtr->symName) &&
	    !memcmp(&inputAddr, &(tmpPtr->addr), sizeof(inputAddr))) {
	   *isLoaded = tmpPtr->isLoaded;
	   tmpPtr->isLoaded = TRUE;
	   return(TRUE);
	}
     }
     tmpPtr = tmpPtr->next;
  }
  return(FALSE);
}  /* IsPublicSymbol */

/******************************************************************************
**
**  FixupName
**
******************************************************************************/
PRIVATE LPSTR FixupName(LPSTR oldName) {
   if (lstrlen(oldName) > 1 && *oldName == PUBLIC_PREFIX)
      return(++oldName);
   return(oldName);
}  /* FixupName */

/******************************************************************************
**
**  IsInModuleAddressRange
**
******************************************************************************/
PRIVATE BOOLEAN IsInModuleAddressRange(U16 offset) {
   if (HasBlocks)
      return(offset >= ModuleAddrRange.offsetStartAddr);
   return(TRUE);

}  /* IsInModuleAddressRange */

/******************************************************************************
**
**  UpdateModuleAddrRangeFromLINNUM
**
******************************************************************************/
PRIVATE VOID UpdateModuleAddrRangeFromLINNUM(U16 offset) {
   if (ModuleAddrRange.offsetStartAddr > offset)
      ModuleAddrRange.offsetStartAddr = offset;
   if (ModuleAddrRange.offsetEndAddr < offset)
      ModuleAddrRange.offsetEndAddr = offset;
}  /* UpdateModuleAddrRangeFromLINNUM */

/******************************************************************************
**
**  UpdateModuleAddrRangeFromBLKDEF
**
******************************************************************************/
PRIVATE VOID UpdateModuleAddrRangeFromBLKDEF(OFFSET_ADDR_RANGE_TYPE
					     *blockAddr) {
   if (blockAddr->offsetEndAddr < blockAddr->offsetStartAddr)
      swab((CHAR *)&(blockAddr->offsetStartAddr),
	   (CHAR *)&(blockAddr->offsetEndAddr), sizeof(U16));	      
   if (ModuleAddrRange.offsetStartAddr > blockAddr->offsetStartAddr)
      ModuleAddrRange.offsetStartAddr = blockAddr->offsetStartAddr;
   if (ModuleAddrRange.offsetEndAddr < blockAddr->offsetEndAddr)
      ModuleAddrRange.offsetEndAddr = blockAddr->offsetEndAddr;
}  /* UpdateModuleAddrRangeFromBLKDEF */

/******************************************************************************
**
**  LoadModuleEnd
**
******************************************************************************/
RETCODE LoadModuleEnd(OMF86_FUNC_PARA *funcPara) {
RETCODE err=GOOD, err2;
BOOLEAN localsLoaded;
QUAL_ADDR_RANGE_TYPE modAddr;

   if (DbgSymbol) {
       if (funcPara->oFlag == MCREATE && ModuleCreated) {
	  if ((err = LoadDebugSymbols(funcPara)) != GOOD)
	     return(err);
       }
       else if ((err = FreeDebugSymbols(err)) != GOOD)
	  return(err);
   }
   localsLoaded = (funcPara->oFlag == MOPEN ||
		   !IsLoadOnDemand(funcPara->flags)) ? TRUE : FALSE;
   if (((funcPara->oFlag == MCREATE && ModuleCreated) ||
	funcPara->oFlag == MOPEN) &&
       ((err=SymAddModuleClose(localsLoaded)) != GOOD) &&
       ((err2=LdrWarning(err, NULL, NULL, NULL)) != GOOD))
      return(err2);
   AddFunc = FALSE; //Hera 5/26/97
   /* Update module range info */
   if (ModuleCreated) {
      if (!ModuleAddrRange.offsetEndAddr) {
	 modAddr.startAddr  = (U16)StartRangeNotSet;
	 modAddr.endAddr    = (U16)StartRangeNotSet - 1;
      }
      else {
	 modAddr.startAddr  = ModuleAddrRange.offsetStartAddr;
	 modAddr.endAddr    = ModuleAddrRange.offsetEndAddr;
      }
      modAddr.startValid = TRUE;
      modAddr.endValid   = TRUE;
      /* NOTES:
      ** The Symbol Table is smart enough to figure out this is the
      ** context we are adding info to (module).
      */
      if (((err = SymAddSymbolSetAddr(&modAddr)) != GOOD) &&
	  ((err = LdrWarning(ER_SYM_NOT_UPDATED, NULL, NULL, NULL)) != GOOD))
	 return(err);
   }
   if (LineNumLoaded) {
      if ((err=SymAddLinenumEnd()) != GOOD) /**Hera 10/17/96 &&
   	  (err2=LdrWarning(err, NULL, NULL, NULL)) != GOOD)**/
	 return(err);
   }
   PlmModuleEnd();
   return(err);
}  /* LoadModuleEnd */

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