/****************************************************************************
**
**  Name:  LEXTERN.C
**
**  Description:
**      Process external definitions (from Public Part of file) in IEEE
**      695 file.
**
**  Status:  CODED
**
**  $Log:   S:/tbird/mt2_68k/l695/lextern.c_v  $
** 
**    Rev 1.0   13 Feb 1997 08:50:54   gene
** Initial revision.
** 
**    Rev 1.0   07 Sep 1995 10:32:16   gene
** Initial revision.
** 
**    Rev 1.13   18 Jan 1994 16:53:26   nghia
** Revised ldrMangle to have correct global state.
** 
**    Rev 1.12   03 Aug 1993 17:41:02   nghia
** Removed LERR_xxxx to use standard error codes.
** 
**    Rev 1.11   14 Jun 1993 11:20:30   nghia
** Merged "pv bmwa" and trunk.
** 
**    Rev 1.10   06 Jun 1993 21:21:24   courtney
** Demangle public labels before storing to symbol table - C++.
** 
**    Rev 1.9   25 May 1993 10:35:16   ernie
** Virtualized _llseek() calls in Seek695File when file buffering added.
** 
**    Rev 1.8   12 Apr 1993 18:00:42   nghia
** Revised ProcessExternPart() to Check Symbol section index before goto the 
** default one.  Cleanup for coding standard.
** 
**    Rev 1.7.1.3   07 Jun 1993 12:05:22   courtney
** Revisions for release 1.4.
** 
**    Rev 1.7.1.2   03 Jun 1993 18:49:26   nghia
** Revised to use the new error codes.
** Reported error using only the Warning() and WarningEx().
** 
**    Rev 1.7.1.1   19 May 1993 18:37:22   nghia
** Rev 1.7.1.0 is rev 1.8
** Revised ProcessExtPart() to report warning on any unsupport ATN.
** 
**    Rev 1.7.1.0   18 May 1993 17:47:32   nghia
** No change.
** 
**    Rev 1.7   23 Mar 1993 17:08:02   nghia
** Updated to use the new MatchRecord and Match2Record.
** 
**    Rev 1.6   08 Mar 1993 10:40:44   nghia
** Major cleanup for names and comments.
** Added check to handle MRI missing {n4} in ATI record of a public symbol.
** Used sectionNames table to extract section information.
** 
**    Rev 1.5   21 Oct 1992 16:37:38   courtney
** Cleaned up error reporting to use string resource.
** 
**    Rev 1.4   08 May 1992 16:33:12   courtney
** Parse RT_NX records so loading publics can continue (had stopped).
** 
**    Rev 1.3   03 Apr 1992 15:18:20   courtney
** New stack handling obsoletes former ????STACKTOP code.
** 
**    Rev 1.2   02 Apr 1992 17:23:46   courtney
** Handling of stack top.
** 
**    Rev 1.1   24 Mar 1992 21:08:50   courtney
** Save stackTop as static data for later callback.
** 
**    Rev 1.0   12 Dec 1991 13:43:52   courtney
** Initial revision.
**
**  $Header:   S:/tbird/mt2_68k/l695/lextern.c_v   1.0   13 Feb 1997 08:50:54   gene  $
**
**  Copyright (C) 1991 Microtek International.  All rights reserved.
**
*****************************************************************************/

                       /****************************
                        *                          *
                        *       INCLUDE FILES      *
                        *                          *
                        ****************************/
#include <io.h>
#ifndef _SYMBLSVR_
#include "symblsvr.h"
#endif
#ifndef __LDR__
#include "ldr.h"
#endif
#ifndef __LDEBUG__
#include "ldebug.h"
#endif
#ifndef __ERR__
#include "err.h"
#endif
#ifndef __LMANGLE__
#include "lmangle.h"
#endif
#ifndef __LFLAGS__
#include "lflags.h"
#endif

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

                       /****************************
                        *                          *
                        *    EXTERNAL VARIABLES    *
                        *                          *
                        ****************************/
extern HDR695 Hdr695;
extern U32 stackTop;
extern CHAR errbuf[];
extern U16 ldrDemangle;
                       /****************************
                        *                          *
                        *     LOCAL PROTOTYPES     *
                        *                          *
                        ****************************/
STATIC LPSTR StripName(LPSTR);

                       /****************************
                        *                          *
                        *      EXECUTABLE CODE     *
                        *                          *
                        ****************************/
/******************************************************************************
**
**  ProcessExtPart
**
******************************************************************************/
/* Process public symbols from Public Part of file - place info into Symbol
   Table.  Note that this part of the file is processed *after* the Debug
   Part (which contains more attribute information for those symbols it
   knows about).
*/
RETCODE ProcessExtPart(HANDLE hfile) {
   BOOLEAN isConst;
   LPSTR sname;  /* pointer to underscore-stripped name */
   U16 at_typeid, nfields, atn_type;
   U16 cbyte;
   U16 nindex, adefn, nelts, sindex;
   U32 lvalue;
   U32 symerr;
   U32 tindex;  /* type index */
   U32 toffset=0;  /* place-holder */
   CHAR lname[IEEE_IDNLEN];
   RETCODE err = GOOD;
   CHAR *pname;  /* pointer to fixed-up name */

   /* first, seek to Extern Part of file */
   if (Seek695File(hfile, Hdr695.hdr_ext, SEEK_SET) == -1L)
      return (ER_BAD_SEEK);

   while (1) {
   /* NOTES: we are abandoning the checking of name index for successive
   ** (i.e., ATI) records to match the preceding NN record.  Likewise,
   ** abandoning re-checking the section index.  It is assumed that this
   ** is a valid .ABS file.  If this proves untrue empirically, then this
   ** code can have this error-checking added to it.
   */
      Get695Byte(hfile, &cbyte);
      switch (cbyte) {
         case RT_NN:  /* certain module names only */
         case RT_NX:  /* external function name - not loaded */
            Get695Nrecord(hfile, &nindex, (LPSTR)lname);
            break;
         case RT_NI:  /* public (external) symbol - code or data */
            Get695Nrecord(hfile, &nindex, (LPSTR)lname);
            sname = StripName((LPSTR)lname);
            /* ATI, ASI records follow */
            /* ATI: attribute record */
            Match2Record(hfile, RT_ATI);
            ProcessATI(hfile, &nindex, &tindex, &adefn, &nelts);
            /* ASI: value record */
            Peek695Byte(hfile, &cbyte);
            if (cbyte != RP_SECTION) {
               if (nelts != 0)
                  return(ER_BAD_ATI_RECORD_IN_FILE);
               Get695Byte(hfile, &cbyte);  /* Get rid of the one we just peek */
               /* Check for next byte is the start of an ASI record */
               Peek695Byte(hfile, &cbyte);
               /* This to handle the Sierra and others compilers */
               if (cbyte != RP_SECTION)
                  return (ER_BAD_ATI_RECORD_IN_FILE);  /* resynch required */
            }
            /* Process the followed ASI record */
            Get695Srecord(hfile, &nindex, &lvalue);
   /* Value is either base address (for variables), or value (for constants) */
   /* Add symbol here.
   ** NOTES: we always add symbols.  The Symbol Server handles various cases:
   **
   ** 1) adding a public symbol not found in the Debug Part (linked in
   **    from library or non-C objects)
   ** 2) updating the address for an extern declared in Debug Part (ATN5)
   ** 3) ignoring this info entirely, since a complete record for this
   **    symbol was already processed from a Debug definition for it.
   ** end Note
   **
   ** If the error is one of:
   **     ER_ADDRESS_UPDATED  (case 2 above)
   **     ER_PUBLIC_IGNORED   (case 3 above)
   ** then we ignore it.
   */
            if (tindex == T695_CODE) {  /* code */
               /* Find section index */
               if (FindBaseIndex(lvalue, &sindex, &isConst) != GOOD) {
                  /* Try the default code section */
                  if ((err = FindBaseCodeIndex(&sindex)) != GOOD) {
                     Warning(err);
                     break;
                  }
               }
               /* strip function signature for C++ function labels */
               if (ldrDemangle)
                  CppFixupFunction(sname, &pname, MOPEN);
               else
                  pname = sname;  /* pointer assign */

               symerr = SymAddLabelPublic((LPSTR)pname, sindex, lvalue);
            } else {  /* data */
               /* find section index */
               if (FindBaseIndex(lvalue, &sindex, &isConst) != GOOD) {
                  /* Try the default data section */
                  if ((err = FindBaseDataIndex(&sindex)) != GOOD) {
                     Warning(err);
                     break;
                  }
                  isConst = FALSE;
               }
               /* strip module signature for C++ data labels */
               if (ldrDemangle)
                  CppFixupGlobal(sname, &pname);
               else
                  pname = sname;  /* pointer assign */

               /* NOTES: This type index (tindex) will *always* map
               ** to a built-in type, so does not require a fix-up.
               */
               symerr = SymAddVarPublic((LPSTR)pname, sindex, tindex, lvalue);
            }
            if (symerr != GOOD) {
               /* this is not a serious error - perhaps only issue
               ** once for duration of load (set a flag), don't keep
               ** issuing.  On for debugging now.
               */
               if (symerr != ER_ADDRESS_UPDATED && symerr !=
                                             ER_PUBLIC_IGNORED) {
                  err = ER_CANNOT_ADD_PUBLIC;
                  WarningEx(err, (LPSTR)pname);
               }
            }
            break;
            /*
            ** Note: these are listed as '80960 call optimization'
            ** records in the 695 addendum (?).  They don't appear to
            ** give any useful information, so we eat up the bytes and
            ** ignore them.
            */
         case RP_ATTR:  /* lone ATN records - var misc records */
            Unget695Byte(hfile, cbyte);
            if (Match2Record(hfile, RT_ATN) != GOOD) {
               /* lets forget about loading publics */
               WarningEx(ER_CANNOT_ADD_PUBLIC, (LPSTR)sname);
               return(ER_CANNOT_ADD_PUBLIC);
            }
            if ((ProcessATN(hfile, &nindex, &tindex, toffset, &atn_type)
               != GOOD) || (atn_type != ATN_VAR_MISC)) {
               /* Display warning on ATN record not handle */
               wsprintf(errbuf, "%d.",atn_type);
               WarningEx(ER_ATTR_NOT_HANDLED, errbuf);
               /* NOTES: Nghia - We should try to synch up to the next
               ** possible NI.  However, the SyncTo() would not work
               ** because, extern section does not have block to detect.
               */
               return(GOOD);
            }
            /* We don't need this stuff */
            Get695Number(hfile, &at_typeid);
            Get695Number(hfile, &nfields);
            break;

         default:
            /* either end-extern part, or out of synch:
            check for RT_AT type records */
            return (GOOD);
      }
   }  /* while */

}  /* ProcessExtPart */

/******************************************************************************
**
**  ProcessATI
**
******************************************************************************/
RETCODE ProcessATI(HANDLE hfile, U16 *pnindex, U32 *ptindex, U16 *padefn,
        U16 *pnelts) {
   /*
   ** pnindex  - pointer to name index
   ** ptindex  - pointer to type index
   ** padefn   - pointer to attribute definition
   ** pnelts   - pointer to number of elements (if tindex != 0)
   */
   /* ATI :
   ** {$F1}{$C9}{symbolname index}{symboltype index}{attribute}{num elements}
   */
   *pnelts = 0;
   Get695Number(hfile, pnindex);   // symbolname index {n1}
   Get695Offset(hfile, ptindex);   // symtype index    {n2}
   Get695Number(hfile, padefn);    // attribute        {n3}
   /* NOTES: 02/29/93 - Nghia
   ** MRI does not generate {n4} field if {n2} is zero, which
   ** is not consistent with the IEEE 695 specification V4.1
   */
   if (*ptindex != 0) {
      Get695Number(hfile, pnelts);    // num elements  {n4}
   }
   return(GOOD);
}  /* ProcessATI */

/******************************************************************************
**
**  StripName
**
******************************************************************************/
/* Strip leading underscore from public symbols (code and data symbols).
   In this way, publics which were extern records during symbol loading
   of the Debug Part of the file will correctly be found and updated
   with address information from the Public Part.  Also, symbols linked
   in from library code/non-C objects will look proper to the user, who
   does not expect to find an underscore prepended (unless their mind
   has been warped by excessive exposure to Unix environments..)
   Return pointer to stripped-string.
*/
STATIC LPSTR StripName(LPSTR lpn1) {
   /* lpn1 - pointer to original string */
   if (lpn1[0] == '_')
      return ((LPSTR)&lpn1[1]);
   return (lpn1);
}  /* StripName */

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