/*****************************************************************************

   Name:                         df.c

   Description:          The main module for the (new) dump formatter.

   Comments:

   History:              10/29/92 - crs - Begun
   Defects:
   122521   10/12/95   scotteg & wdma - gdtr_lim of ffff causes trap in
				 GetLinearAddress because we overflow a
				 16 bit calculation.
   155531     21 May 1996 RJM Make .ML independent of symbol support.
   155531     23 May 1996 RJM Add support for .MK + fixes to .MK
*****************************************************************************/

/*****************************************************************************
                                                        Include Files
*****************************************************************************/
#define  _MT
#define  INCL_DOS

typedef unsigned long ulong_t;
typedef unsigned short ushort_t;
typedef unsigned char uchar_t;
#define _stdcall

#include <os2.h>
#include <string.h>
#include <stdio.h>
#include <io.h>
#include <vmexport.h>
#include <vmowner.h>   //155531
#include <process.h>
#include "df.h"
#include <sas.h>
#include "debsym.h"

/*****************************************************************************
                                                          Prototypes
*****************************************************************************/
int    main( int argc, char *argv[] );
void   usage( char * );
USHORT process( char * dumpFile );
void   DumpFileHdr( void );
void   DumpInfo( void );
int    _sprntf(char *, char *, int *);
int    sprintflc(char *, char *, long);
UINT   GetAddress(ULONG ulOffset, USHORT usNumBytes, UCHAR far *pBuf);
USHORT LinearToPhysical( ULONG linear, ULONG *physaddr);
USHORT LoadTables( void );
SHORT  GetLinearAddress(ULONG, ULONG, USHORT far *, USHORT );
SHORT  LoadSASTables( VOID );
SHORT  DisplaySASTables( VOID );
VOID   GetSegmentLimit( DESCRIPTOR far *desc_ptr, ULONG far *seg_limit );
VOID   CEntryForDotP( SHORT sType, SHORT sSlotReq );
VOID   LoadArenaTable( void );
VOID   LoadObjectTable( void );
VOID   Error( PSZ, USHORT, USHORT, PSZ );
ULONG  FindVPBASE(void);
VOID   FindMTE_H(void);

extern char   *fmtnum(char *,long,int,int,int,char,int);
extern void   lowercase(char *);
extern void   DoCmd( void );
extern USHORT SetupThreadInfo( void );
extern VOID   LoadObjectTable( void );
//extern int    LoadSymbolFile( char *);
extern USHORT InitASM( void );
extern VOID CheckDebug( void ); //111005
extern SHORT  FindSymbolAddress ( struct MapDef huge *MapAddr, CHAR *SymGrpName,
                                                                 CHAR *Symbol, USHORT *sel, ULONG *offset  );
extern int      CActivateMap( CHAR far * szMapName );
extern void PDump(char *);


/*****************************************************************************
                                                         Global Data
*****************************************************************************/
DUMPHDR            dumpHdr;                        /* The first sector of the dump file */
DUMPINFOSTRUC  dumpInfoStruc= {0};         /* */
HFILE              dumpHandle;                     /* file handle for dump file */
ULONG      far *ptrDIR=0;                          /* pointer to directory table */
ULONG      far *ptrGDT=0;                          /* pointer to GDT */
ULONG      far *ptrLDT=0;                          /* pointer to LDT */
ULONG      far *ptrIDT=0;                          /* pointer to IDT */
ULONG     huge *ptrOBJ=0;                          /* pointer to Obj Table */
//122521 UINT               sizeGDT=0;
ULONG              sizeGDT=0;		//122521
UINT               sizeLDT=0;
UINT               sizeIDT=0;
char ourversion[40] = {"a"};
char theirversion[40] = {"b"};
BOOL               bIsDebug = FALSE;   /* debug - retail flag */
ULONG      pgpVPBase = 0;                          /* pointer to PGVP virtual address */
ULONG      pgpVPEnd = -1;                         /* pointer to PGVP end virtual address */
extern ULONG      mte_h;                           /* pointer to MTE head chain */
extern struct MapDef huge *MapDefPtr;           // Pointer to symbol Map Definition struc
HPIPE      hPipe = 0;

BOOL     fFrontEnd = FALSE;                /* stdout ??? */
BOOL     fDebug    = FALSE;                /* display debug errors */
PAGEDATACONTROLBLOCK far *ptrFirstPDCB;
ULONG    lastArena;                                /* pointer to last arena record                */
ULONG    freeArena;                                /* pointer to first free arena record  */
ULONG    lastObject;                               /* pointer to last arena record                */
ULONG    freeObject;                               /* pointer to first free arena record  */

ULONG    ulPhysPageDir;           // linear addr of Page Directory

ULONG    pgPhysMax = 0;

/* added by RJM */
extern   ULONG    palVMAli;
extern   ULONG    pVMLIHead; //155531
/* end of RJM addition */

//      setup SAS table pointers
struct SAS far * ptrSASBase;
struct SAS_tables_section far * ptrSASTables;
struct SAS_kernel_section far * ptrSASKernel;
struct SAS_config_section far * ptrSASConfig;
struct SAS_dd_section     far * ptrSASdd;
struct SAS_vm_section     far * ptrSASvm = 0;
struct SAS_task_section   far * ptrSASTask;
struct SAS_RAS_section    far * ptrSASRAS;
struct SAS_file_section   far * ptrSASFile;
struct SAS_info_section   far * ptrSASInfo;

int isPDump = 0;

CHAR     SymbolFilePath[255]="\0";
PCHAR    pszSymbolFilePath;

void APIENTRY handler( USHORT us1, USHORT us2 )
{
   return;
}

/*****************************************************************************
   Main - The programs entry point.

   Comments:

   Input:

   Output:
*****************************************************************************/
int main( int argc, char *argv[] )
{
   HFILE        hStd;
   unsigned short rc = ERR_NO_ERROR;    /* assume no error */
   PSZ          p;
   USHORT       fStarted = FALSE;
   CHAR         cmdline[255]="\0";

   switch ( argc )
          {
          case 2:
                 break;

          case 3:
          case 4:
                 p = argv[2];
                 while ( *p && *p == ' ' ) p++;
                 if ( *p++ != '-' )
                        {
                          usage( argv[0] );
                          return( rc );
                        }
                 *p &= 0x5f;
                 switch( *p++ )
                        {
                        case 'P':
                           rc = DosMakeNmPipe( p, &hPipe, NP_ACCESS_DUPLEX,
                                        NP_TYPE_BYTE | 1, 4096, 2048, 10000 );
//                                        PIPE_TYPE_MESSAGE | NP_WMESG | NP_RMESG | 1, 4096, 2048, 10000 );
                           if ( rc != 0 )
                                  {
                                  fprintf(stdout, "Error making pipe (%d).\n", rc );
                                  goto done;
                                  }

                           hStd = 0;
                           rc = DosDupHandle( hPipe, &hStd );
                           hStd = 1;
                           rc = DosDupHandle( hPipe, &hStd );
                           hStd = 2;
                           rc = DosDupHandle( hPipe, &hStd );

                           DosConnectNmPipe( hPipe );

                           fFrontEnd = TRUE;

                           break;

                        case 'C':
                           break;

                        case 'D':
                           if (!strcmp(p,"ebug"))
                                 fDebug=TRUE;
                           else
                                 fDebug=FALSE;
                           break;

                        default:
                           usage( argv[0] );
                           return( rc );
                        }


                 break;

          case 1:
          default:
                 usage( argv[0] );
                 return( rc );
          }

if (!strcmp(argv[argc-1],"-Debug"))
{
   fDebug=TRUE;
   fprintf(stdout,"fDebug = on\n");
}
 else
   fDebug=FALSE;

// disable control-c and control-break if not debugging
if (!fDebug)
{
   DosSetSigHandler( handler, 0, 0, 2, 1 );
   DosSetSigHandler( handler, 0, 0, 2, 4 );
}

   strcpy( SymbolFilePath, argv[0] );                             // copy parameter
   pszSymbolFilePath=SymbolFilePath;                              // point to the begining
   pszSymbolFilePath += strlen(pszSymbolFilePath)-1;  // go to the end of the string

   while ( (pszSymbolFilePath  != SymbolFilePath) &&
                   (*pszSymbolFilePath != ':')  &&
                   (*pszSymbolFilePath != '\\') )

           pszSymbolFilePath--;                                                   // find the first location of : \

   if (pszSymbolFilePath==SymbolFilePath)
           *pszSymbolFilePath = '\0';                      // no path was found
         else                                                                                      // else store path
           *++pszSymbolFilePath = '\0';                    // terminate the string here

   strlwr(SymbolFilePath);                                                         // lowercase the path


   /* go off and do it */
   rc = process( argv[1] );

done:
   fflush( stdout );
   /* return status to user */
   return( rc );
}



/*****************************************************************************
   Process -   process the dump

   Comments:

   Input:          char * dumpFile              - file to work with

   Output:         unsigned short rc    - status
*****************************************************************************/
unsigned short process( char * dumpFile )
{
   unsigned short rc = ERR_NO_ERROR;   /* assume no error */
   unsigned int numBytes;
   USHORT       usAction;
   ULONG        ulPos;
   char  far *buf;
   SEL          sel;
   BOOL         done;
   CHAR         KernelSymbol[255]="\0";
   CHAR     allSymbols[]="1*";         /* Used to load all symbol files */

   // setup the ourversion of internal revision number
   rc = InitASM();
   if ( rc )
          goto done;
   fflush(stdout);


   rc = DosOpen( dumpFile, &dumpHandle, &usAction, 0, FILE_NORMAL,
                                  OPEN_ACTION_FAIL_IF_NEW | OPEN_ACTION_OPEN_IF_EXISTS,
                                  OPEN_SHARE_DENYNONE | OPEN_ACCESS_READONLY, 0L );
   if ( rc != 0 )
          {
          fprintf(stdout, "Error opening dump file (%s)\n", dumpFile );
          rc = ERR_OPENING_DUMP;
          goto done;
          }

   /* read the first sector of the file */
   rc = DosRead( dumpHandle, &dumpHdr, sizeof( dumpHdr ), &numBytes );
   if ( numBytes != sizeof( dumpHdr ) )
          {
          fprintf(stdout, "Error reading dump file\n" );
          rc = ERR_READING_DUMP;
          goto done;
          }

   // pdump checking
   // diem this is a process dump 06/25/94
   if (!memcmp(&dumpHdr,"PRCD", 4))
   {
      isPDump = 1;
      PDump(dumpFile);
      return ERR_NO_ERROR;
   }

   /* some crude validation */
   if ( dumpHdr.numDisks > 124 || dumpHdr.flag != 0x0b )
          {
          fprintf(stdout, "Invalid dump header detected\n" );
          rc = ERR_INVALID_HDR;
          goto done;
          }

   /* let's load pgPhysMax */
   rc = DosChgFilePtr( dumpHandle, 0, FILE_END, &ulPos );
   if ( rc )
          {
          fprintf(stdout, "Error reading dump file\n" );
          rc = ERR_READING_DUMP;
          goto done;
          }
   pgPhysMax = ( ulPos - 512 ) / 4096 - 1 ;

   /* let's get the dump info struct */
   rc = DosChgFilePtr( dumpHandle, DUMP_INFO_OFFSET + 512, FILE_BEGIN, &ulPos );
   if ( rc )
          {
          fprintf(stdout, "Error reading dump file\n" );
          rc = ERR_READING_DUMP;
          goto done;
          }

   rc = DosRead( dumpHandle, &dumpInfoStruc, sizeof( dumpInfoStruc ), &numBytes );
   if ( numBytes != sizeof( dumpInfoStruc ) )
          {
          fprintf(stdout, "Error reading dump file\n" );
          rc = ERR_READING_DUMP;
          goto done;
          }

/**************************************************************************/
/* Search for the build version string in the second 32k of the dump file */
/**************************************************************************/
   rc = DosAllocSeg(0x8000, &sel, 0);  /* allocate a search buffer */
   buf = MAKEP(sel, 0);
   done = FALSE;
   rc = DosChgFilePtr( dumpHandle, 0x8200, FILE_BEGIN, &ulPos );
   rc = DosRead( dumpHandle, buf, 0x8000, &numBytes );

   while (!done && OFFSETOF(buf) < 32767)
          {
          if (*buf++ == 'I')
                 if (strstr(buf, "nternal revision") == buf)
                        {
                        strcpy(theirversion, --buf);
                        done = TRUE;
                        }
          }
   DosFreeSeg(sel);

#ifdef MISCSTRICT
   fprintf( stdout, "IBM OS/2 System Dump Formatter for debug kernel\n" );
#else
   fprintf( stdout, "IBM OS/2 System Dump Formatter for retail " );
#endif

   rc = LoadTables( );
   CheckDebug( ); //111005 - check if debug kernel
//       if ( rc )
//              goto done;
   fflush(stdout);




#ifdef MISCSTRICT
   if (bIsDebug == FALSE)
          {
          fprintf(stdout, "The requested dump is a RETAIL kernel, use DF_RET.EXE\n");
          goto done;
          }
          else
                strcat(KernelSymbol," os2krnld");

#else
   if (bIsDebug == TRUE)
          {
                strcat(KernelSymbol," os2krnlb");
                fprintf(stdout, "hstrict kernel\n");
//        fprintf(stdout, "The requested dump is a DEBUG kernel, use DF_DEB.EXE\n");
//              goto done;
          }
          else
          {
                strcat(KernelSymbol," os2krnlr");
                fprintf(stdout, "kernel\n");
          }
#endif

   fprintf(stdout, "Formatter is --> %s\n", ourversion);
   fprintf(stdout, "Dump file is --> %s\n", theirversion);

   rc = LoadSASTables( );
   if ( rc )
          goto done;
   fflush(stdout);

   SetupThreadInfo( );
   fflush(stdout);


// the following is test code where the _mte_h should equal the _mte_h
// searched for in findmte_h()


   KernelSymbol[0]=(CHAR)(strlen(KernelSymbol)-1);

//       if (LoadSymbolFile( KernelSymbol ) || strcmp(ourversion,theirversion))
   if (CActivateMap( KernelSymbol ) || strcmp(ourversion,theirversion))
   {

   pgpVPBase = FindVPBASE();
   pgpVPEnd = -1;
   fflush(stdout);

#ifdef DEBUG
         fprintf(stdout,"\nfindvpbase() pgpVPBase=%lx\n",pgpVPBase);
         fprintf(stdout,"findvpbase() pgpVPEnd =%lx\n",pgpVPEnd);
#endif

/*
 * davidj 11/22/93
 * this surpases and avoids any problems with kernel symbol files not
 * matching the dump.  After 2.1 GA code, r206 SAS_vm_all_mte has the
 * mte_h value
 *
 */

#ifdef BORG
   mte_h=ptrSASvm->SAS_vm_all_mte;
   rc = GetLinearAddress( mte_h, 4L,(USHORT far *)&mte_h,FALSE);
   if (rc != ERR_NO_ERROR)
          FindMTE_H();
#else
   FindMTE_H();
#endif
   fflush(stdout);

#ifdef DEBUG
         fprintf(stdout,"findmte_h() mte_h=%lx\n",mte_h);
#endif

   }
   else
   {
#ifdef DEBUG

         USHORT isel;
         CHAR szSymbol[20];
         CHAR szGroup[20];

         strcpy(szSymbol," _pgpVPBase");
         szSymbol[0]=10;
         isel=0;
         pgpVPBase=0;
         if (FindSymbolAddress( MapDefPtr, szGroup, szSymbol, &isel, &pgpVPBase ))
         {
           rc = GetLinearAddress( pgpVPBase, 4L,(USHORT far *)&pgpVPBase,FALSE);
           if (rc != ERR_NO_ERROR)
           {
                 pgpVPBase = FindVPBASE();
                 pgpVPEnd = -1;
           }
         }
         else
         {
                 pgpVPBase = FindVPBASE();
                 pgpVPEnd = -1;
         }

         // lookup pgpVPEnd
         strcpy(szSymbol," _pgpVPEnd");
         szSymbol[0]=9;
         isel=0;
         pgpVPEnd=-1;
         if (FindSymbolAddress( MapDefPtr, szGroup, szSymbol, &isel, &pgpVPEnd ))
         {
           rc = GetLinearAddress( pgpVPEnd, 4L,(USHORT far *)&pgpVPEnd,FALSE);
           if (rc != ERR_NO_ERROR)
           {
                 pgpVPBase = FindVPBASE();
                 pgpVPEnd = -1;
           }
         }
         else
         {
                 pgpVPBase = FindVPBASE();
                 pgpVPEnd = -1;
         }
         fprintf(stdout,"\nfindvpbase() pgpVPBase=%lx\n",pgpVPBase);
         fprintf(stdout,"findvpbase() pgpVPEnd =%lx\n",pgpVPEnd);
#else
         pgpVPBase = FindVPBASE();
         pgpVPEnd = -1;
#endif

/*
 * davidj 11/22/93
 * this surpases and avoids any problems with kernel symbol files not
 * matching the dump.  After 2.1 GA code, r206 SAS_vm_all_mte has the
 * mte_h value
 *
 */

#ifdef BORG
   mte_h=ptrSASvm->SAS_vm_all_mte;
   rc = GetLinearAddress( mte_h, 4L,(USHORT far *)&mte_h,FALSE);
   if (rc != ERR_NO_ERROR)
          FindMTE_H();
#else
#if 0
         strcpy(szSymbol," _mte_h");
         szSymbol[0]=6;
         isel=0;
         mte_h=0;
         if (FindSymbolAddress( MapDefPtr, szGroup, szSymbol, &isel, &mte_h ))
         {
           rc = GetLinearAddress( mte_h, 4L,(USHORT far *)&mte_h,FALSE);
           if (rc != ERR_NO_ERROR)
                 FindMTE_H();
         }
         else
#endif
                 FindMTE_H();
#endif

   }


#ifdef DEBUG
         fprintf(stdout,"mte_h=%%%lx\n",mte_h);
#endif
//155531
#ifdef PMDEBUG
{
   USHORT isel;
   CHAR szSymbol[20];
   CHAR szGroup[20];

     strcpy(szSymbol," _pVMLIHead");
     szSymbol[0]=10;
     isel=0;
     pVMLIHead=0;

     #ifdef PMDEBUG
     if (!FindSymbolAddress( MapDefPtr, szGroup, szSymbol, &isel, &pVMLIHead ))
     printf("\n.mk will not work because kernel symbol file was not loaded\n");
     #endif

}
#endif


///* added by RJM 23/june/94 to make .ml work */
//{
//   USHORT isel;
//   CHAR szSymbol[20];
//   CHAR szGroup[20];
//
//     strcpy(szSymbol," _palVMAliases");
//     szSymbol[0]=13;
//     isel=0;
//     palVMAli=0;
//
//     if (!FindSymbolAddress( MapDefPtr, szGroup, szSymbol, &isel, &palVMAli ))
//     printf("\n.ml will not work because kernel symbol file was not loaded\n");
//     else {
//       rc = GetLinearAddress( palVMAli, 4L,(USHORT far *)&palVMAli,FALSE);
//     }
//
//}
//* end of addititon by RJM */

//155531
//The following block replaces the above to make .ML independent of symbol support
//
{
   ULONG    ulAddr;                 // Hold a linear address
   VMOB     vmob;                   // VMOB of alias table
   VMAR     vmar;                   // VMAR of alias table
   USHORT   harVMAL;                // handle of VMAL table

   palVMAli=0;
   ulAddr  = dumpInfoStruc.vm_object_ptr;
   while (ulAddr<=lastObject) {
      rc = GetLinearAddress( ulAddr, sizeof(VMOB),(USHORT far *)&vmob,FALSE);
      if (vmob.ob_hobowner==VMALOWNER) {
//         printf("VMAL VMOB addr: %lx\n",ulAddr);
         harVMAL=vmob.ob_har;
//         printf("VMAL har: %x\n",harVMAL);
         ulAddr=dumpInfoStruc.arena_base;
         ulAddr  += ((harVMAL-1)*sizeof(VMAR)); // ulAddr-> arena record
//         printf("Al VMAR addr: %lx\n",ulAddr);
         rc = GetLinearAddress( ulAddr, sizeof(VMAR),(USHORT far *)&vmar,FALSE);
         palVMAli= (vmar.ar_ipg <<12)+sizeof(VMBH);
//         printf("VMALIAS addr: %lx\n",palVMAli);
         ulAddr=0xffffffff; // force exit from loop
      } else {
         ulAddr+=sizeof(VMOB);
      } /* endif */
   } /* endwhile */
   if (palVMAli==0) printf("\nUnable to locate VM Alias Table\n");
}
//end of 155531



// JAB 7/94
   CActivateMap(allSymbols);
   fprintf(stdout,"\n\n");
   fflush(stdout);

   CEntryForDotP( GET_PROC_NORM, -1 );

   fprintf(stdout,"\n");
   fflush(stdout);
   DoCmd();

done:
   if ( dumpHandle != 0 )
          DosClose( dumpHandle );

   return( rc );
}


/*****************************************************************************
   Error -       function that displays errors

   Comments:

   Input:

   Output:
*****************************************************************************/
VOID Error( PSZ szFile, USHORT usLine, USHORT rc, PSZ szText )
{
//      if (fDebug)
//       fprintf( stdout, "File: %Fs - Line: %d - Rc: %d (%s)\n",
   fprintf( stdout, "File: %Fs - Line: %d - Rc: %d\n(%s)\n",
                                  szFile, usLine, rc, szText );
   fflush( stdout );
   return;
}

/*****************************************************************************
   Usage -      Display program usage

   Comments:

   Input:       argv[0].

   Output:      None.
*****************************************************************************/
void usage( char * dfname )
{
   InitASM();
   fprintf(stdout, "\n%s is --> %s\n", dfname, ourversion);

   fprintf(stdout, "usage:   <df_ret | df_deb> <dump file> [-Ppipename | -Ccomport]\n" );
   fprintf(stdout, "\n" );
   fflush(stdout);
}

/*****************************************************************************
   DumpHdr -  Display the file header for disk based dump file

   Comments:

   Input:       None.

   Output:      None.
*****************************************************************************/
void DumpFileHdr( void )
{
   int   i;

   fprintf(stdout, "Dump File Header Info:\n" );
   fprintf(stdout, "  Start Addr1: %ld\n", dumpHdr.startAddr1 );
   fprintf(stdout, "    End Addr1: %ld\n", dumpHdr.endAddr1 );
   fprintf(stdout, "  Total Disks: %ld\n", dumpHdr.numDisks );
   fprintf(stdout, "         Flag: %ld\n", dumpHdr.flag );
   fprintf(stdout, "  Ending addresses by disk:\n" );
   for ( i = 0; i < (int)dumpHdr.numDisks; i++ )
          {
          fprintf(stdout, "    %12ld", dumpHdr.endAddrEachDisk[i] );
          if ( i && (i % 3) == 0 )
                 fprintf(stdout, "\n" );
          }
   fprintf(stdout, "\n" );
   fflush(stdout);
}

/*****************************************************************************
   Dumpinfo -  Display the dump info structure.

   Comments:

   Input:       None.

   Output:      None.
*****************************************************************************/
void DumpInfo( void )
{
   fprintf(stdout,"gdtr_lim: %04X\n", dumpInfoStruc.gdtr_lim );
   fprintf(stdout,"gdtr_base: %08lX\n", dumpInfoStruc.gdtr_base );
   fprintf(stdout,"idtr_lim: %04X\n", dumpInfoStruc.idtr_lim );
   fprintf(stdout,"idtr_base: %08lX\n", dumpInfoStruc.idtr_base );
   fprintf(stdout,"ldtr_reg: %04X\n", dumpInfoStruc.ldtr_reg );
   fprintf(stdout,"lo_data_sel: %04X\n", dumpInfoStruc.lo_data_sel );
   fprintf(stdout,"hi_data_sel: %04X\n", dumpInfoStruc.hi_data_sel );
   fprintf(stdout,"trace_buf_addr: %08lX\n", dumpInfoStruc.trace_buf_addr );
   fprintf(stdout,"sys_anchor_sel: %04X\n", dumpInfoStruc.sys_anchor_sel );
   fprintf(stdout,"arena_base: %08lX\n", dumpInfoStruc.arena_base );
   fprintf(stdout,"max_threads: %04X\n", dumpInfoStruc.max_threads );
   fprintf(stdout,"phys_page_dir: %08lX\n", dumpInfoStruc.phys_page_dir );
   fprintf(stdout,"vm_object_ptr: %08lX\n", dumpInfoStruc.vm_object_ptr );
   fprintf(stdout,"StartInit_Data: %08lX\n", dumpInfoStruc.StartInit_Data );
   fprintf(stdout,"dcm_ote_start: %08lX\n", dumpInfoStruc.dcm_ote_start );
   fprintf(stdout,"CurProcPid: %04X\n", dumpInfoStruc.CurProcPid );
   fprintf(stdout,"TaskData: %08lX\n", dumpInfoStruc.TaskData );
   fprintf(stdout,"FirstPacket: %04X\n", dumpInfoStruc.FirstPacket );
   fprintf(stdout,"LastPacket: %04X\n", dumpInfoStruc.LastPacket );
   fprintf(stdout,"SysSemDataTable: %08lX\n", dumpInfoStruc.SysSemDataTable );
   fprintf(stdout,"GDT_Buffers: %08lX\n", dumpInfoStruc.GDT_Buffers );
   fprintf(stdout,"PapTCBPtrs: %08lX\n", dumpInfoStruc.PapTCBPtrs );
   fprintf(stdout,"callerSS: %04X\n", dumpInfoStruc.callerSS );
   fprintf(stdout,"callerESP: %08lX\n", dumpInfoStruc.callerESP );
   fprintf(stdout,"savePage: %08lX\n", dumpInfoStruc.savePage );
   fflush(stdout);
   return;
}

/*****************************************************************************
   _sprntf -  simple version of sprintf()

   Comments:

   Input:       None.

   Output:      None.
*****************************************************************************/

int _sprntf( char         *buffer,                      /* Destination buffer */
                         register char *fmt,            /* Format string */
                         int      *parmv )                      /* Parameter vector */
{
  long x;                                                 /* Integer to decode */
  register char *cp;                      /* Char pointer */
  char *parm;                                     /* Parameter pointer */
  int parmlen;                                    /* Parameter length */
  int width;                                      /* Field width */
  int precision;                                  /* Field precision */
  int ljust;                                      /* Left-justify flag */
  int longint;                                    /* Long integer flag */
  char pad;                                       /* Pad character */
  int r;                                                  /* Radix */

  cp = buffer;                                    /* Initialize pointer */
  while(*fmt != '\0')             /* While not at end of format string */
  {
          if(*fmt++ != '%')           /* If not a parameter specifier */
          {
                  *cp++ = fmt[-1];                /* Copy the character */
                  continue;                       /* Continue */
          }
          if(ljust = (*fmt == '-'))
                  ++fmt;                                  /* Check for left-justify flag */
          if(*fmt == '0')             /* If zero-padding wanted */
          {
                  pad = '0';              /* Set pad character */
                  ++fmt;                                  /* Skip '0' */
          }
          else
          {
                  pad = ' ';              /* Else pad with spaces */
          }
          width = 0;                              /* Initialize field width */
          precision = 32767;              /* Set maximum precision */

          /* Calculate field width */
          while ( *fmt >= '0' && *fmt <= '9' )
                  width = width*10 + *fmt++ - '0';

          /* Check if precision field */
          if ( *fmt == '.' )
          {
                  ++fmt;
                  precision = 0;
                  /* Calculate field precision */
                  while ( *fmt >= '0' && *fmt <= '9' )
                          precision = precision*10 + *fmt++ - '0';
          }

          /* Check for long integer flag */
          if (longint = (*fmt == 'l') )
                  ++fmt;
          r = 0;
          switch (*fmt)                                           /* Switch on format character */
          {
                  default:                                                /* Bad format type */

                  case '%':                       /* Percent sign */
                          parm = fmt;                             /* Set pointer */
                          parmlen = 1;                            /* Set length */
                          break;

                  case 'c':                       /* Character */
                          parm = (char *) parmv;          /* Set pointer */
                          parmlen = 1;                            /* Set length */
                          ++parmv;                                        /* Increment pointer */
                          pad = ' ';                  /* Pad always a space */
                          break;

                  case 's':                       /* String */
                          parm = (char *) parmv;          /* Set pointer */
//                              parm = (char *) *parmv;          /* Set pointer */
                          parmlen = strlen(parm);         /* Set length */
                          ++parmv;                                        /* Increment pointer */
                          pad = ' ';                  /* Pad always a space */
                          break;

                  case 'd':                       /* Decimal signed */
                  case 'u':                       /* Decimal unsigned */
                          r = 10;
                          break;

                  case 'x':                       /* Hex */
                  case 'X':                       /* Hex */
                          r = 16;
                          break;

                  case 'b':                       /* Binary */
                          r = 2;
                          break;
          }

          if (r != 0)
          {
                  if (longint)                                     /* If long integer */
                  {
                          x = *((long *) parmv);
                          ++parmv;                /* Skip low word */
                  }
                  else
                  {
                          /* Else get short integer */
                          x = (long) *parmv & 0xFFFFL;
                  }
                  ++parmv;                                /* Skip integer */
                  cp = fmtnum( cp, x, r, width, precision, pad, ljust );
                  parmlen = 0;                    /* No padding needed */
          }

          if (parmlen)
          {

                  /* Calculate needed padding */
                  width -= parmlen;

                  /* If padding before param */
                  if( pad == '0' || !ljust )
                  {

                          /* Loop to pad field */
                          while(width > 0)
                          {

                                  /* Pad with zeroes or spaces */
                                  *cp++ = pad;

                                  /* Decrement counter */
                                  --width;
                          }
                  }

                  /* Adjust the field width */
                  parmlen = parmlen > precision ? precision : parmlen;

                  /* Copy the parameter */
                  while ( parmlen-- > 0 )
                          *cp++ = *parm++;

                  /* Pad remainder of field */
                  while ( width-- > 0 )
                          *cp++ = ' ';
          }
          if ( *fmt != '\0' )
                  ++fmt;                                          /* Increment pointer */
  }

  *cp = '\0';                             /* Null terminate buffer */

  return(cp - buffer);    /* Return number of characters used */
}

int sprintflc( char *buffer,                    /* Destination buffer */
                           char *fmt,                           /* Format string */
                           long  parm )                         /* First parameter (if any) */
{
   int rc = sprintf( buffer, fmt, parm );
   lowercase( buffer );                          /* Lower case string if option set */
   return( rc );
}

/*****************************************************************************
   GetAddress -   read data from Dump File

   Comments:

   Input:          ULONG           ulOffset    - address of requested info
                           USHORT          usNumBytes  - size of request
                           UCHAR FAR * pBuf        - where to stick it

   Output:         USHORT (return code)
                                  ERR_NO_ERROR             - success
                                  ERR_INVALID_REQUEST  - requested size invalid

*****************************************************************************/
USHORT   GetAddress(ULONG ulOffset, USHORT usNumBytes, UCHAR far *pBuf)
{
   USHORT       rc;                                        // return code
   ULONG        ulPos;                                     // current file pointer
   USHORT       usBytesRead;                       // number of bytes read
   int          i,j;                                       // temp junk
   ULONG        ulDelta;
/* use 8 buffers for caching scheme */
static ULONG oldaddress[8] = {-1,-1,-1,-1,-1,-1,-1,-1};
static UCHAR far *bufs[8] = {0};
static int         iBufNum = 0;                  // last recently used buffer


rc = 0;  /* assume all is well - Don't blast this! it keeps it working */
                 /* in the cached case since rc would have garbage on exit.    */
/***************************************************************************/
/* We will cache eight pages worth of page table information. These will   */
/* be allocated the first time through, and never freed.                                   */
/***************************************************************************/
   if ( bufs[0] == 0 )
          {
          SEL   sel;
          for (i=0; i<8; i++)
                  {
                  DosAllocSeg(4096, &sel, 0);
                  bufs[i] = MAKEP(sel, 0);
                  }
          }



   // davidj 06/25/94
   // GetAddress was trying to cache a read that was at the very end of the dump
   // as a result the read was failing because the cache could not cache the
   // entire page, and not because it could not read the actual data.

   if ((usNumBytes <= 4096) &&                                          /* don't cache if request is bigger than a page  */
           ((ulOffset + 2048 ) <= (pgPhysMax*4096+1)))  /* don't cache if it goes beyond the end of dump */



   {
   j=-1;
   for (i=0; i<8; i++)
          if ((oldaddress[i] <= ulOffset) && (oldaddress[i] + 4095L >= ulOffset+(ULONG)usNumBytes))
                 j=i;  /* we have the memory in one of the cache buffers */
   if (j == -1)  /* we don't have it cached, read it in */
          {
          j = iBufNum++;   /* get the next available buffer */
          iBufNum &= 7;    /* keep it going from 0 to 7 */

          if ((usNumBytes < 2048)&&(ulOffset >= 2048))  /* center the buffer around this address */
                 oldaddress[j] = ulOffset-2048;
          else
                 oldaddress[j] = ulOffset;

          rc = DosChgFilePtr( dumpHandle, oldaddress[j] + 512L, FILE_BEGIN, &ulPos );
          rc += DosRead( dumpHandle, bufs[j], 4096, &usBytesRead);

//              if ( rc )

// davidj 5/19/93
// if getaddress() tries to access memory that is outside the bound of the
// dumpfile dosread does not return an error, it just comes back with the
// number of bytes read which usually winds up usBytesRead being zero.

          if ( rc || usBytesRead<4096 )
                 {
                 rc = ERR_READING_DUMP;
                 goto done;
                 }

          ulDelta = ulOffset - oldaddress[j];
          memcpy(pBuf, bufs[j]+ulDelta, usNumBytes);
          } /* if non-cached case */
   else  /* we do have it in a cache, just read it out */
          {
          ulDelta = ulOffset - oldaddress[j];
          memcpy(pBuf, bufs[j]+ulDelta, usNumBytes);
          } /* if cached case */
   }
else  /* request is bigger than a page, just read it */
   {
   // Bypass file header
   rc = DosChgFilePtr( dumpHandle, ulOffset + 512, FILE_BEGIN, &ulPos );
   rc += DosRead( dumpHandle, pBuf, usNumBytes, &usBytesRead );
   if ( rc || usNumBytes != usBytesRead )
          {
          rc = ERR_READING_DUMP;
          goto done;
          }
   }  /* if less than a page */

done:

   return(rc);
}

/*****************************************************************************
   LinearToPhysical

   Comments:

   Input:       None.

   Output:      None.
*****************************************************************************/
USHORT LinearToPhysical( ULONG ulLinear,         // Linear address
                                                 ULONG *ulPhysAddr)  // Physical address
{
/* last accessed page table addresses */
   static ULONG   ulLastPageAddr[8] = {-1,-1,-1,-1,-1,-1,-1,-1};
/* Far Pointer to last accessed page */
   static int     *oldPage[8] = {0,0,0,0,0,0,0,0};
   static int     bufnum = 0;                     // last recently used pointer
                  ULONG   ulDir;                                  // Page directory entry
                  ULONG   ulOffset;                       // Offset into table                                   */
                  ULONG   ulAddress;                      // Address into buffer                                 */
                  USHORT  rc = 0;                                 // Return Code                                                 */
                  ULONG FAR *ulPtr;                       // Generic long pointer
                  int     i,j;


   // We will cache eight pages worth of page table information. This will be
   // allocated the first time through, and never freed.
   if ( oldPage[0] == 0 )
          {
          SEL   sel;
          for (i=0; i<8; i++)
                  {
                  DosAllocSeg(4096, &sel, 0);
                  oldPage[i] = MAKEP(sel, 0);
                  }
          }

   // Determine the page dir entry (PDE) within the page directory
   ulDir = ulLinear >> 22;                                // Get offset into page directory
   ulPtr = (ULONG FAR *)ptrDIR + ulDir;   // Calculate addr into our table
   ulAddress = *ulPtr;                                    // Extract addr of page table

   if ((ulAddress & 0x0001) < 1)                  // Fail if page table not present
          {
          rc = ERR_MEM_NOT_PRESENT;
          goto done;
          }

   ulAddress = SHIFT_RIGHT(ulAddress,12); // Strip flags from address
   ulAddress = SHIFT_LEFT(ulAddress, 12); // Reposition

   // Check if page directory is in cache
   j = -1;
   for (i=0; i<8; i++)
          if (ulLastPageAddr[i] == ulAddress) j = i;
   if (j == -1)  /* page not in cache */
          {
          j = bufnum++;
          bufnum &= 7;  /* keep it going from 0-7 */
          ulLastPageAddr[j] = ulAddress;
          rc = GetAddress( ulAddress, 4096, (UCHAR FAR *)oldPage[j] );
          if (rc) goto done;
          }  /* if not cached */

   ulOffset = SHIFT_LEFT(ulLinear,10);    // Strip the high order 10 bits
   ulOffset = SHIFT_RIGHT(ulOffset,22);   // Strip low order 12 & position

   ulPtr = (ULONG far *)oldPage[j] + ulOffset;  // Get address of page
   ulAddress = *ulPtr;                                    // Move to physical address
   if ((ulAddress & 1) < 1)                       // Is page marked not present ?
          {
          rc = ERR_MEM_NOT_PRESENT;
          goto done;
          }

   ulAddress = SHIFT_RIGHT(ulAddress,12); // Strip flags from address
   *ulPhysAddr = (SHIFT_LEFT(ulAddress,12))+
                                 (ulLinear & 0x00000fff); // Strip low order 12 & position

done:
   return(rc);
}

/*****************************************************************************
   GetLinearAddress

   Comments:

   Input:       None.

   Output:      None.
*****************************************************************************/
SHORT GetLinearAddress(ULONG ulLinear,           // must be a linear address
                                           ULONG ulBytesToLoad,  // #of bytes to load into ram
                                           USHORT far *pBuf,     // ram address to load data at
                                           USHORT usCtrlBlocks)  // 0/1 NO/YES build usCtrlBlocks
{
   ULONG        total_bytes_to_load;                     // #of bytes to load into ram
   USHORT       bytes_in_page = 0;                               // bytes avail in current page
   USHORT       bytes_to_get  = 0;                               // bytes to load from current page
   ULONG        bytes_loaded  = 0;                               // total bytes loaded into ram
   ULONG        phys_addr;
   UINT         offset;                                                  // offset into current page
   ULONG        NumOfPages;                                      // Number of Pages data is in
   PAGEDATACONTROLBLOCK far *PDCB_ptr;// Pointer to anyone of the PDBCs
                                                                                         // allocated for the PDCB structs
   USHORT       SomeDataPagedOut = 0;                    // set to YES if any data is Paged
   SHORT        rc;                                                      // Return Code
   SEL          sel;

   // Add 2 below to get another control block in case the data requested is
   // at the end of one page and continues into the beginning of another page.
   NumOfPages = ((ulBytesToLoad / PAGE_SIZE) + 2);

   // Allocate memory for the control blocks.
   rc = DosAllocSeg( (USHORT)(sizeof(struct PageDataControlBlock) * NumOfPages),
                                                &sel, 0 );
   if ( rc )
          {
          fprintf(stdout, "Out of memory in GetLinearAddress\n" );
          rc = ERR_NO_MEMORY;
          goto done;
          }

   ptrFirstPDCB = PDCB_ptr = (PAGEDATACONTROLBLOCK far *)MAKEP( sel, 0 );
   total_bytes_to_load = ulBytesToLoad;         /* initialize total bytes to load */

   while(bytes_loaded < total_bytes_to_load)
          {
          offset=(unsigned)(ulLinear & MASK_FLAGS);   /* last 3 digits = offset         */
          bytes_in_page = (PAGE_SIZE - offset);           /* pages are 0x1000 long each */

          // The IF below is needed to determine if the number of bytes we need
          // to load is greater than the number of bytes in the current page we
          // are processing.  Otherwise all the data we need to load is in this
          // current page.
          if (ulBytesToLoad > bytes_in_page)
                 bytes_to_get = bytes_in_page;
          else           /* all data to be loaded is located in the current page */
                 bytes_to_get = (USHORT)ulBytesToLoad;

          rc = LinearToPhysical( ulLinear, &phys_addr);

          PDCB_ptr->LinearAddress = ulLinear;
          PDCB_ptr->Length                = bytes_to_get;

          if ( !rc )
                 {
                 PDCB_ptr->Data_ptr = pBuf;

                 if (rc = GetAddress(phys_addr,(USHORT)bytes_to_get,(UCHAR far *)pBuf))
                         goto done;
                 }
          else
                 {
                 PDCB_ptr->Data_ptr = 0;
                 SomeDataPagedOut       = TRUE;
                 }

          PDCB_ptr->NextCB       = (PDCB_ptr+1);
          PDCB_ptr++;

//davidj           pBuf += (bytes_to_get / sizeof(*pBuf));

          (CHAR *)pBuf = (CHAR *)pBuf + bytes_to_get;
          ulLinear += bytes_to_get;        // Next linear address
          bytes_loaded += bytes_to_get;    // Total bytes loaded into ram
          ulBytesToLoad -= bytes_to_get;   // Cal bytes remaining to load
          }

   PDCB_ptr -= 1;                                          // Backup to the last control block
   PDCB_ptr->NextCB = 0;                           // This is the last Control Block

   // If not going to use the control blocks then Free up the memory.
   if (usCtrlBlocks == FALSE)
          {
          DosFreeSeg( sel );
          }

   if (SomeDataPagedOut  == TRUE)
          rc = ERR_MEM_NOT_PRESENT;

done:
   return( rc );
}

/*****************************************************************************
   LoadSASTables

   Comments:

   Input:       None.

   Output:      None.
*****************************************************************************/
SHORT LoadSASTables( VOID )
{
   SHORT                   rc;
   ULONG                   addr = 0;
   USHORT                  length = 0;
   UCHAR          far *data_ptr;
   DESCRIPTOR far *desc_ptr;
   SEL                     sel;

   (ULONG)desc_ptr = (ULONG)ptrGDT + (ULONG)dumpInfoStruc.sys_anchor_sel;

   addr = (((ULONG)SHIFT_LEFT(desc_ptr->base_hi, 24)) +
                   ((ULONG)SHIFT_LEFT(desc_ptr->base_mid,16)) +
                   ((ULONG)               desc_ptr->base_lo));

   length = desc_ptr->limit;

   //  allocate segment and load with SAS selector data segment
   rc = DosAllocSeg( 0, &sel, 0 );
   if ( rc )
          {
          fprintf(stdout, "Out of memory in LoadSASTables\n" );
          rc = ERR_NO_MEMORY;
          goto done;
          }
   data_ptr = MAKEP( sel, 0 );

   if ( rc = GetLinearAddress( addr, (ULONG)length,(USHORT far *)data_ptr,FALSE) )
          goto done;

   ptrSASBase = (struct SAS far *)data_ptr;

   //  setup SAS table pointers
   ptrSASTables =(struct SAS_tables_section far *)(data_ptr + ptrSASBase->SAS_tables_data);
   ptrSASKernel =(struct SAS_kernel_section far *)(data_ptr + ptrSASBase->SAS_flat_sel   );
   ptrSASConfig =(struct SAS_config_section far *)(data_ptr + ptrSASBase->SAS_config_data);
   ptrSASdd     =(struct SAS_dd_section         far *)(data_ptr + ptrSASBase->SAS_dd_data        );
   ptrSASvm     =(struct SAS_vm_section         far *)(data_ptr + ptrSASBase->SAS_vm_data        );
   ptrSASTask   =(struct SAS_task_section       far *)(data_ptr + ptrSASBase->SAS_task_data  );
   ptrSASRAS    =(struct SAS_RAS_section        far *)(data_ptr + ptrSASBase->SAS_RAS_data       );
   ptrSASFile   =(struct SAS_file_section       far *)(data_ptr + ptrSASBase->SAS_file_data  );
   ptrSASInfo   =(struct SAS_info_section       far *)(data_ptr + ptrSASBase->SAS_info_data  );

done:
        return( rc );
}

/*****************************************************************************
   DisplaySASTables

   Comments:

   Input:       None.

   Output:      None.
*****************************************************************************/
SHORT DisplaySASTables( VOID )
{
   CHAR sigBuf[5];

   fprintf( stdout,  "--- SAS Base Section ---\n" );

   _fmemcpy( sigBuf, ptrSASBase->SAS_signature, 4 );
   sigBuf[4] = '\0';
   fprintf( stdout,  "%35s: %s\n", "SAS signature", sigBuf );
   fprintf( stdout,  "%35s: %04X\n", "offset to tables section",
                                                   ptrSASBase->SAS_tables_data );
   fprintf( stdout,  "%35s: %04X\n", "FLAT selector for kernel data",
                                                   ptrSASBase->SAS_flat_sel );
   fprintf( stdout,  "%35s: %04X\n", "offset to configuration section",
                                                   ptrSASBase->SAS_config_data );
   fprintf( stdout,  "%35s: %04X\n", "offset to device driver section",
                                                   ptrSASBase->SAS_dd_data );
   fprintf( stdout,  "%35s: %04X\n", "offset to Virtual Memory section",
                                                   ptrSASBase->SAS_vm_data );
   fprintf( stdout,  "%35s: %04X\n", "offset to Tasking section",
                                                   ptrSASBase->SAS_task_data );
   fprintf( stdout,  "%35s: %04X\n", "offset to RAS section",
                                                   ptrSASBase->SAS_RAS_data );
   fprintf( stdout,  "%35s: %04X\n", "offset to File System section",
                                                   ptrSASBase->SAS_file_data );
   fprintf( stdout,  "%35s: %04X\n", "offset to infoseg section",
                                                   ptrSASBase->SAS_info_data );

   fprintf( stdout,  "--- SAS Protected Modes Tables Section ---\n" );
   fprintf( stdout,  "%35s: %04X\n", "selector for GDT", ptrSASTables->SAS_tbl_GDT );
   fprintf( stdout,  "%35s: %04X\n", "selector for LDT", ptrSASTables->SAS_tbl_LDT );
   fprintf( stdout,  "%35s: %04X\n", "selector for IDT", ptrSASTables->SAS_tbl_IDT );
   fprintf( stdout,  "%35s: %04X\n", "selector for GDTPOOL",
                                                ptrSASTables->SAS_tbl_GDTPOOL );

   fprintf( stdout,  "--- SAS Device Driver Section ---\n" );
   fprintf( stdout,  "%35s: %04X\n", "offset for the first bimodal dd",
                           ptrSASdd->SAS_dd_bimodal_chain );
   fprintf( stdout,  "%35s: %04X\n", "offset for the first real mode dd",
                           ptrSASdd->SAS_dd_real_chain );
   fprintf( stdout,  "%35s: %04X\n", "sel for Drive Parameter Block",
                           ptrSASdd->SAS_dd_DPB_segment );
   fprintf( stdout,  "%35s: %04X\n", "sel for ABIOS prot. mode CDA",
                           ptrSASdd->SAS_dd_CDA_anchor_p );
   fprintf( stdout,  "%35s: %04X\n", "seg for ABIOS real mode CDA",
                           ptrSASdd->SAS_dd_CDA_anchor_r );
   fprintf( stdout,  "%35s: %04X\n", "selector for FSC", ptrSASdd->SAS_dd_FSC );

   fprintf( stdout,  "--- SAS Task Section ---\n" );
   fprintf( stdout,  "%35s: %04X\n", "selector for current PTDA", ptrSASTask->SAS_task_PTDA );
   fprintf( stdout,  "%35s: %08lX\n", "FLAT offset for process tree head",
                           ptrSASTask->SAS_task_ptdaptrs );
   fprintf( stdout,  "%35s: %08lX\n", "FLAT address for TCB address array",
                           ptrSASTask->SAS_task_threadptrs );
   fprintf( stdout,  "%35s: %08lX\n", "offset for current TCB number",
                           ptrSASTask->SAS_task_tasknumber );
   fprintf( stdout,  "%35s: %08lX\n", "offset for ThreadCount",
                           ptrSASTask->SAS_task_threadcount );

   fprintf( stdout,  "--- SAS File System Section ---\n" );
   fprintf( stdout,  "%35s: %08lX\n", "handle to MFT PTree", ptrSASFile->SAS_file_MFT );
   fprintf( stdout,  "%35s: %04X\n", "selector for System File Table",
                           ptrSASFile->SAS_file_SFT );
   fprintf( stdout,  "%35s: %04X\n", "sel. for Volume Parameter Bloc",
                           ptrSASFile->SAS_file_VPB );
   fprintf( stdout,  "%35s: %04X\n", "sel. for Current Directory Struc",
                           ptrSASFile->SAS_file_CDS );
   fprintf( stdout,  "%35s: %04X\n", "selector for buffer segment",
                           ptrSASFile->SAS_file_buffers );

   fprintf( stdout,  "--- SAS Information Segment Section ---\n" );
   fprintf( stdout,  "%35s: %04X\n", "selector for global info seg",
                           ptrSASInfo->SAS_info_global );
   fprintf( stdout,  "%35s: %08lX\n", "address of curtask local infoseg",
                           ptrSASInfo->SAS_info_local );
   fprintf( stdout,  "%35s: %08lX\n", "address of DOS task's infoseg",
                           ptrSASInfo->SAS_info_localRM );
   fprintf( stdout,  "%35s: %04X\n", "selector for Codepage Data",
                           ptrSASInfo->SAS_info_CDIB );

   fprintf( stdout,  "--- SAS RAS Section ---\n" );
   fprintf( stdout,  "%35s: %04X\n", "selector for System Trace Data Area",
                           ptrSASRAS->SAS_RAS_STDA_p );
   fprintf( stdout,  "%35s: %04X\n", "segment for System Trace Data Area",
                           ptrSASRAS->SAS_RAS_STDA_r );
   fprintf( stdout,  "%35s: %04X\n", "offset for trace event mask",
                           ptrSASRAS->SAS_RAS_event_mask );

   fprintf( stdout,  "--- SAS Configuration Section ---\n" );
   fprintf( stdout,  "%35s: %04X\n", "offset for Device Config. Table",
                          ptrSASConfig->SAS_config_table );

   fprintf( stdout,  "--- SAS Virtual Memory Mgt. Section ---\n" );
   fprintf( stdout,  "%35s: %08lX\n", "Flat offset of arena records",
                           ptrSASvm->SAS_vm_arena );
   fprintf( stdout,  "%35s: %08lX\n", "Flat offset of object records",
                           ptrSASvm->SAS_vm_object );
   fprintf( stdout,  "%35s: %08lX\n", "Flat offset of context records",
                           ptrSASvm->SAS_vm_context );
   fprintf( stdout,  "%35s: %08lX\n", "Flat offset of kernel mte records",
                           ptrSASvm->SAS_vm_krnl_mte );
   fprintf( stdout,  "%35s: %08lX\n", "Flat offset of linked mte list",
                           ptrSASvm->SAS_vm_glbl_mte );
   fprintf( stdout,  "%35s: %08lX\n", "Flat offset of page frame table",
                           ptrSASvm->SAS_vm_pft );
   fprintf( stdout,  "%35s: %08lX\n", "Flat offset of page range table",
                           ptrSASvm->SAS_vm_prt );
   fprintf( stdout,  "%35s: %08lX\n", "Flat offset of swap frame array",
                           ptrSASvm->SAS_vm_swap );
   fprintf( stdout,  "%35s: %08lX\n", "Flat offset of Idle Head",
                           ptrSASvm->SAS_vm_idle_head );
   fprintf( stdout,  "%35s: %08lX\n", "Flat offset of Free Head",
                           ptrSASvm->SAS_vm_free_head );
   fprintf( stdout,  "%35s: %08lX\n", "Flat offset of Heap Array",
                           ptrSASvm->SAS_vm_heap_info );

#ifdef BORG
   fprintf( stdout,  "%35s: %08lX\n", "Flat offset of all mte records",
                           ptrSASvm->SAS_vm_all_mte );
#endif

   fflush( stdout );

   return( 0 );
}

/*****************************************************************************
   GetSegmentLimit

   Comments:

   Input:       None.

   Output:      None.
*****************************************************************************/
VOID GetSegmentLimit( DESCRIPTOR far *desc_ptr, ULONG far *seg_limit )
{
   ULONG        limit;            /* This will be the segment limit value in the
                                                         descriptor structure passed in. */

   /* Get the upper part of the segment limit from the descriptor */
   limit = (desc_ptr->flag2 & 0xF);

   /* Now combine the upper 4 bits of the limit with the lower 16 bit */
   limit = (SHIFT_LEFT(limit,16) + desc_ptr->limit);

   /* Check IF the G-bit in the descriptor is 1 */
   if (desc_ptr->flag2 & GRANULARITY)
          {
          /* Add the 12 one-bits (0x0fff) to the limit */
          limit = (SHIFT_LEFT(limit,12) + 0x0fff);
          }

   /* Set seg_limit and were all done */
   *seg_limit = limit;
}

/*****************************************************************************
   TableByPage

   Comments:

   Input:       None.

   Output:      None.
*****************************************************************************/
VOID TableByPage(ULONG    addr,            // linear address to get
                                 UINT far *ptr,            // memory location to store data at
                                 UINT     *size)           // requested memory to obtain
{
   ULONG        find_addr;
   USHORT       get_size   = PAGE_SIZE;            // table is read in pages
   USHORT       save_size  = *size;

   for ( *size=0; *size < save_size; )
          {
          if ( PAGE_SIZE - ( addr % PAGE_SIZE) < get_size )
                 get_size = (USHORT)(PAGE_SIZE - ( addr % PAGE_SIZE ));
          else
                 get_size = PAGE_SIZE;

          if (get_size > (save_size-*size))  /* Are we complete?                                  */
                 {
                 get_size = (save_size - *size);
                 }

          if ( LinearToPhysical( addr,&find_addr ))
                 // This page of the LDT is paged out; Set it to 0x00
                 {
                 _fmemset( ptr, 0x00, get_size);
                 *size = *size + get_size;
                 }
          else
                 {
                 if ( GetAddress(find_addr, get_size, (UCHAR FAR *)ptr) == 0)
                        *size = *size + get_size;
                 else
                        {
                        fprintf(stdout, "Error reading table in TableByPage\n" );
                        _fmemset( ptr, 0x00, get_size);
                        }
                 }
          ptr  = ptr + (get_size/2);              /* Increment buffer pointer            */
          addr = addr + get_size;                         /* increment linear address            */
          }
   return;
}

/*****************************************************************************
   LoadTables

   Comments:

   Input:       None.

   Output:      None.
*****************************************************************************/
USHORT LoadTables( void )
{
   USHORT       rc = 0;
   SEL          sel;
   DESCRIPTOR far *gdt;
   ULONG        ulSaveAddr, ulLDTSize;

   rc = DosAllocSeg( 4096, &sel, 0 );
   if ( rc )
          {
          fprintf( stdout,      "Out of memory in LoadTables\n" );
          rc = ERR_NO_MEMORY;
          goto done;
          }
   ptrDIR = MAKEP( sel, 0 );

  ulPhysPageDir = dumpInfoStruc.phys_page_dir;

   if ( rc = GetAddress( dumpInfoStruc.phys_page_dir, 4096,
                                                          (UCHAR FAR *)ptrDIR ))
          goto done;

   ptrDIR[0] =  dumpInfoStruc.savePage;

//122521   sizeGDT = dumpInfoStruc.gdtr_lim + 1;
   sizeGDT = (ULONG)(USHORT)dumpInfoStruc.gdtr_lim + 1;		//122521
			// BugBug -- gdtr_lim should probably get retyped as
			// USHORT but it doesn't seem to cause any other
			// difficulties, so we'll just cast it twice. 122521

// rc = DosAllocSeg( dumpInfoStruc.gdtr_lim + 1, &sel, 0 ); //122521
   rc = DosAllocSeg( sizeGDT, &sel, 0 ); //12251
   if ( rc )
          {
          fprintf( stdout,      "Out of memory in LoadTables\n" );
          rc = ERR_NO_MEMORY;
          goto done;
          }
   ptrGDT = MAKEP( sel, 0 );

   if ( rc = GetLinearAddress( dumpInfoStruc.gdtr_base,
                                     sizeGDT,				//122521
//122521                                                           (ULONG)dumpInfoStruc.gdtr_lim + 1,
                                                           (USHORT FAR *)ptrGDT, FALSE) )
          {
          fprintf( stdout,      "Error loading GDT\n" );
          goto done;
          }

   /* bring LDT table into memory */
   gdt = (DESCRIPTOR far *)((ULONG)ptrGDT +
                                                                 (ULONG)dumpInfoStruc.ldtr_reg);

   ulSaveAddr = (((ULONG)SHIFT_LEFT(gdt->base_hi, 24)) +
                                 ((ULONG)SHIFT_LEFT(gdt->base_mid,16)) +
                                 ((ULONG)                       gdt->base_lo));

   GetSegmentLimit( gdt, &ulLDTSize );           /* limit is zero based */

   rc = DosAllocSeg( 0, &sel, 0 );
   if ( rc )
          {
          fprintf( stdout,      "Out of memory in LoadTables\n" );
          rc = ERR_NO_MEMORY;
          goto done;
          }
   ptrLDT = MAKEP( sel, 0 );

   sizeLDT = (UINT)ulLDTSize;

   TableByPage( (ULONG)ulSaveAddr,(USHORT far *)ptrLDT, &sizeLDT );

   /*  set global variables for LDT (for the running process) */
   ulSaveAddr =  dumpInfoStruc.idtr_base;
   sizeIDT = dumpInfoStruc.idtr_lim + 1;

   rc = DosAllocSeg( sizeIDT, &sel, 0 );
   if ( rc )
          {
          fprintf( stdout,      "Out of memory in LoadTables\n" );
          rc = ERR_NO_MEMORY;
          goto done;
          }
   ptrIDT = MAKEP( sel, 0 );

   TableByPage((ULONG)dumpInfoStruc.idtr_base, (USHORT far *)ptrIDT,&sizeIDT );

   LoadObjectTable();

done:
   return( rc );
}

/*****************************************************************************
                                                         End Of File
*****************************************************************************/

