/****************************************************************************
**
**  Name:  LDEBUG.C
**
**  Description:
**      Process debug records in IEEE 695 binary file.  Load them into the
**      Symbol Table via the Symbol Server.
**
**  Status:  CODED
**
**  $Log:   S:/tbird/mt2_68k/l695/ldebug.c_v  $
** 
**    Rev 1.4   04 Dec 1997 11:04:26   hera
** Fix ProcessDbgPart for MRI4.5 or later
** 
**    Rev 1.3   04 Dec 1997 10:29:38   gene
** process long string.
** 
**    Rev 1.2   21 Aug 1997 13:56:40   gene
** Modify ProcessATN62() and ProcessdbgLocals() to handle variable micellaneous
** type 80 (for c++).
** 
**    Rev 1.1   21 Aug 1997 13:50:14   gene
** 
**    Rev 1.0   13 Feb 1997 08:50:48   gene
** Initial revision.
** 
**    Rev 1.6   26 Nov 1996 09:03:22   kevin
** Hera modified
** 
**    Rev 1.5   01 Oct 1996 13:35:18   kevin
** Hera's fix
** 
**    Rev 1.4   12 Sep 1996 11:41:08   kevin
** support SDS Ver.6.35
** 
**    Rev 1.3   09 Sep 1996 09:47:18   kevin
** Hera's modification
** 
**    Rev 1.1   23 Jul 1996 16:10:28   Judy
** To support MRI ASM file
** 
**    Rev 1.0   10 Jul 1996 15:30:40   Judy
** Initial revision.
** 
**    Rev 1.0   07 Sep 1995 10:32:08   gene
** Initial revision.
** 
**    Rev 1.60   30 Mar 1994 12:35:00   john
** Added changes for 360
** 
**    Rev 1.59   29 Mar 1994 15:16:30   nghia
** Fixed bug in interpreting ATN9 - living register.
** - Call LResetRegs() to reset all variables used the specified register to
** DEAD state.
** - If the DEAD ATN9 is not completed - missed [x2] - just ignore.
** 
**    Rev 1.58   03 Mar 1994 15:25:38   nghia
** Fixed Bug: Introl compiler violated 695 - BB10 without a BB11 caused the
** loader to skip over the rest of the debug information.  Added check for
** the end of the debug section before exit debug processing. If not at
** the end, continue to process the next block.
** 
**    Rev 1.57   01 Mar 1994 09:03:36   nghia
** Fixed bug in PV2.1: load Cooper Power loadfile (Introl), BB4 does not have
** block size.  Detect and force on-demand to load all local for the BB4.
** Revised reports "Attribute type not handle" to report each type only once per
** module.  
** Revised GetBlockEndAddress to report correct error code. - If error occurs,
** use start_address+1 for the end address - handle Introl tool.
** 
**    Rev 1.56   18 Jan 1994 17:03:46   nghia
** Revised ldrMangle to have the correct global state.
** Removed backup recovery for ProcessDbgFunctions().
** 
**    Rev 1.55   01 Oct 1993 09:19:20   nghia
** Revised error condition processing to reset to previous block.
** 
**    Rev 1.54   30 Sep 1993 14:48:16   nghia
** Revised to support error recovery with blockSize == 0.
** When blockSize == 0, onDemand = FALSE, scan all ASM blocks.
** Removed PBEFunction() - wasteful call.
** 
**    Rev 1.53   23 Sep 1993 17:30:22   nghia
** Fixed BUGS:
** 1. Process ATN19 incorrectly.
** 2. Load BB3 without BB5.
** 3. Process Enum type without element and only one ASN record, not multiple.
** 4. Skip over BB10 that have same name as the previously loaded BB3.
** 5. Added support to create forward reference type.
** 6. Sierra generate invalid type index value for UNION type - avoid.
** 7. Processing ATN16 and throw away. 
** 8. Do error recovery at block level - all BB block.
** 9. Do error recovery for extracting end address of function block.
** 10. Added LOAD_ASM() to decode the new load option from dialog box.
** 11. Resynch to the next NN record when error occurred.
** 
**    Rev 1.52   30 Aug 1993 11:08:36   ron
** Changes for Load Progress dialog
** 
**    Rev 1.51   23 Aug 1993 11:20:30   nghia
** Fixed bugs to support optimized code.
** 1. ProcessDbgFunctions() process nested block incorrectly.
** 2. Removed the hack of Seek back and forth to look up block signature. Fixed
**    the Seek695File() to return the correct file position.
** 3. Added error recovery for all block processing to continue loading the next
**    block when there is an error occurred while loading a block.
** 5. Revised ProcessDbgLines() to return the next block position to continue
**    loading.
** 4. Removed all ALT_LANG stuff, since to support a new language, the loader 
**    will need to be changed quite a bit, not just a few parameters passing.
** 6. The loader now will continue process modules with error recovery for each
**    symbol block.  Finally, PLEASE BE CAREFUL ABOUT MAKING CHANGES FOR THE 
**    LOADER.  THE NEW CHANGE MUST BE TESTED WITH ALL TOOL CHAINS.
** 
**    Rev 1.50   10 Aug 1993 11:08:40   courtney
** Proper initialization of function name for ondemand load 'open'
** call was not being done - fixed.
** 
**    Rev 1.49   06 Aug 1993 15:12:36   courtney
** Uninitialized pointer being passed to symbol table caused UAE when
** mangling kept on for non-MRI toolchain - fixed (surfaced as result
** of new mangle/demangle default - see comment in ldr.c 1.84.1).
** 
**    Rev 1.48   03 Aug 1993 17:35:20   nghia
** Removed LERR_xxxx to use standard error codes.
** - Revised some checkAbort() code.
** 
**    Rev 1.47   27 Jul 1993 15:11:24   courtney
** Temporary workaround for Cosmic, which generates global ATN8's within
** local function scope (not permitted by 695 spec).  They get loaded
** as statics without error.  User code which contains variables declared
** with @far will cause these records to be generated.
** 
**    Rev 1.46   15 Jul 1993 18:25:04   steve
** Changed abortFromEsc to BOOLEAN.
** 
**    Rev 1.45   14 Jul 1993 11:58:48   nghia
** Fix bug in ondemand loading:
** revised ProcessDbgModule() and added ProcessDbgModuleOndemand().
** clean up some compiler warning.
** 
**    Rev 1.44   13 Jul 1993 15:13:16   courtney
** (merge 1.31.1.8 comment)
** New algorithm in ProcessDbgFunctions to detect end-function address
** for initial ondemand load (previous algorithm failed on Sagem loadfile
** case) - see inline code notes for details.  New algorithm backtracks;
** also forces sync after processing.
** 
**    Rev 1.43   13 Jul 1993 15:02:18   courtney
** Added support for loading assembly modules (BB10), controlled by
** ldrAsm flag (default => load them).  
** 
**    Rev 1.42   29 Jun 1993 11:45:12   courtney
** Added new pmisc type 57 (to ATN62 processing).  As found in Intermec
** loadfile (Unix cfront-generated file).
** 
**    Rev 1.41   28 Jun 1993 17:01:20   nghia
** Changed cpu_rindex -> regId. 
** This was missed when release 1.5 merged to trunk.
** 
**    Rev 1.40   28 Jun 1993 11:36:24   mindy
** Merged release 1.5 to trunk.
** 
**    Rev 1.39   25 Jun 1993 15:01:42   paul
** replace CHECK_ABORT macro with TskCheckAbort
** This requires use of new PVTASK.DLL because we have
** new imports.
** 
** 
**    Rev 1.38   14 Jun 1993 11:24:10   nghia
** Merged "pv bmwa" and Ernie changes.
** 
** 
**    Rev 1.37   09 Jun 1993 15:04:48   courtney
** Multiple 'this' pointers were getting stored, all as '__0__Xthis'; fixed
** to preserve full mangled name for duplicate 'this' instances in a function.
** 
**    Rev 1.36   08 Jun 1993 14:00:04   courtney
** Restore code to capture nrecs for even unrecognized ATN62 procedure
** misc records.  This keeps the system open to new toolchain files, while
** issuing a warning for codes we don't necessarily know the exact format for.
** 
**    Rev 1.35   06 Jun 1993 21:59:54   courtney
** Removed calls to ErrExit.
** 
**    Rev 1.34   06 Jun 1993 21:17:42   courtney
** C++ support: Demangle function names before storing to symbol table
** (clear duplicate list before for each module - Loader detects dups);
** lseek before peek; demangle globals before storing to ST; kick out
** BB6 XRAY procedure block; support mangle option too (default is nomangle);
** demangle local symbols before loading to ST; filter duplicate 'this'
** instances; enhance ATN62 processing to handle pmisc 80's that can appear
** *outside* XRAY information block: reference arg lists ('B'), compiler-
** generated member functions ('M').
** 
**    Rev 1.33   25 May 1993 10:35:28   ernie
** Virtualized _llseek() calls in Seek695File when file buffering added.
** 
**    Rev 1.32   03 May 1993 15:24:30   nghia
** Merged Mindy's code to support COSMIC.
** Added check to report warning that a module does not have line number info.
** 
**    Rev 1.31.1.5   08 Jun 1993 14:08:20   courtney
** RELEASE PV 1.4
** Restore code to capture nrecs for even unrecognized ATN62's.  This
** way, the Loader remains open-minded with respect to attributes from
** new toolchains, while issuing a warning.
** 
**    Rev 1.31.1.4   07 Jun 1993 11:59:50   courtney
** Revisions for 1.4 release.
** 
**    Rev 1.31.1.3   03 Jun 1993 18:42:20   nghia
** Revised to use all new error code.
** Reported error thru Warning() and WarningEx() only.
** Cleanup compiler warnings.
** 
**    Rev 1.31.1.2   26 May 1993 16:17:58   nghia
** Revised ProcessDbgGlobal() to handle ATN2 - global reg variable.
** Revised ProcessDbgFunctions() to handle BB4 that has ATN9 without NN.
** Revised ProcessDbgLocals() to report attribute type not supported.
** Fixed bugs for Allmos - BMW.
** 
**    Rev 1.31.1.1   19 May 1993 18:05:12   nghia
** Rev 1.31.1.0 is rev 1.32
** Revised ProcessDbgGlobal() to handle ATN16 - C's #define constant 
** (generated by MRI 4.3d) - Suppressed warning for ATN16.
** Also, resynch to the next NN when the loader encounter an unsupported ATN.
** 
**    Rev 1.31.1.0   18 May 1993 14:08:42   nghia
** No change.
**
**    Rev 1.31   21 Apr 1993 15:34:28   nghia
** Fixed bug - Failed to process Compiler ID record for unix compiled loadfile.
** 
**    Rev 1.30   20 Apr 1993 12:32:22   courtney
** ProcessDbgFunctions() - Skip over C++ debug information for now (don't
** load locals for procedure block __XRYCPP - its all contained here
** (pmisc 80 records)).
** Cleanup SyncTo calls to preserve information.
** 
**    Rev 1.29   12 Apr 1993 18:06:50   nghia
** Revised to use the new ProcessATN, and Get695SReccord().
** Used FindBaseCode and FindBaseData for map symbol's section.
** 
**    Rev 1.28   31 Mar 1993 17:53:18   nghia
** Fixed bug: loader failed to process BB5 timestamp information.
**    - Create Ford.tst to test this condition.
** Cleanup for coding standard.
** 
**    Rev 1.27   23 Mar 1993 17:19:16   nghia
** Updated to use the new MatchRecord and Match2Record.
** Revised all routines to return RETCODE.
** Minor cleanup.
** 
**    Rev 1.26   19 Mar 1993 11:36:10   courtney
** Allow ATN8 (definition) to precede ATN5 (extern) in loadfile, without
** generating error.  Loader silently consumes error, and processing of
** publics will fixup address.
** 
**    Rev 1.25   17 Mar 1993 14:07:12   nghia
** Fixed bug: Loading BLOCK3.ABS for Sierra.
** ProcessDbgFunction() does not handle BB6 block if no NN record present.
** Revised and added comments block.
** 
**    Rev 1.24   08 Mar 1993 10:28:40   nghia
** Added check to process 2 extra fields generated by Sierra.
** NOTES: ATN record has extra [n3] and [n4]
** Major cleanup names and comments.
** 
**    Rev 1.23   02 Mar 1993 14:23:54   nghia
** Cleanup and revise to meet Coding standard.
** 
**    Rev 1.22   03 Dec 1992 17:23:00   courtney
** . Remove 'no module' error popup, since returned to source presenter;
** . When processing BE marker for end-function, low addresses (<127
** hence in number not offset format) are now accepted (save last seen
** and restore if necessary).
** 
**    Rev 1.21   04 Nov 1992 17:55:00   courtney
** Error return from ProcessLines - check; ATN62 pmisc records: always
** eat extra byte except type 77 (not just type 51 as inadvertantly
** changed when type 77 was supported).
** 
**    Rev 1.20   27 Oct 1992 14:14:16   courtney
** Display error *once* if ATN9 (optimized code) is detected on symbol load.
** 
**    Rev 1.19   21 Oct 1992 16:33:46   courtney
** Cleaned up error reporting to use string resource.
** 
**    Rev 1.18   15 Oct 1992 16:56:38   courtney
** Added parm to SymAddModuleClose to differentiate the ondemand
** case (module only load).
** 
**    Rev 1.17   07 Oct 1992 18:53:42   courtney
** Fix: end-function address search is more precise - does not get
** confused when addresses look like BE markers; ATN62 type 77
** handling (optimized code - an undocumented type!).
** 
**    Rev 1.16   25 Sep 1992 20:56:26   courtney
** Minor revisions.
** 
**    Rev 1.15   14 Aug 1992 10:07:02   courtney
** Check all retcodes from server calls.
** 
**    Rev 1.14   31 Jul 1992 19:17:08   courtney
** Handle 332.
** 
**    Rev 1.13   22 Jun 1992 15:41:10   courtney
** Stubbed out altlang support till it can be tested.
** 
**    Rev 1.12   01 Jun 1992 20:15:08   courtney
** Added altlang support; abort checking (PPR's 5397, 5344).  Non-C
** modules can be force loaded (sync on NN record type).
** 
**    Rev 1.11   07 May 1992 16:10:18   courtney
** Keep count of number of modules loaded (PPR #5657 for status).
** 
**    Rev 1.10   23 Apr 1992 17:03:46   courtney
** Globals and functions can now be interspersed (they are not
** always at the start of a module).  Fixes PPR #5534.
** 
**    Rev 1.9   20 Apr 1992 17:10:32   courtney
** Support static locals (ATN3, local).
** 
**    Rev 1.8   15 Apr 1992 14:26:14   courtney
** Added comments, FAR modifier to rtable declaration (for PPR #5512).
** 
**    Rev 1.7   14 Apr 1992 12:41:44   courtney
** Handle nested line number blocks (BB5) by skipping over (the rest
** of the language components need to reflect handling - future issue).
** This fixes PPR # 5353.
** 
**    Rev 1.6   02 Apr 1992 17:24:18   courtney
** Create symbols in nested blocks, and nested blocks within nested
** blocks.
** 
**    Rev 1.5   17 Feb 1992 16:33:04   courtney
** Cleanup - removed ifdef brackets
** 
**    Rev 1.4   27 Jan 1992 15:52:10   courtney
** Register index type is now unsigned for Sym calls.
** 
**    Rev 1.3   15 Jan 1992 10:31:12   courtney
** Added support for register translation: 695 -> TBird.
** 
**    Rev 1.2   09 Jan 1992 17:00:02   courtney
** Passes timestamp of loadfile to modules on creation.  Module reference
** parameter removed from ModuleCreate call.
** Process nested blocks.
** Added stubs for register translation - not yet fully implemented.
** ATN9 code ativated and fixed (_LSaveVar, _LActivate)
** 
**    Rev 1.1   31 Dec 1991 10:55:38   courtney
** Numerous changes to fully support ondemand loading, as well as loader
** 'flags', to support code-only or symbol-only loading.
** Added register translation for other servers, which translates register
** indices from 695 to a common register index enumeration (as defined by
** the CPU Server).
** 
**    Rev 1.0   12 Dec 1991 13:44:42   courtney
** Initial revision.
**
**  $Header:   S:/tbird/mt2_68k/l695/ldebug.c_v   1.4   04 Dec 1997 11:04:26   hera  $
**
**  Copyright (C) 1991-1993 Microtek International.  All rights reserved.
**
*****************************************************************************/

                       /****************************
                        *                          *
                        *       INCLUDE FILES      *
                        *                          *
                        ****************************/
#include <limits.h>
#include <io.h>

#ifndef _PROC_
#include "proc.h"
#endif

#ifndef _PVTASK_
#include "pvtask.h"
#endif

#ifndef _SYMBLSVR_
#include "symblsvr.h"
#endif

#ifndef _SYMERROR_
#include "symerror.h"
#endif

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

#ifndef __LDR__
#include "ldr.h"
#endif

#ifndef __LFLAGS__
#include "lflags.h"
#endif
#ifndef __ERR__
#include "err.h"
#endif
#ifndef __LDEBUG__
#include "ldebug.h"
#endif
#ifndef __LOPT__
#include "lopt.h"
#endif
#ifndef __LPROFILE__
#include "lprofile.h"
#endif
#ifndef __LMANGLE__
#include "lmangle.h"
#endif

#ifndef _CLIULIB_
#include "cliulib.h"
#endif
                       /****************************
                        *                          *
                        *     LOCAL DEFINITIONS    *
                        *                          *
                        ****************************/
/* Number of modules loaded */
U32 numberOfModulesLoaded;
                       /****************************
                        *                          *
                        *    EXTERNAL VARIABLES    *
                        *                          *
                        ****************************/
extern U16 toolSelect;          /* Diab Data <Judy 5/29/96> */
extern U16 curbyte;
extern HDR695 Hdr695;
extern SEC_INFO *section_info[MAX_SECTIONS];
extern HDR695 Hdr695;
extern CHAR errbuf[];
extern U16 FAR *rtable;
extern BOOLEAN atn9_processed;
extern U16 ldrDemangle;
extern U32 ldrFlags;           /* global load options flag */
extern LDRSTATBLOCK FAR *lstb; /* progress reporting status block */
extern U32 startRangeNotSet, endRangeNotSet;
extern U32 endDebugPart;      // defined in LRECORD.C

//**Hera 08/27/96**/
extern U16 toolSelect;
extern BOOLEAN MRI45;
//**Hera
//Hera 12/4/97
U32 typeBasis;
                       /****************************
                        *                          *
                        *     LOCAL PROTOTYPES     *
                        *                          *
                        ****************************/
RETCODE PRIVATE isValidAddr(LPU8 pBuffer, U16 len, U32 *pAddr);
RETCODE PRIVATE getBlockEndAddress(HANDLE hfile, U32 blockEndPos,
                                   U32 fnStartOffset, U32 *fnEndOffset);

                       /****************************
                        *                          *
                        *      EXECUTABLE CODE     *
                        *                          *
                        ****************************/
/******************************************************************************
**
** ProcessDebugPart
**
** oflag - MCREATE or MOPEN
**   MCREATE is passed when this is the main loader invocation.  This will
**   create initial symbol table entries for modules and functions.
**   MOPEN is passed when we are loading strictly locals
** lflags - tells what to load (e.g., globals, locals - defined in lflags.h)
** ptrTimeStamp - pointer to timestamp to mark all modules
**       (loadfile timestamp is what we have)
** ptrNumModules - Number of processed modules.
**
******************************************************************************/
RETCODE ProcessDebugPart(HANDLE hfile, BOOLEAN oflag, U16 lflags,
                         TIMESTAMP_TYPE *ptrTimeStamp, U32 *ptrNumModules) {
   BOOLEAN abortFromEsc, createAsm;
   BOOLEAN ondemand, updateModuleRange;
   CHAR blockName[IEEE_IDNLEN], highLevelBlockName[IEEE_IDNLEN] = "";
   RETCODE err = GOOD;
   SYM_DESCRIPTOR moduleDesc = 0L;
   U16 blockType;
   U32 blockPos = 0L, blockSize, nextBlockPos = 0L;
   U32 typeOffset = 0L;

   //**HERA 04/14/96

   U16 type;
   LPSTR TempPtr;

   //**HERA

   numberOfModulesLoaded = 0L;
   LClearRegs();     /* initialize ATN9 record keeping stuff */
   /* Check if there is a debug part */
   if (!Hdr695.hdr_dbg) return GOOD;
   
   /* First, seek to Debug Part of file */
   if (Seek695File(hfile, Hdr695.hdr_dbg, SEEK_SET) == -1L)
      return (ER_BAD_SEEK);

   /* Main block-processing loop for loading symbols */
   while (1) {
      /* Need this in case we need to seek here later for ondemandloading  */
      blockPos = Seek695File(hfile, 0L, SEEK_CUR);
      if (MatchRecord(hfile, RT_BB) == GOOD) {
	 Get695BB(hfile, &blockSize, (LPSTR)blockName, &blockType);

	 //**HERA 08/14/96

	 StripPathString(blockName,&TempPtr);
	 lstrcpy(blockName,TempPtr);

	 //**HERA

         /* NOTES: Nghia - 08/18/93
         ** Calculate the end of the current block to be use for the start
         ** the next block.
         */
         if (blockSize > 0)
            nextBlockPos = blockPos + blockSize;
         else 
            /* Force to load everything */
            lflags = (L695_GLOBALS | L695_LOCALS);

      } else {
         // NOTES: 03/03/94 - Nghia
         // Make sure that the <blockPos> is at the end of debug part
         // else scan to the next BB and continue processing
         // BUG: Introl compiler - BB10 does not have BB11, which cause
         // the block to be out of synch and exit, although the <blockPos>
         // has not reached the end of debug part.
         LONG dummyPos;
         if (endDebugPart && (blockPos < endDebugPart) &&
            ((err = SyncTo(hfile, RT_BB, &dummyPos)) == GOOD))
            continue; // scan BB block again
         
         /* Exit process debug part */
         Unget695Byte(hfile, curbyte);
         break;
      }

      switch (blockType) {
	 /**Hera 08/15/96*/

	 case BB_GLOBAL_TYPE: /*BB2*/
	      Peek695Byte(hfile,&type);
              if(type != RT_BE && toolSelect == MRI_TOOLCHAIN) {
		   MRI45 = TRUE;
                   typeBasis = 0;//Hera 12/4/97 for MRIv4.5 or later
              }
	      else
              {
	        if ((err = SkipOver(hfile, blockPos, blockSize,
				   blockType)) != GOOD) return(err);
                break;
	      }    
	 case BB_LOCAL_TYPE: /*BB1*/
              /* Capture type offset fix-up for all variables that follow*/ 
              if ((err = ProcessDbgTypes(hfile, (LPSTR)blockName, &typeOffset))
                                       != GOOD) {
                if (err == ER_SYM_OUT_OF_MEMORY) return err;
                Warning(err);
                /* Reset to the next block and continue processing*/ 
                if ((err = SkipOver(hfile, blockPos, blockSize,
				   blockType)) != GOOD) return(err);
	      }
	      break;

	 /**Hera**/

	 case BB_MODULE:         /* BB3 */

            moduleDesc = NULL_SYMBOL;
            updateModuleRange = FALSE;
            if ((err = ProcessDbgModule(hfile, (LPSTR)blockName, blockPos,
                   lflags, typeOffset, &moduleDesc, ptrTimeStamp)) != GOOD) {
               if (err != ER_SYM_NOT_UPDATED) {
                  // Reset to the next block and continue processing
                  Warning(err);
                  // Reset to the next block and continue processing
                  if ((err = SkipOver(hfile, blockPos, blockSize, blockType))
                      != GOOD) return(err);
               } else {
                  // set updateModuleRange to force the loader scanning
		  // the ASM block to update module range
                  updateModuleRange = TRUE;
               }
	    }
            /* Remember BB3 block name to skip over its BB10 */
            lstrcpy((LPSTR)highLevelBlockName, (LPSTR)blockName);
            ++numberOfModulesLoaded;

            /* even if ondemand is given, we still need to skip over */
            ondemand = (LOAD_LOCALS(lflags)) ? FALSE : TRUE;
            
            /* NOTES: Nghia - 08/19/93
            ** In case of error, ProcessDbgLines() will set the nextBlockPos
            ** to the input position or the new block to continue.
            ** This to handle both error recovery and a module does not have
            ** a BB5 block follow a BB3 block.
            */
            if ((err = ProcessDbgLines(hfile, ondemand, oflag,
                  &nextBlockPos, &blockSize, moduleDesc)) != GOOD) {
               /* Reset to the next block and continue processing */
	       if ((err = SkipOver(hfile, nextBlockPos, blockSize,
                                   blockType)) != GOOD)
                  return(err);
            }
            break;
            
         case BB_ASMBLOCK:      /* BB10 */
            /* Use the global flag defined in LDR.C */
            if (LOAD_ASM(ldrFlags) || !blockSize || updateModuleRange) { 
               // NOTES: 09/14/93 - Nghia
               // Only process BB10 that does not associate with a previously
               // processed BB3. - If name matched then they're the same.
               // Skip over to the next block. It's very wasteful to scan the
               // BB10 block that associates with a already loaded high level
               // block.
               // 09/29/93 - Nghia
	       // Process BB10 if blockSize is 0 to makesure file load OK.

	       createAsm = (BOOLEAN) lstrcmp((LPSTR) highLevelBlockName,
					(LPSTR) blockName);
	       if ((createAsm) || (!blockSize) || updateModuleRange)
	       {
		  
                  if (ProcessDbgAsmBlock(hfile, blockSize, (LPSTR) blockName,
                                         createAsm, moduleDesc) == GOOD) {
                     // Reset the block name for the next module
		     highLevelBlockName[0] = '\0';

                     //**Reset -- Hera 08/29/96**/
		     updateModuleRange = FALSE;
		     //**Hera**/

                     break; // out of switch 
                  }
               }
	    }

	    // Handle Error recovery
	    //**Reset -- Hera 08/29/96**/
	    updateModuleRange = FALSE;
	    //**Hera**/

            if ((err = SkipOver(hfile, blockPos, blockSize,
                                      blockType)) != GOOD)
	       return(err);
            break;
            
	 default:
            /* Skip to the next block */
            Warning(ER_UNRECOGNIZED_BLK);
            if ((err = SkipOver(hfile, blockPos, blockSize,
                                blockType)) != GOOD) return(err);
            break;
      } /* switch() */
            
      /* Check for user abort */
      if (((err = TskCheckAbort(&abortFromEsc)) != GOOD) || abortFromEsc) {
         LdrProgressDone(err != GOOD ? err : ER_LDR_ABORT);
         return (err != GOOD ? err : ER_LDR_ABORT);
      }
      if (lstb != NULL)
         lstb->curLocation = tell(hfile);
      if ((err = LdrProgressInc()) != GOOD) {
         LdrProgressDone(err);
         return (err);
      }

   } /* end of while */

endloop:
   /* Clear cache for successive Parts */
   Clear695Byte();
   *ptrNumModules = numberOfModulesLoaded;
   return(err);
   
}  /* ProcessDebugPart */


/*****************************************************************************
**
**  ProcessDbgTypes - BB1
**
** In general, we call the Symbol Table to add the type header information
** here; any member information (struct/union) or information particular
** to the type we are dealing with (arrays), we pass off to another routine,
** which adds the item to the Symbol Table.
**
** NOTES: 09/15/93 - Nghia
** All types that need the sizeInMAUs from its base type will defer the
** sizeInMAUs calculation until access time.  The symbol server will update
** the information on demand. The sizeCalculated flag of each type adding to
** the symbol table will be set to FALSE to defer the calculation.  
**
*****************************************************************************/
RETCODE ProcessDbgTypes(HANDLE hfile, LPSTR blockName, U32 *ptoffset) {
   TYPE_HEADER_TYPE typeHdrInfo;
   U16 cbyte, nindex, stype, ltype, typeErr = 0;
   U32 tindex, tmax, toffset, blockPos=0;  /* for type fix-up */
   RETCODE symerr, err;
   LONG filePos;

   /* get max type registered thus far, and use this to compute offset */
   if ((err = SymGetTypeIndexMax(&tmax)) != GOOD)
      return(err);
   if (tmax >= 0x100) {  /* then we have some user-defined types */
      toffset = tmax - 0x100 + 1; 
      *ptoffset = toffset;  /* will be used when variables are loaded */
   } else {
      toffset = *ptoffset = 0L;
   }

   /* Record NN/TY pair defined symbol type information */
   while (MatchRecord(hfile, RT_NN) == GOOD) {
      Get695Nrecord(hfile, &nindex, (LPSTR)blockName);
      if ((MatchRecord(hfile, RT_TY) != GOOD) ||
          (ProcessTY(hfile, &tindex, toffset, &nindex, &stype) != GOOD)) {
          /* If error occurred, SyncTo the next posible NN */
          /* added by <Judy 8/20/97> */
           while (1) {
              /* check for eof */
              if (Get695Byte(hfile, &cbyte) != GOOD)
                 return(ER_BADGET);
              if (cbyte == RT_NN) {
                 /* sync successful */
                 Unget695Byte(hfile, cbyte);
                 if ((filePos = Seek695File(hfile, 0L, SEEK_CUR)) == -1L)
                    return(ER_BAD_SEEK);
                 break;
              }
           }
          /* SyncTo(hfile, RT_NN, &filePos); <Judy 8/20/97> */
          /* Report error */
          WarningEx(ER_SYM_TYPE, blockName);
          continue; /* next type */
      }
      /* Construct general type header info */
      typeHdrInfo.typeChoice    = COMPLEX_TYPE_CLASS;
      typeHdrInfo.t.complexType = stype;
      typeHdrInfo.sizeInMAUs    = 0L;  /* default MAU size for all type */
      typeHdrInfo.typeName      = (LPSTR)blockName;  /* pointer assign */
      /* To handle (void *) type for Diab Data ToolChain <Judy 6/5/96> */
      blockPos = Seek695File(hfile, 0L, SEEK_CUR);
      if (toolSelect==DIAB_DATA_TOOLCHAIN && stype==T695_LARGE_PTR) {
         Peek695Byte(hfile, &ltype);
         if (ltype ==1) {
            Get695Byte(hfile, &ltype);
            typeHdrInfo.sizeInMAUs = 1L;  /* default MAU size for all type */
            stype=T695_VOID;
         }
      }
      /* Symbol type - see Appx A */
      switch (stype) {
         /* UNKNOWN : $21 - ! */
         case T695_UNKNOWN: 
            typeHdrInfo.sizeCalculated = TRUE;
            if ((symerr = SymAddTypeHeader(tindex, &typeHdrInfo)) != GOOD) {
               err = ER_SYM_TYPE;
            }
            break;
         /* SMALL : $4F - O & LARGE PTR : $50 - P */
         case T695_SMALL_PTR: 
         case T695_LARGE_PTR: 
            /* ok for both 332 and 680x0 */
            if ((Hdr695.hdr_cpu == PROC_CPU_CPU32) ||
                  (Hdr695.hdr_cpu == PROC_CPU_68000) ||
                  (Hdr695.hdr_cpu == PROC_CPU_CPU16) ||
                  (Hdr695.hdr_cpu == PROC_CPU_CPU32P)) {
               if (stype == T695_SMALL_PTR)
                  typeHdrInfo.sizeInMAUs = SZ_SMPTR68K;
               else if (stype == T695_LARGE_PTR)
                  typeHdrInfo.sizeInMAUs = SZ_LGPTR68K;
            } else {
               Warning(ER_NOT_CPU);
            }
            typeHdrInfo.sizeCalculated = TRUE;
            if ((symerr = SymAddTypeHeader(tindex, &typeHdrInfo)) != GOOD) {
               err = ER_SYM_TYPE;
               break;
            }
            /* NOTES:
            ** even some of these *look* to us like built-in types
            ** (like, pointer to int), if they are defined here and
            ** given a new type index, we'd better capture them, because
            ** subsequent symbol declarations will probably use these.
            */
            err = GetTypePtr(hfile, tindex, stype, toffset);
            break;

         /* TYPEDEF : $54 - T */
         case T695_TYPEDEF: 
            /* NOTES: 09/15/93 - Nghia
            ** Defer sizeInMAUs calculation to access time
            */
            typeHdrInfo.sizeCalculated = FALSE; 
            err = GetTypeTypedef(hfile, tindex, &typeHdrInfo, toffset);
            break;

         /* VOID : $3F */
         case T695_GVOID: /* undocumented by 695; used by Green Hills <Judy 5/21/96> */
            typeHdrInfo.t.complexType = T695_VOID;
         /* VOID : $56 - V */
         case T695_VOID:  /* undocumented by 695; used by MRI C */
            typeHdrInfo.sizeCalculated = TRUE;
            if ((symerr = SymAddTypeHeader(tindex, &typeHdrInfo)) != GOOD) {
               err = ER_SYM_TYPE;
               break;
            }
            err = MapTypeVoid(tindex);
            break;
         /* STRUCT : $53 - S & UNION : $55 - U */
         case T695_STRUCT:
         case T695_UNION:
            Get695Offset(hfile, &typeHdrInfo.sizeInMAUs);
            typeHdrInfo.sizeCalculated = TRUE;
            if ((symerr = SymAddTypeHeader(tindex, &typeHdrInfo)) != GOOD) {
               err = ER_SYM_TYPE;
               break;
            }
            /* possible undefined struct (because of pointer to it) */
            if (typeHdrInfo.sizeInMAUs != 0L)
               err = GetTypeSU(hfile, tindex, stype, toffset);
            break;

         /* ENUM : $4E - N */
         case T695_ENUM:
            /* check for size of packed enums (supported by MRI) */
            /* default size for enum members is sizeof(int).  Note
            ** that MRI treats as signed/unsigned depending on values
            ** found in enumeration - we don't care, always unsigned.
            */
            typeHdrInfo.sizeInMAUs = SZ_STACKPUSH_68K;
            Peek695Byte(hfile, &cbyte);
            if ((cbyte & 0xff) == 0) {
               Get695Byte(hfile, &cbyte);
               /* size byte follows */
               Get695Number(hfile, &cbyte);
               typeHdrInfo.sizeInMAUs = cbyte;
            }
            
            typeHdrInfo.sizeCalculated = TRUE;
            if ((symerr = SymAddTypeHeader(tindex, &typeHdrInfo)) != GOOD) {
               err = ER_SYM_TYPE;
               break;
            }
            err = GetTypeEnum(hfile, tindex);
            break;

         /* PROCEDURE {with compiler dependencies} : $58 - x <Judy 5/8/96>*/
         case T695_PROC_SIMPLE:
         /* PROCEDURE {with compiler dependencies} : $78 - x */
         case T695_PROC:
            /* Size of procedure type is 0 and calculated */
            typeHdrInfo.sizeCalculated = TRUE;
            /* Note: don't need to demangle function names as type entries
            ** (they will get demangled when stored inside the BB3 module).
            */
            if ((symerr = SymAddTypeHeader(tindex, &typeHdrInfo)) != GOOD) {
               err = ER_SYM_TYPE;
            }
            // <Judy 5/8/96>
            if (stype ==T695_PROC_SIMPLE)
               err = GetTypeProcSimple(hfile, tindex, toffset);
            else
               err = GetTypeProc(hfile, tindex, toffset);
            break;

         /* ARRAY : $5A - Z */
         case T695_ARRAY:
            /* NOTES: Defer sizeInMAUs calculation until access time */
            typeHdrInfo.sizeCalculated = FALSE;
            err = GetTypeArr(hfile, tindex, toffset, &typeHdrInfo);
            break;

         /* BITFIELD : $47 - G */
         case T695_BITFIELD:
            /* NOTES: Defer sizeInMAUs calculation until access time */
            typeHdrInfo.sizeCalculated = FALSE;
            err = GetTypeBit(hfile, tindex, &typeHdrInfo);
            break;
         default:
            // 02/24/94 - Nghia
            // Collect all TY types that are not handle and report only
            // once, or when another new TY type is occurred.
            if (typeErr && (typeErr != stype)) {
               /* Display warning on TY record not handle */
               wsprintf(errbuf, "%d.", typeErr);
               WarningEx(ER_ATTR_NOT_HANDLED, errbuf);
            }
            // record the type error
            typeErr = stype;
            /* Sync to the next possible NN record */
            if ((err = SyncTo(hfile, RT_NN, &filePos)) != GOOD)
               return(err);
            continue;
      } /* switch() */
      /* If error occurred, SyncTo the next posible NN and report error */
      if (err != GOOD) {
         SyncTo(hfile, RT_NN, &filePos);
         WarningEx(err, blockName);
         err = GOOD;
      }
   }  /* while NN */
   // 02/24/94 - Nghia
   // report the last type not handle
   if (typeErr) {
      /* Display warning on TY record not handle */
      wsprintf(errbuf, "%d.", typeErr);
      WarningEx(ER_ATTR_NOT_HANDLED, errbuf);
   }

   Unget695Byte(hfile, curbyte);
   /* close block */
   return(MatchRecord(hfile, RT_BE));
}  /* ProcessDbgTypes */

/*****************************************************************************
**
**  ProcessDbgModuleOnDemand - BB3
**
*****************************************************************************/
RETCODE ProcessDbgModuleOnDemand(HANDLE hfile, U16 lflags, U32 typeOffset) {
   CHAR blockName[IEEE_IDNLEN];
   OFFSET_ADDR_RANGE_TYPE dummyModRange;
   U16 blockType, cbyte;
   U32 blockPos, blockSize;
   RETCODE symerr, err;
   BOOLEAN localflag;

   /* set state to boolean result, will be passed to ModuleClose */
   localflag = (LOAD_LOCALS(lflags) ? TRUE : FALSE);

   /* Clear function list before loading (for C++ duplicate detection) */
   CppClearFunctionTable();
   while (1) {
      /* save current file offset in case we are ondemand, code moved
         to *before* peek, since peek advances the file position */
      blockPos = Seek695File(hfile, 0L, SEEK_CUR);
      Peek695Byte(hfile, &cbyte);
      if (cbyte != RT_NN && cbyte != RT_BB)
         break;
      /* Process globals */
      if (cbyte == RT_NN) {
         if (LOAD_GLOBALS(lflags))
	    err = ProcessDbgGlobals(hfile, typeOffset, TRUE);
         else  /* module-only load, just process */
	    err = ProcessDbgGlobals(hfile, typeOffset, FALSE);
         continue;
      }
      /* Process function blocks */
      if (cbyte == RT_BB) {
         MatchRecord(hfile, RT_BB);
         Peek695Byte(hfile, &cbyte);
         /* NOTES: Nghia - 08/17/93 - Page 31 IEEE695 Spec.
         ** A BB3 must have at least one BB4, BB4 can have BB6s nested but not
         ** BB4, and a BB6 can have another BB6 nested, but not a BB4.
         */
         if (IS_BBFUNCTION(cbyte)) {
            /* Get BB signature */
            Get695BB(hfile, &blockSize, blockName, &blockType);
            /* Process BB4/BB6 functions (nesting BB6) - MOPEN for OnDemand */
            if ((err = ProcessDbgFunctions(hfile, blockType, blockPos,
                                           blockSize, blockName,
                                           &dummyModRange, typeOffset,
                                           MOPEN, lflags)) != GOOD) {
               // 02/24/94 - Nghia
               // close module in case of function block error
               SymAddModuleClose(localflag);
               return(err);
            }
         } else 
            Unget695Byte(hfile, curbyte);  /* unget BB */
      }
   }  /* while globals/functions */
   if ((symerr = SymAddModuleClose(localflag)) != GOOD) {
      Warning(symerr);
   }

   /* Close BB3 block - module scope */
   return(MatchRecord(hfile, RT_BE));
}  /* ProcessDbgModuleOnDemand */

/*****************************************************************************
**
**  ProcessDbgModule - BB3
**
*****************************************************************************/
RETCODE ProcessDbgModule(HANDLE hfile, LPSTR moduleName, U32 moduleOffset,
                         U16 lflags, U32 typeOffset,SYM_DESCRIPTOR *moduleDesc,
                         TIMESTAMP_TYPE *ptrTimeStamp) {
   BASE_INDEX baseIndex;
   BOOLEAN ondemand, localflag;
   CHAR blockName[IEEE_IDNLEN], mref[1] = "";  /* for the Symbol Table */
   OFFSET_ADDR_RANGE_TYPE modRange;
   QUAL_ADDR_RANGE_TYPE modAddr;
   RETCODE symerr, err;
   U16 blockType, cbyte;
   U32 blockPos, blockSize;

   /* Range will get set with successive functions */
   modRange.offsetStartAddr = startRangeNotSet;
   modRange.offsetEndAddr = endRangeNotSet;
   /* Get the default code index from section_info table */
   if ((err = FindBaseCodeIndex(&baseIndex)) != GOOD)
      Warning(err);
   /* If we want to create module, and load locals, then ondemand false */
   ondemand = LOAD_LOCALS(lflags) ? FALSE : TRUE;
   /* NOTES:
   ** Enter module symbol into Symbol Table
   ** Get back module descriptor to load other debug info
   ** Strip off path include in the moduleName
    */

   if ((symerr = SymAddModuleCreate(moduleName, baseIndex, ptrTimeStamp,
                                    &modRange, moduleOffset, ondemand,
                                    typeOffset, moduleDesc)) != GOOD) {
      WarningEx(ER_CANNOT_ADD_MOD, moduleName);
      /* Non-fatal to load process, but can't continue with module */
      return(ER_CANNOT_ADD_MOD);
   }

   /*
   ** Loading just an individual module will propagate thru this code,
   ** don't load globals, don't load functions, just the locals inside them.
   ** Loading for the first time also needs to know - all or just globals.
   ** Also, loop over globals/functions (can be interspersed)
   */

   /* set state to boolean result, will be passed to ModuleClose */
   localflag = (LOAD_LOCALS(lflags) ? TRUE : FALSE);

   /* Clear function list before loading (for C++ duplicate detection) */
   CppClearFunctionTable();

   while (1) {
      /* save current file offset in case we are ondemand, code moved
         to *before* peek, since peek advances the file position */
      blockPos = Seek695File(hfile, 0L, SEEK_CUR);
      Peek695Byte(hfile, &cbyte);
      if (cbyte != RT_NN && cbyte != RT_BB)
         break;
      /* Process globals */
      if (cbyte == RT_NN) {
         if (LOAD_GLOBALS(lflags))
	    err = ProcessDbgGlobals(hfile, typeOffset, TRUE);
         else  /* module-only load, just process */
            err = ProcessDbgGlobals(hfile, typeOffset, FALSE);
	 continue;  // Processing
      }
      /* process functions */
      if (cbyte == RT_BB) {
         MatchRecord(hfile, RT_BB);
         Peek695Byte(hfile, &cbyte);
         /* NOTES: Nghia - 08/17/93 - Page 31 IEEE695 Spec.
         ** A BB3 must have at least one BB4, BB4 can have BB6s nested but not
         ** BB4, and a BB6 can have another BB6 nested, but not a BB4.
         */
         if (IS_BBFUNCTION(cbyte)) {
            /* Get BB signature */
            Get695BB(hfile, &blockSize, blockName, &blockType);
            if ((err = ProcessDbgFunctions(hfile, blockType, blockPos,
                                           blockSize, blockName,
                                           &modRange, typeOffset,
                                           MCREATE, lflags)) != GOOD) {
               // 02/24/94 - Nghia
               // close module in case of function block error
               SymAddModuleClose(localflag);
               return(err);
            }
         } else
            Unget695Byte(hfile, curbyte);  /* unget BB */
      }
   }  /* while process globals/functions */


   if ((symerr = SymAddModuleClose(localflag)) != GOOD) {
      Warning(symerr);
  }

   // NOTES: Nghia - 10/26/94
   // Revised to support MRI ASM module with line numbers
   /* Update module range info */
   if ((modRange.offsetStartAddr != startRangeNotSet) &&
       (modRange.offsetEndAddr != endRangeNotSet)) {  
      modAddr.startAddr  = modRange.offsetStartAddr;
      modAddr.endAddr    = modRange.offsetEndAddr;
      modAddr.startValid = modAddr.endValid = TRUE;
      // NOTES:
      // The Symbol Table is smart enough to figure out this is the
      // context we are adding info to (module).
      if ((symerr = SymAddSymbolSetAddr(&modAddr)) != GOOD)
         Warning(ER_SYM_NOT_UPDATED);
      // Close BB3 block - module scope
      return(MatchRecord(hfile, RT_BE));
   } else {
      // close the BB3 block and return ER_SYM_NOT_UPDATE to process
      // the assembly block for the module range
      return ((symerr = MatchRecord(hfile, RT_BE)) != GOOD) ? symerr
            : ER_SYM_NOT_UPDATED;
   }
}  /* ProcessDbgModule */

/*****************************************************************************
**
**  ProcessDbgGlobals
**
*****************************************************************************/
RETCODE ProcessDbgGlobals(HANDLE hfile, U32 typeOffset, BOOLEAN addsym) {
   BOOLEAN isConst;
   CHAR *pname, blockName[IEEE_IDNLEN], sname[IEEE_IDNLEN];
   LONG filePos;
   LOOP_VAR i;
   RETCODE symerr, err;
   SYM_DESCRIPTOR symP;
   U16 cbyte, nitems, atype;
   U16 nindex, atnType, sindex, reg_index, atnErr = 0;
   U32 lvalue, nvalue, tindex;
   VAR_STORAGE_CLASS varClass;

   /* Process all NN, ATN, ASN records */
   while (MatchRecord(hfile, RT_NN) == GOOD) {
      Get695Nrecord(hfile, &nindex, (LPSTR)sname);
      if ((Match2Record(hfile, RT_ATN) != GOOD) ||
         (ProcessATN(hfile, &nindex, &tindex, typeOffset, &atnType) != GOOD)) {
         /* NOTES - Nghia
         ** Resync to the next possible NN record
         */
         SyncTo(hfile, RT_NN, &filePos);
         continue;
      }
      /* Process ATN record according to its type */
      switch (atnType) {
         // Kludge to get Cosmic stuff to load!
         // to695 seems to be generating ATN_AUTO records at the wrong
         // level for supporting their #define.
         case ATN_AUTO:
            Get695Offset(hfile,&lvalue);
            break;
            
         /* The following ATN types are handled at this (global) level:
         ** ATN 3/4/5/8 - module misc 64 - global var register 2
         */
         case ATN_MOD_MISC:
            /* for now, just get these bytes */
            Get695Byte(hfile, &cbyte);    /* module type index */
            Get695Byte(hfile, &nitems);   /* nitems follow */
            /* NOTES: 04/21/94 - Nghia
            ** MRI generated an extra 1 byte (BUG) after nitems with their DOS
            ** compiler, However this byte does not exist in UNIX version.
            ** The Loader has to detect and handles it.
            */
            Get695Byte(hfile, &cbyte);    /* unused - MRI DOS compiler BUG */
            if ((cbyte == RP_SECTION) || (cbyte == RP_ATTR))
               Unget695Byte(hfile, cbyte);
            /* Process all ASN and ATN records */
            for (i = 0; i < nitems; i++) {
               Peek695Byte(hfile, &cbyte);
               if (cbyte == RP_SECTION) {
                  Match2Record(hfile, RT_ASN);
                  ProcessASN(hfile, &nindex, &nvalue);
               } else if (cbyte == RP_ATTR) {
                  Match2Record(hfile, RT_ATN);
                  ProcessATN(hfile, &nindex, &tindex, typeOffset, &atype);
                  if (atype != ATN_MISC_STR)
                     return (ER_ATN_EXPT);
		  Get695Idn(hfile, (LPSTR)blockName);

               } else  {
                  /* error record not handle */
                  Warning(ER_REC_NOT_HANDLED);
               }
            } /* for */
            break;

         /* Process static and global vars */
         case ATN_STATIC:  /* NN/ATN3/ASN or NN/ATN8/ASN */
         case ATN_GLOBAL:  /* ATN8 */
            /* Get symbol address */
            if ((Match2Record(hfile, RT_ASN) != GOOD) || 
               (ProcessASN(hfile, &nindex, &lvalue) != GOOD)) {
               SyncTo(hfile, RT_NN, &filePos);
               break;
            }
            /* Only demangle name if user said so */
	    if (ldrDemangle)
               CppFixupGlobal(sname, &pname);
            else
               pname = sname;
            
            if (addsym) {
               if (FindBaseIndex(lvalue, &sindex, &isConst) != GOOD) {
                  /* Try the default data section */
                  if ((err = FindBaseDataIndex(&sindex)) != GOOD) {
                     Warning(err);
                     break; /* Continue to the next variable */
                  }
                  isConst = FALSE;
               }
               if (atnType == ATN_STATIC)
                  varClass = STATIC_VAR_CLASS;
               else
                  varClass = GLOBAL_VAR_CLASS;
               symerr = SymAddVar((LPSTR)pname,
		  sindex,  /* section index */
                  tindex,
                  varClass,
                  NOT_REG,
                  (ADD_VAR_ADDR_UNION *)&lvalue,
                  isConst,
                  TRUE,  /* address is valid */
                  &symP);
               /* We allow duplicate name, since ATN5 may have preceded ATN8.
               ** It is ok if the symbol table kicks it out here, the address
               ** will be fixed up when the public for this symbol is added.
               */
	       if ((symerr != GOOD) && (symerr != ER_DUPLICATE_GLOBAL_NAME))
	       {
		 if (!pname)
                    pname = sname;  // restore the original name to report
		 WarningEx(ER_CANNOT_ADD_SYM, (LPSTR)pname);
               }
            }
            break;

	 /* Process extern vars - note there may be more than one of these
	 ** generated for a program (hence a duplicate is ok)
         */
         case ATN_EXTERN_VAR: /* NN/ATN5 only */
            /* Only demangle name if user said so */
            if (ldrDemangle) 
               CppFixupGlobal(sname, &pname);
            else
                pname = sname;
            
            if (addsym) {
               /* address and section index not known yet */
               if ((err = FindBaseDataIndex(&sindex)) != GOOD) {
                  Warning(err);
                  break;
               }
               lvalue = 0L;
               symerr = SymAddVar((LPSTR)pname,
                       sindex,  /* section index */
                       tindex,
                       GLOBAL_VAR_CLASS,
                       NOT_REG,
                       (ADD_VAR_ADDR_UNION *)&lvalue,
                       FALSE,  /* not const */
                       FALSE,  /* address is *not* valid */
		       &symP);
	       if (symerr != GOOD && symerr != ER_DUPLICATE_GLOBAL_NAME) {
		
                    if (!pname) pname = sname; // restore original name
		    WarningEx(ER_CANNOT_ADD_SYM, (LPSTR)pname);
      	       }
            }
            break;

         /* Extern functions (defined by 'x' type) */
         case ATN_EXTERN_FN:  /* NN/ATN4 only */
            break;
         case ATN_REGISTER:
         {
            VAR_LIVING_REG regId;
            Get695Number(hfile, &reg_index);
            if( Rxlate(reg_index,&regId) != GOOD )
               regId = reg_index;
            /* Insert symbol into the symbol table */
            if (FindBaseIndex(lvalue, &sindex, &isConst) != GOOD) {
               /* Try the default data section */
               if ((err = FindBaseDataIndex(&sindex)) != GOOD) {
                  Warning(err);
                  break; /* Continue to the next variable */
               }
            }
            if ((symerr = SymAddVar((LPSTR)sname,
                  sindex,
                  tindex,
                  GLOBAL_VAR_CLASS,
                  LIVING_REG,
                  (ADD_VAR_ADDR_UNION *)&regId,
                  FALSE,  /* not const */
                  TRUE,  /* valid address */
		  &symP)) != GOOD)
		   
		WarningEx(ER_CANNOT_ADD_SYM, (LPSTR)sname);

            /* NOTES: Usually there are ATN9 following ATN2 - ignore for now */
            /* Return err indicates cannot seek file: serious error */
            if ((err = SyncTo(hfile, RT_NN, &filePos)) != GOOD)
               return(err);
            break;
         }
         case ATN_DEFINE_CONST:
         {
            /* NOTES: MRI V4.3d generates ATN16 - C's #define constant */
            /* 09/20/93 - Nghia - Process ATN 16 */
            CHAR defName[IEEE_IDNLEN] = "";
            U32  constValue = 0L;
            ProcessATN16(hfile, &constValue, (LPSTR) defName);
            break;
         }
         default:
            // 02/24/94 - Nghia
            // Display warning on Unrecognized ATN  once
            if (atnErr && (atnErr != atnErr)) {
               wsprintf(errbuf, "%d.", atnErr);
               WarningEx(ER_ATTR_NOT_HANDLED, errbuf);
            }
            atnErr = atnType;
            /* Return err indicates cannot seek file: serious error */
            if ((err = SyncTo(hfile, RT_NN, &filePos)) != GOOD)
               return(err);
            break; /* Process the next NN record */
      }
   }  /* while RT_NN */
   // 02/24/94 - Nghia
   // Report Attribute type not support once
   if (atnErr) {
      wsprintf(errbuf, "%d.", atnErr);
      WarningEx(ER_ATTR_NOT_HANDLED, errbuf);
   }

   Unget695Byte(hfile, curbyte);
   return (GOOD);
}  /* ProcessDbgGlobals */

/*****************************************************************************
**
** ProcessDbgFunctions - BB4/BB6
**
** blockType  - function type (indicates global or static)
** blockPos   - file offset for BB record (in case we are skipping over locals)
** blockSize  - function block size
** fnname     - function name
** pmodRange  - pointer to module address range (gets updated here)
** typeOffset - type fix-up for all type indices
** oflag      - MCREATE or MOPEN (for function symbol)
** lflags     - what to load (globals, locals - see lflags.h)
**
*****************************************************************************/
RETCODE ProcessDbgFunctions(HANDLE hfile, U16 blockType, U32 blockPos,
                            U32 blockSize, LPSTR fnname,
                            OFFSET_ADDR_RANGE_TYPE *pmodRange,
                            U32 typeOffset, BOOLEAN oflag, U16 lflags) {
   BOOLEAN cppLoadfile;  
   CHAR *pname, blockName[IEEE_IDNLEN], pmangledName[IEEE_IDNLEN];  
   FUNC_CLASS fnClass;
   LONG filePos;
   OFFSET_ADDR_RANGE_TYPE fnAddr;
   QUAL_ADDR_RANGE_TYPE fnFinalAddr;
   RETCODE symerr, err;
   U16 cbyte, sindex;
   U32 endBlockPos = 0L;
   U32 fStartOffset, fEndOffset = 0L;
   U32 nstack, rtn_type;
   CHAR spcFg;                  // To add offset of end address of function
   U32 nStartOffset;            // for Diab Data toolchain <judy 5/30/96>

   /* Process Functions (global (BB4) and nested static (BB6) functions)
   ** Also called (recursively) for unnamed blocks in C {}.
   */
   /* Always calculate expected endBlockPos (end of function block), in case
   ** we need to resync. 
   */

   while (IS_BBFUNCTION(blockType)) {
      endBlockPos = blockPos + blockSize;
      PBBFunction(hfile, &nstack, &rtn_type, typeOffset, &fStartOffset);
      spcFg= (nstack==0) ? 4 : 10; /* <Judy 5/30/96> */
      /* function name demangling before symbol table insertion: for either
         initial creation or module-only load */
      /* save mangled name */
      strcpy(pmangledName, fnname);
      if (ldrDemangle) {
         if (((err = CppFixupFunction(fnname, &pname, oflag)) != GOOD) &&
               (err != ER_CPP_NOT_SUPPORTED))
            Warning(err); /* out of memory? */
      } else
         pname = fnname;  /* pointer assign */
      
      /* INITIAL LOADING - Create function on initial loading */
      if (oflag == MCREATE) { 
         /* NOTES: Although each function symbol might have its own section,
         ** call FindBaseIndex(fStartOffset, &sindex, &dummy) to map to
         ** its section, however, the symbol server will fail to lookup
         ** function symbols if the loader does the right thing
         ** (add function symbol to its base). All function symbols will
         ** be added to the default base. - Nghia
         */
         if ((err = FindBaseCodeIndex(&sindex)) != GOOD) {
            Warning(err);
            /* NOTES: Skip over this function block and resynch next BB 
            ** Failure to process function will result in ondemand callback
            ** to load local symbols to fail.
            ** SyncTo should only be used in very drastic cases..
            */
            if ((err = SyncTo(hfile, RT_BB, &filePos)) != GOOD)
               return(err);
            /* Get next BB block */
            blockPos = Seek695File(hfile, 0L, SEEK_CUR);
            if (MatchRecord(hfile, RT_BB) == GOOD)
               Get695BB(hfile, &blockSize, fnname, &blockType);
	    continue; // Next BB block
         }
         /* Enter Function symbol -> Symbol Table */
         fnClass = (blockType == BB_EXTERN_FN) ? FUNC_GLOBAL : FUNC_LOCAL;
         fnAddr.offsetStartAddr = fStartOffset;
         fnAddr.offsetEndAddr   = endRangeNotSet;

         /* NOTES: blocks will call this routine too (null name) */
         /* sindex = section index serves as base index */
         if ((symerr = SymAddFuncCreate((LPSTR)pname, sindex, fnClass,
                                        nstack, &fnAddr, rtn_type)) != GOOD) {
                 WarningEx(ER_CANNOT_ADD_FUNC, (LPSTR)pname);
            /*
            ** NOTES: 09/17/93 - Nghia
            ** Need to skip to the next block and continue processing
            */
            if ((err = SkipOver(hfile, blockPos, blockSize,
                                blockType)) != GOOD) return(err);
            goto ContinueProcessing;
         }
         if (lstb != NULL)
            lstb->numFunctions++;
         /* Update module address range */
         if (pmodRange->offsetStartAddr == startRangeNotSet)
            pmodRange->offsetStartAddr = fStartOffset;
      } else {
         /* ONDEMAND LOADING
         ** Open function context for adding local symbols.  With the addition
         ** of C++ support, a two-level lookup is done.  First, the demangled-
         ** on-the-fly user name.  Second, the mangled name from the loadfile
         ** (which works for duplicates, which are kept in mangled form in
         ** the symbol table).
         */
         /* user wants mangled names */
         if (!ldrDemangle)  
            pname = pmangledName;  /* reassign the original name */

         if ((symerr = SymAddFuncOpen(pname)) != GOOD) {
            /* try mangled name */
            pname = pmangledName;
            if ((symerr = SymAddFuncOpen(pname)) != GOOD) {
               err = ER_FN_NOT_FOUND;
               WarningEx(err, (LPSTR)pname);
               /*
               ** NOTES: 09/17/93 - Nghia
               ** Need to skip to the next block and continue processing
               */
               if ((err = SkipOver(hfile, blockPos, blockSize,
                                   blockType)) != GOOD) return(err);
               goto ContinueProcessing;
            }
         }
      }
      
      /* NOTES: Within a BB4 record, either NN or a BB6 can exist randomly */
      /* See Page 30 of IEEE 695 Spec. - Nghia 03/17/93 */

      /* Special handling for C++ block '__XRYCPP':
      ** Gets created initially for ondemand load.  Local symbols not yet
      ** supported, so we skip over.  This whole procedure block is known
      ** as the 'XRAY information block', and records are described in Appendix
      ** F (C++ information) of the MRI IEEE 695 spec, version 4.1, as of this
      ** writing.
      */
      cppLoadfile = (BOOLEAN) (strcmp(fnname, XRAY_CPPNAME) == 0);

      // NOTES: 02/24/94 - Nghia
      // Force load all local symbol if blockSize == 0,
      // SkipOver does not work correctly to get the end_address of symbol
      if ((LOAD_LOCALS(lflags) && !cppLoadfile) || !blockSize) {
         while (1) {
            Peek695Byte(hfile, &cbyte);
            /* Check for not a NN, BB and ATN record - Nghia - 05/26/93 */
            if ((cbyte != RT_NN) && (cbyte != RT_BB) && (cbyte != RP_ATTR)) {
               break; /* exit while loop */
            }
            /* Check for either an NN/ATN or a BB6 */
            switch (cbyte) {
               /* ATN9/NN record */
               case RP_ATTR:
               case RT_NN:
                  Seek695File(hfile, 0L, SEEK_CUR);
                  ProcessDbgLocals(hfile, typeOffset);
                  spcFg= 10;
                  break;
               /* BB6 record - nested block */
               case RT_BB:
                  blockPos = Seek695File(hfile, 0L, SEEK_CUR);
                  MatchRecord(hfile, RT_BB);
                  /* Nested block found */
                  Get695BB(hfile, &blockSize, blockName, &blockType);
                  endBlockPos = blockPos + blockSize;
                  if (blockType == BB_STATIC_FN) {
                     /* NOTES: Process all BB6 - Call recursively  */
                     ProcessDbgFunctions(hfile, blockType, blockPos,
                                         blockSize, blockName, pmodRange,
                                         typeOffset, MCREATE,
                                         lflags);
                  } else {
                     /* Report bad block nesting */
                     Warning(ER_BAD_NEST);
                     if ((err = SkipOver(hfile, blockPos, blockSize,
                                         blockType)) != GOOD) return(err);
                  }
                  break;
            } /* switch */
         }  /* while */
         
         /* NOTES: 09/08/93 - Nghia
         ** If for some reasons that the end function block is not found,
         ** it will recover to the 'recoverBlockPos' and get the function
         ** block end address.
         */
         if (MatchRecord(hfile, RT_BE) != GOOD) {
            goto SkipToEnd;  
         } else {
            /* Get End address of function or block */
            Get695Offset(hfile, &fEndOffset);
            /* Due to DIAB DATA toolchain provides wrong end address of function
               <Judy 5/30/96> */
            if (toolSelect==DIAB_DATA_TOOLCHAIN) {
                ProcessDbgFunctionStart(hfile, &nStartOffset);
                fEndOffset=(nStartOffset==0)? fEndOffset+spcFg-1 : nStartOffset-1;
            }
         }
     } else {
         /* NOTES: SKIP OVER FUNCTION BLOCK
         ** Do not loading locals and also skipping over nested blocks 
         ** Recalculate endBlockPos for each function
         */
SkipToEnd:                  
         if (!blockSize) {
            if ((err = SkipOver(hfile, blockPos, blockSize, blockType))
                != GOOD) return(err);
            endBlockPos = Seek695File(hfile, 0L, SEEK_CUR);
         } else {
            endBlockPos = blockPos + blockSize;
         }
         // NOTES: 02/24/94 - Nghia
         // failed to get the end address of function, so make the end
         // address = startaddress+1 and warns the user
         if ((err = getBlockEndAddress(hfile, endBlockPos, fStartOffset,
                                &fEndOffset)) != GOOD) {
            Warning(err);
            fEndOffset = fStartOffset+1;
         }
         /* Due to DIAB DATA toolchain provides wrong end address of function
             <Judy 6/25/96> */
         if (toolSelect==DIAB_DATA_TOOLCHAIN) {
             ProcessDbgFunctionStart(hfile, &nStartOffset);
             fEndOffset=(nStartOffset==0)? fEndOffset+spcFg-1 : nStartOffset-1;
         }
         /* Reset file position to the end of block regardless */
         blockPos = Seek695File(hfile, endBlockPos, SEEK_SET);        
      } /* Skip over function */
 
      /* close fn scope */
      if ((symerr = SymAddFuncClose()) != GOOD) {
         Warning(symerr);
      }
      if (oflag == MCREATE) {
         /* Always update module end address */
         pmodRange->offsetEndAddr = fEndOffset;
         /* Finish off fn address range */
         fnFinalAddr.startAddr   = 0;  /* don't change */
         fnFinalAddr.endAddr     = fEndOffset;
         fnFinalAddr.startValid  = FALSE;
         fnFinalAddr.endValid    = TRUE;
         /* The ST is smart enough to figure out we are adding info to
         ** the function context (not any other open context), we hope.
         */
         /* Yes, this applies to fn and block - set end addr */
         if ((symerr = SymAddSymbolSetAddr(&fnFinalAddr)) != GOOD) {
            err = ER_SYM_NOT_UPDATED;
            Warning(err);
         }
      }
/* Error recover from adding function */     
ContinueProcessing:
   
      /* Flush register assignments in preparation of new function scope */
      LClearRegs();
      /* Set blockPos on entry to function, update for successive functions */
      blockPos = Seek695File(hfile, 0L, SEEK_CUR);
      /* Get next item to process */
      if (MatchRecord(hfile, RT_BB) == GOOD) {
         Get695BB(hfile, &blockSize, fnname, &blockType);
         continue;
      } else {
         /* Thru processing BB-function records */
         Unget695Byte(hfile, curbyte);
         return(GOOD);
      }
   }  /* while BB_FUNCTION */

   return(ER_BBFUNCTION_EXPT);
}  /* ProcessDbgFunctions */

/*****************************************************************************
**
**  ProcessDbgFunctionStart
**
** Note: To get next start address of next function. <Judy 6/5/96>
*****************************************************************************/
RETCODE ProcessDbgFunctionStart(HANDLE hfile, U32 *nStartOffset) {
   U16 blockType;
   U32 blockPos, blockSize, nstack, rtn_type;
   U32 ltypeOffset=0L;
   CHAR lfnname[IEEE_IDNLEN];

   *nStartOffset=0;
   blockPos = Seek695File(hfile, 0L, SEEK_CUR);
   if (MatchRecord(hfile, RT_BB) == GOOD) {
      Get695BB(hfile, &blockSize, lfnname, &blockType);
      if (IS_BBFUNCTION(blockType)) {
         PBBFunction(hfile, &nstack, &rtn_type, ltypeOffset, nStartOffset);
      }
   }
   blockPos = Seek695File(hfile, blockPos, SEEK_SET);
   return(GOOD);
}
/*****************************************************************************
**
**  ProcessDbgLocals - Locals to BB4 or BB6
**
*****************************************************************************/
RETCODE ProcessDbgLocals(HANDLE hfile, U32 typeOffset) {
   BASE_INDEX baseIndex;
   BOOLEAN isConst, thisProcessed=FALSE;  /* reset for each local scope */
   CHAR *pname, fnidn[IEEE_IDNLEN], sname[IEEE_IDNLEN];
   LONG filePos;
   LOOP_VAR i;
   RETCODE symerr, err;
   STATIC U16 atn9_flag = TRUE;
   SYM_DESCRIPTOR symP;
   U16 atype;  /* nested ATN type - pmisc 80 */
   U16 cbyte, nindex, atnType, atnErr = 0;
   U16 nrecs, reg_index, rtype;  /* pmisc 80 record type */
   U32 lvalue, nvalue, offset, tindex, typeid;
   VAR_LOCKED_REG lr;

   while (1) {
      /* Process NN/ATN - local vars */
      if (MatchRecord(hfile, RT_NN) == GOOD) {
         Get695Nrecord(hfile, &nindex, (LPSTR)sname);
         /* Strip mangling prefix from local identifier name */
         if (ldrDemangle)
            CppFixupLocal(sname, &pname);
         else
            pname = sname;  /* pointer assign */
         if (strcmp(pname, CPP_USERTHIS) == 0) {
            if (thisProcessed == TRUE)
               /* we'll store the mangled name instead */
               pname = sname;  /* pointer assign */
            else
               thisProcessed = TRUE;
         }
      } else
         Unget695Byte(hfile, curbyte);
      /*
      ** NOTES: ATN9 records are not preceded by NN,
      ** they follow ATN2 (usually) in direct succession
      */
      Peek695Byte(hfile, &cbyte);
      if (cbyte != RP_ATTR) {
         Unget695Byte(hfile, cbyte);
         break;  // big while loop
      }
      
      if ((Match2Record(hfile, RT_ATN) != GOOD) ||
         (ProcessATN(hfile, &nindex, &tindex, typeOffset, &atnType) != GOOD)) {
         /* Recover to the next possible NN record*/
         if ((err = SyncTo(hfile, RT_NN, &filePos)) != GOOD)
            return(err);
         continue;
      }
      switch (atnType) {
         /* The following ATN types are handled at this (local) level:
	 ** ATN 1/2/3/9/10 - proc misc 62
         */
         case ATN_AUTO:  /* stack-based var (ATN1) */
            /* Notes: parameters will have a positive stack offset,
            ** locals will have negative stack offset
            */
            Get695Offset(hfile, &offset);
            /* Since the local vars reside on stack, create a fake section
	    ** base to sactisfy the Symnbol server. This is really a fake
            ** section index
            */
	    FindBaseRTAIndex(&baseIndex);
	    if ((symerr = SymAddVar((LPSTR)pname,
                  baseIndex,
                  tindex,
                  AUTO_VAR_CLASS,
                  NOT_REG,
		  (ADD_VAR_ADDR_UNION *)&offset,  /* signed 32-bit value */
                  FALSE,  /* not const */
                  TRUE,  /* valid address */
		  &symP)) != GOOD)
	     {
		  if (!pname) pname = sname;
		  WarningEx(ER_CANNOT_ADD_SYM, (LPSTR)pname);
	     }
             break;

         case ATN_REGISTER: {  /* register vars (ATN2) */
            /* only generated for unused locals and parms */
            VAR_LIVING_REG regId;
	    Get695Number(hfile, &reg_index);
            if (Rxlate(reg_index,&regId) != GOOD ) 
               break;
            /* xlation not available, error already issued */
            /* this is really a fake section index */
            FindBaseRTAIndex(&baseIndex);
            if ((symerr = SymAddVar((LPSTR)pname,
                  baseIndex,
                  tindex,
                  AUTO_VAR_CLASS,
                  LIVING_REG,
                  (ADD_VAR_ADDR_UNION *)&regId,
                  FALSE,  /* not const */
                  TRUE,  /* valid address */
                  &symP)) != GOOD) {
               WarningEx(ER_CANNOT_ADD_SYM, (LPSTR)pname);
            }
            // living registers start out DEAD.
            if ((err = LSaveVar(nindex, symP, reg_index, DEAD)) != GOOD) {
               /* cannot save, hence don't use later */
               atn9_flag = FALSE;
            }
            break;
         }
         case ATN_LOCKED_REG:  /* locked register vars (ATN10) */
            /* the compiler makes these decisions, i.e. they are not
            ** user-specified 'register' declarations, for heavily used locals.
            */
            Get695Number(hfile, &reg_index);
            if (Rxlate(reg_index, &lr.regIndex) != GOOD)
               lr.regIndex = reg_index;
            /* xlation not available, error already issued */
            /* note! The frame offset field is not always present! */
            Peek695Byte(hfile, &cbyte);
            /* NN or BB or BE or ATN signal end of this record Hera 11/20/96*/
            if (cbyte != RT_NN && cbyte != RT_BE && cbyte != RT_BB && cbyte != RP_ATTR) {
               /* yes, the 68K limits you to +/- 32K for stack offset
               ** (lr.autoVarOffset is S16)
               */
               Get695Offset(hfile, (U32 *)&lr.autoVarOffset);
            } else
               lr.autoVarOffset = 0L;
            /* this is really a fake section index */
            FindBaseRTAIndex(&baseIndex);
            if ((symerr = SymAddVar((LPSTR)pname,
                  baseIndex,
                  tindex,
                  AUTO_VAR_CLASS,
                  LOCKED_REG,
                  (ADD_VAR_ADDR_UNION *)&lr,
                  FALSE,  /* not const */
                  TRUE,  /* valid address */
                  &symP)) != GOOD) {
               WarningEx(ER_CANNOT_ADD_SYM, (LPSTR)pname);
            }
            // locked registers start out LIVE.
            if ((err = LSaveVar(nindex, symP, reg_index, LIVE)) != GOOD) {
               /* cannot save, hence don't use later */
               atn9_flag = FALSE;
            }
            break;

         case ATN_PROC_MISC:  /* procedure miscellaneous */
            ProcessATN62(hfile, &typeid, typeOffset, &nrecs);
            /* Note that you need to be careful when processing new ATN62 type
               records, each has a unique syntax.  Extra fields associated
               with ATN or ASN records may need to be processed.
            */
            if (typeid == PMISC_77) {
               Get695Idn(hfile, fnidn);
               /* NOTES: 09/20/93 - Nghia
               ** Only need to report once
               */
               atn9_processed = TRUE;
            }
            /* pmisc type 80:
            **   these are *not* in XRAY info block (but in BB3 someplace):
            **   record code 'M' (0x4d): member function
            **      (also used for static ctor/dtor.  With 1.1B, 2 of these
            **       are generated for *every* function - don't know why)
            **       note that 'C++ flags' are discarded, and this record
            **       does not create a symbol table entry
            **   record code 'B' (0x42): default and reference argument list
            **
            **   these are in XRAY info block:
            **   record code 'F': source file name
            **   record code 'T': class and related types
            **   record code 'B': default and reference args
            **   record code 'z': pointer to member
            **   record code 'R': reference type var
            */
            if (typeid == PMISC_80) {
              /* marked by<Judy 8/19/97>
               if ((Match2Record(hfile, RT_ASN) != GOOD) ||
                   (ProcessASN(hfile, &nindex, (U32 *)&rtype) != GOOD)) {
                  if ((err = SyncTo(hfile, RT_NN, &filePos)) != GOOD)
                     return(err);
                  continue;
               } */
              /* added by < Judy 8/19/97> */
               Peek695Byte(hfile, &curbyte);
               if (Match2Record(hfile, RT_ASN) == GOOD) {
                   if (ProcessASN(hfile, &nindex, (U32 *)&rtype) != GOOD) {
                     if ((err = SyncTo(hfile, RT_NN, &filePos)) != GOOD)
                         return(err);
                   }
               } else {
                   Unget695Byte(hfile, curbyte);
                   if (Match2Record(hfile, RT_ATN) == GOOD) {
                        ProcessATN(hfile, &nindex, &tindex, typeOffset, &atype);
                        if (atype == ATN_MISC_STR)
                           Get695Idn(hfile, (LPSTR)sname);
                   } else {
                      /* assume fails on first byte */
                      Unget695Byte(hfile, curbyte);
                      if ((err = SyncTo(hfile, RT_NN, &filePos)) != GOOD)
                          return(err);
                   }
               }
              /* eof < Judy 8/19/97> */
               --nrecs;
               if (rtype == XRAY_ARGLIST) {
                  /* template (how it really works, not how its documented):
                  **    'B' (ASN)
                  **    function-name (ATN)
                  **    count (ASN)
                  **         if !0
                  *          {default arg type [, value]}* (count times) (ASNs)
                  **    reference argument indices (ASNs)
                  */
                  /* Eating the name is conditional since it is not documented
                  ** in the 695 spec, so perhaps MRI could change it in a
                  ** future release?
                  */
                  if (Match2Record(hfile, RT_ATN) == GOOD) {
                     ProcessATN(hfile, &nindex, &tindex, typeOffset, &atype);
                     if (atype == ATN_MISC_STR)
                        Get695Idn(hfile, (LPSTR)sname);
                     --nrecs;
                  } else {
                     /* assume fails on first byte */
                     Unget695Byte(hfile, curbyte);
                  }
#if 1
/* Finding undocumented argType masks in class library files.  Since we're not
   supporting reference args in symbol table now, just eat the records.  Please
   leave code here (stubbed out) till we figure out the undefined masks,
   or till MRI documents these!!!
*/
                  for (i=0; i<nrecs; i++) {
                     Match2Record(hfile, RT_ASN);
                     ProcessASN(hfile, &nindex, &nvalue);
                  }
#else
/* !!!Need to fixup function template in symbol table.  Will need to
** correlate sname just read in, to the function scope open in the symbol table.
*/
                  /* get count of default args */
                  Match2Record(hfile, RT_ASN);
                  ProcessASN(hfile, &nindex, &count);
                  --nrecs;
                  for (i=0; i<count; i++) {
                     Match2Record(hfile, RT_ASN);
                     ProcessASN(hfile, &nindex, (U32 *)&argType);
                     --nrecs;
                     if (argType != 0) {
                        /* get default argument value: kick out for now
                        ** since symbol table doesn't keep values
                        */
                        Match2Record(hfile, RT_ASN);
                        Get695Number(hfile, &nindex);  /* name index */
                        /* Note: cannot use standard ProcessASN in this case,
                        ** since value field has any of the following sizes
                        ** (the standard ASN routine only handles U32 values)
                        */
                        --nrecs;
                        switch(argType) {
                           case DEFARG_4BYTE:
                              Get695Offset(hfile, &nvalue);
                              break;
                           case DEFARG_8BYTE:
                              Warning(ER_LONG_DEFARG);
                              /* This is not the correct way to get an 8-byte
                                 value, but lets try anyhow. */
                              Get695Offset(hfile, &nvalue);
                              Get695Offset(hfile, &nvalue);
                              break;
                           case DEFARG_STR:
                              Get695Idn(hfile, (LPSTR)&sname);
                              break;
                        }
                     }
                  }
                  /* if any ASNs left, the rest are reference parm indices */
                  for (i=0; i<nrecs; i++) {
                     Match2Record(hfile, RT_ASN);
                     ProcessASN(hfile, &nindex, (U32 *)&argType);
/* !!!Now for the fun part: based on this argument 'index' (its position in
** the argument list, which starts with 1), add this reference identification
** to the symbol table entry.
*/
                  }
#endif
               } else {
                  /* all others - ignore information */
                  for (i = 0; i < nrecs; i++) {
                    /* marked by <Judy 8/20/97>
                     Match2Record(hfile, RT_ASN);
                     ProcessASN(hfile, &nindex, &nvalue);
                     */
                    /* added by < Judy 8/19/97> */
                     Peek695Byte(hfile, &curbyte);
                     if (Match2Record(hfile, RT_ASN) == GOOD) {
                         if (ProcessASN(hfile, &nindex, &nvalue) != GOOD) {
                           if ((err = SyncTo(hfile, RT_NN, &filePos)) != GOOD)
                               return(err);
                         }
                     } else {
                       Unget695Byte(hfile, curbyte);
                       if (Match2Record(hfile, RT_ATN) == GOOD) {
                          ProcessATN(hfile, &nindex, &tindex, typeOffset, &atype);
                          if (atype == ATN_MISC_STR)
                             Get695Idn(hfile, (LPSTR)sname);
                       } else {
                          /* assume fails on first byte */
                          Unget695Byte(hfile, curbyte);
                          if ((err = SyncTo(hfile, RT_NN, &filePos)) != GOOD)
                              return(err);
                       }
                     }
                    /* eof < Judy 8/19/97> */
                  }
               }
            } else {
               /* all others - ignore information; warning already issued */
               for (i=0; i<nrecs; i++) {
                  Match2Record(hfile, RT_ASN);
                  ProcessASN(hfile, &nindex, &nvalue);
               }
            }
            break;

         case ATN_LIFETIME:  /* variable lifetime information (ATN9) */
         {
            VAR_LIFETIME_STATE lifeState = LIVE;
            /* Requires a [x1] which specifies the absolute PC offset */
            Get695Offset(hfile, &offset);  /* PC offset of activation */
            /* NOTES: if nindex == 0 then this is a DEATH ATN9 record
            ** and the optional [x2] is symbol name index of the reister.
            */
            if (!nindex) {
               /* NOTES: Nghia - 08/18/93
               ** When {n1} == 0 then [x2] is the index of regiter source
               ** return to scratch status starting at the program counter
               ** offset specified in [x1].
               ** However, there is case that {n1} == 0 and there is no [x2];
               ** Therefore, a test for the next ATN/NN signature must handle
               */
               Peek695Byte(hfile, &cbyte);
               if ((cbyte != RT_NN) && (cbyte != RP_ATTR)) {
                  Unget695Byte(hfile, cbyte);
                  /* Get nindex from [x2] that specified the register */
                  Get695Offset(hfile, (U32*)&nindex); 
                  lifeState = DEAD;
                  // reset all variables of the specified register to DEAD
                  if (atn9_flag) 
                     LResetRegs(nindex, offset, lifeState);                    
               } 
               /* No [x2] to get - continue to process */
               break;
            }
            /* Set the life time information */
            if (atn9_flag != FALSE) {
               LActivate(nindex, offset, lifeState);
               atn9_processed = TRUE;
            }
            break;
         }

         /* Process statics */
         /* NN/ATN3/ASN */
         case ATN_STATIC:  /* ATN3 */
            /* get symbol address */
            if ((Match2Record(hfile, RT_ASN) != GOOD) ||
               (ProcessASN(hfile, &nindex, &lvalue) != GOOD)) {
               /* Recover to the next possible NN */
               if ((err = SyncTo(hfile, RT_NN, &filePos)) != GOOD)
                  return(err);
               continue;
            }
               
            if (FindBaseIndex(lvalue, &baseIndex, &isConst) != GOOD) {
               /* Lets try the default data section */
               if ((err = FindBaseDataIndex(&baseIndex)) != GOOD) {
                  Warning(err);
                  /* low level function reports error */
                  break;
               }
               isConst = FALSE;
            }
            if ((symerr = SymAddVar((LPSTR)pname,
                  baseIndex,  /* section index */
                  tindex,
                  STATIC_VAR_CLASS,
                  NOT_REG,
                  (ADD_VAR_ADDR_UNION *)&lvalue,
                  isConst,
                  TRUE,  /* address is valid */
                  &symP)) != GOOD) {
               WarningEx(ER_CANNOT_ADD_SYM, (LPSTR)pname);
            }
            break;

         /* NOTES: Process globals (found in some toolchain output); 
         ** this is explicitly *not* allowed by the 695 spec - we are
         ** notifying the toolchain providers, but for now in the interest
         ** of supporting user code without error we add a hack to add
         ** these records to the symbol table.  Cosmic: case in point,
         ** generates ATN8 for local symbols declared with @far.
         */
         case ATN_GLOBAL:
            /* Get symbol address */
            if ((Match2Record(hfile, RT_ASN) != GOOD) || 
               (ProcessASN(hfile, &nindex, &lvalue) != GOOD)) {
               /* Recover to the next NN */
               if ((err = SyncTo(hfile, RT_NN, &filePos)) != GOOD)
                  return(err);
               continue;
            }
            /* we add them as statics */
            if (FindBaseIndex(lvalue, &baseIndex, &isConst) != GOOD) {
               /* Lets try the default data section */
               if ((err = FindBaseDataIndex(&baseIndex)) != GOOD) {
                  Warning(err);
                  /* low level function reports error */
                  break;
               }
               isConst = FALSE;
            }
            if ((symerr = SymAddVar((LPSTR)pname,
                  baseIndex,  /* section index */
                  tindex,
                  STATIC_VAR_CLASS,
                  NOT_REG,
                  (ADD_VAR_ADDR_UNION *)&lvalue,
                  isConst,
                  TRUE,  /* address is valid */
                  &symP)) != GOOD) {
               WarningEx(ER_CANNOT_ADD_SYM, (LPSTR)pname);
            }
            break;

         default:
            // 02/24/94 - Nghia
            // Report any ATN does not support once
            if (atnErr && (atnErr != atnType)) {
               wsprintf(errbuf, "%d.", atnErr);
               WarningEx(ER_ATTR_NOT_HANDLED, errbuf);
            }
            atnErr = atnType;
            
            /* Return err indicates cannot seek file: serious error */
            if ((err = SyncTo(hfile, RT_NN, &filePos)) != GOOD)
               return(err);
            continue;
      }
   }  /* while NN */

   // 02/24/94 - Nghia
   // Report any ATN does not support once
   if (atnErr) {
      wsprintf(errbuf, "%d.", atnErr);
      WarningEx(ER_ATTR_NOT_HANDLED, errbuf);
   }

   return (GOOD);
}  /* ProcessDbgLocals */

/*****************************************************************************
**
** ProcessDbgLines - Line number block
**
** ondemand - if TRUE, skip over lines (initial load)
**    FALSE for load all, or for module only load (load lines)
** oflag - MCREATE or MOPEN
**    MCREATE = initial load (whether ondemand or not) - MOPEN = load lines
** *nextBlockPos - start position of the line number block, it will be set to
**    the next block for error recovery.
** moduleDesc - module descriptor
**
*****************************************************************************/
RETCODE ProcessDbgLines(HANDLE hfile, BOOLEAN ondemand, BOOLEAN oflag,
                        U32 *nextBlockPos, U32 *nextBlockSize,
                        SYM_DESCRIPTOR moduleDesc) {
   BOOLEAN resetBlock = FALSE;
   CHAR mref[1] = "";  /* because the Symbol Server won't take a NULL parm */
   CHAR sname[IEEE_IDNLEN];
   CHAR srcname[IEEE_IDNLEN];
   U16 blockType, cbyte, dummy;
   U16 lineno, colno, nindex, atnType;
   U16 prelineno;      /* to reserve previous line no. <Judy 5/29/96> */
   U32 blockPos, blockSize;
   U32 laddr, tindex, tjunk = 0L;  /* line number type index is bogus */
   LONG filePos;
   RETCODE symerr = GOOD, nsymerr = GOOD;
   TIMESTAMP_TYPE tsModule;
   S16 errState;

   /* Track file position */
   blockPos = Seek695File(hfile, 0L, SEEK_CUR);
   prelineno=0; /* <Judy 5/29/96> */
   
   /* NOTES:  If current position is not a BB5 block - synch up to */
   while (1) {
      if ((MatchRecord(hfile, RT_BB) != GOOD) ||
         (Get695BB(hfile, &blockSize, (LPSTR)srcname, &blockType)
          != GOOD) || (blockType != BB_LINE)) {
         /* Try reset to start of BB5 and retry */
         if (!resetBlock) {
            if (*nextBlockSize > 0)
               /* NOTES: nextBlockPos = BB3start + BB3size */
               blockPos = Seek695File(hfile, *nextBlockPos, SEEK_SET);
            else
               /* If *nextBlockPos < blockPos, do not seek backward */
               blockPos = Seek695File(hfile, blockPos, SEEK_SET);
            resetBlock = TRUE;
         } else {
            /* NOTES: Nghia - 08/19/93
            ** Cannot match the outer most BB5 block - it might be
            ** a module which does not a BB5 block at all - data module!
            ** Only report once - do not report when doing demand loading.
	    */

            /*Hera 09/26/96 -- We do not report waring, when missing BB5 **/
	    //if (ondemand) {
            //   DESCRIPTOR moduleNameDesc;
            //   if ((nsymerr = SymGetSymbolName(moduleDesc,
            //              (DESCRIPTOR FAR *) &moduleNameDesc)) == GOOD)
                  /* Report Error */
            //      ErrDisplayFormattedError(ER_NO_LINEBLK_IN_MODULE, CHECK_MODE,
            //                    (LPSTR) moduleNameDesc,
            //                    (LPSTR) NULL,
            //                    (LPSTR) NULL,
            //                    MB_OK,
            //                    (S16 FAR *) &errState);
               /* Free Memory allocated by symbol server */
            //   TFree((LPSTR)moduleNameDesc);
               /* Return error to do error recovery - not to report */
	    //}
	    /**Hera**/

            /* If it is a good block then return GOOD to continue */
            if ((blockType >= BB_LOCAL_TYPE) && (blockType <= BB_ASMSECTION)) {
               /* Need to reset to process next block */
               Seek695File(hfile, blockPos, SEEK_SET);             
               return(GOOD);
            }
            else
               return(ER_NO_LINEBLK_IN_MODULE);
         }
      } else {
         /* NOTES: Nghia - 08/19/93
         ** Save the next block position for error recovery
         */
         *nextBlockPos  = blockPos;
         *nextBlockSize = blockSize;
         break; /* Continue Processing BB5 block */
      }
   } /* end of while */
   
   /* Load module reference (full file pathname) for the initial load */
   if ((moduleDesc != 0L) && (oflag == MCREATE)) {
      /* Load module reference with module descriptor */
      if ((symerr = SymAddModuleReference(moduleDesc, (LPSTR)srcname)) != GOOD)
         Warning(ER_MODREF); /* just continue, not fatal */
   }
   
   /* ONDEMAND loading, so do not load line number information */
   if (ondemand) {
      return(SkipOver(hfile, blockPos, blockSize, blockType));
   }
   
   /* START LOADING LINE NUMBER INFORMATION */
   if ((symerr = SymAddLinenumStart(moduleDesc)) != GOOD) {
      Warning(symerr);
      return(ER_LINE_NOT_ADDED);
   }
   /* NOTES: Nghia - According to the IEEE695 Spec. V4.1
   ** a BB5 might optionally include timestamp information.
   ** So, if it presents then process it.
   */
   Peek695Byte(hfile, &cbyte);
   if ((cbyte != RT_BB) && (cbyte != RT_NN)) {
      Get695Time(hfile, &tsModule);
      /* Reset the symbol server timestamp with the new value
      ** Used the same module name and descriptor (mname and mdesc).
      */
   }
   /* Process NN record , followed by {ATN/ASN}* */
   if (MatchRecord(hfile, RT_NN) != GOOD) {
      Warning(ER_LINE_EXPT);
      return(ER_LINE_EXPT);
   }
   Get695Nrecord(hfile, &nindex, (LPSTR)sname);
   while (1) {
      /*
      ** Obtain current file position in case we're skipping over
      ** nested BB5 blocks
      */
      blockPos = Seek695File(hfile, 0L, SEEK_CUR);
      Peek695Byte(hfile, &cbyte);
      /* Check for any number of #include BB5's and skip over */
      while (cbyte == RT_BB) {
         MatchRecord(hfile, RT_BB);
         Get695BB(hfile, &blockSize, (LPSTR)srcname, &blockType);
         if (blockType != BB_LINE) {
            Warning(ER_LINE_EXPT);
            return(ER_LINE_EXPT);
         }
         if ((symerr = SkipOver(hfile, blockPos, blockSize,
                             blockType)) != GOOD) return(symerr);
         blockPos = Seek695File(hfile, 0L, SEEK_CUR);
         Peek695Byte(hfile, &cbyte);
      } /* end of while */

      /* nested BB5's (from #include files) don't usually have line records */
      /* NN, followed by {ATN/ASN}* */
      /* Note that NN may have already been processed above, if there
      ** were no nested BB5's
      */
      if (cbyte == RT_NN) {
         if ((MatchRecord(hfile, RT_NN) != GOOD) ||
             (Get695Nrecord(hfile, &nindex, (LPSTR)sname) != GOOD)) {
            SyncTo(hfile, RT_NN, &filePos);
            continue;
         }
      }
      Peek695Byte(hfile, &cbyte);
      if (cbyte == RP_ATTR)
         Match2Record(hfile, RT_ATN);
      else
         break;
      /* Process the ATN record */
      ProcessATN(hfile, &nindex, &tindex, tjunk, &atnType);
      if (atnType == ATN_LINENO) {
	 ProcessATN7(hfile, &lineno, &colno);
         /* NOTES: Nghia - Check for 2 extra fields of ATN [x3] and [x4] */
         Peek695Byte(hfile, &cbyte);
         if (cbyte != RT_ASN1) {
            Get695Number(hfile, &dummy);
            Get695Number(hfile, &dummy);
         }
      }
      else {
         break;  /* resynch! */
      }
      /* Resynch should probably seek to (stored) end of line no section,
      ** and warn user
      */
      if ((Match2Record(hfile, RT_ASN) != GOOD) ||
          /* Process the follow ASN record */
          (ProcessASN(hfile, &nindex, &laddr) != GOOD)) {
         SyncTo(hfile, RT_NN, &filePos);
         continue;
      }
      /* The compiler does not generate column information. <JUDY 5/29/96> */
      if (toolSelect==DIAB_DATA_TOOLCHAIN) {
         if (prelineno < lineno) {
	    colno++;
            nsymerr = SymAddLinenum(lineno, colno, laddr);
            prelineno = lineno;
            if (lstb != NULL)
               lstb->numLines++;
         }
      }
      else {
         nsymerr = SymAddLinenum(lineno, colno, laddr);
         if (lstb != NULL)
            lstb->numLines++;
      }
      /* Lets get the aggregate of all error codes returned
      ** and not put up an error for each line
      */
      symerr |= nsymerr;
   }
   if (symerr) {
      Warning(ER_LINE_NOT_ADDED);
   }

   if ((symerr = SymAddLinenumEnd()) != GOOD) {
      /* Filter Symbol server error to report correctly */
      if (symerr == ER_NO_LINENUMS_ADDED) {
         DESCRIPTOR moduleNameDesc;
         if ((nsymerr = SymGetSymbolName(moduleDesc,
               (DESCRIPTOR FAR *) &moduleNameDesc)) == GOOD)
         // <Judy 5/8/96>
         // WarningEx(ER_NO_LINENUMS_ADDED, (LPSTR)moduleNameDesc);
         /* Free Memory */
         TFree((LPSTR)moduleNameDesc);
      }
      else
         Warning(symerr);
   }
   /* Make sure that the block is ended */
   if ((symerr = MatchRecord(hfile, RT_BE)) != GOOD) {
      Warning(ER_BAD_LNUM_BLOCK_IN_FILE);
   }   
   return(symerr);
}  /* ProcessDbgLines */

/*****************************************************************************
**
** Get695BB - Return Block Begin (BB) signature
**
** pblockSize   - pointer to block size in bytes
** lpblockName  - block name (module, function name, etc.)
** blockType    - block type on sucess BB1, BB2, BB3, BB4,...
**
*****************************************************************************/
RETCODE Get695BB(HANDLE hfile, U32 *pblockSize, LPSTR lpblockName,
                                                  U16 *blockType) {
   RETCODE err;
   /* All the BB (block begin) record types indicate overall program
   ** structure, and symbol definitions for such entities (module, function,
   ** line number).  All BB records have at least the fields returned
   ** by this routine.  Some may require additional information.
   */
   Get695Byte(hfile, blockType);
   if ((err = Get695Offset(hfile, pblockSize)) != GOOD) return(err);
   if ((err = Get695Idn(hfile, lpblockName)) != GOOD) return(err);
   return(GOOD);
}  /* Get695BB */

/*****************************************************************************
**
** PBBFunction - Global or Static function of BB4 and BB6
**
** pnstack - pointer to number of bytes for stack
** prtn_type - pointer to type index for function return value
** typeOffset - fix-up value for return type
** poffset - pointer to offset for code block
**
*****************************************************************************/
RETCODE PBBFunction(HANDLE hfile, U32 *pnstack, U32 *prtn_type, U32 typeOffset,
                    U32 *poffset) {
   Get695Offset(hfile, pnstack);
   Get695TIndex(hfile, prtn_type, typeOffset);
   Get695Offset(hfile, poffset);
   return(GOOD);
}  /* PBBFunction */

/*****************************************************************************
**
**  ProcessTY - Define Type record
**
** ptindex - pointer to type index
** pnindex - pointer to name index
** pstype - pointer to symbol type
**
*****************************************************************************/
RETCODE ProcessTY(HANDLE hfile, U32 *ptindex, U32 typeOffset, U16 *pnindex,
                                                            U16 *pstype) {
   RETCODE err;

   if ((err = Get695TIndex(hfile, ptindex, typeOffset)) != GOOD) return(err);
   if ((err = MatchRecord(hfile, RT_TY2)) != GOOD) return(err);
   if ((err = Get695Number(hfile, pnindex)) != GOOD) return(err);
   Get695Byte(hfile, pstype);
   return(err);
}  /* ProcessTY */

/*****************************************************************************
**
** ProcessATN - Process ATN record
**
*****************************************************************************/
RETCODE ProcessATN(HANDLE hfile, U16 *pnindex, U32 *ptindex, U32 typeOffset,
                   U16 *n3) {
   RETCODE err;
   
   if ((err = Get695Number(hfile, pnindex)) != GOOD) return(err);
   if ((err = Get695TIndex(hfile, ptindex, typeOffset)) != GOOD) return(err);
   /* ATN type return */
   if ((err = Get695Number(hfile, n3)) != GOOD) return(err); 
   return(GOOD);
}  /* ProcessATN */

/*****************************************************************************
**
**  ProcessASN - Used for both ASN and ATN Global type record
**
*****************************************************************************/
RETCODE ProcessASN(HANDLE hfile, U16 *ptrNameIndex, U32 *ptrValue) {
   RETCODE err;
   
   if ((err = Get695Number(hfile, ptrNameIndex)) != GOOD) return(err);
   if ((err = Get695Offset(hfile, ptrValue)) != GOOD) return(err);
   return(GOOD);
}  /* ProcessASN */

/*****************************************************************************
**
**  ProcessATN62 - (Procedure miscellaneous)
**    ATNs that are local to a procedure handled here.
**
*****************************************************************************/
RETCODE ProcessATN62(HANDLE hfile, U32 *ptypeid, U32 typeOffset, U16 *pnrecs) {
   /* ptypeid - pointer to misc record
      pnrecs - pointer to number of records which follow
   */
   U16 cbyte;
   U16 pmiscType;  /* procedure miscellaneous record type */

   /* This is really the misc record type - see Appx B */
   Get695TIndex(hfile, ptypeid, typeOffset);
   pmiscType = *ptypeid;
   /* The following pmisc types are understood:
   **    PMISC_1:     procedure return address (HP tools/Ford code)
   **    PMISC_51:    language translator comment string
   **    PMISC_57:    jump table description
   **    PMISC_77:    undocumented (optimized MRI output)
   **    PMISC_80:    C++ information
   **
   ** NOTES: Each pmisc type has a unique format.  Since we want to
   ** be open-ended and handle random loadfiles built with random tools,
   ** we assume that unrecognized types have the same general format
   ** (usually a safe assumption), and issue a warning (and take an
   ** action item to contact the toolchain provider).  For unknown pmisc
   ** types, we still return the number of records, the caller will eat
   ** that many ASNs.
   */
   Get695Number(hfile, pnrecs);
   /* <Judy 8/19/97>
   if (pmiscType != PMISC_77)
      * Don't ask why but all other pmisc have it - Throw away *
      Get695Byte(hfile, &cbyte);
     eof <Judy 8/19/97> */
   switch (pmiscType) {
      case PMISC_1:
      case PMISC_51:
      case PMISC_57:
//           Get695Byte(hfile, &cbyte);
           break;
      case PMISC_77:
      case PMISC_80:
           break;
      default:
         /* unrecognized pmisc type */
         Warning(ER_ATN_NOT_HANDLED);
         break;
   }

   return(GOOD);
}  /* ProcessATN62 */

/*****************************************************************************
**
**  ProcessATN7 - Process record: ATN 7 (line number)
**
*****************************************************************************/
RETCODE ProcessATN7(HANDLE hfile, U16 *pline, U16 *pcol) {
   /*  pline - pointer to line number, pcol - pointer to column number */
   Get695Number(hfile, pline);
   Get695Number(hfile, pcol);
   return(GOOD);
}  /* ProcessATN7 */

/*****************************************************************************
**
**  ProcessATN16 - Process record: ATN 16 (Constant definition)
**
*****************************************************************************/
RETCODE ProcessATN16(HANDLE hfile, U32 *nValue, LPSTR defName) {
   BOOLEAN done = FALSE, matchX2 = FALSE;
   U16 cbyte, strLen, nIndex;
   U32 pcLoc;
   LONG filePos;
   CHAR buff[IEEE_IDNLEN];
   LOOP_VAR i;
   RETCODE err;
   
   /* ATN16 - {ATN header}{x1}[x2][x3]|[x4]|ASN
   ** where: [x3] is a numeric, [x4] is a string value
   ** Also, there might be an ASN record indicating the PC where
   ** the definition occurs
   */
   /* get {x1} - Symbol class */
   Get695Byte(hfile, &cbyte); 
   while (!done) {
      Peek695Byte(hfile, &cbyte);
      switch(cbyte) {
         case RT_NN:
         case RT_BB:   
         case RT_BE:   
            return(GOOD);
            
         case ATN16_LOCAL_DEF:
         case ATN16_GLOBAL_DEF:
            /* get the optional [x2] */
            if (!matchX2) {
               Get695Byte(hfile, &cbyte);
               matchX2 = TRUE;
            } else
               SyncTo(hfile, RT_NN, &filePos);
            break;
            
         default :
            /* Get the optional [x3] | [x4] */
            if (!IS_NUMPREFIX(cbyte) || /* $80-$84 Numeric prefix */
               (Get695Offset(hfile, nValue) != GOOD)) {
               SyncTo(hfile, RT_NN, (LONG *)&filePos);
            }
            Peek695Byte(hfile, &cbyte);
            switch(cbyte) {
               case RT_NN:
               case RT_BB:
               case RT_BE:
                  return(GOOD);

               case RP_SECTION :
                  /* There might be an ASN record at the end of ATN16 */
                  if (Match2Record(hfile, RT_ASN) == GOOD) 
                     return(ProcessASN(hfile, &nIndex, &pcLoc));
                  else {
                     if ((err = SyncTo(hfile, RT_NN, &filePos)) != GOOD)
                        return(err);
                  }
                  break;
                  
               case LONG_STR_256:
               case LONG_STR_MAX:
                  /* $DE or $DF : long string signature */
                  Get695Byte(hfile, &cbyte);
                  /* Get [x4] as long string but only the IEEE_IDNLEN size */
                  /* marked by <Judy 9/20/97>
                  if (Get695Number(hfile, &strLen) != GOOD)
                     SyncTo(hfile, RT_NN, (LONG *)&filePos);
                     eof <Judy 9/20/97> */
                  /* added by <Judy 9/20/97> */
                  if (cbyte == LONG_STR_256) {
                     Get695Byte(hfile, (U16 *) &strLen);
                  } else {
                     if (Get695Number(hfile, &strLen) != GOOD)
                        SyncTo(hfile, RT_NN, (LONG *)&filePos);
                  }
                  /* eof <Judy 9/20/97> */
                  for (i = 0; i < strLen; i++) {
                     Get695Byte(hfile, (U16 *) &cbyte);
                     if (i < IEEE_IDNLEN) 
                        buff[i] = cbyte; 
                  }
                  buff[IEEE_IDNLEN - 1] = '\0';
                  lstrcpy((LPSTR)defName, (LPSTR)buff);
                  break;

               default:
                  /* NOTES: 09/20/93 - Nghia
                  ** Usually [x3] is zero, then there must be an [x4] string
                  ** else there will be no string present - MRI 4.3d
                  */
                  /* Get short string (0-127) */
                  if ((*nValue) || (cbyte > SCHAR_MAX) ||
                     (Get695Idn(hfile, defName) != GOOD)) { /* String value */
                     SyncTo(hfile, RT_NN, (LONG *)&filePos);
                  }
                  break;
            } /* end of switch */
      } /* end of switch */
   } 
   return(GOOD);
}  /* ProcessATN16 */

/*****************************************************************************
**
**  isValidAddr - determine if buffer is a valid address
**
*****************************************************************************/
RETCODE PRIVATE isValidAddr(LPU8 pBuffer, U16 len, U32 *pAddr) {
   U8 pbyte;
   U16 nbytes;
   U32 nvalue = 0L;
   LOOP_VAR i;

   pbyte = pBuffer[0];
   if (IS_NUMPREFIX(pbyte)) {
      nbytes = pbyte & ~NP_LONG;
      /* be sure we have this many bytes in buffer */
      if (nbytes > len-1)
         return ER_INVALID_ADDRESS;
      for (i=1; i<nbytes+1; i++) {
         nvalue = nvalue << 8;
         nvalue |= pBuffer[i];
      }
      *pAddr = nvalue;
   } else {
      /* must match single-byte number format */
      if (pbyte <= SCHAR_MAX) {
         /* NOTES: Nghia - 08/19/93
         ** Number format page 1 of the IEEE695 Spec.
         ** Single byte value is between 0-127, the number is $0-$7F
         */
         *pAddr = (U32)pbyte;
      } else {  /* invalid address */
         return ER_INVALID_ADDRESS;
      }
   }

   return (GOOD);
}  /* isValidAddr */

/*****************************************************************************
**
**  getBlockEndAddress - Get the end address of a block 
**
*****************************************************************************/
RETCODE PRIVATE getBlockEndAddress(HANDLE hfile, U32 endBlockPos,
                                   U32 fStartOffset, U32 *fEndOffset) {
   LOOP_VAR i, j;
   U16 cbyte;
   U8 endAddrBuf[FN_ENDADDR_BYTES];
   RETCODE err = GOOD;
   
   /* We have to find the end-address for the function.  This
   ** is the only place in the file where this information is
   ** kept.  It is a bit tricky in the cases to consider, in
   ** the current algorithm to backtrack looking for the address.
   ** Note that it is still quicker to backtrack than to process
   ** all the locals (we are an ondemand loader, remember?).  The
   ** previous algorithm used here (PV 1.4 and previous) failed on
   ** at least one customer loadfile (it backtracked by FN_ENDADDR_OFFSET
   ** bytes and looked forward), by getting confused by a local
   ** address frame offset of 'FF FF FF F9'.
   **
   ** (where F9 is the end-marker for function block (RT_BE),
   ** and F8 is the start of the next function block)
   ** Here are some templates of what is handled:
   **
   **    F9 82 E4 35    normal case
   **    F9 82 B4 F9 F8   note that F9 can be part of the end-address,
   **                   the algorithm needs to verify that what follows
   **                   F9 is a valid address (in this case, there are
   **                   no bytes that follow).
   **    F9 37 F8       single-byte number format accepted, as well
   **                   as the multi-byte offset format given above
   **    F9 84 A2 B4 F9 B6 F8
   **                   Here F9 marker is found within a multi-byte
   **                   offset address, we check carefully that the
   **                   byte that follows the F9 marker is either a
   **                   straight number prefix ($80) indicating a multi-
   **                   byte offset number, *or* a single-byte number
   **                   which follows.  This F9 kicks out since the
   **                   B6 that follows is neither.  So we keep backing
   **                   up till the next F9.
   **    F9 84 A2 36 F9 32 F8
   **                   Though there appears to be a single-byte address
   **                   following the first (from reverse search) F9,
   **                   a check is done to ensure the function
   **                   end-address is larger than the start address
   **                   (both are known at initial load time).  If the
   **                   end address is smaller, the search continues.
   */
   /* local buffer only includes end bytes from previous block */
   Seek695File(hfile, endBlockPos-FN_ENDADDR_OFFSET,SEEK_SET);

   /* get buffer for local processing */
   for (i = 0; i < FN_ENDADDR_BYTES; i++) {
      Get695Byte(hfile, &cbyte);
      endAddrBuf[i] = cbyte;
   }
   /* Scan backward in local buffer, looking for BE marker
   ** indicating end-function block address.
   */
   for (i = FN_ENDADDR_BYTES - 1, j = 0; i >= 0; --i,++j) {
      /* be sure we have atleast one byte to process */
      if (endAddrBuf[i] == RT_BE && j != 0) {
         if ((err = isValidAddr(&endAddrBuf[i+1], j, fEndOffset)) == GOOD) {
            /* be sure end address > start address of function */
            if (*fEndOffset > fStartOffset)
               break; /* !!! else continue searching */
         }
      }
   }
   return(err);
} /* getBlockEndAddress */

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

