/*****************************************************************************
   Name:             memory.c

   Description:      Contains the logic to handle the memory related
                     information within a dump.

   Contains:

   Comments:
                     For the most part all of the symbol file handling
                     found near the end of this module has been stolen
                     from the 'old' dump formatter. It currently supports
                     only the kernel symbols but with not too much
                     work ( principally linking in other MapDef structs
                     in a linked list fashion and changing the query
                     logic ) it could support other symbol files as well.

   History:          11/04/92 - crs - New
                     02/12/93 - davidj took over finishing the symbol support

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

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

*****************************************************************************/
#define SCCSID ""
#define FAR32   _far                    // fp (48-bit pointer, restricted)
#define _stdcall

#define INCL_ERROR_H            /* for bseerr.h */
#define INCL_TYPES
#define  INCL_DOS
#include <os2.h>
//#include <basemac.h>
//#include <basedef.h>
#include <osconst.h>
#include <ostypes.h>

#define FNO_NUM         FNO_LDRMTE_C
#include <fnomem.h>
#include <osmac.h>
#include <mi.h>
#include <bseerr.h>
#include <dossymc.h>
#include <sigdef.h>
#include <except.h>
#include <pgexport.h>
#include <vmexport.h>
#include <selxport.h>
#include <tkexport.h>
typedef (PASCAL FAR32 *FPVOID)();       // fp (the only kind of FPVOID allowed)
#include <kmode.h>
#include <infoseg.h>
#include <curdir.h>
#include <dirent.h>
#include <find.h>
#include <screen.h>
#include <sem.h>
#include <tkptda.h>
#define FOR_EXEHDR      1
#include <newexe.h>
#include <exe386.h>

#undef PT_16BIT
#undef PT_32BIT
#undef HEADER_EXEINFO
#undef HEADER_READRSRCTBL
#undef HEADER_READSECTOR
#undef HEADER_LIBPATHLEN
#undef HEADER_LIBPATH
#undef HEADER_FIXENTRY
#undef HEADER_STE
#undef HEADER_MAPSEL
#include <ldrxport.h>
#include <ldrvars.h>

#include <vmowner.h>
#include <seldesc.h>
#include <sft.h>
#include <mvdmexp.h>
#include <kutil.h>
#include <string.h>
#include <dynxport.h>
#include <harderr.h>
#include <limits.h>
#include <memory.h>

#include <stdio.h>
#include <stdlib.h>
#include "debsym.h"
#include "df.h"
#include <sas.h>

#define  BUFF_LEN     80

/*****************************************************************************
                             Global Data
*****************************************************************************/
static CHAR  *szFile = __FILE__;           // for Error

SEL       sel = 0;                   // selector for file's content
UCHAR huge *pchBuffer;               // will house file's contents

MAPDEF    huge *MapDefPtr   =NULL;  // Pointer to symbol Map Definition struc
MAPDEFLST huge *MapDefLstPtr=NULL;  // Pointer to symbol Map Definition struc
USHORT Hugeinc=8;                    // hunge increment value (1<<usHugeshift)

/*****************************************************************************
                         External References
*****************************************************************************/
extern UINT  GetAddress(ULONG ulOffset, USHORT usNumBytes, UCHAR far *pBuf);
extern VOID  Error( PSZ, USHORT, USHORT, PSZ );
extern SHORT GetLinearAddress(ULONG, ULONG, USHORT far *, USHORT );
extern VOID  checkchr (VOID);
extern VOID  segcross ( CHAR far *, CHAR far *, USHORT );
extern PCHAR print_reg( LONG );

extern ULONG huge *ptrOBJ;               /* pointer to object table */
extern ULONG lastObject;                 /* pointer to last obj record */
extern ULONG freeObject;                 /* pointer to first free obj record  */
extern DUMPINFOSTRUC dumpInfoStruc;
extern PAGEDATACONTROLBLOCK far *ptrFirstPDCB;
extern CHAR     SymbolFilePath[255];

extern struct SAS_vm_section     far * ptrSASvm;


extern CHAR  szModuleName[256];            // Work area for module name
extern CHAR  szModuleName[256];            // Work area for module name
extern ULONG FAR *vpThreadTable;           // thread table
//extern struct ptda_s ptda;                 // storage for a PTDA
extern struct ptda_s FAR *vpPTDA;          // pointer to that structure
//extern struct tcb_s tcb;                   // storage for a TCB
extern struct tcb_s FAR *vpTCB;            // pointer to that structure
//extern struct tsd_s tsd;                   // storage for a TSD
extern struct tsd_s FAR *vpTSD;            // pointer to that structure
//extern struct cri_s cri;
extern struct cri_s FAR *vpCRI;

extern ULONG ulDefaultTSDAddr;
extern ULONG ulDefaultTCBAddr;
extern ULONG ulDefaultPTDAAddr;
extern USHORT usDefaultSlot;
extern USHORT usCurrentSlotAtDumptime;

extern USHORT usSlotCurrentlyInDir;
extern USHORT usCurrentPid;
extern USHORT usRelDispAddr;

extern struct RegSA_struc REGSA ;   // registers on task (.s) switch

extern int isPDump;
extern int GetPdumpMem(ULONG ulAddr, int nBytes, char *buffer);

/*****************************************************************************
                         Function Prototypes
*****************************************************************************/
USHORT FormatMTEOwner( VMHOB  hob, char  *pBuf );
USHORT FormatMTE( ULONG ulMTEAddr, CHAR *pOwner );
VOID   LoadObjectTable( void );

//int  LoadSymbolFile( char *szSymFile );
int  ReadInTheFile( char *szSymFile );
int  CActivateMap( CHAR far * szMapName );
int  SetupGroups( ULONG *ulMTEAddr );
int  LocateMTE ( ULONG *ulMTEAddr, CHAR far * szMapName);
int  ListMTE ( ULONG *ulMTEAddr, USHORT *sel);            // JAB 1/94
void DisplaySTATEInfo( void );
int  CdeActivateMap( CHAR far * szMapName );
int  CListMTEMap( CHAR far * szMapName );



/*****************************************************************************
   FormatMTEOwner

   Comments:

   Input:

   Output:
*****************************************************************************/
USHORT FormatMTEOwner( VMHOB  hob, char  *pBuf )
{
   CHAR    szOwner[128];
   USHORT  rc;
   VMHOB   tmpHandle;
   ULONG   ulMTEAddr;
   VMOB far *object;


//davidj 08/03/93  if hob ==0 then trap

   if (hob == 0)
     return(FALSE);
//

   szOwner[0] = '\0';

   // map handle to MTE address
   object = (VMOB huge *)ptrOBJ + ( (hob - 1) * sizeof( sizeof( VMOB ) ) / 2 );

   tmpHandle = object->ob_hobmte;
   if (object-> ob_hobnext < 0xfff)
      object = (VMOB huge *)ptrOBJ + ((tmpHandle - 1) * sizeof( sizeof(VMOB) ) / 2 );

   ulMTEAddr = (ULONG)object->ob_va;
   if ( ( rc = FormatMTE( ulMTEAddr, szOwner ) ) != ERR_NO_ERROR )
      return( TRUE );

   strcat( pBuf, szOwner );
      return( FALSE );
}

/*****************************************************************************
   FormatMTE

   Comments:

   Input:

   Output:
*****************************************************************************/
USHORT FormatMTE( ULONG ulMTEAddr, CHAR *pOwner )
{
   USHORT   rc;
   struct   ldrmte_s ldrMTE;
//   USHORT   len;
   CHAR     szMTEModname[MTE_NAME_LEN+1];

   rc = GetLinearAddress( ulMTEAddr, sizeof(struct ldrmte_s),
                         (INT far *)&ldrMTE, FALSE );

   if (rc != ERR_NO_ERROR)
      {
      //davidj 03/10/93
      Error( szFile, __LINE__, rc,
               "GetLinearAddress failed in FormatMTE loading ulMTEAddr");
      // might want to display some error msg here.
      return( TRUE );
      }


// warp change
#ifdef WARP

;   strncpy(szMTEModname, ldrMTE.mte_modname, MTE_NAME_LEN);
   strncpy(szMTEModname, ldrMTE.mte_modname, 8);
   strncpy(pOwner, ldrMTE.mte_modname, 8);
   pOwner[8] = '\0';

#else

   rc = GetLinearAddress( ldrMTE.mte_modname, MTE_NAME_LEN,
                          (INT far *)szMTEModname, FALSE );

   if (rc != ERR_NO_ERROR)
      {
//davidj 03/10/93
      Error( szFile, __LINE__, rc,
               "GetLinearAddress failed in FormatMTE loading ldrMTE.mte_modname");
      // might want to display some error msg here.
      return( TRUE );
      }


//   len = szMTEModname[0];              // len stored in element zero
   strncpy( pOwner, &szMTEModname[1], szMTEModname[0] );
   pOwner[len] = '\0';

#endif

//davidj 03/15/93
#ifdef BORG
   if ((char)ldrMTE.mte_flags2 == 'T' && (char)ldrMTE.mte_flags2+1 == 'D')
      strcat(pOwner,"ptda 0002");
#else
   if (ldrMTE.mte_magic[0] == 'T' && ldrMTE.mte_magic[1] == 'D')
      strcat(pOwner,"ptda 0002");
#endif
//davidj 03/15/93

   return( FALSE );
}

/*****************************************************************************
   LoadObjectTable

   Comments:

   Input:   None.

   Output:  None.
*****************************************************************************/
VOID LoadObjectTable( void )
{
   USHORT   rc;
   ULONG    ulAddr;                 // Hold a linear address
   ULONG    ulTableSize;            // Size of arena table
   VMBH     vmbh;                   // VM header of arena table
   char huge *cHuge;
   PAGEDATACONTROLBLOCK FAR *ptrPDCB;
   SEL      sel;

   ulAddr  = dumpInfoStruc.vm_object_ptr - (ULONG)sizeof(VMBH);

   rc = GetLinearAddress( ulAddr, sizeof(VMBH), (INT far *) &vmbh, FALSE );
   if ( rc != ERR_NO_ERROR )
      {
//davidj 03/10/93
      Error( szFile, __LINE__, rc,
               "GetLinearAddress failed in LoadObjectTable loading vmbh");
      // cannot read VM header of object table
      // should display err msg here...
      goto done;
      }

   ulTableSize = (ULONG)vmbh.bh_pbEndBlocks - dumpInfoStruc.vm_object_ptr;

   rc = DosAllocHuge( (USHORT)(ulTableSize / SEGSIZE) ,(USHORT)(ulTableSize % SEGSIZE), &sel,0,0 );
   if ( rc )
      {
      fprintf( stdout,  "Out of memory in LoadObectTable\n" );
      rc = ERR_NO_MEMORY;
      goto done;
      }
   ptrOBJ = MAKEP( sel, 0 );

   // Load object table from dump
   ulAddr = dumpInfoStruc.vm_object_ptr;
   cHuge = (char huge *)ptrOBJ;
   rc = 0;
   while (ulTableSize > 32768L && rc == 0)
      {
      rc = GetLinearAddress( ulAddr, 32768L,(USHORT far *)cHuge, TRUE );
      cHuge += 32768L;
      ulTableSize -=32768L;
      ulAddr += 32768L;
      }
   rc = GetLinearAddress( ulAddr, ulTableSize, (USHORT far *)cHuge, TRUE );

   if ( rc == ERR_MEM_NOT_PRESENT || rc == ERR_NO_ERROR)
      {
      // Continue on...
      }
   else
      {
//davidj 03/10/93
      Error( szFile, __LINE__, rc,
               "GetLinearAddress failed in LoadObjectTable loading object table");
      // The object table couldn't be read in
      // display approp error message.
      ptrOBJ = NULL;
      goto done;
      }

   for (ptrPDCB  = ptrFirstPDCB; ptrPDCB != NULL; ptrPDCB  = ptrPDCB->NextCB)
      {
      // Check whether one of the pages of the object table is paged out
      if (ptrPDCB->Data_ptr == NULL)
         {
         fprintf( stdout, "LoadObjectTable - data paged out from %lx to %lx\n",
                  ptrPDCB->LinearAddress,
                  ptrPDCB->LinearAddress+(ptrPDCB->Length-1 ) );
         }
      }

   DosFreeSeg( SELECTOROF( ptrFirstPDCB ) );

   lastObject = (ULONG)vmbh.bh_pbLastBusy;
   freeObject = (ULONG)vmbh.bh_pbFreeHead;

done:
   return;
}

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

int LocateMTE ( ULONG *ulMTEAddr, CHAR far * szMapName)  // revised JAB 1/94

{
   USHORT   rc=0;
   USHORT   count;
   ldrmte_t   ldrMTE;

#ifndef WARP
   USHORT   len;
   CHAR     szTMPModname[MTE_NAME_LEN+1];
#endif

   CHAR     szMTEModname[MTE_NAME_LEN+1];

   count=0;

   while (*ulMTEAddr)
   {

     rc = GetLinearAddress( *ulMTEAddr, sizeof(struct ldrmte_s),
                           (INT far *)&ldrMTE, FALSE );

     if (rc != ERR_NO_ERROR)
     {
        Error( szFile, __LINE__, rc,
                 "GetLinearAddress failed in LocateMTE loading *ulMTEAddr");
        return( 1 );
     }

//warp change
#ifdef WARP

     strncpy(szMTEModname, ldrMTE.mte_modname, 8);
     szMTEModname[8] = '\0';

#else
     rc = GetLinearAddress( ldrMTE.mte_modname, MTE_NAME_LEN,
                            (INT far *)szTMPModname, FALSE );

     if (rc != ERR_NO_ERROR)
     {
        Error( szFile, __LINE__, rc,
                 "GetLinearAddress failed in LocateMTE loading ldrMTE.mte_modname");
        return( 1 );
     }

     len = szTMPModname[0];              // len stored in element zero
     strncpy( szMTEModname, &szTMPModname[1], len );
     szMTEModname[len] = '\0';

#endif

     if (!strcmp(szMapName, strlwr(szMTEModname)))
         return( 0 );

//#endif
     *ulMTEAddr = (ULONG)ldrMTE.mte_link;
     checkchr();

   }

   return( 0 );
}


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

int ListMTE ( ULONG *ulMTEAddr, USHORT *sel )       // added JAB 1/94
{
   USHORT   rc=0;
//   USHORT   len;
   USHORT   count;
   USHORT   objsel;
// struct   ldrmte_s   ldrMTE;
// struct   ldrsmte_s  ldrsMTE;
   ldrmte_t   ldrMTE;
   ldrsmte_t  ldrsMTE;
   ldrote_t   ldrOTE;
   ULONG      ulLdrOteAddr;
   USHORT     usLdrOteCnt;
   ldrste_t   ldrSTE;
   ULONG      ulLdrSteAddr;
   USHORT     usLdrSteCnt;
   USHORT     usObjectCount;

//   CHAR     szTMPModname[MTE_NAME_LEN+1];
   CHAR     szMTEModname[MTE_NAME_LEN+1];
   CHAR     szMTEPathname[255];
   CHAR     szTMPPathname[255];
   ULONG    ulTmp;

#ifndef WARP
   USHORT   len;
   CHAR     szTMPModname[MTE_NAME_LEN+1];
#endif

count = 0;

while (*ulMTEAddr)
{
     rc = GetLinearAddress( *ulMTEAddr, sizeof(struct ldrmte_s),
                           (INT far *)&ldrMTE, FALSE );

     if (rc != ERR_NO_ERROR)
     {
        Error( szFile, __LINE__, rc,
                 "GetLinearAddress failed in LocateMTE loading *ulMTEAddr");
        return( 1 );
     }

//warp change
#ifdef WARP

   strncpy(szMTEModname, ldrMTE.mte_modname, 8);
   szMTEModname[8] = '\0';

#else

     rc = GetLinearAddress( ldrMTE.mte_modname, MTE_NAME_LEN,
                            (INT far *)szTMPModname, FALSE );

     if (rc != ERR_NO_ERROR)
     {
        Error( szFile, __LINE__, rc,
                 "GetLinearAddress failed in LocateMTE loading ldrMTE.mte_modname");
        return( 1 );
     }

     len = szTMPModname[0];              // len stored in element zero
     strncpy( szMTEModname, &szTMPModname[1], len );
     szMTEModname[len] = '\0';

#endif

     // get the swappable MTE record
     ulTmp = (ULONG)ldrMTE.mte_swapmte;
     rc = GetLinearAddress( ulTmp, sizeof(struct ldrsmte_s),
                           (INT far *)&ldrsMTE, FALSE );

     if (rc != ERR_NO_ERROR)
     {
     // failed to load ldrMTE.mte_swapmte
        strcpy(szMTEPathname,"Swapped out");
     }
     else
     {
       if (ldrsMTE.smte_pathlen >0)
       {
        rc = GetLinearAddress( ldrsMTE.smte_path, ldrsMTE.smte_pathlen,
                               (INT far *)szTMPPathname, FALSE );

        if (rc != ERR_NO_ERROR)
           {
           Error( szFile, __LINE__, rc,
                    "GetLinearAddress failed in CActivateMap loading ldrsMTE.smte_pathname");
           break;
           }

        strncpy(szMTEPathname, szTMPPathname, ldrsMTE.smte_pathlen);
       }

       szMTEPathname[ldrsMTE.smte_pathlen] = '\0';

       fprintf(stdout,"%4d %4.4x %%%lx %-10s %s\n     ",++count, ldrMTE.mte_handle, *ulMTEAddr, szMTEModname, szMTEPathname);

///////////////////////////////////////////////////////////////////////
//davidj 09/28/93  fixed 16 and 32 bit support for symbols           //
//                 also needed this ifdef for pre 2.1 compatibility  //
//                 all
///////////////////////////////////////////////////////////////////////
#ifdef BORG
if ( ldrMTE.mte_flags2 & MTEFORMATLX )
#else
if ((char)ldrMTE.mte_magic[0] == 'L' && (char)ldrMTE.mte_magic[1] == 'X')
#endif
{
       ulLdrOteAddr = ldrsMTE.smte_objtab;
       usLdrOteCnt  = (USHORT)ldrsMTE.smte_objcnt;
       usObjectCount =0;

       while (( usObjectCount < usLdrOteCnt ) && (*sel != objsel))
       {
          rc = GetLinearAddress( ulLdrOteAddr, sizeof(struct ldrote_s),
                             (INT far *)&ldrOTE, FALSE );

          if ( rc == ERR_NO_ERROR )
          {
             if ( ldrOTE.ote_flags & 0x2000 )   // flat
             {
                  objsel=(USHORT)SHIFT_RIGHT(ldrOTE.ote_base, 16);
                  fprintf(stdout,"%04.4x ",objsel);
             }
             else
             {
                  objsel=ldrOTE.ote_selector;
                  fprintf(stdout,"%04.4x ",objsel);
             }
          }

          ulLdrOteAddr += sizeof( struct ldrote_s );
          usObjectCount++;
          if (!(usObjectCount%15)) fprintf(stdout,"     ");
       }

       if ( usLdrOteCnt > 0)
          fprintf(stdout,"\n");
}
else  // 16bit code MTEFORMATNE
{
       ulLdrSteAddr = ldrsMTE.smte_objtab;
       usLdrSteCnt  = (USHORT)ldrsMTE.smte_objcnt;
       usObjectCount =0;

       while (( usObjectCount < usLdrSteCnt ) && (*sel != objsel))
       {
          rc = GetLinearAddress( ulLdrSteAddr, sizeof(struct ldrste_s),
                             (INT far *)&ldrSTE, FALSE );

          if ( rc == ERR_NO_ERROR )
          {
              objsel=ldrSTE.ste_selector;
              fprintf(stdout,"%04.4x ",objsel);
          }

          ulLdrSteAddr += sizeof( struct ldrste_s );
          usObjectCount++;
          if (!(usObjectCount%15)) fprintf(stdout,"     ");
       }

       if ( usLdrSteCnt > 0)
           fprintf(stdout,"\n");
     }
}

   *ulMTEAddr = (ULONG) ldrMTE.mte_link;
   checkchr();

}                 /* end of while */

}                 /* end of ListMTE */



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

   ReadInTheFile

   Just a brute force load of a symbol file. The entire file is read in
   and linked into the MapDefPtr struct.
****************************************************************************/

int ReadInTheFile( char *szSymFile )
{
   FILESTATUS fstsFile;
   UCHAR huge *pchTmp;
   USHORT    usHugeShift;               // segment index shift value                              */
   USHORT    usReturnCode = 0;         // return code from Dos APIs
   USHORT    usAction;                 // open action taken
   ULONG     ulBytesRead;
   HFILE     hFile = 0;                // file handle
   USHORT    usBytes;
   UINT      i;
   ULONG     ulBytesNeeded;
   USHORT    usMSize = sizeof( MapDefPtr->MapLink );

   if (usReturnCode = DosOpen(szSymFile,
                              &hFile,
                              &usAction,
                              0L,
                              FILE_NORMAL,
                              FILE_OPEN,
                              OPEN_ACCESS_READONLY | OPEN_SHARE_DENYNONE,
                              0L))
      {
//      fprintf(stdout,"Error openning Symbol file (%s)\n", strlwr(szSymFile));
      return(usReturnCode);
      }

   DosQFileInfo( hFile, 1, &fstsFile, sizeof( FILESTATUS ));

   ulBytesNeeded = usMSize + fstsFile.cbFile;

                                       // get some memory...
   if (usReturnCode = DosAllocHuge((USHORT)(ulBytesNeeded / UINT_MAX),
                                   (USHORT)(ulBytesNeeded % UINT_MAX),
                                   &sel,
                                   0,
                                   SEG_NONSHARED))
      {
      fprintf( stdout, "Error, Could not allocate memory to load symbol file %s, rc=%d",szSymFile, usReturnCode);
      fflush(stdout);
      DosClose(hFile);
      return(usReturnCode);
      }

//   fprintf(stdout,"allocated selector %d\n",sel);
   DosGetHugeShift(&usHugeShift);

   Hugeinc=(1 << usHugeShift);

//   fprintf( stdout, "Starting to Read in Symbol File %s file\n",szSymFile );
//   fflush(stdout);
   ulBytesRead = 0L;
   i = 0;
   while (ulBytesRead < fstsFile.cbFile)
      {
      usBytes = (fstsFile.cbFile-ulBytesRead) > (ULONG)32768 ?
                        (USHORT)32768 : (USHORT)(fstsFile.cbFile-ulBytesRead);

      pchTmp = (PVOID)MAKEP(sel+( (i / 2) <<usHugeShift),
                            (32768 * (i % 2)) );

      if ( usMSize )
         {
         pchTmp += usMSize;
         if ( usMSize + usBytes > 32768 )
            {
            int   x;
            x = ( usMSize + usBytes ) - (USHORT)32768;
            usBytes -= x;
            }
         usMSize = 0;
         }

      if (usReturnCode = DosRead(hFile,
                                 pchTmp,
                                 usBytes,
                                 &usBytes))
         {
         fprintf( stdout, "Error, Reading Symbol File %s file, rc=%d\n",szSymFile, usReturnCode );
         fflush(stdout);
//         fprintf(stdout,"deallocated selector %d\n",sel);
         DosFreeSeg(sel);
         DosClose(hFile);
         return(usReturnCode);
         }
      ulBytesRead += usBytes;
      i++;
      }

//   fprintf( stdout, "Finished Reading in Symbol File %s file\n",szSymFile );
//   fflush(stdout);

   MapDefPtr = (struct MapDef * )pchBuffer = MAKEP(sel, 0);
   MapDefPtr->MapLink.MapPtr.AddrSeg = 0;
   MapDefPtr->MapLink.MapPtr.AddrSize = 0;
   MapDefPtr->MapFlags = MAP_FLAG_ACTIVE;

   fflush(stdout);
   DosClose( hFile );
   return( 0 );
}



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


   SetupGroups

   This routine assigns the memory locations to the various groups.
*****************************************************************************/

int SetupGroups( ULONG *ulMTEAddr )
{
   struct GroupDef huge *GroupDefPtr;
   USHORT   rc;
   ULONG    ulTmp;
   struct   ldrmte_s  ldrMTE;
   struct   ldrsmte_s ldrsMTE;
   ULONG    ulLdrOteAddr;
   ULONG    ulLdrSteAddr;
   struct   ldrote_s ldrOTE;
   struct   ldrste_s ldrSTE;
   USHORT   usMSize = sizeof( MapDefPtr->MapLink );
   USHORT   usGroupCount = 0;
   ULONG    ulNextGroup = 0;
   UCHAR huge *pchTmp;

   // get the SAS kernel MTE record
   ulTmp = *ulMTEAddr;

   if (isPDump)
     rc = GetPdumpMem(ulTmp, sizeof(struct ldrmte_s), (char *)&ldrMTE);
   else
     rc = GetLinearAddress( ulTmp, sizeof(struct ldrmte_s),
                         (INT far *)&ldrMTE, FALSE );

   if (rc != ERR_NO_ERROR)
      {
      // might want to display some error msg here.
//      Error( szFile, __LINE__, rc, "GetLinearAddress failed in SetupGroups loading mte");
      return( rc );
      }

   // get the swappable MTE record
   ulTmp = (ULONG)ldrMTE.mte_swapmte;

   if (isPDump)
     rc = GetPdumpMem(ulTmp, sizeof(struct ldrsmte_s), (char *)&ldrsMTE);
   else
     rc = GetLinearAddress( ulTmp, sizeof(struct ldrsmte_s),
                           (INT far *)&ldrsMTE, FALSE );

   if (rc != ERR_NO_ERROR)
      {
//      Error( szFile, __LINE__, rc, "GetLinearAddress failed in SetupGroups loading ldrMTE.mte_swapmte");
      // might want to display some error msg here.
      return( rc );
      }

///////////////////////////////////////////////////////////////////////
//davidj 09/28/93  fixed 16 and 32 bit support for symbols           //
//                 also needed this ifdef for pre 2.1 compatibility  //
//                 all
///////////////////////////////////////////////////////////////////////
#ifdef BORG
if ( ldrMTE.mte_flags2 & MTEFORMATLX )
#else
if ((char)ldrMTE.mte_magic[0] == 'L' && (char)ldrMTE.mte_magic[1] == 'X')
#endif
{
   ulLdrOteAddr = ldrsMTE.smte_objtab;

   GroupDefPtr = (struct GroupDef *)((ULONG)MapDefPtr +
                                     (MapDefPtr->GroupChain << 4) + usMSize);

   while ( usGroupCount < (USHORT)MapDefPtr->GroupCnt )
      {
        if (isPDump)
            rc = GetPdumpMem(ulLdrOteAddr, sizeof(struct ldrote_s), (char *)&ldrOTE);
        else
            rc = GetLinearAddress( ulLdrOteAddr, sizeof(struct ldrote_s),
                                   (INT far *)&ldrOTE, FALSE );

      if ( rc == ERR_NO_ERROR )
         {
         if ( ldrOTE.ote_flags & 0x2000 )   // flat
            {
            GroupDefPtr->GroupAddrSel = (USHORT)SHIFT_RIGHT(ldrOTE.ote_base, 16);
            GroupDefPtr->GroupAddrSeg = (USHORT)ldrOTE.ote_base;
            GroupDefPtr->GroupAddrType = SYM_TYPE_LIN;
            }
         else
            {
// david 09/09/93  check to see if the selector is conforming and force
//                 it be a ring 3 so that symbol lookups work

            if ((ldrOTE.ote_selector & 2) && !(ldrOTE.ote_selector & 1))
              GroupDefPtr->GroupAddrSel = ldrOTE.ote_selector +1;
            else
              GroupDefPtr->GroupAddrSel = ldrOTE.ote_selector ;

            GroupDefPtr->GroupAddrSeg = 0x00;
            GroupDefPtr->GroupAddrType = SYM_TYPE_SEL;
            }
         }
      else                                   // swapped out
         {
         GroupDefPtr->GroupAddrSel = 0;
         }

      ulLdrOteAddr += sizeof( struct ldrote_s );

      // Get the next group
      ulNextGroup = SHIFT_LEFT(GroupDefPtr->GroupLink, 4);
      if ( ulNextGroup == 0 )
         {
         usGroupCount = MapDefPtr->GroupCnt;
         }
      else
         {
         pchTmp = (UCHAR huge *)MapDefPtr;
         pchTmp += ulNextGroup;
         pchTmp += usMSize;
         GroupDefPtr = (struct GroupDef huge *)pchTmp;

         usGroupCount++;
         }
      }
}
else  // 16bit code MTEFORMATNE
{
   ulLdrSteAddr = ldrsMTE.smte_objtab;

   GroupDefPtr = (struct GroupDef *)((ULONG)MapDefPtr +
                                     (MapDefPtr->GroupChain << 4) + usMSize);

   while ( usGroupCount < (USHORT)MapDefPtr->GroupCnt )
      {
        if (isPDump)
            rc = GetPdumpMem(ulLdrSteAddr, sizeof(struct ldrste_s), (char *)&ldrSTE);
        else
            rc = GetLinearAddress( ulLdrSteAddr, sizeof(struct ldrste_s),
                                   (INT far *)&ldrSTE, FALSE );

      if ( rc == ERR_NO_ERROR )
         {

// Revised, JAB 2/94
// david 09/09/93  check to see if the selector is conforming and force
//                 it be a ring 3 so that symbol lookups work

          if ((ldrSTE.ste_selector & 2) && !(ldrSTE.ste_selector & 1))
            GroupDefPtr->GroupAddrSel = ldrSTE.ste_selector +1;
          else
            GroupDefPtr->GroupAddrSel = ldrSTE.ste_selector ;

          GroupDefPtr->GroupAddrSeg = 0x00;
          GroupDefPtr->GroupAddrType = SYM_TYPE_SEL;
         }
      else                                   // swapped out
         {
         GroupDefPtr->GroupAddrSel = 0;
         }

      ulLdrSteAddr += sizeof( struct ldrste_s );

      // Get the next group
      ulNextGroup = SHIFT_LEFT(GroupDefPtr->GroupLink, 4);
      if ( ulNextGroup == 0 )
         {
         usGroupCount = MapDefPtr->GroupCnt;
         }
      else
         {
         pchTmp = (UCHAR huge *)MapDefPtr;
         pchTmp += ulNextGroup;
         pchTmp += usMSize;
         GroupDefPtr = (struct GroupDef huge *)pchTmp;

         usGroupCount++;
         }
      }
}
   return( 0 );
}

/***********************************************************
                            Map Add handling...
        Support for wa * added 2/94
***********************************************************/


int CActivateMap( CHAR far * szMapName )
{

   CHAR         szSymbolFilename[255]="\0";
   CHAR         *tmpSymPtr, *SymPtr;
   INT                  pathLen;
   INT                  numLink = 0;
   INT                  fLink = 0;
   INT                  errorReadInFile  = 0;
   INT                  errorSetupGroups = 0;
   ULONG                ulMTEAddr;
   USHORT               rc = 0;
//   USHORT               len;
   ldrmte_t             ldrMTE;
//   CHAR         szTMPModname[MTE_NAME_LEN+1];
   CHAR         szMTEModname[MTE_NAME_LEN+1];
   CHAR         Map_Name[BUFF_LEN];
   CHAR         far  *MapNamePtr;
   MAPDEF       huge *MapAddr;
   MAPDEFLST    huge *tmpMapDefLstPtr, *indexPtr;

#ifndef WARP
   CHAR         *tmpPtr;
   USHORT   len;
   CHAR     szTMPModname[MTE_NAME_LEN+1];
#endif


   if (!szMapName[0])
   {
      fprintf(stdout, "Error, must specify a symbol filename or * for all symbols\n");
      fflush(stdout);
      return(0);
   }

   strlwr(++szMapName);

   if ((tmpSymPtr=strrchr(szMapName,'.')))
        *tmpSymPtr = NULL;

   strcpy(szSymbolFilename, szMapName);

   if ((SymPtr=strrchr(szMapName,'\\')))
      SymPtr += 1;
   else if ((SymPtr=strrchr(szMapName,':')))
      SymPtr += 1;
   else
      SymPtr = szMapName;

   if (SymPtr==szMapName)  // no path has been specified
      sprintf( szSymbolFilename, "%s%s", SymbolFilePath, SymPtr);
   //else there is a path specified

   if ((tmpSymPtr = strrchr(szSymbolFilename,'*')))
        *tmpSymPtr = NULL;

   pathLen = strlen(szSymbolFilename);

//diem 03/10/94
   if (!strcmp(SymPtr,"os2krnlr") || !strcmp(SymPtr,"os2krnld") || !strcmp(SymPtr,"os2krnlb"))
   {
      if (isPDump)
        return 0;

      ulMTEAddr = ptrSASvm->SAS_vm_krnl_mte;
      goto next;
    }

    if (isPDump)
    {
        extern void GetNextMTE( ULONG *mteAddr );

        ulMTEAddr = -1;
        GetNextMTE(&ulMTEAddr);

    }
    else
        ulMTEAddr = (ULONG)mte_h;

   while (ulMTEAddr)
   {
        if (isPDump)
          rc = GetPdumpMem(ulMTEAddr, sizeof(struct ldrmte_s), (char *)&ldrMTE);
        else
          rc = GetLinearAddress(ulMTEAddr, sizeof(struct ldrmte_s),
                                        (INT far *)&ldrMTE, FALSE );

        if (rc != ERR_NO_ERROR)
        {
            fprintf(stdout, "Symbol file (%s) could not be loaded, MTE is Swapped out\n", szSymbolFilename);
            fflush(stdout);
            return( rc );
        }

//warp change
#ifdef WARP

   strncpy(szMTEModname, ldrMTE.mte_modname, 8);
   szMTEModname[8] = '\0';

#else

        rc = GetLinearAddress( ldrMTE.mte_modname, MTE_NAME_LEN,
                                        (INT far *)szTMPModname, FALSE );

        if (rc != ERR_NO_ERROR)
        {
            fprintf(stdout, "Symbol file (%s) could not be loaded, MTE Module Name Swapped out\n", szSymbolFilename);
            fflush(stdout);
            return( 1 );
        }

        len = szTMPModname[0];              // len stored in element zero
        strncpy( szMTEModname, &szTMPModname[1], len );
        szMTEModname[len] = '\0';

#endif

//        if (!strncmp(SymPtr, strlwr(szMTEModname),strlen(SymPtr)) || SymPtr[0] == '*')
        if (!strncmp(SymPtr, strlwr(szMTEModname), 8) || SymPtr[0] == '*')
        {
            if (SymPtr[0] == '*')
               strcpy(&szSymbolFilename[pathLen], strlwr(szMTEModname));
next:
            strcat(szSymbolFilename,".sym");

            if (ReadInTheFile(szSymbolFilename)!=ERR_NO_ERROR)
            {
                if (SymPtr[0] != '*')
                {
                  fprintf(stdout, "Symbol file (%s) could not found\n", szSymbolFilename);
                  fflush(stdout);
                  return( 1 );
                }
                else
                   errorReadInFile = 1;
            }
            else
                 errorReadInFile = 0;

            if (!errorReadInFile)
            {
                for(tmpMapDefLstPtr = MapDefLstPtr; tmpMapDefLstPtr != NULL;
                        tmpMapDefLstPtr = tmpMapDefLstPtr->MapDefPrv)
                {
                   if (MapDefLstPtr==NULL) {
                      fprintf(stdout,"I am inside the for loop\n");
                      fflush(stdout);
                    }
                   MapAddr = tmpMapDefLstPtr->MapDefPtr;
                   MapNamePtr = (CHAR huge *)((ULONG)MapAddr + sizeof(*MapAddr));
                   _fmemcpy(Map_Name, MapNamePtr,MapAddr->MapNameLen);
                   _fmemcpy(Map_Name + MapAddr->MapNameLen, "\0", 1);

                   if(!strcmp(strlwr(Map_Name),strlwr(szMTEModname)) || !strcmp(strlwr(Map_Name),SymPtr))
                   {
                     fprintf(stdout, "Symbol (%s)    \t\t\talready linked\n", strlwr(Map_Name));
                     fflush(stdout);
                     numLink++;
                     fLink = 1;
                     break;
                   }
                   checkchr();
                }

                if (!fLink)
                {
                    if ( SetupGroups( &ulMTEAddr )!=ERR_NO_ERROR )
                    {
                        if (SymPtr[0] != '*')
                        {
                           fprintf(stdout,"Error in SetupGroups for symbol file (%s)\n", szSymbolFilename);
                           fflush(stdout);
                           return( 1 );
                        }
                        else
                           errorSetupGroups = 1;
                    }
                    else
                         errorSetupGroups = 0;

                    if (!errorSetupGroups)
                    {
                       numLink++;
                       fprintf(stdout, "Symbol (%s) linked\n", strlwr(szSymbolFilename));
                       fflush(stdout);

                         if ( MapDefLstPtr==NULL)
                         {
                            MapDefLstPtr=(MAPDEFLST huge *)malloc(sizeof(MAPDEFLST)*2);
//                            fprintf(stdout, "malloc MapDefLstPtr=%ld\n",MapDefLstPtr);
                            MapDefLstPtr->MapDefPrv=(MAPDEFLST *)NULL;
                            MapDefLstPtr->MapDefNxt=(MAPDEFLST *)NULL;
                            MapDefLstPtr->MapDefPtr=MapDefPtr;
                         }
                         else
                         {
                          while ( 1 )
                          {
                            tmpMapDefLstPtr=(MAPDEFLST huge *)malloc(sizeof(MAPDEFLST));
//                            fprintf(stdout, "malloc tmpMapDefLstPtr=%ld\n",tmpMapDefLstPtr);
                            for(indexPtr = MapDefLstPtr;
                              (indexPtr != NULL && tmpMapDefLstPtr!=indexPtr);
                               indexPtr = indexPtr->MapDefPrv);
                            if (indexPtr==NULL)
                            {
                              MapDefLstPtr->MapDefNxt=tmpMapDefLstPtr;
                              tmpMapDefLstPtr->MapDefPrv=MapDefLstPtr;
                              MapDefLstPtr=tmpMapDefLstPtr;
                              MapDefLstPtr->MapDefPtr=MapDefPtr;
                              MapDefLstPtr->MapDefNxt=(MAPDEFLST *)NULL;
                              break;
                            }
                            checkchr();
                          }
                         }
                    }
                }
            }

            if (SymPtr[0] != '*')
            {
                if (!numLink)
                    fprintf(stdout, "Symbol file (%s) not found\n", szSymbolFilename);
                fflush(stdout);
                break;
            }

        }   // endif

        fLink = 0;
        errorReadInFile = 0;
        errorSetupGroups = 0;

        if (isPDump)
            GetNextMTE( &ulMTEAddr );
        else
            ulMTEAddr = (ULONG)ldrMTE.mte_link;

        checkchr();

   } //endwhile

//   if (!numLink)
//      fprintf(stdout, "No symbol file found in this current directory\n");

   fflush(stdout);
}

/************************END OF CActivateMap**************************/



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

   Map Deactivate handling...

Support for WR * added 2/94
****************************************************************************/


int CdeActivateMap( CHAR far * szMapName )

{

CHAR            Map_Name[BUFF_LEN];
CHAR            far *MapNamePtr;
MAPDEFLST    huge   *tmpMapDefLstPtr, *indexPtr;
MAPDEF          huge *MapAddr;
INT             numReleased = 0;


   if (!(szMapName))    // Not a map name
   {
     fprintf(stdout, "Must specify a symbol filename\n");
     fflush(stdout);
     return(0);
   }

   szMapName++;

   /* Traverse chain and find matching symbol name */

   for(indexPtr = MapDefLstPtr; indexPtr != NULL; indexPtr = indexPtr->MapDefPrv)
   {
    tmpMapDefLstPtr = indexPtr;
    MapAddr = tmpMapDefLstPtr->MapDefPtr;
    MapNamePtr = (CHAR huge *)((ULONG)MapAddr + sizeof(*MapAddr));
    _fmemcpy(Map_Name, MapNamePtr,MapAddr->MapNameLen);
    _fmemcpy(Map_Name + MapAddr->MapNameLen, "\0", 1);

    if (!strcmp(strlwr(Map_Name),strlwr(szMapName)) || *szMapName == '*')
        {

           /* update MapDefLstPtr if releasing end node */

           if(tmpMapDefLstPtr->MapDefNxt==NULL)
           {
                if(tmpMapDefLstPtr->MapDefPrv==NULL)
                    MapDefLstPtr = NULL;
                 else
                    MapDefLstPtr = MapDefLstPtr->MapDefPrv;
           }


           /* Redirect pointers as appropriate */

           if(tmpMapDefLstPtr->MapDefPrv != NULL)
                  tmpMapDefLstPtr->MapDefPrv->MapDefNxt =  tmpMapDefLstPtr->MapDefNxt;
           if(tmpMapDefLstPtr->MapDefNxt != NULL)
                 tmpMapDefLstPtr->MapDefNxt->MapDefPrv =  tmpMapDefLstPtr->MapDefPrv;

           /* Finally, release memory occupied by node */

           fprintf(stdout, "Map %s deactivated\n", Map_Name);
           fflush(stdout);
//           fprintf(stdout,"freeing tmpMapDefLstPtr for Map %s\n",Map_Name);
           free(tmpMapDefLstPtr);
           numReleased++;
        }  /* end of Big IF */

        if (*szMapName != '*' && numReleased)
           break;
        checkchr();
   }  /* end of FOR loop */

//diem 3/1/94
  if (MapDefLstPtr)
     MapDefPtr = MapDefLstPtr->MapDefPtr;
  else
     MapDefPtr = NULL;
  fprintf(stdout,"%d symbol file%s released", numReleased, numReleased == 1 ? "" : "s");
  fflush(stdout);

}   /* end of CdeActivateMap */

/****************************************************************************
   List MTE Map handling
****************************************************************************/


int CListMTEMap( CHAR far * szMapName )
{
   ULONG          ulMTEAddr;
   CHAR           *pszSymbol;
   USHORT         sel, *psel;
   ULONG          offset, *poffset;

   pszSymbol = szMapName;

   if (szMapName[0]>1)    // then it is a map name
   {
     szMapName++;
   }
   else
   {
     pszSymbol++;          // by pass 0 which indicates an address
     poffset = (ULONG *) pszSymbol;
     pszSymbol += 4;          // need to pass selector part of the address

     psel = (USHORT *) pszSymbol;

     memcpy(&sel,psel,sizeof(sel));
     memcpy(&offset,poffset,sizeof(poffset));

     ulMTEAddr = (ULONG)mte_h;

     ListMTE ( &ulMTEAddr, &sel);  // changed from LocateMTE

     fflush(stdout);
     return(FALSE);
   }

  fflush(stdout);

}

// from kmode.h
//        KM_REG_DS    FIELDOFFSET(CRI,cri_ds.rip_flags)
//        KM_REG_ES    FIELDOFFSET(CRI,cri_es.rip_flags)
//        KM_REG_SS    FIELDOFFSET(CRI,cri_ss.rip_flags)
//        KM_REG_CS    FIELDOFFSET(CRI,cri_cs.rip_flags)
//        KM_REG_GS    FIELDOFFSET(CRI,cri_gs.rip_flags)
//        KM_REG_FS    FIELDOFFSET(CRI,cri_fs.rip_flags)
//        KM_REG_EAX      FIELDOFFSET(CRI,cri_eax.rip_flags)
//        KM_REG_EBX      FIELDOFFSET(CRI,cri_ebx.rip_flags)
//        KM_REG_ECX      FIELDOFFSET(CRI,cri_ecx.rip_flags)
//        KM_REG_EDX      FIELDOFFSET(CRI,cri_edx.rip_flags)
//        KM_REG_EBP      FIELDOFFSET(CRI,cri_ebp.rip_flags)
//        KM_REG_ESP      FIELDOFFSET(CRI,cri_esp.rip_flags)
//        KM_REG_ESI      FIELDOFFSET(CRI,cri_esi.rip_flags)
//        KM_REG_EDI      FIELDOFFSET(CRI,cri_edi.rip_flags)
//        KM_REG_EIP      FIELDOFFSET(CRI,cri_eip.rip_flags)
//        KM_REG_EFLAG    FIELDOFFSET(CRI,cri_eflag.rip_flags)
//        KM_REG_CBARGS      FIELDOFFSET(CRI,cri_cbargs.rip_flags)
//        KM_REG_TRAPNUM     FIELDOFFSET(CRI,cri_trapnum.rip_flags)
//        KM_REG_ERRCODE     FIELDOFFSET(CRI,cri_errcode.rip_flags)

/****************************************************************************
   DisplaySTATEInfo
****************************************************************************/

void DisplaySTATEInfo( void )
{
   ULONG    ulTCBFrame;
   ULONG    ulFrameOffsetValue;
   ULONG    ulTCBFrameBase;
   VMHOB   tmpHandle;
   ULONG   ulMTEAddr;
   VMOB far *object;
   struct   ldrmte_s ldrMTE;
   ULONG   tcb_fr;           /* Phys addr. off tcb frame      */
   ULONG   tcb_fr_base;      /* Phys addr. off tcb frame      */
   ULONG   frame_offset_val; /* holds offset of frame base */
   ULONG   tsd_r0st;         /* Phys addr. end of ring0 stack */
   ULONG   tsd_stack_offset; /* used to calculate tsd bottom*/
   USHORT  rc;
//   RIP      *pRip;
//   ULONG    *pulRegVal;

   szModuleName[0] = '\0';

//davidj fixing warning of different levels of indirection
   ulTCBFrame = (ULONG)vpTCB->TCB_pFrameBase; // get pointer to TSD stack frame
                                       // get offset
   ulFrameOffsetValue = ulTCBFrame - ulDefaultTSDAddr;
   ulTCBFrameBase = (ULONG)vpTSD + ulFrameOffsetValue;

 /*--------------------------------------------------------------------------*/
 /*                    Display process information                           */
 /*--------------------------------------------------------------------------*/
  fprintf( stdout, "PROCESS slot:%x Pid:%04.4x Ord:%04.4x\n",
                    usDefaultSlot, vpPTDA->ptda_Pid, vpTCB->TCBOrdinal);
 /*--------------------------------------------------------------------------*/
 /*            Display addresses of process control blocks                   */
 /*--------------------------------------------------------------------------*/
 //  fprintf( stdout, "PTDA    handle=%04.4x address=%%%8.8lx sel=#%04.4x\n",
 //                    vpPTDA->ptda_handle, ulDefaultPTDAAddr,
 //                    vpPTDA->pPTDASelf                              );

  fprintf( stdout, "PTDA    handle=%04.4x address=%%%8.8lx\n",
                    vpPTDA->ptda_handle, ulDefaultPTDAAddr);

 /*--------------------------------------------------------------------------*/
 /*            Display MTE information                                       */
 /*--------------------------------------------------------------------------*/
 // mteAddress = fmt_mte_addr(ptda_ptr->ptda_module);

 if ( vpPTDA->ptda_module != 0 )
 {
   FormatMTEOwner( vpPTDA->ptda_module, szModuleName );

   // map handle to MTE address
   object = (VMOB huge *)ptrOBJ + ( (vpPTDA->ptda_module - 1) * sizeof( sizeof( VMOB ) ) / 2 );

   tmpHandle = object->ob_hobmte;
   if (object->ob_hobnext < 0xfff)
      object = (VMOB huge *)ptrOBJ + ((tmpHandle - 1) * sizeof( sizeof(VMOB) ) / 2 );

   ulMTEAddr = (ULONG)object->ob_va;

    fprintf( stdout, "MTE     handle=%04.4x address=%%%8.8lx (%s)\n",
                      vpPTDA->ptda_module, ulMTEAddr, szModuleName);
  //  fprintf( stdout, "MTE     handle=%04.4x address=%%%8.8lx (%s)\n",
  //                  vpPTDA->ptda_module, ulMTEAddr, szModuleName);

 /*--------------------------------------------------------------------------*/
 /* Load the mte_s structure from disk .001 file into RAM and point to it    */
 /*--------------------------------------------------------------------------*/
  if ( ulMTEAddr != 0l )
     {
       rc = GetLinearAddress(ulMTEAddr,
                             sizeof(struct ldrmte_s),
                             (INT far *)&ldrMTE,
                             FALSE);

       if ( rc == 0 )
          /*-----------------------------------------------------------------*/
          /*            Display SMTE Swappable mte information               */
          { /*---------------------------------------------------------------*/
            fprintf( stdout, "SMTE    address=%%%8.8lx \n", ldrMTE.mte_swapmte );

          } /* end(if)          Good rc from read function                   */
       else
          /*-----------------------------------------------------------------*/
          /*            Bad rc from read MTE                                 */
          { /*---------------------------------------------------------------*/
            fprintf( stdout, "SMTE    Swappable MTE information swapped out.\n");
            Error( szFile, __LINE__, rc,
                     "GetLinearAddress failed in LoadThreadTable.");

          } /* end(else)        Bad rc from read MTE                         */
     } /* end(if)               MTE address not zero                         */
 }
 else
 {
    fprintf( stdout, "MTE     not available\n");
    fprintf( stdout, "SMTE    not available\n");
 }
 /*--------------------------------------------------------------------------*/
 /*            Display LDT information                                       */
 /*--------------------------------------------------------------------------*/
 fprintf( stdout, "LDT     handle=%04.4x address=%%%8.8lx \n",
                  vpPTDA->ptda_ldthandle, vpPTDA->ptda_ldtaddr  );

 /*--------------------------------------------------------------------------*/
 /*                    Display stack pointer                                 */
 /* Note: TSD is only valid if TSDKernelESP is not ZERO                      */
 /*--------------------------------------------------------------------------*/
 if (vpTSD->TSDKernelESP != 0 )
    {
     /* 8 chars for UserESP is a short and not a long as defined in tkexport.h */
      fprintf( stdout, "CODE:   user (cs:eip)#%s",print_reg ( KM_REG_CS ));
      fprintf( stdout, ":%s ", print_reg ( KM_REG_EIP ));
      fprintf( stdout, "cbargs=%s\n",print_reg ( KM_REG_CBARGS ) );

      fprintf( stdout, "STACKS: user (ss:esp)#%04.4x:%08.8lx(active)\n",
                                    vpTSD->TSDUserSS, vpTSD->TSDUserESP );

    } /* end(if)                TSD is valid                                 */
 /*--------------------------------------------------------------------------*/
 /* Display Ring 2 SS:ESP information                                        */
 /*--------------------------------------------------------------------------*/
    fprintf( stdout, "        ring2(ss:esp)#%04.4x:%08.8lx(bottom)\n",
                           vpTCB->TCBCpl2_SS, vpTCB->TCBCpl2_ESP   );

 /*--------------------------------------------------------------------------*/
 /* Load physical address of stack frame on ring 0 stack into tcb_fr_base    */
 /* Get the tcb frame base address from the disk .001 file, then subtract    */
 /* the default_tsd_addr to calculate offset.  Add the calculated offset to  */
 /* the tsd_ptr which points to the tsd structure in memory to find the      */
 /* address to be used later to get the register information to be displayed */
 /*--------------------------------------------------------------------------*/
  tcb_fr = (ULONG)vpTCB->TCB_pFrameBase; /* get pointer to tsd stack frame */
  frame_offset_val =  tcb_fr - ulDefaultTSDAddr;      /* get offset          */
  tcb_fr_base   =  (ULONG)vpTSD + frame_offset_val; /*add offset value     */
                                             /* in memory where frame base is*/

 /*--------------------------------------------------------------------------*/
 /* Caculate address of bottom of ring 0 stack                               */
 /*--------------------------------------------------------------------------*/
  /* next line gives a C4059 warning, but the offset value is all I want */
  tsd_stack_offset = FIELDOFFSET(struct tsd_s,TSDUserStack[TSDStackSize]);
  tsd_r0st         = ulDefaultTSDAddr + tsd_stack_offset;

  fprintf( stdout, "        ring0 tcbframe=%%%8.8lx bottom=%%%8.8lx \n",
                               vpTCB->TCB_pFrameBase, tsd_r0st );

  fflush(stdout);
}
