/****************************************************************************
**
**  Name:  LASM.C
**
**  Description: Load processing for assembly blocks
**
**  $Log:   S:/tbird/mt2_68k/l695/lasm.c_v  $
** 
**    Rev 1.0   13 Feb 1997 08:50:44   gene
** Initial revision.
** 
**    Rev 1.4   26 Nov 1996 09:03:54   kevin
** Hera modified
** 
**    Rev 1.3   12 Sep 1996 11:41:48   kevin
** support SDS Ver.6.35
** 
**    Rev 1.2   09 Sep 1996 09:46:48   kevin
** hera's modification
** 
**    Rev 1.1   23 Jul 1996 16:11:04   Judy
** To support MRI ASM file
** 
**    Rev 1.0   10 Jul 1996 15:30:18   Judy
** Initial revision.
** 
**    Rev 1.0   07 Sep 1995 10:32:02   gene
** Initial revision.
** 
**    Rev 1.7   29 Mar 1994 18:04:38   nghia
** Fixed Bug: load multiple copies of the same asm modules for tool other than
** Introl.  Added check for Introl tool to handle asm module processing 
** differently.
** 
**    Rev 1.6   03 Mar 1994 15:28:38   nghia
** Fixed bug for PV2.1:  Introl compiler generated BB10 without BB11, If failed
** to match the BE signature, return error so that the caller can call
** SkipOver() to continue.
** 
**    Rev 1.5   30 Sep 1993 14:40:44   nghia
** Revised to support Applied Micro 695:
** 1. Invalid BB11, missing {Id} {n2}
** 2. Only Create ASM module if user said so.
** 3. Make StripPathString() public to be used by LDEBUG.C
** 4. Revised to handle error recovery with blockSize == 0.
** 
**    Rev 1.4   23 Sep 1993 11:19:14   nghia
** Removed SYM_DESCRIPTOR parameter from ProcessDbgAsmBlock(), it no longer need
** Added error recovery to record processing to synch to the next possible
** record. 
** Strip off path and suffix for ASM module name.
** Added Block skipping to skip over unused BB11 blocks.
** 
**    Rev 1.3   03 Aug 1993 17:21:58   nghia
** Removed LERR_xxxx to use standard error codes.
** 
**    Rev 1.2   26 Jul 1993 17:04:52   courtney
** Enhanced assembly module support for Sierra - they don't generate
** timestamp; also generate ATN19's (public symbols defined in assembly
** blocks).
** 
**    Rev 1.1   26 Jul 1993 09:29:26   courtney
** Conditionalized parsing tool version and timestamp records in assembly
** blocks, since not all toolchains generate these records.
** 
**    Rev 1.0   13 Jul 1993 14:26:58   courtney
** Initial revision.
**  
**  $Header:   S:/tbird/mt2_68k/l695/lasm.c_v   1.0   13 Feb 1997 08:50:44   gene  $
**
**  Copyright (C) 1991-93 Microtek International.  All rights reserved.
**
*****************************************************************************/

                       /****************************
                        *                          *
                        *       INCLUDE FILES      *
                        *                          *
                        ****************************/
#ifndef _SYMBLSVR_
#include "symblsvr.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 __LPROFILE__
#include "lprofile.h"
#endif

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

                       /****************************
                        *                          *
                        *    EXTERNAL VARIABLES    *
                        *                          *
                        ****************************/
extern U32 numberOfModulesLoaded;
extern U16 curbyte;
extern CHAR errbuf[];
extern U32 ldrFlags;   /* Defined in LDR.C - global flags */
extern U16 toolSelect; /* define in LPROFILE.C */
extern U32 startRangeNotSet, endRangeNotSet;

                       /****************************
                        *                          *
                        *     LOCAL PROTOTYPES     *
                        *                          *
                        ****************************/
RETCODE PRIVATE ProcessDbgAsmSection(HANDLE hfile, U16 *pstype,
                                     U16 *psindex,
                                     U32 *pmaddress, U32 *pmoduleSize);

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

/*****************************************************************************
**
**  ProcessDbgAsmBlock
**
** Process BB10 blocks - asm/compiler generated symbols
** BB11 blocks live inside these, as do assembly-generated NN sections.
** Loop over all BB10 blocks clustered together.
**
** hfile      (in)    - file handle.
** blockSize  (in)    - size of block (in bytes on disk)
** moduleName (in)    - name from loadfile
** createAsm  (in)    - whether or not to create asm module
** updateModule (in)  - update the module address range with asm address
**                      range (to support MRI ASM line numbers)
**
*****************************************************************************/
RETCODE ProcessDbgAsmBlock(HANDLE hfile, U32 blockSize, LPSTR moduleName,
                           BOOLEAN createAsm,
                           SYM_DESCRIPTOR updateModule) {
   SYM_DESCRIPTOR moduleDesc;
   CHAR vers[IEEE_IDNLEN]; /* generic text buffer */
   TIMESTAMP_TYPE ts;
   U16 blockType, sectionType, sectionIndex, toolType;
   U32 moduleAddress, moduleSize, nextBlockPos;
   U32 moffset, toffset;
   BOOLEAN ondemand;
   OFFSET_ADDR_RANGE_TYPE modRange;
   RETCODE symerr, err;
   LONG filePos, blockPos;
   U16 cbyte, nindex, atnType, moduleType, nrecs;
   U32 tindex, nvalue;
   LOOP_VAR i;

   //**Hera 08/21/96
   U16 sindex;
   SYM_DESCRIPTOR symP;
   BOOLEAN isConst;
   U32 fileOffset,typeDelta;
   VAR_STORAGE_CLASS varClass;
   //**Hera

   // Note that blocks belonging to a particular module come in the following
   // sequence (MRI C):
   //    BB1   types
   //    BB3   source symbols
   //    BB5   source line numbers
   //    BB10  assembly info
   // Since there can also be assembly modules with no preceding high-level
   // debug info (such as is found in BB3/BB5), we clear the module descriptor
   // passed in after loading the BB10 (its at the end of this chain).

   // initialize
   modRange.offsetStartAddr = startRangeNotSet;
   modRange.offsetEndAddr = endRangeNotSet;

   //**Hera 08/22/96**/
   if ((LOAD_ASM(ldrFlags) && createAsm) || updateModule)
   {
      if (createAsm) {
	 moffset = toffset = 0L;
         ondemand = FALSE;
	 if ((err = FindBaseCodeIndex(&sectionIndex)) != GOOD) {
              Warning(err);
              nextBlockPos = Seek695File(hfile, 0L, SEEK_CUR);
         }
         if ((symerr = SymAddModuleCreate(moduleName,
                                          sectionIndex,
                                          &ts, &modRange,
                                          moffset, ondemand,
					  toffset, &moduleDesc)) != GOOD)
	 {
            err = ER_CANNOT_ADD_ASM_MOD;
            WarningEx(err, (LPSTR)moduleName);
	    nextBlockPos = Seek695File(hfile, 0L, SEEK_CUR);
            return err;
	  }
      }//if(createAsm)
     else
	  SymAddModuleOpen(moduleName,"",&fileOffset,&typeDelta);
   }
   //**Hera**/

   // Loop over BB10 blocks 
   while (1) {
      /* NOTES: 09/29/93 - Nghia
      ** BB10 = {$F8}{$0A}{n1}{Id}{Id}{n2}[[]]...
      ** Applied MicroSystem 695 converter does not generate {id}{n2}
      */
      Peek695Byte(hfile, &cbyte);
      if (cbyte != RT_BB) {      
         /* Throw away object file name (0-length string) */           
         Get695Idn(hfile, vers);
         Get695Number(hfile, &toolType);  /* not used */
         
         Peek695Byte(hfile, &cbyte);
         if (cbyte != RT_BB && cbyte != RT_BE /**Hera 11/19/96**/) {
            /* Note: only MRI generates tool version and timestamp.
               Cosmic does not generate either.  Sierra generates tool
               version only.  All Loader code should be generic in its
               parsing and not be conditionalized for toolchain.
            */
            Get695Idn(hfile, vers);           /* tool version (not used) */
            /* Note: we do have true timestamp information for BB10 blocks.  
            ** It should be used to fixup timestamp info in BB3 record, if it
            ** already exists.  Also, if BB3 follows, it should *not*
            ** trounce existing timestamp info created by BB10 mod create.
            ** NOTES: 09/14/93 - Nghia
            ** BB10 Module's timestamp is not important in debugging.
            ** Instead, file's timestamp has been used for timestamp checking.
            */
            Peek695Byte(hfile, &cbyte);
            if (cbyte != RT_BB && cbyte != RT_BE /**Hera 11/19/96**/)
               Get695Time(hfile, &ts);
         }
      }
      
      /* Loop over NN records and BB11 blocks within this BB10 */
      while (1) {
         /* Switch here: can either find BB11 blocks, or one of the following:
         ** NN/ATN/ASN
         ** NN/ATN/mod misc 55
         */
         Peek695Byte(hfile, &cbyte);
         if (cbyte != RT_BB && cbyte != RT_NN) {
            break; // BB11 loop
         }
         if (cbyte == RT_NN) {
            MatchRecord(hfile, RT_NN);
            /* NOTES: Name *may* be a public symbol name.
            ** Having it defined here gives a nice correlation between
            ** low-level assembly blocks and the public symbols that
            ** are defined within them.  Someday when we have a symbol
            ** browser we can add support for this.
            */
            Get695Nrecord(hfile, &nindex, (LPSTR)vers);
            if ((Match2Record(hfile, RT_ATN) != GOOD) ||
               (ProcessATN(hfile, &nindex, &tindex, 0L, &atnType) != GOOD)) {
               /* Sync to the next possible NN record */
               if ((err = SyncTo(hfile, RT_NN, &filePos)) != GOOD)
                     return(err);
               continue;
	    }
            switch(atnType) {
	       case ATN_STATIC_ASM:  /* ATN 19 - [x1] [x2] ASN */
                  
                  Get695Number(hfile, &nrecs);
                  /* May be global indicator (if not present, indicates
                  ** local symbol).
                  */

                  //**Hera 08/29/96**/
                  varClass = STATIC_VAR_CLASS;
                  Peek695Byte(hfile, &cbyte);
                  if (cbyte == ATN19_GLOBAL)
                  {
                     Get695Byte(hfile, &cbyte);
                     varClass = GLOBAL_VAR_CLASS;
                  }
                  //**Hera**/

                  /* NOTES: 09/20/93 - Nghia
                  ** [x1] = nrecs is not the number of ASN records following
                  ** HP generate [x1] = 0, 1, 36,... but there always 1 ASN
                  */
                  if ((Match2Record(hfile, RT_ASN) != GOOD) ||
                     (ProcessASN(hfile, &nindex, &nvalue) != GOOD))
		     SyncTo(hfile, RT_NN, &filePos);

                  //**Hera 08/22/96*/
	          if (FindBaseIndex(nvalue, &sindex, &isConst) != GOOD) {
		  /* Try the default data section */
                      if ((err = FindBaseDataIndex(&sindex)) != GOOD) {
                           Warning(err);
                           break; /* Continue to the next variable */
		     }
                      isConst = FALSE;
		  }      
                  if(tindex != BI_JUMP)
                  {
		    symerr = SymAddVar((LPSTR)vers,
			      sindex,  /* section index */
		              tindex,  /* TypeIndex*/
			      varClass,
                  	      NOT_REG,
                  	      (ADD_VAR_ADDR_UNION *)&nvalue,
			      isConst,
			      TRUE,  /* address is valid ?*/
			      &symP);

		    if ((symerr != GOOD) && (symerr != ER_DUPLICATE_GLOBAL_NAME))
		         WarningEx(ER_CANNOT_ADD_SYM, (LPSTR)vers);
                  }  
		  //**Hera**/
                  break;
	       case ATN_MOD_MISC:    /* ATN 64 */
                  Get695Number(hfile, &moduleType);
                  /* assume moduleType == MMISC_55 */
                  Get695Number(hfile, &nrecs);
                  /* throw away symbol name - vers == symbol name */
                  Get695Idn(hfile, vers);
                  for (i=0; i < nrecs; i++) {
                     if ((Match2Record(hfile, RT_ASN) != GOOD) ||
                        (ProcessASN(hfile, &nindex, &nvalue) != GOOD)) {
                        SyncTo(hfile, RT_NN, &filePos);
                        break; /* for loop */
                     }
                  }
                  break;
               default:
                  wsprintf(errbuf, "%d.", atnType);
                  WarningEx(ER_ATTR_NOT_HANDLED, errbuf);
                  /* Sync to the next possible NN record */
                  if ((err = SyncTo(hfile, RT_NN, &filePos)) != GOOD)
                     return(err);
                  break;
            }
            continue;
         }
         if (cbyte == RT_BB) {
            blockPos = Seek695File(hfile, 0L, SEEK_CUR);
            MatchRecord(hfile, RT_BB);
            /* Throw away string */
            Get695BB(hfile, &blockSize, (LPSTR)vers, &blockType);
            if (blockType != BB_ASMSECTION)
               break; /* BB11 loop */
               
            // We only care about the code/mixed address region for this
            // asm block, the remainder of asm section types are discarded.
            if (ProcessDbgAsmSection(hfile, &sectionType, &sectionIndex,
                                 &moduleAddress, &moduleSize) != GOOD) {
               if ((err = SkipOver(hfile, blockPos, blockSize, blockType))
                   != GOOD) return(err);
               nextBlockPos = Seek695File(hfile, 0L, SEEK_CUR);
               continue;
            }
            // 11/18/94 - Nghia
            // Collect all code/mixed address ranges for the BB10
            if (((sectionType == ST_ASM_CODE) ||
                (sectionType == ST_ASM_CODEDATA)) &&
                ((LOAD_ASM(ldrFlags) && createAsm) || updateModule)) {
               //**Hera 11/06/96**/
               //moduleSize = (moduleSize > 0) ? moduleSize : 1L;
               if(moduleSize == 0)
                 continue;
               //**Hera**/
               // Assembly module only
               modRange.offsetStartAddr = min(moduleAddress,
                                              modRange.offsetStartAddr);
               moduleAddress += (moduleSize-1);  /* JUDY 6/7/96 */
               /* <Judy 7/11/96>
               modRange.offsetEndAddr = max(moduleAddress,
                                              modRange.offsetEndAddr); */

               modRange.offsetEndAddr = moduleAddress;

            }
	 }  // if BB
      }  // while NN/BB11 inside this BB11

      // NOTES: 09/30/93 - Nghia
      // Only create ASM module if user said so and createAsm is TRUE

      //**Hera 08/22/96**/
    if ((LOAD_ASM(ldrFlags) && createAsm) || updateModule) {
       if ((symerr = SymAddModuleClose(FALSE)) != GOOD)
               Warning(symerr);
	 if(createAsm)
         {
            // NOTES: 09/14/93 - Nghia
            // Count the ASM module loaded for the total modules loaded
            ++numberOfModulesLoaded;
            modRange.offsetStartAddr = startRangeNotSet;
            modRange.offsetEndAddr = endRangeNotSet;
	 } // if createAsm

           else
           {
	   // update the input moduleDescriptor with the new module
	   // address range from the ASM block.
           if ((symerr = SymSetSymbolAddrByDesc(updateModule,
                                                &modRange)) != GOOD)
              Warning(ER_SYM_NOT_UPDATED);
           // Make sure that it only update once.
           updateModule = NULL;
         }
      }
       
      if ((err = MatchRecord(hfile, RT_BE)) != GOOD) {
         Unget695Byte(hfile, curbyte);
         SyncTo(hfile, RT_BB, &filePos);
         // 03/03/94 - Nghia - Introl compiler: BB10 does not have BB11
         if (toolSelect == INTROL_TOOLCHAIN) return err;
         break;
      }
      else
      {
	 createAsm = TRUE;
	 break;
      }       
      //**Hera**/
   }  /* while BB10 blocks remain */

   return (GOOD);
}  /* ProcessDbgAsmBlock */

/*****************************************************************************
**
**  ProcessDbgAsmSection
**
** psectionType - pointer to section type
** psectionIndex - pointer to section index
** pmoduleAddress - pointer to address for section
** pmoduleSize - size of the block 
**
*****************************************************************************/
RETCODE PRIVATE ProcessDbgAsmSection(HANDLE hfile, U16 *psectionType,
                                     U16 *psectionIndex, U32 *pmoduleAddress,
                                     U32 *pmoduleSize) {
   RETCODE err;
   
   if (((err = Get695Number(hfile, psectionType)) != GOOD) ||
       ((err = Get695Number(hfile, psectionIndex)) != GOOD) ||
       ((err = Get695Offset(hfile, pmoduleAddress)) != GOOD) ||
       ((err = MatchRecord(hfile, RT_BE)) != GOOD) ||
       ((err = Get695Offset(hfile, pmoduleSize)) != GOOD)) 
     return err;
   return GOOD;
}  /* ProcessDbgAsmSection */
/*****************************************************************************
**
** StripPathString
**
** moduleName - the original module name
** newName    - the new module Name
**
*****************************************************************************/
RETCODE StripPathString(LPSTR moduleName, LPSTR *newName) {
   BOOLEAN done = FALSE;
   LOOP_VAR strLen, i;

   *newName = moduleName; /* Assign pointer */
   /* Check if moduleName is NULL */
   if ((strLen = strlen(moduleName)) >= 0) {
      strLen -= 1; /* String start from 0 index */
      for (i = strLen; i > 0 && !done; i--) {
         switch(*(moduleName+i)) {
            case '.':
               *(moduleName + i) = (CHAR)'\0';  /* Strip the suffix */
               break;
            case '\\':
            case '/':
            case ':':   
               if (i > 0)
                 *newName = (LPSTR)moduleName + (i + 1);
               done = TRUE;
               break;
         }
      }
   }   
   return(GOOD);
}  /* StripPathString */

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