/****************************************************************************
**
**  Name:  LSECTION.C
**
**  Description:
**      Process section part of IEEE 695 binary file.
**
**  Status:  CODED
**
**  $Log:   S:/tbird/arcppc/l695/lsection.c_v  $
** 
**    Rev 1.0   17 Jan 1997 09:21:22   kevin
** Initial revision.
** 
**    Rev 1.0   07 Sep 1995 10:32:24   gene
** Initial revision.
** 
**    Rev 1.28   25 Feb 1994 17:45:20   nghia
** Remove warning on MAX_SECTIONS - Bruce requested.
** 
**    Rev 1.27   23 Sep 1993 11:11:42   nghia
** Revised CreateDefaultSection() to use basetype value when creating default
** section base.  This will make symbol lookup works better.
** 
**    Rev 1.26   23 Aug 1993 10:43:04   nghia
** Fixed bug mergesection command does not function.
** 
**    Rev 1.25   03 Aug 1993 17:47:50   nghia
** Revised to check for MergedSection flag - no need to read from file.
** Removed LERR_xxxx to use standard error codes.
** 
**    Rev 1.24   28 Jul 1993 15:14:32   nghia
** Added useDefaultSection to create default sections when user select loadfile
** which contains an incompatible tool.
** 
**    Rev 1.23   20 Jul 1993 18:11:06   nghia
** Fixed bug: loader generate "Invalid stack size" error.
** - strstr() compares to not NULL.
** 
**    Rev 1.22   16 Jul 1993 13:03:34   courtney
** Suppress 'section not found' error (refer: PPR 8279, 8228).
** 
**    Rev 1.21   25 Jun 1993 15:03:12   mindy
** 
**    Rev 1.20   14 Jun 1993 11:27:32   nghia
** Merged "pv bmwa" and Ernie changes.
** 
**    Rev 1.19   06 Jun 1993 21:59:40   courtney
** Removed calls to ErrExit.
** 
**    Rev 1.18   25 May 1993 10:35:48   ernie
** Virtualized _llseek() calls in Seek695File when file buffering added.
** 
**    Rev 1.17.1.1   07 Jun 1993 12:07:08   courtney
** Revisions for release 1.4.
** 
**    Rev 1.17.1.0   03 Jun 1993 18:53:34   nghia
** Revised to use the new error code.
** Reported error using only the Warning() and WarningEx().
** 
**    Rev 1.17   03 May 1993 15:18:54   nghia
** Merged Mindy's code to support COSMIC.
** 
**    Rev 1.16   16 Apr 1993 14:00:20   nghia
** Revised ProcessSecPart() to handle merging all sections into the default
** sections.
** 
**    Rev 1.15   12 Apr 1993 18:10:14   nghia
** Revised ProcessSectionPart() to automatically create code and data section
** for the loadfile upon failing to find the sections defined in PWRVIEWS.INI.
** Optimized code for faster processing section.
** 
**    Rev 1.14   31 Mar 1993 17:44:44   nghia
** Revised to coding standard.
** - Missed revision 1.9
** 
**    Rev 1.13   25 Mar 1993 15:17:14   courtney
** Need to keep default data section, even if zero size, for symbol
** loading.
** 
**    Rev 1.12   23 Mar 1993 18:28:50   courtney
** Revised declaration of PSGetData to be RETCODE as prototype.
** 
**    Rev 1.11   23 Mar 1993 18:26:38   courtney
** Revised to current prototype spec in header files.
** 
**    Rev 1.10   23 Mar 1993 18:11:56   courtney
** Kick out zero-sized and null-named sections (they incur overhead
** in both Loader and Symbol Table); do not increment section count
** for these.  Alert user if limit on number of sections (MAX_SECTIONS)
** is hit.
** 
**    Rev 1.8   08 Mar 1993 10:54:46   nghia
** Major cleanup for names and comments.
** 
**    Rev 1.7   03 Dec 1992 17:28:00   courtney
** Don't add sections with null names to symbol table (come from assembly
** files).
** 
**    Rev 1.6   21 Oct 1992 16:38:16   courtney
** Cleaned up error reporting to use string resource.
** 
**    Rev 1.5   14 Sep 1992 10:43:30   courtney
** Switch to TMalloc; tie all section base loading to symbol load
** (had forgotten the fake base for locals).
** 
**    Rev 1.4   03 Jun 1992 10:33:28   courtney
** Always processes section part now, even if symbols are not loaded.
** Added routines to fetch load region info for code, data (vars,
** zerovars) regions.
** 
**    Rev 1.3   03 Apr 1992 15:16:20   courtney
** Stack handling - save top,size of stack in statics for later PPre
** callback.  Obtain info from 'stack' section generated by compiler
** (MRI-specific!).
** 
**    Rev 1.2   09 Jan 1992 16:43:32   courtney
** Comment on freeing sections.
** 
**    Rev 1.1   31 Dec 1991 10:48:50   courtney
** Added routine to free allocated section.
** 
**    Rev 1.0   12 Dec 1991 13:26:54   courtney
** Initial revision.
**
**  $Header:   S:/tbird/arcppc/l695/lsection.c_v   1.0   17 Jan 1997 09:21:22   kevin  $
**
**  Copyright (C) 1991 Microtek International.  All rights reserved.
**
*****************************************************************************/
                       /****************************
                        *                          *
                        *       INCLUDE FILES      *
                        *                          *
                        ****************************/
#include <io.h>

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

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

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

#ifndef __ERR__
#include "err.h"
#endif

#ifndef __LDEBUG__
#include "ldebug.h"
#endif

#ifndef __LPROFILE__
#include "lprofile.h"
#endif

                       /****************************
                        *                          *
                        *     LOCAL DEFINITIONS    *
                        *                          *
                        ****************************/
SEC_INFO *section_info[MAX_SECTIONS+3]; /* Added 3 more for deafault sections */
U16 nSections, codeSecIndex, dataSecIndex, rtaSecIndex;
BOOLEAN findCode, findData, findRTA;
BOOLEAN mergeSections;
                       /****************************
                        *                          *
                        *    EXTERNAL VARIABLES    *
                        *                          *
                        ****************************/
extern BOOLEAN hasStackInfo;
extern CHAR errbuf[];
extern HDR695 Hdr695;
extern U32 stackTop, stackSize;
extern CHAR sectionNames[MAX_NUM_SECTION_NAMES][SIZE_SECTION_NAME];
extern CHAR pwrViewsDir[];
extern BOOLEAN useDefaultSection;

                       /****************************
                        *                          *
                        *     LOCAL PROTOTYPES     *
                        *                          *
                        ****************************/
RETCODE PRIVATE PSGetSection(CHAR *, U16 *);
RETCODE PRIVATE CreateDefaultSection(CHAR *, U16, U16, BASE_TYPE);
RETCODE PRIVATE GetSectionInfo(SEC_INFO *, HANDLE, BASE_TYPE *);

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

/******************************************************************************
**
**  ProcessSecPart
**
******************************************************************************/
RETCODE ProcessSecPart(HANDLE hfile, U16 symflag) {
   BASE_TYPE basetype;
   SEC_INFO *psection;
   U16 index;     /* number of sections processed */
   RETCODE err;

   /*
   ** ALGORITHM:
   ** if (mergeSection || useDefaultSection)
   **    createDefault sections.
   ** else
   **    while (match ($E6) && (numSections < MAX_SECTIONS)) {
   **       get sec index
   **       get ST (name)
   **       get SA (alignment)
   **       get ASS (size)
   **       get ASL (offset)
   **       if (reach MAX_SECTIONS)
   **          discard the rest of all remaining sections.
   **    }
   */

   /* Initialize number of section to 0 */
   index = nSections = 0;
   /* Get MergeSections flag from PWRVIEWS.INI */
   if (useDefaultSection || mergeSections) {
      /* Create default section for CODE, DATA, RTA */
      if ((err = CreateDefaultSection(SBASE_RTA, index, symflag,
                                      BASE_UNKNOWN)) != GOOD)
         return(err);
      rtaSecIndex = index++;
      nSections = index;  /* Set it here so PSGetSection can search */
      /* Create the default code section */
      if ((err = CreateDefaultSection(SBASE_CODE, index, symflag,
                                      BASE_CODE)) != GOOD)
         return(err);
      codeSecIndex = index++;
      /* Create the default data section */
      if ((err = CreateDefaultSection(SBASE_DATA, index, symflag,
                                      BASE_DATA)) != GOOD)
         return(err);
      dataSecIndex = index;
      /* Save the number of sections */
      nSections = index++;
      /* Retrieve the Stack Section if possible */
      if ((psection = (SEC_INFO *)TMalloc(sizeof(SEC_INFO))) != NULL) {
         Seek695File(hfile, Hdr695.hdr_sec, SEEK_SET);
         while (MatchRecord(hfile, RT_ST) == GOOD) {
            if (GetSectionInfo(psection, hfile, &basetype) != GOOD) break;
            if (psection->name[0] == ' ') continue;
            /* section with "stack" in it must be the stack. */
            /* NOTES: Nghia - 7/20/93
            ** strstr() returns NULL if s2 does not occur in s1.
            */
            if (strstr(psection->name, STACK_SEC) != NULL) {
               hasStackInfo = TRUE;
               stackTop = psection->offset;
               stackSize = psection->size;
               break;
            }
         }
         TFree((LPSTR)psection);
      }
      /* Exit out */
      goto DoneProcessSections;
   } /* MergeSections */

   /* Construct array of structs for section info: SEC_INFO
   ** We don't know how many sections there will be, so we allocate
   ** as needed.  For quick access, we keep an array of pointers
   ** to these section info blocks.
   */
   /* first, seek to Section Part of file */
   if (Seek695File(hfile, Hdr695.hdr_sec, SEEK_SET) == -1L)
      return (ER_BAD_SEEK);
   while (MatchRecord(hfile, RT_ST) == GOOD) {
      if ((psection = (SEC_INFO *)TMalloc(sizeof(SEC_INFO))) == NULL) {
         return(ER_NO_MEMORY);
      }
      if ((err = GetSectionInfo(psection, hfile, &basetype)) != GOOD) {
         TFree((LPSTR)psection);
         return(err);
      }
      /* Save stack info: with MRI 4.2A, stack is a section
      ** the 4.1 and prior public '????STACKTOP' symbol is no
      ** longer meaningful
      */
      if (strstr(psection->name, STACK_SEC) != NULL) {
         hasStackInfo = TRUE;
         stackTop = psection->offset;
         stackSize = psection->size;
      }
      /* Base address wants to be 0L for 68K (MRI C), since
         all variables are given absolute addresses */
      if (symflag) {
         /* Thow away any section that matched the follwoing conditions:
         ** 1. For assembly files generate sections with null names.
         ** 2. ROM labels in user code have no size (See EXCEPTION).
         ** Since the symbol table reserved about 4K for each section,
         ** this will save alot of overhead space.
         */
         if ((psection->name[0] == ' ') || ((psection->size == 0) &&
            /* Except for the defined data section name: even if 0-sized,
            ** we keep it for our default lookup
            */
            (stricmp((CHAR *)&psection->name[0],
                      (CHAR *)&sectionNames[DATA_SECT][0]) != 0)) ) {
            TFree((LPSTR)psection);
            continue;
         }
         /* Create a base for the section */
         if (SymAddBaseCreate((LPSTR)psection->name,
                                 index, 0L, basetype) != GOOD) {
            Warning(ER_SYMBASE);
         }
      }
      /* Added section to table */
      section_info[index++] = psection;
      if (index == MAX_SECTIONS) {
         // 02/24/94 - Nghia
         // Bruce requested to remove this warning message
         // Warning(ER_TOOMANY_SEC);
         break; /* Discard the the remaining sections */
      }
   }  /* while */

   /* Check for user defined - Create default section for CODE, DATA, RTA */
   if ((err = CreateDefaultSection(SBASE_RTA, index,
                                   symflag, BASE_UNKNOWN)) != GOOD)
      return(err);
   rtaSecIndex = index++;
   nSections = index;  /* Set it here so PSGetSection can search */
   /* Check the default code section */
   if (PSGetSection(&sectionNames[CODE_SECT][0], &codeSecIndex) != GOOD) {
      /* For 2.0 release, no warning is issued, refer to PPR: 8279, 8228. */
      if ((err = CreateDefaultSection(SBASE_CODE, index, symflag,
                                      BASE_CODE)) != GOOD)
         return(err);
      codeSecIndex = index++;
   }
   /* Check the default data section */
   if (PSGetSection(&sectionNames[DATA_SECT][0], &dataSecIndex) != GOOD) {
      /* For 2.0 release, no warning is issued, refer to PPR: 8279, 8228. */
      if ((err = CreateDefaultSection(SBASE_DATA, index, symflag,
                                      BASE_DATA)) != GOOD)
         return(err);
      dataSecIndex = index++;
   }
   /* Save the number of sections */
   nSections = index;

DoneProcessSections:
/* !!! - DO NOT REPORT WARNING FOR NOW
   if (!hasStackInfo)
      Warning(ER_NO_STKINFO);
*/
   Clear695Byte();
   /* Finished processing section type records */
   return(GOOD);
}  /* ProcessSecPart */

/******************************************************************************
**
**  FreeSections - free memory associated with section info struct
**
******************************************************************************/
RETCODE FreeSections(U16 numSection) {
   LOOP_VAR i;

   /* NOTES:
   ** this can only be called after load is complete.  Only call it if
   ** ondemand is *false*, otherwise we will need to retain section info as
   ** static data inside the Loader DLL for later ondemand loading of
   ** individual modules. Modified 9-8-92  cpm
   ** Also called on each *initial* load.
   */
   for (i = 0; i < numSection; i++) {
      if (TFree((LPSTR)section_info[i]) != GOOD) {
         Warning(ER_BAD_FREE);
         return(ER_BAD_FREE);
      }
   }
   nSections = codeSecIndex = dataSecIndex = rtaSecIndex = 0;
   findCode = findData = findRTA = FALSE;

   return(GOOD);
}  /* FreeSections */

/******************************************************************************
**
**  PSGetCode - Get core region
**
******************************************************************************/
RETCODE PSGetCode(U32 *pstartAddr, U32 *prange) {
   U16 indexVars;
   RETCODE err;

   *pstartAddr = RANGE_NOT_SET;
   *prange = 0L;
   if ((err = FindBaseCodeIndex(&indexVars)) != GOOD)
      return(err);
   *pstartAddr = section_info[indexVars]->offset;
   *prange = section_info[indexVars]->size;
   return(GOOD);
}  /* PSGetCode */

/******************************************************************************
**
**  PSGetData - Get load region for data
**
******************************************************************************/
RETCODE PSGetData(U32 *pstartAddr, U32 *prange) {
   U16 indexVars;
   RETCODE err;

   /* Get array index for sections */
   *pstartAddr = RANGE_NOT_SET;
   *prange = 0L;
   if ((err = FindBaseDataIndex(&indexVars)) != GOOD) {
      return(err);
   }
   *pstartAddr = section_info[indexVars]->offset;
   *prange = section_info[indexVars]->size;
   return(GOOD);
}  /* PSGetData */

/******************************************************************************
**
**  PSGetSection - get index of section in section_info table
**
******************************************************************************/
RETCODE PRIVATE PSGetSection(CHAR *secname, U16 *index) {
   U16 i;

   *index = 0;
   for (i = 0; i < nSections; i++) {
      if (stricmp(section_info[i]->name, secname) == 0) {
         *index = i;
         return (GOOD);
      }
   }
   return(ER_SECTION_NOT_FOUND);
}  /* PSGetSection */

/******************************************************************************
**
**  CreateDefaultSection - create default section in section_info table
**
******************************************************************************/
RETCODE PRIVATE CreateDefaultSection(CHAR *secName, U16 secIndex,
                                     U16 symflag, BASE_TYPE baseType) {
   SEC_INFO *psection;

   /* Set up dummy base for register/auto vars */
   if ((psection = (SEC_INFO *)TMalloc(sizeof(SEC_INFO))) == NULL) {
      return(ER_NO_MEMORY);
   }
   lstrcpy((LPSTR)psection->name, (LPSTR)secName);
   psection->sindex = secIndex;
   psection->size = 200; /* dummy values */
   psection->offset = 0L;
   if ((symflag) && (SymAddBaseCreate((LPSTR)secName,
         secIndex, 0L, baseType) != GOOD) ) {
      Warning(ER_SYMBASE);
   }
   /* Linked to section_info table */
   section_info[secIndex] = psection;
   return(GOOD);
} /* CreateDefaultSection */

/******************************************************************************
**
**  GetSectionInfo - retrieve section information from loadfile
**
******************************************************************************/
RETCODE PRIVATE GetSectionInfo(SEC_INFO *psection, HANDLE hfile,
                                                      BASE_TYPE *basetype) {
   CHAR idn[IEEE_IDNLEN];
   U16 sattr;     /* section attribute (code, ROM data, or data) */
   U16 sindex;    /* section index */
   U16 srecord;   /* other section records */
   U16 stype;     /* section type */
   U16 cbyte;
   U32 svalue;    /* section value (depends on record type) */
   RETCODE err = GOOD;

   Get695Number(hfile, &sindex);
   if ((err = Get695STrecord(hfile, &sattr, &stype)) != GOOD)
      return(err);
   switch(stype) {
      case ST_AS:  /* normal section */
         psection->sindex = sindex;
         Get695Idn(hfile, (LPSTR)idn);
         /* NOTES: 04/01/93 - Nghia - Process optional fields.
         ** ST record = {$E6}{n1}{l}{Id}[n2][n3][n4]
         **
         ** IEEE695 Spec. v4.1, page C-2 - For an absolute file
         ** A section part = {ST [SA] ASS ASL} and there must be at most
         ** one of the above record for any section index.
         */
         Peek695Byte(hfile, &cbyte);
         /* Strip any byte that is not a SA = 0xE7 or ASS = 0xE2 signature */
         while ((cbyte != SR_SA) && (cbyte != RP_SECTION)) {
           Get695Number(hfile, &cbyte);
           Peek695Byte(hfile, &cbyte);
         }
         strcpy(psection->name, idn);
         psection->type = SECTYPE_ABS;
         psection->modifier = sattr;
         /* IMPORTANT: Get either optional [SA] or {ASS} record */
         if (Get695Srecord(hfile, &srecord, &svalue) == SR_SA) {
            /* svalue is section alignment */
            psection->align = svalue;
            /* Get ASS record for the ST */
            Get695Srecord(hfile, &srecord, &svalue);
         } else {
            psection->align = 0;
         }
         /* Either case, the svalue is section size - so save it */
         psection->size = svalue;
         /* Get ASL record for the ST */
         if (Get695Srecord(hfile, &srecord, &svalue) != SR_ASL)
            return(ER_BAD_SECREC);
         /* svalue is section base addr */
         psection->offset = svalue;
         *basetype = FindSecModifier(sattr);
         break;
      default:
         /* other record types not handled yet */
         err = ER_REC_NOT_HANDLED;
         break;
   }
   return(err);
}
/******************************** E O F ***********************************/
